Merge branch 'master' into 0.11

This commit is contained in:
Wim Taymans 2011-09-06 16:13:28 +02:00
commit d4590a1959
59 changed files with 5976 additions and 2413 deletions

2
common

@ -1 +1 @@
Subproject commit 605cd9a65ed61505f24b840d3fe8e252be72b151
Subproject commit a39eb835fb3be2a4c5a6a89b5ca5cc064e79b2e2

View file

@ -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

View file

@ -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 \

102
docs/libs/Makefile.am Normal file
View file

@ -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

48
docs/libs/compiling.sgml Normal file
View file

@ -0,0 +1,48 @@
<?xml version="1.0"?>
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.1.2//EN"
"http://www.oasis-open.org/docbook/xml/4.1.2/docbookx.dtd" [
<!ENTITY % version-entities SYSTEM "version.entities">
%version-entities;
]>
<refentry id="compiling" revision="17 Jan 2002">
<refmeta>
<refentrytitle>Compiling</refentrytitle>
<manvolnum>3</manvolnum>
<refmiscinfo>GStreamer-Bad Library</refmiscinfo>
</refmeta>
<refnamediv>
<refname>Compiling against the bad plugins libraries</refname>
<refpurpose>
How to compile against the bad plugins libraries
</refpurpose>
</refnamediv>
<refsect1>
<title>Compiling against the bad plugins libraries</title>
<para>
To compile against these libraries, you need to tell the compiler where to
find the header files and libraries. This is done with the
<application>pkg-config</application> utility.
</para>
<para>
The following interactive shell session demonstrates how
<application>pkg-config</application> is used:
<programlisting>
$ 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
</programlisting>
</para>
<para>
Note that, because of the number of libraries provided in this package,
the pkg-config information <emphasis>does not add -l flags</emphasis> itself
to choose the libraries to link to. You must add these yourself to select
which of the libraries you want to use.
</para>
</refsect1>
</refentry>

View file

@ -0,0 +1,60 @@
<?xml version="1.0"?>
<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.1.2//EN"
"http://www.oasis-open.org/docbook/xml/4.1.2/docbookx.dtd" [
<!ENTITY % version-entities SYSTEM "version.entities">
%version-entities;
]>
<book id="index" xmlns:xi="http://www.w3.org/2003/XInclude">
<bookinfo>
<title>GStreamer Bad Plugins &GST_MAJORMINOR; Library Reference Manual</title>
<releaseinfo>
for GStreamer Bad Library &GST_MAJORMINOR; (&GST_VERSION;)
<ulink role="online-location" url="http://gstreamer.freedesktop.org/data/doc/gstreamer/head/gst-plugins-bad-libs/html/">http://gstreamer.freedesktop.org/data/doc/gstreamer/head/gst-plugins-bad-libs/html/</ulink>.
</releaseinfo>
</bookinfo>
<part id="gstreamer-plugins-bad">
<title>GStreamer Bad Plugins Libraries</title>
<para>
This manual describes the libraries provided by the GStreamer Bad Plugins
package.
</para>
<xi:include href="compiling.sgml" />
<chapter id="codecparsers">
<title>Bitstream parsing Library</title>
<para>
This library should be linked to by getting cflags and libs from
<filename>gstreamer-plugins-bad-&GST_MAJORMINOR;.pc</filename> and adding
<filename>-lgscodeparsers-&GST_MAJORMINOR;</filename> to the library flags.
</para>
<xi:include href="xml/gsth264parser.xml" />
<xi:include href="xml/gstmpegvideoparser.xml" />
</chapter>
<chapter id="video">
<title>Base video element classes</title>
<xi:include href="xml/gstbasevideocodec.xml" />
<xi:include href="xml/gstbasevideodecoder.xml" />
<xi:include href="xml/gstbasevideoencoder.xml" />
<xi:include href="xml/gstbasevideoutils.xml" />
</chapter>
</part>
<part id="gstreamer-libs-hierarchy">
<title>Object Hierarchy</title>
<xi:include href="xml/tree_index.sgml" />
</part>
<index id="api-index-full">
<title>Index</title>
<xi:include href="xml/api-index-full.xml"><xi:fallback /></xi:include>
</index>
<index id="api-index-deprecated" role="deprecated">
<title>Index of deprecated API</title>
<xi:include href="xml/api-index-deprecated.xml"><xi:fallback /></xi:include>
</index>
<xi:include href="xml/annotation-glossary.xml"><xi:fallback /></xi:include>
</book>

