[FFmpeg-devel] [PATCH 03/14] pthread_frame: merge the functionality for normal decoder init and init_thread_copy

Anton Khirnov anton at khirnov.net
Tue Mar 31 12:47:39 EEST 2020


Quoting David Bryant (2020-03-28 21:22:40)
> On 3/28/20 6:23 AM, Anton Khirnov wrote:
> > Quoting David Bryant (2020-03-27 23:51:19)
> >> On 3/27/20 5:57 AM, Anton Khirnov wrote:
> >>> The current design, where
> >>> - proper init is called for the first per-thread context
> >>> - first thread's private data is copied into private data for all the
> >>>   other threads
> >>> - a "fixup" function is called for all the other threads to e.g.
> >>>   allocate dynamically allocated data
> >>> is very fragile and hard to follow, so it is abandoned. Instead, the
> >>> same init function is used to init each per-thread context. Where
> >>> necessary, AVCodecInternal.is_copy can be used to differentiate between
> >>> the first thread and the other ones (e.g. for decoding the extradata
> >>> just once).
> >>> ---
> >> I'm not sure I fully understand this change. You mention that AVCodecInternal.is_copy can be used where different treatment
> >> might be necessary for subsequent threads, and I see that done in a couple places, but in most cases you have simply deleted the
> >> init_thread_copy() function even when it's not at all obvious (to me anyway) that that won't break the codec.
> > In most cases, just deleting init_thread_copy() is the right thing to
> > do. E.g. all decoders that do not implement update_thread_context() have
> > to be intra-only, so every frame thread is effectively a completely
> > standalone decoder. And in most of the more complex decoders (like h264)
> > the important parameters are dynamically changeable during decoding, so
> > not that much is done in decoder init beyond allocating some stuff that
> > does not depend on the bistream properties.
> >
> > My intent is for each frame-thread worker to be treated inasmuch as
> > possible as a standalone decoder, and where it has to share data with
> > other threads to make this sharing explicit (rather than implicit as is
> > the case now).
> 
> Yes, this makes sense. The confusing part is when the decode_init() function looks completely different than the
> init_thread_copy() function. This is often because the decode_init() function is generating things (tables, etc.) from scratch
> and the init_thread_copy() is just copying the necessary things from the original. In cases where the original generation might
> be time consuming this might make sense, but usually it's probably just making the code more complex and difficult to follow
> (which I believe was your original point).

Yes, precisely. I believe for obscure codecs it's better to waste a
little memory when doing threaded decoding, in return for simpler code.
And if people really care about being as memory-efficient as possible
then doing explicit refcounting on allocated buffers is still possible.

> 
> One possible interim solution for complex cases that break would be to leave the init_thread_copy() function there, but instead
> of having it in the AVCodec struct and called from outside (which is no longer possible), it simply gets called first thing from
> decode_init() if AVCodecInternal.is_copy is set. That way the architecture is cleaned up now, and the codec won't break and can
> be cleaned up when time permits. Just a thought.

I don't really see much point in any interim solutions, since no codecs
should break. You found a problem with wavpack, that's going to be fixed
in the next iteration of this patch.
Speaking of which, ideally we should have a FATE test for DSD files so
that I would have found the failure myself when running test.

> 
> >
> >> Specifically this will break WavPack because now it will be allocating a new dsdctx for every thread instead of sharing one
> >> between all threads. I am happy to fix and test this case once the patch goes in, but is the intent of this patch that the
> >> respective authors will find and fix all the breakages? Or did I just happen to catch the one case you missed?
> > I certainly intended to convert the decoders correctly myself,
> > apparently I didn't pay enough attention to the recent wavpack changes.
> > Hopefully the other conversions are correct, but I will go through the
> > changes again to check.
> >
> > Looking at wavpack, the code looks suspicious to me. You allocate one
> > dsdctx per channel at init, but AFAIU the number of channels can change
> > at each frame.
> >
> Multichannel WavPack consists of sequences of stereo or mono WavPack blocks that include flags indicating whether they are the
> beginning or end of a "frame" or "packet". This allows the number of channels available to be essentially unlimited, however the
> total number of channels in a stream may not change. When decoding, if a sequence of blocks generates more or less than the
> correct number of channels, this is flagged as an error and overrun is prevented (see libavcodec/wavpack.c, line 1499 and line
> 1621).

If my reading of the code is correct, line 1499 only checks for overflow
of the channel count read for the current sequence. That channel count
is exported to AVCodeContext in the block starting on line 1464 and
I don't see any checks for whether it is equal to the initial one.

-- 
Anton Khirnov


More information about the ffmpeg-devel mailing list