Changeset 280584 in webkit
- Timestamp:
- Aug 2, 2021, 9:21:47 PM (5 years ago)
- Location:
- trunk
- Files:
-
- 10 edited
-
LayoutTests/ChangeLog (modified) (1 diff)
-
LayoutTests/webaudio/decode-audio-data-webm-opus-expected.txt (modified) (1 diff)
-
LayoutTests/webaudio/decode-audio-data-webm-opus.html (modified) (2 diffs)
-
Source/WebCore/ChangeLog (modified) (1 diff)
-
Source/WebCore/html/HTMLMediaElement.cpp (modified) (1 diff)
-
Source/WebCore/platform/audio/cocoa/AudioFileReaderCocoa.cpp (modified) (10 diffs)
-
Source/WebCore/platform/graphics/cocoa/AudioTrackPrivateWebM.cpp (modified) (1 diff)
-
Source/WebCore/platform/graphics/cocoa/AudioTrackPrivateWebM.h (modified) (1 diff)
-
Source/WebCore/platform/graphics/cocoa/SourceBufferParserWebM.cpp (modified) (5 diffs)
-
Source/WebCore/platform/graphics/cocoa/SourceBufferParserWebM.h (modified) (5 diffs)
Legend:
- Unmodified
- Added
- Removed
-
trunk/LayoutTests/ChangeLog
r280582 r280584 1 2021-08-02 Jean-Yves Avenard <jya@apple.com> 2 3 https://bugs.webkit.org/show_bug.cgi?id=228140 4 rdar://problem/80883882 5 6 Reviewed by Eric Carlson. 7 8 https://bugs.webkit.org/show_bug.cgi?id=228140 9 10 * webaudio/decode-audio-data-webm-opus-expected.txt: 11 * webaudio/decode-audio-data-webm-opus.html: 12 1 13 2021-08-02 Chris Dumez <cdumez@apple.com> 2 14 -
trunk/LayoutTests/webaudio/decode-audio-data-webm-opus-expected.txt
r280416 r280584 5 5 6 6 PASS Successfully decoded content 7 PASS Decoding returned the right number of frames. 7 8 PASS successfullyParsed is true 8 9 -
trunk/LayoutTests/webaudio/decode-audio-data-webm-opus.html
r280416 r280584 11 11 window.jsTestIsAsync = true; 12 12 13 var context = new window.AudioContext( );13 var context = new window.AudioContext({ sampleRate: 48000 }); 14 14 var request = new XMLHttpRequest(); 15 15 request.open("GET", 'resources/media/opus.webm', true); … … 19 19 context.decodeAudioData(request.response, (buffer) => { 20 20 testPassed("Successfully decoded content"); 21 // File is exactly 1-0.0065s long @ 48000Hz, so 47688 frames. 22 if (buffer.length === 47688) 23 testPassed("Decoding returned the right number of frames."); 24 else 25 testFailed("Decoding returned the wrong number of frames: " + buffer.length); 21 26 finishJSTest(); 22 27 }, () => { -
trunk/Source/WebCore/ChangeLog
r280582 r280584 1 2021-08-02 Jean-Yves Avenard <jya@apple.com> 2 3 [WebAudio] webm; properly trim frames according to the codec delay information 4 https://bugs.webkit.org/show_bug.cgi?id=228140 5 rdar://problem/80883882 6 7 Reviewed by Eric Carlson. 8 9 Add frame-perfect decoding for Opus and Vorbis in WebM container. 10 Unfortunately, due to a vorbis decoder bug, it is not possible to test that 11 vorbis decoding returns the right number of frames. 12 Amend Opus test to ensure the right amount of frames are returned. 13 14 * platform/audio/cocoa/AudioFileReaderCocoa.cpp: 15 (WebCore::AudioFileReader::demuxWebMData const): 16 (WebCore::passthroughInputDataCallback): AudioToolbox internal logging could overflow 17 if we used packet descriptions with offsets, so we take the most commonly used scenario 18 where we have a single packet to decode at a time. 19 (WebCore::AudioFileReader::decodeWebMData const): 20 * platform/graphics/cocoa/AudioTrackPrivateWebM.cpp: 21 (WebCore::AudioTrackPrivateWebM::codecDelay const): 22 (WebCore::AudioTrackPrivateWebM::setDiscardPadding): 23 (WebCore::AudioTrackPrivateWebM::discardPadding const): 24 * platform/graphics/cocoa/AudioTrackPrivateWebM.h: 25 * platform/graphics/cocoa/SourceBufferParserWebM.cpp: 26 (WebCore::SourceBufferParserWebM::OnElementEnd): Fly-by, ensure m_didParseInitializationDataCallback 27 only ever accessed on client thread. 28 (WebCore::SourceBufferParserWebM::OnBlockGroupEnd): 29 * platform/graphics/cocoa/SourceBufferParserWebM.h: Add trimming data callback. 30 Only mark WEBCORE_EXPORT the methods that need it. 31 (WebCore::SourceBufferParserWebM::appendData): 32 (WebCore::SourceBufferParserWebM::setDidParseTrimmingDataCallback): 33 * html/HTMLMediaElement.cpp: 34 (WebCore::HTMLMediaElement::canPlayType const): Make canPlayType(webm/audio; codecs=vorbis) 35 returns maybe if feature flag set. 36 37 1 38 2021-08-02 Chris Dumez <cdumez@apple.com> 2 39 -
trunk/Source/WebCore/html/HTMLMediaElement.cpp
r280531 r280584 1071 1071 // so that sites relying on this test to determine if webaudio use of opus or vorbis won't error. 1072 1072 auto codecs = contentType.codecs(); 1073 if (support == MediaPlayer::SupportsType::IsSupported && ((codecs.contains("opus") && !webMWebAudioEnabled()) || codecs.contains("vorbis")))1073 if (support == MediaPlayer::SupportsType::IsSupported && ((codecs.contains("opus") || codecs.contains("vorbis")) && !webMWebAudioEnabled())) 1074 1074 support = MediaPlayer::SupportsType::IsNotSupported; 1075 1075 #endif -
trunk/Source/WebCore/platform/audio/cocoa/AudioFileReaderCocoa.cpp
r280416 r280584 36 36 #include "AudioFileReader.h" 37 37 #include "AudioSampleDataSource.h" 38 #include "AudioTrackPrivate .h"38 #include "AudioTrackPrivateWebM.h" 39 39 #include "FloatConversion.h" 40 40 #include "InbandTextTrackPrivate.h" … … 131 131 public: 132 132 #if ENABLE(MEDIA_SOURCE) 133 SourceBufferParserWebM::InitializationSegment m_initSegment;133 Ref<AudioTrackPrivateWebM> m_track; 134 134 #endif 135 135 MediaTime m_duration; … … 185 185 std::optional<uint64_t> audioTrackId; 186 186 MediaTime duration; 187 SourceBufferParserWebM::InitializationSegment initSegment;187 RefPtr<AudioTrackPrivateWebM> track; 188 188 Vector<Ref<MediaSampleAVFObjC>> samples; 189 189 parser->setDidEncounterErrorDuringParsingCallback([&](uint64_t) { … … 195 195 duration = init.duration; 196 196 audioTrackId = audioTrack.track->trackUID(); 197 initSegment = WTFMove(init);197 track = static_pointer_cast<AudioTrackPrivateWebM>(audioTrack.track); 198 198 return; 199 199 } … … 208 208 function(); 209 209 }); 210 parser->setDidParseTrimmingDataCallback([&](uint64_t trackID, const MediaTime& discardPadding) { 211 if (!audioTrackId || !track || trackID != *audioTrackId) 212 return; 213 track->setDiscardPadding(discardPadding); 214 }); 210 215 SourceBufferParser::Segment segment({ data, dataSize }); 211 216 parser->appendData(WTFMove(segment)); 212 if (! audioTrackId)217 if (!track) 213 218 return nullptr; 214 219 parser->flushPendingAudioBuffers(); 215 return makeUnique<AudioFileReaderWebMData>(AudioFileReaderWebMData { WTFMove(initSegment), WTFMove(duration), WTFMove(samples) });220 return makeUnique<AudioFileReaderWebMData>(AudioFileReaderWebMData { track.releaseNonNull(), WTFMove(duration), WTFMove(samples) }); 216 221 } 217 222 218 223 struct PassthroughUserData { 219 UInt32 m_channels; 220 UInt32 m_dataSize; 221 const void* m_data; 224 const UInt32 m_channels; 225 const UInt32 m_dataSize; 226 const char* m_data; 227 const bool m_eos; 228 const Vector<AudioStreamPacketDescription>& m_packets; 222 229 UInt32 m_index; 223 Vector<AudioStreamPacketDescription>& m_packets;230 AudioStreamPacketDescription m_packet; 224 231 }; 225 232 … … 237 244 if (userData->m_index == userData->m_packets.size()) { 238 245 *numDataPackets = 0; 239 return kNoMoreDataErr; 246 return userData->m_eos ? noErr : kNoMoreDataErr; 247 } 248 249 if (userData->m_index >= userData->m_packets.size()) { 250 *numDataPackets = 0; 251 return kAudioConverterErr_RequiresPacketDescriptionsError; 240 252 } 241 253 242 254 if (packetDesc) { 243 if (userData->m_index >= userData->m_packets.size()) { 244 *numDataPackets = 0; 245 return kAudioConverterErr_RequiresPacketDescriptionsError; 246 } 247 *packetDesc = &userData->m_packets[userData->m_index]; 255 userData->m_packet = userData->m_packets[userData->m_index]; 256 userData->m_packet.mStartOffset = 0; 257 *packetDesc = &userData->m_packet; 248 258 } 249 259 250 260 data->mBuffers[0].mNumberChannels = userData->m_channels; 251 data->mBuffers[0].mDataByteSize = userData->m_dataSize; 252 data->mBuffers[0].mData = const_cast<void*>(userData->m_data); 253 261 data->mBuffers[0].mDataByteSize = userData->m_packets[userData->m_index].mDataByteSize; 262 data->mBuffers[0].mData = const_cast<char*>(userData->m_data + userData->m_packets[userData->m_index].mStartOffset); 263 264 // Sanity check 265 if (static_cast<char*>(data->mBuffers[0].mData) + data->mBuffers[0].mDataByteSize > userData->m_data + userData->m_dataSize) { 266 RELEASE_LOG_FAULT(WebAudio, "Nonsensical data structure, aborting"); 267 return kAudioConverterErr_UnspecifiedError; 268 } 254 269 *numDataPackets = 1; 255 270 userData->m_index++; … … 304 319 PAL::AudioConverterSetProperty(converter, kAudioConverterDecompressionMagicCookie, magicCookieSize, magicCookie); 305 320 321 AudioConverterPrimeInfo primeInfo = { UInt32(m_webmData->m_track->codecDelay().value_or(MediaTime()).toDouble() * outFormat.mSampleRate), 0 }; 322 INFO_LOG(LOGIDENTIFIER, "Will drop %u leading frames out of %llu", primeInfo.leadingFrames, numberOfFrames); 323 PAL::AudioConverterSetProperty(converter, kAudioConverterPrimeInfo, sizeof(primeInfo), &primeInfo); 324 UInt32 primeMethod = kConverterPrimeMethod_None; 325 PAL::AudioConverterSetProperty(converter, kAudioConverterPrimeMethod, sizeof(primeMethod), &primeMethod); 326 306 327 AudioBufferListHolder decodedBufferList(inFormat.mChannelsPerFrame); 307 328 if (!decodedBufferList) { … … 312 333 size_t decodedFrames = 0; 313 334 OSStatus status; 314 for (auto& sample : m_webmData->m_samples) { 335 for (size_t i = 0; i < m_webmData->m_samples.size(); i++) { 336 auto& sample = m_webmData->m_samples[i]; 315 337 CMSampleBufferRef sampleBuffer = sample->sampleBuffer(); 316 338 auto buffer = PAL::CMSampleBufferGetDataBuffer(sampleBuffer); … … 332 354 return { }; 333 355 334 PassthroughUserData userData = { inFormat.mChannelsPerFrame, UInt32(srcSize), srcData, 0, descriptions};356 PassthroughUserData userData = { inFormat.mChannelsPerFrame, UInt32(srcSize), srcData, i == m_webmData->m_samples.size() - 1, descriptions, 0, { } }; 335 357 336 358 do { … … 354 376 } 355 377 decodedFrames += numFrames; 356 } while (status != kNoMoreDataErr); 357 } 358 return decodedFrames; 378 } while (status != kNoMoreDataErr && status != noErr); 379 } 380 size_t paddingFrames = m_webmData->m_track->discardPadding().value_or(MediaTime()).toDouble() * outFormat.mSampleRate; 381 if (decodedFrames > paddingFrames) 382 return decodedFrames - paddingFrames; 383 return 0; 359 384 } 360 385 #endif -
trunk/Source/WebCore/platform/graphics/cocoa/AudioTrackPrivateWebM.cpp
r278253 r280584 87 87 } 88 88 89 std::optional<MediaTime> AudioTrackPrivateWebM::codecDelay() const 90 { 91 if (!m_track.codec_delay.is_present()) 92 return { }; 93 constexpr uint32_t k_us_in_seconds = 1000000000; 94 return MediaTime(m_track.codec_delay.value(), k_us_in_seconds); 95 } 96 97 void AudioTrackPrivateWebM::setDiscardPadding(const MediaTime& discardPadding) 98 { 99 m_discardPadding = discardPadding; 100 } 101 102 std::optional<MediaTime> AudioTrackPrivateWebM::discardPadding() const 103 { 104 if (m_discardPadding.isInvalid() || m_discardPadding < MediaTime()) 105 return { }; 106 return m_discardPadding; 107 } 108 89 109 } 90 110 -
trunk/Source/WebCore/platform/graphics/cocoa/AudioTrackPrivateWebM.h
r278253 r280584 44 44 std::optional<uint64_t> trackUID() const final; 45 45 std::optional<bool> defaultEnabled() const final; 46 std::optional<MediaTime> codecDelay() const; 47 void setDiscardPadding(const MediaTime&); 48 std::optional<MediaTime> discardPadding() const; 46 49 47 50 private: 48 51 AudioTrackPrivateWebM(webm::TrackEntry&&); 49 52 webm::TrackEntry m_track; 53 MediaTime m_discardPadding { MediaTime::invalidTime() }; 50 54 mutable AtomString m_trackID; 51 55 mutable AtomString m_label; -
trunk/Source/WebCore/platform/graphics/cocoa/SourceBufferParserWebM.cpp
r279904 r280584 265 265 constexpr CMVideoCodecType kCMVideoCodecType_VP9 { 'vp09' }; 266 266 267 constexpr uint32_t k_us_in_seconds = 1000000000; 268 267 269 static bool isWebmParserAvailable() 268 270 { … … 780 782 } 781 783 782 if (m_initializationSegmentEncountered && m_didParseInitializationDataCallback) {784 if (m_initializationSegmentEncountered) { 783 785 m_callOnClientThreadCallback([this, protectedThis = makeRef(*this), initializationSegment = WTFMove(*m_initializationSegment)]() mutable { 784 m_didParseInitializationDataCallback(WTFMove(initializationSegment)); 786 if (m_didParseInitializationDataCallback) 787 m_didParseInitializationDataCallback(WTFMove(initializationSegment)); 785 788 }); 786 789 } … … 848 851 849 852 auto timecodeScale = info.timecode_scale.is_present() ? info.timecode_scale.value() : 1000000; 850 m_timescale = 1000000000/ timecodeScale;853 m_timescale = k_us_in_seconds / timecodeScale; 851 854 m_initializationSegment->duration = info.duration.is_present() ? MediaTime(info.duration.value(), m_timescale) : MediaTime::indefiniteTime(); 852 855 … … 1024 1027 { 1025 1028 UNUSED_PARAM(metadata); 1026 UNUSED_PARAM(blockGroup);1027 1029 INFO_LOG_IF_POSSIBLE(LOGIDENTIFIER); 1030 if (blockGroup.block.is_present() && blockGroup.discard_padding.is_present()) { 1031 auto trackNumber = blockGroup.block.value().track_number; 1032 auto* trackData = trackDataForTrackNumber(trackNumber); 1033 if (!trackData) { 1034 ERROR_LOG_IF_POSSIBLE(LOGIDENTIFIER, "Ignoring unknown track number ", trackNumber); 1035 return Status(Status::kOkCompleted); 1036 } 1037 if (trackData->track().track_uid.is_present() && blockGroup.discard_padding.value() > 0) { 1038 m_callOnClientThreadCallback([this, protectedThis = makeRef(*this), trackID = trackData->track().track_uid.value(), padding = MediaTime(blockGroup.discard_padding.value(), k_us_in_seconds)]() { 1039 if (m_didParseTrimmingDataCallback) 1040 m_didParseTrimmingDataCallback(trackID, padding); 1041 }); 1042 } 1043 } 1028 1044 return Status(Status::kOkCompleted); 1029 1045 } … … 1213 1229 uint64_t duration = 0; 1214 1230 if (track.default_duration.is_present()) 1215 duration = track.default_duration.value() * presentationTime.timescale / 1000000000;1231 duration = track.default_duration.value() * presentationTime.timescale / k_us_in_seconds; 1216 1232 1217 1233 CMSampleBufferRef rawSampleBuffer = nullptr; -
trunk/Source/WebCore/platform/graphics/cocoa/SourceBufferParserWebM.h
r279904 r280584 56 56 class MediaSampleAVFObjC; 57 57 58 class WEBCORE_EXPORTSourceBufferParserWebM : public SourceBufferParser, private webm::Callback {58 class SourceBufferParserWebM : public SourceBufferParser, private webm::Callback { 59 59 WTF_MAKE_FAST_ALLOCATED; 60 60 public: … … 64 64 static MediaPlayerEnums::SupportsType isContentTypeSupported(const ContentType&); 65 65 static const HashSet<String, ASCIICaseInsensitiveHash>& webmMIMETypes(); 66 static RefPtr<SourceBufferParserWebM> create(const ContentType&);66 WEBCORE_EXPORT static RefPtr<SourceBufferParserWebM> create(const ContentType&); 67 67 68 68 SourceBufferParserWebM(); … … 74 74 75 75 Type type() const { return Type::WebM; } 76 void appendData(Segment&&, CompletionHandler<void()>&& = [] { }, AppendFlags = AppendFlags::None) final;76 WEBCORE_EXPORT void appendData(Segment&&, CompletionHandler<void()>&& = [] { }, AppendFlags = AppendFlags::None) final; 77 77 void flushPendingMediaData() final; 78 78 void setShouldProvideMediaDataForTrackID(bool, uint64_t) final; … … 84 84 void setMinimumAudioSampleDuration(float); 85 85 86 void setLogger(const WTF::Logger&, const void* identifier) final;86 WEBCORE_EXPORT void setLogger(const WTF::Logger&, const void* identifier) final; 87 87 88 88 void provideMediaData(RetainPtr<CMSampleBufferRef>, uint64_t, std::optional<size_t> byteRangeOffset); 89 using DidParseTrimmingDataCallback = WTF::Function<void(uint64_t trackID, const MediaTime& discardPadding)>; 90 void setDidParseTrimmingDataCallback(DidParseTrimmingDataCallback&& callback) 91 { 92 m_didParseTrimmingDataCallback = WTFMove(callback); 93 } 89 94 90 95 enum class ErrorCode : int32_t { … … 288 293 const void* m_logIdentifier { nullptr }; 289 294 uint64_t m_nextChildIdentifier { 0 }; 295 DidParseTrimmingDataCallback m_didParseTrimmingDataCallback; 290 296 }; 291 297
Note:
See TracChangeset
for help on using the changeset viewer.