diff mbox

[FFmpeg-devel,2/7] decode: add a method for attaching lavc-internal data to frames

Message ID 20171003131518.4557-3-nfxjfg@googlemail.com
State Superseded
Headers show

Commit Message

wm4 Oct. 3, 2017, 1:15 p.m. UTC
From: Anton Khirnov <anton@khirnov.net>

Use the AVFrame.opaque_ref field. The original user's opaque_ref is
wrapped in the lavc struct and then unwrapped before the frame is
returned to the caller.

This new struct will be useful in the following commits.

Merges Libav commit 359a8a3e2d1194b52b6c386f94fd0929567dfb67.
---
 libavcodec/decode.c | 61 +++++++++++++++++++++++++++++++++++++++++++++++++++--
 libavcodec/decode.h | 13 ++++++++++++
 2 files changed, 72 insertions(+), 2 deletions(-)

Comments

Michael Niedermayer Oct. 3, 2017, 7:40 p.m. UTC | #1
On Tue, Oct 03, 2017 at 03:15:13PM +0200, wm4 wrote:
> From: Anton Khirnov <anton@khirnov.net>
> 

> Use the AVFrame.opaque_ref field. The original user's opaque_ref is
> wrapped in the lavc struct and then unwrapped before the frame is
> returned to the caller.

this is a ugly hack

one and the same field should not be used to hold both the
users opaque_ref as well as a structure which is itself not a user
opaque_ref

[...]
wm4 Oct. 4, 2017, 7:12 a.m. UTC | #2
On Tue, 3 Oct 2017 21:40:58 +0200
Michael Niedermayer <michael@niedermayer.cc> wrote:

> On Tue, Oct 03, 2017 at 03:15:13PM +0200, wm4 wrote:
> > From: Anton Khirnov <anton@khirnov.net>
> >   
> 
> > Use the AVFrame.opaque_ref field. The original user's opaque_ref is
> > wrapped in the lavc struct and then unwrapped before the frame is
> > returned to the caller.  
> 
> this is a ugly hack
> 
> one and the same field should not be used to hold both the
> users opaque_ref as well as a structure which is itself not a user
> opaque_ref

While the AVFrame is within libavcodec, it's libavcodec's frame, not
the user's. Thus your claim doesn't make too much sense. libavcodec
fully controls the meaning for its own AVFrames' opaque_ref, but
reconstruct the user's value when returning it.

Though to be honest, I'd just have defined that get_buffer does not
allow the field to be set.
Michael Niedermayer Oct. 4, 2017, 9:22 a.m. UTC | #3
On Wed, Oct 04, 2017 at 09:12:29AM +0200, wm4 wrote:
> On Tue, 3 Oct 2017 21:40:58 +0200
> Michael Niedermayer <michael@niedermayer.cc> wrote:
> 
> > On Tue, Oct 03, 2017 at 03:15:13PM +0200, wm4 wrote:
> > > From: Anton Khirnov <anton@khirnov.net>
> > >   
> > 
> > > Use the AVFrame.opaque_ref field. The original user's opaque_ref is
> > > wrapped in the lavc struct and then unwrapped before the frame is
> > > returned to the caller.  
> > 
> > this is a ugly hack
> > 
> > one and the same field should not be used to hold both the
> > users opaque_ref as well as a structure which is itself not a user
> > opaque_ref
> 
> While the AVFrame is within libavcodec, it's libavcodec's frame, not
> the user's. Thus your claim doesn't make too much sense. libavcodec
> fully controls the meaning for its own AVFrames' opaque_ref, but
> reconstruct the user's value when returning it.

i disagree
such hacks should not be added, we do have enough hacks already

AVFrames are not really seperated into isolated classes
There arent "the users AVFrames" vs. "the internal AVFrames"

its fragile to create and maintain such seperation with interfaces
that all wrap and unwrap the opaque_ref. Any mistake being a potential
security issue and or crash

Its MUCH more robust and also easier to understand to use a sperate
field
more so, opaque_ref is used in only 5 lines in the whole codebase,
so there is not much code to consider when using a different solution

[...]
wm4 Oct. 4, 2017, 9:34 a.m. UTC | #4
On Wed, 4 Oct 2017 11:22:37 +0200
Michael Niedermayer <michael@niedermayer.cc> wrote:

> On Wed, Oct 04, 2017 at 09:12:29AM +0200, wm4 wrote:
> > On Tue, 3 Oct 2017 21:40:58 +0200
> > Michael Niedermayer <michael@niedermayer.cc> wrote:
> >   
> > > On Tue, Oct 03, 2017 at 03:15:13PM +0200, wm4 wrote:  
> > > > From: Anton Khirnov <anton@khirnov.net>
> > > >     
> > >   
> > > > Use the AVFrame.opaque_ref field. The original user's opaque_ref is
> > > > wrapped in the lavc struct and then unwrapped before the frame is
> > > > returned to the caller.    
> > > 
> > > this is a ugly hack
> > > 
> > > one and the same field should not be used to hold both the
> > > users opaque_ref as well as a structure which is itself not a user
> > > opaque_ref  
> > 
> > While the AVFrame is within libavcodec, it's libavcodec's frame, not
> > the user's. Thus your claim doesn't make too much sense. libavcodec
> > fully controls the meaning for its own AVFrames' opaque_ref, but
> > reconstruct the user's value when returning it.  
> 
> i disagree

Well, you're wrong anyway.

> such hacks should not be added, we do have enough hacks already

It's not a hack.

> AVFrames are not really seperated into isolated classes
> There arent "the users AVFrames" vs. "the internal AVFrames"

Oh yes, there is the concept of an "owner" of an AVFrame, and the owner
of the AVFrame decides what opaque_ref means. It's quite literally for
free use by the owner of the reference.

That the code goes through some acrobatics to preserve opaque_ref as
passed in by get_buffer is just a feature.

> its fragile to create and maintain such seperation with interfaces
> that all wrap and unwrap the opaque_ref. Any mistake being a potential
> security issue and or crash

This is done strictly when returning a valid AVFrame, so there is no
room for mistakes.

> Its MUCH more robust and also easier to understand to use a sperate
> field

No, it's not. If you fail to do call post_process() on returned
AVFrames (which is done by the same code which exchanges opaque_ref)
you have bugs that violate the API or crash anyway.

> more so, opaque_ref is used in only 5 lines in the whole codebase,
> so there is not much code to consider when using a different solution

We shouldn't add such special fields, we have enough hacks already. Is
that your only suggestion how to do this? Because it's a bad one.
Michael Niedermayer Oct. 4, 2017, 9:47 a.m. UTC | #5
On Wed, Oct 04, 2017 at 11:34:18AM +0200, wm4 wrote:
> On Wed, 4 Oct 2017 11:22:37 +0200
> Michael Niedermayer <michael@niedermayer.cc> wrote:
> 
> > On Wed, Oct 04, 2017 at 09:12:29AM +0200, wm4 wrote:
> > > On Tue, 3 Oct 2017 21:40:58 +0200
> > > Michael Niedermayer <michael@niedermayer.cc> wrote:
> > >   
> > > > On Tue, Oct 03, 2017 at 03:15:13PM +0200, wm4 wrote:  
> > > > > From: Anton Khirnov <anton@khirnov.net>
> > > > >     
> > > >   
> > > > > Use the AVFrame.opaque_ref field. The original user's opaque_ref is
> > > > > wrapped in the lavc struct and then unwrapped before the frame is
> > > > > returned to the caller.    
> > > > 
> > > > this is a ugly hack
> > > > 
> > > > one and the same field should not be used to hold both the
> > > > users opaque_ref as well as a structure which is itself not a user
> > > > opaque_ref  
> > > 
> > > While the AVFrame is within libavcodec, it's libavcodec's frame, not
> > > the user's. Thus your claim doesn't make too much sense. libavcodec
> > > fully controls the meaning for its own AVFrames' opaque_ref, but
> > > reconstruct the user's value when returning it.  
> > 
> > i disagree
> 
> Well, you're wrong anyway.
> 
> > such hacks should not be added, we do have enough hacks already
> 
> It's not a hack.

please accept my veto to this patch.

also, please stop sending me insults.

    * Loaded log from Sun Feb 26 13:41:05 2017
    11:34  <wm4> I don't want to hear this from the king of ugly hacks

thanks

[...]
wm4 Oct. 4, 2017, 10:04 a.m. UTC | #6
On Wed, 4 Oct 2017 11:47:39 +0200
Michael Niedermayer <michael@niedermayer.cc> wrote:

> On Wed, Oct 04, 2017 at 11:34:18AM +0200, wm4 wrote:
> > On Wed, 4 Oct 2017 11:22:37 +0200
> > Michael Niedermayer <michael@niedermayer.cc> wrote:
> >   
> > > On Wed, Oct 04, 2017 at 09:12:29AM +0200, wm4 wrote:  
> > > > On Tue, 3 Oct 2017 21:40:58 +0200
> > > > Michael Niedermayer <michael@niedermayer.cc> wrote:
> > > >     
> > > > > On Tue, Oct 03, 2017 at 03:15:13PM +0200, wm4 wrote:    
> > > > > > From: Anton Khirnov <anton@khirnov.net>
> > > > > >       
> > > > >     
> > > > > > Use the AVFrame.opaque_ref field. The original user's opaque_ref is
> > > > > > wrapped in the lavc struct and then unwrapped before the frame is
> > > > > > returned to the caller.      
> > > > > 
> > > > > this is a ugly hack
> > > > > 
> > > > > one and the same field should not be used to hold both the
> > > > > users opaque_ref as well as a structure which is itself not a user
> > > > > opaque_ref    
> > > > 
> > > > While the AVFrame is within libavcodec, it's libavcodec's frame, not
> > > > the user's. Thus your claim doesn't make too much sense. libavcodec
> > > > fully controls the meaning for its own AVFrames' opaque_ref, but
> > > > reconstruct the user's value when returning it.    
> > > 
> > > i disagree  
> > 
> > Well, you're wrong anyway.
> >   
> > > such hacks should not be added, we do have enough hacks already  
> > 
> > It's not a hack.  
> 
> please accept my veto to this patch.

That's completely unreasonable. You didn't even respond to my
arguments. I can't accept your veto.

> also, please stop sending me insults.
> 
>     * Loaded log from Sun Feb 26 13:41:05 2017
>     11:34  <wm4> I don't want to hear this from the king of ugly hacks

I have the feeling your objections to this patch were bullshit in the
first place, so I overreacted a little. But this "insult" wasn't meant
to be public, so this is up to you.

Anyway, you certainly never had problems with adding ugly hacks. It's
possibly that you don't even deny this in most cases, but that you felt
they were absolute "necessary" still.
Tobias Rapp Oct. 4, 2017, 11:37 a.m. UTC | #7
On 04.10.2017 11:34, wm4 wrote:
> On Wed, 4 Oct 2017 11:22:37 +0200
> Michael Niedermayer <michael@niedermayer.cc> wrote:
> 
>> On Wed, Oct 04, 2017 at 09:12:29AM +0200, wm4 wrote:
>>> On Tue, 3 Oct 2017 21:40:58 +0200
>>> Michael Niedermayer <michael@niedermayer.cc> wrote:
>>>    
>>>> On Tue, Oct 03, 2017 at 03:15:13PM +0200, wm4 wrote:
>>>>> From: Anton Khirnov <anton@khirnov.net>
>>>>>      
>>>>    
>>>>> Use the AVFrame.opaque_ref field. The original user's opaque_ref is
>>>>> wrapped in the lavc struct and then unwrapped before the frame is
>>>>> returned to the caller.
>>>>
>>>> this is a ugly hack
>>>>
>>>> one and the same field should not be used to hold both the
>>>> users opaque_ref as well as a structure which is itself not a user
>>>> opaque_ref
>>>
>>> While the AVFrame is within libavcodec, it's libavcodec's frame, not
>>> the user's. Thus your claim doesn't make too much sense. libavcodec
>>> fully controls the meaning for its own AVFrames' opaque_ref, but
>>> reconstruct the user's value when returning it.
>>
>> i disagree
> 
> Well, you're wrong anyway.
> 
>> such hacks should not be added, we do have enough hacks already
> 
> It's not a hack.

Changing the semantics of a field during its lifetime, even when only 
done within private code, is at least unexpected behavior.

>> AVFrames are not really seperated into isolated classes
>> There arent "the users AVFrames" vs. "the internal AVFrames"
> 
> Oh yes, there is the concept of an "owner" of an AVFrame, and the owner
> of the AVFrame decides what opaque_ref means. It's quite literally for
> free use by the owner of the reference.
> 
> That the code goes through some acrobatics to preserve opaque_ref as
> passed in by get_buffer is just a feature.
> 
>> its fragile to create and maintain such seperation with interfaces
>> that all wrap and unwrap the opaque_ref. Any mistake being a potential
>> security issue and or crash
> 
> This is done strictly when returning a valid AVFrame, so there is no
> room for mistakes.

The room for mistake might not increase for external developers but it 
increases for internal developers (maintenance cost).

>> Its MUCH more robust and also easier to understand to use a sperate
>> field
> 
> No, it's not. If you fail to do call post_process() on returned
> AVFrames (which is done by the same code which exchanges opaque_ref)
> you have bugs that violate the API or crash anyway.
> 
>> more so, opaque_ref is used in only 5 lines in the whole codebase,
>> so there is not much code to consider when using a different solution
> 
> We shouldn't add such special fields, we have enough hacks already. Is
> that your only suggestion how to do this? Because it's a bad one.

What would be the drawback of using a separate field?

And please try to reduce the amount of emotions in this thread, and 
increase the amount of objective reasons.

Regards,
Tobias
wm4 Oct. 4, 2017, 12:04 p.m. UTC | #8
On Wed, 4 Oct 2017 13:37:31 +0200
Tobias Rapp <t.rapp@noa-archive.com> wrote:

> On 04.10.2017 11:34, wm4 wrote:
> > On Wed, 4 Oct 2017 11:22:37 +0200
> > Michael Niedermayer <michael@niedermayer.cc> wrote:
> >   
> >> On Wed, Oct 04, 2017 at 09:12:29AM +0200, wm4 wrote:  
> >>> On Tue, 3 Oct 2017 21:40:58 +0200
> >>> Michael Niedermayer <michael@niedermayer.cc> wrote:
> >>>      
> >>>> On Tue, Oct 03, 2017 at 03:15:13PM +0200, wm4 wrote:  
> >>>>> From: Anton Khirnov <anton@khirnov.net>
> >>>>>        
> >>>>      
> >>>>> Use the AVFrame.opaque_ref field. The original user's opaque_ref is
> >>>>> wrapped in the lavc struct and then unwrapped before the frame is
> >>>>> returned to the caller.  
> >>>>
> >>>> this is a ugly hack
> >>>>
> >>>> one and the same field should not be used to hold both the
> >>>> users opaque_ref as well as a structure which is itself not a user
> >>>> opaque_ref  
> >>>
> >>> While the AVFrame is within libavcodec, it's libavcodec's frame, not
> >>> the user's. Thus your claim doesn't make too much sense. libavcodec
> >>> fully controls the meaning for its own AVFrames' opaque_ref, but
> >>> reconstruct the user's value when returning it.  
> >>
> >> i disagree  
> > 
> > Well, you're wrong anyway.
> >   
> >> such hacks should not be added, we do have enough hacks already  
> > 
> > It's not a hack.  
> 
> Changing the semantics of a field during its lifetime, even when only 
> done within private code, is at least unexpected behavior.

