static int file_to_fb(const char * srcpath) { int ret = -1; BMP_READ * bmp = NULL; struct FB * fb = NULL; int sw, sh; int srcbpp, dstbpp; void * pdata = NULL, * bmpdata = NULL; RGB_CONVERT_FUN convert_func = NULL; do { bmp = bmp_open(srcpath); if (!bmp) { break; } fb = fb_create(0); if (!fb) { break; } sw = bmp_width(bmp); sh = bmp_height(bmp); bmpdata = bmp_data(bmp); srcbpp = bmp_bpp(bmp); dstbpp = fb_bpp(fb); convert_func = get_convert_func(srcbpp, dstbpp); if (convert_func) { pdata = convert_func(bmpdata, sw, sh); bmpdata = pdata; } if (!bmp_forward(bmp)) { line_reversal(bmpdata, sw, sh, dstbpp); } rgb_copy(bmpdata, fb_bits(fb), sw, sh, fb_width(fb), fb_height(fb), dstbpp); ret = 0; } while (0); fb_destory(fb); bmp_close(bmp); if (pdata) { free(pdata); } return ret; }
static int file_to_file(const char * srcpath, const char * dstpath, int output_rgb) { int ret = -1; BMP_READ * bmp = NULL; int w, h; int srcbpp, dstbpp; void * pdata = NULL, * bmpdata = NULL; RGB_CONVERT_FUN convert_func = NULL; do { bmp = bmp_open(srcpath); if (!bmp) { break; } w = bmp_width(bmp); h = bmp_height(bmp); bmpdata = bmp_data(bmp); srcbpp = bmp_bpp(bmp); dstbpp = g_rgbbpp[output_rgb]; convert_func = get_convert_func(srcbpp, dstbpp); if (convert_func) { pdata = convert_func(bmpdata, w, h); bmpdata = pdata; } if (!bmp_forward(bmp)) { line_reversal(bmpdata, w, h, dstbpp); } ret = save_bmp(dstpath, w, h, bmpdata, dstbpp); } while (0); bmp_close(bmp); if (pdata) { free(pdata); } return ret; }
static int fb_to_file(const char * dstpath, int output_rgb) { int ret = -1; int w, h; int srcbpp, dstbpp; void * pdata = NULL, * fbdata = NULL; RGB_CONVERT_FUN convert_func = NULL; struct FB * fb = NULL; do { fb = fb_create(1); if (!fb) { break; } w = fb_width(fb); h = fb_height(fb); fbdata = fb_bits(fb); srcbpp = fb_bpp(fb); dstbpp = g_rgbbpp[output_rgb]; convert_func = get_convert_func(srcbpp, dstbpp); if (convert_func) { pdata = convert_func(fbdata, w, h); fbdata = pdata; } ret = save_bmp(dstpath, w, h, fbdata, dstbpp); } while (0); if (pdata) { free(pdata); } fb_destory(fb); return ret; }
static AUO_RESULT x264_out(CONF_GUIEX *conf, const OUTPUT_INFO *oip, PRM_ENC *pe, const SYSTEM_DATA *sys_dat) { AUO_RESULT ret = AUO_RESULT_SUCCESS; PIPE_SET pipes = { 0 }; PROCESS_INFORMATION pi_enc = { 0 }; char x264cmd[MAX_CMD_LEN] = { 0 }; char x264args[MAX_CMD_LEN] = { 0 }; char x264dir[MAX_PATH_LEN] = { 0 }; char *x264fullpath = (conf->x264.use_highbit_depth) ? sys_dat->exstg->s_x264.fullpath_highbit : sys_dat->exstg->s_x264.fullpath; const BOOL afs = conf->vid.afs != 0; CONVERT_CF_DATA pixel_data = { 0 }; video_output_thread_t thread_data = { 0 }; thread_data.repeat = pe->delay_cut_additional_vframe; set_pixel_data(&pixel_data, conf, oip->w, oip->h); int *jitter = NULL; int rp_ret = 0; //x264優先度関連の初期化 DWORD set_priority = (pe->h_p_aviutl || conf->vid.priority != AVIUTLSYNC_PRIORITY_CLASS) ? priority_table[conf->vid.priority].value : NORMAL_PRIORITY_CLASS; //プロセス用情報準備 if (!PathFileExists(x264fullpath)) { ret |= AUO_RESULT_ERROR; error_no_exe_file("x264", x264fullpath); return ret; } PathGetDirectory(x264dir, _countof(x264dir), x264fullpath); //YUY2/YC48->NV12/YUV444, RGBコピー用関数 const int input_csp_idx = get_aviutl_color_format(conf->x264.use_highbit_depth, conf->x264.output_csp, conf->vid.input_as_lw48); const func_convert_frame convert_frame = get_convert_func(oip->w, input_csp_idx, (conf->x264.use_highbit_depth) ? 16 : 8, conf->x264.interlaced, conf->x264.output_csp); if (convert_frame == NULL) { ret |= AUO_RESULT_ERROR; error_select_convert_func(oip->w, oip->h, conf->x264.use_highbit_depth, conf->x264.interlaced, conf->x264.output_csp); return ret; } //映像バッファ用メモリ確保 if (!malloc_pixel_data(&pixel_data, oip->w, oip->h, conf->x264.output_csp, (conf->x264.use_highbit_depth) ? 16 : 8)) { ret |= AUO_RESULT_ERROR; error_malloc_pixel_data(); return ret; } //パイプの設定 pipes.stdIn.mode = AUO_PIPE_ENABLE; pipes.stdErr.mode = AUO_PIPE_ENABLE; pipes.stdIn.bufferSize = pixel_data.total_size * 2; //x264バージョン情報表示・チェック if (AUO_RESULT_ERROR == write_log_x264_version(x264fullpath)) { return (ret | AUO_RESULT_ERROR); } //コマンドライン生成 build_full_cmd(x264cmd, _countof(x264cmd), conf, oip, pe, sys_dat, PIPE_FN); write_log_auo_line(LOG_INFO, "x264 options..."); write_args(x264cmd); sprintf_s(x264args, _countof(x264args), "\"%s\" %s", x264fullpath, x264cmd); remove(pe->temp_filename); //ファイルサイズチェックの時に旧ファイルを参照してしまうのを回避 if (conf->vid.afs && conf->x264.interlaced) { ret |= AUO_RESULT_ERROR; error_afs_interlace_stg(); //jitter用領域確保 } else if ((jitter = (int *)calloc(oip->n + 1, sizeof(int))) == NULL) { ret |= AUO_RESULT_ERROR; error_malloc_tc(); //Aviutl(afs)からのフレーム読み込み } else if (!setup_afsvideo(oip, sys_dat, conf, pe)) { ret |= AUO_RESULT_ERROR; //Aviutl(afs)からのフレーム読み込みに失敗 //x264プロセス開始 } else if ((rp_ret = RunProcess(x264args, x264dir, &pi_enc, &pipes, (set_priority == AVIUTLSYNC_PRIORITY_CLASS) ? GetPriorityClass(pe->h_p_aviutl) : set_priority, TRUE, FALSE)) != RP_SUCCESS) { ret |= AUO_RESULT_ERROR; error_run_process("x264", rp_ret); //書き込みスレッドを開始 } else if (video_output_create_thread(&thread_data, &pixel_data, pipes.f_stdin)) { ret |= AUO_RESULT_ERROR; error_video_output_thread_start(); } else { //全て正常 int i = 0; void *frame = NULL; int *next_jitter = NULL; UINT64 amp_filesize_limit = (UINT64)(1.02 * get_amp_filesize_limit(conf, oip, pe, sys_dat)); BOOL enc_pause = FALSE, copy_frame = FALSE, drop = FALSE; const DWORD aviutl_color_fmt = COLORFORMATS[get_aviutl_color_format(conf->x264.use_highbit_depth, conf->x264.output_csp, conf->vid.input_as_lw48)].FOURCC; //Aviutlの時間を取得 PROCESS_TIME time_aviutl; GetProcessTime(pe->h_p_aviutl, &time_aviutl); //x264が待機に入るまでこちらも待機 while (WaitForInputIdle(pi_enc.hProcess, LOG_UPDATE_INTERVAL) == WAIT_TIMEOUT) log_process_events(); //ログウィンドウ側から制御を可能に DWORD tm_vid_enc_start = timeGetTime(); enable_x264_control(&set_priority, &enc_pause, afs, afs && pe->current_x264_pass == 1, tm_vid_enc_start, oip->n); //------------メインループ------------ for (i = 0, next_jitter = jitter + 1, pe->drop_count = 0; i < oip->n; i++, next_jitter++) { //中断を確認 ret |= (oip->func_is_abort()) ? AUO_RESULT_ABORT : AUO_RESULT_SUCCESS; //x264が実行中なら、メッセージを取得・ログウィンドウに表示 if (ReadLogEnc(&pipes, pe->drop_count, i) < 0) { //勝手に死んだ... ret |= AUO_RESULT_ERROR; error_x264_dead(); break; } if (!(i & 7)) { //Aviutlの進捗表示を更新 oip->func_rest_time_disp(i + oip->n * (pe->current_x264_pass - 1), oip->n * pe->total_x264_pass); //x264優先度 check_enc_priority(pe->h_p_aviutl, pi_enc.hProcess, set_priority); //音声同時処理 ret |= aud_parallel_task(oip, pe); //上限をオーバーしていないかチェック if (!(i & 63) && amp_filesize_limit //上限設定が存在する && !(1 == pe->current_x264_pass && 1 < pe->total_x264_pass)) { //multi passエンコードの1pass目でない UINT64 current_filesize = 0; if (GetFileSizeUInt64(pe->temp_filename, ¤t_filesize) && current_filesize > amp_filesize_limit) { warning_amp_filesize_over_limit(); pe->muxer_to_be_used = MUXER_DISABLED; //muxをスキップ break; } } } //一時停止 while (enc_pause & !ret) { Sleep(LOG_UPDATE_INTERVAL); ret |= (oip->func_is_abort()) ? AUO_RESULT_ABORT : AUO_RESULT_SUCCESS; log_process_events(); } //標準入力への書き込み完了をチェック while (WAIT_TIMEOUT == WaitForSingleObject(thread_data.he_out_fin, LOG_UPDATE_INTERVAL)) { ret |= (oip->func_is_abort()) ? AUO_RESULT_ABORT : AUO_RESULT_SUCCESS; log_process_events(); } //中断・エラー等をチェック if (AUO_RESULT_SUCCESS != ret) break; //コピーフレームフラグ処理 copy_frame = (!!i & (oip->func_get_flag(i) & OUTPUT_INFO_FRAME_FLAG_COPYFRAME)); //Aviutl(afs)からフレームをもらう if (NULL == (frame = ((afs) ? afs_get_video((OUTPUT_INFO *)oip, i, &drop, next_jitter) : oip->func_get_video_ex(i, aviutl_color_fmt)))) { ret |= AUO_RESULT_ERROR; error_afs_get_frame(); break; } drop |= (afs & copy_frame); if (!drop) { //コピーフレームの場合は、映像バッファの中身を更新せず、そのままパイプに流す if (!copy_frame) convert_frame(frame, &pixel_data, oip->w, oip->h); /// YUY2/YC48->NV12/YUV444変換, RGBコピー //標準入力への書き込みを開始 SetEvent(thread_data.he_out_start); } else { *(next_jitter - 1) = DROP_FRAME_FLAG; pe->drop_count++; //次のフレームの変換を許可 SetEvent(thread_data.he_out_fin); } // 「表示 -> セーブ中もプレビュー表示」がチェックされていると // func_update_preview() の呼び出しによって func_get_video_ex() の // 取得したバッファが書き換えられてしまうので、呼び出し位置を移動 (拡張AVI出力 plus より) oip->func_update_preview(); } //------------メインループここまで-------------- //書き込みスレッドを終了 video_output_close_thread(&thread_data, ret); //ログウィンドウからのx264制御を無効化 disable_x264_control(); //パイプを閉じる CloseStdIn(&pipes); if (!ret) oip->func_rest_time_disp(oip->n * pe->current_x264_pass, oip->n * pe->total_x264_pass); //音声の同時処理を終了させる ret |= finish_aud_parallel_task(oip, pe, ret); //音声との同時処理が終了 release_audio_parallel_events(pe); //タイムコード出力 if (!ret && (afs || conf->vid.auo_tcfile_out)) tcfile_out(jitter, oip->n, (double)oip->rate / (double)oip->scale, afs, pe); //エンコーダ終了待機 while (WaitForSingleObject(pi_enc.hProcess, LOG_UPDATE_INTERVAL) == WAIT_TIMEOUT) ReadLogEnc(&pipes, pe->drop_count, i); DWORD tm_vid_enc_fin = timeGetTime(); //最後にメッセージを取得 while (ReadLogEnc(&pipes, pe->drop_count, i) > 0); if (!(ret & AUO_RESULT_ERROR) && afs) write_log_auo_line_fmt(LOG_INFO, "drop %d / %d frames", pe->drop_count, i); write_log_auo_line_fmt(LOG_INFO, "CPU使用率: Aviutl: %.2f%% / x264: %.2f%%", GetProcessAvgCPUUsage(pe->h_p_aviutl, &time_aviutl), GetProcessAvgCPUUsage(pi_enc.hProcess)); write_log_auo_enc_time("x264エンコード時間", tm_vid_enc_fin - tm_vid_enc_start); } //解放処理 if (pipes.stdErr.mode) CloseHandle(pipes.stdErr.h_read); CloseHandle(pi_enc.hProcess); CloseHandle(pi_enc.hThread); free_pixel_data(&pixel_data); if (jitter) free(jitter); ret |= exit_audio_parallel_control(oip, pe, ret); return ret; }