[FFmpeg-devel] [PATCH] h264: add frame packing as stereo_mode frame metadata

Joakim Plate elupus at ecce.se
Thu Jun 27 23:09:06 CEST 2013


This matches the matroska defintion of stereo_mode, with
no metadata written if no info exist in sei
---
 libavcodec/h264.c        |  3 ++
 libavcodec/h264.h        | 36 +++++++++++++++++++-
 libavcodec/h264_parser.c |  3 +-
 libavcodec/h264_sei.c    | 86 ++++++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 126 insertions(+), 2 deletions(-)

diff --git a/libavcodec/h264.c b/libavcodec/h264.c
index bb105ee..2747326 100644
--- a/libavcodec/h264.c
+++ b/libavcodec/h264.c
@@ -1512,6 +1512,7 @@ av_cold int ff_h264_decode_init(AVCodecContext *avctx)
     h->prev_poc_msb = 1 << 16;
     h->prev_frame_num = -1;
     h->x264_build   = -1;
+    h->sei_fpa.frame_packing_arrangement_cancel_flag = -1;
     ff_h264_reset_sei(h);
     if (avctx->codec_id == AV_CODEC_ID_H264) {
         if (avctx->ticks_per_frame == 1) {
@@ -4861,6 +4862,8 @@ static int output_frame(H264Context *h, AVFrame *dst, Picture *srcp)
     if (ret < 0)
         return ret;
 
+    av_dict_set(&dst->metadata, "stereo_mode", ff_h264_sei_stereo_mode(h), 0);
+
     if (!srcp->crop)
         return 0;
 
diff --git a/libavcodec/h264.h b/libavcodec/h264.h
index ed07ad6..b2365bc 100644
--- a/libavcodec/h264.h
+++ b/libavcodec/h264.h
@@ -127,7 +127,8 @@ typedef enum {
     SEI_TYPE_PIC_TIMING             = 1,   ///< picture timing
     SEI_TYPE_USER_DATA_ITU_T_T35    = 4,   ///< user data registered by ITU-T Recommendation T.35
     SEI_TYPE_USER_DATA_UNREGISTERED = 5,   ///< unregistered user data
-    SEI_TYPE_RECOVERY_POINT         = 6    ///< recovery point (frame # to decoder sync)
+    SEI_TYPE_RECOVERY_POINT         = 6,   ///< recovery point (frame # to decoder sync)
+    SEI_TYPE_FRAME_PACKING          = 45,  ///< frame packing arrangement
 } SEI_Type;
 
 /**
@@ -146,6 +147,19 @@ typedef enum {
 } SEI_PicStructType;
 
 /**
+ * frame_packing_arrangement types
+ */
+typedef enum {
+    SEI_FPA_TYPE_CHECKERBOARD        = 0,
+    SEI_FPA_TYPE_INTERLEAVE_COLUMN   = 1,
+    SEI_FPA_TYPE_INTERLEAVE_ROW      = 2,
+    SEI_FPA_TYPE_SIDE_BY_SIDE        = 3,
+    SEI_FPA_TYPE_TOP_BOTTOM          = 4,
+    SEI_FPA_TYPE_INTERLEAVE_TEMPORAL = 5,
+    SEI_FPA_TYPE_2D                  = 6,
+} SEI_FpaType;
+
+/**
  * Sequence parameter set
  */
 typedef struct SPS {
@@ -233,6 +247,18 @@ typedef struct PPS {
 } PPS;
 
 /**
+ * Frame Packing Arrangement Type
+ */
+typedef struct FPA {
+    int         frame_packing_arrangement_id;
+    int         frame_packing_arrangement_cancel_flag; ///< is previous arrangement canceled, -1 if never received
+    SEI_FpaType frame_packing_arrangement_type;
+    int         frame_packing_arrangement_repetition_period;
+    int         content_interpretation_type;
+    int         quincunx_sampling_flag;
+} FPA;
+
+/**
  * Memory management control operation opcode.
  */
 typedef enum MMCOOpcode {
@@ -628,6 +654,8 @@ typedef struct H264Context {
      */
     int valid_recovery_point;
 
+    FPA sei_fpa;
+
     int luma_weight_flag[2];    ///< 7.4.3.2 luma_weight_lX_flag
     int chroma_weight_flag[2];  ///< 7.4.3.2 chroma_weight_lX_flag
 
@@ -775,6 +803,12 @@ void ff_h264_filter_mb(H264Context *h, int mb_x, int mb_y,
  */
 void ff_h264_reset_sei(H264Context *h);
 
+/**
+ * Get stereo_mode string from the h264 frame_packing_arrangement
+ * @param h H.264 context.
+ */
+const char* ff_h264_sei_stereo_mode(H264Context *h);
+
 /*
  * o-o o-o
  *  / / /
diff --git a/libavcodec/h264_parser.c b/libavcodec/h264_parser.c
index 3b7d011..a5d47ed 100644
--- a/libavcodec/h264_parser.c
+++ b/libavcodec/h264_parser.c
@@ -172,6 +172,7 @@ static inline int parse_nal_units(AVCodecParserContext *s,
     h->sei_dpb_output_delay         = 0;
     h->sei_cpb_removal_delay        = -1;
     h->sei_buffering_period_present = 0;
+    h->sei_fpa.frame_packing_arrangement_cancel_flag = -1;
 
     if (!buf_size)
         return 0;
@@ -254,7 +255,7 @@ static inline int parse_nal_units(AVCodecParserContext *s,
             }
             h->sps       = *h->sps_buffers[h->pps.sps_id];
             h->frame_num = get_bits(&h->gb, h->sps.log2_max_frame_num);
-
+ 
             avctx->profile = ff_h264_get_profile(&h->sps);
             avctx->level   = h->sps.level_idc;
 
diff --git a/libavcodec/h264_sei.c b/libavcodec/h264_sei.c
index 5f68a13..9320852 100644
--- a/libavcodec/h264_sei.c
+++ b/libavcodec/h264_sei.c
@@ -204,6 +204,44 @@ static int decode_buffering_period(H264Context *h){
     return 0;
 }
 
+static int decode_frame_packing(H264Context *h, int size){
+    int bits = get_bits_left(&h->gb);
+
+    h->sei_fpa.frame_packing_arrangement_id          = get_ue_golomb(&h->gb);
+    h->sei_fpa.frame_packing_arrangement_cancel_flag = get_bits(&h->gb, 1);
+    if (!h->sei_fpa.frame_packing_arrangement_cancel_flag) {
+        h->sei_fpa.frame_packing_arrangement_type  = get_bits(&h->gb, 7);
+        h->sei_fpa.quincunx_sampling_flag          = get_bits(&h->gb, 1);
+        h->sei_fpa.content_interpretation_type     = get_bits(&h->gb, 6);
+        skip_bits(&h->gb, 1); /* spatial_flipping_flag */
+        skip_bits(&h->gb, 1); /* frame0_flipped_flag */
+        skip_bits(&h->gb, 1); /* field_views_flag */
+        skip_bits(&h->gb, 1); /* current_frame_is_frame0_flag */
+        skip_bits(&h->gb, 1); /* frame0_self_contained_flag */
+        skip_bits(&h->gb, 1); /* frame1_self_contained_flag */
+        if (!h->sei_fpa.quincunx_sampling_flag && h->sei_fpa.frame_packing_arrangement_type != 5) {
+            skip_bits(&h->gb, 4); /* frame0_grid_position_x */
+            skip_bits(&h->gb, 4); /* frame0_grid_position_y */
+            skip_bits(&h->gb, 4); /* frame1_grid_position_x */
+            skip_bits(&h->gb, 4); /* frame1_grid_position_y */
+        }
+        skip_bits(&h->gb, 8); /* frame_packing_arrangement_reserved_byte */
+        h->sei_fpa.frame_packing_arrangement_repetition_period = get_ue_golomb(&h->gb) /* frame_packing_arrangement_repetition_period */;
+    }
+    skip_bits(&h->gb, 1); /* frame_packing_arrangement_extension_flag */
+
+    if (h->avctx->debug & FF_DEBUG_PICT_INFO)
+        av_log(h->avctx, AV_LOG_DEBUG, "SEI FPA %d %d %d %d %d %d\n",
+                                       h->sei_fpa.frame_packing_arrangement_id,
+                                       h->sei_fpa.frame_packing_arrangement_cancel_flag,
+                                       h->sei_fpa.frame_packing_arrangement_type,
+                                       h->sei_fpa.quincunx_sampling_flag,
+                                       h->sei_fpa.content_interpretation_type,
+                                       h->sei_fpa.frame_packing_arrangement_repetition_period);
+    skip_bits_long(&h->gb, 8*size - (bits - get_bits_left(&h->gb)));
+    return 0;
+}
+
 int ff_h264_decode_sei(H264Context *h){
     while (get_bits_left(&h->gb) > 16) {
         int size, type;
@@ -246,6 +284,9 @@ int ff_h264_decode_sei(H264Context *h){
             if(decode_buffering_period(h) < 0)
                 return -1;
             break;
+        case SEI_TYPE_FRAME_PACKING:
+            if(decode_frame_packing(h, size) < 0)
+                return -1;
         default:
             skip_bits(&h->gb, 8*size);
         }
@@ -256,3 +297,48 @@ int ff_h264_decode_sei(H264Context *h){
 
     return 0;
 }
+
+const char* ff_h264_sei_stereo_mode(H264Context *h)
+{
+    if (h->sei_fpa.frame_packing_arrangement_cancel_flag == 0) {
+        switch (h->sei_fpa.frame_packing_arrangement_type) {
+            case SEI_FPA_TYPE_CHECKERBOARD:
+                if (h->sei_fpa.content_interpretation_type == 2)
+                    return "checkerboard_rl";
+                else
+                    return "checkerboard_lr";
+            case SEI_FPA_TYPE_INTERLEAVE_COLUMN:
+                if (h->sei_fpa.content_interpretation_type == 2)
+                    return "col_interleaved_rl";
+                else
+                    return "col_interleaved_lr";
+            case SEI_FPA_TYPE_INTERLEAVE_ROW:
+                if (h->sei_fpa.content_interpretation_type == 2)
+                    return "row_interleaved_rl";
+                else
+                    return "row_interleaved_lr";
+            case SEI_FPA_TYPE_SIDE_BY_SIDE:
+                if (h->sei_fpa.content_interpretation_type == 2)
+                    return "right_left";
+                else
+                    return "left_right";
+            case SEI_FPA_TYPE_TOP_BOTTOM:
+                if (h->sei_fpa.content_interpretation_type == 2)
+                    return "bottom_top";
+                else
+                    return "top_bottom";
+            case SEI_FPA_TYPE_INTERLEAVE_TEMPORAL:
+                if (h->sei_fpa.content_interpretation_type == 2)
+                    return "block_rl";
+                else
+                    return "block_lr";
+            case SEI_FPA_TYPE_2D:
+            default:
+                return "mono";
+        }
+    } else if (h->sei_fpa.frame_packing_arrangement_cancel_flag == 1) {
+        return "mono";
+    } else {
+        return NULL;
+    }
+}
-- 
1.8.2



More information about the ffmpeg-devel mailing list