From c2472804f9984829ea0d46fa200ae13cd366828c Mon Sep 17 00:00:00 2001 From: "Carsten Haitzler (Rasterman)" Date: Sat, 23 Aug 2014 19:29:10 +0900 Subject: [PATCH] add subtitle support into rage on cmdline as well as automatic --- README | 10 ++++++++ TODO | 1 - src/bin/main.c | 30 +++++++++++++++++++--- src/bin/video.c | 48 ++++++++++++++++++++++++++++++++++- src/bin/video.h | 2 ++ src/bin/win.c | 36 ++++++++++++++++++-------- src/bin/winlist.c | 64 +++++++++++++++++++++++------------------------ src/bin/winvid.c | 21 ++++++++++++---- src/bin/winvid.h | 6 +++++ 9 files changed, 165 insertions(+), 53 deletions(-) diff --git a/README b/README index 12aad09..81a6cb9 100644 --- a/README +++ b/README @@ -22,6 +22,16 @@ You can tell it what media/video engine in emotion to ue via -e: rage -e xine dvd:/ rage -e gstreamer1 blah.mp3 +You can also specify subtitle files with -sub: + + rage file.mp4 -sub mysubs.srt + +This depends on video engine support to display them, so it may not +work. Also rage will use a srt or sub format file if found, +automatically. If the filename is video.mp4 or video.avi, video.mov +etc. then rage looks for video.srt or video.sub and automatically will +use it. + If you DND files onto its window, they are added to the playlist. Mouse over the right of the window brings up the playlist. Mouse over the position bar at the bottom, if it's a video, brings up a video diff --git a/TODO b/TODO index 3048837..0e68069 100644 --- a/TODO +++ b/TODO @@ -7,7 +7,6 @@ * spu channel list/selection * video channel list/selection * handle non-seekable content (eg streams) -* add subtitle file cmdline * loop all option * show busy anim until opened cb or failure * thumbnail picker show all thumbs for video in a grid to select position diff --git a/src/bin/main.c b/src/bin/main.c index 2696390..095f204 100644 --- a/src/bin/main.c +++ b/src/bin/main.c @@ -27,11 +27,11 @@ elm_main(int argc, char **argv) { Evas_Object *win; char buf[4096]; - const char *f; Eina_List *list = NULL; int i; Inf *inf; Config *config; + Winvid_Entry *vid = NULL; elm_need_efreet(); config_init(); @@ -60,8 +60,23 @@ elm_main(int argc, char **argv) config->emotion_engine = eina_stringshare_add(argv[i]); } } + else if (!strcmp(argv[i], "-sub")) + { + if (i < (argc - 1)) + { + i++; + if (vid) eina_stringshare_replace(&(vid->sub), argv[i]); + } + } else - list = eina_list_append(list, eina_stringshare_add(argv[i])); + { + vid = calloc(1, sizeof(Winvid_Entry)); + if (vid) + { + vid->file = eina_stringshare_add(argv[i]); + list = eina_list_append(list, vid); + } + } } elm_policy_set(ELM_POLICY_QUIT, ELM_POLICY_QUIT_LAST_WINDOW_CLOSED); @@ -84,11 +99,18 @@ elm_main(int argc, char **argv) } evas_object_event_callback_add(win, EVAS_CALLBACK_RESIZE, _cb_resize, NULL); - evas_object_resize(win, 320, 200); + evas_object_resize(win, + 320 * elm_config_scale_get(), + 200 * elm_config_scale_get()); win_video_init(win); win_video_file_list_set(win, list); - EINA_LIST_FREE(list, f) eina_stringshare_del(f); + EINA_LIST_FREE(list, vid) + { + if (vid->file) eina_stringshare_del(vid->file); + if (vid->sub) eina_stringshare_del(vid->sub); + free(vid); + } inf = evas_object_data_get(win, "inf"); if (argc <= 1) diff --git a/src/bin/video.c b/src/bin/video.c index 3f75224..53cf9d1 100644 --- a/src/bin/video.c +++ b/src/bin/video.c @@ -570,6 +570,14 @@ video_file_get(Evas_Object *obj) return sd->file; } +void +video_sub_file_set(Evas_Object *obj, const char *file) +{ + Video *sd = evas_object_smart_data_get(obj); + if (!sd) return; + emotion_object_video_subtitle_file_set(sd->o_vid, file); +} + void video_mute_set(Evas_Object *obj, Eina_Bool mute) { @@ -955,6 +963,45 @@ video_meta_album_get(Evas_Object *obj) return emotion_object_meta_info_get(sd->o_vid, EMOTION_META_INFO_TRACK_ALBUM); } +void +video_file_autosub_set(Evas_Object *obj, const char *file, const char *sub) +{ + if ((file) && (!sub)) + { + const char *subtypes[] = + { + ".srt", + ".SRT", + ".sub", + ".SUB", + NULL + }; + char *sub = alloca(strlen(file) + 1 + 16); + char *p; + int i; + Eina_Bool found = EINA_FALSE; + + strcpy(sub, file); + p = strchr(sub, '.'); + if (p) + { + for (i = 0; subtypes[i]; i++) + { + strcpy(p, subtypes[i]); + if (ecore_file_exists(sub)) + { + video_sub_file_set(obj, sub); + found = EINA_TRUE; + break; + } + } + } + if (!found) video_sub_file_set(obj, NULL); + } + else video_sub_file_set(obj, sub); + video_file_set(obj, file); +} + // emotion_object_seekable_get // emotion_object_play_speed_set // emotion_object_play_speed_get @@ -962,7 +1009,6 @@ video_meta_album_get(Evas_Object *obj) // emotion_object_buffer_size_get // emotion_object_video_mute_set // emotion_object_video_mute_get -// emotion_object_video_subtitle_file_set // emotion_object_spu_mute_set // emotion_object_spu_mute_get // emotion_object_progress_info_get diff --git a/src/bin/video.h b/src/bin/video.h index 6428433..ab1961e 100644 --- a/src/bin/video.h +++ b/src/bin/video.h @@ -6,6 +6,7 @@ Evas_Object *video_add(Evas_Object *parent); void video_file_set(Evas_Object *obj, const char *file); const char *video_file_get(Evas_Object *obj); +void video_sub_file_set(Evas_Object *obj, const char *file); void video_mute_set(Evas_Object *obj, Eina_Bool mute); Eina_Bool video_mute_get(Evas_Object *obj); void video_play_set(Evas_Object *obj, Eina_Bool play); @@ -51,5 +52,6 @@ Eina_Bool video_lowquality_get(Evas_Object *obj); const char *video_meta_title_get(Evas_Object *obj); const char *video_meta_artist_get(Evas_Object *obj); const char *video_meta_album_get(Evas_Object *obj); +void video_file_autosub_set(Evas_Object *obj, const char *file, const char *sub); #endif diff --git a/src/bin/win.c b/src/bin/win.c index 4a706e6..1dc4f07 100644 --- a/src/bin/win.c +++ b/src/bin/win.c @@ -32,13 +32,18 @@ static void _cb_win_del(void *data EINA_UNUSED, Evas *e EINA_UNUSED, Evas_Object *obj, void *ev EINA_UNUSED) { Inf *inf = evas_object_data_get(obj, "inf"); - const char *f; + Winvid_Entry *vid; if (inf->next_job) ecore_job_del(inf->next_job); if (inf->show_timeout) ecore_timer_del(inf->show_timeout); if (inf->drag_anim) ecore_animator_del(inf->drag_anim); if (inf->mouse_idle_timeout) ecore_timer_del(inf->mouse_idle_timeout); - EINA_LIST_FREE(inf->file_list, f) eina_stringshare_del(f); + EINA_LIST_FREE(inf->file_list, vid) + { + if (vid->file) eina_stringshare_del(vid->file); + if (vid->sub) eina_stringshare_del(vid->sub); + free(vid); + } evas_object_data_del(obj, "inf"); free(inf); } @@ -156,11 +161,11 @@ win_do_next(Evas_Object *win) } static void -_restart_vid(Evas_Object *win, Evas_Object *lay, Evas_Object *vid, const char *file) +_restart_vid(Evas_Object *win, Evas_Object *lay, Evas_Object *vid, const char *file, const char *sub) { video_position_set(vid, 0.0); video_play_set(vid, EINA_FALSE); - video_file_set(vid, file); + video_file_autosub_set(vid, file, sub); video_position_set(vid, 0.0); video_play_set(vid, EINA_TRUE); elm_layout_signal_emit(lay, "action,newvid", "rage"); @@ -172,7 +177,8 @@ void win_video_restart(Evas_Object *win) { Inf *inf = evas_object_data_get(win, "inf"); - _restart_vid(win, inf->lay, inf->vid, inf->file_cur->data); + Winvid_Entry *vid = inf->file_cur->data; + _restart_vid(win, inf->lay, inf->vid, vid->file, vid->sub); } void @@ -180,6 +186,7 @@ win_video_next(Evas_Object *win) { Inf *inf = evas_object_data_get(win, "inf"); Eina_List *l; + Winvid_Entry *vid; if (!inf->file_list) return; if (!inf->file_cur) l = inf->file_list; @@ -190,7 +197,8 @@ win_video_next(Evas_Object *win) return; } inf->file_cur = l; - _restart_vid(win, inf->lay, inf->vid, l->data); + vid = l->data; + _restart_vid(win, inf->lay, inf->vid, vid->file, vid->sub); win_list_sel_update(win); } @@ -199,13 +207,15 @@ win_video_prev(Evas_Object *win) { Inf *inf = evas_object_data_get(win, "inf"); Eina_List *l; + Winvid_Entry *vid; if (!inf->file_list) return; if (!inf->file_cur) l = eina_list_last(inf->file_list); else l = inf->file_cur->prev; if (!l) return; inf->file_cur = l; - _restart_vid(win, inf->lay, inf->vid, l->data); + vid = l->data; + _restart_vid(win, inf->lay, inf->vid, vid->file, vid->sub); win_list_sel_update(win); } @@ -214,11 +224,13 @@ win_video_first(Evas_Object *win) { Inf *inf = evas_object_data_get(win, "inf"); Eina_List *l; + Winvid_Entry *vid; if (!inf->file_list) return; l = inf->file_list; inf->file_cur = l; - _restart_vid(win, inf->lay, inf->vid, l->data); + vid = l->data; + _restart_vid(win, inf->lay, inf->vid, vid->file, vid->sub); win_list_sel_update(win); } @@ -227,12 +239,14 @@ win_video_last(Evas_Object *win) { Inf *inf = evas_object_data_get(win, "inf"); Eina_List *l; + Winvid_Entry *vid; if (!inf->file_list) return; l = eina_list_last(inf->file_list); if (!l) return; inf->file_cur = l; - _restart_vid(win, inf->lay, inf->vid, l->data); + vid = l->data; + _restart_vid(win, inf->lay, inf->vid, vid->file, vid->sub); win_list_sel_update(win); } @@ -343,13 +357,15 @@ win_title_update(Evas_Object *win) Inf *inf = evas_object_data_get(win, "inf"); const char *file, *s; char buf[4096]; + Winvid_Entry *vid; if (!inf->file_cur) { elm_win_title_set(win, "Rage"); return; } - file = inf->file_cur->data; + vid = inf->file_cur->data; + file = vid->file; if (!file) { elm_win_title_set(win, "Rage"); diff --git a/src/bin/winlist.c b/src/bin/winlist.c index 7f7c0e5..6c643bd 100644 --- a/src/bin/winlist.c +++ b/src/bin/winlist.c @@ -13,7 +13,7 @@ static void _ready(Evas_Object *obj) { int w = 1, h = 1; - + if (evas_object_data_get(obj, "ready")) return; evas_object_data_set(obj, "ready", obj); video_position_set(obj, video_length_get(obj) / 2.0); @@ -25,7 +25,7 @@ static void _bring(Evas_Object *obj) { Evas_Coord x, y, w, h, px, py; - + evas_object_geometry_get(obj, &x, &y, &w, &h); evas_object_geometry_get(bx, &px, &py, NULL, NULL); elm_scroller_region_bring_in(sc, x - px, y - py, w, h); @@ -56,7 +56,7 @@ _cb_pos_eval(void *data) { Evas_Object *obj = data; Evas_Coord x, y, w, h, vx, vy, vw, vh; - + evas_object_geometry_get(obj, &x, &y, &w, &h); evas_output_viewport_get(evas_object_evas_get(obj), &vx, &vy, &vw, &vh); if (ELM_RECTS_INTERSECT(x, y, w, h, vx, vy, vw, vh)) @@ -64,11 +64,12 @@ _cb_pos_eval(void *data) if (!evas_object_data_get(obj, "active")) { const char *f; - + f = evas_object_data_get(obj, "file"); + video_file_autosub_set(obj, f, NULL); + video_mute_set(obj, EINA_TRUE); video_play_set(obj, EINA_TRUE); video_loop_set(obj, EINA_TRUE); - video_file_set(obj, f); evas_object_data_set(obj, "active", obj); } } @@ -77,7 +78,7 @@ _cb_pos_eval(void *data) if (evas_object_data_get(obj, "active")) { video_play_set(obj, EINA_FALSE); - video_file_set(obj, NULL); + video_file_autosub_set(obj, NULL, NULL); video_position_set(obj, 0.0); evas_object_data_del(obj, "active"); evas_object_data_del(obj, "ready"); @@ -124,7 +125,7 @@ _sel(Evas_Object *obj) Eina_List *items = elm_box_children_get(bx); Eina_List *l; Evas_Object *o; - + EINA_LIST_FOREACH(items, l, o) { if (evas_object_data_get(o, "selected")) @@ -150,18 +151,19 @@ _fill_box(Evas_Object *win) { Inf *inf = evas_object_data_get(win, "inf"); Eina_List *l; - const char *f, *s; + Winvid_Entry *vid; + const char *s; Evas_Object *o, *base, *rect; char buf[4096]; Evas_Coord w, h, sz = 0; - + elm_coords_finger_size_adjust(1, &sz, 1, &sz); evas_object_geometry_get(win, NULL, NULL, &w, &h); w = w / 8; h = h / 8; if (w < sz) w = sz; if (h < sz) h = sz; - EINA_LIST_FOREACH(inf->file_list, l, f) + EINA_LIST_FOREACH(inf->file_list, l, vid) { base = o = elm_layout_add(win); elm_object_focus_allow_set(o, EINA_FALSE); @@ -171,19 +173,17 @@ _fill_box(Evas_Object *win) evas_object_size_hint_align_set(o, -1.0, 0.5); elm_layout_signal_callback_add(o, "rage,selected", "rage", _cb_selected, win); evas_object_data_set(o, "list", l); - - s = ecore_file_file_get(f); - if ((s) && (s[0] != 0)) - elm_object_part_text_set(o, "rage.title", s); - else - elm_object_part_text_set(o, "rage.title", f); - + + s = ecore_file_file_get(vid->file); + if ((s) && (s[0] != 0)) elm_object_part_text_set(o, "rage.title", s); + else elm_object_part_text_set(o, "rage.title", vid->file); + rect = o = evas_object_rectangle_add(evas_object_evas_get(win)); evas_object_color_set(rect, 0, 0, 0, 0); elm_object_part_content_set(base, "rage.sizer", o); evas_object_data_set(base, "sizer", o); evas_object_size_hint_min_set(o, w, h); - + o = video_add(win); video_art_set(o, EINA_TRUE); evas_object_data_set(o, "base", base); @@ -193,18 +193,18 @@ _fill_box(Evas_Object *win) video_lowquality_set(o, EINA_TRUE); evas_object_smart_callback_add(o, "opened", _cb_opened, win); evas_object_smart_callback_add(o, "length", _cb_length, win); - + evas_object_event_callback_add(o, EVAS_CALLBACK_MOVE, _cb_vid_move, win); evas_object_event_callback_add(o, EVAS_CALLBACK_RESIZE, _cb_vid_resize, win); evas_object_event_callback_add(o, EVAS_CALLBACK_DEL, _cb_vid_del, win); - - evas_object_data_set(o, "file", f); + + evas_object_data_set(o, "file", vid->file); elm_object_part_content_set(base, "rage.content", o); evas_object_show(o); - + elm_box_pack_end(bx, base); evas_object_show(base); - + if (l == inf->file_cur) { evas_object_data_set(base, "selected", base); @@ -219,7 +219,7 @@ void win_list_show(Evas_Object *win) { Inf *inf = evas_object_data_get(win, "inf"); - + if (tb) return; tb = elm_table_add(win); evas_object_show(tb); @@ -237,20 +237,20 @@ win_list_show(Evas_Object *win) elm_scroller_content_min_limit(sc, EINA_TRUE, EINA_FALSE); elm_table_pack(tb, sc, 0, 0, 1, 1); evas_object_show(sc); - + bx = elm_box_add(win); elm_object_focus_allow_set(bx, EINA_FALSE); evas_object_size_hint_weight_set(bx, 1.0, 0.0); evas_object_size_hint_align_set(bx, -1.0, 0.0); elm_box_homogeneous_set(bx, EINA_TRUE); - + _fill_box(win); - + elm_object_content_set(sc, bx); evas_object_show(bx); - + elm_object_part_content_set(inf->lay, "rage.list", tb); - + elm_layout_signal_emit(inf->lay, "list,state,visible", "rage"); } @@ -267,7 +267,7 @@ void win_list_hide(Evas_Object *win) { Inf *inf = evas_object_data_get(win, "inf"); - + if (!tb) return; if (bring_timer) ecore_timer_del(bring_timer); bring_timer = NULL; @@ -291,7 +291,7 @@ win_list_sel_update(Evas_Object *win) Eina_List *items = elm_box_children_get(bx); Eina_List *l; Evas_Object *o; - + EINA_LIST_FOREACH(items, l, o) { if (inf->file_cur == evas_object_data_get(o, "list")) @@ -312,7 +312,7 @@ win_list_size_update(Evas_Object *win) Eina_List *l; Evas_Object *o; Evas_Coord w, h, sz = 0; - + elm_coords_finger_size_adjust(1, &sz, 1, &sz); evas_object_geometry_get(win, NULL, NULL, &w, &h); w = w / 8; diff --git a/src/bin/winvid.c b/src/bin/winvid.c index d6ab7a1..e30a776 100644 --- a/src/bin/winvid.c +++ b/src/bin/winvid.c @@ -208,11 +208,19 @@ win_video_file_list_set(Evas_Object *win, Eina_List *list) { Inf *inf = evas_object_data_get(win, "inf"); Eina_List *l, *list2 = NULL; - const char *f; + Winvid_Entry *vid; - EINA_LIST_FOREACH(list, l, f) + EINA_LIST_FOREACH(list, l, vid) { - list2 = eina_list_append(list2, eina_stringshare_add(f)); + Winvid_Entry *vid2; + + vid2 = calloc(1, sizeof(Winvid_Entry)); + if (vid2) + { + if (vid->file) vid2->file = eina_stringshare_add(vid->file); + if (vid->sub) vid2->sub = eina_stringshare_add(vid->sub); + list2 = eina_list_append(list2, vid2); + } } inf->file_list = list2; win_video_next(win); @@ -222,9 +230,12 @@ void win_video_insert(Evas_Object *win, const char *file) { Inf *inf = evas_object_data_get(win, "inf"); + Winvid_Entry *vid; - inf->file_list = eina_list_append_relative_list - (inf->file_list, eina_stringshare_add(file), inf->file_cur); + vid = calloc(1, sizeof(Winvid_Entry)); + vid->file = eina_stringshare_add(file); + inf->file_list = eina_list_append_relative_list(inf->file_list, vid, + inf->file_cur); evas_object_data_set(win, "file_list", inf->file_list); } diff --git a/src/bin/winvid.h b/src/bin/winvid.h index 0c50aba..9e0a804 100644 --- a/src/bin/winvid.h +++ b/src/bin/winvid.h @@ -1,6 +1,12 @@ #ifndef _WINVID_H__ #define _WINVID_H__ 1 +typedef struct _Winvid_Entry +{ + const char *file; + const char *sub; +} Winvid_Entry; + void win_video_init(Evas_Object *win); void win_video_file_list_set(Evas_Object *win, Eina_List *list); void win_video_insert(Evas_Object *win, const char *file);