File: | var/lib/jenkins/workspace/firefox-scan-build/dom/media/encoder/OpusTrackEncoder.cpp |
Warning: | line 401, column 5 Value stored to 'result' is never read |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
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 | #include "OpusTrackEncoder.h" |
6 | #include "nsString.h" |
7 | #include "mozilla/CheckedInt.h" |
8 | #include "mozilla/ProfilerLabels.h" |
9 | #include "VideoUtils.h" |
10 | |
11 | #include <opus/opus.h> |
12 | |
13 | #define LOG(args, ...) |
14 | |
15 | namespace mozilla { |
16 | |
17 | // The Opus format supports up to 8 channels, and supports multitrack audio up |
18 | // to 255 channels, but the current implementation supports only mono and |
19 | // stereo, and downmixes any more than that. |
20 | constexpr int MAX_SUPPORTED_AUDIO_CHANNELS = 8; |
21 | |
22 | // http://www.opus-codec.org/docs/html_api-1.0.2/group__opus__encoder.html |
23 | // In section "opus_encoder_init", channels must be 1 or 2 of input signal. |
24 | constexpr int MAX_CHANNELS = 2; |
25 | |
26 | // A maximum data bytes for Opus to encode. |
27 | constexpr int MAX_DATA_BYTES = 4096; |
28 | |
29 | // http://tools.ietf.org/html/draft-ietf-codec-oggopus-00#section-4 |
30 | // Second paragraph, " The granule position of an audio data page is in units |
31 | // of PCM audio samples at a fixed rate of 48 kHz." |
32 | constexpr int kOpusSamplingRate = 48000; |
33 | |
34 | // The duration of an Opus frame, and it must be 2.5, 5, 10, 20, 40 or 60 ms. |
35 | constexpr int kFrameDurationMs = 20; |
36 | |
37 | // The supported sampling rate of input signal (Hz), |
38 | // must be one of the following. Will resampled to 48kHz otherwise. |
39 | constexpr int kOpusSupportedInputSamplingRates[] = {8000, 12000, 16000, 24000, |
40 | 48000}; |
41 | |
42 | namespace { |
43 | |
44 | // An endian-neutral serialization of integers. Serializing T in little endian |
45 | // format to aOutput, where T is a 16 bits or 32 bits integer. |
46 | template <typename T> |
47 | static void SerializeToBuffer(T aValue, nsTArray<uint8_t>* aOutput) { |
48 | for (uint32_t i = 0; i < sizeof(T); i++) { |
49 | aOutput->AppendElement((uint8_t)(0x000000ff & (aValue >> (i * 8)))); |
50 | } |
51 | } |
52 | |
53 | static inline void SerializeToBuffer(const nsCString& aComment, |
54 | nsTArray<uint8_t>* aOutput) { |
55 | // Format of serializing a string to buffer is, the length of string (32 bits, |
56 | // little endian), and the string. |
57 | SerializeToBuffer((uint32_t)(aComment.Length()), aOutput); |
58 | aOutput->AppendElements(aComment.get(), aComment.Length()); |
59 | } |
60 | |
61 | static void SerializeOpusIdHeader(uint8_t aChannelCount, uint16_t aPreskip, |
62 | uint32_t aInputSampleRate, |
63 | nsTArray<uint8_t>* aOutput) { |
64 | // The magic signature, null terminator has to be stripped off from strings. |
65 | constexpr uint8_t magic[] = "OpusHead"; |
66 | aOutput->AppendElements(magic, sizeof(magic) - 1); |
67 | |
68 | // The version must always be 1 (8 bits, unsigned). |
69 | aOutput->AppendElement(1); |
70 | |
71 | // Number of output channels (8 bits, unsigned). |
72 | aOutput->AppendElement(aChannelCount); |
73 | |
74 | // Number of samples (at 48 kHz) to discard from the decoder output when |
75 | // starting playback (16 bits, unsigned, little endian). |
76 | SerializeToBuffer(aPreskip, aOutput); |
77 | |
78 | // The sampling rate of input source (32 bits, unsigned, little endian). |
79 | SerializeToBuffer(aInputSampleRate, aOutput); |
80 | |
81 | // Output gain, an encoder should set this field to zero (16 bits, signed, |
82 | // little endian). |
83 | SerializeToBuffer((int16_t)0, aOutput); |
84 | |
85 | // Channel mapping family. Family 0 allows only 1 or 2 channels (8 bits, |
86 | // unsigned). |
87 | aOutput->AppendElement(0); |
88 | } |
89 | |
90 | static void SerializeOpusCommentHeader(const nsCString& aVendor, |
91 | const nsTArray<nsCString>& aComments, |
92 | nsTArray<uint8_t>* aOutput) { |
93 | // The magic signature, null terminator has to be stripped off. |
94 | constexpr uint8_t magic[] = "OpusTags"; |
95 | aOutput->AppendElements(magic, sizeof(magic) - 1); |
96 | |
97 | // The vendor; Should append in the following order: |
98 | // vendor string length (32 bits, unsigned, little endian) |
99 | // vendor string. |
100 | SerializeToBuffer(aVendor, aOutput); |
101 | |
102 | // Add comments; Should append in the following order: |
103 | // comment list length (32 bits, unsigned, little endian) |
104 | // comment #0 string length (32 bits, unsigned, little endian) |
105 | // comment #0 string |
106 | // comment #1 string length (32 bits, unsigned, little endian) |
107 | // comment #1 string ... |
108 | SerializeToBuffer((uint32_t)aComments.Length(), aOutput); |
109 | for (uint32_t i = 0; i < aComments.Length(); ++i) { |
110 | SerializeToBuffer(aComments[i], aOutput); |
111 | } |
112 | } |
113 | |
114 | bool IsSampleRateSupported(TrackRate aSampleRate) { |
115 | // According to www.opus-codec.org, creating an opus encoder requires the |
116 | // sampling rate of source signal be one of 8000, 12000, 16000, 24000, or |
117 | // 48000. If this constraint is not satisfied, we resample the input to 48kHz. |
118 | AutoTArray<int, 5> supportedSamplingRates; |
119 | supportedSamplingRates.AppendElements( |
120 | kOpusSupportedInputSamplingRates, |
121 | ArrayLength(kOpusSupportedInputSamplingRates)); |
122 | return supportedSamplingRates.Contains(aSampleRate); |
123 | } |
124 | |
125 | } // Anonymous namespace. |
126 | |
127 | OpusTrackEncoder::OpusTrackEncoder(TrackRate aTrackRate, |
128 | MediaQueue<EncodedFrame>& aEncodedDataQueue) |
129 | : AudioTrackEncoder(aTrackRate, aEncodedDataQueue), |
130 | mOutputSampleRate(IsSampleRateSupported(aTrackRate) ? aTrackRate |
131 | : kOpusSamplingRate), |
132 | mEncoder(nullptr), |
133 | mLookahead(0), |
134 | mLookaheadWritten(0), |
135 | mResampler(nullptr), |
136 | mNumOutputFrames(0) {} |
137 | |
138 | OpusTrackEncoder::~OpusTrackEncoder() { |
139 | if (mEncoder) { |
140 | opus_encoder_destroy(mEncoder); |
141 | } |
142 | if (mResampler) { |
143 | speex_resampler_destroymoz_speex_resampler_destroy(mResampler); |
144 | mResampler = nullptr; |
145 | } |
146 | } |
147 | |
148 | nsresult OpusTrackEncoder::Init(int aChannels) { |
149 | NS_ENSURE_TRUE((aChannels <= MAX_SUPPORTED_AUDIO_CHANNELS) && (aChannels > 0),do { if ((__builtin_expect(!!(!((aChannels <= MAX_SUPPORTED_AUDIO_CHANNELS ) && (aChannels > 0))), 0))) { NS_DebugBreak(NS_DEBUG_WARNING , "NS_ENSURE_TRUE(" "(aChannels <= MAX_SUPPORTED_AUDIO_CHANNELS) && (aChannels > 0)" ") failed", nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/dom/media/encoder/OpusTrackEncoder.cpp" , 150); return NS_ERROR_FAILURE; } } while (false) |
150 | NS_ERROR_FAILURE)do { if ((__builtin_expect(!!(!((aChannels <= MAX_SUPPORTED_AUDIO_CHANNELS ) && (aChannels > 0))), 0))) { NS_DebugBreak(NS_DEBUG_WARNING , "NS_ENSURE_TRUE(" "(aChannels <= MAX_SUPPORTED_AUDIO_CHANNELS) && (aChannels > 0)" ") failed", nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/dom/media/encoder/OpusTrackEncoder.cpp" , 150); return NS_ERROR_FAILURE; } } while (false); |
151 | |
152 | // This version of encoder API only support 1 or 2 channels, |
153 | // So set the mChannels less or equal 2 and |
154 | // let InterleaveTrackData downmix pcm data. |
155 | mChannels = aChannels > MAX_CHANNELS ? MAX_CHANNELS : aChannels; |
156 | |
157 | // Reject non-audio sample rates. |
158 | NS_ENSURE_TRUE(mTrackRate >= 8000, NS_ERROR_INVALID_ARG)do { if ((__builtin_expect(!!(!(mTrackRate >= 8000)), 0))) { NS_DebugBreak(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "mTrackRate >= 8000" ") failed", nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/dom/media/encoder/OpusTrackEncoder.cpp" , 158); return NS_ERROR_INVALID_ARG; } } while (false); |
159 | NS_ENSURE_TRUE(mTrackRate <= 192000, NS_ERROR_INVALID_ARG)do { if ((__builtin_expect(!!(!(mTrackRate <= 192000)), 0) )) { NS_DebugBreak(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "mTrackRate <= 192000" ") failed", nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/dom/media/encoder/OpusTrackEncoder.cpp" , 159); return NS_ERROR_INVALID_ARG; } } while (false); |
160 | |
161 | if (NeedsResampler()) { |
162 | int error; |
163 | mResampler = speex_resampler_initmoz_speex_resampler_init(mChannels, mTrackRate, kOpusSamplingRate, |
164 | SPEEX_RESAMPLER_QUALITY_DEFAULT4, &error); |
165 | |
166 | if (error != RESAMPLER_ERR_SUCCESS) { |
167 | return NS_ERROR_FAILURE; |
168 | } |
169 | } |
170 | |
171 | int error = 0; |
172 | mEncoder = opus_encoder_create(mOutputSampleRate, mChannels, |
173 | OPUS_APPLICATION_AUDIO2049, &error); |
174 | |
175 | if (error != OPUS_OK0) { |
176 | return NS_ERROR_FAILURE; |
177 | } |
178 | |
179 | if (mAudioBitrate) { |
180 | int bps = static_cast<int>( |
181 | std::min<uint32_t>(mAudioBitrate, std::numeric_limits<int>::max())); |
182 | error = opus_encoder_ctl(mEncoder, OPUS_SET_BITRATE(bps)4002, (((void)((bps) == (opus_int32)0)), (opus_int32)(bps))); |
183 | if (error != OPUS_OK0) { |
184 | return NS_ERROR_FAILURE; |
185 | } |
186 | } |
187 | |
188 | // In the case of Opus we need to calculate the codec delay based on the |
189 | // pre-skip. For more information see: |
190 | // https://tools.ietf.org/html/rfc7845#section-4.2 |
191 | error = opus_encoder_ctl(mEncoder, OPUS_GET_LOOKAHEAD(&mLookahead)4027, ((&mLookahead) + ((&mLookahead) - (opus_int32*) (&mLookahead)))); |
192 | if (error != OPUS_OK0) { |
193 | mLookahead = 0; |
194 | return NS_ERROR_FAILURE; |
195 | } |
196 | |
197 | SetInitialized(); |
198 | |
199 | return NS_OK; |
200 | } |
201 | |
202 | int OpusTrackEncoder::GetLookahead() const { |
203 | return mLookahead * kOpusSamplingRate / mOutputSampleRate; |
204 | } |
205 | |
206 | int OpusTrackEncoder::NumInputFramesPerPacket() const { |
207 | return mTrackRate * kFrameDurationMs / 1000; |
208 | } |
209 | |
210 | int OpusTrackEncoder::NumOutputFramesPerPacket() const { |
211 | return mOutputSampleRate * kFrameDurationMs / 1000; |
212 | } |
213 | |
214 | bool OpusTrackEncoder::NeedsResampler() const { |
215 | // A resampler is needed when mTrackRate is not supported by the opus encoder. |
216 | // This is equivalent to !IsSampleRateSupported(mTrackRate) but less cycles. |
217 | return mTrackRate != mOutputSampleRate && |
218 | mOutputSampleRate == kOpusSamplingRate; |
219 | } |
220 | |
221 | already_AddRefed<TrackMetadataBase> OpusTrackEncoder::GetMetadata() { |
222 | AUTO_PROFILER_LABEL("OpusTrackEncoder::GetMetadata", OTHER)mozilla::AutoProfilerLabel raiiObject222( "OpusTrackEncoder::GetMetadata" , nullptr, JS::ProfilingCategoryPair::OTHER); |
223 | |
224 | MOZ_ASSERT(mInitialized)do { static_assert( mozilla::detail::AssertionConditionType< decltype(mInitialized)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(mInitialized))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("mInitialized", "/var/lib/jenkins/workspace/firefox-scan-build/dom/media/encoder/OpusTrackEncoder.cpp" , 224); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mInitialized" ")"); do { *((volatile int*)__null) = 224; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
225 | |
226 | if (!mInitialized) { |
227 | return nullptr; |
228 | } |
229 | |
230 | RefPtr<OpusMetadata> meta = new OpusMetadata(); |
231 | meta->mChannels = mChannels; |
232 | meta->mSamplingFrequency = mTrackRate; |
233 | |
234 | // Ogg and Webm timestamps are always sampled at 48k for Opus. |
235 | SerializeOpusIdHeader(mChannels, |
236 | mLookahead * (kOpusSamplingRate / mOutputSampleRate), |
237 | mTrackRate, &meta->mIdHeader); |
238 | |
239 | nsCString vendor; |
240 | vendor.AppendASCII(opus_get_version_string()); |
241 | |
242 | nsTArray<nsCString> comments; |
243 | comments.AppendElement( |
244 | nsLiteralCString("ENCODER=Mozilla" MOZ_APP_UA_VERSION"132.0a1")); |
245 | |
246 | SerializeOpusCommentHeader(vendor, comments, &meta->mCommentHeader); |
247 | |
248 | return meta.forget(); |
249 | } |
250 | |
251 | nsresult OpusTrackEncoder::Encode(AudioSegment* aSegment) { |
252 | AUTO_PROFILER_LABEL("OpusTrackEncoder::Encode", OTHER)mozilla::AutoProfilerLabel raiiObject252( "OpusTrackEncoder::Encode" , nullptr, JS::ProfilingCategoryPair::OTHER); |
253 | |
254 | MOZ_ASSERT(aSegment)do { static_assert( mozilla::detail::AssertionConditionType< decltype(aSegment)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(aSegment))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("aSegment", "/var/lib/jenkins/workspace/firefox-scan-build/dom/media/encoder/OpusTrackEncoder.cpp" , 254); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aSegment" ")" ); do { *((volatile int*)__null) = 254; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
255 | MOZ_ASSERT(mInitialized || mCanceled)do { static_assert( mozilla::detail::AssertionConditionType< decltype(mInitialized || mCanceled)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(mInitialized || mCanceled))) , 0))) { do { } while (false); MOZ_ReportAssertionFailure("mInitialized || mCanceled" , "/var/lib/jenkins/workspace/firefox-scan-build/dom/media/encoder/OpusTrackEncoder.cpp" , 255); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mInitialized || mCanceled" ")"); do { *((volatile int*)__null) = 255; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
256 | |
257 | if (mCanceled || IsEncodingComplete()) { |
258 | return NS_ERROR_FAILURE; |
259 | } |
260 | |
261 | if (!mInitialized) { |
262 | // calculation below depends on the truth that mInitialized is true. |
263 | return NS_ERROR_FAILURE; |
264 | } |
265 | |
266 | int result = 0; |
267 | // Loop until we run out of packets of input data |
268 | while (result >= 0 && !IsEncodingComplete()) { |
269 | // re-sampled frames left last time which didn't fit into an Opus packet |
270 | // duration. |
271 | const int framesLeft = mResampledLeftover.Length() / mChannels; |
272 | MOZ_ASSERT(NumOutputFramesPerPacket() >= framesLeft)do { static_assert( mozilla::detail::AssertionConditionType< decltype(NumOutputFramesPerPacket() >= framesLeft)>::isValid , "invalid assertion condition"); if ((__builtin_expect(!!(!( !!(NumOutputFramesPerPacket() >= framesLeft))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("NumOutputFramesPerPacket() >= framesLeft" , "/var/lib/jenkins/workspace/firefox-scan-build/dom/media/encoder/OpusTrackEncoder.cpp" , 272); AnnotateMozCrashReason("MOZ_ASSERT" "(" "NumOutputFramesPerPacket() >= framesLeft" ")"); do { *((volatile int*)__null) = 272; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
273 | // Fetch input frames such that there will be n frames where (n + |
274 | // framesLeft) >= NumOutputFramesPerPacket() after re-sampling. |
275 | const int framesToFetch = NumInputFramesPerPacket() - |
276 | (framesLeft * mTrackRate / kOpusSamplingRate) + |
277 | (NeedsResampler() ? 1 : 0); |
278 | |
279 | if (!mEndOfStream && aSegment->GetDuration() < framesToFetch) { |
280 | // Not enough raw data |
281 | return NS_OK; |
282 | } |
283 | |
284 | // Start encoding data. |
285 | AutoTArray<AudioDataValue, 9600> pcm; |
286 | pcm.SetLength(NumOutputFramesPerPacket() * mChannels); |
287 | |
288 | int frameCopied = 0; |
289 | |
290 | for (AudioSegment::ChunkIterator iter(*aSegment); |
291 | !iter.IsEnded() && frameCopied < framesToFetch; iter.Next()) { |
292 | AudioChunk chunk = *iter; |
293 | |
294 | // Chunk to the required frame size. |
295 | TrackTime frameToCopy = |
296 | std::min(chunk.GetDuration(), |
297 | static_cast<TrackTime>(framesToFetch - frameCopied)); |
298 | |
299 | // Possible greatest value of framesToFetch = 3844: see |
300 | // https://bugzilla.mozilla.org/show_bug.cgi?id=1349421#c8. frameToCopy |
301 | // should not be able to exceed this value. |
302 | MOZ_ASSERT(frameToCopy <= 3844, "frameToCopy exceeded expected range")do { static_assert( mozilla::detail::AssertionConditionType< decltype(frameToCopy <= 3844)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(frameToCopy <= 3844))), 0 ))) { do { } while (false); MOZ_ReportAssertionFailure("frameToCopy <= 3844" " (" "frameToCopy exceeded expected range" ")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/media/encoder/OpusTrackEncoder.cpp" , 302); AnnotateMozCrashReason("MOZ_ASSERT" "(" "frameToCopy <= 3844" ") (" "frameToCopy exceeded expected range" ")"); do { *((volatile int*)__null) = 302; __attribute__((nomerge)) ::abort(); } while (false); } } while (false); |
303 | |
304 | if (!chunk.IsNull()) { |
305 | // Append the interleaved data to the end of pcm buffer. |
306 | AudioTrackEncoder::InterleaveTrackData( |
307 | chunk, frameToCopy, mChannels, |
308 | pcm.Elements() + frameCopied * mChannels); |
309 | } else { |
310 | CheckedInt<int> memsetLength = |
311 | CheckedInt<int>(frameToCopy) * mChannels * sizeof(AudioDataValue); |
312 | if (!memsetLength.isValid()) { |
313 | // This should never happen, but we use a defensive check because |
314 | // we really don't want a bad memset |
315 | MOZ_ASSERT_UNREACHABLE("memsetLength invalid!")do { static_assert( mozilla::detail::AssertionConditionType< decltype(false)>::isValid, "invalid assertion condition"); if ((__builtin_expect(!!(!(!!(false))), 0))) { do { } while ( false); MOZ_ReportAssertionFailure("false" " (" "MOZ_ASSERT_UNREACHABLE: " "memsetLength invalid!" ")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/media/encoder/OpusTrackEncoder.cpp" , 315); AnnotateMozCrashReason("MOZ_ASSERT" "(" "false" ") (" "MOZ_ASSERT_UNREACHABLE: " "memsetLength invalid!" ")"); do { *((volatile int*)__null) = 315; __attribute__((nomerge)) ::abort (); } while (false); } } while (false); |
316 | return NS_ERROR_FAILURE; |
317 | } |
318 | memset(pcm.Elements() + frameCopied * mChannels, 0, |
319 | memsetLength.value()); |
320 | } |
321 | |
322 | frameCopied += frameToCopy; |
323 | } |
324 | |
325 | // Possible greatest value of framesToFetch = 3844: see |
326 | // https://bugzilla.mozilla.org/show_bug.cgi?id=1349421#c8. frameCopied |
327 | // should not be able to exceed this value. |
328 | MOZ_ASSERT(frameCopied <= 3844, "frameCopied exceeded expected range")do { static_assert( mozilla::detail::AssertionConditionType< decltype(frameCopied <= 3844)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(frameCopied <= 3844))), 0 ))) { do { } while (false); MOZ_ReportAssertionFailure("frameCopied <= 3844" " (" "frameCopied exceeded expected range" ")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/media/encoder/OpusTrackEncoder.cpp" , 328); AnnotateMozCrashReason("MOZ_ASSERT" "(" "frameCopied <= 3844" ") (" "frameCopied exceeded expected range" ")"); do { *((volatile int*)__null) = 328; __attribute__((nomerge)) ::abort(); } while (false); } } while (false); |
329 | |
330 | int framesInPCM = frameCopied; |
331 | if (mResampler) { |
332 | AutoTArray<AudioDataValue, 9600> resamplingDest; |
333 | uint32_t inframes = frameCopied; |
334 | uint32_t outframes = inframes * kOpusSamplingRate / mTrackRate + 1; |
335 | |
336 | // We want to consume all the input data, so we slightly oversize the |
337 | // resampled data buffer so we can fit the output data in. We cannot |
338 | // really predict the output frame count at each call. |
339 | resamplingDest.SetLength(outframes * mChannels); |
340 | |
341 | float* in = reinterpret_cast<float*>(pcm.Elements()); |
342 | float* out = reinterpret_cast<float*>(resamplingDest.Elements()); |
343 | speex_resampler_process_interleaved_floatmoz_speex_resampler_process_interleaved_float(mResampler, in, &inframes, out, |
344 | &outframes); |
345 | |
346 | MOZ_ASSERT(pcm.Length() >= mResampledLeftover.Length())do { static_assert( mozilla::detail::AssertionConditionType< decltype(pcm.Length() >= mResampledLeftover.Length())>:: isValid, "invalid assertion condition"); if ((__builtin_expect (!!(!(!!(pcm.Length() >= mResampledLeftover.Length()))), 0 ))) { do { } while (false); MOZ_ReportAssertionFailure("pcm.Length() >= mResampledLeftover.Length()" , "/var/lib/jenkins/workspace/firefox-scan-build/dom/media/encoder/OpusTrackEncoder.cpp" , 346); AnnotateMozCrashReason("MOZ_ASSERT" "(" "pcm.Length() >= mResampledLeftover.Length()" ")"); do { *((volatile int*)__null) = 346; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
347 | PodCopy(pcm.Elements(), mResampledLeftover.Elements(), |
348 | mResampledLeftover.Length()); |
349 | |
350 | uint32_t outframesToCopy = std::min( |
351 | outframes, |
352 | static_cast<uint32_t>(NumOutputFramesPerPacket() - framesLeft)); |
353 | |
354 | MOZ_ASSERT(pcm.Length() - mResampledLeftover.Length() >=do { static_assert( mozilla::detail::AssertionConditionType< decltype(pcm.Length() - mResampledLeftover.Length() >= outframesToCopy * mChannels)>::isValid, "invalid assertion condition"); if ((__builtin_expect(!!(!(!!(pcm.Length() - mResampledLeftover .Length() >= outframesToCopy * mChannels))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("pcm.Length() - mResampledLeftover.Length() >= outframesToCopy * mChannels" , "/var/lib/jenkins/workspace/firefox-scan-build/dom/media/encoder/OpusTrackEncoder.cpp" , 355); AnnotateMozCrashReason("MOZ_ASSERT" "(" "pcm.Length() - mResampledLeftover.Length() >= outframesToCopy * mChannels" ")"); do { *((volatile int*)__null) = 355; __attribute__((nomerge )) ::abort(); } while (false); } } while (false) |
355 | outframesToCopy * mChannels)do { static_assert( mozilla::detail::AssertionConditionType< decltype(pcm.Length() - mResampledLeftover.Length() >= outframesToCopy * mChannels)>::isValid, "invalid assertion condition"); if ((__builtin_expect(!!(!(!!(pcm.Length() - mResampledLeftover .Length() >= outframesToCopy * mChannels))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("pcm.Length() - mResampledLeftover.Length() >= outframesToCopy * mChannels" , "/var/lib/jenkins/workspace/firefox-scan-build/dom/media/encoder/OpusTrackEncoder.cpp" , 355); AnnotateMozCrashReason("MOZ_ASSERT" "(" "pcm.Length() - mResampledLeftover.Length() >= outframesToCopy * mChannels" ")"); do { *((volatile int*)__null) = 355; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
356 | PodCopy(pcm.Elements() + mResampledLeftover.Length(), |
357 | resamplingDest.Elements(), outframesToCopy * mChannels); |
358 | int frameLeftover = outframes - outframesToCopy; |
359 | mResampledLeftover.SetLength(frameLeftover * mChannels); |
360 | PodCopy(mResampledLeftover.Elements(), |
361 | resamplingDest.Elements() + outframesToCopy * mChannels, |
362 | mResampledLeftover.Length()); |
363 | // This is always at 48000Hz. |
364 | framesInPCM = framesLeft + outframesToCopy; |
365 | } |
366 | |
367 | // Remove the raw data which has been pulled to pcm buffer. |
368 | // The value of frameCopied should be equal to (or smaller than, if eos) |
369 | // NumOutputFramesPerPacket(). |
370 | aSegment->RemoveLeading(frameCopied); |
371 | |
372 | // Has reached the end of input stream and all queued data has pulled for |
373 | // encoding. |
374 | bool isFinalPacket = false; |
375 | if (aSegment->GetDuration() == 0 && mEndOfStream && |
376 | framesInPCM < NumOutputFramesPerPacket()) { |
377 | // Pad |mLookahead| samples to the end of the track to prevent loss of |
378 | // original data. |
379 | const int toWrite = std::min(mLookahead - mLookaheadWritten, |
380 | NumOutputFramesPerPacket() - framesInPCM); |
381 | PodZero(pcm.Elements() + framesInPCM * mChannels, toWrite * mChannels); |
382 | mLookaheadWritten += toWrite; |
383 | framesInPCM += toWrite; |
384 | if (mLookaheadWritten == mLookahead) { |
385 | isFinalPacket = true; |
386 | } |
387 | } |
388 | |
389 | MOZ_ASSERT_IF(!isFinalPacket, framesInPCM == NumOutputFramesPerPacket())do { if (!isFinalPacket) { do { static_assert( mozilla::detail ::AssertionConditionType<decltype(framesInPCM == NumOutputFramesPerPacket ())>::isValid, "invalid assertion condition"); if ((__builtin_expect (!!(!(!!(framesInPCM == NumOutputFramesPerPacket()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("framesInPCM == NumOutputFramesPerPacket()" , "/var/lib/jenkins/workspace/firefox-scan-build/dom/media/encoder/OpusTrackEncoder.cpp" , 389); AnnotateMozCrashReason("MOZ_ASSERT" "(" "framesInPCM == NumOutputFramesPerPacket()" ")"); do { *((volatile int*)__null) = 389; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); } } while ( false); |
390 | |
391 | // Append null data to pcm buffer if the leftover data is not enough for |
392 | // opus encoder. |
393 | if (framesInPCM < NumOutputFramesPerPacket() && isFinalPacket) { |
394 | PodZero(pcm.Elements() + framesInPCM * mChannels, |
395 | (NumOutputFramesPerPacket() - framesInPCM) * mChannels); |
396 | } |
397 | auto frameData = MakeRefPtr<EncodedFrame::FrameData>(); |
398 | // Encode the data with Opus Encoder. |
399 | frameData->SetLength(MAX_DATA_BYTES); |
400 | // result is returned as opus error code if it is negative. |
401 | result = 0; |
Value stored to 'result' is never read | |
402 | const float* pcmBuf = static_cast<float*>(pcm.Elements()); |
403 | result = opus_encode_float(mEncoder, pcmBuf, NumOutputFramesPerPacket(), |
404 | frameData->Elements(), MAX_DATA_BYTES); |
405 | frameData->SetLength(result >= 0 ? result : 0); |
406 | |
407 | if (result < 0) { |
408 | LOG("[Opus] Fail to encode data! Result: %s.", opus_strerror(result)); |
409 | } |
410 | if (isFinalPacket) { |
411 | if (mResampler) { |
412 | speex_resampler_destroymoz_speex_resampler_destroy(mResampler); |
413 | mResampler = nullptr; |
414 | } |
415 | mResampledLeftover.SetLength(0); |
416 | } |
417 | |
418 | // timestamp should be the time of the first sample |
419 | mEncodedDataQueue.Push(MakeAndAddRef<EncodedFrame>( |
420 | media::TimeUnit(mNumOutputFrames + mLookahead, mOutputSampleRate), |
421 | static_cast<uint64_t>(framesInPCM) * kOpusSamplingRate / |
422 | mOutputSampleRate, |
423 | kOpusSamplingRate, EncodedFrame::OPUS_AUDIO_FRAME, |
424 | std::move(frameData))); |
425 | |
426 | mNumOutputFrames += NumOutputFramesPerPacket(); |
427 | LOG("[Opus] mOutputTimeStamp %.3f.", |
428 | media::TimeUnit(mNumOutputFrames, mOutputSampleRate).ToSeconds()); |
429 | |
430 | if (isFinalPacket) { |
431 | LOG("[Opus] Done encoding."); |
432 | mEncodedDataQueue.Finish(); |
433 | } |
434 | } |
435 | |
436 | return result >= 0 ? NS_OK : NS_ERROR_FAILURE; |
437 | } |
438 | |
439 | } // namespace mozilla |
440 | |
441 | #undef LOG |