| OLD | NEW |
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 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/formats/mp4/track_run_iterator.h" | 5 #include "media/formats/mp4/track_run_iterator.h" |
| 6 | 6 |
| 7 #include <algorithm> | 7 #include <algorithm> |
| 8 #include <iomanip> | 8 #include <iomanip> |
| 9 #include <limits> |
| 9 | 10 |
| 10 #include "media/formats/mp4/rcheck.h" | 11 #include "media/formats/mp4/rcheck.h" |
| 11 #include "media/formats/mp4/sample_to_group_iterator.h" | 12 #include "media/formats/mp4/sample_to_group_iterator.h" |
| 12 | 13 |
| 13 namespace media { | 14 namespace media { |
| 14 namespace mp4 { | 15 namespace mp4 { |
| 15 | 16 |
| 16 struct SampleInfo { | 17 struct SampleInfo { |
| 17 int size; | 18 int size; |
| 18 int duration; | 19 int duration; |
| 19 int cts_offset; | 20 int cts_offset; |
| 20 bool is_keyframe; | 21 bool is_keyframe; |
| 21 uint32 cenc_group_description_index; | 22 uint32_t cenc_group_description_index; |
| 22 }; | 23 }; |
| 23 | 24 |
| 24 struct TrackRunInfo { | 25 struct TrackRunInfo { |
| 25 uint32 track_id; | 26 uint32_t track_id; |
| 26 std::vector<SampleInfo> samples; | 27 std::vector<SampleInfo> samples; |
| 27 int64 timescale; | 28 int64_t timescale; |
| 28 int64 start_dts; | 29 int64_t start_dts; |
| 29 int64 sample_start_offset; | 30 int64_t sample_start_offset; |
| 30 | 31 |
| 31 bool is_audio; | 32 bool is_audio; |
| 32 const AudioSampleEntry* audio_description; | 33 const AudioSampleEntry* audio_description; |
| 33 const VideoSampleEntry* video_description; | 34 const VideoSampleEntry* video_description; |
| 34 const SampleGroupDescription* track_sample_encryption_group; | 35 const SampleGroupDescription* track_sample_encryption_group; |
| 35 | 36 |
| 36 int64 aux_info_start_offset; // Only valid if aux_info_total_size > 0. | 37 int64_t aux_info_start_offset; // Only valid if aux_info_total_size > 0. |
| 37 int aux_info_default_size; | 38 int aux_info_default_size; |
| 38 std::vector<uint8> aux_info_sizes; // Populated if default_size == 0. | 39 std::vector<uint8_t> aux_info_sizes; // Populated if default_size == 0. |
| 39 int aux_info_total_size; | 40 int aux_info_total_size; |
| 40 | 41 |
| 41 std::vector<CencSampleEncryptionInfoEntry> fragment_sample_encryption_info; | 42 std::vector<CencSampleEncryptionInfoEntry> fragment_sample_encryption_info; |
| 42 | 43 |
| 43 TrackRunInfo(); | 44 TrackRunInfo(); |
| 44 ~TrackRunInfo(); | 45 ~TrackRunInfo(); |
| 45 }; | 46 }; |
| 46 | 47 |
| 47 TrackRunInfo::TrackRunInfo() | 48 TrackRunInfo::TrackRunInfo() |
| 48 : track_id(0), | 49 : track_id(0), |
| 49 timescale(-1), | 50 timescale(-1), |
| 50 start_dts(-1), | 51 start_dts(-1), |
| 51 sample_start_offset(-1), | 52 sample_start_offset(-1), |
| 52 is_audio(false), | 53 is_audio(false), |
| 53 aux_info_start_offset(-1), | 54 aux_info_start_offset(-1), |
| 54 aux_info_default_size(-1), | 55 aux_info_default_size(-1), |
| 55 aux_info_total_size(-1) { | 56 aux_info_total_size(-1) { |
| 56 } | 57 } |
| 57 TrackRunInfo::~TrackRunInfo() {} | 58 TrackRunInfo::~TrackRunInfo() {} |
| 58 | 59 |
| 59 base::TimeDelta TimeDeltaFromRational(int64 numer, int64 denom) { | 60 base::TimeDelta TimeDeltaFromRational(int64_t numer, int64_t denom) { |
| 60 // To avoid overflow, split the following calculation: | 61 // To avoid overflow, split the following calculation: |
| 61 // (numer * base::Time::kMicrosecondsPerSecond) / denom | 62 // (numer * base::Time::kMicrosecondsPerSecond) / denom |
| 62 // into: | 63 // into: |
| 63 // (numer / denom) * base::Time::kMicrosecondsPerSecond + | 64 // (numer / denom) * base::Time::kMicrosecondsPerSecond + |
| 64 // ((numer % denom) * base::Time::kMicrosecondsPerSecond) / denom | 65 // ((numer % denom) * base::Time::kMicrosecondsPerSecond) / denom |
| 65 int64 a = numer / denom; | 66 int64_t a = numer / denom; |
| 66 DCHECK_LE((a > 0 ? a : -a), kint64max / base::Time::kMicrosecondsPerSecond); | 67 DCHECK_LE((a > 0 ? a : -a), std::numeric_limits<int64_t>::max() / |
| 67 int64 timea_in_us = a * base::Time::kMicrosecondsPerSecond; | 68 base::Time::kMicrosecondsPerSecond); |
| 69 int64_t timea_in_us = a * base::Time::kMicrosecondsPerSecond; |
| 68 | 70 |
| 69 int64 b = numer % denom; | 71 int64_t b = numer % denom; |
| 70 DCHECK_LE((b > 0 ? b : -b), kint64max / base::Time::kMicrosecondsPerSecond); | 72 DCHECK_LE((b > 0 ? b : -b), std::numeric_limits<int64_t>::max() / |
| 71 int64 timeb_in_us = (b * base::Time::kMicrosecondsPerSecond) / denom; | 73 base::Time::kMicrosecondsPerSecond); |
| 74 int64_t timeb_in_us = (b * base::Time::kMicrosecondsPerSecond) / denom; |
| 72 | 75 |
| 73 DCHECK((timeb_in_us < 0) || (timea_in_us <= kint64max - timeb_in_us)); | 76 DCHECK((timeb_in_us < 0) || |
| 74 DCHECK((timeb_in_us > 0) || (timea_in_us >= kint64min - timeb_in_us)); | 77 (timea_in_us <= std::numeric_limits<int64_t>::max() - timeb_in_us)); |
| 78 DCHECK((timeb_in_us > 0) || |
| 79 (timea_in_us >= std::numeric_limits<int64_t>::min() - timeb_in_us)); |
| 75 return base::TimeDelta::FromMicroseconds(timea_in_us + timeb_in_us); | 80 return base::TimeDelta::FromMicroseconds(timea_in_us + timeb_in_us); |
| 76 } | 81 } |
| 77 | 82 |
| 78 DecodeTimestamp DecodeTimestampFromRational(int64 numer, int64 denom) { | 83 DecodeTimestamp DecodeTimestampFromRational(int64_t numer, int64_t denom) { |
| 79 return DecodeTimestamp::FromPresentationTime( | 84 return DecodeTimestamp::FromPresentationTime( |
| 80 TimeDeltaFromRational(numer, denom)); | 85 TimeDeltaFromRational(numer, denom)); |
| 81 } | 86 } |
| 82 | 87 |
| 83 TrackRunIterator::TrackRunIterator(const Movie* moov, | 88 TrackRunIterator::TrackRunIterator(const Movie* moov, |
| 84 const scoped_refptr<MediaLog>& media_log) | 89 const scoped_refptr<MediaLog>& media_log) |
| 85 : moov_(moov), media_log_(media_log), sample_offset_(0) { | 90 : moov_(moov), media_log_(media_log), sample_offset_(0) { |
| 86 CHECK(moov); | 91 CHECK(moov); |
| 87 } | 92 } |
| 88 | 93 |
| 89 TrackRunIterator::~TrackRunIterator() {} | 94 TrackRunIterator::~TrackRunIterator() {} |
| 90 | 95 |
| 91 static std::string HexFlags(uint32 flags) { | 96 static std::string HexFlags(uint32_t flags) { |
| 92 std::stringstream stream; | 97 std::stringstream stream; |
| 93 stream << std::setfill('0') << std::setw(sizeof(flags)*2) << std::hex | 98 stream << std::setfill('0') << std::setw(sizeof(flags)*2) << std::hex |
| 94 << flags; | 99 << flags; |
| 95 return stream.str(); | 100 return stream.str(); |
| 96 } | 101 } |
| 97 | 102 |
| 98 static bool PopulateSampleInfo(const TrackExtends& trex, | 103 static bool PopulateSampleInfo(const TrackExtends& trex, |
| 99 const TrackFragmentHeader& tfhd, | 104 const TrackFragmentHeader& tfhd, |
| 100 const TrackFragmentRun& trun, | 105 const TrackFragmentRun& trun, |
| 101 const int64 edit_list_offset, | 106 const int64_t edit_list_offset, |
| 102 const uint32 i, | 107 const uint32_t i, |
| 103 SampleInfo* sample_info, | 108 SampleInfo* sample_info, |
| 104 const SampleDependsOn sdtp_sample_depends_on, | 109 const SampleDependsOn sdtp_sample_depends_on, |
| 105 bool is_audio, | 110 bool is_audio, |
| 106 const scoped_refptr<MediaLog>& media_log) { | 111 const scoped_refptr<MediaLog>& media_log) { |
| 107 if (i < trun.sample_sizes.size()) { | 112 if (i < trun.sample_sizes.size()) { |
| 108 sample_info->size = trun.sample_sizes[i]; | 113 sample_info->size = trun.sample_sizes[i]; |
| 109 } else if (tfhd.default_sample_size > 0) { | 114 } else if (tfhd.default_sample_size > 0) { |
| 110 sample_info->size = tfhd.default_sample_size; | 115 sample_info->size = tfhd.default_sample_size; |
| 111 } else { | 116 } else { |
| 112 sample_info->size = trex.default_sample_size; | 117 sample_info->size = trex.default_sample_size; |
| 113 } | 118 } |
| 114 | 119 |
| 115 if (i < trun.sample_durations.size()) { | 120 if (i < trun.sample_durations.size()) { |
| 116 sample_info->duration = trun.sample_durations[i]; | 121 sample_info->duration = trun.sample_durations[i]; |
| 117 } else if (tfhd.default_sample_duration > 0) { | 122 } else if (tfhd.default_sample_duration > 0) { |
| 118 sample_info->duration = tfhd.default_sample_duration; | 123 sample_info->duration = tfhd.default_sample_duration; |
| 119 } else { | 124 } else { |
| 120 sample_info->duration = trex.default_sample_duration; | 125 sample_info->duration = trex.default_sample_duration; |
| 121 } | 126 } |
| 122 | 127 |
| 123 if (i < trun.sample_composition_time_offsets.size()) { | 128 if (i < trun.sample_composition_time_offsets.size()) { |
| 124 sample_info->cts_offset = trun.sample_composition_time_offsets[i]; | 129 sample_info->cts_offset = trun.sample_composition_time_offsets[i]; |
| 125 } else { | 130 } else { |
| 126 sample_info->cts_offset = 0; | 131 sample_info->cts_offset = 0; |
| 127 } | 132 } |
| 128 sample_info->cts_offset += edit_list_offset; | 133 sample_info->cts_offset += edit_list_offset; |
| 129 | 134 |
| 130 uint32 flags; | 135 uint32_t flags; |
| 131 if (i < trun.sample_flags.size()) { | 136 if (i < trun.sample_flags.size()) { |
| 132 flags = trun.sample_flags[i]; | 137 flags = trun.sample_flags[i]; |
| 133 DVLOG(4) << __FUNCTION__ << " trun sample flags " << HexFlags(flags); | 138 DVLOG(4) << __FUNCTION__ << " trun sample flags " << HexFlags(flags); |
| 134 } else if (tfhd.has_default_sample_flags) { | 139 } else if (tfhd.has_default_sample_flags) { |
| 135 flags = tfhd.default_sample_flags; | 140 flags = tfhd.default_sample_flags; |
| 136 DVLOG(4) << __FUNCTION__ << " tfhd sample flags " << HexFlags(flags); | 141 DVLOG(4) << __FUNCTION__ << " tfhd sample flags " << HexFlags(flags); |
| 137 } else { | 142 } else { |
| 138 flags = trex.default_sample_flags; | 143 flags = trex.default_sample_flags; |
| 139 DVLOG(4) << __FUNCTION__ << " trex sample flags " << HexFlags(flags); | 144 DVLOG(4) << __FUNCTION__ << " trex sample flags " << HexFlags(flags); |
| 140 } | 145 } |
| (...skipping 28 matching lines...) Expand all Loading... |
| 169 DVLOG(4) << __FUNCTION__ << " is_kf:" << sample_info->is_keyframe | 174 DVLOG(4) << __FUNCTION__ << " is_kf:" << sample_info->is_keyframe |
| 170 << " is_sync:" << sample_is_sync_sample | 175 << " is_sync:" << sample_is_sync_sample |
| 171 << " deps:" << sample_depends_on_others | 176 << " deps:" << sample_depends_on_others |
| 172 << " audio:" << is_audio; | 177 << " audio:" << is_audio; |
| 173 | 178 |
| 174 return true; | 179 return true; |
| 175 } | 180 } |
| 176 | 181 |
| 177 static const CencSampleEncryptionInfoEntry* GetSampleEncryptionInfoEntry( | 182 static const CencSampleEncryptionInfoEntry* GetSampleEncryptionInfoEntry( |
| 178 const TrackRunInfo& run_info, | 183 const TrackRunInfo& run_info, |
| 179 uint32 group_description_index) { | 184 uint32_t group_description_index) { |
| 180 const std::vector<CencSampleEncryptionInfoEntry>* entries = nullptr; | 185 const std::vector<CencSampleEncryptionInfoEntry>* entries = nullptr; |
| 181 | 186 |
| 182 // ISO-14496-12 Section 8.9.2.3 and 8.9.4 : group description index | 187 // ISO-14496-12 Section 8.9.2.3 and 8.9.4 : group description index |
| 183 // (1) ranges from 1 to the number of sample group entries in the track | 188 // (1) ranges from 1 to the number of sample group entries in the track |
| 184 // level SampleGroupDescription Box, or (2) takes the value 0 to | 189 // level SampleGroupDescription Box, or (2) takes the value 0 to |
| 185 // indicate that this sample is a member of no group, in this case, the | 190 // indicate that this sample is a member of no group, in this case, the |
| 186 // sample is associated with the default values specified in | 191 // sample is associated with the default values specified in |
| 187 // TrackEncryption Box, or (3) starts at 0x10001, i.e. the index value | 192 // TrackEncryption Box, or (3) starts at 0x10001, i.e. the index value |
| 188 // 1, with the value 1 in the top 16 bits, to reference fragment-local | 193 // 1, with the value 1 in the top 16 bits, to reference fragment-local |
| 189 // SampleGroupDescription Box. | 194 // SampleGroupDescription Box. |
| (...skipping 23 matching lines...) Expand all Loading... |
| 213 // architectures, because we can cache the relatively small auxiliary | 218 // architectures, because we can cache the relatively small auxiliary |
| 214 // information for an entire run and then discard data from the input stream, | 219 // information for an entire run and then discard data from the input stream, |
| 215 // instead of retaining the entire 'mdat' box. | 220 // instead of retaining the entire 'mdat' box. |
| 216 // | 221 // |
| 217 // We optimize for this situation (with no loss of generality) by sorting track | 222 // We optimize for this situation (with no loss of generality) by sorting track |
| 218 // runs during iteration in order of their first data offset (either sample data | 223 // runs during iteration in order of their first data offset (either sample data |
| 219 // or auxiliary data). | 224 // or auxiliary data). |
| 220 class CompareMinTrackRunDataOffset { | 225 class CompareMinTrackRunDataOffset { |
| 221 public: | 226 public: |
| 222 bool operator()(const TrackRunInfo& a, const TrackRunInfo& b) { | 227 bool operator()(const TrackRunInfo& a, const TrackRunInfo& b) { |
| 223 int64 a_aux = a.aux_info_total_size ? a.aux_info_start_offset : kint64max; | 228 int64_t a_aux = a.aux_info_total_size ? a.aux_info_start_offset |
| 224 int64 b_aux = b.aux_info_total_size ? b.aux_info_start_offset : kint64max; | 229 : std::numeric_limits<int64_t>::max(); |
| 230 int64_t b_aux = b.aux_info_total_size ? b.aux_info_start_offset |
| 231 : std::numeric_limits<int64_t>::max(); |
| 225 | 232 |
| 226 int64 a_lesser = std::min(a_aux, a.sample_start_offset); | 233 int64_t a_lesser = std::min(a_aux, a.sample_start_offset); |
| 227 int64 a_greater = std::max(a_aux, a.sample_start_offset); | 234 int64_t a_greater = std::max(a_aux, a.sample_start_offset); |
| 228 int64 b_lesser = std::min(b_aux, b.sample_start_offset); | 235 int64_t b_lesser = std::min(b_aux, b.sample_start_offset); |
| 229 int64 b_greater = std::max(b_aux, b.sample_start_offset); | 236 int64_t b_greater = std::max(b_aux, b.sample_start_offset); |
| 230 | 237 |
| 231 if (a_lesser == b_lesser) return a_greater < b_greater; | 238 if (a_lesser == b_lesser) return a_greater < b_greater; |
| 232 return a_lesser < b_lesser; | 239 return a_lesser < b_lesser; |
| 233 } | 240 } |
| 234 }; | 241 }; |
| 235 | 242 |
| 236 bool TrackRunIterator::Init(const MovieFragment& moof) { | 243 bool TrackRunIterator::Init(const MovieFragment& moof) { |
| 237 runs_.clear(); | 244 runs_.clear(); |
| 238 | 245 |
| 239 for (size_t i = 0; i < moof.tracks.size(); i++) { | 246 for (size_t i = 0; i < moof.tracks.size(); i++) { |
| (...skipping 21 matching lines...) Expand all Loading... |
| 261 } | 268 } |
| 262 size_t desc_idx = traf.header.sample_description_index; | 269 size_t desc_idx = traf.header.sample_description_index; |
| 263 if (!desc_idx) desc_idx = trex->default_sample_description_index; | 270 if (!desc_idx) desc_idx = trex->default_sample_description_index; |
| 264 RCHECK(desc_idx > 0); // Descriptions are one-indexed in the file | 271 RCHECK(desc_idx > 0); // Descriptions are one-indexed in the file |
| 265 desc_idx -= 1; | 272 desc_idx -= 1; |
| 266 | 273 |
| 267 // Process edit list to remove CTS offset introduced in the presence of | 274 // Process edit list to remove CTS offset introduced in the presence of |
| 268 // B-frames (those that contain a single edit with a nonnegative media | 275 // B-frames (those that contain a single edit with a nonnegative media |
| 269 // time). Other uses of edit lists are not supported, as they are | 276 // time). Other uses of edit lists are not supported, as they are |
| 270 // both uncommon and better served by higher-level protocols. | 277 // both uncommon and better served by higher-level protocols. |
| 271 int64 edit_list_offset = 0; | 278 int64_t edit_list_offset = 0; |
| 272 const std::vector<EditListEntry>& edits = trak->edit.list.edits; | 279 const std::vector<EditListEntry>& edits = trak->edit.list.edits; |
| 273 if (!edits.empty()) { | 280 if (!edits.empty()) { |
| 274 if (edits.size() > 1) | 281 if (edits.size() > 1) |
| 275 DVLOG(1) << "Multi-entry edit box detected; some components ignored."; | 282 DVLOG(1) << "Multi-entry edit box detected; some components ignored."; |
| 276 | 283 |
| 277 if (edits[0].media_time < 0) { | 284 if (edits[0].media_time < 0) { |
| 278 DVLOG(1) << "Empty edit list entry ignored."; | 285 DVLOG(1) << "Empty edit list entry ignored."; |
| 279 } else { | 286 } else { |
| 280 edit_list_offset = -edits[0].media_time; | 287 edit_list_offset = -edits[0].media_time; |
| 281 } | 288 } |
| 282 } | 289 } |
| 283 | 290 |
| 284 SampleToGroupIterator sample_to_group_itr(traf.sample_to_group); | 291 SampleToGroupIterator sample_to_group_itr(traf.sample_to_group); |
| 285 bool is_sample_to_group_valid = sample_to_group_itr.IsValid(); | 292 bool is_sample_to_group_valid = sample_to_group_itr.IsValid(); |
| 286 | 293 |
| 287 int64 run_start_dts = traf.decode_time.decode_time; | 294 int64_t run_start_dts = traf.decode_time.decode_time; |
| 288 int sample_count_sum = 0; | 295 int sample_count_sum = 0; |
| 289 for (size_t j = 0; j < traf.runs.size(); j++) { | 296 for (size_t j = 0; j < traf.runs.size(); j++) { |
| 290 const TrackFragmentRun& trun = traf.runs[j]; | 297 const TrackFragmentRun& trun = traf.runs[j]; |
| 291 TrackRunInfo tri; | 298 TrackRunInfo tri; |
| 292 tri.track_id = traf.header.track_id; | 299 tri.track_id = traf.header.track_id; |
| 293 tri.timescale = trak->media.header.timescale; | 300 tri.timescale = trak->media.header.timescale; |
| 294 tri.start_dts = run_start_dts; | 301 tri.start_dts = run_start_dts; |
| 295 tri.sample_start_offset = trun.data_offset; | 302 tri.sample_start_offset = trun.data_offset; |
| 296 tri.track_sample_encryption_group = | 303 tri.track_sample_encryption_group = |
| 297 &trak->media.information.sample_table.sample_group_description; | 304 &trak->media.information.sample_table.sample_group_description; |
| (...skipping 18 matching lines...) Expand all Loading... |
| 316 // container, if it is present. | 323 // container, if it is present. |
| 317 if (traf.auxiliary_offset.offsets.size() > j) { | 324 if (traf.auxiliary_offset.offsets.size() > j) { |
| 318 // There should be an auxiliary info entry corresponding to each sample | 325 // There should be an auxiliary info entry corresponding to each sample |
| 319 // in the auxiliary offset entry's corresponding track run. | 326 // in the auxiliary offset entry's corresponding track run. |
| 320 RCHECK(traf.auxiliary_size.sample_count >= | 327 RCHECK(traf.auxiliary_size.sample_count >= |
| 321 sample_count_sum + trun.sample_count); | 328 sample_count_sum + trun.sample_count); |
| 322 tri.aux_info_start_offset = traf.auxiliary_offset.offsets[j]; | 329 tri.aux_info_start_offset = traf.auxiliary_offset.offsets[j]; |
| 323 tri.aux_info_default_size = | 330 tri.aux_info_default_size = |
| 324 traf.auxiliary_size.default_sample_info_size; | 331 traf.auxiliary_size.default_sample_info_size; |
| 325 if (tri.aux_info_default_size == 0) { | 332 if (tri.aux_info_default_size == 0) { |
| 326 const std::vector<uint8>& sizes = | 333 const std::vector<uint8_t>& sizes = |
| 327 traf.auxiliary_size.sample_info_sizes; | 334 traf.auxiliary_size.sample_info_sizes; |
| 328 tri.aux_info_sizes.insert(tri.aux_info_sizes.begin(), | 335 tri.aux_info_sizes.insert(tri.aux_info_sizes.begin(), |
| 329 sizes.begin() + sample_count_sum, | 336 sizes.begin() + sample_count_sum, |
| 330 sizes.begin() + sample_count_sum + trun.sample_count); | 337 sizes.begin() + sample_count_sum + trun.sample_count); |
| 331 } | 338 } |
| 332 | 339 |
| 333 // If the default info size is positive, find the total size of the aux | 340 // If the default info size is positive, find the total size of the aux |
| 334 // info block from it, otherwise sum over the individual sizes of each | 341 // info block from it, otherwise sum over the individual sizes of each |
| 335 // aux info entry in the aux_offset entry. | 342 // aux info entry in the aux_offset entry. |
| 336 if (tri.aux_info_default_size) { | 343 if (tri.aux_info_default_size) { |
| (...skipping 20 matching lines...) Expand all Loading... |
| 357 | 364 |
| 358 run_start_dts += tri.samples[k].duration; | 365 run_start_dts += tri.samples[k].duration; |
| 359 | 366 |
| 360 if (!is_sample_to_group_valid) { | 367 if (!is_sample_to_group_valid) { |
| 361 // Set group description index to 0 to read encryption information | 368 // Set group description index to 0 to read encryption information |
| 362 // from TrackEncryption Box. | 369 // from TrackEncryption Box. |
| 363 tri.samples[k].cenc_group_description_index = 0; | 370 tri.samples[k].cenc_group_description_index = 0; |
| 364 continue; | 371 continue; |
| 365 } | 372 } |
| 366 | 373 |
| 367 uint32 index = sample_to_group_itr.group_description_index(); | 374 uint32_t index = sample_to_group_itr.group_description_index(); |
| 368 tri.samples[k].cenc_group_description_index = index; | 375 tri.samples[k].cenc_group_description_index = index; |
| 369 if (index != 0) | 376 if (index != 0) |
| 370 RCHECK(GetSampleEncryptionInfoEntry(tri, index)); | 377 RCHECK(GetSampleEncryptionInfoEntry(tri, index)); |
| 371 is_sample_to_group_valid = sample_to_group_itr.Advance(); | 378 is_sample_to_group_valid = sample_to_group_itr.Advance(); |
| 372 } | 379 } |
| 373 runs_.push_back(tri); | 380 runs_.push_back(tri); |
| 374 sample_count_sum += trun.sample_count; | 381 sample_count_sum += trun.sample_count; |
| 375 } | 382 } |
| 376 | 383 |
| 377 // We should have iterated through all samples in SampleToGroup Box. | 384 // We should have iterated through all samples in SampleToGroup Box. |
| (...skipping 27 matching lines...) Expand all Loading... |
| 405 } | 412 } |
| 406 | 413 |
| 407 // This implementation only indicates a need for caching if CENC auxiliary | 414 // This implementation only indicates a need for caching if CENC auxiliary |
| 408 // info is available in the stream. | 415 // info is available in the stream. |
| 409 bool TrackRunIterator::AuxInfoNeedsToBeCached() { | 416 bool TrackRunIterator::AuxInfoNeedsToBeCached() { |
| 410 DCHECK(IsRunValid()); | 417 DCHECK(IsRunValid()); |
| 411 return aux_info_size() > 0 && cenc_info_.size() == 0; | 418 return aux_info_size() > 0 && cenc_info_.size() == 0; |
| 412 } | 419 } |
| 413 | 420 |
| 414 // This implementation currently only caches CENC auxiliary info. | 421 // This implementation currently only caches CENC auxiliary info. |
| 415 bool TrackRunIterator::CacheAuxInfo(const uint8* buf, int buf_size) { | 422 bool TrackRunIterator::CacheAuxInfo(const uint8_t* buf, int buf_size) { |
| 416 RCHECK(AuxInfoNeedsToBeCached() && buf_size >= aux_info_size()); | 423 RCHECK(AuxInfoNeedsToBeCached() && buf_size >= aux_info_size()); |
| 417 | 424 |
| 418 cenc_info_.resize(run_itr_->samples.size()); | 425 cenc_info_.resize(run_itr_->samples.size()); |
| 419 int64 pos = 0; | 426 int64_t pos = 0; |
| 420 for (size_t i = 0; i < run_itr_->samples.size(); i++) { | 427 for (size_t i = 0; i < run_itr_->samples.size(); i++) { |
| 421 int info_size = run_itr_->aux_info_default_size; | 428 int info_size = run_itr_->aux_info_default_size; |
| 422 if (!info_size) | 429 if (!info_size) |
| 423 info_size = run_itr_->aux_info_sizes[i]; | 430 info_size = run_itr_->aux_info_sizes[i]; |
| 424 | 431 |
| 425 if (IsSampleEncrypted(i)) { | 432 if (IsSampleEncrypted(i)) { |
| 426 BufferReader reader(buf + pos, info_size); | 433 BufferReader reader(buf + pos, info_size); |
| 427 RCHECK(cenc_info_[i].Parse(GetIvSize(i), &reader)); | 434 RCHECK(cenc_info_[i].Parse(GetIvSize(i), &reader)); |
| 428 } | 435 } |
| 429 pos += info_size; | 436 pos += info_size; |
| 430 } | 437 } |
| 431 | 438 |
| 432 return true; | 439 return true; |
| 433 } | 440 } |
| 434 | 441 |
| 435 bool TrackRunIterator::IsRunValid() const { | 442 bool TrackRunIterator::IsRunValid() const { |
| 436 return run_itr_ != runs_.end(); | 443 return run_itr_ != runs_.end(); |
| 437 } | 444 } |
| 438 | 445 |
| 439 bool TrackRunIterator::IsSampleValid() const { | 446 bool TrackRunIterator::IsSampleValid() const { |
| 440 return IsRunValid() && (sample_itr_ != run_itr_->samples.end()); | 447 return IsRunValid() && (sample_itr_ != run_itr_->samples.end()); |
| 441 } | 448 } |
| 442 | 449 |
| 443 // Because tracks are in sorted order and auxiliary information is cached when | 450 // Because tracks are in sorted order and auxiliary information is cached when |
| 444 // returning samples, it is guaranteed that no data will be required before the | 451 // returning samples, it is guaranteed that no data will be required before the |
| 445 // lesser of the minimum data offset of this track and the next in sequence. | 452 // lesser of the minimum data offset of this track and the next in sequence. |
| 446 // (The stronger condition - that no data is required before the minimum data | 453 // (The stronger condition - that no data is required before the minimum data |
| 447 // offset of this track alone - is not guaranteed, because the BMFF spec does | 454 // offset of this track alone - is not guaranteed, because the BMFF spec does |
| 448 // not have any inter-run ordering restrictions.) | 455 // not have any inter-run ordering restrictions.) |
| 449 int64 TrackRunIterator::GetMaxClearOffset() { | 456 int64_t TrackRunIterator::GetMaxClearOffset() { |
| 450 int64 offset = kint64max; | 457 int64_t offset = std::numeric_limits<int64_t>::max(); |
| 451 | 458 |
| 452 if (IsSampleValid()) { | 459 if (IsSampleValid()) { |
| 453 offset = std::min(offset, sample_offset_); | 460 offset = std::min(offset, sample_offset_); |
| 454 if (AuxInfoNeedsToBeCached()) | 461 if (AuxInfoNeedsToBeCached()) |
| 455 offset = std::min(offset, aux_info_offset()); | 462 offset = std::min(offset, aux_info_offset()); |
| 456 } | 463 } |
| 457 if (run_itr_ != runs_.end()) { | 464 if (run_itr_ != runs_.end()) { |
| 458 std::vector<TrackRunInfo>::const_iterator next_run = run_itr_ + 1; | 465 std::vector<TrackRunInfo>::const_iterator next_run = run_itr_ + 1; |
| 459 if (next_run != runs_.end()) { | 466 if (next_run != runs_.end()) { |
| 460 offset = std::min(offset, next_run->sample_start_offset); | 467 offset = std::min(offset, next_run->sample_start_offset); |
| 461 if (next_run->aux_info_total_size) | 468 if (next_run->aux_info_total_size) |
| 462 offset = std::min(offset, next_run->aux_info_start_offset); | 469 offset = std::min(offset, next_run->aux_info_start_offset); |
| 463 } | 470 } |
| 464 } | 471 } |
| 465 if (offset == kint64max) return 0; | 472 if (offset == std::numeric_limits<int64_t>::max()) |
| 473 return 0; |
| 466 return offset; | 474 return offset; |
| 467 } | 475 } |
| 468 | 476 |
| 469 uint32 TrackRunIterator::track_id() const { | 477 uint32_t TrackRunIterator::track_id() const { |
| 470 DCHECK(IsRunValid()); | 478 DCHECK(IsRunValid()); |
| 471 return run_itr_->track_id; | 479 return run_itr_->track_id; |
| 472 } | 480 } |
| 473 | 481 |
| 474 bool TrackRunIterator::is_encrypted() const { | 482 bool TrackRunIterator::is_encrypted() const { |
| 475 DCHECK(IsSampleValid()); | 483 DCHECK(IsSampleValid()); |
| 476 return IsSampleEncrypted(sample_itr_ - run_itr_->samples.begin()); | 484 return IsSampleEncrypted(sample_itr_ - run_itr_->samples.begin()); |
| 477 } | 485 } |
| 478 | 486 |
| 479 int64 TrackRunIterator::aux_info_offset() const { | 487 int64_t TrackRunIterator::aux_info_offset() const { |
| 480 return run_itr_->aux_info_start_offset; | 488 return run_itr_->aux_info_start_offset; |
| 481 } | 489 } |
| 482 | 490 |
| 483 int TrackRunIterator::aux_info_size() const { | 491 int TrackRunIterator::aux_info_size() const { |
| 484 return run_itr_->aux_info_total_size; | 492 return run_itr_->aux_info_total_size; |
| 485 } | 493 } |
| 486 | 494 |
| 487 bool TrackRunIterator::is_audio() const { | 495 bool TrackRunIterator::is_audio() const { |
| 488 DCHECK(IsRunValid()); | 496 DCHECK(IsRunValid()); |
| 489 return run_itr_->is_audio; | 497 return run_itr_->is_audio; |
| 490 } | 498 } |
| 491 | 499 |
| 492 const AudioSampleEntry& TrackRunIterator::audio_description() const { | 500 const AudioSampleEntry& TrackRunIterator::audio_description() const { |
| 493 DCHECK(is_audio()); | 501 DCHECK(is_audio()); |
| 494 DCHECK(run_itr_->audio_description); | 502 DCHECK(run_itr_->audio_description); |
| 495 return *run_itr_->audio_description; | 503 return *run_itr_->audio_description; |
| 496 } | 504 } |
| 497 | 505 |
| 498 const VideoSampleEntry& TrackRunIterator::video_description() const { | 506 const VideoSampleEntry& TrackRunIterator::video_description() const { |
| 499 DCHECK(!is_audio()); | 507 DCHECK(!is_audio()); |
| 500 DCHECK(run_itr_->video_description); | 508 DCHECK(run_itr_->video_description); |
| 501 return *run_itr_->video_description; | 509 return *run_itr_->video_description; |
| 502 } | 510 } |
| 503 | 511 |
| 504 int64 TrackRunIterator::sample_offset() const { | 512 int64_t TrackRunIterator::sample_offset() const { |
| 505 DCHECK(IsSampleValid()); | 513 DCHECK(IsSampleValid()); |
| 506 return sample_offset_; | 514 return sample_offset_; |
| 507 } | 515 } |
| 508 | 516 |
| 509 int TrackRunIterator::sample_size() const { | 517 int TrackRunIterator::sample_size() const { |
| 510 DCHECK(IsSampleValid()); | 518 DCHECK(IsSampleValid()); |
| 511 return sample_itr_->size; | 519 return sample_itr_->size; |
| 512 } | 520 } |
| 513 | 521 |
| 514 DecodeTimestamp TrackRunIterator::dts() const { | 522 DecodeTimestamp TrackRunIterator::dts() const { |
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 552 const FrameCENCInfo& cenc_info = cenc_info_[sample_idx]; | 560 const FrameCENCInfo& cenc_info = cenc_info_[sample_idx]; |
| 553 | 561 |
| 554 size_t total_size = 0; | 562 size_t total_size = 0; |
| 555 if (!cenc_info.subsamples.empty() && | 563 if (!cenc_info.subsamples.empty() && |
| 556 (!cenc_info.GetTotalSizeOfSubsamples(&total_size) || | 564 (!cenc_info.GetTotalSizeOfSubsamples(&total_size) || |
| 557 total_size != static_cast<size_t>(sample_size()))) { | 565 total_size != static_cast<size_t>(sample_size()))) { |
| 558 MEDIA_LOG(ERROR, media_log_) << "Incorrect CENC subsample size."; | 566 MEDIA_LOG(ERROR, media_log_) << "Incorrect CENC subsample size."; |
| 559 return scoped_ptr<DecryptConfig>(); | 567 return scoped_ptr<DecryptConfig>(); |
| 560 } | 568 } |
| 561 | 569 |
| 562 const std::vector<uint8>& kid = GetKeyId(sample_idx); | 570 const std::vector<uint8_t>& kid = GetKeyId(sample_idx); |
| 563 return scoped_ptr<DecryptConfig>(new DecryptConfig( | 571 return scoped_ptr<DecryptConfig>(new DecryptConfig( |
| 564 std::string(reinterpret_cast<const char*>(&kid[0]), kid.size()), | 572 std::string(reinterpret_cast<const char*>(&kid[0]), kid.size()), |
| 565 std::string(reinterpret_cast<const char*>(cenc_info.iv), | 573 std::string(reinterpret_cast<const char*>(cenc_info.iv), |
| 566 arraysize(cenc_info.iv)), | 574 arraysize(cenc_info.iv)), |
| 567 cenc_info.subsamples)); | 575 cenc_info.subsamples)); |
| 568 } | 576 } |
| 569 | 577 |
| 570 uint32 TrackRunIterator::GetGroupDescriptionIndex(uint32 sample_index) const { | 578 uint32_t TrackRunIterator::GetGroupDescriptionIndex( |
| 579 uint32_t sample_index) const { |
| 571 DCHECK(IsRunValid()); | 580 DCHECK(IsRunValid()); |
| 572 DCHECK_LT(sample_index, run_itr_->samples.size()); | 581 DCHECK_LT(sample_index, run_itr_->samples.size()); |
| 573 return run_itr_->samples[sample_index].cenc_group_description_index; | 582 return run_itr_->samples[sample_index].cenc_group_description_index; |
| 574 } | 583 } |
| 575 | 584 |
| 576 bool TrackRunIterator::IsSampleEncrypted(size_t sample_index) const { | 585 bool TrackRunIterator::IsSampleEncrypted(size_t sample_index) const { |
| 577 uint32 index = GetGroupDescriptionIndex(sample_index); | 586 uint32_t index = GetGroupDescriptionIndex(sample_index); |
| 578 return (index == 0) | 587 return (index == 0) |
| 579 ? track_encryption().is_encrypted | 588 ? track_encryption().is_encrypted |
| 580 : GetSampleEncryptionInfoEntry(*run_itr_, index)->is_encrypted; | 589 : GetSampleEncryptionInfoEntry(*run_itr_, index)->is_encrypted; |
| 581 } | 590 } |
| 582 | 591 |
| 583 const std::vector<uint8>& TrackRunIterator::GetKeyId( | 592 const std::vector<uint8_t>& TrackRunIterator::GetKeyId( |
| 584 size_t sample_index) const { | 593 size_t sample_index) const { |
| 585 uint32 index = GetGroupDescriptionIndex(sample_index); | 594 uint32_t index = GetGroupDescriptionIndex(sample_index); |
| 586 return (index == 0) ? track_encryption().default_kid | 595 return (index == 0) ? track_encryption().default_kid |
| 587 : GetSampleEncryptionInfoEntry(*run_itr_, index)->key_id; | 596 : GetSampleEncryptionInfoEntry(*run_itr_, index)->key_id; |
| 588 } | 597 } |
| 589 | 598 |
| 590 uint8 TrackRunIterator::GetIvSize(size_t sample_index) const { | 599 uint8_t TrackRunIterator::GetIvSize(size_t sample_index) const { |
| 591 uint32 index = GetGroupDescriptionIndex(sample_index); | 600 uint32_t index = GetGroupDescriptionIndex(sample_index); |
| 592 return (index == 0) ? track_encryption().default_iv_size | 601 return (index == 0) ? track_encryption().default_iv_size |
| 593 : GetSampleEncryptionInfoEntry(*run_itr_, index)->iv_size; | 602 : GetSampleEncryptionInfoEntry(*run_itr_, index)->iv_size; |
| 594 } | 603 } |
| 595 | 604 |
| 596 } // namespace mp4 | 605 } // namespace mp4 |
| 597 } // namespace media | 606 } // namespace media |
| OLD | NEW |