--- branches/dev-api-4/xvidcore/vfw/src/config.c 2004/01/25 06:06:22 1331 +++ branches/dev-api-4/xvidcore/vfw/src/config.c 2004/02/09 10:14:54 1358 @@ -57,9 +57,6 @@ #include #include -#include -#include - #include /* sprintf */ #include /* XviD API */ @@ -79,6 +76,8 @@ HWND g_hTooltip; static int g_use_bitrate = 1; + + int pp_dy, pp_duv, pp_dr, pp_fe; /* decoder options */ /* enumerates child windows, assigns tooltips */ @@ -146,6 +145,38 @@ }; +typedef struct { + char * name; + float value; +} named_float_t; + +static const named_float_t video_fps_list[] = { + { "15.0", 15.0F }, + { "23.976 (FILM)", 23.976F }, + { "25.0 (PAL)", 25.0F }, + { "29.97 (NTSC)", 29.970F }, + { "30.0", 30.0F } +}; + + +typedef struct { + char * name; + int avi_interval; /* audio overhead intervals (milliseconds) */ + float mkv_multiplier; /* mkv multiplier */ +} named_int_t; + + +#define NO_AUDIO 5 +static const named_int_t audio_type_list[] = { + { "MP3-CBR", 1000, 48000/1152/6 }, + { "MP3-VBR", 24, 48000/1152/6 }, + { "OGG", /*?*/1000, 48000*(0.7F/1024 + 0.3F/180) }, + { "AC3", 64, 48000/1536/6 }, + { "DTS", 21, /*?*/48000/1152/6 }, + { "(None)", 0, 0 }, +}; + + /* ===================================================================================== */ /* REGISTRY ============================================================================ */ /* ===================================================================================== */ @@ -192,6 +223,7 @@ /* 2pass1 */ {"discard1pass", ®.discard1pass, 1}, + {"full1pass", ®.full1pass, 0}, /* 2pass2 */ {"keyframe_boost", ®.keyframe_boost, 10}, @@ -203,6 +235,19 @@ {"twopass_max_overflow_improvement", ®.twopass_max_overflow_improvement, 5}, {"twopass_max_overflow_degradation", ®.twopass_max_overflow_degradation, 5}, + /* bitrate calculator */ + {"container_type", ®.container_type, 1}, + {"target_size", ®.target_size, 650 * 1024}, + {"subtitle_size", ®.subtitle_size, 0}, + {"hours", ®.hours, 1}, + {"minutes", ®.minutes, 30}, + {"seconds", ®.seconds, 0}, + {"fps", ®.fps, 2}, + {"audio_mode", ®.audio_mode, 0}, + {"audio_type", ®.audio_type, 0}, + {"audio_rate", ®.audio_rate, 128}, + {"audio_size", ®.audio_size, 0}, + /* motion */ {"motion_search", ®.motion_search, 6}, {"vhq_mode", ®.vhq_mode, 1}, @@ -325,7 +370,7 @@ reg.profile = 0; for (i=0; ici_valid); break; @@ -712,7 +787,7 @@ /* enable/disable controls based on encoder-mode or user selection */ -void adv_mode(HWND hDlg, int idd, CONFIG * config) +static void adv_mode(HWND hDlg, int idd, CONFIG * config) { int profile; int weight_en, quant_en; @@ -785,6 +860,114 @@ SetDlgItemInt(hDlg, IDC_LEVEL_BITRATE, profiles[profile].max_bitrate, FALSE); break; + case IDD_BITRATE : + { + int ctype = SendDlgItemMessage(hDlg, IDC_BITRATE_CFORMAT, CB_GETCURSEL, 0, 0); + int target_size = config_get_uint(hDlg, IDC_BITRATE_TSIZE, 0); + int subtitle_size = config_get_uint(hDlg, IDC_BITRATE_SSIZE, 0); + int fps = SendDlgItemMessage(hDlg, IDC_BITRATE_FPS, CB_GETCURSEL, 0, 0); + + int duration = + 3600 * config_get_uint(hDlg, IDC_BITRATE_HOURS, 0) + + 60 * config_get_uint(hDlg, IDC_BITRATE_MINUTES, 0) + + config_get_uint(hDlg, IDC_BITRATE_SECONDS, 0); + + int audio_type = SendDlgItemMessage(hDlg, IDC_BITRATE_AFORMAT, CB_GETCURSEL, 0, 0); + int audio_mode = IsDlgChecked(hDlg, IDC_BITRATE_AMODE_SIZE); + int audio_rate = config_get_uint(hDlg, IDC_BITRATE_ARATE, 0); + int audio_size = config_get_uint(hDlg, IDC_BITRATE_ASIZE, 0); + + int frames; + int overhead; + int vsize; + + if (duration == 0) + break; + + if (fps < 0 || fps >= sizeof(video_fps_list)/sizeof(named_float_t)) { + fps = 0; + } + if (audio_type < 0 || audio_type >= sizeof(audio_type_list)/sizeof(named_int_t)) { + audio_type = 0; + } + + EnableDlgWindow(hDlg, IDC_BITRATE_AMODE_RATE, audio_type!=NO_AUDIO); + EnableDlgWindow(hDlg, IDC_BITRATE_AMODE_SIZE, audio_type!=NO_AUDIO); + EnableDlgWindow(hDlg, IDC_BITRATE_ARATE, audio_type!=NO_AUDIO && !audio_mode); + EnableDlgWindow(hDlg, IDC_BITRATE_ASIZE, audio_type!=NO_AUDIO && audio_mode); + EnableDlgWindow(hDlg, IDC_BITRATE_ASELECT, audio_type!=NO_AUDIO && audio_mode); + + /* step 1: calculate number of frames */ + frames = (int)(duration * video_fps_list[fps].value); + + /* step 2: calculate audio_size (kbytes)*/ + if (audio_type!=NO_AUDIO) { + if (audio_mode==0) { + audio_size = (duration * audio_rate) / 8; + } + }else{ + audio_size = 0; + } + + /* step 3: calculate container overhead */ + + switch(ctype) { + case 0 : /* AVI */ + case 1 : /* AVI-OpenDML */ + + overhead = frames; + + if (audio_type!=NO_AUDIO) { + overhead += (duration * 1000) / audio_type_list[audio_type].avi_interval; + } + + overhead *= (ctype==0) ? 24 : 16; + + overhead /= 1024; + break; + + case 2 : /* Matroska: gknot formula */ + + /* common overhead */ + overhead = 40 + 12 + 8+ 16*duration + 200 + 100*1/*one audio stream*/ + 11*duration; + + /* video overhead */ + overhead += frames*8 + (int)(frames * 4 * 0.94); + + /* cue tables and menu seek entries (300k default) */ + overhead += 300 * 1024; + + /* audio */ + overhead += (int)(duration * audio_type_list[audio_type].mkv_multiplier); + + overhead /= 1024; + break; + + case 3 : /* OGM: inaccurate model */ + overhead = (int)(0.0039F * (target_size - subtitle_size)); + break; + + default : /* (none) */ + overhead = 0; + break; + } + + SetDlgItemInt(hDlg, IDC_BITRATE_COVERHEAD, overhead, TRUE); + + /* final video bitstream size */ + vsize = target_size - subtitle_size - audio_size - overhead; + if (vsize > 0) { + SetDlgItemInt(hDlg, IDC_BITRATE_VSIZE, vsize, TRUE); + /* convert from kbytes to kbits-per-second */ + SetDlgItemInt(hDlg, IDC_BITRATE_VRATE, (vsize * 8 * 128) / (duration * 125), TRUE); + }else{ + SetDlgItemText(hDlg, IDC_BITRATE_VSIZE, "Overflow"); + SetDlgItemText(hDlg, IDC_BITRATE_VRATE, "Overflow"); + } + + } + break; + case IDD_ZONE : weight_en = IsDlgChecked(hDlg, IDC_ZONE_MODE_WEIGHT); quant_en = IsDlgChecked(hDlg, IDC_ZONE_MODE_QUANT); @@ -823,7 +1006,7 @@ /* upload config data into dialog */ -void adv_upload(HWND hDlg, int idd, CONFIG * config) +static void adv_upload(HWND hDlg, int idd, CONFIG * config) { switch (idd) { @@ -865,6 +1048,7 @@ case IDD_RC_2PASS1 : SetDlgItemText(hDlg, IDC_STATS, config->stats); CheckDlg(hDlg, IDC_DISCARD1PASS, config->discard1pass); + CheckDlg(hDlg, IDC_FULL1PASS, config->full1pass); break; case IDD_RC_2PASS2 : @@ -881,6 +1065,22 @@ SetDlgItemInt(hDlg, IDC_MINKEY, config->kfthreshold, FALSE); break; + case IDD_BITRATE : + SendDlgItemMessage(hDlg, IDC_BITRATE_CFORMAT, CB_SETCURSEL, config->container_type, 0); + SetDlgItemInt(hDlg, IDC_BITRATE_TSIZE, config->target_size, FALSE); + SetDlgItemInt(hDlg, IDC_BITRATE_SSIZE, config->subtitle_size, FALSE); + + SetDlgItemInt(hDlg, IDC_BITRATE_HOURS, config->hours, FALSE); + SetDlgItemInt(hDlg, IDC_BITRATE_MINUTES, config->minutes, FALSE); + SetDlgItemInt(hDlg, IDC_BITRATE_SECONDS, config->seconds, FALSE); + SendDlgItemMessage(hDlg, IDC_BITRATE_FPS, CB_SETCURSEL, config->fps, 0); + + SendDlgItemMessage(hDlg, IDC_BITRATE_AFORMAT, CB_SETCURSEL, config->audio_type, 0); + CheckRadioButton(hDlg, IDC_BITRATE_AMODE_RATE, IDC_BITRATE_AMODE_SIZE, config->audio_mode == 0 ? IDC_BITRATE_AMODE_RATE : IDC_BITRATE_AMODE_SIZE); + SetDlgItemInt(hDlg, IDC_BITRATE_ARATE, config->audio_rate, FALSE); + SetDlgItemInt(hDlg, IDC_BITRATE_ASIZE, config->audio_size, FALSE); + break; + case IDD_ZONE : SetDlgItemInt(hDlg, IDC_ZONE_FRAME, config->zones[config->cur_zone].frame, FALSE); @@ -948,7 +1148,7 @@ /* download config data from dialog */ -void adv_download(HWND hDlg, int idd, CONFIG * config) +static void adv_download(HWND hDlg, int idd, CONFIG * config) { switch (idd) { @@ -995,6 +1195,7 @@ if (GetDlgItemText(hDlg, IDC_STATS, config->stats, MAX_PATH) == 0) lstrcpy(config->stats, CONFIG_2PASS_FILE); config->discard1pass = IsDlgChecked(hDlg, IDC_DISCARD1PASS); + config->full1pass = IsDlgChecked(hDlg, IDC_FULL1PASS); break; case IDD_RC_2PASS2 : @@ -1021,6 +1222,39 @@ break; + case IDD_BITRATE : + config->container_type = SendDlgItemMessage(hDlg, IDC_BITRATE_CFORMAT, CB_GETCURSEL, 0, 0); + config->target_size = config_get_uint(hDlg, IDC_BITRATE_TSIZE, config->target_size); + config->subtitle_size = config_get_uint(hDlg, IDC_BITRATE_SSIZE, config->subtitle_size); + + config->hours = config_get_uint(hDlg, IDC_BITRATE_HOURS, config->hours); + config->minutes = config_get_uint(hDlg, IDC_BITRATE_MINUTES, config->minutes); + config->seconds = config_get_uint(hDlg, IDC_BITRATE_SECONDS, config->seconds); + config->fps = SendDlgItemMessage(hDlg, IDC_BITRATE_FPS, CB_GETCURSEL, 0, 0); + + config->audio_type = SendDlgItemMessage(hDlg, IDC_BITRATE_AFORMAT, CB_GETCURSEL, 0, 0); + config->audio_mode = IsDlgChecked(hDlg, IDC_BITRATE_AMODE_SIZE) ? 1 : 0 ; + config->audio_rate = config_get_uint(hDlg, IDC_BITRATE_ARATE, config->audio_rate); + config->audio_size = config_get_uint(hDlg, IDC_BITRATE_ASIZE, config->audio_size); + + /* the main window uses "AVI bitrate/filesize" not "video bitrate/filesize", + so we have to compensate by frames * 24 bytes */ + { + int frame_compensate = 24 * (int)( + (3600*config->hours + + 60*config->minutes + + config->seconds) * video_fps_list[config->fps].value) / 1024; + + int bitrate_compensate = (int)(24 * video_fps_list[config->fps].value) / 125; + + config->desired_size = + config_get_uint(hDlg, IDC_BITRATE_VSIZE, config->desired_size) - frame_compensate; + + config->bitrate = + config_get_uint(hDlg, IDC_BITRATE_VRATE, config->bitrate) - bitrate_compensate; + } + break; + case IDD_ZONE : config->zones[config->cur_zone].frame = config_get_uint(hDlg, IDC_ZONE_FRAME, config->zones[config->cur_zone].frame); @@ -1101,7 +1335,7 @@ /* advanced dialog proc */ -BOOL CALLBACK adv_proc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) +static BOOL CALLBACK adv_proc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) { PROPSHEETINFO *psi; @@ -1132,9 +1366,48 @@ case IDC_CPU_FORCE : case IDC_AR : case IDC_PAR : + case IDC_BITRATE_AMODE_RATE : + case IDC_BITRATE_AMODE_SIZE : adv_mode(hDlg, psi->idd, psi->config); break; + case IDC_BITRATE_SSELECT : + case IDC_BITRATE_ASELECT : + { + OPENFILENAME ofn; + char filename[MAX_PATH] = ""; + + memset(&ofn, 0, sizeof(OPENFILENAME)); + ofn.lStructSize = sizeof(OPENFILENAME); + + ofn.hwndOwner = hDlg; + if (LOWORD(wParam)==IDC_BITRATE_SSELECT) { + ofn.lpstrFilter = "Subtitle files (*.sub, *.ssa)\0*.sub;*.ssa\0All files (*.*)\0*.*\0\0"; + }else{ + ofn.lpstrFilter = "Audio files (*.mp3, *.ac3)\0*.mp3; *.ac3\0All files (*.*)\0*.*\0\0"; + } + + ofn.lpstrFile = filename; + ofn.nMaxFile = MAX_PATH; + ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST; + + if (GetOpenFileName(&ofn)) { + HANDLE hFile; + DWORD filesize; + + if ((hFile = CreateFile(filename, GENERIC_READ, 0, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0)) == INVALID_HANDLE_VALUE || + (filesize = GetFileSize(hFile, NULL)) == INVALID_FILE_SIZE) { + MessageBox(hDlg, "Could not get file size", "Error", 0); + }else{ + SetDlgItemInt(hDlg, + LOWORD(wParam)==IDC_BITRATE_SSELECT? IDC_BITRATE_SSIZE : IDC_BITRATE_ASIZE, + filesize / 1024, FALSE); + CloseHandle(hFile); + } + } + } + break; + case IDC_QUANTMATRIX : DialogBoxParam(g_hInst, MAKEINTRESOURCE(IDD_QUANTMATRIX), hDlg, quantmatrix_proc, (LPARAM)psi->config); break; @@ -1161,11 +1434,12 @@ ofn.Flags |= OFN_FILEMUSTEXIST; } - if (GetSaveFileName(&ofn)) - { + if ((psi->idd==IDD_RC_2PASS1 && GetSaveFileName(&ofn)) || + (psi->idd==IDD_RC_2PASS2 && GetOpenFileName(&ofn))) { SetDlgItemText(hDlg, IDC_STATS, tmp); } - } + } + break; case IDC_ZONE_FETCH : SetDlgItemInt(hDlg, IDC_ZONE_FRAME, psi->config->ci.ciActiveFrame, FALSE); @@ -1198,24 +1472,39 @@ default : return TRUE; } + }else if ((HIWORD(wParam) == CBN_EDITCHANGE || HIWORD(wParam)==CBN_SELCHANGE) && + (LOWORD(wParam)==IDC_BITRATE_TSIZE || + LOWORD(wParam)==IDC_BITRATE_ARATE )) { + adv_mode(hDlg, psi->idd, psi->config); }else if (HIWORD(wParam) == LBN_SELCHANGE && (LOWORD(wParam) == IDC_PROFILE_PROFILE || LOWORD(wParam) == IDC_LEVEL_PROFILE || LOWORD(wParam) == IDC_QUANTTYPE || - LOWORD(wParam) == IDC_ASPECT_RATIO)) - { + LOWORD(wParam) == IDC_ASPECT_RATIO || + LOWORD(wParam) == IDC_BITRATE_CFORMAT || + LOWORD(wParam) == IDC_BITRATE_AFORMAT || + LOWORD(wParam) == IDC_BITRATE_FPS)) { adv_mode(hDlg, psi->idd, psi->config); }else if (HIWORD(wParam) == EN_UPDATE && (LOWORD(wParam)==IDC_ZONE_WEIGHT || LOWORD(wParam)==IDC_ZONE_QUANT)) { SendDlgItemMessage(hDlg, IDC_ZONE_SLIDER, TBM_SETPOS, TRUE, get_dlgitem_float(hDlg, LOWORD(wParam), 100)); + } else if (HIWORD(wParam) == EN_UPDATE && (LOWORD(wParam)==IDC_PARX || LOWORD(wParam)==IDC_PARY)) { + if (5 == SendDlgItemMessage(hDlg, IDC_ASPECT_RATIO, CB_GETCURSEL, 0, 0)) { if(LOWORD(wParam)==IDC_PARX) psi->config->par_x = config_get_uint(hDlg, LOWORD(wParam), psi->config->par_x); else psi->config->par_y = config_get_uint(hDlg, LOWORD(wParam), psi->config->par_y); } + } else if (HIWORD(wParam) == EN_UPDATE && + (LOWORD(wParam)==IDC_BITRATE_SSIZE || + LOWORD(wParam)==IDC_BITRATE_HOURS || + LOWORD(wParam)==IDC_BITRATE_MINUTES || + LOWORD(wParam)==IDC_BITRATE_SECONDS || + LOWORD(wParam)==IDC_BITRATE_ASIZE)) { + adv_mode(hDlg, psi->idd, psi->config); } else return 0; break; @@ -1268,7 +1557,7 @@ or fasle if changes were canceled. */ -BOOL adv_dialog(HWND hParent, CONFIG * config, const int * dlgs, int size) +static BOOL adv_dialog(HWND hParent, CONFIG * config, const int * dlgs, int size) { PROPSHEETINFO psi[6]; PROPSHEETPAGE psp[6]; @@ -1294,7 +1583,7 @@ } psh.dwSize = sizeof(PROPSHEETHEADER); - psh.dwFlags = PSH_PROPSHEETPAGE | PSH_NOAPPLYNOW; + psh.dwFlags = PSH_PROPSHEETPAGE | PSH_NOAPPLYNOW | PSH_NOCONTEXTHELP; psh.hwndParent = hParent; psh.hInstance = g_hInst; psh.pszCaption = (LPSTR) "XviD Configuration"; @@ -1315,7 +1604,7 @@ /* ===================================================================================== */ -void main_insert_zone(HWND hDlg, zone_t * s, int i, BOOL insert) +static void main_insert_zone(HWND hDlg, zone_t * s, int i, BOOL insert) { char tmp[32]; @@ -1359,7 +1648,8 @@ ListView_SetItemText(hDlg, i, 2, tmp); } -void main_mode(HWND hDlg, CONFIG * config) + +static void main_mode(HWND hDlg, CONFIG * config) { const int profile = SendDlgItemMessage(hDlg, IDC_PROFILE, CB_GETCURSEL, 0, 0); const int rc_mode = SendDlgItemMessage(hDlg, IDC_MODE, CB_GETCURSEL, 0, 0); @@ -1402,6 +1692,7 @@ EnableDlgWindow(hDlg, IDC_BITRATE_S, target_en); EnableDlgWindow(hDlg, IDC_BITRATE, target_en); + EnableDlgWindow(hDlg, IDC_BITRATE_ADV, target_en); EnableDlgWindow(hDlg, IDC_BITRATE_MIN, target_en_slider); EnableDlgWindow(hDlg, IDC_BITRATE_MAX, target_en_slider); @@ -1409,8 +1700,7 @@ } - -void main_upload(HWND hDlg, CONFIG * config) +static void main_upload(HWND hDlg, CONFIG * config) { SendDlgItemMessage(hDlg, IDC_PROFILE, CB_SETCURSEL, config->profile, 0); @@ -1426,11 +1716,12 @@ set_dlgitem_float(hDlg, IDC_BITRATE, config->desired_quant); } - zones_update(hDlg, config);} + zones_update(hDlg, config); +} /* downloads data from main dialog */ -void main_download(HWND hDlg, CONFIG * config) +static void main_download(HWND hDlg, CONFIG * config) { config->profile = SendDlgItemMessage(hDlg, IDC_PROFILE, CB_GETCURSEL, 0, 0); config->mode = SendDlgItemMessage(hDlg, IDC_MODE, CB_GETCURSEL, 0, 0); @@ -1451,6 +1742,7 @@ static const int single_dlgs[] = { IDD_RC_CBR }; static const int pass1_dlgs[] = { IDD_RC_2PASS1 }; static const int pass2_dlgs[] = { IDD_RC_2PASS2 }; +static const int bitrate_dlgs[] = { IDD_BITRATE }; static const int zone_dlgs[] = { IDD_ZONE }; static const int decoder_dlgs[] = { IDD_DEC }; static const int adv_dlgs[] = { IDD_MOTION, IDD_QUANT, IDD_DEBUG}; @@ -1576,7 +1868,6 @@ } break; - case IDC_BITRATE_S : /* alternate between bitrate/desired_length metrics */ main_download(hDlg, config); @@ -1585,6 +1876,13 @@ main_upload(hDlg, config); break; + case IDC_BITRATE_ADV : + main_download(hDlg, config); + adv_dialog(hDlg, config, bitrate_dlgs, sizeof(bitrate_dlgs)/sizeof(int)); + main_mode(hDlg, config); + main_upload(hDlg, config); + break; + case IDC_DECODER : main_download(hDlg, config); adv_dialog(hDlg, config, decoder_dlgs, sizeof(decoder_dlgs)/sizeof(int)); @@ -1819,6 +2117,7 @@ return 1; } + void sort_zones(zone_t * zones, int zone_num, int * sel) {