atsc_epg.c 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251
  1. /*
  2. * atsc_epg utility
  3. *
  4. * Copyright (C) 2009 Yufei Yuan <yfyuan@gmail.com>
  5. * This program is free software; you can redistribute it and/or modify
  6. * it under the terms of the GNU General Public License as published by
  7. * the Free Software Foundation; either version 2 of the License, or
  8. * (at your option) any later version.
  9. *
  10. * This program is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. *
  14. * GNU General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU General Public License
  17. * along with this program; if not, write to the Free Software
  18. * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  19. */
  20. #include <stdio.h>
  21. #include <stdlib.h>
  22. #include <unistd.h>
  23. #include <string.h>
  24. #include <time.h>
  25. #include <signal.h>
  26. #include <sys/types.h>
  27. #include <sys/stat.h>
  28. #include <fcntl.h>
  29. #include <sys/ioctl.h>
  30. #include <sys/poll.h>
  31. #include <errno.h>
  32. #include <getopt.h>
  33. #include <stdarg.h>
  34. #include <libdvbapi/dvbfe.h>
  35. #include <libdvbapi/dvbdemux.h>
  36. #include <libucsi/dvb/section.h>
  37. #include <libucsi/atsc/section.h>
  38. #include <libucsi/atsc/types.h>
  39. #define TIMEOUT 60
  40. #define RRT_TIMEOUT 60
  41. #define MAX_NUM_EVENT_TABLES 128
  42. #define TITLE_BUFFER_LEN 4096
  43. #define MESSAGE_BUFFER_LEN (16 * 1024)
  44. #define MAX_NUM_CHANNELS 16
  45. #define MAX_NUM_EVENTS_PER_CHANNEL (4 * 24 * 7)
  46. static int atsc_scan_table(int dmxfd, uint16_t pid, enum atsc_section_tag tag,
  47. void **table_section);
  48. static const char *program;
  49. static int adapter = 0;
  50. static int period = 12; /* hours */
  51. static int frequency;
  52. static int enable_ett = 0;
  53. static int ctrl_c = 0;
  54. static const char *modulation = NULL;
  55. static char separator[80];
  56. void (*old_handler)(int);
  57. struct atsc_string_buffer {
  58. int buf_len;
  59. int buf_pos;
  60. char *string;
  61. };
  62. struct atsc_event_info {
  63. uint16_t id;
  64. struct tm start;
  65. struct tm end;
  66. int title_pos;
  67. int title_len;
  68. int msg_pos;
  69. int msg_len;
  70. };
  71. struct atsc_eit_section_info {
  72. uint8_t section_num;
  73. uint8_t num_events;
  74. uint8_t num_etms;
  75. uint8_t num_received_etms;
  76. struct atsc_event_info **events;
  77. };
  78. struct atsc_eit_info {
  79. int num_eit_sections;
  80. struct atsc_eit_section_info *section;
  81. };
  82. struct atsc_channel_info {
  83. uint8_t num_eits;
  84. uint8_t service_type;
  85. char short_name[8];
  86. uint16_t major_num;
  87. uint16_t minor_num;
  88. uint16_t tsid;
  89. uint16_t prog_num;
  90. uint16_t src_id;
  91. struct atsc_eit_info *eit;
  92. struct atsc_event_info *last_event;
  93. int event_info_index;
  94. struct atsc_event_info e[MAX_NUM_EVENTS_PER_CHANNEL];
  95. struct atsc_string_buffer title_buf;
  96. struct atsc_string_buffer msg_buf;
  97. };
  98. struct atsc_virtual_channels_info {
  99. int num_channels;
  100. uint16_t eit_pid[MAX_NUM_EVENT_TABLES];
  101. uint16_t ett_pid[MAX_NUM_EVENT_TABLES];
  102. struct atsc_channel_info ch[MAX_NUM_CHANNELS];
  103. } guide;
  104. struct mgt_table_name {
  105. uint16_t range;
  106. const char *string;
  107. };
  108. struct mgt_table_name mgt_tab_name_array[] = {
  109. {0x0000, "terrestrial VCT with current_next_indictor=1"},
  110. {0x0001, "terrestrial VCT with current_next_indictor=0"},
  111. {0x0002, "cable VCT with current_next_indictor=1"},
  112. {0x0003, "cable VCT with current_next_indictor=0"},
  113. {0x0004, "channel ETT"},
  114. {0x0005, "DCCSCT"},
  115. {0x00FF, "reserved for future ATSC use"},
  116. {0x017F, "EIT"},
  117. {0x01FF, "reserved for future ATSC use"},
  118. {0x027F, "event ETT"},
  119. {0x02FF, "reserved for future ATSC use"}, /* FIXME */
  120. {0x03FF, "RRT with rating region"},
  121. {0x0FFF, "user private"},
  122. {0x13FF, "reserved for future ATSC use"},
  123. {0x14FF, "DCCT with dcc_id"},
  124. {0xFFFF, "reserved for future ATSC use"}
  125. };
  126. const char *channel_modulation_mode[] = {
  127. "",
  128. "analog",
  129. "SCTE mode 1",
  130. "SCTE mode 2",
  131. "ATSC 8VSB",
  132. "ATSC 16VSB"
  133. };
  134. const char *channel_service_type[] = {
  135. "",
  136. "analog TV",
  137. "ATSC digital TV",
  138. "ATSC audio",
  139. "ATSC data-only"
  140. };
  141. void *(*table_callback[16])(struct atsc_section_psip *) =
  142. {
  143. NULL, NULL, NULL, NULL, NULL, NULL, NULL,
  144. (void *(*)(struct atsc_section_psip *))atsc_mgt_section_codec,
  145. (void *(*)(struct atsc_section_psip *))atsc_tvct_section_codec,
  146. (void *(*)(struct atsc_section_psip *))atsc_cvct_section_codec,
  147. (void *(*)(struct atsc_section_psip *))atsc_rrt_section_codec,
  148. (void *(*)(struct atsc_section_psip *))atsc_eit_section_codec,
  149. (void *(*)(struct atsc_section_psip *))atsc_ett_section_codec,
  150. (void *(*)(struct atsc_section_psip *))atsc_stt_section_codec,
  151. NULL, NULL
  152. };
  153. static void int_handler(int sig_num)
  154. {
  155. if(SIGINT != sig_num) {
  156. return;
  157. }
  158. ctrl_c = 1;
  159. }
  160. /* shamelessly stolen from dvbsnoop, but almost not modified */
  161. static uint32_t get_bits(const uint8_t *buf, int startbit, int bitlen)
  162. {
  163. const uint8_t *b;
  164. uint32_t mask,tmp_long;
  165. int bitHigh,i;
  166. b = &buf[startbit / 8];
  167. startbit %= 8;
  168. bitHigh = 8;
  169. tmp_long = b[0];
  170. for (i = 0; i < ((bitlen-1) >> 3); i++) {
  171. tmp_long <<= 8;
  172. tmp_long |= b[i+1];
  173. bitHigh += 8;
  174. }
  175. startbit = bitHigh - startbit - bitlen;
  176. tmp_long = tmp_long >> startbit;
  177. mask = (1ULL << bitlen) - 1;
  178. return tmp_long & mask;
  179. }
  180. static void usage(void)
  181. {
  182. fprintf(stderr, "usage: %s [-a <n>] -f <frequency> [-p <period>]"
  183. " [-m <modulation>] [-t] [-h]\n", program);
  184. }
  185. static void help(void)
  186. {
  187. fprintf(stderr,
  188. "\nhelp:\n"
  189. "%s [-a <n>] -f <frequency> [-p <period>] [-m <modulation>] [-t] [-h]\n"
  190. " -a: adapter index to use, (default 0)\n"
  191. " -f: tuning frequency\n"
  192. " -p: period in hours, (default 12)\n"
  193. " -m: modulation ATSC vsb_8|vsb_16 (default vsb_8)\n"
  194. " -t: enable ETT to receive program details, if available\n"
  195. " -h: display this message\n", program);
  196. }
  197. static int close_frontend(struct dvbfe_handle *fe)
  198. {
  199. if(NULL == fe) {
  200. fprintf(stderr, "%s(): NULL pointer detected\n", __FUNCTION__);
  201. }
  202. dvbfe_close(fe);
  203. return 0;
  204. }
  205. static int open_frontend(struct dvbfe_handle **fe)
  206. {
  207. struct dvbfe_info fe_info;
  208. if(NULL == (*fe = dvbfe_open(adapter, 0, 0))) {
  209. fprintf(stderr, "%s(): error calling dvbfe_open()\n",
  210. __FUNCTION__);
  211. return -1;
  212. }
  213. dvbfe_get_info(*fe, 0, &fe_info, DVBFE_INFO_QUERYTYPE_IMMEDIATE, 0);
  214. if(DVBFE_TYPE_ATSC != fe_info.type) {
  215. fprintf(stderr, "%s(): only ATSC frontend supported currently\n",
  216. __FUNCTION__);
  217. return -1;
  218. }
  219. fe_info.feparams.frequency = frequency;
  220. fe_info.feparams.inversion = DVBFE_INVERSION_AUTO;
  221. fe_info.feparams.u.atsc.modulation = DVBFE_ATSC_MOD_VSB_8;
  222. fprintf(stdout, "tuning to %d Hz, please wait...\n", frequency);
  223. if(dvbfe_set(*fe, &fe_info.feparams, TIMEOUT * 1000)) {
  224. fprintf(stderr, "%s(): cannot lock to %d Hz in %d seconds\n",
  225. __FUNCTION__, frequency, TIMEOUT);
  226. return -1;
  227. }
  228. fprintf(stdout, "tuner locked.\n");
  229. return 0;
  230. }
  231. #if ENABLE_RRT
  232. /* this is untested as since this part of the library is broken */
  233. static int parse_rrt(int dmxfd)
  234. {
  235. const enum atsc_section_tag tag = stag_atsc_rating_region;
  236. struct atsc_rrt_section *rrt;
  237. struct atsc_text *region_name;
  238. struct atsc_text_string *atsc_str;
  239. int i, j, ret;
  240. i = 0;
  241. fprintf(stdout, "waiting for RRT: ");
  242. fflush(stdout);
  243. while(i < RRT_TIMEOUT) {
  244. ret = atsc_scan_table(dmxfd, ATSC_BASE_PID, tag, (void **)&rrt);
  245. if(0 > ret) {
  246. fprintf(stderr, "%s(): error calling atsc_scan_table()\n",
  247. __FUNCTION__);
  248. return -1;
  249. }
  250. if(0 == ret) {
  251. if(RRT_TIMEOUT > i) {
  252. fprintf(stdout, ".");
  253. fflush(stdout);
  254. } else {
  255. fprintf(stdout, "\nno RRT in %d seconds\n",
  256. RRT_TIMEOUT);
  257. return 0;
  258. }
  259. i += TIMEOUT;
  260. } else {
  261. fprintf(stdout, "\n");
  262. fflush(stdout);
  263. break;
  264. }
  265. }
  266. region_name = atsc_rrt_section_rating_region_name_text(rrt);
  267. atsc_text_strings_for_each(region_name, atsc_str, i) {
  268. struct atsc_text_string_segment *seg;
  269. atsc_text_string_segments_for_each(atsc_str, seg, j) {
  270. const char *c;
  271. int k;
  272. if(seg->mode < 0x3E) {
  273. fprintf(stderr, "%s(): text mode of 0x%02X "
  274. "not supported yet\n",
  275. __FUNCTION__, seg->mode);
  276. return -1;
  277. }
  278. c = (const char *)atsc_text_string_segment_bytes(seg);
  279. for(k = 0; k < seg->number_bytes; k++) {
  280. fprintf(stdout, "%c", c[k]);
  281. }
  282. }
  283. }
  284. return 0;
  285. }
  286. #endif
  287. static int parse_stt(int dmxfd)
  288. {
  289. const enum atsc_section_tag tag = stag_atsc_system_time;
  290. const struct atsc_stt_section *stt;
  291. time_t rx_time;
  292. time_t sys_time;
  293. int ret;
  294. ret = atsc_scan_table(dmxfd, ATSC_BASE_PID, tag, (void **)&stt);
  295. if(0 > ret) {
  296. fprintf(stderr, "%s(): error calling atsc_scan_table()\n",
  297. __FUNCTION__);
  298. return -1;
  299. }
  300. if(0 == ret) {
  301. fprintf(stdout, "no STT in %d seconds\n", TIMEOUT);
  302. return 0;
  303. }
  304. rx_time = atsctime_to_unixtime(stt->system_time);
  305. time(&sys_time);
  306. fprintf(stdout, "system time: %s", ctime(&sys_time));
  307. fprintf(stdout, "TS STT time: %s", ctime(&rx_time));
  308. return 0;
  309. }
  310. static int parse_tvct(int dmxfd)
  311. {
  312. int num_sections;
  313. uint32_t section_pattern;
  314. const enum atsc_section_tag tag = stag_atsc_terrestrial_virtual_channel;
  315. struct atsc_tvct_section *tvct;
  316. struct atsc_tvct_channel *ch;
  317. struct atsc_channel_info *curr_info;
  318. int i, k, ret;
  319. section_pattern = 0;
  320. num_sections = -1;
  321. do {
  322. ret = atsc_scan_table(dmxfd, ATSC_BASE_PID, tag, (void **)&tvct);
  323. if(0 > ret) {
  324. fprintf(stderr, "%s(): error calling atsc_scan_table()\n",
  325. __FUNCTION__);
  326. return -1;
  327. }
  328. if(0 == ret) {
  329. fprintf(stdout, "no TVCT in %d seconds\n", TIMEOUT);
  330. return 0;
  331. }
  332. if(-1 == num_sections) {
  333. num_sections = 1 + tvct->head.ext_head.last_section_number;
  334. if(32 < num_sections) {
  335. fprintf(stderr, "%s(): no support yet for "
  336. "tables having more than 32 sections\n",
  337. __FUNCTION__);
  338. return -1;
  339. }
  340. } else {
  341. if(num_sections !=
  342. 1 + tvct->head.ext_head.last_section_number) {
  343. fprintf(stderr,
  344. "%s(): last section number does not match\n",
  345. __FUNCTION__);
  346. return -1;
  347. }
  348. }
  349. if(section_pattern & (1 << tvct->head.ext_head.section_number)) {
  350. continue;
  351. }
  352. section_pattern |= 1 << tvct->head.ext_head.section_number;
  353. if(MAX_NUM_CHANNELS < guide.num_channels +
  354. tvct->num_channels_in_section) {
  355. fprintf(stderr, "%s(): no support for more than %d "
  356. "virtual channels in a pyhsical channel\n",
  357. __FUNCTION__, MAX_NUM_CHANNELS);
  358. return -1;
  359. }
  360. curr_info = &guide.ch[guide.num_channels];
  361. guide.num_channels += tvct->num_channels_in_section;
  362. atsc_tvct_section_channels_for_each(tvct, ch, i) {
  363. /* initialize the curr_info structure */
  364. /* each EIT covers 3 hours */
  365. curr_info->num_eits = (period / 3) + !!(period % 3);
  366. while (curr_info->num_eits &&
  367. (0xFFFF == guide.eit_pid[curr_info->num_eits - 1])) {
  368. curr_info->num_eits -= 1;
  369. }
  370. if(curr_info->eit) {
  371. fprintf(stderr, "%s(): non-NULL pointer detected "
  372. "during initialization", __FUNCTION__);
  373. return -1;
  374. }
  375. if(NULL == (curr_info->eit = calloc(curr_info->num_eits,
  376. sizeof(struct atsc_eit_info)))) {
  377. fprintf(stderr, "%s(): error calling calloc()\n",
  378. __FUNCTION__);
  379. return -1;
  380. }
  381. if(NULL == (curr_info->title_buf.string = calloc(TITLE_BUFFER_LEN,
  382. sizeof(char)))) {
  383. fprintf(stderr, "%s(): error calling calloc()\n",
  384. __FUNCTION__);
  385. return -1;
  386. }
  387. curr_info->title_buf.buf_len = TITLE_BUFFER_LEN;
  388. curr_info->title_buf.buf_pos = 0;
  389. if(NULL == (curr_info->msg_buf.string = calloc(MESSAGE_BUFFER_LEN,
  390. sizeof(char)))) {
  391. fprintf(stderr, "%s(): error calling calloc()\n",
  392. __FUNCTION__);
  393. return -1;
  394. }
  395. curr_info->msg_buf.buf_len = MESSAGE_BUFFER_LEN;
  396. curr_info->msg_buf.buf_pos = 0;
  397. for(k = 0; k < 7; k++) {
  398. curr_info->short_name[k] =
  399. get_bits((const uint8_t *)ch->short_name,
  400. k * 16, 16);
  401. }
  402. curr_info->service_type = ch->service_type;
  403. curr_info->major_num = ch->major_channel_number;
  404. curr_info->minor_num = ch->minor_channel_number;
  405. curr_info->tsid = ch->channel_TSID;
  406. curr_info->prog_num = ch->program_number;
  407. curr_info->src_id = ch->source_id;
  408. curr_info++;
  409. }
  410. } while(section_pattern != (uint32_t)((1 << num_sections) - 1));
  411. return 0;
  412. }
  413. static int match_event(struct atsc_eit_info *eit, uint16_t event_id,
  414. struct atsc_event_info **event, uint8_t *curr_index)
  415. {
  416. int j, k;
  417. struct atsc_eit_section_info *section;
  418. if(NULL == eit || NULL == event || NULL == curr_index) {
  419. fprintf(stderr, "%s(): NULL pointer detected\n", __FUNCTION__);
  420. return -1;
  421. }
  422. for(j = 0; j < eit->num_eit_sections; j++) {
  423. section = &eit->section[j];
  424. for(k = 0; k < section->num_events; k++) {
  425. if(section->events[k] && section->events[k]->id ==
  426. event_id) {
  427. *event = section->events[k];
  428. break;
  429. }
  430. }
  431. if(*event) {
  432. *curr_index = j;
  433. break;
  434. }
  435. }
  436. return 0;
  437. }
  438. static int parse_message(struct atsc_channel_info *channel,
  439. struct atsc_ett_section *ett, struct atsc_event_info *event)
  440. {
  441. int i, j;
  442. struct atsc_text *text;
  443. struct atsc_text_string *str;
  444. if(NULL == ett || NULL == event || NULL == channel) {
  445. fprintf(stderr, "%s(): NULL pointer detected\n", __FUNCTION__);
  446. return -1;
  447. }
  448. text = atsc_ett_section_extended_text_message(ett);
  449. atsc_text_strings_for_each(text, str, i) {
  450. struct atsc_text_string_segment *seg;
  451. atsc_text_string_segments_for_each(str, seg, j) {
  452. event->msg_pos = channel->msg_buf.buf_pos;
  453. if(0 > atsc_text_segment_decode(seg,
  454. (uint8_t **)&channel->msg_buf.string,
  455. (size_t *)&channel->msg_buf.buf_len,
  456. (size_t *)&channel->msg_buf.buf_pos)) {
  457. fprintf(stderr, "%s(): error calling "
  458. "atsc_text_segment_decode()\n",
  459. __FUNCTION__);
  460. return -1;
  461. }
  462. event->msg_len = 1 + channel->msg_buf.buf_pos -
  463. event->msg_pos;
  464. }
  465. }
  466. return 0;
  467. }
  468. static int parse_ett(int dmxfd, int index, uint16_t pid)
  469. {
  470. uint8_t curr_index;
  471. uint32_t section_pattern;
  472. const enum atsc_section_tag tag = stag_atsc_extended_text;
  473. struct atsc_eit_info *eit;
  474. struct atsc_ett_section *ett;
  475. struct atsc_channel_info *channel;
  476. struct atsc_event_info *event;
  477. struct atsc_eit_section_info *section;
  478. uint16_t source_id, event_id;
  479. int c, ret;
  480. if(0xFFFF == guide.ett_pid[index]) {
  481. return 0;
  482. }
  483. for(c = 0; c < guide.num_channels; c++) {
  484. channel = &guide.ch[c];
  485. eit = &channel->eit[index];
  486. section_pattern = 0;
  487. while(section_pattern !=
  488. (uint32_t)((1 << eit->num_eit_sections) - 1)) {
  489. if(ctrl_c) {
  490. return 0;
  491. }
  492. ret = atsc_scan_table(dmxfd, pid, tag, (void **)&ett);
  493. fprintf(stdout, ".");
  494. fflush(stdout);
  495. if(0 > ret) {
  496. fprintf(stderr, "%s(): error calling "
  497. "atsc_scan_table()\n", __FUNCTION__);
  498. return -1;
  499. }
  500. if(0 == ret) {
  501. fprintf(stdout, "no ETT %d in %d seconds\n",
  502. index, TIMEOUT);
  503. return 0;
  504. }
  505. source_id = ett->ETM_source_id;
  506. event_id = ett->ETM_sub_id;
  507. if(source_id != channel->src_id) {
  508. continue;
  509. }
  510. event = NULL;
  511. if(match_event(eit, event_id, &event, &curr_index)) {
  512. fprintf(stderr, "%s(): error calling "
  513. "match_event()\n", __FUNCTION__);
  514. return -1;
  515. }
  516. if(NULL == event) {
  517. continue;
  518. }
  519. if(section_pattern & (1 << curr_index)) {
  520. /* the section has been filled, so skip,
  521. * not consider version yet
  522. */
  523. continue;
  524. }
  525. if(event->msg_len) {
  526. /* the message has been filled */
  527. continue;
  528. }
  529. if(parse_message(channel, ett, event)) {
  530. fprintf(stderr, "%s(): error calling "
  531. "parse_message()\n", __FUNCTION__);
  532. return -1;
  533. }
  534. section = &eit->section[curr_index];
  535. if(++section->num_received_etms == section->num_etms) {
  536. section_pattern |= 1 << curr_index;
  537. }
  538. }
  539. }
  540. return 0;
  541. }
  542. static int parse_events(struct atsc_channel_info *curr_info,
  543. struct atsc_eit_section *eit, struct atsc_eit_section_info *section)
  544. {
  545. int i, j, k;
  546. struct atsc_eit_event *e;
  547. time_t start_time, end_time;
  548. if(NULL == curr_info || NULL == eit) {
  549. fprintf(stderr, "%s(): NULL pointer detected\n", __FUNCTION__);
  550. return -1;
  551. }
  552. atsc_eit_section_events_for_each(eit, e, i) {
  553. struct atsc_text *title;
  554. struct atsc_text_string *str;
  555. struct atsc_event_info *e_info =
  556. &curr_info->e[curr_info->event_info_index];
  557. if(0 == i && curr_info->last_event) {
  558. if(e->event_id == curr_info->last_event->id) {
  559. section->events[i] = NULL;
  560. /* skip if it's the same event spanning
  561. * over sections
  562. */
  563. continue;
  564. }
  565. }
  566. curr_info->event_info_index += 1;
  567. section->events[i] = e_info;
  568. e_info->id = e->event_id;
  569. start_time = atsctime_to_unixtime(e->start_time);
  570. end_time = start_time + e->length_in_seconds;
  571. localtime_r(&start_time, &e_info->start);
  572. localtime_r(&end_time, &e_info->end);
  573. if(0 != e->ETM_location && 3 != e->ETM_location) {
  574. /* FIXME assume 1 and 2 is interchangable as of now */
  575. section->num_etms++;
  576. }
  577. title = atsc_eit_event_name_title_text(e);
  578. if (title == NULL)
  579. continue;
  580. atsc_text_strings_for_each(title, str, j) {
  581. struct atsc_text_string_segment *seg;
  582. atsc_text_string_segments_for_each(str, seg, k) {
  583. e_info->title_pos = curr_info->title_buf.buf_pos;
  584. if(0 > atsc_text_segment_decode(seg,
  585. (uint8_t **)&curr_info->title_buf.string,
  586. (size_t *)&curr_info->title_buf.buf_len,
  587. (size_t *)&curr_info->title_buf.buf_pos)) {
  588. fprintf(stderr, "%s(): error calling "
  589. "atsc_text_segment_decode()\n",
  590. __FUNCTION__);
  591. return -1;
  592. }
  593. e_info->title_len = curr_info->title_buf.buf_pos -
  594. e_info->title_pos + 1;
  595. }
  596. }
  597. }
  598. return 0;
  599. }
  600. static int parse_eit(int dmxfd, int index, uint16_t pid)
  601. {
  602. int num_sections;
  603. uint8_t section_num;
  604. uint8_t curr_channel_index;
  605. uint32_t section_pattern;
  606. const enum atsc_section_tag tag = stag_atsc_event_information;
  607. struct atsc_eit_section *eit;
  608. struct atsc_channel_info *curr_info;
  609. struct atsc_eit_info *eit_info;
  610. struct atsc_eit_section_info *section;
  611. uint16_t source_id;
  612. uint32_t eit_instance_pattern = 0;
  613. int i, k, ret;
  614. while(eit_instance_pattern !=
  615. (uint32_t)((1 << guide.num_channels) - 1)) {
  616. source_id = 0xFFFF;
  617. section_pattern = 0;
  618. num_sections = -1;
  619. do {
  620. ret = atsc_scan_table(dmxfd, pid, tag, (void **)&eit);
  621. fprintf(stdout, ".");
  622. fflush(stdout);
  623. if(0 > ret) {
  624. fprintf(stderr, "%s(): error calling "
  625. "atsc_scan_table()\n", __FUNCTION__);
  626. return -1;
  627. }
  628. if(0 == ret) {
  629. fprintf(stdout, "no EIT %d in %d seconds\n",
  630. index, TIMEOUT);
  631. return 0;
  632. }
  633. if(0xFFFF == source_id) {
  634. source_id = atsc_eit_section_source_id(eit);
  635. for(k = 0; k < guide.num_channels; k++) {
  636. if(source_id == guide.ch[k].src_id) {
  637. curr_info = &guide.ch[k];
  638. curr_channel_index = k;
  639. if(0 == index) {
  640. curr_info->last_event = NULL;
  641. }
  642. break;
  643. }
  644. }
  645. if(k == guide.num_channels) {
  646. fprintf(stderr, "%s(): cannot find source_id "
  647. "0x%04X in the EIT\n",
  648. __FUNCTION__, source_id);
  649. return -1;
  650. }
  651. } else {
  652. if(source_id !=
  653. atsc_eit_section_source_id(eit)) {
  654. continue;
  655. }
  656. }
  657. if(eit_instance_pattern & (1 << curr_channel_index)) {
  658. /* we have received this instance,
  659. * so quit quick
  660. */
  661. break;
  662. }
  663. if(-1 == num_sections) {
  664. num_sections = 1 +
  665. eit->head.ext_head.last_section_number;
  666. if(32 < num_sections) {
  667. fprintf(stderr,
  668. "%s(): no support yet for "
  669. "tables having more than "
  670. "32 sections\n", __FUNCTION__);
  671. return -1;
  672. }
  673. } else {
  674. if(num_sections != 1 +
  675. eit->head.ext_head.last_section_number) {
  676. fprintf(stderr,
  677. "%s(): last section number "
  678. "does not match\n",
  679. __FUNCTION__);
  680. return -1;
  681. }
  682. }
  683. if(section_pattern &
  684. (1 << eit->head.ext_head.section_number)) {
  685. continue;
  686. }
  687. section_pattern |= 1 << eit->head.ext_head.section_number;
  688. eit_info = &curr_info->eit[index];
  689. if(NULL == (eit_info->section =
  690. realloc(eit_info->section,
  691. (eit_info->num_eit_sections + 1) *
  692. sizeof(struct atsc_eit_section_info)))) {
  693. fprintf(stderr,
  694. "%s(): error calling realloc()\n",
  695. __FUNCTION__);
  696. return -1;
  697. }
  698. section_num = eit->head.ext_head.section_number;
  699. if(0 == eit_info->num_eit_sections) {
  700. eit_info->num_eit_sections = 1;
  701. section = eit_info->section;
  702. } else {
  703. /* have to sort it into section order
  704. * (temporal order)
  705. */
  706. for(i = 0; i < eit_info->num_eit_sections; i++) {
  707. if(eit_info->section[i].section_num >
  708. section_num) {
  709. break;
  710. }
  711. }
  712. memmove(&eit_info->section[i + 1],
  713. &eit_info->section[i],
  714. (eit_info->num_eit_sections - i) *
  715. sizeof(struct atsc_eit_section_info));
  716. section = &eit_info->section[i - 1];
  717. section = &eit_info->section[i];
  718. eit_info->num_eit_sections += 1;
  719. }
  720. section->section_num = section_num;
  721. section->num_events = eit->num_events_in_section;
  722. section->num_etms = 0;
  723. section->num_received_etms = 0;
  724. if(NULL == (section->events = calloc(section->num_events,
  725. sizeof(struct atsc_event_info *)))) {
  726. fprintf(stderr, "%s(): error calling calloc()\n",
  727. __FUNCTION__);
  728. return -1;
  729. }
  730. if(parse_events(curr_info, eit, section)) {
  731. fprintf(stderr, "%s(): error calling "
  732. "parse_events()\n", __FUNCTION__);
  733. return -1;
  734. }
  735. } while(section_pattern != (uint32_t)((1 << num_sections) - 1));
  736. eit_instance_pattern |= 1 << curr_channel_index;
  737. }
  738. for(i = 0; i < guide.num_channels; i++) {
  739. struct atsc_channel_info *channel = &guide.ch[i];
  740. struct atsc_eit_info *ei = &channel->eit[index];
  741. struct atsc_eit_section_info *s;
  742. if(0 == ei->num_eit_sections) {
  743. channel->last_event = NULL;
  744. continue;
  745. }
  746. s = &ei->section[ei->num_eit_sections - 1];
  747. /* BUG: it's incorrect when last section has no event */
  748. if(0 == s->num_events) {
  749. channel->last_event = NULL;
  750. continue;
  751. }
  752. channel->last_event = s->events[s->num_events - 1];
  753. }
  754. return 0;
  755. }
  756. static int parse_mgt(int dmxfd)
  757. {
  758. const enum atsc_section_tag tag = stag_atsc_master_guide;
  759. struct atsc_mgt_section *mgt;
  760. struct atsc_mgt_table *t;
  761. int i, j, ret;
  762. ret = atsc_scan_table(dmxfd, ATSC_BASE_PID, tag, (void **)&mgt);
  763. if(0 > ret) {
  764. fprintf(stderr, "%s(): error calling atsc_scan_table()\n",
  765. __FUNCTION__);
  766. return -1;
  767. }
  768. if(0 == ret) {
  769. fprintf(stdout, "no MGT in %d seconds\n", TIMEOUT);
  770. return 0;
  771. }
  772. fprintf(stdout, "MGT table:\n");
  773. atsc_mgt_section_tables_for_each(mgt, t, i) {
  774. struct mgt_table_name table;
  775. for(j = 0; j < (int)(sizeof(mgt_tab_name_array) /
  776. sizeof(struct mgt_table_name)); j++) {
  777. if(t->table_type > mgt_tab_name_array[j].range) {
  778. continue;
  779. }
  780. table = mgt_tab_name_array[j];
  781. if(0 == j || mgt_tab_name_array[j - 1].range + 1 ==
  782. mgt_tab_name_array[j].range) {
  783. j = -1;
  784. } else {
  785. j = t->table_type - mgt_tab_name_array[j - 1].range - 1;
  786. if(0x017F == table.range) {
  787. guide.eit_pid[j] = t->table_type_PID;
  788. } else if (0x027F == table.range) {
  789. guide.ett_pid[j] = t->table_type_PID;
  790. }
  791. }
  792. break;
  793. }
  794. fprintf(stdout, " %2d: type = 0x%04X, PID = 0x%04X, %s", i,
  795. t->table_type, t->table_type_PID, table.string);
  796. if(-1 != j) {
  797. fprintf(stdout, " %d", j);
  798. }
  799. fprintf(stdout, "\n");
  800. }
  801. return 0;
  802. }
  803. static int cleanup_guide(void)
  804. {
  805. int i, j, k;
  806. for(i = 0; i < guide.num_channels; i++) {
  807. struct atsc_channel_info *channel = &guide.ch[i];
  808. if(channel->title_buf.string) {
  809. free(channel->title_buf.string);
  810. }
  811. if(channel->msg_buf.string) {
  812. free(channel->msg_buf.string);
  813. }
  814. for(j = 0; j < channel->num_eits; j++) {
  815. struct atsc_eit_info *eit = &channel->eit[j];
  816. for(k = 0; k < eit->num_eit_sections; k++) {
  817. struct atsc_eit_section_info *section =
  818. &eit->section[k];
  819. if(section->num_events) {
  820. free(section->events);
  821. }
  822. }
  823. if(k) {
  824. free(eit->section);
  825. }
  826. }
  827. if(j) {
  828. free(channel->eit);
  829. }
  830. }
  831. return 0;
  832. }
  833. static int print_events(struct atsc_channel_info *channel,
  834. struct atsc_eit_section_info *section)
  835. {
  836. int m;
  837. char line[256];
  838. if(NULL == section) {
  839. fprintf(stderr, "%s(): NULL pointer detected", __FUNCTION__);
  840. return -1;
  841. }
  842. for(m = 0; m < section->num_events; m++) {
  843. struct atsc_event_info *event =
  844. section->events[m];
  845. if(NULL == event) {
  846. continue;
  847. }
  848. fprintf(stdout, "|%02d:%02d--%02d:%02d| ",
  849. event->start.tm_hour, event->start.tm_min,
  850. event->end.tm_hour, event->end.tm_min);
  851. snprintf(line, event->title_len, "%s",
  852. &channel->title_buf.string[event->title_pos]);
  853. line[event->title_len] = '\0';
  854. fprintf(stdout, "%s\n", line);
  855. if(event->msg_len) {
  856. int len = event->msg_len;
  857. int pos = event->msg_pos;
  858. size_t part;
  859. do {
  860. part = len > 255 ? 255 : len;
  861. snprintf(line, part, "%s",
  862. &channel->msg_buf.string[pos]);
  863. line[part] = '\0';
  864. fprintf(stdout, "%s", line);
  865. len -= part;
  866. pos += part;
  867. } while(0 < len);
  868. fprintf(stdout, "\n");
  869. }
  870. }
  871. return 0;
  872. }
  873. static int print_guide(void)
  874. {
  875. int i, j, k;
  876. fprintf(stdout, "%s\n", separator);
  877. for(i = 0; i < guide.num_channels; i++) {
  878. struct atsc_channel_info *channel = &guide.ch[i];
  879. fprintf(stdout, "%d.%d %s\n", channel->major_num,
  880. channel->minor_num, channel->short_name);
  881. for(j = 0; j < channel->num_eits; j++) {
  882. struct atsc_eit_info *eit = &channel->eit[j];
  883. for(k = 0; k < eit->num_eit_sections; k++) {
  884. struct atsc_eit_section_info *section =
  885. &eit->section[k];
  886. if(print_events(channel, section)) {
  887. fprintf(stderr, "%s(): error calling "
  888. "print_events()\n", __FUNCTION__);
  889. return -1;
  890. }
  891. }
  892. }
  893. fprintf(stdout, "%s\n", separator);
  894. }
  895. return 0;
  896. }
  897. static int open_demux(int *dmxfd)
  898. {
  899. if((*dmxfd = dvbdemux_open_demux(adapter, 0, 0)) < 0) {
  900. fprintf(stderr, "%s(): error calling dvbdemux_open_demux()\n",
  901. __FUNCTION__);
  902. return -1;
  903. }
  904. return 0;
  905. }
  906. static int close_demux(int dmxfd)
  907. {
  908. if(dvbdemux_stop(dmxfd)) {
  909. fprintf(stderr, "%s(): error calling dvbdemux_stop()\n",
  910. __FUNCTION__);
  911. return -1;
  912. }
  913. return 0;
  914. }
  915. /* used other utilities as template and generalized here */
  916. static int atsc_scan_table(int dmxfd, uint16_t pid, enum atsc_section_tag tag,
  917. void **table_section)
  918. {
  919. uint8_t filter[18];
  920. uint8_t mask[18];
  921. unsigned char sibuf[4096];
  922. int size;
  923. int ret;
  924. struct pollfd pollfd;
  925. struct section *section;
  926. struct section_ext *section_ext;
  927. struct atsc_section_psip *psip;
  928. /* create a section filter for the table */
  929. memset(filter, 0, sizeof(filter));
  930. memset(mask, 0, sizeof(mask));
  931. filter[0] = tag;
  932. mask[0] = 0xFF;
  933. if(dvbdemux_set_section_filter(dmxfd, pid, filter, mask, 1, 1)) {
  934. fprintf(stderr, "%s(): error calling atsc_scan_table()\n",
  935. __FUNCTION__);
  936. return -1;
  937. }
  938. /* poll for data */
  939. pollfd.fd = dmxfd;
  940. pollfd.events = POLLIN | POLLERR |POLLPRI;
  941. if((ret = poll(&pollfd, 1, TIMEOUT * 1000)) < 0) {
  942. if(ctrl_c) {
  943. return 0;
  944. }
  945. fprintf(stderr, "%s(): error calling poll()\n", __FUNCTION__);
  946. return -1;
  947. }
  948. if(0 == ret) {
  949. return 0;
  950. }
  951. /* read it */
  952. if((size = read(dmxfd, sibuf, sizeof(sibuf))) < 0) {
  953. fprintf(stderr, "%s(): error calling read()\n", __FUNCTION__);
  954. return -1;
  955. }
  956. /* parse section */
  957. section = section_codec(sibuf, size);
  958. if(NULL == section) {
  959. fprintf(stderr, "%s(): error calling section_codec()\n",
  960. __FUNCTION__);
  961. return -1;
  962. }
  963. section_ext = section_ext_decode(section, 0);
  964. if(NULL == section_ext) {
  965. fprintf(stderr, "%s(): error calling section_ext_decode()\n",
  966. __FUNCTION__);
  967. return -1;
  968. }
  969. psip = atsc_section_psip_decode(section_ext);
  970. if(NULL == psip) {
  971. fprintf(stderr,
  972. "%s(): error calling atsc_section_psip_decode()\n",
  973. __FUNCTION__);
  974. return -1;
  975. }
  976. *table_section = table_callback[tag & 0x0F](psip);
  977. if(NULL == *table_section) {
  978. fprintf(stderr, "%s(): error decode table section\n",
  979. __FUNCTION__);
  980. return -1;
  981. }
  982. return 1;
  983. }
  984. int main(int argc, char *argv[])
  985. {
  986. int i, dmxfd;
  987. struct dvbfe_handle *fe;
  988. program = argv[0];
  989. if(1 == argc) {
  990. usage();
  991. exit(-1);
  992. }
  993. for( ; ; ) {
  994. char c;
  995. if(-1 == (c = getopt(argc, argv, "a:f:p:m:th"))) {
  996. break;
  997. }
  998. switch(c) {
  999. case 'a':
  1000. adapter = strtoll(optarg, NULL, 0);
  1001. break;
  1002. case 'f':
  1003. frequency = strtol(optarg, NULL, 0);
  1004. break;
  1005. case 'p':
  1006. period = strtol(optarg, NULL, 0);
  1007. /* each table covers 3 hours */
  1008. if((3 * MAX_NUM_EVENT_TABLES) < period) {
  1009. period = 3 * MAX_NUM_EVENT_TABLES;
  1010. }
  1011. break;
  1012. case 'm':
  1013. /* just stub, so far ATSC only has VSB_8 */
  1014. modulation = optarg;
  1015. break;
  1016. case 't':
  1017. enable_ett = 1;
  1018. break;
  1019. case 'h':
  1020. help();
  1021. exit(0);
  1022. default:
  1023. usage();
  1024. exit(-1);
  1025. }
  1026. }
  1027. memset(separator, '-', sizeof(separator));
  1028. separator[79] = '\0';
  1029. memset(&guide, 0, sizeof(struct atsc_virtual_channels_info));
  1030. memset(guide.eit_pid, 0xFF, MAX_NUM_EVENT_TABLES * sizeof(uint16_t));
  1031. memset(guide.ett_pid, 0xFF, MAX_NUM_EVENT_TABLES * sizeof(uint16_t));
  1032. if(open_frontend(&fe)) {
  1033. fprintf(stderr, "%s(): error calling open_frontend()\n",
  1034. __FUNCTION__);
  1035. return -1;
  1036. }
  1037. if(open_demux(&dmxfd)) {
  1038. fprintf(stderr, "%s(): error calling open_demux()\n",
  1039. __FUNCTION__);
  1040. return -1;
  1041. }
  1042. if(parse_stt(dmxfd)) {
  1043. fprintf(stderr, "%s(): error calling parse_stt()\n",
  1044. __FUNCTION__);
  1045. return -1;
  1046. }
  1047. if(parse_mgt(dmxfd)) {
  1048. fprintf(stderr, "%s(): error calling parse_mgt()\n",
  1049. __FUNCTION__);
  1050. return -1;
  1051. }
  1052. if(parse_tvct(dmxfd)) {
  1053. fprintf(stderr, "%s(): error calling parse_tvct()\n",
  1054. __FUNCTION__);
  1055. return -1;
  1056. }
  1057. #ifdef ENABLE_RRT
  1058. if(parse_rrt(dmxfd)) {
  1059. fprintf(stderr, "%s(): error calling parse_rrt()\n",
  1060. __FUNCTION__);
  1061. return -1;
  1062. }
  1063. #endif
  1064. fprintf(stdout, "receiving EIT ");
  1065. for(i = 0; i < guide.ch[0].num_eits; i++) {
  1066. if(parse_eit(dmxfd, i, guide.eit_pid[i])) {
  1067. fprintf(stderr, "%s(): error calling parse_eit()\n",
  1068. __FUNCTION__);
  1069. return -1;
  1070. }
  1071. }
  1072. fprintf(stdout, "\n");
  1073. old_handler = signal(SIGINT, int_handler);
  1074. if(enable_ett) {
  1075. fprintf(stdout, "receiving ETT ");
  1076. for(i = 0; i < guide.ch[0].num_eits; i++) {
  1077. if(0xFFFF != guide.ett_pid[i]) {
  1078. if(parse_ett(dmxfd, i, guide.ett_pid[i])) {
  1079. fprintf(stderr, "%s(): error calling "
  1080. "parse_eit()\n", __FUNCTION__);
  1081. return -1;
  1082. }
  1083. }
  1084. if(ctrl_c) {
  1085. break;
  1086. }
  1087. }
  1088. fprintf(stdout, "\n");
  1089. }
  1090. signal(SIGINT, old_handler);
  1091. if(print_guide()) {
  1092. fprintf(stderr, "%s(): error calling print_guide()\n",
  1093. __FUNCTION__);
  1094. return -1;
  1095. }
  1096. if(cleanup_guide()) {
  1097. fprintf(stderr, "%s(): error calling cleanup_guide()\n",
  1098. __FUNCTION__);
  1099. return -1;
  1100. }
  1101. if(close_demux(dmxfd)) {
  1102. fprintf(stderr, "%s(): error calling close_demux()\n",
  1103. __FUNCTION__);
  1104. return -1;
  1105. }
  1106. if(close_frontend(fe)) {
  1107. fprintf(stderr, "%s(): error calling close_demux()\n",
  1108. __FUNCTION__);
  1109. return -1;
  1110. }
  1111. return 0;
  1112. }