[libav-api] Segfault using avcodec_decode_audio3 in multithreaded app

Ibrahim Sha'ath ibrahimshaath at gmail.com
Wed Feb 15 13:21:15 CET 2012


> >>> >>>>>> > [wmav2 @ 0x106829e20] prev_block_len_bits N out of range
> >>> >>>>>> > (where N is in the range 4..6).
> >>> >>>>>>
> >>> >>>>>> Do these errors occur when you're decoding only a single file, without
> >>> >>>>>> threading?
> >>> >>>>>
> >>> >>>>> Yes they do, and on both platforms, though I've never seen them cause
> >>> >>>>> a segfault when not parallelised. Also interspersed with those errors
> >>> >>>>> are
> >>> >>>>> [wmav2 @ 0x1030a9800] overflow in spectral RLE, ignoring
> >>> >>>>> [wmav2 @ 0x1030a9800] frame_len overflow
> >>> >>>>>
> >>> >>>>> And very occasionally
> >>> >>>>> [wmav2 @ 0x1030a9800] len -211 invalid
> >>> >>>>>
> >>> >>>>> Do these errors suggest anything in particular to you?
> >>> >>>>
> >>> >>>> Yes, is it possible you're not setting AVCodecContext->bit_rate,
> >>> >>>> ->block_align, ->extradata or ->extradata_size?
> >>> >>>
> >>> >>> I had thought (based on what I'd read in the ffmpeg doxygen) that all
> >>> >>> of those fields (certainly bit_rate, extra_data and extradata_size)
> >>> >>> were set internally by libav for decoding, and only needed to be set
> >>> >>> by the user for encoding?
> >>> >>>
> >>> >>> If I'm wrong, could you suggest what I should set them to, for a
> >>> >>> general decoding solution? I'm seeing no examples online that set
> >>> >>> them.
> >>> >>
> >>> >> They are set, but (in the case of WMA) by the demuxer instead of the
> >>> >> decoder. My impression is you're not using the
> >>> >> AVFormatContext->streams[%d]->codec for decoding, but rather create
> >>> >> one independently. Then you need to copy the demuxer values to the
> >>> >> decoder values. If you're using your own demuxer instead of
> >>> >> libavformat's, see libavformat for how to read them.
> >>> >>
> >>> >
> >>> > I'm doing something in the neighbourhood of this:
> >>> >
> >>> > AVCodecContext* cCtx = fCtx->streams[audioStream]->codec;
> >>> > codec = avcodec_find_decoder(cCtx->codec_id);
> >>> > if(codec == NULL){
> >>> >  throw Exception();
> >>> > }
> >>> > if(avcodec_open2(cCtx, codec, &opts) < 0){
> >>> >  throw Exception();
> >>> > }
> >>> >
> >>> > And then passing that codec context into the decode job. So I think
> >>> > that should be fine, no?
> >>>
> >>> Probably. Can a tool like avconv or avplay playback the file
> >>> succesfully without throwing errors?
> >>
> >> Yes. Plays back with no errors at all.
> >
> > Can we see your full code? It's possible you're initializing the code
> > at the wrong moment when these things aren't known yet...
>
> Sure thing: https://github.com/ibsh/is_KeyFinder/blob/master/decoderlibav.cpp
>
> Although the function at line 155 (which is probably the one you're
> most interested) now does its memory management with av_malloc as
> mentioned earlier in the thread, I just haven't merged that commit
> yet:
>
> int LibAvDecoder::decodePacket(AVCodecContext* cCtx, AVPacket* avpkt,
> AudioStream* ab){
>  while(avpkt->size > 0){
>    int outputBufferSize = ((AVCODEC_MAX_AUDIO_FRAME_SIZE * 3) / 2) *
> sizeof(int16_t);
>    int16_t* outputBuffer = (int16_t*)av_malloc(outputBufferSize);
>    int bytesConsumed = avcodec_decode_audio3(cCtx, outputBuffer,
> &outputBufferSize, avpkt);
>    if(bytesConsumed <= 0){
>      avpkt->size = 0;
>      av_free(outputBuffer);
>      return 1;
>    }
>    int newSamplesDecoded = outputBufferSize / sizeof(int16_t);
>    int oldSampleCount = ab->getSampleCount();
>    try{
>      ab->addToSampleCount(newSamplesDecoded);
>    }catch(Exception& e){
>      av_free(outputBuffer);
>      throw e;
>    }
>    for(int i = 0; i < newSamplesDecoded; i++)
>      ab->setSample(oldSampleCount+i, (float)outputBuffer[i]);
>    if(bytesConsumed < avpkt->size){
>      size_t newLength = avpkt->size - bytesConsumed;
>      uint8_t* datacopy = avpkt->data;
>      avpkt->data = (uint8_t*)av_malloc(newLength);
>      memcpy(avpkt->data, datacopy + bytesConsumed, newLength);
>      av_free(datacopy);
>    }
>    avpkt->size -= bytesConsumed;
>    av_free(outputBuffer);
>  }
>  return 0;
> }
>
> Ibrahim

What do you think, Ronald? Can you see an initialisation problem?

I've been poring over this myself but I just can't see any issues with
the memory allocation, though I must admit I'm not happy with the
memcpy to reduce the packet data.

Am I barking up the wrong tree, do you think? I've been toying with
starting from first principles and remodelling what avplay does, since
it seems to avoid the decoding errors. But if the issue is in the
parallelisation, that may not help with the segfault.

Regards
Ibrahim


More information about the libav-api mailing list