That's not done. Conceptually the AVFrame with the changed behavior is
a new reference. Internally, AVFrame.opaque_ref will always have the
same semantics, pointing to the FrameDecodeData struct. Only at points
where the AVFrame ref is converted to/from the user struct this is
changed.

> > This is done strictly when returning a valid AVFrame, so there is no
> > room for mistakes.  
> 
> The room for mistake might not increase for external developers but it 
> increases for internal developers (maintenance cost).

Like where? There are only 2 places where the code needs to deal with
it, and these are in shared code, not individual decoders.

There are other cases where this will be needed, like fixing
videotoolbox with frame threading.

> >> Its MUCH more robust and also easier to understand to use a sperate
> >> field  
> > 
> > No, it's not. If you fail to do call post_process() on returned
> > AVFrames (which is done by the same code which exchanges opaque_ref)
> > you have bugs that violate the API or crash anyway.
> >   
> >> more so, opaque_ref is used in only 5 lines in the whole codebase,
> >> so there is not much code to consider when using a different solution  
> > 
> > We shouldn't add such special fields, we have enough hacks already. Is
> > that your only suggestion how to do this? Because it's a bad one.  
> 
> What would be the drawback of using a separate field?

That would add a field that is merely needed for an implementation
detail within libavcodec. Would you argue adding one for each case we
encounter? Can user applications request the addition of arbitrary
fields as well, which they might need internally?

opaque_ref is basically a priv pointer, which _always_ has different
meanings depending on the context where it's used. For example, what
does AVCodecContext.priv_data point to? Or AVCodecContext.opaque? It's
even worse with av_log(), which gets a void*, but somehow expects it to
be "something" (a struct where the first member is AVClass* or so). So
don't pretend this commits adds anything confusing if you're fine with
the av_log() shit, or the way how most codecs/filters/(de)muxers are
implemented.

In any case, feel free to make a better suggestion for implementing
this, which doesn't require adding pointless fields to AVFrame. This
is just a Libav merge too - if you care about what gets merged, discuss
it with the original author on the libav-devel mailing list before it
gets committed. I shouldn't have to do this discussion in the author's
place. (In fact I had a similar discussion with the author.)
Carl Eugen Hoyos Oct. 5, 2017, 7:02 a.m. UTC | #9
2017-10-04 14:04 GMT+02:00 wm4 <nfxjfg@googlemail.com>:

> if you care about what gets merged, discuss it with the
> original author on the libav-devel mailing list before it
> gets committed.

You do realize that you are asking for something that
is not possible - did you forget?

Carl Eugen
wm4 Oct. 5, 2017, 8:22 a.m. UTC | #10
On Thu, 5 Oct 2017 09:02:10 +0200
Carl Eugen Hoyos <ceffmpeg@gmail.com> wrote:

> 2017-10-04 14:04 GMT+02:00 wm4 <nfxjfg@googlemail.com>:
> 
> > if you care about what gets merged, discuss it with the
> > original author on the libav-devel mailing list before it
> > gets committed.  
> 
> You do realize that you are asking for something that
> is not possible - did you forget?

Yes, I forgot that it's impossible for you to communicate like a normal
human being. Sorry I can't deal with all your bullshit all at once.
Michael Niedermayer Oct. 5, 2017, 4:47 p.m. UTC | #11
On Wed, Oct 04, 2017 at 02:04:54PM +0200, wm4 wrote:
> On Wed, 4 Oct 2017 13:37:31 +0200
> Tobias Rapp <t.rapp@noa-archive.com> wrote:
> 
> > On 04.10.2017 11:34, wm4 wrote:
> > > On Wed, 4 Oct 2017 11:22:37 +0200
> > > Michael Niedermayer <michael@niedermayer.cc> wrote:
> > >   
> > >> On Wed, Oct 04, 2017 at 09:12:29AM +0200, wm4 wrote:  
> > >>> On Tue, 3 Oct 2017 21:40:58 +0200
> > >>> Michael Niedermayer <michael@niedermayer.cc> wrote:
> > >>>      
> > >>>> On Tue, Oct 03, 2017 at 03:15:13PM +0200, wm4 wrote:  
> > >>>>> From: Anton Khirnov <anton@khirnov.net>
> > >>>>>        
> > >>>>      
> > >>>>> Use the AVFrame.opaque_ref field. The original user's opaque_ref is
> > >>>>> wrapped in the lavc struct and then unwrapped before the frame is
> > >>>>> returned to the caller.  
> > >>>>
> > >>>> this is a ugly hack
> > >>>>
> > >>>> one and the same field should not be used to hold both the
> > >>>> users opaque_ref as well as a structure which is itself not a user
> > >>>> opaque_ref  
> > >>>
> > >>> While the AVFrame is within libavcodec, it's libavcodec's frame, not
> > >>> the user's. Thus your claim doesn't make too much sense. libavcodec
> > >>> fully controls the meaning for its own AVFrames' opaque_ref, but
> > >>> reconstruct the user's value when returning it.  
> > >>
> > >> i disagree  
> > > 
> > > Well, you're wrong anyway.
> > >   
> > >> such hacks should not be added, we do have enough hacks already  
> > > 
> > > It's not a hack.  
> > 
> > Changing the semantics of a field during its lifetime, even when only 
> > done within private code, is at least unexpected behavior.
> 
> That's not done.

The semantics are defined by the docs, which state:
"AVBufferRef for free use by the API user."

And before the patch this is true, all instances of this field are
controled by the user application and are consistent.

after the patch the AVFrames used by a codec have their opaque_ref
replaced by a wraped structure relative to what the outside of this
codec has.


> Conceptually the AVFrame with the changed behavior is
> a new reference. Internally, AVFrame.opaque_ref will always have the
> same semantics, pointing to the FrameDecodeData struct. Only at points
> where the AVFrame ref is converted to/from the user struct this is
> changed.
> 
> > > This is done strictly when returning a valid AVFrame, so there is no
> > > room for mistakes.  
> > 
> > The room for mistake might not increase for external developers but it 
> > increases for internal developers (maintenance cost).
> 
> Like where? There are only 2 places where the code needs to deal with
> it, and these are in shared code, not individual decoders.

just greping for AVFrame in the headers shows callbacks, a direct
pointer to a AVFrame and the API functions that interface the codec

Just thinking of a codec that instanciates another codec and how
exactly the callback which may originate from the user or the outer
codec would unwrap the potential nested wraping.
I really dont think we want this in FFmpeg
And this is just one example ...


[...]
wm4 Oct. 5, 2017, 7:22 p.m. UTC | #12
On Thu, 5 Oct 2017 18:47:01 +0200
Michael Niedermayer <michael@niedermayer.cc> wrote:

> On Wed, Oct 04, 2017 at 02:04:54PM +0200, wm4 wrote:
> > On Wed, 4 Oct 2017 13:37:31 +0200
> > Tobias Rapp <t.rapp@noa-archive.com> wrote:
> >   
> > > On 04.10.2017 11:34, wm4 wrote:  
> > > > On Wed, 4 Oct 2017 11:22:37 +0200
> > > > Michael Niedermayer <michael@niedermayer.cc> wrote:
> > > >     
> > > >> On Wed, Oct 04, 2017 at 09:12:29AM +0200, wm4 wrote:    
> > > >>> On Tue, 3 Oct 2017 21:40:58 +0200
> > > >>> Michael Niedermayer <michael@niedermayer.cc> wrote:
> > > >>>        
> > > >>>> On Tue, Oct 03, 2017 at 03:15:13PM +0200, wm4 wrote:    
> > > >>>>> From: Anton Khirnov <anton@khirnov.net>
> > > >>>>>          
> > > >>>>        
> > > >>>>> Use the AVFrame.opaque_ref field. The original user's opaque_ref is
> > > >>>>> wrapped in the lavc struct and then unwrapped before the frame is
> > > >>>>> returned to the caller.    
> > > >>>>
> > > >>>> this is a ugly hack
> > > >>>>
> > > >>>> one and the same field should not be used to hold both the
> > > >>>> users opaque_ref as well as a structure which is itself not a user
> > > >>>> opaque_ref    
> > > >>>
> > > >>> While the AVFrame is within libavcodec, it's libavcodec's frame, not
> > > >>> the user's. Thus your claim doesn't make too much sense. libavcodec
> > > >>> fully controls the meaning for its own AVFrames' opaque_ref, but
> > > >>> reconstruct the user's value when returning it.    
> > > >>
> > > >> i disagree    
> > > > 
> > > > Well, you're wrong anyway.
> > > >     
> > > >> such hacks should not be added, we do have enough hacks already    
> > > > 
> > > > It's not a hack.    
> > > 
> > > Changing the semantics of a field during its lifetime, even when only 
> > > done within private code, is at least unexpected behavior.  
> > 
> > That's not done.  
> 
> The semantics are defined by the docs, which state:
> "AVBufferRef for free use by the API user."

libavcodec is the API user. I know the semantics of opaque_ref very
well btw., because I added it.

> And before the patch this is true, all instances of this field are
> controled by the user application and are consistent.

The "user" is the AVFrame user, which includes libavcodec.

> after the patch the AVFrames used by a codec have their opaque_ref
> replaced by a wraped structure relative to what the outside of this
> codec has.
> 
> 
> > Conceptually the AVFrame with the changed behavior is
> > a new reference. Internally, AVFrame.opaque_ref will always have the
> > same semantics, pointing to the FrameDecodeData struct. Only at points
> > where the AVFrame ref is converted to/from the user struct this is
> > changed.
> >   
> > > > This is done strictly when returning a valid AVFrame, so there is no
> > > > room for mistakes.    
> > > 
> > > The room for mistake might not increase for external developers but it 
> > > increases for internal developers (maintenance cost).  
> > 
> > Like where? There are only 2 places where the code needs to deal with
> > it, and these are in shared code, not individual decoders.  
> 
> just greping for AVFrame in the headers shows callbacks, a direct
> pointer to a AVFrame and the API functions that interface the codec

Do you mean get_buffer? I explained that in-depth.

> Just thinking of a codec that instanciates another codec and how
> exactly the callback which may originate from the user or the outer
> codec would unwrap the potential nested wraping.

That would happen only if you'd nest get_buffer in an incorrect way.
"Nested codecs" are an ugly hack anyway that are likely to break other
things, especially if get_buffer is used.

I see two decoders which recursively open other codecs (weird jpg
variants). Both would not be broken by this patch, because they don't
proxy get_buffer to the underlying codecs. (But what I see is that they
require shitty ugly hacks due to shitty ugly codec locking, which was
added as shitty ugly hack for shitty ugly broken shit. But apparently
accepting that kind of code in FFmpeg is strangely no problem.)

> I really dont think we want this in FFmpeg

Why so obstinate.

> And this is just one example ...

Your one example was invalid, next one please.
Carl Eugen Hoyos Oct. 5, 2017, 8:01 p.m. UTC | #13
2017-10-05 21:22 GMT+02:00 wm4 <nfxjfg@googlemail.com>:

>> And this is just one example ...
>
> Your one example was invalid, next one please.

One example is more than enough, we can all see that this
is not clean new code.

What is wrong about adding a new field if you really need it?

Carl Eugen
Mark Thompson Oct. 5, 2017, 8:03 p.m. UTC | #14
On 05/10/17 17:47, Michael Niedermayer wrote:
> On Wed, Oct 04, 2017 at 02:04:54PM +0200, wm4 wrote:
>> On Wed, 4 Oct 2017 13:37:31 +0200
>> Tobias Rapp <t.rapp@noa-archive.com> wrote:
>>
>>> On 04.10.2017 11:34, wm4 wrote:
>>>> On Wed, 4 Oct 2017 11:22:37 +0200
>>>> Michael Niedermayer <michael@niedermayer.cc> wrote:
>>>>   
>>>>> On Wed, Oct 04, 2017 at 09:12:29AM +0200, wm4 wrote:  
>>>>>> On Tue, 3 Oct 2017 21:40:58 +0200
>>>>>> Michael Niedermayer <michael@niedermayer.cc> wrote:
>>>>>>      
>>>>>>> On Tue, Oct 03, 2017 at 03:15:13PM +0200, wm4 wrote:  
>>>>>>>> From: Anton Khirnov <anton@khirnov.net>
>>>>>>>>        
>>>>>>>      
>>>>>>>> Use the AVFrame.opaque_ref field. The original user's opaque_ref is
>>>>>>>> wrapped in the lavc struct and then unwrapped before the frame is
>>>>>>>> returned to the caller.  
>>>>>>>
>>>>>>> this is a ugly hack
>>>>>>>
>>>>>>> one and the same field should not be used to hold both the
>>>>>>> users opaque_ref as well as a structure which is itself not a user
>>>>>>> opaque_ref  
>>>>>>
>>>>>> While the AVFrame is within libavcodec, it's libavcodec's frame, not
>>>>>> the user's. Thus your claim doesn't make too much sense. libavcodec
>>>>>> fully controls the meaning for its own AVFrames' opaque_ref, but
>>>>>> reconstruct the user's value when returning it.  
>>>>>
>>>>> i disagree  
>>>>
>>>> Well, you're wrong anyway.
>>>>   
>>>>> such hacks should not be added, we do have enough hacks already  
>>>>
>>>> It's not a hack.  
>>>
>>> Changing the semantics of a field during its lifetime, even when only 
>>> done within private code, is at least unexpected behavior.
>>
>> That's not done.
> 
> The semantics are defined by the docs, which state:
> "AVBufferRef for free use by the API user."
> 
> And before the patch this is true, all instances of this field are
> controled by the user application and are consistent.
> 
> after the patch the AVFrames used by a codec have their opaque_ref
> replaced by a wraped structure relative to what the outside of this
> codec has.
> 
> 
>> Conceptually the AVFrame with the changed behavior is
>> a new reference. Internally, AVFrame.opaque_ref will always have the
>> same semantics, pointing to the FrameDecodeData struct. Only at points
>> where the AVFrame ref is converted to/from the user struct this is
>> changed.
>>
>>>> This is done strictly when returning a valid AVFrame, so there is no
>>>> room for mistakes.  
>>>
>>> The room for mistake might not increase for external developers but it 
>>> increases for internal developers (maintenance cost).
>>
>> Like where? There are only 2 places where the code needs to deal with
>> it, and these are in shared code, not individual decoders.
> 
> just greping for AVFrame in the headers shows callbacks, a direct
> pointer to a AVFrame and the API functions that interface the codec
> 
> Just thinking of a codec that instanciates another codec and how
> exactly the callback which may originate from the user or the outer
> codec would unwrap the potential nested wraping.
> I really dont think we want this in FFmpeg
> And this is just one example ...

I don't understand this discussion.

As far as I can tell, the sequence is this:

* libavcodec allocates an AVFrame structure.
* libavcodec calls get_buffer2 with that AVFrame structure; the user fills its fields.
* libavcodec extracts the buffer references and metadata from the AVFrame, and maybe frees it (some codecs reuse a single AVFrame for the lifetime of the codec, others allocate them each time).
~ decoding happens, the buffers are written to ~
* The user allocates a new AVFrame structure.
* The user calls receive_frame with that new AVFrame structure; libavcodec its fields with references to the decoded data and associated metadata.
* The user can then read the buffers of the frame, along with its metadata.

Why would it matter what happens in the middle?  The AVFrame structure at the end is not the AVFrame structure at the start, and the user can't assume anything about it at all - if they try to dereference a pointer to the AVFrame supplied by libavcodec for get_buffer2 after get_buffer2 has returned then they are definitely invoking undefined behaviour.

- Mark
wm4 Oct. 5, 2017, 8:56 p.m. UTC | #15
On Thu, 5 Oct 2017 22:01:56 +0200
Carl Eugen Hoyos <ceffmpeg@gmail.com> wrote:

> 2017-10-05 21:22 GMT+02:00 wm4 <nfxjfg@googlemail.com>:
> 
> >> And this is just one example ...  
> >
> > Your one example was invalid, next one please.  
> 
> One example is more than enough, we can all see that this
> is not clean new code.

But I showed that his example isn't actually a problem.

> What is wrong about adding a new field if you really need it?

Because AVFrame shouldn't have internal libavcodec fields?
Michael Niedermayer Oct. 5, 2017, 10:01 p.m. UTC | #16
On Thu, Oct 05, 2017 at 09:03:40PM +0100, Mark Thompson wrote:
> On 05/10/17 17:47, Michael Niedermayer wrote:
> > On Wed, Oct 04, 2017 at 02:04:54PM +0200, wm4 wrote:
> >> On Wed, 4 Oct 2017 13:37:31 +0200
> >> Tobias Rapp <t.rapp@noa-archive.com> wrote:
> >>
> >>> On 04.10.2017 11:34, wm4 wrote:
> >>>> On Wed, 4 Oct 2017 11:22:37 +0200
> >>>> Michael Niedermayer <michael@niedermayer.cc> wrote:
> >>>>   
> >>>>> On Wed, Oct 04, 2017 at 09:12:29AM +0200, wm4 wrote:  
> >>>>>> On Tue, 3 Oct 2017 21:40:58 +0200
> >>>>>> Michael Niedermayer <michael@niedermayer.cc> wrote:
> >>>>>>      
> >>>>>>> On Tue, Oct 03, 2017 at 03:15:13PM +0200, wm4 wrote:  
> >>>>>>>> From: Anton Khirnov <anton@khirnov.net>
> >>>>>>>>        
> >>>>>>>      
> >>>>>>>> Use the AVFrame.opaque_ref field. The original user's opaque_ref is
> >>>>>>>> wrapped in the lavc struct and then unwrapped before the frame is
> >>>>>>>> returned to the caller.  
> >>>>>>>
> >>>>>>> this is a ugly hack
> >>>>>>>
> >>>>>>> one and the same field should not be used to hold both the
> >>>>>>> users opaque_ref as well as a structure which is itself not a user
> >>>>>>> opaque_ref  
> >>>>>>
> >>>>>> While the AVFrame is within libavcodec, it's libavcodec's frame, not
> >>>>>> the user's. Thus your claim doesn't make too much sense. libavcodec
> >>>>>> fully controls the meaning for its own AVFrames' opaque_ref, but
> >>>>>> reconstruct the user's value when returning it.  
> >>>>>
> >>>>> i disagree  
> >>>>
> >>>> Well, you're wrong anyway.
> >>>>   
> >>>>> such hacks should not be added, we do have enough hacks already  
> >>>>
> >>>> It's not a hack.  
> >>>
> >>> Changing the semantics of a field during its lifetime, even when only 
> >>> done within private code, is at least unexpected behavior.
> >>
> >> That's not done.
> > 
> > The semantics are defined by the docs, which state:
> > "AVBufferRef for free use by the API user."
> > 
> > And before the patch this is true, all instances of this field are
> > controled by the user application and are consistent.
> > 
> > after the patch the AVFrames used by a codec have their opaque_ref
> > replaced by a wraped structure relative to what the outside of this
> > codec has.
> > 
> > 
> >> Conceptually the AVFrame with the changed behavior is
> >> a new reference. Internally, AVFrame.opaque_ref will always have the
> >> same semantics, pointing to the FrameDecodeData struct. Only at points
> >> where the AVFrame ref is converted to/from the user struct this is
> >> changed.
> >>
> >>>> This is done strictly when returning a valid AVFrame, so there is no
> >>>> room for mistakes.  
> >>>
> >>> The room for mistake might not increase for external developers but it 
> >>> increases for internal developers (maintenance cost).
> >>
> >> Like where? There are only 2 places where the code needs to deal with
> >> it, and these are in shared code, not individual decoders.
> > 
> > just greping for AVFrame in the headers shows callbacks, a direct
> > pointer to a AVFrame and the API functions that interface the codec
> > 
> > Just thinking of a codec that instanciates another codec and how
> > exactly the callback which may originate from the user or the outer
> > codec would unwrap the potential nested wraping.
> > I really dont think we want this in FFmpeg
> > And this is just one example ...
> 

> I don't understand this discussion.

yes, i realize this, but iam not sure why

its pretty simple and clear but you seem to skip over parts of what
i said.


> 
> As far as I can tell, the sequence is this:
> 
> * libavcodec allocates an AVFrame structure.
> * libavcodec calls get_buffer2 with that AVFrame structure; the user fills its fields.
> * libavcodec extracts the buffer references and metadata from the AVFrame, and maybe frees it (some codecs reuse a single AVFrame for the lifetime of the codec, others allocate them each time).
> ~ decoding happens, the buffers are written to ~
> * The user allocates a new AVFrame structure.
> * The user calls receive_frame with that new AVFrame structure; libavcodec its fields with references to the decoded data and associated metadata.
> * The user can then read the buffers of the frame, along with its metadata.
> 
> Why would it matter what happens in the middle?  The AVFrame structure at the end is not the AVFrame structure at the start, and the user can't assume anything about it at all - if they try to dereference a pointer to the AVFrame supplied by libavcodec for get_buffer2 after get_buffer2 has returned then they are definitely invoking undefined behaviour.

First this does not consider nested codecs.
A decoder can instanciate a internal decoder, if that now uses the
user callback it would have to unwrap twice for it if it used a
callback from the outer decoder it has to unwrap once.
This of course also depends on how it instanciates the decoder, that
is at which API level.

Next, if you look at the API and search for AVFrame you will find
that there are more callbacks than get_buffer2() that use AVFrames.
there is for example also
 void (*draw_horiz_band)(struct AVCodecContext *s,
                            const AVFrame *src, int offset[AV_NUM_DATA_POINTERS],
                            int y, int type, int height);

Which too has a AVFrame, which too must be unwraped and in a way specific
on the nesting depth of the decoder.

and then there is
AVFrame *coded_frame;
in AVCodecContext

Which can be accessed by the user as well as codec.

Iam pretty sure if i look more ill find more examples.

And future API changes would all have to consider this wraping and
unwraping.

And then all above is just about decoders, there are encoders too
some share code with decoders and at the same time encoders take
AVFrames from the user. Does the shared code expect wraped opaque_ref
or not?
All this adds alot of complexity to maintaining the code and it would
add many bugs

The opaque_ref wraping is a really bad design. Iam not sure why
people defend it.

[...]
Mark Thompson Oct. 5, 2017, 10:59 p.m. UTC | #17
On 05/10/17 23:01, Michael Niedermayer wrote:
> On Thu, Oct 05, 2017 at 09:03:40PM +0100, Mark Thompson wrote:
>> On 05/10/17 17:47, Michael Niedermayer wrote:
>>> On Wed, Oct 04, 2017 at 02:04:54PM +0200, wm4 wrote:
>>>> On Wed, 4 Oct 2017 13:37:31 +0200
>>>> Tobias Rapp <t.rapp@noa-archive.com> wrote:
>>>>
>>>>> On 04.10.2017 11:34, wm4 wrote:
>>>>>> On Wed, 4 Oct 2017 11:22:37 +0200
>>>>>> Michael Niedermayer <michael@niedermayer.cc> wrote:
>>>>>>   
>>>>>>> On Wed, Oct 04, 2017 at 09:12:29AM +0200, wm4 wrote:  
>>>>>>>> On Tue, 3 Oct 2017 21:40:58 +0200
>>>>>>>> Michael Niedermayer <michael@niedermayer.cc> wrote:
>>>>>>>>      
>>>>>>>>> On Tue, Oct 03, 2017 at 03:15:13PM +0200, wm4 wrote:  
>>>>>>>>>> From: Anton Khirnov <anton@khirnov.net>
>>>>>>>>>>        
>>>>>>>>>      
>>>>>>>>>> Use the AVFrame.opaque_ref field. The original user's opaque_ref is
>>>>>>>>>> wrapped in the lavc struct and then unwrapped before the frame is
>>>>>>>>>> returned to the caller.  
>>>>>>>>>
>>>>>>>>> this is a ugly hack
>>>>>>>>>
>>>>>>>>> one and the same field should not be used to hold both the
>>>>>>>>> users opaque_ref as well as a structure which is itself not a user
>>>>>>>>> opaque_ref  
>>>>>>>>
>>>>>>>> While the AVFrame is within libavcodec, it's libavcodec's frame, not
>>>>>>>> the user's. Thus your claim doesn't make too much sense. libavcodec
>>>>>>>> fully controls the meaning for its own AVFrames' opaque_ref, but
>>>>>>>> reconstruct the user's value when returning it.  
>>>>>>>
>>>>>>> i disagree  
>>>>>>
>>>>>> Well, you're wrong anyway.
>>>>>>   
>>>>>>> such hacks should not be added, we do have enough hacks already  
>>>>>>
>>>>>> It's not a hack.  
>>>>>
>>>>> Changing the semantics of a field during its lifetime, even when only 
>>>>> done within private code, is at least unexpected behavior.
>>>>
>>>> That's not done.
>>>
>>> The semantics are defined by the docs, which state:
>>> "AVBufferRef for free use by the API user."
>>>
>>> And before the patch this is true, all instances of this field are
>>> controled by the user application and are consistent.
>>>
>>> after the patch the AVFrames used by a codec have their opaque_ref
>>> replaced by a wraped structure relative to what the outside of this
>>> codec has.
>>>
>>>
>>>> Conceptually the AVFrame with the changed behavior is
>>>> a new reference. Internally, AVFrame.opaque_ref will always have the
>>>> same semantics, pointing to the FrameDecodeData struct. Only at points
>>>> where the AVFrame ref is converted to/from the user struct this is
>>>> changed.
>>>>
>>>>>> This is done strictly when returning a valid AVFrame, so there is no
>>>>>> room for mistakes.  
>>>>>
>>>>> The room for mistake might not increase for external developers but it 
>>>>> increases for internal developers (maintenance cost).
>>>>
>>>> Like where? There are only 2 places where the code needs to deal with
>>>> it, and these are in shared code, not individual decoders.
>>>
>>> just greping for AVFrame in the headers shows callbacks, a direct
>>> pointer to a AVFrame and the API functions that interface the codec
>>>
>>> Just thinking of a codec that instanciates another codec and how
>>> exactly the callback which may originate from the user or the outer
>>> codec would unwrap the potential nested wraping.
>>> I really dont think we want this in FFmpeg
>>> And this is just one example ...
>>
> 
>> I don't understand this discussion.
> 
> yes, i realize this, but iam not sure why
> 
> its pretty simple and clear but you seem to skip over parts of what
> i said.
> 
> 
>>
>> As far as I can tell, the sequence is this:
>>
>> * libavcodec allocates an AVFrame structure.
>> * libavcodec calls get_buffer2 with that AVFrame structure; the user fills its fields.
>> * libavcodec extracts the buffer references and metadata from the AVFrame, and maybe frees it (some codecs reuse a single AVFrame for the lifetime of the codec, others allocate them each time).
>> ~ decoding happens, the buffers are written to ~
>> * The user allocates a new AVFrame structure.
>> * The user calls receive_frame with that new AVFrame structure; libavcodec its fields with references to the decoded data and associated metadata.
>> * The user can then read the buffers of the frame, along with its metadata.
>>
>> Why would it matter what happens in the middle?  The AVFrame structure at the end is not the AVFrame structure at the start, and the user can't assume anything about it at all - if they try to dereference a pointer to the AVFrame supplied by libavcodec for get_buffer2 after get_buffer2 has returned then they are definitely invoking undefined behaviour.
> 
> First this does not consider nested codecs.
> A decoder can instanciate a internal decoder, if that now uses the
> user callback it would have to unwrap twice for it if it used a
> callback from the outer decoder it has to unwrap once.
> This of course also depends on how it instanciates the decoder, that
> is at which API level.

All decoders pass back to their callers the opaque reference they received, so I don't think nesting is relevant.

> Next, if you look at the API and search for AVFrame you will find
> that there are more callbacks than get_buffer2() that use AVFrames.
> there is for example also
>  void (*draw_horiz_band)(struct AVCodecContext *s,
>                             const AVFrame *src, int offset[AV_NUM_DATA_POINTERS],
>                             int y, int type, int height);
> 
> Which too has a AVFrame, which too must be unwraped and in a way specific
> on the nesting depth of the decoder.

Hmm, ok, I didn't know about this one, and it was never mentioned before.

> and then there is
> AVFrame *coded_frame;
> in AVCodecContext
> 
> Which can be accessed by the user as well as codec.

And immediately above it:

     * - decoding: unused

> Iam pretty sure if i look more ill find more examples.> 
> And future API changes would all have to consider this wraping and
> unwraping.
> 
> And then all above is just about decoders, there are encoders too
> some share code with decoders and at the same time encoders take
> AVFrames from the user. Does the shared code expect wraped opaque_ref
> or not?
> All this adds alot of complexity to maintaining the code and it would
> add many bugs
> 
> The opaque_ref wraping is a really bad design. Iam not sure why
> people defend it.

I disagree with your implication here.  I was under the impression that decoders have exactly one entry and one exit point for frames (get_buffer2 and receive_frame): since the opaque reference is only considered at those two points, there is no additional complexity anywhere and no other code need care about it.  However, apparently the API abstraction has additional holes in it which I was not aware of (the draw_horiz_band callback you have noted above), which seems to invalidate that argument.

