[FFmpeg-trac] #2877(avutil:new): Unable to rewind/seek a mp3

FFmpeg trac at avcodec.org
Fri Aug 16 22:38:16 CEST 2013


#2877: Unable to rewind/seek a mp3
-------------------------------------+-------------------------------------
             Reporter:  jpo38        |                     Type:  defect
               Status:  new          |                 Priority:  normal
            Component:  avutil       |                  Version:
             Keywords:               |  unspecified
  av_seek_frame                      |               Blocked By:
             Blocking:               |  Reproduced by developer:  0
Analyzed by developer:  0            |
-------------------------------------+-------------------------------------
 Summary of the bug:
 I'm working on a program to simply read a mp3. 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 call av_seek_frame to move within the
 file, 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.....

 How to reproduce:
 {{{
 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;
     }
 }
 }}}

-- 
Ticket URL: <https://ffmpeg.org/trac/ffmpeg/ticket/2877>
FFmpeg <http://ffmpeg.org>
FFmpeg issue tracker


More information about the FFmpeg-trac mailing list