mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2025-01-11 09:55:36 +00:00
mpegvideoparse: Port to the new mpeg parsing library
This commit is contained in:
parent
c64b99339c
commit
a983b29a49
6 changed files with 160 additions and 526 deletions
|
@ -4,10 +4,13 @@ libgstvideoparsersbad_la_SOURCES = plugin.c \
|
|||
h263parse.c gsth263parse.c \
|
||||
gsth264parse.c h264parse.c \
|
||||
gstdiracparse.c dirac_parse.c \
|
||||
gstmpegvideoparse.c mpegvideoparse.c
|
||||
gstmpegvideoparse.c
|
||||
|
||||
libgstvideoparsersbad_la_CFLAGS = \
|
||||
$(GST_PLUGINS_BAD_CFLAGS) $(GST_PLUGINS_BASE_CFLAGS) \
|
||||
$(GST_BASE_CFLAGS) $(GST_CFLAGS)
|
||||
libgstvideoparsersbad_la_LIBADD = \
|
||||
libgstvideoparsersbad_la_LIBADD = $(GST_PLUGINS_BASE_LIBS) \
|
||||
$(top_builddir)/gst-libs/gst/codecparsers/libgstcodecparsers-$(GST_MAJORMINOR).la \
|
||||
$(GST_BASE_LIBS) $(GST_LIBS)
|
||||
libgstvideoparsersbad_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
|
||||
libgstvideoparsersbad_la_LIBTOOLFLAGS = --tag=disable-static
|
||||
|
@ -15,7 +18,7 @@ libgstvideoparsersbad_la_LIBTOOLFLAGS = --tag=disable-static
|
|||
noinst_HEADERS = gsth263parse.h h263parse.h \
|
||||
gsth264parse.h h264parse.h \
|
||||
gstdiracparse.h dirac_parse.h \
|
||||
gstmpegvideoparse.h mpegvideoparse.h
|
||||
gstmpegvideoparse.h
|
||||
|
||||
Android.mk: Makefile.am $(BUILT_SOURCES)
|
||||
androgenizer \
|
||||
|
|
|
@ -1,8 +1,10 @@
|
|||
/* GStreamer
|
||||
* Copyright (C) <2007> Jan Schmidt <thaytan@mad.scientist.com>
|
||||
* Copyright (C) <2011> Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
|
||||
* Copyright (C) <2011> Collabora Multimedia
|
||||
* Copyright (C) <2011> Thibault Saunier <thibault.saunier@collabora.com>
|
||||
* Copyright (C) <2011> Collabora ltd
|
||||
* Copyright (C) <2011> Nokia Corporation
|
||||
* Copyright (C) <2011> Intel Corporation
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public
|
||||
|
@ -168,6 +170,7 @@ gst_mpegv_parse_class_init (GstMpegvParseClass * klass)
|
|||
static void
|
||||
gst_mpegv_parse_init (GstMpegvParse * parse, GstMpegvParseClass * g_class)
|
||||
{
|
||||
parse->mpeg_version = 0;
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -175,7 +178,7 @@ gst_mpegv_parse_reset_frame (GstMpegvParse * mpvparse)
|
|||
{
|
||||
/* done parsing; reset state */
|
||||
mpvparse->last_sc = -1;
|
||||
mpvparse->seq_offset = -1;
|
||||
mpvparse->seq_offset = G_MAXUINT;
|
||||
mpvparse->pic_offset = -1;
|
||||
}
|
||||
|
||||
|
@ -187,7 +190,9 @@ gst_mpegv_parse_reset (GstMpegvParse * mpvparse)
|
|||
mpvparse->update_caps = TRUE;
|
||||
|
||||
gst_buffer_replace (&mpvparse->config, NULL);
|
||||
memset (&mpvparse->params, 0, sizeof (mpvparse->params));
|
||||
memset (&mpvparse->sequencehdr, 0, sizeof (mpvparse->sequencehdr));
|
||||
memset (&mpvparse->sequenceext, 0, sizeof (mpvparse->sequenceext));
|
||||
memset (&mpvparse->pichdr, 0, sizeof (mpvparse->pichdr));
|
||||
}
|
||||
|
||||
static gboolean
|
||||
|
@ -217,23 +222,45 @@ gst_mpegv_parse_stop (GstBaseParse * parse)
|
|||
}
|
||||
|
||||
static gboolean
|
||||
gst_mpegv_parse_process_config (GstMpegvParse * mpvparse, const guint8 * data,
|
||||
gsize size)
|
||||
gst_mpegv_parse_process_config (GstMpegvParse * mpvparse, GstBuffer * buf,
|
||||
guint size)
|
||||
{
|
||||
GList *tmp;
|
||||
guint8 *data = GST_BUFFER_DATA (buf);
|
||||
data = data + mpvparse->seq_offset;
|
||||
|
||||
/* only do stuff if something new */
|
||||
if (mpvparse->config && size == GST_BUFFER_SIZE (mpvparse->config) &&
|
||||
memcmp (GST_BUFFER_DATA (mpvparse->config), data, size) == 0)
|
||||
return TRUE;
|
||||
|
||||
if (!gst_mpeg_video_params_parse_config (&mpvparse->params, data, size)) {
|
||||
GST_DEBUG_OBJECT (mpvparse, "failed to parse config data (size %"
|
||||
G_GSSIZE_FORMAT ")", size);
|
||||
if (!gst_mpeg_video_parse_sequence_header (&mpvparse->sequencehdr, data,
|
||||
GST_BUFFER_SIZE (buf) - mpvparse->seq_offset, 0)) {
|
||||
GST_DEBUG_OBJECT (mpvparse,
|
||||
"failed to parse config data (size %" G_GSSIZE_FORMAT ") at offset %d",
|
||||
size, mpvparse->seq_offset);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
GST_LOG_OBJECT (mpvparse, "accepting parsed config size %" G_GSSIZE_FORMAT,
|
||||
size);
|
||||
|
||||
/* Set mpeg version, and parse sequence extension */
|
||||
if (mpvparse->mpeg_version <= 0) {
|
||||
GstMpegVideoTypeOffsetSize *tpoffsz;
|
||||
|
||||
mpvparse->mpeg_version = 1;
|
||||
for (tmp = mpvparse->typeoffsize; tmp; tmp = tmp->next) {
|
||||
tpoffsz = tmp->data;
|
||||
|
||||
if (tpoffsz->type == GST_MPEG_VIDEO_PACKET_EXTENSION) {
|
||||
mpvparse->mpeg_version = 2;
|
||||
gst_mpeg_video_parse_sequence_extension (&mpvparse->sequenceext,
|
||||
GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf), tpoffsz->offset);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* parsing ok, so accept it as new config */
|
||||
if (mpvparse->config != NULL)
|
||||
gst_buffer_unref (mpvparse->config);
|
||||
|
@ -309,22 +336,18 @@ picture_type_name (guint8 pct)
|
|||
/* for off == 0 initial code; returns TRUE if code starts a frame,
|
||||
* otherwise returns TRUE if code terminates preceding frame */
|
||||
static gboolean
|
||||
gst_mpegv_parse_process_sc (GstMpegvParse * mpvparse, GstBuffer * buf, gint off)
|
||||
gst_mpegv_parse_process_sc (GstMpegvParse * mpvparse,
|
||||
GstBuffer * buf, guint off, guint8 code)
|
||||
{
|
||||
gboolean ret = FALSE, do_seq = TRUE;
|
||||
guint8 *data;
|
||||
guint code;
|
||||
gboolean ret = FALSE, packet = TRUE;
|
||||
|
||||
g_return_val_if_fail (buf && GST_BUFFER_SIZE (buf) >= 4, FALSE);
|
||||
|
||||
data = GST_BUFFER_DATA (buf);
|
||||
code = data[off + 3];
|
||||
|
||||
GST_LOG_OBJECT (mpvparse, "process startcode %x (%s)", code,
|
||||
picture_start_code_name (code));
|
||||
|
||||
switch (code) {
|
||||
case MPEG_PACKET_PICTURE:
|
||||
case GST_MPEG_VIDEO_PACKET_PICTURE:
|
||||
GST_LOG_OBJECT (mpvparse, "startcode is PICTURE");
|
||||
/* picture is aggregated with preceding sequence/gop, if any.
|
||||
* so, picture start code only ends if already a previous one */
|
||||
|
@ -332,103 +355,64 @@ gst_mpegv_parse_process_sc (GstMpegvParse * mpvparse, GstBuffer * buf, gint off)
|
|||
mpvparse->pic_offset = off;
|
||||
else
|
||||
ret = TRUE;
|
||||
if (!off)
|
||||
if (off == 4)
|
||||
ret = TRUE;
|
||||
break;
|
||||
case MPEG_PACKET_SEQUENCE:
|
||||
case GST_MPEG_VIDEO_PACKET_SEQUENCE:
|
||||
GST_LOG_OBJECT (mpvparse, "startcode is SEQUENCE");
|
||||
if (off == 0)
|
||||
if (off < mpvparse->seq_offset)
|
||||
mpvparse->seq_offset = off;
|
||||
ret = TRUE;
|
||||
break;
|
||||
case MPEG_PACKET_GOP:
|
||||
case GST_MPEG_VIDEO_PACKET_GOP:
|
||||
GST_LOG_OBJECT (mpvparse, "startcode is GOP");
|
||||
if (mpvparse->seq_offset >= 0)
|
||||
if (mpvparse->seq_offset < G_MAXUINT)
|
||||
ret = mpvparse->gop_split;
|
||||
else
|
||||
ret = TRUE;
|
||||
break;
|
||||
default:
|
||||
do_seq = FALSE;
|
||||
packet = FALSE;
|
||||
break;
|
||||
}
|
||||
|
||||
/* process config data */
|
||||
if (G_UNLIKELY (mpvparse->seq_offset >= 0 && off && do_seq)) {
|
||||
g_assert (mpvparse->seq_offset == 0);
|
||||
gst_mpegv_parse_process_config (mpvparse, GST_BUFFER_DATA (buf), off);
|
||||
/* avoid accepting again for a PICTURE sc following a GOP sc */
|
||||
mpvparse->seq_offset = -1;
|
||||
if (mpvparse->seq_offset != G_MAXUINT && off != mpvparse->seq_offset &&
|
||||
packet) {
|
||||
gst_mpegv_parse_process_config (mpvparse, buf, off - mpvparse->seq_offset);
|
||||
mpvparse->seq_offset = G_MAXUINT;
|
||||
}
|
||||
|
||||
/* extract some picture info if there is any in the frame being terminated */
|
||||
if (G_UNLIKELY (ret && off)) {
|
||||
if (G_LIKELY (mpvparse->pic_offset >= 0 && mpvparse->pic_offset < off)) {
|
||||
if (G_LIKELY (GST_BUFFER_SIZE (buf) >= mpvparse->pic_offset + 6)) {
|
||||
gint pct = (data[mpvparse->pic_offset + 5] >> 3) & 0x7;
|
||||
|
||||
GST_LOG_OBJECT (mpvparse, "picture_coding_type %d (%s)", pct,
|
||||
picture_type_name (pct));
|
||||
mpvparse->intra_frame = (pct == MPEG_PICTURE_TYPE_I);
|
||||
} else {
|
||||
GST_WARNING_OBJECT (mpvparse, "no data following PICTURE startcode");
|
||||
mpvparse->intra_frame = FALSE;
|
||||
}
|
||||
} else {
|
||||
/* frame without picture must be some config, consider as keyframe */
|
||||
mpvparse->intra_frame = TRUE;
|
||||
}
|
||||
GST_LOG_OBJECT (mpvparse, "ending frame of size %d, is intra %d", off,
|
||||
mpvparse->intra_frame);
|
||||
if (ret && mpvparse->pic_offset >= 0 && mpvparse->pic_offset < off) {
|
||||
if (gst_mpeg_video_parse_picture_header (&mpvparse->pichdr,
|
||||
GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf), mpvparse->pic_offset))
|
||||
GST_LOG_OBJECT (mpvparse, "picture_coding_type %d (%s), ending"
|
||||
"frame of size %d", mpvparse->pichdr.pic_type,
|
||||
picture_type_name (mpvparse->pichdr.pic_type), off - 4);
|
||||
else
|
||||
GST_LOG_OBJECT (mpvparse, "Couldn't parse picture at offset %d",
|
||||
mpvparse->pic_offset);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline guint
|
||||
scan_for_start_codes (const GstByteReader * reader, guint offset, guint size)
|
||||
static inline gint
|
||||
get_frame_size (GstMpegvParse * mpvparse, GstBuffer * buf, GList * l_codoffsz)
|
||||
{
|
||||
const guint8 *data;
|
||||
guint32 state;
|
||||
guint i;
|
||||
GList *tmp;
|
||||
GstMpegVideoTypeOffsetSize *codoffsz;
|
||||
|
||||
g_return_val_if_fail (size > 0, -1);
|
||||
g_return_val_if_fail ((guint64) offset + size <= reader->size - reader->byte,
|
||||
-1);
|
||||
for (tmp = l_codoffsz; tmp; tmp = tmp->next) {
|
||||
codoffsz = tmp->data;
|
||||
|
||||
/* we can't find the pattern with less than 4 bytes */
|
||||
if (G_UNLIKELY (size < 4))
|
||||
return -1;
|
||||
GST_LOG_OBJECT (mpvparse, "next start code at %d", codoffsz->offset);
|
||||
|
||||
data = reader->data + reader->byte + offset;
|
||||
|
||||
/* set the state to something that does not match */
|
||||
state = 0xffffffff;
|
||||
|
||||
/* now find data */
|
||||
for (i = 0; i < size; i++) {
|
||||
/* throw away one byte and move in the next byte */
|
||||
state = ((state << 8) | data[i]);
|
||||
if (G_UNLIKELY ((state & 0xffffff00) == 0x00000100)) {
|
||||
/* we have a match but we need to have skipped at
|
||||
* least 4 bytes to fill the state. */
|
||||
if (G_LIKELY (i >= 3))
|
||||
return offset + i - 3;
|
||||
}
|
||||
|
||||
/* Accelerate search for start code */
|
||||
if (data[i] > 1) {
|
||||
while (i < (size - 4) && data[i] > 1) {
|
||||
if (data[i + 3] > 1)
|
||||
i += 4;
|
||||
else
|
||||
i += 1;
|
||||
}
|
||||
state = 0x00000100;
|
||||
}
|
||||
if (gst_mpegv_parse_process_sc (mpvparse, buf, codoffsz->offset,
|
||||
codoffsz->type))
|
||||
return codoffsz->offset - 4;
|
||||
}
|
||||
|
||||
/* nothing found */
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
@ -436,21 +420,10 @@ scan_for_start_codes (const GstByteReader * reader, guint offset, guint size)
|
|||
* see https://bugzilla.gnome.org/show_bug.cgi?id=650093 */
|
||||
#define GST_BASE_PARSE_FRAME_FLAG_PARSING 0x10000
|
||||
|
||||
static gboolean
|
||||
gst_mpegv_parse_check_valid_frame (GstBaseParse * parse,
|
||||
GstBaseParseFrame * frame, guint * framesize, gint * skipsize)
|
||||
static inline void
|
||||
update_frame_parsing_status (GstMpegvParse * mpvparse,
|
||||
GstBaseParseFrame * frame)
|
||||
{
|
||||
GstMpegvParse *mpvparse = GST_MPEGVIDEO_PARSE (parse);
|
||||
GstBuffer *buf = frame->buffer;
|
||||
GstByteReader reader = GST_BYTE_READER_INIT_FROM_BUFFER (buf);
|
||||
gint off = 0;
|
||||
gboolean ret;
|
||||
|
||||
retry:
|
||||
/* at least start code and subsequent byte */
|
||||
if (G_UNLIKELY (GST_BUFFER_SIZE (buf) - off < 5))
|
||||
return FALSE;
|
||||
|
||||
/* avoid stale cached parsing state */
|
||||
if (!(frame->flags & GST_BASE_PARSE_FRAME_FLAG_PARSING)) {
|
||||
GST_LOG_OBJECT (mpvparse, "parsing new frame");
|
||||
|
@ -459,72 +432,75 @@ retry:
|
|||
} else {
|
||||
GST_LOG_OBJECT (mpvparse, "resuming frame parsing");
|
||||
}
|
||||
}
|
||||
|
||||
/* if already found a previous start code, e.g. start of frame, go for next */
|
||||
if (mpvparse->last_sc >= 0) {
|
||||
|
||||
static gboolean
|
||||
gst_mpegv_parse_check_valid_frame (GstBaseParse * parse,
|
||||
GstBaseParseFrame * frame, guint * framesize, gint * skipsize)
|
||||
{
|
||||
GstMpegvParse *mpvparse = GST_MPEGVIDEO_PARSE (parse);
|
||||
GstBuffer *buf = frame->buffer;
|
||||
gboolean ret = FALSE;
|
||||
GList *tmp;
|
||||
gint off = 0, fsize = -1;
|
||||
|
||||
update_frame_parsing_status (mpvparse, frame);
|
||||
|
||||
if (mpvparse->last_sc >= 0)
|
||||
off = mpvparse->last_sc;
|
||||
goto next;
|
||||
|
||||
mpvparse->typeoffsize =
|
||||
gst_mpeg_video_parse (GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf), off);
|
||||
|
||||
/* No sc found */
|
||||
if (mpvparse->typeoffsize == NULL)
|
||||
goto end;
|
||||
|
||||
/* Already found the start code looking for the end */
|
||||
if (mpvparse->last_sc >= 0) {
|
||||
*skipsize = 0;
|
||||
fsize = get_frame_size (mpvparse, buf, mpvparse->typeoffsize);
|
||||
|
||||
goto end;
|
||||
}
|
||||
|
||||
off = scan_for_start_codes (&reader, off, GST_BUFFER_SIZE (buf) - off);
|
||||
for (tmp = mpvparse->typeoffsize; tmp; tmp = g_list_next (tmp)) {
|
||||
GstMpegVideoTypeOffsetSize *codoffsz = tmp->data;
|
||||
|
||||
GST_LOG_OBJECT (mpvparse, "possible sync at buffer offset %d", off);
|
||||
GST_LOG_OBJECT (mpvparse, "next start code at %d", codoffsz->offset);
|
||||
|
||||
/* didn't find anything that looks like a sync word, skip */
|
||||
if (G_UNLIKELY (off < 0)) {
|
||||
*skipsize = GST_BUFFER_SIZE (buf) - 3;
|
||||
return FALSE;
|
||||
}
|
||||
if (codoffsz->size < 0)
|
||||
break;
|
||||
|
||||
/* possible frame header, but not at offset 0? skip bytes before sync */
|
||||
if (G_UNLIKELY (off > 0)) {
|
||||
*skipsize = off;
|
||||
return FALSE;
|
||||
}
|
||||
ret = gst_mpegv_parse_process_sc (mpvparse, buf, codoffsz->offset,
|
||||
codoffsz->type);
|
||||
|
||||
/* note: initial start code is assumed at offset 0 by subsequent code */
|
||||
|
||||
/* examine start code, see if it looks like an initial start code */
|
||||
if (gst_mpegv_parse_process_sc (mpvparse, buf, 0)) {
|
||||
/* found sc */
|
||||
mpvparse->last_sc = 0;
|
||||
} else {
|
||||
off++;
|
||||
goto retry;
|
||||
}
|
||||
|
||||
next:
|
||||
/* start is fine as of now */
|
||||
*skipsize = 0;
|
||||
/* position a bit further than last sc */
|
||||
off++;
|
||||
/* so now we have start code at start of data; locate next start code */
|
||||
off = scan_for_start_codes (&reader, off, GST_BUFFER_SIZE (buf) - off);
|
||||
|
||||
GST_LOG_OBJECT (mpvparse, "next start code at %d", off);
|
||||
if (off < 0) {
|
||||
/* if draining, take all */
|
||||
if (GST_BASE_PARSE_DRAINING (parse)) {
|
||||
off = GST_BUFFER_SIZE (buf);
|
||||
ret = TRUE;
|
||||
} else {
|
||||
/* resume scan where we left it */
|
||||
mpvparse->last_sc = GST_BUFFER_SIZE (buf) - 4;
|
||||
/* request best next available */
|
||||
*framesize = G_MAXUINT;
|
||||
return FALSE;
|
||||
if (ret) {
|
||||
*skipsize = 0;
|
||||
fsize = get_frame_size (mpvparse, buf, tmp->next);
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
/* decide whether this startcode ends a frame */
|
||||
ret = gst_mpegv_parse_process_sc (mpvparse, buf, off);
|
||||
}
|
||||
|
||||
if (ret) {
|
||||
*framesize = off;
|
||||
end:
|
||||
if (fsize > 0) {
|
||||
*framesize = fsize;
|
||||
ret = TRUE;
|
||||
} else if (GST_BASE_PARSE_DRAINING (parse)) {
|
||||
*framesize = GST_BUFFER_SIZE (buf);
|
||||
ret = TRUE;
|
||||
} else {
|
||||
goto next;
|
||||
/* resume scan where we left it */
|
||||
mpvparse->last_sc = GST_BUFFER_SIZE (buf);
|
||||
/* request best next available */
|
||||
*framesize = G_MAXUINT;
|
||||
ret = FALSE;
|
||||
}
|
||||
|
||||
g_list_free_full (mpvparse->typeoffsize, (GDestroyNotify) g_free);
|
||||
mpvparse->typeoffsize = NULL;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -550,22 +526,23 @@ gst_mpegv_parse_update_src_caps (GstMpegvParse * mpvparse)
|
|||
* config data, so we should at least know about version.
|
||||
* If not, it means it has been requested not to drop data, and
|
||||
* upstream and/or app must know what they are doing ... */
|
||||
if (G_LIKELY (mpvparse->params.mpeg_version))
|
||||
|
||||
if (G_LIKELY (mpvparse->mpeg_version))
|
||||
gst_caps_set_simple (caps,
|
||||
"mpegversion", G_TYPE_INT, mpvparse->params.mpeg_version, NULL);
|
||||
"mpegversion", G_TYPE_INT, mpvparse->mpeg_version, NULL);
|
||||
|
||||
gst_caps_set_simple (caps, "systemstream", G_TYPE_BOOLEAN, FALSE,
|
||||
"parsed", G_TYPE_BOOLEAN, TRUE, NULL);
|
||||
|
||||
if (mpvparse->params.width > 0 && mpvparse->params.height > 0) {
|
||||
gst_caps_set_simple (caps, "width", G_TYPE_INT, mpvparse->params.width,
|
||||
"height", G_TYPE_INT, mpvparse->params.height, NULL);
|
||||
if (mpvparse->sequencehdr.width > 0 && mpvparse->sequencehdr.height > 0) {
|
||||
gst_caps_set_simple (caps, "width", G_TYPE_INT, mpvparse->sequencehdr.width,
|
||||
"height", G_TYPE_INT, mpvparse->sequencehdr.height, NULL);
|
||||
}
|
||||
|
||||
/* perhaps we have a framerate */
|
||||
if (mpvparse->params.fps_n > 0 && mpvparse->params.fps_d > 0) {
|
||||
gint fps_num = mpvparse->params.fps_n;
|
||||
gint fps_den = mpvparse->params.fps_d;
|
||||
if (mpvparse->sequencehdr.fps_n > 0 && mpvparse->sequencehdr.fps_d > 0) {
|
||||
gint fps_num = mpvparse->sequencehdr.fps_n;
|
||||
gint fps_den = mpvparse->sequencehdr.fps_d;
|
||||
GstClockTime latency = gst_util_uint64_scale (GST_SECOND, fps_den, fps_num);
|
||||
|
||||
gst_caps_set_simple (caps, "framerate",
|
||||
|
@ -576,9 +553,9 @@ gst_mpegv_parse_update_src_caps (GstMpegvParse * mpvparse)
|
|||
}
|
||||
|
||||
/* or pixel-aspect-ratio */
|
||||
if (mpvparse->params.par_w && mpvparse->params.par_h > 0) {
|
||||
if (mpvparse->sequencehdr.par_w && mpvparse->sequencehdr.par_h > 0) {
|
||||
gst_caps_set_simple (caps, "pixel-aspect-ratio", GST_TYPE_FRACTION,
|
||||
mpvparse->params.par_w, mpvparse->params.par_h, NULL);
|
||||
mpvparse->sequencehdr.par_w, mpvparse->sequencehdr.par_h, NULL);
|
||||
}
|
||||
|
||||
if (mpvparse->config != NULL) {
|
||||
|
@ -586,9 +563,9 @@ gst_mpegv_parse_update_src_caps (GstMpegvParse * mpvparse)
|
|||
GST_TYPE_BUFFER, mpvparse->config, NULL);
|
||||
}
|
||||
|
||||
if (mpvparse->params.mpeg_version == 2) {
|
||||
const guint profile_c = mpvparse->params.profile;
|
||||
const guint level_c = mpvparse->params.level;
|
||||
if (mpvparse->mpeg_version == 2) {
|
||||
const guint profile_c = mpvparse->sequenceext.profile;
|
||||
const guint level_c = mpvparse->sequenceext.level;
|
||||
const gchar *profile = NULL, *level = NULL;
|
||||
/*
|
||||
* Profile indication - 1 => High, 2 => Spatially Scalable,
|
||||
|
@ -657,7 +634,7 @@ gst_mpegv_parse_parse_frame (GstBaseParse * parse, GstBaseParseFrame * frame)
|
|||
|
||||
gst_mpegv_parse_update_src_caps (mpvparse);
|
||||
|
||||
if (G_UNLIKELY (mpvparse->intra_frame))
|
||||
if (G_UNLIKELY (mpvparse->pichdr.pic_type == GST_MPEG_VIDEO_PICTURE_TYPE_I))
|
||||
GST_BUFFER_FLAG_UNSET (buffer, GST_BUFFER_FLAG_DELTA_UNIT);
|
||||
else
|
||||
GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_FLAG_DELTA_UNIT);
|
||||
|
@ -694,8 +671,7 @@ gst_mpegv_parse_set_caps (GstBaseParse * parse, GstCaps * caps)
|
|||
/* best possible parse attempt,
|
||||
* src caps are based on sink caps so it will end up in there
|
||||
* whether sucessful or not */
|
||||
gst_mpegv_parse_process_config (mpvparse, GST_BUFFER_DATA (buf),
|
||||
GST_BUFFER_SIZE (buf));
|
||||
gst_mpegv_parse_process_config (mpvparse, buf, GST_BUFFER_SIZE (buf));
|
||||
}
|
||||
|
||||
/* let's not interfere and accept regardless of config parsing success */
|
||||
|
|
|
@ -1,8 +1,10 @@
|
|||
/* GStreamer
|
||||
* Copyright (C) <2007> Jan Schmidt <thaytan@mad.scientist.com>
|
||||
* Copyright (C) <2011> Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
|
||||
* Copyright (C) <2011> Collabora Multimedia
|
||||
* Copyright (C) <2011> Thibault Saunier <thibault.saunier@collabora.com>
|
||||
* Copyright (C) <2011> Collabora ltd
|
||||
* Copyright (C) <2011> Nokia Corporation
|
||||
* Copyright (C) <2011> Intel Corporation
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public
|
||||
|
@ -26,7 +28,7 @@
|
|||
#include <gst/gst.h>
|
||||
#include <gst/base/gstbaseparse.h>
|
||||
|
||||
#include "mpegvideoparse.h"
|
||||
#include <gst/codecparsers/gstmpegvideoparser.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
|
@ -49,15 +51,18 @@ struct _GstMpegvParse {
|
|||
GstBaseParse element;
|
||||
|
||||
/* parse state */
|
||||
GList *typeoffsize;
|
||||
gint last_sc;
|
||||
gint seq_offset;
|
||||
gint pic_offset;
|
||||
gboolean intra_frame;
|
||||
gboolean update_caps;
|
||||
|
||||
GstBuffer *config;
|
||||
guint8 profile;
|
||||
MPEGVParams params;
|
||||
guint mpeg_version;
|
||||
GstMpegVideoSequenceHdr sequencehdr;
|
||||
GstMpegVideoSequenceExt sequenceext;
|
||||
GstMpegVideoPictureHdr pichdr;
|
||||
|
||||
/* properties */
|
||||
gboolean drop;
|
||||
|
|
|
@ -1,274 +0,0 @@
|
|||
/* GStreamer
|
||||
* Copyright (C) <2007> Jan Schmidt <thaytan@mad.scientist.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||
* Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include "config.h"
|
||||
#endif
|
||||
|
||||
#include "mpegvideoparse.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <gst/base/gstbitreader.h>
|
||||
|
||||
GST_DEBUG_CATEGORY_EXTERN (mpegv_parse_debug);
|
||||
#define GST_CAT_DEFAULT mpegv_parse_debug
|
||||
|
||||
|
||||
#define GET_BITS(b, num, bits) G_STMT_START { \
|
||||
if (!gst_bit_reader_get_bits_uint32(b, bits, num)) \
|
||||
goto failed; \
|
||||
GST_TRACE ("parsed %d bits: %d", num, *(bits)); \
|
||||
} G_STMT_END
|
||||
|
||||
#define MARKER_BIT(b) G_STMT_START { \
|
||||
guint32 i; \
|
||||
GET_BITS(b, 1, &i); \
|
||||
if (i != 0x1) \
|
||||
goto failed; \
|
||||
} G_STMT_END
|
||||
|
||||
static inline gboolean
|
||||
find_start_code (GstBitReader * b)
|
||||
{
|
||||
guint32 bits;
|
||||
|
||||
/* 0 bits until byte aligned */
|
||||
while (b->bit != 0) {
|
||||
GET_BITS (b, 1, &bits);
|
||||
}
|
||||
|
||||
/* 0 bytes until startcode */
|
||||
while (gst_bit_reader_peek_bits_uint32 (b, &bits, 32)) {
|
||||
if (bits >> 8 == 0x1) {
|
||||
return TRUE;
|
||||
} else {
|
||||
gst_bit_reader_skip (b, 8);
|
||||
}
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
|
||||
failed:
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gst_mpeg_video_params_parse_extension (MPEGVParams * params, GstBitReader * br)
|
||||
{
|
||||
guint32 bits;
|
||||
|
||||
/* double-check */
|
||||
GET_BITS (br, 32, &bits);
|
||||
if (bits != 0x100 + MPEG_PACKET_EXTENSION)
|
||||
goto failed;
|
||||
|
||||
/* extension_start_code identifier */
|
||||
GET_BITS (br, 4, &bits);
|
||||
|
||||
/* profile_and_level_indication */
|
||||
GET_BITS (br, 4, &bits);
|
||||
params->profile = bits;
|
||||
GET_BITS (br, 4, &bits);
|
||||
params->level = bits;
|
||||
|
||||
/* progressive_sequence */
|
||||
GET_BITS (br, 1, &bits);
|
||||
params->progressive = bits;
|
||||
|
||||
/* chroma_format */
|
||||
GET_BITS (br, 2, &bits);
|
||||
|
||||
/* horizontal_size_extension */
|
||||
GET_BITS (br, 2, &bits);
|
||||
params->width += (bits << 12);
|
||||
/* vertical_size_extension */
|
||||
GET_BITS (br, 2, &bits);
|
||||
params->height += (bits << 12);
|
||||
|
||||
/* bit_rate_extension */
|
||||
GET_BITS (br, 12, &bits);
|
||||
if (params->bitrate)
|
||||
params->bitrate += (bits << 18) * 400;
|
||||
/* marker_bit */
|
||||
MARKER_BIT (br);
|
||||
/* vbv_buffer_size_extension */
|
||||
GET_BITS (br, 8, &bits);
|
||||
/* low_delay */
|
||||
GET_BITS (br, 1, &bits);
|
||||
|
||||
/* frame_rate_extension_n */
|
||||
GET_BITS (br, 2, &bits);
|
||||
params->fps_n *= bits + 1;
|
||||
/* frame_rate_extension_d */
|
||||
GET_BITS (br, 5, &bits);
|
||||
params->fps_d *= bits + 1;
|
||||
|
||||
return TRUE;
|
||||
|
||||
/* ERRORS */
|
||||
failed:
|
||||
{
|
||||
GST_WARNING ("Failed to parse sequence extension");
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
/* Set the Pixel Aspect Ratio in our hdr from a DAR code in the data */
|
||||
static void
|
||||
set_par_from_dar (MPEGVParams * params, guint8 asr_code)
|
||||
{
|
||||
/* Pixel_width = DAR_width * display_vertical_size */
|
||||
/* Pixel_height = DAR_height * display_horizontal_size */
|
||||
switch (asr_code) {
|
||||
case 0x02: /* 3:4 DAR = 4:3 pixels */
|
||||
params->par_w = 4 * params->height;
|
||||
params->par_h = 3 * params->width;
|
||||
break;
|
||||
case 0x03: /* 9:16 DAR */
|
||||
params->par_w = 16 * params->height;
|
||||
params->par_h = 9 * params->width;
|
||||
break;
|
||||
case 0x04: /* 1:2.21 DAR */
|
||||
params->par_w = 221 * params->height;
|
||||
params->par_h = 100 * params->width;
|
||||
break;
|
||||
case 0x01: /* Square pixels */
|
||||
params->par_w = params->par_h = 1;
|
||||
break;
|
||||
default:
|
||||
GST_DEBUG ("unknown/invalid aspect_ratio_information %d", asr_code);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
set_fps_from_code (MPEGVParams * params, guint8 fps_code)
|
||||
{
|
||||
const gint framerates[][2] = {
|
||||
{30, 1}, {24000, 1001}, {24, 1}, {25, 1},
|
||||
{30000, 1001}, {30, 1}, {50, 1}, {60000, 1001},
|
||||
{60, 1}, {30, 1}
|
||||
};
|
||||
|
||||
if (fps_code && fps_code < 10) {
|
||||
params->fps_n = framerates[fps_code][0];
|
||||
params->fps_d = framerates[fps_code][1];
|
||||
} else {
|
||||
GST_DEBUG ("unknown/invalid frame_rate_code %d", fps_code);
|
||||
/* Force a valid framerate */
|
||||
/* FIXME or should this be kept unknown ?? */
|
||||
params->fps_n = 30000;
|
||||
params->fps_d = 1001;
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gst_mpeg_video_params_parse_sequence (MPEGVParams * params, GstBitReader * br)
|
||||
{
|
||||
guint32 bits;
|
||||
|
||||
GET_BITS (br, 32, &bits);
|
||||
if (bits != 0x100 + MPEG_PACKET_SEQUENCE)
|
||||
goto failed;
|
||||
|
||||
/* assume MPEG-1 till otherwise discovered */
|
||||
params->mpeg_version = 1;
|
||||
|
||||
GET_BITS (br, 12, &bits);
|
||||
params->width = bits;
|
||||
GET_BITS (br, 12, &bits);
|
||||
params->height = bits;
|
||||
|
||||
GET_BITS (br, 4, &bits);
|
||||
set_par_from_dar (params, bits);
|
||||
GET_BITS (br, 4, &bits);
|
||||
set_fps_from_code (params, bits);
|
||||
|
||||
GET_BITS (br, 18, &bits);
|
||||
if (bits == 0x3ffff) {
|
||||
/* VBR stream */
|
||||
params->bitrate = 0;
|
||||
} else {
|
||||
/* Value in header is in units of 400 bps */
|
||||
params->bitrate *= 400;
|
||||
}
|
||||
|
||||
/* skip 1 + VBV buffer size */
|
||||
if (!gst_bit_reader_skip (br, 11))
|
||||
goto failed;
|
||||
|
||||
/* constrained_parameters_flag */
|
||||
GET_BITS (br, 1, &bits);
|
||||
|
||||
/* load_intra_quantiser_matrix */
|
||||
GET_BITS (br, 1, &bits);
|
||||
if (bits) {
|
||||
if (!gst_bit_reader_skip (br, 8 * 64))
|
||||
goto failed;
|
||||
}
|
||||
|
||||
/* load_non_intra_quantiser_matrix */
|
||||
GET_BITS (br, 1, &bits);
|
||||
if (bits) {
|
||||
if (!gst_bit_reader_skip (br, 8 * 64))
|
||||
goto failed;
|
||||
}
|
||||
|
||||
/* check for MPEG-2 sequence extension */
|
||||
while (find_start_code (br)) {
|
||||
gst_bit_reader_peek_bits_uint32 (br, &bits, 32);
|
||||
if (bits == 0x100 + MPEG_PACKET_EXTENSION) {
|
||||
if (!gst_mpeg_video_params_parse_extension (params, br))
|
||||
goto failed;
|
||||
params->mpeg_version = 2;
|
||||
}
|
||||
}
|
||||
|
||||
/* dump some info */
|
||||
GST_LOG ("width x height: %d x %d", params->width, params->height);
|
||||
GST_LOG ("fps: %d/%d", params->fps_n, params->fps_d);
|
||||
GST_LOG ("par: %d/%d", params->par_w, params->par_h);
|
||||
GST_LOG ("profile/level: %d/%d", params->profile, params->level);
|
||||
GST_LOG ("bitrate/progressive: %d/%d", params->bitrate, params->progressive);
|
||||
|
||||
return TRUE;
|
||||
|
||||
/* ERRORS */
|
||||
failed:
|
||||
{
|
||||
GST_WARNING ("Failed to parse sequence header");
|
||||
/* clear out stuff */
|
||||
memset (params, 0, sizeof (*params));
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
gboolean
|
||||
gst_mpeg_video_params_parse_config (MPEGVParams * params, const guint8 * data,
|
||||
guint size)
|
||||
{
|
||||
GstBitReader br;
|
||||
|
||||
if (size < 4)
|
||||
return FALSE;
|
||||
|
||||
gst_bit_reader_init (&br, data, size);
|
||||
|
||||
return gst_mpeg_video_params_parse_sequence (params, &br);
|
||||
}
|
|
@ -1,77 +0,0 @@
|
|||
/* GStreamer
|
||||
* Copyright (C) <2007> Jan Schmidt <thaytan@mad.scientist.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||
* Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#ifndef __GST_MPEGVIDEO_PARAMS_H__
|
||||
#define __GST_MPEGVIDEO_PARAMS_H__
|
||||
|
||||
#include <gst/gst.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
/* Packet ID codes for different packet types we
|
||||
* care about */
|
||||
#define MPEG_PACKET_PICTURE 0x00
|
||||
#define MPEG_PACKET_SLICE_MIN 0x01
|
||||
#define MPEG_PACKET_SLICE_MAX 0xaf
|
||||
#define MPEG_PACKET_SEQUENCE 0xb3
|
||||
#define MPEG_PACKET_EXTENSION 0xb5
|
||||
#define MPEG_PACKET_SEQUENCE_END 0xb7
|
||||
#define MPEG_PACKET_GOP 0xb8
|
||||
#define MPEG_PACKET_NONE 0xff
|
||||
|
||||
/* Extension codes we care about */
|
||||
#define MPEG_PACKET_EXT_SEQUENCE 0x01
|
||||
#define MPEG_PACKET_EXT_SEQUENCE_DISPLAY 0x02
|
||||
#define MPEG_PACKET_EXT_QUANT_MATRIX 0x03
|
||||
|
||||
/* Flags indicating what type of packets are in this block, some are mutually
|
||||
* exclusive though - ie, sequence packs are accumulated separately. GOP &
|
||||
* Picture may occur together or separately */
|
||||
#define MPEG_BLOCK_FLAG_SEQUENCE 0x01
|
||||
#define MPEG_BLOCK_FLAG_PICTURE 0x02
|
||||
#define MPEG_BLOCK_FLAG_GOP 0x04
|
||||
|
||||
#define MPEG_PICTURE_TYPE_I 0x01
|
||||
#define MPEG_PICTURE_TYPE_P 0x02
|
||||
#define MPEG_PICTURE_TYPE_B 0x03
|
||||
#define MPEG_PICTURE_TYPE_D 0x04
|
||||
|
||||
typedef struct _MPEGVParams MPEGVParams;
|
||||
|
||||
struct _MPEGVParams
|
||||
{
|
||||
gint mpeg_version;
|
||||
|
||||
gint profile;
|
||||
gint level;
|
||||
|
||||
gint width, height;
|
||||
gint par_w, par_h;
|
||||
gint fps_n, fps_d;
|
||||
|
||||
gint bitrate;
|
||||
gboolean progressive;
|
||||
};
|
||||
|
||||
GstFlowReturn gst_mpeg_video_params_parse_config (MPEGVParams * params,
|
||||
const guint8 * data, guint size);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif
|
|
@ -183,8 +183,9 @@ mpeg_video_parse_check_caps (guint version, guint8 * seq, gint size)
|
|||
buf = gst_value_get_buffer (val);
|
||||
fail_unless (buf != NULL);
|
||||
/* codec-data = header - GOP */
|
||||
fail_unless (GST_BUFFER_SIZE (buf) == size - 8);
|
||||
fail_unless (memcmp (GST_BUFFER_DATA (buf), seq, GST_BUFFER_SIZE (buf)) == 0);
|
||||
assert_equals_int (GST_BUFFER_SIZE (buf), size - 8);
|
||||
fail_unless (memcmp (GST_BUFFER_DATA (buf), seq + 4,
|
||||
GST_BUFFER_SIZE (buf)) == 0);
|
||||
|
||||
gst_caps_unref (caps);
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue