2010-10-17 19:36:39 +00:00
|
|
|
/* GStreamer media browser
|
|
|
|
* Copyright (C) 2010 Stefan Sauer <ensonic@user.sf.net>
|
|
|
|
*
|
|
|
|
* This library is free software; you can redistribute it and/or
|
|
|
|
* modify it under the terms of the GNU Library General Public
|
|
|
|
* License as published by the Free Software Foundation; either
|
|
|
|
* version 2 of the License, or (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This library is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
* Library General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU Library General Public
|
|
|
|
* License along with this library; if not, write to the
|
|
|
|
* Free Software Foundation, Inc., 51 Franklin Steet,
|
|
|
|
* Boston, MA 02110-1301, USA.
|
|
|
|
*/
|
|
|
|
|
|
|
|
using Gtk;
|
2010-10-17 20:21:16 +00:00
|
|
|
using Gst;
|
2010-11-05 15:17:16 +00:00
|
|
|
using Gee;
|
2010-10-17 19:36:39 +00:00
|
|
|
|
2010-10-18 14:14:46 +00:00
|
|
|
/*
|
|
|
|
we need to update the vapi for yet unreleased gstreamer api:
|
|
|
|
|
|
|
|
cd vala/mediainfo/vapi
|
2010-10-18 19:50:02 +00:00
|
|
|
vala-gen-introspect gstreamer-pbutils-0.10 packages/gstreamer-pbutils-0.10
|
|
|
|
vapigen --vapidir . --library gstreamer-pbutils-0.10 packages/gstreamer-pbutils-0.10/gstreamer-pbutils-0.10.gi
|
2010-11-04 10:47:14 +00:00
|
|
|
git diff packages/gstreamer-pbutils-0.10/gstreamer-pbutils-0.10.metadata >vapi.gstreamer-pbutils-0.10.patch
|
2010-10-26 23:02:15 +00:00
|
|
|
# suse
|
2010-10-19 21:44:18 +00:00
|
|
|
sudo cp gstreamer-pbutils-0.10.vapi /usr/share/vala/mediainfo/vapi/
|
2010-10-26 23:02:15 +00:00
|
|
|
# ubuntu
|
|
|
|
sudo cp gstreamer-pbutils-0.10.vapi /usr/share/vala-0.10/vapi/
|
2010-10-18 14:14:46 +00:00
|
|
|
*/
|
|
|
|
|
2010-12-21 10:01:40 +00:00
|
|
|
public class MediaInfo.Info : VPaned
|
2010-10-17 19:36:39 +00:00
|
|
|
{
|
2010-10-18 19:50:02 +00:00
|
|
|
// ui components
|
2010-11-03 08:01:04 +00:00
|
|
|
private Label container_name;
|
2010-10-18 19:50:02 +00:00
|
|
|
private Label mime_type;
|
|
|
|
private Label duration;
|
2010-11-03 08:33:43 +00:00
|
|
|
private Image icon_image;
|
2010-10-19 21:44:18 +00:00
|
|
|
private Notebook video_streams;
|
|
|
|
private Notebook audio_streams;
|
2010-10-17 20:52:37 +00:00
|
|
|
private DrawingArea drawing_area;
|
2010-10-18 19:50:02 +00:00
|
|
|
// gstreamer objects
|
|
|
|
private Discoverer dc;
|
2010-10-17 20:52:37 +00:00
|
|
|
private Pipeline pb;
|
2010-11-03 08:47:04 +00:00
|
|
|
private bool have_video = false;
|
2010-10-17 19:36:39 +00:00
|
|
|
|
2010-11-05 15:17:16 +00:00
|
|
|
private HashMap<string, string> resolutions;
|
2010-11-08 09:40:06 +00:00
|
|
|
private HashSet<string> tag_black_list;
|
2011-01-12 08:17:56 +00:00
|
|
|
private HashMap<string, string> wikilinks;
|
2010-11-05 15:17:16 +00:00
|
|
|
|
2010-10-17 19:36:39 +00:00
|
|
|
public Info ()
|
|
|
|
{
|
2010-10-18 14:38:32 +00:00
|
|
|
Label label;
|
2010-10-18 19:50:02 +00:00
|
|
|
Table table;
|
|
|
|
AttachOptions fill = AttachOptions.FILL;
|
|
|
|
AttachOptions fill_exp = AttachOptions.EXPAND|AttachOptions.FILL;
|
|
|
|
uint row = 0;
|
2010-10-18 14:38:32 +00:00
|
|
|
|
2010-10-17 20:21:16 +00:00
|
|
|
// configure the view
|
2010-12-21 10:01:40 +00:00
|
|
|
set_border_width (0);
|
2010-10-17 19:36:39 +00:00
|
|
|
|
2010-11-05 15:17:16 +00:00
|
|
|
// setup lookup tables
|
|
|
|
// video resolutions: http://upload.wikimedia.org/wikipedia/mediainfo/commons/e/e5/Vector_Video_Standards2.svg
|
|
|
|
// FIXME: these are only for PAR = 1:1
|
|
|
|
// we could have another list for CIF (http://en.wikipedia.org/wiki/Common_Intermediate_Format)
|
|
|
|
resolutions = new HashMap<string, string> ();
|
|
|
|
// 5:4
|
|
|
|
resolutions["1280 x 1024"] = "SXGA";
|
|
|
|
resolutions["2560 x 2048"] = "QSXGA";
|
|
|
|
// 4:3
|
|
|
|
resolutions["320 x 240"] = "QVGA";
|
|
|
|
resolutions["640 x 480"] = "VGA";
|
|
|
|
resolutions["768 x 576"] = "PAL";
|
|
|
|
resolutions["800 x 600"] = "SVGA";
|
|
|
|
resolutions["1024 x 768"] = "XGA";
|
|
|
|
resolutions["1400 x 1050"] = "SXGA+";
|
|
|
|
resolutions["1600 x 1200"] = "UXGA";
|
|
|
|
resolutions["2048 x 1536"] = "QXGA";
|
|
|
|
// 8:5 (16:10)
|
|
|
|
resolutions["320 x 200"] = "CGA";
|
|
|
|
resolutions["1280 x 800"] = "WXGA";
|
|
|
|
resolutions["1680 x 1050"] = "WXGA+";
|
|
|
|
resolutions["1920 x 1200"] = "WUXGA";
|
|
|
|
// 5:3
|
|
|
|
resolutions["800 x 480"] = "WVGA";
|
|
|
|
resolutions["1280 x 768"] = "WXGA";
|
|
|
|
// 16:9
|
|
|
|
resolutions["854 x 480"] = "WVGA";
|
|
|
|
resolutions["1280 x 720"] = "HD 720";
|
|
|
|
resolutions["1920 x 1080"] = "HD 1080";
|
|
|
|
|
2010-11-08 09:40:06 +00:00
|
|
|
// tags to skip (already extraced to specific discoverer fields)
|
|
|
|
tag_black_list = new HashSet<string> ();
|
|
|
|
tag_black_list.add ("bitrate");
|
|
|
|
tag_black_list.add ("container-format");
|
2010-11-08 09:52:11 +00:00
|
|
|
tag_black_list.add ("duration");
|
2010-12-21 11:21:34 +00:00
|
|
|
tag_black_list.add ("nominal-bitrate");
|
2010-11-08 09:52:11 +00:00
|
|
|
tag_black_list.add ("maximum-bitrate");
|
2011-01-12 08:17:56 +00:00
|
|
|
|
|
|
|
// map from media-type to wikipedia-articles, prefix with http://en.wikipedia.org/wiki/
|
|
|
|
// TODO: add more
|
|
|
|
wikilinks = new HashMap<string, string> ();
|
2011-01-13 07:15:04 +00:00
|
|
|
// container/tag formats
|
2011-01-12 08:17:56 +00:00
|
|
|
wikilinks["application/ogg"] = "Ogg";
|
|
|
|
wikilinks["application/x-annodex"] = "Ogg";
|
|
|
|
wikilinks["video/x-msvideo"] = "Audio_Video_Interleave";
|
2011-01-13 07:15:04 +00:00
|
|
|
// audio codecs
|
|
|
|
wikilinks["audio/x-vorbis"] = "Vorbis";
|
|
|
|
wikilinks["audio/x-wav"] = "WAV";
|
|
|
|
// video codecs
|
|
|
|
wikilinks["video/x-theora"] = "Theora"; // FIXME: check
|
2010-11-08 09:40:06 +00:00
|
|
|
|
2010-10-17 20:21:16 +00:00
|
|
|
// add widgets
|
2010-10-18 19:50:02 +00:00
|
|
|
// FIXME: handle aspect ratio (AspectFrame.ratio)
|
2010-10-17 20:52:37 +00:00
|
|
|
drawing_area = new DrawingArea ();
|
2010-12-21 10:01:40 +00:00
|
|
|
drawing_area.set_size_request (160, 120);
|
2010-10-27 23:15:56 +00:00
|
|
|
drawing_area.expose_event.connect (on_drawing_area_expose);
|
2010-10-26 23:18:17 +00:00
|
|
|
drawing_area.realize.connect (on_drawing_area_realize);
|
2010-10-27 22:41:07 +00:00
|
|
|
drawing_area.unrealize.connect (on_drawing_area_unrealize);
|
2010-12-21 10:01:40 +00:00
|
|
|
pack1 (drawing_area, true, true);
|
|
|
|
|
|
|
|
ScrolledWindow sw = new ScrolledWindow (null, null);
|
|
|
|
sw.set_policy (PolicyType.NEVER, PolicyType.ALWAYS);
|
|
|
|
pack2 (sw, true, true);
|
2010-10-17 20:52:37 +00:00
|
|
|
|
2010-11-03 08:33:43 +00:00
|
|
|
table = new Table (8, 3, false);
|
2010-12-21 10:01:40 +00:00
|
|
|
sw.add_with_viewport (table);
|
2011-01-04 12:56:40 +00:00
|
|
|
|
|
|
|
/* TODO: also use tabs for containers
|
|
|
|
* - this is needed for e.g. mpeg-ts or mp3 inside ape
|
|
|
|
* - we should move duration and mime-type out of the tabs
|
|
|
|
*/
|
2010-10-18 14:38:32 +00:00
|
|
|
label = new Label (null);
|
|
|
|
label.set_markup("<b>Container</b>");
|
2010-10-18 19:50:02 +00:00
|
|
|
label.set_alignment (0.0f, 0.5f);
|
2010-11-03 08:33:43 +00:00
|
|
|
table.attach (label, 0, 3, row, row+1, fill_exp, 0, 0, 1);
|
2010-10-18 19:50:02 +00:00
|
|
|
row++;
|
|
|
|
|
2010-11-03 08:33:43 +00:00
|
|
|
icon_image = new Image ();
|
|
|
|
table.attach (icon_image, 2, 3, row, row+3, fill, 0, 0, 0);
|
|
|
|
|
2010-11-03 08:01:04 +00:00
|
|
|
label = new Label ("Format:");
|
|
|
|
label.set_alignment (1.0f, 0.5f);
|
|
|
|
table.attach (label, 0, 1, row, row+1, fill, 0, 0, 0);
|
|
|
|
container_name = new Label (null);
|
|
|
|
container_name.set_alignment (0.0f, 0.5f);
|
2010-11-30 09:18:37 +00:00
|
|
|
container_name.set_selectable(true);
|
2011-01-12 08:17:56 +00:00
|
|
|
container_name.set_use_markup(true);
|
2010-11-03 08:01:04 +00:00
|
|
|
table.attach (container_name, 1, 2, row, row+1, fill_exp, 0, 3, 1);
|
|
|
|
row++;
|
|
|
|
|
2010-10-18 19:50:02 +00:00
|
|
|
label = new Label ("Mime-Type:");
|
|
|
|
label.set_alignment (1.0f, 0.5f);
|
|
|
|
table.attach (label, 0, 1, row, row+1, fill, 0, 0, 0);
|
|
|
|
mime_type = new Label (null);
|
|
|
|
mime_type.set_alignment (0.0f, 0.5f);
|
2010-11-30 09:18:37 +00:00
|
|
|
mime_type.set_selectable(true);
|
2010-10-18 19:50:02 +00:00
|
|
|
table.attach (mime_type, 1, 2, row, row+1, fill_exp, 0, 3, 1);
|
|
|
|
row++;
|
|
|
|
|
|
|
|
label = new Label ("Duration:");
|
|
|
|
label.set_alignment (1.0f, 0.5f);
|
|
|
|
table.attach (label, 0, 1, row, row+1, fill, 0, 0, 0);
|
|
|
|
duration = new Label (null);
|
|
|
|
duration.set_alignment (0.0f, 0.5f);
|
2010-11-30 09:18:37 +00:00
|
|
|
duration.set_selectable(true);
|
2010-10-18 19:50:02 +00:00
|
|
|
table.attach (duration, 1, 2, row, row+1, fill_exp, 0, 3, 1);
|
|
|
|
row++;
|
|
|
|
|
2011-01-04 12:56:40 +00:00
|
|
|
/* TODO: if screen-height<600 use a *single* notebook for both audio and
|
|
|
|
* video streams
|
|
|
|
* - this needs a bit of cleverness when switching streams
|
|
|
|
*/
|
2010-10-18 19:50:02 +00:00
|
|
|
label = new Label (null);
|
|
|
|
label.set_markup("<b>Video Streams</b>");
|
|
|
|
label.set_alignment (0.0f, 0.5f);
|
2010-11-03 08:33:43 +00:00
|
|
|
table.attach (label, 0, 3, row, row+1, fill_exp, 0, 0, 1);
|
2010-10-18 19:50:02 +00:00
|
|
|
row++;
|
|
|
|
|
2010-10-19 21:44:18 +00:00
|
|
|
video_streams = new Notebook ();
|
2010-10-28 14:34:15 +00:00
|
|
|
video_streams.switch_page.connect (on_video_stream_switched);
|
2010-11-03 08:33:43 +00:00
|
|
|
table.attach (video_streams, 0, 3, row, row+1, fill_exp, 0, 0, 1);
|
2010-10-19 21:44:18 +00:00
|
|
|
row++;
|
2010-10-18 19:50:02 +00:00
|
|
|
|
|
|
|
label = new Label (null);
|
|
|
|
label.set_markup("<b>Audio Streams</b>");
|
|
|
|
label.set_alignment (0.0f, 0.5f);
|
2010-11-03 08:33:43 +00:00
|
|
|
table.attach (label, 0, 3, row, row+1, fill_exp, 0, 0, 1);
|
2010-10-18 19:50:02 +00:00
|
|
|
row++;
|
|
|
|
|
2010-10-19 21:44:18 +00:00
|
|
|
audio_streams = new Notebook ();
|
2010-10-28 14:34:15 +00:00
|
|
|
audio_streams.switch_page.connect (on_audio_stream_switched);
|
2010-11-03 08:33:43 +00:00
|
|
|
table.attach (audio_streams, 0, 3, row, row+1, fill_exp, 0, 0, 1);
|
2010-10-19 21:44:18 +00:00
|
|
|
row++;
|
2010-10-17 19:36:39 +00:00
|
|
|
|
2010-10-19 21:44:18 +00:00
|
|
|
// TODO: add container stream info widgets
|
|
|
|
|
|
|
|
// TODO: add tag list widget
|
|
|
|
|
|
|
|
// TODO: add message list widget
|
2010-10-18 19:50:02 +00:00
|
|
|
|
2010-10-17 19:36:39 +00:00
|
|
|
show_all ();
|
2010-10-17 20:21:16 +00:00
|
|
|
|
|
|
|
// set up the gstreamer components
|
2010-10-18 14:14:46 +00:00
|
|
|
try {
|
|
|
|
dc = new Discoverer ((ClockTime)(Gst.SECOND * 10));
|
|
|
|
} catch (Error e) {
|
2010-10-18 19:50:02 +00:00
|
|
|
debug ("Failed to create the discoverer: %s: %s", e.domain.to_string (), e.message);
|
2010-10-18 14:14:46 +00:00
|
|
|
}
|
2010-10-17 20:52:37 +00:00
|
|
|
|
|
|
|
pb = ElementFactory.make ("playbin2", "player") as Pipeline;
|
|
|
|
Gst.Bus bus = pb.get_bus ();
|
2010-10-18 07:31:43 +00:00
|
|
|
bus.set_sync_handler (bus.sync_signal_handler);
|
|
|
|
bus.sync_message["element"].connect (on_element_sync_message);
|
2010-10-17 20:52:37 +00:00
|
|
|
|
2010-10-27 23:15:56 +00:00
|
|
|
state = State.NULL;
|
2010-10-17 19:36:39 +00:00
|
|
|
}
|
|
|
|
|
2010-10-18 07:31:43 +00:00
|
|
|
~Info ()
|
|
|
|
{
|
|
|
|
// stop previous playback
|
|
|
|
pb.set_state (State.NULL);
|
|
|
|
}
|
|
|
|
|
2010-10-17 20:52:37 +00:00
|
|
|
// public methods
|
|
|
|
|
2010-10-17 19:36:39 +00:00
|
|
|
public bool discover (string uri)
|
|
|
|
{
|
2010-10-18 07:31:43 +00:00
|
|
|
bool res = true;
|
|
|
|
|
|
|
|
// stop previous playback
|
|
|
|
pb.set_state (State.NULL);
|
|
|
|
|
|
|
|
if (uri != null) {
|
2010-10-18 14:14:46 +00:00
|
|
|
DiscovererInfo info;
|
2010-11-03 08:33:43 +00:00
|
|
|
File file = File.new_for_uri(uri);
|
|
|
|
|
|
|
|
try {
|
|
|
|
FileInfo finfo = file.query_info ("standard::*", FileQueryInfoFlags.NONE, null);
|
|
|
|
mime_type.set_text (finfo.get_attribute_string (FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE));
|
|
|
|
icon_image.set_from_gicon ((Icon) finfo.get_attribute_object (FILE_ATTRIBUTE_STANDARD_ICON), IconSize.DIALOG);
|
|
|
|
} catch (Error e) {
|
|
|
|
debug ("Failed to query file info from %s: %s: %s", uri, e.domain.to_string (), e.message);
|
|
|
|
}
|
2010-10-18 14:14:46 +00:00
|
|
|
|
|
|
|
try {
|
2010-10-19 21:44:18 +00:00
|
|
|
GLib.List<DiscovererStreamInfo> l;
|
|
|
|
DiscovererStreamInfo sinfo;
|
2010-10-28 00:08:28 +00:00
|
|
|
//DiscovererVideoInfo vinfo;
|
|
|
|
//DiscovererAudioInfo ainfo;
|
|
|
|
Table table;
|
|
|
|
Label label;
|
|
|
|
uint row;
|
|
|
|
AttachOptions fill = AttachOptions.FILL;
|
|
|
|
AttachOptions fill_exp = AttachOptions.EXPAND|AttachOptions.FILL;
|
2011-01-13 07:15:04 +00:00
|
|
|
string str, wikilink;
|
|
|
|
Caps caps;
|
2010-11-04 08:15:19 +00:00
|
|
|
Structure s;
|
2010-10-19 21:44:18 +00:00
|
|
|
|
2010-10-18 14:14:46 +00:00
|
|
|
info = dc.discover_uri (uri);
|
2010-10-18 19:50:02 +00:00
|
|
|
|
|
|
|
ClockTime dur = info.get_duration ();
|
2010-10-28 00:08:28 +00:00
|
|
|
str = "%u:%02u:%02u.%09u".printf (
|
2010-10-18 19:50:02 +00:00
|
|
|
(uint) (dur / (SECOND * 60 * 60)),
|
|
|
|
(uint) ((dur / (SECOND * 60)) % 60),
|
|
|
|
(uint) ((dur / SECOND) % 60),
|
|
|
|
(uint) ((dur) % SECOND));
|
2010-10-28 00:08:28 +00:00
|
|
|
this.duration.set_text (str);
|
2010-10-18 19:50:02 +00:00
|
|
|
//stdout.printf ("Duration: %s\n", dur_str);
|
|
|
|
|
2010-11-04 10:47:14 +00:00
|
|
|
/*
|
|
|
|
< ensonic> bilboed-pi: is gst_discoverer_info_get_container_streams() containing the info for the conatiner or can those be multiple ones as well?
|
|
|
|
< bilboed-pi> ensonic, if you have DV system-stream in MXF .... you'll have two container streams
|
|
|
|
< bilboed-pi> (yes, they exist)
|
|
|
|
< bilboed-pi> I'd recommend grabbing the top-level stream_info and walking your way down
|
|
|
|
*/
|
|
|
|
/*
|
|
|
|
l = info.get_container_streams ();
|
|
|
|
for (int i = 0; i < l.length (); i++) {
|
|
|
|
sinfo = l.nth_data (i);
|
|
|
|
stdout.printf ("container[%d]: %s\n", i, sinfo.get_caps ().to_string ());
|
|
|
|
}
|
|
|
|
l = info.get_stream_list ();
|
|
|
|
for (int i = 0; i < l.length (); i++) {
|
|
|
|
sinfo = l.nth_data (i);
|
|
|
|
stdout.printf ("stream[%d:%s]: %s\n", i, sinfo.get_stream_type_nick(), sinfo.get_caps ().to_string ());
|
|
|
|
}
|
|
|
|
*/
|
|
|
|
sinfo = info.get_stream_info ();
|
2011-01-13 07:15:04 +00:00
|
|
|
caps = sinfo.get_caps ();
|
|
|
|
wikilink = wikilinks[caps.get_structure(0).get_name()];
|
2011-01-12 08:17:56 +00:00
|
|
|
str = pb_utils_get_codec_description (caps);
|
|
|
|
if (wikilink != null) {
|
|
|
|
// FIXME: make prefix and link translatable
|
|
|
|
container_name.set_markup ("<a href=\"http://en.wikipedia.org/wiki/%s\">%s</a>".printf (wikilink, str));
|
|
|
|
} else {
|
|
|
|
container_name.set_text (str);
|
|
|
|
}
|
2010-11-04 10:47:14 +00:00
|
|
|
|
2010-10-19 21:44:18 +00:00
|
|
|
// get stream info
|
|
|
|
while (video_streams.get_n_pages() > 0) {
|
|
|
|
video_streams.remove_page (-1);
|
|
|
|
}
|
|
|
|
l = info.get_video_streams ();
|
2010-11-03 08:47:04 +00:00
|
|
|
have_video = (l.length () > 0);
|
2010-10-19 21:44:18 +00:00
|
|
|
for (int i = 0; i < l.length (); i++) {
|
|
|
|
sinfo = l.nth_data (i);
|
2011-01-13 07:15:04 +00:00
|
|
|
caps = sinfo.get_caps ();
|
2010-10-28 00:08:28 +00:00
|
|
|
|
|
|
|
row = 0;
|
2010-11-04 08:15:19 +00:00
|
|
|
table = new Table (2, 8, false);
|
2010-10-28 00:08:28 +00:00
|
|
|
|
2011-01-13 07:15:04 +00:00
|
|
|
label = new Label(caps.to_string ());
|
2010-10-28 00:08:28 +00:00
|
|
|
label.set_ellipsize (Pango.EllipsizeMode.END);
|
|
|
|
label.set_alignment (0.0f, 0.5f);
|
2010-11-30 09:18:37 +00:00
|
|
|
label.set_selectable(true);
|
2010-10-28 00:08:28 +00:00
|
|
|
table.attach (label, 0, 2, row, row+1, fill_exp, 0, 0, 1);
|
|
|
|
row++;
|
|
|
|
|
2010-10-28 13:45:55 +00:00
|
|
|
label = new Label ("Codec:");
|
|
|
|
label.set_alignment (1.0f, 0.5f);
|
|
|
|
table.attach (label, 0, 1, row, row+1, fill, 0, 0, 0);
|
2011-01-13 07:15:04 +00:00
|
|
|
wikilink = wikilinks[caps.get_structure(0).get_name()];
|
|
|
|
str = pb_utils_get_codec_description (caps);
|
|
|
|
if (wikilink != null) {
|
|
|
|
// FIXME: make prefix and link translatable
|
|
|
|
str="<a href=\"http://en.wikipedia.org/wiki/%s\">%s</a>".printf (wikilink, str);
|
|
|
|
}
|
2010-10-28 13:45:55 +00:00
|
|
|
label = new Label (str);
|
|
|
|
label.set_alignment (0.0f, 0.5f);
|
2010-11-30 09:18:37 +00:00
|
|
|
label.set_selectable(true);
|
2011-01-13 07:15:04 +00:00
|
|
|
label.set_use_markup(true);
|
2010-10-28 13:45:55 +00:00
|
|
|
table.attach (label, 1, 2, row, row+1, fill_exp, 0, 3, 1);
|
|
|
|
row++;
|
|
|
|
|
2010-10-28 00:08:28 +00:00
|
|
|
label = new Label ("Bitrate:");
|
|
|
|
label.set_alignment (1.0f, 0.5f);
|
|
|
|
table.attach (label, 0, 1, row, row+1, fill, 0, 0, 0);
|
2010-10-28 13:34:08 +00:00
|
|
|
str = "%u / %u bits/second".printf (((DiscovererVideoInfo)sinfo).get_bitrate(),((DiscovererVideoInfo)sinfo).get_max_bitrate());
|
|
|
|
label = new Label (str);
|
|
|
|
label.set_alignment (0.0f, 0.5f);
|
2010-11-30 09:18:37 +00:00
|
|
|
label.set_selectable(true);
|
2010-10-28 13:34:08 +00:00
|
|
|
table.attach (label, 1, 2, row, row+1, fill_exp, 0, 3, 1);
|
|
|
|
row++;
|
|
|
|
|
2010-11-08 08:38:39 +00:00
|
|
|
// add named resolutions: (640x480=VGA)
|
2010-10-28 13:39:35 +00:00
|
|
|
label = new Label ("Resolution:");
|
2010-10-28 13:34:08 +00:00
|
|
|
label.set_alignment (1.0f, 0.5f);
|
|
|
|
table.attach (label, 0, 1, row, row+1, fill, 0, 0, 0);
|
2010-11-05 15:17:16 +00:00
|
|
|
string resolution = "%u x %u".printf (((DiscovererVideoInfo)sinfo).get_width(),((DiscovererVideoInfo)sinfo).get_height());
|
|
|
|
string named_res = resolutions[resolution];
|
|
|
|
if (named_res != null) {
|
|
|
|
str = "%s (%s)".printf (named_res, resolution);
|
|
|
|
} else {
|
|
|
|
str = resolution;
|
|
|
|
}
|
2010-10-28 13:34:08 +00:00
|
|
|
label = new Label (str);
|
|
|
|
label.set_alignment (0.0f, 0.5f);
|
2010-11-30 09:18:37 +00:00
|
|
|
label.set_selectable(true);
|
2010-10-28 13:34:08 +00:00
|
|
|
table.attach (label, 1, 2, row, row+1, fill_exp, 0, 3, 1);
|
|
|
|
row++;
|
|
|
|
|
|
|
|
label = new Label ("Framerate:");
|
|
|
|
label.set_alignment (1.0f, 0.5f);
|
|
|
|
table.attach (label, 0, 1, row, row+1, fill, 0, 0, 0);
|
2010-12-16 21:02:31 +00:00
|
|
|
double fps_num = (double)((DiscovererVideoInfo)sinfo).get_framerate_num();
|
|
|
|
double fps_denom = (double)((DiscovererVideoInfo)sinfo).get_framerate_denom();
|
|
|
|
str = "%.3lf frames/second".printf (fps_num/fps_denom);
|
2010-10-28 13:34:08 +00:00
|
|
|
label = new Label (str);
|
|
|
|
label.set_alignment (0.0f, 0.5f);
|
2010-11-30 09:18:37 +00:00
|
|
|
label.set_selectable(true);
|
2010-10-28 13:34:08 +00:00
|
|
|
table.attach (label, 1, 2, row, row+1, fill_exp, 0, 3, 1);
|
|
|
|
row++;
|
|
|
|
|
|
|
|
label = new Label ("PixelAspect:");
|
|
|
|
label.set_alignment (1.0f, 0.5f);
|
|
|
|
table.attach (label, 0, 1, row, row+1, fill, 0, 0, 0);
|
|
|
|
str = "%u : %u".printf (((DiscovererVideoInfo)sinfo).get_par_num(),((DiscovererVideoInfo)sinfo).get_par_denom());
|
|
|
|
label = new Label (str);
|
|
|
|
label.set_alignment (0.0f, 0.5f);
|
2010-11-30 09:18:37 +00:00
|
|
|
label.set_selectable(true);
|
2010-10-28 13:34:08 +00:00
|
|
|
table.attach (label, 1, 2, row, row+1, fill_exp, 0, 3, 1);
|
|
|
|
row++;
|
|
|
|
|
|
|
|
label = new Label ("Bitdepth:");
|
|
|
|
label.set_alignment (1.0f, 0.5f);
|
|
|
|
table.attach (label, 0, 1, row, row+1, fill, 0, 0, 0);
|
|
|
|
str = "%u bits/pixel".printf (((DiscovererVideoInfo)sinfo).get_depth());
|
2010-10-28 00:08:28 +00:00
|
|
|
label = new Label (str);
|
|
|
|
label.set_alignment (0.0f, 0.5f);
|
2010-11-30 09:18:37 +00:00
|
|
|
label.set_selectable(true);
|
2010-10-28 00:08:28 +00:00
|
|
|
table.attach (label, 1, 2, row, row+1, fill_exp, 0, 3, 1);
|
|
|
|
row++;
|
|
|
|
|
2010-11-04 08:15:19 +00:00
|
|
|
if ((s = sinfo.get_misc ()) != null) {
|
|
|
|
label = new Label ("Details:");
|
|
|
|
label.set_alignment (1.0f, 0.5f);
|
|
|
|
table.attach (label, 0, 1, row, row+1, fill, 0, 0, 0);
|
|
|
|
label = new Label(s.to_string ());
|
|
|
|
label.set_ellipsize (Pango.EllipsizeMode.END);
|
|
|
|
label.set_alignment (0.0f, 0.5f);
|
2010-11-30 09:18:37 +00:00
|
|
|
label.set_selectable(true);
|
2010-11-04 08:15:19 +00:00
|
|
|
table.attach (label, 1, 2, row, row+1, fill_exp, 0, 0, 1);
|
|
|
|
row++;
|
|
|
|
}
|
|
|
|
|
2010-11-04 08:46:43 +00:00
|
|
|
if ((s = (Structure)sinfo.get_tags ()) != null) {
|
|
|
|
// FIXME: use treeview inside scrolled window
|
|
|
|
label = new Label ("Tags:");
|
|
|
|
label.set_alignment (1.0f, 0.0f);
|
|
|
|
table.attach (label, 0, 1, row, row+1, fill, fill, 0, 0);
|
2010-11-08 08:38:39 +00:00
|
|
|
str = build_taglist_info (s);
|
2010-11-04 08:46:43 +00:00
|
|
|
label = new Label(str);
|
|
|
|
label.set_ellipsize (Pango.EllipsizeMode.END);
|
|
|
|
label.set_alignment (0.0f, 0.5f);
|
2010-11-30 09:18:37 +00:00
|
|
|
label.set_selectable(true);
|
2010-11-30 09:19:35 +00:00
|
|
|
label.set_use_markup(true);
|
2010-11-04 08:46:43 +00:00
|
|
|
table.attach (label, 1, 2, row, row+1, fill_exp, 0, 0, 1);
|
|
|
|
row++;
|
|
|
|
}
|
|
|
|
|
2010-10-28 00:08:28 +00:00
|
|
|
video_streams.append_page (table, new Label (@"video $i"));
|
2010-10-19 21:44:18 +00:00
|
|
|
}
|
|
|
|
video_streams.show_all();
|
|
|
|
|
|
|
|
while (audio_streams.get_n_pages() > 0) {
|
|
|
|
audio_streams.remove_page (-1);
|
|
|
|
}
|
|
|
|
l = info.get_audio_streams ();
|
|
|
|
for (int i = 0; i < l.length (); i++) {
|
|
|
|
sinfo = l.nth_data (i);
|
2011-01-13 07:15:04 +00:00
|
|
|
caps = sinfo.get_caps ();
|
2010-10-28 00:08:28 +00:00
|
|
|
|
|
|
|
row = 0;
|
2010-11-04 08:15:19 +00:00
|
|
|
table = new Table (2, 7, false);
|
2010-10-28 00:08:28 +00:00
|
|
|
|
2011-01-13 07:15:04 +00:00
|
|
|
label = new Label(caps.to_string ());
|
2010-10-28 00:08:28 +00:00
|
|
|
label.set_ellipsize (Pango.EllipsizeMode.END);
|
|
|
|
label.set_alignment (0.0f, 0.5f);
|
2010-11-30 09:18:37 +00:00
|
|
|
label.set_selectable(true);
|
2010-10-28 00:08:28 +00:00
|
|
|
table.attach (label, 0, 2, row, row+1, fill_exp, 0, 0, 1);
|
|
|
|
row++;
|
|
|
|
|
2010-10-28 13:45:55 +00:00
|
|
|
label = new Label ("Codec:");
|
|
|
|
label.set_alignment (1.0f, 0.5f);
|
|
|
|
table.attach (label, 0, 1, row, row+1, fill, 0, 0, 0);
|
2011-01-13 07:15:04 +00:00
|
|
|
wikilink = wikilinks[caps.get_structure(0).get_name()];
|
|
|
|
str = pb_utils_get_codec_description (caps);
|
|
|
|
if (wikilink != null) {
|
|
|
|
// FIXME: make prefix and link translatable
|
|
|
|
str="<a href=\"http://en.wikipedia.org/wiki/%s\">%s</a>".printf (wikilink, str);
|
|
|
|
}
|
2010-10-28 13:45:55 +00:00
|
|
|
label = new Label (str);
|
|
|
|
label.set_alignment (0.0f, 0.5f);
|
2010-11-30 09:18:37 +00:00
|
|
|
label.set_selectable(true);
|
2011-01-13 07:15:04 +00:00
|
|
|
label.set_use_markup(true);
|
2010-10-28 13:45:55 +00:00
|
|
|
table.attach (label, 1, 2, row, row+1, fill_exp, 0, 3, 1);
|
|
|
|
row++;
|
|
|
|
|
2010-10-28 00:08:28 +00:00
|
|
|
label = new Label ("Bitrate:");
|
|
|
|
label.set_alignment (1.0f, 0.5f);
|
|
|
|
table.attach (label, 0, 1, row, row+1, fill, 0, 0, 0);
|
2010-10-28 13:34:08 +00:00
|
|
|
str = "%u / %u bits/second".printf (((DiscovererAudioInfo)sinfo).get_bitrate(),((DiscovererAudioInfo)sinfo).get_max_bitrate());
|
|
|
|
label = new Label (str);
|
|
|
|
label.set_alignment (0.0f, 0.5f);
|
2010-11-30 09:18:37 +00:00
|
|
|
label.set_selectable(true);
|
2010-10-28 13:34:08 +00:00
|
|
|
table.attach (label, 1, 2, row, row+1, fill_exp, 0, 3, 1);
|
|
|
|
row++;
|
|
|
|
|
|
|
|
label = new Label ("Samplerate:");
|
|
|
|
label.set_alignment (1.0f, 0.5f);
|
|
|
|
table.attach (label, 0, 1, row, row+1, fill, 0, 0, 0);
|
|
|
|
str = "%u samples/second".printf (((DiscovererAudioInfo)sinfo).get_sample_rate());
|
|
|
|
label = new Label (str);
|
|
|
|
label.set_alignment (0.0f, 0.5f);
|
2010-11-30 09:18:37 +00:00
|
|
|
label.set_selectable(true);
|
2010-10-28 13:34:08 +00:00
|
|
|
table.attach (label, 1, 2, row, row+1, fill_exp, 0, 3, 1);
|
|
|
|
row++;
|
|
|
|
|
2010-11-05 15:17:16 +00:00
|
|
|
// TODO: check channel layouts, can we have some nice names here ?
|
2010-10-28 13:34:08 +00:00
|
|
|
label = new Label ("Channels:");
|
|
|
|
label.set_alignment (1.0f, 0.5f);
|
|
|
|
table.attach (label, 0, 1, row, row+1, fill, 0, 0, 0);
|
|
|
|
str = "%u".printf (((DiscovererAudioInfo)sinfo).get_channels());
|
|
|
|
label = new Label (str);
|
|
|
|
label.set_alignment (0.0f, 0.5f);
|
2010-11-30 09:18:37 +00:00
|
|
|
label.set_selectable(true);
|
2010-10-28 13:34:08 +00:00
|
|
|
table.attach (label, 1, 2, row, row+1, fill_exp, 0, 3, 1);
|
|
|
|
row++;
|
|
|
|
|
|
|
|
label = new Label ("Bitdepth:");
|
|
|
|
label.set_alignment (1.0f, 0.5f);
|
|
|
|
table.attach (label, 0, 1, row, row+1, fill, 0, 0, 0);
|
|
|
|
str = "%u bits/sample".printf (((DiscovererAudioInfo)sinfo).get_depth());
|
2010-10-28 00:08:28 +00:00
|
|
|
label = new Label (str);
|
|
|
|
label.set_alignment (0.0f, 0.5f);
|
2010-11-30 09:18:37 +00:00
|
|
|
label.set_selectable(true);
|
2010-10-28 00:08:28 +00:00
|
|
|
table.attach (label, 1, 2, row, row+1, fill_exp, 0, 3, 1);
|
|
|
|
row++;
|
2010-10-28 13:34:08 +00:00
|
|
|
|
2010-11-04 08:15:19 +00:00
|
|
|
if ((s = sinfo.get_misc ()) != null) {
|
|
|
|
label = new Label ("Details:");
|
|
|
|
label.set_alignment (1.0f, 0.5f);
|
|
|
|
table.attach (label, 0, 1, row, row+1, fill, 0, 0, 0);
|
|
|
|
label = new Label(s.to_string ());
|
|
|
|
label.set_ellipsize (Pango.EllipsizeMode.END);
|
|
|
|
label.set_alignment (0.0f, 0.5f);
|
2010-11-30 09:18:37 +00:00
|
|
|
label.set_selectable(true);
|
2010-11-04 08:15:19 +00:00
|
|
|
table.attach (label, 1, 2, row, row+1, fill_exp, 0, 0, 1);
|
|
|
|
row++;
|
|
|
|
}
|
|
|
|
|
2010-11-04 08:46:43 +00:00
|
|
|
if ((s = (Structure)sinfo.get_tags ()) != null) {
|
|
|
|
// FIXME: use treeview inside scrolled window
|
|
|
|
label = new Label ("Tags:");
|
|
|
|
label.set_alignment (1.0f, 0.0f);
|
|
|
|
table.attach (label, 0, 1, row, row+1, fill, fill, 0, 0);
|
2010-11-08 08:38:39 +00:00
|
|
|
str = build_taglist_info (s);
|
2010-11-04 08:46:43 +00:00
|
|
|
label = new Label(str);
|
|
|
|
label.set_ellipsize (Pango.EllipsizeMode.END);
|
|
|
|
label.set_alignment (0.0f, 0.5f);
|
2010-11-30 09:18:37 +00:00
|
|
|
label.set_selectable(true);
|
2010-11-30 09:19:35 +00:00
|
|
|
label.set_use_markup(true);
|
2010-11-04 08:46:43 +00:00
|
|
|
table.attach (label, 1, 2, row, row+1, fill_exp, 0, 0, 1);
|
|
|
|
row++;
|
|
|
|
}
|
|
|
|
|
2010-10-28 00:08:28 +00:00
|
|
|
audio_streams.append_page (table, new Label (@"audio $i"));
|
2010-10-19 21:44:18 +00:00
|
|
|
}
|
|
|
|
audio_streams.show_all();
|
|
|
|
//l = info.get_container_streams ();
|
2010-10-18 19:50:02 +00:00
|
|
|
|
2010-10-18 14:14:46 +00:00
|
|
|
} catch (Error e) {
|
2010-10-18 19:50:02 +00:00
|
|
|
debug ("Failed to extract metadata from %s: %s: %s", uri, e.domain.to_string (), e.message);
|
2010-10-18 14:14:46 +00:00
|
|
|
}
|
2010-10-17 20:52:37 +00:00
|
|
|
|
2010-10-18 07:31:43 +00:00
|
|
|
// play file
|
|
|
|
((GLib.Object)pb).set_property ("uri", uri);
|
|
|
|
pb.set_state (State.PLAYING);
|
2010-10-17 20:52:37 +00:00
|
|
|
|
2010-10-18 07:31:43 +00:00
|
|
|
res = true;
|
|
|
|
}
|
2010-10-17 20:21:16 +00:00
|
|
|
|
2010-10-18 07:31:43 +00:00
|
|
|
return (res);
|
2010-10-17 19:36:39 +00:00
|
|
|
}
|
2010-10-17 20:52:37 +00:00
|
|
|
|
|
|
|
// signal handlers
|
|
|
|
|
2010-10-27 23:15:56 +00:00
|
|
|
private bool on_drawing_area_expose (Widget widget, Gdk.EventExpose event)
|
|
|
|
{
|
2010-11-03 08:47:04 +00:00
|
|
|
// redraw if not playing and if there is no video
|
|
|
|
if (pb.current_state < State.PAUSED || !have_video) {
|
2010-10-27 23:15:56 +00:00
|
|
|
Gdk.Window w = widget.get_window();
|
|
|
|
Gtk.Allocation a;
|
|
|
|
widget.get_allocation(out a);
|
|
|
|
Cairo.Context cr = Gdk.cairo_create (w);
|
|
|
|
|
|
|
|
cr.set_source_rgb (0, 0, 0);
|
|
|
|
cr.rectangle (0, 0, a.width, a.height);
|
|
|
|
cr.fill ();
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2010-10-26 23:18:17 +00:00
|
|
|
private void on_drawing_area_realize (Widget widget)
|
|
|
|
{
|
|
|
|
widget.get_window ().ensure_native ();
|
|
|
|
widget.unset_flags(Gtk.WidgetFlags.DOUBLE_BUFFERED);
|
|
|
|
}
|
|
|
|
|
2010-10-27 22:41:07 +00:00
|
|
|
private void on_drawing_area_unrealize (Widget widget)
|
|
|
|
{
|
|
|
|
pb.set_state (State.NULL);
|
|
|
|
}
|
|
|
|
|
2010-10-18 07:31:43 +00:00
|
|
|
private void on_element_sync_message (Gst.Bus bus, Message message)
|
2010-10-17 20:52:37 +00:00
|
|
|
{
|
|
|
|
Structure structure = message.get_structure ();
|
|
|
|
if (structure.has_name ("prepare-xwindow-id"))
|
|
|
|
{
|
2010-10-17 21:07:02 +00:00
|
|
|
XOverlay xoverlay = message.src as XOverlay;
|
2010-10-26 23:18:17 +00:00
|
|
|
xoverlay.set_xwindow_id (Gdk.x11_drawable_get_xid (drawing_area.get_window()));
|
2010-10-18 19:50:02 +00:00
|
|
|
|
|
|
|
if (message.src.get_class ().find_property ("force-aspect-ratio") != null) {
|
|
|
|
((GLib.Object)message.src).set_property ("force-aspect-ratio", true);
|
|
|
|
}
|
2010-10-17 20:52:37 +00:00
|
|
|
}
|
|
|
|
}
|
2010-10-28 14:34:15 +00:00
|
|
|
|
2010-11-10 06:50:48 +00:00
|
|
|
/* FIXME: discoverer not neccesarily return the stream in the same order as
|
|
|
|
* playbin2 sees them: https://bugzilla.gnome.org/show_bug.cgi?id=634407
|
|
|
|
*/
|
2010-10-28 14:34:15 +00:00
|
|
|
private void on_video_stream_switched (NotebookPage page, uint page_num)
|
|
|
|
{
|
|
|
|
if (pb.current_state > State.PAUSED) {
|
|
|
|
stdout.printf ("Switching video to: %u\n", page_num);
|
|
|
|
((GLib.Object)pb).set_property ("current-video", (int)page_num);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private void on_audio_stream_switched (NotebookPage page, uint page_num)
|
|
|
|
{
|
|
|
|
if (pb.current_state > State.PAUSED) {
|
|
|
|
stdout.printf ("Switching audio to: %u\n", page_num);
|
|
|
|
((GLib.Object)pb).set_property ("current-audio", (int)page_num);
|
|
|
|
}
|
|
|
|
}
|
2010-11-08 08:38:39 +00:00
|
|
|
|
|
|
|
private string build_taglist_info (Structure s)
|
|
|
|
{
|
2010-11-08 09:40:06 +00:00
|
|
|
uint i;
|
|
|
|
string str, fn, vstr;
|
|
|
|
Gst.Value v;
|
|
|
|
|
2010-11-08 09:52:11 +00:00
|
|
|
// TODO: add special handling for certain tags
|
|
|
|
// image, uris, ...
|
2010-11-08 09:40:06 +00:00
|
|
|
|
|
|
|
str = "";
|
|
|
|
for (i = 0; i < s.n_fields(); i++) {
|
|
|
|
fn = s.nth_field_name (i);
|
2010-11-08 09:52:11 +00:00
|
|
|
// skip a few tags
|
2010-11-08 09:40:06 +00:00
|
|
|
if (tag_black_list.contains (fn))
|
|
|
|
continue;
|
2010-11-08 09:52:11 +00:00
|
|
|
if (fn.has_prefix("private-"))
|
|
|
|
continue;
|
|
|
|
|
2010-11-08 09:40:06 +00:00
|
|
|
if (str.length > 0)
|
|
|
|
str += "\n";
|
|
|
|
v = s.get_value (fn);
|
|
|
|
vstr = v.serialize ().compress ();
|
2010-11-30 09:19:35 +00:00
|
|
|
if (vstr.has_prefix("http://") || vstr.has_prefix("https://")) {
|
|
|
|
vstr = "<a href=\"" + vstr + "\">" + vstr + "</a>";
|
|
|
|
}
|
2010-11-08 09:40:06 +00:00
|
|
|
str += fn + " = " + vstr;
|
|
|
|
}
|
2010-11-08 08:38:39 +00:00
|
|
|
|
|
|
|
return str;
|
|
|
|
}
|
2010-10-17 21:07:02 +00:00
|
|
|
}
|