@@ -20,6 +20,7 @@
#include "libavutil/avassert.h"
#include "libavutil/display.h"
#include "libavutil/mastering_display_metadata.h"
+#include "libavutil/stereo3d.h"
#include "bytestream.h"
#include "cbs.h"
@@ -1684,6 +1685,87 @@ static const SEIMessageTypeDescriptor cbs_sei_common_types[] = {
SEI_MESSAGE_TYPE_END,
};
+static struct {
+ enum AVStereo3DType st_type;
+ uint8_t fpa_type;
+} cbs_sei_fpa_type_map[] = {
+ { AV_STEREO3D_2D, 6 },
+ { AV_STEREO3D_SIDEBYSIDE, 3 },
+ { AV_STEREO3D_TOPBOTTOM, 4 },
+ { AV_STEREO3D_FRAMESEQUENCE, 5 },
+ { AV_STEREO3D_CHECKERBOARD, 0 },
+ { AV_STEREO3D_SIDEBYSIDE_QUINCUNX, 3 },
+ { AV_STEREO3D_LINES, 2 },
+ { AV_STEREO3D_COLUMNS, 1 },
+};
+
+static void cbs_h264_fill_sei_frame_packing_arrangement
+ (H264RawSEIFramePackingArrangement *fpa, const AVStereo3D *st)
+{
+ memset(fpa, 0, sizeof(*fpa));
+
+ for (int i = 0; i < FF_ARRAY_ELEMS(cbs_sei_fpa_type_map); i++) {
+ if (cbs_sei_fpa_type_map[i].st_type == st->type) {
+ fpa->frame_packing_arrangement_type =
+ cbs_sei_fpa_type_map[i].fpa_type;
+ break;
+ }
+ }
+
+ fpa->quincunx_sampling_flag =
+ st->type == AV_STEREO3D_CHECKERBOARD ||
+ st->type == AV_STEREO3D_SIDEBYSIDE_QUINCUNX;
+
+ if (st->type == AV_STEREO3D_2D)
+ fpa->content_interpretation_type = 0;
+ else if (st->flags & AV_STEREO3D_FLAG_INVERT)
+ fpa->content_interpretation_type = 2;
+ else
+ fpa->content_interpretation_type = 1;
+
+ if (st->type == AV_STEREO3D_FRAMESEQUENCE) {
+ if (st->flags & AV_STEREO3D_FLAG_INVERT)
+ fpa->current_frame_is_frame0_flag =
+ st->view == AV_STEREO3D_VIEW_RIGHT;
+ else
+ fpa->current_frame_is_frame0_flag =
+ st->view == AV_STEREO3D_VIEW_LEFT;
+ }
+
+ fpa->frame_packing_arrangement_repetition_period =
+ st->type != AV_STEREO3D_FRAMESEQUENCE;
+}
+
+static void cbs_h264_extract_sei_frame_packing_arrangement
+ (AVStereo3D *st, const H264RawSEIFramePackingArrangement *fpa)
+{
+ memset(st, 0, sizeof(*st));
+
+ if (fpa->frame_packing_arrangement_cancel_flag) {
+ st->type = AV_STEREO3D_2D;
+ return;
+ }
+
+ for (int i = 0; i < FF_ARRAY_ELEMS(cbs_sei_fpa_type_map); i++) {
+ if (cbs_sei_fpa_type_map[i].fpa_type ==
+ fpa->frame_packing_arrangement_type) {
+ st->type = cbs_sei_fpa_type_map[i].st_type;
+ break;
+ }
+ }
+
+ if (st->type == AV_STEREO3D_SIDEBYSIDE &&
+ fpa->quincunx_sampling_flag)
+ st->type = AV_STEREO3D_SIDEBYSIDE_QUINCUNX;
+
+ if (st->type == AV_STEREO3D_2D) {
+ if (fpa->current_frame_is_frame0_flag)
+ st->view = AV_STEREO3D_VIEW_LEFT;
+ else
+ st->view = AV_STEREO3D_VIEW_RIGHT;
+ }
+}
+
static void cbs_h264_fill_sei_display_orientation
(H264RawSEIDisplayOrientation *disp, const int32_t matrix[9])
{
@@ -1791,6 +1873,7 @@ static const SEIMessageTypeDescriptor cbs_sei_h264_types[] = {
1, 0,
sizeof(H264RawSEIFramePackingArrangement),
SEI_MESSAGE_RW(h264, sei_frame_packing_arrangement),
+ SEI_MESSAGE_FE(h264, sei_frame_packing_arrangement),
},
{
SEI_TYPE_DISPLAY_ORIENTATION,
@@ -386,6 +386,8 @@ static const SEIMetadata cbs_sei_metadata[] = {
SEI_TYPE_CONTENT_LIGHT_LEVEL_INFO },
{ CBS_METADATA_DISPLAY_MATRIX,
SEI_TYPE_DISPLAY_ORIENTATION },
+ { CBS_METADATA_STEREO3D,
+ SEI_TYPE_FRAME_PACKING_ARRANGEMENT },
};
static const SEIMessageTypeDescriptor *cbs_sei_find_type_from_metadata