View file

@ -0,0 +1,361 @@
# codecparsers
<SECTION>
<FILE>gsth264parser</FILE>
<TITLE>h264parser</TITLE>
<INCLUDE>gst/codecparsers/gsth264parser.h</INCLUDE>
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
<SUBSECTION Standard>
<SUBSECTION Private>
</SECTION>
<SECTION>
<FILE>gstmpegvideoparser</FILE>
<TITLE>mpegvideoparser</TITLE>
<INCLUDE>gst/codecparsers/gstmpegvideoparser.h</INCLUDE>
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
<SUBSECTION Standard>
<SUBSECTION Private>
</SECTION>
<SECTION>
<FILE>gstphotography</FILE>
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
<SUBSECTION Standard>
GST_PHOTOGRAPHY
GST_IS_PHOTOGRAPHY
GST_TYPE_PHOTOGRAPHY
gst_photography_get_type
GST_PHOTOGRAPHY_GET_IFACE
</SECTION>
<SECTION>
<FILE>gstbasecamerasrc</FILE>
<TITLE>GstBaseCameraSrc</TITLE>
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
<SUBSECTION Standard>
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
</SECTION>
<SECTION>
<FILE>gstbasevideoencoder</FILE>
<TITLE>GstBaseVideoEncoder</TITLE>
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
<SUBSECTION Standard>
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
</SECTION>
<SECTION>
<FILE>gstbasevideodecoder</FILE>
<TITLE>GstBaseVideoDecoder</TITLE>
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
<SUBSECTION Standard>
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
</SECTION>
<SECTION>
<FILE>gstbasevideocodec</FILE>
<TITLE>GstBaseVideoCodec</TITLE>
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
<SUBSECTION Standard>
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
</SECTION>
<SECTION>
<FILE>gstsignalprocessor</FILE>
<TITLE>GstSignalProcessor</TITLE>
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
<SUBSECTION Standard>
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
</SECTION>
<SECTION>
<FILE>photography-enumtypes</FILE>
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
</SECTION>
<SECTION>
<FILE>gstcamerabin-enum</FILE>
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
</SECTION>
<SECTION>
<FILE>gstcamerabinpreview</FILE>
gst_camerabin_create_preview_pipeline
gst_camerabin_destroy_preview_pipeline
gst_camerabin_preview_pipeline_post
gst_camerabin_preview_set_caps
</SECTION>
<SECTION>
<FILE>gstbasevideoutils</FILE>
gst_base_video_rawvideo_convert
gst_base_video_encoded_video_convert
gst_video_state_get_timestamp
</SECTION>

View file

@ -0,0 +1,4 @@
#include <gst/gst.h>
#include <gst/codecparsers/gsth264parser.h>
#include <gst/codecparsers/gstmpegvideoparser.h>

View file

@ -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) {

View file

@ -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)

View file

@ -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:

View file

@ -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 */

View file

@ -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);

View file

@ -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

View file

@ -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)

View file

