From 4533d6faa6493fbe0ac8b5f6cd29aa8a228d0973 Mon Sep 17 00:00:00 2001
From: Thulinma <jaron@vietors.com>
Date: Sat, 14 Mar 2015 13:00:50 +0100
Subject: [PATCH] Added MP4::CO64 box, improved pretty-printing for various
 generic MP4 boxes.

---
 lib/mp4.cpp         |  3 ++
 lib/mp4_generic.cpp | 89 +++++++++++++++++++++++++++++++++++++++------
 lib/mp4_generic.h   | 10 +++++
 3 files changed, 90 insertions(+), 12 deletions(-)

diff --git a/lib/mp4.cpp b/lib/mp4.cpp
index e2d6347e..2ff3f469 100644
--- a/lib/mp4.cpp
+++ b/lib/mp4.cpp
@@ -333,6 +333,9 @@ namespace MP4 {
       case 0x7374636F:
         return ((STCO *)this)->toPrettyString(indent);
         break;
+      case 0x636F3634:
+        return ((CO64 *)this)->toPrettyString(indent);
+        break;
       case 0x7374737A:
         return ((STSZ *)this)->toPrettyString(indent);
         break;
diff --git a/lib/mp4_generic.cpp b/lib/mp4_generic.cpp
index 479d8db3..5dce8443 100644
--- a/lib/mp4_generic.cpp
+++ b/lib/mp4_generic.cpp
@@ -2275,10 +2275,7 @@ namespace MP4 {
     for (unsigned int i = 0; i < getEntryCount(); i++) {
       static STSCEntry temp;
       temp = getSTSCEntry(i);
-      r << std::string(indent + 1, ' ') << "Entry[" << i << "]:" << std::endl;
-      r << std::string(indent + 2, ' ') << "FirstChunk: " << temp.firstChunk << std::endl;
-      r << std::string(indent + 2, ' ') << "SamplesPerChunk: " << temp.samplesPerChunk << std::endl;
-      r << std::string(indent + 2, ' ') << "SampleDescriptionIndex: " << temp.sampleDescriptionIndex << std::endl;
+      r << std::string(indent + 1, ' ') << "Entry[" << i << "]: Chunks " << temp.firstChunk << " onward contain " << temp.samplesPerChunk << " samples, description " << temp.sampleDescriptionIndex << std::endl;
     }
     return r.str();
   }
@@ -2323,9 +2320,65 @@ namespace MP4 {
     r << std::string(indent, ' ') << "[stco] Chunk Offset Box (" << boxedSize() << ")" << std::endl;
     r << fullBox::toPrettyString(indent);
     r << std::string(indent + 1, ' ') << "EntryCount: " << getEntryCount() << std::endl;
-    for (unsigned int i = 0; i < getEntryCount(); i++) {
-      r << std::string(indent + 1, ' ') << "ChunkOffset[" << i << "]: " << getChunkOffset(i) << std::endl;
+    r << std::string(indent + 1, ' ') << "Offsets: ";
+    for (unsigned long i = 0; i < getEntryCount(); i++) {
+      r << getChunkOffset(i);
+      if (i != getEntryCount() - 1){
+        r << ", ";
+      }
     }
+    r << std::endl;
+    return r.str();
+  }
+
+  CO64::CO64(char v, uint32_t f) {
+    memcpy(data + 4, "co64", 4);
+    setVersion(v);
+    setFlags(f);
+    setEntryCount(0);
+  }
+
+  void CO64::setEntryCount(uint32_t newEntryCount) {
+    setInt32(newEntryCount, 4);
+  }
+
+  uint32_t CO64::getEntryCount() {
+    return getInt32(4);
+  }
+
+  void CO64::setChunkOffset(uint64_t newChunkOffset, uint32_t no) {
+    setInt64(newChunkOffset, 8 + no * 8);
+    uint32_t entryCount = getEntryCount();
+    //if entrycount is lower than new entry count, update it and fill any skipped entries with zeroes.
+    if (no + 1 > entryCount) {
+      setEntryCount(no + 1);
+      //fill undefined entries, if any (there's only undefined entries if we skipped an entry)
+      if (no > entryCount){
+        memset(data+payloadOffset+8+entryCount*8, 0, 8*(no-entryCount));
+      }
+    }
+  }
+
+  uint64_t CO64::getChunkOffset(uint32_t no) {
+    if (no >= getEntryCount()) {
+      return 0;
+    }
+    return getInt64(8 + no * 8);
+  }
+
+  std::string CO64::toPrettyString(uint32_t indent) {
+    std::stringstream r;
+    r << std::string(indent, ' ') << "[co64] 64-bits Chunk Offset Box (" << boxedSize() << ")" << std::endl;
+    r << fullBox::toPrettyString(indent);
+    r << std::string(indent + 1, ' ') << "EntryCount: " << getEntryCount() << std::endl;
+    r << std::string(indent + 1, ' ') << "Offsets: ";
+    for (unsigned long i = 0; i < getEntryCount(); i++) {
+      r << getChunkOffset(i);
+      if (i != getEntryCount() - 1){
+        r << ", ";
+      }
+    }
+    r << std::endl;
     return r.str();
   }
 
@@ -2378,11 +2431,17 @@ namespace MP4 {
     std::stringstream r;
     r << std::string(indent, ' ') << "[stsz] Sample Size Box (" << boxedSize() << ")" << std::endl;
     r << fullBox::toPrettyString(indent);
-    r << std::string(indent + 1, ' ') << "SampleSize: " << getSampleSize() << std::endl;
-    r << std::string(indent + 1, ' ') << "SampleCount: " << getSampleCount() << std::endl;
-    for (unsigned int i = 0; i < getSampleCount(); i++) {
-      r << std::string(indent + 1, ' ') << "EntrySize[" << i << "]: " << getEntrySize(i) << std::endl;
+    r << std::string(indent + 1, ' ') << "Global Sample Size: " << getSampleSize() << std::endl;
+    r << std::string(indent + 1, ' ') << "Sample Count: " << getSampleCount() << std::endl;
+
+    r << std::string(indent + 1, ' ') << "Sample sizes: ";
+    for (unsigned long i = 0; i < getSampleCount(); i++) {
+      r << getEntrySize(i);
+      if (i != getSampleCount() - 1){
+        r << ", ";
+      }
     }
+    r << std::endl;
     return r.str();
   }
 
@@ -2841,9 +2900,15 @@ namespace MP4 {
     r << std::string(indent, ' ') << "[stss] Sync Sample Box (" << boxedSize() << ")" << std::endl;
     r << fullBox::toPrettyString(indent);
     r << std::string(indent + 1, ' ') << "EntryCount: " << getEntryCount() << std::endl;
-    for (unsigned int i = 0; i < getEntryCount(); i++) {
-      r << std::string(indent + 1, ' ') << "SampleNumber[" << i << "] : " << getSampleNumber(i) << std::endl;
+
+    r << std::string(indent + 1, ' ') << "Keyframe sample indexes: ";
+    for (unsigned long i = 0; i < getEntryCount(); i++) {
+      r << getSampleNumber(i);
+      if (i != getEntryCount() - 1){
+        r << ", ";
+      }
     }
+    r << std::endl;
     return r.str();
   }
 
diff --git a/lib/mp4_generic.h b/lib/mp4_generic.h
index 8cb5091b..381a12dc 100644
--- a/lib/mp4_generic.h
+++ b/lib/mp4_generic.h
@@ -495,6 +495,16 @@ namespace MP4 {
       std::string toPrettyString(uint32_t indent = 0);
   };
 
+  class CO64: public fullBox {
+    public:
+      CO64(char v = 1, uint32_t f = 0);
+      void setEntryCount(uint32_t newEntryCount);
+      uint32_t getEntryCount();
+      void setChunkOffset(uint64_t newChunkOffset, uint32_t no);
+      uint64_t getChunkOffset(uint32_t no);
+      std::string toPrettyString(uint32_t indent = 0);
+  };
+
   class STSZ: public fullBox {
     public:
       STSZ(char v = 1, uint32_t f = 0);