diff options
author | Wim Taymans <wim.taymans@collabora.co.uk> | 2011-09-26 22:31:17 +0200 |
---|---|---|
committer | Wim Taymans <wim.taymans@collabora.co.uk> | 2011-09-26 22:31:17 +0200 |
commit | 7f4cf50496ef6797aaba819d0924bb5c4baf09a4 (patch) | |
tree | 44154878bf094cb393c31af479377b98df192ff3 | |
parent | 6a44e54b09dcc7a9d0f4499375810892a8582403 (diff) | |
parent | f4e744ff4921bef432b40128bdd0b33786e44732 (diff) |
Merge branch 'master' into 0.11
67 files changed, 5188 insertions, 1549 deletions
diff --git a/common b/common -Subproject a39eb835fb3be2a4c5a6a89b5ca5cc064e79b2e +Subproject 11f0cd5a3fba36f85cf3e434150bfe66b1bf08d diff --git a/configure.ac b/configure.ac index dda50d4c9..a82ddb72d 100644 --- a/configure.ac +++ b/configure.ac @@ -1735,6 +1735,17 @@ AG_GST_CHECK_FEATURE(RTMP, [rtmp library], rtmp, [ AG_GST_PKG_CHECK_MODULES(RTMP, librtmp) ]) +dnl *** spandsp *** +translit(dnm, m, l) AM_CONDITIONAL(USE_SPANDSP, true) +AG_GST_CHECK_FEATURE(SPANDSP, [Spandsp], spandsp, [ + PKG_CHECK_MODULES(SPANDSP, spandsp >= 0.0.6, [ + HAVE_SPANDSP="yes" ], [ + HAVE_SPANDSP="no" + ]) +]) +AC_SUBST(SPANDSP_CFLAGS) +AC_SUBST(SPANDSP_LIBS) + dnl *** GSettings *** translit(dnm, m, l) AM_CONDITIONAL(USE_GSETTINGS, true) AG_GST_CHECK_FEATURE(GSETTINGS, [GSettings plugin], gsettings, [ @@ -1797,6 +1808,7 @@ AM_CONDITIONAL(USE_WILDMIDI, false) AM_CONDITIONAL(USE_SDL, false) AM_CONDITIONAL(USE_SNDFILE, false) AM_CONDITIONAL(USE_SOUNDTOUCH, false) +AM_CONDITIONAL(USE_SPANDSP, false) AM_CONDITIONAL(USE_SPC, false) AM_CONDITIONAL(USE_GME, false) AM_CONDITIONAL(USE_GSETTINGS, false) @@ -2046,6 +2058,7 @@ ext/schroedinger/Makefile ext/sdl/Makefile ext/sndfile/Makefile ext/soundtouch/Makefile +ext/spandsp/Makefile ext/teletextdec/Makefile ext/gme/Makefile ext/gsettings/Makefile diff --git a/docs/libs/.gitignore b/docs/libs/.gitignore new file mode 100644 index 000000000..83bf78579 --- /dev/null +++ b/docs/libs/.gitignore @@ -0,0 +1,28 @@ +Makefile +Makefile.in + +*-decl.txt +*-decl-list.txt +*-undocumented.txt +*-undeclared.txt +*-unused.txt +*.bak +*.args +*.hierarchy +*.interfaces +*.prerequisites +*.signals + +gst-plugins-bad-libs.args.new +gst-plugins-bad-libs.signals.new + +tmpl +xml +html + +gst-plugins-bad-libs-scan +gst-plugins-bad-libs-scan.c +*-registry.* + +*.stamp + diff --git a/docs/libs/Makefile.am b/docs/libs/Makefile.am index e93bbda17..aaa35658d 100644 --- a/docs/libs/Makefile.am +++ b/docs/libs/Makefile.am @@ -13,43 +13,17 @@ FORMATS=html html: html-build.stamp include $(top_srcdir)/common/upload-doc.mak -# generated basefiles -#basefiles = \ -## $(DOC_MODULE).types \ -# $(DOC_MODULE)-sections.txt \ -# $(DOC_MODULE)-docs.sgml - -# ugly hack to make -unused.sgml work -#unused-build.stamp: -# BUILDDIR=`pwd` && \ -# cd $(srcdir)/tmpl && \ -# ln -sf gstreamer-libs-unused.sgml \ -# $$BUILDDIR/tmpl/gstreamer-libs-@GST_MAJORMINOR@-unused.sgml -# touch unused-build.stamp - -# these rules are added to create parallel docs using GST_MAJORMINOR -#$(basefiles): gstreamer-libs-@GST_MAJORMINOR@%: gstreamer-libs% -# cp $< $@ - -#CLEANFILES = $(basefiles) - # The top-level SGML file. Change it if you want. DOC_MAIN_SGML_FILE=$(DOC_MODULE)-docs.sgml -# The directory containing the source code. Relative to $(top_srcdir). +# The directory containing the source code. # gtk-doc will search all .c & .h files beneath here for inline comments # documenting functions and macros. DOC_SOURCE_DIR=$(top_srcdir)/gst-libs/gst -DOC_BUILD_DIR=$(top_builddir)/gst-libs/gst # Extra options to supply to gtkdoc-scan. SCAN_OPTIONS=--deprecated-guards="GST_DISABLE_DEPRECATED" -# FIXME : -# there's something wrong with gstreamer-sections.txt not being in the dist -# maybe it doesn't resolve; we're adding it below for now -#EXTRA_DIST = gstreamer.types.in gstreamer.hierarchy $(DOC_MODULE)-sections.txt gstreamer-sections.txt $(DOC_MAIN_SGML_FILE) - # Extra options to supply to gtkdoc-mkdb. MKDB_OPTIONS=--sgml-mode --output-format=xml @@ -58,20 +32,8 @@ FIXXREF_OPTIONS=--extra-dir=$(GLIB_PREFIX)/share/gtk-doc/html \ --extra-dir=$(GST_PREFIX)/share/gtk-doc/html # Used for dependencies. -HFILE_GLOB=$(DOC_SOURCE_DIR)/*/*.h -CFILE_GLOB=$(DOC_SOURCE_DIR)/*/*.c - -# this is a wingo addition -# thomasvs: another nice wingo addition would be an explanation on why -# this is useful ;) - -SCANOBJ_DEPS = \ - $(top_builddir)/gst-libs/gst/codecparsers/libgstcodecparsers-@GST_MAJORMINOR@.la \ - $(top_builddir)/gst-libs/gst/basecamerabinsrc/libgstbasecamerabinsrc-@GST_MAJORMINOR@.la \ - $(top_builddir)/gst-libs/gst/interfaces/libgstphotography-@GST_MAJORMINOR@.la \ - $(top_builddir)/gst-libs/gst/signalprocessor/libgstsignalprocessor-@GST_MAJORMINOR@.la \ - $(top_builddir)/gst-libs/gst/video/libgstbasevideo-@GST_MAJORMINOR@.la - +HFILE_GLOB=$(top_srcdir)/gst-libs/gst/*/*.h +CFILE_GLOB=$(top_srcdir)/gst-libs/gst/*/*.c # Header files to ignore when scanning. IGNORE_HFILES = @@ -88,7 +50,13 @@ extra_files = # CFLAGS and LDFLAGS for compiling scan program. Only needed if your app/lib # contains GtkObjects/GObjects and you want to document signals and properties. GTKDOC_CFLAGS = $(GST_PLUGINS_BAD_CFLAGS) $(GST_BAD_CFLAGS) $(GST_PLUGINS_BASE_CFLAGS) $(GST_BASE_CFLAGS) -GTKDOC_LIBS = $(SCANOBJ_DEPS) $(GST_BASE_LIBS) $(GST_BAD_LIBS) +GTKDOC_LIBS = \ + $(top_builddir)/gst-libs/gst/codecparsers/libgstcodecparsers-@GST_MAJORMINOR@.la \ + $(top_builddir)/gst-libs/gst/basecamerabinsrc/libgstbasecamerabinsrc-@GST_MAJORMINOR@.la \ + $(top_builddir)/gst-libs/gst/interfaces/libgstphotography-@GST_MAJORMINOR@.la \ + $(top_builddir)/gst-libs/gst/signalprocessor/libgstsignalprocessor-@GST_MAJORMINOR@.la \ + $(top_builddir)/gst-libs/gst/video/libgstbasevideo-@GST_MAJORMINOR@.la \ + $(GST_BASE_LIBS) $(GST_BAD_LIBS) GTKDOC_CC=$(LIBTOOL) --tag=CC --mode=compile $(CC) GTKDOC_LD=$(LIBTOOL) --tag=CC --mode=link $(CC) diff --git a/docs/libs/gst-plugins-bad-libs-docs.sgml b/docs/libs/gst-plugins-bad-libs-docs.sgml index f137ca3c2..bc648842e 100644 --- a/docs/libs/gst-plugins-bad-libs-docs.sgml +++ b/docs/libs/gst-plugins-bad-libs-docs.sgml @@ -30,6 +30,7 @@ </para> <xi:include href="xml/gsth264parser.xml" /> <xi:include href="xml/gstmpegvideoparser.xml" /> + <xi:include href="xml/gstvc1parser.xml" /> </chapter> <chapter id="video"> diff --git a/docs/libs/gst-plugins-bad-libs-sections.txt b/docs/libs/gst-plugins-bad-libs-sections.txt index 73cc72019..cd515e6af 100644 --- a/docs/libs/gst-plugins-bad-libs-sections.txt +++ b/docs/libs/gst-plugins-bad-libs-sections.txt @@ -45,6 +45,40 @@ gst_h264_parse_pps </SECTION> <SECTION> +<FILE>gstvc1parser</FILE> +<TITLE>vc1parser</TITLE> +<INCLUDE>gst/codecparsers/gstvc1parser.h</INCLUDE> +MAX_HRD_NUM_LEAKY_BUCKETS +GST_VC1_BFRACTION_BASIS +GstVC1StartCode +GstVC1Profile +GstVC1ParseResult +GstVC1PictureType +GstVC1Level +GstVC1QuantizerSpec +GstVC1DQProfile +GstVC1Condover +GstVC1MvMode +GstVC1SeqHdr +GstVC1AdvancedSeqHdr +GstVC1SimpleMainSeqHdr +GstVC1HrdParam +GstVC1EntryPointHdr +GstVC1FrameHdr +GstVC1PicAdvanced +GstVC1PicSimpleMain +GstVC1Picture +GstVC1VopDquant +GstVC1BDU +gst_vc1_identify_next_bdu +gst_vc1_parse_sequence_header +gst_vc1_parse_entry_point_header +gst_vc1_parse_frame_header +<SUBSECTION Standard> +<SUBSECTION Private> +</SECTION> + +<SECTION> <FILE>gstmpegvideoparser</FILE> <TITLE>mpegvideoparser</TITLE> <INCLUDE>gst/codecparsers/gstmpegvideoparser.h</INCLUDE> diff --git a/docs/plugins/Makefile.am b/docs/plugins/Makefile.am index 4f8f0cfcd..a948927df 100644 --- a/docs/plugins/Makefile.am +++ b/docs/plugins/Makefile.am @@ -13,33 +13,13 @@ FORMATS=html html: html-build.stamp include $(top_srcdir)/common/upload-doc.mak -# generated basefiles -#basefiles = \ -## $(DOC_MODULE).types \ -# $(DOC_MODULE)-sections.txt \ -# $(DOC_MODULE)-docs.sgml - -# ugly hack to make -unused.sgml work -#unused-build.stamp: -# BUILDDIR=`pwd` && \ -# cd $(srcdir)/tmpl && \ -# ln -sf gstreamer-libs-unused.sgml \ -# $$BUILDDIR/tmpl/gstreamer-libs-@GST_MAJORMINOR@-unused.sgml -# touch unused-build.stamp - -# these rules are added to create parallel docs using GST_MAJORMINOR -#$(basefiles): gstreamer-libs-@GST_MAJORMINOR@%: gstreamer-libs% -# cp $< $@ - -#CLEANFILES = $(basefiles) - # The top-level SGML file. Change it if you want. DOC_MAIN_SGML_FILE=$(DOC_MODULE)-docs.sgml -# The directory containing the source code. Relative to $(top_srcdir). +# The directory containing the source code. # gtk-doc will search all .c & .h files beneath here for inline comments # documenting functions and macros. -DOC_SOURCE_DIR = $(top_srcdir) +DOC_SOURCE_DIR = $(top_srcdir)/gst $(top_srcdir)/ext $(top_srcdir)/sys # Extra options to supply to gtkdoc-scan. SCAN_OPTIONS= @@ -53,15 +33,12 @@ FIXXREF_OPTIONS=--extra-dir=$(GLIB_PREFIX)/share/gtk-doc/html \ --extra-dir=$(GSTPB_PREFIX)/share/gtk-doc/html # Used for dependencies. -HFILE_GLOB=$(DOC_SOURCE_DIR)/*/*/*.h $(DOC_SOURCE_DIR)/*/*/*.hh -CFILE_GLOB=$(DOC_SOURCE_DIR)/*/*/*.c $(DOC_SOURCE_DIR)/*/*/*.cc - -# this is a wingo addition -# thomasvs: another nice wingo addition would be an explanation on why -# this is useful ;) - -SCANOBJ_DEPS = \ - $(top_builddir)/gst-libs/gst/interfaces/libgstphotography-@GST_MAJORMINOR@.la +HFILE_GLOB= \ + $(top_srcdir)/gst/*/*.h $(top_srcdir)/ext/*/*.h $(top_srcdir)/sys/*/*.h \ + $(top_srcdir)/ext/*/*.hh +CFILE_GLOB= \ + $(top_srcdir)/gst/*/*.c $(top_srcdir)/ext/*/*.c $(top_srcdir)/sys/*/*.c \ + $(top_srcdir)/ext/*/*.cc $(top_srcdir)/sys/*/*.m # Header files to ignore when scanning. IGNORE_HFILES = @@ -214,7 +191,9 @@ extra_files = # CFLAGS and LDFLAGS for compiling scan program. Only needed if your app/lib # contains GtkObjects/GObjects and you want to document signals and properties. GTKDOC_CFLAGS = -DGST_USE_UNSTABLE_API $(GST_PLUGINS_BAD_CFLAGS) $(GST_BASE_CFLAGS) -I$(top_builddir) -GTKDOC_LIBS = $(SCANOBJ_DEPS) $(GST_BASE_LIBS) +GTKDOC_LIBS = \ + $(top_builddir)/gst-libs/gst/interfaces/libgstphotography-@GST_MAJORMINOR@.la \ + $(GST_BASE_LIBS) GTKDOC_CC=$(LIBTOOL) --tag=CC --mode=compile $(CC) GTKDOC_LD=$(LIBTOOL) --tag=CC --mode=link $(CC) diff --git a/docs/plugins/gst-plugins-bad-plugins-sections.txt b/docs/plugins/gst-plugins-bad-plugins-sections.txt index 29315d4af..d7fc96e95 100644 --- a/docs/plugins/gst-plugins-bad-plugins-sections.txt +++ b/docs/plugins/gst-plugins-bad-plugins-sections.txt @@ -121,12 +121,12 @@ gst_camerabin_get_type GstCameraBin2 <SUBSECTION Standard> GstCameraBin2Class -GST_CAMERABIN2 -GST_IS_CAMERABIN2 -GST_TYPE_CAMERABIN2 -GST_CAMERABIN2_CLASS -GST_IS_CAMERABIN2_CLASS -gst_camerabin2_get_type +GST_CAMERA_BIN2 +GST_IS_CAMERA_BIN2 +GST_TYPE_CAMERA_BIN2 +GST_CAMERA_BIN2_CLASS +GST_IS_CAMERA_BIN2_CLASS +gst_camera_bin2_get_type </SECTION> <SECTION> diff --git a/ext/Makefile.am b/ext/Makefile.am index 2a6f8ec76..95ba3da75 100644 --- a/ext/Makefile.am +++ b/ext/Makefile.am @@ -324,6 +324,12 @@ else SOUNDTOUCH_DIR= endif +if USE_SPANDSP +SPANDSP_DIR = spandsp +else +SPANDSP_DIR = +endif + if USE_SPC SPC_DIR=spc else @@ -433,6 +439,7 @@ SUBDIRS=\ $(SMOOTHWAVE_DIR) \ $(SNDFILE_DIR) \ $(SOUNDTOUCH_DIR) \ + $(SPANDSP_DIR) \ $(GME_DIR) \ $(SPC_DIR) \ $(SWFDEC_DIR) \ @@ -485,6 +492,7 @@ DIST_SUBDIRS = \ sdl \ sndfile \ soundtouch \ + spandsp \ spc \ gme \ swfdec \ diff --git a/ext/celt/gstceltdec.c b/ext/celt/gstceltdec.c index f80e5cdb1..6d3d9433c 100644 --- a/ext/celt/gstceltdec.c +++ b/ext/celt/gstceltdec.c @@ -560,8 +560,11 @@ celt_dec_chain_parse_header (GstCeltDec * dec, GstBuffer * buf) gint error = CELT_OK; /* get the header */ - celt_header_from_packet ((const unsigned char *) GST_BUFFER_DATA (buf), + error = + celt_header_from_packet ((const unsigned char *) GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf), &dec->header); + if (error < 0) + goto invalid_header; if (memcmp (dec->header.codec_id, "CELT ", 8) != 0) goto invalid_header; @@ -760,7 +763,11 @@ celt_dec_chain_parse_data (GstCeltDec * dec, GstBuffer * buf, #else error = celt_decode (dec->state, data, size, out_data); #endif +#ifdef HAVE_CELT_0_11 + if (error < 0) { +#else if (error != CELT_OK) { +#endif GST_WARNING_OBJECT (dec, "Decoding error: %d", error); return GST_FLOW_ERROR; } diff --git a/ext/celt/gstceltenc.c b/ext/celt/gstceltenc.c index 74815798e..9e6944df0 100644 --- a/ext/celt/gstceltenc.c +++ b/ext/celt/gstceltenc.c @@ -253,6 +253,9 @@ gst_celt_enc_sink_setcaps (GstPad * pad, GstCaps * caps) gst_caps_unref (otherpadcaps); } + if (enc->requested_frame_size > 0) + enc->frame_size = enc->requested_frame_size; + GST_DEBUG_OBJECT (pad, "channels=%d rate=%d frame-size=%d", enc->channels, enc->rate, enc->frame_size); @@ -573,6 +576,7 @@ gst_celt_enc_init (GstCeltEnc * enc, GstCeltEncClass * klass) enc->bitrate = DEFAULT_BITRATE; enc->frame_size = DEFAULT_FRAMESIZE; + enc->requested_frame_size = -1; enc->cbr = DEFAULT_CBR; enc->complexity = DEFAULT_COMPLEXITY; enc->max_bitrate = DEFAULT_MAX_BITRATE; @@ -695,16 +699,18 @@ encoder_creation_failed: /* prepare a buffer for transmission */ static GstBuffer * gst_celt_enc_buffer_from_data (GstCeltEnc * enc, guchar * data, - gint data_len, guint64 granulepos) + guint data_len, gint64 granulepos) { GstBuffer *outbuf; - outbuf = gst_buffer_new_and_alloc (data_len); - memcpy (GST_BUFFER_DATA (outbuf), data, data_len); + outbuf = gst_buffer_new (); + GST_BUFFER_DATA (outbuf) = data; + GST_BUFFER_MALLOCDATA (outbuf) = data; + GST_BUFFER_SIZE (outbuf) = data_len; GST_BUFFER_OFFSET (outbuf) = enc->bytes_out; GST_BUFFER_OFFSET_END (outbuf) = granulepos; - GST_LOG_OBJECT (enc, "encoded buffer of %d bytes", GST_BUFFER_SIZE (outbuf)); + GST_LOG_OBJECT (enc, "encoded buffer of %u bytes", GST_BUFFER_SIZE (outbuf)); return outbuf; } @@ -903,11 +909,17 @@ gst_celt_enc_chain (GstPad * pad, GstBuffer * buf) constraints */ GstBuffer *buf1, *buf2; GstCaps *caps; - guchar data[100]; + /* libcelt has a bug which underestimates header size by 4... */ + unsigned int header_size = enc->header.header_size + 4; + unsigned char *data = g_malloc (header_size); /* create header buffer */ - celt_header_to_packet (&enc->header, data, 100); - buf1 = gst_celt_enc_buffer_from_data (enc, data, 100, 0); + int error = celt_header_to_packet (&enc->header, data, header_size); + if (error < 0) { + g_free (data); + goto no_header; + } + buf1 = gst_celt_enc_buffer_from_data (enc, data, header_size, 0); /* create comment buffer */ buf2 = gst_celt_enc_create_metadata_buffer (enc); @@ -966,6 +978,7 @@ gst_celt_enc_chain (GstPad * pad, GstBuffer * buf) /* Check if we have a continous stream, if not drop some samples or the buffer or * insert some silence samples */ if (enc->next_ts != GST_CLOCK_TIME_NONE && + GST_BUFFER_TIMESTAMP_IS_VALID (buf) && GST_BUFFER_TIMESTAMP (buf) < enc->next_ts) { guint64 diff = enc->next_ts - GST_BUFFER_TIMESTAMP (buf); guint64 diff_bytes; @@ -1038,6 +1051,13 @@ not_setup: goto done; } +no_header: + { + GST_ELEMENT_ERROR (enc, STREAM, ENCODE, (NULL), + ("Failed to encode header")); + ret = GST_FLOW_ERROR; + goto done; + } } @@ -1090,7 +1110,8 @@ gst_celt_enc_set_property (GObject * object, guint prop_id, enc->bitrate = g_value_get_int (value); break; case PROP_FRAMESIZE: - enc->frame_size = g_value_get_int (value); + enc->requested_frame_size = g_value_get_int (value); + enc->frame_size = enc->requested_frame_size; break; case PROP_CBR: enc->cbr = g_value_get_boolean (value); diff --git a/ext/celt/gstceltenc.h b/ext/celt/gstceltenc.h index ec8a283c0..86fbc36f3 100644 --- a/ext/celt/gstceltenc.h +++ b/ext/celt/gstceltenc.h @@ -62,6 +62,7 @@ struct _GstCeltEnc { gint bitrate; gint frame_size; + gint requested_frame_size; gboolean cbr; gint complexity; gint max_bitrate; diff --git a/ext/faac/Makefile.am b/ext/faac/Makefile.am index 13918ed3e..2aafa0229 100644 --- a/ext/faac/Makefile.am +++ b/ext/faac/Makefile.am @@ -1,7 +1,8 @@ plugin_LTLIBRARIES = libgstfaac.la libgstfaac_la_SOURCES = gstfaac.c -libgstfaac_la_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(GST_BASE_CFLAGS) \ +libgstfaac_la_CFLAGS = -DGST_USE_UNSTABLE_API \ + $(GST_PLUGINS_BASE_CFLAGS) $(GST_BASE_CFLAGS) \ $(GST_CFLAGS) $(FAAC_CFLAGS) libgstfaac_la_LIBADD = $(GST_PLUGINS_BASE_LIBS) \ -lgstaudio-@GST_MAJORMINOR@ -lgstpbutils-@GST_MAJORMINOR@ \ diff --git a/ext/faac/gstfaac.c b/ext/faac/gstfaac.c index c0db878d5..eb132d3b4 100644 --- a/ext/faac/gstfaac.c +++ b/ext/faac/gstfaac.c @@ -91,12 +91,6 @@ "rate = (int) {" SAMPLE_RATES "}, " \ "stream-format = (string) { adts, raw }, " \ "profile = (string) { main, lc }" - enum -{ - VBR = 1, - ABR -}; - static GstStaticPadTemplate src_template = GST_STATIC_PAD_TEMPLATE ("src", GST_PAD_SRC, GST_PAD_ALWAYS, @@ -119,74 +113,41 @@ enum PROP_SHORTCTL }; -static void gst_faac_base_init (GstFaacClass * klass); -static void gst_faac_class_init (GstFaacClass * klass); -static void gst_faac_init (GstFaac * faac); -static void gst_faac_finalize (GObject * object); -static void gst_faac_reset (GstFaac * faac); +enum +{ + VBR = 1, + ABR +}; static void gst_faac_set_property (GObject * object, guint prop_id, const GValue * value, GParamSpec * pspec); static void gst_faac_get_property (GObject * object, guint prop_id, GValue * value, GParamSpec * pspec); -static gboolean gst_faac_sink_event (GstPad * pad, GstEvent * event); static gboolean gst_faac_configure_source_pad (GstFaac * faac); -static gboolean gst_faac_sink_setcaps (GstPad * pad, GstCaps * caps); -static GstCaps *gst_faac_sink_getcaps (GstPad * pad); -static GstFlowReturn gst_faac_push_buffers (GstFaac * faac, gboolean force); -static GstFlowReturn gst_faac_chain (GstPad * pad, GstBuffer * data); -static GstStateChangeReturn gst_faac_change_state (GstElement * element, - GstStateChange transition); +static GstCaps *gst_faac_getcaps (GstAudioEncoder * enc); -static GstElementClass *parent_class = NULL; +static gboolean gst_faac_start (GstAudioEncoder * enc); +static gboolean gst_faac_stop (GstAudioEncoder * enc); +static gboolean gst_faac_set_format (GstAudioEncoder * enc, + GstAudioInfo * info); +static GstFlowReturn gst_faac_handle_frame (GstAudioEncoder * enc, + GstBuffer * in_buf); GST_DEBUG_CATEGORY_STATIC (faac_debug); #define GST_CAT_DEFAULT faac_debug -#define FAAC_DEFAULT_OUTPUTFORMAT 0 /* RAW */ #define FAAC_DEFAULT_QUALITY 100 #define FAAC_DEFAULT_BITRATE 128 * 1000 -#define FAAC_DEFAULT_RATE_CONTROL VBR +#define FAAC_DEFAULT_RATE_CONTROL VBR #define FAAC_DEFAULT_TNS FALSE #define FAAC_DEFAULT_MIDSIDE TRUE #define FAAC_DEFAULT_SHORTCTL SHORTCTL_NORMAL -GType -gst_faac_get_type (void) -{ - static GType gst_faac_type = 0; - - if (!gst_faac_type) { - static const GTypeInfo gst_faac_info = { - sizeof (GstFaacClass), - (GBaseInitFunc) gst_faac_base_init, - NULL, - (GClassInitFunc) gst_faac_class_init, - NULL, - NULL, - sizeof (GstFaac), - 0, - (GInstanceInitFunc) gst_faac_init, - }; - const GInterfaceInfo preset_interface_info = { - NULL, /* interface_init */ - NULL, /* interface_finalize */ - NULL /* interface_data */ - }; - - gst_faac_type = g_type_register_static (GST_TYPE_ELEMENT, - "GstFaac", &gst_faac_info, 0); - - g_type_add_interface_static (gst_faac_type, GST_TYPE_PRESET, - &preset_interface_info); - } - - return gst_faac_type; -} +GST_BOILERPLATE (GstFaac, gst_faac, GstAudioEncoder, GST_TYPE_AUDIO_ENCODER); static void -gst_faac_base_init (GstFaacClass * klass) +gst_faac_base_init (gpointer klass) { GstElementClass *element_class = GST_ELEMENT_CLASS (klass); @@ -248,106 +209,80 @@ static void gst_faac_class_init (GstFaacClass * klass) { GObjectClass *gobject_class = G_OBJECT_CLASS (klass); - GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass); + GstAudioEncoderClass *base_class = GST_AUDIO_ENCODER_CLASS (klass); parent_class = g_type_class_peek_parent (klass); gobject_class->set_property = gst_faac_set_property; gobject_class->get_property = gst_faac_get_property; - gobject_class->finalize = GST_DEBUG_FUNCPTR (gst_faac_finalize); + + base_class->start = GST_DEBUG_FUNCPTR (gst_faac_start); + base_class->stop = GST_DEBUG_FUNCPTR (gst_faac_stop); + base_class->set_format = GST_DEBUG_FUNCPTR (gst_faac_set_format); + base_class->handle_frame = GST_DEBUG_FUNCPTR (gst_faac_handle_frame); + base_class->getcaps = GST_DEBUG_FUNCPTR (gst_faac_getcaps); /* properties */ g_object_class_install_property (gobject_class, PROP_QUALITY, g_param_spec_int ("quality", "Quality (%)", "Variable bitrate (VBR) quantizer quality in %", 1, 1000, - FAAC_DEFAULT_QUALITY, G_PARAM_READWRITE)); + FAAC_DEFAULT_QUALITY, + G_PARAM_CONSTRUCT | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); g_object_class_install_property (gobject_class, PROP_BITRATE, g_param_spec_int ("bitrate", "Bitrate (bps)", - "Average bitrate (ABR) in bits/sec", 8 * 1000, 320 * 1000, - FAAC_DEFAULT_BITRATE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + "Average Bitrate (ABR) in bits/sec", 8 * 1000, 320 * 1000, + FAAC_DEFAULT_BITRATE, + G_PARAM_CONSTRUCT | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); g_object_class_install_property (gobject_class, PROP_RATE_CONTROL, g_param_spec_enum ("rate-control", "Rate Control (ABR/VBR)", "Encoding bitrate type (VBR/ABR)", GST_TYPE_FAAC_RATE_CONTROL, - FAAC_DEFAULT_RATE_CONTROL, G_PARAM_READWRITE)); + FAAC_DEFAULT_RATE_CONTROL, + G_PARAM_CONSTRUCT | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); g_object_class_install_property (gobject_class, PROP_TNS, g_param_spec_boolean ("tns", "TNS", "Use temporal noise shaping", - FAAC_DEFAULT_TNS, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + FAAC_DEFAULT_TNS, + G_PARAM_CONSTRUCT | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); g_object_class_install_property (gobject_class, PROP_MIDSIDE, g_param_spec_boolean ("midside", "Midside", "Allow mid/side encoding", - FAAC_DEFAULT_MIDSIDE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + FAAC_DEFAULT_MIDSIDE, + G_PARAM_CONSTRUCT | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); g_object_class_install_property (gobject_class, PROP_SHORTCTL, g_param_spec_enum ("shortctl", "Block type", "Block type encorcing", GST_TYPE_FAAC_SHORTCTL, FAAC_DEFAULT_SHORTCTL, - G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); - - /* virtual functions */ - gstelement_class->change_state = GST_DEBUG_FUNCPTR (gst_faac_change_state); + G_PARAM_CONSTRUCT | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); } static void -gst_faac_init (GstFaac * faac) +gst_faac_init (GstFaac * faac, GstFaacClass * klass) { - faac->sinkpad = gst_pad_new_from_static_template (&sink_template, "sink"); - gst_pad_set_chain_function (faac->sinkpad, - GST_DEBUG_FUNCPTR (gst_faac_chain)); - gst_pad_set_setcaps_function (faac->sinkpad, - GST_DEBUG_FUNCPTR (gst_faac_sink_setcaps)); - gst_pad_set_getcaps_function (faac->sinkpad, - GST_DEBUG_FUNCPTR (gst_faac_sink_getcaps)); - gst_pad_set_event_function (faac->sinkpad, - GST_DEBUG_FUNCPTR (gst_faac_sink_event)); - gst_element_add_pad (GST_ELEMENT (faac), faac->sinkpad); - - faac->srcpad = gst_pad_new_from_static_template (&src_template, "src"); - gst_pad_use_fixed_caps (faac->srcpad); - gst_element_add_pad (GST_ELEMENT (faac), faac->srcpad); - - faac->adapter = gst_adapter_new (); - - faac->profile = LOW; - faac->mpegversion = 4; - - /* default properties */ - faac->quality = FAAC_DEFAULT_QUALITY; - faac->bitrate = FAAC_DEFAULT_BITRATE; - faac->brtype = FAAC_DEFAULT_RATE_CONTROL; - faac->shortctl = FAAC_DEFAULT_SHORTCTL; - faac->outputformat = FAAC_DEFAULT_OUTPUTFORMAT; - faac->tns = FAAC_DEFAULT_TNS; - faac->midside = FAAC_DEFAULT_MIDSIDE; - - gst_faac_reset (faac); } static void -gst_faac_reset (GstFaac * faac) +gst_faac_close_encoder (GstFaac * faac) { + if (faac->handle) + faacEncClose (faac->handle); faac->handle = NULL; - faac->samplerate = -1; - faac->channels = -1; - faac->offset = 0; - gst_adapter_clear (faac->adapter); } -static void -gst_faac_finalize (GObject * object) +static gboolean +gst_faac_start (GstAudioEncoder * enc) { - GstFaac *faac = (GstFaac *) object; + GstFaac *faac = GST_FAAC (enc); - g_object_unref (faac->adapter); - - G_OBJECT_CLASS (parent_class)->finalize (object); + GST_DEBUG_OBJECT (faac, "start"); + return TRUE; } -static void -gst_faac_close_encoder (GstFaac * faac) +static gboolean +gst_faac_stop (GstAudioEncoder * enc) { - if (faac->handle) - faacEncClose (faac->handle); - faac->handle = NULL; - gst_adapter_clear (faac->adapter); - faac->offset = 0; + GstFaac *faac = GST_FAAC (enc); + + GST_DEBUG_OBJECT (faac, "stop"); + gst_faac_close_encoder (faac); + return TRUE; } static const GstAudioChannelPosition aac_channel_positions[][8] = { @@ -380,7 +315,7 @@ static const GstAudioChannelPosition aac_channel_positions[][8] = { }; static GstCaps * -gst_faac_sink_getcaps (GstPad * pad) +gst_faac_getcaps (GstAudioEncoder * enc) { static volatile gsize sinkcaps = 0; @@ -433,87 +368,29 @@ gst_faac_sink_getcaps (GstPad * pad) gst_structure_free (s); g_value_unset (&rates_arr); - GST_DEBUG_OBJECT (pad, "Generated sinkcaps: %" GST_PTR_FORMAT, tmp); + GST_DEBUG_OBJECT (enc, "Generated sinkcaps: %" GST_PTR_FORMAT, tmp); g_once_init_leave (&sinkcaps, (gsize) tmp); } - return gst_caps_ref ((GstCaps *) sinkcaps); -} - -/* check downstream caps to configure format */ -static void -gst_faac_negotiate (GstFaac * faac) -{ - GstCaps *caps; - - caps = gst_pad_get_allowed_caps (faac->srcpad); - - GST_DEBUG_OBJECT (faac, "allowed caps: %" GST_PTR_FORMAT, caps); - - if (caps && gst_caps_get_size (caps) > 0) { - GstStructure *s = gst_caps_get_structure (caps, 0); - const gchar *str = NULL; - gint i = 4; - - if ((str = gst_structure_get_string (s, "stream-format"))) { - if (strcmp (str, "adts") == 0) { - GST_DEBUG_OBJECT (faac, "use ADTS format for output"); - faac->outputformat = 1; - } else if (strcmp (str, "raw") == 0) { - GST_DEBUG_OBJECT (faac, "use RAW format for output"); - faac->outputformat = 0; - } else { - GST_DEBUG_OBJECT (faac, "unknown stream-format: %s", str); - faac->outputformat = 0; - } - } - - if ((str = gst_structure_get_string (s, "profile"))) { - if (strcmp (str, "main") == 0) { - faac->profile = MAIN; - } else if (strcmp (str, "lc") == 0) { - faac->profile = LOW; - } else if (strcmp (str, "ssr") == 0) { - faac->profile = SSR; - } else if (strcmp (str, "ltp") == 0) { - faac->profile = LTP; - } else { - faac->profile = LOW; - } - } - - if (!gst_structure_get_int (s, "mpegversion", &i) || i == 4) { - faac->mpegversion = 4; - } else { - faac->mpegversion = 2; - } - } - - if (caps) - gst_caps_unref (caps); + return gst_audio_encoder_proxy_getcaps (enc, (GstCaps *) sinkcaps); } static gboolean -gst_faac_sink_setcaps (GstPad * pad, GstCaps * caps) +gst_faac_set_format (GstAudioEncoder * enc, GstAudioInfo * info) { - GstFaac *faac = GST_FAAC (gst_pad_get_parent (pad)); - GstStructure *structure = gst_caps_get_structure (caps, 0); + GstFaac *faac = GST_FAAC (enc); faacEncHandle *handle; gint channels, samplerate, width; gulong samples, bytes, fmt = 0, bps = 0; gboolean result = FALSE; - if (!gst_caps_is_fixed (caps)) - goto refuse_caps; - - if (!gst_structure_get_int (structure, "channels", &channels) || - !gst_structure_get_int (structure, "rate", &samplerate)) { - goto refuse_caps; - } + /* base class takes care */ + channels = GST_AUDIO_INFO_CHANNELS (info); + samplerate = GST_AUDIO_INFO_RATE (info); + width = GST_AUDIO_INFO_WIDTH (info); - if (gst_structure_has_name (structure, "audio/x-raw-int")) { - gst_structure_get_int (structure, "width", &width); + if (GST_AUDIO_INFO_IS_INTEGER (info)) { switch (width) { case 16: fmt = FAAC_INPUT_16BIT; @@ -527,30 +404,20 @@ gst_faac_sink_setcaps (GstPad * pad, GstCaps * caps) default: g_return_val_if_reached (FALSE); } - } else if (gst_structure_has_name (structure, "audio/x-raw-float")) { + } else { fmt = FAAC_INPUT_FLOAT; bps = 4; } - if (!fmt) - goto refuse_caps; - - /* If the encoder is initialized, do not - reinitialize it again if not necessary */ - if (faac->handle) { - if (samplerate == faac->samplerate && channels == faac->channels && - fmt == faac->format) - return TRUE; - - /* clear out pending frames */ - gst_faac_push_buffers (faac, TRUE); - - gst_faac_close_encoder (faac); - } + /* clean up in case of re-configure */ + gst_faac_close_encoder (faac); if (!(handle = faacEncOpen (samplerate, channels, &samples, &bytes))) goto setup_failed; + /* mind channel count */ + samples /= channels; + /* ok, record and set up */ faac->format = fmt; faac->bps = bps; @@ -560,13 +427,15 @@ gst_faac_sink_setcaps (GstPad * pad, GstCaps * caps) faac->channels = channels; faac->samplerate = samplerate; - gst_faac_negotiate (faac); - /* finish up */ result = gst_faac_configure_source_pad (faac); + /* report needs to base class */ + gst_audio_encoder_set_frame_samples_min (enc, samples); + gst_audio_encoder_set_frame_samples_max (enc, samples); + gst_audio_encoder_set_frame_max (enc, 1); + done: - gst_object_unref (faac); return result; /* ERRORS */ @@ -575,11 +444,64 @@ setup_failed: GST_ELEMENT_ERROR (faac, LIBRARY, SETTINGS, (NULL), (NULL)); goto done; } -refuse_caps: - { - GST_WARNING_OBJECT (faac, "refused caps %" GST_PTR_FORMAT, caps); - goto done; +} + +/* check downstream caps to configure format */ +static void +gst_faac_negotiate (GstFaac * faac) +{ + GstCaps *caps; + + /* default setup */ + faac->profile = LOW; + faac->mpegversion = 4; + faac->outputformat = 0; + + caps = gst_pad_get_allowed_caps (GST_AUDIO_ENCODER_SRC_PAD (faac)); + + GST_DEBUG_OBJECT (faac, "allowed caps: %" GST_PTR_FORMAT, caps); + + if (caps && gst_caps_get_size (caps) > 0) { + GstStructure *s = gst_caps_get_structure (caps, 0); + const gchar *str = NULL; + gint i = 4; + + if ((str = gst_structure_get_string (s, "stream-format"))) { + if (strcmp (str, "adts") == 0) { + GST_DEBUG_OBJECT (faac, "use ADTS format for output"); + faac->outputformat = 1; + } else if (strcmp (str, "raw") == 0) { + GST_DEBUG_OBJECT (faac, "use RAW format for output"); + faac->outputformat = 0; + } else { + GST_DEBUG_OBJECT (faac, "unknown stream-format: %s", str); + faac->outputformat = 0; + } + } + + if ((str = gst_structure_get_string (s, "profile"))) { + if (strcmp (str, "main") == 0) { + faac->profile = MAIN; + } else if (strcmp (str, "lc") == 0) { + faac->profile = LOW; + } else if (strcmp (str, "ssr") == 0) { + faac->profile = SSR; + } else if (strcmp (str, "ltp") == 0) { + faac->profile = LTP; + } else { + faac->profile = LOW; + } + } + + if (!gst_structure_get_int (s, "mpegversion", &i) || i == 4) { + faac->mpegversion = 4; + } else { + faac->mpegversion = 2; + } } + + if (caps) + gst_caps_unref (caps); } static gboolean @@ -590,6 +512,9 @@ gst_faac_configure_source_pad (GstFaac * faac) faacEncConfiguration *conf; guint maxbitrate; + /* negotiate stream format */ + gst_faac_negotiate (faac); + /* we negotiated caps update current configuration */ conf = faacEncGetCurrentConfiguration (faac->handle); conf->mpegVersion = (faac->mpegversion == 4) ? MPEG4 : MPEG2; @@ -698,7 +623,7 @@ gst_faac_configure_source_pad (GstFaac * faac) GST_DEBUG_OBJECT (faac, "src pad caps: %" GST_PTR_FORMAT, srccaps); - ret = gst_pad_set_caps (faac->srcpad, srccaps); + ret = gst_pad_set_caps (GST_AUDIO_ENCODER_SRC_PAD (faac), srccaps); gst_caps_unref (srccaps); return ret; @@ -717,127 +642,33 @@ invalid_codec_data: } static GstFlowReturn -gst_faac_push_buffers (GstFaac * faac, gboolean force) +gst_faac_handle_frame (GstAudioEncoder * enc, GstBuffer * in_buf) { + GstFaac *faac = GST_FAAC (enc); GstFlowReturn ret = GST_FLOW_OK; - gint av, frame_size, size, ret_size; - GstBuffer *outbuf; - guint64 timestamp, distance; + GstBuffer *out_buf; + gint size, ret_size; const guint8 *data; - /* samples already considers channel count */ - frame_size = faac->samples * faac->bps; - - while (G_LIKELY (ret == GST_FLOW_OK)) { - - av = gst_adapter_available (faac->adapter); - - GST_LOG_OBJECT (faac, "pushing: force: %d, frame_size: %d, av: %d, " - "offset: %d", force, frame_size, av, faac->offset); - - /* idea: - * - start of adapter corresponds with what has already been encoded - * (i.e. really returned by faac) - * - start + offset is what needs to be fed to faac next - * That way we can timestamp the output based - * on adapter provided timestamp (and duration is a fixed frame duration) */ + out_buf = gst_buffer_new_and_alloc (faac->bytes); - /* not enough data for one frame and no flush forcing */ - if (!force && (av < frame_size + faac->offset)) - break; - - if (G_LIKELY (av - faac->offset >= frame_size)) { - GST_LOG_OBJECT (faac, "encoding a frame"); - data = gst_adapter_peek (faac->adapter, faac->offset + frame_size); - data += faac->offset; - size = frame_size; - } else if (av - faac->offset > 0) { - GST_LOG_OBJECT (faac, "encoding leftover"); - data = gst_adapter_peek (faac->adapter, av); - data += faac->offset; - size = av - faac->offset; - } else { - GST_LOG_OBJECT (faac, "emptying encoder"); - data = NULL; - size = 0; - } - - outbuf = gst_buffer_new_and_alloc (faac->bytes); - - if (G_UNLIKELY ((ret_size = faacEncEncode (faac->handle, (gint32 *) data, - size / faac->bps, GST_BUFFER_DATA (outbuf), - faac->bytes)) < 0)) { - gst_buffer_unref (outbuf); - goto encode_failed; - } - - GST_LOG_OBJECT (faac, "encoder return: %d", ret_size); - - /* consumed, advanced view */ - faac->offset += size; - g_assert (faac->offset <= av); - - if (G_UNLIKELY (!ret_size)) { - gst_buffer_unref (outbuf); - if (size) - continue; - else - break; - } - - /* deal with encoder lead-out */ - if (G_UNLIKELY (av == 0 && faac->offset == 0)) { - GST_DEBUG_OBJECT (faac, "encoder returned additional data"); - /* continuous with previous output, ok to have 0 duration */ - timestamp = faac->next_ts; - } else { - /* after some caching, finally some data */ - /* adapter gives time */ - timestamp = gst_adapter_prev_timestamp (faac->adapter, &distance); - } - - if (G_LIKELY ((av = gst_adapter_available (faac->adapter)) >= frame_size)) { - /* must have then come from a complete frame */ - gst_adapter_flush (faac->adapter, frame_size); - faac->offset -= frame_size; - size = frame_size; - } else { - /* otherwise leftover */ - gst_adapter_clear (faac->adapter); - faac->offset = 0; - size = av; - } - - GST_BUFFER_SIZE (outbuf) = ret_size; - if (G_LIKELY (GST_CLOCK_TIME_IS_VALID (timestamp))) - GST_BUFFER_TIMESTAMP (outbuf) = timestamp + - GST_FRAMES_TO_CLOCK_TIME (distance / faac->channels / faac->bps, - faac->samplerate); - GST_BUFFER_DURATION (outbuf) = - GST_FRAMES_TO_CLOCK_TIME (size / faac->channels / faac->bps, - faac->samplerate); - faac->next_ts = - GST_BUFFER_TIMESTAMP (outbuf) + GST_BUFFER_DURATION (outbuf); - - /* perhaps check/set DISCONT based on timestamps ? */ - - GST_LOG_OBJECT (faac, "Pushing out buffer time: %" GST_TIME_FORMAT - " duration: %" GST_TIME_FORMAT, - GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (outbuf)), - GST_TIME_ARGS (GST_BUFFER_DURATION (outbuf))); - - gst_buffer_set_caps (outbuf, GST_PAD_CAPS (faac->srcpad)); - ret = gst_pad_push (faac->srcpad, outbuf); + if (G_LIKELY (in_buf)) { + data = GST_BUFFER_DATA (in_buf); + size = GST_BUFFER_SIZE (in_buf); + } else { + data = NULL; + size = 0; } - /* in case encoder returns less than expected, clear our view as well */ - if (G_UNLIKELY (force)) { -#ifndef GST_DISABLE_GST_DEBUG - if ((av = gst_adapter_available (faac->adapter))) - GST_WARNING_OBJECT (faac, "encoder left %d bytes; discarding", av); -#endif - gst_adapter_clear (faac->adapter); - faac->offset = 0; + if (G_UNLIKELY ((ret_size = faacEncEncode (faac->handle, (gint32 *) data, + size / faac->bps, GST_BUFFER_DATA (out_buf), + GST_BUFFER_SIZE (out_buf))) < 0)) + goto encode_failed; + + GST_LOG_OBJECT (faac, "encoder return: %d", ret_size); + if (ret_size > 0) { + GST_BUFFER_SIZE (out_buf) = ret_size; + ret = gst_audio_encoder_finish_frame (enc, out_buf, faac->samples); } return ret; @@ -850,72 +681,6 @@ encode_failed: } } -static gboolean -gst_faac_sink_event (GstPad * pad, GstEvent * event) -{ - GstFaac *faac; - gboolean ret; - - faac = GST_FAAC (gst_pad_get_parent (pad)); - - GST_LOG_OBJECT (faac, "received %s", GST_EVENT_TYPE_NAME (event)); - - switch (GST_EVENT_TYPE (event)) { - case GST_EVENT_EOS: - { - if (faac->handle) { - /* flush first */ - GST_DEBUG_OBJECT (faac, "Pushing out remaining buffers because of EOS"); - gst_faac_push_buffers (faac, TRUE); - } - - ret = gst_pad_event_default (pad, event); - break; - } - default: - ret = gst_pad_event_default (pad, event); - break; - - } - gst_object_unref (faac); - return ret; -} - -static GstFlowReturn -gst_faac_chain (GstPad * pad, GstBuffer * inbuf) -{ - GstFlowReturn result = GST_FLOW_OK; - GstFaac *faac; - - faac = GST_FAAC (gst_pad_get_parent (pad)); - - if (!faac->handle) - goto no_handle; - - GST_LOG_OBJECT (faac, "Got buffer time: %" GST_TIME_FORMAT " duration: %" - GST_TIME_FORMAT, GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (inbuf)), - GST_TIME_ARGS (GST_BUFFER_DURATION (inbuf))); - - gst_adapter_push (faac->adapter, inbuf); - - result = gst_faac_push_buffers (faac, FALSE); - -done: - gst_object_unref (faac); - - return result; - - /* ERRORS */ -no_handle: - { - GST_ELEMENT_ERROR (faac, CORE, NEGOTIATION, (NULL), - ("format wasn't negotiated before chain function")); - gst_buffer_unref (inbuf); - result = GST_FLOW_ERROR; - goto done; - } -} - static void gst_faac_set_property (GObject * object, guint prop_id, const GValue * value, GParamSpec * pspec) @@ -986,35 +751,6 @@ gst_faac_get_property (GObject * object, GST_OBJECT_UNLOCK (faac); } -static GstStateChangeReturn -gst_faac_change_state (GstElement * element, GstStateChange transition) -{ - GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS; - GstFaac *faac = GST_FAAC (element); - - /* upwards state changes */ - switch (transition) { - default: - break; - } - - ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition); - - /* downwards state changes */ - switch (transition) { - case GST_STATE_CHANGE_PAUSED_TO_READY: - { - gst_faac_close_encoder (faac); - gst_faac_reset (faac); - break; - } - default: - break; - } - - return ret; -} - static gboolean plugin_init (GstPlugin * plugin) { diff --git a/ext/faac/gstfaac.h b/ext/faac/gstfaac.h index f5ab5ab4f..5bd057493 100644 --- a/ext/faac/gstfaac.h +++ b/ext/faac/gstfaac.h @@ -21,8 +21,8 @@ #define __GST_FAAC_H__ #include <gst/gst.h> -#include <gst/base/gstadapter.h> -#include <gst/audio/audio.h> +#include <gst/audio/gstaudioencoder.h> + #include <faac.h> G_BEGIN_DECLS @@ -42,41 +42,37 @@ typedef struct _GstFaac GstFaac; typedef struct _GstFaacClass GstFaacClass; struct _GstFaac { - GstElement element; - - /* pads */ - GstPad *srcpad, *sinkpad; + GstAudioEncoder element; /* stream properties */ gint samplerate, channels, format, - bps, + bps; + + /* input frame size */ + gulong samples; + /* required output buffer size */ + gulong bytes; + + /* negotiated */ + gint mpegversion, outputformat; + + /* properties */ + gint bitrate, + profile, quality, - bitrate, brtype, - profile, - mpegversion, - shortctl, - outputformat; + shortctl; gboolean tns, midside; - gulong bytes, - samples; /* FAAC object */ faacEncHandle handle; - - /* cache of the input */ - GstAdapter *adapter; - /* offset of data to be encoded next */ - guint offset; - /* ts for last buffer */ - GstClockTime next_ts; }; struct _GstFaacClass { - GstElementClass parent_class; + GstAudioEncoderClass parent_class; }; GType gst_faac_get_type (void); diff --git a/ext/faad/Makefile.am b/ext/faad/Makefile.am index 957ad7849..cc7636dca 100644 --- a/ext/faad/Makefile.am +++ b/ext/faad/Makefile.am @@ -1,7 +1,8 @@ plugin_LTLIBRARIES = libgstfaad.la libgstfaad_la_SOURCES = gstfaad.c -libgstfaad_la_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) \ +libgstfaad_la_CFLAGS = -DGST_USE_UNSTABLE_API \ + $(GST_PLUGINS_BASE_CFLAGS) \ $(GST_BASE_CFLAGS) $(GST_CFLAGS) $(FAAD_CFLAGS) libgstfaad_la_LIBADD = $(GST_PLUGINS_BASE_LIBS) -lgstaudio-@GST_MAJORMINOR@ \ $(GST_BASE_LIBS) $(GST_LIBS) $(FAAD_LIBS) diff --git a/ext/faad/gstfaad.c b/ext/faad/gstfaad.c index 1f9c3d228..252e9529d 100644 --- a/ext/faad/gstfaad.c +++ b/ext/faad/gstfaad.c @@ -140,55 +140,24 @@ static GstStaticPadTemplate src_template = GST_STATIC_PAD_TEMPLATE ("src", GST_STATIC_CAPS (STATIC_CAPS) ); -static void gst_faad_base_init (GstFaadClass * klass); -static void gst_faad_class_init (GstFaadClass * klass); -static void gst_faad_init (GstFaad * faad); static void gst_faad_reset (GstFaad * faad); -static void gst_faad_finalize (GObject * object); - -static void clear_queued (GstFaad * faad); - -static gboolean gst_faad_setcaps (GstPad * pad, GstCaps * caps); -static gboolean gst_faad_src_event (GstPad * pad, GstEvent * event); -static gboolean gst_faad_sink_event (GstPad * pad, GstEvent * event); -static gboolean gst_faad_src_query (GstPad * pad, GstQuery * query); -static GstFlowReturn gst_faad_chain (GstPad * pad, GstBuffer * buffer); -static GstStateChangeReturn gst_faad_change_state (GstElement * element, - GstStateChange transition); -static gboolean gst_faad_src_convert (GstFaad * faad, GstFormat src_format, - gint64 src_val, GstFormat dest_format, gint64 * dest_val); -static gboolean gst_faad_open_decoder (GstFaad * faad); -static void gst_faad_close_decoder (GstFaad * faad); -static GstElementClass *parent_class; /* NULL */ +static gboolean gst_faad_start (GstAudioDecoder * dec); +static gboolean gst_faad_stop (GstAudioDecoder * dec); +static gboolean gst_faad_set_format (GstAudioDecoder * dec, GstCaps * caps); +static gboolean gst_faad_parse (GstAudioDecoder * dec, GstAdapter * adapter, + gint * offset, gint * length); +static GstFlowReturn gst_faad_handle_frame (GstAudioDecoder * dec, + GstBuffer * buffer); +static void gst_faad_flush (GstAudioDecoder * dec, gboolean hard); -GType -gst_faad_get_type (void) -{ - static GType gst_faad_type = 0; - - if (!gst_faad_type) { - static const GTypeInfo gst_faad_info = { - sizeof (GstFaadClass), - (GBaseInitFunc) gst_faad_base_init, - NULL, - (GClassInitFunc) gst_faad_class_init, - NULL, - NULL, - sizeof (GstFaad), - 0, - (GInstanceInitFunc) gst_faad_init, - }; - - gst_faad_type = g_type_register_static (GST_TYPE_ELEMENT, - "GstFaad", &gst_faad_info, 0); - } +static gboolean gst_faad_open_decoder (GstFaad * faad); +static void gst_faad_close_decoder (GstFaad * faad); - return gst_faad_type; -} +GST_BOILERPLATE (GstFaad, gst_faad, GstAudioDecoder, GST_TYPE_AUDIO_DECODER); static void -gst_faad_base_init (GstFaadClass * klass) +gst_faad_base_init (gpointer klass) { GstElementClass *element_class = GST_ELEMENT_CLASS (klass); @@ -208,47 +177,27 @@ gst_faad_base_init (GstFaadClass * klass) static void gst_faad_class_init (GstFaadClass * klass) { - GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass); - GObjectClass *gobject_class = G_OBJECT_CLASS (klass); + GstAudioDecoderClass *base_class = GST_AUDIO_DECODER_CLASS (klass); parent_class = g_type_class_peek_parent (klass); - gobject_class->finalize = GST_DEBUG_FUNCPTR (gst_faad_finalize); - - gstelement_class->change_state = GST_DEBUG_FUNCPTR (gst_faad_change_state); + base_class->start = GST_DEBUG_FUNCPTR (gst_faad_start); + base_class->stop = GST_DEBUG_FUNCPTR (gst_faad_stop); + base_class->set_format = GST_DEBUG_FUNCPTR (gst_faad_set_format); + base_class->parse = GST_DEBUG_FUNCPTR (gst_faad_parse); + base_class->handle_frame = GST_DEBUG_FUNCPTR (gst_faad_handle_frame); + base_class->flush = GST_DEBUG_FUNCPTR (gst_faad_flush); } static void -gst_faad_init (GstFaad * faad) +gst_faad_init (GstFaad * faad, GstFaadClass * klass) { - faad->sinkpad = gst_pad_new_from_static_template (&sink_template, "sink"); - gst_element_add_pad (GST_ELEMENT (faad), faad->sinkpad); - gst_pad_set_event_function (faad->sinkpad, - GST_DEBUG_FUNCPTR (gst_faad_sink_event)); - gst_pad_set_setcaps_function (faad->sinkpad, - GST_DEBUG_FUNCPTR (gst_faad_setcaps)); - gst_pad_set_chain_function (faad->sinkpad, - GST_DEBUG_FUNCPTR (gst_faad_chain)); - - faad->srcpad = gst_pad_new_from_static_template (&src_template, "src"); - gst_pad_use_fixed_caps (faad->srcpad); - gst_pad_set_query_function (faad->srcpad, - GST_DEBUG_FUNCPTR (gst_faad_src_query)); - gst_pad_set_event_function (faad->srcpad, - GST_DEBUG_FUNCPTR (gst_faad_src_event)); - gst_element_add_pad (GST_ELEMENT (faad), faad->srcpad); - - faad->adapter = gst_adapter_new (); - gst_faad_reset (faad); } static void gst_faad_reset_stream_state (GstFaad * faad) { - faad->sync_flush = 0; - gst_adapter_clear (faad->adapter); - clear_queued (faad); if (faad->handle) faacDecPostSeekReset (faad->handle, 0); } @@ -256,45 +205,43 @@ gst_faad_reset_stream_state (GstFaad * faad) static void gst_faad_reset (GstFaad * faad) { - gst_segment_init (&faad->segment, GST_FORMAT_TIME); faad->samplerate = -1; faad->channels = -1; faad->init = FALSE; faad->packetised = FALSE; g_free (faad->channel_positions); faad->channel_positions = NULL; - faad->next_ts = GST_CLOCK_TIME_NONE; - faad->prev_ts = 0; - faad->bytes_in = 0; - faad->sum_dur_out = 0; - faad->error_count = 0; faad->last_header = 0; gst_faad_reset_stream_state (faad); } - -static void -gst_faad_finalize (GObject * object) +static gboolean +gst_faad_start (GstAudioDecoder * dec) { - GstFaad *faad = GST_FAAD (object); + GstFaad *faad = GST_FAAD (dec); - g_object_unref (faad->adapter); + GST_DEBUG_OBJECT (dec, "start"); + gst_faad_reset (faad); + + /* call upon legacy upstream byte support (e.g. seeking) */ + gst_audio_decoder_set_byte_time (dec, TRUE); + /* never mind a few errors */ + gst_audio_decoder_set_max_errors (dec, 10); - G_OBJECT_CLASS (parent_class)->finalize (object); + return TRUE; } -static void -gst_faad_send_tags (GstFaad * faad) +static gboolean +gst_faad_stop (GstAudioDecoder * dec) { - GstTagList *tags; + GstFaad *faad = GST_FAAD (dec); - tags = gst_tag_list_new (); - - gst_tag_list_add (tags, GST_TAG_MERGE_REPLACE, - GST_TAG_AUDIO_CODEC, "MPEG-4 AAC audio", NULL); + GST_DEBUG_OBJECT (dec, "stop"); + gst_faad_reset (faad); + gst_faad_close_decoder (faad); - gst_element_found_tags (GST_ELEMENT (faad), tags); + return TRUE; } static gint @@ -327,9 +274,9 @@ aac_rate_idx (gint rate) } static gboolean -gst_faad_setcaps (GstPad * pad, GstCaps * caps) +gst_faad_set_format (GstAudioDecoder * dec, GstCaps * caps) { - GstFaad *faad = GST_FAAD (gst_pad_get_parent (pad)); + GstFaad *faad = GST_FAAD (dec); GstStructure *str = gst_caps_get_structure (caps, 0); GstBuffer *buf; const GValue *value; @@ -352,8 +299,8 @@ gst_faad_setcaps (GstPad * pad, GstCaps * caps) /* We have codec data, means packetised stream */ faad->packetised = TRUE; - buf = gst_value_get_buffer (value); + buf = gst_value_get_buffer (value); g_return_val_if_fail (buf != NULL, FALSE); cdata = GST_BUFFER_DATA (buf); @@ -391,9 +338,6 @@ gst_faad_setcaps (GstPad * pad, GstCaps * caps) faad->channels = 0; faad->init = TRUE; - gst_faad_send_tags (faad); - - gst_adapter_clear (faad->adapter); } else if ((value = gst_structure_get_value (str, "framed")) && g_value_get_boolean (value) == TRUE) { faad->packetised = TRUE; @@ -424,7 +368,6 @@ gst_faad_setcaps (GstPad * pad, GstCaps * caps) } } - gst_object_unref (faad); return TRUE; /* ERRORS */ @@ -535,349 +478,6 @@ gst_faad_chanpos_to_gst (GstFaad * faad, guchar * fpos, guint num, return pos; } -static void -clear_queued (GstFaad * faad) -{ - g_list_foreach (faad->queued, (GFunc) gst_mini_object_unref, NULL); - g_list_free (faad->queued); - faad->queued = NULL; - g_list_foreach (faad->gather, (GFunc) gst_mini_object_unref, NULL); - g_list_free (faad->gather); - faad->gather = NULL; - g_list_foreach (faad->decode, (GFunc) gst_mini_object_unref, NULL); - g_list_free (faad->decode); - faad->decode = NULL; -} - -static GstFlowReturn -flush_queued (GstFaad * faad) -{ - GstFlowReturn ret = GST_FLOW_OK; - - while (faad->queued) { - GstBuffer *buf = GST_BUFFER_CAST (faad->queued->data); - - GST_LOG_OBJECT (faad, "pushing buffer %p, timestamp %" - GST_TIME_FORMAT ", duration %" GST_TIME_FORMAT, buf, - GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)), - GST_TIME_ARGS (GST_BUFFER_DURATION (buf))); - - /* iterate ouput queue an push downstream */ - ret = gst_pad_push (faad->srcpad, buf); - - faad->queued = g_list_delete_link (faad->queued, faad->queued); - } - return ret; -} - -static GstFlowReturn -gst_faad_drain (GstFaad * faad) -{ - GstFlowReturn ret = GST_FLOW_OK; - - GST_DEBUG_OBJECT (faad, "draining"); - - if (faad->segment.rate < 0.0) { - /* also decode tail = head of previous fragment to fill this one */ - while (faad->decode) { - GstBuffer *buf = GST_BUFFER_CAST (faad->decode->data); - - GST_DEBUG_OBJECT (faad, "processing delayed decode buffer"); - gst_faad_chain (faad->sinkpad, buf); - faad->decode = g_list_delete_link (faad->decode, faad->decode); - } - /* if we have some queued frames for reverse playback, flush - * them now */ - ret = flush_queued (faad); - /* move non-decoded leading buffers gathered in previous run - * to decode queue for this run */ - faad->decode = g_list_reverse (faad->gather); - faad->gather = NULL; - } else { - /* squeeze any possible remaining frames that are pending sync */ - gst_faad_chain (faad->sinkpad, NULL); - } - return ret; -} - -static gboolean -gst_faad_do_raw_seek (GstFaad * faad, GstEvent * event) -{ - GstSeekFlags flags; - GstSeekType start_type, end_type; - GstFormat format; - gdouble rate; - gint64 start, start_time; - - gst_event_parse_seek (event, &rate, &format, &flags, &start_type, - &start_time, &end_type, NULL); - - if (rate != 1.0 || - format != GST_FORMAT_TIME || - start_type != GST_SEEK_TYPE_SET || end_type != GST_SEEK_TYPE_NONE) { - return FALSE; - } - - if (!gst_faad_src_convert (faad, GST_FORMAT_TIME, start_time, - GST_FORMAT_BYTES, &start)) { - return FALSE; - } - - event = gst_event_new_seek (1.0, GST_FORMAT_BYTES, flags, - GST_SEEK_TYPE_SET, start, GST_SEEK_TYPE_NONE, -1); - - GST_DEBUG_OBJECT (faad, "seeking to %" GST_TIME_FORMAT " at byte offset %" - G_GINT64_FORMAT, GST_TIME_ARGS (start_time), start); - - return gst_pad_push_event (faad->sinkpad, event); -} - -static gboolean -gst_faad_src_event (GstPad * pad, GstEvent * event) -{ - GstFaad *faad; - gboolean res; - - faad = GST_FAAD (gst_pad_get_parent (pad)); - - GST_LOG_OBJECT (faad, "Handling %s event", GST_EVENT_TYPE_NAME (event)); - - switch (GST_EVENT_TYPE (event)) { - case GST_EVENT_SEEK:{ - /* try upstream first, there might be a demuxer */ - gst_event_ref (event); - if (!(res = gst_pad_push_event (faad->sinkpad, event))) { - res = gst_faad_do_raw_seek (faad, event); - } - gst_event_unref (event); - break; - } - default: - res = gst_pad_push_event (faad->sinkpad, event); - break; - } - - gst_object_unref (faad); - return res; -} - -static gboolean -gst_faad_sink_event (GstPad * pad, GstEvent * event) -{ - GstFaad *faad; - gboolean res = TRUE; - - faad = GST_FAAD (gst_pad_get_parent (pad)); - - GST_LOG_OBJECT (faad, "Handling %s event", GST_EVENT_TYPE_NAME (event)); - - switch (GST_EVENT_TYPE (event)) { - case GST_EVENT_FLUSH_STOP: - gst_faad_reset_stream_state (faad); - res = gst_pad_push_event (faad->srcpad, event); - break; - case GST_EVENT_EOS: - gst_faad_drain (faad); - gst_faad_reset_stream_state (faad); - res = gst_pad_push_event (faad->srcpad, event); - break; - case GST_EVENT_NEWSEGMENT: - { - GstFormat fmt; - gboolean is_update; - gint64 start, end, base; - gdouble rate; - - gst_event_parse_new_segment (event, &is_update, &rate, &fmt, &start, - &end, &base); - - /* drain queued buffers before we activate the new segment */ - gst_faad_drain (faad); - - if (fmt == GST_FORMAT_TIME) { - GST_DEBUG_OBJECT (faad, - "Got NEWSEGMENT event in GST_FORMAT_TIME, passing on (%" - GST_TIME_FORMAT " - %" GST_TIME_FORMAT ")", GST_TIME_ARGS (start), - GST_TIME_ARGS (end)); - gst_segment_set_newsegment (&faad->segment, is_update, rate, fmt, start, - end, base); - } else if (fmt == GST_FORMAT_BYTES) { - gint64 new_start = 0; - gint64 new_end = -1; - - GST_DEBUG_OBJECT (faad, "Got NEWSEGMENT event in GST_FORMAT_BYTES (%" - G_GUINT64_FORMAT " - %" G_GUINT64_FORMAT ")", start, end); - - if (gst_faad_src_convert (faad, GST_FORMAT_BYTES, start, - GST_FORMAT_TIME, &new_start)) { - if (end != -1) { - gst_faad_src_convert (faad, GST_FORMAT_BYTES, end, - GST_FORMAT_TIME, &new_end); - } - } else { - GST_DEBUG_OBJECT (faad, - "no average bitrate yet, sending newsegment with start at 0"); - } - gst_event_unref (event); - - event = gst_event_new_new_segment (is_update, rate, - GST_FORMAT_TIME, new_start, new_end, new_start); - - gst_segment_set_newsegment (&faad->segment, is_update, rate, - GST_FORMAT_TIME, new_start, new_end, new_start); - - GST_DEBUG_OBJECT (faad, - "Sending new NEWSEGMENT event, time %" GST_TIME_FORMAT - " - %" GST_TIME_FORMAT, GST_TIME_ARGS (new_start), - GST_TIME_ARGS (new_end)); - - faad->next_ts = GST_CLOCK_TIME_NONE; - faad->prev_ts = new_start; - } - - res = gst_pad_push_event (faad->srcpad, event); - break; - } - default: - res = gst_pad_event_default (pad, event); - break; - } - - gst_object_unref (faad); - return res; -} - -static gboolean -gst_faad_src_convert (GstFaad * faad, GstFormat src_format, gint64 src_val, - GstFormat dest_format, gint64 * dest_val) -{ - guint64 bytes_in, time_out, val; - - if (src_format == dest_format) { - if (dest_val) - *dest_val = src_val; - return TRUE; - } - - GST_OBJECT_LOCK (faad); - bytes_in = faad->bytes_in; - time_out = faad->sum_dur_out; - GST_OBJECT_UNLOCK (faad); - - if (bytes_in == 0 || time_out == 0) - return FALSE; - - /* convert based on the average bitrate so far */ - if (src_format == GST_FORMAT_BYTES && dest_format == GST_FORMAT_TIME) { - val = gst_util_uint64_scale (src_val, time_out, bytes_in); - } else if (src_format == GST_FORMAT_TIME && dest_format == GST_FORMAT_BYTES) { - val = gst_util_uint64_scale (src_val, bytes_in, time_out); - } else { - return FALSE; - } - - if (dest_val) - *dest_val = (gint64) val; - - return TRUE; -} - -static gboolean -gst_faad_src_query (GstPad * pad, GstQuery * query) -{ - gboolean res = FALSE; - GstFaad *faad; - GstPad *peer = NULL; - - faad = GST_FAAD (gst_pad_get_parent (pad)); - - GST_LOG_OBJECT (faad, "processing %s query", GST_QUERY_TYPE_NAME (query)); - - switch (GST_QUERY_TYPE (query)) { - case GST_QUERY_DURATION:{ - GstFormat format; - gint64 len_bytes, duration; - - /* try upstream first, in case there's a demuxer */ - if ((res = gst_pad_query_default (pad, query))) - break; - - gst_query_parse_duration (query, &format, NULL); - if (format != GST_FORMAT_TIME) { - GST_DEBUG_OBJECT (faad, "query failed: can't handle format %s", - gst_format_get_name (format)); - break; - } - - peer = gst_pad_get_peer (faad->sinkpad); - if (peer == NULL) - break; - - format = GST_FORMAT_BYTES; - if (!gst_pad_query_duration (peer, &format, &len_bytes)) { - GST_DEBUG_OBJECT (faad, "query failed: failed to get upstream length"); - break; - } - - res = gst_faad_src_convert (faad, GST_FORMAT_BYTES, len_bytes, - GST_FORMAT_TIME, &duration); - - if (res) { - gst_query_set_duration (query, GST_FORMAT_TIME, duration); - - GST_LOG_OBJECT (faad, "duration estimate: %" GST_TIME_FORMAT, - GST_TIME_ARGS (duration)); - } - break; - } - case GST_QUERY_POSITION:{ - GstFormat format; - gint64 pos_bytes, pos; - - /* try upstream first, in case there's a demuxer */ - if ((res = gst_pad_query_default (pad, query))) - break; - - gst_query_parse_position (query, &format, NULL); - if (format != GST_FORMAT_TIME) { - GST_DEBUG_OBJECT (faad, "query failed: can't handle format %s", - gst_format_get_name (format)); - break; - } - - peer = gst_pad_get_peer (faad->sinkpad); - if (peer == NULL) - break; - - format = GST_FORMAT_BYTES; - if (!gst_pad_query_position (peer, &format, &pos_bytes)) { - GST_OBJECT_LOCK (faad); - pos = faad->next_ts; - GST_OBJECT_UNLOCK (faad); - res = TRUE; - } else { - res = gst_faad_src_convert (faad, GST_FORMAT_BYTES, pos_bytes, - GST_FORMAT_TIME, &pos); - } - - if (res) { - gst_query_set_position (query, GST_FORMAT_TIME, pos); - } - break; - } - default: - res = gst_pad_query_default (pad, query); - break; - } - - if (peer) - gst_object_unref (peer); - - gst_object_unref (faad); - return res; -} - - static gboolean gst_faad_update_caps (GstFaad * faad, faacDecFrameInfo * info) { @@ -935,7 +535,7 @@ gst_faad_update_caps (GstFaad * faad, faacDecFrameInfo * info) GST_DEBUG_OBJECT (faad, "New output caps: %" GST_PTR_FORMAT, caps); - ret = gst_pad_set_caps (faad->srcpad, caps); + ret = gst_pad_set_caps (GST_AUDIO_DECODER_SRC_PAD (faad), caps); gst_caps_unref (caps); return ret; @@ -950,12 +550,13 @@ gst_faad_update_caps (GstFaad * faad, faacDecFrameInfo * info) * gst/typefind/) for ADTS because 12 bits isn't very reliable. */ static gboolean -gst_faad_sync (GstFaad * faad, guint8 * data, guint size, gboolean next, - guint * off) +gst_faad_sync (GstFaad * faad, const guint8 * data, guint size, gboolean next, + gint * off, gint * length) { guint n = 0; gint snc; gboolean ret = FALSE; + guint len = 0; GST_LOG_OBJECT (faad, "Finding syncpoint"); @@ -968,8 +569,6 @@ gst_faad_sync (GstFaad * faad, guint8 * data, guint size, gboolean next, if ((snc & 0xfff6) == 0xfff0) { /* we have an ADTS syncpoint. Parse length and find * next syncpoint. */ - guint len; - GST_LOG_OBJECT (faad, "Found one ADTS syncpoint at offset 0x%x, tracing next...", n); @@ -1012,10 +611,14 @@ gst_faad_sync (GstFaad * faad, guint8 * data, guint size, gboolean next, } exit: + *off = n; - if (!ret) + if (ret) { + *length = len; + } else { GST_LOG_OBJECT (faad, "Found no syncpoint"); + } return ret; } @@ -1038,78 +641,52 @@ looks_like_valid_header (guint8 * input_data, guint input_size) return FALSE; } -#define FAAD_MAX_ERROR 10 -#define FAAD_MAX_SYNC 10 * 8 * 1024 +static GstFlowReturn +gst_faad_parse (GstAudioDecoder * dec, GstAdapter * adapter, + gint * offset, gint * length) +{ + GstFaad *faad; + const guint8 *data; + guint size; + gboolean sync, eos; + + faad = GST_FAAD (dec); + + size = gst_adapter_available (adapter); + g_return_val_if_fail (size > 0, GST_FLOW_ERROR); + + gst_audio_decoder_get_parse_state (dec, &sync, &eos); + + if (faad->packetised) { + *offset = 0; + *length = size; + return GST_FLOW_OK; + } else { + data = gst_adapter_peek (adapter, size); + return gst_faad_sync (faad, data, size, !eos, offset, length) ? + GST_FLOW_OK : GST_FLOW_UNEXPECTED; + } +} static GstFlowReturn -gst_faad_chain (GstPad * pad, GstBuffer * buffer) +gst_faad_handle_frame (GstAudioDecoder * dec, GstBuffer * buffer) { + GstFaad *faad; GstFlowReturn ret = GST_FLOW_OK; guint input_size; - guint available; guchar *input_data; - GstFaad *faad; GstBuffer *outbuf; faacDecFrameInfo info; void *out; - gboolean run_loop = TRUE; - guint sync_off; - GstClockTime ts; - gboolean next; - - faad = GST_FAAD (gst_pad_get_parent (pad)); - - if (G_LIKELY (buffer)) { - GST_LOG_OBJECT (faad, "buffer of size %d with ts: %" GST_TIME_FORMAT - ", duration %" GST_TIME_FORMAT, GST_BUFFER_SIZE (buffer), - GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buffer)), - GST_TIME_ARGS (GST_BUFFER_DURATION (buffer))); - - if (GST_BUFFER_IS_DISCONT (buffer)) { - gst_faad_drain (faad); - gst_faad_reset_stream_state (faad); - faad->discont = TRUE; - } - - gst_adapter_push (faad->adapter, buffer); - buffer = NULL; - next = TRUE; - } else { - next = FALSE; - } - available = gst_adapter_available (faad->adapter); - input_size = available; - if (G_UNLIKELY (!available)) - goto out; + faad = GST_FAAD (dec); - ts = gst_adapter_prev_timestamp (faad->adapter, NULL); - if (GST_CLOCK_TIME_IS_VALID (ts) && (ts != faad->prev_ts)) { - faad->prev_ts = ts; - } else { - /* nothing new */ - ts = GST_CLOCK_TIME_NONE; - } + /* no fancy draining */ + if (G_UNLIKELY (!buffer)) + return GST_FLOW_OK; - if (!GST_CLOCK_TIME_IS_VALID (faad->next_ts)) - faad->next_ts = faad->prev_ts; - - input_data = (guchar *) gst_adapter_peek (faad->adapter, available); - - if (!faad->packetised) { - if (!gst_faad_sync (faad, input_data, input_size, next, &sync_off)) { - faad->sync_flush += sync_off; - input_size -= sync_off; - if (faad->sync_flush > FAAD_MAX_SYNC) - goto parse_failed; - else - goto out; - } else { - faad->sync_flush = 0; - input_data += sync_off; - input_size -= sync_off; - } - } + input_data = GST_BUFFER_DATA (buffer); + input_size = GST_BUFFER_SIZE (buffer); init: /* init if not already done during capsnego */ @@ -1143,7 +720,6 @@ init: } faad->init = TRUE; - gst_faad_send_tags (faad); /* make sure we create new caps below */ faad->samplerate = 0; @@ -1151,18 +727,11 @@ init: } /* decode cycle */ - info.bytesconsumed = input_size; info.error = 0; - while ((input_size > 0) && run_loop) { + do { - if (faad->packetised) { - /* Only one packet per buffer, no matter how much is really consumed */ - run_loop = FALSE; - } else { - if (input_size < FAAD_MIN_STREAMSIZE || info.bytesconsumed <= 0) { - break; - } + if (!faad->packetised) { /* faad only really parses ADTS header at Init time, not when decoding, * so monitor for changes and kick faad when needed */ if (GST_READ_UINT32_BE (input_data) >> 4 != faad->last_header >> 4) { @@ -1178,33 +747,14 @@ init: out = faacDecDecode (faad->handle, &info, input_data, input_size); if (info.error > 0) { - /* mark discont for the next buffer */ - faad->discont = TRUE; - /* flush a bit, arranges for resync next time */ - input_size--; - faad->error_count++; - /* do not bail out at once, but know when to stop */ - if (faad->error_count > FAAD_MAX_ERROR) - goto decode_failed; - else { - GST_WARNING_OBJECT (faad, "decoding error: %s", - faacDecGetErrorMessage (info.error)); - goto out; - } + /* give up on frame and bail out */ + gst_audio_decoder_finish_frame (dec, NULL, 1); + goto decode_failed; } - /* ok again */ - faad->error_count = 0; - GST_LOG_OBJECT (faad, "%d bytes consumed, %d samples decoded", (guint) info.bytesconsumed, (guint) info.samples); - if (info.bytesconsumed > input_size) - info.bytesconsumed = input_size; - - input_size -= info.bytesconsumed; - input_data += info.bytesconsumed; - if (out && info.samples > 0) { if (!gst_faad_update_caps (faad, &info)) goto negotiation_failed; @@ -1213,82 +763,21 @@ init: if (info.samples > G_MAXUINT / faad->bps) goto sample_overflow; - /* play decoded data */ - if (info.samples > 0) { - guint bufsize = info.samples * faad->bps; - guint num_samples = info.samples / faad->channels; - - /* note: info.samples is total samples, not per channel */ - ret = - gst_pad_alloc_buffer_and_set_caps (faad->srcpad, 0, bufsize, - GST_PAD_CAPS (faad->srcpad), &outbuf); - if (ret != GST_FLOW_OK) - goto out; - - memcpy (GST_BUFFER_DATA (outbuf), out, GST_BUFFER_SIZE (outbuf)); - GST_BUFFER_OFFSET (outbuf) = - GST_CLOCK_TIME_TO_FRAMES (faad->next_ts, faad->samplerate); - GST_BUFFER_TIMESTAMP (outbuf) = faad->next_ts; - GST_BUFFER_DURATION (outbuf) = - GST_FRAMES_TO_CLOCK_TIME (num_samples, faad->samplerate); - - GST_OBJECT_LOCK (faad); - faad->next_ts += GST_BUFFER_DURATION (outbuf); - faad->sum_dur_out += GST_BUFFER_DURATION (outbuf); - faad->bytes_in += info.bytesconsumed; - GST_OBJECT_UNLOCK (faad); - - if ((outbuf = gst_audio_buffer_clip (outbuf, &faad->segment, - faad->samplerate, faad->bps * faad->channels))) { - GST_LOG_OBJECT (faad, - "pushing buffer, off=%" G_GUINT64_FORMAT ", ts=%" GST_TIME_FORMAT, - GST_BUFFER_OFFSET (outbuf), - GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (outbuf))); - - if (faad->discont) { - GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DISCONT); - faad->discont = FALSE; - } - - if (faad->segment.rate > 0.0) { - ret = gst_pad_push (faad->srcpad, outbuf); - } else { - /* reverse playback, queue frame till later when we get a discont. */ - GST_LOG_OBJECT (faad, "queued frame"); - faad->queued = g_list_prepend (faad->queued, outbuf); - ret = GST_FLOW_OK; - } - if (ret != GST_FLOW_OK) - goto out; - } - } - } else { - if (faad->packetised && faad->segment.rate < 0.0) { - /* leading non-decoded frames used as tail - * for next preceding fragment */ - outbuf = gst_adapter_take_buffer (faad->adapter, available); - available = 0; - outbuf = gst_buffer_make_metadata_writable (outbuf); - GST_BUFFER_FLAG_UNSET (outbuf, GST_BUFFER_FLAG_DISCONT); - faad->gather = g_list_prepend (faad->gather, outbuf); - } - } + /* note: info.samples is total samples, not per channel */ + ret = + gst_pad_alloc_buffer_and_set_caps (GST_AUDIO_DECODER_SRC_PAD + (faad), 0, info.samples * faad->bps, + GST_PAD_CAPS (GST_AUDIO_DECODER_SRC_PAD (faad)), &outbuf); + if (ret != GST_FLOW_OK) + goto out; + + memcpy (GST_BUFFER_DATA (outbuf), out, GST_BUFFER_SIZE (outbuf)); - /* adjust to incoming new timestamp, if any, after decoder delay */ - if (GST_CLOCK_TIME_IS_VALID (ts)) { - faad->next_ts = ts; - ts = GST_CLOCK_TIME_NONE; + ret = gst_audio_decoder_finish_frame (dec, outbuf, 1); } - } + } while (FALSE); out: - /* in raw case: (pretend) all consumed */ - if (faad->packetised) - input_size = 0; - gst_adapter_flush (faad->adapter, available - input_size); - - gst_object_unref (faad); - return ret; /* ERRORS */ @@ -1315,9 +804,8 @@ init2_failed: } decode_failed: { - GST_ELEMENT_ERROR (faad, STREAM, DECODE, (NULL), - ("decoding error: %s", faacDecGetErrorMessage (info.error))); - ret = GST_FLOW_ERROR; + GST_AUDIO_DECODER_ERROR (faad, 1, STREAM, DECODE, (NULL), + ("decoding error: %s", faacDecGetErrorMessage (info.error)), ret); goto out; } negotiation_failed: @@ -1334,13 +822,12 @@ sample_overflow: ret = GST_FLOW_ERROR; goto out; } -parse_failed: - { - GST_ELEMENT_ERROR (faad, STREAM, DECODE, (NULL), - ("failed to parse non-packetized stream")); - ret = GST_FLOW_ERROR; - goto out; - } +} + +static void +gst_faad_flush (GstAudioDecoder * dec, gboolean hard) +{ + gst_faad_reset_stream_state (GST_FAAD (dec)); } static gboolean @@ -1377,38 +864,6 @@ gst_faad_close_decoder (GstFaad * faad) } } -static GstStateChangeReturn -gst_faad_change_state (GstElement * element, GstStateChange transition) -{ - GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS; - GstFaad *faad = GST_FAAD (element); - - switch (transition) { - case GST_STATE_CHANGE_NULL_TO_READY: - break; - case GST_STATE_CHANGE_READY_TO_PAUSED: - break; - default: - break; - } - - if (GST_ELEMENT_CLASS (parent_class)->change_state) - ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition); - - switch (transition) { - case GST_STATE_CHANGE_PAUSED_TO_READY: - gst_faad_reset (faad); - gst_faad_close_decoder (faad); - break; - case GST_STATE_CHANGE_READY_TO_NULL: - break; - default: - break; - } - - return ret; -} - static gboolean plugin_init (GstPlugin * plugin) { diff --git a/ext/faad/gstfaad.h b/ext/faad/gstfaad.h index 455225047..deb98b831 100644 --- a/ext/faad/gstfaad.h +++ b/ext/faad/gstfaad.h @@ -21,7 +21,8 @@ #define __GST_FAAD_H__ #include <gst/gst.h> -#include <gst/base/gstadapter.h> +#include <gst/audio/gstaudiodecoder.h> + #ifdef FAAD_IS_NEAAC #include <neaacdec.h> #else @@ -42,10 +43,7 @@ G_BEGIN_DECLS (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_FAAD)) typedef struct _GstFaad { - GstElement element; - - GstPad *srcpad; - GstPad *sinkpad; + GstAudioDecoder element; guint samplerate; /* sample rate of the last MPEG frame */ guint channels; /* number of channels of the last frame */ @@ -55,34 +53,16 @@ typedef struct _GstFaad { guint8 fake_codec_data[2]; guint32 last_header; - GstAdapter *adapter; - /* FAAD object */ faacDecHandle handle; gboolean init; gboolean packetised; /* We must differentiate between raw and packetised streams */ - gint64 prev_ts; /* timestamp of previous buffer */ - gint64 next_ts; /* timestamp of next buffer */ - guint64 bytes_in; /* bytes received */ - guint64 sum_dur_out; /* sum of durations of decoded buffers we sent out */ - gint error_count; - gboolean discont; - gint sync_flush; - - /* segment handling */ - GstSegment segment; - - /* list of raw output buffers for reverse playback */ - GList *queued; - /* gather/decode queues for reverse playback */ - GList *gather; - GList *decode; } GstFaad; typedef struct _GstFaadClass { - GstElementClass parent_class; + GstAudioDecoderClass parent_class; } GstFaadClass; GType gst_faad_get_type (void); diff --git a/ext/kate/gstkateparse.h b/ext/kate/gstkateparse.h index 509f6c498..f9dd041cd 100644 --- a/ext/kate/gstkateparse.h +++ b/ext/kate/gstkateparse.h @@ -36,7 +36,7 @@ G_BEGIN_DECLS (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_KATE_PARSE,GstKateParseClass)) #define GST_IS_KATE_PARSE(obj) \ (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_KATE_PARSE)) -#define GST_IS_KATKATEE_CLASS(klass) \ +#define GST_IS_KATE_PARSE_CLASS(klass) \ (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_KATE_PARSE)) typedef struct _GstKateParse GstKateParse; typedef struct _GstKateParseClass GstKateParseClass; diff --git a/ext/kate/gstkatetiger.c b/ext/kate/gstkatetiger.c index 81ac6f755..41da4db15 100644 --- a/ext/kate/gstkatetiger.c +++ b/ext/kate/gstkatetiger.c @@ -677,6 +677,7 @@ gst_kate_tiger_video_set_caps (GstPad * pad, GstCaps * caps) GstKateTiger *tiger = GST_KATE_TIGER (gst_pad_get_parent (pad)); GstVideoFormat format; gint w, h; + gboolean ret; GST_KATE_TIGER_MUTEX_LOCK (tiger); @@ -692,10 +693,10 @@ gst_kate_tiger_video_set_caps (GstPad * pad, GstCaps * caps) GST_KATE_TIGER_MUTEX_UNLOCK (tiger); - gst_pad_set_caps (tiger->srcpad, caps); + ret = gst_pad_set_caps (tiger->srcpad, caps); gst_object_unref (tiger); - return TRUE; + return ret; } static gdouble @@ -858,9 +859,13 @@ gst_kate_tiger_seek (GstKateTiger * tiger, GstPad * pad, GstEvent * event) gst_event_parse_seek (event, &rate, &format, &flags, &cur_type, &cur, &stop_type, &stop); + if (flags & GST_SEEK_FLAG_FLUSH) + gst_pad_push_event (tiger->srcpad, gst_event_new_flush_start ()); + GST_KATE_TIGER_MUTEX_LOCK (tiger); tiger->video_flushing = TRUE; gst_kate_util_decoder_base_set_flushing (&tiger->decoder, TRUE); + g_cond_broadcast (tiger->cond); GST_KATE_TIGER_MUTEX_UNLOCK (tiger); if (format == GST_FORMAT_TIME) { diff --git a/ext/rtmp/gstrtmpsink.c b/ext/rtmp/gstrtmpsink.c index e3933b150..90a1a79ec 100644 --- a/ext/rtmp/gstrtmpsink.c +++ b/ext/rtmp/gstrtmpsink.c @@ -164,20 +164,6 @@ gst_rtmp_sink_start (GstBaseSink * basesink) /* Mark this as an output connection */ RTMP_EnableWrite (sink->rtmp); - /* open the connection */ - if (!RTMP_IsConnected (sink->rtmp)) { - if (!RTMP_Connect (sink->rtmp, NULL) || !RTMP_ConnectStream (sink->rtmp, 0)) { - GST_ELEMENT_ERROR (sink, RESOURCE, OPEN_WRITE, (NULL), - ("Could not connect to RTMP stream \"%s\" for writing", sink->uri)); - RTMP_Free (sink->rtmp); - sink->rtmp = NULL; - g_free (sink->rtmp_uri); - sink->rtmp_uri = NULL; - return FALSE; - } - GST_DEBUG_OBJECT (sink, "Opened connection to %s", sink->rtmp_uri); - } - sink->first = TRUE; return TRUE; @@ -210,6 +196,21 @@ gst_rtmp_sink_render (GstBaseSink * bsink, GstBuffer * buf) GstBuffer *reffed_buf = NULL; if (sink->first) { + /* open the connection */ + if (!RTMP_IsConnected (sink->rtmp)) { + if (!RTMP_Connect (sink->rtmp, NULL) + || !RTMP_ConnectStream (sink->rtmp, 0)) { + GST_ELEMENT_ERROR (sink, RESOURCE, OPEN_WRITE, (NULL), + ("Could not connect to RTMP stream \"%s\" for writing", sink->uri)); + RTMP_Free (sink->rtmp); + sink->rtmp = NULL; + g_free (sink->rtmp_uri); + sink->rtmp_uri = NULL; + return GST_FLOW_ERROR; + } + GST_DEBUG_OBJECT (sink, "Opened connection to %s", sink->rtmp_uri); + } + /* FIXME: Parse the first buffer and see if it contains a header plus a packet instead * of just assuming it's only the header */ GST_LOG_OBJECT (sink, "Caching first buffer of size %d for concatenation", diff --git a/ext/spandsp/Makefile.am b/ext/spandsp/Makefile.am new file mode 100644 index 000000000..46585958a --- /dev/null +++ b/ext/spandsp/Makefile.am @@ -0,0 +1,9 @@ +plugin_LTLIBRARIES = libgstspandsp.la + +libgstspandsp_la_SOURCES = gstspandsp.c gstspanplc.c +libgstspandsp_la_CFLAGS = $(GST_CFLAGS) $(GST_PLUGINS_BASE_CFLAGS) $(SPANDSP_CFLAGS) +libgstspandsp_la_LIBADD = $(SPANDSP_LIBS) $(GST_PLUGINS_BASE_LIBS) $(GST_LIBS) +libgstspandsp_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS) +libgstspandsp_la_LIBTOOLFLAGS = --tag=disable-static + +noinst_HEADERS = gstspanplc.h diff --git a/ext/spandsp/gstspandsp.c b/ext/spandsp/gstspandsp.c new file mode 100644 index 000000000..ad1c3a817 --- /dev/null +++ b/ext/spandsp/gstspandsp.c @@ -0,0 +1,40 @@ +/* + * (C) 2011 Collabora Ltd. + * Contact: Youness Alaoui <youness.alaoui@collabora.co.uk> + * + * 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 "gstspanplc.h" + +static gboolean +plugin_init (GstPlugin * plugin) +{ + return gst_element_register (plugin, "spanplc", + GST_RANK_PRIMARY, GST_TYPE_SPAN_PLC); +} + +GST_PLUGIN_DEFINE (GST_VERSION_MAJOR, + GST_VERSION_MINOR, + "spandsp", + "libspandsp plugin", + plugin_init, VERSION, "LGPL", GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN) diff --git a/ext/spandsp/gstspanplc.c b/ext/spandsp/gstspanplc.c new file mode 100644 index 000000000..58edce9f4 --- /dev/null +++ b/ext/spandsp/gstspanplc.c @@ -0,0 +1,300 @@ +/* + * (C) 2011 Collabora Ltd. + * Contact: Youness Alaoui <youness.alaoui@collabora.co.uk> + * + * 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:element-spanplc + * + * The spanplc (Packet Loss Concealment) element provides a synthetic + * fill-in signal, to minimise the audible effect of lost packets in + * VoIP applications + * + */ + + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include "gstspanplc.h" + +GST_BOILERPLATE (GstSpanPlc, gst_span_plc, GstElement, GST_TYPE_ELEMENT); + +GST_DEBUG_CATEGORY_STATIC (gst_span_plc_debug); +#define GST_CAT_DEFAULT gst_span_plc_debug + + +static GstStaticPadTemplate src_factory = GST_STATIC_PAD_TEMPLATE ("src", + GST_PAD_SRC, + GST_PAD_ALWAYS, + GST_STATIC_CAPS ("audio/x-raw-int, " + "endianness = (int) BYTE_ORDER, signed = (bool) TRUE, " + "width = (int) 16, depth = (int) 16, " + "rate = (int) [ 1, MAX ], channels = (int) 1") + ); + +static GstStaticPadTemplate sink_factory = GST_STATIC_PAD_TEMPLATE ("sink", + GST_PAD_SINK, + GST_PAD_ALWAYS, + GST_STATIC_CAPS ("audio/x-raw-int, " + "endianness = (int) BYTE_ORDER, signed = (bool) TRUE, " + "width = (int) 16, depth = (int) 16, " + "rate = (int) [ 1, MAX ], channels = (int) 1") + ); + +static void gst_span_plc_dispose (GObject * object); + +static GstStateChangeReturn gst_span_plc_change_state (GstElement * element, + GstStateChange transition); +static gboolean gst_span_plc_setcaps_sink (GstPad * pad, GstCaps * caps); +static GstFlowReturn gst_span_plc_chain (GstPad * pad, GstBuffer * buf); +static gboolean gst_span_plc_event_sink (GstPad * pad, GstEvent * event); + +static void +gst_span_plc_base_init (gpointer gclass) +{ + GstElementClass *element_class = (GstElementClass *) gclass; + + gst_element_class_add_pad_template (element_class, + gst_static_pad_template_get (&src_factory)); + gst_element_class_add_pad_template (element_class, + gst_static_pad_template_get (&sink_factory)); + + gst_element_class_set_details_simple (element_class, "SpanDSP PLC", + "Filter/Effect/Audio", + "Adds packet loss concealment to audio", + "Youness Alaoui <youness.alaoui@collabora.co.uk>"); +} + +/* initialize the plugin's class */ +static void +gst_span_plc_class_init (GstSpanPlcClass * klass) +{ + GObjectClass *gobject_class = (GObjectClass *) klass; + GstElementClass *gstelement_class = (GstElementClass *) klass; + + gobject_class->dispose = gst_span_plc_dispose; + + gstelement_class->change_state = + GST_DEBUG_FUNCPTR (gst_span_plc_change_state); + + GST_DEBUG_CATEGORY_INIT (gst_span_plc_debug, "spanplc", + 0, "spanDSP's packet loss concealment"); +} + +static void +gst_span_plc_init (GstSpanPlc * plc, GstSpanPlcClass * gclass) +{ + GST_DEBUG_OBJECT (plc, "init"); + + plc->srcpad = gst_pad_new_from_static_template (&src_factory, "src"); + plc->sinkpad = gst_pad_new_from_static_template (&sink_factory, "sink"); + + gst_pad_set_setcaps_function (plc->sinkpad, + GST_DEBUG_FUNCPTR (gst_span_plc_setcaps_sink)); + + gst_pad_set_getcaps_function (plc->srcpad, + GST_DEBUG_FUNCPTR (gst_pad_proxy_getcaps)); + gst_pad_set_getcaps_function (plc->sinkpad, + GST_DEBUG_FUNCPTR (gst_pad_proxy_getcaps)); + + gst_pad_set_chain_function (plc->sinkpad, + GST_DEBUG_FUNCPTR (gst_span_plc_chain)); + + gst_pad_set_event_function (plc->sinkpad, + GST_DEBUG_FUNCPTR (gst_span_plc_event_sink)); + + gst_element_add_pad (GST_ELEMENT (plc), plc->srcpad); + gst_element_add_pad (GST_ELEMENT (plc), plc->sinkpad); + + plc->plc_state = NULL; + plc->last_stop = GST_CLOCK_TIME_NONE; + + GST_DEBUG_OBJECT (plc, "init complete"); +} + +static void +gst_span_plc_dispose (GObject * object) +{ + GstSpanPlc *plc = GST_SPAN_PLC (object); + + if (plc->plc_state) + plc_free (plc->plc_state); + plc->plc_state = NULL; + + G_OBJECT_CLASS (parent_class)->dispose (object); +} + +static void +gst_span_plc_flush (GstSpanPlc * plc, gboolean renew) +{ + if (plc->plc_state) + plc_free (plc->plc_state); + if (renew) + plc->plc_state = plc_init (NULL); + else + plc->plc_state = NULL; + plc->last_stop = GST_CLOCK_TIME_NONE; +} + +static GstStateChangeReturn +gst_span_plc_change_state (GstElement * element, GstStateChange transition) +{ + GstSpanPlc *plc = GST_SPAN_PLC (element); + GstStateChangeReturn ret; + + switch (transition) { + case GST_STATE_CHANGE_NULL_TO_READY: + gst_span_plc_flush (plc, TRUE); + break; + default: + break; + } + + ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition); + + switch (transition) { + case GST_STATE_CHANGE_READY_TO_NULL: + gst_span_plc_flush (plc, FALSE); + default: + break; + } + + return ret; +} + +static gboolean +gst_span_plc_setcaps_sink (GstPad * pad, GstCaps * caps) +{ + GstSpanPlc *plc = GST_SPAN_PLC (gst_pad_get_parent (pad)); + GstStructure *s = NULL; + gboolean ret = FALSE; + + ret = gst_pad_set_caps (plc->srcpad, caps); + s = gst_caps_get_structure (caps, 0); + if (s) { + gst_structure_get_int (s, "rate", &plc->sample_rate); + GST_DEBUG_OBJECT (plc, "setcaps: got sample rate : %d", plc->sample_rate); + } + + gst_span_plc_flush (plc, TRUE); + gst_object_unref (plc); + + return ret; +} + +static GstFlowReturn +gst_span_plc_chain (GstPad * pad, GstBuffer * buffer) +{ + GstSpanPlc *plc = GST_SPAN_PLC (GST_PAD_PARENT (pad)); + GstClockTime buffer_duration; + + if (GST_BUFFER_TIMESTAMP_IS_VALID (buffer)) + plc->last_stop = GST_BUFFER_TIMESTAMP (buffer); + else + GST_WARNING_OBJECT (plc, "Buffer has no timestamp!"); + + if (GST_BUFFER_DURATION_IS_VALID (buffer)) { + buffer_duration = GST_BUFFER_DURATION (buffer); + } else { + GST_WARNING_OBJECT (plc, "Buffer has no duration!"); + buffer_duration = (GST_BUFFER_SIZE (buffer) / + (plc->sample_rate * sizeof (guint16))) * GST_SECOND; + GST_DEBUG_OBJECT (plc, "Buffer duration : %" GST_TIME_FORMAT, + GST_TIME_ARGS (buffer_duration)); + } + + plc->last_stop += buffer_duration; + + if (plc->plc_state->missing_samples != 0) + buffer = gst_buffer_make_writable (buffer); + plc_rx (plc->plc_state, (int16_t *) GST_BUFFER_DATA (buffer), + GST_BUFFER_SIZE (buffer) / 2); + + return gst_pad_push (plc->srcpad, buffer); +} + +static void +gst_span_plc_send_fillin (GstSpanPlc * plc, GstClockTime duration) +{ + guint buf_size; + GstBuffer *buffer = NULL; + + buf_size = ((float) duration / GST_SECOND) * plc->sample_rate; + buf_size *= sizeof (guint16); + buffer = gst_buffer_new_and_alloc (buf_size); + GST_DEBUG_OBJECT (plc, "Missing packet of %" GST_TIME_FORMAT + " == %d bytes", GST_TIME_ARGS (duration), buf_size); + plc_fillin (plc->plc_state, (int16_t *) GST_BUFFER_DATA (buffer), + GST_BUFFER_SIZE (buffer) / 2); + GST_BUFFER_TIMESTAMP (buffer) = plc->last_stop; + GST_BUFFER_DURATION (buffer) = duration; + gst_buffer_set_caps (buffer, GST_PAD_CAPS (plc->srcpad)); + gst_pad_push (plc->srcpad, buffer); +} + +static gboolean +gst_span_plc_event_sink (GstPad * pad, GstEvent * event) +{ + gboolean ret = FALSE; + GstSpanPlc *plc = GST_SPAN_PLC (gst_pad_get_parent (pad)); + + GST_DEBUG_OBJECT (plc, "received event %s", GST_EVENT_TYPE_NAME (event)); + + switch (GST_EVENT_TYPE (event)) { + case GST_EVENT_NEWSEGMENT: + { + GstFormat format; + gdouble rate; + gint64 start, stop, time; + gboolean update; + + gst_event_parse_new_segment (event, &update, &rate, &format, &start, + &stop, &time); + + if (format != GST_FORMAT_TIME) + goto newseg_wrong_format; + + if (update) { + /* time progressed without data, see if we can fill the gap with + * some concealment data */ + if (plc->last_stop < start) + gst_span_plc_send_fillin (plc, start - plc->last_stop); + } + plc->last_stop = start; + break; + } + case GST_EVENT_FLUSH_START: + gst_span_plc_flush (plc, TRUE); + break; + default: + break; + } + ret = gst_pad_push_event (plc->srcpad, event); + + gst_object_unref (plc); + + return ret; +newseg_wrong_format: + { + GST_DEBUG_OBJECT (plc, "received non TIME newsegment"); + gst_object_unref (plc); + return FALSE; + } +} diff --git a/ext/spandsp/gstspanplc.h b/ext/spandsp/gstspanplc.h new file mode 100644 index 000000000..86c10ac23 --- /dev/null +++ b/ext/spandsp/gstspanplc.h @@ -0,0 +1,60 @@ +/* + * (C) 2011 Collabora Ltd. + * Contact: Youness Alaoui <youness.alaoui@collabora.co.uk> + * + * 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_SPANDSP_H__ +#define __GST_SPANDSP_H__ + +#include <gst/gst.h> + +#include <spandsp.h> + +G_BEGIN_DECLS + +#define GST_TYPE_SPAN_PLC (gst_span_plc_get_type()) +#define GST_SPAN_PLC(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_SPAN_PLC,GstSpanPlc)) +#define GST_SPAN_PLC_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_SPAN_PLC,GstSpanPlcClass)) +#define GST_IS_SPAN_PLC(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_SPAN_PLC)) +#define GST_IS_SPAN_PLC_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_SPAN_PLC)) + +typedef struct _GstSpanPlc GstSpanPlc; +typedef struct _GstSpanPlcClass GstSpanPlcClass; + +struct _GstSpanPlc +{ + GstElement element; + + GstPad *sinkpad; + GstPad *srcpad; + + /* <private> */ + plc_state_t *plc_state; + GstClockTime last_stop; + gint sample_rate; +}; + +struct _GstSpanPlcClass +{ + GstElementClass parent_class; +}; + +GType gst_span_plc_get_type (void); + +G_END_DECLS + +#endif diff --git a/gst-libs/gst/basecamerabinsrc/gstbasecamerasrc.c b/gst-libs/gst/basecamerabinsrc/gstbasecamerasrc.c index 56bdc6cf6..d5b8ed772 100644 --- a/gst-libs/gst/basecamerabinsrc/gstbasecamerasrc.c +++ b/gst-libs/gst/basecamerabinsrc/gstbasecamerasrc.c @@ -445,7 +445,11 @@ gst_base_camera_src_change_state (GstElement * element, gst_camerabin_create_preview_pipeline (GST_ELEMENT_CAST (self), self->preview_filter); - g_assert (self->preview_pipeline != NULL); + if (self->preview_pipeline == NULL) { + /* failed to create preview pipeline, fail state change */ + return GST_STATE_CHANGE_FAILURE; + } + self->preview_filter_changed = FALSE; if (self->preview_caps) { GST_DEBUG_OBJECT (self, diff --git a/gst-libs/gst/basecamerabinsrc/gstcamerabinpreview.c b/gst-libs/gst/basecamerabinsrc/gstcamerabinpreview.c index b916d7f6b..be42c98dc 100644 --- a/gst-libs/gst/basecamerabinsrc/gstcamerabinpreview.c +++ b/gst-libs/gst/basecamerabinsrc/gstcamerabinpreview.c @@ -146,7 +146,8 @@ gst_camerabin_create_preview_pipeline (GstElement * element, } g_object_set (data->appsrc, "emit-signals", FALSE, NULL); - g_object_set (data->appsink, "sync", FALSE, NULL); + g_object_set (data->appsink, "sync", FALSE, "enable-last-buffer", + FALSE, NULL); gst_bin_add_many (GST_BIN (data->pipeline), data->appsrc, data->capsfilter, data->appsink, csp, vscale, NULL); @@ -230,6 +231,8 @@ void gst_camerabin_destroy_preview_pipeline (GstCameraBinPreviewPipelineData * preview) { + g_return_if_fail (preview != NULL); + if (preview->processing_lock) { g_mutex_free (preview->processing_lock); preview->processing_lock = NULL; diff --git a/gst-libs/gst/codecparsers/Makefile.am b/gst-libs/gst/codecparsers/Makefile.am index 7fa44f158..c3dfe9307 100644 --- a/gst-libs/gst/codecparsers/Makefile.am +++ b/gst-libs/gst/codecparsers/Makefile.am @@ -1,17 +1,27 @@ lib_LTLIBRARIES = libgstcodecparsers-@GST_MAJORMINOR@.la libgstcodecparsers_@GST_MAJORMINOR@_la_SOURCES = \ - gstmpegvideoparser.c gsth264parser.c + gstmpegvideoparser.c gsth264parser.c gstvc1parser.c libgstcodecparsers_@GST_MAJORMINOR@includedir = \ $(includedir)/gstreamer-@GST_MAJORMINOR@/gst/codecparsers libgstcodecparsers_@GST_MAJORMINOR@include_HEADERS = \ - gstmpegvideoparser.h gsth264parser.h + gstmpegvideoparser.h gsth264parser.h gstvc1parser.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) +libgstcodecparsers_@GST_MAJORMINOR@_la_CFLAGS = \ + $(GST_PLUGINS_BAD_CFLAGS) \ + -DGST_USE_UNSTABLE_API \ + $(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@ \ diff --git a/gst-libs/gst/codecparsers/gsth264parser.c b/gst-libs/gst/codecparsers/gsth264parser.c index 869aa6122..b496c0fef 100644 --- a/gst-libs/gst/codecparsers/gsth264parser.c +++ b/gst-libs/gst/codecparsers/gsth264parser.c @@ -32,25 +32,52 @@ * @short_description: Convenience library for h264 video * bitstream parsing. * - * It offers you basic parsing in AVC mode or not. Tp identify Nals in a bitstream and - * parse its basic headers, you should call: + * It offers you bitstream parsing in AVC mode or not. To identify Nals in a bitstream and + * parse its headers, you should call: * <itemizedlist> * <listitem> - * gst_h264_parser_identify_nalu to identify the following nalu in not AVC bitstreams + * #gst_h264_parser_identify_nalu to identify the following nalu in not AVC bitstreams * </listitem> * <listitem> - * gst_h264_parser_identify_nalu_avc to identify the following nalu in AVC bitstreams + * #gst_h264_parser_identify_nalu_avc to identify the nalu in AVC bitstreams * </listitem> * </itemizedlist> * * Then, depending on the #GstH264NalUnitType of the newly parsed #GstH264NalUnit, you should - * call the differents functions to parse the struct. + * call the differents functions to parse the structure: + * <itemizedlist> + * <listitem> + * From #GST_H264_NAL_SLICE to #GST_H264_NAL_SLICE_IDR: #gst_h264_parser_parse_slice_hdr + * </listitem> + * <listitem> + * #GST_H264_NAL_SEI: #gst_h264_parser_parse_sei + * </listitem> + * <listitem> + * #GST_H264_NAL_SPS: #gst_h264_parser_parse_sps + * </listitem> + * <listitem> + * #GST_H264_NAL_PPS: #gst_h264_parser_parse_pps + * </listitem> + * <listitem> + * Any other: #gst_h264_parser_parse_nal + * </listitem> + * </itemizedlist> * * Note: You should always call gst_h264_parser_parse_nal if you don't actually need - * #GstH264NalUnitType to be parsed for your personnal use. This, to guarantee that the + * #GstH264NalUnitType to be parsed for your personnal use, in order to guarantee that the * #GstH264NalParser is always up to date. * - * For more details about the structures, look at the ISO specifications. + * For more details about the structures, look at the ITU-T H.264 and ISO/IEC 14496-10 – MPEG-4 + * Part 10 specifications, you can download them from: + * + * <itemizedlist> + * <listitem> + * ITU-T H.264: http://www.itu.int/rec/T-REC-H.264 + * </listitem> + * <listitem> + * ISO/IEC 14496-10: http://www.iso.org/iso/iso_catalogue/catalogue_tc/catalogue_detail.htm?csnumber=56538 + * </listitem> + * </itemizedlist> */ #ifdef HAVE_CONFIG_H @@ -1064,7 +1091,7 @@ gst_h264_parser_parse_pic_timing (GstH264NalParser * nalparser, guint i; READ_UINT8 (nr, tim->pic_struct, 4); - CHECK_ALLOWED (tim->pic_struct, 0, 8); + CHECK_ALLOWED ((gint8) tim->pic_struct, 0, 8); num_clock_num_ts = num_clock_ts_table[tim->pic_struct]; for (i = 0; i < num_clock_num_ts; i++) { @@ -1090,7 +1117,8 @@ error: /** * gst_h264_nal_parser_new: * - * Creates a nez #GstH264NalParser + * Creates a new #GstH264NalParser. It should be freed with + * gst_h264_nal_parser_free after use. * * Returns: a new #GstH264NalParser */ @@ -1099,7 +1127,7 @@ gst_h264_nal_parser_new (void) { GstH264NalParser *nalparser; - nalparser = g_malloc0 (sizeof (GstH264NalParser)); + nalparser = g_slice_new0 (GstH264NalParser); GST_DEBUG_CATEGORY_INIT (h264_parser_debug, "codecparsers_h264", 0, "h264 parser library"); @@ -1107,14 +1135,28 @@ gst_h264_nal_parser_new (void) } /** + * gst_h264_nal_parser_free: + * @nalparser: the #GstH264NalParser to free + * + * Frees @nalparser and sets it to %NULL + */ +void +gst_h264_nal_parser_free (GstH264NalParser * nalparser) +{ + g_slice_free (GstH264NalParser, nalparser); + + nalparser = NULL; +} + +/** * gst_h264_parser_identify_nalu: * @nalparser: a #GstH264NalParser * @data: The data to parse - * @offset: the offset from which to parse @data + * @offset: the offset from which to parse @data * @size: the size of @data * @nalu: The #GstH264NalUnit where to store parsed nal headers * - * Parses the buffer and set @nalu from the next nalu data from @data + * Parses @data and fills @nalu from the next nalu data from @data * * Returns: a #GstH264ParserResult */ @@ -1125,8 +1167,8 @@ gst_h264_parser_identify_nalu (GstH264NalParser * nalparser, gint off1, off2; if (size - offset < 4) { - GST_DEBUG ("Can't parse, buffer has too small size %u, offset %u", size, - offset); + GST_DEBUG ("Can't parse, buffer has too small size %" G_GSSIZE_FORMAT + ", offset %u", size, offset); return GST_H264_PARSER_ERROR; } @@ -1180,12 +1222,14 @@ gst_h264_parser_identify_nalu (GstH264NalParser * nalparser, /** * gst_h264_parser_identify_nalu_avc: + * @nalparser: a #GstH264NalParser * @data: The data to parse, must be the beging of the Nal unit + * @offset: the offset from which to parse @data * @size: the size of @data * @nal_length_size: the size in bytes of the AVC nal length prefix. * @nalu: The #GstH264NalUnit where to store parsed nal headers * - * Parses the data and sets @nalu from @data. + * Parses @data and sets @nalu. * * Returns: a #GstH264ParserResult */ @@ -1221,6 +1265,17 @@ gst_h264_parser_identify_nalu_avc (GstH264NalParser * nalparser, return GST_H264_PARSER_OK; } +/** + * gst_h264_parser_parse_nal: + * @nalparser: a #GstH264NalParser + * @nalu: The #GstH264NalUnit to parse + * + * This function should be called in the case one doesn't need to + * parse a specific structure. It is necessary to do so to make + * sure @nalparser is up to date. + * + * Returns: a #GstH264ParserResult + */ GstH264ParserResult gst_h264_parser_parse_nal (GstH264NalParser * nalparser, GstH264NalUnit * nalu) { @@ -1241,11 +1296,11 @@ gst_h264_parser_parse_nal (GstH264NalParser * nalparser, GstH264NalUnit * nalu) /** * gst_h264_parser_parse_sps: * @nalparser: a #GstH264NalParser - * @nalu: The #GST_H264_NAL_SPS #GstH264NalUnit you want to parse - * @slice: The #GstH264SPS to set. + * @nalu: The #GST_H264_NAL_SPS #GstH264NalUnit to parse + * @sps: The #GstH264SPS to fill. * @parse_vui_params: Whether to parse the vui_params or not * - * Parses the @data, and sets the @sps. + * Parses @data, and fills the @sps structure. * * Returns: a #GstH264ParserResult */ @@ -1269,11 +1324,11 @@ gst_h264_parser_parse_sps (GstH264NalParser * nalparser, GstH264NalUnit * nalu, /** * gst_h264_parse_sps: - * @nalu: The #GST_H264_NAL_SPS #GstH264NalUnit you want to parse - * @slice: The #GstH264SPS to set. + * @nalu: The #GST_H264_NAL_SPS #GstH264NalUnit to parse + * @sps: The #GstH264SPS to fill. * @parse_vui_params: Whether to parse the vui_params or not * - * Parses the @data, and sets the @sps. + * Parses @data, and fills the @sps structure. * * Returns: a #GstH264ParserResult */ @@ -1413,19 +1468,25 @@ gst_h264_parse_sps (GstH264NalUnit * nalu, GstH264SPS * sps, sps->width = width; sps->height = height; - /* derive framerate */ - /* FIXME verify / also handle other cases */ - GST_LOG ("Framerate: %u %u %u %u", parse_vui_params, - vui->fixed_frame_rate_flag, sps->frame_mbs_only_flag, - vui->pic_struct_present_flag); - - if (parse_vui_params && vui->fixed_frame_rate_flag && - sps->frame_mbs_only_flag && !vui->pic_struct_present_flag) { - sps->fps_num = vui->time_scale; - sps->fps_den = vui->num_units_in_tick; - /* picture is a frame = 2 fields */ - sps->fps_den *= 2; - GST_LOG ("framerate %d/%d", sps->fps_num, sps->fps_den); + if (vui) { + /* derive framerate */ + /* FIXME verify / also handle other cases */ + GST_LOG ("Framerate: %u %u %u %u", parse_vui_params, + vui->fixed_frame_rate_flag, sps->frame_mbs_only_flag, + vui->pic_struct_present_flag); + + if (parse_vui_params && vui->fixed_frame_rate_flag && + sps->frame_mbs_only_flag && !vui->pic_struct_present_flag) { + sps->fps_num = vui->time_scale; + sps->fps_den = vui->num_units_in_tick; + /* picture is a frame = 2 fields */ + sps->fps_den *= 2; + GST_LOG ("framerate %d/%d", sps->fps_num, sps->fps_den); + } + } else { + sps->fps_num = 0; + sps->fps_den = 1; + GST_LOG ("No VUI, unknown framerate"); } sps->valid = TRUE; @@ -1441,12 +1502,10 @@ error: /** * gst_h264_parse_pps: * @nalparser: a #GstH264NalParser - * @data: the data to parse - * @size: the size of @data - * @nalu: The #GST_H264_NAL_PPS #GstH264NalUnit you want to parse - * @slice: The #GstH264PPS to set. + * @nalu: The #GST_H264_NAL_PPS #GstH264NalUnit to parse + * @pps: The #GstH264PPS to fill. * - * Parses the @data, and sets the @pps. + * Parses @data, and fills the @pps structure. * * Returns: a #GstH264ParserResult */ @@ -1572,12 +1631,10 @@ error: /** * gst_h264_parser_parse_pps: * @nalparser: a #GstH264NalParser - * @data: the data to parse - * @size: the size of @data - * @nalu: The #GST_H264_NAL_PPS #GstH264NalUnit you want to parse - * @slice: The #GstH264PPS to set. + * @nalu: The #GST_H264_NAL_PPS #GstH264NalUnit to parse + * @pps: The #GstH264PPS to fill. * - * Parses the @data, and sets the @pps. + * Parses @data, and fills the @pps structure. * * Returns: a #GstH264ParserResult */ @@ -1599,12 +1656,13 @@ gst_h264_parser_parse_pps (GstH264NalParser * nalparser, /** * gst_h264_parser_parse_slice_hdr: - * @nalu: The #GST_H264_NAL_SLICE #GstH264NalUnit you want to parse - * @slice: The #GstH264SliceHdr to set. + * @nalparser: a #GstH264NalParser + * @nalu: The #GST_H264_NAL_SLICE #GstH264NalUnit to parse + * @slice: The #GstH264SliceHdr to fill. * @parse_pred_weight_table: Whether to parse the pred_weight_table or not * @parse_dec_ref_pic_marking: Whether to parse the dec_ref_pic_marking or not * - * Parses the @data, and sets the @slice. + * Parses @data, and fills the @slice structure. * * Returns: a #GstH264ParserResult */ @@ -1776,10 +1834,10 @@ error: /** * gst_h264_parser_parse_sei: * @nalparser: a #GstH264NalParser - * @nalu: The #GST_H264_NAL_SEI #GstH264NalUnit you want to parse - * @slice: The #GstH264SEIMessage to set. + * @nalu: The #GST_H264_NAL_SEI #GstH264NalUnit to parse + * @sei: The #GstH264SEIMessage to fill. * - * Parses the @data, and sets the @pps. + * Parses @data, and fills the @sei structures. * * Returns: a #GstH264ParserResult */ diff --git a/gst-libs/gst/codecparsers/gsth264parser.h b/gst-libs/gst/codecparsers/gsth264parser.h index 84577f686..2dfe2d7b6 100644 --- a/gst-libs/gst/codecparsers/gsth264parser.h +++ b/gst-libs/gst/codecparsers/gsth264parser.h @@ -30,6 +30,11 @@ #ifndef __GST_H264_PARSER_H__ #define __GST_H264_PARSER_H__ +#ifndef GST_USE_UNSTABLE_API +#warning "The H.264 parsing library is unstable API and may change in future." +#warning "You can define GST_USE_UNSTABLE_API to avoid this warning." +#endif + #include <gst/gst.h> G_BEGIN_DECLS @@ -45,19 +50,19 @@ G_BEGIN_DECLS /** * GstH264NalUnitType: - * @GST_H264_NAL_UNKNOWN: Unkonw nal type + * @GST_H264_NAL_UNKNOWN: Unknown nal type * @GST_H264_NAL_SLICE: Slice nal * @GST_H264_NAL_SLICE_DPA: DPA slice nal * @GST_H264_NAL_SLICE_DPB: DPB slice nal * @GST_H264_NAL_SLICE_DPC: DPC slice nal * @GST_H264_NAL_SLICE_IDR: DPR slice nal - * @GST_H264_NAL_SEI: Supplemental enhancement information nal unit - * @GST_H264_NAL_SPS: Sequence parameter set nal unit - * @GST_H264_NAL_PPS: Picture parameter set nal unit - * @GST_H264_NAL_AU_DELIMITER: Access unit delimiter nal unit + * @GST_H264_NAL_SEI: Supplemental enhancement information (SEI) nal unit + * @GST_H264_NAL_SPS: Sequence parameter set (SPS) nal unit + * @GST_H264_NAL_PPS: Picture parameter set (PPS) nal unit + * @GST_H264_NAL_AU_DELIMITER: Access unit (AU) delimiter nal unit * @GST_H264_NAL_SEQ_END: End of sequence nal unit * @GST_H264_NAL_STREAM_END: End of stream nal unit - * @GST_H264_NAL_FILLER_DATA: Filler data na lunit + * @GST_H264_NAL_FILLER_DATA: Filler data nal lunit * * Indicates the type of H264 Nal Units */ @@ -81,13 +86,13 @@ typedef enum /** * GstH264ParserResult: * @GST_H264_PARSER_OK: The parsing succeded - * @GST_H264_PARSER_BROKEN_DATA: The data we parsed where broken - * @GST_H264_PARSER_BROKEN_LINK: The link to a needed struct for the parsing couldn't be found + * @GST_H264_PARSER_BROKEN_DATA: The data to parse is broken + * @GST_H264_PARSER_BROKEN_LINK: The link to structure needed for the parsing couldn't be found * @GST_H264_PARSER_ERROR: An error accured when parsing * @GST_H264_PARSER_NO_NAL: No nal found during the parsing - * @GST_H264_PARSER_NO_NAL_END: Start of the nal found, not the end. + * @GST_H264_PARSER_NO_NAL_END: Start of the nal found, but not the end. * - * Information about how the parsing of a H264 elements went. + * The result of parsing H264 data. */ typedef enum { @@ -101,11 +106,11 @@ typedef enum /** * GstH264SEIPayloadType: - * @GST_H264_SEI_BUF_PERIOD: The Sei Message contains a buffering period message - * @GST_H264_SEI_PIC_TIMING: The Sei Message contains a picture timing message + * @GST_H264_SEI_BUF_PERIOD: Buffering Period SEI Message + * @GST_H264_SEI_PIC_TIMING: Picture Timing SEI Message * ... * - * The type of the SEI message information + * The type of SEI message. */ typedef enum { @@ -294,7 +299,7 @@ struct _GstH264HRDParams * samples outside picture boundaries may be used in inter prediction * @max_bytes_per_pic_denom: indicates a number of bytes not exceeded by the sum of the sizes of * the VCL NAL units associated with any coded picture in the coded video sequence. - * @max_bits_per_mb_denom: indicates the maximum number of coded bits of macroblock_layer() + * @max_bits_per_mb_denom: indicates the maximum number of coded bits of macroblock_layer * @log2_max_mv_length_horizontal: indicate the maximum absolute value of a decoded horizontal * motion vector component * @log2_max_mv_length_vertical: indicate the maximum absolute value of a decoded vertical @@ -363,7 +368,7 @@ struct _GstH264VUIParams * @id: The ID of the sequence parameter set * @profile_idc: indicate the profile to which the coded video sequence conforms * - * + * H264 Sequence Parameter Set (SPS) */ struct _GstH264SPS { @@ -429,6 +434,11 @@ struct _GstH264SPS gboolean valid; }; +/** + * GstH264PPS: + * + * H264 Picture Parameter Set + */ struct _GstH264PPS { gint id; diff --git a/gst-libs/gst/codecparsers/gstmpegvideoparser.c b/gst-libs/gst/codecparsers/gstmpegvideoparser.c index 44df76ad5..e871017fa 100644 --- a/gst-libs/gst/codecparsers/gstmpegvideoparser.c +++ b/gst-libs/gst/codecparsers/gstmpegvideoparser.c @@ -309,12 +309,12 @@ scan_for_start_codes (const GstByteReader * reader, guint offset, guint size) /** * gst_mpeg_video_parse: - * @data: The datas from which to parse + * @data: The data to parse * @size: The size of @data - * @offset: The offset from which to start the parsing + * @offset: The offset from which to start parsing * - * Parses @data, and detects the different packets types, offset, - * and size, starting from @offset + * Parses the MPEG 1/2 video bitstream contained in @data , and returns the + * detect packets as a list of #GstMpegVideoTypeOffsetSize. * * Returns: a #GList of #GstMpegVideoTypeOffsetSize */ @@ -324,7 +324,8 @@ gst_mpeg_video_parse (guint8 * data, gsize size, guint offset) gint off, rsize; GstByteReader br; GList *ret = NULL; - size = size - offset; + + size -= offset; if (!initialized) { GST_DEBUG_CATEGORY_INIT (mpegvideo_parser_debug, "codecparsers_mpegvideo", @@ -373,12 +374,12 @@ gst_mpeg_video_parse (guint8 * data, gsize size, guint offset) /** * gst_mpeg_video_parse_sequence_header: - * @seqhdr: The #GstMpegVideoSequenceHdr to set - * @data: The datas from which to parse the seqhdr + * @seqhdr: (out): The #GstMpegVideoSequenceHdr structure to fill + * @data: The data from which to parse the sequence header * @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 + * Parses the @seqhdr Mpeg Video Sequence Header structure members from @data * * Returns: %TRUE if the seqhdr could be parsed correctly, %FALSE otherwize. */ @@ -388,9 +389,11 @@ gst_mpeg_video_parse_sequence_header (GstMpegVideoSequenceHdr * seqhdr, { GstBitReader br; - size = size - offset; + g_return_val_if_fail (seqhdr != NULL, FALSE); - if (size - offset < 4) + size -= offset; + + if (size < 4) return FALSE; gst_bit_reader_init (&br, &data[offset], size); @@ -400,12 +403,12 @@ gst_mpeg_video_parse_sequence_header (GstMpegVideoSequenceHdr * seqhdr, /** * gst_mpeg_video_parse_sequence_extension: - * @seqhdr: The #GstMpegVideoSequenceExt to set - * @data: The datas from which to parse the seqext + * @seqext: (out): The #GstMpegVideoSequenceExt structure to fill + * @data: The data from which to parse the sequence extension * @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 + * Parses the @seqext Mpeg Video Sequence Extension structure members from @data * * Returns: %TRUE if the seqext could be parsed correctly, %FALSE otherwize. */ @@ -415,7 +418,9 @@ gst_mpeg_video_parse_sequence_extension (GstMpegVideoSequenceExt * seqext, { GstBitReader br; - size = size - offset; + g_return_val_if_fail (seqext != NULL, FALSE); + + size -= offset; if (size < 6) { GST_DEBUG ("not enough bytes to parse the extension"); @@ -464,12 +469,12 @@ gst_mpeg_video_parse_sequence_extension (GstMpegVideoSequenceExt * seqext, /** * gst_mpeg_video_parse_quant_matrix_extension: - * @ext: The #GstMpegVideoQuantMatrixExt to set - * @data: The datas from which to parse @quant + * @quant: (out): The #GstMpegVideoQuantMatrixExt structure to fill + * @data: The data from which to parse the Quantization Matrix extension * @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 + * Parses the @quant Mpeg Video Quant Matrix Extension structure members from * @data * * Returns: %TRUE if the quant matrix extension could be parsed correctly, @@ -482,7 +487,9 @@ gst_mpeg_video_parse_quant_matrix_extension (GstMpegVideoQuantMatrixExt * quant, guint8 i; GstBitReader br; - size = size - offset; + g_return_val_if_fail (quant != NULL, FALSE); + + size -= offset; if (size < 1) { GST_DEBUG ("not enough bytes to parse the extension"); @@ -537,12 +544,12 @@ failed: /** * gst_mpeg_video_parse_picture_extension: - * @ext: The #GstMpegVideoPictureExt to set - * @data: The datas from which to parse the ext + * @ext: (out): The #GstMpegVideoPictureExt structure to fill + * @data: The data from which to parse the picture extension * @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 + * Parse the @ext Mpeg Video Picture Extension structure members from @data * * Returns: %TRUE if the picture extension could be parsed correctly, * %FALSE otherwize. @@ -553,7 +560,9 @@ gst_mpeg_video_parse_picture_extension (GstMpegVideoPictureExt * ext, { GstBitReader br; - size = size - offset; + g_return_val_if_fail (ext != NULL, FALSE); + + size -= offset; if (size < 4) return FALSE; @@ -636,14 +645,15 @@ failed: /** * gst_mpeg_video_parse_picture_header: - * @hdr: The #GstMpegVideoPictureHdr to set - * @data: The datas from which to parse the hdr + * @hdr: (out): The #GstMpegVideoPictureHdr structure to fill + * @data: The data from which to parse the picture header * @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 + * Parsers the @hdr Mpeg Video Picture Header structure members from @data * - * Returns: %TRUE if the picture sequence could be parsed correctly, %FALSE otherwize. + * Returns: %TRUE if the picture sequence could be parsed correctly, %FALSE + * otherwize. */ gboolean gst_mpeg_video_parse_picture_header (GstMpegVideoPictureHdr * hdr, @@ -654,24 +664,26 @@ gst_mpeg_video_parse_picture_header (GstMpegVideoPictureHdr * hdr, size = size - offset; if (size < 4) - return FALSE; + goto failed; gst_bit_reader_init (&br, &data[offset], size); /* temperal sequence number */ if (!gst_bit_reader_get_bits_uint16 (&br, &hdr->tsn, 10)) - return FALSE; + goto failed; + /* frame type */ if (!gst_bit_reader_get_bits_uint8 (&br, (guint8 *) & hdr->pic_type, 3)) - return FALSE; + goto failed; + if (hdr->pic_type == 0 || hdr->pic_type > 4) - return FALSE; /* Corrupted picture packet */ + goto failed; /* Corrupted picture packet */ /* skype VBV delay */ if (!gst_bit_reader_skip (&br, 8)) - return FALSE; + goto failed; if (hdr->pic_type == GST_MPEG_VIDEO_PICTURE_TYPE_P || hdr->pic_type == GST_MPEG_VIDEO_PICTURE_TYPE_B) { @@ -699,20 +711,19 @@ gst_mpeg_video_parse_picture_header (GstMpegVideoPictureHdr * hdr, failed: { - GST_WARNING ("Failed to parse sequence extension"); + GST_WARNING ("Failed to parse picture header"); return FALSE; } } /** * gst_mpeg_video_parse_gop: - * @gop: The #GstMpegVideoGop to set - * @data: The datas from which to parse the gop + * @gop: (out): The #GstMpegVideoGop structure to fill + * @data: The data 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 + * Parses the @gop Mpeg Video Group of Picture structure members from @data * * Returns: %TRUE if the gop could be parsed correctly, %FALSE otherwize. */ @@ -722,7 +733,9 @@ gst_mpeg_video_parse_gop (GstMpegVideoGop * gop, guint8 * data, { GstBitReader br; - size = size - offset; + g_return_val_if_fail (gop != NULL, FALSE); + + size -= offset; if (size < 4) return FALSE; @@ -745,7 +758,7 @@ gst_mpeg_video_parse_gop (GstMpegVideoGop * gop, guint8 * data, READ_UINT8 (&br, gop->closed_gop, 1); - READ_UINT8 (&br, gop->broken_gop, 1); + READ_UINT8 (&br, gop->broken_link, 1); return TRUE; diff --git a/gst-libs/gst/codecparsers/gstmpegvideoparser.h b/gst-libs/gst/codecparsers/gstmpegvideoparser.h index a42792b81..a212a9444 100644 --- a/gst-libs/gst/codecparsers/gstmpegvideoparser.h +++ b/gst-libs/gst/codecparsers/gstmpegvideoparser.h @@ -26,6 +26,11 @@ #ifndef __GST_MPEG_VIDEO_UTILS_H__ #define __GST_MPEG_VIDEO_UTILS_H__ +#ifndef GST_USE_UNSTABLE_API +#warning "The Mpeg video parsing library is unstable API and may change in future." +#warning "You can define GST_USE_UNSTABLE_API to avoid this warning." +#endif + #include <gst/gst.h> G_BEGIN_DECLS @@ -57,32 +62,43 @@ typedef enum { } GstMpegVideoPacketTypeCode; /** + * GST_MPEG_VIDEO_PACKET_IS_SLICE: + * @typecode: The MPEG video packet type code + * + * Checks whether a packet type code is a slice. + * + * Returns: %TRUE if the packet type code corresponds to a slice, + * else %FALSE. + */ +#define GST_MPEG_VIDEO_PACKET_IS_SLICE(typecode) ((typecode) >= GST_MPEG_VIDEO_PACKET_SLICE_MIN && \ + (typecode) <= GST_MPEG_VIDEO_PACKET_SLICE_MAX) + +/** * 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 + * @GST_MPEG_VIDEO_PACKET_EXT_SEQUENCE_DISPLAY: Sequence Display extension code + * @GST_MPEG_VIDEO_PACKET_EXT_QUANT_MATRIX: Quantization Matrix extension code + * @GST_MPEG_VIDEO_PACKET_EXT_PICTURE: Picture coding extension * - * 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 + * 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, GST_MPEG_VIDEO_PACKET_EXT_PICTURE = 0x08 } GstMpegVideoPacketExtensionCode; /** * GstMpegVideoLevel: - * @GST_MPEG_VIDEO_LEVEL_LOW: Level Low - * @GST_MPEG_VIDEO_LEVEL_MAIN: Level Main - * @GST_MPEG_VIDEO_LEVEL_HIGH_1440: Level High 1440 - * @GST_MPEG_VIDEO_LEVEL_HIGH: Level High + * @GST_MPEG_VIDEO_LEVEL_LOW: Low level (LL) + * @GST_MPEG_VIDEO_LEVEL_MAIN: Main level (ML) + * @GST_MPEG_VIDEO_LEVEL_HIGH_1440: High 1440 level (H-14) + * @GST_MPEG_VIDEO_LEVEL_HIGH: High level (HL) * - * Indicates the level in use + * Mpeg-2 Levels. **/ typedef enum { GST_MPEG_VIDEO_LEVEL_HIGH = 0x04, @@ -93,14 +109,14 @@ typedef enum { /** * 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, + * @GST_MPEG_VIDEO_PROFILE_422: 4:2:2 profile (422) + * @GST_MPEG_VIDEO_PROFILE_HIGH: High profile (HP) + * @GST_MPEG_VIDEO_PROFILE_SPATIALLY_SCALABLE: Spatially Scalable profile (Spatial) + * @GST_MPEG_VIDEO_PROFILE_SNR_SCALABLE: SNR Scalable profile (SNR) + * @GST_MPEG_VIDEO_PROFILE_MAIN: Main profile (MP) + * @GST_MPEG_VIDEO_PROFILE_SIMPLE: Simple profile (SP) * - * Indicates the profile type in use + * Mpeg-2 Profiles. **/ typedef enum { GST_MPEG_VIDEO_PROFILE_422 = 0x00, @@ -112,13 +128,29 @@ typedef enum { } GstMpegVideoProfile; /** + * GstMpegVideoChromaFormat: + * @GST_MPEG_VIDEO_CHROMA_RES: Invalid (reserved for future use) + * @GST_MPEG_VIDEO_CHROMA_420: 4:2:0 subsampling + * @GST_MPEG_VIDEO_CHROMA_422: 4:2:2 subsampling + * @GST_MPEG_VIDEO_CHROMA_444: 4:4:4 (non-subsampled) + * + * Chroma subsampling type. + */ +typedef enum { + GST_MPEG_VIDEO_CHROMA_RES = 0x00, + GST_MPEG_VIDEO_CHROMA_420 = 0x01, + GST_MPEG_VIDEO_CHROMA_422 = 0x02, + GST_MPEG_VIDEO_CHROMA_444 = 0x03, +} GstMpegVideoChromaFormat; + +/** * 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 + * @GST_MPEG_VIDEO_PICTURE_TYPE_I: Intra-coded (I) frame + * @GST_MPEG_VIDEO_PICTURE_TYPE_P: Predictive-codec (P) frame + * @GST_MPEG_VIDEO_PICTURE_TYPE_B: Bidirectionally predictive-coded (B) frame + * @GST_MPEG_VIDEO_PICTURE_TYPE_D: D frame * - * Indicates the type of picture + * Picture type. */ typedef enum { GST_MPEG_VIDEO_PICTURE_TYPE_I = 0x01, @@ -131,9 +163,9 @@ typedef enum { * 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 + * @GST_MPEG_VIDEO_PICTURE_STRUCTURE_FRAME: Frame picture * - * Indicates the structure of picture + * Picture structure type. */ typedef enum { GST_MPEG_VIDEO_PICTURE_STRUCTURE_TOP_FIELD = 0x01, @@ -168,20 +200,20 @@ typedef struct _GstMpegVideoTypeOffsetSize GstMpegVideoTypeOffsetSize; struct _GstMpegVideoSequenceHdr { guint16 width, height; - guint8 aspect_ratio_info; - guint8 frame_rate_code; + guint8 aspect_ratio_info; + guint8 frame_rate_code; guint32 bitrate_value; guint16 vbv_buffer_size_value; - guint8 constrained_parameters_flag; + guint8 constrained_parameters_flag; - guint8 intra_quantizer_matrix[64]; - guint8 non_intra_quantizer_matrix[64]; + 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; + guint par_w, par_h; + guint fps_n, fps_d; + guint bitrate; }; /** @@ -194,7 +226,7 @@ struct _GstMpegVideoSequenceHdr * @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 + * @low_delay: %TRUE if the sequence doesn't contain any B-pictures, %FALSE * otherwize * @fps_n_ext: Framerate nominator code * @fps_d_ext: Framerate denominator code @@ -222,14 +254,14 @@ struct _GstMpegVideoSequenceExt /** * GstMpegVideoQuantMatrixExt: - * @load_intra_quantiser_matrix - * @intra_quantiser_matrix - * @load_non_intra_quantiser_matrix + * @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 + * @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 */ @@ -314,7 +346,7 @@ struct _GstMpegVideoPictureExt * @second: Second (0-59) * @frame: Frame (0-59) * @closed_gop: Closed Gop - * @broken_gop: Broken Gop + * @broken_link: Broken link * * The Mpeg Video Group of Picture structure. */ @@ -325,7 +357,7 @@ struct _GstMpegVideoGop guint8 hour, minute, second, frame; guint8 closed_gop; - guint8 broken_gop; + guint8 broken_link; }; /** @@ -339,11 +371,11 @@ struct _GstMpegVideoGop struct _GstMpegVideoTypeOffsetSize { guint8 type; - guint offset; - gint size; + guint offset; + gint size; }; -GList * gst_mpeg_video_parse (guint8 * data, gsize size, guint offset); +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); diff --git a/gst-libs/gst/codecparsers/gstvc1parser.c b/gst-libs/gst/codecparsers/gstvc1parser.c new file mode 100644 index 000000000..8b0b78567 --- /dev/null +++ b/gst-libs/gst/codecparsers/gstvc1parser.c @@ -0,0 +1,1442 @@ +/* Gstreamer + * Copyright (C) <2011> Intel + * Copyright (C) <2011> Collabora Ltd. + * Copyright (C) <2011> Thibault Saunier <thibault.saunier@collabora.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. + */ +/** + * SECTION:gstvc1parser + * @short_description: Convenience library for parsing vc1 video + * bitstream. + * + * For more details about the structures, look at the + * smpte specifications (S421m-2006.pdf). + * + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include "gstvc1parser.h" +#include <gst/base/gstbytereader.h> +#include <gst/base/gstbitreader.h> +#include <string.h> + +#ifndef GST_DISABLE_GST_DEBUG + +#define GST_CAT_DEFAULT ensure_debug_category() + +static GstDebugCategory * +ensure_debug_category (void) +{ + static gsize cat_gonce = 0; + + if (g_once_init_enter (&cat_gonce)) { + gsize cat_done; + + cat_done = (gsize) _gst_debug_category_new ("codecparsers_vc1", 0, + "VC1 codec parsing library"); + + g_once_init_leave (&cat_gonce, cat_done); + } + + return (GstDebugCategory *) cat_gonce; +} + +#else + +#define ensure_debug_category() /* NOOP */ + +#endif /* GST_DISABLE_GST_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 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 + +#define SKIP(br, nbits) G_STMT_START { \ + if (!gst_bit_reader_skip (br, nbits)) { \ + GST_WARNING ("Failed to skip nbits: %d", nbits); \ + goto failed; \ + } \ +} G_STMT_END + +const guint8 vc1_pquant_table[3][32] = { + { /* Implicit quantizer */ + 0, 1, 2, 3, 4, 5, 6, 7, 8, 6, 7, 8, 9, 10, 11, 12, + 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 27, 29, 31}, + { /* Explicit quantizer, pquantizer uniform */ + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31}, + { /* Explicit quantizer, pquantizer non-uniform */ + 0, 1, 1, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, + 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 29, 31} +}; + +const guint8 mvmode_table[2][5] = { + { + GST_VC1_MVMODE_1MV_HPEL_BILINEAR, + GST_VC1_MVMODE_1MV, + GST_VC1_MVMODE_1MV_HPEL, + GST_VC1_MVMODE_MIXED_MV, + GST_VC1_MVMODE_INTENSITY_COMP}, + { + GST_VC1_MVMODE_1MV, + GST_VC1_MVMODE_MIXED_MV, + GST_VC1_MVMODE_1MV_HPEL, + GST_VC1_MVMODE_INTENSITY_COMP, + GST_VC1_MVMODE_1MV_HPEL_BILINEAR} +}; + +const guint8 mvmode2_table[2][4] = { + { + GST_VC1_MVMODE_1MV_HPEL_BILINEAR, + GST_VC1_MVMODE_1MV, + GST_VC1_MVMODE_1MV_HPEL, + GST_VC1_MVMODE_MIXED_MV}, + { + GST_VC1_MVMODE_1MV, + GST_VC1_MVMODE_MIXED_MV, + GST_VC1_MVMODE_1MV_HPEL, + GST_VC1_MVMODE_1MV_HPEL_BILINEAR} +}; + +static const guint bfraction_vlc_table[] = { + 0x00, 3, 128, + 0x01, 3, 85, + 0x02, 3, 170, + 0x03, 3, 64, + 0x04, 3, 192, + 0x05, 3, 51, + 0x06, 3, 102, + 0x70, 3, 153, + 0x71, 7, 204, + 0x72, 7, 43, + 0x73, 7, 215, + 0x74, 7, 37, + 0x75, 7, 74, + 0x76, 7, 111, + 0x77, 7, 148, + 0x78, 7, 185, + 0x79, 7, 222, + 0x7a, 7, 32, + 0x7b, 7, 96, + 0x7c, 7, 160, + 0x7d, 7, 224, + 0x7e, 7, 0, /* Indicate sthat it is smtpe reserved */ + 0x7f, 7, GST_VC1_PICTURE_TYPE_BI +}; + +/* Imode types */ +enum +{ + IMODE_RAW, + IMODE_NORM2, + IMODE_DIFF2, + IMODE_NORM6, + IMODE_DIFF6, + IMODE_ROWSKIP, + IMODE_COLSKIP +}; + +static const guint imode_vlc_table[] = { + 0x02, 2, IMODE_NORM2, /* 10 */ + 0x03, 2, IMODE_NORM6, /* 11 */ + 0x02, 3, IMODE_ROWSKIP, /* 010 */ + 0x03, 3, IMODE_COLSKIP, /* 011 */ + 0x01, 3, IMODE_DIFF2, /* 001 */ + 0x01, 4, IMODE_DIFF6, /* 0001 */ + 0x00, 4, IMODE_RAW /* 0000 */ +}; + +const guint vc1_norm2_codes_vlc_table[] = { + 0x00, 1, 1, + 0x03, 2, 3, + 0x04, 3, 3, + 0x05, 3, 2 +}; + +const guint norm6_vlc_table[256] = { + 0x001, 1, 0, + 0x002, 4, 0, + 0x003, 4, 0, + 0x004, 4, 0, + 0x005, 4, 0, + 0x006, 4, 0, + 0x007, 4, 0, + 0x007, 6, 0, + 0x000, 8, 0, + 0x001, 8, 0, + 0x002, 8, 0, + 0x003, 8, 0, + 0x004, 8, 0, + 0x005, 8, 0, + 0x006, 8, 0, + 0x007, 8, 0, + 0x008, 8, 0, + 0x009, 8, 0, + 0x00A, 8, 0, + 0x00B, 8, 0, + 0x00C, 8, 0, + 0x00D, 8, 0, + 0x00E, 8, 0, + 0x037, 9, 0, + 0x036, 9, 0, + 0x035, 9, 0, + 0x034, 9, 0, + 0x033, 9, 0, + 0x032, 9, 0, + 0x047, 10, 0, + 0x04B, 10, 0, + 0x04D, 10, 0, + 0x04E, 10, 0, + 0x30E, 13, 0, + 0x053, 10, 0, + 0x055, 10, 0, + 0x056, 10, 0, + 0x30D, 13, 0, + 0x059, 10, 0, + 0x05A, 10, 0, + 0x30C, 13, 0, + 0x05C, 10, 0, + 0x30B, 13, 0, + 0x30A, 13, 0, + 0x043, 10, 0, + 0x045, 10, 0, + 0x046, 10, 0, + 0x309, 13, 0, + 0x049, 10, 0, + 0x04A, 10, 0, + 0x308, 13, 0, + 0x04C, 10, 0, + 0x307, 13, 0, + 0x306, 13, 0, + 0x051, 10, 0, + 0x052, 10, 0, + 0x305, 13, 0, + 0x054, 10, 0, + 0x304, 13, 0, + 0x303, 13, 0, + 0x058, 10, 0, + 0x302, 13, 0, + 0x301, 13, 0, + 0x300, 13, 0 +}; + +static inline guint8 +decode_colskip (GstBitReader * br, guint width, guint height) +{ + guint i; + guint8 colskip; + + GST_DEBUG ("Colskip rowskip"); + + for (i = 0; i < height; i++) { + READ_UINT8 (br, colskip, 1); + + if (colskip) + SKIP (br, width); + } + + return 1; + +failed: + GST_WARNING ("Failed to parse colskip"); + + return 0; +} + +static inline guint8 +decode_rowskip (GstBitReader * br, guint width, guint height) +{ + guint i; + guint8 rowskip; + + GST_DEBUG ("Parsing rowskip"); + + for (i = 0; i < height; i++) { + READ_UINT8 (br, rowskip, 1); + + if (rowskip) + SKIP (br, width); + } + return 1; + +failed: + GST_WARNING ("Failed to parse rowskip"); + + return 0; +} + +static inline gint8 +decode012 (GstBitReader * br) +{ + guint8 n; + + READ_UINT8 (br, n, 1); + + if (n == 0) + return 0; + + READ_UINT8 (br, n, 1); + + return n + 1; + +failed: + GST_WARNING ("Could not decode 0 1 2 returning -1"); + + return -1; +} + +static inline guint +calculate_nb_pan_scan_win (GstVC1AdvancedSeqHdr * advseqhdr, + GstVC1PicAdvanced * pic) +{ + if (advseqhdr->interlace && !advseqhdr->psf) { + if (advseqhdr->pulldown) + return pic->rff + 2; + + return 2; + + } else { + if (advseqhdr->pulldown) + return pic->rptfrm + 1; + + return 1; + } +} + + +/** + * table should look like: + * {Value, nbBits, Meaning, + * ... + * } nbBits must be increasing + */ +static gboolean +decode_vlc (GstBitReader * br, guint * res, const guint * table, guint length) +{ + guint8 i; + guint cbits = 0; + guint32 value = 0; + + for (i = 0; i < length; i += 3) { + if (cbits != table[i + 1]) { + cbits = table[i + 1]; + if (!gst_bit_reader_peek_bits_uint32 (br, &value, cbits)) { + goto failed; + } + } + + if (value == table[i]) { + SKIP (br, cbits); + if (res) + *res = table[i + 2]; + + return TRUE; + } + } + +failed: + { + GST_DEBUG ("Could not decode VLC returning -1"); + + return FALSE; + } +} + +/*** bitplane decoding ***/ +static gint +bitplane_decoding (GstBitReader * br, guint height, + guint width, guint8 * is_raw) +{ + guint imode; + guint i, j, offset = 0; + + SKIP (br, 1); + if (!decode_vlc (br, &imode, imode_vlc_table, G_N_ELEMENTS (imode_vlc_table))) + goto failed; + + switch (imode) { + case IMODE_RAW: + + GST_DEBUG ("Parsing IMODE_RAW"); + + *is_raw = TRUE; + return TRUE; + + case IMODE_DIFF2: + case IMODE_NORM2: + + GST_DEBUG ("Parsing IMODE_DIFF2 or IMODE_NORM2 biplane"); + + if ((height * width) & 1) { + SKIP (br, 1); + } + + for (i = offset; i < height * width; i += 2) { + /*guint x; */ + if (!decode_vlc (br, NULL, vc1_norm2_codes_vlc_table, + G_N_ELEMENTS (vc1_norm2_codes_vlc_table))) { + goto failed; + } + } + break; + + case IMODE_DIFF6: + case IMODE_NORM6: + + GST_DEBUG ("Parsing IMODE_DIFF6 or IMODE_NORM6 biplane"); + + if (!(height % 3) && (width % 3)) { // use 2x3 decoding + + for (i = 0; i < height; i += 3) { + for (j = width & 1; j < width; j += 2) { + if (!decode_vlc (br, NULL, norm6_vlc_table, + G_N_ELEMENTS (norm6_vlc_table))) { + goto failed; + } + } + } + } else { + for (i = height & 1; i < height; i += 2) { + for (j = width % 3; j < width; j += 3) { + if (!decode_vlc (br, NULL, norm6_vlc_table, + G_N_ELEMENTS (norm6_vlc_table))) { + goto failed; + } + } + } + + j = width % 3; + if (j) + decode_colskip (br, height, width); + + if (height & 1) + decode_rowskip (br, height, width); + } + break; + case IMODE_ROWSKIP: + + GST_DEBUG ("Parsing IMODE_ROWSKIP biplane"); + + if (!decode_rowskip (br, width, height)) + goto failed; + break; + case IMODE_COLSKIP: + + GST_DEBUG ("Parsing IMODE_COLSKIP biplane"); + + if (decode_colskip (br, width, height)) + goto failed; + break; + } + + return TRUE; + +failed: + GST_WARNING ("Failed to decode bitplane"); + + return FALSE; +} + +static gboolean +parse_vopdquant (GstBitReader * br, GstVC1FrameHdr * framehdr, guint8 dquant) +{ + GstVC1VopDquant *vopdquant = &framehdr->vopdquant; + + GST_DEBUG ("Parsing vopdquant"); + + vopdquant->dqbilevel = 0; + + if (dquant == 2) { + READ_UINT8 (br, vopdquant->dquantfrm, 1); + + READ_UINT8 (br, vopdquant->pqdiff, 3); + + if (vopdquant->pqdiff == 7) + READ_UINT8 (br, vopdquant->abspq, 5); + else + vopdquant->abspq = framehdr->pquant + vopdquant->pqdiff + 1; + + } else { + READ_UINT8 (br, vopdquant->dquantfrm, 1); + GST_DEBUG (" %u DquantFrm %u", gst_bit_reader_get_pos (br), + vopdquant->dquantfrm); + + if (vopdquant->dquantfrm) { + READ_UINT8 (br, vopdquant->dqprofile, 1); + + switch (vopdquant->dqprofile) { + case GST_VC1_DQPROFILE_SINGLE_EDGE: + case GST_VC1_DQPROFILE_DOUBLE_EDGES: + READ_UINT8 (br, vopdquant->dqsbedge, 2); + break; + + case GST_VC1_DQPROFILE_ALL_MBS: + READ_UINT8 (br, vopdquant->dqbilevel, 1); + break; + } + + if (vopdquant->dqbilevel + || vopdquant->dqprofile != GST_VC1_DQPROFILE_ALL_MBS) { + { + READ_UINT8 (br, vopdquant->pqdiff, 3); + + if (vopdquant->pqdiff == 7) + READ_UINT8 (br, vopdquant->abspq, 5); + } + } + } + } + + return TRUE; + +failed: + GST_WARNING ("Failed to parse vopdquant"); + + return FALSE; +} + +static inline gint +scan_for_start_codes (const guint8 * data, guint size) +{ + GstByteReader br; + gst_byte_reader_init (&br, data, size); + + /* NALU not empty, so we can at least expect 1 (even 2) bytes following sc */ + return gst_byte_reader_masked_scan_uint32 (&br, 0xffffff00, 0x00000100, + 0, size); +} + +static inline gint +get_unary (GstBitReader * br, gint stop, gint len) +{ + int i; + guint8 current = 0xff; + + for (i = 0; i < len; i++) { + gst_bit_reader_get_bits_uint8 (br, ¤t, 1); + if (current == stop) + return i; + } + + return i; +} + +static GstVC1ParseResult +parse_hrd_param_flag (GstBitReader * br, GstVC1HrdParam * hrd_param) +{ + guint i; + + GST_DEBUG ("Parsing Hrd param flag"); + + + if (gst_bit_reader_get_remaining (br) < 13) + goto failed; + + hrd_param->hrd_num_leaky_buckets = + gst_bit_reader_get_bits_uint8_unchecked (br, 5); + hrd_param->bit_rate_exponent = + gst_bit_reader_get_bits_uint8_unchecked (br, 4); + hrd_param->buffer_size_exponent = + gst_bit_reader_get_bits_uint8_unchecked (br, 4); + + if (gst_bit_reader_get_remaining (br) < + (32 * hrd_param->hrd_num_leaky_buckets)) + goto failed; + + for (i = 0; i < hrd_param->hrd_num_leaky_buckets; i++) { + hrd_param->hrd_rate[i] = gst_bit_reader_get_bits_uint16_unchecked (br, 16); + hrd_param->hrd_buffer[i] = + gst_bit_reader_get_bits_uint16_unchecked (br, 16); + } + + return GST_VC1_PARSER_OK; + +failed: + GST_WARNING ("Failed to parse hrd param flag"); + + return GST_VC1_PARSER_ERROR; +} + +static GstVC1ParseResult +parse_sequence_header_advanced (GstVC1SeqHdr * seqhdr, GstBitReader * br) +{ + GstVC1AdvancedSeqHdr *advanced = &seqhdr->profile.advanced; + + GST_DEBUG ("Parsing sequence header in advanced mode"); + + READ_UINT8 (br, advanced->level, 3); + + READ_UINT8 (br, seqhdr->colordiff_format, 2); + READ_UINT8 (br, seqhdr->frmrtq_postproc, 3); + READ_UINT8 (br, seqhdr->bitrtq_postproc, 5); + + GST_DEBUG ("level %u, colordiff_format %u , frmrtq_postproc %u," + " bitrtq_postproc %u", advanced->level, seqhdr->colordiff_format, + seqhdr->frmrtq_postproc, seqhdr->bitrtq_postproc); + + /* Calulate bitrate and framerate */ + if (seqhdr->frmrtq_postproc == 0 && seqhdr->bitrtq_postproc == 30) { + seqhdr->framerate = 0; + seqhdr->bitrate = 0; + } else if (seqhdr->frmrtq_postproc == 0 && seqhdr->bitrtq_postproc == 30) { + seqhdr->framerate = 2; + seqhdr->bitrate = 1952; + } else if (seqhdr->frmrtq_postproc == 0 && seqhdr->bitrtq_postproc == 31) { + seqhdr->framerate = 6; + seqhdr->bitrate = 2016; + } else { + if (seqhdr->frmrtq_postproc == 7) { + seqhdr->framerate = 30; + } else { + seqhdr->framerate = 2 + (seqhdr->frmrtq_postproc * 4); + } + if (seqhdr->bitrtq_postproc == 31) { + seqhdr->bitrate = 2016; + } else { + seqhdr->bitrate = 32 + (seqhdr->bitrtq_postproc * 64); + } + } + + if (gst_bit_reader_get_remaining (br) < 32) + goto failed; + + advanced->postprocflag = gst_bit_reader_get_bits_uint8_unchecked (br, 1); + advanced->max_coded_width = gst_bit_reader_get_bits_uint16_unchecked (br, 12); + advanced->max_coded_height = + gst_bit_reader_get_bits_uint16_unchecked (br, 12); + advanced->max_coded_width = (advanced->max_coded_width + 1) << 1; + advanced->max_coded_height = (advanced->max_coded_height + 1) << 1; + advanced->pulldown = gst_bit_reader_get_bits_uint8_unchecked (br, 1); + advanced->interlace = gst_bit_reader_get_bits_uint8_unchecked (br, 1); + advanced->tfcntrflag = gst_bit_reader_get_bits_uint8_unchecked (br, 1); + seqhdr->finterpflag = gst_bit_reader_get_bits_uint8_unchecked (br, 1); + + GST_DEBUG ("postprocflag %u, max_coded_width %u, max_coded_height %u," + "pulldown %u, interlace %u, tfcntrflag %u, finterpflag %u", + advanced->postprocflag, advanced->max_coded_width, + advanced->max_coded_height, advanced->pulldown, + advanced->interlace, advanced->tfcntrflag, seqhdr->finterpflag); + + /* Skipping reserved bit */ + gst_bit_reader_skip_unchecked (br, 1); + + advanced->psf = gst_bit_reader_get_bits_uint8_unchecked (br, 1); + advanced->display_ext = gst_bit_reader_get_bits_uint8_unchecked (br, 1); + if (advanced->display_ext) { + READ_UINT16 (br, advanced->disp_horiz_size, 14); + READ_UINT16 (br, advanced->disp_vert_size, 14); + + advanced->disp_horiz_size++; + advanced->disp_vert_size++; + + READ_UINT8 (br, advanced->aspect_ratio_flag, 1); + + if (advanced->aspect_ratio_flag) { + READ_UINT8 (br, advanced->aspect_ratio, 4); + + if (advanced->aspect_ratio == 15) { + READ_UINT8 (br, advanced->aspect_horiz_size, 8); + READ_UINT8 (br, advanced->aspect_vert_size, 8); + } + } + READ_UINT8 (br, advanced->framerate_flag, 1); + if (advanced->framerate_flag) { + READ_UINT8 (br, advanced->framerateind, 1); + + if (!advanced->framerateind) { + READ_UINT8 (br, advanced->frameratenr, 8); + READ_UINT8 (br, advanced->frameratedr, 4); + } else { + READ_UINT16 (br, advanced->framerateexp, 16); + } + } + READ_UINT8 (br, advanced->color_format_flag, 1); + + if (advanced->color_format_flag) { + if (gst_bit_reader_get_remaining (br) < 24) + goto failed; + + advanced->color_prim = gst_bit_reader_get_bits_uint8_unchecked (br, 8); + advanced->transfer_char = gst_bit_reader_get_bits_uint8_unchecked (br, 8); + advanced->matrix_coef = gst_bit_reader_get_bits_uint8_unchecked (br, 8); + } + } + READ_UINT8 (br, advanced->hrd_param_flag, 1); + if (advanced->hrd_param_flag) + return parse_hrd_param_flag (br, &advanced->hrd_param); + + return GST_VC1_PARSER_OK; + +failed: + GST_WARNING ("Failed to parse advanced headers"); + + return GST_VC1_PARSER_ERROR; +} + +static GstVC1ParseResult +parse_frame_header_advanced (GstBitReader * br, GstVC1FrameHdr * framehdr, + GstVC1SeqHdr * seqhdr) +{ + GstVC1AdvancedSeqHdr *advhdr = &seqhdr->profile.advanced; + GstVC1PicAdvanced *pic = &framehdr->pic.advanced; + GstVC1EntryPointHdr *entrypthdr = &advhdr->entrypoint; + guint8 mvmodeidx; + guint width = (entrypthdr->coded_width + 15) >> 4; + guint height = (entrypthdr->coded_height + 15) >> 4; + + GST_DEBUG ("Parsing Frame header advanced %u", advhdr->interlace); + + /* Set the conveninence fields */ + framehdr->profile = seqhdr->profiletype; + framehdr->dquant = entrypthdr->dquant; + + if (advhdr->interlace) { + gint8 fcm = decode012 (br); + + if (fcm < 0) + goto failed; + + pic->fcm = (guint8) fcm; + } + + framehdr->ptype = get_unary (br, 0, 4); + + if (framehdr->ptype == GST_VC1_PICTURE_TYPE_SKIPPED) + goto failed; + + if (advhdr->tfcntrflag) { + READ_UINT8 (br, pic->tfcntr, 8); + GST_DEBUG ("tfcntr %u", pic->tfcntr); + } + + if (advhdr->pulldown) { + if (!advhdr->interlace || advhdr->psf) { + + READ_UINT8 (br, pic->rptfrm, 2); + GST_DEBUG ("rptfrm %u", pic->rptfrm); + + } else { + + READ_UINT8 (br, pic->tff, 1); + READ_UINT8 (br, pic->rff, 1); + GST_DEBUG ("tff %u, rff %u", pic->tff, pic->rff); + } + } + + if (entrypthdr->panscan_flag) { + READ_UINT8 (br, pic->ps_present, 1); + + if (pic->ps_present) { + guint i, nb_pan_scan_win = calculate_nb_pan_scan_win (advhdr, pic); + + if (gst_bit_reader_get_remaining (br) < 64 * nb_pan_scan_win) + goto failed; + + for (i = 0; i < nb_pan_scan_win; i++) { + pic->ps_hoffset = gst_bit_reader_get_bits_uint32_unchecked (br, 18); + pic->ps_voffset = gst_bit_reader_get_bits_uint32_unchecked (br, 18); + pic->ps_width = gst_bit_reader_get_bits_uint16_unchecked (br, 14); + pic->ps_height = gst_bit_reader_get_bits_uint16_unchecked (br, 14); + } + } + } + + READ_UINT8 (br, pic->rndctrl, 1); + + if (advhdr->interlace) { + READ_UINT8 (br, pic->uvsamp, 1); + GST_DEBUG ("uvsamp %u", pic->uvsamp); + } + + if (seqhdr->finterpflag) { + READ_UINT8 (br, framehdr->interpfrm, 1); + GST_DEBUG ("interpfrm %u", framehdr->interpfrm); + } + + if (framehdr->ptype == GST_VC1_PICTURE_TYPE_B) { + if (!decode_vlc (br, (guint *) & pic->bfraction, bfraction_vlc_table, + G_N_ELEMENTS (bfraction_vlc_table))) + goto failed; + + GST_DEBUG ("bfraction %u", pic->bfraction); + + if (pic->bfraction == GST_VC1_PICTURE_TYPE_BI) { + framehdr->ptype = GST_VC1_PICTURE_TYPE_BI; + } + + } + + READ_UINT8 (br, framehdr->pqindex, 5); + if (!framehdr->pqindex) + goto failed; + + /* compute pquant */ + if (entrypthdr->quantizer == GST_VC1_QUANTIZER_IMPLICITLY) + framehdr->pquant = vc1_pquant_table[0][framehdr->pqindex]; + else + framehdr->pquant = vc1_pquant_table[1][framehdr->pqindex]; + + framehdr->pquantizer = 1; + if (entrypthdr->quantizer == GST_VC1_QUANTIZER_IMPLICITLY) + framehdr->pquantizer = framehdr->pqindex < 9; + if (entrypthdr->quantizer == GST_VC1_QUANTIZER_NON_UNIFORM) + framehdr->pquantizer = 0; + + if (framehdr->pqindex <= 8) + READ_UINT8 (br, framehdr->halfqp, 1); + else + framehdr->halfqp = 0; + + if (entrypthdr->quantizer == GST_VC1_QUANTIZER_EXPLICITLY) { + READ_UINT8 (br, framehdr->pquantizer, 1); + } + + if (advhdr->postprocflag) + READ_UINT8 (br, pic->postproc, 2); + + GST_DEBUG ("Parsing %u picture, pqindex %u, pquant %u pquantizer %u" + "halfqp %u", framehdr->ptype, framehdr->pqindex, framehdr->pquant, + framehdr->pquantizer, framehdr->halfqp); + + switch (framehdr->ptype) { + case GST_VC1_PICTURE_TYPE_I: + case GST_VC1_PICTURE_TYPE_BI: + if (!bitplane_decoding (br, height, width, &pic->acpred)) + goto failed; + + if (entrypthdr->overlap && framehdr->pquant <= 8) { + pic->condover = decode012 (br); + + if (pic->condover == (guint8) - 1) + goto failed; + + else if (pic->condover == GST_VC1_CONDOVER_SELECT) { + + if (!bitplane_decoding (br, height, width, &pic->overflags)) + goto failed; + GST_DEBUG ("overflags %u", pic->overflags); + } + } + + framehdr->transacfrm = get_unary (br, 0, 2); + pic->transacfrm2 = get_unary (br, 0, 2); + READ_UINT8 (br, framehdr->transdctab, 1); + + if (framehdr->dquant) + parse_vopdquant (br, framehdr, framehdr->dquant); + + GST_DEBUG ("acpred %u, condover %u transacfrm %u transacfrm2 %u,", + pic->acpred, pic->condover, framehdr->transacfrm, pic->transacfrm2); + break; + + case GST_VC1_PICTURE_TYPE_B: + if (entrypthdr->extended_mv) + pic->mvrange = get_unary (br, 0, 3); + else + pic->mvrange = 0; + + READ_UINT8 (br, pic->mvmode, 1); + + if (!bitplane_decoding (br, height, width, &pic->directmb)) + goto failed; + + if (!bitplane_decoding (br, height, width, &pic->skipmb)) + goto failed; + + READ_UINT8 (br, pic->mvtab, 2); + READ_UINT8 (br, pic->cbptab, 2); + + if (framehdr->dquant) { + parse_vopdquant (br, framehdr, framehdr->dquant); + } + + if (entrypthdr->vstransform) { + READ_UINT8 (br, pic->ttmbf, 1); + + if (pic->ttmbf) { + READ_UINT8 (br, pic->ttfrm, 2); + } + } + + framehdr->transacfrm = get_unary (br, 0, 2); + READ_UINT8 (br, framehdr->transdctab, 1); + + GST_DEBUG ("transacfrm %u transdctab %u mvmode %u mvtab %u," + "cbptab %u directmb %u skipmb %u", framehdr->transacfrm, + framehdr->transdctab, pic->mvmode, pic->mvtab, pic->cbptab, + pic->directmb, pic->skipmb); + + break; + case GST_VC1_PICTURE_TYPE_P: + if (entrypthdr->extended_mv) + pic->mvrange = get_unary (br, 0, 3); + else + pic->mvrange = 0; + + mvmodeidx = framehdr->pquant > 12 ? 0 : 1; + pic->mvmode = mvmode_table[mvmodeidx][get_unary (br, 1, 4)]; + + if (pic->mvmode == GST_VC1_MVMODE_INTENSITY_COMP) { + + pic->mvmode2 = mvmode2_table[mvmodeidx][get_unary (br, 1, 4)]; + READ_UINT8 (br, pic->lumscale, 6); + READ_UINT8 (br, pic->lumshift, 6); + + GST_DEBUG ("lumscale %u lumshift %u", pic->lumscale, pic->lumshift); + } + + if (pic->mvmode == GST_VC1_MVMODE_MIXED_MV || + (pic->mvmode == GST_VC1_MVMODE_INTENSITY_COMP && + pic->mvmode2 == GST_VC1_MVMODE_MIXED_MV)) { + if (!bitplane_decoding (br, height, width, &pic->mvtypemb)) + goto failed; + GST_DEBUG ("mvtypemb %u", pic->mvtypemb); + } + + if (!bitplane_decoding (br, height, width, &pic->skipmb) || + gst_bit_reader_get_remaining (br) < 4) + goto failed; + + pic->mvtab = gst_bit_reader_get_bits_uint8_unchecked (br, 2); + pic->cbptab = gst_bit_reader_get_bits_uint8_unchecked (br, 2); + + if (framehdr->dquant) { + parse_vopdquant (br, framehdr, framehdr->dquant); + } + + if (entrypthdr->vstransform) { + READ_UINT8 (br, pic->ttmbf, 1); + + if (pic->ttmbf) { + READ_UINT8 (br, pic->ttfrm, 2); + } + } + + framehdr->transacfrm = get_unary (br, 0, 2); + READ_UINT8 (br, framehdr->transdctab, 1); + + GST_DEBUG ("transacfrm %u transdctab %u mvmode %u mvtab %u," + "cbptab %u skipmb %u", framehdr->transacfrm, framehdr->transdctab, + pic->mvmode, pic->mvtab, pic->cbptab, pic->skipmb); + + break; + } + + return GST_VC1_PARSER_OK; + +failed: + GST_WARNING ("Failed to parse frame header"); + + return GST_VC1_PARSER_ERROR; +} + +static GstVC1ParseResult +parse_frame_header (GstBitReader * br, GstVC1FrameHdr * framehdr, + GstVC1SeqHdr * seqhdr) +{ + guint8 mvmodeidx; + GstVC1PicSimpleMain *pic = &framehdr->pic.simple; + GstVC1SimpleMainSeqHdr *simplehdr = &seqhdr->profile.simplemain; + guint width = (simplehdr->coded_width + 15) >> 4; + guint height = (simplehdr->coded_height + 15) >> 4; + + + GST_DEBUG ("Parsing frame header in simple or main mode"); + + /* Set the conveninence fields */ + framehdr->profile = seqhdr->profiletype; + framehdr->dquant = simplehdr->dquant; + + framehdr->interpfrm = 0; + if (seqhdr->finterpflag) + READ_UINT8 (br, framehdr->interpfrm, 1); + + READ_UINT8 (br, pic->frmcnt, 2); + + pic->rangeredfrm = 0; + if (simplehdr->rangered) { + READ_UINT8 (br, pic->rangeredfrm, 2); + } + + /* Figuring out the picture type */ + READ_UINT8 (br, framehdr->ptype, 1); + if (simplehdr->maxbframes) { + if (!framehdr->ptype) { + READ_UINT8 (br, framehdr->ptype, 1); + + if (framehdr->ptype) + framehdr->ptype = GST_VC1_PICTURE_TYPE_I; + else + framehdr->ptype = GST_VC1_PICTURE_TYPE_B; + + } else + framehdr->ptype = GST_VC1_PICTURE_TYPE_P; + + } else { + if (framehdr->ptype) + framehdr->ptype = GST_VC1_PICTURE_TYPE_P; + else + framehdr->ptype = GST_VC1_PICTURE_TYPE_I; + } + + + if (framehdr->ptype == GST_VC1_PICTURE_TYPE_B) { + + if (!decode_vlc (br, (guint *) & pic->bfraction, bfraction_vlc_table, + G_N_ELEMENTS (bfraction_vlc_table))) + goto failed; + + if (pic->bfraction == GST_VC1_PICTURE_TYPE_BI) { + framehdr->ptype = GST_VC1_PICTURE_TYPE_BI; + } + GST_DEBUG ("bfraction= %d", pic->bfraction); + } + + if (framehdr->ptype == GST_VC1_PICTURE_TYPE_I || + framehdr->ptype == GST_VC1_PICTURE_TYPE_BI) + READ_UINT8 (br, pic->bf, 7); + + READ_UINT8 (br, framehdr->pqindex, 5); + if (!framehdr->pqindex) + return GST_VC1_PARSER_ERROR; + + GST_DEBUG ("pqindex %u", framehdr->pqindex); + + /* compute pquant */ + if (simplehdr->quantizer == GST_VC1_QUANTIZER_IMPLICITLY) + framehdr->pquant = vc1_pquant_table[0][framehdr->pqindex]; + else + framehdr->pquant = vc1_pquant_table[1][framehdr->pqindex]; + + GST_DEBUG ("pquant %u", framehdr->pquant); + + if (framehdr->pqindex <= 8) + READ_UINT8 (br, framehdr->halfqp, 1); + else + framehdr->halfqp = 0; + + /* Set pquantizer */ + framehdr->pquantizer = 1; + if (simplehdr->quantizer == GST_VC1_QUANTIZER_IMPLICITLY) + framehdr->pquantizer = framehdr->pqindex < 9; + else if (simplehdr->quantizer == GST_VC1_QUANTIZER_NON_UNIFORM) + framehdr->pquantizer = 0; + + if (simplehdr->quantizer == GST_VC1_QUANTIZER_EXPLICITLY) + READ_UINT8 (br, framehdr->pquantizer, 1); + + if (simplehdr->extended_mv == 1) { + pic->mvrange = get_unary (br, 0, 3); + GST_DEBUG ("mvrange %u", pic->mvrange); + } + + if (simplehdr->multires && (framehdr->ptype == GST_VC1_PICTURE_TYPE_P || + framehdr->ptype == GST_VC1_PICTURE_TYPE_I)) { + READ_UINT8 (br, pic->respic, 2); + GST_DEBUG ("Respic %u", pic->respic); + } + + GST_DEBUG ("Parsing %u Frame, pquantizer %u, halfqp %u, rangeredfrm %u, " + "interpfrm %u", framehdr->ptype, framehdr->pquantizer, framehdr->halfqp, + pic->rangeredfrm, framehdr->interpfrm); + + switch (framehdr->ptype) { + case GST_VC1_PICTURE_TYPE_I: + case GST_VC1_PICTURE_TYPE_BI: + framehdr->transacfrm = get_unary (br, 0, 2); + pic->transacfrm2 = get_unary (br, 0, 2); + READ_UINT8 (br, framehdr->transdctab, 1); + + GST_DEBUG ("transacfrm %u, transacfrm2 %u, transdctab %u", + framehdr->transacfrm, pic->transacfrm2, framehdr->transdctab); + break; + + case GST_VC1_PICTURE_TYPE_P: + mvmodeidx = framehdr->pquant > 12; + + pic->mvmode = mvmode_table[mvmodeidx][get_unary (br, 1, 4)]; + + if (pic->mvmode == GST_VC1_MVMODE_INTENSITY_COMP) { + pic->mvmode2 = mvmode2_table[mvmodeidx][get_unary (br, 1, 4)]; + READ_UINT8 (br, pic->lumscale, 6); + READ_UINT8 (br, pic->lumshift, 6); + GST_DEBUG ("lumscale %u lumshift %u", pic->lumscale, pic->lumshift); + } + + if (pic->mvmode == GST_VC1_MVMODE_MIXED_MV || + (pic->mvmode == GST_VC1_MVMODE_INTENSITY_COMP && + pic->mvmode2 == GST_VC1_MVMODE_MIXED_MV)) { + if (!bitplane_decoding (br, height, width, &pic->mvtypemb)) + goto failed; + GST_DEBUG ("mvtypemb %u", pic->mvtypemb); + } + if (!bitplane_decoding (br, height, width, &pic->skipmb)) + goto failed; + + READ_UINT8 (br, pic->mvtab, 2); + READ_UINT8 (br, pic->cbptab, 2); + + if (framehdr->dquant) { + parse_vopdquant (br, framehdr, framehdr->dquant); + } + + if (simplehdr->vstransform) { + READ_UINT8 (br, pic->ttmbf, 1); + GST_DEBUG ("ttmbf %u", pic->ttmbf); + + if (pic->ttmbf) { + READ_UINT8 (br, pic->ttfrm, 2); + GST_DEBUG ("ttfrm %u", pic->ttfrm); + } + } + + framehdr->transacfrm = get_unary (br, 0, 2); + READ_UINT8 (br, framehdr->transdctab, 1); + + GST_DEBUG ("transacfrm %u transdctab %u mvmode %u mvtab %u," + "cbptab %u skipmb %u", framehdr->transacfrm, framehdr->transdctab, + pic->mvmode, pic->mvtab, pic->cbptab, pic->skipmb); + break; + + case GST_VC1_PICTURE_TYPE_B: + READ_UINT8 (br, pic->mvmode, 1); + if (!bitplane_decoding (br, height, width, &pic->directmb)) + goto failed; + if (!bitplane_decoding (br, height, width, &pic->skipmb) == -1) + goto failed; + + READ_UINT8 (br, pic->mvtab, 2); + READ_UINT8 (br, pic->cbptab, 2); + + if (framehdr->dquant) + parse_vopdquant (br, framehdr, framehdr->dquant); + + if (simplehdr->vstransform) { + READ_UINT8 (br, pic->ttmbf, 1); + + if (pic->ttmbf) { + READ_UINT8 (br, pic->ttfrm, 2); + } + } + + framehdr->transacfrm = get_unary (br, 0, 2); + READ_UINT8 (br, framehdr->transdctab, 1); + + GST_DEBUG ("transacfrm %u transdctab %u mvmode %u mvtab %u," + "cbptab %u directmb %u skipmb %u", framehdr->transacfrm, + framehdr->transdctab, pic->mvmode, pic->mvtab, pic->cbptab, + pic->directmb, pic->skipmb); + + break; + } + + return GST_VC1_PARSER_OK; + +failed: + GST_WARNING ("Failed to parse Simple picture header"); + + return GST_VC1_PARSER_ERROR; +} + +/**** API ****/ +/** + * gst_vc1_identify_next_bdu: + * @data: The data to parse + * @size: the size of @data + * @bdu: (out): The #GstVC1BDU where to store parsed bdu headers + * + * Parses @data and fills @bdu fields + * + * Returns: a #GstVC1ParseResult + */ +GstVC1ParseResult +gst_vc1_identify_next_bdu (const guint8 * data, gsize size, GstVC1BDU * bdu) +{ + gint off1, off2; + + g_return_val_if_fail (bdu != NULL, GST_VC1_PARSER_ERROR); + + ensure_debug_category (); + + if (size <= 4) { + GST_DEBUG ("Can't parse, buffer is to small size %" G_GSSIZE_FORMAT, size); + return GST_VC1_PARSER_ERROR; + } + + off1 = scan_for_start_codes (data, size); + + if (off1 < 0) { + GST_DEBUG ("No start code prefix in this buffer"); + return GST_VC1_PARSER_NO_BDU; + } + + bdu->sc_offset = off1; + + bdu->offset = off1 + 4; + bdu->data = (guint8 *) data; + bdu->type = (GstVC1StartCode) (data[bdu->offset - 1]); + + off2 = scan_for_start_codes (data + bdu->offset, size - bdu->offset); + if (off2 < 0) { + GST_DEBUG ("Bdu start %d, No end found", bdu->offset); + + return GST_VC1_PARSER_NO_BDU_END; + } + + if (off2 > 0 && data[bdu->offset + off2 - 1] == 00) + off2--; + + bdu->size = off2; + + GST_DEBUG ("Complete bdu found. Off: %d, Size: %d", bdu->offset, bdu->size); + return GST_VC1_PARSER_OK; +} + +/** + * gst_vc1_parse_sequence_header: + * @data: The data to parse + * @size: the size of @data + * @seqhdr: The #GstVC1SeqHdr to set. + * + * Parses @data, and fills @seqhdr fields. + * + * Returns: a #GstVC1ParseResult + */ +GstVC1ParseResult +gst_vc1_parse_sequence_header (const guint8 * data, gsize size, + GstVC1SeqHdr * seqhdr) +{ + GstBitReader br; + guint8 old_interlaced_mode; + GstVC1SimpleMainSeqHdr *simplehdr = &seqhdr->profile.simplemain; + + g_return_val_if_fail (seqhdr != NULL, GST_VC1_PARSER_ERROR); + + ensure_debug_category (); + + gst_bit_reader_init (&br, data, size); + + READ_UINT8 (&br, seqhdr->profiletype, 2); + + if (seqhdr->profiletype == GST_VC1_PROFILE_ADVANCED) { + return parse_sequence_header_advanced (seqhdr, &br); + } + + GST_DEBUG ("Parsing sequence header in simple or main mode"); + + if (gst_bit_reader_get_remaining (&br) < 29) + goto failed; + + /* Reserved bits */ + old_interlaced_mode = gst_bit_reader_get_bits_uint8_unchecked (&br, 1); + if (old_interlaced_mode) + GST_WARNING ("Old interlaced mode used"); + + simplehdr->wmvp = gst_bit_reader_get_bits_uint8_unchecked (&br, 1); + if (simplehdr->wmvp) + GST_DEBUG ("WMVP mode"); + + seqhdr->frmrtq_postproc = gst_bit_reader_get_bits_uint8_unchecked (&br, 3); + seqhdr->bitrtq_postproc = gst_bit_reader_get_bits_uint8_unchecked (&br, 5); + simplehdr->loop_filter = gst_bit_reader_get_bits_uint8_unchecked (&br, 1); + + /* Skipping reserved3 bit */ + gst_bit_reader_skip_unchecked (&br, 1); + + simplehdr->multires = gst_bit_reader_get_bits_uint8_unchecked (&br, 1); + + /* Skipping reserved4 bit */ + gst_bit_reader_skip_unchecked (&br, 1); + + simplehdr->fastuvmc = gst_bit_reader_get_bits_uint8_unchecked (&br, 1); + simplehdr->extended_mv = gst_bit_reader_get_bits_uint8_unchecked (&br, 1); + simplehdr->dquant = gst_bit_reader_get_bits_uint8_unchecked (&br, 2); + simplehdr->vstransform = gst_bit_reader_get_bits_uint8_unchecked (&br, 1); + + /* Skipping reserved5 bit */ + gst_bit_reader_skip_unchecked (&br, 1); + + simplehdr->overlap = gst_bit_reader_get_bits_uint8_unchecked (&br, 1); + simplehdr->syncmarker = gst_bit_reader_get_bits_uint8_unchecked (&br, 1); + simplehdr->rangered = gst_bit_reader_get_bits_uint8_unchecked (&br, 1); + simplehdr->maxbframes = gst_bit_reader_get_bits_uint8_unchecked (&br, 3); + simplehdr->quantizer = gst_bit_reader_get_bits_uint8_unchecked (&br, 2); + seqhdr->finterpflag = gst_bit_reader_get_bits_uint8_unchecked (&br, 1); + + GST_DEBUG ("frmrtq_postproc %u, bitrtq_postproc %u, loop_filter %u, " + "multires %u, fastuvmc %u, extended_mv %u, dquant %u, vstransform %u, " + "overlap %u, syncmarker %u, rangered %u, maxbframes %u, quantizer %u, " + "finterpflag %u", seqhdr->frmrtq_postproc, seqhdr->bitrtq_postproc, + simplehdr->loop_filter, simplehdr->multires, simplehdr->fastuvmc, + simplehdr->extended_mv, simplehdr->dquant, simplehdr->vstransform, + simplehdr->overlap, simplehdr->syncmarker, simplehdr->rangered, + simplehdr->maxbframes, simplehdr->quantizer, seqhdr->finterpflag); + + if (simplehdr->wmvp) { + if (gst_bit_reader_get_remaining (&br) < 29) + goto failed; + + simplehdr->coded_width = gst_bit_reader_get_bits_uint16_unchecked (&br, 11); + simplehdr->coded_height = + gst_bit_reader_get_bits_uint16_unchecked (&br, 11); + simplehdr->framerate = gst_bit_reader_get_bits_uint8_unchecked (&br, 5); + gst_bit_reader_skip_unchecked (&br, 1); + simplehdr->slice_code = gst_bit_reader_get_bits_uint8_unchecked (&br, 1); + + GST_DEBUG ("coded_width %u, coded_height %u, framerate %u slice_code %u", + simplehdr->coded_width, simplehdr->coded_height, simplehdr->framerate, + simplehdr->slice_code); + } + + return GST_VC1_PARSER_OK; + +failed: + GST_WARNING ("Failed to parse sequence header"); + + return GST_VC1_PARSER_ERROR; +} + +/** + * gst_vc1_parse_entry_point_header: + * @data: The data to parse + * @size: the size of @data + * @entrypoint: (out): The #GstVC1EntryPointHdr to set. + * @seqhdr: The #GstVC1SeqHdr currently being parsed + * + * Parses @data, and sets @entrypoint fields. + * + * Returns: a #GstVC1EntryPointHdr + */ +GstVC1ParseResult +gst_vc1_parse_entry_point_header (const guint8 * data, gsize size, + GstVC1EntryPointHdr * entrypoint, GstVC1SeqHdr * seqhdr) +{ + GstBitReader br; + guint8 i; + GstVC1AdvancedSeqHdr *advanced = &seqhdr->profile.advanced; + + g_return_val_if_fail (entrypoint != NULL, GST_VC1_PARSER_ERROR); + + ensure_debug_category (); + + gst_bit_reader_init (&br, data, size); + + if (gst_bit_reader_get_remaining (&br) < 13) + goto failed; + + entrypoint->broken_link = gst_bit_reader_get_bits_uint8_unchecked (&br, 1); + entrypoint->closed_entry = gst_bit_reader_get_bits_uint8_unchecked (&br, 1); + entrypoint->panscan_flag = gst_bit_reader_get_bits_uint8_unchecked (&br, 1); + entrypoint->refdist_flag = gst_bit_reader_get_bits_uint8_unchecked (&br, 1); + entrypoint->loopfilter = gst_bit_reader_get_bits_uint8_unchecked (&br, 1); + entrypoint->fastuvmc = gst_bit_reader_get_bits_uint8_unchecked (&br, 1); + entrypoint->extended_mv = gst_bit_reader_get_bits_uint8_unchecked (&br, 1); + entrypoint->dquant = gst_bit_reader_get_bits_uint8_unchecked (&br, 2); + entrypoint->vstransform = gst_bit_reader_get_bits_uint8_unchecked (&br, 1); + entrypoint->overlap = gst_bit_reader_get_bits_uint8_unchecked (&br, 1); + entrypoint->quantizer = gst_bit_reader_get_bits_uint8_unchecked (&br, 2); + + if (advanced->hrd_param_flag) { + for (i = 0; i < seqhdr->profile.advanced.hrd_param.hrd_num_leaky_buckets; + i++) + READ_UINT8 (&br, entrypoint->hrd_full[MAX_HRD_NUM_LEAKY_BUCKETS], 8); + } + + READ_UINT8 (&br, entrypoint->coded_size_flag, 1); + if (entrypoint->coded_size_flag) { + READ_UINT16 (&br, entrypoint->coded_width, 12); + READ_UINT16 (&br, entrypoint->coded_height, 12); + entrypoint->coded_height = (entrypoint->coded_height + 1) << 1; + entrypoint->coded_width = (entrypoint->coded_width + 1) << 1; + } + + if (entrypoint->extended_mv) + READ_UINT8 (&br, entrypoint->extended_dmv, 1); + + READ_UINT8 (&br, entrypoint->range_mapy_flag, 1); + if (entrypoint->range_mapy_flag) + READ_UINT8 (&br, entrypoint->range_mapy, 3); + + READ_UINT8 (&br, entrypoint->range_mapuv_flag, 1); + if (entrypoint->range_mapy_flag) + READ_UINT8 (&br, entrypoint->range_mapuv, 3); + + advanced->entrypoint = *entrypoint; + + return GST_VC1_PARSER_OK; + +failed: + GST_WARNING ("Failed to parse entry point header"); + + return GST_VC1_PARSER_ERROR; +} + +/** + * gst_vc1_parse_frame_header: + * @data: The data to parse + * @size: the size of @data + * @entrypoint: The #GstVC1EntryPointHdr to set. + * @seqhdr: The #GstVC1SeqHdr currently being parsed + * + * Parses @data, and fills @entrypoint fields. + * + * Returns: a #GstVC1EntryPointHdr + */ +GstVC1ParseResult +gst_vc1_parse_frame_header (const guint8 * data, gsize size, + GstVC1FrameHdr * framehdr, GstVC1SeqHdr * seqhdr) +{ + GstBitReader br; + + ensure_debug_category (); + + gst_bit_reader_init (&br, data, size); + + if (seqhdr->profiletype == GST_VC1_PROFILE_ADVANCED) + return parse_frame_header_advanced (&br, framehdr, seqhdr); + else + return parse_frame_header (&br, framehdr, seqhdr); + +} diff --git a/gst-libs/gst/codecparsers/gstvc1parser.h b/gst-libs/gst/codecparsers/gstvc1parser.h new file mode 100644 index 000000000..511df6417 --- /dev/null +++ b/gst-libs/gst/codecparsers/gstvc1parser.h @@ -0,0 +1,468 @@ +/* Gstreamer + * Copyright (C) <2011> Intel + * Copyright (C) <2011> Collabora Ltd. + * Copyright (C) <2011> Thibault Saunier <thibault.saunier@collabora.com> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef __GST_VC1_PARSER_H__ +#define __GST_VC1_PARSER_H__ + +#ifndef GST_USE_UNSTABLE_API +#warning "The VC1 parsing library is unstable API and may change in future." +#warning "You can define GST_USE_UNSTABLE_API to avoid this warning." +#endif + +#include <gst/gst.h> + +G_BEGIN_DECLS + +#define MAX_HRD_NUM_LEAKY_BUCKETS 31 + +/** + * @GST_VC1_BFRACTION_BASIS: The @bfraction variable should be divided + * by this constant to have the actual value. + */ +#define GST_VC1_BFRACTION_BASIS 256 + +typedef enum { + GST_VC1_END_OF_SEQ = 0x0A, + GST_VC1_SLICE = 0x0B, + GST_VC1_FIELD = 0x0C, + GST_VC1_FRAME = 0x0D, + GST_VC1_ENTRYPOINT = 0x0E, + GST_VC1_SEQUENCE = 0x0F, + GST_VC1_SLICE_USER = 0x1B, + GST_VC1_FIELD_USER = 0x1C, + GST_VC1_FRAME_USER = 0x1D, + GST_VC1_ENTRY_POINT_USER = 0x1E, + GST_VC1_SEQUENCE_USER = 0x1F +} GstVC1StartCode; + +typedef enum { + GST_VC1_PROFILE_SIMPLE, + GST_VC1_PROFILE_MAIN, + GST_VC1_PROFILE_RESERVED, + GST_VC1_PROFILE_ADVANCED +} GstVC1Profile; + +typedef enum { + GST_VC1_PARSER_OK, + GST_VC1_PARSER_BROKEN_DATA, + GST_VC1_PARSER_NO_BDU, + GST_VC1_PARSER_NO_BDU_END, + GST_VC1_PARSER_ERROR, +} GstVC1ParseResult; + +typedef enum +{ + GST_VC1_PICTURE_TYPE_P, + GST_VC1_PICTURE_TYPE_B, + GST_VC1_PICTURE_TYPE_I, + GST_VC1_PICTURE_TYPE_BI, + GST_VC1_PICTURE_TYPE_SKIPPED +} GstVC1PictureType; + +typedef enum +{ + GST_VC1_LEVEL_LOW = 0, /* Simple/Main profile low level */ + GST_VC1_LEVELMEDIUM = 1, /* Simple/Main profile medium level */ + GST_VC1_LEVELHIGH = 2, /* Main profile high level */ + + GST_VC1_LEVEL_L0 = 0, /* Advanced profile level 0 */ + GST_VC1_LEVEL_L1 = 1, /* Advanced profile level 1 */ + GST_VC1_LEVEL_L2 = 2, /* Advanced profile level 2 */ + GST_VC1_LEVEL_L3 = 3, /* Advanced profile level 3 */ + GST_VC1_LEVEL_L4 = 4, /* Advanced profile level 4 */ + + /* 5 to 7 reserved */ + GST_VC1_LEVEL_UNKNOWN = 255 /* Unknown profile */ +} GstVC1Level; + +typedef enum +{ + GST_VC1_QUANTIZER_IMPLICITLY, + GST_VC1_QUANTIZER_EXPLICITLY, + GST_VC1_QUANTIZER_NON_UNIFORM, + GST_VC1_QUANTIZER_UNIFORM +} GstVC1QuantizerSpec; + +typedef enum { + GST_VC1_DQPROFILE_FOUR_EDGES, + GST_VC1_DQPROFILE_DOUBLE_EDGES, + GST_VC1_DQPROFILE_SINGLE_EDGE, + GST_VC1_DQPROFILE_ALL_MBS +} GstVC1DQProfile; + +typedef enum { + GST_VC1_CONDOVER_NONE, + GST_VC1_CONDOVER_ALL, + GST_VC1_CONDOVER_SELECT +} GstVC1Condover; + +/** + * GstVC1MvMode: + * + */ +typedef enum +{ + GST_VC1_MVMODE_1MV_HPEL_BILINEAR, + GST_VC1_MVMODE_1MV, + GST_VC1_MVMODE_1MV_HPEL, + GST_VC1_MVMODE_MIXED_MV, + GST_VC1_MVMODE_INTENSITY_COMP +} GstVC1MvMode; + +typedef struct _GstVC1SeqHdr GstVC1SeqHdr; +typedef struct _GstVC1AdvancedSeqHdr GstVC1AdvancedSeqHdr; +typedef struct _GstVC1SimpleMainSeqHdr GstVC1SimpleMainSeqHdr; +typedef struct _GstVC1HrdParam GstVC1HrdParam; +typedef struct _GstVC1EntryPointHdr GstVC1EntryPointHdr; + +/* Pictures Structures */ +typedef struct _GstVC1FrameHdr GstVC1FrameHdr; +typedef struct _GstVC1PicAdvanced GstVC1PicAdvanced; +typedef struct _GstVC1PicSimpleMain GstVC1PicSimpleMain; +typedef struct _GstVC1Picture GstVC1Picture; + +typedef struct _GstVC1VopDquant GstVC1VopDquant; + +typedef struct _GstVC1BDU GstVC1BDU; + +struct _GstVC1HrdParam +{ + guint8 hrd_num_leaky_buckets; + guint8 bit_rate_exponent; + guint8 buffer_size_exponent; + guint16 hrd_rate[MAX_HRD_NUM_LEAKY_BUCKETS]; + guint16 hrd_buffer[MAX_HRD_NUM_LEAKY_BUCKETS]; +}; + +/** + * GstVC1SimpleMainSeqHdr: + * + * Structure for simple and main profile sequence headers specific parameters. + */ +struct _GstVC1SimpleMainSeqHdr +{ + guint8 res_sprite; + guint8 loop_filter; + guint8 multires; + guint8 fastuvmc; + guint8 extended_mv; + guint8 dquant; + guint8 vstransform; + guint8 overlap; + guint8 syncmarker; + guint8 rangered; + guint8 maxbframes; + guint8 quantizer; + + /* This should be filled by user if previously known */ + guint16 coded_width; + /* This should be filled by user if previously known */ + guint16 coded_height; + + /* Wmvp specific */ + guint8 wmvp; /* Specify if the stream is wmp or not */ + guint8 framerate; + guint8 slice_code; +}; + +/** + * GstVC1EntryPointHdr: + * + * Structure for entrypoint header, this will be used only in advanced profiles + */ +struct _GstVC1EntryPointHdr +{ + guint8 broken_link; + guint8 closed_entry; + guint8 panscan_flag; + guint8 refdist_flag; + guint8 loopfilter; + guint8 fastuvmc; + guint8 extended_mv; + guint8 dquant; + guint8 vstransform; + guint8 overlap; + guint8 quantizer; + guint8 coded_size_flag; + guint16 coded_width; + guint16 coded_height; + guint8 extended_dmv; + guint8 range_mapy_flag; + guint8 range_mapy; + guint8 range_mapuv_flag; + guint8 range_mapuv; + + guint8 hrd_full[MAX_HRD_NUM_LEAKY_BUCKETS]; +}; + +/** + * GstVC1AdvancedSeqHdr: + * + * Structure for the advanced profile sequence headers specific parameters. + */ +struct _GstVC1AdvancedSeqHdr +{ + guint8 level; + guint8 postprocflag; + guint16 max_coded_width; + guint16 max_coded_height; + guint8 pulldown; + guint8 interlace; + guint8 tfcntrflag; + guint8 psf; + guint8 display_ext; + guint16 disp_horiz_size; + guint16 disp_vert_size; + guint8 aspect_ratio_flag; + guint8 aspect_ratio; + guint8 aspect_horiz_size; + guint8 aspect_vert_size; + guint8 framerate_flag; + guint8 framerateind; + guint8 frameratenr; + guint8 frameratedr; + guint16 framerateexp; + guint8 color_format_flag; + guint8 color_prim; + guint8 transfer_char; + guint8 matrix_coef; + guint8 hrd_param_flag; + + GstVC1HrdParam hrd_param; + + /* The last parsed entry point */ + GstVC1EntryPointHdr entrypoint; +}; + +/** + * GstVC1SeqHdr: + * + * Structure for sequence headers in any profile. + */ +struct _GstVC1SeqHdr +{ + guint8 profiletype; + guint8 colordiff_format; + guint8 frmrtq_postproc; + guint8 bitrtq_postproc; + guint8 finterpflag; + + /* calculated */ + guint framerate; /* Around in fps, 0 if unknown*/ + guint bitrate; /* Around in kpbs, 0 if unknown*/ + + union { + GstVC1AdvancedSeqHdr advanced; + GstVC1SimpleMainSeqHdr simplemain; + } profile; + +}; + +/** + * GstVC1PicSimpleMain: + * @bfaction: Should be divided by #GST_VC1_BFRACTION_BASIS + * to get the real value. + */ +struct _GstVC1PicSimpleMain +{ + guint8 frmcnt; + guint8 mvrange; + guint8 rangeredfrm; + + /* I and P pic simple and main profiles only */ + guint8 respic; + + /* I and BI pic simple and main profiles only */ + guint8 transacfrm2; + guint8 bf; + + /* B and P pic simple and main profiles only */ + guint8 mvmode; + guint8 mvtab; + guint8 ttmbf; + + /* P pic simple and main profiles only */ + guint8 mvmode2; + guint8 lumscale; + guint8 lumshift; + + guint8 cbptab; + guint8 ttfrm; + + /* B and BI picture only + * Should be divided by #GST_VC1_BFRACTION_BASIS + * to get the real value. */ + guint8 bfraction; + + /* Biplane value, those fields only mention the fact + * that the bitplane is in raw mode or not */ + guint8 mvtypemb; + guint8 skipmb; + guint8 directmb; /* B pic main profile only */ +}; + +/** + * GstVC1PicAdvanced: + * @bfaction: Should be divided by #GST_VC1_BFRACTION_BASIS + * to get the real value. + */ +struct _GstVC1PicAdvanced +{ + guint8 fcm; + guint8 tfcntr; + + guint8 rptfrm; + guint8 tff; + guint8 rff; + guint8 ps_present; + guint32 ps_hoffset; + guint32 ps_voffset; + guint16 ps_width; + guint16 ps_height; + guint8 rndctrl; + guint8 uvsamp; + guint8 postproc; + + /* B and P picture specific */ + guint8 mvrange; + guint8 mvmode; + guint8 mvtab; + guint8 cbptab; + guint8 ttmbf; + guint8 ttfrm; + + /* B and BI picture only + * Should be divided by #GST_VC1_BFRACTION_BASIS + * to get the real value. */ + guint8 bfraction; + + /* ppic */ + guint8 mvmode2; + guint8 lumscale; + guint8 lumshift; + + /* bipic */ + guint8 bf; + guint8 condover; + guint8 transacfrm2; + + /* Biplane value, those fields only mention the fact + * that the bitplane is in raw mode or not */ + guint8 acpred; + guint8 overflags; + guint8 mvtypemb; + guint8 skipmb; + guint8 directmb; +}; + + +struct _GstVC1VopDquant +{ + guint8 pqdiff; + guint8 abspq; + + + /* if dqant != 2*/ + guint8 dquantfrm; + guint8 dqprofile; + + /* if dqprofile == GST_VC1_DQPROFILE_SINGLE_EDGE + * or GST_VC1_DQPROFILE_DOUBLE_EDGE:*/ + guint8 dqsbedge; + + /* if dqprofile == GST_VC1_DQPROFILE_SINGLE_EDGE + * or GST_VC1_DQPROFILE_DOUBLE_EDGE:*/ + guint8 dqbedge; + + /* if dqprofile == GST_VC1_DQPROFILE_ALL_MBS */ + guint8 dqbilevel; + +}; + +/** + * GstVC1FrameHdr: + * + * Structure that represent picture in any profile or mode. + * You should look at @ptype and @profile to know what is currently + * in use. + */ +struct _GstVC1FrameHdr +{ + /* common fields */ + guint8 ptype; + guint8 interpfrm; + guint8 halfqp; + guint8 transacfrm; + guint8 transdctab; + guint8 pqindex; + guint8 pquantizer; + + /* Computed */ + guint8 pquant; + + /* Convenience fields */ + guint8 profile; + guint8 dquant; + + /* If dquant */ + GstVC1VopDquant vopdquant; + + union { + GstVC1PicSimpleMain simple; + GstVC1PicAdvanced advanced; + } pic; +}; + +/** + * GstVC1BDU: + * + * Structure that represents a Bitstream Data Unit. + */ +struct _GstVC1BDU +{ + GstVC1StartCode type; + guint size; + guint sc_offset; + guint offset; + guint8 * data; +}; + +GstVC1ParseResult gst_vc1_identify_next_bdu (const guint8 *data, + gsize size, + GstVC1BDU *bdu); + + +GstVC1ParseResult gst_vc1_parse_sequence_header (const guint8 *data, + gsize size, + GstVC1SeqHdr * seqhdr); + +GstVC1ParseResult gst_vc1_parse_entry_point_header (const guint8 *data, + gsize size, + GstVC1EntryPointHdr * entrypoint, + GstVC1SeqHdr *seqhdr); + +GstVC1ParseResult gst_vc1_parse_frame_header (const guint8 *data, + gsize size, + GstVC1FrameHdr * framehdr, + GstVC1SeqHdr *seqhdr); + +G_END_DECLS +#endif diff --git a/gst-plugins-bad.spec.in b/gst-plugins-bad.spec.in index adbd33df6..eac41e081 100644 --- a/gst-plugins-bad.spec.in +++ b/gst-plugins-bad.spec.in @@ -227,7 +227,6 @@ make ERROR_CFLAGS='' ERROR_CXXFLAGS='' %{_libdir}/gstreamer-%{majorminor}/libgsth264parse.so %{_libdir}/gstreamer-%{majorminor}/libgsthdvparse.so %{_libdir}/gstreamer-%{majorminor}/libgstid3tag.so -%{_libdir}/gstreamer-%{majorminor}/libgstinvtelecine.so %{_libdir}/gstreamer-%{majorminor}/libgstivfparse.so %{_libdir}/gstreamer-%{majorminor}/libgstjpegformat.so %{_libdir}/gstreamer-%{majorminor}/libgstlegacyresample.so @@ -274,9 +273,13 @@ make ERROR_CFLAGS='' ERROR_CXXFLAGS='' %{_libdir}/gstreamer-%{majorminor}/libgstvideofiltersbad.so %{_libdir}/gstreamer-%{majorminor}/libgstvideoparsersbad.so %{_libdir}/gstreamer-%{majorminor}/libgsty4mdec.so -%{_libdir}/gstreamer-%{majorminor}//libgstopenal.so +%{_libdir}/gstreamer-%{majorminor}/libgstopenal.so %{_libdir}/libgstbasecamerabinsrc-%{majorminor}.so.0 %{_libdir}/libgstbasecamerabinsrc-%{majorminor}.so.0.0.0 +%{_libdir}/gstreamer-%{majorminor}/libgstaudiovisualizers.so +%{_libdir}/gstreamer-%{majorminor}/libgstfaceoverlay.so +%{_libdir}/gstreamer-%{majorminor}/libgstinter.so +%{_libdir}/gstreamer-%{majorminor}/libgstremovesilence.so # System (Linux) specific plugins %{_libdir}/gstreamer-%{majorminor}/libgstdvb.so @@ -343,10 +346,12 @@ make ERROR_CFLAGS='' ERROR_CXXFLAGS='' # pkg-config files %{_libdir}/pkgconfig/gstreamer-plugins-bad-%{majorminor}.pc +%{_libdir}/pkgconfig/gstreamer-codecparsers-0.10.pc %files devel-docs %defattr(-,root,root,-) %doc %{_datadir}/gtk-doc/html/gst-plugins-bad-plugins-%{majorminor} +%doc %{_datadir}/gtk-doc/html/gst-plugins-bad-libs-%{majorminor} %changelog * Thu May 19 2011 Christian Schaller <christian.schaller@collabora.co.uk> diff --git a/gst/camerabin2/gstcamerabin2.c b/gst/camerabin2/gstcamerabin2.c index 1caa16404..5a227138e 100644 --- a/gst/camerabin2/gstcamerabin2.c +++ b/gst/camerabin2/gstcamerabin2.c @@ -166,9 +166,15 @@ #include <gst/gst-i18n-plugin.h> #include <gst/pbutils/pbutils.h> +#if GLIB_CHECK_VERSION(2,29,6) +#define gst_camerabin2_atomic_int_add g_atomic_int_add +#else +#define gst_camerabin2_atomic_int_add g_atomic_int_exchange_and_add +#endif + #define GST_CAMERA_BIN2_PROCESSING_INC(c) \ { \ - gint bef = g_atomic_int_exchange_and_add (&c->processing_counter, 1); \ + gint bef = gst_camerabin2_atomic_int_add (&c->processing_counter, 1); \ if (bef == 0) \ g_object_notify (G_OBJECT (c), "idle"); \ GST_DEBUG_OBJECT ((c), "Processing counter incremented to: %d", \ @@ -374,11 +380,6 @@ gst_camera_bin_start_capture (GstCameraBin2 * camerabin) if (camerabin->audio_src) { GstClock *clock = gst_pipeline_get_clock (GST_PIPELINE_CAST (camerabin)); - /* FIXME We need to set audiosrc to null to make it resync the ringbuffer - * while bug https://bugzilla.gnome.org/show_bug.cgi?id=648359 isn't - * fixed */ - gst_element_set_state (camerabin->audio_src, GST_STATE_NULL); - /* need to reset eos status (pads could be flushing) */ gst_element_set_state (camerabin->audio_capsfilter, GST_STATE_READY); gst_element_set_state (camerabin->audio_volume, GST_STATE_READY); @@ -446,6 +447,14 @@ gst_camera_bin_stop_capture (GstCameraBin2 * camerabin) if (camerabin->mode == MODE_VIDEO && camerabin->audio_src) { camerabin->audio_drop_eos = FALSE; gst_element_send_event (camerabin->audio_src, gst_event_new_eos ()); + + /* FIXME We need to set audiosrc to null to make it resync the ringbuffer + * while bug https://bugzilla.gnome.org/show_bug.cgi?id=648359 isn't + * fixed. + * + * Also, we set to NULL here to stop capturing audio through to the next + * video mode start capture. */ + gst_element_set_state (camerabin->audio_src, GST_STATE_NULL); } } @@ -485,7 +494,12 @@ gst_camera_bin_src_notify_readyforcapture (GObject * obj, GParamSpec * pspec, GST_DEBUG_OBJECT (camera, "Switching videobin location to %s", location); g_object_set (camera->videosink, "location", location, NULL); g_free (location); - gst_element_set_state (camera->videosink, GST_STATE_PLAYING); + if (gst_element_set_state (camera->videosink, GST_STATE_PLAYING) == + GST_STATE_CHANGE_FAILURE) { + /* Resets the latest state change return, that would be a failure + * and could cause problems in a camerabin2 state change */ + gst_element_set_state (camera->videosink, GST_STATE_NULL); + } gst_element_set_state (camera->video_encodebin, GST_STATE_PLAYING); gst_element_set_state (camera->videobin_capsfilter, GST_STATE_PLAYING); } @@ -916,6 +930,8 @@ gst_camera_bin_handle_message (GstBin * bin, GstMessage * message) if (gst_structure_has_name (structure, "GstMultiFileSink")) { GST_CAMERA_BIN2_PROCESSING_DEC (GST_CAMERA_BIN2_CAST (bin)); filename = gst_structure_get_string (structure, "filename"); + GST_DEBUG_OBJECT (bin, "Got file save message from multifilesink, " + "image %s has been saved", filename); if (filename) { gst_image_capture_bin_post_image_done (GST_CAMERA_BIN2_CAST (bin), filename); @@ -930,6 +946,8 @@ gst_camera_bin_handle_message (GstBin * bin, GstMessage * message) gst_message_parse_warning (message, &err, &debug); if (err->domain == GST_RESOURCE_ERROR) { /* some capturing failed */ + GST_WARNING_OBJECT (bin, "Capture failed, reason: %s - %s", + err->message, debug); GST_CAMERA_BIN2_PROCESSING_DEC (GST_CAMERA_BIN2_CAST (bin)); } } @@ -1152,6 +1170,17 @@ gst_camera_bin_src_notify_max_zoom_cb (GObject * self, GParamSpec * pspec, g_object_notify (G_OBJECT (camera), "max-zoom"); } +static void +gst_camera_bin_src_notify_zoom_cb (GObject * self, GParamSpec * pspec, + gpointer user_data) +{ + GstCameraBin2 *camera = (GstCameraBin2 *) user_data; + + g_object_get (self, "zoom", &camera->zoom, NULL); + GST_DEBUG_OBJECT (camera, "Zoom updated to %f", camera->zoom); + g_object_notify (G_OBJECT (camera), "zoom"); +} + static gboolean gst_camera_bin_image_src_buffer_probe (GstPad * pad, GstBuffer * buf, gpointer data) @@ -1208,7 +1237,12 @@ gst_camera_bin_image_sink_event_probe (GstPad * pad, GstEvent * event, GST_DEBUG_OBJECT (camerabin, "Setting filename to imagesink: %s", filename); g_object_set (camerabin->imagesink, "location", filename, NULL); - gst_element_set_state (camerabin->imagesink, GST_STATE_PLAYING); + if (gst_element_set_state (camerabin->imagesink, GST_STATE_PLAYING) == + GST_STATE_CHANGE_FAILURE) { + /* Resets the latest state change return, that would be a failure + * and could cause problems in a camerabin2 state change */ + gst_element_set_state (camerabin->imagesink, GST_STATE_NULL); + } } } break; @@ -1495,6 +1529,8 @@ gst_camera_bin_create_elements (GstCameraBin2 * camera) "preview-caps", camera->preview_caps, "preview-filter", camera->preview_filter, NULL); } + g_signal_connect (G_OBJECT (camera->src), "notify::zoom", + (GCallback) gst_camera_bin_src_notify_zoom_cb, camera); g_object_set (camera->src, "zoom", camera->zoom, NULL); g_signal_connect (G_OBJECT (camera->src), "notify::max-zoom", (GCallback) gst_camera_bin_src_notify_max_zoom_cb, camera); diff --git a/gst/hls/gsthlsdemux.c b/gst/hls/gsthlsdemux.c index 143f36387..ad29f7837 100644 --- a/gst/hls/gsthlsdemux.c +++ b/gst/hls/gsthlsdemux.c @@ -1,6 +1,9 @@ /* GStreamer * Copyright (C) 2010 Marc-Andre Lureau <marcandre.lureau@gmail.com> * Copyright (C) 2010 Andoni Morales Alastruey <ylatuya@gmail.com> + * Copyright (C) 2011, Hewlett-Packard Development Company, L.P. + * Author: Youness Alaoui <youness.alaoui@collabora.co.uk>, Collabora Ltd. + * Author: Sebastian Dröge <sebastian.droege@collabora.co.uk>, Collabora Ltd. * * Gsthlsdemux.c: * @@ -310,6 +313,7 @@ gst_hls_demux_change_state (GstElement * element, GstStateChange transition) case GST_STATE_CHANGE_PAUSED_TO_READY: demux->cancelled = TRUE; gst_hls_demux_stop (demux); + gst_task_join (demux->task); gst_hls_demux_reset (demux, FALSE); break; default: @@ -406,7 +410,8 @@ gst_hls_demux_src_event (GstPad * pad, GstEvent * event) GST_M3U8_CLIENT_LOCK (demux->client); GST_DEBUG_OBJECT (demux, "seeking to sequence %d", current_sequence); demux->client->sequence = current_sequence; - demux->position = start; + gst_m3u8_client_get_current_position (demux->client, &demux->position); + demux->position_shift = start - demux->position; demux->need_segment = TRUE; GST_M3U8_CLIENT_UNLOCK (demux->client); @@ -462,6 +467,7 @@ gst_hls_demux_sink_event (GstPad * pad, GstEvent * event) playlist = gst_hls_src_buf_to_utf8_playlist ((gchar *) GST_BUFFER_DATA (demux->playlist), GST_BUFFER_SIZE (demux->playlist)); gst_buffer_unref (demux->playlist); + demux->playlist = NULL; if (playlist == NULL) { GST_WARNING_OBJECT (demux, "Error validating first playlist."); } else if (!gst_m3u8_client_update (demux->client, playlist)) { @@ -573,9 +579,7 @@ gst_hls_demux_fetcher_sink_event (GstPad * pad, GstEvent * event) GST_DEBUG_OBJECT (demux, "Got EOS on the fetcher pad"); /* signal we have fetched the URI */ if (!demux->cancelled) { - g_mutex_lock (demux->fetcher_lock); g_cond_broadcast (demux->fetcher_cond); - g_mutex_unlock (demux->fetcher_lock); } } default: @@ -665,7 +669,7 @@ gst_hls_demux_stop (GstHLSDemux * demux) g_mutex_lock (demux->fetcher_lock); gst_hls_demux_stop_fetcher_locked (demux, TRUE); g_mutex_unlock (demux->fetcher_lock); - gst_task_join (demux->task); + gst_task_stop (demux->task); gst_hls_demux_stop_update (demux); } @@ -748,13 +752,15 @@ gst_hls_demux_loop (GstHLSDemux * demux) demux->need_segment = TRUE; } if (demux->need_segment) { + GstClockTime start = demux->position + demux->position_shift; /* And send a newsegment */ - GST_DEBUG_OBJECT (demux, "Sending new-segment. Segment start:%" - GST_TIME_FORMAT, GST_TIME_ARGS (demux->position)); + GST_DEBUG_OBJECT (demux, "Sending new-segment. segment start:%" + GST_TIME_FORMAT, GST_TIME_ARGS (start)); gst_pad_push_event (demux->srcpad, - gst_event_new_new_segment (FALSE, 1.0, GST_FORMAT_TIME, demux->position, - GST_CLOCK_TIME_NONE, demux->position)); + gst_event_new_new_segment (FALSE, 1.0, GST_FORMAT_TIME, + start, GST_CLOCK_TIME_NONE, start)); demux->need_segment = FALSE; + demux->position_shift = 0; } if (GST_CLOCK_TIME_IS_VALID (GST_BUFFER_DURATION (buf))) @@ -883,6 +889,7 @@ gst_hls_demux_reset (GstHLSDemux * demux, gboolean dispose) g_queue_clear (demux->queue); demux->position = 0; + demux->position_shift = 0; demux->need_segment = TRUE; } @@ -1034,6 +1041,7 @@ gst_hls_demux_cache_fragments (GstHLSDemux * demux) demux->client->sequence -= demux->fragments_cache; else demux->client->sequence = 0; + gst_m3u8_client_get_current_position (demux->client, &demux->position); GST_M3U8_CLIENT_UNLOCK (demux->client); } else { GstClockTime duration = gst_m3u8_client_get_duration (demux->client); diff --git a/gst/hls/gsthlsdemux.h b/gst/hls/gsthlsdemux.h index bac8ef317..a09a88b76 100644 --- a/gst/hls/gsthlsdemux.h +++ b/gst/hls/gsthlsdemux.h @@ -89,6 +89,7 @@ struct _GstHLSDemux /* Position in the stream */ GstClockTime position; + GstClockTime position_shift; gboolean need_segment; }; diff --git a/gst/hls/m3u8.c b/gst/hls/m3u8.c index c407d72d8..449b63ee9 100644 --- a/gst/hls/m3u8.c +++ b/gst/hls/m3u8.c @@ -468,13 +468,31 @@ _find_next (GstM3U8MediaFile * file, GstM3U8Client * client) return TRUE; } +void +gst_m3u8_client_get_current_position (GstM3U8Client * client, + GstClockTime * timestamp) +{ + GList *l; + GList *walk; + + l = g_list_find_custom (client->current->files, client, + (GCompareFunc) _find_next); + + *timestamp = 0; + for (walk = client->current->files; walk; walk = walk->next) { + if (walk == l) + break; + *timestamp += GST_M3U8_MEDIA_FILE (walk->data)->duration; + } + *timestamp *= GST_SECOND; +} + gboolean gst_m3u8_client_get_next_fragment (GstM3U8Client * client, gboolean * discontinuity, const gchar ** uri, GstClockTime * duration, GstClockTime * timestamp) { GList *l; - GList *walk; GstM3U8MediaFile *file; g_return_val_if_fail (client != NULL, FALSE); @@ -490,6 +508,8 @@ gst_m3u8_client_get_next_fragment (GstM3U8Client * client, return FALSE; } + gst_m3u8_client_get_current_position (client, timestamp); + file = GST_M3U8_MEDIA_FILE (l->data); *discontinuity = client->sequence != file->sequence; @@ -498,14 +518,6 @@ gst_m3u8_client_get_next_fragment (GstM3U8Client * client, *uri = file->uri; *duration = file->duration * GST_SECOND; - *timestamp = 0; - for (walk = client->current->files; walk; walk = walk->next) { - if (walk == l) - break; - *timestamp += GST_M3U8_MEDIA_FILE (walk->data)->duration; - } - *timestamp *= GST_SECOND; - GST_M3U8_CLIENT_UNLOCK (client); return TRUE; } diff --git a/gst/hls/m3u8.h b/gst/hls/m3u8.h index 8c83990f8..a428a67a4 100644 --- a/gst/hls/m3u8.h +++ b/gst/hls/m3u8.h @@ -84,6 +84,8 @@ void gst_m3u8_client_set_current (GstM3U8Client * client, GstM3U8 * m3u8); gboolean gst_m3u8_client_get_next_fragment (GstM3U8Client * client, gboolean * discontinuity, const gchar ** uri, GstClockTime * duration, GstClockTime * timestamp); +void gst_m3u8_client_get_current_position (GstM3U8Client * client, + GstClockTime * timestamp); GstClockTime gst_m3u8_client_get_duration (GstM3U8Client * client); GstClockTime gst_m3u8_client_get_target_duration (GstM3U8Client * client); const gchar *gst_m3u8_client_get_uri(GstM3U8Client * client); diff --git a/gst/mpegdemux/gstmpegtsdemux.c b/gst/mpegdemux/gstmpegtsdemux.c index 986914d0c..849cda0aa 100644 --- a/gst/mpegdemux/gstmpegtsdemux.c +++ b/gst/mpegdemux/gstmpegtsdemux.c @@ -417,7 +417,7 @@ gst_mpegts_demux_remove_pads (GstMpegTSDemux * demux) #endif -static guint32 crc_tab[256] = { +static const guint32 crc_tab[256] = { 0x00000000, 0x04c11db7, 0x09823b6e, 0x0d4326d9, 0x130476dc, 0x17c56b6b, 0x1a864db2, 0x1e475005, 0x2608edb8, 0x22c9f00f, 0x2f8ad6d6, 0x2b4bcb61, 0x350c9b64, 0x31cd86d3, 0x3c8ea00a, 0x384fbdbd, 0x4c11db70, 0x48d0c6c7, diff --git a/gst/mpegpsmux/psmux.c b/gst/mpegpsmux/psmux.c index 9d0493c1d..0a714d038 100644 --- a/gst/mpegpsmux/psmux.c +++ b/gst/mpegpsmux/psmux.c @@ -348,7 +348,7 @@ psmux_write_system_header (PsMux * mux) bits_write (&bw, 24, PSMUX_START_CODE_PREFIX); bits_write (&bw, 8, PSMUX_SYSTEM_HEADER); - bits_write (&bw, 16, len); /* header_length */ + bits_write (&bw, 16, len - 6); /* header_length (bytes after this field) */ bits_write (&bw, 1, 1); /* marker */ bits_write (&bw, 22, mux->rate_bound); /* rate_bound */ bits_write (&bw, 1, 1); /* marker */ diff --git a/gst/mpegtsdemux/mpegtsbase.c b/gst/mpegtsdemux/mpegtsbase.c index 5542abf02..437af9d78 100644 --- a/gst/mpegtsdemux/mpegtsbase.c +++ b/gst/mpegtsdemux/mpegtsbase.c @@ -1,7 +1,11 @@ /* - * mpegtsbase.c - + * mpegtsbase.c - * Copyright (C) 2007 Alessandro Decina * 2010 Edward Hervey + * Copyright (C) 2011, Hewlett-Packard Development Company, L.P. + * Author: Youness Alaoui <youness.alaoui@collabora.co.uk>, Collabora Ltd. + * Author: Sebastian Dröge <sebastian.droege@collabora.co.uk>, Collabora Ltd. + * Author: Edward Hervey <bilboed@bilboed.com>, Collabora Ltd. * * Authors: * Alessandro Decina <alessandro@nnva.org> diff --git a/gst/mpegtsdemux/mpegtsbase.h b/gst/mpegtsdemux/mpegtsbase.h index cce4e0fd7..872e77ee8 100644 --- a/gst/mpegtsdemux/mpegtsbase.h +++ b/gst/mpegtsdemux/mpegtsbase.h @@ -2,6 +2,9 @@ * mpegtsbase.h - GStreamer MPEG transport stream base class * Copyright (C) 2009 Edward Hervey <edward.hervey@collabora.co.uk> * 2007 Alessandro Decina + * Copyright (C) 2011, Hewlett-Packard Development Company, L.P. + * Author: Youness Alaoui <youness.alaoui@collabora.co.uk>, Collabora Ltd. + * Author: Sebastian Dröge <sebastian.droege@collabora.co.uk>, Collabora Ltd. * * Authors: * Alessandro Decina <alessandro@nnva.org> diff --git a/gst/mpegtsdemux/tsdemux.c b/gst/mpegtsdemux/tsdemux.c index 3a327a5cd..3facd6407 100644 --- a/gst/mpegtsdemux/tsdemux.c +++ b/gst/mpegtsdemux/tsdemux.c @@ -2,6 +2,10 @@ * tsdemux.c * Copyright (C) 2009 Zaheer Abbas Merali * 2010 Edward Hervey + * Copyright (C) 2011, Hewlett-Packard Development Company, L.P. + * Author: Youness Alaoui <youness.alaoui@collabora.co.uk>, Collabora Ltd. + * Author: Sebastian Dröge <sebastian.droege@collabora.co.uk>, Collabora Ltd. + * Author: Edward Hervey <bilboed@bilboed.com>, Collabora Ltd. * * Authors: * Zaheer Abbas Merali <zaheerabbas at merali dot org> diff --git a/gst/mpegvideoparse/mpegvideoparse.c b/gst/mpegvideoparse/mpegvideoparse.c index 2f4e96cec..52a34c10f 100644 --- a/gst/mpegvideoparse/mpegvideoparse.c +++ b/gst/mpegvideoparse/mpegvideoparse.c @@ -1027,7 +1027,7 @@ plugin_init (GstPlugin * plugin) "MPEG Video Parser"); return gst_element_register (plugin, "legacympegvideoparse", - GST_RANK_PRIMARY, GST_TYPE_MPEGVIDEOPARSE); + GST_RANK_NONE, GST_TYPE_MPEGVIDEOPARSE); } GST_PLUGIN_DEFINE (GST_VERSION_MAJOR, diff --git a/gst/pcapparse/Makefile.am b/gst/pcapparse/Makefile.am index 08a9d25ad..6c357f209 100644 --- a/gst/pcapparse/Makefile.am +++ b/gst/pcapparse/Makefile.am @@ -8,10 +8,10 @@ else endif libgstpcapparse_la_SOURCES = \ - gstpcapparse.c + gstpcapparse.c gstirtspparse.c plugin.c noinst_HEADERS = \ - gstpcapparse.h + gstpcapparse.h gstirtspparse.h libgstpcapparse_la_CFLAGS = $(GST_CFLAGS) $(GST_BASE_CFLAGS) libgstpcapparse_la_LIBADD = $(GST_LIBS) $(GST_BASE_LIBS) $(WINSOCK2_LIBS) diff --git a/gst/pcapparse/gstirtspparse.c b/gst/pcapparse/gstirtspparse.c new file mode 100644 index 000000000..26317e622 --- /dev/null +++ b/gst/pcapparse/gstirtspparse.c @@ -0,0 +1,255 @@ +/* GStreamer Interleaved RTSP parser + * Copyright (C) 2011 Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk> + * Copyright (C) 2011 Nokia Corporation. All rights reserved. + * Contact: Stefan Kost <stefan.kost@nokia.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. + */ +/** + * SECTION:element-irtspparse + * @short_description: Interleaved RTSP parser + * @see_also: #GstPcapParse + * + * This is an interleaved RTSP parser that allows extracting specific + * so-called "channels" from received interleaved (TCP) RTSP data + * (typically extracted from some network capture). + * + * <refsect2> + * <title>Example launch line</title> + * |[ + * gst-launch-0.10 filesrc location=h264crasher.pcap ! pcapparse ! irtspparse + * ! rtph264depay ! ffdec_h264 ! fakesink + * ]| Read from a pcap dump file using filesrc, extract the raw TCP packets, + * depayload and decode them. + * </refsect2> + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <string.h> + +#include "gstirtspparse.h" +#include <gst/base/gstbytereader.h> + +GST_DEBUG_CATEGORY_STATIC (irtsp_parse_debug); +#define GST_CAT_DEFAULT irtsp_parse_debug + +enum +{ + PROP_0, + PROP_CHANNEL_ID +}; + + +static GstStaticPadTemplate src_template = GST_STATIC_PAD_TEMPLATE ("src", + GST_PAD_SRC, + GST_PAD_ALWAYS, + GST_STATIC_CAPS ("application/x-rtp ; application/x-rtcp")); + +static GstStaticPadTemplate sink_template = GST_STATIC_PAD_TEMPLATE ("sink", + GST_PAD_SINK, + GST_PAD_ALWAYS, + GST_STATIC_CAPS_ANY); + +static void gst_irtsp_parse_finalize (GObject * object); + +static gboolean gst_irtsp_parse_start (GstBaseParse * parse); +static gboolean gst_irtsp_parse_stop (GstBaseParse * parse); +static gboolean gst_irtsp_parse_check_valid_frame (GstBaseParse * parse, + GstBaseParseFrame * frame, guint * size, gint * skipsize); +static GstFlowReturn gst_irtsp_parse_parse_frame (GstBaseParse * parse, + GstBaseParseFrame * frame); + +static void gst_irtsp_parse_set_property (GObject * object, + guint prop_id, const GValue * value, GParamSpec * pspec); +static void gst_irtsp_parse_get_property (GObject * object, + guint prop_id, GValue * value, GParamSpec * pspec); + +GST_BOILERPLATE (GstIRTSPParse, gst_irtsp_parse, GstBaseParse, + GST_TYPE_BASE_PARSE); + +static void +gst_irtsp_parse_base_init (gpointer klass) +{ + GstElementClass *element_class = GST_ELEMENT_CLASS (klass); + + gst_element_class_add_pad_template (element_class, + gst_static_pad_template_get (&sink_template)); + gst_element_class_add_pad_template (element_class, + gst_static_pad_template_get (&src_template)); + + gst_element_class_set_details_simple (element_class, "IRTSPParse", + "Raw/Parser", + "Parses a raw interleaved RTSP stream", + "Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>"); +} + +static void +gst_irtsp_parse_class_init (GstIRTSPParseClass * klass) +{ + GstBaseParseClass *parse_class = GST_BASE_PARSE_CLASS (klass); + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + GST_DEBUG_CATEGORY_INIT (irtsp_parse_debug, "irtspparse", 0, + "Interleaved RTSP stream parser"); + + object_class->finalize = gst_irtsp_parse_finalize; + + object_class->set_property = gst_irtsp_parse_set_property; + object_class->get_property = gst_irtsp_parse_get_property; + + g_object_class_install_property (object_class, PROP_CHANNEL_ID, + g_param_spec_int ("channel-id", "channel-id", + "Channel Identifier", 0, 255, + 0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + + parse_class->start = GST_DEBUG_FUNCPTR (gst_irtsp_parse_start); + parse_class->stop = GST_DEBUG_FUNCPTR (gst_irtsp_parse_stop); + parse_class->check_valid_frame = + GST_DEBUG_FUNCPTR (gst_irtsp_parse_check_valid_frame); + parse_class->parse_frame = GST_DEBUG_FUNCPTR (gst_irtsp_parse_parse_frame); +} + +static void +gst_irtsp_parse_reset (GstIRTSPParse * IRTSPParse) +{ +} + +static void +gst_irtsp_parse_init (GstIRTSPParse * IRTSPParse, GstIRTSPParseClass * klass) +{ + gst_base_parse_set_min_frame_size (GST_BASE_PARSE (IRTSPParse), 4); + gst_irtsp_parse_reset (IRTSPParse); +} + +static void +gst_irtsp_parse_finalize (GObject * object) +{ + G_OBJECT_CLASS (parent_class)->finalize (object); +} + +static gboolean +gst_irtsp_parse_start (GstBaseParse * parse) +{ + GstIRTSPParse *IRTSPParse = GST_IRTSP_PARSE (parse); + + GST_DEBUG_OBJECT (parse, "starting"); + + gst_irtsp_parse_reset (IRTSPParse); + + return TRUE; +} + +static gboolean +gst_irtsp_parse_stop (GstBaseParse * parse) +{ + GST_DEBUG_OBJECT (parse, "stopping"); + + return TRUE; +} + +static gboolean +gst_irtsp_parse_check_valid_frame (GstBaseParse * parse, + GstBaseParseFrame * frame, guint * framesize, gint * skipsize) +{ + GstIRTSPParse *IRTSPParse = GST_IRTSP_PARSE (parse); + GstBuffer *buf = frame->buffer; + GstByteReader reader = GST_BYTE_READER_INIT_FROM_BUFFER (buf); + gint off; + + if (G_UNLIKELY (GST_BUFFER_SIZE (buf) < 4)) + return FALSE; + + off = gst_byte_reader_masked_scan_uint32 (&reader, 0xffff0000, + 0x24000000 + (IRTSPParse->channel_id << 16), 0, GST_BUFFER_SIZE (buf)); + + GST_LOG_OBJECT (parse, "possible sync at buffer offset %d", off); + + /* didn't find anything that looks like a sync word, skip */ + if (off < 0) { + *skipsize = GST_BUFFER_SIZE (buf) - 3; + return FALSE; + } + + /* possible frame header, but not at offset 0? skip bytes before sync */ + if (off > 0) { + *skipsize = off; + return FALSE; + } + + *framesize = GST_READ_UINT16_BE (GST_BUFFER_DATA (frame->buffer) + 2) + 4; + GST_LOG_OBJECT (parse, "got frame size %d", *framesize); + + return TRUE; +} + +static GstFlowReturn +gst_irtsp_parse_parse_frame (GstBaseParse * parse, GstBaseParseFrame * frame) +{ + /* HACK HACK skip header. + * could also ask baseparse to skip this, + * but that would give us a discontinuity for free + * which is a bit too much to have on all our packets */ + GST_BUFFER_DATA (frame->buffer) += 4; + GST_BUFFER_SIZE (frame->buffer) -= 4; + + if (!GST_PAD_CAPS (GST_BASE_PARSE_SRC_PAD (parse))) { + GstCaps *caps; + + caps = gst_caps_new_simple ("application/x-rtp", NULL); + gst_pad_set_caps (GST_BASE_PARSE_SRC_PAD (parse), caps); + gst_caps_unref (caps); + } + + GST_BUFFER_FLAG_UNSET (frame->buffer, GST_BUFFER_FLAG_DISCONT); + + return GST_FLOW_OK; + +} + +static void +gst_irtsp_parse_set_property (GObject * object, + guint prop_id, const GValue * value, GParamSpec * pspec) +{ + GstIRTSPParse *IRTSPParse = GST_IRTSP_PARSE (object); + + switch (prop_id) { + case PROP_CHANNEL_ID: + IRTSPParse->channel_id = g_value_get_int (value); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +gst_irtsp_parse_get_property (GObject * object, + guint prop_id, GValue * value, GParamSpec * pspec) +{ + GstIRTSPParse *IRTSPParse = GST_IRTSP_PARSE (object); + + switch (prop_id) { + case PROP_CHANNEL_ID: + g_value_set_int (value, IRTSPParse->channel_id); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} diff --git a/gst/pcapparse/gstirtspparse.h b/gst/pcapparse/gstirtspparse.h new file mode 100644 index 000000000..a3d613f2a --- /dev/null +++ b/gst/pcapparse/gstirtspparse.h @@ -0,0 +1,70 @@ +/* GStreamer Interleaved RTSP parser + * Copyright (C) 2011 Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk> + * Copyright (C) 2011 Nokia Corporation. All rights reserved. + * Contact: Stefan Kost <stefan.kost@nokia.com> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef __GST_IRTSP_PARSE_H__ +#define __GST_IRTSP_PARSE_H__ + +#include <gst/gst.h> +#include <gst/base/gstbaseparse.h> + +G_BEGIN_DECLS + +#define GST_TYPE_IRTSP_PARSE \ + (gst_irtsp_parse_get_type()) +#define GST_IRTSP_PARSE(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST((obj), GST_TYPE_IRTSP_PARSE, GstIRTSPParse)) +#define GST_IRTSP_PARSE_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST((klass), GST_TYPE_IRTSP_PARSE, GstIRTSPParseClass)) +#define GST_IS_IRTSP_PARSE(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE((obj), GST_TYPE_IRTSP_PARSE)) +#define GST_IS_IRTSP_PARSE_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_TYPE((klass), GST_TYPE_IRTSP_PARSE)) + +typedef struct _GstIRTSPParse GstIRTSPParse; +typedef struct _GstIRTSPParseClass GstIRTSPParseClass; + +/** + * GstIRTSPParse: + * + * The opaque GstIRTSPParse object + */ +struct _GstIRTSPParse { + GstBaseParse baseparse; + + guint8 channel_id; + /*< private >*/ +}; + +/** + * GstIRTSPParseClass: + * @parent_class: Element parent class. + * + * The opaque GstIRTSPParseClass data structure. + */ +struct _GstIRTSPParseClass { + GstBaseParseClass baseparse_class; +}; + +GType gst_irtsp_parse_get_type (void); + +G_END_DECLS + +#endif /* __GST_IRTSP_PARSE_H__ */ diff --git a/gst/pcapparse/gstpcapparse.c b/gst/pcapparse/gstpcapparse.c index 596391667..16eb58c5a 100644 --- a/gst/pcapparse/gstpcapparse.c +++ b/gst/pcapparse/gstpcapparse.c @@ -607,17 +607,3 @@ gst_pcap_sink_event (GstPad * pad, GstEvent * event) return ret; } - - -static gboolean -plugin_init (GstPlugin * plugin) -{ - return gst_element_register (plugin, "pcapparse", - GST_RANK_NONE, GST_TYPE_PCAP_PARSE); -} - -GST_PLUGIN_DEFINE (GST_VERSION_MAJOR, - GST_VERSION_MINOR, - "pcapparse", - "Element parsing raw pcap streams", - plugin_init, VERSION, "LGPL", "GStreamer", "http://gstreamer.net/") diff --git a/gst/pcapparse/plugin.c b/gst/pcapparse/plugin.c new file mode 100644 index 000000000..d034e3d03 --- /dev/null +++ b/gst/pcapparse/plugin.c @@ -0,0 +1,44 @@ +/* + * Copyright 2007 Ole André Vadla RavnÃ¥s <ole.andre.ravnas@tandberg.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 "gstpcapparse.h" +#include "gstirtspparse.h" + +static gboolean +plugin_init (GstPlugin * plugin) +{ + gboolean ret; + + ret = gst_element_register (plugin, "pcapparse", + GST_RANK_NONE, GST_TYPE_PCAP_PARSE); + ret &= gst_element_register (plugin, "irtspparse", + GST_RANK_NONE, GST_TYPE_IRTSP_PARSE); + + return ret; +} + +GST_PLUGIN_DEFINE (GST_VERSION_MAJOR, + GST_VERSION_MINOR, + "pcapparse", + "Element parsing raw pcap streams", + plugin_init, VERSION, "LGPL", "GStreamer", "http://gstreamer.net/") diff --git a/gst/rtpvp8/Makefile.am b/gst/rtpvp8/Makefile.am index ef7425f1d..e1725bbb3 100644 --- a/gst/rtpvp8/Makefile.am +++ b/gst/rtpvp8/Makefile.am @@ -2,10 +2,12 @@ plugin_LTLIBRARIES = libgstrtpvp8.la libgstrtpvp8_la_SOURCES = gstrtpvp8.c \ gstrtpvp8depay.c \ - gstrtpvp8pay.c + gstrtpvp8pay.c \ + dboolhuff.c noinst_HEADERS = gstrtpvp8depay.h \ - gstrtpvp8pay.h + gstrtpvp8pay.h \ + dboolhuff.h libgstrtpvp8_la_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) \ $(GST_BASE_CFLAGS) $(GST_CFLAGS) diff --git a/gst/rtpvp8/dboolhuff.LICENSE b/gst/rtpvp8/dboolhuff.LICENSE new file mode 100644 index 000000000..7a6f99547 --- /dev/null +++ b/gst/rtpvp8/dboolhuff.LICENSE @@ -0,0 +1,30 @@ +Copyright (c) 2010, Google Inc. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + + * Neither the name of Google nor the names of its contributors may + be used to endorse or promote products derived from this software + without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + diff --git a/gst/rtpvp8/dboolhuff.c b/gst/rtpvp8/dboolhuff.c new file mode 100644 index 000000000..0e1fd6e2f --- /dev/null +++ b/gst/rtpvp8/dboolhuff.c @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2010 The WebM project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the dboolhuff.LICENSE file in this directory. + * See the libvpx original distribution for more information, + * including patent information, and author information. + */ + + +#include "dboolhuff.h" + +const unsigned char vp8_norm[256] __attribute__ ((aligned (16))) = { +0, 7, 6, 6, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + +int +vp8dx_start_decode (BOOL_DECODER * br, + const unsigned char *source, unsigned int source_sz) +{ + br->user_buffer_end = source + source_sz; + br->user_buffer = source; + br->value = 0; + br->count = -8; + br->range = 255; + + if (source_sz && !source) + return 1; + + /* Populate the buffer */ + vp8dx_bool_decoder_fill (br); + + return 0; +} + + +void +vp8dx_bool_decoder_fill (BOOL_DECODER * br) +{ + const unsigned char *bufptr; + const unsigned char *bufend; + VP8_BD_VALUE value; + int count; + bufend = br->user_buffer_end; + bufptr = br->user_buffer; + value = br->value; + count = br->count; + + VP8DX_BOOL_DECODER_FILL (count, value, bufptr, bufend); + + br->user_buffer = bufptr; + br->value = value; + br->count = count; +} diff --git a/gst/rtpvp8/dboolhuff.h b/gst/rtpvp8/dboolhuff.h new file mode 100644 index 000000000..41b0f5d9a --- /dev/null +++ b/gst/rtpvp8/dboolhuff.h @@ -0,0 +1,151 @@ +/* + * Copyright (c) 2010 The WebM project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the dboolhuff.LICENSE file in this directory. + * See the libvpx original distribution for more information, + * including patent information, and author information. + */ + + +#ifndef DBOOLHUFF_H +#define DBOOLHUFF_H +#include <stddef.h> +#include <limits.h> +#include <glib.h> + +typedef size_t VP8_BD_VALUE; + +# define VP8_BD_VALUE_SIZE ((int)sizeof(VP8_BD_VALUE)*CHAR_BIT) +/*This is meant to be a large, positive constant that can still be efficiently + loaded as an immediate (on platforms like ARM, for example). + Even relatively modest values like 100 would work fine.*/ +# define VP8_LOTS_OF_BITS (0x40000000) + +typedef struct +{ + const unsigned char *user_buffer_end; + const unsigned char *user_buffer; + VP8_BD_VALUE value; + int count; + unsigned int range; +} BOOL_DECODER; + +extern const unsigned char vp8_norm[256] __attribute__((aligned(16))); + +int vp8dx_start_decode(BOOL_DECODER *br, + const unsigned char *source, + unsigned int source_sz); + +void vp8dx_bool_decoder_fill(BOOL_DECODER *br); + +/*The refill loop is used in several places, so define it in a macro to make + sure they're all consistent. + An inline function would be cleaner, but has a significant penalty, because + multiple BOOL_DECODER fields must be modified, and the compiler is not smart + enough to eliminate the stores to those fields and the subsequent reloads + from them when inlining the function.*/ +#define VP8DX_BOOL_DECODER_FILL(_count,_value,_bufptr,_bufend) \ + do \ + { \ + int shift = VP8_BD_VALUE_SIZE - 8 - ((_count) + 8); \ + int loop_end, x; \ + size_t bits_left = ((_bufend)-(_bufptr))*CHAR_BIT; \ + \ + x = shift + CHAR_BIT - bits_left; \ + loop_end = 0; \ + if(x >= 0) \ + { \ + (_count) += VP8_LOTS_OF_BITS; \ + loop_end = x; \ + if(!bits_left) break; \ + } \ + while(shift >= loop_end) \ + { \ + (_count) += CHAR_BIT; \ + (_value) |= (VP8_BD_VALUE)*(_bufptr)++ << shift; \ + shift -= CHAR_BIT; \ + } \ + } \ + while(0) \ + + +static int vp8dx_decode_bool(BOOL_DECODER *br, int probability) { + unsigned int bit = 0; + VP8_BD_VALUE value; + unsigned int split; + VP8_BD_VALUE bigsplit; + int count; + unsigned int range; + + split = 1 + (((br->range - 1) * probability) >> 8); + + if(br->count < 0) + vp8dx_bool_decoder_fill(br); + + value = br->value; + count = br->count; + + bigsplit = (VP8_BD_VALUE)split << (VP8_BD_VALUE_SIZE - 8); + + range = split; + + if (value >= bigsplit) + { + range = br->range - split; + value = value - bigsplit; + bit = 1; + } + + { + register unsigned int shift = vp8_norm[range]; + range <<= shift; + value <<= shift; + count -= shift; + } + br->value = value; + br->count = count; + br->range = range; + + return bit; +} + +static G_GNUC_UNUSED int vp8_decode_value(BOOL_DECODER *br, int bits) +{ + int z = 0; + int bit; + + for (bit = bits - 1; bit >= 0; bit--) + { + z |= (vp8dx_decode_bool(br, 0x80) << bit); + } + + return z; +} + +static G_GNUC_UNUSED int vp8dx_bool_error(BOOL_DECODER *br) +{ + /* Check if we have reached the end of the buffer. + * + * Variable 'count' stores the number of bits in the 'value' buffer, minus + * 8. The top byte is part of the algorithm, and the remainder is buffered + * to be shifted into it. So if count == 8, the top 16 bits of 'value' are + * occupied, 8 for the algorithm and 8 in the buffer. + * + * When reading a byte from the user's buffer, count is filled with 8 and + * one byte is filled into the value buffer. When we reach the end of the + * data, count is additionally filled with VP8_LOTS_OF_BITS. So when + * count == VP8_LOTS_OF_BITS - 1, the user's data has been exhausted. + */ + if ((br->count > VP8_BD_VALUE_SIZE) && (br->count < VP8_LOTS_OF_BITS)) + { + /* We have tried to decode bits after the end of + * stream was encountered. + */ + return 1; + } + + /* No error. */ + return 0; +} +#endif diff --git a/gst/rtpvp8/gstrtpvp8pay.c b/gst/rtpvp8/gstrtpvp8pay.c index c6c773dca..d3795da3b 100644 --- a/gst/rtpvp8/gstrtpvp8pay.c +++ b/gst/rtpvp8/gstrtpvp8pay.c @@ -25,6 +25,7 @@ #include <gst/base/gstbitreader.h> #include <gst/rtp/gstrtppayloads.h> #include <gst/rtp/gstrtpbuffer.h> +#include "dboolhuff.h" #include "gstrtpvp8pay.h" #define FI_FRAG_UNFRAGMENTED 0x0 @@ -130,6 +131,8 @@ gst_rtp_vp8_pay_parse_frame (GstRtpVP8Pay * self, GstBuffer * buffer) guint8 tmp8 = 0; guint8 *data; guint8 partitions; + guint offset; + BOOL_DECODER bc; reader = gst_bit_reader_new_from_buffer (buffer); @@ -150,7 +153,8 @@ gst_rtp_vp8_pay_parse_frame (GstRtpVP8Pay * self, GstBuffer * buffer) header_size = data[2] << 11 | data[1] << 3 | (data[0] >> 5); /* Include the uncompressed data blob in the header */ - header_size += keyframe ? 10 : 3; + offset = keyframe ? 10 : 3; + header_size += offset; if (!gst_bit_reader_skip (reader, 24)) goto error; @@ -166,109 +170,81 @@ gst_rtp_vp8_pay_parse_frame (GstRtpVP8Pay * self, GstBuffer * buffer) if (!gst_bit_reader_get_bits_uint8 (reader, &tmp8, 8) || tmp8 != 0x2a) goto error; - /* Skip horizontal size code (16 bits) vertical size code (16 bits), - * color space (1 bit) and clamping type (1 bit) */ - if (!gst_bit_reader_skip (reader, 34)) + /* Skip horizontal size code (16 bits) vertical size code (16 bits) */ + if (!gst_bit_reader_skip (reader, 32)) goto error; } - /* segmentation_enabled */ - if (!gst_bit_reader_get_bits_uint8 (reader, &tmp8, 1)) - goto error; + offset = keyframe ? 10 : 3; + vp8dx_start_decode (&bc, GST_BUFFER_DATA (buffer) + offset, + GST_BUFFER_SIZE (buffer) - offset); - if (tmp8 != 0) { - gboolean update_mb_segmentation_map; - gboolean update_segment_feature_data; - - if (!gst_bit_reader_get_bits_uint8 (reader, &tmp8, 2)) - goto error; + if (keyframe) { + /* color space (1 bit) and clamping type (1 bit) */ + vp8dx_decode_bool (&bc, 0x80); + vp8dx_decode_bool (&bc, 0x80); + } - update_mb_segmentation_map = (tmp8 & 0x2) != 0; - update_segment_feature_data = (tmp8 & 0x1) != 0; + /* segmentation_enabled */ + if (vp8dx_decode_bool (&bc, 0x80)) { + guint8 update_mb_segmentation_map = vp8dx_decode_bool (&bc, 0x80); + guint8 update_segment_feature_data = vp8dx_decode_bool (&bc, 0x80); if (update_segment_feature_data) { /* skip segment feature mode */ - if (!gst_bit_reader_skip (reader, 1)) - goto error; + vp8dx_decode_bool (&bc, 0x80); + /* quantizer update */ for (i = 0; i < 4; i++) { - /* quantizer update */ - if (!gst_bit_reader_get_bits_uint8 (reader, &tmp8, 1)) - goto error; - - if (tmp8 != 0) { - /* skip quantizer value (7 bits) and sign (1 bit) */ - if (!gst_bit_reader_skip (reader, 8)) - goto error; - } + /* skip flagged quantizer value (7 bits) and sign (1 bit) */ + if (vp8dx_decode_bool (&bc, 0x80)) + vp8_decode_value (&bc, 8); } + /* loop filter update */ for (i = 0; i < 4; i++) { - /* loop filter update */ - if (!gst_bit_reader_get_bits_uint8 (reader, &tmp8, 1)) - goto error; - - if (tmp8 != 0) { - /* skip lf update value (6 bits) and sign (1 bit) */ - if (!gst_bit_reader_skip (reader, 7)) - goto error; - } + /* skip flagged lf update value (6 bits) and sign (1 bit) */ + if (vp8dx_decode_bool (&bc, 0x80)) + vp8_decode_value (&bc, 7); } } if (update_mb_segmentation_map) { + /* segment prob update */ for (i = 0; i < 3; i++) { - /* segment prob update */ - if (!gst_bit_reader_get_bits_uint8 (reader, &tmp8, 1)) - goto error; - - if (tmp8 != 0) { - /* skip segment prob */ - if (!gst_bit_reader_skip (reader, 8)) - goto error; - } + /* skip flagged segment prob */ + if (vp8dx_decode_bool (&bc, 0x80)) + vp8_decode_value (&bc, 8); } } } /* skip filter type (1 bit), loop filter level (6 bits) and * sharpness level (3 bits) */ - if (!gst_bit_reader_skip (reader, 10)) - goto error; + vp8_decode_value (&bc, 1); + vp8_decode_value (&bc, 6); + vp8_decode_value (&bc, 3); /* loop_filter_adj_enabled */ - if (!gst_bit_reader_get_bits_uint8 (reader, &tmp8, 1)) - goto error; - - if (tmp8 != 0) { - /* loop filter adj enabled */ + if (vp8dx_decode_bool (&bc, 0x80)) { - /* mode_ref_lf_delta_update */ - if (!gst_bit_reader_get_bits_uint8 (reader, &tmp8, 1)) - goto error; - - if (tmp8 != 0) { - /* mode_ref_lf_data_update */ - int i; + /* delta update */ + if (vp8dx_decode_bool (&bc, 0x80)) { for (i = 0; i < 8; i++) { /* 8 updates, 1 bit indicate whether there is one and if follow by a * 7 bit update */ - if (!gst_bit_reader_get_bits_uint8 (reader, &tmp8, 1)) - goto error; - - if (tmp8 != 0) { - /* skip delta magnitude (6 bits) and sign (1 bit) */ - if (!gst_bit_reader_skip (reader, 7)) - goto error; - } + if (vp8dx_decode_bool (&bc, 0x80)) + vp8_decode_value (&bc, 7); } } } - if (!gst_bit_reader_get_bits_uint8 (reader, &tmp8, 2)) + if (vp8dx_bool_error (&bc)) goto error; + tmp8 = vp8_decode_value (&bc, 2); + partitions = 1 << tmp8; /* Check if things are still sensible */ diff --git a/gst/videoparsers/Makefile.am b/gst/videoparsers/Makefile.am index 811d5f860..ac2a51711 100644 --- a/gst/videoparsers/Makefile.am +++ b/gst/videoparsers/Makefile.am @@ -7,6 +7,7 @@ libgstvideoparsersbad_la_SOURCES = plugin.c \ libgstvideoparsersbad_la_CFLAGS = \ $(GST_PLUGINS_BAD_CFLAGS) $(GST_PLUGINS_BASE_CFLAGS) \ + -DGST_USE_UNSTABLE_API \ $(GST_BASE_CFLAGS) $(GST_CFLAGS) libgstvideoparsersbad_la_LIBADD = $(GST_PLUGINS_BASE_LIBS) \ $(top_builddir)/gst-libs/gst/codecparsers/libgstcodecparsers-$(GST_MAJORMINOR).la \ diff --git a/gst/videoparsers/dirac_parse.c b/gst/videoparsers/dirac_parse.c index 3a3193d92..5b367c36c 100644 --- a/gst/videoparsers/dirac_parse.c +++ b/gst/videoparsers/dirac_parse.c @@ -165,7 +165,7 @@ dirac_sequence_header_parse (DiracSequenceHeader * header, /* standard stuff */ -static DiracSequenceHeader schro_video_formats[] = { +static const DiracSequenceHeader schro_video_formats[] = { {0, 0, 0, 0, 0, /* custom */ 640, 480, SCHRO_CHROMA_420, @@ -323,7 +323,7 @@ struct _SchroFrameRate int denominator; }; -static SchroFrameRate schro_frame_rates[] = { +static const SchroFrameRate schro_frame_rates[] = { {0, 0}, {24000, 1001}, {24, 1}, diff --git a/gst/videoparsers/gstdiracparse.c b/gst/videoparsers/gstdiracparse.c index 3feaa4192..ef99b7ae9 100644 --- a/gst/videoparsers/gstdiracparse.c +++ b/gst/videoparsers/gstdiracparse.c @@ -78,14 +78,19 @@ static GstStaticPadTemplate gst_dirac_parse_sink_template = GST_STATIC_PAD_TEMPLATE ("sink", GST_PAD_SINK, GST_PAD_ALWAYS, - GST_STATIC_CAPS ("video/x-dirac, parsed=(boolean)FALSE") + GST_STATIC_CAPS ("video/x-dirac") ); static GstStaticPadTemplate gst_dirac_parse_src_template = GST_STATIC_PAD_TEMPLATE ("src", GST_PAD_SRC, GST_PAD_ALWAYS, - GST_STATIC_CAPS ("video/x-dirac, parsed=(boolean)TRUE") + GST_STATIC_CAPS ("video/x-dirac, parsed=(boolean)TRUE, " + "width=(int)[1,MAX], height=(int)[1,MAX], " + "framerate=(fraction)[0/1,MAX], " + "pixel-aspect-ratio=(fraction)[0/1,MAX], " + "interlaced=(boolean){TRUE,FALSE}, " + "profile=(int)[0,MAX], level=(int)[0,MAX]") ); /* class initialization */ diff --git a/gst/videoparsers/gsth263parse.c b/gst/videoparsers/gsth263parse.c index 877c75e44..4a5633f3b 100644 --- a/gst/videoparsers/gsth263parse.c +++ b/gst/videoparsers/gsth263parse.c @@ -39,14 +39,13 @@ static GstStaticPadTemplate srctemplate = GST_STATIC_PAD_TEMPLATE ("src", GST_PAD_SRC, GST_PAD_ALWAYS, GST_STATIC_CAPS ("video/x-h263, variant = (string) itu, " - "parsed = (boolean) true") + "parsed = (boolean) true, framerate=(fraction)[0/1,MAX]") ); static GstStaticPadTemplate sinktemplate = GST_STATIC_PAD_TEMPLATE ("sink", GST_PAD_SINK, GST_PAD_ALWAYS, - GST_STATIC_CAPS ("video/x-h263, variant = (string) itu, " - "parsed = (boolean) false") + GST_STATIC_CAPS ("video/x-h263, variant = (string) itu") ); GST_BOILERPLATE (GstH263Parse, gst_h263_parse, GstElement, GST_TYPE_BASE_PARSE); @@ -102,7 +101,7 @@ gst_h263_parse_start (GstBaseParse * parse) { GstH263Parse *h263parse = GST_H263_PARSE (parse); - GST_DEBUG ("Start"); + GST_DEBUG_OBJECT (h263parse, "start"); h263parse->bitrate = 0; h263parse->profile = -1; @@ -118,7 +117,7 @@ gst_h263_parse_start (GstBaseParse * parse) static gboolean gst_h263_parse_stop (GstBaseParse * parse) { - GST_DEBUG ("Stop"); + GST_DEBUG_OBJECT (parse, "stop"); return TRUE; } @@ -139,7 +138,7 @@ gst_h263_parse_sink_event (GstBaseParse * parse, GstEvent * event) gst_event_parse_tag (event, &taglist); if (gst_tag_list_get_uint (taglist, GST_TAG_BITRATE, &h263parse->bitrate)) - GST_DEBUG ("Got bitrate tag: %u", h263parse->bitrate); + GST_DEBUG_OBJECT (h263parse, "got bitrate tag: %u", h263parse->bitrate); break; } @@ -201,7 +200,7 @@ gst_h263_parse_set_src_caps (GstH263Parse * h263parse, if (sink_caps && (st = gst_caps_get_structure (sink_caps, 0)) && gst_structure_get_fraction (st, "framerate", &fr_num, &fr_denom)) { /* Got it in caps - nothing more to do */ - GST_DEBUG ("Sink caps override framerate from headers"); + GST_DEBUG_OBJECT (h263parse, "sink caps override framerate from headers"); } else { /* Caps didn't have the framerate - get it from params */ gst_h263_parse_get_framerate (params, &fr_num, &fr_denom); @@ -308,7 +307,8 @@ gst_h263_parse_check_valid_frame (GstBaseParse * parse, /* XXX: After getting a keyframe, should we adjust min_frame_size to * something smaller so we don't end up collecting too many non-keyframes? */ - GST_DEBUG ("Found a frame of size %d at pos %d", *framesize, *skipsize); + GST_DEBUG_OBJECT (h263parse, "found a frame of size %d at pos %d", + *framesize, *skipsize); return TRUE; diff --git a/gst/videoparsers/gsth264parse.c b/gst/videoparsers/gsth264parse.c index 3821f0031..d2009d60e 100644 --- a/gst/videoparsers/gsth264parse.c +++ b/gst/videoparsers/gsth264parse.c @@ -62,12 +62,14 @@ enum static GstStaticPadTemplate sinktemplate = GST_STATIC_PAD_TEMPLATE ("sink", GST_PAD_SINK, GST_PAD_ALWAYS, - GST_STATIC_CAPS ("video/x-h264, parsed = (boolean) false")); + GST_STATIC_CAPS ("video/x-h264")); static GstStaticPadTemplate srctemplate = GST_STATIC_PAD_TEMPLATE ("src", GST_PAD_SRC, GST_PAD_ALWAYS, - GST_STATIC_CAPS ("video/x-h264, parsed = (boolean) true")); + GST_STATIC_CAPS ("video/x-h264, parsed = (boolean) true, " + "stream-format=(string) { avc, byte-stream }, " + "alignment=(string) { au, nal }")); GST_BOILERPLATE (GstH264Parse, gst_h264_parse, GstBaseParse, GST_TYPE_BASE_PARSE); @@ -237,8 +239,7 @@ gst_h264_parse_stop (GstBaseParse * parse) for (i = 0; i < GST_H264_MAX_PPS_COUNT; i++) gst_buffer_replace (&h264parse->pps_nals[i], NULL); - g_free (h264parse->nalparser); - h264parse->nalparser = NULL; + gst_h264_nal_parser_free (h264parse->nalparser); return TRUE; } @@ -338,7 +339,8 @@ gst_h264_parse_wrap_nal (GstH264Parse * h264parse, guint format, guint8 * data, GstBuffer *buf; const guint nl = h264parse->nal_length_size; - GST_DEBUG ("Nal length %d %d", size, h264parse->nal_length_size); + GST_DEBUG_OBJECT (h264parse, "nal length %d %d", size, + h264parse->nal_length_size); buf = gst_buffer_new_and_alloc (size + nl + 4); if (format == GST_H264_PARSE_FORMAT_AVC) { @@ -364,11 +366,11 @@ gst_h264_parser_store_nal (GstH264Parse * h264parse, guint id, if (naltype == GST_H264_NAL_SPS) { store_size = GST_H264_MAX_SPS_COUNT; store = h264parse->sps_nals; - GST_DEBUG ("Storing sps %u", id); + GST_DEBUG_OBJECT (h264parse, "storing sps %u", id); } else if (naltype == GST_H264_NAL_PPS) { store_size = GST_H264_MAX_PPS_COUNT; store = h264parse->pps_nals; - GST_DEBUG ("Storing pps %u", id); + GST_DEBUG_OBJECT (h264parse, "storing pps %u", id); } else return; @@ -476,8 +478,8 @@ gst_h264_parse_process_nal (GstH264Parse * h264parse, GstH264NalUnit * nalu) /* if we need to sneak codec NALs into the stream, * this is a good place, so fake it as IDR * (which should be at start anyway) */ - GST_DEBUG ("Frame start: %i first_mb_in_slice %i", h264parse->frame_start, - slice.first_mb_in_slice); + GST_DEBUG_OBJECT (h264parse, "frame start: %i first_mb_in_slice %i", + h264parse->frame_start, slice.first_mb_in_slice); if (G_LIKELY (!h264parse->push_codec)) break; /* fall-through */ @@ -486,7 +488,7 @@ gst_h264_parse_process_nal (GstH264Parse * h264parse, GstH264NalUnit * nalu) if (gst_h264_parser_parse_slice_hdr (nalparser, nalu, &slice, FALSE, FALSE) == GST_H264_PARSER_ERROR) return; - GST_DEBUG ("Frame start: %i first_mb_in_slice %i", + GST_DEBUG_OBJECT (h264parse, "frame start: %i first_mb_in_slice %i", h264parse->frame_start, slice.first_mb_in_slice); } /* real frame data */ @@ -494,15 +496,17 @@ gst_h264_parse_process_nal (GstH264Parse * h264parse, GstH264NalUnit * nalu) /* mark where config needs to go if interval expired */ /* mind replacement buffer if applicable */ - if (h264parse->format == GST_H264_PARSE_FORMAT_AVC) - h264parse->idr_pos = gst_adapter_available (h264parse->frame_out); - else - h264parse->idr_pos = nalu->offset - 4; - GST_DEBUG_OBJECT (h264parse, "marking IDR in frame at offset %d", - h264parse->idr_pos); + if (h264parse->idr_pos == -1) { + if (h264parse->format == GST_H264_PARSE_FORMAT_AVC) + h264parse->idr_pos = gst_adapter_available (h264parse->frame_out); + else + h264parse->idr_pos = nalu->offset - 4; + GST_DEBUG_OBJECT (h264parse, "marking IDR in frame at offset %d", + h264parse->idr_pos); + } - GST_DEBUG ("first MB: %u, slice type: %u", slice.first_mb_in_slice, - slice.type); + GST_DEBUG_OBJECT (h264parse, "first MB: %u, slice type: %u", + slice.first_mb_in_slice, slice.type); break; default: gst_h264_parser_parse_nal (nalparser, nalu); @@ -531,7 +535,7 @@ gst_h264_parse_collect_nal (GstH264Parse * h264parse, const guint8 * data, GstH264NalUnitType nal_type = nalu->type; GstH264NalUnit nnalu; - GST_DEBUG ("Parsing collecte nal"); + GST_DEBUG_OBJECT (h264parse, "parsing collected nal"); parse_res = gst_h264_parser_identify_nalu (h264parse->nalparser, data, nalu->offset + nalu->size, size, &nnalu); @@ -612,16 +616,18 @@ gst_h264_parse_check_valid_frame (GstBaseParse * parse, drain = GST_BASE_PARSE_DRAINING (parse); current_off = h264parse->current_off; - GST_DEBUG ("Last parse position %u", current_off); + GST_DEBUG_OBJECT (h264parse, "last parse position %u", current_off); while (TRUE) { switch (gst_h264_parser_identify_nalu (nalparser, data, current_off, size, &nalu)) { case GST_H264_PARSER_OK: - GST_DEBUG ("Complete nal found. %u Off: %u, Size: %u", + GST_DEBUG_OBJECT (h264parse, "complete nal found. " + "current offset: %u, Nal offset: %u, Nal Size: %u", current_off, nalu.offset, nalu.size); current_off = nalu.offset + nalu.size; - GST_DEBUG ("CURENT OFF. %u, %u", current_off, nalu.offset + nalu.size); + GST_DEBUG_OBJECT (h264parse, "current off. %u, %u", current_off, + nalu.offset + nalu.size); if (!h264parse->nalu.size && !h264parse->nalu.valid) h264parse->nalu = nalu; break; @@ -643,15 +649,15 @@ gst_h264_parse_check_valid_frame (GstBaseParse * parse, if (nalu.sc_offset == h264parse->nalu.sc_offset) { *skipsize = nalu.offset; - GST_DEBUG ("Skiping broken nal"); + GST_DEBUG_OBJECT (h264parse, "skipping broken nal"); return FALSE; } else { nalu.size = 0; - goto end; } case GST_H264_PARSER_NO_NAL_END: - GST_DEBUG ("Not a complete nal found at offset %u", nalu.offset); + GST_DEBUG_OBJECT (h264parse, "not a complete nal found at offset %u", + nalu.offset); current_off = nalu.sc_offset; /* We keep the reference to this nal so we start over the parsing @@ -660,8 +666,8 @@ gst_h264_parse_check_valid_frame (GstBaseParse * parse, h264parse->nalu = nalu; if (drain) { - GST_DEBUG ("Drainning NAL %u %u %u", size, h264parse->nalu.offset, - h264parse->nalu.size); + GST_DEBUG_OBJECT (h264parse, "drainning NAL %u %u %u", size, + h264parse->nalu.offset, h264parse->nalu.size); /* Can't parse the nalu */ if (size - h264parse->nalu.offset < 2) { *skipsize = nalu.offset; @@ -677,8 +683,8 @@ gst_h264_parse_check_valid_frame (GstBaseParse * parse, current_off = nalu.offset + nalu.size; - GST_DEBUG ("%p Complete nal found. Off: %u, Size: %u", data, nalu.offset, - nalu.size); + GST_DEBUG_OBJECT (h264parse, "%p complete nal found. Off: %u, Size: %u", + data, nalu.offset, nalu.size); gst_h264_parse_process_nal (h264parse, &nalu); if (gst_h264_parse_collect_nal (h264parse, data, size, &nalu) || drain) @@ -697,7 +703,7 @@ end: return TRUE; parsing_error: - GST_DEBUG ("Error parsing Nal Unit"); + GST_DEBUG_OBJECT (h264parse, "error parsing Nal Unit"); more: /* ask for best next available */ diff --git a/gst/videoparsers/gstmpegvideoparse.c b/gst/videoparsers/gstmpegvideoparse.c index 12d98d5d7..5db0080a1 100644 --- a/gst/videoparsers/gstmpegvideoparse.c +++ b/gst/videoparsers/gstmpegvideoparse.c @@ -46,8 +46,7 @@ static GstStaticPadTemplate sink_template = GST_STATIC_PAD_TEMPLATE ("sink", GST_PAD_SINK, GST_PAD_ALWAYS, GST_STATIC_CAPS ("video/mpeg, " - "mpegversion = (int) [1, 2], " - "parsed = (boolean) false, " "systemstream = (boolean) false") + "mpegversion = (int) [1, 2], " "systemstream = (boolean) false") ); /* Properties */ @@ -72,6 +71,8 @@ static gboolean gst_mpegv_parse_check_valid_frame (GstBaseParse * parse, static GstFlowReturn gst_mpegv_parse_parse_frame (GstBaseParse * parse, GstBaseParseFrame * frame); static gboolean gst_mpegv_parse_set_caps (GstBaseParse * parse, GstCaps * caps); +static GstFlowReturn gst_mpegv_parse_pre_push_frame (GstBaseParse * parse, + GstBaseParseFrame * frame); static void gst_mpegv_parse_set_property (GObject * object, guint prop_id, const GValue * value, GParamSpec * pspec); @@ -165,6 +166,8 @@ gst_mpegv_parse_class_init (GstMpegvParseClass * klass) GST_DEBUG_FUNCPTR (gst_mpegv_parse_check_valid_frame); parse_class->parse_frame = GST_DEBUG_FUNCPTR (gst_mpegv_parse_parse_frame); parse_class->set_sink_caps = GST_DEBUG_FUNCPTR (gst_mpegv_parse_set_caps); + parse_class->pre_push_frame = + GST_DEBUG_FUNCPTR (gst_mpegv_parse_pre_push_frame); } static void @@ -188,6 +191,7 @@ gst_mpegv_parse_reset (GstMpegvParse * mpvparse) gst_mpegv_parse_reset_frame (mpvparse); mpvparse->profile = 0; mpvparse->update_caps = TRUE; + mpvparse->send_codec_tag = TRUE; gst_buffer_replace (&mpvparse->config, NULL); memset (&mpvparse->sequencehdr, 0, sizeof (mpvparse->sequencehdr)); @@ -237,13 +241,12 @@ gst_mpegv_parse_process_config (GstMpegvParse * mpvparse, GstBuffer * buf, 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", + "failed to parse config data (size %d) at offset %d", size, mpvparse->seq_offset); return FALSE; } - GST_LOG_OBJECT (mpvparse, "accepting parsed config size %" G_GSSIZE_FORMAT, - size); + GST_LOG_OBJECT (mpvparse, "accepting parsed config size %d", size); /* Set mpeg version, and parse sequence extension */ if (mpvparse->mpeg_version <= 0) { @@ -490,15 +493,23 @@ end: } else if (GST_BASE_PARSE_DRAINING (parse)) { *framesize = GST_BUFFER_SIZE (buf); ret = TRUE; + } else { /* resume scan where we left it */ - mpvparse->last_sc = GST_BUFFER_SIZE (buf); + if (!mpvparse->last_sc) + *skipsize = mpvparse->last_sc = GST_BUFFER_SIZE (buf) - 3; + else if (mpvparse->typeoffsize) + mpvparse->last_sc = GST_BUFFER_SIZE (buf) - 3; + else + *skipsize = 0; + /* request best next available */ *framesize = G_MAXUINT; ret = FALSE; } - g_list_free_full (mpvparse->typeoffsize, (GDestroyNotify) g_free); + g_list_foreach (mpvparse->typeoffsize, (GFunc) g_free, NULL); + g_list_free (mpvparse->typeoffsize); mpvparse->typeoffsize = NULL; return ret; @@ -654,6 +665,37 @@ gst_mpegv_parse_parse_frame (GstBaseParse * parse, GstBaseParseFrame * frame) return GST_FLOW_OK; } +static GstFlowReturn +gst_mpegv_parse_pre_push_frame (GstBaseParse * parse, GstBaseParseFrame * frame) +{ + GstMpegvParse *mpvparse = GST_MPEGVIDEO_PARSE (parse); + GstTagList *taglist; + + /* tag sending done late enough in hook to ensure pending events + * have already been sent */ + + if (G_UNLIKELY (mpvparse->send_codec_tag)) { + gchar *codec; + + /* codec tag */ + codec = g_strdup_printf ("MPEG %d Video", mpvparse->mpeg_version); + taglist = gst_tag_list_new (); + gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, + GST_TAG_VIDEO_CODEC, codec, NULL); + g_free (codec); + + gst_element_found_tags_for_pad (GST_ELEMENT (mpvparse), + GST_BASE_PARSE_SRC_PAD (mpvparse), taglist); + + mpvparse->send_codec_tag = FALSE; + } + + /* usual clipping applies */ + frame->flags |= GST_BASE_PARSE_FRAME_FLAG_CLIP; + + return GST_FLOW_OK; +} + static gboolean gst_mpegv_parse_set_caps (GstBaseParse * parse, GstCaps * caps) { diff --git a/gst/videoparsers/gstmpegvideoparse.h b/gst/videoparsers/gstmpegvideoparse.h index 6837a316e..593c53e8b 100644 --- a/gst/videoparsers/gstmpegvideoparse.h +++ b/gst/videoparsers/gstmpegvideoparse.h @@ -56,6 +56,7 @@ struct _GstMpegvParse { gint seq_offset; gint pic_offset; gboolean update_caps; + gboolean send_codec_tag; GstBuffer *config; guint8 profile; diff --git a/gst/videoparsers/plugin.c b/gst/videoparsers/plugin.c index a6db91d35..94a6c10fe 100644 --- a/gst/videoparsers/plugin.c +++ b/gst/videoparsers/plugin.c @@ -33,13 +33,13 @@ plugin_init (GstPlugin * plugin) gboolean ret; ret = gst_element_register (plugin, "h263parse", - GST_RANK_NONE, GST_TYPE_H263_PARSE); + GST_RANK_PRIMARY + 1, GST_TYPE_H263_PARSE); ret = gst_element_register (plugin, "h264parse", - GST_RANK_NONE, GST_TYPE_H264_PARSE); + GST_RANK_PRIMARY + 1, GST_TYPE_H264_PARSE); ret = gst_element_register (plugin, "diracparse", GST_RANK_NONE, GST_TYPE_DIRAC_PARSE); ret = gst_element_register (plugin, "mpegvideoparse", - GST_RANK_NONE, GST_TYPE_MPEGVIDEO_PARSE); + GST_RANK_PRIMARY + 1, GST_TYPE_MPEGVIDEO_PARSE); return ret; } diff --git a/tests/check/Makefile.am b/tests/check/Makefile.am index 47bd813c9..75750ea99 100644 --- a/tests/check/Makefile.am +++ b/tests/check/Makefile.am @@ -185,6 +185,7 @@ check_PROGRAMS = \ elements/rtpmux \ libs/mpegvideoparser \ libs/h264parser \ + libs/vc1parser \ $(check_schro) \ $(check_vp8) \ elements/viewfinderbin \ @@ -218,6 +219,7 @@ elements_h264parse_LDADD = libparser.la $(LDADD) libs_mpegvideoparser_CFLAGS = \ $(GST_PLUGINS_BAD_CFLAGS) $(GST_PLUGINS_BASE_CFLAGS) \ + -DGST_USE_UNSTABLE_API \ $(GST_BASE_CFLAGS) $(GST_CFLAGS) $(AM_CFLAGS) libs_mpegvideoparser_LDADD = \ @@ -227,6 +229,7 @@ libs_mpegvideoparser_LDADD = \ libs_h264parser_CFLAGS = \ $(GST_PLUGINS_BAD_CFLAGS) $(GST_PLUGINS_BASE_CFLAGS) \ + -DGST_USE_UNSTABLE_API \ $(GST_BASE_CFLAGS) $(GST_CFLAGS) $(AM_CFLAGS) libs_h264parser_LDADD = \ @@ -234,6 +237,16 @@ libs_h264parser_LDADD = \ $(GST_PLUGINS_BAD_LIBS) -lgstcodecparsers-@GST_MAJORMINOR@ \ $(GST_BASE_LIBS) $(GST_LIBS) $(LDADD) +libs_vc1parser_CFLAGS = \ + $(GST_PLUGINS_BAD_CFLAGS) $(GST_PLUGINS_BASE_CFLAGS) \ + -DGST_USE_UNSTABLE_API \ + $(GST_BASE_CFLAGS) $(GST_CFLAGS) $(AM_CFLAGS) + +libs_vc1parser_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/h264parser.c b/tests/check/libs/h264parser.c index 3bc8c49e5..5d87980f9 100644 --- a/tests/check/libs/h264parser.c +++ b/tests/check/libs/h264parser.c @@ -145,7 +145,7 @@ GST_START_TEST (test_h264_parse_slice_dpa) assert_equals_int (res, GST_H264_PARSER_OK); assert_equals_int (nalu.type, GST_H264_NAL_SLICE_DPA); - g_free (parser); + gst_h264_nal_parser_free (parser); } GST_END_TEST; diff --git a/tests/check/libs/vc1parser.c b/tests/check/libs/vc1parser.c new file mode 100644 index 000000000..5c9ef73ee --- /dev/null +++ b/tests/check/libs/vc1parser.c @@ -0,0 +1,1230 @@ +/* Gstreamer + * Copyright (C) <2011> Intel + * Copyright (C) <2011> Collabora Ltd. + * Copyright (C) <2011> Thibault Saunier <thibault.saunier@collabora.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. + */ +#include <gst/check/gstcheck.h> +#include <gst/codecparsers/gstvc1parser.h> + +static guint8 sequence_fullframe[] = { + 0x00, 0x00, 0x01, 0x0f, 0xca, 0x86, 0x13, 0xf0, 0xef, 0x88, + 0x80, 0x00, 0x00, 0x01, 0x0e, 0x48, 0x3f, 0x4f, 0xc3, 0xbc, + 0x3f, 0x2b, 0x3f, 0x3c, 0x3f, 0x00, 0x00, 0x01, 0x0d, 0x3f, + 0x0c, 0x14, 0x27, 0x3f, 0x68, 0x0c, 0x03, 0x3f, 0x3f, 0x55, + 0x3f, 0x60, 0x71, 0x24, 0x38, 0x28, 0x1b, 0xda, 0xac, 0x01, + 0x3f, 0x3f, 0x3f, 0x33, 0x3f, 0x61, 0x75, 0x70, 0x3f, 0x3f, + 0x3f, 0x0d, 0x3f, 0x03, 0x3f, 0x3f, 0x1b, 0x3f, 0x3f, 0x61, + 0x1a, 0x73, 0x01, 0x26, 0x07, 0x0e, 0x29, 0x3f, 0x1d, 0x68, + 0xe1, 0xa2, 0x98, 0x59, 0x21, 0x3f, 0x1e, 0x7c, 0x3f, 0x3f, + 0x3f, 0x65, 0x49, 0x3f, 0x3f, 0x7e, 0x3f, 0x07, 0x6a, 0x0f, + 0xdb, 0x87, 0x3f, 0x3f, 0x3f, 0x41, 0x3f, 0x3f, 0x77, 0x3f, + 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x44, 0x3f, 0x4a, 0x50, 0x53, + 0x3f, 0x3f, 0x65, 0x3f, 0x2e, 0x3f, 0x3f, 0x3f, 0x08, 0x3f, + 0x3f, 0x04, 0x5e, 0x11, 0x7d, 0x12, 0x3f, 0x4a, 0x6b, 0x50, + 0x42, 0x3f, 0x15, 0x3f, 0x3f, 0x61, 0x3f, 0x3f, 0x75, 0x41, + 0x3f, 0x3f, 0x75, 0x71, 0x3f, 0x3f, 0x3b, 0x3f, 0x0d, 0x3f, + 0x3f, 0x6e, 0x3f, 0x3f, 0x06, 0x3f, 0x30, 0x08, 0x72, 0x3f, + 0x3b, 0x3f, 0x67, 0x6e, 0x3f, 0x50, 0x1b, 0x61, 0x5a, 0x20, + 0x2b, 0x70, 0x3f, 0x2c, 0x22, 0x3f, 0x36, 0x3f, 0x44, 0x40, + 0x00, 0x00, 0x01, 0x05, 0x3f +}; + +static guint8 pframe_header_main[] = { + 0x4e, 0x29, 0x1a, 0x11 +}; + +static guint8 pframe_main[] = { + 0x6a, 0x88, 0xbc, 0x1d, 0x40, 0x16, 0x96, 0x90, 0x05, 0x82, + 0xac, 0x22, 0x88, 0xe0, 0x5d, 0x52, 0xca, 0x85, 0x4c, 0x47, + 0x9d, 0xc9, 0x25, 0x45, 0x56, 0x99, 0x44, 0x15, 0xa5, 0xc5, + 0xe1, 0x35, 0x11, 0x72, 0xc1, 0x27, 0x22, 0x6a, 0x08, 0x9a, + 0x72, 0x4e, 0xe7, 0xa3, 0xf7, 0x23, 0x9d, 0x11, 0x8d, 0xc8, + 0xe6, 0x4f, 0x46, 0x98, 0xe2, 0x03, 0xcc, 0x6c, 0xe8, 0x77, + 0xd4, 0x7c, 0xfc, 0x13, 0x39, 0x20, 0x23, 0x03, 0x24, 0xcd, + 0x15, 0xbf, 0x54, 0x61, 0xf2, 0x25, 0x25, 0xa0, 0x83, 0xa0, +}; + +static guint8 bframe_header_main[] = { + 0x4e, 0x39, 0x1a, 0x11 +}; + +static guint8 bframe_main[] = { + 0x80, 0xae, 0x01, 0x43, 0x47, 0x6a, 0x9f, 0x53, 0x04, 0x55, 0x2a, + 0x8b, 0x42, 0x75, 0x8b, 0x35, 0x50, 0xf5, 0x95, 0x56, 0xf2, 0x00, + 0xe0, 0xa0, 0x60, 0x2c, 0xe8, 0x6b, 0x60, 0x0b, 0x20, 0x00, 0x11, + 0xf1, 0x51, 0xfe, 0x91, 0x60, 0x6a, 0xe6, 0x12, 0x04, 0x2c, 0xe3, + 0x07, 0x0a, 0x09, 0x09, 0x12, 0xcb, 0xe1, 0x42, 0x88, 0x10, 0x67, + 0x80, 0x4c, 0xbf, 0x26, 0x00, 0x82, 0x61, 0x07, 0x21, 0x63, 0x4c, + 0x0c, 0x32, 0x03, 0x53, 0x19, 0x1b, 0x4d, 0xca, 0xc9, 0xe0, 0xc1, + 0x6d, 0x32, 0x48, 0xc9, 0xd7, 0xa6, 0x63, 0x4d, 0xeb, 0xd4, 0x1c, + 0x02, 0x05, 0xfe, 0x57, 0x29, 0x00, 0x58, 0xb0, 0x67, 0x2d, 0x04, + 0xee, 0x1b, 0xaf, 0x53, 0x40, 0x89, 0xbe, 0xf5, 0x76, 0x20, 0x0b, + 0x83, 0xc1, 0x88, 0xee, 0x83, 0x94, 0xab, 0x1c, 0x79, 0xdd, 0x44, + 0xe5, 0x15, 0xae, 0xa5, 0xd3, 0xd5, 0x68, 0x31, 0x3e, 0x5a, 0xa4, + 0x6b, 0x9e, 0xe3, 0xd2, 0x49, 0x00, 0x1d, 0x6d, 0xeb, 0x0d, 0x6b, + 0x54, 0xcd, 0xd2, 0xaf, 0x1f, 0x2b, 0xba, 0xf3, 0xd9, 0x4c, 0x71 +}; + +static guint8 i_bi_frame_header[] = { + 0x4e, 0x79, 0x1a, 0x11 +}; + +static guint8 biframe_main[] = { + 0x0f, 0xe0, 0x4c, 0x56, 0x19, 0xdb, 0x40, 0x68, 0xd9, 0x14, 0x2c, 0x92, + 0x55, 0x1f, 0x59, 0xd5, 0x5b, 0xd8, 0x55, 0x13, 0x19, 0x64, 0x40, 0x2c, + 0x27, 0x38, 0x71, 0x9d, 0x05, 0x52, 0x02, 0x18, 0x7b, 0x9d, 0x22, 0x88, + 0x97, 0xaa, 0x54, 0x95, 0x52, 0x49, 0x23, 0x0b, 0x98, 0xee, 0x6c, 0x26, + 0xe6, 0xff, 0xff, 0x1a, 0x25, 0x15, 0xc3, 0x30, 0x4f, 0x1f, 0xbd, 0xb1, + 0x09, 0x1b, 0x55, 0x33, 0x6c, 0xcd, 0x8c, 0x11, 0x87, 0x1b, 0x86, 0x02, + 0x78, 0xfd, 0x69, 0xc1, 0xa2, 0x3b, 0x27, 0x08, 0xc8, 0x63, 0x5f, 0x52, + 0x10, 0x50, 0xe0, 0xf4, 0x4a, 0xfd, 0x83, 0x30, 0x3f, 0x20, 0x8d, 0x3a, + 0x88, 0xa0, 0x00, 0x23, 0xd8, 0x51, 0xd0, 0xf6, 0x8c, 0xc4, 0xe8, 0x2d, + 0x8c, 0x10, 0x13, 0xae, 0xb2, 0xaa, 0xc0, 0x92, 0x68, 0x33, 0x7b, 0x8f, + 0x63, 0x0e, 0xda, 0x35, 0xc6, 0xa1, 0x11, 0xe6, 0x44, 0xe3, 0xb1, 0x52, + 0xe9, 0x01, 0x05, 0x93, 0x1a, 0x36, 0x41, 0xf6, 0x62, 0x66, 0x05, 0xfb, + 0xd6, 0x99, 0x80, 0x8a, 0x97, 0xad, 0xa4, 0x25, 0xec, 0x1a, 0x04, 0xf3, + 0x0c, 0x9c, 0xe0, 0xea, 0x49, 0xfa, 0x4d, 0x58, 0xc8, 0x1b, 0x63, 0x23, + 0xdc, 0x07, 0x9d, 0xe9, 0x84, 0x93, 0x12, 0xc8, 0xfc, 0x86, 0x98, 0xb0, + 0x3d, 0xc8, 0xb4, 0xed, 0x4c, 0x18, 0xbe, 0xd8, 0x38, 0x1b, 0x6d, 0x39, + 0x90, 0x06, 0x43, 0x75, 0x82, 0x89, 0xc1, 0x6f, 0xf1, 0x12, 0x6d, 0x84, + 0x54, 0x45, 0x62, 0x2d, 0x00, 0x0a, 0x0e, 0x06, 0xf0, 0x04, 0x06, 0x5a +}; + +static guint8 iframe_main[] = { + 0x10, 0x04, 0x88, 0x18, 0x1f, 0xdf, 0xe1, 0xe1, 0xde, 0x17, 0x85, 0xe1, + 0x78, 0x5e, 0x17, 0x85, 0xe1, 0x78, 0x5e, 0x17, 0x85, 0xe1, 0x78, 0x5e, + 0x17, 0x85, 0xe1, 0x78, 0x5e, 0x17, 0x85, 0xe1, 0x78, 0x5e, 0x17, 0x85, + 0xe1, 0x78, 0x5e, 0x17, 0x85, 0xe1, 0x78, 0x5e, 0x17, 0x85, 0xe1, 0x78, + 0x5e, 0x17, 0x85, 0xe1, 0x78, 0x5e, 0x17, 0x85, 0xe1, 0x78, 0x5e, 0x17, + 0x85, 0xe1, 0x78, 0x5e, 0x17, 0x85, 0xe1, 0x78, 0x5e, 0x17, 0x85, 0xe1, + 0x78, 0x5e, 0x17, 0x85, 0xe1, 0x78, 0x5e, 0x17, 0x85, 0xe1, 0x78, 0x5e, + 0x17, 0x85, 0xe1, 0x78, 0x5e, 0x17, 0x85, 0xe1, 0x78, 0x5e, 0x17, 0x85, + 0xe1, 0x78, 0x5e, 0x17, 0x85, 0xe1, 0x78, 0x5e, 0x17, 0x85, 0xe1, 0x78, + 0x5e, 0x17, 0x85, 0xe1, 0x78, 0x5e, 0x17, 0x85, 0xe1, 0x78, 0x5e, 0x17, + 0x85, 0xe1, 0x78, 0x5e, 0x17, 0x85, 0xe1, 0x78, 0x5e, 0x17, 0x85, 0xe1, + 0x78, 0x5e, 0x17, 0x85, 0xe1, 0x78, 0x5e, 0x17, 0x85, 0xe1, 0x78, 0x5e, + 0x17, 0x85, 0xe1, 0x78, 0x5e, 0x17, 0x85, 0xe1, 0x78, 0x5e, 0x17, 0x85, + 0xe1, 0x78, 0x5e, 0x17, 0x85, 0xe1, 0x78, 0x5e, 0x17, 0x85, 0xe1, 0x78 +}; + +static guint8 iframe_adv_hdr[] = { + 0xdb, 0xfe, 0x3b, 0xf2, 0x1b, 0xca, 0x3b, 0xf8, 0x86, 0xf1, 0x80, + 0xca, 0x02, 0x02, 0x03, 0x09, 0xa5, 0xb8, 0xd7, 0x07, 0xfc +}; + +static guint8 entrypoint[] = { + 0x5a, 0xc7, 0xfc, 0xef, 0xc8, 0x6c, 0x40 +}; + +static guint8 iframe_adv[] = { + 0x69, 0x1c, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x7f, 0x16, 0x0c, 0x0f, 0x13, 0xf0, 0xfc, 0x3f, 0x0f, 0xc3, 0xf0, + 0xfc, 0x3f, 0x0f, 0xc3, 0xf0, 0xfc, 0x3f, 0x0f, 0xc3, 0xf0, 0xfc, + 0x3f, 0x0f, 0xc3, 0xf0, 0xfc, 0x3f, 0x0f, 0xc3, 0xf0, 0xfc, 0x3f, + 0x0f, 0xc3, 0xf0, 0xfc, 0x3f, 0x0f, 0xc3, 0xf0, 0xfc, 0x3f, 0x0f, + 0xc3, 0xf0, 0xfc, 0x3f, 0x0f, 0xc3, 0xf0, 0xfc, 0x3f, 0x0f, 0xc3, + 0xf0, 0xfc, 0x3f, 0x0f, 0xc3, 0xf0, 0xfc, 0x3f, 0x0f, 0xc3, 0xf0, + 0xfc, 0x3f, 0x0f, 0xc3, 0xf0, 0xfc, 0x3f, 0x0f, 0xc3, 0xf0, 0xfc, + 0x3f, 0x0f, 0xc3, 0xf0, 0xfc, 0x3f, 0x0f, 0xc3, 0xf0, 0xfc, 0x3f, + 0x0f, 0xc3, 0xf0, 0xfc, 0x3f, 0x0f, 0xc3, 0xf0, 0xfc, 0x3f, 0x0f, + 0xc3, 0xf0, 0xfc, 0x3f, 0x0f, 0xc3, 0xf0, 0xfc, 0x3f, 0x0f, 0xc3, + 0xf0, 0xfc, 0x3f, 0x0f, 0xc3, 0xf0, 0xfc, 0x3f, 0x0f, 0xc3, 0xf0, + 0xfc, 0x3f, 0x0f, 0xc3, 0xf0, 0xfc, 0x3f, 0x0f, 0xc3, 0xf0, 0xfc, + 0x3f, 0x0f, 0xc3, 0xf0, 0xfc, 0x3f, 0x0f, 0xc3, 0xf0, 0xfc, 0x3f, + 0x0f, 0xc3, 0xf0, 0xfc, 0x3f, 0x0f, 0xc3, 0xf0, 0xfc, 0x3f, 0x0f, + 0xc3, 0xf0, 0xfc, 0x3f, 0x0f, 0xc3, 0xf0, 0xfc, 0x3f, 0x0f, 0xc3, + 0xf0, 0xfc, 0x3f, 0x0f, 0xc3, 0xf0, 0xfc, 0x3f, 0x0f, 0xc3, 0xf0, + 0xfc, 0x3f, 0x0f, 0xc3, 0xf0, 0xfc, 0x3f, 0x0f, 0xc3, 0xf0, 0xfc, + 0x3f, 0x0f, 0xc3, 0xf0, 0xfc, 0x3f, 0x0f, 0xc3, 0xf0, 0xfc, 0x3f, + 0x0f, 0xc3, 0xf0, 0xfc, 0x3f, 0x0f, 0xc3, 0xf0, 0xfc, 0x3f, 0x0f +}; + +static guint8 bframe_adv[] = { + 0x46, 0x03, 0x1f, 0xf0, 0x8d, 0xd8, 0xbf, 0xc0, 0xcc, 0x14, + 0x24, 0xdc, 0x60, 0xe2, 0xa8, 0x5e, 0x0d, 0xff, 0xfc, 0x3b, + 0x12, 0xfd, 0xe1, 0x2e, 0xd1, 0x84, 0xb0, 0xc2, 0xc4, 0xc1, + 0x60, 0x20, 0x4a, 0x7c, 0x33, 0xff, 0xf2, 0x10, 0xd8, 0x5c, + 0xf6, 0x7f, 0xc4, 0xd5, 0x0e, 0x0e, 0x51, 0xa8, 0x57, 0xff, + 0xfa, 0x43, 0x1f, 0xd0, 0x80, 0xdc, 0x58, 0x02, 0x02, 0xaf, + 0x10, 0xc6, 0x10, 0x12, 0x80, 0xd8, 0x07, 0xff, 0x9d, 0x00, + 0x50, 0x51, 0xa8, 0x0a, 0xd3, 0xef, 0x54, 0x03, 0xcb, 0x3f, + 0xff, 0x2b, 0x8b, 0x21, 0xcb, 0xdb, 0xf1, 0x62, 0x4e, 0x4d, + 0x8b, 0x03, 0x00, 0x16, 0x53, 0xff, 0xa6, 0x65, 0x12, 0x70, + 0xe0, 0x3f, 0xf4, 0x85, 0xb8, 0x4b, 0xc6, 0x04, 0x52, 0xff, + 0xc1, 0xf0, 0x80, 0x39, 0x85, 0x9f, 0xf4, 0xca, 0x91, 0x28, + 0x10, 0x64, 0x2c, 0xe0, 0xff, 0xff, 0x03, 0x2c, 0x3a, 0xfe, + 0x03, 0xc3, 0x2d, 0x0e, 0x60, 0x61, 0x80, 0x09, 0x9f, 0xff, + 0x03, 0x88, 0xc5, 0xd7, 0x9f, 0xfe, 0x1c, 0x14, 0x62, 0xc0, + 0x62, 0xc1, 0x7f, 0xef, 0x87, 0x7d, 0x6c, 0xbf, 0xf7, 0xc2, + 0x00, 0x10, 0x59, 0xd7, 0xfc, 0x33, 0x15, 0xbd, 0x35, 0xec, + 0x17, 0x0b, 0x07, 0x20, 0xd8, 0x42, 0x7e, 0xbf, 0xfc, 0x56, + 0xdd, 0x1f, 0x9c, 0x3a, 0x70, 0x45, 0x93, 0x01, 0x05, 0x37, + 0xb7, 0xff, 0x9f, 0x25, 0x5b, 0xb1, 0xbb, 0x87, 0x35, 0x02, + 0x70, 0x7e, 0x89, 0xb7, 0xf8, 0x5a, 0xb8, 0xb0, 0xb5, 0x04, + 0x4d, 0x2e, 0x11, 0xb9, 0x74, 0xa1, 0x95, 0xf0, 0x7f, 0x7b, + 0x38, 0x58, 0x50, 0x61, 0x9f, 0x3f, 0x80, 0x42, 0x7d, 0x15, + 0x82, 0x00, 0x1d, 0x85, 0x2b, 0x85, 0xf7, 0x14, 0x94, 0x60, + 0x42, 0x38, 0x28, 0xa8, 0x68, 0x2d, 0x28, 0x31, 0xbc, 0x36, + 0x48, 0x64, 0xc0, 0x21, 0x56, 0x30, 0xb9, 0xc0, 0x45, 0x90, + 0xe7, 0x12, 0x83, 0x84, 0xb1, 0x25, 0x86, 0x12, 0x18, 0x2d, + 0x08, 0xe8, 0x2a, 0x98, 0x8e, 0x0d, 0x00, 0xaa, 0x72, 0x75, + 0x61, 0x87, 0x00, 0x44, 0x57, 0xd4, 0x26, 0x02, 0x23, 0x90, + 0xc0, 0x04, 0x90, 0x80, 0x70, 0x46, 0x11, 0xe0, 0x20, 0x26, + 0x8c, 0x04, 0xa2, 0x88, 0x8e, 0x30, 0xc0, 0x30, 0x60, 0xdf, + 0xa2, 0xdf, 0x02, 0xd0, 0x01, 0x40, 0x99, 0x4e, 0xa4, 0x7f, + 0x84, 0x89, 0x63, 0x07, 0x0d, 0x19, 0x1d, 0x6c, 0x88, 0xca, + 0x1c, 0x1d, 0x07, 0x43, 0xc1, 0x02, 0x9c, 0x60, 0xa3, 0x09, + 0x0b, 0xc1, 0xfd, 0xa6, 0xa8, 0x21, 0x83, 0x8c, 0x08, 0x49, + 0x40, 0x56, 0xf9, 0xa6, 0x6a, 0x01, 0x52, 0x0d, 0x0e, 0x12, + 0xe1, 0x4c, 0xbf, 0x88, 0xe5, 0xa8, 0xb8, 0x02, 0x26, 0x0c, + 0x24, 0x74, 0x15, 0x38, 0x70, 0x25, 0x30, 0x24, 0x5e, 0xe0, + 0x22, 0x70, 0x68, 0x96, 0x7f, 0xec, 0x10, 0x23, 0x94, 0x30, + 0x61, 0x62, 0x38, 0xb0, 0x29, 0x2d, 0x78, 0x21, 0xb3, 0xca, + 0x40, 0xee, 0x11, 0xa0, 0x6f, 0xf8, 0x07, 0x71, 0x70, 0x47, + 0xb8, 0x5f, 0x5e, 0x89, 0x6c, 0x31, 0x58, 0x22, 0x0f, 0xff, + 0xf7, 0x17, 0x00, 0x30, 0x85, 0xf3, 0xc2, 0xb0, 0x55, 0xfe, + 0xbf, 0xfe, 0x0a, 0x7c, 0x16, 0x07, 0xf0, 0xdb, 0x81, 0xf9, + 0x40, 0x30, 0x81, 0x84, 0xac, 0x0f, 0xff, 0xe2, 0xb3, 0x4f, + 0xc3, 0x8d, 0x30, 0x76, 0x9a, 0x33, 0xa0, 0x10, 0x50, 0xc8, + 0x60, 0xae, 0x2b, 0x22, 0xff, 0xf8, 0xa9, 0x02, 0xf9, 0xf6, + 0x7a, 0x44, 0x37, 0x69, 0x8b, 0x01, 0x2b, 0x9f, 0xff, 0x81, + 0x60, 0x7a, 0xb9, 0x01, 0x0b, 0x27, 0x70, 0x40, 0xa1, 0x50, + 0x60, 0xa4, 0x61, 0xa1, 0x66, 0x30, 0x91, 0x55, 0x6f, 0xff, + 0xe6, 0x0d, 0x14, 0xae, 0xc8, 0x1a, 0x2c, 0x23, 0x4c, 0xc9, + 0x94, 0x4c, 0x07, 0x61, 0x0d, 0x46, 0x63, 0x89, 0xca, 0xbf, + 0xff, 0xea, 0x27, 0x0c, 0x30, 0x1e, 0x66, 0x1c, 0x13, 0x50, + 0xb0, 0xd8, 0x34, 0x02, 0x14, 0x30, 0x01, 0x54, 0x6a, 0xbf, + 0xff, 0x97, 0xa2, 0x3a, 0x83, 0x85, 0x04, 0x8a, 0xc2, 0x60, + 0xc0, 0x85, 0x57, 0x71, 0x61, 0x45, 0x22, 0x01, 0x07, 0x00, + 0x22, 0xff, 0xfb, 0x5b, 0xf1, 0x80, 0x8b, 0x46, 0x81, 0x68, + 0x02, 0xe2, 0x71, 0x00, 0x11, 0x81, 0x86, 0x2f, 0xff, 0xf7, + 0x5f, 0xdd, 0x42, 0x06, 0x03, 0x38, 0xb4, 0x01, 0xf6, 0xc0, + 0xff, 0xc7, 0xfb, 0xb8, 0x15, 0x0b, 0xfc, 0x1c, 0x09, 0x86, + 0x18, 0x30, 0x34, 0x15, 0x9c, 0x6a, 0x55, 0xff, 0xff, 0xbf, + 0xe2, 0xc0, 0xc3, 0x86, 0xe2, 0x38, 0x18, 0xb3, 0x14, 0x81, + 0xc0, 0x06, 0x04, 0xc2, 0x98, 0xb0, 0x12, 0x7f, 0xff, 0x8c, + 0x06, 0xbf, 0x71, 0x85, 0x0c, 0x08, 0x47, 0x11, 0x87, 0xa0, + 0xa4, 0xe0, 0x63, 0x0a, 0x0c, 0xae, 0x0a, 0xbf, 0xfe, 0xe0, + 0x78, 0xb0, 0x13, 0xb8, 0x20, 0xc3, 0x5d, 0xc5, 0x21, 0x44, + 0x82, 0x48, 0x00, 0x18, 0x24, 0x54, 0x00, 0x03, 0x5c, 0x1b, + 0xff, 0xc3, 0x9a, 0x16, 0x30, 0xb1, 0x85, 0x07, 0x38, 0xc8, + 0x59, 0x20, 0x81, 0x4c, 0x56, 0x75, 0x27, 0x0d, 0x08, 0x71, + 0x58, 0x47, 0x0e, 0x12, 0x85, 0x81, 0x61, 0xbf, 0xfc, 0x5a, + 0x4a, 0x0c, 0x28, 0x56, 0x20, 0x03, 0x14, 0x63, 0x0a, 0x2a, + 0x45, 0x80, 0xd1, 0x38, 0x28, 0x68, 0x32, 0x27, 0xa2, 0x05, + 0xff, 0xf7, 0x03, 0xe2, 0x30, 0x3c, 0x56, 0x61, 0x4e, 0x30, + 0x18, 0xad, 0x80, 0xdc, 0x15, 0x04, 0xa7, 0x0c, 0x18, 0x30, + 0x10, 0x38, 0x62, 0xff, 0xe1, 0x87, 0x3c, 0x20, 0x60, 0x63, + 0x0a, 0x02, 0x29, 0xf0, 0xc2, 0xa4, 0x2c, 0x04, 0x66, 0x2b, + 0x02, 0x72, 0xff, 0xce, 0x07, 0xd0, 0x10, 0x0e, 0x13, 0xc5, + 0x22, 0xc3, 0x02, 0x96, 0x10, 0x33, 0x18, 0x08, 0x1e, 0xe7, + 0xff, 0x9f, 0xd0, 0x61, 0xb9, 0x0a, 0xdf, 0xdc, 0x83, 0x85, + 0x61, 0x38, 0x61, 0x69, 0x24, 0x12, 0x7f, 0xf0, 0x3a, 0x73, + 0x03, 0x09, 0x87, 0x7c, 0x30, 0xb8, 0x58, 0x9c, 0x18, 0x30, + 0x05, 0xd0, 0x4c, 0xff, 0xcb, 0xe3, 0x86, 0x14, 0x5a, 0xc3, + 0x0b, 0x8a, 0xd7, 0x05, 0x15, 0x06, 0x0a, 0x00, 0x50, 0x78, + 0x93, 0xff, 0x7f, 0xc6, 0xc5, 0x97, 0xf0, 0x97, 0x18, 0x70, + 0x71, 0x8c, 0x14, 0x58, 0x03, 0xb4, 0x61, 0xa0, 0x7f, 0xef, + 0xae, 0x18, 0x29, 0x84, 0xee, 0xbf, 0x88, 0xa0, 0x33, 0x0e, + 0x11, 0x41, 0xfc, 0xff, 0xf1, 0xa8, 0xda, 0x1c, 0xa1, 0x81, + 0x05, 0x8a, 0x9f, 0xf1, 0x2c, 0x30, 0x55, 0x18, 0x40, 0xc2, + 0x7d, 0x8b, 0xf7, 0x8a, 0x80, 0x42, 0x58, 0x94, 0x30, 0x51, + 0x1c, 0x00, 0x83, 0x08, 0x4b, 0x3e, 0x1c, 0x1b, 0xe2, 0xb0, + 0x4b, 0x06, 0x03, 0x32, 0xa8, 0xc0, 0xc6, 0x08, 0xb5, 0x6c, + 0x02, 0xa6, 0x00, 0x22, 0xa0, 0xd8, 0x53, 0x1a, 0x0c, 0x0d, + 0x78, 0x97, 0x8c, 0x1c, 0x60, 0xa2, 0x5e, 0xc3, 0x21, 0x86, + 0x8c, 0x0c, 0x55, 0x41, 0x28, 0x46, 0x1b, 0x82, 0x35, 0x85, + 0x4e, 0x03, 0xc1, 0x62, 0x31, 0x8b, 0x83, 0x0b, 0x18, 0x54, + 0x30, 0xbc, 0x1c, 0x38, 0x13, 0x02, 0x08, 0x03, 0x18, 0x08, + 0x86, 0x1a, 0x36, 0x09, 0x33, 0x15, 0x1d, 0x00, 0x0b, 0xf0, + 0xc1, 0x60, 0x2c, 0x0c, 0x58, 0x13, 0x01, 0xc6, 0x0e, 0xa2, + 0xc7, 0x87, 0x0b, 0x3e, 0x16, 0x40, 0x22, 0x88, 0xb8, 0x27, + 0x11, 0x07, 0x07, 0x04, 0xf4, 0xfb, 0x84, 0x30, 0x8e, 0x08, + 0x30, 0xb2, 0x18, 0x08, 0xd8, 0x53, 0xf8, 0x8a, 0x5f, 0x15, + 0x86, 0x10, 0x1b, 0x54, 0x03, 0x11, 0x40, 0x3f, 0xe8, 0x30, + 0x84, 0x15, 0x02, 0xc4, 0x61, 0x44, 0x61, 0x62, 0xe1, 0x7f, + 0xba, 0x84, 0xe1, 0x03, 0x0b, 0x1a, 0x02, 0x2c, 0xcb, 0xfc, + 0x39, 0xc2, 0x4c, 0x26, 0x36, 0x18, 0x68, 0x19, 0x5d, 0x7f, + 0x49, 0x5c, 0x61, 0xc2, 0xd0, 0xa7, 0x42, 0xfe, 0xeb, 0x9a, + 0x01, 0x10, 0x10, 0x9c, 0x2b, 0x46, 0x00, 0x08, 0x91, 0x60, + 0x61, 0x5f, 0x1a, 0x0a, 0xce, 0x2c, 0x0b, 0x30, 0xc2, 0xff, + 0x41, 0x1f, 0xf8, 0xc0, 0x23, 0x03, 0x18, 0x69, 0x62, 0x58, + 0x0f, 0xe0, 0x43, 0x02, 0x11, 0x85, 0x21, 0x84, 0xf7, 0xff, + 0xb7, 0xc6, 0x14, 0x50, 0xc1, 0x0c, 0x66, 0xa1, 0x2e, 0xb0, + 0xc0, 0xa5, 0xd0, 0xcc, 0xc6, 0x15, 0xa8, 0xa5, 0xfc, 0x38, + 0x4b, 0x00, 0xe1, 0xc0, 0x25, 0xc4, 0x54, 0x09, 0x14, 0x50, + 0x4b, 0xd2, 0x25, 0xc5, 0x68, 0xac, 0x2a, 0x04, 0xe2, 0x90, + 0x27, 0xf1, 0x2f, 0xdc, 0x61, 0x67, 0xe2, 0x32, 0x0d, 0xc0, + 0x80, 0xe2, 0xb6, 0x2b, 0x0d, 0x8a, 0x18, 0x30, 0x51, 0x4a, + 0xbb, 0xff, 0xfc, 0x4e, 0xfc, 0x6a, 0xa2, 0xb0, 0x97, 0x0e, + 0x75, 0x0c, 0x21, 0x82, 0x06, 0x8b, 0x11, 0x86, 0x8c, 0x38, + 0x2c, 0x0c, 0x5a, 0x97, 0xff, 0x83, 0x17, 0x87, 0x20, 0x96, + 0x29, 0x05, 0x8a, 0xc6, 0x10, 0x2b, 0x38, 0x20, 0xc0, 0x06, + 0xc0, 0x82, 0xc0, 0xc8, 0x60, 0x4a, 0x1a, 0xd1, 0xaf, 0xff, + 0xb8, 0xc3, 0x38, 0x43, 0x04, 0x8a, 0x31, 0x81, 0x0a, 0x30, + 0x81, 0x86, 0x8c, 0x2c, 0x08, 0x5c, 0x18, 0x00, 0x0b, 0x82, + 0x84, 0x60, 0x0e, 0x07, 0xff, 0xf1, 0x2f, 0x0c, 0x13, 0x40, + 0x84, 0xe5, 0x41, 0x58, 0x1d, 0xf1, 0x90, 0x70, 0x94, 0x30, + 0xa6, 0x02, 0x82, 0x90, 0xb5, 0x81, 0xff, 0xfc, 0xf1, 0xbe, + 0x60, 0x4c, 0x18, 0x30, 0xe1, 0x84, 0x0a, 0x50, 0x21, 0x80, + 0x90, 0xb0, 0x2d, 0x30, 0xb4, 0x34, 0x04, 0x11, 0x6f, 0xff, + 0xf8, 0x5c, 0x61, 0x45, 0xe0, 0x40, 0x22, 0x30, 0xaa, 0x18, + 0x30, 0x41, 0x2c, 0x60, 0xc3, 0x09, 0x11, 0xe8, 0x42, 0x30, + 0x8e, 0x04, 0x0c, 0x2b, 0x7f, 0xfe, 0x80, 0x45, 0xf8, 0x8e, + 0x23, 0x0d, 0xc3, 0x81, 0x04, 0x51, 0x14, 0x0f, 0xe2, 0x1a, 0x10, + 0x07, 0xf2, 0x48, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x29, 0x96, + 0x00, 0x00, 0x00, 0x08, 0x00, 0x92, 0x03, 0x42, 0x1e, 0xc1, + 0x80, 0xba, 0x03, 0x54, 0x13, 0xe6, 0x88, 0xc0, 0xb6, 0x28, + 0x30, 0x39, 0x08, 0x01, 0x48, 0x53, 0x16, 0x03, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x4c, 0x07, 0x81, 0x00, 0x00, + 0x00, 0x50, 0x2b, 0x0a, 0x42, 0x50, 0x45, 0x85, 0x4e, 0x08, + 0x64, 0x0c, 0x58, 0x86, 0x30, 0x06, 0x06, 0x70, 0x24, 0x00, + 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x44, 0xb6, 0x1f, 0xe4, 0xb6, 0x31, 0x25, 0x43, 0xb1, 0x87, + 0xc1, 0x11, 0x86, 0xa1, 0x10, 0xe4, 0x3d, 0x5e, 0x1c, 0x42, + 0xe9, 0x64, 0xb9, 0x6b, 0x80, 0x29, 0x85, 0xdb, 0xc3, 0x4c, + 0x52, 0xb0, 0x84, 0x86, 0x88, 0x0c, 0x00, 0x02, 0x43, 0xb3, + 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x83, 0x00, 0x00, + 0x0a, 0x26, 0x8a, 0x1e, 0x82, 0x98, 0x07, 0x01, 0x51, 0x85, + 0x80, 0x42, 0x11, 0x8f, 0xd2, 0x30, 0xbf, 0x0a, 0x09, 0xcb, + 0x45, 0x10, 0x98, 0x78, 0x18, 0xe0, 0xf8, 0xf4, 0x2d, 0x01, + 0x80, 0xc0, 0x60, 0x30, 0xb8, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0xd8, 0x24, 0x00, 0x14, 0x87, 0xe0, 0x11, 0x01, 0xc1, + 0x2a, 0x07, 0x07, 0x01, 0x81, 0xa1, 0x9e, 0x74, 0x38, 0x1c, + 0x0e, 0x04, 0x2c, 0x21, 0x84, 0x02, 0xd4, 0x31, 0x00, 0xa8, + 0x82, 0x36, 0x30, 0xc8, 0xe4, 0x0c, 0x32, 0xbb, 0x8a, 0xb7, + 0x00, 0x98, 0x08, 0x2e, 0x61, 0xec, 0x00, 0x4a, 0x60, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xbf, 0xf8, 0x04, 0x03, 0x40, 0x00, + 0x45, 0xe9, 0x40, 0x40, 0xd2, 0x0a, 0x84, 0x78, 0xf4, 0x66, + 0xf8, 0x4a, 0x92, 0x82, 0x4c, 0xc9, 0xd0, 0x12, 0xb4, 0x68, + 0x83, 0x27, 0xb0, 0x36, 0x02, 0x80, 0x98, 0x09, 0x84, 0xe1, + 0x60, 0x0c, 0x0d, 0x03, 0x74, 0x0b, 0x86, 0x40, 0x1e, 0x89, + 0xf0, 0x1f, 0x81, 0x4e, 0x00, 0x2b, 0xf0, 0x04, 0x80, 0x00, + 0x00, 0x00, 0x00, 0x03, 0x78, 0x00, 0x00, 0x09, 0x96, 0x24, + 0x09, 0x0d, 0x14, 0x03, 0x87, 0x80, 0xe8, 0x54, 0x09, 0x0f, + 0xf4, 0x09, 0x33, 0x9e, 0xd0, 0x4e, 0x0c, 0x31, 0x80, 0x41, + 0x84, 0x98, 0xe3, 0xc1, 0x88, 0x27, 0xa0, 0xd2, 0x0a, 0x90, + 0x66, 0x4b, 0x0d, 0xc0, 0xac, 0x61, 0x97, 0x9c, 0x12, 0x1b, + 0xec, 0x51, 0x5c, 0x48, 0xa2, 0x9e, 0x1d, 0x03, 0x12, 0x03, + 0x0c, 0xe4, 0x53, 0xb2, 0x80, 0x1c, 0xe2, 0xc2, 0xc0, 0x00, + 0x00, 0x00, 0x00, 0x05, 0x60, 0x01, 0x57, 0x04, 0x86, 0x48, + 0x04, 0xf9, 0x01, 0x20, 0x2e, 0x15, 0x94, 0x01, 0x0e, 0xf2, + 0x9f, 0x40, 0x51, 0x6c, 0x0d, 0x06, 0x24, 0x50, 0x48, 0x00, + 0x83, 0x65, 0x05, 0x67, 0x25, 0x36, 0x7a, 0x26, 0x83, 0xd1, + 0x9e, 0xc2, 0x7f, 0x40, 0xd0, 0x2a, 0x14, 0x26, 0xb8, 0xac, + 0x64, 0x86, 0xd8, 0x47, 0x84, 0x89, 0x4e, 0x79, 0xc8, 0x21, + 0x4c, 0x24, 0x17, 0xa6, 0x6a, 0x51, 0x32, 0x6b, 0x93, 0x20, + 0xa1, 0x72, 0x65, 0x97, 0x77, 0x03, 0x18, 0x88, 0x41, 0xe0, + 0x88, 0x40, 0x21, 0x4e, 0xb6, 0x05, 0x60, 0x02, 0x40, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x8f, 0x03, 0x44, 0xc0, + 0x23, 0x20, 0x06, 0x88, 0x32, 0x16, 0x19, 0xc2, 0xc9, 0x79, + 0xf4, 0xd9, 0x3d, 0x32, 0x22, 0xc9, 0x4e, 0x41, 0x80, 0x4c, + 0x34, 0x0b, 0x31, 0x82, 0x19, 0x80, 0x93, 0x3c, 0xf2, 0x04, + 0xa4, 0x39, 0x21, 0x8c, 0xd6, 0x12, 0x40, 0x80, 0x84, 0x1a, + 0x6e, 0xe3, 0x09, 0xe8, 0x4c, 0x1a, 0x00, 0xe0, 0x49, 0xa8, + 0x02, 0xb2, 0x31, 0x06, 0x60, 0xf8, 0x28, 0x11, 0x68, 0x24, + 0x14, 0x82, 0xfc, 0x82, 0xf9, 0x82, 0x07, 0x48, 0xab, 0x25, + 0xca, 0x0e, 0x44, 0x6a, 0x28, 0x24, 0x28, 0x54, 0x1a, 0x80, + 0x44, 0x46, 0x80, 0xa4, 0x63, 0x2e, 0x02, 0x90, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x01, 0x21, 0xbf, 0xc1, 0xa0, 0x78, 0x2c, + 0xc5, 0xde, 0x80, 0xc0, 0x4c, 0x22, 0x22, 0x53, 0x01, 0xc8, + 0x38, 0x18, 0x42, 0xbb, 0x05, 0xb3, 0x26, 0xc0, 0xf6, 0x4b, + 0x01, 0xd0, 0x12, 0x01, 0xac, 0x0f, 0x18, 0x73, 0x6d, 0x2c, + 0x8c, 0x85, 0x28, 0x4c, 0x90, 0x80, 0x10, 0x82, 0x5d, 0x50, + 0x13, 0xd6, 0x34, 0xc8, 0x08, 0x4b, 0x09, 0x86, 0x64, 0x06, + 0xb3, 0xdd, 0xa6, 0x4b, 0xd2, 0x6c, 0x97, 0x27, 0xf0, 0x8d, + 0x45, 0xd1, 0x81, 0xc2, 0x0c, 0x2e, 0x44, 0x98, 0xe1, 0x26, + 0xbd, 0xaa, 0x12, 0x6b, 0xfb, 0x80, 0x90, 0xdc, 0x42, 0x16, + 0xdf, 0xd4, 0xd4, 0x08, 0x5c, 0xa3, 0x75, 0xbc, 0x82, 0x09, + 0x83, 0x01, 0x81, 0x70, 0xbb, 0x30, 0xb4, 0x41, 0x4c, 0x68, + 0x30, 0x29, 0x02, 0x82, 0x1f, 0x0c, 0x71, 0x40, 0x00, 0x00, + 0x00, 0x00, 0x07, 0x83, 0x80, 0x18, 0x06, 0x10, 0x47, 0x43, + 0xb0, 0x48, 0x81, 0xa0, 0x13, 0x6d, 0x9c, 0x84, 0xc5, 0xd9, + 0x85, 0x6e, 0x15, 0x79, 0x5c, 0xc5, 0x32, 0xf8, 0x51, 0x31, + 0x96, 0x2e, 0x00, 0x01, 0x05, 0xc0, 0x92, 0x89, 0x08, 0x60, + 0x9b, 0x32, 0x58, 0x25, 0xad, 0xc0, 0x8a, 0x18, 0x66, 0x43, + 0x58, 0x51, 0xb0, 0x11, 0x08, 0x94, 0x01, 0x22, 0x5b, 0xe0, + 0x4c, 0x84, 0x14, 0x80, 0x4a, 0x9c, 0x02, 0x8a, 0x00, 0x38, + 0xe1, 0xf5, 0x3b, 0x20, 0x21, 0x28, 0x1e, 0x0b, 0xd8, 0x80, + 0x81, 0x8a, 0x89, 0x64, 0xb1, 0x2f, 0xe3, 0x30, 0x2d, 0xd4, + 0x20, 0x08, 0x43, 0xf1, 0x19, 0x0a, 0x85, 0x9e, 0xb2, 0xd0, + 0x00, 0x54, 0x56, 0x50, 0x2c, 0x04, 0x80, 0xee, 0x0e, 0x8a, + 0x54, 0x29, 0x10, 0xa5, 0x82, 0xfb, 0x82, 0xc3, 0x80, 0x10, + 0x04, 0x00, 0x00, 0x00, 0x00, 0x01, 0x37, 0xf0, 0x00, 0x01, + 0xeb, 0x59, 0x3d, 0x83, 0x21, 0x41, 0xf6, 0xdd, 0x22, 0xc9, + 0x72, 0x6c, 0x8a, 0xc1, 0x04, 0x9a, 0x5b, 0x94, 0x12, 0x1e, + 0x5a, 0x09, 0x11, 0x2c, 0x0a, 0x2d, 0x05, 0x6b, 0x57, 0x64, + 0xcc, 0x34, 0x47, 0x00, 0x88, 0x2a, 0xa0, 0x7a, 0x41, 0x8b, + 0xb2, 0x88, 0x20, 0x9b, 0xf0, 0x24, 0x40, 0x46, 0x09, 0x54, + 0xe0, 0x68, 0x27, 0xf0, 0x09, 0x68, 0x80, 0xb4, 0x23, 0x53, + 0x38, 0x84, 0x1f, 0x02, 0x6d, 0x62, 0x05, 0x78, 0x49, 0x98, + 0x0e, 0x18, 0xc6, 0x43, 0x20, 0x21, 0x02, 0x0a, 0x44, 0x64, + 0x1c, 0x1d, 0x04, 0xa0, 0xc8, 0x07, 0x07, 0xe1, 0x28, 0xa6, + 0x6c, 0x37, 0xc5, 0x51, 0x86, 0xdd, 0x00, 0xbd, 0x00, 0x00, + 0x00, 0x00, 0x01, 0x2b, 0x80, 0x01, 0xb3, 0x13, 0xe8, 0x76, + 0x09, 0xea, 0x04, 0x23, 0x0b, 0x21, 0x01, 0x02, 0x18, 0x07, + 0x00, 0x8c, 0xd2, 0x0d, 0x64, 0xc8, 0x1b, 0x09, 0x30, 0x48, + 0xa5, 0x97, 0x0d, 0x20, 0xa0, 0x91, 0x27, 0x08, 0x32, 0x41, + 0x56, 0x04, 0x99, 0xcf, 0x20, 0x4a, 0x09, 0xb8, 0x86, 0x49, + 0x19, 0xc0, 0x48, 0xd4, 0xf3, 0x82, 0xae, 0x38, 0x63, 0x04, + 0x26, 0x16, 0x1e, 0x30, 0xd7, 0x4c, 0x80, 0x12, 0x50, 0xfd, + 0x92, 0xe2, 0x03, 0x9f, 0x40, 0x2b, 0x67, 0x38, 0x16, 0x17, + 0x4f, 0xf9, 0x76, 0xaf, 0x09, 0x8b, 0xb9, 0x84, 0x00, 0x02, + 0x8f, 0x2c, 0x00, 0x5d, 0x03, 0x50, 0x00, 0x42, 0x13, 0x06, + 0x60, 0x96, 0xc3, 0xd0, 0x00, 0x3c, 0x10, 0xc0, 0x4e, 0x02, + 0x00, 0x04, 0xe0, 0xf0, 0x23, 0x60, 0x00, 0x00, 0x00, 0x00, + 0x24, 0x1b, 0xe0, 0x00, 0x04, 0x02, 0xe9, 0x4c, 0x97, 0x26, + 0x40, 0x70, 0x24, 0x3b, 0x50, 0xb6, 0x40, 0x54, 0x41, 0x26, + 0x79, 0xa4, 0x94, 0xbc, 0xc5, 0x97, 0x18, 0x61, 0x88, 0x2e, + 0x70, 0x22, 0x62, 0x3c, 0x02, 0x05, 0x80, 0x90, 0xea, 0x06, + 0x68, 0xf4, 0xb2, 0x66, 0x06, 0x09, 0x33, 0x07, 0x54, 0x83, + 0x64, 0xcc, 0x28, 0xc1, 0x60, 0xba, 0x08, 0x8d, 0x1a, 0xf1, + 0xa0, 0x84, 0x85, 0x81, 0x94, 0x23, 0x06, 0x2f, 0x22, 0xb2, +}; + +static guint8 bframe2_adv[] = { + 0x46, 0x88, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x03, 0xf8, 0xa1, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, +}; + +static guint8 pframe_adv[] = { + 0x24, 0x20, 0x04, 0xbf, 0x85, 0x88, 0x65, 0xc1, 0x00, 0xdc, + 0x4c, 0x06, 0xce, 0x05, 0x01, 0x01, 0x41, 0x0c, 0x60, 0x42, + 0x67, 0xff, 0xfb, 0x85, 0x0b, 0x9c, 0x56, 0x0d, 0x0b, 0x1b, + 0x8c, 0x08, 0x08, 0x47, 0x1b, 0xce, 0xc1, 0x83, 0x09, 0x8a, + 0xa1, 0x83, 0x09, 0x16, 0x7f, 0xff, 0x98, 0x94, 0xff, 0x81, + 0x4f, 0xf9, 0x41, 0xe1, 0x83, 0x01, 0xff, 0xff, 0x14, 0x40, + 0xcd, 0x70, 0xd7, 0xf2, 0xf7, 0xc1, 0xf1, 0x18, 0x59, 0xff, + 0xfc, 0x51, 0x18, 0x68, 0x2c, 0xd4, 0x54, 0x16, 0xbf, 0xfe, + 0x0c, 0xf1, 0x81, 0x28, 0x67, 0xff, 0x86, 0x39, 0x05, 0xe6, + 0x5f, 0xff, 0xe0, 0x48, 0xc0, 0xff, 0xfe, 0x61, 0x18, 0x37, + 0xff, 0x97, 0xdc, 0x1c, 0x45, 0x06, 0x06, 0xff, 0xf0, 0x30, + 0x7d, 0x17, 0xff, 0xff, 0x86, 0x07, 0x03, 0xff, 0xf9, 0x01, + 0xf0, 0x7f, 0xff, 0xdf, 0xc1, 0x20, 0x9f, 0xfd, 0x0c, 0x0f, + 0x86, 0x7f, 0xff, 0xee, 0x50, 0xef, 0xfe, 0xc1, 0xa5, 0xc6, + 0x1b, 0xff, 0xff, 0x86, 0x61, 0x9f, 0xfc, 0x1c, 0x1f, 0xa2, + 0xff, 0xff, 0xe0, 0xf8, 0x10, 0x1f, 0xfe, 0x0e, 0x0f, 0x99, + 0x95, 0xff, 0xff, 0xb8, 0x3e, 0xe5, 0xff, 0x81, 0x83, 0xe1, + 0x6b, 0xff, 0xff, 0x40, 0xc0, 0x7c, 0x30, 0xbf, 0xe0, 0xb2, + 0x0e, 0x09, 0x61, 0x53, 0xff, 0xfd, 0x60, 0x20, 0xfc, 0x27, + 0xf0, 0x96, 0x51, 0x26, 0x6c, 0xcf, 0xff, 0xff, 0xe7, 0x60, + 0xe0, 0xb5, 0xee, 0x82, 0xa0, 0xb8, 0x41, 0x32, 0x3f, 0x2f, + 0xcd, 0x3f, 0xa0, 0xa8, 0x96, 0x8e, 0x2a, 0x4c, 0x08, 0x6e, + 0x36, 0x1a, 0x83, 0x2a, 0x8b, 0x02, 0xcb, 0x2f, 0xff, 0xe9, + 0xf8, 0xa4, 0x0e, 0x00, 0x12, 0xc1, 0x88, 0xc3, 0x0c, 0x05, + 0x51, 0x44, 0x61, 0xa3, 0x0b, 0x18, 0x58, 0x38, 0x70, 0x97, + 0xff, 0xff, 0xf8, 0x8c, 0x14, 0x2c, 0x0c, 0x19, 0x86, 0x0c, + 0x27, 0x09, 0xc1, 0x03, 0x08, 0x62, 0xc0, 0xff, 0xff, 0xfe, + 0x94, 0x6d, 0x22, 0x77, 0xc0, 0x44, 0x71, 0x1c, 0x60, 0xe5, + 0xb7, 0xff, 0xfe, 0xbf, 0xba, 0x57, 0x82, 0x0c, 0x24, 0xc8, + 0x5a, 0xbf, 0xff, 0xff, 0xcb, 0x14, 0xc8, 0x30, 0x43, 0x16, + 0x29, 0x51, 0x86, 0x0b, 0x00, 0x51, 0x60, 0x60, 0xc0, 0x17, + 0x75, 0xff, 0xf9, 0x77, 0x0e, 0x18, 0x4b, 0x84, 0xc5, 0x47, + 0x11, 0xc5, 0x10, 0x68, 0x1b, 0x8c, 0x00, 0x6a, 0x71, 0x60, + 0xc0, 0x46, 0xe2, 0xe0, 0x22, 0x65, 0xff, 0xd6, 0x09, 0x0e, + 0x01, 0x15, 0x55, 0x85, 0x48, 0x28, 0x8f, 0xc2, 0x42, 0x06, + 0x1c, 0x23, 0x8b, 0x01, 0x42, 0x74, 0x08, 0x61, 0x9f, 0xff, + 0xc2, 0xca, 0x19, 0x81, 0x02, 0x10, 0x20, 0xc0, 0x1c, 0x5c, + 0x13, 0x84, 0xe6, 0x1a, 0x8b, 0x02, 0x38, 0x98, 0x09, 0x98, + 0xa3, 0xff, 0xfd, 0xc9, 0x05, 0x5e, 0x82, 0x18, 0xc1, 0x40, + 0xc6, 0xf6, 0x04, 0x14, 0x40, 0x60, 0x80, 0xfd, 0x04, 0x6f, + 0xff, 0xf4, 0x58, 0x0a, 0xf8, 0x86, 0x30, 0x02, 0x14, 0x44, + 0xe2, 0xc2, 0x43, 0x3c, 0x1b, 0xff, 0x86, 0xb5, 0x66, 0x16, + 0xf0, 0x7f, 0xa0, 0x9c, 0x5e, 0x84, 0x07, 0xd1, 0x73, 0xff, + 0xee, 0x88, 0xc2, 0xe1, 0x7f, 0xfc, 0xc0, 0xf0, 0x59, 0x65, + 0xfe, 0x9f, 0x70, 0xbf, 0xff, 0xdc, 0x1e, 0x2a, 0x02, 0x57, + 0xff, 0xc0, 0x26, 0x2d, 0x3c, 0x4d, 0x5f, 0xff, 0xc4, 0xc1, + 0x30, 0x11, 0x15, 0xc4, 0xaf, 0xfc, 0x5c, 0x0e, 0x0e, 0x0e, + 0x84, 0x8c, 0x34, 0x34, 0xbf, 0xff, 0x11, 0x81, 0x30, 0x10, + 0x48, 0x87, 0xf9, 0x43, 0x05, 0x25, 0x04, 0x11, 0x43, 0x70, + 0x4f, 0xff, 0xfd, 0x04, 0xe1, 0x0e, 0xfe, 0x6f, 0x83, 0x88, + 0xe1, 0x98, 0x76, 0x0f, 0xfc, 0x89, 0x0e, 0xe7, 0xc2, 0x78, + 0x4c, 0x24, 0xd4, 0x18, 0x8c, 0xbf, 0x27, 0x16, 0xd0, 0xb0, + 0xc9, 0xf4, 0x12, 0x6a, 0x08, 0xe4, 0x5c, 0x24, 0xbf, 0x46, + 0x60, 0xf6, 0x53, 0xf5, 0x6c, 0xff, 0x2e, 0x32, 0x09, 0x1e, + 0xab, 0x09, 0x00, 0x1e, 0x88, 0x56, 0x6e, 0x7a, 0x1c, 0xd0, + 0x30, 0x3c, 0xab, 0xf0, 0x44, 0x5a, 0x90, 0x4f, 0x9a, 0xf0, + 0xe6, 0x7d, 0x62, 0xc1, 0x87, 0x4b, 0xdb, 0xfd, 0x68, 0xd9, + 0x35, 0x3b, 0x01, 0x04, 0x81, 0x2c, 0x24, 0xee, 0xb3, 0x9b, + 0x65, 0x30, 0x49, 0x20, 0xa8, 0x08, 0xf6, 0xaf, 0x33, 0x80, + 0x38, 0x49, 0xa3, 0x94, 0x6e, 0x35, 0x06, 0x4d, 0xc3, 0x30, + 0x92, 0x7c, 0x3c, 0x6b, 0x9e, 0xd5, 0x31, 0x4d, 0x69, 0x87, + 0x2e, 0x04, 0x7e, 0x04, 0x12, 0x5f, 0xa3, 0x0a, 0xe4, 0x5b, + 0x21, 0x6c, 0x45, 0x54, 0x29, 0x11, 0x48, 0x8a, 0xa8, 0x52, + 0x22, 0xa8, 0x33, 0x06, 0xe0, 0xbd, 0xe8, 0x41, 0x00, 0x03, + 0x52, 0xe7, 0x00, 0x7d, 0xf0, 0x42, 0x4d, 0x0f, 0x20, 0x26, + 0x24, 0x09, 0xbb, 0x48, 0x1c, 0xeb, 0xa5, 0xa2, 0x0e, 0xed, + 0x11, 0x66, 0x97, 0x93, 0xb8, 0x4a, 0x70, 0x8a, 0x75, 0x38, + 0x47, 0xc1, 0x26, 0x3e, 0x50, 0x87, 0x33, 0xf2, 0x37, 0xc7, + 0x3b, 0x67, 0x09, 0x33, 0x44, 0xfc, 0xcd, 0xda, 0x19, 0xa6, + 0x3f, 0x27, 0xec, 0x24, 0x12, 0x64, 0x06, 0x13, 0xdd, 0x9e, + 0x81, 0x92, 0x17, 0x5f, 0xb3, 0xd9, 0x37, 0xf2, 0x0f, 0x15, + 0x00, 0x87, 0xb3, 0xe6, 0xc9, 0xc1, 0xbc, 0x24, 0x7f, 0x0f, + 0x7c, 0x76, 0x4c, 0xe0, 0xfb, 0xf7, 0x66, 0x4c, 0x9c, 0x19, + 0x32, 0x6f, 0xb2, 0x64, 0xfa, 0x00, 0x01, 0x26, 0xaa, 0xa4, + 0x16, 0x45, 0x1f, 0x94, 0xee, 0xde, 0x33, 0x09, 0x2e, 0x48, + 0xc2, 0x4b, 0xf4, 0x62, 0x91, 0x16, 0x00, 0x52, 0x20, 0xe2, + 0xba, 0xe2, 0x35, 0x42, 0xa7, 0xa0, 0x9c, 0x9e, 0xcc, 0x39, + 0x9d, 0x31, 0x00, 0xc3, 0xe0, 0x2a, 0x1f, 0x85, 0x61, 0xd3, + 0x63, 0x3f, 0x22, 0xa8, 0xd9, 0xc1, 0x50, 0x50, 0x2f, 0x21, + 0xb1, 0xd8, 0x49, 0x34, 0xa0, 0xb0, 0x0c, 0x7d, 0xe9, 0x53, + 0x27, 0x09, 0xf9, 0x1b, 0x33, 0x5d, 0x93, 0xb8, 0x48, 0x89, + 0xbb, 0x18, 0x4e, 0xf0, 0x44, 0x86, 0x13, 0x7a, 0x16, 0xc4, + 0x36, 0xc7, 0x24, 0xe2, 0x39, 0x20, 0x20, 0x62, 0xb0, 0xf1, + 0xa0, 0x21, 0xc7, 0x2a, 0xdf, 0xd6, 0xd1, 0x5e, 0xcf, 0xba, + 0x09, 0x92, 0xa4, 0xb7, 0xd6, 0x7b, 0x0b, 0xaa, 0x60, 0xe7, + 0x8c, 0xe2, 0xfb, 0xf8, 0xb1, 0x96, 0x70, 0xc5, 0xf7, 0x3d, + 0x7a, 0xce, 0x13, 0x09, 0x0f, 0xd4, 0x2c, 0xfe, 0x30, 0xdd, + 0xdc, 0x11, 0xb1, 0x4e, 0xab, 0x98, 0x0d, 0x45, 0xf0, 0x41, + 0x9d, 0x0c, 0xd6, 0xa1, 0x8e, 0x5c, 0xf4, 0xdf, 0x93, 0x88, + 0x3f, 0x23, 0x61, 0x23, 0x6e, 0xf4, 0x78, 0xac, 0xfa, 0x00, + 0x00, 0x07, 0x1f, 0x94, 0xe9, 0x13, 0xd3, 0x05, 0x61, 0x99, + 0x22, 0x49, 0xf8, 0x6d, 0xb9, 0xb3, 0x83, 0xa6, 0x70, 0x78, + 0xf3, 0x37, 0x54, 0xdf, 0xb6, 0x82, 0x67, 0x07, 0x3d, 0x66, + 0xea, 0x86, 0x72, 0xd3, 0x38, 0x3b, 0x0a, 0xcd, 0xd5, 0x0e, + 0x00, 0x07, 0x19, 0x6d, 0x92, 0x77, 0x3e, 0x0d, 0xba, 0x66, + 0xa6, 0x8c, 0x8d, 0x48, 0xf2, 0xe2, 0x38, 0x31, 0x7f, 0x71, + 0xf9, 0xe8, 0x6c, 0x46, 0xb1, 0x91, 0xc5, 0x6a, 0xbb, 0x16, + 0x36, 0x44, 0xb3, 0x67, 0x64, 0xcf, 0xee, 0xcc, 0x04, 0x61, + 0x7b, 0x91, 0x7e, 0xcd, 0x47, 0x27, 0x16, 0x0f, 0x04, 0x8f, + 0x02, 0x84, 0x8f, 0x85, 0xb5, 0xb3, 0x5a, 0x81, 0x23, 0xa8, +}; + +static guint8 pframe2_adv[] = { + 0x1c, 0x22, 0x1f, 0xdc, 0x9d, 0x3b, 0x81, 0x61, 0x85, 0x2, + 0x57, 0xa0, 0x50, 0xac, 0x03, 0x81, 0x0c, 0x39, 0x4f, 0xff, + 0xc2, 0x20, 0x9f, 0xf4, 0x86, 0x16, 0x8e, 0xe1, 0xda, 0x0c, + 0x24, 0x4b, 0x3f, 0xff, 0x03, 0x77, 0xfe, 0x05, 0x10, 0xc5, + 0x81, 0x3a, 0x50, 0x71, 0x4c, 0x56, 0x10, 0xfa, 0x06, 0x82, + 0xaf, 0xfe, 0x19, 0x49, 0x17, 0xb6, 0x42, 0xad, 0xf0, 0xe8, + 0x6f, 0xc0, 0x97, 0xff, 0x83, 0xd0, 0xce, 0x15, 0x16, 0x85, + 0xa6, 0x77, 0x09, 0xb3, 0xe1, 0x88, 0x30, 0xd0, 0x0f, 0x18, + 0x60, 0x40, 0x5f, 0xfe, 0x07, 0x6f, 0x6c, 0x18, 0x09, 0xdf, + 0xc3, 0x00, 0xee, 0x98, 0x39, 0x8b, 0x40, 0xff, 0xf8, 0x64, + 0xfb, 0xae, 0xae, 0x25, 0xc1, 0x61, 0xa1, 0xa1, 0x63, 0x06, + 0xba, 0xb8, 0x9a, 0x00, 0xe6, 0x40, 0x75, 0xff, 0x08, 0xfc, + 0xa2, 0x88, 0xa2, 0xf7, 0xd4, 0x47, 0xe2, 0x8b, 0x20, 0x11, + 0x02, 0xe0, 0xc1, 0x80, 0xdf, 0xe0, 0xff, 0xe2, 0x18, 0xe0, + 0x40, 0x42, 0xe0, 0xc0, 0x82, 0x59, 0x49, 0x9c, 0x4c, 0x60, + 0x95, 0x86, 0x60, 0xff, 0xf8, 0x22, 0x7d, 0x21, 0xa1, 0x62, + 0x60, 0xc0, 0x06, 0x06, 0x30, 0x90, 0xa0, 0xc1, 0xbb, 0xa0, + 0x10, 0x8e, 0xcf, 0xca, 0x17, 0x4f, 0xf0, 0x34, 0xfb, 0x00, + 0x88, 0xe0, 0xa3, 0x07, 0x04, 0x18, 0x30, 0xe2, 0xc8, 0x50, + 0xb4, 0x14, 0xac, 0x12, 0x9d, 0x30, 0xcf, 0xfb, 0x97, 0xeb, + 0x42, 0x14, 0x83, 0x45, 0x30, 0x31, 0x70, 0x4d, 0x14, 0xc5, + 0x10, 0x51, 0x4c, 0x61, 0x21, 0x4f, 0xf8, 0x1d, 0x7f, 0x0c, + 0xf8, 0x30, 0x1e, 0xa3, 0x00, 0x08, 0x0b, 0x15, 0x46, 0x0a, + 0x0a, 0x26, 0x87, 0x02, 0x06, 0x0a, 0xa3, 0x0a, 0x54, 0x18, + 0x62, 0x80, 0x70, 0x3f, 0xf0, 0xcf, 0xe6, 0x0e, 0x1a, 0x82, + 0x34, 0x30, 0x59, 0x14, 0xc6, 0xa3, 0x04, 0x18, 0x70, 0xc1, + 0x82, 0xc6, 0x05, 0x21, 0x27, 0xe0, 0x7f, 0xe1, 0x8d, 0xae, + 0x91, 0x6a, 0x1c, 0x04, 0x30, 0x00, 0xc1, 0xba, 0x90, 0x59, + 0x89, 0xda, 0xd4, 0x61, 0x8b, 0xc1, 0xfe, 0xda, 0x8c, 0x30, + 0xa0, 0x3d, 0xa3, 0x06, 0x0d, 0x01, 0x85, 0x08, 0x6e, 0x16, + 0x04, 0x30, 0x01, 0x30, 0x51, 0x06, 0x15, 0x1a, 0x03, 0xe2, + 0xd5, 0xeb, 0xa1, 0x98, 0x2d, 0x02, 0x97, 0x77, 0x57, 0x16, + 0x05, 0x61, 0x14, 0x92, 0x32, 0x50, 0x01, 0x4c, 0x46, 0x18, + 0x40, 0x97, 0x9a, 0x0a, 0x97, 0x70, 0xaf, 0x84, 0x84, 0xbd, + 0x7a, 0x45, 0x60, 0xa1, 0x14, 0x47, 0x17, 0x06, 0x00, 0x30, + 0x29, 0x44, 0x51, 0x24, 0x60, 0x62, 0x30, 0x15, 0x08, 0x19, + 0xda, 0xa2, 0x32, 0x06, 0x81, 0xf0, 0x0c, 0x30, 0x43, 0xeb, + 0x00, 0x06, 0x40, 0x60, 0x40, 0xb0, 0xe1, 0x68, 0x34, 0x0c, + 0x04, 0x6e, 0x29, 0x08, 0xc3, 0x01, 0x1b, 0x06, 0xe0, 0x00, + 0x37, 0x55, 0x03, 0xdc, 0x0e, 0xea, 0x04, 0xb2, 0xda, 0x09, + 0x21, 0x54, 0x60, 0xa2, 0x5d, 0x86, 0x02, 0x22, 0x81, 0x80, + 0x0b, 0x44, 0x82, 0x3d, 0x04, 0x71, 0x4a, 0x10, 0x11, 0xfc, + 0x61, 0x04, 0xc0, 0x5b, 0x01, 0x00, 0x46, 0x12, 0x07, 0x11, + 0x83, 0x05, 0x31, 0x24, 0x4a, 0x0c, 0x09, 0x04, 0x15, 0x00, + 0xd0, 0xdc, 0x0f, 0xd3, 0xfd, 0xc5, 0x86, 0x38, 0x5f, 0x85, + 0xc0, 0x42, 0xc2, 0x48, 0x61, 0x20, 0x41, 0x62, 0x48, 0xb0, + 0x0a, 0x49, 0x60, 0xb8, 0x96, 0xef, 0xad, 0xba, 0x60, 0x23, + 0x88, 0xa2, 0x39, 0x60, 0xa8, 0x23, 0x86, 0x8d, 0x02, 0x81, + 0x86, 0x18, 0x30, 0x23, 0x13, 0x42, 0xa3, 0x5b, 0x38, 0x14, + 0x20, 0x5a, 0x18, 0x4a, 0xae, 0x68, 0x8d, 0x4a, 0x8c, 0x00, + 0x51, 0x0e, 0x63, 0x18, 0x10, 0x9a, 0x0c, 0x70, 0x41, 0x38, + 0x46, 0x21, 0x18, 0x25, 0x00, 0x50, 0x95, 0xb8, 0x38, 0x75, + 0xe1, 0xab, 0xe8, 0xa2, 0x3f, 0x18, 0x77, 0xb9, 0xc5, 0x81, + 0x86, 0x0b, 0x2a, 0x21, 0x8c, 0x08, 0x2e, 0x2a, 0x0a, 0xa4, + 0x10, 0xd8, 0x58, 0x3e, 0x80, 0x25, 0x09, 0xcf, 0x47, 0x16, + 0xb9, 0x8a, 0x8e, 0x26, 0x0a, 0x76, 0x51, 0x18, 0x80, 0x19, + 0xa8, 0x0c, 0x9e, 0x5f, 0x6f, 0xd8, 0x59, 0xf7, 0x05, 0x13, + 0x14, 0x53, 0x30, 0x40, 0xa5, 0x04, 0x55, 0xb1, 0x00, 0x55, + 0x74, 0xf9, 0x83, 0xd4, 0xf1, 0x37, 0xee, 0x16, 0x32, 0x12, + 0xf4, 0x14, 0xc8, 0x4b, 0x30, 0xd4, 0x02, 0x92, 0x80, 0x61, + 0x02, 0x88, 0x94, 0xbf, 0xf8, 0x18, 0xc3, 0x97, 0xe5, 0x58, + 0xa8, 0x35, 0x98, 0x1a, 0xc1, 0x41, 0xd4, 0x19, 0xc6, 0x18, + 0x48, 0xb0, 0xbf, 0xfc, 0x1c, 0x56, 0x6e, 0x13, 0xcc, 0x04, + 0x4b, 0x07, 0x27, 0x55, 0x2f, 0x7d, 0x44, 0x61, 0x65, 0x3f, + 0xf0, 0xc0, 0xc0, 0xab, 0x89, 0x83, 0x0d, 0x67, 0x16, 0x00, + 0xc8, 0xa1, 0x84, 0x41, 0x95, 0x33, 0xb8, 0x2e, 0x18, 0x25, + 0xff, 0xf8, 0x18, 0x96, 0xa2, 0xc0, 0x18, 0x58, 0x06, 0x3a, + 0xbf, 0xc1, 0x96, 0xed, 0x10, 0xc4, 0x98, 0xc0, 0x46, 0x13, + 0xff, 0xe1, 0x63, 0x03, 0x17, 0x01, 0x6e, 0x74, 0x06, 0x70, + 0x2a, 0x6a, 0xb3, 0x74, 0x07, 0x61, 0x58, 0x2c, 0x2d, 0xbf, + 0xfd, 0x01, 0x42, 0x30, 0x85, 0xfb, 0xc6, 0x1a, 0x0a, 0x14, + 0x2c, 0x5c, 0x08, 0xbc, 0x43, 0x2f, 0xc2, 0x5f, 0x72, 0x8b, + 0x9c, 0x32, 0x06, 0x0a, 0x27, 0x03, 0x50, 0x61, 0x5f, 0x41, + 0x4e, 0x19, 0x83, 0xff, 0xfb, 0x42, 0x3e, 0x6e, 0x34, 0x12, + 0x7f, 0x75, 0x18, 0x04, 0x1f, 0x06, 0x86, 0x7f, 0xf9, 0x44, + 0x97, 0xee, 0x0d, 0xe9, 0xf2, 0x38, 0x3e, 0xf8, 0x37, 0xfe, + 0x98, 0x1c, 0xd6, 0x30, 0x11, 0x2f, 0xff, 0xe0, 0x76, 0x50, + 0x38, 0x5f, 0xfe, 0x70, 0xc4, 0x29, 0x0b, 0x82, 0x2f, 0xff, + 0xe0, 0x62, 0x48, 0xc3, 0x85, 0x10, 0xa1, 0x69, 0x17, 0xfe, + 0x50, 0xc8, 0x5f, 0x4f, 0xff, 0xfc, 0x30, 0xa0, 0x7f, 0xe9, + 0x0c, 0x00, 0xc2, 0x7f, 0xff, 0xf9, 0x0a, 0x82, 0x56, 0x0d, + 0xfe, 0xd0, 0x8e, 0xff, 0xff, 0xfd, 0x04, 0x64, 0x58, 0x5f, + 0xfe, 0x0f, 0xdc, 0x5a, 0xff, 0xff, 0xe0, 0x9c, 0x33, 0xfd, + 0x60, 0x7c, 0x38, 0x0f, 0xff, 0xff, 0x81, 0xf8, 0x1f, 0xfc, + 0x0f, 0x82, 0x7f, 0xff, 0xe8, 0xe5, 0x3c, 0x0f, 0xf7, 0xc0, + 0xf8, 0xc3, 0x17, 0xff, 0xff, 0x13, 0x37, 0xc1, 0xbf, 0xe0, + 0x70, 0xcc, 0xbf, 0xff, 0xf1, 0x85, 0xfc, 0x1f, 0xfe, 0x07, + 0x83, 0x2f, 0xff, 0xff, 0x1b, 0x7c, 0x1f, 0xfd, 0x42, 0x94, + 0x36, 0x9f, 0xff, 0xfc, 0x1f, 0xe0, 0xfd, 0x99, 0x86, 0x02, + 0x1a, 0x29, 0x81, 0x21, 0x7f, 0xff, 0xfc, 0x83, 0x95, 0x85, + 0x11, 0x60, 0x60, 0x22, 0xc8, 0xd0, 0xc2, 0xc4, 0xb5, 0x83, + 0x95, 0x27, 0xa7, 0xff, 0xfc, 0x85, 0x85, 0xb4, 0x47, 0x24, + 0x18, 0x28, 0xaa, 0x1a, 0x23, 0x2a, 0x84, 0xdb, 0xff, 0xff, + 0xf2, 0x63, 0x92, 0xc4, 0xc0, 0x21, 0xc0, 0xc2, 0xc0, 0x00, + 0x82, 0xc6, 0x00, 0x28, 0x89, 0x72, 0xff, 0xff, 0xef, 0x16, + 0x05, 0x11, 0x1c, 0x61, 0x22, 0x38, 0x50, 0xb8, 0x2a, 0xbb, + 0x9c, 0xe7, 0xcf, 0xff, 0xff, 0xe6, 0x30, 0xce, 0x0f, 0xc0, + 0x04, 0x71, 0x1d, 0xff, 0xff, 0xff, 0xfb, 0xb7, 0x07, 0xe1, + 0x21, 0x82, 0xc0, 0x87, 0x6b, 0xb7, 0xff, 0xff, 0xf7, 0x0c, + 0x10, 0xc5, 0x85, 0x40, 0x96, 0x12, 0x58, 0xe1, 0xc1, 0x5d, + 0xff, 0xff, 0xfb, 0x89, 0xcb, 0x84, 0x30, 0x9c, 0x2a, 0xc5, + 0x41, 0x64, 0x5a, 0xee, 0x0d, 0x8a, 0x61, 0x4b, 0xff, 0xff, + 0x0c, 0xc0, 0x86, 0x10, 0x23, 0x8a, 0x42, 0xe3, 0x0a, 0xc0, + 0x23, 0x07, 0x14, 0x6e, 0x2c, 0x09, 0x4e, 0x2c, 0x05, 0x82, + 0x01, 0x02, 0x2f, 0xff, 0xf4, 0x07, 0xb0, 0x8d, 0x02, 0x09, + 0x14, 0x45, 0x81, 0x86, 0xb8, 0x10, 0xb0, 0x27, 0x00, 0x30, + 0xaa, 0x21, 0x85, 0x80, 0x5c, 0x56, 0x2f, 0xff, 0xf0, 0x7a, + 0x0c, 0x01, 0x68, 0x14, 0x08, 0x1a, 0x82, 0x3d, 0xc2, 0xc4, + 0xe0, 0x60, 0xc0, 0x0e, 0x30, 0x10, 0x6f, 0xff, 0xf4, 0x5b, + 0x8b, 0x3e, 0x30, 0x92, 0x70, 0xc1, 0x86, 0x80, 0x48, 0x33, + 0xc0, 0x82, 0xc5, 0x8f, 0xff, 0xf0, 0xb7, 0x88, 0xed, 0xf1, + 0x85, 0x80, 0x7c, 0x1b, 0xa0, 0x9d, 0xff, 0xfe, 0x51, 0x47, + 0x45, 0xff, 0x94, 0x2f, 0x0c, 0x15, 0x46, 0xff, 0xff, 0xd3, + 0x0c, 0x58, 0x67, 0xfe, 0x74, 0x57, 0x11, 0x80, 0xc6, 0x14, + 0xe2, 0xc0, 0xa9, 0xff, 0x9d, 0xd4, 0x34, 0x61, 0xc2, 0x5a, + 0x09, 0x7f, 0xfa, 0x60, 0xc0, 0x80, 0x8c, 0x6e, 0x62, 0x6a, + 0xff, 0xc4, 0x50, 0x3c, 0x86, 0x1a, 0x70, 0x3f, 0xfe, 0x0d, + 0x8b, 0x90, 0xc7, 0x04, 0x10, 0xd7, 0xfe, 0x10, 0x00, 0x28, + 0x82, 0x0b, 0x01, 0xc3, 0x0a, 0x84, 0x7f, 0xfb, 0xc2, 0x36, + 0x10, 0xf3, 0xf5, 0xe1, 0x64, 0x80, 0x88, 0x0e, 0x29, 0x94, + 0x1f, 0xf2, 0x49, 0xcf, 0xc9, 0xe4, 0xf3, 0xf2, 0x79, 0x3c, + 0xfc, 0x9e, 0x4f, 0x3f, 0x27, 0x93, 0xcf, 0xc9, 0xe4, 0xf3, + 0xf2, 0x79, 0x3c, 0xe2, 0x2f, 0xc9, 0xc9, 0x5c, 0x62, 0x09, + 0x32, 0x51, 0x20, 0x69, 0x21, 0xa1, 0x4e, 0xe0, 0x60, 0x79, + 0xcd, 0x39, 0x96, 0x2a, 0x12, 0x65, 0x1b, 0x59, 0x45, 0x60, + 0x94, 0x98, 0x24, 0xd4, 0x4e, 0xc1, 0xf0, 0x48, 0x73, 0xbd, + 0xf8, 0xce, 0xd1, 0x9d, 0x6f, 0x70, 0xcc, 0x91, 0x08, 0xc2, + 0x4e, 0x77, 0x92, 0x21, 0x18, 0x49, 0xd0, 0xf7, 0x47, 0x21, + 0x08, 0xc2, 0x4e, 0x87, 0x92, 0x21, 0x18, 0x48, 0x90, 0xba, + 0x67, 0x43, 0xf2, 0x44, 0x58, 0x24, 0xe7, 0x79, 0x2b, 0xbe, + 0x78, 0xc2, 0x94, 0xbc, 0x90, 0x94, 0x7a, 0x84, 0xc4, 0x82, + 0x71, 0xeb, 0x25, 0xf2, 0x4e, 0xe6, 0x1f, 0x0f, 0x59, 0x08, + 0xb7, 0x41, 0xf1, 0x55, 0xc2, 0x4c, 0x29, 0x7a, 0x09, 0x33, + 0xd9, 0x81, 0x9e, 0x49, 0x9b, 0x2c, 0xf2, 0x79, 0xf9, 0x3c, + 0x9e, 0x7e, 0x4f, 0x27, 0x9f, 0x93, 0xc9, 0xe7, 0xe4, 0xf2, + 0x79, 0xc6, 0x63, 0x3e, 0x73, 0xc8, 0xf2, 0xe7, 0xe4, 0xf2, + 0x79, 0xf9, 0x3c, 0x9e, 0x7e, 0x4f, 0x27, 0x9f, 0x93, 0xc9, + 0xe7, 0xe4, 0xf2, 0x42, 0x4b, 0x35, 0xa2, 0x8b, 0xd5, 0x18, + 0x71, 0xf4, 0x0f, 0xc8, 0x49, 0x92, 0x6d, 0x61, 0xc1, 0x4a, + 0x94, 0x7d, 0x09, 0x15, 0x4c, 0x00, 0x48, 0xa8, 0x78, 0x12, + 0x29, 0xfb, 0x3f, 0x89, 0x82, 0x4d, 0xc3, 0x3a, 0x09, 0x32, + 0x3d, 0xf7, 0x92, 0x2e, 0x2e, 0x9b, 0xbb, 0x11, 0x8d, 0x9a, + 0x3f, 0x68, 0x01, 0x99, 0x0f, 0x21, 0x0a, 0xe6, 0x75, 0x0d, + 0x92, 0x32, 0xc9, 0xfc, 0x08, 0x25, 0xb2, 0xf7, 0xfd, 0xfc, + 0x01, 0xc9, 0x93, 0xc9, 0x6f, 0x08, 0x49, 0x9c, 0xf2, 0x75, + 0x92, 0x76, 0x09, 0x35, 0x26, 0x6f, 0x24, 0x3c, 0x82, 0x40, + 0x12, 0x19, 0xb6, 0x64, 0x27, 0xbf, 0x2d, 0xbb, 0x59, 0x60, + 0x91, 0x54, 0xe3, 0x6f, 0x64, 0x64, 0x99, 0xe4, 0xb3, 0x71, + 0x4c, 0xf2, 0x79, 0xfe, 0x4f, 0x27, 0x9f, 0x93, 0xc9, 0xe7, + 0xe4, 0xf2, 0x79, 0xf9, 0x3c, 0x9e, 0x7e, 0x4f, 0x27, 0x9f, + 0x93, 0xc9, 0xe7, 0xe4, 0xf2, 0x79, 0xf9, 0x3c, 0x9e, 0x7e, + 0x4f, 0x24, 0x24, 0x42, 0xaa, 0xc2, 0x40, 0x93, 0xc7, 0xe1, + 0xa8, 0xc6, 0xd9, 0x84, 0xa5, 0x02, 0xd6, 0x84, 0x8a, 0x76, + 0x0e, 0xc5, 0xec, 0xc7, 0x70, 0x08, 0xa8, 0x70, 0xf8, 0xa5, + 0x45, 0x2e, 0x09, 0x10, 0xef, 0x82, 0x40, 0x43, 0x08, 0x52, + 0x61, 0x86, 0x47, 0x28, 0xb1, 0xb4, 0x5f, 0x96, 0xb7, 0xec, + 0xd8, 0xe6, 0xec, 0xdf, 0x4d, 0xb9, 0x3c, 0x96, 0x6c, 0x2b, + 0x24, 0x42, 0x3d, 0xfa, 0xbc, 0xad, 0xe3, 0xa2, 0x37, 0x62, + 0x15, 0xf7, 0xed, 0xb0, 0xee, 0x4d, 0x5d, 0xf3, 0x81, 0x19, + 0x23, 0x16, 0x81, 0x9b, 0x25, 0x76, 0x65, 0x1d, 0x92, 0xf9, + 0x39, 0xdf, 0x7e, 0x6a, 0x3b, 0x64, 0x8e, 0x4c, 0xc1, 0x7a, + 0xc9, 0x3d, 0x66, 0x68, 0x4d, 0xd9, 0x27, 0x1c, 0x88, 0x74, + 0x24, 0x46, 0x2a, 0x68, 0xa6, 0x72, 0x70, 0x86, 0xac, 0xd0, + 0x46, 0x99, 0x06, 0xdb, 0x25, 0x32, 0x08, 0x7b, 0x2f, 0x04, + 0x5f, 0xb3, 0x9e, 0x4c, 0xfc, 0x9d, 0x94, 0x23, 0x3c, 0x9e, + 0x7f, 0x93, 0xc9, 0xe7, 0xe4, 0xf2, 0x79, 0xf9, 0x3c, 0x9e, + 0x71, 0x07, 0x10, 0x7e, 0x7e, 0x4f, 0x27, 0x9f, 0x93, 0xc9, + 0xe7, 0xe4, 0xf2, 0x79, 0xf9, 0x3c, 0x9e, 0x7e, 0x4f, 0x24, + 0x24, 0x76, 0xa5, 0xca, 0x61, 0xc4, 0x7a, 0x92, 0x3d, 0x0a, + 0x5c, 0x9f, 0xca, 0x47, 0x09, 0x31, 0xa2, 0x52, 0x18, 0xb5, + 0x65, 0x1f, 0x44, 0x65, 0xf6, 0xc2, 0x44, 0x0f, 0x91, 0xb8, + 0x31, 0x21, 0xc2, 0x44, 0x23, 0x70, 0x90, 0xf6, 0xe1, 0x22, + 0x09, 0xfc, 0x00, 0x20, 0x77, 0x61, 0x20, 0xce, 0x3b, 0x45, + 0x9e, 0xb5, 0xa8, 0x01, 0xb0, 0x4d, 0xe3, 0x0e, 0x7e, 0x24, + 0xc3, 0xbd, 0xf8, 0x64, 0x9d, 0xd9, 0x88, 0x6d, 0x93, 0xc9, + 0x66, 0x8b, 0x39, 0x93, 0x57, 0x59, 0xee, 0x4b, 0xe8, 0x4e, + 0xb2, 0x45, 0x2f, 0xb4, 0xe8, 0x64, 0xaf, 0x2d, 0xc0, 0xdf, + 0xb2, 0x4f, 0x31, 0x32, 0x4f, 0x2e, 0x62, 0x83, 0xf5, 0xd0, + 0xa1, 0xf9, 0x3a, 0x97, 0xdf, 0xdf, 0x3d, 0x53, 0x92, 0x32, + 0x5c, 0xc7, 0xb4, 0xcc, 0xc8, 0x71, 0xbd, 0xd9, 0xf9, 0x2c, + 0xf2, 0x79, 0xfe, 0x4f, 0x27, 0x9f, 0x93, 0xc9, 0xe7, 0xe4, + 0xf2, 0x79, 0xf9, 0x3c, 0x9e, 0x73, 0xc8, 0xf2, 0xe7, 0xe4, + 0xf2, 0x79, 0xf9, 0x3c, 0x9e, 0x7e, 0x4f, 0x27, 0x9f, 0x93, + 0xc9, 0xe7, 0x3c, 0xf9, 0x38, 0xd8, 0x8c, 0x8e, 0x98, 0x62, + 0x16, 0x31, 0x3d, 0xa0, 0x73, 0x1f, 0x8a, 0x46, 0x10, 0x0c, + 0x11, 0xcb, 0x2f, 0x57, 0x1d, 0x82, 0x4f, 0x47, 0x64, 0x58, + 0x01, 0x07, 0x07, 0x2c, 0x50, 0xe1, 0x4a, 0xc9, 0x29, 0xa6, + 0xe6, 0x66, 0x13, 0x7d, 0x84, 0x89, 0x3f, 0x00, 0x48, 0x82, + 0x57, 0x10, 0x8f, 0xe5, 0xe5, 0xf7, 0x3e, 0xd6, 0xf3, 0x0c, + 0xb7, 0xe7, 0xc9, 0x8f, 0x3e, 0x4f, 0x6a, 0xfc, 0xf3, 0xd5, + 0xe9, 0x4a, 0x0a, 0x46, 0x52, 0x52, 0x97, 0x88, 0xe5, 0xb8, + 0x7e, 0x1c, 0xdc, 0x58, 0x72, 0xdb, 0xe1, 0xe4, 0x8b, 0x6f, + 0xea, 0x41, 0xa1, 0x03, 0x6f, 0xd0, 0xe6, 0x5d, 0xd1, 0x90, + 0xeb, 0x7d, 0xb6, 0x7e, 0xe8, 0x0e, 0x8e, 0x53, 0xef, 0xe7, + 0xdc, 0x2c, 0x91, 0x96, 0xec, 0x12, 0x28, 0x9b, 0x93, 0xb9, + 0x74, 0xaf, 0x00, 0xd8, 0x90, 0xd5, 0x99, 0x21, 0xe5, 0x9d, + 0x03, 0x5f, 0x5c, 0x95, 0x22, 0x9b, 0x09, 0x38, 0x1e, 0x48, + 0xcf, 0x24, 0x39, 0x4c, 0xcd, 0x8d, 0x64, 0x8e, 0x82, 0x4d +}; + +GST_START_TEST (test_vc1_identify_bdu) +{ + GstVC1ParseResult res; + GstVC1BDU bdu; + GstVC1SeqHdr hdr; + GstVC1EntryPointHdr entrypt; + + res = gst_vc1_identify_next_bdu (sequence_fullframe, + sizeof (sequence_fullframe), &bdu); + + assert_equals_int (res, GST_VC1_PARSER_OK); + assert_equals_int (bdu.type, GST_VC1_SEQUENCE); + + res = gst_vc1_parse_sequence_header (bdu.data + bdu.offset, bdu.size, &hdr); + assert_equals_int (res, GST_VC1_PARSER_OK); + assert_equals_int (hdr.profiletype, GST_VC1_PROFILE_ADVANCED); + + assert_equals_int (hdr.profile.advanced.level, GST_VC1_LEVEL_L1); + assert_equals_int (hdr.colordiff_format, 1); + + res = gst_vc1_identify_next_bdu (sequence_fullframe + bdu.sc_offset + + bdu.size, sizeof (sequence_fullframe) - bdu.sc_offset - bdu.size, &bdu); + + fail_unless (res == GST_VC1_PARSER_OK); + fail_unless (bdu.type == GST_VC1_ENTRYPOINT); + + res = gst_vc1_parse_entry_point_header (bdu.data + bdu.offset, + bdu.size, &entrypt, &hdr); + fail_unless (res == GST_VC1_PARSER_OK); +} + +GST_END_TEST; + +GST_START_TEST (test_vc1_parse_p_frame_header_main) +{ + GstVC1FrameHdr framehdr; + GstVC1SeqHdr seqhdr; + + GstVC1SimpleMainSeqHdr *simplehdr = &seqhdr.profile.simplemain; + GstVC1PicSimpleMain *pic = &framehdr.pic.simple; + + assert_equals_int (gst_vc1_parse_sequence_header (pframe_header_main, + sizeof (pframe_header_main), &seqhdr), GST_VC1_PARSER_OK); + + assert_equals_int (seqhdr.profiletype, GST_VC1_PROFILE_MAIN); + + simplehdr->coded_height = 240; + simplehdr->coded_width = 320; + + assert_equals_int (seqhdr.frmrtq_postproc, 7); + assert_equals_int (seqhdr.bitrtq_postproc, 2); + assert_equals_int (simplehdr->loop_filter, 1); + assert_equals_int (simplehdr->multires, 0); + assert_equals_int (simplehdr->extended_mv, 0); + assert_equals_int (simplehdr->rangered, 0); + assert_equals_int (simplehdr->vstransform, 1); + assert_equals_int (simplehdr->overlap, 1); + assert_equals_int (simplehdr->syncmarker, 0); + assert_equals_int (simplehdr->dquant, 1); + assert_equals_int (simplehdr->quantizer, 0); + assert_equals_int (simplehdr->maxbframes, 1); + + assert_equals_int (gst_vc1_parse_frame_header (pframe_main, + sizeof (pframe_main), &framehdr, &seqhdr), GST_VC1_PARSER_OK); + assert_equals_int (framehdr.ptype, GST_VC1_PICTURE_TYPE_P); + assert_equals_int (framehdr.interpfrm, 0); + assert_equals_int (pic->frmcnt, 1); + assert_equals_int (pic->rangeredfrm, 0); + assert_equals_int (framehdr.pqindex, 10); + assert_equals_int (framehdr.pquant, 7); + assert_equals_int (framehdr.halfqp, 0); + assert_equals_int (framehdr.pquantizer, 0); + +} + +GST_END_TEST; + +GST_START_TEST (test_vc1_parse_b_frame_header_main) +{ + GstVC1FrameHdr framehdr; + GstVC1SeqHdr seqhdr; + + GstVC1SimpleMainSeqHdr *simplehdr = &seqhdr.profile.simplemain; + GstVC1PicSimpleMain *pic = &framehdr.pic.simple; + + assert_equals_int (gst_vc1_parse_sequence_header (bframe_header_main, + sizeof (bframe_header_main), &seqhdr), GST_VC1_PARSER_OK); + + assert_equals_int (seqhdr.profiletype, GST_VC1_PROFILE_MAIN); + + simplehdr->coded_height = 240; + simplehdr->coded_width = 320; + + assert_equals_int (seqhdr.frmrtq_postproc, 7); + assert_equals_int (seqhdr.bitrtq_postproc, 3); + assert_equals_int (simplehdr->loop_filter, 1); + assert_equals_int (simplehdr->multires, 0); + assert_equals_int (simplehdr->extended_mv, 0); + assert_equals_int (simplehdr->rangered, 0); + assert_equals_int (simplehdr->vstransform, 1); + assert_equals_int (simplehdr->overlap, 1); + assert_equals_int (simplehdr->syncmarker, 0); + assert_equals_int (simplehdr->dquant, 1); + assert_equals_int (simplehdr->quantizer, 0); + assert_equals_int (simplehdr->maxbframes, 1); + + assert_equals_int (gst_vc1_parse_frame_header (bframe_main, + sizeof (bframe_main), &framehdr, &seqhdr), GST_VC1_PARSER_OK); + + assert_equals_int (framehdr.ptype, GST_VC1_PICTURE_TYPE_B); + assert_equals_int (framehdr.interpfrm, 0); + + assert_equals_int (pic->frmcnt, 2); + assert_equals_int (pic->rangeredfrm, 0); + assert_equals_int (pic->ttmbf, 0); + assert_equals_int (pic->mvtab, 2); + assert_equals_int (pic->cbptab, 1); + assert_equals_int (framehdr.pquant, 7); + assert_equals_int (framehdr.halfqp, 0); + assert_equals_int (framehdr.pquantizer, 0); +} + +GST_END_TEST; + +GST_START_TEST (test_vc1_parse_bi_frame_header_main) +{ + GstVC1FrameHdr framehdr; + GstVC1SeqHdr seqhdr; + + GstVC1SimpleMainSeqHdr *simplehdr = &seqhdr.profile.simplemain; + GstVC1PicSimpleMain *pic = &framehdr.pic.simple; + simplehdr->coded_height = 240; + simplehdr->coded_width = 320; + + assert_equals_int (gst_vc1_parse_sequence_header (i_bi_frame_header, + sizeof (i_bi_frame_header), &seqhdr), GST_VC1_PARSER_OK); + + assert_equals_int (seqhdr.profiletype, GST_VC1_PROFILE_MAIN); + assert_equals_int (seqhdr.frmrtq_postproc, 7); + assert_equals_int (seqhdr.bitrtq_postproc, 7); + assert_equals_int (simplehdr->loop_filter, 1); + assert_equals_int (simplehdr->multires, 0); + assert_equals_int (simplehdr->extended_mv, 0); + assert_equals_int (simplehdr->rangered, 0); + assert_equals_int (simplehdr->vstransform, 1); + assert_equals_int (simplehdr->overlap, 1); + assert_equals_int (simplehdr->syncmarker, 0); + assert_equals_int (simplehdr->dquant, 1); + assert_equals_int (simplehdr->quantizer, 0); + assert_equals_int (simplehdr->maxbframes, 1); + + assert_equals_int (gst_vc1_parse_frame_header (biframe_main, + sizeof (biframe_main), &framehdr, &seqhdr), GST_VC1_PARSER_OK); + assert_equals_int (framehdr.ptype, GST_VC1_PICTURE_TYPE_BI); + assert_equals_int (framehdr.interpfrm, 0); + + assert_equals_int (pic->frmcnt, 0); + assert_equals_int (pic->rangeredfrm, 0); + assert_equals_int (framehdr.pqindex, 6); + assert_equals_int (framehdr.pquant, 6); + assert_equals_int (framehdr.halfqp, 0); + assert_equals_int (framehdr.pquantizer, 1); +} + +GST_END_TEST; + +GST_START_TEST (test_vc1_parse_i_frame_header_main) +{ + GstVC1FrameHdr framehdr; + GstVC1SeqHdr seqhdr; + + GstVC1SimpleMainSeqHdr *simplehdr = &seqhdr.profile.simplemain; + GstVC1PicSimpleMain *pic = &framehdr.pic.simple; + + simplehdr->coded_height = 240; + simplehdr->coded_width = 320; + + assert_equals_int (gst_vc1_parse_sequence_header (i_bi_frame_header, + sizeof (i_bi_frame_header), &seqhdr), GST_VC1_PARSER_OK); + + assert_equals_int (seqhdr.profiletype, GST_VC1_PROFILE_MAIN); + assert_equals_int (seqhdr.frmrtq_postproc, 7); + assert_equals_int (seqhdr.bitrtq_postproc, 7); + assert_equals_int (simplehdr->loop_filter, 1); + assert_equals_int (simplehdr->multires, 0); + assert_equals_int (simplehdr->extended_mv, 0); + assert_equals_int (simplehdr->rangered, 0); + assert_equals_int (simplehdr->vstransform, 1); + assert_equals_int (simplehdr->overlap, 1); + assert_equals_int (simplehdr->syncmarker, 0); + assert_equals_int (simplehdr->dquant, 1); + assert_equals_int (simplehdr->quantizer, 0); + assert_equals_int (simplehdr->maxbframes, 1); + + assert_equals_int (gst_vc1_parse_frame_header (iframe_main, + sizeof (iframe_main), &framehdr, &seqhdr), GST_VC1_PARSER_OK); + assert_equals_int (framehdr.ptype, GST_VC1_PICTURE_TYPE_I); + assert_equals_int (framehdr.interpfrm, 0); + + assert_equals_int (pic->frmcnt, 0); + assert_equals_int (pic->rangeredfrm, 0); + assert_equals_int (framehdr.pqindex, 4); + assert_equals_int (framehdr.pquant, 4); + assert_equals_int (framehdr.halfqp, 1); + assert_equals_int (framehdr.pquantizer, 1); +} + +GST_END_TEST; + +GST_START_TEST (test_vc1_parse_i_frame_header_adv) +{ + GstVC1FrameHdr framehdr; + GstVC1SeqHdr seqhdr; + + GstVC1AdvancedSeqHdr *advhdr = &seqhdr.profile.advanced; + GstVC1EntryPointHdr *entrypt = &advhdr->entrypoint; + GstVC1PicAdvanced *pic = &framehdr.pic.advanced; + + assert_equals_int (gst_vc1_parse_sequence_header (iframe_adv_hdr, + sizeof (iframe_adv_hdr), &seqhdr), GST_VC1_PARSER_OK); + + assert_equals_int (seqhdr.profiletype, GST_VC1_PROFILE_ADVANCED); + assert_equals_int (advhdr->level, GST_VC1_LEVEL_L3); + assert_equals_int (seqhdr.frmrtq_postproc, 7); + assert_equals_int (seqhdr.bitrtq_postproc, 31); + assert_equals_int (advhdr->postprocflag, 0); + assert_equals_int (advhdr->max_coded_width, 1920); + assert_equals_int (advhdr->max_coded_height, 1080); + assert_equals_int (advhdr->interlace, 1); + assert_equals_int (advhdr->tfcntrflag, 0); + assert_equals_int (seqhdr.finterpflag, 0); + + assert_equals_int (advhdr->display_ext, 1); + assert_equals_int (advhdr->disp_horiz_size, 1920); + assert_equals_int (advhdr->disp_vert_size, 1080); + + assert_equals_int (gst_vc1_parse_entry_point_header (entrypoint, + sizeof (entrypoint), entrypt, &seqhdr), GST_VC1_PARSER_OK); + + assert_equals_int (entrypt->broken_link, 0); + assert_equals_int (entrypt->closed_entry, 1); + assert_equals_int (entrypt->panscan_flag, 0); + assert_equals_int (entrypt->refdist_flag, 1); + assert_equals_int (entrypt->loopfilter, 1); + assert_equals_int (entrypt->fastuvmc, 0); + assert_equals_int (entrypt->extended_mv, 1); + assert_equals_int (entrypt->dquant, 1); + assert_equals_int (entrypt->vstransform, 1); + assert_equals_int (entrypt->overlap, 0); + assert_equals_int (entrypt->quantizer, 0); + assert_equals_int (entrypt->coded_height, 1080); + assert_equals_int (entrypt->coded_width, 1920); + + assert_equals_int (gst_vc1_parse_frame_header (iframe_adv, + sizeof (iframe_adv), &framehdr, &seqhdr), GST_VC1_PARSER_OK); + + assert_equals_int (framehdr.ptype, GST_VC1_PICTURE_TYPE_I); + assert_equals_int (framehdr.pqindex, 3); + assert_equals_int (framehdr.pquant, 3); + assert_equals_int (framehdr.halfqp, 1); + assert_equals_int (framehdr.pquantizer, 1); + + assert_equals_int (pic->fcm, 0); + assert_equals_int (pic->tff, 1); + assert_equals_int (pic->rff, 0); + assert_equals_int (pic->rndctrl, 0); +} + +GST_END_TEST; + +GST_START_TEST (test_vc1_parse_b_frame_header_adv) +{ + GstVC1FrameHdr framehdr; + GstVC1SeqHdr seqhdr; + + GstVC1AdvancedSeqHdr *advhdr = &seqhdr.profile.advanced; + GstVC1EntryPointHdr *entrypt = &advhdr->entrypoint; + GstVC1PicAdvanced *pic = &framehdr.pic.advanced; + + assert_equals_int (gst_vc1_parse_sequence_header (iframe_adv_hdr, + sizeof (iframe_adv_hdr), &seqhdr), GST_VC1_PARSER_OK); + + assert_equals_int (seqhdr.profiletype, GST_VC1_PROFILE_ADVANCED); + assert_equals_int (advhdr->level, GST_VC1_LEVEL_L3); + assert_equals_int (seqhdr.frmrtq_postproc, 7); + assert_equals_int (seqhdr.bitrtq_postproc, 31); + assert_equals_int (advhdr->postprocflag, 0); + assert_equals_int (advhdr->max_coded_width, 1920); + assert_equals_int (advhdr->max_coded_height, 1080); + assert_equals_int (advhdr->interlace, 1); + assert_equals_int (advhdr->tfcntrflag, 0); + assert_equals_int (seqhdr.finterpflag, 0); + + assert_equals_int (advhdr->display_ext, 1); + assert_equals_int (advhdr->disp_horiz_size, 1920); + assert_equals_int (advhdr->disp_vert_size, 1080); + + assert_equals_int (gst_vc1_parse_entry_point_header (entrypoint, + sizeof (entrypoint), entrypt, &seqhdr), GST_VC1_PARSER_OK); + + assert_equals_int (entrypt->broken_link, 0); + assert_equals_int (entrypt->closed_entry, 1); + assert_equals_int (entrypt->panscan_flag, 0); + assert_equals_int (entrypt->refdist_flag, 1); + assert_equals_int (entrypt->loopfilter, 1); + assert_equals_int (entrypt->fastuvmc, 0); + assert_equals_int (entrypt->extended_mv, 1); + assert_equals_int (entrypt->dquant, 1); + assert_equals_int (entrypt->vstransform, 1); + assert_equals_int (entrypt->overlap, 0); + assert_equals_int (entrypt->quantizer, 0); + + assert_equals_int (gst_vc1_parse_frame_header (bframe_adv, + sizeof (bframe_adv), &framehdr, &seqhdr), GST_VC1_PARSER_OK); + + assert_equals_int (framehdr.ptype, GST_VC1_PICTURE_TYPE_B); + assert_equals_int (framehdr.pqindex, 1); + assert_equals_int (framehdr.pquant, 1); + assert_equals_int (framehdr.halfqp, 1); + assert_equals_int (framehdr.pquantizer, 1); + + assert_equals_int (framehdr.vopdquant.dquantfrm, 0); + assert_equals_int (framehdr.transacfrm, 1); + + assert_equals_int (gst_vc1_parse_frame_header (bframe2_adv, + sizeof (bframe2_adv), &framehdr, &seqhdr), GST_VC1_PARSER_OK); + assert_equals_int (framehdr.ptype, GST_VC1_PICTURE_TYPE_B); + assert_equals_int (framehdr.pqindex, 4); + assert_equals_int (framehdr.pquant, 4); + assert_equals_int (framehdr.halfqp, 0); + assert_equals_int (framehdr.pquantizer, 1); + assert_equals_int (framehdr.transacfrm, 0); + + assert_equals_int (pic->mvrange, 0); + assert_equals_int (pic->mvmode, 0); +} + + +GST_END_TEST; + +GST_START_TEST (test_vc1_parse_p_frame_header_adv) +{ + GstVC1FrameHdr framehdr; + GstVC1SeqHdr seqhdr; + + GstVC1AdvancedSeqHdr *advhdr = &seqhdr.profile.advanced; + GstVC1EntryPointHdr *entrypt = &advhdr->entrypoint; + GstVC1PicAdvanced *pic = &framehdr.pic.advanced; + + assert_equals_int (gst_vc1_parse_sequence_header (iframe_adv_hdr, + sizeof (iframe_adv_hdr), &seqhdr), GST_VC1_PARSER_OK); + + assert_equals_int (seqhdr.profiletype, GST_VC1_PROFILE_ADVANCED); + assert_equals_int (advhdr->level, GST_VC1_LEVEL_L3); + assert_equals_int (seqhdr.frmrtq_postproc, 7); + assert_equals_int (seqhdr.bitrtq_postproc, 31); + assert_equals_int (advhdr->postprocflag, 0); + assert_equals_int (advhdr->max_coded_width, 1920); + assert_equals_int (advhdr->max_coded_height, 1080); + assert_equals_int (advhdr->interlace, 1); + assert_equals_int (advhdr->tfcntrflag, 0); + assert_equals_int (seqhdr.finterpflag, 0); + + assert_equals_int (advhdr->display_ext, 1); + assert_equals_int (advhdr->disp_horiz_size, 1920); + assert_equals_int (advhdr->disp_vert_size, 1080); + + assert_equals_int (gst_vc1_parse_entry_point_header (entrypoint, + sizeof (entrypoint), entrypt, &seqhdr), GST_VC1_PARSER_OK); + assert_equals_int (entrypt->broken_link, 0); + assert_equals_int (entrypt->closed_entry, 1); + assert_equals_int (entrypt->panscan_flag, 0); + assert_equals_int (entrypt->refdist_flag, 1); + assert_equals_int (entrypt->loopfilter, 1); + assert_equals_int (entrypt->fastuvmc, 0); + assert_equals_int (entrypt->extended_mv, 1); + assert_equals_int (entrypt->dquant, 1); + assert_equals_int (entrypt->vstransform, 1); + assert_equals_int (entrypt->overlap, 0); + assert_equals_int (entrypt->quantizer, 0); + assert_equals_int (entrypt->coded_height, 1080); + assert_equals_int (entrypt->coded_width, 1920); + + + assert_equals_int (gst_vc1_parse_frame_header (pframe_adv, + sizeof (pframe_adv), &framehdr, &seqhdr), GST_VC1_PARSER_OK); + assert_equals_int (framehdr.ptype, GST_VC1_PICTURE_TYPE_P); + assert_equals_int (framehdr.pqindex, 1); + assert_equals_int (framehdr.pquant, 1); + assert_equals_int (framehdr.halfqp, 0); + assert_equals_int (framehdr.pquantizer, 1); + + assert_equals_int (pic->mvmode, 0); + assert_equals_int (pic->mvrange, 0); + + assert_equals_int (gst_vc1_parse_frame_header (pframe2_adv, + sizeof (pframe2_adv), &framehdr, &seqhdr), GST_VC1_PARSER_OK); + assert_equals_int (framehdr.ptype, GST_VC1_PICTURE_TYPE_P); + assert_equals_int (framehdr.pqindex, 1); + assert_equals_int (framehdr.pquant, 1); + assert_equals_int (framehdr.halfqp, 0); + assert_equals_int (framehdr.pquantizer, 1); + + assert_equals_int (pic->mvmode, 3); + assert_equals_int (pic->mvrange, 0); +} + +GST_END_TEST static Suite * +vc1parser_suite (void) +{ + Suite *s = suite_create ("VC1 Parser library"); + + TCase *tc_chain = tcase_create ("general"); + + suite_add_tcase (s, tc_chain); + tcase_add_test (tc_chain, test_vc1_identify_bdu); + tcase_add_test (tc_chain, test_vc1_parse_p_frame_header_main); + tcase_add_test (tc_chain, test_vc1_parse_b_frame_header_main); + tcase_add_test (tc_chain, test_vc1_parse_bi_frame_header_main); + tcase_add_test (tc_chain, test_vc1_parse_i_frame_header_main); + tcase_add_test (tc_chain, test_vc1_parse_i_frame_header_adv); + tcase_add_test (tc_chain, test_vc1_parse_b_frame_header_adv); + tcase_add_test (tc_chain, test_vc1_parse_p_frame_header_adv); + + return s; +} + +int +main (int argc, char **argv) +{ + int nf; + + Suite *s = vc1parser_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; +} |