[M47_2526] Chromium upversion to m47_2526 branch
[platform/framework/web/chromium-efl.git] / tizen_src / chromium_impl / media / capture / video / tizen / video_capture_device_tizen.cc
1 // Copyright (c) 2012 The Samsung Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "media/capture/video/tizen/video_capture_device_tizen.h"
6
7 #include "third_party/libyuv/include/libyuv.h"
8
9 #if defined(WEBRTC_DEBUG_DUMPFILE)
10 #include <fcntl.h>
11 #include <unistd.h>
12 #endif
13
14 #include "base/bind.h"
15 #include "ui/gfx/screen.h"
16
17 #if defined(WEBRTC_DEBUG_DUMPFILE)
18 int fd_1 = -1;
19 int fd_2 = -1;
20 #define WEBRTC_DEBUG_INITDUMP() { \
21   struct stat st = {0}; \
22   if (stat("/opt/usr", &st) == -1) { \
23     mkdir("/opt/usr", 0644); \
24   } \
25   LOG(INFO) << " DUMP OUTPUT to file: /opt/usr/before.yuv, /opt/usr/after.yuv"; \
26   fd_1 = open( "/opt/usr/before.yuv", O_WRONLY | O_CREAT | O_EXCL, 0644); \
27   fd_2 = open( "/opt/usr/after.yuv", O_WRONLY | O_CREAT | O_EXCL, 0644); \
28 }
29 #else
30 #define WEBRTC_DEBUG_INITDUMP() { \
31 /* Do nothing */ }
32 #endif
33
34 #if defined(WEBRTC_DEBUG_DUMPFILE)
35 #define WEBRTC_DEBUG_DUMPFRAME(frame, yplane) { \
36   int written = \
37       write(fd_1, frame->data.triple_plane.y, frame->data.triple_plane.y_size); \
38   written += \
39       write(fd_1, frame->data.triple_plane.u, frame->data.triple_plane.u_size); \
40   written += \
41       write(fd_1, frame->data.triple_plane.v, frame->data.triple_plane.v_size); \
42   LOG(INFO) << written << " bytes written to dump file. before.yuv"; \
43   written = write(fd_2, yplane, frame->width * frame->height * 3 / 2); \
44   LOG(INFO) << written << " bytes written to dump file. after.yuv"; \
45 }
46 #else
47 #define WEBRTC_DEBUG_DUMPFRAME(frame, yplane) { \
48 /* Do nothing */ }
49 #endif
50
51 namespace {
52
53 enum { kMjpegWidth = 640 };
54 enum { kMjpegHeight = 480 };
55 enum { kTypicalFramerate = 30 };
56 enum { kTypicalFormat = CAMERA_PIXEL_FORMAT_NV12 };
57 enum CameraOrientation {
58   DEGREE_0 = 0,
59   DEGREE_90 = 90,
60   DEGREE_180 = 180,
61   DEGREE_270 = 270,
62   DEGREE_360 = 360,
63 };
64
65 struct _video_capture_err {
66   camera_error_e err_code;
67   std::string err_msg;
68 };
69
70 const static _video_capture_err video_capture_err[] = {
71   {CAMERA_ERROR_NONE, "Successful"},
72   {CAMERA_ERROR_INVALID_PARAMETER, "Invalid parameter"},
73   {CAMERA_ERROR_INVALID_STATE, "Invalid state"},
74   {CAMERA_ERROR_OUT_OF_MEMORY, "Out of memory"},
75   {CAMERA_ERROR_DEVICE, "Device error"},
76   {CAMERA_ERROR_INVALID_OPERATION, "Internal error"},
77   {CAMERA_ERROR_SOUND_POLICY, "Blocked by Audio Session Manager"},
78   {CAMERA_ERROR_SECURITY_RESTRICTED, "Restricted by security system policy"},
79   {CAMERA_ERROR_DEVICE_BUSY,
80       "The device is using another application or working on some operation"},
81   {CAMERA_ERROR_DEVICE_NOT_FOUND, "No camera device"},
82   {CAMERA_ERROR_SOUND_POLICY_BY_CALL,
83       "Blocked by Audio Session Manager - CALL"},
84   {CAMERA_ERROR_SOUND_POLICY_BY_ALARM,
85       "Blocked by Audio Session Manager - ALARM"},
86   {CAMERA_ERROR_ESD, "ESD situation "},
87   {CAMERA_ERROR_PERMISSION_DENIED,
88       "The access to the resources can not be granted"},
89   {CAMERA_ERROR_NOT_SUPPORTED, "The feature is not supported"},
90 };
91
92 camera_pixel_format_e toCapiType(media::VideoPixelFormat e) {
93   switch (e) {
94     case media::PIXEL_FORMAT_NV12:
95       return CAMERA_PIXEL_FORMAT_NV12;
96     case media::PIXEL_FORMAT_NV21:
97       return CAMERA_PIXEL_FORMAT_NV21;
98     case media::PIXEL_FORMAT_YUY2:
99       return CAMERA_PIXEL_FORMAT_YUYV;
100     case media::PIXEL_FORMAT_RGB24:
101       return CAMERA_PIXEL_FORMAT_RGB888;
102     case media::PIXEL_FORMAT_UYVY:
103       return CAMERA_PIXEL_FORMAT_UYVY;
104     case media::PIXEL_FORMAT_ARGB:
105       return CAMERA_PIXEL_FORMAT_ARGB;
106     case media::PIXEL_FORMAT_I420:
107       return CAMERA_PIXEL_FORMAT_I420;
108     case media::PIXEL_FORMAT_YV12:
109       return CAMERA_PIXEL_FORMAT_YV12;
110     case media::PIXEL_FORMAT_MJPEG:
111       return CAMERA_PIXEL_FORMAT_JPEG;
112     default:
113       NOTREACHED();
114   }
115   return CAMERA_PIXEL_FORMAT_INVALID;
116 }
117
118 bool OnPreviewFormat(
119     camera_pixel_format_e format, void* user_data) {
120   std::vector<camera_pixel_format_e>* list_format =
121       static_cast< std::vector<camera_pixel_format_e>* >(user_data);
122   DCHECK(list_format);
123
124   list_format->push_back(format);
125
126   return true;
127 }
128
129 } // unnamed namespace
130
131 namespace media {
132
133 const std::string VideoCaptureDeviceTizen::kFrontCameraName = "front";
134 const std::string VideoCaptureDeviceTizen::kBackCameraName = "back";
135 #if defined(OS_TIZEN_MOBILE)
136 const std::string VideoCaptureDeviceTizen::kFrontCameraId = "1";
137 const std::string VideoCaptureDeviceTizen::kBackCameraId = "0";
138 #else
139 const std::string VideoCaptureDeviceTizen::kBackCameraId = "1";
140 const std::string VideoCaptureDeviceTizen::kFrontCameraId = "0";
141 #endif
142
143 struct CameraSpec {
144   const char* device_id_;
145   CameraOrientation orientation_;
146 };
147
148 const static CameraSpec kCameraSpecs[] = {
149 #if defined(OS_TIZEN_MOBILE)
150     {VideoCaptureDeviceTizen::kBackCameraId.c_str(), DEGREE_90},
151     {VideoCaptureDeviceTizen::kFrontCameraId.c_str(), DEGREE_270}
152 #else
153     {VideoCaptureDeviceTizen::kFrontCameraId.c_str(), DEGREE_0},
154 #endif
155 };
156
157 static CameraOrientation GetCameraOrientation(const char* device_id) {
158   for (size_t i = 0; i < arraysize(kCameraSpecs); i++) {
159     const CameraSpec& cameraspec = kCameraSpecs[i];
160     if (strcmp(cameraspec.device_id_, device_id) == 0) {
161       return cameraspec.orientation_;
162     }
163   }
164   return DEGREE_0;
165 }
166
167 const std::string VideoCaptureDevice::Name::GetModel() const {
168   return "tizen camera";
169 }
170
171 VideoCaptureDeviceTizen::VideoCaptureDeviceTizen(const Name& device_name)
172     : state_(kIdle),
173       device_name_(device_name),
174       worker_("VideoCapture"),
175       buffer_(),
176       camera_(NULL) {
177   WEBRTC_DEBUG_INITDUMP();
178 }
179
180 VideoCaptureDeviceTizen::~VideoCaptureDeviceTizen() {
181   state_ = kIdle;
182   DCHECK(!worker_.IsRunning());
183 }
184
185 void VideoCaptureDeviceTizen::AllocateAndStart(
186     const VideoCaptureParams& params,
187     scoped_ptr<VideoCaptureDevice::Client> client) {
188   DCHECK(!worker_.IsRunning());
189   worker_.Start();
190   worker_.message_loop()->PostTask(
191       FROM_HERE,
192       base::Bind(&VideoCaptureDeviceTizen::OnAllocateAndStart,
193                  base::Unretained(this),
194                  params.requested_format.frame_size.width(),
195                  params.requested_format.frame_size.height(),
196                  params.requested_format.frame_rate,
197                  params.requested_format.pixel_format,
198                  base::Passed(&client)));
199 }
200
201 void VideoCaptureDeviceTizen::StopAndDeAllocate() {
202   DCHECK(worker_.IsRunning());
203   worker_.message_loop()->PostTask(
204       FROM_HERE,
205       base::Bind(&VideoCaptureDeviceTizen::OnStopAndDeAllocate,
206                  base::Unretained(this)));
207   worker_.Stop();
208   DeAllocateVideoBuffers();
209 }
210
211 camera_device_e VideoCaptureDeviceTizen::DeviceNameToCameraId(
212     const VideoCaptureDevice::Name& device_name) {
213   if (device_name.id().compare("0") == 0){
214     return CAMERA_DEVICE_CAMERA0;
215   } else if (device_name.id().compare("1") == 0) {
216     return CAMERA_DEVICE_CAMERA1;
217   } else {
218     NOTREACHED();
219   }
220   return static_cast<camera_device_e>(-1);
221 }
222
223 std::string VideoCaptureDeviceTizen::GetCameraErrorMessage(int err_code) {
224   for (size_t i = 0; i < arraysize(video_capture_err); i++) {
225     if (video_capture_err[i].err_code ==
226           static_cast<camera_error_e>(err_code)) {
227       return video_capture_err[i].err_msg;
228     }
229   }
230   return std::string("Camera Internal Error");
231 }
232
233 void VideoCaptureDeviceTizen::OnCameraCaptured(camera_preview_data_s* frame,
234                                                void* data) {
235   VideoCaptureDeviceTizen* self = static_cast<VideoCaptureDeviceTizen*>(data);
236   camera_attr_fps_e current_fps =
237       static_cast<camera_attr_fps_e>(kTypicalFramerate);
238   camera_attr_get_preview_fps(self->camera_, &current_fps);
239
240   DVLOG(3)  << " width:" << frame->width
241             << " height:" << frame->height;
242
243   const gfx::Display display =
244       gfx::Screen::GetNativeScreen()->GetPrimaryDisplay();
245   int orientation = display.RotationAsDegree();
246   gfx::Size target_resolution(frame->width, frame->height);
247   int target_rotation = (orientation +
248       GetCameraOrientation(self->device_name_.id().c_str())) % DEGREE_360;
249   if ((target_rotation / DEGREE_90) & 0x1) {
250     target_resolution.SetSize(frame->height, frame->width);
251     DVLOG(3) << " rotation from:" << orientation
252              << " to: " << target_rotation;
253   }
254
255   uint8* yplane = reinterpret_cast<uint8*>(self->buffer_->data());
256   uint8* uplane = yplane + frame->data.triple_plane.y_size;
257   uint8* vplane = uplane + frame->data.triple_plane.u_size;
258   int src_stride_y = frame->width;
259   int src_stride_uv = (src_stride_y + 1) / 2;
260   int tgt_stride_y = target_resolution.width();
261   int tgt_stride_uv = (tgt_stride_y + 1) / 2;
262
263   if (0 != libyuv::I420Rotate(
264         frame->data.triple_plane.y, src_stride_y,
265         frame->data.triple_plane.u, src_stride_uv,
266         frame->data.triple_plane.v, src_stride_uv,
267         yplane, tgt_stride_y,
268         uplane, tgt_stride_uv,
269         vplane, tgt_stride_uv,
270         frame->width, frame->height,
271         static_cast<libyuv::RotationMode>(target_rotation))) {
272     LOG(ERROR) << " Error when rotating the video frame";
273   }
274   WEBRTC_DEBUG_DUMPFRAME(frame, yplane);
275
276   gfx::Rect rect(target_resolution.width(), target_resolution.height());
277
278   scoped_refptr<VideoFrame> videoframe =
279       VideoFrame::CreateFrame(VideoFrame::I420, target_resolution,
280                               rect, target_resolution, base::TimeDelta());
281
282   self->client_->OnIncomingCapturedVideoFrame(self->buffer_.Pass(),
283                                               videoframe,
284                                               base::TimeTicks::Now());
285 }
286
287 void VideoCaptureDeviceTizen::OnAllocateAndStart(int width,
288                                                  int height,
289                                                  int frame_rate,
290                                                  VideoPixelFormat format,
291                                                  scoped_ptr<Client> client) {
292   DVLOG(3) << " width:" << width
293             << " height:" << height
294             << " frame_rate:" << frame_rate
295             << " format:" << VideoCaptureFormat::PixelFormatToString(format);
296
297   DCHECK_EQ(worker_.message_loop(), base::MessageLoop::current());
298
299   client_ = client.Pass();
300
301   if (CAMERA_ERROR_NONE !=
302       camera_create(DeviceNameToCameraId(device_name_), &camera_)) {
303     LOG(ERROR) << "Fail to create camera";
304     SetErrorState("Fail to create camera");
305     return;
306   }
307
308   if (CAMERA_ERROR_NONE !=
309       camera_set_display(camera_, CAMERA_DISPLAY_TYPE_NONE, NULL)) {
310     LOG(ERROR) << "Fail to set using camera buffer";
311     SetErrorState("Camera internal Error");
312     return;
313   }
314
315   if (CAMERA_ERROR_NONE !=
316       camera_set_preview_resolution(camera_, width, height)) {
317     LOG(WARNING) << "trying default resolution: "
318                  << kMjpegWidth << " x " << kMjpegHeight;
319
320     if (CAMERA_ERROR_NONE !=
321         camera_set_preview_resolution(camera_, kMjpegWidth, kMjpegHeight)) {
322       LOG(ERROR) << "fail to try default resolution: "
323                  << kMjpegWidth << " x " << kMjpegHeight;
324       SetErrorState("Camera internal Error");
325       return;
326     }
327   }
328
329   if (CAMERA_ERROR_NONE !=
330       camera_set_preview_format(camera_, toCapiType(format))) {
331     std::vector<camera_pixel_format_e> supported_formats;
332     if (CAMERA_ERROR_NONE !=
333         camera_foreach_supported_preview_format(
334             camera_, OnPreviewFormat, &supported_formats)) {
335       LOG(ERROR) << "Cannot get the supported formats for camera";
336       SetErrorState("Camera internal Error");
337       return;
338     }
339     if (supported_formats.empty()) {
340       LOG(ERROR) << "Cannot get the supported formats for camera";
341       SetErrorState("Camera internal Error");
342       return;
343     }
344     if (CAMERA_ERROR_NONE !=
345         camera_set_preview_format(camera_, supported_formats[0])) {
346       LOG(ERROR) << "fail to set preview format: " << supported_formats[0];
347       SetErrorState("Camera internal Error");
348       return;
349     }
350   }
351
352   if (CAMERA_ERROR_NONE !=
353       camera_set_preview_cb(camera_, OnCameraCaptured, this)) {
354     SetErrorState("Camera internal Error");
355     return;
356   }
357
358   if (CAMERA_ERROR_NONE !=
359       camera_attr_set_preview_fps(
360           camera_, static_cast<camera_attr_fps_e>(frame_rate))) {
361     LOG(WARNING) << "Camera does not support frame rate:" <<  frame_rate;
362     LOG(WARNING) << "trying default frame rate: " << kTypicalFramerate;
363     if (CAMERA_ERROR_NONE !=
364         camera_attr_set_preview_fps(
365             camera_, static_cast<camera_attr_fps_e>(kTypicalFramerate))) {
366       SetErrorState("Camera internal Error");
367       return;
368     }
369   }
370
371   if (!AllocateVideoBuffers(width, height)) {
372     LOG(ERROR) << "Allocate buffer failed";
373     SetErrorState("Camera internal Error");
374     return;
375   }
376
377   state_ = kCapturing;
378
379   if (CAMERA_ERROR_NONE != camera_start_preview(camera_)) {
380     LOG(ERROR) << "Fail to start camera";
381     SetErrorState("Camera internal Error");
382   }
383 }
384
385 void VideoCaptureDeviceTizen::OnStopAndDeAllocate() {
386   DCHECK_EQ(worker_.message_loop(), base::MessageLoop::current());
387
388   camera_stop_preview(camera_);
389   camera_destroy(camera_);
390   DeAllocateVideoBuffers();
391
392   state_ = kIdle;
393   client_.reset();
394 }
395
396 bool VideoCaptureDeviceTizen::AllocateVideoBuffers(int width, int height) {
397   buffer_ = client_->ReserveOutputBuffer(media::PIXEL_FORMAT_I420,
398                                          gfx::Size(width, height));
399   return (buffer_.get() != NULL);
400 }
401
402 void VideoCaptureDeviceTizen::DeAllocateVideoBuffers() {
403   /* Nothing to do */
404 }
405
406 void VideoCaptureDeviceTizen::SetErrorState(const std::string& reason) {
407   LOG(ERROR) << "Camera Error: " << reason;
408   DCHECK(!worker_.IsRunning() ||
409          worker_.message_loop() == base::MessageLoop::current());
410   state_ = kError;
411   client_->OnError(reason);
412 }
413
414 }  // namespace media