Commit 3f72fadc authored by Mark Nauwelaerts's avatar Mark Nauwelaerts Committed by Tim-Philipp Müller

gst/quicktime/: Cut detour in sample description extension construction.

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.
parent 2196cf6b
...@@ -2802,12 +2802,15 @@ atom_trak_set_video_type (AtomTRAK * trak, AtomsContext * context, ...@@ -2802,12 +2802,15 @@ atom_trak_set_video_type (AtomTRAK * trak, AtomsContext * context,
/* some sample description construction helpers */ /* some sample description construction helpers */
static AtomInfo * AtomInfo *
build_esds_atom (guint32 track_id, guint8 object_type, guint8 stream_type, build_esds_extension (AtomTRAK * trak, guint8 object_type, guint8 stream_type,
const GstBuffer * codec_data) const GstBuffer * codec_data)
{ {
guint32 track_id;
AtomESDS *esds; AtomESDS *esds;
track_id = trak->tkhd.track_ID;
esds = atom_esds_new (); esds = atom_esds_new ();
esds->es.id = track_id & 0xFFFF; esds->es.id = track_id & 0xFFFF;
esds->es.dec_conf_desc.object_type = object_type; 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, ...@@ -2829,14 +2832,17 @@ build_esds_atom (guint32 track_id, guint8 object_type, guint8 stream_type,
atom_esds_free); atom_esds_free);
} }
static AtomInfo * AtomInfo *
build_mov_aac_extension (guint32 track_id, const GstBuffer * codec_data) build_mov_aac_extension (AtomTRAK * trak, const GstBuffer * codec_data)
{ {
guint32 track_id;
AtomWAVE *wave; AtomWAVE *wave;
AtomFRMA *frma; AtomFRMA *frma;
Atom *ext_atom; Atom *ext_atom;
GstBuffer *buf; GstBuffer *buf;
track_id = trak->tkhd.track_ID;
/* Add WAVE atom to the MP4A sample table entry */ /* Add WAVE atom to the MP4A sample table entry */
wave = atom_wave_new (); wave = atom_wave_new ();
...@@ -2848,7 +2854,7 @@ build_mov_aac_extension (guint32 track_id, const GstBuffer * codec_data) ...@@ -2848,7 +2854,7 @@ build_mov_aac_extension (guint32 track_id, const GstBuffer * codec_data)
/* Add ESDS atom to WAVE */ /* Add ESDS atom to WAVE */
wave->extension_atoms = g_list_prepend (wave->extension_atoms, 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)); ESDS_STREAM_TYPE_AUDIO, codec_data));
/* Add MP4A atom to the WAVE: /* Add MP4A atom to the WAVE:
...@@ -2874,60 +2880,69 @@ build_mov_aac_extension (guint32 track_id, const GstBuffer * codec_data) ...@@ -2874,60 +2880,69 @@ build_mov_aac_extension (guint32 track_id, const GstBuffer * codec_data)
atom_wave_free); 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 * AtomInfo *
build_sample_entry_extension (AtomTRAK * trak, AtomsTreeFlavor flavor, build_jp2h_extension (AtomTRAK * trak, gint width, gint height, guint32 fourcc)
guint32 fourcc, guint esds_type, const GstBuffer * codec_data)
{ {
AtomInfo *result = NULL; AtomData *atom_data;
guint32 ext_fourcc = 0; GstBuffer *buf;
guint32 track_id; guint8 *data;
guint8 cenum;
g_return_val_if_fail (trak != NULL, NULL);
track_id = trak->tkhd.track_ID; if (fourcc == GST_MAKE_FOURCC ('s', 'R', 'G', 'B')) {
cenum = 0x10;
/* extension varies depending on format */ } else if (fourcc == GST_MAKE_FOURCC ('s', 'Y', 'U', 'V')) {
if (flavor == ATOMS_TREE_FLAVOR_ISOM) { cenum = 0x12;
guint8 stream_type = 0; } else
return FALSE;
if (fourcc == FOURCC_mp4a)
stream_type = ESDS_STREAM_TYPE_AUDIO; buf = gst_buffer_new_and_alloc (22 + 12);
else if (fourcc == FOURCC_mp4v) data = GST_BUFFER_DATA (buf);
stream_type = ESDS_STREAM_TYPE_VISUAL;
if (stream_type) /* ihdr = image header box */
result = build_esds_atom (track_id, esds_type, stream_type, codec_data); GST_WRITE_UINT32_BE (data, 22);
} else { GST_WRITE_UINT32_LE (data + 4, GST_MAKE_FOURCC ('i', 'h', 'd', 'r'));
switch (fourcc) { GST_WRITE_UINT32_BE (data + 8, height);
case FOURCC_mp4a: GST_WRITE_UINT32_BE (data + 12, width);
if (esds_type != ESDS_OBJECT_TYPE_MPEG1_P3) { /* FIXME perhaps parse from stream,
result = build_mov_aac_extension (track_id, codec_data); * though exactly 3 in any respectable colourspace */
} GST_WRITE_UINT16_BE (data + 16, 3);
break; /* 8 bits per component, unsigned */
case FOURCC_mp4v: GST_WRITE_UINT8 (data + 18, 0x7);
{ /* compression type; reserved */
guint8 stream_type = ESDS_STREAM_TYPE_VISUAL; GST_WRITE_UINT8 (data + 19, 0x7);
/* colour space (un)known */
result = build_esds_atom (track_id, esds_type, stream_type, codec_data); GST_WRITE_UINT8 (data + 20, 0x0);
break; /* 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) */ return build_atom_info_wrapper ((Atom *) atom_data, atom_data_copy_data,
switch (fourcc) { atom_data_free);
case FOURCC_avc1: }
ext_fourcc = FOURCC_avcC;
break;
}
/* simply wrap codec data in some atom */ AtomInfo *
if (ext_fourcc && codec_data) { build_codec_data_extension (guint32 fourcc, const GstBuffer * codec_data)
AtomData *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, result = build_atom_info_wrapper ((Atom *) data, atom_data_copy_data,
atom_data_free); atom_data_free);
} }
......
...@@ -595,10 +595,6 @@ typedef struct ...@@ -595,10 +595,6 @@ typedef struct
GstBuffer *codec_data; GstBuffer *codec_data;
} AudioSampleEntry; } 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, void atom_trak_set_audio_type (AtomTRAK * trak, AtomsContext * context,
AudioSampleEntry * entry, guint32 scale, AudioSampleEntry * entry, guint32 scale,
AtomInfo * ext, gint sample_size); AtomInfo * ext, gint sample_size);
...@@ -606,6 +602,13 @@ void atom_trak_set_video_type (AtomTRAK * trak, AtomsContext * context, ...@@ -606,6 +602,13 @@ void atom_trak_set_video_type (AtomTRAK * trak, AtomsContext * context,
VisualSampleEntry * entry, guint32 rate, VisualSampleEntry * entry, guint32 rate,
AtomInfo * ext); 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 * Meta tags functions
......
...@@ -142,6 +142,8 @@ G_BEGIN_DECLS ...@@ -142,6 +142,8 @@ G_BEGIN_DECLS
#define FOURCC_ctts GST_MAKE_FOURCC('c','t','t','s') #define FOURCC_ctts GST_MAKE_FOURCC('c','t','t','s')
#define FOURCC_drac GST_MAKE_FOURCC('d','r','a','c') #define FOURCC_drac GST_MAKE_FOURCC('d','r','a','c')
#define FOURCC_jpeg GST_MAKE_FOURCC('j','p','e','g') #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 */ /* Xiph fourcc */
#define FOURCC_XiTh GST_MAKE_FOURCC('X','i','T','h') #define FOURCC_XiTh GST_MAKE_FOURCC('X','i','T','h')
......
...@@ -1150,7 +1150,6 @@ gst_qt_mux_audio_sink_set_caps (GstPad * pad, GstCaps * caps) ...@@ -1150,7 +1150,6 @@ gst_qt_mux_audio_sink_set_caps (GstPad * pad, GstCaps * caps)
AudioSampleEntry entry = { 0, }; AudioSampleEntry entry = { 0, };
AtomInfo *ext_atom = NULL; AtomInfo *ext_atom = NULL;
gint constant_size = 0; gint constant_size = 0;
guint esds_type = 0;
/* find stream data */ /* find stream data */
qtpad = (GstQTPad *) gst_pad_get_element_private (pad); qtpad = (GstQTPad *) gst_pad_get_element_private (pad);
...@@ -1208,7 +1207,9 @@ gst_qt_mux_audio_sink_set_caps (GstPad * pad, GstCaps * caps) ...@@ -1208,7 +1207,9 @@ gst_qt_mux_audio_sink_set_caps (GstPad * pad, GstCaps * caps)
entry.fourcc = FOURCC__mp3; entry.fourcc = FOURCC__mp3;
else { else {
entry.fourcc = FOURCC_mp4a; 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.samples_per_packet = 1152;
entry.bytes_per_sample = 2; entry.bytes_per_sample = 2;
...@@ -1218,7 +1219,6 @@ gst_qt_mux_audio_sink_set_caps (GstPad * pad, GstCaps * caps) ...@@ -1218,7 +1219,6 @@ gst_qt_mux_audio_sink_set_caps (GstPad * pad, GstCaps * caps)
case 4: case 4:
/* AAC */ /* AAC */
entry.fourcc = FOURCC_mp4a; entry.fourcc = FOURCC_mp4a;
esds_type = ESDS_OBJECT_TYPE_MPEG4_P3;
if (!codec_data || GST_BUFFER_SIZE (codec_data) < 2) if (!codec_data || GST_BUFFER_SIZE (codec_data) < 2)
GST_WARNING_OBJECT (qtmux, "no (valid) codec_data for AAC audio"); GST_WARNING_OBJECT (qtmux, "no (valid) codec_data for AAC audio");
else { else {
...@@ -1230,6 +1230,12 @@ gst_qt_mux_audio_sink_set_caps (GstPad * pad, GstCaps * caps) ...@@ -1230,6 +1230,12 @@ gst_qt_mux_audio_sink_set_caps (GstPad * pad, GstCaps * caps)
GST_WARNING_OBJECT (qtmux, GST_WARNING_OBJECT (qtmux,
"non-LC AAC may not run well on (Apple) QuickTime/iTunes"); "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; break;
default: default:
break; break;
...@@ -1306,9 +1312,6 @@ gst_qt_mux_audio_sink_set_caps (GstPad * pad, GstCaps * caps) ...@@ -1306,9 +1312,6 @@ gst_qt_mux_audio_sink_set_caps (GstPad * pad, GstCaps * caps)
/* ok, set the pad info accordingly */ /* ok, set the pad info accordingly */
qtpad->fourcc = entry.fourcc; qtpad->fourcc = entry.fourcc;
qtpad->sample_size = constant_size; 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, atom_trak_set_audio_type (qtpad->trak, qtmux->context, &entry,
entry.sample_rate, ext_atom, constant_size); entry.sample_rate, ext_atom, constant_size);
...@@ -1362,7 +1365,6 @@ gst_qt_mux_video_sink_set_caps (GstPad * pad, GstCaps * caps) ...@@ -1362,7 +1365,6 @@ gst_qt_mux_video_sink_set_caps (GstPad * pad, GstCaps * caps)
VisualSampleEntry entry = { 0, }; VisualSampleEntry entry = { 0, };
GstQTMuxFormat format; GstQTMuxFormat format;
AtomInfo *ext_atom = NULL; AtomInfo *ext_atom = NULL;
guint esds_type = 0;
gboolean sync = FALSE; gboolean sync = FALSE;
/* find stream data */ /* find stream data */
...@@ -1382,12 +1384,16 @@ gst_qt_mux_video_sink_set_caps (GstPad * pad, GstCaps * caps) ...@@ -1382,12 +1384,16 @@ gst_qt_mux_video_sink_set_caps (GstPad * pad, GstCaps * caps)
/* required parts */ /* required parts */
if (!gst_structure_get_int (structure, "width", &width) || if (!gst_structure_get_int (structure, "width", &width) ||
!gst_structure_get_int (structure, "height", &height) || !gst_structure_get_int (structure, "height", &height))
!gst_structure_get_fraction (structure, "framerate", &framerate_num,
&framerate_den))
goto refuse_caps; goto refuse_caps;
/* optional */ /* 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); gst_structure_get_int (structure, "depth", &depth);
value = gst_structure_get_value (structure, "codec_data"); value = gst_structure_get_value (structure, "codec_data");
if (value != NULL) if (value != NULL)
...@@ -1450,7 +1456,9 @@ gst_qt_mux_video_sink_set_caps (GstPad * pad, GstCaps * caps) ...@@ -1450,7 +1456,9 @@ gst_qt_mux_video_sink_set_caps (GstPad * pad, GstCaps * caps)
} }
if (version) { if (version) {
entry.fourcc = FOURCC_mp4v; 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) if (!codec_data)
GST_WARNING_OBJECT (qtmux, "no codec_data for MPEG4 video; " GST_WARNING_OBJECT (qtmux, "no codec_data for MPEG4 video; "
"output might not play in Apple QuickTime (try global-headers?)"); "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) ...@@ -1460,6 +1468,7 @@ gst_qt_mux_video_sink_set_caps (GstPad * pad, GstCaps * caps)
qtpad->is_out_of_order = TRUE; qtpad->is_out_of_order = TRUE;
if (!codec_data) if (!codec_data)
GST_WARNING_OBJECT (qtmux, "no codec_data in h264 caps"); 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) { } else if (strcmp (mimetype, "video/x-dv") == 0) {
gint version = 0; gint version = 0;
gboolean pal = TRUE; gboolean pal = TRUE;
...@@ -1491,6 +1500,17 @@ gst_qt_mux_video_sink_set_caps (GstPad * pad, GstCaps * caps) ...@@ -1491,6 +1500,17 @@ gst_qt_mux_video_sink_set_caps (GstPad * pad, GstCaps * caps)
} else if (strcmp (mimetype, "image/jpeg") == 0) { } else if (strcmp (mimetype, "image/jpeg") == 0) {
entry.fourcc = FOURCC_jpeg; entry.fourcc = FOURCC_jpeg;
sync = FALSE; 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) { } else if (strcmp (mimetype, "video/x-qt-part") == 0) {
guint32 fourcc; guint32 fourcc;
...@@ -1505,9 +1525,6 @@ gst_qt_mux_video_sink_set_caps (GstPad * pad, GstCaps * caps) ...@@ -1505,9 +1525,6 @@ gst_qt_mux_video_sink_set_caps (GstPad * pad, GstCaps * caps)
/* ok, set the pad info accordingly */ /* ok, set the pad info accordingly */
qtpad->fourcc = entry.fourcc; qtpad->fourcc = entry.fourcc;
qtpad->sync = sync; 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, atom_trak_set_video_type (qtpad->trak, qtmux->context, &entry, rate,
ext_atom); ext_atom);
......
...@@ -193,7 +193,7 @@ gst_qt_mux_map_format_to_header (GstQTMuxFormat format, GstBuffer ** _prefix, ...@@ -193,7 +193,7 @@ gst_qt_mux_map_format_to_header (GstQTMuxFormat format, GstBuffer ** _prefix,
static guint8 mjp2_prefix[] = static guint8 mjp2_prefix[] =
{ 0, 0, 0, 12, 'j', 'P', ' ', ' ', 0x0D, 0x0A, 0x87, 0x0A }; { 0, 0, 0, 12, 'j', 'P', ' ', ' ', 0x0D, 0x0A, 0x87, 0x0A };
guint32 *comp = NULL; guint32 *comp = NULL;
guint32 major = 0, version; guint32 major = 0, version = 0;
GstBuffer *prefix = NULL; GstBuffer *prefix = NULL;
GList *result = NULL; GList *result = NULL;
...@@ -202,7 +202,6 @@ gst_qt_mux_map_format_to_header (GstQTMuxFormat format, GstBuffer ** _prefix, ...@@ -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 (_version != NULL);
g_return_if_fail (_compatible != NULL); g_return_if_fail (_compatible != NULL);
version = 1;
switch (format) { switch (format) {
case GST_QT_MUX_FORMAT_QT: case GST_QT_MUX_FORMAT_QT:
major = FOURCC_qt__; major = FOURCC_qt__;
...@@ -220,6 +219,7 @@ gst_qt_mux_map_format_to_header (GstQTMuxFormat format, GstBuffer ** _prefix, ...@@ -220,6 +219,7 @@ gst_qt_mux_map_format_to_header (GstQTMuxFormat format, GstBuffer ** _prefix,
case GST_QT_MUX_FORMAT_MJ2: case GST_QT_MUX_FORMAT_MJ2:
major = FOURCC_mjp2; major = FOURCC_mjp2;
comp = mjp2_brands; comp = mjp2_brands;
version = 0;
prefix = gst_buffer_new_and_alloc (sizeof (mjp2_prefix)); prefix = gst_buffer_new_and_alloc (sizeof (mjp2_prefix));
memcpy (GST_BUFFER_DATA (prefix), mjp2_prefix, GST_BUFFER_SIZE (prefix)); memcpy (GST_BUFFER_DATA (prefix), mjp2_prefix, GST_BUFFER_SIZE (prefix));
break; break;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment