Welcome Ethumb, it's ready to get out of PROTO.
[framework/uifw/ethumb.git] / src / plugins / emotion / emotion.c
1 #include "Ethumb.h"
2 #include "Ethumb_Plugin.h"
3 #include "config.h"
4
5 #include <stdio.h>
6 #include <stdlib.h>
7 #include <Eina.h>
8 #include <Eet.h>
9 #include <Ecore_File.h>
10 #include <Evas.h>
11 #include <Edje.h>
12 #include <Edje_Edit.h>
13 #include <Emotion.h>
14
15 struct _emotion_plugin
16 {
17    int fps;
18    double ptotal, len, pi;
19    double total_time, tmp_time;
20    int pcount;
21    int frnum;
22    int first;
23    Eet_File *ef;
24    Evas_Object *video;
25    Ethumb *e;
26    int w, h;
27 };
28
29 static void
30 _resize_movie(struct _emotion_plugin *_plugin)
31 {
32    Ethumb *e = _plugin->e;
33    double ratio;
34    int w, h;
35    int fx, fy, fw, fh;
36
37    ratio = emotion_object_ratio_get(_plugin->video);
38    ethumb_calculate_aspect_from_ratio(e, ratio, &w, &h);
39    ethumb_calculate_fill_from_ratio(e, ratio, &fx, &fy, &fw, &fh);
40
41    _plugin->w = w;
42    _plugin->h = h;
43
44    ethumb_plugin_image_resize(e, _plugin->w, _plugin->h);
45
46    evas_object_resize(_plugin->video, fw, fh);
47    evas_object_move(_plugin->video, fx, fy);
48    emotion_object_audio_mute_set(_plugin->video, 1);
49 }
50
51 static void
52 _frame_resized_cb(void *data, Evas_Object *o __UNUSED__, void *event_info __UNUSED__)
53 {
54    _resize_movie(data);
55 }
56
57 static void
58 _video_stopped_cb(void *data, Evas_Object *o __UNUSED__, void *event_info __UNUSED__)
59 {
60    struct _emotion_plugin *_plugin = data;
61
62    _plugin->pi = 0;
63    _plugin->ptotal = 0;
64    _plugin->first = 0;
65    _plugin->total_time = _plugin->tmp_time;
66 }
67
68 static void
69 _video_pos_set(struct _emotion_plugin *_plugin)
70 {
71    double pos;
72    double interval;
73
74    pos = ethumb_video_start_get(_plugin->e);
75    interval = ethumb_video_interval_get(_plugin->e);
76    _plugin->len = emotion_object_play_length_get(_plugin->video);
77
78    if (_plugin->len > 0)
79      _plugin->first = 1;
80
81    if (pos <=0 || pos >= 1)
82      _plugin->pi = 0.2 * _plugin->len + _plugin->pcount *
83         _plugin->len * interval;
84    else
85      _plugin->pi = pos * _plugin->len + _plugin->pcount *
86         _plugin->len * interval;
87
88    emotion_object_position_set(_plugin->video, _plugin->pi);
89 }
90
91 static int
92 _setup_thumbnail(struct _emotion_plugin *_plugin)
93 {
94    char buf[4096];
95    Evas *evas;
96    Evas_Object *edje;
97    int i;
98    const char *thumb_path;
99
100    ethumb_thumb_path_get(_plugin->e, &thumb_path, NULL);
101    evas = ethumb_evas_get(_plugin->e);
102
103    if (!edje_file_group_exists(thumb_path, "movie/thumb"))
104      {
105         fprintf(stderr, "ERROR: no group 'movie/thumb' found.\n");
106         goto exit_error;
107      }
108
109    edje = edje_object_add(evas);
110    edje_object_file_set(edje, thumb_path, "movie/thumb");
111    if (!edje_object_part_exists(edje, "image"))
112      {
113         fprintf(stderr, "ERROR: no 'image' part found.\n");
114         evas_object_del(edje);
115         goto exit_error;
116      }
117    if (!edje_edit_program_exist(edje, "animate"))
118      {
119         fprintf(stderr, "ERROR: no 'animate' program found.\n");
120         evas_object_del(edje);
121         goto exit_error;
122      }
123
124    for (i = 0; i < _plugin->frnum; i++)
125      {
126         snprintf(buf, sizeof(buf), "images/%d", i);
127         edje_edit_image_data_add(edje, buf, i);
128         if (i == 0)
129           edje_edit_state_image_set(edje, "image", "default 0.00", buf);
130         else
131           edje_edit_state_tween_add(edje, "image", "default 0.00", buf);
132      }
133
134    edje_edit_program_transition_time_set(edje, "animate",
135                                          _plugin->total_time);
136    edje_edit_program_transition_time_set(edje, "animate_loop",
137                                          _plugin->total_time);
138    edje_edit_group_min_w_set(edje, _plugin->w);
139    edje_edit_group_max_w_set(edje, _plugin->w);
140    edje_edit_group_min_h_set(edje, _plugin->h);
141    edje_edit_group_max_h_set(edje, _plugin->h);
142    edje_edit_save(edje);
143
144    evas_object_del(edje);
145
146    return 1;
147
148 exit_error:
149    return 0;
150 }
151
152 static void
153 _finish_thumb_generation(struct _emotion_plugin *_plugin, int success)
154 {
155    int r = 0;
156    evas_object_smart_callback_del(_plugin->video, "frame_resize",
157                                   _frame_resized_cb);
158    emotion_object_play_set(_plugin->video, 0);
159    evas_object_del(_plugin->video);
160    if (_plugin->ef)
161      eet_close(_plugin->ef);
162
163    if (success)
164      r = _setup_thumbnail(_plugin);
165
166    free(_plugin);
167    ethumb_finished_callback_call(_plugin->e, r);
168 }
169
170 static int
171 _frame_grab_single(void *data)
172 {
173    struct _emotion_plugin *_plugin = data;
174    Ethumb *e = _plugin->e;
175    double p;
176
177    if (_plugin->len <= 0)
178      {
179         _video_pos_set(_plugin);
180         return EINA_TRUE;
181      }
182
183    p = emotion_object_position_get(_plugin->video);
184    if (p < _plugin->pi)
185      return EINA_TRUE;
186
187    ethumb_image_save(e);
188
189    evas_object_smart_callback_del(_plugin->video, "frame_resize",
190                                   _frame_resized_cb);
191    emotion_object_play_set(_plugin->video, 0);
192    evas_object_del(_plugin->video);
193    free(_plugin);
194    ethumb_finished_callback_call(e, 1);
195
196    return EINA_FALSE;
197 }
198
199 static int
200 _frame_grab(void *data)
201 {
202    struct _emotion_plugin *_plugin = data;
203    Ethumb *e = _plugin->e;
204    char buf[4096];
205    const void *pixels;
206    double p;
207
208    if (_plugin->len <= 0)
209      {
210         _video_pos_set(_plugin);
211         return EINA_TRUE;
212      }
213
214    p = emotion_object_position_get(_plugin->video);
215    if (p < _plugin->pi)
216      return EINA_TRUE;
217
218    if (_plugin->first)
219      {
220         _plugin->pi = p;
221         _plugin->first = 0;
222      }
223
224    if (p > _plugin->pi + _plugin->ptotal)
225      {
226         _plugin->total_time += _plugin->tmp_time;
227         if (_plugin->pcount >= ethumb_video_ntimes_get(e))
228           {
229              _finish_thumb_generation(_plugin, EINA_TRUE);
230              return EINA_FALSE;
231           }
232         else
233           {
234              _plugin->pcount++;
235              _video_pos_set(_plugin);
236              return EINA_TRUE;
237           }
238      }
239
240    _plugin->tmp_time = p - _plugin->pi;
241
242    if (_plugin->ef)
243      {
244         Ecore_Evas *ee = ethumb_ecore_evas_get(e);
245         int quality, compress;
246
247         quality = ethumb_thumb_quality_get(e);
248         compress = ethumb_thumb_compress_get(e);
249
250         pixels = ecore_evas_buffer_pixels_get(ee);
251         snprintf(buf, sizeof(buf), "images/%d", _plugin->frnum);
252         eet_data_image_write(_plugin->ef, buf, pixels, _plugin->w, _plugin->h,
253                              0, compress, quality, quality);
254         _plugin->frnum++;
255      }
256
257    return EINA_TRUE;
258 }
259
260 static void
261 _generate_animated_thumb(struct _emotion_plugin *_plugin)
262 {
263    const char *thumb_path;
264    char *thumb_dir;
265    char buf[4096];
266    Ethumb *e = _plugin->e;
267
268    snprintf(buf, sizeof(buf), "%s/data/emotion_template.edj", PLUGINSDIR);
269    ethumb_thumb_path_get(e, &thumb_path, NULL);
270    thumb_dir = ecore_file_dir_get(thumb_path);
271    ecore_file_mkpath(thumb_dir);
272    free(thumb_dir);
273    ecore_file_cp(buf, thumb_path);
274    _plugin->ef = eet_open(thumb_path, EET_FILE_MODE_READ_WRITE);
275    if (!_plugin->ef)
276      {
277         fprintf(stderr, "ERROR: could not open '%s'\n", thumb_path);
278         _finish_thumb_generation(_plugin, 0);
279      }
280
281    ecore_timer_add(1.0 / ethumb_video_fps_get(e), _frame_grab, _plugin);
282 }
283
284 static void
285 _generate_thumb(Ethumb *e)
286 {
287    Evas_Object *o;
288    int r;
289    const char *file;
290    float start;
291    Ethumb_Thumb_Format f;
292    struct _emotion_plugin *_plugin = calloc(sizeof(struct _emotion_plugin), 1);
293
294    o = emotion_object_add(ethumb_evas_get(e));
295    r = emotion_object_init(o, "xine");
296    if (!r)
297      {
298         fprintf(stderr, "ERROR: could not start emotion using gstreamer"
299                 " plugin.\n");
300         evas_object_del(o);
301         ethumb_finished_callback_call(e, 0);
302         free(_plugin);
303         return;
304      }
305
306    _plugin->video = o;
307
308    ethumb_file_get(e, &file, NULL);
309    start = ethumb_video_start_get(e);
310    f = ethumb_thumb_format_get(e);
311
312    emotion_object_file_set(o, file);
313
314    _plugin->video = o;
315    _plugin->e = e;
316
317    _plugin->ptotal = ethumb_video_time_get(e) / ethumb_video_ntimes_get(e);
318    _plugin->pcount = 1;
319
320    _resize_movie(_plugin);
321    evas_object_smart_callback_add(o, "frame_resize",
322                                   _frame_resized_cb, _plugin);
323    evas_object_smart_callback_add(o, "decode_stop",
324                                   _video_stopped_cb, _plugin);
325
326    if (f == ETHUMB_THUMB_EET)
327      {
328         _generate_animated_thumb(_plugin);
329      }
330    else
331      {
332         ecore_timer_add(0.1, _frame_grab_single, _plugin);
333      }
334
335    _video_pos_set(_plugin);
336    emotion_object_play_set(o, 1);
337    evas_object_show(o);
338 }
339
340 EAPI Ethumb_Plugin *
341 ethumb_plugin_get(void)
342 {
343    static const char *extensions[] = { "avi", "mp4", "ogv", "mov", NULL };
344    static Ethumb_Plugin plugin =
345      {
346         extensions,
347         _generate_thumb,
348      };
349
350    return &plugin;
351 }
352
353 static Eina_Bool
354 _module_init(void)
355 {
356    return EINA_TRUE;
357 }
358
359 static void
360 _module_shutdown(void)
361 {
362 }
363
364 EINA_MODULE_INIT(_module_init);
365 EINA_MODULE_SHUTDOWN(_module_shutdown);