From c64b99339c56b504173b45748e0f93a741c68268 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Tue, 19 Jul 2011 13:52:01 +0200 Subject: [PATCH] codecparsers: mpeg: Add an mpeg video bitstream parsing library Create a new codecparsers library --- configure.ac | 1 + docs/libs/gst-plugins-bad-libs-docs.sgml | 10 + docs/libs/gst-plugins-bad-libs-sections.txt | 28 + docs/libs/gst-plugins-bad-libs.types | 2 + gst-libs/gst/Makefile.am | 4 +- gst-libs/gst/codecparsers/Makefile.am | 29 + gst-libs/gst/codecparsers/gstmpegvideoparser.c | 749 +++++++++++++++++++++++++ gst-libs/gst/codecparsers/gstmpegvideoparser.h | 365 ++++++++++++ gst-plugins-bad.spec.in | 3 + pkgconfig/gstreamer-plugins-bad.pc.in | 3 +- tests/check/Makefile.am | 10 + tests/check/libs/mpegvideoparser.c | 208 +++++++ 12 files changed, 1409 insertions(+), 3 deletions(-) create mode 100644 gst-libs/gst/codecparsers/Makefile.am create mode 100644 gst-libs/gst/codecparsers/gstmpegvideoparser.c create mode 100644 gst-libs/gst/codecparsers/gstmpegvideoparser.h create mode 100644 tests/check/libs/mpegvideoparser.c diff --git a/configure.ac b/configure.ac index 5d90452..17ea3b9 100644 --- a/configure.ac +++ b/configure.ac @@ -1946,6 +1946,7 @@ gst-libs/gst/Makefile gst-libs/gst/basecamerabinsrc/Makefile gst-libs/gst/interfaces/Makefile gst-libs/gst/signalprocessor/Makefile +gst-libs/gst/codecparsers/Makefile gst-libs/gst/video/Makefile sys/Makefile sys/dshowdecwrapper/Makefile diff --git a/docs/libs/gst-plugins-bad-libs-docs.sgml b/docs/libs/gst-plugins-bad-libs-docs.sgml index 49f0402..d1113bc 100644 --- a/docs/libs/gst-plugins-bad-libs-docs.sgml +++ b/docs/libs/gst-plugins-bad-libs-docs.sgml @@ -20,6 +20,16 @@ package. + + + Bitstream parsing Library + + This library should be linked to by getting cflags and libs from + gstreamer-plugins-bad-&GST_MAJORMINOR;.pc and adding + -lgscodeparsers-&GST_MAJORMINOR; to the library flags. + + + diff --git a/docs/libs/gst-plugins-bad-libs-sections.txt b/docs/libs/gst-plugins-bad-libs-sections.txt index e69de29..a09929c 100644 --- a/docs/libs/gst-plugins-bad-libs-sections.txt +++ b/docs/libs/gst-plugins-bad-libs-sections.txt @@ -0,0 +1,28 @@ +# codecparsers +
+gstmpegvideoparser +mpegvideoparser +gst/codecparsers/gstmpegvideoparser.h +GstMpegVideoPacketTypeCode +GstMpegVideoPacketExtensionCode +GstMpegVideoLevel +GstMpegVideoProfile +GstMpegVideoPictureType +GstMpegVideoPictureStructure +GstMpegVideoSequenceHdr +GstMpegVideoSequenceExt +GstMpegVideoPictureHdr +GstMpegVideoGop +GstMpegVideoPictureExt +GstMpegVideoQuantMatrixExt +GstMpegVideoTypeOffsetSize +gst_mpeg_video_parse +gst_mpeg_video_parse_sequence_header +gst_mpeg_video_parse_picture_header +gst_mpeg_video_parse_picture_extension +gst_mpeg_video_parse_gop +gst_mpeg_video_parse_sequence_extension +gst_mpeg_video_parse_quant_matrix_extension + + +
diff --git a/docs/libs/gst-plugins-bad-libs.types b/docs/libs/gst-plugins-bad-libs.types index 9f4950e..4ca1a2b 100644 --- a/docs/libs/gst-plugins-bad-libs.types +++ b/docs/libs/gst-plugins-bad-libs.types @@ -1 +1,3 @@ #include + +#include diff --git a/gst-libs/gst/Makefile.am b/gst-libs/gst/Makefile.am index ac83c68..130956e 100644 --- a/gst-libs/gst/Makefile.am +++ b/gst-libs/gst/Makefile.am @@ -1,6 +1,6 @@ -SUBDIRS = interfaces signalprocessor video basecamerabinsrc +SUBDIRS = interfaces signalprocessor video basecamerabinsrc codecparsers noinst_HEADERS = gst-i18n-plugin.h gettext.h -DIST_SUBDIRS = interfaces signalprocessor video basecamerabinsrc +DIST_SUBDIRS = interfaces signalprocessor video basecamerabinsrc codecparsers diff --git a/gst-libs/gst/codecparsers/Makefile.am b/gst-libs/gst/codecparsers/Makefile.am new file mode 100644 index 0000000..86a7b16 --- /dev/null +++ b/gst-libs/gst/codecparsers/Makefile.am @@ -0,0 +1,29 @@ +lib_LTLIBRARIES = libgstcodecparsers-@GST_MAJORMINOR@.la + +libgstcodecparsers_@GST_MAJORMINOR@_la_SOURCES = gstmpegvideoparser.c + +libgstcodecparsers_@GST_MAJORMINOR@includedir = \ + $(includedir)/gstreamer-@GST_MAJORMINOR@/gst/codecparsers + +libgstcodecparsers_@GST_MAJORMINOR@include_HEADERS = \ + gstmpegvideoparser.h + +libgstcodecparsers_@GST_MAJORMINOR@_la_CFLAGS = $(GST_PLUGINS_BAD_CFLAGS) $(GST_CFLAGS) +libgstcodecparsers_@GST_MAJORMINOR@_la_LIBADD = $(GST_BASE_LIBS) $(GST_LIBS) +libgstcodecparsers_@GST_MAJORMINOR@_la_LDFLAGS = $(GST_LIB_LDFLAGS) $(GST_ALL_LDFLAGS) $(GST_LT_LDFLAGS) + +Android.mk: $(BUILT_SOURCES) Makefile.am + androgenizer -:PROJECT libgstcodecparsers -:STATIC libgstcodecparsers-@GST_MAJORMINOR@ \ + -:TAGS eng debug \ + -:REL_TOP $(top_srcdir) -:ABS_TOP $(abs_top_srcdir) \ + -:SOURCES $(libgstcodecparsers_@GST_MAJORMINOR@_la_SOURCES) \ + $(built_sources) \ + -:CFLAGS $(DEFS) $(libgstcodecparsers_@GST_MAJORMINOR@_la_CFLAGS) \ + -:LDFLAGS $(libgstcodecparsers_@GST_MAJORMINOR@_la_LDFLAGS) \ + $(libgstcodecparsers@GST_MAJORMINOR@_la_LIBADD) \ + -ldl \ + -:HEADER_TARGET gstreamer-@GST_MAJORMINOR@/gst/codecparsers \ + -:HEADERS $(libgstcodecparsersinclude_HEADERS) \ + $(built_headers) \ + -:PASSTHROUGH LOCAL_ARM_MODE:=arm \ + > $@ diff --git a/gst-libs/gst/codecparsers/gstmpegvideoparser.c b/gst-libs/gst/codecparsers/gstmpegvideoparser.c new file mode 100644 index 0000000..be34e5f --- /dev/null +++ b/gst-libs/gst/codecparsers/gstmpegvideoparser.c @@ -0,0 +1,749 @@ +/* Gstreamer + * Copyright (C) <2011> Intel Corporation + * Copyright (C) <2011> Collabora Ltd. + * Copyright (C) <2011> Thibault Saunier + * + * From bad/sys/vdpau/mpeg/mpegutil.c: + * Copyright (C) <2007> Jan Schmidt + * Copyright (C) <2009> Carl-Anton Ingmarsson + * + * 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. + */ + +/** + * SECTION:gstmpegvideoparser + * @short_description: Convenience library for mpeg1 and 2 video + * bitstream parsing. + * + * + * + * Provides useful functions for mpeg videos bitstream parsing. + * + * + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include "gstmpegvideoparser.h" + +#include +#include +#include + +#define MARKER_BIT 0x1 + +#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 READ_UINT8(br, val, nbits) G_STMT_START { \ + if (!gst_bit_reader_get_bits_uint8 (br, &val, nbits)) { \ + GST_WARNING ("failed to read uint8, nbits: %d", nbits); \ + goto failed; \ + } \ +} G_STMT_END + +#define READ_UINT16(br, val, nbits) G_STMT_START { \ + if (!gst_bit_reader_get_bits_uint16 (br, &val, nbits)) { \ + GST_WARNING ("failed to read uint16, nbits: %d", nbits); \ + goto failed; \ + } \ +} G_STMT_END + +#define READ_UINT32(br, val, nbits) G_STMT_START { \ + if (!gst_bit_reader_get_bits_uint32 (br, &val, nbits)) { \ + GST_WARNING ("failed to read uint32, nbits: %d", nbits); \ + goto failed; \ + } \ +} G_STMT_END + +/* default intra quant matrix, in zig-zag order */ +const guint8 default_intra_quantizer_matrix[64] = { + 8, + 16, 16, + 19, 16, 19, + 22, 22, 22, 22, + 22, 22, 26, 24, 26, + 27, 27, 27, 26, 26, 26, + 26, 27, 27, 27, 29, 29, 29, + 34, 34, 34, 29, 29, 29, 27, 27, + 29, 29, 32, 32, 34, 34, 37, + 38, 37, 35, 35, 34, 35, + 38, 38, 40, 40, 40, + 48, 48, 46, 46, + 56, 56, 58, + 69, 69, + 83 +}; + +const guint8 mpeg_zigzag_8x8[64] = { + 0, 1, 8, 16, 9, 2, 3, 10, + 17, 24, 32, 25, 18, 11, 4, 5, + 12, 19, 26, 33, 40, 48, 41, 34, + 27, 20, 13, 6, 7, 14, 21, 28, + 35, 42, 49, 56, 57, 50, 43, 36, + 29, 22, 15, 23, 30, 37, 44, 51, + 58, 59, 52, 45, 38, 31, 39, 46, + 53, 60, 61, 54, 47, 55, 62, 63 +}; + +GST_DEBUG_CATEGORY (mpegvideo_parser_debug); +#define GST_CAT_DEFAULT mpegvideo_parser_debug + +static gboolean initialized = FALSE; + +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; +} + +/* Set the Pixel Aspect Ratio in our hdr from a DAR code in the data */ +static void +set_par_from_dar (GstMpegVideoSequenceHdr * seqhdr, 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 */ + seqhdr->par_w = 4 * seqhdr->height; + seqhdr->par_h = 3 * seqhdr->width; + break; + case 0x03: /* 9:16 DAR */ + seqhdr->par_w = 16 * seqhdr->height; + seqhdr->par_h = 9 * seqhdr->width; + break; + case 0x04: /* 1:2.21 DAR */ + seqhdr->par_w = 221 * seqhdr->height; + seqhdr->par_h = 100 * seqhdr->width; + break; + case 0x01: /* Square pixels */ + seqhdr->par_w = seqhdr->par_h = 1; + break; + default: + GST_DEBUG ("unknown/invalid aspect_ratio_information %d", asr_code); + break; + } +} + +static void +set_fps_from_code (GstMpegVideoSequenceHdr * seqhdr, 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) { + seqhdr->fps_n = framerates[fps_code][0]; + seqhdr->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 ?? */ + seqhdr->fps_n = 30000; + seqhdr->fps_d = 1001; + } +} + +static gboolean +gst_mpeg_video_parse_sequence (GstMpegVideoSequenceHdr * seqhdr, + GstBitReader * br) +{ + guint8 bits; + guint8 load_intra_flag, load_non_intra_flag; + + /* Setting the height/width codes */ + READ_UINT16 (br, seqhdr->width, 12); + READ_UINT16 (br, seqhdr->height, 12); + + READ_UINT8 (br, seqhdr->aspect_ratio_info, 4); + set_par_from_dar (seqhdr, seqhdr->aspect_ratio_info); + + READ_UINT8 (br, seqhdr->frame_rate_code, 4); + set_fps_from_code (seqhdr, seqhdr->frame_rate_code); + + READ_UINT32 (br, seqhdr->bitrate_value, 18); + if (seqhdr->bitrate_value == 0x3ffff) { + /* VBR stream */ + seqhdr->bitrate = 0; + } else { + /* Value in header is in units of 400 bps */ + seqhdr->bitrate *= 400; + } + + READ_UINT8 (br, bits, 1); + if (bits != MARKER_BIT) + goto failed; + + /* VBV buffer size */ + READ_UINT16 (br, seqhdr->vbv_buffer_size_value, 10); + + /* constrained_parameters_flag */ + READ_UINT8 (br, seqhdr->constrained_parameters_flag, 1); + + /* load_intra_quantiser_matrix */ + READ_UINT8 (br, load_intra_flag, 1); + if (load_intra_flag) { + gint i; + for (i = 0; i < 64; i++) + READ_UINT8 (br, seqhdr->intra_quantizer_matrix[mpeg_zigzag_8x8[i]], 8); + } else + memcpy (seqhdr->intra_quantizer_matrix, default_intra_quantizer_matrix, 64); + + /* non intra quantizer matrix */ + READ_UINT8 (br, load_non_intra_flag, 1); + if (load_non_intra_flag) { + gint i; + for (i = 0; i < 64; i++) + READ_UINT8 (br, seqhdr->non_intra_quantizer_matrix[mpeg_zigzag_8x8[i]], + 8); + } else + memset (seqhdr->non_intra_quantizer_matrix, 16, 64); + + /* dump some info */ + GST_LOG ("width x height: %d x %d", seqhdr->width, seqhdr->height); + GST_LOG ("fps: %d/%d", seqhdr->fps_n, seqhdr->fps_d); + GST_LOG ("par: %d/%d", seqhdr->par_w, seqhdr->par_h); + GST_LOG ("bitrate: %d", seqhdr->bitrate); + + return TRUE; + + /* ERRORS */ +failed: + { + GST_WARNING ("Failed to parse sequence header"); + /* clear out stuff */ + memset (seqhdr, 0, sizeof (*seqhdr)); + return FALSE; + } +} + +static inline guint +scan_for_start_codes (const GstByteReader * reader, guint offset, guint size) +{ + 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); + + /* we can't find the pattern with less than 4 bytes */ + if (G_UNLIKELY (size < 4)) + return -1; + + 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; + } + + /* TODO: reimplement making 010001 not detected as a sc + * 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; + *} + */ + } + + /* nothing found */ + return -1; +} + +/****** API *******/ + +/** + * gst_mpeg_video_parse: + * @data: The datas from which to parse + * @size: The size of @data + * @offset: The offset from which to start the parsing + * + * Parses @data, and detects the different packets types, offset, + * and size, starting from @offset + * + * Returns: a #GList of #GstMpegVideoTypeOffsetSize + */ +GList * +gst_mpeg_video_parse (guint8 * data, gsize size, guint offset) +{ + gint off, rsize; + GstByteReader br; + GList *ret = NULL; + size = size - offset; + + if (!initialized) { + GST_DEBUG_CATEGORY_INIT (mpegvideo_parser_debug, "codecparsers_mpegvideo", + 0, "Mpegvideo parser library"); + initialized = TRUE; + } + + if (size <= 0) { + GST_DEBUG ("Can't parse from offset %d, buffer is to small", offset); + return NULL; + } + + gst_byte_reader_init (&br, &data[offset], size); + + off = scan_for_start_codes (&br, 0, size); + + if (off < 0) { + GST_DEBUG ("No start code prefix in this buffer"); + return NULL; + } + + while (off >= 0 && off + 3 < size) { + GstMpegVideoTypeOffsetSize *codoffsize; + + gst_byte_reader_skip (&br, off + 3); + + codoffsize = g_malloc (sizeof (GstMpegVideoTypeOffsetSize)); + gst_byte_reader_get_uint8 (&br, &codoffsize->type); + + codoffsize->offset = gst_byte_reader_get_pos (&br) + offset; + + rsize = gst_byte_reader_get_remaining (&br); + if (rsize <= 0) + break; + + off = scan_for_start_codes (&br, 0, rsize); + + codoffsize->size = off; + + ret = g_list_prepend (ret, codoffsize); + codoffsize = ret->data; + } + + return g_list_reverse (ret); +} + +/** + * gst_mpeg_video_parse_sequence_header: + * @seqhdr: The #GstMpegVideoSequenceHdr to set + * @data: The datas from which to parse the seqhdr + * @size: The size of @data + * @offset: The offset in byte from which to start parsing @data + * + * Sets the @seqhdr Mpeg Video Sequence Header structure members from @data + * + * Returns: %TRUE if the seqhdr could be parsed correctly, %FALSE otherwize. + */ +gboolean +gst_mpeg_video_parse_sequence_header (GstMpegVideoSequenceHdr * seqhdr, + guint8 * data, gsize size, guint offset) +{ + GstBitReader br; + + size = size - offset; + + if (size - offset < 4) + return FALSE; + + gst_bit_reader_init (&br, &data[offset], size); + + return gst_mpeg_video_parse_sequence (seqhdr, &br); +} + +/** + * gst_mpeg_video_parse_sequence_extension: + * @seqhdr: The #GstMpegVideoSequenceExt to set + * @data: The datas from which to parse the seqext + * @size: The size of @data + * @offset: The offset in byte from which to start parsing @data + * + * Sets the @seqext Mpeg Video Sequence Extension structure members from @data + * + * Returns: %TRUE if the seqext could be parsed correctly, %FALSE otherwize. + */ +gboolean +gst_mpeg_video_parse_sequence_extension (GstMpegVideoSequenceExt * seqext, + guint8 * data, gsize size, guint offset) +{ + GstBitReader br; + + size = size - offset; + + if (size < 6) { + GST_DEBUG ("not enough bytes to parse the extension"); + return FALSE; + } + + gst_bit_reader_init (&br, &data[offset], size); + + if (gst_bit_reader_get_bits_uint8_unchecked (&br, 4) != + GST_MPEG_VIDEO_PACKET_EXT_SEQUENCE) { + GST_DEBUG ("Not parsing a sequence extension"); + return FALSE; + } + + /* skip profile and level escape bit */ + gst_bit_reader_skip_unchecked (&br, 1); + + seqext->profile = gst_bit_reader_get_bits_uint8_unchecked (&br, 3); + seqext->level = gst_bit_reader_get_bits_uint8_unchecked (&br, 4); + + /* progressive */ + seqext->progressive = gst_bit_reader_get_bits_uint8_unchecked (&br, 1); + + /* chroma format */ + seqext->chroma_format = gst_bit_reader_get_bits_uint8_unchecked (&br, 2); + + /* resolution extension */ + seqext->horiz_size_ext = gst_bit_reader_get_bits_uint8_unchecked (&br, 2); + seqext->vert_size_ext = gst_bit_reader_get_bits_uint8_unchecked (&br, 2); + + seqext->bitrate_ext = gst_bit_reader_get_bits_uint16_unchecked (&br, 12); + + /* skip marker bits */ + gst_bit_reader_skip_unchecked (&br, 1); + + seqext->vbv_buffer_size_extension = + gst_bit_reader_get_bits_uint8_unchecked (&br, 8); + seqext->low_delay = gst_bit_reader_get_bits_uint8_unchecked (&br, 1); + + /* framerate extension */ + seqext->fps_n_ext = gst_bit_reader_get_bits_uint8_unchecked (&br, 2); + seqext->fps_d_ext = gst_bit_reader_get_bits_uint8_unchecked (&br, 2); + + return TRUE; +} + +/** + * gst_mpeg_video_parse_quant_matrix_extension: + * @ext: The #GstMpegVideoQuantMatrixExt to set + * @data: The datas from which to parse @quant + * @size: The size of @data + * @offset: The offset in byte from which to start the parsing + * + * Sets the @quant Mpeg Video Quant Matrix Extension structure members from + * @data + * + * Returns: %TRUE if the quant matrix extension could be parsed correctly, + * %FALSE otherwize. + */ +gboolean +gst_mpeg_video_parse_quant_matrix_extension (GstMpegVideoQuantMatrixExt * quant, + guint8 * data, gsize size, guint offset) +{ + guint8 i; + GstBitReader br; + + size = size - offset; + + if (size < 1) { + GST_DEBUG ("not enough bytes to parse the extension"); + return FALSE; + } + + gst_bit_reader_init (&br, &data[offset], size); + + if (gst_bit_reader_get_bits_uint8_unchecked (&br, 4) != + GST_MPEG_VIDEO_PACKET_EXT_QUANT_MATRIX) { + GST_DEBUG ("Not parsing a quant matrix extension"); + return FALSE; + } + + READ_UINT8 (&br, quant->load_intra_quantiser_matrix, 1); + if (quant->load_intra_quantiser_matrix) { + for (i = 0; i < 64; i++) { + READ_UINT8 (&br, quant->intra_quantiser_matrix[mpeg_zigzag_8x8[i]], 8); + } + } + + READ_UINT8 (&br, quant->load_non_intra_quantiser_matrix, 1); + if (quant->load_non_intra_quantiser_matrix) { + for (i = 0; i < 64; i++) { + READ_UINT8 (&br, quant->non_intra_quantiser_matrix[mpeg_zigzag_8x8[i]], + 8); + } + } + + READ_UINT8 (&br, quant->load_chroma_intra_quantiser_matrix, 1); + if (quant->load_non_intra_quantiser_matrix) { + for (i = 0; i < 64; i++) { + READ_UINT8 (&br, quant->chroma_intra_quantiser_matrix[mpeg_zigzag_8x8[i]], + 8); + } + } + + READ_UINT8 (&br, quant->load_chroma_non_intra_quantiser_matrix, 1); + if (quant->load_chroma_non_intra_quantiser_matrix) { + for (i = 0; i < 64; i++) { + READ_UINT8 (&br, + quant->chroma_non_intra_quantiser_matrix[mpeg_zigzag_8x8[i]], 8); + } + } + + return TRUE; + +failed: + GST_WARNING ("error parsing \"Quant Matrix Extension\""); + return FALSE; +} + +/** + * gst_mpeg_video_parse_picture_extension: + * @ext: The #GstMpegVideoPictureExt to set + * @data: The datas from which to parse the ext + * @size: The size of @data + * @offset: The offset in byte from which to start the parsing + * + * Sets the @ext Mpeg Video Picture Extension structure members from @data + * + * Returns: %TRUE if the picture extension could be parsed correctly, + * %FALSE otherwize. + */ +gboolean +gst_mpeg_video_parse_picture_extension (GstMpegVideoPictureExt * ext, + guint8 * data, gsize size, guint offset) +{ + GstBitReader br; + + size = size - offset; + + if (size < 4) + return FALSE; + + gst_bit_reader_init (&br, &data[offset], size); + + /* f_code */ + READ_UINT8 (&br, ext->f_code[0][0], 4); + READ_UINT8 (&br, ext->f_code[0][1], 4); + READ_UINT8 (&br, ext->f_code[1][0], 4); + READ_UINT8 (&br, ext->f_code[1][1], 4); + + /* intra DC precision */ + READ_UINT8 (&br, ext->intra_dc_precision, 2); + + /* picture structure */ + READ_UINT8 (&br, ext->picture_structure, 2); + + /* top field first */ + READ_UINT8 (&br, ext->top_field_first, 1); + + /* frame pred frame dct */ + READ_UINT8 (&br, ext->frame_pred_frame_dct, 1); + + /* concealment motion vectors */ + READ_UINT8 (&br, ext->concealment_motion_vectors, 1); + + /* q scale type */ + READ_UINT8 (&br, ext->q_scale_type, 1); + + /* intra vlc format */ + READ_UINT8 (&br, ext->intra_vlc_format, 1); + + /* alternate scan */ + READ_UINT8 (&br, ext->alternate_scan, 1); + + /* repeat first field */ + READ_UINT8 (&br, ext->repeat_first_field, 1); + + /* chroma_420_type */ + READ_UINT8 (&br, ext->chroma_420_type, 1); + + /* progressive_frame */ + READ_UINT8 (&br, ext->progressive_frame, 1); + + /* composite display */ + READ_UINT8 (&br, ext->composite_display, 1); + + if (ext->composite_display) { + + /* v axis */ + READ_UINT8 (&br, ext->v_axis, 1); + + /* field sequence */ + READ_UINT8 (&br, ext->field_sequence, 3); + + /* sub carrier */ + READ_UINT8 (&br, ext->sub_carrier, 1); + + /* burst amplitude */ + READ_UINT8 (&br, ext->burst_amplitude, 7); + + /* sub_carrier phase */ + READ_UINT8 (&br, ext->sub_carrier_phase, 8); + } + + return TRUE; + +failed: + GST_WARNING ("error parsing \"Picture Coding Extension\""); + return FALSE; + +} + +/** + * gst_mpeg_video_parse_picture_header: + * @hdr: The #GstMpegVideoPictureHdr to set + * @data: The datas from which to parse the hdr + * @size: The size of @data + * @offset: The offset in byte from which to start the parsing + * + * Sets the @hdr Mpeg Video Picture Header structure members from @data + * + * Returns: %TRUE if the picture sequence could be parsed correctly, %FALSE otherwize. + */ +gboolean +gst_mpeg_video_parse_picture_header (GstMpegVideoPictureHdr * hdr, + guint8 * data, gsize size, guint offset) +{ + GstBitReader br; + + size = size - offset; + + if (size < 4) + return FALSE; + + gst_bit_reader_init (&br, &data[offset], size); + + /* temperal sequence number */ + if (!gst_bit_reader_get_bits_uint16 (&br, &hdr->tsn, 10)) + return FALSE; + + /* frame type */ + if (!gst_bit_reader_get_bits_uint8 (&br, (guint8 *) & hdr->pic_type, 3)) + return FALSE; + + if (hdr->pic_type == 0 || hdr->pic_type > 4) + return FALSE; /* Corrupted picture packet */ + + /* skype VBV delay */ + if (!gst_bit_reader_skip (&br, 8)) + return FALSE; + + if (hdr->pic_type == GST_MPEG_VIDEO_PICTURE_TYPE_P + || hdr->pic_type == GST_MPEG_VIDEO_PICTURE_TYPE_B) { + + READ_UINT8 (&br, hdr->full_pel_forward_vector, 1); + + READ_UINT8 (&br, hdr->f_code[0][0], 3); + hdr->f_code[0][1] = hdr->f_code[0][0]; + } else { + hdr->full_pel_forward_vector = 0; + hdr->f_code[0][0] = hdr->f_code[0][1] = 0; + } + + if (hdr->pic_type == GST_MPEG_VIDEO_PICTURE_TYPE_B) { + READ_UINT8 (&br, hdr->full_pel_backward_vector, 1); + + READ_UINT8 (&br, hdr->f_code[1][0], 3); + hdr->f_code[1][1] = hdr->f_code[1][0]; + } else { + hdr->full_pel_backward_vector = 0; + hdr->f_code[1][0] = hdr->f_code[1][1] = 0; + } + + return TRUE; + +failed: + { + GST_WARNING ("Failed to parse sequence extension"); + return FALSE; + } +} + +/** + * gst_mpeg_video_parse_gop: + * @gop: The #GstMpegVideoGop to set + * @data: The datas from which to parse the gop + * @size: The size of @data + * @offset: The offset in byte from which to start the parsing + * + * + * Sets the @gop Mpeg Video Group of Picture structure members from @data + * + * Returns: %TRUE if the gop could be parsed correctly, %FALSE otherwize. + */ +gboolean +gst_mpeg_video_parse_gop (GstMpegVideoGop * gop, guint8 * data, + gsize size, guint offset) +{ + GstBitReader br; + + size = size - offset; + + if (size < 4) + return FALSE; + + gst_bit_reader_init (&br, &data[offset], size); + + READ_UINT8 (&br, gop->drop_frame_flag, 1); + + READ_UINT8 (&br, gop->hour, 5); + + READ_UINT8 (&br, gop->minute, 6); + + /* skip unused bit */ + if (!gst_bit_reader_skip (&br, 1)) + return FALSE; + + READ_UINT8 (&br, gop->second, 6); + + READ_UINT8 (&br, gop->frame, 6); + + READ_UINT8 (&br, gop->closed_gop, 1); + + READ_UINT8 (&br, gop->broken_gop, 1); + + return TRUE; + +failed: + GST_WARNING ("error parsing \"GOP\""); + return FALSE; +} diff --git a/gst-libs/gst/codecparsers/gstmpegvideoparser.h b/gst-libs/gst/codecparsers/gstmpegvideoparser.h new file mode 100644 index 0000000..8d034af --- /dev/null +++ b/gst-libs/gst/codecparsers/gstmpegvideoparser.h @@ -0,0 +1,365 @@ +/* Gstreamer + * Copyright (C) <2011> Intel Corporation + * Copyright (C) <2011> Collabora Ltd. + * Copyright (C) <2011> Thibault Saunier + * + * From bad/sys/vdpau/mpeg/mpegutil.c: + * Copyright (C) <2007> Jan Schmidt + * Copyright (C) <2009> Carl-Anton Ingmarsson + * + * 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_MPEG_VIDEO_UTILS_H__ +#define __GST_MPEG_VIDEO_UTILS_H__ + +#include + +G_BEGIN_DECLS + +/** + * GstMpegVideoPacketTypeCode: + * @GST_MPEG_VIDEO_PACKET_PICTURE: Picture packet starting code + * @GST_MPEG_VIDEO_PACKET_SLICE_MIN: Picture packet starting code + * @GST_MPEG_VIDEO_PACKET_SLICE_MAX: Slice max packet starting code + * @GST_MPEG_VIDEO_PACKET_SEQUENCE : Sequence packet starting code + * @GST_MPEG_VIDEO_PACKET_EXTENSION: Extension packet starting code + * @GST_MPEG_VIDEO_PACKET_SEQUENCE_END: Sequence end packet code + * @GST_MPEG_VIDEO_PACKET_GOP: Group of Picture packet starting code + * @GST_MPEG_VIDEO_PACKET_NONE: None packet code + * + * Indicates the type of MPEG packet + */ +typedef enum { + GST_MPEG_VIDEO_PACKET_PICTURE = 0x00, + GST_MPEG_VIDEO_PACKET_SLICE_MIN = 0x01, + GST_MPEG_VIDEO_PACKET_SLICE_MAX = 0xaf, + GST_MPEG_VIDEO_PACKET_SEQUENCE = 0xb3, + GST_MPEG_VIDEO_PACKET_EXTENSION = 0xb5, + GST_MPEG_VIDEO_PACKET_SEQUENCE_END = 0xb7, + GST_MPEG_VIDEO_PACKET_GOP = 0xb8, + GST_MPEG_VIDEO_PACKET_NONE = 0xff +} GstMpegVideoPacketTypeCode; + +/** + * GstMpegVideoPacketExtensionCode: + * @GST_MPEG_VIDEO_PACKET_EXT_SEQUENCE: Sequence extension code + * @GST_MPEG_VIDEO_PACKET_EXT_SEQUENCE_DISPLAY: Display extension code + * @GST_MPEG_VIDEO_PACKET_EXT_QUANT_MATRIX: Quantizer extension code + * @GST_MPEG_VIDEO_PACKET_EXT_GOP: Group Of Picture extension code + * + * Indicates 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 + */ +typedef enum { + GST_MPEG_VIDEO_PACKET_EXT_SEQUENCE = 0x01, + GST_MPEG_VIDEO_PACKET_EXT_SEQUENCE_DISPLAY = 0x02, + GST_MPEG_VIDEO_PACKET_EXT_QUANT_MATRIX = 0x03, + GST_MPEG_VIDEO_PACKET_EXT_GOP = 0x04 +} GstMpegVideoPacketExtensionCode; + +/** + * GstMpegVideoLevel: + * @GST_MPEG_VIDEO_LEVEL_LOW + * @GST_MPEG_VIDEO_LEVEL_MAIN + * @GST_MPEG_VIDEO_LEVEL_HIGH_1440 + * @GST_MPEG_VIDEO_LEVEL_HIGH + * + * Indicates the level in use + **/ +typedef enum { + GST_MPEG_VIDEO_LEVEL_HIGH = 0x04, + GST_MPEG_VIDEO_LEVEL_HIGH_1440 = 0x06, + GST_MPEG_VIDEO_LEVEL_MAIN = 0x08, + GST_MPEG_VIDEO_LEVEL_LOW = 0x0a +} GstMpegVideoLevel; + +/** + * GstMpegVideoProfile: + * @GST_MPEG_VIDEO_PROFILE_422, + * @GST_MPEG_VIDEO_PROFILE_HIGH, + * @GST_MPEG_VIDEO_PROFILE_SPATIALLY_SCALABLE, + * @GST_MPEG_VIDEO_PROFILE_SNR_SCALABLE, + * @GST_MPEG_VIDEO_PROFILE_MAIN, + * @GST_MPEG_VIDEO_PROFILE_SIMPLE, + * + * Indicates the profile type in use + **/ +typedef enum { + GST_MPEG_VIDEO_PROFILE_422 = 0x00, + GST_MPEG_VIDEO_PROFILE_HIGH = 0x01, + GST_MPEG_VIDEO_PROFILE_SPATIALLY_SCALABLE = 0x02, + GST_MPEG_VIDEO_PROFILE_SNR_SCALABLE = 0x03, + GST_MPEG_VIDEO_PROFILE_MAIN = 0x04, + GST_MPEG_VIDEO_PROFILE_SIMPLE = 0x05 +} GstMpegVideoProfile; + +/** + * GstMpegVideoPictureType: + * @GST_MPEG_VIDEO_PICTURE_TYPE_I: Type I + * @GST_MPEG_VIDEO_PICTURE_TYPE_P: Type P + * @GST_MPEG_VIDEO_PICTURE_TYPE_B: Type B + * @GST_MPEG_VIDEO_PICTURE_TYPE_D: Type D + * + * Indicates the type of picture + */ +typedef enum { + GST_MPEG_VIDEO_PICTURE_TYPE_I = 0x01, + GST_MPEG_VIDEO_PICTURE_TYPE_P = 0x02, + GST_MPEG_VIDEO_PICTURE_TYPE_B = 0x03, + GST_MPEG_VIDEO_PICTURE_TYPE_D = 0x04 +} GstMpegVideoPictureType; + +/** + * GstMpegVideoPictureStructure: + * @GST_MPEG_VIDEO_PICTURE_STRUCTURE_TOP_FIELD: Top field + * @GST_MPEG_VIDEO_PICTURE_STRUCTURE_BOTTOM_FIELD: Bottom field + * @GST_MPEG_VIDEO_PICTURE_STRUCTURE_FRAME: Frame + * + * Indicates the structure of picture + */ +typedef enum { + GST_MPEG_VIDEO_PICTURE_STRUCTURE_TOP_FIELD = 0x01, + GST_MPEG_VIDEO_PICTURE_STRUCTURE_BOTTOM_FIELD = 0x02, + GST_MPEG_VIDEO_PICTURE_STRUCTURE_FRAME = 0x03 +} GstMpegVideoPictureStructure; + +typedef struct _GstMpegVideoSequenceHdr GstMpegVideoSequenceHdr; +typedef struct _GstMpegVideoSequenceExt GstMpegVideoSequenceExt; +typedef struct _GstMpegVideoPictureHdr GstMpegVideoPictureHdr; +typedef struct _GstMpegVideoGop GstMpegVideoGop; +typedef struct _GstMpegVideoPictureExt GstMpegVideoPictureExt; +typedef struct _GstMpegVideoQuantMatrixExt GstMpegVideoQuantMatrixExt; +typedef struct _GstMpegVideoTypeOffsetSize GstMpegVideoTypeOffsetSize; + +/** + * GstMpegVideoSequenceHdr: + * @width: Width of each frame + * @height: Height of each frame + * @par_w: Calculated Pixel Aspect Ratio width + * @par_h: Pixel Aspect Ratio height + * @fps_n: Calculated Framrate nominator + * @fps_d: Calculated Framerate denominator + * @bitrate_value: Value of the bitrate as is in the stream (400bps unit) + * @bitrate: the real bitrate of the Mpeg video stream in bits per second, 0 if VBR stream + * @constrained_parameters_flag: %TRUE if this stream uses contrained parameters. + * @intra_quantizer_matrix: intra-quantization table + * @non_intra_quantizer_matrix: non-intra quantization table + * + * The Mpeg2 Video Sequence Header structure. + */ +struct _GstMpegVideoSequenceHdr +{ + guint16 width, height; + guint8 aspect_ratio_info; + guint8 frame_rate_code; + guint32 bitrate_value; + guint16 vbv_buffer_size_value; + + guint8 constrained_parameters_flag; + + guint8 intra_quantizer_matrix[64]; + guint8 non_intra_quantizer_matrix[64]; + + /* Calculated values */ + guint par_w, par_h; + guint fps_n, fps_d; + guint bitrate; +}; + +/** + * GstMpegVideoSequenceExt: + * @profile: mpeg2 decoder profil + * @level: mpeg2 decoder level + * @progressive: %TRUE if the frames are progressive %FALSE otherwize + * @chroma_format: indicates the chrominance format + * @horiz_size_ext: Horizontal size + * @vert_size_ext: Vertical size + * @bitrate_ext: The bitrate + * @vbv_buffer_size_extension: Vbv vuffer size + * @low_delay: %TRUE if the sequence doesn't contain any B-pitcture, %FALSE + * otherwize + * @fps_n_ext: Framerate nominator code + * @fps_d_ext: Framerate denominator code + * + * The Mpeg2 Video Sequence Extension structure. + **/ +struct _GstMpegVideoSequenceExt +{ + /* mpeg2 decoder profile */ + guint8 profile; + /* mpeg2 decoder level */ + guint8 level; + + guint8 progressive; + guint8 chroma_format; + + guint8 horiz_size_ext, vert_size_ext; + + guint16 bitrate_ext; + guint8 vbv_buffer_size_extension; + guint8 low_delay; + guint8 fps_n_ext, fps_d_ext; + +}; + +/** + * GstMpegVideoQuantMatrixExt: + * @load_intra_quantiser_matrix + * @intra_quantiser_matrix + * @load_non_intra_quantiser_matrix + * @non_intra_quantiser_matrix: + * @load_chroma_intra_quantiser_matrix + * @chroma_intra_quantiser_matrix + * @load_chroma_non_intra_quantiser_matrix + * @chroma_non_intra_quantiser_matrix + * + * The Quant Matrix Extension structure + */ +struct _GstMpegVideoQuantMatrixExt +{ + guint8 load_intra_quantiser_matrix; + guint8 intra_quantiser_matrix[64]; + guint8 load_non_intra_quantiser_matrix; + guint8 non_intra_quantiser_matrix[64]; + guint8 load_chroma_intra_quantiser_matrix; + guint8 chroma_intra_quantiser_matrix[64]; + guint8 load_chroma_non_intra_quantiser_matrix; + guint8 chroma_non_intra_quantiser_matrix[64]; +}; + +/** + * GstMpegVideoPictureHdr: + * @tsn: Temporal Sequence Number + * @pic_type: Type of the frame + * @full_pel_forward_vector: the full pel forward flag of + * the frame: 0 or 1. + * @full_pel_backward_vector: the full pel backward flag + * of the frame: 0 or 1. + * @f_code: F code + * + * The Mpeg2 Video Picture Header structure. + */ +struct _GstMpegVideoPictureHdr +{ + guint16 tsn; + guint8 pic_type; + + guint8 full_pel_forward_vector, full_pel_backward_vector; + + guint8 f_code[2][2]; +}; + +/** + * GstMpegVideoPictureExt: + * @intra_dc_precision: Intra DC precision + * @picture_structure: Structure of the picture + * @top_field_first: Top field first + * @frame_pred_frame_dct: Frame + * @concealment_motion_vectors: Concealment Motion Vectors + * @q_scale_type: Q Scale Type + * @intra_vlc_format: Intra Vlc Format + * @alternate_scan: Alternate Scan + * @repeat_first_field: Repeat First Field + * @chroma_420_type: Chroma 420 Type + * @progressive_frame: %TRUE if the frame is progressive %FALSE otherwize + * + * The Mpeg2 Video Picture Extension structure. + */ +struct _GstMpegVideoPictureExt +{ + guint8 f_code[2][2]; + + guint8 intra_dc_precision; + guint8 picture_structure; + guint8 top_field_first; + guint8 frame_pred_frame_dct; + guint8 concealment_motion_vectors; + guint8 q_scale_type; + guint8 intra_vlc_format; + guint8 alternate_scan; + guint8 repeat_first_field; + guint8 chroma_420_type; + guint8 progressive_frame; + guint8 composite_display; + guint8 v_axis; + guint8 field_sequence; + guint8 sub_carrier; + guint8 burst_amplitude; + guint8 sub_carrier_phase; +}; + +/** + * GstMpegVideoGop: + * @drop_frame_flag: Drop Frame Flag + * @hour: Hour (0-23) + * @minute: Minute (O-59) + * @second: Second (0-59) + * @frame: Frame (0-59) + * @closed_gop: Closed Gop + * @broken_gop: Broken Gop + * + * The Mpeg Video Group of Picture structure. + */ +struct _GstMpegVideoGop +{ + guint8 drop_frame_flag; + + guint8 hour, minute, second, frame; + + guint8 closed_gop; + guint8 broken_gop; +}; + +/** + * GstMpegVideoTypeOffsetSize: + * @type: the type of the packet that start at @offset + * @offset: the offset of the packet start in bytes, it is the exact, start of the packet, no sync code included + * @size: The size in bytes of the packet or -1 if the end wasn't found. It is the exact size of the packet, no sync code included + * + * A structure that contains the type of a packet, its offset and its size + */ +struct _GstMpegVideoTypeOffsetSize +{ + guint8 type; + guint offset; + gint size; +}; + +GList * gst_mpeg_video_parse (guint8 * data, gsize size, guint offset); + +gboolean gst_mpeg_video_parse_sequence_header (GstMpegVideoSequenceHdr * params, + guint8 * data, gsize size, guint offset); + +gboolean gst_mpeg_video_parse_picture_header (GstMpegVideoPictureHdr* hdr, + guint8 * data, gsize size, guint offset); + +gboolean gst_mpeg_video_parse_picture_extension (GstMpegVideoPictureExt *ext, + guint8 * data, gsize size, guint offset); + +gboolean gst_mpeg_video_parse_gop (GstMpegVideoGop * gop, + guint8 * data, gsize size, guint offset); + +gboolean gst_mpeg_video_parse_sequence_extension (GstMpegVideoSequenceExt * seqext, + guint8 * data, gsize size, guint offset); + +gboolean gst_mpeg_video_parse_quant_matrix_extension (GstMpegVideoQuantMatrixExt * quant, + guint8 * data, gsize size, guint offset); + +G_END_DECLS + +#endif diff --git a/gst-plugins-bad.spec.in b/gst-plugins-bad.spec.in index c1c81f1..adbd33d 100644 --- a/gst-plugins-bad.spec.in +++ b/gst-plugins-bad.spec.in @@ -204,6 +204,7 @@ make ERROR_CFLAGS='' ERROR_CXXFLAGS='' %{_libdir}/libgstbasevideo-%{majorminor}.so.* %{_libdir}/libgstphotography-%{majorminor}.so.* %{_libdir}/libgstsignalprocessor-%{majorminor}.so.* +%{_libdir}/libgstcodecparsers-%{majorminor}.so.* # Plugins without external dependencies %{_libdir}/gstreamer-%{majorminor}/libgstadpcmdec.so %{_libdir}/gstreamer-%{majorminor}/libgstadpcmenc.so @@ -329,8 +330,10 @@ make ERROR_CFLAGS='' ERROR_CXXFLAGS='' %{_libdir}/libgstbasevideo-%{majorminor}.so %{_libdir}/libgstphotography-%{majorminor}.so %{_libdir}/libgstsignalprocessor-%{majorminor}.so +%{_libdir}/libgstcodecparsers-%{majorminor}.so %{_libdir}/libgstbasecamerabinsrc-%{majorminor}.so %{_includedir}/gstreamer-%{majorminor}/gst/interfaces/photography* +%{_includedir}/gstreamer-%{majorminor}/gst/codecparsers %{_includedir}/gstreamer-%{majorminor}/gst/signalprocessor %{_includedir}/gstreamer-%{majorminor}/gst/video %{_includedir}/gstreamer-%{majorminor}/gst/basecamerabinsrc/gstbasecamerasrc.h diff --git a/pkgconfig/gstreamer-plugins-bad.pc.in b/pkgconfig/gstreamer-plugins-bad.pc.in index c75ff59..1fad717 100644 --- a/pkgconfig/gstreamer-plugins-bad.pc.in +++ b/pkgconfig/gstreamer-plugins-bad.pc.in @@ -7,6 +7,7 @@ Name: GStreamer Bad Plugin libraries Description: Currently includes the photography interface library Requires: gstreamer-@GST_MAJORMINOR@ gstreamer-base-@GST_MAJORMINOR@ Version: @VERSION@ -Libs: -L${libdir} -lgstphotography-@GST_MAJORMINOR@ +Libs: -L${libdir} -lgstphotography-@GST_MAJORMINOR@\ + -L${libdir} -lgstcodecparsers-@GST_MAJORMINOR@\ Cflags: -I${includedir} diff --git a/tests/check/Makefile.am b/tests/check/Makefile.am index 174c730..8528eb2 100644 --- a/tests/check/Makefile.am +++ b/tests/check/Makefile.am @@ -183,6 +183,7 @@ check_PROGRAMS = \ pipelines/colorspace \ $(check_mimic) \ elements/rtpmux \ + libs/mpegvideoparser \ $(check_schro) \ $(check_vp8) \ elements/viewfinderbin \ @@ -214,6 +215,15 @@ elements_h263parse_LDADD = libparser.la $(LDADD) elements_h264parse_LDADD = libparser.la $(LDADD) +libs_mpegvideoparser_CFLAGS = \ + $(GST_PLUGINS_BAD_CFLAGS) $(GST_PLUGINS_BASE_CFLAGS) \ + $(GST_BASE_CFLAGS) $(GST_CFLAGS) $(AM_CFLAGS) + +libs_mpegvideoparser_LDADD = \ + $(top_builddir)/gst-libs/gst/codecparsers/libgstcodecparsers-@GST_MAJORMINOR@.la \ + $(GST_PLUGINS_BAD_LIBS) -lgstcodecparsers-@GST_MAJORMINOR@ \ + $(GST_BASE_LIBS) $(GST_LIBS) $(LDADD) + elements_voaacenc_CFLAGS = \ $(GST_PLUGINS_BASE_CFLAGS) \ $(GST_BASE_CFLAGS) $(GST_CFLAGS) $(AM_CFLAGS) diff --git a/tests/check/libs/mpegvideoparser.c b/tests/check/libs/mpegvideoparser.c new file mode 100644 index 0000000..414a45e --- /dev/null +++ b/tests/check/libs/mpegvideoparser.c @@ -0,0 +1,208 @@ +/* Gstreamer + * Copyright (C) <2011> Intel Corporation + * Copyright (C) <2011> Collabora Ltd. + * Copyright (C) <2011> Thibault Saunier + * + * 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. + */ + +#include +#include + +/* actually seq + gop */ +static guint8 mpeg2_seq[] = { + 0x00, 0x00, 0x01, 0xb3, 0x02, 0x00, 0x18, 0x15, 0xff, 0xff, 0xe0, 0x28, + 0x00, 0x00, 0x01, 0xb3, 0x78, 0x04, 0x38, 0x37, 0xff, 0xff, 0xf0, 0x00, + 0x00, 0x00, 0x01, 0xb5, 0x14, 0x8a, 0x00, 0x11, 0x03, 0x71, + 0x00, 0x00, 0x01, 0xb8, 0x00, 0x08, 0x00, 0x00, + 0x00, 0x00, 0x01, 0x03, 0x00, 0x08, 0x00, 0x00 +}; + +static guint8 mis_identified_datas[] = { + 0x00, 0x00, 0x01, 0x1f, 0x4a, 0xf4, 0xd4, 0xd8, 0x08, 0x23, 0xdd, + 0x7c, 0xd3, 0x75, 0x21, 0x43, 0x85, 0x31, 0x43, 0x04, 0x24, 0x30, + 0x18, 0x43, 0xba, 0x1a, 0x50, 0x60, 0xbb, 0x53, 0x56, 0x80, 0x41, + 0xb9, 0xd4, 0x25, 0x42, 0xea, 0x71, 0xb7, 0x49, 0x84, 0x0b, 0x14, + 0x24, 0xc2, 0xaa, 0xba, 0xf9, 0xf7, 0x5b, 0x78, 0xa2, 0xba, 0xd3, + 0xc7, 0x12, 0xee, 0xbe, 0xba, 0xfa, 0xeb, 0xeb, 0xaf, 0xbe, 0x6f, + 0xce, 0x92, 0x05, 0x15, 0x22, 0x44, 0xf4, 0xc9, 0x1b, 0xcd, 0x84, + 0x80, 0x87, 0x35, 0x6c, 0x07, 0x82, 0xaf, 0x3c, 0x3a, 0x89, 0x48, + 0x3a, 0x26, 0x00, 0x64, 0x03, 0x12, 0x60, 0x03, 0xf4, 0x8c, 0x21, + 0x16, 0xbe, 0x3c, 0x7c, 0x18, 0x03, 0x10, 0x0c, 0x80, 0xa0, 0x05, + 0xe1, 0x85, 0x94, 0x90, 0xc4, 0x74, 0x05, 0x72, 0x80, 0x7a, 0x8e, + 0x3e, 0x00, 0x30, + /* The accelerated version of scan_for_start_codes() + * mis-identifies the following as a start code */ + 0x01, 0x00, 0x01, 0x80, 0x68, 0x14, + 0x26, 0xe4, 0x80, 0x98, 0x0a, 0xba, 0x77, 0x01, 0xc2, 0x42, 0x12, + 0xc4, 0x59, 0x2a, 0xbb, 0x49, 0xf2, 0xc5, 0xa8, 0xd9, 0x30, 0x33, + 0x16, 0x50, 0x60, 0x61, 0x41, 0xaa, 0x0d, 0x41, 0x5b, 0x17, 0x77, + 0x76, 0x1a, 0x14, 0x3a, 0x08, 0x19, 0x3d, 0x6c, 0x94, 0x55, 0xd0, + 0x94, 0x5a, 0xeb, 0x61, 0x22, 0xa7, 0xa6, 0x83, 0x47, 0x6d, 0x4d, + 0x84, 0xc4, 0x6f, 0x78, 0xd8, 0x3a, 0xb4, 0x02, 0x0c, 0x36, 0xa6, + 0x0b, 0x18, 0x49, 0xf7, 0xad, 0x00, 0x82, 0x09, 0xba, 0x12, 0xba, + 0x1d, 0x44, 0x94, 0x0a, 0x1b, 0x03, 0xbb, 0xa2, 0x53, 0x02, 0xc0, + 0x41, 0xac, 0x22, + /* the real start code is here */ + 0x00, 0x00, 0x01, 0x20, 0x4a, 0xfd, 0xf5, 0x50 +}; + +static GstMpegVideoPacketTypeCode ordercode[] = { + GST_MPEG_VIDEO_PACKET_SEQUENCE, + GST_MPEG_VIDEO_PACKET_EXTENSION, + GST_MPEG_VIDEO_PACKET_GOP, +}; + +GST_START_TEST (test_mpeg_parse) +{ + gint i; + GList *list, *tmp; + GstMpegVideoTypeOffsetSize *typeoffsz; + + list = gst_mpeg_video_parse (mpeg2_seq, sizeof (mpeg2_seq), 12); + + assert_equals_int (g_list_length (list), 4); + for (tmp = list, i = 0; tmp; tmp = g_list_next (tmp), i++) { + typeoffsz = tmp->data; + if (i == 3) { + fail_unless (GST_MPEG_VIDEO_PACKET_SLICE_MIN <= typeoffsz->type && + typeoffsz->type <= GST_MPEG_VIDEO_PACKET_SLICE_MAX); + fail_unless (typeoffsz->size < 0); + } else + assert_equals_int (ordercode[i], typeoffsz->type); + } + + g_list_free_full (list, (GDestroyNotify) g_free); +} + +GST_END_TEST; + +GST_START_TEST (test_mpeg_parse_sequence_header) +{ + GList *list; + GstMpegVideoTypeOffsetSize *typeoffsz; + GstMpegVideoSequenceHdr seqhdr; + + list = gst_mpeg_video_parse (mpeg2_seq, sizeof (mpeg2_seq), 12); + + typeoffsz = list->data; + fail_unless (typeoffsz->type == GST_MPEG_VIDEO_PACKET_SEQUENCE); + fail_unless (gst_mpeg_video_parse_sequence_header (&seqhdr, mpeg2_seq, + sizeof (mpeg2_seq), typeoffsz->offset)); + assert_equals_int (seqhdr.width, 1920); + assert_equals_int (seqhdr.height, 1080); + assert_equals_int (seqhdr.aspect_ratio_info, 3); + assert_equals_int (seqhdr.par_w, 17280); + assert_equals_int (seqhdr.par_h, 17280); + assert_equals_int (seqhdr.frame_rate_code, 7); + assert_equals_int (seqhdr.fps_n, 60000); + assert_equals_int (seqhdr.fps_d, 1001); + assert_equals_int (seqhdr.bitrate_value, 262143); + assert_equals_int (seqhdr.bitrate, 0); + assert_equals_int (seqhdr.vbv_buffer_size_value, 512); + fail_unless (seqhdr.constrained_parameters_flag == FALSE); + + g_list_free_full (list, (GDestroyNotify) g_free); +} + +GST_END_TEST; + +GST_START_TEST (test_mpeg_parse_sequence_extension) +{ + GList *list; + GstMpegVideoTypeOffsetSize *typeoffsz; + GstMpegVideoSequenceExt seqext; + + list = gst_mpeg_video_parse (mpeg2_seq, sizeof (mpeg2_seq), 12); + + typeoffsz = list->next->data; + fail_unless (typeoffsz->type == GST_MPEG_VIDEO_PACKET_EXTENSION); + fail_unless (gst_mpeg_video_parse_sequence_extension (&seqext, + mpeg2_seq, sizeof (mpeg2_seq), typeoffsz->offset)); + assert_equals_int (seqext.profile, 4); + assert_equals_int (seqext.level, 8); + assert_equals_int (seqext.progressive, 1); + assert_equals_int (seqext.chroma_format, 1); + assert_equals_int (seqext.horiz_size_ext, 0); + assert_equals_int (seqext.vert_size_ext, 0); + assert_equals_int (seqext.vert_size_ext, 0); + assert_equals_int (seqext.bitrate_ext, 8); + assert_equals_int (seqext.vbv_buffer_size_extension, 3); + assert_equals_int (seqext.low_delay, 0); + assert_equals_int (seqext.fps_n_ext, 3); + assert_equals_int (seqext.fps_d_ext, 2); + + g_list_free_full (list, (GDestroyNotify) g_free); +} + +GST_END_TEST; + +GST_START_TEST (test_mis_identified_datas) +{ + GList *list, *tmp; + GstMpegVideoTypeOffsetSize *typeoffsz; + guint8 *data = mis_identified_datas; + + list = gst_mpeg_video_parse (mis_identified_datas, + sizeof (mis_identified_datas), 0); + + assert_equals_int (g_list_length (list), 2); + for (tmp = list; tmp; tmp = g_list_next (tmp)) { + typeoffsz = tmp->data; + + assert_equals_int (data[typeoffsz->offset - 4], 0); + assert_equals_int (data[typeoffsz->offset - 3], 0); + assert_equals_int (data[typeoffsz->offset - 2], 1); + } + + g_list_free_full (list, (GDestroyNotify) g_free); +} + +GST_END_TEST; + +static Suite * +videoparsers_suite (void) +{ + Suite *s = suite_create ("Video Parsers library"); + + TCase *tc_chain = tcase_create ("general"); + + suite_add_tcase (s, tc_chain); + tcase_add_test (tc_chain, test_mpeg_parse); + tcase_add_test (tc_chain, test_mpeg_parse_sequence_header); + tcase_add_test (tc_chain, test_mpeg_parse_sequence_extension); + tcase_add_test (tc_chain, test_mis_identified_datas); + + return s; +} + +int +main (int argc, char **argv) +{ + int nf; + + Suite *s = videoparsers_suite (); + + SRunner *sr = srunner_create (s); + + gst_check_init (&argc, &argv); + + srunner_run_all (sr, CK_NORMAL); + nf = srunner_ntests_failed (sr); + srunner_free (sr); + + return nf; +} -- 2.7.4