Skip to content

Commit eb0ade9

Browse files
dgsiegelhodefoting
authored andcommitted
pinpoint: Show still of video when exporting presentation to pdf
When exporting to pdf, a still of the included video will be automatically created and shown in the background.
1 parent e5133b4 commit eb0ade9

File tree

4 files changed

+378
-2
lines changed

4 files changed

+378
-2
lines changed

pinpoint/Makefile.am

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ pinpoint_SOURCES = \
1414
pinpoint.h \
1515
pp-cairo.c \
1616
pp-clutter.c \
17+
gst-video-thumbnailer.c \
1718
$(DAX_SOURCES)
1819

1920
EXTRA_DIST=sample.txt wth.jpg bg.jpg pp-super-aa.c pp-super-aa.h

pinpoint/gst-video-thumbnailer.c

Lines changed: 318 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,318 @@
1+
/*
2+
* Bickley - a meta data management framework.
3+
* Copyright © 2008 - 2009, Intel Corporation.
4+
*
5+
* This program is free software; you can redistribute it and/or modify it
6+
* under the terms and conditions of the GNU Lesser General Public License,
7+
* version 2.1, as published by the Free Software Foundation.
8+
*
9+
* This program is distributed in the hope it will be useful, but WITHOUT
10+
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11+
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
12+
* more details.
13+
*
14+
* You should have received a copy of the GNU Lesser General Public License
15+
* along with this program; if not, write to the Free Software Foundation,
16+
* Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA
17+
*/
18+
19+
#include <config.h>
20+
21+
#include <string.h>
22+
#include <stdlib.h>
23+
#include <glib.h>
24+
25+
#include <gio/gio.h>
26+
#include <gst/gst.h>
27+
#include <gdk-pixbuf/gdk-pixbuf.h>
28+
29+
#include "gst-video-thumbnailer.h"
30+
31+
static void
32+
push_buffer (GstElement *element,
33+
GstBuffer *out_buffer,
34+
GstPad *pad,
35+
GstBuffer *in_buffer)
36+
{
37+
gst_buffer_set_caps (out_buffer, GST_BUFFER_CAPS (in_buffer));
38+
GST_BUFFER_SIZE (out_buffer) = GST_BUFFER_SIZE (in_buffer);
39+
memcpy (GST_BUFFER_DATA (out_buffer), GST_BUFFER_DATA (in_buffer),
40+
GST_BUFFER_SIZE (in_buffer));
41+
}
42+
43+
static void
44+
pull_buffer (GstElement *element,
45+
GstBuffer *in_buffer,
46+
GstPad *pad,
47+
GstBuffer **out_buffer)
48+
{
49+
*out_buffer = gst_buffer_ref (in_buffer);
50+
}
51+
52+
GdkPixbuf *
53+
convert_buffer_to_pixbuf (GstBuffer *buffer,
54+
GCancellable *cancellable)
55+
{
56+
GstCaps *pb_caps;
57+
GstElement *pipeline;
58+
GstBuffer *out_buffer = NULL;
59+
GstElement *src, *sink, *colorspace, *scale, *filter;
60+
GstBus *bus;
61+
GstMessage *msg;
62+
GstStateChangeReturn state;
63+
gboolean ret;
64+
int width, height, dw, dh, i;
65+
GstStructure *s;
66+
67+
s = gst_caps_get_structure (GST_BUFFER_CAPS (buffer), 0);
68+
gst_structure_get_int (s, "width", &dw);
69+
gst_structure_get_int (s, "height", &dh);
70+
71+
pb_caps = gst_caps_new_simple ("video/x-raw-rgb",
72+
"bpp", G_TYPE_INT, 24,
73+
"depth", G_TYPE_INT, 24,
74+
"width", G_TYPE_INT, dw,
75+
"height", G_TYPE_INT, dh,
76+
"pixel-aspect-ratio", GST_TYPE_FRACTION, 1, 1,
77+
NULL);
78+
79+
pipeline = gst_pipeline_new ("pipeline");
80+
81+
src = gst_element_factory_make ("fakesrc", "src");
82+
colorspace = gst_element_factory_make ("ffmpegcolorspace", "colorspace");
83+
scale = gst_element_factory_make ("videoscale", "scale");
84+
filter = gst_element_factory_make ("capsfilter", "filter");
85+
sink = gst_element_factory_make ("fakesink", "sink");
86+
87+
gst_bin_add_many (GST_BIN (pipeline), src, colorspace, scale,
88+
filter, sink, NULL);
89+
90+
g_object_set (filter,
91+
"caps", pb_caps,
92+
NULL);
93+
g_object_set (src,
94+
"num-buffers", 1,
95+
"sizetype", 2,
96+
"sizemax", GST_BUFFER_SIZE (buffer),
97+
"signal-handoffs", TRUE,
98+
NULL);
99+
g_signal_connect (src, "handoff",
100+
G_CALLBACK (push_buffer), buffer);
101+
102+
g_object_set (sink,
103+
"signal-handoffs", TRUE,
104+
"preroll-queue-len", 1,
105+
NULL);
106+
g_signal_connect (sink, "handoff",
107+
G_CALLBACK (pull_buffer), &out_buffer);
108+
109+
ret = gst_element_link (src, colorspace);
110+
if (ret == FALSE) {
111+
g_warning ("Failed to link src->colorspace");
112+
return NULL;
113+
}
114+
115+
ret = gst_element_link (colorspace, scale);
116+
if (ret == FALSE) {
117+
g_warning ("Failed to link colorspace->scale");
118+
return NULL;
119+
}
120+
121+
ret = gst_element_link (scale, filter);
122+
if (ret == FALSE) {
123+
g_warning ("Failed to link scale->filter");
124+
return NULL;
125+
}
126+
127+
ret = gst_element_link (filter, sink);
128+
if (ret == FALSE) {
129+
g_warning ("Failed to link filter->sink");
130+
return NULL;
131+
}
132+
133+
bus = gst_element_get_bus (GST_ELEMENT (pipeline));
134+
state = gst_element_set_state (GST_ELEMENT (pipeline), GST_STATE_PLAYING);
135+
136+
i = 0;
137+
msg = NULL;
138+
while (msg == NULL && i < 5) {
139+
msg = gst_bus_timed_pop_filtered (bus, GST_SECOND,
140+
GST_MESSAGE_ERROR | GST_MESSAGE_EOS);
141+
i++;
142+
}
143+
144+
/* FIXME: Notify about error? */
145+
gst_message_unref (msg);
146+
147+
gst_caps_unref (pb_caps);
148+
149+
if (out_buffer) {
150+
GdkPixbuf *pixbuf;
151+
char *data;
152+
153+
data = g_memdup (GST_BUFFER_DATA (out_buffer),
154+
GST_BUFFER_SIZE (out_buffer));
155+
pixbuf = gdk_pixbuf_new_from_data ((guchar *) data,
156+
GDK_COLORSPACE_RGB, FALSE,
157+
8, dw, dh, GST_ROUND_UP_4 (dw * 3),
158+
(GdkPixbufDestroyNotify) g_free,
159+
NULL);
160+
161+
gst_buffer_unref (buffer);
162+
return pixbuf;
163+
}
164+
165+
/* FIXME: Check what buffers need freed */
166+
return NULL;
167+
}
168+
169+
GdkPixbuf *
170+
gst_video_thumbnailer_get_shot (const gchar *location,
171+
GCancellable *cancellable)
172+
{
173+
GstElement *playbin, *audio_sink, *video_sink;
174+
GstStateChangeReturn state;
175+
GdkPixbuf *shot = NULL;
176+
int count = 0;
177+
gchar *uri = g_strconcat ("file://", location, NULL);
178+
179+
playbin = gst_element_factory_make ("playbin", "playbin");
180+
audio_sink = gst_element_factory_make ("fakesink", "audiosink");
181+
video_sink = gst_element_factory_make ("fakesink", "videosink");
182+
183+
g_object_set (playbin,
184+
"uri", uri,
185+
"audio-sink", audio_sink,
186+
"video-sink", video_sink,
187+
NULL);
188+
g_object_set (video_sink,
189+
"sync", TRUE,
190+
NULL);
191+
state = gst_element_set_state (playbin, GST_STATE_PAUSED);
192+
while (state == GST_STATE_CHANGE_ASYNC
193+
&& count < 5
194+
&& !g_cancellable_is_cancelled (cancellable)) {
195+
g_print ("Waiting in loop %d\n", count);
196+
state = gst_element_get_state (playbin, NULL, 0, 1 * GST_SECOND);
197+
count++;
198+
199+
/* Spin mainloop so we can pick up the cancels */
200+
while (g_main_context_pending (NULL)) {
201+
g_main_context_iteration (NULL, FALSE);
202+
}
203+
}
204+
205+
if (g_cancellable_is_cancelled (cancellable)) {
206+
g_print ("Video %s was cancelled\n", uri);
207+
state = GST_STATE_CHANGE_FAILURE;
208+
}
209+
210+
if (state != GST_STATE_CHANGE_FAILURE &&
211+
state != GST_STATE_CHANGE_ASYNC) {
212+
GstFormat format = GST_FORMAT_TIME;
213+
gint64 duration;
214+
215+
if (gst_element_query_duration (playbin, &format, &duration)) {
216+
gint64 seekpos;
217+
GstBuffer *frame;
218+
219+
if (duration > 0) {
220+
if (duration / (3 * GST_SECOND) > 90) {
221+
seekpos = (rand () % (duration / (3 * GST_SECOND))) * GST_SECOND;
222+
} else {
223+
seekpos = (rand () % (duration / (GST_SECOND))) * GST_SECOND;
224+
}
225+
} else {
226+
seekpos = 5 * GST_SECOND;
227+
}
228+
229+
gst_element_seek_simple (playbin, GST_FORMAT_TIME,
230+
GST_SEEK_FLAG_FLUSH |
231+
GST_SEEK_FLAG_ACCURATE, seekpos);
232+
233+
/* Wait for seek to complete */
234+
count = 0;
235+
state = gst_element_get_state (playbin, NULL, 0,
236+
0.2 * GST_SECOND);
237+
while (state == GST_STATE_CHANGE_ASYNC && count < 3) {
238+
g_print ("Waiting in loop %d\n", count);
239+
state = gst_element_get_state (playbin, NULL, 0, 1 * GST_SECOND);
240+
count++;
241+
}
242+
243+
g_object_get (playbin,
244+
"frame", &frame,
245+
NULL);
246+
if (frame == NULL) {
247+
g_warning ("No frame for %s", uri);
248+
return NULL;
249+
}
250+
251+
shot = convert_buffer_to_pixbuf (frame, cancellable);
252+
}
253+
}
254+
255+
gst_element_set_state (playbin, GST_STATE_NULL);
256+
g_object_unref (playbin);
257+
g_free (uri);
258+
259+
return shot;
260+
}
261+
262+
static gboolean
263+
is_interesting (GdkPixbuf *pixbuf)
264+
{
265+
int width, height, r, rowstride;
266+
gboolean has_alpha;
267+
guint32 histogram[4][4][4] = {{{0,},},};
268+
guchar *pixels;
269+
int pxl_count = 0, count, i;
270+
271+
width = gdk_pixbuf_get_width (pixbuf);
272+
height = gdk_pixbuf_get_height (pixbuf);
273+
rowstride = gdk_pixbuf_get_rowstride (pixbuf);
274+
has_alpha = gdk_pixbuf_get_has_alpha (pixbuf);
275+
276+
pixels = gdk_pixbuf_get_pixels (pixbuf);
277+
for (r = 0; r < height; r++) {
278+
guchar *row = pixels + (r * rowstride);
279+
int c;
280+
281+
for (c = 0; c < width; c++) {
282+
guchar r, g, b;
283+
284+
r = row[0];
285+
g = row[1];
286+
b = row[2];
287+
288+
histogram[r / 64][g / 64][b / 64]++;
289+
290+
if (has_alpha) {
291+
row += 4;
292+
} else {
293+
row += 3;
294+
}
295+
296+
pxl_count++;
297+
}
298+
}
299+
300+
count = 0;
301+
for (i = 0; i < 4; i++) {
302+
int j;
303+
for (j = 0; j < 4; j++) {
304+
int k;
305+
306+
for (k = 0; k < 4; k++) {
307+
/* Count how many bins have more than
308+
1% of the pixels in the histogram */
309+
if (histogram[i][j][k] > pxl_count / 100) {
310+
count++;
311+
}
312+
}
313+
}
314+
}
315+
316+
/* Image is boring if there is only 1 bin with > 1% of pixels */
317+
return count > 1;
318+
}

pinpoint/gst-video-thumbnailer.h

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
/*
2+
* Bickley - a meta data management framework.
3+
* Copyright © 2008 - 2009, Intel Corporation.
4+
*
5+
* This program is free software; you can redistribute it and/or modify it
6+
* under the terms and conditions of the GNU Lesser General Public License,
7+
* version 2.1, as published by the Free Software Foundation.
8+
*
9+
* This program is distributed in the hope it will be useful, but WITHOUT
10+
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11+
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
12+
* more details.
13+
*
14+
* You should have received a copy of the GNU Lesser General Public License
15+
* along with this program; if not, write to the Free Software Foundation,
16+
* Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA
17+
*/
18+
19+
#ifndef __GST_VIDEO_THUMBNAILER_H__
20+
#define __GST_VIDEO_THUMBNAILER_H__
21+
22+
#ifdef HAVE_CONFIG_H
23+
#include "config.h"
24+
#endif
25+
26+
GdkPixbuf * gst_video_thumbnailer_get_shot (const gchar *location, GCancellable *cancellable);
27+
#endif

0 commit comments

Comments
 (0)