Commit 6f8a2978 authored by Erlend Eriksen's avatar Erlend Eriksen

mp4mux: add meta track (Fixes #554)

parent 64a991d7
Pipeline #16401 passed with stages
in 12 minutes and 59 seconds
......@@ -693,6 +693,7 @@ atom_stsd_remove_entries (AtomSTSD * stsd)
sample_entry_tmcd_free ((SampleTableEntryTMCD *) se);
break;
case CLOSEDCAPTION:
case META:
default:
/* best possible cleanup */
atom_sample_entry_free (se);
......@@ -2481,6 +2482,11 @@ atom_stsd_copy_data (AtomSTSD * stsd, guint8 ** buffer, guint64 * size,
walker->data, buffer, size, offset)) {
return 0;
}
} else if (se->kind == META) {
if (!sample_entry_generic_copy_data ((SampleTableEntry *)
walker->data, buffer, size, offset)) {
return 0;
}
} else {
if (!atom_hint_sample_entry_copy_data (
(AtomHintSampleEntry *) walker->data, buffer, size, offset)) {
......@@ -3713,6 +3719,12 @@ atom_minf_set_subtitle (AtomMINF * minf)
atom_minf_clear_handlers (minf);
}
static void
atom_minf_set_meta (AtomMINF * minf)
{
atom_minf_clear_handlers (minf);
}
static void
atom_hdlr_set_type (AtomHDLR * hdlr, AtomsContext * context, guint32 comp_type,
guint32 hdlr_type)
......@@ -3757,6 +3769,15 @@ atom_mdia_set_hdlr_type_subtitle (AtomMDIA * mdia, AtomsContext * context)
atom_hdlr_set_name (&mdia->hdlr, "SubtitleHandler");
}
static void
atom_mdia_set_hdlr_type_meta (AtomMDIA * mdia, AtomsContext * context,
const gchar * hdlr_name)
{
atom_hdlr_set_type (&mdia->hdlr, context, FOURCC_mhlr, FOURCC_meta);
atom_hdlr_set_name (&mdia->hdlr, hdlr_name);
}
static void
atom_mdia_set_audio (AtomMDIA * mdia, AtomsContext * context)
{
......@@ -3778,6 +3799,14 @@ atom_mdia_set_subtitle (AtomMDIA * mdia, AtomsContext * context)
atom_minf_set_subtitle (&mdia->minf);
}
static void
atom_mdia_set_meta (AtomMDIA * mdia, AtomsContext * context,
const gchar * hdlr_name)
{
atom_mdia_set_hdlr_type_meta (mdia, context, hdlr_name);
atom_minf_set_meta (&mdia->minf);
}
static void
atom_tkhd_set_audio (AtomTKHD * tkhd)
{
......@@ -3807,6 +3836,12 @@ atom_tkhd_set_subtitle (AtomTKHD * tkhd, AtomsContext * context, guint32 width,
tkhd->height = height;
}
static void
atom_tkhd_set_meta (AtomTKHD * tkhd)
{
tkhd->volume = 0;
tkhd->width = tkhd->height = 0;
}
static void
atom_edts_add_entry (AtomEDTS * edts, gint index, EditListEntry * entry)
......@@ -3995,6 +4030,14 @@ atom_trak_set_subtitle (AtomTRAK * trak, AtomsContext * context)
atom_mdia_set_subtitle (&trak->mdia, context);
}
static void
atom_trak_set_meta (AtomTRAK * trak, AtomsContext * context,
const gchar * hdlr_name)
{
atom_tkhd_set_meta (&trak->tkhd);
atom_mdia_set_meta (&trak->mdia, context, hdlr_name);
}
static void
atom_trak_set_audio_commons (AtomTRAK * trak, AtomsContext * context,
guint32 rate)
......@@ -4023,6 +4066,14 @@ atom_trak_set_subtitle_commons (AtomTRAK * trak, AtomsContext * context)
trak->tkhd.layer = -1; /* above video (layer 0) */
}
static void
atom_trak_set_meta_commons (AtomTRAK * trak, AtomsContext * context,
guint32 rate, const gchar * hdlr_name)
{
atom_trak_set_meta (trak, context, hdlr_name);
trak->mdia.mdhd.time_info.timescale = rate;
}
void
sample_table_entry_add_ext_atom (SampleTableEntry * ste, AtomInfo * ext)
{
......@@ -4139,6 +4190,32 @@ atom_trak_set_caption_type (AtomTRAK * trak, AtomsContext * context,
return ste;
}
SampleTableEntry *
atom_trak_set_meta_type (AtomTRAK * trak, AtomsContext * context,
guint32 trak_timescale, guint32 meta_type, const gchar * hdlr_name)
{
SampleTableEntry *ste;
AtomSMHD *smhd = trak->mdia.minf.smhd;
AtomSTSD *stsd = &trak->mdia.minf.stbl.stsd;
atom_trak_set_meta_commons (trak, context, trak_timescale, hdlr_name);
ste = g_new0 (SampleTableEntry, 1);
atom_sample_entry_init (ste, meta_type);
ste->kind = META;
ste->data_reference_index = 1;
stsd->entries = g_list_prepend (stsd->entries, ste);
stsd->n_entries++;
smhd = atom_smhd_new ();
trak->mdia.minf.smhd = smhd;
trak->is_video = FALSE;
trak->is_h264 = FALSE;
return ste;
}
static AtomInfo *
build_pasp_extension (gint par_width, gint par_height)
{
......
......@@ -387,7 +387,8 @@ typedef enum _SampleEntryKind
VIDEO,
SUBTITLE,
TIMECODE,
CLOSEDCAPTION
CLOSEDCAPTION,
META
} SampleEntryKind;
typedef struct _SampleTableEntry
......@@ -1059,6 +1060,9 @@ atom_trak_set_timecode_type (AtomTRAK * trak, AtomsContext * context, guint trak
SampleTableEntry * atom_trak_set_caption_type (AtomTRAK *trak, AtomsContext *context,
guint32 trak_timescale, guint32 caption_type);
SampleTableEntry * atom_trak_set_meta_type (AtomTRAK *trak, AtomsContext *context,
guint32 trak_timescale, guint32 meta_type, const gchar * hdlr_name);
void atom_trak_update_bitrates (AtomTRAK * trak, guint32 avg_bitrate,
guint32 max_bitrate);
......
......@@ -463,7 +463,7 @@ gst_qt_mux_base_init (gpointer g_class)
GstQTMuxClass *klass = (GstQTMuxClass *) g_class;
GstQTMuxClassParams *params;
GstPadTemplate *videosinktempl, *audiosinktempl, *subtitlesinktempl,
*captionsinktempl;
*captionsinktempl, *metasinktempl;
GstPadTemplate *srctempl;
gchar *longname, *description;
......@@ -515,6 +515,13 @@ gst_qt_mux_base_init (gpointer g_class)
gst_element_class_add_pad_template (element_class, captionsinktempl);
}
if (params->meta_sink_caps) {
metasinktempl = gst_pad_template_new_with_gtype ("meta_%u",
GST_PAD_SINK, GST_PAD_REQUEST, params->meta_sink_caps,
GST_TYPE_QT_MUX_PAD);
gst_element_class_add_pad_template (element_class, metasinktempl);
}
klass->format = params->prop->format;
}
......@@ -6147,6 +6154,61 @@ refuse_caps:
}
}
static gboolean
gst_qt_mux_meta_sink_set_caps (GstQTPad * qtpad, GstCaps * caps)
{
GstPad *pad = qtpad->collect.pad;
GstQTMux *qtmux = GST_QT_MUX_CAST (gst_pad_get_parent (pad));
GstStructure *structure;
const gchar *fourcc_str = NULL;
guint32 fourcc_entry;
const gchar *hdlr_name = NULL;
guint32 timescale;
if (qtpad->fourcc)
return gst_qt_mux_can_renegotiate (qtmux, pad, caps);
GST_DEBUG_OBJECT (qtmux, "%s:%s, caps=%" GST_PTR_FORMAT,
GST_DEBUG_PAD_NAME (pad), caps);
qtpad->is_out_of_order = FALSE;
qtpad->sync = FALSE;
qtpad->prepare_buf_func = NULL;
structure = gst_caps_get_structure (caps, 0);
if ((fourcc_str = gst_structure_get_string (structure, "fourcc"))
&& strlen (fourcc_str) == 4)
fourcc_entry = GST_STR_FOURCC (fourcc_str);
else
goto refuse_caps;
if (!(hdlr_name = gst_structure_get_string (structure, "hdlr-name")))
goto refuse_caps;
timescale = gst_qt_mux_pad_get_timescale (GST_QT_MUX_PAD_CAST (pad));
if (!timescale && qtmux->trak_timescale)
timescale = qtmux->trak_timescale;
else if (!timescale)
timescale = 30000;
qtpad->fourcc = fourcc_entry;
qtpad->trak_ste =
(SampleTableEntry *) atom_trak_set_meta_type (qtpad->trak,
qtmux->context, timescale, fourcc_entry, hdlr_name);
gst_object_unref (qtmux);
return TRUE;
/* ERRORS */
refuse_caps:
{
GST_WARNING_OBJECT (qtmux, "pad %s refused caps %" GST_PTR_FORMAT,
GST_PAD_NAME (pad), caps);
gst_object_unref (qtmux);
return FALSE;
}
}
static gboolean
gst_qt_mux_sink_event (GstCollectPads * pads, GstCollectData * data,
GstEvent * event, gpointer user_data)
......@@ -6272,6 +6334,7 @@ gst_qt_mux_release_pad (GstElement * element, GstPad * pad)
mux->video_pads = 0;
mux->audio_pads = 0;
mux->subtitle_pads = 0;
mux->meta_pads = 0;
}
}
......@@ -6324,6 +6387,14 @@ gst_qt_mux_request_new_pad (GstElement * element,
name = g_strdup_printf ("caption_%u", qtmux->caption_pads++);
}
lock = FALSE;
} else if (templ == gst_element_class_get_pad_template (klass, "meta_%u")) {
setcaps_func = gst_qt_mux_meta_sink_set_caps;
if (req_name != NULL && sscanf (req_name, "meta_%u", &pad_id) == 1) {
name = g_strdup (req_name);
} else {
name = g_strdup_printf ("meta_%u", qtmux->meta_pads++);
}
lock = FALSE;
} else
goto wrong_template;
......@@ -6624,7 +6695,7 @@ gst_qt_mux_register (GstPlugin * plugin)
while (TRUE) {
GstQTMuxFormatProp *prop;
GstCaps *subtitle_caps, *caption_caps;
GstCaps *subtitle_caps, *caption_caps, *meta_caps;
prop = &gst_qt_mux_format_list[i];
format = prop->format;
......@@ -6649,6 +6720,12 @@ gst_qt_mux_register (GstPlugin * plugin)
} else {
gst_caps_unref (caption_caps);
}
meta_caps = gst_static_caps_get (&prop->meta_sink_caps);
if (!gst_caps_is_equal (meta_caps, GST_CAPS_NONE)) {
params->meta_sink_caps = meta_caps;
} else {
gst_caps_unref (meta_caps);
}
/* create the type now */
type = g_type_register_static (GST_TYPE_ELEMENT, prop->type_name, &typeinfo,
......
......@@ -292,7 +292,7 @@ struct _GstQTMux
GstClockTime start_gap_threshold;
/* for request pad naming */
guint video_pads, audio_pads, subtitle_pads, caption_pads;
guint video_pads, audio_pads, subtitle_pads, caption_pads, meta_pads;
};
struct _GstQTMuxClass
......@@ -311,6 +311,7 @@ typedef struct _GstQTMuxClassParams
GstCaps *audio_sink_caps;
GstCaps *subtitle_sink_caps;
GstCaps *caption_sink_caps;
GstCaps *meta_sink_caps;
} GstQTMuxClassParams;
#define GST_QT_MUX_PARAMS_QDATA g_quark_from_static_string("qt-mux-params")
......
......@@ -166,6 +166,9 @@
"text/x-raw, " \
"format=(string)utf8"
#define DATA_META \
"meta/x-raw"
#define CEA608_CAPS \
"closedcaption/x-cea-608, format=(string)s334-1a"
#define CEA708_CAPS \
......@@ -216,7 +219,8 @@ GstQTMuxFormatProp gst_qt_mux_format_list[] = {
"audio/x-mulaw, " COMMON_AUDIO_CAPS (2, MAX) "; "
AMR_CAPS " ; " ALAC_CAPS " ; " OPUS_CAPS),
GST_STATIC_CAPS (TEXT_UTF8),
GST_STATIC_CAPS (CEA608_CAPS "; " CEA708_CAPS)}
GST_STATIC_CAPS (CEA608_CAPS "; " CEA708_CAPS),
GST_STATIC_CAPS (DATA_META)}
,
/* ISO 14496-14: mp42 as ISO base media extension
* (supersedes original ISO 144996-1 mp41) */
......@@ -233,7 +237,7 @@ GstQTMuxFormatProp gst_qt_mux_format_list[] = {
GST_STATIC_CAPS (MP123_CAPS "; "
AAC_CAPS " ; " AC3_CAPS " ; " ALAC_CAPS " ; " OPUS_CAPS),
GST_STATIC_CAPS (TEXT_UTF8),
GST_STATIC_CAPS_NONE}
GST_STATIC_CAPS_NONE, GST_STATIC_CAPS (DATA_META)}
,
/* Microsoft Smooth Streaming fmp4/isml */
/* TODO add WMV/WMA support */
......@@ -247,7 +251,7 @@ GstQTMuxFormatProp gst_qt_mux_format_list[] = {
GST_STATIC_CAPS (MPEG4V_CAPS "; " H264_CAPS),
GST_STATIC_CAPS (MP3_CAPS "; " AAC_CAPS),
GST_STATIC_CAPS_NONE,
GST_STATIC_CAPS_NONE}
GST_STATIC_CAPS_NONE, GST_STATIC_CAPS_NONE}
,
/* 3GPP Technical Specification 26.244 V7.3.0
* (extended in 3GPP2 File Formats for Multimedia Services) */
......@@ -261,7 +265,7 @@ GstQTMuxFormatProp gst_qt_mux_format_list[] = {
GST_STATIC_CAPS (H263_CAPS "; " MPEG4V_CAPS "; " H264_CAPS),
GST_STATIC_CAPS (AMR_CAPS "; " MP3_CAPS "; " AAC_CAPS "; " AC3_CAPS),
GST_STATIC_CAPS (TEXT_UTF8),
GST_STATIC_CAPS_NONE}
GST_STATIC_CAPS_NONE, GST_STATIC_CAPS_NONE}
,
/* ISO 15444-3: Motion-JPEG-2000 (also ISO base media extension) */
{
......@@ -275,7 +279,7 @@ GstQTMuxFormatProp gst_qt_mux_format_list[] = {
"image/x-jpc, " COMMON_VIDEO_CAPS),
GST_STATIC_CAPS (PCM_CAPS),
GST_STATIC_CAPS_NONE,
GST_STATIC_CAPS_NONE}
GST_STATIC_CAPS_NONE, GST_STATIC_CAPS_NONE}
,
{
GST_QT_MUX_FORMAT_NONE,
......
......@@ -56,7 +56,8 @@ typedef enum _GstQTMuxFormat
GST_QT_MUX_FORMAT_MP4,
GST_QT_MUX_FORMAT_3GP,
GST_QT_MUX_FORMAT_MJ2,
GST_QT_MUX_FORMAT_ISML
GST_QT_MUX_FORMAT_ISML,
GST_QT_MUX_FORMAT_META
} GstQTMuxFormat;
typedef struct _GstQTMuxFormatProp
......@@ -71,6 +72,7 @@ typedef struct _GstQTMuxFormatProp
GstStaticCaps audio_sink_caps;
GstStaticCaps subtitle_sink_caps;
GstStaticCaps caption_sink_caps;
GstStaticCaps meta_sink_caps;
} GstQTMuxFormatProp;
extern GstQTMuxFormatProp gst_qt_mux_format_list[];
......
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