[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