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