Fri, 16 Jan 2015 04:50:19 +0100
Replace accessor implementation with direct member state manipulation, by
request https://trac.torproject.org/projects/tor/ticket/9701#comment:32
michael@0 | 1 | /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-*/ |
michael@0 | 2 | /* This Source Code Form is subject to the terms of the Mozilla Public |
michael@0 | 3 | * License, v. 2.0. If a copy of the MPL was not distributed with this file, |
michael@0 | 4 | * You can obtain one at http://mozilla.org/MPL/2.0/. */ |
michael@0 | 5 | |
michael@0 | 6 | #ifndef ISOCOMPOSITOR_H_ |
michael@0 | 7 | #define ISOCOMPOSITOR_H_ |
michael@0 | 8 | |
michael@0 | 9 | #include "mozilla/Endian.h" |
michael@0 | 10 | #include "nsTArray.h" |
michael@0 | 11 | #include "ISOTrackMetadata.h" |
michael@0 | 12 | #include "EncodedFrameContainer.h" |
michael@0 | 13 | |
michael@0 | 14 | namespace mozilla { |
michael@0 | 15 | |
michael@0 | 16 | class Box; |
michael@0 | 17 | class ISOControl; |
michael@0 | 18 | |
michael@0 | 19 | /** |
michael@0 | 20 | * This class collects elementary stream data to form a fragment. |
michael@0 | 21 | * ISOMediaWriter will check if the data is enough; if yes, the corresponding |
michael@0 | 22 | * moof will be created and write to ISOControl. |
michael@0 | 23 | * Each audio and video has its own fragment and only one during the whole |
michael@0 | 24 | * life cycle, when a fragment is formed in ISOControl, Flush() needs to |
michael@0 | 25 | * be called to reset it. |
michael@0 | 26 | */ |
michael@0 | 27 | class FragmentBuffer { |
michael@0 | 28 | public: |
michael@0 | 29 | // aTrackType: it could be Audio_Track or Video_Track. |
michael@0 | 30 | // aFragDuration: it is the fragment duration. (microsecond per unit) |
michael@0 | 31 | // Audio and video have the same fragment duration. |
michael@0 | 32 | FragmentBuffer(uint32_t aTrackType, uint32_t aFragDuration); |
michael@0 | 33 | ~FragmentBuffer(); |
michael@0 | 34 | |
michael@0 | 35 | // Get samples of first fragment, that will swap all the elements in the |
michael@0 | 36 | // mFragArray[0] when aFlush = true, and caller is responsible for drop |
michael@0 | 37 | // EncodedFrame reference count. |
michael@0 | 38 | nsresult GetFirstFragment(nsTArray<nsRefPtr<EncodedFrame>>& aFragment, |
michael@0 | 39 | bool aFlush = false); |
michael@0 | 40 | |
michael@0 | 41 | // Add sample frame to the last element fragment of mFragArray. If sample |
michael@0 | 42 | // number is enough, it will append a new fragment element. And the new |
michael@0 | 43 | // sample will be added to the new fragment element of mFragArray. |
michael@0 | 44 | nsresult AddFrame(EncodedFrame* aFrame); |
michael@0 | 45 | |
michael@0 | 46 | // Get total sample size of first complete fragment size. |
michael@0 | 47 | uint32_t GetFirstFragmentSampleSize(); |
michael@0 | 48 | |
michael@0 | 49 | // Get sample number of first complete fragment. |
michael@0 | 50 | uint32_t GetFirstFragmentSampleNumber(); |
michael@0 | 51 | |
michael@0 | 52 | // Check if it accumulates enough frame data. |
michael@0 | 53 | // It returns true when data is enough to form a fragment. |
michael@0 | 54 | bool HasEnoughData(); |
michael@0 | 55 | |
michael@0 | 56 | // Called by ISOMediaWriter when TrackEncoder has sent the last frame. The |
michael@0 | 57 | // remains frame data will form the last moof and move the state machine to |
michael@0 | 58 | // in ISOMediaWriter to last phrase. |
michael@0 | 59 | nsresult SetEndOfStream() { |
michael@0 | 60 | mEOS = true; |
michael@0 | 61 | return NS_OK; |
michael@0 | 62 | } |
michael@0 | 63 | bool EOS() { return mEOS; } |
michael@0 | 64 | |
michael@0 | 65 | // CSD (codec specific data), it is generated by encoder and the data depends |
michael@0 | 66 | // on codec type. This data will be sent as a special frame from encoder to |
michael@0 | 67 | // ISOMediaWriter and pass to this class via AddFrame(). |
michael@0 | 68 | nsresult GetCSD(nsTArray<uint8_t>& aCSD); |
michael@0 | 69 | |
michael@0 | 70 | bool HasCSD() { return mCSDFrame; } |
michael@0 | 71 | |
michael@0 | 72 | uint32_t GetType() { return mTrackType; } |
michael@0 | 73 | |
michael@0 | 74 | void SetLastFragmentLastFrameTime(uint32_t aTime) { |
michael@0 | 75 | mLastFrameTimeOfLastFragment = aTime; |
michael@0 | 76 | } |
michael@0 | 77 | |
michael@0 | 78 | uint32_t GetLastFragmentLastFrameTime() { |
michael@0 | 79 | return mLastFrameTimeOfLastFragment; |
michael@0 | 80 | } |
michael@0 | 81 | |
michael@0 | 82 | private: |
michael@0 | 83 | uint32_t mTrackType; |
michael@0 | 84 | |
michael@0 | 85 | // Fragment duration, microsecond per unit. |
michael@0 | 86 | uint32_t mFragDuration; |
michael@0 | 87 | |
michael@0 | 88 | // Media start time, microsecond per unit. |
michael@0 | 89 | // Together with mFragDuration, mFragmentNumber and EncodedFrame->GetTimeStamp(), |
michael@0 | 90 | // when the difference between current frame time and mMediaStartTime is |
michael@0 | 91 | // exceeded current fragment ceiling timeframe, that means current fragment has |
michael@0 | 92 | // enough data and a new element in mFragArray will be added. |
michael@0 | 93 | uint64_t mMediaStartTime; |
michael@0 | 94 | |
michael@0 | 95 | // Current fragment number. It will be increase when a new element of |
michael@0 | 96 | // mFragArray is created. |
michael@0 | 97 | // Note: |
michael@0 | 98 | // It only means the fragment number of current accumulated frames, not |
michael@0 | 99 | // the current 'creating' fragment mFragNum in ISOControl. |
michael@0 | 100 | uint32_t mFragmentNumber; |
michael@0 | 101 | |
michael@0 | 102 | // The last frame time stamp of last fragment. It is for calculating the |
michael@0 | 103 | // play duration of first frame in current fragment. The frame duration is |
michael@0 | 104 | // defined as "current frame timestamp - last frame timestamp" here. So it |
michael@0 | 105 | // needs to keep the last timestamp of last fragment. |
michael@0 | 106 | uint32_t mLastFrameTimeOfLastFragment; |
michael@0 | 107 | |
michael@0 | 108 | // Array of fragments, each element has enough samples to form a |
michael@0 | 109 | // complete fragment. |
michael@0 | 110 | nsTArray<nsTArray<nsRefPtr<EncodedFrame>>> mFragArray; |
michael@0 | 111 | |
michael@0 | 112 | // Codec specific data frame, it will be generated by encoder and send to |
michael@0 | 113 | // ISOMediaWriter through WriteEncodedTrack(). The data will be vary depends |
michael@0 | 114 | // on codec type. |
michael@0 | 115 | nsRefPtr<EncodedFrame> mCSDFrame; |
michael@0 | 116 | |
michael@0 | 117 | // END_OF_STREAM from ContainerWriter |
michael@0 | 118 | bool mEOS; |
michael@0 | 119 | }; |
michael@0 | 120 | |
michael@0 | 121 | /** |
michael@0 | 122 | * ISOControl will be carried to each box when box is created. It is the main |
michael@0 | 123 | * bridge for box to output stream to ContainerWriter and retrieve information. |
michael@0 | 124 | * ISOControl acts 3 different roles: |
michael@0 | 125 | * 1. Holds the pointer of audio metadata, video metadata, fragment and |
michael@0 | 126 | * pass them to boxes. |
michael@0 | 127 | * 2. Provide the functions to generate the base structure of MP4; they are |
michael@0 | 128 | * GenerateFtyp, GenerateMoov, GenerateMoof, and GenerateMfra. |
michael@0 | 129 | * 3. The actually writer used by MuxOperation::Write() in each box. It provides |
michael@0 | 130 | * writing methods for different kind of data; they are Write, WriteArray, |
michael@0 | 131 | * WriteBits...etc. |
michael@0 | 132 | */ |
michael@0 | 133 | class ISOControl { |
michael@0 | 134 | |
michael@0 | 135 | friend class Box; |
michael@0 | 136 | |
michael@0 | 137 | public: |
michael@0 | 138 | ISOControl(uint32_t aMuxingType); |
michael@0 | 139 | ~ISOControl(); |
michael@0 | 140 | |
michael@0 | 141 | nsresult GenerateFtyp(); |
michael@0 | 142 | nsresult GenerateMoov(); |
michael@0 | 143 | nsresult GenerateMoof(uint32_t aTrackType); |
michael@0 | 144 | |
michael@0 | 145 | // Swap elementary stream pointer to output buffers. |
michael@0 | 146 | uint32_t WriteAVData(nsTArray<uint8_t>& aArray); |
michael@0 | 147 | |
michael@0 | 148 | uint32_t Write(uint8_t* aBuf, uint32_t aSize); |
michael@0 | 149 | |
michael@0 | 150 | uint32_t Write(uint8_t aData); |
michael@0 | 151 | |
michael@0 | 152 | template <typename T> |
michael@0 | 153 | uint32_t Write(T aData) { |
michael@0 | 154 | MOZ_ASSERT(!mBitCount); |
michael@0 | 155 | |
michael@0 | 156 | aData = NativeEndian::swapToNetworkOrder(aData); |
michael@0 | 157 | Write((uint8_t*)&aData, sizeof(T)); |
michael@0 | 158 | return sizeof(T); |
michael@0 | 159 | } |
michael@0 | 160 | |
michael@0 | 161 | template <typename T> |
michael@0 | 162 | uint32_t WriteArray(const T &aArray, uint32_t aSize) { |
michael@0 | 163 | MOZ_ASSERT(!mBitCount); |
michael@0 | 164 | |
michael@0 | 165 | uint32_t size = 0; |
michael@0 | 166 | for (uint32_t i = 0; i < aSize; i++) { |
michael@0 | 167 | size += Write(aArray[i]); |
michael@0 | 168 | } |
michael@0 | 169 | return size; |
michael@0 | 170 | } |
michael@0 | 171 | |
michael@0 | 172 | uint32_t WriteFourCC(const char* aType); |
michael@0 | 173 | |
michael@0 | 174 | // Bit writing. Note: it needs to be byte-boundary before using |
michael@0 | 175 | // others non-bit writing function. |
michael@0 | 176 | uint32_t WriteBits(uint64_t aBits, size_t aNumBits); |
michael@0 | 177 | |
michael@0 | 178 | // This is called by GetContainerData and swap all the buffers to aOutputBuffers. |
michael@0 | 179 | nsresult GetBufs(nsTArray<nsTArray<uint8_t>>* aOutputBufs); |
michael@0 | 180 | |
michael@0 | 181 | // Presentation time in seconds since midnight, Jan. 1, 1904, in UTC time. |
michael@0 | 182 | uint32_t GetTime(); |
michael@0 | 183 | |
michael@0 | 184 | // current fragment number |
michael@0 | 185 | uint32_t GetCurFragmentNumber() { return mFragNum; } |
michael@0 | 186 | |
michael@0 | 187 | nsresult SetFragment(FragmentBuffer* aFragment); |
michael@0 | 188 | FragmentBuffer* GetFragment(uint32_t aType); |
michael@0 | 189 | |
michael@0 | 190 | uint32_t GetMuxingType() { return mMuxingType; } |
michael@0 | 191 | |
michael@0 | 192 | nsresult SetMetadata(TrackMetadataBase* aTrackMeta); |
michael@0 | 193 | nsresult GetAudioMetadata(nsRefPtr<AudioTrackMetadata>& aAudMeta); |
michael@0 | 194 | nsresult GetVideoMetadata(nsRefPtr<VideoTrackMetadata>& aVidMeta); |
michael@0 | 195 | |
michael@0 | 196 | // Track ID is the Metadata index in mMetaArray. It allows only 1 audio |
michael@0 | 197 | // track and 1 video track in this muxer. In this muxer, it is prohibt to have |
michael@0 | 198 | // mutiple audio track or video track in the same file. |
michael@0 | 199 | uint32_t GetTrackID(TrackMetadataBase::MetadataKind aKind); |
michael@0 | 200 | uint32_t GetNextTrackID(); |
michael@0 | 201 | |
michael@0 | 202 | bool HasAudioTrack(); |
michael@0 | 203 | bool HasVideoTrack(); |
michael@0 | 204 | |
michael@0 | 205 | private: |
michael@0 | 206 | uint32_t GetBufPos(); |
michael@0 | 207 | nsresult FlushBuf(); |
michael@0 | 208 | |
michael@0 | 209 | // One of value in TYPE_XXX, defined in ISOMediaWriter. |
michael@0 | 210 | uint32_t mMuxingType; |
michael@0 | 211 | |
michael@0 | 212 | // Audio and video fragments are owned by ISOMediaWriter. |
michael@0 | 213 | // They don't need to worry about pointer going stale because ISOMediaWriter's |
michael@0 | 214 | // lifetime is longer than ISOControl. |
michael@0 | 215 | FragmentBuffer* mAudioFragmentBuffer; |
michael@0 | 216 | FragmentBuffer* mVideoFragmentBuffer; |
michael@0 | 217 | |
michael@0 | 218 | // Generated fragment number |
michael@0 | 219 | uint32_t mFragNum; |
michael@0 | 220 | |
michael@0 | 221 | // The (index + 1) will be the track ID. |
michael@0 | 222 | nsTArray<nsRefPtr<TrackMetadataBase>> mMetaArray; |
michael@0 | 223 | |
michael@0 | 224 | // Array of output buffers. |
michael@0 | 225 | // To save memory usage, audio/video sample will be swapped into a new element |
michael@0 | 226 | // of this array. |
michael@0 | 227 | // |
michael@0 | 228 | // For example, |
michael@0 | 229 | // mOutBuffers[0] --> boxes (allocated by muxer) |
michael@0 | 230 | // mOutBuffers[1] --> video raw data (allocated by encoder) |
michael@0 | 231 | // mOutBuffers[2] --> video raw data (allocated by encoder) |
michael@0 | 232 | // mOutBuffers[3] --> video raw data (allocated by encoder) |
michael@0 | 233 | // mOutBuffers[4] --> boxes (allocated by muxer) |
michael@0 | 234 | // mOutBuffers[5] --> audio raw data (allocated by encoder) |
michael@0 | 235 | // ...etc. |
michael@0 | 236 | // |
michael@0 | 237 | nsTArray<nsTArray<uint8_t>> mOutBuffers; |
michael@0 | 238 | |
michael@0 | 239 | // Accumulate output size from Write(). |
michael@0 | 240 | uint64_t mOutputSize; |
michael@0 | 241 | |
michael@0 | 242 | // Bit writing operation. Note: the mBitCount should be 0 before any |
michael@0 | 243 | // byte-boundary writing method be called (Write(uint32_t), Write(uint16_t)...etc); |
michael@0 | 244 | // otherwise, there will be assertion on these functions. |
michael@0 | 245 | uint8_t mBitCount; |
michael@0 | 246 | uint8_t mBit; |
michael@0 | 247 | }; |
michael@0 | 248 | |
michael@0 | 249 | } |
michael@0 | 250 | #endif |