2
* Copyright (C) 2007 Copyright (C) 2007 daniel g. siegel <dgsiegel@gmail.com>
4
* Licensed under the GNU General Public License Version 2
6
* This program is free software; you can redistribute it and/or modify
7
* it under the terms of the GNU General Public License as published by
8
* the Free Software Foundation; either version 2 of the License, or
9
* (at your option) any later version.
11
* This program is distributed in the hope that it will be useful,
12
* but WITHOUT ANY WARRANTY; without even the implied warranty of
13
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
* GNU General Public License for more details.
16
* You should have received a copy of the GNU General Public License
17
* along with this program. If not, see <http://www.gnu.org/licenses/>.
20
#include "cheese-config.h"
22
#include <gst/interfaces/xoverlay.h>
24
#include <glib/gi18n.h>
26
#include <libgnomevfs/gnome-vfs.h>
29
#include "cheese-window.h"
30
#include "cheese-pipeline-video.h"
31
#include "cheese-effects-widget.h"
32
#include "cheese-fileutil.h"
33
#include "cheese-thumbnails.h"
35
G_DEFINE_TYPE(PipelineVideo, cheese_pipeline_video, G_TYPE_OBJECT)
37
static GObjectClass *parent_class = NULL;
39
typedef struct _PipelineVideoPrivate PipelineVideoPrivate;
41
struct _PipelineVideoPrivate
44
gchar *source_pipeline;
48
GstElement *pipeline, *pipeline_rec;
49
GstElement *ximagesink, *ximagesink_rec;
50
GstElement *fakesink, *fakesink_rec;
53
GstElement *ffmpeg1, *ffmpeg2, *ffmpeg3;
54
GstElement *ffmpeg1_rec, *ffmpeg2_rec, *ffmpeg3_rec, *ffmpeg4_rec;
55
GstElement *tee, *tee_rec;
56
GstElement *queuedisplay, *queuedisplay_rec, *queuemovie;
57
GstElement *effect, *effect_rec;
59
GstElement *audioconvert;
60
GstElement *vorbisenc;
63
GstElement *theoraenc;
64
GstElement *videorate;
65
GstElement *videoscale;
66
GstCaps *filter, *filter_rec;
69
#define PIPELINE_VIDEO_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), PIPELINE_VIDEO_TYPE, PipelineVideoPrivate))
72
static void cheese_pipeline_video_create_display(PipelineVideo *self);
73
static void cheese_pipeline_video_create_rec(PipelineVideo *self);
76
cheese_pipeline_video_finalize(GObject *object)
78
PipelineVideoPrivate *priv = PIPELINE_VIDEO_GET_PRIVATE(object);
79
gst_caps_unref(priv->filter);
81
(*parent_class->finalize) (object);
86
cheese_pipeline_video_new(void)
88
PipelineVideo *self = g_object_new(PIPELINE_VIDEO_TYPE, NULL);
94
cheese_pipeline_video_class_init(PipelineVideoClass *klass)
96
GObjectClass *object_class;
98
parent_class = g_type_class_peek_parent(klass);
99
object_class = (GObjectClass*) klass;
101
object_class->finalize = cheese_pipeline_video_finalize;
102
g_type_class_add_private(klass, sizeof(PipelineVideoPrivate));
104
G_OBJECT_CLASS(klass)->finalize = (GObjectFinalizeFunc) cheese_pipeline_video_finalize;
108
cheese_pipeline_video_init(PipelineVideo *self)
113
cheese_pipeline_video_set_play(PipelineVideo *self)
115
PipelineVideoPrivate *priv = PIPELINE_VIDEO_GET_PRIVATE(self);
117
gst_element_set_state(priv->pipeline_rec, GST_STATE_PLAYING);
119
gst_element_set_state(priv->pipeline, GST_STATE_PLAYING);
124
cheese_pipeline_video_set_stop(PipelineVideo *self)
126
PipelineVideoPrivate *priv = PIPELINE_VIDEO_GET_PRIVATE(self);
128
gst_element_set_state(priv->pipeline_rec, GST_STATE_NULL);
130
gst_element_set_state(priv->pipeline, GST_STATE_NULL);
135
cheese_pipeline_video_button_clicked(GtkWidget *widget, gpointer self)
137
PipelineVideoPrivate *priv = PIPELINE_VIDEO_GET_PRIVATE(self);
139
cheese_pipeline_video_set_stop(self);
140
priv->lens_open = !priv->lens_open;
141
if (priv->lens_open) {
142
gtk_widget_set_sensitive(GTK_WIDGET(cheese_window.widgets.button_effects), FALSE);
143
gtk_label_set_text_with_mnemonic(GTK_LABEL(cheese_window.widgets.label_take_photo), _("<b>_Stop recording</b>"));
144
gtk_label_set_use_markup(GTK_LABEL(cheese_window.widgets.label_take_photo), TRUE);
145
gtk_image_set_from_stock(GTK_IMAGE(cheese_window.widgets.image_take_photo), GTK_STOCK_MEDIA_STOP, GTK_ICON_SIZE_BUTTON);
147
gtk_widget_set_sensitive(GTK_WIDGET(cheese_window.widgets.button_effects), TRUE);
148
gtk_label_set_text_with_mnemonic(GTK_LABEL(cheese_window.widgets.label_take_photo), _("<b>_Start recording</b>"));
149
gtk_label_set_use_markup(GTK_LABEL(cheese_window.widgets.label_take_photo), TRUE);
150
gtk_image_set_from_stock(GTK_IMAGE(cheese_window.widgets.image_take_photo), GTK_STOCK_MEDIA_RECORD, GTK_ICON_SIZE_BUTTON);
152
g_print("Video saved: %s\n", priv->filename);
153
cheese_thumbnails_append_item(priv->filename);
154
priv->filename = cheese_fileutil_get_video_filename();
156
g_object_set(priv->filesink, "location", priv->filename, NULL);
158
// we have to create a new instance of oggmux, as
159
// it is waiting for an EOS signal otherwise
160
gst_element_unlink(priv->theoraenc, priv->oggmux);
161
gst_element_unlink(priv->vorbisenc, priv->oggmux);
162
gst_element_unlink(priv->oggmux, priv->filesink);
164
gst_bin_remove(GST_BIN(priv->pipeline_rec), priv->oggmux);
165
priv->oggmux = gst_element_factory_make("oggmux", "oggmux");
166
gst_bin_add(GST_BIN(priv->pipeline_rec), priv->oggmux);
168
gst_element_link(priv->theoraenc, priv->oggmux);
169
gst_element_link(priv->vorbisenc, priv->oggmux);
170
gst_element_link(priv->oggmux, priv->filesink);
173
// gst_element_set_state(priv->pipeline_rec, GST_STATE_READY);
174
cheese_pipeline_video_set_play(self);
179
cheese_pipeline_video_get_ximagesink(PipelineVideo *self)
181
PipelineVideoPrivate *priv = PIPELINE_VIDEO_GET_PRIVATE(self);
182
return priv->ximagesink;
186
cheese_pipeline_video_get_fakesink(PipelineVideo *self)
188
PipelineVideoPrivate *priv = PIPELINE_VIDEO_GET_PRIVATE(self);
189
return priv->fakesink;
193
cheese_pipeline_video_get_pipeline(PipelineVideo *self)
195
PipelineVideoPrivate *priv = PIPELINE_VIDEO_GET_PRIVATE(self);
196
return priv->lens_open ? priv->pipeline_rec : priv->pipeline;
200
cheese_pipeline_video_change_effect(gchar *effect, gpointer self)
202
PipelineVideoPrivate *priv = PIPELINE_VIDEO_GET_PRIVATE(self);
204
if (effect != NULL) {
205
cheese_pipeline_video_set_stop(PIPELINE_VIDEO(self));
207
gst_element_unlink(priv->ffmpeg1, priv->effect);
208
gst_element_unlink(priv->effect, priv->ffmpeg2);
209
gst_bin_remove(GST_BIN(priv->pipeline), priv->effect);
211
gst_element_unlink(priv->ffmpeg1_rec, priv->effect_rec);
212
gst_element_unlink(priv->effect_rec, priv->ffmpeg2_rec);
213
gst_bin_remove(GST_BIN(priv->pipeline_rec), priv->effect_rec);
215
g_print("changing to effect: %s\n", effect);
216
priv->effect = gst_parse_bin_from_description(effect, TRUE, NULL);
217
priv->effect_rec = gst_parse_bin_from_description(effect, TRUE, NULL);
219
gst_bin_add(GST_BIN(priv->pipeline_rec), priv->effect_rec);
220
gst_bin_add(GST_BIN(priv->pipeline), priv->effect);
222
gst_element_link(priv->ffmpeg1, priv->effect);
223
gst_element_link(priv->effect, priv->ffmpeg2);
225
gst_element_link(priv->ffmpeg1_rec, priv->effect_rec);
226
gst_element_link(priv->effect_rec, priv->ffmpeg2_rec);
228
cheese_pipeline_video_set_play(self);
229
priv->used_effect = effect;
234
cheese_pipeline_video_create(gchar *source_pipeline, PipelineVideo *self) {
236
PipelineVideoPrivate *priv = PIPELINE_VIDEO_GET_PRIVATE(self);
237
priv->source_pipeline = source_pipeline;
238
cheese_pipeline_video_create_display(self);
239
cheese_pipeline_video_create_rec(self);
243
cheese_pipeline_video_create_display(PipelineVideo *self) {
245
PipelineVideoPrivate *priv = PIPELINE_VIDEO_GET_PRIVATE(self);
248
priv->pipeline = gst_pipeline_new("pipeline");
249
priv->source = gst_parse_bin_from_description(priv->source_pipeline, TRUE, NULL);
250
gst_bin_add(GST_BIN(priv->pipeline), priv->source);
252
priv->ffmpeg1 = gst_element_factory_make("ffmpegcolorspace", "ffmpegcolorspace");
253
gst_bin_add(GST_BIN(priv->pipeline), priv->ffmpeg1);
255
priv->effect = gst_element_factory_make("identity", "effect");
256
gst_bin_add(GST_BIN(priv->pipeline), priv->effect);
258
priv->ffmpeg2 = gst_element_factory_make("ffmpegcolorspace", "ffmpegcolorspace2");
259
gst_bin_add(GST_BIN(priv->pipeline), priv->ffmpeg2);
261
priv->ffmpeg3 = gst_element_factory_make("ffmpegcolorspace", "ffmpegcolorspace3");
262
gst_bin_add(GST_BIN(priv->pipeline), priv->ffmpeg3);
264
priv->tee = gst_element_factory_make("tee", "tee");
265
gst_bin_add(GST_BIN(priv->pipeline), priv->tee);
267
priv->queuedisplay = gst_element_factory_make("queue", "queuedisplay");
268
gst_bin_add(GST_BIN(priv->pipeline), priv->queuedisplay);
270
priv->ximagesink = gst_element_factory_make("gconfvideosink", "gconfvideosink");
271
gst_bin_add(GST_BIN(priv->pipeline), priv->ximagesink);
273
gst_element_link(priv->source, priv->ffmpeg1);
274
gst_element_link(priv->ffmpeg1, priv->effect);
275
gst_element_link(priv->effect, priv->ffmpeg2);
277
// theoraenc needs raw yuv data...
278
priv->filter = gst_caps_new_simple("video/x-raw-yuv", NULL);
279
link_ok = gst_element_link_filtered(priv->ffmpeg2, priv->tee, priv->filter);
281
g_warning("Failed to link elements!");
284
gst_element_link(priv->tee, priv->queuedisplay);
285
gst_element_link(priv->queuedisplay, priv->ffmpeg3);
287
gst_element_link(priv->ffmpeg3, priv->ximagesink);
291
cheese_pipeline_video_create_rec(PipelineVideo *self) {
293
PipelineVideoPrivate *priv = PIPELINE_VIDEO_GET_PRIVATE(self);
296
priv->pipeline_rec = gst_pipeline_new("pipeline");
297
priv->source = gst_parse_bin_from_description(priv->source_pipeline, TRUE, NULL);
298
gst_bin_add(GST_BIN(priv->pipeline_rec), priv->source);
300
priv->ffmpeg1_rec = gst_element_factory_make("ffmpegcolorspace", "ffmpegcolorspace_rec");
301
gst_bin_add(GST_BIN(priv->pipeline_rec), priv->ffmpeg1_rec);
303
priv->effect_rec = gst_element_factory_make("identity", "effect_rec");
304
gst_bin_add(GST_BIN(priv->pipeline_rec), priv->effect_rec);
306
priv->ffmpeg2_rec = gst_element_factory_make("ffmpegcolorspace", "ffmpegcolorspace2_rec");
307
gst_bin_add(GST_BIN(priv->pipeline_rec), priv->ffmpeg2_rec);
309
priv->ffmpeg3_rec = gst_element_factory_make("ffmpegcolorspace", "ffmpegcolorspace3_rec");
310
gst_bin_add(GST_BIN(priv->pipeline_rec), priv->ffmpeg3_rec);
312
priv->ffmpeg4_rec = gst_element_factory_make("ffmpegcolorspace", "ffmpegcolorspace4_rec");
313
gst_bin_add(GST_BIN(priv->pipeline_rec), priv->ffmpeg4_rec);
315
priv->tee_rec = gst_element_factory_make("tee", "tee_rec");
316
gst_bin_add(GST_BIN(priv->pipeline_rec), priv->tee_rec);
318
priv->videorate = gst_element_factory_make("videorate", "videorate");
319
gst_bin_add(GST_BIN(priv->pipeline_rec), priv->videorate);
321
priv->videoscale = gst_element_factory_make("videoscale", "videoscale");
322
gst_bin_add(GST_BIN(priv->pipeline_rec), priv->videoscale);
324
priv->queuedisplay_rec = gst_element_factory_make("queue", "queuedisplay_rec");
325
gst_bin_add(GST_BIN(priv->pipeline_rec), priv->queuedisplay_rec);
327
priv->ximagesink_rec = gst_element_factory_make("gconfvideosink", "gconfvideosink_rec");
328
gst_bin_add(GST_BIN(priv->pipeline_rec), priv->ximagesink_rec);
331
* the pipeline looks like this:
332
* v4l(2)src -> ffmpegcsp
334
* '-> ffmpegcsp -> effects -> ffmpegcsp
335
* -------------------------------------------------------'
336
* '--> tee (filtered) -> queue-> ffmpegcsp -> gconfvideosink
340
* queuemovie -------,
341
* |--------> mux -> filesink
348
gst_element_link(priv->source, priv->videoscale);
349
priv->filter_rec = gst_caps_new_simple("video/x-raw-yuv",
350
"width", G_TYPE_INT, 320,
351
"height", G_TYPE_INT, 240, NULL);
352
link_ok = gst_element_link_filtered(priv->videoscale, priv->videorate, priv->filter_rec);
354
g_warning("Failed to link elements!");
356
priv->filter_rec = gst_caps_new_simple("video/x-raw-yuv", "framerate", GST_TYPE_FRACTION, 15, 1, NULL);
357
link_ok = gst_element_link_filtered(priv->videorate, priv->ffmpeg1_rec, priv->filter_rec);
359
g_warning("Failed to link elements!");
361
gst_element_link(priv->ffmpeg1_rec, priv->effect_rec);
362
gst_element_link(priv->effect_rec, priv->ffmpeg2_rec);
363
//gst_element_link(priv->ffmpeg2, priv->tee);
365
gst_element_link(priv->ffmpeg2_rec, priv->tee_rec);
367
gst_element_link(priv->tee_rec, priv->queuedisplay_rec);
368
gst_element_link(priv->queuedisplay_rec, priv->ffmpeg3_rec);
370
gst_element_link(priv->ffmpeg3_rec, priv->ximagesink_rec);
372
priv->audiosrc = gst_element_factory_make("gconfaudiosrc", "gconfaudiosrc");
373
gst_bin_add(GST_BIN(priv->pipeline_rec), priv->audiosrc);
375
priv->audioconvert = gst_element_factory_make("audioconvert", "audioconvert");
376
gst_bin_add(GST_BIN(priv->pipeline_rec), priv->audioconvert);
378
priv->vorbisenc = gst_element_factory_make("vorbisenc", "vorbisenc");
379
gst_bin_add(GST_BIN(priv->pipeline_rec), priv->vorbisenc);
381
priv->oggmux = gst_element_factory_make("oggmux", "oggmux");
382
gst_bin_add(GST_BIN(priv->pipeline_rec), priv->oggmux);
384
priv->filesink = gst_element_factory_make("filesink", "filesink");
385
gst_bin_add(GST_BIN(priv->pipeline_rec), priv->filesink);
386
priv->filename = cheese_fileutil_get_video_filename();
387
g_object_set(priv->filesink, "location", priv->filename, NULL);
389
priv->theoraenc = gst_element_factory_make("theoraenc", "theoraenc");
390
gst_bin_add(GST_BIN(priv->pipeline_rec), priv->theoraenc);
392
priv->queuemovie = gst_element_factory_make("queue", "queuemovie");
393
gst_bin_add(GST_BIN(priv->pipeline_rec), priv->queuemovie);
395
//gst_element_link(priv->tee_rec, priv->ffmpeg4_rec);
396
gst_element_link(priv->tee_rec, priv->queuemovie);
397
gst_element_link(priv->queuemovie, priv->ffmpeg4_rec);
399
// theoraenc needs raw yuv data...
400
priv->filter_rec = gst_caps_new_simple("video/x-raw-yuv", NULL);
401
//priv->filter_rec = gst_caps_new_simple("video/x-raw-yuv", "framerate", GST_TYPE_FRACTION, 15, 1, NULL);
402
link_ok = gst_element_link_filtered(priv->ffmpeg4_rec, priv->theoraenc, priv->filter_rec);
404
g_warning("Failed to link elements!");
406
//gst_element_link(priv->queuemovie, priv->theoraenc);
408
gst_element_link(priv->theoraenc, priv->oggmux);
410
priv->filter = gst_caps_new_simple("audio/x-raw-int",
411
"channels", G_TYPE_INT, 2,
412
"rate", G_TYPE_INT, 32000,
413
"depth", G_TYPE_INT, 16, NULL);
415
gst_element_link(priv->audiosrc, priv->audioconvert);
416
//link_ok = gst_element_link_filtered(priv->audiosrc, priv->audioconvert, priv->filter);
417
//link_ok = gst_element_link_filtered(priv->audioconvert, priv->vorbisenc, priv->filter);
419
// g_warning("Failed to link elements!");
422
gst_element_link(priv->audioconvert, priv->vorbisenc);
423
gst_element_link(priv->vorbisenc, priv->oggmux);
424
gst_element_link(priv->oggmux, priv->filesink);