tagging audio streams and changing audio sink to pulseaudio
[profile/ivi/webkit-efl.git] / Source / WebCore / platform / graphics / gstreamer / WebKitCameraSourceGStreamer.cpp
1 /*
2     Copyright (C) 2012 Samsung Electronics.
3
4     This library is free software; you can redistribute it and/or
5     modify it under the terms of the GNU Library General Public
6     License as published by the Free Software Foundation; either
7     version 2.1 of the License, or (at your option) any later version.
8
9     This library is distributed in the hope that it will be useful,
10     but WITHOUT ANY WARRANTY; without even the implied warranty of
11     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12     Library General Public License for more details.
13
14     You should have received a copy of the GNU Library General Public License
15     along with this library; see the file COPYING.LIB.  If not, write to
16     the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17     Boston, MA 02110-1301, USA.
18 */
19
20 #include "config.h"
21 #include "WebKitCameraSourceGStreamer.h"
22
23 #if ENABLE(VIDEO) && USE(GSTREAMER)
24
25 #include "GOwnPtr.h"
26 #include "GRefPtr.h"
27 #include "GRefPtrGStreamer.h"
28 #include <sensors.h>
29 #include <vconf.h>
30
31 #define RADIAN_VALUE (57.2957)
32 #define VCAPS "video/x-raw-yuv, format=(fourcc)I420, width=(int)320, height=(int)240, framerate=(fraction)30/1"
33
34 enum {
35     ROTATE_0,
36     ROTATE_90,
37     ROTATE_180,
38     ROTATE_270,
39     ROTATE_ERROR
40 };
41
42 using namespace WebCore;
43
44 class RotationManager {
45     WTF_MAKE_NONCOPYABLE(RotationManager);
46     public:
47         RotationManager(WebKitCameraSrc*);
48         virtual ~RotationManager();
49
50         static void onRotationChanged(unsigned long long timeStamp, sensor_data_accuracy_e accuracy, float x, float y, float z, void* userData);
51         void registerRotationCallback();
52         void unregisterRotationCallback();
53         void updateMethod();
54         int rotation(float x, float y, float z);
55
56     private:
57         WebKitCameraSrc* m_src;
58         sensor_h m_handle;
59 };
60
61 #define WEBKIT_CAMERA_SRC_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE((obj), WEBKIT_TYPE_CAMERA_SRC, WebKitCameraSrcPrivate))
62 struct _WebKitCameraSrcPrivate {
63     GstElement* src;
64     GstElement* demux;
65     GstElement* dec;
66     GstElement* flip;
67     GstElement* autoconv;
68     GstElement* videoCaps;
69     GstElement* videoRate;
70     GstPad* srcpad;
71     gchar* uri;
72     gboolean isRecording;
73
74     gint cameraId;
75     gint rotation;
76     gint method;
77
78     RotationManager* rotationManager;
79 };
80
81 enum {
82     PROP_LOCATION = 1,
83     PROP_IS_RECORDING = 2
84 };
85
86 static GstStaticPadTemplate srcTemplate = GST_STATIC_PAD_TEMPLATE("src",
87                                                                   GST_PAD_SRC,
88                                                                   GST_PAD_ALWAYS,
89                                                                   GST_STATIC_CAPS_ANY);
90
91 GST_DEBUG_CATEGORY_STATIC(webkit_camera_src_debug);
92 #define GST_CAT_DEFAULT webkit_camera_src_debug
93
94 static void webKitCameraSrcUriHandlerInit(gpointer gIface, gpointer ifaceData);
95
96 static void webKitCameraSrcFinalize(GObject*);
97 static void webKitCameraSrcSetProperty(GObject*, guint propertyID, const GValue*, GParamSpec*);
98 static void webKitCameraSrcGetProperty(GObject*, guint propertyID, GValue*, GParamSpec*);
99 static GstStateChangeReturn webKitCameraSrcChangeState(GstElement*, GstStateChange);
100
101 static gboolean webKitCameraSrcQueryWithParent(GstPad*, GstObject*, GstQuery*);
102 #ifndef GST_API_VERSION_1
103 static gboolean webKitCameraSrcQuery(GstPad*, GstQuery*);
104 #endif
105
106 static void webKitCameraSrcStop(WebKitCameraSrc*, bool);
107
108 #define webkit_camera_src_parent_class parent_class
109 // We split this out into another macro to avoid a check-webkit-style error.
110 #define WEBKIT_CAMERA_SRC_CATEGORY_INIT GST_DEBUG_CATEGORY_INIT(webkit_camera_src_debug, "webkitcamerasrc", 0, "camerasrc element");
111 G_DEFINE_TYPE_WITH_CODE(WebKitCameraSrc, webkit_camera_src, GST_TYPE_BIN,
112                          G_IMPLEMENT_INTERFACE(GST_TYPE_URI_HANDLER, webKitCameraSrcUriHandlerInit);
113                          WEBKIT_CAMERA_SRC_CATEGORY_INIT);
114
115 static void webkit_camera_src_class_init(WebKitCameraSrcClass* klass)
116 {
117     GObjectClass* oklass = G_OBJECT_CLASS(klass);
118     GstElementClass* eklass = GST_ELEMENT_CLASS(klass);
119
120     oklass->finalize = webKitCameraSrcFinalize;
121     oklass->set_property = webKitCameraSrcSetProperty;
122     oklass->get_property = webKitCameraSrcGetProperty;
123
124     gst_element_class_add_pad_template(eklass,
125                                        gst_static_pad_template_get(&srcTemplate));
126 #ifdef GST_API_VERSION_1
127     gst_element_class_set_metadata(eklass,
128 #else
129     gst_element_class_set_details_simple(eklass,
130 #endif
131                                          (gchar*) "WebKit Camera source element",
132                                          (gchar*) "Source",
133                                          (gchar*) "Handles Camera uris",
134                                          (gchar*) "Dong-gwan Kim <donggwan.kim@samsung.com>");
135
136     /* Allows setting the uri using the 'location' property, which is used
137      * for example by gst_element_make_from_uri() */
138     g_object_class_install_property(oklass,
139                                     PROP_LOCATION,
140                                     g_param_spec_string("location",
141                                                         "location",
142                                                         "Location to read from",
143                                                         0,
144                                                         (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
145     g_object_class_install_property(oklass,
146                                     PROP_IS_RECORDING,
147                                     g_param_spec_boolean("is-recording",
148                                                         "is-recording",
149                                                         "Is recording",
150                                                         FALSE,
151                                                         (GParamFlags) (G_PARAM_READWRITE)));
152     eklass->change_state = webKitCameraSrcChangeState;
153
154     g_type_class_add_private(klass, sizeof(WebKitCameraSrcPrivate));
155 }
156
157 static void newPadCallback(GstElement* element, GstPad* pad, WebKitCameraSrc* src)
158 {
159     WebKitCameraSrcPrivate* priv = WEBKIT_CAMERA_SRC_GET_PRIVATE(src);
160
161     gst_pad_link(pad, gst_element_get_static_pad(priv->dec, "sink"));
162     gst_element_link_many(priv->dec, priv->autoconv, priv->videoRate, priv->videoCaps, priv->flip, NULL);
163
164 }
165
166 #define DEFAULT_IP_CAMERA_PORT 8888
167 static void webkit_camera_src_init(WebKitCameraSrc* src)
168 {
169     GRefPtr<GstPadTemplate> padTemplate = adoptGRef(gst_static_pad_template_get(&srcTemplate));
170     WebKitCameraSrcPrivate* priv = WEBKIT_CAMERA_SRC_GET_PRIVATE(src);
171     src->priv = priv;
172
173     GstCaps* caps = 0;
174     caps = gst_caps_from_string(VCAPS);
175
176     priv->rotationManager = new RotationManager(src);
177     priv->src = gst_element_factory_make("tcpclientsrc", 0);
178     priv->demux = gst_element_factory_make("multipartdemux", 0);
179     priv->dec = gst_element_factory_make("jpegdec", 0);
180     priv->autoconv  = gst_element_factory_make("ffmpegcolorspace", "autoconv");
181     priv->flip = gst_element_factory_make("videoflip", 0);
182     priv->videoRate = gst_element_factory_make("videorate", 0);
183     priv->videoCaps = gst_element_factory_make("capsfilter", 0);
184     g_object_set(G_OBJECT(priv->videoCaps), "caps", caps, NULL);
185     gst_caps_unref(caps);
186     g_object_set(priv->src, "protocol", 0, NULL);
187     g_object_set(priv->src, "host", "localhost", NULL);
188     g_object_set(priv->src, "port", DEFAULT_IP_CAMERA_PORT, NULL);
189     g_object_set(priv->src, "do-timestamp", true, NULL);
190
191     if (gst_element_factory_find("camerasrc"))
192         g_object_set(priv->flip, "method", 1, NULL);
193
194     gst_bin_add_many(GST_BIN(src), priv->src, priv->demux, priv->dec, priv->flip, priv->videoRate, priv->videoCaps, priv->autoconv, NULL);
195     g_signal_connect(priv->demux, "pad-added", G_CALLBACK(newPadCallback), src);
196
197     GRefPtr<GstPad> targetPad = adoptGRef(gst_element_get_static_pad(GST_ELEMENT(priv->flip), "src"));
198     priv->srcpad = gst_ghost_pad_new_from_template("src", targetPad.get(), padTemplate.get());
199
200     gst_pad_set_active(priv->srcpad, TRUE);
201     gst_element_add_pad(GST_ELEMENT(src), priv->srcpad);
202
203     gst_element_link(priv->src, priv->demux);
204     webKitCameraSrcStop(src, false);
205 }
206
207 static void webKitCameraSrcFinalize(GObject* object)
208 {
209     WebKitCameraSrc* src = WEBKIT_CAMERA_SRC(object);
210     WebKitCameraSrcPrivate* priv = src->priv;
211
212     delete priv->rotationManager;
213
214     g_free(priv->uri);
215
216     GST_CALL_PARENT(G_OBJECT_CLASS, finalize, ((GObject* )(src)));
217 }
218
219 static void webKitCameraSrcSetProperty(GObject* object, guint propID, const GValue* value, GParamSpec* pspec)
220 {
221     WebKitCameraSrc* src = WEBKIT_CAMERA_SRC(object);
222     WebKitCameraSrcPrivate* priv = src->priv;
223
224     switch (propID) {
225     case PROP_LOCATION:
226 #ifdef GST_API_VERSION_1
227         gst_uri_handler_set_uri(reinterpret_cast<GstURIHandler*>(src), g_value_get_string(value), 0);
228 #else
229         gst_uri_handler_set_uri(reinterpret_cast<GstURIHandler*>(src), g_value_get_string(value));
230 #endif
231         break;
232     case PROP_IS_RECORDING:
233         priv->isRecording = g_value_get_boolean(value);
234         break;
235     default:
236         G_OBJECT_WARN_INVALID_PROPERTY_ID(object, propID, pspec);
237         break;
238     }
239 }
240
241 static void webKitCameraSrcGetProperty(GObject* object, guint propID, GValue* value, GParamSpec* pspec)
242 {
243     WebKitCameraSrc* src = WEBKIT_CAMERA_SRC(object);
244     WebKitCameraSrcPrivate* priv = src->priv;
245
246     switch (propID) {
247     case PROP_LOCATION:
248         g_value_set_string(value, priv->uri);
249         break;
250     case PROP_IS_RECORDING:
251         g_value_set_boolean(value, priv->isRecording);
252         break;
253     default:
254         G_OBJECT_WARN_INVALID_PROPERTY_ID(object, propID, pspec);
255         break;
256     }
257 }
258
259
260 static void webKitCameraSrcStop(WebKitCameraSrc* src, bool seeking)
261 {
262     WebKitCameraSrcPrivate* priv = src->priv;
263
264     GST_OBJECT_LOCK(src);
265
266     priv->cameraId = 0;
267     priv->rotation = 0;
268
269     GST_OBJECT_UNLOCK(src);
270
271     GST_DEBUG_OBJECT(src, "Stopped request");
272 }
273
274 static bool webKitCameraSrcStart(WebKitCameraSrc* src)
275 {
276     WebKitCameraSrcPrivate* priv = src->priv;
277
278     if (!priv->uri) {
279         GST_ERROR_OBJECT(src, "No URI provided");
280         return false;
281     }
282
283     GST_OBJECT_LOCK(src);
284
285     priv->cameraId = 0;
286     priv->rotation = 0;
287
288     GST_OBJECT_UNLOCK(src);
289
290     GST_DEBUG_OBJECT(src, "Started request");
291
292     return true;
293 }
294
295 static GstStateChangeReturn webKitCameraSrcChangeState(GstElement* element, GstStateChange transition)
296 {
297     GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
298     WebKitCameraSrc* src = WEBKIT_CAMERA_SRC(element);
299     WebKitCameraSrcPrivate* priv = src->priv;
300
301     switch (transition) {
302     case GST_STATE_CHANGE_NULL_TO_READY:
303         break;
304     default:
305         break;
306     }
307
308     ret = GST_ELEMENT_CLASS(parent_class)->change_state(element, transition);
309     if (G_UNLIKELY(ret == GST_STATE_CHANGE_FAILURE)) {
310         GST_DEBUG_OBJECT(src, "State change failed");
311         return ret;
312     }
313
314     switch (transition) {
315     case GST_STATE_CHANGE_READY_TO_PAUSED:
316         GST_DEBUG_OBJECT(src, "READY->PAUSED");
317         if (!webKitCameraSrcStart(src))
318             ret = GST_STATE_CHANGE_FAILURE;
319         break;
320     case GST_STATE_CHANGE_PAUSED_TO_READY:
321         GST_DEBUG_OBJECT(src, "PAUSED->READY");
322         webKitCameraSrcStop(src, false);
323         break;
324     default:
325         break;
326     }
327
328     return ret;
329 }
330
331 static gboolean webKitCameraSrcQueryWithParent(GstPad* pad, GstObject* parent, GstQuery* query)
332 {
333     WebKitCameraSrc* webkitSrc = WEBKIT_CAMERA_SRC(GST_ELEMENT(parent));
334     gboolean result = FALSE;
335
336     switch (GST_QUERY_TYPE(query)) {
337     case GST_QUERY_URI: {
338         gst_query_set_uri(query, webkitSrc->priv->uri);
339         result = TRUE;
340         break;
341     }
342     default: {
343         GRefPtr<GstPad> target = adoptGRef(gst_ghost_pad_get_target(GST_GHOST_PAD_CAST(pad)));
344
345         // Forward the query to the proxy target pad.
346         if (target)
347             result = gst_pad_query(target.get(), query);
348         break;
349     }
350     }
351
352     return result;
353 }
354
355 #ifndef GST_API_VERSION_1
356 static gboolean webKitCameraSrcQuery(GstPad* pad, GstQuery* query)
357 {
358     GRefPtr<GstElement> src = adoptGRef(gst_pad_get_parent_element(pad));
359     return webKitCameraSrcQueryWithParent(pad, GST_OBJECT(src.get()), query);
360 }
361 #endif
362
363 // uri handler interface
364
365 #ifdef GST_API_VERSION_1
366 static GstURIType webKitCameraSrcUriGetType(GType)
367 {
368     return GST_URI_SRC;
369 }
370
371 const gchar* const* webKitCameraSrcGetProtocols(GType)
372 {
373     static const char* protocols[] = {"camera", 0 };
374     return protocols;
375 }
376
377 static gchar* webKitCameraSrcGetUri(GstURIHandler* handler)
378 {
379     return g_strdup(WEBKIT_CAMERA_SRC(handler)->priv->uri);
380 }
381
382 static gboolean webKitCameraSrcSetUri(GstURIHandler* handler, const gchar* uri, GError** error)
383 {
384     WebKitCameraSrc* src = WEBKIT_CAMERA_SRC(handler);
385     WebKitCameraSrcPrivate* priv = src->priv;
386
387     if (GST_STATE(src) >= GST_STATE_PAUSED) {
388         GST_ERROR_OBJECT(src, "URI can only be set in states < PAUSED");
389         return FALSE;
390     }
391
392     g_free(priv->uri);
393     priv->uri = 0;
394
395     if (!uri)
396         return TRUE;
397
398     int cameraId = 0;
399     sscanf(uri, "camera://%d", &cameraId);
400
401     priv->uri = g_strdup(uri);
402     priv->cameraId = cameraId;
403
404     return TRUE;
405 }
406
407 #else
408 static GstURIType webKitCameraSrcUriGetType(void)
409 {
410     return GST_URI_SRC;
411 }
412
413 static gchar** webKitCameraSrcGetProtocols(void)
414 {
415     static gchar* protocols[] = {(gchar*) "camera", 0 };
416     return protocols;
417 }
418
419 static const gchar* webKitCameraSrcGetUri(GstURIHandler* handler)
420 {
421     return g_strdup(WEBKIT_CAMERA_SRC(handler)->priv->uri);
422 }
423
424 static gboolean webKitCameraSrcSetUri(GstURIHandler* handler, const gchar* uri)
425 {
426     WebKitCameraSrc* src = WEBKIT_CAMERA_SRC(handler);
427     WebKitCameraSrcPrivate* priv = src->priv;
428
429     if (GST_STATE(src) >= GST_STATE_PAUSED) {
430         GST_ERROR_OBJECT(src, "URI can only be set in states < PAUSED");
431         return FALSE;
432     }
433
434     g_free(priv->uri);
435     priv->uri = 0;
436
437     if (!uri)
438         return TRUE;
439
440     int cameraId = 0;
441     sscanf(uri, "camera://%d", &cameraId);
442
443     priv->uri = g_strdup(uri);
444     priv->cameraId = cameraId;
445
446     return TRUE;
447 }
448 #endif
449
450 static void webKitCameraSrcUriHandlerInit(gpointer gIface, gpointer ifaceData)
451 {
452     GstURIHandlerInterface* iface = (GstURIHandlerInterface *) gIface;
453
454     iface->get_type = webKitCameraSrcUriGetType;
455     iface->get_protocols = webKitCameraSrcGetProtocols;
456     iface->get_uri = webKitCameraSrcGetUri;
457     iface->set_uri = webKitCameraSrcSetUri;
458 }
459
460 RotationManager::RotationManager(WebKitCameraSrc* src) : m_src(src)
461 {
462     registerRotationCallback();
463 }
464
465 RotationManager::~RotationManager()
466 {
467     unregisterRotationCallback();
468 }
469
470 void RotationManager::onRotationChanged(unsigned long long timeStamp, sensor_data_accuracy_e accuracy, float x, float y, float z, void* userData)
471 {
472     RotationManager* manager = static_cast<RotationManager*>(userData);
473     if ((!manager->m_src))
474         return;
475
476     WebKitCameraSrcPrivate* priv = manager->m_src->priv;
477     if (priv->isRecording)
478         return;
479
480     int autoRotateScreen = 0;
481     vconf_get_bool(VCONFKEY_SETAPPL_AUTO_ROTATE_SCREEN_BOOL, &autoRotateScreen);
482     if (!autoRotateScreen)
483         return;
484
485     int rotation = manager->rotation(x, y, z);
486     if (rotation == ROTATE_ERROR || rotation == priv->rotation)
487         return;
488
489     priv->rotation = rotation;
490     manager->updateMethod();
491     g_object_set(G_OBJECT(priv->flip), "method", priv->method, NULL);
492 }
493
494 void RotationManager::registerRotationCallback()
495 {
496     sensor_type_e type = SENSOR_ACCELEROMETER;
497
498     sensor_create(&m_handle);
499     sensor_accelerometer_set_cb(m_handle, 0, onRotationChanged, this); 
500     sensor_start(m_handle, type);
501
502     return;
503 }
504
505 void RotationManager::unregisterRotationCallback()
506 {
507     sensor_type_e type = SENSOR_ACCELEROMETER;
508
509     sensor_accelerometer_unset_cb(m_handle);
510     sensor_stop(m_handle, type);
511     sensor_destroy(m_handle);
512
513     return;
514 }
515
516 void RotationManager::updateMethod()
517 {
518     WebKitCameraSrcPrivate* priv = m_src->priv;
519
520     if (gst_element_factory_find("camerasrc")) {
521         switch (priv->rotation) {
522         case ROTATE_0:
523             priv->method = priv->cameraId ? 0 : 1;
524             break;
525         case ROTATE_90:
526             priv->method = priv->cameraId ? 1 : 2;
527             break;
528         case ROTATE_180:
529             priv->method = priv->cameraId ? 2 : 3;
530             break;
531         case ROTATE_270:
532             priv->method = priv->cameraId ? 3 : 0;
533             break;
534         default:
535             break;
536         }
537     } else {
538         switch (priv->rotation) {
539         case ROTATE_0:
540             priv->method = 0;
541             break;
542         case ROTATE_90:
543             priv->method = 3;
544             break;
545         case ROTATE_180:
546             priv->method = 2;
547             break;
548         case ROTATE_270:
549             priv->method = 1;
550             break;
551         default:
552             break;
553         }
554     }
555 }
556
557 int RotationManager::rotation(float x, float y, float z)
558 {
559     double atanV, normZ, rawZ;
560     int accTheta, accPitch;
561     int rotation;
562
563     atanV = atan2(y, x);
564     accTheta = (int)(atanV * (RADIAN_VALUE) + 270) % 360;
565     rawZ = (double)(z / (0.004 * 9.81));
566
567     if (rawZ > 250)
568         normZ = 1.0;
569     else if (rawZ < -250)
570         normZ = -1.0;
571     else
572         normZ = ((double)rawZ) / 250;
573
574     accPitch = (int)(acos(normZ) * (RADIAN_VALUE));
575
576     if ((accPitch > 35) && (accPitch < 145)) {
577         if ((accTheta >= 315 && accTheta <= 359) || (accTheta >= 0 && accTheta < 45))
578             rotation = ROTATE_0;
579         else if (accTheta >= 45 && accTheta < 135)
580             rotation = ROTATE_90;
581         else if (accTheta >= 135 && accTheta < 225)
582             rotation = ROTATE_180;
583         else if (accTheta >= 225 && accTheta < 315)
584             rotation = ROTATE_270;
585         else
586             rotation = ROTATE_ERROR;
587     } else
588         rotation = ROTATE_ERROR;
589
590     return rotation;
591 }
592
593 #endif // USE(GSTREAMER)
594