qtmux: add support for text/x-raw subtitles

Adds it to mp4mux, qtmux and gppmux.

Buffers need to be prefixed with 2 bytes for the text length before
being muxed.

https://bugzilla.gnome.org/show_bug.cgi?id=581295
This commit is contained in:
Thiago Santos 2014-02-06 12:15:22 -03:00
parent d644cda79b
commit 99e966e2e1
2 changed files with 94 additions and 6 deletions

View file

@ -550,6 +550,39 @@ gst_qt_mux_prepare_jpc_buffer (GstQTPad * qtpad, GstBuffer * buf,
return newbuf; return newbuf;
} }
static GstBuffer *
gst_qt_mux_prepare_tx3g_buffer (GstQTPad * qtpad, GstBuffer * buf,
GstQTMux * qtmux)
{
GstBuffer *newbuf;
GstMapInfo frommap;
GstMapInfo tomap;
gsize size;
GST_LOG_OBJECT (qtmux, "Preparing tx3g buffer %" GST_PTR_FORMAT, buf);
if (buf == NULL)
return NULL;
size = gst_buffer_get_size (buf);
newbuf = gst_buffer_new_and_alloc (size + 2);
gst_buffer_map (buf, &frommap, GST_MAP_READ);
gst_buffer_map (newbuf, &tomap, GST_MAP_WRITE);
GST_WRITE_UINT16_BE (tomap.data, size);
memcpy (tomap.data + 2, frommap.data, size);
gst_buffer_unmap (newbuf, &tomap);
gst_buffer_unmap (buf, &frommap);
gst_buffer_copy_into (newbuf, buf, GST_BUFFER_COPY_METADATA, 0, size);
gst_buffer_unref (buf);
return newbuf;
}
static void static void
gst_qt_mux_add_mp4_tag (GstQTMux * qtmux, const GstTagList * list, gst_qt_mux_add_mp4_tag (GstQTMux * qtmux, const GstTagList * list,
const char *tag, const char *tag2, guint32 fourcc) const char *tag, const char *tag2, guint32 fourcc)
@ -1806,6 +1839,10 @@ gst_qt_mux_stop_file (GstQTMux * qtmux)
guint32 timescale; guint32 timescale;
GstClockTime first_ts = GST_CLOCK_TIME_NONE; GstClockTime first_ts = GST_CLOCK_TIME_NONE;
/* for setting some subtitles fields */
guint max_width = 0;
guint max_height = 0;
GST_DEBUG_OBJECT (qtmux, "Updating remaining values and sending last data"); GST_DEBUG_OBJECT (qtmux, "Updating remaining values and sending last data");
/* pushing last buffers for each pad */ /* pushing last buffers for each pad */
@ -1845,6 +1882,12 @@ gst_qt_mux_stop_file (GstQTMux * qtmux)
first_ts = qtpad->last_dts; first_ts = qtpad->last_dts;
} }
/* subtitles need to know the video width/height,
* it is stored shifted 16 bits to the left according to the
* spec */
max_width = MAX (max_width, (qtpad->trak->tkhd.width >> 16));
max_height = MAX (max_height, (qtpad->trak->tkhd.height >> 16));
/* update average bitrate of streams if needed */ /* update average bitrate of streams if needed */
{ {
guint32 avgbitrate = 0; guint32 avgbitrate = 0;
@ -1860,6 +1903,23 @@ gst_qt_mux_stop_file (GstQTMux * qtmux)
} }
} }
/* need to update values on subtitle traks now that we know the
* max width and height */
for (walk = qtmux->collect->data; walk; walk = g_slist_next (walk)) {
GstCollectData *cdata = (GstCollectData *) walk->data;
GstQTPad *qtpad = (GstQTPad *) cdata;
if (!qtpad->fourcc) {
GST_DEBUG_OBJECT (qtmux, "Pad %s has never had buffers",
GST_PAD_NAME (qtpad->collect.pad));
continue;
}
if (qtpad->fourcc == FOURCC_tx3g) {
atom_trak_tx3g_update_dimension (qtpad->trak, max_width, max_height);
}
}
if (qtmux->fragment_sequence) { if (qtmux->fragment_sequence) {
GstSegment segment; GstSegment segment;
@ -3142,6 +3202,8 @@ gst_qt_mux_subtitle_sink_set_caps (GstQTPad * qtpad, GstCaps * caps)
{ {
GstPad *pad = qtpad->collect.pad; GstPad *pad = qtpad->collect.pad;
GstQTMux *qtmux = GST_QT_MUX_CAST (gst_pad_get_parent (pad)); GstQTMux *qtmux = GST_QT_MUX_CAST (gst_pad_get_parent (pad));
GstStructure *structure;
SubtitleSampleEntry entry = { 0, };
qtpad->prepare_buf_func = NULL; qtpad->prepare_buf_func = NULL;
@ -3168,16 +3230,38 @@ gst_qt_mux_subtitle_sink_set_caps (GstQTPad * qtpad, GstCaps * caps)
GST_DEBUG_PAD_NAME (pad), caps); GST_DEBUG_PAD_NAME (pad), caps);
/* subtitles default */ /* subtitles default */
subtitle_sample_entry_init (&entry);
qtpad->is_out_of_order = FALSE; qtpad->is_out_of_order = FALSE;
qtpad->sync = FALSE; qtpad->sync = FALSE;
qtpad->prepare_buf_func = NULL;
/* TODO fill me */ structure = gst_caps_get_structure (caps, 0);
if (gst_structure_has_name (structure, "text/x-raw")) {
const gchar *format = gst_structure_get_string (structure, "format");
if (format && strcmp (format, "utf8") == 0) {
entry.fourcc = FOURCC_tx3g;
qtpad->prepare_buf_func = gst_qt_mux_prepare_tx3g_buffer;
}
}
if (!entry.fourcc)
goto refuse_caps;
qtpad->fourcc = entry.fourcc;
atom_trak_set_subtitle_type (qtpad->trak, qtmux->context, &entry);
gst_object_unref (qtmux); gst_object_unref (qtmux);
/* not implemented */ return TRUE;
return FALSE;
/* ERRORS */ /* 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;
}
refuse_renegotiation: refuse_renegotiation:
{ {
GST_WARNING_OBJECT (qtmux, GST_WARNING_OBJECT (qtmux,

View file

@ -133,6 +133,10 @@
"audio/x-alac, " \ "audio/x-alac, " \
COMMON_AUDIO_CAPS(2, MAX) COMMON_AUDIO_CAPS(2, MAX)
#define TEXT_UTF8 \
"text/x-raw, " \
"format=(string)utf8"
/* FIXME 0.11 - take a look at bugs #580005 and #340375 */ /* FIXME 0.11 - take a look at bugs #580005 and #340375 */
GstQTMuxFormatProp gst_qt_mux_format_list[] = { GstQTMuxFormatProp gst_qt_mux_format_list[] = {
/* original QuickTime format; see Apple site (e.g. qtff.pdf) */ /* original QuickTime format; see Apple site (e.g. qtff.pdf) */
@ -167,7 +171,7 @@ GstQTMuxFormatProp gst_qt_mux_format_list[] = {
"audio/x-alaw, " COMMON_AUDIO_CAPS (2, MAX) "; " "audio/x-alaw, " COMMON_AUDIO_CAPS (2, MAX) "; "
"audio/x-mulaw, " COMMON_AUDIO_CAPS (2, MAX) "; " "audio/x-mulaw, " COMMON_AUDIO_CAPS (2, MAX) "; "
AMR_CAPS " ; " ALAC_CAPS), AMR_CAPS " ; " ALAC_CAPS),
GST_STATIC_CAPS_NONE} GST_STATIC_CAPS (TEXT_UTF8)}
, ,
/* ISO 14496-14: mp42 as ISO base media extension /* ISO 14496-14: mp42 as ISO base media extension
* (supersedes original ISO 144996-1 mp41) */ * (supersedes original ISO 144996-1 mp41) */
@ -181,7 +185,7 @@ GstQTMuxFormatProp gst_qt_mux_format_list[] = {
GST_STATIC_CAPS (MPEG4V_CAPS "; " H264_CAPS ";" GST_STATIC_CAPS (MPEG4V_CAPS "; " H264_CAPS ";"
"video/x-mp4-part," COMMON_VIDEO_CAPS), "video/x-mp4-part," COMMON_VIDEO_CAPS),
GST_STATIC_CAPS (MP3_CAPS "; " AAC_CAPS " ; " ALAC_CAPS), GST_STATIC_CAPS (MP3_CAPS "; " AAC_CAPS " ; " ALAC_CAPS),
GST_STATIC_CAPS_NONE} GST_STATIC_CAPS (TEXT_UTF8)}
, ,
/* Microsoft Smooth Streaming fmp4/isml */ /* Microsoft Smooth Streaming fmp4/isml */
/* TODO add WMV/WMA support */ /* TODO add WMV/WMA support */
@ -207,7 +211,7 @@ GstQTMuxFormatProp gst_qt_mux_format_list[] = {
GST_STATIC_CAPS ("video/quicktime, variant = (string) 3gpp"), GST_STATIC_CAPS ("video/quicktime, variant = (string) 3gpp"),
GST_STATIC_CAPS (H263_CAPS "; " MPEG4V_CAPS "; " H264_CAPS), GST_STATIC_CAPS (H263_CAPS "; " MPEG4V_CAPS "; " H264_CAPS),
GST_STATIC_CAPS (AMR_CAPS "; " MP3_CAPS "; " AAC_CAPS), GST_STATIC_CAPS (AMR_CAPS "; " MP3_CAPS "; " AAC_CAPS),
GST_STATIC_CAPS_NONE} GST_STATIC_CAPS (TEXT_UTF8)}
, ,
/* ISO 15444-3: Motion-JPEG-2000 (also ISO base media extension) */ /* ISO 15444-3: Motion-JPEG-2000 (also ISO base media extension) */
{ {