Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "media/mp4/track_run_iterator.h" | 5 #include "media/mp4/track_run_iterator.h" |
| 6 | 6 |
| 7 #include <algorithm> | 7 #include <algorithm> |
| 8 | 8 |
| 9 #include "media/base/stream_parser_buffer.h" | 9 #include "media/base/stream_parser_buffer.h" |
| 10 #include "media/mp4/rcheck.h" | 10 #include "media/mp4/rcheck.h" |
| 11 | 11 |
| 12 namespace { | |
| 13 static const uint32 kSampleIsDifferenceSampleFlagMask = 0x10000; | |
| 14 } | |
| 15 | |
| 12 namespace media { | 16 namespace media { |
| 13 namespace mp4 { | 17 namespace mp4 { |
| 14 | 18 |
| 15 struct SampleInfo { | 19 struct SampleInfo { |
| 16 int size; | 20 int size; |
| 17 int duration; | 21 int duration; |
| 18 int cts_offset; | 22 int cts_offset; |
| 19 bool is_keyframe; | 23 bool is_keyframe; |
| 20 }; | 24 }; |
| 21 | 25 |
| 22 struct TrackRunInfo { | 26 struct TrackRunInfo { |
| 23 uint32 track_id; | 27 uint32 track_id; |
| 24 std::vector<SampleInfo> samples; | 28 std::vector<SampleInfo> samples; |
| 25 int64 timescale; | 29 int64 timescale; |
| 26 int64 start_dts; | 30 int64 start_dts; |
| 27 int64 sample_start_offset; | 31 int64 sample_start_offset; |
| 28 | 32 |
| 29 bool is_audio; | 33 bool is_audio; |
| 30 const AudioSampleEntry* audio_description; | 34 const AudioSampleEntry* audio_description; |
| 31 const VideoSampleEntry* video_description; | 35 const VideoSampleEntry* video_description; |
| 32 | 36 |
| 37 int64 aux_info_start_offset; // Only valid if aux_info_total_size > 0. | |
| 38 int aux_info_default_size; | |
| 39 std::vector<uint8> aux_info_sizes; // Populated if default_size == 0. | |
| 40 int aux_info_total_size; | |
| 41 | |
| 33 TrackRunInfo(); | 42 TrackRunInfo(); |
| 34 ~TrackRunInfo(); | 43 ~TrackRunInfo(); |
| 35 }; | 44 }; |
| 36 | 45 |
| 37 TrackRunInfo::TrackRunInfo() | 46 TrackRunInfo::TrackRunInfo() |
| 38 : track_id(0), | 47 : track_id(0), |
| 39 timescale(-1), | 48 timescale(-1), |
| 40 start_dts(-1), | 49 start_dts(-1), |
| 41 sample_start_offset(-1), | 50 sample_start_offset(-1), |
| 42 is_audio(false) { | 51 is_audio(false), |
| 52 aux_info_start_offset(-1), | |
| 53 aux_info_default_size(-1), | |
| 54 aux_info_total_size(-1) { | |
| 43 } | 55 } |
| 44 TrackRunInfo::~TrackRunInfo() {} | 56 TrackRunInfo::~TrackRunInfo() {} |
| 45 | 57 |
| 46 TimeDelta TimeDeltaFromFrac(int64 numer, int64 denom) { | 58 TimeDelta TimeDeltaFromRational(int64 numer, int64 denom) { |
| 47 DCHECK_LT((numer > 0 ? numer : -numer), | 59 DCHECK_LT((numer > 0 ? numer : -numer), |
| 48 kint64max / base::Time::kMicrosecondsPerSecond); | 60 kint64max / base::Time::kMicrosecondsPerSecond); |
| 49 return TimeDelta::FromMicroseconds( | 61 return TimeDelta::FromMicroseconds( |
| 50 base::Time::kMicrosecondsPerSecond * numer / denom); | 62 base::Time::kMicrosecondsPerSecond * numer / denom); |
| 51 } | 63 } |
| 52 | 64 |
| 53 static const uint32 kSampleIsDifferenceSampleFlagMask = 0x10000; | |
| 54 | |
| 55 | |
| 56 TrackRunIterator::TrackRunIterator(const Movie* moov) | 65 TrackRunIterator::TrackRunIterator(const Movie* moov) |
| 57 : moov_(moov), sample_offset_(0) { | 66 : moov_(moov), sample_offset_(0) { |
| 58 CHECK(moov); | 67 CHECK(moov); |
| 59 } | 68 } |
| 60 TrackRunIterator::~TrackRunIterator() {} | 69 TrackRunIterator::~TrackRunIterator() {} |
| 61 | 70 |
| 62 static void PopulateSampleInfo(const TrackExtends& trex, | 71 static void PopulateSampleInfo(const TrackExtends& trex, |
| 63 const TrackFragmentHeader& tfhd, | 72 const TrackFragmentHeader& tfhd, |
| 64 const TrackFragmentRun& trun, | 73 const TrackFragmentRun& trun, |
| 65 const uint32 i, | 74 const uint32 i, |
| (...skipping 24 matching lines...) Expand all Loading... | |
| 90 if (i < trun.sample_flags.size()) { | 99 if (i < trun.sample_flags.size()) { |
| 91 flags = trun.sample_flags[i]; | 100 flags = trun.sample_flags[i]; |
| 92 } else if (tfhd.has_default_sample_flags) { | 101 } else if (tfhd.has_default_sample_flags) { |
| 93 flags = tfhd.default_sample_flags; | 102 flags = tfhd.default_sample_flags; |
| 94 } else { | 103 } else { |
| 95 flags = trex.default_sample_flags; | 104 flags = trex.default_sample_flags; |
| 96 } | 105 } |
| 97 sample_info->is_keyframe = !(flags & kSampleIsDifferenceSampleFlagMask); | 106 sample_info->is_keyframe = !(flags & kSampleIsDifferenceSampleFlagMask); |
| 98 } | 107 } |
| 99 | 108 |
| 109 // In well-structured encrypted media, each track run will be immediately | |
| 110 // preceded by its auxiliary information; this is the only optimal storage | |
| 111 // pattern in terms of minimum number of bytes from a serial stream needed to | |
| 112 // begin playback. It also allows us to optimize caching on memory-constrained | |
| 113 // architectures, because we can cache the relatively small auxiliary | |
| 114 // information for an entire run and then discard data from the input stream, | |
| 115 // instead of retaining the entire 'mdat' box. | |
| 116 // | |
| 117 // We optimize for this situation (with no loss of generality) by sorting track | |
| 118 // runs during iteration in order of their first data offset (either sample data | |
| 119 // or auxiliary data). | |
| 100 class CompareMinTrackRunDataOffset { | 120 class CompareMinTrackRunDataOffset { |
| 101 public: | 121 public: |
| 102 bool operator()(const TrackRunInfo& a, const TrackRunInfo& b) { | 122 bool operator()(const TrackRunInfo& a, const TrackRunInfo& b) { |
| 103 return a.sample_start_offset < b.sample_start_offset; | 123 int64 a_aux = a.aux_info_total_size ? a.aux_info_start_offset : kint64max; |
| 124 int64 b_aux = b.aux_info_total_size ? b.aux_info_start_offset : kint64max; | |
| 125 | |
| 126 int64 a_lesser = std::min(a_aux, a.sample_start_offset); | |
| 127 int64 a_greater = std::max(a_aux, a.sample_start_offset); | |
| 128 int64 b_lesser = std::min(b_aux, b.sample_start_offset); | |
| 129 int64 b_greater = std::max(b_aux, b.sample_start_offset); | |
| 130 | |
| 131 if (a_lesser == b_lesser) return a_greater < b_greater; | |
| 132 return a_lesser < b_lesser; | |
| 104 } | 133 } |
| 105 }; | 134 }; |
| 106 | 135 |
| 107 bool TrackRunIterator::Init(const MovieFragment& moof) { | 136 bool TrackRunIterator::Init(const MovieFragment& moof) { |
| 108 runs_.clear(); | 137 runs_.clear(); |
| 109 | 138 |
| 110 for (size_t i = 0; i < moof.tracks.size(); i++) { | 139 for (size_t i = 0; i < moof.tracks.size(); i++) { |
| 111 const TrackFragment& traf = moof.tracks[i]; | 140 const TrackFragment& traf = moof.tracks[i]; |
| 112 | 141 |
| 113 const Track* trak = NULL; | 142 const Track* trak = NULL; |
| 114 for (size_t t = 0; t < moov_->tracks.size(); t++) { | 143 for (size_t t = 0; t < moov_->tracks.size(); t++) { |
| 115 if (moov_->tracks[t].header.track_id == traf.header.track_id) | 144 if (moov_->tracks[t].header.track_id == traf.header.track_id) |
| 116 trak = &moov_->tracks[t]; | 145 trak = &moov_->tracks[t]; |
| 117 } | 146 } |
| 118 RCHECK(trak); | 147 RCHECK(trak); |
| 119 | 148 |
| 120 const TrackExtends* trex = NULL; | 149 const TrackExtends* trex = NULL; |
| 121 for (size_t t = 0; t < moov_->extends.tracks.size(); t++) { | 150 for (size_t t = 0; t < moov_->extends.tracks.size(); t++) { |
| 122 if (moov_->extends.tracks[t].track_id == traf.header.track_id) | 151 if (moov_->extends.tracks[t].track_id == traf.header.track_id) |
| 123 trex = &moov_->extends.tracks[t]; | 152 trex = &moov_->extends.tracks[t]; |
| 124 } | 153 } |
| 125 RCHECK(trex); | 154 RCHECK(trex); |
| 126 | 155 |
| 127 const SampleDescription& stsd = | 156 const SampleDescription& stsd = |
| 128 trak->media.information.sample_table.description; | 157 trak->media.information.sample_table.description; |
| 129 if (stsd.type != kAudio && stsd.type != kVideo) { | 158 if (stsd.type != kAudio && stsd.type != kVideo) { |
| 130 DVLOG(1) << "Skipping unhandled track type"; | 159 DVLOG(1) << "Skipping unhandled track type"; |
| 131 continue; | 160 continue; |
| 132 } | 161 } |
| 133 int desc_idx = traf.header.sample_description_index; | 162 size_t desc_idx = traf.header.sample_description_index; |
| 134 if (!desc_idx) desc_idx = trex->default_sample_description_index; | 163 if (!desc_idx) desc_idx = trex->default_sample_description_index; |
| 135 desc_idx--; // Descriptions are one-indexed in the file | 164 RCHECK(desc_idx > 0); // Descriptions are one-indexed in the file |
| 165 desc_idx -= 1; | |
| 136 | 166 |
| 137 int64 run_start_dts = traf.decode_time.decode_time; | 167 int64 run_start_dts = traf.decode_time.decode_time; |
| 168 int sample_count_sum = 0; | |
| 138 | 169 |
| 139 for (size_t j = 0; j < traf.runs.size(); j++) { | 170 for (size_t j = 0; j < traf.runs.size(); j++) { |
| 140 const TrackFragmentRun& trun = traf.runs[j]; | 171 const TrackFragmentRun& trun = traf.runs[j]; |
| 141 TrackRunInfo tri; | 172 TrackRunInfo tri; |
| 142 tri.track_id = traf.header.track_id; | 173 tri.track_id = traf.header.track_id; |
| 143 tri.timescale = trak->media.header.timescale; | 174 tri.timescale = trak->media.header.timescale; |
| 144 tri.start_dts = run_start_dts; | 175 tri.start_dts = run_start_dts; |
| 145 tri.sample_start_offset = trun.data_offset; | 176 tri.sample_start_offset = trun.data_offset; |
| 146 | 177 |
| 147 tri.is_audio = (stsd.type == kAudio); | 178 tri.is_audio = (stsd.type == kAudio); |
| 148 if (tri.is_audio) { | 179 if (tri.is_audio) { |
| 180 RCHECK(!stsd.audio_entries.empty()); | |
| 181 if (desc_idx > stsd.audio_entries.size()) | |
| 182 desc_idx = 0; | |
| 149 tri.audio_description = &stsd.audio_entries[desc_idx]; | 183 tri.audio_description = &stsd.audio_entries[desc_idx]; |
| 150 } else { | 184 } else { |
| 185 RCHECK(!stsd.video_entries.empty()); | |
| 186 if (desc_idx > stsd.video_entries.size()) | |
| 187 desc_idx = 0; | |
| 151 tri.video_description = &stsd.video_entries[desc_idx]; | 188 tri.video_description = &stsd.video_entries[desc_idx]; |
| 152 } | 189 } |
| 153 | 190 |
| 191 // Collect information from the auxiliary_offset entry with the same index | |
| 192 // in the 'saiz' container as the current run's index in the 'trun' | |
| 193 // container, if it is present. | |
| 194 if (traf.auxiliary_offset.offsets.size() > j) { | |
| 195 // There should be an auxiliary info entry corresponding to each sample | |
| 196 // in the auxiliary offset entry's corresponding track run. | |
| 197 RCHECK(traf.auxiliary_size.sample_count >= | |
| 198 sample_count_sum + trun.sample_count); | |
| 199 tri.aux_info_start_offset = traf.auxiliary_offset.offsets[j]; | |
| 200 tri.aux_info_default_size = | |
| 201 traf.auxiliary_size.default_sample_info_size; | |
| 202 if (tri.aux_info_default_size == 0) { | |
| 203 const std::vector<uint8>& sizes = | |
| 204 traf.auxiliary_size.sample_info_sizes; | |
| 205 tri.aux_info_sizes.insert(tri.aux_info_sizes.begin(), | |
| 206 sizes.begin() + sample_count_sum, | |
| 207 sizes.begin() + sample_count_sum + trun.sample_count); | |
| 208 } | |
| 209 | |
| 210 // If the default info size is positive, find the total size of the aux | |
| 211 // info block from it, otherwise sum over the individual sizes of each | |
| 212 // aux info entry in the aux_offset entry. | |
| 213 if (tri.aux_info_default_size) { | |
| 214 tri.aux_info_total_size = | |
| 215 tri.aux_info_default_size * trun.sample_count; | |
| 216 } else { | |
| 217 tri.aux_info_total_size = 0; | |
| 218 for (size_t k = 0; k < trun.sample_count; k++) { | |
| 219 tri.aux_info_total_size += tri.aux_info_sizes[k]; | |
| 220 } | |
| 221 } | |
| 222 } else { | |
| 223 tri.aux_info_start_offset = -1; | |
| 224 tri.aux_info_total_size = 0; | |
| 225 } | |
| 226 | |
| 154 tri.samples.resize(trun.sample_count); | 227 tri.samples.resize(trun.sample_count); |
| 155 for (size_t k = 0; k < trun.sample_count; k++) { | 228 for (size_t k = 0; k < trun.sample_count; k++) { |
| 156 PopulateSampleInfo(*trex, traf.header, trun, k, &tri.samples[k]); | 229 PopulateSampleInfo(*trex, traf.header, trun, k, &tri.samples[k]); |
| 157 run_start_dts += tri.samples[k].duration; | 230 run_start_dts += tri.samples[k].duration; |
| 158 } | 231 } |
| 159 runs_.push_back(tri); | 232 runs_.push_back(tri); |
| 233 sample_count_sum += trun.sample_count; | |
| 160 } | 234 } |
| 161 } | 235 } |
| 162 | 236 |
| 163 std::sort(runs_.begin(), runs_.end(), CompareMinTrackRunDataOffset()); | 237 std::sort(runs_.begin(), runs_.end(), CompareMinTrackRunDataOffset()); |
| 164 run_itr_ = runs_.begin(); | 238 run_itr_ = runs_.begin(); |
| 165 ResetRun(); | 239 ResetRun(); |
| 166 return true; | 240 return true; |
| 167 } | 241 } |
| 168 | 242 |
| 169 void TrackRunIterator::AdvanceRun() { | 243 void TrackRunIterator::AdvanceRun() { |
| 170 ++run_itr_; | 244 ++run_itr_; |
| 171 ResetRun(); | 245 ResetRun(); |
| 172 } | 246 } |
| 173 | 247 |
| 174 void TrackRunIterator::ResetRun() { | 248 void TrackRunIterator::ResetRun() { |
| 175 if (!RunIsValid()) return; | 249 if (!IsRunValid()) return; |
| 176 sample_dts_ = run_itr_->start_dts; | 250 sample_dts_ = run_itr_->start_dts; |
| 177 sample_offset_ = run_itr_->sample_start_offset; | 251 sample_offset_ = run_itr_->sample_start_offset; |
| 178 sample_itr_ = run_itr_->samples.begin(); | 252 sample_itr_ = run_itr_->samples.begin(); |
| 253 cenc_info_.clear(); | |
| 179 } | 254 } |
| 180 | 255 |
| 181 void TrackRunIterator::AdvanceSample() { | 256 void TrackRunIterator::AdvanceSample() { |
| 182 DCHECK(SampleIsValid()); | 257 DCHECK(IsSampleValid()); |
| 183 sample_dts_ += sample_itr_->duration; | 258 sample_dts_ += sample_itr_->duration; |
| 184 sample_offset_ += sample_itr_->size; | 259 sample_offset_ += sample_itr_->size; |
| 185 ++sample_itr_; | 260 ++sample_itr_; |
| 186 } | 261 } |
| 187 | 262 |
| 188 bool TrackRunIterator::RunIsValid() const { | 263 // This implementation only indicates a need for caching if CENC auxiliary |
| 264 // info is available in the stream. | |
| 265 bool TrackRunIterator::AuxInfoNeedsToBeCached() { | |
| 266 DCHECK(IsRunValid()); | |
| 267 return is_encrypted() && aux_info_size() > 0 && cenc_info_.size() == 0; | |
| 268 } | |
| 269 | |
| 270 // This implementation currently only caches CENC auxiliary info. | |
| 271 bool TrackRunIterator::CacheAuxInfo(const uint8* buf, int buf_size) { | |
| 272 RCHECK(AuxInfoNeedsToBeCached() && buf_size >= aux_info_size()); | |
| 273 | |
| 274 cenc_info_.resize(run_itr_->samples.size()); | |
| 275 int64 pos = 0; | |
| 276 for (size_t i = 0; i < run_itr_->samples.size(); i++) { | |
| 277 int info_size = run_itr_->aux_info_default_size; | |
| 278 if (!info_size) | |
| 279 info_size = run_itr_->aux_info_sizes[i]; | |
| 280 | |
| 281 BufferReader reader(buf + pos, info_size); | |
| 282 RCHECK(cenc_info_[i].Parse(track_encryption().default_iv_size, &reader)); | |
| 283 pos += info_size; | |
| 284 } | |
| 285 | |
| 286 return true; | |
| 287 } | |
| 288 | |
| 289 bool TrackRunIterator::IsRunValid() const { | |
| 189 return run_itr_ != runs_.end(); | 290 return run_itr_ != runs_.end(); |
| 190 } | 291 } |
| 191 | 292 |
| 192 bool TrackRunIterator::SampleIsValid() const { | 293 bool TrackRunIterator::IsSampleValid() const { |
| 193 return RunIsValid() && (sample_itr_ != run_itr_->samples.end()); | 294 return IsRunValid() && (sample_itr_ != run_itr_->samples.end()); |
| 194 } | 295 } |
| 195 | 296 |
| 297 // Because tracks are in sorted order and auxiliary information is cached when | |
| 298 // returning samples, it is guaranteed that no data will be required before the | |
| 299 // lesser of the minimum data offset of this track and the next in sequence. | |
| 300 // (The stronger condition - that no data is required before the minimum data | |
| 301 // offset of this track alone - is not guaranteed, because the BMFF spec does | |
| 302 // not have any inter-run ordering restrictions.) | |
| 196 int64 TrackRunIterator::GetMaxClearOffset() { | 303 int64 TrackRunIterator::GetMaxClearOffset() { |
| 197 int64 offset = kint64max; | 304 int64 offset = kint64max; |
| 198 | 305 |
| 199 if (SampleIsValid()) | 306 if (IsSampleValid()) { |
| 200 offset = std::min(offset, sample_offset_); | 307 offset = std::min(offset, sample_offset_); |
| 201 if (run_itr_ == runs_.end()) | 308 if (AuxInfoNeedsToBeCached()) |
| 202 return offset; | 309 offset = std::min(offset, aux_info_offset()); |
| 203 std::vector<TrackRunInfo>::const_iterator next_run = run_itr_ + 1; | 310 } |
| 204 if (next_run != runs_.end()) | 311 if (run_itr_ != runs_.end()) { |
| 205 offset = std::min(offset, next_run->sample_start_offset); | 312 std::vector<TrackRunInfo>::const_iterator next_run = run_itr_ + 1; |
| 313 if (next_run != runs_.end()) { | |
| 314 offset = std::min(offset, next_run->sample_start_offset); | |
| 315 if (next_run->aux_info_total_size) | |
| 316 offset = std::min(offset, next_run->aux_info_start_offset); | |
| 317 } | |
| 318 } | |
| 319 if (offset == kint64max) return 0; | |
| 206 return offset; | 320 return offset; |
| 207 } | 321 } |
| 208 | 322 |
| 209 TimeDelta TrackRunIterator::GetMinDecodeTimestamp() { | 323 TimeDelta TrackRunIterator::GetMinDecodeTimestamp() { |
| 210 TimeDelta dts = kInfiniteDuration(); | 324 TimeDelta dts = kInfiniteDuration(); |
| 211 for (size_t i = 0; i < runs_.size(); i++) { | 325 for (size_t i = 0; i < runs_.size(); i++) { |
| 212 dts = std::min(dts, TimeDeltaFromFrac(runs_[i].start_dts, | 326 dts = std::min(dts, TimeDeltaFromRational(runs_[i].start_dts, |
| 213 runs_[i].timescale)); | 327 runs_[i].timescale)); |
| 214 } | 328 } |
| 215 return dts; | 329 return dts; |
| 216 } | 330 } |
| 217 | 331 |
| 218 uint32 TrackRunIterator::track_id() const { | 332 uint32 TrackRunIterator::track_id() const { |
| 219 DCHECK(RunIsValid()); | 333 DCHECK(IsRunValid()); |
| 220 return run_itr_->track_id; | 334 return run_itr_->track_id; |
| 221 } | 335 } |
| 222 | 336 |
| 223 bool TrackRunIterator::is_encrypted() const { | 337 bool TrackRunIterator::is_encrypted() const { |
| 224 DCHECK(RunIsValid()); | 338 DCHECK(IsRunValid()); |
| 225 return false; | 339 return track_encryption().is_encrypted; |
| 340 } | |
| 341 | |
| 342 int64 TrackRunIterator::aux_info_offset() const { | |
| 343 return run_itr_->aux_info_start_offset; | |
| 344 } | |
| 345 | |
| 346 int TrackRunIterator::aux_info_size() const { | |
| 347 return run_itr_->aux_info_total_size; | |
| 226 } | 348 } |
| 227 | 349 |
| 228 bool TrackRunIterator::is_audio() const { | 350 bool TrackRunIterator::is_audio() const { |
| 229 DCHECK(RunIsValid()); | 351 DCHECK(IsRunValid()); |
| 230 return run_itr_->is_audio; | 352 return run_itr_->is_audio; |
| 231 } | 353 } |
| 232 | 354 |
| 233 const AudioSampleEntry& TrackRunIterator::audio_description() const { | 355 const AudioSampleEntry& TrackRunIterator::audio_description() const { |
| 234 DCHECK(is_audio()); | 356 DCHECK(is_audio()); |
| 235 DCHECK(run_itr_->audio_description); | 357 DCHECK(run_itr_->audio_description); |
| 236 return *run_itr_->audio_description; | 358 return *run_itr_->audio_description; |
| 237 } | 359 } |
| 238 | 360 |
| 239 const VideoSampleEntry& TrackRunIterator::video_description() const { | 361 const VideoSampleEntry& TrackRunIterator::video_description() const { |
| 240 DCHECK(!is_audio()); | 362 DCHECK(!is_audio()); |
| 241 DCHECK(run_itr_->video_description); | 363 DCHECK(run_itr_->video_description); |
| 242 return *run_itr_->video_description; | 364 return *run_itr_->video_description; |
| 243 } | 365 } |
| 244 | 366 |
| 245 int64 TrackRunIterator::sample_offset() const { | 367 int64 TrackRunIterator::sample_offset() const { |
| 246 DCHECK(SampleIsValid()); | 368 DCHECK(IsSampleValid()); |
| 247 return sample_offset_; | 369 return sample_offset_; |
| 248 } | 370 } |
| 249 | 371 |
| 250 int TrackRunIterator::sample_size() const { | 372 int TrackRunIterator::sample_size() const { |
| 251 DCHECK(SampleIsValid()); | 373 DCHECK(IsSampleValid()); |
| 252 return sample_itr_->size; | 374 return sample_itr_->size; |
| 253 } | 375 } |
| 254 | 376 |
| 255 TimeDelta TrackRunIterator::dts() const { | 377 TimeDelta TrackRunIterator::dts() const { |
| 256 DCHECK(SampleIsValid()); | 378 DCHECK(IsSampleValid()); |
| 257 return TimeDeltaFromFrac(sample_dts_, run_itr_->timescale); | 379 return TimeDeltaFromRational(sample_dts_, run_itr_->timescale); |
| 258 } | 380 } |
| 259 | 381 |
| 260 TimeDelta TrackRunIterator::cts() const { | 382 TimeDelta TrackRunIterator::cts() const { |
| 261 DCHECK(SampleIsValid()); | 383 DCHECK(IsSampleValid()); |
| 262 return TimeDeltaFromFrac(sample_dts_ + sample_itr_->cts_offset, | 384 return TimeDeltaFromRational(sample_dts_ + sample_itr_->cts_offset, |
| 263 run_itr_->timescale); | 385 run_itr_->timescale); |
| 264 } | 386 } |
| 265 | 387 |
| 266 TimeDelta TrackRunIterator::duration() const { | 388 TimeDelta TrackRunIterator::duration() const { |
| 267 DCHECK(SampleIsValid()); | 389 DCHECK(IsSampleValid()); |
| 268 return TimeDeltaFromFrac(sample_itr_->duration, run_itr_->timescale); | 390 return TimeDeltaFromRational(sample_itr_->duration, run_itr_->timescale); |
| 269 } | 391 } |
| 270 | 392 |
| 271 bool TrackRunIterator::is_keyframe() const { | 393 bool TrackRunIterator::is_keyframe() const { |
| 272 DCHECK(SampleIsValid()); | 394 DCHECK(IsSampleValid()); |
| 273 return sample_itr_->is_keyframe; | 395 return sample_itr_->is_keyframe; |
| 274 } | 396 } |
| 275 | 397 |
| 398 const TrackEncryption& TrackRunIterator::track_encryption() const { | |
| 399 if (is_audio()) | |
| 400 return audio_description().sinf.info.track_encryption; | |
| 401 return video_description().sinf.info.track_encryption; | |
| 402 } | |
| 403 | |
| 404 scoped_ptr<DecryptConfig> TrackRunIterator::GetDecryptConfig() { | |
| 405 size_t sample_idx = sample_itr_ - run_itr_->samples.begin(); | |
| 406 DCHECK(sample_idx < cenc_info_.size()); | |
| 407 const FrameCENCInfo& cenc_info = cenc_info_[sample_idx]; | |
| 408 DCHECK(is_encrypted() && !AuxInfoNeedsToBeCached()); | |
| 409 | |
| 410 if (!cenc_info.subsamples.empty() && | |
| 411 (cenc_info.GetTotalSizeOfSubsamples() != | |
| 412 static_cast<size_t>(sample_size()))) { | |
| 413 DVLOG(1) << "Incorrect CENC subsample size."; | |
| 414 return scoped_ptr<DecryptConfig>(); | |
| 415 } | |
| 416 | |
| 417 const std::vector<uint8>& kid = track_encryption().default_kid; | |
| 418 return scoped_ptr<DecryptConfig>(new DecryptConfig( | |
| 419 std::string(&kid[0], &kid[0] + kid.size()), | |
| 420 std::string(cenc_info.iv, cenc_info.iv + arraysize(cenc_info.iv)), | |
| 421 std::string(), | |
|
ddorwin
2012/07/24 01:00:10
May help with readability:
// No checksum in MP4
strobe_
2012/07/25 01:05:13
Done.
| |
| 422 0, | |
| 423 cenc_info.subsamples)); | |
| 424 } | |
| 425 | |
| 276 } // namespace mp4 | 426 } // namespace mp4 |
| 277 } // namespace media | 427 } // namespace media |
| OLD | NEW |