Changeset 255345 in webkit
- Timestamp:
- Jan 29, 2020 2:02:38 AM (4 years ago)
- Location:
- trunk
- Files:
-
- 8 added
- 13 edited
- 1 copied
Legend:
- Unmodified
- Added
- Removed
-
trunk/LayoutTests/ChangeLog
r255342 r255345 1 2020-01-29 youenn fablet <youenn@apple.com> 2 3 [Cocoa] Use AVAssetWriterDelegate to implement MediaRecorder 4 https://bugs.webkit.org/show_bug.cgi?id=206582 5 6 Reviewed by Eric Carlson. 7 8 * http/wpt/mediarecorder/MediaRecorder-AV-audio-video-dataavailable-gpuprocess.html: 9 Remove web audio generation since there seems to be some unstability in web audio -> stream -> media recorder. 10 which should be fixed as follow-up specific patches. 11 1 12 2020-01-28 Carlos Garcia Campos <cgarcia@igalia.com> 2 13 -
trunk/LayoutTests/http/wpt/mediarecorder/MediaRecorder-AV-audio-video-dataavailable-gpuprocess.html
r254256 r255345 57 57 58 58 async_test(t => { 59 const ac = new AudioContext();60 const osc = ac.createOscillator();61 const dest = ac.createMediaStreamDestination();62 const audio = dest.stream;63 osc.connect(dest);64 65 59 const video = createVideoStream(); 66 assert_equals(video.getAudioTracks().length, 0, "video mediastream starts with no audio track");67 assert_equals(audio.getAudioTracks().length, 1, "audio mediastream starts with one audio track");68 video.addTrack(audio.getAudioTracks()[0]);69 assert_equals(video.getAudioTracks().length, 1, "video mediastream starts with one audio track");70 60 const recorder = new MediaRecorder(video); 71 61 let mode = 0; -
trunk/Source/WebCore/ChangeLog
r255342 r255345 1 2020-01-29 youenn fablet <youenn@apple.com> 2 3 [Cocoa] Use AVAssetWriterDelegate to implement MediaRecorder 4 https://bugs.webkit.org/show_bug.cgi?id=206582 5 6 Reviewed by Eric Carlson. 7 8 AVAssetWriterDelegate allows to grab recorded data whenever wanted. 9 This delegate requires passing compressed samples to AVAssetWriter. 10 Implement video encoding and audio encoding in dedicated classes and use these classes before adding buffers to AVAssetWriter. 11 Since AVAssetWriterDelegate is Apple SDK only, keep the existing file based implementation as a fallback. 12 13 Covered by existing tests. 14 15 * platform/mediarecorder/cocoa/AudioSampleBufferCompressor.h: 16 * platform/mediarecorder/cocoa/AudioSampleBufferCompressor.mm: 17 (WebCore::AudioSampleBufferCompressor::create): 18 (WebCore::AudioSampleBufferCompressor::AudioSampleBufferCompressor): 19 (WebCore::AudioSampleBufferCompressor::~AudioSampleBufferCompressor): 20 (WebCore::AudioSampleBufferCompressor::initialize): 21 (WebCore::AudioSampleBufferCompressor::finish): 22 (WebCore::AudioSampleBufferCompressor::audioConverterComplexInputDataProc): 23 (WebCore::AudioSampleBufferCompressor::initAudioConverterForSourceFormatDescription): 24 (WebCore::AudioSampleBufferCompressor::computeBufferSizeForAudioFormat): 25 (WebCore::AudioSampleBufferCompressor::attachPrimingTrimsIfNeeded): 26 (WebCore::AudioSampleBufferCompressor::gradualDecoderRefreshCount): 27 (WebCore::AudioSampleBufferCompressor::sampleBufferWithNumPackets): 28 (WebCore::AudioSampleBufferCompressor::processSampleBuffersUntilLowWaterTime): 29 (WebCore::AudioSampleBufferCompressor::provideSourceDataNumOutputPackets): 30 (WebCore::AudioSampleBufferCompressor::processSampleBuffer): 31 (WebCore::AudioSampleBufferCompressor::addSampleBuffer): 32 (WebCore::AudioSampleBufferCompressor::getOutputSampleBuffer): 33 (WebCore::AudioSampleBufferCompressor::takeOutputSampleBuffer): 34 * platform/mediarecorder/cocoa/MediaRecorderPrivateWriterCocoa.h: 35 * platform/mediarecorder/cocoa/MediaRecorderPrivateWriterCocoa.mm: 36 (WebCore::MediaRecorderPrivateWriter::create): 37 (WebCore::MediaRecorderPrivateWriter::MediaRecorderPrivateWriter): 38 (WebCore::MediaRecorderPrivateWriter::initialize): 39 (WebCore::MediaRecorderPrivateWriter::processNewCompressedVideoSampleBuffers): 40 (WebCore::MediaRecorderPrivateWriter::processNewCompressedAudioSampleBuffers): 41 (WebCore::MediaRecorderPrivateWriter::appendCompressedAudioSampleBuffer): 42 (WebCore::MediaRecorderPrivateWriter::appendCompressedVideoSampleBuffer): 43 (WebCore::MediaRecorderPrivateWriter::appendVideoSampleBuffer): 44 (WebCore::MediaRecorderPrivateWriter::appendAudioSampleBuffer): 45 (WebCore::MediaRecorderPrivateWriter::stopRecording): 46 * platform/mediarecorder/cocoa/VideoSampleBufferCompressor.h: 47 * platform/mediarecorder/cocoa/VideoSampleBufferCompressor.mm: 48 (WebCore::VideoSampleBufferCompressor::create): 49 (WebCore::VideoSampleBufferCompressor::VideoSampleBufferCompressor): 50 (WebCore::VideoSampleBufferCompressor::~VideoSampleBufferCompressor): 51 (WebCore::VideoSampleBufferCompressor::initialize): 52 (WebCore::VideoSampleBufferCompressor::finish): 53 (WebCore::VideoSampleBufferCompressor::videoCompressionCallback): 54 (WebCore::VideoSampleBufferCompressor::initCompressionSession): 55 (WebCore::VideoSampleBufferCompressor::processSampleBuffer): 56 (WebCore::VideoSampleBufferCompressor::addSampleBuffer): 57 (WebCore::VideoSampleBufferCompressor::getOutputSampleBuffer): 58 (WebCore::VideoSampleBufferCompressor::takeOutputSampleBuffer): 59 1 60 2020-01-28 Carlos Garcia Campos <cgarcia@igalia.com> 2 61 -
trunk/Source/WebCore/PAL/ChangeLog
r255049 r255345 1 2020-01-29 youenn fablet <youenn@apple.com> 2 3 [Cocoa] Use AVAssetWriterDelegate to implement MediaRecorder 4 https://bugs.webkit.org/show_bug.cgi?id=206582 5 6 Reviewed by Eric Carlson. 7 8 Add soft link macros for VideoToolbox and AudioToolbox. 9 10 * PAL.xcodeproj/project.pbxproj: 11 * pal/cf/AudioToolboxSoftLink.cpp: Added. 12 * pal/cf/AudioToolboxSoftLink.h: Added. 13 * pal/cf/CoreMediaSoftLink.cpp: 14 * pal/cf/CoreMediaSoftLink.h: 15 * pal/cf/VideoToolboxSoftLink.cpp: Added. 16 * pal/cf/VideoToolboxSoftLink.h: Added. 17 1 18 2020-01-22 Darin Adler <darin@apple.com> 2 19 -
trunk/Source/WebCore/PAL/PAL.xcodeproj/project.pbxproj
r253834 r255345 116 116 2E1342CD215AA10A007199D2 /* UIKitSoftLink.mm in Sources */ = {isa = PBXBuildFile; fileRef = 2E1342CB215AA10A007199D2 /* UIKitSoftLink.mm */; }; 117 117 31308B1420A21705003FB929 /* SystemPreviewSPI.h in Headers */ = {isa = PBXBuildFile; fileRef = 31308B1320A21705003FB929 /* SystemPreviewSPI.h */; }; 118 416E995323DAE6BE00E871CB /* AudioToolboxSoftLink.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 416E995123DAE6BD00E871CB /* AudioToolboxSoftLink.cpp */; }; 119 416E995423DAE6BE00E871CB /* AudioToolboxSoftLink.h in Headers */ = {isa = PBXBuildFile; fileRef = 416E995223DAE6BE00E871CB /* AudioToolboxSoftLink.h */; }; 120 416E995723DAEFF800E871CB /* VideoToolboxSoftLink.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 416E995523DAEFF700E871CB /* VideoToolboxSoftLink.cpp */; }; 121 416E995823DAEFF800E871CB /* VideoToolboxSoftLink.h in Headers */ = {isa = PBXBuildFile; fileRef = 416E995623DAEFF700E871CB /* VideoToolboxSoftLink.h */; }; 118 122 442956CD218A72DF0080DB54 /* RevealSPI.h in Headers */ = {isa = PBXBuildFile; fileRef = 442956CC218A72DE0080DB54 /* RevealSPI.h */; }; 119 123 4450FC9F21F5F602004DFA56 /* QuickLookSoftLink.mm in Sources */ = {isa = PBXBuildFile; fileRef = 4450FC9D21F5F602004DFA56 /* QuickLookSoftLink.mm */; }; … … 292 296 31308B1320A21705003FB929 /* SystemPreviewSPI.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SystemPreviewSPI.h; sourceTree = "<group>"; }; 293 297 37119A7820CCB5FF002C6DC9 /* WebKitTargetConditionals.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = WebKitTargetConditionals.xcconfig; sourceTree = "<group>"; }; 298 416E995123DAE6BD00E871CB /* AudioToolboxSoftLink.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = AudioToolboxSoftLink.cpp; sourceTree = "<group>"; }; 299 416E995223DAE6BE00E871CB /* AudioToolboxSoftLink.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AudioToolboxSoftLink.h; sourceTree = "<group>"; }; 300 416E995523DAEFF700E871CB /* VideoToolboxSoftLink.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = VideoToolboxSoftLink.cpp; sourceTree = "<group>"; }; 301 416E995623DAEFF700E871CB /* VideoToolboxSoftLink.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = VideoToolboxSoftLink.h; sourceTree = "<group>"; }; 294 302 442956CC218A72DE0080DB54 /* RevealSPI.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RevealSPI.h; sourceTree = "<group>"; }; 295 303 4450FC9D21F5F602004DFA56 /* QuickLookSoftLink.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = QuickLookSoftLink.mm; sourceTree = "<group>"; }; … … 525 533 isa = PBXGroup; 526 534 children = ( 535 416E995123DAE6BD00E871CB /* AudioToolboxSoftLink.cpp */, 536 416E995223DAE6BE00E871CB /* AudioToolboxSoftLink.h */, 527 537 0CF99CA61F738436007EE793 /* CoreMediaSoftLink.cpp */, 528 538 0CF99CA71F738437007EE793 /* CoreMediaSoftLink.h */, 539 416E995523DAEFF700E871CB /* VideoToolboxSoftLink.cpp */, 540 416E995623DAEFF700E871CB /* VideoToolboxSoftLink.h */, 529 541 ); 530 542 path = cf; … … 716 728 57FD318B22B35989008D0E8B /* AppSSOSoftLink.h in Headers */, 717 729 576CA9D622B854AB0030143C /* AppSSOSPI.h in Headers */, 730 416E995423DAE6BE00E871CB /* AudioToolboxSoftLink.h in Headers */, 718 731 2D02E93C2056FAA700A13797 /* AudioToolboxSPI.h in Headers */, 719 732 572A107822B456F500F410C8 /* AuthKitSPI.h in Headers */, … … 839 852 0C5AF9221F43A4C7002EAC02 /* UIKitSPI.h in Headers */, 840 853 0C2DA1471F3BEB4900DBC317 /* URLFormattingSPI.h in Headers */, 854 416E995823DAEFF800E871CB /* VideoToolboxSoftLink.h in Headers */, 841 855 0C2DA1591F3BEB4900DBC317 /* WebFilterEvaluatorSPI.h in Headers */, 842 856 A10826F91F576292004772AC /* WebPanel.h in Headers */, … … 931 945 files = ( 932 946 57FD318A22B3593E008D0E8B /* AppSSOSoftLink.mm in Sources */, 947 416E995323DAE6BE00E871CB /* AudioToolboxSoftLink.cpp in Sources */, 933 948 077E87B1226A460200A2AFF0 /* AVFoundationSoftLink.mm in Sources */, 934 949 0C5FFF0F1F78D9DA009EFF1A /* ClockCM.mm in Sources */, … … 957 972 A3AB6E651F3D217F009C14B1 /* SystemSleepListenerMac.mm in Sources */, 958 973 2E1342CD215AA10A007199D2 /* UIKitSoftLink.mm in Sources */, 974 416E995723DAEFF800E871CB /* VideoToolboxSoftLink.cpp in Sources */, 959 975 A10826FA1F576292004772AC /* WebPanel.mm in Sources */, 960 976 ); -
trunk/Source/WebCore/PAL/pal/cf/CoreMediaSoftLink.cpp
r240332 r255345 47 47 SOFT_LINK_FUNCTION_FOR_SOURCE(PAL, CoreMedia, CMBlockBufferCopyDataBytes, OSStatus, (CMBlockBufferRef theSourceBuffer, size_t offsetToData, size_t dataLength, void* destination), (theSourceBuffer, offsetToData, dataLength, destination)) 48 48 SOFT_LINK_FUNCTION_FOR_SOURCE(PAL, CoreMedia, CMBlockBufferGetDataLength, size_t, (CMBlockBufferRef theBuffer), (theBuffer)) 49 SOFT_LINK_FUNCTION_FOR_SOURCE(PAL, CoreMedia, CMBlockBufferReplaceDataBytes, OSStatus, (const void* sourceBytes, CMBlockBufferRef destinationBuffer, size_t offsetIntoDestination, size_t dataLength), (sourceBytes, destinationBuffer, offsetIntoDestination, dataLength)) 49 50 SOFT_LINK_FUNCTION_FOR_SOURCE(PAL, CoreMedia, CMFormatDescriptionGetExtensions, CFDictionaryRef, (CMFormatDescriptionRef desc), (desc)) 50 51 SOFT_LINK_FUNCTION_FOR_SOURCE(PAL, CoreMedia, CMSampleBufferGetTypeID, CFTypeID, (void), ()) … … 137 138 SOFT_LINK_FUNCTION_FOR_SOURCE(PAL, CoreMedia, CMBufferQueueGetEndPresentationTimeStamp, CMTime, (CMBufferQueueRef queue), (queue)) 138 139 SOFT_LINK_FUNCTION_FOR_SOURCE(PAL, CoreMedia, CMBufferQueueInstallTriggerWithIntegerThreshold, OSStatus, (CMBufferQueueRef queue, CMBufferQueueTriggerCallback triggerCallback, void* triggerRefcon, CMBufferQueueTriggerCondition triggerCondition, CMItemCount triggerThreshold, CMBufferQueueTriggerToken* triggerTokenOut), (queue, triggerCallback, triggerRefcon, triggerCondition, triggerThreshold, triggerTokenOut)) 140 SOFT_LINK_FUNCTION_FOR_SOURCE(PAL, CoreMedia, CMBufferQueueMarkEndOfData, OSStatus, (CMBufferQueueRef queue), (queue)) 139 141 140 142 SOFT_LINK_CONSTANT_FOR_SOURCE(PAL, CoreMedia, kCMSampleAttachmentKey_DoNotDisplay, CFStringRef) … … 164 166 SOFT_LINK_FUNCTION_FOR_SOURCE(PAL, CoreMedia, CMSampleBufferSetDataReady, OSStatus, (CMSampleBufferRef sbuf), (sbuf)) 165 167 SOFT_LINK_FUNCTION_FOR_SOURCE(PAL, CoreMedia, CMAudioFormatDescriptionCreate, OSStatus, (CFAllocatorRef allocator, const AudioStreamBasicDescription* asbd, size_t layoutSize, const AudioChannelLayout* layout, size_t magicCookieSize, const void* magicCookie, CFDictionaryRef extensions, CMAudioFormatDescriptionRef* outDesc), (allocator, asbd, layoutSize, layout, magicCookieSize, magicCookie, extensions, outDesc)) 168 SOFT_LINK_FUNCTION_FOR_SOURCE(PAL, CoreMedia, CMAudioFormatDescriptionGetMagicCookie, const void*, (CMAudioFormatDescriptionRef desc, size_t* sizeOut), (desc, sizeOut)) 169 SOFT_LINK_FUNCTION_FOR_SOURCE(PAL, CoreMedia, CMAudioFormatDescriptionGetRichestDecodableFormat, const AudioFormatListItem *, (CMAudioFormatDescriptionRef desc), (desc)) 170 166 171 SOFT_LINK_FUNCTION_FOR_SOURCE(PAL, CoreMedia, CMClockGetHostTimeClock, CMClockRef, (void), ()) 167 172 SOFT_LINK_FUNCTION_FOR_SOURCE(PAL, CoreMedia, CMClockGetTime, CMTime, (CMClockRef clock), (clock)) -
trunk/Source/WebCore/PAL/pal/cf/CoreMediaSoftLink.h
r240332 r255345 50 50 SOFT_LINK_FUNCTION_FOR_HEADER(PAL, CoreMedia, CMBlockBufferGetDataLength, size_t, (CMBlockBufferRef theBuffer), (theBuffer)) 51 51 #define CMBlockBufferGetDataLength softLink_CoreMedia_CMBlockBufferGetDataLength 52 SOFT_LINK_FUNCTION_FOR_HEADER(PAL, CoreMedia, CMBlockBufferReplaceDataBytes, OSStatus, (const void* sourceBytes, CMBlockBufferRef destinationBuffer, size_t offsetIntoDestination, size_t dataLength), (sourceBytes, destinationBuffer, offsetIntoDestination, dataLength)) 53 #define CMBlockBufferReplaceDataBytes softLink_CoreMedia_CMBlockBufferReplaceDataBytes 52 54 SOFT_LINK_FUNCTION_FOR_HEADER(PAL, CoreMedia, CMFormatDescriptionGetExtensions, CFDictionaryRef, (CMFormatDescriptionRef desc), (desc)) 53 55 #define CMFormatDescriptionGetExtensions softLink_CoreMedia_CMFormatDescriptionGetExtensions … … 228 230 SOFT_LINK_FUNCTION_FOR_HEADER(PAL, CoreMedia, CMBufferQueueInstallTriggerWithIntegerThreshold, OSStatus, (CMBufferQueueRef queue, CMBufferQueueTriggerCallback triggerCallback, void* triggerRefcon, CMBufferQueueTriggerCondition triggerCondition, CMItemCount triggerThreshold, CMBufferQueueTriggerToken* triggerTokenOut), (queue, triggerCallback, triggerRefcon, triggerCondition, triggerThreshold, triggerTokenOut)) 229 231 #define CMBufferQueueInstallTriggerWithIntegerThreshold softLink_CoreMedia_CMBufferQueueInstallTriggerWithIntegerThreshold 232 SOFT_LINK_FUNCTION_FOR_HEADER(PAL, CoreMedia, CMBufferQueueMarkEndOfData, OSStatus, (CMBufferQueueRef queue), (queue)) 233 #define CMBufferQueueMarkEndOfData softLink_CoreMedia_CMBufferQueueMarkEndOfData 230 234 231 235 SOFT_LINK_CONSTANT_FOR_HEADER(PAL, CoreMedia, kCMSampleAttachmentKey_DoNotDisplay, CFStringRef) … … 257 261 SOFT_LINK_CONSTANT_FOR_HEADER(PAL, CoreMedia, kCMSampleBufferConsumerNotification_BufferConsumed, CFStringRef) 258 262 #define kCMSampleBufferConsumerNotification_BufferConsumed get_CoreMedia_kCMSampleBufferConsumerNotification_BufferConsumed() 263 264 SOFT_LINK_FUNCTION_FOR_HEADER(PAL, CoreMedia, CMAudioFormatDescriptionGetMagicCookie, const void*, (CMAudioFormatDescriptionRef desc, size_t* sizeOut), (desc, sizeOut)) 265 #define CMAudioFormatDescriptionGetMagicCookie softLink_CoreMedia_CMAudioFormatDescriptionGetMagicCookie 259 266 SOFT_LINK_FUNCTION_FOR_HEADER(PAL, CoreMedia, CMAudioFormatDescriptionGetStreamBasicDescription, const AudioStreamBasicDescription *, (CMAudioFormatDescriptionRef desc), (desc)) 260 267 #define CMAudioFormatDescriptionGetStreamBasicDescription softLink_CoreMedia_CMAudioFormatDescriptionGetStreamBasicDescription … … 265 272 SOFT_LINK_FUNCTION_FOR_HEADER(PAL, CoreMedia, CMSampleBufferGetNumSamples, CMItemCount, (CMSampleBufferRef sbuf), (sbuf)) 266 273 #define CMSampleBufferGetNumSamples softLink_CoreMedia_CMSampleBufferGetNumSamples 274 SOFT_LINK_FUNCTION_FOR_HEADER(PAL, CoreMedia, CMAudioFormatDescriptionGetRichestDecodableFormat, const AudioFormatListItem *, (CMAudioFormatDescriptionRef desc), (desc)) 275 #define CMAudioFormatDescriptionGetRichestDecodableFormat softLink_CoreMedia_CMAudioFormatDescriptionGetRichestDecodableFormat 267 276 SOFT_LINK_FUNCTION_FOR_HEADER(PAL, CoreMedia, CMSampleBufferCopySampleBufferForRange, OSStatus, (CFAllocatorRef allocator, CMSampleBufferRef sbuf, CFRange sampleRange, CMSampleBufferRef* sBufOut), (allocator, sbuf, sampleRange, sBufOut)) 268 277 #define CMSampleBufferCopySampleBufferForRange softLink_CoreMedia_CMSampleBufferCopySampleBufferForRange -
trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj
r255257 r255345 1098 1098 416E6FE91BBD12E5000A6043 /* ReadableStreamBuiltins.h in Headers */ = {isa = PBXBuildFile; fileRef = 9B03D8061BB3110D00B764D8 /* ReadableStreamBuiltins.h */; settings = {ATTRIBUTES = (Private, ); }; }; 1099 1099 416E6FE91BBD12E5000A6053 /* WritableStreamBuiltins.h in Headers */ = {isa = PBXBuildFile; fileRef = 9B03D8061BB3110D00B764E8 /* WritableStreamBuiltins.h */; settings = {ATTRIBUTES = (Private, ); }; }; 1100 416F799023D750CF00829FC1 /* AudioSampleBufferCompressor.mm in Sources */ = {isa = PBXBuildFile; fileRef = 416F798F23D750CB00829FC1 /* AudioSampleBufferCompressor.mm */; }; 1100 1101 417253AB1354BBBC00360F2A /* MediaControlElements.h in Headers */ = {isa = PBXBuildFile; fileRef = 417253A91354BBBC00360F2A /* MediaControlElements.h */; }; 1101 1102 417612AF1E3A994000C3D81D /* LibWebRTCMediaEndpoint.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 417612AB1E3A993B00C3D81D /* LibWebRTCMediaEndpoint.cpp */; }; … … 1138 1139 41BF204922BA7BE80004F812 /* RealtimeVideoSource.h in Headers */ = {isa = PBXBuildFile; fileRef = 41BF204022B947160004F812 /* RealtimeVideoSource.h */; settings = {ATTRIBUTES = (Private, ); }; }; 1139 1140 41C760B10EDE03D300C1655F /* ScriptState.h in Headers */ = {isa = PBXBuildFile; fileRef = 41C760B00EDE03D300C1655F /* ScriptState.h */; settings = {ATTRIBUTES = (Private, ); }; }; 1141 41CD6F8C23D6E82100B16421 /* VideoSampleBufferCompressor.mm in Sources */ = {isa = PBXBuildFile; fileRef = 41CD6F8B23D6E81D00B16421 /* VideoSampleBufferCompressor.mm */; }; 1140 1142 41D015CA0F4B5C71004A662F /* ContentType.h in Headers */ = {isa = PBXBuildFile; fileRef = 41D015C80F4B5C71004A662F /* ContentType.h */; settings = {ATTRIBUTES = (Private, ); }; }; 1141 1143 41D129CE1F3D0EF600D15E47 /* WorkerGlobalScopeCaches.h in Headers */ = {isa = PBXBuildFile; fileRef = 41FB278D1F34C28200795487 /* WorkerGlobalScopeCaches.h */; }; … … 7362 7364 416E0B37209BC3C2004A95D9 /* FetchIdentifier.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FetchIdentifier.h; sourceTree = "<group>"; }; 7363 7365 416E29A5102FA962007FC14E /* WorkerReportingProxy.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WorkerReportingProxy.h; sourceTree = "<group>"; }; 7366 416F798D23D750CA00829FC1 /* AudioSampleBufferCompressor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AudioSampleBufferCompressor.h; sourceTree = "<group>"; }; 7367 416F798F23D750CB00829FC1 /* AudioSampleBufferCompressor.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = AudioSampleBufferCompressor.mm; sourceTree = "<group>"; }; 7368 416F799323D8B69C00829FC1 /* MediaRecorderPrivateWriterCocoaFileBased.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MediaRecorderPrivateWriterCocoaFileBased.mm; sourceTree = "<group>"; }; 7364 7369 4170A2E91D8C0CC000318452 /* JSDOMWrapper.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSDOMWrapper.cpp; sourceTree = "<group>"; }; 7365 7370 417253A81354BBBC00360F2A /* MediaControlElements.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = MediaControlElements.cpp; sourceTree = "<group>"; }; … … 7469 7474 41C7E1061E6A54360027B4DE /* CanvasCaptureMediaStreamTrack.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CanvasCaptureMediaStreamTrack.h; sourceTree = "<group>"; }; 7470 7475 41C7E1081E6AA37C0027B4DE /* CanvasCaptureMediaStreamTrack.idl */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = CanvasCaptureMediaStreamTrack.idl; sourceTree = "<group>"; }; 7476 41CD6F8923D6E81C00B16421 /* VideoSampleBufferCompressor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = VideoSampleBufferCompressor.h; sourceTree = "<group>"; }; 7477 41CD6F8B23D6E81D00B16421 /* VideoSampleBufferCompressor.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = VideoSampleBufferCompressor.mm; sourceTree = "<group>"; }; 7471 7478 41CF8BE41D46222000707DC9 /* FetchBodyConsumer.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = FetchBodyConsumer.cpp; sourceTree = "<group>"; }; 7472 7479 41CF8BE51D46222000707DC9 /* FetchBodyConsumer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FetchBodyConsumer.h; sourceTree = "<group>"; }; … … 18895 18902 isa = PBXGroup; 18896 18903 children = ( 18904 416F798D23D750CA00829FC1 /* AudioSampleBufferCompressor.h */, 18905 416F798F23D750CB00829FC1 /* AudioSampleBufferCompressor.mm */, 18897 18906 4D73F94C218C4A87003A3ED6 /* MediaRecorderPrivateWriterCocoa.h */, 18898 18907 4D73F94D218C4A87003A3ED6 /* MediaRecorderPrivateWriterCocoa.mm */, 18908 416F799323D8B69C00829FC1 /* MediaRecorderPrivateWriterCocoaFileBased.mm */, 18909 41CD6F8923D6E81C00B16421 /* VideoSampleBufferCompressor.h */, 18910 41CD6F8B23D6E81D00B16421 /* VideoSampleBufferCompressor.mm */, 18899 18911 ); 18900 18912 path = cocoa; … … 33547 33559 CD0EEE0E14743F39003EAFA2 /* AudioDestinationIOS.cpp in Sources */, 33548 33560 CD5596911475B678001D0BD0 /* AudioFileReaderIOS.cpp in Sources */, 33561 416F799023D750CF00829FC1 /* AudioSampleBufferCompressor.mm in Sources */, 33549 33562 CDA79827170A279100D45C55 /* AudioSessionIOS.mm in Sources */, 33550 33563 CD8A7BBB197735FE00CBD643 /* AudioSourceProviderAVFObjC.mm in Sources */, … … 34279 34292 3FBC4AF3189881560046EE38 /* VideoFullscreenInterfaceAVKit.mm in Sources */, 34280 34293 52D5A18F1C54592300DE34A3 /* VideoFullscreenLayerManagerObjC.mm in Sources */, 34294 41CD6F8C23D6E82100B16421 /* VideoSampleBufferCompressor.mm in Sources */, 34281 34295 BE88E0DE1715D2A200658D98 /* VideoTrack.cpp in Sources */, 34282 34296 BE88E0E11715D2A200658D98 /* VideoTrackList.cpp in Sources */, -
trunk/Source/WebCore/platform/graphics/cv/ImageTransferSessionVT.mm
r254555 r255345 96 96 }; 97 97 98 98 99 NSDictionary* pixelBufferPoolOptions = @{ 99 100 (__bridge NSString *)kCVPixelBufferPoolMinimumBufferCountKey: @(6) -
trunk/Source/WebCore/platform/mediarecorder/MediaRecorderPrivateAVFImpl.cpp
r254194 r255345 30 30 31 31 #include "AudioStreamDescription.h" 32 #include "MediaRecorderPrivateWriterCocoa.h" 32 33 #include "MediaSample.h" 33 34 #include "MediaStreamPrivate.h" … … 69 70 } 70 71 } 71 auto writer = MediaRecorderPrivateWriter::create(audioTrack, videoTrack); 72 73 int width = 0, height = 0; 74 if (videoTrack) { 75 auto& settings = videoTrack->settings(); 76 width = settings.width(); 77 height = settings.height(); 78 } 79 auto writer = MediaRecorderPrivateWriter::create(!!audioTrack, width, height); 72 80 if (!writer) 73 81 return nullptr; -
trunk/Source/WebCore/platform/mediarecorder/cocoa/MediaRecorderPrivateWriterCocoa.h
r254823 r255345 26 26 27 27 #if ENABLE(MEDIA_STREAM) 28 #include "AudioStreamDescription.h" 28 29 29 30 #include "SharedBuffer.h" … … 35 36 #include <wtf/WeakPtr.h> 36 37 #include <wtf/threads/BinarySemaphore.h> 38 #include <CoreAudio/CoreAudioTypes.h> 39 #include <CoreMedia/CMTime.h> 37 40 38 41 typedef struct opaqueCMSampleBuffer *CMSampleBufferRef; 42 typedef const struct opaqueCMFormatDescription* CMFormatDescriptionRef; 43 typedef struct opaqueCMBufferQueueTriggerToken *CMBufferQueueTriggerToken; 39 44 40 45 OBJC_CLASS AVAssetWriter; 41 46 OBJC_CLASS AVAssetWriterInput; 47 OBJC_CLASS WebAVAssetWriterDelegate; 42 48 43 49 namespace WTF { … … 47 53 namespace WebCore { 48 54 55 class AudioSampleBufferCompressor; 49 56 class AudioStreamDescription; 50 57 class MediaStreamTrackPrivate; 51 58 class PlatformAudioData; 59 class VideoSampleBufferCompressor; 52 60 53 class WEBCORE_EXPORT MediaRecorderPrivateWriter : public ThreadSafeRefCounted<MediaRecorderPrivateWriter, WTF::DestructionThread::Main>, public CanMakeWeakPtr<MediaRecorderPrivateWriter > {61 class WEBCORE_EXPORT MediaRecorderPrivateWriter : public ThreadSafeRefCounted<MediaRecorderPrivateWriter, WTF::DestructionThread::Main>, public CanMakeWeakPtr<MediaRecorderPrivateWriter, WeakPtrFactoryInitialization::Eager> { 54 62 public: 55 static RefPtr<MediaRecorderPrivateWriter> create(const MediaStreamTrackPrivate* audioTrack, const MediaStreamTrackPrivate* videoTrack);56 63 static RefPtr<MediaRecorderPrivateWriter> create(bool hasAudio, int width, int height); 57 64 ~MediaRecorderPrivateWriter(); 58 59 bool setupWriter(); 60 bool setVideoInput(int width, int height); 61 bool setAudioInput(); 65 62 66 void appendVideoSampleBuffer(CMSampleBufferRef); 63 67 void appendAudioSampleBuffer(const PlatformAudioData&, const AudioStreamDescription&, const WTF::MediaTime&, size_t); … … 65 69 void fetchData(CompletionHandler<void(RefPtr<SharedBuffer>&&)>&&); 66 70 71 #if USE(APPLE_INTERNAL_SDK) 72 void appendData(const char*, size_t); 73 void appendData(Ref<SharedBuffer>&&); 74 #endif 75 67 76 private: 77 #if USE(APPLE_INTERNAL_SDK) 78 MediaRecorderPrivateWriter(bool hasAudio, bool hasVideo); 79 void clear(); 80 81 bool initialize(); 82 83 static void compressedVideoOutputBufferCallback(void*, CMBufferQueueTriggerToken); 84 static void compressedAudioOutputBufferCallback(void*, CMBufferQueueTriggerToken); 85 86 void startAssetWriter(); 87 void appendCompressedSampleBuffers(); 88 89 bool appendCompressedAudioSampleBuffer(); 90 bool appendCompressedVideoSampleBuffer(); 91 92 void processNewCompressedAudioSampleBuffers(); 93 void processNewCompressedVideoSampleBuffers(); 94 95 void flushCompressedSampleBuffers(CompletionHandler<void()>&&); 96 void appendEndOfVideoSampleDurationIfNeeded(CompletionHandler<void()>&&); 97 #else 68 98 MediaRecorderPrivateWriter(RetainPtr<AVAssetWriter>&&, String&& path); 69 99 void clear(); 70 100 101 bool setupWriter(); 102 bool setVideoInput(int width, int height); 103 bool setAudioInput(); 104 #endif 105 106 bool m_hasStartedWriting { false }; 107 bool m_isStopped { false }; 108 71 109 RetainPtr<AVAssetWriter> m_writer; 110 111 bool m_isStopping { false }; 112 RefPtr<SharedBuffer> m_data; 113 CompletionHandler<void(RefPtr<SharedBuffer>&&)> m_fetchDataCompletionHandler; 114 115 #if USE(APPLE_INTERNAL_SDK) 116 bool m_hasAudio; 117 bool m_hasVideo; 118 119 RetainPtr<CMFormatDescriptionRef> m_audioFormatDescription; 120 std::unique_ptr<AudioSampleBufferCompressor> m_audioCompressor; 121 RetainPtr<AVAssetWriterInput> m_audioAssetWriterInput; 122 123 RetainPtr<CMFormatDescriptionRef> m_videoFormatDescription; 124 std::unique_ptr<VideoSampleBufferCompressor> m_videoCompressor; 125 RetainPtr<AVAssetWriterInput> m_videoAssetWriterInput; 126 CMTime m_lastVideoPresentationTime; 127 CMTime m_lastVideoDecodingTime; 128 bool m_hasEncodedVideoSamples { false }; 129 130 RetainPtr<WebAVAssetWriterDelegate> m_writerDelegate; 131 #else 72 132 RetainPtr<AVAssetWriterInput> m_videoInput; 73 133 RetainPtr<AVAssetWriterInput> m_audioInput; … … 79 139 BinarySemaphore m_finishWritingAudioSemaphore; 80 140 BinarySemaphore m_finishWritingVideoSemaphore; 81 bool m_hasStartedWriting { false };82 bool m_isStopped { false };83 141 bool m_isFirstAudioSample { true }; 84 142 dispatch_queue_t m_audioPullQueue; … … 87 145 Deque<RetainPtr<CMSampleBufferRef>> m_audioBufferPool; 88 146 89 bool m_isStopping { false }; 90 RefPtr<SharedBuffer> m_data; 91 CompletionHandler<void(RefPtr<SharedBuffer>&&)> m_fetchDataCompletionHandler; 147 #endif 92 148 }; 93 149 -
trunk/Source/WebCore/platform/mediarecorder/cocoa/MediaRecorderPrivateWriterCocoa.mm
r254823 r255345 27 27 #include "MediaRecorderPrivateWriterCocoa.h" 28 28 29 #if !USE(APPLE_INTERNAL_SDK) 30 #include "MediaRecorderPrivateWriterCocoaFileBased.mm" 31 #else 32 29 33 #if ENABLE(MEDIA_STREAM) && USE(AVFOUNDATION) 30 34 35 #include "AudioSampleBufferCompressor.h" 31 36 #include "AudioStreamDescription.h" 32 37 #include "Logging.h" 33 38 #include "MediaStreamTrackPrivate.h" 39 #include "VideoSampleBufferCompressor.h" 34 40 #include "WebAudioBufferList.h" 35 41 #include <AVFoundation/AVAssetWriter.h> 36 42 #include <AVFoundation/AVAssetWriterInput.h> 43 #include <AVFoundation/AVAssetWriter_Private.h> 44 #include <pal/avfoundation/MediaTimeAVFoundation.h> 37 45 #include <pal/cf/CoreMediaSoftLink.h> 46 #include <wtf/BlockPtr.h> 38 47 #include <wtf/CompletionHandler.h> 39 48 #include <wtf/FileSystem.h> 49 #include <wtf/cf/TypeCastsCF.h> 40 50 41 51 #import <pal/cocoa/AVFoundationSoftLink.h> 42 52 43 #undef AVEncoderBitRateKey 44 #define AVEncoderBitRateKey getAVEncoderBitRateKeyWithFallback() 45 #undef AVFormatIDKey 46 #define AVFormatIDKey getAVFormatIDKeyWithFallback() 47 #undef AVNumberOfChannelsKey 48 #define AVNumberOfChannelsKey getAVNumberOfChannelsKeyWithFallback() 49 #undef AVSampleRateKey 50 #define AVSampleRateKey getAVSampleRateKeyWithFallback() 53 @interface WebAVAssetWriterDelegate : NSObject <AVAssetWriterDelegate> { 54 WeakPtr<WebCore::MediaRecorderPrivateWriter> m_writer; 55 } 56 57 - (instancetype)initWithWriter:(WebCore::MediaRecorderPrivateWriter*)writer; 58 - (void)close; 59 - (void)finish; 60 61 @end 62 63 @implementation WebAVAssetWriterDelegate { 64 }; 65 66 - (instancetype)initWithWriter:(WebCore::MediaRecorderPrivateWriter*)writer 67 { 68 ASSERT(isMainThread()); 69 self = [super init]; 70 if (self) 71 self->m_writer = makeWeakPtr(writer); 72 73 return self; 74 } 75 76 - (void)dealloc 77 { 78 [super dealloc]; 79 } 80 81 - (void)assetWriter:(AVAssetWriter *)assetWriter didProduceFragmentedHeaderData:(NSData *)fragmentedHeaderData 82 { 83 UNUSED_PARAM(assetWriter); 84 if (!isMainThread()) { 85 if (auto size = [fragmentedHeaderData length]) { 86 callOnMainThread([protectedSelf = RetainPtr<WebAVAssetWriterDelegate>(self), buffer = WebCore::SharedBuffer::create(static_cast<const char*>([fragmentedHeaderData bytes]), size)]() mutable { 87 if (protectedSelf->m_writer) 88 protectedSelf->m_writer->appendData(WTFMove(buffer)); 89 }); 90 } 91 return; 92 } 93 94 if (m_writer) 95 m_writer->appendData(static_cast<const char*>([fragmentedHeaderData bytes]), [fragmentedHeaderData length]); 96 } 97 98 - (void)assetWriter:(AVAssetWriter *)assetWriter didProduceFragmentedMediaData:(NSData *)fragmentedMediaData fragmentedMediaDataReport:(AVFragmentedMediaDataReport *)fragmentedMediaDataReport 99 { 100 UNUSED_PARAM(assetWriter); 101 UNUSED_PARAM(fragmentedMediaDataReport); 102 if (!isMainThread()) { 103 if (auto size = [fragmentedMediaData length]) { 104 callOnMainThread([protectedSelf = RetainPtr<WebAVAssetWriterDelegate>(self), buffer = WebCore::SharedBuffer::create(static_cast<const char*>([fragmentedMediaData bytes]), size)]() mutable { 105 if (protectedSelf->m_writer) 106 protectedSelf->m_writer->appendData(WTFMove(buffer)); 107 }); 108 } 109 return; 110 } 111 112 if (m_writer) 113 m_writer->appendData(static_cast<const char*>([fragmentedMediaData bytes]), [fragmentedMediaData length]); 114 } 115 116 - (void)close 117 { 118 m_writer = nullptr; 119 } 120 121 - (void)finish 122 { 123 m_writer = nullptr; 124 } 125 126 @end 51 127 52 128 namespace WebCore { … … 54 130 using namespace PAL; 55 131 56 static NSString *getAVFormatIDKeyWithFallback()57 {58 if (PAL::canLoad_AVFoundation_AVFormatIDKey())59 return PAL::get_AVFoundation_AVFormatIDKey();60 61 RELEASE_LOG_ERROR(Media, "Failed to load AVFormatIDKey");62 return @"AVFormatIDKey";63 }64 65 static NSString *getAVNumberOfChannelsKeyWithFallback()66 {67 if (PAL::canLoad_AVFoundation_AVNumberOfChannelsKey())68 return PAL::get_AVFoundation_AVNumberOfChannelsKey();69 70 RELEASE_LOG_ERROR(Media, "Failed to load AVNumberOfChannelsKey");71 return @"AVNumberOfChannelsKey";72 }73 74 static NSString *getAVSampleRateKeyWithFallback()75 {76 if (PAL::canLoad_AVFoundation_AVSampleRateKey())77 return PAL::get_AVFoundation_AVSampleRateKey();78 79 RELEASE_LOG_ERROR(Media, "Failed to load AVSampleRateKey");80 return @"AVSampleRateKey";81 }82 83 static NSString *getAVEncoderBitRateKeyWithFallback()84 {85 if (PAL::canLoad_AVFoundation_AVEncoderBitRateKey())86 return PAL::get_AVFoundation_AVEncoderBitRateKey();87 88 RELEASE_LOG_ERROR(Media, "Failed to load AVEncoderBitRateKey");89 return @"AVEncoderBitRateKey";90 }91 92 RefPtr<MediaRecorderPrivateWriter> MediaRecorderPrivateWriter::create(const MediaStreamTrackPrivate* audioTrack, const MediaStreamTrackPrivate* videoTrack)93 {94 int width = 0, height = 0;95 if (videoTrack) {96 auto& settings = videoTrack->settings();97 width = settings.width();98 height = settings.height();99 }100 return create(!!audioTrack, width, height);101 }102 103 132 RefPtr<MediaRecorderPrivateWriter> MediaRecorderPrivateWriter::create(bool hasAudio, int width, int height) 104 133 { 105 NSString *directory = FileSystem::createTemporaryDirectory(@"videos"); 106 NSString *filename = [NSString stringWithFormat:@"/%lld.mp4", CMClockGetTime(CMClockGetHostTimeClock()).value]; 107 NSString *path = [directory stringByAppendingString:filename]; 108 109 NSURL *outputURL = [NSURL fileURLWithPath:path]; 110 String filePath = [path UTF8String]; 134 auto writer = adoptRef(*new MediaRecorderPrivateWriter(hasAudio, width && height)); 135 if (!writer->initialize()) 136 return nullptr; 137 return writer; 138 } 139 140 void MediaRecorderPrivateWriter::compressedVideoOutputBufferCallback(void *mediaRecorderPrivateWriter, CMBufferQueueTriggerToken) 141 { 142 auto *writer = static_cast<MediaRecorderPrivateWriter*>(mediaRecorderPrivateWriter); 143 writer->processNewCompressedVideoSampleBuffers(); 144 } 145 146 void MediaRecorderPrivateWriter::compressedAudioOutputBufferCallback(void *mediaRecorderPrivateWriter, CMBufferQueueTriggerToken) 147 { 148 auto *writer = static_cast<MediaRecorderPrivateWriter*>(mediaRecorderPrivateWriter); 149 writer->processNewCompressedAudioSampleBuffers(); 150 } 151 152 MediaRecorderPrivateWriter::MediaRecorderPrivateWriter(bool hasAudio, bool hasVideo) 153 : m_hasAudio(hasAudio) 154 , m_hasVideo(hasVideo) 155 { 156 } 157 158 MediaRecorderPrivateWriter::~MediaRecorderPrivateWriter() 159 { 160 clear(); 161 } 162 163 bool MediaRecorderPrivateWriter::initialize() 164 { 111 165 NSError *error = nil; 112 auto avAssetWriter = adoptNS([PAL::allocAVAssetWriterInstance() initWithURL:outputURL fileType:AVFileTypeMPEG4 error:&error]);166 m_writer = adoptNS([PAL::allocAVAssetWriterInstance() initWithFileType:AVFileTypeMPEG4 error:&error]); 113 167 if (error) { 114 168 RELEASE_LOG_ERROR(MediaStream, "create AVAssetWriter instance failed with error code %ld", (long)error.code); 115 return nullptr; 116 } 117 118 auto writer = adoptRef(*new MediaRecorderPrivateWriter(WTFMove(avAssetWriter), WTFMove(filePath))); 119 120 if (hasAudio && !writer->setAudioInput()) 121 return nullptr; 122 123 if (width && height) { 124 if (!writer->setVideoInput(width, height)) 125 return nullptr; 126 } 127 128 return WTFMove(writer); 129 } 130 131 MediaRecorderPrivateWriter::MediaRecorderPrivateWriter(RetainPtr<AVAssetWriter>&& avAssetWriter, String&& filePath) 132 : m_writer(WTFMove(avAssetWriter)) 133 , m_path(WTFMove(filePath)) 134 { 135 } 136 137 MediaRecorderPrivateWriter::~MediaRecorderPrivateWriter() 138 { 139 clear(); 169 return false; 170 } 171 172 m_writerDelegate = adoptNS([[WebAVAssetWriterDelegate alloc] initWithWriter: this]); 173 [m_writer.get() setDelegate:m_writerDelegate.get()]; 174 175 if (m_hasAudio) { 176 m_audioCompressor = AudioSampleBufferCompressor::create(compressedAudioOutputBufferCallback, this); 177 if (!m_audioCompressor) 178 return false; 179 } 180 if (m_hasVideo) { 181 m_videoCompressor = VideoSampleBufferCompressor::create(kCMVideoCodecType_H264, compressedVideoOutputBufferCallback, this); 182 if (!m_videoCompressor) 183 return false; 184 } 185 return true; 186 } 187 188 void MediaRecorderPrivateWriter::processNewCompressedVideoSampleBuffers() 189 { 190 ASSERT(m_hasVideo); 191 if (!m_videoFormatDescription) { 192 m_videoFormatDescription = CMSampleBufferGetFormatDescription(m_videoCompressor->getOutputSampleBuffer()); 193 callOnMainThread([weakThis = makeWeakPtr(this), this] { 194 if (!weakThis) 195 return; 196 197 if (m_hasAudio && !m_audioFormatDescription) 198 return; 199 200 startAssetWriter(); 201 }); 202 } 203 if (!m_hasStartedWriting) 204 return; 205 appendCompressedSampleBuffers(); 206 } 207 208 void MediaRecorderPrivateWriter::processNewCompressedAudioSampleBuffers() 209 { 210 ASSERT(m_hasAudio); 211 if (!m_audioFormatDescription) { 212 m_audioFormatDescription = CMSampleBufferGetFormatDescription(m_audioCompressor->getOutputSampleBuffer()); 213 callOnMainThread([weakThis = makeWeakPtr(this), this] { 214 if (!weakThis) 215 return; 216 217 if (m_hasVideo && !m_videoFormatDescription) 218 return; 219 220 startAssetWriter(); 221 }); 222 } 223 if (!m_hasStartedWriting) 224 return; 225 appendCompressedSampleBuffers(); 226 } 227 228 void MediaRecorderPrivateWriter::startAssetWriter() 229 { 230 if (m_hasVideo) { 231 m_videoAssetWriterInput = adoptNS([PAL::allocAVAssetWriterInputInstance() initWithMediaType:AVMediaTypeVideo outputSettings:nil sourceFormatHint:m_videoFormatDescription.get()]); 232 [m_videoAssetWriterInput setExpectsMediaDataInRealTime:true]; 233 if (![m_writer.get() canAddInput:m_videoAssetWriterInput.get()]) { 234 RELEASE_LOG_ERROR(MediaStream, "MediaRecorderPrivateWriter::startAssetWriter failed canAddInput for video"); 235 return; 236 } 237 [m_writer.get() addInput:m_videoAssetWriterInput.get()]; 238 } 239 240 if (m_hasAudio) { 241 m_audioAssetWriterInput = adoptNS([PAL::allocAVAssetWriterInputInstance() initWithMediaType:AVMediaTypeAudio outputSettings:nil sourceFormatHint:m_audioFormatDescription.get()]); 242 [m_audioAssetWriterInput setExpectsMediaDataInRealTime:true]; 243 if (![m_writer.get() canAddInput:m_audioAssetWriterInput.get()]) { 244 RELEASE_LOG_ERROR(MediaStream, "MediaRecorderPrivateWriter::startAssetWriter failed canAddInput for audio"); 245 return; 246 } 247 [m_writer.get() addInput:m_audioAssetWriterInput.get()]; 248 } 249 250 if (![m_writer.get() startWriting]) { 251 RELEASE_LOG_ERROR(MediaStream, "MediaRecorderPrivateWriter::startAssetWriter failed startWriting"); 252 return; 253 } 254 255 [m_writer.get() startSessionAtSourceTime:kCMTimeZero]; 256 257 appendCompressedSampleBuffers(); 258 259 m_hasStartedWriting = true; 260 } 261 262 bool MediaRecorderPrivateWriter::appendCompressedAudioSampleBuffer() 263 { 264 if (!m_audioCompressor) 265 return false; 266 267 if (![m_audioAssetWriterInput isReadyForMoreMediaData]) 268 return false; 269 270 auto buffer = m_audioCompressor->takeOutputSampleBuffer(); 271 if (!buffer) 272 return false; 273 274 [m_audioAssetWriterInput.get() appendSampleBuffer:buffer.get()]; 275 return true; 276 } 277 278 bool MediaRecorderPrivateWriter::appendCompressedVideoSampleBuffer() 279 { 280 if (!m_videoCompressor) 281 return false; 282 283 if (![m_videoAssetWriterInput isReadyForMoreMediaData]) 284 return false; 285 286 auto buffer = m_videoCompressor->takeOutputSampleBuffer(); 287 if (!buffer) 288 return false; 289 290 m_lastVideoPresentationTime = CMSampleBufferGetPresentationTimeStamp(buffer.get()); 291 m_lastVideoDecodingTime = CMSampleBufferGetDecodeTimeStamp(buffer.get()); 292 m_hasEncodedVideoSamples = true; 293 294 [m_videoAssetWriterInput.get() appendSampleBuffer:buffer.get()]; 295 return true; 296 } 297 298 void MediaRecorderPrivateWriter::appendCompressedSampleBuffers() 299 { 300 while (appendCompressedVideoSampleBuffer() || appendCompressedAudioSampleBuffer()) { }; 301 } 302 303 static inline void appendEndsPreviousSampleDurationMarker(AVAssetWriterInput *assetWriterInput, CMTime presentationTimeStamp, CMTime decodingTimeStamp) 304 { 305 CMSampleTimingInfo timingInfo = { kCMTimeInvalid, presentationTimeStamp, decodingTimeStamp}; 306 307 CMSampleBufferRef buffer = NULL; 308 auto error = CMSampleBufferCreate(kCFAllocatorDefault, NULL, true, NULL, NULL, NULL, 0, 1, &timingInfo, 0, NULL, &buffer); 309 if (error) { 310 RELEASE_LOG_ERROR(MediaStream, "MediaRecorderPrivateWriter appendEndsPreviousSampleDurationMarker failed CMSampleBufferCreate with %d", error); 311 return; 312 } 313 auto sampleBuffer = adoptCF(buffer); 314 315 CMSetAttachment(sampleBuffer.get(), kCMSampleBufferAttachmentKey_EndsPreviousSampleDuration, kCFBooleanTrue, kCMAttachmentMode_ShouldPropagate); 316 if (![assetWriterInput appendSampleBuffer:sampleBuffer.get()]) 317 RELEASE_LOG_ERROR(MediaStream, "MediaRecorderPrivateWriter appendSampleBuffer to writer input failed"); 318 } 319 320 void MediaRecorderPrivateWriter::appendEndOfVideoSampleDurationIfNeeded(CompletionHandler<void()>&& completionHandler) 321 { 322 if (!m_hasEncodedVideoSamples) { 323 completionHandler(); 324 return; 325 } 326 if ([m_videoAssetWriterInput isReadyForMoreMediaData]) { 327 appendEndsPreviousSampleDurationMarker(m_videoAssetWriterInput.get(), m_lastVideoPresentationTime, m_lastVideoDecodingTime); 328 completionHandler(); 329 return; 330 } 331 332 callOnMainThread([this, weakThis = makeWeakPtr(this), completionHandler = WTFMove(completionHandler)]() mutable { 333 if (!weakThis) { 334 completionHandler(); 335 return; 336 } 337 appendEndOfVideoSampleDurationIfNeeded(WTFMove(completionHandler)); 338 }); 339 /* 340 auto block = makeBlockPtr([this, weakThis = makeWeakPtr(this), completionHandler = WTFMove(completionHandler)]() mutable { 341 if (weakThis) { 342 appendEndsPreviousSampleDurationMarker(m_videoAssetWriterInput.get(), m_lastVideoPresentationTime, m_lastVideoDecodingTime); 343 [m_videoAssetWriterInput markAsFinished]; 344 } 345 completionHandler(); 346 }); 347 [m_videoAssetWriterInput requestMediaDataWhenReadyOnQueue:dispatch_get_main_queue() usingBlock:block.get()]; 348 */ 349 } 350 351 void MediaRecorderPrivateWriter::flushCompressedSampleBuffers(CompletionHandler<void()>&& completionHandler) 352 { 353 appendCompressedSampleBuffers(); 354 appendEndOfVideoSampleDurationIfNeeded(WTFMove(completionHandler)); 140 355 } 141 356 142 357 void MediaRecorderPrivateWriter::clear() 143 358 { 144 if (m_videoInput) {145 m_videoInput.clear();146 dispatch_release(m_videoPullQueue);147 }148 if (m_audioInput) {149 m_audioInput.clear();150 dispatch_release(m_audioPullQueue);151 }152 359 if (m_writer) 153 360 m_writer.clear(); … … 158 365 } 159 366 160 bool MediaRecorderPrivateWriter::setVideoInput(int width, int height)161 {162 ASSERT(!m_videoInput);163 164 NSDictionary *compressionProperties = @{165 AVVideoAverageBitRateKey : [NSNumber numberWithInt:width * height * 12],166 AVVideoExpectedSourceFrameRateKey : @(30),167 AVVideoMaxKeyFrameIntervalKey : @(120),168 AVVideoProfileLevelKey : AVVideoProfileLevelH264MainAutoLevel169 };170 171 NSDictionary *videoSettings = @{172 AVVideoCodecKey: AVVideoCodecH264,173 AVVideoWidthKey: [NSNumber numberWithInt:width],174 AVVideoHeightKey: [NSNumber numberWithInt:height],175 AVVideoCompressionPropertiesKey: compressionProperties176 };177 178 m_videoInput = adoptNS([PAL::allocAVAssetWriterInputInstance() initWithMediaType:AVMediaTypeVideo outputSettings:videoSettings sourceFormatHint:nil]);179 [m_videoInput setExpectsMediaDataInRealTime:true];180 181 if (![m_writer canAddInput:m_videoInput.get()]) {182 m_videoInput = nullptr;183 RELEASE_LOG_ERROR(MediaStream, "the video input is not allowed to add to the AVAssetWriter");184 return false;185 }186 [m_writer addInput:m_videoInput.get()];187 m_videoPullQueue = dispatch_queue_create("WebCoreVideoRecordingPullBufferQueue", DISPATCH_QUEUE_SERIAL);188 return true;189 }190 191 bool MediaRecorderPrivateWriter::setAudioInput()192 {193 ASSERT(!m_audioInput);194 195 NSDictionary *audioSettings = @{196 AVEncoderBitRateKey : @(28000),197 AVFormatIDKey : @(kAudioFormatMPEG4AAC),198 AVNumberOfChannelsKey : @(1),199 AVSampleRateKey : @(22050)200 };201 202 m_audioInput = adoptNS([PAL::allocAVAssetWriterInputInstance() initWithMediaType:AVMediaTypeAudio outputSettings:audioSettings sourceFormatHint:nil]);203 [m_audioInput setExpectsMediaDataInRealTime:true];204 205 if (![m_writer canAddInput:m_audioInput.get()]) {206 m_audioInput = nullptr;207 RELEASE_LOG_ERROR(MediaStream, "the audio input is not allowed to add to the AVAssetWriter");208 return false;209 }210 [m_writer addInput:m_audioInput.get()];211 m_audioPullQueue = dispatch_queue_create("WebCoreAudioRecordingPullBufferQueue", DISPATCH_QUEUE_SERIAL);212 return true;213 }214 367 215 368 static inline RetainPtr<CMSampleBufferRef> copySampleBufferWithCurrentTimeStamp(CMSampleBufferRef originalBuffer) … … 218 371 CMItemCount count = 0; 219 372 CMSampleBufferGetSampleTimingInfoArray(originalBuffer, 0, nil, &count); 220 373 221 374 Vector<CMSampleTimingInfo> timeInfo(count); 222 375 CMSampleBufferGetSampleTimingInfoArray(originalBuffer, count, timeInfo.data(), &count); 223 224 for ( CMItemCounti = 0; i < count; i++) {376 377 for (auto i = 0; i < count; i++) { 225 378 timeInfo[i].decodeTimeStamp = kCMTimeInvalid; 226 379 timeInfo[i].presentationTimeStamp = startTime; 227 380 } 381 382 CMSampleBufferRef newBuffer = nullptr; 383 if (auto error = CMSampleBufferCreateCopyWithNewTiming(kCFAllocatorDefault, originalBuffer, count, timeInfo.data(), &newBuffer)) { 384 RELEASE_LOG_ERROR(MediaStream, "MediaRecorderPrivateWriter CMSampleBufferCreateCopyWithNewTiming failed with %d", error); 385 return nullptr; 386 } 387 return adoptCF(newBuffer); 388 } 228 389 229 CMSampleBufferRef newBuffer = nullptr;230 auto error = CMSampleBufferCreateCopyWithNewTiming(kCFAllocatorDefault, originalBuffer, count, timeInfo.data(), &newBuffer);231 if (error)232 return nullptr;233 return adoptCF(newBuffer);234 }235 236 390 void MediaRecorderPrivateWriter::appendVideoSampleBuffer(CMSampleBufferRef sampleBuffer) 237 391 { 238 ASSERT(m_videoInput); 239 if (m_isStopped) 240 return; 241 242 if (!m_hasStartedWriting) { 243 if (![m_writer startWriting]) { 244 m_isStopped = true; 245 RELEASE_LOG_ERROR(MediaStream, "create AVAssetWriter instance failed with error code %ld", (long)[m_writer error]); 246 return; 247 } 248 [m_writer startSessionAtSourceTime:CMClockGetTime(CMClockGetHostTimeClock())]; 249 m_hasStartedWriting = true; 250 RefPtr<MediaRecorderPrivateWriter> protectedThis = this; 251 [m_videoInput requestMediaDataWhenReadyOnQueue:m_videoPullQueue usingBlock:[this, protectedThis = WTFMove(protectedThis)] { 252 do { 253 if (![m_videoInput isReadyForMoreMediaData]) 254 break; 255 auto locker = holdLock(m_videoLock); 256 if (m_videoBufferPool.isEmpty()) 257 break; 258 auto buffer = m_videoBufferPool.takeFirst(); 259 locker.unlockEarly(); 260 if (![m_videoInput appendSampleBuffer:buffer.get()]) 261 break; 262 } while (true); 263 if (m_isStopped && m_videoBufferPool.isEmpty()) { 264 [m_videoInput markAsFinished]; 265 m_finishWritingVideoSemaphore.signal(); 266 } 267 }]; 268 return; 269 } 270 auto bufferWithCurrentTime = copySampleBufferWithCurrentTimeStamp(sampleBuffer); 271 if (!bufferWithCurrentTime) 272 return; 273 274 auto locker = holdLock(m_videoLock); 275 m_videoBufferPool.append(WTFMove(bufferWithCurrentTime)); 392 // FIXME: We should not set the timestamps if they are already set. 393 if (auto bufferWithCurrentTime = copySampleBufferWithCurrentTimeStamp(sampleBuffer)) 394 m_videoCompressor->addSampleBuffer(bufferWithCurrentTime.get()); 276 395 } 277 396 … … 281 400 CMFormatDescriptionRef format = nullptr; 282 401 auto error = CMAudioFormatDescriptionCreate(kCFAllocatorDefault, basicDescription, 0, NULL, 0, NULL, NULL, &format); 283 if (error) 402 if (error) { 403 RELEASE_LOG_ERROR(MediaStream, "MediaRecorderPrivateWriter CMAudioFormatDescriptionCreate failed with %d", error); 284 404 return nullptr; 405 } 285 406 return adoptCF(format); 286 407 } 287 408 288 static inline RetainPtr<CMSampleBufferRef> createAudioSampleBufferWithPacketDescriptions(CMFormatDescriptionRef format, size_t sampleCount) 289 { 290 CMTime startTime = CMClockGetTime(CMClockGetHostTimeClock()); 291 CMSampleBufferRef sampleBuffer = nullptr; 292 auto error = CMAudioSampleBufferCreateWithPacketDescriptions(kCFAllocatorDefault, NULL, false, NULL, NULL, format, sampleCount, startTime, NULL, &sampleBuffer); 293 if (error) 294 return nullptr; 295 return adoptCF(sampleBuffer); 296 } 297 298 void MediaRecorderPrivateWriter::appendAudioSampleBuffer(const PlatformAudioData& data, const AudioStreamDescription& description, const WTF::MediaTime&, size_t sampleCount) 299 { 300 ASSERT(m_audioInput); 301 if ((!m_hasStartedWriting && m_videoInput) || m_isStopped) 302 return; 409 static inline RetainPtr<CMSampleBufferRef> createAudioSampleBuffer(const PlatformAudioData& data, const AudioStreamDescription& description, const WTF::MediaTime& time, size_t sampleCount) 410 { 303 411 auto format = createAudioFormatDescription(description); 304 412 if (!format) 305 return; 306 if (m_isFirstAudioSample) { 307 if (!m_videoInput) { 308 // audio-only recording. 309 if (![m_writer startWriting]) { 310 m_isStopped = true; 311 return; 312 } 313 [m_writer startSessionAtSourceTime:CMClockGetTime(CMClockGetHostTimeClock())]; 314 m_hasStartedWriting = true; 315 } 316 m_isFirstAudioSample = false; 317 RefPtr<MediaRecorderPrivateWriter> protectedThis = this; 318 [m_audioInput requestMediaDataWhenReadyOnQueue:m_audioPullQueue usingBlock:[this, protectedThis = WTFMove(protectedThis)] { 319 do { 320 if (![m_audioInput isReadyForMoreMediaData]) 321 break; 322 auto locker = holdLock(m_audioLock); 323 if (m_audioBufferPool.isEmpty()) 324 break; 325 auto buffer = m_audioBufferPool.takeFirst(); 326 locker.unlockEarly(); 327 [m_audioInput appendSampleBuffer:buffer.get()]; 328 } while (true); 329 if (m_isStopped && m_audioBufferPool.isEmpty()) { 330 [m_audioInput markAsFinished]; 331 m_finishWritingAudioSemaphore.signal(); 332 } 413 return nullptr; 414 415 CMSampleBufferRef sampleBuffer = nullptr; 416 auto error = CMAudioSampleBufferCreateWithPacketDescriptions(kCFAllocatorDefault, NULL, false, NULL, NULL, format.get(), sampleCount, toCMTime(time), NULL, &sampleBuffer); 417 if (error) { 418 RELEASE_LOG_ERROR(MediaStream, "MediaRecorderPrivateWriter createAudioSampleBufferWithPacketDescriptions failed with %d", error); 419 return nullptr; 420 } 421 auto buffer = adoptCF(sampleBuffer); 422 423 error = CMSampleBufferSetDataBufferFromAudioBufferList(buffer.get(), kCFAllocatorDefault, kCFAllocatorDefault, 0, downcast<WebAudioBufferList>(data).list()); 424 if (error) { 425 RELEASE_LOG_ERROR(MediaStream, "MediaRecorderPrivateWriter CMSampleBufferSetDataBufferFromAudioBufferList failed with %d", error); 426 return nullptr; 427 } 428 return buffer; 429 } 430 431 void MediaRecorderPrivateWriter::appendAudioSampleBuffer(const PlatformAudioData& data, const AudioStreamDescription& description, const WTF::MediaTime& time, size_t sampleCount) 432 { 433 if (auto sampleBuffer = createAudioSampleBuffer(data, description, time, sampleCount)) 434 m_audioCompressor->addSampleBuffer(sampleBuffer.get()); 435 } 436 437 void MediaRecorderPrivateWriter::stopRecording() 438 { 439 if (m_isStopped) 440 return; 441 442 m_isStopped = true; 443 444 if (m_videoCompressor) 445 m_videoCompressor->finish(); 446 if (m_audioCompressor) 447 m_audioCompressor->finish(); 448 449 if (!m_hasStartedWriting) 450 return; 451 ASSERT([m_writer status] == AVAssetWriterStatusWriting); 452 453 m_isStopping = true; 454 455 flushCompressedSampleBuffers([this, weakThis = makeWeakPtr(this)]() mutable { 456 if (!weakThis) 457 return; 458 459 [m_writer flush]; 460 [m_writer finishWritingWithCompletionHandler:[this, weakThis = WTFMove(weakThis)]() mutable { 461 callOnMainThread([this, weakThis = WTFMove(weakThis)]() mutable { 462 if (!weakThis) 463 return; 464 465 m_isStopping = false; 466 if (m_fetchDataCompletionHandler) { 467 auto buffer = WTFMove(m_data); 468 m_fetchDataCompletionHandler(WTFMove(buffer)); 469 } 470 471 m_isStopped = false; 472 m_hasStartedWriting = false; 473 clear(); 474 }); 333 475 }]; 334 } 335 336 auto sampleBuffer = createAudioSampleBufferWithPacketDescriptions(format.get(), sampleCount); 337 if (!sampleBuffer) 338 return; 339 auto error = CMSampleBufferSetDataBufferFromAudioBufferList(sampleBuffer.get(), kCFAllocatorDefault, kCFAllocatorDefault, 0, downcast<WebAudioBufferList>(data).list()); 340 if (error) 341 return; 342 343 auto locker = holdLock(m_audioLock); 344 m_audioBufferPool.append(WTFMove(sampleBuffer)); 345 } 346 347 void MediaRecorderPrivateWriter::stopRecording() 348 { 349 if (m_isStopped) 350 return; 351 352 m_isStopped = true; 353 if (!m_hasStartedWriting) 354 return; 355 ASSERT([m_writer status] == AVAssetWriterStatusWriting); 356 if (m_videoInput) 357 m_finishWritingVideoSemaphore.wait(); 358 359 if (m_audioInput) 360 m_finishWritingAudioSemaphore.wait(); 361 362 m_isStopping = true; 363 [m_writer finishWritingWithCompletionHandler:[this, weakPtr = makeWeakPtr(*this)]() mutable { 364 callOnMainThread([this, weakPtr = WTFMove(weakPtr), buffer = SharedBuffer::createWithContentsOfFile(m_path)]() mutable { 365 if (!weakPtr) 366 return; 367 368 m_isStopping = false; 369 if (m_fetchDataCompletionHandler) 370 m_fetchDataCompletionHandler(WTFMove(buffer)); 371 else 372 m_data = WTFMove(buffer); 373 374 m_isStopped = false; 375 m_hasStartedWriting = false; 376 m_isFirstAudioSample = true; 377 clear(); 378 }); 379 m_finishWritingSemaphore.signal(); 380 }]; 381 m_finishWritingSemaphore.wait(); 476 }); 382 477 } 383 478 … … 393 488 } 394 489 490 void MediaRecorderPrivateWriter::appendData(const char* data, size_t size) 491 { 492 if (!m_data) { 493 m_data = SharedBuffer::create(data, size); 494 return; 495 } 496 m_data->append(data, size); 497 } 498 499 void MediaRecorderPrivateWriter::appendData(Ref<SharedBuffer>&& buffer) 500 { 501 if (!m_data) { 502 m_data = WTFMove(buffer); 503 return; 504 } 505 m_data->append(WTFMove(buffer)); 506 } 507 395 508 } // namespace WebCore 396 509 397 510 #endif // ENABLE(MEDIA_STREAM) && USE(AVFOUNDATION) 511 #endif -
trunk/Source/WebCore/platform/mediarecorder/cocoa/MediaRecorderPrivateWriterCocoaFileBased.mm
r255343 r255345 24 24 */ 25 25 26 #include "config.h"27 #include "MediaRecorderPrivateWriterCocoa.h"28 29 26 #if ENABLE(MEDIA_STREAM) && USE(AVFOUNDATION) 30 27 … … 88 85 RELEASE_LOG_ERROR(Media, "Failed to load AVEncoderBitRateKey"); 89 86 return @"AVEncoderBitRateKey"; 90 }91 92 RefPtr<MediaRecorderPrivateWriter> MediaRecorderPrivateWriter::create(const MediaStreamTrackPrivate* audioTrack, const MediaStreamTrackPrivate* videoTrack)93 {94 int width = 0, height = 0;95 if (videoTrack) {96 auto& settings = videoTrack->settings();97 width = settings.width();98 height = settings.height();99 }100 return create(!!audioTrack, width, height);101 87 } 102 88 -
trunk/Source/WebKit/ChangeLog
r255343 r255345 1 2020-01-29 youenn fablet <youenn@apple.com> 2 3 [Cocoa] Use AVAssetWriterDelegate to implement MediaRecorder 4 https://bugs.webkit.org/show_bug.cgi?id=206582 5 6 Reviewed by Eric Carlson. 7 8 * GPUProcess/webrtc/RemoteMediaRecorder.cpp: 9 (WebKit::RemoteMediaRecorder::create): 10 Use new constructor. 11 1 12 2020-01-29 Carlos Garcia Campos <cgarcia@igalia.com> 2 13
Note: See TracChangeset
for help on using the changeset viewer.