1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/content/media/encoder/fmp4_muxer/ISOControl.h Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,250 @@ 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 +#ifndef ISOCOMPOSITOR_H_ 1.10 +#define ISOCOMPOSITOR_H_ 1.11 + 1.12 +#include "mozilla/Endian.h" 1.13 +#include "nsTArray.h" 1.14 +#include "ISOTrackMetadata.h" 1.15 +#include "EncodedFrameContainer.h" 1.16 + 1.17 +namespace mozilla { 1.18 + 1.19 +class Box; 1.20 +class ISOControl; 1.21 + 1.22 +/** 1.23 + * This class collects elementary stream data to form a fragment. 1.24 + * ISOMediaWriter will check if the data is enough; if yes, the corresponding 1.25 + * moof will be created and write to ISOControl. 1.26 + * Each audio and video has its own fragment and only one during the whole 1.27 + * life cycle, when a fragment is formed in ISOControl, Flush() needs to 1.28 + * be called to reset it. 1.29 + */ 1.30 +class FragmentBuffer { 1.31 +public: 1.32 + // aTrackType: it could be Audio_Track or Video_Track. 1.33 + // aFragDuration: it is the fragment duration. (microsecond per unit) 1.34 + // Audio and video have the same fragment duration. 1.35 + FragmentBuffer(uint32_t aTrackType, uint32_t aFragDuration); 1.36 + ~FragmentBuffer(); 1.37 + 1.38 + // Get samples of first fragment, that will swap all the elements in the 1.39 + // mFragArray[0] when aFlush = true, and caller is responsible for drop 1.40 + // EncodedFrame reference count. 1.41 + nsresult GetFirstFragment(nsTArray<nsRefPtr<EncodedFrame>>& aFragment, 1.42 + bool aFlush = false); 1.43 + 1.44 + // Add sample frame to the last element fragment of mFragArray. If sample 1.45 + // number is enough, it will append a new fragment element. And the new 1.46 + // sample will be added to the new fragment element of mFragArray. 1.47 + nsresult AddFrame(EncodedFrame* aFrame); 1.48 + 1.49 + // Get total sample size of first complete fragment size. 1.50 + uint32_t GetFirstFragmentSampleSize(); 1.51 + 1.52 + // Get sample number of first complete fragment. 1.53 + uint32_t GetFirstFragmentSampleNumber(); 1.54 + 1.55 + // Check if it accumulates enough frame data. 1.56 + // It returns true when data is enough to form a fragment. 1.57 + bool HasEnoughData(); 1.58 + 1.59 + // Called by ISOMediaWriter when TrackEncoder has sent the last frame. The 1.60 + // remains frame data will form the last moof and move the state machine to 1.61 + // in ISOMediaWriter to last phrase. 1.62 + nsresult SetEndOfStream() { 1.63 + mEOS = true; 1.64 + return NS_OK; 1.65 + } 1.66 + bool EOS() { return mEOS; } 1.67 + 1.68 + // CSD (codec specific data), it is generated by encoder and the data depends 1.69 + // on codec type. This data will be sent as a special frame from encoder to 1.70 + // ISOMediaWriter and pass to this class via AddFrame(). 1.71 + nsresult GetCSD(nsTArray<uint8_t>& aCSD); 1.72 + 1.73 + bool HasCSD() { return mCSDFrame; } 1.74 + 1.75 + uint32_t GetType() { return mTrackType; } 1.76 + 1.77 + void SetLastFragmentLastFrameTime(uint32_t aTime) { 1.78 + mLastFrameTimeOfLastFragment = aTime; 1.79 + } 1.80 + 1.81 + uint32_t GetLastFragmentLastFrameTime() { 1.82 + return mLastFrameTimeOfLastFragment; 1.83 + } 1.84 + 1.85 +private: 1.86 + uint32_t mTrackType; 1.87 + 1.88 + // Fragment duration, microsecond per unit. 1.89 + uint32_t mFragDuration; 1.90 + 1.91 + // Media start time, microsecond per unit. 1.92 + // Together with mFragDuration, mFragmentNumber and EncodedFrame->GetTimeStamp(), 1.93 + // when the difference between current frame time and mMediaStartTime is 1.94 + // exceeded current fragment ceiling timeframe, that means current fragment has 1.95 + // enough data and a new element in mFragArray will be added. 1.96 + uint64_t mMediaStartTime; 1.97 + 1.98 + // Current fragment number. It will be increase when a new element of 1.99 + // mFragArray is created. 1.100 + // Note: 1.101 + // It only means the fragment number of current accumulated frames, not 1.102 + // the current 'creating' fragment mFragNum in ISOControl. 1.103 + uint32_t mFragmentNumber; 1.104 + 1.105 + // The last frame time stamp of last fragment. It is for calculating the 1.106 + // play duration of first frame in current fragment. The frame duration is 1.107 + // defined as "current frame timestamp - last frame timestamp" here. So it 1.108 + // needs to keep the last timestamp of last fragment. 1.109 + uint32_t mLastFrameTimeOfLastFragment; 1.110 + 1.111 + // Array of fragments, each element has enough samples to form a 1.112 + // complete fragment. 1.113 + nsTArray<nsTArray<nsRefPtr<EncodedFrame>>> mFragArray; 1.114 + 1.115 + // Codec specific data frame, it will be generated by encoder and send to 1.116 + // ISOMediaWriter through WriteEncodedTrack(). The data will be vary depends 1.117 + // on codec type. 1.118 + nsRefPtr<EncodedFrame> mCSDFrame; 1.119 + 1.120 + // END_OF_STREAM from ContainerWriter 1.121 + bool mEOS; 1.122 +}; 1.123 + 1.124 +/** 1.125 + * ISOControl will be carried to each box when box is created. It is the main 1.126 + * bridge for box to output stream to ContainerWriter and retrieve information. 1.127 + * ISOControl acts 3 different roles: 1.128 + * 1. Holds the pointer of audio metadata, video metadata, fragment and 1.129 + * pass them to boxes. 1.130 + * 2. Provide the functions to generate the base structure of MP4; they are 1.131 + * GenerateFtyp, GenerateMoov, GenerateMoof, and GenerateMfra. 1.132 + * 3. The actually writer used by MuxOperation::Write() in each box. It provides 1.133 + * writing methods for different kind of data; they are Write, WriteArray, 1.134 + * WriteBits...etc. 1.135 + */ 1.136 +class ISOControl { 1.137 + 1.138 +friend class Box; 1.139 + 1.140 +public: 1.141 + ISOControl(uint32_t aMuxingType); 1.142 + ~ISOControl(); 1.143 + 1.144 + nsresult GenerateFtyp(); 1.145 + nsresult GenerateMoov(); 1.146 + nsresult GenerateMoof(uint32_t aTrackType); 1.147 + 1.148 + // Swap elementary stream pointer to output buffers. 1.149 + uint32_t WriteAVData(nsTArray<uint8_t>& aArray); 1.150 + 1.151 + uint32_t Write(uint8_t* aBuf, uint32_t aSize); 1.152 + 1.153 + uint32_t Write(uint8_t aData); 1.154 + 1.155 + template <typename T> 1.156 + uint32_t Write(T aData) { 1.157 + MOZ_ASSERT(!mBitCount); 1.158 + 1.159 + aData = NativeEndian::swapToNetworkOrder(aData); 1.160 + Write((uint8_t*)&aData, sizeof(T)); 1.161 + return sizeof(T); 1.162 + } 1.163 + 1.164 + template <typename T> 1.165 + uint32_t WriteArray(const T &aArray, uint32_t aSize) { 1.166 + MOZ_ASSERT(!mBitCount); 1.167 + 1.168 + uint32_t size = 0; 1.169 + for (uint32_t i = 0; i < aSize; i++) { 1.170 + size += Write(aArray[i]); 1.171 + } 1.172 + return size; 1.173 + } 1.174 + 1.175 + uint32_t WriteFourCC(const char* aType); 1.176 + 1.177 + // Bit writing. Note: it needs to be byte-boundary before using 1.178 + // others non-bit writing function. 1.179 + uint32_t WriteBits(uint64_t aBits, size_t aNumBits); 1.180 + 1.181 + // This is called by GetContainerData and swap all the buffers to aOutputBuffers. 1.182 + nsresult GetBufs(nsTArray<nsTArray<uint8_t>>* aOutputBufs); 1.183 + 1.184 + // Presentation time in seconds since midnight, Jan. 1, 1904, in UTC time. 1.185 + uint32_t GetTime(); 1.186 + 1.187 + // current fragment number 1.188 + uint32_t GetCurFragmentNumber() { return mFragNum; } 1.189 + 1.190 + nsresult SetFragment(FragmentBuffer* aFragment); 1.191 + FragmentBuffer* GetFragment(uint32_t aType); 1.192 + 1.193 + uint32_t GetMuxingType() { return mMuxingType; } 1.194 + 1.195 + nsresult SetMetadata(TrackMetadataBase* aTrackMeta); 1.196 + nsresult GetAudioMetadata(nsRefPtr<AudioTrackMetadata>& aAudMeta); 1.197 + nsresult GetVideoMetadata(nsRefPtr<VideoTrackMetadata>& aVidMeta); 1.198 + 1.199 + // Track ID is the Metadata index in mMetaArray. It allows only 1 audio 1.200 + // track and 1 video track in this muxer. In this muxer, it is prohibt to have 1.201 + // mutiple audio track or video track in the same file. 1.202 + uint32_t GetTrackID(TrackMetadataBase::MetadataKind aKind); 1.203 + uint32_t GetNextTrackID(); 1.204 + 1.205 + bool HasAudioTrack(); 1.206 + bool HasVideoTrack(); 1.207 + 1.208 +private: 1.209 + uint32_t GetBufPos(); 1.210 + nsresult FlushBuf(); 1.211 + 1.212 + // One of value in TYPE_XXX, defined in ISOMediaWriter. 1.213 + uint32_t mMuxingType; 1.214 + 1.215 + // Audio and video fragments are owned by ISOMediaWriter. 1.216 + // They don't need to worry about pointer going stale because ISOMediaWriter's 1.217 + // lifetime is longer than ISOControl. 1.218 + FragmentBuffer* mAudioFragmentBuffer; 1.219 + FragmentBuffer* mVideoFragmentBuffer; 1.220 + 1.221 + // Generated fragment number 1.222 + uint32_t mFragNum; 1.223 + 1.224 + // The (index + 1) will be the track ID. 1.225 + nsTArray<nsRefPtr<TrackMetadataBase>> mMetaArray; 1.226 + 1.227 + // Array of output buffers. 1.228 + // To save memory usage, audio/video sample will be swapped into a new element 1.229 + // of this array. 1.230 + // 1.231 + // For example, 1.232 + // mOutBuffers[0] --> boxes (allocated by muxer) 1.233 + // mOutBuffers[1] --> video raw data (allocated by encoder) 1.234 + // mOutBuffers[2] --> video raw data (allocated by encoder) 1.235 + // mOutBuffers[3] --> video raw data (allocated by encoder) 1.236 + // mOutBuffers[4] --> boxes (allocated by muxer) 1.237 + // mOutBuffers[5] --> audio raw data (allocated by encoder) 1.238 + // ...etc. 1.239 + // 1.240 + nsTArray<nsTArray<uint8_t>> mOutBuffers; 1.241 + 1.242 + // Accumulate output size from Write(). 1.243 + uint64_t mOutputSize; 1.244 + 1.245 + // Bit writing operation. Note: the mBitCount should be 0 before any 1.246 + // byte-boundary writing method be called (Write(uint32_t), Write(uint16_t)...etc); 1.247 + // otherwise, there will be assertion on these functions. 1.248 + uint8_t mBitCount; 1.249 + uint8_t mBit; 1.250 +}; 1.251 + 1.252 +} 1.253 +#endif