gstreamer use appsrc with playbin2

转自:http://docs.gstreamer.com/display/GstSDK/Playback+tutorial+3%3A+Short-cutting+the+pipeline

Goal

Basic tutorial 8: Short-cutting the pipeline showed how an application can manually extract or inject data into a pipeline by using two special elements called appsrc and appsink. playbin2 allows using these elements too, but the method to connect them is different. To connect an appsink to playbin2 see Playback tutorial 7: Custom playbin2 sinks. This tutorial shows:

A playbin2 waveform generator

Copy this code into a text file named playback-tutorial-3.c.

This tutorial is included in the SDK since release 2012.7. If you cannot find it in the downloaded code, please install the latest release of the GStreamer SDK.        

playback-tutorial-3.c
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
#include <gst/gst.h>
#include <string.h>
   
#define CHUNK_SIZE 1024   /* Amount of bytes we are sending in each buffer */
#define SAMPLE_RATE 44100 /* Samples per second we are sending */
#define AUDIO_CAPS "audio/x-raw-int,channels=1,rate=%d,signed=(boolean)true,width=16,depth=16,endianness=BYTE_ORDER"
   
/* Structure to contain all our information, so we can pass it to callbacks */
typedef struct _CustomData {
   GstElement *pipeline;
   GstElement *app_source;
   
   guint64 num_samples;   /* Number of samples generated so far (for timestamp generation) */
   gfloat a, b, c, d;     /* For waveform generation */
   
   guint sourceid;        /* To control the GSource */
   
   GMainLoop *main_loop;  /* GLib's Main Loop */
} CustomData;
   
/* This method is called by the idle GSource in the mainloop, to feed CHUNK_SIZE bytes into appsrc.
  * The ide handler is added to the mainloop when appsrc requests us to start sending data (need-data signal)
  * and is removed when appsrc has enough data (enough-data signal).
  */
static gboolean push_data (CustomData *data) {
   GstBuffer *buffer;
   GstFlowReturn ret;
   int i;
   gint16 *raw;
   gint num_samples = CHUNK_SIZE / 2; /* Because each sample is 16 bits */
   gfloat freq;
   
   /* Create a new empty buffer */
   buffer = gst_buffer_new_and_alloc (CHUNK_SIZE);
   
   /* Set its timestamp and duration */
   GST_BUFFER_TIMESTAMP (buffer) = gst_util_uint64_scale (data->num_samples, GST_SECOND, SAMPLE_RATE);
   GST_BUFFER_DURATION (buffer) = gst_util_uint64_scale (CHUNK_SIZE, GST_SECOND, SAMPLE_RATE);
   
   /* Generate some psychodelic waveforms */
   raw = (gint16 *)GST_BUFFER_DATA (buffer);
   data->c += data->d;
   data->d -= data->c / 1000;
   freq = 1100 + 1000 * data->d;
   for (i = 0; i < num_samples; i++) {
     data->a += data->b;
     data->b -= data->a / freq;
     raw[i] = (gint16)(500 * data->a);
   }
   data->num_samples += num_samples;
   
   /* Push the buffer into the appsrc */
   g_signal_emit_by_name (data->app_source, "push-buffer" , buffer, &ret);
   
   /* Free the buffer now that we are done with it */
   gst_buffer_unref (buffer);
   
   if (ret != GST_FLOW_OK) {
     /* We got some error, stop sending data */
     return FALSE;
   }
   
   return TRUE;
}
   
/* This signal callback triggers when appsrc needs data. Here, we add an idle handler
  * to the mainloop to start pushing data into the appsrc */
static void start_feed (GstElement *source, guint size, CustomData *data) {
   if (data->sourceid == 0) {
     g_print ( "Start feeding\n" );
     data->sourceid = g_idle_add ((GSourceFunc) push_data, data);
   }
}
   
/* This callback triggers when appsrc has enough data and we can stop sending.
  * We remove the idle handler from the mainloop */
static void stop_feed (GstElement *source, CustomData *data) {
   if (data->sourceid != 0) {
     g_print ( "Stop feeding\n" );
     g_source_remove (data->sourceid);
     data->sourceid = 0;
   }
}
   
/* This function is called when an error message is posted on the bus */
static void error_cb (GstBus *bus, GstMessage *msg, CustomData *data) {
   GError *err;
   gchar *debug_info;
   
   /* Print error details on the screen */
   gst_message_parse_error (msg, &err, &debug_info);
   g_printerr ( "Error received from element %s: %s\n" , GST_OBJECT_NAME (msg->src), err->message);
   g_printerr ( "Debugging information: %s\n" , debug_info ? debug_info : "none" );
   g_clear_error (&err);
   g_free (debug_info);
   
   g_main_loop_quit (data->main_loop);
}
   
