MP7File.cpp

00001 /*********************************************************************** 00002 * * 00003 * ViTooKi * 00004 * * 00005 * title: MP7File.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 "MP7File.hpp" 00045 #include "ContainerInfo.hpp" 00046 #include "VideoESInfo.hpp" 00047 #include "AdaptorChain.hpp" 00048 00049 #include "../container/ISOMP4ContainerFile.hpp" 00050 #include "../container/ContainerDemux.hpp" 00051 00052 #include "../adaptors/Forwarder.hpp" 00053 #include "../adaptors/SpatialReductionAdaptor.hpp" 00054 #include "../net/Url.hpp" 00055 00056 const char *const 00057 MP7File::NL = "\r\n"; 00058 const char *const 00059 MP7File::content = "Content"; 00060 const char *const 00061 MP7File::name = "Name"; 00062 const char *const 00063 MP7File::fileFormat = "FileFormat"; 00064 const char *const 00065 MP7File::variationSet = "VariationSet"; 00066 const char *const 00067 MP7File::fileSize = "FileSize"; 00068 const char *const 00069 MP7File::mediaProfile = "MediaProfile"; 00070 const char *const 00071 MP7File::componentMediaProfile = "ComponentMediaProfile"; 00072 const char *const 00073 MP7File::bitRate = "BitRate"; 00074 const char *const 00075 MP7File::mediaLocator = "MediaLocator"; 00076 const char *const 00077 MP7File::preHeader = 00078 "<?xml version=\"1.0\" encoding=\"iso-8859-1\"?>%s<Mpeg7 xmlns=\"urn:mpeg:mpeg7:schema:2001\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:mpeg7=\"urn:mpeg:mpeg7:schema:2001\" xsi:schemaLocation=\"urn:mpeg:mpeg7:schema:2001 definitions2.xsd\">%s\t<Description xsi:type=\"VariationDescriptionType\">%s"; 00079 const char *const 00080 MP7File::closeHeader = "\t</Description>%s</Mpeg7>%s"; 00081 00088 char *MP7File::generateMP7Description(ContainerInfo * mp4Info, 00089 char *mp7File, bool showVisualResult) 00090 { 00091 00092 FILE *fp = MP7File::openMP7File(mp7File); 00093 if (!fp) 00094 return NULL; 00095 00097 ContainerDemux::demultiplexAndUpdateIO(mp4Info,"."); 00098 00099 ContainerInfo *clone = mp4Info->clone(); 00100 VideoESInfo *esi = clone->getFirstVisualES(); 00101 unsigned int w = esi->getWidth() / 2; 00102 unsigned int h = esi->getHeight() / 2; 00103 Adaptor **adaptors = new Adaptor *[3]; 00104 adaptors[0] = new Forwarder(); 00105 adaptors[1] = new TemporalAdaptor(); 00106 adaptors[2] = new StrongTemporalAdaptor(); 00107 MP7File::writeVariationSet(fp, adaptors, 3, clone, showVisualResult); 00108 delete clone; 00109 delete adaptors[0]; 00110 delete adaptors[1]; 00111 delete adaptors[2]; 00112 delete adaptors; 00113 00114 clone = mp4Info->clone(); 00115 esi = clone->getFirstVisualES(); 00116 adaptors = new Adaptor *[1]; 00117 adaptors[0] = 00118 new SpatialReductionAdaptor(esi, &w, &h, 00119 esi->getAvgBandwidth() / 4); 00120 MP7File::writeVariationSet(fp, adaptors, 1, clone, showVisualResult); 00121 delete clone; 00122 delete adaptors[0]; 00123 delete adaptors; 00124 00125 00126 MP7File::closeMP7File(fp); 00127 00128 return mp7File; 00129 }; 00130 00131 00132 FILE *MP7File::openMP7File(const char *mp7File) 00133 { 00134 FILE *fp = fopen(mp7File, "wb"); 00135 if (!fp) 00136 return NULL; 00137 fprintf(fp, preHeader, NL, NL, NL); 00138 return fp; 00139 }; 00140 00142 bool MP7File::closeMP7File(FILE * fp) 00143 { 00144 if (!fp) 00145 return false; 00146 fprintf(fp, closeHeader, NL, NL); 00147 fclose(fp); 00148 return true; 00149 } 00150 00151 bool MP7File::writeVariationSet(FILE * fp, Adaptor ** adaptors, 00152 int numAdaptors, ContainerInfo * mp4Info, 00153 bool showVisualResult) 00154 { 00155 MP7File::writeEntry(fp, 2, variationSet, false); 00156 MP7File::writeEntry(fp, 3, "Source xsi:type=\"VideoType\"", false); 00157 MP7File::writeEntry(fp, 4, "Video id=\"SourceVideo\"", false); 00158 MP7File::writeMediaInformation(fp, 5,mp4Info); 00159 MP7File::writeEntry(fp, 4, "Video", true); 00160 MP7File::writeEntry(fp, 3, "Source", true); 00161 char *adaptorName = new char[MAX_STR_LEN]; 00162 dprintf_full("MP7File::writeVariationSet Doing %i adaptations\r\n",numAdaptors); 00163 // description of the video is finished 00164 // now do the Variation description 00165 float fidelity = 1.0; // FIXME: calculate fidelity 00166 for (int i = 0; i < numAdaptors; i++) { 00167 strcpy(adaptorName,adaptors[i]->getName()); 00168 dprintf_full("MP7File::writeVariationSet Doing %s\r\n", adaptors[i]->getName()); 00169 if (showVisualResult) { 00170 ContainerDemux::demultiplexAndUpdateIO(mp4Info, ".", adaptors[i], false, 00171 false, true); 00172 } else 00173 ContainerDemux::demultiplexAndUpdateIO(mp4Info, ".", adaptors[i], false, 00174 false, false); 00175 00176 fidelity -= (float) (1.0 / (numAdaptors + 1)); // FIXME 00177 MP7File::writeAdaptation(fp, 3, mp4Info, adaptorName, i + 1, i + 1, 00178 fidelity); 00179 } 00180 00181 MP7File::writeEntry(fp, 2, variationSet, true); 00182 00183 delete [] adaptorName; 00184 return true; 00185 }; 00186 00187 u32 MP7File::writeMediaInformation(FILE * fp, u32 indent, 00188 ContainerInfo * mp4Info) 00189 { 00190 MP7File::writeEntry(fp, indent, "MediaInformation", false); 00191 MP7File::writeEntry(fp, indent + 1, mediaProfile, false); 00192 00193 // write for each ES a ComponentMediaProfile entry 00194 list < ESInfo * >*l = mp4Info->getESList(); 00195 list < ESInfo * >::iterator li = l->begin(); 00196 u64 totalSize = 0; 00197 u32 maxDurInMs = 1; 00198 while (li != l->end()) { 00199 totalSize += MP7File::writeCMP(fp, indent + 2, (*li)); 00200 if (maxDurInMs < (*li)->getDurationInMs()) 00201 maxDurInMs = (*li)->getDurationInMs(); 00202 ++li; 00203 } 00204 // now write the info for the complete mp4 stream 00205 MP7File::writeEntry(fp, indent + 2, "MediaFormat", false); 00206 00207 MP7File::writeEntry(fp, indent + 3, "Content href=\"MPEG7ContentCS\"", 00208 false); 00209 MP7File::writeEntry(fp, indent + 4, "Name>audiovisual</Name", false); 00210 MP7File::writeEntry(fp, indent + 3, "Content", true); 00211 00212 MP7File::writeEntry(fp, indent + 3, 00213 "FileFormat href=\"urn:mpeg:mpeg7:cs:FileFormatCS:2001:5\"", 00214 false); 00215 MP7File::writeEntry(fp, indent + 4, "Name xml:lang=\"en\">mp4</Name", 00216 false); 00217 MP7File::writeEntry(fp, indent + 3, fileFormat, true); 00218 00219 // now write the filesize & bitrate of the complete stream 00220 MP7File::writeVideoDescriptionEntry(fp, indent + 3, fileSize, 00221 totalSize); 00222 MP7File::writeVideoDescriptionEntry(fp, indent + 3, bitRate, 00223 ((8000 * totalSize) / maxDurInMs)); 00224 // debug info 00225 // MP7File::writeVideoDescriptionEntry(fp,indent+3,"DEBUG durationInMs", maxDurInMs); 00226 00227 MP7File::writeEntry(fp, indent + 2, "MediaFormat", true); 00228 00229 // now write MediaInstance 00230 MP7File::writeEntry(fp, indent + 2, "MediaInstance", false); 00231 MP7File::writeEntry(fp, indent + 3, 00232 "InstanceIdentifier organization=\"MPEG\" type=\"MPEG7ContentSetOnLineId\"> mpeg7 </InstanceIdentifier", 00233 false); 00234 MP7File::writeEntry(fp, indent + 3, mediaLocator, false); 00235 const char* u=mp4Info->getLocalFile(); 00236 MP7File::writeVideoDescriptionEntry(fp, indent + 4, "MediaUri", 00237 u); 00238 MP7File::writeEntry(fp, indent + 3, mediaLocator, true); 00239 MP7File::writeEntry(fp, indent + 2, "MediaInstance", true); 00240 00241 MP7File::writeEntry(fp, indent + 1, mediaProfile, true); 00242 MP7File::writeEntry(fp, indent, "MediaInformation", true); 00243 return totalSize; 00244 }; 00245 00250 bool MP7File::setAdaptors(ContainerInfo * mp4Info, char *mp7File) 00251 { 00252 return false; 00253 }; 00254 00259 bool MP7File::convertMetaInfoToMP7(const ContainerInfo * mp4Info, 00260 char *mp7File) 00261 { 00262 return false; 00263 }; 00264 00266 void MP7File::writeSimpleEntry(FILE * fp, u32 indent, 00267 const char *const key) 00268 { 00269 for (u32 i = 0; i < indent; i++) { 00270 fputc((int) '\t', fp); 00271 } 00272 fprintf(fp, "<%s/>%s", key, NL); 00273 } 00274 00275 void MP7File::writeEntry(FILE * fp, u32 indent, const char *const key, 00276 bool close) 00277 { 00278 for (u32 i = 0; i < indent; i++) { 00279 fputc((int) '\t', fp); 00280 } 00281 if (close) 00282 fprintf(fp, "</%s>%s", key, NL); 00283 else 00284 fprintf(fp, "<%s>%s", key, NL); 00285 }; 00286 00287 u32 MP7File::writeCMP(FILE * fp, u32 indent, ESInfo * es) 00288 { 00289 char *temp = new char[4096]; 00290 temp[0] = 0; 00291 sprintf(temp, "ComponentMediaProfile id=\"ES%llu\"", es->getStreamId()); 00292 MP7File::writeEntry(fp, indent, temp, false); 00293 MP7File::writeEntry(fp, indent + 1, "MediaFormat", false); 00294 00295 // write content 00296 MP7File::writeEntry(fp, indent + 2, "Content href=\"MPEG7ContentCS\"", 00297 false); 00298 00299 temp[0] = 0; 00300 if (es->isVisualStream()) { 00301 MP7File::writeEntry(fp, indent + 3, "Name>visual</Name", false); 00302 MP7File::writeEntry(fp, indent + 2, "Content", true); 00303 //write fileformat 00304 //<VisualCoding> 00305 // <Format href="urn:mpeg:mpeg7:cs:VisualCodingFormatCS:2001:1" colorDomain="color"/> 00306 // <Frame height="240" rate="" width="320"/> 00307 //</VisualCoding> 00308 MP7File::writeEntry(fp, indent + 2, "VisualCoding", false); 00309 MP7File::writeSimpleEntry(fp, indent + 3, 00310 "Format href=\"urn:mpeg:mpeg7:cs:VisualCodingFormatCS:2001:3\""); 00311 MP7File::writeEntry(fp, indent + 3, 00312 "Name xml:lang=\"en\">MPEG-4 Visual</Name", 00313 false); 00314 sprintf(temp, "Frame height=\"%i\" width=\"%i\" rate=\"%.2f\"", 00315 ((VideoESInfo*)es)->getHeight(), ((VideoESInfo*)es)->getWidth(), ((VideoESInfo*)es)->getFPS()); 00316 MP7File::writeSimpleEntry(fp, indent + 3, temp); 00317 MP7File::writeEntry(fp, indent + 2, "VisualCoding", true); 00318 00319 } else if (es->isAudioStream()) { 00320 MP7File::writeEntry(fp, indent + 3, "Name>audio</Name", false); 00321 MP7File::writeEntry(fp, indent + 2, "Content", true); 00322 // FIXME: no possibility to detect which audio we have: hard-code zu MP3 00323 //write fileformat 00324 MP7File::writeEntry(fp, indent + 2, "AudioCoding", false); 00325 MP7File::writeSimpleEntry(fp, indent + 3, 00326 "Format href=\"urn:mpeg:mpeg7:cs:AudioCodingFormatCS:2001:3.3\""); 00327 MP7File::writeEntry(fp, indent + 3, 00328 "Name xml:lang=\"en\">MPEG-1 Audio Layer III</Name", 00329 false); 00330 // close fileformat 00331 MP7File::writeEntry(fp, indent + 2, "AudioCoding", true); 00332 } else { 00333 MP7File::writeEntry(fp, indent + 3, "Name>generic</Name", false); 00334 MP7File::writeEntry(fp, indent + 2, "Content", true); 00335 // FIXME: no possibility to detect if BIFS or ODstream 00336 // set to MPEG-4 Scene Description Simple 2D Profile 00337 //write fileformat 00338 MP7File::writeEntry(fp, indent + 2, "SceneCodingFormat", false); 00339 MP7File::writeSimpleEntry(fp, indent + 3, 00340 "Format href=\"urn:mpeg:mpeg7:cs:SceneCodingFormatCS:2001:1.1\""); 00341 MP7File::writeEntry(fp, indent + 3, 00342 "Name xml:lang=\"en\">MPEG-4 Scene Description</Name", 00343 false); 00344 // close fileformat 00345 MP7File::writeEntry(fp, indent + 2, "SceneCodingFormat", true); 00346 } 00347 00348 u64 size = 0; 00349 const char *inp = es->getInput(); 00350 dprintf_full(inp); 00351 FILE *f; 00352 if ((f=fopen(inp,"r"))) { 00353 fseek(f,0L, SEEK_END); 00354 size=ftell(f); 00355 fclose(f); 00356 } 00357 00358 // write size: <FileSize>10000000</FileSize> 00359 // Note: size contains header too 00360 // MP7File::writeVideoDescriptionEntry(fp,indent+2,fileSize,size); 00361 00362 /* // now calc the bitrate -> 00363 u32 bitrate=0; 00364 if(es->isVisualStream() || es->isAudioStream()) { 00365 bitrate=(u32)((8000*size)/es->getDurationInMs()); 00366 } 00367 else { //generic streams are soo small that the produce irregulary high bitrate values 00368 if(es->getDurationInMs()<1000) { 00369 bitrate=size*8; 00370 } 00371 else { 00372 bitrate=(u32)((8000*size)/es->getDurationInMs()); 00373 } 00374 } */ 00375 // MP7File::writeVideoDescriptionEntry(fp,indent+2,bitRate,bitrate); 00376 MP7File::writeEntry(fp, indent + 1, "MediaFormat", true); 00377 MP7File::writeEntry(fp, indent, componentMediaProfile, true); 00378 00379 delete [] temp; 00380 return size; 00381 }; 00382 00383 void MP7File::writeVideoDescriptionEntry(FILE * fp, u32 indent, 00384 const char *const key, 00385 u32 intValue) 00386 { 00387 for (u32 i = 0; i < indent; i++) { 00388 fputc((int) '\t', fp); 00389 } 00390 fprintf(fp, "<%s>%u</%s>%s", key, intValue, key, NL); 00391 }; 00392 00393 void MP7File::writeVideoDescriptionEntry(FILE * fp, u32 indent, 00394 const char *const key, 00395 const char *stringVal) 00396 { 00397 for (u32 i = 0; i < indent; i++) { 00398 fputc((int) '\t', fp); 00399 } 00400 fprintf(fp, "<%s>%s</%s>%s", key, stringVal, key, NL); 00401 }; 00402 00403 void MP7File::writeAdaptation(FILE * fp, u32 indent, ContainerInfo * mp4, 00404 const char * adaptName, u32 variationId, 00405 u32 priority, float fidelity) 00406 { 00407 // <Variation id="VARIATION1" fidelity="0.85" priority="1"> 00408 // <!-- <SourceRef idref="ES1"/> --> 00409 // <Content xsi:type="VideoType"> 00410 // <Video id="var1"> 00411 // <MediaInformation> 00412 char *a = new char[128]; 00413 sprintf(a, 00414 "Variation id=\"VARIATION%i\" fidelity=\"%f\" priority=\"%i\"", 00415 variationId, fidelity, priority); 00416 MP7File::writeEntry(fp, indent, a, false); 00417 MP7File::writeEntry(fp, indent + 1, "Content xsi:type=\"VideoType\"", 00418 false); 00419 sprintf(a, "Video id=\"var%i\"", variationId); 00420 MP7File::writeEntry(fp, indent + 2, a, false); 00421 MP7File::writeMediaInformation(fp, indent + 3, mp4); 00422 // </Video> 00423 // </Content> 00424 // <VariationRelationship>qualityReduction</VariationRelationship> 00425 // </Variation> 00426 MP7File::writeEntry(fp, indent + 2, "Video", true); 00427 MP7File::writeEntry(fp, indent + 1, "Content", true); 00428 MP7File::writeVideoDescriptionEntry(fp, indent + 1, 00429 "VariationRelationship", 00430 adaptName); 00431 MP7File::writeEntry(fp, indent, "Variation", true); 00432 00433 delete [] a; 00434 };