Are there any other holes in the decoding or encoding abstractions through which frames are able to leak?  It would be helpful to have a list of these somewhere so that people considering how AVFrames travel through libavcodec don't get caught out by this sort of thing in future.

Thanks,

- Mark
Mark Thompson Oct. 5, 2017, 11:38 p.m. UTC | #18
On 05/10/17 23:59, Mark Thompson wrote:
> On 05/10/17 23:01, Michael Niedermayer wrote:
>> On Thu, Oct 05, 2017 at 09:03:40PM +0100, Mark Thompson wrote:
>>> On 05/10/17 17:47, Michael Niedermayer wrote:
>>>> On Wed, Oct 04, 2017 at 02:04:54PM +0200, wm4 wrote:
>>>>> On Wed, 4 Oct 2017 13:37:31 +0200
>>>>> Tobias Rapp <t.rapp@noa-archive.com> wrote:
>>>>>
>>>>>> On 04.10.2017 11:34, wm4 wrote:
>>>>>>> On Wed, 4 Oct 2017 11:22:37 +0200
>>>>>>> Michael Niedermayer <michael@niedermayer.cc> wrote:
>>>>>>>   
>>>>>>>> On Wed, Oct 04, 2017 at 09:12:29AM +0200, wm4 wrote:  
>>>>>>>>> On Tue, 3 Oct 2017 21:40:58 +0200
>>>>>>>>> Michael Niedermayer <michael@niedermayer.cc> wrote:
>>>>>>>>>      
>>>>>>>>>> On Tue, Oct 03, 2017 at 03:15:13PM +0200, wm4 wrote:  
>>>>>>>>>>> From: Anton Khirnov <anton@khirnov.net>
>>>>>>>>>>>        
>>>>>>>>>>      
>>>>>>>>>>> Use the AVFrame.opaque_ref field. The original user's opaque_ref is
>>>>>>>>>>> wrapped in the lavc struct and then unwrapped before the frame is
>>>>>>>>>>> returned to the caller.  
>>>>>>>>>>
>>>>>>>>>> this is a ugly hack
>>>>>>>>>>
>>>>>>>>>> one and the same field should not be used to hold both the
>>>>>>>>>> users opaque_ref as well as a structure which is itself not a user
>>>>>>>>>> opaque_ref  
>>>>>>>>>
>>>>>>>>> While the AVFrame is within libavcodec, it's libavcodec's frame, not
>>>>>>>>> the user's. Thus your claim doesn't make too much sense. libavcodec
>>>>>>>>> fully controls the meaning for its own AVFrames' opaque_ref, but
>>>>>>>>> reconstruct the user's value when returning it.  
>>>>>>>>
>>>>>>>> i disagree  
>>>>>>>
>>>>>>> Well, you're wrong anyway.
>>>>>>>   
>>>>>>>> such hacks should not be added, we do have enough hacks already  
>>>>>>>
>>>>>>> It's not a hack.  
>>>>>>
>>>>>> Changing the semantics of a field during its lifetime, even when only 
>>>>>> done within private code, is at least unexpected behavior.
>>>>>
>>>>> That's not done.
>>>>
>>>> The semantics are defined by the docs, which state:
>>>> "AVBufferRef for free use by the API user."
>>>>
>>>> And before the patch this is true, all instances of this field are
>>>> controled by the user application and are consistent.
>>>>
>>>> after the patch the AVFrames used by a codec have their opaque_ref
>>>> replaced by a wraped structure relative to what the outside of this
>>>> codec has.
>>>>
>>>>
>>>>> Conceptually the AVFrame with the changed behavior is
>>>>> a new reference. Internally, AVFrame.opaque_ref will always have the
>>>>> same semantics, pointing to the FrameDecodeData struct. Only at points
>>>>> where the AVFrame ref is converted to/from the user struct this is
>>>>> changed.
>>>>>
>>>>>>> This is done strictly when returning a valid AVFrame, so there is no
>>>>>>> room for mistakes.  
>>>>>>
>>>>>> The room for mistake might not increase for external developers but it 
>>>>>> increases for internal developers (maintenance cost).
>>>>>
>>>>> Like where? There are only 2 places where the code needs to deal with
>>>>> it, and these are in shared code, not individual decoders.
>>>>
>>>> just greping for AVFrame in the headers shows callbacks, a direct
>>>> pointer to a AVFrame and the API functions that interface the codec
>>>>
>>>> Just thinking of a codec that instanciates another codec and how
>>>> exactly the callback which may originate from the user or the outer
>>>> codec would unwrap the potential nested wraping.
>>>> I really dont think we want this in FFmpeg
>>>> And this is just one example ...
>>>
>>
>>> I don't understand this discussion.
>>
>> yes, i realize this, but iam not sure why
>>
>> its pretty simple and clear but you seem to skip over parts of what
>> i said.
>>
>>
>>>
>>> As far as I can tell, the sequence is this:
>>>
>>> * libavcodec allocates an AVFrame structure.
>>> * libavcodec calls get_buffer2 with that AVFrame structure; the user fills its fields.
>>> * libavcodec extracts the buffer references and metadata from the AVFrame, and maybe frees it (some codecs reuse a single AVFrame for the lifetime of the codec, others allocate them each time).
>>> ~ decoding happens, the buffers are written to ~
>>> * The user allocates a new AVFrame structure.
>>> * The user calls receive_frame with that new AVFrame structure; libavcodec its fields with references to the decoded data and associated metadata.
>>> * The user can then read the buffers of the frame, along with its metadata.
>>>
>>> Why would it matter what happens in the middle?  The AVFrame structure at the end is not the AVFrame structure at the start, and the user can't assume anything about it at all - if they try to dereference a pointer to the AVFrame supplied by libavcodec for get_buffer2 after get_buffer2 has returned then they are definitely invoking undefined behaviour.
>>
>> First this does not consider nested codecs.
>> A decoder can instanciate a internal decoder, if that now uses the
>> user callback it would have to unwrap twice for it if it used a
>> callback from the outer decoder it has to unwrap once.
>> This of course also depends on how it instanciates the decoder, that
>> is at which API level.
> 
> All decoders pass back to their callers the opaque reference they received, so I don't think nesting is relevant.
> 
>> Next, if you look at the API and search for AVFrame you will find
>> that there are more callbacks than get_buffer2() that use AVFrames.
>> there is for example also
>>  void (*draw_horiz_band)(struct AVCodecContext *s,
>>                             const AVFrame *src, int offset[AV_NUM_DATA_POINTERS],
>>                             int y, int type, int height);
>>
>> Which too has a AVFrame, which too must be unwraped and in a way specific
>> on the nesting depth of the decoder.
> 
> Hmm, ok, I didn't know about this one, and it was never mentioned before.
> 
>> and then there is
>> AVFrame *coded_frame;
>> in AVCodecContext
>>
>> Which can be accessed by the user as well as codec.
> 
> And immediately above it:
> 
>      * - decoding: unused
> 
>> Iam pretty sure if i look more ill find more examples.> 
>> And future API changes would all have to consider this wraping and
>> unwraping.
>>
>> And then all above is just about decoders, there are encoders too
>> some share code with decoders and at the same time encoders take
>> AVFrames from the user. Does the shared code expect wraped opaque_ref
>> or not?
>> All this adds alot of complexity to maintaining the code and it would
>> add many bugs
>>
>> The opaque_ref wraping is a really bad design. Iam not sure why
>> people defend it.
> 
> I disagree with your implication here.  I was under the impression that decoders have exactly one entry and one exit point for frames (get_buffer2 and receive_frame): since the opaque reference is only considered at those two points, there is no additional complexity anywhere and no other code need care about it.  However, apparently the API abstraction has additional holes in it which I was not aware of (the draw_horiz_band callback you have noted above), which seems to invalidate that argument.
> 
> Are there any other holes in the decoding or encoding abstractions through which frames are able to leak?  It would be helpful to have a list of these somewhere so that people considering how AVFrames travel through libavcodec don't get caught out by this sort of thing in future.

Having thought about this a bit more, the wrapped_avframe decoder rather messes with it too.  If the input frame (packet) has opaque_ref set then the unwrap process would try to use it and fail.
wm4 Oct. 5, 2017, 11:48 p.m. UTC | #19
On Fri, 6 Oct 2017 00:01:30 +0200
Michael Niedermayer <michael@niedermayer.cc> wrote:

> The opaque_ref wraping is a really bad design. Iam not sure why
> people defend it.

FFmpeg is full of this design. There are plenty of structs with
opaque/priv fields that change meaning depending on the context
(basically how the struct is used or what uses it). It affects all
decoders, encoders, filters, demuxers, muxers, the av_log() call,
functions that work with AVClass, AVOption, and probably more.

Are you saying that FFmpeg is really bad design? That's funny.

There is nothing unclean about this use of opaque_ref, just that it
somewhat collides with awful legacy hacks like draw_horiz_band (but
which could be fixed anyway).

Also what you said about nested decoders is simply incorrect. The
nested decoder is used only by the decoder implementation itself, and
always uses the default get_buffer callback for the nested codec, so
the returned AVFrame.opaque_ref is returned as NULL. Now it's possible
that the new code will assert if the parent codec has AV_CODEC_CAP_DR1
set. This is because if AV_CODEC_CAP_DR1 is set, the AVFrame is
expected to be allocated by the codec context's ff_get_buffer() (which
would guarantee opaque_ref is set correctly). It looks like avrndec.c
does not do this correctly if is_mjpeg is set. But in fact, this codec
violates the API by declaring DR1 support, but not calling the user
get_buffer2 callback. This could be fixed.

An actually valid point is brought up by Mark Thompson (and not by
you), but this can be fixed easily by wrapping the AVFrame properly
before returning. (Assuming the desired semantics are that the
opaque_ref is returned to the user as-is.)

So, still no problem found. What is the problem?

Now I'm very curious to hear what your "cleaner" solution to this
problem is.
Michael Niedermayer Oct. 13, 2017, 5:41 p.m. UTC | #20
On Fri, Oct 06, 2017 at 01:48:14AM +0200, wm4 wrote:
> On Fri, 6 Oct 2017 00:01:30 +0200
> Michael Niedermayer <michael@niedermayer.cc> wrote:
> 
> > The opaque_ref wraping is a really bad design. Iam not sure why
> > people defend it.
> 
> FFmpeg is full of this design. There are plenty of structs with
> opaque/priv fields that change meaning depending on the context
> (basically how the struct is used or what uses it). It affects all
> decoders, encoders, filters, demuxers, muxers, the av_log() call,
> functions that work with AVClass, AVOption, and probably more.

what you write is not true

each decoder, demuxer, ... CLASS has its own type of private context
nothing outside code specific to that class messes with it.
A snow decoder has a snow context.
If the outside structure is moved around its still a snow decoder with
a snow private context. No amount of moving the structure around makes
it invalid.

OTOH, opaque_ref is defined by the user application.
There is a single user application in the address space.

Before the patch
all AVFrame opaque_ref have the same type, no amount of moving/passing
AVFrames around results in an invalid AVFrame.

after the patch this is very different.
Each AVFrame becomes tied to the code that created it, opaque_ref
has a type that outside decoders, is defined by the user application
inside decoders, its a internal structure.

AVFrames are no longer a universal structure that can simply be passed
around.
This is bad design and it is fragile

private and opaque are also intended to be very different things.
In FFmpeg private is a internal thing like the internal context of an
encoder. Opaque is a exteral thing, from the user application or caller


You may have misunderstood me but
I am against AVFrames depending on the code that created them.
This is not just about this implementation (which is in fact buggy too),


Pointing to the implementation issues and bugs was just intended
to show how fragile this is.
I do not understand how one can on one hand see all the problems this
causes yet not see that the API that causes this is what is at fault.
And it is MUCH easier to fix the API than to fix all the issues that
context specific AVFrames would cause


> 
> Are you saying that FFmpeg is really bad design? That's funny.
>
> There is nothing unclean about this use of opaque_ref, just that it
> somewhat collides with awful legacy hacks like draw_horiz_band (but
> which could be fixed anyway).
> 

> Also what you said about nested decoders is simply incorrect. The

It is not incorrect in case current implementations of decoders
dont trigger it. 


[...]

> 
> Now I'm very curious to hear what your "cleaner" solution to this
> problem is.

add a new field to AVFrame if you want a field with semantics that
are different.
you said you are against this IIRC. But thats the simple, robust and
easy maintainable solution
more so if that field is not void* it could provide type checking
which most people consider a good thing.

A system simiar to side data for opaque data could be used too, i
would say thats overkill but some people like side data

One entry for the users opaque structure
One entry for the libavcodec private structure
One entry for a future libavfilter private structure

And this way you need no wraping or unwraping, a AVFrame either
has some extra opaque fields or it doesnt. nothing could cast them to
the wrong type.
This is much more robust than putting all these things in opaque_ref
and spending time and more time and more time writing code wraping
and unwraping at every interface point and then cursing half the
interface and likely in the future fighting over every bit of added
interface as it massivly increases complexity with the wraping

