/* 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 #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; guint8 *data; gsize size; 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 ("uridecodebin uri=%s ! ffmpegcolorspace ! videoscale ! " " 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_error_free (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 */ 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_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", &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 */ #if 0 caps = GST_BUFFER_CAPS (buffer); #endif /* FIXME, get buffer caps somehow */ caps = NULL; 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 */ data = gst_buffer_map (buffer, &size, NULL, GST_MAP_READ); pixbuf = gdk_pixbuf_new_from_data (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); gst_buffer_unmap (buffer, data, size); /* 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); }