28
28
#include < boost/make_unique.hpp>
29
29
30
30
#include < algorithm>
31
- #include < gst/app/gstappsink.h>
32
31
33
32
namespace detail
34
33
{
@@ -37,9 +36,9 @@ struct RingBuffer
37
36
{
38
37
static constexpr size_t size = s;
39
38
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 ;
43
42
44
43
void push ( const T* data, size_t count )
45
44
{
@@ -86,6 +85,7 @@ gstreamer_file_source::gstreamer_file_source( const std::string&
86
85
audio::ifstream_info::container_type container,
87
86
size_t stream )
88
87
: m_pipeline( nullptr , gst_object_unref )
88
+ , m_sink( nullptr , gst_object_unref )
89
89
, m_ring_buffer( new RingBuffer() )
90
90
{
91
91
init_gstreamer ();
@@ -133,10 +133,10 @@ void gstreamer_file_source::init_gstreamer()
133
133
134
134
void gstreamer_file_source::setup_source ( const std::string& path, audio::ifstream_info::container_type container )
135
135
{
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 );
140
140
fill_format_info ( caps_struct, container );
141
141
}
142
142
@@ -151,11 +151,12 @@ GstElement* gstreamer_file_source::prepare_pipeline( const std::string& path )
151
151
GstElement* queue = gst_element_factory_make ( " queue" , " queue" );
152
152
GstElement* sink = gst_element_factory_make ( " appsink" , " sink" );
153
153
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 );
155
155
gst_element_link_many ( source, decodebin, NULL );
156
156
gst_element_link_many ( queue, sink, NULL );
157
157
158
158
g_object_set ( source, " location" , path.c_str (), NULL );
159
+ g_object_set ( sink, " sync" , FALSE , NULL );
159
160
160
161
g_signal_connect ( decodebin, " pad-added" , G_CALLBACK ( &onPadAdded ), queue );
161
162
@@ -187,18 +188,19 @@ void gstreamer_file_source::fill_format_info( GstStructure*
187
188
m_info.codec ( audio::ifstream_info::codec_type::mp3 );
188
189
m_info.lossless ( false );
189
190
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
-
196
191
int sample_rate = 0 ;
197
192
if ( !gst_structure_get_int ( caps_struct, " rate" , &sample_rate ) )
198
193
throw std::runtime_error ( " gstreamer_file_source: could not query sample rate from gstreamer" );
199
194
200
195
m_info.sample_rate ( sample_rate );
201
196
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
+
202
204
int num_channels = 0 ;
203
205
if ( !gst_structure_get_int ( caps_struct, " channels" , &num_channels ) )
204
206
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
239
241
void gstreamer_file_source::onPadAdded ( GstElement* element, GstPad* pad, GstElement* sink )
240
242
{
241
243
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" );
243
259
}
244
260
245
261
// ----------------------------------------------------------------------------------------------------------------------
@@ -305,14 +321,13 @@ std::streamsize gstreamer_file_source::recursive_read( char* dst, std::streamsiz
305
321
306
322
if ( numBytesRequested )
307
323
{
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 );
312
326
313
- if ( sample )
327
+ if ( samplePtr )
314
328
{
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 () );
316
331
317
332
GstMapInfo mapped;
318
333
0 commit comments