content/media/encoder/fmp4_muxer/ISOMediaWriter.cpp

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

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

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

     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 "ISOMediaWriter.h"
     7 #include "ISOControl.h"
     8 #include "ISOMediaBoxes.h"
     9 #include "ISOTrackMetadata.h"
    10 #include "nsThreadUtils.h"
    11 #include "MediaEncoder.h"
    12 #include "VideoUtils.h"
    14 #undef LOG
    15 #ifdef MOZ_WIDGET_GONK
    16 #include <android/log.h>
    17 #define LOG(args...) __android_log_print(ANDROID_LOG_INFO, "MediaEncoder", ## args);
    18 #else
    19 #define LOG(args, ...)
    20 #endif
    22 namespace mozilla {
    24 const static uint32_t FRAG_DURATION = 2 * USECS_PER_S;    // microsecond per unit
    26 ISOMediaWriter::ISOMediaWriter(uint32_t aType, uint32_t aHint)
    27   : ContainerWriter()
    28   , mState(MUXING_HEAD)
    29   , mBlobReady(false)
    30   , mType(0)
    31 {
    32   if (aType & CREATE_AUDIO_TRACK) {
    33     mType |= Audio_Track;
    34   }
    35   if (aType & CREATE_VIDEO_TRACK) {
    36     mType |= Video_Track;
    37   }
    38   mControl = new ISOControl(aHint);
    39   MOZ_COUNT_CTOR(ISOMediaWriter);
    40 }
    42 ISOMediaWriter::~ISOMediaWriter()
    43 {
    44   MOZ_COUNT_DTOR(ISOMediaWriter);
    45 }
    47 nsresult
    48 ISOMediaWriter::RunState()
    49 {
    50   nsresult rv;
    51   switch (mState) {
    52     case MUXING_HEAD:
    53     {
    54       rv = mControl->GenerateFtyp();
    55       NS_ENSURE_SUCCESS(rv, rv);
    56       rv = mControl->GenerateMoov();
    57       NS_ENSURE_SUCCESS(rv, rv);
    58       mState = MUXING_FRAG;
    59       break;
    60     }
    61     case MUXING_FRAG:
    62     {
    63       rv = mControl->GenerateMoof(mType);
    64       NS_ENSURE_SUCCESS(rv, rv);
    66       bool EOS;
    67       if (ReadyToRunState(EOS) && EOS) {
    68         mState = MUXING_DONE;
    69       }
    70       break;
    71     }
    72     case MUXING_DONE:
    73     {
    74       break;
    75     }
    76   }
    77   mBlobReady = true;
    78   return NS_OK;
    79 }
    81 nsresult
    82 ISOMediaWriter::WriteEncodedTrack(const EncodedFrameContainer& aData,
    83                                   uint32_t aFlags)
    84 {
    85   // Muxing complete, it doesn't allowed to reentry again.
    86   if (mState == MUXING_DONE) {
    87     MOZ_ASSERT(false);
    88     return NS_ERROR_FAILURE;
    89   }
    91   FragmentBuffer* frag = nullptr;
    92   uint32_t len = aData.GetEncodedFrames().Length();
    94   if (!len) {
    95     // no frame? why bother to WriteEncodedTrack
    96     return NS_OK;
    97   }
    98   for (uint32_t i = 0; i < len; i++) {
    99     nsRefPtr<EncodedFrame> frame(aData.GetEncodedFrames()[i]);
   100     EncodedFrame::FrameType type = frame->GetFrameType();
   101     if (type == EncodedFrame::AAC_AUDIO_FRAME ||
   102         type == EncodedFrame::AAC_CSD ||
   103         type == EncodedFrame::AMR_AUDIO_FRAME ||
   104         type == EncodedFrame::AMR_AUDIO_CSD) {
   105       frag = mAudioFragmentBuffer;
   106     } else if (type == EncodedFrame::AVC_I_FRAME ||
   107                type == EncodedFrame::AVC_P_FRAME ||
   108                type == EncodedFrame::AVC_B_FRAME ||
   109                type == EncodedFrame::AVC_CSD) {
   110       frag = mVideoFragmentBuffer;
   111     } else {
   112       MOZ_ASSERT(0);
   113       return NS_ERROR_FAILURE;
   114     }
   116     frag->AddFrame(frame);
   117   }
   119   // Encoder should send CSD (codec specific data) frame before sending the
   120   // audio/video frames. When CSD data is ready, it is sufficient to generate a
   121   // moov data. If encoder doesn't send CSD yet, muxer needs to wait before
   122   // generating anything.
   123   if (mType & Audio_Track && (!mAudioFragmentBuffer ||
   124                               !mAudioFragmentBuffer->HasCSD())) {
   125     return NS_OK;
   126   }
   127   if (mType & Video_Track && (!mVideoFragmentBuffer ||
   128                               !mVideoFragmentBuffer->HasCSD())) {
   129     return NS_OK;
   130   }
   132   // Only one FrameType in EncodedFrameContainer so it doesn't need to be
   133   // inside the for-loop.
   134   if (frag && (aFlags & END_OF_STREAM)) {
   135     frag->SetEndOfStream();
   136   }
   138   nsresult rv;
   139   bool EOS;
   140   if (ReadyToRunState(EOS)) {
   141     // TODO:
   142     // The MediaEncoder doesn't use nsRunnable, so thread will be
   143     // stocked on that part and the new added nsRunnable won't get to run
   144     // before MediaEncoder completing. Before MediaEncoder change, it needs
   145     // to call RunState directly.
   146     // https://bugzilla.mozilla.org/show_bug.cgi?id=950429
   147     rv = RunState();
   148     NS_ENSURE_SUCCESS(rv, rv);
   149   }
   151   return NS_OK;
   152 }
   154 bool
   155 ISOMediaWriter::ReadyToRunState(bool& aEOS)
   156 {
   157   aEOS = false;
   158   bool bReadyToMux = true;
   159   if ((mType & Audio_Track) && (mType & Video_Track)) {
   160     if (!mAudioFragmentBuffer->HasEnoughData()) {
   161       bReadyToMux = false;
   162     }
   163     if (!mVideoFragmentBuffer->HasEnoughData()) {
   164       bReadyToMux = false;
   165     }
   167     if (mAudioFragmentBuffer->EOS() && mVideoFragmentBuffer->EOS()) {
   168       aEOS = true;
   169       bReadyToMux = true;
   170     }
   171   } else if (mType == Audio_Track) {
   172     if (!mAudioFragmentBuffer->HasEnoughData()) {
   173       bReadyToMux = false;
   174     }
   175     if (mAudioFragmentBuffer->EOS()) {
   176       aEOS = true;
   177       bReadyToMux = true;
   178     }
   179   } else if (mType == Video_Track) {
   180     if (!mVideoFragmentBuffer->HasEnoughData()) {
   181       bReadyToMux = false;
   182     }
   183     if (mVideoFragmentBuffer->EOS()) {
   184       aEOS = true;
   185       bReadyToMux = true;
   186     }
   187   }
   189   return bReadyToMux;
   190 }
   192 nsresult
   193 ISOMediaWriter::GetContainerData(nsTArray<nsTArray<uint8_t>>* aOutputBufs,
   194                                  uint32_t aFlags)
   195 {
   196   if (mBlobReady) {
   197     if (mState == MUXING_DONE) {
   198       mIsWritingComplete = true;
   199     }
   200     mBlobReady = false;
   201     return mControl->GetBufs(aOutputBufs);
   202   }
   203   return NS_OK;
   204 }
   206 nsresult
   207 ISOMediaWriter::SetMetadata(TrackMetadataBase* aMetadata)
   208 {
   209   if (aMetadata->GetKind() == TrackMetadataBase::METADATA_AAC ||
   210       aMetadata->GetKind() == TrackMetadataBase::METADATA_AMR) {
   211     mControl->SetMetadata(aMetadata);
   212     mAudioFragmentBuffer = new FragmentBuffer(Audio_Track, FRAG_DURATION);
   213     mControl->SetFragment(mAudioFragmentBuffer);
   214     return NS_OK;
   215   }
   216   if (aMetadata->GetKind() == TrackMetadataBase::METADATA_AVC) {
   217     mControl->SetMetadata(aMetadata);
   218     mVideoFragmentBuffer = new FragmentBuffer(Video_Track, FRAG_DURATION);
   219     mControl->SetFragment(mVideoFragmentBuffer);
   220     return NS_OK;
   221   }
   223   return NS_ERROR_FAILURE;
   224 }
   226 }  // namespace mozilla

mercurial