@ -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 \
> $@

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,682 @@
/* Gstreamer
* Copyright (C) <2011> Intel Corporation
* Copyright (C) <2011> Collabora Ltd.
* Copyright (C) <2011> Thibault Saunier <thibault.saunier@collabora.com>
*
* Some bits C-c,C-v'ed and s/4/3 from h264parse and videoparsers/h264parse.c:
* Copyright (C) <2010> Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
* Copyright (C) <2010> Collabora Multimedia
* Copyright (C) <2010> Nokia Corporation
*
* (C) 2005 Michal Benes <michal.benes@itonis.tv>
* (C) 2008 Wim Taymans <wim.taymans@gmail.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#ifndef __GST_H264_PARSER_H__
#define __GST_H264_PARSER_H__
#include <gst/gst.h>
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

View file

@ -0,0 +1,755 @@
/* Gstreamer
* Copyright (C) <2011> Intel Corporation
* Copyright (C) <2011> Collabora Ltd.
* Copyright (C) <2011> Thibault Saunier <thibault.saunier@collabora.com>
*
* From bad/sys/vdpau/mpeg/mpegutil.c:
* Copyright (C) <2007> Jan Schmidt <thaytan@mad.scientist.com>
* Copyright (C) <2009> Carl-Anton Ingmarsson <ca.ingmarsson@gmail.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
/**
* SECTION:gstmpegvideoparser
* @short_description: Convenience library for mpeg1 and 2 video
* bitstream parsing.
*
* <refsect2>
* <para>
* Provides useful functions for mpeg videos bitstream parsing.
* </para>
* </refsect2>
*/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include "gstmpegvideoparser.h"
#include <string.h>
#include <gst/base/gstbitreader.h>
#include <gst/base/gstbytereader.h>
#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;
}

View file

@ -0,0 +1,368 @@
/* Gstreamer
* Copyright (C) <2011> Intel Corporation
* Copyright (C) <2011> Collabora Ltd.
* Copyright (C) <2011> Thibault Saunier <thibault.saunier@collabora.com>
*
* From bad/sys/vdpau/mpeg/mpegutil.c:
* Copyright (C) <2007> Jan Schmidt <thaytan@mad.scientist.com>
* Copyright (C) <2009> Carl-Anton Ingmarsson <ca.ingmarsson@gmail.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#ifndef __GST_MPEG_VIDEO_UTILS_H__
#define __GST_MPEG_VIDEO_UTILS_H__
#include <gst/gst.h>
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

View file

@ -1,3 +0,0 @@
play-enumtypes.[ch]
play-marshal.[ch]
play-marshal.list

View file

@ -1,104 +0,0 @@
/* GStreamer
* Copyright (C) 2003 Julien Moutte <julien@moutte.net>
*
* 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 <gst/gst.h>
#include <gst/xoverlay/xoverlay.h>
#include <gst/play/play-enumtypes.h>
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__ */

View file

@ -1,144 +0,0 @@
<?xml version="1.0" encoding="Windows-1252"?>
<VisualStudioProject
ProjectType="Visual C++"
Version="7.10"
Name="play"
ProjectGUID="{979C216F-0ACF-4956-AE00-055A42D67899}"
RootNamespace="play"
Keyword="Win32Proj">
<Platforms>
<Platform
Name="Win32"/>
</Platforms>
<Configurations>
<Configuration
Name="Debug|Win32"
OutputDirectory="../../../win32/Debug"
IntermediateDirectory="../../../win32/Debug"
ConfigurationType="2"
CharacterSet="2">
<Tool
Name="VCCLCompilerTool"
Optimization="0"
AdditionalIncludeDirectories="../../../../gstreamer/win32;../../../../gstreamer;../../../../gstreamer/libs;../../../../glib;../../../../glib/glib;../../../../glib/gmodule;&quot;../../../gst-libs&quot;;../../../../popt/include;../../../../libxml2/include/libxml2"
PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;HAVE_CONFIG_H;_USE_MATH_DEFINES"
MinimalRebuild="TRUE"
BasicRuntimeChecks="3"
RuntimeLibrary="3"
UsePrecompiledHeader="0"
WarningLevel="3"
Detect64BitPortabilityProblems="TRUE"
DebugInformationFormat="4"/>
<Tool
Name="VCCustomBuildTool"/>
<Tool
Name="VCLinkerTool"
AdditionalDependencies="glib-2.0.lib gmodule-2.0.lib gthread-2.0.lib gobject-2.0.lib libgstreamer.lib gstbytestream.lib iconv.lib intl.lib"
OutputFile="$(OutDir)/gstplay.dll"
LinkIncremental="2"
AdditionalLibraryDirectories="../../../../gstreamer/win32/Debug;../../../../glib/glib;../../../../glib/gmodule;../../../../glib/gthread;../../../../glib/gobject;../../../../gettext/lib;../../../../libiconv/lib"
ModuleDefinitionFile="play.def"
GenerateDebugInformation="TRUE"
ProgramDatabaseFile="$(OutDir)/play.pdb"
SubSystem="2"
OptimizeReferences="2"
ImportLibrary="$(OutDir)/gstplay.lib"
TargetMachine="1"/>
<Tool
Name="VCMIDLTool"/>
<Tool
Name="VCPostBuildEventTool"
CommandLine="copy /Y $(TargetPath) c:\gstreamer\plugins"/>
<Tool
Name="VCPreBuildEventTool"/>
<Tool
Name="VCPreLinkEventTool"/>
<Tool
Name="VCResourceCompilerTool"/>
<Tool
Name="VCWebServiceProxyGeneratorTool"/>
<Tool
Name="VCXMLDataGeneratorTool"/>
<Tool
Name="VCWebDeploymentTool"/>
<Tool
Name="VCManagedWrapperGeneratorTool"/>
<Tool
Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
</Configuration>
<Configuration
Name="Release|Win32"
OutputDirectory="../../../win32/Release"
IntermediateDirectory="../../../win32/Release"
ConfigurationType="2"
CharacterSet="2">
<Tool
Name="VCCLCompilerTool"
AdditionalIncludeDirectories="../../../../gstreamer/win32;../../../../gstreamer;../../../../gstreamer/libs;../../../../glib;../../../../glib/glib;../../../../glib/gmodule;&quot;../../../gst-libs&quot;;../../../../popt/include;../../../../libxml2/include/libxml2"
PreprocessorDefinitions="WIN32;NDEBUG;GST_DISABLE_GST_DEBUG;_WINDOWS;_USRDLL;HAVE_CONFIG_H;_USE_MATH_DEFINES"
RuntimeLibrary="2"
UsePrecompiledHeader="0"
WarningLevel="3"
Detect64BitPortabilityProblems="TRUE"
DebugInformationFormat="3"/>
<Tool
Name="VCCustomBuildTool"/>
<Tool
Name="VCLinkerTool"
AdditionalDependencies="glib-2.0.lib gmodule-2.0.lib gthread-2.0.lib gobject-2.0.lib libgstreamer.lib gstbytestream.lib iconv.lib intl.lib"
OutputFile="$(OutDir)/gstplay.dll"
LinkIncremental="1"
AdditionalLibraryDirectories="../../../../gstreamer/win32/Release;../../../../glib/glib;../../../../glib/gmodule;../../../../glib/gthread;../../../../glib/gobject;../../../../gettext/lib;../../../../libiconv/lib"
ModuleDefinitionFile="play.def"
GenerateDebugInformation="TRUE"
SubSystem="2"
OptimizeReferences="2"
EnableCOMDATFolding="2"
ImportLibrary="$(OutDir)/gstplay.lib"
TargetMachine="1"/>
<Tool
Name="VCMIDLTool"/>
<Tool
Name="VCPostBuildEventTool"
CommandLine="copy /Y $(TargetPath) c:\gstreamer\plugins"/>
<Tool
Name="VCPreBuildEventTool"/>
<Tool
Name="VCPreLinkEventTool"/>
<Tool
Name="VCResourceCompilerTool"/>
<Tool
Name="VCWebServiceProxyGeneratorTool"/>
<Tool
Name="VCXMLDataGeneratorTool"/>
<Tool
Name="VCWebDeploymentTool"/>
<Tool
Name="VCManagedWrapperGeneratorTool"/>
<Tool
Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
</Configuration>
</Configurations>
<References>
</References>
<Files>
<Filter
Name="Source Files"
Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx"
UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}">
<File
RelativePath=".\play.c">
</File>
</Filter>
<Filter
Name="Header Files"
Filter="h;hpp;hxx;hm;inl;inc;xsd"
UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}">
<File
RelativePath=".\play.h">
</File>
</Filter>
</Files>
<Globals>
</Globals>
</VisualStudioProject>

View file

@ -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);

View file

@ -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

View file

@ -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");

View file

@ -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;

View file

@ -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 */

View file

@ -65,7 +65,7 @@
* <row>
* <entry>number</entry>
* <entry>G_TYPE_INT</entry>
* <entry>0-16</entry>
* <entry>0-15</entry>
* <entry>The event number.</entry>
* </row>
* <row>
@ -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:

View file

@ -81,6 +81,8 @@ struct _GstDTMFSrc
gboolean paused;
GstClockID clockid;
GstClockTime last_stop;
gint sample_rate;
};

View file

@ -63,7 +63,7 @@
* <row>
* <entry>number</entry>
* <entry>G_TYPE_INT</entry>
* <entry>0-16</entry>
* <entry>0-15</entry>
* <entry>The event number.</entry>
* </row>
* <row>
@ -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

View file

@ -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;
};

View file

@ -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);

View file

@ -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;
}

View file

@ -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);

View file

@ -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;
}

View file

@ -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);

View file

@ -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)

View file

@ -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)

View file

@ -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);

View file

@ -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);
};

View file

@ -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 \

View file

@ -1,7 +1,10 @@
/* GStreamer H.264 Parser
* Copyright (C) <2010> Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
* 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 <mark.nauwelaerts@collabora.co.uk>
* Copyright (C) <2011> Thibault Saunier <thibault.saunier@collabora.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
@ -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 <mark.nauwelaerts@collabora.co.uk>");
@ -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);
}
}

View file

@ -1,7 +1,10 @@
/* GStreamer H.264 Parser
* Copyright (C) <2010> Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
* 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 <mark.nauwelaerts@collabora.co.uk>
* Copyright (C) <2011> Thibault Saunier <thibault.saunier@collabora.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
@ -24,8 +27,7 @@
#include <gst/gst.h>
#include <gst/base/gstbaseparse.h>
#include "h264parse.h"
#include <gst/codecparsers/gsth264parser.h>
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;

View file

@ -1,8 +1,10 @@
/* GStreamer
* Copyright (C) <2007> Jan Schmidt <thaytan@mad.scientist.com>
* Copyright (C) <2011> Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
* Copyright (C) <2011> Collabora Multimedia
* Copyright (C) <2011> Thibault Saunier <thibault.saunier@collabora.com>
* Copyright (C) <2011> Collabora ltd
* Copyright (C) <2011> Nokia Corporation
* Copyright (C) <2011> Intel Corporation
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
@ -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 */

View file

