Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | |
| 2 // Use of this source code is governed by a BSD-style license that can be | |
| 3 // found in the LICENSE file. | |
| 4 | |
| 5 #include "media/mp4/track_run_iterator.h" | |
| 6 | |
| 7 #include "media/mp4/rcheck.h" | |
| 8 #include <algorithm> | |
| 9 | |
| 10 namespace media { | |
| 11 namespace mp4 { | |
| 12 | |
| 13 base::TimeDelta TimeDeltaFromFrac(int64 numer, uint64 denom) { | |
| 14 return base::TimeDelta::FromMicroseconds( | |
|
acolwell GONE FROM CHROMIUM
2012/06/06 17:32:39
nit: Add a DCHECK_LT(numer, xxx) to alert us if we
strobe_
2012/06/07 16:33:54
Overflow happens around 300,000 years. But since i
| |
| 15 base::Time::kMicrosecondsPerSecond * numer / denom); | |
| 16 } | |
| 17 | |
| 18 const static uint32 kSampleIsDifferenceSampleFlagMask = 0x10000; | |
| 19 | |
| 20 TrackRunInfo::TrackRunInfo() {} | |
| 21 TrackRunInfo::~TrackRunInfo() {} | |
| 22 | |
| 23 TrackRunIterator::TrackRunIterator() {} | |
| 24 TrackRunIterator::~TrackRunIterator() {} | |
| 25 | |
| 26 template<typename T> bool FindByTrackID(uint32 track_id, | |
| 27 const std::vector<T>& ts, | |
|
acolwell GONE FROM CHROMIUM
2012/06/06 17:32:39
nit: more descriptive name please.
strobe_
2012/06/07 16:33:54
Oops, that was dead code.
| |
| 28 const T** result) { | |
| 29 for (size_t i = 0; i < ts.size(); i++) { | |
| 30 if (ts[i].track_id == track_id) { | |
| 31 *result = &ts[i]; | |
| 32 return true; | |
| 33 } | |
| 34 } | |
| 35 return false; | |
| 36 } | |
| 37 | |
| 38 void PopulateSampleInfo(const Track& trak, | |
| 39 const TrackExtends& trex, | |
| 40 const TrackFragmentHeader& tfhd, | |
| 41 const TrackFragmentRun& trun, | |
| 42 const size_t i, | |
| 43 SampleInfo* si) { | |
| 44 if (i < trun.sample_sizes.size()) { | |
| 45 si->size = trun.sample_sizes[i]; | |
| 46 } else if (tfhd.default_sample_size > 0) { | |
| 47 si->size = tfhd.default_sample_size; | |
| 48 } else { | |
| 49 si->size = trex.default_sample_size; | |
| 50 } | |
| 51 | |
| 52 const uint64 timescale = trak.media.header.timescale; | |
| 53 uint64 duration; | |
| 54 if (i < trun.sample_durations.size()) { | |
| 55 duration = trun.sample_durations[i]; | |
| 56 } else if (tfhd.default_sample_duration > 0) { | |
| 57 duration = tfhd.default_sample_duration; | |
| 58 } else { | |
| 59 duration = trex.default_sample_duration; | |
| 60 } | |
| 61 si->duration = TimeDeltaFromFrac(duration, timescale); | |
| 62 | |
| 63 if (i < trun.sample_composition_time_offsets.size()) { | |
| 64 si->cts_offset = TimeDeltaFromFrac(trun.sample_composition_time_offsets[i], | |
| 65 timescale); | |
| 66 } else { | |
| 67 si->cts_offset = TimeDelta::FromMicroseconds(0); | |
| 68 } | |
| 69 | |
| 70 uint32 flags; | |
| 71 if (i < trun.sample_flags.size()) { | |
| 72 flags = trun.sample_flags[i]; | |
| 73 } else if (tfhd.has_default_sample_flags) { | |
| 74 flags = tfhd.default_sample_flags; | |
| 75 } else { | |
| 76 flags = trex.default_sample_flags; | |
| 77 } | |
| 78 si->is_keyframe = !(flags & kSampleIsDifferenceSampleFlagMask); | |
| 79 } | |
| 80 | |
| 81 class CompareOffset { | |
| 82 public: | |
| 83 bool operator()(TrackRunInfo a, TrackRunInfo b) { | |
| 84 size_t a_min = a.sample_start_offset; | |
| 85 if (a.is_encrypted && a.cenc_start_offset < a_min) | |
| 86 a_min = a.cenc_start_offset; | |
| 87 size_t b_min = b.sample_start_offset; | |
| 88 if (b.is_encrypted && b.cenc_start_offset < b_min) | |
| 89 b_min = b.cenc_start_offset; | |
| 90 return a_min < b_min; | |
| 91 } | |
| 92 }; | |
| 93 | |
| 94 bool TrackRunIterator::Init(const Movie& moov, const MovieFragment& moof) { | |
| 95 runs_.clear(); | |
| 96 | |
| 97 for (size_t i = 0; i < moof.tracks.size(); i++) { | |
| 98 const TrackFragment& traf = moof.tracks[i]; | |
| 99 | |
| 100 const Track* trak = NULL; | |
| 101 for (size_t t = 0; t < moov.tracks.size(); t++) { | |
| 102 if (moov.tracks[t].header.track_id == traf.header.track_id) | |
| 103 trak = &moov.tracks[t]; | |
| 104 } | |
| 105 | |
| 106 const TrackExtends* trex = NULL; | |
| 107 for (size_t t = 0; t < moov.extends.tracks.size(); t++) { | |
| 108 if (moov.extends.tracks[t].track_id == traf.header.track_id) | |
| 109 trex = &moov.extends.tracks[t]; | |
| 110 } | |
| 111 RCHECK(trak && trex); | |
| 112 | |
| 113 const ProtectionSchemeInfo* sinf = NULL; | |
| 114 const SampleDescription& stsd = | |
| 115 trak->media.information.sample_table.description; | |
| 116 if (stsd.type == kAudio) { | |
| 117 sinf = &stsd.audio_entries[0].sinf; | |
| 118 } else if (stsd.type == kVideo) { | |
| 119 sinf = &stsd.video_entries[0].sinf; | |
| 120 } else { | |
| 121 DVLOG(1) << "Skipping unhandled track type"; | |
| 122 continue; | |
| 123 } | |
| 124 | |
| 125 for (size_t j = 0; j < traf.runs.size(); j++) { | |
| 126 const TrackFragmentRun& trun = traf.runs[j]; | |
| 127 TrackRunInfo tri; | |
| 128 tri.track_id = traf.header.track_id; | |
| 129 tri.start_dts = TimeDeltaFromFrac(traf.decode_time.decode_time, | |
| 130 trak->media.header.timescale); | |
| 131 tri.sample_start_offset = trun.data_offset; | |
| 132 tri.is_encrypted = sinf->info.track_encryption.is_encrypted; | |
| 133 // TODO(strobe): CENC recovery and testing | |
| 134 | |
| 135 tri.samples.resize(trun.sample_count); | |
| 136 | |
| 137 for (size_t k = 0; k < trun.sample_count; k++) { | |
| 138 PopulateSampleInfo(*trak, *trex, traf.header, trun, k, &tri.samples[k]); | |
| 139 } | |
| 140 runs_.push_back(tri); | |
| 141 } | |
| 142 } | |
| 143 | |
| 144 std::sort(runs_.begin(), runs_.end(), CompareOffset()); | |
| 145 run_itr_ = runs_.begin(); | |
| 146 min_clear_offset_itr_ = min_clear_offsets_.begin(); | |
| 147 ResetRun(); | |
| 148 return true; | |
| 149 } | |
| 150 | |
| 151 void TrackRunIterator::AdvanceRun() { | |
| 152 ++run_itr_; | |
| 153 if (min_clear_offset_itr_ != min_clear_offsets_.end()) | |
| 154 ++min_clear_offset_itr_; | |
| 155 ResetRun(); | |
| 156 } | |
| 157 | |
| 158 void TrackRunIterator::ResetRun() { | |
| 159 if (RunValid()) { | |
|
acolwell GONE FROM CHROMIUM
2012/06/06 17:32:39
nit: reverse check and return early.
strobe_
2012/06/07 16:33:54
Done.
| |
| 160 sample_dts_ = run_itr_->start_dts; | |
| 161 sample_offset_ = run_itr_->sample_start_offset; | |
| 162 sample_itr_ = run_itr_->samples.begin(); | |
| 163 } | |
| 164 } | |
| 165 | |
| 166 void TrackRunIterator::AdvanceSample() { | |
| 167 DCHECK(SampleValid()); | |
| 168 sample_dts_ += sample_itr_->duration; | |
| 169 sample_offset_ += sample_itr_->size; | |
| 170 // XXX frame_cenc_info_ | |
|
acolwell GONE FROM CHROMIUM
2012/06/06 17:32:39
Change this to a TODO?
strobe_
2012/06/07 16:33:54
Done.
| |
| 171 ++sample_itr_; | |
| 172 } | |
| 173 | |
| 174 bool TrackRunIterator::NeedsCENC() { | |
| 175 return is_encrypted(); | |
| 176 } | |
| 177 | |
| 178 bool TrackRunIterator::CacheCENC(const uint8* buf, size_t size) { | |
| 179 LOG(FATAL) << "Not implemented"; | |
| 180 return false; | |
| 181 } | |
| 182 | |
| 183 bool TrackRunIterator::RunValid() { | |
| 184 return run_itr_ != runs_.end(); | |
| 185 } | |
| 186 | |
| 187 bool TrackRunIterator::SampleValid() { | |
| 188 return RunValid() && (sample_itr_ != run_itr_->samples.end()); | |
| 189 } | |
| 190 | |
| 191 size_t TrackRunIterator::GetMaxClearOffset() { | |
| 192 size_t offset = kuint64max; | |
| 193 | |
| 194 if (SampleValid()) { | |
| 195 offset = std::min(offset, sample_offset_); | |
| 196 if (NeedsCENC()) { | |
| 197 offset = std::min(offset, cenc_offset()); | |
| 198 } | |
| 199 } | |
| 200 if (min_clear_offset_itr_ != min_clear_offsets_.end()) { | |
| 201 offset = std::min(offset, *min_clear_offset_itr_); | |
| 202 } | |
| 203 if (offset == kuint64max) return 0; | |
| 204 return offset; | |
| 205 } | |
| 206 | |
| 207 const FrameCENCInfo& TrackRunIterator::frame_cenc_info() { | |
| 208 DCHECK(is_encrypted()); | |
| 209 return frame_cenc_info_; | |
| 210 } | |
| 211 | |
| 212 } // namespace mp4 | |
| 213 } // namespace media | |
| OLD | NEW |