blob: 3bb8411b9578419f9a5c2ba0541872696402eaed
1 | #undef NDEBUG |
2 | |
3 | #include <stdio.h> |
4 | #include <stdlib.h> |
5 | #include <pthread.h> |
6 | #include <unistd.h> |
7 | #include <string.h> |
8 | #include "vbi.h" |
9 | #include "exp-gfx.h" |
10 | #include "hamm.h" |
11 | #include "dvb_demux.h" |
12 | #include "sliced.h" |
13 | #include "sliced_vbi.h" |
14 | #include "am_vbi.h" |
15 | #include "vbi_dmx.h" |
16 | |
17 | /********************define variable***************************/ |
18 | |
19 | |
20 | typedef struct |
21 | { |
22 | vbi_decoder *dec; |
23 | vbi_bool cc_status; |
24 | AM_VBI_CC_Para_t cc_para; |
25 | AM_VBI_XDS_Para_t xds_para; |
26 | int page_no; |
27 | int sub_page_no; |
28 | vbi_bool disp_update; |
29 | vbi_bool running; |
30 | uint64_t pts; |
31 | pthread_mutex_t lock; |
32 | pthread_cond_t cond; |
33 | pthread_t thread; |
34 | }AM_VBI_Parser_t; |
35 | |
36 | vbi_pgno pgno = -1; |
37 | |
38 | //AM_VBI_Parser_t *parser = NULL; |
39 | |
40 | #if 0 |
41 | static void |
42 | reset (AM_VBI_Parser_t *parser) |
43 | { |
44 | vbi_page page; |
45 | vbi_bool success; |
46 | int row; |
47 | |
48 | success = vbi_fetch_cc_page (parser->dec, &page, pgno, TRUE); |
49 | assert (success); |
50 | |
51 | for (row = 0; row <= page.rows; ++row) |
52 | render (parser,&page, row); |
53 | |
54 | vbi_unref_page (&page); |
55 | } |
56 | #endif |
57 | /**********************************************************/ |
58 | |
59 | |
60 | void vbi_cc_show(AM_VBI_Parser_t *parser) |
61 | { |
62 | |
63 | vbi_page page; |
64 | vbi_bool success; |
65 | int row; |
66 | //user_data = user_data; |
67 | |
68 | //if (pgno != -1 && parser->page_no != pgno) |
69 | // return; |
70 | |
71 | /* Fetching & rendering in the handler |
72 | is a bad idea, but this is only a test */ |
73 | AM_DEBUG("NTSC-------------------- vbi_cc_show****************\n"); |
74 | success = vbi_fetch_cc_page (parser->dec, &page, parser->page_no, TRUE); |
75 | AM_DEBUG("NTSC--------------1212------vbi_fetch_cc_page success****************\n"); |
76 | assert (success); |
77 | |
78 | int i ,j; |
79 | if(parser->cc_para.draw_begin) |
80 | parser->cc_para.draw_begin(parser); |
81 | |
82 | vbi_draw_cc_page_region (&page, VBI_PIXFMT_RGBA32_LE, parser->cc_para.bitmap, |
83 | parser->cc_para.pitch, 0, 0, page.columns, page.rows); |
84 | |
85 | if(parser->cc_para.draw_end) |
86 | parser->cc_para.draw_end(parser); |
87 | vbi_unref_page (&page); |
88 | } |
89 | |
90 | |
91 | static void* vbi_cc_thread(void *arg) |
92 | { |
93 | AM_VBI_Parser_t *parser = (AM_VBI_Parser_t*)arg; |
94 | |
95 | pthread_mutex_lock(&parser->lock); |
96 | AM_DEBUG("NTSC***************________________ vbi_cc_thread parser->running = %d\n",parser->running); |
97 | while(parser->running) |
98 | { |
99 | AM_DEBUG("NTSC***************________________ vbi_cc_thread disp_update = %d\n",parser->disp_update); |
100 | while(parser->running && !parser->disp_update){ |
101 | pthread_cond_wait(&parser->cond, &parser->lock); |
102 | } |
103 | AM_DEBUG("NTSC***************________________ vbi_cc_thread disp_update = %d\n",parser->disp_update); |
104 | if(parser->disp_update){ |
105 | vbi_cc_show(parser); |
106 | parser->disp_update = FALSE; |
107 | } |
108 | } |
109 | pthread_mutex_unlock(&parser->lock); |
110 | |
111 | return NULL; |
112 | } |
113 | |
114 | static void vbi_cc_handler(vbi_event * ev,void * user_data) |
115 | { |
116 | AM_VBI_Parser_t *parser = (AM_VBI_Parser_t*)user_data; |
117 | |
118 | if(parser->page_no == 0) |
119 | return; |
120 | //***************************************************temp add cc status |
121 | if(parser->cc_status == AM_TRUE) |
122 | if(parser->page_no == ev->ev.caption.pgno){ |
123 | //parser->page_no = ev->ev.caption.pgno; |
124 | parser->disp_update = AM_TRUE; |
125 | pthread_cond_signal(&parser->cond); |
126 | |
127 | //vbi_cc_show(parser); |
128 | } |
129 | } |
130 | |
131 | |
132 | |
133 | |
134 | |
135 | |
136 | |
137 | |
138 | |
139 | static void vbi_xds_handler (vbi_event * ev, void * user_data) |
140 | { |
141 | AM_DEBUG("xds-------------------- xds_handler****************"); |
142 | AM_VBI_Parser_t *parser = (AM_VBI_Parser_t*)user_data; |
143 | |
144 | |
145 | if(ev == NULL) |
146 | return; |
147 | vbi_program_info * prog_info = ev->ev.prog_info; |
148 | |
149 | vbi_xds_subclass_program xds_program = 0; |
150 | switch(ev->type) |
151 | { |
152 | case VBI_EVENT_ASPECT : |
153 | /* program identification number */ |
154 | if(!(prog_info->month == -1 && prog_info->day == -1 |
155 | && prog_info->hour == -1 && prog_info->min == -1 )) |
156 | { |
157 | xds_program = VBI_XDS_PROGRAM_ID; |
158 | AM_DEBUG("xds*********VBI_XDS_PROGRAM_ID \n"); |
159 | break; |
160 | } |
161 | /* program name */ |
162 | if(!(prog_info->title[0] == 0)) |
163 | { |
164 | xds_program = VBI_XDS_PROGRAM_NAME; |
165 | AM_DEBUG("xds*********VBI_XDS_PROGRAM_NAME \n"); |
166 | break; |
167 | } |
168 | /* program aspect ratio */ |
169 | if(!(prog_info->aspect.first_line == prog_info->aspect.last_line == -1 && prog_info->aspect.ratio == 0.0)) |
170 | { |
171 | xds_program = VBI_XDS_PROGRAM_ASPECT_RATIO; |
172 | AM_DEBUG("xds*********VBI_XDS_PROGRAM_ASPECT_RATIO \n"); |
173 | break; |
174 | } |
175 | |
176 | break; |
177 | case VBI_EVENT_PROG_INFO : |
178 | /* 02 Program Length */ |
179 | if(!(prog_info->length_hour == -1 && prog_info->length_min == -1 &&prog_info->elapsed_hour == -1 && |
180 | prog_info->elapsed_min == -1 &&prog_info->elapsed_sec == -1 )) |
181 | { |
182 | xds_program = VBI_XDS_PROGRAM_LENGTH; |
183 | AM_DEBUG("xds*********VBI_XDS_PROGRAM_LENGTH \n"); |
184 | break; |
185 | } |
186 | |
187 | /* 04 Program type */ |
188 | /* |
189 | * If unknown type_classf == VBI_PROG_CLASSF_NONE. |
190 | * VBI_PROG_CLASSF_EIA_608 can have up to 32 tags |
191 | * identifying 96 keywords. Their numerical value |
192 | * is given here instead of composing a string for |
193 | * easier filtering. Use vbi_prog_type_str_by_id to |
194 | * get the keywords. A zero marks the end. |
195 | */ |
196 | if(!(prog_info->type_classf == VBI_PROG_CLASSF_NONE)) |
197 | { |
198 | xds_program = VBI_XDS_PROGRAM_TYPE; |
199 | AM_DEBUG("xds*********VBI_XDS_PROGRAM_TYPE \n"); |
200 | break; |
201 | } |
202 | |
203 | /* 05 Program rating */ |
204 | /* |
205 | * For details STFW for "v-chip" |
206 | * If unknown rating_auth == VBI_RATING_NONE |
207 | */ |
208 | if(!(prog_info->rating.auth == VBI_RATING_AUTH_NONE)) |
209 | { |
210 | xds_program = VBI_XDS_PROGRAM_RATING; |
211 | AM_DEBUG("xds*********VBI_XDS_PROGRAM_RATING \n"); |
212 | break; |
213 | } |
214 | |
215 | /* 06 Program Audio Services */ |
216 | /* |
217 | * BTSC audio (two independent tracks) is flagged according to XDS, |
218 | * Zweiton/NICAM/EIA-J audio is flagged mono/none, stereo/none or |
219 | * mono/mono for bilingual transmissions. |
220 | */ |
221 | if((prog_info->audio[0].mode != VBI_AUDIO_MODE_UNKNOWN) || |
222 | (prog_info->audio[1].mode != VBI_AUDIO_MODE_UNKNOWN)) |
223 | { |
224 | xds_program = VBI_XDS_PROGRAM_AUDIO_SERVICES; |
225 | AM_DEBUG("xds*********VBI_XDS_PROGRAM_AUDIO_SERVICES \n"); |
226 | break; |
227 | } |
228 | |
229 | /* 07 Program Caption Services */ |
230 | /* |
231 | * Bits 0...7 corresponding to Caption page 1...8. |
232 | * Note for the current program this information is also |
233 | * available via vbi_classify_page(). |
234 | * |
235 | * If unknown caption_services == -1, _language[] = NULL |
236 | */ |
237 | if(!(prog_info->caption_services == -1)) |
238 | { |
239 | xds_program = VBI_XDS_PROGRAM_CAPTION_SERVICES; |
240 | AM_DEBUG("xds*********VBI_XDS_PROGRAM_CAPTION_SERVICES \n"); |
241 | break; |
242 | } |
243 | break; |
244 | |
245 | } |
246 | |
247 | if(prog_info->rating.auth != VBI_RATING_AUTH_NONE) |
248 | { |
249 | AM_DEBUG("xds**********prog_info->rating_auth = %d\n",prog_info->rating.auth ); |
250 | |
251 | if(prog_info->rating.auth == VBI_RATING_AUTH_MPAA) |
252 | AM_DEBUG("xds**********result*******************VBI_RATING_AUTH_MPAA\n"); |
253 | if(prog_info->rating.auth == VBI_RATING_AUTH_TV_US) |
254 | AM_DEBUG("xds**********result*******************VBI_RATING_AUTH_TV_US\n"); |
255 | if(prog_info->rating.auth == VBI_RATING_AUTH_TV_CA_EN) |
256 | AM_DEBUG("xds**********result*******************VBI_RATING_AUTH_TV_CA_EN\n"); |
257 | if(prog_info->rating.auth == VBI_RATING_AUTH_TV_CA_FR) |
258 | AM_DEBUG("xds**********result*******************VBI_RATING_AUTH_TV_CA_FR\n"); |
259 | if(prog_info->rating.auth == VBI_RATING_AUTH_NONE) |
260 | AM_DEBUG("result*******************VBI_RATING_AUTH_NONE\n"); |
261 | |
262 | if (prog_info->rating.dlsv == VBI_RATING_D) |
263 | AM_DEBUG("xds**********result*******************VBI_RATING_D\n"); |
264 | if (prog_info->rating.dlsv == VBI_RATING_L) |
265 | AM_DEBUG("xds**********result*******************VBI_RATING_L\n"); |
266 | if (prog_info->rating.dlsv == VBI_RATING_S) |
267 | AM_DEBUG("xds**********result*******************VBI_RATING_S\n"); |
268 | if (prog_info->rating.dlsv == VBI_RATING_V) |
269 | AM_DEBUG("xds**********result*******************VBI_RATING_V\n"); |
270 | AM_DEBUG("xds**********result*******************prog_info->rating_id = %d\n",prog_info->rating.id ); |
271 | |
272 | } |
273 | |
274 | parser->xds_para.xds_callback(parser,xds_program,*prog_info); |
275 | |
276 | } |
277 | |
278 | /**********************************************************/ |
279 | |
280 | static vbi_bool |
281 | decode_frame (const vbi_sliced * sliced, |
282 | unsigned int n_lines, |
283 | const uint8_t * raw, |
284 | const vbi_sampling_par *sp, |
285 | double sample_time, |
286 | int64_t stream_time, |
287 | void * user_data) |
288 | { |
289 | AM_DEBUG("NTSC-------------------- decode_frame\n"); |
290 | if(user_data == NULL) return FALSE; |
291 | AM_VBI_Parser_t *parser = (AM_VBI_Parser_t*)user_data; |
292 | raw = raw; |
293 | sp = sp; |
294 | stream_time = stream_time; /* unused */ |
295 | |
296 | vbi_decode (parser->dec, sliced, n_lines, sample_time); |
297 | return TRUE; |
298 | } |
299 | |
300 | |
301 | |
302 | vbi_bool |
303 | decode_vbi (int dev_no, int fid, const uint8_t *data, int len, void *user_data){ |
304 | |
305 | AM_DEBUG("NTSC-------------------- decode_vbi len = %d\n",len); |
306 | AM_VBI_Parser_t *parser = (AM_VBI_Parser_t*)user_data; |
307 | if(user_data == NULL) |
308 | AM_DEBUG("NTSC-------------------- decode_vbi NOT user_data "); |
309 | |
310 | int length = len; |
311 | struct stream *st; |
312 | if(len < 0 || data == NULL) |
313 | goto error; |
314 | st = read_stream_new (data,length,FILE_FORMAT_SLICED, |
315 | 0,decode_frame,parser); |
316 | |
317 | stream_loop (st); |
318 | stream_delete (st); |
319 | return AM_SUCCESS; |
320 | |
321 | error: |
322 | return AM_FAILURE; |
323 | |
324 | } |
325 | |
326 | void init_vbi_decoder( AM_VBI_Parser_t* parser) |
327 | { |
328 | memset(parser, 0, sizeof(AM_VBI_Parser_t)); |
329 | parser->dec = vbi_decoder_new (); |
330 | assert (NULL != parser->dec); |
331 | pthread_mutex_init(&parser->lock, NULL); |
332 | pthread_cond_init(&parser->cond, NULL); |
333 | } |
334 | |
335 | |
336 | |
337 | |
338 | vbi_bool AM_VBI_CC_Create(AM_VBI_Handle_t *handle, AM_VBI_CC_Para_t *para) |
339 | { |
340 | AM_VBI_Parser_t* parser = NULL; |
341 | if(*handle == NULL) |
342 | { |
343 | |
344 | parser = (AM_VBI_Parser_t*)malloc(sizeof(AM_VBI_Parser_t)); |
345 | if(!parser) |
346 | { |
347 | return AM_VBI_DMX_ERR_NOT_ALLOCATED; |
348 | } |
349 | init_vbi_decoder(parser); |
350 | }else |
351 | parser = (AM_VBI_Parser_t*)handle; |
352 | |
353 | vbi_bool success; |
354 | success = vbi_event_handler_add (parser->dec, VBI_EVENT_CAPTION, |
355 | vbi_cc_handler, parser); |
356 | |
357 | //****************************************************** |
358 | //success = vbi_event_handler_add (parser->dec, VBI_EVENT_ASPECT | VBI_EVENT_PROG_INFO, |
359 | // vbi_xds_handler, parser); |
360 | //************************************************ |
361 | assert (success); |
362 | parser->cc_para = *para; |
363 | *handle = parser; |
364 | return AM_SUCCESS; |
365 | } |
366 | |
367 | |
368 | AM_ErrorCode_t AM_VBI_CC_Start(AM_VBI_Handle_t handle) |
369 | { |
370 | AM_DEBUG("NTSC-------------------- ******************AM_NTSC_CC_Start \n"); |
371 | AM_VBI_Parser_t *parser = (AM_VBI_Parser_t*)handle; |
372 | vbi_bool ret = AM_SUCCESS; |
373 | |
374 | //*******************************************************temp |
375 | parser->cc_status = AM_TRUE; |
376 | //*******************************************************temp |
377 | if(!parser) |
378 | { |
379 | AM_DEBUG("NTSC-------------------- ******************AM_CC_ERR_INVALID_HANDLE \n"); |
380 | return AM_CC_ERR_INVALID_HANDLE; |
381 | } |
382 | |
383 | pthread_mutex_lock(&parser->lock); |
384 | |
385 | if(!parser->running) |
386 | { |
387 | parser->running = AM_TRUE; |
388 | if(pthread_create(&parser->thread, NULL, vbi_cc_thread, parser)) |
389 | { |
390 | parser->running = AM_FALSE; |
391 | ret = AM_CC_ERR_CANNOT_CREATE_THREAD; |
392 | } |
393 | } |
394 | pthread_mutex_unlock(&parser->lock); |
395 | |
396 | return AM_SUCCESS; |
397 | } |
398 | |
399 | |
400 | |
401 | |
402 | |
403 | /********************************************************/ |
404 | AM_ErrorCode_t AM_VBI_CC_Stop(AM_VBI_Handle_t handle) |
405 | { |
406 | AM_DEBUG("NTSC-------------------- ******************AM_VBI_CC_Stop \n"); |
407 | AM_VBI_Parser_t *parser = (AM_VBI_Parser_t*)handle; |
408 | vbi_bool ret = AM_SUCCESS; |
409 | |
410 | pthread_t th; |
411 | vbi_bool wait = AM_FALSE; |
412 | |
413 | if(!parser) |
414 | { |
415 | AM_DEBUG("NTSC-------------------- ******************AM_CC_ERR_INVALID_HANDLE \n"); |
416 | return AM_CC_ERR_INVALID_HANDLE; |
417 | } |
418 | |
419 | pthread_mutex_lock(&parser->lock); |
420 | |
421 | if(parser->running) |
422 | { |
423 | parser->running = AM_FALSE; |
424 | wait = AM_TRUE; |
425 | th = parser->thread; |
426 | } |
427 | |
428 | pthread_mutex_unlock(&parser->lock); |
429 | pthread_cond_signal(&parser->cond); |
430 | |
431 | if(wait) |
432 | { |
433 | pthread_join(th, NULL); |
434 | } |
435 | |
436 | return AM_SUCCESS; |
437 | } |
438 | |
439 | |
440 | void* AM_VBI_CC_GetUserData(AM_VBI_Handle_t handle) |
441 | { |
442 | AM_VBI_Parser_t *parser = (AM_VBI_Parser_t*)handle; |
443 | if(!parser) |
444 | { |
445 | return NULL; |
446 | } |
447 | return parser->cc_para.user_data; |
448 | } |
449 | |
450 | vbi_bool AM_VBI_XDS_Create(AM_VBI_Handle_t *handle,AM_VBI_XDS_Para_t *para) |
451 | { |
452 | vbi_bool ret = AM_SUCCESS; |
453 | AM_VBI_Parser_t* parser; |
454 | if(*handle == NULL) |
455 | { |
456 | AM_DEBUG("NTSC-------------------- ******************AM_XDS_Create handle is null \n"); |
457 | parser = (AM_VBI_Parser_t*)malloc(sizeof(AM_VBI_Parser_t)); |
458 | if(!parser) |
459 | { |
460 | return AM_VBI_DMX_ERR_NOT_ALLOCATED; |
461 | } |
462 | init_vbi_decoder(parser); |
463 | *handle = parser; |
464 | }else |
465 | parser = (AM_VBI_Parser_t*)*handle; |
466 | parser->xds_para = *para; |
467 | AM_DEBUG("NTSC--------------- ******************vbi_event_handler_add xds_handle \n"); |
468 | ret = vbi_event_handler_add (parser->dec, VBI_EVENT_ASPECT | VBI_EVENT_PROG_INFO, |
469 | vbi_xds_handler, parser); |
470 | |
471 | assert (ret); |
472 | return AM_SUCCESS; |
473 | |
474 | } |
475 | |
476 | |
477 | vbi_bool AM_VBI_CC_set_type(AM_VBI_Handle_t handle,VBI_CC_TYPE cc_type) |
478 | { |
479 | AM_DEBUG("NTSC-------------------- ******************AM_VBI_CC_set_type ===%d\n",cc_type); |
480 | AM_VBI_Parser_t *parser = (AM_VBI_Parser_t*)handle; |
481 | |
482 | if(cc_type < 1 || cc_type >8) |
483 | return AM_FAILURE; |
484 | else |
485 | parser->page_no = cc_type; |
486 | return AM_SUCCESS; |
487 | } |
488 | |
489 | vbi_bool AM_VBI_CC_set_status(AM_VBI_Handle_t handle,vbi_bool flag) |
490 | { |
491 | AM_DEBUG("NTSC-------------------- ******************AM_VBI_CC_set_status ===%d\n"); |
492 | AM_VBI_Parser_t *parser = (AM_VBI_Parser_t*)handle; |
493 | if(flag == AM_TRUE) |
494 | parser->cc_status = AM_TRUE; |
495 | else |
496 | if(flag == AM_FAILURE) |
497 | parser->cc_status = AM_FAILURE; |
498 | return AM_SUCCESS; |
499 | |
500 | } |
501 | |
502 |