00001 //=========================================================================== 00002 //Copyright (C) 2003, 2004 Zentaro Kavanagh 00003 // 00004 //Redistribution and use in source and binary forms, with or without 00005 //modification, are permitted provided that the following conditions 00006 //are met: 00007 // 00008 //- Redistributions of source code must retain the above copyright 00009 // notice, this list of conditions and the following disclaimer. 00010 // 00011 //- Redistributions in binary form must reproduce the above copyright 00012 // notice, this list of conditions and the following disclaimer in the 00013 // documentation and/or other materials provided with the distribution. 00014 // 00015 //- Neither the name of Zentaro Kavanagh nor the names of contributors 00016 // may be used to endorse or promote products derived from this software 00017 // without specific prior written permission. 00018 // 00019 //THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 00020 //``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 00021 //LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 00022 //PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE ORGANISATION OR 00023 //CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 00024 //EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 00025 //PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 00026 //PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 00027 //LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 00028 //NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 00029 //SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 00030 //=========================================================================== 00031 #include "stdafx.h" 00032 #include <libOOOgg/OggPageInterleaver.h> 00033 00034 OggPageInterleaver::OggPageInterleaver(IOggCallback* inFileWriter, INotifyComplete* inNotifier) 00035 : mFileWriter(inFileWriter) 00036 , mNotifier(inNotifier) 00037 , mProgressTime(0) 00038 , mBytesWritten(0) 00039 { 00040 #ifdef OGGCODECS_LOGGING 00041 debugLog.open("G:\\logs\\interleaver.log", ios_base::out); 00042 #endif 00043 } 00044 00045 OggPageInterleaver::~OggPageInterleaver(void) 00046 { 00047 #ifdef OGGCODECS_LOGGING 00048 debugLog.close(); 00049 #endif 00050 00051 00052 //Need to delete stream objects 00053 } 00054 00055 OggMuxStream* OggPageInterleaver::newStream() { 00056 OggMuxStream* retStream = new OggMuxStream(this); 00057 mInputStreams.push_back(retStream); 00058 return retStream; 00059 } 00060 00061 void OggPageInterleaver::notifyArrival() { 00062 #ifdef OGGCODECS_LOGGING 00063 debugLog<<endl; 00064 debugLog<<"notifyArrival : "<<endl; 00065 #endif 00066 processData(); 00067 } 00068 void OggPageInterleaver::processData() { 00069 /* 00070 IF ALL EOS THEN 00071 FINSH UP 00072 SIGNAL END OF STREAMS 00073 ELSE 00074 WHILE IS PROCESSABLE 00075 lowestStream = NULL 00076 FOR EACH stream in mInputStreams 00077 IF NOT stream IS EMPTY THEN 00078 IF lowestStream = NULL THEN 00079 lowestStream = stream 00080 ELSE IF stream.frontTime < lowestStream.frontTime THEN 00081 lowestStream = stream 00082 END IF 00083 END IF 00084 NEXT stream 00085 IF lowestStream = NULL THEN 00086 CURSE LOUDLY 00087 ELSE 00088 WRITE lowestStream.frontPage 00089 END IF 00090 WEND 00091 END IF 00092 */ 00093 // 00094 //Temp 00095 #ifdef OGGCODECS_LOGGING 00096 debugLog<<endl; 00097 debugLog<<"ProcessData : "<<endl; 00098 #endif 00099 00100 if (isAllEOS()) { 00101 //debugLog<<"ProcessData : All Streams EOS."<<endl; 00102 00103 //Finish up 00104 while (!isAllEmpty()) { 00105 //debugLog<<"ProcessData : All Streams EOS : Flushing."<<endl; 00106 writeLowest(); 00107 } 00108 //debugLog<<"ProcessData : All Streams EOS : Notify complete."<<endl; 00109 mNotifier->NotifyComplete(); 00110 } else { 00111 //debugLog<<"ProcessData : All Streams *NOT* EOS."<<endl; 00112 while (isProcessable()) { 00113 //debugLog<<"ProcessData : Writing lowest"<<endl; 00114 writeLowest(); 00115 } 00116 //debugLog<<"ProcessData : No more processable data"<<endl; 00117 if (isAllEOS() && isAllEmpty()) { 00118 //debugLog<<"ProcessData : All EOS and all Empty... Notifying complete..."<<endl; 00119 mNotifier->NotifyComplete(); 00120 } 00121 } 00122 //debugLog<<"==============="<<endl; 00123 00124 } 00125 00126 00127 00128 void OggPageInterleaver::writeLowest() { 00129 OggMuxStream* locLowestStream = NULL; 00130 for (size_t i = 0; i < mInputStreams.size(); i++) { 00131 if (!mInputStreams[i]->isEmpty() && mInputStreams[i]->isActive()) { 00132 if (locLowestStream == NULL) { 00133 if (mInputStreams[i]->peekFront() == NULL) { 00134 int x = 0; 00135 x= x/x; 00136 } 00137 locLowestStream = mInputStreams[i]; 00138 //debugLog<<"writeLowest : Defaulting stream "<<i<<" @ Gran = "<<locLowestStream->frontTime()<<" & Time = "<<locLowestStream->scaledFrontTime()<<endl; 00139 //debugLog<<"writeLowest : Defaulting stream "<<i<<endl; 00140 } else { 00141 LOOG_INT64 locCurrLowTime = locLowestStream->scaledFrontTime(); 00142 LOOG_INT64 locTestLowTime = mInputStreams[i]->scaledFrontTime(); 00143 00144 //debuging 00145 //LOOG_INT64 locCurrLowTimeUNS = locLowestStream->frontTime(); 00146 //LOOG_INT64 locTestLowTimeUNS = mInputStreams[i]->frontTime(); 00147 //debugging end 00148 00149 //debugLog<<"writeLowest : Scaled : Curr = "<<locCurrLowTime<<" -- Test["<<(unsigned long)i<<"] = "<<locTestLowTime<<endl; 00150 //debugLog<<"writeLowest : UNSCAL : Curr = "<<locCurrLowTimeUNS<<" -- Test["<<(unsigned long)i<<"] = "<<locTestLowTimeUNS<<endl; 00151 00152 00153 //ASSERT (all header packets have granule pos 0) 00154 // 00155 00156 //In english this means... any bos pages go first... then any no gran pos pages (-1 gran pos).. 00157 // then any remaining streams with headers then whoevers got the lowest time. 00158 if ( 00159 //Precedence goes to BOS pages. 00160 ( (mInputStreams[i]->peekFront() != NULL) && 00161 (mInputStreams[i]->peekFront()->header()->isBOS()) ) || 00162 00163 ( (mInputStreams[i]->peekFront() != NULL) && 00164 ((mInputStreams[i]->peekFront()->header()->GranulePos()) == -1) ) || 00165 00166 //If the tested page hasn't sent all it's headers and the current one either 00167 // a) Has already sent all it's pages OR 00168 // b) Has sent more than the test page 00169 ( (mInputStreams[i]->peekFront() != NULL) && 00170 (!mInputStreams[i]->sentAllHeaders()) && 00171 //(!locLowestStream->peekFront()->header()->isBOS()) ) || 00172 ((locLowestStream->sentAllHeaders()) || 00173 (mInputStreams[i]->packetsSent() < locLowestStream->packetsSent())) ) || 00174 00175 ( 00176 (locTestLowTime < locCurrLowTime)) 00177 ) 00178 { 00179 00180 //DeBUGGIN BLOCK 00181 if ( (mInputStreams[i]->peekFront() != NULL) && 00182 (mInputStreams[i]->peekFront()->header()->isBOS()) ) { 00183 //debugLog<<"WriteLowest : Selecting because BOS"<<endl; 00184 } 00185 if ( (mInputStreams[i]->peekFront() != NULL) && 00186 ((mInputStreams[i]->peekFront()->header()->GranulePos()) == -1) ) { 00187 //debugLog<<"WriteLowest : Selecting because gran pos = -1"<<endl; 00188 } 00189 00190 if ((mInputStreams[i]->peekFront() != NULL) && 00191 (!mInputStreams[i]->sentAllHeaders()) && 00192 (mInputStreams[i]->packetsSent() < locLowestStream->packetsSent()) ) { 00193 00194 //debugLog<<"WriteLowest : Selecting because hasn't sent all headers"<<endl; 00195 } 00196 00197 if (locTestLowTime < locCurrLowTime) { 00198 00199 //debugLog<<"WriteLowest : Selecting because test time "<<locTestLowTime<<" less than "<<locCurrLowTime<<endl; 00200 } 00201 //END BEBUGGING BLOCK 00202 locLowestStream = mInputStreams[i]; 00203 //debugLog<<"writeLowest : Selecting stream "<<(unsigned long)i<<" @ Gran = "<<locLowestStream->frontTime()<<" & Time = "<<locLowestStream->scaledFrontTime()<<endl; 00204 } 00205 } 00206 } 00207 } 00208 if (locLowestStream == NULL) { 00209 throw 0; 00210 } else { 00211 //debugLog<<"writeLowest : Writing..."<<endl; 00212 if (locLowestStream->scaledFrontTime() != -1) { 00213 mProgressTime = locLowestStream->scaledFrontTime(); 00214 } 00215 00216 //debugLog<<"writeLowest : Progress Time = "<<mProgressTime<<endl; 00217 00218 OggPage* locPageToWrite = locLowestStream->popFront(); 00219 mBytesWritten += locPageToWrite->pageSize(); 00220 //TODO::: Handle case where the popped page is a null pointer. Can it even happen ?? There should never be a null pointer. 00221 mFileWriter->acceptOggPage(locPageToWrite); //Gives away page 00222 } 00223 00224 } 00225 00226 LOOG_INT64 OggPageInterleaver::progressTime() 00227 { 00228 return mProgressTime; 00229 } 00230 00231 LOOG_INT64 OggPageInterleaver::bytesWritten() 00232 { 00233 return mBytesWritten; 00234 } 00235 bool OggPageInterleaver::isProcessable() { 00236 bool retVal = true; 00237 //ASSERT(mInputStreams.size() >= 1) 00238 for (size_t i = 0; i < mInputStreams.size(); i++) { 00239 retVal = retVal && (mInputStreams[i]->isProcessable()); 00240 } 00241 //if (retVal) { 00242 // debugLog<<"isPRocessable : TRUE"<<endl; 00243 //} else { 00244 // debugLog<<"isPRocessable : FALSE"<<endl; 00245 //} 00246 return retVal; 00247 } 00248 bool OggPageInterleaver::isAllEOS() { 00249 bool retVal = true; 00250 //ASSERT(mInputStreams.size() >= 1) 00251 for (size_t i = 0; i < mInputStreams.size(); i++) { 00252 //if (mInputStreams[i]->isEOS()) { 00253 // debugLog<<"isAllEOS : ***** Stream "<<(unsigned long)i<<" is EOS"<<endl; 00254 //} else { 00255 // debugLog<<"isAllEOS : ***** Stream "<<(unsigned long)i<<" not EOS"<<endl; 00256 //} 00257 retVal = retVal && (mInputStreams[i]->isEOS() || !mInputStreams[i]->isActive()); 00258 } 00259 //if (retVal) { 00260 // debugLog<<"isAllEOS : TRUE"<<endl; 00261 //} else { 00262 // debugLog<<"isAllEOS : FALSE"<<endl; 00263 //} 00264 return retVal; 00265 } 00266 00267 bool OggPageInterleaver::isAllEmpty() { 00268 bool retVal = true; 00269 //ASSERT(mInputStreams.size() >= 1) 00270 for (size_t i = 0; i < mInputStreams.size(); i++) { 00271 retVal = retVal && (mInputStreams[i]->isEmpty()); 00272 } 00273 return retVal; 00274 }