Hi, I'm playing around with the FFmpeg tutorials at (http://dranger.com/ffmpeg/) and trying to update them to the most recent version of FFmpeg. I'm having problems decoding audio. In particular, the entire data array of the AVFrame I pass in is zero after decoding.
Here's the code around the problem area: int bytes_consumed; int got_frame; bytes_consumed = avcodec_decode_audio4 ( aCodecCtx, frame, &got_frame, &pkt ); if (got_frame) { int bytes_decoded = av_samples_get_buffer_size ( NULL, aCodecCtx->channels, frame->nb_samples, aCodecCtx->sample_fmt, 1 ); int sum = 0; int i = 0; for (i = i; i < bytes_decoded; ++i) sum += abs(frame->data[0][i]); fprintf(stderr, "sum: %d\n", sum); return bytes_decoded; } The whole data array sums to zero every time, and I get silence as output. I'm attaching my full source for reference. Why does this happen? What am I doing wrong? ffmpeg version N-41103-g67b7631 built on Jun 4 2012 17:00:05 with gcc 4.4.3 Thank you in advance for your help. Cheers, Michael
// tutorial03.c // A pedagogical video player that will stream through every video frame as // fast as it can and play audio (out of sync). // // Code based on FFplay, Copyright (c) 2003 Fabrice Bellard, // and a tutorial by Martin Bohme (boe...@inb.uni-luebeckremovethis.de) // Updated for ffmpeg version N-41103-g67b7631 by misha.pen...@gmail.com. // Tested on Ubuntu 10.04 LTS, GCC 4.4.3. // Use the Makefile to build all the samples. // // Run using // // Run using // bin/tutorial03.out myvideofile.mpg // // to play the stream on your screen. // #include <libavcodec/avcodec.h> #include <libavformat/avformat.h> #include <libswscale/swscale.h> #include <SDL/SDL.h> #include <SDL/SDL_thread.h> #ifdef __MINGW32__ #undef main /* Prevents SDL from overriding main() */ #endif #include <stdio.h> #define SDL_AUDIO_BUFFER_SIZE 1024 #define INBUF_SIZE 4096 #define AUDIO_INBUF_SIZE 20480 struct PacketQueue { AVPacketList *first_pkt; AVPacketList *last_pkt; int nb_packets; int size; SDL_mutex *mutex; SDL_cond *cond; }; struct PacketQueue audioq; int quit = 0; /* * Initialize the packet queue. */ void packet_queue_init(struct PacketQueue *q) { memset(q, 0, sizeof(struct PacketQueue)); q->mutex = SDL_CreateMutex(); q->cond = SDL_CreateCond(); } /* * Puts a new packet onto the queue. * * @param[in] q The packet queue. * @param[in] pkt The packet. * * @return 0 on success, non-zero on failure. */ int packet_queue_put(struct PacketQueue *q, AVPacket *pkt) { /* * pkt1 A queue node. */ AVPacketList *pkt1; /* * This is a HACK to ensure the packet is allocated. */ if (av_dup_packet(pkt) < 0) return -1; pkt1 = av_malloc(sizeof(AVPacketList)); if (!pkt1) return -1; pkt1->pkt = *pkt; pkt1->next = NULL; SDL_LockMutex(q->mutex); if (!q->last_pkt) q->first_pkt = pkt1; else q->last_pkt->next = pkt1; q->last_pkt = pkt1; q->nb_packets++; q->size += pkt1->pkt.size; SDL_CondSignal(q->cond); SDL_UnlockMutex(q->mutex); return 0; } /* * Grab a packet from the packet queue. * * @param[in] q The packet queue. * @param[out] pkt The grabbed packet. * @param[in] block If non-zero, the function will block until the queue * is non-empty. * * @return 1 if the packet was successfully grabbed, 0 if the queue was * empty (in non-blocking case) and -1 if the application was signalled * to terminate. */ static int packet_queue_get(struct PacketQueue *q, AVPacket *pkt, int block) { AVPacketList *pkt1; int ret; SDL_LockMutex(q->mutex); for(;;) { if (quit) { ret = -1; break; } pkt1 = q->first_pkt; if (pkt1) { q->first_pkt = pkt1->next; if (!q->first_pkt) q->last_pkt = NULL; q->nb_packets--; q->size -= pkt1->pkt.size; *pkt = pkt1->pkt; av_free(pkt1); ret = 1; break; } else if (!block) { ret = 0; break; } else { SDL_CondWait(q->cond, q->mutex); } } SDL_UnlockMutex(q->mutex); return ret; } /* * Decode an audio frame. * * @param[in] aCodecCtx The codec context of the audio stream we're decoding. * @param[out] frame The decoded audio frame. * * @returns the number of bytes decoded or -1 if the application was * signalled to terminate. */ int audio_decode_frame (AVCodecContext *aCodecCtx, AVFrame *frame) { static init_flag = 1; static AVPacket pkt; /* * If the function is being called for the first time, initialize the * packet. */ if (init_flag) { av_init_packet(&pkt); init_flag = 0; } /* * pkt The current packet. Note that it's static, meaning it will persist * between separate calls to this functions. * * The outer loop grabs new packets into pkt. * The inner loop consumes the current packet in its entirety. */ for (;;) { while (pkt.size > 0) { int bytes_consumed; int got_frame; /* * bytes_consumed * The number of bytes consumed from the current packet * during this iteration. * got_frame * avcodec_decode_audio4 sets this to non-zero if a * frame could be decoded, zero otherwise. */ bytes_consumed = avcodec_decode_audio4 ( aCodecCtx, frame, &got_frame, &pkt ); if (bytes_consumed < 0) { /* * if error, skip frame */ break; } if (got_frame) { int bytes_decoded = av_samples_get_buffer_size ( NULL, aCodecCtx->channels, frame->nb_samples, aCodecCtx->sample_fmt, 1 ); #if 0 int sum = 0; int i = 0; for (i = i; i < bytes_decoded; ++i) sum += abs(frame->data[0][i]); fprintf(stderr, "sum: %d\n", sum); #endif return bytes_decoded; } pkt.size -= bytes_consumed; pkt.data += bytes_consumed; } /* * Free the old packet. */ if (pkt.data) av_free_packet(&pkt); if (quit) return -1; /* * This is where we actually get a new packet from the global * packet queue. * * NB. The reason this happens all the way at the end of the loop is * that the function may be called while a packet is half-consumed. * In that case, we want to make sure we consume the entire packet * before grabbing a new one. * * Keep in mind that pkt is static, so it persists between calls to * this function. */ if (packet_queue_get(&audioq, &pkt, 1) < 0) return -1; } } /* * Read packets from the queue and put them into a buffer that SDL will * then play back. This function gets called by SDL periodically. * * @param[in] userdata Payload containing the AVCodecContext. * @param[out] out_buf The buffer to write packets to. * @param[in] out_buf_len The size of buffer. */ void audio_callback(void *userdata, Uint8 *out_buf, int out_buf_len) { AVCodecContext *aCodecCtx = (AVCodecContext *)userdata; AVFrame frame; static uint8_t tmp_buf[AUDIO_INBUF_SIZE + FF_INPUT_BUFFER_PADDING_SIZE]; static unsigned int tmp_buf_len = 0; static unsigned int tmp_buf_index = 0; /* * aCodecContext The AVCodecContext corresponding to the audio * stream that we are decoding. * frame A frame to store decoded samples. * tmp_buf A temporary buffer that we write the decoded samples * into. Once this buffer fills up, we write its * contents into the SDL output buffer. * tmp_buf_len The number of audio bytes currently in the buffer. * tmp_buf_index The current position in the buffer. Everything prior * to this position has already been sent to SDL. * * The pipeline looks like this: * * stream --> frame --> tmp_buf --> out_buf */ /* * Continue writing until the buffer output to SDL is full. */ while (out_buf_len > 0) { int incr; /* * incr The number of bytes to write to the output buffer during * this iteration. * * If we've gone past the end of our temporary buffer, refill it by * decoding another frame. */ if (tmp_buf_index >= tmp_buf_len) { int bytes_decoded; /* * nbytes The number of bytes decoded. * We have already sent all our data. Get more data by decoding * some more packets into our temporary buffer. */ avcodec_get_frame_defaults(&frame); nbytes = audio_decode_frame(aCodecCtx, &frame); /* * If error (in particular, the app is terminating), output * silence. Otherwise, write the decoded frame to the temporary * buffer. */ if (bytes_decoded < 0) { tmp_buf_len = 1024; memset(tmp_buf, 0, tmp_buf_len); } else { memcpy(tmp_buf, frame.data[0], bytes_decoded); tmp_buf_len = nbytes; } tmp_buf_index = 0; } incr = tmp_buf_len - tmp_buf_index; /* * Make sure we don't overflow the output buffer. */ if (incr > out_buf_len) incr = out_buf_len; memcpy(out_buf, (uint8_t *)tmp_buf + tmp_buf_index, incr); out_buf_len -= incr; out_buf += incr; tmp_buf_index += incr; } } int main(int argc, char *argv[]) { AVFormatContext *pFormatCtx = NULL; AVCodecContext *pCodecCtx = NULL; AVCodec *pCodec = NULL; AVFrame *pFrame = NULL; AVPacket packet; int i; int videoStream; int audioStream; int frameFinished; float aspect_ratio; AVCodecContext *aCodecCtx = NULL; AVCodec *aCodec = NULL; SDL_Overlay *bmp = NULL; SDL_Surface *screen = NULL; SDL_Rect rect; SDL_Event event; SDL_AudioSpec wanted_spec; SDL_AudioSpec spec; struct SwsContext *sws_ctx = NULL; AVDictionary *videoOptionsDict = NULL; AVDictionary *audioOptionsDict = NULL; if (argc < 2) { fprintf(stderr, "Usage: test <file>\n"); exit(1); } // Register all formats and codecs av_register_all(); if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_TIMER)) { fprintf(stderr, "Could not initialize SDL - %s\n", SDL_GetError()); exit(1); } if (avformat_open_input(&pFormatCtx, argv[1], NULL, NULL) != 0) { fprintf(stderr, "Could not open file: %s\n", argv[1]); return -1; } if (avformat_find_stream_info(pFormatCtx, NULL) < 0) { fprintf(stderr, "Could not find stream information.\n"); return -1; } av_dump_format(pFormatCtx, 0, argv[1], 0); // Find the first video stream videoStream = -1; audioStream = -1; for (i = 0; i < pFormatCtx->nb_streams; i++) { int codec_type = pFormatCtx->streams[i]->codec->codec_type; if (codec_type == AVMEDIA_TYPE_VIDEO && videoStream < 0) videoStream = i; if (codec_type == AVMEDIA_TYPE_AUDIO && audioStream < 0) audioStream = i; } if (videoStream == -1) { fprintf(stderr, "Unable to find a video stream!\n"); return -1; } if (audioStream == -1) { fprintf(stderr, "Unable to find an audio stream!\n"); return -1; } aCodecCtx=pFormatCtx->streams[audioStream]->codec; // // Set audio settings from codec info // wanted_spec.freq = aCodecCtx->sample_rate; wanted_spec.format = AUDIO_S16SYS; wanted_spec.channels = aCodecCtx->channels; wanted_spec.silence = 0; wanted_spec.samples = SDL_AUDIO_BUFFER_SIZE; wanted_spec.callback = audio_callback; wanted_spec.userdata = aCodecCtx; if (SDL_OpenAudio(&wanted_spec, &spec) < 0) { fprintf(stderr, "SDL_OpenAudio: %s\n", SDL_GetError()); return -1; } aCodec = avcodec_find_decoder(aCodecCtx->codec_id); if (!aCodec) { fprintf(stderr, "Unsupported audio codec!\n"); return -1; } if (avcodec_open2(aCodecCtx, aCodec, &audioOptionsDict) < 0) { fprintf(stderr, "Unable to open audio codec!\n"); return -1; } packet_queue_init(&audioq); SDL_PauseAudio(0); // Get a pointer to the codec context for the video stream pCodecCtx=pFormatCtx->streams[videoStream]->codec; // Find the decoder for the video stream pCodec=avcodec_find_decoder(pCodecCtx->codec_id); if (pCodec==NULL) { fprintf(stderr, "Unsupported video codec!\n"); return -1; // Codec not found } // Open codec if(avcodec_open2(pCodecCtx, pCodec, &videoOptionsDict) < 0) { fprintf(stderr, "Unable to open video codec!\n"); return -1; } // Allocate video frame pFrame=avcodec_alloc_frame(); // Make a screen to put our video #ifndef __DARWIN__ screen = SDL_SetVideoMode(pCodecCtx->width, pCodecCtx->height, 0, 0); #else screen = SDL_SetVideoMode(pCodecCtx->width, pCodecCtx->height, 24, 0); #endif if (!screen) { fprintf(stderr, "SDL: could not set video mode - exiting\n"); exit(1); } // // Allocate a place to put our YUV image on that screen // bmp = SDL_CreateYUVOverlay ( pCodecCtx->width, pCodecCtx->height, SDL_YV12_OVERLAY, screen ); sws_ctx = sws_getContext ( pCodecCtx->width, pCodecCtx->height, pCodecCtx->pix_fmt, pCodecCtx->width, pCodecCtx->height, PIX_FMT_YUV420P, SWS_BILINEAR, NULL, NULL, NULL ); // Read frames and save first five frames to disk i=0; while (av_read_frame(pFormatCtx, &packet)>=0) { // Is this a packet from the video stream? if (packet.stream_index==videoStream) { // Decode video frame avcodec_decode_video2 ( pCodecCtx, pFrame, &frameFinished, &packet ); // Did we get a video frame? if (frameFinished) { SDL_LockYUVOverlay(bmp); AVPicture pict; pict.data[0] = bmp->pixels[0]; pict.data[1] = bmp->pixels[2]; pict.data[2] = bmp->pixels[1]; pict.linesize[0] = bmp->pitches[0]; pict.linesize[1] = bmp->pitches[2]; pict.linesize[2] = bmp->pitches[1]; sws_scale ( sws_ctx, pFrame->data, pFrame->linesize, 0, pCodecCtx->height, pict.data, pict.linesize ); SDL_UnlockYUVOverlay(bmp); rect.x = 0; rect.y = 0; rect.w = pCodecCtx->width; rect.h = pCodecCtx->height; SDL_DisplayYUVOverlay(bmp, &rect); av_free_packet(&packet); } } else if(packet.stream_index==audioStream) { packet_queue_put(&audioq, &packet); } else { av_free_packet(&packet); } // Free the packet that was allocated by av_read_frame SDL_PollEvent(&event); switch(event.type) { case SDL_QUIT: quit = 1; SDL_Quit(); exit(0); break; default: break; } } av_free(pFrame); avcodec_close(pCodecCtx); avcodec_close(aCodecCtx); avformat_close_input(&pFormatCtx); return 0; }
_______________________________________________ Libav-user mailing list Libav-user@ffmpeg.org http://ffmpeg.org/mailman/listinfo/libav-user