Hi!

I enhanced the QuickTimeFileSink to be able to write MP4 files larger then
2GB. It uses TellFile64 and SeekFile64 from InputFile.hh instead of fseek and
ftell, the mdat atom is written in 64bit format and all the stco atoms are
co64 now.

And I've fixed a bug which causes damaged mp4a.esds atoms in .mp4 format.
Patch is for both.

The parts
@@ -1656,16 +1694,20 @@
@@ -1717,7 +1759,7 @@
are the esds fix.

Regards, Wolfgang Breyha
-- 
Wolfgang Breyha <wbre...@gmx.net> | http://www.blafasel.at/
Vienna University Computer Center | Austria

diff -urN live.orig/liveMedia/include/QuickTimeFileSink.hh 
live/liveMedia/include/QuickTimeFileSink.hh
--- live.orig/liveMedia/include/QuickTimeFileSink.hh    2010-03-10 
16:46:39.000000000 +0100
+++ live/liveMedia/include/QuickTimeFileSink.hh 2010-03-12 14:17:34.000000000 
+0100
@@ -85,6 +85,7 @@
 private:
   ///// Definitions specific to the QuickTime file format:
 
+  unsigned addWord64(u_int64_t word);
   unsigned addWord(unsigned word);
   unsigned addHalfWord(unsigned short halfWord);
   unsigned addByte(unsigned char byte) {
@@ -96,8 +97,10 @@
   unsigned addArbitraryString(char const* str,
                              Boolean oneByteLength = True);
   unsigned addAtomHeader(char const* atomName);
+  unsigned addAtomHeader64(char const* atomName);
       // strlen(atomName) must be 4
-  void setWord(unsigned filePosn, unsigned size);
+  void setWord(int64_t filePosn, unsigned size);
+  void setWord64(int64_t filePosn, u_int64_t size);
 
   unsigned movieTimeScale() const {return fLargestRTPtimestampFrequency;}
 
@@ -150,7 +153,7 @@
                       _atom(stts);
                       _atom(stsc);
                       _atom(stsz);
-                      _atom(stco);
+                      _atom(co64);
           _atom(udta);
               _atom(name);
               _atom(hnti);
@@ -175,8 +178,8 @@
 private:
   unsigned short fMovieWidth, fMovieHeight;
   unsigned fMovieFPS;
-  unsigned fMDATposition;
-  unsigned fMVHD_durationPosn;
+  int64_t fMDATposition;
+  int64_t fMVHD_durationPosn;
   unsigned fMaxTrackDurationM; // in movie time units
   class SubsessionIOState* fCurrentIOState;
 };
diff -urN live.orig/liveMedia/QuickTimeFileSink.cpp 
live/liveMedia/QuickTimeFileSink.cpp
--- live.orig/liveMedia/QuickTimeFileSink.cpp   2010-03-10 16:46:39.000000000 
+0100
+++ live/liveMedia/QuickTimeFileSink.cpp        2010-03-12 14:16:35.000000000 
+0100
@@ -21,6 +21,7 @@
 #include "QuickTimeFileSink.hh"
 #include "QuickTimeGenericRTPSource.hh"
 #include "GroupsockHelper.hh"
+#include "InputFile.hh"
 #include "OutputFile.hh"
 #include "H263plusVideoRTPSource.hh" // for the special header
 #include "MPEG4GenericRTPSource.hh" //for 
