summaryrefslogtreecommitdiffstats
path: root/dom/media/encoder/fmp4_muxer/ISOMediaBoxes.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'dom/media/encoder/fmp4_muxer/ISOMediaBoxes.cpp')
-rw-r--r--dom/media/encoder/fmp4_muxer/ISOMediaBoxes.cpp1550
1 files changed, 1550 insertions, 0 deletions
diff --git a/dom/media/encoder/fmp4_muxer/ISOMediaBoxes.cpp b/dom/media/encoder/fmp4_muxer/ISOMediaBoxes.cpp
new file mode 100644
index 000000000..32a0c577b
--- /dev/null
+++ b/dom/media/encoder/fmp4_muxer/ISOMediaBoxes.cpp
@@ -0,0 +1,1550 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-*/
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include <climits>
+#include "TrackMetadataBase.h"
+#include "ISOMediaBoxes.h"
+#include "ISOControl.h"
+#include "ISOMediaWriter.h"
+#include "EncodedFrameContainer.h"
+#include "ISOTrackMetadata.h"
+#include "MP4ESDS.h"
+#include "AMRBox.h"
+#include "AVCBox.h"
+#include "EVRCBox.h"
+#include "VideoUtils.h"
+
+namespace mozilla {
+
+// 14496-12 6.2.2 'Data Types and fields'
+const uint32_t iso_matrix[] = { 0x00010000, 0, 0,
+ 0, 0x00010000, 0,
+ 0, 0, 0x40000000 };
+
+uint32_t
+set_sample_flags(bool aSync)
+{
+ std::bitset<32> flags;
+ flags.set(16, !aSync);
+ return flags.to_ulong();
+}
+
+Box::BoxSizeChecker::BoxSizeChecker(ISOControl* aControl, uint32_t aSize)
+{
+ mControl = aControl;
+ ori_size = mControl->GetBufPos();
+ box_size = aSize;
+ MOZ_COUNT_CTOR(BoxSizeChecker);
+}
+
+Box::BoxSizeChecker::~BoxSizeChecker()
+{
+ uint32_t cur_size = mControl->GetBufPos();
+ if ((cur_size - ori_size) != box_size) {
+ MOZ_ASSERT(false);
+ }
+
+ MOZ_COUNT_DTOR(BoxSizeChecker);
+}
+
+nsresult
+MediaDataBox::Generate(uint32_t* aBoxSize)
+{
+ mFirstSampleOffset = size;
+ mAllSampleSize = 0;
+
+ if (mTrackType & Audio_Track) {
+ FragmentBuffer* frag = mControl->GetFragment(Audio_Track);
+ mAllSampleSize += frag->GetFirstFragmentSampleSize();
+ }
+ if (mTrackType & Video_Track) {
+ FragmentBuffer* frag = mControl->GetFragment(Video_Track);
+ mAllSampleSize += frag->GetFirstFragmentSampleSize();
+ }
+
+ size += mAllSampleSize;
+ *aBoxSize = size;
+ return NS_OK;
+}
+
+nsresult
+MediaDataBox::Write()
+{
+ nsresult rv;
+ BoxSizeChecker checker(mControl, size);
+ Box::Write();
+ nsTArray<uint32_t> types;
+ types.AppendElement(Audio_Track);
+ types.AppendElement(Video_Track);
+
+ for (uint32_t l = 0; l < types.Length(); l++) {
+ if (mTrackType & types[l]) {
+ FragmentBuffer* frag = mControl->GetFragment(types[l]);
+ nsTArray<RefPtr<EncodedFrame>> frames;
+
+ // Here is the last time we get fragment frames, flush it!
+ rv = frag->GetFirstFragment(frames, true);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ uint32_t len = frames.Length();
+ for (uint32_t i = 0; i < len; i++) {
+ nsTArray<uint8_t> frame_buffer;
+ frames.ElementAt(i)->SwapOutFrameData(frame_buffer);
+ mControl->WriteAVData(frame_buffer);
+ }
+ }
+ }
+
+ return NS_OK;
+}
+
+MediaDataBox::MediaDataBox(uint32_t aTrackType, ISOControl* aControl)
+ : Box(NS_LITERAL_CSTRING("mdat"), aControl)
+ , mAllSampleSize(0)
+ , mFirstSampleOffset(0)
+ , mTrackType(aTrackType)
+{
+ MOZ_COUNT_CTOR(MediaDataBox);
+}
+
+MediaDataBox::~MediaDataBox()
+{
+ MOZ_COUNT_DTOR(MediaDataBox);
+}
+
+uint32_t
+TrackRunBox::fillSampleTable()
+{
+ uint32_t table_size = 0;
+ nsresult rv;
+ nsTArray<RefPtr<EncodedFrame>> frames;
+ FragmentBuffer* frag = mControl->GetFragment(mTrackType);
+
+ rv = frag->GetFirstFragment(frames);
+ if (NS_FAILED(rv)) {
+ return 0;
+ }
+ uint32_t len = frames.Length();
+ sample_info_table = MakeUnique<tbl[]>(len);
+ // Create sample table according to 14496-12 8.8.8.2.
+ for (uint32_t i = 0; i < len; i++) {
+ // Sample size.
+ sample_info_table[i].sample_size = 0;
+ if (flags.to_ulong() & flags_sample_size_present) {
+ sample_info_table[i].sample_size = frames.ElementAt(i)->GetFrameData().Length();
+ mAllSampleSize += sample_info_table[i].sample_size;
+ table_size += sizeof(uint32_t);
+ }
+
+ // Sample flags.
+ sample_info_table[i].sample_flags = 0;
+ if (flags.to_ulong() & flags_sample_flags_present) {
+ sample_info_table[i].sample_flags =
+ set_sample_flags(
+ (frames.ElementAt(i)->GetFrameType() == EncodedFrame::AVC_I_FRAME));
+ table_size += sizeof(uint32_t);
+ }
+
+ // Sample duration.
+ sample_info_table[i].sample_duration = 0;
+ if (flags.to_ulong() & flags_sample_duration_present) {
+ // Calculate each frame's duration, it is decided by "current frame
+ // timestamp - last frame timestamp".
+ uint64_t frame_time = 0;
+ if (i == 0) {
+ frame_time = frames.ElementAt(i)->GetTimeStamp() -
+ frag->GetLastFragmentLastFrameTime();
+ } else {
+ frame_time = frames.ElementAt(i)->GetTimeStamp() -
+ frames.ElementAt(i - 1)->GetTimeStamp();
+ // Keep the last frame time of current fagment, it will be used to calculate
+ // the first frame duration of next fragment.
+ if ((len - 1) == i) {
+ frag->SetLastFragmentLastFrameTime(frames.ElementAt(i)->GetTimeStamp());
+ }
+ }
+
+ // In TrackRunBox, there should be exactly one type, either audio or video.
+ MOZ_ASSERT((mTrackType & Video_Track) ^ (mTrackType & Audio_Track));
+ sample_info_table[i].sample_duration = (mTrackType & Video_Track ?
+ frame_time * mVideoMeta->GetVideoClockRate() / USECS_PER_S :
+ frame_time * mAudioMeta->GetAudioSampleRate() / USECS_PER_S);
+
+ table_size += sizeof(uint32_t);
+ }
+
+ sample_info_table[i].sample_composition_time_offset = 0;
+ }
+ return table_size;
+}
+
+nsresult
+TrackRunBox::Generate(uint32_t* aBoxSize)
+{
+ FragmentBuffer* frag = mControl->GetFragment(mTrackType);
+ sample_count = frag->GetFirstFragmentSampleNumber();
+ size += sizeof(sample_count);
+
+ // data_offset needs to be updated if there is other
+ // TrackRunBox before this one.
+ if (flags.to_ulong() & flags_data_offset_present) {
+ data_offset = 0;
+ size += sizeof(data_offset);
+ }
+ size += fillSampleTable();
+
+ *aBoxSize = size;
+
+ return NS_OK;
+}
+
+nsresult
+TrackRunBox::SetDataOffset(uint32_t aOffset)
+{
+ data_offset = aOffset;
+ return NS_OK;
+}
+
+nsresult
+TrackRunBox::Write()
+{
+ WRITE_FULLBOX(mControl, size)
+ mControl->Write(sample_count);
+ if (flags.to_ulong() & flags_data_offset_present) {
+ mControl->Write(data_offset);
+ }
+ for (uint32_t i = 0; i < sample_count; i++) {
+ if (flags.to_ulong() & flags_sample_duration_present) {
+ mControl->Write(sample_info_table[i].sample_duration);
+ }
+ if (flags.to_ulong() & flags_sample_size_present) {
+ mControl->Write(sample_info_table[i].sample_size);
+ }
+ if (flags.to_ulong() & flags_sample_flags_present) {
+ mControl->Write(sample_info_table[i].sample_flags);
+ }
+ }
+
+ return NS_OK;
+}
+
+TrackRunBox::TrackRunBox(uint32_t aType, uint32_t aFlags, ISOControl* aControl)
+ : FullBox(NS_LITERAL_CSTRING("trun"), 0, aFlags, aControl)
+ , sample_count(0)
+ , data_offset(0)
+ , first_sample_flags(0)
+ , mAllSampleSize(0)
+ , mTrackType(aType)
+{
+ MOZ_COUNT_CTOR(TrackRunBox);
+}
+
+TrackRunBox::~TrackRunBox()
+{
+ MOZ_COUNT_DTOR(TrackRunBox);
+}
+
+nsresult
+TrackFragmentHeaderBox::UpdateBaseDataOffset(uint64_t aOffset)
+{
+ base_data_offset = aOffset;
+ return NS_OK;
+}
+
+nsresult
+TrackFragmentHeaderBox::Generate(uint32_t* aBoxSize)
+{
+ track_ID = (mTrackType == Audio_Track ?
+ mControl->GetTrackID(mAudioMeta->GetKind()) :
+ mControl->GetTrackID(mVideoMeta->GetKind()));
+ size += sizeof(track_ID);
+
+ if (flags.to_ulong() & base_data_offset_present) {
+ // base_data_offset needs to add size of 'trun', 'tfhd' and
+ // header of 'mdat' later.
+ base_data_offset = 0;
+ size += sizeof(base_data_offset);
+ }
+ if (flags.to_ulong() & default_sample_duration_present) {
+ if (mTrackType == Video_Track) {
+ if (!mVideoMeta->GetVideoFrameRate()) {
+ // 0 means frame rate is variant, so it is wrong to write
+ // default_sample_duration.
+ MOZ_ASSERT(0);
+ default_sample_duration = 0;
+ } else {
+ default_sample_duration = mVideoMeta->GetVideoClockRate() / mVideoMeta->GetVideoFrameRate();
+ }
+ } else if (mTrackType == Audio_Track) {
+ default_sample_duration = mAudioMeta->GetAudioFrameDuration();
+ } else {
+ MOZ_ASSERT(0);
+ return NS_ERROR_FAILURE;
+ }
+ size += sizeof(default_sample_duration);
+ }
+ *aBoxSize = size;
+ return NS_OK;
+}
+
+nsresult
+TrackFragmentHeaderBox::Write()
+{
+ WRITE_FULLBOX(mControl, size)
+ mControl->Write(track_ID);
+ if (flags.to_ulong() & base_data_offset_present) {
+ mControl->Write(base_data_offset);
+ }
+ if (flags.to_ulong() & default_sample_duration_present) {
+ mControl->Write(default_sample_duration);
+ }
+ return NS_OK;
+}
+
+TrackFragmentHeaderBox::TrackFragmentHeaderBox(uint32_t aType,
+ uint32_t aFlags,
+ ISOControl* aControl)
+ : FullBox(NS_LITERAL_CSTRING("tfhd"), 0, aFlags, aControl)
+ , track_ID(0)
+ , base_data_offset(0)
+ , default_sample_duration(0)
+{
+ mTrackType = aType;
+ MOZ_COUNT_CTOR(TrackFragmentHeaderBox);
+}
+
+TrackFragmentHeaderBox::~TrackFragmentHeaderBox()
+{
+ MOZ_COUNT_DTOR(TrackFragmentHeaderBox);
+}
+
+TrackFragmentBox::TrackFragmentBox(uint32_t aType, ISOControl* aControl)
+ : DefaultContainerImpl(NS_LITERAL_CSTRING("traf"), aControl)
+ , mTrackType(aType)
+{
+ // Flags in TrackFragmentHeaderBox.
+ uint32_t tf_flags = base_data_offset_present;
+
+ // Ideally, audio encoder generates audio frame in const rate. However, some
+ // audio encoders don't do it so the audio frame duration needs to be checked
+ // here.
+ if ((mTrackType & Audio_Track) && mAudioMeta->GetAudioFrameDuration()) {
+ tf_flags |= default_sample_duration_present;
+ }
+
+ boxes.AppendElement(new TrackFragmentHeaderBox(aType, tf_flags, aControl));
+
+ // Always adds flags_data_offset_present in each TrackRunBox, Android
+ // parser requires this flag to calculate the correct bitstream offset.
+ uint32_t tr_flags = flags_sample_size_present | flags_data_offset_present;
+
+ // Flags in TrackRunBox.
+ // If there is no default sample duration exists, each frame duration needs to
+ // be recored in the TrackRunBox.
+ tr_flags |= (tf_flags & default_sample_duration_present ? 0 : flags_sample_duration_present);
+
+ // For video, add sample_flags to record I frame.
+ tr_flags |= (mTrackType & Video_Track ? flags_sample_flags_present : 0);
+
+ boxes.AppendElement(new TrackRunBox(mTrackType, tr_flags, aControl));
+ MOZ_COUNT_CTOR(TrackFragmentBox);
+}
+
+TrackFragmentBox::~TrackFragmentBox()
+{
+ MOZ_COUNT_DTOR(TrackFragmentBox);
+}
+
+nsresult
+MovieFragmentHeaderBox::Generate(uint32_t* aBoxSize)
+{
+ sequence_number = mControl->GetCurFragmentNumber();
+ size += sizeof(sequence_number);
+ *aBoxSize = size;
+ return NS_OK;
+}
+
+nsresult
+MovieFragmentHeaderBox::Write()
+{
+ WRITE_FULLBOX(mControl, size)
+ mControl->Write(sequence_number);
+ return NS_OK;
+}
+
+MovieFragmentHeaderBox::MovieFragmentHeaderBox(uint32_t aTrackType,
+ ISOControl* aControl)
+ : FullBox(NS_LITERAL_CSTRING("mfhd"), 0, 0, aControl)
+ , sequence_number(0)
+ , mTrackType(aTrackType)
+{
+ MOZ_COUNT_CTOR(MovieFragmentHeaderBox);
+}
+
+MovieFragmentHeaderBox::~MovieFragmentHeaderBox()
+{
+ MOZ_COUNT_DTOR(MovieFragmentHeaderBox);
+}
+
+MovieFragmentBox::MovieFragmentBox(uint32_t aType, ISOControl* aControl)
+ : DefaultContainerImpl(NS_LITERAL_CSTRING("moof"), aControl)
+ , mTrackType(aType)
+{
+ boxes.AppendElement(new MovieFragmentHeaderBox(mTrackType, aControl));
+
+ if (mTrackType & Audio_Track) {
+ boxes.AppendElement(
+ new TrackFragmentBox(Audio_Track, aControl));
+ }
+ if (mTrackType & Video_Track) {
+ boxes.AppendElement(
+ new TrackFragmentBox(Video_Track, aControl));
+ }
+ MOZ_COUNT_CTOR(MovieFragmentBox);
+}
+
+MovieFragmentBox::~MovieFragmentBox()
+{
+ MOZ_COUNT_DTOR(MovieFragmentBox);
+}
+
+nsresult
+MovieFragmentBox::Generate(uint32_t* aBoxSize)
+{
+ nsresult rv = DefaultContainerImpl::Generate(aBoxSize);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ // Correct data_offset if there are both audio and video track in
+ // this fragment. This offset means the offset in the MediaDataBox.
+ if (mTrackType & (Audio_Track | Video_Track)) {
+ nsTArray<RefPtr<MuxerOperation>> truns;
+ rv = Find(NS_LITERAL_CSTRING("trun"), truns);
+ NS_ENSURE_SUCCESS(rv, rv);
+ uint32_t len = truns.Length();
+ uint32_t data_offset = 0;
+ for (uint32_t i = 0; i < len; i++) {
+ TrackRunBox* trun = (TrackRunBox*) truns.ElementAt(i).get();
+ rv = trun->SetDataOffset(data_offset);
+ NS_ENSURE_SUCCESS(rv, rv);
+ data_offset += trun->GetAllSampleSize();
+ }
+ }
+
+ return NS_OK;
+}
+
+nsresult
+TrackExtendsBox::Generate(uint32_t* aBoxSize)
+{
+ track_ID = (mTrackType == Audio_Track ?
+ mControl->GetTrackID(mAudioMeta->GetKind()) :
+ mControl->GetTrackID(mVideoMeta->GetKind()));
+
+ if (mTrackType == Audio_Track) {
+ default_sample_description_index = 1;
+ default_sample_duration = mAudioMeta->GetAudioFrameDuration();
+ default_sample_size = mAudioMeta->GetAudioFrameSize();
+ default_sample_flags = set_sample_flags(1);
+ } else if (mTrackType == Video_Track) {
+ default_sample_description_index = 1;
+ // Video meta data has assigned framerate, it implies that this video's
+ // frame rate should be fixed.
+ if (mVideoMeta->GetVideoFrameRate()) {
+ default_sample_duration =
+ mVideoMeta->GetVideoClockRate() / mVideoMeta->GetVideoFrameRate();
+ }
+ default_sample_size = 0;
+ default_sample_flags = set_sample_flags(0);
+ } else {
+ MOZ_ASSERT(0);
+ return NS_ERROR_FAILURE;
+ }
+
+ size += sizeof(track_ID) +
+ sizeof(default_sample_description_index) +
+ sizeof(default_sample_duration) +
+ sizeof(default_sample_size) +
+ sizeof(default_sample_flags);
+
+ *aBoxSize = size;
+
+ return NS_OK;
+}
+
+nsresult
+TrackExtendsBox::Write()
+{
+ WRITE_FULLBOX(mControl, size)
+ mControl->Write(track_ID);
+ mControl->Write(default_sample_description_index);
+ mControl->Write(default_sample_duration);
+ mControl->Write(default_sample_size);
+ mControl->Write(default_sample_flags);
+
+ return NS_OK;
+}
+
+TrackExtendsBox::TrackExtendsBox(uint32_t aType, ISOControl* aControl)
+ : FullBox(NS_LITERAL_CSTRING("trex"), 0, 0, aControl)
+ , track_ID(0)
+ , default_sample_description_index(0)
+ , default_sample_duration(0)
+ , default_sample_size(0)
+ , default_sample_flags(0)
+ , mTrackType(aType)
+{
+ MOZ_COUNT_CTOR(TrackExtendsBox);
+}
+
+TrackExtendsBox::~TrackExtendsBox()
+{
+ MOZ_COUNT_DTOR(TrackExtendsBox);
+}
+
+MovieExtendsBox::MovieExtendsBox(ISOControl* aControl)
+ : DefaultContainerImpl(NS_LITERAL_CSTRING("mvex"), aControl)
+{
+ if (mAudioMeta) {
+ boxes.AppendElement(new TrackExtendsBox(Audio_Track, aControl));
+ }
+ if (mVideoMeta) {
+ boxes.AppendElement(new TrackExtendsBox(Video_Track, aControl));
+ }
+ MOZ_COUNT_CTOR(MovieExtendsBox);
+}
+
+MovieExtendsBox::~MovieExtendsBox()
+{
+ MOZ_COUNT_DTOR(MovieExtendsBox);
+}
+
+nsresult
+ChunkOffsetBox::Generate(uint32_t* aBoxSize)
+{
+ // We don't need time to sample table in fragmented mp4.
+ entry_count = 0;
+ size += sizeof(entry_count);
+ *aBoxSize = size;
+ return NS_OK;
+}
+
+nsresult
+ChunkOffsetBox::Write()
+{
+ WRITE_FULLBOX(mControl, size)
+ mControl->Write(entry_count);
+ return NS_OK;
+}
+
+ChunkOffsetBox::ChunkOffsetBox(uint32_t aType, ISOControl* aControl)
+ : FullBox(NS_LITERAL_CSTRING("stco"), 0, 0, aControl)
+ , entry_count(0)
+{
+ MOZ_COUNT_CTOR(ChunkOffsetBox);
+}
+
+ChunkOffsetBox::~ChunkOffsetBox()
+{
+ MOZ_COUNT_DTOR(ChunkOffsetBox);
+}
+
+nsresult
+SampleToChunkBox::Generate(uint32_t* aBoxSize)
+{
+ // We don't need time to sample table in fragmented mp4
+ entry_count = 0;
+ size += sizeof(entry_count);
+ *aBoxSize = size;
+ return NS_OK;
+}
+
+nsresult
+SampleToChunkBox::Write()
+{
+ WRITE_FULLBOX(mControl, size)
+ mControl->Write(entry_count);
+ return NS_OK;
+}
+
+SampleToChunkBox::SampleToChunkBox(uint32_t aType, ISOControl* aControl)
+ : FullBox(NS_LITERAL_CSTRING("stsc"), 0, 0, aControl)
+ , entry_count(0)
+{
+ MOZ_COUNT_CTOR(SampleToChunkBox);
+}
+
+SampleToChunkBox::~SampleToChunkBox()
+{
+ MOZ_COUNT_DTOR(SampleToChunkBox);
+}
+
+nsresult
+TimeToSampleBox::Generate(uint32_t* aBoxSize)
+{
+ // We don't need time to sample table in fragmented mp4.
+ entry_count = 0;
+ size += sizeof(entry_count);
+ *aBoxSize = size;
+ return NS_OK;
+}
+
+nsresult
+TimeToSampleBox::Write()
+{
+ WRITE_FULLBOX(mControl, size)
+ mControl->Write(entry_count);
+ return NS_OK;
+}
+
+TimeToSampleBox::TimeToSampleBox(uint32_t aType, ISOControl* aControl)
+ : FullBox(NS_LITERAL_CSTRING("stts"), 0, 0, aControl)
+ , entry_count(0)
+{
+ MOZ_COUNT_CTOR(TimeToSampleBox);
+}
+
+TimeToSampleBox::~TimeToSampleBox()
+{
+ MOZ_COUNT_DTOR(TimeToSampleBox);
+}
+
+nsresult
+SampleDescriptionBox::Generate(uint32_t* aBoxSize)
+{
+ entry_count = 1;
+ size += sizeof(entry_count);
+
+ nsresult rv;
+ uint32_t box_size;
+ rv = sample_entry_box->Generate(&box_size);
+ NS_ENSURE_SUCCESS(rv, rv);
+ size += box_size;
+ *aBoxSize = size;
+
+ return NS_OK;
+}
+
+nsresult
+SampleDescriptionBox::Write()
+{
+ WRITE_FULLBOX(mControl, size)
+ nsresult rv;
+ mControl->Write(entry_count);
+ rv = sample_entry_box->Write();
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ return NS_OK;
+}
+
+SampleDescriptionBox::SampleDescriptionBox(uint32_t aType, ISOControl* aControl)
+ : FullBox(NS_LITERAL_CSTRING("stsd"), 0, 0, aControl)
+ , entry_count(0)
+{
+ mTrackType = aType;
+
+ switch (mTrackType) {
+ case Audio_Track:
+ {
+ CreateAudioSampleEntry(sample_entry_box);
+ }
+ break;
+ case Video_Track:
+ {
+ CreateVideoSampleEntry(sample_entry_box);
+ }
+ break;
+ }
+ MOZ_ASSERT(sample_entry_box);
+ MOZ_COUNT_CTOR(SampleDescriptionBox);
+}
+
+nsresult
+SampleDescriptionBox::CreateAudioSampleEntry(RefPtr<SampleEntryBox>& aSampleEntry)
+{
+ if (mAudioMeta->GetKind() == TrackMetadataBase::METADATA_AMR) {
+ aSampleEntry = new AMRSampleEntry(mControl);
+ } else if (mAudioMeta->GetKind() == TrackMetadataBase::METADATA_AAC) {
+ aSampleEntry = new MP4AudioSampleEntry(mControl);
+ } else if (mAudioMeta->GetKind() == TrackMetadataBase::METADATA_EVRC) {
+ aSampleEntry = new EVRCSampleEntry(mControl);
+ } else {
+ MOZ_ASSERT(0);
+ }
+ return NS_OK;
+}
+
+nsresult
+SampleDescriptionBox::CreateVideoSampleEntry(RefPtr<SampleEntryBox>& aSampleEntry)
+{
+ if (mVideoMeta->GetKind() == TrackMetadataBase::METADATA_AVC) {
+ aSampleEntry = new AVCSampleEntry(mControl);
+ } else {
+ MOZ_ASSERT(0);
+ }
+ return NS_OK;
+}
+
+SampleDescriptionBox::~SampleDescriptionBox()
+{
+ MOZ_COUNT_DTOR(SampleDescriptionBox);
+}
+
+nsresult
+SampleSizeBox::Generate(uint32_t* aBoxSize)
+{
+ size += sizeof(sample_size) +
+ sizeof(sample_count);
+ *aBoxSize = size;
+ return NS_OK;
+}
+
+nsresult
+SampleSizeBox::Write()
+{
+ WRITE_FULLBOX(mControl, size)
+ mControl->Write(sample_size);
+ mControl->Write(sample_count);
+ return NS_OK;
+}
+
+SampleSizeBox::SampleSizeBox(ISOControl* aControl)
+ : FullBox(NS_LITERAL_CSTRING("stsz"), 0, 0, aControl)
+ , sample_size(0)
+ , sample_count(0)
+{
+ MOZ_COUNT_CTOR(SampleSizeBox);
+}
+
+SampleSizeBox::~SampleSizeBox()
+{
+ MOZ_COUNT_DTOR(SampleSizeBox);
+}
+
+SampleTableBox::SampleTableBox(uint32_t aType, ISOControl* aControl)
+ : DefaultContainerImpl(NS_LITERAL_CSTRING("stbl"), aControl)
+{
+ boxes.AppendElement(new SampleDescriptionBox(aType, aControl));
+ boxes.AppendElement(new TimeToSampleBox(aType, aControl));
+ boxes.AppendElement(new SampleToChunkBox(aType, aControl));
+ boxes.AppendElement(new SampleSizeBox(aControl));
+ boxes.AppendElement(new ChunkOffsetBox(aType, aControl));
+ MOZ_COUNT_CTOR(SampleTableBox);
+}
+
+SampleTableBox::~SampleTableBox()
+{
+ MOZ_COUNT_DTOR(SampleTableBox);
+}
+
+nsresult
+DataEntryUrlBox::Generate(uint32_t* aBoxSize)
+{
+ // location is null here, do nothing
+ size += location.Length();
+ *aBoxSize = size;
+
+ return NS_OK;
+}
+
+nsresult
+DataEntryUrlBox::Write()
+{
+ WRITE_FULLBOX(mControl, size)
+ return NS_OK;
+}
+
+DataEntryUrlBox::DataEntryUrlBox()
+ : FullBox(NS_LITERAL_CSTRING("url "), 0, 0, (ISOControl*) nullptr)
+{
+ MOZ_COUNT_CTOR(DataEntryUrlBox);
+}
+
+DataEntryUrlBox::DataEntryUrlBox(ISOControl* aControl)
+ : FullBox(NS_LITERAL_CSTRING("url "), 0, flags_media_at_the_same_file, aControl)
+{
+ MOZ_COUNT_CTOR(DataEntryUrlBox);
+}
+
+DataEntryUrlBox::DataEntryUrlBox(const DataEntryUrlBox& aBox)
+ : FullBox(aBox.boxType, aBox.version, aBox.flags.to_ulong(), aBox.mControl)
+{
+ location = aBox.location;
+ MOZ_COUNT_CTOR(DataEntryUrlBox);
+}
+
+DataEntryUrlBox::~DataEntryUrlBox()
+{
+ MOZ_COUNT_DTOR(DataEntryUrlBox);
+}
+
+nsresult DataReferenceBox::Generate(uint32_t* aBoxSize)
+{
+ entry_count = 1; // only allow on entry here
+ size += sizeof(uint32_t);
+
+ for (uint32_t i = 0; i < entry_count; i++) {
+ uint32_t box_size = 0;
+ DataEntryUrlBox* url = new DataEntryUrlBox(mControl);
+ url->Generate(&box_size);
+ size += box_size;
+ urls.AppendElement(url);
+ }
+
+ *aBoxSize = size;
+
+ return NS_OK;
+}
+
+nsresult DataReferenceBox::Write()
+{
+ WRITE_FULLBOX(mControl, size)
+ mControl->Write(entry_count);
+
+ for (uint32_t i = 0; i < entry_count; i++) {
+ urls[i]->Write();
+ }
+
+ return NS_OK;
+}
+
+DataReferenceBox::DataReferenceBox(ISOControl* aControl)
+ : FullBox(NS_LITERAL_CSTRING("dref"), 0, 0, aControl)
+ , entry_count(0)
+{
+ MOZ_COUNT_CTOR(DataReferenceBox);
+}
+
+DataReferenceBox::~DataReferenceBox()
+{
+ MOZ_COUNT_DTOR(DataReferenceBox);
+}
+
+DataInformationBox::DataInformationBox(ISOControl* aControl)
+ : DefaultContainerImpl(NS_LITERAL_CSTRING("dinf"), aControl)
+{
+ boxes.AppendElement(new DataReferenceBox(aControl));
+ MOZ_COUNT_CTOR(DataInformationBox);
+}
+
+DataInformationBox::~DataInformationBox()
+{
+ MOZ_COUNT_DTOR(DataInformationBox);
+}
+
+nsresult
+VideoMediaHeaderBox::Generate(uint32_t* aBoxSize)
+{
+ size += sizeof(graphicsmode) +
+ sizeof(opcolor);
+
+ *aBoxSize = size;
+
+ return NS_OK;
+}
+
+nsresult
+VideoMediaHeaderBox::Write()
+{
+ WRITE_FULLBOX(mControl, size)
+ mControl->Write(graphicsmode);
+ mControl->WriteArray(opcolor, 3);
+ return NS_OK;
+}
+
+VideoMediaHeaderBox::VideoMediaHeaderBox(ISOControl* aControl)
+ : FullBox(NS_LITERAL_CSTRING("vmhd"), 0, 1, aControl)
+ , graphicsmode(0)
+{
+ memset(opcolor, 0 , sizeof(opcolor));
+ MOZ_COUNT_CTOR(VideoMediaHeaderBox);
+}
+
+VideoMediaHeaderBox::~VideoMediaHeaderBox()
+{
+ MOZ_COUNT_DTOR(VideoMediaHeaderBox);
+}
+
+nsresult
+SoundMediaHeaderBox::Generate(uint32_t* aBoxSize)
+{
+ balance = 0;
+ reserved = 0;
+ size += sizeof(balance) +
+ sizeof(reserved);
+
+ *aBoxSize = size;
+
+ return NS_OK;
+}
+
+nsresult
+SoundMediaHeaderBox::Write()
+{
+ WRITE_FULLBOX(mControl, size)
+ mControl->Write(balance);
+ mControl->Write(reserved);
+
+ return NS_OK;
+}
+
+SoundMediaHeaderBox::SoundMediaHeaderBox(ISOControl* aControl)
+ : FullBox(NS_LITERAL_CSTRING("smhd"), 0, 0, aControl)
+{
+ MOZ_COUNT_CTOR(SoundMediaHeaderBox);
+}
+
+SoundMediaHeaderBox::~SoundMediaHeaderBox()
+{
+ MOZ_COUNT_DTOR(SoundMediaHeaderBox);
+}
+
+MediaInformationBox::MediaInformationBox(uint32_t aType, ISOControl* aControl)
+ : DefaultContainerImpl(NS_LITERAL_CSTRING("minf"), aControl)
+{
+ mTrackType = aType;
+
+ if (mTrackType == Audio_Track) {
+ boxes.AppendElement(new SoundMediaHeaderBox(aControl));
+ } else if (mTrackType == Video_Track) {
+ boxes.AppendElement(new VideoMediaHeaderBox(aControl));
+ } else {
+ MOZ_ASSERT(0);
+ }
+
+ boxes.AppendElement(new DataInformationBox(aControl));
+ boxes.AppendElement(new SampleTableBox(aType, aControl));
+ MOZ_COUNT_CTOR(MediaInformationBox);
+}
+
+MediaInformationBox::~MediaInformationBox()
+{
+ MOZ_COUNT_DTOR(MediaInformationBox);
+}
+
+nsresult
+HandlerBox::Generate(uint32_t* aBoxSize)
+{
+ pre_defined = 0;
+ if (mTrackType == Audio_Track) {
+ handler_type = FOURCC('s', 'o', 'u', 'n');
+ } else if (mTrackType == Video_Track) {
+ handler_type = FOURCC('v', 'i', 'd', 'e');
+ }
+
+ size += sizeof(pre_defined) +
+ sizeof(handler_type) +
+ sizeof(reserved);
+
+ *aBoxSize = size;
+
+ return NS_OK;
+}
+
+nsresult
+HandlerBox::Write()
+{
+ WRITE_FULLBOX(mControl, size)
+ mControl->Write(pre_defined);
+ mControl->Write(handler_type);
+ mControl->WriteArray(reserved, 3);
+
+ return NS_OK;
+}
+
+HandlerBox::HandlerBox(uint32_t aType, ISOControl* aControl)
+ : FullBox(NS_LITERAL_CSTRING("hdlr"), 0, 0, aControl)
+ , pre_defined(0)
+ , handler_type(0)
+{
+ mTrackType = aType;
+ memset(reserved, 0 , sizeof(reserved));
+ MOZ_COUNT_CTOR(HandlerBox);
+}
+
+HandlerBox::~HandlerBox()
+{
+ MOZ_COUNT_DTOR(HandlerBox);
+}
+
+MediaHeaderBox::MediaHeaderBox(uint32_t aType, ISOControl* aControl)
+ : FullBox(NS_LITERAL_CSTRING("mdhd"), 0, 0, aControl)
+ , creation_time(0)
+ , modification_time(0)
+ , timescale(0)
+ , duration(0)
+ , pad(0)
+ , lang1(0)
+ , lang2(0)
+ , lang3(0)
+ , pre_defined(0)
+{
+ mTrackType = aType;
+ MOZ_COUNT_CTOR(MediaHeaderBox);
+}
+
+MediaHeaderBox::~MediaHeaderBox()
+{
+ MOZ_COUNT_DTOR(MediaHeaderBox);
+}
+
+uint32_t
+MediaHeaderBox::GetTimeScale()
+{
+ if (mTrackType == Audio_Track) {
+ return mAudioMeta->GetAudioSampleRate();
+ }
+
+ return mVideoMeta->GetVideoClockRate();
+}
+
+nsresult
+MediaHeaderBox::Generate(uint32_t* aBoxSize)
+{
+ creation_time = mControl->GetTime();
+ modification_time = mControl->GetTime();
+ timescale = GetTimeScale();
+ duration = 0; // fragmented mp4
+
+ pad = 0;
+ lang1 = 'u' - 0x60; // "und" underdetermined language
+ lang2 = 'n' - 0x60;
+ lang3 = 'd' - 0x60;
+ size += (pad.size() + lang1.size() + lang2.size() + lang3.size()) / CHAR_BIT;
+
+ pre_defined = 0;
+ size += sizeof(creation_time) +
+ sizeof(modification_time) +
+ sizeof(timescale) +
+ sizeof(duration) +
+ sizeof(pre_defined);
+
+ *aBoxSize = size;
+
+ return NS_OK;
+}
+
+nsresult
+MediaHeaderBox::Write()
+{
+ WRITE_FULLBOX(mControl, size)
+ mControl->Write(creation_time);
+ mControl->Write(modification_time);
+ mControl->Write(timescale);
+ mControl->Write(duration);
+ mControl->WriteBits(pad.to_ulong(), pad.size());
+ mControl->WriteBits(lang1.to_ulong(), lang1.size());
+ mControl->WriteBits(lang2.to_ulong(), lang2.size());
+ mControl->WriteBits(lang3.to_ulong(), lang3.size());
+ mControl->Write(pre_defined);
+
+ return NS_OK;
+}
+
+MovieBox::MovieBox(ISOControl* aControl)
+ : DefaultContainerImpl(NS_LITERAL_CSTRING("moov"), aControl)
+{
+ boxes.AppendElement(new MovieHeaderBox(aControl));
+ if (aControl->HasAudioTrack()) {
+ boxes.AppendElement(new TrackBox(Audio_Track, aControl));
+ }
+ if (aControl->HasVideoTrack()) {
+ boxes.AppendElement(new TrackBox(Video_Track, aControl));
+ }
+ boxes.AppendElement(new MovieExtendsBox(aControl));
+ MOZ_COUNT_CTOR(MovieBox);
+}
+
+MovieBox::~MovieBox()
+{
+ MOZ_COUNT_DTOR(MovieBox);
+}
+
+nsresult
+MovieHeaderBox::Generate(uint32_t* aBoxSize)
+{
+ creation_time = mControl->GetTime();
+ modification_time = mControl->GetTime();
+ timescale = GetTimeScale();
+ duration = 0; // The duration is always 0 in fragmented mp4.
+ next_track_ID = mControl->GetNextTrackID();
+
+ size += sizeof(next_track_ID) +
+ sizeof(creation_time) +
+ sizeof(modification_time) +
+ sizeof(timescale) +
+ sizeof(duration) +
+ sizeof(rate) +
+ sizeof(volume) +
+ sizeof(reserved16) +
+ sizeof(reserved32) +
+ sizeof(matrix) +
+ sizeof(pre_defined);
+
+ *aBoxSize = size;
+
+ return NS_OK;
+}
+
+nsresult
+MovieHeaderBox::Write()
+{
+ WRITE_FULLBOX(mControl, size)
+ mControl->Write(creation_time);
+ mControl->Write(modification_time);
+ mControl->Write(timescale);
+ mControl->Write(duration);
+ mControl->Write(rate);
+ mControl->Write(volume);
+ mControl->Write(reserved16);
+ mControl->WriteArray(reserved32, 2);
+ mControl->WriteArray(matrix, 9);
+ mControl->WriteArray(pre_defined, 6);
+ mControl->Write(next_track_ID);
+
+ return NS_OK;
+}
+
+uint32_t
+MovieHeaderBox::GetTimeScale()
+{
+ // Only audio track in container.
+ if (mAudioMeta && !mVideoMeta) {
+ return mAudioMeta->GetAudioSampleRate();
+ }
+
+ // return video rate
+ return mVideoMeta->GetVideoClockRate();
+}
+
+MovieHeaderBox::~MovieHeaderBox()
+{
+ MOZ_COUNT_DTOR(MovieHeaderBox);
+}
+
+MovieHeaderBox::MovieHeaderBox(ISOControl* aControl)
+ : FullBox(NS_LITERAL_CSTRING("mvhd"), 0, 0, aControl)
+ , creation_time(0)
+ , modification_time(0)
+ , timescale(90000)
+ , duration(0)
+ , rate(0x00010000)
+ , volume(0x0100)
+ , reserved16(0)
+ , next_track_ID(1)
+{
+ memcpy(matrix, iso_matrix, sizeof(matrix));
+ memset(reserved32, 0, sizeof(reserved32));
+ memset(pre_defined, 0, sizeof(pre_defined));
+ MOZ_COUNT_CTOR(MovieHeaderBox);
+}
+
+TrackHeaderBox::TrackHeaderBox(uint32_t aType, ISOControl* aControl)
+ : FullBox(NS_LITERAL_CSTRING("tkhd"), 0,
+ flags_track_enabled | flags_track_in_movie | flags_track_in_preview,
+ aControl)
+ , creation_time(0)
+ , modification_time(0)
+ , track_ID(0)
+ , reserved(0)
+ , duration(0)
+ , layer(0)
+ , alternate_group(0)
+ , volume(0)
+ , reserved3(0)
+ , width(0)
+ , height(0)
+{
+ mTrackType = aType;
+ memcpy(matrix, iso_matrix, sizeof(matrix));
+ memset(reserved2, 0, sizeof(reserved2));
+ MOZ_COUNT_CTOR(TrackHeaderBox);
+}
+
+TrackHeaderBox::~TrackHeaderBox()
+{
+ MOZ_COUNT_DTOR(TrackHeaderBox);
+}
+
+nsresult
+TrackHeaderBox::Generate(uint32_t* aBoxSize)
+{
+ creation_time = mControl->GetTime();
+ modification_time = mControl->GetTime();
+ track_ID = (mTrackType == Audio_Track ?
+ mControl->GetTrackID(mAudioMeta->GetKind()) :
+ mControl->GetTrackID(mVideoMeta->GetKind()));
+ // fragmented mp4
+ duration = 0;
+
+ // volume, audiotrack is always 0x0100 in 14496-12 8.3.2.2
+ volume = (mTrackType == Audio_Track ? 0x0100 : 0);
+
+ if (mTrackType == Video_Track) {
+ width = mVideoMeta->GetVideoDisplayWidth() << 16;
+ height = mVideoMeta->GetVideoDisplayHeight() << 16;
+ // Check display size, using the pixel size if any of them is invalid.
+ if (!width || !height) {
+ width = mVideoMeta->GetVideoWidth() << 16;
+ height = mVideoMeta->GetVideoHeight() << 16;
+ }
+ }
+
+ size += sizeof(creation_time) +
+ sizeof(modification_time) +
+ sizeof(track_ID) +
+ sizeof(reserved) +
+ sizeof(duration) +
+ sizeof(reserved2) +
+ sizeof(layer) +
+ sizeof(alternate_group) +
+ sizeof(volume) +
+ sizeof(reserved3) +
+ sizeof(matrix) +
+ sizeof(width) +
+ sizeof(height);
+
+ *aBoxSize = size;
+
+ return NS_OK;
+}
+
+nsresult
+TrackHeaderBox::Write()
+{
+ WRITE_FULLBOX(mControl, size)
+ mControl->Write(creation_time);
+ mControl->Write(modification_time);
+ mControl->Write(track_ID);
+ mControl->Write(reserved);
+ mControl->Write(duration);
+ mControl->WriteArray(reserved2, 2);
+ mControl->Write(layer);
+ mControl->Write(alternate_group);
+ mControl->Write(volume);
+ mControl->Write(reserved3);
+ mControl->WriteArray(matrix, 9);
+ mControl->Write(width);
+ mControl->Write(height);
+
+ return NS_OK;
+}
+
+nsresult
+FileTypeBox::Generate(uint32_t* aBoxSize)
+{
+ minor_version = 0;
+
+ if (mControl->GetMuxingType() == ISOMediaWriter::TYPE_FRAG_MP4) {
+ if (!mControl->HasVideoTrack() && mControl->HasAudioTrack()) {
+ major_brand = "M4A ";
+ } else {
+ major_brand = "MP42";
+ }
+ compatible_brands.AppendElement("mp42");
+ compatible_brands.AppendElement("isom");
+ } else if (mControl->GetMuxingType() == ISOMediaWriter::TYPE_FRAG_3GP) {
+ major_brand = "3gp9";
+ // According to 3GPP TS 26.244 V12.2.0, section 5.3.4, it's recommended to
+ // list all compatible brands here. 3GP spec supports fragment from '3gp6'.
+ compatible_brands.AppendElement("3gp9");
+ compatible_brands.AppendElement("3gp8");
+ compatible_brands.AppendElement("3gp7");
+ compatible_brands.AppendElement("3gp6");
+ compatible_brands.AppendElement("isom");
+ } else if (mControl->GetMuxingType() == ISOMediaWriter::TYPE_FRAG_3G2) {
+ major_brand = "3g2a";
+ // 3GPP2 Release 0 and A and 3GPP Release 6 allow movie fragmentation
+ compatible_brands.AppendElement("3gp9");
+ compatible_brands.AppendElement("3gp8");
+ compatible_brands.AppendElement("3gp7");
+ compatible_brands.AppendElement("3gp6");
+ compatible_brands.AppendElement("isom");
+ compatible_brands.AppendElement("3g2c");
+ compatible_brands.AppendElement("3g2b");
+ compatible_brands.AppendElement("3g2a");
+ } else {
+ MOZ_ASSERT(0);
+ }
+
+ size += major_brand.Length() +
+ sizeof(minor_version) +
+ compatible_brands.Length() * 4;
+
+ *aBoxSize = size;
+
+ return NS_OK;
+}
+
+nsresult
+FileTypeBox::Write()
+{
+ BoxSizeChecker checker(mControl, size);
+ Box::Write();
+ mControl->WriteFourCC(major_brand.get());
+ mControl->Write(minor_version);
+ uint32_t len = compatible_brands.Length();
+ for (uint32_t i = 0; i < len; i++) {
+ mControl->WriteFourCC(compatible_brands[i].get());
+ }
+
+ return NS_OK;
+}
+
+FileTypeBox::FileTypeBox(ISOControl* aControl)
+ : Box(NS_LITERAL_CSTRING("ftyp"), aControl)
+ , minor_version(0)
+{
+ MOZ_COUNT_CTOR(FileTypeBox);
+}
+
+FileTypeBox::~FileTypeBox()
+{
+ MOZ_COUNT_DTOR(FileTypeBox);
+}
+
+MediaBox::MediaBox(uint32_t aType, ISOControl* aControl)
+ : DefaultContainerImpl(NS_LITERAL_CSTRING("mdia"), aControl)
+{
+ mTrackType = aType;
+ boxes.AppendElement(new MediaHeaderBox(aType, aControl));
+ boxes.AppendElement(new HandlerBox(aType, aControl));
+ boxes.AppendElement(new MediaInformationBox(aType, aControl));
+ MOZ_COUNT_CTOR(MediaBox);
+}
+
+MediaBox::~MediaBox()
+{
+ MOZ_COUNT_DTOR(MediaBox);
+}
+
+nsresult
+DefaultContainerImpl::Generate(uint32_t* aBoxSize)
+{
+ nsresult rv;
+ uint32_t box_size;
+ uint32_t len = boxes.Length();
+ for (uint32_t i = 0; i < len; i++) {
+ rv = boxes.ElementAt(i)->Generate(&box_size);
+ NS_ENSURE_SUCCESS(rv, rv);
+ size += box_size;
+ }
+ *aBoxSize = size;
+ return NS_OK;
+}
+
+nsresult
+DefaultContainerImpl::Find(const nsACString& aType,
+ nsTArray<RefPtr<MuxerOperation>>& aOperations)
+{
+ nsresult rv = Box::Find(aType, aOperations);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ uint32_t len = boxes.Length();
+ for (uint32_t i = 0; i < len; i++) {
+ rv = boxes.ElementAt(i)->Find(aType, aOperations);
+ NS_ENSURE_SUCCESS(rv, rv);
+ }
+ return NS_OK;
+}
+
+nsresult
+DefaultContainerImpl::Write()
+{
+ BoxSizeChecker checker(mControl, size);
+ Box::Write();
+
+ nsresult rv;
+ uint32_t len = boxes.Length();
+ for (uint32_t i = 0; i < len; i++) {
+ rv = boxes.ElementAt(i)->Write();
+ NS_ENSURE_SUCCESS(rv, rv);
+ }
+
+ return NS_OK;
+}
+
+DefaultContainerImpl::DefaultContainerImpl(const nsACString& aType,
+ ISOControl* aControl)
+ : Box(aType, aControl)
+{
+}
+
+nsresult
+Box::Write()
+{
+ mControl->Write(size);
+ mControl->WriteFourCC(boxType.get());
+ return NS_OK;
+}
+
+nsresult
+Box::Find(const nsACString& aType, nsTArray<RefPtr<MuxerOperation>>& aOperations)
+{
+ if (boxType == aType) {
+ aOperations.AppendElement(this);
+ }
+ return NS_OK;
+}
+
+Box::Box(const nsACString& aType, ISOControl* aControl)
+ : size(8), mControl(aControl)
+{
+ MOZ_ASSERT(aType.Length() == 4);
+ boxType = aType;
+ aControl->GetAudioMetadata(mAudioMeta);
+ aControl->GetVideoMetadata(mVideoMeta);
+}
+
+FullBox::FullBox(const nsACString& aType, uint8_t aVersion, uint32_t aFlags,
+ ISOControl* aControl)
+ : Box(aType, aControl)
+{
+ std::bitset<24> tmp_flags(aFlags);
+ version = aVersion;
+ flags = tmp_flags;
+ size += sizeof(version) + flags.size() / CHAR_BIT;
+}
+
+nsresult
+FullBox::Write()
+{
+ Box::Write();
+ mControl->Write(version);
+ mControl->WriteBits(flags.to_ulong(), flags.size());
+ return NS_OK;
+}
+
+TrackBox::TrackBox(uint32_t aTrackType, ISOControl* aControl)
+ : DefaultContainerImpl(NS_LITERAL_CSTRING("trak"), aControl)
+{
+ boxes.AppendElement(new TrackHeaderBox(aTrackType, aControl));
+ boxes.AppendElement(new MediaBox(aTrackType, aControl));
+ MOZ_COUNT_CTOR(TrackBox);
+}
+
+TrackBox::~TrackBox()
+{
+ MOZ_COUNT_DTOR(TrackBox);
+}
+
+SampleEntryBox::SampleEntryBox(const nsACString& aFormat, ISOControl* aControl)
+ : Box(aFormat, aControl)
+ , data_reference_index(0)
+{
+ data_reference_index = 1; // There is only one data reference in each track.
+ size += sizeof(reserved) +
+ sizeof(data_reference_index);
+ memset(reserved, 0, sizeof(reserved));
+}
+
+nsresult
+SampleEntryBox::Write()
+{
+ Box::Write();
+ mControl->Write(reserved, sizeof(reserved));
+ mControl->Write(data_reference_index);
+ return NS_OK;
+}
+
+nsresult
+AudioSampleEntry::Write()
+{
+ SampleEntryBox::Write();
+ mControl->Write(sound_version);
+ mControl->Write(reserved2, sizeof(reserved2));
+ mControl->Write(channels);
+ mControl->Write(sample_size);
+ mControl->Write(compressionId);
+ mControl->Write(packet_size);
+ mControl->Write(timeScale);
+ return NS_OK;
+}
+
+AudioSampleEntry::AudioSampleEntry(const nsACString& aFormat, ISOControl* aControl)
+ : SampleEntryBox(aFormat, aControl)
+ , sound_version(0)
+ , channels(2)
+ , sample_size(16)
+ , compressionId(0)
+ , packet_size(0)
+ , timeScale(0)
+{
+ memset(reserved2, 0 , sizeof(reserved2));
+ channels = mAudioMeta->GetAudioChannels();
+ timeScale = mAudioMeta->GetAudioSampleRate() << 16;
+
+ size += sizeof(sound_version) +
+ sizeof(reserved2) +
+ sizeof(sample_size) +
+ sizeof(channels) +
+ sizeof(packet_size) +
+ sizeof(compressionId) +
+ sizeof(timeScale);
+
+ MOZ_COUNT_CTOR(AudioSampleEntry);
+}
+
+AudioSampleEntry::~AudioSampleEntry()
+{
+ MOZ_COUNT_DTOR(AudioSampleEntry);
+}
+
+nsresult
+VisualSampleEntry::Write()
+{
+ SampleEntryBox::Write();
+
+ mControl->Write(reserved, sizeof(reserved));
+ mControl->Write(width);
+ mControl->Write(height);
+ mControl->Write(horizresolution);
+ mControl->Write(vertresolution);
+ mControl->Write(reserved2);
+ mControl->Write(frame_count);
+ mControl->Write(compressorName, sizeof(compressorName));
+ mControl->Write(depth);
+ mControl->Write(pre_defined);
+
+ return NS_OK;
+}
+
+VisualSampleEntry::VisualSampleEntry(const nsACString& aFormat, ISOControl* aControl)
+ : SampleEntryBox(aFormat, aControl)
+ , width(0)
+ , height(0)
+ , horizresolution(resolution_72_dpi)
+ , vertresolution(resolution_72_dpi)
+ , reserved2(0)
+ , frame_count(1)
+ , depth(video_depth)
+ , pre_defined(-1)
+{
+ memset(reserved, 0 , sizeof(reserved));
+ memset(compressorName, 0 , sizeof(compressorName));
+
+ // both fields occupy 16 bits defined in 14496-2 6.2.3.
+ width = mVideoMeta->GetVideoWidth();
+ height = mVideoMeta->GetVideoHeight();
+
+ size += sizeof(reserved) +
+ sizeof(width) +
+ sizeof(height) +
+ sizeof(horizresolution) +
+ sizeof(vertresolution) +
+ sizeof(reserved2) +
+ sizeof(frame_count) +
+ sizeof(compressorName) +
+ sizeof(depth) +
+ sizeof(pre_defined);
+
+ MOZ_COUNT_CTOR(VisualSampleEntry);
+}
+
+VisualSampleEntry::~VisualSampleEntry()
+{
+ MOZ_COUNT_DTOR(VisualSampleEntry);
+}
+
+}