jpeg2000parse: parse RSIZ capabilities and put profile/level into the caps
authorAaron Boxer <boxerab@gmail.com>
Fri, 12 May 2017 19:28:46 +0000 (15:28 -0400)
committerSebastian Dröge <sebastian@centricular.com>
Wed, 7 Jun 2017 07:06:26 +0000 (10:06 +0300)
The RSIZ capabilities tag stores the JPEG 2000 profile. In the case of
broadcast profiles, it also stores the broadcast main level, which
specifies the bit rate.

https://bugzilla.gnome.org/show_bug.cgi?id=782337

gst/videoparsers/gstjpeg2000parse.c
gst/videoparsers/gstjpeg2000parse.h

index e2ebc8c..f20aea0 100644 (file)
 #include "gstjpeg2000parse.h"
 #include <gst/base/base.h>
 
+/* Not used at the moment
+static gboolean gst_jpeg2000_parse_is_cinema(guint16 rsiz)   {
+       return ((rsiz >= GST_JPEG2000_PARSE_PROFILE_CINEMA_2K) && (rsiz <= GST_JPEG2000_PARSE_PROFILE_CINEMA_S4K));
+}
+static gboolean gst_jpeg2000_parse_is_storage(guint16 rsiz)   {
+       return (rsiz == GST_JPEG2000_PARSE_PROFILE_CINEMA_LTS);
+}
+*/
+static gboolean
+gst_jpeg2000_parse_is_broadcast (guint16 rsiz)
+{
+  return ((rsiz >= GST_JPEG2000_PARSE_PROFILE_BC_SINGLE) &&
+      (rsiz <= ((GST_JPEG2000_PARSE_PROFILE_BC_MULTI_R) | (0x000b)))
+      && ((rsiz & (~GST_JPEG2000_PARSE_PROFILE_BC_MASK)) == 0));
+}
+
+static gboolean
+gst_jpeg2000_parse_is_imf (guint16 rsiz)
+{
+  return ((rsiz >= GST_JPEG2000_PARSE_PROFILE_IMF_2K)
+      && (rsiz <= ((GST_JPEG2000_PARSE_PROFILE_IMF_8K_R) | (0x009b))));
+}
+
+static gboolean
+gst_jpeg2000_parse_is_part_2 (guint16 rsiz)
+{
+  return (rsiz & GST_JPEG2000_PARSE_PROFILE_PART2);
+}
+
 
 
 static void
@@ -67,11 +96,13 @@ static GstStaticPadTemplate srctemplate =
         " width = (int)[1, MAX], height = (int)[1, MAX],"
         GST_JPEG2000_SAMPLING_LIST ","
         GST_JPEG2000_COLORSPACE_LIST ","
+        " profile = (int)[0, 49151],"
         " parsed = (boolean) true;"
         "image/x-j2c,"
         " width = (int)[1, MAX], height = (int)[1, MAX],"
         GST_JPEG2000_SAMPLING_LIST ","
-        GST_JPEG2000_COLORSPACE_LIST "," " parsed = (boolean) true")
+        GST_JPEG2000_COLORSPACE_LIST ","
+        " profile = (int)[0, 49151]," " parsed = (boolean) true")
     );
 
 static GstStaticPadTemplate sinktemplate =
