From a983b29a4921497d325dd64c5fc9630158742635 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Thu, 23 Jun 2011 12:54:43 -0400 Subject: [PATCH] mpegvideoparse: Port to the new mpeg parsing library --- gst/videoparsers/Makefile.am | 9 +- gst/videoparsers/gstmpegvideoparse.c | 308 ++++++++++++-------------- gst/videoparsers/gstmpegvideoparse.h | 13 +- gst/videoparsers/mpegvideoparse.c | 274 ----------------------- gst/videoparsers/mpegvideoparse.h | 77 ------- tests/check/elements/mpegvideoparse.c | 5 +- 6 files changed, 160 insertions(+), 526 deletions(-) delete mode 100644 gst/videoparsers/mpegvideoparse.c delete mode 100644 gst/videoparsers/mpegvideoparse.h diff --git a/gst/videoparsers/Makefile.am b/gst/videoparsers/Makefile.am index 6cebef5330..4fa87b8a79 100644 --- a/gst/videoparsers/Makefile.am +++ b/gst/videoparsers/Makefile.am @@ -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 \ diff --git a/gst/videoparsers/gstmpegvideoparse.c b/gst/videoparsers/gstmpegvideoparse.c index 7ebbdf36a4..12d98d5d77 100644 --- a/gst/videoparsers/gstmpegvideoparse.c +++ b/gst/videoparsers/gstmpegvideoparse.c @@ -1,8 +1,10 @@ /* GStreamer * Copyright (C) <2007> Jan Schmidt * Copyright (C) <2011> Mark Nauwelaerts - * Copyright (C) <2011> Collabora Multimedia + * Copyright (C) <2011> Thibault Saunier + * 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 */ diff --git a/gst/videoparsers/gstmpegvideoparse.h b/gst/videoparsers/gstmpegvideoparse.h index a3706a41a4..6837a316e4 100644 --- a/gst/videoparsers/gstmpegvideoparse.h +++ b/gst/videoparsers/gstmpegvideoparse.h @@ -1,8 +1,10 @@ /* GStreamer * Copyright (C) <2007> Jan Schmidt * Copyright (C) <2011> Mark Nauwelaerts - * Copyright (C) <2011> Collabora Multimedia + * Copyright (C) <2011> Thibault Saunier + * 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 #include -#include "mpegvideoparse.h" +#include 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; diff --git a/gst/videoparsers/mpegvideoparse.c b/gst/videoparsers/mpegvideoparse.c deleted file mode 100644 index e85d77bdbb..0000000000 --- a/gst/videoparsers/mpegvideoparse.c +++ /dev/null @@ -1,274 +0,0 @@ -/* GStreamer - * Copyright (C) <2007> Jan Schmidt - * - * 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 -#include - -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); -} diff --git a/gst/videoparsers/mpegvideoparse.h b/gst/videoparsers/mpegvideoparse.h deleted file mode 100644 index f0092b7137..0000000000 --- a/gst/videoparsers/mpegvideoparse.h +++ /dev/null @@ -1,77 +0,0 @@ -/* GStreamer - * Copyright (C) <2007> Jan Schmidt - * - * 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 - -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 diff --git a/tests/check/elements/mpegvideoparse.c b/tests/check/elements/mpegvideoparse.c index 9dac4633d2..9aab78f9f1 100644 --- a/tests/check/elements/mpegvideoparse.c +++ b/tests/check/elements/mpegvideoparse.c @@ -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); }