diff --git a/common b/common
index 605cd9a65e..a39eb835fb 160000
--- a/common
+++ b/common
@@ -1 +1 @@
-Subproject commit 605cd9a65ed61505f24b840d3fe8e252be72b151
+Subproject commit a39eb835fb3be2a4c5a6a89b5ca5cc064e79b2e2
diff --git a/configure.ac b/configure.ac
index 44dc48a805..dda50d4c9c 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1963,6 +1963,7 @@ gst-libs/gst/Makefile
gst-libs/gst/basecamerabinsrc/Makefile
gst-libs/gst/interfaces/Makefile
gst-libs/gst/signalprocessor/Makefile
+gst-libs/gst/codecparsers/Makefile
gst-libs/gst/video/Makefile
sys/Makefile
sys/dshowdecwrapper/Makefile
@@ -2058,10 +2059,13 @@ ext/zbar/Makefile
po/Makefile.in
docs/Makefile
docs/plugins/Makefile
+docs/libs/Makefile
docs/version.entities
pkgconfig/Makefile
pkgconfig/gstreamer-plugins-bad.pc
pkgconfig/gstreamer-plugins-bad-uninstalled.pc
+pkgconfig/gstreamer-codecparsers.pc
+pkgconfig/gstreamer-codecparsers-uninstalled.pc
tools/Makefile
m4/Makefile
win32/common/config.h
diff --git a/docs/Makefile.am b/docs/Makefile.am
index 7af47d43f1..a99c90f362 100644
--- a/docs/Makefile.am
+++ b/docs/Makefile.am
@@ -10,8 +10,8 @@ else
GTK_DOC_DIRS =
endif
-SUBDIRS = $(GTK_DOC_DIRS)
-DIST_SUBDIRS = plugins
+SUBDIRS = libs $(GTK_DOC_DIRS)
+DIST_SUBDIRS = libs plugins
EXTRA_DIST = \
random/ChangeLog-0.8 \
diff --git a/docs/libs/Makefile.am b/docs/libs/Makefile.am
new file mode 100644
index 0000000000..e93bbda17b
--- /dev/null
+++ b/docs/libs/Makefile.am
@@ -0,0 +1,102 @@
+## Process this file with automake to produce Makefile.in
+
+# FIXME: fix the docs then remove this variable
+DOCS_ARE_INCOMPLETE_PLEASE_FIXME=yespleasedo
+
+# The name of the module, e.g. 'glib'.
+#DOC_MODULE=gst-plugins-libs-@GST_MAJORMINOR@
+DOC_MODULE=gst-plugins-bad-libs
+
+# for upload-doc.mak
+DOC=gst-plugins-bad-libs
+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).
+# 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
+
+# Extra options to supply to gtkdoc-fixref.
+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
+
+
+# Header files to ignore when scanning.
+IGNORE_HFILES =
+
+# Images to copy into HTML directory.
+HTML_IMAGES =
+
+# Extra SGML files that are included by $(DOC_MAIN_SGML_FILE).
+content_files = compiling.sgml
+
+# Other files to distribute.
+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_CC=$(LIBTOOL) --tag=CC --mode=compile $(CC)
+GTKDOC_LD=$(LIBTOOL) --tag=CC --mode=link $(CC)
+
+# If you need to override some of the declarations, place them in this file
+# and uncomment this line.
+#DOC_OVERRIDES = $(DOC_MODULE)-overrides.txt
+DOC_OVERRIDES =
+
+include $(top_srcdir)/common/gtk-doc.mak
+
diff --git a/docs/libs/compiling.sgml b/docs/libs/compiling.sgml
new file mode 100644
index 0000000000..949209a068
--- /dev/null
+++ b/docs/libs/compiling.sgml
@@ -0,0 +1,48 @@
+
+
+%version-entities;
+]>
+
+
+Compiling
+3
+GStreamer-Bad Library
+
+
+
+Compiling against the bad plugins libraries
+
+How to compile against the bad plugins libraries
+
+
+
+
+Compiling against the bad plugins libraries
+
+
+To compile against these libraries, you need to tell the compiler where to
+find the header files and libraries. This is done with the
+pkg-config utility.
+
+
+The following interactive shell session demonstrates how
+pkg-config is used:
+
+$ pkg-config --cflags gstreamer-plugins-bad-&GST_MAJORMINOR;
+-D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -pthread -I/usr/include/gstreamer-&GST_MAJORMINOR; -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libxml2
+$ pkg-config --libs gstreamer-plugins-bad-&GST_MAJORMINOR;
+-Wl,--export-dynamic -pthread -lgstreamer-&GST_MAJORMINOR; -lgobject-2.0 -lgmodule-2.0 -ldl -lgthread-2.0 -lxml2 -lpthread -lz -lm -lglib-2.0
+
+
+
+
+Note that, because of the number of libraries provided in this package,
+the pkg-config information does not add -l flags itself
+to choose the libraries to link to. You must add these yourself to select
+which of the libraries you want to use.
+
+
+
+
diff --git a/docs/libs/gst-plugins-bad-libs-docs.sgml b/docs/libs/gst-plugins-bad-libs-docs.sgml
new file mode 100644
index 0000000000..f137ca3c2f
--- /dev/null
+++ b/docs/libs/gst-plugins-bad-libs-docs.sgml
@@ -0,0 +1,60 @@
+
+
+%version-entities;
+]>
+
+
+ GStreamer Bad Plugins &GST_MAJORMINOR; Library Reference Manual
+
+ for GStreamer Bad Library &GST_MAJORMINOR; (&GST_VERSION;)
+ http://gstreamer.freedesktop.org/data/doc/gstreamer/head/gst-plugins-bad-libs/html/.
+
+
+
+
+ GStreamer Bad Plugins Libraries
+
+ This manual describes the libraries provided by the GStreamer Bad Plugins
+ package.
+
+
+
+
+ Bitstream parsing Library
+
+ This library should be linked to by getting cflags and libs from
+ gstreamer-plugins-bad-&GST_MAJORMINOR;.pc and adding
+ -lgscodeparsers-&GST_MAJORMINOR; to the library flags.
+
+
+
+
+
+
+ Base video element classes
+
+
+
+
+
+
+
+
+ Object Hierarchy
+
+
+
+
+ Index
+
+
+
+ Index of deprecated API
+
+
+
+
+
+
diff --git a/docs/libs/gst-plugins-bad-libs-overrides.txt b/docs/libs/gst-plugins-bad-libs-overrides.txt
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/docs/libs/gst-plugins-bad-libs-sections.txt b/docs/libs/gst-plugins-bad-libs-sections.txt
new file mode 100644
index 0000000000..73cc720197
--- /dev/null
+++ b/docs/libs/gst-plugins-bad-libs-sections.txt
@@ -0,0 +1,361 @@
+# codecparsers
+
+gsth264parser
+h264parser
+gst/codecparsers/gsth264parser.h
+GST_H264_MAX_SPS_COUNT
+GST_H264_MAX_PPS_COUNT
+GST_H264_IS_P_SLICE
+GST_H264_IS_B_SLICE
+GST_H264_IS_I_SLICE
+GST_H264_IS_SP_SLICE
+GST_H264_IS_SI_SLICE
+GstH264NalUnitType
+GstH264ParserResult
+GstH264SEIPayloadType
+GstH264SEIPicStructType
+GstH264SliceType
+GstH264NalParser
+GstH264NalUnit
+GstH264SPS
+GstH264PPS
+GstH264HRDParams
+GstH264VUIParams
+GstH264DecRefPicMarking
+GstH264RefPicMarking
+GstH264PredWeightTable
+GstH264SliceHdr
+GstH264ClockTimestamp
+GstH264PicTiming
+GstH264BufferingPeriod
+GstH264SEIMessage
+gst_h264_parser_identify_nalu
+gst_h264_parser_identify_nalu_avc
+gst_h264_parser_parse_nal
+gst_h264_parser_parse_slice_hdr
+gst_h264_parser_parse_sps
+gst_h264_parser_parse_pps
+gst_h264_parser_parse_sei
+gst_h264_nal_parser_new
+gst_h264_nal_parser_free
+gst_h264_parse_sps
+gst_h264_parse_pps
+
+
+
+
+
+gstmpegvideoparser
+mpegvideoparser
+gst/codecparsers/gstmpegvideoparser.h
+GstMpegVideoPacketTypeCode
+GstMpegVideoPacketExtensionCode
+GstMpegVideoLevel
+GstMpegVideoProfile
+GstMpegVideoPictureType
+GstMpegVideoPictureStructure
+GstMpegVideoSequenceHdr
+GstMpegVideoSequenceExt
+GstMpegVideoPictureHdr
+GstMpegVideoGop
+GstMpegVideoPictureExt
+GstMpegVideoQuantMatrixExt
+GstMpegVideoTypeOffsetSize
+gst_mpeg_video_parse
+gst_mpeg_video_parse_sequence_header
+gst_mpeg_video_parse_picture_header
+gst_mpeg_video_parse_picture_extension
+gst_mpeg_video_parse_gop
+gst_mpeg_video_parse_sequence_extension
+gst_mpeg_video_parse_quant_matrix_extension
+
+
+
+
+
+gstphotography
+GST_PHOTOGRAPHY_AUTOFOCUS_DONE
+GST_PHOTOGRAPHY_SHAKE_RISK
+GST_PHOTOGRAPHY_PROP_WB_MODE
+GST_PHOTOGRAPHY_PROP_COLOUR_TONE
+GST_PHOTOGRAPHY_PROP_SCENE_MODE
+GST_PHOTOGRAPHY_PROP_FLASH_MODE
+GST_PHOTOGRAPHY_PROP_NOISE_REDUCTION
+GST_PHOTOGRAPHY_PROP_FOCUS_STATUS
+GST_PHOTOGRAPHY_PROP_CAPABILITIES
+GST_PHOTOGRAPHY_PROP_SHAKE_RISK
+GST_PHOTOGRAPHY_PROP_EV_COMP
+GST_PHOTOGRAPHY_PROP_ISO_SPEED
+GST_PHOTOGRAPHY_PROP_APERTURE
+GST_PHOTOGRAPHY_PROP_EXPOSURE
+GST_PHOTOGRAPHY_PROP_IMAGE_CAPTURE_SUPPORTED_CAPS
+GST_PHOTOGRAPHY_PROP_IMAGE_PREVIEW_SUPPORTED_CAPS
+GST_PHOTOGRAPHY_PROP_FLICKER_MODE
+GST_PHOTOGRAPHY_PROP_FOCUS_MODE
+GST_PHOTOGRAPHY_PROP_ZOOM
+GstPhotographyNoiseReduction
+GstWhiteBalanceMode
+GstColourToneMode
+GstSceneMode
+GstFlashMode
+GstFocusStatus
+GstPhotoCaps
+GstPhotoShakeRisk
+GstFlickerReductionMode
+GstFocusMode
+GstPhotoCapturePrepared
+get_ev_compensation
+get_iso_speed
+get_aperture
+get_exposure
+get_white_balance_mode
+get_colour_tone_mode
+get_scene_mode
+get_flash_mode
+get_zoom
+get_flicker_mode
+get_focus_mode
+set_ev_compensation
+set_iso_speed
+set_aperture
+set_exposure
+set_white_balance_mode
+set_colour_tone_mode
+set_scene_mode
+set_flash_mode
+set_zoom
+set_flicker_mode
+set_focus_mode
+get_capabilities
+prepare_for_capture
+set_autofocus
+set_config
+get_config
+get_noise_reduction
+set_noise_reduction
+gst_photography_get_ev_compensation
+gst_photography_get_iso_speed
+gst_photography_get_aperture
+gst_photography_get_exposure
+gst_photography_get_white_balance_mode
+gst_photography_get_colour_tone_mode
+gst_photography_get_scene_mode
+gst_photography_get_flash_mode
+gst_photography_get_noise_reduction
+gst_photography_get_zoom
+gst_photography_get_flicker_mode
+gst_photography_get_focus_mode
+gst_photography_set_ev_compensation
+gst_photography_set_iso_speed
+gst_photography_set_aperture
+gst_photography_set_exposure
+gst_photography_set_white_balance_mode
+gst_photography_set_colour_tone_mode
+gst_photography_set_scene_mode
+gst_photography_set_flash_mode
+gst_photography_set_noise_reduction
+gst_photography_set_zoom
+gst_photography_set_flicker_mode
+gst_photography_set_focus_mode
+gst_photography_get_capabilities
+gst_photography_prepare_for_capture
+gst_photography_set_autofocus
+gst_photography_set_config
+gst_photography_get_config
+GstPhotography
+
+GST_PHOTOGRAPHY
+GST_IS_PHOTOGRAPHY
+GST_TYPE_PHOTOGRAPHY
+gst_photography_get_type
+GST_PHOTOGRAPHY_GET_IFACE
+
+
+
+gstbasecamerasrc
+GstBaseCameraSrc
+GST_BASE_CAMERA_SRC_CAST
+GST_BASE_CAMERA_SRC_VIEWFINDER_PAD_NAME
+GST_BASE_CAMERA_SRC_IMAGE_PAD_NAME
+GST_BASE_CAMERA_SRC_VIDEO_PAD_NAME
+GST_BASE_CAMERA_SRC_PREVIEW_MESSAGE_NAME
+GstBaseCameraSrc
+GstBaseCameraSrcClass
+MIN_ZOOM
+MAX_ZOOM
+ZOOM_1X
+gst_base_camera_src_get_photography
+gst_base_camera_src_get_color_balance
+gst_base_camera_src_set_mode
+gst_base_camera_src_setup_zoom
+gst_base_camera_src_setup_preview
+gst_base_camera_src_finish_capture
+gst_base_camera_src_post_preview
+
+GST_BASE_CAMERA_SRC
+GST_IS_BASE_CAMERA_SRC
+GST_TYPE_BASE_CAMERA_SRC
+gst_base_camera_src_get_type
+GST_BASE_CAMERA_SRC_CLASS
+GST_IS_BASE_CAMERA_SRC_CLASS
+GST_BASE_CAMERA_SRC_GET_CLASS
+
+
+
+gstbasevideoencoder
+GstBaseVideoEncoder
+GST_BASE_VIDEO_ENCODER_SINK_NAME
+GST_BASE_VIDEO_ENCODER_SRC_NAME
+GST_BASE_VIDEO_ENCODER_FLOW_DROPPED
+GstBaseVideoEncoder
+GstBaseVideoEncoderClass
+gst_base_video_encoder_get_state
+gst_base_video_encoder_get_oldest_frame
+gst_base_video_encoder_finish_frame
+gst_base_video_encoder_set_latency
+gst_base_video_encoder_set_latency_fields
+
+GST_BASE_VIDEO_ENCODER
+GST_IS_BASE_VIDEO_ENCODER
+GST_TYPE_BASE_VIDEO_ENCODER
+gst_base_video_encoder_get_type
+GST_BASE_VIDEO_ENCODER_CLASS
+GST_IS_BASE_VIDEO_ENCODER_CLASS
+GST_BASE_VIDEO_ENCODER_GET_CLASS
+
+
+
+gstbasevideodecoder
+GstBaseVideoDecoder
+GST_BASE_VIDEO_DECODER_SINK_NAME
+GST_BASE_VIDEO_DECODER_SRC_NAME
+GST_BASE_VIDEO_DECODER_FLOW_NEED_DATA
+GST_BASE_VIDEO_DECODER_FLOW_DROPPED
+GST_BASE_AUDIO_DECODER_ERROR
+GstBaseVideoDecoder
+GstBaseVideoDecoderClass
+gst_base_video_decoder_class_set_capture_pattern
+gst_base_video_decoder_get_frame
+gst_base_video_decoder_get_oldest_frame
+gst_base_video_decoder_add_to_frame
+gst_base_video_decoder_lost_sync
+gst_base_video_decoder_have_frame
+gst_base_video_decoder_set_sync_point
+gst_base_video_decoder_set_src_caps
+gst_base_video_decoder_alloc_src_buffer
+gst_base_video_decoder_alloc_src_frame
+gst_base_video_decoder_get_state
+gst_base_video_decoder_get_max_decode_time
+gst_base_video_decoder_finish_frame
+
+GST_BASE_VIDEO_DECODER
+GST_IS_BASE_VIDEO_DECODER
+GST_TYPE_BASE_VIDEO_DECODER
+gst_base_video_decoder_get_type
+GST_BASE_VIDEO_DECODER_CLASS
+GST_IS_BASE_VIDEO_DECODER_CLASS
+GST_BASE_VIDEO_DECODER_GET_CLASS
+
+
+
+gstbasevideocodec
+GstBaseVideoCodec
+GST_BASE_VIDEO_CODEC_SINK_NAME
+GST_BASE_VIDEO_CODEC_SRC_NAME
+GST_BASE_VIDEO_CODEC_SRC_PAD
+GST_BASE_VIDEO_CODEC_SINK_PAD
+GST_BASE_VIDEO_CODEC_FLOW_NEED_DATA
+GST_BASE_VIDEO_CODEC_STREAM_LOCK
+GST_BASE_VIDEO_CODEC_STREAM_UNLOCK
+GstVideoState
+GstVideoFrame
+GstBaseVideoCodec
+GstBaseVideoCodecClass
+gst_base_video_codec_new_frame
+gst_base_video_codec_free_frame
+
+GST_BASE_VIDEO_CODEC
+GST_IS_BASE_VIDEO_CODEC
+GST_TYPE_BASE_VIDEO_CODEC
+gst_base_video_codec_get_type
+GST_BASE_VIDEO_CODEC_CLASS
+GST_IS_BASE_VIDEO_CODEC_CLASS
+GST_BASE_VIDEO_CODEC_GET_CLASS
+
+
+
+gstsignalprocessor
+GstSignalProcessor
+GstSignalProcessorClassFlags
+GST_SIGNAL_PROCESSOR_CLASS_CAN_PROCESS_IN_PLACE
+GST_SIGNAL_PROCESSOR_CLASS_SET_CAN_PROCESS_IN_PLACE
+GstSignalProcessorState
+GST_SIGNAL_PROCESSOR_IS_INITIALIZED
+GST_SIGNAL_PROCESSOR_IS_RUNNING
+GstSignalProcessorGroup
+GstSignalProcessor
+GstSignalProcessorClass
+gst_signal_processor_class_add_pad_template
+
+GST_SIGNAL_PROCESSOR
+GST_IS_SIGNAL_PROCESSOR
+GST_TYPE_SIGNAL_PROCESSOR
+gst_signal_processor_get_type
+GST_SIGNAL_PROCESSOR_CLASS
+GST_IS_SIGNAL_PROCESSOR_CLASS
+GST_SIGNAL_PROCESSOR_GET_CLASS
+
+
+
+
+photography-enumtypes
+gst_photography_noise_reduction_get_type
+GST_TYPE_PHOTOGRAPHY_NOISE_REDUCTION
+gst_white_balance_mode_get_type
+GST_TYPE_WHITE_BALANCE_MODE
+gst_colour_tone_mode_get_type
+GST_TYPE_COLOUR_TONE_MODE
+gst_scene_mode_get_type
+GST_TYPE_SCENE_MODE
+gst_flash_mode_get_type
+GST_TYPE_FLASH_MODE
+gst_focus_status_get_type
+GST_TYPE_FOCUS_STATUS
+gst_photo_caps_get_type
+GST_TYPE_PHOTO_CAPS
+gst_photo_shake_risk_get_type
+GST_TYPE_PHOTO_SHAKE_RISK
+gst_flicker_reduction_mode_get_type
+GST_TYPE_FLICKER_REDUCTION_MODE
+gst_focus_mode_get_type
+GST_TYPE_FOCUS_MODE
+
+
+
+gstcamerabin-enum
+DEFAULT_WIDTH
+DEFAULT_HEIGHT
+DEFAULT_CAPTURE_WIDTH
+DEFAULT_CAPTURE_HEIGHT
+DEFAULT_FPS_N
+DEFAULT_FPS_D
+DEFAULT_ZOOM
+GstCameraBinMode
+GST_TYPE_CAMERABIN_MODE
+gst_camerabin_mode_get_type
+
+
+
+gstcamerabinpreview
+gst_camerabin_create_preview_pipeline
+gst_camerabin_destroy_preview_pipeline
+gst_camerabin_preview_pipeline_post
+gst_camerabin_preview_set_caps
+
+
+
+gstbasevideoutils
+gst_base_video_rawvideo_convert
+gst_base_video_encoded_video_convert
+gst_video_state_get_timestamp
+
diff --git a/docs/libs/gst-plugins-bad-libs.types b/docs/libs/gst-plugins-bad-libs.types
new file mode 100644
index 0000000000..493215718a
--- /dev/null
+++ b/docs/libs/gst-plugins-bad-libs.types
@@ -0,0 +1,4 @@
+#include
+
+#include
+#include
diff --git a/ext/libmms/gstmms.c b/ext/libmms/gstmms.c
index 23a5226ea3..cf7a091454 100644
--- a/ext/libmms/gstmms.c
+++ b/ext/libmms/gstmms.c
@@ -273,7 +273,7 @@ gst_mms_prepare_seek_segment (GstBaseSrc * src, GstEvent * event,
static gboolean
gst_mms_do_seek (GstBaseSrc * src, GstSegment * segment)
{
- mms_off_t start;
+ gint64 start;
GstMMS *mmssrc = GST_MMS (src);
if (segment->format == GST_FORMAT_TIME) {
diff --git a/ext/opencv/MotionCells.cpp b/ext/opencv/MotionCells.cpp
index 2b81b305dd..5223bc7f73 100644
--- a/ext/opencv/MotionCells.cpp
+++ b/ext/opencv/MotionCells.cpp
@@ -95,6 +95,8 @@ MotionCells::MotionCells ()
m_saveerrorcode = 0;
m_alpha = 0.5;
m_beta = 0.5;
+ m_useAlpha = false;
+ m_isVisible = false;
}
@@ -168,8 +170,6 @@ MotionCells::performDetectionMotionCells (IplImage * p_frame,
m_pbwImage = cvCreateImage (m_frameSize, IPL_DEPTH_8U, 1);
cvPyrDown (m_pprevFrame, m_pprevDown);
cvCvtColor (m_pprevDown, m_pprevgreyImage, CV_RGB2GRAY);
- if (m_pprevFrame)
- cvReleaseImage (&m_pprevFrame);
cvPyrDown (m_pcurFrame, m_pcurDown);
cvCvtColor (m_pcurDown, m_pcurgreyImage, CV_RGB2GRAY);
m_pdifferenceImage = cvCloneImage (m_pcurgreyImage);
@@ -268,6 +268,8 @@ MotionCells::performDetectionMotionCells (IplImage * p_frame,
cvReleaseImage (&transparencyimg);
}
+ if (m_pprevFrame)
+ cvReleaseImage (&m_pprevFrame);
m_pprevFrame = cvCloneImage (m_pcurFrame);
m_framecnt = 0;
if (m_pcurFrame)
diff --git a/ext/soundtouch/gstpitch.cc b/ext/soundtouch/gstpitch.cc
index 46f73194d5..6b5b95f151 100644
--- a/ext/soundtouch/gstpitch.cc
+++ b/ext/soundtouch/gstpitch.cc
@@ -55,6 +55,7 @@ struct _GstPitchPrivate
enum
{
ARG_0,
+ ARG_OUT_RATE,
ARG_RATE,
ARG_TEMPO,
ARG_PITCH
@@ -147,6 +148,11 @@ gst_pitch_class_init (GstPitchClass * klass)
"Audio stream rate", 0.1, 10.0, 1.0,
(GParamFlags) (G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE | G_PARAM_STATIC_STRINGS)));
+ g_object_class_install_property (gobject_class, ARG_OUT_RATE,
+ g_param_spec_float ("output-rate", "Output Rate",
+ "Output rate on downstream segment events", 0.1, 10.0, 1.0,
+ (GParamFlags) (G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE | G_PARAM_STATIC_STRINGS)));
+
g_type_class_add_private (gobject_class, sizeof (GstPitchPrivate));
}
@@ -186,12 +192,14 @@ gst_pitch_init (GstPitch * pitch, GstPitchClass * pitch_class)
pitch->tempo = 1.0;
pitch->rate = 1.0;
+ pitch->out_seg_rate = 1.0;
+ pitch->seg_arate = 1.0;
pitch->pitch = 1.0;
pitch->next_buffer_time = 0;
pitch->next_buffer_offset = 0;
pitch->priv->st->setRate (pitch->rate);
- pitch->priv->st->setTempo (pitch->tempo);
+ pitch->priv->st->setTempo (pitch->tempo * pitch->seg_arate);
pitch->priv->st->setPitch (pitch->pitch);
pitch->priv->stream_time_ratio = 1.0;
@@ -232,18 +240,22 @@ gst_pitch_set_property (GObject * object, guint prop_id,
switch (prop_id) {
case ARG_TEMPO:
pitch->tempo = g_value_get_float (value);
- pitch->priv->stream_time_ratio = pitch->tempo * pitch->rate;
- pitch->priv->st->setTempo (pitch->tempo);
+ pitch->priv->stream_time_ratio = pitch->tempo * pitch->rate * pitch->seg_arate;
+ pitch->priv->st->setTempo (pitch->tempo * pitch->seg_arate);
GST_OBJECT_UNLOCK (pitch);
gst_pitch_update_duration (pitch);
break;
case ARG_RATE:
pitch->rate = g_value_get_float (value);
- pitch->priv->stream_time_ratio = pitch->tempo * pitch->rate;
+ pitch->priv->stream_time_ratio = pitch->tempo * pitch->rate * pitch->seg_arate;
pitch->priv->st->setRate (pitch->rate);
GST_OBJECT_UNLOCK (pitch);
gst_pitch_update_duration (pitch);
break;
+ case ARG_OUT_RATE:
+ /* Has no effect until the next input segment */
+ pitch->out_seg_rate = g_value_get_float (value);
+ GST_OBJECT_UNLOCK (pitch);
case ARG_PITCH:
pitch->pitch = g_value_get_float (value);
pitch->priv->st->setPitch (pitch->pitch);
@@ -270,6 +282,9 @@ gst_pitch_get_property (GObject * object, guint prop_id,
case ARG_RATE:
g_value_set_float (value, pitch->rate);
break;
+ case ARG_OUT_RATE:
+ g_value_set_float (value, pitch->out_seg_rate);
+ break;
case ARG_PITCH:
g_value_set_float (value, pitch->pitch);
break;
@@ -695,16 +710,17 @@ gst_pitch_process_segment (GstPitch * pitch, GstEvent ** event)
gint64 start_value, stop_value, base;
gint64 next_offset = 0, next_time = 0;
gboolean update = FALSE;
- gdouble rate;
+ gdouble rate, out_seg_rate, arate, our_arate;
gfloat stream_time_ratio;
g_return_val_if_fail (event, FALSE);
GST_OBJECT_LOCK (pitch);
stream_time_ratio = pitch->priv->stream_time_ratio;
+ out_seg_rate = pitch->out_seg_rate;
GST_OBJECT_UNLOCK (pitch);
- gst_event_parse_new_segment (*event, &update, &rate, &format, &start_value,
+ gst_event_parse_new_segment_full (*event, &update, &rate, &arate, &format, &start_value,
&stop_value, &base);
if (format != GST_FORMAT_TIME && format != GST_FORMAT_DEFAULT) {
@@ -713,21 +729,36 @@ gst_pitch_process_segment (GstPitch * pitch, GstEvent ** event)
"open ended NEWSEGMENT in TIME format.");
gst_event_unref (*event);
*event =
- gst_event_new_new_segment (update, rate, GST_FORMAT_TIME, 0, -1, 0);
+ gst_event_new_new_segment_full (update, rate, arate, GST_FORMAT_TIME, 0, -1, 0);
start_value = 0;
stop_value = -1;
base = 0;
}
+ /* Figure out how much of the incoming 'rate' we'll apply ourselves */
+ our_arate = rate / out_seg_rate;
+ /* update the output rate variables */
+ rate = out_seg_rate;
+ arate *= our_arate;
+
GST_LOG_OBJECT (pitch->sinkpad,
"segment %" G_GINT64_FORMAT " - %" G_GINT64_FORMAT " (%d)", start_value,
stop_value, format);
+ stream_time_ratio = pitch->tempo * pitch->rate * pitch->seg_arate;
+
if (stream_time_ratio == 0) {
GST_LOG_OBJECT (pitch->sinkpad, "stream_time_ratio is zero");
return FALSE;
}
+ /* Update the playback rate */
+ GST_OBJECT_LOCK (pitch);
+ pitch->seg_arate = our_arate;
+ pitch->priv->stream_time_ratio = stream_time_ratio;
+ pitch->priv->st->setTempo (pitch->tempo * pitch->seg_arate);
+ GST_OBJECT_UNLOCK (pitch);
+
start_value = (gint64) (start_value / stream_time_ratio);
if (stop_value != -1)
stop_value = (gint64) (stop_value / stream_time_ratio);
@@ -752,8 +783,8 @@ gst_pitch_process_segment (GstPitch * pitch, GstEvent ** event)
pitch->next_buffer_offset = next_offset;
gst_event_unref (*event);
- *event = gst_event_new_new_segment (update, rate, format, start_value,
- stop_value, base);
+ *event = gst_event_new_new_segment_full (update, rate, arate, format,
+ start_value, stop_value, base);
return TRUE;
}
@@ -772,6 +803,8 @@ gst_pitch_sink_event (GstPad * pad, GstEvent * event)
case GST_EVENT_FLUSH_STOP:
gst_pitch_flush_buffer (pitch, FALSE);
pitch->priv->st->clear ();
+ pitch->next_buffer_offset = 0;
+ pitch->next_buffer_time = 0;
pitch->min_latency = pitch->max_latency = 0;
break;
case GST_EVENT_EOS:
diff --git a/ext/soundtouch/gstpitch.hh b/ext/soundtouch/gstpitch.hh
index 32cb04dd13..ad1f7f6d1f 100644
--- a/ext/soundtouch/gstpitch.hh
+++ b/ext/soundtouch/gstpitch.hh
@@ -58,11 +58,18 @@ struct _GstPitch
* > 1 makes the stream shorter
*/
+ gfloat out_seg_rate; /* change output segment rate
+ * Affects playback when input
+ * segments have rate != out_rate
+ */
+
gfloat pitch; /* change pitch
* change the pitch without affecting the
* duration, stream length doesn't change
*/
+ gfloat seg_arate; /* Rate to apply from input segment */
+
/* values extracted from caps */
gint samplerate; /* samplerate */
gint channels; /* number of audio channels */
diff --git a/ext/vp8/gstvp8enc.c b/ext/vp8/gstvp8enc.c
index f0d282f220..e832975644 100644
--- a/ext/vp8/gstvp8enc.c
+++ b/ext/vp8/gstvp8enc.c
@@ -563,7 +563,7 @@ gst_vp8_enc_set_property (GObject * object, guint prop_id,
gst_vp8_enc->static_threshold = g_value_get_int (value);
break;
case PROP_DROP_FRAME:
- gst_vp8_enc->drop_frame = g_value_get_boolean (value);
+ gst_vp8_enc->drop_frame = g_value_get_int (value);
break;
case PROP_RESIZE_ALLOWED:
gst_vp8_enc->resize_allowed = g_value_get_boolean (value);
@@ -652,7 +652,7 @@ gst_vp8_enc_get_property (GObject * object, guint prop_id, GValue * value,
g_value_set_int (value, gst_vp8_enc->static_threshold);
break;
case PROP_DROP_FRAME:
- g_value_set_boolean (value, gst_vp8_enc->drop_frame);
+ g_value_set_int (value, gst_vp8_enc->drop_frame);
break;
case PROP_RESIZE_ALLOWED:
g_value_set_boolean (value, gst_vp8_enc->resize_allowed);
diff --git a/gst-libs/gst/Makefile.am b/gst-libs/gst/Makefile.am
index ac83c681fe..130956ee4c 100644
--- a/gst-libs/gst/Makefile.am
+++ b/gst-libs/gst/Makefile.am
@@ -1,6 +1,6 @@
-SUBDIRS = interfaces signalprocessor video basecamerabinsrc
+SUBDIRS = interfaces signalprocessor video basecamerabinsrc codecparsers
noinst_HEADERS = gst-i18n-plugin.h gettext.h
-DIST_SUBDIRS = interfaces signalprocessor video basecamerabinsrc
+DIST_SUBDIRS = interfaces signalprocessor video basecamerabinsrc codecparsers
diff --git a/gst-libs/gst/basecamerabinsrc/gstcamerabinpreview.c b/gst-libs/gst/basecamerabinsrc/gstcamerabinpreview.c
index 6b854197dd..b916d7f6b3 100644
--- a/gst-libs/gst/basecamerabinsrc/gstcamerabinpreview.c
+++ b/gst-libs/gst/basecamerabinsrc/gstcamerabinpreview.c
@@ -125,9 +125,9 @@ gst_camerabin_create_preview_pipeline (GstElement * element,
{
GstCameraBinPreviewPipelineData *data;
GstElement *csp;
- GstElement *csp2;
GstElement *vscale;
gboolean added = FALSE;
+ gboolean linkfail = FALSE;
GstBus *bus;
GstAppSinkCallbacks callbacks = { 0, };
@@ -138,29 +138,48 @@ gst_camerabin_create_preview_pipeline (GstElement * element,
data->capsfilter = gst_element_factory_make ("capsfilter",
"preview-capsfilter");
data->appsink = gst_element_factory_make ("appsink", "preview-appsink");
- csp = gst_element_factory_make ("ffmpegcolorspace", "preview-csp0");
- csp2 = gst_element_factory_make ("ffmpegcolorspace", "preview-csp1");
+ csp = gst_element_factory_make ("ffmpegcolorspace", "preview-csp");
vscale = gst_element_factory_make ("videoscale", "preview-vscale");
- if (!data->appsrc || !data->capsfilter || !data->appsink || !csp ||
- !csp2 || !vscale) {
+ if (!data->appsrc || !data->capsfilter || !data->appsink || !csp || !vscale) {
goto error;
}
+ g_object_set (data->appsrc, "emit-signals", FALSE, NULL);
+ g_object_set (data->appsink, "sync", FALSE, NULL);
+
gst_bin_add_many (GST_BIN (data->pipeline), data->appsrc, data->capsfilter,
- data->appsink, csp, csp2, vscale, NULL);
+ data->appsink, csp, vscale, NULL);
if (filter)
gst_bin_add (GST_BIN (data->pipeline), gst_object_ref (filter));
added = TRUE;
if (filter) {
- if (!gst_element_link_many (data->appsrc, filter, csp, vscale, csp2,
- data->capsfilter, data->appsink, NULL))
- goto error;
+ linkfail |=
+ GST_PAD_LINK_FAILED (gst_element_link_pads_full (data->appsrc, "src",
+ filter, NULL, GST_PAD_LINK_CHECK_NOTHING));
+ linkfail |=
+ GST_PAD_LINK_FAILED (gst_element_link_pads_full (filter, NULL,
+ vscale, "sink", GST_PAD_LINK_CHECK_CAPS));
} else {
- if (!gst_element_link_many (data->appsrc, csp, vscale, csp2,
- data->capsfilter, data->appsink, NULL))
- goto error;
+ linkfail |=
+ GST_PAD_LINK_FAILED (gst_element_link_pads_full (data->appsrc, "src",
+ vscale, "sink", GST_PAD_LINK_CHECK_NOTHING));
+ }
+
+ linkfail |=
+ GST_PAD_LINK_FAILED (gst_element_link_pads_full (vscale, "src", csp,
+ "sink", GST_PAD_LINK_CHECK_NOTHING));
+ linkfail |=
+ GST_PAD_LINK_FAILED (gst_element_link_pads_full (csp, "src",
+ data->capsfilter, "sink", GST_PAD_LINK_CHECK_NOTHING));
+ linkfail |=
+ GST_PAD_LINK_FAILED (gst_element_link_pads_full (data->capsfilter, "src",
+ data->appsink, "sink", GST_PAD_LINK_CHECK_NOTHING));
+
+ if (linkfail) {
+ GST_WARNING ("Failed to link preview pipeline elements");
+ goto error;
}
callbacks.new_buffer = gst_camerabin_preview_pipeline_new_buffer;
@@ -188,8 +207,6 @@ error:
if (!added) {
if (csp)
gst_object_unref (csp);
- if (csp2)
- gst_object_unref (csp2);
if (vscale)
gst_object_unref (vscale);
if (data->appsrc)
diff --git a/gst-libs/gst/codecparsers/Makefile.am b/gst-libs/gst/codecparsers/Makefile.am
new file mode 100644
index 0000000000..7fa44f1585
--- /dev/null
+++ b/gst-libs/gst/codecparsers/Makefile.am
@@ -0,0 +1,30 @@
+lib_LTLIBRARIES = libgstcodecparsers-@GST_MAJORMINOR@.la
+
+libgstcodecparsers_@GST_MAJORMINOR@_la_SOURCES = \
+ gstmpegvideoparser.c gsth264parser.c
+
+libgstcodecparsers_@GST_MAJORMINOR@includedir = \
+ $(includedir)/gstreamer-@GST_MAJORMINOR@/gst/codecparsers
+
+libgstcodecparsers_@GST_MAJORMINOR@include_HEADERS = \
+ gstmpegvideoparser.h gsth264parser.h
+
+libgstcodecparsers_@GST_MAJORMINOR@_la_CFLAGS = $(GST_PLUGINS_BAD_CFLAGS) $(GST_CFLAGS)
+libgstcodecparsers_@GST_MAJORMINOR@_la_LIBADD = $(GST_BASE_LIBS) $(GST_LIBS)
+libgstcodecparsers_@GST_MAJORMINOR@_la_LDFLAGS = $(GST_LIB_LDFLAGS) $(GST_ALL_LDFLAGS) $(GST_LT_LDFLAGS)
+
+Android.mk: $(BUILT_SOURCES) Makefile.am
+ androgenizer -:PROJECT libgstcodecparsers -:STATIC libgstcodecparsers-@GST_MAJORMINOR@ \
+ -:TAGS eng debug \
+ -:REL_TOP $(top_srcdir) -:ABS_TOP $(abs_top_srcdir) \
+ -:SOURCES $(libgstcodecparsers_@GST_MAJORMINOR@_la_SOURCES) \
+ $(built_sources) \
+ -:CFLAGS $(DEFS) $(libgstcodecparsers_@GST_MAJORMINOR@_la_CFLAGS) \
+ -:LDFLAGS $(libgstcodecparsers_@GST_MAJORMINOR@_la_LDFLAGS) \
+ $(libgstcodecparsers@GST_MAJORMINOR@_la_LIBADD) \
+ -ldl \
+ -:HEADER_TARGET gstreamer-@GST_MAJORMINOR@/gst/codecparsers \
+ -:HEADERS $(libgstcodecparsersinclude_HEADERS) \
+ $(built_headers) \
+ -:PASSTHROUGH LOCAL_ARM_MODE:=arm \
+ > $@
diff --git a/gst-libs/gst/codecparsers/gsth264parser.c b/gst-libs/gst/codecparsers/gsth264parser.c
new file mode 100644
index 0000000000..869aa6122b
--- /dev/null
+++ b/gst-libs/gst/codecparsers/gsth264parser.c
@@ -0,0 +1,1837 @@
+/* Gstreamer
+ * Copyright (C) <2011> Intel Corporation
+ * Copyright (C) <2011> Collabora Ltd.
+ * Copyright (C) <2011> Thibault Saunier
+ *
+ * Some bits C-c,C-v'ed and s/4/3 from h264parse and videoparsers/h264parse.c:
+ * Copyright (C) <2010> Mark Nauwelaerts
+ * Copyright (C) <2010> Collabora Multimedia
+ * Copyright (C) <2010> Nokia Corporation
+ *
+ * (C) 2005 Michal Benes
+ * (C) 2008 Wim Taymans
+ *
+ * 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:gsth264parser
+ * @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:
+ *
+ *
+ * gst_h264_parser_identify_nalu to identify the following nalu in not AVC bitstreams
+ *
+ *
+ * gst_h264_parser_identify_nalu_avc to identify the following nalu in AVC bitstreams
+ *
+ *
+ *
+ * Then, depending on the #GstH264NalUnitType of the newly parsed #GstH264NalUnit, you should
+ * call the differents functions to parse the struct.
+ *
+ * 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
+ * #GstH264NalParser is always up to date.
+ *
+ * For more details about the structures, look at the ISO specifications.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include "gsth264parser.h"
+
+#include
+#include
+#include
+
+GST_DEBUG_CATEGORY (h264_parser_debug);
+#define GST_CAT_DEFAULT h264_parser_debug
+
+/**** Default scaling_lists according to Table 7-2 *****/
+const guint8 default_4x4_intra[16] = {
+ 6, 13, 13, 20, 20, 20, 28, 28, 28, 28, 32, 32,
+ 32, 37, 37, 42
+};
+
+const guint8 default_4x4_inter[16] = {
+ 10, 14, 14, 20, 20, 20, 24, 24, 24, 24, 27, 27,
+ 27, 30, 30, 34
+};
+
+const guint8 default_8x8_intra[64] = {
+ 6, 10, 10, 13, 11, 13, 16, 16, 16, 16, 18, 18,
+ 18, 18, 18, 23, 23, 23, 23, 23, 23, 25, 25, 25, 25, 25, 25, 25, 27, 27, 27,
+ 27, 27, 27, 27, 27, 29, 29, 29, 29, 29, 29, 29, 31, 31, 31, 31, 31, 31, 33,
+ 33, 33, 33, 33, 36, 36, 36, 36, 38, 38, 38, 40, 40, 42
+};
+
+const guint8 default_8x8_inter[64] = {
+ 9, 13, 13, 15, 13, 15, 17, 17, 17, 17, 19, 19,
+ 19, 19, 19, 21, 21, 21, 21, 21, 21, 22, 22, 22, 22, 22, 22, 22, 24, 24, 24,
+ 24, 24, 24, 24, 24, 25, 25, 25, 25, 25, 25, 25, 27, 27, 27, 27, 27, 27, 28,
+ 28, 28, 28, 28, 30, 30, 30, 30, 32, 32, 32, 33, 33, 35
+};
+
+const guint8 zigzag_8x8[64] = {
+ 0, 1, 8, 16, 9, 2, 3, 10,
+ 17, 24, 32, 25, 18, 11, 4, 5,
+ 12, 19, 26, 33, 40, 48, 41, 34,
+ 27, 20, 13, 6, 7, 14, 21, 28,
+ 35, 42, 49, 56, 57, 50, 43, 36,
+ 29, 22, 15, 23, 30, 37, 44, 51,
+ 58, 59, 52, 45, 38, 31, 39, 46,
+ 53, 60, 61, 54, 47, 55, 62, 63
+};
+
+const guint8 zigzag_4x4[16] = {
+ 0, 1, 4, 8,
+ 5, 2, 3, 6,
+ 9, 12, 13, 10,
+ 7, 11, 14, 15,
+};
+
+/* Compute Ceil(Log2(v)) */
+/* Derived from branchless code for integer log2(v) from:
+ */
+static guint
+ceil_log2 (guint32 v)
+{
+ guint r, shift;
+
+ v--;
+ r = (v > 0xFFFF) << 4;
+ v >>= r;
+ shift = (v > 0xFF) << 3;
+ v >>= shift;
+ r |= shift;
+ shift = (v > 0xF) << 2;
+ v >>= shift;
+ r |= shift;
+ shift = (v > 0x3) << 1;
+ v >>= shift;
+ r |= shift;
+ r |= (v >> 1);
+ return r + 1;
+}
+
+/****** Nal parser ******/
+
+typedef struct
+{
+ const guint8 *data;
+ guint size;
+
+ guint byte; /* Byte position */
+ guint bits_in_cache; /* bitpos in the cache of next bit */
+ guint8 first_byte;
+ guint64 cache; /* cached bytes */
+} NalReader;
+
+static void
+nal_reader_init (NalReader * nr, const guint8 * data, guint size)
+{
+ nr->data = data;
+ nr->size = size;
+
+ nr->byte = 0;
+ nr->bits_in_cache = 0;
+ /* fill with something other than 0 to detect emulation prevention bytes */
+ nr->first_byte = 0xff;
+ nr->cache = 0xff;
+}
+
+static gboolean
+nal_reader_read (NalReader * nr, guint nbits)
+{
+ if (G_UNLIKELY (nr->byte * 8 + (nbits - nr->bits_in_cache) > nr->size * 8)) {
+ GST_DEBUG ("Can not read %u bits, bits in cache %u, Byte * 8 %u, size in "
+ "bits %u", nbits, nr->bits_in_cache, nr->byte * 8, nr->size * 8);
+ return FALSE;
+ }
+
+ while (nr->bits_in_cache < nbits) {
+ guint8 byte;
+ gboolean check_three_byte;
+
+ check_three_byte = TRUE;
+ next_byte:
+ if (G_UNLIKELY (nr->byte >= nr->size))
+ return FALSE;
+
+ byte = nr->data[nr->byte++];
+
+ /* check if the byte is a emulation_prevention_three_byte */
+ if (check_three_byte && byte == 0x03 && nr->first_byte == 0x00 &&
+ ((nr->cache & 0xff) == 0)) {
+ /* next byte goes unconditionally to the cache, even if it's 0x03 */
+ check_three_byte = FALSE;
+ goto next_byte;
+ }
+ nr->cache = (nr->cache << 8) | nr->first_byte;
+ nr->first_byte = byte;
+ nr->bits_in_cache += 8;
+ }
+
+ return TRUE;
+}
+
+static inline gboolean
+nal_reader_skip (NalReader * nr, guint nbits)
+{
+ g_return_val_if_fail (nr != NULL, FALSE);
+
+ if (G_UNLIKELY (!nal_reader_read (nr, nbits)))
+ return FALSE;
+
+ nr->bits_in_cache -= nbits;
+
+ return TRUE;
+}
+
+static inline gboolean
+nal_reader_skip_to_byte (NalReader * nr)
+{
+ g_return_val_if_fail (nr != NULL, FALSE);
+
+ if (nr->bits_in_cache == 0) {
+ if (G_LIKELY ((nr->size - nr->byte) > 0))
+ nr->byte++;
+ else
+ return FALSE;
+ }
+
+ nr->bits_in_cache = 0;
+
+ return TRUE;
+}
+
+static inline guint
+nal_reader_get_pos (const NalReader * nr)
+{
+ return nr->byte * 8 - nr->bits_in_cache;
+}
+
+static inline guint
+nal_reader_get_remaining (const NalReader * nr)
+{
+ return (nr->size - nr->byte) * 8 + nr->bits_in_cache;
+}
+
+#define GST_NAL_READER_READ_BITS(bits) \
+static gboolean \
+nal_reader_get_bits_uint##bits (NalReader *nr, guint##bits *val, guint nbits) \
+{ \
+ guint shift; \
+ \
+ g_return_val_if_fail (nr != NULL, FALSE); \
+ g_return_val_if_fail (val != NULL, FALSE); \
+ g_return_val_if_fail (nbits <= bits, FALSE); \
+ \
+ if (!nal_reader_read (nr, nbits)) \
+ return FALSE; \
+ \
+ /* bring the required bits down and truncate */ \
+ shift = nr->bits_in_cache - nbits; \
+ *val = nr->first_byte >> shift; \
+ \
+ *val |= nr->cache << (8 - shift); \
+ /* mask out required bits */ \
+ if (nbits < bits) \
+ *val &= ((guint##bits)1 << nbits) - 1; \
+ \
+ nr->bits_in_cache = shift; \
+ \
+ return TRUE; \
+} \
+
+GST_NAL_READER_READ_BITS (8);
+GST_NAL_READER_READ_BITS (16);
+GST_NAL_READER_READ_BITS (32);
+
+#define GST_NAL_READER_PEAK_BITS(bits) \
+static gboolean \
+nal_reader_peek_bits_uint##bits (const NalReader *nr, guint##bits *val, guint nbits) \
+{ \
+ NalReader tmp; \
+ \
+ g_return_val_if_fail (nr != NULL, FALSE); \
+ tmp = *nr; \
+ return nal_reader_get_bits_uint##bits (&tmp, val, nbits); \
+}
+
+GST_NAL_READER_PEAK_BITS (8);
+
+static gboolean
+nal_reader_get_ue (NalReader * nr, guint32 * val)
+{
+ guint i = 0;
+ guint8 bit;
+ guint32 value;
+
+ if (G_UNLIKELY (!nal_reader_get_bits_uint8 (nr, &bit, 1))) {
+
+ return FALSE;
+ }
+
+ while (bit == 0) {
+ i++;
+ if G_UNLIKELY
+ ((!nal_reader_get_bits_uint8 (nr, &bit, 1)))
+ return FALSE;
+ }
+
+ g_return_val_if_fail (i <= 32, FALSE);
+
+ if (G_UNLIKELY (!nal_reader_get_bits_uint32 (nr, &value, i)))
+ return FALSE;
+
+ *val = (1 << i) - 1 + value;
+
+ return TRUE;
+}
+
+static gboolean
+nal_reader_get_se (NalReader * nr, gint32 * val)
+{
+ guint32 value;
+
+ if (G_UNLIKELY (!nal_reader_get_ue (nr, &value)))
+ return FALSE;
+
+ if (value % 2)
+ *val = (value / 2) + 1;
+ else
+ *val = -(value / 2);
+
+ return TRUE;
+}
+
+#define CHECK_ALLOWED(val, min, max) { \
+ if (val < min || val > max) { \
+ GST_WARNING ("value not in allowed range. value: %d, range %d-%d", \
+ val, min, max); \
+ goto error; \
+ } \
+}
+
+#define READ_UINT8(nr, val, nbits) { \
+ if (!nal_reader_get_bits_uint8 (nr, &val, nbits)) { \
+ GST_WARNING ("failed to read uint8, nbits: %d", nbits); \
+ goto error; \
+ } \
+}
+
+#define READ_UINT16(nr, val, nbits) { \
+ if (!nal_reader_get_bits_uint16 (nr, &val, nbits)) { \
+ GST_WARNING ("failed to read uint16, nbits: %d", nbits); \
+ goto error; \
+ } \
+}
+
+#define READ_UINT32(nr, val, nbits) { \
+ if (!nal_reader_get_bits_uint32 (nr, &val, nbits)) { \
+ GST_WARNING ("failed to read uint32, nbits: %d", nbits); \
+ goto error; \
+ } \
+}
+
+#define READ_UINT64(nr, val, nbits) { \
+ if (!nal_reader_get_bits_uint64 (nr, &val, nbits)) { \
+ GST_WARNING ("failed to read uint32, nbits: %d", nbits); \
+ goto error; \
+ } \
+}
+
+#define READ_UE(nr, val) { \
+ if (!nal_reader_get_ue (nr, &val)) { \
+ GST_WARNING ("failed to read UE"); \
+ goto error; \
+ } \
+}
+
+#define READ_UE_ALLOWED(nr, val, min, max) { \
+ guint32 tmp; \
+ READ_UE (nr, tmp); \
+ CHECK_ALLOWED (tmp, min, max); \
+ val = tmp; \
+}
+
+#define READ_SE(nr, val) { \
+ if (!nal_reader_get_se (nr, &val)) { \
+ GST_WARNING ("failed to read SE"); \
+ goto error; \
+ } \
+}
+
+#define READ_SE_ALLOWED(nr, val, min, max) { \
+ gint32 tmp; \
+ READ_SE (nr, tmp); \
+ CHECK_ALLOWED (tmp, min, max); \
+ val = tmp; \
+}
+
+/*********** end of nal parser ***************/
+
+/***** Utils ****/
+#define EXTENDED_SAR 255
+
+static GstH264SPS *
+gst_h264_parser_get_sps (GstH264NalParser * nalparser, guint8 sps_id)
+{
+ GstH264SPS *sps;
+
+ sps = &nalparser->sps[sps_id];
+
+ if (sps->valid)
+ return sps;
+
+ return NULL;
+}
+
+static GstH264PPS *
+gst_h264_parser_get_pps (GstH264NalParser * nalparser, guint8 pps_id)
+{
+ GstH264PPS *pps;
+
+ pps = &nalparser->pps[pps_id];
+
+ if (pps->valid)
+ return pps;
+
+ return NULL;
+}
+
+static inline void
+set_nalu_datas (GstH264NalUnit * nalu)
+{
+ guint8 *data = nalu->data + nalu->offset;
+
+ nalu->type = (data[0] & 0x1f);
+ nalu->ref_idc = (data[0] & 0x60) >> 5;
+ nalu->idr_pic_flag = (nalu->type == 5 ? 1 : 0);
+
+ GST_DEBUG ("Nal type %u, ref_idc %u", nalu->type, nalu->ref_idc);
+}
+
+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 gboolean
+gst_h264_parser_more_data (NalReader * nr)
+{
+ guint remaining;
+
+ remaining = nal_reader_get_remaining (nr);
+ if (remaining == 0)
+ return FALSE;
+
+ if (remaining <= 8) {
+ guint8 rbsp_stop_one_bit;
+
+ if (!nal_reader_peek_bits_uint8 (nr, &rbsp_stop_one_bit, 1))
+ return FALSE;
+
+ if (rbsp_stop_one_bit == 1) {
+ guint8 zero_bits;
+
+ if (remaining == 1)
+ return FALSE;
+
+ if (!nal_reader_peek_bits_uint8 (nr, &zero_bits, remaining))
+ return FALSE;
+
+ if ((zero_bits - (1 << (remaining - 1))) == 0)
+ return FALSE;
+ }
+ }
+
+ return TRUE;
+}
+
+/****** Parsing functions *****/
+
+static gboolean
+gst_h264_parse_hrd_parameters (GstH264HRDParams * hrd, NalReader * nr)
+{
+ guint sched_sel_idx;
+
+ GST_DEBUG ("parsing \"HRD Parameters\"");
+
+ READ_UE_ALLOWED (nr, hrd->cpb_cnt_minus1, 0, 31);
+ READ_UINT8 (nr, hrd->bit_rate_scale, 4);
+ READ_UINT8 (nr, hrd->cpb_size_scale, 4);
+
+ for (sched_sel_idx = 0; sched_sel_idx <= hrd->cpb_cnt_minus1; sched_sel_idx++) {
+ READ_UE (nr, hrd->bit_rate_value_minus1[sched_sel_idx]);
+ READ_UE (nr, hrd->cpb_size_value_minus1[sched_sel_idx]);
+ }
+
+ READ_UINT8 (nr, hrd->initial_cpb_removal_delay_length_minus1, 5);
+ READ_UINT8 (nr, hrd->cpb_removal_delay_length_minus1, 5);
+ READ_UINT8 (nr, hrd->dpb_output_delay_length_minus1, 5);
+ READ_UINT8 (nr, hrd->time_offset_length, 5);
+
+ return TRUE;
+
+error:
+ GST_WARNING ("error parsing \"HRD Parameters\"");
+ return FALSE;
+}
+
+static gboolean
+gst_h264_parse_vui_parameters (GstH264SPS * sps, NalReader * nr)
+{
+ GstH264VUIParams *vui = &sps->vui_parameters;
+
+ GST_DEBUG ("parsing \"VUI Parameters\"");
+
+ /* set default values for fields that might not be present in the bitstream
+ and have valid defaults */
+ vui->aspect_ratio_idc = 0;
+ vui->video_format = 5;
+ vui->video_full_range_flag = 0;
+ vui->colour_primaries = 2;
+ vui->transfer_characteristics = 2;
+ vui->matrix_coefficients = 2;
+ vui->chroma_sample_loc_type_top_field = 0;
+ vui->chroma_sample_loc_type_bottom_field = 0;
+ vui->low_delay_hrd_flag = 0;
+
+ READ_UINT8 (nr, vui->aspect_ratio_info_present_flag, 1);
+ if (vui->aspect_ratio_info_present_flag) {
+ READ_UINT8 (nr, vui->aspect_ratio_idc, 8);
+ if (vui->aspect_ratio_idc == EXTENDED_SAR) {
+ READ_UINT16 (nr, vui->sar_width, 16);
+ READ_UINT16 (nr, vui->sar_height, 16);
+ }
+ }
+
+ READ_UINT8 (nr, vui->overscan_info_present_flag, 1);
+ if (vui->overscan_info_present_flag)
+ READ_UINT8 (nr, vui->overscan_appropriate_flag, 1);
+
+ READ_UINT8 (nr, vui->video_signal_type_present_flag, 1);
+ if (vui->video_signal_type_present_flag) {
+
+ READ_UINT8 (nr, vui->video_format, 3);
+ READ_UINT8 (nr, vui->video_full_range_flag, 1);
+ READ_UINT8 (nr, vui->colour_description_present_flag, 1);
+ if (vui->colour_description_present_flag) {
+ READ_UINT8 (nr, vui->colour_primaries, 8);
+ READ_UINT8 (nr, vui->transfer_characteristics, 8);
+ READ_UINT8 (nr, vui->matrix_coefficients, 8);
+ }
+ }
+
+ READ_UINT8 (nr, vui->chroma_loc_info_present_flag, 1);
+ if (vui->chroma_loc_info_present_flag) {
+ READ_UE_ALLOWED (nr, vui->chroma_sample_loc_type_top_field, 0, 5);
+ READ_UE_ALLOWED (nr, vui->chroma_sample_loc_type_bottom_field, 0, 5);
+ }
+
+ READ_UINT8 (nr, vui->timing_info_present_flag, 1);
+ if (vui->timing_info_present_flag) {
+ READ_UINT32 (nr, vui->num_units_in_tick, 32);
+ if (vui->num_units_in_tick == 0)
+ GST_WARNING ("num_units_in_tick = 0 detected in stream "
+ "(incompliant to H.264 E.2.1).");
+
+ READ_UINT32 (nr, vui->time_scale, 32);
+ if (vui->time_scale == 0)
+ GST_WARNING ("time_scale = 0 detected in stream "
+ "(incompliant to H.264 E.2.1).");
+
+ READ_UINT8 (nr, vui->fixed_frame_rate_flag, 1);
+ }
+
+ READ_UINT8 (nr, vui->nal_hrd_parameters_present_flag, 1);
+ if (vui->nal_hrd_parameters_present_flag) {
+ if (!gst_h264_parse_hrd_parameters (&vui->nal_hrd_parameters, nr))
+ goto error;
+ }
+
+ READ_UINT8 (nr, vui->vcl_hrd_parameters_present_flag, 1);
+ if (vui->vcl_hrd_parameters_present_flag) {
+ if (!gst_h264_parse_hrd_parameters (&vui->vcl_hrd_parameters, nr))
+ goto error;
+ }
+
+ if (vui->nal_hrd_parameters_present_flag ||
+ vui->vcl_hrd_parameters_present_flag)
+ READ_UINT8 (nr, vui->low_delay_hrd_flag, 1);
+
+ READ_UINT8 (nr, vui->pic_struct_present_flag, 1);
+ READ_UINT8 (nr, vui->bitstream_restriction_flag, 1);
+ if (vui->bitstream_restriction_flag) {
+ READ_UINT8 (nr, vui->motion_vectors_over_pic_boundaries_flag, 1);
+ READ_UE (nr, vui->max_bytes_per_pic_denom);
+ READ_UE_ALLOWED (nr, vui->max_bits_per_mb_denom, 0, 16);
+ READ_UE_ALLOWED (nr, vui->log2_max_mv_length_horizontal, 0, 16);
+ READ_UE_ALLOWED (nr, vui->log2_max_mv_length_vertical, 0, 16);
+ READ_UE_ALLOWED (nr, vui->log2_max_mv_length_vertical, 0, 16);
+ READ_UE (nr, vui->num_reorder_frames);
+ READ_UE (nr, vui->max_dec_frame_buffering);
+ }
+
+ return TRUE;
+
+error:
+ GST_WARNING ("error parsing \"VUI Parameters\"");
+ return FALSE;
+}
+
+static gboolean
+gst_h264_parser_parse_scaling_list (NalReader * nr,
+ guint8 scaling_lists_4x4[6][16], guint8 scaling_lists_8x8[6][64],
+ const guint8 fallback_4x4_inter[16], const guint8 fallback_4x4_intra[16],
+ const guint8 fallback_8x8_inter[64], const guint8 fallback_8x8_intra[64],
+ guint8 n_lists)
+{
+ guint i;
+
+ GST_DEBUG ("parsing scaling lists");
+
+ for (i = 0; i < 12; i++) {
+ gboolean use_default = FALSE;
+
+ if (i < n_lists) {
+ guint8 scaling_list_present_flag;
+
+ READ_UINT8 (nr, scaling_list_present_flag, 1);
+ if (scaling_list_present_flag) {
+ guint8 *scaling_list;
+ const guint8 *scan;
+ guint size;
+ guint j;
+ guint8 last_scale, next_scale;
+
+ if (i < 6) {
+ scaling_list = scaling_lists_4x4[i];
+ scan = zigzag_4x4;
+ size = 16;
+ } else {
+ scaling_list = scaling_lists_8x8[i - 6];
+ scan = zigzag_8x8;
+ size = 64;
+ }
+
+ last_scale = 8;
+ next_scale = 8;
+ for (j = 0; j < size; j++) {
+ if (next_scale != 0) {
+ gint32 delta_scale;
+
+ READ_SE (nr, delta_scale);
+ next_scale = (last_scale + delta_scale) & 0xff;
+ }
+ if (j == 0 && next_scale == 0) {
+ use_default = TRUE;
+ break;
+ }
+ last_scale = scaling_list[scan[j]] =
+ (next_scale == 0) ? last_scale : next_scale;
+ }
+ } else
+ use_default = TRUE;
+ } else
+ use_default = TRUE;
+
+ if (use_default) {
+ switch (i) {
+ case 0:
+ memcpy (scaling_lists_4x4[0], fallback_4x4_intra, 16);
+ break;
+ case 1:
+ memcpy (scaling_lists_4x4[1], scaling_lists_4x4[0], 16);
+ break;
+ case 2:
+ memcpy (scaling_lists_4x4[2], scaling_lists_4x4[1], 16);
+ break;
+ case 3:
+ memcpy (scaling_lists_4x4[3], fallback_4x4_inter, 16);
+ break;
+ case 4:
+ memcpy (scaling_lists_4x4[4], scaling_lists_4x4[3], 16);
+ break;
+ case 5:
+ memcpy (scaling_lists_4x4[5], scaling_lists_4x4[4], 16);
+ break;
+ case 6:
+ memcpy (scaling_lists_8x8[0], fallback_8x8_intra, 64);
+ break;
+ case 7:
+ memcpy (scaling_lists_8x8[1], fallback_8x8_inter, 64);
+ break;
+ case 8:
+ memcpy (scaling_lists_8x8[2], scaling_lists_8x8[0], 64);
+ break;
+ case 9:
+ memcpy (scaling_lists_8x8[3], scaling_lists_8x8[1], 64);
+ break;
+ case 10:
+ memcpy (scaling_lists_8x8[4], scaling_lists_8x8[2], 64);
+ break;
+ case 11:
+ memcpy (scaling_lists_8x8[5], scaling_lists_8x8[3], 64);
+ break;
+
+ default:
+ break;
+ }
+ }
+ }
+
+ return TRUE;
+
+error:
+ GST_WARNING ("error parsing scaling lists");
+ return FALSE;
+}
+
+static gboolean
+slice_parse_ref_pic_list_reordering (GstH264SliceHdr * slice, NalReader * nr)
+{
+ GST_DEBUG ("parsing \"Reference picture list reordering\"");
+
+ if (!GST_H264_IS_I_SLICE (slice) && !GST_H264_IS_SI_SLICE (slice)) {
+ guint8 ref_pic_list_reordering_flag_l0;
+ guint32 reordering_of_pic_nums_idc;
+
+ READ_UINT8 (nr, ref_pic_list_reordering_flag_l0, 1);
+ if (ref_pic_list_reordering_flag_l0)
+ do {
+ READ_UE (nr, reordering_of_pic_nums_idc);
+ if (reordering_of_pic_nums_idc == 0 || reordering_of_pic_nums_idc == 1) {
+ guint32 abs_diff_pic_num_minus1 G_GNUC_UNUSED;
+
+ READ_UE_ALLOWED (nr, abs_diff_pic_num_minus1, 0,
+ slice->max_pic_num - 1);
+ } else if (reordering_of_pic_nums_idc == 2) {
+ guint32 long_term_pic_num;
+
+ READ_UE (nr, long_term_pic_num);
+ }
+ } while (reordering_of_pic_nums_idc != 3);
+ }
+
+ if (GST_H264_IS_B_SLICE (slice)) {
+ guint8 ref_pic_list_reordering_flag_l1;
+ guint32 reordering_of_pic_nums_idc;
+
+ READ_UINT8 (nr, ref_pic_list_reordering_flag_l1, 1);
+ if (ref_pic_list_reordering_flag_l1)
+ do {
+ READ_UE (nr, reordering_of_pic_nums_idc);
+ if (reordering_of_pic_nums_idc == 0 || reordering_of_pic_nums_idc == 1) {
+ guint32 abs_diff_num_minus1;
+
+ READ_UE (nr, abs_diff_num_minus1);
+ } else if (reordering_of_pic_nums_idc == 2) {
+ guint32 long_term_pic_num;
+
+ READ_UE (nr, long_term_pic_num);
+ }
+ } while (reordering_of_pic_nums_idc != 3);
+ }
+
+ return TRUE;
+
+error:
+ GST_WARNING ("error parsing \"Reference picture list reordering\"");
+ return FALSE;
+}
+
+static gboolean
+gst_h264_slice_parse_dec_ref_pic_marking (GstH264SliceHdr * slice,
+ GstH264NalUnit * nalu, NalReader * nr)
+{
+ GstH264DecRefPicMarking *dec_ref_pic_m;
+
+ GST_DEBUG ("parsing \"Decoded reference picture marking\"");
+
+ dec_ref_pic_m = &slice->dec_ref_pic_marking;
+
+ if (nalu->idr_pic_flag) {
+ READ_UINT8 (nr, dec_ref_pic_m->no_output_of_prior_pics_flag, 1);
+ READ_UINT8 (nr, dec_ref_pic_m->long_term_reference_flag, 1);
+ } else {
+ READ_UINT8 (nr, dec_ref_pic_m->adaptive_ref_pic_marking_mode_flag, 1);
+ if (dec_ref_pic_m->adaptive_ref_pic_marking_mode_flag) {
+ guint32 mem_mgmt_ctrl_op;
+ GstH264RefPicMarking *refpicmarking;
+
+ dec_ref_pic_m->n_ref_pic_marking = 0;
+ while (1) {
+ refpicmarking =
+ &dec_ref_pic_m->ref_pic_marking[dec_ref_pic_m->n_ref_pic_marking];
+
+ READ_UE (nr, mem_mgmt_ctrl_op);
+ if (mem_mgmt_ctrl_op == 0)
+ break;
+
+ refpicmarking->memory_management_control_operation = mem_mgmt_ctrl_op;
+
+ if (mem_mgmt_ctrl_op == 1 || mem_mgmt_ctrl_op == 3)
+ READ_UE (nr, refpicmarking->difference_of_pic_nums_minus1);
+
+ if (mem_mgmt_ctrl_op == 2)
+ READ_UE (nr, refpicmarking->long_term_pic_num);
+
+ if (mem_mgmt_ctrl_op == 3 || mem_mgmt_ctrl_op == 6)
+ READ_UE (nr, refpicmarking->long_term_frame_idx);
+
+ if (mem_mgmt_ctrl_op == 4)
+ READ_UE (nr, refpicmarking->max_long_term_frame_idx_plus1);
+
+ dec_ref_pic_m->n_ref_pic_marking++;
+ }
+ }
+ }
+
+ return TRUE;
+
+error:
+ GST_WARNING ("error parsing \"Decoded reference picture marking\"");
+ return FALSE;
+}
+
+static gboolean
+gst_h264_slice_parse_pred_weight_table (GstH264SliceHdr * slice,
+ NalReader * nr, guint8 chroma_array_type)
+{
+ GstH264PredWeightTable *p;
+ gint16 default_luma_weight, default_chroma_weight;
+ gint i;
+
+ GST_DEBUG ("parsing \"Prediction weight table\"");
+
+ p = &slice->pred_weight_table;
+
+ READ_UE_ALLOWED (nr, p->luma_log2_weight_denom, 0, 7);
+ /* set default values */
+ default_luma_weight = 1 << p->luma_log2_weight_denom;
+ for (i = 0; i < G_N_ELEMENTS (p->luma_weight_l0); i++)
+ p->luma_weight_l0[i] = default_luma_weight;
+ memset (p->luma_offset_l0, 0, sizeof (p->luma_offset_l0));
+ if (GST_H264_IS_B_SLICE (slice)) {
+ for (i = 0; i < G_N_ELEMENTS (p->luma_weight_l1); i++)
+ p->luma_weight_l1[i] = default_luma_weight;
+ memset (p->luma_offset_l1, 0, sizeof (p->luma_offset_l1));
+ }
+
+ if (chroma_array_type != 0) {
+ READ_UE_ALLOWED (nr, p->chroma_log2_weight_denom, 0, 7);
+ /* set default values */
+ default_chroma_weight = 1 << p->chroma_log2_weight_denom;
+ for (i = 0; i < G_N_ELEMENTS (p->chroma_weight_l0); i++) {
+ p->chroma_weight_l0[i][0] = default_chroma_weight;
+ p->chroma_weight_l0[i][1] = default_chroma_weight;
+ }
+ memset (p->chroma_offset_l0, 0, sizeof (p->chroma_offset_l0));
+ if (GST_H264_IS_B_SLICE (slice)) {
+ for (i = 0; i < G_N_ELEMENTS (p->chroma_weight_l1); i++) {
+ p->chroma_weight_l1[i][0] = default_chroma_weight;
+ p->chroma_weight_l1[i][1] = default_chroma_weight;
+ }
+ memset (p->chroma_offset_l1, 0, sizeof (p->chroma_offset_l1));
+ }
+ }
+
+ for (i = 0; i <= slice->num_ref_idx_l0_active_minus1; i++) {
+ guint8 luma_weight_l0_flag;
+
+ READ_UINT8 (nr, luma_weight_l0_flag, 1);
+ if (luma_weight_l0_flag) {
+ READ_SE_ALLOWED (nr, p->luma_weight_l0[i], -128, 127);
+ READ_SE_ALLOWED (nr, p->luma_offset_l0[i], -128, 127);
+ }
+ if (chroma_array_type != 0) {
+ guint8 chroma_weight_l0_flag;
+ gint j;
+
+ READ_UINT8 (nr, chroma_weight_l0_flag, 1);
+ if (chroma_weight_l0_flag) {
+ for (j = 0; j < 2; j++) {
+ READ_SE_ALLOWED (nr, p->chroma_weight_l0[i][j], -128, 127);
+ READ_SE_ALLOWED (nr, p->chroma_offset_l0[i][j], -128, 127);
+ }
+ }
+ }
+ }
+
+ if (GST_H264_IS_B_SLICE (slice)) {
+ for (i = 0; i <= slice->num_ref_idx_l1_active_minus1; i++) {
+ guint8 luma_weight_l1_flag;
+
+ READ_UINT8 (nr, luma_weight_l1_flag, 1);
+ if (luma_weight_l1_flag) {
+ READ_SE_ALLOWED (nr, p->luma_weight_l1[i], -128, 127);
+ READ_SE_ALLOWED (nr, p->luma_offset_l1[i], -128, 127);
+ }
+ if (chroma_array_type != 0) {
+ guint8 chroma_weight_l1_flag;
+ gint j;
+
+ READ_UINT8 (nr, chroma_weight_l1_flag, 1);
+ if (chroma_weight_l1_flag) {
+ for (j = 0; j < 2; j++) {
+ READ_SE_ALLOWED (nr, p->chroma_weight_l1[i][j], -128, 127);
+ READ_SE_ALLOWED (nr, p->chroma_offset_l1[i][j], -128, 127);
+ }
+ }
+ }
+ }
+ }
+
+ return TRUE;
+
+error:
+ GST_WARNING ("error parsing \"Prediction weight table\"");
+ return FALSE;
+}
+
+static gboolean
+gst_h264_parser_parse_buffering_period (GstH264NalParser * nalparser,
+ GstH264BufferingPeriod * per, NalReader * nr)
+{
+ GstH264SPS *sps;
+ guint8 sps_id;
+
+ GST_DEBUG ("parsing \"Buffering period\"");
+
+ READ_UE_ALLOWED (nr, sps_id, 0, GST_H264_MAX_SPS_COUNT);
+ sps = gst_h264_parser_get_sps (nalparser, sps_id);
+ if (!sps) {
+ GST_WARNING ("couldn't find associated sequence parameter set with id: %d",
+ sps_id);
+ return GST_H264_PARSER_BROKEN_LINK;
+ }
+ per->sps = sps;
+
+ if (sps->vui_parameters_present_flag) {
+ GstH264VUIParams *vui = &sps->vui_parameters;
+
+ if (vui->nal_hrd_parameters_present_flag) {
+ GstH264HRDParams *hrd = &vui->nal_hrd_parameters;
+ guint8 sched_sel_idx;
+
+ for (sched_sel_idx = 0; sched_sel_idx <= hrd->cpb_cnt_minus1;
+ sched_sel_idx++) {
+ READ_UINT8 (nr, per->nal_initial_cpb_removal_delay[sched_sel_idx], 5);
+ READ_UINT8 (nr,
+ per->nal_initial_cpb_removal_delay_offset[sched_sel_idx], 5);
+ }
+ }
+
+ if (vui->vcl_hrd_parameters_present_flag) {
+ GstH264HRDParams *hrd = &vui->vcl_hrd_parameters;
+ guint8 sched_sel_idx;
+
+ for (sched_sel_idx = 0; sched_sel_idx <= hrd->cpb_cnt_minus1;
+ sched_sel_idx++) {
+ READ_UINT8 (nr, per->vcl_initial_cpb_removal_delay[sched_sel_idx], 5);
+ READ_UINT8 (nr,
+ per->vcl_initial_cpb_removal_delay_offset[sched_sel_idx], 5);
+ }
+ }
+ }
+
+ return GST_H264_PARSER_OK;
+
+error:
+ GST_WARNING ("error parsing \"Buffering period\"");
+ return GST_H264_PARSER_ERROR;
+}
+
+static gboolean
+gst_h264_parse_clock_timestamp (GstH264ClockTimestamp * tim,
+ GstH264VUIParams * vui, NalReader * nr)
+{
+ guint8 full_timestamp_flag;
+ guint8 time_offset_length;
+
+ GST_DEBUG ("parsing \"Clock timestamp\"");
+
+ /* defalt values */
+ tim->time_offset = 0;
+
+ READ_UINT8 (nr, tim->ct_type, 2);
+ READ_UINT8 (nr, tim->nuit_field_based_flag, 1);
+ READ_UINT8 (nr, tim->counting_type, 5);
+ READ_UINT8 (nr, full_timestamp_flag, 1);
+ READ_UINT8 (nr, tim->discontinuity_flag, 1);
+ READ_UINT8 (nr, tim->cnt_dropped_flag, 1);
+ READ_UINT8 (nr, tim->n_frames, 8);
+
+ if (full_timestamp_flag) {
+ tim->seconds_flag = TRUE;
+ READ_UINT8 (nr, tim->seconds_value, 6);
+
+ tim->minutes_flag = TRUE;
+ READ_UINT8 (nr, tim->minutes_value, 6);
+
+ tim->hours_flag = TRUE;
+ READ_UINT8 (nr, tim->hours_value, 5);
+ } else {
+ READ_UINT8 (nr, tim->seconds_flag, 1);
+ if (tim->seconds_flag) {
+ READ_UINT8 (nr, tim->seconds_value, 6);
+ READ_UINT8 (nr, tim->minutes_flag, 1);
+ if (tim->minutes_flag) {
+ READ_UINT8 (nr, tim->minutes_value, 6);
+ READ_UINT8 (nr, tim->hours_flag, 1);
+ if (tim->hours_flag)
+ READ_UINT8 (nr, tim->hours_value, 5);
+ }
+ }
+ }
+
+ time_offset_length = 0;
+ if (vui->nal_hrd_parameters_present_flag)
+ time_offset_length = vui->nal_hrd_parameters.time_offset_length;
+ else if (vui->vcl_hrd_parameters_present_flag)
+ time_offset_length = vui->vcl_hrd_parameters.time_offset_length;
+
+ if (time_offset_length > 0)
+ READ_UINT32 (nr, tim->time_offset, time_offset_length);
+
+error:
+ GST_WARNING ("error parsing \"Clock timestamp\"");
+ return FALSE;
+}
+
+static gboolean
+gst_h264_parser_parse_pic_timing (GstH264NalParser * nalparser,
+ GstH264PicTiming * tim, NalReader * nr)
+{
+ GST_DEBUG ("parsing \"Picture timing\"");
+ if (!nalparser->last_sps || !nalparser->last_sps->valid) {
+ GST_WARNING ("didn't get the associated sequence paramater set for the "
+ "current access unit");
+ goto error;
+ }
+
+ /* default values */
+ memset (tim->clock_timestamp_flag, 0, 3);
+
+ if (nalparser->last_sps->vui_parameters_present_flag) {
+ GstH264VUIParams *vui = &nalparser->last_sps->vui_parameters;
+
+ if (vui->nal_hrd_parameters_present_flag) {
+ READ_UINT32 (nr, tim->cpb_removal_delay,
+ vui->nal_hrd_parameters.cpb_removal_delay_length_minus1 + 1);
+ READ_UINT32 (nr, tim->dpb_output_delay,
+ vui->nal_hrd_parameters.dpb_output_delay_length_minus1 + 1);
+ } else if (vui->nal_hrd_parameters_present_flag) {
+ READ_UINT32 (nr, tim->cpb_removal_delay,
+ vui->vcl_hrd_parameters.cpb_removal_delay_length_minus1 + 1);
+ READ_UINT32 (nr, tim->dpb_output_delay,
+ vui->vcl_hrd_parameters.dpb_output_delay_length_minus1 + 1);
+ }
+
+ if (vui->pic_struct_present_flag) {
+ const guint8 num_clock_ts_table[9] = {
+ 1, 1, 1, 2, 2, 3, 3, 2, 3
+ };
+ guint8 num_clock_num_ts;
+ guint i;
+
+ READ_UINT8 (nr, tim->pic_struct, 4);
+ CHECK_ALLOWED (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++) {
+ READ_UINT8 (nr, tim->clock_timestamp_flag[i], 1);
+ if (tim->clock_timestamp_flag[i]) {
+ if (!gst_h264_parse_clock_timestamp (&tim->clock_timestamp[i], vui,
+ nr))
+ goto error;
+ }
+ }
+ }
+ }
+
+ return GST_H264_PARSER_OK;
+
+error:
+ GST_WARNING ("error parsing \"Picture timing\"");
+ return GST_H264_PARSER_ERROR;
+}
+
+/******** API *************/
+
+/**
+ * gst_h264_nal_parser_new:
+ *
+ * Creates a nez #GstH264NalParser
+ *
+ * Returns: a new #GstH264NalParser
+ */
+GstH264NalParser *
+gst_h264_nal_parser_new (void)
+{
+ GstH264NalParser *nalparser;
+
+ nalparser = g_malloc0 (sizeof (GstH264NalParser));
+ GST_DEBUG_CATEGORY_INIT (h264_parser_debug, "codecparsers_h264", 0,
+ "h264 parser library");
+
+ return nalparser;
+}
+
+/**
+ * gst_h264_parser_identify_nalu:
+ * @nalparser: a #GstH264NalParser
+ * @data: The data to parse
+ * @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
+ *
+ * Returns: a #GstH264ParserResult
+ */
+GstH264ParserResult
+gst_h264_parser_identify_nalu (GstH264NalParser * nalparser,
+ const guint8 * data, guint offset, gsize size, GstH264NalUnit * nalu)
+{
+ gint off1, off2;
+
+ if (size - offset < 4) {
+ GST_DEBUG ("Can't parse, buffer has too small size %u, offset %u", size,
+ offset);
+ return GST_H264_PARSER_ERROR;
+ }
+
+ off1 = scan_for_start_codes (data + offset, size - offset);
+
+ if (off1 < 0) {
+ GST_DEBUG ("No start code prefix in this buffer");
+ return GST_H264_PARSER_NO_NAL;
+ }
+
+ if (offset + off1 == size - 1) {
+ GST_DEBUG ("Missing data to identify nal unit");
+
+ return GST_H264_PARSER_ERROR;
+ }
+
+ nalu->valid = TRUE;
+ nalu->sc_offset = offset + off1;
+ /* sc might have 2 or 3 0-bytes */
+ if (nalu->sc_offset > 0 && data[nalu->sc_offset - 1] == 00)
+ nalu->sc_offset--;
+
+ nalu->offset = offset + off1 + 3;
+ nalu->data = (guint8 *) data;
+ set_nalu_datas (nalu);
+
+ if (nalu->type == GST_H264_NAL_SEQ_END ||
+ nalu->type == GST_H264_NAL_STREAM_END) {
+ GST_DEBUG ("end-of-seq or end-of-stream nal found");
+ nalu->size = 0;
+ return GST_H264_PARSER_OK;
+ }
+
+ off2 = scan_for_start_codes (data + nalu->offset, size - nalu->offset);
+ if (off2 < 0) {
+ GST_DEBUG ("Nal start %d, No end found", nalu->offset);
+
+ return GST_H264_PARSER_NO_NAL_END;
+ }
+
+ if (off2 > 0 && data[nalu->offset + off2 - 1] == 00)
+ off2--;
+
+ nalu->size = off2;
+ if (nalu->size < 2)
+ return GST_H264_PARSER_BROKEN_DATA;
+
+ GST_DEBUG ("Complete nal found. Off: %d, Size: %d", nalu->offset, nalu->size);
+ return GST_H264_PARSER_OK;
+}
+
+/**
+ * gst_h264_parser_identify_nalu_avc:
+ * @data: The data to parse, must be the beging of the Nal unit
+ * @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.
+ *
+ * Returns: a #GstH264ParserResult
+ */
+GstH264ParserResult
+gst_h264_parser_identify_nalu_avc (GstH264NalParser * nalparser,
+ const guint8 * data, guint offset, gsize size, guint8 nal_length_size,
+ GstH264NalUnit * nalu)
+{
+ GstBitReader br;
+
+ size = size - offset;
+ gst_bit_reader_init (&br, data + offset, size);
+
+ gst_bit_reader_get_bits_uint32 (&br, &nalu->size, nal_length_size * 8);
+ nalu->sc_offset = offset;
+ nalu->offset = offset + nal_length_size;
+
+ if (size < nalu->size + nal_length_size) {
+ nalu->size = 0;
+
+ return GST_H264_PARSER_NO_NAL_END;
+ }
+
+ nalu->data = (guint8 *) data;
+
+ set_nalu_datas (nalu);
+
+ if (nalu->size < 2)
+ return GST_H264_PARSER_BROKEN_DATA;
+
+ nalu->valid = TRUE;
+
+ return GST_H264_PARSER_OK;
+}
+
+GstH264ParserResult
+gst_h264_parser_parse_nal (GstH264NalParser * nalparser, GstH264NalUnit * nalu)
+{
+ GstH264SPS sps;
+ GstH264PPS pps;
+
+ switch (nalu->type) {
+ case GST_H264_NAL_SPS:
+ return gst_h264_parser_parse_sps (nalparser, nalu, &sps, FALSE);
+ break;
+ case GST_H264_NAL_PPS:
+ return gst_h264_parser_parse_pps (nalparser, nalu, &pps);
+ }
+
+ return GST_H264_PARSER_OK;
+}
+
+/**
+ * gst_h264_parser_parse_sps:
+ * @nalparser: a #GstH264NalParser
+ * @nalu: The #GST_H264_NAL_SPS #GstH264NalUnit you want to parse
+ * @slice: The #GstH264SPS to set.
+ * @parse_vui_params: Whether to parse the vui_params or not
+ *
+ * Parses the @data, and sets the @sps.
+ *
+ * Returns: a #GstH264ParserResult
+ */
+GstH264ParserResult
+gst_h264_parser_parse_sps (GstH264NalParser * nalparser, GstH264NalUnit * nalu,
+ GstH264SPS * sps, gboolean parse_vui_params)
+{
+ GstH264ParserResult res = gst_h264_parse_sps (nalu, sps, parse_vui_params);
+
+ if (res == GST_H264_PARSER_OK) {
+ GST_DEBUG ("adding sequence parameter set with id: %d to array", sps->id);
+
+ nalparser->sps[sps->id] = *sps;
+ nalparser->last_sps = &nalparser->sps[sps->id];
+ }
+
+
+
+ return res;
+}
+
+/**
+ * gst_h264_parse_sps:
+ * @nalu: The #GST_H264_NAL_SPS #GstH264NalUnit you want to parse
+ * @slice: The #GstH264SPS to set.
+ * @parse_vui_params: Whether to parse the vui_params or not
+ *
+ * Parses the @data, and sets the @sps.
+ *
+ * Returns: a #GstH264ParserResult
+ */
+GstH264ParserResult
+gst_h264_parse_sps (GstH264NalUnit * nalu, GstH264SPS * sps,
+ gboolean parse_vui_params)
+{
+ NalReader nr;
+ gint width, height;
+ guint8 frame_cropping_flag;
+ guint subwc[] = { 1, 2, 2, 1 };
+ guint subhc[] = { 1, 2, 1, 1 };
+ GstH264VUIParams *vui = NULL;
+
+ GST_DEBUG ("parsing SPS");
+ nal_reader_init (&nr, nalu->data + nalu->offset + 1, nalu->size - 1);
+
+ /* set default values for fields that might not be present in the bitstream
+ and have valid defaults */
+ sps->chroma_format_idc = 1;
+ sps->separate_colour_plane_flag = 0;
+ sps->bit_depth_luma_minus8 = 0;
+ sps->bit_depth_chroma_minus8 = 0;
+ memset (sps->scaling_lists_4x4, 16, 96);
+ memset (sps->scaling_lists_8x8, 16, 384);
+ sps->mb_adaptive_frame_field_flag = 0;
+ sps->frame_crop_left_offset = 0;
+ sps->frame_crop_right_offset = 0;
+ sps->frame_crop_top_offset = 0;
+ sps->frame_crop_bottom_offset = 0;
+
+ READ_UINT8 (&nr, sps->profile_idc, 8);
+ READ_UINT8 (&nr, sps->constraint_set0_flag, 1);
+ READ_UINT8 (&nr, sps->constraint_set1_flag, 1);
+ READ_UINT8 (&nr, sps->constraint_set2_flag, 1);
+ READ_UINT8 (&nr, sps->constraint_set3_flag, 1);
+
+ /* skip reserved_zero_4bits */
+ if (!nal_reader_skip (&nr, 4))
+ goto error;
+
+ READ_UINT8 (&nr, sps->level_idc, 8);
+
+ READ_UE_ALLOWED (&nr, sps->id, 0, GST_H264_MAX_SPS_COUNT);
+
+ if (sps->profile_idc == 100 || sps->profile_idc == 110 ||
+ sps->profile_idc == 122 || sps->profile_idc == 244 ||
+ sps->profile_idc == 44 || sps->profile_idc == 83 ||
+ sps->profile_idc == 86) {
+ READ_UE_ALLOWED (&nr, sps->chroma_format_idc, 0, 3);
+ if (sps->chroma_format_idc == 3)
+ READ_UINT8 (&nr, sps->separate_colour_plane_flag, 1);
+
+ READ_UE_ALLOWED (&nr, sps->bit_depth_luma_minus8, 0, 6);
+ READ_UE_ALLOWED (&nr, sps->bit_depth_chroma_minus8, 0, 6);
+ READ_UINT8 (&nr, sps->qpprime_y_zero_transform_bypass_flag, 1);
+
+ READ_UINT8 (&nr, sps->scaling_matrix_present_flag, 1);
+ if (sps->scaling_matrix_present_flag) {
+ guint8 n_lists;
+
+ n_lists = (sps->chroma_format_idc != 3) ? 8 : 12;
+ if (!gst_h264_parser_parse_scaling_list (&nr,
+ sps->scaling_lists_4x4, sps->scaling_lists_8x8,
+ default_4x4_inter, default_4x4_intra,
+ default_8x8_inter, default_8x8_intra, n_lists))
+ goto error;
+ }
+ }
+
+ READ_UE_ALLOWED (&nr, sps->log2_max_frame_num_minus4, 0, 12);
+
+ sps->max_frame_num = 1 << (sps->log2_max_frame_num_minus4 + 4);
+
+ READ_UE_ALLOWED (&nr, sps->pic_order_cnt_type, 0, 2);
+ if (sps->pic_order_cnt_type == 0) {
+ READ_UE_ALLOWED (&nr, sps->log2_max_pic_order_cnt_lsb_minus4, 0, 12);
+ } else if (sps->pic_order_cnt_type == 1) {
+ guint i;
+
+ READ_UINT8 (&nr, sps->delta_pic_order_always_zero_flag, 1);
+ READ_SE (&nr, sps->offset_for_non_ref_pic);
+ READ_SE (&nr, sps->offset_for_top_to_bottom_field);
+ READ_UE_ALLOWED (&nr, sps->num_ref_frames_in_pic_order_cnt_cycle, 0, 255);
+
+ for (i = 0; i < sps->num_ref_frames_in_pic_order_cnt_cycle; i++)
+ READ_SE (&nr, sps->offset_for_ref_frame[i]);
+ }
+
+ READ_UE (&nr, sps->num_ref_frames);
+ READ_UINT8 (&nr, sps->gaps_in_frame_num_value_allowed_flag, 1);
+ READ_UE (&nr, sps->pic_width_in_mbs_minus1);
+ READ_UE (&nr, sps->pic_height_in_map_units_minus1);
+ READ_UINT8 (&nr, sps->frame_mbs_only_flag, 1);
+
+ if (!sps->frame_mbs_only_flag)
+ READ_UINT8 (&nr, sps->mb_adaptive_frame_field_flag, 1);
+
+ READ_UINT8 (&nr, sps->direct_8x8_inference_flag, 1);
+ READ_UINT8 (&nr, frame_cropping_flag, 1);
+ if (frame_cropping_flag) {
+ READ_UE (&nr, sps->frame_crop_left_offset);
+ READ_UE (&nr, sps->frame_crop_right_offset);
+ READ_UE (&nr, sps->frame_crop_top_offset);
+ READ_UE (&nr, sps->frame_crop_bottom_offset);
+ }
+
+ READ_UINT8 (&nr, sps->vui_parameters_present_flag, 1);
+ if (sps->vui_parameters_present_flag && parse_vui_params) {
+ if (!gst_h264_parse_vui_parameters (sps, &nr))
+ goto error;
+ vui = &sps->vui_parameters;
+ }
+
+ /* calculate ChromaArrayType */
+ if (sps->separate_colour_plane_flag)
+ sps->chroma_array_type = 0;
+ else
+ sps->chroma_array_type = sps->chroma_format_idc;
+
+ /* Calculate width and height */
+ width = (sps->pic_width_in_mbs_minus1 + 1);
+ width *= 16;
+ height = (sps->pic_height_in_map_units_minus1 + 1);
+ height *= 16 * (2 - sps->frame_mbs_only_flag);
+ GST_LOG ("initial width=%d, height=%d", width, height);
+
+ width -= (sps->frame_crop_left_offset + sps->frame_crop_right_offset)
+ * subwc[sps->chroma_format_idc];
+ height -= (sps->frame_crop_top_offset + sps->frame_crop_bottom_offset
+ * subhc[sps->chroma_format_idc] * (2 - sps->frame_mbs_only_flag));
+ if (width < 0 || height < 0) {
+ GST_WARNING ("invalid width/height in SPS");
+ return FALSE;
+ }
+ GST_LOG ("final width=%u, height=%u", width, height);
+ 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);
+ }
+
+ sps->valid = TRUE;
+
+ return GST_H264_PARSER_OK;
+
+error:
+ GST_WARNING ("error parsing \"Sequence parameter set\"");
+
+ return GST_H264_PARSER_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.
+ *
+ * Parses the @data, and sets the @pps.
+ *
+ * Returns: a #GstH264ParserResult
+ */
+GstH264ParserResult
+gst_h264_parse_pps (GstH264NalParser * nalparser, GstH264NalUnit * nalu,
+ GstH264PPS * pps)
+{
+ NalReader nr;
+ GstH264SPS *sps;
+ gint sps_id;
+ guint8 pic_scaling_matrix_present_flag;
+ gint qp_bd_offset;
+
+ GST_DEBUG ("parsing PPS");
+
+ nal_reader_init (&nr, nalu->data + nalu->offset + 1, nalu->size - 1);
+
+ READ_UE_ALLOWED (&nr, pps->id, 0, GST_H264_MAX_PPS_COUNT);
+ READ_UE_ALLOWED (&nr, sps_id, 0, GST_H264_MAX_SPS_COUNT);
+
+ sps = gst_h264_parser_get_sps (nalparser, sps_id);
+ if (!sps) {
+ GST_WARNING ("couldn't find associated sequence parameter set with id: %d",
+ sps_id);
+ return GST_H264_PARSER_BROKEN_LINK;
+ }
+ pps->sequence = sps;
+ qp_bd_offset = 6 * (sps->bit_depth_luma_minus8 +
+ sps->separate_colour_plane_flag);
+
+ /* set default values for fields that might not be present in the bitstream
+ and have valid defaults */
+ pps->slice_group_id = NULL;
+ pps->transform_8x8_mode_flag = 0;
+ memcpy (&pps->scaling_lists_4x4, &sps->scaling_lists_4x4, 96);
+ memcpy (&pps->scaling_lists_8x8, &sps->scaling_lists_8x8, 384);
+
+ READ_UINT8 (&nr, pps->entropy_coding_mode_flag, 1);
+ READ_UINT8 (&nr, pps->pic_order_present_flag, 1);
+ READ_UE_ALLOWED (&nr, pps->num_slice_groups_minus1, 0, 7);
+ if (pps->num_slice_groups_minus1 > 0) {
+ READ_UE_ALLOWED (&nr, pps->slice_group_map_type, 0, 6);
+
+ if (pps->slice_group_map_type == 0) {
+ gint i;
+
+ for (i = 0; i <= pps->num_slice_groups_minus1; i++)
+ READ_UE (&nr, pps->run_length_minus1[i]);
+ } else if (pps->slice_group_map_type == 2) {
+ gint i;
+
+ for (i = 0; i <= pps->num_slice_groups_minus1; i++) {
+ READ_UE (&nr, pps->top_left[i]);
+ READ_UE (&nr, pps->bottom_right[i]);
+ }
+ } else if (pps->slice_group_map_type >= 3 && pps->slice_group_map_type <= 5) {
+ READ_UINT8 (&nr, pps->slice_group_change_direction_flag, 1);
+ READ_UE (&nr, pps->slice_group_change_rate_minus1);
+ } else if (pps->slice_group_map_type == 6) {
+ gint bits;
+ gint i;
+
+ READ_UE (&nr, pps->pic_size_in_map_units_minus1);
+ bits = g_bit_storage (pps->num_slice_groups_minus1);
+
+ pps->slice_group_id =
+ g_new (guint8, pps->pic_size_in_map_units_minus1 + 1);
+ for (i = 0; i <= pps->pic_size_in_map_units_minus1; i++)
+ READ_UINT8 (&nr, pps->slice_group_id[i], bits);
+ }
+ }
+
+ READ_UE_ALLOWED (&nr, pps->num_ref_idx_l0_active_minus1, 0, 31);
+ READ_UE_ALLOWED (&nr, pps->num_ref_idx_l1_active_minus1, 0, 31);
+ READ_UINT8 (&nr, pps->weighted_pred_flag, 1);
+ READ_UINT8 (&nr, pps->weighted_bipred_idc, 2);
+ READ_SE_ALLOWED (&nr, pps->pic_init_qp_minus26, -(26 + qp_bd_offset), 25);
+ READ_SE_ALLOWED (&nr, pps->pic_init_qs_minus26, -26, 25);
+ READ_SE_ALLOWED (&nr, pps->chroma_qp_index_offset, -12, 12);
+ pps->second_chroma_qp_index_offset = pps->chroma_qp_index_offset;
+ READ_UINT8 (&nr, pps->deblocking_filter_control_present_flag, 1);
+ READ_UINT8 (&nr, pps->constrained_intra_pred_flag, 1);
+ READ_UINT8 (&nr, pps->redundant_pic_cnt_present_flag, 1);
+
+ if (!gst_h264_parser_more_data (&nr))
+ goto done;
+
+ READ_UINT8 (&nr, pps->transform_8x8_mode_flag, 1);
+
+ READ_UINT8 (&nr, pic_scaling_matrix_present_flag, 1);
+ if (pic_scaling_matrix_present_flag) {
+ guint8 n_lists;
+
+ n_lists = 6 + ((sps->chroma_format_idc != 3) ? 2 : 6) *
+ pps->transform_8x8_mode_flag;
+
+ if (sps->scaling_matrix_present_flag) {
+ if (!gst_h264_parser_parse_scaling_list (&nr,
+ pps->scaling_lists_4x4, pps->scaling_lists_8x8,
+ sps->scaling_lists_4x4[0], sps->scaling_lists_4x4[3],
+ sps->scaling_lists_8x8[0], sps->scaling_lists_8x8[3], n_lists))
+ goto error;
+ } else {
+ if (!gst_h264_parser_parse_scaling_list (&nr,
+ pps->scaling_lists_4x4, pps->scaling_lists_8x8,
+ default_4x4_inter, default_4x4_intra,
+ default_8x8_inter, default_8x8_intra, n_lists))
+ goto error;
+ }
+ }
+
+ READ_SE_ALLOWED (&nr, pps->second_chroma_qp_index_offset, -12, 12);
+
+done:
+ pps->valid = TRUE;
+ return GST_H264_PARSER_OK;
+
+error:
+ GST_WARNING ("error parsing \"Picture parameter set\"");
+ return GST_H264_PARSER_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.
+ *
+ * Parses the @data, and sets the @pps.
+ *
+ * Returns: a #GstH264ParserResult
+ */
+GstH264ParserResult
+gst_h264_parser_parse_pps (GstH264NalParser * nalparser,
+ GstH264NalUnit * nalu, GstH264PPS * pps)
+{
+ GstH264ParserResult res = gst_h264_parse_pps (nalparser, nalu, pps);
+
+ if (res == GST_H264_PARSER_OK) {
+ GST_DEBUG ("adding picture parameter set with id: %d to array", pps->id);
+
+ nalparser->pps[pps->id] = *pps;
+ nalparser->last_pps = &nalparser->pps[pps->id];
+ }
+
+ return res;
+}
+
+/**
+ * gst_h264_parser_parse_slice_hdr:
+ * @nalu: The #GST_H264_NAL_SLICE #GstH264NalUnit you want to parse
+ * @slice: The #GstH264SliceHdr to set.
+ * @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.
+ *
+ * Returns: a #GstH264ParserResult
+ */
+GstH264ParserResult
+gst_h264_parser_parse_slice_hdr (GstH264NalParser * nalparser,
+ GstH264NalUnit * nalu, GstH264SliceHdr * slice,
+ gboolean parse_pred_weight_table, gboolean parse_dec_ref_pic_marking)
+{
+ NalReader nr;
+ gint pps_id;
+ GstH264PPS *pps;
+ GstH264SPS *sps;
+
+ if (!nalu->size) {
+ GST_DEBUG ("Invalid Nal Unit");
+ return GST_H264_PARSER_ERROR;
+ }
+
+
+ nal_reader_init (&nr, nalu->data + nalu->offset + 1, nalu->size - 1);
+
+ READ_UE (&nr, slice->first_mb_in_slice);
+ READ_UE (&nr, slice->type);
+
+ GST_DEBUG ("parsing \"Slice header\", slice type %u", slice->type);
+
+ READ_UE_ALLOWED (&nr, pps_id, 0, GST_H264_MAX_PPS_COUNT);
+ pps = gst_h264_parser_get_pps (nalparser, pps_id);
+
+ if (!pps) {
+ GST_WARNING ("couldn't find associated picture parameter set with id: %d",
+ pps_id);
+
+ return GST_H264_PARSER_BROKEN_LINK;
+ }
+
+ slice->pps = pps;
+ sps = pps->sequence;
+ if (!sps) {
+ GST_WARNING ("couldn't find associated sequence parameter set with id: %d",
+ pps->id);
+ return GST_H264_PARSER_BROKEN_LINK;
+ }
+
+ /* set default values for fields that might not be present in the bitstream
+ and have valid defaults */
+ slice->field_pic_flag = 0;
+ slice->bottom_field_flag = 0;
+ slice->delta_pic_order_cnt_bottom = 0;
+ slice->delta_pic_order_cnt[0] = 0;
+ slice->delta_pic_order_cnt[1] = 0;
+ slice->redundant_pic_cnt = 0;
+ slice->num_ref_idx_l0_active_minus1 = pps->num_ref_idx_l0_active_minus1;
+ slice->num_ref_idx_l1_active_minus1 = pps->num_ref_idx_l1_active_minus1;
+ slice->disable_deblocking_filter_idc = 0;
+ slice->slice_alpha_c0_offset_div2 = 0;
+
+ if (sps->separate_colour_plane_flag)
+ READ_UINT8 (&nr, slice->colour_plane_id, 2);
+
+ READ_UINT16 (&nr, slice->frame_num, sps->log2_max_frame_num_minus4 + 4);
+
+ if (!sps->frame_mbs_only_flag) {
+ READ_UINT8 (&nr, slice->field_pic_flag, 1);
+ if (slice->field_pic_flag)
+ READ_UINT8 (&nr, slice->bottom_field_flag, 1);
+ }
+
+ /* calculate MaxPicNum */
+ if (slice->field_pic_flag)
+ slice->max_pic_num = sps->max_frame_num;
+ else
+ slice->max_pic_num = 2 * sps->max_frame_num;
+
+ if (nalu->type == 5)
+ READ_UE_ALLOWED (&nr, slice->idr_pic_id, 0, G_MAXUINT16);
+
+ if (sps->pic_order_cnt_type == 0) {
+ READ_UINT16 (&nr, slice->pic_order_cnt_lsb,
+ sps->log2_max_pic_order_cnt_lsb_minus4 + 4);
+
+ if (pps->pic_order_present_flag && !slice->field_pic_flag)
+ READ_SE (&nr, slice->delta_pic_order_cnt_bottom);
+ }
+
+ if (sps->pic_order_cnt_type == 1 && !sps->delta_pic_order_always_zero_flag) {
+ READ_SE (&nr, slice->delta_pic_order_cnt[0]);
+ if (pps->pic_order_present_flag && !slice->field_pic_flag)
+ READ_SE (&nr, slice->delta_pic_order_cnt[1]);
+ }
+
+ if (pps->redundant_pic_cnt_present_flag)
+ READ_UE_ALLOWED (&nr, slice->redundant_pic_cnt, 0, G_MAXINT8);
+
+ if (GST_H264_IS_B_SLICE (slice))
+ READ_UINT8 (&nr, slice->direct_spatial_mv_pred_flag, 1);
+
+ if (GST_H264_IS_P_SLICE (slice) || GST_H264_IS_SP_SLICE (slice) ||
+ GST_H264_IS_B_SLICE (slice)) {
+ guint8 num_ref_idx_active_override_flag;
+
+ READ_UINT8 (&nr, num_ref_idx_active_override_flag, 1);
+ if (num_ref_idx_active_override_flag) {
+ READ_UE_ALLOWED (&nr, slice->num_ref_idx_l0_active_minus1, 0, 31);
+
+ if (GST_H264_IS_B_SLICE (slice))
+ READ_UE_ALLOWED (&nr, slice->num_ref_idx_l1_active_minus1, 0, 31);
+ }
+ }
+
+ if (!slice_parse_ref_pic_list_reordering (slice, &nr))
+ goto error;
+
+ if ((pps->weighted_pred_flag && (GST_H264_IS_P_SLICE (slice)
+ || GST_H264_IS_SP_SLICE (slice)))
+ || (pps->weighted_bipred_idc == 1 && GST_H264_IS_B_SLICE (slice))) {
+ if (!gst_h264_slice_parse_pred_weight_table (slice, &nr,
+ sps->chroma_array_type))
+ goto error;
+ }
+
+ if (nalu->ref_idc != 0) {
+ if (!gst_h264_slice_parse_dec_ref_pic_marking (slice, nalu, &nr))
+ goto error;
+ }
+
+ if (pps->entropy_coding_mode_flag && !GST_H264_IS_I_SLICE (slice) &&
+ !GST_H264_IS_SI_SLICE (slice))
+ READ_UE_ALLOWED (&nr, slice->cabac_init_idc, 0, 2);
+
+ READ_SE_ALLOWED (&nr, slice->slice_qp_delta, -87, 77);
+
+ if (GST_H264_IS_SP_SLICE (slice) || GST_H264_IS_SI_SLICE (slice)) {
+ guint8 sp_for_switch_flag;
+
+ if (GST_H264_IS_SP_SLICE (slice))
+ READ_UINT8 (&nr, sp_for_switch_flag, 1);
+ READ_SE_ALLOWED (&nr, slice->slice_qs_delta, -51, 51);
+ }
+
+ if (pps->deblocking_filter_control_present_flag) {
+ READ_UE_ALLOWED (&nr, slice->disable_deblocking_filter_idc, 0, 2);
+ if (slice->disable_deblocking_filter_idc != 1) {
+ READ_SE_ALLOWED (&nr, slice->slice_alpha_c0_offset_div2, -6, 6);
+ READ_SE_ALLOWED (&nr, slice->slice_beta_offset_div2, -6, 6);
+ }
+ }
+
+ if (pps->num_slice_groups_minus1 > 0 &&
+ pps->slice_group_map_type >= 3 && pps->slice_group_map_type <= 5) {
+ /* Ceil(Log2(PicSizeInMapUnits / SliceGroupChangeRate + 1)) [7-33] */
+ guint32 PicWidthInMbs = sps->pic_width_in_mbs_minus1 + 1;
+ guint32 PicHeightInMapUnits = sps->pic_height_in_map_units_minus1 + 1;
+ guint32 PicSizeInMapUnits = PicWidthInMbs * PicHeightInMapUnits;
+ guint32 SliceGroupChangeRate = pps->slice_group_change_rate_minus1 + 1;
+ const guint n = ceil_log2 (PicSizeInMapUnits / SliceGroupChangeRate + 1);
+ READ_UINT16 (&nr, slice->slice_group_change_cycle, n);
+ }
+
+ slice->header_size = nal_reader_get_pos (&nr);
+
+ return GST_H264_PARSER_OK;
+
+error:
+ GST_WARNING ("error parsing \"Slice header\"");
+ return GST_H264_PARSER_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.
+ *
+ * Parses the @data, and sets the @pps.
+ *
+ * Returns: a #GstH264ParserResult
+ */
+GstH264ParserResult
+gst_h264_parser_parse_sei (GstH264NalParser * nalparser, GstH264NalUnit * nalu,
+ GstH264SEIMessage * sei)
+{
+ NalReader nr;
+
+ guint32 payloadSize;
+ guint8 payload_type_byte, payload_size_byte;
+ guint remaining, payload_size;
+ gboolean res;
+
+ GST_DEBUG ("parsing \"Sei message\"");
+
+ nal_reader_init (&nr, nalu->data + nalu->offset + 1, nalu->size - 1);
+
+ sei->payloadType = 0;
+ do {
+ READ_UINT8 (&nr, payload_type_byte, 8);
+ sei->payloadType += payload_type_byte;
+ } while (payload_type_byte == 0xff);
+
+ payloadSize = 0;
+ do {
+ READ_UINT8 (&nr, payload_size_byte, 8);
+ payloadSize += payload_size_byte;
+ }
+ while (payload_size_byte == 0xff);
+
+ remaining = nal_reader_get_remaining (&nr) * 8;
+ payload_size = payloadSize < remaining ? payloadSize : remaining;
+
+ GST_DEBUG ("SEI message received: payloadType %u, payloadSize = %u bytes",
+ sei->payloadType, payload_size);
+
+ if (sei->payloadType == GST_H264_SEI_BUF_PERIOD) {
+ /* Set the nal reader size properly */
+ nr.size = payload_size;
+ res = gst_h264_parser_parse_buffering_period (nalparser,
+ &sei->buffering_period, &nr);
+ } else if (sei->payloadType == GST_H264_SEI_PIC_TIMING) {
+ /* Set the nal reader size properly */
+ nr.size = payload_size;
+ res = gst_h264_parser_parse_pic_timing (nalparser, &sei->pic_timing, &nr);
+ } else
+ res = GST_H264_PARSER_OK;
+
+ return res;
+
+error:
+ GST_WARNING ("error parsing \"Sei message\"");
+ return GST_H264_PARSER_ERROR;
+}
diff --git a/gst-libs/gst/codecparsers/gsth264parser.h b/gst-libs/gst/codecparsers/gsth264parser.h
new file mode 100644
index 0000000000..84577f686b
--- /dev/null
+++ b/gst-libs/gst/codecparsers/gsth264parser.h
@@ -0,0 +1,682 @@
+/* Gstreamer
+ * Copyright (C) <2011> Intel Corporation
+ * Copyright (C) <2011> Collabora Ltd.
+ * Copyright (C) <2011> Thibault Saunier
+ *
+ * Some bits C-c,C-v'ed and s/4/3 from h264parse and videoparsers/h264parse.c:
+ * Copyright (C) <2010> Mark Nauwelaerts
+ * Copyright (C) <2010> Collabora Multimedia
+ * Copyright (C) <2010> Nokia Corporation
+ *
+ * (C) 2005 Michal Benes
+ * (C) 2008 Wim Taymans
+ *
+ * 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_H264_PARSER_H__
+#define __GST_H264_PARSER_H__
+
+#include
+
+G_BEGIN_DECLS
+
+#define GST_H264_MAX_SPS_COUNT 32
+#define GST_H264_MAX_PPS_COUNT 256
+
+#define GST_H264_IS_P_SLICE(slice) (((slice)->type % 5) == GST_H264_P_SLICE)
+#define GST_H264_IS_B_SLICE(slice) (((slice)->type % 5) == GST_H264_B_SLICE)
+#define GST_H264_IS_I_SLICE(slice) (((slice)->type % 5) == GST_H264_I_SLICE)
+#define GST_H264_IS_SP_SLICE(slice) (((slice)->type % 5) == GST_H264_SP_SLICE)
+#define GST_H264_IS_SI_SLICE(slice) (((slice)->type % 5) == GST_H264_SI_SLICE)
+
+/**
+ * GstH264NalUnitType:
+ * @GST_H264_NAL_UNKNOWN: Unkonw 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_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
+ *
+ * Indicates the type of H264 Nal Units
+ */
+typedef enum
+{
+ GST_H264_NAL_UNKNOWN = 0,
+ GST_H264_NAL_SLICE = 1,
+ GST_H264_NAL_SLICE_DPA = 2,
+ GST_H264_NAL_SLICE_DPB = 3,
+ GST_H264_NAL_SLICE_DPC = 4,
+ GST_H264_NAL_SLICE_IDR = 5,
+ GST_H264_NAL_SEI = 6,
+ GST_H264_NAL_SPS = 7,
+ GST_H264_NAL_PPS = 8,
+ GST_H264_NAL_AU_DELIMITER = 9,
+ GST_H264_NAL_SEQ_END = 10,
+ GST_H264_NAL_STREAM_END = 11,
+ GST_H264_NAL_FILLER_DATA = 12
+} GstH264NalUnitType;
+
+/**
+ * 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_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.
+ *
+ * Information about how the parsing of a H264 elements went.
+ */
+typedef enum
+{
+ GST_H264_PARSER_OK,
+ GST_H264_PARSER_BROKEN_DATA,
+ GST_H264_PARSER_BROKEN_LINK,
+ GST_H264_PARSER_ERROR,
+ GST_H264_PARSER_NO_NAL,
+ GST_H264_PARSER_NO_NAL_END
+} GstH264ParserResult;
+
+/**
+ * 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
+ * ...
+ *
+ * The type of the SEI message information
+ */
+typedef enum
+{
+ GST_H264_SEI_BUF_PERIOD = 0,
+ GST_H264_SEI_PIC_TIMING = 1
+ /* and more... */
+} GstH264SEIPayloadType;
+
+/**
+ * GstH264SEIPicStructType:
+ * @GST_H264_SEI_PIC_STRUCT_FRAME: Picture is a frame
+ * @GST_H264_SEI_PIC_STRUCT_TOP_FIELD: Top field of frame
+ * @GST_H264_SEI_PIC_STRUCT_BOTTOM_FIELD: Botom field of frame
+ * @GST_H264_SEI_PIC_STRUCT_TOP_BOTTOM: Top bottom field of frame
+ * @GST_H264_SEI_PIC_STRUCT_BOTTOM_TOP: bottom top field of frame
+ * @GST_H264_SEI_PIC_STRUCT_TOP_BOTTOM_TOP: top bottom top field of frame
+ * @GST_H264_SEI_PIC_STRUCT_BOTTOM_TOP_BOTTOM: bottom top bottom field of frame
+ * @GST_H264_SEI_PIC_STRUCT_FRAME_DOUBLING: indicates that the frame should
+ * be displayed two times consecutively
+ * @GST_H264_SEI_PIC_STRUCT_FRAME_TRIPLING: indicates that the frame should be
+ * displayed three times consecutively
+ *
+ * SEI pic_struct type
+ */
+typedef enum
+{
+ GST_H264_SEI_PIC_STRUCT_FRAME = 0,
+ GST_H264_SEI_PIC_STRUCT_TOP_FIELD = 1,
+ GST_H264_SEI_PIC_STRUCT_BOTTOM_FIELD = 2,
+ GST_H264_SEI_PIC_STRUCT_TOP_BOTTOM = 3,
+ GST_H264_SEI_PIC_STRUCT_BOTTOM_TOP = 4,
+ GST_H264_SEI_PIC_STRUCT_TOP_BOTTOM_TOP = 5,
+ GST_H264_SEI_PIC_STRUCT_BOTTOM_TOP_BOTTOM = 6,
+ GST_H264_SEI_PIC_STRUCT_FRAME_DOUBLING = 7,
+ GST_H264_SEI_PIC_STRUCT_FRAME_TRIPLING = 8
+} GstH264SEIPicStructType;
+
+/**
+ * GstH264SliceType:
+ *
+ * Type of Picture slice
+ */
+
+typedef enum
+{
+ GST_H264_P_SLICE = 0,
+ GST_H264_B_SLICE = 1,
+ GST_H264_I_SLICE = 2,
+ GST_H264_SP_SLICE = 3,
+ GST_H264_SI_SLICE = 4,
+ GST_H264_S_P_SLICE = 5,
+ GST_H264_S_B_SLICE = 6,
+ GST_H264_S_I_SLICE = 7,
+ GST_H264_S_SP_SLICE = 8,
+ GST_H264_S_SI_SLICE = 9
+} GstH264SliceType;
+
+typedef struct _GstH264NalParser GstH264NalParser;
+
+typedef struct _GstH264NalUnit GstH264NalUnit;
+
+typedef struct _GstH264SPS GstH264SPS;
+typedef struct _GstH264PPS GstH264PPS;
+typedef struct _GstH264HRDParams GstH264HRDParams;
+typedef struct _GstH264VUIParams GstH264VUIParams;
+
+typedef struct _GstH264DecRefPicMarking GstH264DecRefPicMarking;
+typedef struct _GstH264RefPicMarking GstH264RefPicMarking;
+typedef struct _GstH264PredWeightTable GstH264PredWeightTable;
+typedef struct _GstH264SliceHdr GstH264SliceHdr;
+
+typedef struct _GstH264ClockTimestamp GstH264ClockTimestamp;
+typedef struct _GstH264PicTiming GstH264PicTiming;
+typedef struct _GstH264BufferingPeriod GstH264BufferingPeriod;
+typedef struct _GstH264SEIMessage GstH264SEIMessage;
+
+/**
+ * GstH264NalUnit:
+ * @ref_idc: not equal to 0 specifies that the content of the NAL unit contains a sequence
+ * parameter set, a sequence * parameter set extension, a subset sequence parameter set, a
+ * picture parameter set, a slice of a reference picture, a slice data partition of a
+ * reference picture, or a prefix NAL unit preceding a slice of a reference picture.
+ * @type: A #GstH264NalUnitType
+ * @idr_pic_flag: calculated idr_pic_flag
+ * @size: The size of the nal unit starting from @offset
+ * @offset: The offset of the actual start of the nal unit
+ * @sc_offset:The offset of the start code of the nal unit
+ * @valid: If the nal unit is valid, which mean it has
+ * already been parsed
+ * @data: The data from which the Nalu has been parsed
+ *
+ * Structure defining the Nal unit headers
+ */
+struct _GstH264NalUnit
+{
+ guint16 ref_idc;
+ guint16 type;
+
+ /* calculated values */
+ guint8 idr_pic_flag;
+ guint size;
+ guint offset;
+ guint sc_offset;
+ gboolean valid;
+
+ guint8 *data;
+};
+
+/**
+ * GstH264HRDParams:
+ * @cpb_cnt_minus1: plus 1 specifies the number of alternative
+ * CPB specifications in the bitstream
+ * @bit_rate_scale: specifies the maximum input bit rate of the
+ * SchedSelIdx-th CPB
+ * @cpb_size_scale: specifies the CPB size of the SchedSelIdx-th CPB
+ * @guint32 bit_rate_value_minus1: specifies the maximum input bit rate for the
+ * SchedSelIdx-th CPB
+ * @cpb_size_value_minus1: is used together with cpb_size_scale to specify the
+ * SchedSelIdx-th CPB size
+ * @cbr_flag: Specifies if running in itermediate bitrate mode or constant
+ * @initial_cpb_removal_delay_length_minus1: specifies the length in bits of
+ * the cpb_removal_delay syntax element
+ * @cpb_removal_delay_length_minus1: specifies the length in bits of the
+ * dpb_output_delay syntax element
+ * @dpb_output_delay_length_minus1: >0 specifies the length in bits of the time_offset syntax element.
+ * =0 specifies that the time_offset syntax element is not present
+ * @time_offset_length: Length of the time offset
+ *
+ * Defines the HRD parameters
+ */
+struct _GstH264HRDParams
+{
+ guint8 cpb_cnt_minus1;
+ guint8 bit_rate_scale;
+ guint8 cpb_size_scale;
+
+ guint32 bit_rate_value_minus1[32];
+ guint32 cpb_size_value_minus1[32];
+ guint8 cbr_flag[32];
+
+ guint8 initial_cpb_removal_delay_length_minus1;
+ guint8 cpb_removal_delay_length_minus1;
+ guint8 dpb_output_delay_length_minus1;
+ guint8 time_offset_length;
+};
+
+/**
+ * GstH264VUIParams:
+ * @aspect_ratio_info_present_flag: %TRUE specifies that aspect_ratio_idc is present.
+ * %FALSE specifies that aspect_ratio_idc is not present
+ * @aspect_ratio_idc specifies the value of the sample aspect ratio of the luma samples
+ * @sar_width indicates the horizontal size of the sample aspect ratio
+ * @sar_height indicates the vertical size of the sample aspect ratio
+ * @overscan_info_present_flag: %TRUE overscan_appropriate_flag is present %FALSE otherwize
+ * @overscan_appropriate_flag: %TRUE indicates that the cropped decoded pictures
+ * output are suitable for display using overscan. %FALSE the cropped decoded pictures
+ * output contain visually important information
+ * @video_signal_type_present_flag: %TRUE specifies that video_format, video_full_range_flag and
+ * colour_description_present_flag are present.
+ * @video_format: indicates the representation of the picture
+ * @video_full_range_flag: indicates the black level and range of the luma and chroma signals
+ * @colour_description_present_flag: %TRUE specifies that colour_primaries,
+ * transfer_characteristics and matrix_coefficients are present
+ * @colour_primaries: indicates the chromaticity coordinates of the source primaries
+ * @transfer_characteristics: indicates the opto-electronic transfer characteristic
+ * @matrix_coefficients: describes the matrix coefficients used in deriving luma and chroma signals
+ * @chroma_loc_info_present_flag: %TRUE specifies that chroma_sample_loc_type_top_field and
+ * chroma_sample_loc_type_bottom_field are present, %FALSE otherwize
+ * @chroma_sample_loc_type_top_field: specify the location of chroma for top field
+ * @chroma_sample_loc_type_bottom_field specify the location of chroma for bottom field
+ * @timing_info_present_flag: %TRUE specifies that num_units_in_tick,
+ * time_scale and fixed_frame_rate_flag are present in the bitstream
+ * @num_units_in_tick: is the number of time units of a clock operating at the frequency time_scale Hz
+ * time_scale: is the number of time units that pass in one second
+ * @fixed_frame_rate_flag: %TRUE indicates that the temporal distance between the HRD output times
+ * of any two consecutive pictures in output order is constrained as specified in the spec, %FALSE
+ * otherwize.
+ * @nal_hrd_parameters_present_flag: %TRUE if nal hrd parameters present in the bitstream
+ * @vcl_hrd_parameters_present_flag: %TRUE if nal vlc hrd parameters present in the bitstream
+ * @low_delay_hrd_flag: specifies the HRD operational mode
+ * @pic_struct_present_flag: %TRUE specifies that picture timing SEI messages are present or not
+ * @bitstream_restriction_flag: %TRUE specifies that the following coded video sequence bitstream restriction
+ * parameters are present
+ * @motion_vectors_over_pic_boundaries_flag: %FALSE indicates that no sample outside the
+ * picture boundaries and no sample at a fractional sample position, %TRUE indicates that one or more
+ * 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()
+ * @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
+ * motion vector component
+ * @num_reorder_frames: indicates the maximum number of frames, complementary field pairs,
+ * or non-paired fields that precede any frame,
+ * @max_dec_frame_buffering: specifies the required size of the HRD decoded picture buffer in
+ * units of frame buffers.
+ *
+ * The structure representing the VUI parameters.
+ */
+struct _GstH264VUIParams
+{
+ guint8 aspect_ratio_info_present_flag;
+ guint8 aspect_ratio_idc;
+ /* if aspect_ratio_idc == 255 */
+ guint16 sar_width;
+ guint16 sar_height;
+
+ guint8 overscan_info_present_flag;
+ /* if overscan_info_present_flag */
+ guint8 overscan_appropriate_flag;
+
+ guint8 video_signal_type_present_flag;
+ guint8 video_format;
+ guint8 video_full_range_flag;
+ guint8 colour_description_present_flag;
+ guint8 colour_primaries;
+ guint8 transfer_characteristics;
+ guint8 matrix_coefficients;
+
+ guint8 chroma_loc_info_present_flag;
+ guint8 chroma_sample_loc_type_top_field;
+ guint8 chroma_sample_loc_type_bottom_field;
+
+ guint8 timing_info_present_flag;
+ /* if timing_info_present_flag */
+ guint32 num_units_in_tick;
+ guint32 time_scale;
+ guint8 fixed_frame_rate_flag;
+
+ guint8 nal_hrd_parameters_present_flag;
+ /* if nal_hrd_parameters_present_flag */
+ GstH264HRDParams nal_hrd_parameters;
+
+ guint8 vcl_hrd_parameters_present_flag;
+ /* if nal_hrd_parameters_present_flag */
+ GstH264HRDParams vcl_hrd_parameters;
+
+ guint8 low_delay_hrd_flag;
+ guint8 pic_struct_present_flag;
+
+ guint8 bitstream_restriction_flag;
+ /* if bitstream_restriction_flag */
+ guint8 motion_vectors_over_pic_boundaries_flag;
+ guint32 max_bytes_per_pic_denom;
+ guint32 max_bits_per_mb_denom;
+ guint32 log2_max_mv_length_horizontal;
+ guint32 log2_max_mv_length_vertical;
+ guint32 num_reorder_frames;
+ guint32 max_dec_frame_buffering;
+};
+
+/**
+ * GstH264SPS:
+ * @id: The ID of the sequence parameter set
+ * @profile_idc: indicate the profile to which the coded video sequence conforms
+ *
+ *
+ */
+struct _GstH264SPS
+{
+ gint id;
+
+ guint8 profile_idc;
+ guint8 constraint_set0_flag;
+ guint8 constraint_set1_flag;
+ guint8 constraint_set2_flag;
+ guint8 constraint_set3_flag;
+ guint8 level_idc;
+
+ guint8 chroma_format_idc;
+ guint8 separate_colour_plane_flag;
+ guint8 bit_depth_luma_minus8;
+ guint8 bit_depth_chroma_minus8;
+ guint8 qpprime_y_zero_transform_bypass_flag;
+
+ guint8 scaling_matrix_present_flag;
+ guint8 scaling_lists_4x4[6][16];
+ guint8 scaling_lists_8x8[6][64];
+
+ guint8 log2_max_frame_num_minus4;
+ guint8 pic_order_cnt_type;
+
+ /* if pic_order_cnt_type == 0 */
+ guint8 log2_max_pic_order_cnt_lsb_minus4;
+
+ /* else if pic_order_cnt_type == 1 */
+ guint8 delta_pic_order_always_zero_flag;
+ gint32 offset_for_non_ref_pic;
+ gint32 offset_for_top_to_bottom_field;
+ guint8 num_ref_frames_in_pic_order_cnt_cycle;
+ gint32 offset_for_ref_frame[255];
+
+ guint32 num_ref_frames;
+ guint8 gaps_in_frame_num_value_allowed_flag;
+ guint32 pic_width_in_mbs_minus1;
+ guint32 pic_height_in_map_units_minus1;
+ guint8 frame_mbs_only_flag;
+
+ guint8 mb_adaptive_frame_field_flag;
+
+ guint8 direct_8x8_inference_flag;
+
+ guint8 frame_cropping_flag;
+
+ /* if frame_cropping_flag */
+ guint32 frame_crop_left_offset;
+ guint32 frame_crop_right_offset;
+ guint32 frame_crop_top_offset;
+ guint32 frame_crop_bottom_offset;
+
+ guint8 vui_parameters_present_flag;
+ /* if vui_parameters_present_flag */
+ GstH264VUIParams vui_parameters;
+
+ /* calculated values */
+ guint8 chroma_array_type;
+ guint32 max_frame_num;
+ gint width, height;
+ gint fps_num, fps_den;
+ gboolean valid;
+};
+
+struct _GstH264PPS
+{
+ gint id;
+
+ GstH264SPS *sequence;
+
+ guint8 entropy_coding_mode_flag;
+ guint8 pic_order_present_flag;
+
+ guint32 num_slice_groups_minus1;
+
+ /* if num_slice_groups_minus1 > 0 */
+ guint8 slice_group_map_type;
+ /* and if slice_group_map_type == 0 */
+ guint32 run_length_minus1[8];
+ /* or if slice_group_map_type == 2 */
+ guint32 top_left[8];
+ guint32 bottom_right[8];
+ /* or if slice_group_map_type == (3, 4, 5) */
+ guint8 slice_group_change_direction_flag;
+ guint32 slice_group_change_rate_minus1;
+ /* or if slice_group_map_type == 6 */
+ guint32 pic_size_in_map_units_minus1;
+ guint8 *slice_group_id;
+
+ guint8 num_ref_idx_l0_active_minus1;
+ guint8 num_ref_idx_l1_active_minus1;
+ guint8 weighted_pred_flag;
+ guint8 weighted_bipred_idc;
+ gint8 pic_init_qp_minus26;
+ gint8 pic_init_qs_minus26;
+ gint8 chroma_qp_index_offset;
+ guint8 deblocking_filter_control_present_flag;
+ guint8 constrained_intra_pred_flag;
+ guint8 redundant_pic_cnt_present_flag;
+
+ guint8 transform_8x8_mode_flag;
+
+ guint8 scaling_lists_4x4[6][16];
+ guint8 scaling_lists_8x8[6][64];
+
+ guint8 second_chroma_qp_index_offset;
+
+ gboolean valid;
+};
+
+struct _GstH264PredWeightTable
+{
+ guint8 luma_log2_weight_denom;
+ guint8 chroma_log2_weight_denom;
+
+ gint16 luma_weight_l0[32];
+ gint8 luma_offset_l0[32];
+
+ /* if seq->ChromaArrayType != 0 */
+ gint16 chroma_weight_l0[32][2];
+ gint8 chroma_offset_l0[32][2];
+
+ /* if slice->slice_type % 5 == 1 */
+ gint16 luma_weight_l1[32];
+ gint8 luma_offset_l1[32];
+
+ /* and if seq->ChromaArrayType != 0 */
+ gint16 chroma_weight_l1[32][2];
+ gint8 chroma_offset_l1[32][2];
+};
+
+struct _GstH264RefPicMarking
+{
+ guint8 memory_management_control_operation;
+
+ guint32 difference_of_pic_nums_minus1;
+ guint32 long_term_pic_num;
+ guint32 long_term_frame_idx;
+ guint32 max_long_term_frame_idx_plus1;
+};
+
+struct _GstH264DecRefPicMarking
+{
+ /* if slice->nal_unit.IdrPicFlag */
+ guint8 no_output_of_prior_pics_flag;
+ guint8 long_term_reference_flag;
+
+ guint8 adaptive_ref_pic_marking_mode_flag;
+ GstH264RefPicMarking ref_pic_marking[10];
+ guint8 n_ref_pic_marking;
+};
+
+
+struct _GstH264SliceHdr
+{
+ guint32 first_mb_in_slice;
+ guint32 type;
+ GstH264PPS *pps;
+
+ /* if seq->separate_colour_plane_flag */
+ guint8 colour_plane_id;
+
+ guint16 frame_num;
+
+ guint8 field_pic_flag;
+ guint8 bottom_field_flag;
+
+ /* if nal_unit.type == 5 */
+ guint16 idr_pic_id;
+
+ /* if seq->pic_order_cnt_type == 0 */
+ guint16 pic_order_cnt_lsb;
+ /* if seq->pic_order_present_flag && !field_pic_flag */
+ gint32 delta_pic_order_cnt_bottom;
+
+ gint32 delta_pic_order_cnt[2];
+ guint8 redundant_pic_cnt;
+
+ /* if slice_type == B_SLICE */
+ guint8 direct_spatial_mv_pred_flag;
+
+ guint8 num_ref_idx_l0_active_minus1;
+ guint8 num_ref_idx_l1_active_minus1;
+
+ GstH264PredWeightTable pred_weight_table;
+ /* if nal_unit.ref_idc != 0 */
+ GstH264DecRefPicMarking dec_ref_pic_marking;
+
+ guint8 cabac_init_idc;
+ gint8 slice_qp_delta;
+ gint8 slice_qs_delta;
+
+ guint8 disable_deblocking_filter_idc;
+ gint8 slice_alpha_c0_offset_div2;
+ gint8 slice_beta_offset_div2;
+
+ guint16 slice_group_change_cycle;
+
+ /* calculated values */
+ guint32 max_pic_num;
+ gboolean valid;
+
+ /* Size of the slice_header() in bits */
+ guint header_size;
+};
+
+
+struct _GstH264ClockTimestamp
+{
+ guint8 ct_type;
+ guint8 nuit_field_based_flag;
+ guint8 counting_type;
+ guint8 discontinuity_flag;
+ guint8 cnt_dropped_flag;
+ guint8 n_frames;
+
+ guint8 seconds_flag;
+ guint8 seconds_value;
+
+ guint8 minutes_flag;
+ guint8 minutes_value;
+
+ guint8 hours_flag;
+ guint8 hours_value;
+
+ guint32 time_offset;
+};
+
+struct _GstH264PicTiming
+{
+ guint32 cpb_removal_delay;
+ guint32 dpb_output_delay;
+
+ guint8 pic_struct_present_flag;
+ /* if pic_struct_present_flag */
+ guint8 pic_struct;
+
+ guint8 clock_timestamp_flag[3];
+ GstH264ClockTimestamp clock_timestamp[3];
+};
+
+struct _GstH264BufferingPeriod
+{
+ GstH264SPS *sps;
+
+ /* seq->vui_parameters->nal_hrd_parameters_present_flag */
+ guint8 nal_initial_cpb_removal_delay[32];
+ guint8 nal_initial_cpb_removal_delay_offset[32];
+
+ /* seq->vui_parameters->vcl_hrd_parameters_present_flag */
+ guint8 vcl_initial_cpb_removal_delay[32];
+ guint8 vcl_initial_cpb_removal_delay_offset[32];
+};
+
+struct _GstH264SEIMessage
+{
+ GstH264SEIPayloadType payloadType;
+
+ union {
+ GstH264BufferingPeriod buffering_period;
+ GstH264PicTiming pic_timing;
+ /* ... could implement more */
+ };
+};
+
+/**
+ * GstH264NalParser:
+ *
+ * H264 NAL Parser (opaque structure).
+ */
+struct _GstH264NalParser
+{
+ /*< private >*/
+ GstH264SPS sps[GST_H264_MAX_SPS_COUNT];
+ GstH264PPS pps[GST_H264_MAX_PPS_COUNT];
+ GstH264SPS *last_sps;
+ GstH264PPS *last_pps;
+};
+
+GstH264NalParser *gst_h264_nal_parser_new (void);
+
+GstH264ParserResult gst_h264_parser_identify_nalu (GstH264NalParser *nalparser,
+ const guint8 *data, guint offset,
+ gsize size, GstH264NalUnit *nalu);
+
+GstH264ParserResult gst_h264_parser_identify_nalu_avc (GstH264NalParser *nalparser, const guint8 *data,
+ guint offset, gsize size, guint8 nal_length_size,
+ GstH264NalUnit *nalu);
+
+GstH264ParserResult gst_h264_parser_parse_nal (GstH264NalParser *nalparser,
+ GstH264NalUnit *nalu);
+
+GstH264ParserResult gst_h264_parser_parse_slice_hdr (GstH264NalParser *nalparser, GstH264NalUnit *nalu,
+ GstH264SliceHdr *slice, gboolean parse_pred_weight_table,
+ gboolean parse_dec_ref_pic_marking);
+
+GstH264ParserResult gst_h264_parser_parse_sps (GstH264NalParser *nalparser, GstH264NalUnit *nalu,
+ GstH264SPS *sps, gboolean parse_vui_params);
+
+GstH264ParserResult gst_h264_parser_parse_pps (GstH264NalParser *nalparser,
+ GstH264NalUnit *nalu, GstH264PPS *pps);
+
+GstH264ParserResult gst_h264_parser_parse_sei (GstH264NalParser *nalparser,
+ GstH264NalUnit *nalu, GstH264SEIMessage *sei);
+
+void gst_h264_nal_parser_free (GstH264NalParser *nalparser);
+
+GstH264ParserResult gst_h264_parse_sps (GstH264NalUnit *nalu,
+ GstH264SPS *sps, gboolean parse_vui_params);
+
+GstH264ParserResult gst_h264_parse_pps (GstH264NalParser *nalparser,
+ GstH264NalUnit *nalu, GstH264PPS *pps);
+
+G_END_DECLS
+#endif
diff --git a/gst-libs/gst/codecparsers/gstmpegvideoparser.c b/gst-libs/gst/codecparsers/gstmpegvideoparser.c
new file mode 100644
index 0000000000..44df76ad5e
--- /dev/null
+++ b/gst-libs/gst/codecparsers/gstmpegvideoparser.c
@@ -0,0 +1,755 @@
+/* Gstreamer
+ * Copyright (C) <2011> Intel Corporation
+ * Copyright (C) <2011> Collabora Ltd.
+ * Copyright (C) <2011> Thibault Saunier
+ *
+ * From bad/sys/vdpau/mpeg/mpegutil.c:
+ * Copyright (C) <2007> Jan Schmidt
+ * Copyright (C) <2009> Carl-Anton Ingmarsson
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+/**
+ * SECTION:gstmpegvideoparser
+ * @short_description: Convenience library for mpeg1 and 2 video
+ * bitstream parsing.
+ *
+ *
+ *
+ * Provides useful functions for mpeg videos bitstream parsing.
+ *
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include "gstmpegvideoparser.h"
+
+#include
+#include
+#include
+
+#define MARKER_BIT 0x1
+
+#define GET_BITS(b, num, bits) G_STMT_START { \
+ if (!gst_bit_reader_get_bits_uint32(b, bits, num)) \
+ goto failed; \
+ GST_TRACE ("parsed %d bits: %d", num, *(bits)); \
+} G_STMT_END
+
+#define READ_UINT8(br, val, nbits) G_STMT_START { \
+ if (!gst_bit_reader_get_bits_uint8 (br, &val, nbits)) { \
+ GST_WARNING ("failed to read uint8, nbits: %d", nbits); \
+ goto failed; \
+ } \
+} G_STMT_END
+
+#define READ_UINT16(br, val, nbits) G_STMT_START { \
+ if (!gst_bit_reader_get_bits_uint16 (br, &val, nbits)) { \
+ GST_WARNING ("failed to read uint16, nbits: %d", nbits); \
+ goto failed; \
+ } \
+} G_STMT_END
+
+#define READ_UINT32(br, val, nbits) G_STMT_START { \
+ if (!gst_bit_reader_get_bits_uint32 (br, &val, nbits)) { \
+ GST_WARNING ("failed to read uint32, nbits: %d", nbits); \
+ goto failed; \
+ } \
+} G_STMT_END
+
+/* default intra quant matrix, in zig-zag order */
+const guint8 default_intra_quantizer_matrix[64] = {
+ 8,
+ 16, 16,
+ 19, 16, 19,
+ 22, 22, 22, 22,
+ 22, 22, 26, 24, 26,
+ 27, 27, 27, 26, 26, 26,
+ 26, 27, 27, 27, 29, 29, 29,
+ 34, 34, 34, 29, 29, 29, 27, 27,
+ 29, 29, 32, 32, 34, 34, 37,
+ 38, 37, 35, 35, 34, 35,
+ 38, 38, 40, 40, 40,
+ 48, 48, 46, 46,
+ 56, 56, 58,
+ 69, 69,
+ 83
+};
+
+const guint8 mpeg_zigzag_8x8[64] = {
+ 0, 1, 8, 16, 9, 2, 3, 10,
+ 17, 24, 32, 25, 18, 11, 4, 5,
+ 12, 19, 26, 33, 40, 48, 41, 34,
+ 27, 20, 13, 6, 7, 14, 21, 28,
+ 35, 42, 49, 56, 57, 50, 43, 36,
+ 29, 22, 15, 23, 30, 37, 44, 51,
+ 58, 59, 52, 45, 38, 31, 39, 46,
+ 53, 60, 61, 54, 47, 55, 62, 63
+};
+
+GST_DEBUG_CATEGORY (mpegvideo_parser_debug);
+#define GST_CAT_DEFAULT mpegvideo_parser_debug
+
+static gboolean initialized = FALSE;
+
+static inline gboolean
+find_start_code (GstBitReader * b)
+{
+ guint32 bits;
+
+ /* 0 bits until byte aligned */
+ while (b->bit != 0) {
+ GET_BITS (b, 1, &bits);
+ }
+
+ /* 0 bytes until startcode */
+ while (gst_bit_reader_peek_bits_uint32 (b, &bits, 32)) {
+ if (bits >> 8 == 0x1) {
+ return TRUE;
+ } else {
+ gst_bit_reader_skip (b, 8);
+ }
+ }
+
+ return FALSE;
+
+failed:
+ return FALSE;
+}
+
+/* Set the Pixel Aspect Ratio in our hdr from a DAR code in the data */
+static void
+set_par_from_dar (GstMpegVideoSequenceHdr * seqhdr, guint8 asr_code)
+{
+ /* Pixel_width = DAR_width * display_vertical_size */
+ /* Pixel_height = DAR_height * display_horizontal_size */
+ switch (asr_code) {
+ case 0x02: /* 3:4 DAR = 4:3 pixels */
+ seqhdr->par_w = 4 * seqhdr->height;
+ seqhdr->par_h = 3 * seqhdr->width;
+ break;
+ case 0x03: /* 9:16 DAR */
+ seqhdr->par_w = 16 * seqhdr->height;
+ seqhdr->par_h = 9 * seqhdr->width;
+ break;
+ case 0x04: /* 1:2.21 DAR */
+ seqhdr->par_w = 221 * seqhdr->height;
+ seqhdr->par_h = 100 * seqhdr->width;
+ break;
+ case 0x01: /* Square pixels */
+ seqhdr->par_w = seqhdr->par_h = 1;
+ break;
+ default:
+ GST_DEBUG ("unknown/invalid aspect_ratio_information %d", asr_code);
+ break;
+ }
+}
+
+static void
+set_fps_from_code (GstMpegVideoSequenceHdr * seqhdr, guint8 fps_code)
+{
+ const gint framerates[][2] = {
+ {30, 1}, {24000, 1001}, {24, 1}, {25, 1},
+ {30000, 1001}, {30, 1}, {50, 1}, {60000, 1001},
+ {60, 1}, {30, 1}
+ };
+
+ if (fps_code && fps_code < 10) {
+ seqhdr->fps_n = framerates[fps_code][0];
+ seqhdr->fps_d = framerates[fps_code][1];
+ } else {
+ GST_DEBUG ("unknown/invalid frame_rate_code %d", fps_code);
+ /* Force a valid framerate */
+ /* FIXME or should this be kept unknown ?? */
+ seqhdr->fps_n = 30000;
+ seqhdr->fps_d = 1001;
+ }
+}
+
+static gboolean
+gst_mpeg_video_parse_sequence (GstMpegVideoSequenceHdr * seqhdr,
+ GstBitReader * br)
+{
+ guint8 bits;
+ guint8 load_intra_flag, load_non_intra_flag;
+
+ /* Setting the height/width codes */
+ READ_UINT16 (br, seqhdr->width, 12);
+ READ_UINT16 (br, seqhdr->height, 12);
+
+ READ_UINT8 (br, seqhdr->aspect_ratio_info, 4);
+ set_par_from_dar (seqhdr, seqhdr->aspect_ratio_info);
+
+ READ_UINT8 (br, seqhdr->frame_rate_code, 4);
+ set_fps_from_code (seqhdr, seqhdr->frame_rate_code);
+
+ READ_UINT32 (br, seqhdr->bitrate_value, 18);
+ if (seqhdr->bitrate_value == 0x3ffff) {
+ /* VBR stream */
+ seqhdr->bitrate = 0;
+ } else {
+ /* Value in header is in units of 400 bps */
+ seqhdr->bitrate *= 400;
+ }
+
+ READ_UINT8 (br, bits, 1);
+ if (bits != MARKER_BIT)
+ goto failed;
+
+ /* VBV buffer size */
+ READ_UINT16 (br, seqhdr->vbv_buffer_size_value, 10);
+
+ /* constrained_parameters_flag */
+ READ_UINT8 (br, seqhdr->constrained_parameters_flag, 1);
+
+ /* load_intra_quantiser_matrix */
+ READ_UINT8 (br, load_intra_flag, 1);
+ if (load_intra_flag) {
+ gint i;
+ for (i = 0; i < 64; i++)
+ READ_UINT8 (br, seqhdr->intra_quantizer_matrix[mpeg_zigzag_8x8[i]], 8);
+ } else
+ memcpy (seqhdr->intra_quantizer_matrix, default_intra_quantizer_matrix, 64);
+
+ /* non intra quantizer matrix */
+ READ_UINT8 (br, load_non_intra_flag, 1);
+ if (load_non_intra_flag) {
+ gint i;
+ for (i = 0; i < 64; i++)
+ READ_UINT8 (br, seqhdr->non_intra_quantizer_matrix[mpeg_zigzag_8x8[i]],
+ 8);
+ } else
+ memset (seqhdr->non_intra_quantizer_matrix, 16, 64);
+
+ /* dump some info */
+ GST_LOG ("width x height: %d x %d", seqhdr->width, seqhdr->height);
+ GST_LOG ("fps: %d/%d", seqhdr->fps_n, seqhdr->fps_d);
+ GST_LOG ("par: %d/%d", seqhdr->par_w, seqhdr->par_h);
+ GST_LOG ("bitrate: %d", seqhdr->bitrate);
+
+ return TRUE;
+
+ /* ERRORS */
+failed:
+ {
+ GST_WARNING ("Failed to parse sequence header");
+ /* clear out stuff */
+ memset (seqhdr, 0, sizeof (*seqhdr));
+ return FALSE;
+ }
+}
+
+static inline guint
+scan_for_start_codes (const GstByteReader * reader, guint offset, guint size)
+{
+ const guint8 *data;
+ guint32 state;
+ guint i;
+
+ g_return_val_if_fail (size > 0, -1);
+ g_return_val_if_fail ((guint64) offset + size <= reader->size - reader->byte,
+ -1);
+
+ /* we can't find the pattern with less than 4 bytes */
+ if (G_UNLIKELY (size < 4))
+ return -1;
+
+ data = reader->data + reader->byte + offset;
+
+ /* set the state to something that does not match */
+ state = 0xffffffff;
+
+ /* now find data */
+ for (i = 0; i < size; i++) {
+ /* throw away one byte and move in the next byte */
+ state = ((state << 8) | data[i]);
+ if (G_UNLIKELY ((state & 0xffffff00) == 0x00000100)) {
+ /* we have a match but we need to have skipped at
+ * least 4 bytes to fill the state. */
+ if (G_LIKELY (i >= 3))
+ return offset + i - 3;
+ }
+
+ /* TODO: reimplement making 010001 not detected as a sc
+ * Accelerate search for start code
+ * if (data[i] > 1) {
+ * while (i < (size - 4) && data[i] > 1) {
+ * if (data[i + 3] > 1)
+ * i += 4;
+ * else
+ * i += 1;
+ * }
+ * state = 0x00000100;
+ *}
+ */
+ }
+
+ /* nothing found */
+ return -1;
+}
+
+/****** API *******/
+
+/**
+ * gst_mpeg_video_parse:
+ * @data: The datas from which to parse
+ * @size: The size of @data
+ * @offset: The offset from which to start the parsing
+ *
+ * Parses @data, and detects the different packets types, offset,
+ * and size, starting from @offset
+ *
+ * Returns: a #GList of #GstMpegVideoTypeOffsetSize
+ */
+GList *
+gst_mpeg_video_parse (guint8 * data, gsize size, guint offset)
+{
+ gint off, rsize;
+ GstByteReader br;
+ GList *ret = NULL;
+ size = size - offset;
+
+ if (!initialized) {
+ GST_DEBUG_CATEGORY_INIT (mpegvideo_parser_debug, "codecparsers_mpegvideo",
+ 0, "Mpegvideo parser library");
+ initialized = TRUE;
+ }
+
+ if (size <= 0) {
+ GST_DEBUG ("Can't parse from offset %d, buffer is to small", offset);
+ return NULL;
+ }
+
+ gst_byte_reader_init (&br, &data[offset], size);
+
+ off = scan_for_start_codes (&br, 0, size);
+
+ if (off < 0) {
+ GST_DEBUG ("No start code prefix in this buffer");
+ return NULL;
+ }
+
+ while (off >= 0 && off + 3 < size) {
+ GstMpegVideoTypeOffsetSize *codoffsize;
+
+ gst_byte_reader_skip (&br, off + 3);
+
+ codoffsize = g_malloc (sizeof (GstMpegVideoTypeOffsetSize));
+ gst_byte_reader_get_uint8 (&br, &codoffsize->type);
+
+ codoffsize->offset = gst_byte_reader_get_pos (&br) + offset;
+
+ rsize = gst_byte_reader_get_remaining (&br);
+ if (rsize <= 0)
+ break;
+
+ off = scan_for_start_codes (&br, 0, rsize);
+
+ codoffsize->size = off;
+
+ ret = g_list_prepend (ret, codoffsize);
+ codoffsize = ret->data;
+ }
+
+ return g_list_reverse (ret);
+}
+
+/**
+ * gst_mpeg_video_parse_sequence_header:
+ * @seqhdr: The #GstMpegVideoSequenceHdr to set
+ * @data: The datas from which to parse the seqhdr
+ * @size: The size of @data
+ * @offset: The offset in byte from which to start parsing @data
+ *
+ * Sets the @seqhdr Mpeg Video Sequence Header structure members from @data
+ *
+ * Returns: %TRUE if the seqhdr could be parsed correctly, %FALSE otherwize.
+ */
+gboolean
+gst_mpeg_video_parse_sequence_header (GstMpegVideoSequenceHdr * seqhdr,
+ guint8 * data, gsize size, guint offset)
+{
+ GstBitReader br;
+
+ size = size - offset;
+
+ if (size - offset < 4)
+ return FALSE;
+
+ gst_bit_reader_init (&br, &data[offset], size);
+
+ return gst_mpeg_video_parse_sequence (seqhdr, &br);
+}
+
+/**
+ * gst_mpeg_video_parse_sequence_extension:
+ * @seqhdr: The #GstMpegVideoSequenceExt to set
+ * @data: The datas from which to parse the seqext
+ * @size: The size of @data
+ * @offset: The offset in byte from which to start parsing @data
+ *
+ * Sets the @seqext Mpeg Video Sequence Extension structure members from @data
+ *
+ * Returns: %TRUE if the seqext could be parsed correctly, %FALSE otherwize.
+ */
+gboolean
+gst_mpeg_video_parse_sequence_extension (GstMpegVideoSequenceExt * seqext,
+ guint8 * data, gsize size, guint offset)
+{
+ GstBitReader br;
+
+ size = size - offset;
+
+ if (size < 6) {
+ GST_DEBUG ("not enough bytes to parse the extension");
+ return FALSE;
+ }
+
+ gst_bit_reader_init (&br, &data[offset], size);
+
+ if (gst_bit_reader_get_bits_uint8_unchecked (&br, 4) !=
+ GST_MPEG_VIDEO_PACKET_EXT_SEQUENCE) {
+ GST_DEBUG ("Not parsing a sequence extension");
+ return FALSE;
+ }
+
+ /* skip profile and level escape bit */
+ gst_bit_reader_skip_unchecked (&br, 1);
+
+ seqext->profile = gst_bit_reader_get_bits_uint8_unchecked (&br, 3);
+ seqext->level = gst_bit_reader_get_bits_uint8_unchecked (&br, 4);
+
+ /* progressive */
+ seqext->progressive = gst_bit_reader_get_bits_uint8_unchecked (&br, 1);
+
+ /* chroma format */
+ seqext->chroma_format = gst_bit_reader_get_bits_uint8_unchecked (&br, 2);
+
+ /* resolution extension */
+ seqext->horiz_size_ext = gst_bit_reader_get_bits_uint8_unchecked (&br, 2);
+ seqext->vert_size_ext = gst_bit_reader_get_bits_uint8_unchecked (&br, 2);
+
+ seqext->bitrate_ext = gst_bit_reader_get_bits_uint16_unchecked (&br, 12);
+
+ /* skip marker bits */
+ gst_bit_reader_skip_unchecked (&br, 1);
+
+ seqext->vbv_buffer_size_extension =
+ gst_bit_reader_get_bits_uint8_unchecked (&br, 8);
+ seqext->low_delay = gst_bit_reader_get_bits_uint8_unchecked (&br, 1);
+
+ /* framerate extension */
+ seqext->fps_n_ext = gst_bit_reader_get_bits_uint8_unchecked (&br, 2);
+ seqext->fps_d_ext = gst_bit_reader_get_bits_uint8_unchecked (&br, 2);
+
+ return TRUE;
+}
+
+/**
+ * gst_mpeg_video_parse_quant_matrix_extension:
+ * @ext: The #GstMpegVideoQuantMatrixExt to set
+ * @data: The datas from which to parse @quant
+ * @size: The size of @data
+ * @offset: The offset in byte from which to start the parsing
+ *
+ * Sets the @quant Mpeg Video Quant Matrix Extension structure members from
+ * @data
+ *
+ * Returns: %TRUE if the quant matrix extension could be parsed correctly,
+ * %FALSE otherwize.
+ */
+gboolean
+gst_mpeg_video_parse_quant_matrix_extension (GstMpegVideoQuantMatrixExt * quant,
+ guint8 * data, gsize size, guint offset)
+{
+ guint8 i;
+ GstBitReader br;
+
+ size = size - offset;
+
+ if (size < 1) {
+ GST_DEBUG ("not enough bytes to parse the extension");
+ return FALSE;
+ }
+
+ gst_bit_reader_init (&br, &data[offset], size);
+
+ if (gst_bit_reader_get_bits_uint8_unchecked (&br, 4) !=
+ GST_MPEG_VIDEO_PACKET_EXT_QUANT_MATRIX) {
+ GST_DEBUG ("Not parsing a quant matrix extension");
+ return FALSE;
+ }
+
+ READ_UINT8 (&br, quant->load_intra_quantiser_matrix, 1);
+ if (quant->load_intra_quantiser_matrix) {
+ for (i = 0; i < 64; i++) {
+ READ_UINT8 (&br, quant->intra_quantiser_matrix[mpeg_zigzag_8x8[i]], 8);
+ }
+ }
+
+ READ_UINT8 (&br, quant->load_non_intra_quantiser_matrix, 1);
+ if (quant->load_non_intra_quantiser_matrix) {
+ for (i = 0; i < 64; i++) {
+ READ_UINT8 (&br, quant->non_intra_quantiser_matrix[mpeg_zigzag_8x8[i]],
+ 8);
+ }
+ }
+
+ READ_UINT8 (&br, quant->load_chroma_intra_quantiser_matrix, 1);
+ if (quant->load_non_intra_quantiser_matrix) {
+ for (i = 0; i < 64; i++) {
+ READ_UINT8 (&br, quant->chroma_intra_quantiser_matrix[mpeg_zigzag_8x8[i]],
+ 8);
+ }
+ }
+
+ READ_UINT8 (&br, quant->load_chroma_non_intra_quantiser_matrix, 1);
+ if (quant->load_chroma_non_intra_quantiser_matrix) {
+ for (i = 0; i < 64; i++) {
+ READ_UINT8 (&br,
+ quant->chroma_non_intra_quantiser_matrix[mpeg_zigzag_8x8[i]], 8);
+ }
+ }
+
+ return TRUE;
+
+failed:
+ GST_WARNING ("error parsing \"Quant Matrix Extension\"");
+ return FALSE;
+}
+
+/**
+ * gst_mpeg_video_parse_picture_extension:
+ * @ext: The #GstMpegVideoPictureExt to set
+ * @data: The datas from which to parse the ext
+ * @size: The size of @data
+ * @offset: The offset in byte from which to start the parsing
+ *
+ * Sets the @ext Mpeg Video Picture Extension structure members from @data
+ *
+ * Returns: %TRUE if the picture extension could be parsed correctly,
+ * %FALSE otherwize.
+ */
+gboolean
+gst_mpeg_video_parse_picture_extension (GstMpegVideoPictureExt * ext,
+ guint8 * data, gsize size, guint offset)
+{
+ GstBitReader br;
+
+ size = size - offset;
+
+ if (size < 4)
+ return FALSE;
+
+ gst_bit_reader_init (&br, &data[offset], size);
+
+ if (gst_bit_reader_get_bits_uint8_unchecked (&br, 4) !=
+ GST_MPEG_VIDEO_PACKET_EXT_PICTURE) {
+ GST_DEBUG ("Not parsing a picture extension");
+ return FALSE;
+ }
+
+ /* f_code */
+ READ_UINT8 (&br, ext->f_code[0][0], 4);
+ READ_UINT8 (&br, ext->f_code[0][1], 4);
+ READ_UINT8 (&br, ext->f_code[1][0], 4);
+ READ_UINT8 (&br, ext->f_code[1][1], 4);
+
+ /* intra DC precision */
+ READ_UINT8 (&br, ext->intra_dc_precision, 2);
+
+ /* picture structure */
+ READ_UINT8 (&br, ext->picture_structure, 2);
+
+ /* top field first */
+ READ_UINT8 (&br, ext->top_field_first, 1);
+
+ /* frame pred frame dct */
+ READ_UINT8 (&br, ext->frame_pred_frame_dct, 1);
+
+ /* concealment motion vectors */
+ READ_UINT8 (&br, ext->concealment_motion_vectors, 1);
+
+ /* q scale type */
+ READ_UINT8 (&br, ext->q_scale_type, 1);
+
+ /* intra vlc format */
+ READ_UINT8 (&br, ext->intra_vlc_format, 1);
+
+ /* alternate scan */
+ READ_UINT8 (&br, ext->alternate_scan, 1);
+
+ /* repeat first field */
+ READ_UINT8 (&br, ext->repeat_first_field, 1);
+
+ /* chroma_420_type */
+ READ_UINT8 (&br, ext->chroma_420_type, 1);
+
+ /* progressive_frame */
+ READ_UINT8 (&br, ext->progressive_frame, 1);
+
+ /* composite display */
+ READ_UINT8 (&br, ext->composite_display, 1);
+
+ if (ext->composite_display) {
+
+ /* v axis */
+ READ_UINT8 (&br, ext->v_axis, 1);
+
+ /* field sequence */
+ READ_UINT8 (&br, ext->field_sequence, 3);
+
+ /* sub carrier */
+ READ_UINT8 (&br, ext->sub_carrier, 1);
+
+ /* burst amplitude */
+ READ_UINT8 (&br, ext->burst_amplitude, 7);
+
+ /* sub_carrier phase */
+ READ_UINT8 (&br, ext->sub_carrier_phase, 8);
+ }
+
+ return TRUE;
+
+failed:
+ GST_WARNING ("error parsing \"Picture Coding Extension\"");
+ return FALSE;
+
+}
+
+/**
+ * gst_mpeg_video_parse_picture_header:
+ * @hdr: The #GstMpegVideoPictureHdr to set
+ * @data: The datas from which to parse the hdr
+ * @size: The size of @data
+ * @offset: The offset in byte from which to start the parsing
+ *
+ * Sets the @hdr Mpeg Video Picture Header structure members from @data
+ *
+ * Returns: %TRUE if the picture sequence could be parsed correctly, %FALSE otherwize.
+ */
+gboolean
+gst_mpeg_video_parse_picture_header (GstMpegVideoPictureHdr * hdr,
+ guint8 * data, gsize size, guint offset)
+{
+ GstBitReader br;
+
+ size = size - offset;
+
+ if (size < 4)
+ return FALSE;
+
+ gst_bit_reader_init (&br, &data[offset], size);
+
+ /* temperal sequence number */
+ if (!gst_bit_reader_get_bits_uint16 (&br, &hdr->tsn, 10))
+ return FALSE;
+
+ /* frame type */
+ if (!gst_bit_reader_get_bits_uint8 (&br, (guint8 *) & hdr->pic_type, 3))
+ return FALSE;
+
+ if (hdr->pic_type == 0 || hdr->pic_type > 4)
+ return FALSE; /* Corrupted picture packet */
+
+ /* skype VBV delay */
+ if (!gst_bit_reader_skip (&br, 8))
+ return FALSE;
+
+ if (hdr->pic_type == GST_MPEG_VIDEO_PICTURE_TYPE_P
+ || hdr->pic_type == GST_MPEG_VIDEO_PICTURE_TYPE_B) {
+
+ READ_UINT8 (&br, hdr->full_pel_forward_vector, 1);
+
+ READ_UINT8 (&br, hdr->f_code[0][0], 3);
+ hdr->f_code[0][1] = hdr->f_code[0][0];
+ } else {
+ hdr->full_pel_forward_vector = 0;
+ hdr->f_code[0][0] = hdr->f_code[0][1] = 0;
+ }
+
+ if (hdr->pic_type == GST_MPEG_VIDEO_PICTURE_TYPE_B) {
+ READ_UINT8 (&br, hdr->full_pel_backward_vector, 1);
+
+ READ_UINT8 (&br, hdr->f_code[1][0], 3);
+ hdr->f_code[1][1] = hdr->f_code[1][0];
+ } else {
+ hdr->full_pel_backward_vector = 0;
+ hdr->f_code[1][0] = hdr->f_code[1][1] = 0;
+ }
+
+ return TRUE;
+
+failed:
+ {
+ GST_WARNING ("Failed to parse sequence extension");
+ return FALSE;
+ }
+}
+
+/**
+ * gst_mpeg_video_parse_gop:
+ * @gop: The #GstMpegVideoGop to set
+ * @data: The datas from which to parse the gop
+ * @size: The size of @data
+ * @offset: The offset in byte from which to start the parsing
+ *
+ *
+ * Sets the @gop Mpeg Video Group of Picture structure members from @data
+ *
+ * Returns: %TRUE if the gop could be parsed correctly, %FALSE otherwize.
+ */
+gboolean
+gst_mpeg_video_parse_gop (GstMpegVideoGop * gop, guint8 * data,
+ gsize size, guint offset)
+{
+ GstBitReader br;
+
+ size = size - offset;
+
+ if (size < 4)
+ return FALSE;
+
+ gst_bit_reader_init (&br, &data[offset], size);
+
+ READ_UINT8 (&br, gop->drop_frame_flag, 1);
+
+ READ_UINT8 (&br, gop->hour, 5);
+
+ READ_UINT8 (&br, gop->minute, 6);
+
+ /* skip unused bit */
+ if (!gst_bit_reader_skip (&br, 1))
+ return FALSE;
+
+ READ_UINT8 (&br, gop->second, 6);
+
+ READ_UINT8 (&br, gop->frame, 6);
+
+ READ_UINT8 (&br, gop->closed_gop, 1);
+
+ READ_UINT8 (&br, gop->broken_gop, 1);
+
+ return TRUE;
+
+failed:
+ GST_WARNING ("error parsing \"GOP\"");
+ return FALSE;
+}
diff --git a/gst-libs/gst/codecparsers/gstmpegvideoparser.h b/gst-libs/gst/codecparsers/gstmpegvideoparser.h
new file mode 100644
index 0000000000..a42792b81b
--- /dev/null
+++ b/gst-libs/gst/codecparsers/gstmpegvideoparser.h
@@ -0,0 +1,368 @@
+/* Gstreamer
+ * Copyright (C) <2011> Intel Corporation
+ * Copyright (C) <2011> Collabora Ltd.
+ * Copyright (C) <2011> Thibault Saunier
+ *
+ * From bad/sys/vdpau/mpeg/mpegutil.c:
+ * Copyright (C) <2007> Jan Schmidt
+ * Copyright (C) <2009> Carl-Anton Ingmarsson
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __GST_MPEG_VIDEO_UTILS_H__
+#define __GST_MPEG_VIDEO_UTILS_H__
+
+#include
+
+G_BEGIN_DECLS
+
+/**
+ * GstMpegVideoPacketTypeCode:
+ * @GST_MPEG_VIDEO_PACKET_PICTURE: Picture packet starting code
+ * @GST_MPEG_VIDEO_PACKET_SLICE_MIN: Picture packet starting code
+ * @GST_MPEG_VIDEO_PACKET_SLICE_MAX: Slice max packet starting code
+ * @GST_MPEG_VIDEO_PACKET_USER_DATA: User data packet starting code
+ * @GST_MPEG_VIDEO_PACKET_SEQUENCE : Sequence packet starting code
+ * @GST_MPEG_VIDEO_PACKET_EXTENSION: Extension packet starting code
+ * @GST_MPEG_VIDEO_PACKET_SEQUENCE_END: Sequence end packet code
+ * @GST_MPEG_VIDEO_PACKET_GOP: Group of Picture packet starting code
+ * @GST_MPEG_VIDEO_PACKET_NONE: None packet code
+ *
+ * Indicates the type of MPEG packet
+ */
+typedef enum {
+ GST_MPEG_VIDEO_PACKET_PICTURE = 0x00,
+ GST_MPEG_VIDEO_PACKET_SLICE_MIN = 0x01,
+ GST_MPEG_VIDEO_PACKET_SLICE_MAX = 0xaf,
+ GST_MPEG_VIDEO_PACKET_USER_DATA = 0xb2,
+ GST_MPEG_VIDEO_PACKET_SEQUENCE = 0xb3,
+ GST_MPEG_VIDEO_PACKET_EXTENSION = 0xb5,
+ GST_MPEG_VIDEO_PACKET_SEQUENCE_END = 0xb7,
+ GST_MPEG_VIDEO_PACKET_GOP = 0xb8,
+ GST_MPEG_VIDEO_PACKET_NONE = 0xff
+} GstMpegVideoPacketTypeCode;
+
+/**
+ * GstMpegVideoPacketExtensionCode:
+ * @GST_MPEG_VIDEO_PACKET_EXT_SEQUENCE: Sequence extension code
+ * @GST_MPEG_VIDEO_PACKET_EXT_SEQUENCE_DISPLAY: Display extension code
+ * @GST_MPEG_VIDEO_PACKET_EXT_QUANT_MATRIX: Quantizer extension code
+ * @GST_MPEG_VIDEO_PACKET_EXT_GOP: Group Of Picture extension code
+ *
+ * Indicates what type of packets are in this
+ * block, some are mutually * exclusive though - ie, sequence packs are
+ * accumulated separately. GOP & Picture may occur together or separately
+ */
+typedef enum {
+ GST_MPEG_VIDEO_PACKET_EXT_SEQUENCE = 0x01,
+ GST_MPEG_VIDEO_PACKET_EXT_SEQUENCE_DISPLAY = 0x02,
+ GST_MPEG_VIDEO_PACKET_EXT_QUANT_MATRIX = 0x03,
+ GST_MPEG_VIDEO_PACKET_EXT_GOP = 0x04,
+ 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
+ *
+ * Indicates the level in use
+ **/
+typedef enum {
+ GST_MPEG_VIDEO_LEVEL_HIGH = 0x04,
+ GST_MPEG_VIDEO_LEVEL_HIGH_1440 = 0x06,
+ GST_MPEG_VIDEO_LEVEL_MAIN = 0x08,
+ GST_MPEG_VIDEO_LEVEL_LOW = 0x0a
+} GstMpegVideoLevel;
+
+/**
+ * GstMpegVideoProfile:
+ * @GST_MPEG_VIDEO_PROFILE_422,
+ * @GST_MPEG_VIDEO_PROFILE_HIGH,
+ * @GST_MPEG_VIDEO_PROFILE_SPATIALLY_SCALABLE,
+ * @GST_MPEG_VIDEO_PROFILE_SNR_SCALABLE,
+ * @GST_MPEG_VIDEO_PROFILE_MAIN,
+ * @GST_MPEG_VIDEO_PROFILE_SIMPLE,
+ *
+ * Indicates the profile type in use
+ **/
+typedef enum {
+ GST_MPEG_VIDEO_PROFILE_422 = 0x00,
+ GST_MPEG_VIDEO_PROFILE_HIGH = 0x01,
+ GST_MPEG_VIDEO_PROFILE_SPATIALLY_SCALABLE = 0x02,
+ GST_MPEG_VIDEO_PROFILE_SNR_SCALABLE = 0x03,
+ GST_MPEG_VIDEO_PROFILE_MAIN = 0x04,
+ GST_MPEG_VIDEO_PROFILE_SIMPLE = 0x05
+} GstMpegVideoProfile;
+
+/**
+ * GstMpegVideoPictureType:
+ * @GST_MPEG_VIDEO_PICTURE_TYPE_I: Type I
+ * @GST_MPEG_VIDEO_PICTURE_TYPE_P: Type P
+ * @GST_MPEG_VIDEO_PICTURE_TYPE_B: Type B
+ * @GST_MPEG_VIDEO_PICTURE_TYPE_D: Type D
+ *
+ * Indicates the type of picture
+ */
+typedef enum {
+ GST_MPEG_VIDEO_PICTURE_TYPE_I = 0x01,
+ GST_MPEG_VIDEO_PICTURE_TYPE_P = 0x02,
+ GST_MPEG_VIDEO_PICTURE_TYPE_B = 0x03,
+ GST_MPEG_VIDEO_PICTURE_TYPE_D = 0x04
+} GstMpegVideoPictureType;
+
+/**
+ * GstMpegVideoPictureStructure:
+ * @GST_MPEG_VIDEO_PICTURE_STRUCTURE_TOP_FIELD: Top field
+ * @GST_MPEG_VIDEO_PICTURE_STRUCTURE_BOTTOM_FIELD: Bottom field
+ * @GST_MPEG_VIDEO_PICTURE_STRUCTURE_FRAME: Frame
+ *
+ * Indicates the structure of picture
+ */
+typedef enum {
+ GST_MPEG_VIDEO_PICTURE_STRUCTURE_TOP_FIELD = 0x01,
+ GST_MPEG_VIDEO_PICTURE_STRUCTURE_BOTTOM_FIELD = 0x02,
+ GST_MPEG_VIDEO_PICTURE_STRUCTURE_FRAME = 0x03
+} GstMpegVideoPictureStructure;
+
+typedef struct _GstMpegVideoSequenceHdr GstMpegVideoSequenceHdr;
+typedef struct _GstMpegVideoSequenceExt GstMpegVideoSequenceExt;
+typedef struct _GstMpegVideoPictureHdr GstMpegVideoPictureHdr;
+typedef struct _GstMpegVideoGop GstMpegVideoGop;
+typedef struct _GstMpegVideoPictureExt GstMpegVideoPictureExt;
+typedef struct _GstMpegVideoQuantMatrixExt GstMpegVideoQuantMatrixExt;
+typedef struct _GstMpegVideoTypeOffsetSize GstMpegVideoTypeOffsetSize;
+
+/**
+ * GstMpegVideoSequenceHdr:
+ * @width: Width of each frame
+ * @height: Height of each frame
+ * @par_w: Calculated Pixel Aspect Ratio width
+ * @par_h: Pixel Aspect Ratio height
+ * @fps_n: Calculated Framrate nominator
+ * @fps_d: Calculated Framerate denominator
+ * @bitrate_value: Value of the bitrate as is in the stream (400bps unit)
+ * @bitrate: the real bitrate of the Mpeg video stream in bits per second, 0 if VBR stream
+ * @constrained_parameters_flag: %TRUE if this stream uses contrained parameters.
+ * @intra_quantizer_matrix: intra-quantization table
+ * @non_intra_quantizer_matrix: non-intra quantization table
+ *
+ * The Mpeg2 Video Sequence Header structure.
+ */
+struct _GstMpegVideoSequenceHdr
+{
+ guint16 width, height;
+ guint8 aspect_ratio_info;
+ guint8 frame_rate_code;
+ guint32 bitrate_value;
+ guint16 vbv_buffer_size_value;
+
+ guint8 constrained_parameters_flag;
+
+ guint8 intra_quantizer_matrix[64];
+ guint8 non_intra_quantizer_matrix[64];
+
+ /* Calculated values */
+ guint par_w, par_h;
+ guint fps_n, fps_d;
+ guint bitrate;
+};
+
+/**
+ * GstMpegVideoSequenceExt:
+ * @profile: mpeg2 decoder profil
+ * @level: mpeg2 decoder level
+ * @progressive: %TRUE if the frames are progressive %FALSE otherwize
+ * @chroma_format: indicates the chrominance format
+ * @horiz_size_ext: Horizontal size
+ * @vert_size_ext: Vertical size
+ * @bitrate_ext: The bitrate
+ * @vbv_buffer_size_extension: Vbv vuffer size
+ * @low_delay: %TRUE if the sequence doesn't contain any B-pitcture, %FALSE
+ * otherwize
+ * @fps_n_ext: Framerate nominator code
+ * @fps_d_ext: Framerate denominator code
+ *
+ * The Mpeg2 Video Sequence Extension structure.
+ **/
+struct _GstMpegVideoSequenceExt
+{
+ /* mpeg2 decoder profile */
+ guint8 profile;
+ /* mpeg2 decoder level */
+ guint8 level;
+
+ guint8 progressive;
+ guint8 chroma_format;
+
+ guint8 horiz_size_ext, vert_size_ext;
+
+ guint16 bitrate_ext;
+ guint8 vbv_buffer_size_extension;
+ guint8 low_delay;
+ guint8 fps_n_ext, fps_d_ext;
+
+};
+
+/**
+ * GstMpegVideoQuantMatrixExt:
+ * @load_intra_quantiser_matrix
+ * @intra_quantiser_matrix
+ * @load_non_intra_quantiser_matrix
+ * @non_intra_quantiser_matrix:
+ * @load_chroma_intra_quantiser_matrix
+ * @chroma_intra_quantiser_matrix
+ * @load_chroma_non_intra_quantiser_matrix
+ * @chroma_non_intra_quantiser_matrix
+ *
+ * The Quant Matrix Extension structure
+ */
+struct _GstMpegVideoQuantMatrixExt
+{
+ guint8 load_intra_quantiser_matrix;
+ guint8 intra_quantiser_matrix[64];
+ guint8 load_non_intra_quantiser_matrix;
+ guint8 non_intra_quantiser_matrix[64];
+ guint8 load_chroma_intra_quantiser_matrix;
+ guint8 chroma_intra_quantiser_matrix[64];
+ guint8 load_chroma_non_intra_quantiser_matrix;
+ guint8 chroma_non_intra_quantiser_matrix[64];
+};
+
+/**
+ * GstMpegVideoPictureHdr:
+ * @tsn: Temporal Sequence Number
+ * @pic_type: Type of the frame
+ * @full_pel_forward_vector: the full pel forward flag of
+ * the frame: 0 or 1.
+ * @full_pel_backward_vector: the full pel backward flag
+ * of the frame: 0 or 1.
+ * @f_code: F code
+ *
+ * The Mpeg2 Video Picture Header structure.
+ */
+struct _GstMpegVideoPictureHdr
+{
+ guint16 tsn;
+ guint8 pic_type;
+
+ guint8 full_pel_forward_vector, full_pel_backward_vector;
+
+ guint8 f_code[2][2];
+};
+
+/**
+ * GstMpegVideoPictureExt:
+ * @intra_dc_precision: Intra DC precision
+ * @picture_structure: Structure of the picture
+ * @top_field_first: Top field first
+ * @frame_pred_frame_dct: Frame
+ * @concealment_motion_vectors: Concealment Motion Vectors
+ * @q_scale_type: Q Scale Type
+ * @intra_vlc_format: Intra Vlc Format
+ * @alternate_scan: Alternate Scan
+ * @repeat_first_field: Repeat First Field
+ * @chroma_420_type: Chroma 420 Type
+ * @progressive_frame: %TRUE if the frame is progressive %FALSE otherwize
+ *
+ * The Mpeg2 Video Picture Extension structure.
+ */
+struct _GstMpegVideoPictureExt
+{
+ guint8 f_code[2][2];
+
+ guint8 intra_dc_precision;
+ guint8 picture_structure;
+ guint8 top_field_first;
+ guint8 frame_pred_frame_dct;
+ guint8 concealment_motion_vectors;
+ guint8 q_scale_type;
+ guint8 intra_vlc_format;
+ guint8 alternate_scan;
+ guint8 repeat_first_field;
+ guint8 chroma_420_type;
+ guint8 progressive_frame;
+ guint8 composite_display;
+ guint8 v_axis;
+ guint8 field_sequence;
+ guint8 sub_carrier;
+ guint8 burst_amplitude;
+ guint8 sub_carrier_phase;
+};
+
+/**
+ * GstMpegVideoGop:
+ * @drop_frame_flag: Drop Frame Flag
+ * @hour: Hour (0-23)
+ * @minute: Minute (O-59)
+ * @second: Second (0-59)
+ * @frame: Frame (0-59)
+ * @closed_gop: Closed Gop
+ * @broken_gop: Broken Gop
+ *
+ * The Mpeg Video Group of Picture structure.
+ */
+struct _GstMpegVideoGop
+{
+ guint8 drop_frame_flag;
+
+ guint8 hour, minute, second, frame;
+
+ guint8 closed_gop;
+ guint8 broken_gop;
+};
+
+/**
+ * GstMpegVideoTypeOffsetSize:
+ * @type: the type of the packet that start at @offset
+ * @offset: the offset of the packet start in bytes, it is the exact, start of the packet, no sync code included
+ * @size: The size in bytes of the packet or -1 if the end wasn't found. It is the exact size of the packet, no sync code included
+ *
+ * A structure that contains the type of a packet, its offset and its size
+ */
+struct _GstMpegVideoTypeOffsetSize
+{
+ guint8 type;
+ guint offset;
+ gint size;
+};
+
+GList * gst_mpeg_video_parse (guint8 * data, gsize size, guint offset);
+
+gboolean gst_mpeg_video_parse_sequence_header (GstMpegVideoSequenceHdr * params,
+ guint8 * data, gsize size, guint offset);
+
+gboolean gst_mpeg_video_parse_picture_header (GstMpegVideoPictureHdr* hdr,
+ guint8 * data, gsize size, guint offset);
+
+gboolean gst_mpeg_video_parse_picture_extension (GstMpegVideoPictureExt *ext,
+ guint8 * data, gsize size, guint offset);
+
+gboolean gst_mpeg_video_parse_gop (GstMpegVideoGop * gop,
+ guint8 * data, gsize size, guint offset);
+
+gboolean gst_mpeg_video_parse_sequence_extension (GstMpegVideoSequenceExt * seqext,
+ guint8 * data, gsize size, guint offset);
+
+gboolean gst_mpeg_video_parse_quant_matrix_extension (GstMpegVideoQuantMatrixExt * quant,
+ guint8 * data, gsize size, guint offset);
+
+G_END_DECLS
+
+#endif
diff --git a/gst-libs/gst/play/.gitignore b/gst-libs/gst/play/.gitignore
deleted file mode 100644
index b7f5a7eb66..0000000000
--- a/gst-libs/gst/play/.gitignore
+++ /dev/null
@@ -1,3 +0,0 @@
-play-enumtypes.[ch]
-play-marshal.[ch]
-play-marshal.list
diff --git a/gst-libs/gst/play/play.h b/gst-libs/gst/play/play.h
deleted file mode 100644
index 6cbedce379..0000000000
--- a/gst-libs/gst/play/play.h
+++ /dev/null
@@ -1,104 +0,0 @@
-/* GStreamer
- * Copyright (C) 2003 Julien Moutte
- *
- * 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_PLAY_H__
-#define __GST_PLAY_H__
-
-#include
-#include
-#include
-
-G_BEGIN_DECLS
-
-/* GError stuff */
-
-#define GST_PLAY_ERROR gst_play_error_quark ()
-/* GObject stuff */
-
-#define GST_TYPE_PLAY (gst_play_get_type())
-#define GST_PLAY(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_PLAY, GstPlay))
-#define GST_PLAY_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_PLAY, GstPlayClass))
-#define GST_IS_PLAY(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_PLAY))
-#define GST_IS_PLAY_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_PLAY))
-#define GST_PLAY_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GTK_TYPE_PLAY, GstPlayClass))
-
-typedef enum
-{
- GST_PLAY_SINK_TYPE_AUDIO,
- GST_PLAY_SINK_TYPE_VIDEO,
- GST_PLAY_SINK_TYPE_ANY,
-} GstPlaySinkType;
-
-typedef struct _GstPlay GstPlay;
-typedef struct _GstPlayClass GstPlayClass;
-typedef struct _GstPlayPrivate GstPlayPrivate;
-
-struct _GstPlay
-{
- GstPipeline pipeline;
-
- GstPlayPrivate *priv;
-
- gpointer _gst_reserved[GST_PADDING];
-};
-
-struct _GstPlayClass
-{
- GstPipelineClass parent_class;
-
- void (*time_tick) (GstPlay *play, gint64 time_nanos);
- void (*stream_length) (GstPlay *play, gint64 length_nanos);
- void (*have_video_size) (GstPlay *play, gint width, gint height);
-
- gpointer _gst_reserved[GST_PADDING];
-};
-
-GType gst_play_get_type (void);
-GstPlay * gst_play_new (GError **error);
-
-gboolean gst_play_set_data_src (GstPlay *play,
- GstElement *data_src);
-gboolean gst_play_set_video_sink (GstPlay *play,
- GstElement *video_sink);
-gboolean gst_play_set_audio_sink (GstPlay *play,
- GstElement *audio_sink);
-
-gboolean gst_play_set_visualization (GstPlay *play,
- GstElement *element);
-gboolean gst_play_connect_visualization (GstPlay *play,
- gboolean connect);
-
-gboolean gst_play_set_location (GstPlay *play,
- const char *location);
-char * gst_play_get_location (GstPlay *play);
-
-gboolean gst_play_seek_to_time (GstPlay *play,
- gint64 time_nanos);
-
-GstElement * gst_play_get_sink_element (GstPlay *play,
- GstElement *element,
- GstPlaySinkType sink_type);
-GList * gst_play_get_all_by_interface (GstPlay *play,
- GType interface);
-
-gdouble gst_play_get_framerate (GstPlay *play);
-
-G_END_DECLS
-
-#endif /* __GST_PLAY_H__ */
diff --git a/gst-libs/gst/play/play.vcproj b/gst-libs/gst/play/play.vcproj
deleted file mode 100644
index d55cb3a579..0000000000
--- a/gst-libs/gst/play/play.vcproj
+++ /dev/null
@@ -1,144 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/gst-libs/gst/video/gstbasevideoencoder.c b/gst-libs/gst/video/gstbasevideoencoder.c
index e1c2c77a62..b04cf7710b 100644
--- a/gst-libs/gst/video/gstbasevideoencoder.c
+++ b/gst-libs/gst/video/gstbasevideoencoder.c
@@ -432,6 +432,7 @@ done:
GST_LOG_OBJECT (base_video_encoder, "Returning caps %" GST_PTR_FORMAT, fcaps);
+ g_object_unref (base_video_encoder);
return fcaps;
}
@@ -1024,6 +1025,10 @@ gst_base_video_encoder_set_latency_fields (GstBaseVideoEncoder *
{
gint64 latency;
+ /* 0 numerator is used for "don't know" */
+ if (GST_BASE_VIDEO_CODEC (base_video_encoder)->state.fps_n == 0)
+ return;
+
latency = gst_util_uint64_scale (n_fields,
GST_BASE_VIDEO_CODEC (base_video_encoder)->state.fps_d * GST_SECOND,
2 * GST_BASE_VIDEO_CODEC (base_video_encoder)->state.fps_n);
diff --git a/gst-plugins-bad.spec.in b/gst-plugins-bad.spec.in
index c1c81f198f..adbd33df61 100644
--- a/gst-plugins-bad.spec.in
+++ b/gst-plugins-bad.spec.in
@@ -204,6 +204,7 @@ make ERROR_CFLAGS='' ERROR_CXXFLAGS=''
%{_libdir}/libgstbasevideo-%{majorminor}.so.*
%{_libdir}/libgstphotography-%{majorminor}.so.*
%{_libdir}/libgstsignalprocessor-%{majorminor}.so.*
+%{_libdir}/libgstcodecparsers-%{majorminor}.so.*
# Plugins without external dependencies
%{_libdir}/gstreamer-%{majorminor}/libgstadpcmdec.so
%{_libdir}/gstreamer-%{majorminor}/libgstadpcmenc.so
@@ -329,8 +330,10 @@ make ERROR_CFLAGS='' ERROR_CXXFLAGS=''
%{_libdir}/libgstbasevideo-%{majorminor}.so
%{_libdir}/libgstphotography-%{majorminor}.so
%{_libdir}/libgstsignalprocessor-%{majorminor}.so
+%{_libdir}/libgstcodecparsers-%{majorminor}.so
%{_libdir}/libgstbasecamerabinsrc-%{majorminor}.so
%{_includedir}/gstreamer-%{majorminor}/gst/interfaces/photography*
+%{_includedir}/gstreamer-%{majorminor}/gst/codecparsers
%{_includedir}/gstreamer-%{majorminor}/gst/signalprocessor
%{_includedir}/gstreamer-%{majorminor}/gst/video
%{_includedir}/gstreamer-%{majorminor}/gst/basecamerabinsrc/gstbasecamerasrc.h
diff --git a/gst/camerabin2/gstcamerabin2.c b/gst/camerabin2/gstcamerabin2.c
index f40ef051be..1caa164048 100644
--- a/gst/camerabin2/gstcamerabin2.c
+++ b/gst/camerabin2/gstcamerabin2.c
@@ -273,6 +273,8 @@ gst_cam_flags_get_type (void)
{C_FLAGS (GST_CAM_FLAG_NO_VIEWFINDER_CONVERSION),
"Do not use viewfinder conversion " "elements",
"no-viewfinder-conversion"},
+ {C_FLAGS (GST_CAM_FLAG_NO_IMAGE_CONVERSION), "Do not use image conversion "
+ "elements", "no-image-conversion"},
{0, NULL, NULL}
};
static volatile GType id = 0;
@@ -1132,7 +1134,7 @@ gst_camera_bin_link_encodebin (GstCameraBin2 * camera, GstElement * encodebin,
return GST_PAD_LINK_REFUSED;
}
- ret = gst_pad_link (srcpad, sinkpad);
+ ret = gst_pad_link_full (srcpad, sinkpad, GST_PAD_LINK_CHECK_CAPS);
gst_object_unref (sinkpad);
gst_object_unref (srcpad);
@@ -1368,7 +1370,8 @@ gst_camera_bin_create_elements (GstCameraBin2 * camera)
}
g_object_set (camera->viewfinderbin_queue, "leaky", 2, "silent", TRUE,
- NULL);
+ "max-size-time", (guint64) 0, "max-size-bytes", (guint) 0,
+ "max-size-buffers", (guint) 1, NULL);
gst_bin_add_many (GST_BIN_CAST (camera),
gst_object_ref (camera->video_encodebin),
@@ -1422,8 +1425,14 @@ gst_camera_bin_create_elements (GstCameraBin2 * camera)
encbin_flags |= (1 << 1);
g_object_set (camera->video_encodebin, "flags", encbin_flags, NULL);
+ /* image encodebin has only video branch so disable its conversion elements
+ * appropriately */
+ if (camera->flags & GST_CAM_FLAG_NO_IMAGE_CONVERSION)
+ g_object_set (camera->image_encodebin, "flags", (1 << 1), NULL);
+
g_object_set (camera->viewfinderbin, "disable-converters",
- camera->flags & GST_CAM_FLAG_NO_VIEWFINDER_CONVERSION, NULL);
+ camera->flags & GST_CAM_FLAG_NO_VIEWFINDER_CONVERSION ? TRUE : FALSE,
+ NULL);
if (camera->video_profile_switch) {
GST_DEBUG_OBJECT (camera, "Switching encodebin's profile");
diff --git a/gst/camerabin2/gstcamerabin2.h b/gst/camerabin2/gstcamerabin2.h
index b2cf61f6ce..46113d0372 100644
--- a/gst/camerabin2/gstcamerabin2.h
+++ b/gst/camerabin2/gstcamerabin2.h
@@ -38,7 +38,10 @@ typedef enum
/* matches GstEncFlags GST_ENC_FLAG_NO_VIDEO_CONVERSION in encodebin */
GST_CAM_FLAG_NO_VIDEO_CONVERSION = (1 << 1),
/* maps to 'disable-converters' property in viewfinderbin */
- GST_CAM_FLAG_NO_VIEWFINDER_CONVERSION = (1 << 2)
+ GST_CAM_FLAG_NO_VIEWFINDER_CONVERSION = (1 << 2),
+ /* maps to GstEncFlags GST_ENC_FLAG_NO_VIDEO_CONVERSION in the image bin's
+ * encodebin */
+ GST_CAM_FLAG_NO_IMAGE_CONVERSION = (1 << 3)
} GstCamFlags;
diff --git a/gst/dtmf/gstdtmfcommon.h b/gst/dtmf/gstdtmfcommon.h
index aff881b987..82617d72fd 100644
--- a/gst/dtmf/gstdtmfcommon.h
+++ b/gst/dtmf/gstdtmfcommon.h
@@ -9,9 +9,9 @@
#define MAX_VOLUME 36
#define MIN_EVENT 0
-#define MAX_EVENT 16
+#define MAX_EVENT 15
#define MIN_EVENT_STRING "0"
-#define MAX_EVENT_STRING "16"
+#define MAX_EVENT_STRING "15"
#ifndef M_PI
#define M_PI 3.14159265358979323846 /* pi */
diff --git a/gst/dtmf/gstdtmfsrc.c b/gst/dtmf/gstdtmfsrc.c
index 79525b5729..7492b151e7 100644
--- a/gst/dtmf/gstdtmfsrc.c
+++ b/gst/dtmf/gstdtmfsrc.c
@@ -65,7 +65,7 @@
*
* number
* G_TYPE_INT
- * 0-16
+ * 0-15
* The event number.
*
*
@@ -323,6 +323,7 @@ gst_dtmf_src_handle_dtmf_event (GstDTMFSrc * dtmfsrc,
gint event_type;
gboolean start;
gint method;
+ GstClockTime last_stop;
if (!gst_structure_get_int (event_structure, "type", &event_type) ||
!gst_structure_get_boolean (event_structure, "start", &start) ||
@@ -335,6 +336,14 @@ gst_dtmf_src_handle_dtmf_event (GstDTMFSrc * dtmfsrc,
}
}
+
+ GST_OBJECT_LOCK (dtmfsrc);
+ if (gst_structure_get_clock_time (event_structure, "last-stop", &last_stop))
+ dtmfsrc->last_stop = last_stop;
+ else
+ dtmfsrc->last_stop = GST_CLOCK_TIME_NONE;
+ GST_OBJECT_UNLOCK (dtmfsrc);
+
if (start) {
gint event_number;
gint event_volume;
@@ -447,19 +456,37 @@ gst_dtmf_src_get_property (GObject * object, guint prop_id, GValue * value,
static void
gst_dtmf_prepare_timestamps (GstDTMFSrc * dtmfsrc)
{
- GstClock *clock;
+ GstClockTime last_stop;
+ GstClockTime timestamp;
- clock = gst_element_get_clock (GST_ELEMENT (dtmfsrc));
- if (clock != NULL) {
- dtmfsrc->timestamp = gst_clock_get_time (clock)
- - gst_element_get_base_time (GST_ELEMENT (dtmfsrc));
- gst_object_unref (clock);
+ GST_OBJECT_LOCK (dtmfsrc);
+ last_stop = dtmfsrc->last_stop;
+ GST_OBJECT_UNLOCK (dtmfsrc);
+
+ if (GST_CLOCK_TIME_IS_VALID (last_stop)) {
+ timestamp = last_stop;
} else {
- gchar *dtmf_name = gst_element_get_name (dtmfsrc);
- GST_ERROR_OBJECT (dtmfsrc, "No clock set for element %s", dtmf_name);
- dtmfsrc->timestamp = GST_CLOCK_TIME_NONE;
- g_free (dtmf_name);
+ GstClock *clock;
+
+ /* If there is no valid start time, lets use now as the start time */
+
+ clock = gst_element_get_clock (GST_ELEMENT (dtmfsrc));
+ if (clock != NULL) {
+ timestamp = gst_clock_get_time (clock)
+ - gst_element_get_base_time (GST_ELEMENT (dtmfsrc));
+ gst_object_unref (clock);
+ } else {
+ gchar *dtmf_name = gst_element_get_name (dtmfsrc);
+ GST_ERROR_OBJECT (dtmfsrc, "No clock set for element %s", dtmf_name);
+ dtmfsrc->timestamp = GST_CLOCK_TIME_NONE;
+ g_free (dtmf_name);
+ return;
+ }
}
+
+ /* Make sure the timestamp always goes forward */
+ if (timestamp > dtmfsrc->timestamp)
+ dtmfsrc->timestamp = timestamp;
}
static void
@@ -584,6 +611,12 @@ gst_dtmf_src_create_next_tone_packet (GstDTMFSrc * dtmfsrc,
/* timestamp and duration of GstBuffer */
GST_BUFFER_DURATION (buf) = dtmfsrc->interval * GST_MSECOND;
GST_BUFFER_TIMESTAMP (buf) = dtmfsrc->timestamp;
+
+ GST_LOG_OBJECT (dtmfsrc, "Creating new buffer with event %u duration "
+ " gst: %" GST_TIME_FORMAT " at %" GST_TIME_FORMAT,
+ event->event_number, GST_TIME_ARGS (GST_BUFFER_DURATION (buf)),
+ GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)));
+
dtmfsrc->timestamp += GST_BUFFER_DURATION (buf);
/* Set caps on the buffer before pushing it */
@@ -823,6 +856,7 @@ gst_dtmf_src_change_state (GstElement * element, GstStateChange transition)
g_slice_free (GstDTMFSrcEvent, event);
event = g_async_queue_try_pop (dtmfsrc->event_queue);
}
+ dtmfsrc->timestamp = 0;
no_preroll = TRUE;
break;
default:
diff --git a/gst/dtmf/gstdtmfsrc.h b/gst/dtmf/gstdtmfsrc.h
index aa5d35a611..cda5840a5f 100644
--- a/gst/dtmf/gstdtmfsrc.h
+++ b/gst/dtmf/gstdtmfsrc.h
@@ -81,6 +81,8 @@ struct _GstDTMFSrc
gboolean paused;
GstClockID clockid;
+ GstClockTime last_stop;
+
gint sample_rate;
};
diff --git a/gst/dtmf/gstrtpdtmfsrc.c b/gst/dtmf/gstrtpdtmfsrc.c
index c7e1c1fb2a..8f07cafc4a 100644
--- a/gst/dtmf/gstrtpdtmfsrc.c
+++ b/gst/dtmf/gstrtpdtmfsrc.c
@@ -63,7 +63,7 @@
*
* number
* G_TYPE_INT
- * 0-16
+ * 0-15
* The event number.
*
*
@@ -122,9 +122,7 @@
#include "gstrtpdtmfsrc.h"
#define GST_RTP_DTMF_TYPE_EVENT 1
-#define DEFAULT_PACKET_INTERVAL 50 /* ms */
-#define MIN_PACKET_INTERVAL 10 /* ms */
-#define MAX_PACKET_INTERVAL 50 /* ms */
+#define DEFAULT_PTIME 40 /* ms */
#define DEFAULT_SSRC -1
#define DEFAULT_PT 96
#define DEFAULT_TIMESTAMP_OFFSET -1
@@ -155,7 +153,6 @@ enum
PROP_CLOCK_RATE,
PROP_TIMESTAMP,
PROP_SEQNUM,
- PROP_INTERVAL,
PROP_REDUNDANCY
};
@@ -264,11 +261,6 @@ gst_rtp_dtmf_src_class_init (GstRTPDTMFSrcClass * klass)
g_param_spec_uint ("pt", "payload type",
"The payload type of the packets",
0, 0x80, DEFAULT_PT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
- g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_INTERVAL,
- g_param_spec_uint ("interval", "Interval between rtp packets",
- "Interval in ms between two rtp packets", MIN_PACKET_INTERVAL,
- MAX_PACKET_INTERVAL, DEFAULT_PACKET_INTERVAL,
- G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_REDUNDANCY,
g_param_spec_uint ("packet-redundancy", "Packet Redundancy",
"Number of packets to send to indicate start and stop dtmf events",
@@ -309,7 +301,7 @@ gst_rtp_dtmf_src_init (GstRTPDTMFSrc * object, GstRTPDTMFSrcClass * g_class)
object->ts_offset = DEFAULT_TIMESTAMP_OFFSET;
object->pt = DEFAULT_PT;
object->clock_rate = DEFAULT_CLOCK_RATE;
- object->interval = DEFAULT_PACKET_INTERVAL;
+ object->ptime = DEFAULT_PTIME;
object->packet_redundancy = DEFAULT_PACKET_REDUNDANCY;
object->event_queue =
@@ -342,6 +334,7 @@ gst_rtp_dtmf_src_handle_dtmf_event (GstRTPDTMFSrc * dtmfsrc,
gint event_type;
gboolean start;
gint method;
+ GstClockTime last_stop;
if (!gst_structure_get_int (event_structure, "type", &event_type) ||
!gst_structure_get_boolean (event_structure, "start", &start) ||
@@ -354,6 +347,13 @@ gst_rtp_dtmf_src_handle_dtmf_event (GstRTPDTMFSrc * dtmfsrc,
}
}
+ GST_OBJECT_LOCK (dtmfsrc);
+ if (gst_structure_get_clock_time (event_structure, "last-stop", &last_stop))
+ dtmfsrc->last_stop = last_stop;
+ else
+ dtmfsrc->last_stop = GST_CLOCK_TIME_NONE;
+ GST_OBJECT_UNLOCK (dtmfsrc);
+
if (start) {
gint event_number;
gint event_volume;
@@ -448,9 +448,6 @@ gst_rtp_dtmf_src_set_property (GObject * object, guint prop_id,
dtmfsrc->pt = g_value_get_uint (value);
dtmfsrc->dirty = TRUE;
break;
- case PROP_INTERVAL:
- dtmfsrc->interval = g_value_get_uint (value);
- break;
case PROP_REDUNDANCY:
dtmfsrc->packet_redundancy = g_value_get_uint (value);
break;
@@ -490,9 +487,6 @@ gst_rtp_dtmf_src_get_property (GObject * object, guint prop_id, GValue * value,
case PROP_SEQNUM:
g_value_set_uint (value, dtmfsrc->seqnum);
break;
- case PROP_INTERVAL:
- g_value_set_uint (value, dtmfsrc->interval);
- break;
case PROP_REDUNDANCY:
g_value_set_uint (value, dtmfsrc->packet_redundancy);
break;
@@ -502,29 +496,40 @@ gst_rtp_dtmf_src_get_property (GObject * object, guint prop_id, GValue * value,
}
}
-static void
+static gboolean
gst_rtp_dtmf_prepare_timestamps (GstRTPDTMFSrc * dtmfsrc)
{
- GstClock *clock;
+ GstClockTime last_stop;
- clock = gst_element_get_clock (GST_ELEMENT (dtmfsrc));
- if (clock != NULL) {
- dtmfsrc->timestamp = gst_clock_get_time (clock)
- + (MIN_INTER_DIGIT_INTERVAL * GST_MSECOND)
- - gst_element_get_base_time (GST_ELEMENT (dtmfsrc));
- dtmfsrc->start_timestamp = dtmfsrc->timestamp;
- gst_object_unref (clock);
+ GST_OBJECT_LOCK (dtmfsrc);
+ last_stop = dtmfsrc->last_stop;
+ GST_OBJECT_UNLOCK (dtmfsrc);
+
+ if (GST_CLOCK_TIME_IS_VALID (last_stop)) {
+ dtmfsrc->start_timestamp = last_stop;
} else {
- gchar *dtmf_name = gst_element_get_name (dtmfsrc);
- GST_ERROR_OBJECT (dtmfsrc, "No clock set for element %s", dtmf_name);
- dtmfsrc->timestamp = GST_CLOCK_TIME_NONE;
- g_free (dtmf_name);
+ GstClock *clock = gst_element_get_clock (GST_ELEMENT (dtmfsrc));
+
+ if (clock == NULL)
+ return FALSE;
+
+ dtmfsrc->start_timestamp = gst_clock_get_time (clock)
+ - gst_element_get_base_time (GST_ELEMENT (dtmfsrc));
+ gst_object_unref (clock);
}
+ /* If the last stop was in the past, then lets add the buffers together */
+ if (dtmfsrc->start_timestamp < dtmfsrc->timestamp)
+ dtmfsrc->start_timestamp = dtmfsrc->timestamp;
+
+ dtmfsrc->timestamp = dtmfsrc->start_timestamp;
+
dtmfsrc->rtp_timestamp = dtmfsrc->ts_base +
gst_util_uint64_scale_int (gst_segment_to_running_time (&GST_BASE_SRC
(dtmfsrc)->segment, GST_FORMAT_TIME, dtmfsrc->timestamp),
dtmfsrc->clock_rate, GST_SECOND);
+
+ return TRUE;
}
@@ -539,7 +544,7 @@ gst_rtp_dtmf_src_add_start_event (GstRTPDTMFSrc * dtmfsrc, gint event_number,
event->payload = g_slice_new0 (GstRTPDTMFPayload);
event->payload->event = CLAMP (event_number, MIN_EVENT, MAX_EVENT);
event->payload->volume = CLAMP (event_volume, MIN_VOLUME, MAX_VOLUME);
- event->payload->duration = dtmfsrc->interval * dtmfsrc->clock_rate / 1000;
+ event->payload->duration = dtmfsrc->ptime * dtmfsrc->clock_rate / 1000;
g_async_queue_push (dtmfsrc->event_queue, event);
}
@@ -586,30 +591,40 @@ gst_rtp_dtmf_prepare_buffer_data (GstRTPDTMFSrc * dtmfsrc, GstBuffer * buf)
if (dtmfsrc->redundancy_count > 1)
GST_BUFFER_DURATION (buf) = 0;
else
- GST_BUFFER_DURATION (buf) = dtmfsrc->interval * GST_MSECOND;
+ GST_BUFFER_DURATION (buf) = dtmfsrc->ptime * GST_MSECOND;
GST_BUFFER_TIMESTAMP (buf) = dtmfsrc->timestamp;
- dtmfsrc->timestamp += GST_BUFFER_DURATION (buf);
payload = (GstRTPDTMFPayload *) gst_rtp_buffer_get_payload (buf);
/* copy payload and convert to network-byte order */
g_memmove (payload, dtmfsrc->payload, sizeof (GstRTPDTMFPayload));
- /* Force the packet duration to a certain minumum
- * if its the end of the event
- */
- if (payload->e &&
- payload->duration < MIN_PULSE_DURATION * dtmfsrc->clock_rate / 1000)
- payload->duration = MIN_PULSE_DURATION * dtmfsrc->clock_rate / 1000;
payload->duration = g_htons (payload->duration);
+ if (dtmfsrc->redundancy_count <= 1 && dtmfsrc->last_packet) {
+ GstClockTime inter_digit_interval = MIN_INTER_DIGIT_INTERVAL;
+
+ if (inter_digit_interval % dtmfsrc->ptime != 0)
+ inter_digit_interval += dtmfsrc->ptime -
+ (MIN_INTER_DIGIT_INTERVAL % dtmfsrc->ptime);
+
+ GST_BUFFER_DURATION (buf) += inter_digit_interval * GST_MSECOND;
+ }
+
+ GST_LOG_OBJECT (dtmfsrc, "Creating new buffer with event %u duration "
+ " gst: %" GST_TIME_FORMAT " at %" GST_TIME_FORMAT "(rtp ts:%u dur:%u)",
+ dtmfsrc->payload->event, GST_TIME_ARGS (GST_BUFFER_DURATION (buf)),
+ GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)), dtmfsrc->rtp_timestamp,
+ dtmfsrc->payload->duration);
/* duration of DTMF payloadfor the NEXT packet */
/* not updated for redundant packets */
- if (dtmfsrc->redundancy_count == 0)
- dtmfsrc->payload->duration +=
- dtmfsrc->interval * dtmfsrc->clock_rate / 1000;
+ if (dtmfsrc->redundancy_count <= 1)
+ dtmfsrc->payload->duration += dtmfsrc->ptime * dtmfsrc->clock_rate / 1000;
+
+ if (GST_CLOCK_TIME_IS_VALID (dtmfsrc->timestamp))
+ dtmfsrc->timestamp += GST_BUFFER_DURATION (buf);
}
@@ -660,7 +675,8 @@ gst_rtp_dtmf_src_create (GstBaseSrc * basesrc, guint64 offset,
dtmfsrc->last_packet = FALSE;
/* Set the redundancy on the first packet */
dtmfsrc->redundancy_count = dtmfsrc->packet_redundancy;
- gst_rtp_dtmf_prepare_timestamps (dtmfsrc);
+ if (!gst_rtp_dtmf_prepare_timestamps (dtmfsrc))
+ goto no_clock;
dtmfsrc->payload = event->payload;
event->payload = NULL;
@@ -727,6 +743,8 @@ gst_rtp_dtmf_src_create (GstBaseSrc * basesrc, guint64 offset,
GST_DEBUG_OBJECT (dtmfsrc, "Processed events, now lets wait on the clock");
clock = gst_element_get_clock (GST_ELEMENT (basesrc));
+ if (!clock)
+ goto no_clock;
clockid = gst_clock_new_single_shot_id (clock, dtmfsrc->timestamp +
gst_element_get_base_time (GST_ELEMENT (dtmfsrc)));
gst_object_unref (clock);
@@ -793,6 +811,12 @@ paused:
} else {
return GST_FLOW_WRONG_STATE;
}
+
+no_clock:
+ GST_ELEMENT_ERROR (dtmfsrc, STREAM, MUX, ("No available clock"),
+ ("No available clock"));
+ gst_pad_pause_task (GST_BASE_SRC_PAD (dtmfsrc));
+ return GST_FLOW_ERROR;
}
@@ -913,6 +937,23 @@ gst_rtp_dtmf_src_negotiate (GstBaseSrc * basesrc)
GST_LOG_OBJECT (dtmfsrc, "using internal seqnum-base %u",
dtmfsrc->seqnum_base);
}
+
+ if (gst_structure_has_field_typed (s, "ptime", G_TYPE_UINT)) {
+ value = gst_structure_get_value (s, "ptime");
+ dtmfsrc->ptime = g_value_get_uint (value);
+ GST_LOG_OBJECT (dtmfsrc, "using peer ptime %u", dtmfsrc->ptime);
+ } else if (gst_structure_has_field_typed (s, "maxptime", G_TYPE_UINT)) {
+ value = gst_structure_get_value (s, "maxptime");
+ dtmfsrc->ptime = g_value_get_uint (value);
+ GST_LOG_OBJECT (dtmfsrc, "using peer maxptime as ptime %u",
+ dtmfsrc->ptime);
+ } else {
+ /* FIXME, fixate_nearest_uint would be even better */
+ gst_structure_set (s, "ptime", G_TYPE_UINT, dtmfsrc->ptime, NULL);
+ GST_LOG_OBJECT (dtmfsrc, "using internal ptime %u", dtmfsrc->ptime);
+ }
+
+
GST_DEBUG_OBJECT (dtmfsrc, "with peer caps: %" GST_PTR_FORMAT, srccaps);
}
@@ -945,6 +986,7 @@ gst_rtp_dtmf_src_ready_to_paused (GstRTPDTMFSrc * dtmfsrc)
else
dtmfsrc->ts_base = dtmfsrc->ts_offset;
+ dtmfsrc->timestamp = 0;
}
static GstStateChangeReturn
diff --git a/gst/dtmf/gstrtpdtmfsrc.h b/gst/dtmf/gstrtpdtmfsrc.h
index d04c6ecb7c..9be9df69cb 100644
--- a/gst/dtmf/gstrtpdtmfsrc.h
+++ b/gst/dtmf/gstrtpdtmfsrc.h
@@ -90,10 +90,12 @@ struct _GstRTPDTMFSrc
guint pt;
guint ssrc;
guint current_ssrc;
- guint16 interval;
+ guint16 ptime;
guint16 packet_redundancy;
guint32 clock_rate;
+ GstClockTime last_stop;
+
gboolean dirty;
guint16 redundancy_count;
};
diff --git a/gst/hls/gsthlsdemux.c b/gst/hls/gsthlsdemux.c
index 1e984b9dc9..143f36387d 100644
--- a/gst/hls/gsthlsdemux.c
+++ b/gst/hls/gsthlsdemux.c
@@ -100,16 +100,15 @@ static gboolean gst_hls_demux_fetcher_sink_event (GstPad * pad,
GstEvent * event);
static void gst_hls_demux_loop (GstHLSDemux * demux);
static void gst_hls_demux_stop (GstHLSDemux * demux);
-static void gst_hls_demux_stop_fetcher (GstHLSDemux * demux,
+static void gst_hls_demux_stop_fetcher_locked (GstHLSDemux * demux,
gboolean cancelled);
+static void gst_hls_demux_stop_update (GstHLSDemux * demux);
static gboolean gst_hls_demux_start_update (GstHLSDemux * demux);
static gboolean gst_hls_demux_cache_fragments (GstHLSDemux * demux);
static gboolean gst_hls_demux_schedule (GstHLSDemux * demux);
static gboolean gst_hls_demux_switch_playlist (GstHLSDemux * demux);
-static gboolean gst_hls_demux_get_next_fragment (GstHLSDemux * demux,
- gboolean retry);
-static gboolean gst_hls_demux_update_playlist (GstHLSDemux * demux,
- gboolean retry);
+static gboolean gst_hls_demux_get_next_fragment (GstHLSDemux * demux);
+static gboolean gst_hls_demux_update_playlist (GstHLSDemux * demux);
static void gst_hls_demux_reset (GstHLSDemux * demux, gboolean dispose);
static gboolean gst_hls_demux_set_location (GstHLSDemux * demux,
const gchar * uri);
@@ -155,10 +154,7 @@ gst_hls_demux_dispose (GObject * obj)
g_cond_free (demux->thread_cond);
g_mutex_free (demux->thread_lock);
- if (GST_TASK_STATE (demux->task) != GST_TASK_STOPPED) {
- gst_task_stop (demux->task);
- gst_task_join (demux->task);
- }
+ gst_task_join (demux->task);
gst_object_unref (demux->task);
g_static_rec_mutex_free (&demux->task_lock);
@@ -290,9 +286,17 @@ gst_hls_demux_change_state (GstElement * element, GstStateChange transition)
GstHLSDemux *demux = GST_HLS_DEMUX (element);
switch (transition) {
- case GST_STATE_CHANGE_NULL_TO_READY:
+ case GST_STATE_CHANGE_READY_TO_PAUSED:
gst_hls_demux_reset (demux, FALSE);
break;
+ case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
+ /* Start the streaming loop in paused only if we already received
+ the main playlist. It might have been stopped if we were in PAUSED
+ state and we filled our queue with enough cached fragments
+ */
+ if (gst_m3u8_client_get_uri (demux->client)[0] != '\0')
+ gst_hls_demux_start_update (demux);
+ break;
default:
break;
}
@@ -300,9 +304,13 @@ gst_hls_demux_change_state (GstElement * element, GstStateChange transition)
ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
switch (transition) {
+ case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
+ gst_hls_demux_stop_update (demux);
+ break;
case GST_STATE_CHANGE_PAUSED_TO_READY:
demux->cancelled = TRUE;
- g_cond_signal (demux->fetcher_cond);
+ gst_hls_demux_stop (demux);
+ gst_hls_demux_reset (demux, FALSE);
break;
default:
break;
@@ -348,6 +356,7 @@ gst_hls_demux_src_event (GstPad * pad, GstEvent * event)
" stop: %" GST_TIME_FORMAT, rate, GST_TIME_ARGS (start),
GST_TIME_ARGS (stop));
+ GST_M3U8_CLIENT_LOCK (demux->client);
file = GST_M3U8_MEDIA_FILE (demux->client->current->files->data);
current_sequence = file->sequence;
current_pos = 0;
@@ -363,6 +372,7 @@ gst_hls_demux_src_event (GstPad * pad, GstEvent * event)
}
current_pos += file->duration;
}
+ GST_M3U8_CLIENT_UNLOCK (demux->client);
if (walk == NULL) {
GST_WARNING_OBJECT (demux, "Could not find seeked fragment");
@@ -374,9 +384,13 @@ gst_hls_demux_src_event (GstPad * pad, GstEvent * event)
gst_pad_push_event (demux->srcpad, gst_event_new_flush_start ());
}
- gst_hls_demux_stop_fetcher (demux, TRUE);
+ demux->cancelled = TRUE;
+ gst_task_pause (demux->task);
+ g_mutex_lock (demux->fetcher_lock);
+ gst_hls_demux_stop_fetcher_locked (demux, TRUE);
+ g_mutex_unlock (demux->fetcher_lock);
+ gst_hls_demux_stop_update (demux);
gst_task_pause (demux->task);
- g_cond_signal (demux->thread_cond);
/* wait for streaming to finish */
g_static_rec_mutex_lock (&demux->task_lock);
@@ -386,17 +400,23 @@ gst_hls_demux_src_event (GstPad * pad, GstEvent * event)
GstBuffer *buf = g_queue_pop_head (demux->queue);
gst_buffer_unref (buf);
}
+ g_queue_clear (demux->queue);
+ gst_adapter_clear (demux->download);
+ GST_M3U8_CLIENT_LOCK (demux->client);
GST_DEBUG_OBJECT (demux, "seeking to sequence %d", current_sequence);
demux->client->sequence = current_sequence;
demux->position = start;
demux->need_segment = TRUE;
+ GST_M3U8_CLIENT_UNLOCK (demux->client);
+
if (flags & GST_SEEK_FLAG_FLUSH) {
GST_DEBUG_OBJECT (demux, "sending flush stop");
gst_pad_push_event (demux->srcpad, gst_event_new_flush_stop ());
}
+ demux->cancelled = FALSE;
gst_task_start (demux->task);
g_static_rec_mutex_unlock (&demux->task_lock);
@@ -507,7 +527,7 @@ gst_hls_demux_src_query (GstPad * pad, GstQuery * query)
if (hlsdemux->client) {
/* FIXME: Do we answer with the variant playlist, with the current
* playlist or the the uri of the least downlowaded fragment? */
- gst_query_set_uri (query, hlsdemux->client->current->uri);
+ gst_query_set_uri (query, gst_m3u8_client_get_uri (hlsdemux->client));
ret = TRUE;
}
break;
@@ -552,8 +572,11 @@ gst_hls_demux_fetcher_sink_event (GstPad * pad, GstEvent * event)
case GST_EVENT_EOS:{
GST_DEBUG_OBJECT (demux, "Got EOS on the fetcher pad");
/* signal we have fetched the URI */
- if (!demux->cancelled)
- g_cond_signal (demux->fetcher_cond);
+ if (!demux->cancelled) {
+ g_mutex_lock (demux->fetcher_lock);
+ g_cond_broadcast (demux->fetcher_cond);
+ g_mutex_unlock (demux->fetcher_lock);
+ }
}
default:
break;
@@ -593,8 +616,6 @@ gst_hls_demux_fetcher_chain (GstPad * pad, GstBuffer * buf)
goto done;
}
- GST_LOG_OBJECT (demux, "The uri fetcher received a new buffer of size %u",
- GST_BUFFER_SIZE (buf));
gst_adapter_push (demux->download, buf);
done:
@@ -604,7 +625,7 @@ done:
}
static void
-gst_hls_demux_stop_fetcher (GstHLSDemux * demux, gboolean cancelled)
+gst_hls_demux_stop_fetcher_locked (GstHLSDemux * demux, gboolean cancelled)
{
GstPad *pad;
@@ -630,20 +651,22 @@ gst_hls_demux_stop_fetcher (GstHLSDemux * demux, gboolean cancelled)
demux->fetcher = NULL;
/* if we stopped it to cancell a download, free the cached buffer */
- if (cancelled && !gst_adapter_available (demux->download)) {
+ if (cancelled && gst_adapter_available (demux->download)) {
gst_adapter_clear (demux->download);
- /* signal the fetcher thread that the download has finished/cancelled */
- g_cond_signal (demux->fetcher_cond);
}
+ /* signal the fetcher thread that the download has finished/cancelled */
+ if (cancelled)
+ g_cond_broadcast (demux->fetcher_cond);
}
static void
gst_hls_demux_stop (GstHLSDemux * demux)
{
- gst_hls_demux_stop_fetcher (demux, TRUE);
- if (GST_TASK_STATE (demux->task) != GST_TASK_STOPPED)
- gst_task_stop (demux->task);
- g_cond_signal (demux->thread_cond);
+ 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_hls_demux_stop_update (demux);
}
static void
@@ -653,6 +676,18 @@ switch_pads (GstHLSDemux * demux, GstCaps * newcaps)
GST_DEBUG ("Switching pads (oldpad:%p)", oldpad);
+ /* FIXME: This is a workaround for a bug in playsink.
+ * If we're switching from an audio-only or video-only fragment
+ * to an audio-video segment, the new sink doesn't know about
+ * the current running time and audio/video will go out of sync.
+ *
+ * This should be fixed in playsink by distributing the
+ * current running time to newly created sinks and is
+ * fixed in 0.11 with the new segments.
+ */
+ if (demux->srcpad)
+ gst_pad_push_event (demux->srcpad, gst_event_new_flush_stop ());
+
/* First create and activate new pad */
demux->srcpad = gst_pad_new_from_static_template (&srctemplate, NULL);
gst_pad_set_event_function (demux->srcpad,
@@ -690,8 +725,9 @@ gst_hls_demux_loop (GstHLSDemux * demux)
if (!gst_hls_demux_cache_fragments (demux))
goto cache_error;
- /* we can start now the updates thread */
- gst_hls_demux_start_update (demux);
+ /* we can start now the updates thread (only if on playing) */
+ if (GST_STATE (demux) == GST_STATE_PLAYING)
+ gst_hls_demux_start_update (demux);
GST_INFO_OBJECT (demux, "First fragments cached successfully");
}
@@ -699,7 +735,7 @@ gst_hls_demux_loop (GstHLSDemux * demux)
if (demux->end_of_playlist)
goto end_of_playlist;
- goto empty_queue;
+ goto pause_task;
}
buf = g_queue_pop_head (demux->queue);
@@ -740,9 +776,12 @@ end_of_playlist:
cache_error:
{
- GST_ELEMENT_ERROR (demux, RESOURCE, NOT_FOUND,
- ("Could not cache the first fragments"), (NULL));
- gst_hls_demux_stop (demux);
+ gst_task_pause (demux->task);
+ if (!demux->cancelled) {
+ GST_ELEMENT_ERROR (demux, RESOURCE, NOT_FOUND,
+ ("Could not cache the first fragments"), (NULL));
+ gst_hls_demux_stop (demux);
+ }
return;
}
@@ -754,7 +793,7 @@ error:
return;
}
-empty_queue:
+pause_task:
{
gst_task_pause (demux->task);
return;
@@ -769,7 +808,11 @@ gst_hls_demux_fetcher_bus_handler (GstBus * bus,
if (GST_MESSAGE_TYPE (message) == GST_MESSAGE_ERROR) {
demux->fetcher_error = TRUE;
- g_cond_signal (demux->fetcher_cond);
+ if (!demux->cancelled) {
+ g_mutex_lock (demux->fetcher_lock);
+ g_cond_broadcast (demux->fetcher_cond);
+ g_mutex_unlock (demux->fetcher_lock);
+ }
}
gst_message_unref (message);
@@ -777,7 +820,7 @@ gst_hls_demux_fetcher_bus_handler (GstBus * bus,
}
static gboolean
-gst_hls_demux_make_fetcher (GstHLSDemux * demux, const gchar * uri)
+gst_hls_demux_make_fetcher_locked (GstHLSDemux * demux, const gchar * uri)
{
GstPad *pad;
@@ -824,8 +867,10 @@ gst_hls_demux_reset (GstHLSDemux * demux, gboolean dispose)
gst_adapter_clear (demux->download);
- if (demux->client)
+ if (demux->client) {
gst_m3u8_client_free (demux->client);
+ demux->client = NULL;
+ }
if (!dispose) {
demux->client = gst_m3u8_client_new ("");
@@ -861,6 +906,7 @@ gst_hls_demux_update_thread (GstHLSDemux * demux)
* switch to a different bitrate */
g_mutex_lock (demux->thread_lock);
+ GST_DEBUG_OBJECT (demux, "Started updates thread");
while (TRUE) {
/* block until the next scheduled update or the signal to quit this thread */
if (g_cond_timed_wait (demux->thread_cond, demux->thread_lock,
@@ -870,9 +916,17 @@ gst_hls_demux_update_thread (GstHLSDemux * demux)
/* update the playlist for live sources */
if (gst_m3u8_client_is_live (demux->client)) {
- if (!gst_hls_demux_update_playlist (demux, TRUE)) {
- GST_ERROR_OBJECT (demux, "Could not update the playlist");
- goto quit;
+ if (!gst_hls_demux_update_playlist (demux)) {
+ demux->client->update_failed_count++;
+ if (demux->client->update_failed_count < DEFAULT_FAILED_COUNT) {
+ GST_WARNING_OBJECT (demux, "Could not update the playlist");
+ gst_hls_demux_schedule (demux);
+ continue;
+ } else {
+ GST_ELEMENT_ERROR (demux, RESOURCE, NOT_FOUND,
+ ("Could not update the playlist"), (NULL));
+ goto quit;
+ }
}
}
@@ -891,31 +945,62 @@ gst_hls_demux_update_thread (GstHLSDemux * demux)
}
/* fetch the next fragment */
- if (!gst_hls_demux_get_next_fragment (demux, TRUE)) {
- if (!demux->end_of_playlist && !demux->cancelled)
- GST_ERROR_OBJECT (demux, "Could not fetch the next fragment");
- goto quit;
- }
+ if (g_queue_is_empty (demux->queue)) {
+ if (!gst_hls_demux_get_next_fragment (demux)) {
+ if (!demux->end_of_playlist && !demux->cancelled) {
+ demux->client->update_failed_count++;
+ if (demux->client->update_failed_count < DEFAULT_FAILED_COUNT) {
+ GST_WARNING_OBJECT (demux, "Could not fetch the next fragment");
+ continue;
+ } else {
+ GST_ELEMENT_ERROR (demux, RESOURCE, NOT_FOUND,
+ ("Could not fetch the next fragment"), (NULL));
+ goto quit;
+ }
+ }
+ } else {
+ demux->client->update_failed_count = 0;
+ }
- /* try to switch to another bitrate if needed */
- gst_hls_demux_switch_playlist (demux);
+ /* try to switch to another bitrate if needed */
+ gst_hls_demux_switch_playlist (demux);
+ }
}
quit:
{
+ GST_DEBUG_OBJECT (demux, "Stopped updates thread");
+ demux->updates_thread = NULL;
g_mutex_unlock (demux->thread_lock);
return TRUE;
}
}
+
+static void
+gst_hls_demux_stop_update (GstHLSDemux * demux)
+{
+ GST_DEBUG_OBJECT (demux, "Stopping updates thread");
+ while (demux->updates_thread) {
+ g_mutex_lock (demux->thread_lock);
+ g_cond_signal (demux->thread_cond);
+ g_mutex_unlock (demux->thread_lock);
+ }
+}
+
static gboolean
gst_hls_demux_start_update (GstHLSDemux * demux)
{
GError *error;
/* creates a new thread for the updates */
- demux->updates_thread = g_thread_create (
- (GThreadFunc) gst_hls_demux_update_thread, demux, TRUE, &error);
+ g_mutex_lock (demux->thread_lock);
+ if (demux->updates_thread == NULL) {
+ GST_DEBUG_OBJECT (demux, "Starting updates thread");
+ demux->updates_thread = g_thread_create (
+ (GThreadFunc) gst_hls_demux_update_thread, demux, FALSE, &error);
+ }
+ g_mutex_unlock (demux->thread_lock);
return (error != NULL);
}
@@ -924,23 +1009,16 @@ gst_hls_demux_cache_fragments (GstHLSDemux * demux)
{
gint i;
- /* Start parsing the main playlist */
- gst_m3u8_client_set_current (demux->client, demux->client->main);
-
- if (gst_m3u8_client_is_live (demux->client)) {
- if (!gst_hls_demux_update_playlist (demux, FALSE)) {
- GST_ERROR_OBJECT (demux, "Could not fetch the main playlist %s",
- demux->client->main->uri);
- return FALSE;
- }
- }
-
/* If this playlist is a variant playlist, select the first one
* and update it */
if (gst_m3u8_client_has_variant_playlist (demux->client)) {
- GstM3U8 *child = demux->client->main->current_variant->data;
+ GstM3U8 *child = NULL;
+
+ GST_M3U8_CLIENT_LOCK (demux->client);
+ child = demux->client->main->current_variant->data;
+ GST_M3U8_CLIENT_UNLOCK (demux->client);
gst_m3u8_client_set_current (demux->client, child);
- if (!gst_hls_demux_update_playlist (demux, FALSE)) {
+ if (!gst_hls_demux_update_playlist (demux)) {
GST_ERROR_OBJECT (demux, "Could not fetch the child playlist %s",
child->uri);
return FALSE;
@@ -950,11 +1028,22 @@ gst_hls_demux_cache_fragments (GstHLSDemux * demux)
/* If it's a live source, set the sequence number to the end of the list
* and substract the 'fragmets_cache' to start from the last fragment*/
if (gst_m3u8_client_is_live (demux->client)) {
+ GST_M3U8_CLIENT_LOCK (demux->client);
demux->client->sequence += g_list_length (demux->client->current->files);
if (demux->client->sequence >= demux->fragments_cache)
demux->client->sequence -= demux->fragments_cache;
else
demux->client->sequence = 0;
+ GST_M3U8_CLIENT_UNLOCK (demux->client);
+ } else {
+ GstClockTime duration = gst_m3u8_client_get_duration (demux->client);
+
+ GST_DEBUG_OBJECT (demux, "Sending duration message : %" GST_TIME_FORMAT,
+ GST_TIME_ARGS (duration));
+ if (duration != GST_CLOCK_TIME_NONE)
+ gst_element_post_message (GST_ELEMENT (demux),
+ gst_message_new_duration (GST_OBJECT (demux),
+ GST_FORMAT_TIME, duration));
}
/* Cache the first fragments */
@@ -964,8 +1053,9 @@ gst_hls_demux_cache_fragments (GstHLSDemux * demux)
100 * i / demux->fragments_cache));
g_get_current_time (&demux->next_update);
g_time_val_add (&demux->next_update,
- demux->client->current->targetduration * 1000000);
- if (!gst_hls_demux_get_next_fragment (demux, FALSE)) {
+ gst_m3u8_client_get_target_duration (demux->client)
+ / GST_SECOND * G_USEC_PER_SEC);
+ if (!gst_hls_demux_get_next_fragment (demux)) {
if (!demux->cancelled)
GST_ERROR_OBJECT (demux, "Error caching the first fragments");
return FALSE;
@@ -992,7 +1082,13 @@ gst_hls_demux_fetch_location (GstHLSDemux * demux, const gchar * uri)
g_mutex_lock (demux->fetcher_lock);
- if (!gst_hls_demux_make_fetcher (demux, uri)) {
+ while (demux->fetcher)
+ g_cond_wait (demux->fetcher_cond, demux->fetcher_lock);
+
+ if (demux->cancelled)
+ goto quit;
+
+ if (!gst_hls_demux_make_fetcher_locked (demux, uri)) {
goto uri_error;
}
@@ -1004,9 +1100,9 @@ gst_hls_demux_fetch_location (GstHLSDemux * demux, const gchar * uri)
GST_DEBUG_OBJECT (demux, "Waiting to fetch the URI");
g_cond_wait (demux->fetcher_cond, demux->fetcher_lock);
- gst_hls_demux_stop_fetcher (demux, FALSE);
+ gst_hls_demux_stop_fetcher_locked (demux, FALSE);
- if (gst_adapter_available (demux->download)) {
+ if (!demux->fetcher_error && gst_adapter_available (demux->download)) {
GST_INFO_OBJECT (demux, "URI fetched successfully");
bret = TRUE;
}
@@ -1031,6 +1127,8 @@ state_change_error:
quit:
{
+ /* Unlock any other fetcher that might be waiting */
+ g_cond_broadcast (demux->fetcher_cond);
g_mutex_unlock (demux->fetcher_lock);
return bret;
}
@@ -1051,15 +1149,15 @@ gst_hls_src_buf_to_utf8_playlist (gchar * data, guint size)
}
static gboolean
-gst_hls_demux_update_playlist (GstHLSDemux * demux, gboolean retry)
+gst_hls_demux_update_playlist (GstHLSDemux * demux)
{
const guint8 *data;
gchar *playlist;
guint avail;
+ const gchar *uri = gst_m3u8_client_get_current_uri (demux->client);
- GST_INFO_OBJECT (demux, "Updating the playlist %s",
- demux->client->current->uri);
- if (!gst_hls_demux_fetch_location (demux, demux->client->current->uri))
+ GST_INFO_OBJECT (demux, "Updating the playlist %s", uri);
+ if (!gst_hls_demux_fetch_location (demux, uri))
return FALSE;
avail = gst_adapter_available (demux->download);
@@ -1079,26 +1177,36 @@ gst_hls_demux_change_playlist (GstHLSDemux * demux, gboolean is_fast)
{
GList *list;
GstStructure *s;
+ gint new_bandwidth;
+ GST_M3U8_CLIENT_LOCK (demux->client);
if (is_fast)
list = g_list_next (demux->client->main->current_variant);
else
list = g_list_previous (demux->client->main->current_variant);
/* Don't do anything else if the playlist is the same */
- if (!list || list->data == demux->client->current)
+ if (!list || list->data == demux->client->current) {
+ GST_M3U8_CLIENT_UNLOCK (demux->client);
return TRUE;
+ }
demux->client->main->current_variant = list;
+ GST_M3U8_CLIENT_UNLOCK (demux->client);
gst_m3u8_client_set_current (demux->client, list->data);
- gst_hls_demux_update_playlist (demux, TRUE);
+
+ GST_M3U8_CLIENT_LOCK (demux->client);
+ new_bandwidth = demux->client->current->bandwidth;
+ GST_M3U8_CLIENT_UNLOCK (demux->client);
+
+ gst_hls_demux_update_playlist (demux);
GST_INFO_OBJECT (demux, "Client is %s, switching to bitrate %d",
- is_fast ? "fast" : "slow", demux->client->current->bandwidth);
+ is_fast ? "fast" : "slow", new_bandwidth);
s = gst_structure_new ("playlist",
- "uri", G_TYPE_STRING, demux->client->current->uri,
- "bitrate", G_TYPE_INT, demux->client->current->bandwidth, NULL);
+ "uri", G_TYPE_STRING, gst_m3u8_client_get_current_uri (demux->client),
+ "bitrate", G_TYPE_INT, new_bandwidth, NULL);
gst_element_post_message (GST_ELEMENT_CAST (demux),
gst_message_new_element (GST_OBJECT_CAST (demux), s));
@@ -1129,7 +1237,8 @@ gst_hls_demux_schedule (GstHLSDemux * demux)
/* schedule the next update using the target duration field of the
* playlist */
g_time_val_add (&demux->next_update,
- demux->client->current->targetduration * update_factor * 1000000);
+ gst_m3u8_client_get_target_duration (demux->client)
+ / GST_SECOND * G_USEC_PER_SEC * update_factor);
GST_DEBUG_OBJECT (demux, "Next update scheduled at %s",
g_time_val_to_iso8601 (&demux->next_update));
@@ -1143,28 +1252,38 @@ gst_hls_demux_switch_playlist (GstHLSDemux * demux)
gint64 diff, limit;
g_get_current_time (&now);
- if (!demux->client->main->lists)
+ GST_M3U8_CLIENT_LOCK (demux->client);
+ if (!demux->client->main->lists) {
+ GST_M3U8_CLIENT_UNLOCK (demux->client);
return TRUE;
+ }
+ GST_M3U8_CLIENT_UNLOCK (demux->client);
/* compare the time when the fragment was downloaded with the time when it was
* scheduled */
diff = (GST_TIMEVAL_TO_TIME (demux->next_update) - GST_TIMEVAL_TO_TIME (now));
- limit = demux->client->current->targetduration * GST_SECOND *
- demux->bitrate_switch_tol;
+ limit = gst_m3u8_client_get_target_duration (demux->client)
+ * demux->bitrate_switch_tol;
GST_DEBUG ("diff:%s%" GST_TIME_FORMAT ", limit:%" GST_TIME_FORMAT,
diff < 0 ? "-" : " ", GST_TIME_ARGS (ABS (diff)), GST_TIME_ARGS (limit));
/* if we are on time switch to a higher bitrate */
if (diff > limit) {
- gst_hls_demux_change_playlist (demux, TRUE);
+ while (diff > limit) {
+ gst_hls_demux_change_playlist (demux, TRUE);
+ diff -= limit;
+ }
+ demux->accumulated_delay = 0;
} else if (diff < 0) {
/* if the client is too slow wait until it has accumulated a certain delay to
* switch to a lower bitrate */
demux->accumulated_delay -= diff;
if (demux->accumulated_delay >= limit) {
- gst_hls_demux_change_playlist (demux, FALSE);
- } else if (demux->accumulated_delay < 0) {
+ while (demux->accumulated_delay >= limit) {
+ gst_hls_demux_change_playlist (demux, FALSE);
+ demux->accumulated_delay -= limit;
+ }
demux->accumulated_delay = 0;
}
}
@@ -1172,7 +1291,7 @@ gst_hls_demux_switch_playlist (GstHLSDemux * demux)
}
static gboolean
-gst_hls_demux_get_next_fragment (GstHLSDemux * demux, gboolean retry)
+gst_hls_demux_get_next_fragment (GstHLSDemux * demux)
{
GstBuffer *buf;
guint avail;
@@ -1191,8 +1310,15 @@ gst_hls_demux_get_next_fragment (GstHLSDemux * demux, gboolean retry)
GST_INFO_OBJECT (demux, "Fetching next fragment %s", next_fragment_uri);
- if (!gst_hls_demux_fetch_location (demux, next_fragment_uri))
+ if (!gst_hls_demux_fetch_location (demux, next_fragment_uri)) {
+ /* FIXME: The gst_m3u8_get_next_fragment increments the sequence number
+ but another thread might call get_next_fragment and this decrement
+ will not redownload the failed fragment, but might duplicate the
+ download of a succeeded fragment
+ */
+ g_atomic_int_add (&demux->client->sequence, -1);
return FALSE;
+ }
avail = gst_adapter_available (demux->download);
buf = gst_adapter_take_buffer (demux->download, avail);
diff --git a/gst/hls/m3u8.c b/gst/hls/m3u8.c
index 26548101f3..c407d72d83 100644
--- a/gst/hls/m3u8.c
+++ b/gst/hls/m3u8.c
@@ -225,11 +225,13 @@ gst_m3u8_update (GstM3U8 * self, gchar * data, gboolean * updated)
title = NULL;
data += 7;
while (TRUE) {
- end = g_utf8_strchr (data, -1, '\n'); /* FIXME: support \r\n */
+ end = g_utf8_strchr (data, -1, '\n');
if (end)
*end = '\0';
if (data[0] != '#') {
+ gchar *r;
+
if (duration < 0 && list == NULL) {
GST_LOG ("%s: got line without EXTINF or EXTSTREAMINF, dropping", data);
goto next_line;
@@ -250,8 +252,13 @@ gst_m3u8_update (GstM3U8 * self, gchar * data, gboolean * updated)
*slash = '\0';
data = g_strdup_printf ("%s/%s", self->uri, data);
*slash = '/';
- } else
+ } else {
data = g_strdup (data);
+ }
+
+ r = g_utf8_strchr (data, -1, '\r');
+ if (r)
+ *r = '\0';
if (list != NULL) {
if (g_list_find_custom (self->lists, data,
@@ -382,6 +389,7 @@ gst_m3u8_client_new (const gchar * uri)
client->current = NULL;
client->sequence = -1;
client->update_failed_count = 0;
+ client->lock = g_mutex_new ();
gst_m3u8_set_uri (client->main, g_strdup (uri));
return client;
@@ -393,6 +401,7 @@ gst_m3u8_client_free (GstM3U8Client * self)
g_return_if_fail (self != NULL);
gst_m3u8_free (self->main);
+ g_mutex_free (self->lock);
g_free (self);
}
@@ -401,10 +410,12 @@ gst_m3u8_client_set_current (GstM3U8Client * self, GstM3U8 * m3u8)
{
g_return_if_fail (self != NULL);
+ GST_M3U8_CLIENT_LOCK (self);
if (m3u8 != self->current) {
self->current = m3u8;
self->update_failed_count = 0;
}
+ GST_M3U8_CLIENT_UNLOCK (self);
}
gboolean
@@ -412,17 +423,19 @@ gst_m3u8_client_update (GstM3U8Client * self, gchar * data)
{
GstM3U8 *m3u8;
gboolean updated = FALSE;
+ gboolean ret = FALSE;
g_return_val_if_fail (self != NULL, FALSE);
+ GST_M3U8_CLIENT_LOCK (self);
m3u8 = self->current ? self->current : self->main;
if (!gst_m3u8_update (m3u8, data, &updated))
- return FALSE;
+ goto out;
if (!updated) {
self->update_failed_count++;
- return FALSE;
+ goto out;
}
/* select the first playlist, for now */
@@ -440,7 +453,10 @@ gst_m3u8_client_update (GstM3U8Client * self, gchar * data)
GST_DEBUG ("Setting first sequence at %d", self->sequence);
}
- return TRUE;
+ ret = TRUE;
+out:
+ GST_M3U8_CLIENT_UNLOCK (self);
+ return ret;
}
static gboolean
@@ -465,11 +481,14 @@ gst_m3u8_client_get_next_fragment (GstM3U8Client * client,
g_return_val_if_fail (client->current != NULL, FALSE);
g_return_val_if_fail (discontinuity != NULL, FALSE);
+ GST_M3U8_CLIENT_LOCK (client);
GST_DEBUG ("Looking for fragment %d", client->sequence);
l = g_list_find_custom (client->current->files, client,
(GCompareFunc) _find_next);
- if (l == NULL)
+ if (l == NULL) {
+ GST_M3U8_CLIENT_UNLOCK (client);
return FALSE;
+ }
file = GST_M3U8_MEDIA_FILE (l->data);
@@ -487,6 +506,7 @@ gst_m3u8_client_get_next_fragment (GstM3U8Client * client,
}
*timestamp *= GST_SECOND;
+ GST_M3U8_CLIENT_UNLOCK (client);
return TRUE;
}
@@ -503,37 +523,82 @@ gst_m3u8_client_get_duration (GstM3U8Client * client)
g_return_val_if_fail (client != NULL, GST_CLOCK_TIME_NONE);
+ GST_M3U8_CLIENT_LOCK (client);
/* We can only get the duration for on-demand streams */
- if (!client->current->endlist)
+ if (!client->current->endlist) {
+ GST_M3U8_CLIENT_UNLOCK (client);
return GST_CLOCK_TIME_NONE;
+ }
g_list_foreach (client->current->files, (GFunc) _sum_duration, &duration);
+ GST_M3U8_CLIENT_UNLOCK (client);
+ return duration * GST_SECOND;
+}
+
+GstClockTime
+gst_m3u8_client_get_target_duration (GstM3U8Client * client)
+{
+ GstClockTime duration = 0;
+
+ g_return_val_if_fail (client != NULL, GST_CLOCK_TIME_NONE);
+
+ GST_M3U8_CLIENT_LOCK (client);
+ duration = client->current->targetduration;
+ GST_M3U8_CLIENT_UNLOCK (client);
return duration * GST_SECOND;
}
const gchar *
gst_m3u8_client_get_uri (GstM3U8Client * client)
{
+ const gchar *uri;
+
g_return_val_if_fail (client != NULL, NULL);
- return client->main->uri;
+ GST_M3U8_CLIENT_LOCK (client);
+ uri = client->main->uri;
+ GST_M3U8_CLIENT_UNLOCK (client);
+ return uri;
+}
+
+const gchar *
+gst_m3u8_client_get_current_uri (GstM3U8Client * client)
+{
+ const gchar *uri;
+
+ g_return_val_if_fail (client != NULL, NULL);
+
+ GST_M3U8_CLIENT_LOCK (client);
+ uri = client->current->uri;
+ GST_M3U8_CLIENT_UNLOCK (client);
+ return uri;
}
gboolean
gst_m3u8_client_has_variant_playlist (GstM3U8Client * client)
{
+ gboolean ret;
+
g_return_val_if_fail (client != NULL, FALSE);
- return client->main->lists != NULL;
+ GST_M3U8_CLIENT_LOCK (client);
+ ret = (client->main->lists != NULL);
+ GST_M3U8_CLIENT_UNLOCK (client);
+ return ret;
}
gboolean
gst_m3u8_client_is_live (GstM3U8Client * client)
{
+ gboolean ret;
+
g_return_val_if_fail (client != NULL, FALSE);
+ GST_M3U8_CLIENT_LOCK (client);
if (!client->current || client->current->endlist)
- return FALSE;
-
- return TRUE;
+ ret = FALSE;
+ else
+ ret = TRUE;
+ GST_M3U8_CLIENT_UNLOCK (client);
+ return ret;
}
diff --git a/gst/hls/m3u8.h b/gst/hls/m3u8.h
index aefe8667d1..8c83990f87 100644
--- a/gst/hls/m3u8.h
+++ b/gst/hls/m3u8.h
@@ -32,6 +32,9 @@ typedef struct _GstM3U8Client GstM3U8Client;
#define GST_M3U8(m) ((GstM3U8*)m)
#define GST_M3U8_MEDIA_FILE(f) ((GstM3U8MediaFile*)f)
+#define GST_M3U8_CLIENT_LOCK(c) g_mutex_lock (c->lock);
+#define GST_M3U8_CLIENT_UNLOCK(c) g_mutex_unlock (c->lock);
+
struct _GstM3U8
{
gchar *uri;
@@ -70,6 +73,7 @@ struct _GstM3U8Client
GstM3U8 *current;
guint update_failed_count;
gint sequence; /* the next sequence for this client */
+ GMutex *lock;
};
@@ -81,7 +85,9 @@ gboolean gst_m3u8_client_get_next_fragment (GstM3U8Client * client,
gboolean * discontinuity, const gchar ** uri, GstClockTime * duration,
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);
+const gchar *gst_m3u8_client_get_current_uri(GstM3U8Client * client);
gboolean gst_m3u8_client_has_variant_playlist(GstM3U8Client * client);
gboolean gst_m3u8_client_is_live(GstM3U8Client * client);
diff --git a/gst/mpegtsdemux/mpegtsbase.c b/gst/mpegtsdemux/mpegtsbase.c
index 1749ba2ccc..5542abf029 100644
--- a/gst/mpegtsdemux/mpegtsbase.c
+++ b/gst/mpegtsdemux/mpegtsbase.c
@@ -1154,6 +1154,18 @@ gst_mpegts_base_handle_eos (MpegTSBase * base)
return TRUE;
}
+static inline void
+mpegts_base_flush (MpegTSBase * base)
+{
+ MpegTSBaseClass *klass = GST_MPEGTS_BASE_GET_CLASS (base);
+
+ /* Call implementation */
+ if (G_UNLIKELY (klass->flush == NULL))
+ GST_WARNING_OBJECT (base, "Class doesn't have a 'flush' implementation !");
+ else
+ klass->flush (base);
+}
+
static gboolean
mpegts_base_sink_event (GstPad * pad, GstEvent * event)
{
@@ -1191,6 +1203,7 @@ mpegts_base_sink_event (GstPad * pad, GstEvent * event)
break;
case GST_EVENT_FLUSH_START:
mpegts_packetizer_flush (base->packetizer);
+ mpegts_base_flush (base);
res = GST_MPEGTS_BASE_GET_CLASS (base)->push_event (base, event);
gst_event_unref (event);
break;
@@ -1442,7 +1455,7 @@ mpegts_base_handle_seek_event (MpegTSBase * base, GstPad * pad,
if (base->mode == BASE_MODE_PUSHING) {
GST_ERROR ("seeking in push mode not supported");
- goto done;
+ goto push_mode;
}
/* stop streaming, either by flushing or by pausing the task */
@@ -1493,7 +1506,7 @@ mpegts_base_handle_seek_event (MpegTSBase * base, GstPad * pad,
//else
done:
gst_pad_start_task (base->sinkpad, (GstTaskFunction) mpegts_base_loop, base);
-
+push_mode:
GST_PAD_STREAM_UNLOCK (base->sinkpad);
return ret == GST_FLOW_OK;
}
diff --git a/gst/mpegtsdemux/mpegtsbase.h b/gst/mpegtsdemux/mpegtsbase.h
index 1513898ec5..cce4e0fd72 100644
--- a/gst/mpegtsdemux/mpegtsbase.h
+++ b/gst/mpegtsdemux/mpegtsbase.h
@@ -162,6 +162,9 @@ struct _MpegTSBaseClass {
/* seek is called to wait for seeking */
GstFlowReturn (*seek) (MpegTSBase * base, GstEvent * event, guint16 pid);
+ /* flush all streams */
+ void (*flush) (MpegTSBase * base);
+
/* signals */
void (*pat_info) (GstStructure *pat);
void (*pmt_info) (GstStructure *pmt);
diff --git a/gst/mpegtsdemux/tsdemux.c b/gst/mpegtsdemux/tsdemux.c
index f7dc5cc6b1..3a327a5cd9 100644
--- a/gst/mpegtsdemux/tsdemux.c
+++ b/gst/mpegtsdemux/tsdemux.c
@@ -188,6 +188,7 @@ static void gst_ts_demux_reset (MpegTSBase * base);
static GstFlowReturn
gst_ts_demux_push (MpegTSBase * base, MpegTSPacketizerPacket * packet,
MpegTSPacketizerSection * section);
+static void gst_ts_demux_flush (MpegTSBase * base);
static void
gst_ts_demux_stream_added (MpegTSBase * base, MpegTSBaseStream * stream,
MpegTSBaseProgram * program);
@@ -282,6 +283,7 @@ gst_ts_demux_class_init (GstTSDemuxClass * klass)
ts_class->stream_removed = gst_ts_demux_stream_removed;
ts_class->find_timestamps = GST_DEBUG_FUNCPTR (find_timestamps);
ts_class->seek = GST_DEBUG_FUNCPTR (gst_ts_demux_do_seek);
+ ts_class->flush = GST_DEBUG_FUNCPTR (gst_ts_demux_flush);
}
static void
@@ -882,9 +884,7 @@ gst_ts_demux_srcpad_event (GstPad * pad, GstEvent * event)
switch (GST_EVENT_TYPE (event)) {
case GST_EVENT_SEEK:
res = mpegts_base_handle_seek_event ((MpegTSBase *) demux, pad, event);
- if (res)
- demux->need_newsegment = TRUE;
- else
+ if (!res)
GST_WARNING ("seeking failed");
gst_event_unref (event);
break;
@@ -2278,6 +2278,15 @@ gst_ts_demux_handle_packet (GstTSDemux * demux, TSDemuxStream * stream,
return res;
}
+static void
+gst_ts_demux_flush (MpegTSBase * base)
+{
+ GstTSDemux *demux = GST_TS_DEMUX_CAST (base);
+
+ demux->need_newsegment = TRUE;
+ gst_ts_demux_flush_streams (demux);
+}
+
static GstFlowReturn
gst_ts_demux_push (MpegTSBase * base, MpegTSPacketizerPacket * packet,
MpegTSPacketizerSection * section)
diff --git a/gst/rtpmux/gstrtpdtmfmux.c b/gst/rtpmux/gstrtpdtmfmux.c
index f62c6263db..97ffacd2f0 100644
--- a/gst/rtpmux/gstrtpdtmfmux.c
+++ b/gst/rtpmux/gstrtpdtmfmux.c
@@ -64,6 +64,8 @@ static GstStateChangeReturn gst_rtp_dtmf_mux_change_state (GstElement * element,
static gboolean gst_rtp_dtmf_mux_accept_buffer_locked (GstRTPMux * rtp_mux,
GstRTPMuxPadPrivate * padpriv, GstBuffer * buffer);
+static gboolean gst_rtp_dtmf_mux_src_event (GstRTPMux * rtp_mux,
+ GstEvent * event);
GST_BOILERPLATE (GstRTPDTMFMux, gst_rtp_dtmf_mux, GstRTPMux, GST_TYPE_RTP_MUX);
@@ -100,6 +102,7 @@ gst_rtp_dtmf_mux_class_init (GstRTPDTMFMuxClass * klass)
gstelement_class->change_state =
GST_DEBUG_FUNCPTR (gst_rtp_dtmf_mux_change_state);
gstrtpmux_class->accept_buffer_locked = gst_rtp_dtmf_mux_accept_buffer_locked;
+ gstrtpmux_class->src_event = gst_rtp_dtmf_mux_src_event;
}
static gboolean
@@ -173,6 +176,28 @@ gst_rtp_dtmf_mux_request_new_pad (GstElement * element, GstPadTemplate * templ,
return pad;
}
+static gboolean
+gst_rtp_dtmf_mux_src_event (GstRTPMux * rtp_mux, GstEvent * event)
+{
+ if (GST_EVENT_TYPE (event) == GST_EVENT_CUSTOM_UPSTREAM) {
+ const GstStructure *s = gst_event_get_structure (event);
+
+ if (s && gst_structure_has_name (s, "dtmf-event")) {
+ GST_OBJECT_LOCK (rtp_mux);
+ if (GST_CLOCK_TIME_IS_VALID (rtp_mux->last_stop)) {
+ event = (GstEvent *)
+ gst_mini_object_make_writable (GST_MINI_OBJECT_CAST (event));
+ s = gst_event_get_structure (event);
+ gst_structure_set ((GstStructure *) s,
+ "last-stop", G_TYPE_UINT64, rtp_mux->last_stop, NULL);
+ }
+ GST_OBJECT_UNLOCK (rtp_mux);
+ }
+ }
+
+ return GST_RTP_MUX_CLASS (parent_class)->src_event (rtp_mux, event);
+}
+
static GstStateChangeReturn
gst_rtp_dtmf_mux_change_state (GstElement * element, GstStateChange transition)
diff --git a/gst/rtpmux/gstrtpmux.c b/gst/rtpmux/gstrtpmux.c
index 57929ec608..f86fd5d6bc 100644
--- a/gst/rtpmux/gstrtpmux.c
+++ b/gst/rtpmux/gstrtpmux.c
@@ -107,6 +107,9 @@ static void gst_rtp_mux_get_property (GObject * object, guint prop_id,
GValue * value, GParamSpec * pspec);
static void gst_rtp_mux_dispose (GObject * object);
+static gboolean gst_rtp_mux_src_event_real (GstRTPMux *rtp_mux,
+ GstEvent * event);
+
GST_BOILERPLATE (GstRTPMux, gst_rtp_mux, GstElement, GST_TYPE_ELEMENT);
static void
@@ -137,6 +140,8 @@ gst_rtp_mux_class_init (GstRTPMuxClass * klass)
gobject_class->set_property = gst_rtp_mux_set_property;
gobject_class->dispose = gst_rtp_mux_dispose;
+ klass->src_event = gst_rtp_mux_src_event_real;
+
g_object_class_install_property (G_OBJECT_CLASS (klass),
PROP_TIMESTAMP_OFFSET, g_param_spec_int ("timestamp-offset",
"Timestamp Offset",
@@ -183,16 +188,30 @@ restart:
static gboolean
gst_rtp_mux_src_event (GstPad * pad, GstEvent * event)
{
- GstElement *rtp_mux;
+ GstRTPMux *rtp_mux;
+ GstRTPMuxClass *klass;
+ gboolean ret = FALSE;
+
+ rtp_mux = (GstRTPMux *) gst_pad_get_parent_element (pad);
+ g_return_val_if_fail (rtp_mux != NULL, FALSE);
+ klass = GST_RTP_MUX_GET_CLASS (rtp_mux);
+
+ ret = klass->src_event (rtp_mux, event);
+
+ gst_object_unref (rtp_mux);
+
+ return ret;
+}
+
+static gboolean
+gst_rtp_mux_src_event_real (GstRTPMux *rtp_mux, GstEvent * event)
+{
GstIterator *iter;
GstPad *sinkpad;
gboolean result = FALSE;
gboolean done = FALSE;
- rtp_mux = gst_pad_get_parent_element (pad);
- g_return_val_if_fail (rtp_mux != NULL, FALSE);
-
- iter = gst_element_iterate_sink_pads (rtp_mux);
+ iter = gst_element_iterate_sink_pads (GST_ELEMENT (rtp_mux));
while (!done) {
switch (gst_iterator_next (iter, (gpointer) & sinkpad)) {
@@ -213,7 +232,6 @@ gst_rtp_mux_src_event (GstPad * pad, GstEvent * event)
}
}
gst_iterator_free (iter);
- gst_object_unref (rtp_mux);
gst_event_unref (event);
return result;
@@ -236,6 +254,7 @@ gst_rtp_mux_init (GstRTPMux * object, GstRTPMuxClass * g_class)
object->seqnum_offset = DEFAULT_SEQNUM_OFFSET;
object->segment_pending = TRUE;
+ object->last_stop = GST_CLOCK_TIME_NONE;
}
static void
@@ -394,6 +413,20 @@ gst_rtp_mux_chain_list (GstPad * pad, GstBufferList * bufferlist)
break;
gst_buffer_list_iterator_take (it, rtpbuf);
+
+ do {
+ if (GST_BUFFER_DURATION_IS_VALID (rtpbuf) &&
+ GST_BUFFER_TIMESTAMP_IS_VALID (rtpbuf))
+ rtp_mux->last_stop = GST_BUFFER_TIMESTAMP (rtpbuf) +
+ GST_BUFFER_DURATION (rtpbuf);
+ else
+ rtp_mux->last_stop = GST_CLOCK_TIME_NONE;
+
+ gst_buffer_list_iterator_take (it, rtpbuf);
+
+ } while ((rtpbuf = gst_buffer_list_iterator_next (it)) != NULL);
+
+
}
gst_buffer_list_iterator_free (it);
@@ -456,15 +489,25 @@ gst_rtp_mux_chain (GstPad * pad, GstBuffer * buffer)
drop = !process_buffer_locked (rtp_mux, padpriv, buffer);
- if (!drop && rtp_mux->segment_pending) {
- /*
- * We set the start at 0, because we re-timestamps to the running time
- */
- newseg_event = gst_event_new_new_segment_full (FALSE, 1.0, 1.0,
- GST_FORMAT_TIME, 0, -1, 0);
+ if (!drop) {
+ if (rtp_mux->segment_pending) {
+ /*
+ * We set the start at 0, because we re-timestamps to the running time
+ */
+ newseg_event = gst_event_new_new_segment_full (FALSE, 1.0, 1.0,
+ GST_FORMAT_TIME, 0, -1, 0);
- rtp_mux->segment_pending = FALSE;
+ rtp_mux->segment_pending = FALSE;
+ }
+
+ if (GST_BUFFER_DURATION_IS_VALID (buffer) &&
+ GST_BUFFER_TIMESTAMP_IS_VALID (buffer))
+ rtp_mux->last_stop = GST_BUFFER_TIMESTAMP (buffer) +
+ GST_BUFFER_DURATION (buffer);
+ else
+ rtp_mux->last_stop = GST_CLOCK_TIME_NONE;
}
+
GST_OBJECT_UNLOCK (rtp_mux);
if (newseg_event)
@@ -709,6 +752,7 @@ gst_rtp_mux_sink_event (GstPad * pad, GstEvent * event)
GstRTPMuxPadPrivate *padpriv;
GST_OBJECT_LOCK (mux);
+ mux->last_stop = GST_CLOCK_TIME_NONE;
mux->segment_pending = TRUE;
padpriv = gst_pad_get_element_private (pad);
if (padpriv)
@@ -801,6 +845,8 @@ gst_rtp_mux_ready_to_paused (GstRTPMux * rtp_mux)
else
rtp_mux->ts_base = rtp_mux->ts_offset;
+ rtp_mux->last_stop = GST_CLOCK_TIME_NONE;
+
GST_DEBUG_OBJECT (rtp_mux, "set clock-base to %u", rtp_mux->ts_base);
GST_OBJECT_UNLOCK (rtp_mux);
diff --git a/gst/rtpmux/gstrtpmux.h b/gst/rtpmux/gstrtpmux.h
index 96513836d5..7bfea60c0b 100644
--- a/gst/rtpmux/gstrtpmux.h
+++ b/gst/rtpmux/gstrtpmux.h
@@ -31,7 +31,7 @@
G_BEGIN_DECLS
#define GST_TYPE_RTP_MUX (gst_rtp_mux_get_type())
#define GST_RTP_MUX(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_RTP_MUX, GstRTPMux))
-#define GST_RTP_MUX_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_RTP_MUX, GstRTPMux))
+#define GST_RTP_MUX_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_RTP_MUX, GstRTPMuxClass))
#define GST_RTP_MUX_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_RTP_MUX, GstRTPMuxClass))
#define GST_IS_RTP_MUX(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_RTP_MUX))
#define GST_IS_RTP_MUX_CLASS(obj) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_RTP_MUX))
@@ -74,6 +74,8 @@ struct _GstRTPMux
guint current_ssrc;
gboolean segment_pending;
+
+ GstClockTime last_stop;
};
struct _GstRTPMuxClass
@@ -82,6 +84,8 @@ struct _GstRTPMuxClass
gboolean (*accept_buffer_locked) (GstRTPMux *rtp_mux,
GstRTPMuxPadPrivate * padpriv, GstBuffer * buffer);
+
+ gboolean (*src_event) (GstRTPMux *rtp_mux, GstEvent *event);
};
diff --git a/gst/videoparsers/Makefile.am b/gst/videoparsers/Makefile.am
index 6cebef5330..811d5f860a 100644
--- a/gst/videoparsers/Makefile.am
+++ b/gst/videoparsers/Makefile.am
@@ -2,20 +2,21 @@ plugin_LTLIBRARIES = libgstvideoparsersbad.la
libgstvideoparsersbad_la_SOURCES = plugin.c \
h263parse.c gsth263parse.c \
- gsth264parse.c h264parse.c \
gstdiracparse.c dirac_parse.c \
- gstmpegvideoparse.c mpegvideoparse.c
+ gsth264parse.c gstmpegvideoparse.c
+
libgstvideoparsersbad_la_CFLAGS = \
+ $(GST_PLUGINS_BAD_CFLAGS) $(GST_PLUGINS_BASE_CFLAGS) \
$(GST_BASE_CFLAGS) $(GST_CFLAGS)
-libgstvideoparsersbad_la_LIBADD = \
+libgstvideoparsersbad_la_LIBADD = $(GST_PLUGINS_BASE_LIBS) \
+ $(top_builddir)/gst-libs/gst/codecparsers/libgstcodecparsers-$(GST_MAJORMINOR).la \
$(GST_BASE_LIBS) $(GST_LIBS)
libgstvideoparsersbad_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
libgstvideoparsersbad_la_LIBTOOLFLAGS = --tag=disable-static
noinst_HEADERS = gsth263parse.h h263parse.h \
- gsth264parse.h h264parse.h \
gstdiracparse.h dirac_parse.h \
- gstmpegvideoparse.h mpegvideoparse.h
+ gsth264parse.h gstmpegvideoparse.h
Android.mk: Makefile.am $(BUILT_SOURCES)
androgenizer \
diff --git a/gst/videoparsers/gsth264parse.c b/gst/videoparsers/gsth264parse.c
index 089b5a7878..3821f0031f 100644
--- a/gst/videoparsers/gsth264parse.c
+++ b/gst/videoparsers/gsth264parse.c
@@ -1,7 +1,10 @@
/* GStreamer H.264 Parser
- * Copyright (C) <2010> Mark Nauwelaerts
- * Copyright (C) <2010> Collabora Multimedia
+ * Copyright (C) <2010> Collabora ltd
* Copyright (C) <2010> Nokia Corporation
+ * Copyright (C) <2011> Intel Corporation
+ *
+ * Copyright (C) <2010> Mark Nauwelaerts
+ * Copyright (C) <2011> Thibault Saunier
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
@@ -99,7 +102,7 @@ gst_h264_parse_base_init (gpointer g_class)
gst_static_pad_template_get (&sinktemplate));
gst_element_class_set_details_simple (gstelement_class, "H.264 parser",
- "Codec/Parser/Video",
+ "Codec/Parser/Converter/Video",
"Parses H.264 streams",
"Mark Nauwelaerts ");
@@ -163,9 +166,14 @@ gst_h264_parse_finalize (GObject * object)
static void
gst_h264_parse_reset_frame (GstH264Parse * h264parse)
{
+ GST_DEBUG_OBJECT (h264parse, "reset frame");
+
/* done parsing; reset state */
- h264parse->last_nal_pos = 0;
- h264parse->next_sc_pos = 0;
+ h264parse->nalu.valid = FALSE;
+ h264parse->nalu.offset = 0;
+ h264parse->nalu.size = 0;
+ h264parse->current_off = 0;
+
h264parse->picture_start = FALSE;
h264parse->update_caps = FALSE;
h264parse->idr_pos = -1;
@@ -202,7 +210,13 @@ gst_h264_parse_start (GstBaseParse * parse)
GST_DEBUG_OBJECT (parse, "start");
gst_h264_parse_reset (h264parse);
- gst_h264_params_create (&h264parse->params, GST_ELEMENT (h264parse));
+ h264parse->nalparser = gst_h264_nal_parser_new ();
+
+ h264parse->dts = GST_CLOCK_TIME_NONE;
+ h264parse->ts_trn_nb = GST_CLOCK_TIME_NONE;
+ h264parse->sei_pic_struct_pres_flag = FALSE;
+ h264parse->sei_pic_struct = 0;
+ h264parse->field_pic_flag = 0;
gst_base_parse_set_min_frame_size (parse, 6);
@@ -212,13 +226,19 @@ gst_h264_parse_start (GstBaseParse * parse)
static gboolean
gst_h264_parse_stop (GstBaseParse * parse)
{
+ guint i;
GstH264Parse *h264parse = GST_H264_PARSE (parse);
GST_DEBUG_OBJECT (parse, "stop");
gst_h264_parse_reset (h264parse);
- gst_h264_params_free (h264parse->params);
- h264parse->params = NULL;
+ for (i = 0; i < GST_H264_MAX_SPS_COUNT; i++)
+ gst_buffer_replace (&h264parse->sps_nals[i], NULL);
+ 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;
return TRUE;
}
@@ -318,6 +338,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);
+
buf = gst_buffer_new_and_alloc (size + nl + 4);
if (format == GST_H264_PARSE_FORMAT_AVC) {
GST_WRITE_UINT32_BE (GST_BUFFER_DATA (buf), size << (32 - 8 * nl));
@@ -332,65 +354,158 @@ gst_h264_parse_wrap_nal (GstH264Parse * h264parse, guint format, guint8 * data,
return buf;
}
+static void
+gst_h264_parser_store_nal (GstH264Parse * h264parse, guint id,
+ GstH264NalUnitType naltype, GstH264NalUnit * nalu)
+{
+ GstBuffer *buf, **store;
+ guint size = nalu->size, store_size;
+
+ if (naltype == GST_H264_NAL_SPS) {
+ store_size = GST_H264_MAX_SPS_COUNT;
+ store = h264parse->sps_nals;
+ GST_DEBUG ("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);
+ } else
+ return;
+
+ if (id >= store_size) {
+ GST_DEBUG_OBJECT (h264parse, "unable to store nal, id out-of-range %d", id);
+ return;
+ }
+
+ buf = gst_buffer_new_and_alloc (size);
+ memcpy (GST_BUFFER_DATA (buf), nalu->data + nalu->offset, size);
+
+ if (store[id])
+ gst_buffer_unref (store[id]);
+
+ store[id] = buf;
+}
+
/* SPS/PPS/IDR considered key, all others DELTA;
* so downstream waiting for keyframe can pick up at SPS/PPS/IDR */
#define NAL_TYPE_IS_KEY(nt) (((nt) == 5) || ((nt) == 7) || ((nt) == 8))
/* caller guarantees 2 bytes of nal payload */
static void
-gst_h264_parse_process_nal (GstH264Parse * h264parse, guint8 * data,
- gint sc_pos, gint nal_pos, guint nal_size)
+gst_h264_parse_process_nal (GstH264Parse * h264parse, GstH264NalUnit * nalu)
{
guint nal_type;
+ GstH264SliceHdr slice;
+ GstH264PPS pps;
+ GstH264SPS sps;
+ GstH264SEIMessage sei;
+
+ gboolean slcparsed = FALSE;
+ GstH264NalParser *nalparser = h264parse->nalparser;
- g_return_if_fail (nal_pos - sc_pos > 0 && nal_pos - sc_pos <= 4);
/* nothing to do for broken input */
- if (G_UNLIKELY (nal_size < 2)) {
- GST_DEBUG_OBJECT (h264parse, "not processing nal size %u", nal_size);
+ if (G_UNLIKELY (nalu->size < 2)) {
+ GST_DEBUG_OBJECT (h264parse, "not processing nal size %u", nalu->size);
return;
}
- /* lower layer collects params */
- gst_h264_params_parse_nal (h264parse->params, data + nal_pos, nal_size);
-
/* we have a peek as well */
- nal_type = data[nal_pos] & 0x1f;
+ nal_type = nalu->type;
h264parse->keyframe |= NAL_TYPE_IS_KEY (nal_type);
+ GST_DEBUG_OBJECT (h264parse, "processing nal of type %u, size %u",
+ nal_type, nalu->size);
+
switch (nal_type) {
- case NAL_SPS:
- case NAL_PPS:
+ case GST_H264_NAL_SPS:
+ gst_h264_parser_parse_sps (nalparser, nalu, &sps, TRUE);
+
+ GST_DEBUG_OBJECT (h264parse, "triggering src caps check");
+ h264parse->update_caps = TRUE;
+ /* found in stream, no need to forcibly push at start */
+ h264parse->push_codec = FALSE;
+
+ gst_h264_parser_store_nal (h264parse, sps.id, nal_type, nalu);
+ break;
+ case GST_H264_NAL_PPS:
+ gst_h264_parser_parse_pps (nalparser, nalu, &pps);
/* parameters might have changed, force caps check */
GST_DEBUG_OBJECT (h264parse, "triggering src caps check");
h264parse->update_caps = TRUE;
/* found in stream, no need to forcibly push at start */
h264parse->push_codec = FALSE;
+
+ gst_h264_parser_store_nal (h264parse, pps.id, nal_type, nalu);
break;
- case NAL_SLICE:
- case NAL_SLICE_DPA:
- case NAL_SLICE_DPB:
- case NAL_SLICE_DPC:
+ case GST_H264_NAL_SEI:
+ gst_h264_parser_parse_sei (nalparser, nalu, &sei);
+ switch (sei.payloadType) {
+ case GST_H264_SEI_PIC_TIMING:
+ h264parse->sei_pic_struct_pres_flag =
+ sei.pic_timing.pic_struct_present_flag;
+ h264parse->sei_cpb_removal_delay = sei.pic_timing.cpb_removal_delay;
+ if (h264parse->sei_pic_struct_pres_flag)
+ h264parse->sei_pic_struct = sei.pic_timing.pic_struct;
+ break;
+ case GST_H264_SEI_BUF_PERIOD:
+ if (h264parse->ts_trn_nb == GST_CLOCK_TIME_NONE ||
+ h264parse->dts == GST_CLOCK_TIME_NONE)
+ h264parse->ts_trn_nb = 0;
+ else
+ h264parse->ts_trn_nb = h264parse->dts;
+
+ GST_LOG_OBJECT (h264parse,
+ "new buffering period; ts_trn_nb updated: %" GST_TIME_FORMAT,
+ GST_TIME_ARGS (h264parse->ts_trn_nb));
+ break;
+ }
+ break;
+
+ case GST_H264_NAL_SLICE:
+ case GST_H264_NAL_SLICE_DPA:
+ case GST_H264_NAL_SLICE_DPB:
+ case GST_H264_NAL_SLICE_DPC:
+ slcparsed = TRUE;
+ if (gst_h264_parser_parse_slice_hdr (nalparser, nalu,
+ &slice, FALSE, FALSE) == GST_H264_PARSER_ERROR)
+ return;
+
/* real frame data */
- h264parse->frame_start |= (h264parse->params->first_mb_in_slice == 0);
+ h264parse->frame_start |= (slice.first_mb_in_slice == 0);
/* 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);
if (G_LIKELY (!h264parse->push_codec))
break;
/* fall-through */
- case NAL_SLICE_IDR:
+ case GST_H264_NAL_SLICE_IDR:
+ if (!slcparsed) {
+ 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",
+ h264parse->frame_start, slice.first_mb_in_slice);
+ }
/* real frame data */
- h264parse->frame_start |= (h264parse->params->first_mb_in_slice == 0);
+ h264parse->frame_start |= (slice.first_mb_in_slice == 0);
+
/* 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 = sc_pos;
+ 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);
break;
+ default:
+ gst_h264_parser_parse_nal (nalparser, nalu);
}
/* if AVC output needed, collect properly prefixed nal in adapter,
@@ -400,7 +515,7 @@ gst_h264_parse_process_nal (GstH264Parse * h264parse, guint8 * data,
GST_LOG_OBJECT (h264parse, "collecting NAL in AVC frame");
buf = gst_h264_parse_wrap_nal (h264parse, h264parse->format,
- data + nal_pos, nal_size);
+ nalu->data + nalu->offset, nalu->size);
gst_adapter_push (h264parse->frame_out, buf);
}
}
@@ -408,21 +523,31 @@ gst_h264_parse_process_nal (GstH264Parse * h264parse, guint8 * data,
/* caller guarantees at least 2 bytes of nal payload for each nal
* returns TRUE if next_nal indicates that nal terminates an AU */
static inline gboolean
-gst_h264_parse_collect_nal (GstH264Parse * h264parse, guint8 * nal,
- guint8 * next_nal)
+gst_h264_parse_collect_nal (GstH264Parse * h264parse, const guint8 * data,
+ guint size, GstH264NalUnit * nalu)
{
- gint nal_type;
gboolean complete;
+ GstH264ParserResult parse_res;
+ GstH264NalUnitType nal_type = nalu->type;
+ GstH264NalUnit nnalu;
- if (h264parse->align == GST_H264_PARSE_ALIGN_NAL)
+ GST_DEBUG ("Parsing collecte nal");
+ parse_res = gst_h264_parser_identify_nalu (h264parse->nalparser, data,
+ nalu->offset + nalu->size, size, &nnalu);
+
+ if (parse_res == GST_H264_PARSER_ERROR)
+ return FALSE;
+
+ if (h264parse->align == GST_H264_PARSE_ALIGN_NAL) {
return TRUE;
+ }
/* determine if AU complete */
- nal_type = nal[0] & 0x1f;
GST_LOG_OBJECT (h264parse, "nal type: %d", nal_type);
/* coded slice NAL starts a picture,
* i.e. other types become aggregated in front of it */
- h264parse->picture_start |= (nal_type == 1 || nal_type == 2 || nal_type == 5);
+ h264parse->picture_start |= (nal_type == GST_H264_NAL_SLICE ||
+ nal_type == GST_H264_NAL_SLICE_DPA || nal_type == GST_H264_NAL_SLICE_IDR);
/* consider a coded slices (IDR or not) to start a picture,
* (so ending the previous one) if first_mb_in_slice == 0
@@ -431,35 +556,23 @@ gst_h264_parse_collect_nal (GstH264Parse * h264parse, guint8 * nal,
* but in practice it works in sane cases, needs not much parsing,
* and also works with broken frame_num in NAL
* (where spec-wise would fail) */
- nal_type = next_nal[0] & 0x1f;
+ nal_type = nnalu.type;
+ complete = h264parse->picture_start && (nal_type >= GST_H264_NAL_SEI &&
+ nal_type <= GST_H264_NAL_AU_DELIMITER);
+
GST_LOG_OBJECT (h264parse, "next nal type: %d", nal_type);
- complete = h264parse->picture_start && (nal_type >= 6 && nal_type <= 9);
complete |= h264parse->picture_start &&
- (nal_type == 1 || nal_type == 2 || nal_type == 5) &&
+ (nal_type == GST_H264_NAL_SLICE ||
+ nal_type == GST_H264_NAL_SLICE_DPA ||
+ nal_type == GST_H264_NAL_SLICE_IDR) &&
/* first_mb_in_slice == 0 considered start of frame */
- (next_nal[1] & 0x80);
+ (nnalu.data[nnalu.offset + 1] & 0x80);
GST_LOG_OBJECT (h264parse, "au complete: %d", complete);
return complete;
}
-/* finds next startcode == 00 00 01, along with a subsequent byte */
-static guint
-gst_h264_parse_find_sc (GstBuffer * buffer, guint skip)
-{
- GstByteReader br;
- guint sc_pos = -1;
-
- gst_byte_reader_init_from_buffer (&br, buffer);
-
- /* NALU not empty, so we can at least expect 1 (even 2) bytes following sc */
- sc_pos = gst_byte_reader_masked_scan_uint32 (&br, 0xffffff00, 0x00000100,
- skip, gst_byte_reader_get_remaining (&br) - skip);
-
- return sc_pos;
-}
-
/* FIXME move into baseparse, or anything equivalent;
* see https://bugzilla.gnome.org/show_bug.cgi?id=650093 */
#define GST_BASE_PARSE_FRAME_FLAG_PARSING 0x10000
@@ -470,10 +583,11 @@ gst_h264_parse_check_valid_frame (GstBaseParse * parse,
{
GstH264Parse *h264parse = GST_H264_PARSE (parse);
GstBuffer *buffer = frame->buffer;
- gint sc_pos, nal_pos, next_sc_pos, next_nal_pos;
guint8 *data;
- guint size;
+ guint size, current_off = 0;
gboolean drain;
+ GstH264NalParser *nalparser = h264parse->nalparser;
+ GstH264NalUnit nalu = h264parse->nalu;
/* expect at least 3 bytes startcode == sc, and 2 bytes NALU payload */
if (G_UNLIKELY (GST_BUFFER_SIZE (buffer) < 5))
@@ -495,105 +609,108 @@ gst_h264_parse_check_valid_frame (GstBaseParse * parse,
data = GST_BUFFER_DATA (buffer);
size = GST_BUFFER_SIZE (buffer);
- GST_LOG_OBJECT (h264parse, "last_nal_pos: %d, last_scan_pos %d",
- h264parse->last_nal_pos, h264parse->next_sc_pos);
-
- nal_pos = h264parse->last_nal_pos;
- next_sc_pos = h264parse->next_sc_pos;
-
- if (!next_sc_pos) {
- sc_pos = gst_h264_parse_find_sc (buffer, 0);
-
- if (sc_pos == -1) {
- /* SC not found, need more data */
- sc_pos = GST_BUFFER_SIZE (buffer) - 3;
- /* avoid going < 0 later on */
- nal_pos = next_sc_pos = sc_pos;
- goto more;
- }
-
- nal_pos = sc_pos + 3;
- next_sc_pos = nal_pos;
- /* sc might have 2 or 3 0-bytes */
- if (sc_pos > 0 && data[sc_pos - 1] == 00)
- sc_pos--;
- GST_LOG_OBJECT (h264parse, "found sc at offset %d", sc_pos);
- } else {
- /* previous checks already arrange sc at start */
- sc_pos = 0;
- }
-
drain = GST_BASE_PARSE_DRAINING (parse);
+ current_off = h264parse->current_off;
+
+ GST_DEBUG ("Last parse position %u", current_off);
while (TRUE) {
- gint prev_sc_pos;
+ 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",
+ current_off, nalu.offset, nalu.size);
- next_sc_pos = gst_h264_parse_find_sc (buffer, next_sc_pos);
- if (next_sc_pos == -1) {
- GST_LOG_OBJECT (h264parse, "no next sc");
- if (drain) {
- /* FLUSH/EOS, it's okay if we can't find the next frame */
- next_sc_pos = size;
- next_nal_pos = size;
- } else {
- next_sc_pos = size - 3;
- goto more;
- }
- } else {
- next_nal_pos = next_sc_pos + 3;
- if (data[next_sc_pos - 1] == 00)
- next_sc_pos--;
- GST_LOG_OBJECT (h264parse, "found next sc at offset %d", next_sc_pos);
- /* need at least 1 more byte of next NAL */
- if (!drain && (next_nal_pos == size - 1))
- goto more;
- }
-
- /* determine nal's sc position */
- prev_sc_pos = nal_pos - 3;
- g_assert (prev_sc_pos >= 0);
- if (prev_sc_pos > 0 && data[prev_sc_pos - 1] == 0)
- prev_sc_pos--;
-
- /* already consume and gather info from NAL */
- if (G_UNLIKELY (next_sc_pos - nal_pos < 2)) {
- GST_WARNING_OBJECT (h264parse, "input stream is corrupt; "
- "it contains a NAL unit of length %d", next_sc_pos - nal_pos);
- /* broken nal at start -> arrange to skip it,
- * otherwise have it terminate current au
- * (and so it will be skippd on next frame round) */
- if (prev_sc_pos == sc_pos) {
- *skipsize = sc_pos + 2;
- return FALSE;
- } else {
- next_sc_pos = prev_sc_pos;
+ current_off = nalu.offset + nalu.size;
+ GST_DEBUG ("CURENT OFF. %u, %u", current_off, nalu.offset + nalu.size);
+ if (!h264parse->nalu.size && !h264parse->nalu.valid)
+ h264parse->nalu = nalu;
break;
- }
- }
- gst_h264_parse_process_nal (h264parse, data, prev_sc_pos, nal_pos,
- next_sc_pos - nal_pos);
- if (next_nal_pos >= size - 1 ||
- gst_h264_parse_collect_nal (h264parse, data + nal_pos,
- data + next_nal_pos))
- break;
+ case GST_H264_PARSER_BROKEN_LINK:
+ return FALSE;
+ case GST_H264_PARSER_ERROR:
+ current_off = size - 3;
+ goto parsing_error;
+ case GST_H264_PARSER_NO_NAL:
+ current_off = size - 3;
+ goto more;
+ case GST_H264_PARSER_BROKEN_DATA:
+ GST_WARNING_OBJECT (h264parse, "input stream is corrupt; "
+ "it contains a NAL unit of length %d", nalu.size);
- /* move along */
- next_sc_pos = nal_pos = next_nal_pos;
+ /* broken nal at start -> arrange to skip it,
+ * otherwise have it terminate current au
+ * (and so it will be skipped on next frame round) */
+ if (nalu.sc_offset == h264parse->nalu.sc_offset) {
+ *skipsize = nalu.offset;
+
+ GST_DEBUG ("Skiping 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);
+
+ current_off = nalu.sc_offset;
+ /* We keep the reference to this nal so we start over the parsing
+ * here */
+ if (!h264parse->nalu.size && !h264parse->nalu.valid)
+ h264parse->nalu = nalu;
+
+ if (drain) {
+ GST_DEBUG ("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;
+ return FALSE;
+ }
+
+ /* We parse it anyway */
+ nalu.size = size - nalu.offset;
+ break;
+ }
+ goto more;
+ }
+
+ current_off = nalu.offset + nalu.size;
+
+ GST_DEBUG ("%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)
+ break;
}
- *skipsize = sc_pos;
- *framesize = next_sc_pos - sc_pos;
+end:
+ /* FIXME this shouldnt be needed */
+ if (h264parse->nalu.sc_offset > 0 && data[h264parse->nalu.sc_offset - 1] == 0)
+ h264parse->nalu.sc_offset--;
+
+ *skipsize = h264parse->nalu.sc_offset;
+ *framesize = nalu.offset + nalu.size - h264parse->nalu.sc_offset; /* CHECKME */
+ h264parse->current_off = current_off;
return TRUE;
+parsing_error:
+ GST_DEBUG ("Error parsing Nal Unit");
more:
+
/* ask for best next available */
*framesize = G_MAXUINT;
+ if (!h264parse->nalu.size) {
+ /* skip up to initial startcode */
+ *skipsize = h264parse->nalu.sc_offset;
+ } else {
+ *skipsize = 0;
+ }
- /* skip up to initial startcode */
- *skipsize = sc_pos;
- /* resume scanning here next time */
- h264parse->last_nal_pos = nal_pos - sc_pos;
- h264parse->next_sc_pos = next_sc_pos - sc_pos;
+ /* Restart parsing from here next time */
+ h264parse->current_off = current_off;
return FALSE;
}
@@ -610,8 +727,8 @@ gst_h264_parse_make_codec_data (GstH264Parse * h264parse)
/* only nal payload in stored nals */
- for (i = 0; i < MAX_SPS_COUNT; i++) {
- if ((nal = h264parse->params->sps_nals[i])) {
+ for (i = 0; i < GST_H264_MAX_SPS_COUNT; i++) {
+ if ((nal = h264parse->sps_nals[i])) {
num_sps++;
/* size bytes also count */
sps_size += GST_BUFFER_SIZE (nal) + 2;
@@ -623,8 +740,8 @@ gst_h264_parse_make_codec_data (GstH264Parse * h264parse)
}
}
}
- for (i = 0; i < MAX_PPS_COUNT; i++) {
- if ((nal = h264parse->params->pps_nals[i])) {
+ for (i = 0; i < GST_H264_MAX_PPS_COUNT; i++) {
+ if ((nal = h264parse->pps_nals[i])) {
num_pps++;
/* size bytes also count */
pps_size += GST_BUFFER_SIZE (nal) + 2;
@@ -648,8 +765,8 @@ gst_h264_parse_make_codec_data (GstH264Parse * h264parse)
data[5] = 0xe0 | num_sps; /* number of SPSs */
data += 6;
- for (i = 0; i < MAX_SPS_COUNT; i++) {
- if ((nal = h264parse->params->sps_nals[i])) {
+ for (i = 0; i < GST_H264_MAX_SPS_COUNT; i++) {
+ if ((nal = h264parse->sps_nals[i])) {
GST_WRITE_UINT16_BE (data, GST_BUFFER_SIZE (nal));
memcpy (data + 2, GST_BUFFER_DATA (nal), GST_BUFFER_SIZE (nal));
data += 2 + GST_BUFFER_SIZE (nal);
@@ -658,8 +775,8 @@ gst_h264_parse_make_codec_data (GstH264Parse * h264parse)
data[0] = num_pps;
data++;
- for (i = 0; i < MAX_PPS_COUNT; i++) {
- if ((nal = h264parse->params->pps_nals[i])) {
+ for (i = 0; i < GST_H264_MAX_PPS_COUNT; i++) {
+ if ((nal = h264parse->pps_nals[i])) {
GST_WRITE_UINT16_BE (data, GST_BUFFER_SIZE (nal));
memcpy (data + 2, GST_BUFFER_DATA (nal), GST_BUFFER_SIZE (nal));
data += 2 + GST_BUFFER_SIZE (nal);
@@ -672,7 +789,7 @@ gst_h264_parse_make_codec_data (GstH264Parse * h264parse)
static void
gst_h264_parse_update_src_caps (GstH264Parse * h264parse, GstCaps * caps)
{
- GstH264ParamsSPS *sps;
+ GstH264SPS *sps;
GstCaps *sink_caps;
gboolean modified = FALSE;
GstBuffer *buf = NULL;
@@ -695,7 +812,7 @@ gst_h264_parse_update_src_caps (GstH264Parse * h264parse, GstCaps * caps)
else
sink_caps = gst_caps_new_simple ("video/x-h264", NULL);
- sps = h264parse->params->sps;
+ sps = h264parse->nalparser->last_sps;
GST_DEBUG_OBJECT (h264parse, "sps: %p", sps);
/* only codec-data for nice-and-clean au aligned packetized avc format */
@@ -764,6 +881,134 @@ gst_h264_parse_update_src_caps (GstH264Parse * h264parse, GstCaps * caps)
gst_buffer_unref (buf);
}
+static void
+gst_h264_parse_get_timestamp (GstH264Parse * h264parse,
+ GstClockTime * out_ts, GstClockTime * out_dur, gboolean frame)
+{
+ GstH264SPS *sps = h264parse->nalparser->last_sps;
+ GstClockTime upstream;
+ gint duration = 1;
+
+ g_return_if_fail (out_dur != NULL);
+ g_return_if_fail (out_ts != NULL);
+
+ upstream = *out_ts;
+
+ if (!frame) {
+ GST_LOG_OBJECT (h264parse, "no frame data -> 0 duration");
+ *out_dur = 0;
+ goto exit;
+ } else {
+ *out_ts = upstream;
+ }
+
+ if (!sps) {
+ GST_DEBUG_OBJECT (h264parse, "referred SPS invalid");
+ goto exit;
+ } else if (!sps->vui_parameters.timing_info_present_flag) {
+ GST_DEBUG_OBJECT (h264parse,
+ "unable to compute timestamp: timing info not present");
+ goto exit;
+ } else if (sps->vui_parameters.time_scale == 0) {
+ GST_DEBUG_OBJECT (h264parse,
+ "unable to compute timestamp: time_scale = 0 "
+ "(this is forbidden in spec; bitstream probably contains error)");
+ goto exit;
+ }
+
+ if (h264parse->sei_pic_struct_pres_flag &&
+ h264parse->sei_pic_struct != (guint8) - 1) {
+ /* Note that when h264parse->sei_pic_struct == -1 (unspecified), there
+ * are ways to infer its value. This is related to computing the
+ * TopFieldOrderCnt and BottomFieldOrderCnt, which looks
+ * complicated and thus not implemented for the time being. Yet
+ * the value we have here is correct for many applications
+ */
+ switch (h264parse->sei_pic_struct) {
+ case GST_H264_SEI_PIC_STRUCT_TOP_FIELD:
+ case GST_H264_SEI_PIC_STRUCT_BOTTOM_FIELD:
+ duration = 1;
+ break;
+ case GST_H264_SEI_PIC_STRUCT_FRAME:
+ case GST_H264_SEI_PIC_STRUCT_TOP_BOTTOM:
+ case GST_H264_SEI_PIC_STRUCT_BOTTOM_TOP:
+ duration = 2;
+ break;
+ case GST_H264_SEI_PIC_STRUCT_TOP_BOTTOM_TOP:
+ case GST_H264_SEI_PIC_STRUCT_BOTTOM_TOP_BOTTOM:
+ duration = 3;
+ break;
+ case GST_H264_SEI_PIC_STRUCT_FRAME_DOUBLING:
+ duration = 4;
+ break;
+ case GST_H264_SEI_PIC_STRUCT_FRAME_TRIPLING:
+ duration = 6;
+ break;
+ default:
+ GST_DEBUG_OBJECT (h264parse,
+ "h264parse->sei_pic_struct of unknown value %d. Not parsed",
+ h264parse->sei_pic_struct);
+ break;
+ }
+ } else {
+ duration = h264parse->field_pic_flag ? 1 : 2;
+ }
+
+ GST_LOG_OBJECT (h264parse, "frame tick duration %d", duration);
+
+ /*
+ * h264parse.264 C.1.2 Timing of coded picture removal (equivalent to DTS):
+ * Tr,n(0) = initial_cpb_removal_delay[ SchedSelIdx ] / 90000
+ * Tr,n(n) = Tr,n(nb) + Tc * cpb_removal_delay(n)
+ * where
+ * Tc = num_units_in_tick / time_scale
+ */
+
+ if (h264parse->ts_trn_nb != GST_CLOCK_TIME_NONE) {
+ GST_LOG_OBJECT (h264parse, "buffering based ts");
+ /* buffering period is present */
+ if (upstream != GST_CLOCK_TIME_NONE) {
+ /* If upstream timestamp is valid, we respect it and adjust current
+ * reference point */
+ h264parse->ts_trn_nb = upstream -
+ (GstClockTime) gst_util_uint64_scale_int
+ (h264parse->sei_cpb_removal_delay * GST_SECOND,
+ sps->vui_parameters.num_units_in_tick,
+ sps->vui_parameters.time_scale);
+ } else {
+ /* If no upstream timestamp is given, we write in new timestamp */
+ upstream = h264parse->dts = h264parse->ts_trn_nb +
+ (GstClockTime) gst_util_uint64_scale_int
+ (h264parse->sei_cpb_removal_delay * GST_SECOND,
+ sps->vui_parameters.num_units_in_tick,
+ sps->vui_parameters.time_scale);
+ }
+ } else {
+ GstClockTime dur;
+
+ GST_LOG_OBJECT (h264parse, "duration based ts");
+ /* naive method: no removal delay specified
+ * track upstream timestamp and provide best guess frame duration */
+ dur = gst_util_uint64_scale_int (duration * GST_SECOND,
+ sps->vui_parameters.num_units_in_tick, sps->vui_parameters.time_scale);
+ /* sanity check */
+ if (dur < GST_MSECOND) {
+ GST_DEBUG_OBJECT (h264parse, "discarding dur %" GST_TIME_FORMAT,
+ GST_TIME_ARGS (dur));
+ } else {
+ *out_dur = dur;
+ }
+ }
+
+exit:
+ if (GST_CLOCK_TIME_IS_VALID (upstream))
+ *out_ts = h264parse->dts = upstream;
+
+ if (GST_CLOCK_TIME_IS_VALID (*out_dur) &&
+ GST_CLOCK_TIME_IS_VALID (h264parse->dts))
+ h264parse->dts += *out_dur;
+}
+
static GstFlowReturn
gst_h264_parse_parse_frame (GstBaseParse * parse, GstBaseParseFrame * frame)
{
@@ -776,7 +1021,7 @@ gst_h264_parse_parse_frame (GstBaseParse * parse, GstBaseParseFrame * frame)
gst_h264_parse_update_src_caps (h264parse, NULL);
- gst_h264_params_get_timestamp (h264parse->params,
+ gst_h264_parse_get_timestamp (h264parse,
&GST_BUFFER_TIMESTAMP (buffer), &GST_BUFFER_DURATION (buffer),
h264parse->frame_start);
@@ -864,16 +1109,16 @@ gst_h264_parse_pre_push_frame (GstBaseParse * parse, GstBaseParseFrame * frame)
if (h264parse->align == GST_H264_PARSE_ALIGN_NAL) {
/* send separate config NAL buffers */
GST_DEBUG_OBJECT (h264parse, "- sending SPS/PPS");
- for (i = 0; i < MAX_SPS_COUNT; i++) {
- if ((codec_nal = h264parse->params->sps_nals[i])) {
+ for (i = 0; i < GST_H264_MAX_SPS_COUNT; i++) {
+ if ((codec_nal = h264parse->sps_nals[i])) {
GST_DEBUG_OBJECT (h264parse, "sending SPS nal");
gst_h264_parse_push_codec_buffer (h264parse, codec_nal,
timestamp);
h264parse->last_report = new_ts;
}
}
- for (i = 0; i < MAX_PPS_COUNT; i++) {
- if ((codec_nal = h264parse->params->pps_nals[i])) {
+ for (i = 0; i < GST_H264_MAX_PPS_COUNT; i++) {
+ if ((codec_nal = h264parse->pps_nals[i])) {
GST_DEBUG_OBJECT (h264parse, "sending PPS nal");
gst_h264_parse_push_codec_buffer (h264parse, codec_nal,
timestamp);
@@ -890,8 +1135,8 @@ gst_h264_parse_pre_push_frame (GstBaseParse * parse, GstBaseParseFrame * frame)
gst_byte_writer_put_data (&bw, GST_BUFFER_DATA (buffer),
h264parse->idr_pos);
GST_DEBUG_OBJECT (h264parse, "- inserting SPS/PPS");
- for (i = 0; i < MAX_SPS_COUNT; i++) {
- if ((codec_nal = h264parse->params->sps_nals[i])) {
+ for (i = 0; i < GST_H264_MAX_SPS_COUNT; i++) {
+ if ((codec_nal = h264parse->sps_nals[i])) {
GST_DEBUG_OBJECT (h264parse, "inserting SPS nal");
gst_byte_writer_put_uint32_be (&bw,
bs ? 1 : GST_BUFFER_SIZE (codec_nal));
@@ -900,8 +1145,8 @@ gst_h264_parse_pre_push_frame (GstBaseParse * parse, GstBaseParseFrame * frame)
h264parse->last_report = new_ts;
}
}
- for (i = 0; i < MAX_PPS_COUNT; i++) {
- if ((codec_nal = h264parse->params->pps_nals[i])) {
+ for (i = 0; i < GST_H264_MAX_PPS_COUNT; i++) {
+ if ((codec_nal = h264parse->pps_nals[i])) {
GST_DEBUG_OBJECT (h264parse, "inserting PPS nal");
gst_byte_writer_put_uint32_be (&bw,
bs ? 1 : GST_BUFFER_SIZE (codec_nal));
@@ -937,7 +1182,9 @@ gst_h264_parse_set_caps (GstBaseParse * parse, GstCaps * caps)
GstStructure *str;
const GValue *value;
GstBuffer *codec_data = NULL;
- guint size, format, align;
+ guint size, format, align, off;
+ GstH264NalUnit nalu;
+ GstH264ParserResult parseres;
h264parse = GST_H264_PARSE (parse);
@@ -959,7 +1206,7 @@ gst_h264_parse_set_caps (GstBaseParse * parse, GstCaps * caps)
if (format != GST_H264_PARSE_FORMAT_BYTE &&
(value = gst_structure_get_value (str, "codec_data"))) {
guint8 *data;
- guint num_sps, num_pps, profile, len;
+ guint num_sps, num_pps, profile;
gint i;
GST_DEBUG_OBJECT (h264parse, "have packetized h264");
@@ -992,28 +1239,29 @@ gst_h264_parse_set_caps (GstBaseParse * parse, GstCaps * caps)
GST_DEBUG_OBJECT (h264parse, "nal length %u", h264parse->nal_length_size);
num_sps = data[5] & 0x1f;
- data += 6;
- size -= 6;
+ off = 6;
for (i = 0; i < num_sps; i++) {
- len = GST_READ_UINT16_BE (data);
- if (size < len + 2 || len < 2)
+ parseres = gst_h264_parser_identify_nalu_avc (h264parse->nalparser,
+ data, off, size - off, 2, &nalu);
+ if (parseres != GST_H264_PARSER_OK)
goto avcc_too_small;
- /* digest for later reference */
- gst_h264_parse_process_nal (h264parse, data, 0, 2, len);
- data += len + 2;
- size -= len + 2;
+
+ gst_h264_parse_process_nal (h264parse, &nalu);
+ off = nalu.offset + nalu.size;
}
+
num_pps = data[0];
data++;
size++;
for (i = 0; i < num_pps; i++) {
- len = GST_READ_UINT16_BE (data);
- if (size < len + 2 || len < 2)
+ parseres = gst_h264_parser_identify_nalu_avc (h264parse->nalparser,
+ data, off, size - off, 2, &nalu);
+ if (parseres != GST_H264_PARSER_OK) {
goto avcc_too_small;
- /* digest for later reference */
- gst_h264_parse_process_nal (h264parse, data, 0, 2, len);
- data += len + 2;
- size -= len + 2;
+ }
+
+ gst_h264_parse_process_nal (h264parse, &nalu);
+ off = nalu.offset + nalu.size;
}
h264parse->codec_data = gst_buffer_ref (codec_data);
@@ -1089,10 +1337,12 @@ gst_h264_parse_chain (GstPad * pad, GstBuffer * buffer)
GstBuffer *sub;
GstFlowReturn ret = GST_FLOW_OK;
guint32 len;
+ GstH264NalUnit nalu;
const guint nl = h264parse->nal_length_size;
GST_LOG_OBJECT (h264parse, "processing packet buffer of size %d",
GST_BUFFER_SIZE (buffer));
+
gst_byte_reader_init_from_buffer (&br, buffer);
while (ret == GST_FLOW_OK && gst_byte_reader_get_remaining (&br)) {
GST_DEBUG_OBJECT (h264parse, "AVC nal offset %d",
@@ -1114,9 +1364,10 @@ gst_h264_parse_chain (GstPad * pad, GstBuffer * buffer)
break;
default:
goto not_negotiated;
- break;
}
+
GST_DEBUG_OBJECT (h264parse, "AVC nal size %d", len);
+
if (gst_byte_reader_get_remaining (&br) < len)
goto parse_failed;
if (h264parse->split_packetized) {
@@ -1133,9 +1384,10 @@ gst_h264_parse_chain (GstPad * pad, GstBuffer * buffer)
/* NOTE: so if it is really configured to do so,
* pre_push can/will still insert codec-data at intervals,
* which is not really pure pass-through, but anyway ... */
- gst_h264_parse_process_nal (h264parse,
+ gst_h264_parser_identify_nalu (h264parse->nalparser,
GST_BUFFER_DATA (buffer), gst_byte_reader_get_pos (&br) - nl,
- gst_byte_reader_get_pos (&br), len);
+ GST_BUFFER_SIZE (buffer), &nalu);
+ gst_h264_parse_process_nal (h264parse, &nalu);
gst_byte_reader_skip_unchecked (&br, len);
}
}
diff --git a/gst/videoparsers/gsth264parse.h b/gst/videoparsers/gsth264parse.h
index 1aa1323211..e013a3faca 100644
--- a/gst/videoparsers/gsth264parse.h
+++ b/gst/videoparsers/gsth264parse.h
@@ -1,7 +1,10 @@
/* GStreamer H.264 Parser
- * Copyright (C) <2010> Mark Nauwelaerts
- * Copyright (C) <2010> Collabora Multimedia
+ * Copyright (C) <2010> Collabora ltd
* Copyright (C) <2010> Nokia Corporation
+ * Copyright (C) <2011> Intel Corporation
+ *
+ * Copyright (C) <2010> Mark Nauwelaerts
+ * Copyright (C) <2011> Thibault Saunier
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
@@ -24,8 +27,7 @@
#include
#include
-
-#include "h264parse.h"
+#include
G_BEGIN_DECLS
@@ -61,16 +63,34 @@ struct _GstH264Parse
gboolean packetized;
/* state */
- GstH264Params *params;
+ GstH264NalParser *nalparser;
+ GstH264NalUnit nalu;
guint align;
guint format;
+ guint current_off;
GstClockTime last_report;
gboolean push_codec;
+ /* collected SPS and PPS NALUs */
+ GstBuffer *sps_nals[GST_H264_MAX_SPS_COUNT];
+ GstBuffer *pps_nals[GST_H264_MAX_PPS_COUNT];
+
+ /* Infos we need to keep track of */
+ guint32 sei_cpb_removal_delay;
+ guint8 sei_pic_struct;
+ guint8 sei_pic_struct_pres_flag;
+ guint field_pic_flag;
+
+ /* cached timestamps */
+ /* (trying to) track upstream dts and interpolate */
+ GstClockTime dts;
+ /* dts at start of last buffering period */
+ GstClockTime ts_trn_nb;
+
/* frame parsing */
- guint last_nal_pos;
- guint next_sc_pos;
+ /*guint last_nal_pos;*/
+ /*guint next_sc_pos;*/
gint idr_pos;
gboolean update_caps;
GstAdapter *frame_out;
diff --git a/gst/videoparsers/gstmpegvideoparse.c b/gst/videoparsers/gstmpegvideoparse.c
index 7ebbdf36a4..12d98d5d77 100644
--- a/gst/videoparsers/gstmpegvideoparse.c
+++ b/gst/videoparsers/gstmpegvideoparse.c
@@ -1,8 +1,10 @@
/* GStreamer
* Copyright (C) <2007> Jan Schmidt
* Copyright (C) <2011> Mark Nauwelaerts
- * Copyright (C) <2011> Collabora Multimedia
+ * Copyright (C) <2011> Thibault Saunier
+ * Copyright (C) <2011> Collabora ltd
* Copyright (C) <2011> Nokia Corporation
+ * Copyright (C) <2011> Intel Corporation
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
@@ -168,6 +170,7 @@ gst_mpegv_parse_class_init (GstMpegvParseClass * klass)
static void
gst_mpegv_parse_init (GstMpegvParse * parse, GstMpegvParseClass * g_class)
{
+ parse->mpeg_version = 0;
}
static void
@@ -175,7 +178,7 @@ gst_mpegv_parse_reset_frame (GstMpegvParse * mpvparse)
{
/* done parsing; reset state */
mpvparse->last_sc = -1;
- mpvparse->seq_offset = -1;
+ mpvparse->seq_offset = G_MAXUINT;
mpvparse->pic_offset = -1;
}
@@ -187,7 +190,9 @@ gst_mpegv_parse_reset (GstMpegvParse * mpvparse)
mpvparse->update_caps = TRUE;
gst_buffer_replace (&mpvparse->config, NULL);
- memset (&mpvparse->params, 0, sizeof (mpvparse->params));
+ memset (&mpvparse->sequencehdr, 0, sizeof (mpvparse->sequencehdr));
+ memset (&mpvparse->sequenceext, 0, sizeof (mpvparse->sequenceext));
+ memset (&mpvparse->pichdr, 0, sizeof (mpvparse->pichdr));
}
static gboolean
@@ -217,23 +222,45 @@ gst_mpegv_parse_stop (GstBaseParse * parse)
}
static gboolean
-gst_mpegv_parse_process_config (GstMpegvParse * mpvparse, const guint8 * data,
- gsize size)
+gst_mpegv_parse_process_config (GstMpegvParse * mpvparse, GstBuffer * buf,
+ guint size)
{
+ GList *tmp;
+ guint8 *data = GST_BUFFER_DATA (buf);
+ data = data + mpvparse->seq_offset;
+
/* only do stuff if something new */
if (mpvparse->config && size == GST_BUFFER_SIZE (mpvparse->config) &&
memcmp (GST_BUFFER_DATA (mpvparse->config), data, size) == 0)
return TRUE;
- if (!gst_mpeg_video_params_parse_config (&mpvparse->params, data, size)) {
- GST_DEBUG_OBJECT (mpvparse, "failed to parse config data (size %"
- G_GSSIZE_FORMAT ")", size);
+ if (!gst_mpeg_video_parse_sequence_header (&mpvparse->sequencehdr, data,
+ GST_BUFFER_SIZE (buf) - mpvparse->seq_offset, 0)) {
+ GST_DEBUG_OBJECT (mpvparse,
+ "failed to parse config data (size %" G_GSSIZE_FORMAT ") at offset %d",
+ size, mpvparse->seq_offset);
return FALSE;
}
GST_LOG_OBJECT (mpvparse, "accepting parsed config size %" G_GSSIZE_FORMAT,
size);
+ /* Set mpeg version, and parse sequence extension */
+ if (mpvparse->mpeg_version <= 0) {
+ GstMpegVideoTypeOffsetSize *tpoffsz;
+
+ mpvparse->mpeg_version = 1;
+ for (tmp = mpvparse->typeoffsize; tmp; tmp = tmp->next) {
+ tpoffsz = tmp->data;
+
+ if (tpoffsz->type == GST_MPEG_VIDEO_PACKET_EXTENSION) {
+ mpvparse->mpeg_version = 2;
+ gst_mpeg_video_parse_sequence_extension (&mpvparse->sequenceext,
+ GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf), tpoffsz->offset);
+ }
+ }
+ }
+
/* parsing ok, so accept it as new config */
if (mpvparse->config != NULL)
gst_buffer_unref (mpvparse->config);
@@ -309,22 +336,18 @@ picture_type_name (guint8 pct)
/* for off == 0 initial code; returns TRUE if code starts a frame,
* otherwise returns TRUE if code terminates preceding frame */
static gboolean
-gst_mpegv_parse_process_sc (GstMpegvParse * mpvparse, GstBuffer * buf, gint off)
+gst_mpegv_parse_process_sc (GstMpegvParse * mpvparse,
+ GstBuffer * buf, guint off, guint8 code)
{
- gboolean ret = FALSE, do_seq = TRUE;
- guint8 *data;
- guint code;
+ gboolean ret = FALSE, packet = TRUE;
g_return_val_if_fail (buf && GST_BUFFER_SIZE (buf) >= 4, FALSE);
- data = GST_BUFFER_DATA (buf);
- code = data[off + 3];
-
GST_LOG_OBJECT (mpvparse, "process startcode %x (%s)", code,
picture_start_code_name (code));
switch (code) {
- case MPEG_PACKET_PICTURE:
+ case GST_MPEG_VIDEO_PACKET_PICTURE:
GST_LOG_OBJECT (mpvparse, "startcode is PICTURE");
/* picture is aggregated with preceding sequence/gop, if any.
* so, picture start code only ends if already a previous one */
@@ -332,103 +355,64 @@ gst_mpegv_parse_process_sc (GstMpegvParse * mpvparse, GstBuffer * buf, gint off)
mpvparse->pic_offset = off;
else
ret = TRUE;
- if (!off)
+ if (off == 4)
ret = TRUE;
break;
- case MPEG_PACKET_SEQUENCE:
+ case GST_MPEG_VIDEO_PACKET_SEQUENCE:
GST_LOG_OBJECT (mpvparse, "startcode is SEQUENCE");
- if (off == 0)
+ if (off < mpvparse->seq_offset)
mpvparse->seq_offset = off;
ret = TRUE;
break;
- case MPEG_PACKET_GOP:
+ case GST_MPEG_VIDEO_PACKET_GOP:
GST_LOG_OBJECT (mpvparse, "startcode is GOP");
- if (mpvparse->seq_offset >= 0)
+ if (mpvparse->seq_offset < G_MAXUINT)
ret = mpvparse->gop_split;
else
ret = TRUE;
break;
default:
- do_seq = FALSE;
+ packet = FALSE;
break;
}
- /* process config data */
- if (G_UNLIKELY (mpvparse->seq_offset >= 0 && off && do_seq)) {
- g_assert (mpvparse->seq_offset == 0);
- gst_mpegv_parse_process_config (mpvparse, GST_BUFFER_DATA (buf), off);
- /* avoid accepting again for a PICTURE sc following a GOP sc */
- mpvparse->seq_offset = -1;
+ if (mpvparse->seq_offset != G_MAXUINT && off != mpvparse->seq_offset &&
+ packet) {
+ gst_mpegv_parse_process_config (mpvparse, buf, off - mpvparse->seq_offset);
+ mpvparse->seq_offset = G_MAXUINT;
}
/* extract some picture info if there is any in the frame being terminated */
- if (G_UNLIKELY (ret && off)) {
- if (G_LIKELY (mpvparse->pic_offset >= 0 && mpvparse->pic_offset < off)) {
- if (G_LIKELY (GST_BUFFER_SIZE (buf) >= mpvparse->pic_offset + 6)) {
- gint pct = (data[mpvparse->pic_offset + 5] >> 3) & 0x7;
-
- GST_LOG_OBJECT (mpvparse, "picture_coding_type %d (%s)", pct,
- picture_type_name (pct));
- mpvparse->intra_frame = (pct == MPEG_PICTURE_TYPE_I);
- } else {
- GST_WARNING_OBJECT (mpvparse, "no data following PICTURE startcode");
- mpvparse->intra_frame = FALSE;
- }
- } else {
- /* frame without picture must be some config, consider as keyframe */
- mpvparse->intra_frame = TRUE;
- }
- GST_LOG_OBJECT (mpvparse, "ending frame of size %d, is intra %d", off,
- mpvparse->intra_frame);
+ if (ret && mpvparse->pic_offset >= 0 && mpvparse->pic_offset < off) {
+ if (gst_mpeg_video_parse_picture_header (&mpvparse->pichdr,
+ GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf), mpvparse->pic_offset))
+ GST_LOG_OBJECT (mpvparse, "picture_coding_type %d (%s), ending"
+ "frame of size %d", mpvparse->pichdr.pic_type,
+ picture_type_name (mpvparse->pichdr.pic_type), off - 4);
+ else
+ GST_LOG_OBJECT (mpvparse, "Couldn't parse picture at offset %d",
+ mpvparse->pic_offset);
}
return ret;
}
-static inline guint
-scan_for_start_codes (const GstByteReader * reader, guint offset, guint size)
+static inline gint
+get_frame_size (GstMpegvParse * mpvparse, GstBuffer * buf, GList * l_codoffsz)
{
- const guint8 *data;
- guint32 state;
- guint i;
+ GList *tmp;
+ GstMpegVideoTypeOffsetSize *codoffsz;
- g_return_val_if_fail (size > 0, -1);
- g_return_val_if_fail ((guint64) offset + size <= reader->size - reader->byte,
- -1);
+ for (tmp = l_codoffsz; tmp; tmp = tmp->next) {
+ codoffsz = tmp->data;
- /* we can't find the pattern with less than 4 bytes */
- if (G_UNLIKELY (size < 4))
- return -1;
+ GST_LOG_OBJECT (mpvparse, "next start code at %d", codoffsz->offset);
- data = reader->data + reader->byte + offset;
-
- /* set the state to something that does not match */
- state = 0xffffffff;
-
- /* now find data */
- for (i = 0; i < size; i++) {
- /* throw away one byte and move in the next byte */
- state = ((state << 8) | data[i]);
- if (G_UNLIKELY ((state & 0xffffff00) == 0x00000100)) {
- /* we have a match but we need to have skipped at
- * least 4 bytes to fill the state. */
- if (G_LIKELY (i >= 3))
- return offset + i - 3;
- }
-
- /* Accelerate search for start code */
- if (data[i] > 1) {
- while (i < (size - 4) && data[i] > 1) {
- if (data[i + 3] > 1)
- i += 4;
- else
- i += 1;
- }
- state = 0x00000100;
- }
+ if (gst_mpegv_parse_process_sc (mpvparse, buf, codoffsz->offset,
+ codoffsz->type))
+ return codoffsz->offset - 4;
}
- /* nothing found */
return -1;
}
@@ -436,21 +420,10 @@ scan_for_start_codes (const GstByteReader * reader, guint offset, guint size)
* see https://bugzilla.gnome.org/show_bug.cgi?id=650093 */
#define GST_BASE_PARSE_FRAME_FLAG_PARSING 0x10000
-static gboolean
-gst_mpegv_parse_check_valid_frame (GstBaseParse * parse,
- GstBaseParseFrame * frame, guint * framesize, gint * skipsize)
+static inline void
+update_frame_parsing_status (GstMpegvParse * mpvparse,
+ GstBaseParseFrame * frame)
{
- GstMpegvParse *mpvparse = GST_MPEGVIDEO_PARSE (parse);
- GstBuffer *buf = frame->buffer;
- GstByteReader reader = GST_BYTE_READER_INIT_FROM_BUFFER (buf);
- gint off = 0;
- gboolean ret;
-
-retry:
- /* at least start code and subsequent byte */
- if (G_UNLIKELY (GST_BUFFER_SIZE (buf) - off < 5))
- return FALSE;
-
/* avoid stale cached parsing state */
if (!(frame->flags & GST_BASE_PARSE_FRAME_FLAG_PARSING)) {
GST_LOG_OBJECT (mpvparse, "parsing new frame");
@@ -459,72 +432,75 @@ retry:
} else {
GST_LOG_OBJECT (mpvparse, "resuming frame parsing");
}
+}
- /* if already found a previous start code, e.g. start of frame, go for next */
- if (mpvparse->last_sc >= 0) {
+
+static gboolean
+gst_mpegv_parse_check_valid_frame (GstBaseParse * parse,
+ GstBaseParseFrame * frame, guint * framesize, gint * skipsize)
+{
+ GstMpegvParse *mpvparse = GST_MPEGVIDEO_PARSE (parse);
+ GstBuffer *buf = frame->buffer;
+ gboolean ret = FALSE;
+ GList *tmp;
+ gint off = 0, fsize = -1;
+
+ update_frame_parsing_status (mpvparse, frame);
+
+ if (mpvparse->last_sc >= 0)
off = mpvparse->last_sc;
- goto next;
+
+ mpvparse->typeoffsize =
+ gst_mpeg_video_parse (GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf), off);
+
+ /* No sc found */
+ if (mpvparse->typeoffsize == NULL)
+ goto end;
+
+ /* Already found the start code looking for the end */
+ if (mpvparse->last_sc >= 0) {
+ *skipsize = 0;
+ fsize = get_frame_size (mpvparse, buf, mpvparse->typeoffsize);
+
+ goto end;
}
- off = scan_for_start_codes (&reader, off, GST_BUFFER_SIZE (buf) - off);
+ for (tmp = mpvparse->typeoffsize; tmp; tmp = g_list_next (tmp)) {
+ GstMpegVideoTypeOffsetSize *codoffsz = tmp->data;
- GST_LOG_OBJECT (mpvparse, "possible sync at buffer offset %d", off);
+ GST_LOG_OBJECT (mpvparse, "next start code at %d", codoffsz->offset);
- /* didn't find anything that looks like a sync word, skip */
- if (G_UNLIKELY (off < 0)) {
- *skipsize = GST_BUFFER_SIZE (buf) - 3;
- return FALSE;
- }
+ if (codoffsz->size < 0)
+ break;
- /* possible frame header, but not at offset 0? skip bytes before sync */
- if (G_UNLIKELY (off > 0)) {
- *skipsize = off;
- return FALSE;
- }
+ ret = gst_mpegv_parse_process_sc (mpvparse, buf, codoffsz->offset,
+ codoffsz->type);
- /* note: initial start code is assumed at offset 0 by subsequent code */
-
- /* examine start code, see if it looks like an initial start code */
- if (gst_mpegv_parse_process_sc (mpvparse, buf, 0)) {
- /* found sc */
- mpvparse->last_sc = 0;
- } else {
- off++;
- goto retry;
- }
-
-next:
- /* start is fine as of now */
- *skipsize = 0;
- /* position a bit further than last sc */
- off++;
- /* so now we have start code at start of data; locate next start code */
- off = scan_for_start_codes (&reader, off, GST_BUFFER_SIZE (buf) - off);
-
- GST_LOG_OBJECT (mpvparse, "next start code at %d", off);
- if (off < 0) {
- /* if draining, take all */
- if (GST_BASE_PARSE_DRAINING (parse)) {
- off = GST_BUFFER_SIZE (buf);
- ret = TRUE;
- } else {
- /* resume scan where we left it */
- mpvparse->last_sc = GST_BUFFER_SIZE (buf) - 4;
- /* request best next available */
- *framesize = G_MAXUINT;
- return FALSE;
+ if (ret) {
+ *skipsize = 0;
+ fsize = get_frame_size (mpvparse, buf, tmp->next);
+ break;
}
- } else {
- /* decide whether this startcode ends a frame */
- ret = gst_mpegv_parse_process_sc (mpvparse, buf, off);
}
- if (ret) {
- *framesize = off;
+end:
+ if (fsize > 0) {
+ *framesize = fsize;
+ ret = TRUE;
+ } else if (GST_BASE_PARSE_DRAINING (parse)) {
+ *framesize = GST_BUFFER_SIZE (buf);
+ ret = TRUE;
} else {
- goto next;
+ /* resume scan where we left it */
+ mpvparse->last_sc = GST_BUFFER_SIZE (buf);
+ /* request best next available */
+ *framesize = G_MAXUINT;
+ ret = FALSE;
}
+ g_list_free_full (mpvparse->typeoffsize, (GDestroyNotify) g_free);
+ mpvparse->typeoffsize = NULL;
+
return ret;
}
@@ -550,22 +526,23 @@ gst_mpegv_parse_update_src_caps (GstMpegvParse * mpvparse)
* config data, so we should at least know about version.
* If not, it means it has been requested not to drop data, and
* upstream and/or app must know what they are doing ... */
- if (G_LIKELY (mpvparse->params.mpeg_version))
+
+ if (G_LIKELY (mpvparse->mpeg_version))
gst_caps_set_simple (caps,
- "mpegversion", G_TYPE_INT, mpvparse->params.mpeg_version, NULL);
+ "mpegversion", G_TYPE_INT, mpvparse->mpeg_version, NULL);
gst_caps_set_simple (caps, "systemstream", G_TYPE_BOOLEAN, FALSE,
"parsed", G_TYPE_BOOLEAN, TRUE, NULL);
- if (mpvparse->params.width > 0 && mpvparse->params.height > 0) {
- gst_caps_set_simple (caps, "width", G_TYPE_INT, mpvparse->params.width,
- "height", G_TYPE_INT, mpvparse->params.height, NULL);
+ if (mpvparse->sequencehdr.width > 0 && mpvparse->sequencehdr.height > 0) {
+ gst_caps_set_simple (caps, "width", G_TYPE_INT, mpvparse->sequencehdr.width,
+ "height", G_TYPE_INT, mpvparse->sequencehdr.height, NULL);
}
/* perhaps we have a framerate */
- if (mpvparse->params.fps_n > 0 && mpvparse->params.fps_d > 0) {
- gint fps_num = mpvparse->params.fps_n;
- gint fps_den = mpvparse->params.fps_d;
+ if (mpvparse->sequencehdr.fps_n > 0 && mpvparse->sequencehdr.fps_d > 0) {
+ gint fps_num = mpvparse->sequencehdr.fps_n;
+ gint fps_den = mpvparse->sequencehdr.fps_d;
GstClockTime latency = gst_util_uint64_scale (GST_SECOND, fps_den, fps_num);
gst_caps_set_simple (caps, "framerate",
@@ -576,9 +553,9 @@ gst_mpegv_parse_update_src_caps (GstMpegvParse * mpvparse)
}
/* or pixel-aspect-ratio */
- if (mpvparse->params.par_w && mpvparse->params.par_h > 0) {
+ if (mpvparse->sequencehdr.par_w && mpvparse->sequencehdr.par_h > 0) {
gst_caps_set_simple (caps, "pixel-aspect-ratio", GST_TYPE_FRACTION,
- mpvparse->params.par_w, mpvparse->params.par_h, NULL);
+ mpvparse->sequencehdr.par_w, mpvparse->sequencehdr.par_h, NULL);
}
if (mpvparse->config != NULL) {
@@ -586,9 +563,9 @@ gst_mpegv_parse_update_src_caps (GstMpegvParse * mpvparse)
GST_TYPE_BUFFER, mpvparse->config, NULL);
}
- if (mpvparse->params.mpeg_version == 2) {
- const guint profile_c = mpvparse->params.profile;
- const guint level_c = mpvparse->params.level;
+ if (mpvparse->mpeg_version == 2) {
+ const guint profile_c = mpvparse->sequenceext.profile;
+ const guint level_c = mpvparse->sequenceext.level;
const gchar *profile = NULL, *level = NULL;
/*
* Profile indication - 1 => High, 2 => Spatially Scalable,
@@ -657,7 +634,7 @@ gst_mpegv_parse_parse_frame (GstBaseParse * parse, GstBaseParseFrame * frame)
gst_mpegv_parse_update_src_caps (mpvparse);
- if (G_UNLIKELY (mpvparse->intra_frame))
+ if (G_UNLIKELY (mpvparse->pichdr.pic_type == GST_MPEG_VIDEO_PICTURE_TYPE_I))
GST_BUFFER_FLAG_UNSET (buffer, GST_BUFFER_FLAG_DELTA_UNIT);
else
GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_FLAG_DELTA_UNIT);
@@ -694,8 +671,7 @@ gst_mpegv_parse_set_caps (GstBaseParse * parse, GstCaps * caps)
/* best possible parse attempt,
* src caps are based on sink caps so it will end up in there
* whether sucessful or not */
- gst_mpegv_parse_process_config (mpvparse, GST_BUFFER_DATA (buf),
- GST_BUFFER_SIZE (buf));
+ gst_mpegv_parse_process_config (mpvparse, buf, GST_BUFFER_SIZE (buf));
}
/* let's not interfere and accept regardless of config parsing success */
diff --git a/gst/videoparsers/gstmpegvideoparse.h b/gst/videoparsers/gstmpegvideoparse.h
index a3706a41a4..6837a316e4 100644
--- a/gst/videoparsers/gstmpegvideoparse.h
+++ b/gst/videoparsers/gstmpegvideoparse.h
@@ -1,8 +1,10 @@
/* GStreamer
* Copyright (C) <2007> Jan Schmidt
* Copyright (C) <2011> Mark Nauwelaerts
- * Copyright (C) <2011> Collabora Multimedia
+ * Copyright (C) <2011> Thibault Saunier
+ * Copyright (C) <2011> Collabora ltd
* Copyright (C) <2011> Nokia Corporation
+ * Copyright (C) <2011> Intel Corporation
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
@@ -26,7 +28,7 @@
#include
#include
-#include "mpegvideoparse.h"
+#include
G_BEGIN_DECLS
@@ -49,15 +51,18 @@ struct _GstMpegvParse {
GstBaseParse element;
/* parse state */
+ GList *typeoffsize;
gint last_sc;
gint seq_offset;
gint pic_offset;
- gboolean intra_frame;
gboolean update_caps;
GstBuffer *config;
guint8 profile;
- MPEGVParams params;
+ guint mpeg_version;
+ GstMpegVideoSequenceHdr sequencehdr;
+ GstMpegVideoSequenceExt sequenceext;
+ GstMpegVideoPictureHdr pichdr;
/* properties */
gboolean drop;
diff --git a/gst/videoparsers/h264parse.c b/gst/videoparsers/h264parse.c
deleted file mode 100644
index a556d449cc..0000000000
--- a/gst/videoparsers/h264parse.c
+++ /dev/null
@@ -1,1046 +0,0 @@
-/* GStreamer H.264 Parser
- * Copyright (C) <2010> Mark Nauwelaerts
- * Copyright (C) <2010> Collabora Multimedia
- * Copyright (C) <2010> Nokia Corporation
- *
- * Some bits C-c,C-v'ed and s/4/3 from h264parse:
- * (C) 2005 Michal Benes
- * (C) 2008 Wim Taymans
- *
- * 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 "h264parse.h"
-
-#include
-
-GST_DEBUG_CATEGORY_EXTERN (h264_parse_debug);
-#define GST_CAT_DEFAULT h264_parse_debug
-
-/* simple bitstream parser, automatically skips over
- * emulation_prevention_three_bytes. */
-typedef struct
-{
- const guint8 *orig_data;
- const guint8 *data;
- const guint8 *end;
- /* bitpos in the cache of next bit */
- gint head;
- /* cached bytes */
- guint64 cache;
-} GstNalBs;
-
-static void
-gst_nal_bs_init (GstNalBs * bs, const guint8 * data, guint size)
-{
- bs->orig_data = data;
- bs->data = data;
- bs->end = data + size;
- bs->head = 0;
- /* fill with something other than 0 to detect emulation prevention bytes */
- bs->cache = 0xffffffff;
-}
-
-static inline void
-gst_nal_bs_get_data (GstNalBs * bs, const guint8 ** data, guint * size)
-{
- *data = bs->orig_data;
- *size = bs->end - bs->orig_data;
-}
-
-static guint32
-gst_nal_bs_read (GstNalBs * bs, guint n)
-{
- guint32 res = 0;
- gint shift;
-
- if (n == 0)
- return res;
-
- /* fill up the cache if we need to */
- while (bs->head < n) {
- guint8 byte;
- gboolean check_three_byte;
-
- check_three_byte = TRUE;
- next_byte:
- if (bs->data >= bs->end) {
- /* we're at the end, can't produce more than head number of bits */
- n = bs->head;
- break;
- }
- /* get the byte, this can be an emulation_prevention_three_byte that we need
- * to ignore. */
- byte = *bs->data++;
- if (check_three_byte && byte == 0x03 && ((bs->cache & 0xffff) == 0)) {
- /* next byte goes unconditionally to the cache, even if it's 0x03 */
- check_three_byte = FALSE;
- goto next_byte;
- }
- /* shift bytes in cache, moving the head bits of the cache left */
- bs->cache = (bs->cache << 8) | byte;
- bs->head += 8;
- }
-
- /* bring the required bits down and truncate */
- if ((shift = bs->head - n) > 0)
- res = bs->cache >> shift;
- else
- res = bs->cache;
-
- /* mask out required bits */
- if (n < 32)
- res &= (1 << n) - 1;
-
- bs->head = shift;
-
- return res;
-}
-
-static gboolean
-gst_nal_bs_eos (GstNalBs * bs)
-{
- return (bs->data >= bs->end) && (bs->head == 0);
-}
-
-/* read unsigned Exp-Golomb code */
-static gint
-gst_nal_bs_read_ue (GstNalBs * bs)
-{
- gint i = 0;
-
- while (gst_nal_bs_read (bs, 1) == 0 && !gst_nal_bs_eos (bs) && i < 32)
- i++;
-
- return ((1 << i) - 1 + gst_nal_bs_read (bs, i));
-}
-
-/* read signed Exp-Golomb code */
-static gint
-gst_nal_bs_read_se (GstNalBs * bs)
-{
- gint i = 0;
-
- i = gst_nal_bs_read_ue (bs);
- /* (-1)^(i+1) Ceil (i / 2) */
- i = (i + 1) / 2 * (i & 1 ? 1 : -1);
-
- return i;
-}
-
-/* end parser helper */
-
-static void
-gst_h264_params_store_nal (GstH264Params * params, GstBuffer ** store,
- gint store_size, gint id, GstNalBs * bs)
-{
- const guint8 *data;
- GstBuffer *buf;
- guint size;
-
- if (id >= store_size) {
- GST_DEBUG_OBJECT (params->el,
- "unable to store nal, id out-of-range %d", id);
- return;
- }
-
- gst_nal_bs_get_data (bs, &data, &size);
- buf = gst_buffer_new_and_alloc (size);
- memcpy (GST_BUFFER_DATA (buf), data, size);
-
- if (store[id])
- gst_buffer_unref (store[id]);
-
- store[id] = buf;
-}
-
-static GstH264ParamsSPS *
-gst_h264_params_get_sps (GstH264Params * params, guint8 sps_id, gboolean set)
-{
- GstH264ParamsSPS *sps;
-
- g_return_val_if_fail (params != NULL, NULL);
-
- if (G_UNLIKELY (sps_id >= MAX_SPS_COUNT)) {
- GST_WARNING_OBJECT (params->el,
- "requested sps_id=%04x out of range", sps_id);
- return NULL;
- }
-
- sps = ¶ms->sps_buffers[sps_id];
- if (set) {
- if (sps->valid) {
- params->sps = sps;
- } else {
- GST_WARNING_OBJECT (params->el, "invalid sps not selected");
- params->sps = NULL;
- sps = NULL;
- }
- }
-
- return sps;
-}
-
-static GstH264ParamsPPS *
-gst_h264_params_get_pps (GstH264Params * params, guint8 pps_id, gboolean set)
-{
- GstH264ParamsPPS *pps;
-
- g_return_val_if_fail (params != NULL, NULL);
-
- pps = ¶ms->pps_buffers[pps_id];
- if (set) {
- if (pps->valid) {
- params->pps = pps;
- } else {
- GST_WARNING_OBJECT (params->el, "invalid pps not selected");
- params->pps = NULL;
- pps = NULL;
- }
- }
-
- return pps;
-}
-
-static gboolean
-gst_h264_params_decode_sps_vui_hrd (GstH264Params * params,
- GstH264ParamsSPS * sps, GstNalBs * bs)
-{
- gint sched_sel_idx;
-
- sps->cpb_cnt_minus1 = gst_nal_bs_read_ue (bs);
- if (sps->cpb_cnt_minus1 > 31U) {
- GST_WARNING_OBJECT (params->el, "cpb_cnt_minus1 = %d out of range",
- sps->cpb_cnt_minus1);
- return FALSE;
- }
-
- /* bit_rate_scale */
- gst_nal_bs_read (bs, 4);
- /* cpb_size_scale */
- gst_nal_bs_read (bs, 4);
-
- for (sched_sel_idx = 0; sched_sel_idx <= sps->cpb_cnt_minus1; sched_sel_idx++) {
- /* bit_rate_value_minus1 */
- gst_nal_bs_read_ue (bs);
- /* cpb_size_value_minus1 */
- gst_nal_bs_read_ue (bs);
- /* cbr_flag */
- gst_nal_bs_read (bs, 1);
- }
-
- sps->initial_cpb_removal_delay_length_minus1 = gst_nal_bs_read (bs, 5);
- sps->cpb_removal_delay_length_minus1 = gst_nal_bs_read (bs, 5);
- sps->dpb_output_delay_length_minus1 = gst_nal_bs_read (bs, 5);
- sps->time_offset_length_minus1 = gst_nal_bs_read (bs, 5);
-
- return TRUE;
-}
-
-static gboolean
-gst_h264_params_decode_sps_vui (GstH264Params * params, GstH264ParamsSPS * sps,
- GstNalBs * bs)
-{
- if (G_UNLIKELY (!sps))
- return FALSE;
-
- /* aspect_ratio_info_present_flag */
- if (gst_nal_bs_read (bs, 1)) {
- /* aspect_ratio_idc */
- if (gst_nal_bs_read (bs, 8) == 255) {
- /* Extended_SAR */
- /* sar_width */
- gst_nal_bs_read (bs, 16);
- /* sar_height */
- gst_nal_bs_read (bs, 16);
- }
- }
-
- /* overscan_info_present_flag */
- if (gst_nal_bs_read (bs, 1)) {
- /* overscan_appropriate_flag */
- gst_nal_bs_read (bs, 1);
- }
-
- /* video_signal_type_present_flag */
- if (gst_nal_bs_read (bs, 1)) {
- /* video_format */
- gst_nal_bs_read (bs, 3);
- /* video_full_range_flag */
- gst_nal_bs_read (bs, 1);
-
- /* colour_description_present_flag */
- if (gst_nal_bs_read (bs, 1)) {
- /* colour_primaries */
- gst_nal_bs_read (bs, 8);
- /* transfer_characteristics */
- gst_nal_bs_read (bs, 8);
- /* matrix_coefficients */
- gst_nal_bs_read (bs, 8);
- }
- }
-
- /* chroma_loc_info_present_flag */
- if (gst_nal_bs_read (bs, 1)) {
- /* chroma_sample_loc_type_top_field */
- gst_nal_bs_read_ue (bs);
- /* chroma_sample_loc_type_bottom_field */
- gst_nal_bs_read_ue (bs);
- }
-
- sps->timing_info_present_flag = gst_nal_bs_read (bs, 1);
- if (sps->timing_info_present_flag) {
- guint32 num_units_in_tick = gst_nal_bs_read (bs, 32);
- guint32 time_scale = gst_nal_bs_read (bs, 32);
-
- /* If any of these parameters = 0, discard all timing_info */
- if (time_scale == 0) {
- GST_WARNING_OBJECT (params->el,
- "time_scale = 0 detected in stream (incompliant to H.264 E.2.1)."
- " Discarding related info.");
- } else if (num_units_in_tick == 0) {
- GST_WARNING_OBJECT (params->el,
- "num_units_in_tick = 0 detected in stream (incompliant to H.264 E.2.1)."
- " Discarding related info.");
- } else {
- sps->num_units_in_tick = num_units_in_tick;
- sps->time_scale = time_scale;
- sps->fixed_frame_rate_flag = gst_nal_bs_read (bs, 1);
- GST_LOG_OBJECT (params->el, "timing info: dur=%d/%d fixed=%d",
- num_units_in_tick, time_scale, sps->fixed_frame_rate_flag);
- }
- }
-
- sps->nal_hrd_parameters_present_flag = gst_nal_bs_read (bs, 1);
- if (sps->nal_hrd_parameters_present_flag) {
- gst_h264_params_decode_sps_vui_hrd (params, sps, bs);
- }
- sps->vcl_hrd_parameters_present_flag = gst_nal_bs_read (bs, 1);
- if (sps->vcl_hrd_parameters_present_flag) {
- gst_h264_params_decode_sps_vui_hrd (params, sps, bs);
- }
- if (sps->nal_hrd_parameters_present_flag
- || sps->vcl_hrd_parameters_present_flag) {
- gst_nal_bs_read (bs, 1); /* low_delay_hrd_flag */
- }
-
- sps->pic_struct_present_flag = gst_nal_bs_read (bs, 1);
-
- /* derive framerate */
- /* FIXME verify / also handle other cases */
- if (sps->fixed_frame_rate_flag && sps->frame_mbs_only_flag &&
- !sps->pic_struct_present_flag) {
- sps->fps_num = sps->time_scale;
- sps->fps_den = sps->num_units_in_tick;
- /* picture is a frame = 2 fields */
- sps->fps_den *= 2;
- GST_LOG_OBJECT (params->el, "framerate %d/%d", sps->fps_num, sps->fps_den);
- }
-
- return TRUE;
-}
-
-static gboolean
-gst_h264_params_decode_sps (GstH264Params * params, GstNalBs * bs)
-{
- guint8 profile_idc, level_idc;
- guint8 sps_id;
- GstH264ParamsSPS *sps = NULL;
- guint subwc[] = { 1, 2, 2, 1 };
- guint subhc[] = { 1, 2, 1, 1 };
- guint chroma;
- guint fc_top, fc_bottom, fc_left, fc_right;
- gint width, height;
-
- profile_idc = gst_nal_bs_read (bs, 8);
- /* constraint_set0_flag */
- gst_nal_bs_read (bs, 1);
- /* constraint_set1_flag */
- gst_nal_bs_read (bs, 1);
- /* constraint_set1_flag */
- gst_nal_bs_read (bs, 1);
- /* constraint_set1_flag */
- gst_nal_bs_read (bs, 1);
- /* reserved */
- gst_nal_bs_read (bs, 4);
- level_idc = gst_nal_bs_read (bs, 8);
-
- sps_id = gst_nal_bs_read_ue (bs);
- sps = gst_h264_params_get_sps (params, sps_id, FALSE);
- if (G_UNLIKELY (sps == NULL))
- return FALSE;
-
- gst_h264_params_store_nal (params, params->sps_nals, MAX_SPS_COUNT, sps_id,
- bs);
-
- /* could be redefined mid stream, arrange for clear state */
- memset (sps, 0, sizeof (*sps));
-
- GST_LOG_OBJECT (params->el, "sps id %d", sps_id);
- sps->valid = TRUE;
- /* validate and force activate this one if it is the first SPS we see */
- if (params->sps == NULL)
- params->sps = sps;
-
- sps->profile_idc = profile_idc;
- sps->level_idc = level_idc;
-
- if (profile_idc == 100 || profile_idc == 110 || profile_idc == 122
- || profile_idc == 244 || profile_idc == 44 ||
- profile_idc == 83 || profile_idc == 86) {
- gint scp_flag = 0;
-
- /* chroma_format_idc */
- if ((chroma = gst_nal_bs_read_ue (bs)) == 3) {
- /* separate_colour_plane_flag */
- sps->scp_flag = gst_nal_bs_read (bs, 1);
- }
- /* bit_depth_luma_minus8 */
- gst_nal_bs_read_ue (bs);
- /* bit_depth_chroma_minus8 */
- gst_nal_bs_read_ue (bs);
- /* qpprime_y_zero_transform_bypass_flag */
- gst_nal_bs_read (bs, 1);
- /* seq_scaling_matrix_present_flag */
- if (gst_nal_bs_read (bs, 1)) {
- gint i, j, m, d;
-
- m = (chroma != 3) ? 8 : 12;
- for (i = 0; i < m; i++) {
- /* seq_scaling_list_present_flag[i] */
- d = gst_nal_bs_read (bs, 1);
- if (d) {
- gint lastScale = 8, nextScale = 8, deltaScale;
-
- j = (i < 6) ? 16 : 64;
- for (; j > 0; j--) {
- if (nextScale != 0) {
- deltaScale = gst_nal_bs_read_se (bs);
- nextScale = (lastScale + deltaScale + 256) % 256;
- }
- if (nextScale != 0)
- lastScale = nextScale;
- }
- }
- }
- }
- if (scp_flag)
- chroma = 0;
- } else {
- /* inferred value */
- chroma = 1;
- }
-
- /* between 0 and 12 */
- sps->log2_max_frame_num_minus4 = gst_nal_bs_read_ue (bs);
- if (sps->log2_max_frame_num_minus4 > 12) {
- GST_WARNING_OBJECT (params->el,
- "log2_max_frame_num_minus4 = %d out of range" " [0,12]",
- sps->log2_max_frame_num_minus4);
- return FALSE;
- }
-
- sps->pic_order_cnt_type = gst_nal_bs_read_ue (bs);
- if (sps->pic_order_cnt_type == 0) {
- sps->log2_max_pic_order_cnt_lsb_minus4 = gst_nal_bs_read_ue (bs);
- } else if (sps->pic_order_cnt_type == 1) {
- gint d;
-
- /* delta_pic_order_always_zero_flag */
- gst_nal_bs_read (bs, 1);
- /* offset_for_non_ref_pic */
- gst_nal_bs_read_ue (bs);
- /* offset_for_top_to_bottom_field */
- gst_nal_bs_read_ue (bs);
- /* num_ref_frames_in_pic_order_cnt_cycle */
- d = gst_nal_bs_read_ue (bs);
- for (; d > 0; d--) {
- /* offset_for_ref_frame[i] */
- gst_nal_bs_read_ue (bs);
- }
- }
-
- /* max_num_ref_frames */
- gst_nal_bs_read_ue (bs);
- /* gaps_in_frame_num_value_allowed_flag */
- gst_nal_bs_read (bs, 1);
- /* pic_width_in_mbs_minus1 */
- width = gst_nal_bs_read_ue (bs);
- /* pic_height_in_map_units_minus1 */
- height = gst_nal_bs_read_ue (bs);
-
- sps->frame_mbs_only_flag = gst_nal_bs_read (bs, 1);
- if (!sps->frame_mbs_only_flag) {
- /* mb_adaptive_frame_field_flag */
- gst_nal_bs_read (bs, 1);
- }
-
- width++;
- width *= 16;
- height++;
- height *= 16 * (2 - sps->frame_mbs_only_flag);
-
- /* direct_8x8_inference_flag */
- gst_nal_bs_read (bs, 1);
- /* frame_cropping_flag */
- if (gst_nal_bs_read (bs, 1)) {
- /* frame_crop_left_offset */
- fc_left = gst_nal_bs_read_ue (bs);
- /* frame_crop_right_offset */
- fc_right = gst_nal_bs_read_ue (bs);
- /* frame_crop_top_offset */
- fc_top = gst_nal_bs_read_ue (bs);
- /* frame_crop_bottom_offset */
- fc_bottom = gst_nal_bs_read_ue (bs);
- } else {
- fc_left = fc_right = fc_top = fc_bottom = 0;
- }
-
- GST_LOG_OBJECT (params->el, "decoding SPS: profile_idc = %d, "
- "level_idc = %d, sps_id = %d, pic_order_cnt_type = %d, "
- "frame_mbs_only_flag = %d",
- sps->profile_idc, sps->level_idc, sps_id, sps->pic_order_cnt_type,
- sps->frame_mbs_only_flag);
-
- /* calculate width and height */
- GST_LOG_OBJECT (params->el, "initial width=%d, height=%d", width, height);
- GST_LOG_OBJECT (params->el, "crop (%d,%d)(%d,%d)",
- fc_left, fc_top, fc_right, fc_bottom);
- if (chroma > 3) {
- GST_LOG_OBJECT (params->el, "chroma=%d in SPS is out of range", chroma);
- return FALSE;
- }
- width -= (fc_left + fc_right) * subwc[chroma];
- height -=
- (fc_top + fc_bottom) * subhc[chroma] * (2 - sps->frame_mbs_only_flag);
- if (width < 0 || height < 0) {
- GST_WARNING_OBJECT (params->el, "invalid width/height in SPS");
- return FALSE;
- }
- GST_LOG_OBJECT (params->el, "final width=%u, height=%u", width, height);
- sps->width = width;
- sps->height = height;
-
- sps->vui_parameters_present_flag = gst_nal_bs_read (bs, 1);
- if (sps->vui_parameters_present_flag) {
- /* discard parsing problem */
- gst_h264_params_decode_sps_vui (params, sps, bs);
- }
-
- return TRUE;
-}
-
-static gboolean
-gst_h264_params_decode_pps (GstH264Params * params, GstNalBs * bs)
-{
- gint pps_id;
- GstH264ParamsPPS *pps = NULL;
-
- pps_id = gst_nal_bs_read_ue (bs);
- if (G_UNLIKELY (pps_id >= MAX_PPS_COUNT)) {
- GST_WARNING_OBJECT (params->el,
- "requested pps_id=%04x out of range", pps_id);
- return FALSE;
- }
-
-
- pps = gst_h264_params_get_pps (params, pps_id, FALSE);
- if (G_UNLIKELY (pps == NULL))
- return FALSE;
-
- /* validate and set */
- pps->valid = TRUE;
- params->pps = pps;
-
- gst_h264_params_store_nal (params, params->pps_nals, MAX_PPS_COUNT, pps_id,
- bs);
-
- pps->sps_id = gst_nal_bs_read_ue (bs);
- GST_LOG_OBJECT (params->el, "pps %d referencing sps %d", pps_id, pps->sps_id);
-
- /* activate referenced sps */
- if (!gst_h264_params_get_sps (params, pps->sps_id, TRUE))
- return FALSE;
-
- /* not parsing the rest for the time being */
- return TRUE;
-}
-
-static gboolean
-gst_h264_params_decode_sei_buffering_period (GstH264Params * params,
- GstNalBs * bs)
-{
-#ifdef EXTRA_PARSE
- guint8 sps_id;
- gint sched_sel_idx;
- GstH264ParamsSPS *sps;
-
- sps_id = gst_nal_bs_read_ue (bs);
- sps = gst_h264_params_get_sps (params, sps_id, TRUE);
- if (G_UNLIKELY (sps == NULL))
- return FALSE;
-
- if (sps->nal_hrd_parameters_present_flag) {
- for (sched_sel_idx = 0; sched_sel_idx <= sps->cpb_cnt_minus1;
- sched_sel_idx++) {
- params->initial_cpb_removal_delay[sched_sel_idx]
- = gst_nal_bs_read (bs,
- sps->initial_cpb_removal_delay_length_minus1 + 1);
- /* initial_cpb_removal_delay_offset */
- gst_nal_bs_read (bs, sps->initial_cpb_removal_delay_length_minus1 + 1);
- }
- }
-
- if (sps->vcl_hrd_parameters_present_flag) {
- for (sched_sel_idx = 0; sched_sel_idx <= sps->cpb_cnt_minus1;
- sched_sel_idx++) {
- params->initial_cpb_removal_delay[sched_sel_idx]
- = gst_nal_bs_read (bs,
- sps->initial_cpb_removal_delay_length_minus1 + 1);
- /* initial_cpb_removal_delay_offset */
- gst_nal_bs_read (bs, sps->initial_cpb_removal_delay_length_minus1 + 1);
- }
- }
-#endif
-
- if (params->ts_trn_nb == GST_CLOCK_TIME_NONE ||
- params->dts == GST_CLOCK_TIME_NONE)
- params->ts_trn_nb = 0;
- else
- params->ts_trn_nb = params->dts;
-
- GST_LOG_OBJECT (params->el,
- "new buffering period; ts_trn_nb updated: %" GST_TIME_FORMAT,
- GST_TIME_ARGS (params->ts_trn_nb));
-
- return 0;
-}
-
-static gboolean
-gst_h264_params_decode_sei_picture_timing (GstH264Params * params,
- GstNalBs * bs)
-{
- GstH264ParamsSPS *sps = params->sps;
-
- if (sps == NULL) {
- GST_WARNING_OBJECT (params->el,
- "SPS == NULL; delayed decoding of picture timing info not implemented ");
- return FALSE;
- }
-
- if (sps->nal_hrd_parameters_present_flag
- || sps->vcl_hrd_parameters_present_flag) {
- params->sei_cpb_removal_delay =
- gst_nal_bs_read (bs, sps->cpb_removal_delay_length_minus1 + 1);
- /* sei_dpb_output_delay */
- gst_nal_bs_read (bs, sps->dpb_output_delay_length_minus1 + 1);
- }
-
- if (sps->pic_struct_present_flag) {
-#ifdef EXTRA_PARSE
- /* pic_struct to NumClockTS lookup table */
- static const guint8 sei_num_clock_ts_table[9] =
- { 1, 1, 1, 2, 2, 3, 3, 2, 3 };
- guint i, num_clock_ts;
- guint sei_ct_type = 0;
-#endif
-
- params->sei_pic_struct = gst_nal_bs_read (bs, 4);
- GST_LOG_OBJECT (params, "pic_struct:%d", params->sei_pic_struct);
- if (params->sei_pic_struct > SEI_PIC_STRUCT_FRAME_TRIPLING)
- return FALSE;
-
-#ifdef EXTRA_PARSE
- num_clock_ts = sei_num_clock_ts_table[params->sei_pic_struct];
-
- for (i = 0; i < num_clock_ts; i++) {
- /* clock_timestamp_flag */
- if (gst_nal_bs_read (bs, 1)) {
- guint full_timestamp_flag;
-
- sei_ct_type |= 1 << gst_nal_bs_read (bs, 2);
- /* nuit_field_based_flag */
- gst_nal_bs_read (bs, 1);
- /* counting_type */
- gst_nal_bs_read (bs, 5);
- full_timestamp_flag = gst_nal_bs_read (bs, 1);
- /* discontinuity_flag */
- gst_nal_bs_read (bs, 1);
- /* cnt_dropped_flag */
- gst_nal_bs_read (bs, 1);
- /* n_frames */
- gst_nal_bs_read (bs, 8);
- if (full_timestamp_flag) {
- /* seconds_value 0..59 */
- gst_nal_bs_read (bs, 6);
- /* minutes_value 0..59 */
- gst_nal_bs_read (bs, 6);
- /* hours_value 0..23 */
- gst_nal_bs_read (bs, 5);
- } else {
- /* seconds_flag */
- if (gst_nal_bs_read (bs, 1)) {
- /* seconds_value range 0..59 */
- gst_nal_bs_read (bs, 6);
- /* minutes_flag */
- if (gst_nal_bs_read (bs, 1)) {
- /* minutes_value 0..59 */
- gst_nal_bs_read (bs, 6);
- /* hours_flag */
- if (gst_nal_bs_read (bs, 1))
- /* hours_value 0..23 */
- gst_nal_bs_read (bs, 5);
- }
- }
- }
- if (sps->time_offset_length_minus1 >= 0) {
- /* time_offset */
- gst_nal_bs_read (bs, sps->time_offset_length_minus1 + 1);
- }
- }
- }
-
- GST_LOG_OBJECT (params, "ct_type:%X", sei_ct_type);
-#endif
- }
-
- return TRUE;
-}
-
-static gboolean
-gst_h264_params_decode_sei (GstH264Params * params, GstNalBs * bs)
-{
- guint8 tmp;
- GstH264ParamsSEIPayloadType payloadType = 0;
- gint8 payloadSize = 0;
-
- do {
- tmp = gst_nal_bs_read (bs, 8);
- payloadType += tmp;
- } while (tmp == 255);
- do {
- tmp = gst_nal_bs_read (bs, 8);
- payloadSize += tmp;
- } while (tmp == 255);
-
- GST_LOG_OBJECT (params->el,
- "SEI message received: payloadType = %d, payloadSize = %d bytes",
- payloadType, payloadSize);
-
- switch (payloadType) {
- case SEI_BUF_PERIOD:
- if (!gst_h264_params_decode_sei_buffering_period (params, bs))
- return FALSE;
- break;
- case SEI_PIC_TIMING:
- /* TODO: According to H264 D2.2 Note1, it might be the case that the
- * picture timing SEI message is encountered before the corresponding SPS
- * is specified. Need to hold down the message and decode it later. */
- if (!gst_h264_params_decode_sei_picture_timing (params, bs))
- return FALSE;
- break;
- default:
- GST_LOG_OBJECT (params->el,
- "SEI message of payloadType = %d is received but not parsed",
- payloadType);
- break;
- }
-
- return TRUE;
-}
-
-static gboolean
-gst_h264_params_decode_slice_header (GstH264Params * params, GstNalBs * bs)
-{
- GstH264ParamsSPS *sps;
- GstH264ParamsPPS *pps;
- guint8 pps_id;
-
- params->first_mb_in_slice = gst_nal_bs_read_ue (bs);
- params->slice_type = gst_nal_bs_read_ue (bs);
-
- pps_id = gst_nal_bs_read_ue (bs);
- GST_LOG_OBJECT (params->el, "slice header references pps id %d", pps_id);
- pps = gst_h264_params_get_pps (params, pps_id, TRUE);
- if (G_UNLIKELY (pps == NULL))
- return FALSE;
- sps = gst_h264_params_get_sps (params, pps->sps_id, TRUE);
- if (G_UNLIKELY (sps == NULL))
- return FALSE;
-
- if (sps->scp_flag) {
- /* colour_plane_id */
- gst_nal_bs_read (bs, 2);
- }
-
- /* frame num */
- gst_nal_bs_read (bs, sps->log2_max_pic_order_cnt_lsb_minus4 + 4);
-
- if (!sps->frame_mbs_only_flag) {
- params->field_pic_flag = gst_nal_bs_read (bs, 1);
- if (params->field_pic_flag)
- params->bottom_field_flag = gst_nal_bs_read (bs, 1);
- }
-
- /* not parsing the rest for the time being */
- return TRUE;
-}
-
-/* only payload in @data */
-gboolean
-gst_h264_params_parse_nal (GstH264Params * params, guint8 * data, gint size)
-{
- GstH264ParamsNalUnitType nal_type;
- GstNalBs bs;
- gint nal_ref_idc;
- gboolean res = TRUE;
-
- g_return_val_if_fail (params != NULL, FALSE);
- g_return_val_if_fail (data != NULL, FALSE);
- g_return_val_if_fail (size != 0, FALSE);
-
- nal_type = (data[0] & 0x1f);
- nal_ref_idc = (data[0] & 0x60) >> 5;
-
- GST_LOG_OBJECT (params->el, "NAL type: %d, ref_idc: %d", nal_type,
- nal_ref_idc);
-
- gst_nal_bs_init (&bs, data + 1, size - 1);
- /* optimality HACK */
- bs.orig_data = data;
-
- /* first parse some things needed to get to the frame type */
- switch (nal_type) {
- case NAL_SLICE:
- case NAL_SLICE_DPA:
- case NAL_SLICE_DPB:
- case NAL_SLICE_DPC:
- case NAL_SLICE_IDR:
- {
- gint first_mb_in_slice, slice_type;
-
- gst_h264_params_decode_slice_header (params, &bs);
- first_mb_in_slice = params->first_mb_in_slice;
- slice_type = params->slice_type;
-
- GST_LOG_OBJECT (params->el, "first MB: %d, slice type: %d",
- first_mb_in_slice, slice_type);
-
- switch (slice_type) {
- case 0:
- case 5:
- case 3:
- case 8: /* SP */
- /* P frames */
- GST_LOG_OBJECT (params->el, "we have a P slice");
- break;
- case 1:
- case 6:
- /* B frames */
- GST_LOG_OBJECT (params->el, "we have a B slice");
- break;
- case 2:
- case 7:
- case 4:
- case 9:
- /* I frames */
- GST_LOG_OBJECT (params->el, "we have an I slice");
- break;
- }
- break;
- }
- case NAL_SEI:
- GST_LOG_OBJECT (params->el, "SEI NAL");
- res = gst_h264_params_decode_sei (params, &bs);
- break;
- case NAL_SPS:
- GST_LOG_OBJECT (params->el, "SPS NAL");
- res = gst_h264_params_decode_sps (params, &bs);
- break;
- case NAL_PPS:
- GST_LOG_OBJECT (params->el, "PPS NAL");
- res = gst_h264_params_decode_pps (params, &bs);
- break;
- case NAL_AU_DELIMITER:
- GST_LOG_OBJECT (params->el, "AU delimiter NAL");
- break;
- default:
- GST_LOG_OBJECT (params->el, "unparsed NAL");
- break;
- }
-
- return res;
-}
-
-void
-gst_h264_params_get_timestamp (GstH264Params * params,
- GstClockTime * out_ts, GstClockTime * out_dur, gboolean frame)
-{
- GstH264ParamsSPS *sps = params->sps;
- GstClockTime upstream;
- gint duration = 1;
-
- g_return_if_fail (out_dur != NULL);
- g_return_if_fail (out_ts != NULL);
-
- upstream = *out_ts;
-
- if (!frame) {
- GST_LOG_OBJECT (params->el, "no frame data -> 0 duration");
- *out_dur = 0;
- goto exit;
- } else {
- *out_ts = upstream;
- }
-
- if (!sps) {
- GST_DEBUG_OBJECT (params->el, "referred SPS invalid");
- goto exit;
- } else if (!sps->timing_info_present_flag) {
- GST_DEBUG_OBJECT (params->el,
- "unable to compute timestamp: timing info not present");
- goto exit;
- } else if (sps->time_scale == 0) {
- GST_DEBUG_OBJECT (params->el,
- "unable to compute timestamp: time_scale = 0 "
- "(this is forbidden in spec; bitstream probably contains error)");
- goto exit;
- }
-
- if (sps->pic_struct_present_flag && params->sei_pic_struct != (guint8) - 1) {
- /* Note that when h264parse->sei_pic_struct == -1 (unspecified), there
- * are ways to infer its value. This is related to computing the
- * TopFieldOrderCnt and BottomFieldOrderCnt, which looks
- * complicated and thus not implemented for the time being. Yet
- * the value we have here is correct for many applications
- */
- switch (params->sei_pic_struct) {
- case SEI_PIC_STRUCT_TOP_FIELD:
- case SEI_PIC_STRUCT_BOTTOM_FIELD:
- duration = 1;
- break;
- case SEI_PIC_STRUCT_FRAME:
- case SEI_PIC_STRUCT_TOP_BOTTOM:
- case SEI_PIC_STRUCT_BOTTOM_TOP:
- duration = 2;
- break;
- case SEI_PIC_STRUCT_TOP_BOTTOM_TOP:
- case SEI_PIC_STRUCT_BOTTOM_TOP_BOTTOM:
- duration = 3;
- break;
- case SEI_PIC_STRUCT_FRAME_DOUBLING:
- duration = 4;
- break;
- case SEI_PIC_STRUCT_FRAME_TRIPLING:
- duration = 6;
- break;
- default:
- GST_DEBUG_OBJECT (params,
- "h264parse->sei_pic_struct of unknown value %d. Not parsed",
- params->sei_pic_struct);
- break;
- }
- } else {
- duration = params->field_pic_flag ? 1 : 2;
- }
-
- GST_LOG_OBJECT (params->el, "frame tick duration %d", duration);
-
- /*
- * h264parse.264 C.1.2 Timing of coded picture removal (equivalent to DTS):
- * Tr,n(0) = initial_cpb_removal_delay[ SchedSelIdx ] / 90000
- * Tr,n(n) = Tr,n(nb) + Tc * cpb_removal_delay(n)
- * where
- * Tc = num_units_in_tick / time_scale
- */
-
- if (params->ts_trn_nb != GST_CLOCK_TIME_NONE) {
- GST_LOG_OBJECT (params->el, "buffering based ts");
- /* buffering period is present */
- if (upstream != GST_CLOCK_TIME_NONE) {
- /* If upstream timestamp is valid, we respect it and adjust current
- * reference point */
- params->ts_trn_nb = upstream -
- (GstClockTime) gst_util_uint64_scale_int
- (params->sei_cpb_removal_delay * GST_SECOND,
- sps->num_units_in_tick, sps->time_scale);
- } else {
- /* If no upstream timestamp is given, we write in new timestamp */
- upstream = params->dts = params->ts_trn_nb +
- (GstClockTime) gst_util_uint64_scale_int
- (params->sei_cpb_removal_delay * GST_SECOND,
- sps->num_units_in_tick, sps->time_scale);
- }
- } else {
- GstClockTime dur;
-
- GST_LOG_OBJECT (params->el, "duration based ts");
- /* naive method: no removal delay specified
- * track upstream timestamp and provide best guess frame duration */
- dur = gst_util_uint64_scale_int (duration * GST_SECOND,
- sps->num_units_in_tick, sps->time_scale);
- /* sanity check */
- if (dur < GST_MSECOND) {
- GST_DEBUG_OBJECT (params->el, "discarding dur %" GST_TIME_FORMAT,
- GST_TIME_ARGS (dur));
- } else {
- *out_dur = dur;
- }
- }
-
-exit:
- if (GST_CLOCK_TIME_IS_VALID (upstream))
- *out_ts = params->dts = upstream;
-
- if (GST_CLOCK_TIME_IS_VALID (*out_dur) &&
- GST_CLOCK_TIME_IS_VALID (params->dts))
- params->dts += *out_dur;
-}
-
-void
-gst_h264_params_create (GstH264Params ** _params, GstElement * element)
-{
- GstH264Params *params;
-
- g_return_if_fail (_params != NULL);
-
- params = g_new0 (GstH264Params, 1);
- params->el = element;
-
- params->dts = GST_CLOCK_TIME_NONE;
- params->ts_trn_nb = GST_CLOCK_TIME_NONE;
-
- *_params = params;
-}
-
-void
-gst_h264_params_free (GstH264Params * params)
-{
- gint i;
-
- g_return_if_fail (params != NULL);
-
- for (i = 0; i < MAX_SPS_COUNT; i++)
- gst_buffer_replace (¶ms->sps_nals[i], NULL);
- for (i = 0; i < MAX_PPS_COUNT; i++)
- gst_buffer_replace (¶ms->pps_nals[i], NULL);
-
- g_free (params);
-}
diff --git a/gst/videoparsers/h264parse.h b/gst/videoparsers/h264parse.h
deleted file mode 100644
index 517c8542b2..0000000000
--- a/gst/videoparsers/h264parse.h
+++ /dev/null
@@ -1,186 +0,0 @@
-/* GStreamer H.264 Parser
- * Copyright (C) <2010> Mark Nauwelaerts
- * Copyright (C) <2010> Collabora Multimedia
- * Copyright (C) <2010> Nokia Corporation
- *
- * Some bits C-c,C-v'ed and s/4/3 from h264parse:
- * (C) 2005 Michal Benes
- * (C) 2008 Wim Taymans
- *
- * 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_H264_PARAMS_H__
-#define __GST_H264_PARAMS_H__
-
-#include
-
-G_BEGIN_DECLS
-
-typedef enum
-{
- NAL_UNKNOWN = 0,
- NAL_SLICE = 1,
- NAL_SLICE_DPA = 2,
- NAL_SLICE_DPB = 3,
- NAL_SLICE_DPC = 4,
- NAL_SLICE_IDR = 5,
- NAL_SEI = 6,
- NAL_SPS = 7,
- NAL_PPS = 8,
- NAL_AU_DELIMITER = 9,
- NAL_SEQ_END = 10,
- NAL_STREAM_END = 11,
- NAL_FILTER_DATA = 12
-} GstH264ParamsNalUnitType;
-
-/* SEI type */
-typedef enum
-{
- SEI_BUF_PERIOD = 0,
- SEI_PIC_TIMING = 1
- /* and more... */
-} GstH264ParamsSEIPayloadType;
-
-/* SEI pic_struct type */
-typedef enum
-{
- SEI_PIC_STRUCT_FRAME = 0,
- SEI_PIC_STRUCT_TOP_FIELD = 1,
- SEI_PIC_STRUCT_BOTTOM_FIELD = 2,
- SEI_PIC_STRUCT_TOP_BOTTOM = 3,
- SEI_PIC_STRUCT_BOTTOM_TOP = 4,
- SEI_PIC_STRUCT_TOP_BOTTOM_TOP = 5,
- SEI_PIC_STRUCT_BOTTOM_TOP_BOTTOM = 6,
- SEI_PIC_STRUCT_FRAME_DOUBLING = 7,
- SEI_PIC_STRUCT_FRAME_TRIPLING = 8
-} GstH264ParamsSEIPicStructType;
-
-typedef struct _GstH264Params GstH264Params;
-typedef struct _GstH264ParamsSPS GstH264ParamsSPS;
-typedef struct _GstH264ParamsPPS GstH264ParamsPPS;
-
-#define MAX_SPS_COUNT 32
-#define MAX_PPS_COUNT 256
-
-/* SPS: sequential parameter sets */
-struct _GstH264ParamsSPS
-{
- gboolean valid;
-
- /* raw values */
- guint8 profile_idc;
- guint8 level_idc;
-
- guint8 sps_id;
-
- guint8 pic_order_cnt_type;
-
- guint8 log2_max_frame_num_minus4;
- gboolean frame_mbs_only_flag;
- guint8 log2_max_pic_order_cnt_lsb_minus4;
-
- gboolean frame_cropping_flag;
- gboolean scp_flag;
-
- /* VUI parameters */
- gboolean vui_parameters_present_flag;
-
- gboolean timing_info_present_flag;
- guint32 num_units_in_tick;
- guint32 time_scale;
- gboolean fixed_frame_rate_flag;
-
- gboolean nal_hrd_parameters_present_flag;
- gboolean vcl_hrd_parameters_present_flag;
-
- /* hrd parameters */
- guint8 cpb_cnt_minus1;
- gint initial_cpb_removal_delay_length_minus1;
- gint cpb_removal_delay_length_minus1;
- gint dpb_output_delay_length_minus1;
- gboolean time_offset_length_minus1;
-
- gboolean pic_struct_present_flag;
-
- /* ... and probably more ... */
-
- /* derived values */
- gint width, height;
- gint fps_num, fps_den;
-};
-
-/* PPS: pic parameter sets */
-struct _GstH264ParamsPPS
-{
- gboolean valid;
-
- /* raw values */
- guint8 pps_id;
- guint8 sps_id;
-};
-
-struct _GstH264Params
-{
- /* debug purposes */
- GstElement *el;
-
- /* SPS: sequential parameter set */
- GstH264ParamsSPS sps_buffers[MAX_SPS_COUNT];
- /* current SPS; most recent one in stream or referenced by PPS */
- GstH264ParamsSPS *sps;
- /* PPS: sequential parameter set */
- GstH264ParamsPPS pps_buffers[MAX_PPS_COUNT];
- /* current PPS; most recent one in stream */
- GstH264ParamsPPS *pps;
-
- /* extracted from slice header or otherwise relevant nal */
- guint8 first_mb_in_slice;
- guint8 slice_type;
- gboolean field_pic_flag;
- gboolean bottom_field_flag;
-
- /* SEI: supplemental enhancement messages */
-#ifdef EXTRA_PARSE
- /* buffering period */
- guint32 initial_cpb_removal_delay[32];
-#endif
- /* picture timing */
- guint32 sei_cpb_removal_delay;
- guint8 sei_pic_struct;
- /* And more... */
-
- /* cached timestamps */
- /* (trying to) track upstream dts and interpolate */
- GstClockTime dts;
- /* dts at start of last buffering period */
- GstClockTime ts_trn_nb;
-
- /* collected SPS and PPS NALUs */
- GstBuffer *sps_nals[MAX_SPS_COUNT];
- GstBuffer *pps_nals[MAX_PPS_COUNT];
-};
-
-gboolean gst_h264_params_parse_nal (GstH264Params * params, guint8 * nal, gint size);
-void gst_h264_params_get_timestamp (GstH264Params * params,
- GstClockTime * out_ts, GstClockTime * out_dur,
- gboolean frame);
-void gst_h264_params_create (GstH264Params ** _params, GstElement * element);
-void gst_h264_params_free (GstH264Params * params);
-
-
-G_END_DECLS
-#endif
diff --git a/gst/videoparsers/mpegvideoparse.c b/gst/videoparsers/mpegvideoparse.c
deleted file mode 100644
index e85d77bdbb..0000000000
--- a/gst/videoparsers/mpegvideoparse.c
+++ /dev/null
@@ -1,274 +0,0 @@
-/* GStreamer
- * Copyright (C) <2007> Jan Schmidt
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
- */
-
-#ifdef HAVE_CONFIG_H
-# include "config.h"
-#endif
-
-#include "mpegvideoparse.h"
-
-#include
-#include
-
-GST_DEBUG_CATEGORY_EXTERN (mpegv_parse_debug);
-#define GST_CAT_DEFAULT mpegv_parse_debug
-
-
-#define GET_BITS(b, num, bits) G_STMT_START { \
- if (!gst_bit_reader_get_bits_uint32(b, bits, num)) \
- goto failed; \
- GST_TRACE ("parsed %d bits: %d", num, *(bits)); \
-} G_STMT_END
-
-#define MARKER_BIT(b) G_STMT_START { \
- guint32 i; \
- GET_BITS(b, 1, &i); \
- if (i != 0x1) \
- goto failed; \
-} G_STMT_END
-
-static inline gboolean
-find_start_code (GstBitReader * b)
-{
- guint32 bits;
-
- /* 0 bits until byte aligned */
- while (b->bit != 0) {
- GET_BITS (b, 1, &bits);
- }
-
- /* 0 bytes until startcode */
- while (gst_bit_reader_peek_bits_uint32 (b, &bits, 32)) {
- if (bits >> 8 == 0x1) {
- return TRUE;
- } else {
- gst_bit_reader_skip (b, 8);
- }
- }
-
- return FALSE;
-
-failed:
- return FALSE;
-}
-
-static gboolean
-gst_mpeg_video_params_parse_extension (MPEGVParams * params, GstBitReader * br)
-{
- guint32 bits;
-
- /* double-check */
- GET_BITS (br, 32, &bits);
- if (bits != 0x100 + MPEG_PACKET_EXTENSION)
- goto failed;
-
- /* extension_start_code identifier */
- GET_BITS (br, 4, &bits);
-
- /* profile_and_level_indication */
- GET_BITS (br, 4, &bits);
- params->profile = bits;
- GET_BITS (br, 4, &bits);
- params->level = bits;
-
- /* progressive_sequence */
- GET_BITS (br, 1, &bits);
- params->progressive = bits;
-
- /* chroma_format */
- GET_BITS (br, 2, &bits);
-
- /* horizontal_size_extension */
- GET_BITS (br, 2, &bits);
- params->width += (bits << 12);
- /* vertical_size_extension */
- GET_BITS (br, 2, &bits);
- params->height += (bits << 12);
-
- /* bit_rate_extension */
- GET_BITS (br, 12, &bits);
- if (params->bitrate)
- params->bitrate += (bits << 18) * 400;
- /* marker_bit */
- MARKER_BIT (br);
- /* vbv_buffer_size_extension */
- GET_BITS (br, 8, &bits);
- /* low_delay */
- GET_BITS (br, 1, &bits);
-
- /* frame_rate_extension_n */
- GET_BITS (br, 2, &bits);
- params->fps_n *= bits + 1;
- /* frame_rate_extension_d */
- GET_BITS (br, 5, &bits);
- params->fps_d *= bits + 1;
-
- return TRUE;
-
- /* ERRORS */
-failed:
- {
- GST_WARNING ("Failed to parse sequence extension");
- return FALSE;
- }
-}
-
-/* Set the Pixel Aspect Ratio in our hdr from a DAR code in the data */
-static void
-set_par_from_dar (MPEGVParams * params, guint8 asr_code)
-{
- /* Pixel_width = DAR_width * display_vertical_size */
- /* Pixel_height = DAR_height * display_horizontal_size */
- switch (asr_code) {
- case 0x02: /* 3:4 DAR = 4:3 pixels */
- params->par_w = 4 * params->height;
- params->par_h = 3 * params->width;
- break;
- case 0x03: /* 9:16 DAR */
- params->par_w = 16 * params->height;
- params->par_h = 9 * params->width;
- break;
- case 0x04: /* 1:2.21 DAR */
- params->par_w = 221 * params->height;
- params->par_h = 100 * params->width;
- break;
- case 0x01: /* Square pixels */
- params->par_w = params->par_h = 1;
- break;
- default:
- GST_DEBUG ("unknown/invalid aspect_ratio_information %d", asr_code);
- break;
- }
-}
-
-static void
-set_fps_from_code (MPEGVParams * params, guint8 fps_code)
-{
- const gint framerates[][2] = {
- {30, 1}, {24000, 1001}, {24, 1}, {25, 1},
- {30000, 1001}, {30, 1}, {50, 1}, {60000, 1001},
- {60, 1}, {30, 1}
- };
-
- if (fps_code && fps_code < 10) {
- params->fps_n = framerates[fps_code][0];
- params->fps_d = framerates[fps_code][1];
- } else {
- GST_DEBUG ("unknown/invalid frame_rate_code %d", fps_code);
- /* Force a valid framerate */
- /* FIXME or should this be kept unknown ?? */
- params->fps_n = 30000;
- params->fps_d = 1001;
- }
-}
-
-static gboolean
-gst_mpeg_video_params_parse_sequence (MPEGVParams * params, GstBitReader * br)
-{
- guint32 bits;
-
- GET_BITS (br, 32, &bits);
- if (bits != 0x100 + MPEG_PACKET_SEQUENCE)
- goto failed;
-
- /* assume MPEG-1 till otherwise discovered */
- params->mpeg_version = 1;
-
- GET_BITS (br, 12, &bits);
- params->width = bits;
- GET_BITS (br, 12, &bits);
- params->height = bits;
-
- GET_BITS (br, 4, &bits);
- set_par_from_dar (params, bits);
- GET_BITS (br, 4, &bits);
- set_fps_from_code (params, bits);
-
- GET_BITS (br, 18, &bits);
- if (bits == 0x3ffff) {
- /* VBR stream */
- params->bitrate = 0;
- } else {
- /* Value in header is in units of 400 bps */
- params->bitrate *= 400;
- }
-
- /* skip 1 + VBV buffer size */
- if (!gst_bit_reader_skip (br, 11))
- goto failed;
-
- /* constrained_parameters_flag */
- GET_BITS (br, 1, &bits);
-
- /* load_intra_quantiser_matrix */
- GET_BITS (br, 1, &bits);
- if (bits) {
- if (!gst_bit_reader_skip (br, 8 * 64))
- goto failed;
- }
-
- /* load_non_intra_quantiser_matrix */
- GET_BITS (br, 1, &bits);
- if (bits) {
- if (!gst_bit_reader_skip (br, 8 * 64))
- goto failed;
- }
-
- /* check for MPEG-2 sequence extension */
- while (find_start_code (br)) {
- gst_bit_reader_peek_bits_uint32 (br, &bits, 32);
- if (bits == 0x100 + MPEG_PACKET_EXTENSION) {
- if (!gst_mpeg_video_params_parse_extension (params, br))
- goto failed;
- params->mpeg_version = 2;
- }
- }
-
- /* dump some info */
- GST_LOG ("width x height: %d x %d", params->width, params->height);
- GST_LOG ("fps: %d/%d", params->fps_n, params->fps_d);
- GST_LOG ("par: %d/%d", params->par_w, params->par_h);
- GST_LOG ("profile/level: %d/%d", params->profile, params->level);
- GST_LOG ("bitrate/progressive: %d/%d", params->bitrate, params->progressive);
-
- return TRUE;
-
- /* ERRORS */
-failed:
- {
- GST_WARNING ("Failed to parse sequence header");
- /* clear out stuff */
- memset (params, 0, sizeof (*params));
- return FALSE;
- }
-}
-
-gboolean
-gst_mpeg_video_params_parse_config (MPEGVParams * params, const guint8 * data,
- guint size)
-{
- GstBitReader br;
-
- if (size < 4)
- return FALSE;
-
- gst_bit_reader_init (&br, data, size);
-
- return gst_mpeg_video_params_parse_sequence (params, &br);
-}
diff --git a/gst/videoparsers/mpegvideoparse.h b/gst/videoparsers/mpegvideoparse.h
deleted file mode 100644
index f0092b7137..0000000000
--- a/gst/videoparsers/mpegvideoparse.h
+++ /dev/null
@@ -1,77 +0,0 @@
-/* GStreamer
- * Copyright (C) <2007> Jan Schmidt
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
- */
-
-#ifndef __GST_MPEGVIDEO_PARAMS_H__
-#define __GST_MPEGVIDEO_PARAMS_H__
-
-#include
-
-G_BEGIN_DECLS
-
-/* Packet ID codes for different packet types we
- * care about */
-#define MPEG_PACKET_PICTURE 0x00
-#define MPEG_PACKET_SLICE_MIN 0x01
-#define MPEG_PACKET_SLICE_MAX 0xaf
-#define MPEG_PACKET_SEQUENCE 0xb3
-#define MPEG_PACKET_EXTENSION 0xb5
-#define MPEG_PACKET_SEQUENCE_END 0xb7
-#define MPEG_PACKET_GOP 0xb8
-#define MPEG_PACKET_NONE 0xff
-
-/* Extension codes we care about */
-#define MPEG_PACKET_EXT_SEQUENCE 0x01
-#define MPEG_PACKET_EXT_SEQUENCE_DISPLAY 0x02
-#define MPEG_PACKET_EXT_QUANT_MATRIX 0x03
-
-/* Flags indicating what type of packets are in this block, some are mutually
- * exclusive though - ie, sequence packs are accumulated separately. GOP &
- * Picture may occur together or separately */
-#define MPEG_BLOCK_FLAG_SEQUENCE 0x01
-#define MPEG_BLOCK_FLAG_PICTURE 0x02
-#define MPEG_BLOCK_FLAG_GOP 0x04
-
-#define MPEG_PICTURE_TYPE_I 0x01
-#define MPEG_PICTURE_TYPE_P 0x02
-#define MPEG_PICTURE_TYPE_B 0x03
-#define MPEG_PICTURE_TYPE_D 0x04
-
-typedef struct _MPEGVParams MPEGVParams;
-
-struct _MPEGVParams
-{
- gint mpeg_version;
-
- gint profile;
- gint level;
-
- gint width, height;
- gint par_w, par_h;
- gint fps_n, fps_d;
-
- gint bitrate;
- gboolean progressive;
-};
-
-GstFlowReturn gst_mpeg_video_params_parse_config (MPEGVParams * params,
- const guint8 * data, guint size);
-
-G_END_DECLS
-
-#endif
diff --git a/pkgconfig/Makefile.am b/pkgconfig/Makefile.am
index 38cd20bb71..99e1f1c1d8 100644
--- a/pkgconfig/Makefile.am
+++ b/pkgconfig/Makefile.am
@@ -1,9 +1,11 @@
### all of the standard pc files we need to generate
pcverfiles = \
- gstreamer-plugins-bad-@GST_MAJORMINOR@.pc
+ gstreamer-plugins-bad-@GST_MAJORMINOR@.pc \
+ gstreamer-codecparsers-@GST_MAJORMINOR@.pc
pcverfiles_uninstalled = \
- gstreamer-plugins-bad-@GST_MAJORMINOR@-uninstalled.pc
+ gstreamer-plugins-bad-@GST_MAJORMINOR@-uninstalled.pc \
+ gstreamer-codecparsers-@GST_MAJORMINOR@-uninstalled.pc
all-local: $(pcverfiles) $(pcverfiles_uninstalled)
@@ -22,7 +24,8 @@ pkgconfig_DATA = $(pcverfiles)
CLEANFILES = $(pcverfiles) $(pcverfiles_uninstalled)
pcinfiles = \
- gstreamer-plugins-bad.pc.in gstreamer-plugins-bad-uninstalled.pc.in
+ gstreamer-plugins-bad.pc.in gstreamer-plugins-bad-uninstalled.pc.in \
+ gstreamer-codecparsers.pc.in gstreamer-codecparsers-uninstalled.pc.in
DISTCLEANFILES = $(pcinfiles:.in=)
EXTRA_DIST = $(pcinfiles)
diff --git a/pkgconfig/gstreamer-codecparsers-uninstalled.pc.in b/pkgconfig/gstreamer-codecparsers-uninstalled.pc.in
new file mode 100644
index 0000000000..5a01ba8d09
--- /dev/null
+++ b/pkgconfig/gstreamer-codecparsers-uninstalled.pc.in
@@ -0,0 +1,12 @@
+prefix=
+exec_prefix=
+libdir=${pcfiledir}/../gst-libs/gst/codecparsers
+includedir=${pcfiledir}/../gst-libs
+
+Name: GStreamer codec parsers, Uninstalled
+Description: Bitstream parsers for GStreamer elements, uninstalled
+Requires: gstreamer-@GST_MAJORMINOR@ gstreamer-base-@GST_MAJORMINOR@
+Version: @VERSION@
+Libs: -L${libdir} ${libdir}/libgstcodecparsers-@GST_MAJORMINOR@.la
+Cflags: -I${includedir}
+
diff --git a/pkgconfig/gstreamer-codecparsers.pc.in b/pkgconfig/gstreamer-codecparsers.pc.in
new file mode 100644
index 0000000000..e2fc6d1ad8
--- /dev/null
+++ b/pkgconfig/gstreamer-codecparsers.pc.in
@@ -0,0 +1,12 @@
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+libdir=@libdir@
+includedir=@includedir@/gstreamer-@GST_MAJORMINOR@
+
+Name: GStreamer codec parsers
+Description: Bitstream parsers for GStreamer elements
+Requires: gstreamer-@GST_MAJORMINOR@ gstreamer-base-@GST_MAJORMINOR@
+Version: @VERSION@
+Libs: -L${libdir} -lgstcodecparsers-@GST_MAJORMINOR@
+Cflags: -I${includedir}
+
diff --git a/pkgconfig/gstreamer-plugins-bad.pc.in b/pkgconfig/gstreamer-plugins-bad.pc.in
index c75ff59c77..1fad717474 100644
--- a/pkgconfig/gstreamer-plugins-bad.pc.in
+++ b/pkgconfig/gstreamer-plugins-bad.pc.in
@@ -7,6 +7,7 @@ Name: GStreamer Bad Plugin libraries
Description: Currently includes the photography interface library
Requires: gstreamer-@GST_MAJORMINOR@ gstreamer-base-@GST_MAJORMINOR@
Version: @VERSION@
-Libs: -L${libdir} -lgstphotography-@GST_MAJORMINOR@
+Libs: -L${libdir} -lgstphotography-@GST_MAJORMINOR@\
+ -L${libdir} -lgstcodecparsers-@GST_MAJORMINOR@\
Cflags: -I${includedir}
diff --git a/tests/check/Makefile.am b/tests/check/Makefile.am
index dca2775b1b..47bd813c98 100644
--- a/tests/check/Makefile.am
+++ b/tests/check/Makefile.am
@@ -183,6 +183,8 @@ check_PROGRAMS = \
pipelines/colorspace \
$(check_mimic) \
elements/rtpmux \
+ libs/mpegvideoparser \
+ libs/h264parser \
$(check_schro) \
$(check_vp8) \
elements/viewfinderbin \
@@ -214,6 +216,24 @@ elements_h263parse_LDADD = libparser.la $(LDADD)
elements_h264parse_LDADD = libparser.la $(LDADD)
+libs_mpegvideoparser_CFLAGS = \
+ $(GST_PLUGINS_BAD_CFLAGS) $(GST_PLUGINS_BASE_CFLAGS) \
+ $(GST_BASE_CFLAGS) $(GST_CFLAGS) $(AM_CFLAGS)
+
+libs_mpegvideoparser_LDADD = \
+ $(top_builddir)/gst-libs/gst/codecparsers/libgstcodecparsers-@GST_MAJORMINOR@.la \
+ $(GST_PLUGINS_BAD_LIBS) -lgstcodecparsers-@GST_MAJORMINOR@ \
+ $(GST_BASE_LIBS) $(GST_LIBS) $(LDADD)
+
+libs_h264parser_CFLAGS = \
+ $(GST_PLUGINS_BAD_CFLAGS) $(GST_PLUGINS_BASE_CFLAGS) \
+ $(GST_BASE_CFLAGS) $(GST_CFLAGS) $(AM_CFLAGS)
+
+libs_h264parser_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)
@@ -242,7 +262,6 @@ elements_camerabin_LDADD = \
elements_camerabin_SOURCES = elements/camerabin.c
-if BUILD_EXPERIMENTAL
elements_camerabin2_CFLAGS = \
$(GST_PLUGINS_BAD_CFLAGS) $(GST_PLUGINS_BASE_CFLAGS) \
$(GST_BASE_CFLAGS) $(GST_CFLAGS) $(AM_CFLAGS) -DGST_USE_UNSTABLE_API
@@ -253,8 +272,6 @@ elements_camerabin2_LDADD = \
$(GST_PLUGINS_BASE_LIBS) $(GST_BASE_LIBS) $(GST_LIBS) $(LDADD)
elements_camerabin2_SOURCES = elements/camerabin2.c
-endif
-
elements_jifmux_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(EXIF_CFLAGS) $(AM_CFLAGS)
elements_jifmux_LDADD = $(GST_PLUGINS_BASE_LIBS) -lgsttag-$(GST_MAJORMINOR) $(GST_CHECK_LIBS) $(EXIF_LIBS) $(LDADD)
elements_jifmux_SOURCES = elements/jifmux.c
diff --git a/tests/check/elements/mpegvideoparse.c b/tests/check/elements/mpegvideoparse.c
index 9dac4633d2..9aab78f9f1 100644
--- a/tests/check/elements/mpegvideoparse.c
+++ b/tests/check/elements/mpegvideoparse.c
@@ -183,8 +183,9 @@ mpeg_video_parse_check_caps (guint version, guint8 * seq, gint size)
buf = gst_value_get_buffer (val);
fail_unless (buf != NULL);
/* codec-data = header - GOP */
- fail_unless (GST_BUFFER_SIZE (buf) == size - 8);
- fail_unless (memcmp (GST_BUFFER_DATA (buf), seq, GST_BUFFER_SIZE (buf)) == 0);
+ assert_equals_int (GST_BUFFER_SIZE (buf), size - 8);
+ fail_unless (memcmp (GST_BUFFER_DATA (buf), seq + 4,
+ GST_BUFFER_SIZE (buf)) == 0);
gst_caps_unref (caps);
}
diff --git a/tests/check/libs/h264parser.c b/tests/check/libs/h264parser.c
new file mode 100644
index 0000000000..3bc8c49e57
--- /dev/null
+++ b/tests/check/libs/h264parser.c
@@ -0,0 +1,182 @@
+/* Gstreamer
+ * Copyright (C) <2011> Intel Corporation
+ * Copyright (C) <2011> Collabora Ltd.
+ * Copyright (C) <2011> Thibault Saunier
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+#include
+#include
+
+static guint8 slice_dpa[] = {
+ 0x00, 0x00, 0x01, 0x02, 0x00, 0x02, 0x01, 0x03, 0x00,
+ 0x04, 0x00, 0x05, 0x00, 0x06, 0x00, 0x07, 0x00, 0x09, 0x00, 0x0a, 0x00,
+ 0x0b, 0x00, 0x0c, 0x00, 0x0d, 0x00, 0x0e, 0x00, 0x0f, 0x00, 0x10, 0x00,
+ 0x11, 0x00, 0x12, 0x00, 0x13, 0x00, 0x14, 0x00, 0x15, 0x00, 0x16, 0x00,
+ 0x17, 0x00, 0x18, 0x00, 0x19, 0x00, 0x1a, 0x00, 0x1b, 0x00, 0x1c, 0x00,
+ 0x1d, 0x00, 0x1e, 0x00, 0x1f, 0x00, 0x20, 0x00, 0x21, 0x00, 0x22, 0x00,
+ 0x23, 0x00, 0x24, 0x00, 0x25, 0x00, 0x26, 0x00, 0x27, 0x00, 0x28, 0x00,
+ 0x29, 0x00, 0x2a, 0x00, 0x2b, 0x00, 0x2c, 0x00, 0x2d, 0x00, 0x2e, 0x00,
+ 0x2f, 0x00, 0x30, 0x00, 0x31, 0x00, 0x32, 0x00, 0x33, 0x00, 0x34, 0x00,
+ 0x35, 0x00, 0x36, 0x00, 0x37, 0x00, 0x38, 0x00, 0x39, 0x00, 0x3a, 0x00,
+ 0x3b, 0x00, 0x3c, 0x00, 0x3d, 0x00, 0x3e, 0x00, 0x3f, 0x00, 0x40, 0x00,
+ 0x41, 0x00, 0x42, 0x00, 0x43, 0x00, 0x44, 0x00, 0x45, 0x00, 0x46, 0x00,
+ 0x47, 0x00, 0x48, 0x00, 0x49, 0x00, 0x4a, 0x00, 0x4b, 0x00, 0x4c, 0x00,
+ 0x4d, 0x00, 0x4e, 0x00, 0x4f, 0x00, 0x50, 0x00, 0x51, 0x00, 0x52, 0x00,
+ 0x53, 0x00, 0x54, 0x00, 0x55, 0x00, 0x56, 0x00, 0x57, 0x00, 0x58, 0x00,
+ 0x59, 0x00, 0x5a, 0x00, 0x5b, 0x00, 0x5c, 0x00, 0x5d, 0x00, 0x5e, 0x00,
+ 0x5f, 0x00, 0x60, 0x00, 0x61, 0x01, 0x04, 0x00, 0xc4, 0x00, 0xa6, 0x00,
+ 0xc5, 0x00, 0xab, 0x00, 0x82, 0x00, 0xc2, 0x00, 0xd8, 0x00, 0xc6, 0x00,
+ 0xe4, 0x00, 0xbe, 0x00, 0xb0, 0x00, 0xe6, 0x00, 0xb6, 0x00, 0xb7, 0x00,
+ 0xb4, 0x00, 0xb5, 0x00, 0x87, 0x00, 0xb2, 0x00, 0xb3, 0x00, 0xd9, 0x00,
+ 0x8c, 0x00, 0xe5, 0x00, 0xbf, 0x00, 0xb1, 0x00, 0xe7, 0x00, 0xbb, 0x00,
+ 0xa3, 0x00, 0x84, 0x00, 0x85, 0x00, 0xbd, 0x00, 0x96, 0x00, 0xe8, 0x00,
+ 0x86, 0x00, 0x8e, 0x00, 0x8b, 0x00, 0x9d, 0x00, 0xa9, 0x00, 0x8a, 0x01,
+ 0x05, 0x00, 0x83, 0x00, 0xf2, 0x00, 0xf3, 0x00, 0x8d, 0x00, 0x97, 0x00,
+ 0x88, 0x00, 0xde, 0x00, 0xf1, 0x00, 0x9e, 0x00, 0xaa, 0x00, 0xf5, 0x00,
+ 0xf4, 0x00, 0xf6, 0x00, 0xa2, 0x00, 0xad, 0x00, 0xc9, 0x00, 0xc7, 0x00,
+ 0xae, 0x00, 0x62, 0x00, 0x63, 0x00, 0x90, 0x00, 0x64, 0x00, 0xcb, 0x00,
+ 0x65, 0x00, 0xc8, 0x00, 0xca, 0x00, 0xcf, 0x00, 0xcc, 0x00, 0xcd, 0x00,
+ 0xce, 0x00, 0xe9, 0x00, 0x66, 0x00, 0xd3, 0x00, 0xd0, 0x00, 0xd1, 0x00,
+ 0xaf, 0x00, 0x67, 0x00, 0x91, 0x00, 0xd6, 0x00, 0xd4, 0x00, 0xd5, 0x00,
+ 0x68, 0x00, 0xeb, 0x00, 0xed, 0x00, 0x89, 0x00, 0x6a, 0x00, 0x69, 0x00,
+ 0x6b, 0x00, 0x6d, 0x00, 0x6c, 0x00, 0x6e, 0x00, 0xa0, 0x00, 0x6f, 0x00,
+ 0x71, 0x00, 0x70, 0x00, 0x72, 0x00, 0x73, 0x00, 0x75, 0x00, 0x74, 0x00,
+ 0x76, 0x00, 0x77, 0x00, 0xea, 0x00, 0x78, 0x00, 0x7a, 0x00, 0x79, 0x00,
+ 0x7b, 0x00, 0x7d, 0x00, 0x7c, 0x00, 0xa1, 0x00, 0x7f, 0x00, 0x7e, 0x00,
+ 0x80, 0x00, 0x81, 0x00, 0xec, 0x00, 0xee, 0x00, 0xba, 0x01, 0x06, 0x00,
+ 0xef, 0x00, 0xe1, 0x00, 0xe0, 0x00, 0xdc, 0x01, 0x07, 0x01, 0x08, 0x01,
+ 0x09, 0x01, 0x0a, 0x01, 0x0b, 0x01, 0x0c, 0x00, 0xdb, 0x00, 0xe2, 0x01,
+ 0x0d, 0x01, 0x0e, 0x01, 0x0f, 0x01, 0x10, 0x01, 0x11, 0x01, 0x12, 0x00,
+ 0xdf, 0x01, 0x13, 0x01, 0x14, 0x01, 0x15, 0x01, 0x16, 0x01, 0x17, 0x00,
+ 0xfd, 0x00, 0xff, 0x01, 0x18, 0x01, 0x19, 0x01, 0x1a, 0x01, 0x1b, 0x01,
+ 0x1c, 0x01, 0x1d, 0x01, 0x1e, 0x01, 0x1f, 0x01, 0x20, 0x01, 0x21, 0x01,
+ 0x22, 0x01, 0x23, 0x01, 0x24, 0x01, 0x25, 0x01, 0x26, 0x00, 0xfe, 0x01,
+ 0x00, 0x01, 0x27, 0x01, 0x28, 0x01, 0x29, 0x01, 0x2a, 0x01, 0x2b, 0x01,
+ 0x2c, 0x01, 0x2d, 0x01, 0x2e, 0x01, 0x2f, 0x01, 0x30, 0x01, 0x31, 0x00,
+ 0xe3, 0x00, 0xd7, 0x01, 0x32, 0x00, 0xf8, 0x00, 0xf9, 0x01, 0x33, 0x01,
+ 0x34, 0x01, 0x35, 0x01, 0x36, 0x01, 0x37, 0x01, 0x38, 0x01, 0x39, 0x01,
+ 0x3a, 0x01, 0x3b, 0x01, 0x3c, 0x01, 0x3d, 0x01, 0x3e, 0x01, 0x3f, 0x01,
+ 0x40, 0x01, 0x41, 0x01, 0x42, 0x01, 0x43, 0x01, 0x44, 0x01, 0x45, 0x01,
+ 0x46, 0x01, 0x47, 0x01, 0x48, 0x01, 0x49, 0x01, 0x4a, 0x01, 0x4b, 0x01,
+ 0x4c, 0x00, 0x08, 0x05, 0x2e, 0x6e, 0x75, 0x6c, 0x6c, 0x0c, 0x76, 0x69,
+ 0x73, 0x69, 0x62, 0x6c, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x04, 0x45,
+ 0x75, 0x72, 0x6f, 0x06, 0x6d, 0x61, 0x63, 0x72, 0x6f, 0x6e, 0x0a, 0x62,
+ 0x75, 0x6c, 0x6c, 0x65, 0x74, 0x6d, 0x61, 0x74, 0x68, 0x06, 0x53, 0x61,
+ 0x63, 0x75, 0x74, 0x65, 0x06, 0x54, 0x63, 0x61, 0x72, 0x6f, 0x6e, 0x06,
+ 0x5a, 0x61, 0x63, 0x75, 0x74, 0x65, 0x06, 0x73, 0x61, 0x63, 0x75, 0x74,
+ 0x65, 0x06, 0x74, 0x63, 0x61, 0x72, 0x6f, 0x6e, 0x06, 0x7a, 0x61, 0x63,
+ 0x75, 0x74, 0x65, 0x07, 0x41, 0x6f, 0x67, 0x6f, 0x6e, 0x65, 0x6b, 0x07,
+ 0x61, 0x6f, 0x67, 0x6f, 0x6e, 0x65, 0x6b, 0x0c, 0x73, 0x63, 0x6f, 0x6d,
+ 0x6d, 0x61, 0x61, 0x63, 0x63, 0x65, 0x6e, 0x74, 0x0c, 0x53, 0x63, 0x6f,
+ 0x6d, 0x6d, 0x61, 0x61, 0x63, 0x63, 0x65, 0x6e, 0x74, 0x0a, 0x5a, 0x64,
+ 0x6f, 0x74, 0x61, 0x63, 0x63, 0x65, 0x6e, 0x74, 0x06, 0x4c, 0x63, 0x61,
+ 0x72, 0x6f, 0x6e, 0x06, 0x6c, 0x63, 0x61, 0x72, 0x6f, 0x6e, 0x0a, 0x7a,
+ 0x64, 0x6f, 0x74, 0x61, 0x63, 0x63, 0x65, 0x6e, 0x74, 0x06, 0x52, 0x61,
+ 0x63, 0x75, 0x74, 0x65, 0x06, 0x41, 0x62, 0x72, 0x65, 0x76, 0x65, 0x06,
+ 0x4c, 0x61, 0x63, 0x75, 0x74, 0x65, 0x07, 0x45, 0x6f, 0x67, 0x6f, 0x6e,
+ 0x65, 0x6b, 0x06, 0x45, 0x63, 0x61, 0x72, 0x6f, 0x6e, 0x06, 0x44, 0x63,
+ 0x61, 0x72, 0x6f, 0x6e, 0x07, 0x44, 0x6d, 0x61, 0x63, 0x72, 0x6f, 0x6e,
+ 0x06, 0x4e, 0x61, 0x63, 0x75, 0x74, 0x65, 0x06, 0x4e, 0x63, 0x61, 0x72,
+ 0x6f, 0x6e, 0x0d, 0x4f, 0x68, 0x75, 0x6e, 0x67, 0x61, 0x72, 0x75, 0x6d,
+ 0x6c, 0x61, 0x75, 0x74, 0x06, 0x52, 0x63, 0x61, 0x72, 0x6f, 0x6e, 0x05,
+ 0x55, 0x72, 0x69, 0x6e, 0x67, 0x09, 0x6e, 0x75, 0x6e, 0x67, 0x61, 0x64,
+ 0x65, 0x73, 0x68, 0x0d, 0x55, 0x68, 0x75, 0x6e, 0x67, 0x61, 0x72, 0x75,
+ 0x6d, 0x6c, 0x61, 0x75, 0x74, 0x0c, 0x54, 0x63, 0x6f, 0x6d, 0x6d, 0x61,
+ 0x61, 0x63, 0x63, 0x65, 0x6e, 0x74, 0x06, 0x72, 0x61, 0x63, 0x75, 0x74,
+ 0x65, 0x06, 0x61, 0x62, 0x72, 0x65, 0x76, 0x65, 0x06, 0x6c, 0x61, 0x63,
+ 0x75, 0x74, 0x65, 0x07, 0x65, 0x6f, 0x67, 0x6f, 0x6e, 0x65, 0x6b, 0x06,
+ 0x65, 0x63, 0x61, 0x72, 0x6f, 0x6e, 0x06, 0x64, 0x63, 0x61, 0x72, 0x6f,
+ 0x6e, 0x07, 0x64, 0x6d, 0x61, 0x63, 0x72, 0x6f, 0x6e, 0x06, 0x6e, 0x61,
+ 0x63, 0x75, 0x74, 0x65, 0x06, 0x6e, 0x63, 0x61, 0x72, 0x6f, 0x6e, 0x0d,
+ 0x6f, 0x68, 0x75, 0x6e, 0x67, 0x61, 0x72, 0x75, 0x6d, 0x6c, 0x61, 0x75,
+ 0x74, 0x06, 0x72, 0x63, 0x61, 0x72, 0x6f, 0x6e, 0x05, 0x75, 0x72, 0x69,
+ 0x6e, 0x67, 0x0d, 0x75, 0x68, 0x75, 0x6e, 0x67, 0x61, 0x72, 0x75, 0x6d,
+ 0x6c, 0x61, 0x75, 0x74, 0x0c, 0x74, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x61,
+ 0x63, 0x63, 0x65, 0x6e, 0x74, 0x0a, 0x49, 0x64, 0x6f, 0x74, 0x61, 0x63,
+ 0x63, 0x65, 0x6e, 0x74, 0x0c, 0x52, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x61,
+ 0x63, 0x63, 0x65, 0x6e, 0x74, 0x0c, 0x72, 0x63, 0x6f, 0x6d, 0x6d, 0x61,
+ 0x61, 0x63, 0x63, 0x65, 0x6e, 0x74, 0x07, 0x49, 0x6f, 0x67, 0x6f, 0x6e,
+ 0x65, 0x6b, 0x07, 0x41, 0x6d, 0x61, 0x63, 0x72, 0x6f, 0x6e, 0x07, 0x45,
+ 0x6d, 0x61, 0x63, 0x72, 0x6f, 0x6e, 0x0a, 0x45, 0x64, 0x6f, 0x74, 0x61,
+ 0x63, 0x63, 0x65, 0x6e, 0x74, 0x0c, 0x47, 0x63, 0x6f, 0x6d, 0x6d, 0x61,
+ 0x61, 0x63, 0x63, 0x65, 0x6e, 0x74, 0x0c, 0x4b, 0x63, 0x6f, 0x6d, 0x6d,
+ 0x61, 0x61, 0x63, 0x63, 0x65, 0x6e, 0x74, 0x07, 0x49, 0x6d, 0x61, 0x63,
+ 0x72, 0x6f, 0x6e, 0x0c, 0x4c, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x61, 0x63,
+ 0x63, 0x65, 0x6e, 0x74, 0x0c, 0x4e, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x61,
+ 0x63, 0x63, 0x65, 0x6e, 0x74, 0x07, 0x4f, 0x6d, 0x61, 0x63, 0x72, 0x6f,
+ 0x6e, 0x07, 0x55, 0x6f, 0x67, 0x6f, 0x6e, 0x65, 0x6b, 0x07, 0x55, 0x6d,
+ 0x61, 0x63, 0x72, 0x6f, 0x6e, 0x07, 0x69, 0x6f, 0x67, 0x6f, 0x6e, 0x65,
+ 0x6b, 0x07, 0x61, 0x6d, 0x61, 0x63, 0x72, 0x6f, 0x6e, 0x07, 0x65, 0x6d,
+ 0x61, 0x63, 0x72, 0x6f, 0x6e, 0x0a, 0x65, 0x64, 0x6f, 0x74, 0x61, 0x63,
+ 0x63, 0x65, 0x6e, 0x74, 0x0c, 0x67, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x61,
+ 0x63, 0x63, 0x65, 0x6e, 0x74, 0x0c, 0x6b, 0x63, 0x6f, 0x6d, 0x6d, 0x61,
+ 0x61, 0x63, 0x63, 0x65, 0x6e, 0x74, 0x07, 0x69, 0x6d, 0x61, 0x63, 0x72,
+ 0x6f, 0x6e, 0x0c, 0x6c, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x61, 0x63, 0x63,
+ 0x65, 0x6e, 0x74, 0x0c, 0x6e, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x61, 0x63,
+ 0x63, 0x65, 0x6e, 0x74, 0x07, 0x6f, 0x6d, 0x61, 0x63, 0x72, 0x6f, 0x6e,
+ 0x07, 0x75, 0x6f, 0x67, 0x6f, 0x6e, 0x65, 0x6b, 0x07, 0x75, 0x6d, 0x61,
+ 0x63, 0x72, 0x6f, 0x6e, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02
+};
+
+GST_START_TEST (test_h264_parse_slice_dpa)
+{
+ GstH264ParserResult res;
+ GstH264NalUnit nalu;
+
+ GstH264NalParser *parser = gst_h264_nal_parser_new ();
+
+ res = gst_h264_parser_identify_nalu (parser, slice_dpa, 0,
+ sizeof (slice_dpa), &nalu);
+
+ assert_equals_int (res, GST_H264_PARSER_OK);
+ assert_equals_int (nalu.type, GST_H264_NAL_SLICE_DPA);
+
+ g_free (parser);
+}
+
+GST_END_TEST;
+
+static Suite *
+h264parser_suite (void)
+{
+ Suite *s = suite_create ("H264 Parser library");
+
+ TCase *tc_chain = tcase_create ("general");
+
+ suite_add_tcase (s, tc_chain);
+ tcase_add_test (tc_chain, test_h264_parse_slice_dpa);
+
+ return s;
+}
+
+int
+main (int argc, char **argv)
+{
+ int nf;
+
+ Suite *s = h264parser_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;
+}
diff --git a/tests/check/libs/mpegvideoparser.c b/tests/check/libs/mpegvideoparser.c
new file mode 100644
index 0000000000..414a45e232
--- /dev/null
+++ b/tests/check/libs/mpegvideoparser.c
@@ -0,0 +1,208 @@
+/* Gstreamer
+ * Copyright (C) <2011> Intel Corporation
+ * Copyright (C) <2011> Collabora Ltd.
+ * Copyright (C) <2011> Thibault Saunier
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include
+#include
+
+/* actually seq + gop */
+static guint8 mpeg2_seq[] = {
+ 0x00, 0x00, 0x01, 0xb3, 0x02, 0x00, 0x18, 0x15, 0xff, 0xff, 0xe0, 0x28,
+ 0x00, 0x00, 0x01, 0xb3, 0x78, 0x04, 0x38, 0x37, 0xff, 0xff, 0xf0, 0x00,
+ 0x00, 0x00, 0x01, 0xb5, 0x14, 0x8a, 0x00, 0x11, 0x03, 0x71,
+ 0x00, 0x00, 0x01, 0xb8, 0x00, 0x08, 0x00, 0x00,
+ 0x00, 0x00, 0x01, 0x03, 0x00, 0x08, 0x00, 0x00
+};
+
+static guint8 mis_identified_datas[] = {
+ 0x00, 0x00, 0x01, 0x1f, 0x4a, 0xf4, 0xd4, 0xd8, 0x08, 0x23, 0xdd,
+ 0x7c, 0xd3, 0x75, 0x21, 0x43, 0x85, 0x31, 0x43, 0x04, 0x24, 0x30,
+ 0x18, 0x43, 0xba, 0x1a, 0x50, 0x60, 0xbb, 0x53, 0x56, 0x80, 0x41,
+ 0xb9, 0xd4, 0x25, 0x42, 0xea, 0x71, 0xb7, 0x49, 0x84, 0x0b, 0x14,
+ 0x24, 0xc2, 0xaa, 0xba, 0xf9, 0xf7, 0x5b, 0x78, 0xa2, 0xba, 0xd3,
+ 0xc7, 0x12, 0xee, 0xbe, 0xba, 0xfa, 0xeb, 0xeb, 0xaf, 0xbe, 0x6f,
+ 0xce, 0x92, 0x05, 0x15, 0x22, 0x44, 0xf4, 0xc9, 0x1b, 0xcd, 0x84,
+ 0x80, 0x87, 0x35, 0x6c, 0x07, 0x82, 0xaf, 0x3c, 0x3a, 0x89, 0x48,
+ 0x3a, 0x26, 0x00, 0x64, 0x03, 0x12, 0x60, 0x03, 0xf4, 0x8c, 0x21,
+ 0x16, 0xbe, 0x3c, 0x7c, 0x18, 0x03, 0x10, 0x0c, 0x80, 0xa0, 0x05,
+ 0xe1, 0x85, 0x94, 0x90, 0xc4, 0x74, 0x05, 0x72, 0x80, 0x7a, 0x8e,
+ 0x3e, 0x00, 0x30,
+ /* The accelerated version of scan_for_start_codes()
+ * mis-identifies the following as a start code */
+ 0x01, 0x00, 0x01, 0x80, 0x68, 0x14,
+ 0x26, 0xe4, 0x80, 0x98, 0x0a, 0xba, 0x77, 0x01, 0xc2, 0x42, 0x12,
+ 0xc4, 0x59, 0x2a, 0xbb, 0x49, 0xf2, 0xc5, 0xa8, 0xd9, 0x30, 0x33,
+ 0x16, 0x50, 0x60, 0x61, 0x41, 0xaa, 0x0d, 0x41, 0x5b, 0x17, 0x77,
+ 0x76, 0x1a, 0x14, 0x3a, 0x08, 0x19, 0x3d, 0x6c, 0x94, 0x55, 0xd0,
+ 0x94, 0x5a, 0xeb, 0x61, 0x22, 0xa7, 0xa6, 0x83, 0x47, 0x6d, 0x4d,
+ 0x84, 0xc4, 0x6f, 0x78, 0xd8, 0x3a, 0xb4, 0x02, 0x0c, 0x36, 0xa6,
+ 0x0b, 0x18, 0x49, 0xf7, 0xad, 0x00, 0x82, 0x09, 0xba, 0x12, 0xba,
+ 0x1d, 0x44, 0x94, 0x0a, 0x1b, 0x03, 0xbb, 0xa2, 0x53, 0x02, 0xc0,
+ 0x41, 0xac, 0x22,
+ /* the real start code is here */
+ 0x00, 0x00, 0x01, 0x20, 0x4a, 0xfd, 0xf5, 0x50
+};
+
+static GstMpegVideoPacketTypeCode ordercode[] = {
+ GST_MPEG_VIDEO_PACKET_SEQUENCE,
+ GST_MPEG_VIDEO_PACKET_EXTENSION,
+ GST_MPEG_VIDEO_PACKET_GOP,
+};
+
+GST_START_TEST (test_mpeg_parse)
+{
+ gint i;
+ GList *list, *tmp;
+ GstMpegVideoTypeOffsetSize *typeoffsz;
+
+ list = gst_mpeg_video_parse (mpeg2_seq, sizeof (mpeg2_seq), 12);
+
+ assert_equals_int (g_list_length (list), 4);
+ for (tmp = list, i = 0; tmp; tmp = g_list_next (tmp), i++) {
+ typeoffsz = tmp->data;
+ if (i == 3) {
+ fail_unless (GST_MPEG_VIDEO_PACKET_SLICE_MIN <= typeoffsz->type &&
+ typeoffsz->type <= GST_MPEG_VIDEO_PACKET_SLICE_MAX);
+ fail_unless (typeoffsz->size < 0);
+ } else
+ assert_equals_int (ordercode[i], typeoffsz->type);
+ }
+
+ g_list_free_full (list, (GDestroyNotify) g_free);
+}
+
+GST_END_TEST;
+
+GST_START_TEST (test_mpeg_parse_sequence_header)
+{
+ GList *list;
+ GstMpegVideoTypeOffsetSize *typeoffsz;
+ GstMpegVideoSequenceHdr seqhdr;
+
+ list = gst_mpeg_video_parse (mpeg2_seq, sizeof (mpeg2_seq), 12);
+
+ typeoffsz = list->data;
+ fail_unless (typeoffsz->type == GST_MPEG_VIDEO_PACKET_SEQUENCE);
+ fail_unless (gst_mpeg_video_parse_sequence_header (&seqhdr, mpeg2_seq,
+ sizeof (mpeg2_seq), typeoffsz->offset));
+ assert_equals_int (seqhdr.width, 1920);
+ assert_equals_int (seqhdr.height, 1080);
+ assert_equals_int (seqhdr.aspect_ratio_info, 3);
+ assert_equals_int (seqhdr.par_w, 17280);
+ assert_equals_int (seqhdr.par_h, 17280);
+ assert_equals_int (seqhdr.frame_rate_code, 7);
+ assert_equals_int (seqhdr.fps_n, 60000);
+ assert_equals_int (seqhdr.fps_d, 1001);
+ assert_equals_int (seqhdr.bitrate_value, 262143);
+ assert_equals_int (seqhdr.bitrate, 0);
+ assert_equals_int (seqhdr.vbv_buffer_size_value, 512);
+ fail_unless (seqhdr.constrained_parameters_flag == FALSE);
+
+ g_list_free_full (list, (GDestroyNotify) g_free);
+}
+
+GST_END_TEST;
+
+GST_START_TEST (test_mpeg_parse_sequence_extension)
+{
+ GList *list;
+ GstMpegVideoTypeOffsetSize *typeoffsz;
+ GstMpegVideoSequenceExt seqext;
+
+ list = gst_mpeg_video_parse (mpeg2_seq, sizeof (mpeg2_seq), 12);
+
+ typeoffsz = list->next->data;
+ fail_unless (typeoffsz->type == GST_MPEG_VIDEO_PACKET_EXTENSION);
+ fail_unless (gst_mpeg_video_parse_sequence_extension (&seqext,
+ mpeg2_seq, sizeof (mpeg2_seq), typeoffsz->offset));
+ assert_equals_int (seqext.profile, 4);
+ assert_equals_int (seqext.level, 8);
+ assert_equals_int (seqext.progressive, 1);
+ assert_equals_int (seqext.chroma_format, 1);
+ assert_equals_int (seqext.horiz_size_ext, 0);
+ assert_equals_int (seqext.vert_size_ext, 0);
+ assert_equals_int (seqext.vert_size_ext, 0);
+ assert_equals_int (seqext.bitrate_ext, 8);
+ assert_equals_int (seqext.vbv_buffer_size_extension, 3);
+ assert_equals_int (seqext.low_delay, 0);
+ assert_equals_int (seqext.fps_n_ext, 3);
+ assert_equals_int (seqext.fps_d_ext, 2);
+
+ g_list_free_full (list, (GDestroyNotify) g_free);
+}
+
+GST_END_TEST;
+
+GST_START_TEST (test_mis_identified_datas)
+{
+ GList *list, *tmp;
+ GstMpegVideoTypeOffsetSize *typeoffsz;
+ guint8 *data = mis_identified_datas;
+
+ list = gst_mpeg_video_parse (mis_identified_datas,
+ sizeof (mis_identified_datas), 0);
+
+ assert_equals_int (g_list_length (list), 2);
+ for (tmp = list; tmp; tmp = g_list_next (tmp)) {
+ typeoffsz = tmp->data;
+
+ assert_equals_int (data[typeoffsz->offset - 4], 0);
+ assert_equals_int (data[typeoffsz->offset - 3], 0);
+ assert_equals_int (data[typeoffsz->offset - 2], 1);
+ }
+
+ g_list_free_full (list, (GDestroyNotify) g_free);
+}
+
+GST_END_TEST;
+
+static Suite *
+videoparsers_suite (void)
+{
+ Suite *s = suite_create ("Video Parsers library");
+
+ TCase *tc_chain = tcase_create ("general");
+
+ suite_add_tcase (s, tc_chain);
+ tcase_add_test (tc_chain, test_mpeg_parse);
+ tcase_add_test (tc_chain, test_mpeg_parse_sequence_header);
+ tcase_add_test (tc_chain, test_mpeg_parse_sequence_extension);
+ tcase_add_test (tc_chain, test_mis_identified_datas);
+
+ return s;
+}
+
+int
+main (int argc, char **argv)
+{
+ int nf;
+
+ Suite *s = videoparsers_suite ();
+
+ SRunner *sr = srunner_create (s);
+
+ gst_check_init (&argc, &argv);
+
+ srunner_run_all (sr, CK_NORMAL);
+ nf = srunner_ntests_failed (sr);
+ srunner_free (sr);
+
+ return nf;
+}