[Libav-user] Unable to correctly rewind a stream

Jean Porcherot jeanporcherot at yahoo.fr
Fri Jul 26 15:59:07 CEST 2013


Hi everyone,

Not sure I will be using this list correctly. Pardon me if I'm not (first
time I try it).

I'm working on a program to simply read a mp3 file. For some reason
(optimization), I want to read the file by blocks (possibly non consecutive
and I often move forward and backward). But I am unable to safely navigate
through the file, I try to call av_seek_frame, but then, extracted data are
incorrect.

I could isolate the problem in a very basic sample program. This program
opens a file, reads the audio stream (saves it to a vector of doubles),
then calls av_seek_frame to move back to the beginning of the file and
finally try to read it a second time (saving it to a new vector of
doubles). The resulting two vectors of double are slighlty different.....

If anyone sees what's wrong, this would help!!!

Thanks

Jean

Here is the program:
extern "C" {
#include "libavformat/avformat.h"
#include "libavutil/samplefmt.h"
#include <libswresample/swresample.h>
#include <libavutil/opt.h>
}

#include <iostream>
#include <sstream>
#include <fstream>
#include <vector>

AVFormatContext* container = NULL;
AVCodecContext *ctx = NULL;
int audio_stream = 0;

bool open_audio_stream( char* file )
{
    bool bRes = false;

    av_register_all();

    container = avformat_alloc_context();
    AVCodec *codec = NULL;
    if ( avformat_open_input(&container,file,NULL,NULL) < 0 ||
         av_find_stream_info(container) < 0 ||
         (audio_stream = av_find_best_stream(container, AVMEDIA_TYPE_AUDIO,
-1, -1, NULL, 0)) < 0 ||
         (ctx = container->streams[audio_stream]->codec) == NULL ||
         (codec = avcodec_find_decoder(ctx->codec_id)) == NULL ||
         avcodec_open2( ctx, codec, NULL ) < 0 )
    {
        std::cout << "Failed to open audio stream" << std::endl;
        return false;
    }
    else
    {
        return true;
    }
}

bool read_audio_stream( std::vector<std::vector<double>>& extracted )
{
    bool bRes = false;

    extracted.resize( ctx->channels ); // prepare container

    // read to read the file!
    AVPacket packet;
    av_init_packet( &packet );
    packet.pos = 0;
    packet.data = NULL;
    packet.size = 0;

    AVFrame *frame = avcodec_alloc_frame();

    int tempdatabuffer_size = 0;
    double* tempdatabuffer = NULL;

    struct SwrContext *swr_ctx;
    swr_ctx = swr_alloc();
    if ( swr_ctx )
    {
        // prepare object used for data conversion
        av_opt_set_int(swr_ctx, "in_channel_count", ctx->channels, 0);
        av_opt_set_int(swr_ctx, "in_channel_layout", ctx->channel_layout,
0);
        av_opt_set_int(swr_ctx, "in_sample_rate", ctx->sample_rate, 0);
        av_opt_set_sample_fmt(swr_ctx, "in_sample_fmt", ctx->sample_fmt, 0);
        av_opt_set_int(swr_ctx, "out_channel_layout", ctx->channel_layout,
0);
        av_opt_set_int(swr_ctx, "out_channel_count", ctx->channels, 0);
        av_opt_set_int(swr_ctx, "out_sample_rate", ctx->sample_rate, 0);
        av_opt_set_sample_fmt(swr_ctx, "out_sample_fmt", AV_SAMPLE_FMT_DBL,
0);
        if ( swr_init(swr_ctx) >= 0 )
        {
            int tempdatabuffer_size = 0;
            double* tempdatabuffer = NULL;

            bRes = true;

            int frameFinished = 0;
            int sample = 0;
            while ( av_read_frame( container, &packet ) >= 0 &&
                    packet.stream_index == audio_stream )
            {
                if ( avcodec_decode_audio4( ctx, frame, &frameFinished,
&packet ) >= 0 )
                {
                    if ( frame->nb_samples*ctx->channels >
tempdatabuffer_size )
                    {
                        // update temp buffer, it's actually too small!!
                        tempdatabuffer_size =
frame->nb_samples*ctx->channels;
                        if ( tempdatabuffer )
                            delete [] tempdatabuffer;
                        tempdatabuffer = new double[tempdatabuffer_size];
                    }

                    if ( swr_convert(swr_ctx, (uint8_t **)&tempdatabuffer,
tempdatabuffer_size, (const uint8_t **)&(frame->data[0]),
frame->nb_samples) )
                    {
                        for ( sample = 0; sample != frame->nb_samples;
++sample )
                        {
                            for ( int chan = 0; chan != ctx->channels;
++chan )
                            {
                                extracted[chan].push_back(
tempdatabuffer[sample*ctx->channels + chan] );
                            }
                        }
                    }
                }
            }

            if ( tempdatabuffer ) delete [] tempdatabuffer;
        }

    }
    swr_free(&swr_ctx);
    avcodec_free_frame( &frame );

    return bRes;
}

int main(int argc, char **argv)
{
    if ( argc == 2 )
    {
        if ( open_audio_stream( argv[1] ) )
        {
            std::vector<std::vector<double>> first_read;
            std::vector<std::vector<double>> second_read;
            if ( read_audio_stream( first_read ) )
            {
                // rewind!
                av_seek_frame( container, audio_stream, 0,
AVSEEK_FLAG_FRAME );

                if ( read_audio_stream( second_read ) )
                {
                    if ( first_read.size() == second_read.size() )
                    {
                        std::cout << "Comparing " << first_read.size() << "
channels" << std::endl;
                        for ( unsigned int chan = 0; chan !=
first_read.size(); ++chan )
                        {
                            if ( first_read[chan].size() ==
second_read[chan].size() )
                            {
                                std::cout << "Comparing " <<
first_read[chan].size() << " samples for channel " << chan << std::endl;
                                for ( unsigned int sample = 0; sample !=
first_read[chan].size(); ++sample )
                                {
                                    if ( first_read[chan][sample] !=
second_read[chan][sample] )
                                    {
                                        std::cout << "Different data found
for sample " << sample << " of channel " << chan << std::endl;
                                        return 1;
                                    }
                                }
                                std::cout << "Results are equivalent!!!" <<
std::endl;
                                return 0;
                            }
                            else
                            {
                                std::cout << "Did not find the same number
of samples" << std::endl;
                            }
                        }
                    }
                    else
                    {
                        std::cout << "Did not find the same number of
channels" << std::endl;
                    }
                }

                av_close_input_file(container);
            }
        }

        return 1;
    }
    else
    {
        printf("usage: %s file\n",
               argv[0]);
        return 1;
    }
}
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://ffmpeg.org/pipermail/libav-user/attachments/20130726/2318d8d6/attachment.html>


More information about the Libav-user mailing list