[Libav-user] av_buffersink_get_frame() crashes

Radu Robotin radu.robotin at gmail.com
Mon May 13 18:48:32 CEST 2013


Here is a little update: I haven't found the problem yet :)
To summaries the issue: I'm trying to migrate from ffmpeg 1.2 to the latest
build. With version 1.2 everything is working. I am decoding and filtering
several streams, each stream is processed in it's own thread, a frame is
taken and decoded, inserted in a filtergraph for filtering, pulled out the
filtered frame and inserted into a local buffer. This process loops as long
as the input stream is valid. The issue is, with the new API I
have av_buffersink_get_frame() that I'd like to use to get the filtered
frame out of buffersink. At the first run of this decode-filter
loop, everything works fine, but at the second pass (i.e. for the second
frame) it crashes - most of the time is segfault, sometimes I get a glibc
message detecting a corrupted double linked list. Gdb points me inside
of av_buffersink_get_frame() where some pointers are zero when trying to
read a fifo buffer.

The strangest thing is that under valgrind everything works fine. Tested
several times, under valgrind it just works.

What am I missing here? Why is it working under valgrind and crashes during
normal running? I really need help with this one!!
Thank you guys, for any suggestions and help!
Best,
Radu


On Fri, May 3, 2013 at 5:38 PM, Radu Robotin <radu.robotin at gmail.com> wrote:

