11 G_DEFINE_TYPE(Video, video, GTK_TYPE_FRAME);
13 #define video_DECODER "decoder"
14 #define video_COLOR "colorspace"
15 #define video_SCALE "videoscale"
16 #define video_SINK "videosink"
18 gboolean video_save_mpeg(RESULT *res, gchar *file)
20 char binary_data[EB_SIZE_PAGE];
22 EB_Error_Code error_code;
26 BOOK_INFO *binfo = res->binfo;
30 error_code = eb_set_subbook(binfo->book, binfo->subbook_no);
31 if(error_code != EB_SUCCESS)
33 LOG(LOG_CRITICAL, "Failed to set subbook %s, %d : %s", binfo->path, binfo->subbook_no, eb_error_message(error_code));
37 if((error_code = eb_decompose_movie_file_name(argv, res->filename)) != EB_SUCCESS)
40 error_code = eb_set_binary_mpeg(binfo->book, argv);
41 if(error_code != EB_SUCCESS)
43 LOG(LOG_CRITICAL, "Failed to set binary mpeg: %s", eb_error_message(error_code));
47 fp = fopen(file, "wb");
50 LOG(LOG_CRITICAL, "Failed to open file: %s", file);
56 error_code = eb_read_binary(binfo->book, EB_SIZE_PAGE, binary_data, &read_length);
57 if(error_code != EB_SUCCESS || read_length == 0)
62 fwrite(binary_data, read_length, 1, fp);
68 void video_save_as(GtkWidget *w, gpointer data)
70 static gchar *path = NULL;
71 path = app_browse_disk(_("Save Video As"), mainwnd_get_wnd(), GTK_FILE_CHOOSER_ACTION_SAVE, GTK_STOCK_SAVE_AS, path);
74 RESULT *res = (RESULT*)data;
75 if(video_save_mpeg(res, path) != EB_SUCCESS)
76 LOG(LOG_WARNING, _("Failed to save video"));
81 #ifdef ENABLE_GSTREAMER
83 static gpointer video_parent_class_ptr = NULL;
85 static void video_finalize(GObject *obj)
87 g_return_if_fail(obj != NULL);
88 g_return_if_fail(EB_IS_VIDEO(obj));
90 Video *v = video(obj);
91 g_idle_remove_by_data(v->pipeline);
92 gst_element_set_state(v->pipeline, GST_STATE_NULL);
93 gst_object_unref(GST_OBJECT(v->pipeline));
94 G_OBJECT_CLASS(video_parent_class_ptr)->finalize(obj);
97 static void video_play_pause_set_icon(Video *self, gboolean play)
99 GtkWidget *image = gtk_bin_get_child(GTK_BIN(self->btn));
100 gtk_widget_destroy(image);
101 image = gtk_image_new_from_stock(play ? GTK_STOCK_MEDIA_PAUSE : GTK_STOCK_MEDIA_PLAY, GTK_ICON_SIZE_SMALL_TOOLBAR);
102 gtk_button_set_image(GTK_BUTTON(self->btn), image);
105 static void video_play_pause(Video *self, gboolean play)
107 if(self->output->window && self->pipeline)
109 gst_x_overlay_set_xwindow_id(GST_X_OVERLAY(self->sink), GDK_WINDOW_XID(self->output->window));
110 gst_element_set_state(self->pipeline, play ? GST_STATE_PLAYING : GST_STATE_PAUSED);
111 video_play_pause_set_icon(self, play);
115 static gboolean video_pause(gpointer data)
117 Video *v = video(data);
118 video_play_pause(v, FALSE);
122 static gboolean video_reset(gpointer data)
124 Video *v = video(data);
125 video_play_pause(v, TRUE);
126 g_idle_add(video_pause, data);
130 static void video_resize(Video *self, gint w, gint h)
132 GdkScreen *screen = gdk_screen_get_default();
133 gint sw = gdk_screen_get_width(screen), sh = gdk_screen_get_height(screen);
134 if((w > 0) && (h > 0) && (w <= sw) && (h <= sh))
136 gtk_widget_set_size_request(self->output, w, h);
138 GtkWidget *wnd = gtk_widget_get_toplevel(self->output);
139 gtk_widget_set_size_request(wnd, -1, h + 15*GTK_ICON_SIZE_SMALL_TOOLBAR);
141 self->video_resized = TRUE;
145 gboolean video_bus_cb(GstBus *bus, GstMessage *msg, gpointer data)
147 Video *v = video(data);
148 switch (GST_MESSAGE_TYPE(msg))
150 case GST_MESSAGE_STATE_CHANGED:
154 GstState oldstate, newstate;
155 gst_message_parse_state_changed(msg, &oldstate, &newstate, NULL);
156 if(oldstate == GST_STATE_READY && newstate == GST_STATE_PAUSED)
158 gchar *name = gst_element_get_name(msg->src);
159 if(!g_strcmp0(name, video_DECODER))
161 GstPad *pad = gst_element_get_static_pad(GST_ELEMENT(msg->src), "src");
165 gst_video_get_size(pad, &w, &h);
166 video_resize(v, w, h);
173 case GST_MESSAGE_EOS:
175 gst_element_set_state(v->pipeline, GST_STATE_NULL);
176 g_idle_add(video_reset, (gpointer)v);
180 case GST_MESSAGE_ERROR:
185 gst_message_parse_error(msg, &error, &debug);
188 LOG(LOG_INFO, "%s\n", error->message);
200 static gboolean video_timeout(gpointer data)
202 if(!EB_IS_VIDEO(data)) return FALSE;
204 Video *v = video(data);
206 GstFormat format = GST_FORMAT_TIME;
211 if(!GST_IS_ELEMENT(v->pipeline))
214 gst_element_query_position(v->pipeline, &format, &pos);
215 if(format != GST_FORMAT_TIME)
225 sprintf(time, "%.2d:%.2d", mm, ss);
227 sprintf(time, "%.2d:%.2d:%.2d", hh, mm, ss);
229 gtk_label_set_text(GTK_LABEL(v->time), time);
231 gst_x_overlay_expose(GST_X_OVERLAY(v->sink));
236 static void video_output_prepare(Video *self)
238 GstElement *src, *dec, *color, *scale;
240 RESULT *res = render.link;
242 self->pipeline = gst_pipeline_new("pipeline");
243 src = g_object_new(EB_GST_TYPE_SRC, NULL);
244 EB_GST_SRC(src)->res = res;
245 dec = gst_element_factory_make("mpeg2dec", video_DECODER);
246 color = gst_element_factory_make("ffmpegcolorspace", video_COLOR);
247 scale = gst_element_factory_make("videoscale", video_SCALE);
248 self->sink = gst_element_factory_make("ximagesink", video_SINK);
250 gst_bin_add_many(GST_BIN(self->pipeline), src, dec, color, scale, self->sink, NULL);
251 gst_element_link_many(src, dec, color, scale, self->sink, NULL);
253 bus = gst_pipeline_get_bus(GST_PIPELINE(self->pipeline));
254 gst_bus_add_watch(bus, video_bus_cb, (gpointer)self);
255 gst_object_unref(bus);
257 g_timeout_add(500, video_timeout, (gpointer)self);
259 video_reset((gpointer)self);
262 void video_play_pause_cb(GtkWidget *w, gpointer data)
264 Video *v = video(data);
265 GstState state, pending;
266 gst_element_get_state(GST_ELEMENT(v->pipeline), &state, &pending, GST_CLOCK_TIME_NONE);
267 gboolean play = (state != GST_STATE_PLAYING);
268 video_play_pause(v, play);
273 static void video_class_init(VideoClass *klass)
275 #ifdef ENABLE_GSTREAMER
276 GObjectClass *gobject_class = G_OBJECT_CLASS(klass);
277 gobject_class->finalize = video_finalize;
278 video_parent_class_ptr = g_type_class_peek_parent(klass);
282 static void video_init(Video *self)
284 GtkWidget *hbox = NULL;
285 #ifdef ENABLE_GSTREAMER
286 GtkWidget *vbox = gtk_vbox_new(FALSE, 0);
287 gtk_container_add(GTK_CONTAINER(self), vbox);
289 self->output = gtk_drawing_area_new();
290 gtk_box_pack_start(GTK_BOX(vbox), self->output, TRUE, TRUE, 0);
291 gtk_widget_set_size_request(self->output, 320, 240);
292 self->video_resized = FALSE;
294 hbox = gtk_hbox_new(FALSE, 0);
295 gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, TRUE, 0);
297 self->btn = gtk_button_new();
298 GtkWidget *image = gtk_image_new_from_stock(GTK_STOCK_MEDIA_PLAY, GTK_ICON_SIZE_SMALL_TOOLBAR);
299 gtk_button_set_image(GTK_BUTTON(self->btn), image);
300 g_signal_connect(G_OBJECT(self->btn), "clicked", G_CALLBACK(video_play_pause_cb), (gpointer)self);
301 gtk_box_pack_start(GTK_BOX(hbox), self->btn, FALSE, TRUE, 0);
303 self->time = gtk_label_new("");
304 gtk_misc_set_alignment(GTK_MISC(self->time), 1, 0.5);
305 gtk_box_pack_start(GTK_BOX(hbox), self->time, TRUE, TRUE, 0);
307 hbox = gtk_hbox_new(FALSE, 0);
308 gtk_container_add(GTK_CONTAINER(self), hbox);
310 GtkWidget *label = gtk_label_new(_("Video"));
311 gtk_box_pack_start(GTK_BOX(hbox), label, TRUE, TRUE, 0);
313 GtkWidget *btn = gtk_button_new();
314 GtkWidget *img = gtk_image_new_from_stock(GTK_STOCK_SAVE_AS, GTK_ICON_SIZE_SMALL_TOOLBAR);
315 gtk_container_add(GTK_CONTAINER(btn), img);
316 //g_signal_connect(G_OBJECT(btn), "clicked", G_CALLBACK(video_save_as), render.link);
317 gtk_box_pack_start(GTK_BOX(hbox), btn, FALSE, TRUE, 0);
320 void video_render(Video *self)
323 GtkTextIter iter1, iter2;
324 if(render_get_last_mark("mpeg", &iter1, &iter2))
326 gtk_text_buffer_delete(render.buf, &iter1, &iter2);
327 gtk_text_buffer_get_end_iter(render.buf, &iter1);
328 gtk_text_buffer_insert(render.buf, &iter1, "\n", -1);
329 gtk_text_buffer_get_end_iter(render.buf, &iter1);
330 GtkTextChildAnchor *anchor = gtk_text_buffer_create_child_anchor(render.buf, &iter1);
331 gtk_text_view_add_child_at_anchor(GTK_TEXT_VIEW(render.view), GTK_WIDGET(self), anchor);
332 gtk_text_buffer_insert(render.buf, &iter1, "\n", -1);
333 g_object_set_data_full(G_OBJECT(self), "video", render.link, result_free);
334 gtk_widget_show_all(GTK_WIDGET(self));
335 gtk_widget_realize(GTK_WIDGET(self));
336 while(gtk_events_pending())
337 gtk_main_iteration();
338 #ifdef ENABLE_GSTREAMER
339 video_output_prepare(self);