[...]
Michael Niedermayer Oct. 13, 2017, 6:03 p.m. UTC | #21
On Fri, Oct 06, 2017 at 12:38:44AM +0100, Mark Thompson wrote:
> On 05/10/17 23:59, Mark Thompson wrote:
> > On 05/10/17 23:01, Michael Niedermayer wrote:
> >> On Thu, Oct 05, 2017 at 09:03:40PM +0100, Mark Thompson wrote:
> >>> On 05/10/17 17:47, Michael Niedermayer wrote:
> >>>> On Wed, Oct 04, 2017 at 02:04:54PM +0200, wm4 wrote:
> >>>>> On Wed, 4 Oct 2017 13:37:31 +0200
> >>>>> Tobias Rapp <t.rapp@noa-archive.com> wrote:
> >>>>>
> >>>>>> On 04.10.2017 11:34, wm4 wrote:
> >>>>>>> On Wed, 4 Oct 2017 11:22:37 +0200
> >>>>>>> Michael Niedermayer <michael@niedermayer.cc> wrote:
> >>>>>>>   
> >>>>>>>> On Wed, Oct 04, 2017 at 09:12:29AM +0200, wm4 wrote:  
> >>>>>>>>> On Tue, 3 Oct 2017 21:40:58 +0200
> >>>>>>>>> Michael Niedermayer <michael@niedermayer.cc> wrote:
> >>>>>>>>>      
> >>>>>>>>>> On Tue, Oct 03, 2017 at 03:15:13PM +0200, wm4 wrote:  
> >>>>>>>>>>> From: Anton Khirnov <anton@khirnov.net>
> >>>>>>>>>>>        
> >>>>>>>>>>      
> >>>>>>>>>>> Use the AVFrame.opaque_ref field. The original user's opaque_ref is
> >>>>>>>>>>> wrapped in the lavc struct and then unwrapped before the frame is
> >>>>>>>>>>> returned to the caller.  
> >>>>>>>>>>
> >>>>>>>>>> this is a ugly hack
> >>>>>>>>>>
> >>>>>>>>>> one and the same field should not be used to hold both the
> >>>>>>>>>> users opaque_ref as well as a structure which is itself not a user
> >>>>>>>>>> opaque_ref  
> >>>>>>>>>
> >>>>>>>>> While the AVFrame is within libavcodec, it's libavcodec's frame, not
> >>>>>>>>> the user's. Thus your claim doesn't make too much sense. libavcodec
> >>>>>>>>> fully controls the meaning for its own AVFrames' opaque_ref, but
> >>>>>>>>> reconstruct the user's value when returning it.  
> >>>>>>>>
> >>>>>>>> i disagree  
> >>>>>>>
> >>>>>>> Well, you're wrong anyway.
> >>>>>>>   
> >>>>>>>> such hacks should not be added, we do have enough hacks already  
> >>>>>>>
> >>>>>>> It's not a hack.  
> >>>>>>
> >>>>>> Changing the semantics of a field during its lifetime, even when only 
> >>>>>> done within private code, is at least unexpected behavior.
> >>>>>
> >>>>> That's not done.
> >>>>
> >>>> The semantics are defined by the docs, which state:
> >>>> "AVBufferRef for free use by the API user."
> >>>>
> >>>> And before the patch this is true, all instances of this field are
> >>>> controled by the user application and are consistent.
> >>>>
> >>>> after the patch the AVFrames used by a codec have their opaque_ref
> >>>> replaced by a wraped structure relative to what the outside of this
> >>>> codec has.
> >>>>
> >>>>
> >>>>> Conceptually the AVFrame with the changed behavior is
> >>>>> a new reference. Internally, AVFrame.opaque_ref will always have the
> >>>>> same semantics, pointing to the FrameDecodeData struct. Only at points
> >>>>> where the AVFrame ref is converted to/from the user struct this is
> >>>>> changed.
> >>>>>
> >>>>>>> This is done strictly when returning a valid AVFrame, so there is no
> >>>>>>> room for mistakes.  
> >>>>>>
> >>>>>> The room for mistake might not increase for external developers but it 
> >>>>>> increases for internal developers (maintenance cost).
> >>>>>
> >>>>> Like where? There are only 2 places where the code needs to deal with
> >>>>> it, and these are in shared code, not individual decoders.
> >>>>
> >>>> just greping for AVFrame in the headers shows callbacks, a direct
> >>>> pointer to a AVFrame and the API functions that interface the codec
> >>>>
> >>>> Just thinking of a codec that instanciates another codec and how
> >>>> exactly the callback which may originate from the user or the outer
> >>>> codec would unwrap the potential nested wraping.
> >>>> I really dont think we want this in FFmpeg
> >>>> And this is just one example ...
> >>>
> >>
> >>> I don't understand this discussion.
> >>
> >> yes, i realize this, but iam not sure why
> >>
> >> its pretty simple and clear but you seem to skip over parts of what
> >> i said.
> >>
> >>
> >>>
> >>> As far as I can tell, the sequence is this:
> >>>
> >>> * libavcodec allocates an AVFrame structure.
> >>> * libavcodec calls get_buffer2 with that AVFrame structure; the user fills its fields.
> >>> * libavcodec extracts the buffer references and metadata from the AVFrame, and maybe frees it (some codecs reuse a single AVFrame for the lifetime of the codec, others allocate them each time).
> >>> ~ decoding happens, the buffers are written to ~
> >>> * The user allocates a new AVFrame structure.
> >>> * The user calls receive_frame with that new AVFrame structure; libavcodec its fields with references to the decoded data and associated metadata.
> >>> * The user can then read the buffers of the frame, along with its metadata.
> >>>
> >>> Why would it matter what happens in the middle?  The AVFrame structure at the end is not the AVFrame structure at the start, and the user can't assume anything about it at all - if they try to dereference a pointer to the AVFrame supplied by libavcodec for get_buffer2 after get_buffer2 has returned then they are definitely invoking undefined behaviour.
> >>
> >> First this does not consider nested codecs.
> >> A decoder can instanciate a internal decoder, if that now uses the
> >> user callback it would have to unwrap twice for it if it used a
> >> callback from the outer decoder it has to unwrap once.
> >> This of course also depends on how it instanciates the decoder, that
> >> is at which API level.
> > 
> > All decoders pass back to their callers the opaque reference they received, so I don't think nesting is relevant.
> > 
> >> Next, if you look at the API and search for AVFrame you will find
> >> that there are more callbacks than get_buffer2() that use AVFrames.
> >> there is for example also
> >>  void (*draw_horiz_band)(struct AVCodecContext *s,
> >>                             const AVFrame *src, int offset[AV_NUM_DATA_POINTERS],
> >>                             int y, int type, int height);
> >>
> >> Which too has a AVFrame, which too must be unwraped and in a way specific
> >> on the nesting depth of the decoder.
> > 
> > Hmm, ok, I didn't know about this one, and it was never mentioned before.
> > 
> >> and then there is
> >> AVFrame *coded_frame;
> >> in AVCodecContext
> >>
> >> Which can be accessed by the user as well as codec.
> > 
> > And immediately above it:
> > 
> >      * - decoding: unused
> > 
> >> Iam pretty sure if i look more ill find more examples.> 
> >> And future API changes would all have to consider this wraping and
> >> unwraping.
> >>
> >> And then all above is just about decoders, there are encoders too
> >> some share code with decoders and at the same time encoders take
> >> AVFrames from the user. Does the shared code expect wraped opaque_ref
> >> or not?
> >> All this adds alot of complexity to maintaining the code and it would
> >> add many bugs
> >>
> >> The opaque_ref wraping is a really bad design. Iam not sure why
> >> people defend it.
> > 
> > I disagree with your implication here.  I was under the impression that decoders have exactly one entry and one exit point for frames (get_buffer2 and receive_frame): since the opaque reference is only considered at those two points, there is no additional complexity anywhere and no other code need care about it.  However, apparently the API abstraction has additional holes in it which I was not aware of (the draw_horiz_band callback you have noted above), which seems to invalidate that argument.
> > 

> > Are there any other holes in the decoding or encoding abstractions through which frames are able to leak?  It would be helpful to have a list of these somewhere so that people considering how AVFrames travel through libavcodec don't get caught out by this sort of thing in future.

I dont really know and as a maintainer of some of this code, i dont
really want to have to keep track of how exactly AVFrames can pass
through the code.

And as the one taking care of a lot of security i totally have to
reject this. It turns a robust system into something thats really
fragile. This is only secure if every way a AVFrame can pass through
the code has each interface point carefully convert the opaque_ref type.
Thats a large source of bugs and exploits.
Just look at how hard it is to get this patch work initially.
How many future commits will change the way AVFrames move and incorrectly
update all the wraping. developers are not machines this suprising
requirement of (un)wraping on interfaces will not be done correctly
in a few years from now even if you get it all correct now.

Now add libavformat, libavdevice, libavfilter specific opaque_ref
wraping

you really consider this to be good design by any definition of "good"?


> 
> Having thought about this a bit more, the wrapped_avframe decoder rather messes with it too.  If the input frame (packet) has opaque_ref set then the unwrap process would try to use it and fail.

[...]
wm4 Oct. 13, 2017, 7:06 p.m. UTC | #22
On Fri, 13 Oct 2017 20:03:12 +0200
Michael Niedermayer <michael@niedermayer.cc> wrote:

> I dont really know and as a maintainer of some of this code, i dont
> really want to have to keep track of how exactly AVFrames can pass
> through the code.

You have to do that anyway.

> And as the one taking care of a lot of security i totally have to
> reject this. It turns a robust system into something thats really
> fragile. This is only secure if every way a AVFrame can pass through
> the code has each interface point carefully convert the opaque_ref type.
> Thats a large source of bugs and exploits.

The security argument is bullshit. It's very clearly defined how the
field behaves. If you pass it to libavcodec you have to wrap it, if you
return it you have to unwrap it.

> Just look at how hard it is to get this patch work initially.

