content/media/encoder/fmp4_muxer/ISOControl.cpp

Fri, 16 Jan 2015 04:50:19 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Fri, 16 Jan 2015 04:50:19 +0100
branch
TOR_BUG_9701
changeset 13
44a2da4a2ab2
permissions
-rw-r--r--

Replace accessor implementation with direct member state manipulation, by
request https://trac.torproject.org/projects/tor/ticket/9701#comment:32

     1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-*/
     2 /* This Source Code Form is subject to the terms of the Mozilla Public
     3  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
     4  * You can obtain one at http://mozilla.org/MPL/2.0/. */
     6 #include <time.h>
     7 #include "nsAutoPtr.h"
     8 #include "ISOControl.h"
     9 #include "ISOMediaBoxes.h"
    10 #include "EncodedFrameContainer.h"
    12 namespace mozilla {
    14 // For MP4 creation_time and modification_time offset from January 1, 1904 to
    15 // January 1, 1970.
    16 #define iso_time_offset 2082844800
    18 FragmentBuffer::FragmentBuffer(uint32_t aTrackType, uint32_t aFragDuration)
    19   : mTrackType(aTrackType)
    20   , mFragDuration(aFragDuration)
    21   , mMediaStartTime(0)
    22   , mFragmentNumber(0)
    23   , mLastFrameTimeOfLastFragment(0)
    24   , mEOS(false)
    25 {
    26   mFragArray.AppendElement();
    27   MOZ_COUNT_CTOR(FragmentBuffer);
    28 }
    30 FragmentBuffer::~FragmentBuffer()
    31 {
    32   MOZ_COUNT_DTOR(FragmentBuffer);
    33 }
    35 bool
    36 FragmentBuffer::HasEnoughData()
    37 {
    38   // Audio or video frame is enough to form a moof.
    39   return (mFragArray.Length() > 1);
    40 }
    42 nsresult
    43 FragmentBuffer::GetCSD(nsTArray<uint8_t>& aCSD)
    44 {
    45   if (!mCSDFrame) {
    46     return NS_ERROR_FAILURE;
    47   }
    48   aCSD.AppendElements(mCSDFrame->GetFrameData().Elements(),
    49                       mCSDFrame->GetFrameData().Length());
    51   return NS_OK;
    52 }
    54 nsresult
    55 FragmentBuffer::AddFrame(EncodedFrame* aFrame)
    56 {
    57   // already EOS, it rejects all new data.
    58   if (mEOS) {
    59     MOZ_ASSERT(0);
    60     return NS_OK;
    61   }
    63   EncodedFrame::FrameType type = aFrame->GetFrameType();
    64   if (type == EncodedFrame::AAC_CSD || type == EncodedFrame::AVC_CSD ||
    65       type == EncodedFrame::AMR_AUDIO_CSD) {
    66     mCSDFrame = aFrame;
    67     // Use CSD's timestamp as the start time. Encoder should send CSD frame first
    68     // and then data frames.
    69     mMediaStartTime = aFrame->GetTimeStamp();
    70     mFragmentNumber = 1;
    71     return NS_OK;
    72   }
    74   // if the timestamp is incorrect, abort it.
    75   if (aFrame->GetTimeStamp() < mMediaStartTime) {
    76     MOZ_ASSERT(false);
    77     return NS_ERROR_FAILURE;
    78   }
    80   mFragArray.LastElement().AppendElement(aFrame);
    82   // check if current fragment is reach the fragment duration.
    83   if ((aFrame->GetTimeStamp() - mMediaStartTime) >= (mFragDuration * mFragmentNumber)) {
    84     mFragArray.AppendElement();
    85     mFragmentNumber++;
    86   }
    88   return NS_OK;
    89 }
    91 nsresult
    92 FragmentBuffer::GetFirstFragment(nsTArray<nsRefPtr<EncodedFrame>>& aFragment,
    93                                  bool aFlush)
    94 {
    95   // It should be called only if there is a complete fragment in mFragArray.
    96   if (mFragArray.Length() <= 1 && !mEOS) {
    97     MOZ_ASSERT(false);
    98     return NS_ERROR_FAILURE;
    99   }
   101   if (aFlush) {
   102     aFragment.SwapElements(mFragArray.ElementAt(0));
   103     mFragArray.RemoveElementAt(0);
   104   } else {
   105     aFragment.AppendElements(mFragArray.ElementAt(0));
   106   }
   107   return NS_OK;
   108 }
   110 uint32_t
   111 FragmentBuffer::GetFirstFragmentSampleNumber()
   112 {
   113   return mFragArray.ElementAt(0).Length();
   114 }
   116 uint32_t
   117 FragmentBuffer::GetFirstFragmentSampleSize()
   118 {
   119   uint32_t size = 0;
   120   uint32_t len = mFragArray.ElementAt(0).Length();
   121   for (uint32_t i = 0; i < len; i++) {
   122     size += mFragArray.ElementAt(0).ElementAt(i)->GetFrameData().Length();
   123   }
   124   return size;
   125 }
   127 ISOControl::ISOControl(uint32_t aMuxingType)
   128   : mMuxingType(aMuxingType)
   129   , mAudioFragmentBuffer(nullptr)
   130   , mVideoFragmentBuffer(nullptr)
   131   , mFragNum(0)
   132   , mOutputSize(0)
   133   , mBitCount(0)
   134   , mBit(0)
   135 {
   136   // Create a data array for first mp4 Box, ftyp.
   137   mOutBuffers.SetLength(1);
   138   MOZ_COUNT_CTOR(ISOControl);
   139 }
   141 ISOControl::~ISOControl()
   142 {
   143   MOZ_COUNT_DTOR(ISOControl);
   144 }
   146 uint32_t
   147 ISOControl::GetNextTrackID()
   148 {
   149   return (mMetaArray.Length() + 1);
   150 }
   152 uint32_t
   153 ISOControl::GetTrackID(TrackMetadataBase::MetadataKind aKind)
   154 {
   155   for (uint32_t i = 0; i < mMetaArray.Length(); i++) {
   156     if (mMetaArray[i]->GetKind() == aKind) {
   157       return (i + 1);
   158     }
   159   }
   161   // Track ID shouldn't be 0. It must be something wrong here.
   162   MOZ_ASSERT(0);
   163   return 0;
   164 }
   166 nsresult
   167 ISOControl::SetMetadata(TrackMetadataBase* aTrackMeta)
   168 {
   169   if (aTrackMeta->GetKind() == TrackMetadataBase::METADATA_AAC ||
   170       aTrackMeta->GetKind() == TrackMetadataBase::METADATA_AMR ||
   171       aTrackMeta->GetKind() == TrackMetadataBase::METADATA_AVC) {
   172     mMetaArray.AppendElement(aTrackMeta);
   173     return NS_OK;
   174   }
   175   return NS_ERROR_FAILURE;
   176 }
   178 nsresult
   179 ISOControl::GetAudioMetadata(nsRefPtr<AudioTrackMetadata>& aAudMeta)
   180 {
   181   for (uint32_t i = 0; i < mMetaArray.Length() ; i++) {
   182     if (mMetaArray[i]->GetKind() == TrackMetadataBase::METADATA_AAC ||
   183         mMetaArray[i]->GetKind() == TrackMetadataBase::METADATA_AMR) {
   184       aAudMeta = static_cast<AudioTrackMetadata*>(mMetaArray[i].get());
   185       return NS_OK;
   186     }
   187   }
   188   return NS_ERROR_FAILURE;
   189 }
   191 nsresult
   192 ISOControl::GetVideoMetadata(nsRefPtr<VideoTrackMetadata>& aVidMeta)
   193 {
   194   for (uint32_t i = 0; i < mMetaArray.Length() ; i++) {
   195     if (mMetaArray[i]->GetKind() == TrackMetadataBase::METADATA_AVC) {
   196       aVidMeta = static_cast<VideoTrackMetadata*>(mMetaArray[i].get());
   197       return NS_OK;
   198     }
   199   }
   200   return NS_ERROR_FAILURE;
   201 }
   203 bool
   204 ISOControl::HasAudioTrack()
   205 {
   206   nsRefPtr<AudioTrackMetadata> audMeta;
   207   GetAudioMetadata(audMeta);
   208   return audMeta;
   209 }
   211 bool
   212 ISOControl::HasVideoTrack()
   213 {
   214   nsRefPtr<VideoTrackMetadata> vidMeta;
   215   GetVideoMetadata(vidMeta);
   216   return vidMeta;
   217 }
   219 nsresult
   220 ISOControl::SetFragment(FragmentBuffer* aFragment)
   221 {
   222   if (aFragment->GetType() == Audio_Track) {
   223     mAudioFragmentBuffer = aFragment;
   224   } else {
   225     mVideoFragmentBuffer = aFragment;
   226   }
   227   return NS_OK;
   228 }
   230 FragmentBuffer*
   231 ISOControl::GetFragment(uint32_t aType)
   232 {
   233   if (aType == Audio_Track) {
   234     return mAudioFragmentBuffer;
   235   } else if (aType == Video_Track){
   236     return mVideoFragmentBuffer;
   237   }
   238   MOZ_ASSERT(0);
   239   return nullptr;
   240 }
   242 nsresult
   243 ISOControl::GetBufs(nsTArray<nsTArray<uint8_t>>* aOutputBufs)
   244 {
   245   uint32_t len = mOutBuffers.Length();
   246   for (uint32_t i = 0; i < len; i++) {
   247     mOutBuffers[i].SwapElements(*aOutputBufs->AppendElement());
   248   }
   249   return FlushBuf();
   250 }
   252 nsresult
   253 ISOControl::FlushBuf()
   254 {
   255   mOutBuffers.SetLength(1);
   256   return NS_OK;
   257 }
   259 uint32_t
   260 ISOControl::WriteAVData(nsTArray<uint8_t>& aArray)
   261 {
   262   MOZ_ASSERT(!mBitCount);
   264   uint32_t len = aArray.Length();
   265   if (!len) {
   266     return 0;
   267   }
   269   mOutputSize += len;
   271   // The last element already has data, allocated a new element for pointer
   272   // swapping.
   273   if (mOutBuffers.LastElement().Length()) {
   274     mOutBuffers.AppendElement();
   275   }
   276   // Swap the video/audio data pointer.
   277   mOutBuffers.LastElement().SwapElements(aArray);
   278   // Following data could be boxes, so appending a new uint8_t array here.
   279   mOutBuffers.AppendElement();
   281   return len;
   282 }
   284 uint32_t
   285 ISOControl::WriteBits(uint64_t aBits, size_t aNumBits)
   286 {
   287   uint8_t output_byte = 0;
   289   MOZ_ASSERT(aNumBits <= 64);
   290   // TODO: rewritten following with bitset?
   291   for (size_t i = aNumBits; i > 0; i--) {
   292     mBit |= (((aBits >> (i - 1)) & 1) << (8 - ++mBitCount));
   293     if (mBitCount == 8) {
   294       Write(&mBit, sizeof(uint8_t));
   295       mBit = 0;
   296       mBitCount = 0;
   297       output_byte++;
   298     }
   299   }
   300   return output_byte;
   301 }
   303 uint32_t
   304 ISOControl::Write(uint8_t* aBuf, uint32_t aSize)
   305 {
   306   mOutBuffers.LastElement().AppendElements(aBuf, aSize);
   307   mOutputSize += aSize;
   308   return aSize;
   309 }
   311 uint32_t
   312 ISOControl::Write(uint8_t aData)
   313 {
   314   MOZ_ASSERT(!mBitCount);
   315   Write((uint8_t*)&aData, sizeof(uint8_t));
   316   return sizeof(uint8_t);
   317 }
   319 uint32_t
   320 ISOControl::GetBufPos()
   321 {
   322   uint32_t len = mOutBuffers.Length();
   323   uint32_t pos = 0;
   324   for (uint32_t i = 0; i < len; i++) {
   325     pos += mOutBuffers.ElementAt(i).Length();
   326   }
   327   return pos;
   328 }
   330 uint32_t
   331 ISOControl::WriteFourCC(const char* aType)
   332 {
   333   // Bit operation should be aligned to byte before writing any byte data.
   334   MOZ_ASSERT(!mBitCount);
   336   uint32_t size = strlen(aType);
   337   if (size == 4) {
   338     return Write((uint8_t*)aType, size);
   339   }
   341   return 0;
   342 }
   344 nsresult
   345 ISOControl::GenerateFtyp()
   346 {
   347   nsresult rv;
   348   uint32_t size;
   349   nsAutoPtr<FileTypeBox> type_box(new FileTypeBox(this));
   350   rv = type_box->Generate(&size);
   351   NS_ENSURE_SUCCESS(rv, rv);
   352   rv = type_box->Write();
   353   NS_ENSURE_SUCCESS(rv, rv);
   354   return NS_OK;
   355 }
   357 nsresult
   358 ISOControl::GenerateMoov()
   359 {
   360   nsresult rv;
   361   uint32_t size;
   362   nsAutoPtr<MovieBox> moov_box(new MovieBox(this));
   363   rv = moov_box->Generate(&size);
   364   NS_ENSURE_SUCCESS(rv, rv);
   365   rv = moov_box->Write();
   366   NS_ENSURE_SUCCESS(rv, rv);
   367   return NS_OK;
   368 }
   370 nsresult
   371 ISOControl::GenerateMoof(uint32_t aTrackType)
   372 {
   373   mFragNum++;
   375   nsresult rv;
   376   uint32_t size;
   377   uint64_t first_sample_offset = mOutputSize;
   378   nsAutoPtr<MovieFragmentBox> moof_box(new MovieFragmentBox(aTrackType, this));
   379   nsAutoPtr<MediaDataBox> mdat_box(new MediaDataBox(aTrackType, this));
   381   rv = moof_box->Generate(&size);
   382   NS_ENSURE_SUCCESS(rv, rv);
   383   first_sample_offset += size;
   384   rv = mdat_box->Generate(&size);
   385   NS_ENSURE_SUCCESS(rv, rv);
   386   first_sample_offset += mdat_box->FirstSampleOffsetInMediaDataBox();
   388   // correct offset info
   389   nsTArray<nsRefPtr<MuxerOperation>> tfhds;
   390   rv = moof_box->Find(NS_LITERAL_CSTRING("tfhd"), tfhds);
   391   NS_ENSURE_SUCCESS(rv, rv);
   392   uint32_t len = tfhds.Length();
   393   for (uint32_t i = 0; i < len; i++) {
   394     TrackFragmentHeaderBox* tfhd = (TrackFragmentHeaderBox*) tfhds.ElementAt(i).get();
   395     rv = tfhd->UpdateBaseDataOffset(first_sample_offset);
   396     NS_ENSURE_SUCCESS(rv, rv);
   397   }
   399   rv = moof_box->Write();
   400   NS_ENSURE_SUCCESS(rv, rv);
   401   rv = mdat_box->Write();
   402   NS_ENSURE_SUCCESS(rv, rv);
   404   return NS_OK;
   405 }
   407 uint32_t
   408 ISOControl::GetTime()
   409 {
   410   return (uint64_t)time(nullptr) + iso_time_offset;
   411 }
   413 }

mercurial