void x264_speedcontrol_new( x264_t *h ) { x264_speedcontrol_t *sc = h->sc = x264_malloc( sizeof(x264_speedcontrol_t) ); x264_emms(); memset( sc, 0, sizeof(x264_speedcontrol_t) ); if( h->param.sc.f_speed <= 0 ) h->param.sc.f_speed = 1; sc->fps = h->param.i_fps_num / h->param.i_fps_den; sc->spf = 1e6 / sc->fps; h->param.sc.i_buffer_size = X264_MAX( 3, h->param.sc.i_buffer_size ); sc->buffer_size = h->param.sc.i_buffer_size * 1e6 / sc->fps; sc->buffer_fill = sc->buffer_size * h->param.sc.f_buffer_init; sc->buffer_fill = x264_clip3( sc->buffer_fill, sc->spf, sc->buffer_size ); sc->compensation_period = sc->buffer_size/4; sc->timestamp = x264_mdate(); sc->preset = -1; sc->prev_frame = 0; sc->cplx_num = 3e3; //FIXME estimate initial complexity sc->cplx_den = .1; sc->cplx_decay = 1 - 1./h->param.sc.i_buffer_size; sc->stat.min_buffer = sc->buffer_size; sc->stat.max_buffer = 0; sc->user_param = h->param; }
int main(int argc, char *argv[]) { int ret = 0; int i; if( argc > 1 && !strncmp( argv[1], "--bench", 7 ) ) { #if !defined(ARCH_X86) && !defined(ARCH_X86_64) fprintf( stderr, "no --bench for your cpu until you port rdtsc\n" ); return 1; #endif do_bench = 1; if( argv[1][7] == '=' ) { bench_pattern = argv[1]+8; bench_pattern_len = strlen(bench_pattern); } argc--; argv++; } i = ( argc > 1 ) ? atoi(argv[1]) : x264_mdate(); fprintf( stderr, "x264: using random seed %u\n", i ); srand( i ); buf1 = x264_malloc( 0x3e00 + 16*BENCH_ALIGNS ); buf2 = buf1 + 0xf00; buf3 = buf2 + 0xf00; buf4 = buf3 + 0x1000; for( i=0; i<0x1e00; i++ ) buf1[i] = rand() & 0xFF; memset( buf1+0x1e00, 0, 0x2000 ); /* 16-byte alignment is guaranteed whenever it's useful, but some functions also vary in speed depending on %64 */ if( do_bench ) for( i=0; i<BENCH_ALIGNS && !ret; i++ ) { buf2 = buf1 + 0xf00; buf3 = buf2 + 0xf00; buf4 = buf3 + 0x1000; ret |= x264_stack_pagealign( check_all_flags, i*16 ); buf1 += 16; quiet = 1; fprintf( stderr, "%d/%d\r", i+1, BENCH_ALIGNS ); } else ret = check_all_flags(); if( ret ) { fprintf( stderr, "x264: at least one test has failed. Go and fix that Right Now!\n" ); return -1; } fprintf( stderr, "x264: All tests passed Yeah :)\n" ); if( do_bench ) print_bench(); return 0; }
gpointer x264_gtk_encode_encode (X264_Thread_Data *thread_data) { GIOStatus status; gsize size; X264_Pipe_Data pipe_data; x264_param_t *param; x264_picture_t pic; x264_t *h; hnd_t hin; hnd_t hout; int i_frame; int i_frame_total; int64_t i_start; int64_t i_end; int64_t i_file; int i_frame_size; int i_progress; int err; g_print (_("encoding...\n")); param = thread_data->param; err = x264_set_drivers (thread_data->in_container, thread_data->out_container); if (err < 0) { GtkWidget *no_driver; no_driver = gtk_message_dialog_new (GTK_WINDOW(thread_data->dialog), GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE, (err == -2) ? _("Error: unknown output file type") : _("Error: unknown input file type")); gtk_dialog_run (GTK_DIALOG (no_driver)); gtk_widget_destroy (no_driver); return NULL; } if (p_open_infile (thread_data->file_input, &hin, param)) { fprintf( stderr, _("could not open input file '%s'\n"), thread_data->file_input ); return NULL; } p_open_outfile ((char *)thread_data->file_output, &hout); i_frame_total = p_get_frame_total (hin ); if (((i_frame_total == 0) || (param->i_frame_total < i_frame_total)) && (param->i_frame_total > 0)) i_frame_total = param->i_frame_total; param->i_frame_total = i_frame_total; if ((h = x264_encoder_open (param)) == NULL) { fprintf (stderr, _("x264_encoder_open failed\n")); p_close_infile (hin); p_close_outfile (hout); g_free (param); return NULL; } if (p_set_outfile_param (hout, param)) { fprintf (stderr, _("can't set outfile param\n")); p_close_infile (hin); p_close_outfile (hout); g_free (param); return NULL; } /* Create a new pic */ x264_picture_alloc (&pic, X264_CSP_I420, param->i_width, param->i_height ); i_start = x264_mdate(); /* Encode frames */ for (i_frame = 0, i_file = 0, i_progress = 0; ((i_frame < i_frame_total) || (i_frame_total == 0)); ) { if (p_read_frame (&pic, hin, i_frame)) break; pic.i_pts = (int64_t)i_frame * param->i_fps_den; i_file += x264_encode_frame (h, hout, &pic); i_frame++; /* update status line (up to 1000 times per input file) */ if (param->i_log_level < X264_LOG_DEBUG && (i_frame_total ? i_frame * 1000 / i_frame_total > i_progress : i_frame % 10 == 0)) { int64_t i_elapsed = x264_mdate () - i_start; if (i_frame_total) { pipe_data.frame = i_frame; pipe_data.frame_total = i_frame_total; pipe_data.file = i_file; pipe_data.elapsed = i_elapsed; status = g_io_channel_write_chars (thread_data->io_write, (const gchar *)&pipe_data, sizeof (X264_Pipe_Data), &size, NULL); if (status != G_IO_STATUS_NORMAL) { g_print (_("Error ! %d %d %d\n"), status, (int)sizeof (X264_Pipe_Data), (int)size); } else { /* we force the GIOChannel to write to the pipeline */ status = g_io_channel_flush (thread_data->io_write, NULL); if (status != G_IO_STATUS_NORMAL) { g_print (_("Error ! %d\n"), status); } } } } } /* Flush delayed B-frames */ do { i_file += i_frame_size = x264_encode_frame (h, hout, NULL); } while (i_frame_size); i_end = x264_mdate (); x264_picture_clean (&pic); x264_encoder_close (h); fprintf (stderr, "\n"); p_close_infile (hin); p_close_outfile (hout); if (i_frame > 0) { double fps = (double)i_frame * (double)1000000 / (double)(i_end - i_start); fprintf (stderr, _("encoded %d frames, %.2f fps, %.2f kb/s\n"), i_frame, fps, (double) i_file * 8 * param->i_fps_num / ((double) param->i_fps_den * i_frame * 1000)); } gtk_widget_set_sensitive (thread_data->end_button, TRUE); gtk_widget_hide (thread_data->button); return NULL; }
/***************************************************************************** * Encode: *****************************************************************************/ static int Encode( x264_param_t *param, cli_opt_t *opt ) { x264_t *h; x264_picture_t pic; int i_frame, i_frame_total; int64_t i_start, i_end; int64_t i_file; int i_frame_size; int i_progress; i_frame_total = p_get_frame_total( opt->hin ); i_frame_total -= opt->i_seek; if( ( i_frame_total == 0 || param->i_frame_total < i_frame_total ) && param->i_frame_total > 0 ) i_frame_total = param->i_frame_total; param->i_frame_total = i_frame_total; if( ( h = x264_encoder_open( param ) ) == NULL ) { fprintf( stderr, "x264_encoder_open failed\n" ); p_close_infile( opt->hin ); p_close_outfile( opt->hout ); return -1; } if( p_set_outfile_param( opt->hout, param ) ) { fprintf( stderr, "can't set outfile param\n" ); p_close_infile( opt->hin ); p_close_outfile( opt->hout ); return -1; } /* Create a new pic */ x264_picture_alloc( &pic, X264_CSP_I420, param->i_width, param->i_height ); i_start = x264_mdate(); /* Encode frames */ for( i_frame = 0, i_file = 0, i_progress = 0; b_ctrl_c == 0 && (i_frame < i_frame_total || i_frame_total == 0); ) { if( p_read_frame( &pic, opt->hin, i_frame + opt->i_seek ) ) break; pic.i_pts = (int64_t)i_frame * param->i_fps_den; if( opt->qpfile ) parse_qpfile( opt, &pic, i_frame + opt->i_seek ); else { /* Do not force any parameters */ pic.i_type = X264_TYPE_AUTO; pic.i_qpplus1 = 0; } i_file += Encode_frame( h, opt->hout, &pic ); i_frame++; /* update status line (up to 1000 times per input file) */ if( opt->b_progress && param->i_log_level < X264_LOG_DEBUG && ( i_frame_total ? i_frame * 1000 / i_frame_total > i_progress : i_frame % 10 == 0 ) ) { int64_t i_elapsed = x264_mdate() - i_start; double fps = i_elapsed > 0 ? i_frame * 1000000. / i_elapsed : 0; if( i_frame_total ) { int eta = i_elapsed * (i_frame_total - i_frame) / ((int64_t)i_frame * 1000000); i_progress = i_frame * 1000 / i_frame_total; fprintf( stderr, "encoded frames: %d/%d (%.1f%%), %.2f fps, eta %d:%02d:%02d \r", i_frame, i_frame_total, (float)i_progress / 10, fps, eta/3600, (eta/60)%60, eta%60 ); } else fprintf( stderr, "encoded frames: %d, %.2f fps \r", i_frame, fps ); fflush( stderr ); // needed in windows } } /* Flush delayed B-frames */ do { i_file += i_frame_size = Encode_frame( h, opt->hout, NULL ); } while( i_frame_size ); i_end = x264_mdate(); x264_picture_clean( &pic ); x264_encoder_close( h ); fprintf( stderr, "\n" ); if( b_ctrl_c ) fprintf( stderr, "aborted at input frame %d\n", opt->i_seek + i_frame ); p_close_infile( opt->hin ); p_close_outfile( opt->hout ); if( i_frame > 0 ) { double fps = (double)i_frame * (double)1000000 / (double)( i_end - i_start ); fprintf( stderr, "encoded %d frames, %.2f fps, %.2f kb/s\n", i_frame, fps, (double) i_file * 8 * param->i_fps_num / ( (double) param->i_fps_den * i_frame * 1000 ) ); } return 0; }
typedef struct { FFMS_VideoSource *video_source; FFMS_Track *track; int reduce_pts; int vfr_input; int num_frames; int64_t time; } ffms_hnd_t; static int FFMS_CC update_progress( int64_t current, int64_t total, void *private ) { int64_t *update_time = private; int64_t oldtime = *update_time; int64_t newtime = x264_mdate(); if( oldtime && newtime - oldtime < UPDATE_INTERVAL ) return 0; *update_time = newtime; char buf[200]; sprintf( buf, "ffms [info]: indexing input file [%.1f%%]", 100.0 * current / total ); fprintf( stderr, "%s \r", buf+5 ); x264_cli_set_console_title( buf ); fflush( stderr ); return 0; } /* handle the deprecated jpeg pixel formats */ static int handle_jpeg( int csp, int *fullrange ) {
void x264_speedcontrol_frame( x264_t *h ) { x264_speedcontrol_t *sc = h->sc; int64_t t, delta_t, delta_buffer; int delta_f; x264_emms(); // update buffer state after encoding and outputting the previous frame(s) t = x264_mdate(); delta_f = h->i_frame - sc->prev_frame; delta_t = t - sc->timestamp; delta_buffer = delta_f * sc->spf / h->param.sc.f_speed - delta_t; sc->buffer_fill += delta_buffer; sc->prev_frame = h->i_frame; sc->timestamp = t; // update the time predictor if( delta_f ) { int cpu_time = h->param.sc.b_alt_timer ? sc->cpu_time : delta_t; float decay = powf( sc->cplx_decay, delta_f ); sc->cplx_num *= decay; sc->cplx_den *= decay; sc->cplx_num += cpu_time / presets[sc->preset].time; sc->cplx_den += delta_f; sc->stat.avg_preset += sc->preset * delta_f; sc->stat.den += delta_f; } sc->stat.min_buffer = X264_MIN( sc->buffer_fill, sc->stat.min_buffer ); sc->stat.max_buffer = X264_MAX( sc->buffer_fill, sc->stat.max_buffer ); if( sc->buffer_fill > sc->buffer_size ) // oops, cpu was idle { // not really an error, but we'll warn for debugging purposes static int64_t idle_t = 0, print_interval = 0; idle_t += sc->buffer_fill - sc->buffer_size; if( t - print_interval > 1e6 ) { x264_log( h, X264_LOG_WARNING, "speedcontrol idle (%.6f sec)\n", idle_t/1e6 ); print_interval = t; idle_t = 0; } sc->buffer_fill = sc->buffer_size; } else if( sc->buffer_fill < 0 && delta_buffer < 0 ) // oops, we're late { // don't clip fullness to 0; we'll hope the real buffer was bigger than // specified, and maybe we can catch up. if the application had to drop // frames, then it should override the buffer fullness (FIXME implement this). x264_log( h, X264_LOG_WARNING, "speedcontrol underflow (%.6f sec)\n", sc->buffer_fill/1e6 ); } { // pick the preset that should return the buffer to 3/4-full within a time // specified by compensation_period float target = sc->spf / h->param.sc.f_speed * (sc->buffer_fill + sc->compensation_period) / (sc->buffer_size*3/4 + sc->compensation_period); float cplx = sc->cplx_num / sc->cplx_den; float set, t0, t1; float filled = (float) sc->buffer_fill / sc->buffer_size; int i; t0 = presets[0].time * cplx; for( i=1;; i++ ) { t1 = presets[i].time * cplx; if( t1 >= target || i == PRESETS-1 ) break; t0 = t1; } // linear interpolation between states set = i-1 + (target - t0) / (t1 - t0); // Even if our time estimations in the PRESETS array are off // this will push us towards our target fullness set += (20 * (filled-0.75)); set = x264_clip3f(set,0,PRESETS-1); apply_preset( h, dither( sc, set ) ); // FIXME if (h->param.i_log_level >= X264_LOG_DEBUG) { static float cpu, wall, tgt, den; float decay = 1-1/100.; cpu = cpu*decay + sc->cpu_time; wall = wall*decay + delta_t; tgt = tgt*decay + target; den = den*decay + 1; fprintf( stderr, "speed: %.2f %d[%.5f] (t/c/w: %6.0f/%6.0f/%6.0f = %.4f) fps=%.2f\r", set, sc->preset, (float)sc->buffer_fill / sc->buffer_size, tgt/den, cpu/den, wall/den, cpu/wall, 1e6*den/wall ); } } }
void x264_speedcontrol_frame_end( x264_t *h ) { x264_speedcontrol_t *sc = h->sc; if( h->param.sc.b_alt_timer ) sc->cpu_time = x264_mdate() - sc->timestamp; }