Merge branch 'master' into 0.11

Conflicts:
	configure.ac
	ext/alsa/gstalsasrc.c
	gst-libs/gst/audio/gstbaseaudiosink.c
	gst-libs/gst/tag/gstxmptag.c
	gst/playback/gstsubtitleoverlay.c
	gst/videorate/gstvideorate.c
	sys/xvimage/xvimagesink.c
This commit is contained in:
Sebastian Dröge 2011-05-16 17:06:22 +02:00
commit d0362c2b87
70 changed files with 7903 additions and 711 deletions

2240
ChangeLog

File diff suppressed because it is too large Load diff

163
NEWS
View file

@ -1,4 +1,165 @@
This is GStreamer Base Plug-ins 0.10.32, "Your Life You Like It Well"
This is GStreamer Base Plug-ins 0.10.34, "Lemmings"
Changes since 0.10.33:
* None: this release is identical to 0.10.33 and just done to keep core/base
versions in sync
Changes since 0.10.32:
* audioringbuffer: make sure to not start if the may_start flag is FALSE
* baseaudiosink: arrange for running clock when rendering eos
* baseaudiosink: don't allow aligning behind the read-segment
* baseaudiosink: start ringbuffer upon going to PLAYING and already EOS
* riff: Add support for video/x-camstudio
* rtcpbuffer: fix invalid read in validation of padding in rtcp packet
* rtcpbuffer: Round to next 32bit word, not current 32bit word at end of SDES chunk
* rtpbuffer: Off-by-one error when creating RTP header extensions with a two-byte header
* rtsptransport: ensure valid int result when parsing ranges
* tag: map the ID3v2 TENC frame to GST_TAG_ENCODED_BY
* tag: add GST_TAG_CAPTURING_EXPOSURE_COMPENSATION incl. EXIF/XMP mappings
* tag: add a new GstTagXmpWriter interface to select XMP schemas to be used
* tagdemux: also push cached events downstream when operating in pull mode
* video: add GST_VIDEO_BUFFER_PROGRESSIVE flag
* video: add ARGB64 and AYUV64 (16 bits per channel) formats
* video: add r210 (10 bits per channel) format
* video: add gst_video_format_get_component_depth() and _new_template_caps()
* video: fix creation of grayscale caps and height calculation for YUV9/YVU9
* appsink: emit "new-buffer-list" signal for buffer lists if handled by app
* audiorate: add "skip-to-first" property
* decodebin2: don't use the same parser element multiple times in the same chain
* decodebin2: improve detection of raw caps in expose-all-streams=false mode
* discoverer: don't wait for subtitle streams to preroll; leak fixes
* discoverer: use nominal bitrate if bitrate tag is unavailable
* encodebin: add an audioconvert after the audio resampler
* encodebin: fix refcounting issues and leaks related to request pads
* encodebin: return a new reference of the pad for the "request-pad" signal
* encodebin: set all elements to NULL and remove them from the bin when removing a source group
* encodebin: tear down old profiles when setting new ones
* multifdsink: disconnect inactive clients in the select loop too
* oggmux: prefer headers from caps to determine stream type (for VP8)
* oggmux: fix issue with ogg page numbering and discont flag handling
* oggmux: ensure stream serial numbers are unique
* oggmux: use running time for muxing instead of timestamps
* oggparse: better detection of delta unit flag
* playbin2, uridecodebin: add "source-setup" signal
* playbin2: always prefer the custom set sink and also set it back to NULL in all cases
* playbin2: check if an already existing sink supports the non-raw format too
* playbin2: fix handling of non-raw custom sinks
* playbin2: if a sink claims to support ANY caps assume that it only supports the usual raw formats
* playbin2: only consider the audio/video sinks in autoplug_continue for the normal uridecodebin
* playbin2: use gst_pad_accept_caps() instead of intersecting with the getcaps caps
* playbin2: set sinks to READY before checking if it accept caps
* textoverlay: add support for ARGB and other RGB alpha variants, and xBGR and RGBx
* textoverlay: add support for vertical center alignment
* textoverlay: converted AYUV to use 'A OVER B' alpha compositing
* textoverlay: use a class wide mutex to work around pango reentrance issues
* theoraenc: don't reset the video quality when setting the bitrate
* theoraenc: allow adjustment of the speed level while running
* theoraenc: set speed-level property defaults from libtheora's defaults
* typefinding: MPEG-TS detection fixes
* typefinding: detect HTTP live streaming m3u8 playlists
* typefinding: detect windows icon files and DEGAS images (to avoid false positives)
* typefinding: detect raw h.263
* typefinding: add depth and endianness fields to DTS caps
* uridecodebin: Add default handler for autoplug-select
* uridecodebin: add https:// to protocols for which to enable buffering
* uridecodebin: expose "autoplug-sort" signal
* uridecodebin: post proper error message if decodebin2/typefind elements are missing
* uridecodebin: Return NULL from the default autoplug-sort handler
* videorate: fix "skip-to-first" timestamp setup
* videoscale: add 16-bit-channel support (ARGB64, AYUV64), fix ARGB bilinear scaling
* videotestsrc: add 16-bit-per-channel support (ARGB64, AYUV64)
* vorbis: add support for using tremolo on android
* vorbistag: Add support for METADATA_BLOCK_PICTURE tags
* vorbistag: Write GST_TAG_IMAGE and GST_TAG_PREVIEW_IMAGE as METADATA_BLOCK_PICTURE
* win32: fix DEFAULT_AUDIOSINK, should be direct*sound*sink
* xvimagesink: don't paint the window black when going to NULL
Bugs fixed since 0.10.32:
* 618516 : [typefinding] need raw H.263 typefinder
* 619778 : oggdemux: fails on zero-length pages with Patent_Absurdity_HD_3540kbit.ogv
* 633837 : videoscale: invalid reads after conversion to orc linear scaling
* 412678 : random segfaults or memory corruptions with multiple textoverlays (pango not reentrant)
* 620364 : [typefinding] .ico file detected as AAC
* 625129 : typefinding: file incorrectly detected as audio/x-dts
* 626152 : [playbin2] add " source-setup " signal
* 627268 : [tag] add GST_TAG_ENCODED_BY and map id3v2 TENC frame
* 629196 : oggmux: re-tagging an Ogg Vorbis file may corrupt audio data
* 632291 : discoverer: sparse tracks cause prerolling to hang till timeout
* 632889 : [multifdsink] [PATCH] Disconnect inactive clients in the select loop too
* 635669 : [vorbistag] Support METADATA_BLOCK_PICTURE for Vorbis cover art
* 635784 : ringbuffer: make sure to not start if the may_start flag is FALSE
* 635800 : xvimagesink flashes black when going from READY_TO_NULL
* 636886 : baseaudiosink: no running clock when eos leads to hang in PLAYING
* 639136 : [oggparse]code is not safe when using libogg fuctions
* 639159 : [textoverloay] Add vertical center alignment option
* 639237 : textoverlay: patch to use " A OVER B " alpha compositing
* 639744 : [oggdemux] Removing dead code:
* 640189 : oggmux: cleanup
* 640211 : oggmux: ensure serialnos are unique
* 640607 : appsink never sends " new-buffer-list " signal
* 640709 : [typefindfunctions] h264 typefinder registered with MPEG_VIDEO_CAPS
* 640804 : checks: encodebin test fails if theora or vorbis plugins are not available
* 641706 : discoverer: Keep references on discoverer objects for callbacks
* 641860 : discoverer: Use nominal bitrate if bitrate tag is unavailable
* 641917 : [gdppay] Ensure buffer's medata is writeable before setting it
* 641927 : [encodebin] refcount issue with the " request-pad " signal
* 641952 : [videoscale] assertion on fixate_caps
* 642174 : Playbin2 cannot work with non-raw custom sinks
* 642232 : theoraenc sets Video quality to zero when explicitely setting the bitrate to 0
* 642274 : [playbin2] arbitrary audio-sink is chosen even though explicitely having set a custom audio-sink bin
* 642381 : potential memleak in decodebin2
* 642466 : playbin2: after replacing a video sink with the pipeline in NULL state I still get the old one
* 642720 : audiotestsrc: pipelines with multiple instances with wave=gaussian-noise, white-noise, or pink-noise are very slow
* 642942 : adder: offset_end field of outgoing buffers is set to GST_BUFFER_OFFSET_NONE
* 642949 : pbutils: encoding-target: chaining error object in loading target from file may cause crash if there is no error
* 643775 : [oggmux] use running time instead of timestamps
* 644416 : [encodebin] Cannot be reused
* 644745 : [oggmux] Fails to mux Speex content, doesn't preroll
* 644845 : [alsa] Comparison of unsigned int < 0 always false in gstalsamixer.c
* 644996 : libsABI check doesn't depend only on architecture
* 645167 : [xmp] Add a new XmpConfig interface
* 645437 : encoding-profile: Fix syntax in Example: Creating a profile
* 646570 : baseaudiosink: don't allow aligning behind the read-segment
* 646572 : baseaudiosrc: protect against ringbuffer disappearing while in a query
* 646573 : baseaudiosrc: Add src object lock around call to ringbuffer parse caps
* 646575 : rtcpbuffer: Round to next 32bit word, not current 32bit word at end of SDES chunk
* 646576 : rtcpbuffer: fix invalid read in validation of padding in rtcp packet
* 646923 : video: Remove unused variable
* 646924 : rtp: Remove unused variables
* 646925 : encoding-profile: Remove unused variables
* 646952 : Fix the strlol return type mismatch :
* 647399 : Bad typo in ID3 tags: psychadelic - > psychedelic
* 647721 : Remove excessive checking for video.c
* 647781 : [playbin2] missing shutdown steps and inconsistent error behaviour
* 647856 : [oggmux] Assumes that the first buffer can be used to detect the stream type
* 647857 : [xvimagesink/ximagesink] Handle NULL caps in buffer_alloc()
* 647942 : [pango] Use different Pango contexts for the different subclasses
* 647943 : [pango] Class global pango mutex not always used
* 648459 : tag: exif: register common tags from tag library
* 648466 : Ogg to LPCM transcoding fails
* 648548 : videoscale broken with orc 0.4.13
* 642667 : [playbin2] autoplug-factories code does not do what it claims to do
* 642732 : [playbin2] sinks set to READY after activating groups causes bad autoplug-continue decisions
* 646744 : libgsttag: Minor issues building gst-plugins-base with MS compiler
* 647294 : gst-plugins-base doesn't compile with GCC 4.6
API additions since 0.10.32:
* gst_tag_list_to_xmp_buffer_full()
* gst_tag_xmp_list_schemas()
* gst_tag_xmp_writer_add_all_schemas()
* gst_tag_xmp_writer_add_schema()
* gst_tag_xmp_writer_get_type()
* gst_tag_xmp_writer_has_schema()
* gst_tag_xmp_writer_remove_all_schemas()
* gst_tag_xmp_writer_remove_schema()
* gst_tag_xmp_writer_tag_list_to_xmp_buffer()
* GST_TAG_CAPTURING_EXPOSURE_COMPENSATION
* gst_video_format_get_component_depth()
* gst_video_format_new_template_caps()
Changes since 0.10.31:

159
RELEASE
View file

@ -1,5 +1,5 @@
Release notes for GStreamer Base Plug-ins 0.10.32 "Your Life You Like It Well"
Release notes for GStreamer Base Plug-ins 0.10.34 "Lemmings"
@ -9,6 +9,8 @@ GStreamer Base Plug-ins.
The 0.10.x series is a stable series targeted at end users.
It is not API or ABI compatible with the stable 0.8.x series.
It is, however, parallel installable with the 0.8.x series.
@ -53,130 +55,9 @@ contains a set of less supported plug-ins that haven't passed the
Features of this release
* GLib requirement is now >= 2.22, gobject-introspection >= 0.9.12
* New encodebin element
* New encoding profile and encoding targets API in pbutils
* audioresample: corrected buffer duration calculation to account for nonzero initial timestamp
* audioresample: provide as much valid output ts and offset as valid input
* audioresample: push half a history length, instead of a full history length, at end-of-stream so that output segment and input segment have same duration
* decodebin2: deprecate new-decoded-pad and removed-decoded-pad signals (use "pad-added" and "pad-removed" instead)
* multifdsink: add first and last buffer's timestamp to the stats; only keep last valid timestamp
* oggdemux: extract more tags (vorbis comment headers, Kate)
* oggdemux: ignore header pages when looking for keyframe; set headers on caps
* oggdemux: fix interpretation of Theora granule position and parsing of Theora size
* oggparse: Set DELTA_UNIT on buffers
* playbin2: delay stream-changed messages, fixing KATE subtitle recognition
* textoverlay: make text, xpos, ypos, color, and silent properties controllable
* typefinding: (E)AC-3 and ISO typefinder improvements; add yuv4mpeg typefinder
* typefinding: add "stream-format" to h264 caps, and framed=false to DTS caps
* typefinding: assume EBML files without doctype are matroska
* videorate: fix behaviour for frame rate cap changes
* vorbisdec: avoid using invalid timestamps; keep timestamps when no decoded output
* ximagesink, xvimagesink: add read-only window-width and window-height properties
* baseaudiopay: fix timestamps on buffer lists
* baseaudiosink: protect against ringbuffer disappearing while in a query
* basedepay: add support for buffer lists in the depayloader
* basertppay: use RTP base time when invalid timestamps
* rtpbuffer: relax arrangement for RTP bufferlists
* rtpdepayloader: add support for getting events
* rtppayload: copy applied rate to segment
* sdp: add method to check for multicast addresses
* sdp: only parse TTL for IP4 addresses
* video: add 8-bit paletted RGB, YUV9, YVU9 and IYU1 video formats
* video: return correct component width/height for A420
Bugs fixed in this release
* 619778 : oggdemux: fails on zero-length pages with Patent_Absurdity_HD_3540kbit.ogv
* 586570 : Add GAP Flag support to audioresample
* 623413 : pbutils: Add/Fix some media descriptions
* 627476 : New profile library and encoding plugin
* 629349 : [oggdemux] extract stream tags for tagreadbin and transcoding
* 632667 : [ximagesink] added read-only properties window-width and window-height
* 634397 : [multifdsink] [PATCH] Add the timestamp of the first and last buffer to the stats
* 634522 : gst-visualize-m.m imports but doesn't use File::Basename
* 635231 : baseaudiosink: protect against ringbuffer disappearing while in a query
* 636198 : decodebin2: " removed-decoded-pad " signal never fired
* 636769 : [appsink] Flushing property is never reset
* 636827 : Usage of gst_caps_interset where gst_caps_can_intersect was intended?
* 637324 : oggdemux: unable to demux Ogg files with Skeleton in push mode
* 637377 : timeoverlay: add missing break
* 637519 : ogg: implement packet duration query for kate streams
* 637586 : playbin2 fails to recognize subtitle caps from katedec
* 637735 : [encoding-profile] automatic load/save support and registry
* 637758 : [exiftag] Generates buffers with uninitialized data during taglist- > exif buffer serialization
* 637822 : oggdemux: allocate buffers using gst_buffer_new_and_alloc
* 637927 : oggdemux: set headers on caps
* 638200 : [oggdemux] fails to playback video file
* 638276 : oggstream: when the last keyframe position is not known, do not use -1
* 638859 : textoverlay: make misc. properties controllable
* 638901 : [encodebin] proper element documentation
* 638903 : [encodebin] missing-plugin support
* 638961 : Small configure bashism 0.10.31.2
* 639039 : gobject-introspection: GstPbutils gir scanner fails to link with gold linker
* 639121 : oggdemux: outdated comment for gst_ogg_demux_submit_buffer()
* 639215 : examples: Allow building with newer GTK+
* 639730 : discoverer: Validate timeouts before processing them
* 639755 : discoverer: Clean up callbacks in dispose()
* 639778 : discoverer: Drop new stream tags once preroll is done
* 639790 : [gdp] Fix metadata g_warning
* 639747 : Please export GST_TYPE_APP_STREAM_TYPE
* 553244 : theoraparse doesn't work at all (throws criticals and asserts)
API changed in this release
- API additions:
* This release is identical to 0.10.33 (to keep core/base versions in sync)
There were no bugs fixed in this release
* gst_app_stream_type_get_type()
* gst_discoverer_info_get_seekable()
* gst_encoding_audio_profile_get_type()
* gst_encoding_audio_profile_new()
* gst_encoding_container_profile_add_profile()
* gst_encoding_container_profile_contains_profile()
* gst_encoding_container_profile_get_profiles()
* gst_encoding_container_profile_get_type()
* gst_encoding_container_profile_new()
* gst_encoding_list_all_targets()
* gst_encoding_list_available_categories()
* gst_encoding_profile_find()
* gst_encoding_profile_get_description()
* gst_encoding_profile_get_format()
* gst_encoding_profile_get_input_caps()
* gst_encoding_profile_get_name()
* gst_encoding_profile_get_presence()
* gst_encoding_profile_get_preset()
* gst_encoding_profile_get_restriction()
* gst_encoding_profile_get_type()
* gst_encoding_profile_get_type_nick()
* gst_encoding_profile_is_equal()
* gst_encoding_profile_set_description()
* gst_encoding_profile_set_format()
* gst_encoding_profile_set_name()
* gst_encoding_profile_set_presence()
* gst_encoding_profile_set_preset()
* gst_encoding_profile_set_restriction()
* gst_encoding_target_add_profile()
* gst_encoding_target_get_category()
* gst_encoding_target_get_description()
* gst_encoding_target_get_name()
* gst_encoding_target_get_profile()
* gst_encoding_target_get_profiles()
* gst_encoding_target_get_type()
* gst_encoding_target_load()
* gst_encoding_target_load_from_file()
* gst_encoding_target_new()
* gst_encoding_target_save()
* gst_encoding_target_save_to_file()
* gst_encoding_video_profile_get_pass()
* gst_encoding_video_profile_get_type()
* gst_encoding_video_profile_get_variableframerate()
* gst_encoding_video_profile_new()
* gst_encoding_video_profile_set_pass()
* gst_encoding_video_profile_set_variableframerate()
* gst_base_rtp_depayload_push_list()
* gst_rtsp_url_decode_path_components()
* gst_sdp_address_is_multicast()
* gst_video_parse_caps_palette()
Download
@ -205,35 +86,5 @@ Applications
Contributors to this release
* Alessandro Decina
* Andoni Morales Alastruey
* Andrea Sebastianutti
* Andy Wingo
* Arun Raghavan
* Bastien Nocera
* Benjamin Gaignard
* Byeong-ryeol Kim
* David Schleef
* Edward Hervey
* Evan Broder
* Gavin Stark
* Havard Graff
* Koop Mast
* Lane Brooks
* Leo Singer
* Mark Nauwelaerts
* Michael Smith
* René Stadler
* Rob Clark
* Robert Swain
* Sebastian Dröge
* Sreerenj Balachandran
* Stefan Kost
* Thiago Santos
* Tim-Philipp Müller
* Vincent Penquerc'h
* Wim Taymans
* Yang Xichuan
* Zeeshan Ali (Khattak)
* christian schaller
 

View file

@ -49,7 +49,7 @@ dnl - interfaces added/removed/changed -> increment CURRENT, REVISION = 0
dnl - interfaces added -> increment AGE
dnl - interfaces removed -> AGE = 0
dnl sets GST_LT_LDFLAGS
AS_LIBTOOL(GST, 23, 0, 23)
AS_LIBTOOL(GST, 24, 0, 24)
dnl FIXME: this macro doesn't actually work;
dnl the generated libtool script has no support for the listed tags.

View file

@ -52,6 +52,7 @@
<xi:include href="xml/gstbaseaudiosrc.xml" />
<xi:include href="xml/gstmultichannel.xml" />
<xi:include href="xml/gstringbuffer.xml" />
<xi:include href="xml/gstaudioiec61937.xml" />
</chapter>
<chapter id="gstreamer-cdda">

View file

@ -317,6 +317,13 @@ gst_ring_buffer_debug_spec_buff
gst_ring_buffer_debug_spec_caps
</SECTION>
<SECTION>
<FILE>gstaudioiec61937</FILE>
<INCLUDE>gst/audio/gstaudioiec61937.h</INCLUDE>
gst_audio_iec61937_frame_size
gst_audio_iec61937_payload
</SECTION>
# cdda

View file

@ -3,10 +3,10 @@
<description>Adds multiple streams</description>
<filename>../../gst/adder/.libs/libgstadder.so</filename>
<basename>libgstadder.so</basename>
<version>0.10.32.4</version>
<version>0.10.34.1</version>
<license>LGPL</license>
<source>gst-plugins-base</source>
<package>GStreamer Base Plug-ins prerelease</package>
<package>GStreamer Base Plug-ins git</package>
<origin>Unknown package origin</origin>
<elements>
<element>

View file

@ -3,10 +3,10 @@
<description>ALSA plugin library</description>
<filename>../../ext/alsa/.libs/libgstalsa.so</filename>
<basename>libgstalsa.so</basename>
<version>0.10.32.4</version>
<version>0.10.34.1</version>
<license>LGPL</license>
<source>gst-plugins-base</source>
<package>GStreamer Base Plug-ins prerelease</package>
<package>GStreamer Base Plug-ins git</package>
<origin>Unknown package origin</origin>
<elements>
<element>

View file

@ -3,10 +3,10 @@
<description>Elements used to communicate with applications</description>
<filename>../../gst/app/.libs/libgstapp.so</filename>
<basename>libgstapp.so</basename>
<version>0.10.32.4</version>
<version>0.10.34.1</version>
<license>LGPL</license>
<source>gst-plugins-base</source>
<package>GStreamer Base Plug-ins prerelease</package>
<package>GStreamer Base Plug-ins git</package>
<origin>Unknown package origin</origin>
<elements>
<element>

View file

@ -3,10 +3,10 @@
<description>Convert audio to different formats</description>
<filename>../../gst/audioconvert/.libs/libgstaudioconvert.so</filename>
<basename>libgstaudioconvert.so</basename>
<version>0.10.32.4</version>
<version>0.10.34.1</version>
<license>LGPL</license>
<source>gst-plugins-base</source>
<package>GStreamer Base Plug-ins prerelease</package>
<package>GStreamer Base Plug-ins git</package>
<origin>Unknown package origin</origin>
<elements>
<element>

View file

@ -3,10 +3,10 @@
<description>Adjusts audio frames</description>
<filename>../../gst/audiorate/.libs/libgstaudiorate.so</filename>
<basename>libgstaudiorate.so</basename>
<version>0.10.32.4</version>
<version>0.10.34.1</version>
<license>LGPL</license>
<source>gst-plugins-base</source>
<package>GStreamer Base Plug-ins prerelease</package>
<package>GStreamer Base Plug-ins git</package>
<origin>Unknown package origin</origin>
<elements>
<element>

View file

@ -3,10 +3,10 @@
<description>Resamples audio</description>
<filename>../../gst/audioresample/.libs/libgstaudioresample.so</filename>
<basename>libgstaudioresample.so</basename>
<version>0.10.32.4</version>
<version>0.10.34.1</version>
<license>LGPL</license>
<source>gst-plugins-base</source>
<package>GStreamer Base Plug-ins prerelease</package>
<package>GStreamer Base Plug-ins git</package>
<origin>Unknown package origin</origin>
<elements>
<element>

View file

@ -3,10 +3,10 @@
<description>Creates audio test signals of given frequency and volume</description>
<filename>../../gst/audiotestsrc/.libs/libgstaudiotestsrc.so</filename>
<basename>libgstaudiotestsrc.so</basename>
<version>0.10.32.4</version>
<version>0.10.34.1</version>
<license>LGPL</license>
<source>gst-plugins-base</source>
<package>GStreamer Base Plug-ins prerelease</package>
<package>GStreamer Base Plug-ins git</package>
<origin>Unknown package origin</origin>
<elements>
<element>

View file

@ -3,10 +3,10 @@
<description>Read audio from CD in paranoid mode</description>
<filename>../../ext/cdparanoia/.libs/libgstcdparanoia.so</filename>
<basename>libgstcdparanoia.so</basename>
<version>0.10.32.4</version>
<version>0.10.34.1</version>
<license>LGPL</license>
<source>gst-plugins-base</source>
<package>GStreamer Base Plug-ins prerelease</package>
<package>GStreamer Base Plug-ins git</package>
<origin>Unknown package origin</origin>
<elements>
<element>

View file

@ -3,10 +3,10 @@
<description>decoder bin</description>
<filename>../../gst/playback/.libs/libgstdecodebin.so</filename>
<basename>libgstdecodebin.so</basename>
<version>0.10.32.4</version>
<version>0.10.34.1</version>
<license>LGPL</license>
<source>gst-plugins-base</source>
<package>GStreamer Base Plug-ins prerelease</package>
<package>GStreamer Base Plug-ins git</package>
<origin>Unknown package origin</origin>
<elements>
<element>

View file

@ -3,10 +3,10 @@
<description>various encoding-related elements</description>
<filename>../../gst/encoding/.libs/libgstencodebin.so</filename>
<basename>libgstencodebin.so</basename>
<version>0.10.32.4</version>
<version>0.10.34.1</version>
<license>LGPL</license>
<source>gst-plugins-base</source>
<package>GStreamer Base Plug-ins prerelease</package>
<package>GStreamer Base Plug-ins git</package>
<origin>Unknown package origin</origin>
<elements>
<element>

View file

@ -3,7 +3,7 @@
<description>colorspace conversion copied from FFMpeg 0.4.9-pre1</description>
<filename>../../gst/ffmpegcolorspace/.libs/libgstffmpegcolorspace.so</filename>
<basename>libgstffmpegcolorspace.so</basename>
<version>0.10.32.4</version>
<version>0.10.34.1</version>
<license>LGPL</license>
<source>gst-plugins-base</source>
<package>FFMpeg</package>

View file

@ -3,10 +3,10 @@
<description>Payload/depayload GDP packets</description>
<filename>../../gst/gdp/.libs/libgstgdp.so</filename>
<basename>libgstgdp.so</basename>
<version>0.10.32.4</version>
<version>0.10.34.1</version>
<license>LGPL</license>
<source>gst-plugins-base</source>
<package>GStreamer Base Plug-ins prerelease</package>
<package>GStreamer Base Plug-ins git</package>
<origin>Unknown package origin</origin>
<elements>
<element>

View file

@ -3,10 +3,10 @@
<description>GIO elements</description>
<filename>../../ext/gio/.libs/libgstgio.so</filename>
<basename>libgstgio.so</basename>
<version>0.10.32.4</version>
<version>0.10.34.1</version>
<license>LGPL</license>
<source>gst-plugins-base</source>
<package>GStreamer Base Plug-ins prerelease</package>
<package>GStreamer Base Plug-ins git</package>
<origin>Unknown package origin</origin>
<elements>
<element>

View file

@ -3,10 +3,10 @@
<description>elements to read from and write to Gnome-VFS uri&apos;s</description>
<filename>../../ext/gnomevfs/.libs/libgstgnomevfs.so</filename>
<basename>libgstgnomevfs.so</basename>
<version>0.10.32.4</version>
<version>0.10.34.1</version>
<license>LGPL</license>
<source>gst-plugins-base</source>
<package>GStreamer Base Plug-ins prerelease</package>
<package>GStreamer Base Plug-ins git</package>
<origin>Unknown package origin</origin>
<elements>
<element>

View file

@ -3,10 +3,10 @@
<description>libvisual visualization plugins</description>
<filename>../../ext/libvisual/.libs/libgstlibvisual.so</filename>
<basename>libgstlibvisual.so</basename>
<version>0.10.32.4</version>
<version>0.10.34.1</version>
<license>LGPL</license>
<source>gst-plugins-base</source>
<package>GStreamer Base Plug-ins prerelease</package>
<package>GStreamer Base Plug-ins git</package>
<origin>Unknown package origin</origin>
<elements>
<element>

