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