[FFmpeg-devel] [PATCH 16/23] avcodec/hevc/refs: export Stereo 3D side data

James Almer jamrial at gmail.com
Sun Sep 15 06:18:36 EEST 2024


On 9/14/2024 7:12 PM, James Almer wrote:
> On 9/14/2024 7:45 AM, Anton Khirnov wrote:
>> From: James Almer <jamrial at gmail.com>
>>
>> Use the 3D Reference Displays Info SEI message to link a view_id with
>> an eye.
>>
>> Signed-off-by: James Almer <jamrial at gmail.com>
>> ---
>>   libavcodec/hevc/hevcdec.c |  1 +
>>   libavcodec/hevc/refs.c    | 19 +++++++++++++++++++
>>   2 files changed, 20 insertions(+)
>>
>> diff --git a/libavcodec/hevc/hevcdec.c b/libavcodec/hevc/hevcdec.c
>> index 692f19e97e..b784b10bcf 100644
>> --- a/libavcodec/hevc/hevcdec.c
>> +++ b/libavcodec/hevc/hevcdec.c
>> @@ -3968,6 +3968,7 @@ static int 
>> hevc_update_thread_context(AVCodecContext *dst,
>>       s->sei.common.mastering_display    = s0- 
>> >sei.common.mastering_display;
>>       s->sei.common.content_light        = s0->sei.common.content_light;
>>       s->sei.common.aom_film_grain       = s0->sei.common.aom_film_grain;
>> +    s->sei.tdrdi                       = s0->sei.tdrdi;
>>       return 0;
>>   }
>> diff --git a/libavcodec/hevc/refs.c b/libavcodec/hevc/refs.c
>> index b9b08ca416..ac1b07a308 100644
>> --- a/libavcodec/hevc/refs.c
>> +++ b/libavcodec/hevc/refs.c
>> @@ -22,6 +22,7 @@
>>    */
>>   #include "libavutil/mem.h"
>> +#include "libavutil/stereo3d.h"
>>   #include "container_fifo.h"
>>   #include "decode.h"
>> @@ -94,6 +95,7 @@ static HEVCFrame *alloc_frame(HEVCContext *s, 
>> HEVCLayerContext *l)
>>           // add view ID side data if it's nontrivial
>>           if (vps->nb_layers > 1 || view_id) {
>> +            HEVCSEITDRDI *tdrdi = &s->sei.tdrdi;
>>               AVFrameSideData *sd = av_frame_side_data_new(&frame->f- 
>> >side_data,
>>                                                            &frame->f- 
>> >nb_side_data,
>>                                                            
>> AV_FRAME_DATA_VIEW_ID,
>> @@ -101,6 +103,23 @@ static HEVCFrame *alloc_frame(HEVCContext *s, 
>> HEVCLayerContext *l)
>>               if (!sd)
>>                   goto fail;
>>               *(int*)sd->data = view_id;
>> +
>> +            if (tdrdi->num_ref_displays) {
>> +                AVStereo3D *stereo_3d;
>> +
>> +                av_frame_remove_side_data(frame->f, 
>> AV_FRAME_DATA_STEREO3D);
> 
> As this is now being called before ff_progress_frame_get_buffer() (is 
> there a reason you wanted the view_id side data and this one applied to 
> the frame before get_buffer()?), it became a no-op and any stereo 3d 
> side data in the input packet will be appended to the frame, resulting 
> in something like:
> 
>> [Parsed_showinfo_0 @ 00000281481551c0]   side data - View ID: view id: 0
>> [Parsed_showinfo_0 @ 00000281481551c0]   side data - Stereo 3D: type - 
>> frame alternate, view - right, primary_eye - none
>> [Parsed_showinfo_0 @ 00000281481551c0]   side data - Spherical 
>> Mapping: rectilinear
>> [Parsed_showinfo_0 @ 00000281481551c0]   side data - Stereo 3D: type - 
>> unspecified, view - packed, primary_eye - none, baseline: 19240, 
>> horizontal_disparity_adjustment: 0.0200, horizontal_field_of_view: 63.400
> 
> We don't really want to lose the information that's coded in the 
> container but not in the bitstream (Which happened in the previous 
> version of the patch too), so we should instead amend the container 
> level side data with the bitstream information.
> 
> Something like:
> 
>> diff --git a/libavcodec/hevc/refs.c b/libavcodec/hevc/refs.c
>> index ac1b07a308..f4c2b18e83 100644
>> --- a/libavcodec/hevc/refs.c
>> +++ b/libavcodec/hevc/refs.c
>> @@ -93,21 +93,32 @@ static HEVCFrame *alloc_frame(HEVCContext *s, 
>> HEVCLayerContext *l)
>>          if (ret < 0)
>>              return NULL;
>>
>> +        if (!(s->layers_active_output & (1 << s->cur_layer)))
>> +            frame->f->flags |= AV_FRAME_FLAG_DISCARD;
>> +
>> +        ret = ff_progress_frame_get_buffer(s->avctx, &frame->tf,
>> +                                           AV_GET_BUFFER_FLAG_REF);
>> +        if (ret < 0)
>> +            return NULL;
>> +
>>          // add view ID side data if it's nontrivial
>>          if (vps->nb_layers > 1 || view_id) {
>>              HEVCSEITDRDI *tdrdi = &s->sei.tdrdi;
>> -            AVFrameSideData *sd = av_frame_side_data_new(&frame->f- 
>> >side_data,
>> -                                                         &frame->f- 
>> >nb_side_data,
>> -                                                         
>> AV_FRAME_DATA_VIEW_ID,
>> -                                                         sizeof(int), 
>> 0);
>> +            AVFrameSideData *sd;
>> +
>> +            av_frame_remove_side_data(frame->f, AV_FRAME_DATA_VIEW_ID);
>> +            sd = av_frame_new_side_data(frame->f, 
>> AV_FRAME_DATA_VIEW_ID, sizeof(int));
>>              if (!sd)
>>                  goto fail;
>>              *(int*)sd->data = view_id;
>>
>>              if (tdrdi->num_ref_displays) {
>> -                AVStereo3D *stereo_3d;
>> +                AVStereo3D *stereo_3d = NULL;
>>
>> -                av_frame_remove_side_data(frame->f, 
>> AV_FRAME_DATA_STEREO3D);
>> +                sd = av_frame_get_side_data(frame->f, 
>> AV_FRAME_DATA_STEREO3D);
>> +                if (sd)
>> +                    stereo_3d = (AVStereo3D *)sd->data;
>> +                else
>>                  stereo_3d = av_stereo3d_create_side_data(frame->f);
>>                  if (!stereo_3d)
>>                      goto fail;
>> @@ -122,14 +133,6 @@ static HEVCFrame *alloc_frame(HEVCContext *s, 
>> HEVCLayerContext *l)
>>              }
>>          }
>>
>> -        if (!(s->layers_active_output & (1 << s->cur_layer)))
>> -            frame->f->flags |= AV_FRAME_FLAG_DISCARD;
>> -
>> -        ret = ff_progress_frame_get_buffer(s->avctx, &frame->tf,
>> -                                           AV_GET_BUFFER_FLAG_REF);
>> -        if (ret < 0)
>> -            return NULL;
>> -
>>          frame->rpl = ff_refstruct_allocz(s->pkt.nb_nals * 
>> sizeof(*frame->rpl));
>>          if (!frame->rpl)
>>              goto fail;
> 
> Which results in
> 
>> [Parsed_showinfo_0 @ 000001f776dc6020]   side data - Spherical 
>> Mapping: rectilinear
>> [Parsed_showinfo_0 @ 000001f776dc6020]   side data - Stereo 3D: type - 
>> frame alternate, view - right, primary_eye - none, baseline: 19240, 
>> horizontal_disparity_adjustment: 0.0200, horizontal_field_of_view: 63.400
>> [Parsed_showinfo_0 @ 000001f776dc6020]   side data - View ID: view id: 0
> 

Turns out doing this results in the output muxer/encoder context having 
this as global side data, because enc_open() in ffmpeg_enc.c initializes 
avctx.decoded_side_data with the first frame. Which would maybe be nice 
if not for the fact you get "view - right" even if you output both.

It does not happen with your patch as is because the loop in enc_open() 
will use the last side data of a given type, and the second one for 
stereo 3d in this scenario is coincidentally the source container one.

-------------- 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/20240915/c044629b/attachment.sig>


More information about the ffmpeg-devel mailing list