summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSebastian Dröge <slomo@circular-chaos.org>2008-06-19 09:12:55 +0000
committerSebastian Dröge <slomo@circular-chaos.org>2008-06-19 09:12:55 +0000
commit7afcb8068a8bf707357336ea0606f0db75be3878 (patch)
tree4e985590c66a9d99e39a1ea6b34114049393d75f
parent2d799149482b74709a3116527ad6859b8e289695 (diff)
gst/matroska/: Add a "vfunc" to the track context for postprocessing frames and convert the wavpack and subtitle post...
Original commit message from CVS: * gst/matroska/matroska-demux.c: (gst_matroska_track_free), (gst_matroska_demux_add_mpeg_seq_header), (gst_matroska_demux_add_wvpk_header), (gst_matroska_demux_check_subtitle_buffer), (gst_matroska_demux_parse_blockgroup_or_simpleblock), (gst_matroska_demux_video_caps), (gst_matroska_demux_audio_caps), (gst_matroska_demux_subtitle_caps): * gst/matroska/matroska-ids.h: Add a "vfunc" to the track context for postprocessing frames and convert the wavpack and subtitle postprocessing to this vfunc. Copy buffer flags in those functions to the new buffers too. Parse CodecState elements of Blocks. Add a postprocessing function for MPEG video that adds the sequence header from the codec private data or codec state to the frames if it's not already there.
-rw-r--r--ChangeLog20
-rw-r--r--gst/matroska/matroska-demux.c147
-rw-r--r--gst/matroska/matroska-ids.h14
3 files changed, 141 insertions, 40 deletions
diff --git a/ChangeLog b/ChangeLog
index 51d9fddc..37066f96 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,25 @@
2008-06-19 Sebastian Dröge <slomo@circular-chaos.org>
+ * gst/matroska/matroska-demux.c: (gst_matroska_track_free),
+ (gst_matroska_demux_add_mpeg_seq_header),
+ (gst_matroska_demux_add_wvpk_header),
+ (gst_matroska_demux_check_subtitle_buffer),
+ (gst_matroska_demux_parse_blockgroup_or_simpleblock),
+ (gst_matroska_demux_video_caps), (gst_matroska_demux_audio_caps),
+ (gst_matroska_demux_subtitle_caps):
+ * gst/matroska/matroska-ids.h:
+ Add a "vfunc" to the track context for postprocessing frames and
+ convert the wavpack and subtitle postprocessing to this vfunc.
+ Copy buffer flags in those functions to the new buffers too.
+
+ Parse CodecState elements of Blocks.
+
+ Add a postprocessing function for MPEG video that adds the sequence
+ header from the codec private data or codec state to the frames if
+ it's not already there.
+
+2008-06-19 Sebastian Dröge <slomo@circular-chaos.org>
+
* gst/matroska/matroska-demux.c:
(gst_matroska_demux_parse_blockgroup_or_simpleblock):
If a gap of more than 1/2 second is found in one stream send a
diff --git a/gst/matroska/matroska-demux.c b/gst/matroska/matroska-demux.c
index f73715f1..a09dc89c 100644
--- a/gst/matroska/matroska-demux.c
+++ b/gst/matroska/matroska-demux.c
@@ -219,6 +219,7 @@ gst_matroska_track_free (GstMatroskaTrackContext * track)
g_free (track->name);
g_free (track->language);
g_free (track->codec_priv);
+ g_free (track->codec_state);
if (track->encodings != NULL) {
int i;
@@ -3248,20 +3249,72 @@ gst_matroska_demux_push_dvd_clut_change_event (GstMatroskaDemux * demux,
g_free (buf);
}
-static gboolean
-gst_matroska_demux_stream_is_wavpack (GstMatroskaTrackContext * stream)
+static GstFlowReturn
+gst_matroska_demux_add_mpeg_seq_header (GstElement * element,
+ GstMatroskaTrackContext * stream, GstBuffer ** buf)
{
- if (stream->type == GST_MATROSKA_TRACK_TYPE_AUDIO) {
- return (strcmp (stream->codec_id,
- GST_MATROSKA_CODEC_ID_AUDIO_WAVPACK4) == 0);
+ GstMatroskaDemux *demux = GST_MATROSKA_DEMUX (element);
+
+ guint8 *seq_header;
+
+ guint seq_header_len;
+
+ guint32 header;
+
+ if (stream->codec_state) {
+ seq_header = stream->codec_state;
+ seq_header_len = stream->codec_state_size;
+ } else if (stream->codec_priv) {
+ seq_header = stream->codec_priv;
+ seq_header_len = stream->codec_priv_size;
+ } else {
+ return GST_FLOW_OK;
}
- return FALSE;
+
+ /* Sequence header only needed for keyframes */
+ if (GST_BUFFER_FLAG_IS_SET (*buf, GST_BUFFER_FLAG_DELTA_UNIT))
+ return GST_FLOW_OK;
+
+ if (GST_BUFFER_SIZE (*buf) < 4)
+ return GST_FLOW_OK;
+
+ header = GST_READ_UINT32_BE (GST_BUFFER_DATA (*buf));
+ /* Sequence start code, if not found prepend */
+ if (header != 0x000001b3) {
+ GstBuffer *newbuf;
+
+ GstFlowReturn ret, cret;
+
+ ret = gst_pad_alloc_buffer_and_set_caps (stream->pad,
+ GST_BUFFER_OFFSET_NONE, GST_BUFFER_SIZE (*buf) + seq_header_len,
+ stream->caps, &newbuf);
+ cret = gst_matroska_demux_combine_flows (demux, stream, ret);
+ if (ret != GST_FLOW_OK) {
+ GST_WARNING_OBJECT (demux, "Reallocating buffer for sequence header "
+ "failed: %s, combined flow return: %s", gst_flow_get_name (ret),
+ gst_flow_get_name (cret));
+ return cret;
+ }
+
+ GST_DEBUG_OBJECT (demux, "Prepending MPEG sequence header");
+ gst_buffer_copy_metadata (newbuf, *buf, GST_BUFFER_COPY_TIMESTAMPS |
+ GST_BUFFER_COPY_FLAGS);
+ g_memmove (GST_BUFFER_DATA (newbuf), seq_header, seq_header_len);
+ g_memmove (GST_BUFFER_DATA (newbuf) + seq_header_len,
+ GST_BUFFER_DATA (*buf), GST_BUFFER_SIZE (*buf));
+ gst_buffer_unref (*buf);
+ *buf = newbuf;
+ }
+
+ return GST_FLOW_OK;
}
static GstFlowReturn
-gst_matroska_demux_add_wvpk_header (GstMatroskaDemux * demux,
- GstMatroskaTrackContext * stream, gint block_length, GstBuffer ** buf)
+gst_matroska_demux_add_wvpk_header (GstElement * element,
+ GstMatroskaTrackContext * stream, GstBuffer ** buf)
{
+ GstMatroskaDemux *demux = GST_MATROSKA_DEMUX (element);
+
GstBuffer *newbuf;
guint8 *data;
@@ -3283,7 +3336,7 @@ gst_matroska_demux_add_wvpk_header (GstMatroskaDemux * demux,
/* -20 because ck_size is the size of the wavpack block -8
* and lace_size is the size of the wavpack block + 12
* (the three guint32 of the header that already are in the buffer) */
- wvh.ck_size = block_length + sizeof (Wavpack4Header) - 20;
+ wvh.ck_size = GST_BUFFER_SIZE (*buf) + sizeof (Wavpack4Header) - 20;
wvh.version = GST_READ_UINT16_LE (stream->codec_priv);
wvh.track_no = 0;
wvh.index_no = 0;
@@ -3291,7 +3344,7 @@ gst_matroska_demux_add_wvpk_header (GstMatroskaDemux * demux,
wvh.block_index = 0;
/* block_samples, flags and crc are already in the buffer */
- newlen = block_length + sizeof (Wavpack4Header) - 12;
+ newlen = GST_BUFFER_SIZE (*buf) + sizeof (Wavpack4Header) - 12;
ret = gst_pad_alloc_buffer_and_set_caps (stream->pad, GST_BUFFER_OFFSET_NONE,
newlen, stream->caps, &newbuf);
cret = gst_matroska_demux_combine_flows (demux, stream, ret);
@@ -3312,18 +3365,21 @@ gst_matroska_demux_add_wvpk_header (GstMatroskaDemux * demux,
GST_WRITE_UINT8 (data + 11, wvh.index_no);
GST_WRITE_UINT32_LE (data + 12, wvh.total_samples);
GST_WRITE_UINT32_LE (data + 16, wvh.block_index);
- g_memmove (data + 20, GST_BUFFER_DATA (*buf), block_length);
- gst_buffer_copy_metadata (newbuf, *buf, GST_BUFFER_COPY_TIMESTAMPS);
+ g_memmove (data + 20, GST_BUFFER_DATA (*buf), GST_BUFFER_SIZE (*buf));
+ gst_buffer_copy_metadata (newbuf, *buf,
+ GST_BUFFER_COPY_TIMESTAMPS | GST_BUFFER_COPY_FLAGS);
gst_buffer_unref (*buf);
*buf = newbuf;
return cret;
}
-static GstBuffer *
-gst_matroska_demux_check_subtitle_buffer (GstMatroskaDemux * demux,
- GstMatroskaTrackContext * stream, GstBuffer * buf)
+static GstFlowReturn
+gst_matroska_demux_check_subtitle_buffer (GstElement * element,
+ GstMatroskaTrackContext * stream, GstBuffer ** buf)
{
+ GstMatroskaDemux *demux = GST_MATROSKA_DEMUX (element);
+
GstMatroskaTrackSubtitleContext *sub_stream;
const gchar *encoding, *data;
@@ -3338,15 +3394,12 @@ gst_matroska_demux_check_subtitle_buffer (GstMatroskaDemux * demux,
sub_stream = (GstMatroskaTrackSubtitleContext *) stream;
- if (!sub_stream->check_utf8)
- return buf;
-
- data = (const gchar *) GST_BUFFER_DATA (buf);
- size = GST_BUFFER_SIZE (buf);
+ data = (const gchar *) GST_BUFFER_DATA (*buf);
+ size = GST_BUFFER_SIZE (*buf);
if (!sub_stream->invalid_utf8) {
if (g_utf8_validate (data, size, NULL)) {
- return buf;
+ return GST_FLOW_OK;
}
GST_WARNING_OBJECT (demux, "subtitle stream %d is not valid UTF-8, this "
"is broken according to the matroska specification", stream->num);
@@ -3388,10 +3441,12 @@ gst_matroska_demux_check_subtitle_buffer (GstMatroskaDemux * demux,
GST_BUFFER_MALLOCDATA (newbuf) = (guint8 *) utf8;
GST_BUFFER_DATA (newbuf) = (guint8 *) utf8;
GST_BUFFER_SIZE (newbuf) = strlen (utf8);
- gst_buffer_copy_metadata (newbuf, buf, GST_BUFFER_COPY_TIMESTAMPS);
+ gst_buffer_copy_metadata (newbuf, *buf,
+ GST_BUFFER_COPY_TIMESTAMPS | GST_BUFFER_COPY_FLAGS);
gst_buffer_unref (buf);
- return newbuf;
+ *buf = newbuf;
+ return GST_FLOW_OK;
}
static GstBuffer *
@@ -3709,6 +3764,25 @@ gst_matroska_demux_parse_blockgroup_or_simpleblock (GstMatroskaDemux * demux,
break;
}
+ case GST_MATROSKA_ID_CODECSTATE:{
+ guint8 *data;
+
+ guint64 data_len = 0;
+
+ if ((ret =
+ gst_ebml_read_binary (ebml, &id, &data,
+ &data_len)) != GST_FLOW_OK)
+ break;
+
+ g_free (stream->codec_state);
+ stream->codec_state = data;
+ stream->codec_state_size = data_len;
+ /* TODO: decompress/decrypt if necessary */
+ GST_DEBUG_OBJECT (demux, "CodecState of %u bytes",
+ stream->codec_state_size);
+ break;
+ }
+
default:
GST_WARNING_OBJECT (demux,
"Unknown BlockGroup subelement 0x%x - ignoring", id);
@@ -3718,7 +3792,6 @@ gst_matroska_demux_parse_blockgroup_or_simpleblock (GstMatroskaDemux * demux,
case GST_MATROSKA_ID_BLOCKADDITIONS:
case GST_MATROSKA_ID_REFERENCEPRIORITY:
case GST_MATROSKA_ID_REFERENCEVIRTUAL:
- case GST_MATROSKA_ID_CODECSTATE:
case GST_MATROSKA_ID_SLICES:
ret = gst_ebml_read_skip (ebml);
break;
@@ -3802,11 +3875,6 @@ gst_matroska_demux_parse_blockgroup_or_simpleblock (GstMatroskaDemux * demux,
gst_matroska_demux_sync_streams (demux);
- if (gst_matroska_demux_stream_is_wavpack (stream)) {
- ret =
- gst_matroska_demux_add_wvpk_header (demux, stream, lace_size[n],
- &sub);
- }
if (duration) {
GST_BUFFER_DURATION (sub) = duration / laces;
@@ -3848,9 +3916,9 @@ gst_matroska_demux_parse_blockgroup_or_simpleblock (GstMatroskaDemux * demux,
gst_buffer_set_caps (sub, GST_PAD_CAPS (stream->pad));
- /* Fix up broken files with subtitles that are not UTF8 */
- if (stream->type == GST_MATROSKA_TRACK_TYPE_SUBTITLE) {
- sub = gst_matroska_demux_check_subtitle_buffer (demux, stream, sub);
+ /* Postprocess the buffers depending on the codec used */
+ if (stream->postprocess_frame) {
+ ret = stream->postprocess_frame (GST_ELEMENT (demux), stream, &sub);
}
ret = gst_pad_push (stream->pad, sub);
@@ -4639,6 +4707,7 @@ gst_matroska_demux_video_caps (GstMatroskaTrackVideoContext *
"systemstream", G_TYPE_BOOLEAN, FALSE,
"mpegversion", G_TYPE_INT, mpegversion, NULL);
*codec_name = g_strdup_printf ("MPEG-%d video", mpegversion);
+ context->postprocess_frame = gst_matroska_demux_add_mpeg_seq_header;
} else if (!strcmp (codec_id, GST_MATROSKA_CODEC_ID_VIDEO_MJPEG)) {
caps = gst_caps_new_simple ("image/jpeg", NULL);
*codec_name = g_strdup ("Motion-JPEG");
@@ -4996,6 +5065,7 @@ gst_matroska_demux_audio_caps (GstMatroskaTrackAudioContext *
"width", G_TYPE_INT, audiocontext->bitdepth,
"framed", G_TYPE_BOOLEAN, TRUE, NULL);
*codec_name = g_strdup ("Wavpack audio");
+ context->postprocess_frame = gst_matroska_demux_add_wvpk_header;
} else if ((!strcmp (codec_id, GST_MATROSKA_CODEC_ID_AUDIO_REAL_14_4)) ||
(!strcmp (codec_id, GST_MATROSKA_CODEC_ID_AUDIO_REAL_14_4)) ||
(!strcmp (codec_id, GST_MATROSKA_CODEC_ID_AUDIO_REAL_COOK))) {
@@ -5047,6 +5117,9 @@ gst_matroska_demux_subtitle_caps (GstMatroskaTrackSubtitleContext *
{
GstCaps *caps = NULL;
+ GstMatroskaTrackContext *context =
+ (GstMatroskaTrackContext *) subtitlecontext;
+
/* for backwards compatibility */
if (!g_ascii_strcasecmp (codec_id, GST_MATROSKA_CODEC_ID_SUBTITLE_ASCII))
codec_id = GST_MATROSKA_CODEC_ID_SUBTITLE_UTF8;
@@ -5061,24 +5134,22 @@ gst_matroska_demux_subtitle_caps (GstMatroskaTrackSubtitleContext *
* Check if we have to do something with codec_private */
if (!strcmp (codec_id, GST_MATROSKA_CODEC_ID_SUBTITLE_UTF8)) {
caps = gst_caps_new_simple ("text/plain", NULL);
- subtitlecontext->check_utf8 = TRUE;
+ context->postprocess_frame = gst_matroska_demux_check_subtitle_buffer;
} else if (!strcmp (codec_id, GST_MATROSKA_CODEC_ID_SUBTITLE_SSA)) {
caps = gst_caps_new_simple ("application/x-ssa", NULL);
- subtitlecontext->check_utf8 = TRUE;
+ context->postprocess_frame = gst_matroska_demux_check_subtitle_buffer;
} else if (!strcmp (codec_id, GST_MATROSKA_CODEC_ID_SUBTITLE_ASS)) {
caps = gst_caps_new_simple ("application/x-ass", NULL);
- subtitlecontext->check_utf8 = TRUE;
+ context->postprocess_frame = gst_matroska_demux_check_subtitle_buffer;
} else if (!strcmp (codec_id, GST_MATROSKA_CODEC_ID_SUBTITLE_USF)) {
caps = gst_caps_new_simple ("application/x-usf", NULL);
- subtitlecontext->check_utf8 = TRUE;
+ context->postprocess_frame = gst_matroska_demux_check_subtitle_buffer;
} else if (!strcmp (codec_id, GST_MATROSKA_CODEC_ID_SUBTITLE_VOBSUB)) {
caps = gst_caps_new_simple ("video/x-dvd-subpicture", NULL);
((GstMatroskaTrackContext *) subtitlecontext)->send_dvd_event = TRUE;
- subtitlecontext->check_utf8 = FALSE;
} else {
GST_DEBUG ("Unknown subtitle stream: codec_id='%s'", codec_id);
caps = gst_caps_new_simple ("application/x-subtitle-unknown", NULL);
- subtitlecontext->check_utf8 = FALSE;
}
if (data != NULL && size > 0) {
diff --git a/gst/matroska/matroska-ids.h b/gst/matroska/matroska-ids.h
index 6ad20607..fcf6e60d 100644
--- a/gst/matroska/matroska-ids.h
+++ b/gst/matroska/matroska-ids.h
@@ -452,8 +452,11 @@ typedef enum {
GST_MATROSKA_VIDEOTRACK_INTERLACED = (GST_MATROSKA_TRACK_SHIFT<<0)
} GstMatroskaVideoTrackFlags;
+
+typedef struct _GstMatroskaTrackContext GstMatroskaTrackContext;
+
/* TODO: check if all fields are used */
-typedef struct _GstMatroskaTrackContext {
+struct _GstMatroskaTrackContext {
GstPad *pad;
GstCaps *caps;
guint index;
@@ -463,6 +466,8 @@ typedef struct _GstMatroskaTrackContext {
gchar *codec_id, *codec_name, *name, *language;
gpointer codec_priv;
guint codec_priv_size;
+ gpointer codec_state;
+ guint codec_state_size;
GstMatroskaTrackType type;
guint uid, num;
GstMatroskaTrackFlags flags;
@@ -491,13 +496,18 @@ typedef struct _GstMatroskaTrackContext {
* they are put into codec private data, not muxed into the stream */
guint xiph_headers_to_skip;
+ /* Used for postprocessing a frame before it is pushed from the demuxer */
+ GstFlowReturn (*postprocess_frame) (GstElement *element,
+ GstMatroskaTrackContext *context,
+ GstBuffer **buffer);
+
/* Tags to send after newsegment event */
GstTagList *pending_tags;
/* A GArray of GstMatroskaTrackEncoding structures which contain the
* encoding (compression/encryption) settings for this track, if any */
GArray *encodings;
-} GstMatroskaTrackContext;
+};
typedef struct _GstMatroskaTrackVideoContext {
GstMatroskaTrackContext parent;