content/media/encoder/fmp4_muxer/ISOMediaBoxes.cpp

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

mercurial