2 Copyright (C) 2012 Samsung Electronics.
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.
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.
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.
21 #include "WebKitCameraSourceGStreamer.h"
23 #if ENABLE(VIDEO) && USE(GSTREAMER)
27 #include "GRefPtrGStreamer.h"
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"
42 using namespace WebCore;
44 class RotationManager {
45 WTF_MAKE_NONCOPYABLE(RotationManager);
47 RotationManager(WebKitCameraSrc*);
48 virtual ~RotationManager();
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();
54 int rotation(float x, float y, float z);
57 WebKitCameraSrc* m_src;
61 #define WEBKIT_CAMERA_SRC_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE((obj), WEBKIT_TYPE_CAMERA_SRC, WebKitCameraSrcPrivate))
62 struct _WebKitCameraSrcPrivate {
68 GstElement* videoCaps;
69 GstElement* videoRate;
78 RotationManager* rotationManager;
86 static GstStaticPadTemplate srcTemplate = GST_STATIC_PAD_TEMPLATE("src",
91 GST_DEBUG_CATEGORY_STATIC(webkit_camera_src_debug);
92 #define GST_CAT_DEFAULT webkit_camera_src_debug
94 static void webKitCameraSrcUriHandlerInit(gpointer gIface, gpointer ifaceData);
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);
101 static gboolean webKitCameraSrcQueryWithParent(GstPad*, GstObject*, GstQuery*);
102 #ifndef GST_API_VERSION_1
103 static gboolean webKitCameraSrcQuery(GstPad*, GstQuery*);
106 static void webKitCameraSrcStop(WebKitCameraSrc*, bool);
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);
115 static void webkit_camera_src_class_init(WebKitCameraSrcClass* klass)
117 GObjectClass* oklass = G_OBJECT_CLASS(klass);
118 GstElementClass* eklass = GST_ELEMENT_CLASS(klass);
120 oklass->finalize = webKitCameraSrcFinalize;
121 oklass->set_property = webKitCameraSrcSetProperty;
122 oklass->get_property = webKitCameraSrcGetProperty;
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,
129 gst_element_class_set_details_simple(eklass,
131 (gchar*) "WebKit Camera source element",
133 (gchar*) "Handles Camera uris",
134 (gchar*) "Dong-gwan Kim <donggwan.kim@samsung.com>");
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,
140 g_param_spec_string("location",
142 "Location to read from",
144 (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
145 g_object_class_install_property(oklass,
147 g_param_spec_boolean("is-recording",
151 (GParamFlags) (G_PARAM_READWRITE)));
152 eklass->change_state = webKitCameraSrcChangeState;
154 g_type_class_add_private(klass, sizeof(WebKitCameraSrcPrivate));
157 static void newPadCallback(GstElement* element, GstPad* pad, WebKitCameraSrc* src)
159 WebKitCameraSrcPrivate* priv = WEBKIT_CAMERA_SRC_GET_PRIVATE(src);
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);
166 #define DEFAULT_IP_CAMERA_PORT 8888
167 static void webkit_camera_src_init(WebKitCameraSrc* src)
169 GRefPtr<GstPadTemplate> padTemplate = adoptGRef(gst_static_pad_template_get(&srcTemplate));
170 WebKitCameraSrcPrivate* priv = WEBKIT_CAMERA_SRC_GET_PRIVATE(src);
174 caps = gst_caps_from_string(VCAPS);
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);
191 if (gst_element_factory_find("camerasrc"))
192 g_object_set(priv->flip, "method", 1, NULL);
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);
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());
200 gst_pad_set_active(priv->srcpad, TRUE);
201 gst_element_add_pad(GST_ELEMENT(src), priv->srcpad);
203 gst_element_link(priv->src, priv->demux);
204 webKitCameraSrcStop(src, false);
207 static void webKitCameraSrcFinalize(GObject* object)
209 WebKitCameraSrc* src = WEBKIT_CAMERA_SRC(object);
210 WebKitCameraSrcPrivate* priv = src->priv;
212 delete priv->rotationManager;
216 GST_CALL_PARENT(G_OBJECT_CLASS, finalize, ((GObject* )(src)));
219 static void webKitCameraSrcSetProperty(GObject* object, guint propID, const GValue* value, GParamSpec* pspec)
221 WebKitCameraSrc* src = WEBKIT_CAMERA_SRC(object);
222 WebKitCameraSrcPrivate* priv = src->priv;
226 #ifdef GST_API_VERSION_1
227 gst_uri_handler_set_uri(reinterpret_cast<GstURIHandler*>(src), g_value_get_string(value), 0);
229 gst_uri_handler_set_uri(reinterpret_cast<GstURIHandler*>(src), g_value_get_string(value));
232 case PROP_IS_RECORDING:
233 priv->isRecording = g_value_get_boolean(value);
236 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, propID, pspec);
241 static void webKitCameraSrcGetProperty(GObject* object, guint propID, GValue* value, GParamSpec* pspec)
243 WebKitCameraSrc* src = WEBKIT_CAMERA_SRC(object);
244 WebKitCameraSrcPrivate* priv = src->priv;
248 g_value_set_string(value, priv->uri);
250 case PROP_IS_RECORDING:
251 g_value_set_boolean(value, priv->isRecording);
254 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, propID, pspec);
260 static void webKitCameraSrcStop(WebKitCameraSrc* src, bool seeking)
262 WebKitCameraSrcPrivate* priv = src->priv;
264 GST_OBJECT_LOCK(src);
269 GST_OBJECT_UNLOCK(src);
271 GST_DEBUG_OBJECT(src, "Stopped request");
274 static bool webKitCameraSrcStart(WebKitCameraSrc* src)
276 WebKitCameraSrcPrivate* priv = src->priv;
279 GST_ERROR_OBJECT(src, "No URI provided");
283 GST_OBJECT_LOCK(src);
288 GST_OBJECT_UNLOCK(src);
290 GST_DEBUG_OBJECT(src, "Started request");
295 static GstStateChangeReturn webKitCameraSrcChangeState(GstElement* element, GstStateChange transition)
297 GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
298 WebKitCameraSrc* src = WEBKIT_CAMERA_SRC(element);
299 WebKitCameraSrcPrivate* priv = src->priv;
301 switch (transition) {
302 case GST_STATE_CHANGE_NULL_TO_READY:
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");
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;
320 case GST_STATE_CHANGE_PAUSED_TO_READY:
321 GST_DEBUG_OBJECT(src, "PAUSED->READY");
322 webKitCameraSrcStop(src, false);
331 static gboolean webKitCameraSrcQueryWithParent(GstPad* pad, GstObject* parent, GstQuery* query)
333 WebKitCameraSrc* webkitSrc = WEBKIT_CAMERA_SRC(GST_ELEMENT(parent));
334 gboolean result = FALSE;
336 switch (GST_QUERY_TYPE(query)) {
337 case GST_QUERY_URI: {
338 gst_query_set_uri(query, webkitSrc->priv->uri);
343 GRefPtr<GstPad> target = adoptGRef(gst_ghost_pad_get_target(GST_GHOST_PAD_CAST(pad)));
345 // Forward the query to the proxy target pad.
347 result = gst_pad_query(target.get(), query);
355 #ifndef GST_API_VERSION_1
356 static gboolean webKitCameraSrcQuery(GstPad* pad, GstQuery* query)
358 GRefPtr<GstElement> src = adoptGRef(gst_pad_get_parent_element(pad));
359 return webKitCameraSrcQueryWithParent(pad, GST_OBJECT(src.get()), query);
363 // uri handler interface
365 #ifdef GST_API_VERSION_1
366 static GstURIType webKitCameraSrcUriGetType(GType)
371 const gchar* const* webKitCameraSrcGetProtocols(GType)
373 static const char* protocols[] = {"camera", 0 };
377 static gchar* webKitCameraSrcGetUri(GstURIHandler* handler)
379 return g_strdup(WEBKIT_CAMERA_SRC(handler)->priv->uri);
382 static gboolean webKitCameraSrcSetUri(GstURIHandler* handler, const gchar* uri, GError** error)
384 WebKitCameraSrc* src = WEBKIT_CAMERA_SRC(handler);
385 WebKitCameraSrcPrivate* priv = src->priv;
387 if (GST_STATE(src) >= GST_STATE_PAUSED) {
388 GST_ERROR_OBJECT(src, "URI can only be set in states < PAUSED");
399 sscanf(uri, "camera://%d", &cameraId);
401 priv->uri = g_strdup(uri);
402 priv->cameraId = cameraId;
408 static GstURIType webKitCameraSrcUriGetType(void)
413 static gchar** webKitCameraSrcGetProtocols(void)
415 static gchar* protocols[] = {(gchar*) "camera", 0 };
419 static const gchar* webKitCameraSrcGetUri(GstURIHandler* handler)
421 return g_strdup(WEBKIT_CAMERA_SRC(handler)->priv->uri);
424 static gboolean webKitCameraSrcSetUri(GstURIHandler* handler, const gchar* uri)
426 WebKitCameraSrc* src = WEBKIT_CAMERA_SRC(handler);
427 WebKitCameraSrcPrivate* priv = src->priv;
429 if (GST_STATE(src) >= GST_STATE_PAUSED) {
430 GST_ERROR_OBJECT(src, "URI can only be set in states < PAUSED");
441 sscanf(uri, "camera://%d", &cameraId);
443 priv->uri = g_strdup(uri);
444 priv->cameraId = cameraId;
450 static void webKitCameraSrcUriHandlerInit(gpointer gIface, gpointer ifaceData)
452 GstURIHandlerInterface* iface = (GstURIHandlerInterface *) gIface;
454 iface->get_type = webKitCameraSrcUriGetType;
455 iface->get_protocols = webKitCameraSrcGetProtocols;
456 iface->get_uri = webKitCameraSrcGetUri;
457 iface->set_uri = webKitCameraSrcSetUri;
460 RotationManager::RotationManager(WebKitCameraSrc* src) : m_src(src)
462 registerRotationCallback();
465 RotationManager::~RotationManager()
467 unregisterRotationCallback();
470 void RotationManager::onRotationChanged(unsigned long long timeStamp, sensor_data_accuracy_e accuracy, float x, float y, float z, void* userData)
472 RotationManager* manager = static_cast<RotationManager*>(userData);
473 if ((!manager->m_src))
476 WebKitCameraSrcPrivate* priv = manager->m_src->priv;
477 if (priv->isRecording)
480 int autoRotateScreen = 0;
481 vconf_get_bool(VCONFKEY_SETAPPL_AUTO_ROTATE_SCREEN_BOOL, &autoRotateScreen);
482 if (!autoRotateScreen)
485 int rotation = manager->rotation(x, y, z);
486 if (rotation == ROTATE_ERROR || rotation == priv->rotation)
489 priv->rotation = rotation;
490 manager->updateMethod();
491 g_object_set(G_OBJECT(priv->flip), "method", priv->method, NULL);
494 void RotationManager::registerRotationCallback()
496 sensor_type_e type = SENSOR_ACCELEROMETER;
498 sensor_create(&m_handle);
499 sensor_accelerometer_set_cb(m_handle, 0, onRotationChanged, this);
500 sensor_start(m_handle, type);
505 void RotationManager::unregisterRotationCallback()
507 sensor_type_e type = SENSOR_ACCELEROMETER;
509 sensor_accelerometer_unset_cb(m_handle);
510 sensor_stop(m_handle, type);
511 sensor_destroy(m_handle);
516 void RotationManager::updateMethod()
518 WebKitCameraSrcPrivate* priv = m_src->priv;
520 if (gst_element_factory_find("camerasrc")) {
521 switch (priv->rotation) {
523 priv->method = priv->cameraId ? 0 : 1;
526 priv->method = priv->cameraId ? 1 : 2;
529 priv->method = priv->cameraId ? 2 : 3;
532 priv->method = priv->cameraId ? 3 : 0;
538 switch (priv->rotation) {
557 int RotationManager::rotation(float x, float y, float z)
559 double atanV, normZ, rawZ;
560 int accTheta, accPitch;
564 accTheta = (int)(atanV * (RADIAN_VALUE) + 270) % 360;
565 rawZ = (double)(z / (0.004 * 9.81));
569 else if (rawZ < -250)
572 normZ = ((double)rawZ) / 250;
574 accPitch = (int)(acos(normZ) * (RADIAN_VALUE));
576 if ((accPitch > 35) && (accPitch < 145)) {
577 if ((accTheta >= 315 && accTheta <= 359) || (accTheta >= 0 && accTheta < 45))
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;
586 rotation = ROTATE_ERROR;
588 rotation = ROTATE_ERROR;
593 #endif // USE(GSTREAMER)