Upstream version 10.39.225.0
[platform/framework/web/crosswalk.git] / src / media / formats / mp4 / track_run_iterator.cc
index bc38352..604074c 100644 (file)
@@ -7,12 +7,8 @@
 #include <algorithm>
 
 #include "media/base/buffers.h"
-#include "media/base/stream_parser_buffer.h"
 #include "media/formats/mp4/rcheck.h"
-
-namespace {
-static const uint32 kSampleIsDifferenceSampleFlagMask = 0x10000;
-}
+#include "media/formats/mp4/sample_to_group_iterator.h"
 
 namespace media {
 namespace mp4 {
@@ -22,6 +18,8 @@ struct SampleInfo {
   int duration;
   int cts_offset;
   bool is_keyframe;
+  bool is_random_access_point;
+  uint32 cenc_group_description_index;
 };
 
 struct TrackRunInfo {
@@ -40,6 +38,8 @@ struct TrackRunInfo {
   std::vector<uint8> aux_info_sizes;  // Populated if default_size == 0.
   int aux_info_total_size;
 
+  std::vector<CencSampleEncryptionInfoEntry> sample_encryption_info;
+
   TrackRunInfo();
   ~TrackRunInfo();
 };
@@ -56,7 +56,7 @@ TrackRunInfo::TrackRunInfo()
 }
 TrackRunInfo::~TrackRunInfo() {}
 
-TimeDelta TimeDeltaFromRational(int64 numer, int64 denom) {
+base::TimeDelta TimeDeltaFromRational(int64 numer, int64 denom) {
   // To avoid overflow, split the following calculation:
   // (numer * base::Time::kMicrosecondsPerSecond) / denom
   // into:
@@ -72,7 +72,12 @@ TimeDelta TimeDeltaFromRational(int64 numer, int64 denom) {
 
   DCHECK((timeb_in_us < 0) || (timea_in_us <= kint64max - timeb_in_us));
   DCHECK((timeb_in_us > 0) || (timea_in_us >= kint64min - timeb_in_us));
-  return TimeDelta::FromMicroseconds(timea_in_us + timeb_in_us);
+  return base::TimeDelta::FromMicroseconds(timea_in_us + timeb_in_us);
+}
+
+DecodeTimestamp DecodeTimestampFromRational(int64 numer, int64 denom) {
+  return DecodeTimestamp::FromPresentationTime(
+      TimeDeltaFromRational(numer, denom));
 }
 
 TrackRunIterator::TrackRunIterator(const Movie* moov,
@@ -83,13 +88,14 @@ TrackRunIterator::TrackRunIterator(const Movie* moov,
 
 TrackRunIterator::~TrackRunIterator() {}
 
-static void PopulateSampleInfo(const TrackExtends& trex,
+static bool PopulateSampleInfo(const TrackExtends& trex,
                                const TrackFragmentHeader& tfhd,
                                const TrackFragmentRun& trun,
                                const int64 edit_list_offset,
                                const uint32 i,
                                SampleInfo* sample_info,
-                               const SampleDependsOn sample_depends_on) {
+                               const SampleDependsOn sdtp_sample_depends_on,
+                               const LogCB& log_cb) {
   if (i < trun.sample_sizes.size()) {
     sample_info->size = trun.sample_sizes[i];
   } else if (tfhd.default_sample_size > 0) {
@@ -122,9 +128,24 @@ static void PopulateSampleInfo(const TrackExtends& trex,
     flags = trex.default_sample_flags;
   }
 
+  SampleDependsOn sample_depends_on =
+      static_cast<SampleDependsOn>((flags >> 24) & 0x3);
+
+  if (sample_depends_on == kSampleDependsOnUnknown)
+    sample_depends_on = sdtp_sample_depends_on;
+
+  // ISO/IEC 14496-12  Section 8.8.3.1 : The negation of |sample_is_sync_sample|
+  // provides the same information as the sync sample table [8.6.2]. When
+  // |sample_is_sync_sample| is true for a sample, it is the same as if the
+  // sample were not in a movie fragment and marked with an entry in the sync
+  // sample table (or, if all samples are sync samples, the sync sample table
+  // were absent).
+  bool sample_is_sync_sample = !(flags & kSampleIsNonSyncSample);
+  sample_info->is_random_access_point = sample_is_sync_sample;
+
   switch (sample_depends_on) {
     case kSampleDependsOnUnknown:
-      sample_info->is_keyframe = !(flags & kSampleIsDifferenceSampleFlagMask);
+      sample_info->is_keyframe = sample_is_sync_sample;
       break;
 
     case kSampleDependsOnOthers:
@@ -136,8 +157,10 @@ static void PopulateSampleInfo(const TrackExtends& trex,
       break;
 
     case kSampleDependsOnReserved:
-      CHECK(false);
+      MEDIA_LOG(log_cb) << "Reserved value used in sample dependency info.";
+      return false;
   }
+  return true;
 }
 
 // In well-structured encrypted media, each track run will be immediately
@@ -215,10 +238,11 @@ bool TrackRunIterator::Init(const MovieFragment& moof) {
       }
     }
 
+    SampleToGroupIterator sample_to_group_itr(traf.sample_to_group);
+    bool is_sample_to_group_valid = sample_to_group_itr.IsValid();
+
     int64 run_start_dts = traf.decode_time.decode_time;
     int sample_count_sum = 0;
-    bool is_sync_sample_box_present =
-        trak->media.information.sample_table.sync_sample.is_present;
     for (size_t j = 0; j < traf.runs.size(); j++) {
       const TrackFragmentRun& trun = traf.runs[j];
       TrackRunInfo tri;
@@ -226,6 +250,7 @@ bool TrackRunIterator::Init(const MovieFragment& moof) {
       tri.timescale = trak->media.header.timescale;
       tri.start_dts = run_start_dts;
       tri.sample_start_offset = trun.data_offset;
+      tri.sample_encryption_info = traf.sample_group_description.entries;
 
       tri.is_audio = (stsd.type == kAudio);
       if (tri.is_audio) {
@@ -278,21 +303,49 @@ bool TrackRunIterator::Init(const MovieFragment& moof) {
 
       tri.samples.resize(trun.sample_count);
       for (size_t k = 0; k < trun.sample_count; k++) {
-        PopulateSampleInfo(*trex, traf.header, trun, edit_list_offset,
-                           k, &tri.samples[k], traf.sdtp.sample_depends_on(k));
+        if (!PopulateSampleInfo(*trex, traf.header, trun, edit_list_offset,
+                                k, &tri.samples[k],
+                                traf.sdtp.sample_depends_on(k),
+                                log_cb_)) {
+          return false;
+        }
+
         run_start_dts += tri.samples[k].duration;
 
-        // ISO-14496-12 Section 8.20.1 : If the sync sample box is not present,
-        // every sample is a random access point.
-        //
-        // NOTE: MPEG's "is random access point" concept is equivalent to this
-        // and downstream code's "is keyframe" concept.
-        if (!is_sync_sample_box_present)
-          tri.samples[k].is_keyframe = true;
+        if (!is_sample_to_group_valid) {
+          // Set group description index to 0 to read encryption information
+          // from TrackEncryption Box.
+          tri.samples[k].cenc_group_description_index = 0;
+          continue;
+        }
+
+        // ISO-14496-12 Section 8.9.2.3 and 8.9.4 : group description index
+        // (1) ranges from 1 to the number of sample group entries in the track
+        // level SampleGroupDescription Box, or (2) takes the value 0 to
+        // indicate that this sample is a member of no group, in this case, the
+        // sample is associated with the default values specified in
+        // TrackEncryption Box, or (3) starts at 0x10001, i.e. the index value
+        // 1, with the value 1 in the top 16 bits, to reference fragment-local
+        // SampleGroupDescription Box.
+        // Case (1) is not supported currently. We might not need it either as
+        // the same functionality can be better achieved using (2).
+        uint32 index = sample_to_group_itr.group_description_index();
+        if (index >= SampleToGroupEntry::kFragmentGroupDescriptionIndexBase) {
+          index -= SampleToGroupEntry::kFragmentGroupDescriptionIndexBase;
+          RCHECK(index != 0 && index <= tri.sample_encryption_info.size());
+        } else if (index != 0) {
+          NOTIMPLEMENTED() << "'sgpd' box in 'moov' is not supported.";
+          return false;
+        }
+        tri.samples[k].cenc_group_description_index = index;
+        is_sample_to_group_valid = sample_to_group_itr.Advance();
       }
       runs_.push_back(tri);
       sample_count_sum += trun.sample_count;
     }
+
+    // We should have iterated through all samples in SampleToGroup Box.
+    RCHECK(!sample_to_group_itr.IsValid());
   }
 
   std::sort(runs_.begin(), runs_.end(), CompareMinTrackRunDataOffset());
@@ -325,7 +378,7 @@ void TrackRunIterator::AdvanceSample() {
 // info is available in the stream.
 bool TrackRunIterator::AuxInfoNeedsToBeCached() {
   DCHECK(IsRunValid());
-  return is_encrypted() && aux_info_size() > 0 && cenc_info_.size() == 0;
+  return aux_info_size() > 0 && cenc_info_.size() == 0;
 }
 
 // This implementation currently only caches CENC auxiliary info.
@@ -339,8 +392,10 @@ bool TrackRunIterator::CacheAuxInfo(const uint8* buf, int buf_size) {
     if (!info_size)
       info_size = run_itr_->aux_info_sizes[i];
 
-    BufferReader reader(buf + pos, info_size);
-    RCHECK(cenc_info_[i].Parse(track_encryption().default_iv_size, &reader));
+    if (IsSampleEncrypted(i)) {
+      BufferReader reader(buf + pos, info_size);
+      RCHECK(cenc_info_[i].Parse(GetIvSize(i), &reader));
+    }
     pos += info_size;
   }
 
@@ -387,8 +442,8 @@ uint32 TrackRunIterator::track_id() const {
 }
 
 bool TrackRunIterator::is_encrypted() const {
-  DCHECK(IsRunValid());
-  return track_encryption().is_encrypted;
+  DCHECK(IsSampleValid());
+  return IsSampleEncrypted(sample_itr_ - run_itr_->samples.begin());
 }
 
 int64 TrackRunIterator::aux_info_offset() const {
@@ -426,18 +481,18 @@ int TrackRunIterator::sample_size() const {
   return sample_itr_->size;
 }
 
-TimeDelta TrackRunIterator::dts() const {
+DecodeTimestamp TrackRunIterator::dts() const {
   DCHECK(IsSampleValid());
-  return TimeDeltaFromRational(sample_dts_, run_itr_->timescale);
+  return DecodeTimestampFromRational(sample_dts_, run_itr_->timescale);
 }
 
-TimeDelta TrackRunIterator::cts() const {
+base::TimeDelta TrackRunIterator::cts() const {
   DCHECK(IsSampleValid());
   return TimeDeltaFromRational(sample_dts_ + sample_itr_->cts_offset,
                                run_itr_->timescale);
 }
 
-TimeDelta TrackRunIterator::duration() const {
+base::TimeDelta TrackRunIterator::duration() const {
   DCHECK(IsSampleValid());
   return TimeDeltaFromRational(sample_itr_->duration, run_itr_->timescale);
 }
@@ -447,6 +502,11 @@ bool TrackRunIterator::is_keyframe() const {
   return sample_itr_->is_keyframe;
 }
 
+bool TrackRunIterator::is_random_access_point() const {
+  DCHECK(IsSampleValid());
+  return sample_itr_->is_random_access_point;
+}
+
 const TrackEncryption& TrackRunIterator::track_encryption() const {
   if (is_audio())
     return audio_description().sinf.info.track_encryption;
@@ -454,10 +514,17 @@ const TrackEncryption& TrackRunIterator::track_encryption() const {
 }
 
 scoped_ptr<DecryptConfig> TrackRunIterator::GetDecryptConfig() {
+  DCHECK(is_encrypted());
+
+  if (cenc_info_.empty()) {
+    DCHECK_EQ(0, aux_info_size());
+    MEDIA_LOG(log_cb_) << "Aux Info is not available.";
+    return scoped_ptr<DecryptConfig>();
+  }
+
   size_t sample_idx = sample_itr_ - run_itr_->samples.begin();
-  DCHECK(sample_idx < cenc_info_.size());
+  DCHECK_LT(sample_idx, cenc_info_.size());
   const FrameCENCInfo& cenc_info = cenc_info_[sample_idx];
-  DCHECK(is_encrypted() && !AuxInfoNeedsToBeCached());
 
   size_t total_size = 0;
   if (!cenc_info.subsamples.empty() &&
@@ -467,7 +534,7 @@ scoped_ptr<DecryptConfig> TrackRunIterator::GetDecryptConfig() {
     return scoped_ptr<DecryptConfig>();
   }
 
-  const std::vector<uint8>& kid = track_encryption().default_kid;
+  const std::vector<uint8>& kid = GetKeyId(sample_idx);
   return scoped_ptr<DecryptConfig>(new DecryptConfig(
       std::string(reinterpret_cast<const char*>(&kid[0]), kid.size()),
       std::string(reinterpret_cast<const char*>(cenc_info.iv),
@@ -475,5 +542,40 @@ scoped_ptr<DecryptConfig> TrackRunIterator::GetDecryptConfig() {
       cenc_info.subsamples));
 }
 
+uint32 TrackRunIterator::GetGroupDescriptionIndex(uint32 sample_index) const {
+  DCHECK(IsRunValid());
+  DCHECK_LT(sample_index, run_itr_->samples.size());
+  return run_itr_->samples[sample_index].cenc_group_description_index;
+}
+
+const CencSampleEncryptionInfoEntry&
+TrackRunIterator::GetSampleEncryptionInfoEntry(
+    uint32 group_description_index) const {
+  DCHECK(IsRunValid());
+  DCHECK_NE(group_description_index, 0u);
+  DCHECK_LE(group_description_index, run_itr_->sample_encryption_info.size());
+  // |group_description_index| is 1-based. Subtract by 1 to index the vector.
+  return run_itr_->sample_encryption_info[group_description_index - 1];
+}
+
+bool TrackRunIterator::IsSampleEncrypted(size_t sample_index) const {
+  uint32 index = GetGroupDescriptionIndex(sample_index);
+  return (index == 0) ? track_encryption().is_encrypted
+                      : GetSampleEncryptionInfoEntry(index).is_encrypted;
+}
+
+const std::vector<uint8>& TrackRunIterator::GetKeyId(
+    size_t sample_index) const {
+  uint32 index = GetGroupDescriptionIndex(sample_index);
+  return (index == 0) ? track_encryption().default_kid
+                      : GetSampleEncryptionInfoEntry(index).key_id;
+}
+
+uint8 TrackRunIterator::GetIvSize(size_t sample_index) const {
+  uint32 index = GetGroupDescriptionIndex(sample_index);
+  return (index == 0) ? track_encryption().default_iv_size
+                      : GetSampleEncryptionInfoEntry(index).iv_size;
+}
+
 }  // namespace mp4
 }  // namespace media