blob: 3deeaee99ab5d8da5280cfb3fe93328e60aaab79
1 | /* |
2 | * Copyright 2014 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 | #define LOG_TAG "TvInput" |
18 | #include <fcntl.h> |
19 | #include <errno.h> |
20 | |
21 | #include <cutils/log.h> |
22 | #include <cutils/native_handle.h> |
23 | |
24 | #include <hardware/tv_input.h> |
25 | #include "tv_input.h" |
26 | #include <tvcmd.h> |
27 | #include <ui/GraphicBufferMapper.h> |
28 | #include <ui/GraphicBuffer.h> |
29 | #include <gralloc_priv.h> |
30 | #include <gralloc_helper.h> |
31 | |
32 | #if PLATFORM_SDK_VERSION > 23 |
33 | #include <gralloc_usage_ext.h> |
34 | #endif |
35 | |
36 | #include <hardware/hardware.h> |
37 | #include <linux/videodev2.h> |
38 | #include <android/native_window.h> |
39 | |
40 | static const int SCREENSOURCE_GRALLOC_USAGE = ( |
41 | GRALLOC_USAGE_HW_TEXTURE | GRALLOC_USAGE_HW_RENDER | |
42 | GRALLOC_USAGE_SW_READ_RARELY | GRALLOC_USAGE_SW_WRITE_NEVER); |
43 | |
44 | static int capWidth; |
45 | static int capHeight; |
46 | |
47 | struct sideband_handle_t *pTvStream = nullptr; |
48 | |
49 | void EventCallback::onTvEvent (const source_connect_t &scrConnect) { |
50 | tv_input_private_t *priv = (tv_input_private_t *)(mPri); |
51 | |
52 | //ALOGI("callback::onTvEvent msgType = %d", scrConnect.msgType); |
53 | switch (scrConnect.msgType) { |
54 | case SOURCE_CONNECT_CALLBACK: { |
55 | tv_source_input_t source = (tv_source_input_t)scrConnect.source; |
56 | int connectState = scrConnect.state; |
57 | ALOGI("callback::onTvEvent source = %d, status = %d", source, connectState); |
58 | |
59 | if (source != SOURCE_HDMI1 && source != SOURCE_HDMI2 && source != SOURCE_HDMI3 |
60 | && source != SOURCE_HDMI4 && source != SOURCE_AV1 && source != SOURCE_AV2) |
61 | break; |
62 | |
63 | if (connectState == 1) { |
64 | notifyDeviceStatus(priv, source, TV_INPUT_EVENT_DEVICE_AVAILABLE); |
65 | notifyDeviceStatus(priv, source, TV_INPUT_EVENT_STREAM_CONFIGURATIONS_CHANGED); |
66 | } else { |
67 | notifyDeviceStatus(priv, source, TV_INPUT_EVENT_DEVICE_UNAVAILABLE); |
68 | } |
69 | } |
70 | break; |
71 | |
72 | default: |
73 | break; |
74 | } |
75 | } |
76 | |
77 | void channelControl(tv_input_private_t *priv, bool opsStart, int device_id) { |
78 | if (priv->mpTv) { |
79 | ALOGI ("%s, device id:%d ,startTV:%d\n", __FUNCTION__, device_id, opsStart?1:0); |
80 | |
81 | if (opsStart) { |
82 | priv->mpTv->startTv(); |
83 | priv->mpTv->switchSourceInput((tv_source_input_t) device_id); |
84 | } else if (priv->mpTv->getCurrentSourceInput() == device_id) { |
85 | priv->mpTv->stopTv(); |
86 | } |
87 | } |
88 | } |
89 | |
90 | int notifyDeviceStatus(tv_input_private_t *priv, tv_source_input_t inputSrc, int type) |
91 | { |
92 | tv_input_event_t event; |
93 | event.device_info.device_id = inputSrc; |
94 | event.device_info.audio_type = AUDIO_DEVICE_NONE; |
95 | event.device_info.audio_address = NULL; |
96 | event.type = type; |
97 | switch (inputSrc) { |
98 | case SOURCE_TV: |
99 | case SOURCE_DTV: |
100 | case SOURCE_ADTV: |
101 | event.device_info.type = TV_INPUT_TYPE_TUNER; |
102 | break; |
103 | case SOURCE_AV1: |
104 | case SOURCE_AV2: |
105 | event.device_info.type = TV_INPUT_TYPE_COMPOSITE; |
106 | break; |
107 | case SOURCE_HDMI1: |
108 | case SOURCE_HDMI2: |
109 | case SOURCE_HDMI3: |
110 | case SOURCE_HDMI4: |
111 | event.device_info.type = TV_INPUT_TYPE_HDMI; |
112 | event.device_info.hdmi.port_id = priv->mpTv->getHdmiPort(inputSrc); |
113 | break; |
114 | case SOURCE_SPDIF: |
115 | event.device_info.type = TV_INPUT_TYPE_OTHER_HARDWARE; |
116 | break; |
117 | default: |
118 | break; |
119 | } |
120 | priv->callback->notify(&priv->device, &event, priv->callback_data); |
121 | return 0; |
122 | } |
123 | |
124 | static int notifyCaptureSucceeded(tv_input_private_t *priv, int device_id, int stream_id, uint32_t seq) |
125 | { |
126 | tv_input_event_t event; |
127 | event.type = TV_INPUT_EVENT_CAPTURE_SUCCEEDED; |
128 | event.capture_result.device_id = device_id; |
129 | event.capture_result.stream_id = stream_id; |
130 | event.capture_result.seq = seq; |
131 | priv->callback->notify(&priv->device, &event, priv->callback_data); |
132 | return 0; |
133 | } |
134 | |
135 | static int notifyCaptureFail(tv_input_private_t *priv, int device_id, int stream_id, uint32_t seq) |
136 | { |
137 | tv_input_event_t event; |
138 | event.type = TV_INPUT_EVENT_CAPTURE_FAILED; |
139 | event.capture_result.device_id = device_id; |
140 | event.capture_result.stream_id = stream_id; |
141 | event.capture_result.seq = seq; |
142 | priv->callback->notify(&priv->device, &event, priv->callback_data); |
143 | return 0; |
144 | } |
145 | |
146 | static bool getStreamConfigs(int dev_id __unused, int *num_configurations, const tv_stream_config_t **configs) |
147 | { |
148 | static tv_stream_config_t mconfig[2]; |
149 | mconfig[0].stream_id = STREAM_ID_NORMAL; |
150 | mconfig[0].type = TV_STREAM_TYPE_INDEPENDENT_VIDEO_SOURCE ; |
151 | mconfig[0].max_video_width = 1920; |
152 | mconfig[0].max_video_height = 1080; |
153 | mconfig[1].stream_id = STREAM_ID_FRAME_CAPTURE; |
154 | mconfig[1].type = TV_STREAM_TYPE_BUFFER_PRODUCER ; |
155 | mconfig[1].max_video_width = 1920; |
156 | mconfig[1].max_video_height = 1080; |
157 | *num_configurations = 2; |
158 | *configs = mconfig; |
159 | return true; |
160 | } |
161 | |
162 | static int getTvStream(tv_stream_t *stream) |
163 | { |
164 | if (stream->stream_id == STREAM_ID_NORMAL) { |
165 | if (pTvStream == nullptr) { |
166 | pTvStream = (struct sideband_handle_t *)native_handle_create(0, 2); |
167 | if (pTvStream == nullptr) { |
168 | ALOGE("tvstream can not be initialized"); |
169 | return -EINVAL; |
170 | } |
171 | } |
172 | pTvStream->identflag = 0xabcdcdef; //magic word |
173 | pTvStream->usage = GRALLOC_USAGE_AML_VIDEO_OVERLAY; |
174 | stream->type = TV_STREAM_TYPE_INDEPENDENT_VIDEO_SOURCE; |
175 | stream->sideband_stream_source_handle = (native_handle_t *)pTvStream; |
176 | } else if (stream->stream_id == STREAM_ID_FRAME_CAPTURE) { |
177 | stream->type = TV_STREAM_TYPE_BUFFER_PRODUCER; |
178 | } |
179 | return 0; |
180 | } |
181 | |
182 | void initTvDevices(tv_input_private_t *priv) |
183 | { |
184 | int supportDevices[20]; |
185 | int count = 0; |
186 | priv->mpTv->getSupportInputDevices(supportDevices, &count); |
187 | |
188 | if (count == 0) { |
189 | ALOGE("tv.source.input.ids.default is not set."); |
190 | return; |
191 | } |
192 | |
193 | bool isHotplugDetectOn = priv->mpTv->getHdmiAvHotplugDetectOnoff(); |
194 | ALOGI("hdmi/av hotplug detect on: %s", isHotplugDetectOn?"YES":"NO"); |
195 | if (isHotplugDetectOn) |
196 | priv->mpTv->setTvObserver(priv->eventCallback); |
197 | |
198 | for (int i = 0; i < count; i++) { |
199 | tv_source_input_t inputSrc = (tv_source_input_t)supportDevices[i]; |
200 | |
201 | bool status = true; |
202 | if (isHotplugDetectOn && SOURCE_AV1 <= inputSrc && inputSrc <= SOURCE_HDMI4) { |
203 | status = priv->mpTv->getSourceConnectStatus(inputSrc); |
204 | } |
205 | |
206 | if (status) { |
207 | notifyDeviceStatus(priv, inputSrc, TV_INPUT_EVENT_DEVICE_AVAILABLE); |
208 | notifyDeviceStatus(priv, inputSrc, TV_INPUT_EVENT_STREAM_CONFIGURATIONS_CHANGED); |
209 | } |
210 | } |
211 | } |
212 | |
213 | static int tv_input_initialize(struct tv_input_device *dev, |
214 | const tv_input_callback_ops_t *callback, void *data) |
215 | { |
216 | if (dev == NULL || callback == NULL) { |
217 | return -EINVAL; |
218 | } |
219 | tv_input_private_t *priv = (tv_input_private_t *)dev; |
220 | if (priv->callback != NULL) { |
221 | ALOGE("tv input had been init done, do not need init again"); |
222 | return -EEXIST; |
223 | } |
224 | priv->callback = callback; |
225 | priv->callback_data = data; |
226 | |
227 | initTvDevices(priv); |
228 | return 0; |
229 | } |
230 | |
231 | static int tv_input_get_stream_configurations(const struct tv_input_device *dev __unused, |
232 | int device_id, int *num_configurations, |
233 | const tv_stream_config_t **configs) |
234 | { |
235 | if (getStreamConfigs(device_id, num_configurations, configs)) { |
236 | return 0; |
237 | } |
238 | return -EINVAL; |
239 | } |
240 | |
241 | static int tv_input_open_stream(struct tv_input_device *dev, int device_id, |
242 | tv_stream_t *stream) |
243 | { |
244 | tv_input_private_t *priv = (tv_input_private_t *)dev; |
245 | if (priv) { |
246 | if (getTvStream(stream) != 0) { |
247 | return -EINVAL; |
248 | } |
249 | if (stream->stream_id == STREAM_ID_NORMAL) { |
250 | channelControl(priv, true, device_id); |
251 | } |
252 | else if (stream->stream_id == STREAM_ID_FRAME_CAPTURE) { |
253 | aml_screen_module_t* screenModule; |
254 | if (hw_get_module(AML_SCREEN_HARDWARE_MODULE_ID, (const hw_module_t **)&screenModule) < 0) { |
255 | ALOGE("can not get screen source module"); |
256 | } else { |
257 | screenModule->common.methods->open((const hw_module_t *)screenModule, |
258 | AML_SCREEN_SOURCE, (struct hw_device_t**)&(priv->mDev)); |
259 | //do test here, we can use ops of mDev to operate vdin source |
260 | } |
261 | |
262 | if (priv->mDev) { |
263 | if (capWidth == 0 || capHeight == 0) { |
264 | capWidth = stream->buffer_producer.width; |
265 | capHeight = stream->buffer_producer.height; |
266 | } |
267 | priv->mDev->ops.set_format(priv->mDev, capWidth, capHeight, V4L2_PIX_FMT_NV21); |
268 | priv->mDev->ops.set_port_type(priv->mDev, (int)0x4000); //TVIN_PORT_HDMI0 = 0x4000 |
269 | priv->mDev->ops.start_v4l2_device(priv->mDev); |
270 | } |
271 | } |
272 | return 0; |
273 | } |
274 | return -EINVAL; |
275 | } |
276 | |
277 | static int tv_input_close_stream(struct tv_input_device *dev, int device_id, |
278 | int stream_id) |
279 | { |
280 | tv_input_private_t *priv = (tv_input_private_t *)dev; |
281 | if (stream_id == STREAM_ID_NORMAL) { |
282 | channelControl(priv, false, device_id); |
283 | return 0; |
284 | } else if (stream_id == STREAM_ID_FRAME_CAPTURE) { |
285 | if (priv->mDev) { |
286 | priv->mDev->ops.stop_v4l2_device(priv->mDev); |
287 | } |
288 | return 0; |
289 | } |
290 | return -EINVAL; |
291 | } |
292 | |
293 | static int tv_input_request_capture( |
294 | struct tv_input_device *dev, int device_id, |
295 | int stream_id, buffer_handle_t buffer, uint32_t seq) |
296 | { |
297 | tv_input_private_t *priv = (tv_input_private_t *)dev; |
298 | unsigned char *dest = NULL; |
299 | if (priv->mDev) { |
300 | aml_screen_buffer_info_t buffInfo; |
301 | int ret = priv->mDev->ops.aquire_buffer(priv->mDev, &buffInfo); |
302 | if (ret != 0 || (buffInfo.buffer_mem == nullptr)) { |
303 | ALOGE("Get V4l2 buffer failed"); |
304 | notifyCaptureFail(priv,device_id,stream_id,--seq); |
305 | return -EWOULDBLOCK; |
306 | } |
307 | long *src = (long *)buffInfo.buffer_mem; |
308 | |
309 | ANativeWindowBuffer *buf = container_of(buffer, ANativeWindowBuffer, handle); |
310 | sp<GraphicBuffer> graphicBuffer(new GraphicBuffer(buf->handle, GraphicBuffer::WRAP_HANDLE, |
311 | buf->width, buf->height, |
312 | buf->format, buf->layerCount, |
313 | buf->usage, buf->stride)); |
314 | graphicBuffer->lock(SCREENSOURCE_GRALLOC_USAGE, (void **)&dest); |
315 | if (dest == NULL) { |
316 | ALOGE("Invalid Gralloc Handle"); |
317 | return -EWOULDBLOCK; |
318 | } |
319 | memcpy(dest, src, capWidth*capHeight); |
320 | graphicBuffer->unlock(); |
321 | graphicBuffer.clear(); |
322 | priv->mDev->ops.release_buffer(priv->mDev, src); |
323 | |
324 | notifyCaptureSucceeded(priv, device_id, stream_id, seq); |
325 | return 0; |
326 | } |
327 | return -EWOULDBLOCK; |
328 | } |
329 | |
330 | static int tv_input_cancel_capture(struct tv_input_device *, int, int, uint32_t) |
331 | { |
332 | return -EINVAL; |
333 | } |
334 | |
335 | static int tv_input_set_capturesurface_size(struct tv_input_device *dev __unused, int width, int height) |
336 | { |
337 | if (width == 0 || height == 0) { |
338 | return -EINVAL; |
339 | } else { |
340 | capWidth = width; |
341 | capHeight = height; |
342 | return 1; |
343 | } |
344 | } |
345 | |
346 | static int tv_input_device_close(struct hw_device_t *dev) |
347 | { |
348 | tv_input_private_t *priv = (tv_input_private_t *)dev; |
349 | if (priv) { |
350 | if (priv->mpTv) { |
351 | delete priv->mpTv; |
352 | priv->mpTv = nullptr; |
353 | } |
354 | |
355 | if (priv->mDev) { |
356 | delete priv->mDev; |
357 | priv->mDev = nullptr; |
358 | } |
359 | |
360 | if (priv->eventCallback) { |
361 | delete priv->eventCallback; |
362 | priv->eventCallback = nullptr; |
363 | } |
364 | free(priv); |
365 | |
366 | native_handle_delete((native_handle_t*)pTvStream); |
367 | } |
368 | return 0; |
369 | } |
370 | |
371 | static int tv_input_device_open(const struct hw_module_t *module, |
372 | const char *name, struct hw_device_t **device) |
373 | { |
374 | int status = -EINVAL; |
375 | if (!strcmp(name, TV_INPUT_DEFAULT_DEVICE)) { |
376 | tv_input_private_t *dev = (tv_input_private_t *)malloc(sizeof(*dev)); |
377 | /* initialize our state here */ |
378 | memset(dev, 0, sizeof(*dev)); |
379 | dev->mpTv = new TvInputIntf(); |
380 | dev->eventCallback = new EventCallback(dev); |
381 | /* initialize the procs */ |
382 | dev->device.common.tag = HARDWARE_DEVICE_TAG; |
383 | dev->device.common.version = TV_INPUT_DEVICE_API_VERSION_0_1; |
384 | dev->device.common.module = const_cast<hw_module_t *>(module); |
385 | dev->device.common.close = tv_input_device_close; |
386 | |
387 | dev->device.initialize = tv_input_initialize; |
388 | dev->device.get_stream_configurations = |
389 | tv_input_get_stream_configurations; |
390 | dev->device.open_stream = tv_input_open_stream; |
391 | dev->device.close_stream = tv_input_close_stream; |
392 | dev->device.request_capture = tv_input_request_capture; |
393 | dev->device.cancel_capture = tv_input_cancel_capture; |
394 | //dev->device.set_capturesurface_size = tv_input_set_capturesurface_size; |
395 | |
396 | *device = &dev->device.common; |
397 | status = 0; |
398 | } |
399 | return status; |
400 | } |
401 | |
402 | static struct hw_module_methods_t tv_input_module_methods = { |
403 | .open = tv_input_device_open |
404 | }; |
405 | |
406 | /* |
407 | * The tv input Module |
408 | */ |
409 | tv_input_module_t HAL_MODULE_INFO_SYM = { |
410 | .common = { |
411 | .tag = HARDWARE_MODULE_TAG, |
412 | .version_major = 0, |
413 | .version_minor = 1, |
414 | .id = TV_INPUT_HARDWARE_MODULE_ID, |
415 | .name = "Amlogic tv input Module", |
416 | .author = "Amlogic Corp.", |
417 | .methods = &tv_input_module_methods, |
418 | } |
419 | }; |
420 |