summaryrefslogtreecommitdiff
path: root/tv_input.cpp (plain)
blob: ea9f225c432ede85074fe0010664183f12dfc3e7
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 <hardware/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 bool isHotplugDetectOn = priv->mpTv->GetHdmiAvHotplugDetectOnoff();
151 if (isHotplugDetectOn) {
152 if (source != SOURCE_HDMI1 && source != SOURCE_HDMI2 && source != SOURCE_HDMI3
153 && source != SOURCE_HDMI4 && source != SOURCE_AV1 && source != SOURCE_AV2)
154 break;
155
156 if (connectState == 1) {
157 notify_tv_device_status(priv, source, TV_INPUT_EVENT_DEVICE_AVAILABLE);
158 notify_tv_device_status(priv, source, TV_INPUT_EVENT_STREAM_CONFIGURATIONS_CHANGED);
159 } else {
160 notify_tv_device_status(priv, source, TV_INPUT_EVENT_DEVICE_UNAVAILABLE);
161 }
162 } else {
163 if (connectState == 1 && (source == SOURCE_AV1 || source == SOURCE_AV2)) {
164 // need close afe at first ,it's a workarround way
165 notify_tv_device_status(priv, source, TV_INPUT_EVENT_DEVICE_UNAVAILABLE);
166 notify_tv_device_status(priv, source, TV_INPUT_EVENT_DEVICE_AVAILABLE);
167 notify_tv_device_status(priv, source, TV_INPUT_EVENT_STREAM_CONFIGURATIONS_CHANGED);
168 }
169 }
170 break;
171 }
172 default:
173 break;
174 }
175}
176
177#define NORMAL_STREAM_ID 1
178#define FRAME_CAPTURE_STREAM_ID 2
179static tv_stream_config_t mconfig[2];
180static int get_stream_configs(int dev_id __unused, int *num_configurations, const tv_stream_config_t **configs)
181{
182 mconfig[0].stream_id = NORMAL_STREAM_ID;
183 mconfig[0].type = TV_STREAM_TYPE_INDEPENDENT_VIDEO_SOURCE ;
184 mconfig[0].max_video_width = 1920;
185 mconfig[0].max_video_height = 1080;
186 mconfig[1].stream_id = FRAME_CAPTURE_STREAM_ID;
187 mconfig[1].type = TV_STREAM_TYPE_BUFFER_PRODUCER ;
188 mconfig[1].max_video_width = 1920;
189 mconfig[1].max_video_height = 1080;
190 *num_configurations = 2;
191 *configs = mconfig;
192 return 0;
193}
194
195static int get_tv_stream(tv_stream_t *stream)
196{
197 static struct sideband_handle_t *tvstream = NULL;
198 if (stream->stream_id == NORMAL_STREAM_ID) {
199 if ( !tvstream ) {
200 tvstream = (struct sideband_handle_t *)native_handle_create(0, 2);
201 if ( !tvstream ) {
202 return -EINVAL;
203 }
204 }
205 tvstream->identflag = 0xabcdcdef; //magic word
206 tvstream->usage = GRALLOC_USAGE_AML_VIDEO_OVERLAY;
207 stream->type = TV_STREAM_TYPE_INDEPENDENT_VIDEO_SOURCE;
208 stream->sideband_stream_source_handle = (native_handle_t *)tvstream;
209 } else if (stream->stream_id == FRAME_CAPTURE_STREAM_ID) {
210 stream->type = TV_STREAM_TYPE_BUFFER_PRODUCER;
211 }
212 return 0;
213}
214
215static void available_all_tv_device(tv_input_private_t *priv)
216{
217 int tv_devices[15];
218 int count = 0;
219 priv->mpTv->getAllTvDevices(tv_devices, &count);
220
221 if (count == 0) {
222 ALOGE("tv.source.input.ids.default is not set.");
223 return;
224 }
225
226 bool isHotplugDetectOn = priv->mpTv->GetHdmiAvHotplugDetectOnoff();
227
228 // if (isHotplugDetectOn)
229 priv->mpTv->setTvObserver(priv->tvcallback);
230
231 for (int i=0; i < count; i++) {
232 tv_source_input_t source_input = (tv_source_input_t)tv_devices[i];
233
234 bool status = true;
235 if (isHotplugDetectOn && SOURCE_AV1 <= source_input && source_input <= SOURCE_HDMI4) {
236 status = priv->mpTv->GetSourceConnectStatus(source_input);
237 }
238
239 if (status) {
240 notify_tv_device_status(priv, source_input, TV_INPUT_EVENT_DEVICE_AVAILABLE);
241 notify_tv_device_status(priv, source_input, TV_INPUT_EVENT_STREAM_CONFIGURATIONS_CHANGED);
242 }
243 }
244}
245
246static int tv_input_device_open(const struct hw_module_t *module,
247 const char *name, struct hw_device_t **device);
248
249static struct hw_module_methods_t tv_input_module_methods = {
250open:
251 tv_input_device_open
252};
253
254tv_input_module_t HAL_MODULE_INFO_SYM = {
255common:
256 {
257tag:
258 HARDWARE_MODULE_TAG,
259 version_major: 0,
260 version_minor: 1,
261id:
262 TV_INPUT_HARDWARE_MODULE_ID,
263name: "TVInput module"
264 ,
265author: "Amlogic"
266 ,
267methods:
268 &tv_input_module_methods,
269dso: NULL,
270reserved: {0},
271 }
272};
273
274/*****************************************************************************/
275static int tv_input_initialize(struct tv_input_device *dev,
276 const tv_input_callback_ops_t *callback, void *data)
277{
278 if (dev == NULL || callback == NULL) {
279 return -EINVAL;
280 }
281 tv_input_private_t *priv = (tv_input_private_t *)dev;
282 if (priv->callback != NULL) {
283 return -EEXIST;
284 }
285 priv->callback = callback;
286 priv->callback_data = data;
287
288 available_all_tv_device(priv);
289 return 0;
290}
291
292static int tv_input_get_stream_configurations(const struct tv_input_device *dev __unused,
293 int device_id, int *num_configurations,
294 const tv_stream_config_t **configs)
295{
296 if (get_stream_configs(device_id, num_configurations, configs) == 0) {
297 return 0;
298 }
299 return -EINVAL;
300}
301
302static int tv_input_open_stream(struct tv_input_device *dev, int device_id,
303 tv_stream_t *stream)
304{
305 tv_input_private_t *priv = (tv_input_private_t *)dev;
306 if (priv) {
307 if (get_tv_stream(stream) != 0) {
308 return -EINVAL;
309 }
310 if (stream->stream_id == NORMAL_STREAM_ID) {
311 TvIputHal_ChannelConl(priv, 1, device_id);
312 return 0;
313 } else if (stream->stream_id == FRAME_CAPTURE_STREAM_ID) {
314 aml_screen_module_t* mModule;
315 if (hw_get_module(AML_SCREEN_HARDWARE_MODULE_ID,
316 (const hw_module_t **)&mModule) < 0) {
317 ALOGE("can not get screen source module");
318 } else {
319 mModule->common.methods->open((const hw_module_t *)mModule,
320 AML_SCREEN_SOURCE, (struct hw_device_t**)&(priv->mDev));
321 //do test here, we can use ops of mDev to operate vdin source
322 }
323
324 if (priv->mDev) {
325 if (capWidth == 0 || capHeight == 0) {
326 capWidth = stream->buffer_producer.width;
327 capHeight = stream->buffer_producer.height;
328 }
329 priv->mDev->ops.set_format(priv->mDev, capWidth, capHeight, V4L2_PIX_FMT_NV21);
330 priv->mDev->ops.set_port_type(priv->mDev, (int)0x4000); //TVIN_PORT_HDMI0 = 0x4000
331 priv->mDev->ops.start_v4l2_device(priv->mDev);
332 }
333 return 0;
334 }
335 }
336 return -EINVAL;
337}
338
339static int tv_input_close_stream(struct tv_input_device *dev, int device_id,
340 int stream_id)
341{
342 tv_input_private_t *priv = (tv_input_private_t *)dev;
343 if (stream_id == NORMAL_STREAM_ID) {
344 TvIputHal_ChannelConl(priv, 0, device_id);
345 return 0;
346 } else if (stream_id == FRAME_CAPTURE_STREAM_ID) {
347 if (priv->mDev) {
348 priv->mDev->ops.stop_v4l2_device(priv->mDev);
349 }
350 return 0;
351 }
352 return -EINVAL;
353}
354
355static int tv_input_request_capture(
356 struct tv_input_device *dev __unused, int device_id __unused,
357 int stream_id __unused, buffer_handle_t buffer __unused, uint32_t seq __unused)
358{
359 tv_input_private_t *priv = (tv_input_private_t *)dev;
360 int index;
361 aml_screen_buffer_info_t buff_info;
362 int mFrameWidth , mFrameHeight ;
363 int ret;
364 long *src = NULL;
365 unsigned char *dest = NULL;
366 ANativeWindowBuffer *buf;
367 if (priv->mDev) {
368 ret = priv->mDev->ops.aquire_buffer(priv->mDev, &buff_info);
369 if (ret != 0 || (buff_info.buffer_mem == 0)) {
370 LOGD("Get V4l2 buffer failed");
371 notify_TV_Input_Capture_Fail(priv,device_id,stream_id,--seq);
372 return -EWOULDBLOCK;
373 }
374 src = (long *)buff_info.buffer_mem;
375 buf = container_of(buffer, ANativeWindowBuffer, handle);
376 sp<GraphicBuffer> graphicBuffer(new GraphicBuffer(buf, false));
377 graphicBuffer->lock(SCREENSOURCE_GRALLOC_USAGE, (void **)&dest);
378 if (dest == NULL) {
379 LOGD("Invalid Gralloc Handle");
380 return -EWOULDBLOCK;
381 }
382 memcpy(dest, src, capWidth*capHeight);
383 graphicBuffer->unlock();
384 graphicBuffer.clear();
385 priv->mDev->ops.release_buffer(priv->mDev, src);
386
387 notify_TV_Input_Capture_Succeeded(priv,device_id,stream_id,seq);
388 return 0;
389 }
390 return -EWOULDBLOCK;
391}
392
393static int tv_input_cancel_capture(struct tv_input_device *, int, int, uint32_t)
394{
395 return -EINVAL;
396}
397
398static int tv_input_set_capturesurface_size(struct tv_input_device *dev __unused, int width, int height)
399{
400 if (width == 0 || height == 0) {
401 return -EINVAL;
402 } else {
403 capWidth = width;
404 capHeight = height;
405 return 1;
406 }
407}
408/*****************************************************************************/
409
410static int tv_input_device_close(struct hw_device_t *dev)
411{
412 tv_input_private_t *priv = (tv_input_private_t *)dev;
413 if (priv) {
414 if (priv->mpTv) {
415 delete priv->mpTv;
416 }
417 if (priv->mDev) {
418 delete priv->mDev;
419 }
420 free(priv);
421 }
422 return 0;
423}
424
425/*****************************************************************************/
426
427static int tv_input_device_open(const struct hw_module_t *module,
428 const char *name, struct hw_device_t **device)
429{
430 int status = -EINVAL;
431 if (!strcmp(name, TV_INPUT_DEFAULT_DEVICE)) {
432 tv_input_private_t *dev = (tv_input_private_t *)malloc(sizeof(*dev));
433 /* initialize our state here */
434 memset(dev, 0, sizeof(*dev));
435 dev->mpTv = new TvPlay();
436 dev->tvcallback = new TvCallback(dev);
437 /* initialize the procs */
438 dev->device.common.tag = HARDWARE_DEVICE_TAG;
439 dev->device.common.version = TV_INPUT_DEVICE_API_VERSION_0_1;
440 dev->device.common.module = const_cast<hw_module_t *>(module);
441 dev->device.common.close = tv_input_device_close;
442
443 dev->device.initialize = tv_input_initialize;
444 dev->device.get_stream_configurations =
445 tv_input_get_stream_configurations;
446 dev->device.open_stream = tv_input_open_stream;
447 dev->device.close_stream = tv_input_close_stream;
448 dev->device.request_capture = tv_input_request_capture;
449 dev->device.cancel_capture = tv_input_cancel_capture;
450 dev->device.set_capturesurface_size = tv_input_set_capturesurface_size;
451
452 *device = &dev->device.common;
453 status = 0;
454 }
455 return status;
456}
457