@@ -272,6 +303,11 @@ gst_jpeg2000_parse_handle_frame (GstBaseParse * parse,
   guint8 dx[GST_JPEG2000_PARSE_MAX_SUPPORTED_COMPONENTS];
   guint8 dy[GST_JPEG2000_PARSE_MAX_SUPPORTED_COMPONENTS];
   guint16 numcomps;
+  guint16 capabilities = 0;
+  guint16 profile = 0;
+  gboolean validate_main_level = FALSE;
+  guint8 main_level = 0;
+  guint8 sub_level = 0;
   guint16 compno;
   GstJPEG2000Sampling parsed_sampling = GST_JPEG2000_SAMPLING_NONE;
   const gchar *sink_sampling_string = NULL;
@@ -361,10 +397,47 @@ gst_jpeg2000_parse_handle_frame (GstBaseParse * parse,
       goto beach;
   }
 
-  /* 2 to skip marker size, and another 2 to skip rsiz field */
-  if (!gst_byte_reader_skip (&reader, num_prefix_bytes + 2 + 2))
+  /* 2 to skip marker size */
+  if (!gst_byte_reader_skip (&reader, num_prefix_bytes + 2))
+    goto beach;
+
+  if (!gst_byte_reader_get_uint16_be (&reader, &capabilities))
     goto beach;
 
+  profile = capabilities & GST_JPEG2000_PARSE_PROFILE_MASK;
+  if (!gst_jpeg2000_parse_is_part_2 (capabilities)) {
+    if ((profile > GST_JPEG2000_PARSE_PROFILE_CINEMA_LTS)
+        && !gst_jpeg2000_parse_is_broadcast (profile)
+        && !gst_jpeg2000_parse_is_imf (profile)) {
+      GST_ELEMENT_ERROR (jpeg2000parse, STREAM, DECODE, NULL,
+          ("Unrecognized JPEG 2000 profile %d", profile));
+      ret = GST_FLOW_ERROR;
+      goto beach;
+    }
+    if (gst_jpeg2000_parse_is_broadcast (profile)) {
+      main_level = capabilities & 0xF;
+      validate_main_level = TRUE;
+    } else if (gst_jpeg2000_parse_is_imf (profile)) {
+      main_level = capabilities & 0xF;
+      validate_main_level = TRUE;
+      sub_level = (capabilities >> 4) & 0xF;
+      if (sub_level > 9) {
+        GST_ELEMENT_ERROR (jpeg2000parse, STREAM, DECODE, NULL,
+            ("Sub level %d is invalid", sub_level));
+        ret = GST_FLOW_ERROR;
+        goto beach;
+      }
+    }
+    if (validate_main_level && main_level > 11) {
+      GST_ELEMENT_ERROR (jpeg2000parse, STREAM, DECODE, NULL,
+          ("Main level %d is invalid", main_level));
+      ret = GST_FLOW_ERROR;
+      goto beach;
+
+    }
+  }
+
+
   if (!gst_byte_reader_get_uint32_be (&reader, &x1))
     goto beach;
 
@@ -560,10 +633,23 @@ gst_jpeg2000_parse_handle_frame (GstBaseParse * parse,
 
     src_caps =
         gst_caps_new_simple (media_type_from_codec_format
-        (jpeg2000parse->codec_format), "width", G_TYPE_INT, width, "height",
-        G_TYPE_INT, height, "colorspace", G_TYPE_STRING,
+        (jpeg2000parse->codec_format),
+        "width", G_TYPE_INT, width,
+        "height", G_TYPE_INT, height,
+        "colorspace", G_TYPE_STRING,
         gst_jpeg2000_colorspace_to_string (colorspace), "sampling",
-        G_TYPE_STRING, gst_jpeg2000_sampling_to_string (source_sampling), NULL);
+        G_TYPE_STRING, gst_jpeg2000_sampling_to_string (source_sampling),
+        "profile", G_TYPE_UINT, profile, NULL);
+
+    if (gst_jpeg2000_parse_is_broadcast (capabilities)
+        || gst_jpeg2000_parse_is_imf (capabilities)) {
+      gst_caps_set_simple (src_caps, "main-level", G_TYPE_UINT, main_level,
+          NULL);
+      if (gst_jpeg2000_parse_is_imf (capabilities)) {
+        gst_caps_set_simple (src_caps, "sub-level", G_TYPE_UINT, sub_level,
+            NULL);
+      }
+    }
 
     if (gst_structure_get_fraction (current_caps_struct, "framerate", &fr_num,
             &fr_denom)) {
index 93236db..6000f34 100644 (file)
@@ -42,7 +42,64 @@ G_BEGIN_DECLS
 typedef struct _GstJPEG2000Parse GstJPEG2000Parse;
 typedef struct _GstJPEG2000ParseClass GstJPEG2000ParseClass;
 
-#define GST_JPEG2000_PARSE_MAX_SUPPORTED_COMPONENTS 4
+
+/**
+ * JPEG 2000 Profiles (stored in rsiz/capabilities field in code stream header)
+ * See Table A.10 from 15444-1 (updated in various AMDs)
+ *
+ * For broadcast profiles, the GST_JPEG2000_PARSE_PROFILE_BC_XXXX profile value must be combined with the target
+ * main level (3-0 LSBs, with value between 0 and 11).
+ * Example:
+ * capabilities  GST_JPEG2000_PARSE_PROFILE_BC_MULTI | 0x0005 (in this case, main level equals 5)
+ *
+ * For IMF profiles, the GST_JPEG2000_PARSE_PROFILE_IMF_XXXX profile value must be combined with the target main level
+ * (3-0 LSBs, with value between 0 and 11), and target sub level (7-4 LSBs, with value between 0 and 9).
+ * Example:
+ * capabilities  GST_JPEG2000_PARSE_PROFILE_IMF_2K | 0x0040 | 0x0005 (in this case, main level equals 5 and sub level equals 4)
+ *
+ *
+ * Broadcast main level (15444-1 AMD4,AMD8)
+ *
+ * Note: Mbit/s == 10^6 bits/s;  Msamples/s == 10^6 samples/s
+ *
+ * Level 0: no max rate
+ * Level 1:    200 Mbits/s, 65  Msamples/s
+ * Level 2:    200 Mbits/s, 130 Msamples/s
+ * Level 3:    200 Mbits/s, 195 Msamples/s
+ * Level 4:    400 Mbits/s, 260 Msamples/s
+ * Level 5:    800Mbits/s,  520 Msamples/s
+ * Level >= 6: 2^(Level-6) * 1600 Mbits/s, 2^(Level-6) * 1200 Msamples/s
+ *
+ * Broadcast tiling
+ *
+ * Either single-tile or multi-tile. Multi-tile only permits
+ * 1 or 4 tiles per frame, where multiple tiles have identical
+ * sizes, and are configured in either 2x2 or 1x4 layout.
+ *
+ * */
+
+#define GST_JPEG2000_PARSE_PROFILE_NONE        0x0000 /** no profile -  defined in 15444-1 */
+#define GST_JPEG2000_PARSE_PROFILE_0           0x0001 /** Profile 0 - defined in  15444-1,Table A.45 */
+#define GST_JPEG2000_PARSE_PROFILE_1           0x0002 /** Profile 1 - defined in 15444-1,Table A.45 */
+#define GST_JPEG2000_PARSE_PROFILE_CINEMA_2K   0x0003 /** 2K Cinema profile - defined in 15444-1 AMD1 */
+#define GST_JPEG2000_PARSE_PROFILE_CINEMA_4K   0x0004 /** 4K Cinema profile - defined in 15444-1 AMD1 */
+#define GST_JPEG2000_PARSE_PROFILE_CINEMA_S2K  0x0005 /** Scalable 2K Cinema profile - defined in 15444-1 AMD2 */
+#define GST_JPEG2000_PARSE_PROFILE_CINEMA_S4K  0x0006 /** Scalable 4K Cinema profile - defined in 15444-1 AMD2 */
+#define GST_JPEG2000_PARSE_PROFILE_CINEMA_LTS  0x0007/** Long Term Storage Cinema profile - defined in 15444-1 AMD2 */
+#define GST_JPEG2000_PARSE_PROFILE_BC_SINGLE   0x0100 /** Single Tile Broadcast profile - defined in 15444-1 AMD3 */
+#define GST_JPEG2000_PARSE_PROFILE_BC_MULTI    0x0200 /** Multi Tile Broadcast profile - defined in 15444-1 AMD3 */
+#define GST_JPEG2000_PARSE_PROFILE_BC_MULTI_R  0x0300 /** Multi Tile Reversible Broadcast profile - defined in 15444-1 AMD3 */
+#define GST_JPEG2000_PARSE_PROFILE_BC_MASK             0x0F0F /** Mask for broadcast profile, including main level */
+#define GST_JPEG2000_PARSE_PROFILE_IMF_2K      0x0400 /** 2K Single Tile Lossy IMF profile - defined in 15444-1 AMD 8 */
+#define GST_JPEG2000_PARSE_PROFILE_IMF_4K      0x0401 /** 4K Single Tile Lossy IMF profile - defined in 15444-1 AMD 8 */
+#define GST_JPEG2000_PARSE_PROFILE_IMF_8K      0x0402 /** 8K Single Tile Lossy IMF profile - defined in 15444-1 AMD 8 */
+#define GST_JPEG2000_PARSE_PROFILE_IMF_2K_R    0x0403 /** 2K Single/Multi Tile Reversible IMF profile - defined in 15444-1 AMD 8 */
+#define GST_JPEG2000_PARSE_PROFILE_IMF_4K_R    0x0800 /** 4K Single/Multi Tile Reversible IMF profile - defined in 15444-1 AMD 8 */
+#define GST_JPEG2000_PARSE_PROFILE_IMF_8K_R    0x0801 /** 8K Single/Multi Tile Reversible IMF profile - defined in 15444-1 AMD 8 */
+#define GST_JPEG2000_PARSE_PROFILE_MASK           0xBFFF  /** Mask for profile bits */
+#define GST_JPEG2000_PARSE_PROFILE_PART2               0x8000 /** At least 1 extension defined in 15444-2 (Part-2) */
+
+#define GST_JPEG2000_PARSE_MAX_SUPPORTED_COMPONENTS  4
 
 typedef enum
 {