mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2025-02-17 03:35:21 +00:00
mpeg4videoparse: port to 0.11
This commit is contained in:
parent
67dac04012
commit
e82262969c
2 changed files with 73 additions and 50 deletions
|
@ -299,7 +299,7 @@ GST_PLUGINS_NONPORTED=" adpcmdec adpcmenc aiff asfmux \
|
|||
fieldanalysis freeze frei0r gaudieffects geometrictransform h264parse \
|
||||
hdvparse hls id3tag inter interlace ivfparse jpegformat jp2kdecimator \
|
||||
liveadder legacyresample librfb mpegdemux mpegtsdemux mpegtsmux \
|
||||
mpegpsmux mpeg4videoparse mpegvideoparse mve mxf nsf nuvdemux \
|
||||
mpegpsmux mpegvideoparse mve mxf nsf nuvdemux \
|
||||
patchdetect pcapparse pnm rawparse real removesilence rtpmux rtpvp8 scaletempo \
|
||||
sdi segmentclip siren speed subenc stereo tta videofilters \
|
||||
videomaxrate videomeasure videoparsers videosignal vmnc y4m \
|
||||
|
|
|
@ -61,8 +61,8 @@ enum
|
|||
PROP_LAST
|
||||
};
|
||||
|
||||
GST_BOILERPLATE (GstMpeg4VParse, gst_mpeg4vparse, GstBaseParse,
|
||||
GST_TYPE_BASE_PARSE);
|
||||
#define gst_mpeg4vparse_parent_class parent_class
|
||||
G_DEFINE_TYPE (GstMpeg4VParse, gst_mpeg4vparse, GST_TYPE_BASE_PARSE);
|
||||
|
||||
static gboolean gst_mpeg4vparse_start (GstBaseParse * parse);
|
||||
static gboolean gst_mpeg4vparse_stop (GstBaseParse * parse);
|
||||
|
@ -79,22 +79,6 @@ static void gst_mpeg4vparse_set_property (GObject * object, guint prop_id,
|
|||
static void gst_mpeg4vparse_get_property (GObject * object, guint prop_id,
|
||||
GValue * value, GParamSpec * pspec);
|
||||
|
||||
static void
|
||||
gst_mpeg4vparse_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_template));
|
||||
gst_element_class_add_pad_template (element_class,
|
||||
gst_static_pad_template_get (&sink_template));
|
||||
|
||||
gst_element_class_set_details_simple (element_class,
|
||||
"MPEG 4 video elementary stream parser", "Codec/Parser/Video",
|
||||
"Parses MPEG-4 Part 2 elementary video streams",
|
||||
"Julien Moutte <julien@fluendo.com>");
|
||||
}
|
||||
|
||||
static void
|
||||
gst_mpeg4vparse_set_property (GObject * object, guint property_id,
|
||||
const GValue * value, GParamSpec * pspec)
|
||||
|
@ -135,6 +119,7 @@ static void
|
|||
gst_mpeg4vparse_class_init (GstMpeg4VParseClass * klass)
|
||||
{
|
||||
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
|
||||
GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass);
|
||||
GstBaseParseClass *parse_class = GST_BASE_PARSE_CLASS (klass);
|
||||
|
||||
parent_class = g_type_class_peek_parent (klass);
|
||||
|
@ -156,6 +141,16 @@ gst_mpeg4vparse_class_init (GstMpeg4VParseClass * klass)
|
|||
0, 3600, DEFAULT_CONFIG_INTERVAL,
|
||||
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
|
||||
|
||||
gst_element_class_add_pad_template (gstelement_class,
|
||||
gst_static_pad_template_get (&src_template));
|
||||
gst_element_class_add_pad_template (gstelement_class,
|
||||
gst_static_pad_template_get (&sink_template));
|
||||
|
||||
gst_element_class_set_details_simple (gstelement_class,
|
||||
"MPEG 4 video elementary stream parser", "Codec/Parser/Video",
|
||||
"Parses MPEG-4 Part 2 elementary video streams",
|
||||
"Julien Moutte <julien@fluendo.com>");
|
||||
|
||||
/* Override BaseParse vfuncs */
|
||||
parse_class->start = GST_DEBUG_FUNCPTR (gst_mpeg4vparse_start);
|
||||
parse_class->stop = GST_DEBUG_FUNCPTR (gst_mpeg4vparse_stop);
|
||||
|
@ -168,7 +163,7 @@ gst_mpeg4vparse_class_init (GstMpeg4VParseClass * klass)
|
|||
}
|
||||
|
||||
static void
|
||||
gst_mpeg4vparse_init (GstMpeg4VParse * parse, GstMpeg4VParseClass * g_class)
|
||||
gst_mpeg4vparse_init (GstMpeg4VParse * parse)
|
||||
{
|
||||
parse->interval = DEFAULT_CONFIG_INTERVAL;
|
||||
parse->last_report = GST_CLOCK_TIME_NONE;
|
||||
|
@ -226,8 +221,8 @@ gst_mpeg4vparse_process_config (GstMpeg4VParse * mp4vparse, const guint8 * data,
|
|||
gsize size)
|
||||
{
|
||||
/* only do stuff if something new */
|
||||
if (mp4vparse->config && size == GST_BUFFER_SIZE (mp4vparse->config) &&
|
||||
memcmp (GST_BUFFER_DATA (mp4vparse->config), data, size) == 0)
|
||||
if (mp4vparse->config && size == gst_buffer_get_size (mp4vparse->config) &&
|
||||
gst_buffer_memcmp (mp4vparse->config, 0, data, size) == 0)
|
||||
return TRUE;
|
||||
|
||||
if (!gst_mpeg4_params_parse_config (&mp4vparse->params, data, size)) {
|
||||
|
@ -244,7 +239,7 @@ gst_mpeg4vparse_process_config (GstMpeg4VParse * mp4vparse, const guint8 * data,
|
|||
gst_buffer_unref (mp4vparse->config);
|
||||
|
||||
mp4vparse->config = gst_buffer_new_and_alloc (size);
|
||||
memcpy (GST_BUFFER_DATA (mp4vparse->config), data, size);
|
||||
gst_buffer_fill (mp4vparse->config, 0, data, size);
|
||||
|
||||
/* trigger src caps update */
|
||||
mp4vparse->update_caps = TRUE;
|
||||
|
@ -258,11 +253,12 @@ gst_mpeg4vparse_process_sc (GstMpeg4VParse * mp4vparse, GstBuffer * buf,
|
|||
gint off)
|
||||
{
|
||||
guint8 *data;
|
||||
gsize size;
|
||||
guint code;
|
||||
|
||||
g_return_val_if_fail (buf && GST_BUFFER_SIZE (buf) >= off + 4, FALSE);
|
||||
g_return_val_if_fail (buf && gst_buffer_get_size (buf) >= off + 4, FALSE);
|
||||
|
||||
data = GST_BUFFER_DATA (buf);
|
||||
data = gst_buffer_map (buf, &size, NULL, GST_MAP_READ);
|
||||
code = data[off + 3];
|
||||
|
||||
GST_LOG_OBJECT (mp4vparse, "process startcode %x", code);
|
||||
|
@ -270,7 +266,7 @@ gst_mpeg4vparse_process_sc (GstMpeg4VParse * mp4vparse, GstBuffer * buf,
|
|||
/* if we found a VOP, next start code ends it,
|
||||
* except for final VOS end sequence code included in last VOP-frame */
|
||||
if (mp4vparse->vop_offset >= 0 && code != MPEG4_VOS_ENDCODE) {
|
||||
if (G_LIKELY (GST_BUFFER_SIZE (buf) > mp4vparse->vop_offset + 4)) {
|
||||
if (G_LIKELY (size > mp4vparse->vop_offset + 4)) {
|
||||
mp4vparse->intra_frame =
|
||||
((data[mp4vparse->vop_offset + 4] >> 6 & 0x3) == 0);
|
||||
} else {
|
||||
|
@ -279,6 +275,7 @@ gst_mpeg4vparse_process_sc (GstMpeg4VParse * mp4vparse, GstBuffer * buf,
|
|||
}
|
||||
GST_LOG_OBJECT (mp4vparse, "ending frame of size %d, is intra %d", off,
|
||||
mp4vparse->intra_frame);
|
||||
gst_buffer_unmap (buf, data, size);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
@ -300,7 +297,7 @@ gst_mpeg4vparse_process_sc (GstMpeg4VParse * mp4vparse, GstBuffer * buf,
|
|||
offset = mp4vparse->vos_offset >= 0 ?
|
||||
mp4vparse->vos_offset : mp4vparse->vo_offset;
|
||||
if (offset >= 0) {
|
||||
gst_mpeg4vparse_process_config (mp4vparse, GST_BUFFER_DATA (buf), off);
|
||||
gst_mpeg4vparse_process_config (mp4vparse, data, off);
|
||||
/* avoid accepting again for a VOP sc following a GOP sc */
|
||||
mp4vparse->vos_offset = -1;
|
||||
mp4vparse->vo_offset = -1;
|
||||
|
@ -319,6 +316,7 @@ gst_mpeg4vparse_process_sc (GstMpeg4VParse * mp4vparse, GstBuffer * buf,
|
|||
}
|
||||
break;
|
||||
}
|
||||
gst_buffer_unmap (buf, data, size);
|
||||
|
||||
/* at least need to have a VOP in a frame */
|
||||
return FALSE;
|
||||
|
@ -334,15 +332,20 @@ gst_mpeg4vparse_check_valid_frame (GstBaseParse * parse,
|
|||
{
|
||||
GstMpeg4VParse *mp4vparse = GST_MPEG4VIDEOPARSE (parse);
|
||||
GstBuffer *buf = frame->buffer;
|
||||
GstByteReader reader = GST_BYTE_READER_INIT_FROM_BUFFER (buf);
|
||||
GstByteReader reader;
|
||||
gint off = 0;
|
||||
gboolean ret;
|
||||
gboolean ret = FALSE;
|
||||
guint code;
|
||||
guint8 *data;
|
||||
gsize size;
|
||||
|
||||
data = gst_buffer_map (buf, &size, NULL, GST_MAP_READ);
|
||||
gst_byte_reader_init (&reader, data, size);
|
||||
|
||||
retry:
|
||||
/* at least start code and subsequent byte */
|
||||
if (G_UNLIKELY (GST_BUFFER_SIZE (buf) - off < 5))
|
||||
return FALSE;
|
||||
if (G_UNLIKELY (size - off < 5))
|
||||
goto done;
|
||||
|
||||
/* avoid stale cached parsing state */
|
||||
if (!(frame->flags & GST_BASE_PARSE_FRAME_FLAG_PARSING)) {
|
||||
|
@ -360,24 +363,24 @@ retry:
|
|||
}
|
||||
|
||||
off = gst_byte_reader_masked_scan_uint32 (&reader, 0xffffff00, 0x00000100,
|
||||
off, GST_BUFFER_SIZE (buf) - off);
|
||||
off, size - off);
|
||||
|
||||
GST_LOG_OBJECT (mp4vparse, "possible sync at buffer offset %d", off);
|
||||
|
||||
/* didn't find anything that looks like a sync word, skip */
|
||||
if (G_UNLIKELY (off < 0)) {
|
||||
*skipsize = GST_BUFFER_SIZE (buf) - 3;
|
||||
return FALSE;
|
||||
*skipsize = size - 3;
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* possible frame header, but not at offset 0? skip bytes before sync */
|
||||
if (G_UNLIKELY (off > 0)) {
|
||||
*skipsize = off;
|
||||
return FALSE;
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* ensure start code looks like a real starting start code */
|
||||
code = GST_BUFFER_DATA (buf)[3];
|
||||
code = data[3];
|
||||
switch (code) {
|
||||
case MPEG4_VOP_STARTCODE:
|
||||
case MPEG4_VOS_STARTCODE:
|
||||
|
@ -405,20 +408,20 @@ next:
|
|||
off++;
|
||||
/* so now we have start code at start of data; locate next start code */
|
||||
off = gst_byte_reader_masked_scan_uint32 (&reader, 0xffffff00, 0x00000100,
|
||||
off, GST_BUFFER_SIZE (buf) - off);
|
||||
off, size - off);
|
||||
|
||||
GST_LOG_OBJECT (mp4vparse, "next start code at %d", off);
|
||||
if (off < 0) {
|
||||
/* if draining, take all */
|
||||
if (GST_BASE_PARSE_DRAINING (parse)) {
|
||||
off = GST_BUFFER_SIZE (buf);
|
||||
off = size;
|
||||
ret = TRUE;
|
||||
} else {
|
||||
/* resume scan where we left it */
|
||||
mp4vparse->last_sc = GST_BUFFER_SIZE (buf) - 4;
|
||||
mp4vparse->last_sc = size - 4;
|
||||
/* request best next available */
|
||||
*framesize = G_MAXUINT;
|
||||
return FALSE;
|
||||
goto done;
|
||||
}
|
||||
} else {
|
||||
/* decide whether this startcode ends a frame */
|
||||
|
@ -431,6 +434,9 @@ next:
|
|||
goto next;
|
||||
}
|
||||
|
||||
done:
|
||||
gst_buffer_unmap (buf, data, size);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -440,14 +446,14 @@ gst_mpeg4vparse_update_src_caps (GstMpeg4VParse * mp4vparse)
|
|||
GstCaps *caps = NULL;
|
||||
|
||||
/* only update if no src caps yet or explicitly triggered */
|
||||
if (G_LIKELY (GST_PAD_CAPS (GST_BASE_PARSE_SRC_PAD (mp4vparse)) &&
|
||||
if (G_LIKELY (gst_pad_has_current_caps (GST_BASE_PARSE_SRC_PAD (mp4vparse)) &&
|
||||
!mp4vparse->update_caps))
|
||||
return;
|
||||
|
||||
/* carry over input caps as much as possible; override with our own stuff */
|
||||
caps = GST_PAD_CAPS (GST_BASE_PARSE_SINK_PAD (mp4vparse));
|
||||
caps = gst_pad_get_current_caps (GST_BASE_PARSE_SINK_PAD (mp4vparse));
|
||||
if (caps) {
|
||||
caps = gst_caps_copy (caps);
|
||||
caps = gst_caps_make_writable (caps);
|
||||
} else {
|
||||
caps = gst_caps_new_simple ("video/mpeg",
|
||||
"mpegversion", G_TYPE_INT, 4, NULL);
|
||||
|
@ -521,6 +527,20 @@ gst_mpeg4vparse_parse_frame (GstBaseParse * parse, GstBaseParseFrame * frame)
|
|||
return GST_FLOW_OK;
|
||||
}
|
||||
|
||||
static gint
|
||||
compare_buffers (GstBuffer * buf1, GstBuffer * buf2)
|
||||
{
|
||||
gpointer data;
|
||||
gsize size;
|
||||
gint ret;
|
||||
|
||||
data = gst_buffer_map (buf2, &size, NULL, GST_MAP_READ);
|
||||
ret = gst_buffer_memcmp (buf1, 0, data, size);
|
||||
gst_buffer_unmap (buf2, data, size);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static GstFlowReturn
|
||||
gst_mpeg4vparse_pre_push_frame (GstBaseParse * parse, GstBaseParseFrame * frame)
|
||||
{
|
||||
|
@ -555,15 +575,14 @@ gst_mpeg4vparse_pre_push_frame (GstBaseParse * parse, GstBaseParseFrame * frame)
|
|||
GST_LOG_OBJECT (parse, "inserting config in stream");
|
||||
|
||||
/* avoid inserting duplicate config */
|
||||
if ((GST_BUFFER_SIZE (buffer) < GST_BUFFER_SIZE (mp4vparse->config)) ||
|
||||
memcmp (GST_BUFFER_DATA (buffer),
|
||||
GST_BUFFER_DATA (mp4vparse->config),
|
||||
GST_BUFFER_SIZE (mp4vparse->config))) {
|
||||
if ((gst_buffer_get_size (buffer) <
|
||||
gst_buffer_get_size (mp4vparse->config))
|
||||
|| compare_buffers (buffer, mp4vparse->config)) {
|
||||
GstBuffer *superbuf;
|
||||
|
||||
/* insert header */
|
||||
superbuf = gst_buffer_merge (mp4vparse->config, buffer);
|
||||
gst_buffer_copy_metadata (superbuf, buffer, GST_BUFFER_COPY_ALL);
|
||||
gst_buffer_copy_into (superbuf, buffer, GST_BUFFER_COPY_ALL, 0, -1);
|
||||
gst_buffer_replace (&frame->buffer, superbuf);
|
||||
gst_buffer_unref (superbuf);
|
||||
} else {
|
||||
|
@ -594,11 +613,15 @@ gst_mpeg4vparse_set_caps (GstBaseParse * parse, GstCaps * caps)
|
|||
|
||||
if ((value = gst_structure_get_value (s, "codec_data")) != NULL
|
||||
&& (buf = gst_value_get_buffer (value))) {
|
||||
guint8 *data;
|
||||
gsize size;
|
||||
|
||||
data = gst_buffer_map (buf, &size, NULL, GST_MAP_READ);
|
||||
/* best possible parse attempt,
|
||||
* src caps are based on sink caps so it will end up in there
|
||||
* whether sucessful or not */
|
||||
gst_mpeg4vparse_process_config (mp4vparse, GST_BUFFER_DATA (buf),
|
||||
GST_BUFFER_SIZE (buf));
|
||||
gst_mpeg4vparse_process_config (mp4vparse, data, size);
|
||||
gst_buffer_unmap (buf, data, size);
|
||||
}
|
||||
|
||||
/* let's not interfere and accept regardless of config parsing success */
|
||||
|
|
Loading…
Reference in a new issue