Skip to content

decoder: do not construct the access unit on the calling thread - #4059

Open
anabobillo3 wants to merge 1 commit into
cisco:masterfrom
anabobillo3:decoder-threaded-midbuf-finish
Open

anabobillo3 wants to merge 1 commit into
cisco:masterfrom
anabobillo3:decoder-threaded-midbuf-finish

Conversation

@anabobillo3

Copy link
Copy Markdown

With more than one decoding thread, the calling thread only parses a DecodeFrameNoDelay() buffer into the access unit list, and a worker constructs the access unit. The ConstructAccessUnit() calls on the parse path of WelsDecodeBs() are gated on GetThreadCount() <= 1 for that reason, and so is the CheckAndFinishLastPic() call for the last NAL of the buffer.

The ConstructAccessUnit() inside CheckAndFinishLastPic() is not. The NAL loop calls CheckAndFinishLastPic() for every NAL but the last, so when a non-VCL NAL (an access unit delimiter, an SEI, an overwriting SPS/PPS) ends the access unit in the middle of the buffer, the calling thread constructs that access unit itself, ahead of the worker hand-off:

  • on the first call the picture buffer is not allocated yet, and PrefetchPic() dereferences the NULL picture buffer;
  • on later calls the calling thread decodes the picture while the workers use the same pictures.

Change

Gate that one call on GetThreadCount() <= 1, like the other constructs on the parse path. The access unit then stays in the list for the worker, as it already does when the buffer ends with the picture's last slice. Single-threaded decoding is unchanged.

The rest of CheckAndFinishLastPic() (the error concealment and finish of a picture a worker left incomplete) still runs on the calling thread; the worker chain relies on it to signal that picture.

Threaded decoding takes one picture per call. A buffer that carries two pictures split by a delimiter now decodes the same way two pictures in one call without a delimiter already do upstream.

Test

ThreadDecoderTrailingNonVclTest.DelimiterAndSeiAfterSlicesDecodeAllFrames decodes res/Adobe_PDF_sample_a_1024x768_50Frms.264 with two threads, each call carrying one frame followed by the next access unit's delimiter and SEI, and expects every call to return without error and all 50 frames to be decoded.

  • Before this change: the new test crashes in PrefetchPic().
  • After: the new test passes 10 times in a row, ThreadDecoderNalListBoundsTest and the rest of Thread* pass, and the full codec_unittest passes (484 tests).

With more than one thread, the calling thread only parses a
DecodeFrameNoDelay() buffer into the access unit list and a worker
constructs the access unit: the ConstructAccessUnit() calls on the parse
path of WelsDecodeBs() are gated on GetThreadCount() <= 1. The one in
CheckAndFinishLastPic(), which the NAL loop calls for every NAL but the
last, is not: when a non-VCL NAL (an access unit delimiter, an SEI, an
overwriting parameter set) ends the access unit in the middle of the
buffer, the calling thread constructs it there, ahead of the worker
hand-off. On the first call the picture buffer is not allocated yet and
PrefetchPic() dereferences the NULL picture buffer; later calls decode
the picture on the calling thread while workers use the same pictures.

Gate that call on GetThreadCount() <= 1 like the others, so the access
unit stays in the list for the worker, as it does when the buffer ends
with the picture's last slice.

The new test decodes a stream in which each call carries one frame
followed by the next access unit's delimiter and SEI.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant