mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-12-25 01:30:38 +00:00
Merge branch 'master' into 0.11
This commit is contained in:
commit
d4590a1959
59 changed files with 5976 additions and 2413 deletions
2
common
2
common
|
@ -1 +1 @@
|
|||
Subproject commit 605cd9a65ed61505f24b840d3fe8e252be72b151
|
||||
Subproject commit a39eb835fb3be2a4c5a6a89b5ca5cc064e79b2e2
|
|
@ -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
|
||||
|
|
|
@ -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
102
docs/libs/Makefile.am
Normal 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
48
docs/libs/compiling.sgml
Normal 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>
|
60
docs/libs/gst-plugins-bad-libs-docs.sgml
Normal file
60
docs/libs/gst-plugins-bad-libs-docs.sgml
Normal 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>
|
||||
|
0
docs/libs/gst-plugins-bad-libs-overrides.txt
Normal file
0
docs/libs/gst-plugins-bad-libs-overrides.txt
Normal file
361
docs/libs/gst-plugins-bad-libs-sections.txt
Normal file
361
docs/libs/gst-plugins-bad-libs-sections.txt
Normal 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>
|
4
docs/libs/gst-plugins-bad-libs.types
Normal file
4
docs/libs/gst-plugins-bad-libs.types
Normal file
|
@ -0,0 +1,4 @@
|
|||
#include <gst/gst.h>
|
||||
|
||||
#include <gst/codecparsers/gsth264parser.h>
|
||||
#include <gst/codecparsers/gstmpegvideoparser.h>
|
|
@ -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) {
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
30
gst-libs/gst/codecparsers/Makefile.am
Normal file
30
gst-libs/gst/codecparsers/Makefile.am
Normal 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 \
|
||||
> $@
|
1837
gst-libs/gst/codecparsers/gsth264parser.c
Normal file
1837
gst-libs/gst/codecparsers/gsth264parser.c
Normal file
File diff suppressed because it is too large
Load diff
682
gst-libs/gst/codecparsers/gsth264parser.h
Normal file
682
gst-libs/gst/codecparsers/gsth264parser.h
Normal 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
|
755
gst-libs/gst/codecparsers/gstmpegvideoparser.c
Normal file
755
gst-libs/gst/codecparsers/gstmpegvideoparser.c
Normal 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;
|
||||
}
|
368
gst-libs/gst/codecparsers/gstmpegvideoparser.h
Normal file
368
gst-libs/gst/codecparsers/gstmpegvideoparser.h
Normal 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
|
3
gst-libs/gst/play/.gitignore
vendored
3
gst-libs/gst/play/.gitignore
vendored
|
@ -1,3 +0,0 @@
|
|||
play-enumtypes.[ch]
|
||||
play-marshal.[ch]
|
||||
play-marshal.list
|
|
@ -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__ */
|
|
@ -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;"../../../gst-libs";../../../../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;"../../../gst-libs";../../../../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>
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -81,6 +81,8 @@ struct _GstDTMFSrc
|
|||
gboolean paused;
|
||||
GstClockID clockid;
|
||||
|
||||
GstClockTime last_stop;
|
||||
|
||||
gint sample_rate;
|
||||
};
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -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 \
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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
|
@ -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
|
|
@ -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);
|
||||
}
|
|
@ -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
|
|
@ -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)
|
||||
|
|
12
pkgconfig/gstreamer-codecparsers-uninstalled.pc.in
Normal file
12
pkgconfig/gstreamer-codecparsers-uninstalled.pc.in
Normal 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}
|
||||
|
12
pkgconfig/gstreamer-codecparsers.pc.in
Normal file
12
pkgconfig/gstreamer-codecparsers.pc.in
Normal 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}
|
||||
|
|
@ -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}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
182
tests/check/libs/h264parser.c
Normal file
182
tests/check/libs/h264parser.c
Normal 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;
|
||||
}
|
208
tests/check/libs/mpegvideoparser.c
Normal file
208
tests/check/libs/mpegvideoparser.c
Normal 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;
|
||||
}
|
Loading…
Reference in a new issue