"samplingFrequencyFromAudioSpecificConfig()"
@@ -36,19 +37,19 @@
 
 class ChunkDescriptor {
 public:
-  ChunkDescriptor(unsigned offsetInFile, unsigned size,
+  ChunkDescriptor(int64_t offsetInFile, unsigned size,
                  unsigned frameSize, unsigned frameDuration,
                  struct timeval presentationTime);
   virtual ~ChunkDescriptor();
 
-  ChunkDescriptor* extendChunk(unsigned newOffsetInFile, unsigned newSize,
+  ChunkDescriptor* extendChunk(int64_t newOffsetInFile, unsigned newSize,
                               unsigned newFrameSize,
                               unsigned newFrameDuration,
                               struct timeval newPresentationTime);
       // this may end up allocating a new chunk instead
 public:
   ChunkDescriptor* fNextChunk;
-  unsigned fOffsetInFile;
+  int64_t fOffsetInFile;
   unsigned fNumFrames;
   unsigned fFrameSize;
   unsigned fFrameDuration;
@@ -148,7 +149,7 @@
   unsigned fQTTotNumSamples;
   unsigned fQTDurationM; // in media time units
   unsigned fQTDurationT; // in track time units
-  unsigned fTKHD_durationPosn;
+  int64_t fTKHD_durationPosn;
       // position of the duration in the output 'tkhd' atom
   unsigned fQTInitialOffsetDuration;
       // if there's a pause at the beginning
@@ -179,7 +180,7 @@
   // used by the above two routines:
   unsigned useFrame1(unsigned sourceDataSize,
                     struct timeval presentationTime,
-                    unsigned frameDuration, unsigned destFileOffset);
+                    unsigned frameDuration, int64_t destFileOffset);
       // returns the number of samples in this data
 
 private:
@@ -187,7 +188,7 @@
   struct {
     unsigned frameSize;
     struct timeval presentationTime;
-    unsigned destFileOffset; // used for non-hint tracks only
+    int64_t destFileOffset; // used for non-hint tracks only
 
     // The remaining fields are used for hint tracks only:
     unsigned startSampleNumber;
@@ -292,8 +293,10 @@
   // Begin by writing a "mdat" atom at the start of the file.
   // (Later, when we've finished copying data to the file, we'll come
   // back and fill in its size.)
-  fMDATposition = ftell(fOutFid);
-  addAtomHeader("mdat");
+  fMDATposition = TellFile64(fOutFid);
+  addAtomHeader64("mdat");
+  // add 64Bit offset
+  fMDATposition += 8;
 }
 
 QuickTimeFileSink::~QuickTimeFileSink() {
@@ -455,8 +458,8 @@
 
   // Begin by filling in the initial "mdat" atom with the current
   // file size:
-  unsigned curFileSize = ftell(fOutFid);
-  setWord(fMDATposition, curFileSize);
+  int64_t curFileSize = TellFile64(fOutFid);
+  setWord64(fMDATposition, (u_int64_t)curFileSize);
 
   // Then, note the time of the first received data:
   MediaSubsessionIterator iter(fInputSession);
@@ -750,7 +753,7 @@
   unsigned char* const frameSource = buffer.dataStart();
   unsigned const frameSize = buffer.bytesInUse();
   struct timeval const& presentationTime = buffer.presentationTime();
-  unsigned const destFileOffset = ftell(fOurSink.fOutFid);
+  int64_t const destFileOffset = TellFile64(fOurSink.fOutFid);
   unsigned sampleNumberOfFrameStart = fQTTotNumSamples + 1;
   Boolean avcHack = fQTMediaDataAtomCreator == 
&QuickTimeFileSink::addAtom_avc1;
 
@@ -854,7 +857,7 @@
       }
     }
 
-    unsigned const hintSampleDestFileOffset = ftell(fOurSink.fOutFid);
+    int64_t const hintSampleDestFileOffset = TellFile64(fOurSink.fOutFid);
 
     unsigned const maxPacketSize = 1450;
     unsigned short numPTEntries
@@ -1009,7 +1012,7 @@
 unsigned SubsessionIOState::useFrame1(unsigned sourceDataSize,
                                      struct timeval presentationTime,
                                      unsigned frameDuration,
-                                     unsigned destFileOffset) {
+                                     int64_t destFileOffset) {
   // Figure out the actual frame size for this data:
   unsigned frameSize = fQTBytesPerFrame;
   if (frameSize == 0) {
@@ -1088,7 +1091,7 @@
 }
 
 ChunkDescriptor
-::ChunkDescriptor(unsigned offsetInFile, unsigned size,
+::ChunkDescriptor(int64_t offsetInFile, unsigned size,
                  unsigned frameSize, unsigned frameDuration,
                  struct timeval presentationTime)
   : fNextChunk(NULL), fOffsetInFile(offsetInFile),
@@ -1102,7 +1105,7 @@
 }
 
 ChunkDescriptor* ChunkDescriptor
-::extendChunk(unsigned newOffsetInFile, unsigned newSize,
+::extendChunk(int64_t newOffsetInFile, unsigned newSize,
              unsigned newFrameSize, unsigned newFrameDuration,
              struct timeval newPresentationTime) {
   // First, check whether the new space is just at the end of this
@@ -1130,6 +1133,15 @@
 
 ////////// QuickTime-specific implementation //////////
 
+unsigned QuickTimeFileSink::addWord64(u_int64_t word) {
+  addByte(word>>56); addByte(word>>48);
+  addByte(word>>40); addByte(word>>32);
+  addByte(word>>24); addByte(word>>16);
+  addByte(word>>8); addByte(word);
+
+  return 8;
+}
+
 unsigned QuickTimeFileSink::addWord(unsigned word) {
   addByte(word>>24); addByte(word>>16);
   addByte(word>>8); addByte(word);
@@ -1188,11 +1200,37 @@
   return 8;
 }
 
-void QuickTimeFileSink::setWord(unsigned filePosn, unsigned size) {
+unsigned QuickTimeFileSink::addAtomHeader64(char const* atomName) {
+  // Output 64Bit size marker
+  addWord(1);
+
+  // Output the 4-byte atom name:
+  add4ByteString(atomName);
+
+  addWord64(0);
+
+  return 16;
+}
+
+void QuickTimeFileSink::setWord(int64_t filePosn, unsigned size) {
   do {
-    if (fseek(fOutFid, filePosn, SEEK_SET) < 0) break;
+    if (SeekFile64(fOutFid, filePosn, SEEK_SET) < 0) break;
     addWord(size);
-    if (fseek(fOutFid, 0, SEEK_END) < 0) break; // go back to where we were
+    if (SeekFile64(fOutFid, 0, SEEK_END) < 0) break; // go back to where we 
were
+
+    return;
+  } while (0);
+
+  // One of the fseek()s failed, probable because we're not a seekable file
+  envir() << "QuickTimeFileSink::setWord(): fseek failed (err "
+         << envir().getErrno() << ")\n";
+}
+
+void QuickTimeFileSink::setWord64(int64_t filePosn, u_int64_t size) {
+  do {
+    if (SeekFile64(fOutFid, filePosn, SEEK_SET) < 0) break;
+    addWord64(size);
+    if (SeekFile64(fOutFid, 0, SEEK_END) < 0) break; // go back to where we 
were
 
     return;
   } while (0);
@@ -1206,7 +1244,7 @@
 
 #define addAtom(name) \
     unsigned QuickTimeFileSink::addAtom_##name() { \
-    unsigned initFilePosn = ftell(fOutFid); \
+    int64_t initFilePosn = TellFile64(fOutFid); \
     unsigned size = addAtomHeader("" #name "")
 
 #define addAtomEnd \
@@ -1273,7 +1311,7 @@
   size += addWord(movieTimeScale()); // Time scale
 
   unsigned const duration = fMaxTrackDurationM;
-  fMVHD_durationPosn = ftell(fOutFid);
+  fMVHD_durationPosn = TellFile64(fOutFid);
   size += addWord(duration); // Duration
 
   size += addWord(0x00010000); // Preferred rate
@@ -1327,7 +1365,7 @@
   size += addWord(0x00000000); // Reserved
 
   unsigned const duration = fCurrentIOState->fQTDurationM; // movie units
-  fCurrentIOState->fTKHD_durationPosn = ftell(fOutFid);
+  fCurrentIOState->fTKHD_durationPosn = TellFile64(fOutFid);
   size += addWord(duration); // Duration
   size += addZeroWords(3); // Reserved+Layer+Alternate grp
   size += addWord(0x01000000); // Volume + Reserved
@@ -1366,7 +1404,7 @@
 
   // Add a dummy "Number of entries" field
   // (and remember its position).  We'll fill this field in later:
-  unsigned numEntriesPosition = ftell(fOutFid);
+  int64_t numEntriesPosition = TellFile64(fOutFid);
   size += addWord(0); // dummy for "Number of entries"
   unsigned numEdits = 0;
   unsigned totalDurationOfEdits = 0; // in movie time units
@@ -1525,7 +1563,7 @@
 addAtomEnd;
 
 unsigned QuickTimeFileSink::addAtom_hdlr2() {
-  unsigned initFilePosn = ftell(fOutFid);
+  int64_t initFilePosn = TellFile64(fOutFid);
   unsigned size = addAtomHeader("hdlr");
   size += addWord(0x00000000); // Version + Flags
   size += add4ByteString("dhlr"); // Component type
@@ -1554,7 +1592,7 @@
   size += addAtom_stts();
   size += addAtom_stsc();
   size += addAtom_stsz();
-  size += addAtom_stco();
+  size += addAtom_co64();
 addAtomEnd;
 
 addAtom(stsd);
@@ -1566,7 +1604,7 @@
 addAtomEnd;
 
 unsigned QuickTimeFileSink::addAtom_genericMedia() {
-  unsigned initFilePosn = ftell(fOutFid);
+  int64_t initFilePosn = TellFile64(fOutFid);
 
   // Our source is assumed to be a "QuickTimeGenericRTPSource"
   // Use its "sdAtom" state for our contents:
@@ -1579,7 +1617,7 @@
 addAtomEnd;
 
 unsigned QuickTimeFileSink::addAtom_soundMediaGeneral() {
-  unsigned initFilePosn = ftell(fOutFid);
+  int64_t initFilePosn = TellFile64(fOutFid);
   unsigned size = addAtomHeader(fCurrentIOState->fQTAudioDataType);
 
 // General sample description fields:
@@ -1603,7 +1641,7 @@
 unsigned QuickTimeFileSink::addAtom_Qclp() {
   // The beginning of this atom looks just like a general Sound Media atom,
   // except with a version field of 1:
-  unsigned initFilePosn = ftell(fOutFid);
+  int64_t initFilePosn = TellFile64(fOutFid);
   fCurrentIOState->fQTAudioDataType = "Qclp";
   fCurrentIOState->fQTSoundSampleVersion = 1;
   unsigned size = addAtom_soundMediaGeneral();
@@ -1656,16 +1694,20 @@
 addAtomEnd;
 
 unsigned QuickTimeFileSink::addAtom_mp4a() {
+  unsigned size = 0;
   // The beginning of this atom looks just like a general Sound Media atom,
   // except with a version field of 1:
-  unsigned initFilePosn = ftell(fOutFid);
+  int64_t initFilePosn = TellFile64(fOutFid);
   fCurrentIOState->fQTAudioDataType = "mp4a";
-  fCurrentIOState->fQTSoundSampleVersion = 1;
-  unsigned size = addAtom_soundMediaGeneral();
 
   if (fGenerateMP4Format) {
+    fCurrentIOState->fQTSoundSampleVersion = 0;
+    size = addAtom_soundMediaGeneral();
     size += addAtom_esds();
   } else {
+    fCurrentIOState->fQTSoundSampleVersion = 1;
+    size = addAtom_soundMediaGeneral();
+
     // Next, add the four fields that are particular to version 1:
     // (Later, parameterize these #####)
     size += addWord(fCurrentIOState->fQTTimeUnitsPerSample);
@@ -1717,7 +1759,7 @@
   if (strcmp(subsession.mediumName(), "audio") == 0) {
     // MPEG-4 audio
     size += addWord(0x06808080); // ???
-    size += addByte(0x01); // ???
+    size += addHalfWord(0x0102); // ???
   } else {
     // MPEG-4 video
     size += addHalfWord(0x0601); // ???
@@ -1844,7 +1886,7 @@
 addAtomEnd;
 
 unsigned QuickTimeFileSink::addAtom_rtp() {
-  unsigned initFilePosn = ftell(fOutFid);
+  int64_t initFilePosn = TellFile64(fOutFid);
   unsigned size = addAtomHeader("rtp ");
 
   size += addWord(0x00000000); // Reserved (1st 4 bytes)
@@ -1864,7 +1906,7 @@
 
   // First, add a dummy "Number of entries" field
   // (and remember its position).  We'll fill this field in later:
-  unsigned numEntriesPosition = ftell(fOutFid);
+  int64_t numEntriesPosition = TellFile64(fOutFid);
   size += addWord(0); // dummy for "Number of entries"
 
   // Then, run through the chunk descriptors, and enter the entries
@@ -1906,7 +1948,7 @@
 
   // First, add a dummy "Number of entries" field
   // (and remember its position).  We'll fill this field in later:
-  unsigned numEntriesPosition = ftell(fOutFid);
+  int64_t numEntriesPosition = TellFile64(fOutFid);
   size += addWord(0); // dummy for "Number of entries"
 
   // Then, run through the chunk descriptors, and enter the entries
@@ -1997,14 +2039,14 @@
   }
 addAtomEnd;
 
-addAtom(stco); // Chunk Offset
+addAtom(co64); // Chunk Offset
   size += addWord(0x00000000); // Version+flags
   size += addWord(fCurrentIOState->fNumChunks); // Number of entries
 
   // Run through the chunk descriptors, entering the file offsets:
   ChunkDescriptor* chunk = fCurrentIOState->fHeadChunk;
   while (chunk != NULL) {
-    size += addWord(chunk->fOffsetInFile);
+    size += addWord64(chunk->fOffsetInFile);
 
     chunk = chunk->fNextChunk;
   }
@@ -2028,7 +2070,7 @@
 addAtomEnd;
 
 unsigned QuickTimeFileSink::addAtom_sdp() {
-  unsigned initFilePosn = ftell(fOutFid);
+  int64_t initFilePosn = TellFile64(fOutFid);
   unsigned size = addAtomHeader("sdp ");
 
   // Add this subsession's SDP lines:
@@ -2168,6 +2210,6 @@
 
 // A dummy atom (with name "????"):
 unsigned QuickTimeFileSink::addAtom_dummy() {
-    unsigned initFilePosn = ftell(fOutFid);
+    int64_t initFilePosn = TellFile64(fOutFid);
     unsigned size = addAtomHeader("????");
 addAtomEnd;
_______________________________________________
live-devel mailing list
live-devel@lists.live555.com
http://lists.live555.com/mailman/listinfo/live-devel

Reply via email to