In this tutorial, we will see how to play a multimedia file (video) in an application.
Multimedia example:
The whole code__: multimedia.c
The EFL have a special library for multimedia file playing purposes: Emotion.
That library has some wrappers in Elementary to let you easily write
applications: these are Elm_Video
and Elm_Player
.
* Elm_Video provides a simple video object.
* Elm_Player provides an interface to show a bar with basic actions (like rewind, fast forward, pause, etc.) to interract with a playing video.
———–
=== Basic video widgets ===
<code c>
Evas_Object *video;
video = elm_video_add(win);
evas_object_size_hint_weight_set(video, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
elm_video_file_set(video, FILE);
elm_video_play(video);
evas_object_show(video);
</code>
Create a new Elm_Video
object. This object is the main widget for a video.
The actual video file is then set (which is here the FILE
macro).
Elm_Video
can take either a path to a file or any kind of URL. Finally,
the video starts playing
<code c>
Evas_Object *player;
player = elm_player_add(win);
evas_object_size_hint_weight_set(player, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
elm_object_content_set(player, video);
evas_object_smart_callback_add(player, “info,clicked”, _player_info_cb, video);
evas_object_show(player);
</code>
Now create an Elm_Player
object. This object wraps around an Elm_Video
to have it automatically resized, to show a user interface with basic buttons,
a progress bar and other stuff. A callback is added for the
info,clicked
event, which is launched when the user clicks on the
information button in the player interface. This callback will be detailed
further.
The player interface is eventually set as a naviframe item.
<code c>
Elm_Object_Item *it = elm_naviframe_item_push(nav, “Video”, NULL, NULL, player, NULL);
elm_naviframe_item_title_enabled_set(it, EINA_FALSE, EINA_FALSE);
</code>
=== Getting more information ===
The purpose is to display some information about the video the user wants to. For
instance, the video file name, its location, duration, and
image size will be displayed. This list is of course not exhaustive and much
more information could be added.
Some are not directly available in Elm_Video
nor in
Elm_Player
. But the underlaying Emotion object is available with the
elm_video_emotion_get(video)
function.
== Playing Status ==
Set the label to display the playing status in _player_info_cb
.
<code c>
label = elm_label_add(table);
evas_object_show(label);
_player_info_status_update(label, emotion, NULL);
elm_table_pack(table, label, 0, 0, 2, 1);
evas_object_smart_callback_add(emotion, “playback_finished”, _player_info_status_update, label);
</code>
That function is also registered as a callback upon playback_finished
so
that the status is updated upon playback completion.
Get the playing status with _player_info_status_update
callback:
The emotion_object_play_get
return true if the video is playing, if not
the video is in paused or ended.
<code c>
static void
_player_info_status_update(void *data, Evas_Object *obj, void *event_info)
{
Evas_Object *emotion = obj, *label = data;
char buf[256];
switch on main item
if (!info)
{
evas_object_smart_callback_del(obj, “playback_finished”, _player_info_status_update);
return;
}
update
double position = emotion_object_position_get(emotion);
double duration = emotion_object_play_length_get(emotion);
if (emotion_object_play_get(emotion))
elm_object_text_set(label, “<b>Playing</b>”);
else if (position < duration)
elm_object_text_set(label, “<b>Paused</b>”);
else
elm_object_text_set(label, “<b>Ended</b>”);
}
</code>
== Get the file name and location ==
Get the file name and location with emotion_object_file_get
and
ecore_file_file_get
functions.
<code c>
label = elm_label_add(table);
elm_object_text_set(label, “File:”);
evas_object_show(label);
elm_table_pack(table, label, 0, 1, 1, 1);
const char *file = emotion_object_file_get(emotion);
label = elm_label_add(table);
elm_object_text_set(label, ecore_file_file_get(file));
evas_object_show(label);
elm_table_pack(table, label, 1, 1, 1, 1);
label = elm_label_add(table);
elm_object_text_set(label, “Location:”);
evas_object_show(label);
elm_table_pack(table, label, 0, 2, 1, 1);
label = elm_label_add(table);
elm_object_text_set(label, ecore_file_dir_get(file));
evas_object_show(label);
elm_table_pack(table, label, 1, 2, 1, 1);
</code>
== Get time position and duration ==
Get video time position and duration using elm_video_play_position_get
and
elm_video_play_length_get
functions. These functions returns double time
values in seconds.
<code c>
label = elm_label_add(table);
elm_object_text_set(label, “Time:”);
evas_object_show(label);
elm_table_pack(table, label, 0, 3, 1, 1);
label = elm_label_add(table);
double position = elm_video_play_position_get(video);
double duration = elm_video_play_length_get(video);
int p_sec = (int) position % 60;
int p_min = position / 60;
int p_hour = position / 3600;
int d_sec = (int) duration % 60;
int d_min = duration / 60;
int d_hour = duration / 3600;
snprintf(buf, sizeof(buf), “%d:%02d:%02d / %d:%02d:%02d”, p_hour, p_min, p_sec, d_hour, d_min, d_sec);
elm_object_text_set(label, buf);
evas_object_show(label);
elm_table_pack(table, label, 1, 3, 1, 1);
evas_object_smart_callback_add(emotion, “position_update”, _player_info_time_update, label);
evas_object_smart_callback_add(emotion, “length_change”, _player_info_time_update, label);
</code>
Here, a callback on both position_update and length_change events are added so
that timings are always up-to-date.
<code c>
static void
_player_info_time_update(void *data, Evas_Object *obj, void *event_info)
{
Evas_Object *emotion = obj, *label = data;
char buf[256];
switch on main item
if (!info)
{
evas_object_smart_callback_del(emotion, “position_update”, _player_info_time_update);
evas_object_smart_callback_del(emotion, “length_change”, _player_info_time_update);
return;
}
update
double position = emotion_object_position_get(emotion);
double duration = emotion_object_play_length_get(emotion);
int p_sec = (int) position % 60;
int p_min = position / 60;
int p_hour = position / 3600;
int d_sec = (int) duration % 60;
int d_min = duration / 60;
int d_hour = duration / 3600;
snprintf(buf, sizeof(buf), “%d:%02d:%02d / %d:%02d:%02d”, p_hour, p_min, p_sec, d_hour, d_min, d_sec);
elm_object_text_set(label, buf);
}
</code>
In this callback, the emotion functions emotion_object_position_get
and
emotion_object_play_length_get
are used instead of elm_video_play_position_get
and
elm_video_play_length_get
. They have the exact same semantics, but are shown
here so that you know that some data exposed through Emotion may also be
available thanks to Elm_Video
: _player_info_status_update
could also
have been called directly after the widget creation as for
_player_info_time_update
.
== Get the video dimensions ==
Finally get the video dimensions using emotion_object_size_get
by giving
width and height pointers as parameters:
<code c>
label = elm_label_add(table);
elm_object_text_set(label, “Size:”);
evas_object_show(label);
elm_table_pack(table, label, 0, 4, 1, 1);
label = elm_label_add(table);
int w, h;
emotion_object_size_get(emotion, &w, &h);
snprintf(buf, sizeof(buf), “%d × %d”, w, h);
elm_object_text_set(label, buf);
evas_object_show(label);
elm_table_pack(table, label, 1, 4, 1, 1);
</code>
All of this is shown in a separate naviframe item.
<code c>
Elm_Object_Item *it = elm_naviframe_item_push(nav, “Information”, NULL, NULL, table, NULL);
elm_naviframe_item_pop_cb_set(it, _player_info_del_cb, NULL);
</code>
The _player_info_del_cb
function is here registered in order to be called
when the naviframe item is popped. This callback sets the global boolean
info
to EINA_FALSE
, and so allows other delete callbacks to be
called.
The whole code__: multimedia.c