diff --git a/libavcodec/cbs_h264.h b/libavcodec/cbs_h264.h
index abc0c1b732..512674ec07 100644
--- a/libavcodec/cbs_h264.h
+++ b/libavcodec/cbs_h264.h
@@ -296,6 +296,29 @@ typedef struct H264RawSEIRecoveryPoint {
     uint8_t changing_slice_group_idc;
 } H264RawSEIRecoveryPoint;
 
+typedef struct H264RawSEIFramePackingArrangement {
+    uint32_t frame_packing_arrangement_id;
+    uint8_t  frame_packing_arrangement_cancel_flag;
+
+    uint8_t  frame_packing_arrangement_type;
+    uint8_t  quincunx_sampling_flag;
+    uint8_t  content_interpretation_type;
+    uint8_t  spatial_flipping_flag;
+    uint8_t  frame0_flipped_flag;
+    uint8_t  field_views_flag;
+    uint8_t  current_frame_is_frame0_flag;
+    uint8_t  frame0_self_contained_flag;
+    uint8_t  frame1_self_contained_flag;
+    uint8_t  frame0_grid_position_x;
+    uint8_t  frame0_grid_position_y;
+    uint8_t  frame1_grid_position_x;
+    uint8_t  frame1_grid_position_y;
+    uint8_t  frame_packing_arrangement_reserved_byte;
+    uint16_t frame_packing_arrangement_repetition_period;
+
+    uint8_t  frame_packing_arrangement_extension_flag;
+} H264RawSEIFramePackingArrangement;
+
 typedef struct H264RawSEIDisplayOrientation {
     uint8_t display_orientation_cancel_flag;
     uint8_t hor_flip;
@@ -329,6 +352,7 @@ typedef struct H264RawSEIPayload {
         H264RawSEIUserDataRegistered user_data_registered;
         H264RawSEIUserDataUnregistered user_data_unregistered;
         H264RawSEIRecoveryPoint recovery_point;
+        H264RawSEIFramePackingArrangement frame_packing_arrangement;
         H264RawSEIDisplayOrientation display_orientation;
         H264RawSEIMasteringDisplayColourVolume mastering_display_colour_volume;
         H264RawSEIAlternativeTransferCharacteristics
diff --git a/libavcodec/cbs_h2645.c b/libavcodec/cbs_h2645.c
index f0bd5cacc8..8cea55509b 100644
--- a/libavcodec/cbs_h2645.c
+++ b/libavcodec/cbs_h2645.c
@@ -1328,6 +1328,7 @@ void ff_cbs_h264_free_sei_payload(H264RawSEIPayload *payload)
     case H264_SEI_TYPE_PIC_TIMING:
     case H264_SEI_TYPE_PAN_SCAN_RECT:
     case H264_SEI_TYPE_RECOVERY_POINT:
+    case H264_SEI_TYPE_FRAME_PACKING:
     case H264_SEI_TYPE_DISPLAY_ORIENTATION:
     case H264_SEI_TYPE_MASTERING_DISPLAY_COLOUR_VOLUME:
     case H264_SEI_TYPE_ALTERNATIVE_TRANSFER:
diff --git a/libavcodec/cbs_h264_syntax_template.c b/libavcodec/cbs_h264_syntax_template.c
index 878d348b94..e68944d3b8 100644
--- a/libavcodec/cbs_h264_syntax_template.c
+++ b/libavcodec/cbs_h264_syntax_template.c
@@ -779,6 +779,42 @@ static int FUNC(sei_recovery_point)(CodedBitstreamContext *ctx, RWContext *rw,
     return 0;
 }
 
+static int FUNC(sei_frame_packing_arrangement)(CodedBitstreamContext *ctx, RWContext *rw,
+                                               H264RawSEIFramePackingArrangement *current)
+{
+    int err;
+
+    HEADER("Frame Packing Arrangement");
+
+    ue(frame_packing_arrangement_id, 0, UINT32_MAX - 1);
+    flag(frame_packing_arrangement_cancel_flag);
+
+    if (!current->frame_packing_arrangement_cancel_flag) {
+        u(7, frame_packing_arrangement_type, 0, 7);
+        flag(quincunx_sampling_flag);
+        u(6, content_interpretation_type, 0, 2);
+        flag(spatial_flipping_flag);
+        flag(frame0_flipped_flag);
+        flag(field_views_flag);
+        flag(current_frame_is_frame0_flag);
+        flag(frame0_self_contained_flag);
+        flag(frame1_self_contained_flag);
+        if (!current->quincunx_sampling_flag &&
+            current->frame_packing_arrangement_type != 5) {
+            ub(4, frame0_grid_position_x);
+            ub(4, frame0_grid_position_y);
+            ub(4, frame1_grid_position_x);
+            ub(4, frame1_grid_position_y);
+        }
+        u(8, frame_packing_arrangement_reserved_byte, 0, 0);
+        ue(frame_packing_arrangement_repetition_period, 0, 16384);
+    }
+
+    flag(frame_packing_arrangement_extension_flag);
+
+    return 0;
+}
+
 static int FUNC(sei_display_orientation)(CodedBitstreamContext *ctx, RWContext *rw,
                                          H264RawSEIDisplayOrientation *current)
 {
@@ -879,6 +915,10 @@ static int FUNC(sei_payload)(CodedBitstreamContext *ctx, RWContext *rw,
         CHECK(FUNC(sei_display_orientation)
               (ctx, rw, &current->payload.display_orientation));
         break;
+    case H264_SEI_TYPE_FRAME_PACKING:
+        CHECK(FUNC(sei_frame_packing_arrangement)
+              (ctx, rw, &current->payload.frame_packing_arrangement));
+        break;
     case H264_SEI_TYPE_MASTERING_DISPLAY_COLOUR_VOLUME:
         CHECK(FUNC(sei_mastering_display_colour_volume)
               (ctx, rw, &current->payload.mastering_display_colour_volume));