> Here is the some parts of the code that's causing trouble: the
> ffmpegFetchDecodeResampleNext()  is called for fetching a frame form a
> stream, decoding and then filtering and putting the filtered frame in an
> internal buffer - then the process repeats. Before any call to
> ffmpegFetchDecodeResampleNext, the codec and the context for decoding are
> initialized, as well as the filtergraph.
>
> The first call to ffmpegFetchDecodeResampleNext() works as expected,. the
> second one fails (with coredump) when trying to get the filtered frame from
> the filtergraph.
>
> What has changed in the way filterghraph is handled? I had no issues
> working with version 1.2. Can you please help me and tell me what I'm doing
> wrong?
>
>
> Thanks a lot!
>
> refbuf_t * ffmpegFetchDecodeResampleNext(myFFmpegContext * ff, source_t
> *source){
>     refbuf_t * retRefBuff = NULL;
>   AVPacket pPacket;
>     AVFrame *frame = av_frame_alloc();
>     AVFrame *filt_frame = av_frame_alloc();
>     AVFrame *enc_frame = av_frame_alloc();
>
>     if (!frame || !filt_frame || !enc_frame) {
>         ERROR0("Could not allocate frame(s)");
>         return NULL;
>     }
>       int ret;
>   int localbuffering = 1;
>   while(global.running == ICE_RUNNING && source->running &&
> localbuffering)
> {
> ff->timeout = time(NULL);
>  ret= av_read_frame(ff->pInputFormatCtx, &pPacket);
>         if(ret == AVERROR(EAGAIN)){
>             WARN1("av_read_frame error EAGAIN, error reading frame,
> continuing %s",ff->localMount);
> av_free_packet(&pPacket);
>             continue;
>         }
> if(ret == EOF){
> source->running = 0;
> ERROR1("av_read_frame error, EOF, exiting %s",ff->localMount);
>  av_free_packet(&pPacket);
> break;
> }
>         if (ret < 0) {
>  WARN1("av_read_frame error, error reading frame, breaking
> %s",ff->localMount);
> av_free_packet(&pPacket);
>  ff->failedReads++;
> if(ff->failedReads >= 10)
> source->running = 0;
>             return NULL;
>         }
>
> ff->failedReads = 0;
>
> time_t current = time (NULL);
>  source->last_read = current;
>      int got_frame = 0;
> avcodec_get_frame_defaults(frame);
>  ret = avcodec_decode_audio4(ff->pInputCodecCtx, frame, &got_frame,
> &pPacket);
>
> if(ret < 0 ){
>  WARN1("avcodec_decode_audio3 unable to decode %s",ff->localMount);
> ff->failedDecodes++;
>  if(ff->failedDecodes >= 500){
> source->running = 0;
> ERROR1("avcodec_decode_audio3 unable to decode %s error limit reached,
> closing stream",ff->localMount);
>  av_free_packet(&pPacket);
>         return NULL;
> }
>  }
>
> else if(got_frame == 0){
>  thread_sleep (delay*1000);
>  }
>
> else{
>
> ff->failedDecodes = 0;
>  int resample_changed = ff->resample_sample_fmt !=
> ff->pInputCodecCtx->sample_fmt || ff->resample_channels !=
> ff->pInputCodecCtx->channels || ff->resample_sample_rate !=
> ff->pInputCodecCtx->sample_rate;
>                         if (resample_changed)  {
> if (resample_changed)   {
> ff->resample_sample_fmt  = ff->pInputCodecCtx->sample_fmt;
>              ff->resample_channels    = ff->pInputCodecCtx->channels;
>              ff->resample_sample_rate = ff->pInputCodecCtx->sample_rate;
>  }
> /*RESAMPLING parameters */
> INFO3("resampling context ch:%d spl:%d %s",ff->pInputCodecCtx->channels,
> ff->pInputCodecCtx->sample_rate, ff->localMount);
>  INFO2("volume for %s :%d",ff->localMount, ff->volume);
> if ((ret = init_filters(ff,source)) < 0) {
>    ERROR1( "Error while init_filters %s",ff->localMount);
> av_free_packet(&pPacket);
>  source->running = 0;
> return NULL;
> }
>
>
> }
>
>             //feed the filter graph with the new frame
>
>              if (av_buffersrc_add_frame_flags(ff->buffersrc_ctx, frame,0)
> < 0) {
> ERROR1( "Error while feeding the audio filtergraph %s",ff->localMount);
>                 }
>
>             /* pull filtered audio from the filtergraph */
>             while (1) {
>
> // This is where the crash happens - initially it was something like:
> // AVFilterBufferRef *samplesref; // ret =
> av_buffersink_get_buffer_ref(ff->buffersink_ctx, &samplesref, 0);
> //
>
>                 ret = av_buffersink_get_frame(ff->buffersink_ctx,
> filt_frame);
>
> // At the second call of this function, we don't get to this point, as it
> crashes when trying to extract the frame from the filtergraph
>
>                 if(ret == AVERROR(EAGAIN) || ret == AVERROR_EOF)
> break;
>                 if(ret < 0)
>  WARN1("error av_buffersink_get_frame, %s",ff->localMount);
>                 if (ret>=0) {
> //print_samplesref(samplesref);
>                     char * resampleBuff = (char *)filt_frame->data[0];
>                     size_out = filt_frame->nb_samples *
> av_get_channel_layout_nb_channels(av_frame_get_channel_layout(filt_frame));
>
>                    //process the frame and put it in a circular buffer to
> be returned at exit
> ................................................
>
>                     av_frame_unref(filt_frame);
>                     av_frame_unref(frame);
>                 }
>
>             }
>             av_frame_unref(filt_frame);
>             av_frame_unref(frame);
> if(ret < 0) {
> av_free_packet(&pPacket);
>  break;
> }
>  }
>  av_free_packet(&pPacket);
> }
>     av_frame_free(&filt_frame);
>     av_frame_free(&frame);
>     av_frame_free(&enc_frame);
>
>     return nextPreBuffer(source);
> }
>
>
> the decoder and the filtergraph are initialized prior calling this
> function.  Here is a snippet with the function used for filter_init. It's
> pretty much standard as in the example file
>
>
> static int init_filters(myFFmpegContext * ff, source_t *source)
> {
> AVFormatContext *fmt_ctx = ff->pInputFormatCtx;
>  AVCodecContext *dec_ctx = ff->pInputCodecCtx;
> int audio_stream_index = ff->audioStreamIndex;
>
>     char args[512];
>     int ret;
>     char *pcTemp_string1, *pcTemp_string2;
>     char buffer[10];
>
>     AVFilter *abuffersrc  = avfilter_get_by_name("abuffer");
>     AVFilter *abuffersink = avfilter_get_by_name("abuffersink");
>     AVFilterInOut *outputs = avfilter_inout_alloc();
>     AVFilterInOut *inputs  = avfilter_inout_alloc();
>     const enum AVSampleFormat sample_fmts[] = { AV_SAMPLE_FMT_S16,
> AV_SAMPLE_FMT_NONE };
>     AVABufferSinkParams *abuffersink_params;
>
>
>     const AVFilterLink *outlink;
>     AVRational time_base = fmt_ctx->streams[audio_stream_index]->time_base;
>
> if(ff->filter_graph)
> avfilter_graph_free(&ff->filter_graph);
> ff->filter_graph = avfilter_graph_alloc();
>
>     /* buffer audio source: the decoded frames from the decoder will be
> inserted here. */
>     if (!dec_ctx->channel_layout)
>         dec_ctx->channel_layout =
> av_get_default_channel_layout(dec_ctx->channels);
>     snprintf(args, sizeof(args),
> "time_base=%d/%d:sample_rate=%d:sample_fmt=%s:channel_layout=0x%"PRIx64,
> time_base.num, time_base.den, dec_ctx->sample_rate,
> av_get_sample_fmt_name(dec_ctx->sample_fmt), dec_ctx->channel_layout);
>     ret = avfilter_graph_create_filter(&ff->buffersrc_ctx, abuffersrc,
> "in", args, NULL, ff->filter_graph);
>     if (ret < 0) {
>         av_log(NULL, AV_LOG_ERROR, "Cannot create audio buffer source\n");
>         return ret;
>     }
>
>     /* buffer audio sink: to terminate the filter chain. */
>     //abuffersink_params = av_abuffersink_params_alloc();
>     //abuffersink_params->sample_fmts     = sample_fmts;
>     ret = avfilter_graph_create_filter(&ff->buffersink_ctx, abuffersink,
> "out", NULL, NULL, ff->filter_graph);
>     //av_free(abuffersink_params);
>     if (ret < 0) {
>         av_log(NULL, AV_LOG_ERROR, "Cannot create audio buffer sink\n");
>         return ret;
>     }
>
>
>
>     /* Endpoints for the filter graph. */
>     outputs->name       = av_strdup("in");
>     outputs->filter_ctx = ff->buffersrc_ctx;
>     outputs->pad_idx    = 0;
>     outputs->next       = NULL;
>
>     inputs->name       = av_strdup("out");
>     inputs->filter_ctx = ff->buffersink_ctx;
>     inputs->pad_idx    = 0;
>     inputs->next       = NULL;
>
> char *filter_descr = default_filter_descr;
>
> snprintf(args,sizeof(args), "%s,volume=%.2f",filter_descr , volume);
>     INFO1("Filter string: %s",filter_descr);
>
>     if ((ret = avfilter_graph_parse(ff->filter_graph, args,  &inputs,
> &outputs, NULL)) < 0)
>         return ret;
>
>     if ((ret = avfilter_graph_config(ff->filter_graph, NULL)) < 0)
>         return ret;
>
> av_log(NULL, AV_LOG_INFO,  "%s\n", args);
>     /* Print summary of the sink buffer
>      * Note: args buffer is reused to store channel layout string */
>     outlink = ff->buffersink_ctx->inputs[0];
>     av_get_channel_layout_string(args, sizeof(args), -1,
> outlink->channel_layout);
>      av_log(NULL, AV_LOG_INFO, "Output: srate:%dHz fmt:%s chlayout:%s\n",
> (int)outlink->sample_rate, (char
> *)av_x_if_null(av_get_sample_fmt_name((AVSampleFormat)outlink->format),
> "?"), args);
>
>     return 0;
> }
>
>
>
> On Fri, May 3, 2013 at 1:36 PM, Nicolas George <
> nicolas.george at normalesup.org> wrote:
>
>> Le tridi 13 floréal, an CCXXI, Radu Robotin a écrit :
>> > I'm using ffmpeg with libavcodec and libavfilters for a custom project.
>> > I've recently upgraded to the latest version available from git and
>> noticed
>> > that my previous code has stopped working. I'm processing several
>> streams,
>> > each in his own thread in the following way:
>> >
>> >      next sample is taken from the stream, decoded and then inserted in
>> the
>> > buffer source of the filtergraph using av_buffersrc_add_frame()
>> >      a frame is extracted from the buffer sink of the filtergraph using
>> > av_buffersink_get_frame()
>> >     the filtered frame is  copied in a buffer for further processing
>> >
>> > before upgrading to the latest version of ffmpeg I've been using ffmpeg
>> 1.2
>> > and everything worked flawlessly.  The filtered buffer was pulled from
>> the
>> > filtergraph using the av_buffersink_get_buffer_ref().
>>
>> The change from buffer ref to frames was accompanied with a change in the
>> lifetime of the frames. What you describe looks like a problem with that,
>> but without seeing the code it is impossible to tell for sure.
>>
>> > The problem I'm encountering: at the first pass everything works fine,
>> > however when I call the processing function for the second time (for
>> > processing the next frame), it coredumps when I call
>> > av_buffersink_get_frame() with the message " corrupted double-linked
>> list ".
>> > I tried further investigating the problem and have several
>> > frames processed during the same call of this function: everything works
>> > until the second call, then it coredumps at the same point.
>>
>> The "corrupted double-linked list" message seems to indicate corrupted
>> memory: either you write to an invalid location, or you write to a
>> location
>> that was previously freed, but you do not get the error immediately. I
>> suggest you use valgrind to get an error at the exact time of the problem.
>>
>> > To me it seems that something changes the structure of the filtergraph
>> > between the calls to the processing function.
>>
>> I am rather sure that the structure of the filter graph is not supposed to
>> change after it has been configured.
>>
>> Regards,
>>
>> --
>>   Nicolas George
>>
>> -----BEGIN PGP SIGNATURE-----
>> Version: GnuPG v1.4.12 (GNU/Linux)
>>
>> iEYEARECAAYFAlGDkyQACgkQsGPZlzblTJO/swCgkvXLQfnrP65ERswa1evJZSlp
>> jBgAoKLHeBMgtGqB9oAsjmpKL0eDVv5G
>> =0vJ2
>> -----END PGP SIGNATURE-----
>>
>> _______________________________________________
>> Libav-user mailing list
>> Libav-user at ffmpeg.org
>> http://ffmpeg.org/mailman/listinfo/libav-user
>>
>>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://ffmpeg.org/pipermail/libav-user/attachments/20130513/f1470538/attachment.html>


More information about the Libav-user mailing list