/* This function is called when playbin2 has created the appsrc element, so we have
  * a chance to configure it. */
static void source_setup (GstElement *pipeline, GstElement *source, CustomData *data) {
   gchar *audio_caps_text;
   GstCaps *audio_caps;
   
   g_print ( "Source has been created. Configuring.\n" );
   data->app_source = source;
   
   /* Configure appsrc */
   audio_caps_text = g_strdup_printf (AUDIO_CAPS, SAMPLE_RATE);
   audio_caps = gst_caps_from_string (audio_caps_text);
   g_object_set (source, "caps" , audio_caps, NULL);
   g_signal_connect (source, "need-data" , G_CALLBACK (start_feed), data);
   g_signal_connect (source, "enough-data" , G_CALLBACK (stop_feed), data);
   gst_caps_unref (audio_caps);
   g_free (audio_caps_text);
}
   
int main( int argc, char *argv[]) {
   CustomData data;
   GstBus *bus;
   
   /* Initialize cumstom data structure */
   memset (&data, 0, sizeof (data));
   data.b = 1; /* For waveform generation */
   data.d = 1;
   
   /* Initialize GStreamer */
   gst_init (&argc, &argv);
   
   /* Create the playbin2 element */
   data.pipeline = gst_parse_launch ( "playbin2 uri=appsrc://" , NULL);
   g_signal_connect (data.pipeline, "source-setup" , G_CALLBACK (source_setup), &data);
   
   /* Instruct the bus to emit signals for each received message, and connect to the interesting signals */
   bus = gst_element_get_bus (data.pipeline);
   gst_bus_add_signal_watch (bus);
   g_signal_connect (G_OBJECT (bus), "message::error" , (GCallback)error_cb, &data);
   gst_object_unref (bus);
   
   /* Start playing the pipeline */
   gst_element_set_state (data.pipeline, GST_STATE_PLAYING);
   
   /* Create a GLib Main Loop and set it to run */
   data.main_loop = g_main_loop_new (NULL, FALSE);
   g_main_loop_run (data.main_loop);
   
   /* Free resources */
   gst_element_set_state (data.pipeline, GST_STATE_NULL);
   gst_object_unref (data.pipeline);
   return 0;
}

To use an appsrc as the source for the pipeline, simply instantiate a playbin2 and set its URI to appsrc://

?
131
132
/* Create the playbin2 element */
data.pipeline = gst_parse_launch ( "playbin2 uri=appsrc://" , NULL);

playbin2 will create an internal appsrc element and fire the source-setup signal to allow the application to configure it:

?
133
g_signal_connect (data.pipeline, "source-setup" , G_CALLBACK (source_setup), &data);

In particular, it is important to set the caps property of appsrc, since, once the signal handler returns, playbin2 will instantiate the next element in the pipeline according to these caps:

?
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
/* This function is called when playbin2 has created the appsrc element, so we have
  * a chance to configure it. */
static void source_setup (GstElement *pipeline, GstElement *source, CustomData *data) {
   gchar *audio_caps_text;
   GstCaps *audio_caps;
   
   g_print ( "Source has been created. Configuring.\n" );
   data->app_source = source;
   
   /* Configure appsrc */
   audio_caps_text = g_strdup_printf (AUDIO_CAPS, SAMPLE_RATE);
   audio_caps = gst_caps_from_string (audio_caps_text);
   g_object_set (source, "caps" , audio_caps, NULL);
   g_signal_connect (source, "need-data" , G_CALLBACK (start_feed), data);
   g_signal_connect (source, "enough-data" , G_CALLBACK (stop_feed), data);
   gst_caps_unref (audio_caps);
   g_free (audio_caps_text);
}

The configuration of the appsrc is exactly the same as in Basic tutorial 8: Short-cutting the pipeline: the caps are set to audio/x-raw-int, and two callbacks are registered, so the element can tell the application when it needs to start and stop pushing data. See Basic tutorial 8: Short-cutting the pipeline for more details.

From this point onwards, playbin2 takes care of the rest of the pipeline, and the application only needs to worry about generating more data when told so.

To learn how data can be extracted from playbin2 using the appsink element, see Playback tutorial 7: Custom playbin2 sinks.

Conclusion

This tutorial applies the concepts shown in Basic tutorial 8: Short-cutting the pipeline to playbin2. In particular, it has shown:

  • How to connect appsrc with playbin2 using the special URI appsrc://
  • How to configure the appsrc using the source-setup signal

It has been a pleasure having you here, and see you soon!

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值