Mercurial > pt1
comparison recpt1/recpt1.c @ 8:6da603afd363
added udp capability
author | Yoshiki Yazawa <yaz@honeyplanet.jp> |
---|---|
date | Mon, 23 Feb 2009 03:06:17 +0900 |
parents | 407af34cfbd9 |
children | 4615eaf04415 |
comparison
equal
deleted
inserted
replaced
7:407af34cfbd9 | 8:6da603afd363 |
---|---|
7 #include <string.h> | 7 #include <string.h> |
8 #include <pthread.h> | 8 #include <pthread.h> |
9 #include <unistd.h> | 9 #include <unistd.h> |
10 #include <getopt.h> | 10 #include <getopt.h> |
11 | 11 |
12 #include <netdb.h> | |
13 #include <arpa/inet.h> | |
14 #include <netinet/in.h> | |
15 | |
12 #include <sys/ioctl.h> | 16 #include <sys/ioctl.h> |
13 #include "pt1_ioctl.h" | 17 #include "pt1_ioctl.h" |
14 | 18 |
15 #include "recpt1.h" | 19 #include "recpt1.h" |
16 #include "decoder.h" | 20 #include "decoder.h" |
17 | 21 |
18 /* globals */ | 22 /* globals */ |
19 int f_exit = FALSE; | 23 int f_exit = FALSE; |
24 | |
25 typedef struct sock_data { | |
26 int sfd; /* socket fd */ | |
27 struct sockaddr_in addr; | |
28 } sock_data; | |
20 | 29 |
21 typedef struct thread_data { | 30 typedef struct thread_data { |
22 QUEUE_T *queue; | 31 QUEUE_T *queue; |
23 decoder *decoder; | 32 decoder *decoder; |
24 int fd; | 33 int wfd; /* output file fd */ |
34 sock_data *sock_data; | |
25 } thread_data; | 35 } thread_data; |
26 | 36 |
27 /* lookup frequency conversion table*/ | 37 /* lookup frequency conversion table*/ |
28 ISDB_T_FREQ_CONV_TABLE * | 38 ISDB_T_FREQ_CONV_TABLE * |
29 searchrecoff(char *channel) | 39 searchrecoff(char *channel) |
44 | 54 |
45 QUEUE_T * | 55 QUEUE_T * |
46 create_queue(size_t size) | 56 create_queue(size_t size) |
47 { | 57 { |
48 QUEUE_T *p_queue; | 58 QUEUE_T *p_queue; |
49 int memsize = sizeof(QUEUE_T) + size * sizeof(BUFSZ); | 59 int memsize = sizeof(QUEUE_T) + size * sizeof(BUFSZ); |
50 | 60 |
51 p_queue = (QUEUE_T*)calloc(memsize, sizeof(char)); | 61 p_queue = (QUEUE_T*)calloc(memsize, sizeof(char)); |
52 | 62 |
53 if(p_queue != NULL) { | 63 if(p_queue != NULL) { |
54 p_queue->size = size; | 64 p_queue->size = size; |
102 | 112 |
103 /* dequeue data. this function will block if queue is empty. */ | 113 /* dequeue data. this function will block if queue is empty. */ |
104 BUFSZ * | 114 BUFSZ * |
105 dequeue(QUEUE_T *p_queue) | 115 dequeue(QUEUE_T *p_queue) |
106 { | 116 { |
107 BUFSZ *buffer; | 117 BUFSZ *buffer; |
108 | 118 |
109 pthread_mutex_lock(&p_queue->mutex); | 119 pthread_mutex_lock(&p_queue->mutex); |
110 /* entered the critical section*/ | 120 /* entered the critical section*/ |
111 | 121 |
112 /* wait until queue is filled */ | 122 /* wait until queue is filled */ |
137 write_func(void *p) | 147 write_func(void *p) |
138 { | 148 { |
139 thread_data *data = (thread_data *)p; | 149 thread_data *data = (thread_data *)p; |
140 QUEUE_T *p_queue = data->queue; | 150 QUEUE_T *p_queue = data->queue; |
141 decoder *dec = data->decoder; | 151 decoder *dec = data->decoder; |
142 int wfd = data->fd; | 152 int wfd = data->wfd; |
143 int use_b25 = dec ? 1 : 0; | 153 int use_b25 = dec ? 1 : 0; |
144 BUFSZ *buf; | 154 int use_udp = data->sock_data ? 1 : 0; |
155 int sfd = 0; | |
156 struct sockaddr *addr = NULL; | |
157 BUFSZ *buf; | |
145 ARIB_STD_B25_BUFFER sbuf, dbuf; | 158 ARIB_STD_B25_BUFFER sbuf, dbuf; |
146 int code; | 159 int code; |
160 | |
161 if(use_udp) { | |
162 sfd = data->sock_data->sfd; | |
163 addr = (struct sockaddr *)&data->sock_data->addr; | |
164 } | |
147 | 165 |
148 while(1) { | 166 while(1) { |
149 buf = dequeue(p_queue); | 167 buf = dequeue(p_queue); |
150 /* no entry in the queue */ | 168 /* no entry in the queue */ |
151 if(buf == NULL){ | 169 if(buf == NULL){ |
163 fprintf(stderr, "b25_decode failed\n"); | 181 fprintf(stderr, "b25_decode failed\n"); |
164 close(wfd); | 182 close(wfd); |
165 break; | 183 break; |
166 } | 184 } |
167 write(wfd, dbuf.data, dbuf.size); | 185 write(wfd, dbuf.data, dbuf.size); |
186 | |
187 if(use_udp && sfd) { | |
188 sendto(sfd, dbuf.data, dbuf.size, 0, | |
189 addr, sizeof(struct sockaddr_in)); | |
190 } | |
168 free(buf); | 191 free(buf); |
169 } else { | 192 } else { |
170 write(wfd, sbuf.data, sbuf.size); | 193 write(wfd, sbuf.data, sbuf.size); |
194 | |
195 if(use_udp && sfd) { | |
196 sendto(sfd, sbuf.data, sbuf.size, 0, | |
197 addr, sizeof(struct sockaddr_in)); | |
198 } | |
171 free(buf); | 199 free(buf); |
172 } | 200 } |
173 | 201 |
174 /* normal exit */ | 202 /* normal exit */ |
175 if((f_exit) && (!p_queue->no_empty)) { | 203 if((f_exit) && (!p_queue->no_empty)) { |
176 if(use_b25) { | 204 if(use_b25) { |
177 code = b25_finish(dec, &sbuf, &dbuf); | 205 code = b25_finish(dec, &sbuf, &dbuf); |
178 if(code < 0) { | 206 if(code < 0) { |
179 fprintf(stderr, "b25_finish failed\n"); | 207 fprintf(stderr, "b25_finish failed\n"); |
180 close(wfd); | 208 close(wfd); |
209 close(sfd); | |
181 break; | 210 break; |
182 } | 211 } |
183 write(wfd, dbuf.data, dbuf.size); | 212 write(wfd, dbuf.data, dbuf.size); |
213 | |
214 if(use_udp && sfd) { | |
215 sendto(sfd, dbuf.data, dbuf.size, 0, | |
216 addr, sizeof(struct sockaddr_in)); | |
217 } | |
184 } | 218 } |
185 close(wfd); | 219 close(wfd); |
220 close(sfd); | |
186 break; | 221 break; |
187 } | 222 } |
188 } | 223 } |
189 | 224 |
190 return NULL; | 225 return NULL; |
226 } | |
227 | |
228 void | |
229 show_usage(char *cmd) | |
230 { | |
231 fprintf(stderr, "Usage: %s [--b25 [--round N] [--strip] [--EMM]] [--udp hostname [--port port]] channel recsec destfile\n", cmd); | |
191 } | 232 } |
192 | 233 |
193 int | 234 int |
194 main(int argc, char **argv) | 235 main(int argc, char **argv) |
195 { | 236 { |
196 int fd, wfd; | 237 int tfd, wfd; |
197 int lp; | 238 int lp; |
198 int recsec; | 239 int recsec; |
199 time_t start_time, cur_time; | 240 time_t start_time, cur_time; |
200 FREQUENCY freq; | 241 FREQUENCY freq; |
201 ISDB_T_FREQ_CONV_TABLE *ptr; | 242 ISDB_T_FREQ_CONV_TABLE *ptr; |
202 pthread_t dequeue_threads; | 243 pthread_t dequeue_threads; |
203 QUEUE_T *p_queue = create_queue(MAX_QUEUE); | 244 QUEUE_T *p_queue = create_queue(MAX_QUEUE); |
204 BUFSZ *bufptr; | 245 BUFSZ *bufptr; |
205 decoder *dec = NULL; | 246 decoder *dec = NULL; |
206 thread_data tdata; | 247 thread_data tdata; |
207 decoder_options dopt; | 248 decoder_options dopt = { |
208 | 249 4, /* round */ |
209 int use_b25 = 0; | 250 0, /* strip */ |
251 0 /* emm */ | |
252 }; | |
253 | |
210 int result; | 254 int result; |
211 int option_index; | 255 int option_index; |
212 struct option long_options[] = { | 256 struct option long_options[] = { |
213 { "b25", 0, NULL, 'b'}, | 257 { "b25", 0, NULL, 'b'}, |
214 { "B25", 0, NULL, 'b'}, | 258 { "B25", 0, NULL, 'b'}, |
215 { "round", 1, NULL, 'r'}, | 259 { "round", 1, NULL, 'r'}, |
216 { "strip", 0, NULL, 's'}, | 260 { "strip", 0, NULL, 's'}, |
217 { "emm", 0, NULL, 'm'}, | 261 { "emm", 0, NULL, 'm'}, |
218 { "EMM", 0, NULL, 'm'} | 262 { "EMM", 0, NULL, 'm'}, |
263 { "udp", 1, NULL, 'u'}, | |
264 { "port", 1, NULL, 'p'} | |
219 }; | 265 }; |
220 | 266 |
221 dopt.round = 4; | 267 int use_b25 = 0; |
222 dopt.strip = 0; | 268 int use_udp = 0; |
223 dopt.emm = 0; | 269 char *host_to = NULL; |
224 | 270 int port_to = 1234; |
225 while((result = getopt_long(argc, argv, "br:sm", long_options, &option_index)) != -1) { | 271 sock_data *sdata = NULL; |
272 | |
273 while((result = getopt_long(argc, argv, "br:sm" "u:p:", long_options, &option_index)) != -1) { | |
226 switch(result) { | 274 switch(result) { |
227 case 'b': | 275 case 'b': |
228 use_b25 = 1; | 276 use_b25 = 1; |
229 fprintf(stderr, "using B25...\n"); | 277 fprintf(stderr, "using B25...\n"); |
230 break; | 278 break; |
231 case 's': | 279 case 's': |
232 dopt.strip = 1; | 280 dopt.strip = 1; |
233 fprintf(stderr, "enable B25 strip\n"); | 281 fprintf(stderr, "enable B25 strip\n"); |
234 break; | 282 break; |
235 case 'm': | 283 case 'm': |
236 dopt.emm = 1; | 284 dopt.emm = 1; |
237 fprintf(stderr, "enable B25 emm processing\n"); | 285 fprintf(stderr, "enable B25 emm processing\n"); |
238 break; | 286 break; |
239 case 'r': | 287 case 'r': |
240 dopt.round = atoi(optarg); | 288 dopt.round = atoi(optarg); |
241 fprintf(stderr, "set round %d\n", dopt.round); | 289 fprintf(stderr, "set round %d\n", dopt.round); |
242 break; | 290 break; |
243 case ':': | 291 case ':': |
244 fprintf(stderr, "%c needs value\n", result); | 292 fprintf(stderr, "%c needs value\n", result); |
245 break; | 293 break; |
246 case '?': | 294 case '?': |
247 fprintf(stderr, "Usage: [--b25 [--round N] [--strip] [--EMM]] channel recsec destfile\n"); | 295 show_usage(argv[0]); |
248 break; | 296 break; |
249 } | 297 case 'u': |
250 } | 298 use_udp = 1; |
251 | 299 host_to = optarg; |
252 if(argc - optind < 3) { | 300 fprintf(stderr, "UDP destination address: %s\n", host_to); |
253 printf("Usage %s: [--b25 [--round N] [--strip] [--EMM]] channel recsec destfile\n", argv[0]); | 301 break; |
302 case 'p': | |
303 port_to = atoi(optarg); | |
304 fprintf(stderr, "UDP port: %d\n", port_to); | |
305 break; | |
306 } | |
307 } | |
308 | |
309 if(argc - optind < 3) { | |
310 show_usage(argv[0]); | |
254 printf("channel =\n"); | 311 printf("channel =\n"); |
255 printf("151ch:BS朝日\n"); | 312 printf("151ch:BS朝日\n"); |
256 printf("161ch:BS-i\n"); | 313 printf("161ch:BS-i\n"); |
257 printf("191ch:WOWOW\n"); | 314 printf("191ch:WOWOW\n"); |
258 printf("171ch:BSジャパン\n"); | 315 printf("171ch:BSジャパン\n"); |
265 printf("102ch:NHK衛星第2放送(BS2)\n"); | 322 printf("102ch:NHK衛星第2放送(BS2)\n"); |
266 printf("103ch:NHKハイビジョン(BShi)\n"); | 323 printf("103ch:NHKハイビジョン(BShi)\n"); |
267 printf("CS2-CS24:CSチャンネル\n"); | 324 printf("CS2-CS24:CSチャンネル\n"); |
268 return 1; | 325 return 1; |
269 } | 326 } |
270 ptr = searchrecoff(argv[optind]); | 327 ptr = searchrecoff(argv[optind]); |
271 if(ptr == NULL){ | 328 if(ptr == NULL){ |
272 printf("Channel Select Error(%s)\n", argv[optind]); | 329 printf("Channel Select Error(%s)\n", argv[optind]); |
273 return 1; | 330 return 1; |
274 } | 331 } |
275 | 332 |
276 freq.frequencyno = ptr->set_freq; | 333 freq.frequencyno = ptr->set_freq; |
277 freq.slot = ptr->add_freq; | 334 freq.slot = ptr->add_freq; |
278 | 335 |
279 if(ptr->type == CHTYPE_SATELLITE) { | 336 if(ptr->type == CHTYPE_SATELLITE) { |
280 for(lp = 0; lp < 2; lp++) { | 337 for(lp = 0; lp < 2; lp++) { |
281 fd = open(bsdev[lp], O_RDONLY); | 338 tfd = open(bsdev[lp], O_RDONLY); |
282 if(fd >= 0) { | 339 if(tfd >= 0) { |
283 break; | 340 break; |
284 } | 341 } |
285 } | 342 } |
286 if(fd < 0) { | 343 if(tfd < 0) { |
287 fprintf(stderr, "Device Open Error\n"); | 344 fprintf(stderr, "Device Open Error\n"); |
288 return 1; | 345 return 1; |
289 } | 346 } |
290 } else { | 347 } else { |
291 for(lp = 0; lp < 2; lp++) { | 348 for(lp = 0; lp < 2; lp++) { |
292 fd = open(isdb_t_dev[lp], O_RDONLY); | 349 tfd = open(isdb_t_dev[lp], O_RDONLY); |
293 if(fd >= 0) { | 350 if(tfd >= 0) { |
294 break; | 351 break; |
295 } | 352 } |
296 } | 353 } |
297 if(fd < 0) { | 354 if(tfd < 0) { |
298 fprintf(stderr, "Device Open Error\n"); | 355 fprintf(stderr, "Device Open Error\n"); |
299 return 1; | 356 return 1; |
300 } | 357 } |
301 } | 358 } |
302 recsec = atoi(argv[optind + 1]); | 359 recsec = atoi(argv[optind + 1]); |
303 | 360 |
304 /* initialize decoder */ | 361 /* initialize decoder */ |
305 if(use_b25) { | 362 if(use_b25) { |
306 dec = b25_startup(&dopt); | 363 dec = b25_startup(&dopt); |
307 if(!dec) { | 364 if(!dec) { |
309 fprintf(stderr, "fall back to encrypted recording\n"); | 366 fprintf(stderr, "fall back to encrypted recording\n"); |
310 use_b25 = 0; | 367 use_b25 = 0; |
311 } | 368 } |
312 } | 369 } |
313 | 370 |
371 /* initialize udp connection */ | |
372 if(use_udp) { | |
373 sdata = calloc(1, sizeof(sock_data)); | |
374 struct in_addr ia; | |
375 ia.s_addr = inet_addr(host_to); | |
376 if(ia.s_addr == INADDR_NONE) { | |
377 struct hostent *hoste = gethostbyname(host_to); | |
378 if(!hoste) { | |
379 perror("failed to get host by name"); | |
380 return 1; | |
381 } | |
382 ia.s_addr = *(in_addr_t*) (hoste->h_addr_list[0]); | |
383 } | |
384 sdata->addr.sin_family = AF_INET; | |
385 sdata->addr.sin_port = htons (port_to); | |
386 sdata->addr.sin_addr.s_addr = ia.s_addr; | |
387 if((sdata->sfd = socket(PF_INET, SOCK_DGRAM, 0)) < 0) { | |
388 perror("socket"); | |
389 return 1; | |
390 } | |
391 } | |
392 | |
314 /* open output file */ | 393 /* open output file */ |
315 wfd = open(argv[optind + 2], (O_RDWR | O_CREAT | O_TRUNC), 0666); | 394 wfd = open(argv[optind + 2], (O_RDWR | O_CREAT | O_TRUNC), 0666); |
316 if(wfd < 0) { | 395 if(wfd < 0) { |
317 fprintf(stderr, "Output File Open Error(%s)\n", argv[optind + 2]); | 396 fprintf(stderr, "Output File Open Error(%s)\n", argv[optind + 2]); |
318 return 1; | 397 return 1; |
319 } | 398 } |
320 | 399 |
321 if(ioctl(fd, SET_CHANNEL, &freq) < 0) { | 400 if(ioctl(tfd, SET_CHANNEL, &freq) < 0) { |
322 fprintf(stderr, "Tuner Select Error\n"); | 401 fprintf(stderr, "Tuner Select Error\n"); |
323 return 1; | 402 return 1; |
324 } | 403 } |
325 | 404 |
326 /* make reader thread */ | 405 /* make reader thread */ |
327 tdata.queue = p_queue; | 406 tdata.queue = p_queue; |
328 tdata.decoder = dec; | 407 tdata.decoder = dec; |
329 tdata.fd = wfd; | 408 tdata.wfd = wfd; |
409 tdata.sock_data = sdata; | |
330 pthread_create(&dequeue_threads, NULL, write_func, &tdata); | 410 pthread_create(&dequeue_threads, NULL, write_func, &tdata); |
331 | 411 |
332 /* start recording */ | 412 /* start recording */ |
333 if(ioctl(fd, START_REC, 0) < 0) { | 413 if(ioctl(tfd, START_REC, 0) < 0) { |
334 fprintf(stderr, "Tuner Start Error\n"); | 414 fprintf(stderr, "Tuner Start Error\n"); |
335 return 1; | 415 return 1; |
336 } | 416 } |
337 | 417 |
338 time(&start_time); | 418 time(&start_time); |
339 | 419 |
340 /* read from tuner */ | 420 /* read from tuner */ |
341 while(1) { | 421 while(1) { |
342 time(&cur_time); | 422 time(&cur_time); |
343 bufptr = malloc(sizeof(BUFSZ)); | 423 bufptr = malloc(sizeof(BUFSZ)); |
344 bufptr->size = read(fd, bufptr->buffer, MAX_READ_SIZE); | 424 bufptr->size = read(tfd, bufptr->buffer, MAX_READ_SIZE); |
345 if(bufptr->size <= 0) { | 425 if(bufptr->size <= 0) { |
346 if((cur_time - start_time) >= recsec) { | 426 if((cur_time - start_time) >= recsec) { |
347 f_exit = TRUE; | 427 f_exit = TRUE; |
348 enqueue(p_queue, NULL); | 428 enqueue(p_queue, NULL); |
349 break; | 429 break; |
353 } | 433 } |
354 enqueue(p_queue, bufptr); | 434 enqueue(p_queue, bufptr); |
355 | 435 |
356 /* stop recording */ | 436 /* stop recording */ |
357 if((cur_time - start_time) >= recsec) { | 437 if((cur_time - start_time) >= recsec) { |
358 ioctl(fd, STOP_REC, 0); | 438 ioctl(tfd, STOP_REC, 0); |
359 /* read remaining data */ | 439 /* read remaining data */ |
360 while(1) { | 440 while(1) { |
361 bufptr = malloc(sizeof(BUFSZ)); | 441 bufptr = malloc(sizeof(BUFSZ)); |
362 bufptr->size = read(fd, bufptr->buffer, MAX_READ_SIZE); | 442 bufptr->size = read(tfd, bufptr->buffer, MAX_READ_SIZE); |
363 if(bufptr->size <= 0) { | 443 if(bufptr->size <= 0) { |
364 f_exit = TRUE; | 444 f_exit = TRUE; |
365 enqueue(p_queue, NULL); | 445 enqueue(p_queue, NULL); |
366 break; | 446 break; |
367 } | 447 } |
369 } | 449 } |
370 break; | 450 break; |
371 } | 451 } |
372 } | 452 } |
373 /* close tuner */ | 453 /* close tuner */ |
374 close(fd); | 454 close(tfd); |
375 | 455 |
376 /* wait reader thread */ | 456 /* wait reader thread */ |
377 pthread_join(dequeue_threads, NULL); | 457 pthread_join(dequeue_threads, NULL); |
378 destroy_queue(p_queue); | 458 destroy_queue(p_queue); |
379 | 459 |
460 /* close socket */ | |
461 if(use_udp) { | |
462 close(sdata->sfd); | |
463 free(sdata); | |
464 } | |
465 | |
380 /* release decoder */ | 466 /* release decoder */ |
381 if(use_b25) { | 467 if(use_b25) { |
382 b25_shutdown(dec); | 468 b25_shutdown(dec); |
383 } | 469 } |
384 | 470 |