summaryrefslogtreecommitdiff
path: root/tv_input.cpp (plain)
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
40static 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
44static int capWidth;
45static int capHeight;
46
47struct sideband_handle_t *pTvStream = nullptr;
48
49void 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
77void 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
90int 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
124static 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
135static 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
146static 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
162static 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
182void 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
213static 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
231static 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
241static 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
277static 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
293static 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
330static int tv_input_cancel_capture(struct tv_input_device *, int, int, uint32_t)
331{
332 return -EINVAL;
333}
334
335static 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
346static 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
371static 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
402static struct hw_module_methods_t tv_input_module_methods = {
403 .open = tv_input_device_open
404};
405
406/*
407 * The tv input Module
408 */
409tv_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