1 /*
2 * Copyright (C) 2011 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.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://www.apache.org/licenses/LICENSE-2.0
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 /*
18 * Contains implementation of a class EmulatedQemuCamera that encapsulates
19 * functionality of an emulated camera connected to the host.
20 */
21
22 #define LOG_NDEBUG 0
23 #define LOG_TAG "EmulatedCamera_QemuCamera"
24 #include <cutils/log.h>
25 #include "EmulatedQemuCamera.h"
26 #include "EmulatedCameraFactory.h"
27
28 #undef min
29 #undef max
30 #include <sstream>
31 #include <string>
32 #include <vector>
33
34 namespace android {
35
EmulatedQemuCamera(int cameraId,struct hw_module_t * module)36 EmulatedQemuCamera::EmulatedQemuCamera(int cameraId, struct hw_module_t* module)
37 : EmulatedCamera(cameraId, module),
38 mQemuCameraDevice(this)
39 {
40 }
41
~EmulatedQemuCamera()42 EmulatedQemuCamera::~EmulatedQemuCamera()
43 {
44 }
45
46 /****************************************************************************
47 * EmulatedCamera virtual overrides.
48 ***************************************************************************/
49
Initialize(const char * device_name,const char * frame_dims,const char * facing_dir)50 status_t EmulatedQemuCamera::Initialize(const char* device_name,
51 const char* frame_dims,
52 const char* facing_dir)
53 {
54 ALOGV("%s:\n Name=%s\n Facing '%s'\n Dimensions=%s",
55 __FUNCTION__, device_name, facing_dir, frame_dims);
56 /* Save dimensions. */
57 mFrameDims = frame_dims;
58
59 /* Initialize camera device. */
60 status_t res = mQemuCameraDevice.Initialize(device_name);
61 if (res != NO_ERROR) {
62 return res;
63 }
64
65 /* Initialize base class. */
66 res = EmulatedCamera::Initialize();
67 if (res != NO_ERROR) {
68 return res;
69 }
70
71 /*
72 * Set customizable parameters.
73 */
74 using Size = std::pair<int, int>;
75 std::vector<Size> resolutions;
76 std::stringstream ss(frame_dims);
77 std::string input;
78 while (std::getline(ss, input, ',')) {
79 int width = 0;
80 int height = 0;
81 char none = 0;
82 /* Expect only two results because that means there was nothing after
83 * the height, we don't want any trailing characters. Otherwise we just
84 * ignore this entry. */
85 if (sscanf(input.c_str(), "%dx%d%c", &width, &height, &none) == 2) {
86 resolutions.push_back(Size(width, height));
87 ALOGI("%s: %dx%d", __FUNCTION__, width, height);
88 }
89 }
90
91 /* The Android framework contains a wrapper around the v1 Camera API so that
92 * it can be used with API v2. This wrapper attempts to figure out the
93 * sensor resolution of the camera by looking at the resolution with the
94 * largest area and infer that the dimensions of that resolution must also
95 * be the size of the camera sensor. Any resolution with a dimension that
96 * exceeds the sensor size will be rejected so Camera API calls will start
97 * failing. To work around this we remove any resolutions with at least one
98 * dimension exceeding that of the max area resolution. */
99
100 /* First find the resolution with the maximum area, the "sensor size" */
101 int maxArea = 0;
102 int maxAreaWidth = 0;
103 int maxAreaHeight = 0;
104 for (const auto& res : resolutions) {
105 int area = res.first * res.second;
106 if (area > maxArea) {
107 maxArea = area;
108 maxAreaWidth = res.first;
109 maxAreaHeight = res.second;
110 }
111 }
112
113 /* Next remove any resolution with a dimension exceeding the sensor size. */
114 for (auto res = resolutions.begin(); res != resolutions.end(); ) {
115 if (res->first > maxAreaWidth || res->second > maxAreaHeight) {
116 /* Width and/or height larger than sensor, remove it */
117 res = resolutions.erase(res);
118 } else {
119 ++res;
120 }
121 }
122
123 if (resolutions.empty()) {
124 ALOGE("%s: Qemu camera has no valid resolutions", __FUNCTION__);
125 return EINVAL;
126 }
127
128 /* Next rebuild the frame size string for the camera parameters */
129 std::stringstream sizesStream;
130 for (size_t i = 0; i < resolutions.size(); ++i) {
131 if (i != 0) {
132 sizesStream << ',';
133 }
134 sizesStream << resolutions[i].first << 'x' << resolutions[i].second;
135 }
136 std::string sizes = sizesStream.str();
137
138 mParameters.set(EmulatedCamera::FACING_KEY, facing_dir);
139 mParameters.set(EmulatedCamera::ORIENTATION_KEY,
140 gEmulatedCameraFactory.getQemuCameraOrientation());
141 mParameters.set(CameraParameters::KEY_ROTATION,
142 gEmulatedCameraFactory.getQemuCameraOrientation());
143 mParameters.set(CameraParameters::KEY_SUPPORTED_PICTURE_SIZES,
144 sizes.c_str());
145 mParameters.set(CameraParameters::KEY_SUPPORTED_PREVIEW_SIZES,
146 sizes.c_str());
147 mParameters.set(CameraParameters::KEY_SUPPORTED_VIDEO_SIZES,
148 sizes.c_str());
149
150 std::string preferred_size = std::to_string(resolutions[0].first)
151 + "x" + std::to_string(resolutions[0].second);
152 mParameters.set(CameraParameters::KEY_PREFERRED_PREVIEW_SIZE_FOR_VIDEO,
153 preferred_size.c_str());
154
155 /*
156 * Use first dimension reported by the device to set current preview and
157 * picture sizes.
158 */
159 int x = resolutions[0].first;
160 int y = resolutions[0].second;
161 mParameters.setPreviewSize(x, y);
162 mParameters.setPictureSize(x, y);
163
164 ALOGV("%s: Qemu camera %s is initialized. Current frame is %dx%d",
165 __FUNCTION__, device_name, x, y);
166
167 return NO_ERROR;
168 }
169
getCameraDevice()170 EmulatedCameraDevice* EmulatedQemuCamera::getCameraDevice()
171 {
172 return &mQemuCameraDevice;
173 }
174
175 }; /* namespace android */
176