1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/content/media/encoder/fmp4_muxer/ISOMediaBoxes.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,1537 @@ 1.4 +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-*/ 1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this file, 1.7 + * You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.8 + 1.9 +#include <climits> 1.10 +#include "TrackMetadataBase.h" 1.11 +#include "ISOMediaBoxes.h" 1.12 +#include "ISOControl.h" 1.13 +#include "ISOMediaWriter.h" 1.14 +#include "EncodedFrameContainer.h" 1.15 +#include "ISOTrackMetadata.h" 1.16 +#include "MP4ESDS.h" 1.17 +#include "AMRBox.h" 1.18 +#include "AVCBox.h" 1.19 +#include "VideoUtils.h" 1.20 + 1.21 +namespace mozilla { 1.22 + 1.23 +// 14496-12 6.2.2 'Data Types and fields' 1.24 +const uint32_t iso_matrix[] = { 0x00010000, 0, 0, 1.25 + 0, 0x00010000, 0, 1.26 + 0, 0, 0x40000000 }; 1.27 + 1.28 +uint32_t 1.29 +set_sample_flags(bool aSync) 1.30 +{ 1.31 + std::bitset<32> flags; 1.32 + flags.set(16, !aSync); 1.33 + return flags.to_ulong(); 1.34 +} 1.35 + 1.36 +Box::BoxSizeChecker::BoxSizeChecker(ISOControl* aControl, uint32_t aSize) 1.37 +{ 1.38 + mControl = aControl; 1.39 + ori_size = mControl->GetBufPos(); 1.40 + box_size = aSize; 1.41 + MOZ_COUNT_CTOR(BoxSizeChecker); 1.42 +} 1.43 + 1.44 +Box::BoxSizeChecker::~BoxSizeChecker() 1.45 +{ 1.46 + uint32_t cur_size = mControl->GetBufPos(); 1.47 + if ((cur_size - ori_size) != box_size) { 1.48 + MOZ_ASSERT(false); 1.49 + } 1.50 + 1.51 + MOZ_COUNT_DTOR(BoxSizeChecker); 1.52 +} 1.53 + 1.54 +nsresult 1.55 +MediaDataBox::Generate(uint32_t* aBoxSize) 1.56 +{ 1.57 + mFirstSampleOffset = size; 1.58 + mAllSampleSize = 0; 1.59 + 1.60 + if (mTrackType & Audio_Track) { 1.61 + FragmentBuffer* frag = mControl->GetFragment(Audio_Track); 1.62 + mAllSampleSize += frag->GetFirstFragmentSampleSize(); 1.63 + } 1.64 + if (mTrackType & Video_Track) { 1.65 + FragmentBuffer* frag = mControl->GetFragment(Video_Track); 1.66 + mAllSampleSize += frag->GetFirstFragmentSampleSize(); 1.67 + } 1.68 + 1.69 + size += mAllSampleSize; 1.70 + *aBoxSize = size; 1.71 + return NS_OK; 1.72 +} 1.73 + 1.74 +nsresult 1.75 +MediaDataBox::Write() 1.76 +{ 1.77 + nsresult rv; 1.78 + BoxSizeChecker checker(mControl, size); 1.79 + Box::Write(); 1.80 + nsTArray<uint32_t> types; 1.81 + types.AppendElement(Audio_Track); 1.82 + types.AppendElement(Video_Track); 1.83 + 1.84 + for (uint32_t l = 0; l < types.Length(); l++) { 1.85 + if (mTrackType & types[l]) { 1.86 + FragmentBuffer* frag = mControl->GetFragment(types[l]); 1.87 + nsTArray<nsRefPtr<EncodedFrame>> frames; 1.88 + 1.89 + // Here is the last time we get fragment frames, flush it! 1.90 + rv = frag->GetFirstFragment(frames, true); 1.91 + NS_ENSURE_SUCCESS(rv, rv); 1.92 + 1.93 + uint32_t len = frames.Length(); 1.94 + for (uint32_t i = 0; i < len; i++) { 1.95 + nsTArray<uint8_t> frame_buffer; 1.96 + frames.ElementAt(i)->SwapOutFrameData(frame_buffer); 1.97 + mControl->WriteAVData(frame_buffer); 1.98 + } 1.99 + } 1.100 + } 1.101 + 1.102 + return NS_OK; 1.103 +} 1.104 + 1.105 +MediaDataBox::MediaDataBox(uint32_t aTrackType, ISOControl* aControl) 1.106 + : Box(NS_LITERAL_CSTRING("mdat"), aControl) 1.107 + , mAllSampleSize(0) 1.108 + , mFirstSampleOffset(0) 1.109 + , mTrackType(aTrackType) 1.110 +{ 1.111 + MOZ_COUNT_CTOR(MediaDataBox); 1.112 +} 1.113 + 1.114 +MediaDataBox::~MediaDataBox() 1.115 +{ 1.116 + MOZ_COUNT_DTOR(MediaDataBox); 1.117 +} 1.118 + 1.119 +uint32_t 1.120 +TrackRunBox::fillSampleTable() 1.121 +{ 1.122 + uint32_t table_size = 0; 1.123 + nsresult rv; 1.124 + nsTArray<nsRefPtr<EncodedFrame>> frames; 1.125 + FragmentBuffer* frag = mControl->GetFragment(mTrackType); 1.126 + 1.127 + rv = frag->GetFirstFragment(frames); 1.128 + if (NS_FAILED(rv)) { 1.129 + return 0; 1.130 + } 1.131 + uint32_t len = frames.Length(); 1.132 + sample_info_table = new tbl[len]; 1.133 + // Create sample table according to 14496-12 8.8.8.2. 1.134 + for (uint32_t i = 0; i < len; i++) { 1.135 + // Sample size. 1.136 + sample_info_table[i].sample_size = 0; 1.137 + if (flags.to_ulong() & flags_sample_size_present) { 1.138 + sample_info_table[i].sample_size = frames.ElementAt(i)->GetFrameData().Length(); 1.139 + mAllSampleSize += sample_info_table[i].sample_size; 1.140 + table_size += sizeof(uint32_t); 1.141 + } 1.142 + 1.143 + // Sample flags. 1.144 + sample_info_table[i].sample_flags = 0; 1.145 + if (flags.to_ulong() & flags_sample_flags_present) { 1.146 + sample_info_table[i].sample_flags = 1.147 + set_sample_flags( 1.148 + (frames.ElementAt(i)->GetFrameType() == EncodedFrame::AVC_I_FRAME)); 1.149 + table_size += sizeof(uint32_t); 1.150 + } 1.151 + 1.152 + // Sample duration. 1.153 + sample_info_table[i].sample_duration = 0; 1.154 + if (flags.to_ulong() & flags_sample_duration_present) { 1.155 + // Calculate each frame's duration, it is decided by "current frame 1.156 + // timestamp - last frame timestamp". 1.157 + uint64_t frame_time = 0; 1.158 + if (i == 0) { 1.159 + frame_time = frames.ElementAt(i)->GetTimeStamp() - 1.160 + frag->GetLastFragmentLastFrameTime(); 1.161 + } else { 1.162 + frame_time = frames.ElementAt(i)->GetTimeStamp() - 1.163 + frames.ElementAt(i - 1)->GetTimeStamp(); 1.164 + // Keep the last frame time of current fagment, it will be used to calculate 1.165 + // the first frame duration of next fragment. 1.166 + if ((len - 1) == i) { 1.167 + frag->SetLastFragmentLastFrameTime(frames.ElementAt(i)->GetTimeStamp()); 1.168 + } 1.169 + } 1.170 + 1.171 + // In TrackRunBox, there should be exactly one type, either audio or video. 1.172 + MOZ_ASSERT((mTrackType & Video_Track) ^ (mTrackType & Audio_Track)); 1.173 + sample_info_table[i].sample_duration = (mTrackType & Video_Track ? 1.174 + frame_time * mVideoMeta->GetVideoClockRate() / USECS_PER_S : 1.175 + frame_time * mAudioMeta->GetAudioSampleRate() / USECS_PER_S); 1.176 + 1.177 + table_size += sizeof(uint32_t); 1.178 + } 1.179 + 1.180 + sample_info_table[i].sample_composition_time_offset = 0; 1.181 + } 1.182 + return table_size; 1.183 +} 1.184 + 1.185 +nsresult 1.186 +TrackRunBox::Generate(uint32_t* aBoxSize) 1.187 +{ 1.188 + FragmentBuffer* frag = mControl->GetFragment(mTrackType); 1.189 + sample_count = frag->GetFirstFragmentSampleNumber(); 1.190 + size += sizeof(sample_count); 1.191 + 1.192 + // data_offset needs to be updated if there is other 1.193 + // TrackRunBox before this one. 1.194 + if (flags.to_ulong() & flags_data_offset_present) { 1.195 + data_offset = 0; 1.196 + size += sizeof(data_offset); 1.197 + } 1.198 + size += fillSampleTable(); 1.199 + 1.200 + *aBoxSize = size; 1.201 + 1.202 + return NS_OK; 1.203 +} 1.204 + 1.205 +nsresult 1.206 +TrackRunBox::SetDataOffset(uint32_t aOffset) 1.207 +{ 1.208 + data_offset = aOffset; 1.209 + return NS_OK; 1.210 +} 1.211 + 1.212 +nsresult 1.213 +TrackRunBox::Write() 1.214 +{ 1.215 + WRITE_FULLBOX(mControl, size) 1.216 + mControl->Write(sample_count); 1.217 + if (flags.to_ulong() & flags_data_offset_present) { 1.218 + mControl->Write(data_offset); 1.219 + } 1.220 + for (uint32_t i = 0; i < sample_count; i++) { 1.221 + if (flags.to_ulong() & flags_sample_duration_present) { 1.222 + mControl->Write(sample_info_table[i].sample_duration); 1.223 + } 1.224 + if (flags.to_ulong() & flags_sample_size_present) { 1.225 + mControl->Write(sample_info_table[i].sample_size); 1.226 + } 1.227 + if (flags.to_ulong() & flags_sample_flags_present) { 1.228 + mControl->Write(sample_info_table[i].sample_flags); 1.229 + } 1.230 + } 1.231 + 1.232 + return NS_OK; 1.233 +} 1.234 + 1.235 +TrackRunBox::TrackRunBox(uint32_t aType, uint32_t aFlags, ISOControl* aControl) 1.236 + : FullBox(NS_LITERAL_CSTRING("trun"), 0, aFlags, aControl) 1.237 + , sample_count(0) 1.238 + , data_offset(0) 1.239 + , first_sample_flags(0) 1.240 + , mAllSampleSize(0) 1.241 + , mTrackType(aType) 1.242 +{ 1.243 + MOZ_COUNT_CTOR(TrackRunBox); 1.244 +} 1.245 + 1.246 +TrackRunBox::~TrackRunBox() 1.247 +{ 1.248 + MOZ_COUNT_DTOR(TrackRunBox); 1.249 +} 1.250 + 1.251 +nsresult 1.252 +TrackFragmentHeaderBox::UpdateBaseDataOffset(uint64_t aOffset) 1.253 +{ 1.254 + base_data_offset = aOffset; 1.255 + return NS_OK; 1.256 +} 1.257 + 1.258 +nsresult 1.259 +TrackFragmentHeaderBox::Generate(uint32_t* aBoxSize) 1.260 +{ 1.261 + track_ID = (mTrackType == Audio_Track ? 1.262 + mControl->GetTrackID(mAudioMeta->GetKind()) : 1.263 + mControl->GetTrackID(mVideoMeta->GetKind())); 1.264 + size += sizeof(track_ID); 1.265 + 1.266 + if (flags.to_ulong() & base_data_offset_present) { 1.267 + // base_data_offset needs to add size of 'trun', 'tfhd' and 1.268 + // header of 'mdat' later. 1.269 + base_data_offset = 0; 1.270 + size += sizeof(base_data_offset); 1.271 + } 1.272 + if (flags.to_ulong() & default_sample_duration_present) { 1.273 + if (mTrackType == Video_Track) { 1.274 + if (!mVideoMeta->GetVideoFrameRate()) { 1.275 + // 0 means frame rate is variant, so it is wrong to write 1.276 + // default_sample_duration. 1.277 + MOZ_ASSERT(0); 1.278 + default_sample_duration = 0; 1.279 + } else { 1.280 + default_sample_duration = mVideoMeta->GetVideoClockRate() / mVideoMeta->GetVideoFrameRate(); 1.281 + } 1.282 + } else if (mTrackType == Audio_Track) { 1.283 + default_sample_duration = mAudioMeta->GetAudioFrameDuration(); 1.284 + } else { 1.285 + MOZ_ASSERT(0); 1.286 + return NS_ERROR_FAILURE; 1.287 + } 1.288 + size += sizeof(default_sample_duration); 1.289 + } 1.290 + *aBoxSize = size; 1.291 + return NS_OK; 1.292 +} 1.293 + 1.294 +nsresult 1.295 +TrackFragmentHeaderBox::Write() 1.296 +{ 1.297 + WRITE_FULLBOX(mControl, size) 1.298 + mControl->Write(track_ID); 1.299 + if (flags.to_ulong() & base_data_offset_present) { 1.300 + mControl->Write(base_data_offset); 1.301 + } 1.302 + if (flags.to_ulong() & default_sample_duration_present) { 1.303 + mControl->Write(default_sample_duration); 1.304 + } 1.305 + return NS_OK; 1.306 +} 1.307 + 1.308 +TrackFragmentHeaderBox::TrackFragmentHeaderBox(uint32_t aType, 1.309 + uint32_t aFlags, 1.310 + ISOControl* aControl) 1.311 + : FullBox(NS_LITERAL_CSTRING("tfhd"), 0, aFlags, aControl) 1.312 + , track_ID(0) 1.313 + , base_data_offset(0) 1.314 + , default_sample_duration(0) 1.315 +{ 1.316 + mTrackType = aType; 1.317 + MOZ_COUNT_CTOR(TrackFragmentHeaderBox); 1.318 +} 1.319 + 1.320 +TrackFragmentHeaderBox::~TrackFragmentHeaderBox() 1.321 +{ 1.322 + MOZ_COUNT_DTOR(TrackFragmentHeaderBox); 1.323 +} 1.324 + 1.325 +TrackFragmentBox::TrackFragmentBox(uint32_t aType, ISOControl* aControl) 1.326 + : DefaultContainerImpl(NS_LITERAL_CSTRING("traf"), aControl) 1.327 + , mTrackType(aType) 1.328 +{ 1.329 + // Flags in TrackFragmentHeaderBox. 1.330 + uint32_t tf_flags = base_data_offset_present; 1.331 + 1.332 + // Ideally, audio encoder generates audio frame in const rate. However, some 1.333 + // audio encoders don't do it so the audio frame duration needs to be checked 1.334 + // here. 1.335 + if ((mTrackType & Audio_Track) && mAudioMeta->GetAudioFrameDuration()) { 1.336 + tf_flags |= default_sample_duration_present; 1.337 + } 1.338 + 1.339 + boxes.AppendElement(new TrackFragmentHeaderBox(aType, tf_flags, aControl)); 1.340 + 1.341 + // Always adds flags_data_offset_present in each TrackRunBox, Android 1.342 + // parser requires this flag to calculate the correct bitstream offset. 1.343 + uint32_t tr_flags = flags_sample_size_present | flags_data_offset_present; 1.344 + 1.345 + // Flags in TrackRunBox. 1.346 + // If there is no default sample duration exists, each frame duration needs to 1.347 + // be recored in the TrackRunBox. 1.348 + tr_flags |= (tf_flags & default_sample_duration_present ? 0 : flags_sample_duration_present); 1.349 + 1.350 + // For video, add sample_flags to record I frame. 1.351 + tr_flags |= (mTrackType & Video_Track ? flags_sample_flags_present : 0); 1.352 + 1.353 + boxes.AppendElement(new TrackRunBox(mTrackType, tr_flags, aControl)); 1.354 + MOZ_COUNT_CTOR(TrackFragmentBox); 1.355 +} 1.356 + 1.357 +TrackFragmentBox::~TrackFragmentBox() 1.358 +{ 1.359 + MOZ_COUNT_DTOR(TrackFragmentBox); 1.360 +} 1.361 + 1.362 +nsresult 1.363 +MovieFragmentHeaderBox::Generate(uint32_t* aBoxSize) 1.364 +{ 1.365 + sequence_number = mControl->GetCurFragmentNumber(); 1.366 + size += sizeof(sequence_number); 1.367 + *aBoxSize = size; 1.368 + return NS_OK; 1.369 +} 1.370 + 1.371 +nsresult 1.372 +MovieFragmentHeaderBox::Write() 1.373 +{ 1.374 + WRITE_FULLBOX(mControl, size) 1.375 + mControl->Write(sequence_number); 1.376 + return NS_OK; 1.377 +} 1.378 + 1.379 +MovieFragmentHeaderBox::MovieFragmentHeaderBox(uint32_t aTrackType, 1.380 + ISOControl* aControl) 1.381 + : FullBox(NS_LITERAL_CSTRING("mfhd"), 0, 0, aControl) 1.382 + , sequence_number(0) 1.383 + , mTrackType(aTrackType) 1.384 +{ 1.385 + MOZ_COUNT_CTOR(MovieFragmentHeaderBox); 1.386 +} 1.387 + 1.388 +MovieFragmentHeaderBox::~MovieFragmentHeaderBox() 1.389 +{ 1.390 + MOZ_COUNT_DTOR(MovieFragmentHeaderBox); 1.391 +} 1.392 + 1.393 +MovieFragmentBox::MovieFragmentBox(uint32_t aType, ISOControl* aControl) 1.394 + : DefaultContainerImpl(NS_LITERAL_CSTRING("moof"), aControl) 1.395 + , mTrackType(aType) 1.396 +{ 1.397 + boxes.AppendElement(new MovieFragmentHeaderBox(mTrackType, aControl)); 1.398 + 1.399 + if (mTrackType & Audio_Track) { 1.400 + boxes.AppendElement( 1.401 + new TrackFragmentBox(Audio_Track, aControl)); 1.402 + } 1.403 + if (mTrackType & Video_Track) { 1.404 + boxes.AppendElement( 1.405 + new TrackFragmentBox(Video_Track, aControl)); 1.406 + } 1.407 + MOZ_COUNT_CTOR(MovieFragmentBox); 1.408 +} 1.409 + 1.410 +MovieFragmentBox::~MovieFragmentBox() 1.411 +{ 1.412 + MOZ_COUNT_DTOR(MovieFragmentBox); 1.413 +} 1.414 + 1.415 +nsresult 1.416 +MovieFragmentBox::Generate(uint32_t* aBoxSize) 1.417 +{ 1.418 + nsresult rv = DefaultContainerImpl::Generate(aBoxSize); 1.419 + NS_ENSURE_SUCCESS(rv, rv); 1.420 + 1.421 + // Correct data_offset if there are both audio and video track in 1.422 + // this fragment. This offset means the offset in the MediaDataBox. 1.423 + if (mTrackType & (Audio_Track | Video_Track)) { 1.424 + nsTArray<nsRefPtr<MuxerOperation>> truns; 1.425 + rv = Find(NS_LITERAL_CSTRING("trun"), truns); 1.426 + NS_ENSURE_SUCCESS(rv, rv); 1.427 + uint32_t len = truns.Length(); 1.428 + uint32_t data_offset = 0; 1.429 + for (uint32_t i = 0; i < len; i++) { 1.430 + TrackRunBox* trun = (TrackRunBox*) truns.ElementAt(i).get(); 1.431 + rv = trun->SetDataOffset(data_offset); 1.432 + NS_ENSURE_SUCCESS(rv, rv); 1.433 + data_offset += trun->GetAllSampleSize(); 1.434 + } 1.435 + } 1.436 + 1.437 + return NS_OK; 1.438 +} 1.439 + 1.440 +nsresult 1.441 +TrackExtendsBox::Generate(uint32_t* aBoxSize) 1.442 +{ 1.443 + track_ID = (mTrackType == Audio_Track ? 1.444 + mControl->GetTrackID(mAudioMeta->GetKind()) : 1.445 + mControl->GetTrackID(mVideoMeta->GetKind())); 1.446 + 1.447 + if (mTrackType == Audio_Track) { 1.448 + default_sample_description_index = 1; 1.449 + default_sample_duration = mAudioMeta->GetAudioFrameDuration(); 1.450 + default_sample_size = mAudioMeta->GetAudioFrameSize(); 1.451 + default_sample_flags = set_sample_flags(1); 1.452 + } else if (mTrackType == Video_Track) { 1.453 + default_sample_description_index = 1; 1.454 + // Video meta data has assigned framerate, it implies that this video's 1.455 + // frame rate should be fixed. 1.456 + if (mVideoMeta->GetVideoFrameRate()) { 1.457 + default_sample_duration = 1.458 + mVideoMeta->GetVideoClockRate() / mVideoMeta->GetVideoFrameRate(); 1.459 + } 1.460 + default_sample_size = 0; 1.461 + default_sample_flags = set_sample_flags(0); 1.462 + } else { 1.463 + MOZ_ASSERT(0); 1.464 + return NS_ERROR_FAILURE; 1.465 + } 1.466 + 1.467 + size += sizeof(track_ID) + 1.468 + sizeof(default_sample_description_index) + 1.469 + sizeof(default_sample_duration) + 1.470 + sizeof(default_sample_size) + 1.471 + sizeof(default_sample_flags); 1.472 + 1.473 + *aBoxSize = size; 1.474 + 1.475 + return NS_OK; 1.476 +} 1.477 + 1.478 +nsresult 1.479 +TrackExtendsBox::Write() 1.480 +{ 1.481 + WRITE_FULLBOX(mControl, size) 1.482 + mControl->Write(track_ID); 1.483 + mControl->Write(default_sample_description_index); 1.484 + mControl->Write(default_sample_duration); 1.485 + mControl->Write(default_sample_size); 1.486 + mControl->Write(default_sample_flags); 1.487 + 1.488 + return NS_OK; 1.489 +} 1.490 + 1.491 +TrackExtendsBox::TrackExtendsBox(uint32_t aType, ISOControl* aControl) 1.492 + : FullBox(NS_LITERAL_CSTRING("trex"), 0, 0, aControl) 1.493 + , track_ID(0) 1.494 + , default_sample_description_index(0) 1.495 + , default_sample_duration(0) 1.496 + , default_sample_size(0) 1.497 + , default_sample_flags(0) 1.498 + , mTrackType(aType) 1.499 +{ 1.500 + MOZ_COUNT_CTOR(TrackExtendsBox); 1.501 +} 1.502 + 1.503 +TrackExtendsBox::~TrackExtendsBox() 1.504 +{ 1.505 + MOZ_COUNT_DTOR(TrackExtendsBox); 1.506 +} 1.507 + 1.508 +MovieExtendsBox::MovieExtendsBox(ISOControl* aControl) 1.509 + : DefaultContainerImpl(NS_LITERAL_CSTRING("mvex"), aControl) 1.510 +{ 1.511 + if (mAudioMeta) { 1.512 + boxes.AppendElement(new TrackExtendsBox(Audio_Track, aControl)); 1.513 + } 1.514 + if (mVideoMeta) { 1.515 + boxes.AppendElement(new TrackExtendsBox(Video_Track, aControl)); 1.516 + } 1.517 + MOZ_COUNT_CTOR(MovieExtendsBox); 1.518 +} 1.519 + 1.520 +MovieExtendsBox::~MovieExtendsBox() 1.521 +{ 1.522 + MOZ_COUNT_DTOR(MovieExtendsBox); 1.523 +} 1.524 + 1.525 +nsresult 1.526 +ChunkOffsetBox::Generate(uint32_t* aBoxSize) 1.527 +{ 1.528 + // We don't need time to sample table in fragmented mp4. 1.529 + entry_count = 0; 1.530 + size += sizeof(entry_count); 1.531 + *aBoxSize = size; 1.532 + return NS_OK; 1.533 +} 1.534 + 1.535 +nsresult 1.536 +ChunkOffsetBox::Write() 1.537 +{ 1.538 + WRITE_FULLBOX(mControl, size) 1.539 + mControl->Write(entry_count); 1.540 + return NS_OK; 1.541 +} 1.542 + 1.543 +ChunkOffsetBox::ChunkOffsetBox(uint32_t aType, ISOControl* aControl) 1.544 + : FullBox(NS_LITERAL_CSTRING("stco"), 0, 0, aControl) 1.545 + , entry_count(0) 1.546 +{ 1.547 + MOZ_COUNT_CTOR(ChunkOffsetBox); 1.548 +} 1.549 + 1.550 +ChunkOffsetBox::~ChunkOffsetBox() 1.551 +{ 1.552 + MOZ_COUNT_DTOR(ChunkOffsetBox); 1.553 +} 1.554 + 1.555 +nsresult 1.556 +SampleToChunkBox::Generate(uint32_t* aBoxSize) 1.557 +{ 1.558 + // We don't need time to sample table in fragmented mp4 1.559 + entry_count = 0; 1.560 + size += sizeof(entry_count); 1.561 + *aBoxSize = size; 1.562 + return NS_OK; 1.563 +} 1.564 + 1.565 +nsresult 1.566 +SampleToChunkBox::Write() 1.567 +{ 1.568 + WRITE_FULLBOX(mControl, size) 1.569 + mControl->Write(entry_count); 1.570 + return NS_OK; 1.571 +} 1.572 + 1.573 +SampleToChunkBox::SampleToChunkBox(uint32_t aType, ISOControl* aControl) 1.574 + : FullBox(NS_LITERAL_CSTRING("stsc"), 0, 0, aControl) 1.575 + , entry_count(0) 1.576 +{ 1.577 + MOZ_COUNT_CTOR(SampleToChunkBox); 1.578 +} 1.579 + 1.580 +SampleToChunkBox::~SampleToChunkBox() 1.581 +{ 1.582 + MOZ_COUNT_DTOR(SampleToChunkBox); 1.583 +} 1.584 + 1.585 +nsresult 1.586 +TimeToSampleBox::Generate(uint32_t* aBoxSize) 1.587 +{ 1.588 + // We don't need time to sample table in fragmented mp4. 1.589 + entry_count = 0; 1.590 + size += sizeof(entry_count); 1.591 + *aBoxSize = size; 1.592 + return NS_OK; 1.593 +} 1.594 + 1.595 +nsresult 1.596 +TimeToSampleBox::Write() 1.597 +{ 1.598 + WRITE_FULLBOX(mControl, size) 1.599 + mControl->Write(entry_count); 1.600 + return NS_OK; 1.601 +} 1.602 + 1.603 +TimeToSampleBox::TimeToSampleBox(uint32_t aType, ISOControl* aControl) 1.604 + : FullBox(NS_LITERAL_CSTRING("stts"), 0, 0, aControl) 1.605 + , entry_count(0) 1.606 +{ 1.607 + MOZ_COUNT_CTOR(TimeToSampleBox); 1.608 +} 1.609 + 1.610 +TimeToSampleBox::~TimeToSampleBox() 1.611 +{ 1.612 + MOZ_COUNT_DTOR(TimeToSampleBox); 1.613 +} 1.614 + 1.615 +nsresult 1.616 +SampleDescriptionBox::Generate(uint32_t* aBoxSize) 1.617 +{ 1.618 + entry_count = 1; 1.619 + size += sizeof(entry_count); 1.620 + 1.621 + nsresult rv; 1.622 + uint32_t box_size; 1.623 + rv = sample_entry_box->Generate(&box_size); 1.624 + NS_ENSURE_SUCCESS(rv, rv); 1.625 + size += box_size; 1.626 + *aBoxSize = size; 1.627 + 1.628 + return NS_OK; 1.629 +} 1.630 + 1.631 +nsresult 1.632 +SampleDescriptionBox::Write() 1.633 +{ 1.634 + WRITE_FULLBOX(mControl, size) 1.635 + nsresult rv; 1.636 + mControl->Write(entry_count); 1.637 + rv = sample_entry_box->Write(); 1.638 + NS_ENSURE_SUCCESS(rv, rv); 1.639 + 1.640 + return NS_OK; 1.641 +} 1.642 + 1.643 +SampleDescriptionBox::SampleDescriptionBox(uint32_t aType, ISOControl* aControl) 1.644 + : FullBox(NS_LITERAL_CSTRING("stsd"), 0, 0, aControl) 1.645 + , entry_count(0) 1.646 +{ 1.647 + mTrackType = aType; 1.648 + 1.649 + switch (mTrackType) { 1.650 + case Audio_Track: 1.651 + { 1.652 + CreateAudioSampleEntry(sample_entry_box); 1.653 + } 1.654 + break; 1.655 + case Video_Track: 1.656 + { 1.657 + CreateVideoSampleEntry(sample_entry_box); 1.658 + } 1.659 + break; 1.660 + } 1.661 + MOZ_ASSERT(sample_entry_box); 1.662 + MOZ_COUNT_CTOR(SampleDescriptionBox); 1.663 +} 1.664 + 1.665 +nsresult 1.666 +SampleDescriptionBox::CreateAudioSampleEntry(nsRefPtr<SampleEntryBox>& aSampleEntry) 1.667 +{ 1.668 + if (mAudioMeta->GetKind() == TrackMetadataBase::METADATA_AMR) { 1.669 + aSampleEntry = new AMRSampleEntry(mControl); 1.670 + } else if (mAudioMeta->GetKind() == TrackMetadataBase::METADATA_AAC) { 1.671 + aSampleEntry = new MP4AudioSampleEntry(mControl); 1.672 + } else { 1.673 + MOZ_ASSERT(0); 1.674 + } 1.675 + return NS_OK; 1.676 +} 1.677 + 1.678 +nsresult 1.679 +SampleDescriptionBox::CreateVideoSampleEntry(nsRefPtr<SampleEntryBox>& aSampleEntry) 1.680 +{ 1.681 + if (mVideoMeta->GetKind() == TrackMetadataBase::METADATA_AVC) { 1.682 + aSampleEntry = new AVCSampleEntry(mControl); 1.683 + } else { 1.684 + MOZ_ASSERT(0); 1.685 + } 1.686 + return NS_OK; 1.687 +} 1.688 + 1.689 +SampleDescriptionBox::~SampleDescriptionBox() 1.690 +{ 1.691 + MOZ_COUNT_DTOR(SampleDescriptionBox); 1.692 +} 1.693 + 1.694 +nsresult 1.695 +SampleSizeBox::Generate(uint32_t* aBoxSize) 1.696 +{ 1.697 + size += sizeof(sample_size) + 1.698 + sizeof(sample_count); 1.699 + *aBoxSize = size; 1.700 + return NS_OK; 1.701 +} 1.702 + 1.703 +nsresult 1.704 +SampleSizeBox::Write() 1.705 +{ 1.706 + WRITE_FULLBOX(mControl, size) 1.707 + mControl->Write(sample_size); 1.708 + mControl->Write(sample_count); 1.709 + return NS_OK; 1.710 +} 1.711 + 1.712 +SampleSizeBox::SampleSizeBox(ISOControl* aControl) 1.713 + : FullBox(NS_LITERAL_CSTRING("stsz"), 0, 0, aControl) 1.714 + , sample_size(0) 1.715 + , sample_count(0) 1.716 +{ 1.717 + MOZ_COUNT_CTOR(SampleSizeBox); 1.718 +} 1.719 + 1.720 +SampleSizeBox::~SampleSizeBox() 1.721 +{ 1.722 + MOZ_COUNT_DTOR(SampleSizeBox); 1.723 +} 1.724 + 1.725 +SampleTableBox::SampleTableBox(uint32_t aType, ISOControl* aControl) 1.726 + : DefaultContainerImpl(NS_LITERAL_CSTRING("stbl"), aControl) 1.727 +{ 1.728 + boxes.AppendElement(new SampleDescriptionBox(aType, aControl)); 1.729 + boxes.AppendElement(new TimeToSampleBox(aType, aControl)); 1.730 + boxes.AppendElement(new SampleToChunkBox(aType, aControl)); 1.731 + boxes.AppendElement(new SampleSizeBox(aControl)); 1.732 + boxes.AppendElement(new ChunkOffsetBox(aType, aControl)); 1.733 + MOZ_COUNT_CTOR(SampleTableBox); 1.734 +} 1.735 + 1.736 +SampleTableBox::~SampleTableBox() 1.737 +{ 1.738 + MOZ_COUNT_DTOR(SampleTableBox); 1.739 +} 1.740 + 1.741 +nsresult 1.742 +DataEntryUrlBox::Generate(uint32_t* aBoxSize) 1.743 +{ 1.744 + // location is null here, do nothing 1.745 + size += location.Length(); 1.746 + *aBoxSize = size; 1.747 + 1.748 + return NS_OK; 1.749 +} 1.750 + 1.751 +nsresult 1.752 +DataEntryUrlBox::Write() 1.753 +{ 1.754 + WRITE_FULLBOX(mControl, size) 1.755 + return NS_OK; 1.756 +} 1.757 + 1.758 +DataEntryUrlBox::DataEntryUrlBox() 1.759 + : FullBox(NS_LITERAL_CSTRING("url "), 0, 0, (ISOControl*) nullptr) 1.760 +{ 1.761 + MOZ_COUNT_CTOR(DataEntryUrlBox); 1.762 +} 1.763 + 1.764 +DataEntryUrlBox::DataEntryUrlBox(ISOControl* aControl) 1.765 + : FullBox(NS_LITERAL_CSTRING("url "), 0, flags_media_at_the_same_file, aControl) 1.766 +{ 1.767 + MOZ_COUNT_CTOR(DataEntryUrlBox); 1.768 +} 1.769 + 1.770 +DataEntryUrlBox::DataEntryUrlBox(const DataEntryUrlBox& aBox) 1.771 + : FullBox(aBox.boxType, aBox.version, aBox.flags.to_ulong(), aBox.mControl) 1.772 +{ 1.773 + location = aBox.location; 1.774 + MOZ_COUNT_CTOR(DataEntryUrlBox); 1.775 +} 1.776 + 1.777 +DataEntryUrlBox::~DataEntryUrlBox() 1.778 +{ 1.779 + MOZ_COUNT_DTOR(DataEntryUrlBox); 1.780 +} 1.781 + 1.782 +nsresult DataReferenceBox::Generate(uint32_t* aBoxSize) 1.783 +{ 1.784 + entry_count = 1; // only allow on entry here 1.785 + size += sizeof(uint32_t); 1.786 + 1.787 + for (uint32_t i = 0; i < entry_count; i++) { 1.788 + uint32_t box_size = 0; 1.789 + DataEntryUrlBox* url = new DataEntryUrlBox(mControl); 1.790 + url->Generate(&box_size); 1.791 + size += box_size; 1.792 + urls.AppendElement(url); 1.793 + } 1.794 + 1.795 + *aBoxSize = size; 1.796 + 1.797 + return NS_OK; 1.798 +} 1.799 + 1.800 +nsresult DataReferenceBox::Write() 1.801 +{ 1.802 + WRITE_FULLBOX(mControl, size) 1.803 + mControl->Write(entry_count); 1.804 + 1.805 + for (uint32_t i = 0; i < entry_count; i++) { 1.806 + urls[i]->Write(); 1.807 + } 1.808 + 1.809 + return NS_OK; 1.810 +} 1.811 + 1.812 +DataReferenceBox::DataReferenceBox(ISOControl* aControl) 1.813 + : FullBox(NS_LITERAL_CSTRING("dref"), 0, 0, aControl) 1.814 + , entry_count(0) 1.815 +{ 1.816 + MOZ_COUNT_CTOR(DataReferenceBox); 1.817 +} 1.818 + 1.819 +DataReferenceBox::~DataReferenceBox() 1.820 +{ 1.821 + MOZ_COUNT_DTOR(DataReferenceBox); 1.822 +} 1.823 + 1.824 +DataInformationBox::DataInformationBox(ISOControl* aControl) 1.825 + : DefaultContainerImpl(NS_LITERAL_CSTRING("dinf"), aControl) 1.826 +{ 1.827 + boxes.AppendElement(new DataReferenceBox(aControl)); 1.828 + MOZ_COUNT_CTOR(DataInformationBox); 1.829 +} 1.830 + 1.831 +DataInformationBox::~DataInformationBox() 1.832 +{ 1.833 + MOZ_COUNT_DTOR(DataInformationBox); 1.834 +} 1.835 + 1.836 +nsresult 1.837 +VideoMediaHeaderBox::Generate(uint32_t* aBoxSize) 1.838 +{ 1.839 + size += sizeof(graphicsmode) + 1.840 + sizeof(opcolor); 1.841 + 1.842 + *aBoxSize = size; 1.843 + 1.844 + return NS_OK; 1.845 +} 1.846 + 1.847 +nsresult 1.848 +VideoMediaHeaderBox::Write() 1.849 +{ 1.850 + WRITE_FULLBOX(mControl, size) 1.851 + mControl->Write(graphicsmode); 1.852 + mControl->WriteArray(opcolor, 3); 1.853 + return NS_OK; 1.854 +} 1.855 + 1.856 +VideoMediaHeaderBox::VideoMediaHeaderBox(ISOControl* aControl) 1.857 + : FullBox(NS_LITERAL_CSTRING("vmhd"), 0, 1, aControl) 1.858 + , graphicsmode(0) 1.859 +{ 1.860 + memset(opcolor, 0 , sizeof(opcolor)); 1.861 + MOZ_COUNT_CTOR(VideoMediaHeaderBox); 1.862 +} 1.863 + 1.864 +VideoMediaHeaderBox::~VideoMediaHeaderBox() 1.865 +{ 1.866 + MOZ_COUNT_DTOR(VideoMediaHeaderBox); 1.867 +} 1.868 + 1.869 +nsresult 1.870 +SoundMediaHeaderBox::Generate(uint32_t* aBoxSize) 1.871 +{ 1.872 + balance = 0; 1.873 + reserved = 0; 1.874 + size += sizeof(balance) + 1.875 + sizeof(reserved); 1.876 + 1.877 + *aBoxSize = size; 1.878 + 1.879 + return NS_OK; 1.880 +} 1.881 + 1.882 +nsresult 1.883 +SoundMediaHeaderBox::Write() 1.884 +{ 1.885 + WRITE_FULLBOX(mControl, size) 1.886 + mControl->Write(balance); 1.887 + mControl->Write(reserved); 1.888 + 1.889 + return NS_OK; 1.890 +} 1.891 + 1.892 +SoundMediaHeaderBox::SoundMediaHeaderBox(ISOControl* aControl) 1.893 + : FullBox(NS_LITERAL_CSTRING("smhd"), 0, 0, aControl) 1.894 +{ 1.895 + MOZ_COUNT_CTOR(SoundMediaHeaderBox); 1.896 +} 1.897 + 1.898 +SoundMediaHeaderBox::~SoundMediaHeaderBox() 1.899 +{ 1.900 + MOZ_COUNT_DTOR(SoundMediaHeaderBox); 1.901 +} 1.902 + 1.903 +MediaInformationBox::MediaInformationBox(uint32_t aType, ISOControl* aControl) 1.904 + : DefaultContainerImpl(NS_LITERAL_CSTRING("minf"), aControl) 1.905 +{ 1.906 + mTrackType = aType; 1.907 + 1.908 + if (mTrackType == Audio_Track) { 1.909 + boxes.AppendElement(new SoundMediaHeaderBox(aControl)); 1.910 + } else if (mTrackType == Video_Track) { 1.911 + boxes.AppendElement(new VideoMediaHeaderBox(aControl)); 1.912 + } else { 1.913 + MOZ_ASSERT(0); 1.914 + } 1.915 + 1.916 + boxes.AppendElement(new DataInformationBox(aControl)); 1.917 + boxes.AppendElement(new SampleTableBox(aType, aControl)); 1.918 + MOZ_COUNT_CTOR(MediaInformationBox); 1.919 +} 1.920 + 1.921 +MediaInformationBox::~MediaInformationBox() 1.922 +{ 1.923 + MOZ_COUNT_DTOR(MediaInformationBox); 1.924 +} 1.925 + 1.926 +nsresult 1.927 +HandlerBox::Generate(uint32_t* aBoxSize) 1.928 +{ 1.929 + pre_defined = 0; 1.930 + if (mTrackType == Audio_Track) { 1.931 + handler_type = FOURCC('s', 'o', 'u', 'n'); 1.932 + } else if (mTrackType == Video_Track) { 1.933 + handler_type = FOURCC('v', 'i', 'd', 'e'); 1.934 + } 1.935 + 1.936 + size += sizeof(pre_defined) + 1.937 + sizeof(handler_type) + 1.938 + sizeof(reserved); 1.939 + 1.940 + *aBoxSize = size; 1.941 + 1.942 + return NS_OK; 1.943 +} 1.944 + 1.945 +nsresult 1.946 +HandlerBox::Write() 1.947 +{ 1.948 + WRITE_FULLBOX(mControl, size) 1.949 + mControl->Write(pre_defined); 1.950 + mControl->Write(handler_type); 1.951 + mControl->WriteArray(reserved, 3); 1.952 + 1.953 + return NS_OK; 1.954 +} 1.955 + 1.956 +HandlerBox::HandlerBox(uint32_t aType, ISOControl* aControl) 1.957 + : FullBox(NS_LITERAL_CSTRING("hdlr"), 0, 0, aControl) 1.958 + , pre_defined(0) 1.959 + , handler_type(0) 1.960 +{ 1.961 + mTrackType = aType; 1.962 + memset(reserved, 0 , sizeof(reserved)); 1.963 + MOZ_COUNT_CTOR(HandlerBox); 1.964 +} 1.965 + 1.966 +HandlerBox::~HandlerBox() 1.967 +{ 1.968 + MOZ_COUNT_DTOR(HandlerBox); 1.969 +} 1.970 + 1.971 +MediaHeaderBox::MediaHeaderBox(uint32_t aType, ISOControl* aControl) 1.972 + : FullBox(NS_LITERAL_CSTRING("mdhd"), 0, 0, aControl) 1.973 + , creation_time(0) 1.974 + , modification_time(0) 1.975 + , timescale(0) 1.976 + , duration(0) 1.977 + , pad(0) 1.978 + , lang1(0) 1.979 + , lang2(0) 1.980 + , lang3(0) 1.981 + , pre_defined(0) 1.982 +{ 1.983 + mTrackType = aType; 1.984 + MOZ_COUNT_CTOR(MediaHeaderBox); 1.985 +} 1.986 + 1.987 +MediaHeaderBox::~MediaHeaderBox() 1.988 +{ 1.989 + MOZ_COUNT_DTOR(MediaHeaderBox); 1.990 +} 1.991 + 1.992 +uint32_t 1.993 +MediaHeaderBox::GetTimeScale() 1.994 +{ 1.995 + if (mTrackType == Audio_Track) { 1.996 + return mAudioMeta->GetAudioSampleRate(); 1.997 + } 1.998 + 1.999 + return mVideoMeta->GetVideoClockRate(); 1.1000 +} 1.1001 + 1.1002 +nsresult 1.1003 +MediaHeaderBox::Generate(uint32_t* aBoxSize) 1.1004 +{ 1.1005 + creation_time = mControl->GetTime(); 1.1006 + modification_time = mControl->GetTime(); 1.1007 + timescale = GetTimeScale(); 1.1008 + duration = 0; // fragmented mp4 1.1009 + 1.1010 + pad = 0; 1.1011 + lang1 = 'u' - 0x60; // "und" underdetermined language 1.1012 + lang2 = 'n' - 0x60; 1.1013 + lang3 = 'd' - 0x60; 1.1014 + size += (pad.size() + lang1.size() + lang2.size() + lang3.size()) / CHAR_BIT; 1.1015 + 1.1016 + pre_defined = 0; 1.1017 + size += sizeof(creation_time) + 1.1018 + sizeof(modification_time) + 1.1019 + sizeof(timescale) + 1.1020 + sizeof(duration) + 1.1021 + sizeof(pre_defined); 1.1022 + 1.1023 + *aBoxSize = size; 1.1024 + 1.1025 + return NS_OK; 1.1026 +} 1.1027 + 1.1028 +nsresult 1.1029 +MediaHeaderBox::Write() 1.1030 +{ 1.1031 + WRITE_FULLBOX(mControl, size) 1.1032 + mControl->Write(creation_time); 1.1033 + mControl->Write(modification_time); 1.1034 + mControl->Write(timescale); 1.1035 + mControl->Write(duration); 1.1036 + mControl->WriteBits(pad.to_ulong(), pad.size()); 1.1037 + mControl->WriteBits(lang1.to_ulong(), lang1.size()); 1.1038 + mControl->WriteBits(lang2.to_ulong(), lang2.size()); 1.1039 + mControl->WriteBits(lang3.to_ulong(), lang3.size()); 1.1040 + mControl->Write(pre_defined); 1.1041 + 1.1042 + return NS_OK; 1.1043 +} 1.1044 + 1.1045 +MovieBox::MovieBox(ISOControl* aControl) 1.1046 + : DefaultContainerImpl(NS_LITERAL_CSTRING("moov"), aControl) 1.1047 +{ 1.1048 + boxes.AppendElement(new MovieHeaderBox(aControl)); 1.1049 + if (aControl->HasAudioTrack()) { 1.1050 + boxes.AppendElement(new TrackBox(Audio_Track, aControl)); 1.1051 + } 1.1052 + if (aControl->HasVideoTrack()) { 1.1053 + boxes.AppendElement(new TrackBox(Video_Track, aControl)); 1.1054 + } 1.1055 + boxes.AppendElement(new MovieExtendsBox(aControl)); 1.1056 + MOZ_COUNT_CTOR(MovieBox); 1.1057 +} 1.1058 + 1.1059 +MovieBox::~MovieBox() 1.1060 +{ 1.1061 + MOZ_COUNT_DTOR(MovieBox); 1.1062 +} 1.1063 + 1.1064 +nsresult 1.1065 +MovieHeaderBox::Generate(uint32_t* aBoxSize) 1.1066 +{ 1.1067 + creation_time = mControl->GetTime(); 1.1068 + modification_time = mControl->GetTime(); 1.1069 + timescale = GetTimeScale(); 1.1070 + duration = 0; // The duration is always 0 in fragmented mp4. 1.1071 + next_track_ID = mControl->GetNextTrackID(); 1.1072 + 1.1073 + size += sizeof(next_track_ID) + 1.1074 + sizeof(creation_time) + 1.1075 + sizeof(modification_time) + 1.1076 + sizeof(timescale) + 1.1077 + sizeof(duration) + 1.1078 + sizeof(rate) + 1.1079 + sizeof(volume) + 1.1080 + sizeof(reserved16) + 1.1081 + sizeof(reserved32) + 1.1082 + sizeof(matrix) + 1.1083 + sizeof(pre_defined); 1.1084 + 1.1085 + *aBoxSize = size; 1.1086 + 1.1087 + return NS_OK; 1.1088 +} 1.1089 + 1.1090 +nsresult 1.1091 +MovieHeaderBox::Write() 1.1092 +{ 1.1093 + WRITE_FULLBOX(mControl, size) 1.1094 + mControl->Write(creation_time); 1.1095 + mControl->Write(modification_time); 1.1096 + mControl->Write(timescale); 1.1097 + mControl->Write(duration); 1.1098 + mControl->Write(rate); 1.1099 + mControl->Write(volume); 1.1100 + mControl->Write(reserved16); 1.1101 + mControl->WriteArray(reserved32, 2); 1.1102 + mControl->WriteArray(matrix, 9); 1.1103 + mControl->WriteArray(pre_defined, 6); 1.1104 + mControl->Write(next_track_ID); 1.1105 + 1.1106 + return NS_OK; 1.1107 +} 1.1108 + 1.1109 +uint32_t 1.1110 +MovieHeaderBox::GetTimeScale() 1.1111 +{ 1.1112 + // Only audio track in container. 1.1113 + if (mAudioMeta && !mVideoMeta) { 1.1114 + return mAudioMeta->GetAudioSampleRate(); 1.1115 + } 1.1116 + 1.1117 + // return video rate 1.1118 + return mVideoMeta->GetVideoClockRate(); 1.1119 +} 1.1120 + 1.1121 +MovieHeaderBox::~MovieHeaderBox() 1.1122 +{ 1.1123 + MOZ_COUNT_DTOR(MovieHeaderBox); 1.1124 +} 1.1125 + 1.1126 +MovieHeaderBox::MovieHeaderBox(ISOControl* aControl) 1.1127 + : FullBox(NS_LITERAL_CSTRING("mvhd"), 0, 0, aControl) 1.1128 + , creation_time(0) 1.1129 + , modification_time(0) 1.1130 + , timescale(90000) 1.1131 + , duration(0) 1.1132 + , rate(0x00010000) 1.1133 + , volume(0x0100) 1.1134 + , reserved16(0) 1.1135 + , next_track_ID(1) 1.1136 +{ 1.1137 + memcpy(matrix, iso_matrix, sizeof(matrix)); 1.1138 + memset(reserved32, 0, sizeof(reserved32)); 1.1139 + memset(pre_defined, 0, sizeof(pre_defined)); 1.1140 + MOZ_COUNT_CTOR(MovieHeaderBox); 1.1141 +} 1.1142 + 1.1143 +TrackHeaderBox::TrackHeaderBox(uint32_t aType, ISOControl* aControl) 1.1144 + : FullBox(NS_LITERAL_CSTRING("tkhd"), 0, 1.1145 + flags_track_enabled | flags_track_in_movie | flags_track_in_preview, 1.1146 + aControl) 1.1147 + , creation_time(0) 1.1148 + , modification_time(0) 1.1149 + , track_ID(0) 1.1150 + , reserved(0) 1.1151 + , duration(0) 1.1152 + , layer(0) 1.1153 + , alternate_group(0) 1.1154 + , volume(0) 1.1155 + , reserved3(0) 1.1156 + , width(0) 1.1157 + , height(0) 1.1158 +{ 1.1159 + mTrackType = aType; 1.1160 + memcpy(matrix, iso_matrix, sizeof(matrix)); 1.1161 + memset(reserved2, 0, sizeof(reserved2)); 1.1162 + MOZ_COUNT_CTOR(TrackHeaderBox); 1.1163 +} 1.1164 + 1.1165 +TrackHeaderBox::~TrackHeaderBox() 1.1166 +{ 1.1167 + MOZ_COUNT_DTOR(TrackHeaderBox); 1.1168 +} 1.1169 + 1.1170 +nsresult 1.1171 +TrackHeaderBox::Generate(uint32_t* aBoxSize) 1.1172 +{ 1.1173 + creation_time = mControl->GetTime(); 1.1174 + modification_time = mControl->GetTime(); 1.1175 + track_ID = (mTrackType == Audio_Track ? 1.1176 + mControl->GetTrackID(mAudioMeta->GetKind()) : 1.1177 + mControl->GetTrackID(mVideoMeta->GetKind())); 1.1178 + // fragmented mp4 1.1179 + duration = 0; 1.1180 + 1.1181 + // volume, audiotrack is always 0x0100 in 14496-12 8.3.2.2 1.1182 + volume = (mTrackType == Audio_Track ? 0x0100 : 0); 1.1183 + 1.1184 + if (mTrackType == Video_Track) { 1.1185 + width = mVideoMeta->GetVideoDisplayWidth() << 16; 1.1186 + height = mVideoMeta->GetVideoDisplayHeight() << 16; 1.1187 + // Check display size, using the pixel size if any of them is invalid. 1.1188 + if (!width || !height) { 1.1189 + width = mVideoMeta->GetVideoWidth() << 16; 1.1190 + height = mVideoMeta->GetVideoHeight() << 16; 1.1191 + } 1.1192 + } 1.1193 + 1.1194 + size += sizeof(creation_time) + 1.1195 + sizeof(modification_time) + 1.1196 + sizeof(track_ID) + 1.1197 + sizeof(reserved) + 1.1198 + sizeof(duration) + 1.1199 + sizeof(reserved2) + 1.1200 + sizeof(layer) + 1.1201 + sizeof(alternate_group) + 1.1202 + sizeof(volume) + 1.1203 + sizeof(reserved3) + 1.1204 + sizeof(matrix) + 1.1205 + sizeof(width) + 1.1206 + sizeof(height); 1.1207 + 1.1208 + *aBoxSize = size; 1.1209 + 1.1210 + return NS_OK; 1.1211 +} 1.1212 + 1.1213 +nsresult 1.1214 +TrackHeaderBox::Write() 1.1215 +{ 1.1216 + WRITE_FULLBOX(mControl, size) 1.1217 + mControl->Write(creation_time); 1.1218 + mControl->Write(modification_time); 1.1219 + mControl->Write(track_ID); 1.1220 + mControl->Write(reserved); 1.1221 + mControl->Write(duration); 1.1222 + mControl->WriteArray(reserved2, 2); 1.1223 + mControl->Write(layer); 1.1224 + mControl->Write(alternate_group); 1.1225 + mControl->Write(volume); 1.1226 + mControl->Write(reserved3); 1.1227 + mControl->WriteArray(matrix, 9); 1.1228 + mControl->Write(width); 1.1229 + mControl->Write(height); 1.1230 + 1.1231 + return NS_OK; 1.1232 +} 1.1233 + 1.1234 +nsresult 1.1235 +FileTypeBox::Generate(uint32_t* aBoxSize) 1.1236 +{ 1.1237 + minor_version = 0; 1.1238 + 1.1239 + if (mControl->GetMuxingType() == ISOMediaWriter::TYPE_FRAG_MP4) { 1.1240 + if (!mControl->HasVideoTrack() && mControl->HasAudioTrack()) { 1.1241 + major_brand = "M4A "; 1.1242 + } else { 1.1243 + major_brand = "MP42"; 1.1244 + } 1.1245 + compatible_brands.AppendElement("mp42"); 1.1246 + compatible_brands.AppendElement("isom"); 1.1247 + } else if (mControl->GetMuxingType() == ISOMediaWriter::TYPE_FRAG_3GP) { 1.1248 + major_brand = "3gp9"; 1.1249 + // According to 3GPP TS 26.244 V12.2.0, section 5.3.4, it's recommended to 1.1250 + // list all compatible brands here. 3GP spec supports fragment from '3gp6'. 1.1251 + compatible_brands.AppendElement("3gp9"); 1.1252 + compatible_brands.AppendElement("3gp8"); 1.1253 + compatible_brands.AppendElement("3gp7"); 1.1254 + compatible_brands.AppendElement("3gp6"); 1.1255 + compatible_brands.AppendElement("isom"); 1.1256 + } else { 1.1257 + MOZ_ASSERT(0); 1.1258 + } 1.1259 + 1.1260 + size += major_brand.Length() + 1.1261 + sizeof(minor_version) + 1.1262 + compatible_brands.Length() * 4; 1.1263 + 1.1264 + *aBoxSize = size; 1.1265 + 1.1266 + return NS_OK; 1.1267 +} 1.1268 + 1.1269 +nsresult 1.1270 +FileTypeBox::Write() 1.1271 +{ 1.1272 + BoxSizeChecker checker(mControl, size); 1.1273 + Box::Write(); 1.1274 + mControl->WriteFourCC(major_brand.get()); 1.1275 + mControl->Write(minor_version); 1.1276 + uint32_t len = compatible_brands.Length(); 1.1277 + for (uint32_t i = 0; i < len; i++) { 1.1278 + mControl->WriteFourCC(compatible_brands[i].get()); 1.1279 + } 1.1280 + 1.1281 + return NS_OK; 1.1282 +} 1.1283 + 1.1284 +FileTypeBox::FileTypeBox(ISOControl* aControl) 1.1285 + : Box(NS_LITERAL_CSTRING("ftyp"), aControl) 1.1286 + , minor_version(0) 1.1287 +{ 1.1288 + MOZ_COUNT_CTOR(FileTypeBox); 1.1289 +} 1.1290 + 1.1291 +FileTypeBox::~FileTypeBox() 1.1292 +{ 1.1293 + MOZ_COUNT_DTOR(FileTypeBox); 1.1294 +} 1.1295 + 1.1296 +MediaBox::MediaBox(uint32_t aType, ISOControl* aControl) 1.1297 + : DefaultContainerImpl(NS_LITERAL_CSTRING("mdia"), aControl) 1.1298 +{ 1.1299 + mTrackType = aType; 1.1300 + boxes.AppendElement(new MediaHeaderBox(aType, aControl)); 1.1301 + boxes.AppendElement(new HandlerBox(aType, aControl)); 1.1302 + boxes.AppendElement(new MediaInformationBox(aType, aControl)); 1.1303 + MOZ_COUNT_CTOR(MediaBox); 1.1304 +} 1.1305 + 1.1306 +MediaBox::~MediaBox() 1.1307 +{ 1.1308 + MOZ_COUNT_DTOR(MediaBox); 1.1309 +} 1.1310 + 1.1311 +nsresult 1.1312 +DefaultContainerImpl::Generate(uint32_t* aBoxSize) 1.1313 +{ 1.1314 + nsresult rv; 1.1315 + uint32_t box_size; 1.1316 + uint32_t len = boxes.Length(); 1.1317 + for (uint32_t i = 0; i < len; i++) { 1.1318 + rv = boxes.ElementAt(i)->Generate(&box_size); 1.1319 + NS_ENSURE_SUCCESS(rv, rv); 1.1320 + size += box_size; 1.1321 + } 1.1322 + *aBoxSize = size; 1.1323 + return NS_OK; 1.1324 +} 1.1325 + 1.1326 +nsresult 1.1327 +DefaultContainerImpl::Find(const nsACString& aType, 1.1328 + nsTArray<nsRefPtr<MuxerOperation>>& aOperations) 1.1329 +{ 1.1330 + nsresult rv = Box::Find(aType, aOperations); 1.1331 + NS_ENSURE_SUCCESS(rv, rv); 1.1332 + 1.1333 + uint32_t len = boxes.Length(); 1.1334 + for (uint32_t i = 0; i < len; i++) { 1.1335 + rv = boxes.ElementAt(i)->Find(aType, aOperations); 1.1336 + NS_ENSURE_SUCCESS(rv, rv); 1.1337 + } 1.1338 + return NS_OK; 1.1339 +} 1.1340 + 1.1341 +nsresult 1.1342 +DefaultContainerImpl::Write() 1.1343 +{ 1.1344 + BoxSizeChecker checker(mControl, size); 1.1345 + Box::Write(); 1.1346 + 1.1347 + nsresult rv; 1.1348 + uint32_t len = boxes.Length(); 1.1349 + for (uint32_t i = 0; i < len; i++) { 1.1350 + rv = boxes.ElementAt(i)->Write(); 1.1351 + NS_ENSURE_SUCCESS(rv, rv); 1.1352 + } 1.1353 + 1.1354 + return NS_OK; 1.1355 +} 1.1356 + 1.1357 +DefaultContainerImpl::DefaultContainerImpl(const nsACString& aType, 1.1358 + ISOControl* aControl) 1.1359 + : Box(aType, aControl) 1.1360 +{ 1.1361 +} 1.1362 + 1.1363 +nsresult 1.1364 +Box::Write() 1.1365 +{ 1.1366 + mControl->Write(size); 1.1367 + mControl->WriteFourCC(boxType.get()); 1.1368 + return NS_OK; 1.1369 +} 1.1370 + 1.1371 +nsresult 1.1372 +Box::Find(const nsACString& aType, nsTArray<nsRefPtr<MuxerOperation>>& aOperations) 1.1373 +{ 1.1374 + if (boxType == aType) { 1.1375 + aOperations.AppendElement(this); 1.1376 + } 1.1377 + return NS_OK; 1.1378 +} 1.1379 + 1.1380 +Box::Box(const nsACString& aType, ISOControl* aControl) 1.1381 + : size(8), mControl(aControl) 1.1382 +{ 1.1383 + MOZ_ASSERT(aType.Length() == 4); 1.1384 + boxType = aType; 1.1385 + aControl->GetAudioMetadata(mAudioMeta); 1.1386 + aControl->GetVideoMetadata(mVideoMeta); 1.1387 +} 1.1388 + 1.1389 +FullBox::FullBox(const nsACString& aType, uint8_t aVersion, uint32_t aFlags, 1.1390 + ISOControl* aControl) 1.1391 + : Box(aType, aControl) 1.1392 +{ 1.1393 + // Cast to uint64_t due to VC2010 bug. 1.1394 + std::bitset<24> tmp_flags((uint64_t)aFlags); 1.1395 + version = aVersion; 1.1396 + flags = tmp_flags; 1.1397 + size += sizeof(version) + flags.size() / CHAR_BIT; 1.1398 +} 1.1399 + 1.1400 +nsresult 1.1401 +FullBox::Write() 1.1402 +{ 1.1403 + Box::Write(); 1.1404 + mControl->Write(version); 1.1405 + mControl->WriteBits(flags.to_ulong(), flags.size()); 1.1406 + return NS_OK; 1.1407 +} 1.1408 + 1.1409 +TrackBox::TrackBox(uint32_t aTrackType, ISOControl* aControl) 1.1410 + : DefaultContainerImpl(NS_LITERAL_CSTRING("trak"), aControl) 1.1411 +{ 1.1412 + boxes.AppendElement(new TrackHeaderBox(aTrackType, aControl)); 1.1413 + boxes.AppendElement(new MediaBox(aTrackType, aControl)); 1.1414 + MOZ_COUNT_CTOR(TrackBox); 1.1415 +} 1.1416 + 1.1417 +TrackBox::~TrackBox() 1.1418 +{ 1.1419 + MOZ_COUNT_DTOR(TrackBox); 1.1420 +} 1.1421 + 1.1422 +SampleEntryBox::SampleEntryBox(const nsACString& aFormat, ISOControl* aControl) 1.1423 + : Box(aFormat, aControl) 1.1424 + , data_reference_index(0) 1.1425 +{ 1.1426 + data_reference_index = 1; // There is only one data reference in each track. 1.1427 + size += sizeof(reserved) + 1.1428 + sizeof(data_reference_index); 1.1429 + memset(reserved, 0, sizeof(reserved)); 1.1430 +} 1.1431 + 1.1432 +nsresult 1.1433 +SampleEntryBox::Write() 1.1434 +{ 1.1435 + Box::Write(); 1.1436 + mControl->Write(reserved, sizeof(reserved)); 1.1437 + mControl->Write(data_reference_index); 1.1438 + return NS_OK; 1.1439 +} 1.1440 + 1.1441 +nsresult 1.1442 +AudioSampleEntry::Write() 1.1443 +{ 1.1444 + SampleEntryBox::Write(); 1.1445 + mControl->Write(sound_version); 1.1446 + mControl->Write(reserved2, sizeof(reserved2)); 1.1447 + mControl->Write(channels); 1.1448 + mControl->Write(sample_size); 1.1449 + mControl->Write(compressionId); 1.1450 + mControl->Write(packet_size); 1.1451 + mControl->Write(timeScale); 1.1452 + return NS_OK; 1.1453 +} 1.1454 + 1.1455 +AudioSampleEntry::AudioSampleEntry(const nsACString& aFormat, ISOControl* aControl) 1.1456 + : SampleEntryBox(aFormat, aControl) 1.1457 + , sound_version(0) 1.1458 + , channels(2) 1.1459 + , sample_size(16) 1.1460 + , compressionId(0) 1.1461 + , packet_size(0) 1.1462 + , timeScale(0) 1.1463 +{ 1.1464 + memset(reserved2, 0 , sizeof(reserved2)); 1.1465 + channels = mAudioMeta->GetAudioChannels(); 1.1466 + timeScale = mAudioMeta->GetAudioSampleRate() << 16; 1.1467 + 1.1468 + size += sizeof(sound_version) + 1.1469 + sizeof(reserved2) + 1.1470 + sizeof(sample_size) + 1.1471 + sizeof(channels) + 1.1472 + sizeof(packet_size) + 1.1473 + sizeof(compressionId) + 1.1474 + sizeof(timeScale); 1.1475 + 1.1476 + MOZ_COUNT_CTOR(AudioSampleEntry); 1.1477 +} 1.1478 + 1.1479 +AudioSampleEntry::~AudioSampleEntry() 1.1480 +{ 1.1481 + MOZ_COUNT_DTOR(AudioSampleEntry); 1.1482 +} 1.1483 + 1.1484 +nsresult 1.1485 +VisualSampleEntry::Write() 1.1486 +{ 1.1487 + SampleEntryBox::Write(); 1.1488 + 1.1489 + mControl->Write(reserved, sizeof(reserved)); 1.1490 + mControl->Write(width); 1.1491 + mControl->Write(height); 1.1492 + mControl->Write(horizresolution); 1.1493 + mControl->Write(vertresolution); 1.1494 + mControl->Write(reserved2); 1.1495 + mControl->Write(frame_count); 1.1496 + mControl->Write(compressorName, sizeof(compressorName)); 1.1497 + mControl->Write(depth); 1.1498 + mControl->Write(pre_defined); 1.1499 + 1.1500 + return NS_OK; 1.1501 +} 1.1502 + 1.1503 +VisualSampleEntry::VisualSampleEntry(const nsACString& aFormat, ISOControl* aControl) 1.1504 + : SampleEntryBox(aFormat, aControl) 1.1505 + , width(0) 1.1506 + , height(0) 1.1507 + , horizresolution(resolution_72_dpi) 1.1508 + , vertresolution(resolution_72_dpi) 1.1509 + , reserved2(0) 1.1510 + , frame_count(1) 1.1511 + , depth(video_depth) 1.1512 + , pre_defined(-1) 1.1513 +{ 1.1514 + memset(reserved, 0 , sizeof(reserved)); 1.1515 + memset(compressorName, 0 , sizeof(compressorName)); 1.1516 + 1.1517 + // both fields occupy 16 bits defined in 14496-2 6.2.3. 1.1518 + width = mVideoMeta->GetVideoWidth(); 1.1519 + height = mVideoMeta->GetVideoHeight(); 1.1520 + 1.1521 + size += sizeof(reserved) + 1.1522 + sizeof(width) + 1.1523 + sizeof(height) + 1.1524 + sizeof(horizresolution) + 1.1525 + sizeof(vertresolution) + 1.1526 + sizeof(reserved2) + 1.1527 + sizeof(frame_count) + 1.1528 + sizeof(compressorName) + 1.1529 + sizeof(depth) + 1.1530 + sizeof(pre_defined); 1.1531 + 1.1532 + MOZ_COUNT_CTOR(VisualSampleEntry); 1.1533 +} 1.1534 + 1.1535 +VisualSampleEntry::~VisualSampleEntry() 1.1536 +{ 1.1537 + MOZ_COUNT_DTOR(VisualSampleEntry); 1.1538 +} 1.1539 + 1.1540 +}