[FFmpeg-devel] [PATCH 1/3] avcodec/avpacket: add av_packet_resize()
Marton Balint
cus at passwd.hu
Fri Mar 12 19:09:43 EET 2021
On Thu, 11 Mar 2021, James Almer wrote:
> On 3/11/2021 7:40 PM, Marton Balint wrote:
>>
>>
>> On Thu, 11 Mar 2021, James Almer wrote:
>>
>>> On 3/11/2021 1:11 PM, Marton Balint wrote:
>>>>
>>>>
>>>> On Thu, 11 Mar 2021, James Almer wrote:
>>>>
>>>>> This function acts as a replacement for both av_grow_packet() and
>>>>> av_shrink_packet(), the latter which is now deprecated and will be
>>>>> removed as
>>>>> it does not correctly handle non-writable packets.
>>>>
>>>> I don't think this is a good idea, av_shrink_packet cannot fail,
>>>> av_grow_packet can. By using the same function you are losing the
>>>> information if the end result should be checked or not.
>>>
>>> I'm not sure i follow. av_shrink_packet() is not being changed at all,
>>> just deprecated, scheduled for removal, and its use discouraged.
>>
>> But why are you complicating code with mandatory return value checking?
>
> Because unlike av_shrink_packet(), av_packet_resize() is more thorough
> when handling AVPackets and allows new usage scenarios that were not
> allowed with the former, thus it can fail.
>
>> Because as soon as a function returns an error, you have to check it,
>> and forward it upwards.
>
> Is error checking that much of a problem? I don't understand why it
> bothers people so much.
>
>>
>>> Maybe i should have split this in two, one to add av_packet_resize()
>>> and one to deprecate av_shrink_packet(), to avoid confusion.
>>>
>>> In any case, the fact av_shrink_packet() cannot fail is the reason I'm
>>> getting rid of it. It's zeroing the padding without bothering to check
>>> if the packet is writable at all.
>>
>> Add an assert to it then.
>
> We only assert on internal bugs, not invalid arguments passed by callers
> to a public function. The asserts would need to be added above each
> av_shrink_packet() call.
There are a lot of cases when we assert for bad API usage. See
av_frame_ref() or av_frame_move_ref(). We assert if the dst is not empty.
> And that's only for our internal uses of the
> function. It does nothing to the issue of it being public API that can't
> properly handle AVPackets in their current form.
>
> > Shrinking a non-writable packet seems bad API usage anyways.
>
> I get a packet from a demuxer. It contains two independent portions
> (NALUs, OBUs, etc) i want to separate in order to feed them to something
> like a multi threaded decoder. And so I create a new reference to it,
> resulting in two packets pointing to the same data. I shrink one to only
> contain the first portion, and i add the required byte offset to the
> data pointer and subtract it to the size field on the second packet so
> it contains only the second portion.
> The result if i use av_packet_resize() will be two valid, properly
> padded packets containing their respective expected data, but if i use
> av_shrink_packet(), the result will be the packet with the second
> portion featuring padding bytes worth of data zeroed at the start of its
> payload.
This looks like an unfortunate example, since you are:
- adding a reference to the packet, so you don't have to duplicate data
- and then want to add zero padding to the partial packet, so you will
duplicate data.
And I think the padding does not have to be zero for the partial packet.
>
> I'm sure there are other similar valid scenarios where attempting to
> shrink a non writable packet is not "bad API usage".
>
>>
>> If you want to shrink a writable packet, then maybe you don't even need
>> zero padding, because the buffer possibly already contains some defined
>> value, and the main reason of zero padding is avoiding reading
>> uninitialized data...
>
> If i allocate a payload of size 1024, ultimately fill only 512 bytes,
> then resize it to that value (typical scenario in lavf demuxers), if i
> don't zero the bytes after the 512 offset then they will remain
> uninitialized.
I am not sure I see your point here, if the data after the padding is
uninitalized, that is not a problem. I made a typo above, and meant
non-writable packet in my comment. And my reasoning is that if a packet is
non-writable, it already contains initialized data with a zero padding. If
you shrink that by reducing pkt->size only, you will not have
uninitialized data, only the padding will not be zeroed. And that is
preferable to copying the data only for zeroing the padding, because - as
far as I know - the padding does not have to be zeroed, it only have to be
initialized.
I agree that it is not nice that av_shrink_packet() writes something to
the packet, people may not think about it and misuse it instead of
directly decreaseing pkt->size when they need a partial packet. That is
why I suggested the assert(). One might argue that it kind of breaks
behaviour, but I'd say it does not break it too much, and writing to a
non-writable packet was broken in the first place.
Alternatively we can change av_shrink_packet() to only zero the padding if
the packet is writable, which has the benefit that it will do what people
generally expect, no matter if you throw a writable or a non-writable
packet to it.
A third alternative is to introduce void av_shrink_packet2() in which you
explicitly document that a writable packet is needed and do the assert
there, and deprecate av_shrink_packet().
Regards,
Marton
More information about the ffmpeg-devel
mailing list