diff options
author | Bastien Nocera <hadess@hadess.net> | 2008-06-10 21:16:49 +0000 |
---|---|---|
committer | Bastien Nocera <hadess@src.gnome.org> | 2008-06-10 21:16:49 +0000 |
commit | 9505320afc41bade135ccf43f113a2317bcdb03a (patch) | |
tree | e4e2408b60eb3742d5b1de91421a70cb0b716560 | |
parent | 6f75c77e5492e34774a05939fae0c3e3caea0175 (diff) | |
download | totem-9505320afc41bade135ccf43f113a2317bcdb03a.tar.gz |
Require gstreamer-tag as well
2008-06-10 Bastien Nocera <hadess@hadess.net>
* configure.in: Require gstreamer-tag as well
* src/backend/bacon-video-widget.h:
* src/backend/bacon-video-widget-gst-0.10.c
(bacon_video_widget_get_metadata_pixbuf),
(bacon_video_widget_get_best_image),
(bacon_video_widget_get_metadata): Add code to read covers from
video and audio files, through the tags
* src/backend/bacon-video-widget-xine.c
(bacon_video_widget_get_metadata): Implement stubs of the above
* src/totem-video-thumbnailer.c (capture_interesting_frame),
(capture_frame_at_time), (has_audio), (on_got_metadata_event),
(main): Implement saving the cover of a video/audio file
(Closes: #318748)
svn path=/trunk/; revision=5462
-rw-r--r-- | ChangeLog | 16 | ||||
-rw-r--r-- | src/backend/bacon-video-widget-gst-0.10.c | 89 | ||||
-rw-r--r-- | src/backend/bacon-video-widget-xine.c | 2 | ||||
-rw-r--r-- | src/backend/bacon-video-widget.h | 1 | ||||
-rw-r--r-- | src/totem-video-thumbnailer.c | 85 |
5 files changed, 175 insertions, 18 deletions
@@ -1,5 +1,21 @@ 2008-06-10 Bastien Nocera <hadess@hadess.net> + * configure.in: Require gstreamer-tag as well + * src/backend/bacon-video-widget.h: + * src/backend/bacon-video-widget-gst-0.10.c + (bacon_video_widget_get_metadata_pixbuf), + (bacon_video_widget_get_best_image), + (bacon_video_widget_get_metadata): Add code to read covers from + video and audio files, through the tags + * src/backend/bacon-video-widget-xine.c + (bacon_video_widget_get_metadata): Implement stubs of the above + * src/totem-video-thumbnailer.c (capture_interesting_frame), + (capture_frame_at_time), (has_audio), (on_got_metadata_event), + (main): Implement saving the cover of a video/audio file + (Closes: #318748) + +2008-06-10 Bastien Nocera <hadess@hadess.net> + * browser-plugin/totem-plugin-viewer.c (on_video_button_press_event): Patch from Baptiste Mille-Mathias <bmm80@free.fr> to add double-click -> fullscreen support diff --git a/src/backend/bacon-video-widget-gst-0.10.c b/src/backend/bacon-video-widget-gst-0.10.c index 3fc529073..5223b7db0 100644 --- a/src/backend/bacon-video-widget-gst-0.10.c +++ b/src/backend/bacon-video-widget-gst-0.10.c @@ -50,6 +50,9 @@ /* for missing decoder/demuxer detection */ #include <gst/pbutils/pbutils.h> +/* for the cover metadata info */ +#include <gst/tag/tag.h> + /* system */ #include <unistd.h> #include <time.h> @@ -4568,6 +4571,67 @@ bvw_process_pending_tag_messages (BaconVideoWidget * bvw) gst_object_unref (bus); } +static GdkPixbuf * +bacon_video_widget_get_metadata_pixbuf (BaconVideoWidget * bvw, + GstBuffer *buffer) +{ + GdkPixbufLoader *loader; + GdkPixbuf *pixbuf; + + loader = gdk_pixbuf_loader_new (); + if (!gdk_pixbuf_loader_write (loader, buffer->data, buffer->size, NULL)) { + g_object_unref (loader); + return NULL; + } + if (!gdk_pixbuf_loader_close (loader, NULL)) { + g_object_unref (loader); + return NULL; + } + + pixbuf = gdk_pixbuf_loader_get_pixbuf (loader); + if (pixbuf) + g_object_ref (pixbuf); + g_object_unref (loader); + return pixbuf; +} + +static const GValue * +bacon_video_widget_get_best_image (BaconVideoWidget *bvw) +{ + const GValue *cover_value; + guint i; + + for (i = 0; ; i++) { + const GValue *value; + GstBuffer *buffer; + GstStructure *caps_struct; + int type; + + value = gst_tag_list_get_value_index (bvw->priv->tagcache, + GST_TAG_IMAGE, + i); + if (value == NULL) + break; + + buffer = gst_value_get_buffer (value); + + caps_struct = gst_caps_get_structure (buffer->caps, 0); + gst_structure_get_enum (caps_struct, + "image-type", + GST_TYPE_TAG_IMAGE_TYPE, + &type); + if (type == GST_TAG_IMAGE_TYPE_UNDEFINED) { + if (cover_value == NULL) + cover_value = value; + } else if (type == GST_TAG_IMAGE_TYPE_FRONT_COVER) { + cover_value = value; + break; + } + } + + return cover_value; +} + void bacon_video_widget_get_metadata (BaconVideoWidget * bvw, BaconVideoWidgetMetadataType type, @@ -4603,6 +4667,31 @@ bacon_video_widget_get_metadata (BaconVideoWidget * bvw, case BVW_INFO_HAS_AUDIO: bacon_video_widget_get_metadata_bool (bvw, type, value); break; + case BVW_INFO_COVER: + { + const GValue *cover_value; + + g_value_init (value, GDK_TYPE_PIXBUF); + + if (bvw->priv->tagcache == NULL) + break; + cover_value = bacon_video_widget_get_best_image (bvw); + if (!cover_value) { + cover_value = gst_tag_list_get_value_index (bvw->priv->tagcache, + GST_TAG_PREVIEW_IMAGE, + 0); + } + if (cover_value) { + GstBuffer *buffer; + GdkPixbuf *pixbuf; + + buffer = gst_value_get_buffer (cover_value); + pixbuf = bacon_video_widget_get_metadata_pixbuf (bvw, buffer); + if (pixbuf) + g_value_take_object (value, pixbuf); + } + } + break; default: g_return_if_reached (); } diff --git a/src/backend/bacon-video-widget-xine.c b/src/backend/bacon-video-widget-xine.c index fb19d5ed3..fdd406de4 100644 --- a/src/backend/bacon-video-widget-xine.c +++ b/src/backend/bacon-video-widget-xine.c @@ -4032,6 +4032,8 @@ bacon_video_widget_get_metadata (BaconVideoWidget *bvw, case BVW_INFO_HAS_AUDIO: bacon_video_widget_get_metadata_bool (bvw, type, value); break; + case BVW_INFO_COVER: + break; default: g_assert_not_reached (); } diff --git a/src/backend/bacon-video-widget.h b/src/backend/bacon-video-widget.h index e5ee77f86..50bc2c45b 100644 --- a/src/backend/bacon-video-widget.h +++ b/src/backend/bacon-video-widget.h @@ -199,6 +199,7 @@ typedef enum { BVW_INFO_ALBUM, BVW_INFO_DURATION, BVW_INFO_TRACK_NUMBER, + BVW_INFO_COVER, /* Video */ BVW_INFO_HAS_VIDEO, BVW_INFO_DIMENSION_X, diff --git a/src/totem-video-thumbnailer.c b/src/totem-video-thumbnailer.c index b9fcf2399..5b3765fc5 100644 --- a/src/totem-video-thumbnailer.c +++ b/src/totem-video-thumbnailer.c @@ -57,6 +57,11 @@ static gboolean g_fatal_warnings = FALSE; static gint64 second_index = -1; static char **filenames = NULL; +typedef struct { + const char *output; + const char *input; +} callback_data; + #ifdef THUMB_DEBUG static void show_pixbuf (GdkPixbuf *pix) @@ -326,7 +331,9 @@ save_pixbuf (GdkPixbuf *pixbuf, const char *path, } static GdkPixbuf * -capture_interesting_frame (BaconVideoWidget * bvw, char *input, char *output) +capture_interesting_frame (BaconVideoWidget *bvw, + const char *input, + const char *output) { GdkPixbuf* pixbuf; guint current; @@ -343,9 +350,9 @@ capture_interesting_frame (BaconVideoWidget * bvw, char *input, char *output) * interesting frame */ for (current = 0; current < G_N_ELEMENTS(frame_locations); current++) { - PROGRESS_DEBUG("About to seek to %f\n", frame_locations[current]); + PROGRESS_DEBUG("About to seek to %f", frame_locations[current]); if (bacon_video_widget_seek (bvw, frame_locations[current], NULL) == FALSE) { - PROGRESS_DEBUG("Couldn't seek to %f\n", frame_locations[current]); + PROGRESS_DEBUG("Couldn't seek to %f", frame_locations[current]); bacon_video_widget_play (bvw, NULL); } @@ -362,10 +369,10 @@ capture_interesting_frame (BaconVideoWidget * bvw, char *input, char *output) } /* Pull the frame, if it's interesting we bail early */ - PROGRESS_DEBUG("About to get frame for iter %d\n", current); + PROGRESS_DEBUG("About to get frame for iter %d", current); pixbuf = bacon_video_widget_get_current_frame (bvw); if (pixbuf != NULL && is_image_interesting (pixbuf) != FALSE) { - PROGRESS_DEBUG("Frame for iter %d is interesting\n", current); + PROGRESS_DEBUG("Frame for iter %d is interesting", current); break; } @@ -377,13 +384,16 @@ capture_interesting_frame (BaconVideoWidget * bvw, char *input, char *output) pixbuf = NULL; } } - PROGRESS_DEBUG("Frame for iter %d was not interesting\n", current); + PROGRESS_DEBUG("Frame for iter %d was not interesting", current); } return pixbuf; } static GdkPixbuf * -capture_frame_at_time(BaconVideoWidget *bvw, char *input, char *output, gint64 seconds) +capture_frame_at_time(BaconVideoWidget *bvw, + const char *input, + const char *output, + gint64 seconds) { GError *err = NULL; @@ -412,6 +422,42 @@ capture_frame_at_time(BaconVideoWidget *bvw, char *input, char *output, gint64 return bacon_video_widget_get_current_frame (bvw); } +static gboolean +has_audio (BaconVideoWidget *bvw) +{ + GValue value = { 0, }; + + bacon_video_widget_get_metadata (bvw, BVW_INFO_HAS_VIDEO, &value); + return g_value_get_boolean (&value); +} + +static void +on_got_metadata_event (BaconVideoWidget *bvw, callback_data *data) +{ + GValue value = { 0, }; + GdkPixbuf *pixbuf; + + PROGRESS_DEBUG("Got metadata, checking if we have a cover"); + bacon_video_widget_get_metadata (bvw, BVW_INFO_COVER, &value); + pixbuf = g_value_get_object (&value); + + if (pixbuf) { + PROGRESS_DEBUG("Saving cover image"); + + bacon_video_widget_close (bvw); + totem_resources_monitor_stop (); + gtk_widget_destroy (GTK_WIDGET (bvw)); + + save_pixbuf (pixbuf, data->output, data->input, output_size, TRUE); + g_object_unref (pixbuf); + + exit (0); + } else if (has_audio (bvw) == FALSE) { + PROGRESS_DEBUG("No covers, and no video, exiting"); + exit (0); + } +} + static const GOptionEntry entries[] = { { "jpeg", 'j', 0, G_OPTION_ARG_NONE, &jpeg_output, "Output the thumbnail as a JPEG instead of PNG", NULL }, { "size", 's', 0, G_OPTION_ARG_INT, &output_size, "Size of the thumbnail in pixels", NULL }, @@ -432,7 +478,8 @@ int main (int argc, char *argv[]) GError *err = NULL; BaconVideoWidget *bvw; GdkPixbuf *pixbuf; - char *input, *output; + const char *input, *output; + callback_data data; #ifdef G_OS_UNIX nice (20); @@ -456,7 +503,6 @@ int main (int argc, char *argv[]) return 1; } -#ifndef THUMB_DEBUG if (g_fatal_warnings) { GLogLevelFlags fatal_mask; @@ -464,7 +510,6 @@ int main (int argc, char *argv[]) fatal_mask |= G_LOG_LEVEL_WARNING | G_LOG_LEVEL_CRITICAL; g_log_set_always_fatal (fatal_mask); } -#endif /* THUMB_DEBUG */ if (filenames == NULL || g_strv_length (filenames) != 2) { char *help; @@ -476,7 +521,7 @@ int main (int argc, char *argv[]) input = filenames[0]; output = filenames[1]; - PROGRESS_DEBUG("Initialised libraries, about to create video widget\n"); + PROGRESS_DEBUG("Initialised libraries, about to create video widget"); bvw = BACON_VIDEO_WIDGET (bacon_video_widget_new (-1, -1, BVW_USE_TYPE_CAPTURE, &err)); if (err != NULL) { @@ -485,13 +530,18 @@ int main (int argc, char *argv[]) g_error_free (err); exit (1); } + data.input = input; + data.output = output; + g_signal_connect (G_OBJECT (bvw), "got-metadata", + G_CALLBACK (on_got_metadata_event), + &data); - PROGRESS_DEBUG("Video widget created\n"); + PROGRESS_DEBUG("Video widget created"); if (time_limit != FALSE) totem_resources_monitor_start (input, 0); - PROGRESS_DEBUG("About to open video file\n"); + PROGRESS_DEBUG("About to open video file"); if (bacon_video_widget_open (bvw, input, &err) == FALSE) { g_print ("totem-video-thumbnailer couldn't open file '%s'\n" @@ -501,8 +551,8 @@ int main (int argc, char *argv[]) exit (1); } - PROGRESS_DEBUG("Opened video file: '%s'\n", input); - PROGRESS_DEBUG("About to play file\n"); + PROGRESS_DEBUG("Opened video file: '%s'", input); + PROGRESS_DEBUG("About to play file"); bacon_video_widget_play (bvw, &err); if (err != NULL) { @@ -511,8 +561,7 @@ int main (int argc, char *argv[]) g_error_free (err); exit (1); } - - PROGRESS_DEBUG("Started playing file\n"); + PROGRESS_DEBUG("Started playing file"); /* If the user has told us to use a frame at a specific second * into the video, just use that frame no matter how boring it @@ -533,7 +582,7 @@ int main (int argc, char *argv[]) exit (1); } - PROGRESS_DEBUG("Saving captured screenshot\n"); + PROGRESS_DEBUG("Saving captured screenshot"); save_pixbuf (pixbuf, output, input, output_size, FALSE); g_object_unref (pixbuf); |