gst/quicktime/: Cut detour in sample description extension construction.
authorMark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
Fri, 14 Nov 2008 20:17:10 +0000 (20:17 +0000)
committerTim-Philipp Müller <tim.muller@collabora.co.uk>
Tue, 12 Apr 2011 19:32:10 +0000 (20:32 +0100)
Original commit message from CVS:
* gst/quicktime/atoms.c: (build_esds_extension),
(build_mov_aac_extension), (build_jp2h_extension),
(build_codec_data_extension):
* gst/quicktime/atoms.h:
* gst/quicktime/fourcc.h:
* gst/quicktime/gstqtmux.c: (gst_qt_mux_audio_sink_set_caps),
(gst_qt_mux_video_sink_set_caps):
* gst/quicktime/gstqtmuxmap.c: (gst_qt_mux_map_format_to_header):
Cut detour in sample description extension construction.
Also actually implement ISO JPEG2000 mj2 format.

gst/quicktime/atoms.c
gst/quicktime/atoms.h
gst/quicktime/fourcc.h
gst/quicktime/gstqtmux.c
gst/quicktime/gstqtmuxmap.c

index 3b0d83f..636f21c 100644 (file)
@@ -2802,12 +2802,15 @@ atom_trak_set_video_type (AtomTRAK * trak, AtomsContext * context,
 
 /* some sample description construction helpers */
 
-static AtomInfo *
-build_esds_atom (guint32 track_id, guint8 object_type, guint8 stream_type,
+AtomInfo *
+build_esds_extension (AtomTRAK * trak, guint8 object_type, guint8 stream_type,
     const GstBuffer * codec_data)
 {
+  guint32 track_id;
   AtomESDS *esds;
 
+  track_id = trak->tkhd.track_ID;
+
   esds = atom_esds_new ();
   esds->es.id = track_id & 0xFFFF;
   esds->es.dec_conf_desc.object_type = object_type;
@@ -2829,14 +2832,17 @@ build_esds_atom (guint32 track_id, guint8 object_type, guint8 stream_type,
       atom_esds_free);
 }
 
-static AtomInfo *
-build_mov_aac_extension (guint32 track_id, const GstBuffer * codec_data)
+AtomInfo *
+build_mov_aac_extension (AtomTRAK * trak, const GstBuffer * codec_data)
 {
+  guint32 track_id;
   AtomWAVE *wave;
   AtomFRMA *frma;
   Atom *ext_atom;
   GstBuffer *buf;
 
+  track_id = trak->tkhd.track_ID;
+
   /* Add WAVE atom to the MP4A sample table entry */
   wave = atom_wave_new ();
 
@@ -2848,7 +2854,7 @@ build_mov_aac_extension (guint32 track_id, const GstBuffer * codec_data)
 
   /* Add ESDS atom to WAVE */
   wave->extension_atoms = g_list_prepend (wave->extension_atoms,
-      build_esds_atom (track_id, ESDS_OBJECT_TYPE_MPEG4_P3,
+      build_esds_extension (trak, ESDS_OBJECT_TYPE_MPEG4_P3,
           ESDS_STREAM_TYPE_AUDIO, codec_data));
 
   /* Add MP4A atom to the WAVE:
@@ -2874,60 +2880,69 @@ build_mov_aac_extension (guint32 track_id, const GstBuffer * codec_data)
       atom_wave_free);
 }
 
-/* if applicable, construct Sample Table Entry extension atoms for a trak,
- * typically wrapping codec data;
- * for the given flavor of the format, fourcc type of the sample entry,
- * and in case of MP4 covered streams, the ESDS type */
 AtomInfo *
-build_sample_entry_extension (AtomTRAK * trak, AtomsTreeFlavor flavor,
-    guint32 fourcc, guint esds_type, const GstBuffer * codec_data)
+build_jp2h_extension (AtomTRAK * trak, gint width, gint height, guint32 fourcc)
 {
-  AtomInfo *result = NULL;
-  guint32 ext_fourcc = 0;
-  guint32 track_id;
-
-  g_return_val_if_fail (trak != NULL, NULL);
-  track_id = trak->tkhd.track_ID;
-
-  /* extension varies depending on format */
-  if (flavor == ATOMS_TREE_FLAVOR_ISOM) {
-    guint8 stream_type = 0;
-
-    if (fourcc == FOURCC_mp4a)
-      stream_type = ESDS_STREAM_TYPE_AUDIO;
-    else if (fourcc == FOURCC_mp4v)
-      stream_type = ESDS_STREAM_TYPE_VISUAL;
-    if (stream_type)
-      result = build_esds_atom (track_id, esds_type, stream_type, codec_data);
-  } else {
-    switch (fourcc) {
-      case FOURCC_mp4a:
-        if (esds_type != ESDS_OBJECT_TYPE_MPEG1_P3) {
-          result = build_mov_aac_extension (track_id, codec_data);
-        }
-        break;
-      case FOURCC_mp4v:
-      {
-        guint8 stream_type = ESDS_STREAM_TYPE_VISUAL;
-
-        result = build_esds_atom (track_id, esds_type, stream_type, codec_data);
-        break;
-      }
-    }
-  }
+  AtomData *atom_data;
+  GstBuffer *buf;
+  guint8 *data;
+  guint8 cenum;
+
+  if (fourcc == GST_MAKE_FOURCC ('s', 'R', 'G', 'B')) {
+    cenum = 0x10;
+  } else if (fourcc == GST_MAKE_FOURCC ('s', 'Y', 'U', 'V')) {
+    cenum = 0x12;
+  } else
+    return FALSE;
+
+  buf = gst_buffer_new_and_alloc (22 + 12);
+  data = GST_BUFFER_DATA (buf);
+
+  /* ihdr = image header box */
+  GST_WRITE_UINT32_BE (data, 22);
+  GST_WRITE_UINT32_LE (data + 4, GST_MAKE_FOURCC ('i', 'h', 'd', 'r'));
+  GST_WRITE_UINT32_BE (data + 8, height);
+  GST_WRITE_UINT32_BE (data + 12, width);
+  /* FIXME perhaps parse from stream,
+   * though exactly 3 in any respectable colourspace */
+  GST_WRITE_UINT16_BE (data + 16, 3);
+  /* 8 bits per component, unsigned */
+  GST_WRITE_UINT8 (data + 18, 0x7);
+  /* compression type; reserved */
+  GST_WRITE_UINT8 (data + 19, 0x7);
+  /* colour space (un)known */
+  GST_WRITE_UINT8 (data + 20, 0x0);
+  /* intellectual property right (box present) */
+  GST_WRITE_UINT8 (data + 21, 0x0);
+
+  /* colour specification box */
+  data += 22;
+  GST_WRITE_UINT32_BE (data, 12);
+  GST_WRITE_UINT32_LE (data + 4, GST_MAKE_FOURCC ('c', 'o', 'l', 'r'));
+  /* specification method: enumerated */
+  GST_WRITE_UINT8 (data + 8, 0x1);
+  /* precedence; reserved */
+  GST_WRITE_UINT8 (data + 9, 0x0);
+  /* approximation; reserved */
+  GST_WRITE_UINT8 (data + 10, 0x0);
+  /* enumerated colourspace */
+  GST_WRITE_UINT8 (data + 11, cenum);
+
+  atom_data = atom_data_new_from_gst_buffer (FOURCC_jp2h, buf);
+  gst_buffer_unref (buf);
 
-  /* stable extension across format (or only relevant for particular format) */
-  switch (fourcc) {
-    case FOURCC_avc1:
-      ext_fourcc = FOURCC_avcC;
-      break;
-  }
+  return build_atom_info_wrapper ((Atom *) atom_data, atom_data_copy_data,
+      atom_data_free);
+}
 
-  /* simply wrap codec data in some atom */
-  if (ext_fourcc && codec_data) {
-    AtomData *data;
+AtomInfo *
+build_codec_data_extension (guint32 fourcc, const GstBuffer * codec_data)
+{
+  AtomData *data;
+  AtomInfo *result = NULL;
 
-    data = atom_data_new_from_gst_buffer (ext_fourcc, codec_data);
+  if (codec_data) {
+    data = atom_data_new_from_gst_buffer (fourcc, codec_data);
     result = build_atom_info_wrapper ((Atom *) data, atom_data_copy_data,
         atom_data_free);
   }
index f469abc..22451e6 100644 (file)
@@ -595,10 +595,6 @@ typedef struct
   GstBuffer *codec_data;
 } AudioSampleEntry;
 
-AtomInfo* build_sample_entry_extension (AtomTRAK * trak, AtomsTreeFlavor flavor,
-                                        guint32 fourcc, guint esds_type,
-                                        const GstBuffer * codec_data);
-
 void atom_trak_set_audio_type (AtomTRAK * trak, AtomsContext * context,
                                AudioSampleEntry * entry, guint32 scale,
                                AtomInfo * ext, gint sample_size);
@@ -606,6 +602,13 @@ void atom_trak_set_video_type (AtomTRAK * trak, AtomsContext * context,
                                VisualSampleEntry * entry, guint32 rate,
                                AtomInfo * ext);
 
+AtomInfo *   build_codec_data_extension  (guint32 fourcc, const GstBuffer * codec_data);
+AtomInfo *   build_mov_aac_extension     (AtomTRAK * trak, const GstBuffer * codec_data);
+AtomInfo *   build_esds_extension        (AtomTRAK * trak, guint8 object_type,
+                                          guint8 stream_type, const GstBuffer * codec_data);
+AtomInfo *   build_jp2h_extension        (AtomTRAK * trak, gint width, gint height,
+                                          guint32 fourcc);
+
 
 /*
  * Meta tags functions
index 905ca23..2dd2e87 100644 (file)
@@ -142,6 +142,8 @@ G_BEGIN_DECLS
 #define FOURCC_ctts     GST_MAKE_FOURCC('c','t','t','s')
 #define FOURCC_drac     GST_MAKE_FOURCC('d','r','a','c')
 #define FOURCC_jpeg     GST_MAKE_FOURCC('j','p','e','g')
+#define FOURCC_mjp2     GST_MAKE_FOURCC('m','j','p','2')
+#define FOURCC_jp2h     GST_MAKE_FOURCC('j','p','2','h')
 
 /* Xiph fourcc */
 #define FOURCC_XiTh     GST_MAKE_FOURCC('X','i','T','h')
index 7eaf730..ab59b48 100644 (file)
@@ -1150,7 +1150,6 @@ gst_qt_mux_audio_sink_set_caps (GstPad * pad, GstCaps * caps)
   AudioSampleEntry entry = { 0, };
   AtomInfo *ext_atom = NULL;
   gint constant_size = 0;
-  guint esds_type = 0;
 
   /* find stream data */
   qtpad = (GstQTPad *) gst_pad_get_element_private (pad);
@@ -1208,7 +1207,9 @@ gst_qt_mux_audio_sink_set_caps (GstPad * pad, GstCaps * caps)
               entry.fourcc = FOURCC__mp3;
             else {
               entry.fourcc = FOURCC_mp4a;
-              esds_type = ESDS_OBJECT_TYPE_MPEG1_P3;
+              ext_atom =
+                  build_esds_extension (qtpad->trak, ESDS_OBJECT_TYPE_MPEG1_P3,
+                  ESDS_STREAM_TYPE_AUDIO, codec_data);
             }
             entry.samples_per_packet = 1152;
             entry.bytes_per_sample = 2;
@@ -1218,7 +1219,6 @@ gst_qt_mux_audio_sink_set_caps (GstPad * pad, GstCaps * caps)
       case 4:
         /* AAC */
         entry.fourcc = FOURCC_mp4a;
-        esds_type = ESDS_OBJECT_TYPE_MPEG4_P3;
         if (!codec_data || GST_BUFFER_SIZE (codec_data) < 2)
           GST_WARNING_OBJECT (qtmux, "no (valid) codec_data for AAC audio");
         else {
@@ -1230,6 +1230,12 @@ gst_qt_mux_audio_sink_set_caps (GstPad * pad, GstCaps * caps)
             GST_WARNING_OBJECT (qtmux,
                 "non-LC AAC may not run well on (Apple) QuickTime/iTunes");
         }
+        if (format == GST_QT_MUX_FORMAT_QT)
+          ext_atom = build_mov_aac_extension (qtpad->trak, codec_data);
+        else
+          ext_atom =
+              build_esds_extension (qtpad->trak, ESDS_OBJECT_TYPE_MPEG4_P3,
+              ESDS_STREAM_TYPE_AUDIO, codec_data);
         break;
       default:
         break;
@@ -1306,9 +1312,6 @@ gst_qt_mux_audio_sink_set_caps (GstPad * pad, GstCaps * caps)
   /* ok, set the pad info accordingly */
   qtpad->fourcc = entry.fourcc;
   qtpad->sample_size = constant_size;
-  /* collect optional extensions */
-  ext_atom = build_sample_entry_extension (qtpad->trak, qtmux->context->flavor,
-      entry.fourcc, esds_type, codec_data);
   atom_trak_set_audio_type (qtpad->trak, qtmux->context, &entry,
       entry.sample_rate, ext_atom, constant_size);
 
@@ -1362,7 +1365,6 @@ gst_qt_mux_video_sink_set_caps (GstPad * pad, GstCaps * caps)
   VisualSampleEntry entry = { 0, };
   GstQTMuxFormat format;
   AtomInfo *ext_atom = NULL;
-  guint esds_type = 0;
   gboolean sync = FALSE;
 
   /* find stream data */
@@ -1382,12 +1384,16 @@ gst_qt_mux_video_sink_set_caps (GstPad * pad, GstCaps * caps)
 
   /* required parts */
   if (!gst_structure_get_int (structure, "width", &width) ||
-      !gst_structure_get_int (structure, "height", &height) ||
-      !gst_structure_get_fraction (structure, "framerate", &framerate_num,
-          &framerate_den))
+      !gst_structure_get_int (structure, "height", &height))
     goto refuse_caps;
 
   /* optional */
+  depth = -1;
+  /* works as a default timebase */
+  framerate_num = 10000;
+  framerate_den = 1;
+  gst_structure_get_fraction (structure, "framerate", &framerate_num,
+      &framerate_den);
   gst_structure_get_int (structure, "depth", &depth);
   value = gst_structure_get_value (structure, "codec_data");
   if (value != NULL)
@@ -1450,7 +1456,9 @@ gst_qt_mux_video_sink_set_caps (GstPad * pad, GstCaps * caps)
     }
     if (version) {
       entry.fourcc = FOURCC_mp4v;
-      esds_type = ESDS_OBJECT_TYPE_MPEG4_P2;
+      ext_atom =
+          build_esds_extension (qtpad->trak, ESDS_OBJECT_TYPE_MPEG4_P2,
+          ESDS_STREAM_TYPE_VISUAL, codec_data);
       if (!codec_data)
         GST_WARNING_OBJECT (qtmux, "no codec_data for MPEG4 video; "
             "output might not play in Apple QuickTime (try global-headers?)");
@@ -1460,6 +1468,7 @@ gst_qt_mux_video_sink_set_caps (GstPad * pad, GstCaps * caps)
     qtpad->is_out_of_order = TRUE;
     if (!codec_data)
       GST_WARNING_OBJECT (qtmux, "no codec_data in h264 caps");
+    ext_atom = build_codec_data_extension (FOURCC_avcC, codec_data);
   } else if (strcmp (mimetype, "video/x-dv") == 0) {
     gint version = 0;
     gboolean pal = TRUE;
@@ -1491,6 +1500,17 @@ gst_qt_mux_video_sink_set_caps (GstPad * pad, GstCaps * caps)
   } else if (strcmp (mimetype, "image/jpeg") == 0) {
     entry.fourcc = FOURCC_jpeg;
     sync = FALSE;
+  } else if (strcmp (mimetype, "image/x-j2c") == 0) {
+    guint32 fourcc;
+
+    entry.fourcc = FOURCC_mjp2;
+    sync = FALSE;
+    if (!gst_structure_get_fourcc (structure, "fourcc", &fourcc) ||
+        !(ext_atom =
+            build_jp2h_extension (qtpad->trak, width, height, fourcc))) {
+      GST_DEBUG_OBJECT (qtmux, "missing or invalid fourcc in jp2 caps");
+      goto refuse_caps;
+    }
   } else if (strcmp (mimetype, "video/x-qt-part") == 0) {
     guint32 fourcc;
 
@@ -1505,9 +1525,6 @@ gst_qt_mux_video_sink_set_caps (GstPad * pad, GstCaps * caps)
   /* ok, set the pad info accordingly */
   qtpad->fourcc = entry.fourcc;
   qtpad->sync = sync;
-  /* collect optional extensions */
-  ext_atom = build_sample_entry_extension (qtpad->trak, qtmux->context->flavor,
-      entry.fourcc, esds_type, codec_data);
   atom_trak_set_video_type (qtpad->trak, qtmux->context, &entry, rate,
       ext_atom);
 
index ca62cc0..58eb881 100644 (file)
@@ -193,7 +193,7 @@ gst_qt_mux_map_format_to_header (GstQTMuxFormat format, GstBuffer ** _prefix,
   static guint8 mjp2_prefix[] =
       { 0, 0, 0, 12, 'j', 'P', ' ', ' ', 0x0D, 0x0A, 0x87, 0x0A };
   guint32 *comp = NULL;
-  guint32 major = 0, version;
+  guint32 major = 0, version = 0;
   GstBuffer *prefix = NULL;
   GList *result = NULL;
 
@@ -202,7 +202,6 @@ gst_qt_mux_map_format_to_header (GstQTMuxFormat format, GstBuffer ** _prefix,
   g_return_if_fail (_version != NULL);
   g_return_if_fail (_compatible != NULL);
 
-  version = 1;
   switch (format) {
     case GST_QT_MUX_FORMAT_QT:
       major = FOURCC_qt__;
@@ -220,6 +219,7 @@ gst_qt_mux_map_format_to_header (GstQTMuxFormat format, GstBuffer ** _prefix,
     case GST_QT_MUX_FORMAT_MJ2:
       major = FOURCC_mjp2;
       comp = mjp2_brands;
+      version = 0;
       prefix = gst_buffer_new_and_alloc (sizeof (mjp2_prefix));
       memcpy (GST_BUFFER_DATA (prefix), mjp2_prefix, GST_BUFFER_SIZE (prefix));
       break;