content/media/encoder/fmp4_muxer/ISOControl.h

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

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

mercurial