View file

@ -3,10 +3,10 @@
<description>ogg stream manipulation (info about ogg: http://xiph.org)</description>
<filename>../../ext/ogg/.libs/libgstogg.so</filename>
<basename>libgstogg.so</basename>
<version>0.10.32.4</version>
<version>0.10.34.1</version>
<license>LGPL</license>
<source>gst-plugins-base</source>
<package>GStreamer Base Plug-ins prerelease</package>
<package>GStreamer Base Plug-ins git</package>
<origin>Unknown package origin</origin>
<elements>
<element>

View file

@ -3,10 +3,10 @@
<description>Pango-based text rendering and overlay</description>
<filename>../../ext/pango/.libs/libgstpango.so</filename>
<basename>libgstpango.so</basename>
<version>0.10.32.4</version>
<version>0.10.34.1</version>
<license>LGPL</license>
<source>gst-plugins-base</source>
<package>GStreamer Base Plug-ins prerelease</package>
<package>GStreamer Base Plug-ins git</package>
<origin>Unknown package origin</origin>
<elements>
<element>

View file

@ -3,10 +3,10 @@
<description>various playback elements</description>
<filename>../../gst/playback/.libs/libgstplaybin.so</filename>
<basename>libgstplaybin.so</basename>
<version>0.10.32.4</version>
<version>0.10.34.1</version>
<license>LGPL</license>
<source>gst-plugins-base</source>
<package>GStreamer Base Plug-ins prerelease</package>
<package>GStreamer Base Plug-ins git</package>
<origin>Unknown package origin</origin>
<elements>
<element>

View file

@ -3,10 +3,10 @@
<description>Subtitle parsing</description>
<filename>../../gst/subparse/.libs/libgstsubparse.so</filename>
<basename>libgstsubparse.so</basename>
<version>0.10.32.4</version>
<version>0.10.34.1</version>
<license>LGPL</license>
<source>gst-plugins-base</source>
<package>GStreamer Base Plug-ins prerelease</package>
<package>GStreamer Base Plug-ins git</package>
<origin>Unknown package origin</origin>
<elements>
<element>

View file

@ -3,10 +3,10 @@
<description>transfer data over the network via TCP</description>
<filename>../../gst/tcp/.libs/libgsttcp.so</filename>
<basename>libgsttcp.so</basename>
<version>0.10.32.4</version>
<version>0.10.34.1</version>
<license>LGPL</license>
<source>gst-plugins-base</source>
<package>GStreamer Base Plug-ins prerelease</package>
<package>GStreamer Base Plug-ins git</package>
<origin>Unknown package origin</origin>
<elements>
<element>

View file

@ -3,10 +3,10 @@
<description>Theora plugin library</description>
<filename>../../ext/theora/.libs/libgsttheora.so</filename>
<basename>libgsttheora.so</basename>
<version>0.10.32.4</version>
<version>0.10.34.1</version>
<license>LGPL</license>
<source>gst-plugins-base</source>
<package>GStreamer Base Plug-ins prerelease</package>
<package>GStreamer Base Plug-ins git</package>
<origin>Unknown package origin</origin>
<elements>
<element>

View file

@ -3,10 +3,10 @@
<description>default typefind functions</description>
<filename>../../gst/typefind/.libs/libgsttypefindfunctions.so</filename>
<basename>libgsttypefindfunctions.so</basename>
<version>0.10.32.4</version>
<version>0.10.34.1</version>
<license>LGPL</license>
<source>gst-plugins-base</source>
<package>GStreamer Base Plug-ins prerelease</package>
<package>GStreamer Base Plug-ins git</package>
<origin>Unknown package origin</origin>
<elements>
</elements>

View file

@ -3,10 +3,10 @@
<description>URI Decoder bin</description>
<filename>../../gst/playback/.libs/libgstdecodebin2.so</filename>
<basename>libgstdecodebin2.so</basename>
<version>0.10.32.4</version>
<version>0.10.34.1</version>
<license>LGPL</license>
<source>gst-plugins-base</source>
<package>GStreamer Base Plug-ins prerelease</package>
<package>GStreamer Base Plug-ins git</package>
<origin>Unknown package origin</origin>
<elements>
<element>

View file

@ -3,10 +3,10 @@
<description>Adjusts video frames</description>
<filename>../../gst/videorate/.libs/libgstvideorate.so</filename>
<basename>libgstvideorate.so</basename>
<version>0.10.32.4</version>
<version>0.10.34.1</version>
<license>LGPL</license>
<source>gst-plugins-base</source>
<package>GStreamer Base Plug-ins prerelease</package>
<package>GStreamer Base Plug-ins git</package>
<origin>Unknown package origin</origin>
<elements>
<element>

View file

@ -3,10 +3,10 @@
<description>Resizes video</description>
<filename>../../gst/videoscale/.libs/libgstvideoscale.so</filename>
<basename>libgstvideoscale.so</basename>
<version>0.10.32.4</version>
<version>0.10.34.1</version>
<license>LGPL</license>
<source>gst-plugins-base</source>
<package>GStreamer Base Plug-ins prerelease</package>
<package>GStreamer Base Plug-ins git</package>
<origin>Unknown package origin</origin>
<elements>
<element>

View file

@ -3,10 +3,10 @@
<description>Creates a test video stream</description>
<filename>../../gst/videotestsrc/.libs/libgstvideotestsrc.so</filename>
<basename>libgstvideotestsrc.so</basename>
<version>0.10.32.4</version>
<version>0.10.34.1</version>
<license>LGPL</license>
<source>gst-plugins-base</source>
<package>GStreamer Base Plug-ins prerelease</package>
<package>GStreamer Base Plug-ins git</package>
<origin>Unknown package origin</origin>
<elements>
<element>

View file

@ -3,10 +3,10 @@
<description>plugin for controlling audio volume</description>
<filename>../../gst/volume/.libs/libgstvolume.so</filename>
<basename>libgstvolume.so</basename>
<version>0.10.32.4</version>
<version>0.10.34.1</version>
<license>LGPL</license>
<source>gst-plugins-base</source>
<package>GStreamer Base Plug-ins prerelease</package>
<package>GStreamer Base Plug-ins git</package>
<origin>Unknown package origin</origin>
<elements>
<element>

View file

@ -3,10 +3,10 @@
<description>Vorbis plugin library</description>
<filename>../../ext/vorbis/.libs/libgstvorbis.so</filename>
<basename>libgstvorbis.so</basename>
<version>0.10.32.4</version>
<version>0.10.34.1</version>
<license>LGPL</license>
<source>gst-plugins-base</source>
<package>GStreamer Base Plug-ins prerelease</package>
<package>GStreamer Base Plug-ins git</package>
<origin>Unknown package origin</origin>
<elements>
<element>

View file

@ -3,10 +3,10 @@
<description>X11 video output element based on standard Xlib calls</description>
<filename>../../sys/ximage/.libs/libgstximagesink.so</filename>
<basename>libgstximagesink.so</basename>
<version>0.10.32.4</version>
<version>0.10.34.1</version>
<license>LGPL</license>
<source>gst-plugins-base</source>
<package>GStreamer Base Plug-ins prerelease</package>
<package>GStreamer Base Plug-ins git</package>
<origin>Unknown package origin</origin>
<elements>
<element>

View file

@ -3,10 +3,10 @@
<description>XFree86 video output plugin using Xv extension</description>
<filename>../../sys/xvimage/.libs/libgstxvimagesink.so</filename>
<basename>libgstxvimagesink.so</basename>
<version>0.10.32.4</version>
<version>0.10.34.1</version>
<license>LGPL</license>
<source>gst-plugins-base</source>
<package>GStreamer Base Plug-ins prerelease</package>
<package>GStreamer Base Plug-ins git</package>
<origin>Unknown package origin</origin>
<elements>
<element>

View file

@ -87,6 +87,12 @@ static gboolean gst_alsasrc_close (GstAudioSrc * asrc);
static guint gst_alsasrc_read (GstAudioSrc * asrc, gpointer data, guint length);
static guint gst_alsasrc_delay (GstAudioSrc * asrc);
static void gst_alsasrc_reset (GstAudioSrc * asrc);
static GstStateChangeReturn gst_alsasrc_change_state (GstElement * element,
GstStateChange transition);
static GstFlowReturn gst_alsasrc_create (GstBaseSrc * bsrc, guint64 offset,
guint length, GstBuffer ** outbuf);
static GstClockTime gst_alsasrc_get_timestamp (GstAlsaSrc * src);
/* AlsaSrc signals and args */
enum
@ -189,11 +195,13 @@ gst_alsasrc_class_init (GstAlsaSrcClass * klass)
GstElementClass *gstelement_class;
GstBaseSrcClass *gstbasesrc_class;
GstAudioSrcClass *gstaudiosrc_class;
GstBaseAudioSrcClass *gstbaseaudiosrc_class;
gobject_class = (GObjectClass *) klass;
gstelement_class = (GstElementClass *) klass;
gstbasesrc_class = (GstBaseSrcClass *) klass;
gstaudiosrc_class = (GstAudioSrcClass *) klass;
gstbaseaudiosrc_class = (GstBaseAudioSrcClass *) klass;
gobject_class->finalize = gst_alsasrc_finalize;
gobject_class->get_property = gst_alsasrc_get_property;
@ -206,7 +214,10 @@ gst_alsasrc_class_init (GstAlsaSrcClass * klass)
gst_element_class_add_pad_template (gstelement_class,
gst_static_pad_template_get (&alsasrc_src_factory));
gstelement_class->change_state = GST_DEBUG_FUNCPTR (gst_alsasrc_change_state);
gstbasesrc_class->get_caps = GST_DEBUG_FUNCPTR (gst_alsasrc_getcaps);
gstbasesrc_class->create = GST_DEBUG_FUNCPTR (gst_alsasrc_create);
gstaudiosrc_class->open = GST_DEBUG_FUNCPTR (gst_alsasrc_open);
gstaudiosrc_class->prepare = GST_DEBUG_FUNCPTR (gst_alsasrc_prepare);
@ -232,6 +243,49 @@ gst_alsasrc_class_init (GstAlsaSrcClass * klass)
DEFAULT_PROP_CARD_NAME, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
}
static GstClockTime
gst_alsasrc_get_timestamp (GstAlsaSrc * src)
{
snd_pcm_status_t *status;
snd_htimestamp_t tstamp;
GstClockTime timestamp;
snd_pcm_uframes_t availmax;
GST_DEBUG_OBJECT (src, "Getting alsa timestamp!");
if (!src) {
GST_ERROR_OBJECT (src, "No alsa handle created yet !");
return 0;
}
if (snd_pcm_status_malloc (&status) != 0) {
GST_ERROR_OBJECT (src, "snd_pcm_status_malloc failed");
}
if (snd_pcm_status (src->handle, status) != 0) {
GST_ERROR_OBJECT (src, "snd_pcm_status failed");
}
/* get high resolution time stamp from driver */
snd_pcm_status_get_htstamp (status, &tstamp);
timestamp = GST_TIMESPEC_TO_TIME (tstamp);
/* Max available frames sets the depth of the buffer */
availmax = snd_pcm_status_get_avail_max (status);
/* Compensate the fact that the timestamp references the last sample */
timestamp -= gst_util_uint64_scale_int (availmax * 2, GST_SECOND, src->rate);
/* Compensate for the delay until the package is available */
timestamp += gst_util_uint64_scale_int (snd_pcm_status_get_delay (status),
GST_SECOND, src->rate);
snd_pcm_status_free (status);
GST_DEBUG_OBJECT (src, "ALSA timestamp : %" GST_TIME_FORMAT,
GST_TIME_ARGS (timestamp));
return timestamp;
}
static void
gst_alsasrc_set_property (GObject * object, guint prop_id,
const GValue * value, GParamSpec * pspec)
@ -282,6 +336,57 @@ gst_alsasrc_get_property (GObject * object, guint prop_id,
}
}
static GstStateChangeReturn
gst_alsasrc_change_state (GstElement * element, GstStateChange transition)
{
GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
GstBaseAudioSrc *src = GST_BASE_AUDIO_SRC (element);
GstAlsaSrc *asrc = GST_ALSA_SRC (element);
GstClock *clk;
switch (transition) {
/* Show the compiler that we care */
case GST_STATE_CHANGE_NULL_TO_READY:
case GST_STATE_CHANGE_READY_TO_PAUSED:
case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
case GST_STATE_CHANGE_PAUSED_TO_READY:
case GST_STATE_CHANGE_READY_TO_NULL:
break;
case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
clk = src->clock;
asrc->driver_timestamps = FALSE;
if (GST_IS_SYSTEM_CLOCK (clk)) {
gint clocktype;
g_object_get (clk, "clock-type", &clocktype, NULL);
if (clocktype == GST_CLOCK_TYPE_MONOTONIC) {
asrc->driver_timestamps = TRUE;
}
}
break;
}
ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
return ret;
}
static GstFlowReturn
gst_alsasrc_create (GstBaseSrc * bsrc, guint64 offset, guint length,
GstBuffer ** outbuf)
{
GstFlowReturn ret = GST_FLOW_OK;
GstAlsaSrc *asrc = GST_ALSA_SRC (bsrc);
ret =
GST_BASE_SRC_CLASS (parent_class)->create (bsrc, offset, length, outbuf);
if (asrc->driver_timestamps == TRUE && *outbuf) {
GST_BUFFER_TIMESTAMP (*outbuf) =
gst_alsasrc_get_timestamp ((GstAlsaSrc *) bsrc);
}
return ret;
}
static void
gst_alsasrc_init (GstAlsaSrc * alsasrc)
{
@ -289,6 +394,7 @@ gst_alsasrc_init (GstAlsaSrc * alsasrc)
alsasrc->device = g_strdup (DEFAULT_PROP_DEVICE);
alsasrc->cached_caps = NULL;
alsasrc->driver_timestamps = FALSE;
alsasrc->alsa_lock = g_mutex_new ();
}

View file

@ -64,6 +64,7 @@ struct _GstAlsaSrc {
guint rate;
guint channels;
gint bytes_per_sample;
gboolean driver_timestamps;
guint buffer_time;
guint period_time;

View file

@ -26,7 +26,8 @@ libgstaudio_@GST_MAJORMINOR@_la_SOURCES = \
gstbaseaudiosrc.c \
gstaudiofilter.c \
gstaudiosink.c \
gstaudiosrc.c
gstaudiosrc.c \
gstaudioiec61937.c
nodist_libgstaudio_@GST_MAJORMINOR@_la_SOURCES = $(built_sources) $(built_headers)
libgstaudio_@GST_MAJORMINOR@includedir = $(includedir)/gstreamer-@GST_MAJORMINOR@/gst/audio
@ -40,7 +41,8 @@ libgstaudio_@GST_MAJORMINOR@include_HEADERS = \
gstaudiosink.h \
gstaudiosrc.h \
mixerutils.h \
multichannel.h
multichannel.h \
gstaudioiec61937.h
nodist_libgstaudio_@GST_MAJORMINOR@include_HEADERS = \
audio-enumtypes.h

View file

@ -0,0 +1,319 @@
/* GStreamer audio helper functions for IEC 61937 payloading
* (c) 2011 Intel Corporation
* 2011 Collabora Multimedia
* 2011 Arun Raghavan <arun.raghavan@collabora.co.uk>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
/**
* SECTION:gstaudioiec61937
* @short_description: Utility functions for IEC 61937 payloading
*
* This module contains some helper functions for encapsulating various
* audio formats in IEC 61937 headers and padding.
*
* Since: 0.10.35
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <string.h>
#include "gstaudioiec61937.h"
#define IEC61937_HEADER_SIZE 8
#define IEC61937_PAYLOAD_SIZE_AC3 (1536 * 4)
#define IEC61937_PAYLOAD_SIZE_EAC3 (6144 * 4)
static gint
caps_get_int_field (const GstCaps * caps, const gchar * field)
{
const GstStructure *st;
gint ret = 0;
st = gst_caps_get_structure (caps, 0);
gst_structure_get_int (st, field, &ret);
return ret;
}
static const gchar *
caps_get_string_field (const GstCaps * caps, const gchar * field)
{
const GstStructure *st = gst_caps_get_structure (caps, 0);
return gst_structure_get_string (st, field);
}
/**
* gst_audio_iec61937_frame_size
* @type: the type of data to be payloaded as a #GstBufferFormatType
*
* Returns 0 if the given @type is not supported or cannot be payloaded, else
* returns the size of the buffer expected by gst_audio_iec61937_payload() for
* payloading @type.
*
* Since: 0.10.35
*/
guint
gst_audio_iec61937_frame_size (const GstRingBufferSpec * spec)
{
switch (spec->type) {
case GST_BUFTYPE_AC3:
return IEC61937_PAYLOAD_SIZE_AC3;
case GST_BUFTYPE_EAC3:
/* Check that the parser supports /some/ alignment. Need to be less
* strict about this at checking time since the alignment is dynamically
* set at the moment. */
if (caps_get_string_field (spec->caps, "alignment"))
return IEC61937_PAYLOAD_SIZE_EAC3;
else
return 0;
case GST_BUFTYPE_DTS:
{
gint dts_frame_size = caps_get_int_field (spec->caps, "frame-size");
gint iec_frame_size = caps_get_int_field (spec->caps, "block-size") * 4;
/* Note: this will also (correctly) fail if either field is missing */
if (iec_frame_size >= (dts_frame_size + IEC61937_HEADER_SIZE))
return iec_frame_size;
else
return 0;
}
case GST_BUFTYPE_MPEG:
{
int version, layer, channels, frames;
version = caps_get_int_field (spec->caps, "mpegaudioversion");
layer = caps_get_int_field (spec->caps, "layer");
channels = caps_get_int_field (spec->caps, "channels");
/* Bail out if we can't figure out either, if it's MPEG 2.5, or if it's
* MP3 with multichannel audio */
if (!version || !layer || version == 3 || channels > 2)
return 0;
if (version == 1 && layer == 1)
frames = 384;
else if (version == 2 && layer == 1 && spec->rate < 32000)
frames = 768;
else if (version == 2 && layer == 1 && spec->rate < 32000)
frames = 2304;
else
frames = 1152;
return frames * 4;
}
default:
return 0;
}
}
/**
* gst_audio_iec61937_payload
* @src: a buffer containing the data to payload
* @src_n: size of @src in bytes
* @dst: the destination buffer to store the payloaded contents in. Should not
* overlap with @src
* @dst_n: size of @dst in bytes
* @type: the type of data in @src
*
* Payloads @src in the form specified by IEC 61937 for @type and stores
* the result in @dst. @src must contain exactly one frame of data and the
* frame is not checked for errors.
*
* Returns: transfer-full: #TRUE if the payloading was successful, #FALSE
* otherwise.
*
* Since: 0.10.35
*/
gboolean
gst_audio_iec61937_payload (const guint8 * src, guint src_n, guint8 * dst,
guint dst_n, const GstRingBufferSpec * spec)
{
guint i, tmp;
#if G_BYTE_ORDER == G_BIG_ENDIAN
guint8 zero = 0, one = 1, two = 2, three = 3, four = 4, five = 5, six = 6,
seven = 7;
#else
/* We need to send the data byte-swapped */
guint8 zero = 1, one = 0, two = 3, three = 2, four = 5, five = 4, six = 7,
seven = 6;
#endif
g_return_val_if_fail (src != NULL, FALSE);
g_return_val_if_fail (dst != NULL, FALSE);
g_return_val_if_fail (src != dst, FALSE);
g_return_val_if_fail (dst_n >= gst_audio_iec61937_frame_size (spec), FALSE);
if (dst_n < src_n + IEC61937_HEADER_SIZE)
return FALSE;
/* Pa, Pb */
dst[zero] = 0xF8;
dst[one] = 0x72;
dst[two] = 0x4E;
dst[three] = 0x1F;
switch (spec->type) {
case GST_BUFTYPE_AC3:
{
g_return_val_if_fail (src_n >= 6, FALSE);
/* Pc: bit 13-15 - stream number (0)
* bit 11-12 - reserved (0)
* bit 8-10 - bsmod from AC3 frame */
dst[four] = src[5] & 0x7;
/* Pc: bit 7 - error bit (0)
* bit 5-6 - subdata type (0)
* bit 0-4 - data type (1) */
dst[five] = 1;
/* Pd: bit 15-0 - frame size in bits */
tmp = src_n * 8;
dst[six] = (guint8) (tmp >> 8);
dst[seven] = (guint8) (tmp & 0xff);
break;
}
case GST_BUFTYPE_EAC3:
{
if (g_str_equal (caps_get_string_field (spec->caps, "alignment"),
"iec61937"))
return FALSE;
/* Pc: bit 13-15 - stream number (0)
* bit 11-12 - reserved (0)
* bit 8-10 - bsmod from E-AC3 frame if present */
/* FIXME: this works, but nicer if we can put in the actual bsmod */
dst[four] = 0;
/* Pc: bit 7 - error bit (0)
* bit 5-6 - subdata type (0)
* bit 0-4 - data type (21) */
dst[five] = 21;
/* Pd: bit 15-0 - frame size in bytes */
dst[six] = ((guint16) src_n) >> 8;
dst[seven] = ((guint16) src_n) & 0xff;
break;
}
case GST_BUFTYPE_DTS:
{
int blocksize = caps_get_int_field (spec->caps, "block-size");
g_return_val_if_fail (src_n != 0, FALSE);
if (blocksize == 0)
return FALSE;
/* Pc: bit 13-15 - stream number (0)
* bit 11-12 - reserved (0)
* bit 8-10 - for DTS type I-III (0) */
dst[four] = 0;
/* Pc: bit 7 - error bit (0)
* bit 5-6 - reserved (0)
* bit 0-4 - data type (11 = type I, 12 = type II,
* 13 = type III) */
dst[five] = 11 + (blocksize / 1024);
/* Pd: bit 15-0 - frame size in bytes */
dst[six] = ((guint16) src_n) >> 8;
dst[seven] = ((guint16) src_n) & 0xff;
break;
}
case GST_BUFTYPE_MPEG:
{
int version, layer;
version = caps_get_int_field (spec->caps, "mpegaudioversion");
layer = caps_get_int_field (spec->caps, "layer");
g_return_val_if_fail (version > 0 && layer > 0, FALSE);
/* NOTE: multichannel audio (MPEG-2) is not supported */
/* Pc: bit 13-15 - stream number (0)
* bit 11-12 - reserved (0)
* bit 9-10 - 0 - no dynamic range control
* - 2 - dynamic range control exists
* - 1,3 - reserved
* bit 8 - Normal (0) or Karaoke (1) mode */
dst[four] = 0;
/* Pc: bit 7 - error bit (0)
* bit 5-6 - reserved (0)
* bit 0-4 - data type (04 = MPEG 1, Layer 1
* 05 = MPEG 1, Layer 2, 3 / MPEG 2, w/o ext.
* 06 = MPEG 2, with extension
* 08 - MPEG 2 LSF, Layer 1
* 09 - MPEG 2 LSF, Layer 2
* 10 - MPEG 2 LSF, Layer 3 */
if (version == 1 && layer == 1)
dst[five] = 0x04;
else if ((version == 1 && (layer == 2 || layer == 3)) ||
(version == 2 && spec->rate >= 32000))
dst[five] = 0x05;
else if (version == 2 && layer == 1 && spec->rate < 32000)
dst[five] = 0x08;
else if (version == 2 && layer == 2 && spec->rate < 32000)
dst[five] = 0x09;
else if (version == 2 && layer == 3 && spec->rate < 32000)
dst[five] = 0x0A;
else
g_return_val_if_reached (FALSE);
/* Pd: bit 15-0 - frame size in bits */
dst[six] = ((guint16) src_n * 8) >> 8;
dst[seven] = ((guint16) src_n * 8) & 0xff;
break;
}
default:
return FALSE;
}
/* Copy the payload */
i = 8;
#if G_BYTE_ORDER == G_BIG_ENDIAN
memcpy (dst + i, src, src_n);
#else
/* Byte-swapped again */
/* FIXME: orc-ify this */
for (tmp = 1; tmp < src_n; tmp += 2) {
dst[i + tmp - 1] = src[tmp];
dst[i + tmp] = src[tmp - 1];
}
/* Do we have 1 byte remaining? */
if (src_n % 2) {
dst[i + src_n - 1] = 0;
dst[i + src_n] = src[src_n - 1];
i++;
}
#endif
i += src_n;
/* Zero the rest */
memset (dst + i, 0, dst_n - i);
return TRUE;
}

View file

@ -0,0 +1,38 @@
/* GStreamer audio helper functions for IEC 61937 payloading
* (c) 2011 Intel Corporation
* 2011 Collabora Multimedia
* 2011 Arun Raghavan <arun.raghavan@collabora.co.uk>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
/**
* SECTION:gstaudioiec61937
* @short_description: Utility functions for IEC 61937 payloading
*
* This module contains some helper functions for encapsulating various
* audio formats in IEC 61937 headers and padding.
*/
#ifndef __GST_AUDIO_IEC61937_H__
#define __GST_AUDIO_IEC61937_H__
#include <gst/audio/gstringbuffer.h>
guint gst_audio_iec61937_frame_size (const GstRingBufferSpec * spec);
gboolean gst_audio_iec61937_payload (const guint8 * src, guint src_n,
guint8 * dst, guint dst_n, const GstRingBufferSpec * spec);
#endif /* __GST_AUDIO_IEC61937_H__ */

View file

@ -1345,6 +1345,7 @@ gst_base_audio_sink_render (GstBaseSink * bsink, GstBuffer * buf)
guint64 in_offset;
GstClockTime time, stop, render_start, render_stop, sample_offset;
GstClockTimeDiff sync_offset, ts_offset;
GstBaseAudioSinkClass *bclass;
GstBaseAudioSink *sink;
GstRingBuffer *ringbuf;
gint64 diff, align;
@ -1362,8 +1363,10 @@ gst_base_audio_sink_render (GstBaseSink * bsink, GstBuffer * buf)
GstFlowReturn ret;
GstSegment clip_seg;
gint64 time_offset;
GstBuffer *out = NULL;
sink = GST_BASE_AUDIO_SINK (bsink);
bclass = GST_BASE_AUDIO_SINK_GET_CLASS (sink);
ringbuf = sink->ringbuffer;
@ -1387,6 +1390,17 @@ gst_base_audio_sink_render (GstBaseSink * bsink, GstBuffer * buf)
GST_OBJECT_UNLOCK (sink);
}
/* Before we go on, let's see if we need to payload the data. If yes, we also
* need to unref the output buffer before leaving. */
if (bclass->payload) {
out = bclass->payload (sink, buf);
if (!out)
goto payload_failed;
buf = out;
}
bps = ringbuf->spec.bytes_per_sample;
size = gst_buffer_get_size (buf);
@ -1669,7 +1683,13 @@ no_sync:
gst_ring_buffer_start (ringbuf);
}
return GST_FLOW_OK;
ret = GST_FLOW_OK;
done:
if (out)
gst_buffer_unref (out);
return ret;
/* SPECIAL cases */
out_of_segment:
@ -1678,33 +1698,42 @@ out_of_segment:
"dropping sample out of segment time %" GST_TIME_FORMAT ", start %"
GST_TIME_FORMAT, GST_TIME_ARGS (time),
GST_TIME_ARGS (bsink->segment.start));
return GST_FLOW_OK;
ret = GST_FLOW_OK;
goto done;
}
/* ERRORS */
payload_failed:
{
GST_ELEMENT_ERROR (sink, STREAM, FORMAT, (NULL), ("failed to payload."));
ret = GST_FLOW_ERROR;
goto done;
}
wrong_state:
{
GST_DEBUG_OBJECT (sink, "ringbuffer not negotiated");
GST_ELEMENT_ERROR (sink, STREAM, FORMAT, (NULL), ("sink not negotiated."));
return GST_FLOW_NOT_NEGOTIATED;
ret = GST_FLOW_NOT_NEGOTIATED;
goto done;
}
wrong_size:
{
GST_DEBUG_OBJECT (sink, "wrong size");
GST_ELEMENT_ERROR (sink, STREAM, WRONG_TYPE,
(NULL), ("sink received buffer of wrong size."));
return GST_FLOW_ERROR;
ret = GST_FLOW_ERROR;
goto done;
}
stopping:
{
GST_DEBUG_OBJECT (sink, "preroll got interrupted: %d (%s)", ret,
gst_flow_get_name (ret));
gst_buffer_unmap (buf, data, size);
return ret;
goto done;
}
sync_latency_failed:
{
GST_DEBUG_OBJECT (sink, "failed waiting for latency");
return ret;
goto done;
}
}

