1/**************************************************************************** 2** libmatroska : parse Matroska files, see http://www.matroska.org/ 3** 4** <file/class description> 5** 6** Copyright (C) 2002-2003 Steve Lhomme. All rights reserved. 7** 8** This file is part of libmatroska. 9** 10** This library is free software; you can redistribute it and/or 11** modify it under the terms of the GNU Lesser General Public 12** License as published by the Free Software Foundation; either 13** version 2.1 of the License, or (at your option) any later version. 14** 15** This library is distributed in the hope that it will be useful, 16** but WITHOUT ANY WARRANTY; without even the implied warranty of 17** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 18** Lesser General Public License for more details. 19** 20** You should have received a copy of the GNU Lesser General Public 21** License along with this library; if not, write to the Free Software 22** Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 23** 24** See http://www.matroska.org/license/lgpl/ for LGPL licensing information.** 25** Contact license@matroska.org if any conditions of this licensing are 26** not clear to you. 27** 28**********************************************************************/ 29 30/*! 31 \file 32 \version \$Id: FileKax.cpp 640 2004-07-09 21:05:36Z mosu $ 33 \author Steve Lhomme <robux4 @ users.sf.net> 34*/ 35//#include "StdInclude.h" 36#include "matroska/FileKax.h" 37//#include "Cluster.h" 38//#include "Track.h" 39//#include "Block.h" 40//#include "Frame.h" 41//#include "Version.h" 42 43START_LIBMATROSKA_NAMESPACE 44 45//typedef Track *TrackID; 46 47FileMatroska::FileMatroska(IOCallback & output) 48 :myFile(output) 49#ifdef OLD 50 ,myCurrReadBlock(NULL) 51 ,myMinClusterSize(5*1024) // 5KB is the min size of a cluster 52 ,myMaxClusterSize(2*1024*1024) // 2MB is the max size of a cluster 53 ,myCurrReadBlockTrack(0) 54 ,myCurrWriteCluster(2*1024*1024) // myMaxClusterSize 55 ,myCurrReadCluster(NULL) 56 ,myReadBlockNumber(0) 57#endif // OLD 58{ 59#ifdef OLD 60 myStreamInfo.MainHeaderSize = TypeHeader::default_size() + 61 ActualHeader::default_size() + 62 ExtendedInfo::default_size() + 63 ContentInfo::default_size(); 64 myStreamInfo.TrackEntrySize = Track::default_size(); 65 myStreamInfo.BlockHeadSize = BLOCK_HEADER_SIZE; 66 myStreamInfo.ClusterHeadSize = CLUSTER_HEADER_SIZE; 67 myStreamInfo.ClusterFootSize = CLUSTER_TRAILER_SIZE; 68#endif // OLD 69} 70 71FileMatroska::~FileMatroska() 72{ 73// if (myCurrCluster != NULL) 74// throw 0; // there are some data left to write 75// if (myCurrReadCluster != NULL || myCurrReadBlock != NULL) 76// throw 0; // there are some data left to write 77} 78 79#ifdef OLD 80void FileMatroska::SetMaxClusterSize(const uint32 value) 81{ 82 myMaxClusterSize = value; 83 myCurrWriteCluster.setMaxSize(value); 84} 85 86void FileMatroska::Close(const uint32 aTimeLength) 87{ 88 Flush(); 89 90 // get the file size 91 myFile.setFilePointer(0,seek_end); 92 myMainHeader.type_SetSize(myFile.getFilePointer()); 93 94 // rewrite the header at the beginning 95 myFile.setFilePointer(0,seek_beginning); 96 97 // get the Track-entry size 98 uint32 track_entries_size = 0; 99 for (size_t i=0; i<myTracks.size(); i++) 100 { 101 track_entries_size += myTracks[i]->default_size(); 102 } 103 104 myStreamInfo.TrackEntriesSize = track_entries_size; 105 myStreamInfo.TimeLength = aTimeLength; 106 myMainHeader.Render(myFile, myStreamInfo); 107 108 for (i=0; i<myTracks.size(); i++) 109 { 110 delete myTracks[i]; 111 } 112} 113 114/*! 115 \warning after rendering the head, some parameters are locked 116*/ 117uint32 FileMatroska::RenderHead(const std::string & aEncoderApp) 118{ 119 try { 120 uint32 track_entries_size = 0; 121 for (size_t i=0; i<myTracks.size(); i++) 122 { 123 track_entries_size += myTracks[i]->default_size(); 124 } 125 126 std::string aStr = LIB_NAME; 127 aStr += " "; 128 aStr += VERSION; 129 myStreamInfo.EncoderLib = aStr; 130 131 myStreamInfo.EncoderApp = aEncoderApp; 132 133 myStreamInfo.TrackEntryPosition = 0 + myStreamInfo.MainHeaderSize; 134 myStreamInfo.TrackEntriesSize = myTracks.size() * myStreamInfo.TrackEntrySize; 135 136 myStreamInfo.CodecEntryPosition = myStreamInfo.MainHeaderSize + myStreamInfo.TrackEntriesSize; 137 myStreamInfo.CodecEntrySize = 4; 138 for (i=0; i<myTracks.size(); i++) 139 { 140 myStreamInfo.CodecEntrySize += myTracks[i]->CodecSize(); 141 } 142 143 // Main Header 144 uint32 result = myMainHeader.Render(myFile, myStreamInfo); 145 146 // Track Entries 147 for (i=0; i<myTracks.size(); i++) 148 { 149 myTracks[i]->RenderEntry(myFile, i+1); 150 } 151 myStreamInfo.ClusterPosition = myStreamInfo.CodecEntryPosition + myStreamInfo.CodecEntrySize; 152 153 // Codec Header 154 result = CodecHeader::Render(myFile, myTracks); 155 156 return result; 157 } 158 catch (exception & Ex) 159 { 160 throw Ex; 161 } 162} 163 164/*! 165 \return 0 if the track was not created, or a valid track number 166*/ 167Track * FileMatroska::CreateTrack(const track_type aType) 168{ 169 myTracks.push_back(new Track(aType)); 170 return myTracks.back(); 171} 172 173/*Track *FileMatroska::findTrack(Track * aTrack) const 174{ 175 for (size_t i=0; i<myTracks.size(); i++) 176 { 177 if (myTracks[i] == aTrack) 178 return myTracks[i]; 179 } 180 181 return NULL; 182}*/ 183 184void FileMatroska::track_SetName(Track * aTrack, const std::string & aName) 185{ 186 if (IsMyTrack(aTrack)) 187 { 188 aTrack->SetName(aName); 189 } 190} 191 192void FileMatroska::track_SetLaced(Track * aTrack, const bool bLaced) 193{ 194 if (IsMyTrack(aTrack)) 195 { 196 aTrack->SetLaced(bLaced); 197 } 198} 199 200bool FileMatroska::AddFrame(Track * aTrack, const uint32 aTimecode, const binary *aFrame, const uint32 aFrameSize, 201 const bool aKeyFrame, const bool aBFrame) 202{ 203 try { 204 // make sure we know that track 205 if (IsMyTrack(aTrack)) 206 { 207 // pass the cluster to the track 208 // handle the creation of a new cluster if needed 209 if (aTrack->AddFrame(aTimecode, aFrame, aFrameSize, aKeyFrame, aBFrame)) 210 { 211 while (!aTrack->SerialiseBlock(myCurrWriteCluster)) 212 { 213 /// \todo handle errors 214 uint32 aNbBlock; 215 myStreamInfo.ClusterSize += myCurrWriteCluster.Render(myFile, aNbBlock); 216 myStreamInfo.NumberBlock += aNbBlock; 217 myCurrWriteCluster.Flush(); 218 } 219 } 220 return true; 221 } 222 return false; 223 } 224 catch (exception & Ex) 225 { 226 throw Ex; 227 } 228} 229 230void FileMatroska::Flush() 231{ 232 uint32 aNbBlock; 233 myStreamInfo.ClusterSize += myCurrWriteCluster.Render(myFile,aNbBlock); 234 myStreamInfo.NumberBlock += aNbBlock; 235} 236 237uint32 FileMatroska::ReadHead() 238{ 239 try { 240 uint32 result = myMainHeader.Read(myFile, myStreamInfo); 241 242 return result; 243 } 244 catch (exception & Ex) 245 { 246 throw Ex; 247 } 248} 249 250uint32 FileMatroska::ReadTracks() 251{ 252 try { 253 uint32 result = 0; 254 255 // seek to the start of the Track Entries 256 myFile.setFilePointer(myStreamInfo.TrackEntryPosition); 257 // get the number of Track Entries 258 uint8 TrackNumber = myStreamInfo.TrackEntriesSize / myStreamInfo.TrackEntrySize; 259 // read all the Track Entries 260 myTracks.clear(); 261 for (uint8 TrackIdx = 0; TrackIdx<TrackNumber; TrackIdx ++) { 262 Track * tmpTrack = Track::ReadEntry(myFile, TrackIdx+1, myStreamInfo); 263 if (tmpTrack == NULL) 264 throw 0; 265 266 myTracks.push_back(tmpTrack); 267 } 268 269 return result; 270 } 271 catch (exception & Ex) 272 { 273 throw Ex; 274 } 275} 276 277uint32 FileMatroska::ReadCodec() 278{ 279 try { 280 // seek to the start of the Track Entries 281 myFile.setFilePointer(myStreamInfo.CodecEntryPosition); 282 283 uint32 result = CodecHeader::Read(myFile, myTracks); 284 285 return result; 286 } 287 catch (exception & Ex) 288 { 289 throw Ex; 290 } 291} 292 293inline bool FileMatroska::IsMyTrack(const Track * aTrack) const 294{ 295 if (aTrack == 0) 296 throw 0; 297 298 for (std::vector<Track*>::const_iterator i = myTracks.begin(); i != myTracks.end(); i ++) 299 { 300 if (*i == aTrack) 301 break; 302 } 303 304 if (i != myTracks.end()) 305 return true; 306 else 307 return false; 308} 309 310void FileMatroska::SelectReadingTrack(Track * aTrack, bool select) 311{ 312 if (IsMyTrack(aTrack)) 313 { 314 // here we have the right track 315 // check if it's not already selected 316 for (std::vector<uint8>::iterator j = mySelectedTracks.begin(); 317 j != mySelectedTracks.end(); j ++) 318 { 319 if (*j == aTrack->TrackNumber()) 320 break; 321 } 322 323 if (select && j == mySelectedTracks.end()) 324 mySelectedTracks.push_back(aTrack->TrackNumber()); 325 else if (!select && j != mySelectedTracks.end()) 326 mySelectedTracks.erase(j); 327 328 std::sort(mySelectedTracks.begin(), mySelectedTracks.end()); 329 } 330} 331 332inline bool FileMatroska::IsReadingTrack(const uint8 aTrackNumber) const 333{ 334 for (std::vector<uint8>::const_iterator trackIdx = mySelectedTracks.begin(); 335 trackIdx != mySelectedTracks.end() && *trackIdx < aTrackNumber; 336 trackIdx++) 337 {} 338 339 if (trackIdx == mySelectedTracks.end()) 340 return false; 341 else 342 return true; 343} 344 345// 346 347void FileMatroska::Track_GetInfo(const Track * aTrack, TrackInfo & aTrackInfo) const 348{ 349 if (IsMyTrack(aTrack)) 350 { 351 aTrack->GetInfo(aTrackInfo); 352 } 353} 354 355// Audio related getters/setters 356 357void FileMatroska::Track_GetInfo_Audio(const Track * aTrack, TrackInfoAudio & aTrackInfo) const 358{ 359 if (IsMyTrack(aTrack)) 360 { 361 aTrack->GetInfoAudio(aTrackInfo); 362 } 363} 364 365void FileMatroska::Track_SetInfo_Audio(Track * aTrack, const TrackInfoAudio & aTrackInfo) 366{ 367 if (IsMyTrack(aTrack)) 368 { 369 aTrack->SetInfoAudio(aTrackInfo); 370 } 371} 372 373// Video related getters/setters 374 375void FileMatroska::Track_GetInfo_Video(const Track * aTrack, TrackInfoVideo & aTrackInfo) const 376{ 377 if (IsMyTrack(aTrack)) 378 { 379 aTrack->GetInfoVideo(aTrackInfo); 380 } 381} 382 383void FileMatroska::Track_SetInfo_Video(Track * aTrack, const TrackInfoVideo & aTrackInfo) 384{ 385 if (IsMyTrack(aTrack)) 386 { 387 aTrack->SetInfoVideo(aTrackInfo); 388 } 389} 390 391/*! 392 \todo exit when there is no Block left 393*/ 394bool FileMatroska::ReadFrame(Track * & aTrack, uint32 & aTimecode, const binary * & aFrame, uint32 & aFrameSize, 395 bool & aKeyFrame, bool & aBFrame) 396{ 397 if (myCurrReadBlockTrack == 0) 398 { 399 do { 400 if (myReadBlockNumber >= myStreamInfo.NumberBlock) 401 { 402// myReadBlockNumber = myStreamInfo.NumberBlock; 403 return false; 404 } 405 406 // get the next frame in the file 407 if (!myCurrReadCluster.BlockLeft()) 408 { 409 myCurrReadCluster.Flush(); 410 try { 411 myCurrReadCluster.FindHead(myFile); 412 } 413 catch (exception & Ex) 414 { 415 return false; 416 } 417 } 418 419 myCurrReadCluster.GetBlock( myCurrReadBlock, myCurrReadBlockSize, myCurrReadBlockTrack ); 420 myReadBlockNumber++; 421 } while (!IsReadingTrack(myCurrReadBlockTrack)); 422 423 // get the track associated (normally from myTracks) 424 aTrack = myTracks[myCurrReadBlockTrack-1]; 425 // get the next frame from the current block 426 aTrack->HandleBlock(myCurrReadBlock, myCurrReadBlockSize); 427 } 428 else 429 { 430 // get the track associated (normally from myTracks) 431 aTrack = myTracks[myCurrReadBlockTrack-1]; 432 } 433 434 Frame * myReadFrame; 435 aTrack->GetNextFrame(aTimecode, myReadFrame, aKeyFrame, aBFrame); 436 aFrame = myReadFrame->buf(); 437 aFrameSize = myReadFrame->length(); 438 439 if (aTrack->NoFrameLeft()) 440 { 441 aTrack->FlushBlock(); 442 myCurrReadBlockTrack = 0; 443 } 444 445 return true; 446} 447#endif // OLD 448 449END_LIBMATROSKA_NAMESPACE 450