[FFmpeg-devel] [PATCH+RFC] AVFrame for audio

Justin Ruggles justin.ruggles
Sat Oct 23 16:03:12 CEST 2010


Justin Ruggles wrote:

> Michael Niedermayer wrote:
> 
>> On Sat, Oct 16, 2010 at 04:12:26PM -0400, Justin Ruggles wrote:
>>> Michael Niedermayer wrote:
>>>
>>>> On Fri, Oct 15, 2010 at 06:35:01PM -0400, Justin Ruggles wrote:
>>>>> Justin Ruggles wrote:
>>>>>
>>>>>> Michael Niedermayer wrote:
>>>>>>
>>>>>>> On Wed, Oct 13, 2010 at 07:52:12PM -0400, Justin Ruggles wrote:
>>>>>>>> Michael Niedermayer wrote:
>>>>>>>>
>>>>>>>>> On Wed, Oct 06, 2010 at 11:05:26AM -0400, Justin Ruggles wrote:
>>>>>>>>>> Michael Niedermayer wrote:
>>>>>>>>>>
>>>>>>>>>>> On Tue, Oct 05, 2010 at 04:55:12PM -0400, Justin Ruggles wrote:
>>>>>>>>>>>> Michael Niedermayer wrote:
>>>>>>>>>>>>
>>>>>>>>>>>>> On Wed, Sep 29, 2010 at 09:20:04PM -0400, Justin Ruggles wrote:
>>>>>>>>>>>>>> Hi,
>>>>>>>>>>>>>>
>>>>>>>>>>>>>> Peter Ross wrote:
>>>>>>>>>>>>>>
>>>>>>>>>>>>>>> On Thu, Sep 02, 2010 at 07:11:37PM -0400, Justin Ruggles wrote:
>>>>>>>>>>>>>>>> Hi,
>>>>>>>>> [...]
>>>>>>>>>>>>> [...]
>>>>>>>>>>>>>> @@ -644,29 +677,49 @@
>>>>>>>>>>>>>>  }
>>>>>>>>>>>>>>  #endif
>>>>>>>>>>>>>>  
>>>>>>>>>>>>>> +#if LIBAVCODEC_VERSION_MAJOR < 53
>>>>>>>>>>>>>>  int attribute_align_arg avcodec_decode_audio3(AVCodecContext *avctx, int16_t *samples,
>>>>>>>>>>>>>>                           int *frame_size_ptr,
>>>>>>>>>>>>>>                           AVPacket *avpkt)
>>>>>>>>>>>>>>  {
>>>>>>>>>>>>>> +    AVFrame frame;
>>>>>>>>>>>>>> +    int ret, got_frame = 0;
>>>>>>>>>>>>>> +
>>>>>>>>>>>>>> +    avcodec_get_frame_defaults(&frame);
>>>>>>>>>>>>>> +
>>>>>>>>>>>>>> +    ret = avcodec_decode_audio4(avctx, &frame, &got_frame, avpkt);
>>>>>>>>>>>>>> +
>>>>>>>>>>>>>> +    if (ret >= 0 && got_frame) {
>>>>>>>>>>>>>> +        *frame_size_ptr = frame.nb_samples * avctx->channels *
>>>>>>>>>>>>>> +                          (av_get_bits_per_sample_format(avctx->sample_fmt) / 8);
>>>>>>>>>>>>>> +
>>>>>>>>>>>>>> +        /* ensure data will fit in the output buffer */
>>>>>>>>>>>>>> +        if (*frame_size_ptr > AVCODEC_MAX_AUDIO_FRAME_SIZE) {
>>>>>>>>>>>>>> +            av_log(avctx, AV_LOG_WARNING, "avcodec_decode_audio3 samples "
>>>>>>>>>>>>>> +                   "truncated to AVCODEC_MAX_AUDIO_FRAME_SIZE\n");
>>>>>>>>>>>>>> +            *frame_size_ptr = AVCODEC_MAX_AUDIO_FRAME_SIZE;
>>>>>>>>>>>>>> +        }
>>>>>>>>>>>>>> +
>>>>>>>>>>>>>> +        memcpy(samples, frame.data[0], *frame_size_ptr);
>>>>>>>>>>>>>  the default get_buffer() should return the appropriate
>>>>>>>>>>>>> buffer for this case.
>>>>>>>>>>>> I'm sorry, I don't understand your comment.
>>>>>>>>>>> i mean (non functional psseudocode below to explain the idea)
>>>>>>>>>>> avcodec_decode_audio3(){
>>>>>>>>>>>     avctx->foobar= samples;
>>>>>>>>>>>     ret = avcodec_decode_audio4(avctx, &frame, &got_frame, avpkt);
>>>>>>>>>>>     ...
>>>>>>>>>>>     assert(samples == frame.data[0]);
>>>>>>>>>>>
>>>>>>>>>>> -----
>>>>>>>>>>> default_get_buffer(){
>>>>>>>>>>>     if(avctx->foobar)
>>>>>>>>>>>         return avctx->foobar;
>>>>>>>>>>>
>>>>>>>>>>>
>>>>>>>>>>> (and yes this cannot work for all theoretical decoders)
>>>>>>>>>> I think I get it.  So avctx->foobar would be an optional user-supplied
>>>>>>>>>> buffer (avctx->user_buffer?) that default_get_buffer() would return if
>>>>>>>>>> it is non-NULL, right?
>>>>>>>>> yes
>>>>>>>>>
>>>>>>>>>
>>>>>>>>>> The problem I see is this:
>>>>>>>>>> avcodec_decode_audio3() would use avcodec_decode_audio4().
>>>>>>>>>> avcodec_decode_audio4() allocates as large a buffer as is needed through
>>>>>>>>>> get_buffer(), but the avcodec_decode_audio3() API only requires the
>>>>>>>>>> user-supplied buffer to be AVCODEC_MAX_AUDIO_FRAME_SIZE.  Couldn't this
>>>>>>>>>> lead to the decoder writing past the end of a user-supplied buffer if it
>>>>>>>>>> isn't large enough?  I guess we could also add a field
>>>>>>>>>> avctx->user_buffer_size?
>>>>>>>>> yes, of course
>>>>>>>>> it was just a rough idea ...
>>>>>>>> I'm running into some questions trying to implement the rough idea.  The
>>>>>>>> only way I can see this working smoothly is if avcodec_decode_audio3()
>>>>>>>> always sets get/release_buffer to default.  Also, either all audio
>>>>>>>> decoders will have to support CODEC_CAP_DR1 (i.e. they always use
>>>>>>>> get/release_buffer) or there needs to be a fallback that will memcpy
>>>>>>>> into the user buffer if CODEC_CAP_DR1 is not supported.
>>>>>>> old API decoders surely dont need to copy with old API.
>>>>>>> old API decoders surely dont need to copy with new API if the api can provide
>>>>>>> a buffer to the decoder (this can be through function argument like its done
>>>>>>> currently)
>>>>>>> new API decoders surely dont need to copy with new API because otherwise the
>>>>>>> API sucks and needs more work
>>>>>>> whats left is new API decoders and used with old API and for this get_buffer()
>>>>>>> should return the user supplied buffer if its large enough and fail if its not
>>>>>>> large enough.
>>>>>>> The case where the user overrides get_buffer() and supplies a user specified
>>>>>>> buffer which its own code doesnt use is a case that id consider user error.
>>>>>> I think I might have been misinterpreting the API.  For video decoders,
>>>>>> what does it mean as far as buffer allocation when CODEC_CAP_DR1 is not set?
>>>>> So I think I have this worked out and I don't see how we can avoid a
>>>>> memcpy with the old API when CODEC_CAP_DR1 is not set.  There would be
>>>>> no other way to get the data into the correct output buffer.
>>>>>
>>>>> other questions:
>>>>>
>>>>> 1. Should AVCodecContext.user_buffer be supported for video decoders?
>>>> possible but this is seperate, lets not entangle this patch with too many
>>>> other changes
>>>>
>>>>
>>>>> If so, should it be user_buffer[4] and user_buffer_size[4]?
>>>> possible
>>>>
>>>>
>>>>
>>>>> 2. avcodec_default_get_buffer() supports allocating multiple internal
>>>>> buffers.  How should that be handled if the buffer is supplied by the
>>>>> user?  Don't support multiple buffers?  Use the user-supplied buffer
>>>>> just for the first one?
>>>> there are buffer hints (grep for hint in avcodec.h) that specify if a buffer
>>>> will be reused/read/preserved/blah
>>>> the user supplied buffer is likely just valid for this call and cannot be used
>>>> for some cases of the hints. For what remains using the buffer on the first
>>>> call only seems ok
>>> I think I've implemented it in a way that will work even when the
>>> various buffer hints are set.  This implementation will not use memcpy
>>> in avcodec_decode_audio3() in the most common case of the decoder
>>> supporting CODEC_CAP_DR1, only needing 1 buffer, and not needing a
>>> buffer larger than AVCODEC_MAX_AUDIO_FRAME_SIZE.
>>>
>>> One thing I'm unsure of is whether to truncate output if it is too large
>>> for avcodec_decode_audio3() (which is done in this patch) or to return
>>> an error instead.
>> I think its better to tell the user straight through an error that there is a
>> problem instead of generating output that contains randomly truncated packets
> 
> Ok. New patch.

So does this look ok as far as the buffering and API and such?  If so I
will start going through each audio decoder to change to the new API.  I
just don't want to waste my time with that until it's agreed that this
approach is ok.

-Justin



More information about the ffmpeg-devel mailing list