📄 2pass.cpp.svn-base
字号:
/************************************************************************** * * XVID 2PASS CODE * codec * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * *************************************************************************/#include "stdafx.h"#include "2pass.h"#include "TencStats.h"#include "ffdshow_constants.h"#include "IffdshowBase.h"#include "IffdshowEnc.h"#include "TffPict.h"//================================= TxvidStats =================================TxvidStats::TxvidStats(const char_t *Iflnm,bool write):flnm(Iflnm){ ok=false; fw=NULL; if (!flnm || !flnm[0]) return; if (write) { fw=fopen(flnm,_l("wb")); if (!fw) return; int32_t version=-20; size_t len=fwrite(&version,1,4,fw); ok=(len==4); } else { FILE *f=fopen(flnm,_l("rb"));if (!f) return; int ver;fread(&ver,1,4,f);if (ver!=-20) {fclose(f);return;} fseek(f,0,SEEK_END); long flen=ftell(f); fseek(f,4,SEEK_SET); while (!feof(f)) { NNSTATS nns; size_t len=fread(&nns,1,sizeof(nns),f); if (len!=sizeof(NNSTATS)) break; stats.push_back(nns); } fclose(f); resetRead(); } ok=true; }TxvidStats::~TxvidStats(){ if (fw) fclose(fw);}size_t TxvidStats::size(void) const{ return stats.size();}void TxvidStats::resetRead(void){ pos=0;}bool TxvidStats::readNext(NNSTATS *nns){ if (pos<size()) { *nns=stats[pos++]; return true; } else return false; }const NNSTATS* TxvidStats::operator [](size_t i) const{ return (i<size())?&stats[i]:NULL;}TxvidStats::operator const NNSTATS* (void) const{ return stats.empty()?NULL:&*stats.begin();}size_t TxvidStats::write(const NNSTATS *nns){ stats.push_back(*nns); return flnm?fw?fwrite(nns,1,sizeof(NNSTATS),fw):0:sizeof(NNSTATS);}//================================= Txvid_2pass =================================int Txvid_2pass::codec_2pass_init(void){ int frames = 0, bframes = 0, pframes = 0, credits_frames = 0, i_frames = 0, recminbsize = 0, recminpsize = 0, recminisize = 0; int64_t bframe_total_ext = 0, pframe_total_ext = 0, pframe_total = 0, bframe_total = 0, i_total = 0, i_total_ext = 0, i_boost_total = 0, start = 0, end = 0, start_curved = 0, end_curved = 0; int64_t desired = (int64_t)config.desiredSize * 1024; double total1 = 0.0; double total2 = 0.0; double dbytes, dbytes2; /* ensure free() is called safely */ twopass.nns1_array = NULL; twopass.nns2_array = NULL; switch (config.mode) { case DLG_MODE_2PASS_1 : if (!statsWrite) statsWrite = ownStatsWrite=new TxvidStats(config.stats1flnm,true); if (!statsWrite->ok) { DEBUGERR(_l("2pass init error - couldn't write to stats1")); return ICERR_ERROR; } break; case DLG_MODE_2PASS_2_INT : case DLG_MODE_2PASS_2_EXT : if (!statsRead) statsRead = ownStatsRead=new TxvidStats(config.stats1flnm,false); if (!statsRead->ok) { DEBUGERR(_l("2pass init error - couldn't open stats1")); return ICERR_ERROR; } twopass.nns_array_length = 0; twopass.nns_array_pos = 0; // read the stats file(s) into array(s) and reorder them so they // correctly represent the frames that the encoder will receive. if (config.mode == DLG_MODE_2PASS_2_EXT) { if (!statsRead2) statsRead2=ownStatsRead2 = new TxvidStats(config.stats2flnm,false); if (!statsRead2->ok) { DEBUGERR(_l("2pass init error - couldn't open stats2")); return ICERR_ERROR; } twopass.nns1_array =*statsRead; twopass.nns2_array =*statsRead2; frames=(int)std::min(statsRead->size(),statsRead2->size()); } else // DLG_MODE_2PASS_2_INT { twopass.nns1_array=*statsRead; frames=(int)statsRead->size(); } if (config.xvid2pass_use_write && !statsWrite) statsWrite=ownStatsWrite=new TxvidStats(config.stats1flnm,true); twopass.nns_array_length = frames; frames = 0;/* // this isn't necessary with the current core. // reorder the array(s) so they are in the order that they were received // IPBBPBB to // IBBPBBP for (i=0; i<twopass.nns_array_length; i++) { NNSTATS temp_nns, temp_nns2; int k, num_bframes; if (twopass.nns1_array[i].dd_v & NNSTATS_BFRAME) { num_bframes = 1; for (k=i+1; k<twopass.nns_array_length; k++) { if (twopass.nns1_array[k].dd_v & NNSTATS_BFRAME) num_bframes++; else k=twopass.nns_array_length; } i--; memcpy (&temp_nns, &twopass.nns1_array[i], sizeof(NNSTATS)); if (config.mode == DLG_MODE_2PASS_2_EXT) memcpy (&temp_nns2, &twopass.nns2_array[i], sizeof(NNSTATS)); for (k=0; k<num_bframes; k++) { memcpy(&twopass.nns1_array[i], &twopass.nns1_array[i+1], sizeof(NNSTATS)); if (config.mode == DLG_MODE_2PASS_2_EXT) memcpy(&twopass.nns2_array[i], &twopass.nns2_array[i+1], sizeof(NNSTATS)); i++; } memcpy(&twopass.nns1_array[i], &temp_nns, sizeof(NNSTATS)); if (config.mode == DLG_MODE_2PASS_2_EXT) memcpy(&twopass.nns2_array[i], &temp_nns2, sizeof(NNSTATS)); } }*/ // continue with the initialization.. if (config.mode == DLG_MODE_2PASS_2_EXT) { while (1) { if (twopass.nns_array_pos >= twopass.nns_array_length) { twopass.nns_array_pos = 0; break; } memcpy(&twopass.nns1, &twopass.nns1_array[twopass.nns_array_pos], sizeof(NNSTATS)); memcpy(&twopass.nns2, &twopass.nns2_array[twopass.nns_array_pos], sizeof(NNSTATS)); twopass.nns_array_pos++; // skip unnecessary frames. if (twopass.nns1.dd_v & NNSTATS_SKIPFRAME || twopass.nns1.dd_v & NNSTATS_PADFRAME || twopass.nns1.dd_v & NNSTATS_DELAYFRAME) continue; if (!codec_is_in_credits(frames)) { if (twopass.nns1.quant & NNSTATS_KEYFRAME) { i_total += twopass.nns2.bytes; i_boost_total += twopass.nns2.bytes * config.keyframe_boost / 100; twopass.keyframe_locations[i_frames] = frames; ++i_frames; } else { if (twopass.nns1.dd_v & NNSTATS_BFRAME) { bframe_total += twopass.nns1.bytes; bframe_total_ext += twopass.nns2.bytes; bframes++; } else { pframe_total += twopass.nns1.bytes; pframe_total_ext += twopass.nns2.bytes; pframes++; } } } else ++credits_frames; if (twopass.nns1.quant & NNSTATS_KEYFRAME) { // this test needs to be corrected.. if (!(twopass.nns1.kblk + twopass.nns1.mblk)) recminisize = twopass.nns1.bytes; } else if (twopass.nns1.dd_v & NNSTATS_BFRAME) { if (!(twopass.nns1.kblk + twopass.nns1.mblk)) recminbsize = twopass.nns1.bytes; } else { if (!(twopass.nns1.kblk + twopass.nns1.mblk)) recminpsize = twopass.nns1.bytes; } ++frames; } twopass.keyframe_locations[i_frames] = frames; twopass.movie_curve = ((double)(bframe_total_ext + pframe_total_ext + i_boost_total) / (bframe_total_ext + pframe_total_ext)); if (bframes) twopass.average_bframe = (double)bframe_total_ext / bframes / twopass.movie_curve; if (pframes) twopass.average_pframe = (double)pframe_total_ext / pframes / twopass.movie_curve; else if (bframes) twopass.average_pframe = twopass.average_bframe; // b-frame packed bitstream fix else { DEBUGERR(_l("ERROR: No p-frames or b-frames were present in the 1st pass. Rate control cannot function properly!")); return ICERR_ERROR; } // perform prepass to compensate for over/undersizing frames = 0; if (config.use_alt_curve) { twopass.alt_curve_low = twopass.average_pframe - twopass.average_pframe * (double)config.alt_curve_low_dist / 100.0; twopass.alt_curve_low_diff = twopass.average_pframe - twopass.alt_curve_low; twopass.alt_curve_high = twopass.average_pframe + twopass.average_pframe * (double)config.alt_curve_high_dist / 100.0; twopass.alt_curve_high_diff = twopass.alt_curve_high - twopass.average_pframe; if (config.alt_curve_use_auto) { if (bframe_total + pframe_total > bframe_total_ext + pframe_total_ext) { config.alt_curve_min_rel_qual = (int)(100.0 - (100.0 - 100.0 / ((double)(bframe_total + pframe_total) / (double)(bframe_total_ext + pframe_total_ext))) * (double)config.alt_curve_auto_str / 100.0); if (config.alt_curve_min_rel_qual < 20) config.alt_curve_min_rel_qual = 20; } else config.alt_curve_min_rel_qual = 100; } twopass.alt_curve_mid_qual = (1.0 + (double)config.alt_curve_min_rel_qual / 100.0) / 2.0; twopass.alt_curve_qual_dev = 1.0 - twopass.alt_curve_mid_qual; if (config.alt_curve_low_dist > 100) { switch(config.alt_curve_type) { case 2: // Sine Curve (high aggressiveness) twopass.alt_curve_qual_dev *= 2.0 / (1.0 + sin(DEG2RAD * (twopass.average_pframe * 90.0 / twopass.alt_curve_low_diff))); twopass.alt_curve_mid_qual = 1.0 - twopass.alt_curve_qual_dev * sin(DEG2RAD * (twopass.average_pframe * 90.0 / twopass.alt_curve_low_diff)); break; case 1: // Linear (medium aggressiveness) twopass.alt_curve_qual_dev *= 2.0 / (1.0 + twopass.average_pframe / twopass.alt_curve_low_diff); twopass.alt_curve_mid_qual = 1.0 - twopass.alt_curve_qual_dev * twopass.average_pframe / twopass.alt_curve_low_diff; break; case 0: // Cosine Curve (low aggressiveness) twopass.alt_curve_qual_dev *= 2.0 / (1.0 + (1.0 - cos(DEG2RAD * (twopass.average_pframe * 90.0 / twopass.alt_curve_low_diff)))); twopass.alt_curve_mid_qual = 1.0 - twopass.alt_curve_qual_dev * (1.0 - cos(DEG2RAD * (twopass.average_pframe * 90.0 / twopass.alt_curve_low_diff))); } } } while (1) { if (twopass.nns_array_pos >= twopass.nns_array_length) { twopass.nns_array_pos = 0; break; } memcpy(&twopass.nns1, &twopass.nns1_array[twopass.nns_array_pos], sizeof(NNSTATS)); memcpy(&twopass.nns2, &twopass.nns2_array[twopass.nns_array_pos], sizeof(NNSTATS)); twopass.nns_array_pos++; if (frames == 0) { twopass.minbsize = (twopass.nns1.kblk + 88) / 8; twopass.minpsize = (twopass.nns1.kblk + 88) / 8; twopass.minisize = ((twopass.nns1.kblk * 22) + 240) / 8; if (recminbsize > twopass.minbsize) twopass.minbsize = recminbsize; if (recminpsize > twopass.minpsize) twopass.minpsize = recminpsize; if (recminisize > twopass.minisize) twopass.minisize = recminisize; } // skip unnecessary frames. if (twopass.nns1.dd_v & NNSTATS_SKIPFRAME || twopass.nns1.dd_v & NNSTATS_PADFRAME || twopass.nns1.dd_v & NNSTATS_DELAYFRAME) continue; if (!codec_is_in_credits( frames) && !(twopass.nns1.quant & NNSTATS_KEYFRAME)) { dbytes = twopass.nns2.bytes / twopass.movie_curve; total1 += dbytes; if (twopass.nns1.dd_v & NNSTATS_BFRAME) dbytes *= twopass.average_pframe / twopass.average_bframe; if (config.use_alt_curve) { if (dbytes > twopass.average_pframe) { if (dbytes >= twopass.alt_curve_high) dbytes2 = dbytes * (twopass.alt_curve_mid_qual - twopass.alt_curve_qual_dev); else { switch(config.alt_curve_type) { case 2: dbytes2 = dbytes * (twopass.alt_curve_mid_qual - twopass.alt_curve_qual_dev * sin(DEG2RAD * ((dbytes - twopass.average_pframe) * 90.0 / twopass.alt_curve_high_diff))); break; case 1: dbytes2 = dbytes * (twopass.alt_curve_mid_qual - twopass.alt_curve_qual_dev * (dbytes - twopass.average_pframe) / twopass.alt_curve_high_diff); break; case 0: dbytes2 = dbytes * (twopass.alt_curve_mid_qual - twopass.alt_curve_qual_dev * (1.0 - cos(DEG2RAD * ((dbytes - twopass.average_pframe) * 90.0 / twopass.alt_curve_high_diff)))); } } } else { if (dbytes <= twopass.alt_curve_low) dbytes2 = dbytes; else { switch(config.alt_curve_type) { case 2: dbytes2 = dbytes * (twopass.alt_curve_mid_qual - twopass.alt_curve_qual_dev * sin(DEG2RAD * ((dbytes - twopass.average_pframe) * 90.0 / twopass.alt_curve_low_diff)));
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -