diff --git a/ChangeLog b/ChangeLog index 0b97c53ea5..a37a932e53 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,12 @@ +2007-09-20 Wim Taymans + + * configure.ac: + * tests/examples/Makefile.am: + * tests/examples/snapshot/.cvsignore: + * tests/examples/snapshot/Makefile.am: + * tests/examples/snapshot/snapshot.c: (main): + Add simple snapshot example program using appsink. + 2007-09-20 Stefan Kost * tests/check/generic/states.c: diff --git a/configure.ac b/configure.ac index 3bca76e22c..d0fa5a23c9 100644 --- a/configure.ac +++ b/configure.ac @@ -699,6 +699,7 @@ tests/examples/Makefile tests/examples/dynamic/Makefile tests/examples/seek/Makefile tests/examples/volume/Makefile +tests/examples/snapshot/Makefile tests/icles/Makefile docs/Makefile docs/design/Makefile diff --git a/tests/examples/Makefile.am b/tests/examples/Makefile.am index 8502c38765..0e1ed8e18a 100644 --- a/tests/examples/Makefile.am +++ b/tests/examples/Makefile.am @@ -1,9 +1,9 @@ if HAVE_FT2 -FT2_SUBDIRS = seek +FT2_SUBDIRS = seek snapshot else FT2_SUBDIRS = endif SUBDIRS = $(FT2_SUBDIRS) volume dynamic -DIST_SUBDIRS = seek volume dynamic +DIST_SUBDIRS = seek volume dynamic snapshot diff --git a/tests/examples/snapshot/.gitignore b/tests/examples/snapshot/.gitignore new file mode 100644 index 0000000000..a701b4cb03 --- /dev/null +++ b/tests/examples/snapshot/.gitignore @@ -0,0 +1,2 @@ +snapshot +snapshot.png diff --git a/tests/examples/snapshot/Makefile.am b/tests/examples/snapshot/Makefile.am new file mode 100644 index 0000000000..16830eef92 --- /dev/null +++ b/tests/examples/snapshot/Makefile.am @@ -0,0 +1,10 @@ +if HAVE_GTK +GTK_EXAMPLES=snapshot +endif + +examples = $(GTK_EXAMPLES) + +noinst_PROGRAMS = $(examples) + +LIBS = $(GST_LIBS) $(GTK_LIBS) +AM_CFLAGS = $(GST_CFLAGS) $(GTK_CFLAGS) diff --git a/tests/examples/snapshot/snapshot.c b/tests/examples/snapshot/snapshot.c new file mode 100644 index 0000000000..67d5c52aee --- /dev/null +++ b/tests/examples/snapshot/snapshot.c @@ -0,0 +1,144 @@ +/* GStreamer snapshot example + * Copyright (C) <2007> 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include +#include + +#define CAPS "video/x-raw-rgb,width=160,pixel-aspect-ratio=1/1,bpp=(int)24,depth=(int)24,endianness=(int)4321,red_mask=(int)0xff0000, green_mask=(int)0x00ff00, blue_mask=(int)0x0000ff" + +int +main (int argc, char *argv[]) +{ + GstElement *pipeline, *sink; + gint width, height; + GstBuffer *buffer; + gchar *descr; + GError *error = NULL; + GdkPixbuf *pixbuf; + gint64 duration, position; + GstFormat format; + GstStateChangeReturn ret; + gboolean res; + + gst_init (&argc, &argv); + + if (argc != 2) { + g_print ("usage: %s \n Writes snapshot.png in the current directory", + argv[0]); + exit (-1); + } + + /* create a new pipeline */ + descr = + g_strdup_printf ("uridecodebin uri=%s ! ffmpegcolorspace ! videoscale ! " + " appsink name=sink caps=\"" CAPS "\"", argv[1]); + pipeline = gst_parse_launch (descr, &error); + g_assert (error == NULL); + + /* 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 */ + format = GST_FORMAT_TIME; + gst_element_query_duration (pipeline, &format, &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_FLUSH, + position); + + /* get the preroll buffer from appsink, this block untils appsink really + * prerolls */ + g_signal_emit_by_name (sink, "pull-preroll", &buffer, 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 (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_BUFFER_CAPS (buffer); + 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 */ + pixbuf = gdk_pixbuf_new_from_data (GST_BUFFER_DATA (buffer), + 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); + } 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); +}