Bug Summary

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

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-pc-linux-gnu -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name Unified_cpp_dom_media_encoder0.cpp -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=cplusplus -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -analyzer-config-compatibility-mode=true -mrelocation-model pic -pic-level 2 -fhalf-no-semantic-interposition -mframe-pointer=all -relaxed-aliasing -ffp-contract=off -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -fdebug-compilation-dir=/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dom/media/encoder -fcoverage-compilation-dir=/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dom/media/encoder -resource-dir /usr/lib/llvm-18/lib/clang/18 -include /var/lib/jenkins/workspace/firefox-scan-build/config/gcc_hidden.h -include /var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/mozilla-config.h -I /var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/stl_wrappers -I /var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/system_wrappers -U _FORTIFY_SOURCE -D _FORTIFY_SOURCE=2 -D DEBUG=1 -D MOZ_HAS_MOZGLUE -D MOZILLA_INTERNAL_API -D IMPL_LIBXUL -D STATIC_EXPORTABLE_JS_API -I /var/lib/jenkins/workspace/firefox-scan-build/dom/media/encoder -I /var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dom/media/encoder -I /var/lib/jenkins/workspace/firefox-scan-build/dom/media -I /var/lib/jenkins/workspace/firefox-scan-build/ipc/chromium/src -I /var/lib/jenkins/workspace/firefox-scan-build/media/libyuv/libyuv/include -I /var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/ipc/ipdl/_ipdlheaders -I /var/lib/jenkins/workspace/firefox-scan-build/ipc/chromium/src -I /var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include -I /var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/nspr -I /var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/nss -D MOZILLA_CLIENT -internal-isystem /usr/bin/../lib/gcc/x86_64-linux-gnu/13/../../../../include/c++/13 -internal-isystem /usr/bin/../lib/gcc/x86_64-linux-gnu/13/../../../../include/x86_64-linux-gnu/c++/13 -internal-isystem /usr/bin/../lib/gcc/x86_64-linux-gnu/13/../../../../include/c++/13/backward -internal-isystem /usr/lib/llvm-18/lib/clang/18/include -internal-isystem /usr/local/include -internal-isystem /usr/bin/../lib/gcc/x86_64-linux-gnu/13/../../../../x86_64-linux-gnu/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -O2 -Wno-error=tautological-type-limit-compare -Wno-invalid-offsetof -Wno-range-loop-analysis -Wno-deprecated-anon-enum-enum-conversion -Wno-deprecated-enum-enum-conversion -Wno-deprecated-this-capture -Wno-inline-new-delete -Wno-error=deprecated-declarations -Wno-error=array-bounds -Wno-error=free-nonheap-object -Wno-error=atomic-alignment -Wno-error=deprecated-builtins -Wno-psabi -Wno-error=builtin-macro-redefined -Wno-vla-cxx-extension -Wno-unknown-warning-option -Wno-error=attributes -fdeprecated-macro -ferror-limit 19 -stack-protector 2 -fstack-clash-protection -ftrivial-auto-var-init=pattern -fno-rtti -fgnuc-version=4.2.1 -fno-aligned-allocation -vectorize-loops -vectorize-slp -analyzer-checker optin.performance.Padding -analyzer-output=html -analyzer-config stable-report-filename=true -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /tmp/scan-build-2024-05-16-034744-15991-1 -x c++ Unified_cpp_dom_media_encoder0.cpp
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
15namespace 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.
20constexpr 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.
24constexpr int MAX_CHANNELS = 2;
25
26// A maximum data bytes for Opus to encode.
27constexpr 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."
32constexpr int kOpusSamplingRate = 48000;
33
34// The duration of an Opus frame, and it must be 2.5, 5, 10, 20, 40 or 60 ms.
35constexpr 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.
39constexpr int kOpusSupportedInputSamplingRates[] = {8000, 12000, 16000, 24000,
40 48000};
41
42namespace {
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.
46template <typename T>
47static 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
53static 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
61static 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
90static 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
114bool 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
127OpusTrackEncoder::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
138OpusTrackEncoder::~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
148nsresult 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
202int OpusTrackEncoder::GetLookahead() const {
203 return mLookahead * kOpusSamplingRate / mOutputSampleRate;
204}
205
206int OpusTrackEncoder::NumInputFramesPerPacket() const {
207 return mTrackRate * kFrameDurationMs / 1000;
208}
209
210int OpusTrackEncoder::NumOutputFramesPerPacket() const {
211 return mOutputSampleRate * kFrameDurationMs / 1000;
212}
213
214bool 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
221already_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"128.0a1"));
245
246 SerializeOpusCommentHeader(vendor, comments, &meta->mCommentHeader);
247
248 return meta.forget();
249}
250
251nsresult 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