14535ae552c3a8b23f20edfd58ca0b74cabd0b8f
[platform/framework/web/provider.git] / sample / org.tizen.live-video / src / CVideo.cpp
1 /*
2  * Copyright 2013  Samsung Electronics Co., Ltd
3  *
4  * Licensed under the Flora License, Version 1.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://floralicense.org/license/
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
19 #include <X11/Xlib.h>
20 #include <Ecore.h>
21 #include <Ecore_X.h>
22
23 #include <dlog.h>
24
25 #include <provider.h>
26 #include <provider_buffer.h>
27
28 #include <mm_types.h>
29 #include <mm_error.h>
30 #include <mm_message.h>
31 #include <mm_player.h>
32
33 #include "debug.h"
34 #include "CWindow.h"
35 #include "CVideo.h"
36 #include "CModel.h"
37
38 Eina_List *CVideo::s_pList = NULL;
39
40
41 CVideo *CVideo::Find(enum target_type type, const char *id)
42 {
43         Eina_List *l;
44         void *item;
45         CVideo *video;
46
47         EINA_LIST_FOREACH(s_pList, l, item) {
48                 video = (CVideo *)item;
49
50                 if (video->Type() == type && !strcmp(video->Id(), id))
51                         return video;
52         }
53
54         return NULL;
55 }
56
57 CVideo *CVideo::Create(enum target_type type, const char *id, int w, int h)
58 {
59         CVideo *video;
60         struct livebox_buffer *pBuffer;
61
62         if (!ecore_x_damage_query()) {
63                 ErrPrint("Damage event is not supported\n");
64                 return NULL;
65         }
66
67         try {
68                 video = new CVideo(type, w, h);
69         } catch (...) {
70                 ErrPrint("Failed to create a video instance\n");
71                 return NULL;
72         }
73
74         video->m_sId = strdup(id);
75         if (!video->m_sId) {
76                 ErrPrint("Heap: %s\n", strerror(errno));
77                 video->Destroy();
78                 return NULL;    
79         }
80
81         pBuffer = provider_buffer_acquire(video->Type(), PKGNAME, video->Id(),
82                                                 video->Width(), video->Height(), sizeof(int),
83                                                 CVideo::s_BufferEventHandler, video);
84         if (!pBuffer) {
85                 ErrPrint("Failed to acquire buffer handle\n");
86                 video->Destroy();
87                 return NULL;
88         }
89
90         /*!
91          * \note
92          * this function must has to be called before add an item to the s_pList
93          */
94         video->SetBuffer(pBuffer);
95
96         s_pList = eina_list_append(s_pList, video);
97         return video;
98 }
99
100 Eina_Bool CVideo::s_DamageEventHandler(void *data, int type, void *event)
101 {
102         CVideo *video = (CVideo *)data;
103         Ecore_X_Event_Damage *e = (Ecore_X_Event_Damage *)event;
104
105         if (e->drawable == video->PixmapId()) {
106                 switch (video->Type()) {
107                 case TYPE_LB:
108                         provider_send_updated(PKGNAME, video->Id(), video->Width(), video->Height(), 1.0f, NULL, NULL);
109                         break;
110                 case TYPE_PD:
111                         provider_send_desc_updated(PKGNAME, video->Id(), NULL);
112                         break;
113                 default:
114                         ErrPrint("Unknown video type\n");
115                         break;
116                 }
117
118                 video->Update();
119         }
120
121         return ECORE_CALLBACK_PASS_ON;
122 }
123
124 int CVideo::Update(void)
125 {
126         ecore_x_damage_subtract(m_vDamage, None, None);
127         return 0;
128 }
129
130 void CVideo::SetBuffer(struct livebox_buffer *pBuffer)
131 {
132         if (!pBuffer) {
133                 if (m_pDamageHandler)
134                         ecore_event_handler_del(m_pDamageHandler);
135
136                 m_pDamageHandler = NULL;
137
138                 if (m_vDamage)
139                         ecore_x_damage_free(m_vDamage);
140
141                 m_vDamage = 0;
142                 return;
143         }
144
145         m_pBuffer = pBuffer;
146
147         m_nId = provider_buffer_pixmap_id(m_pBuffer);
148         if (m_nId == 0) {
149                 ErrPrint("Failed to get pixmap\n");
150                 return;
151         }
152
153         m_pDamageHandler = ecore_event_handler_add(ECORE_X_EVENT_DAMAGE_NOTIFY, CVideo::s_DamageEventHandler, this);
154         if (!m_pDamageHandler) {
155                 ErrPrint("Failed to add a event handler\n");
156                 return;
157         }
158
159         m_vDamage = ecore_x_damage_new(m_nId, ECORE_X_DAMAGE_REPORT_RAW_RECTANGLES);
160         if (!m_vDamage) {
161                 ErrPrint("Failed to create a new damage object\n");
162                 return;
163         }
164
165         DbgPrint("Prepare callback\n");
166         Clear();
167 }
168
169 int CVideo::s_BufferEventHandler(struct livebox_buffer *buffer, enum buffer_event event, double timestamp, double x, double y, void *data)
170 {
171         CVideo *video = (CVideo *)data;
172         int ix;
173         int iy;
174
175         ix = video->Width() * x;
176         iy = video->Height() * y;
177
178         switch (event) {
179         case BUFFER_EVENT_ENTER:
180                 break;
181         case BUFFER_EVENT_LEAVE:
182                 break;
183         case BUFFER_EVENT_DOWN:
184                 DbgPrint("Down: %dx%d\n", ix, iy);
185                 break;
186         case BUFFER_EVENT_MOVE:
187                 break;
188         case BUFFER_EVENT_UP:
189                 DbgPrint("Up: %dx%d\n", ix, iy);
190                 break;
191         default:
192                 break;
193         }
194
195         return 0;
196 }
197
198 int CVideo::Destroy(void)
199 {
200         int ret;
201         DbgPrint("Destroy a video object\n");
202
203         s_pList = eina_list_remove(s_pList, this);
204
205         Stop(); /*!< Just try to stop playing */
206
207         if (m_nId)
208                 ecore_x_damage_free(m_vDamage);
209
210         if (m_pDamageHandler)
211                 ecore_event_handler_del(m_pDamageHandler);
212
213         free(m_sId);
214
215         ret = provider_buffer_release(m_pBuffer);
216         DbgPrint("release: %d\n", ret);
217         delete this;
218         return 0;
219 }
220
221 int CVideo::Resize(int w, int h)
222 {
223         struct livebox_buffer *pBuffer;
224
225         if (m_nWidth == w && m_nHeight == h) {
226                 DbgPrint("Size has no changes\n");
227                 return 0;
228         }
229
230         m_nWidth = w;
231         m_nHeight = h;
232
233         if (!m_pBuffer) {
234                 ErrPrint("Buffer is not available\n");
235                 return -EINVAL;
236         }
237
238         SetBuffer(NULL);
239
240         provider_buffer_release(m_pBuffer);
241         m_pBuffer = NULL;
242
243         pBuffer = provider_buffer_acquire(m_vType, PKGNAME,
244                                 m_sId, m_nWidth, m_nHeight, sizeof(int),
245                                 CVideo::s_BufferEventHandler, this);
246
247         SetBuffer(pBuffer);
248
249         if (m_vState == PLAYING) {
250                 const char *uri;
251                 m_sError = NULL;
252
253                 uri = CModel::GetInstance()->VideoFilename();
254                 DbgPrint("Update PIXMAP: 0x%X (file: %s)\n", m_nId, uri);
255                 mm_player_set_attribute(m_vPlayer, &m_sError,
256                                 "display_surface_type", MM_DISPLAY_SURFACE_X,
257                                 "display_width", m_nWidth,
258                                 "display_height", m_nHeight,
259                                 "display_overlay", &m_nId, sizeof(m_nId),
260                                 "profile_uri", uri, strlen(uri),
261                                 "display_rotation", MM_DISPLAY_ROTATION_NONE,
262                                 "profile_play_count", 1,
263                                 NULL);
264                 if (m_sError)
265                         ErrPrint("SetAttribute: %s\n", m_sError);
266         }
267
268         return 0;
269 }
270
271 int CVideo::s_MMMessageHandler(int message, void *_param, void *user_param)
272 {
273         CVideo *video = (CVideo *)user_param;
274         // MMMessageParamType *param = (MMMessageParamType *)_param;
275
276         switch (message) {
277         case MM_MESSAGE_END_OF_STREAM:
278                 video->Stop();
279                 DbgPrint("End of stream\n");
280                 break;
281         default:
282                 return FALSE;
283         }
284         
285         return TRUE;
286 }
287
288 void CVideo::Clear(void)
289 {
290         static unsigned int s_color = 0x00FF0000;
291         GC gc;
292
293         gc = XCreateGC((Display *)ecore_x_display_get(), PixmapId(), 0, 0);
294
295         XSetForeground((Display *)ecore_x_display_get(), gc, 0xFF000000 | s_color);
296         XFillRectangle((Display *)ecore_x_display_get(), PixmapId(), gc, 0, 0, Width(), Height());
297
298         XSync((Display *)ecore_x_display_get(), FALSE);
299         XFreeGC((Display *)ecore_x_display_get(), gc);
300
301         s_color >>= 2;
302         if (s_color == 0)
303                 s_color = 0xFF000000;
304 }
305
306 int CVideo::Play(const char *uri)
307 {
308         if (m_vState == PLAYING)
309                 return -EBUSY;
310
311         if (mm_player_create(&m_vPlayer) != MM_ERROR_NONE) {
312                 ErrPrint("Failed to create a player\n");
313                 return -EFAULT;
314         }
315
316         m_sError = NULL;
317         mm_player_set_attribute(m_vPlayer, &m_sError,
318                                 "display_surface_type", MM_DISPLAY_SURFACE_X,
319                                 "display_width", m_nWidth,
320                                 "display_height", m_nHeight,
321                                 "display_overlay", &m_nId, sizeof(m_nId),
322                                 "profile_uri", uri, strlen(uri),
323                                 "display_rotation", MM_DISPLAY_ROTATION_NONE,
324                                 "profile_play_count", 1,
325                                 NULL);
326         if (m_sError)
327                 ErrPrint("SetAttribute: %s\n", m_sError);
328
329         if (mm_player_realize(m_vPlayer) != MM_ERROR_NONE) {
330                 ErrPrint("Failed to realize a player\n");
331                 mm_player_destroy(m_vPlayer);
332                 m_vPlayer = 0;
333                 return -EFAULT;
334         }
335
336         mm_player_set_message_callback(m_vPlayer, CVideo::s_MMMessageHandler, this);
337         mm_player_start(m_vPlayer);
338         m_vState = PLAYING;
339
340         DbgPrint("Play file %s on %d\n", uri, m_nId);
341         return 0;
342 }
343
344 int CVideo::Stop(void)
345 {
346         if (m_vState == STOPPED)
347                 return -EALREADY;
348
349         m_vState = STOPPED;
350
351         if (m_vPlayer) {
352                 mm_player_unrealize(m_vPlayer);
353                 mm_player_destroy(m_vPlayer);
354                 m_vPlayer = 0;
355         }
356
357         DbgPrint("Stop playing\n");
358         return 0;
359 }
360
361 CVideo::CVideo(enum target_type type, int width, int height)
362 : m_vState(STOPPED)
363 , m_vType(type)
364 , m_nWidth(width)
365 , m_nHeight(height)
366 , m_pBuffer(NULL)
367 , m_nId(0)
368 , m_sId(NULL)
369 , m_sError(NULL)
370 , m_vPlayer(0)
371 {
372 }
373
374 CVideo::~CVideo(void)
375 {
376 }
377
378 CVideo::TVideoState CVideo::State(void)
379 {
380         return m_vState;
381 }
382
383 /* End of a file */