View file

@ -141,6 +141,10 @@ struct _GstBaseAudioSink {
* GstBaseAudioSinkClass:
* @parent_class: the parent class.
* @create_ringbuffer: create and return a #GstRingBuffer to write to.
* @payload: payload data in a format suitable to write to the sink. If no
* payloading is required, returns a reffed copy of the original
* buffer, else returns the payloaded buffer with all other metadata
* copied. (Since: 0.10.35)
*
* #GstBaseAudioSink class. Override the vmethod to implement
* functionality.
@ -151,8 +155,12 @@ struct _GstBaseAudioSinkClass {
/* subclass ringbuffer allocation */
GstRingBuffer* (*create_ringbuffer) (GstBaseAudioSink *sink);
/* subclass payloader */
GstBuffer* (*payload) (GstBaseAudioSink *sink,
GstBuffer *buffer);
/*< private >*/
gpointer _gst_reserved[GST_PADDING];
gpointer _gst_reserved[GST_PADDING - 1];
};
GType gst_base_audio_sink_get_type(void);

View file

@ -327,7 +327,7 @@ gst_ring_buffer_parse_caps (GstRingBufferSpec * spec, GstCaps * caps)
/* we have to differentiate between int and float formats */
mimetype = gst_structure_get_name (structure);
if (!strncmp (mimetype, "audio/x-raw-int", 15)) {
if (g_str_equal (mimetype, "audio/x-raw-int")) {
gint endianness;
const FormatDef *def;
gint j, bytes;
@ -367,7 +367,7 @@ gst_ring_buffer_parse_caps (GstRingBufferSpec * spec, GstCaps * caps)
spec->silence_sample[i * bytes + j] = def->silence[j];
}
}
} else if (!strncmp (mimetype, "audio/x-raw-float", 17)) {
} else if (g_str_equal (mimetype, "audio/x-raw-float")) {
spec->type = GST_BUFTYPE_FLOAT;
@ -392,7 +392,7 @@ gst_ring_buffer_parse_caps (GstRingBufferSpec * spec, GstCaps * caps)
}
/* float silence is all zeros.. */
memset (spec->silence_sample, 0, 32);
} else if (!strncmp (mimetype, "audio/x-alaw", 12)) {
} else if (g_str_equal (mimetype, "audio/x-alaw")) {
/* extract the needed information from the cap */
if (!(gst_structure_get_int (structure, "rate", &spec->rate) &&
gst_structure_get_int (structure, "channels", &spec->channels)))
@ -404,7 +404,7 @@ gst_ring_buffer_parse_caps (GstRingBufferSpec * spec, GstCaps * caps)
spec->depth = 8;
for (i = 0; i < spec->channels; i++)
spec->silence_sample[i] = 0xd5;
} else if (!strncmp (mimetype, "audio/x-mulaw", 13)) {
} else if (g_str_equal (mimetype, "audio/x-mulaw")) {
/* extract the needed information from the cap */
if (!(gst_structure_get_int (structure, "rate", &spec->rate) &&
gst_structure_get_int (structure, "channels", &spec->channels)))
@ -416,7 +416,7 @@ gst_ring_buffer_parse_caps (GstRingBufferSpec * spec, GstCaps * caps)
spec->depth = 8;
for (i = 0; i < spec->channels; i++)
spec->silence_sample[i] = 0xff;
} else if (!strncmp (mimetype, "audio/x-iec958", 14)) {
} else if (g_str_equal (mimetype, "audio/x-iec958")) {
/* extract the needed information from the cap */
if (!(gst_structure_get_int (structure, "rate", &spec->rate)))
goto parse_error;
@ -426,7 +426,7 @@ gst_ring_buffer_parse_caps (GstRingBufferSpec * spec, GstCaps * caps)
spec->width = 16;
spec->depth = 16;
spec->channels = 2;
} else if (!strncmp (mimetype, "audio/x-ac3", 11)) {
} else if (g_str_equal (mimetype, "audio/x-ac3")) {
/* extract the needed information from the cap */
if (!(gst_structure_get_int (structure, "rate", &spec->rate)))
goto parse_error;
@ -436,6 +436,39 @@ gst_ring_buffer_parse_caps (GstRingBufferSpec * spec, GstCaps * caps)
spec->width = 16;
spec->depth = 16;
spec->channels = 2;
} else if (g_str_equal (mimetype, "audio/x-eac3")) {
/* extract the needed information from the cap */
if (!(gst_structure_get_int (structure, "rate", &spec->rate)))
goto parse_error;
spec->type = GST_BUFTYPE_EAC3;
spec->format = GST_EAC3;
spec->width = 64;
spec->depth = 64;
spec->channels = 2;
} else if (g_str_equal (mimetype, "audio/x-dts")) {
/* extract the needed information from the cap */
if (!(gst_structure_get_int (structure, "rate", &spec->rate)))
goto parse_error;
spec->type = GST_BUFTYPE_DTS;
spec->format = GST_DTS;
spec->width = 16;
spec->depth = 16;
spec->channels = 2;
} else if (g_str_equal (mimetype, "audio/mpeg") &&
gst_structure_get_int (structure, "mpegaudioversion", &i) &&
(i == 1 || i == 2)) {
/* Now we know this is MPEG-1 or MPEG-2 (non AAC) */
/* extract the needed information from the cap */
if (!(gst_structure_get_int (structure, "rate", &spec->rate)))
goto parse_error;
spec->type = GST_BUFTYPE_MPEG;
spec->format = GST_MPEG;
spec->width = 16;
spec->depth = 16;
spec->channels = 2;
} else {
goto parse_error;
}

View file

