--- /dev/null
+class ThumbnailSink : Gst.BaseSink {
+ int width;
+ int height;
+
+ const string caps_string = """video/x-raw-rgb,bpp = (int) 32, depth = (int) 32,
+ endianness = (int) BIG_ENDIAN,
+ blue_mask = (int) 0xFF000000,
+ green_mask = (int) 0x00FF0000,
+ red_mask = (int) 0x0000FF00,
+ width = (int) [ 1, max ],
+ height = (int) [ 1, max ],
+ framerate = (fraction) [ 0, max ]""";
+
+ public signal void have_thumbnail(Gdk.Pixbuf b);
+
+ class construct {
+ Gst.StaticPadTemplate pad;
+ pad.name_template = "sink";
+ pad.direction = Gst.PadDirection.SINK;
+ pad.presence = Gst.PadPresence.ALWAYS;
+ pad.static_caps.str = caps_string;
+
+ add_pad_template(pad.get());
+ }
+
+ // This empty construct block eliminates a build warning about chaining up to a private
+ // constructor.
+ construct {
+ }
+
+ public ThumbnailSink() {
+ set_sync(false);
+ }
+
+ public override bool set_caps(Gst.Caps c) {
+ if (c.get_size() < 1)
+ return false;
+
+ Gst.Structure s = c.get_structure(0);
+
+ if (!s.get_int("width", out width) ||
+ !s.get_int("height", out height))
+ return false;
+ return true;
+ }
+
+ void convert_pixbuf_to_rgb(Gdk.Pixbuf buf) {
+ uchar* data = buf.get_pixels();
+ int limit = buf.get_width() * buf.get_height();
+
+ while (limit-- != 0) {
+ uchar temp = data[0];
+ data[0] = data[2];
+ data[2] = temp;
+
+ data += 4;
+ }
+ }
+
+ public override Gst.FlowReturn preroll(Gst.Buffer b) {
+ Gdk.Pixbuf buf = new Gdk.Pixbuf.from_data(b.data, Gdk.Colorspace.RGB,
+ true, 8, width, height, width * 4, null);
+ convert_pixbuf_to_rgb(buf);
+
+ have_thumbnail(buf);
+ return Gst.FlowReturn.OK;
+ }
+}