codecparsers: h264: parse MVC syntax elements.
authorGwenole Beauchesne <gwenole.beauchesne@intel.com>
Wed, 26 Sep 2012 16:46:36 +0000 (18:46 +0200)
committerJan Schmidt <jan@centricular.com>
Wed, 29 Oct 2014 12:09:41 +0000 (23:09 +1100)
https://bugzilla.gnome.org/show_bug.cgi?id=685215

Signed-off-by: Gwenole Beauchesne <gwenole.beauchesne@intel.com>
gst-libs/gst/codecparsers/gsth264parser.c
gst-libs/gst/codecparsers/gsth264parser.h

index 6631745..5cafa1c 100644 (file)
@@ -204,6 +204,8 @@ static gboolean
 gst_h264_parse_nalu_header (GstH264NalUnit * nalu)
 {
   guint8 *data = nalu->data + nalu->offset;
+  guint8 svc_extension_flag;
+  GstBitReader br;
 
   if (nalu->size < 1)
     return FALSE;
@@ -211,6 +213,37 @@ gst_h264_parse_nalu_header (GstH264NalUnit * nalu)
   nalu->type = (data[0] & 0x1f);
   nalu->ref_idc = (data[0] & 0x60) >> 5;
   nalu->idr_pic_flag = (nalu->type == 5 ? 1 : 0);
+  nalu->header_bytes = 1;
+
+  switch (nalu->type) {
+    case GST_H264_NAL_PREFIX_UNIT:
+    case GST_H264_NAL_SLICE_EXT:
+      if (nalu->size < 4)
+        return FALSE;
+      gst_bit_reader_init (&br, nalu->data + nalu->offset + nalu->header_bytes,
+          nalu->size - nalu->header_bytes);
+
+      svc_extension_flag = gst_bit_reader_get_bits_uint8_unchecked (&br, 1);
+      if (!svc_extension_flag) {        /* MVC */
+        GstH264NalUnitExtensionMVC *const mvc = &nalu->extension.mvc;
+
+        nalu->extension_type = GST_H264_NAL_EXTENSION_MVC;
+        mvc->non_idr_flag = gst_bit_reader_get_bits_uint8_unchecked (&br, 1);
+        mvc->priority_id = gst_bit_reader_get_bits_uint8_unchecked (&br, 6);
+        mvc->view_id = gst_bit_reader_get_bits_uint16_unchecked (&br, 10);
+        mvc->temporal_id = gst_bit_reader_get_bits_uint8_unchecked (&br, 3);
+        mvc->anchor_pic_flag = gst_bit_reader_get_bits_uint8_unchecked (&br, 1);
+        mvc->inter_view_flag = gst_bit_reader_get_bits_uint8_unchecked (&br, 1);
+
+        /* Update IdrPicFlag (H.7.4.1.1) */
+        nalu->idr_pic_flag = !mvc->non_idr_flag;
+      }
+      nalu->header_bytes += 3;
+      break;
+    default:
+      nalu->extension_type = GST_H264_NAL_EXTENSION_NONE;
+      break;
+  }
 
   GST_DEBUG ("Nal type %u, ref_idc %u", nalu->type, nalu->ref_idc);
   return TRUE;
@@ -497,7 +530,7 @@ error:
 
 static gboolean
 slice_parse_ref_pic_list_modification_1 (GstH264SliceHdr * slice,
-    NalReader * nr, guint list)
+    NalReader * nr, guint list, gboolean is_mvc)
 {
   GstH264RefPicListModification *entries;
   guint8 *ref_pic_list_modification_flag, *n_ref_pic_list_modification;
@@ -526,7 +559,11 @@ slice_parse_ref_pic_list_modification_1 (GstH264SliceHdr * slice,
             slice->max_pic_num - 1);
       } else if (modification_of_pic_nums_idc == 2) {
         READ_UE (nr, entries[i].value.long_term_pic_num);
-      }
+      } else if (is_mvc && (modification_of_pic_nums_idc == 4 ||
+              modification_of_pic_nums_idc == 5)) {
+        READ_UE (nr, entries[i].value.abs_diff_view_idx_minus1);
+      } else
+        continue;
       entries[i++].modification_of_pic_nums_idc = modification_of_pic_nums_idc;
     }
   }
@@ -540,15 +577,16 @@ error:
 }
 
 static gboolean
