FramePatternDetector.cpp

00001 /*********************************************************************** 00002 * * 00003 * ViTooKi * 00004 * * 00005 * title: FramePatternDetector.cpp * 00006 * * 00007 * * 00008 * * 00009 * ITEC institute of the University of Klagenfurt (Austria) * 00010 * http://www.itec.uni-klu.ac.at * 00011 * * 00012 * * 00013 * For more information visit the ViTooKi homepage: * 00014 * http://ViTooKi.sourceforge.net * 00015 * vitooki-user@lists.sourceforge.net * 00016 * vitooki-devel@lists.sourceforge.net * 00017 * * 00018 * This file is part of ViTooKi, a free video toolkit. * 00019 * ViTooKi is free software; you can redistribute it and/or * 00020 * modify it under the terms of the GNU General Public License * 00021 * as published by the Free Software Foundation; either version 2 * 00022 * of the License, or (at your option) any later version. * 00023 * * 00024 * This program is distributed in the hope that it will be useful, * 00025 * but WITHOUT ANY WARRANTY; without even the implied warranty of * 00026 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 00027 * GNU General Public License for more details. * 00028 * * 00029 * You should have received a copy of the GNU General Public License * 00030 * along with this program; if not, write to the Free Software * 00031 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, * 00032 * MA 02111-1307, USA. * 00033 * * 00034 ***********************************************************************/ 00035 00036 /*********************************************************************** 00037 * * 00038 * REVISION HISTORY: * 00039 * * 00040 * * 00041 * * 00042 ***********************************************************************/ 00043 00044 #include "FramePatternDetector.hpp" 00045 00046 /* Constructor: @param updateEsInfoAtClose set to true if you want the adaptor to 00047 * automatically overwrite the values in @param esi, when the adaptor is closed (and at least one 00048 * complete GOP was analyzed!) 00049 */ 00050 FramePatternDetector::FramePatternDetector(VideoESInfo* esi, bool updateEsInfoAtClose) 00051 { 00052 strcpy(name,"FramePatternDetector"); 00053 memset(bFramesBetweenCounter,0,sizeof(int)*FRAMEPATTERNDETECTOR_MAX_BFRAMES_BETWEEN); 00054 memset(gopSizesDetected,0,sizeof(int)*FRAMEPATTERNDETECTOR_MAX_GOP_ANALYZE); 00055 00056 updateESInfo = updateEsInfoAtClose; 00057 es = esi; 00058 framesSinceIFrame=0; 00059 bFramesBetween=0; 00060 currentGOP=-1; 00061 staticGopSize=false; 00062 staticGopPattern=false; 00063 foundBFramesBetween=-1; 00064 foundGopSize=-1; 00065 lastCTSIFrame=0; 00066 stopBFrames=false; 00067 stopGOPSize=false; 00068 bFrameSize=0; 00069 totalVideoSize=0; 00070 }; 00071 00072 void FramePatternDetector::initialize() { 00073 } 00074 00075 FramePatternDetector::~FramePatternDetector() 00076 { 00077 } 00078 00079 list < Frame * > FramePatternDetector::adapt(Frame * frm) { 00080 assert(frm); 00081 list < Frame * >tmp; 00082 u32 thisCTS=0; 00083 00084 totalVideoSize+=frm->getAU()->size; 00085 if(frm->getAU()->frameType==Frame::B_VOP) 00086 bFrameSize+=frm->getAU()->size; 00087 //standard forwarding adaptor behaviour 00088 tmp.push_front(frm); 00089 if(currentGOP>=FRAMEPATTERNDETECTOR_MAX_GOP_ANALYZE) { 00090 // stop analyze 00091 return tmp; 00092 } 00093 00094 thisCTS = frm->getAU()->cts; 00095 00096 if(frm->getType() == Frame::I_VOP && currentGOP<0) { 00097 framesSinceIFrame=1; 00098 bFramesBetween=0; 00099 currentGOP=0; 00100 foundBFramesBetween=0; 00101 foundGopSize=0; 00102 lastCTSIFrame=frm->getAU()->cts; 00103 stopBFrames=false; 00104 } 00105 else { 00106 handleFrameType(frm->getType(),thisCTS); 00107 if(currentGOP>=FRAMEPATTERNDETECTOR_MAX_GOP_ANALYZE) 00108 detectGopSize(); 00109 } 00110 00111 return tmp; 00112 00113 } 00114 00115 void FramePatternDetector::handleFrameType(Frame::FrameType current,u32 ctsCur) { 00116 int expectedFrames=0; 00117 if(lastFrame==current) { 00118 if(lastFrame==Frame::B_VOP) { 00119 bFramesBetween++; 00120 } 00121 else if(lastFrame==Frame::P_VOP) { 00122 //two consecutive P 00123 bFramesBetweenCounter[0]++; 00124 } 00125 else if(lastFrame==Frame::I_VOP) { 00126 // two consec. I 00127 expectedFrames=(ctsCur-lastCTSIFrame)/es->getVOPTimeIncrement(); 00128 gopSizesDetected[currentGOP]=expectedFrames; 00129 if(foundGopSize==-1) { 00130 //calc cts value 00131 foundGopSize=expectedFrames; 00132 if(expectedFrames!=framesSinceIFrame) 00133 dprintf_small("FramePatternDetector::handleFrameType: expected %u frames per GOP, only got %u\n", 00134 expectedFrames,framesSinceIFrame); 00135 } 00136 framesSinceIFrame=1; 00137 lastCTSIFrame=ctsCur; 00138 analyzeBFramePattern(); 00139 currentGOP++; 00140 memset(bFramesBetweenCounter,0,sizeof(int)*FRAMEPATTERNDETECTOR_MAX_BFRAMES_BETWEEN); 00141 } 00142 } 00143 else if(current==Frame::B_VOP) { 00144 // last frame is not a B-frame, a new B-frame start! 00145 bFramesBetween=1; 00146 } 00147 else { 00148 // if we have an I or P frame, this always ends a bframepattern 00149 // except in the first GOP which has IPBB instead of IBBPBB 00150 if(ctsCur>es->getVOPTimeIncrement()) 00151 bFramesBetweenCounter[bFramesBetween]++; 00152 bFramesBetween=0; 00153 // if we have an I-frame we have to handle GOPsize additionaly 00154 if(current==Frame::I_VOP) { 00155 gopSizesDetected[currentGOP]=(ctsCur-lastCTSIFrame)/es->getVOPTimeIncrement(); 00156 if(gopSizesDetected[currentGOP]!=framesSinceIFrame) 00157 dprintf_small("FramePatternDetector::handleFrameType: expected %u frames per GOP, only got %u\n", 00158 expectedFrames,framesSinceIFrame); 00159 framesSinceIFrame=1; 00160 lastCTSIFrame=ctsCur; 00161 analyzeBFramePattern(); 00162 currentGOP++; 00163 memset(bFramesBetweenCounter,0,sizeof(int)*FRAMEPATTERNDETECTOR_MAX_BFRAMES_BETWEEN); 00164 } 00165 } 00166 lastFrame=current; 00167 } 00168 00169 void FramePatternDetector::analyzeBFramePattern() 00170 { 00171 if(stopBFrames) 00172 return; 00173 //search the maximum in the array 00174 int maxVal=bFramesBetweenCounter[0]; 00175 int sum=0; 00176 int maxIndex=0; 00177 for(int i=1;i<FRAMEPATTERNDETECTOR_MAX_BFRAMES_BETWEEN;i++) { 00178 sum+=bFramesBetweenCounter[i]; 00179 if(maxVal<bFramesBetweenCounter[i]) { 00180 maxIndex=i; 00181 maxVal=bFramesBetweenCounter[i]; 00182 } 00183 } 00184 if( ((double)maxVal)/sum>FRAMEPATTERNDETECTOR_BFRAME_THRESHOLD) { 00185 this->foundBFramesBetween=maxIndex; 00186 staticGopPattern=true; 00187 stopBFrames=true; 00188 } 00189 else 00190 staticGopPattern=false; 00191 } 00192 00193 void FramePatternDetector::detectGopSize() { 00194 if(stopGOPSize) 00195 return; 00196 if(currentGOP<=0) 00197 return; 00198 int* occurrence=new int[currentGOP]; 00199 int i=0,j=0; 00200 memset(occurrence,0,sizeof(int)*currentGOP); 00201 00202 // inefficient, who cares... 00203 for(i=0;i<currentGOP;i++) { 00204 for(j=0;j<currentGOP;j++){ 00205 if(gopSizesDetected[i]==gopSizesDetected[j]) 00206 occurrence[i]++; 00207 } 00208 } 00209 00210 int max=occurrence[0]; 00211 int maxpos=0; 00212 // search the maximum in occurrence 00213 for(i=1;i<currentGOP;i++) { 00214 if(occurrence[i]>max) { 00215 maxpos=i; 00216 max=occurrence[i]; 00217 } 00218 } 00219 if(FRAMEPATTERNDETECTOR_GOP_THRESHOLD < ((double)max)/currentGOP) { 00220 foundGopSize=gopSizesDetected[maxpos]; 00221 staticGopSize=true; 00222 } 00223 else 00224 staticGopSize=false; 00225 stopGOPSize=true; 00226 delete occurrence; 00227 } 00228 00229 list < Frame * > FramePatternDetector::close() { 00230 list < Frame * >tmp; 00231 if(!stopGOPSize) 00232 detectGopSize(); 00233 if(updateESInfo) { 00234 if(stopBFrames) 00235 es->setAvgBFrameSize( ((double)this->bFrameSize)/totalVideoSize); 00236 if(staticGopSize && foundGopSize>0 && stopGOPSize) 00237 es->setGOP_size(foundGopSize); 00238 if(staticGopPattern && foundBFramesBetween>=0 && stopBFrames) 00239 es->setNum_B_frames(foundBFramesBetween); 00240 es->setStaticFramePattern(staticGopPattern); 00241 } 00242 return tmp; 00243 }; 00244