efl/src/modules/ethumb/emotion/emotion.c

581 lines
13 KiB
C

#ifdef HAVE_CONFIG_H
#include "config.h"
#else
#define EFL_EO_API_SUPPORT
#define EFL_BETA_API_SUPPORT
#endif
#include "Ethumb.h"
#include "Ethumb_Plugin.h"
#define EDJE_EDIT_IS_UNSTABLE_AND_I_KNOW_ABOUT_IT 1
#include <stdio.h>
#include <stdlib.h>
#include <Eo.h>
#include <Eina.h>
#include <Eet.h>
#include <Ecore_File.h>
#include <Evas.h>
#include <Ecore.h>
#include <Edje.h>
#include <Edje_Edit.h>
#include <Emotion.h>
static Eina_Prefix *_pfx = NULL;
static int _init_count = 0;
static int _log_dom = -1;
#define DBG(...) EINA_LOG_DOM_DBG(_log_dom, __VA_ARGS__)
#define INF(...) EINA_LOG_DOM_INFO(_log_dom, __VA_ARGS__)
#define WRN(...) EINA_LOG_DOM_WARN(_log_dom, __VA_ARGS__)
#define ERR(...) EINA_LOG_DOM_ERR(_log_dom, __VA_ARGS__)
struct _emotion_plugin
{
unsigned int fps;
double ptotal, len, pi;
double total_time, tmp_time;
unsigned int pcount;
unsigned int frnum;
unsigned int okfr;
Eina_Bool first;
Eet_File *ef;
Evas_Object *video;
Evas_Object *edje_frame;
Ethumb *e;
int w, h;
};
static Eina_Bool _frame_grab(void *data);
static Eina_Bool _frame_grab_single(void *data);
static void
_resize_movie(struct _emotion_plugin *_plugin)
{
Ethumb *e = _plugin->e;
double ratio;
int w, h;
int fx, fy, fw, fh;
ratio = emotion_object_ratio_get(_plugin->video);
ethumb_calculate_aspect_from_ratio(e, ratio, &w, &h);
ethumb_calculate_fill_from_ratio(e, ratio, &fx, &fy, &fw, &fh);
DBG("size: w=%d, h=%d fill: x=%d, y=%d, w=%d, h=%d", w, h, fx, fy, fw, fh);
_plugin->w = w;
_plugin->h = h;
ethumb_plugin_image_resize(e, _plugin->w, _plugin->h);
if (_plugin->edje_frame)
{
evas_object_resize(_plugin->edje_frame, fw, fh);
evas_object_move(_plugin->edje_frame, fx, fy);
}
else
{
evas_object_resize(_plugin->video, fw, fh);
evas_object_move(_plugin->video, fx, fy);
}
emotion_object_audio_mute_set(_plugin->video, 1);
}
static void
_frame_decode_cb(void *data, const Efl_Event *event EINA_UNUSED)
{
struct _emotion_plugin *_plugin = data;
if (_plugin->ef)
_frame_grab(data);
else
_frame_grab_single(data);
return;
}
static void
_frame_resized_cb(void *data, const Efl_Event *event EINA_UNUSED)
{
_resize_movie(data);
}
static void
_video_stopped_cb(void *data, const Efl_Event *event EINA_UNUSED)
{
struct _emotion_plugin *_plugin = data;
_plugin->okfr = 0;
_plugin->pi = 0;
_plugin->ptotal = 0;
_plugin->first = EINA_FALSE;
_plugin->total_time = _plugin->tmp_time;
}
static void
_video_pos_set(struct _emotion_plugin *_plugin)
{
double pos;
double interval;
pos = ethumb_video_start_get(_plugin->e);
interval = ethumb_video_interval_get(_plugin->e);
_plugin->len = emotion_object_play_length_get(_plugin->video);
if (_plugin->len > 0)
_plugin->first = EINA_TRUE;
if ((pos <= 0) || (pos >= 1))
_plugin->pi = (0.1 * _plugin->len) +
(_plugin->pcount * _plugin->len * interval);
else
_plugin->pi = (pos * _plugin->len) +
(_plugin->pcount * _plugin->len * interval);
emotion_object_position_set(_plugin->video, _plugin->pi);
}
static int
_setup_thumbnail(struct _emotion_plugin *_plugin)
{
char buf[4096];
Evas *evas;
Evas_Object *edje;
unsigned int i;
const char *thumb_path;
ethumb_thumb_path_get(_plugin->e, &thumb_path, NULL);
evas = ethumb_evas_get(_plugin->e);
if (!edje_file_group_exists(thumb_path, "movie/thumb"))
{
ERR("no group 'movie/thumb' found in file=%s", thumb_path);
goto exit_error;
}
edje = edje_edit_object_add(evas);
edje_object_file_set(edje, thumb_path, "movie/thumb");
if (!edje_object_part_exists(edje, "image"))
{
ERR("no 'image' part found in file=%s, group=movie/thumb", thumb_path);
evas_object_del(edje);
goto exit_error;
}
if (!edje_edit_program_exist(edje, "animate"))
{
ERR("no 'animate' program found in file=%s, group=movie/thumb",
thumb_path);
evas_object_del(edje);
goto exit_error;
}
for (i = 0; i < _plugin->frnum; i++)
{
snprintf(buf, sizeof(buf), "images/%u", i);
edje_edit_image_data_add(edje, buf, i);
if (i == 0)
edje_edit_state_image_set(edje, "image", "default", 0.00, buf);
else
edje_edit_state_tween_add(edje, "image", "default", 0.00, buf);
}
edje_edit_program_transition_time_set(edje, "animate",
_plugin->total_time);
edje_edit_program_transition_time_set(edje, "animate_loop",
_plugin->total_time);
edje_edit_group_min_w_set(edje, _plugin->w);
edje_edit_group_max_w_set(edje, _plugin->w);
edje_edit_group_min_h_set(edje, _plugin->h);
edje_edit_group_max_h_set(edje, _plugin->h);
edje_edit_save(edje);
evas_object_del(edje);
return 1;
exit_error:
return 0;
}
static void
_finish_thumb_obj(void *data)
{
struct _emotion_plugin *_plugin = data;
evas_object_del(_plugin->video);
if (_plugin->edje_frame) evas_object_del(_plugin->edje_frame);
free(_plugin);
}
static void
_finish_thumb_generation(struct _emotion_plugin *_plugin, int success)
{
int r = 0;
efl_event_callback_del(_plugin->video, EFL_CANVAS_VIDEO_EVENT_FRAME_RESIZE, _frame_resized_cb, _plugin);
efl_event_callback_del(_plugin->video, EFL_CANVAS_VIDEO_EVENT_FRAME_DECODE, _frame_decode_cb, _plugin);
efl_event_callback_del(_plugin->video, EFL_CANVAS_VIDEO_EVENT_PLAYBACK_STOP, _video_stopped_cb, _plugin);
emotion_object_play_set(_plugin->video, 0);
if (_plugin->ef)
{
Eet_Error err = eet_close(_plugin->ef);
if (err != EET_ERROR_NONE)
{
ERR("Error writing Eet thumbnail file: %d", err);
success = EINA_FALSE;
}
}
if (success)
r = _setup_thumbnail(_plugin);
ethumb_finished_callback_call(_plugin->e, r);
ecore_job_add(_finish_thumb_obj, _plugin);
}
static Eina_Bool
_frame_grab_single(void *data)
{
struct _emotion_plugin *_plugin = data;
Ethumb *e = _plugin->e;
double p;
if (_plugin->len <= 0)
{
_video_pos_set(_plugin);
return EINA_TRUE;
}
p = emotion_object_position_get(_plugin->video);
_plugin->okfr++;
if (_plugin->okfr < 5)
return EINA_TRUE;
DBG("saving static thumbnail at position=%f (intended=%f)", p, _plugin->pi);
ethumb_image_save(e);
efl_event_callback_del(_plugin->video, EFL_CANVAS_VIDEO_EVENT_FRAME_RESIZE, _frame_resized_cb, _plugin);
emotion_object_play_set(_plugin->video, 0);
evas_object_del(_plugin->video);
if (_plugin->edje_frame) evas_object_del(_plugin->edje_frame);
free(_plugin);
ethumb_finished_callback_call(e, 1);
return EINA_FALSE;
}
static Eina_Bool
_frame_grab(void *data)
{
struct _emotion_plugin *_plugin = data;
Ethumb *e = _plugin->e;
char buf[4096];
const void *pixels;
double p;
if (_plugin->len <= 0)
{
_video_pos_set(_plugin);
return EINA_TRUE;
}
p = emotion_object_position_get(_plugin->video);
if (p < _plugin->pi)
return EINA_TRUE;
if (_plugin->first)
{
_plugin->pi = p;
_plugin->first = EINA_FALSE;
}
if (p > _plugin->pi + _plugin->ptotal)
{
_plugin->total_time += _plugin->tmp_time;
if (_plugin->pcount >= ethumb_video_ntimes_get(e))
{
_finish_thumb_generation(_plugin, EINA_TRUE);
return EINA_FALSE;
}
else
{
_plugin->pcount++;
_video_pos_set(_plugin);
return EINA_TRUE;
}
}
_plugin->tmp_time = p - _plugin->pi;
if (_plugin->ef)
{
Ecore_Evas *ee = ethumb_ecore_evas_get(e);
int quality, compress;
quality = ethumb_thumb_quality_get(e);
compress = ethumb_thumb_compress_get(e);
pixels = ecore_evas_buffer_pixels_get(ee);
snprintf(buf, sizeof(buf), "images/%d", _plugin->frnum);
eet_data_image_write(_plugin->ef, buf, pixels, _plugin->w, _plugin->h,
0, compress, quality, quality);
_plugin->frnum++;
}
return EINA_TRUE;
}
static void
_generate_animated_thumb(struct _emotion_plugin *_plugin)
{
const char *thumb_path;
char *thumb_dir;
char buf[4096];
Ethumb *e = _plugin->e;
snprintf(buf, sizeof(buf),
"%s/ethumb/modules/emotion/" MODULE_ARCH "/template.edj",
eina_prefix_lib_get(_pfx));
ethumb_thumb_path_get(e, &thumb_path, NULL);
thumb_dir = ecore_file_dir_get(thumb_path);
ecore_file_mkpath(thumb_dir);
free(thumb_dir);
if (!eina_file_copy(buf, thumb_path, 0, NULL, NULL))
{
ERR("Couldn't copy file '%s' to '%s'", buf, thumb_path);
ERR("could not open '%s'", thumb_path);
_finish_thumb_generation(_plugin, 0);
return;
}
_plugin->ef = eet_open(thumb_path, EET_FILE_MODE_READ_WRITE);
if (!_plugin->ef)
{
ERR("could not open '%s'", thumb_path);
_finish_thumb_generation(_plugin, 0);
}
}
static void *
_thumb_generate(Ethumb *e)
{
Evas_Object *o;
int r;
const char *file;
Ethumb_Thumb_Format f;
double dv;
struct _emotion_plugin *_plugin = calloc(1, sizeof(struct _emotion_plugin));
const char *ffile, *fgroup, *fswallow;
o = emotion_object_add(ethumb_evas_get(e));
r = emotion_object_init(o, NULL);
if (!r)
{
ERR("Could not initialize emotion object.");
evas_object_del(o);
ethumb_finished_callback_call(e, 0);
free(_plugin);
return NULL;
}
_plugin->video = o;
ethumb_file_get(e, &file, NULL);
f = ethumb_thumb_format_get(e);
emotion_object_file_set(o, file);
emotion_object_audio_mute_set(o, EINA_TRUE);
_plugin->video = o;
_plugin->e = e;
dv = ethumb_video_ntimes_get(e);
if (dv > 0.0) _plugin->ptotal = ethumb_video_time_get(e) / dv;
else _plugin->ptotal = 0.0;
_plugin->pcount = 1;
_resize_movie(_plugin);
efl_event_callback_add
(o, EFL_CANVAS_VIDEO_EVENT_FRAME_DECODE, _frame_decode_cb, _plugin);
efl_event_callback_add
(o, EFL_CANVAS_VIDEO_EVENT_FRAME_RESIZE, _frame_resized_cb, _plugin);
efl_event_callback_add
(o, EFL_CANVAS_VIDEO_EVENT_PLAYBACK_STOP, _video_stopped_cb, _plugin);
if (f == ETHUMB_THUMB_EET)
{
_generate_animated_thumb(_plugin);
}
_video_pos_set(_plugin);
emotion_object_play_set(o, 1);
evas_object_show(o);
ethumb_frame_get(e, &ffile, &fgroup, &fswallow);
if (ffile && fgroup && fswallow)
{
Evas_Object *ed = edje_object_add(ethumb_evas_get(e));
if (!ed)
{
ERR("could not create edje frame object.");
return _plugin;
}
if (!edje_object_file_set(ed, ffile, fgroup))
{
ERR("could not load frame theme.");
evas_object_del(ed);
return _plugin;
}
edje_object_part_swallow(ed, fswallow, o);
if (!edje_object_part_swallow_get(ed, fswallow))
{
ERR("could not swallow video to edje frame.");
evas_object_del(ed);
return _plugin;
}
evas_object_show(ed);
_plugin->edje_frame = ed;
}
return _plugin;
}
static void
_thumb_cancel(Ethumb *e EINA_UNUSED, void *data)
{
struct _emotion_plugin *_plugin = data;
if (_plugin->ef) eet_close(_plugin->ef);
evas_object_del(_plugin->video);
if (_plugin->edje_frame) evas_object_del(_plugin->edje_frame);
free(_plugin);
}
static const char *extensions[] = { /* based on emotion's list */
"264",
"3g2",
"3gp",
"3gp2",
"3gpp",
"3gpp2",
"3p2",
"asf",
"avi",
"bdm",
"bdmv",
"clpi",
"clp",
"fla",
"flv",
"m1v",
"m2v",
"m2t",
"m4v",
"mkv",
"mov",
"mp2",
"mp2ts",
"mp4",
"mpe",
"mpeg",
"mpg",
"mpl",
"mpls",
"mts",
"mxf",
"nut",
"nuv",
"ogg",
"ogm",
"ogv",
"rm",
"rmj",
"rmm",
"rms",
"rmx",
"rmvb",
"swf",
"ts",
"weba",
"webm",
"wmv",
NULL
};
static const Ethumb_Plugin plugin =
{
ETHUMB_PLUGIN_API_VERSION,
"emotion",
extensions,
_thumb_generate,
_thumb_cancel
};
static Eina_Bool
_module_init(void)
{
if (_init_count > 0)
{
_init_count++;
return EINA_TRUE;
}
_log_dom = eina_log_domain_register("ethumb_emotion", EINA_COLOR_GREEN);
if (_log_dom < 0)
{
EINA_LOG_ERR("Could not register log domain: ethumb_emotion");
goto error_log;
}
_pfx = eina_prefix_new(NULL, ethumb_init,
"ETHUMB", "ethumb", "checkme",
PACKAGE_BIN_DIR, PACKAGE_LIB_DIR,
PACKAGE_DATA_DIR, PACKAGE_DATA_DIR);
if (!_pfx)
{
ERR("Could not get ethumb installation prefix.");
goto error_pfx;
}
emotion_init();
ethumb_plugin_register(&plugin);
_init_count = 1;
return EINA_TRUE;
error_pfx:
eina_log_domain_unregister(_log_dom);
_log_dom = -1;
error_log:
return EINA_FALSE;
}
static void
_module_shutdown(void)
{
if (_init_count <= 0)
{
EINA_LOG_ERR("Init count not greater than 0 in shutdown.");
return;
}
_init_count--;
if (_init_count > 0) return;
ethumb_plugin_unregister(&plugin);
emotion_shutdown();
eina_prefix_free(_pfx);
_pfx = NULL;
eina_log_domain_unregister(_log_dom);
_log_dom = -1;
}
EINA_MODULE_INIT(_module_init);
EINA_MODULE_SHUTDOWN(_module_shutdown);