summaryrefslogtreecommitdiffstats
path: root/gst/mxf/mxfmpeg.c
diff options
context:
space:
mode:
authorSebastian Dröge <sebastian.droege@collabora.co.uk>2009-02-06 09:53:13 +0100
committerSebastian Dröge <sebastian.droege@collabora.co.uk>2009-02-06 09:53:13 +0100
commit6208795598029c4e902c923434100e91d3ce2398 (patch)
tree2102e4cde4a92a8f43ed896eeead4aa7cc92af15 /gst/mxf/mxfmpeg.c
parentc9f6a8b58664319d7db5f90166012c55c92a3191 (diff)
downloadgst-plugins-bad-6208795598029c4e902c923434100e91d3ce2398.tar.gz
gst-plugins-bad-6208795598029c4e902c923434100e91d3ce2398.tar.bz2
gst-plugins-bad-6208795598029c4e902c923434100e91d3ce2398.zip
mxfdemux: Add keyframe detection for MPEG2 video streams
This is useful for seeking as we usually want to seek to the previous keyframe. The keyframe detection is done by parsing the MPEG2 elementary stream and if a GOP or I-frame packet is found we assume a keyframe in this edit unit.
Diffstat (limited to 'gst/mxf/mxfmpeg.c')
-rw-r--r--gst/mxf/mxfmpeg.c82
1 files changed, 82 insertions, 0 deletions
diff --git a/gst/mxf/mxfmpeg.c b/gst/mxf/mxfmpeg.c
index 5bfa4562..940b2439 100644
--- a/gst/mxf/mxfmpeg.c
+++ b/gst/mxf/mxfmpeg.c
@@ -37,6 +37,8 @@
#include "mxfmpeg.h"
+#include <gst/base/gstbytereader.h>
+
GST_DEBUG_CATEGORY_EXTERN (mxf_debug);
#define GST_CAT_DEFAULT mxf_debug
@@ -224,6 +226,14 @@ static void
mxf_metadata_mpeg_video_descriptor_handle_tag;
}
+typedef enum
+{
+ MXF_MPEG_ESSENCE_TYPE_OTHER = 0,
+ MXF_MPEG_ESSENCE_TYPE_VIDEO_MPEG2,
+ MXF_MPEG_ESSENCE_TYPE_VIDEO_MPEG4,
+ MXF_MPEG_ESSENCE_TYPE_VIDEO_AVC
+} MXFMPEGEssenceType;
+
static gboolean
mxf_is_mpeg_essence_track (const MXFMetadataTimelineTrack * track)
{
@@ -253,11 +263,57 @@ mxf_is_mpeg_essence_track (const MXFMetadataTimelineTrack * track)
return FALSE;
}
+/* See ISO/IEC 13818-2 for MPEG ES format */
+gboolean
+mxf_mpeg_is_mpeg2_keyframe (GstBuffer * buffer)
+{
+ GstByteReader reader = GST_BYTE_READER_INIT_FROM_BUFFER (buffer);
+ guint32 tmp;
+
+ while (gst_byte_reader_get_remaining (&reader) > 3) {
+ if (gst_byte_reader_peek_uint24_be (&reader, &tmp) && tmp == 0x000001) {
+ guint8 type;
+
+ /* Found sync code */
+ gst_byte_reader_skip (&reader, 3);
+
+ if (!gst_byte_reader_get_uint8 (&reader, &type))
+ break;
+
+ /* GOP packets are meant as random access markers */
+ if (type == 0xb8) {
+ return TRUE;
+ } else if (type == 0x00) {
+ guint8 pic_type;
+
+ if (!gst_byte_reader_skip (&reader, 5))
+ break;
+
+ if (!gst_byte_reader_get_uint8 (&reader, &pic_type))
+ break;
+
+ pic_type = (pic_type >> 3) & 0x07;
+ if (pic_type == 0x01) {
+ return TRUE;
+ } else {
+ return FALSE;
+ }
+ }
+ } else {
+ gst_byte_reader_skip (&reader, 1);
+ }
+ }
+
+ return FALSE;
+}
+
static GstFlowReturn
mxf_mpeg_video_handle_essence_element (const MXFUL * key, GstBuffer * buffer,
GstCaps * caps, MXFMetadataTimelineTrack * track,
gpointer mapping_data, GstBuffer ** outbuf)
{
+ MXFMPEGEssenceType type = *((MXFMPEGEssenceType *) mapping_data);
+
*outbuf = buffer;
/* SMPTE 381M 6.1 */
@@ -267,6 +323,18 @@ mxf_mpeg_video_handle_essence_element (const MXFUL * key, GstBuffer * buffer,
return GST_FLOW_ERROR;
}
+ switch (type) {
+ case MXF_MPEG_ESSENCE_TYPE_VIDEO_MPEG2:
+ if (mxf_mpeg_is_mpeg2_keyframe (buffer))
+ GST_BUFFER_FLAG_UNSET (buffer, GST_BUFFER_FLAG_DELTA_UNIT);
+ else
+ GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_FLAG_DELTA_UNIT);
+ break;
+
+ default:
+ break;
+ }
+
return GST_FLOW_OK;
}
@@ -339,6 +407,10 @@ mxf_mpeg_es_create_caps (MXFMetadataTimelineTrack * track, GstTagList ** tags,
{
GstCaps *caps = NULL;
const gchar *codec_name = NULL;
+ MXFMPEGEssenceType t, *mdata;
+
+ *mapping_data = g_malloc (sizeof (MXFMPEGEssenceType));
+ mdata = (MXFMPEGEssenceType *) * mapping_data;
/* SMPTE RP224 */
if (p) {
@@ -348,6 +420,8 @@ mxf_mpeg_es_create_caps (MXFMetadataTimelineTrack * track, GstTagList ** tags,
gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 2,
"systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
codec_name = "MPEG-2 Video";
+ t = MXF_MPEG_ESSENCE_TYPE_VIDEO_MPEG2;
+ memcpy (mdata, &t, sizeof (MXFMPEGEssenceType));
} else if (p->picture_essence_coding.u[0] != 0x06
|| p->picture_essence_coding.u[1] != 0x0e
|| p->picture_essence_coding.u[2] != 0x2b
@@ -367,10 +441,14 @@ mxf_mpeg_es_create_caps (MXFMetadataTimelineTrack * track, GstTagList ** tags,
caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 2,
"systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
codec_name = "MPEG-2 Video";
+ t = MXF_MPEG_ESSENCE_TYPE_VIDEO_MPEG2;
+ memcpy (mdata, &t, sizeof (MXFMPEGEssenceType));
} else if (p->picture_essence_coding.u[13] == 0x10) {
caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 1,
"systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
codec_name = "MPEG-1 Video";
+ t = MXF_MPEG_ESSENCE_TYPE_VIDEO_MPEG2;
+ memcpy (mdata, &t, sizeof (MXFMPEGEssenceType));
} else if (p->picture_essence_coding.u[13] == 0x20) {
MXFLocalTag *local_tag =
(((MXFMetadataBase *) p)->other_tags) ?
@@ -389,12 +467,16 @@ mxf_mpeg_es_create_caps (MXFMetadataTimelineTrack * track, GstTagList ** tags,
gst_buffer_unref (codec_data);
}
codec_name = "MPEG-4 Video";
+ t = MXF_MPEG_ESSENCE_TYPE_VIDEO_MPEG4;
+ memcpy (mdata, &t, sizeof (MXFMPEGEssenceType));
} else if ((p->picture_essence_coding.u[13] >> 4) == 0x03) {
/* RP 2008 */
/* TODO: What about codec_data for AVC1 streams? */
caps = gst_caps_new_simple ("video/x-h264", NULL);
codec_name = "h.264 Video";
+ t = MXF_MPEG_ESSENCE_TYPE_VIDEO_AVC;
+ memcpy (mdata, &t, sizeof (MXFMPEGEssenceType));
} else {
GST_ERROR ("Unsupported MPEG picture essence coding 0x%02x",
p->picture_essence_coding.u[13]);