Main Page | Alphabetical List | Data Structures | File List | Data Fields | Globals

xdvshow-main.c

Go to the documentation of this file.
00001 /* 00002 * Copyright (c) 1999, 2000, 2001, 2002 WIDE Project 00003 * Author : Akimichi OGAWA (akimichi@sfc.wide.ad.jp) 00004 * 00005 * Redistribution and use in source and binary forms, with or without 00006 * modification, are permitted provided that the following conditions 00007 * are met: 00008 * 1. Redistributions of source code MUST retain the above copyright 00009 * notice, this list of conditions and the following disclaimer. 00010 * 2. Redistributions in binary form MUST reproduce the above copyright 00011 * notice, this list of conditions and the following disclaimer in the 00012 * documentation and/or other materials provided with the distribution. 00013 * 3. All advertising materials mentioning features or use of this software 00014 * MUST display the following acknowledgement: 00015 * This product includes software developed by Akimichi OGAWA. 00016 * 4. The name of the author MAY NOT be used to endorse or promote products 00017 * derived from this software without specific prior written permission. 00018 * 00019 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 00020 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 00021 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 00022 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, 00023 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 00024 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 00025 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 00026 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 00027 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 00028 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 00029 * POSSIBILITY OF SUCH DAMAGE. 00030 * 00031 */ 00032 00033 #ifdef HAVE_CONFIG_H 00034 #include <config.h> 00035 #endif /* HAVE_CONFIG_H */ 00036 00037 #include <stdio.h> 00038 #include <string.h> 00039 #include <stdlib.h> 00040 #include <unistd.h> 00041 #include <sys/time.h> 00042 #include <signal.h> 00043 #include <sys/socket.h> 00044 #include <sys/shm.h> 00045 #include <assert.h> 00046 00047 #include <sys/types.h> 00048 #include <sys/stat.h> 00049 #include <fcntl.h> 00050 #include <unistd.h> 00051 00052 #include <pthread.h> 00053 00054 #ifdef LINUX 00055 #include <getopt.h> 00056 #endif /* LINUX */ 00057 00058 #include <libdv/dv.h> 00059 00060 #include <xdvshow-info.h> 00061 00062 #if (HAVE_SDL || HAVE_SDL11) 00063 #include <xdvshow-sdl.h> 00064 #endif /* HAVE_SDL */ 00065 00066 #include <xdvshow-x11.h> 00067 00068 #include "xdvshow-shm.h" 00069 #include "xdvshow-rtp.h" 00070 #include "xdvshow-file.h" 00071 #include "xdvshow-ieee1394.h" 00072 #include "xdvshow-audio.h" 00073 #include "xdvshow-flags.h" 00074 #include "xdvshow-const.h" 00075 #include "xdvshow-defs.h" 00076 00077 int flags_stereo = 0; 00078 int flags_fulscreen = 0; 00079 #if (HAVE_SDL || HAVE_SDL11) 00080 int flags_sdl = 1; 00081 int flags_x11 = 0; 00082 #else 00083 int flags_sdl = 0; 00084 int flags_x11 = 1; 00085 #endif 00086 int fags_sdlnooverlay = 0; 00087 int flags_file = 0; 00088 int flags_zoom = 0; 00089 int flags_scale = 0; 00090 int flags_dump = 0; 00091 int flags_deinterlace = 0; 00092 int flags_reflector = 0; 00093 int flags_use_audio = 0; 00094 00095 int flags_format_wide = 0; 00096 int flags_format_normal = 0; 00097 00098 u_int32_t flags = 0x0; 00099 u_int32_t dv_format_type = e_dv_system_625_50; 00100 int (*input_func) __P((u_char **)); 00101 int (*input_unlock_func) __P(()); 00102 00103 int (*audio_input_func) __P((u_char **)); 00104 int (*audio_unlock_func) __P(()); 00105 00106 char *prog_name = XDVSHOW_PROGNAME; 00107 00108 void *video_thread_func __P((void *)); 00109 void *audio_thread_func __P((void *)); 00110 00111 u_char *videodata; 00112 00113 u_char *audioframe; 00114 int16_t *audio_buffers[4]; 00115 00116 00117 struct xdvshow_rtp_param rtp_param; 00118 00119 int dump_fd; 00120 char *reflector_address; 00121 00122 struct timeval currtime; 00123 long frametime_usec; 00124 long frametimeadd_usec = 27000; 00125 long framedelay_usec; 00126 00127 dv_decoder_t *dv_dec; 00128 00129 pthread_t read_thread; 00130 pthread_t ping_thread; 00131 pthread_t video_thread; 00132 00142 static void 00143 sigint_signal(int signo) { 00144 00145 void *thread_result; 00146 int ret; 00147 00148 assert(signo == SIGINT); 00149 00150 DPRINT_BARE("\n"); 00151 DPRINT("Entering SIGINT handling.\n"); 00152 00153 if (flags_reflector) { 00154 DPRINT("Waiting for ping thread to finish.\n"); 00155 ret = pthread_join(ping_thread, &thread_result); 00156 if (ret < 0) { 00157 perror("ping_thread join failed"); 00158 } 00159 } 00160 00161 /* XXX - when calling pthread_cancel(video_thread) here, I get blocking 00162 behavior again. Perhaps this is due to buggy libc_r on FreeBSD 5.X 00163 (X < 3) and will be corrected as a part of libpthead on 5.3. A backtrace 00164 of the blocking looks usually like: 00165 #0 0x281fdd1b in pthread_testcancel () from /usr/lib/libkse.so.1 00166 #1 0x281f649c in pthread_mutexattr_init () from /usr/lib/libkse.so.1 00167 #2 0x281fa524 in pthread_setconcurrency () from /usr/lib/libkse.so.1 00168 #3 0x281f11b6 in _nanosleep () from /usr/lib/libkse.so.1 00169 #4 0x2824420f in sleep () from /lib/libc.so.5 00170 #5 0x281e712f in sleep () from /usr/lib/libkse.so.1 00171 #6 0x0804b72b in audio_thread_func (data=0x8063000) at xdvshow-main.c:627 00172 #7 0x0804b337 in main (argc=3, argv=0xbfbfe40c) at xdvshow-main.c:509 00173 #8 0x08049822 in _start () 00174 */ 00175 DPRINT("Waiting for video thread to finish.\n"); 00176 00177 /* In some pathological cases (other init failed for some reason) 00178 * the video thread may not be initialized. */ 00179 if (video_thread) { 00180 #ifndef FREEBSD_5 00181 pthread_cancel(video_thread); 00182 #endif /* FREEBSD_5 */ 00183 ret = pthread_join(video_thread, &thread_result); 00184 if (ret < 0) { 00185 perror("video_thread join failed"); 00186 } 00187 } else { 00188 DPRINT("No video thread initialized.\n"); 00189 } 00190 00191 00192 DPRINT("Waiting for read thread to finish.\n"); 00193 /* XXX - pthread_cancel is blocking here on linux machine (2.4.22 kernel) 00194 when using SDL for video displaying. 00195 */ 00196 #ifdef LINUX26 00197 pthread_cancel(read_thread); 00198 #endif /* LINUX26 */ 00199 pthread_kill(read_thread, SIGTERM); 00200 ret = pthread_join(read_thread, &thread_result); 00201 if (ret < 0) { 00202 perror("read_thread join failed"); 00203 } 00204 00205 if (flags_dump) { 00206 DPRINT("Closing dump file.\n"); 00207 close(dump_fd); 00208 } 00209 00210 #if (HAVE_SDL || HAVE_SDL11) 00211 if (flags_sdl != 0) { 00212 DPRINT("Closing SDL.\n"); 00213 xdvshow_close_window(); 00214 } 00215 #endif /* HAVE_SDL */ 00216 if (flags_x11 != 0) { 00217 DPRINT("Closing X11.\n"); 00218 xdvshow_x11_close_window(); 00219 } 00220 00221 DPRINT("Freeing memory.\n"); 00222 dv_decoder_free(dv_dec); 00223 00224 if(shmdt(_xdvshow_shm.shm_buf) != 0) { 00225 perror("shmdt on _xdvshow_shm.shm_buf"); 00226 } 00227 if (shmctl(_xdvshow_shm.shmid, IPC_RMID, NULL) != 0) { 00228 perror("shmctl on _xdvshow_shm.shmid"); 00229 } 00230 00231 printf("Exit\n"); 00232 exit (EXIT_SUCCESS); 00233 } 00234 00243 int 00244 main(int argc, char *argv[]) 00245 { 00246 int ret; 00247 00248 u_char *dvframe; 00249 00250 pthread_attr_t bigstack; 00251 00252 int i; 00253 00254 char *audio_dev = NULL; 00255 00256 extern char *optarg; 00257 int op; 00258 00259 void *open_option = NULL; 00260 00261 void * (*input_open) __P((void *)); 00262 00263 void (*input_close) __P((void)); 00264 00265 memset(&rtp_param, 0, sizeof(rtp_param)); 00266 00267 dv_dec = dv_decoder_new(FALSE, FALSE, FALSE); 00268 if (dv_dec == NULL) { 00269 fprintf(stderr, "ERROR : dv_decoder_new\n"); 00270 return(EXIT_FAILURE); 00271 } 00272 00273 dv_dec->quality = DV_QUALITY_BEST; 00274 00275 input_open = xdvshow_prepare_rtp; 00276 input_func = xdvshow_read_shm; 00277 input_unlock_func = xdvshow_read_unlock; 00278 audio_input_func = xdvshow_read_audio_shm; 00279 audio_unlock_func = xdvshow_read_audio_unlock; 00280 input_close = xdvshow_close_shm; 00281 open_option = &rtp_param; 00282 00283 rtp_param.s_addr.ss_family = (sa_family_t) AF_INET; 00284 rtp_param.port = 12000; 00285 00286 while ((op = getopt(argc, argv, "A:vhf:46P:j:r:odDFzZSixs")) > 0) { 00287 switch (op) { 00288 case 'v': 00289 show_version(); 00290 exit(EXIT_SUCCESS); 00291 00292 case 'f': 00293 input_open = xdvshow_prepare_file; 00294 input_func = xdvshow_read_shm; 00295 audio_input_func = xdvshow_read_audio_shm; 00296 input_close = xdvshow_close_file; 00297 open_option = optarg; 00298 flags_file = 1; 00299 break; 00300 00301 case '4': 00302 rtp_param.s_addr.ss_family = (sa_family_t) AF_INET; 00303 break; 00304 00305 #ifdef ENABLE_INET6 00306 case '6': 00307 rtp_param.s_addr.ss_family = (sa_family_t) AF_INET6; 00308 break; 00309 #endif /* ENABLE_INET6 */ 00310 00311 case 'P': 00312 rtp_param.port = atoi(optarg); 00313 printf("Port: %d\n", rtp_param.port); 00314 if (rtp_param.port < 1) { 00315 printf("Invalid port number : %d\n", rtp_param.port); 00316 return(EXIT_FAILURE); 00317 } 00318 break; 00319 00320 case 'j': 00321 rtp_param.multi_addr_str = optarg; 00322 break; 00323 00324 case 'A': 00325 flags_use_audio = 1; 00326 audio_dev = optarg; 00327 break; 00328 00329 case 'r': 00330 flags_reflector = 1; 00331 reflector_address = optarg; 00332 break; 00333 00334 case 'z': 00335 if (flags_stereo == 0) { 00336 flags_zoom = 1; 00337 } else { 00338 printf("Zoom not enabled with stereo flag.\n"); 00339 } 00340 break; 00341 00342 case 'Z': 00343 flags_scale = 1; 00344 break; 00345 00346 case 'S': 00347 flags_stereo = 1; 00348 if (flags_zoom != 0) { 00349 flags_zoom = 0; 00350 printf("Zoom not enabled with stereo flag.\n"); 00351 } 00352 break; 00353 00354 case 'F': 00355 flags_fullscreen = 1; 00356 break; 00357 00358 #if (LINUX && HAVE_LIBRAW1394) || FREEBSD_5 00359 case 'i': 00360 input_open = xdvshow_capture_raw; 00361 input_func = xdvshow_read_shm; 00362 audio_input_func = xdvshow_read_audio_shm; 00363 input_close = NULL; 00364 open_option = NULL; 00365 break; 00366 #endif /* (LINUX && HAVE_LIBRAW1394) || FREEBSD_5 */ 00367 00368 #if (HAVE_SDL || HAVE_SDL11) 00369 case 's': 00370 flags_sdl = 1; 00371 flags_x11 = 0; 00372 break; 00373 00374 case 'o': 00375 flags_sdlnooverlay = 1; 00376 break; 00377 #endif /* HAVE_SDL */ 00378 00379 case 'x': 00380 flags_x11 = 1; 00381 flags_sdl = 0; 00382 flags_fullscreen = 0; 00383 break; 00384 00385 case 'd': 00386 flags_dump = 1; 00387 #ifdef __USE_LARGEFILES64 00388 dump_fd = open("dump.dv", O_RDWR | O_CREAT | O_LARGEFILE, 00644); 00389 #else 00390 dump_fd = open("dump.dv", O_RDWR | O_CREAT, 00644); 00391 #endif /* __USE_LARGEFILES64 */ 00392 00393 if (dump_fd < 0) { 00394 perror("open dump.dv"); 00395 flags_dump = 0; 00396 } 00397 break; 00398 00399 case 'D': 00400 flags_deinterlace = 1; 00401 break; 00402 00403 case 'h': 00404 default: 00405 show_usage(argv[0]); 00406 return(EXIT_FAILURE); 00407 break; 00408 00409 } 00410 } 00411 00412 if (signal(SIGINT, sigint_signal) == SIG_ERR) { 00413 fprintf(stderr, "Cannot install signal handler.\n"); 00414 } 00415 00416 #ifdef DEBUG 00417 if (flags_file) { 00418 gettimeofday(&currtime, NULL); 00419 DPRINT("Start: %ld : %ld\n", currtime.tv_sec, currtime.tv_usec); 00420 } 00421 #endif 00422 00423 if (flags_file){ 00424 gettimeofday(&currtime, NULL); 00425 frametime_usec = currtime.tv_usec + frametimeadd_usec; 00426 } 00427 00428 if (flags_reflector) { 00429 memset(&ping_thread, 0, sizeof(ping_thread)); 00430 if((ret = pthread_create(&ping_thread, NULL, xdvshow_ping_reflector, (void *)reflector_address))) { 00431 perror("ping thread creation"); 00432 assert(ret==0); 00433 } 00434 } 00435 00436 pthread_attr_init(&bigstack); 00437 pthread_attr_setstacksize(&bigstack, (size_t) THREAD_STACKSIZE); 00438 00439 /* We need to initialize semaphores first to avoid timing problems */ 00440 if(xdvshow_semaphore_init() != 0) { 00441 perror("Failed to initialize semaphores!"); 00442 dv_decoder_free(dv_dec); 00443 /* TODO: Some other deallocations are probably supposed to be here! */ 00444 exit(EXIT_FAILURE); 00445 } 00446 00447 memset(&read_thread, 0, sizeof(read_thread)); 00448 if (input_open == xdvshow_prepare_rtp) { 00449 if ((ret = pthread_create(&read_thread, &bigstack, xdvshow_prepare_rtp, (void *)open_option))) { 00450 perror("xdvshow_prepare_rtp thread creation"); 00451 assert(ret==0); 00452 } 00453 } 00454 pthread_attr_destroy(&bigstack); 00455 if (input_open == xdvshow_prepare_file) { 00456 if((ret = pthread_create(&read_thread, NULL, xdvshow_prepare_file, (void *)open_option))) { 00457 perror("xdvshow_prepare_file thread creation"); 00458 assert(ret==0); 00459 } 00460 } 00461 if (input_open == xdvshow_capture_raw) { 00462 if((ret = pthread_create(&read_thread, NULL, xdvshow_capture_raw, (void *)open_option))) { 00463 perror("xdvshow_capture_raw thread creation"); 00464 assert(ret==0); 00465 } 00466 } 00467 00468 DPRINT("Read thread started\n"); 00469 00470 while ((flags_format_normal == 0) && (flags_format_wide == 0)) { 00471 00472 DPRINT("Reading DV frames for 16:9/4:3 detection.\n"); 00473 ret = (*input_func)(&dvframe); 00474 if (ret < 0) { 00475 kill(getpid(), SIGINT); 00476 return(EXIT_FAILURE); 00477 } 00478 00479 DPRINT("Detecting 16:9/4:3 formats.\n"); 00480 00481 dv_parse_header(dv_dec, dvframe); 00482 00483 if (dv_format_wide(dv_dec)) { 00484 flags_format_normal = 1; 00485 fprintf (stderr, "Detected 16:9 format\n"); 00486 } 00487 if (dv_format_normal(dv_dec)) { 00488 flags_format_wide = 1; 00489 fprintf (stderr, "Detected 4:3 format\n"); 00490 } 00491 00492 fprintf(stderr, "Audio is %.1f kHz, %d bits quantization, %d channels, emphasis %s\n", 00493 (float)dv_dec->audio->frequency / 1000.0, 00494 dv_dec->audio->quantization, 00495 dv_dec->audio->num_channels, 00496 (dv_dec->audio->emphasis ? "on" : "off")); 00497 00498 if ((flags_format_normal != 0) && (flags_format_wide != 0)) { 00499 fprintf (stderr, "Error detecting 16:9/4:3 video format. Trying again...\n"); 00500 flags_format_normal = 0; 00501 flags_format_wide = 0; 00502 } 00503 00504 if (input_unlock_func) { 00505 (*input_unlock_func)(); 00506 } 00507 } 00508 00509 dv_format_type = dv_dec->system; 00510 switch (dv_format_type) { 00511 case e_dv_system_525_60: 00512 fprintf (stderr, "Detected NTSC format\n"); 00513 break; 00514 case e_dv_system_625_50: 00515 fprintf (stderr, "Detected PAL format\n"); 00516 break; 00517 default: 00518 fprintf (stderr, "Error detecting NTSC/PAL format...\n"); 00519 } 00520 00521 00522 if (flags_use_audio) { 00523 00524 ret = xdvshow_init_audio(audio_dev, dv_dec->audio); 00525 if (ret < 0) { 00526 fprintf(stderr, "Audio init failed. Audio disabled.\n"); 00527 flags_use_audio = 0; 00528 00529 goto audio_init_failed; 00530 } 00531 00532 for (i = 0; i < 4; i++) { 00533 audio_buffers[i] = malloc(DV_AUDIO_MAX_SAMPLES * sizeof(u_int16_t)); 00534 00535 if (audio_buffers[i] == NULL) { 00536 fprintf(stderr, "Failed to init audio.\n"); 00537 flags_use_audio = 0; 00538 } 00539 else if (memset (audio_buffers[i], 0, DV_AUDIO_MAX_SAMPLES * sizeof(u_int16_t)) == NULL) { 00540 perror("memset of audio_buffers[i] failed"); 00541 assert(0); 00542 } 00543 } 00544 } 00545 00546 audio_init_failed: 00547 00548 if(memset(&video_thread, 0, sizeof(video_thread)) == NULL) { 00549 perror("memset of video_thread failed"); 00550 assert(0); 00551 } 00552 ret = pthread_create(&video_thread, NULL, video_thread_func, (void *)dv_dec); 00553 if(ret != 0) { 00554 perror("video_thread creation failed"); 00555 } 00556 00557 audio_thread_func((void *)dv_dec); 00558 00559 kill(getpid(), SIGINT); 00560 00561 return(EXIT_SUCCESS); 00562 } 00573 void * 00574 video_thread_func(void *data) 00575 { 00576 int ret = 0; 00577 00578 dv_decoder_t *dv_dec = NULL; 00579 00580 struct x_params param; 00581 00582 memset(&param, 0, sizeof(param)); 00583 00584 dv_dec = (dv_decoder_t *)data; 00585 00586 param.dv_format_type = dv_format_type; 00587 00588 #if (HAVE_SDL || HAVE_SDL11) 00589 if (flags_sdl) { 00590 ret = xdvshow_open_window(prog_name, &param); 00591 } 00592 #endif /* HAVE_SDL */ 00593 if (flags_x11) { 00594 ret = xdvshow_x11_open_window(prog_name, &param); 00595 } 00596 if (ret < 0) { 00597 printf("failed to open window\n"); 00598 kill(getpid(), SIGINT); 00599 return(NULL); 00600 } 00601 00602 while (1) { 00603 #if (HAVE_SDL || HAVE_SDL11) 00604 xdvshow_SDL_handle_events(); 00605 #endif /* HAVE_SDL */ 00606 00607 (*input_func)(&videodata); 00608 00609 if (flags_dump) { 00610 ret = write(dump_fd, videodata, 144000); 00611 DPRINT("Videodata written: %d\n", ret); 00612 if(ret == -1) { 00613 perror("writing videodata failed"); 00614 } 00615 } 00616 00617 pthread_testcancel(); 00618 dv_decode_full_frame(dv_dec, 00619 videodata, 00620 param.decode_format, 00621 param.pixels, 00622 param.pitches); 00623 00624 pthread_testcancel(); 00625 #if (HAVE_SDL || HAVE_SDL11) 00626 if (flags_sdl) { 00627 xdvshow_render(); 00628 } 00629 #endif /* HAVE_SDL */ 00630 if (flags_x11) { 00631 xdvshow_x11_render(); 00632 } 00633 DPRINT("DISPLAYED\n"); 00634 pthread_testcancel(); 00635 00636 if (input_unlock_func) { 00637 (*input_unlock_func)(); 00638 } 00639 pthread_testcancel(); 00640 00641 if (flags_file){ 00642 gettimeofday(&currtime, NULL); 00643 framedelay_usec = frametime_usec - currtime.tv_usec; 00644 if (framedelay_usec < 0 || framedelay_usec > 40000){ 00645 DPRINT("Machine too slow or timing is queer somehow :(\n"); 00646 DPRINT("currtime_usec: %ld, frametime_usec: %ld, framedelay_usec: %ld\n", 00647 currtime.tv_usec, frametime_usec, framedelay_usec); 00648 } else { 00649 usleep(framedelay_usec); 00650 DPRINT("currtime_sec: %ld\n", currtime.tv_sec); 00651 DPRINT("currtime_usec: %ld, frametime_usec: %ld, framedelay_usec: %ld\n", 00652 currtime.tv_usec, frametime_usec, framedelay_usec); 00653 } 00654 gettimeofday(&currtime, NULL); 00655 frametime_usec = currtime.tv_usec + frametimeadd_usec; 00656 if (frametime_usec > 1000000){ 00657 frametime_usec = frametime_usec - 1000000; 00658 } 00659 } 00660 } 00661 00662 return(NULL); 00663 } 00664 00676 void * 00677 audio_thread_func(void *data) 00678 { 00679 int ret = 0; 00680 00681 if (flags_use_audio) { 00682 while(1) { 00683 (*audio_input_func)(&audioframe); 00684 00685 dv_decode_full_audio(dv_dec, audioframe, audio_buffers); 00686 ret = xdvshow_play_audio(dv_dec->audio, audio_buffers); 00687 if (ret < 0) { 00688 break; 00689 } 00690 00691 if (audio_unlock_func) { 00692 (*audio_unlock_func)(); 00693 } 00694 } 00695 } else { 00696 while (1) { 00697 sleep(30); 00698 } 00699 } 00700 00701 return(NULL); 00702 } 00703

Generated on Wed Nov 3 19:19:02 2004 for xdvshow by doxygen 1.3.7