From fd872d5f12daa80884b1202f7207a2f3eacb2764 Mon Sep 17 00:00:00 2001 From: Mark Nauwelaerts Date: Fri, 14 Nov 2008 20:17:10 +0000 Subject: gst/qtmux/: Cut detour in sample description extension construction. Original commit message from CVS: * gst/qtmux/atoms.c: (build_esds_extension), (build_mov_aac_extension), (build_jp2h_extension), (build_codec_data_extension): * gst/qtmux/atoms.h: * gst/qtmux/fourcc.h: * gst/qtmux/gstqtmux.c: (gst_qt_mux_audio_sink_set_caps), (gst_qt_mux_video_sink_set_caps): * gst/qtmux/gstqtmuxmap.c: (gst_qt_mux_map_format_to_header): Cut detour in sample description extension construction. Also actually implement ISO JPEG2000 mj2 format. --- ChangeLog | 13 +++++ gst/qtmux/atoms.c | 123 +++++++++++++++++++++++++++--------------------- gst/qtmux/atoms.h | 11 +++-- gst/qtmux/fourcc.h | 2 + gst/qtmux/gstqtmux.c | 45 ++++++++++++------ gst/qtmux/gstqtmuxmap.c | 4 +- 6 files changed, 124 insertions(+), 74 deletions(-) diff --git a/ChangeLog b/ChangeLog index aae89e82..783f52c4 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,16 @@ +2008-11-14 Mark Nauwelaerts + + * gst/qtmux/atoms.c: (build_esds_extension), + (build_mov_aac_extension), (build_jp2h_extension), + (build_codec_data_extension): + * gst/qtmux/atoms.h: + * gst/qtmux/fourcc.h: + * gst/qtmux/gstqtmux.c: (gst_qt_mux_audio_sink_set_caps), + (gst_qt_mux_video_sink_set_caps): + * gst/qtmux/gstqtmuxmap.c: (gst_qt_mux_map_format_to_header): + Cut detour in sample description extension construction. + Also actually implement ISO JPEG2000 mj2 format. + 2008-11-14 Mark Nauwelaerts * ext/x264/gstx264enc.c: (gst_x264_enc_set_src_caps): diff --git a/gst/qtmux/atoms.c b/gst/qtmux/atoms.c index 3b0d83fe..636f21c2 100644 --- a/gst/qtmux/atoms.c +++ b/gst/qtmux/atoms.c @@ -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); } diff --git a/gst/qtmux/atoms.h b/gst/qtmux/atoms.h index f469abc1..22451e61 100644 --- a/gst/qtmux/atoms.h +++ b/gst/qtmux/atoms.h @@ -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 diff --git a/gst/qtmux/fourcc.h b/gst/qtmux/fourcc.h index 905ca231..2dd2e879 100644 --- a/gst/qtmux/fourcc.h +++ b/gst/qtmux/fourcc.h @@ -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') diff --git a/gst/qtmux/gstqtmux.c b/gst/qtmux/gstqtmux.c index 7eaf730d..ab59b483 100644 --- a/gst/qtmux/gstqtmux.c +++ b/gst/qtmux/gstqtmux.c @@ -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); diff --git a/gst/qtmux/gstqtmuxmap.c b/gst/qtmux/gstqtmuxmap.c index ca62cc07..58eb8818 100644 --- a/gst/qtmux/gstqtmuxmap.c +++ b/gst/qtmux/gstqtmuxmap.c @@ -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; -- cgit v1.2.1