#include <stdio.h>
#include <string.h>
+#include <gst/audio/audio.h>
#include <gst/riff/riff-media.h>
#include <gst/tag/tag.h>
#include "matroska-mux.h"
#include "matroska-ids.h"
+#define GST_MATROSKA_MUX_CHAPLANG "und"
+
GST_DEBUG_CATEGORY_STATIC (matroskamux_debug);
#define GST_CAT_DEFAULT matroskamux_debug
*/
static GstStaticPadTemplate videosink_templ =
- GST_STATIC_PAD_TEMPLATE ("video_%d",
+ GST_STATIC_PAD_TEMPLATE ("video_%u",
GST_PAD_SINK,
GST_PAD_REQUEST,
GST_STATIC_CAPS ("video/mpeg, "
COMMON_VIDEO_CAPS "; "
"video/x-vp8, "
COMMON_VIDEO_CAPS "; "
- "video/x-raw-yuv, "
- "format = (fourcc) { YUY2, I420, YV12, UYVY, AYUV }, "
+ "video/x-raw, "
+ "format = (string) { YUY2, I420, YV12, UYVY, AYUV }, "
COMMON_VIDEO_CAPS "; "
"video/x-wmv, " "wmvversion = (int) [ 1, 3 ], " COMMON_VIDEO_CAPS)
);
* * require codec data, etc as needed
*/
static GstStaticPadTemplate audiosink_templ =
- GST_STATIC_PAD_TEMPLATE ("audio_%d",
+ GST_STATIC_PAD_TEMPLATE ("audio_%u",
GST_PAD_SINK,
GST_PAD_REQUEST,
GST_STATIC_CAPS ("audio/mpeg, "
COMMON_AUDIO_CAPS "; "
"audio/x-speex, "
COMMON_AUDIO_CAPS "; "
- "audio/x-raw-int, "
- "width = (int) 8, "
- "depth = (int) 8, "
- "signed = (boolean) false, "
- COMMON_AUDIO_CAPS ";"
- "audio/x-raw-int, "
- "width = (int) 16, "
- "depth = (int) 16, "
- "endianness = (int) { BIG_ENDIAN, LITTLE_ENDIAN }, "
- "signed = (boolean) true, "
- COMMON_AUDIO_CAPS ";"
- "audio/x-raw-int, "
- "width = (int) 24, "
- "depth = (int) 24, "
- "endianness = (int) { BIG_ENDIAN, LITTLE_ENDIAN }, "
- "signed = (boolean) true, "
- COMMON_AUDIO_CAPS ";"
- "audio/x-raw-int, "
- "width = (int) 32, "
- "depth = (int) 32, "
- "endianness = (int) { BIG_ENDIAN, LITTLE_ENDIAN }, "
- "signed = (boolean) true, "
- COMMON_AUDIO_CAPS ";"
- "audio/x-raw-float, "
- "width = (int) [ 32, 64 ], "
- "endianness = (int) LITTLE_ENDIAN, "
+ "audio/x-raw, "
+ "format = (string) { U8, S16BE, S16LE, S24BE, S24LE, S32BE, S32LE, F32LE, F64LE }, "
+ "layout = (string) interleaved, "
COMMON_AUDIO_CAPS ";"
"audio/x-tta, "
"width = (int) { 8, 16, 24 }, "
static GArray *used_uids;
G_LOCK_DEFINE_STATIC (used_uids);
-static void gst_matroska_mux_add_interfaces (GType type);
-
-GST_BOILERPLATE_FULL (GstMatroskaMux, gst_matroska_mux, GstElement,
- GST_TYPE_ELEMENT, gst_matroska_mux_add_interfaces);
+#define parent_class gst_matroska_mux_parent_class
+G_DEFINE_TYPE_WITH_CODE (GstMatroskaMux, gst_matroska_mux, GST_TYPE_ELEMENT,
+ G_IMPLEMENT_INTERFACE (GST_TYPE_TAG_SETTER, NULL)
+ G_IMPLEMENT_INTERFACE (GST_TYPE_TOC_SETTER, NULL)
+ );
/* Matroska muxer destructor */
static void gst_matroska_mux_finalize (GObject * object);
/* pad functions */
static gboolean gst_matroska_mux_handle_src_event (GstPad * pad,
- GstEvent * event);
+ GstObject * parent, GstEvent * event);
static GstPad *gst_matroska_mux_request_new_pad (GstElement * element,
- GstPadTemplate * templ, const gchar * name);
+ GstPadTemplate * templ, const gchar * name, const GstCaps * caps);
static void gst_matroska_mux_release_pad (GstElement * element, GstPad * pad);
/* gst internal change state handler */
gpointer data);
static void
-gst_matroska_mux_add_interfaces (GType type)
-{
- static const GInterfaceInfo tag_setter_info = { NULL, NULL, NULL };
-
- g_type_add_interface_static (type, GST_TYPE_TAG_SETTER, &tag_setter_info);
-}
-
-static void
-gst_matroska_mux_base_init (gpointer g_class)
-{
-}
-
-static void
gst_matroska_mux_class_init (GstMatroskaMuxClass * klass)
{
GObjectClass *gobject_class;
gobject_class = (GObjectClass *) klass;
gstelement_class = (GstElementClass *) klass;
- gst_element_class_add_static_pad_template (gstelement_class,
- &videosink_templ);
- gst_element_class_add_static_pad_template (gstelement_class,
- &audiosink_templ);
- gst_element_class_add_static_pad_template (gstelement_class,
- &subtitlesink_templ);
- gst_element_class_add_static_pad_template (gstelement_class, &src_templ);
- gst_element_class_set_details_simple (gstelement_class, "Matroska muxer",
+ gst_element_class_add_pad_template (gstelement_class,
+ gst_static_pad_template_get (&videosink_templ));
+ gst_element_class_add_pad_template (gstelement_class,
+ gst_static_pad_template_get (&audiosink_templ));
+ gst_element_class_add_pad_template (gstelement_class,
+ gst_static_pad_template_get (&subtitlesink_templ));
+ gst_element_class_add_pad_template (gstelement_class,
+ gst_static_pad_template_get (&src_templ));
+ gst_element_class_set_static_metadata (gstelement_class, "Matroska muxer",
"Codec/Muxer",
"Muxes video/audio/subtitle streams into a matroska stream",
"GStreamer maintainers <gstreamer-devel@lists.sourceforge.net>");
* Matroska muxer constructor.
*/
static void
-gst_matroska_mux_init (GstMatroskaMux * mux, GstMatroskaMuxClass * g_class)
+gst_matroska_mux_init (GstMatroskaMux * mux)
{
GstPadTemplate *templ;
templ =
- gst_element_class_get_pad_template (GST_ELEMENT_CLASS (g_class), "src");
+ gst_element_class_get_pad_template (GST_ELEMENT_GET_CLASS (mux), "src");
mux->srcpad = gst_pad_new_from_template (templ, "src");
gst_pad_set_event_function (mux->srcpad, gst_matroska_mux_handle_src_event);
* Release resources of a matroska collect pad.
*/
static void
-gst_matroska_pad_free (GstMatroskaPad * collect_pad)
+gst_matroska_pad_free (GstPad * collect_pad)
{
- gst_matroska_pad_reset (collect_pad, TRUE);
+ gst_matroska_pad_reset ((GstMatroskaPad *) collect_pad, TRUE);
}
/* reset tags */
gst_tag_setter_reset_tags (GST_TAG_SETTER (mux));
+
+ mux->tags_pos = 0;
+
+ /* reset chapters */
+ gst_toc_setter_reset_toc (GST_TOC_SETTER (mux));
+
+ mux->chapters_pos = 0;
}
/**
* Returns: #TRUE on success.
*/
static gboolean
-gst_matroska_mux_handle_src_event (GstPad * pad, GstEvent * event)
+gst_matroska_mux_handle_src_event (GstPad * pad, GstObject * parent,
+ GstEvent * event)
{
GstEventType type;
break;
}
- return gst_pad_event_default (pad, event);
+ return gst_pad_event_default (pad, parent, event);
}
gst_matroska_mux_handle_sink_event (GstCollectPads2 * pads,
GstCollectData2 * data, GstEvent * event, gpointer user_data)
{
- GstMatroskaTrackContext *context;
GstMatroskaPad *collect_pad;
+ GstMatroskaTrackContext *context;
GstMatroskaMux *mux;
GstPad *pad;
GstTagList *list;
+ gboolean ret = TRUE;
mux = GST_MATROSKA_MUX (user_data);
collect_pad = (GstMatroskaPad *) data;
g_assert (context);
switch (GST_EVENT_TYPE (event)) {
+ case GST_EVENT_CAPS:{
+ GstCaps *caps;
+
+ collect_pad = (GstMatroskaPad *) gst_pad_get_element_private (pad);
+ gst_event_parse_caps (event, &caps);
+
+ ret = collect_pad->capsfunc (pad, caps);
+ gst_event_unref (event);
+ event = NULL;
+ break;
+ }
case GST_EVENT_TAG:{
gchar *lang = NULL;
gst_event_unref (event);
/* handled this, don't want collectpads to forward it downstream */
event = NULL;
+ ret = TRUE;
break;
}
- case GST_EVENT_NEWSEGMENT:{
- GstFormat format;
+ case GST_EVENT_TOC:{
+ GstToc *toc;
- gst_event_parse_new_segment (event, NULL, NULL, &format, NULL, NULL,
- NULL);
- if (format != GST_FORMAT_TIME) {
- gst_event_unref (event);
- event = NULL;
+ if (mux->chapters_pos > 0)
+ break;
+
+ GST_DEBUG_OBJECT (mux, "received toc event");
+ gst_event_parse_toc (event, &toc, NULL);
+
+ if (toc != NULL) {
+ if (gst_toc_setter_get_toc (GST_TOC_SETTER (mux)) != NULL) {
+ gst_toc_setter_reset_toc (GST_TOC_SETTER (mux));
+ GST_INFO_OBJECT (pad, "Replacing TOC with a new one");
+ }
+
+ gst_toc_setter_set_toc (GST_TOC_SETTER (mux), toc);
+ gst_toc_free (toc);
}
+
+ gst_event_unref (event);
+ /* handled this, don't want collectpads to forward it downstream */
+ event = NULL;
break;
}
case GST_EVENT_CUSTOM_DOWNSTREAM:{
/* transform into private data for stream; text form */
gst_matroska_mux_build_vobsub_private (context, clut);
}
- break;
}
+ /* fall through */
default:
break;
}
- /* now GstCollectPads2 can take care of the rest, e.g. EOS */
- if (event)
- return FALSE;
- else
- return TRUE;
+ if (event != NULL)
+ return gst_collect_pads2_event_default (pads, data, event, FALSE);
+
+ return ret;
}
static void
GstStructure *structure;
const gchar *mimetype;
const GValue *value = NULL;
- const GstBuffer *codec_buf = NULL;
+ GstBuffer *codec_buf = NULL;
gint width, height, pixel_width, pixel_height;
gint fps_d, fps_n;
gboolean interlaced = FALSE;
/* extract codec_data, may turn out needed */
value = gst_structure_get_value (structure, "codec_data");
if (value)
- codec_buf = gst_value_get_buffer (value);
+ codec_buf = (GstBuffer *) gst_value_get_buffer (value);
/* find type */
- if (!strcmp (mimetype, "video/x-raw-yuv")) {
+ if (!strcmp (mimetype, "video/x-raw")) {
+ const gchar *fstr;
gst_matroska_mux_set_codec_id (context,
GST_MATROSKA_CODEC_ID_VIDEO_UNCOMPRESSED);
- gst_structure_get_fourcc (structure, "format", &videocontext->fourcc);
+ fstr = gst_structure_get_string (structure, "format");
+ if (fstr && strlen (fstr) == 4)
+ videocontext->fourcc = GST_STR_FOURCC (fstr);
+ } else if (!strcmp (mimetype, "image/jpeg")) {
+ gst_matroska_mux_set_codec_id (context, GST_MATROSKA_CODEC_ID_VIDEO_MJPEG);
} else if (!strcmp (mimetype, "video/x-xvid") /* MS/VfW compatibility cases */
||!strcmp (mimetype, "video/x-huffyuv")
|| !strcmp (mimetype, "video/x-divx")
}
} else if (!strcmp (mimetype, "video/x-wmv")) {
gint wmvversion;
- guint32 format;
- if (gst_structure_get_fourcc (structure, "format", &format)) {
- fourcc = format;
+ const gchar *fstr;
+
+ fstr = gst_structure_get_string (structure, "format");
+ if (fstr && strlen (fstr) == 4) {
+ fourcc = GST_STR_FOURCC (fstr);
} else if (gst_structure_get_int (structure, "wmvversion", &wmvversion)) {
if (wmvversion == 2) {
fourcc = GST_MAKE_FOURCC ('W', 'M', 'V', '2');
/* process codec private/initialization data, if any */
if (codec_buf) {
- size += GST_BUFFER_SIZE (codec_buf);
+ size += gst_buffer_get_size (codec_buf);
bih = g_realloc (bih, size);
GST_WRITE_UINT32_LE (&bih->size, size);
- memcpy ((guint8 *) bih + sizeof (gst_riff_strf_vids),
- GST_BUFFER_DATA (codec_buf), GST_BUFFER_SIZE (codec_buf));
+ gst_buffer_extract (codec_buf, 0,
+ (guint8 *) bih + sizeof (gst_riff_strf_vids), -1);
}
gst_matroska_mux_set_codec_id (context,
gst_matroska_mux_free_codec_priv (context);
/* Create avcC header */
if (codec_buf != NULL) {
- context->codec_priv_size = GST_BUFFER_SIZE (codec_buf);
+ context->codec_priv_size = gst_buffer_get_size (codec_buf);
context->codec_priv = g_malloc0 (context->codec_priv_size);
- memcpy (context->codec_priv, GST_BUFFER_DATA (codec_buf),
- context->codec_priv_size);
+ gst_buffer_extract (codec_buf, 0, context->codec_priv, -1);
}
} else if (!strcmp (mimetype, "video/x-theora")) {
const GValue *streamheader;
/* global headers may be in codec data */
if (codec_buf != NULL) {
gst_matroska_mux_free_codec_priv (context);
- context->codec_priv_size = GST_BUFFER_SIZE (codec_buf);
+ context->codec_priv_size = gst_buffer_get_size (codec_buf);
context->codec_priv = g_malloc0 (context->codec_priv_size);
- memcpy (context->codec_priv, GST_BUFFER_DATA (codec_buf),
- context->codec_priv_size);
+ gst_buffer_extract (codec_buf, 0, context->codec_priv, -1);
}
} else if (!strcmp (mimetype, "video/x-msmpeg")) {
msmpeg43:
GstBuffer *codec_data_buf = g_value_peek_pointer (mdpr_data);
- priv_data_size = GST_BUFFER_SIZE (codec_data_buf);
+ priv_data_size = gst_buffer_get_size (codec_data_buf);
priv_data = g_malloc0 (priv_data_size);
- memcpy (priv_data, GST_BUFFER_DATA (codec_data_buf), priv_data_size);
+ gst_buffer_extract (codec_data_buf, 0, priv_data, -1);
gst_matroska_mux_free_codec_priv (context);
context->codec_priv = priv_data;
priv_data_size = 1;
if (bufarr->len > 0) {
for (i = 0; i < bufarr->len - 1; i++) {
- priv_data_size += GST_BUFFER_SIZE (buf[i]) / 0xff + 1;
+ priv_data_size += gst_buffer_get_size (buf[i]) / 0xff + 1;
}
}
for (i = 0; i < bufarr->len; ++i) {
- priv_data_size += GST_BUFFER_SIZE (buf[i]);
+ priv_data_size += gst_buffer_get_size (buf[i]);
}
priv_data = g_malloc0 (priv_data_size);
if (bufarr->len > 0) {
for (bufi = 0; bufi < bufarr->len - 1; bufi++) {
- for (i = 0; i < GST_BUFFER_SIZE (buf[bufi]) / 0xff; ++i) {
+ for (i = 0; i < gst_buffer_get_size (buf[bufi]) / 0xff; ++i) {
priv_data[offset++] = 0xff;
}
- priv_data[offset++] = GST_BUFFER_SIZE (buf[bufi]) % 0xff;
+ priv_data[offset++] = gst_buffer_get_size (buf[bufi]) % 0xff;
}
}
for (i = 0; i < bufarr->len; ++i) {
- memcpy (priv_data + offset, GST_BUFFER_DATA (buf[i]),
- GST_BUFFER_SIZE (buf[i]));
- offset += GST_BUFFER_SIZE (buf[i]);
+ gst_buffer_extract (buf[i], 0, priv_data + offset, -1);
+ offset += gst_buffer_get_size (buf[i]);
}
gst_matroska_mux_free_codec_priv (context);
if (!xiphN_streamheader_to_codecdata (streamheader, context, &buf0, 3))
return FALSE;
- if (buf0 == NULL || GST_BUFFER_SIZE (buf0) < 1 + 6 + 4) {
+ if (buf0 == NULL || gst_buffer_get_size (buf0) < 1 + 6 + 4) {
GST_WARNING ("First vorbis header too small, ignoring");
} else {
- if (memcmp (GST_BUFFER_DATA (buf0) + 1, "vorbis", 6) == 0) {
+ if (gst_buffer_memcmp (buf0, 1, "vorbis", 6) == 0) {
GstMatroskaTrackAudioContext *audiocontext;
+ GstMapInfo map;
guint8 *hdr;
- hdr = GST_BUFFER_DATA (buf0) + 1 + 6 + 4;
+ gst_buffer_map (buf0, &map, GST_MAP_READ);
+ hdr = map.data + 1 + 6 + 4;
audiocontext = (GstMatroskaTrackAudioContext *) context;
audiocontext->channels = GST_READ_UINT8 (hdr);
audiocontext->samplerate = GST_READ_UINT32_LE (hdr + 1);
+ gst_buffer_unmap (buf0, &map);
}
}
if (!xiphN_streamheader_to_codecdata (streamheader, context, &buf0, 3))
return FALSE;
- if (buf0 == NULL || GST_BUFFER_SIZE (buf0) < 1 + 6 + 26) {
+ if (buf0 == NULL || gst_buffer_get_size (buf0) < 1 + 6 + 26) {
GST_WARNING ("First theora header too small, ignoring");
- } else if (memcmp (GST_BUFFER_DATA (buf0), "\200theora\003\002", 9) != 0) {
+ } else if (gst_buffer_memcmp (buf0, 0, "\200theora\003\002", 9) != 0) {
GST_WARNING ("First header not a theora identification header, ignoring");
} else {
GstMatroskaTrackVideoContext *videocontext;
guint fps_num, fps_denom, par_num, par_denom;
+ GstMapInfo map;
guint8 *hdr;
- hdr = GST_BUFFER_DATA (buf0) + 1 + 6 + 3 + 2 + 2;
+ gst_buffer_map (buf0, &map, GST_MAP_READ);
+ hdr = map.data + 1 + 6 + 3 + 2 + 2;
videocontext = (GstMatroskaTrackVideoContext *) context;
videocontext->pixel_width = GST_READ_UINT32_BE (hdr) >> 8;
videocontext->display_height = 0;
}
hdr += 3 + 3;
+
+ gst_buffer_unmap (buf0, &map);
}
if (buf0)
if (!xiphN_streamheader_to_codecdata (streamheader, context, &buf0, -1))
return FALSE;
- if (buf0 == NULL || GST_BUFFER_SIZE (buf0) < 64) { /* Kate ID header is 64 bytes */
+ if (buf0 == NULL || gst_buffer_get_size (buf0) < 64) { /* Kate ID header is 64 bytes */
GST_WARNING ("First kate header too small, ignoring");
- } else if (memcmp (GST_BUFFER_DATA (buf0), "\200kate\0\0\0", 8) != 0) {
+ } else if (gst_buffer_memcmp (buf0, 0, "\200kate\0\0\0", 8) != 0) {
GST_WARNING ("First header not a kate identification header, ignoring");
}
buffer = g_value_peek_pointer (bufval);
/* Need at least OggFLAC mapping header, fLaC marker and STREAMINFO block */
- if (GST_BUFFER_SIZE (buffer) < 9 + 4 + 4 + 34
- || memcmp (GST_BUFFER_DATA (buffer) + 1, "FLAC", 4) != 0
- || memcmp (GST_BUFFER_DATA (buffer) + 9, "fLaC", 4) != 0) {
+ if (gst_buffer_get_size (buffer) < 9 + 4 + 4 + 34
+ || gst_buffer_memcmp (buffer, 1, "FLAC", 4) != 0
+ || gst_buffer_memcmp (buffer, 9, "fLaC", 4) != 0) {
GST_WARNING ("Invalid streamheader for FLAC");
return FALSE;
}
gst_matroska_mux_free_codec_priv (context);
- context->codec_priv = g_malloc (GST_BUFFER_SIZE (buffer) - 9);
- context->codec_priv_size = GST_BUFFER_SIZE (buffer) - 9;
- memcpy (context->codec_priv, GST_BUFFER_DATA (buffer) + 9,
- GST_BUFFER_SIZE (buffer) - 9);
+ context->codec_priv_size = gst_buffer_get_size (buffer) - 9;
+ context->codec_priv = g_malloc (context->codec_priv_size);
+ gst_buffer_extract (buffer, 9, context->codec_priv, -1);
for (i = 1; i < bufarr->len; i++) {
+ guint old_size;
bufval = &g_array_index (bufarr, GValue, i);
if (G_VALUE_TYPE (bufval) != GST_TYPE_BUFFER) {
buffer = g_value_peek_pointer (bufval);
- context->codec_priv =
- g_realloc (context->codec_priv,
- context->codec_priv_size + GST_BUFFER_SIZE (buffer));
- memcpy ((guint8 *) context->codec_priv + context->codec_priv_size,
- GST_BUFFER_DATA (buffer), GST_BUFFER_SIZE (buffer));
- context->codec_priv_size =
- context->codec_priv_size + GST_BUFFER_SIZE (buffer);
+ old_size = context->codec_priv_size;
+ context->codec_priv_size += gst_buffer_get_size (buffer);
+
+ context->codec_priv = g_realloc (context->codec_priv,
+ context->codec_priv_size);
+ gst_buffer_extract (buffer, 0,
+ (guint8 *) context->codec_priv + old_size, -1);
}
return TRUE;
GArray *bufarr;
GValue *bufval;
GstBuffer *buffer;
+ guint old_size;
if (streamheader == NULL || G_VALUE_TYPE (streamheader) != GST_TYPE_ARRAY) {
GST_WARNING ("No or invalid streamheader field in the caps");
buffer = g_value_peek_pointer (bufval);
- if (GST_BUFFER_SIZE (buffer) < 80
- || memcmp (GST_BUFFER_DATA (buffer), "Speex ", 8) != 0) {
+ if (gst_buffer_get_size (buffer) < 80
+ || gst_buffer_memcmp (buffer, 0, "Speex ", 8) != 0) {
GST_WARNING ("Invalid streamheader for Speex");
return FALSE;
}
gst_matroska_mux_free_codec_priv (context);
- context->codec_priv = g_malloc (GST_BUFFER_SIZE (buffer));
- context->codec_priv_size = GST_BUFFER_SIZE (buffer);
- memcpy (context->codec_priv, GST_BUFFER_DATA (buffer),
- GST_BUFFER_SIZE (buffer));
+ context->codec_priv_size = gst_buffer_get_size (buffer);
+ context->codec_priv = g_malloc (context->codec_priv_size);
+ gst_buffer_extract (buffer, 0, context->codec_priv, -1);
bufval = &g_array_index (bufarr, GValue, 1);
buffer = g_value_peek_pointer (bufval);
- context->codec_priv =
- g_realloc (context->codec_priv,
- context->codec_priv_size + GST_BUFFER_SIZE (buffer));
- memcpy ((guint8 *) context->codec_priv + context->codec_priv_size,
- GST_BUFFER_DATA (buffer), GST_BUFFER_SIZE (buffer));
- context->codec_priv_size =
- context->codec_priv_size + GST_BUFFER_SIZE (buffer);
+ old_size = context->codec_priv_size;
+ context->codec_priv_size += gst_buffer_get_size (buffer);
+ context->codec_priv = g_realloc (context->codec_priv,
+ context->codec_priv_size);
+ gst_buffer_extract (buffer, 0, (guint8 *) context->codec_priv + old_size, -1);
return TRUE;
}
static const gchar *
-aac_codec_data_to_codec_id (const GstBuffer * buf)
+aac_codec_data_to_codec_id (GstBuffer * buf)
{
const gchar *result;
- gint profile;
+ guint8 profile;
/* default to MAIN */
profile = 1;
- if (GST_BUFFER_SIZE (buf) >= 2) {
- profile = GST_READ_UINT8 (GST_BUFFER_DATA (buf));
+ if (gst_buffer_get_size (buf) >= 2) {
+ gst_buffer_extract (buf, 0, &profile, 1);
profile >>= 3;
}
gint samplerate = 0, channels = 0;
GstStructure *structure;
const GValue *codec_data = NULL;
- const GstBuffer *buf = NULL;
+ GstBuffer *buf = NULL;
const gchar *stream_format = NULL;
mux = GST_MATROSKA_MUX (GST_PAD_PARENT (pad));
default:
goto refuse_caps;
}
- } else if (!strcmp (mimetype, "audio/x-raw-int")) {
- gint width, depth;
- gint endianness = G_LITTLE_ENDIAN;
- gboolean signedness = TRUE;
-
- if (!gst_structure_get_int (structure, "width", &width) ||
- !gst_structure_get_int (structure, "depth", &depth) ||
- !gst_structure_get_boolean (structure, "signed", &signedness)) {
- GST_DEBUG_OBJECT (mux, "broken caps, width/depth/signed field missing");
- goto refuse_caps;
- }
-
- if (depth > 8 &&
- !gst_structure_get_int (structure, "endianness", &endianness)) {
- GST_DEBUG_OBJECT (mux, "broken caps, no endianness specified");
- goto refuse_caps;
- }
+ } else if (!strcmp (mimetype, "audio/x-raw")) {
+ GstAudioInfo info;
- if (width != depth) {
- GST_DEBUG_OBJECT (mux, "width must be same as depth!");
+ gst_audio_info_init (&info);
+ if (!gst_audio_info_from_caps (&info, caps)) {
+ GST_DEBUG_OBJECT (mux,
+ "broken caps, rejected by gst_audio_info_from_caps");
goto refuse_caps;
}
- /* FIXME: where is this spec'ed out? (tpm) */
- if ((width == 8 && signedness) || (width >= 16 && !signedness)) {
- GST_DEBUG_OBJECT (mux, "8-bit PCM must be unsigned, 16-bit PCM signed");
- goto refuse_caps;
- }
-
- audiocontext->bitdepth = depth;
- if (endianness == G_BIG_ENDIAN)
- gst_matroska_mux_set_codec_id (context,
- GST_MATROSKA_CODEC_ID_AUDIO_PCM_INT_BE);
- else
- gst_matroska_mux_set_codec_id (context,
- GST_MATROSKA_CODEC_ID_AUDIO_PCM_INT_LE);
-
- } else if (!strcmp (mimetype, "audio/x-raw-float")) {
- gint width;
+ switch (GST_AUDIO_INFO_FORMAT (&info)) {
+ case GST_AUDIO_FORMAT_U8:
+ case GST_AUDIO_FORMAT_S16BE:
+ case GST_AUDIO_FORMAT_S16LE:
+ case GST_AUDIO_FORMAT_S24BE:
+ case GST_AUDIO_FORMAT_S24LE:
+ case GST_AUDIO_FORMAT_S32BE:
+ case GST_AUDIO_FORMAT_S32LE:
+ if (GST_AUDIO_INFO_WIDTH (&info) != GST_AUDIO_INFO_DEPTH (&info)) {
+ GST_DEBUG_OBJECT (mux, "width must be same as depth!");
+ goto refuse_caps;
+ }
+ if (GST_AUDIO_INFO_IS_BIG_ENDIAN (&info))
+ gst_matroska_mux_set_codec_id (context,
+ GST_MATROSKA_CODEC_ID_AUDIO_PCM_INT_BE);
+ else
+ gst_matroska_mux_set_codec_id (context,
+ GST_MATROSKA_CODEC_ID_AUDIO_PCM_INT_LE);
+ break;
+ case GST_AUDIO_FORMAT_F32LE:
+ case GST_AUDIO_FORMAT_F64LE:
+ gst_matroska_mux_set_codec_id (context,
+ GST_MATROSKA_CODEC_ID_AUDIO_PCM_FLOAT);
+ break;
- if (!gst_structure_get_int (structure, "width", &width)) {
- GST_DEBUG_OBJECT (mux, "broken caps, width field missing");
- goto refuse_caps;
+ default:
+ GST_DEBUG_OBJECT (mux, "wrong format in raw audio caps");
+ goto refuse_caps;
}
- audiocontext->bitdepth = width;
- gst_matroska_mux_set_codec_id (context,
- GST_MATROSKA_CODEC_ID_AUDIO_PCM_FLOAT);
-
+ audiocontext->bitdepth = GST_AUDIO_INFO_WIDTH (&info);
} else if (!strcmp (mimetype, "audio/x-vorbis")) {
const GValue *streamheader;
GstBuffer *codec_data_buf = g_value_peek_pointer (mdpr_data);
- priv_data_size = GST_BUFFER_SIZE (codec_data_buf);
+ priv_data_size = gst_buffer_get_size (codec_data_buf);
priv_data = g_malloc0 (priv_data_size);
- memcpy (priv_data, GST_BUFFER_DATA (codec_data_buf), priv_data_size);
+ gst_buffer_extract (codec_data_buf, 0, priv_data, -1);
gst_matroska_mux_free_codec_priv (context);
codec_priv_size = WAVEFORMATEX_SIZE;
if (buf)
- codec_priv_size += GST_BUFFER_SIZE (buf);
+ codec_priv_size += gst_buffer_get_size (buf);
/* serialize waveformatex structure */
codec_priv = g_malloc0 (codec_priv_size);
GST_WRITE_UINT16_LE (codec_priv + 12, block_align);
GST_WRITE_UINT16_LE (codec_priv + 14, 0);
if (buf)
- GST_WRITE_UINT16_LE (codec_priv + 16, GST_BUFFER_SIZE (buf));
+ GST_WRITE_UINT16_LE (codec_priv + 16, gst_buffer_get_size (buf));
else
GST_WRITE_UINT16_LE (codec_priv + 16, 0);
/* process codec private/initialization data, if any */
if (buf) {
- memcpy ((guint8 *) codec_priv + WAVEFORMATEX_SIZE,
- GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf));
+ gst_buffer_extract (buf, 0,
+ (guint8 *) codec_priv + WAVEFORMATEX_SIZE, -1);
}
gst_matroska_mux_set_codec_id (context, GST_MATROSKA_CODEC_ID_AUDIO_ACM);
const gchar *mimetype;
GstStructure *structure;
const GValue *value = NULL;
- const GstBuffer *buf = NULL;
+ GstBuffer *buf = NULL;
gboolean ret = TRUE;
mux = GST_MATROSKA_MUX (GST_PAD_PARENT (pad));
if (value)
buf = gst_value_get_buffer (value);
if (buf != NULL) {
+ GstMapInfo map;
guint8 *priv_data = NULL;
- guint priv_data_size = 0;
- priv_data_size = GST_BUFFER_SIZE (buf);
- if (priv_data_size > SUBTITLE_MAX_CODEC_PRIVATE) {
+ gst_buffer_map (buf, &map, GST_MAP_READ);
+
+ if (map.size > SUBTITLE_MAX_CODEC_PRIVATE) {
GST_WARNING_OBJECT (mux, "pad %" GST_PTR_FORMAT " subtitle private data"
" exceeded maximum (%d); discarding", pad,
SUBTITLE_MAX_CODEC_PRIVATE);
+ gst_buffer_unmap (buf, &map);
return TRUE;
}
gst_matroska_mux_free_codec_priv (context);
- priv_data = g_malloc0 (priv_data_size);
- memcpy (priv_data, GST_BUFFER_DATA (buf), priv_data_size);
+ priv_data = g_malloc0 (map.size);
+ memcpy (priv_data, map.data, map.size);
context->codec_priv = priv_data;
- context->codec_priv_size = priv_data_size;
+ context->codec_priv_size = map.size;
+ gst_buffer_unmap (buf, &map);
}
- GST_DEBUG_OBJECT (pad, "codec_id %s, codec data size %u",
+ GST_DEBUG_OBJECT (pad, "codec_id %s, codec data size %" G_GSIZE_FORMAT,
GST_STR_NULL (context->codec_id), context->codec_priv_size);
exit:
*/
static GstPad *
gst_matroska_mux_request_new_pad (GstElement * element,
- GstPadTemplate * templ, const gchar * req_name)
+ GstPadTemplate * templ, const gchar * req_name, const GstCaps * caps)
{
GstElementClass *klass = GST_ELEMENT_GET_CLASS (element);
GstMatroskaMux *mux = GST_MATROSKA_MUX (element);
GstMatroskamuxPad *newpad;
gchar *name = NULL;
const gchar *pad_name = NULL;
- GstPadSetCapsFunction setcapsfunc = NULL;
+ GstMatroskaCapsFunc capsfunc = NULL;
GstMatroskaTrackContext *context = NULL;
gint pad_id;
gboolean locked = TRUE;
gchar *id = NULL;
- if (templ == gst_element_class_get_pad_template (klass, "audio_%d")) {
+ if (templ == gst_element_class_get_pad_template (klass, "audio_%u")) {
/* don't mix named and unnamed pads, if the pad already exists we fail when
* trying to add it */
- if (req_name != NULL && sscanf (req_name, "audio_%d", &pad_id) == 1) {
+ if (req_name != NULL && sscanf (req_name, "audio_%u", &pad_id) == 1) {
pad_name = req_name;
} else {
- name = g_strdup_printf ("audio_%d", mux->num_a_streams++);
+ name = g_strdup_printf ("audio_%u", mux->num_a_streams++);
pad_name = name;
}
- setcapsfunc = GST_DEBUG_FUNCPTR (gst_matroska_mux_audio_pad_setcaps);
+ capsfunc = GST_DEBUG_FUNCPTR (gst_matroska_mux_audio_pad_setcaps);
context = (GstMatroskaTrackContext *)
g_new0 (GstMatroskaTrackAudioContext, 1);
context->type = GST_MATROSKA_TRACK_TYPE_AUDIO;
context->name = g_strdup ("Audio");
- } else if (templ == gst_element_class_get_pad_template (klass, "video_%d")) {
+ } else if (templ == gst_element_class_get_pad_template (klass, "video_%u")) {
/* don't mix named and unnamed pads, if the pad already exists we fail when
* trying to add it */
- if (req_name != NULL && sscanf (req_name, "video_%d", &pad_id) == 1) {
+ if (req_name != NULL && sscanf (req_name, "video_%u", &pad_id) == 1) {
pad_name = req_name;
} else {
- name = g_strdup_printf ("video_%d", mux->num_v_streams++);
+ name = g_strdup_printf ("video_%u", mux->num_v_streams++);
pad_name = name;
}
- setcapsfunc = GST_DEBUG_FUNCPTR (gst_matroska_mux_video_pad_setcaps);
+ capsfunc = GST_DEBUG_FUNCPTR (gst_matroska_mux_video_pad_setcaps);
context = (GstMatroskaTrackContext *)
g_new0 (GstMatroskaTrackVideoContext, 1);
context->type = GST_MATROSKA_TRACK_TYPE_VIDEO;
context->name = g_strdup ("Video");
- } else if (templ == gst_element_class_get_pad_template (klass, "subtitle_%d")) {
+ } else if (templ == gst_element_class_get_pad_template (klass, "subtitle_%u")) {
/* don't mix named and unnamed pads, if the pad already exists we fail when
* trying to add it */
- if (req_name != NULL && sscanf (req_name, "subtitle_%d", &pad_id) == 1) {
+ if (req_name != NULL && sscanf (req_name, "subtitle_%u", &pad_id) == 1) {
pad_name = req_name;
} else {
- name = g_strdup_printf ("subtitle_%d", mux->num_t_streams++);
+ name = g_strdup_printf ("subtitle_%u", mux->num_t_streams++);
pad_name = name;
}
- setcapsfunc = GST_DEBUG_FUNCPTR (gst_matroska_mux_subtitle_pad_setcaps);
+ capsfunc = GST_DEBUG_FUNCPTR (gst_matroska_mux_subtitle_pad_setcaps);
context = (GstMatroskaTrackContext *)
g_new0 (GstMatroskaTrackSubtitleContext, 1);
context->type = GST_MATROSKA_TRACK_TYPE_SUBTITLE;
gst_matroska_pad_reset (collect_pad, FALSE);
collect_pad->track->codec_id = id;
- gst_pad_set_setcaps_function (GST_PAD (newpad), setcapsfunc);
+ collect_pad->capsfunc = capsfunc;
gst_pad_set_active (GST_PAD (newpad), TRUE);
if (!gst_element_add_pad (element, GST_PAD (newpad)))
goto pad_add_failed;
context->codec_priv, context->codec_priv_size);
}
+static void
+gst_matroska_mux_write_chapter_title (const gchar * title, GstEbmlWrite * ebml)
+{
+ guint64 title_master;
+
+ title_master =
+ gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_CHAPTERDISPLAY);
+
+ gst_ebml_write_utf8 (ebml, GST_MATROSKA_ID_CHAPSTRING, title);
+ gst_ebml_write_ascii (ebml, GST_MATROSKA_ID_CHAPLANGUAGE,
+ GST_MATROSKA_MUX_CHAPLANG);
+
+ gst_ebml_write_master_finish (ebml, title_master);
+}
+
+static void
+gst_matroska_mux_write_chapter (GstMatroskaMux * mux, GstTocEntry * edition,
+ GstTocEntry * entry, GstEbmlWrite * ebml, guint64 * master_chapters,
+ guint64 * master_edition)
+{
+ guint64 uid, master_chapteratom;
+ GList *cur;
+ GstTocEntry *cur_entry;
+ guint count, i;
+ gchar *title;
+ gint64 start, stop;
+
+ if (G_UNLIKELY (master_chapters != NULL && *master_chapters == 0))
+ *master_chapters =
+ gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_CHAPTERS);
+
+ if (G_UNLIKELY (master_edition != NULL && *master_edition == 0)) {
+ /* create uid for the parent */
+ uid = gst_matroska_mux_create_uid ();
+ g_free (edition->uid);
+ edition->uid = g_strdup_printf ("%" G_GUINT64_FORMAT, uid);
+
+ *master_edition =
+ gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_EDITIONENTRY);
+
+ gst_ebml_write_uint (ebml, GST_MATROSKA_ID_EDITIONUID, uid);
+ gst_ebml_write_uint (ebml, GST_MATROSKA_ID_EDITIONFLAGHIDDEN, 0);
+ gst_ebml_write_uint (ebml, GST_MATROSKA_ID_EDITIONFLAGDEFAULT, 0);
+ gst_ebml_write_uint (ebml, GST_MATROSKA_ID_EDITIONFLAGORDERED, 0);
+ }
+
+ uid = gst_matroska_mux_create_uid ();
+ gst_toc_entry_get_start_stop (entry, &start, &stop);
+
+ master_chapteratom =
+ gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_CHAPTERATOM);
+ g_free (entry->uid);
+ entry->uid = g_strdup_printf ("%" G_GUINT64_FORMAT, uid);
+ gst_ebml_write_uint (ebml, GST_MATROSKA_ID_CHAPTERUID, uid);
+ gst_ebml_write_uint (ebml, GST_MATROSKA_ID_CHAPTERTIMESTART, start);
+ gst_ebml_write_uint (ebml, GST_MATROSKA_ID_CHAPTERTIMESTOP, stop);
+ gst_ebml_write_uint (ebml, GST_MATROSKA_ID_CHAPTERFLAGHIDDEN, 0);
+ gst_ebml_write_uint (ebml, GST_MATROSKA_ID_CHAPTERFLAGENABLED, 1);
+
+ cur = entry->subentries;
+ while (cur != NULL) {
+ cur_entry = cur->data;
+ gst_matroska_mux_write_chapter (mux, NULL, cur_entry, ebml, NULL, NULL);
+
+ cur = cur->next;
+ }
+
+ if (G_LIKELY (entry->tags != NULL)) {
+ count = gst_tag_list_get_tag_size (entry->tags, GST_TAG_TITLE);
+
+ for (i = 0; i < count; ++i) {
+ gst_tag_list_get_string_index (entry->tags, GST_TAG_TITLE, i, &title);
+ gst_matroska_mux_write_chapter_title (title, ebml);
+ g_free (title);
+ }
+
+ /* remove title tag */
+ if (G_LIKELY (count > 0))
+ gst_tag_list_remove_tag (entry->tags, GST_TAG_TITLE);
+ }
+
+ gst_ebml_write_master_finish (ebml, master_chapteratom);
+}
+
+static void
+gst_matroska_mux_write_chapter_edition (GstMatroskaMux * mux,
+ GstTocEntry * entry, GstEbmlWrite * ebml, guint64 * master_chapters)
+{
+ guint64 master_edition = 0;
+ GList *cur;
+ GstTocEntry *subentry;
+
+ cur = entry->subentries;
+ while (cur != NULL) {
+ subentry = cur->data;
+ gst_matroska_mux_write_chapter (mux, entry, subentry, ebml, master_chapters,
+ &master_edition);
+
+ cur = cur->next;
+ }
+
+ if (G_LIKELY (master_edition != 0))
+ gst_ebml_write_master_finish (ebml, master_edition);
+}
/**
* gst_matroska_mux_start:
const gchar *doctype;
guint32 seekhead_id[] = { GST_MATROSKA_ID_SEGMENTINFO,
GST_MATROSKA_ID_TRACKS,
+ GST_MATROSKA_ID_CHAPTERS,
GST_MATROSKA_ID_CUES,
GST_MATROSKA_ID_TAGS,
0
if (gst_pad_peer_query (mux->srcpad, query)) {
gst_query_parse_seeking (query, NULL, &seekable, NULL, NULL);
GST_INFO_OBJECT (mux, "downstream is %sseekable", seekable ? "" : "not ");
- if (!seekable) {
- mux->streamable = TRUE;
- g_object_notify (G_OBJECT (mux), "streamable");
- GST_WARNING_OBJECT (mux, "downstream is not seekable, but "
- "streamable=false. Will ignore that and create streamable output "
- "instead");
- }
} else {
/* have to assume seeking is supported if query not handled downstream */
- /* FIXME 0.11: change to query not handled => seeking not supported */
GST_WARNING_OBJECT (mux, "downstream did not handle seeking query");
+ seekable = FALSE;
+ }
+ if (!seekable) {
+ mux->streamable = TRUE;
+ g_object_notify (G_OBJECT (mux), "streamable");
+ GST_WARNING_OBJECT (mux, "downstream is not seekable, but "
+ "streamable=false. Will ignore that and create streamable output "
+ "instead");
}
+ gst_query_unref (query);
}
if (!strcmp (mux->doctype, GST_MATROSKA_DOCTYPE_WEBM)) {
- ebml->caps = gst_caps_new_simple ("video/webm", NULL);
+ ebml->caps = gst_caps_new_empty_simple ("video/webm");
} else {
- ebml->caps = gst_caps_new_simple ("video/x-matroska", NULL);
+ ebml->caps = gst_caps_new_empty_simple ("video/x-matroska");
}
/* we start with a EBML header */
doctype = mux->doctype;
for (collected = mux->collect->data; collected;
collected = g_slist_next (collected)) {
GstMatroskaPad *collect_pad;
- GstFormat format = GST_FORMAT_TIME;
GstPad *thepad;
gint64 trackduration;
/* Query the total length of the track. */
GST_DEBUG_OBJECT (thepad, "querying peer duration");
- if (gst_pad_query_peer_duration (thepad, &format, &trackduration)) {
+ if (gst_pad_peer_query_duration (thepad, GST_FORMAT_TIME, &trackduration)) {
GST_DEBUG_OBJECT (thepad, "duration: %" GST_TIME_FORMAT,
GST_TIME_ARGS (trackduration));
if (trackduration != GST_CLOCK_TIME_NONE && trackduration > duration) {
}
gst_ebml_write_master_finish (ebml, master);
+ /* chapters */
+ if (gst_toc_setter_get_toc (GST_TOC_SETTER (mux)) != NULL && !mux->streamable) {
+ guint64 master_chapters = 0;
+ GstTocEntry *toc_entry;
+ const GstToc *toc;
+ GList *cur, *to_write = NULL;
+ gint64 start, stop;
+
+ GST_DEBUG ("Writing chapters");
+
+ toc = gst_toc_setter_get_toc (GST_TOC_SETTER (mux));
+
+ /* check whether we have editions or chapters at the root level */
+ toc_entry = toc->entries->data;
+
+ if (toc_entry->type != GST_TOC_ENTRY_TYPE_EDITION) {
+ toc_entry = gst_toc_entry_new (GST_TOC_ENTRY_TYPE_EDITION, "");
+ gst_toc_entry_set_start_stop (toc_entry, -1, -1);
+
+ /* aggregate all chapters without root edition */
+ cur = toc->entries;
+ while (cur != NULL) {
+ toc_entry->subentries =
+ g_list_prepend (toc_entry->subentries, cur->data);
+ cur = cur->next;
+ }
+
+ gst_toc_entry_get_start_stop (((GstTocEntry *) toc_entry->
+ subentries->data), &start, NULL);
+ toc_entry->subentries = g_list_reverse (toc_entry->subentries);
+ gst_toc_entry_get_start_stop (((GstTocEntry *) toc_entry->
+ subentries->data), NULL, &stop);
+ gst_toc_entry_set_start_stop (toc_entry, start, stop);
+
+ to_write = g_list_append (to_write, toc_entry);
+ } else {
+ toc_entry = NULL;
+ to_write = toc->entries;
+ }
+
+ /* finally write chapters */
+ mux->chapters_pos = ebml->pos;
+
+ cur = to_write;
+ while (cur != NULL) {
+ gst_matroska_mux_write_chapter_edition (mux, cur->data, ebml,
+ &master_chapters);
+ cur = cur->next;
+ }
+
+ /* close master element if any edition was written */
+ if (G_LIKELY (master_chapters != 0))
+ gst_ebml_write_master_finish (ebml, master_chapters);
+
+ if (toc_entry != NULL) {
+ g_list_free (toc_entry->subentries);
+ toc_entry->subentries = NULL;
+ gst_toc_entry_free (toc_entry);
+ g_list_free (to_write);
+ }
+ }
+
/* lastly, flush the cache */
gst_ebml_write_flush_cache (ebml, FALSE, 0);
}
}
}
+static void
+gst_matroska_mux_write_toc_entry_tags (GstMatroskaMux * mux,
+ const GstTocEntry * entry, guint64 * master_tags)
+{
+ guint64 master_tag, master_targets;
+ GstEbmlWrite *ebml;
+ GList *cur;
+
+ ebml = mux->ebml_write;
+
+ if (G_UNLIKELY (entry->tags != NULL && !gst_tag_list_is_empty (entry->tags))) {
+ if (*master_tags == 0) {
+ mux->tags_pos = ebml->pos;
+ *master_tags = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_TAGS);
+ }
+
+ master_tag = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_TAG);
+ master_targets =
+ gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_TARGETS);
+
+ if (entry->type == GST_TOC_ENTRY_TYPE_EDITION)
+ gst_ebml_write_uint (ebml, GST_MATROSKA_ID_TARGETEDITIONUID,
+ g_ascii_strtoull (entry->uid, NULL, 10));
+ else
+ gst_ebml_write_uint (ebml, GST_MATROSKA_ID_TARGETCHAPTERUID,
+ g_ascii_strtoull (entry->uid, NULL, 10));
+
+ gst_ebml_write_master_finish (ebml, master_targets);
+ gst_tag_list_foreach (entry->tags, gst_matroska_mux_write_simple_tag, ebml);
+ gst_ebml_write_master_finish (ebml, master_tag);
+ }
+
+ cur = entry->subentries;
+ while (cur != NULL) {
+ gst_matroska_mux_write_toc_entry_tags (mux, cur->data, master_tags);
+ cur = cur->next;
+ }
+}
/**
* gst_matroska_mux_finish:
/* tags */
tags = gst_tag_setter_get_tag_list (GST_TAG_SETTER (mux));
- if (tags != NULL && !gst_tag_list_is_empty (tags)) {
- guint64 master_tags, master_tag;
+ if ((tags != NULL && !gst_tag_list_is_empty (tags))
+ || gst_toc_setter_get_toc (GST_TOC_SETTER (mux)) != NULL) {
+ guint64 master_tags = 0, master_tag;
+ GList *cur;
+ const GstToc *toc;
GST_DEBUG_OBJECT (mux, "Writing tags");
- /* TODO: maybe limit via the TARGETS id by looking at the source pad */
- mux->tags_pos = ebml->pos;
- master_tags = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_TAGS);
- master_tag = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_TAG);
- gst_tag_list_foreach (tags, gst_matroska_mux_write_simple_tag, ebml);
- gst_ebml_write_master_finish (ebml, master_tag);
- gst_ebml_write_master_finish (ebml, master_tags);
+ toc = gst_toc_setter_get_toc (GST_TOC_SETTER (mux));
+
+ if (tags != NULL) {
+ /* TODO: maybe limit via the TARGETS id by looking at the source pad */
+ mux->tags_pos = ebml->pos;
+ master_tags = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_TAGS);
+ master_tag = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_TAG);
+
+ if (tags != NULL)
+ gst_tag_list_foreach (tags, gst_matroska_mux_write_simple_tag, ebml);
+ if (toc != NULL)
+ gst_tag_list_foreach (toc->tags, gst_matroska_mux_write_simple_tag,
+ ebml);
+
+ gst_ebml_write_master_finish (ebml, master_tag);
+ }
+
+ if (toc != NULL) {
+ cur = toc->entries;
+ while (cur != NULL) {
+ gst_matroska_mux_write_toc_entry_tags (mux, cur->data, &master_tags);
+ cur = cur->next;
+ }
+ }
+
+ if (master_tags != 0)
+ gst_ebml_write_master_finish (ebml, master_tags);
}
/* update seekhead. We know that:
- * - a seekhead contains 4 entries.
+ * - a seekhead contains 5 entries.
* - order of entries is as above.
* - a seekhead has a 4-byte header + 8-byte length
* - each entry is 2-byte master, 2-byte ID pointer,
mux->info_pos - mux->segment_master);
gst_ebml_replace_uint (ebml, mux->seekhead_pos + 60,
mux->tracks_pos - mux->segment_master);
- if (mux->index != NULL) {
+ if (gst_toc_setter_get_toc (GST_TOC_SETTER (mux)) != NULL
+ && mux->chapters_pos > 0) {
gst_ebml_replace_uint (ebml, mux->seekhead_pos + 88,
- mux->cues_pos - mux->segment_master);
+ mux->chapters_pos - mux->segment_master);
} else {
/* void'ify */
guint64 my_pos = ebml->pos;
gst_ebml_write_buffer_header (ebml, GST_EBML_ID_VOID, 26);
gst_ebml_write_seek (ebml, my_pos);
}
- if (tags != NULL) {
+ if (mux->index != NULL) {
gst_ebml_replace_uint (ebml, mux->seekhead_pos + 116,
- mux->tags_pos - mux->segment_master);
+ mux->cues_pos - mux->segment_master);
} else {
/* void'ify */
guint64 my_pos = ebml->pos;
gst_ebml_write_seek (ebml, my_pos);
}
+ if (tags != NULL) {
+ gst_ebml_replace_uint (ebml, mux->seekhead_pos + 144,
+ mux->tags_pos - mux->segment_master);
+ } else {
+ /* void'ify */
+ guint64 my_pos = ebml->pos;
+
+ gst_ebml_write_seek (ebml, mux->seekhead_pos + 124);
+ gst_ebml_write_buffer_header (ebml, GST_EBML_ID_VOID, 26);
+ gst_ebml_write_seek (ebml, my_pos);
+ }
+
/* loop tracks:
* - first get the overall duration
* (a released track may have left a duration in here)
gint16 relative_timestamp, int flags)
{
GstBuffer *hdr;
+ guint8 *data = g_malloc (4);
- hdr = gst_buffer_new_and_alloc (4);
+ hdr = gst_buffer_new_wrapped (data, 4);
/* track num - FIXME: what if num >= 0x80 (unlikely)? */
- GST_BUFFER_DATA (hdr)[0] = track->num | 0x80;
+ data[0] = track->num | 0x80;
/* time relative to clustertime */
- GST_WRITE_UINT16_BE (GST_BUFFER_DATA (hdr) + 1, relative_timestamp);
+ GST_WRITE_UINT16_BE (data + 1, relative_timestamp);
/* flags */
- GST_BUFFER_DATA (hdr)[3] = flags;
+ data[3] = flags;
return hdr;
}
{
GstMatroskaTrackVideoContext *ctx =
(GstMatroskaTrackVideoContext *) collect_pad->track;
- const guint8 *data = GST_BUFFER_DATA (buf);
- guint size = GST_BUFFER_SIZE (buf);
+ GstMapInfo map;
+ guint8 *data;
+ gsize size;
guint8 parse_code;
guint32 next_parse_offset;
GstBuffer *ret = NULL;
gboolean is_muxing_unit = FALSE;
- if (GST_BUFFER_SIZE (buf) < 13) {
+ gst_buffer_map (buf, &map, GST_MAP_READ);
+ data = map.data;
+ size = map.size;
+
+ if (size < 13) {
+ gst_buffer_unmap (buf, &map);
gst_buffer_unref (buf);
return ret;
}
/* Check if this buffer contains a picture or end-of-sequence packet */
while (size >= 13) {
if (GST_READ_UINT32_BE (data) != 0x42424344 /* 'BBCD' */ ) {
+ gst_buffer_unmap (buf, &map);
gst_buffer_unref (buf);
return ret;
}
}
if (ctx->dirac_unit)
- ctx->dirac_unit = gst_buffer_join (ctx->dirac_unit, gst_buffer_ref (buf));
+ ctx->dirac_unit = gst_buffer_append (ctx->dirac_unit, gst_buffer_ref (buf));
else
ctx->dirac_unit = gst_buffer_ref (buf);
+ gst_buffer_unmap (buf, &map);
+
if (is_muxing_unit) {
- ret = gst_buffer_make_metadata_writable (ctx->dirac_unit);
+ ret = gst_buffer_make_writable (ctx->dirac_unit);
ctx->dirac_unit = NULL;
- gst_buffer_copy_metadata (ret, buf,
- GST_BUFFER_COPY_FLAGS | GST_BUFFER_COPY_TIMESTAMPS |
- GST_BUFFER_COPY_CAPS);
+ gst_buffer_copy_into (ret, buf,
+ GST_BUFFER_COPY_FLAGS | GST_BUFFER_COPY_TIMESTAMPS, 0, -1);
gst_buffer_unref (buf);
} else {
gst_buffer_unref (buf);
streamheader_buffer = gst_ebml_stop_streamheader (ebml);
if (!strcmp (mux->doctype, GST_MATROSKA_DOCTYPE_WEBM)) {
- caps = gst_caps_new_simple ("video/webm", NULL);
+ caps = gst_caps_new_empty_simple ("video/webm");
} else {
- caps = gst_caps_new_simple ("video/x-matroska", NULL);
+ caps = gst_caps_new_empty_simple ("video/x-matroska");
}
s = gst_caps_get_structure (caps, 0);
g_value_init (&streamheader, GST_TYPE_ARRAY);
g_value_init (&bufval, GST_TYPE_BUFFER);
- GST_BUFFER_FLAG_SET (streamheader_buffer, GST_BUFFER_FLAG_IN_CAPS);
+ GST_BUFFER_FLAG_SET (streamheader_buffer, GST_BUFFER_FLAG_HEADER);
gst_value_set_buffer (&bufval, streamheader_buffer);
gst_value_array_append_value (&streamheader, &bufval);
g_value_unset (&bufval);
relative_timestamp, flags);
gst_ebml_write_set_cache (ebml, 0x40);
gst_ebml_write_buffer_header (ebml, GST_MATROSKA_ID_SIMPLEBLOCK,
- GST_BUFFER_SIZE (buf) + GST_BUFFER_SIZE (hdr));
+ gst_buffer_get_size (buf) + gst_buffer_get_size (hdr));
gst_ebml_write_buffer (ebml, hdr);
gst_ebml_write_flush_cache (ebml, FALSE, GST_BUFFER_TIMESTAMP (buf));
gst_ebml_write_buffer (ebml, buf);
return gst_ebml_last_write_result (ebml);
} else {
- gst_ebml_write_set_cache (ebml, GST_BUFFER_SIZE (buf) * 2);
+ gst_ebml_write_set_cache (ebml, gst_buffer_get_size (buf) * 2);
/* write and call order slightly unnatural,
* but avoids seek and minizes pushing */
blockgroup = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_BLOCKGROUP);
if (write_duration)
gst_ebml_write_uint (ebml, GST_MATROSKA_ID_BLOCKDURATION, block_duration);
gst_ebml_write_buffer_header (ebml, GST_MATROSKA_ID_BLOCK,
- GST_BUFFER_SIZE (buf) + GST_BUFFER_SIZE (hdr));
+ gst_buffer_get_size (buf) + gst_buffer_get_size (hdr));
gst_ebml_write_buffer (ebml, hdr);
- gst_ebml_write_master_finish_full (ebml, blockgroup, GST_BUFFER_SIZE (buf));
+ gst_ebml_write_master_finish_full (ebml, blockgroup,
+ gst_buffer_get_size (buf));
gst_ebml_write_flush_cache (ebml, FALSE, GST_BUFFER_TIMESTAMP (buf));
gst_ebml_write_buffer (ebml, buf);
GST_DEBUG_OBJECT (mux, "... but streamable, nothing to finish");
}
gst_pad_push_event (mux->srcpad, gst_event_new_eos ());
- ret = GST_FLOW_UNEXPECTED;
+ ret = GST_FLOW_EOS;
goto exit;
}