From a19f0375ec009a0552498c9045cb69492cbab10a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Tue, 17 Mar 2009 14:27:50 +0100 Subject: [PATCH] mxfmux: Make sure to include a picture in the edit units when muxing MPEG2/MPEG4 --- gst/mxf/mxfmpeg.c | 153 ++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 149 insertions(+), 4 deletions(-) diff --git a/gst/mxf/mxfmpeg.c b/gst/mxf/mxfmpeg.c index 609e53bd6a..534b9fc8a9 100644 --- a/gst/mxf/mxfmpeg.c +++ b/gst/mxf/mxfmpeg.c @@ -868,8 +868,9 @@ typedef struct } MPEGAudioMappingData; static GstFlowReturn -mxf_mpeg_write_func (GstBuffer * buffer, GstCaps * caps, gpointer mapping_data, - GstAdapter * adapter, GstBuffer ** outbuf, gboolean flush) +mxf_mpeg_audio_write_func (GstBuffer * buffer, GstCaps * caps, + gpointer mapping_data, GstAdapter * adapter, GstBuffer ** outbuf, + gboolean flush) { *outbuf = buffer; return GST_FLOW_OK; @@ -949,7 +950,7 @@ mxf_mpeg_audio_get_descriptor (GstPadTemplate * tmpl, GstCaps * caps, memcpy (&ret->parent.essence_container, &mpeg_essence_container_ul, 16); mxf_metadata_generic_sound_essence_descriptor_from_caps (ret, caps); - *handler = mxf_mpeg_write_func; + *handler = mxf_mpeg_audio_write_func; return (MXFMetadataFileDescriptor *) ret; } @@ -1003,6 +1004,134 @@ static MXFEssenceElementWriter mxf_mpeg_audio_essence_element_writer = { "rate = (int) [ 8000, 96000 ], " \ "channels = (int) [ 1, 8 ]" +/* See ISO/IEC 13818-2 for MPEG ES format */ +gboolean +mxf_mpeg_is_mpeg2_frame (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; + + /* PICTURE */ + if (type == 0x00) { + return TRUE; + } + } else { + gst_byte_reader_skip (&reader, 1); + } + } + + return FALSE; +} + +static gboolean +mxf_mpeg_is_mpeg4_frame (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; + + /* PICTURE */ + if (type == 0xb6) { + return TRUE; + } + } else { + gst_byte_reader_skip (&reader, 1); + } + } + + return FALSE; +} + +static GstFlowReturn +mxf_mpeg_video_write_func (GstBuffer * buffer, GstCaps * caps, + gpointer mapping_data, GstAdapter * adapter, GstBuffer ** outbuf, + gboolean flush) +{ + MXFMPEGEssenceType type = MXF_MPEG_ESSENCE_TYPE_OTHER; + + if (mapping_data) + type = *((MXFMPEGEssenceType *) mapping_data); + + if (type == MXF_MPEG_ESSENCE_TYPE_VIDEO_MPEG2) { + if (buffer && !mxf_mpeg_is_mpeg2_frame (buffer)) { + gst_adapter_push (adapter, buffer); + *outbuf = NULL; + return GST_FLOW_OK; + } else if (buffer || gst_adapter_available (adapter)) { + guint av = gst_adapter_available (adapter); + GstBuffer *ret; + + if (buffer) + ret = gst_buffer_new_and_alloc (GST_BUFFER_SIZE (buffer) + av); + else + ret = gst_buffer_new_and_alloc (av); + + if (av) { + GstBuffer *tmp = gst_adapter_take_buffer (adapter, av); + memcpy (GST_BUFFER_DATA (ret), GST_BUFFER_DATA (tmp), av); + gst_buffer_unref (tmp); + } + + if (buffer) { + memcpy (GST_BUFFER_DATA (ret) + av, GST_BUFFER_DATA (buffer), + GST_BUFFER_SIZE (buffer)); + gst_buffer_unref (buffer); + } + *outbuf = ret; + return GST_FLOW_OK; + } + } else if (type == MXF_MPEG_ESSENCE_TYPE_VIDEO_MPEG4) { + if (buffer && !mxf_mpeg_is_mpeg4_frame (buffer)) { + gst_adapter_push (adapter, buffer); + *outbuf = NULL; + return GST_FLOW_OK; + } else if (buffer || gst_adapter_available (adapter)) { + guint av = gst_adapter_available (adapter); + GstBuffer *ret; + + if (buffer) + ret = gst_buffer_new_and_alloc (GST_BUFFER_SIZE (buffer) + av); + else + ret = gst_buffer_new_and_alloc (av); + + if (av) { + GstBuffer *tmp = gst_adapter_take_buffer (adapter, av); + memcpy (GST_BUFFER_DATA (ret), GST_BUFFER_DATA (tmp), av); + gst_buffer_unref (tmp); + } + + if (buffer) { + memcpy (GST_BUFFER_DATA (ret) + av, GST_BUFFER_DATA (buffer), + GST_BUFFER_SIZE (buffer)); + gst_buffer_unref (buffer); + } + *outbuf = ret; + return GST_FLOW_OK; + } + } + + *outbuf = buffer; + return GST_FLOW_OK; +} static const guint8 mpeg_video_picture_essence_compression_ul[] = { 0x06, 0x0e, 0x2b, 0x34, 0x04, 0x01, 0x01, 0x00, @@ -1032,12 +1161,24 @@ mxf_mpeg_video_get_descriptor (GstPadTemplate * tmpl, GstCaps * caps, return NULL; if (mpegversion == 1) { + MXFMPEGEssenceType type = MXF_MPEG_ESSENCE_TYPE_VIDEO_MPEG2; + + *mapping_data = g_new0 (MXFMPEGEssenceType, 1); + memcpy (*mapping_data, &type, sizeof (MXFMPEGEssenceType)); ret->parent.parent.picture_essence_coding.u[13] = 0x10; } else if (mpegversion == 2) { + MXFMPEGEssenceType type = MXF_MPEG_ESSENCE_TYPE_VIDEO_MPEG2; + + *mapping_data = g_new0 (MXFMPEGEssenceType, 1); + memcpy (*mapping_data, &type, sizeof (MXFMPEGEssenceType)); ret->parent.parent.picture_essence_coding.u[13] = 0x01; } else { const GValue *v; const GstBuffer *codec_data; + MXFMPEGEssenceType type = MXF_MPEG_ESSENCE_TYPE_VIDEO_MPEG4; + + *mapping_data = g_new0 (MXFMPEGEssenceType, 1); + memcpy (*mapping_data, &type, sizeof (MXFMPEGEssenceType)); ret->parent.parent.picture_essence_coding.u[13] = 0x20; if ((v = gst_structure_get_value (s, "codec_data"))) { @@ -1050,6 +1191,10 @@ mxf_mpeg_video_get_descriptor (GstPadTemplate * tmpl, GstCaps * caps, } } } else if (strcmp (gst_structure_get_name (s), "video/x-h264") == 0) { + MXFMPEGEssenceType type = MXF_MPEG_ESSENCE_TYPE_VIDEO_AVC; + + *mapping_data = g_new0 (MXFMPEGEssenceType, 1); + memcpy (*mapping_data, &type, sizeof (MXFMPEGEssenceType)); ret->parent.parent.picture_essence_coding.u[13] = 0x30; } else { g_assert_not_reached (); @@ -1058,7 +1203,7 @@ mxf_mpeg_video_get_descriptor (GstPadTemplate * tmpl, GstCaps * caps, mxf_metadata_generic_picture_essence_descriptor_from_caps (&ret-> parent.parent, caps); - *handler = mxf_mpeg_write_func; + *handler = mxf_mpeg_video_write_func; return (MXFMetadataFileDescriptor *) ret; }