@ -88,12 +88,14 @@ typedef enum {
* @GST_BUFTYPE_MU_LAW: samples in mulaw
* @GST_BUFTYPE_A_LAW: samples in alaw
* @GST_BUFTYPE_IMA_ADPCM: samples in ima adpcm
* @GST_BUFTYPE_MPEG: samples in mpeg audio format
* @GST_BUFTYPE_MPEG: samples in mpeg audio (but not AAC) format
* @GST_BUFTYPE_GSM: samples in gsm format
* @GST_BUFTYPE_IEC958: samples in IEC958 frames (e.g. AC3)
* @GST_BUFTYPE_AC3: samples in AC3 format
* @GST_BUFTYPE_EAC3: samples in EAC3 format
* @GST_BUFTYPE_DTS: samples in DTS format
* @GST_BUFTYPE_MPEG2_AAC: samples in MPEG-2 AAC format
* @GST_BUFTYPE_MPEG4_AAC: samples in MPEG-4 AAC format
*
* The format of the samples in the ringbuffer.
*/
@ -109,7 +111,9 @@ typedef enum
GST_BUFTYPE_IEC958,
GST_BUFTYPE_AC3,
GST_BUFTYPE_EAC3,
GST_BUFTYPE_DTS
GST_BUFTYPE_DTS,
GST_BUFTYPE_MPEG2_AAC,
GST_BUFTYPE_MPEG4_AAC,
} GstBufferFormatType;
typedef enum
@ -161,7 +165,9 @@ typedef enum
GST_IEC958,
GST_AC3,
GST_EAC3,
GST_DTS
GST_DTS,
GST_MPEG2_AAC,
GST_MPEG4_AAC,
} GstBufferFormat;
/**

View file

@ -51,6 +51,7 @@ static const gchar *schema_list[] = {
"exif",
"photoshop",
"Iptc4xmpCore",
"Iptc4xmpExt",
NULL
};
@ -112,14 +113,31 @@ xmp_serialization_data_use_schema (XmpSerializationData * serdata,
return FALSE;
}
typedef enum
{
GstXmpTagTypeSimple = 0,
GstXmpTagTypeBag,
GstXmpTagTypeSeq,
GstXmpTagTypeStruct,
/* Not really a xmp type, this is a tag that in gst is represented with
* a single value and on xmp it needs 2 (or more) simple values
*
* e.g. GST_TAG_GEO_LOCATION_ELEVATION needs to be mapped into 2 complementary
* tags in the exif's schema. One of them stores the absolute elevation,
* and the other one stores if it is above of below sea level.
*/
GstXmpTagTypeCompound
} GstXmpTagType;
#define GST_XMP_TAG_TYPE_SIMPLE 0
#define GST_XMP_TAG_TYPE_BAG 1
#define GST_XMP_TAG_TYPE_SEQ 2
struct _XmpTag
{
const gchar *gst_tag;
const gchar *tag_name;
gint type;
GstXmpTagType type;
/* Used for struct and compound types */
GSList *children;
XmpSerializationFunc serialize;
XmpDeserializationFunc deserialize;
@ -129,10 +147,10 @@ static GstTagMergeMode
xmp_tag_get_merge_mode (XmpTag * xmptag)
{
switch (xmptag->type) {
case GST_XMP_TAG_TYPE_BAG:
case GST_XMP_TAG_TYPE_SEQ:
case GstXmpTagTypeBag:
case GstXmpTagTypeSeq:
return GST_TAG_MERGE_APPEND;
case GST_XMP_TAG_TYPE_SIMPLE:
case GstXmpTagTypeSimple:
default:
return GST_TAG_MERGE_KEEP;
}
@ -142,31 +160,25 @@ static const gchar *
xmp_tag_get_type_name (XmpTag * xmptag)
{
switch (xmptag->type) {
case GST_XMP_TAG_TYPE_SEQ:
case GstXmpTagTypeSeq:
return "rdf:Seq";
default:
g_assert_not_reached ();
case GST_XMP_TAG_TYPE_BAG:
case GstXmpTagTypeBag:
return "rdf:Bag";
}
}
struct _PendingXmpTag
{
const gchar *gst_tag;
XmpTag *xmp_tag;
gchar *str;
};
typedef struct _PendingXmpTag PendingXmpTag;
/*
* A schema is a mapping of strings (the tag name in gstreamer) to a list of
* tags in xmp (XmpTag). We need a list because some tags are split into 2
* when serialized into xmp.
* e.g. GST_TAG_GEO_LOCATION_ELEVATION needs to be mapped into 2 complementary
* tags in the exif's schema. One of them stores the absolute elevation,
* and the other one stores if it is above of below sea level.
* tags in xmp (XmpTag).
*/
typedef GHashTable GstXmpSchema;
#define gst_xmp_schema_lookup g_hash_table_lookup
@ -182,6 +194,21 @@ gst_xmp_schema_new ()
*/
static GHashTable *__xmp_schemas;
static GstXmpSchema *
_gst_xmp_get_schema (const gchar * name)
{
GQuark key;
GstXmpSchema *schema;
key = g_quark_from_string (name);
schema = g_hash_table_lookup (__xmp_schemas, GUINT_TO_POINTER (key));
if (!schema) {
GST_WARNING ("Schema %s doesn't exist", name);
}
return schema;
}
static void
_gst_xmp_add_schema (const gchar * name, GstXmpSchema * schema)
{
@ -199,19 +226,59 @@ _gst_xmp_add_schema (const gchar * name, GstXmpSchema * schema)
}
static void
_gst_xmp_schema_add_mapping (GstXmpSchema * schema, const gchar * gst_tag,
GPtrArray * array)
_gst_xmp_schema_add_mapping (GstXmpSchema * schema, XmpTag * tag)
{
GQuark key;
key = g_quark_from_string (gst_tag);
key = g_quark_from_string (tag->gst_tag);
if (gst_xmp_schema_lookup (schema, GUINT_TO_POINTER (key))) {
GST_WARNING ("Tag %s already present for the schema", gst_tag);
GST_WARNING ("Tag %s already present for the schema", tag->gst_tag);
g_assert_not_reached ();
return;
}
gst_xmp_schema_insert (schema, GUINT_TO_POINTER (key), array);
gst_xmp_schema_insert (schema, GUINT_TO_POINTER (key), tag);
}
static XmpTag *
gst_xmp_tag_create (const gchar * gst_tag, const gchar * xmp_tag,
gint xmp_type, XmpSerializationFunc serialization_func,
XmpDeserializationFunc deserialization_func)
{
XmpTag *xmpinfo;
xmpinfo = g_slice_new (XmpTag);
xmpinfo->gst_tag = gst_tag;
xmpinfo->tag_name = xmp_tag;
xmpinfo->type = xmp_type;
xmpinfo->serialize = serialization_func;
xmpinfo->deserialize = deserialization_func;
xmpinfo->children = NULL;
return xmpinfo;
}
static XmpTag *
gst_xmp_tag_create_compound (const gchar * gst_tag, const gchar * xmp_tag_a,
const gchar * xmp_tag_b, XmpSerializationFunc serialization_func_a,
XmpSerializationFunc serialization_func_b,
XmpDeserializationFunc deserialization_func)
{
XmpTag *xmptag;
XmpTag *xmptag_a =
gst_xmp_tag_create (gst_tag, xmp_tag_a, GstXmpTagTypeSimple,
serialization_func_a, deserialization_func);
XmpTag *xmptag_b =
gst_xmp_tag_create (gst_tag, xmp_tag_b, GstXmpTagTypeSimple,
serialization_func_b, deserialization_func);
xmptag =
gst_xmp_tag_create (gst_tag, NULL, GstXmpTagTypeCompound, NULL, NULL);
xmptag->children = g_slist_prepend (xmptag->children, xmptag_b);
xmptag->children = g_slist_prepend (xmptag->children, xmptag_a);
return xmptag;
}
static void
@ -220,19 +287,9 @@ _gst_xmp_schema_add_simple_mapping (GstXmpSchema * schema,
XmpSerializationFunc serialization_func,
XmpDeserializationFunc deserialization_func)
{
XmpTag *xmpinfo;
GPtrArray *array;
xmpinfo = g_slice_new (XmpTag);
xmpinfo->tag_name = xmp_tag;
xmpinfo->type = xmp_type;
xmpinfo->serialize = serialization_func;
xmpinfo->deserialize = deserialization_func;
array = g_ptr_array_sized_new (1);
g_ptr_array_add (array, xmpinfo);
_gst_xmp_schema_add_mapping (schema, gst_tag, array);
_gst_xmp_schema_add_mapping (schema,
gst_xmp_tag_create (gst_tag, xmp_tag, xmp_type, serialization_func,
deserialization_func));
}
/*
@ -240,6 +297,7 @@ _gst_xmp_schema_add_simple_mapping (GstXmpSchema * schema,
* appended, and the API is not public, so we shouldn't
* have our lists modified during usage
*/
#if 0
static GPtrArray *
_xmp_tag_get_mapping (const gchar * gst_tag, XmpSerializationData * serdata)
{
@ -260,6 +318,7 @@ _xmp_tag_get_mapping (const gchar * gst_tag, XmpSerializationData * serdata)
}
return ret;
}
#endif
/* finds the gst tag that maps to this xmp tag in this schema */
static const gchar *
@ -269,22 +328,30 @@ _gst_xmp_schema_get_mapping_reverse (GstXmpSchema * schema,
GHashTableIter iter;
gpointer key, value;
const gchar *ret = NULL;
gint index;
/* Iterate over the hashtable */
g_hash_table_iter_init (&iter, schema);
while (!ret && g_hash_table_iter_next (&iter, &key, &value)) {
GPtrArray *array = (GPtrArray *) value;
/* each mapping might contain complementary tags */
for (index = 0; index < array->len; index++) {
XmpTag *xmpinfo = (XmpTag *) g_ptr_array_index (array, index);
XmpTag *xmpinfo = (XmpTag *) value;
if (xmpinfo->tag_name) {
if (strcmp (xmpinfo->tag_name, xmp_tag) == 0) {
*_xmp_tag = xmpinfo;
ret = g_quark_to_string (GPOINTER_TO_UINT (key));
goto out;
}
} else if (xmpinfo->children) {
GSList *iter;
for (iter = xmpinfo->children; iter; iter = g_slist_next (iter)) {
XmpTag *child = iter->data;
if (strcmp (child->tag_name, xmp_tag) == 0) {
*_xmp_tag = child;
ret = g_quark_to_string (GPOINTER_TO_UINT (key));
goto out;
}
}
} else {
g_assert_not_reached ();
}
}
@ -839,7 +906,6 @@ deserialize_tiff_orientation (XmpTag * xmptag, GstTagList * taglist,
static gpointer
_init_xmp_tag_map (gpointer user_data)
{
GPtrArray *array;
XmpTag *xmpinfo;
GstXmpSchema *schema;
@ -851,135 +917,115 @@ _init_xmp_tag_map (gpointer user_data)
*/
schema = gst_xmp_schema_new ();
_gst_xmp_schema_add_simple_mapping (schema, GST_TAG_ARTIST,
"dc:creator", GST_XMP_TAG_TYPE_SEQ, NULL, NULL);
"dc:creator", GstXmpTagTypeSeq, NULL, NULL);
_gst_xmp_schema_add_simple_mapping (schema, GST_TAG_COPYRIGHT,
"dc:rights", GST_XMP_TAG_TYPE_SIMPLE, NULL, NULL);
"dc:rights", GstXmpTagTypeSimple, NULL, NULL);
_gst_xmp_schema_add_simple_mapping (schema, GST_TAG_DATE, "dc:date",
GST_XMP_TAG_TYPE_SEQ, NULL, NULL);
GstXmpTagTypeSeq, NULL, NULL);
_gst_xmp_schema_add_simple_mapping (schema, GST_TAG_DESCRIPTION,
"dc:description", GST_XMP_TAG_TYPE_SIMPLE, NULL, NULL);
"dc:description", GstXmpTagTypeSimple, NULL, NULL);
_gst_xmp_schema_add_simple_mapping (schema, GST_TAG_KEYWORDS,
"dc:subject", GST_XMP_TAG_TYPE_BAG, NULL, NULL);
"dc:subject", GstXmpTagTypeBag, NULL, NULL);
_gst_xmp_schema_add_simple_mapping (schema, GST_TAG_TITLE, "dc:title",
GST_XMP_TAG_TYPE_SIMPLE, NULL, NULL);
GstXmpTagTypeSimple, NULL, NULL);
/* FIXME: we probably want GST_TAG_{,AUDIO_,VIDEO_}MIME_TYPE */
_gst_xmp_schema_add_simple_mapping (schema, GST_TAG_VIDEO_CODEC,
"dc:format", GST_XMP_TAG_TYPE_SIMPLE, NULL, NULL);
"dc:format", GstXmpTagTypeSimple, NULL, NULL);
_gst_xmp_add_schema ("dc", schema);
/* xap (xmp) schema */
schema = gst_xmp_schema_new ();
_gst_xmp_schema_add_simple_mapping (schema, GST_TAG_USER_RATING,
"xmp:Rating", GST_XMP_TAG_TYPE_SIMPLE, NULL, deserialize_xmp_rating);
"xmp:Rating", GstXmpTagTypeSimple, NULL, deserialize_xmp_rating);
_gst_xmp_add_schema ("xap", schema);
/* tiff */
schema = gst_xmp_schema_new ();
_gst_xmp_schema_add_simple_mapping (schema,
GST_TAG_DEVICE_MANUFACTURER, "tiff:Make", GST_XMP_TAG_TYPE_SIMPLE, NULL,
GST_TAG_DEVICE_MANUFACTURER, "tiff:Make", GstXmpTagTypeSimple, NULL,
NULL);
_gst_xmp_schema_add_simple_mapping (schema, GST_TAG_DEVICE_MODEL,
"tiff:Model", GST_XMP_TAG_TYPE_SIMPLE, NULL, NULL);
"tiff:Model", GstXmpTagTypeSimple, NULL, NULL);
_gst_xmp_schema_add_simple_mapping (schema, GST_TAG_APPLICATION_NAME,
"tiff:Software", GST_XMP_TAG_TYPE_SIMPLE, NULL, NULL);
"tiff:Software", GstXmpTagTypeSimple, NULL, NULL);
_gst_xmp_schema_add_simple_mapping (schema, GST_TAG_IMAGE_ORIENTATION,
"tiff:Orientation", GST_XMP_TAG_TYPE_SIMPLE, serialize_tiff_orientation,
"tiff:Orientation", GstXmpTagTypeSimple, serialize_tiff_orientation,
deserialize_tiff_orientation);
_gst_xmp_add_schema ("tiff", schema);
/* exif schema */
schema = gst_xmp_schema_new ();
_gst_xmp_schema_add_simple_mapping (schema, GST_TAG_DATE_TIME,
"exif:DateTimeOriginal", GST_XMP_TAG_TYPE_SIMPLE, NULL, NULL);
"exif:DateTimeOriginal", GstXmpTagTypeSimple, NULL, NULL);
_gst_xmp_schema_add_simple_mapping (schema,
GST_TAG_GEO_LOCATION_LATITUDE, "exif:GPSLatitude",
GST_XMP_TAG_TYPE_SIMPLE, serialize_exif_latitude,
deserialize_exif_latitude);
GstXmpTagTypeSimple, serialize_exif_latitude, deserialize_exif_latitude);
_gst_xmp_schema_add_simple_mapping (schema, GST_TAG_GEO_LOCATION_LONGITUDE,
"exif:GPSLongitude", GST_XMP_TAG_TYPE_SIMPLE, serialize_exif_longitude,
"exif:GPSLongitude", GstXmpTagTypeSimple, serialize_exif_longitude,
deserialize_exif_longitude);
_gst_xmp_schema_add_simple_mapping (schema,
GST_TAG_CAPTURING_EXPOSURE_COMPENSATION, "exif:ExposureBiasValue",
GST_XMP_TAG_TYPE_SIMPLE, NULL, NULL);
GstXmpTagTypeSimple, NULL, NULL);
/* compound exif tags */
array = g_ptr_array_sized_new (2);
xmpinfo = g_slice_new (XmpTag);
xmpinfo->tag_name = "exif:GPSAltitude";
xmpinfo->serialize = serialize_exif_altitude;
xmpinfo->deserialize = deserialize_exif_altitude;
xmpinfo->type = GST_XMP_TAG_TYPE_SIMPLE;
g_ptr_array_add (array, xmpinfo);
xmpinfo = g_slice_new (XmpTag);
xmpinfo->tag_name = "exif:GPSAltitudeRef";
xmpinfo->serialize = serialize_exif_altituderef;
xmpinfo->deserialize = deserialize_exif_altitude;
xmpinfo->type = GST_XMP_TAG_TYPE_SIMPLE;
g_ptr_array_add (array, xmpinfo);
_gst_xmp_schema_add_mapping (schema, GST_TAG_GEO_LOCATION_ELEVATION, array);
xmpinfo = gst_xmp_tag_create_compound (GST_TAG_GEO_LOCATION_ELEVATION,
"exif:GPSAltitude", "exif:GPSAltitudeRef", serialize_exif_altitude,
serialize_exif_altituderef, deserialize_exif_altitude);
_gst_xmp_schema_add_mapping (schema, xmpinfo);
array = g_ptr_array_sized_new (2);
xmpinfo = g_slice_new (XmpTag);
xmpinfo->tag_name = "exif:GPSSpeed";
xmpinfo->serialize = serialize_exif_gps_speed;
xmpinfo->deserialize = deserialize_exif_gps_speed;
xmpinfo->type = GST_XMP_TAG_TYPE_SIMPLE;
g_ptr_array_add (array, xmpinfo);
xmpinfo = g_slice_new (XmpTag);
xmpinfo->tag_name = "exif:GPSSpeedRef";
xmpinfo->serialize = serialize_exif_gps_speedref;
xmpinfo->deserialize = deserialize_exif_gps_speed;
xmpinfo->type = GST_XMP_TAG_TYPE_SIMPLE;
g_ptr_array_add (array, xmpinfo);
_gst_xmp_schema_add_mapping (schema,
GST_TAG_GEO_LOCATION_MOVEMENT_SPEED, array);
xmpinfo = gst_xmp_tag_create_compound (GST_TAG_GEO_LOCATION_MOVEMENT_SPEED,
"exif:GPSSpeed", "exif:GPSSpeedRef", serialize_exif_gps_speed,
serialize_exif_gps_speedref, deserialize_exif_gps_speed);
_gst_xmp_schema_add_mapping (schema, xmpinfo);
array = g_ptr_array_sized_new (2);
xmpinfo = g_slice_new (XmpTag);
xmpinfo->tag_name = "exif:GPSTrack";
xmpinfo->serialize = serialize_exif_gps_direction;
xmpinfo->deserialize = deserialize_exif_gps_track;
xmpinfo->type = GST_XMP_TAG_TYPE_SIMPLE;
g_ptr_array_add (array, xmpinfo);
xmpinfo = g_slice_new (XmpTag);
xmpinfo->tag_name = "exif:GPSTrackRef";
xmpinfo->serialize = serialize_exif_gps_directionref;
xmpinfo->deserialize = deserialize_exif_gps_track;
xmpinfo->type = GST_XMP_TAG_TYPE_SIMPLE;
g_ptr_array_add (array, xmpinfo);
_gst_xmp_schema_add_mapping (schema,
GST_TAG_GEO_LOCATION_MOVEMENT_DIRECTION, array);
xmpinfo =
gst_xmp_tag_create_compound (GST_TAG_GEO_LOCATION_MOVEMENT_DIRECTION,
"exif:GPSTrack", "exif:GPSTrackRef", serialize_exif_gps_direction,
serialize_exif_gps_directionref, deserialize_exif_gps_track);
_gst_xmp_schema_add_mapping (schema, xmpinfo);
xmpinfo = gst_xmp_tag_create_compound (GST_TAG_GEO_LOCATION_CAPTURE_DIRECTION,
"exif:GPSImgDirection", "exif:GPSImgDirectionRef",
serialize_exif_gps_direction, serialize_exif_gps_directionref,
deserialize_exif_gps_img_direction);
_gst_xmp_schema_add_mapping (schema, xmpinfo);
array = g_ptr_array_sized_new (2);
xmpinfo = g_slice_new (XmpTag);
xmpinfo->tag_name = "exif:GPSImgDirection";
xmpinfo->serialize = serialize_exif_gps_direction;
xmpinfo->deserialize = deserialize_exif_gps_img_direction;
xmpinfo->type = GST_XMP_TAG_TYPE_SIMPLE;
g_ptr_array_add (array, xmpinfo);
xmpinfo = g_slice_new (XmpTag);
xmpinfo->tag_name = "exif:GPSImgDirectionRef";
xmpinfo->serialize = serialize_exif_gps_directionref;
xmpinfo->deserialize = deserialize_exif_gps_img_direction;
xmpinfo->type = GST_XMP_TAG_TYPE_SIMPLE;
g_ptr_array_add (array, xmpinfo);
_gst_xmp_schema_add_mapping (schema,
GST_TAG_GEO_LOCATION_CAPTURE_DIRECTION, array);
_gst_xmp_add_schema ("exif", schema);
/* photoshop schema */
schema = gst_xmp_schema_new ();
_gst_xmp_schema_add_simple_mapping (schema,
GST_TAG_GEO_LOCATION_COUNTRY, "photoshop:Country",
GST_XMP_TAG_TYPE_SIMPLE, NULL, NULL);
GstXmpTagTypeSimple, NULL, NULL);
_gst_xmp_schema_add_simple_mapping (schema, GST_TAG_GEO_LOCATION_CITY,
"photoshop:City", GST_XMP_TAG_TYPE_SIMPLE, NULL, NULL);
"photoshop:City", GstXmpTagTypeSimple, NULL, NULL);
_gst_xmp_add_schema ("photoshop", schema);
/* iptc4xmpcore schema */
schema = gst_xmp_schema_new ();
_gst_xmp_schema_add_simple_mapping (schema,
GST_TAG_GEO_LOCATION_SUBLOCATION, "Iptc4xmpCore:Location",
GST_XMP_TAG_TYPE_SIMPLE, NULL, NULL);
GstXmpTagTypeSimple, NULL, NULL);
_gst_xmp_add_schema ("Iptc4xmpCore", schema);
/* iptc4xmpext schema */
schema = gst_xmp_schema_new ();
xmpinfo = gst_xmp_tag_create (NULL, "Iptc4xmpExt:LocationShown",
GstXmpTagTypeStruct, NULL, NULL);
xmpinfo->children = g_slist_prepend (xmpinfo->children,
gst_xmp_tag_create (GST_TAG_GEO_LOCATION_SUBLOCATION,
"LocationDetails:Sublocation", GstXmpTagTypeSimple, NULL, NULL));
xmpinfo->children =
g_slist_prepend (xmpinfo->children,
gst_xmp_tag_create (GST_TAG_GEO_LOCATION_CITY,
"LocationDetails:City", GstXmpTagTypeSimple, NULL, NULL));
xmpinfo->children =
g_slist_prepend (xmpinfo->children,
gst_xmp_tag_create (GST_TAG_GEO_LOCATION_COUNTRY,
"LocationDetails:Country", GstXmpTagTypeSimple, NULL, NULL));
_gst_xmp_schema_add_mapping (schema, xmpinfo);
_gst_xmp_add_schema ("Iptc4xmpExt", schema);
return NULL;
}
@ -1004,6 +1050,7 @@ static const GstXmpNamespaceMatch ns_match[] = {
{"xap", "http://ns.adobe.com/xap/1.0/"},
{"photoshop", "http://ns.adobe.com/photoshop/1.0/"},
{"Iptc4xmpCore", "http://iptc.org/std/Iptc4xmpCore/1.0/xmlns/"},
{"Iptc4xmpExt", "http://iptc.org/std/Iptc4xmpExt/2008-02-29/"},
{NULL, NULL}
};
@ -1017,11 +1064,14 @@ struct _GstXmpNamespaceMap
/* parsing */
static void
read_one_tag (GstTagList * list, const gchar * tag, XmpTag * xmptag,
read_one_tag (GstTagList * list, XmpTag * xmptag,
const gchar * v, GSList ** pending_tags)
{
GType tag_type;
GstTagMergeMode merge_mode;
const gchar *tag = xmptag->gst_tag;
g_return_if_fail (tag != NULL);
if (xmptag && xmptag->deserialize) {
xmptag->deserialize (xmptag, list, tag, xmptag->tag_name, v, pending_tags);
@ -1208,17 +1258,27 @@ gst_tag_list_from_xmp_buffer (GstBuffer * buffer)
gboolean in_tag;
gchar *part, *pp;
guint i;
const gchar *last_tag = NULL;
XmpTag *last_xmp_tag = NULL;
GSList *pending_tags = NULL;
/* Used for strucuture xmp tags */
XmpTag *context_tag = NULL;
GstXmpNamespaceMap ns_map[] = {
{"dc", NULL},
{"exif", NULL},
{"tiff", NULL},
{"xap", NULL},
{"photoshop", NULL},
{"Iptc4xmpCore", NULL},
{"dc", NULL}
,
{"exif", NULL}
,
{"tiff", NULL}
,
{"xap", NULL}
,
{"photoshop", NULL}
,
{"Iptc4xmpCore", NULL}
,
{"Iptc4xmpExt", NULL}
,
{NULL, NULL}
};
@ -1226,6 +1286,8 @@ gst_tag_list_from_xmp_buffer (GstBuffer * buffer)
g_return_val_if_fail (GST_IS_BUFFER (buffer), NULL);
GST_LOG ("Starting xmp parsing");
xps = gst_buffer_map (buffer, &len, NULL, GST_MAP_READ);
g_return_val_if_fail (len > 0, NULL);
@ -1326,19 +1388,41 @@ gst_tag_list_from_xmp_buffer (GstBuffer * buffer)
}
}
} else {
const gchar *gst_tag;
XmpTag *xmp_tag = NULL;
/* FIXME: eventualy rewrite ns
* find ':'
* check if ns before ':' is in ns_map and ns_map[i].gstreamer_ns!=NULL
* do 2 stage filter in tag_matches
*/
gst_tag = _gst_xmp_tag_get_mapping_reverse (as, &xmp_tag);
if (gst_tag) {
if (context_tag) {
GSList *iter;
for (iter = context_tag->children; iter;
iter = g_slist_next (iter)) {
XmpTag *child = iter->data;
GST_DEBUG ("Looking at child tag %s : %s", child->tag_name,
as);
if (strcmp (child->tag_name, as) == 0) {
xmp_tag = child;
break;
}
}
} else {
GST_LOG ("Looking for tag: %s", as);
_gst_xmp_tag_get_mapping_reverse (as, &xmp_tag);
}
if (xmp_tag) {
PendingXmpTag *ptag;
GST_DEBUG ("Found xmp tag: %s -> %s", xmp_tag->tag_name,
xmp_tag->gst_tag);
/* we shouldn't find a xmp structure here */
g_assert (xmp_tag->gst_tag != NULL);
ptag = g_slice_new (PendingXmpTag);
ptag->gst_tag = gst_tag;
ptag->xmp_tag = xmp_tag;
ptag->str = g_strdup (v);
@ -1365,15 +1449,42 @@ gst_tag_list_from_xmp_buffer (GstBuffer * buffer)
/* skip rdf tags for now */
if (strncmp (part, "rdf:", 4)) {
const gchar *parttag;
/* if we're inside some struct, we look only on its children */
if (context_tag) {
GSList *iter;
parttag = _gst_xmp_tag_get_mapping_reverse (part, &last_xmp_tag);
if (parttag) {
last_tag = parttag;
/* check if this is the closing of the context */
if (part[0] == '/'
&& strcmp (part + 1, context_tag->tag_name) == 0) {
GST_DEBUG ("Closing context tag %s", part);
context_tag = NULL;
} else {
for (iter = context_tag->children; iter;
iter = g_slist_next (iter)) {
XmpTag *child = iter->data;
GST_DEBUG ("Looking at child tag %s : %s", child->tag_name,
part);
if (strcmp (child->tag_name, part) == 0) {
last_xmp_tag = child;
break;
}
}
}
} else {
GST_LOG ("Looking for tag: %s", part);
_gst_xmp_tag_get_mapping_reverse (part, &last_xmp_tag);
if (last_xmp_tag && last_xmp_tag->type == GstXmpTagTypeStruct) {
context_tag = last_xmp_tag;
last_xmp_tag = NULL;
}
}
}
}
}
GST_LOG ("Next cycle");
/* next cycle */
ne++;
if (ne < xp2) {
@ -1393,15 +1504,23 @@ gst_tag_list_from_xmp_buffer (GstBuffer * buffer)
if (ns[0] != '\n' && &ns[1] <= ne) {
/* only log non-newline nodes, we still have to parse them */
GST_INFO ("txt: %s", part);
if (last_tag) {
if (last_xmp_tag) {
PendingXmpTag *ptag;
ptag = g_slice_new (PendingXmpTag);
ptag->gst_tag = last_tag;
ptag->xmp_tag = last_xmp_tag;
ptag->str = g_strdup (part);
GST_DEBUG ("Found tag %s -> %s", last_xmp_tag->tag_name,
last_xmp_tag->gst_tag);
pending_tags = g_slist_append (pending_tags, ptag);
if (last_xmp_tag->type == GstXmpTagTypeStruct) {
g_assert (context_tag == NULL); /* we can't handle struct nesting currently */
context_tag = last_xmp_tag;
} else {
ptag = g_slice_new (PendingXmpTag);
ptag->xmp_tag = last_xmp_tag;
ptag->str = g_strdup (part);
pending_tags = g_slist_append (pending_tags, ptag);
}
}
}
/* next cycle */
@ -1416,7 +1535,7 @@ gst_tag_list_from_xmp_buffer (GstBuffer * buffer)
pending_tags = g_slist_delete_link (pending_tags, pending_tags);
read_one_tag (list, ptag->gst_tag, ptag->xmp_tag, ptag->str, &pending_tags);
read_one_tag (list, ptag->xmp_tag, ptag->str, &pending_tags);
g_free (ptag->str);
g_slice_free (PendingXmpTag, ptag);
@ -1522,70 +1641,93 @@ gst_value_serialize_xmp (const GValue * value)
}
static void
write_one_tag (const GstTagList * list, const gchar * tag, gpointer user_data)
write_one_tag (const GstTagList * list, XmpTag * xmp_tag, gpointer user_data)
{
guint i = 0, ct = gst_tag_list_get_tag_size (list, tag), tag_index;
guint i = 0, ct;
XmpSerializationData *serialization_data = user_data;
GString *data = serialization_data->data;
GPtrArray *xmp_tag_array = NULL;
char *s;
/* map gst-tag to xmp tag */
xmp_tag_array = _xmp_tag_get_mapping (tag, serialization_data);
/* struct type handled differently */
if (xmp_tag->type == GstXmpTagTypeStruct ||
xmp_tag->type == GstXmpTagTypeCompound) {
GSList *iter;
gboolean use_it = FALSE;
if (!xmp_tag_array) {
GST_WARNING ("no mapping for %s to xmp", tag);
/* check if any of the inner tags are present on the taglist */
for (iter = xmp_tag->children; iter && !use_it; iter = g_slist_next (iter)) {
XmpTag *child_tag = iter->data;
if (gst_tag_list_get_value_index (list, child_tag->gst_tag, 0) != NULL) {
use_it = TRUE;
break;
}
}
if (use_it) {
if (xmp_tag->tag_name)
string_open_tag (data, xmp_tag->tag_name);
/* now write it */
for (iter = xmp_tag->children; iter; iter = g_slist_next (iter)) {
write_one_tag (list, iter->data, user_data);
}
if (xmp_tag->tag_name)
string_close_tag (data, xmp_tag->tag_name);
}
return;
}
for (tag_index = 0; tag_index < xmp_tag_array->len; tag_index++) {
XmpTag *xmp_tag;
/* at this point we must have a gst_tag */
g_assert (xmp_tag->gst_tag);
if (gst_tag_list_get_value_index (list, xmp_tag->gst_tag, 0) == NULL)
return;
xmp_tag = g_ptr_array_index (xmp_tag_array, tag_index);
string_open_tag (data, xmp_tag->tag_name);
ct = gst_tag_list_get_tag_size (list, xmp_tag->gst_tag);
string_open_tag (data, xmp_tag->tag_name);
/* fast path for single valued tag */
if (ct == 1 || xmp_tag->type == GST_XMP_TAG_TYPE_SIMPLE) {
/* fast path for single valued tag */
if (ct == 1 || xmp_tag->type == GstXmpTagTypeSimple) {
if (xmp_tag->serialize) {
s = xmp_tag->serialize (gst_tag_list_get_value_index (list,
xmp_tag->gst_tag, 0));
} else {
s = gst_value_serialize_xmp (gst_tag_list_get_value_index (list,
xmp_tag->gst_tag, 0));
}
if (s) {
g_string_append (data, s);
g_free (s);
} else {
GST_WARNING ("unhandled type for %s to xmp", xmp_tag->gst_tag);
}
} else {
const gchar *typename;
typename = xmp_tag_get_type_name (xmp_tag);
string_open_tag (data, typename);
for (i = 0; i < ct; i++) {
GST_DEBUG ("mapping %s[%u/%u] to xmp", xmp_tag->gst_tag, i, ct);
if (xmp_tag->serialize) {
s = xmp_tag->serialize (gst_tag_list_get_value_index (list, tag, 0));
s = xmp_tag->serialize (gst_tag_list_get_value_index (list,
xmp_tag->gst_tag, i));
} else {
s = gst_value_serialize_xmp (gst_tag_list_get_value_index (list, tag,
0));
s = gst_value_serialize_xmp (gst_tag_list_get_value_index (list,
xmp_tag->gst_tag, i));
}
if (s) {
string_open_tag (data, "rdf:li");
g_string_append (data, s);
string_close_tag (data, "rdf:li");
g_free (s);
} else {
GST_WARNING ("unhandled type for %s to xmp", tag);
GST_WARNING ("unhandled type for %s to xmp", xmp_tag->gst_tag);
}
} else {
const gchar *typename;
typename = xmp_tag_get_type_name (xmp_tag);
string_open_tag (data, typename);
for (i = 0; i < ct; i++) {
GST_DEBUG ("mapping %s[%u/%u] to xmp", tag, i, ct);
if (xmp_tag->serialize) {
s = xmp_tag->serialize (gst_tag_list_get_value_index (list, tag, i));
} else {
s = gst_value_serialize_xmp (gst_tag_list_get_value_index (list, tag,
i));
}
if (s) {
string_open_tag (data, "rdf:li");
g_string_append (data, s);
string_close_tag (data, "rdf:li");
g_free (s);
} else {
GST_WARNING ("unhandled type for %s to xmp", tag);
}
}
string_close_tag (data, typename);
}
string_close_tag (data, xmp_tag->tag_name);
string_close_tag (data, typename);
}
string_close_tag (data, xmp_tag->tag_name);
}
/**
@ -1639,8 +1781,25 @@ gst_tag_list_to_xmp_buffer_full (const GstTagList * list, gboolean read_only,
g_string_append (data, ">\n");
g_string_append (data, "<rdf:Description rdf:about=\"\">\n");
/* iterate the taglist */
gst_tag_list_foreach (list, write_one_tag, &serialization_data);
/* iterate the schemas */
if (schemas == NULL) {
/* use all schemas */
schemas = gst_tag_xmp_list_schemas ();
}
for (i = 0; schemas[i] != NULL; i++) {
GstXmpSchema *schema = _gst_xmp_get_schema (schemas[i]);
GHashTableIter iter;
gpointer key, value;
if (schema == NULL)
continue;
/* Iterate over the hashtable */
g_hash_table_iter_init (&iter, schema);
while (g_hash_table_iter_next (&iter, &key, &value)) {
write_one_tag (list, value, (gpointer) & serialization_data);
}
}
/* xmp footer */
g_string_append (data, "</rdf:Description>\n");

View file

@ -1,4 +1,4 @@
/* GStreamer XmpConfig
/* GStreamer TagXmpWriter
* Copyright (C) 2010 Thiago Santos <thiago.sousa.santos@collabora.co.uk>
*
* This library is free software; you can redistribute it and/or
@ -18,7 +18,7 @@
*/
/**
* SECTION:gstxmpconfig
* SECTION:gsttagxmpwriter
* @short_description: Interface for elements that provide XMP serialization
*
* <refsect2>

View file

@ -34,6 +34,28 @@ A wide range of video and audio decoders, encoders, and filters are included.
</GitRepository>
</repository>
<release>
<Version>
<revision>0.10.34</revision>
<branch>0.10</branch>
<name>Lemmings</name>
<created>2011-05-13</created>
<file-release rdf:resource="http://gstreamer.freedesktop.org/src/gst-plugins-base/gst-plugins-base-0.10.34.tar.bz2" />
<file-release rdf:resource="http://gstreamer.freedesktop.org/src/gst-plugins-base/gst-plugins-base-0.10.34.tar.gz" />
</Version>
</release>
<release>
<Version>
<revision>0.10.33</revision>
<branch>0.10</branch>
<name>Relaxing Distractions</name>
<created>2011-05-10</created>
<file-release rdf:resource="http://gstreamer.freedesktop.org/src/gst-plugins-base/gst-plugins-base-0.10.33.tar.bz2" />
<file-release rdf:resource="http://gstreamer.freedesktop.org/src/gst-plugins-base/gst-plugins-base-0.10.33.tar.gz" />
</Version>
</release>
<release>
<Version>
<revision>0.10.32</revision>

View file

@ -928,6 +928,7 @@ _create_stream_group (GstEncodeBin * ebin, GstEncodingProfile * sprof,
GList *tmp, *tosync = NULL;
const GstCaps *format;
const GstCaps *restriction;
const gchar *missing_element_name;
format = gst_encoding_profile_get_format (sprof);
restriction = gst_encoding_profile_get_restriction (sprof);
@ -1177,10 +1178,19 @@ _create_stream_group (GstEncodeBin * ebin, GstEncodingProfile * sprof,
cspace = gst_element_factory_make ("ffmpegcolorspace", NULL);
scale = gst_element_factory_make ("videoscale", NULL);
if (!scale) {
missing_element_name = "videoscale";
goto missing_element;
}
/* 4-tap scaling and black borders */
g_object_set (scale, "method", 2, "add-borders", TRUE, NULL);
cspace2 = gst_element_factory_make ("ffmpegcolorspace", NULL);
if (!cspace || !cspace2) {
missing_element_name = "ffmpegcolorspace";
goto missing_element;
}
gst_bin_add_many ((GstBin *) ebin, cspace, scale, cspace2, NULL);
tosync = g_list_append (tosync, cspace);
tosync = g_list_append (tosync, scale);
@ -1197,6 +1207,11 @@ _create_stream_group (GstEncodeBin * ebin, GstEncodingProfile * sprof,
if (!gst_encoding_video_profile_get_variableframerate
(GST_ENCODING_VIDEO_PROFILE (sprof))) {
vrate = gst_element_factory_make ("videorate", NULL);
if (!vrate) {
missing_element_name = "videorate";
goto missing_element;
}
gst_bin_add ((GstBin *) ebin, vrate);
tosync = g_list_prepend (tosync, vrate);
sgroup->converters = g_list_prepend (sgroup->converters, vrate);
@ -1215,9 +1230,21 @@ _create_stream_group (GstEncodeBin * ebin, GstEncodingProfile * sprof,
arate = gst_element_factory_make ("audiorate", NULL);
g_object_set (arate, "tolerance", (guint64) ebin->tolerance, NULL);
if (!arate) {
missing_element_name = "audiorate";
goto missing_element;
}
aconv = gst_element_factory_make ("audioconvert", NULL);
aconv2 = gst_element_factory_make ("audioconvert", NULL);
ares = gst_element_factory_make ("audioresample", NULL);
if (!aconv || !aconv2) {
missing_element_name = "audioconvert";
goto missing_element;
}
if (!ares) {
missing_element_name = "audioresample";
goto missing_element;
}
gst_bin_add_many ((GstBin *) ebin, arate, aconv, ares, aconv2, NULL);
tosync = g_list_append (tosync, arate);
@ -1288,6 +1315,15 @@ no_muxer_pad:
"Couldn't find a compatible muxer pad to link encoder to");
goto cleanup;
missing_element:
gst_element_post_message (GST_ELEMENT_CAST (ebin),
gst_missing_element_message_new (GST_ELEMENT_CAST (ebin),
missing_element_name));
GST_ELEMENT_ERROR (ebin, CORE, MISSING_PLUGIN,
(_("Missing element '%s' - check your GStreamer installation."),
missing_element_name), (NULL));
goto cleanup;
encoder_link_failure:
GST_ERROR_OBJECT (ebin, "Failed to link the encoder");
goto cleanup;

View file

@ -18,6 +18,8 @@ libgstplaybin_la_SOURCES = \
gststreaminfo.c \
gststreamselector.c \
gstsubtitleoverlay.c \
gstplaysinkvideoconvert.c \
gstplaysinkaudioconvert.c \
gststreamsynchronizer.c
nodist_libgstplaybin_la_SOURCES = $(built_sources)
@ -57,6 +59,8 @@ noinst_HEADERS = \
gststreamselector.h \
gstrawcaps.h \
gstsubtitleoverlay.h \
gstplaysinkvideoconvert.h \
gstplaysinkaudioconvert.h \
gststreamsynchronizer.h
BUILT_SOURCES = $(built_headers) $(built_sources)

View file

@ -170,6 +170,8 @@ struct _GstDecodeBin
GList *blocked_pads; /* pads that have set to block */
gboolean expose_allstreams; /* Whether to expose unknow type streams or not */
gboolean upstream_seekable; /* if upstream is seekable */
};
struct _GstDecodeBinClass
@ -216,9 +218,10 @@ enum
/* automatic sizes, while prerolling we buffer up to 2MB, we ignore time
* and buffers in this case. */
#define AUTO_PREROLL_SIZE_BYTES 2 * 1024 * 1024
#define AUTO_PREROLL_SIZE_BUFFERS 0
#define AUTO_PREROLL_SIZE_TIME 0
#define AUTO_PREROLL_SIZE_BYTES 2 * 1024 * 1024
#define AUTO_PREROLL_SIZE_BUFFERS 0
#define AUTO_PREROLL_NOT_SEEKABLE_SIZE_TIME 0
#define AUTO_PREROLL_SEEKABLE_SIZE_TIME 10 * GST_SECOND
/* whan playing, keep a max of 2MB of data but try to keep the number of buffers
* as low as possible (try to aim for 5 buffers) */
@ -2042,6 +2045,48 @@ beach:
return;
}
/* check_upstream_seekable:
*
* Check if upstream is seekable.
*/
static void
check_upstream_seekable (GstDecodeBin * dbin, GstPad * pad)
{
GstQuery *query;
gint64 start = -1, stop = -1;
dbin->upstream_seekable = FALSE;
query = gst_query_new_seeking (GST_FORMAT_BYTES);
if (!gst_pad_peer_query (pad, query)) {
GST_DEBUG_OBJECT (dbin, "seeking query failed");
gst_query_unref (query);
return;
}
gst_query_parse_seeking (query, NULL, &dbin->upstream_seekable,
&start, &stop);
gst_query_unref (query);
/* try harder to query upstream size if we didn't get it the first time */
if (dbin->upstream_seekable && stop == -1) {
GstFormat fmt = GST_FORMAT_BYTES;
GST_DEBUG_OBJECT (dbin, "doing duration query to fix up unset stop");
gst_pad_query_peer_duration (pad, &fmt, &stop);
}
/* if upstream doesn't know the size, it's likely that it's not seekable in
* practice even if it technically may be seekable */
if (dbin->upstream_seekable && (start != 0 || stop <= start)) {
GST_DEBUG_OBJECT (dbin, "seekable but unknown start/stop -> disable");
dbin->upstream_seekable = FALSE;
}
GST_DEBUG_OBJECT (dbin, "upstream seekable: %d", dbin->upstream_seekable);
}
static void
type_found (GstElement * typefind, guint probability,
GstCaps * caps, GstDecodeBin * decode_bin)
@ -2070,6 +2115,10 @@ type_found (GstElement * typefind, guint probability,
pad = gst_element_get_static_pad (typefind, "src");
sink_pad = gst_element_get_static_pad (typefind, "sink");
/* if upstream is seekable we can safely set a limit in time to the queues so
* that streams at low bitrates can preroll */
check_upstream_seekable (decode_bin, sink_pad);
/* need some lock here to prevent race with shutdown state change
* which might yank away e.g. decode_chain while building stuff here.
* In typical cases, STREAM_LOCK is held and handles that, it need not
@ -2653,7 +2702,8 @@ decodebin_set_queue_size (GstDecodeBin * dbin, GstElement * multiqueue,
if ((max_buffers = dbin->max_size_buffers) == 0)
max_buffers = AUTO_PREROLL_SIZE_BUFFERS;
if ((max_time = dbin->max_size_time) == 0)
max_time = AUTO_PREROLL_SIZE_TIME;
max_time = dbin->upstream_seekable ? AUTO_PREROLL_SEEKABLE_SIZE_TIME :
AUTO_PREROLL_NOT_SEEKABLE_SIZE_TIME;
} else {
/* update runtime limits. At runtime, we try to keep the amount of buffers
* in the queues as low as possible (but at least 5 buffers). */

View file

@ -1,5 +1,6 @@
/* GStreamer
* Copyright (C) <2007> Wim Taymans <wim.taymans@gmail.com>
* Copyright (C) <2011> Sebastian Dröge <sebastian.droege@collabora.co.uk>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
@ -271,6 +272,14 @@ struct _GstSourceSelect
#define GST_SOURCE_GROUP_LOCK(group) (g_mutex_lock (GST_SOURCE_GROUP_GET_LOCK(group)))
#define GST_SOURCE_GROUP_UNLOCK(group) (g_mutex_unlock (GST_SOURCE_GROUP_GET_LOCK(group)))
enum
{
PLAYBIN_STREAM_AUDIO = 0,
PLAYBIN_STREAM_VIDEO,
PLAYBIN_STREAM_TEXT,
PLAYBIN_STREAM_LAST
};
/* a structure to hold the objects for decoding a uri and the subtitle uri
*/
struct _GstSourceGroup
@ -319,7 +328,7 @@ struct _GstSourceGroup
GList *stream_changed_pending;
/* selectors for different streams */
GstSourceSelect selector[GST_PLAY_SINK_TYPE_LAST];
GstSourceSelect selector[PLAYBIN_STREAM_LAST];
};
#define GST_PLAY_BIN_GET_LOCK(bin) (&((GstPlayBin*)(bin))->lock)
@ -1089,30 +1098,25 @@ init_group (GstPlayBin * playbin, GstSourceGroup * group)
/* If you add any items to these lists, check that media_list[] is defined
* above to be large enough to hold MAX(items)+1, so as to accomodate a
* NULL terminator (set when the memory is zeroed on allocation) */
group->selector[0].media_list[0] = "audio/x-raw-";
group->selector[0].type = GST_PLAY_SINK_TYPE_AUDIO_RAW;
group->selector[0].channels = group->audio_channels;
group->selector[1].media_list[0] = "audio/";
group->selector[1].type = GST_PLAY_SINK_TYPE_AUDIO;
group->selector[1].channels = group->audio_channels;
group->selector[2].media_list[0] = "text/";
group->selector[2].media_list[1] = "application/x-subtitle";
group->selector[2].media_list[2] = "application/x-ssa";
group->selector[2].media_list[3] = "application/x-ass";
group->selector[2].media_list[4] = "video/x-dvd-subpicture";
group->selector[2].media_list[5] = "subpicture/";
group->selector[2].media_list[6] = "subtitle/";
group->selector[2].get_media_caps = gst_subtitle_overlay_create_factory_caps;
group->selector[2].type = GST_PLAY_SINK_TYPE_TEXT;
group->selector[2].channels = group->text_channels;
group->selector[3].media_list[0] = "video/x-raw-";
group->selector[3].type = GST_PLAY_SINK_TYPE_VIDEO_RAW;
group->selector[3].channels = group->video_channels;
group->selector[4].media_list[0] = "video/";
group->selector[4].type = GST_PLAY_SINK_TYPE_VIDEO;
group->selector[4].channels = group->video_channels;
group->selector[PLAYBIN_STREAM_AUDIO].media_list[0] = "audio/";
group->selector[PLAYBIN_STREAM_AUDIO].type = GST_PLAY_SINK_TYPE_AUDIO;
group->selector[PLAYBIN_STREAM_AUDIO].channels = group->audio_channels;
group->selector[PLAYBIN_STREAM_VIDEO].media_list[0] = "video/";
group->selector[PLAYBIN_STREAM_VIDEO].type = GST_PLAY_SINK_TYPE_VIDEO;
group->selector[PLAYBIN_STREAM_VIDEO].channels = group->video_channels;
group->selector[PLAYBIN_STREAM_TEXT].media_list[0] = "text/";
group->selector[PLAYBIN_STREAM_TEXT].media_list[1] = "application/x-subtitle";
group->selector[PLAYBIN_STREAM_TEXT].media_list[2] = "application/x-ssa";
group->selector[PLAYBIN_STREAM_TEXT].media_list[3] = "application/x-ass";
group->selector[PLAYBIN_STREAM_TEXT].media_list[4] = "video/x-dvd-subpicture";
group->selector[PLAYBIN_STREAM_TEXT].media_list[5] = "subpicture/";
group->selector[PLAYBIN_STREAM_TEXT].media_list[6] = "subtitle/";
group->selector[PLAYBIN_STREAM_TEXT].get_media_caps =
gst_subtitle_overlay_create_factory_caps;
group->selector[PLAYBIN_STREAM_TEXT].type = GST_PLAY_SINK_TYPE_TEXT;
group->selector[PLAYBIN_STREAM_TEXT].channels = group->text_channels;
for (n = 0; n < GST_PLAY_SINK_TYPE_LAST; n++) {
for (n = 0; n < PLAYBIN_STREAM_LAST; n++) {
GstSourceSelect *select = &group->selector[n];
select->sinkpad_delayed_event = NULL;
select->sinkpad_data_probe = 0;
@ -1124,7 +1128,7 @@ free_group (GstPlayBin * playbin, GstSourceGroup * group)
{
int n;
for (n = 0; n < GST_PLAY_SINK_TYPE_LAST; n++) {
for (n = 0; n < PLAYBIN_STREAM_LAST; n++) {
GstSourceSelect *select = &group->selector[n];
if (select->sinkpad && select->sinkpad_data_probe)
gst_pad_remove_data_probe (select->sinkpad, select->sinkpad_data_probe);
@ -1493,6 +1497,10 @@ gst_play_bin_set_current_video_stream (GstPlayBin * playbin, gint stream)
GstPad *sinkpad;
GST_PLAY_BIN_LOCK (playbin);
GST_DEBUG_OBJECT (playbin, "Changing current video stream %d -> %d",
playbin->current_video, stream);
group = get_group (playbin);
if (!(channels = group->video_channels))
goto no_channels;
@ -1536,6 +1544,10 @@ gst_play_bin_set_current_audio_stream (GstPlayBin * playbin, gint stream)
GstPad *sinkpad;
GST_PLAY_BIN_LOCK (playbin);
GST_DEBUG_OBJECT (playbin, "Changing current audio stream %d -> %d",
playbin->current_audio, stream);
group = get_group (playbin);
if (!(channels = group->audio_channels))
goto no_channels;
@ -1651,6 +1663,10 @@ gst_play_bin_set_current_text_stream (GstPlayBin * playbin, gint stream)
GstPad *sinkpad;
GST_PLAY_BIN_LOCK (playbin);
GST_DEBUG_OBJECT (playbin, "Changing current text stream %d -> %d",
playbin->current_text, stream);
group = get_group (playbin);
if (!(channels = group->text_channels))
goto no_channels;
@ -2313,7 +2329,7 @@ selector_active_pad_changed (GObject * selector, GParamSpec * pspec,
GST_PLAY_BIN_LOCK (playbin);
group = get_group (playbin);
for (i = 0; i < GST_PLAY_SINK_TYPE_LAST; i++) {
for (i = 0; i < PLAYBIN_STREAM_LAST; i++) {
if (selector == G_OBJECT (group->selector[i].selector)) {
select = &group->selector[i];
}
@ -2399,7 +2415,7 @@ array_has_value (const gchar * values[], const gchar * value)
gint i;
for (i = 0; values[i]; i++) {
if (g_str_has_prefix (value, values[i]))
if (values[i] && g_str_has_prefix (value, values[i]))
return TRUE;
}
return FALSE;
@ -2471,7 +2487,7 @@ pad_added_cb (GstElement * decodebin, GstPad * pad, GstSourceGroup * group)
GST_DEBUG_PAD_NAME (pad), caps, group);
/* major type of the pad, this determines the selector to use */
for (i = 0; i < GST_PLAY_SINK_TYPE_LAST; i++) {
for (i = 0; i < PLAYBIN_STREAM_LAST; i++) {
if (array_has_value (group->selector[i].media_list, name)) {
select = &group->selector[i];
break;
@ -2730,7 +2746,7 @@ no_more_pads_cb (GstElement * decodebin, GstSourceGroup * group)
GST_PLAY_BIN_SHUTDOWN_LOCK (playbin, shutdown);
GST_SOURCE_GROUP_LOCK (group);
for (i = 0; i < GST_PLAY_SINK_TYPE_LAST; i++) {
for (i = 0; i < PLAYBIN_STREAM_LAST; i++) {
GstSourceSelect *select = &group->selector[i];
/* check if the specific media type was detected and thus has a selector
@ -2793,14 +2809,10 @@ no_more_pads_cb (GstElement * decodebin, GstSourceGroup * group)
GST_SOURCE_GROUP_UNLOCK (group);
GST_LOG_OBJECT (playbin, "reconfigure sink");
/* we configure the modes if we were the last decodebin to complete. */
gst_play_sink_reconfigure (playbin->playsink);
/* signal the other decodebins that they can continue now. */
GST_SOURCE_GROUP_LOCK (group);
/* unblock all selectors */
for (i = 0; i < GST_PLAY_SINK_TYPE_LAST; i++) {
for (i = 0; i < PLAYBIN_STREAM_LAST; i++) {
GstSourceSelect *select = &group->selector[i];
/* All streamsynchronizer streams should see stream-changed message,
@ -2866,7 +2878,7 @@ shutdown:
* instead of a NOT_LINKED error.
*/
GST_SOURCE_GROUP_LOCK (group);
for (i = 0; i < GST_PLAY_SINK_TYPE_LAST; i++) {
for (i = 0; i < PLAYBIN_STREAM_LAST; i++) {
GstSourceSelect *select = &group->selector[i];
if (select->srcpad) {
@ -3464,7 +3476,7 @@ deactivate_group (GstPlayBin * playbin, GstSourceGroup * group)
GST_SOURCE_GROUP_LOCK (group);
group->active = FALSE;
for (i = 0; i < GST_PLAY_SINK_TYPE_LAST; i++) {
for (i = 0; i < PLAYBIN_STREAM_LAST; i++) {
GstSourceSelect *select = &group->selector[i];
GST_DEBUG_OBJECT (playbin, "unlinking selector %s", select->media_list[0]);

View file

@ -1,5 +1,6 @@
/* GStreamer
* Copyright (C) <2007> Wim Taymans <wim.taymans@gmail.com>
* Copyright (C) <2011> Sebastian Dröge <sebastian.droege@collabora.co.uk>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
@ -30,6 +31,8 @@
#include "gstplaysink.h"
#include "gststreamsynchronizer.h"
#include "gstplaysinkvideoconvert.h"
#include "gstplaysinkaudioconvert.h"
GST_DEBUG_CATEGORY_STATIC (gst_play_sink_debug);
#define GST_CAT_DEFAULT gst_play_sink_debug
@ -58,7 +61,6 @@ typedef struct
GstPad *sinkpad;
GstElement *queue;
GstElement *conv;
GstElement *resample;
GstElement *volume; /* element with the volume property */
gboolean sink_volume; /* if the volume was provided by the sink */
GstElement *mute; /* element with the mute property */
@ -80,7 +82,6 @@ typedef struct
GstPad *sinkpad;
GstElement *queue;
GstElement *conv;
GstElement *scale;
GstElement *sink;
gboolean async;
GstElement *ts_offset;
@ -149,6 +150,7 @@ struct _GstPlaySink
/* audio */
GstPad *audio_pad;
gboolean audio_pad_raw;
gboolean audio_pad_blocked;
GstPad *audio_srcpad_stream_synchronizer;
GstPad *audio_sinkpad_stream_synchronizer;
/* audio tee */
@ -159,10 +161,12 @@ struct _GstPlaySink
/* video */
GstPad *video_pad;
gboolean video_pad_raw;
gboolean video_pad_blocked;
GstPad *video_srcpad_stream_synchronizer;
GstPad *video_sinkpad_stream_synchronizer;
/* text */
GstPad *text_pad;
gboolean text_pad_blocked;
GstPad *text_srcpad_stream_synchronizer;
GstPad *text_sinkpad_stream_synchronizer;
@ -191,21 +195,12 @@ struct _GstPlaySinkClass
GstBuffer *(*convert_frame) (GstPlaySink * playsink, GstCaps * caps);
};
static GstStaticPadTemplate audiorawtemplate =
GST_STATIC_PAD_TEMPLATE ("audio_raw_sink",
GST_PAD_SINK,
GST_PAD_REQUEST,
GST_STATIC_CAPS_ANY);
static GstStaticPadTemplate audiotemplate =
GST_STATIC_PAD_TEMPLATE ("audio_sink",
GST_PAD_SINK,
GST_PAD_REQUEST,
GST_STATIC_CAPS_ANY);
static GstStaticPadTemplate videorawtemplate =
GST_STATIC_PAD_TEMPLATE ("video_raw_sink",
GST_PAD_SINK,
GST_PAD_REQUEST,
GST_STATIC_CAPS_ANY);
static GstStaticPadTemplate videotemplate =
GST_STATIC_PAD_TEMPLATE ("video_sink",
GST_PAD_SINK,
@ -216,6 +211,19 @@ static GstStaticPadTemplate texttemplate = GST_STATIC_PAD_TEMPLATE ("text_sink",
GST_PAD_REQUEST,
GST_STATIC_CAPS_ANY);
/* FIXME 0.11: Remove */
static GstStaticPadTemplate audiorawtemplate =
GST_STATIC_PAD_TEMPLATE ("audio_raw_sink",
GST_PAD_SINK,
GST_PAD_REQUEST,
GST_STATIC_CAPS_ANY);
static GstStaticPadTemplate videorawtemplate =
GST_STATIC_PAD_TEMPLATE ("video_raw_sink",
GST_PAD_SINK,
GST_PAD_REQUEST,
GST_STATIC_CAPS_ANY);
/* props */
enum
{
@ -613,6 +621,7 @@ gst_play_sink_get_sink (GstPlaySink * playsink, GstPlaySinkType type)
GST_PLAY_SINK_LOCK (playsink);
switch (type) {
case GST_PLAY_SINK_TYPE_AUDIO:
case GST_PLAY_SINK_TYPE_AUDIO_RAW:
{
GstPlayAudioChain *chain;
if ((chain = (GstPlayAudioChain *) playsink->audiochain))
@ -621,6 +630,7 @@ gst_play_sink_get_sink (GstPlaySink * playsink, GstPlaySinkType type)
break;
}
case GST_PLAY_SINK_TYPE_VIDEO:
case GST_PLAY_SINK_TYPE_VIDEO_RAW:
{
GstPlayVideoChain *chain;
if ((chain = (GstPlayVideoChain *) playsink->videochain))
@ -1084,7 +1094,7 @@ try_element (GstPlaySink * playsink, GstElement * element, gboolean unref)
}
/* make the element (bin) that contains the elements needed to perform
* video display.
* video display. Only used for *raw* video streams.
*
* +------------------------------------------------------------+
* | vbin |
@ -1275,46 +1285,19 @@ gen_video_chain (GstPlaySink * playsink, gboolean raw, gboolean async)
head = prev = chain->queue;
}
if (raw && !(playsink->flags & GST_PLAY_FLAG_NATIVE_VIDEO)) {
GST_DEBUG_OBJECT (playsink, "creating ffmpegcolorspace");
chain->conv = gst_element_factory_make ("ffmpegcolorspace", "vconv");
if (chain->conv == NULL) {
post_missing_element_message (playsink, "ffmpegcolorspace");
GST_ELEMENT_WARNING (playsink, CORE, MISSING_PLUGIN,
(_("Missing element '%s' - check your GStreamer installation."),
"ffmpegcolorspace"), ("video rendering might fail"));
if (!(playsink->flags & GST_PLAY_FLAG_NATIVE_VIDEO)) {
GST_DEBUG_OBJECT (playsink, "creating videoconverter");
chain->conv =
g_object_new (GST_TYPE_PLAY_SINK_VIDEO_CONVERT, "name", "vconv", NULL);
gst_bin_add (bin, chain->conv);
if (prev) {
if (!gst_element_link_pads_full (prev, "src", chain->conv, "sink",
GST_PAD_LINK_CHECK_TEMPLATE_CAPS))
goto link_failed;
} else {
gst_bin_add (bin, chain->conv);
if (prev) {
if (!gst_element_link_pads_full (prev, "src", chain->conv, "sink",
GST_PAD_LINK_CHECK_TEMPLATE_CAPS))
goto link_failed;
} else {
head = chain->conv;
}
prev = chain->conv;
}
GST_DEBUG_OBJECT (playsink, "creating videoscale");
chain->scale = gst_element_factory_make ("videoscale", "vscale");
if (chain->scale == NULL) {
post_missing_element_message (playsink, "videoscale");
GST_ELEMENT_WARNING (playsink, CORE, MISSING_PLUGIN,
(_("Missing element '%s' - check your GStreamer installation."),
"videoscale"), ("possibly a liboil version mismatch?"));
} else {
/* Add black borders if necessary to keep the DAR */
g_object_set (chain->scale, "add-borders", TRUE, NULL);
gst_bin_add (bin, chain->scale);
if (prev) {
if (!gst_element_link_pads_full (prev, "src", chain->scale, "sink",
GST_PAD_LINK_CHECK_TEMPLATE_CAPS))
goto link_failed;
} else {
head = chain->scale;
}
prev = chain->scale;
head = chain->conv;
}
prev = chain->conv;
}
if (prev) {
@ -1385,13 +1368,12 @@ setup_video_chain (GstPlaySink * playsink, gboolean raw, gboolean async)
chain = playsink->videochain;
chain->chain.raw = raw;
/* if the chain was active we don't do anything */
if (GST_PLAY_CHAIN (chain)->activated == TRUE)
return TRUE;
if (chain->chain.raw != raw)
return FALSE;
/* try to set the sink element to READY again */
ret = gst_element_set_state (chain->sink, GST_STATE_READY);
if (ret == GST_STATE_CHANGE_FAILURE)
@ -1420,6 +1402,7 @@ setup_video_chain (GstPlaySink * playsink, gboolean raw, gboolean async)
}
/* make an element for playback of video with subtitles embedded.
* Only used for *raw* video streams.
*
* +--------------------------------------------+
* | tbin |
@ -1764,54 +1747,32 @@ gen_audio_chain (GstPlaySink * playsink, gboolean raw)
chain->sink_volume = FALSE;
}
if (raw && !(playsink->flags & GST_PLAY_FLAG_NATIVE_AUDIO)) {
if (!(playsink->flags & GST_PLAY_FLAG_NATIVE_AUDIO) || (!have_volume
&& playsink->flags & GST_PLAY_FLAG_SOFT_VOLUME)) {
GST_DEBUG_OBJECT (playsink, "creating audioconvert");
chain->conv = gst_element_factory_make ("audioconvert", "aconv");
if (chain->conv == NULL) {
post_missing_element_message (playsink, "audioconvert");
GST_ELEMENT_WARNING (playsink, CORE, MISSING_PLUGIN,
(_("Missing element '%s' - check your GStreamer installation."),
"audioconvert"), ("possibly a liboil version mismatch?"));
chain->conv =
g_object_new (GST_TYPE_PLAY_SINK_AUDIO_CONVERT, "name", "aconv", NULL);
gst_bin_add (bin, chain->conv);
if (prev) {
if (!gst_element_link_pads_full (prev, "src", chain->conv, "sink",
GST_PAD_LINK_CHECK_TEMPLATE_CAPS))
goto link_failed;
} else {
gst_bin_add (bin, chain->conv);
if (prev) {
if (!gst_element_link_pads_full (prev, "src", chain->conv, "sink",
GST_PAD_LINK_CHECK_TEMPLATE_CAPS))
goto link_failed;
} else {
head = chain->conv;
}
prev = chain->conv;
head = chain->conv;
}
prev = chain->conv;
GST_DEBUG_OBJECT (playsink, "creating audioresample");
chain->resample = gst_element_factory_make ("audioresample", "aresample");
if (chain->resample == NULL) {
post_missing_element_message (playsink, "audioresample");
GST_ELEMENT_WARNING (playsink, CORE, MISSING_PLUGIN,
(_("Missing element '%s' - check your GStreamer installation."),
"audioresample"), ("possibly a liboil version mismatch?"));
} else {
gst_bin_add (bin, chain->resample);
if (prev) {
if (!gst_element_link_pads_full (prev, "src", chain->resample, "sink",
GST_PAD_LINK_CHECK_TEMPLATE_CAPS))
goto link_failed;
} else {
head = chain->resample;
}
prev = chain->resample;
}
GST_PLAY_SINK_AUDIO_CONVERT_CAST (chain->conv)->use_converters =
!(playsink->flags & GST_PLAY_FLAG_NATIVE_AUDIO);
GST_PLAY_SINK_AUDIO_CONVERT_CAST (chain->conv)->use_volume = (!have_volume
&& playsink->flags & GST_PLAY_FLAG_SOFT_VOLUME);
if (!have_volume && playsink->flags & GST_PLAY_FLAG_SOFT_VOLUME) {
GST_DEBUG_OBJECT (playsink, "creating volume");
chain->volume = gst_element_factory_make ("volume", "volume");
if (chain->volume == NULL) {
post_missing_element_message (playsink, "volume");
GST_ELEMENT_WARNING (playsink, CORE, MISSING_PLUGIN,
(_("Missing element '%s' - check your GStreamer installation."),
"volume"), ("possibly a liboil version mismatch?"));
} else {
GstPlaySinkAudioConvert *conv =
GST_PLAY_SINK_AUDIO_CONVERT_CAST (chain->conv);
if (conv->volume) {
chain->volume = conv->volume;
have_volume = TRUE;
g_signal_connect (chain->volume, "notify::volume",
@ -1826,16 +1787,6 @@ gen_audio_chain (GstPlaySink * playsink, gboolean raw)
g_object_set (G_OBJECT (chain->volume), "volume", playsink->volume,
NULL);
g_object_set (G_OBJECT (chain->mute), "mute", playsink->mute, NULL);
gst_bin_add (bin, chain->volume);
if (prev) {
if (!gst_element_link_pads_full (prev, "src", chain->volume, "sink",
GST_PAD_LINK_CHECK_TEMPLATE_CAPS))
goto link_failed;
} else {
head = chain->volume;
}
prev = chain->volume;
}
}
}
@ -1917,13 +1868,12 @@ setup_audio_chain (GstPlaySink * playsink, gboolean raw)
chain = playsink->audiochain;
chain->chain.raw = raw;
/* if the chain was active we don't do anything */
if (GST_PLAY_CHAIN (chain)->activated == TRUE)
return TRUE;
if (chain->chain.raw != raw)
return FALSE;
/* try to set the sink element to READY again */
ret = gst_element_set_state (chain->sink, GST_STATE_READY);
if (ret == GST_STATE_CHANGE_FAILURE)
@ -1963,29 +1913,35 @@ setup_audio_chain (GstPlaySink * playsink, gboolean raw)
g_signal_connect (chain->mute, "notify::mute",
G_CALLBACK (notify_mute_cb), playsink);
}
GST_PLAY_SINK_AUDIO_CONVERT_CAST (chain->conv)->use_volume = FALSE;
} else {
GstPlaySinkAudioConvert *conv =
GST_PLAY_SINK_AUDIO_CONVERT_CAST (chain->conv);
/* no volume, we need to add a volume element when we can */
conv->use_volume = TRUE;
GST_DEBUG_OBJECT (playsink, "the sink has no volume property");
if (!raw) {
GST_LOG_OBJECT (playsink, "non-raw format, can't do soft volume control");
disconnect_chain (chain, playsink);
chain->volume = NULL;
chain->mute = NULL;
} else {
/* both last and current chain are raw audio, there should be a volume
* element already, unless the sink changed from one with a volume
* property to one that hasn't got a volume property, in which case we
* re-generate the chain */
if (chain->volume == NULL) {
GST_DEBUG_OBJECT (playsink, "no existing volume element to re-use");
/* undo background state change done earlier */
gst_element_set_state (chain->sink, GST_STATE_NULL);
return FALSE;
}
/* Disconnect signals */
disconnect_chain (chain, playsink);
GST_DEBUG_OBJECT (playsink, "reusing existing volume element");
if (conv->volume) {
chain->volume = conv->volume;
chain->mute = chain->volume;
g_signal_connect (chain->volume, "notify::volume",
G_CALLBACK (notify_volume_cb), playsink);
g_signal_connect (chain->mute, "notify::mute",
G_CALLBACK (notify_mute_cb), playsink);
/* configure with the latest volume and mute */
g_object_set (G_OBJECT (chain->volume), "volume", playsink->volume, NULL);
g_object_set (G_OBJECT (chain->mute), "mute", playsink->mute, NULL);
}
GST_DEBUG_OBJECT (playsink, "reusing existing volume element");
}
return TRUE;
}
@ -2864,6 +2820,196 @@ gst_play_sink_convert_frame (GstPlaySink * playsink, GstCaps * caps)
return result;
}
static gboolean
is_raw_structure (GstStructure * s)
{
const gchar *name;
name = gst_structure_get_name (s);
if (g_str_has_prefix (name, "video/x-raw-") ||
g_str_has_prefix (name, "audio/x-raw-"))
return TRUE;
return FALSE;
}
static gboolean
is_raw_pad (GstPad * pad)
{
GstPad *peer = gst_pad_get_peer (pad);
GstCaps *caps;
gboolean raw = TRUE;
if (!peer)
return raw;
caps = gst_pad_get_negotiated_caps (peer);
if (!caps) {
guint i, n;
caps = gst_pad_get_caps_reffed (peer);
n = gst_caps_get_size (caps);
for (i = 0; i < n; i++) {
gboolean r = is_raw_structure (gst_caps_get_structure (caps, i));
if (i == 0) {
raw = r;
} else if (raw != r) {
GST_ERROR_OBJECT (pad,
"Caps contains raw and non-raw structures: %" GST_PTR_FORMAT, caps);
raw = FALSE;
break;
}
}
} else {
raw = is_raw_structure (gst_caps_get_structure (caps, 0));
}
gst_caps_unref (caps);
gst_object_unref (peer);
return raw;
}
static void
sinkpad_blocked_cb (GstPad * blockedpad, gboolean blocked, gpointer user_data)
{
GstPlaySink *playsink = (GstPlaySink *) user_data;
GstPad *pad;
GST_PLAY_SINK_LOCK (playsink);
pad = GST_PAD_CAST (gst_proxy_pad_get_internal (GST_PROXY_PAD (blockedpad)));
if (pad == playsink->video_pad) {
playsink->video_pad_blocked = blocked;
GST_DEBUG_OBJECT (pad, "Video pad blocked: %d", blocked);
} else if (pad == playsink->audio_pad) {
playsink->audio_pad_blocked = blocked;
GST_DEBUG_OBJECT (pad, "Audio pad blocked: %d", blocked);
} else if (pad == playsink->text_pad) {
playsink->text_pad_blocked = blocked;
GST_DEBUG_OBJECT (pad, "Text pad blocked: %d", blocked);
}
if (!blocked) {
gst_object_unref (pad);
GST_PLAY_SINK_UNLOCK (playsink);
return;
}
if ((!playsink->video_pad || playsink->video_pad_blocked) &&
(!playsink->audio_pad || playsink->audio_pad_blocked) &&
(!playsink->text_pad || playsink->text_pad_blocked)) {
GST_DEBUG_OBJECT (playsink, "All pads blocked -- reconfiguring");
if (playsink->video_pad) {
playsink->video_pad_raw = is_raw_pad (playsink->video_pad);
GST_DEBUG_OBJECT (playsink, "Video pad is raw: %d",
playsink->video_pad_raw);
}
if (playsink->audio_pad) {
playsink->audio_pad_raw = is_raw_pad (playsink->audio_pad);
GST_DEBUG_OBJECT (playsink, "Audio pad is raw: %d",
playsink->audio_pad_raw);
}
gst_play_sink_reconfigure (playsink);
if (playsink->video_pad) {
GstPad *opad =
GST_PAD_CAST (gst_proxy_pad_get_internal (GST_PROXY_PAD
(playsink->video_pad)));
gst_pad_set_blocked_async_full (opad, FALSE, sinkpad_blocked_cb,
gst_object_ref (playsink), (GDestroyNotify) gst_object_unref);
gst_object_unref (opad);
}
if (playsink->audio_pad) {
GstPad *opad =
GST_PAD_CAST (gst_proxy_pad_get_internal (GST_PROXY_PAD
(playsink->audio_pad)));
gst_pad_set_blocked_async_full (opad, FALSE, sinkpad_blocked_cb,
gst_object_ref (playsink), (GDestroyNotify) gst_object_unref);
gst_object_unref (opad);
}
if (playsink->text_pad) {
GstPad *opad =
GST_PAD_CAST (gst_proxy_pad_get_internal (GST_PROXY_PAD
(playsink->text_pad)));
gst_pad_set_blocked_async_full (opad, FALSE, sinkpad_blocked_cb,
gst_object_ref (playsink), (GDestroyNotify) gst_object_unref);
gst_object_unref (opad);
}
}
gst_object_unref (pad);
GST_PLAY_SINK_UNLOCK (playsink);
}
static void
caps_notify_cb (GstPad * pad, GParamSpec * unused, GstPlaySink * playsink)
{
gboolean reconfigure = FALSE;
GstCaps *caps;
gboolean raw;
g_object_get (pad, "caps", &caps, NULL);
if (!caps)
return;
if (pad == playsink->audio_pad) {
raw = is_raw_pad (pad);
reconfigure = (! !playsink->audio_pad_raw != ! !raw)
&& playsink->audiochain;
GST_DEBUG_OBJECT (pad,
"Audio caps changed: raw %d reconfigure %d caps %" GST_PTR_FORMAT, raw,
reconfigure, caps);
} else if (pad == playsink->video_pad) {
raw = is_raw_pad (pad);
reconfigure = (! !playsink->video_pad_raw != ! !raw)
&& playsink->videochain;
GST_DEBUG_OBJECT (pad,
"Video caps changed: raw %d reconfigure %d caps %" GST_PTR_FORMAT, raw,
reconfigure, caps);
}
gst_caps_unref (caps);
if (reconfigure) {
GST_PLAY_SINK_LOCK (playsink);
if (playsink->video_pad) {
GstPad *opad =
GST_PAD_CAST (gst_proxy_pad_get_internal (GST_PROXY_PAD
(playsink->video_pad)));
gst_pad_set_blocked_async_full (opad, TRUE, sinkpad_blocked_cb,
gst_object_ref (playsink), (GDestroyNotify) gst_object_unref);
gst_object_unref (opad);
}
if (playsink->audio_pad) {
GstPad *opad =
GST_PAD_CAST (gst_proxy_pad_get_internal (GST_PROXY_PAD
(playsink->audio_pad)));
gst_pad_set_blocked_async_full (opad, TRUE, sinkpad_blocked_cb,
gst_object_ref (playsink), (GDestroyNotify) gst_object_unref);
gst_object_unref (opad);
}
if (playsink->text_pad) {
GstPad *opad =
GST_PAD_CAST (gst_proxy_pad_get_internal (GST_PROXY_PAD
(playsink->text_pad)));
gst_pad_set_blocked_async_full (opad, TRUE, sinkpad_blocked_cb,
gst_object_ref (playsink), (GDestroyNotify) gst_object_unref);
gst_object_unref (opad);
}
GST_PLAY_SINK_UNLOCK (playsink);
}
}
/**
* gst_play_sink_request_pad
* @playsink: a #GstPlaySink
@ -2878,7 +3024,6 @@ gst_play_sink_request_pad (GstPlaySink * playsink, GstPlaySinkType type)
{
GstPad *res = NULL;
gboolean created = FALSE;
gboolean raw = FALSE;
gboolean activate = TRUE;
const gchar *pad_name = NULL;
@ -2887,11 +3032,8 @@ gst_play_sink_request_pad (GstPlaySink * playsink, GstPlaySinkType type)
GST_PLAY_SINK_LOCK (playsink);
switch (type) {
case GST_PLAY_SINK_TYPE_AUDIO_RAW:
pad_name = "audio_raw_sink";
raw = TRUE;
case GST_PLAY_SINK_TYPE_AUDIO:
if (pad_name == NULL)
pad_name = "audio_sink";
pad_name = "audio_sink";
if (!playsink->audio_tee) {
GST_LOG_OBJECT (playsink, "creating tee");
/* create tee when needed. This element will feed the audio sink chain
@ -2917,24 +3059,25 @@ gst_play_sink_request_pad (GstPlaySink * playsink, GstPlaySinkType type)
GST_LOG_OBJECT (playsink, "ghosting tee sinkpad");
playsink->audio_pad =
gst_ghost_pad_new (pad_name, playsink->audio_tee_sink);
g_signal_connect (G_OBJECT (playsink->audio_pad), "notify::caps",
G_CALLBACK (caps_notify_cb), playsink);
created = TRUE;
}
playsink->audio_pad_raw = raw;
playsink->audio_pad_raw = FALSE;
res = playsink->audio_pad;
break;
case GST_PLAY_SINK_TYPE_VIDEO_RAW:
pad_name = "video_raw_sink";
raw = TRUE;
case GST_PLAY_SINK_TYPE_VIDEO:
if (pad_name == NULL)
pad_name = "video_sink";
pad_name = "video_sink";
if (!playsink->video_pad) {
GST_LOG_OBJECT (playsink, "ghosting videosink");
playsink->video_pad =
gst_ghost_pad_new_no_target (pad_name, GST_PAD_SINK);
g_signal_connect (G_OBJECT (playsink->video_pad), "notify::caps",
G_CALLBACK (caps_notify_cb), playsink);
created = TRUE;
}
playsink->video_pad_raw = raw;
playsink->video_pad_raw = FALSE;
res = playsink->video_pad;
break;
case GST_PLAY_SINK_TYPE_TEXT:
@ -2970,6 +3113,14 @@ gst_play_sink_request_pad (GstPlaySink * playsink, GstPlaySinkType type)
* element is 'running' */
gst_pad_set_active (res, TRUE);
gst_element_add_pad (GST_ELEMENT_CAST (playsink), res);
if (type != GST_PLAY_SINK_TYPE_FLUSHING) {
GstPad *blockpad =
GST_PAD_CAST (gst_proxy_pad_get_internal (GST_PROXY_PAD (res)));
gst_pad_set_blocked_async_full (blockpad, TRUE, sinkpad_blocked_cb,
gst_object_ref (playsink), (GDestroyNotify) gst_object_unref);
gst_object_unref (blockpad);
}
if (!activate)
gst_pad_set_active (res, activate);
}
@ -3026,8 +3177,12 @@ gst_play_sink_release_pad (GstPlaySink * playsink, GstPad * pad)
GST_PLAY_SINK_LOCK (playsink);
if (pad == playsink->video_pad) {
res = &playsink->video_pad;
g_signal_handlers_disconnect_by_func (playsink->video_pad, caps_notify_cb,
playsink);
} else if (pad == playsink->audio_pad) {
res = &playsink->audio_pad;
g_signal_handlers_disconnect_by_func (playsink->audio_pad, caps_notify_cb,
playsink);
} else if (pad == playsink->text_pad) {
res = &playsink->text_pad;
} else {
@ -3208,6 +3363,46 @@ gst_play_sink_change_state (GstElement * element, GstStateChange transition)
ret = GST_STATE_CHANGE_ASYNC;
break;
case GST_STATE_CHANGE_PAUSED_TO_READY:
/* unblock all pads here */
GST_PLAY_SINK_LOCK (playsink);
if (playsink->video_pad) {
GstPad *opad =
GST_PAD_CAST (gst_proxy_pad_get_internal (GST_PROXY_PAD
(playsink->video_pad)));
if (gst_pad_is_blocked (opad)) {
gst_pad_set_blocked_async_full (opad, FALSE, sinkpad_blocked_cb,
gst_object_ref (playsink), (GDestroyNotify) gst_object_unref);
}
gst_object_unref (opad);
playsink->video_pad_blocked = FALSE;
}
if (playsink->audio_pad) {
GstPad *opad =
GST_PAD_CAST (gst_proxy_pad_get_internal (GST_PROXY_PAD
(playsink->audio_pad)));
if (gst_pad_is_blocked (opad)) {
gst_pad_set_blocked_async_full (opad, FALSE, sinkpad_blocked_cb,
gst_object_ref (playsink), (GDestroyNotify) gst_object_unref);
}
gst_object_unref (opad);
playsink->audio_pad_blocked = FALSE;
}
if (playsink->text_pad) {
GstPad *opad =
GST_PAD_CAST (gst_proxy_pad_get_internal (GST_PROXY_PAD
(playsink->text_pad)));
if (gst_pad_is_blocked (opad)) {
gst_pad_set_blocked_async_full (opad, FALSE, sinkpad_blocked_cb,
gst_object_ref (playsink), (GDestroyNotify) gst_object_unref);
}
gst_object_unref (opad);
playsink->text_pad_blocked = FALSE;
}
GST_PLAY_SINK_UNLOCK (playsink);
/* fall through */
case GST_STATE_CHANGE_READY_TO_NULL:
if (playsink->audiochain && playsink->audiochain->sink_volume) {
/* remove our links to the mute and volume elements when they were

View file

@ -41,11 +41,11 @@ G_BEGIN_DECLS
/**
* GstPlaySinkType:
* @GST_PLAY_SINK_TYPE_AUDIO: A non-raw audio pad
* @GST_PLAY_SINK_TYPE_AUDIO_RAW: a raw audio pad
* @GST_PLAY_SINK_TYPE_VIDEO: a non-raw video pad
* @GST_PLAY_SINK_TYPE_VIDEO_RAW: a raw video pad
* @GST_PLAY_SINK_TYPE_TEXT: a raw text pad
* @GST_PLAY_SINK_TYPE_AUDIO: an audio pad
* @GST_PLAY_SINK_TYPE_AUDIO_RAW: a raw audio pad. Deprecated.
* @GST_PLAY_SINK_TYPE_VIDEO: a video pad
* @GST_PLAY_SINK_TYPE_VIDEO_RAW: a raw video pad. Deprecated.
* @GST_PLAY_SINK_TYPE_TEXT: a text pad
* @GST_PLAY_SINK_TYPE_LAST: the last type
* @GST_PLAY_SINK_TYPE_FLUSHING: a flushing pad, used when shutting down
*

View file

@ -0,0 +1,516 @@
/* GStreamer
* Copyright (C) <2011> Sebastian Dröge <sebastian.droege@collabora.co.uk>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "gstplaysinkaudioconvert.h"
#include <gst/pbutils/pbutils.h>
#include <gst/gst-i18n-plugin.h>
GST_DEBUG_CATEGORY_STATIC (gst_play_sink_audio_convert_debug);
#define GST_CAT_DEFAULT gst_play_sink_audio_convert_debug
#define parent_class gst_play_sink_audio_convert_parent_class
G_DEFINE_TYPE (GstPlaySinkAudioConvert, gst_play_sink_audio_convert,
GST_TYPE_BIN);
static GstStaticPadTemplate srctemplate = GST_STATIC_PAD_TEMPLATE ("src",
GST_PAD_SRC,
GST_PAD_ALWAYS,
GST_STATIC_CAPS_ANY);
static GstStaticPadTemplate sinktemplate = GST_STATIC_PAD_TEMPLATE ("sink",
GST_PAD_SINK,
GST_PAD_ALWAYS,
GST_STATIC_CAPS_ANY);
static gboolean
is_raw_caps (GstCaps * caps)
{
gint i, n;
GstStructure *s;
const gchar *name;
n = gst_caps_get_size (caps);
for (i = 0; i < n; i++) {
s = gst_caps_get_structure (caps, i);
name = gst_structure_get_name (s);
if (!g_str_has_prefix (name, "audio/x-raw"))
return FALSE;
}
return TRUE;
}
static void
post_missing_element_message (GstPlaySinkAudioConvert * self,
const gchar * name)
{
GstMessage *msg;
msg = gst_missing_element_message_new (GST_ELEMENT_CAST (self), name);
gst_element_post_message (GST_ELEMENT_CAST (self), msg);
}
static void
distribute_running_time (GstElement * element, const GstSegment * segment)
{
GstEvent *event;
GstPad *pad;
pad = gst_element_get_static_pad (element, "sink");
if (segment->accum) {
event = gst_event_new_new_segment_full (FALSE, segment->rate,
segment->applied_rate, segment->format, 0, segment->accum, 0);
gst_pad_push_event (pad, event);
}
event = gst_event_new_new_segment_full (FALSE, segment->rate,
segment->applied_rate, segment->format,
segment->start, segment->stop, segment->time);
gst_pad_push_event (pad, event);
gst_object_unref (pad);
}
static void
pad_blocked_cb (GstPad * pad, gboolean blocked, GstPlaySinkAudioConvert * self)
{
GstPad *peer;
GstCaps *caps;
gboolean raw;
GST_PLAY_SINK_AUDIO_CONVERT_LOCK (self);
self->sink_proxypad_blocked = blocked;
GST_DEBUG_OBJECT (self, "Pad blocked: %d", blocked);
if (!blocked)
goto done;
/* There must be a peer at this point */
peer = gst_pad_get_peer (self->sinkpad);
caps = gst_pad_get_negotiated_caps (peer);
if (!caps)
caps = gst_pad_get_caps_reffed (peer);
gst_object_unref (peer);
raw = is_raw_caps (caps);
GST_DEBUG_OBJECT (self, "Caps %" GST_PTR_FORMAT " are raw: %d", caps, raw);
gst_caps_unref (caps);
if (raw == self->raw)
goto unblock;
self->raw = raw;
if (raw) {
GstBin *bin = GST_BIN_CAST (self);
GstElement *head = NULL, *prev = NULL;
GstPad *pad;
GST_DEBUG_OBJECT (self, "Creating raw conversion pipeline");
gst_ghost_pad_set_target (GST_GHOST_PAD_CAST (self->sinkpad), NULL);
gst_ghost_pad_set_target (GST_GHOST_PAD_CAST (self->srcpad), NULL);
if (self->use_converters) {
self->conv = gst_element_factory_make ("audioconvert", "conv");
if (self->conv == NULL) {
post_missing_element_message (self, "audioconvert");
GST_ELEMENT_WARNING (self, CORE, MISSING_PLUGIN,
(_("Missing element '%s' - check your GStreamer installation."),
"audioconvert"), ("audio rendering might fail"));
} else {
gst_bin_add (bin, self->conv);
gst_element_sync_state_with_parent (self->conv);
distribute_running_time (self->conv, &self->segment);
prev = head = self->conv;
}
self->resample = gst_element_factory_make ("audioresample", "resample");
if (self->resample == NULL) {
post_missing_element_message (self, "audioresample");
GST_ELEMENT_WARNING (self, CORE, MISSING_PLUGIN,
(_("Missing element '%s' - check your GStreamer installation."),
"audioresample"), ("possibly a liboil version mismatch?"));
} else {
gst_bin_add (bin, self->resample);
gst_element_sync_state_with_parent (self->resample);
distribute_running_time (self->resample, &self->segment);
if (prev) {
if (!gst_element_link_pads_full (prev, "src", self->resample, "sink",
GST_PAD_LINK_CHECK_TEMPLATE_CAPS))
goto link_failed;
} else {
head = self->resample;
}
prev = self->resample;
}
}
if (self->use_volume && self->volume) {
gst_bin_add (bin, gst_object_ref (self->volume));
gst_element_sync_state_with_parent (self->volume);
distribute_running_time (self->volume, &self->segment);
if (prev) {
if (!gst_element_link_pads_full (prev, "src", self->volume, "sink",
GST_PAD_LINK_CHECK_TEMPLATE_CAPS))
goto link_failed;
} else {
head = self->volume;
}
prev = self->volume;
}
if (head) {
pad = gst_element_get_static_pad (head, "sink");
gst_ghost_pad_set_target (GST_GHOST_PAD_CAST (self->sinkpad), pad);
gst_object_unref (pad);
}
if (prev) {
pad = gst_element_get_static_pad (prev, "src");
gst_ghost_pad_set_target (GST_GHOST_PAD_CAST (self->srcpad), pad);
gst_object_unref (pad);
}
if (!head && !prev) {
gst_ghost_pad_set_target (GST_GHOST_PAD_CAST (self->srcpad),
self->sink_proxypad);
}
GST_DEBUG_OBJECT (self, "Raw conversion pipeline created");
} else {
GstBin *bin = GST_BIN_CAST (self);
GST_DEBUG_OBJECT (self, "Removing raw conversion pipeline");
gst_ghost_pad_set_target (GST_GHOST_PAD_CAST (self->sinkpad), NULL);
gst_ghost_pad_set_target (GST_GHOST_PAD_CAST (self->srcpad), NULL);
if (self->conv) {
gst_element_set_state (self->conv, GST_STATE_NULL);
gst_bin_remove (bin, self->conv);
self->conv = NULL;
}
if (self->resample) {
gst_element_set_state (self->resample, GST_STATE_NULL);
gst_bin_remove (bin, self->resample);
self->resample = NULL;
}
if (self->volume) {
gst_element_set_state (self->volume, GST_STATE_NULL);
if (GST_OBJECT_PARENT (self->volume) == GST_OBJECT_CAST (self)) {
gst_bin_remove (GST_BIN_CAST (self), self->volume);
}
}
gst_ghost_pad_set_target (GST_GHOST_PAD_CAST (self->srcpad),
self->sink_proxypad);
GST_DEBUG_OBJECT (self, "Raw conversion pipeline removed");
}
unblock:
gst_pad_set_blocked_async_full (self->sink_proxypad, FALSE,
(GstPadBlockCallback) pad_blocked_cb, gst_object_ref (self),
(GDestroyNotify) gst_object_unref);
done:
GST_PLAY_SINK_AUDIO_CONVERT_UNLOCK (self);
return;
link_failed:
{
GST_ELEMENT_ERROR (self, CORE, PAD,
(NULL), ("Failed to configure the audio converter."));
gst_ghost_pad_set_target (GST_GHOST_PAD_CAST (self->srcpad),
self->sink_proxypad);
gst_pad_set_blocked_async_full (self->sink_proxypad, FALSE,
(GstPadBlockCallback) pad_blocked_cb, gst_object_ref (self),
(GDestroyNotify) gst_object_unref);
return;
}
}
static gboolean
gst_play_sink_audio_convert_sink_event (GstPad * pad, GstEvent * event)
{
GstPlaySinkAudioConvert *self =
GST_PLAY_SINK_AUDIO_CONVERT (gst_pad_get_parent (pad));
gboolean ret;
ret = gst_proxy_pad_event_default (pad, gst_event_ref (event));
if (GST_EVENT_TYPE (event) == GST_EVENT_NEWSEGMENT) {
gboolean update;
gdouble rate, applied_rate;
GstFormat format;
gint64 start, stop, position;
GST_PLAY_SINK_AUDIO_CONVERT_LOCK (self);
gst_event_parse_new_segment_full (event, &update, &rate, &applied_rate,
&format, &start, &stop, &position);
GST_DEBUG_OBJECT (self, "Segment before %" GST_SEGMENT_FORMAT,
&self->segment);
gst_segment_set_newsegment_full (&self->segment, update, rate, applied_rate,
format, start, stop, position);
GST_DEBUG_OBJECT (self, "Segment after %" GST_SEGMENT_FORMAT,
&self->segment);
GST_PLAY_SINK_AUDIO_CONVERT_UNLOCK (self);
} else if (GST_EVENT_TYPE (event) == GST_EVENT_FLUSH_STOP) {
GST_PLAY_SINK_AUDIO_CONVERT_LOCK (self);
GST_DEBUG_OBJECT (self, "Resetting segment");
gst_segment_init (&self->segment, GST_FORMAT_UNDEFINED);
GST_PLAY_SINK_AUDIO_CONVERT_UNLOCK (self);
}
gst_event_unref (event);
gst_object_unref (self);
return ret;
}
static gboolean
gst_play_sink_audio_convert_sink_setcaps (GstPad * pad, GstCaps * caps)
{
GstPlaySinkAudioConvert *self =
GST_PLAY_SINK_AUDIO_CONVERT (gst_pad_get_parent (pad));
gboolean ret;
GstStructure *s;
const gchar *name;
gboolean reconfigure = FALSE;
GST_PLAY_SINK_AUDIO_CONVERT_LOCK (self);
s = gst_caps_get_structure (caps, 0);
name = gst_structure_get_name (s);
if (g_str_has_prefix (name, "audio/x-raw-")) {
if (!self->raw && !gst_pad_is_blocked (self->sink_proxypad)) {
GST_DEBUG_OBJECT (self, "Changing caps from non-raw to raw");
reconfigure = TRUE;
gst_pad_set_blocked_async_full (self->sink_proxypad, TRUE,
(GstPadBlockCallback) pad_blocked_cb, gst_object_ref (self),
(GDestroyNotify) gst_object_unref);
}
} else {
if (self->raw && !gst_pad_is_blocked (self->sink_proxypad)) {
GST_DEBUG_OBJECT (self, "Changing caps from raw to non-raw");
reconfigure = TRUE;
gst_pad_set_blocked_async_full (self->sink_proxypad, TRUE,
(GstPadBlockCallback) pad_blocked_cb, gst_object_ref (self),
(GDestroyNotify) gst_object_unref);
}
}
/* Otherwise the setcaps below fails */
if (reconfigure) {
gst_ghost_pad_set_target (GST_GHOST_PAD_CAST (self->sinkpad), NULL);
gst_ghost_pad_set_target (GST_GHOST_PAD_CAST (self->srcpad), NULL);
}
GST_PLAY_SINK_AUDIO_CONVERT_UNLOCK (self);
ret = gst_ghost_pad_setcaps_default (pad, caps);
GST_DEBUG_OBJECT (self, "Setting sink caps %" GST_PTR_FORMAT ": %d", caps,
ret);
gst_object_unref (self);
return ret;
}
static GstCaps *
gst_play_sink_audio_convert_getcaps (GstPad * pad)
{
GstPlaySinkAudioConvert *self =
GST_PLAY_SINK_AUDIO_CONVERT (gst_pad_get_parent (pad));
GstCaps *ret;
GstPad *otherpad, *peer;
GST_PLAY_SINK_AUDIO_CONVERT_LOCK (self);
if (pad == self->srcpad)
otherpad = gst_object_ref (self->sinkpad);
else
otherpad = gst_object_ref (self->srcpad);
GST_PLAY_SINK_AUDIO_CONVERT_UNLOCK (self);
peer = gst_pad_get_peer (otherpad);
if (peer) {
ret = gst_pad_get_caps_reffed (peer);
gst_object_unref (peer);
} else {
ret = gst_caps_new_any ();
}
gst_object_unref (otherpad);
gst_object_unref (self);
return ret;
}
static void
gst_play_sink_audio_convert_finalize (GObject * object)
{
GstPlaySinkAudioConvert *self = GST_PLAY_SINK_AUDIO_CONVERT_CAST (object);
if (self->volume)
gst_object_unref (self->volume);
gst_object_unref (self->sink_proxypad);
g_mutex_free (self->lock);
G_OBJECT_CLASS (parent_class)->finalize (object);
}
static GstStateChangeReturn
gst_play_sink_audio_convert_change_state (GstElement * element,
GstStateChange transition)
{
GstStateChangeReturn ret;
GstPlaySinkAudioConvert *self = GST_PLAY_SINK_AUDIO_CONVERT_CAST (element);
switch (transition) {
case GST_STATE_CHANGE_PAUSED_TO_READY:
GST_PLAY_SINK_AUDIO_CONVERT_LOCK (self);
if (gst_pad_is_blocked (self->sink_proxypad))
gst_pad_set_blocked_async_full (self->sink_proxypad, FALSE,
(GstPadBlockCallback) pad_blocked_cb, gst_object_ref (self),
(GDestroyNotify) gst_object_unref);
GST_PLAY_SINK_AUDIO_CONVERT_UNLOCK (self);
break;
default:
break;
}
ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
if (ret == GST_STATE_CHANGE_FAILURE)
return ret;
switch (transition) {
case GST_STATE_CHANGE_PAUSED_TO_READY:
GST_PLAY_SINK_AUDIO_CONVERT_LOCK (self);
gst_segment_init (&self->segment, GST_FORMAT_UNDEFINED);
if (self->conv) {
gst_element_set_state (self->conv, GST_STATE_NULL);
gst_bin_remove (GST_BIN_CAST (self), self->conv);
self->conv = NULL;
}
if (self->resample) {
gst_element_set_state (self->resample, GST_STATE_NULL);
gst_bin_remove (GST_BIN_CAST (self), self->resample);
self->resample = NULL;
}
if (self->volume) {
gst_element_set_state (self->volume, GST_STATE_NULL);
if (GST_OBJECT_PARENT (self->volume) == GST_OBJECT_CAST (self)) {
gst_bin_remove (GST_BIN_CAST (self), self->volume);
}
}
gst_ghost_pad_set_target (GST_GHOST_PAD_CAST (self->srcpad),
self->sink_proxypad);
self->raw = FALSE;
GST_PLAY_SINK_AUDIO_CONVERT_UNLOCK (self);
break;
case GST_STATE_CHANGE_READY_TO_PAUSED:
GST_PLAY_SINK_AUDIO_CONVERT_LOCK (self);
if (!gst_pad_is_blocked (self->sink_proxypad))
gst_pad_set_blocked_async_full (self->sink_proxypad, TRUE,
(GstPadBlockCallback) pad_blocked_cb, gst_object_ref (self),
(GDestroyNotify) gst_object_unref);
GST_PLAY_SINK_AUDIO_CONVERT_UNLOCK (self);
default:
break;
}
return ret;
}
static void
gst_play_sink_audio_convert_class_init (GstPlaySinkAudioConvertClass * klass)
{
GObjectClass *gobject_class;
GstElementClass *gstelement_class;
GST_DEBUG_CATEGORY_INIT (gst_play_sink_audio_convert_debug,
"playsinkaudioconvert", 0, "play bin");
gobject_class = (GObjectClass *) klass;
gstelement_class = (GstElementClass *) klass;
gobject_class->finalize = gst_play_sink_audio_convert_finalize;
gst_element_class_add_pad_template (gstelement_class,
gst_static_pad_template_get (&srctemplate));
gst_element_class_add_pad_template (gstelement_class,
gst_static_pad_template_get (&sinktemplate));
gst_element_class_set_details_simple (gstelement_class,
"Player Sink Audio Converter", "Audio/Bin/Converter",
"Convenience bin for audio conversion",
"Sebastian Dröge <sebastian.droege@collabora.co.uk>");
gstelement_class->change_state =
GST_DEBUG_FUNCPTR (gst_play_sink_audio_convert_change_state);
}
static void
gst_play_sink_audio_convert_init (GstPlaySinkAudioConvert * self)
{
GstPadTemplate *templ;
self->lock = g_mutex_new ();
gst_segment_init (&self->segment, GST_FORMAT_UNDEFINED);
templ = gst_static_pad_template_get (&sinktemplate);
self->sinkpad = gst_ghost_pad_new_no_target_from_template ("sink", templ);
gst_pad_set_event_function (self->sinkpad,
GST_DEBUG_FUNCPTR (gst_play_sink_audio_convert_sink_event));
gst_pad_set_setcaps_function (self->sinkpad,
GST_DEBUG_FUNCPTR (gst_play_sink_audio_convert_sink_setcaps));
gst_pad_set_getcaps_function (self->sinkpad,
GST_DEBUG_FUNCPTR (gst_play_sink_audio_convert_getcaps));
self->sink_proxypad =
GST_PAD_CAST (gst_proxy_pad_get_internal (GST_PROXY_PAD (self->sinkpad)));
gst_element_add_pad (GST_ELEMENT_CAST (self), self->sinkpad);
gst_object_unref (templ);
templ = gst_static_pad_template_get (&srctemplate);
self->srcpad = gst_ghost_pad_new_no_target_from_template ("src", templ);
gst_pad_set_getcaps_function (self->srcpad,
GST_DEBUG_FUNCPTR (gst_play_sink_audio_convert_getcaps));
gst_element_add_pad (GST_ELEMENT_CAST (self), self->srcpad);
gst_object_unref (templ);
gst_ghost_pad_set_target (GST_GHOST_PAD_CAST (self->srcpad),
self->sink_proxypad);
/* FIXME: Only create this on demand but for now we need
* it to always exist because of playsink's volume proxying
* logic.
*/
self->volume = gst_element_factory_make ("volume", "volume");
if (self->volume)
gst_object_ref_sink (self->volume);
}

View file

@ -0,0 +1,89 @@
/* GStreamer
* Copyright (C) <2011> Sebastian Dröge <sebastian.droege@collabora.co.uk>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#include <gst/gst.h>
#ifndef __GST_PLAY_SINK_AUDIO_CONVERT_H__
#define __GST_PLAY_SINK_AUDIO_CONVERT_H__
G_BEGIN_DECLS
#define GST_TYPE_PLAY_SINK_AUDIO_CONVERT \
(gst_play_sink_audio_convert_get_type())
#define GST_PLAY_SINK_AUDIO_CONVERT(obj) \
(G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_PLAY_SINK_AUDIO_CONVERT, GstPlaySinkAudioConvert))
#define GST_PLAY_SINK_AUDIO_CONVERT_CAST(obj) \
((GstPlaySinkAudioConvert *) obj)
#define GST_PLAY_SINK_AUDIO_CONVERT_CLASS(klass) \
(G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_PLAY_SINK_AUDIO_CONVERT, GstPlaySinkAudioConvertClass))
#define GST_IS_PLAY_SINK_AUDIO_CONVERT(obj) \
(G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_PLAY_SINK_AUDIO_CONVERT))
#define GST_IS_PLAY_SINK_AUDIO_CONVERT_CLASS(klass) \
(G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_PLAY_SINK_AUDIO_CONVERT))
#define GST_PLAY_SINK_AUDIO_CONVERT_LOCK(obj) G_STMT_START { \
GST_LOG_OBJECT (obj, \
"locking from thread %p", \
g_thread_self ()); \
g_mutex_lock (GST_PLAY_SINK_AUDIO_CONVERT_CAST(obj)->lock); \
GST_LOG_OBJECT (obj, \
"locked from thread %p", \
g_thread_self ()); \
} G_STMT_END
#define GST_PLAY_SINK_AUDIO_CONVERT_UNLOCK(obj) G_STMT_START { \
GST_LOG_OBJECT (obj, \
"unlocking from thread %p", \
g_thread_self ()); \
g_mutex_unlock (GST_PLAY_SINK_AUDIO_CONVERT_CAST(obj)->lock); \
} G_STMT_END
typedef struct _GstPlaySinkAudioConvert GstPlaySinkAudioConvert;
typedef struct _GstPlaySinkAudioConvertClass GstPlaySinkAudioConvertClass;
struct _GstPlaySinkAudioConvert
{
GstBin parent;
/* < private > */
GMutex *lock;
GstPad *sinkpad, *sink_proxypad;
gboolean sink_proxypad_blocked;
GstSegment segment;
GstPad *srcpad;
gboolean raw;
GstElement *conv, *resample;
/* < pseudo public > */
GstElement *volume;
gboolean use_volume;
gboolean use_converters;
};
struct _GstPlaySinkAudioConvertClass
{
GstBinClass parent;
};
GType gst_play_sink_audio_convert_get_type (void);
G_END_DECLS
#endif /* __GST_PLAY_SINK_AUDIO_CONVERT_H__ */

View file

@ -0,0 +1,479 @@
/* GStreamer
* Copyright (C) <2011> Sebastian Dröge <sebastian.droege@collabora.co.uk>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "gstplaysinkvideoconvert.h"
#include <gst/pbutils/pbutils.h>
#include <gst/gst-i18n-plugin.h>
GST_DEBUG_CATEGORY_STATIC (gst_play_sink_video_convert_debug);
#define GST_CAT_DEFAULT gst_play_sink_video_convert_debug
#define parent_class gst_play_sink_video_convert_parent_class
G_DEFINE_TYPE (GstPlaySinkVideoConvert, gst_play_sink_video_convert,
GST_TYPE_BIN);
static GstStaticPadTemplate srctemplate = GST_STATIC_PAD_TEMPLATE ("src",
GST_PAD_SRC,
GST_PAD_ALWAYS,
GST_STATIC_CAPS_ANY);
static GstStaticPadTemplate sinktemplate = GST_STATIC_PAD_TEMPLATE ("sink",
GST_PAD_SINK,
GST_PAD_ALWAYS,
GST_STATIC_CAPS_ANY);
static gboolean
is_raw_caps (GstCaps * caps)
{
gint i, n;
GstStructure *s;
const gchar *name;
n = gst_caps_get_size (caps);
for (i = 0; i < n; i++) {
s = gst_caps_get_structure (caps, i);
name = gst_structure_get_name (s);
if (!g_str_has_prefix (name, "video/x-raw"))
return FALSE;
}
return TRUE;
}
static void
post_missing_element_message (GstPlaySinkVideoConvert * self,
const gchar * name)
{
GstMessage *msg;
msg = gst_missing_element_message_new (GST_ELEMENT_CAST (self), name);
gst_element_post_message (GST_ELEMENT_CAST (self), msg);
}
static void
distribute_running_time (GstElement * element, const GstSegment * segment)
{
GstEvent *event;
GstPad *pad;
pad = gst_element_get_static_pad (element, "sink");
if (segment->accum) {
event = gst_event_new_new_segment_full (FALSE, segment->rate,
segment->applied_rate, segment->format, 0, segment->accum, 0);
gst_pad_push_event (pad, event);
}
event = gst_event_new_new_segment_full (FALSE, segment->rate,
segment->applied_rate, segment->format,
segment->start, segment->stop, segment->time);
gst_pad_push_event (pad, event);
gst_object_unref (pad);
}
static void
pad_blocked_cb (GstPad * pad, gboolean blocked, GstPlaySinkVideoConvert * self)
{
GstPad *peer;
GstCaps *caps;
gboolean raw;
GST_PLAY_SINK_VIDEO_CONVERT_LOCK (self);
self->sink_proxypad_blocked = blocked;
GST_DEBUG_OBJECT (self, "Pad blocked: %d", blocked);
if (!blocked)
goto done;
/* There must be a peer at this point */
peer = gst_pad_get_peer (self->sinkpad);
caps = gst_pad_get_negotiated_caps (peer);
if (!caps)
caps = gst_pad_get_caps_reffed (peer);
gst_object_unref (peer);
raw = is_raw_caps (caps);
GST_DEBUG_OBJECT (self, "Caps %" GST_PTR_FORMAT " are raw: %d", caps, raw);
gst_caps_unref (caps);
if (raw == self->raw)
goto unblock;
self->raw = raw;
if (raw) {
GstBin *bin = GST_BIN_CAST (self);
GstElement *head = NULL, *prev = NULL;
GstPad *pad;
GST_DEBUG_OBJECT (self, "Creating raw conversion pipeline");
gst_ghost_pad_set_target (GST_GHOST_PAD_CAST (self->sinkpad), NULL);
gst_ghost_pad_set_target (GST_GHOST_PAD_CAST (self->srcpad), NULL);
self->conv = gst_element_factory_make ("ffmpegcolorspace", "conv");
if (self->conv == NULL) {
post_missing_element_message (self, "ffmpegcolorspace");
GST_ELEMENT_WARNING (self, CORE, MISSING_PLUGIN,
(_("Missing element '%s' - check your GStreamer installation."),
"ffmpegcolorspace"), ("video rendering might fail"));
} else {
gst_bin_add (bin, self->conv);
gst_element_sync_state_with_parent (self->conv);
distribute_running_time (self->conv, &self->segment);
prev = head = self->conv;
}
self->scale = gst_element_factory_make ("videoscale", "scale");
if (self->scale == NULL) {
post_missing_element_message (self, "videoscale");
GST_ELEMENT_WARNING (self, CORE, MISSING_PLUGIN,
(_("Missing element '%s' - check your GStreamer installation."),
"videoscale"), ("possibly a liboil version mismatch?"));
} else {
/* Add black borders if necessary to keep the DAR */
g_object_set (self->scale, "add-borders", TRUE, NULL);
gst_bin_add (bin, self->scale);
gst_element_sync_state_with_parent (self->scale);
distribute_running_time (self->scale, &self->segment);
if (prev) {
if (!gst_element_link_pads_full (prev, "src", self->scale, "sink",
GST_PAD_LINK_CHECK_TEMPLATE_CAPS))
goto link_failed;
} else {
head = self->scale;
}
prev = self->scale;
}
if (head) {
pad = gst_element_get_static_pad (head, "sink");
gst_ghost_pad_set_target (GST_GHOST_PAD_CAST (self->sinkpad), pad);
gst_object_unref (pad);
}
if (prev) {
pad = gst_element_get_static_pad (prev, "src");
gst_ghost_pad_set_target (GST_GHOST_PAD_CAST (self->srcpad), pad);
gst_object_unref (pad);
}
if (!head && !prev) {
gst_ghost_pad_set_target (GST_GHOST_PAD_CAST (self->srcpad),
self->sink_proxypad);
}
GST_DEBUG_OBJECT (self, "Raw conversion pipeline created");
} else {
GstBin *bin = GST_BIN_CAST (self);
GST_DEBUG_OBJECT (self, "Removing raw conversion pipeline");
gst_ghost_pad_set_target (GST_GHOST_PAD_CAST (self->sinkpad), NULL);
gst_ghost_pad_set_target (GST_GHOST_PAD_CAST (self->srcpad), NULL);
if (self->conv) {
gst_element_set_state (self->conv, GST_STATE_NULL);
gst_bin_remove (bin, self->conv);
self->conv = NULL;
}
if (self->scale) {
gst_element_set_state (self->scale, GST_STATE_NULL);
gst_bin_remove (bin, self->scale);
self->scale = NULL;
}
gst_ghost_pad_set_target (GST_GHOST_PAD_CAST (self->srcpad),
self->sink_proxypad);
GST_DEBUG_OBJECT (self, "Raw conversion pipeline removed");
}
unblock:
gst_pad_set_blocked_async_full (self->sink_proxypad, FALSE,
(GstPadBlockCallback) pad_blocked_cb, gst_object_ref (self),
(GDestroyNotify) gst_object_unref);
done:
GST_PLAY_SINK_VIDEO_CONVERT_UNLOCK (self);
return;
link_failed:
{
GST_ELEMENT_ERROR (self, CORE, PAD,
(NULL), ("Failed to configure the video converter."));
gst_ghost_pad_set_target (GST_GHOST_PAD_CAST (self->srcpad),
self->sink_proxypad);
gst_pad_set_blocked_async_full (self->sink_proxypad, FALSE,
(GstPadBlockCallback) pad_blocked_cb, gst_object_ref (self),
(GDestroyNotify) gst_object_unref);
return;
}
}
static gboolean
gst_play_sink_video_convert_sink_event (GstPad * pad, GstEvent * event)
{
GstPlaySinkVideoConvert *self =
GST_PLAY_SINK_VIDEO_CONVERT (gst_pad_get_parent (pad));
gboolean ret;
ret = gst_proxy_pad_event_default (pad, gst_event_ref (event));
if (GST_EVENT_TYPE (event) == GST_EVENT_NEWSEGMENT) {
gboolean update;
gdouble rate, applied_rate;
GstFormat format;
gint64 start, stop, position;
GST_PLAY_SINK_VIDEO_CONVERT_LOCK (self);
gst_event_parse_new_segment_full (event, &update, &rate, &applied_rate,
&format, &start, &stop, &position);
GST_DEBUG_OBJECT (self, "Segment before %" GST_SEGMENT_FORMAT,
&self->segment);
gst_segment_set_newsegment_full (&self->segment, update, rate, applied_rate,
format, start, stop, position);
GST_DEBUG_OBJECT (self, "Segment after %" GST_SEGMENT_FORMAT,
&self->segment);
GST_PLAY_SINK_VIDEO_CONVERT_UNLOCK (self);
} else if (GST_EVENT_TYPE (event) == GST_EVENT_FLUSH_STOP) {
GST_PLAY_SINK_VIDEO_CONVERT_LOCK (self);
GST_DEBUG_OBJECT (self, "Resetting segment");
gst_segment_init (&self->segment, GST_FORMAT_UNDEFINED);
GST_PLAY_SINK_VIDEO_CONVERT_UNLOCK (self);
}
gst_event_unref (event);
gst_object_unref (self);
return ret;
}
static gboolean
gst_play_sink_video_convert_sink_setcaps (GstPad * pad, GstCaps * caps)
{
GstPlaySinkVideoConvert *self =
GST_PLAY_SINK_VIDEO_CONVERT (gst_pad_get_parent (pad));
gboolean ret;
GstStructure *s;
const gchar *name;
gboolean reconfigure = FALSE;
GST_PLAY_SINK_VIDEO_CONVERT_LOCK (self);
s = gst_caps_get_structure (caps, 0);
name = gst_structure_get_name (s);
if (g_str_has_prefix (name, "video/x-raw-")) {
if (!self->raw && !gst_pad_is_blocked (self->sink_proxypad)) {
GST_DEBUG_OBJECT (self, "Changing caps from non-raw to raw");
reconfigure = TRUE;
gst_pad_set_blocked_async_full (self->sink_proxypad, TRUE,
(GstPadBlockCallback) pad_blocked_cb, gst_object_ref (self),
(GDestroyNotify) gst_object_unref);
}
} else {
if (self->raw && !gst_pad_is_blocked (self->sink_proxypad)) {
GST_DEBUG_OBJECT (self, "Changing caps from raw to non-raw");
reconfigure = TRUE;
gst_pad_set_blocked_async_full (self->sink_proxypad, TRUE,
(GstPadBlockCallback) pad_blocked_cb, gst_object_ref (self),
(GDestroyNotify) gst_object_unref);
}
}
/* Otherwise the setcaps below fails */
if (reconfigure) {
gst_ghost_pad_set_target (GST_GHOST_PAD_CAST (self->sinkpad), NULL);
gst_ghost_pad_set_target (GST_GHOST_PAD_CAST (self->srcpad), NULL);
}
GST_PLAY_SINK_VIDEO_CONVERT_UNLOCK (self);
ret = gst_ghost_pad_setcaps_default (pad, caps);
GST_DEBUG_OBJECT (self, "Setting sink caps %" GST_PTR_FORMAT ": %d", caps,
ret);
gst_object_unref (self);
return ret;
}
static GstCaps *
gst_play_sink_video_convert_getcaps (GstPad * pad)
{
GstPlaySinkVideoConvert *self =
GST_PLAY_SINK_VIDEO_CONVERT (gst_pad_get_parent (pad));
GstCaps *ret;
GstPad *otherpad, *peer;
GST_PLAY_SINK_VIDEO_CONVERT_LOCK (self);
if (pad == self->srcpad)
otherpad = gst_object_ref (self->sinkpad);
else
otherpad = gst_object_ref (self->srcpad);
GST_PLAY_SINK_VIDEO_CONVERT_UNLOCK (self);
peer = gst_pad_get_peer (otherpad);
if (peer) {
ret = gst_pad_get_caps_reffed (peer);
gst_object_unref (peer);
} else {
ret = gst_caps_new_any ();
}
gst_object_unref (otherpad);
gst_object_unref (self);
return ret;
}
static void
gst_play_sink_video_convert_finalize (GObject * object)
{
GstPlaySinkVideoConvert *self = GST_PLAY_SINK_VIDEO_CONVERT_CAST (object);
gst_object_unref (self->sink_proxypad);
g_mutex_free (self->lock);
G_OBJECT_CLASS (parent_class)->finalize (object);
}
static GstStateChangeReturn
gst_play_sink_video_convert_change_state (GstElement * element,
GstStateChange transition)
{
GstStateChangeReturn ret;
GstPlaySinkVideoConvert *self = GST_PLAY_SINK_VIDEO_CONVERT_CAST (element);
switch (transition) {
case GST_STATE_CHANGE_PAUSED_TO_READY:
GST_PLAY_SINK_VIDEO_CONVERT_LOCK (self);
if (gst_pad_is_blocked (self->sink_proxypad))
gst_pad_set_blocked_async_full (self->sink_proxypad, FALSE,
(GstPadBlockCallback) pad_blocked_cb, gst_object_ref (self),
(GDestroyNotify) gst_object_unref);
GST_PLAY_SINK_VIDEO_CONVERT_UNLOCK (self);
break;
default:
break;
}
ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
if (ret == GST_STATE_CHANGE_FAILURE)
return ret;
switch (transition) {
case GST_STATE_CHANGE_PAUSED_TO_READY:
GST_PLAY_SINK_VIDEO_CONVERT_LOCK (self);
gst_segment_init (&self->segment, GST_FORMAT_UNDEFINED);
if (self->conv) {
gst_element_set_state (self->conv, GST_STATE_NULL);
gst_bin_remove (GST_BIN_CAST (self), self->conv);
self->conv = NULL;
}
if (self->scale) {
gst_element_set_state (self->scale, GST_STATE_NULL);
gst_bin_remove (GST_BIN_CAST (self), self->scale);
self->scale = NULL;
}
gst_ghost_pad_set_target (GST_GHOST_PAD_CAST (self->srcpad),
self->sink_proxypad);
self->raw = FALSE;
GST_PLAY_SINK_VIDEO_CONVERT_UNLOCK (self);
break;
case GST_STATE_CHANGE_READY_TO_PAUSED:
GST_PLAY_SINK_VIDEO_CONVERT_LOCK (self);
if (!gst_pad_is_blocked (self->sink_proxypad))
gst_pad_set_blocked_async_full (self->sink_proxypad, TRUE,
(GstPadBlockCallback) pad_blocked_cb, gst_object_ref (self),
(GDestroyNotify) gst_object_unref);
GST_PLAY_SINK_VIDEO_CONVERT_UNLOCK (self);
default:
break;
}
return ret;
}
static void
gst_play_sink_video_convert_class_init (GstPlaySinkVideoConvertClass * klass)
{
GObjectClass *gobject_class;
GstElementClass *gstelement_class;
GST_DEBUG_CATEGORY_INIT (gst_play_sink_video_convert_debug,
"playsinkvideoconvert", 0, "play bin");
gobject_class = (GObjectClass *) klass;
gstelement_class = (GstElementClass *) klass;
gobject_class->finalize = gst_play_sink_video_convert_finalize;
gst_element_class_add_pad_template (gstelement_class,
gst_static_pad_template_get (&srctemplate));
gst_element_class_add_pad_template (gstelement_class,
gst_static_pad_template_get (&sinktemplate));
gst_element_class_set_details_simple (gstelement_class,
"Player Sink Video Converter", "Video/Bin/Converter",
"Convenience bin for video conversion",
"Sebastian Dröge <sebastian.droege@collabora.co.uk>");
gstelement_class->change_state =
GST_DEBUG_FUNCPTR (gst_play_sink_video_convert_change_state);
}
static void
gst_play_sink_video_convert_init (GstPlaySinkVideoConvert * self)
{
GstPadTemplate *templ;
self->lock = g_mutex_new ();
gst_segment_init (&self->segment, GST_FORMAT_UNDEFINED);
templ = gst_static_pad_template_get (&sinktemplate);
self->sinkpad = gst_ghost_pad_new_no_target_from_template ("sink", templ);
gst_pad_set_event_function (self->sinkpad,
GST_DEBUG_FUNCPTR (gst_play_sink_video_convert_sink_event));
gst_pad_set_setcaps_function (self->sinkpad,
GST_DEBUG_FUNCPTR (gst_play_sink_video_convert_sink_setcaps));
gst_pad_set_getcaps_function (self->sinkpad,
GST_DEBUG_FUNCPTR (gst_play_sink_video_convert_getcaps));
self->sink_proxypad =
GST_PAD_CAST (gst_proxy_pad_get_internal (GST_PROXY_PAD (self->sinkpad)));
gst_element_add_pad (GST_ELEMENT_CAST (self), self->sinkpad);
gst_object_unref (templ);
templ = gst_static_pad_template_get (&srctemplate);
self->srcpad = gst_ghost_pad_new_no_target_from_template ("src", templ);
gst_pad_set_getcaps_function (self->srcpad,
GST_DEBUG_FUNCPTR (gst_play_sink_video_convert_getcaps));
gst_element_add_pad (GST_ELEMENT_CAST (self), self->srcpad);
gst_object_unref (templ);
gst_ghost_pad_set_target (GST_GHOST_PAD_CAST (self->srcpad),
self->sink_proxypad);
}

View file

@ -0,0 +1,84 @@
/* GStreamer
* Copyright (C) <2011> Sebastian Dröge <sebastian.droege@collabora.co.uk>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#include <gst/gst.h>
#ifndef __GST_PLAY_SINK_VIDEO_CONVERT_H__
#define __GST_PLAY_SINK_VIDEO_CONVERT_H__
G_BEGIN_DECLS
#define GST_TYPE_PLAY_SINK_VIDEO_CONVERT \
(gst_play_sink_video_convert_get_type())
#define GST_PLAY_SINK_VIDEO_CONVERT(obj) \
(G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_PLAY_SINK_VIDEO_CONVERT, GstPlaySinkVideoConvert))
#define GST_PLAY_SINK_VIDEO_CONVERT_CAST(obj) \
((GstPlaySinkVideoConvert *) obj)
#define GST_PLAY_SINK_VIDEO_CONVERT_CLASS(klass) \
(G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_PLAY_SINK_VIDEO_CONVERT, GstPlaySinkVideoConvertClass))
#define GST_IS_PLAY_SINK_VIDEO_CONVERT(obj) \
(G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_PLAY_SINK_VIDEO_CONVERT))
#define GST_IS_PLAY_SINK_VIDEO_CONVERT_CLASS(klass) \
(G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_PLAY_SINK_VIDEO_CONVERT))
#define GST_PLAY_SINK_VIDEO_CONVERT_LOCK(obj) G_STMT_START { \
GST_LOG_OBJECT (obj, \
"locking from thread %p", \
g_thread_self ()); \
g_mutex_lock (GST_PLAY_SINK_VIDEO_CONVERT_CAST(obj)->lock); \
GST_LOG_OBJECT (obj, \
"locked from thread %p", \
g_thread_self ()); \
} G_STMT_END
#define GST_PLAY_SINK_VIDEO_CONVERT_UNLOCK(obj) G_STMT_START { \
GST_LOG_OBJECT (obj, \
"unlocking from thread %p", \
g_thread_self ()); \
g_mutex_unlock (GST_PLAY_SINK_VIDEO_CONVERT_CAST(obj)->lock); \
} G_STMT_END
typedef struct _GstPlaySinkVideoConvert GstPlaySinkVideoConvert;
typedef struct _GstPlaySinkVideoConvertClass GstPlaySinkVideoConvertClass;
struct _GstPlaySinkVideoConvert
{
GstBin parent;
/* < private > */
GMutex *lock;
GstPad *sinkpad, *sink_proxypad;
gboolean sink_proxypad_blocked;
GstSegment segment;
GstPad *srcpad;
gboolean raw;
GstElement *conv, *scale;
};
struct _GstPlaySinkVideoConvertClass
{
GstBinClass parent;
};
GType gst_play_sink_video_convert_get_type (void);
G_END_DECLS
#endif /* __GST_PLAY_SINK_VIDEO_CONVERT_H__ */

View file

@ -1544,7 +1544,7 @@ gst_subtitle_overlay_src_proxy_chain (GstPad * proxypad, GstBuffer * buffer)
return GST_FLOW_ERROR;
}
ret = self->src_proxy_chain (proxypad, buffer);
ret = gst_proxy_pad_chain_default (proxypad, buffer);
if (IS_VIDEO_CHAIN_IGNORE_ERROR (ret)) {
GST_ERROR_OBJECT (self, "Downstream chain error: %s",
@ -1581,7 +1581,7 @@ gst_subtitle_overlay_src_proxy_event (GstPad * proxypad, GstEvent * event)
event = NULL;
ret = TRUE;
} else {
ret = self->src_proxy_event (proxypad, event);
ret = gst_proxy_pad_event_default (proxypad, event);
event = NULL;
}
@ -1619,7 +1619,7 @@ gst_subtitle_overlay_video_sink_setcaps (GstPad * pad, GstCaps * caps)
}
GST_SUBTITLE_OVERLAY_UNLOCK (self);
ret = self->video_sink_setcaps (pad, caps);
ret = gst_ghost_pad_setcaps_default (pad, caps);
out:
gst_object_unref (self);
@ -1639,7 +1639,7 @@ gst_subtitle_overlay_video_sink_event (GstPad * pad, GstEvent * event)
self->fps_n = self->fps_d = 0;
}
ret = self->video_sink_event (pad, gst_event_ref (event));
ret = gst_proxy_pad_event_default (pad, gst_event_ref (event));
if (GST_EVENT_TYPE (event) == GST_EVENT_SEGMENT) {
@ -1664,7 +1664,7 @@ static GstFlowReturn
gst_subtitle_overlay_video_sink_chain (GstPad * pad, GstBuffer * buffer)
{
GstSubtitleOverlay *self = GST_SUBTITLE_OVERLAY (GST_PAD_PARENT (pad));
GstFlowReturn ret = self->video_sink_chain (pad, buffer);
GstFlowReturn ret = gst_proxy_pad_chain_default (pad, buffer);
if (G_UNLIKELY (self->downstream_chain_error) || self->passthrough_identity) {
return ret;
@ -1697,7 +1697,7 @@ gst_subtitle_overlay_subtitle_sink_chain (GstPad * pad, GstBuffer * buffer)
gst_buffer_unref (buffer);
return GST_FLOW_OK;
} else {
GstFlowReturn ret = self->subtitle_sink_chain (pad, buffer);
GstFlowReturn ret = gst_proxy_pad_chain_default (pad, buffer);
if (IS_SUBTITLE_CHAIN_IGNORE_ERROR (ret)) {
GST_DEBUG_OBJECT (self, "Subtitle chain error: %s",
@ -1772,7 +1772,7 @@ gst_subtitle_overlay_subtitle_sink_setcaps (GstPad * pad, GstCaps * caps)
if (target && gst_pad_accept_caps (target, caps)) {
GST_DEBUG_OBJECT (pad, "Target accepts caps");
ret = self->subtitle_sink_setcaps (pad, caps);
ret = gst_ghost_pad_setcaps_default (pad, caps);
GST_SUBTITLE_OVERLAY_UNLOCK (self);
goto out;
}
@ -1833,7 +1833,7 @@ gst_subtitle_overlay_subtitle_sink_link (GstPad * pad, GstPad * peer)
gst_caps_unref (caps);
}
ret = self->subtitle_sink_link (pad, peer);
ret = gst_ghost_pad_link_default (pad, peer);
gst_object_unref (self);
return ret;
@ -1852,7 +1852,7 @@ gst_subtitle_overlay_subtitle_sink_unlink (GstPad * pad)
GST_DEBUG_OBJECT (pad, "Pad unlinking");
gst_caps_replace (&self->subcaps, NULL);
self->subtitle_sink_unlink (pad);
gst_ghost_pad_unlink_default (pad);
GST_SUBTITLE_OVERLAY_LOCK (self);
self->subtitle_error = FALSE;
@ -1924,7 +1924,7 @@ gst_subtitle_overlay_subtitle_sink_event (GstPad * pad, GstEvent * event)
break;
}
ret = self->subtitle_sink_event (pad, gst_event_ref (event));
ret = gst_proxy_pad_event_default (pad, gst_event_ref (event));
if (GST_EVENT_TYPE (event) == GST_EVENT_SEGMENT) {
GST_DEBUG_OBJECT (pad, "segment event: %" GST_PTR_FORMAT, event);
@ -1943,8 +1943,6 @@ static void
gst_subtitle_overlay_init (GstSubtitleOverlay * self)
{
GstPadTemplate *templ;
GstIterator *it;
GValue item = { 0, };
GstPad *proxypad = NULL;
self->lock = g_mutex_new ();
@ -1952,68 +1950,45 @@ gst_subtitle_overlay_init (GstSubtitleOverlay * self)
templ = gst_static_pad_template_get (&srctemplate);
self->srcpad = gst_ghost_pad_new_no_target_from_template ("src", templ);
it = gst_pad_iterate_internal_links (self->srcpad);
if (G_UNLIKELY (!it
|| gst_iterator_next (it, &item) != GST_ITERATOR_OK
|| ((proxypad = g_value_get_object (&item)) == NULL))) {
GST_ERROR_OBJECT (self, "Failed to get proxypad of srcpad");
} else {
self->src_proxy_event = GST_PAD_EVENTFUNC (proxypad);
gst_pad_set_event_function (proxypad,
GST_DEBUG_FUNCPTR (gst_subtitle_overlay_src_proxy_event));
self->src_proxy_chain = GST_PAD_CHAINFUNC (proxypad);
gst_pad_set_chain_function (proxypad,
GST_DEBUG_FUNCPTR (gst_subtitle_overlay_src_proxy_chain));
g_value_unset (&item);
}
if (it)
gst_iterator_free (it);
proxypad =
GST_PAD_CAST (gst_proxy_pad_get_internal (GST_PROXY_PAD (self->srcpad)));
gst_pad_set_event_function (proxypad,
GST_DEBUG_FUNCPTR (gst_subtitle_overlay_src_proxy_event));
gst_pad_set_chain_function (proxypad,
GST_DEBUG_FUNCPTR (gst_subtitle_overlay_src_proxy_chain));
gst_object_unref (proxypad);
gst_element_add_pad (GST_ELEMENT_CAST (self), self->srcpad);
templ = gst_static_pad_template_get (&video_sinktemplate);
self->video_sinkpad =
gst_ghost_pad_new_no_target_from_template ("video_sink", templ);
self->video_sink_event = GST_PAD_EVENTFUNC (self->video_sinkpad);
gst_pad_set_event_function (self->video_sinkpad,
GST_DEBUG_FUNCPTR (gst_subtitle_overlay_video_sink_event));
self->video_sink_setcaps = GST_PAD_SETCAPSFUNC (self->video_sinkpad);
gst_pad_set_setcaps_function (self->video_sinkpad,
GST_DEBUG_FUNCPTR (gst_subtitle_overlay_video_sink_setcaps));
self->video_sink_chain = GST_PAD_CHAINFUNC (self->video_sinkpad);
gst_pad_set_chain_function (self->video_sinkpad,
GST_DEBUG_FUNCPTR (gst_subtitle_overlay_video_sink_chain));
proxypad = NULL;
it = gst_pad_iterate_internal_links (self->video_sinkpad);
if (G_UNLIKELY (!it
|| gst_iterator_next (it, &item) != GST_ITERATOR_OK
|| ((proxypad = g_value_dup_object (&item)) == NULL))) {
GST_ERROR_OBJECT (self,
"Failed to get internally linked pad from video sinkpad");
}
if (it)
gst_iterator_free (it);
proxypad =
GST_PAD_CAST (gst_proxy_pad_get_internal (GST_PROXY_PAD
(self->video_sinkpad)));
self->video_block_pad = proxypad;
g_value_unset (&item);
gst_element_add_pad (GST_ELEMENT_CAST (self), self->video_sinkpad);
templ = gst_static_pad_template_get (&subtitle_sinktemplate);
self->subtitle_sinkpad =
gst_ghost_pad_new_no_target_from_template ("subtitle_sink", templ);
self->subtitle_sink_link = GST_PAD_LINKFUNC (self->subtitle_sinkpad);
gst_pad_set_link_function (self->subtitle_sinkpad,
GST_DEBUG_FUNCPTR (gst_subtitle_overlay_subtitle_sink_link));
self->subtitle_sink_unlink = GST_PAD_UNLINKFUNC (self->subtitle_sinkpad);
gst_pad_set_unlink_function (self->subtitle_sinkpad,
GST_DEBUG_FUNCPTR (gst_subtitle_overlay_subtitle_sink_unlink));
self->subtitle_sink_event = GST_PAD_EVENTFUNC (self->subtitle_sinkpad);
gst_pad_set_event_function (self->subtitle_sinkpad,
GST_DEBUG_FUNCPTR (gst_subtitle_overlay_subtitle_sink_event));
self->subtitle_sink_setcaps = GST_PAD_SETCAPSFUNC (self->subtitle_sinkpad);
gst_pad_set_setcaps_function (self->subtitle_sinkpad,
GST_DEBUG_FUNCPTR (gst_subtitle_overlay_subtitle_sink_setcaps));
self->subtitle_sink_chain = GST_PAD_CHAINFUNC (self->subtitle_sinkpad);
gst_pad_set_chain_function (self->subtitle_sinkpad,
GST_DEBUG_FUNCPTR (gst_subtitle_overlay_subtitle_sink_chain));
gst_pad_set_getcaps_function (self->subtitle_sinkpad,
@ -2021,17 +1996,9 @@ gst_subtitle_overlay_init (GstSubtitleOverlay * self)
gst_pad_set_acceptcaps_function (self->subtitle_sinkpad,
GST_DEBUG_FUNCPTR (gst_subtitle_overlay_subtitle_sink_acceptcaps));
proxypad = NULL;
it = gst_pad_iterate_internal_links (self->subtitle_sinkpad);
if (G_UNLIKELY (!it
|| gst_iterator_next (it, &item) != GST_ITERATOR_OK
|| ((proxypad = g_value_dup_object (&item)) == NULL))) {
GST_ERROR_OBJECT (self,
"Failed to get internally linked pad from subtitle sinkpad");
}
if (it)
gst_iterator_free (it);
g_value_unset (&item);
proxypad =
GST_PAD_CAST (gst_proxy_pad_get_internal (GST_PROXY_PAD
(self->subtitle_sinkpad)));
self->subtitle_block_pad = proxypad;
gst_element_add_pad (GST_ELEMENT_CAST (self), self->subtitle_sinkpad);

View file

@ -68,26 +68,16 @@ struct _GstSubtitleOverlay
gboolean do_async;
GstPad *srcpad;
GstPadEventFunction src_proxy_event;
GstPadChainFunction src_proxy_chain;
gboolean downstream_chain_error;
GstPad *video_sinkpad;
GstPad *video_block_pad;
GstPadSetCapsFunction video_sink_setcaps;
GstPadEventFunction video_sink_event;
GstPadChainFunction video_sink_chain;
gboolean video_sink_blocked;
GstSegment video_segment;
gint fps_n, fps_d;
GstPad *subtitle_sinkpad;
GstPad *subtitle_block_pad;
GstPadLinkFunction subtitle_sink_link;
GstPadUnlinkFunction subtitle_sink_unlink;
GstPadEventFunction subtitle_sink_event;
GstPadChainFunction subtitle_sink_chain;
GstPadSetCapsFunction subtitle_sink_setcaps;
gboolean subtitle_sink_blocked;
GstSegment subtitle_segment;
gboolean subtitle_flush;

View file

@ -57,6 +57,12 @@ typedef struct _GstURIDecodeBinClass GstURIDecodeBinClass;
#define GST_URI_DECODE_BIN_LOCK(dec) (g_mutex_lock(GST_URI_DECODE_BIN_GET_LOCK(dec)))
#define GST_URI_DECODE_BIN_UNLOCK(dec) (g_mutex_unlock(GST_URI_DECODE_BIN_GET_LOCK(dec)))
typedef struct _GstURIDecodeBinStream
{
gulong probe_id;
guint bitrate;
} GstURIDecodeBinStream;
/**
* GstURIDecodeBin
*
@ -91,7 +97,7 @@ struct _GstURIDecodeBin
guint have_type_id; /* have-type signal id from typefind */
GSList *decodebins;
GSList *pending_decodebins;
GSList *srcpads;
GHashTable *streams;
gint numpads;
/* for dynamic sources */
@ -930,7 +936,99 @@ source_no_more_pads (GstElement * element, GstURIDecodeBin * bin)
no_more_pads_full (element, FALSE, bin);
}
/* Called by the signal handlers when a decodebin has
static void
configure_stream_buffering (GstURIDecodeBin * decoder)
{
GstElement *queue = NULL;
GHashTableIter iter;
gpointer key, value;
gint bitrate = 0;
/* automatic configuration enabled ? */
if (decoder->buffer_size != -1)
return;
GST_URI_DECODE_BIN_LOCK (decoder);
if (decoder->queue)
queue = gst_object_ref (decoder->queue);
g_hash_table_iter_init (&iter, decoder->streams);
while (g_hash_table_iter_next (&iter, &key, &value)) {
GstURIDecodeBinStream *stream = value;
if (stream->bitrate && bitrate >= 0)
bitrate += stream->bitrate;
else
bitrate = -1;
}
GST_URI_DECODE_BIN_UNLOCK (decoder);
GST_DEBUG_OBJECT (decoder, "overall bitrate %d", bitrate);
if (!queue)
return;
if (bitrate > 0) {
guint64 time;
guint bytes;
/* all streams have a bitrate;
* configure queue size based on queue duration using combined bitrate */
g_object_get (queue, "max-size-time", &time, NULL);
GST_DEBUG_OBJECT (decoder, "queue buffering time %" GST_TIME_FORMAT,
GST_TIME_ARGS (time));
if (time > 0) {
bytes = gst_util_uint64_scale (time, bitrate, 8 * GST_SECOND);
GST_DEBUG_OBJECT (decoder, "corresponds to buffer size %d", bytes);
g_object_set (queue, "max-size-bytes", bytes, NULL);
}
}
gst_object_unref (queue);
}
static gboolean
decoded_pad_event_probe (GstPad * pad, GstEvent * event,
GstURIDecodeBin * decoder)
{
GST_LOG_OBJECT (pad, "%s, decoder %p", GST_EVENT_TYPE_NAME (event), decoder);
/* look for a bitrate tag */
switch (GST_EVENT_TYPE (event)) {
case GST_EVENT_TAG:
{
GstTagList *list;
guint bitrate = 0;
GstURIDecodeBinStream *stream;
gst_event_parse_tag (event, &list);
if (!gst_tag_list_get_uint_index (list, GST_TAG_NOMINAL_BITRATE, 0,
&bitrate)) {
gst_tag_list_get_uint_index (list, GST_TAG_BITRATE, 0, &bitrate);
}
GST_DEBUG_OBJECT (pad, "found bitrate %u", bitrate);
if (bitrate) {
GST_URI_DECODE_BIN_LOCK (decoder);
stream = g_hash_table_lookup (decoder->streams, pad);
GST_URI_DECODE_BIN_UNLOCK (decoder);
if (stream) {
stream->bitrate = bitrate;
/* no longer need this probe now */
gst_pad_remove_event_probe (pad, stream->probe_id);
/* configure buffer if possible */
configure_stream_buffering (decoder);
}
}
break;
}
default:
break;
}
/* never drop */
return TRUE;
}
/* Called by the signal handlers when a decodebin has
* found a new raw pad.
*/
static void
@ -940,6 +1038,7 @@ new_decoded_pad_cb (GstElement * element, GstPad * pad, gboolean last,
GstPad *newpad;
GstPadTemplate *pad_tmpl;
gchar *padname;
GstURIDecodeBinStream *stream;
GST_DEBUG_OBJECT (element, "new decoded pad, name: <%s>. Last: %d",
GST_PAD_NAME (pad), last);
@ -957,11 +1056,19 @@ new_decoded_pad_cb (GstElement * element, GstPad * pad, gboolean last,
/* store ref to the ghostpad so we can remove it */
g_object_set_data (G_OBJECT (pad), "uridecodebin.ghostpad", newpad);
/* add event probe to monitor tags */
stream = g_slice_alloc0 (sizeof (GstURIDecodeBinStream));
stream->probe_id =
gst_pad_add_event_probe (pad, G_CALLBACK (decoded_pad_event_probe),
decoder);
GST_URI_DECODE_BIN_LOCK (decoder);
g_hash_table_insert (decoder->streams, pad, stream);
GST_URI_DECODE_BIN_UNLOCK (decoder);
gst_pad_set_active (newpad, TRUE);
gst_element_add_pad (GST_ELEMENT_CAST (decoder), newpad);
}
static gboolean
source_pad_event_probe (GstPad * pad, GstEvent * event,
GstURIDecodeBin * decoder)
@ -1422,22 +1529,6 @@ remove_decoders (GstURIDecodeBin * bin, gboolean force)
GST_OBJECT_FLAG_SET (bin, GST_ELEMENT_IS_SOURCE);
}
static void
remove_pads (GstURIDecodeBin * bin)
{
GSList *walk;
for (walk = bin->srcpads; walk; walk = g_slist_next (walk)) {
GstPad *pad = GST_PAD_CAST (walk->data);
GST_DEBUG_OBJECT (bin, "removing old pad");
gst_pad_set_active (pad, FALSE);
gst_element_remove_pad (GST_ELEMENT_CAST (bin), pad);
}
g_slist_free (bin->srcpads);
bin->srcpads = NULL;
}
static void
proxy_unknown_type_signal (GstElement * element, GstPad * pad, GstCaps * caps,
GstURIDecodeBin * dec)
@ -1789,6 +1880,12 @@ could_not_link:
}
}
static void
free_stream (gpointer value)
{
g_slice_free (GstURIDecodeBinStream, value);
}
/* remove source and all related elements */
static void
remove_source (GstURIDecodeBin * bin)
@ -1822,6 +1919,10 @@ remove_source (GstURIDecodeBin * bin)
gst_bin_remove (GST_BIN_CAST (bin), bin->typefind);
bin->typefind = NULL;
}
if (bin->streams) {
g_hash_table_destroy (bin->streams);
bin->streams = NULL;
}
/* Don't loose the SOURCE flag */
GST_OBJECT_FLAG_SET (bin, GST_ELEMENT_IS_SOURCE);
}
@ -1916,6 +2017,9 @@ setup_source (GstURIDecodeBin * decoder)
/* remove the old decoders now, if any */
remove_decoders (decoder, FALSE);
/* stream admin setup */
decoder->streams = g_hash_table_new_full (NULL, NULL, NULL, free_stream);
/* see if the source element emits raw audio/video all by itself,
* if so, we can create streams for the pads and be done with it.
* Also check that is has source pads, if not, we assume it will
@ -2408,14 +2512,12 @@ gst_uri_decode_bin_change_state (GstElement * element,
case GST_STATE_CHANGE_PAUSED_TO_READY:
GST_DEBUG ("paused to ready");
remove_decoders (decoder, FALSE);
remove_pads (decoder);
remove_source (decoder);
do_async_done (decoder);
break;
case GST_STATE_CHANGE_READY_TO_NULL:
GST_DEBUG ("ready to null");
remove_decoders (decoder, TRUE);
remove_pads (decoder);
remove_source (decoder);
break;
default:

View file

@ -86,6 +86,8 @@ enum
#define DEFAULT_SILENT TRUE
#define DEFAULT_NEW_PREF 1.0
#define DEFAULT_SKIP_TO_FIRST FALSE
#define DEFAULT_DROP_ONLY FALSE
#define DEFAULT_AVERAGE_PERIOD 0
enum
{
@ -96,7 +98,9 @@ enum
ARG_DROP,
ARG_SILENT,
ARG_NEW_PREF,
ARG_SKIP_TO_FIRST
ARG_SKIP_TO_FIRST,
ARG_DROP_ONLY,
ARG_AVERAGE_PERIOD
/* FILL ME */
};
@ -194,6 +198,33 @@ gst_video_rate_class_init (GstVideoRateClass * klass)
gst_element_class_add_pad_template (element_class,
gst_static_pad_template_get (&gst_video_rate_src_template));
/**
* GstVideoRate:drop-only:
*
* Only drop frames, no duplicates are produced.
*
* Since: 0.10.34
*/
g_object_class_install_property (object_class, ARG_DROP_ONLY,
g_param_spec_boolean ("drop-only", "Only Drop",
"Only drop frames, no duplicates are produced",
DEFAULT_DROP_ONLY, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
/**
* GstVideoRate:average-period:
*
* Arrange for maximum framerate by dropping frames beyond a certain framerate,
* where the framerate is calculated using a moving average over the
* configured.
*
* Since: 0.10.34
*/
g_object_class_install_property (object_class, ARG_AVERAGE_PERIOD,
g_param_spec_uint64 ("average-period", "Period over which to average",
"Period over which to average the framerate (in ns) (0 = disabled)",
0, G_MAXINT64, DEFAULT_AVERAGE_PERIOD,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
element_class->change_state = GST_DEBUG_FUNCPTR (gst_video_rate_change_state);
}
@ -321,6 +352,8 @@ gst_video_rate_setcaps (GstPad * pad, GstCaps * caps)
videorate->out_frame_count = 0;
videorate->to_rate_numerator = rate_numerator;
videorate->to_rate_denominator = rate_denominator;
videorate->wanted_diff = gst_util_uint64_scale_int (GST_SECOND,
rate_denominator, rate_numerator);
otherpad = videorate->sinkpad;
} else {
videorate->from_rate_numerator = rate_numerator;
@ -430,6 +463,7 @@ gst_video_rate_reset (GstVideoRate * videorate)
videorate->next_ts = GST_CLOCK_TIME_NONE;
videorate->last_ts = GST_CLOCK_TIME_NONE;
videorate->discont = TRUE;
videorate->average = 0;
gst_video_rate_swap_prev (videorate, NULL, 0);
gst_segment_init (&videorate->segment, GST_FORMAT_TIME);
@ -463,6 +497,8 @@ gst_video_rate_init (GstVideoRate * videorate)
gst_video_rate_reset (videorate);
videorate->silent = DEFAULT_SILENT;
videorate->new_pref = DEFAULT_NEW_PREF;
videorate->drop_only = DEFAULT_DROP_ONLY;
videorate->average_period = DEFAULT_AVERAGE_PERIOD;
videorate->from_rate_numerator = 0;
videorate->from_rate_denominator = 0;
@ -513,8 +549,11 @@ gst_video_rate_flush_prev (GstVideoRate * videorate, gboolean duplicate)
GST_BUFFER_DURATION (outbuf) = videorate->next_ts - push_ts;
}
/* adapt for looping, bring back to time in current segment. */
GST_BUFFER_TIMESTAMP (outbuf) = push_ts - videorate->segment.base;
/* We do not need to update time in VFR (variable frame rate) mode */
if (!videorate->drop_only) {
/* adapt for looping, bring back to time in current segment. */
GST_BUFFER_TIMESTAMP (outbuf) = push_ts - videorate->segment.accum;
}
GST_LOG_OBJECT (videorate,
"old is best, dup, pushing buffer outgoing ts %" GST_TIME_FORMAT,
@ -762,12 +801,69 @@ gst_video_rate_query (GstPad * pad, GstQuery ** query)
return res;
}
static GstFlowReturn
gst_video_rate_chain_max_avg (GstVideoRate * videorate, GstBuffer * buf)
{
GstClockTime ts = GST_BUFFER_TIMESTAMP (buf);
videorate->in++;
if (!GST_CLOCK_TIME_IS_VALID (ts) || videorate->wanted_diff == 0)
goto push;
/* drop frames if they exceed our output rate */
if (GST_CLOCK_TIME_IS_VALID (videorate->last_ts)) {
GstClockTimeDiff diff = ts - videorate->last_ts;
/* Drop buffer if its early compared to the desired frame rate and
* the current average is higher than the desired average
*/
if (diff < videorate->wanted_diff &&
videorate->average < videorate->wanted_diff)
goto drop;
/* Update average */
if (videorate->average) {
GstClockTimeDiff wanted_diff;
if (G_LIKELY (videorate->average_period > videorate->wanted_diff))
wanted_diff = videorate->wanted_diff;
else
wanted_diff = videorate->average_period * 10;
videorate->average =
gst_util_uint64_scale_round (videorate->average,
videorate->average_period - wanted_diff,
videorate->average_period) +
gst_util_uint64_scale_round (diff, wanted_diff,
videorate->average_period);
} else {
videorate->average = diff;
}
}
videorate->last_ts = ts;
push:
videorate->out++;
return gst_pad_push (videorate->srcpad, buf);
drop:
gst_buffer_unref (buf);
if (!videorate->silent)
gst_video_rate_notify_drop (videorate);
return GST_FLOW_OK;
}
static GstFlowReturn
gst_video_rate_chain (GstPad * pad, GstBuffer * buffer)
{
GstVideoRate *videorate;
GstFlowReturn res = GST_FLOW_OK;
GstClockTime intime, in_ts, in_dur;
GstClockTime avg_period;
gboolean skip = FALSE;
videorate = GST_VIDEO_RATE (GST_PAD_PARENT (pad));
@ -776,6 +872,29 @@ gst_video_rate_chain (GstPad * pad, GstBuffer * buffer)
videorate->to_rate_denominator == 0)
goto not_negotiated;
GST_OBJECT_LOCK (videorate);
avg_period = videorate->average_period_set;
GST_OBJECT_UNLOCK (videorate);
/* MT-safe switching between modes */
if (G_UNLIKELY (avg_period != videorate->average_period)) {
videorate->average_period = avg_period;
videorate->last_ts = GST_CLOCK_TIME_NONE;
if (avg_period && !videorate->average) {
/* enabling average mode */
videorate->average = 0;
} else {
/* enable regular mode */
gst_video_rate_swap_prev (videorate, NULL, 0);
/* arrange for skip-to-first behaviour */
videorate->next_ts = GST_CLOCK_TIME_NONE;
skip = TRUE;
}
}
if (videorate->average_period > 0)
return gst_video_rate_chain_max_avg (videorate, buffer);
in_ts = GST_BUFFER_TIMESTAMP (buffer);
in_dur = GST_BUFFER_DURATION (buffer);
@ -805,7 +924,7 @@ gst_video_rate_chain (GstPad * pad, GstBuffer * buffer)
if (!GST_CLOCK_TIME_IS_VALID (videorate->next_ts)) {
/* new buffer, we expect to output a buffer that matches the first
* timestamp in the segment */
if (videorate->skip_to_first) {
if (videorate->skip_to_first || skip) {
videorate->next_ts = intime;
videorate->base_ts = in_ts - videorate->segment.start;
videorate->out_frame_count = 0;
@ -871,6 +990,10 @@ gst_video_rate_chain (GstPad * pad, GstBuffer * buffer)
goto done;
}
}
/* Do not produce any dups. We can exit loop now */
if (videorate->drop_only)
break;
/* continue while the first one was the best, if they were equal avoid
* going into an infinite loop */
}
@ -931,6 +1054,7 @@ gst_video_rate_set_property (GObject * object,
{
GstVideoRate *videorate = GST_VIDEO_RATE (object);
GST_OBJECT_LOCK (videorate);
switch (prop_id) {
case ARG_SILENT:
videorate->silent = g_value_get_boolean (value);
@ -941,10 +1065,17 @@ gst_video_rate_set_property (GObject * object,
case ARG_SKIP_TO_FIRST:
videorate->skip_to_first = g_value_get_boolean (value);
break;
case ARG_DROP_ONLY:
videorate->drop_only = g_value_get_boolean (value);
break;
case ARG_AVERAGE_PERIOD:
videorate->average_period = g_value_get_uint64 (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
GST_OBJECT_UNLOCK (videorate);
}
static void
@ -953,6 +1084,7 @@ gst_video_rate_get_property (GObject * object,
{
GstVideoRate *videorate = GST_VIDEO_RATE (object);
GST_OBJECT_LOCK (videorate);
switch (prop_id) {
case ARG_IN:
g_value_set_uint64 (value, videorate->in);
@ -975,10 +1107,17 @@ gst_video_rate_get_property (GObject * object,
case ARG_SKIP_TO_FIRST:
g_value_set_boolean (value, videorate->skip_to_first);
break;
case ARG_DROP_ONLY:
g_value_set_boolean (value, videorate->drop_only);
break;
case ARG_AVERAGE_PERIOD:
g_value_set_uint64 (value, videorate->average_period);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
GST_OBJECT_UNLOCK (videorate);
}
static GstStateChangeReturn

View file

@ -63,6 +63,10 @@ struct _GstVideoRate
gboolean discont;
guint64 last_ts; /* Timestamp of last input buffer */
guint64 average_period;
GstClockTimeDiff wanted_diff; /* target average diff */
GstClockTimeDiff average; /* moving average period */
/* segment handling */
GstSegment segment;
@ -71,6 +75,8 @@ struct _GstVideoRate
gboolean silent;
gdouble new_pref;
gboolean skip_to_first;
gboolean drop_only;
guint64 average_period_set;
};
struct _GstVideoRateClass

View file

@ -129,6 +129,7 @@ check_PROGRAMS = \
elements/multifdsink \
elements/playbin \
elements/playbin2 \
elements/playbin2-compressed \
$(check_subparse) \
elements/videorate \
elements/videoscale \
@ -376,6 +377,9 @@ elements_playbin_CFLAGS = $(GST_BASE_CFLAGS) $(AM_CFLAGS)
elements_playbin2_LDADD = $(GST_BASE_LIBS) $(LDADD)
elements_playbin2_CFLAGS = $(GST_BASE_CFLAGS) $(AM_CFLAGS)
elements_playbin2_compressed_LDADD = $(top_builddir)/gst-libs/gst/interfaces/libgstinterfaces-@GST_MAJORMINOR@.la $(GST_BASE_LIBS) $(LDADD)
elements_playbin2_compressed_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(GST_BASE_CFLAGS) $(AM_CFLAGS)
elements_decodebin_LDADD = $(GST_BASE_LIBS) $(LDADD)
elements_decodebin_CFLAGS = $(GST_BASE_CFLAGS) $(AM_CFLAGS)

File diff suppressed because it is too large Load diff

View file

@ -925,12 +925,13 @@ tag_list_equals (GstTagList * taglist, GstTagList * taglist2)
}
static void
do_xmp_tag_serialization_deserialization (GstTagList * taglist)
do_xmp_tag_serialization_deserialization (GstTagList * taglist,
const gchar ** schemas)
{
GstTagList *taglist2;
GstBuffer *buf;
buf = gst_tag_list_to_xmp_buffer (taglist, TRUE);
buf = gst_tag_list_to_xmp_buffer_full (taglist, TRUE, schemas);
taglist2 = gst_tag_list_from_xmp_buffer (buf);
tag_list_equals (taglist, taglist2);
@ -947,7 +948,7 @@ do_simple_xmp_tag_serialization_deserialization (const gchar * gsttag,
gst_tag_list_add_value (taglist, GST_TAG_MERGE_REPLACE, gsttag, value);
do_xmp_tag_serialization_deserialization (taglist);
do_xmp_tag_serialization_deserialization (taglist, NULL);
gst_tag_list_free (taglist);
}
@ -1134,13 +1135,19 @@ GST_END_TEST;
GST_START_TEST (test_xmp_compound_tags)
{
const gchar *schemas[] = { "Iptc4xmpExt", NULL };
GstTagList *taglist = gst_tag_list_new ();
gst_tag_list_add (taglist, GST_TAG_MERGE_APPEND, GST_TAG_KEYWORDS, "k1",
GST_TAG_KEYWORDS, "k2", GST_TAG_TITLE, "title", GST_TAG_KEYWORDS, "k3",
NULL);
do_xmp_tag_serialization_deserialization (taglist, NULL);
gst_tag_list_free (taglist);
do_xmp_tag_serialization_deserialization (taglist);
taglist = gst_tag_list_new ();
gst_tag_list_add (taglist, GST_TAG_MERGE_APPEND, GST_TAG_GEO_LOCATION_COUNTRY,
"Brazil", GST_TAG_GEO_LOCATION_CITY, "Campina Grande", NULL);
do_xmp_tag_serialization_deserialization (taglist, schemas);
gst_tag_list_free (taglist);
}

View file

@ -6,7 +6,9 @@ EXTRA_DIST = gstcapslist.h
noinst_PROGRAMS = $(examples)
LDADD = $(top_builddir)/gst-libs/gst/pbutils/libgstpbutils-@GST_MAJORMINOR@.la \
$(GST_BASE_LIBS) \
$(GST_LIBS)
AM_CFLAGS = -I$(top_builddir)/gst-libs \
$(GST_PLUGINS_BASE_CFLAGS) \
$(GST_BASE_CFLAGS) \
$(GST_CFLAGS)

View file

@ -1,7 +1,7 @@
#ifndef _GST_PLUGINS_BASE__STDINT_H
#define _GST_PLUGINS_BASE__STDINT_H 1
#ifndef _GENERATED_STDINT_H
#define _GENERATED_STDINT_H "gst-plugins-base 0.10.32.4"
#define _GENERATED_STDINT_H "gst-plugins-base 0.10.34.1"
/* generated using gnu compiler gcc (Debian 4.5.2-8) 4.5.2 */
#define _STDINT_HAVE_STDINT_H 1
#include <stdint.h>

View file

@ -75,13 +75,13 @@
#define GST_MAJORMINOR "0.10"
/* package name in plugins */
#define GST_PACKAGE_NAME "GStreamer Base Plug-ins prerelease"
#define GST_PACKAGE_NAME "GStreamer Base Plug-ins git"
/* package origin */
#define GST_PACKAGE_ORIGIN "Unknown package origin"
/* GStreamer package release date/time for plugins as YYYY-MM-DD */
#define GST_PACKAGE_RELEASE_DATETIME "2011-04-30T15:57Z"
#define GST_PACKAGE_RELEASE_DATETIME "2011-05-14T08:32Z"
/* I know the API is subject to change. */
#undef G_UDEV_API_IS_SUBJECT_TO_CHANGE
@ -337,7 +337,7 @@
#define PACKAGE_NAME "GStreamer Base Plug-ins"
/* Define to the full name and version of this package. */
#define PACKAGE_STRING "GStreamer Base Plug-ins 0.10.32.4"
#define PACKAGE_STRING "GStreamer Base Plug-ins 0.10.34.1"
/* Define to the one symbol short name of this package. */
#define PACKAGE_TARNAME "gst-plugins-base"
@ -346,7 +346,7 @@
#undef PACKAGE_URL
/* Define to the version of this package. */
#define PACKAGE_VERSION "0.10.32.4"
#define PACKAGE_VERSION "0.10.34.1"
/* directory where plugins are located */
#ifdef _DEBUG
@ -377,7 +377,7 @@
#undef USE_TREMOLO
/* Version number of package */
#define VERSION "0.10.32.4"
#define VERSION "0.10.34.1"
/* Define WORDS_BIGENDIAN to 1 if your processor stores words with the most
significant byte first (like Motorola and SPARC, unlike Intel). */

View file

@ -17,6 +17,8 @@ EXPORTS
gst_audio_frame_byte_size
gst_audio_frame_length
gst_audio_get_channel_positions
gst_audio_iec61937_frame_size
gst_audio_iec61937_payload
gst_audio_is_buffer_framed
gst_audio_set_caps_channel_positions_list
gst_audio_set_channel_positions