typefind: Add typefind function for H265
authorSreerenj Balachandran <sreerenj.balachandran@intel.com>
Tue, 24 Sep 2013 12:51:46 +0000 (15:51 +0300)
committerSebastian Dröge <slomo@circular-chaos.org>
Tue, 1 Oct 2013 21:14:33 +0000 (23:14 +0200)
https://bugzilla.gnome.org/show_bug.cgi?id=708680

gst/typefind/gsttypefindfunctions.c

index 93021b41e7c8fc5770dfc7112a26dc423aa08ae4..5126efb9a27583741098b0f455087aa7289f9a67 100644 (file)
@@ -2685,6 +2685,99 @@ h264_video_type_find (GstTypeFind * tf, gpointer unused)
   }
 }
 
+/*** video/x-h265 H265 elementary video stream ***/
+
+static GstStaticCaps h265_video_caps =
+GST_STATIC_CAPS ("video/x-h265,stream-format=byte-stream");
+
+#define H265_VIDEO_CAPS gst_static_caps_get(&h265_video_caps)
+
+#define H265_MAX_PROBE_LENGTH (128 * 1024)      /* 128kB for HD should be enough. */
+
+static void
+h265_video_type_find (GstTypeFind * tf, gpointer unused)
+{
+  DataScanCtx c = { 0, NULL, 0 };
+
+  /* Stream consists of: a series of sync codes (00 00 00 01) followed
+   * by NALs
+   */
+  gboolean seen_irap = FALSE;
+  gboolean seen_vps = FALSE;
+  gboolean seen_sps = FALSE;
+  gboolean seen_pps = FALSE;
+  int nut;
+  int good = 0;
+  int bad = 0;
+
+  while (c.offset < H265_MAX_PROBE_LENGTH) {
+    if (G_UNLIKELY (!data_scan_ctx_ensure_data (tf, &c, 5)))
+      break;
+
+    if (IS_MPEG_HEADER (c.data)) {
+      /* forbiden_zero_bit | nal_unit_type */
+      nut = c.data[3] & 0xfe;
+
+      /* if forbidden bit is different to 0 won't be h265 */
+      if (nut > 0x7e) {
+        bad++;
+        break;
+      }
+      nut = nut >> 1;
+
+      /* if nuh_layer_id is not zero or nuh_temporal_id_plus1 is zero then
+       * it won't be h265 */
+      if ((c.data[3] & 0x01) || (c.data[4] & 0xf8) || !(c.data[4] & 0x07)) {
+        bad++;
+        break;
+      }
+
+      /* collect statistics about the NAL types */
+      if ((nut >= 0 && nut <= 9) || (nut >= 16 && nut <= 21) || (nut >= 32
+              && nut <= 40)) {
+        if (nut == 32)
+          seen_vps = TRUE;
+        else if (nut == 33)
+          seen_sps = TRUE;
+        else if (nut == 34)
+          seen_pps = TRUE;
+        else if (nut >= 16 || nut <= 21) {
+          /* BLA, IDR and CRA pictures are belongs to be IRAP picture */
+          /* we are not counting the reserved IRAP pictures (22 and 23) to good */
+          seen_irap = TRUE;
+        }
+
+        good++;
+      } else if ((nut >= 10 && nut <= 15) || (nut >= 22 && nut <= 31)
+          || (nut >= 41 && nut <= 47)) {
+        /* reserved values are counting as bad */
+        bad++;
+      } else {
+        /* unspecified (48..63), application specific */
+        /* don't consider these as bad */
+      }
+
+      GST_LOG ("good:%d, bad:%d, pps:%d, sps:%d, vps:%d, irap:%d", good, bad,
+          seen_pps, seen_sps, seen_vps, seen_irap);
+
+      if (seen_sps && seen_pps && seen_irap && good >= 10 && bad < 4) {
+        gst_type_find_suggest (tf, GST_TYPE_FIND_LIKELY, H265_VIDEO_CAPS);
+        return;
+      }
+
+      data_scan_ctx_advance (tf, &c, 5);
+    }
+    data_scan_ctx_advance (tf, &c, 1);
+  }
+
+  GST_LOG ("good:%d, bad:%d, pps:%d, sps:%d, vps:%d, irap:%d", good, bad,
+      seen_pps, seen_sps, seen_vps, seen_irap);
+
+  if (good >= 2 && bad == 0) {
+    gst_type_find_suggest (tf, GST_TYPE_FIND_POSSIBLE, H265_VIDEO_CAPS);
+  }
+}
+
 /*** video/mpeg video stream ***/
 
 static GstStaticCaps mpeg_video_caps = GST_STATIC_CAPS ("video/mpeg, "
@@ -5365,6 +5458,8 @@ plugin_init (GstPlugin * plugin)
       h263_video_type_find, "h263,263", H263_VIDEO_CAPS, NULL, NULL);
   TYPE_FIND_REGISTER (plugin, "video/x-h264", GST_RANK_PRIMARY,
       h264_video_type_find, "h264,x264,264", H264_VIDEO_CAPS, NULL, NULL);
+  TYPE_FIND_REGISTER (plugin, "video/x-h265", GST_RANK_PRIMARY,
+      h265_video_type_find, "h265,x265,265", H265_VIDEO_CAPS, NULL, NULL);
   TYPE_FIND_REGISTER (plugin, "video/x-nuv", GST_RANK_SECONDARY, nuv_type_find,
       "nuv", NUV_CAPS, NULL, NULL);