summaryrefslogtreecommitdiff
path: root/tvapi/libtv/tv/CTvSubtitle.cpp (plain)
blob: bd84703d54efcefae54d5911732326114677a6ac
1//
2//
3// amlogic 2013
4//
5// @ Project : tv
6// @ Date : 2013-11
7// @ Author :
8//
9//
10#include "CTvSubtitle.h"
11#include "am_misc.h"
12#include "am_dmx.h"
13CTvSubtitle::CTvSubtitle()
14{
15 mpObser = NULL;
16}
17CTvSubtitle::~CTvSubtitle()
18{
19}
20void CTvSubtitle::setObserver(IObserver *pObser)
21{
22 isSubOpen = false;
23 mpObser = pObser;
24}
25void CTvSubtitle::setBuffer(char *share_mem)
26{
27 pthread_mutex_lock(&lock);
28 buffer = (unsigned char *)share_mem;
29 pthread_mutex_unlock(&lock);
30}
31void CTvSubtitle::stopDecoder()
32{
33}
34/**
35 * 开始字幕信息解析showboz sync
36 */
37void CTvSubtitle::startSub()
38{
39}
40
41/**
42 * 停止图文/字幕信息解析
43 */
44void CTvSubtitle::stop()
45{
46}
47
48/**
49 * 停止图文/字幕信息解析并清除缓存数据
50 */
51void CTvSubtitle::clear()
52{
53
54}
55
56/**
57 * 在图文模式下进入下一页
58 */
59void CTvSubtitle::nextPage()
60{
61
62}
63
64/**
65 * 在图文模式下进入上一页
66 */
67void CTvSubtitle::previousPage()
68{
69
70}
71
72/**
73 * 在图文模式下跳转到指定页
74 * @param page 要跳转到的页号
75 */
76void CTvSubtitle::gotoPage(int page)
77{
78
79}
80
81/**
82 * 在图文模式下跳转到home页
83 */
84void CTvSubtitle::goHome()
85{
86
87}
88
89/**
90 * 在图文模式下根据颜色跳转到指定链接
91 * @param color 颜色,COLOR_RED/COLOR_GREEN/COLOR_YELLOW/COLOR_BLUE
92 */
93void CTvSubtitle::colorLink(int color)
94{
95
96}
97
98/**
99 * 在图文模式下设定搜索字符串
100 * @param pattern 搜索匹配字符串
101 * @param casefold 是否区分大小写
102 */
103void CTvSubtitle::setSearchPattern(char *pattern, bool casefold)
104{
105
106}
107
108/**
109 * 搜索下一页
110 */
111void CTvSubtitle::searchNext()
112{
113}
114
115/**
116 * 搜索上一页
117 */
118void CTvSubtitle::searchPrevious()
119{
120}
121
122int CTvSubtitle::sub_init(int bmp_width, int bmp_height)
123{
124 pthread_mutex_init(&lock, NULL);
125 bmp_w = bmp_width;
126 bmp_h = bmp_height;
127 sub_w = 720;
128 sub_h = 576;
129 bmp_pitch = bmp_w * 4;
130 return 0;
131}
132
133int CTvSubtitle::sub_destroy()
134{
135 return 0;
136}
137
138int CTvSubtitle::sub_lock()
139{
140 pthread_mutex_lock(&lock);
141 return 0;
142}
143
144int CTvSubtitle::sub_unlock()
145{
146 pthread_mutex_unlock(&lock);
147 return 0;
148}
149
150int CTvSubtitle::sub_clear()
151{
152 return 0;
153}
154
155static void clear_bitmap(CTvSubtitle *pSub)
156{
157 unsigned char *ptr = pSub->buffer;
158 int y = pSub->bmp_h;
159
160 while (y--) {
161 memset(ptr, 0, pSub->bmp_pitch);
162 ptr += pSub->bmp_pitch;
163 }
164
165}
166
167static void show_sub_cb(AM_SUB2_Handle_t handle, AM_SUB2_Picture_t *pic)
168{
169 LOGD("dvb callback-----------");
170
171 CTvSubtitle *pSub = ((CTvSubtitle *) AM_SUB2_GetUserData(handle));
172 pthread_mutex_lock(&pSub->lock);
173 clear_bitmap(pSub);
174
175 if (pic) {
176 AM_SUB2_Region_t *rgn = pic->p_region;
177 pSub->sub_w = pic->original_width;
178 pSub->sub_h = pic->original_height;
179 while (rgn) {
180 int sx, sy, dx, dy, rw, rh;
181
182 // ensure we have a valid buffer
183 if (! rgn->p_buf) {
184 rgn = rgn->p_next;
185 continue;
186 }
187
188 sx = 0;
189 sy = 0;
190 dx = pic->original_x + rgn->left;
191 dy = pic->original_y + rgn->top;
192 rw = rgn->width;
193 rh = rgn->height;
194
195 if (dx < 0) {
196 sx = -dx;
197 dx = 0;
198 rw += dx;
199 }
200
201 if (dx + rw > pSub->bmp_w) {
202 rw = pSub->bmp_w - dx;
203 }
204
205 if (dy < 0) {
206 sy = -dy;
207 dy = 0;
208 rh += dy;
209 }
210
211 if (dy + rh > pSub->bmp_h) {
212 rh = pSub->bmp_h - dy;
213 }
214
215 if ((rw > 0) && (rh > 0)) {
216 unsigned char *sbegin = (unsigned char *)rgn->p_buf + sy * rgn->width + sx;
217 unsigned char *dbegin = pSub->buffer + dy * pSub->bmp_pitch + dx * 4;
218 unsigned char *src, *dst;
219 int size;
220
221 while (rh) {
222 src = sbegin;
223 dst = dbegin;
224 size = rw;
225 while (size--) {
226 int c = src[0];
227
228 if (c < (int)rgn->entry) {
229 if (rgn->clut[c].a) {
230 *dst++ = rgn->clut[c].r;
231 *dst++ = rgn->clut[c].g;
232 *dst++ = rgn->clut[c].b;
233 } else {
234 dst += 3;
235 }
236 *dst++ = rgn->clut[c].a;
237 } else {
238 dst += 4;
239 }
240 src ++;
241 }
242 sbegin += rgn->width;
243 dbegin += pSub->bmp_pitch;
244 rh--;
245 }
246 }
247
248 rgn = rgn->p_next;
249 }
250 pSub->mpObser->updateSubtitle(pic->original_width, pic->original_height);
251 }
252 pthread_mutex_unlock(&pSub->lock);
253
254}
255
256static uint64_t get_pts_cb(void *handle, uint64_t pts)
257{
258 char buf[32];
259 AM_ErrorCode_t ret;
260 uint32_t v;
261 uint64_t r;
262
263 ret = AM_FileRead("/sys/class/tsync/pts_pcrscr", buf, sizeof(buf));
264 if (!ret) {
265 v = strtoul(buf, 0, 16);
266 if (pts & (1LL << 32)) {
267 r = ((uint64_t)v) | (1LL << 32);
268 } else {
269 r = (uint64_t)v;
270 }
271 } else {
272 r = 0LL;
273 }
274
275 return r;
276}
277
278static void pes_data_cb(int dev_no, int fhandle, const uint8_t *data, int len, void *user_data)
279{
280 CTvSubtitle *pSub = ((CTvSubtitle *) user_data);
281 AM_PES_Decode(pSub->pes_handle, (uint8_t *)data, len);
282}
283
284static int close_dmx(CTvSubtitle *pSub)
285{
286 AM_DMX_FreeFilter(pSub->dmx_id, pSub->filter_handle);
287 AM_DMX_Close(pSub->dmx_id);
288 pSub->dmx_id = -1;
289 pSub->filter_handle = -1;
290
291 return 0;
292}
293
294static int open_dmx(CTvSubtitle *pSub, int dmx_id, int pid)
295{
296 close_dmx(pSub);
297 AM_DMX_OpenPara_t op;
298 struct dmx_pes_filter_params pesp;
299 AM_ErrorCode_t ret;
300
301 pSub->dmx_id = -1;
302 pSub->filter_handle = -1;
303 memset(&op, 0, sizeof(op));
304
305 ret = AM_DMX_Open(dmx_id, &op);
306 if (ret != AM_SUCCESS) {
307 LOGD("error AM_DMX_Open != AM_SUCCESS");
308 goto error;
309 }
310 pSub->dmx_id = dmx_id;
311
312 ret = AM_DMX_AllocateFilter(dmx_id, &pSub->filter_handle);
313 if (ret != AM_SUCCESS) {
314 LOGD("error AM_DMX_AllocateFilter != AM_SUCCESS");
315 goto error;
316 }
317
318 ret = AM_DMX_SetBufferSize(dmx_id, pSub->filter_handle, 0x80000);
319 if (ret != AM_SUCCESS) {
320 LOGD("error AM_DMX_SetBufferSize != AM_SUCCESS");
321 goto error;
322 }
323
324 memset(&pesp, 0, sizeof(pesp));
325 pesp.pid = pid;
326 pesp.output = DMX_OUT_TAP;
327 pesp.pes_type = DMX_PES_TELETEXT0;
328
329 ret = AM_DMX_SetPesFilter(dmx_id, pSub->filter_handle, &pesp);
330 if (ret != AM_SUCCESS) {
331 LOGD("error AM_DMX_SetPesFilter != AM_SUCCESS, err = %d", strerror(errno));
332 goto error;
333 }
334
335 ret = AM_DMX_SetCallback(dmx_id, pSub->filter_handle, pes_data_cb, pSub);
336 if (ret != AM_SUCCESS) {
337 LOGD("error AM_DMX_SetCallback != AM_SUCCESS");
338 goto error;
339 }
340
341 ret = AM_DMX_StartFilter(dmx_id, pSub->filter_handle);
342 if (ret != AM_SUCCESS) {
343 LOGD("error AM_DMX_StartFilter != AM_SUCCESS,dmx_id=%d,filter_handle=%d, ret = %d", dmx_id, pSub->filter_handle, ret);
344 goto error;
345 }
346
347 return 0;
348error:
349 if (pSub->filter_handle != -1) {
350 AM_DMX_FreeFilter(dmx_id, pSub->filter_handle);
351 }
352 if (pSub->dmx_id != -1) {
353 AM_DMX_Close(dmx_id);
354 }
355
356 return -1;
357}
358
359static void pes_sub_cb(AM_PES_Handle_t handle, uint8_t *buf, int size)
360{
361 CTvSubtitle *pSub = ((CTvSubtitle *) AM_SUB2_GetUserData(handle));
362 AM_SUB2_Decode(pSub->sub_handle, buf, size);
363}
364
365int CTvSubtitle::sub_switch_status()
366{
367 return isSubOpen ? 1 : 0;
368}
369int CTvSubtitle::sub_start_dvb_sub(int dmx_id, int pid, int page_id, int anc_page_id)
370{
371 LOGD("start dvb subtitle=----------------");
372
373 AM_PES_Para_t pesp;
374 AM_SUB2_Para_t subp;
375 int ret;
376
377 memset(&pesp, 0, sizeof(pesp));
378 pesp.packet = pes_sub_cb;
379 pesp.user_data = this;
380 ret = AM_PES_Create(&pes_handle, &pesp);
381 if (ret != AM_SUCCESS) {
382 LOGD("error AM_PES_Create != AM_SUCCESS");
383 goto error;
384 }
385
386 memset(&subp, 0, sizeof(subp));
387 subp.show = show_sub_cb;
388 subp.get_pts = get_pts_cb;
389 subp.composition_id = page_id;
390 subp.ancillary_id = anc_page_id;
391 subp.user_data = this;
392 ret = AM_SUB2_Create(&sub_handle, &subp);
393 if (ret != AM_SUCCESS) {
394 LOGD("error AM_SUB2_Create != AM_SUCCESS");
395 goto error;
396 }
397
398 ret = AM_SUB2_Start(sub_handle);
399 if (ret != AM_SUCCESS) {
400 LOGD("error AM_SUB2_Start != AM_SUCCESS");
401 goto error;
402 }
403
404 ret = open_dmx(this, dmx_id, pid);
405 if (ret < 0) {
406 LOGD("error open_dmx != AM_SUCCESS");
407 goto error;
408 }
409 isSubOpen = true;
410 return 0;
411error:
412 if (sub_handle) {
413 AM_SUB2_Destroy(sub_handle);
414 sub_handle = NULL;
415 }
416 if (pes_handle) {
417 AM_PES_Destroy(pes_handle);
418 pes_handle = NULL;
419 }
420 return -1;
421}
422
423int CTvSubtitle::sub_start_dtv_tt(int dmx_id, int region_id, int pid, int page, int sub_page, bool is_sub)
424{
425 return 0;
426}
427
428int CTvSubtitle::sub_stop_dvb_sub()
429{
430 pthread_mutex_lock(&lock);
431 close_dmx(this);
432 AM_SUB2_Destroy(sub_handle);
433 AM_PES_Destroy(pes_handle);
434
435 clear_bitmap(this);
436 mpObser->updateSubtitle(0, 0);
437
438 sub_handle = NULL;
439 pes_handle = NULL;
440 isSubOpen = false;
441 pthread_mutex_unlock(&lock);
442 return 0;
443}
444
445int CTvSubtitle::sub_stop_dtv_tt()
446{
447 return 0;
448}
449
450int CTvSubtitle::sub_tt_goto(int page)
451{
452 return 0;
453}
454
455int CTvSubtitle::sub_tt_color_link(int color)
456{
457 return 0;
458}
459
460int CTvSubtitle::sub_tt_home_link()
461{
462 return 0;
463}
464
465int CTvSubtitle::sub_tt_next(int dir)
466{
467 return 0;
468}
469
470int CTvSubtitle::sub_tt_set_search_pattern(char *pattern, bool casefold)
471{
472 return 0;
473}
474
475int CTvSubtitle::sub_tt_search(int dir)
476{
477 return 0;
478}
479
480/*
481 * 1, Set the country first and parameters should be either USA or KOREA
482#define CMD_SET_COUNTRY_USA 0x5001
483#define CMD_SET_COUNTRY_KOREA 0x5002
484
4852, Set the source type which including
486 a)VBI data(for analog program only)
487 b)USER data(for AIR or Cable service)
488CMD_CC_SET_VBIDATA = 0x7001,
489CMD_CC_SET_USERDATA = 0x7002,
4902.1 If the frontend type is Analog we must set the channel Index
491 with command 'CMD_CC_SET_CHAN_NUM' and the parameter is like 57M
492 we set 0x20000, this should according to USA standard frequency
493 table.
494
4953, Next is to set the CC service type
496
497#define CMD_CC_1 0x3001
498#define CMD_CC_2 0x3002
499#define CMD_CC_3 0x3003
500#define CMD_CC_4 0x3004
501
502//this doesn't support currently
503#define CMD_TT_1 0x3005
504#define CMD_TT_2 0x3006
505#define CMD_TT_3 0x3007
506#define CMD_TT_4 0x3008
507
508#define CMD_SERVICE_1 0x4001
509#define CMD_SERVICE_2 0x4002
510#define CMD_SERVICE_3 0x4003
511#define CMD_SERVICE_4 0x4004
512#define CMD_SERVICE_5 0x4005
513#define CMD_SERVICE_6 0x4006
514
5154, Then set CMD_CC_START to start the CC service, and you needn't to stop
516
517CC service while switching services
518
5195, CMD_CC_STOP should be called in some cases like switch source, change
520
521program, no signal, blocked...*/
522
523//channel_num == 0 ,if frontend is dtv
524//else != 0
525int CTvSubtitle::sub_start_atsc_cc(enum cc_param_country country, enum cc_param_source_type src_type, int channel_num, enum cc_param_caption_type caption_type)
526{
527 LOGD("----sub_start_atsc_cc-1--- country=%d,src=%d,ctype=%d", country, src_type, caption_type);
528 switch (country) {
529 case CC_PARAM_COUNTRY_USA:
530 AM_CC_Cmd(CMD_SET_COUNTRY_USA);
531 break;
532 case CC_PARAM_COUNTRY_KOREA:
533 AM_CC_Cmd(CMD_SET_COUNTRY_KOREA);
534 break;
535 default:
536 AM_CC_Cmd(CMD_SET_COUNTRY_USA);
537 break;
538 }
539
540 switch (src_type) {
541 case CC_PARAM_SOURCE_VBIDATA:
542 AM_CC_Cmd(CMD_CC_SET_VBIDATA);
543 break;
544 case CC_PARAM_SOURCE_USERDATA:
545 AM_CC_Cmd(CMD_CC_SET_USERDATA);
546 break;
547 default:
548 AM_CC_Cmd(CMD_CC_SET_USERDATA);
549 break;
550 }
551
552 //just for test
553 if (channel_num == 0) {
554 } else {
555 //AM_CC_Cmd(CMD_CC_SET_CHAN_NUM);
556 }
557
558 AM_CLOSECAPTION_cmd_t cc_t_cmd;
559 switch (caption_type) {
560 case CC_PARAM_ANALOG_CAPTION_TYPE_CC1:
561 cc_t_cmd = CMD_CC_1;
562 break;
563 case CC_PARAM_ANALOG_CAPTION_TYPE_CC2:
564 cc_t_cmd = CMD_CC_2;
565 break;
566 case CC_PARAM_ANALOG_CAPTION_TYPE_CC3:
567 cc_t_cmd = CMD_CC_3;
568 break;
569 case CC_PARAM_ANALOG_CAPTION_TYPE_CC4:
570 cc_t_cmd = CMD_CC_4;
571 break;
572 case CC_PARAM_DIGITAL_CAPTION_TYPE_SERVICE1:
573 cc_t_cmd = CMD_SERVICE_1;
574 break;
575 case CC_PARAM_DIGITAL_CAPTION_TYPE_SERVICE2:
576 cc_t_cmd = CMD_SERVICE_2;
577 break;
578 case CC_PARAM_DIGITAL_CAPTION_TYPE_SERVICE3:
579 cc_t_cmd = CMD_SERVICE_3;
580 break;
581 case CC_PARAM_DIGITAL_CAPTION_TYPE_SERVICE4:
582 cc_t_cmd = CMD_SERVICE_4;
583 break;
584 default:
585 cc_t_cmd = CMD_SERVICE_1;
586 break;
587 }
588 AM_CC_Cmd(cc_t_cmd);
589
590 AM_CC_Set_CallBack(close_caption_callback, this);
591 AM_VCHIP_Set_CallBack(atv_vchip_callback, this);
592 //start
593 AM_CC_Cmd(CMD_CC_START);
594 LOGD("----sub_start_atsc_cc-2--- country=%d,src=%d,ctype=%d", country, src_type, caption_type);
595 return 0;
596}
597
598int CTvSubtitle::sub_stop_atsc_cc()
599{
600 LOGD("----sub_stop_atsc_cc----");
601 AM_CC_Cmd(CMD_CC_STOP);
602 return 0;
603}
604int CTvSubtitle::ResetVchipChgStat()
605{
606 avchip_chg = 0;
607 AM_CC_Cmd(CMD_VCHIP_RST_CHGSTAT);
608 return 0;
609}
610int CTvSubtitle::IsVchipChange()
611{
612 return avchip_chg;
613}
614//cnt :data buf len
615//databuf len is max 512
616//cmdbuf len is max 128
617void CTvSubtitle::close_caption_callback(char *str, int cnt, int data_buf[], int cmd_buf[], void *user_data)
618{
619
620 /*
621 CTvSubtitle *pSub = (CTvSubtitle *)user_data;
622
623 if (pSub == NULL)
624 {
625 LOGD("sub cc callback is null user data for this");
626 return;
627 }
628
629 if (pSub->mpObser == NULL) return;
630
631 pSub->mCurCCEv.mDataBufSize = cnt;
632 pSub->mCurCCEv.mpDataBuffer = data_buf;
633 pSub->mCurCCEv.mCmdBufSize = 128;//max
634 pSub->mCurCCEv.mpCmdBuffer = cmd_buf;
635
636 pSub->mpObser->onEvent(pSub->mCurCCEv);
637 */
638}
639void CTvSubtitle::atv_vchip_callback(int Is_chg, void *user_data)
640{
641 CTvSubtitle *pSub = (CTvSubtitle *)user_data;
642 pSub->avchip_chg = Is_chg;
643}
644