diff --git a/dom/media/platforms/apple/AppleEncoderModule.cpp b/dom/media/platforms/apple/AppleEncoderModule.cpp index f07f39f48cdb..6fa4a53ab5f5 100644 --- a/dom/media/platforms/apple/AppleEncoderModule.cpp +++ b/dom/media/platforms/apple/AppleEncoderModule.cpp @@ -8,7 +8,6 @@ #include "AppleVTEncoder.h" #include "VideoUtils.h" -#include "nsCocoaFeatures.h" namespace mozilla { @@ -28,10 +27,7 @@ bool AppleEncoderModule::Supports(const EncoderConfig& aConfig) const { if (!CanLikelyEncode(aConfig)) { return false; } - // Only two temporal layers supported, and only from 11.3 and more recent - if (aConfig.mScalabilityMode == ScalabilityMode::L1T3 || - (aConfig.mScalabilityMode != ScalabilityMode::None && - !nsCocoaFeatures::IsAtLeastVersion(11, 3, 0))) { + if (aConfig.mScalabilityMode != ScalabilityMode::None) { return false; } return aConfig.mCodec == CodecType::H264; diff --git a/dom/media/platforms/apple/AppleVTEncoder.cpp b/dom/media/platforms/apple/AppleVTEncoder.cpp index dfde3007e32c..c464ddd6f3ce 100644 --- a/dom/media/platforms/apple/AppleVTEncoder.cpp +++ b/dom/media/platforms/apple/AppleVTEncoder.cpp @@ -15,7 +15,6 @@ #include "H264.h" #include "AppleUtils.h" -#include "nsCocoaFeatures.h" namespace mozilla { extern LazyLogModule sPEMLog; @@ -26,23 +25,7 @@ extern LazyLogModule sPEMLog; MOZ_LOG(sPEMLog, mozilla::LogLevel::Debug, \ ("[AppleVTEncoder] %s: " fmt, __func__, ##__VA_ARGS__)) -static CFDictionaryRef BuildEncoderSpec(const bool aHardwareNotAllowed, - const bool aLowLatencyRateControl) { - if (__builtin_available(macos 11.3, *)) { - if (aLowLatencyRateControl) { - // If doing low-latency rate control, the hardware encoder is required. - const void* keys[] = { - kVTVideoEncoderSpecification_RequireHardwareAcceleratedVideoEncoder, - kVTVideoEncoderSpecification_EnableLowLatencyRateControl}; - const void* values[] = {kCFBooleanTrue, kCFBooleanTrue}; - - static_assert(ArrayLength(keys) == ArrayLength(values), - "Non matching keys/values array size"); - return CFDictionaryCreate( - kCFAllocatorDefault, keys, values, ArrayLength(keys), - &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); - } - } +static CFDictionaryRef BuildEncoderSpec(const bool aHardwareNotAllowed) { const void* keys[] = { kVTVideoEncoderSpecification_EnableHardwareAcceleratedVideoEncoder}; const void* values[] = {aHardwareNotAllowed ? kCFBooleanFalse @@ -58,14 +41,12 @@ static CFDictionaryRef BuildEncoderSpec(const bool aHardwareNotAllowed, static void FrameCallback(void* aEncoder, void* aFrameRefCon, OSStatus aStatus, VTEncodeInfoFlags aInfoFlags, CMSampleBufferRef aSampleBuffer) { - if (aInfoFlags & kVTEncodeInfo_FrameDropped) { - LOGE("frame tagged as dropped"); - return; - } if (aStatus != noErr || !aSampleBuffer) { LOGE("VideoToolbox encoder returned no data status=%d sample=%p", aStatus, aSampleBuffer); aSampleBuffer = nullptr; + } else if (aInfoFlags & kVTEncodeInfo_FrameDropped) { + LOGE("frame tagged as dropped"); return; } (static_cast(aEncoder))->OutputFrame(aSampleBuffer); @@ -160,20 +141,7 @@ RefPtr AppleVTEncoder::Init() { return InitPromise::CreateAndReject(NS_ERROR_ILLEGAL_VALUE, __func__); } - if (mConfig.mScalabilityMode != ScalabilityMode::None && - !nsCocoaFeatures::IsAtLeastVersion(11, 3, 0)) { - LOGE("SVC only supported on macOS 11.3 and more recent"); - return InitPromise::CreateAndReject( - MediaResult(NS_ERROR_DOM_MEDIA_NOT_SUPPORTED_ERR, - "SVC only supported on macOS 11.3 and more recent"), - __func__); - } - - bool lowLatencyRateControl = - mConfig.mUsage == Usage::Realtime || - mConfig.mScalabilityMode != ScalabilityMode::None; - AutoCFRelease spec( - BuildEncoderSpec(mHardwareNotAllowed, lowLatencyRateControl)); + AutoCFRelease spec(BuildEncoderSpec(mHardwareNotAllowed)); AutoCFRelease srcBufferAttr( BuildSourceImageBufferAttributes()); if (!srcBufferAttr) { @@ -198,23 +166,15 @@ RefPtr AppleVTEncoder::Init() { } if (mConfig.mUsage == Usage::Realtime && !SetRealtime(mSession, true)) { - LOGE("fail to configure realtime properties"); + LOGE("fail to configurate realtime properties"); return InitPromise::CreateAndReject( MediaResult(NS_ERROR_DOM_MEDIA_FATAL_ERR, - "fail to configure real-time"), + "fail to configurate average bitrate"), __func__); } if (mConfig.mBitrate) { - if (mConfig.mCodec == CodecType::H264 && - mConfig.mBitrateMode == BitrateMode::Constant) { - // Not supported, fall-back to VBR. - LOGD("H264 CBR not supported in VideoToolbox, falling back to VBR"); - mConfig.mBitrateMode = BitrateMode::Variable; - } - bool rv = - SetBitrateAndMode(mSession, mConfig.mBitrateMode, mConfig.mBitrate); - if (!rv) { + if (!SetBitrateAndMode(mSession, mConfig.mBitrateMode, mConfig.mBitrate)) { LOGE("failed to set bitrate to %d and mode to %s", mConfig.mBitrate, mConfig.mBitrateMode == BitrateMode::Constant ? "constant" : "variable"); @@ -225,60 +185,6 @@ RefPtr AppleVTEncoder::Init() { } } - if (mConfig.mScalabilityMode != ScalabilityMode::None) { - // A real-time encoder, with reordering disabled is required for SVC to - // work. - if (!SetRealtime(mSession, true)) { - LOGE("fail to configure real-time encoding for svc"); - return InitPromise::CreateAndReject( - MediaResult(NS_ERROR_DOM_MEDIA_FATAL_ERR, - "fail to configure real-time encoding for svc"), - __func__); - } - - mConfig.mUsage = Usage::Realtime; - - if (__builtin_available(macos 11.3, *)) { - float baseLayerFPSRatio = 1.0f; - switch (mConfig.mScalabilityMode) { - case ScalabilityMode::L1T2: - baseLayerFPSRatio = 0.5; - break; - case ScalabilityMode::L1T3: - // Not supported in hw on macOS, but is accepted and errors out when - // encoding. Reject the configuration now. - LOGE("macOS only supports L1T2 h264 SVC"); - return InitPromise::CreateAndReject( - MediaResult(NS_ERROR_DOM_MEDIA_FATAL_ERR, - nsPrintfCString("macOS only support L1T2 h264 SVC")), - __func__); - default: - MOZ_ASSERT_UNREACHABLE("Unhandled value"); - } - CFNumberRef baseLayerFPSRatioRef = CFNumberCreate( - kCFAllocatorDefault, kCFNumberFloatType, &baseLayerFPSRatio); - AutoCFRelease cf(CFNumberCreate( - kCFAllocatorDefault, kCFNumberFloatType, &baseLayerFPSRatio)); - if (VTSessionSetProperty( - mSession, kVTCompressionPropertyKey_BaseLayerFrameRateFraction, - baseLayerFPSRatioRef)) { - LOGE("Failed to set base layer framerate fraction to %f", - baseLayerFPSRatio); - return InitPromise::CreateAndReject( - MediaResult(NS_ERROR_DOM_MEDIA_FATAL_ERR, - nsPrintfCString("fail to configure SVC (base ratio: %f", - baseLayerFPSRatio)), - __func__); - } - } else { - LOGE("MacOS version too old to enable SVC"); - return InitPromise::CreateAndReject( - MediaResult(NS_ERROR_DOM_MEDIA_FATAL_ERR, - "macOS version too old to enable SVC"), - __func__); - } - } - int64_t interval = mConfig.mKeyframeInterval > std::numeric_limits::max() ? std::numeric_limits::max() @@ -550,23 +456,12 @@ void AppleVTEncoder::OutputFrame(CMSampleBufferRef aBuffer) { LOGD("::OutputFrame"); RefPtr output(new MediaRawData()); - if (__builtin_available(macos 11.3, *)) { - if (mConfig.mScalabilityMode != ScalabilityMode::None) { - CFDictionaryRef dict = (CFDictionaryRef)(CFArrayGetValueAtIndex( - CMSampleBufferGetSampleAttachmentsArray(aBuffer, true), 0)); - CFBooleanRef isBaseLayerRef = (CFBooleanRef)CFDictionaryGetValue( - dict, (const void*)kCMSampleAttachmentKey_IsDependedOnByOthers); - Boolean isBaseLayer = CFBooleanGetValue(isBaseLayerRef); - output->mTemporalLayerId.emplace(isBaseLayer ? 0 : 1); - } - } - bool forceAvcc = false; if (mConfig.mCodecSpecific->is()) { forceAvcc = mConfig.mCodecSpecific->as().mFormat == H264BitStreamFormat::AVC; } - bool asAnnexB = !forceAvcc; + bool asAnnexB = mConfig.mUsage == Usage::Realtime && !forceAvcc; bool succeeded = WriteExtraData(output, aBuffer, asAnnexB) && WriteNALUs(output, aBuffer, asAnnexB); @@ -609,9 +504,9 @@ RefPtr AppleVTEncoder::Encode( RefPtr AppleVTEncoder::Reconfigure( const RefPtr& aConfigurationChanges) { - return InvokeAsync(mTaskQueue, this, __func__, - &AppleVTEncoder::ProcessReconfigure, - aConfigurationChanges); + return InvokeAsync&>( + mTaskQueue, this, __func__, &AppleVTEncoder::ProcessReconfigure, + aConfigurationChanges); } RefPtr AppleVTEncoder::ProcessEncode( @@ -660,10 +555,7 @@ AppleVTEncoder::ProcessReconfigure( const RefPtr& aConfigurationChanges) { bool ok = false; for (const auto& confChange : aConfigurationChanges->mChanges) { - // A reconfiguration on the fly succeeds if all changes can be applied - // successfuly. In case of failure, the encoder will be drained and - // recreated. - ok &= confChange.match( + ok |= confChange.match( // Not supported yet [&](const DimensionsChange& aChange) -> bool { return false; }, [&](const DisplayDimensionsChange& aChange) -> bool { return false; }, @@ -835,6 +727,11 @@ RefPtr AppleVTEncoder::ProcessDrain() { AssertOnTaskQueue(); MOZ_ASSERT(mSession); + if (mFramesCompleted) { + MOZ_DIAGNOSTIC_ASSERT(mEncodedData.IsEmpty()); + return EncodePromise::CreateAndResolve(EncodedData(), __func__); + } + OSStatus status = VTCompressionSessionCompleteFrames(mSession, kCMTimeIndefinite); if (status != noErr) { @@ -842,6 +739,7 @@ RefPtr AppleVTEncoder::ProcessDrain() { return EncodePromise::CreateAndReject(NS_ERROR_DOM_MEDIA_FATAL_ERR, __func__); } + mFramesCompleted = true; // VTCompressionSessionCompleteFrames() could have queued multiple tasks with // the new drained frames. Dispatch a task after them to resolve the promise // with those frames. diff --git a/dom/media/platforms/apple/AppleVTEncoder.h b/dom/media/platforms/apple/AppleVTEncoder.h index c8c5f691509b..b3a88e209848 100644 --- a/dom/media/platforms/apple/AppleVTEncoder.h +++ b/dom/media/platforms/apple/AppleVTEncoder.h @@ -28,6 +28,7 @@ class AppleVTEncoder final : public MediaDataEncoder { mTaskQueue(aTaskQueue), mHardwareNotAllowed(aConfig.mHardwarePreference == HardwarePreference::RequireSoftware), + mFramesCompleted(false), mError(NS_OK), mSession(nullptr) { MOZ_ASSERT(mConfig.mSize.width > 0 && mConfig.mSize.height > 0); @@ -73,6 +74,7 @@ class AppleVTEncoder final : public MediaDataEncoder { const bool mHardwareNotAllowed; // Access only in mTaskQueue. EncodedData mEncodedData; + bool mFramesCompleted; RefPtr mAvcc; // Stores latest avcC data. MediaResult mError; diff --git a/dom/media/webcodecs/EncoderAgent.cpp b/dom/media/webcodecs/EncoderAgent.cpp index bb02f1835fcc..e6af17a0be45 100644 --- a/dom/media/webcodecs/EncoderAgent.cpp +++ b/dom/media/webcodecs/EncoderAgent.cpp @@ -205,7 +205,6 @@ RefPtr EncoderAgent::Reconfigure( self->mReconfigurationRequest.Complete(); LOGE("EncoderAgent #%zu (%p) reconfigure success", self->mId, self.get()); - self->SetState(State::Configured); self->mReconfigurationPromise.Resolve(true, __func__); }, [self = RefPtr{this}](const MediaResult& aError) { diff --git a/testing/web-platform/meta/webcodecs/full-cycle-test.https.any.js.ini b/testing/web-platform/meta/webcodecs/full-cycle-test.https.any.js.ini index a67317af2adf..a90838a41773 100644 --- a/testing/web-platform/meta/webcodecs/full-cycle-test.https.any.js.ini +++ b/testing/web-platform/meta/webcodecs/full-cycle-test.https.any.js.ini @@ -1,6 +1,6 @@ [full-cycle-test.https.any.html?vp9_p2] disabled: - if (os == "android") or (bits == 32): not implemented + if (os == "mac") or (os == "android") or (bits == 32): not implemented [Encoding and decoding cycle] expected: [PASS, FAIL] @@ -13,7 +13,7 @@ [full-cycle-test.https.any.html?vp9_p0] disabled: - if (os == "android") or (bits == 32): not implemented + if (os == "mac") or (os == "android") or (bits == 32): not implemented [Encoding and decoding cycle] expected: [PASS, FAIL] @@ -26,7 +26,7 @@ [full-cycle-test.https.any.html?vp8] disabled: - if (os == "android") or (bits == 32): not implemented + if (os == "mac") or (os == "android") or (bits == 32): not implemented [Encoding and decoding cycle] expected: [PASS, FAIL] @@ -39,7 +39,7 @@ [full-cycle-test.https.any.html?h264_avc] disabled: - if (os == "android") or (version == "Ubuntu 18.04"): not implemented + if (os == "mac") or (os == "android") or (version == "Ubuntu 18.04"): not implemented [full-cycle-test.https.any.html?av1] disabled: @@ -69,7 +69,7 @@ [full-cycle-test.https.any.worker.html?vp8] disabled: - if (os == "android") or (bits == 32): not implemented + if (os == "mac") or (os == "android") or (bits == 32): not implemented [Encoding and decoding cycle] expected: [PASS, FAIL] @@ -82,11 +82,11 @@ [full-cycle-test.https.any.html?h264_annexb] disabled: - if (os == "android") or (version == "Ubuntu 18.04"): not implemented + if (os == "mac") or (os == "android") or (version == "Ubuntu 18.04"): not implemented [full-cycle-test.https.any.worker.html?vp9_p0] disabled: - if (os == "android") or (version == "Ubuntu 18.04"): not implemented + if (os == "mac") or (os == "android") or (version == "Ubuntu 18.04"): not implemented [Encoding and decoding cycle] expected: [PASS, FAIL] @@ -99,15 +99,15 @@ [full-cycle-test.https.any.worker.html?h264_avc] disabled: - if (os == "android") or (version == "Ubuntu 18.04"): not implemented + if (os == "mac") or (os == "android") or (version == "Ubuntu 18.04"): not implemented [full-cycle-test.https.any.worker.html?h264_annexb] disabled: - if (os == "android") or (version == "Ubuntu 18.04"): not implemented + if (os == "mac") or (os == "android") or (version == "Ubuntu 18.04"): not implemented [full-cycle-test.https.any.worker.html?vp9_p2] disabled: - if (os == "android") or (bits == 32): not implemented + if (os == "mac") or (os == "android") or (bits == 32): not implemented [Encoding and decoding cycle] expected: [PASS, FAIL] diff --git a/testing/web-platform/meta/webcodecs/reconfiguring-encoder.https.any.js.ini b/testing/web-platform/meta/webcodecs/reconfiguring-encoder.https.any.js.ini index 5f37771e1170..7371f71a20d8 100644 --- a/testing/web-platform/meta/webcodecs/reconfiguring-encoder.https.any.js.ini +++ b/testing/web-platform/meta/webcodecs/reconfiguring-encoder.https.any.js.ini @@ -1,6 +1,6 @@ [reconfiguring-encoder.https.any.worker.html?h264_avc] disabled: - if (os == "android") or (version == "Ubuntu 18.04"): not implemented + if (os == "mac") or (os == "android") or (version == "Ubuntu 18.04"): not implemented [reconfiguring-encoder.https.any.html?av1] disabled: @@ -20,11 +20,11 @@ [reconfiguring-encoder.https.any.html?h264_annexb] disabled: - if (os == "android") or (version == "Ubuntu 18.04"): not implemented + if (os == "mac") or (os == "android") or (version == "Ubuntu 18.04"): not implemented [reconfiguring-encoder.https.any.worker.html?h264_annexb] disabled: - if (os == "android") or (version == "Ubuntu 18.04"): not implemented + if (os == "mac") or (os == "android") or (version == "Ubuntu 18.04"): not implemented [reconfiguring-encoder.https.any.html?vp9_p2] disabled: @@ -46,7 +46,7 @@ [reconfiguring-encoder.https.any.html?h264_avc] disabled: - if (os == "android") or (version == "Ubuntu 18.04"): not implemented + if (os == "mac") or (os == "android") or (version == "Ubuntu 18.04"): not implemented [reconfiguring-encoder.https.any.html?vp8] disabled: diff --git a/testing/web-platform/meta/webcodecs/temporal-svc-encoding.https.any.js.ini b/testing/web-platform/meta/webcodecs/temporal-svc-encoding.https.any.js.ini index 48329d34de09..9b99c75bd6d1 100644 --- a/testing/web-platform/meta/webcodecs/temporal-svc-encoding.https.any.js.ini +++ b/testing/web-platform/meta/webcodecs/temporal-svc-encoding.https.any.js.ini @@ -10,15 +10,7 @@ if (os == "win") or (os == "android"): not implemented [temporal-svc-encoding.https.any.worker.html?h264] - disabled: - if (os == "win") or (os == "linux") or (os == "android"): not implemented - [SVC L1T2] - expected: - if (os == "mac") and (os_version == "10.15"): PRECONDITION_FAILED - PASS - [SVC L1T3] - expected: PRECONDITION_FAILED - + disabled: not implemented [temporal-svc-encoding.https.any.html?av1] disabled: not implemented @@ -28,16 +20,9 @@ if (os == "win") or (os == "android"): not implemented [temporal-svc-encoding.https.any.html?h264] - disabled: - if (os == "win") or (os == "linux") or (os == "android"): not implemented - [SVC L1T2] - expected: - if (os == "mac") and (os_version == "10.15"): PRECONDITION_FAILED - PASS - [SVC L1T3] - expected: PRECONDITION_FAILED - + disabled: not implemented [temporal-svc-encoding.https.any.html?vp9] disabled: if (os == "win") or (os == "android"): not implemented + diff --git a/testing/web-platform/meta/webcodecs/video-encoder-flush.https.any.js.ini b/testing/web-platform/meta/webcodecs/video-encoder-flush.https.any.js.ini index 9d3f5858d03e..baba28e119cd 100644 --- a/testing/web-platform/meta/webcodecs/video-encoder-flush.https.any.js.ini +++ b/testing/web-platform/meta/webcodecs/video-encoder-flush.https.any.js.ini @@ -8,11 +8,11 @@ [video-encoder-flush.https.any.worker.html?h264_annexb] disabled: - if (os == "android") or (version == "Ubuntu 18.04"): not implemented + if (os == "mac") or (os == "android") or (version == "Ubuntu 18.04"): not implemented [video-encoder-flush.https.any.html?h264_annexb] disabled: - if (os == "android") or (version == "Ubuntu 18.04"): not implemented + if (os == "mac") or (os == "android") or (version == "Ubuntu 18.04"): not implemented [video-encoder-flush.https.any.worker.html?vp8] disabled: @@ -24,8 +24,8 @@ [video-encoder-flush.https.any.worker.html?h264_avc] disabled: - if (os == "android") or (version == "Ubuntu 18.04"): not implemented + if (os == "mac") or (os == "android") or (version == "Ubuntu 18.04"): not implemented [video-encoder-flush.https.any.html?h264_avc] disabled: - if (os == "android") or (version == "Ubuntu 18.04"): not implemented + if (os == "mac") or (os == "android") or (version == "Ubuntu 18.04"): not implemented diff --git a/testing/web-platform/meta/webcodecs/videoFrame-createImageBitmap.https.any.js.ini b/testing/web-platform/meta/webcodecs/videoFrame-createImageBitmap.https.any.js.ini index 5a2f40deec49..c96d63e442b4 100644 --- a/testing/web-platform/meta/webcodecs/videoFrame-createImageBitmap.https.any.js.ini +++ b/testing/web-platform/meta/webcodecs/videoFrame-createImageBitmap.https.any.js.ini @@ -1,13 +1,13 @@ [videoFrame-createImageBitmap.https.any.html] disabled: - if (os == "android"): not implemented + if (os == "macOS") or (os == "android"): not implemented [Create ImageBitmap for a VideoFrame from VP9 decoder.] expected: if (os == "win") and ccov: FAIL [videoFrame-createImageBitmap.https.any.worker.html] disabled: - if (os == "android"): not implemented + if (os == "macOS") or (os == "android"): not implemented [Create ImageBitmap for a VideoFrame from VP9 decoder.] expected: if (os == "win") and ccov: FAIL