2828#include < boost/make_unique.hpp>
2929
3030#include < algorithm>
31- #include < gst/app/gstappsink.h>
3231
3332namespace detail
3433{
@@ -37,9 +36,9 @@ struct RingBuffer
3736{
3837 static constexpr size_t size = s;
3938 static constexpr size_t mask = ( s - 1 );
40- std::array<T, s> m_buffer;
41- uint64_t m_write_head = 0 ;
42- uint64_t m_read_head = 0 ;
39+ std::array<T, s> m_buffer;
40+ uint64_t m_write_head = 0 ;
41+ uint64_t m_read_head = 0 ;
4342
4443 void push ( const T* data, size_t count )
4544 {
@@ -86,6 +85,7 @@ gstreamer_file_source::gstreamer_file_source( const std::string&
8685 audio::ifstream_info::container_type container,
8786 size_t stream )
8887: m_pipeline( nullptr , gst_object_unref )
88+ , m_sink( nullptr , gst_object_unref )
8989, m_ring_buffer( new RingBuffer() )
9090{
9191 init_gstreamer ();
@@ -133,10 +133,10 @@ void gstreamer_file_source::init_gstreamer()
133133
134134void gstreamer_file_source::setup_source ( const std::string& path, audio::ifstream_info::container_type container )
135135{
136- GstElement* sink = prepare_pipeline ( path );
137- auto sinkpad = gst_element_get_static_pad ( sink , " sink" );
138- auto caps = gst_pad_get_current_caps ( sinkpad );
139- auto caps_struct = gst_caps_get_structure ( caps, 0 );
136+ m_sink. reset ( prepare_pipeline ( path ) );
137+ auto sinkpad = gst_element_get_static_pad ( m_sink. get () , " sink" );
138+ auto caps = gst_pad_get_current_caps ( sinkpad );
139+ auto caps_struct = gst_caps_get_structure ( caps, 0 );
140140 fill_format_info ( caps_struct, container );
141141}
142142
@@ -151,11 +151,12 @@ GstElement* gstreamer_file_source::prepare_pipeline( const std::string& path )
151151 GstElement* queue = gst_element_factory_make ( " queue" , " queue" );
152152 GstElement* sink = gst_element_factory_make ( " appsink" , " sink" );
153153
154- gst_bin_add_many ( GST_BIN ( m_pipeline.get () ), source, decodebin, queue, sink, nullptr );
154+ gst_bin_add_many ( GST_BIN ( m_pipeline.get () ), source, decodebin, queue, gst_object_ref ( sink ) , nullptr );
155155 gst_element_link_many ( source, decodebin, NULL );
156156 gst_element_link_many ( queue, sink, NULL );
157157
158158 g_object_set ( source, " location" , path.c_str (), NULL );
159+ g_object_set ( sink, " sync" , FALSE , NULL );
159160
160161 g_signal_connect ( decodebin, " pad-added" , G_CALLBACK ( &onPadAdded ), queue );
161162
@@ -187,18 +188,19 @@ void gstreamer_file_source::fill_format_info( GstStructure*
187188 m_info.codec ( audio::ifstream_info::codec_type::mp3 );
188189 m_info.lossless ( false );
189190
190- gint64 num_frames = 0 ;
191- if ( !gst_element_query_duration ( m_pipeline.get (), GST_FORMAT_DEFAULT, &num_frames ) )
192- throw std::runtime_error ( " gstreamer_file_source: could not query duration from gstreamer" );
193-
194- m_info.num_frames ( num_frames );
195-
196191 int sample_rate = 0 ;
197192 if ( !gst_structure_get_int ( caps_struct, " rate" , &sample_rate ) )
198193 throw std::runtime_error ( " gstreamer_file_source: could not query sample rate from gstreamer" );
199194
200195 m_info.sample_rate ( sample_rate );
201196
197+ gint64 num_ns = 0 ;
198+ if ( !gst_element_query_duration ( m_pipeline.get (), GST_FORMAT_TIME, &num_ns ) )
199+ throw std::runtime_error ( " gstreamer_file_source: could not query duration from gstreamer" );
200+
201+ gint64 num_frames = sample_rate * num_ns / GST_SECOND;
202+ m_info.num_frames ( num_frames );
203+
202204 int num_channels = 0 ;
203205 if ( !gst_structure_get_int ( caps_struct, " channels" , &num_channels ) )
204206 throw std::runtime_error ( " gstreamer_file_source: could not query number of channels from gstreamer" );
@@ -239,7 +241,21 @@ pcm::number_type gstreamer_file_source::gst_format_char_to_number_type( const gc
239241void gstreamer_file_source::onPadAdded ( GstElement* element, GstPad* pad, GstElement* sink )
240242{
241243 tGstPtr<GstPad> sinkpad ( gst_element_get_static_pad ( sink, " sink" ), gst_object_unref );
242- gst_pad_link ( pad, sinkpad.get () );
244+
245+ if ( gst_pad_is_linked ( sinkpad.get () ) )
246+ return ; // already linked
247+
248+ tGstPtr<GstCaps> caps ( gst_pad_get_current_caps ( pad ), gst_object_unref );
249+ auto s = gst_caps_get_structure ( caps.get (), 0 );
250+ auto name = gst_structure_get_name ( s );
251+
252+ if ( !g_str_has_prefix ( name, " audio/" ) )
253+ return ; // not the kind of pad we are looking for, maybe video?
254+
255+ auto result = gst_pad_link ( pad, sinkpad.get () );
256+
257+ if ( result != GST_PAD_LINK_OK )
258+ throw std::runtime_error ( " gstreamer_file_source: could not link pad" );
243259}
244260
245261// ----------------------------------------------------------------------------------------------------------------------
@@ -305,14 +321,13 @@ std::streamsize gstreamer_file_source::recursive_read( char* dst, std::streamsiz
305321
306322 if ( numBytesRequested )
307323 {
308- tGstPtr<GstElement> sink ( gst_bin_get_by_name ( GST_BIN ( m_pipeline.get () ), " sink" ), gst_object_unref );
309- GstAppSink* app_sink = reinterpret_cast <GstAppSink*>( sink.get () );
310-
311- tGstPtr<GstSample> sample ( gst_app_sink_pull_sample ( app_sink ), (GUnref) gst_sample_unref );
324+ GstSample* samplePtr = nullptr ;
325+ g_signal_emit_by_name ( m_sink.get (), " try-pull-sample" , &samplePtr, nullptr );
312326
313- if ( sample )
327+ if ( samplePtr )
314328 {
315- auto buffer = gst_sample_get_buffer ( sample.get () );
329+ tGstPtr<GstSample> sample ( samplePtr, (GUnref) gst_sample_unref );
330+ auto buffer = gst_sample_get_buffer ( sample.get () );
316331
317332 GstMapInfo mapped;
318333
0 commit comments