[FFmpeg-devel] [PATCH 13/13] fftools/ffmpeg_demux: merge streams in a LCEVC stream group

James Almer jamrial at gmail.com
Fri Sep 6 17:05:33 EEST 2024


On 9/6/2024 10:33 AM, Anton Khirnov wrote:
> Quoting James Almer (2024-09-06 14:15:36)
>> On 9/6/2024 8:56 AM, Anton Khirnov wrote:
>>> Quoting James Almer (2024-08-31 18:31:14)
>>>>    static int demux_send(Demuxer *d, DemuxThreadContext *dt, DemuxStream *ds,
>>>>                          AVPacket *pkt, unsigned flags)
>>>>    {
>>>>        InputFile  *f = &d->f;
>>>> -    int ret;
>>>> +    int ret = 0;
>>>>    
>>>>        // pkt can be NULL only when flushing BSFs
>>>>        av_assert0(ds->bsf || pkt);
>>>>    
>>>> +    // a stream can only be disabled if it's needed by a group
>>>
>>> This makes no sense to me.
>>
>> I made av_read_frame() output packets for all the streams belonging to a
>> group, even if some of those streams are not selected/used for an
>> output. In the case of LCEVC groups, the normal scenario is to merge
>> enhancement stream packets into the video one, with the enhancement
>> stream not being used on its own by any output stream.
>> DemuxStream->discard is used for this, where it can be 0 (not used by
>> any output) when AVStream->discard is obviously going to be 1 for lavf
>> to export packets for the stream.
>>
>> If a packet where DemuxStream->discard is 0 reaches this point, the only
>> valid scenario is that it's part of a group.
>>
>>>
>>>> +    av_assert0(ds->nb_stream_groups || !ds->discard);
>>>> +
>>>> +    // create a reference for the packet to be filtered by group bsfs
>>>
>>> What are "group bsfs"?
>>
>> Bsfs that are used by and all (or some) of a group's streams, as is the
>> case of lcevc_merge, and stored in DemuxStreamGroup->bsf.
>>
>>>
>>>> +    if (pkt && ds->nb_stream_groups) {
>>>> +        av_packet_unref(dt->pkt_group_bsf);
>>>> +        ret = av_packet_ref(dt->pkt_group_bsf, pkt);
>>>> +        if (ret < 0)
>>>> +            return ret;
>>>> +    }
>>>> +
>>>>        // send heartbeat for sub2video streams
>>>> -    if (d->pkt_heartbeat && pkt && pkt->pts != AV_NOPTS_VALUE) {
>>>> +    if (d->pkt_heartbeat && pkt && !ds->discard && pkt->pts != AV_NOPTS_VALUE) {
>>>
>>> Random added checks for ds->discard are extremely confusing and tell me
>>> you're overloading that poor field to mean something extremely
>>> non-obvious.
>>
>> I added this here to make sure I'm not sending a heartbeat packet when
>> handling a packet for a stream that's not used by any output on its own.
> 
> This is not the the only place where you're adding a check for discard,

Because it's the only code i don't want to trigger for non-standalone 
output packets.

> and I strongly dislike that 'discard' now does not mean 'discard'
> anymore.

No, the packet is discarded in the end, and never makes anywhere on its 
own unless it's used by an output. DemuxStream->discard is in fact the 
one field where you can check if a stream is effectively disabled, and 
that doesn't change with this patch. What changes is that lavf may now 
output packets not used by any output (AVStream->discard being 0), and 
the code needs to be aware of this.

> 
> Furthermore, I really dislike how invasive such an obscure feature is.

Ideally, lavf would export the LCEVC stream payload as packet side data 
in the video's stream, but that's apparently only possible with mov/mp4 
and maybe matroska, not TS. Hence a Stream Group is used and everything 
left to the caller.

That said, is this so invasive? This patch adds 
DemuxStreamGroup/InputStreamGroup, cleanly initializes them like we 
already do with DemuxStream/InputStream, and then factorizes the bsf 
packet loop so it can be used for the stream bsf and the group bsf.
The only truly big change is making libavformat output streams that are 
not strictly used by an output, which is achieved by making 
AVStream->discard not be set, and keep relying on DemuxStream->discard 
to know what stream is disabled or not.

You can try remuxing an LCEVC sample with split enhancement in different 
ways to test this:

# decode video stream only. Enhancement stream is output as well and 
merged into video stream as side data, which lavc will see and use.
ffmpeg -i input.mp4 output.mp4

# remux video stream only. Enhancement stream is output as well and 
merged into video stream as side data. Muxers will not care about it, 
but an hypothetical bsf could for example be inserted in the process to 
add it to the h264/hevc bitstream as a SEI message.
ffmpeg -i input.mp4 -c:v copy -dn -map 0:0 output.mp4

# remux enhancement stream only. Video stream is output by lavf but 
discarded by the CLI.
ffmpeg -i input.mp4 -c:d copy -vn -map 0:1 output.mp4

# remux both video and enhancement streams. Enhancement stream is merged 
into video stream as side data too.
ffmpeg -i input.mp4 -c:v copy -c:d copy -map 0 output.mp4

> 
>>>> +        int j;
>>>> +
>>>> +        for (j = 0; j < f->nb_streams; j++)
>>>> +            if (stg->streams[i] == f->streams[j]->st)
>>>> +                break;
>>>> +
>>>> +        if (j == f->nb_streams)
>>>> +            return AVERROR_BUG;
>>>
>>> Isn't all this just "j = stg->streams[i]->index"?
>>
>> Is f->streams guaranteed to have the same streams as ic->streams? If so,
>> probably. Will change then.
> 
> I guess you're right that it's better not to rely on it. Still, I'd
> rather this was factored into a separate function.

Ok.

-------------- next part --------------
A non-text attachment was scrubbed...
Name: OpenPGP_signature.asc
Type: application/pgp-signature
Size: 495 bytes
Desc: OpenPGP digital signature
URL: <https://ffmpeg.org/pipermail/ffmpeg-devel/attachments/20240906/e23dac5c/attachment.sig>


More information about the ffmpeg-devel mailing list