前面俩篇文章中,记录了使用AppSrc的情况下,如何注入数据与自动探测数据类型及解码,但Sink部分只强制指定了使用alsasink来输出声音。对于同时输出声音与图像的场景,GStreamer提供了playsink组件,用于自动选择合适的video与audio sink。
playsink同样也是playbin的后端组件,如下的代码实现了playsink的配置:
#include <stdio.h>
#include <stdlib.h>
#include <gst/gst.h>
#include <gst/app/gstappsrc.h>
static FILE * fp;
static GstPad * audioPad;
void _needData( GstAppSrc * src, guint arg1, gpointer user_data )
{
GstBuffer * _buf;
GstFlowReturn _ret;
int _size;
arg1 *= 4;
_buf = gst_buffer_new_and_alloc( arg1 );
GST_BUFFER_OFFSET( _buf ) = ftell( fp );
_size = fread( GST_BUFFER_DATA( _buf ), 1, arg1, fp );
GST_BUFFER_SIZE( _buf ) = _size;
GST_BUFFER_OFFSET_END( _buf ) = GST_BUFFER_OFFSET( _buf ) + _size;
if( feof( fp ))
{
g_message( "rewind to head" );
fseek( fp, 0, SEEK_SET );
}
g_signal_emit_by_name( src, "push-buffer", _buf, &_ret );
gst_buffer_unref( _buf );
}
void _enoughData( GstElement * src, gpointer user_data )
{
g_message( "%s", __func__ );
}
GstElement * _pipeline, * _src, * _codec, * _sink;
/*
* === FUNCTION ======================================================================
* Name: _decNewPad
* Description:
* =====================================================================================
*/
static void _decNewPad( GstElement * decodebin, GstPad * pad, gpointer user_data )
{
GstCaps * _caps;
GstStructure * _str;
const gchar * _name;
GstPadTemplate * _tpl = NULL;
GstElementClass * _klass;
gboolean _ret;
_caps = gst_pad_get_caps_reffed( pad );
_str = gst_caps_get_structure( _caps, 0 );
_name = gst_structure_get_name( _str );
_klass = GST_ELEMENT_GET_CLASS( _sink );
if( g_str_has_prefix( _name, "audio" ))
{
_tpl = gst_element_class_get_pad_template( _klass, "audio_sink" );
}
if( _tpl != NULL )
{
GstPad * _sinkPad;
_sinkPad = gst_element_request_pad( _sink, _tpl, NULL, NULL );
if( !gst_pad_is_linked( _sinkPad ))
{
gst_pad_link( pad, _sinkPad );
}
g_object_unref( _sinkPad );
}
g_signal_emit_by_name( _sink, "reconfigure", &_ret );
//gst_pad_link( pad, audioPad );
} /* ----- end of static function _decNewPad ----- */
/*
* === FUNCTION ======================================================================
* Name: main
* Description:
* =====================================================================================
*/
int main ( int argc, char *argv[] )
{
fp = fopen( argv[1], "r" );
g_assert( fp != NULL );
gst_init( &argc, &argv );
g_assert( _src = gst_element_factory_make( "appsrc", "source" ));
g_assert( _codec = gst_element_factory_make( "decodebin", "codec" ));
g_signal_connect( _codec, "pad-added", G_CALLBACK( _decNewPad ), NULL );
g_assert( _sink = gst_element_factory_make( "playsink", "sink" ));
gst_util_set_object_arg (G_OBJECT (_sink), "flags",
"audio+video");
// g_assert( _sink = gst_element_factory_make( "pulsesink", "sink" ));
// g_assert( audioPad = gst_element_get_static_pad( _sink, "sink" ));
_pipeline = gst_pipeline_new( "pipeline" );
gst_bin_add_many( GST_BIN( _pipeline ), _src, _codec, _sink, NULL );
gst_element_link_many( _src, _codec, NULL );
g_signal_connect ( _src, "need-data", G_CALLBACK( _needData ), NULL );
g_signal_connect ( _src, "enough-data", G_CALLBACK( _enoughData ), NULL );
gst_element_set_state( _pipeline, GST_STATE_PLAYING );
sleep(1);
GST_DEBUG_BIN_TO_DOT_FILE( _pipeline, GST_DEBUG_GRAPH_SHOW_ALL, "pipeline" );
pause();
return 0;
} /* ---------- end of function main ---------- */