(1)appsink的使用:
#include
#define HAVE_GTK
#ifdef HAVE_GTK
#include
#endif
#include
#define CAPS "video/x-raw,format=RGB,width=160,pixel-aspect-ratio=1/1"
int
main (int argc, char *argv[])
{
GstElement *pipeline, *sink;
gint width, height;
GstSample *sample;
gchar *descr;
GError *error = NULL;
gint64 duration, position;
GstStateChangeReturn ret;
gboolean res;
GstMapInfo map;
gst_init (&argc, &argv);
if (argc != 2) {
g_print ("usage: %s \n Writes snapshot.png in the current directory\n",
argv[0]);
exit (-1);
}
/* create a new pipeline */
descr =
g_strdup_printf ("videotestsrc pattern=%s ! "
" appsink name=sink caps=\"" CAPS "\"", argv[1]);
pipeline = gst_parse_launch (descr, &error);
if (error != NULL) {
g_print ("could not construct pipeline: %s\n", error->message);
g_clear_error (&error);
exit (-1);
}
/* get sink */
sink = gst_bin_get_by_name (GST_BIN (pipeline), "sink");
/* set to PAUSED to make the first frame arrive in the sink */
ret = gst_element_set_state (pipeline, GST_STATE_PAUSED);
switch (ret) {
case GST_STATE_CHANGE_FAILURE:
g_print ("failed to play the file\n");
exit (-1);
case GST_STATE_CHANGE_NO_PREROLL:
/* for live sources, we need to set the pipeline to PLAYING before we can
* receive a buffer. We don't do that yet */
g_print ("live sources not supported yet\n");
exit (-1);
default:
break;
}
/* This can block for up to 5 seconds. If your machine is really overloaded,
* it might time out before the pipeline prerolled and we generate an error. A
* better way is to run a mainloop and catch errors there. */
ret = gst_element_get_state (pipeline, NULL, NULL, 5 * GST_SECOND);
if (ret == GST_STATE_CHANGE_FAILURE) {
g_print ("failed to play the file\n");
exit (-1);
}
/* get the duration */
gst_element_query_duration (pipeline, GST_FORMAT_TIME, &duration);
if (duration != -1)
/* we have a duration, seek to 5% */
position = duration * 5 / 100;
else
/* no duration, seek to 1 second, this could EOS */
position = 1 * GST_SECOND;
/* seek to the a position in the file. Most files have a black first frame so
* by seeking to somewhere else we have a bigger chance of getting something
* more interesting. An optimisation would be to detect black images and then
* seek a little more */
gst_element_seek_simple (pipeline, GST_FORMAT_TIME,
GST_SEEK_FLAG_KEY_UNIT | GST_SEEK_FLAG_FLUSH, position);
/* get the preroll buffer from appsink, this block untils appsink really
* prerolls */
g_signal_emit_by_name (sink, "pull-preroll", &sample, NULL);
/* if we have a buffer now, convert it to a pixbuf. It's possible that we
* don't have a buffer because we went EOS right away or had an error. */
if (sample) {
GstBuffer *buffer;
GstCaps *caps;
GstStructure *s;
/* get the snapshot buffer format now. We set the caps on the appsink so
* that it can only be an rgb buffer. The only thing we have not specified
* on the caps is the height, which is dependant on the pixel-aspect-ratio
* of the source material */
caps = gst_sample_get_caps (sample);
if (!caps) {
g_print ("could not get snapshot format\n");
exit (-1);
}
s = gst_caps_get_structure (caps, 0);
/* we need to get the final caps on the buffer to get the size */
res = gst_structure_get_int (s, "width", &width);
res |= gst_structure_get_int (s, "height", &height);
if (!res) {
g_print ("could not get snapshot dimension\n");
exit (-1);
}
/* create pixmap from buffer and save, gstreamer video buffers have a stride
* that is rounded up to the nearest multiple of 4 */
buffer = gst_sample_get_buffer (sample);
/* Mapping a buffer can fail (non-readable) */
if (gst_buffer_map (buffer, &map, GST_MAP_READ)) {
/* print the buffer data for debug */
int i = 0, j = 0;
g_print("width=%d, height = %d\n", width, height);
for(; i < width; i++){
for(; j < height; j++){
g_print("%x ", map.data[i*width + j]);
}
g_print("\n");
}
#ifdef HAVE_GTK
GdkPixbuf * pixbuf = gdk_pixbuf_new_from_data (map.data,
GDK_COLORSPACE_RGB, FALSE, 8, width, height,
GST_ROUND_UP_4 (width * 3), NULL, NULL);
/* save the pixbuf */
gdk_pixbuf_save (pixbuf, "snapshot.png", "png", &error, NULL);
#endif
gst_buffer_unmap (buffer, &map);
}
gst_sample_unref (sample);
} else {
g_print ("could not make snapshot\n");
}
/* cleanup and exit */
gst_element_set_state (pipeline, GST_STATE_NULL);
gst_object_unref (pipeline);
exit (0);
}
需要安装gtk:sudo apt-get install libgtk2.0-dev
编译命令:gcc appsink_example.c -o appsink_example $(pkg-config --cflags --libs gstreamer-1.0 gtk+-2.0)
执行: ./appsink_example red
(2)appsrc 例子:
/*
I don't know if it is syntax highlighter or blogger, but I can't seem to
put angle brackets around header file names properly.
*/
#include
#include
#include
typedef struct {
GstPipeline *pipeline;
GstAppSrc *src;
GstElement *sink;
GstElement *decoder;
GstElement *ffmpeg;
GstElement *videosink;
GMainLoop *loop;
guint sourceid;
FILE *file;
}gst_app_t;
static gst_app_t gst_app;
#define BUFF_SIZE (1024)
static gboolean read_data(gst_app_t *app)
{
GstBuffer *buffer;
guint8 *ptr;
gint size;
GstFlowReturn ret;
ptr = g_malloc(BUFF_SIZE);
g_assert(ptr);
//g_print("read data...................\n");
size = fread(ptr, 1, BUFF_SIZE, app->file);
if(size == 0){
ret = gst_app_src_end_of_stream(app->src);
g_debug("eos returned %d at %d\n", ret, __LINE__);
return FALSE;
}
buffer = gst_buffer_new();
GST_BUFFER_MALLOCDATA(buffer) = ptr;
GST_BUFFER_SIZE(buffer) = size;
GST_BUFFER_DATA(buffer) = GST_BUFFER_MALLOCDATA(buffer);
ret = gst_app_src_push_buffer(app->src, buffer);
if(ret != GST_FLOW_OK){
g_debug("push buffer returned %d for %d bytes \n", ret, size);
return FALSE;
}
if(size != BUFF_SIZE){
ret = gst_app_src_end_of_stream(app->src);
g_debug("eos returned %d at %d\n", ret, __LINE__);
return FALSE;
}
return TRUE;
}
static void start_feed (GstElement * pipeline, guint size, gst_app_t *app)
{
g_print("start feed...................\n");
if (app->sourceid == 0) {
GST_DEBUG ("start feeding");
app->sourceid = g_idle_add ((GSourceFunc) read_data, app);
}
}
static void stop_feed (GstElement * pipeline, gst_app_t *app)
{
g_print("stop feed...................\n");
if (app->sourceid != 0) {
GST_DEBUG ("stop feeding");
g_source_remove (app->sourceid);
app->sourceid = 0;
}
}
static void on_pad_added(GstElement *element, GstPad *pad)
{
GstCaps *caps;
GstStructure *str;
gchar *name;
GstPad *ffmpegsink;
GstPadLinkReturn ret;
g_debug("pad added");
caps = gst_pad_get_caps(pad);
str = gst_caps_get_structure(caps, 0);
g_assert(str);
name = (gchar*)gst_structure_get_name(str);
g_debug("pad name %s", name);
if(g_strrstr(name, "video")){
ffmpegsink = gst_element_get_pad(gst_app.ffmpeg, "sink");
g_assert(ffmpegsink);
ret = gst_pad_link(pad, ffmpegsink);
g_debug("pad_link returned %d\n", ret);
gst_object_unref(ffmpegsink);
}
gst_caps_unref(caps);
}
static gboolean bus_callback(GstBus *bus, GstMessage *message, gpointer *ptr)
{
gst_app_t *app = (gst_app_t*)ptr;
switch(GST_MESSAGE_TYPE(message)){
case GST_MESSAGE_ERROR:{
gchar *debug;
GError *err;
gst_message_parse_error(message, &err, &debug);
g_print("Error %s\n", err->message);
g_error_free(err);
g_free(debug);
g_main_loop_quit(app->loop);
}
break;
case GST_MESSAGE_WARNING:{
gchar *debug;
GError *err;
gchar *name;
gst_message_parse_warning(message, &err, &debug);
g_print("Warning %s\nDebug %s\n", err->message, debug);
name = GST_MESSAGE_SRC_NAME(message);
g_print("Name of src %s\n", name ? name : "nil");
g_error_free(err);
g_free(debug);
}
break;
case GST_MESSAGE_EOS:
g_print("End of stream\n");
g_main_loop_quit(app->loop);
break;
case GST_MESSAGE_STATE_CHANGED:
break;
default:
g_print("got message %s\n", \
gst_message_type_get_name (GST_MESSAGE_TYPE (message)));
break;
}
return TRUE;
}
int main(int argc, char *argv[])
{
gst_app_t *app = &gst_app;
GstBus *bus;
GstStateChangeReturn state_ret;
if(argc != 2){
printf("File name not specified\n");
return 1;
}
app->file = fopen(argv[1], "r");
g_assert(app->file);
gst_init(NULL, NULL);
app->pipeline = (GstPipeline*)gst_pipeline_new("mypipeline");
bus = gst_pipeline_get_bus(app->pipeline);
gst_bus_add_watch(bus, (GstBusFunc)bus_callback, app);
gst_object_unref(bus);
app->src = (GstAppSrc*)gst_element_factory_make("appsrc", "mysrc");
app->decoder = gst_element_factory_make("decodebin2", "mydecoder");
app->ffmpeg = gst_element_factory_make("ffmpegcolorspace", "myffmpeg");
app->videosink = gst_element_factory_make("autovideosink", "myvsink");
g_assert(app->src);
g_assert(app->decoder);
g_assert(app->ffmpeg);
g_assert(app->videosink);
g_signal_connect(app->src, "need-data", G_CALLBACK(start_feed), app);
g_signal_connect(app->src, "enough-data", G_CALLBACK(stop_feed), app);
g_signal_connect(app->decoder, "pad-added",
G_CALLBACK(on_pad_added), app->decoder);
gst_bin_add_many(GST_BIN(app->pipeline), (GstElement*)app->src,
app->decoder, app->ffmpeg, app->videosink, NULL);
if(!gst_element_link((GstElement*)app->src, app->decoder)){
g_warning("failed to link src anbd decoder");
}
if(!gst_element_link(app->ffmpeg, app->videosink)){
g_warning("failed to link ffmpeg and xvsink");
}
state_ret = gst_element_set_state((GstElement*)app->pipeline, GST_STATE_PLAYING);
g_warning("set state returned %d\n", state_ret);
app->loop = g_main_loop_new(NULL, FALSE);
g_main_loop_run(app->loop);
state_ret = gst_element_set_state((GstElement*)app->pipeline, GST_STATE_NULL);
g_warning("set state null returned %d\n", state_ret);
return 0;
}
编译:gcc appsrc2.c -o appsrc2 $(pkg-config --cflags --libs gstreamer-0.10 gstreamer-app-0.10)
运行:./appsrc2 xx.avi
(3)appsink和appsrc一起使用的例子:
/* GStreamer
*
* appsink-src.c: example for using appsink and appsrc.
*
* Copyright (C) 2008 Wim Taymans
*
* 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., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#include
#include
#include
#include
/* these are the caps we are going to pass through the appsink and appsrc */
const gchar *audio_caps =
"audio/x-raw,format=S16LE,channels=2,rate=44100,layout=interleaved";
#define DEVICE "alsa_output.pci-0000_00_05.0.analog-stereo.monitor"
#define APPSRC_PULL_MODE (0) /* appsrc working in pull mode or not */
#define PLAY_FILE (0) /* play file or get data from pulseaudio */
#define SAVE_FILE (1) /* save a file or playing directly */
static GstBuffer* s_app_buffer = NULL;
typedef struct
{
GMainLoop *loop;
GstElement *sink_pipeline;
GstElement *src_pipeline;
} ProgramData;
/* called when the appsink notifies us that there is a new buffer ready for
* processing */
static GstFlowReturn
on_new_sample_from_sink (GstElement * sink_elm, ProgramData * data)
{
GstSample *sample = NULL;
GstBuffer *buffer, *app_buffer;
GstElement *sink, *source;
GstFlowReturn ret;
GstMapInfo map;
/* get the sample from appsink */
//sample = gst_app_sink_pull_sample (GST_APP_SINK (sink_elm));
#if 0
sink = gst_bin_get_by_name (GST_BIN (data->src_pipeline), "testsink");
g_signal_emit_by_name (sink, "pull-sample", &sample, &ret);
gst_object_unref (sink);
#else
g_signal_emit_by_name(sink_elm, "pull-sample", &sample, &ret);
#endif
if(sample){
buffer = gst_sample_get_buffer (sample);
g_print("on_new_sample_from_sink() call!; size = %d\n", gst_buffer_get_size(buffer));
}
else{
g_print("sample is NULL \n");
return ret;
}
/* 查看pull 到的sample 数据 */
#if 0
/* Mapping a buffer can fail (non-readable) */
if (gst_buffer_map (buffer, &map, GST_MAP_READ)) {
/* print the buffer data for debug */
int i = 0, j = 0;
for(; i < 10; i++)
g_print("%x ", map.data[i]);
g_print("\n");
}
#endif
/* make a copy */
#if !APPSRC_PULL_MODE
app_buffer = gst_buffer_copy (buffer);
#else
s_app_buffer = gst_buffer_copy(buffer);
#endif
/* we don't need the appsink sample anymore */
gst_sample_unref (sample);
/* 如果appsrc 为push 模式,直接将数据注入给appsrc */
/* get source an push new buffer */
#if !APPSRC_PULL_MODE
source = gst_bin_get_by_name (GST_BIN (data->sink_pipeline), "testsource");
//ret = gst_app_src_push_buffer (GST_APP_SRC (source), app_buffer);
g_signal_emit_by_name( source, "push-buffer", app_buffer, &ret );//数据送入pipeline
gst_object_unref (source);
gst_buffer_unref(app_buffer);
#endif
return ret;
}
/* called when we get a GstMessage from the source pipeline when we get EOS, we
* notify the appsrc of it. */
static gboolean
on_appsink_message (GstBus * bus, GstMessage * message, ProgramData * data)
{
GstElement *source;
switch (GST_MESSAGE_TYPE (message)) {
case GST_MESSAGE_EOS:
g_print ("The source got dry\n");
source = gst_bin_get_by_name (GST_BIN (data->sink_pipeline), "testsource");
//gst_app_src_end_of_stream (GST_APP_SRC (source));
g_signal_emit_by_name (source, "end-of-stream", NULL);
gst_object_unref (source);
break;
case GST_MESSAGE_ERROR:
g_print ("Received error\n");
g_main_loop_quit (data->loop);
break;
default:
break;
}
return TRUE;
}
/* called when we get a GstMessage from the sink pipeline when we get EOS, we
* exit the mainloop and this testapp. */
static gboolean
on_appsrc_message (GstBus * bus, GstMessage * message, ProgramData * data)
{
/* nil */
switch (GST_MESSAGE_TYPE (message)) {
case GST_MESSAGE_EOS:
g_print ("Finished playback\n");
g_main_loop_quit (data->loop);
break;
case GST_MESSAGE_ERROR:
g_print ("Received error\n");
g_main_loop_quit (data->loop);
break;
default:
break;
}
return TRUE;
}
static gboolean read_data(ProgramData* app_data)
{
GstElement *appsink;
appsink = gst_bin_get_by_name (GST_BIN (app_data->src_pipeline), "testsink");
GstFlowReturn ret = on_new_sample_from_sink(appsink, app_data);
gst_object_unref(appsink);
GstElement *source = NULL;
if(s_app_buffer){
g_print("read data()....\n");
source = gst_bin_get_by_name (GST_BIN (app_data->sink_pipeline), "testsource");
//ret = gst_app_src_push_buffer (GST_APP_SRC (source), app_buffer);
g_signal_emit_by_name( source, "push-buffer", s_app_buffer, &ret );//数据送入pipeline
gst_object_unref (source);
gst_buffer_unref(s_app_buffer);
s_app_buffer = NULL;
}
else{
g_print("read_data() s_app_buffer is NULL\n");
}
return TRUE;
}
static void on_appsrc_need_data(GstElement *appsrc,
guint unused_size,
ProgramData* app_data)
{
g_print("on_appsrc_need_data() call !!!\n");
guint src_id = g_idle_add ((GSourceFunc) read_data, app_data);
return;
}
int main (int argc, char *argv[])
{
gchar *filename = NULL;
ProgramData *data = NULL;
gchar *string = NULL;
GstBus *bus = NULL;
GstElement *testsink = NULL;
GstElement *testsource = NULL;
gst_init (&argc, &argv);
if (argc == 2)
filename = g_strdup (argv[1]);
else
filename = g_strdup ("xxx/xxxx.wav");
if (!g_file_test (filename, G_FILE_TEST_EXISTS)) {
g_print ("File %s does not exist\n", filename);
return -1;
}
data = g_new0 (ProgramData, 1);
data->loop = g_main_loop_new (NULL, FALSE);
/* setting up source pipeline, we read from a file and convert to our desired
* caps. */
#if PLAY_FILE /* 播放wav 歌曲 */
string =
g_strdup_printf
("filesrc location=\"%s\" ! wavparse ! audioconvert ! appsink caps=\"%s\" name=testsink",
filename, audio_caps);
#else /* 从pulseaudio 抓取 */
string =
g_strdup_printf
("pulsesrc device=%s ! audioconvert ! appsink caps=\"%s\" name=testsink",
DEVICE, audio_caps);
#endif
g_free (filename);
g_print("%s\n", string);
data->src_pipeline = gst_parse_launch (string, NULL);
g_free (string);
if (data->src_pipeline == NULL) {
g_print ("Bad source\n");
return -1;
}
/* to be notified of messages from this pipeline, mostly EOS */
bus = gst_element_get_bus (data->src_pipeline);
gst_bus_add_watch (bus, (GstBusFunc) on_appsink_message, data);
gst_object_unref (bus);
/* we use appsink in push mode, it sends us a signal when data is available
* and we pull out the data in the signal callback. We want the appsink to
* push as fast as it can, hence the sync=false */
testsink = gst_bin_get_by_name (GST_BIN (data->src_pipeline), "testsink");
#if !APPSRC_PULL_MODE
g_object_set (G_OBJECT (testsink), "emit-signals", TRUE, "sync", FALSE, NULL);
g_signal_connect (testsink, "new-sample",
G_CALLBACK (on_new_sample_from_sink), data);
#endif
gst_object_unref (testsink);
/* setting up sink pipeline, we push audio data into this pipeline that will
* then play it back using the default audio sink. We have no blocking
* behaviour on the src which means that we will push the entire file into
* memory. */
#if !SAVE_FILE
string =
g_strdup_printf ("appsrc name=testsource caps=\"%s\" ! autoaudiosink",
audio_caps);
#else
string =
g_strdup_printf ("appsrc name=testsource caps=\"%s\" ! avenc_aac ! avmux_adts ! filesink location=sink_src.aac",
audio_caps);
#endif
data->sink_pipeline = gst_parse_launch (string, NULL);
g_free (string);
if (data->sink_pipeline == NULL) {
g_print ("Bad sink\n");
return -1;
}
testsource = gst_bin_get_by_name (GST_BIN (data->sink_pipeline), "testsource");
/* configure for time-based format */
g_object_set (testsource, "format", GST_FORMAT_TIME, NULL);
/* uncomment the next line to block when appsrc has buffered enough */
/* g_object_set (testsource, "block", TRUE, NULL); */
#if APPSRC_PULL_MODE
g_signal_connect (testsource, "need-data",
G_CALLBACK (on_appsrc_need_data), data);
#endif
gst_object_unref (testsource);
bus = gst_element_get_bus (data->sink_pipeline);
gst_bus_add_watch (bus, (GstBusFunc) on_appsrc_message, data);
gst_object_unref (bus);
/* launching things */
gst_element_set_state (data->src_pipeline, GST_STATE_PLAYING);
gst_element_set_state (data->sink_pipeline, GST_STATE_PLAYING);
/* let's run !, this loop will quit when the sink pipeline goes EOS or when an
* error occurs in the source or sink pipelines. */
g_print ("Let's run!\n");
g_main_loop_run (data->loop);
g_print ("Going out\n");
gst_element_set_state (data->src_pipeline, GST_STATE_NULL);
gst_element_set_state (data->sink_pipeline, GST_STATE_NULL);
gst_object_unref (data->src_pipeline);
gst_object_unref (data->sink_pipeline);
g_main_loop_unref (data->loop);
g_free (data);
return 0;
}
编译:
//gcc appsink_src_test.c -o appsink_src_test $(pkg-config --cflags --libs gstreamer-1.0)
// or gcc appsink_src_test.c -o appsink_src_test $(pkg-config --cflags --libs gstreamer-1.0 gstreamer-app-1.0)