qtmux: support for SVQ3

Adds support for muxing SVQ3 content. Usually this format
has decoder info that must be passed in the 'seqh' field
in the caps. It is also good to add the gama atom to make
quicktime not crash.

Fixes #587922
This commit is contained in:
Thiago Santos 2009-10-29 08:36:02 -03:00 committed by Tim-Philipp Müller
parent d24d1e40ea
commit 496bd01a0f
5 changed files with 101 additions and 5 deletions

View file

@ -3055,7 +3055,7 @@ build_pasp_extension (AtomTRAK * trak, gint par_width, gint par_height)
void void
atom_trak_set_video_type (AtomTRAK * trak, AtomsContext * context, atom_trak_set_video_type (AtomTRAK * trak, AtomsContext * context,
VisualSampleEntry * entry, guint32 scale, AtomInfo * ext) VisualSampleEntry * entry, guint32 scale, GList * ext_atoms_list)
{ {
SampleTableEntryMP4V *ste; SampleTableEntryMP4V *ste;
gint dwidth, dheight; gint dwidth, dheight;
@ -3087,14 +3087,15 @@ atom_trak_set_video_type (AtomTRAK * trak, AtomsContext * context,
trak->is_video = TRUE; trak->is_video = TRUE;
trak->is_h264 = (entry->fourcc == FOURCC_avc1); trak->is_h264 = (entry->fourcc == FOURCC_avc1);
ste->version = entry->version;
ste->width = entry->width; ste->width = entry->width;
ste->height = entry->height; ste->height = entry->height;
ste->depth = entry->depth; ste->depth = entry->depth;
ste->color_table_id = entry->color_table_id; ste->color_table_id = entry->color_table_id;
ste->frame_count = entry->frame_count; ste->frame_count = entry->frame_count;
if (ext) if (ext_atoms_list)
ste->extension_atoms = g_list_prepend (ste->extension_atoms, ext); ste->extension_atoms = g_list_concat (ste->extension_atoms, ext_atoms_list);
/* QT spec has a pasp extension atom in stsd that can hold PAR */ /* QT spec has a pasp extension atom in stsd that can hold PAR */
if (par_n && (context->flavor == ATOMS_TREE_FLAVOR_MOV)) { if (par_n && (context->flavor == ATOMS_TREE_FLAVOR_MOV)) {
@ -3301,3 +3302,38 @@ build_h263_extension ()
gst_buffer_unref (buf); gst_buffer_unref (buf);
return res; return res;
} }
AtomInfo *
build_gama_atom (gdouble gamma)
{
AtomInfo *res;
guint32 gamma_fp;
GstBuffer *buf;
/* convert to uint32 from fixed point */
gamma_fp = (guint32) 65536 *gamma;
buf = gst_buffer_new_and_alloc (4);
GST_WRITE_UINT32_BE (GST_BUFFER_DATA (buf), gamma_fp);
res = build_codec_data_extension (FOURCC_gama, buf);
gst_buffer_unref (buf);
return res;
}
AtomInfo *
build_SMI_atom (const GstBuffer * seqh)
{
AtomInfo *res;
GstBuffer *buf;
/* the seqh plus its size and fourcc */
buf = gst_buffer_new_and_alloc (GST_BUFFER_SIZE (seqh) + 8);
GST_WRITE_UINT32_LE (GST_BUFFER_DATA (buf), FOURCC_SEQH);
GST_WRITE_UINT32_BE (GST_BUFFER_DATA (buf) + 4, GST_BUFFER_SIZE (seqh));
memcpy (GST_BUFFER_DATA (buf) + 8, GST_BUFFER_DATA (seqh),
GST_BUFFER_SIZE (seqh));
res = build_codec_data_extension (FOURCC_SMI_, buf);
gst_buffer_unref (buf);
return res;
}

View file

@ -628,6 +628,7 @@ void atom_moov_add_trak (AtomMOOV *moov, AtomTRAK *trak);
typedef struct typedef struct
{ {
guint16 version;
guint32 fourcc; guint32 fourcc;
guint width; guint width;
guint height; guint height;
@ -659,9 +660,10 @@ typedef struct
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);
void atom_trak_set_video_type (AtomTRAK * trak, AtomsContext * context, void atom_trak_set_video_type (AtomTRAK * trak, AtomsContext * context,
VisualSampleEntry * entry, guint32 rate, VisualSampleEntry * entry, guint32 rate,
AtomInfo * ext); GList * ext_atoms_list);
AtomInfo * build_codec_data_extension (guint32 fourcc, const GstBuffer * codec_data); AtomInfo * build_codec_data_extension (guint32 fourcc, const GstBuffer * codec_data);
AtomInfo * build_mov_aac_extension (AtomTRAK * trak, const GstBuffer * codec_data); AtomInfo * build_mov_aac_extension (AtomTRAK * trak, const GstBuffer * codec_data);
@ -671,6 +673,8 @@ AtomInfo * build_jp2h_extension (AtomTRAK * trak, gint width, gint heig
guint32 fourcc); guint32 fourcc);
AtomInfo * build_amr_extension (); AtomInfo * build_amr_extension ();
AtomInfo * build_h263_extension (); AtomInfo * build_h263_extension ();
AtomInfo * build_gama_atom (gdouble gamma);
AtomInfo * build_SMI_atom (const GstBuffer *seqh);
/* /*

View file

@ -170,6 +170,11 @@ G_BEGIN_DECLS
#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_mjp2 GST_MAKE_FOURCC('m','j','p','2')
#define FOURCC_jp2h GST_MAKE_FOURCC('j','p','2','h') #define FOURCC_jp2h GST_MAKE_FOURCC('j','p','2','h')
#define FOURCC_gama GST_MAKE_FOURCC('g','a','m','a')
/* SVQ3 fourcc */
#define FOURCC_SEQH GST_MAKE_FOURCC('S','E','Q','H')
#define FOURCC_SMI_ GST_MAKE_FOURCC('S','M','I',' ')
/* Xiph fourcc */ /* Xiph fourcc */
#define FOURCC_XiTh GST_MAKE_FOURCC('X','i','T','h') #define FOURCC_XiTh GST_MAKE_FOURCC('X','i','T','h')

View file

@ -1776,6 +1776,7 @@ 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;
GList *ext_atom_list = NULL;
gboolean sync = FALSE; gboolean sync = FALSE;
int par_num, par_den; int par_num, par_den;
@ -1859,11 +1860,14 @@ gst_qt_mux_video_sink_set_caps (GstPad * pad, GstCaps * caps)
break; break;
} }
} else if (strcmp (mimetype, "video/x-h263") == 0) { } else if (strcmp (mimetype, "video/x-h263") == 0) {
ext_atom = NULL;
if (format == GST_QT_MUX_FORMAT_QT) if (format == GST_QT_MUX_FORMAT_QT)
entry.fourcc = FOURCC_h263; entry.fourcc = FOURCC_h263;
else else
entry.fourcc = FOURCC_s263; entry.fourcc = FOURCC_s263;
ext_atom = build_h263_extension (); ext_atom = build_h263_extension ();
if (ext_atom != NULL)
ext_atom_list = g_list_prepend (ext_atom_list, ext_atom);
} else if (strcmp (mimetype, "video/x-divx") == 0 || } else if (strcmp (mimetype, "video/x-divx") == 0 ||
strcmp (mimetype, "video/mpeg") == 0) { strcmp (mimetype, "video/mpeg") == 0) {
gint version = 0; gint version = 0;
@ -1880,6 +1884,8 @@ gst_qt_mux_video_sink_set_caps (GstPad * pad, GstCaps * caps)
ext_atom = ext_atom =
build_esds_extension (qtpad->trak, ESDS_OBJECT_TYPE_MPEG4_P2, build_esds_extension (qtpad->trak, ESDS_OBJECT_TYPE_MPEG4_P2,
ESDS_STREAM_TYPE_VISUAL, codec_data); ESDS_STREAM_TYPE_VISUAL, codec_data);
if (ext_atom != NULL)
ext_atom_list = g_list_prepend (ext_atom_list, ext_atom);
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?)");
@ -1890,6 +1896,42 @@ gst_qt_mux_video_sink_set_caps (GstPad * pad, GstCaps * caps)
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); ext_atom = build_codec_data_extension (FOURCC_avcC, codec_data);
if (ext_atom != NULL)
ext_atom_list = g_list_prepend (ext_atom_list, ext_atom);
} else if (strcmp (mimetype, "video/x-svq") == 0) {
gint version = 0;
const GstBuffer *seqh = NULL;
const GValue *seqh_value;
gdouble gamma = 0;
gst_structure_get_int (structure, "svqversion", &version);
if (version == 3) {
entry.fourcc = FOURCC_SVQ3;
entry.version = 3;
entry.depth = 32;
qtpad->is_out_of_order = TRUE;
seqh_value = gst_structure_get_value (structure, "seqh");
if (seqh_value) {
seqh = gst_value_get_buffer (seqh_value);
ext_atom = build_SMI_atom (seqh);
if (ext_atom)
ext_atom_list = g_list_prepend (ext_atom_list, ext_atom);
}
/* we need to add the gamma anyway because quicktime might crash
* when it doesn't find it */
if (!gst_structure_get_double (structure, "applied-gamma", &gamma)) {
/* it seems that using 0 here makes it ignored */
gamma = 0.0;
}
ext_atom = build_gama_atom (gamma);
if (ext_atom)
ext_atom_list = g_list_prepend (ext_atom_list, ext_atom);
} else {
GST_WARNING_OBJECT (qtmux, "SVQ version %d not supported. Please file "
"a bug at http://bugzilla.gnome.org", version);
}
} 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;
@ -1924,6 +1966,7 @@ gst_qt_mux_video_sink_set_caps (GstPad * pad, GstCaps * caps)
} else if (strcmp (mimetype, "image/x-j2c") == 0) { } else if (strcmp (mimetype, "image/x-j2c") == 0) {
guint32 fourcc; guint32 fourcc;
ext_atom = NULL;
entry.fourcc = FOURCC_mjp2; entry.fourcc = FOURCC_mjp2;
sync = FALSE; sync = FALSE;
if (!gst_structure_get_fourcc (structure, "fourcc", &fourcc) || if (!gst_structure_get_fourcc (structure, "fourcc", &fourcc) ||
@ -1932,6 +1975,8 @@ gst_qt_mux_video_sink_set_caps (GstPad * pad, GstCaps * caps)
GST_DEBUG_OBJECT (qtmux, "missing or invalid fourcc in jp2 caps"); GST_DEBUG_OBJECT (qtmux, "missing or invalid fourcc in jp2 caps");
goto refuse_caps; goto refuse_caps;
} }
if (ext_atom)
ext_atom_list = g_list_prepend (ext_atom_list, ext_atom);
} else if (strcmp (mimetype, "video/x-qt-part") == 0) { } else if (strcmp (mimetype, "video/x-qt-part") == 0) {
guint32 fourcc; guint32 fourcc;
@ -1955,7 +2000,7 @@ gst_qt_mux_video_sink_set_caps (GstPad * pad, GstCaps * caps)
qtpad->fourcc = entry.fourcc; qtpad->fourcc = entry.fourcc;
qtpad->sync = sync; qtpad->sync = sync;
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_list);
gst_object_unref (qtmux); gst_object_unref (qtmux);
return TRUE; return TRUE;

