content/media/encoder/fmp4_muxer/ISOMediaWriter.cpp

branch
TOR_BUG_9701
changeset 15
b8a032363ba2
equal deleted inserted replaced
-1:000000000000 0:65f3fdfb0b4a
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/. */
5
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"
13
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
21
22 namespace mozilla {
23
24 const static uint32_t FRAG_DURATION = 2 * USECS_PER_S; // microsecond per unit
25
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 }
41
42 ISOMediaWriter::~ISOMediaWriter()
43 {
44 MOZ_COUNT_DTOR(ISOMediaWriter);
45 }
46
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);
65
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 }
80
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 }
90
91 FragmentBuffer* frag = nullptr;
92 uint32_t len = aData.GetEncodedFrames().Length();
93
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 }
115
116 frag->AddFrame(frame);
117 }
118
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 }
131
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 }
137
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 }
150
151 return NS_OK;
152 }
153
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 }
166
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 }
188
189 return bReadyToMux;
190 }
191
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 }
205
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 }
222
223 return NS_ERROR_FAILURE;
224 }
225
226 } // namespace mozilla

mercurial