The only hard thing was "discussing" this with you. I even gave up my
resistance to release ffmpeg 3.4 without it, and took care of your
considerations (see updated patches I've sent before).

Normally you're quick to apply whatever fragile and complicated BS
there is, only here you're making an exception. Why the special
treatment.

> How many future commits will change the way AVFrames move and incorrectly
> update all the wraping. developers are not machines this suprising
> requirement of (un)wraping on interfaces will not be done correctly
> in a few years from now even if you get it all correct now.

Again, this is not complicated. Even if it is, it's less complicated
than all the tricky things you insist on and defend.

> Now add libavformat, libavdevice, libavfilter specific opaque_ref
> wraping
> 
> you really consider this to be good design by any definition of "good"?

It's probably better than whatever you could come up with. But you
didn't even make a suggestion.
wm4 Oct. 13, 2017, 7:19 p.m. UTC | #23
On Fri, 13 Oct 2017 19:41:28 +0200
Michael Niedermayer <michael@niedermayer.cc> wrote:

> On Fri, Oct 06, 2017 at 01:48:14AM +0200, wm4 wrote:
> > On Fri, 6 Oct 2017 00:01:30 +0200
> > Michael Niedermayer <michael@niedermayer.cc> wrote:
> >   
> > > The opaque_ref wraping is a really bad design. Iam not sure why
> > > people defend it.  
> > 
> > FFmpeg is full of this design. There are plenty of structs with
> > opaque/priv fields that change meaning depending on the context
> > (basically how the struct is used or what uses it). It affects all
> > decoders, encoders, filters, demuxers, muxers, the av_log() call,
> > functions that work with AVClass, AVOption, and probably more.  
> 
> what you write is not true
> 
> each decoder, demuxer, ... CLASS has its own type of private context
> nothing outside code specific to that class messes with it.
> A snow decoder has a snow context.
> If the outside structure is moved around its still a snow decoder with
> a snow private context. No amount of moving the structure around makes
> it invalid.
> 
> OTOH, opaque_ref is defined by the user application.
> There is a single user application in the address space.

You misunderstand how AVFrame works. AVFrame has an owner, and this
owner decides how certain fields are handled. This includes for example
the pts fields, whose meaning entirely depend on an undefined timebase.
opaque_ref is merely a more advanced case of this.

> Before the patch
> all AVFrame opaque_ref have the same type, no amount of moving/passing
> AVFrames around results in an invalid AVFrame.

Wrong. Even a user application could have multiple uses of opaque_ref,
all with their own meaning. You can't interpret this field without
context about where its value came from.

> after the patch this is very different.
> Each AVFrame becomes tied to the code that created it, opaque_ref
> has a type that outside decoders, is defined by the user application
> inside decoders, its a internal structure.
> 
> AVFrames are no longer a universal structure that can simply be passed
> around.
> This is bad design and it is fragile
> 
> private and opaque are also intended to be very different things.
> In FFmpeg private is a internal thing like the internal context of an
> encoder. Opaque is a exteral thing, from the user application or caller

Why can you access the private fields anyway? This is fragile and bad
design.

> You may have misunderstood me but
> I am against AVFrames depending on the code that created them.

Suggest something better.

> This is not just about this implementation (which is in fact buggy too),

Is it.

> Pointing to the implementation issues and bugs was just intended
> to show how fragile this is.
> I do not understand how one can on one hand see all the problems this
> causes yet not see that the API that causes this is what is at fault.
> And it is MUCH easier to fix the API than to fix all the issues that
> context specific AVFrames would cause

Fix what API? Do you even understand for what this is needed?

> add a new field to AVFrame if you want a field with semantics that
> are different.

HAHAHAHAHAHAHAAHAHAHAHA

This is a load of badly designed bullshit. This would add another
AVFrame field for something that is INTERNAL and IMPLEMENTATION DEFINED
to libavcodec. Do you know that we have a field for this, which is
supposed to be used by anything that requires INTERNAL and
IMPLEMENTATION DEFINED values by the AVFrame users? It's called
opaque_ref.

> you said you are against this IIRC. But thats the simple, robust and
> easy maintainable solution

It's not simple, because you STILL can forget to unwrap or wrap the
AVFrame properly. Forgetting to unwrap it would be "harmless" in your
opinion because the user isn't allowed to read it, while with
opaque_ref it would be "dangerous". But the truth is that an
"unwrapped" frame doesn't contain the correct data anyway - post
processing was not run, and returning the frame in this state to the
user is undefined behavior.

Skipping unwrapping is a bug. Unwrapping will restore opaque_ref to the
value it should be.

Please come up with something that is actually better.

Anyway, in my opinion, it would be better to disallow opaque_ref being
set by the user's get_buffer2 callback. That would solve most of the
issues you have with it, but surely you would come up with some crap to
block my work anyway.

> more so if that field is not void* it could provide type checking
> which most people consider a good thing.
> 
> A system simiar to side data for opaque data could be used too, i
> would say thats overkill but some people like side data

Side data has literally nothing to do with this. Side data types can't
be defined by the user anyway. Why do codec/filter/demuxer private
fields have no type checking? Or av_log? Or the whole AVOption API?
Please answer this.

> One entry for the users opaque structure
> One entry for the libavcodec private structure
> One entry for a future libavfilter private structure

One entry for application 1.
...
One entry for application 1000000000.

GREAT DESIGN

> And this way you need no wraping or unwraping, a AVFrame either

YOU FUCKING NEED UNWRAPPING FOR POSTPROCESSING

Both intended uses, cuvid and videotoolbox, require this. Unwrapping
can't be skipped. Skipping unwrapping is a bug.

> has some extra opaque fields or it doesnt. nothing could cast them to
> the wrong type.

Why is such a thing not required for codecs/filters/demuxers? Hell,
your beloved mpegvideo pile of garbage could really use this.

> This is much more robust than putting all these things in opaque_ref
> and spending time and more time and more time writing code wraping
> and unwraping at every interface point and then cursing half the
> interface and likely in the future fighting over every bit of added
> interface as it massivly increases complexity with the wraping

All this code is already written.

And again, you can NOT SKIP UNWRAPPING.

opaque_ref is superior to adding a new AVFrame field for every private
use case.
Michael Niedermayer Oct. 14, 2017, 9:01 p.m. UTC | #24
On Fri, Oct 13, 2017 at 09:19:04PM +0200, wm4 wrote:
> On Fri, 13 Oct 2017 19:41:28 +0200
> Michael Niedermayer <michael@niedermayer.cc> wrote:
> 
> > On Fri, Oct 06, 2017 at 01:48:14AM +0200, wm4 wrote:
> > > On Fri, 6 Oct 2017 00:01:30 +0200
> > > Michael Niedermayer <michael@niedermayer.cc> wrote:
> > >   
> > > > The opaque_ref wraping is a really bad design. Iam not sure why
> > > > people defend it.  
> > > 
> > > FFmpeg is full of this design. There are plenty of structs with
> > > opaque/priv fields that change meaning depending on the context
> > > (basically how the struct is used or what uses it). It affects all
> > > decoders, encoders, filters, demuxers, muxers, the av_log() call,
> > > functions that work with AVClass, AVOption, and probably more.  
> > 
> > what you write is not true
> > 
> > each decoder, demuxer, ... CLASS has its own type of private context
> > nothing outside code specific to that class messes with it.
> > A snow decoder has a snow context.
> > If the outside structure is moved around its still a snow decoder with
> > a snow private context. No amount of moving the structure around makes
> > it invalid.
> > 
> > OTOH, opaque_ref is defined by the user application.
> > There is a single user application in the address space.
> 
> You misunderstand how AVFrame works. AVFrame has an owner, and this
> owner decides how certain fields are handled. This includes for example
> the pts fields, whose meaning entirely depend on an undefined timebase.
> opaque_ref is merely a more advanced case of this.

The API docs say about opaque_ref
"FFmpeg will never check the contents of the buffer ref."
the unwraping code does exactly that and any code using it internally
does as well.

Let me quote the code from one of these patches:

diff --git a/libavcodec/decode.c b/libavcodec/decode.c
index 437b848248..04f7156154 100644
--- a/libavcodec/decode.c
+++ b/libavcodec/decode.c
[...]
+        if (frame->opaque_ref) {
+            FrameDecodeData *fdd;
+            AVBufferRef *user_opaque_ref;
+
+            fdd = (FrameDecodeData*)frame->opaque_ref->data;

This violates the API and it is semantically wrong.

about pts, that is off topic, but no amount of moving an AVFrame
around makes a valid AVFrame pts into an invalid AVFrame pts.
AVFrame pts refers to a unspecified timebase either way.
If the code knows that timebase and knows the origin it can interpret
the timestamp.
It may make sense to add more information about the pts into AVFrame
so its more self contained, but this is off topic


> 
> > Before the patch
> > all AVFrame opaque_ref have the same type, no amount of moving/passing
> > AVFrames around results in an invalid AVFrame.
> 

> Wrong. Even a user application could have multiple uses of opaque_ref,
> all with their own meaning. You can't interpret this field without
> context about where its value came from.

No matter if the user app uses 1, 2 or n types in opaque_ref.
Its still at all points the user apps type and thus the same type for
this discussions point of view.
interpreting the user apps opaque_ref is entirely in the user
applications domain. We can never interpret it. The user application
should know how to interpret its own data.


[...]

> > more so if that field is not void* it could provide type checking
> > which most people consider a good thing.
> > 
> > A system simiar to side data for opaque data could be used too, i
> > would say thats overkill but some people like side data
> 
> Side data has literally nothing to do with this. Side data types can't
> be defined by the user anyway.

> Why do codec/filter/demuxer private
> fields have no type checking? Or av_log? Or the whole AVOption API?
> Please answer this.

This thread is the wrong place to discuss this, this is off topic
Of course it would be good if we can check types in more cases ...


[...]

> > And this way you need no wraping or unwraping, a AVFrame either
> 
> YOU FUCKING NEED UNWRAPPING FOR POSTPROCESSING

> 
> Both intended uses, cuvid and videotoolbox, require this. Unwrapping
> can't be skipped. Skipping unwrapping is a bug.

IIUC these need a postprocessing function to be called.
There is no relation between calling a postprocessing function and
wraping and unwraping the users opaque_ref. You can do either without
the other.


[...]
wm4 Oct. 16, 2017, 7:40 a.m. UTC | #25
On Sat, 14 Oct 2017 23:01:41 +0200
Michael Niedermayer <michael@niedermayer.cc> wrote:

> On Fri, Oct 13, 2017 at 09:19:04PM +0200, wm4 wrote:
> > On Fri, 13 Oct 2017 19:41:28 +0200
> > Michael Niedermayer <michael@niedermayer.cc> wrote:
> >   
> > > On Fri, Oct 06, 2017 at 01:48:14AM +0200, wm4 wrote:  
> > > > On Fri, 6 Oct 2017 00:01:30 +0200
> > > > Michael Niedermayer <michael@niedermayer.cc> wrote:
> > > >     
> > > > > The opaque_ref wraping is a really bad design. Iam not sure why
> > > > > people defend it.    
> > > > 
> > > > FFmpeg is full of this design. There are plenty of structs with
> > > > opaque/priv fields that change meaning depending on the context
> > > > (basically how the struct is used or what uses it). It affects all
> > > > decoders, encoders, filters, demuxers, muxers, the av_log() call,
> > > > functions that work with AVClass, AVOption, and probably more.    
> > > 
> > > what you write is not true
> > > 
> > > each decoder, demuxer, ... CLASS has its own type of private context
> > > nothing outside code specific to that class messes with it.
> > > A snow decoder has a snow context.
> > > If the outside structure is moved around its still a snow decoder with
> > > a snow private context. No amount of moving the structure around makes
> > > it invalid.
> > > 
> > > OTOH, opaque_ref is defined by the user application.
> > > There is a single user application in the address space.  
> > 
> > You misunderstand how AVFrame works. AVFrame has an owner, and this
> > owner decides how certain fields are handled. This includes for example
> > the pts fields, whose meaning entirely depend on an undefined timebase.
> > opaque_ref is merely a more advanced case of this.  
> 
> The API docs say about opaque_ref
> "FFmpeg will never check the contents of the buffer ref."
> the unwraping code does exactly that and any code using it internally
> does as well.

It doesn't - not the user's. We use only the field for internal
purposes (as AVFrame users), and we never do anything with the user's
value.

I'm not sure if you get this, so let me repeat this. We never interpret
the user's value, nor do we return our own internal value of this to
the user. Make sure you understand this.

> Let me quote the code from one of these patches:
> 
> diff --git a/libavcodec/decode.c b/libavcodec/decode.c
> index 437b848248..04f7156154 100644
> --- a/libavcodec/decode.c
> +++ b/libavcodec/decode.c
> [...]
> +        if (frame->opaque_ref) {
> +            FrameDecodeData *fdd;
> +            AVBufferRef *user_opaque_ref;
> +
> +            fdd = (FrameDecodeData*)frame->opaque_ref->data;
> 
> This violates the API and it is semantically wrong.


No it does not. Cease your bullshit. It never inspects the user value,
it only wraps it. Stop trying to misrepresent it or inventing semantics
on top of the doxygen (which I write btw.).

> > Wrong. Even a user application could have multiple uses of opaque_ref,
> > all with their own meaning. You can't interpret this field without
> > context about where its value came from.  
> 
> No matter if the user app uses 1, 2 or n types in opaque_ref.
> Its still at all points the user apps type and thus the same type for
> this discussions point of view.

No. The user app could have multiple uses of it with multiple types, at
different points in the program.

> interpreting the user apps opaque_ref is entirely in the user
> applications domain. We can never interpret it. The user application
> should know how to interpret its own data.

And we never interpret it. Why do you think we do?

Am I talking to a fucking wall? A bot?

> > Both intended uses, cuvid and videotoolbox, require this. Unwrapping
> > can't be skipped. Skipping unwrapping is a bug.  
> 
> IIUC these need a postprocessing function to be called.
> There is no relation between calling a postprocessing function and
> wraping and unwraping the users opaque_ref. You can do either without
> the other.

Yes there is. You claim opaque_ref is "unsafe" because you could forget
unwrapping it. But forgetting unwrapping is equivalent to forgetting
calling the postprocessing, which would be a bug.

Why is one kind of bug so critical that leads you to reject this patch,
while the you barely acknowledge the other bug and don't care?

Unless you have real arguments, I'll push the updated patches in 24h.
Xiaolei Yu Oct. 16, 2017, 11:28 a.m. UTC | #26
On 10/03/2017 09:15 PM, wm4 wrote:
> From: Anton Khirnov <anton@khirnov.net>
> 
> Use the AVFrame.opaque_ref field. The original user's opaque_ref is
> wrapped in the lavc struct and then unwrapped before the frame is
> returned to the caller.
> 
> This new struct will be useful in the following commits.
> 

How about using AVFrame::buf[]?
wm4 Oct. 16, 2017, 11:36 a.m. UTC | #27
On Mon, 16 Oct 2017 19:28:27 +0800
Xiaolei Yu <dreifachstein@gmail.com> wrote:

> On 10/03/2017 09:15 PM, wm4 wrote:
> > From: Anton Khirnov <anton@khirnov.net>
> > 
> > Use the AVFrame.opaque_ref field. The original user's opaque_ref is
> > wrapped in the lavc struct and then unwrapped before the frame is
> > returned to the caller.
> > 
> > This new struct will be useful in the following commits.
> >   
> 
> How about using AVFrame::buf[]?

My local crash-fix hack for videotoolbox actually uses buf[] for this
purpose, but it won't work in general, because video data might need
it. Also that would have exactly the same problems as opaque_ref.
Actually, all approaches will have exactly the same problems as
opaque_ref, but michael doesn't get it.
Xiaolei Yu Oct. 16, 2017, 12:32 p.m. UTC | #28
On 10/16/2017 07:36 PM, wm4 wrote:
> On Mon, 16 Oct 2017 19:28:27 +0800
> Xiaolei Yu <dreifachstein@gmail.com> wrote:
> 
>> On 10/03/2017 09:15 PM, wm4 wrote:
>>> From: Anton Khirnov <anton@khirnov.net>
>>>
>>> Use the AVFrame.opaque_ref field. The original user's opaque_ref is
>>> wrapped in the lavc struct and then unwrapped before the frame is
>>> returned to the caller.
>>>
>>> This new struct will be useful in the following commits.
>>>   
>>
>> How about using AVFrame::buf[]?
> 
> My local crash-fix hack for videotoolbox actually uses buf[] for this
> purpose, but it won't work in general, because video data might need
> it. Also that would have exactly the same problems as opaque_ref.
> Actually, all approaches will have exactly the same problems as
> opaque_ref, but michael doesn't get it.

I think handling foreign memory with a cpu-centric api will always be kinda
awkward. But using AVFrame::buf[] is more natural if we treat them as a
family of cpu-unaddressable images. Also it would be great (in the future)
to allow users to pass them around without a round trip to the main memory.
 

> _______________________________________________
> ffmpeg-devel mailing list
> ffmpeg-devel@ffmpeg.org
> http://ffmpeg.org/mailman/listinfo/ffmpeg-devel
>
wm4 Oct. 16, 2017, 1:09 p.m. UTC | #29
On Mon, 16 Oct 2017 20:32:03 +0800
Xiaolei Yu <dreifachstein@gmail.com> wrote:

> On 10/16/2017 07:36 PM, wm4 wrote:
> > On Mon, 16 Oct 2017 19:28:27 +0800
> > Xiaolei Yu <dreifachstein@gmail.com> wrote:
> >   
> >> On 10/03/2017 09:15 PM, wm4 wrote:  
> >>> From: Anton Khirnov <anton@khirnov.net>
> >>>
> >>> Use the AVFrame.opaque_ref field. The original user's opaque_ref is
> >>> wrapped in the lavc struct and then unwrapped before the frame is
> >>> returned to the caller.
> >>>
> >>> This new struct will be useful in the following commits.
> >>>     
> >>
> >> How about using AVFrame::buf[]?  
> > 
> > My local crash-fix hack for videotoolbox actually uses buf[] for this
> > purpose, but it won't work in general, because video data might need
> > it. Also that would have exactly the same problems as opaque_ref.
> > Actually, all approaches will have exactly the same problems as
> > opaque_ref, but michael doesn't get it.  
> 
> I think handling foreign memory with a cpu-centric api will always be kinda
> awkward. But using AVFrame::buf[] is more natural if we treat them as a
> family of cpu-unaddressable images. Also it would be great (in the future)
> to allow users to pass them around without a round trip to the main memory.

No, AVFrame.buf[] always points to CPU addressable memory. For hardware
decoding, the AVFrame.buf[0] usually points to a dummy AVBufferRef
(with either size 0, or pointing towards some other struct describing
the hardware surface).

Not sure how this relates to the current discussion. The problem with
videotoolbox is that AVHWAccel.end_frame can be run on a worker thread,
and videotoolbox needs to set the actual hardware surface in that
callback (because Apple's API returns the frame once all decoding is
done, and you can't pass a user-allocated surface to it). The worker
thread can't propagate its AVFrame changes back to the main thread
(where another AVFrame reference to the same frame is returned). Thus a
post process callback is required, and the AVFrame within libavcodec is
always invalid from a user point of view until post process is invoked.
Michael Niedermayer Oct. 16, 2017, 10:58 p.m. UTC | #30
On Mon, Oct 16, 2017 at 09:40:26AM +0200, wm4 wrote:
> On Sat, 14 Oct 2017 23:01:41 +0200
> Michael Niedermayer <michael@niedermayer.cc> wrote:
> 
> > On Fri, Oct 13, 2017 at 09:19:04PM +0200, wm4 wrote:
> > > On Fri, 13 Oct 2017 19:41:28 +0200
> > > Michael Niedermayer <michael@niedermayer.cc> wrote:
> > >   
> > > > On Fri, Oct 06, 2017 at 01:48:14AM +0200, wm4 wrote:  
> > > > > On Fri, 6 Oct 2017 00:01:30 +0200
> > > > > Michael Niedermayer <michael@niedermayer.cc> wrote:
> > > > >     
> > > > > > The opaque_ref wraping is a really bad design. Iam not sure why
> > > > > > people defend it.    
> > > > > 
> > > > > FFmpeg is full of this design. There are plenty of structs with
> > > > > opaque/priv fields that change meaning depending on the context
> > > > > (basically how the struct is used or what uses it). It affects all
> > > > > decoders, encoders, filters, demuxers, muxers, the av_log() call,
> > > > > functions that work with AVClass, AVOption, and probably more.    
> > > > 
> > > > what you write is not true
> > > > 
> > > > each decoder, demuxer, ... CLASS has its own type of private context
> > > > nothing outside code specific to that class messes with it.
> > > > A snow decoder has a snow context.
> > > > If the outside structure is moved around its still a snow decoder with
> > > > a snow private context. No amount of moving the structure around makes
> > > > it invalid.
> > > > 
> > > > OTOH, opaque_ref is defined by the user application.
> > > > There is a single user application in the address space.  
> > > 
> > > You misunderstand how AVFrame works. AVFrame has an owner, and this
> > > owner decides how certain fields are handled. This includes for example
> > > the pts fields, whose meaning entirely depend on an undefined timebase.
> > > opaque_ref is merely a more advanced case of this.  
> > 
> > The API docs say about opaque_ref
> > "FFmpeg will never check the contents of the buffer ref."
> > the unwraping code does exactly that and any code using it internally
> > does as well.
> 

> It doesn't - not the user's. We use only the field for internal
> purposes (as AVFrame users), and we never do anything with the user's
> value.
> 
> I'm not sure if you get this, so let me repeat this. We never interpret
> the user's value, nor do we return our own internal value of this to
> the user. Make sure you understand this.

sure, the patch uses the opaque_ref field for its libavcodec internal
purposes

Theres where the need for wraping and unwraping comes from.
These are 2 semantically distinct use cases that do not fit well in a
single field.

One can put anything in any (large enough) field of any structure that
way.
On all input APIs replace the field by a new structure and put
the original fields content in that structure.
On output take the field of the internal struct, free the structure
and write the original fields value back
Thats exactly what this patches wraping code does.

And thats what I called a fragile hack.

it also violates the API IMO, but thats not so much the point

The data the user application wants to attach to a AVFrame for the
user applications extrenal purposes
and
The data libavcodec wants to attach for internal (hwaccel) use.

Are 2 distinct things. You can have none, either one or both theres
no relation between them.


[...]
>
> > > Both intended uses, cuvid and videotoolbox, require this. Unwrapping
> > > can't be skipped. Skipping unwrapping is a bug.  
> > 
> > IIUC these need a postprocessing function to be called.
> > There is no relation between calling a postprocessing function and
> > wraping and unwraping the users opaque_ref. You can do either without
> > the other.
> 

> Yes there is. You claim opaque_ref is "unsafe" because you could forget
> unwrapping it. But forgetting unwrapping is equivalent to forgetting
> calling the postprocessing, which would be a bug.

We can discuss about cases where unwraping is needed while postprocessing
is not but i think this would distract from the subject so it would be
better in a different thread.


> 
> Why is one kind of bug so critical that leads you to reject this patch,
> while the you barely acknowledge the other bug and don't care?
> 

> Unless you have real arguments, I'll push the updated patches in 24h.

If you wish to push this patch against my veto, you have to get the
vote comittee to override my veto. There is no need for you to accept
my arguments.

Iam interrested to hear the argumentation of other developers
why this code is not a hack, not fragile, not hard to maintain, not a
security risk and why we should go this path instead of some
alternative without these issues.

Maybe iam totally wrong and everyone feels this patch is the way code
should be written and API designed.
But it would surprise me alot if there are alot of people supporting
this kind of design

Thanks

[...]
wm4 Oct. 17, 2017, 4:49 a.m. UTC | #31
I have realized that your veto is actually not valid:
- it's a Libav merge
- it has been for months in the Libav repo and you didn't specifically
  care, nor did you make an attempt to merge the commit in a "fixed" way
- this patch would have been merged normally, and you wouldn't have
  cared at all about it

So unless you intend to make a better, working proposal, I will _not_
allow you to make this "my" problem. I will psuh this in 3 hours. After
that, you're free to to reimplement this in a different way or whatever
as a merge cleanup.

On Tue, 17 Oct 2017 00:58:58 +0200
Michael Niedermayer <michael@niedermayer.cc> wrote:

> On Mon, Oct 16, 2017 at 09:40:26AM +0200, wm4 wrote:
> > On Sat, 14 Oct 2017 23:01:41 +0200
> > Michael Niedermayer <michael@niedermayer.cc> wrote:
> >   
> > > On Fri, Oct 13, 2017 at 09:19:04PM +0200, wm4 wrote:  
> > > > On Fri, 13 Oct 2017 19:41:28 +0200
> > > > Michael Niedermayer <michael@niedermayer.cc> wrote:
> > > >     
> > > > > On Fri, Oct 06, 2017 at 01:48:14AM +0200, wm4 wrote:    
> > > > > > On Fri, 6 Oct 2017 00:01:30 +0200
> > > > > > Michael Niedermayer <michael@niedermayer.cc> wrote:
> > > > > >       
> > > > > > > The opaque_ref wraping is a really bad design. Iam not sure why
> > > > > > > people defend it.      
> > > > > > 
> > > > > > FFmpeg is full of this design. There are plenty of structs with
> > > > > > opaque/priv fields that change meaning depending on the context
> > > > > > (basically how the struct is used or what uses it). It affects all
> > > > > > decoders, encoders, filters, demuxers, muxers, the av_log() call,
> > > > > > functions that work with AVClass, AVOption, and probably more.      
> > > > > 
> > > > > what you write is not true
> > > > > 
> > > > > each decoder, demuxer, ... CLASS has its own type of private context
> > > > > nothing outside code specific to that class messes with it.
> > > > > A snow decoder has a snow context.
> > > > > If the outside structure is moved around its still a snow decoder with
> > > > > a snow private context. No amount of moving the structure around makes
> > > > > it invalid.
> > > > > 
> > > > > OTOH, opaque_ref is defined by the user application.
> > > > > There is a single user application in the address space.    
> > > > 
> > > > You misunderstand how AVFrame works. AVFrame has an owner, and this
> > > > owner decides how certain fields are handled. This includes for example
> > > > the pts fields, whose meaning entirely depend on an undefined timebase.
> > > > opaque_ref is merely a more advanced case of this.    
> > > 
> > > The API docs say about opaque_ref
> > > "FFmpeg will never check the contents of the buffer ref."
> > > the unwraping code does exactly that and any code using it internally
> > > does as well.  
> >   
> 
> > It doesn't - not the user's. We use only the field for internal
> > purposes (as AVFrame users), and we never do anything with the user's
> > value.
> > 
> > I'm not sure if you get this, so let me repeat this. We never interpret
> > the user's value, nor do we return our own internal value of this to
> > the user. Make sure you understand this.  
> 
> sure, the patch uses the opaque_ref field for its libavcodec internal
> purposes
> 
> Theres where the need for wraping and unwraping comes from.
> These are 2 semantically distinct use cases that do not fit well in a
> single field.
> 
> One can put anything in any (large enough) field of any structure that
> way.
> On all input APIs replace the field by a new structure and put
> the original fields content in that structure.
> On output take the field of the internal struct, free the structure
> and write the original fields value back
> Thats exactly what this patches wraping code does.
> 
> And thats what I called a fragile hack.
> 
> it also violates the API IMO, but thats not so much the point
> 
> The data the user application wants to attach to a AVFrame for the
> user applications extrenal purposes
> and
> The data libavcodec wants to attach for internal (hwaccel) use.
> 
> Are 2 distinct things. You can have none, either one or both theres
> no relation between them.
> 
> 
> [...]
> >  
> > > > Both intended uses, cuvid and videotoolbox, require this. Unwrapping
> > > > can't be skipped. Skipping unwrapping is a bug.    
> > > 
> > > IIUC these need a postprocessing function to be called.
> > > There is no relation between calling a postprocessing function and
> > > wraping and unwraping the users opaque_ref. You can do either without
> > > the other.  
> >   
> 
> > Yes there is. You claim opaque_ref is "unsafe" because you could forget
> > unwrapping it. But forgetting unwrapping is equivalent to forgetting
> > calling the postprocessing, which would be a bug.  
> 
> We can discuss about cases where unwraping is needed while postprocessing
> is not but i think this would distract from the subject so it would be
> better in a different thread.
> 
> 
> > 
> > Why is one kind of bug so critical that leads you to reject this patch,
> > while the you barely acknowledge the other bug and don't care?
> >   
> 
> > Unless you have real arguments, I'll push the updated patches in 24h.  
> 
> If you wish to push this patch against my veto, you have to get the
> vote comittee to override my veto. There is no need for you to accept
> my arguments.
> 
> Iam interrested to hear the argumentation of other developers
> why this code is not a hack, not fragile, not hard to maintain, not a
> security risk and why we should go this path instead of some
> alternative without these issues.
> 
> Maybe iam totally wrong and everyone feels this patch is the way code
> should be written and API designed.
> But it would surprise me alot if there are alot of people supporting
> this kind of design
> 
> Thanks
> 
> [...]
wm4 Oct. 17, 2017, 5:26 a.m. UTC | #32
Correction: will push as part of cuvid/videotoolbox patches whenever
they're ready.

On Tue, 17 Oct 2017 00:58:58 +0200
Michael Niedermayer <michael@niedermayer.cc> wrote:

> > It doesn't - not the user's. We use only the field for internal
> > purposes (as AVFrame users), and we never do anything with the user's
> > value.
> > 
> > I'm not sure if you get this, so let me repeat this. We never interpret
> > the user's value, nor do we return our own internal value of this to
> > the user. Make sure you understand this.  
> 
> sure, the patch uses the opaque_ref field for its libavcodec internal
> purposes

Which it is allowed to.

> Theres where the need for wraping and unwraping comes from.
> These are 2 semantically distinct use cases that do not fit well in a
> single field.

There's nothing semantically distinct. The opaque_ref field's semantics
are defined by the owner of the AVFrame, and when ownership is passed
through the components, rewrapping might be needed. Which is what the
patch does.

How often did I repeat this and how often did you not understand this?

> One can put anything in any (large enough) field of any structure that
> way.
> On all input APIs replace the field by a new structure and put
> the original fields content in that structure.
> On output take the field of the internal struct, free the structure
> and write the original fields value back
> Thats exactly what this patches wraping code does.
> 
> And thats what I called a fragile hack.

Anything you suggested is even worse and even more fragile.

> it also violates the API IMO, but thats not so much the point

It does not. I created the fucking API.

> The data the user application wants to attach to a AVFrame for the
> user applications extrenal purposes
> and
> The data libavcodec wants to attach for internal (hwaccel) use.
> 
> Are 2 distinct things. You can have none, either one or both theres
> no relation between them.

AVFrame does not dictate a use for this field. The use of the field is
determined by the owner of the AVFrame, which is libavcodec while the
frame is in libavcodec.

How often did I repeat this and how often did you not understand this?

> 
> [...]
> >  
> > > > Both intended uses, cuvid and videotoolbox, require this. Unwrapping
> > > > can't be skipped. Skipping unwrapping is a bug.    
> > > 
> > > IIUC these need a postprocessing function to be called.
> > > There is no relation between calling a postprocessing function and
> > > wraping and unwraping the users opaque_ref. You can do either without
> > > the other.  
> >   
> 
> > Yes there is. You claim opaque_ref is "unsafe" because you could forget
> > unwrapping it. But forgetting unwrapping is equivalent to forgetting
> > calling the postprocessing, which would be a bug.  
> 
> We can discuss about cases where unwraping is needed while postprocessing
> is not but i think this would distract from the subject so it would be
> better in a different thread.

The fuck? Unwrapping is equivalent to doing postprocessing required to
make it a valid output frame.

> 
> > 
> > Why is one kind of bug so critical that leads you to reject this patch,
> > while the you barely acknowledge the other bug and don't care?
> >   
> 
> > Unless you have real arguments, I'll push the updated patches in 24h.  
> 
> If you wish to push this patch against my veto, you have to get the
> vote comittee to override my veto. There is no need for you to accept
> my arguments.

There's no need for me to justify merging a Libav patch, although I've
wasted more than enough time doing so. If you don't like Libav
patches, maybe you should never have forked.

> Iam interrested to hear the argumentation of other developers
> why this code is not a hack, not fragile, not hard to maintain, not a
> security risk and why we should go this path instead of some
> alternative without these issues.
> 
> Maybe iam totally wrong and everyone feels this patch is the way code
> should be written and API designed.
> But it would surprise me alot if there are alot of people supporting
> this kind of design
> 
> Thanks
> 
> [...]
Thilo Borgmann Oct. 17, 2017, 6:23 p.m. UTC | #33
Am 17.10.17 um 06:49 schrieb wm4:
> I have realized that your veto is actually not valid:
> - it's a Libav merge
> - it has been for months in the Libav repo and you didn't specifically
>   care, nor did you make an attempt to merge the commit in a "fixed" way
> - this patch would have been merged normally, and you wouldn't have
>   cared at all about it
> 
> So unless you intend to make a better, working proposal, I will _not_
> allow you to make this "my" problem. I will psuh this in 3 hours. After
> that, you're free to to reimplement this in a different way or whatever
> as a merge cleanup.

Can you please stop this and just find a reasonable way to find consensus on the issues you're facing?

Is it really of such importance that you want to push this although there are still concerns about what you want to do? Is this at all in any way relevant for security so that time would be at all a factor? I don't see any of your arguments mentioned above to be a valid reason to overrule someone else's opinion.

And no, I do not have the slightest clue about what you folks are discussing about but this should not even matter - I just criticize the way you are going to take here...

-Thilo
wm4 Oct. 17, 2017, 6:27 p.m. UTC | #34
On Tue, 17 Oct 2017 20:23:25 +0200
Thilo Borgmann <thilo.borgmann@mail.de> wrote:

> Am 17.10.17 um 06:49 schrieb wm4:
> > I have realized that your veto is actually not valid:
> > - it's a Libav merge
> > - it has been for months in the Libav repo and you didn't specifically
> >   care, nor did you make an attempt to merge the commit in a "fixed" way
> > - this patch would have been merged normally, and you wouldn't have
> >   cared at all about it
> > 
> > So unless you intend to make a better, working proposal, I will _not_
> > allow you to make this "my" problem. I will psuh this in 3 hours. After
> > that, you're free to to reimplement this in a different way or whatever
> > as a merge cleanup.  
> 
> Can you please stop this and just find a reasonable way to find consensus on the issues you're facing?
> 
> Is it really of such importance that you want to push this although there are still concerns about what you want to do? Is this at all in any way relevant for security so that time would be at all a factor? I don't see any of your arguments mentioned above to be a valid reason to overrule someone else's opinion.

I don't want trivial things getting blocked by pure bullshit that's
probably politically and not technically motivated.

The best part about this dumb shit is that I could probably send
patches for cuvid/videotoolbox that use dumb workarounds (i.e. uglier
and shittier hacks) than the discussed patch, and NOBODY WOULD FUCKING
CARE.

I'm pretty fed up with this shit.

Please keep out of this discussion if you can't contribute anything too.
Thilo Borgmann Oct. 17, 2017, 6:37 p.m. UTC | #35
Am 17.10.17 um 20:27 schrieb wm4:
> On Tue, 17 Oct 2017 20:23:25 +0200
> Thilo Borgmann <thilo.borgmann@mail.de> wrote:
> 
>> Am 17.10.17 um 06:49 schrieb wm4:
>>> I have realized that your veto is actually not valid:
>>> - it's a Libav merge
>>> - it has been for months in the Libav repo and you didn't specifically
>>>   care, nor did you make an attempt to merge the commit in a "fixed" way
>>> - this patch would have been merged normally, and you wouldn't have
>>>   cared at all about it
>>>
>>> So unless you intend to make a better, working proposal, I will _not_
>>> allow you to make this "my" problem. I will psuh this in 3 hours. After
>>> that, you're free to to reimplement this in a different way or whatever
>>> as a merge cleanup.  
>>
>> Can you please stop this and just find a reasonable way to find consensus on the issues you're facing?
>>
>> Is it really of such importance that you want to push this although there are still concerns about what you want to do? Is this at all in any way relevant for security so that time would be at all a factor? I don't see any of your arguments mentioned above to be a valid reason to overrule someone else's opinion.
> 
> I don't want trivial things getting blocked by pure bullshit that's
> probably politically and not technically motivated.
> 
> The best part about this dumb shit is that I could probably send
> patches for cuvid/videotoolbox that use dumb workarounds (i.e. uglier
> and shittier hacks) than the discussed patch, and NOBODY WOULD FUCKING
> CARE.
> 
> I'm pretty fed up with this shit.
> 
> Please keep out of this discussion if you can't contribute anything too.

I do care because I am delaying my work on some other cuvid related thing because of this.

I would prefer not to dive into this topic any further because it seems rather "not so important" to my task. And just another cook in the kitchen would also more likely avoid conensus here.

All I ask for is for you to find a reasonable to argue about your issues.

I hope you see my point why I am raising my voice. Thanks!

-Thilo
Thilo Borgmann Oct. 17, 2017, 6:39 p.m. UTC | #36
Am 17.10.17 um 20:37 schrieb Thilo Borgmann:
> Am 17.10.17 um 20:27 schrieb wm4:
>> On Tue, 17 Oct 2017 20:23:25 +0200
>> Thilo Borgmann <thilo.borgmann@mail.de> wrote:
>>
>>> Am 17.10.17 um 06:49 schrieb wm4:
>>>> I have realized that your veto is actually not valid:
>>>> - it's a Libav merge
>>>> - it has been for months in the Libav repo and you didn't specifically
>>>>   care, nor did you make an attempt to merge the commit in a "fixed" way
>>>> - this patch would have been merged normally, and you wouldn't have
>>>>   cared at all about it
>>>>
>>>> So unless you intend to make a better, working proposal, I will _not_
>>>> allow you to make this "my" problem. I will psuh this in 3 hours. After
>>>> that, you're free to to reimplement this in a different way or whatever
>>>> as a merge cleanup.  
>>>
>>> Can you please stop this and just find a reasonable way to find consensus on the issues you're facing?
>>>
>>> Is it really of such importance that you want to push this although there are still concerns about what you want to do? Is this at all in any way relevant for security so that time would be at all a factor? I don't see any of your arguments mentioned above to be a valid reason to overrule someone else's opinion.
>>
>> I don't want trivial things getting blocked by pure bullshit that's
>> probably politically and not technically motivated.
>>
>> The best part about this dumb shit is that I could probably send
>> patches for cuvid/videotoolbox that use dumb workarounds (i.e. uglier
>> and shittier hacks) than the discussed patch, and NOBODY WOULD FUCKING
>> CARE.
>>
>> I'm pretty fed up with this shit.
>>
>> Please keep out of this discussion if you can't contribute anything too.
> 
> I do care because I am delaying my work on some other cuvid related thing because of this.
> 
> I would prefer not to dive into this topic any further because it seems rather "not so important" to my task. And just another cook in the kitchen would also more likely avoid conensus here.
> 
> All I ask for is for you to find a reasonable to argue about your issues.
                                               ^
                                              way


> I hope you see my point why I am raising my voice. Thanks!
> 
> -Thilo
Timo Rothenpieler Oct. 17, 2017, 6:46 p.m. UTC | #37
Am 17.10.2017 um 20:37 schrieb Thilo Borgmann:
> Am 17.10.17 um 20:27 schrieb wm4:
>> On Tue, 17 Oct 2017 20:23:25 +0200
>> Thilo Borgmann <thilo.borgmann@mail.de> wrote:
>>
>>> Am 17.10.17 um 06:49 schrieb wm4:
>>>> I have realized that your veto is actually not valid:
>>>> - it's a Libav merge
>>>> - it has been for months in the Libav repo and you didn't specifically
>>>>    care, nor did you make an attempt to merge the commit in a "fixed" way
>>>> - this patch would have been merged normally, and you wouldn't have
>>>>    cared at all about it
>>>>
>>>> So unless you intend to make a better, working proposal, I will _not_
>>>> allow you to make this "my" problem. I will psuh this in 3 hours. After
>>>> that, you're free to to reimplement this in a different way or whatever
>>>> as a merge cleanup.
>>>
>>> Can you please stop this and just find a reasonable way to find consensus on the issues you're facing?
>>>
>>> Is it really of such importance that you want to push this although there are still concerns about what you want to do? Is this at all in any way relevant for security so that time would be at all a factor? I don't see any of your arguments mentioned above to be a valid reason to overrule someone else's opinion.
>>
>> I don't want trivial things getting blocked by pure bullshit that's
>> probably politically and not technically motivated.
>>
>> The best part about this dumb shit is that I could probably send
>> patches for cuvid/videotoolbox that use dumb workarounds (i.e. uglier
>> and shittier hacks) than the discussed patch, and NOBODY WOULD FUCKING
>> CARE.
>>
>> I'm pretty fed up with this shit.
>>
>> Please keep out of this discussion if you can't contribute anything too.
> 
> I do care because I am delaying my work on some other cuvid related thing because of this.
> 
> I would prefer not to dive into this topic any further because it seems rather "not so important" to my task. And just another cook in the kitchen would also more likely avoid conensus here.
> 
> All I ask for is for you to find a reasonable to argue about your issues.
> 
> I hope you see my point why I am raising my voice. Thanks!
> 
> -Thilo
I second this. The exact way this is implemented is entirely 
unimportant. But this pointless fighting leads nowhere.
While I agree that this patch is technically correct and does not 
violate API in any way, I also kind of dislike using opaque_ref for 
this, and would welcome coming up with a nicer solution, that's ideally 
compatible with libavs approach without too much work on every patch 
that touches it.
Michael Niedermayer Oct. 18, 2017, 10:15 a.m. UTC | #38
On Tue, Oct 17, 2017 at 06:49:51AM +0200, wm4 wrote:
> I have realized that your veto is actually not valid:
> - it's a Libav merge

There is no exception for changes from Libav.
Not in the policy and not in actual actions. We never pushed
changes with standing objections.


[...]
Michael Niedermayer Oct. 18, 2017, 11:04 a.m. UTC | #39
On Tue, Oct 17, 2017 at 07:26:01AM +0200, wm4 wrote:
[...]

> 
> > it also violates the API IMO, but thats not so much the point
> 
> It does not. I created the fucking API.
> 
> > The data the user application wants to attach to a AVFrame for the
> > user applications extrenal purposes
> > and
> > The data libavcodec wants to attach for internal (hwaccel) use.
> > 
> > Are 2 distinct things. You can have none, either one or both theres
> > no relation between them.
> 
> AVFrame does not dictate a use for this field. The use of the field is
> determined by the owner of the AVFrame, which is libavcodec while the
> frame is in libavcodec.
> 
> How often did I repeat this and how often did you not understand this?

opaque_ref is defined to have the same semantics as opaque.
opaque definitly does NOT have the semantics you write about in this
thread.
opaque is a field that exists for a very long time

I think you and Libav misunderstood the opaque field semantics

Just think about it, the opaque field existed when the *frame structure
was defined in libavcodec. The user of libavcodec is NOT libavcodec
This field was never intended to be used by any of our libs to store
their private data.

It was the move of AVFrame to libavutil that made the documentation
of opaque ambigous and this likely lead to this misunderstanding
compn Oct. 18, 2017, 1:48 p.m. UTC | #40
On Tue, 17 Oct 2017 20:37:32 +0200, Thilo Borgmann
<thilo.borgmann@mail.de> wrote:

> I do care because I am delaying my work on some other cuvid related thing because of this.
> 
> I would prefer not to dive into this topic any further because it seems rather "not so important" to my task. And just another cook in the kitchen would also more likely avoid conensus here.

thilo, can we bribe you to massage this patch a little?

it seems like wm4 and michael both are not budging...
a third party might be able to settle the stalemate.

-compn
compn Oct. 18, 2017, 2:02 p.m. UTC | #41
On Wed, 4 Oct 2017 11:34:18 +0200, wm4 <nfxjfg@googlemail.com> wrote:

> > more so, opaque_ref is used in only 5 lines in the whole codebase,
> > so there is not much code to consider when using a different solution
> 
> We shouldn't add such special fields, we have enough hacks already. Is
> that your only suggestion how to do this? Because it's a bad one.

michael, do you have other suggestions how to solve this problem? are
you going to fix the errors in the doxygen that you noticed due to
merges?

wm4, would you object to adding another special field? if
someone else edited this and made a patch?

-compn
Michael Niedermayer Oct. 18, 2017, 2:34 p.m. UTC | #42
On Wed, Oct 18, 2017 at 09:48:16AM -0400, Compn wrote:
[...]

> a third party might be able to settle the stalemate.

i strongly support this. And it was in part why i suggested to take
this to the vote comittee. Most people from the vote committee are
uninvolved in this

This should be carefully looked at by people with cool heads and
decided.

I had actually written something similar in my last reply but i edited
it out before sending as it seemed to get a bit lengthy and redundant.

[...]
Marton Balint Oct. 18, 2017, 7:29 p.m. UTC | #43
On Wed, 18 Oct 2017, Michael Niedermayer wrote:

> On Wed, Oct 18, 2017 at 09:48:16AM -0400, Compn wrote:
> [...]
>
>> a third party might be able to settle the stalemate.
>
> i strongly support this. And it was in part why i suggested to take
> this to the vote comittee. Most people from the vote committee are
> uninvolved in this
>
> This should be carefully looked at by people with cool heads and
> decided.

I tried to follow the discussion but I still don't get why adding a 
new "priv_ref" field to AVFrame for lavc internal use is frowned upon. 
It seems like the easiest solution to relax the concerns and a small 
price to pay to put this story behind us.

Unfortunately I don't know much about hwaccel, so I can't judge the 
whole patch series, but for me it is not evident that post-processing 
belongs to the decoder interface, if everybody agrees that it does, then 
OK.

I also find storing an AVBufferRef in an AVBufferRef a bit confusing, 
because sooner or later we won't know if we have to do a deep ref on 
referencing an avframe, or not, so I'd try to avoid that in general.

Regards,
Marton
Thilo Borgmann Oct. 18, 2017, 10:41 p.m. UTC | #44
Am 18.10.17 um 16:02 schrieb Compn:
> On Wed, 4 Oct 2017 11:34:18 +0200, wm4 <nfxjfg@googlemail.com> wrote:
> 
>>> more so, opaque_ref is used in only 5 lines in the whole codebase,
>>> so there is not much code to consider when using a different solution
>>
>> We shouldn't add such special fields, we have enough hacks already. Is
>> that your only suggestion how to do this? Because it's a bad one.
> 
> michael, do you have other suggestions how to solve this problem? are
> you going to fix the errors in the doxygen that you noticed due to
> merges?
> 
> wm4, would you object to adding another special field? if
> someone else edited this and made a patch?

If the two of you could agree on an alternate, suitable approach, I could offer
to do the codemonkey's work like compn suggested. However, I still lack some
knowledge about API and HWACCEL which would result in certain inefficiency in
doing so. OTOH this comes along with a nonbiased perspective which might be a
positive thing here.

I'd appreciate it if anyone else would be willing to commit some coding to a
solution, though. I am not eager to do it but I can if we stall completely
otherwise.

-Thilo
diff mbox

Patch

diff --git a/libavcodec/decode.c b/libavcodec/decode.c
index 437b848248..04f7156154 100644
--- a/libavcodec/decode.c
+++ b/libavcodec/decode.c
@@ -640,6 +640,26 @@  static int decode_receive_frame_internal(AVCodecContext *avctx, AVFrame *frame)
     if (ret == AVERROR_EOF)
         avci->draining_done = 1;
 
+    /* unwrap the per-frame decode data and restore the original opaque_ref*/
+    if (!ret) {
+        /* the only case where decode data is not set should be decoders
+         * that do not call ff_get_buffer() */
+        av_assert0((frame->opaque_ref && frame->opaque_ref->size == sizeof(FrameDecodeData)) ||
+                   !(avctx->codec->capabilities & AV_CODEC_CAP_DR1));
+
+        if (frame->opaque_ref) {
+            FrameDecodeData *fdd;
+            AVBufferRef *user_opaque_ref;
+
+            fdd = (FrameDecodeData*)frame->opaque_ref->data;
+
+            user_opaque_ref = fdd->user_opaque_ref;
+            fdd->user_opaque_ref = NULL;
+            av_buffer_unref(&frame->opaque_ref);
+            frame->opaque_ref = user_opaque_ref;
+        }
+    }
+
     return ret;
 }
 
@@ -1612,6 +1632,37 @@  static void validate_avframe_allocation(AVCodecContext *avctx, AVFrame *frame)
     }
 }
 
+static void decode_data_free(void *opaque, uint8_t *data)
+{
+    FrameDecodeData *fdd = (FrameDecodeData*)data;
+
+    av_buffer_unref(&fdd->user_opaque_ref);
+
+    av_freep(&fdd);
+}
+
+static int attach_decode_data(AVFrame *frame)
+{
+    AVBufferRef *fdd_buf;
+    FrameDecodeData *fdd;
+
+    fdd = av_mallocz(sizeof(*fdd));
+    if (!fdd)
+        return AVERROR(ENOMEM);
+
+    fdd_buf = av_buffer_create((uint8_t*)fdd, sizeof(*fdd), decode_data_free,
+                               NULL, AV_BUFFER_FLAG_READONLY);
+    if (!fdd_buf) {
+        av_freep(&fdd);
+        return AVERROR(ENOMEM);
+    }
+
+    fdd->user_opaque_ref = frame->opaque_ref;
+    frame->opaque_ref    = fdd_buf;
+
+    return 0;
+}
+
 static int get_buffer_internal(AVCodecContext *avctx, AVFrame *frame, int flags)
 {
     const AVHWAccel *hwaccel = avctx->hwaccel;
@@ -1648,8 +1699,14 @@  static int get_buffer_internal(AVCodecContext *avctx, AVFrame *frame, int flags)
         avctx->sw_pix_fmt = avctx->pix_fmt;
 
     ret = avctx->get_buffer2(avctx, frame, flags);
-    if (ret >= 0)
-        validate_avframe_allocation(avctx, frame);
+    if (ret < 0)
+        goto end;
+
+    validate_avframe_allocation(avctx, frame);
+
+    ret = attach_decode_data(frame);
+    if (ret < 0)
+        goto end;
 
 end:
     if (avctx->codec_type == AVMEDIA_TYPE_VIDEO && !override_dimensions &&
diff --git a/libavcodec/decode.h b/libavcodec/decode.h
index c9630228dc..ab8327f95c 100644
--- a/libavcodec/decode.h
+++ b/libavcodec/decode.h
@@ -21,8 +21,21 @@ 
 #ifndef AVCODEC_DECODE_H
 #define AVCODEC_DECODE_H
 
+#include "libavutil/buffer.h"
+
 #include "avcodec.h"
 
+/**
+ * This struct stores per-frame lavc-internal data and is attached to it via
+ * opaque_ref.
+ */
+typedef struct FrameDecodeData {
+    /**
+     * The original user-set opaque_ref.
+     */
+    AVBufferRef *user_opaque_ref;
+} FrameDecodeData;
+
 /**
  * Called by decoders to get the next packet for decoding.
  *