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

Reply via email to