/* 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
static void
gst_mpegv_parse_init (GstMpegvParse * parse, GstMpegvParseClass * g_class)
{
+ parse->mpeg_version = 0;
}
static void
{
/* done parsing; reset state */
mpvparse->last_sc = -1;
- mpvparse->seq_offset = -1;
+ mpvparse->seq_offset = G_MAXUINT;
mpvparse->pic_offset = -1;
}
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
}
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);
/* 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 */
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;
-
- g_return_val_if_fail (size > 0, -1);
- g_return_val_if_fail ((guint64) offset + size <= reader->size - reader->byte,
- -1);
+ GList *tmp;
+ GstMpegVideoTypeOffsetSize *codoffsz;
- /* we can't find the pattern with less than 4 bytes */
- if (G_UNLIKELY (size < 4))
- return -1;
+ for (tmp = l_codoffsz; tmp; tmp = tmp->next) {
+ codoffsz = tmp->data;
- data = reader->data + reader->byte + offset;
+ GST_LOG_OBJECT (mpvparse, "next start code at %d", codoffsz->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;
}
* 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");
} 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;
- }
- off = scan_for_start_codes (&reader, off, GST_BUFFER_SIZE (buf) - off);
+ mpvparse->typeoffsize =
+ gst_mpeg_video_parse (GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf), off);
- GST_LOG_OBJECT (mpvparse, "possible sync at buffer offset %d", off);
+ /* No sc found */
+ if (mpvparse->typeoffsize == NULL)
+ goto end;
- /* didn't find anything that looks like a sync word, skip */
- if (G_UNLIKELY (off < 0)) {
- *skipsize = GST_BUFFER_SIZE (buf) - 3;
- return FALSE;
- }
+ /* Already found the start code looking for the end */
+ if (mpvparse->last_sc >= 0) {
+ *skipsize = 0;
+ fsize = get_frame_size (mpvparse, buf, mpvparse->typeoffsize);
- /* possible frame header, but not at offset 0? skip bytes before sync */
- if (G_UNLIKELY (off > 0)) {
- *skipsize = off;
- return FALSE;
+ goto end;
}
- /* note: initial start code is assumed at offset 0 by subsequent code */
+ for (tmp = mpvparse->typeoffsize; tmp; tmp = g_list_next (tmp)) {
+ GstMpegVideoTypeOffsetSize *codoffsz = tmp->data;
- /* 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;
- }
+ GST_LOG_OBJECT (mpvparse, "next start code at %d", codoffsz->offset);
-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 (codoffsz->size < 0)
+ break;
+
+ ret = gst_mpegv_parse_process_sc (mpvparse, buf, codoffsz->offset,
+ codoffsz->type);
+
+ 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;
}
* 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",
}
/* 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) {
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,
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);
/* 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 */
+++ /dev/null
-/* 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);
-}