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.
5 #include "media/video/capture/tizen/video_capture_device_tizen.h"
7 #include "third_party/libyuv/include/libyuv.h"
9 #if defined(WEBRTC_DEBUG_DUMPFILE)
14 #include "base/bind.h"
15 #include "ui/gfx/screen.h"
17 #if defined(WEBRTC_DEBUG_DUMPFILE)
20 #define WEBRTC_DEBUG_INITDUMP() { \
21 struct stat st = {0}; \
22 if (stat("/opt/usr", &st) == -1) { \
23 mkdir("/opt/usr", 0644); \
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); \
30 #define WEBRTC_DEBUG_INITDUMP() { \
34 #if defined(WEBRTC_DEBUG_DUMPFILE)
35 #define WEBRTC_DEBUG_DUMPFRAME(frame, yplane) { \
37 write(fd_1, frame->data.triple_plane.y, frame->data.triple_plane.y_size); \
39 write(fd_1, frame->data.triple_plane.u, frame->data.triple_plane.u_size); \
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"; \
47 #define WEBRTC_DEBUG_DUMPFRAME(frame, yplane) { \
53 enum { kMjpegWidth = 640 };
54 enum { kMjpegHeight = 480 };
55 enum { kTypicalFramerate = 30 };
56 enum { kTypicalFormat = CAMERA_PIXEL_FORMAT_NV12 };
57 enum CameraOrientation {
65 struct _video_capture_err {
66 camera_error_e err_code;
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"},
92 camera_pixel_format_e toCapiType(media::VideoPixelFormat 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;
115 return CAMERA_PIXEL_FORMAT_INVALID;
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);
124 list_format->push_back(format);
129 } // unnamed namespace
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";
139 const std::string VideoCaptureDeviceTizen::kBackCameraId = "1";
140 const std::string VideoCaptureDeviceTizen::kFrontCameraId = "0";
144 const char* device_id_;
145 CameraOrientation orientation_;
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}
153 {VideoCaptureDeviceTizen::kFrontCameraId.c_str(), DEGREE_0},
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_;
167 const std::string VideoCaptureDevice::Name::GetModel() const {
168 return "tizen camera";
171 VideoCaptureDeviceTizen::VideoCaptureDeviceTizen(const Name& device_name)
173 device_name_(device_name),
174 worker_("VideoCapture"),
177 WEBRTC_DEBUG_INITDUMP();
180 VideoCaptureDeviceTizen::~VideoCaptureDeviceTizen() {
182 DCHECK(!worker_.IsRunning());
185 void VideoCaptureDeviceTizen::AllocateAndStart(
186 const VideoCaptureParams& params,
187 scoped_ptr<VideoCaptureDevice::Client> client) {
188 DCHECK(!worker_.IsRunning());
190 worker_.message_loop()->PostTask(
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)));
201 void VideoCaptureDeviceTizen::StopAndDeAllocate() {
202 DCHECK(worker_.IsRunning());
203 worker_.message_loop()->PostTask(
205 base::Bind(&VideoCaptureDeviceTizen::OnStopAndDeAllocate,
206 base::Unretained(this)));
208 DeAllocateVideoBuffers();
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;
220 return static_cast<camera_device_e>(-1);
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;
230 return std::string("Camera Internal Error");
233 void VideoCaptureDeviceTizen::OnCameraCaptured(camera_preview_data_s* frame,
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_, ¤t_fps);
240 DVLOG(3) << " width:" << frame->width
241 << " height:" << frame->height;
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;
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;
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";
274 WEBRTC_DEBUG_DUMPFRAME(frame, yplane);
276 gfx::Rect rect(target_resolution.width(), target_resolution.height());
278 scoped_refptr<VideoFrame> videoframe =
279 VideoFrame::CreateFrame(VideoFrame::I420, target_resolution,
280 rect, target_resolution, base::TimeDelta());
282 self->client_->OnIncomingCapturedVideoFrame(self->buffer_.Pass(),
284 base::TimeTicks::Now());
287 void VideoCaptureDeviceTizen::OnAllocateAndStart(int width,
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);
297 DCHECK_EQ(worker_.message_loop(), base::MessageLoop::current());
299 client_ = client.Pass();
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");
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");
315 if (CAMERA_ERROR_NONE !=
316 camera_set_preview_resolution(camera_, width, height)) {
317 LOG(WARNING) << "trying default resolution: "
318 << kMjpegWidth << " x " << kMjpegHeight;
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");
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");
339 if (supported_formats.empty()) {
340 LOG(ERROR) << "Cannot get the supported formats for camera";
341 SetErrorState("Camera internal Error");
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");
352 if (CAMERA_ERROR_NONE !=
353 camera_set_preview_cb(camera_, OnCameraCaptured, this)) {
354 SetErrorState("Camera internal Error");
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");
371 if (!AllocateVideoBuffers(width, height)) {
372 LOG(ERROR) << "Allocate buffer failed";
373 SetErrorState("Camera internal Error");
379 if (CAMERA_ERROR_NONE != camera_start_preview(camera_)) {
380 LOG(ERROR) << "Fail to start camera";
381 SetErrorState("Camera internal Error");
385 void VideoCaptureDeviceTizen::OnStopAndDeAllocate() {
386 DCHECK_EQ(worker_.message_loop(), base::MessageLoop::current());
388 camera_stop_preview(camera_);
389 camera_destroy(camera_);
390 DeAllocateVideoBuffers();
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);
402 void VideoCaptureDeviceTizen::DeAllocateVideoBuffers() {
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());
411 client_->OnError(reason);