matroska: port to 0.11

Support for TAG_IMAGE and TAG_ATTACHMENT is commented out; this requires caps
on buffers which is gone from 0.11.

Segment handling in the demuxer is a bit complex; I added some FIXME comments
in places where I'm not yet sure if I ported correctly.
This commit is contained in:
René Stadler 2011-11-26 10:01:07 +01:00
parent eeaa9e0bbc
commit 17240ac9ec
14 changed files with 850 additions and 815 deletions

View file

@ -314,7 +314,7 @@ dnl *** plug-ins to include ***
dnl Non ported plugins (non-dependant, then dependant)
dnl Make sure you have a space before and after all plugins
GST_PLUGINS_NONPORTED="deinterlace flx goom2k1 \
imagefreeze interleave matroska monoscope smpte \
imagefreeze interleave monoscope smpte \
videobox videomixer \
cairo cairo_gobject dv1394 gdk_pixbuf libdv libpng \
oss oss4 shout2 \

View file

@ -164,6 +164,7 @@ gst_ebml_read_init (GstEbmlRead * ebml, GstElement * el, GstBuffer * buf,
guint64 offset)
{
GstEbmlMaster m;
gsize buf_size;
g_return_if_fail (el);
g_return_if_fail (buf);
@ -171,9 +172,10 @@ gst_ebml_read_init (GstEbmlRead * ebml, GstElement * el, GstBuffer * buf,
ebml->el = el;
ebml->offset = offset;
ebml->buf = buf;
ebml->buf_data = gst_buffer_map (buf, &buf_size, NULL, GST_MAP_READ);
ebml->readers = g_array_sized_new (FALSE, FALSE, sizeof (GstEbmlMaster), 10);
m.offset = ebml->offset;
gst_byte_reader_init (&m.br, GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf));
gst_byte_reader_init (&m.br, ebml->buf_data, buf_size);
g_array_append_val (ebml->readers, m);
}
@ -183,8 +185,10 @@ gst_ebml_read_clear (GstEbmlRead * ebml)
if (ebml->readers)
g_array_free (ebml->readers, TRUE);
ebml->readers = NULL;
if (ebml->buf)
if (ebml->buf) {
gst_buffer_unmap (ebml->buf, ebml->buf_data, -1);
gst_buffer_unref (ebml->buf);
}
ebml->buf = NULL;
ebml->el = NULL;
}
@ -334,7 +338,8 @@ gst_ebml_read_buffer (GstEbmlRead * ebml, guint32 * id, GstBuffer ** buf)
offset = gst_ebml_read_get_pos (ebml) - ebml->offset;
if (G_LIKELY (gst_byte_reader_skip (gst_ebml_read_br (ebml), length))) {
*buf = gst_buffer_create_sub (ebml->buf, offset, length);
*buf = gst_buffer_copy_region (ebml->buf, GST_BUFFER_COPY_ALL,
offset, length);
} else {
*buf = NULL;
return GST_FLOW_PARSE;

View file

@ -54,6 +54,7 @@ typedef struct _GstEbmlRead {
GstElement *el;
GstBuffer *buf;
gpointer buf_data;
guint64 offset;
GArray *readers;

View file

@ -33,18 +33,14 @@
GST_DEBUG_CATEGORY_STATIC (gst_ebml_write_debug);
#define GST_CAT_DEFAULT gst_ebml_write_debug
#define _do_init(thing) \
#define _do_init \
GST_DEBUG_CATEGORY_INIT (gst_ebml_write_debug, "ebmlwrite", 0, "Write EBML structured data")
GST_BOILERPLATE_FULL (GstEbmlWrite, gst_ebml_write, GstObject, GST_TYPE_OBJECT,
#define parent_class gst_ebml_write_parent_class
G_DEFINE_TYPE_WITH_CODE (GstEbmlWrite, gst_ebml_write, GST_TYPE_OBJECT,
_do_init);
static void gst_ebml_write_finalize (GObject * object);
static void
gst_ebml_write_base_init (gpointer g_class)
{
}
static void
gst_ebml_write_class_init (GstEbmlWriteClass * klass)
{
@ -54,11 +50,11 @@ gst_ebml_write_class_init (GstEbmlWriteClass * klass)
}
static void
gst_ebml_write_init (GstEbmlWrite * ebml, GstEbmlWriteClass * klass)
gst_ebml_write_init (GstEbmlWrite * ebml)
{
ebml->srcpad = NULL;
ebml->pos = 0;
ebml->last_pos = G_MAXUINT64; /* force newsegment event */
ebml->last_pos = G_MAXUINT64; /* force segment event */
ebml->cache = NULL;
ebml->streamheader = NULL;
@ -89,7 +85,7 @@ gst_ebml_write_finalize (GObject * object)
ebml->caps = NULL;
}
GST_CALL_PARENT (G_OBJECT_CLASS, finalize, (object));
G_OBJECT_CLASS (parent_class)->finalize (object);
}
@ -126,7 +122,7 @@ void
gst_ebml_write_reset (GstEbmlWrite * ebml)
{
ebml->pos = 0;
ebml->last_pos = G_MAXUINT64; /* force newsegment event */
ebml->last_pos = G_MAXUINT64; /* force segment event */
if (ebml->cache) {
gst_byte_writer_free (ebml->cache);
@ -182,7 +178,7 @@ gst_ebml_stop_streamheader (GstEbmlWrite * ebml)
buffer = gst_byte_writer_free_and_get_buffer (ebml->streamheader);
ebml->streamheader = NULL;
GST_DEBUG ("Streamheader was size %d", GST_BUFFER_SIZE (buffer));
GST_DEBUG ("Streamheader was size %d", gst_buffer_get_size (buffer));
ebml->writing_streamheader = FALSE;
return buffer;
@ -211,14 +207,19 @@ gst_ebml_write_set_cache (GstEbmlWrite * ebml, guint size)
}
static gboolean
gst_ebml_writer_send_new_segment_event (GstEbmlWrite * ebml, guint64 new_pos)
gst_ebml_writer_send_segment_event (GstEbmlWrite * ebml, guint64 new_pos)
{
GstSegment segment;
gboolean res;
GST_INFO ("seeking to %" G_GUINT64_FORMAT, new_pos);
res = gst_pad_push_event (ebml->srcpad,
gst_event_new_new_segment (FALSE, 1.0, GST_FORMAT_BYTES, new_pos, -1, 0));
gst_segment_init (&segment, GST_FORMAT_BYTES);
segment.start = new_pos;
segment.stop = -1;
segment.position = 0;
res = gst_pad_push_event (ebml->srcpad, gst_event_new_segment (&segment));
if (!res)
GST_WARNING ("seek to %" G_GUINT64_FORMAT "failed", new_pos);
@ -244,14 +245,13 @@ gst_ebml_write_flush_cache (GstEbmlWrite * ebml, gboolean is_keyframe,
buffer = gst_byte_writer_free_and_get_buffer (ebml->cache);
ebml->cache = NULL;
GST_DEBUG ("Flushing cache of size %d", GST_BUFFER_SIZE (buffer));
gst_buffer_set_caps (buffer, ebml->caps);
GST_DEBUG ("Flushing cache of size %d", gst_buffer_get_size (buffer));
GST_BUFFER_TIMESTAMP (buffer) = timestamp;
GST_BUFFER_OFFSET (buffer) = ebml->pos - GST_BUFFER_SIZE (buffer);
GST_BUFFER_OFFSET (buffer) = ebml->pos - gst_buffer_get_size (buffer);
GST_BUFFER_OFFSET_END (buffer) = ebml->pos;
if (ebml->last_write_result == GST_FLOW_OK) {
if (GST_BUFFER_OFFSET (buffer) != ebml->last_pos) {
gst_ebml_writer_send_new_segment_event (ebml, GST_BUFFER_OFFSET (buffer));
gst_ebml_writer_send_segment_event (ebml, GST_BUFFER_OFFSET (buffer));
GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_FLAG_DISCONT);
}
if (ebml->writing_streamheader) {
@ -290,7 +290,7 @@ gst_ebml_write_element_new (GstEbmlWrite * ebml, guint8 ** data_out, guint size)
buf = gst_buffer_new_and_alloc (size);
GST_BUFFER_TIMESTAMP (buf) = ebml->timestamp;
*data_out = GST_BUFFER_DATA (buf);
*data_out = gst_buffer_map (buf, NULL, NULL, GST_MAP_WRITE);
return buf;
}
@ -408,31 +408,33 @@ gst_ebml_write_element_push (GstEbmlWrite * ebml, GstBuffer * buf,
{
guint data_size;
if (!buf_data)
buf_data = GST_BUFFER_DATA (buf);
if (buf_data_end) {
if (buf_data_end)
data_size = buf_data_end - buf_data;
GST_BUFFER_SIZE (buf) = data_size;
} else {
data_size = GST_BUFFER_SIZE (buf);
}
else
data_size = gst_buffer_get_size (buf);
ebml->pos += data_size;
/* if there's no cache, then don't push it! */
if (ebml->writing_streamheader) {
if (!buf_data)
buf_data = gst_buffer_map (buf, NULL, NULL, GST_MAP_WRITE);
gst_byte_writer_put_data (ebml->streamheader, buf_data, data_size);
}
if (ebml->cache) {
if (!buf_data)
buf_data = gst_buffer_map (buf, NULL, NULL, GST_MAP_WRITE);
gst_byte_writer_put_data (ebml->cache, buf_data, data_size);
gst_buffer_unmap (buf, buf_data, -1);
gst_buffer_unref (buf);
return;
}
if (buf_data)
gst_buffer_unmap (buf, buf_data, -1);
if (ebml->last_write_result == GST_FLOW_OK) {
buf = gst_buffer_make_metadata_writable (buf);
gst_buffer_set_caps (buf, ebml->caps);
buf = gst_buffer_make_writable (buf);
GST_BUFFER_OFFSET (buf) = ebml->pos - data_size;
GST_BUFFER_OFFSET_END (buf) = ebml->pos;
if (ebml->writing_streamheader) {
@ -441,7 +443,7 @@ gst_ebml_write_element_push (GstEbmlWrite * ebml, GstBuffer * buf,
GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DELTA_UNIT);
if (GST_BUFFER_OFFSET (buf) != ebml->last_pos) {
gst_ebml_writer_send_new_segment_event (ebml, GST_BUFFER_OFFSET (buf));
gst_ebml_writer_send_segment_event (ebml, GST_BUFFER_OFFSET (buf));
GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DISCONT);
}
ebml->last_pos = ebml->pos;
@ -730,12 +732,12 @@ gst_ebml_write_master_finish_full (GstEbmlWrite * ebml, guint64 startpos,
guint64 extra_size)
{
guint64 pos = ebml->pos;
GstBuffer *buf;
guint8 *data = g_malloc (8);
GstBuffer *buf = gst_buffer_new_wrapped (data, 8);
gst_ebml_write_seek (ebml, startpos);
buf = gst_buffer_new_and_alloc (8);
GST_WRITE_UINT64_BE (GST_BUFFER_DATA (buf),
GST_WRITE_UINT64_BE (data,
(G_GINT64_CONSTANT (1) << 56) | (pos - startpos - 8 + extra_size));
gst_ebml_write_element_push (ebml, buf, NULL, NULL);
@ -835,11 +837,12 @@ void
gst_ebml_replace_uint (GstEbmlWrite * ebml, guint64 pos, guint64 num)
{
guint64 oldpos = ebml->pos;
GstBuffer *buf = gst_buffer_new_and_alloc (8);
guint8 *data_start, *data_end;
GstBuffer *buf;
data_start = GST_BUFFER_DATA (buf);
data_start = g_malloc (8);
data_end = data_start;
buf = gst_buffer_new_wrapped (data_start, 8);
gst_ebml_write_seek (ebml, pos);
gst_ebml_write_set_uint (&data_end, num, 8);

File diff suppressed because it is too large Load diff

View file

@ -87,7 +87,7 @@ typedef struct _GstMatroskaDemux {
gboolean building_index;
guint64 index_offset;
GstEvent *seek_event;
gboolean need_newsegment;
gboolean need_segment;
/* reverse playback */
GArray *seek_index;

View file

@ -486,10 +486,10 @@ struct _GstMatroskaTrackContext {
/* some often-used info */
gchar *codec_id, *codec_name, *name, *language;
guint8 *codec_priv;
guint codec_priv_size;
guint8 *codec_state;
guint codec_state_size;
gpointer codec_priv;
gsize codec_priv_size;
gpointer codec_state;
gsize codec_state_size;
GstMatroskaTrackType type;
guint uid, num;
GstMatroskaTrackFlags flags;

View file

@ -49,6 +49,7 @@
#include <stdio.h>
#include <string.h>
#include <gst/audio/audio.h>
#include <gst/riff/riff-media.h>
#include <gst/tag/tag.h>
@ -126,8 +127,8 @@ static GstStaticPadTemplate videosink_templ =
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)
);
@ -163,32 +164,8 @@ static GstStaticPadTemplate audiosink_templ =
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 }, "
COMMON_AUDIO_CAPS ";"
"audio/x-tta, "
"width = (int) { 8, 16, 24 }, "
@ -213,10 +190,9 @@ GST_STATIC_PAD_TEMPLATE ("subtitle_%u",
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));
/* Matroska muxer destructor */
static void gst_matroska_mux_finalize (GObject * object);
@ -227,9 +203,9 @@ gst_matroska_mux_collected (GstCollectPads * pads, gpointer user_data);
/* 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 */
@ -262,19 +238,6 @@ static void
gst_matroska_mux_write_simple_tag (const GstTagList * list, const gchar * tag,
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)
{
@ -343,12 +306,12 @@ gst_matroska_mux_class_init (GstMatroskaMuxClass * klass)
* 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);
@ -586,7 +549,8 @@ gst_matroska_mux_reset (GstElement * element)
* 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;
@ -600,7 +564,7 @@ gst_matroska_mux_handle_src_event (GstPad * pad, GstEvent * event)
break;
}
return gst_pad_event_default (pad, event);
return gst_pad_event_default (pad, parent, event);
}
/**
@ -613,17 +577,27 @@ gst_matroska_mux_handle_src_event (GstPad * pad, GstEvent * event)
* Returns: #TRUE on success.
*/
static gboolean
gst_matroska_mux_handle_sink_event (GstPad * pad, GstEvent * event)
gst_matroska_mux_handle_sink_event (GstPad * pad, GstObject * parent,
GstEvent * event)
{
GstMatroskaTrackContext *context;
GstMatroskaPad *collect_pad;
GstMatroskaMux *mux;
GstMatroskaMux *mux = GST_MATROSKA_MUX (parent);
GstTagList *list;
gboolean ret = TRUE;
mux = GST_MATROSKA_MUX (gst_pad_get_parent (pad));
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;
@ -658,12 +632,11 @@ gst_matroska_mux_handle_sink_event (GstPad * pad, GstEvent * event)
event = NULL;
break;
}
case GST_EVENT_NEWSEGMENT:{
GstFormat format;
case GST_EVENT_SEGMENT:{
const GstSegment *segment;
gst_event_parse_new_segment (event, NULL, NULL, &format, NULL, NULL,
NULL);
if (format != GST_FORMAT_TIME) {
gst_event_parse_segment (event, &segment);
if (segment->format != GST_FORMAT_TIME) {
ret = FALSE;
gst_event_unref (event);
event = NULL;
@ -687,9 +660,7 @@ gst_matroska_mux_handle_sink_event (GstPad * pad, GstEvent * event)
/* now GstCollectPads can take care of the rest, e.g. EOS */
if (event)
ret = mux->collect_event (pad, event);
gst_object_unref (mux);
ret = mux->collect_event (pad, parent, event);
return ret;
}
@ -714,7 +685,7 @@ gst_matroska_mux_video_pad_setcaps (GstPad * pad, GstCaps * caps)
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;
@ -790,12 +761,17 @@ skip_details:
/* 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;
context->codec_id = g_strdup (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")) {
context->codec_id = g_strdup (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")
@ -848,9 +824,11 @@ skip_details:
}
} 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');
@ -879,11 +857,11 @@ skip_details:
/* 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);
}
context->codec_id = g_strdup (GST_MATROSKA_CODEC_ID_VIDEO_VFW_FOURCC);
@ -900,10 +878,9 @@ skip_details:
/* 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;
@ -946,10 +923,9 @@ skip_details:
/* global headers may be in codec data */
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-msmpeg")) {
msmpeg43:
@ -984,10 +960,10 @@ skip_details:
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);
context->codec_priv = priv_data;
context->codec_priv_size = priv_data_size;
@ -1045,12 +1021,12 @@ xiphN_streamheader_to_codecdata (const GValue * streamheader,
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);
@ -1060,17 +1036,16 @@ xiphN_streamheader_to_codecdata (const GValue * streamheader,
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]);
}
context->codec_priv = priv_data;
@ -1116,17 +1091,19 @@ vorbis_streamheader_to_codecdata (const GValue * streamheader,
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;
guint8 *hdr;
guint8 *data, *hdr;
hdr = GST_BUFFER_DATA (buf0) + 1 + 6 + 4;
data = gst_buffer_map (buf0, NULL, NULL, GST_MAP_READ);
hdr = 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, data, -1);
}
}
@ -1145,16 +1122,17 @@ theora_streamheader_to_codecdata (const GValue * streamheader,
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;
guint8 *hdr;
guint8 *data, *hdr;
hdr = GST_BUFFER_DATA (buf0) + 1 + 6 + 3 + 2 + 2;
data = gst_buffer_map (buf0, NULL, NULL, GST_MAP_READ);
hdr = data + 1 + 6 + 3 + 2 + 2;
videocontext = (GstMatroskaTrackVideoContext *) context;
videocontext->pixel_width = GST_READ_UINT32_BE (hdr) >> 8;
@ -1185,6 +1163,8 @@ theora_streamheader_to_codecdata (const GValue * streamheader,
videocontext->display_height = 0;
}
hdr += 3 + 3;
gst_buffer_unmap (buf0, data, -1);
}
if (buf0)
@ -1202,9 +1182,9 @@ kate_streamheader_to_codecdata (const GValue * streamheader,
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");
}
@ -1245,19 +1225,19 @@ flac_streamheader_to_codecdata (const GValue * streamheader,
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;
}
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) {
@ -1270,13 +1250,13 @@ flac_streamheader_to_codecdata (const GValue * streamheader,
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;
@ -1289,6 +1269,7 @@ speex_streamheader_to_codecdata (const GValue * streamheader,
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");
@ -1311,16 +1292,15 @@ speex_streamheader_to_codecdata (const GValue * streamheader,
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;
}
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);
@ -1334,28 +1314,26 @@ speex_streamheader_to_codecdata (const GValue * streamheader,
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;
}
@ -1401,7 +1379,7 @@ gst_matroska_mux_audio_pad_setcaps (GstPad * pad, GstCaps * caps)
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));
@ -1513,51 +1491,45 @@ gst_matroska_mux_audio_pad_setcaps (GstPad * pad, GstCaps * caps)
default:
goto refuse_caps;
}
} else if (!strcmp (mimetype, "audio/x-raw-int")) {
gint width, depth;
gint endianness = G_LITTLE_ENDIAN;
gboolean signedness = TRUE;
} else if (!strcmp (mimetype, "audio/x-raw")) {
GstAudioInfo info;
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");
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;
}
if (depth > 8 &&
!gst_structure_get_int (structure, "endianness", &endianness)) {
GST_DEBUG_OBJECT (mux, "broken caps, no endianness specified");
goto refuse_caps;
}
if (width != depth) {
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;
}
/* 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)
if (GST_AUDIO_INFO_IS_BIG_ENDIAN (&info))
context->codec_id = g_strdup (GST_MATROSKA_CODEC_ID_AUDIO_PCM_INT_BE);
else
context->codec_id = g_strdup (GST_MATROSKA_CODEC_ID_AUDIO_PCM_INT_LE);
break;
} else if (!strcmp (mimetype, "audio/x-raw-float")) {
gint width;
case GST_AUDIO_FORMAT_F32LE:
case GST_AUDIO_FORMAT_F64LE:
context->codec_id = g_strdup (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");
default:
GST_DEBUG_OBJECT (mux, "wrong format in raw audio caps");
goto refuse_caps;
}
audiocontext->bitdepth = width;
context->codec_id = g_strdup (GST_MATROSKA_CODEC_ID_AUDIO_PCM_FLOAT);
audiocontext->bitdepth = GST_AUDIO_INFO_WIDTH (&info);
} else if (!strcmp (mimetype, "audio/x-vorbis")) {
const GValue *streamheader;
@ -1650,10 +1622,10 @@ gst_matroska_mux_audio_pad_setcaps (GstPad * pad, GstCaps * caps)
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);
context->codec_priv = priv_data;
context->codec_priv_size = priv_data_size;
@ -1717,7 +1689,7 @@ gst_matroska_mux_audio_pad_setcaps (GstPad * pad, GstCaps * caps)
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);
@ -1728,14 +1700,14 @@ gst_matroska_mux_audio_pad_setcaps (GstPad * pad, GstCaps * caps)
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);
}
context->codec_id = g_strdup (GST_MATROSKA_CODEC_ID_AUDIO_ACM);
@ -1839,7 +1811,7 @@ gst_matroska_mux_subtitle_pad_setcaps (GstPad * pad, GstCaps * caps)
*/
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);
@ -1847,7 +1819,7 @@ gst_matroska_mux_request_new_pad (GstElement * element,
GstPad *newpad = NULL;
gchar *name = NULL;
const gchar *pad_name = NULL;
GstPadSetCapsFunction setcapsfunc = NULL;
GstMatroskaCapsFunc capsfunc = NULL;
GstMatroskaTrackContext *context = NULL;
gint pad_id;
@ -1860,7 +1832,7 @@ gst_matroska_mux_request_new_pad (GstElement * element,
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;
@ -1874,7 +1846,7 @@ gst_matroska_mux_request_new_pad (GstElement * element,
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;
@ -1888,7 +1860,7 @@ gst_matroska_mux_request_new_pad (GstElement * element,
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;
@ -1920,7 +1892,7 @@ gst_matroska_mux_request_new_pad (GstElement * element,
gst_pad_set_event_function (newpad,
GST_DEBUG_FUNCPTR (gst_matroska_mux_handle_sink_event));
gst_pad_set_setcaps_function (newpad, setcapsfunc);
collect_pad->capsfunc = capsfunc;
gst_pad_set_active (newpad, TRUE);
if (!gst_element_add_pad (element, newpad))
goto pad_add_failed;
@ -2109,9 +2081,9 @@ gst_matroska_mux_start (GstMatroskaMux * mux)
GTimeVal time = { 0, 0 };
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;
@ -2176,7 +2148,6 @@ gst_matroska_mux_start (GstMatroskaMux * mux)
for (collected = mux->collect->data; collected;
collected = g_slist_next (collected)) {
GstMatroskaPad *collect_pad;
GstFormat format = GST_FORMAT_TIME;
GstPad *thepad;
gint64 trackduration;
@ -2185,7 +2156,7 @@ gst_matroska_mux_start (GstMatroskaMux * mux)
/* 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) {
@ -2503,7 +2474,7 @@ gst_matroska_mux_best_pad (GstMatroskaMux * mux, gboolean * popped)
GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (collect_pad->buffer)),
GST_TIME_ARGS (time));
collect_pad->buffer =
gst_buffer_make_metadata_writable (collect_pad->buffer);
gst_buffer_make_writable (collect_pad->buffer);
GST_BUFFER_TIMESTAMP (collect_pad->buffer) = time;
}
}
@ -2539,15 +2510,16 @@ gst_matroska_mux_create_buffer_header (GstMatroskaTrackContext * track,
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;
}
@ -2562,14 +2534,18 @@ gst_matroska_mux_handle_dirac_packet (GstMatroskaMux * mux,
{
GstMatroskaTrackVideoContext *ctx =
(GstMatroskaTrackVideoContext *) collect_pad->track;
const guint8 *data = GST_BUFFER_DATA (buf);
guint size = GST_BUFFER_SIZE (buf);
guint8 *buf_data, *data;
gsize size;
guint8 parse_code;
guint32 next_parse_offset;
GstBuffer *ret = NULL;
gboolean is_muxing_unit = FALSE;
if (GST_BUFFER_SIZE (buf) < 13) {
buf_data = gst_buffer_map (buf, &size, NULL, GST_MAP_READ);
data = buf_data;
if (size < 13) {
gst_buffer_unmap (buf, buf_data, -1);
gst_buffer_unref (buf);
return ret;
}
@ -2577,6 +2553,7 @@ gst_matroska_mux_handle_dirac_packet (GstMatroskaMux * mux,
/* 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, buf_data, -1);
gst_buffer_unref (buf);
return ret;
}
@ -2607,12 +2584,13 @@ gst_matroska_mux_handle_dirac_packet (GstMatroskaMux * mux,
else
ctx->dirac_unit = gst_buffer_ref (buf);
gst_buffer_unmap (buf, buf_data, -1);
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);
@ -2634,9 +2612,9 @@ gst_matroska_mux_stop_streamheader (GstMatroskaMux * mux)
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);
@ -2836,14 +2814,14 @@ gst_matroska_mux_write_data (GstMatroskaMux * mux, GstMatroskaPad * collect_pad)
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);
@ -2853,9 +2831,10 @@ gst_matroska_mux_write_data (GstMatroskaMux * mux, GstMatroskaPad * collect_pad)
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);

View file

@ -53,10 +53,13 @@ typedef struct _GstMatroskaMetaSeekIndex {
guint64 pos;
} GstMatroskaMetaSeekIndex;
typedef gboolean (*GstMatroskaCapsFunc) (GstPad *pad, GstCaps *caps);
/* all information needed for one matroska stream */
typedef struct
{
GstCollectData collect; /* we extend the CollectData */
GstMatroskaCapsFunc capsfunc;
GstMatroskaTrackContext *track;
GstBuffer *buffer; /* the queued buffer for this pad */

View file

@ -111,16 +111,14 @@ static gboolean gst_matroska_parse_element_query (GstElement * element,
static gboolean gst_matroska_parse_handle_seek_event (GstMatroskaParse * parse,
GstPad * pad, GstEvent * event);
static gboolean gst_matroska_parse_handle_src_event (GstPad * pad,
GstEvent * event);
static const GstQueryType *gst_matroska_parse_get_src_query_types (GstPad *
pad);
GstObject * parent, GstEvent * event);
static gboolean gst_matroska_parse_handle_src_query (GstPad * pad,
GstQuery * query);
GstObject * parent, GstQuery * query);
static gboolean gst_matroska_parse_handle_sink_event (GstPad * pad,
GstEvent * event);
GstObject * parent, GstEvent * event);
static GstFlowReturn gst_matroska_parse_chain (GstPad * pad,
GstBuffer * buffer);
GstObject * parent, GstBuffer * buffer);
static GstStateChangeReturn
gst_matroska_parse_change_state (GstElement * element,
@ -135,24 +133,8 @@ static gboolean perform_seek_to_offset (GstMatroskaParse * parse,
guint64 offset);
GType gst_matroska_parse_get_type (void);
GST_BOILERPLATE (GstMatroskaParse, gst_matroska_parse, GstElement,
GST_TYPE_ELEMENT);
static void
gst_matroska_parse_base_init (gpointer klass)
{
GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
gst_element_class_add_pad_template (element_class,
gst_static_pad_template_get (&src_templ));
gst_element_class_add_pad_template (element_class,
gst_static_pad_template_get (&sink_templ));
gst_element_class_set_details_simple (element_class, "Matroska parser",
"Codec/Parser",
"Parses Matroska/WebM streams into video/audio/subtitles",
"GStreamer maintainers <gstreamer-devel@lists.sourceforge.net>");
}
#define parent_class gst_matroska_parse_parent_class
G_DEFINE_TYPE (GstMatroskaParse, gst_matroska_parse, GST_TYPE_ELEMENT);
static void
gst_matroska_parse_finalize (GObject * object)
@ -196,11 +178,20 @@ gst_matroska_parse_class_init (GstMatroskaParseClass * klass)
GST_DEBUG_FUNCPTR (gst_matroska_parse_set_index);
gstelement_class->get_index =
GST_DEBUG_FUNCPTR (gst_matroska_parse_get_index);
gst_element_class_add_pad_template (gstelement_class,
gst_static_pad_template_get (&src_templ));
gst_element_class_add_pad_template (gstelement_class,
gst_static_pad_template_get (&sink_templ));
gst_element_class_set_details_simple (gstelement_class,
"Matroska parser", "Codec/Parser",
"Parses Matroska/WebM streams into video/audio/subtitles",
"GStreamer maintainers <gstreamer-devel@lists.sourceforge.net>");
}
static void
gst_matroska_parse_init (GstMatroskaParse * parse,
GstMatroskaParseClass * klass)
gst_matroska_parse_init (GstMatroskaParse * parse)
{
parse->common.sinkpad = gst_pad_new_from_static_template (&sink_templ,
"sink");
@ -213,8 +204,6 @@ gst_matroska_parse_init (GstMatroskaParse * parse,
parse->srcpad = gst_pad_new_from_static_template (&src_templ, "src");
gst_pad_set_event_function (parse->srcpad,
GST_DEBUG_FUNCPTR (gst_matroska_parse_handle_src_event));
gst_pad_set_query_type_function (parse->srcpad,
GST_DEBUG_FUNCPTR (gst_matroska_parse_get_src_query_types));
gst_pad_set_query_function (parse->srcpad,
GST_DEBUG_FUNCPTR (gst_matroska_parse_handle_src_query));
gst_pad_use_fixed_caps (parse->srcpad);
@ -374,7 +363,7 @@ gst_matroska_parse_reset (GstElement * element)
if (parse->common.global_tags) {
gst_tag_list_free (parse->common.global_tags);
}
parse->common.global_tags = gst_tag_list_new ();
parse->common.global_tags = gst_tag_list_new_empty ();
if (parse->common.cached_buffer) {
gst_buffer_unref (parse->common.cached_buffer);
@ -1078,19 +1067,6 @@ gst_matroska_parse_add_stream (GstMatroskaParse * parse, GstEbmlRead * ebml)
return ret;
}
static const GstQueryType *
gst_matroska_parse_get_src_query_types (GstPad * pad)
{
static const GstQueryType query_types[] = {
GST_QUERY_POSITION,
GST_QUERY_DURATION,
GST_QUERY_SEEKING,
0
};
return query_types;
}
static gboolean
gst_matroska_parse_query (GstMatroskaParse * parse, GstPad * pad,
GstQuery * query)
@ -1115,7 +1091,7 @@ gst_matroska_parse_query (GstMatroskaParse * parse, GstPad * pad,
gst_query_set_position (query, GST_FORMAT_TIME, context->pos);
else
gst_query_set_position (query, GST_FORMAT_TIME,
parse->common.segment.last_stop);
parse->common.segment.position);
GST_OBJECT_UNLOCK (parse);
} else if (format == GST_FORMAT_DEFAULT && context
&& context->default_duration) {
@ -1175,7 +1151,7 @@ gst_matroska_parse_query (GstMatroskaParse * parse, GstPad * pad,
break;
}
default:
res = gst_pad_query_default (pad, query);
res = gst_pad_query_default (pad, (GstObject *) parse, query);
break;
}
@ -1189,15 +1165,14 @@ gst_matroska_parse_element_query (GstElement * element, GstQuery * query)
}
static gboolean
gst_matroska_parse_handle_src_query (GstPad * pad, GstQuery * query)
gst_matroska_parse_handle_src_query (GstPad * pad, GstObject * parent,
GstQuery * query)
{
gboolean ret;
GstMatroskaParse *parse = GST_MATROSKA_PARSE (gst_pad_get_parent (pad));
GstMatroskaParse *parse = GST_MATROSKA_PARSE (parent);
ret = gst_matroska_parse_query (parse, pad, query);
gst_object_unref (parse);
return ret;
}
@ -1248,6 +1223,8 @@ gst_matroska_parse_search_cluster (GstMatroskaParse * parse, gint64 * pos)
GstFlowReturn ret = GST_FLOW_OK;
const guint chunk = 64 * 1024;
GstBuffer *buf = NULL;
gpointer data;
gsize size;
guint64 length;
guint32 id;
guint needed;
@ -1263,13 +1240,13 @@ gst_matroska_parse_search_cluster (GstMatroskaParse * parse, gint64 * pos)
if (ret != GST_FLOW_OK)
break;
GST_DEBUG_OBJECT (parse, "read buffer size %d at offset %" G_GINT64_FORMAT,
GST_BUFFER_SIZE (buf), newpos);
gst_byte_reader_init_from_buffer (&reader, buf);
gst_buffer_get_size (buf), newpos);
data = gst_buffer_map (buf, &size, NULL, GST_MAP_READ);
gst_byte_reader_init (&reader, data, size);
cluster_pos = 0;
resume:
cluster_pos = gst_byte_reader_masked_scan_uint32 (&reader, 0xffffffff,
GST_MATROSKA_ID_CLUSTER, cluster_pos,
GST_BUFFER_SIZE (buf) - cluster_pos);
GST_MATROSKA_ID_CLUSTER, cluster_pos, size - cluster_pos);
if (cluster_pos >= 0) {
newpos += cluster_pos;
GST_DEBUG_OBJECT (parse,
@ -1311,13 +1288,15 @@ gst_matroska_parse_search_cluster (GstMatroskaParse * parse, gint64 * pos)
goto resume;
} else {
/* partial cluster id may have been in tail of buffer */
newpos += MAX (GST_BUFFER_SIZE (buf), 4) - 3;
newpos += MAX (size, 4) - 3;
gst_buffer_unmap (buf, data, size);
gst_buffer_unref (buf);
buf = NULL;
}
}
if (buf) {
gst_buffer_unmap (buf, data, size);
gst_buffer_unref (buf);
buf = NULL;
}
@ -1362,7 +1341,7 @@ gst_matroska_parse_handle_seek_event (GstMatroskaParse * parse,
if (event) {
GST_DEBUG_OBJECT (parse, "configuring seek");
gst_segment_set_seek (&seeksegment, rate, format, flags,
gst_segment_do_seek (&seeksegment, rate, format, flags,
cur_type, cur, stop_type, stop, &update);
}
@ -1371,7 +1350,7 @@ gst_matroska_parse_handle_seek_event (GstMatroskaParse * parse,
/* check sanity before we start flushing and all that */
GST_OBJECT_LOCK (parse);
if ((entry = gst_matroska_read_common_do_index_seek (&parse->common, track,
seeksegment.last_stop, &parse->seek_index, &parse->seek_entry)) ==
seeksegment.position, &parse->seek_index, &parse->seek_entry)) ==
NULL) {
/* pull mode without index can scan later on */
GST_DEBUG_OBJECT (parse, "No matching seek entry in index");
@ -1473,9 +1452,10 @@ gst_matroska_parse_handle_seek_push (GstMatroskaParse * parse, GstPad * pad,
}
static gboolean
gst_matroska_parse_handle_src_event (GstPad * pad, GstEvent * event)
gst_matroska_parse_handle_src_event (GstPad * pad, GstObject * parent,
GstEvent * event)
{
GstMatroskaParse *parse = GST_MATROSKA_PARSE (gst_pad_get_parent (pad));
GstMatroskaParse *parse = GST_MATROSKA_PARSE (parent);
gboolean res = TRUE;
switch (GST_EVENT_TYPE (event)) {
@ -1499,7 +1479,7 @@ gst_matroska_parse_handle_src_event (GstPad * pad, GstEvent * event)
GstClockTimeDiff diff;
GstClockTime timestamp;
gst_event_parse_qos (event, &proportion, &diff, &timestamp);
gst_event_parse_qos (event, NULL, &proportion, &diff, &timestamp);
GST_OBJECT_LOCK (parse);
videocontext->earliest_time = timestamp + diff;
@ -1522,8 +1502,6 @@ gst_matroska_parse_handle_src_event (GstPad * pad, GstEvent * event)
break;
}
gst_object_unref (parse);
return res;
}
@ -1635,6 +1613,8 @@ gst_matroska_parse_parse_blockgroup_or_simpleblock (GstMatroskaParse * parse,
guint32 id;
guint64 block_duration = 0;
GstBuffer *buf = NULL;
gpointer buf_data = NULL;
gsize buf_size = 0;
gint stream_num = -1, n, laces = 0;
guint size = 0;
gint *lace_size = NULL;
@ -1668,8 +1648,10 @@ gst_matroska_parse_parse_blockgroup_or_simpleblock (GstMatroskaParse * parse,
if ((ret = gst_ebml_read_buffer (ebml, &id, &buf)) != GST_FLOW_OK)
break;
data = GST_BUFFER_DATA (buf);
size = GST_BUFFER_SIZE (buf);
buf_data = gst_buffer_map (buf, &buf_size, NULL, GST_MAP_READ);
data = buf_data;
size = buf_size;
/* first byte(s): blocknum */
if ((n = gst_matroska_ebmlnum_uint (data, size, &num)) < 0)
@ -1873,18 +1855,18 @@ gst_matroska_parse_parse_blockgroup_or_simpleblock (GstMatroskaParse * parse,
}
/* need to refresh segment info ASAP */
if (GST_CLOCK_TIME_IS_VALID (lace_time) && parse->need_newsegment) {
GstSegment segment;
GST_DEBUG_OBJECT (parse,
"generating segment starting at %" GST_TIME_FORMAT,
GST_TIME_ARGS (lace_time));
/* pretend we seeked here */
gst_segment_set_seek (&parse->common.segment, parse->common.segment.rate,
gst_segment_do_seek (&parse->common.segment, parse->common.segment.rate,
GST_FORMAT_TIME, 0, GST_SEEK_TYPE_SET, lace_time,
GST_SEEK_TYPE_SET, GST_CLOCK_TIME_NONE, NULL);
/* now convey our segment notion downstream */
gst_matroska_parse_send_event (parse, gst_event_new_new_segment (FALSE,
parse->common.segment.rate, parse->common.segment.format,
parse->common.segment.start, parse->common.segment.stop,
parse->common.segment.start));
segment = parse->common.segment;
segment.position = segment.start;
gst_matroska_parse_send_event (parse, gst_event_new_segment (&segment));
parse->need_newsegment = FALSE;
}
@ -2134,8 +2116,10 @@ gst_matroska_parse_parse_blockgroup_or_simpleblock (GstMatroskaParse * parse,
}
done:
if (buf)
if (buf) {
gst_buffer_unmap (buf, buf_data, buf_size);
gst_buffer_unref (buf);
}
g_free (lace_size);
return ret;
@ -2419,10 +2403,9 @@ gst_matroska_parse_check_seekability (GstMatroskaParse * parse)
/* try harder to query upstream size if we didn't get it the first time */
if (seekable && stop == -1) {
GstFormat fmt = GST_FORMAT_BYTES;
GST_DEBUG_OBJECT (parse, "doing duration query to fix up unset stop");
gst_pad_query_peer_duration (parse->common.sinkpad, &fmt, &stop);
gst_pad_peer_query_duration (parse->common.sinkpad, GST_FORMAT_BYTES,
&stop);
}
/* if upstream doesn't know the size, it's likely that it's not seekable in
@ -2506,14 +2489,15 @@ gst_matroska_parse_accumulate_streamheader (GstMatroskaParse * parse,
GstBuffer *buf;
buf = gst_buffer_span (parse->streamheader, 0, buffer,
GST_BUFFER_SIZE (parse->streamheader) + GST_BUFFER_SIZE (buffer));
gst_buffer_get_size (parse->streamheader) +
gst_buffer_get_size (buffer));
gst_buffer_unref (parse->streamheader);
parse->streamheader = buf;
} else {
parse->streamheader = gst_buffer_ref (buffer);
}
GST_DEBUG ("%d", GST_BUFFER_SIZE (parse->streamheader));
GST_DEBUG ("%d", gst_buffer_get_size (parse->streamheader));
}
static GstFlowReturn
@ -2529,7 +2513,7 @@ gst_matroska_parse_output (GstMatroskaParse * parse, GstBuffer * buffer,
GValue bufval = { 0 };
GstBuffer *buf;
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);
@ -2545,7 +2529,6 @@ gst_matroska_parse_output (GstMatroskaParse * parse, GstBuffer * buffer,
gst_pad_set_caps (parse->srcpad, caps);
buf = gst_buffer_copy (parse->streamheader);
gst_buffer_set_caps (buf, caps);
gst_caps_unref (caps);
GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DISCONT);
@ -2567,7 +2550,6 @@ gst_matroska_parse_output (GstMatroskaParse * parse, GstBuffer * buffer,
} else {
GST_BUFFER_TIMESTAMP (buffer) = parse->last_timestamp;
}
gst_buffer_set_caps (buffer, GST_PAD_CAPS (parse->srcpad));
ret = gst_pad_push (parse->srcpad, gst_buffer_ref (buffer));
return ret;
@ -3028,9 +3010,9 @@ perform_seek_to_offset (GstMatroskaParse * parse, guint64 offset)
}
static GstFlowReturn
gst_matroska_parse_chain (GstPad * pad, GstBuffer * buffer)
gst_matroska_parse_chain (GstPad * pad, GstObject * parent, GstBuffer * buffer)
{
GstMatroskaParse *parse = GST_MATROSKA_PARSE (GST_PAD_PARENT (pad));
GstMatroskaParse *parse = GST_MATROSKA_PARSE (parent);
guint available;
GstFlowReturn ret = GST_FLOW_OK;
guint needed = 0;
@ -3075,7 +3057,8 @@ next:
}
static gboolean
gst_matroska_parse_handle_sink_event (GstPad * pad, GstEvent * event)
gst_matroska_parse_handle_sink_event (GstPad * pad, GstObject * parent,
GstEvent * event)
{
gboolean res = TRUE;
GstMatroskaParse *parse = GST_MATROSKA_PARSE (GST_PAD_PARENT (pad));
@ -3084,23 +3067,15 @@ gst_matroska_parse_handle_sink_event (GstPad * pad, GstEvent * event)
"have event type %s: %p on sink pad", GST_EVENT_TYPE_NAME (event), event);
switch (GST_EVENT_TYPE (event)) {
case GST_EVENT_NEWSEGMENT:
case GST_EVENT_SEGMENT:
{
GstFormat format;
gdouble rate, arate;
gint64 start, stop, time = 0;
gboolean update;
GstSegment segment;
const GstSegment *segment;
/* some debug output */
gst_segment_init (&segment, GST_FORMAT_UNDEFINED);
gst_event_parse_new_segment_full (event, &update, &rate, &arate, &format,
&start, &stop, &time);
gst_segment_set_newsegment_full (&segment, update, rate, arate, format,
start, stop, time);
gst_event_parse_segment (event, &segment);
GST_DEBUG_OBJECT (parse,
"received format %d newsegment %" GST_SEGMENT_FORMAT, format,
&segment);
"received format %d newsegment %" GST_SEGMENT_FORMAT,
segment->format, segment);
if (parse->common.state < GST_MATROSKA_READ_STATE_DATA) {
GST_DEBUG_OBJECT (parse, "still starting");
@ -3108,7 +3083,7 @@ gst_matroska_parse_handle_sink_event (GstPad * pad, GstEvent * event)
}
/* we only expect a BYTE segment, e.g. following a seek */
if (format != GST_FORMAT_BYTES) {
if (segment->format != GST_FORMAT_BYTES) {
GST_DEBUG_OBJECT (parse, "unsupported segment format, ignoring");
goto exit;
}
@ -3117,15 +3092,15 @@ gst_matroska_parse_handle_sink_event (GstPad * pad, GstEvent * event)
/* clear current segment leftover */
gst_adapter_clear (parse->common.adapter);
/* and some streaming setup */
parse->common.offset = start;
parse->common.offset = segment->start;
/* do not know where we are;
* need to come across a cluster and generate newsegment */
parse->common.segment.last_stop = GST_CLOCK_TIME_NONE;
parse->common.segment.position = GST_CLOCK_TIME_NONE;
parse->cluster_time = GST_CLOCK_TIME_NONE;
parse->cluster_offset = 0;
parse->need_newsegment = TRUE;
/* but keep some of the upstream segment */
parse->common.segment.rate = rate;
parse->common.segment.rate = segment->rate;
exit:
/* chain will send initial newsegment after pads have been added,
* or otherwise come up with one */
@ -3155,13 +3130,13 @@ gst_matroska_parse_handle_sink_event (GstPad * pad, GstEvent * event)
gst_matroska_read_common_reset_streams (&parse->common,
GST_CLOCK_TIME_NONE, TRUE);
GST_OBJECT_UNLOCK (parse);
parse->common.segment.last_stop = GST_CLOCK_TIME_NONE;
parse->common.segment.position = GST_CLOCK_TIME_NONE;
parse->cluster_time = GST_CLOCK_TIME_NONE;
parse->cluster_offset = 0;
/* fall-through */
}
default:
res = gst_pad_event_default (pad, event);
res = gst_pad_event_default (pad, parent, event);
break;
}

View file

@ -58,7 +58,7 @@ GST_DEBUG_CATEGORY (matroskareadcommon_debug);
static gboolean
gst_matroska_decompress_data (GstMatroskaTrackEncoding * enc,
guint8 ** data_out, guint * size_out,
gpointer * data_out, gsize * size_out,
GstMatroskaTrackCompressionAlgorithm algo)
{
guint8 *new_data = NULL;
@ -237,8 +237,8 @@ gst_matroska_decode_content_encodings (GArray * encodings)
for (i = 0; i < encodings->len; i++) {
GstMatroskaTrackEncoding *enc =
&g_array_index (encodings, GstMatroskaTrackEncoding, i);
guint8 *data = NULL;
guint size;
gpointer data = NULL;
gsize size;
if ((enc->scope & GST_MATROSKA_TRACK_ENCODING_SCOPE_NEXT_CONTENT_ENCODING)
== 0)
@ -270,11 +270,11 @@ gst_matroska_decode_content_encodings (GArray * encodings)
}
gboolean
gst_matroska_decode_data (GArray * encodings, guint8 ** data_out,
guint * size_out, GstMatroskaTrackEncodingScope scope, gboolean free)
gst_matroska_decode_data (GArray * encodings, gpointer * data_out,
gsize * size_out, GstMatroskaTrackEncodingScope scope, gboolean free)
{
guint8 *data;
guint size;
gpointer data;
gsize size;
gboolean ret = TRUE;
gint i;
@ -288,8 +288,8 @@ gst_matroska_decode_data (GArray * encodings, guint8 ** data_out,
for (i = 0; i < encodings->len; i++) {
GstMatroskaTrackEncoding *enc =
&g_array_index (encodings, GstMatroskaTrackEncoding, i);
guint8 *new_data = NULL;
guint new_size = 0;
gpointer new_data = NULL;
gsize new_size = 0;
if ((enc->scope & scope) == 0)
continue;
@ -430,21 +430,31 @@ gst_matroska_read_common_found_global_tag (GstMatroskaReadCommon * common,
gst_tag_list_insert (common->global_tags, taglist, GST_TAG_MERGE_APPEND);
gst_tag_list_free (taglist);
} else {
GstEvent *tag_event = gst_event_new_tag (taglist);
gint i;
/* hm, already sent, no need to cache and wait anymore */
GST_DEBUG_OBJECT (common, "Sending late global tags %" GST_PTR_FORMAT,
taglist);
gst_element_found_tags (el, taglist);
for (i = 0; i < common->src->len; i++) {
GstMatroskaTrackContext *stream;
stream = g_ptr_array_index (common->src, i);
gst_pad_push_event (stream->pad, gst_event_ref (tag_event));
}
gst_event_unref (tag_event);
}
}
gint64
gst_matroska_read_common_get_length (GstMatroskaReadCommon * common)
{
GstFormat fmt = GST_FORMAT_BYTES;
gint64 end = -1;
if (!gst_pad_query_peer_duration (common->sinkpad, &fmt, &end) ||
fmt != GST_FORMAT_BYTES || end < 0)
if (!gst_pad_peer_query_duration (common->sinkpad, GST_FORMAT_BYTES,
&end) || end < 0)
GST_DEBUG_OBJECT (common, "no upstream length");
return end;
@ -569,7 +579,7 @@ gst_matroska_read_common_parse_attached_file (GstMatroskaReadCommon * common,
if (filename && mimetype && data && datalen > 0) {
GstTagImageType image_type = GST_TAG_IMAGE_TYPE_NONE;
GstBuffer *tagbuffer = NULL;
GstCaps *caps;
/* GstCaps *caps; */
gchar *filename_lc = g_utf8_strdown (filename, -1);
GST_DEBUG_OBJECT (common, "Creating tag for attachment with "
@ -600,31 +610,32 @@ gst_matroska_read_common_parse_attached_file (GstMatroskaReadCommon * common,
if (!tagbuffer)
image_type = GST_TAG_IMAGE_TYPE_NONE;
else
data = NULL;
}
/* if this failed create an attachment buffer */
if (!tagbuffer) {
tagbuffer = gst_buffer_new_and_alloc (datalen);
tagbuffer = gst_buffer_new_wrapped (g_memdup (data, datalen), datalen);
memcpy (GST_BUFFER_DATA (tagbuffer), data, datalen);
GST_BUFFER_SIZE (tagbuffer) = datalen;
caps = gst_type_find_helper_for_buffer (NULL, tagbuffer, NULL);
if (caps == NULL)
caps = gst_caps_new_simple (mimetype, NULL);
gst_buffer_set_caps (tagbuffer, caps);
gst_caps_unref (caps);
/* FIXME: We can't attach caps to buffers in 0.11. */
/* caps = gst_type_find_helper_for_buffer (NULL, tagbuffer, NULL); */
/* if (caps == NULL) */
/* caps = gst_caps_new_simple (mimetype, NULL); */
/* gst_buffer_set_caps (tagbuffer, caps); */
/* gst_caps_unref (caps); */
}
/* FIXME: We can't attach caps to buffers in 0.11. */
/* Set filename and description on the caps */
caps = GST_BUFFER_CAPS (tagbuffer);
gst_caps_set_simple (caps, "filename", G_TYPE_STRING, filename, NULL);
if (description)
gst_caps_set_simple (caps, "description", G_TYPE_STRING, description,
NULL);
/* caps = GST_BUFFER_CAPS (tagbuffer); */
/* gst_caps_set_simple (caps, "filename", G_TYPE_STRING, filename, NULL); */
/* if (description) */
/* gst_caps_set_simple (caps, "description", G_TYPE_STRING, description, */
/* NULL); */
GST_DEBUG_OBJECT (common,
"Created attachment buffer with caps: %" GST_PTR_FORMAT, caps);
/* GST_DEBUG_OBJECT (common, */
/* "Created attachment buffer with caps: %" GST_PTR_FORMAT, caps); */
/* and append to the tag list */
if (image_type != GST_TAG_IMAGE_TYPE_NONE)
@ -658,7 +669,7 @@ gst_matroska_read_common_parse_attachments (GstMatroskaReadCommon * common,
return ret;
}
taglist = gst_tag_list_new ();
taglist = gst_tag_list_new_empty ();
while (ret == GST_FLOW_OK && gst_ebml_read_has_remaining (ebml, 1, TRUE)) {
if ((ret = gst_ebml_peek_id (ebml, &id)) != GST_FLOW_OK)
@ -1280,9 +1291,7 @@ gst_matroska_read_common_parse_info (GstMatroskaReadCommon * common,
break;
GST_DEBUG_OBJECT (common, "Title: %s", GST_STR_NULL (text));
taglist = gst_tag_list_new ();
gst_tag_list_add (taglist, GST_TAG_MERGE_APPEND, GST_TAG_TITLE, text,
NULL);
taglist = gst_tag_list_new (GST_TAG_TITLE, text, NULL);
gst_matroska_read_common_found_global_tag (common, el, taglist);
g_free (text);
break;
@ -1313,7 +1322,7 @@ gst_matroska_read_common_parse_info (GstMatroskaReadCommon * common,
dur_u = gst_gdouble_to_guint64 (dur_f *
gst_guint64_to_gdouble (common->time_scale));
if (GST_CLOCK_TIME_IS_VALID (dur_u) && dur_u <= G_MAXINT64)
gst_segment_set_duration (&common->segment, GST_FORMAT_TIME, dur_u);
common->segment.duration = dur_u;
}
DEBUG_ELEMENT_STOP (common, ebml, "SegmentInfo", ret);
@ -1518,7 +1527,7 @@ gst_matroska_read_common_parse_metadata (GstMatroskaReadCommon * common,
return ret;
}
taglist = gst_tag_list_new ();
taglist = gst_tag_list_new_empty ();
while (ret == GST_FLOW_OK && gst_ebml_read_has_remaining (ebml, 1, TRUE)) {
if ((ret = gst_ebml_peek_id (ebml, &id)) != GST_FLOW_OK)
@ -1551,7 +1560,8 @@ static GstFlowReturn
gst_matroska_read_common_peek_adapter (GstMatroskaReadCommon * common, guint
peek, const guint8 ** data)
{
*data = gst_adapter_peek (common->adapter, peek);
/* Caller needs to gst_adapter_unmap. */
*data = gst_adapter_map (common->adapter, peek);
if (*data == NULL)
return GST_FLOW_UNEXPECTED;
@ -1571,19 +1581,26 @@ gst_matroska_read_common_peek_bytes (GstMatroskaReadCommon * common, guint64
* We do it mainly to avoid pulling buffers of 1 byte all the time */
if (common->cached_buffer) {
guint64 cache_offset = GST_BUFFER_OFFSET (common->cached_buffer);
guint cache_size = GST_BUFFER_SIZE (common->cached_buffer);
gsize cache_size = gst_buffer_get_size (common->cached_buffer);
if (cache_offset <= common->offset &&
(common->offset + size) <= (cache_offset + cache_size)) {
if (p_buf)
*p_buf = gst_buffer_create_sub (common->cached_buffer,
common->offset - cache_offset, size);
if (bytes)
*bytes = GST_BUFFER_DATA (common->cached_buffer) + common->offset -
cache_offset;
*p_buf = gst_buffer_copy_region (common->cached_buffer,
GST_BUFFER_COPY_ALL, common->offset - cache_offset, size);
if (bytes) {
if (!common->cached_data)
common->cached_data = gst_buffer_map (common->cached_buffer,
NULL, NULL, GST_MAP_READ);
*bytes = common->cached_data + common->offset - cache_offset;
}
return GST_FLOW_OK;
}
/* not enough data in the cache, free cache and get a new one */
if (common->cached_data) {
gst_buffer_unmap (common->cached_buffer, common->cached_data, -1);
common->cached_data = NULL;
}
gst_buffer_unref (common->cached_buffer);
common->cached_buffer = NULL;
}
@ -1596,11 +1613,15 @@ gst_matroska_read_common_peek_bytes (GstMatroskaReadCommon * common, guint64
return ret;
}
if (GST_BUFFER_SIZE (common->cached_buffer) >= size) {
if (gst_buffer_get_size (common->cached_buffer) >= size) {
if (p_buf)
*p_buf = gst_buffer_create_sub (common->cached_buffer, 0, size);
if (bytes)
*bytes = GST_BUFFER_DATA (common->cached_buffer);
*p_buf = gst_buffer_copy_region (common->cached_buffer,
GST_BUFFER_COPY_ALL, 0, size);
if (bytes) {
common->cached_data = gst_buffer_map (common->cached_buffer,
NULL, NULL, GST_MAP_READ);
*bytes = common->cached_data;
}
return GST_FLOW_OK;
}
@ -1621,10 +1642,10 @@ gst_matroska_read_common_peek_bytes (GstMatroskaReadCommon * common, guint64
return ret;
}
if (GST_BUFFER_SIZE (common->cached_buffer) < size) {
if (gst_buffer_get_size (common->cached_buffer) < size) {
GST_WARNING_OBJECT (common, "Dropping short buffer at offset %"
G_GUINT64_FORMAT ": wanted %u bytes, got %u bytes", common->offset,
size, GST_BUFFER_SIZE (common->cached_buffer));
size, gst_buffer_get_size (common->cached_buffer));
gst_buffer_unref (common->cached_buffer);
common->cached_buffer = NULL;
@ -1636,9 +1657,13 @@ gst_matroska_read_common_peek_bytes (GstMatroskaReadCommon * common, guint64
}
if (p_buf)
*p_buf = gst_buffer_create_sub (common->cached_buffer, 0, size);
if (bytes)
*bytes = GST_BUFFER_DATA (common->cached_buffer);
*p_buf = gst_buffer_copy_region (common->cached_buffer,
GST_BUFFER_COPY_ALL, 0, size);
if (bytes) {
common->cached_data = gst_buffer_map (common->cached_buffer,
NULL, NULL, GST_MAP_READ);
*bytes = common->cached_data;
}
return GST_FLOW_OK;
}
@ -1664,9 +1689,15 @@ GstFlowReturn
gst_matroska_read_common_peek_id_length_push (GstMatroskaReadCommon * common,
GstElement * el, guint32 * _id, guint64 * _length, guint * _needed)
{
return gst_ebml_peek_id_length (_id, _length, _needed,
GstFlowReturn ret;
ret = gst_ebml_peek_id_length (_id, _length, _needed,
(GstPeekData) gst_matroska_read_common_peek_adapter, (gpointer) common,
el, common->offset);
gst_adapter_unmap (common->adapter);
return ret;
}
static GstFlowReturn

View file

@ -81,6 +81,7 @@ typedef struct _GstMatroskaReadCommon {
/* pull mode caching */
GstBuffer *cached_buffer;
guint8 *cached_data;
/* push and pull mode */
guint64 offset;
@ -90,8 +91,8 @@ typedef struct _GstMatroskaReadCommon {
} GstMatroskaReadCommon;
GstFlowReturn gst_matroska_decode_content_encodings (GArray * encodings);
gboolean gst_matroska_decode_data (GArray * encodings, guint8 ** data_out,
guint * size_out, GstMatroskaTrackEncodingScope scope, gboolean free);
gboolean gst_matroska_decode_data (GArray * encodings, gpointer * data_out,
gsize * size_out, GstMatroskaTrackEncodingScope scope, gboolean free);
gint gst_matroska_index_seek_find (GstMatroskaIndex * i1, GstClockTime * time,
gpointer user_data);
GstMatroskaIndex * gst_matroska_read_common_do_index_seek (

View file

@ -32,8 +32,8 @@
* ]| This pipeline re-encodes a video file of any format into a WebM file.
* |[
* gst-launch-0.10 webmmux name=mux ! filesink location=test.webm \
* videotestsrc num-buffers=250 ! video/x-raw-yuv,framerate=25/1 ! ffmpegcolorspace ! vp8enc ! queue ! mux.video_0 \
* audiotestsrc samplesperbuffer=44100 num-buffers=10 ! audio/x-raw-float,rate=44100 ! vorbisenc ! queue ! mux.audio_0
* videotestsrc num-buffers=250 ! video/x-raw,framerate=25/1 ! ffmpegcolorspace ! vp8enc ! queue ! mux.video_0 \
* audiotestsrc samplesperbuffer=44100 num-buffers=10 ! audio/x-raw,rate=44100 ! vorbisenc ! queue ! mux.audio_0
* ]| This pipeline muxes a test video and a sine wave into a WebM file.
* </refsect2>
*/
@ -53,8 +53,7 @@
"channels = (int) [ 1, MAX ], " \
"rate = (int) [ 1, MAX ]"
GST_BOILERPLATE (GstWebMMux, gst_webm_mux, GstMatroskaMux,
GST_TYPE_MATROSKA_MUX);
G_DEFINE_TYPE (GstWebMMux, gst_webm_mux, GST_TYPE_MATROSKA_MUX);
static GstStaticPadTemplate webm_src_templ = GST_STATIC_PAD_TEMPLATE ("src",
GST_PAD_SRC,
@ -76,11 +75,6 @@ GST_STATIC_PAD_TEMPLATE ("audio_%u",
GST_STATIC_CAPS ("audio/x-vorbis, " COMMON_AUDIO_CAPS)
);
static void
gst_webm_mux_base_init (gpointer g_class)
{
}
static void
gst_webm_mux_class_init (GstWebMMuxClass * klass)
{
@ -99,7 +93,7 @@ gst_webm_mux_class_init (GstWebMMuxClass * klass)
}
static void
gst_webm_mux_init (GstWebMMux * mux, GstWebMMuxClass * g_class)
gst_webm_mux_init (GstWebMMux * mux)
{
GST_MATROSKA_MUX (mux)->doctype = GST_MATROSKA_DOCTYPE_WEBM;
}

View file

@ -163,6 +163,7 @@ static GstElement *
setup_matroskamux (GstStaticPadTemplate * srctemplate)
{
GstElement *matroskamux;
GstSegment segment;
GST_DEBUG ("setup_matroskamux");
matroskamux = gst_check_setup_element ("matroskamux");
@ -170,6 +171,14 @@ setup_matroskamux (GstStaticPadTemplate * srctemplate)
mysrcpad = setup_src_pad (matroskamux, srctemplate, NULL);
mysinkpad = setup_sink_pad (matroskamux, &sinktemplate, NULL);
fail_unless (gst_element_set_state (matroskamux,
GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS,
"could not set to playing");
gst_segment_init (&segment, GST_FORMAT_TIME);
fail_unless (gst_pad_push_event (mysrcpad,
gst_event_new_segment (&segment)), "Segment event rejected");
return matroskamux;
}
@ -187,8 +196,8 @@ cleanup_matroskamux (GstElement * matroskamux)
static void
check_buffer_data (GstBuffer * buffer, void *data, size_t data_size)
{
fail_unless (GST_BUFFER_SIZE (buffer) == data_size);
fail_unless (memcmp (data, GST_BUFFER_DATA (buffer), data_size) == 0);
fail_unless (gst_buffer_get_size (buffer) == data_size);
fail_unless (gst_buffer_memcmp (buffer, 0, data, data_size) == 0);
}
GST_START_TEST (test_ebml_header)
@ -207,11 +216,8 @@ GST_START_TEST (test_ebml_header)
};
matroskamux = setup_matroskamux (&srcac3template);
fail_unless (gst_element_set_state (matroskamux,
GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS,
"could not set to playing");
inbuffer = gst_buffer_new_and_alloc (1);
inbuffer = gst_buffer_new_allocate (NULL, 1, 0);
ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
fail_unless (gst_pad_push (mysrcpad, inbuffer) == GST_FLOW_OK);
num_buffers = g_list_length (buffers);
@ -259,14 +265,12 @@ GST_START_TEST (test_vorbis_header)
};
matroskamux = setup_matroskamux (&srcvorbistemplate);
fail_unless (gst_element_set_state (matroskamux,
GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS,
"could not set to playing");
inbuffer = gst_buffer_new_and_alloc (1);
caps = gst_caps_from_string (VORBIS_CAPS_STRING);
gst_buffer_set_caps (inbuffer, caps);
fail_unless (gst_pad_set_caps (mysrcpad, caps));
gst_caps_unref (caps);
inbuffer = gst_buffer_new_allocate (NULL, 1, 0);
ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
fail_unless (gst_pad_push (mysrcpad, inbuffer) == GST_FLOW_OK);
@ -274,14 +278,16 @@ GST_START_TEST (test_vorbis_header)
for (i = 0; i < num_buffers; ++i) {
gint j;
gsize buffer_size;
outbuffer = GST_BUFFER (buffers->data);
fail_if (outbuffer == NULL);
buffer_size = gst_buffer_get_size (outbuffer);
buffers = g_list_remove (buffers, outbuffer);
if (!vorbis_header_found && GST_BUFFER_SIZE (outbuffer) >= sizeof (data)) {
for (j = 0; j <= GST_BUFFER_SIZE (outbuffer) - sizeof (data); j++) {
if (memcmp (GST_BUFFER_DATA (outbuffer) + j, data, sizeof (data)) == 0) {
if (!vorbis_header_found && buffer_size >= sizeof (data)) {
for (j = 0; j <= buffer_size - sizeof (data); j++) {
if (gst_buffer_memcmp (outbuffer, j, data, sizeof (data)) == 0) {
vorbis_header_found = TRUE;
break;
}
@ -307,6 +313,7 @@ GST_START_TEST (test_block_group)
{
GstElement *matroskamux;
GstBuffer *inbuffer, *outbuffer;
guint8 *indata;
GstCaps *caps;
int num_buffers;
int i;
@ -317,16 +324,14 @@ GST_START_TEST (test_block_group)
guint8 data1[] = { 0x42 };
matroskamux = setup_matroskamux (&srcac3template);
fail_unless (gst_element_set_state (matroskamux,
GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS,
"could not set to playing");
caps = gst_caps_from_string (AC3_CAPS_STRING);
fail_unless (gst_pad_set_caps (mysrcpad, caps));
gst_caps_unref (caps);
/* Generate the header */
inbuffer = gst_buffer_new_and_alloc (1);
inbuffer = gst_buffer_new_allocate (NULL, 1, 0);
GST_BUFFER_TIMESTAMP (inbuffer) = 0;
caps = gst_caps_from_string (AC3_CAPS_STRING);
gst_buffer_set_caps (inbuffer, caps);
gst_caps_unref (caps);
ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
fail_unless_equals_int (gst_pad_push (mysrcpad, inbuffer), GST_FLOW_OK);
@ -346,12 +351,10 @@ GST_START_TEST (test_block_group)
buffers = NULL;
/* Now push a buffer */
inbuffer = gst_buffer_new_and_alloc (1);
GST_BUFFER_DATA (inbuffer)[0] = 0x42;
indata = g_malloc (1);
inbuffer = gst_buffer_new_wrapped (indata, 1);
indata[0] = 0x42;
GST_BUFFER_TIMESTAMP (inbuffer) = 1000000;
caps = gst_caps_from_string (AC3_CAPS_STRING);
gst_buffer_set_caps (inbuffer, caps);
gst_caps_unref (caps);
ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
fail_unless (gst_pad_push (mysrcpad, inbuffer) == GST_FLOW_OK);
@ -396,11 +399,8 @@ GST_START_TEST (test_reset)
int i;
matroskamux = setup_matroskamux (&srcac3template);
fail_unless (gst_element_set_state (matroskamux,
GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS,
"could not set to playing");
inbuffer = gst_buffer_new_and_alloc (1);
inbuffer = gst_buffer_new_allocate (NULL, 1, 0);
ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
fail_unless (gst_pad_push (mysrcpad, inbuffer) == GST_FLOW_OK);
num_buffers = g_list_length (buffers);
@ -414,7 +414,7 @@ GST_START_TEST (test_reset)
GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS,
"could not set to playing");
inbuffer = gst_buffer_new_and_alloc (1);
inbuffer = gst_buffer_new_allocate (NULL, 1, 0);
ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
fail_unless (gst_pad_push (mysrcpad, inbuffer) == GST_FLOW_OK);
num_buffers = g_list_length (buffers);