[0.3.144] Add PLAYER_DISPLAY_OVERLAY_SYNC_UI type for sync UI and video
[platform/core/api/player.git] / test / player_media_packet_test.c
1 /*
2  * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved
3  *
4  * Licensed under the Apache License, Version 2.0 (the License);
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an AS IS BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 #include <Elementary.h>
18 #include <tbm_surface.h>
19 #include <dlog.h>
20 #include <player.h>
21 #include <glib.h>
22 #include <appcore-efl.h>
23
24 #define KEY_END "XF86Stop"
25 #define MEDIA_FILE_PATH "/home/owner/content/Color.mp4"
26 #ifdef PACKAGE
27 #undef PACKAGE
28 #endif
29 #define PACKAGE "player_test"
30
31 #ifdef LOG_TAG
32 #undef LOG_TAG
33 #endif
34 #define LOG_TAG "PLAYER_TEST"
35
36 static int app_create(void *data);
37 static int app_reset(bundle *b, void *data);
38 static int app_resume(void *data);
39 static int app_pause(void *data);
40 static int app_terminate(void *data);
41
42 struct appcore_ops ops = {
43         .create = app_create,
44         .terminate = app_terminate,
45         .pause = app_pause,
46         .resume = app_resume,
47         .reset = app_reset,
48 };
49
50 typedef struct appdata {
51         Evas_Object *win;
52         Evas_Object *img;
53         media_packet_h packet;
54         Ecore_Pipe *pipe;
55         player_h player_handle;
56         GList *packet_list;
57         GMutex buffer_lock;
58         int w, h;
59 } appdata_s;
60
61 static void win_delete_request_cb(void *data, Evas_Object *obj, void *event_info)
62 {
63         elm_exit();
64 }
65
66 static Eina_Bool keydown_cb(void *data, int type, void *event)
67 {
68         /* appdata_s *ad = data; */
69         Ecore_Event_Key *ev = event;
70
71         LOGD("start");
72
73         if (!strcmp(ev->keyname, KEY_END)) {
74                 /* Let window go to hide state. */
75                 /* elm_win_lower(ad->win); */
76                 LOGD("elm exit");
77                 elm_exit();
78
79                 return ECORE_CALLBACK_DONE;
80         }
81
82         LOGD("done");
83
84         return ECORE_CALLBACK_PASS_ON;
85 }
86
87 static void create_base_gui(appdata_s *ad)
88 {
89         /* Enable GLES Backend */
90         elm_config_accel_preference_set("opengl");
91
92         /* Window */
93         ad->win = elm_win_util_standard_add(PACKAGE, PACKAGE);
94         /* This is not supported in 3.0
95            elm_win_wm_desktop_layout_support_set(ad->win, EINA_TRUE); */
96         elm_win_autodel_set(ad->win, EINA_TRUE);
97 #if 0
98         if (elm_win_wm_rotation_supported_get(ad->win)) {
99                 int rots[4] = { 0, 90, 180, 270 };
100                 elm_win_wm_rotation_available_rotations_set(ad->win, (const int *)(&rots), 4);
101         }
102 #endif
103         evas_object_smart_callback_add(ad->win, "delete,request", win_delete_request_cb, ad);
104
105         Evas *e = evas_object_evas_get(ad->win);
106
107         elm_win_screen_size_get(ad->win, NULL, NULL, &ad->w, &ad->h);
108         LOGD("surface size (%d x %d)\n", ad->w, ad->h);
109
110         /* Image Object */
111         ad->img = evas_object_image_filled_add(e);
112         evas_object_image_size_set(ad->img, ad->w, ad->h);
113         evas_object_size_hint_weight_set(ad->img, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
114         evas_object_show(ad->img);
115
116         elm_win_resize_object_add(ad->win, ad->img);
117
118         /* Show window after base gui is set up */
119         evas_object_show(ad->win);
120 }
121
122 static void _media_packet_video_decoded_cb(media_packet_h packet, void *user_data)
123 {
124         /* This callback function would be called on different thread */
125         appdata_s *ad = user_data;
126
127         if (ad == NULL) {
128                 LOGE("appdata is NULL");
129                 return;
130         }
131
132         g_mutex_lock(&ad->buffer_lock);
133
134         if (ad->pipe == NULL) {
135                 media_packet_destroy(packet);
136                 LOGW("release media packet immediately");
137                 g_mutex_unlock(&ad->buffer_lock);
138                 return;
139         }
140
141         /* add packet list */
142         ad->packet_list = g_list_prepend(ad->packet_list, (gpointer)packet);
143
144         LOGD("packet %p", packet);
145
146         /* Send packet to main thread */
147         ecore_pipe_write(ad->pipe, &packet, sizeof(media_packet_h));
148
149         g_mutex_unlock(&ad->buffer_lock);
150
151         return;
152 }
153
154 static void pipe_cb(void *data, void *buf, unsigned int len)
155 {
156         /* Now, we get a player surface to be set here. */
157         appdata_s *ad = data;
158         tbm_surface_h surface;
159 #ifdef _CAN_USE_NATIVE_SURFACE_TBM
160         Evas_Native_Surface surf;
161 #endif
162         tbm_surface_info_s suf_info;
163         uint32_t plane_idx;
164         int ret;
165         GList *last_item = NULL;
166
167         LOGD("start");
168
169         g_mutex_lock(&ad->buffer_lock);
170
171         /* Destroy previous packet */
172         if (ad->packet) {
173                 ret = media_packet_destroy(ad->packet);
174                 if (ret != MEDIA_PACKET_ERROR_NONE)
175                         LOGE("Failed to destroy media packet. ret (%d)", ret);
176                 ad->packet = NULL;
177         }
178
179         /* remove packet from list */
180         last_item = g_list_last(ad->packet_list);
181         if (last_item) {
182                 /* Get new packet */
183                 ad->packet = (media_packet_h)last_item->data;;
184                 ad->packet_list = g_list_remove(ad->packet_list, ad->packet);
185                 LOGD("ad->packet %p", ad->packet);
186         }
187
188         if (ad->packet == NULL) {
189                 LOGW("NULL packet");
190                 g_mutex_unlock(&ad->buffer_lock);
191                 return;
192         }
193
194         ret = media_packet_get_tbm_surface(ad->packet, &surface);
195         if (ret != MEDIA_PACKET_ERROR_NONE) {
196                 LOGE("Failed to get surface from media packet. ret(0x%x)", ret);
197
198                 media_packet_destroy(ad->packet);
199                 ad->packet = NULL;
200
201                 g_mutex_unlock(&ad->buffer_lock);
202
203                 return;
204         }
205
206         LOGD("surface %p", surface);
207
208         g_mutex_unlock(&ad->buffer_lock);
209
210 #ifdef _CAN_USE_NATIVE_SURFACE_TBM
211         /* Set tbm surface to image native surface */
212         memset(&surf, 0x0, sizeof(surf));
213         surf.version = EVAS_NATIVE_SURFACE_VERSION;
214         surf.type = EVAS_NATIVE_SURFACE_TBM;
215         surf.data.tizen.buffer = surface;
216         surf.data.tizen.rot = 270;
217         evas_object_image_native_surface_set(ad->img, &surf);
218
219         /* Set dirty image region to be redrawn */
220         evas_object_image_data_update_add(ad->img, 0, 0, ad->w, ad->h);
221 #else
222         unsigned char *ptr = NULL;
223         unsigned char *buf_data = NULL;
224         media_format_h format = NULL;
225         media_format_mimetype_e mimetype;
226
227         media_packet_get_format(ad->packet, &format);
228         media_format_get_video_info(format, &mimetype, NULL, NULL, NULL, NULL);
229         media_format_unref(format);
230
231         if (mimetype == MEDIA_FORMAT_I420 || mimetype == MEDIA_FORMAT_NV12 || mimetype == MEDIA_FORMAT_NV12T) {
232
233                 tbm_surface_get_info(surface, &suf_info);
234                 buf_data = (unsigned char *)g_malloc0(suf_info.size);
235                 if (!buf_data) {
236                         LOGE("no free space");
237                         return;
238                 }
239                 ptr = buf_data;
240
241                 for (plane_idx = 0; plane_idx < suf_info.num_planes; plane_idx++) {
242                         memcpy(ptr, suf_info.planes[plane_idx].ptr, suf_info.planes[plane_idx].size);
243                         ptr += suf_info.planes[plane_idx].size;
244                 }
245                 /* dump buf data here, if needed */
246                 g_free(buf_data);
247         }
248 #endif
249
250         LOGD("done");
251
252         return;
253 }
254
255 static int app_create(void *data)
256 {
257         /* Hook to take necessary actions before main event loop starts
258            Initialize UI resources and application's data
259            If this function returns true, the main loop of application starts
260            If this function returns false, the application is terminated */
261         appdata_s *ad = data;
262
263         LOGD("start");
264
265         create_base_gui(ad);
266         ecore_event_handler_add(ECORE_EVENT_KEY_DOWN, keydown_cb, NULL);
267
268         g_mutex_init(&ad->buffer_lock);
269
270         LOGD("done");
271
272         return 0;
273 }
274
275 static int app_pause(void *data)
276 {
277         /* Take necessary actions when application becomes invisible. */
278         appdata_s *ad = (appdata_s *)data;
279         GList *list = NULL;
280         media_packet_h packet = NULL;
281         int ret = PLAYER_ERROR_NONE;
282
283         LOGD("start");
284
285         if (ad == NULL) {
286                 LOGE("appdata is NULL");
287                 return -1;
288         }
289
290         if (ad->player_handle == NULL) {
291                 g_print("player_handle is NULL");
292                 return -1;
293         }
294
295         /* stop render last set frame */
296         evas_object_image_native_surface_set(ad->img, NULL);
297
298         g_mutex_lock(&ad->buffer_lock);
299
300         /* remove ecore pipe */
301         ecore_pipe_del(ad->pipe);
302         ad->pipe = NULL;
303
304         /* remove packet list */
305         list = ad->packet_list;
306         while (list) {
307                 packet = list->data;
308                 list = g_list_next(list);
309
310                 if (!packet) {
311                         LOGW("packet is NULL");
312                 } else {
313                         LOGD("destroy packet %p", packet);
314                         media_packet_destroy(packet);
315                         packet = NULL;
316                         ad->packet_list = g_list_remove(ad->packet_list, packet);
317                 }
318         }
319
320         if (ad->packet_list) {
321                 g_list_free(ad->packet_list);
322                 ad->packet_list = NULL;
323         }
324
325         /* Destroy previous packet */
326         if (ad->packet) {
327                 LOGD("destroy packet %p", ad->packet);
328                 ret = media_packet_destroy(ad->packet);
329                 if (ret != MEDIA_PACKET_ERROR_NONE)
330                         LOGE("Failed to destroy media packet. ret (%d)", ret);
331                 ad->packet = NULL;
332         }
333
334         g_mutex_unlock(&ad->buffer_lock);
335
336         ret = player_unset_media_packet_video_frame_decoded_cb(ad->player_handle);
337         if (ret != PLAYER_ERROR_NONE) {
338                 g_print("player_unset_media_packet_video_frame_decoded_cb failed : 0x%x", ret);
339                 return false;
340         }
341
342         ret = player_unprepare(ad->player_handle);
343         if (ret != PLAYER_ERROR_NONE) {
344                 g_print("player_unprepare failed : 0x%x", ret);
345                 return false;
346         }
347
348         ret = player_destroy(ad->player_handle);
349         if (ret != PLAYER_ERROR_NONE) {
350                 g_print("player_destroy failed : 0x%x", ret);
351                 return false;
352         }
353
354         ad->player_handle = NULL;
355
356         LOGD("done");
357
358         return 0;
359 }
360
361 static int app_resume(void *data)
362 {
363         LOGD("start");
364
365         LOGD("done");
366
367         return 0;
368 }
369
370 static int app_reset(bundle *b, void *data)
371 {
372         /* Take necessary actions when application becomes visible. */
373         appdata_s *ad = (appdata_s *)data;
374         int ret = PLAYER_ERROR_NONE;
375
376         LOGD("start");
377
378         if (ad == NULL) {
379                 LOGE("appdata is NULL");
380                 return -1;
381         }
382
383         /* create ecore pipe */
384         ad->pipe = ecore_pipe_add(pipe_cb, ad);
385
386         ret = player_create(&ad->player_handle);
387         if (ret != PLAYER_ERROR_NONE) {
388                 LOGE("player_create failed : 0x%x", ret);
389                 return -1;
390         }
391
392         ret = player_set_media_packet_video_frame_decoded_cb(ad->player_handle, _media_packet_video_decoded_cb, ad);
393         if (ret != PLAYER_ERROR_NONE) {
394                 LOGE("player_set_media_packet_video_frame_decoded_cb failed : 0x%x", ret);
395                 goto FAILED;
396         }
397
398         ret = player_set_display(ad->player_handle, PLAYER_DISPLAY_TYPE_NONE, NULL);
399         if (ret != PLAYER_ERROR_NONE) {
400                 LOGE("player_set_display failed : 0x%x", ret);
401                 goto FAILED;
402         }
403
404         ret = player_set_uri(ad->player_handle, MEDIA_FILE_PATH);
405         if (ret != PLAYER_ERROR_NONE) {
406                 LOGE("player_set_uri failed : 0x%x", ret);
407                 goto FAILED;
408         }
409
410         ret = player_prepare(ad->player_handle);
411         if (ret != PLAYER_ERROR_NONE) {
412                 LOGE("player prepare failed : 0x%x", ret);
413                 goto FAILED;
414         }
415
416         ret = player_start(ad->player_handle);
417         if (ret != PLAYER_ERROR_NONE) {
418                 LOGE("player start failed : 0x%x", ret);
419                 goto FAILED;
420         }
421
422         LOGD("done");
423
424         return 0;
425
426 FAILED:
427         if (ad->player_handle) {
428                 player_destroy(ad->player_handle);
429                 ad->player_handle = NULL;
430         }
431
432         return -1;
433
434 }
435
436 static int app_terminate(void *data)
437 {
438         /* Release all resources. */
439         appdata_s *ad = (appdata_s *)data;
440
441         LOGD("start");
442
443         if (ad == NULL) {
444                 LOGE("appdata is NULL");
445                 return -1;
446         }
447
448         app_pause(data);
449
450         g_mutex_clear(&ad->buffer_lock);
451
452         LOGD("done");
453
454         return 0;
455 }
456
457 int main(int argc, char *argv[])
458 {
459         int ret = 0;
460         static appdata_s ad = {0, };
461
462         LOGD("start");
463
464         memset(&ad, 0x0, sizeof(appdata_s));
465
466         LOGD("call appcore_efl_main");
467
468         ops.data = &ad;
469
470         ret = appcore_efl_main(PACKAGE, &argc, &argv, &ops);
471
472         LOGD("appcore_efl_main() ret = 0x%x", ret);
473
474         return ret;
475 }