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