-slice_parse_ref_pic_list_modification (GstH264SliceHdr * slice, NalReader * nr)
+slice_parse_ref_pic_list_modification (GstH264SliceHdr * slice, NalReader * nr,
+    gboolean is_mvc)
 {
   if (!GST_H264_IS_I_SLICE (slice) && !GST_H264_IS_SI_SLICE (slice)) {
-    if (!slice_parse_ref_pic_list_modification_1 (slice, nr, 0))
+    if (!slice_parse_ref_pic_list_modification_1 (slice, nr, 0, is_mvc))
       return FALSE;
   }
 
   if (GST_H264_IS_B_SLICE (slice)) {
-    if (!slice_parse_ref_pic_list_modification_1 (slice, nr, 1))
+    if (!slice_parse_ref_pic_list_modification_1 (slice, nr, 1, is_mvc))
       return FALSE;
   }
   return TRUE;
@@ -1288,9 +1326,11 @@ gst_h264_parse_sps_data (NalReader * nr, GstH264SPS * sps,
   READ_UINT8 (nr, sps->constraint_set1_flag, 1);
   READ_UINT8 (nr, sps->constraint_set2_flag, 1);
   READ_UINT8 (nr, sps->constraint_set3_flag, 1);
+  READ_UINT8 (nr, sps->constraint_set4_flag, 1);
+  READ_UINT8 (nr, sps->constraint_set5_flag, 1);
 
-  /* skip reserved_zero_4bits */
-  if (!nal_reader_skip (nr, 4))
+  /* skip reserved_zero_2bits */
+  if (!nal_reader_skip (nr, 2))
     goto error;
 
   READ_UINT8 (nr, sps->level_idc, 8);
@@ -1300,7 +1340,8 @@ gst_h264_parse_sps_data (NalReader * nr, GstH264SPS * sps,
   if (sps->profile_idc == 100 || sps->profile_idc == 110 ||
       sps->profile_idc == 122 || sps->profile_idc == 244 ||
       sps->profile_idc == 44 || sps->profile_idc == 83 ||
-      sps->profile_idc == 86) {
+      sps->profile_idc == 86 || sps->profile_idc == 118 ||
+      sps->profile_idc == 128) {
     READ_UE_ALLOWED (nr, sps->chroma_format_idc, 0, 3);
     if (sps->chroma_format_idc == 3)
       READ_UINT8 (nr, sps->separate_colour_plane_flag, 1);
@@ -1449,7 +1490,8 @@ gst_h264_parse_sps (GstH264NalUnit * nalu, GstH264SPS * sps,
   INITIALIZE_DEBUG_CATEGORY;
   GST_DEBUG ("parsing SPS");
 
-  nal_reader_init (&nr, nalu->data + nalu->offset + 1, nalu->size - 1);
+  nal_reader_init (&nr, nalu->data + nalu->offset + nalu->header_bytes,
+      nalu->size - nalu->header_bytes);
 
   if (!gst_h264_parse_sps_data (&nr, sps, parse_vui_params))
     goto error;
@@ -1465,6 +1507,67 @@ error:
 }
 
 /**
+ * gst_h264_parser_parse_subset_sps:
+ * @nalparser: a #GstH264NalParser
+ * @nalu: The #GST_H264_NAL_SUBSET_SPS #GstH264NalUnit to parse
+ * @sps: The #GstH264SPS to fill.
+ * @parse_vui_params: Whether to parse the vui_params or not
+ *
+ * Parses @data, and fills in the @sps structure.
+ *
+ * Returns: a #GstH264ParserResult
+ */
+GstH264ParserResult
+gst_h264_parser_parse_subset_sps (GstH264NalParser * nalparser,
+    GstH264NalUnit * nalu, GstH264SPS * sps, gboolean parse_vui_params)
+{
+  GstH264ParserResult res;
+
+  res = gst_h264_parse_subset_sps (nalu, sps, parse_vui_params);
+  if (res == GST_H264_PARSER_OK) {
+    GST_DEBUG ("adding sequence parameter set with id: %d to array", sps->id);
+
+    nalparser->sps[sps->id] = *sps;
+    nalparser->last_sps = &nalparser->sps[sps->id];
+  }
+  return res;
+}
+
+/**
+ * gst_h264_parse_subset_sps:
+ * @nalu: The #GST_H264_NAL_SUBSET_SPS #GstH264NalUnit to parse
+ * @sps: The #GstH264SPS to fill.
+ * @parse_vui_params: Whether to parse the vui_params or not
+ *
+ * Parses @data, and fills in the @sps structure.
+ *
+ * Returns: a #GstH264ParserResult
+ */
+GstH264ParserResult
+gst_h264_parse_subset_sps (GstH264NalUnit * nalu, GstH264SPS * sps,
+    gboolean parse_vui_params)
+{
+  NalReader nr;
+
+  INITIALIZE_DEBUG_CATEGORY;
+  GST_DEBUG ("parsing Subset SPS");
+
+  nal_reader_init (&nr, nalu->data + nalu->offset + nalu->header_bytes,
+      nalu->size - nalu->header_bytes);
+
+  if (!gst_h264_parse_sps_data (&nr, sps, parse_vui_params))
+    goto error;
+
+  sps->valid = TRUE;
+  return GST_H264_PARSER_OK;
+
+error:
+  GST_WARNING ("error parsing \"Subset sequence parameter set\"");
+  sps->valid = FALSE;
+  return GST_H264_PARSER_ERROR;
+}
+
+/**
  * gst_h264_parse_pps:
  * @nalparser: a #GstH264NalParser
  * @nalu: The #GST_H264_NAL_PPS #GstH264NalUnit to parse
@@ -1491,7 +1594,8 @@ gst_h264_parse_pps (GstH264NalParser * nalparser, GstH264NalUnit * nalu,
   INITIALIZE_DEBUG_CATEGORY;
   GST_DEBUG ("parsing PPS");
 
-  nal_reader_init (&nr, nalu->data + nalu->offset + 1, nalu->size - 1);
+  nal_reader_init (&nr, nalu->data + nalu->offset + nalu->header_bytes,
+      nalu->size - nalu->header_bytes);
 
   READ_UE_ALLOWED (&nr, pps->id, 0, GST_H264_MAX_PPS_COUNT - 1);
   READ_UE_ALLOWED (&nr, sps_id, 0, GST_H264_MAX_SPS_COUNT - 1);
@@ -1676,7 +1780,8 @@ gst_h264_parser_parse_slice_hdr (GstH264NalParser * nalparser,
   }
 
 
-  nal_reader_init (&nr, nalu->data + nalu->offset + 1, nalu->size - 1);
+  nal_reader_init (&nr, nalu->data + nalu->offset + nalu->header_bytes,
+      nalu->size - nalu->header_bytes);
 
   READ_UE (&nr, slice->first_mb_in_slice);
   READ_UE (&nr, slice->type);
@@ -1768,7 +1873,8 @@ gst_h264_parser_parse_slice_hdr (GstH264NalParser * nalparser,
     }
   }
 
-  if (!slice_parse_ref_pic_list_modification (slice, &nr))
+  if (!slice_parse_ref_pic_list_modification (slice, &nr,
+          GST_H264_IS_MVC_NALU (nalu)))
     goto error;
 
   if ((pps->weighted_pred_flag && (GST_H264_IS_P_SLICE (slice)
@@ -1846,7 +1952,8 @@ gst_h264_parser_parse_sei (GstH264NalParser * nalparser, GstH264NalUnit * nalu,
   GstH264ParserResult res;
 
   GST_DEBUG ("parsing SEI nal");
-  nal_reader_init (&nr, nalu->data + nalu->offset + 1, nalu->size - 1);
+  nal_reader_init (&nr, nalu->data + nalu->offset + nalu->header_bytes,
+      nalu->size - nalu->header_bytes);
   *messages = g_array_new (FALSE, FALSE, sizeof (GstH264SEIMessage));
 
   do {
index 27e8214..a78f307 100644 (file)
@@ -48,6 +48,9 @@ G_BEGIN_DECLS
 #define GST_H264_IS_SP_SLICE(slice) (((slice)->type % 5) == GST_H264_SP_SLICE)
 #define GST_H264_IS_SI_SLICE(slice) (((slice)->type % 5) == GST_H264_SI_SLICE)
 
+#define GST_H264_IS_MVC_NALU(nalu) \
+  ((nalu)->extension_type == GST_H264_NAL_EXTENSION_MVC)
+
 /**
  * GstH264Profile:
  * @GST_H264_PROFILE_BASELINE: Baseline profile (A.2.1)
@@ -132,6 +135,19 @@ typedef enum
 } GstH264NalUnitType;
 
 /**
+ * GstH264NalUnitExtensionType:
+ * @GST_H264_NAL_EXTENSION_NONE: No NAL unit header extension is available
+ * @GST_H264_NAL_EXTENSION_MVC: NAL unit header extension for MVC (Annex H)
+ *
+ * Indicates the type of H.264 NAL unit extension.
+ */
+typedef enum
+{
+  GST_H264_NAL_EXTENSION_NONE = 0,
+  GST_H264_NAL_EXTENSION_MVC,
+} GstH264NalUnitExtensionType;
+
+/**
  * GstH264ParserResult:
  * @GST_H264_PARSER_OK: The parsing succeded
  * @GST_H264_PARSER_BROKEN_DATA: The data to parse is broken
@@ -221,6 +237,7 @@ typedef enum
 typedef struct _GstH264NalParser              GstH264NalParser;
 
 typedef struct _GstH264NalUnit                GstH264NalUnit;
+typedef struct _GstH264NalUnitExtensionMVC    GstH264NalUnitExtensionMVC;
 
 typedef struct _GstH264SPS                    GstH264SPS;
 typedef struct _GstH264PPS                    GstH264PPS;
@@ -240,6 +257,29 @@ typedef struct _GstH264RecoveryPoint          GstH264RecoveryPoint;
 typedef struct _GstH264SEIMessage             GstH264SEIMessage;
 
 /**
+ * GstH264NalUnitExtensionMVC:
+ * @non_idr_flag: If equal to 0, it specifies that the current access
+ *   unit is an IDR access unit
+ * @priority_id: The priority identifier for the NAL unit
+ * @view_id: The view identifier for the NAL unit
+ * @temporal_id: The temporal identifier for the NAL unit
+ * @anchor_pic_flag: If equal to 1, it specifies that the current
+ *   access unit is an anchor access unit
+ * @inter_view_flag: If equal to 0, it specifies that the current view
+ *   component is not used for inter-view prediction by any other view
+ *   component in the current access unit
+ */
+struct _GstH264NalUnitExtensionMVC
+{
+  guint8 non_idr_flag;
+  guint8 priority_id;
+  guint16 view_id;
+  guint8 temporal_id;
+  guint8 anchor_pic_flag;
+  guint8 inter_view_flag;
+};
+
+/**
  * GstH264NalUnit:
  * @ref_idc: not equal to 0 specifies that the content of the NAL unit
  *  contains a sequence parameter set, a sequence parameter set
@@ -257,6 +297,7 @@ typedef struct _GstH264SEIMessage             GstH264SEIMessage;
  * @valid: If the nal unit is valid, which means it has
  * already been parsed
  * @data: The data from which the Nalu has been parsed
+ * @header_bytes: The size of the NALU header in bytes
  *
  * Structure defining the Nal unit headers
  */
@@ -273,6 +314,12 @@ struct _GstH264NalUnit
   gboolean valid;
 
   guint8 *data;
+
+  guint8 header_bytes;
+  guint8 extension_type;
+  union {
+    GstH264NalUnitExtensionMVC mvc;
+  } extension;
 };
 
 /**
@@ -439,6 +486,8 @@ struct _GstH264SPS
   guint8 constraint_set1_flag;
   guint8 constraint_set2_flag;
   guint8 constraint_set3_flag;
+  guint8 constraint_set4_flag;
+  guint8 constraint_set5_flag;
   guint8 level_idc;
 
   guint8 chroma_format_idc;
@@ -556,6 +605,8 @@ struct _GstH264RefPicListModification
     guint32 abs_diff_pic_num_minus1;
     /* if modification_of_pic_nums_idc == 2 */
     guint32 long_term_pic_num;
+    /* if modification_of_pic_nums_idc == 4 || 5 */
+    guint32 abs_diff_view_idx_minus1;
   } value;
 };
 
@@ -768,6 +819,9 @@ GstH264ParserResult gst_h264_parser_parse_slice_hdr   (GstH264NalParser *nalpars
                                                        GstH264SliceHdr *slice, gboolean parse_pred_weight_table,
                                                        gboolean parse_dec_ref_pic_marking);
 
+GstH264ParserResult gst_h264_parser_parse_subset_sps  (GstH264NalParser *nalparser, GstH264NalUnit *nalu,
+                                                       GstH264SPS *sps, gboolean parse_vui_params);
+
 GstH264ParserResult gst_h264_parser_parse_sps         (GstH264NalParser *nalparser, GstH264NalUnit *nalu,
                                                        GstH264SPS *sps, gboolean parse_vui_params);
 
@@ -779,6 +833,9 @@ GstH264ParserResult gst_h264_parser_parse_sei         (GstH264NalParser *nalpars
 
 void gst_h264_nal_parser_free                         (GstH264NalParser *nalparser);
 
+GstH264ParserResult gst_h264_parse_subset_sps         (GstH264NalUnit *nalu,
+                                                       GstH264SPS *sps, gboolean parse_vui_params);
+
 GstH264ParserResult gst_h264_parse_sps                (GstH264NalUnit *nalu,
                                                        GstH264SPS *sps, gboolean parse_vui_params);