content/media/encoder/fmp4_muxer/ISOMediaBoxes.cpp

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

michael@0 1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-*/
michael@0 2 /* This Source Code Form is subject to the terms of the Mozilla Public
michael@0 3 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
michael@0 4 * You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 5
michael@0 6 #include <climits>
michael@0 7 #include "TrackMetadataBase.h"
michael@0 8 #include "ISOMediaBoxes.h"
michael@0 9 #include "ISOControl.h"
michael@0 10 #include "ISOMediaWriter.h"
michael@0 11 #include "EncodedFrameContainer.h"
michael@0 12 #include "ISOTrackMetadata.h"
michael@0 13 #include "MP4ESDS.h"
michael@0 14 #include "AMRBox.h"
michael@0 15 #include "AVCBox.h"
michael@0 16 #include "VideoUtils.h"
michael@0 17
michael@0 18 namespace mozilla {
michael@0 19
michael@0 20 // 14496-12 6.2.2 'Data Types and fields'
michael@0 21 const uint32_t iso_matrix[] = { 0x00010000, 0, 0,
michael@0 22 0, 0x00010000, 0,
michael@0 23 0, 0, 0x40000000 };
michael@0 24
michael@0 25 uint32_t
michael@0 26 set_sample_flags(bool aSync)
michael@0 27 {
michael@0 28 std::bitset<32> flags;
michael@0 29 flags.set(16, !aSync);
michael@0 30 return flags.to_ulong();
michael@0 31 }
michael@0 32
michael@0 33 Box::BoxSizeChecker::BoxSizeChecker(ISOControl* aControl, uint32_t aSize)
michael@0 34 {
michael@0 35 mControl = aControl;
michael@0 36 ori_size = mControl->GetBufPos();
michael@0 37 box_size = aSize;
michael@0 38 MOZ_COUNT_CTOR(BoxSizeChecker);
michael@0 39 }
michael@0 40
michael@0 41 Box::BoxSizeChecker::~BoxSizeChecker()
michael@0 42 {
michael@0 43 uint32_t cur_size = mControl->GetBufPos();
michael@0 44 if ((cur_size - ori_size) != box_size) {
michael@0 45 MOZ_ASSERT(false);
michael@0 46 }
michael@0 47
michael@0 48 MOZ_COUNT_DTOR(BoxSizeChecker);
michael@0 49 }
michael@0 50
michael@0 51 nsresult
michael@0 52 MediaDataBox::Generate(uint32_t* aBoxSize)
michael@0 53 {
michael@0 54 mFirstSampleOffset = size;
michael@0 55 mAllSampleSize = 0;
michael@0 56
michael@0 57 if (mTrackType & Audio_Track) {
michael@0 58 FragmentBuffer* frag = mControl->GetFragment(Audio_Track);
michael@0 59 mAllSampleSize += frag->GetFirstFragmentSampleSize();
michael@0 60 }
michael@0 61 if (mTrackType & Video_Track) {
michael@0 62 FragmentBuffer* frag = mControl->GetFragment(Video_Track);
michael@0 63 mAllSampleSize += frag->GetFirstFragmentSampleSize();
michael@0 64 }
michael@0 65
michael@0 66 size += mAllSampleSize;
michael@0 67 *aBoxSize = size;
michael@0 68 return NS_OK;
michael@0 69 }
michael@0 70
michael@0 71 nsresult
michael@0 72 MediaDataBox::Write()
michael@0 73 {
michael@0 74 nsresult rv;
michael@0 75 BoxSizeChecker checker(mControl, size);
michael@0 76 Box::Write();
michael@0 77 nsTArray<uint32_t> types;
michael@0 78 types.AppendElement(Audio_Track);
michael@0 79 types.AppendElement(Video_Track);
michael@0 80
michael@0 81 for (uint32_t l = 0; l < types.Length(); l++) {
michael@0 82 if (mTrackType & types[l]) {
michael@0 83 FragmentBuffer* frag = mControl->GetFragment(types[l]);
michael@0 84 nsTArray<nsRefPtr<EncodedFrame>> frames;
michael@0 85
michael@0 86 // Here is the last time we get fragment frames, flush it!
michael@0 87 rv = frag->GetFirstFragment(frames, true);
michael@0 88 NS_ENSURE_SUCCESS(rv, rv);
michael@0 89
michael@0 90 uint32_t len = frames.Length();
michael@0 91 for (uint32_t i = 0; i < len; i++) {
michael@0 92 nsTArray<uint8_t> frame_buffer;
michael@0 93 frames.ElementAt(i)->SwapOutFrameData(frame_buffer);
michael@0 94 mControl->WriteAVData(frame_buffer);
michael@0 95 }
michael@0 96 }
michael@0 97 }
michael@0 98
michael@0 99 return NS_OK;
michael@0 100 }
michael@0 101
michael@0 102 MediaDataBox::MediaDataBox(uint32_t aTrackType, ISOControl* aControl)
michael@0 103 : Box(NS_LITERAL_CSTRING("mdat"), aControl)
michael@0 104 , mAllSampleSize(0)
michael@0 105 , mFirstSampleOffset(0)
michael@0 106 , mTrackType(aTrackType)
michael@0 107 {
michael@0 108 MOZ_COUNT_CTOR(MediaDataBox);
michael@0 109 }
michael@0 110
michael@0 111 MediaDataBox::~MediaDataBox()
michael@0 112 {
michael@0 113 MOZ_COUNT_DTOR(MediaDataBox);
michael@0 114 }
michael@0 115
michael@0 116 uint32_t
michael@0 117 TrackRunBox::fillSampleTable()
michael@0 118 {
michael@0 119 uint32_t table_size = 0;
michael@0 120 nsresult rv;
michael@0 121 nsTArray<nsRefPtr<EncodedFrame>> frames;
michael@0 122 FragmentBuffer* frag = mControl->GetFragment(mTrackType);
michael@0 123
michael@0 124 rv = frag->GetFirstFragment(frames);
michael@0 125 if (NS_FAILED(rv)) {
michael@0 126 return 0;
michael@0 127 }
michael@0 128 uint32_t len = frames.Length();
michael@0 129 sample_info_table = new tbl[len];
michael@0 130 // Create sample table according to 14496-12 8.8.8.2.
michael@0 131 for (uint32_t i = 0; i < len; i++) {
michael@0 132 // Sample size.
michael@0 133 sample_info_table[i].sample_size = 0;
michael@0 134 if (flags.to_ulong() & flags_sample_size_present) {
michael@0 135 sample_info_table[i].sample_size = frames.ElementAt(i)->GetFrameData().Length();
michael@0 136 mAllSampleSize += sample_info_table[i].sample_size;
michael@0 137 table_size += sizeof(uint32_t);
michael@0 138 }
michael@0 139
michael@0 140 // Sample flags.
michael@0 141 sample_info_table[i].sample_flags = 0;
michael@0 142 if (flags.to_ulong() & flags_sample_flags_present) {
michael@0 143 sample_info_table[i].sample_flags =
michael@0 144 set_sample_flags(
michael@0 145 (frames.ElementAt(i)->GetFrameType() == EncodedFrame::AVC_I_FRAME));
michael@0 146 table_size += sizeof(uint32_t);
michael@0 147 }
michael@0 148
michael@0 149 // Sample duration.
michael@0 150 sample_info_table[i].sample_duration = 0;
michael@0 151 if (flags.to_ulong() & flags_sample_duration_present) {
michael@0 152 // Calculate each frame's duration, it is decided by "current frame
michael@0 153 // timestamp - last frame timestamp".
michael@0 154 uint64_t frame_time = 0;
michael@0 155 if (i == 0) {
michael@0 156 frame_time = frames.ElementAt(i)->GetTimeStamp() -
michael@0 157 frag->GetLastFragmentLastFrameTime();
michael@0 158 } else {
michael@0 159 frame_time = frames.ElementAt(i)->GetTimeStamp() -
michael@0 160 frames.ElementAt(i - 1)->GetTimeStamp();
michael@0 161 // Keep the last frame time of current fagment, it will be used to calculate
michael@0 162 // the first frame duration of next fragment.
michael@0 163 if ((len - 1) == i) {
michael@0 164 frag->SetLastFragmentLastFrameTime(frames.ElementAt(i)->GetTimeStamp());
michael@0 165 }
michael@0 166 }
michael@0 167
michael@0 168 // In TrackRunBox, there should be exactly one type, either audio or video.
michael@0 169 MOZ_ASSERT((mTrackType & Video_Track) ^ (mTrackType & Audio_Track));
michael@0 170 sample_info_table[i].sample_duration = (mTrackType & Video_Track ?
michael@0 171 frame_time * mVideoMeta->GetVideoClockRate() / USECS_PER_S :
michael@0 172 frame_time * mAudioMeta->GetAudioSampleRate() / USECS_PER_S);
michael@0 173
michael@0 174 table_size += sizeof(uint32_t);
michael@0 175 }
michael@0 176
michael@0 177 sample_info_table[i].sample_composition_time_offset = 0;
michael@0 178 }
michael@0 179 return table_size;
michael@0 180 }
michael@0 181
michael@0 182 nsresult
michael@0 183 TrackRunBox::Generate(uint32_t* aBoxSize)
michael@0 184 {
michael@0 185 FragmentBuffer* frag = mControl->GetFragment(mTrackType);
michael@0 186 sample_count = frag->GetFirstFragmentSampleNumber();
michael@0 187 size += sizeof(sample_count);
michael@0 188
michael@0 189 // data_offset needs to be updated if there is other
michael@0 190 // TrackRunBox before this one.
michael@0 191 if (flags.to_ulong() & flags_data_offset_present) {
michael@0 192 data_offset = 0;
michael@0 193 size += sizeof(data_offset);
michael@0 194 }
michael@0 195 size += fillSampleTable();
michael@0 196
michael@0 197 *aBoxSize = size;
michael@0 198
michael@0 199 return NS_OK;
michael@0 200 }
michael@0 201
michael@0 202 nsresult
michael@0 203 TrackRunBox::SetDataOffset(uint32_t aOffset)
michael@0 204 {
michael@0 205 data_offset = aOffset;
michael@0 206 return NS_OK;
michael@0 207 }
michael@0 208
michael@0 209 nsresult
michael@0 210 TrackRunBox::Write()
michael@0 211 {
michael@0 212 WRITE_FULLBOX(mControl, size)
michael@0 213 mControl->Write(sample_count);
michael@0 214 if (flags.to_ulong() & flags_data_offset_present) {
michael@0 215 mControl->Write(data_offset);
michael@0 216 }
michael@0 217 for (uint32_t i = 0; i < sample_count; i++) {
michael@0 218 if (flags.to_ulong() & flags_sample_duration_present) {
michael@0 219 mControl->Write(sample_info_table[i].sample_duration);
michael@0 220 }
michael@0 221 if (flags.to_ulong() & flags_sample_size_present) {
michael@0 222 mControl->Write(sample_info_table[i].sample_size);
michael@0 223 }
michael@0 224 if (flags.to_ulong() & flags_sample_flags_present) {
michael@0 225 mControl->Write(sample_info_table[i].sample_flags);
michael@0 226 }
michael@0 227 }
michael@0 228
michael@0 229 return NS_OK;
michael@0 230 }
michael@0 231
michael@0 232 TrackRunBox::TrackRunBox(uint32_t aType, uint32_t aFlags, ISOControl* aControl)
michael@0 233 : FullBox(NS_LITERAL_CSTRING("trun"), 0, aFlags, aControl)
michael@0 234 , sample_count(0)
michael@0 235 , data_offset(0)
michael@0 236 , first_sample_flags(0)
michael@0 237 , mAllSampleSize(0)
michael@0 238 , mTrackType(aType)
michael@0 239 {
michael@0 240 MOZ_COUNT_CTOR(TrackRunBox);
michael@0 241 }
michael@0 242
michael@0 243 TrackRunBox::~TrackRunBox()
michael@0 244 {
michael@0 245 MOZ_COUNT_DTOR(TrackRunBox);
michael@0 246 }
michael@0 247
michael@0 248 nsresult
michael@0 249 TrackFragmentHeaderBox::UpdateBaseDataOffset(uint64_t aOffset)
michael@0 250 {
michael@0 251 base_data_offset = aOffset;
michael@0 252 return NS_OK;
michael@0 253 }
michael@0 254
michael@0 255 nsresult
michael@0 256 TrackFragmentHeaderBox::Generate(uint32_t* aBoxSize)
michael@0 257 {
michael@0 258 track_ID = (mTrackType == Audio_Track ?
michael@0 259 mControl->GetTrackID(mAudioMeta->GetKind()) :
michael@0 260 mControl->GetTrackID(mVideoMeta->GetKind()));
michael@0 261 size += sizeof(track_ID);
michael@0 262
michael@0 263 if (flags.to_ulong() & base_data_offset_present) {
michael@0 264 // base_data_offset needs to add size of 'trun', 'tfhd' and
michael@0 265 // header of 'mdat' later.
michael@0 266 base_data_offset = 0;
michael@0 267 size += sizeof(base_data_offset);
michael@0 268 }
michael@0 269 if (flags.to_ulong() & default_sample_duration_present) {
michael@0 270 if (mTrackType == Video_Track) {
michael@0 271 if (!mVideoMeta->GetVideoFrameRate()) {
michael@0 272 // 0 means frame rate is variant, so it is wrong to write
michael@0 273 // default_sample_duration.
michael@0 274 MOZ_ASSERT(0);
michael@0 275 default_sample_duration = 0;
michael@0 276 } else {
michael@0 277 default_sample_duration = mVideoMeta->GetVideoClockRate() / mVideoMeta->GetVideoFrameRate();
michael@0 278 }
michael@0 279 } else if (mTrackType == Audio_Track) {
michael@0 280 default_sample_duration = mAudioMeta->GetAudioFrameDuration();
michael@0 281 } else {
michael@0 282 MOZ_ASSERT(0);
michael@0 283 return NS_ERROR_FAILURE;
michael@0 284 }
michael@0 285 size += sizeof(default_sample_duration);
michael@0 286 }
michael@0 287 *aBoxSize = size;
michael@0 288 return NS_OK;
michael@0 289 }
michael@0 290
michael@0 291 nsresult
michael@0 292 TrackFragmentHeaderBox::Write()
michael@0 293 {
michael@0 294 WRITE_FULLBOX(mControl, size)
michael@0 295 mControl->Write(track_ID);
michael@0 296 if (flags.to_ulong() & base_data_offset_present) {
michael@0 297 mControl->Write(base_data_offset);
michael@0 298 }
michael@0 299 if (flags.to_ulong() & default_sample_duration_present) {
michael@0 300 mControl->Write(default_sample_duration);
michael@0 301 }
michael@0 302 return NS_OK;
michael@0 303 }
michael@0 304
michael@0 305 TrackFragmentHeaderBox::TrackFragmentHeaderBox(uint32_t aType,
michael@0 306 uint32_t aFlags,
michael@0 307 ISOControl* aControl)
michael@0 308 : FullBox(NS_LITERAL_CSTRING("tfhd"), 0, aFlags, aControl)
michael@0 309 , track_ID(0)
michael@0 310 , base_data_offset(0)
michael@0 311 , default_sample_duration(0)
michael@0 312 {
michael@0 313 mTrackType = aType;
michael@0 314 MOZ_COUNT_CTOR(TrackFragmentHeaderBox);
michael@0 315 }
michael@0 316
michael@0 317 TrackFragmentHeaderBox::~TrackFragmentHeaderBox()
michael@0 318 {
michael@0 319 MOZ_COUNT_DTOR(TrackFragmentHeaderBox);
michael@0 320 }
michael@0 321
michael@0 322 TrackFragmentBox::TrackFragmentBox(uint32_t aType, ISOControl* aControl)
michael@0 323 : DefaultContainerImpl(NS_LITERAL_CSTRING("traf"), aControl)
michael@0 324 , mTrackType(aType)
michael@0 325 {
michael@0 326 // Flags in TrackFragmentHeaderBox.
michael@0 327 uint32_t tf_flags = base_data_offset_present;
michael@0 328
michael@0 329 // Ideally, audio encoder generates audio frame in const rate. However, some
michael@0 330 // audio encoders don't do it so the audio frame duration needs to be checked
michael@0 331 // here.
michael@0 332 if ((mTrackType & Audio_Track) && mAudioMeta->GetAudioFrameDuration()) {
michael@0 333 tf_flags |= default_sample_duration_present;
michael@0 334 }
michael@0 335
michael@0 336 boxes.AppendElement(new TrackFragmentHeaderBox(aType, tf_flags, aControl));
michael@0 337
michael@0 338 // Always adds flags_data_offset_present in each TrackRunBox, Android
michael@0 339 // parser requires this flag to calculate the correct bitstream offset.
michael@0 340 uint32_t tr_flags = flags_sample_size_present | flags_data_offset_present;
michael@0 341
michael@0 342 // Flags in TrackRunBox.
michael@0 343 // If there is no default sample duration exists, each frame duration needs to
michael@0 344 // be recored in the TrackRunBox.
michael@0 345 tr_flags |= (tf_flags & default_sample_duration_present ? 0 : flags_sample_duration_present);
michael@0 346
michael@0 347 // For video, add sample_flags to record I frame.
michael@0 348 tr_flags |= (mTrackType & Video_Track ? flags_sample_flags_present : 0);
michael@0 349
michael@0 350 boxes.AppendElement(new TrackRunBox(mTrackType, tr_flags, aControl));
michael@0 351 MOZ_COUNT_CTOR(TrackFragmentBox);
michael@0 352 }
michael@0 353
michael@0 354 TrackFragmentBox::~TrackFragmentBox()
michael@0 355 {
michael@0 356 MOZ_COUNT_DTOR(TrackFragmentBox);
michael@0 357 }
michael@0 358
michael@0 359 nsresult
michael@0 360 MovieFragmentHeaderBox::Generate(uint32_t* aBoxSize)
michael@0 361 {
michael@0 362 sequence_number = mControl->GetCurFragmentNumber();
michael@0 363 size += sizeof(sequence_number);
michael@0 364 *aBoxSize = size;
michael@0 365 return NS_OK;
michael@0 366 }
michael@0 367
michael@0 368 nsresult
michael@0 369 MovieFragmentHeaderBox::Write()
michael@0 370 {
michael@0 371 WRITE_FULLBOX(mControl, size)
michael@0 372 mControl->Write(sequence_number);
michael@0 373 return NS_OK;
michael@0 374 }
michael@0 375
michael@0 376 MovieFragmentHeaderBox::MovieFragmentHeaderBox(uint32_t aTrackType,
michael@0 377 ISOControl* aControl)
michael@0 378 : FullBox(NS_LITERAL_CSTRING("mfhd"), 0, 0, aControl)
michael@0 379 , sequence_number(0)
michael@0 380 , mTrackType(aTrackType)
michael@0 381 {
michael@0 382 MOZ_COUNT_CTOR(MovieFragmentHeaderBox);
michael@0 383 }
michael@0 384
michael@0 385 MovieFragmentHeaderBox::~MovieFragmentHeaderBox()
michael@0 386 {
michael@0 387 MOZ_COUNT_DTOR(MovieFragmentHeaderBox);
michael@0 388 }
michael@0 389
michael@0 390 MovieFragmentBox::MovieFragmentBox(uint32_t aType, ISOControl* aControl)
michael@0 391 : DefaultContainerImpl(NS_LITERAL_CSTRING("moof"), aControl)
michael@0 392 , mTrackType(aType)
michael@0 393 {
michael@0 394 boxes.AppendElement(new MovieFragmentHeaderBox(mTrackType, aControl));
michael@0 395
michael@0 396 if (mTrackType & Audio_Track) {
michael@0 397 boxes.AppendElement(
michael@0 398 new TrackFragmentBox(Audio_Track, aControl));
michael@0 399 }
michael@0 400 if (mTrackType & Video_Track) {
michael@0 401 boxes.AppendElement(
michael@0 402 new TrackFragmentBox(Video_Track, aControl));
michael@0 403 }
michael@0 404 MOZ_COUNT_CTOR(MovieFragmentBox);
michael@0 405 }
michael@0 406
michael@0 407 MovieFragmentBox::~MovieFragmentBox()
michael@0 408 {
michael@0 409 MOZ_COUNT_DTOR(MovieFragmentBox);
michael@0 410 }
michael@0 411
michael@0 412 nsresult
michael@0 413 MovieFragmentBox::Generate(uint32_t* aBoxSize)
michael@0 414 {
michael@0 415 nsresult rv = DefaultContainerImpl::Generate(aBoxSize);
michael@0 416 NS_ENSURE_SUCCESS(rv, rv);
michael@0 417
michael@0 418 // Correct data_offset if there are both audio and video track in
michael@0 419 // this fragment. This offset means the offset in the MediaDataBox.
michael@0 420 if (mTrackType & (Audio_Track | Video_Track)) {
michael@0 421 nsTArray<nsRefPtr<MuxerOperation>> truns;
michael@0 422 rv = Find(NS_LITERAL_CSTRING("trun"), truns);
michael@0 423 NS_ENSURE_SUCCESS(rv, rv);
michael@0 424 uint32_t len = truns.Length();
michael@0 425 uint32_t data_offset = 0;
michael@0 426 for (uint32_t i = 0; i < len; i++) {
michael@0 427 TrackRunBox* trun = (TrackRunBox*) truns.ElementAt(i).get();
michael@0 428 rv = trun->SetDataOffset(data_offset);
michael@0 429 NS_ENSURE_SUCCESS(rv, rv);
michael@0 430 data_offset += trun->GetAllSampleSize();
michael@0 431 }
michael@0 432 }
michael@0 433
michael@0 434 return NS_OK;
michael@0 435 }
michael@0 436
michael@0 437 nsresult
michael@0 438 TrackExtendsBox::Generate(uint32_t* aBoxSize)
michael@0 439 {
michael@0 440 track_ID = (mTrackType == Audio_Track ?
michael@0 441 mControl->GetTrackID(mAudioMeta->GetKind()) :
michael@0 442 mControl->GetTrackID(mVideoMeta->GetKind()));
michael@0 443
michael@0 444 if (mTrackType == Audio_Track) {
michael@0 445 default_sample_description_index = 1;
michael@0 446 default_sample_duration = mAudioMeta->GetAudioFrameDuration();
michael@0 447 default_sample_size = mAudioMeta->GetAudioFrameSize();
michael@0 448 default_sample_flags = set_sample_flags(1);
michael@0 449 } else if (mTrackType == Video_Track) {
michael@0 450 default_sample_description_index = 1;
michael@0 451 // Video meta data has assigned framerate, it implies that this video's
michael@0 452 // frame rate should be fixed.
michael@0 453 if (mVideoMeta->GetVideoFrameRate()) {
michael@0 454 default_sample_duration =
michael@0 455 mVideoMeta->GetVideoClockRate() / mVideoMeta->GetVideoFrameRate();
michael@0 456 }
michael@0 457 default_sample_size = 0;
michael@0 458 default_sample_flags = set_sample_flags(0);
michael@0 459 } else {
michael@0 460 MOZ_ASSERT(0);
michael@0 461 return NS_ERROR_FAILURE;
michael@0 462 }
michael@0 463
michael@0 464 size += sizeof(track_ID) +
michael@0 465 sizeof(default_sample_description_index) +
michael@0 466 sizeof(default_sample_duration) +
michael@0 467 sizeof(default_sample_size) +
michael@0 468 sizeof(default_sample_flags);
michael@0 469
michael@0 470 *aBoxSize = size;
michael@0 471
michael@0 472 return NS_OK;
michael@0 473 }
michael@0 474
michael@0 475 nsresult
michael@0 476 TrackExtendsBox::Write()
michael@0 477 {
michael@0 478 WRITE_FULLBOX(mControl, size)
michael@0 479 mControl->Write(track_ID);
michael@0 480 mControl->Write(default_sample_description_index);
michael@0 481 mControl->Write(default_sample_duration);
michael@0 482 mControl->Write(default_sample_size);
michael@0 483 mControl->Write(default_sample_flags);
michael@0 484
michael@0 485 return NS_OK;
michael@0 486 }
michael@0 487
michael@0 488 TrackExtendsBox::TrackExtendsBox(uint32_t aType, ISOControl* aControl)
michael@0 489 : FullBox(NS_LITERAL_CSTRING("trex"), 0, 0, aControl)
michael@0 490 , track_ID(0)
michael@0 491 , default_sample_description_index(0)
michael@0 492 , default_sample_duration(0)
michael@0 493 , default_sample_size(0)
michael@0 494 , default_sample_flags(0)
michael@0 495 , mTrackType(aType)
michael@0 496 {
michael@0 497 MOZ_COUNT_CTOR(TrackExtendsBox);
michael@0 498 }
michael@0 499
michael@0 500 TrackExtendsBox::~TrackExtendsBox()
michael@0 501 {
michael@0 502 MOZ_COUNT_DTOR(TrackExtendsBox);
michael@0 503 }
michael@0 504
michael@0 505 MovieExtendsBox::MovieExtendsBox(ISOControl* aControl)
michael@0 506 : DefaultContainerImpl(NS_LITERAL_CSTRING("mvex"), aControl)
michael@0 507 {
michael@0 508 if (mAudioMeta) {
michael@0 509 boxes.AppendElement(new TrackExtendsBox(Audio_Track, aControl));
michael@0 510 }
michael@0 511 if (mVideoMeta) {
michael@0 512 boxes.AppendElement(new TrackExtendsBox(Video_Track, aControl));
michael@0 513 }
michael@0 514 MOZ_COUNT_CTOR(MovieExtendsBox);
michael@0 515 }
michael@0 516
michael@0 517 MovieExtendsBox::~MovieExtendsBox()
michael@0 518 {
michael@0 519 MOZ_COUNT_DTOR(MovieExtendsBox);
michael@0 520 }
michael@0 521
michael@0 522 nsresult
michael@0 523 ChunkOffsetBox::Generate(uint32_t* aBoxSize)
michael@0 524 {
michael@0 525 // We don't need time to sample table in fragmented mp4.
michael@0 526 entry_count = 0;
michael@0 527 size += sizeof(entry_count);
michael@0 528 *aBoxSize = size;
michael@0 529 return NS_OK;
michael@0 530 }
michael@0 531
michael@0 532 nsresult
michael@0 533 ChunkOffsetBox::Write()
michael@0 534 {
michael@0 535 WRITE_FULLBOX(mControl, size)
michael@0 536 mControl->Write(entry_count);
michael@0 537 return NS_OK;
michael@0 538 }
michael@0 539
michael@0 540 ChunkOffsetBox::ChunkOffsetBox(uint32_t aType, ISOControl* aControl)
michael@0 541 : FullBox(NS_LITERAL_CSTRING("stco"), 0, 0, aControl)
michael@0 542 , entry_count(0)
michael@0 543 {
michael@0 544 MOZ_COUNT_CTOR(ChunkOffsetBox);
michael@0 545 }
michael@0 546
michael@0 547 ChunkOffsetBox::~ChunkOffsetBox()
michael@0 548 {
michael@0 549 MOZ_COUNT_DTOR(ChunkOffsetBox);
michael@0 550 }
michael@0 551
michael@0 552 nsresult
michael@0 553 SampleToChunkBox::Generate(uint32_t* aBoxSize)
michael@0 554 {
michael@0 555 // We don't need time to sample table in fragmented mp4
michael@0 556 entry_count = 0;
michael@0 557 size += sizeof(entry_count);
michael@0 558 *aBoxSize = size;
michael@0 559 return NS_OK;
michael@0 560 }
michael@0 561
michael@0 562 nsresult
michael@0 563 SampleToChunkBox::Write()
michael@0 564 {
michael@0 565 WRITE_FULLBOX(mControl, size)
michael@0 566 mControl->Write(entry_count);
michael@0 567 return NS_OK;
michael@0 568 }
michael@0 569
michael@0 570 SampleToChunkBox::SampleToChunkBox(uint32_t aType, ISOControl* aControl)
michael@0 571 : FullBox(NS_LITERAL_CSTRING("stsc"), 0, 0, aControl)
michael@0 572 , entry_count(0)
michael@0 573 {
michael@0 574 MOZ_COUNT_CTOR(SampleToChunkBox);
michael@0 575 }
michael@0 576
michael@0 577 SampleToChunkBox::~SampleToChunkBox()
michael@0 578 {
michael@0 579 MOZ_COUNT_DTOR(SampleToChunkBox);
michael@0 580 }
michael@0 581
michael@0 582 nsresult
michael@0 583 TimeToSampleBox::Generate(uint32_t* aBoxSize)
michael@0 584 {
michael@0 585 // We don't need time to sample table in fragmented mp4.
michael@0 586 entry_count = 0;
michael@0 587 size += sizeof(entry_count);
michael@0 588 *aBoxSize = size;
michael@0 589 return NS_OK;
michael@0 590 }
michael@0 591
michael@0 592 nsresult
michael@0 593 TimeToSampleBox::Write()
michael@0 594 {
michael@0 595 WRITE_FULLBOX(mControl, size)
michael@0 596 mControl->Write(entry_count);
michael@0 597 return NS_OK;
michael@0 598 }
michael@0 599
michael@0 600 TimeToSampleBox::TimeToSampleBox(uint32_t aType, ISOControl* aControl)
michael@0 601 : FullBox(NS_LITERAL_CSTRING("stts"), 0, 0, aControl)
michael@0 602 , entry_count(0)
michael@0 603 {
michael@0 604 MOZ_COUNT_CTOR(TimeToSampleBox);
michael@0 605 }
michael@0 606
michael@0 607 TimeToSampleBox::~TimeToSampleBox()
michael@0 608 {
michael@0 609 MOZ_COUNT_DTOR(TimeToSampleBox);
michael@0 610 }
michael@0 611
michael@0 612 nsresult
michael@0 613 SampleDescriptionBox::Generate(uint32_t* aBoxSize)
michael@0 614 {
michael@0 615 entry_count = 1;
michael@0 616 size += sizeof(entry_count);
michael@0 617
michael@0 618 nsresult rv;
michael@0 619 uint32_t box_size;
michael@0 620 rv = sample_entry_box->Generate(&box_size);
michael@0 621 NS_ENSURE_SUCCESS(rv, rv);
michael@0 622 size += box_size;
michael@0 623 *aBoxSize = size;
michael@0 624
michael@0 625 return NS_OK;
michael@0 626 }
michael@0 627
michael@0 628 nsresult
michael@0 629 SampleDescriptionBox::Write()
michael@0 630 {
michael@0 631 WRITE_FULLBOX(mControl, size)
michael@0 632 nsresult rv;
michael@0 633 mControl->Write(entry_count);
michael@0 634 rv = sample_entry_box->Write();
michael@0 635 NS_ENSURE_SUCCESS(rv, rv);
michael@0 636
michael@0 637 return NS_OK;
michael@0 638 }
michael@0 639
michael@0 640 SampleDescriptionBox::SampleDescriptionBox(uint32_t aType, ISOControl* aControl)
michael@0 641 : FullBox(NS_LITERAL_CSTRING("stsd"), 0, 0, aControl)
michael@0 642 , entry_count(0)
michael@0 643 {
michael@0 644 mTrackType = aType;
michael@0 645
michael@0 646 switch (mTrackType) {
michael@0 647 case Audio_Track:
michael@0 648 {
michael@0 649 CreateAudioSampleEntry(sample_entry_box);
michael@0 650 }
michael@0 651 break;
michael@0 652 case Video_Track:
michael@0 653 {
michael@0 654 CreateVideoSampleEntry(sample_entry_box);
michael@0 655 }
michael@0 656 break;
michael@0 657 }
michael@0 658 MOZ_ASSERT(sample_entry_box);
michael@0 659 MOZ_COUNT_CTOR(SampleDescriptionBox);
michael@0 660 }
michael@0 661
michael@0 662 nsresult
michael@0 663 SampleDescriptionBox::CreateAudioSampleEntry(nsRefPtr<SampleEntryBox>& aSampleEntry)
michael@0 664 {
michael@0 665 if (mAudioMeta->GetKind() == TrackMetadataBase::METADATA_AMR) {
michael@0 666 aSampleEntry = new AMRSampleEntry(mControl);
michael@0 667 } else if (mAudioMeta->GetKind() == TrackMetadataBase::METADATA_AAC) {
michael@0 668 aSampleEntry = new MP4AudioSampleEntry(mControl);
michael@0 669 } else {
michael@0 670 MOZ_ASSERT(0);
michael@0 671 }
michael@0 672 return NS_OK;
michael@0 673 }
michael@0 674
michael@0 675 nsresult
michael@0 676 SampleDescriptionBox::CreateVideoSampleEntry(nsRefPtr<SampleEntryBox>& aSampleEntry)
michael@0 677 {
michael@0 678 if (mVideoMeta->GetKind() == TrackMetadataBase::METADATA_AVC) {
michael@0 679 aSampleEntry = new AVCSampleEntry(mControl);
michael@0 680 } else {
michael@0 681 MOZ_ASSERT(0);
michael@0 682 }
michael@0 683 return NS_OK;
michael@0 684 }
michael@0 685
michael@0 686 SampleDescriptionBox::~SampleDescriptionBox()
michael@0 687 {
michael@0 688 MOZ_COUNT_DTOR(SampleDescriptionBox);
michael@0 689 }
michael@0 690
michael@0 691 nsresult
michael@0 692 SampleSizeBox::Generate(uint32_t* aBoxSize)
michael@0 693 {
michael@0 694 size += sizeof(sample_size) +
michael@0 695 sizeof(sample_count);
michael@0 696 *aBoxSize = size;
michael@0 697 return NS_OK;
michael@0 698 }
michael@0 699
michael@0 700 nsresult
michael@0 701 SampleSizeBox::Write()
michael@0 702 {
michael@0 703 WRITE_FULLBOX(mControl, size)
michael@0 704 mControl->Write(sample_size);
michael@0 705 mControl->Write(sample_count);
michael@0 706 return NS_OK;
michael@0 707 }
michael@0 708
michael@0 709 SampleSizeBox::SampleSizeBox(ISOControl* aControl)
michael@0 710 : FullBox(NS_LITERAL_CSTRING("stsz"), 0, 0, aControl)
michael@0 711 , sample_size(0)
michael@0 712 , sample_count(0)
michael@0 713 {
michael@0 714 MOZ_COUNT_CTOR(SampleSizeBox);
michael@0 715 }
michael@0 716
michael@0 717 SampleSizeBox::~SampleSizeBox()
michael@0 718 {
michael@0 719 MOZ_COUNT_DTOR(SampleSizeBox);
michael@0 720 }
michael@0 721
michael@0 722 SampleTableBox::SampleTableBox(uint32_t aType, ISOControl* aControl)
michael@0 723 : DefaultContainerImpl(NS_LITERAL_CSTRING("stbl"), aControl)
michael@0 724 {
michael@0 725 boxes.AppendElement(new SampleDescriptionBox(aType, aControl));
michael@0 726 boxes.AppendElement(new TimeToSampleBox(aType, aControl));
michael@0 727 boxes.AppendElement(new SampleToChunkBox(aType, aControl));
michael@0 728 boxes.AppendElement(new SampleSizeBox(aControl));
michael@0 729 boxes.AppendElement(new ChunkOffsetBox(aType, aControl));
michael@0 730 MOZ_COUNT_CTOR(SampleTableBox);
michael@0 731 }
michael@0 732
michael@0 733 SampleTableBox::~SampleTableBox()
michael@0 734 {
michael@0 735 MOZ_COUNT_DTOR(SampleTableBox);
michael@0 736 }
michael@0 737
michael@0 738 nsresult
michael@0 739 DataEntryUrlBox::Generate(uint32_t* aBoxSize)
michael@0 740 {
michael@0 741 // location is null here, do nothing
michael@0 742 size += location.Length();
michael@0 743 *aBoxSize = size;
michael@0 744
michael@0 745 return NS_OK;
michael@0 746 }
michael@0 747
michael@0 748 nsresult
michael@0 749 DataEntryUrlBox::Write()
michael@0 750 {
michael@0 751 WRITE_FULLBOX(mControl, size)
michael@0 752 return NS_OK;
michael@0 753 }
michael@0 754
michael@0 755 DataEntryUrlBox::DataEntryUrlBox()
michael@0 756 : FullBox(NS_LITERAL_CSTRING("url "), 0, 0, (ISOControl*) nullptr)
michael@0 757 {
michael@0 758 MOZ_COUNT_CTOR(DataEntryUrlBox);
michael@0 759 }
michael@0 760
michael@0 761 DataEntryUrlBox::DataEntryUrlBox(ISOControl* aControl)
michael@0 762 : FullBox(NS_LITERAL_CSTRING("url "), 0, flags_media_at_the_same_file, aControl)
michael@0 763 {
michael@0 764 MOZ_COUNT_CTOR(DataEntryUrlBox);
michael@0 765 }
michael@0 766
michael@0 767 DataEntryUrlBox::DataEntryUrlBox(const DataEntryUrlBox& aBox)
michael@0 768 : FullBox(aBox.boxType, aBox.version, aBox.flags.to_ulong(), aBox.mControl)
michael@0 769 {
michael@0 770 location = aBox.location;
michael@0 771 MOZ_COUNT_CTOR(DataEntryUrlBox);
michael@0 772 }
michael@0 773
michael@0 774 DataEntryUrlBox::~DataEntryUrlBox()
michael@0 775 {
michael@0 776 MOZ_COUNT_DTOR(DataEntryUrlBox);
michael@0 777 }
michael@0 778
michael@0 779 nsresult DataReferenceBox::Generate(uint32_t* aBoxSize)
michael@0 780 {
michael@0 781 entry_count = 1; // only allow on entry here
michael@0 782 size += sizeof(uint32_t);
michael@0 783
michael@0 784 for (uint32_t i = 0; i < entry_count; i++) {
michael@0 785 uint32_t box_size = 0;
michael@0 786 DataEntryUrlBox* url = new DataEntryUrlBox(mControl);
michael@0 787 url->Generate(&box_size);
michael@0 788 size += box_size;
michael@0 789 urls.AppendElement(url);
michael@0 790 }
michael@0 791
michael@0 792 *aBoxSize = size;
michael@0 793
michael@0 794 return NS_OK;
michael@0 795 }
michael@0 796
michael@0 797 nsresult DataReferenceBox::Write()
michael@0 798 {
michael@0 799 WRITE_FULLBOX(mControl, size)
michael@0 800 mControl->Write(entry_count);
michael@0 801
michael@0 802 for (uint32_t i = 0; i < entry_count; i++) {
michael@0 803 urls[i]->Write();
michael@0 804 }
michael@0 805
michael@0 806 return NS_OK;
michael@0 807 }
michael@0 808
michael@0 809 DataReferenceBox::DataReferenceBox(ISOControl* aControl)
michael@0 810 : FullBox(NS_LITERAL_CSTRING("dref"), 0, 0, aControl)
michael@0 811 , entry_count(0)
michael@0 812 {
michael@0 813 MOZ_COUNT_CTOR(DataReferenceBox);
michael@0 814 }
michael@0 815
michael@0 816 DataReferenceBox::~DataReferenceBox()
michael@0 817 {
michael@0 818 MOZ_COUNT_DTOR(DataReferenceBox);
michael@0 819 }
michael@0 820
michael@0 821 DataInformationBox::DataInformationBox(ISOControl* aControl)
michael@0 822 : DefaultContainerImpl(NS_LITERAL_CSTRING("dinf"), aControl)
michael@0 823 {
michael@0 824 boxes.AppendElement(new DataReferenceBox(aControl));
michael@0 825 MOZ_COUNT_CTOR(DataInformationBox);
michael@0 826 }
michael@0 827
michael@0 828 DataInformationBox::~DataInformationBox()
michael@0 829 {
michael@0 830 MOZ_COUNT_DTOR(DataInformationBox);
michael@0 831 }
michael@0 832
michael@0 833 nsresult
michael@0 834 VideoMediaHeaderBox::Generate(uint32_t* aBoxSize)
michael@0 835 {
michael@0 836 size += sizeof(graphicsmode) +
michael@0 837 sizeof(opcolor);
michael@0 838
michael@0 839 *aBoxSize = size;
michael@0 840
michael@0 841 return NS_OK;
michael@0 842 }
michael@0 843
michael@0 844 nsresult
michael@0 845 VideoMediaHeaderBox::Write()
michael@0 846 {
michael@0 847 WRITE_FULLBOX(mControl, size)
michael@0 848 mControl->Write(graphicsmode);
michael@0 849 mControl->WriteArray(opcolor, 3);
michael@0 850 return NS_OK;
michael@0 851 }
michael@0 852
michael@0 853 VideoMediaHeaderBox::VideoMediaHeaderBox(ISOControl* aControl)
michael@0 854 : FullBox(NS_LITERAL_CSTRING("vmhd"), 0, 1, aControl)
michael@0 855 , graphicsmode(0)
michael@0 856 {
michael@0 857 memset(opcolor, 0 , sizeof(opcolor));
michael@0 858 MOZ_COUNT_CTOR(VideoMediaHeaderBox);
michael@0 859 }
michael@0 860
michael@0 861 VideoMediaHeaderBox::~VideoMediaHeaderBox()
michael@0 862 {
michael@0 863 MOZ_COUNT_DTOR(VideoMediaHeaderBox);
michael@0 864 }
michael@0 865
michael@0 866 nsresult
michael@0 867 SoundMediaHeaderBox::Generate(uint32_t* aBoxSize)
michael@0 868 {
michael@0 869 balance = 0;
michael@0 870 reserved = 0;
michael@0 871 size += sizeof(balance) +
michael@0 872 sizeof(reserved);
michael@0 873
michael@0 874 *aBoxSize = size;
michael@0 875
michael@0 876 return NS_OK;
michael@0 877 }
michael@0 878
michael@0 879 nsresult
michael@0 880 SoundMediaHeaderBox::Write()
michael@0 881 {
michael@0 882 WRITE_FULLBOX(mControl, size)
michael@0 883 mControl->Write(balance);
michael@0 884 mControl->Write(reserved);
michael@0 885
michael@0 886 return NS_OK;
michael@0 887 }
michael@0 888
michael@0 889 SoundMediaHeaderBox::SoundMediaHeaderBox(ISOControl* aControl)
michael@0 890 : FullBox(NS_LITERAL_CSTRING("smhd"), 0, 0, aControl)
michael@0 891 {
michael@0 892 MOZ_COUNT_CTOR(SoundMediaHeaderBox);
michael@0 893 }
michael@0 894
michael@0 895 SoundMediaHeaderBox::~SoundMediaHeaderBox()
michael@0 896 {
michael@0 897 MOZ_COUNT_DTOR(SoundMediaHeaderBox);
michael@0 898 }
michael@0 899
michael@0 900 MediaInformationBox::MediaInformationBox(uint32_t aType, ISOControl* aControl)
michael@0 901 : DefaultContainerImpl(NS_LITERAL_CSTRING("minf"), aControl)
michael@0 902 {
michael@0 903 mTrackType = aType;
michael@0 904
michael@0 905 if (mTrackType == Audio_Track) {
michael@0 906 boxes.AppendElement(new SoundMediaHeaderBox(aControl));
michael@0 907 } else if (mTrackType == Video_Track) {
michael@0 908 boxes.AppendElement(new VideoMediaHeaderBox(aControl));
michael@0 909 } else {
michael@0 910 MOZ_ASSERT(0);
michael@0 911 }
michael@0 912
michael@0 913 boxes.AppendElement(new DataInformationBox(aControl));
michael@0 914 boxes.AppendElement(new SampleTableBox(aType, aControl));
michael@0 915 MOZ_COUNT_CTOR(MediaInformationBox);
michael@0 916 }
michael@0 917
michael@0 918 MediaInformationBox::~MediaInformationBox()
michael@0 919 {
michael@0 920 MOZ_COUNT_DTOR(MediaInformationBox);
michael@0 921 }
michael@0 922
michael@0 923 nsresult
michael@0 924 HandlerBox::Generate(uint32_t* aBoxSize)
michael@0 925 {
michael@0 926 pre_defined = 0;
michael@0 927 if (mTrackType == Audio_Track) {
michael@0 928 handler_type = FOURCC('s', 'o', 'u', 'n');
michael@0 929 } else if (mTrackType == Video_Track) {
michael@0 930 handler_type = FOURCC('v', 'i', 'd', 'e');
michael@0 931 }
michael@0 932
michael@0 933 size += sizeof(pre_defined) +
michael@0 934 sizeof(handler_type) +
michael@0 935 sizeof(reserved);
michael@0 936
michael@0 937 *aBoxSize = size;
michael@0 938
michael@0 939 return NS_OK;
michael@0 940 }
michael@0 941
michael@0 942 nsresult
michael@0 943 HandlerBox::Write()
michael@0 944 {
michael@0 945 WRITE_FULLBOX(mControl, size)
michael@0 946 mControl->Write(pre_defined);
michael@0 947 mControl->Write(handler_type);
michael@0 948 mControl->WriteArray(reserved, 3);
michael@0 949
michael@0 950 return NS_OK;
michael@0 951 }
michael@0 952
michael@0 953 HandlerBox::HandlerBox(uint32_t aType, ISOControl* aControl)
michael@0 954 : FullBox(NS_LITERAL_CSTRING("hdlr"), 0, 0, aControl)
michael@0 955 , pre_defined(0)
michael@0 956 , handler_type(0)
michael@0 957 {
michael@0 958 mTrackType = aType;
michael@0 959 memset(reserved, 0 , sizeof(reserved));
michael@0 960 MOZ_COUNT_CTOR(HandlerBox);
michael@0 961 }
michael@0 962
michael@0 963 HandlerBox::~HandlerBox()
michael@0 964 {
michael@0 965 MOZ_COUNT_DTOR(HandlerBox);
michael@0 966 }
michael@0 967
michael@0 968 MediaHeaderBox::MediaHeaderBox(uint32_t aType, ISOControl* aControl)
michael@0 969 : FullBox(NS_LITERAL_CSTRING("mdhd"), 0, 0, aControl)
michael@0 970 , creation_time(0)
michael@0 971 , modification_time(0)
michael@0 972 , timescale(0)
michael@0 973 , duration(0)
michael@0 974 , pad(0)
michael@0 975 , lang1(0)
michael@0 976 , lang2(0)
michael@0 977 , lang3(0)
michael@0 978 , pre_defined(0)
michael@0 979 {
michael@0 980 mTrackType = aType;
michael@0 981 MOZ_COUNT_CTOR(MediaHeaderBox);
michael@0 982 }
michael@0 983
michael@0 984 MediaHeaderBox::~MediaHeaderBox()
michael@0 985 {
michael@0 986 MOZ_COUNT_DTOR(MediaHeaderBox);
michael@0 987 }
michael@0 988
michael@0 989 uint32_t
michael@0 990 MediaHeaderBox::GetTimeScale()
michael@0 991 {
michael@0 992 if (mTrackType == Audio_Track) {
michael@0 993 return mAudioMeta->GetAudioSampleRate();
michael@0 994 }
michael@0 995
michael@0 996 return mVideoMeta->GetVideoClockRate();
michael@0 997 }
michael@0 998
michael@0 999 nsresult
michael@0 1000 MediaHeaderBox::Generate(uint32_t* aBoxSize)
michael@0 1001 {
michael@0 1002 creation_time = mControl->GetTime();
michael@0 1003 modification_time = mControl->GetTime();
michael@0 1004 timescale = GetTimeScale();
michael@0 1005 duration = 0; // fragmented mp4
michael@0 1006
michael@0 1007 pad = 0;
michael@0 1008 lang1 = 'u' - 0x60; // "und" underdetermined language
michael@0 1009 lang2 = 'n' - 0x60;
michael@0 1010 lang3 = 'd' - 0x60;
michael@0 1011 size += (pad.size() + lang1.size() + lang2.size() + lang3.size()) / CHAR_BIT;
michael@0 1012
michael@0 1013 pre_defined = 0;
michael@0 1014 size += sizeof(creation_time) +
michael@0 1015 sizeof(modification_time) +
michael@0 1016 sizeof(timescale) +
michael@0 1017 sizeof(duration) +
michael@0 1018 sizeof(pre_defined);
michael@0 1019
michael@0 1020 *aBoxSize = size;
michael@0 1021
michael@0 1022 return NS_OK;
michael@0 1023 }
michael@0 1024
michael@0 1025 nsresult
michael@0 1026 MediaHeaderBox::Write()
michael@0 1027 {
michael@0 1028 WRITE_FULLBOX(mControl, size)
michael@0 1029 mControl->Write(creation_time);
michael@0 1030 mControl->Write(modification_time);
michael@0 1031 mControl->Write(timescale);
michael@0 1032 mControl->Write(duration);
michael@0 1033 mControl->WriteBits(pad.to_ulong(), pad.size());
michael@0 1034 mControl->WriteBits(lang1.to_ulong(), lang1.size());
michael@0 1035 mControl->WriteBits(lang2.to_ulong(), lang2.size());
michael@0 1036 mControl->WriteBits(lang3.to_ulong(), lang3.size());
michael@0 1037 mControl->Write(pre_defined);
michael@0 1038
michael@0 1039 return NS_OK;
michael@0 1040 }
michael@0 1041
michael@0 1042 MovieBox::MovieBox(ISOControl* aControl)
michael@0 1043 : DefaultContainerImpl(NS_LITERAL_CSTRING("moov"), aControl)
michael@0 1044 {
michael@0 1045 boxes.AppendElement(new MovieHeaderBox(aControl));
michael@0 1046 if (aControl->HasAudioTrack()) {
michael@0 1047 boxes.AppendElement(new TrackBox(Audio_Track, aControl));
michael@0 1048 }
michael@0 1049 if (aControl->HasVideoTrack()) {
michael@0 1050 boxes.AppendElement(new TrackBox(Video_Track, aControl));
michael@0 1051 }
michael@0 1052 boxes.AppendElement(new MovieExtendsBox(aControl));
michael@0 1053 MOZ_COUNT_CTOR(MovieBox);
michael@0 1054 }
michael@0 1055
michael@0 1056 MovieBox::~MovieBox()
michael@0 1057 {
michael@0 1058 MOZ_COUNT_DTOR(MovieBox);
michael@0 1059 }
michael@0 1060
michael@0 1061 nsresult
michael@0 1062 MovieHeaderBox::Generate(uint32_t* aBoxSize)
michael@0 1063 {
michael@0 1064 creation_time = mControl->GetTime();
michael@0 1065 modification_time = mControl->GetTime();
michael@0 1066 timescale = GetTimeScale();
michael@0 1067 duration = 0; // The duration is always 0 in fragmented mp4.
michael@0 1068 next_track_ID = mControl->GetNextTrackID();
michael@0 1069
michael@0 1070 size += sizeof(next_track_ID) +
michael@0 1071 sizeof(creation_time) +
michael@0 1072 sizeof(modification_time) +
michael@0 1073 sizeof(timescale) +
michael@0 1074 sizeof(duration) +
michael@0 1075 sizeof(rate) +
michael@0 1076 sizeof(volume) +
michael@0 1077 sizeof(reserved16) +
michael@0 1078 sizeof(reserved32) +
michael@0 1079 sizeof(matrix) +
michael@0 1080 sizeof(pre_defined);
michael@0 1081
michael@0 1082 *aBoxSize = size;
michael@0 1083
michael@0 1084 return NS_OK;
michael@0 1085 }
michael@0 1086
michael@0 1087 nsresult
michael@0 1088 MovieHeaderBox::Write()
michael@0 1089 {
michael@0 1090 WRITE_FULLBOX(mControl, size)
michael@0 1091 mControl->Write(creation_time);
michael@0 1092 mControl->Write(modification_time);
michael@0 1093 mControl->Write(timescale);
michael@0 1094 mControl->Write(duration);
michael@0 1095 mControl->Write(rate);
michael@0 1096 mControl->Write(volume);
michael@0 1097 mControl->Write(reserved16);
michael@0 1098 mControl->WriteArray(reserved32, 2);
michael@0 1099 mControl->WriteArray(matrix, 9);
michael@0 1100 mControl->WriteArray(pre_defined, 6);
michael@0 1101 mControl->Write(next_track_ID);
michael@0 1102
michael@0 1103 return NS_OK;
michael@0 1104 }
michael@0 1105
michael@0 1106 uint32_t
michael@0 1107 MovieHeaderBox::GetTimeScale()
michael@0 1108 {
michael@0 1109 // Only audio track in container.
michael@0 1110 if (mAudioMeta && !mVideoMeta) {
michael@0 1111 return mAudioMeta->GetAudioSampleRate();
michael@0 1112 }
michael@0 1113
michael@0 1114 // return video rate
michael@0 1115 return mVideoMeta->GetVideoClockRate();
michael@0 1116 }
michael@0 1117
michael@0 1118 MovieHeaderBox::~MovieHeaderBox()
michael@0 1119 {
michael@0 1120 MOZ_COUNT_DTOR(MovieHeaderBox);
michael@0 1121 }
michael@0 1122
michael@0 1123 MovieHeaderBox::MovieHeaderBox(ISOControl* aControl)
michael@0 1124 : FullBox(NS_LITERAL_CSTRING("mvhd"), 0, 0, aControl)
michael@0 1125 , creation_time(0)
michael@0 1126 , modification_time(0)
michael@0 1127 , timescale(90000)
michael@0 1128 , duration(0)
michael@0 1129 , rate(0x00010000)
michael@0 1130 , volume(0x0100)
michael@0 1131 , reserved16(0)
michael@0 1132 , next_track_ID(1)
michael@0 1133 {
michael@0 1134 memcpy(matrix, iso_matrix, sizeof(matrix));
michael@0 1135 memset(reserved32, 0, sizeof(reserved32));
michael@0 1136 memset(pre_defined, 0, sizeof(pre_defined));
michael@0 1137 MOZ_COUNT_CTOR(MovieHeaderBox);
michael@0 1138 }
michael@0 1139
michael@0 1140 TrackHeaderBox::TrackHeaderBox(uint32_t aType, ISOControl* aControl)
michael@0 1141 : FullBox(NS_LITERAL_CSTRING("tkhd"), 0,
michael@0 1142 flags_track_enabled | flags_track_in_movie | flags_track_in_preview,
michael@0 1143 aControl)
michael@0 1144 , creation_time(0)
michael@0 1145 , modification_time(0)
michael@0 1146 , track_ID(0)
michael@0 1147 , reserved(0)
michael@0 1148 , duration(0)
michael@0 1149 , layer(0)
michael@0 1150 , alternate_group(0)
michael@0 1151 , volume(0)
michael@0 1152 , reserved3(0)
michael@0 1153 , width(0)
michael@0 1154 , height(0)
michael@0 1155 {
michael@0 1156 mTrackType = aType;
michael@0 1157 memcpy(matrix, iso_matrix, sizeof(matrix));
michael@0 1158 memset(reserved2, 0, sizeof(reserved2));
michael@0 1159 MOZ_COUNT_CTOR(TrackHeaderBox);
michael@0 1160 }
michael@0 1161
michael@0 1162 TrackHeaderBox::~TrackHeaderBox()
michael@0 1163 {
michael@0 1164 MOZ_COUNT_DTOR(TrackHeaderBox);
michael@0 1165 }
michael@0 1166
michael@0 1167 nsresult
michael@0 1168 TrackHeaderBox::Generate(uint32_t* aBoxSize)
michael@0 1169 {
michael@0 1170 creation_time = mControl->GetTime();
michael@0 1171 modification_time = mControl->GetTime();
michael@0 1172 track_ID = (mTrackType == Audio_Track ?
michael@0 1173 mControl->GetTrackID(mAudioMeta->GetKind()) :
michael@0 1174 mControl->GetTrackID(mVideoMeta->GetKind()));
michael@0 1175 // fragmented mp4
michael@0 1176 duration = 0;
michael@0 1177
michael@0 1178 // volume, audiotrack is always 0x0100 in 14496-12 8.3.2.2
michael@0 1179 volume = (mTrackType == Audio_Track ? 0x0100 : 0);
michael@0 1180
michael@0 1181 if (mTrackType == Video_Track) {
michael@0 1182 width = mVideoMeta->GetVideoDisplayWidth() << 16;
michael@0 1183 height = mVideoMeta->GetVideoDisplayHeight() << 16;
michael@0 1184 // Check display size, using the pixel size if any of them is invalid.
michael@0 1185 if (!width || !height) {
michael@0 1186 width = mVideoMeta->GetVideoWidth() << 16;
michael@0 1187 height = mVideoMeta->GetVideoHeight() << 16;
michael@0 1188 }
michael@0 1189 }
michael@0 1190
michael@0 1191 size += sizeof(creation_time) +
michael@0 1192 sizeof(modification_time) +
michael@0 1193 sizeof(track_ID) +
michael@0 1194 sizeof(reserved) +
michael@0 1195 sizeof(duration) +
michael@0 1196 sizeof(reserved2) +
michael@0 1197 sizeof(layer) +
michael@0 1198 sizeof(alternate_group) +
michael@0 1199 sizeof(volume) +
michael@0 1200 sizeof(reserved3) +
michael@0 1201 sizeof(matrix) +
michael@0 1202 sizeof(width) +
michael@0 1203 sizeof(height);
michael@0 1204
michael@0 1205 *aBoxSize = size;
michael@0 1206
michael@0 1207 return NS_OK;
michael@0 1208 }
michael@0 1209
michael@0 1210 nsresult
michael@0 1211 TrackHeaderBox::Write()
michael@0 1212 {
michael@0 1213 WRITE_FULLBOX(mControl, size)
michael@0 1214 mControl->Write(creation_time);
michael@0 1215 mControl->Write(modification_time);
michael@0 1216 mControl->Write(track_ID);
michael@0 1217 mControl->Write(reserved);
michael@0 1218 mControl->Write(duration);
michael@0 1219 mControl->WriteArray(reserved2, 2);
michael@0 1220 mControl->Write(layer);
michael@0 1221 mControl->Write(alternate_group);
michael@0 1222 mControl->Write(volume);
michael@0 1223 mControl->Write(reserved3);
michael@0 1224 mControl->WriteArray(matrix, 9);
michael@0 1225 mControl->Write(width);
michael@0 1226 mControl->Write(height);
michael@0 1227
michael@0 1228 return NS_OK;
michael@0 1229 }
michael@0 1230
michael@0 1231 nsresult
michael@0 1232 FileTypeBox::Generate(uint32_t* aBoxSize)
michael@0 1233 {
michael@0 1234 minor_version = 0;
michael@0 1235
michael@0 1236 if (mControl->GetMuxingType() == ISOMediaWriter::TYPE_FRAG_MP4) {
michael@0 1237 if (!mControl->HasVideoTrack() && mControl->HasAudioTrack()) {
michael@0 1238 major_brand = "M4A ";
michael@0 1239 } else {
michael@0 1240 major_brand = "MP42";
michael@0 1241 }
michael@0 1242 compatible_brands.AppendElement("mp42");
michael@0 1243 compatible_brands.AppendElement("isom");
michael@0 1244 } else if (mControl->GetMuxingType() == ISOMediaWriter::TYPE_FRAG_3GP) {
michael@0 1245 major_brand = "3gp9";
michael@0 1246 // According to 3GPP TS 26.244 V12.2.0, section 5.3.4, it's recommended to
michael@0 1247 // list all compatible brands here. 3GP spec supports fragment from '3gp6'.
michael@0 1248 compatible_brands.AppendElement("3gp9");
michael@0 1249 compatible_brands.AppendElement("3gp8");
michael@0 1250 compatible_brands.AppendElement("3gp7");
michael@0 1251 compatible_brands.AppendElement("3gp6");
michael@0 1252 compatible_brands.AppendElement("isom");
michael@0 1253 } else {
michael@0 1254 MOZ_ASSERT(0);
michael@0 1255 }
michael@0 1256
michael@0 1257 size += major_brand.Length() +
michael@0 1258 sizeof(minor_version) +
michael@0 1259 compatible_brands.Length() * 4;
michael@0 1260
michael@0 1261 *aBoxSize = size;
michael@0 1262
michael@0 1263 return NS_OK;
michael@0 1264 }
michael@0 1265
michael@0 1266 nsresult
michael@0 1267 FileTypeBox::Write()
michael@0 1268 {
michael@0 1269 BoxSizeChecker checker(mControl, size);
michael@0 1270 Box::Write();
michael@0 1271 mControl->WriteFourCC(major_brand.get());
michael@0 1272 mControl->Write(minor_version);
michael@0 1273 uint32_t len = compatible_brands.Length();
michael@0 1274 for (uint32_t i = 0; i < len; i++) {
michael@0 1275 mControl->WriteFourCC(compatible_brands[i].get());
michael@0 1276 }
michael@0 1277
michael@0 1278 return NS_OK;
michael@0 1279 }
michael@0 1280
michael@0 1281 FileTypeBox::FileTypeBox(ISOControl* aControl)
michael@0 1282 : Box(NS_LITERAL_CSTRING("ftyp"), aControl)
michael@0 1283 , minor_version(0)
michael@0 1284 {
michael@0 1285 MOZ_COUNT_CTOR(FileTypeBox);
michael@0 1286 }
michael@0 1287
michael@0 1288 FileTypeBox::~FileTypeBox()
michael@0 1289 {
michael@0 1290 MOZ_COUNT_DTOR(FileTypeBox);
michael@0 1291 }
michael@0 1292
michael@0 1293 MediaBox::MediaBox(uint32_t aType, ISOControl* aControl)
michael@0 1294 : DefaultContainerImpl(NS_LITERAL_CSTRING("mdia"), aControl)
michael@0 1295 {
michael@0 1296 mTrackType = aType;
michael@0 1297 boxes.AppendElement(new MediaHeaderBox(aType, aControl));
michael@0 1298 boxes.AppendElement(new HandlerBox(aType, aControl));
michael@0 1299 boxes.AppendElement(new MediaInformationBox(aType, aControl));
michael@0 1300 MOZ_COUNT_CTOR(MediaBox);
michael@0 1301 }
michael@0 1302
michael@0 1303 MediaBox::~MediaBox()
michael@0 1304 {
michael@0 1305 MOZ_COUNT_DTOR(MediaBox);
michael@0 1306 }
michael@0 1307
michael@0 1308 nsresult
michael@0 1309 DefaultContainerImpl::Generate(uint32_t* aBoxSize)
michael@0 1310 {
michael@0 1311 nsresult rv;
michael@0 1312 uint32_t box_size;
michael@0 1313 uint32_t len = boxes.Length();
michael@0 1314 for (uint32_t i = 0; i < len; i++) {
michael@0 1315 rv = boxes.ElementAt(i)->Generate(&box_size);
michael@0 1316 NS_ENSURE_SUCCESS(rv, rv);
michael@0 1317 size += box_size;
michael@0 1318 }
michael@0 1319 *aBoxSize = size;
michael@0 1320 return NS_OK;
michael@0 1321 }
michael@0 1322
michael@0 1323 nsresult
michael@0 1324 DefaultContainerImpl::Find(const nsACString& aType,
michael@0 1325 nsTArray<nsRefPtr<MuxerOperation>>& aOperations)
michael@0 1326 {
michael@0 1327 nsresult rv = Box::Find(aType, aOperations);
michael@0 1328 NS_ENSURE_SUCCESS(rv, rv);
michael@0 1329
michael@0 1330 uint32_t len = boxes.Length();
michael@0 1331 for (uint32_t i = 0; i < len; i++) {
michael@0 1332 rv = boxes.ElementAt(i)->Find(aType, aOperations);
michael@0 1333 NS_ENSURE_SUCCESS(rv, rv);
michael@0 1334 }
michael@0 1335 return NS_OK;
michael@0 1336 }
michael@0 1337
michael@0 1338 nsresult
michael@0 1339 DefaultContainerImpl::Write()
michael@0 1340 {
michael@0 1341 BoxSizeChecker checker(mControl, size);
michael@0 1342 Box::Write();
michael@0 1343
michael@0 1344 nsresult rv;
michael@0 1345 uint32_t len = boxes.Length();
michael@0 1346 for (uint32_t i = 0; i < len; i++) {
michael@0 1347 rv = boxes.ElementAt(i)->Write();
michael@0 1348 NS_ENSURE_SUCCESS(rv, rv);
michael@0 1349 }
michael@0 1350
michael@0 1351 return NS_OK;
michael@0 1352 }
michael@0 1353
michael@0 1354 DefaultContainerImpl::DefaultContainerImpl(const nsACString& aType,
michael@0 1355 ISOControl* aControl)
michael@0 1356 : Box(aType, aControl)
michael@0 1357 {
michael@0 1358 }
michael@0 1359
michael@0 1360 nsresult
michael@0 1361 Box::Write()
michael@0 1362 {
michael@0 1363 mControl->Write(size);
michael@0 1364 mControl->WriteFourCC(boxType.get());
michael@0 1365 return NS_OK;
michael@0 1366 }
michael@0 1367
michael@0 1368 nsresult
michael@0 1369 Box::Find(const nsACString& aType, nsTArray<nsRefPtr<MuxerOperation>>& aOperations)
michael@0 1370 {
michael@0 1371 if (boxType == aType) {
michael@0 1372 aOperations.AppendElement(this);
michael@0 1373 }
michael@0 1374 return NS_OK;
michael@0 1375 }
michael@0 1376
michael@0 1377 Box::Box(const nsACString& aType, ISOControl* aControl)
michael@0 1378 : size(8), mControl(aControl)
michael@0 1379 {
michael@0 1380 MOZ_ASSERT(aType.Length() == 4);
michael@0 1381 boxType = aType;
michael@0 1382 aControl->GetAudioMetadata(mAudioMeta);
michael@0 1383 aControl->GetVideoMetadata(mVideoMeta);
michael@0 1384 }
michael@0 1385
michael@0 1386 FullBox::FullBox(const nsACString& aType, uint8_t aVersion, uint32_t aFlags,
michael@0 1387 ISOControl* aControl)
michael@0 1388 : Box(aType, aControl)
michael@0 1389 {
michael@0 1390 // Cast to uint64_t due to VC2010 bug.
michael@0 1391 std::bitset<24> tmp_flags((uint64_t)aFlags);
michael@0 1392 version = aVersion;
michael@0 1393 flags = tmp_flags;
michael@0 1394 size += sizeof(version) + flags.size() / CHAR_BIT;
michael@0 1395 }
michael@0 1396
michael@0 1397 nsresult
michael@0 1398 FullBox::Write()
michael@0 1399 {
michael@0 1400 Box::Write();
michael@0 1401 mControl->Write(version);
michael@0 1402 mControl->WriteBits(flags.to_ulong(), flags.size());
michael@0 1403 return NS_OK;
michael@0 1404 }
michael@0 1405
michael@0 1406 TrackBox::TrackBox(uint32_t aTrackType, ISOControl* aControl)
michael@0 1407 : DefaultContainerImpl(NS_LITERAL_CSTRING("trak"), aControl)
michael@0 1408 {
michael@0 1409 boxes.AppendElement(new TrackHeaderBox(aTrackType, aControl));
michael@0 1410 boxes.AppendElement(new MediaBox(aTrackType, aControl));
michael@0 1411 MOZ_COUNT_CTOR(TrackBox);
michael@0 1412 }
michael@0 1413
michael@0 1414 TrackBox::~TrackBox()
michael@0 1415 {
michael@0 1416 MOZ_COUNT_DTOR(TrackBox);
michael@0 1417 }
michael@0 1418
michael@0 1419 SampleEntryBox::SampleEntryBox(const nsACString& aFormat, ISOControl* aControl)
michael@0 1420 : Box(aFormat, aControl)
michael@0 1421 , data_reference_index(0)
michael@0 1422 {
michael@0 1423 data_reference_index = 1; // There is only one data reference in each track.
michael@0 1424 size += sizeof(reserved) +
michael@0 1425 sizeof(data_reference_index);
michael@0 1426 memset(reserved, 0, sizeof(reserved));
michael@0 1427 }
michael@0 1428
michael@0 1429 nsresult
michael@0 1430 SampleEntryBox::Write()
michael@0 1431 {
michael@0 1432 Box::Write();
michael@0 1433 mControl->Write(reserved, sizeof(reserved));
michael@0 1434 mControl->Write(data_reference_index);
michael@0 1435 return NS_OK;
michael@0 1436 }
michael@0 1437
michael@0 1438 nsresult
michael@0 1439 AudioSampleEntry::Write()
michael@0 1440 {
michael@0 1441 SampleEntryBox::Write();
michael@0 1442 mControl->Write(sound_version);
michael@0 1443 mControl->Write(reserved2, sizeof(reserved2));
michael@0 1444 mControl->Write(channels);
michael@0 1445 mControl->Write(sample_size);
michael@0 1446 mControl->Write(compressionId);
michael@0 1447 mControl->Write(packet_size);
michael@0 1448 mControl->Write(timeScale);
michael@0 1449 return NS_OK;
michael@0 1450 }
michael@0 1451
michael@0 1452 AudioSampleEntry::AudioSampleEntry(const nsACString& aFormat, ISOControl* aControl)
michael@0 1453 : SampleEntryBox(aFormat, aControl)
michael@0 1454 , sound_version(0)
michael@0 1455 , channels(2)
michael@0 1456 , sample_size(16)
michael@0 1457 , compressionId(0)
michael@0 1458 , packet_size(0)
michael@0 1459 , timeScale(0)
michael@0 1460 {
michael@0 1461 memset(reserved2, 0 , sizeof(reserved2));
michael@0 1462 channels = mAudioMeta->GetAudioChannels();
michael@0 1463 timeScale = mAudioMeta->GetAudioSampleRate() << 16;
michael@0 1464
michael@0 1465 size += sizeof(sound_version) +
michael@0 1466 sizeof(reserved2) +
michael@0 1467 sizeof(sample_size) +
michael@0 1468 sizeof(channels) +
michael@0 1469 sizeof(packet_size) +
michael@0 1470 sizeof(compressionId) +
michael@0 1471 sizeof(timeScale);
michael@0 1472
michael@0 1473 MOZ_COUNT_CTOR(AudioSampleEntry);
michael@0 1474 }
michael@0 1475
michael@0 1476 AudioSampleEntry::~AudioSampleEntry()
michael@0 1477 {
michael@0 1478 MOZ_COUNT_DTOR(AudioSampleEntry);
michael@0 1479 }
michael@0 1480
michael@0 1481 nsresult
michael@0 1482 VisualSampleEntry::Write()
michael@0 1483 {
michael@0 1484 SampleEntryBox::Write();
michael@0 1485
michael@0 1486 mControl->Write(reserved, sizeof(reserved));
michael@0 1487 mControl->Write(width);
michael@0 1488 mControl->Write(height);
michael@0 1489 mControl->Write(horizresolution);
michael@0 1490 mControl->Write(vertresolution);
michael@0 1491 mControl->Write(reserved2);
michael@0 1492 mControl->Write(frame_count);
michael@0 1493 mControl->Write(compressorName, sizeof(compressorName));
michael@0 1494 mControl->Write(depth);
michael@0 1495 mControl->Write(pre_defined);
michael@0 1496
michael@0 1497 return NS_OK;
michael@0 1498 }
michael@0 1499
michael@0 1500 VisualSampleEntry::VisualSampleEntry(const nsACString& aFormat, ISOControl* aControl)
michael@0 1501 : SampleEntryBox(aFormat, aControl)
michael@0 1502 , width(0)
michael@0 1503 , height(0)
michael@0 1504 , horizresolution(resolution_72_dpi)
michael@0 1505 , vertresolution(resolution_72_dpi)
michael@0 1506 , reserved2(0)
michael@0 1507 , frame_count(1)
michael@0 1508 , depth(video_depth)
michael@0 1509 , pre_defined(-1)
michael@0 1510 {
michael@0 1511 memset(reserved, 0 , sizeof(reserved));
michael@0 1512 memset(compressorName, 0 , sizeof(compressorName));
michael@0 1513
michael@0 1514 // both fields occupy 16 bits defined in 14496-2 6.2.3.
michael@0 1515 width = mVideoMeta->GetVideoWidth();
michael@0 1516 height = mVideoMeta->GetVideoHeight();
michael@0 1517
michael@0 1518 size += sizeof(reserved) +
michael@0 1519 sizeof(width) +
michael@0 1520 sizeof(height) +
michael@0 1521 sizeof(horizresolution) +
michael@0 1522 sizeof(vertresolution) +
michael@0 1523 sizeof(reserved2) +
michael@0 1524 sizeof(frame_count) +
michael@0 1525 sizeof(compressorName) +
michael@0 1526 sizeof(depth) +
michael@0 1527 sizeof(pre_defined);
michael@0 1528
michael@0 1529 MOZ_COUNT_CTOR(VisualSampleEntry);
michael@0 1530 }
michael@0 1531
michael@0 1532 VisualSampleEntry::~VisualSampleEntry()
michael@0 1533 {
michael@0 1534 MOZ_COUNT_DTOR(VisualSampleEntry);
michael@0 1535 }
michael@0 1536
michael@0 1537 }

mercurial