@ -1,8 +1,10 @@
/* GStreamer
* Copyright (C) <2007> Jan Schmidt <thaytan@mad.scientist.com>
* Copyright (C) <2011> Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
* Copyright (C) <2011> Collabora Multimedia
* Copyright (C) <2011> Thibault Saunier <thibault.saunier@collabora.com>
* Copyright (C) <2011> Collabora ltd
* Copyright (C) <2011> Nokia Corporation
* Copyright (C) <2011> Intel Corporation
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
@ -26,7 +28,7 @@
#include <gst/gst.h>
#include <gst/base/gstbaseparse.h>
#include "mpegvideoparse.h"
#include <gst/codecparsers/gstmpegvideoparser.h>
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;

File diff suppressed because it is too large Load diff

View file

@ -1,186 +0,0 @@
/* GStreamer H.264 Parser
* Copyright (C) <2010> Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
* 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 <michal.benes@itonis.tv>
* (C) 2008 Wim Taymans <wim.taymans@gmail.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#ifndef __GST_H264_PARAMS_H__
#define __GST_H264_PARAMS_H__
#include <gst/gst.h>
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

View file

@ -1,274 +0,0 @@
/* GStreamer
* Copyright (C) <2007> Jan Schmidt <thaytan@mad.scientist.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include "mpegvideoparse.h"
#include <string.h>
#include <gst/base/gstbitreader.h>
GST_DEBUG_CATEGORY_EXTERN (mpegv_parse_debug);
#define GST_CAT_DEFAULT mpegv_parse_debug
#define GET_BITS(b, num, bits) G_STMT_START { \
if (!gst_bit_reader_get_bits_uint32(b, bits, num)) \
goto failed; \
GST_TRACE ("parsed %d bits: %d", num, *(bits)); \
} G_STMT_END
#define MARKER_BIT(b) G_STMT_START { \
guint32 i; \
GET_BITS(b, 1, &i); \
if (i != 0x1) \
goto failed; \
} G_STMT_END
static inline gboolean
find_start_code (GstBitReader * b)
{
guint32 bits;
/* 0 bits until byte aligned */
while (b->bit != 0) {
GET_BITS (b, 1, &bits);
}
/* 0 bytes until startcode */
while (gst_bit_reader_peek_bits_uint32 (b, &bits, 32)) {
if (bits >> 8 == 0x1) {
return TRUE;
} else {
gst_bit_reader_skip (b, 8);
}
}
return FALSE;
failed:
return FALSE;
}
static gboolean
gst_mpeg_video_params_parse_extension (MPEGVParams * params, GstBitReader * br)
{
guint32 bits;
/* double-check */
GET_BITS (br, 32, &bits);
if (bits != 0x100 + MPEG_PACKET_EXTENSION)
goto failed;
/* extension_start_code identifier */
GET_BITS (br, 4, &bits);
/* profile_and_level_indication */
GET_BITS (br, 4, &bits);
params->profile = bits;
GET_BITS (br, 4, &bits);
params->level = bits;
/* progressive_sequence */
GET_BITS (br, 1, &bits);
params->progressive = bits;
/* chroma_format */
GET_BITS (br, 2, &bits);
/* horizontal_size_extension */
GET_BITS (br, 2, &bits);
params->width += (bits << 12);
/* vertical_size_extension */
GET_BITS (br, 2, &bits);
params->height += (bits << 12);
/* bit_rate_extension */
GET_BITS (br, 12, &bits);
if (params->bitrate)
params->bitrate += (bits << 18) * 400;
/* marker_bit */
MARKER_BIT (br);
/* vbv_buffer_size_extension */
GET_BITS (br, 8, &bits);
/* low_delay */
GET_BITS (br, 1, &bits);
/* frame_rate_extension_n */
GET_BITS (br, 2, &bits);
params->fps_n *= bits + 1;
/* frame_rate_extension_d */
GET_BITS (br, 5, &bits);
params->fps_d *= bits + 1;
return TRUE;
/* ERRORS */
failed:
{
GST_WARNING ("Failed to parse sequence extension");
return FALSE;
}
}
/* Set the Pixel Aspect Ratio in our hdr from a DAR code in the data */
static void
set_par_from_dar (MPEGVParams * params, guint8 asr_code)
{
/* Pixel_width = DAR_width * display_vertical_size */
/* Pixel_height = DAR_height * display_horizontal_size */
switch (asr_code) {
case 0x02: /* 3:4 DAR = 4:3 pixels */
params->par_w = 4 * params->height;
params->par_h = 3 * params->width;
break;
case 0x03: /* 9:16 DAR */
params->par_w = 16 * params->height;
params->par_h = 9 * params->width;
break;
case 0x04: /* 1:2.21 DAR */
params->par_w = 221 * params->height;
params->par_h = 100 * params->width;
break;
case 0x01: /* Square pixels */
params->par_w = params->par_h = 1;
break;
default:
GST_DEBUG ("unknown/invalid aspect_ratio_information %d", asr_code);
break;
}
}
static void
set_fps_from_code (MPEGVParams * params, guint8 fps_code)
{
const gint framerates[][2] = {
{30, 1}, {24000, 1001}, {24, 1}, {25, 1},
{30000, 1001}, {30, 1}, {50, 1}, {60000, 1001},
{60, 1}, {30, 1}
};
if (fps_code && fps_code < 10) {
params->fps_n = framerates[fps_code][0];
params->fps_d = framerates[fps_code][1];
} else {
GST_DEBUG ("unknown/invalid frame_rate_code %d", fps_code);
/* Force a valid framerate */
/* FIXME or should this be kept unknown ?? */
params->fps_n = 30000;
params->fps_d = 1001;
}
}
static gboolean
gst_mpeg_video_params_parse_sequence (MPEGVParams * params, GstBitReader * br)
{
guint32 bits;
GET_BITS (br, 32, &bits);
if (bits != 0x100 + MPEG_PACKET_SEQUENCE)
goto failed;
/* assume MPEG-1 till otherwise discovered */
params->mpeg_version = 1;
GET_BITS (br, 12, &bits);
params->width = bits;
GET_BITS (br, 12, &bits);
params->height = bits;
GET_BITS (br, 4, &bits);
set_par_from_dar (params, bits);
GET_BITS (br, 4, &bits);
set_fps_from_code (params, bits);
GET_BITS (br, 18, &bits);
if (bits == 0x3ffff) {
/* VBR stream */
params->bitrate = 0;
} else {
/* Value in header is in units of 400 bps */
params->bitrate *= 400;
}
/* skip 1 + VBV buffer size */
if (!gst_bit_reader_skip (br, 11))
goto failed;
/* constrained_parameters_flag */
GET_BITS (br, 1, &bits);
/* load_intra_quantiser_matrix */
GET_BITS (br, 1, &bits);
if (bits) {
if (!gst_bit_reader_skip (br, 8 * 64))
goto failed;
}
/* load_non_intra_quantiser_matrix */
GET_BITS (br, 1, &bits);
if (bits) {
if (!gst_bit_reader_skip (br, 8 * 64))
goto failed;
}
/* check for MPEG-2 sequence extension */
while (find_start_code (br)) {
gst_bit_reader_peek_bits_uint32 (br, &bits, 32);
if (bits == 0x100 + MPEG_PACKET_EXTENSION) {
if (!gst_mpeg_video_params_parse_extension (params, br))
goto failed;
params->mpeg_version = 2;
}
}
/* dump some info */
GST_LOG ("width x height: %d x %d", params->width, params->height);
GST_LOG ("fps: %d/%d", params->fps_n, params->fps_d);
GST_LOG ("par: %d/%d", params->par_w, params->par_h);
GST_LOG ("profile/level: %d/%d", params->profile, params->level);
GST_LOG ("bitrate/progressive: %d/%d", params->bitrate, params->progressive);
return TRUE;
/* ERRORS */
failed:
{
GST_WARNING ("Failed to parse sequence header");
/* clear out stuff */
memset (params, 0, sizeof (*params));
return FALSE;
}
}
gboolean
gst_mpeg_video_params_parse_config (MPEGVParams * params, const guint8 * data,
guint size)
{
GstBitReader br;
if (size < 4)
return FALSE;
gst_bit_reader_init (&br, data, size);
return gst_mpeg_video_params_parse_sequence (params, &br);
}

View file

@ -1,77 +0,0 @@
/* GStreamer
* Copyright (C) <2007> Jan Schmidt <thaytan@mad.scientist.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#ifndef __GST_MPEGVIDEO_PARAMS_H__
#define __GST_MPEGVIDEO_PARAMS_H__
#include <gst/gst.h>
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

View file

@ -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)

View file

@ -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}

View file

@ -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}

View file

@ -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}

View file

@ -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

View file

@ -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);
}

View file

@ -0,0 +1,182 @@
/* Gstreamer
* Copyright (C) <2011> Intel Corporation
* Copyright (C) <2011> Collabora Ltd.
* Copyright (C) <2011> Thibault Saunier <thibault.saunier@collabora.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#include <gst/check/gstcheck.h>
#include <gst/codecparsers/gsth264parser.h>
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;
}

View file

@ -0,0 +1,208 @@
/* Gstreamer
* Copyright (C) <2011> Intel Corporation
* Copyright (C) <2011> Collabora Ltd.
* Copyright (C) <2011> Thibault Saunier <thibault.saunier@collabora.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#include <gst/check/gstcheck.h>
#include <gst/codecparsers/gstmpegvideoparser.h>
/* 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;
}