View file

@ -73,6 +73,11 @@
"divxversion = (int) 5, "\ "divxversion = (int) 5, "\
COMMON_VIDEO_CAPS COMMON_VIDEO_CAPS
#define SVQ_CAPS \
"video/x-svq, " \
"svqversion = (int) 3, " \
COMMON_VIDEO_CAPS
#define COMMON_AUDIO_CAPS(c, r) \ #define COMMON_AUDIO_CAPS(c, r) \
"channels = (int) [ 1, " G_STRINGIFY (c) " ], " \ "channels = (int) [ 1, " G_STRINGIFY (c) " ], " \
"rate = (int) [ 1, " G_STRINGIFY (r) " ]" "rate = (int) [ 1, " G_STRINGIFY (r) " ]"
@ -141,6 +146,7 @@ GstQTMuxFormatProp gst_qt_mux_format_list[] = {
MPEG4V_CAPS "; " MPEG4V_CAPS "; "
H263_CAPS "; " H263_CAPS "; "
H264_CAPS "; " H264_CAPS "; "
SVQ_CAPS "; "
"video/x-dv, " "video/x-dv, "
"systemstream = (boolean) false, " "systemstream = (boolean) false, "
COMMON_VIDEO_CAPS "; " COMMON_VIDEO_CAPS "; "