Title: [282196] trunk
Revision
282196
Author
[email protected]
Date
2021-09-09 00:02:21 -0700 (Thu, 09 Sep 2021)

Log Message

[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

Source/WebCore:

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):

LayoutTests:

Reviewed by Eric Carlson.

* webaudio/decode-audio-data-webm-opus-resample-expected.txt: Added.
* webaudio/decode-audio-data-webm-opus-resample.html: Added.

Modified Paths

Added Paths

Diff

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
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to