Modified: trunk/LayoutTests/ChangeLog (282195 => 282196)
--- trunk/LayoutTests/ChangeLog 2021-09-09 07:01:12 UTC (rev 282195)
+++ trunk/LayoutTests/ChangeLog 2021-09-09 07:02:21 UTC (rev 282196)
@@ -1,3 +1,14 @@
+2021-09-09 Jean-Yves Avenard <[email protected]>
+
+ [WebAudio/WebM] Incorrect number of frames returned if decoding frame rate doesn't match original
+ https://bugs.webkit.org/show_bug.cgi?id=229251
+ rdar://problem/82095650
+
+ Reviewed by Eric Carlson.
+
+ * webaudio/decode-audio-data-webm-opus-resample-expected.txt: Added.
+ * webaudio/decode-audio-data-webm-opus-resample.html: Added.
+
2021-09-07 Tim Nguyen <[email protected]>
Re-import css/css-pseudo WPT
Modified: trunk/LayoutTests/platform/mac/TestExpectations (282195 => 282196)
--- trunk/LayoutTests/platform/mac/TestExpectations 2021-09-09 07:01:12 UTC (rev 282195)
+++ trunk/LayoutTests/platform/mac/TestExpectations 2021-09-09 07:02:21 UTC (rev 282196)
@@ -1712,6 +1712,7 @@
[ Catalina Mojave BigSur ] media/media-source/media-webm-opus-partial.html [ Skip ]
[ Catalina Mojave BigSur ] media/media-source/media-webm-opus-partial-abort.html [ Skip ]
[ Catalina Mojave BigSur ] webaudio/decode-audio-data-webm-opus.html [ Skip ]
+[ Catalina Mojave BigSur ] webaudio/decode-audio-data-webm-opus-resample.html [ Skip ]
[ Catalina Mojave BigSur ] webaudio/decode-audio-data-webm-vorbis.html [ Skip ]
webkit.org/b/214422 imported/w3c/web-platform-tests/webaudio/the-audio-api/the-audiocontext-interface/suspend-after-construct.html [ Pass Failure ]
Added: trunk/LayoutTests/webaudio/decode-audio-data-webm-opus-resample-expected.txt (0 => 282196)
--- trunk/LayoutTests/webaudio/decode-audio-data-webm-opus-resample-expected.txt (rev 0)
+++ trunk/LayoutTests/webaudio/decode-audio-data-webm-opus-resample-expected.txt 2021-09-09 07:02:21 UTC (rev 282196)
@@ -0,0 +1,11 @@
+Test that decoding an opus webm file with resampling succeeds
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS Successfully decoded content
+PASS Decoding returned the right number of frames.
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
Added: trunk/LayoutTests/webaudio/decode-audio-data-webm-opus-resample.html (0 => 282196)
--- trunk/LayoutTests/webaudio/decode-audio-data-webm-opus-resample.html (rev 0)
+++ trunk/LayoutTests/webaudio/decode-audio-data-webm-opus-resample.html 2021-09-09 07:02:21 UTC (rev 282196)
@@ -0,0 +1,36 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script src=""
+<script type="text/_javascript_" src=""
+</head>
+<body>
+<script>
+description("Test that decoding an opus webm file with resampling succeeds");
+
+window.jsTestIsAsync = true;
+
+var context = new window.AudioContext({ sampleRate: 44100 });
+var request = new XMLHttpRequest();
+request.open("GET", 'resources/media/opus.webm', true);
+request.responseType = "arraybuffer";
+
+request._onload_ = function() {
+ context.decodeAudioData(request.response, (buffer) => {
+ testPassed("Successfully decoded content");
+ // File is exactly 1-0.0065s long @ 48000Hz, so 47688 frames, after resampling it should be 47688/48000*44100 = 43813.
+ if (buffer.length === 43813)
+ testPassed("Decoding returned the right number of frames.");
+ else
+ testFailed("Decoding returned the wrong number of frames: " + buffer.length);
+ finishJSTest();
+ }, () => {
+ testFailed("Failed to decode file");
+ finishJSTest();
+ });
+}
+request.send();
+
+</script>
+</body>
+</html>
Modified: trunk/Source/WebCore/ChangeLog (282195 => 282196)
--- trunk/Source/WebCore/ChangeLog 2021-09-09 07:01:12 UTC (rev 282195)
+++ trunk/Source/WebCore/ChangeLog 2021-09-09 07:02:21 UTC (rev 282196)
@@ -1,3 +1,18 @@
+2021-09-09 Jean-Yves Avenard <[email protected]>
+
+ [WebAudio/WebM] Incorrect number of frames returned if decoding frame rate doesn't match original
+ https://bugs.webkit.org/show_bug.cgi?id=229251
+ rdar://problem/82095650
+
+ Reviewed by Eric Carlson..
+
+ We can't rely on CoreMedia to performed the trimming correctly when resampling is also to be done.
+ It gives unexpected results. Let's do it ourselves instead.
+ Test: webaudio/decode-audio-data-webm-opus-resample.html
+
+ * platform/audio/cocoa/AudioFileReaderCocoa.cpp:
+ (WebCore::AudioFileReader::decodeWebMData const):
+
2021-09-08 Youenn Fablet <[email protected]>
RTCPeerConnection.addIceCandidate takes an optional argument
Modified: trunk/Source/WebCore/platform/audio/cocoa/AudioFileReaderCocoa.cpp (282195 => 282196)
--- trunk/Source/WebCore/platform/audio/cocoa/AudioFileReaderCocoa.cpp 2021-09-09 07:01:12 UTC (rev 282195)
+++ trunk/Source/WebCore/platform/audio/cocoa/AudioFileReaderCocoa.cpp 2021-09-09 07:02:21 UTC (rev 282196)
@@ -318,12 +318,6 @@
if (magicCookie && magicCookieSize)
PAL::AudioConverterSetProperty(converter, kAudioConverterDecompressionMagicCookie, magicCookieSize, magicCookie);
- AudioConverterPrimeInfo primeInfo = { UInt32(m_webmData->m_track->codecDelay().value_or(MediaTime()).toDouble() * outFormat.mSampleRate), 0 };
- INFO_LOG(LOGIDENTIFIER, "Will drop %u leading frames out of %llu", primeInfo.leadingFrames, numberOfFrames);
- PAL::AudioConverterSetProperty(converter, kAudioConverterPrimeInfo, sizeof(primeInfo), &primeInfo);
- UInt32 primeMethod = kConverterPrimeMethod_None;
- PAL::AudioConverterSetProperty(converter, kAudioConverterPrimeMethod, sizeof(primeMethod), &primeMethod);
-
AudioBufferListHolder decodedBufferList(inFormat.mChannelsPerFrame);
if (!decodedBufferList) {
RELEASE_LOG_FAULT(WebAudio, "Unable to create decoder");
@@ -330,7 +324,20 @@
return { };
}
+ // Instruct the decoder to not drop any frames
+ // (by default the Opus decoder assumes that SampleRate / 400 frames are to be dropped.
+ AudioConverterPrimeInfo primeInfo = { 0, 0 };
+ PAL::AudioConverterSetProperty(converter, kAudioConverterPrimeInfo, sizeof(primeInfo), &primeInfo);
+ UInt32 primeMethod = kConverterPrimeMethod_None;
+ PAL::AudioConverterSetProperty(converter, kAudioConverterPrimeMethod, sizeof(primeMethod), &primeMethod);
+
+ uint32_t leadingTrim = m_webmData->m_track->codecDelay().value_or(MediaTime::zeroTime()).toDouble() * outFormat.mSampleRate;
+ // Calculate the number of trailing frames to be trimmed by rounding to nearest integer while minimizing cummulative rounding errors.
+ uint32_t trailingTrim = (m_webmData->m_track->codecDelay().value_or(MediaTime::zeroTime()) + m_webmData->m_track->discardPadding().value_or(MediaTime::zeroTime())).toDouble() * outFormat.mSampleRate - leadingTrim + 0.5;
+ INFO_LOG(LOGIDENTIFIER, "Will drop ", leadingTrim, " leading and ", trailingTrim, " trailing frames out of ", numberOfFrames);
+
size_t decodedFrames = 0;
+ size_t totalDecodedFrames = 0;
OSStatus status;
for (size_t i = 0; i < m_webmData->m_samples.size(); i++) {
auto& sample = m_webmData->m_samples[i];
@@ -357,12 +364,14 @@
do {
if (numberOfFrames < decodedFrames) {
- RELEASE_LOG_FAULT(WebAudio, "Decoded more frames than first calculated");
+ RELEASE_LOG_FAULT(WebAudio, "Decoded more frames than first calculated, no available space left");
return { };
}
// in: the max number of packets we can handle from the decoder.
// out: the number of packets the decoder is actually returning.
- UInt32 numFrames = std::min<uint32_t>(std::numeric_limits<int32_t>::max() / sizeof(float), numberOfFrames - decodedFrames);
+ // The AudioConverter will sometimes pad with trailing silence if we set the free space to what it actually is (numberOfFrames - decodedFrames).
+ // So we set it to what there is left to decode instead.
+ UInt32 numFrames = std::min<uint32_t>(std::numeric_limits<int32_t>::max() / sizeof(float), numberOfFrames - totalDecodedFrames);
for (UInt32 i = 0; i < inFormat.mChannelsPerFrame; i++) {
decodedBufferList->mBuffers[i].mNumberChannels = 1;
@@ -374,12 +383,19 @@
RELEASE_LOG_FAULT(WebAudio, "Error decoding data");
return { };
}
+ totalDecodedFrames += numFrames;
+ if (leadingTrim > 0) {
+ UInt32 toTrim = std::min(leadingTrim, numFrames);
+ for (UInt32 i = 0; i < outFormat.mChannelsPerFrame; i++)
+ memcpy(decodedBufferList->mBuffers[i].mData, static_cast<float*>(decodedBufferList->mBuffers[i].mData) + toTrim, (numFrames - toTrim) * sizeof(float));
+ leadingTrim -= toTrim;
+ numFrames -= toTrim;
+ }
decodedFrames += numFrames;
} while (status != kNoMoreDataErr && status != noErr);
}
- size_t paddingFrames = m_webmData->m_track->discardPadding().value_or(MediaTime()).toDouble() * outFormat.mSampleRate;
- if (decodedFrames > paddingFrames)
- return decodedFrames - paddingFrames;
+ if (decodedFrames > trailingTrim)
+ return decodedFrames - trailingTrim;
return 0;
}
#endif