y4m_ratio_t y4m_guess_sar(int width, int height, y4m_ratio_t dar) { int i; double implicit_sar = (double)(dar.n * height) / (double)(dar.d * width); const y4m_ratio_t *sarray[] = { &y4m_sar_SQUARE, &y4m_sar_NTSC_CCIR601, &y4m_sar_NTSC_16_9, &y4m_sar_NTSC_SVCD_4_3, &y4m_sar_NTSC_SVCD_16_9, &y4m_sar_PAL_CCIR601, &y4m_sar_PAL_16_9, &y4m_sar_PAL_SVCD_4_3, &y4m_sar_PAL_SVCD_16_9, &y4m_sar_UNKNOWN }; for (i = 0; !(Y4M_RATIO_EQL(*(sarray[i]),y4m_sar_UNKNOWN)); i++) { double ratio = implicit_sar / Y4M_RATIO_DBL(*(sarray[i])); if ( (ratio > (1.0 - GUESS_ASPECT_TOLERANCE)) && (ratio < (1.0 + GUESS_ASPECT_TOLERANCE)) ) return *(sarray[i]); } return y4m_sar_UNKNOWN; }
/** init_parse_files * Verifies the PNG input files and prepares YUV4MPEG header information. * @returns 0 on success */ static int init_parse_files(parameters_t *param) { char pngname[255]; snprintf(pngname, sizeof(pngname), param->pngformatstr, param->begin); mjpeg_debug("Analyzing %s to get the right pic params", pngname); if (decode_png(pngname, 0, param) == -1) mjpeg_error_exit1("Reading of %s failed.\n", pngname); mjpeg_info("Image dimensions are %ux%u", param->width, param->height); mjpeg_info("Movie frame rate is: %f frames/second", Y4M_RATIO_DBL(param->framerate)); switch (param->interlace) { case Y4M_ILACE_NONE: mjpeg_info("Non-interlaced/progressive frames."); break; case Y4M_ILACE_BOTTOM_FIRST: mjpeg_info("Interlaced frames, bottom field first."); break; case Y4M_ILACE_TOP_FIRST: mjpeg_info("Interlaced frames, top field first."); break; default: mjpeg_error_exit1("Interlace has not been specified (use -I option)"); break; } if ((param->interlace != Y4M_ILACE_NONE) && (param->interleave == -1)) mjpeg_error_exit1("Interleave has not been specified (use -L option)"); if (!(param->interleave) && (param->interlace != Y4M_ILACE_NONE)) { param->height *= 2; mjpeg_info("Non-interleaved fields (image height doubled)"); } mjpeg_info("Frame size: %u x %u", param->width, param->height); return 0; }
y4m_ratio_t mpeg_conform_framerate( double fps ) { mpeg_framerate_code_t i; y4m_ratio_t result; /* try to match it to a standard frame rate */ /* (start at '1', because 0 is unknown/illegal) */ for (i = 1; i < mpeg_num_framerates; i++) { double deviation = 1.0 - (Y4M_RATIO_DBL(mpeg_framerates[i]) / fps); if ( (deviation > -MPEG_FPS_TOLERANCE) && (deviation < +MPEG_FPS_TOLERANCE) ) return mpeg_framerates[i]; } /* no luck? just turn it into a ratio (6 decimal place accuracy) */ result.n = (int)((fps * 1000000.0) + 0.5); result.d = 1000000; y4m_ratio_reduce(&result); return result; }
int main (int argc, char *argv[]) { extern char *optarg; int cpucap = cpu_accel (); char c; int fd_in = 0; int fd_out = 1; int errno = 0; int have_framerate = 0; int force_interlacing = 0; y4m_frame_info_t iframeinfo; y4m_stream_info_t istreaminfo; y4m_frame_info_t oframeinfo; y4m_stream_info_t ostreaminfo; int output_frame_number = 0; int input_frame_number = 0; y4m_ratio_t output_frame_rate, input_frame_rate, frame_rate_ratio; float ratio = 0; // input/output, output should be > input ) int scene_change; y4m_ratio_t ratio_percent_frame; float percent_threshold = 0.02; /* percent_threshold is there to avoid interpolating frames when the output frame * is very close to an input frame */ mjpeg_log (LOG_INFO, "-------------------------------------------------"); mjpeg_log (LOG_INFO, " Motion-Compensating-Frame-Rate-Converter "); mjpeg_log (LOG_INFO, "-------------------------------------------------"); while ((c = getopt (argc, argv, "hvb:p:r:t:s:f")) != -1) { switch (c) { case 'h': { mjpeg_log (LOG_INFO, "Usage "); mjpeg_log (LOG_INFO, "-------------------------"); mjpeg_log (LOG_INFO, " This program converts frame rates"); mjpeg_log (LOG_INFO, "with a smart algorithm that estimates the motion of the elements"); mjpeg_log (LOG_INFO, "to smooth the motion, rather than duplicating frames."); mjpeg_log (LOG_INFO, " It's way smoother, but introduces a bit of blocking and/or"); mjpeg_log (LOG_INFO, " maybe blurryness when things move too fast."); mjpeg_log (LOG_INFO, " "); mjpeg_log (LOG_INFO, " -r Frame rate for the resulting stream (in X:Y fractional form)"); mjpeg_log (LOG_INFO, " -b block size (default = 8, will be rounded to even number )"); mjpeg_log (LOG_INFO, " -p search path radius (default = 8, do not use high values ~ > 20)"); mjpeg_log (LOG_INFO, "-t frame approximation threshold (default=50, higher=better)"); mjpeg_log (LOG_INFO, "-s scene change threshold (default=8, 0=disable scene change detection)"); mjpeg_log (LOG_INFO, "-r Frame rate for the resulting stream (in X:Y fractional form)"); mjpeg_log (LOG_INFO, " -f force processing interlaced input (don't know what it does)"); mjpeg_log (LOG_INFO, " -v verbose/debug"); exit (0); break; } case 'v': { verbose = 1; break; } case 'f': { force_interlacing = 1; break; } case 'b': { block_size = strtol (optarg, (char **) NULL, 10); /* we only want even block sizes */ if (block_size % 1 != 0) { block_size = block_size + 1; mjpeg_log (LOG_WARN, "Block size changed to %d", block_size); } else mjpeg_log (LOG_INFO, "Block size: %d", block_size); break; } case 'p': { search_path_radius = strtol (optarg, (char **) NULL, 10); /* safer atoi */ mjpeg_log (LOG_INFO, "Search radius %d", search_path_radius); break; } case 'r': { if (Y4M_OK != y4m_parse_ratio (&output_frame_rate, optarg)) mjpeg_error_exit1 ("Syntax for frame rate should be Numerator:Denominator"); mjpeg_log (LOG_INFO, "New Frame rate %d:%d", output_frame_rate.n, output_frame_rate.d); have_framerate = 1; break; } case 't': { percent_threshold = strtol (optarg, (char **) NULL, 10); if ((percent_threshold > 1) && (percent_threshold <= 1024)) percent_threshold = 1.0 / percent_threshold; else mjpeg_error_exit1 ("Threshold should be between 2 and 1024"); mjpeg_log (LOG_INFO, "Approximation threshold %d", (int) ((float) 1.0 / percent_threshold)); break; } case 's': { scene_change_threshold = strtol (optarg, (char **) NULL, 10); if (scene_change_threshold == 0) mjpeg_log (LOG_INFO, "Scene change detection disabled"); else mjpeg_log (LOG_INFO, "Scene change threshold: %d00 percent", scene_change_threshold); break; } } } if (!have_framerate) { mjpeg_error_exit1 ("Please specify a frame rate; yuvmotionfps -h for more info"); } /* initialize motion_library */ init_motion_search (); /* initialize MMX transforms (fixme) */ if ((cpucap & ACCEL_X86_MMXEXT) != 0 || (cpucap & ACCEL_X86_SSE) != 0) { #if 0 mjpeg_log (LOG_INFO, "FIXME: could use MMX/SSE Block/Frame-Copy/Blend if I had one ;-)"); #endif } /* initialize stream-information */ y4m_accept_extensions (1); y4m_init_stream_info (&istreaminfo); y4m_init_frame_info (&iframeinfo); y4m_init_stream_info (&ostreaminfo); y4m_init_frame_info (&oframeinfo); /* open input stream */ if ((errno = y4m_read_stream_header (fd_in, &istreaminfo)) != Y4M_OK) { mjpeg_log (LOG_ERROR, "Couldn't read YUV4MPEG header: %s!", y4m_strerr (errno)); exit (1); } /* get format information */ width = y4m_si_get_width (&istreaminfo); height = y4m_si_get_height (&istreaminfo); input_chroma_subsampling = y4m_si_get_chroma (&istreaminfo); mjpeg_log (LOG_INFO, "Y4M-Stream is %ix%i(%s)", width, height, input_chroma_subsampling == Y4M_CHROMA_420JPEG ? "4:2:0 MPEG1" : input_chroma_subsampling == Y4M_CHROMA_420MPEG2 ? "4:2:0 MPEG2" : input_chroma_subsampling == Y4M_CHROMA_420PALDV ? "4:2:0 PAL-DV" : input_chroma_subsampling == Y4M_CHROMA_444 ? "4:4:4" : input_chroma_subsampling == Y4M_CHROMA_422 ? "4:2:2" : input_chroma_subsampling == Y4M_CHROMA_411 ? "4:1:1 NTSC-DV" : input_chroma_subsampling == Y4M_CHROMA_MONO ? "MONOCHROME" : input_chroma_subsampling == Y4M_CHROMA_444ALPHA ? "4:4:4:4 ALPHA" : "unknown"); /* if chroma-subsampling isn't supported bail out ... */ switch (input_chroma_subsampling) { case Y4M_CHROMA_420JPEG: break; case Y4M_CHROMA_420PALDV: case Y4M_CHROMA_420MPEG2: case Y4M_CHROMA_411: mjpeg_log (LOG_WARN, "This chroma subsampling mode has not been thoroughly tested"); break; default: mjpeg_error_exit1 ("Y4M-Stream is not 4:2:0. Other chroma-modes currently not allowed. Sorry."); } /* the output is progressive 4:2:0 MPEG 1 */ y4m_si_set_interlace (&ostreaminfo, Y4M_ILACE_NONE); y4m_si_set_chroma (&ostreaminfo, Y4M_CHROMA_420JPEG); y4m_si_set_width (&ostreaminfo, width); y4m_si_set_height (&ostreaminfo, height); y4m_si_set_sampleaspect (&ostreaminfo, y4m_si_get_sampleaspect (&istreaminfo)); input_frame_rate = y4m_si_get_framerate (&istreaminfo); y4m_si_set_framerate (&ostreaminfo, output_frame_rate); if (width % block_size != 0) { mjpeg_log (LOG_WARN, "Warning, stream width(%d) is not a multiple of block_size (%d)", width, block_size); mjpeg_log (LOG_WARN, "The right side of the image might not be what you want"); } if (height % block_size != 0) { mjpeg_log (LOG_WARN, "Warning, stream height(%d) is not a multiple of block_size (%d)", height, block_size); mjpeg_log (LOG_WARN, "The lower side of the image might not be what you want"); } /* Calculate the different ratios: * ratio is (input framerate / output framerate) * ratio_percent_frame is the fractional representation of percent frame */ frame_rate_ratio.n = input_frame_rate.n * output_frame_rate.d; frame_rate_ratio.d = input_frame_rate.d * output_frame_rate.n; y4m_ratio_reduce (&frame_rate_ratio); ratio = (float) frame_rate_ratio.n / frame_rate_ratio.d; ratio_percent_frame.d = 1; ratio_percent_frame.n = 0; if (ratio == 0) mjpeg_error_exit1 ("Cannot have ratio =0 "); else if (ratio > 128) mjpeg_error_exit1 ("Cannot have ratio >128 "); if ((y4m_si_get_interlace (&istreaminfo) != Y4M_ILACE_NONE) && (!force_interlacing)) { mjpeg_error_exit1 ("Sorry, can only convert progressive streams"); } /* write the outstream header */ y4m_write_stream_header (fd_out, &ostreaminfo); /* now allocate the needed buffers */ { /* calculate the memory offset needed to allow the processing * functions to overshot. The biggest overshot is needed for the * MC-functions, so we'll use 8*width... */ buff_offset = width * 8; buff_size = buff_offset * 2 + width * height; inframe[0] = buff_offset + (uint8_t *) malloc (buff_size); inframe[1] = buff_offset + (uint8_t *) malloc (buff_size); inframe[2] = buff_offset + (uint8_t *) malloc (buff_size); reconstructed[0] = buff_offset + (uint8_t *) malloc (buff_size); reconstructed[1] = buff_offset + (uint8_t *) malloc (buff_size); reconstructed[2] = buff_offset + (uint8_t *) malloc (buff_size); frame1[0] = buff_offset + (uint8_t *) malloc (buff_size); frame1[1] = buff_offset + (uint8_t *) malloc (buff_size); frame1[2] = buff_offset + (uint8_t *) malloc (buff_size); mjpeg_log (LOG_INFO, "Buffers allocated."); } /* initialize motion-search-pattern */ init_search_pattern (); errno = y4m_read_frame (fd_in, &istreaminfo, &iframeinfo, frame1); if (errno != Y4M_OK) goto The_end; /* read every frame until the end of the input stream and process it */ while (Y4M_OK == (errno = y4m_read_frame (fd_in, &istreaminfo, &iframeinfo, inframe))) { /* frame1 contains the previous input frame * inframe contains the current input frame * reconstructed contains the current output frame * percent_frame is the amount of time after which the output frame is sent * in percent of the time between input frames * * Input: * frame1 . . . . . . . . . . . . . . . . . . inframe * Output: * . . . . . . . . . . .reconstructed. . . . . . . * |<- - percent_frame - - - ->| * |< - - - - - - - - - -100% - - - - - - - - - >| * * The variable ratio_percent_frame is the fractional representation of * percent_frame; it is there to avoid rounding errors */ input_frame_number++; if (verbose) { mjpeg_log (LOG_INFO, "Input frame number %d", input_frame_number); } while (percent_frame < (1.0 - percent_threshold)) { output_frame_number++; if (verbose) { mjpeg_log (LOG_INFO, "Output frame number %d", output_frame_number); } #define ABS(value) ((value)<0)?-(value):(value) if (ABS (percent_frame) <= percent_threshold) { /* I put a threshold here to avoid wasting time */ /* The output frame coincides with the input frame * so there is no need to do any processing * just copy the input frame as is */ y4m_write_frame (fd_out, &ostreaminfo, &oframeinfo, frame1); if (verbose) mjpeg_log (LOG_INFO, "Percent %f rounded to next frame", percent_frame); } else { /* We have to interpolate the frame (between the current inframe * and the previous frame1 * if there is a scene change, motion_compensate_field will * return 1 and we use the previous frame */ if (verbose) mjpeg_log (LOG_INFO, "Percent %f", percent_frame); scene_change = motion_compensate_field (); if (scene_change) { mjpeg_log (LOG_INFO, "Scene change at frame %d", input_frame_number); y4m_write_frame (fd_out, &ostreaminfo, &oframeinfo, frame1); } else { y4m_write_frame (fd_out, &ostreaminfo, &oframeinfo, reconstructed); } } ratio_percent_frame = add_ratio (ratio_percent_frame, frame_rate_ratio); percent_frame = Y4M_RATIO_DBL (ratio_percent_frame); } /* Skip input frames if downsampling (ratio > 1) * when upsampling, ratio < 1 * so we have ( 1< percent_frame < 2) at this point * hence we don't go in in the loop */ while (percent_frame >= 2) { percent_frame = percent_frame - 1; ratio_percent_frame = ratio_minus_1 (ratio_percent_frame); if (Y4M_OK != (errno = y4m_read_frame (fd_in, &istreaminfo, &iframeinfo, inframe))) goto The_end; } ratio_percent_frame = ratio_minus_1 (ratio_percent_frame); percent_frame = percent_frame - 1; /* store the previous frame */ memcpy (frame1[0], inframe[0], width * height); memcpy (frame1[1], inframe[1], width * height / 4); memcpy (frame1[2], inframe[2], width * height / 4); } The_end: /* free allocated buffers */ { free (inframe[0] - buff_offset); free (inframe[1] - buff_offset); free (inframe[2] - buff_offset); free (reconstructed[0] - buff_offset); free (reconstructed[1] - buff_offset); free (reconstructed[2] - buff_offset); free (frame1[0] - buff_offset); free (frame1[1] - buff_offset); free (frame1[2] - buff_offset); mjpeg_log (LOG_INFO, "Buffers freed."); } /* did stream end unexpectedly ? */ if (errno != Y4M_ERR_EOF) mjpeg_error_exit1 ("%s", y4m_strerr (errno)); /* Exit gently */ return (0); }
static boolean lives_yuv_stream_start_read(lives_clip_t *sfile) { double ofps=sfile->fps; lives_yuv4m_t *yuv4mpeg=(lives_yuv4m_t *)sfile->ext_src; pthread_t y4thread; char *filename=yuv4mpeg->filename,*tmp; int alarm_handle=0; int ohsize=sfile->hsize; int ovsize=sfile->vsize; y4data thread_data; register int i; if (filename==NULL) return FALSE; if (yuv4mpeg->fd==-1) { // create a thread to open the fifo thread_data.filename=filename; pthread_create(&y4thread,NULL,y4open_thread,(void *)&thread_data); alarm_handle=lives_alarm_set(YUV4_O_TIME); d_print(""); d_print(_("Waiting for yuv4mpeg frames...")); while (!lives_alarm_get(alarm_handle)&&!pthread_kill(y4thread,0)) { // wait for thread to complete or timeout lives_usleep(prefs->sleep_time); lives_widget_context_update(); } if (lives_alarm_get(alarm_handle)) { // timeout - kill thread and wait for it to terminate pthread_cancel(y4thread); pthread_join(y4thread,NULL); lives_alarm_clear(alarm_handle); d_print_failed(); d_print(_("Unable to open the incoming video stream\n")); yuv4mpeg->fd=thread_data.fd; if (yuv4mpeg->fd>=0) { close(yuv4mpeg->fd); yuv4mpeg->fd=-1; } return FALSE; } pthread_join(y4thread,NULL); lives_alarm_clear(alarm_handle); yuv4mpeg->fd=thread_data.fd; if (yuv4mpeg->fd<0) { return FALSE; } } // create a thread to open the stream header thread_data.yuv4mpeg=yuv4mpeg; pthread_create(&y4thread,NULL,y4header_thread,&thread_data); alarm_handle=lives_alarm_set(YUV4_H_TIME); while (!lives_alarm_get(alarm_handle)&&!pthread_kill(y4thread,0)) { // wait for thread to complete or timeout lives_usleep(prefs->sleep_time); lives_widget_context_update(); } if (lives_alarm_get(alarm_handle)) { // timeout - kill thread and wait for it to terminate pthread_cancel(y4thread); pthread_join(y4thread,NULL); lives_alarm_clear(alarm_handle); d_print(_("Unable to read the stream header\n")); return FALSE; } pthread_join(y4thread,NULL); lives_alarm_clear(alarm_handle); i=thread_data.i; if (i != Y4M_OK) { char *tmp; d_print((tmp=lives_strdup_printf("yuv4mpeg: %s\n", y4m_strerr(i)))); lives_free(tmp); return FALSE; } d_print(_("got header\n")); sfile->hsize = yuv4mpeg->hsize = y4m_si_get_width(&(yuv4mpeg->streaminfo)); sfile->vsize = yuv4mpeg->vsize = y4m_si_get_height(&(yuv4mpeg->streaminfo)); sfile->fps=cfile->pb_fps=lives_strtod(lives_strdup_printf("%.8f",Y4M_RATIO_DBL (y4m_si_get_framerate(&(yuv4mpeg->streaminfo)))),NULL); if (!(sfile->hsize*sfile->vsize)) { do_error_dialog(lives_strdup_printf(_("Video dimensions: %d x %d are invalid. Stream cannot be opened"), sfile->hsize,sfile->vsize)); return FALSE; } if (sfile->hsize!=ohsize||sfile->vsize!=ovsize||sfile->fps!=ofps) { set_main_title(sfile->file_name,0); } d_print((tmp=lives_strdup_printf(_("Reset clip values for %s: size=%dx%d fps=%.3f\n"),yuv4mpeg->name, cfile->hsize,yuv4mpeg->vsize,cfile->bpp,cfile->fps))); lives_free(tmp); yuv4mpeg->ready=TRUE; return TRUE; }
mpeg_aspect_code_t mpeg_guess_mpeg_aspect_code(int mpeg_version, y4m_ratio_t sampleaspect, int frame_width, int frame_height) { if (Y4M_RATIO_EQL(sampleaspect, y4m_sar_UNKNOWN)) { return 0; } switch (mpeg_version) { case 1: if (Y4M_RATIO_EQL(sampleaspect, y4m_sar_SQUARE)) { return 1; } else if (Y4M_RATIO_EQL(sampleaspect, y4m_sar_NTSC_CCIR601)) { return 12; } else if (Y4M_RATIO_EQL(sampleaspect, y4m_sar_NTSC_16_9)) { return 6; } else if (Y4M_RATIO_EQL(sampleaspect, y4m_sar_PAL_CCIR601)) { return 8; } else if (Y4M_RATIO_EQL(sampleaspect, y4m_sar_PAL_16_9)) { return 3; } return 0; break; case 2: if (Y4M_RATIO_EQL(sampleaspect, y4m_sar_SQUARE)) { return 1; /* '1' means square *pixels* in MPEG-2; go figure. */ } else { int i; double true_far; /* true frame aspect ratio */ true_far = (double)(sampleaspect.n * frame_width) / (double)(sampleaspect.d * frame_height); /* start at '2'... */ for (i = 2; i < (int)(mpeg_num_aspect_ratios[mpeg_version-1]); i++) { double ratio = true_far / Y4M_RATIO_DBL(mpeg_aspect_ratios[mpeg_version-1][i]); if ( (ratio > (1.0 - GUESS_ASPECT_TOLERANCE)) && (ratio < (1.0 + GUESS_ASPECT_TOLERANCE)) ) return i; } return 0; } break; default: return 0; break; } }
int main(int argc, char *argv[]) { int verbosity = 1; double time_between_frames = 0.0; double frame_rate = 0.0; struct timeval time_now; int n, frame; unsigned char *yuv[3]; int in_fd = 0; int screenwidth=0, screenheight=0; y4m_stream_info_t streaminfo; y4m_frame_info_t frameinfo; int frame_width; int frame_height; int wait_for_sync = 1; char *window_title = NULL; while ((n = getopt(argc, argv, "hs:t:f:cv:")) != EOF) { switch (n) { case 'c': wait_for_sync = 0; break; case 's': if (sscanf(optarg, "%dx%d", &screenwidth, &screenheight) != 2) { mjpeg_error_exit1( "-s option needs two arguments: -s 10x10"); exit(1); } break; case 't': window_title = optarg; break; case 'f': frame_rate = atof(optarg); if( frame_rate <= 0.0 || frame_rate > 200.0 ) mjpeg_error_exit1( "-f option needs argument > 0.0 and < 200.0"); break; case 'v': verbosity = atoi(optarg); if ((verbosity < 0) || (verbosity > 2)) mjpeg_error_exit1("-v needs argument from {0, 1, 2} (not %d)", verbosity); break; case 'h': case '?': usage(); exit(1); break; default: usage(); exit(1); } } mjpeg_default_handler_verbosity(verbosity); y4m_accept_extensions(1); y4m_init_stream_info(&streaminfo); y4m_init_frame_info(&frameinfo); if ((n = y4m_read_stream_header(in_fd, &streaminfo)) != Y4M_OK) { mjpeg_error("Couldn't read YUV4MPEG2 header: %s!", y4m_strerr(n)); exit (1); } switch (y4m_si_get_chroma(&streaminfo)) { case Y4M_CHROMA_420JPEG: case Y4M_CHROMA_420MPEG2: case Y4M_CHROMA_420PALDV: break; default: mjpeg_error_exit1("Cannot handle non-4:2:0 streams yet!"); } frame_width = y4m_si_get_width(&streaminfo); frame_height = y4m_si_get_height(&streaminfo); if ((screenwidth <= 0) || (screenheight <= 0)) { /* no user supplied screen size, so let's use the stream info */ y4m_ratio_t aspect = y4m_si_get_sampleaspect(&streaminfo); if (!(Y4M_RATIO_EQL(aspect, y4m_sar_UNKNOWN))) { /* if pixel aspect ratio present, use it */ #if 1 /* scale width, but maintain height (line count) */ screenheight = frame_height; screenwidth = frame_width * aspect.n / aspect.d; #else if ((frame_width * aspect.d) < (frame_height * aspect.n)) { screenwidth = frame_width; screenheight = frame_width * aspect.d / aspect.n; } else { screenheight = frame_height; screenwidth = frame_height * aspect.n / aspect.d; } #endif } else { /* unknown aspect ratio -- assume square pixels */ screenwidth = frame_width; screenheight = frame_height; } } /* Initialize the SDL library */ if( SDL_Init(SDL_INIT_VIDEO) < 0 ) { mjpeg_error("Couldn't initialize SDL: %s", SDL_GetError()); exit(1); } /* set window title */ SDL_WM_SetCaption(window_title, NULL); /* yuv params */ yuv[0] = malloc(frame_width * frame_height * sizeof(unsigned char)); yuv[1] = malloc(frame_width * frame_height / 4 * sizeof(unsigned char)); yuv[2] = malloc(frame_width * frame_height / 4 * sizeof(unsigned char)); screen = SDL_SetVideoMode(screenwidth, screenheight, 0, SDL_SWSURFACE); if ( screen == NULL ) { mjpeg_error("SDL: Couldn't set %dx%d: %s", screenwidth, screenheight, SDL_GetError()); exit(1); } else { mjpeg_debug("SDL: Set %dx%d @ %d bpp", screenwidth, screenheight, screen->format->BitsPerPixel); } /* since IYUV ordering is not supported by Xv accel on maddog's system * (Matrox G400 --- although, the alias I420 is, but this is not * recognized by SDL), we use YV12 instead, which is identical, * except for ordering of Cb and Cr planes... * we swap those when we copy the data to the display buffer... */ yuv_overlay = SDL_CreateYUVOverlay(frame_width, frame_height, SDL_YV12_OVERLAY, screen); if ( yuv_overlay == NULL ) { mjpeg_error("SDL: Couldn't create SDL_yuv_overlay: %s", SDL_GetError()); exit(1); } if ( yuv_overlay->hw_overlay ) mjpeg_debug("SDL: Using hardware overlay."); rect.x = 0; rect.y = 0; rect.w = screenwidth; rect.h = screenheight; SDL_DisplayYUVOverlay(yuv_overlay, &rect); signal (SIGINT, sigint_handler); frame = 0; if ( frame_rate == 0.0 ) { /* frame rate has not been set from command-line... */ if (Y4M_RATIO_EQL(y4m_fps_UNKNOWN, y4m_si_get_framerate(&streaminfo))) { mjpeg_info("Frame-rate undefined in stream... assuming 25Hz!" ); frame_rate = 25.0; } else { frame_rate = Y4M_RATIO_DBL(y4m_si_get_framerate(&streaminfo)); } } time_between_frames = 1.e6 / frame_rate; gettimeofday(&time_now,0); while ((n = y4m_read_frame(in_fd, &streaminfo, &frameinfo, yuv)) == Y4M_OK && (!got_sigint)) { /* Lock SDL_yuv_overlay */ if ( SDL_MUSTLOCK(screen) ) { if ( SDL_LockSurface(screen) < 0 ) break; } if (SDL_LockYUVOverlay(yuv_overlay) < 0) break; /* let's draw the data (*yuv[3]) on a SDL screen (*screen) */ memcpy(yuv_overlay->pixels[0], yuv[0], frame_width * frame_height); memcpy(yuv_overlay->pixels[1], yuv[2], frame_width * frame_height / 4); memcpy(yuv_overlay->pixels[2], yuv[1], frame_width * frame_height / 4); /* Unlock SDL_yuv_overlay */ if ( SDL_MUSTLOCK(screen) ) { SDL_UnlockSurface(screen); } SDL_UnlockYUVOverlay(yuv_overlay); /* Show, baby, show! */ SDL_DisplayYUVOverlay(yuv_overlay, &rect); mjpeg_info("Playing frame %4.4d - %s", frame, print_status(frame, frame_rate)); if (wait_for_sync) while(get_time_diff(time_now) < time_between_frames) { usleep(1000); } frame++; gettimeofday(&time_now,0); } if ((n != Y4M_OK) && (n != Y4M_ERR_EOF)) mjpeg_error("Couldn't read frame: %s", y4m_strerr(n)); for (n=0; n<3; n++) { free(yuv[n]); } mjpeg_info("Played %4.4d frames (%s)", frame, print_status(frame, frame_rate)); SDL_FreeYUVOverlay(yuv_overlay); SDL_Quit(); y4m_fini_frame_info(&frameinfo); y4m_fini_stream_info(&streaminfo); return 0; }