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