Call was negotiated with H264 Base Profile 42e01f but encoded in High Profile
authoryouenn@apple.com <youenn@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 10 Jun 2019 15:59:14 +0000 (15:59 +0000)
committeryouenn@apple.com <youenn@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 10 Jun 2019 15:59:14 +0000 (15:59 +0000)
https://bugs.webkit.org/show_bug.cgi?id=195124
<rdar://problem/48453085>

Reviewed by Eric Carlson.

Source/ThirdParty/libwebrtc:

Use VTB directly instead of VCP when baseline is requested.
For platforms supporting the VCP-in-VTB API, use VCP for high profile, VTB for baseline.
For platforms not supporting the VCP-in-VTB API, use regular VTB for both baseline and high profile.
On MacOS, if VTB session creation fails, use VCP as a fallback.
Keep VTB-only code path for non internal builds.

* Source/webrtc/sdk/WebKit/EncoderUtilities.h: Removed.
* Source/webrtc/sdk/WebKit/VideoProcessingSoftLink.h:
* Source/webrtc/sdk/objc/components/video_codec/RTCVideoEncoderH264.mm:
(-[RTCSingleVideoEncoderH264 initWithCodecInfo:simulcastIndex:]):
(-[RTCSingleVideoEncoderH264 hasCompressionSession]):
(-[RTCSingleVideoEncoderH264 encode:codecSpecificInfo:frameTypes:]):
(-[RTCSingleVideoEncoderH264 resetCompressionSessionIfNeededWithFrame:]):
(-[RTCSingleVideoEncoderH264 resetCompressionSessionWithPixelFormat:]):
(-[RTCSingleVideoEncoderH264 configureCompressionSession]):
(-[RTCSingleVideoEncoderH264 destroyCompressionSession]):
(-[RTCSingleVideoEncoderH264 setEncoderBitrateBps:]):
* Source/webrtc/sdk/objc/components/video_codec/helpers.cc:
* Source/webrtc/sdk/objc/components/video_codec/helpers.h:

LayoutTests:

* webrtc/video-h264-expected.txt: Added.
* webrtc/video-h264.html: Added.

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@246263 268f45cc-cd09-0410-ab3c-d52691b4dbfc

LayoutTests/ChangeLog
LayoutTests/webrtc/video-h264-expected.txt [new file with mode: 0644]
LayoutTests/webrtc/video-h264.html [new file with mode: 0644]
Source/ThirdParty/libwebrtc/ChangeLog
Source/ThirdParty/libwebrtc/Source/webrtc/sdk/WebKit/EncoderUtilities.h [deleted file]
Source/ThirdParty/libwebrtc/Source/webrtc/sdk/WebKit/VideoProcessingSoftLink.h
Source/ThirdParty/libwebrtc/Source/webrtc/sdk/objc/components/video_codec/RTCVideoEncoderH264.mm
Source/ThirdParty/libwebrtc/Source/webrtc/sdk/objc/components/video_codec/helpers.cc
Source/ThirdParty/libwebrtc/Source/webrtc/sdk/objc/components/video_codec/helpers.h

index 74e8b9e..238810e 100644 (file)
@@ -1,3 +1,14 @@
+2019-06-10  Youenn Fablet  <youenn@apple.com>
+
+        Call was negotiated with H264 Base Profile 42e01f but encoded in High Profile
+        https://bugs.webkit.org/show_bug.cgi?id=195124
+        <rdar://problem/48453085>
+
+        Reviewed by Eric Carlson.
+
+        * webrtc/video-h264-expected.txt: Added.
+        * webrtc/video-h264.html: Added.
+
 2019-06-08  Cathie Chen  <cathiechen@igalia.com>
 
         resize-observer/element-leak.html fails on Windows platform
diff --git a/LayoutTests/webrtc/video-h264-expected.txt b/LayoutTests/webrtc/video-h264-expected.txt
new file mode 100644 (file)
index 0000000..00a88ce
--- /dev/null
@@ -0,0 +1,5 @@
+
+
+PASS Baseline H264 
+PASS High H264 
+
diff --git a/LayoutTests/webrtc/video-h264.html b/LayoutTests/webrtc/video-h264.html
new file mode 100644 (file)
index 0000000..3fd04f6
--- /dev/null
@@ -0,0 +1,96 @@
+<!doctype html>
+<html>
+    <head>
+        <meta charset="utf-8">
+        <title>Testing H264 baseline and high profile</title>
+        <script src="../resources/testharness.js"></script>
+        <script src="../resources/testharnessreport.js"></script>
+    </head>
+    <body>
+        <video id="video" autoplay=""></video>
+        <canvas id="canvas" width="640" height="480"></canvas>
+        <script src ="routines.js"></script>
+        <script>
+function grabFrameData(x, y, w, h)
+{
+    canvas.width = video.videoWidth;
+    canvas.height = video.videoHeight;
+
+    canvas.getContext('2d').drawImage(video, x, y, w, h, x, y, w, h);
+    return canvas.getContext('2d').getImageData(x, y, w, h).data;
+}
+
+function testImage()
+{
+    const data = grabFrameData(10, 325, 250, 1);
+
+    var index = 20;
+    assert_true(data[index] < 100);
+    assert_true(data[index + 1] < 100);
+    assert_true(data[index + 2] < 100);
+
+    index = 80;
+    assert_true(data[index] > 200);
+    assert_true(data[index + 1] > 200);
+    assert_true(data[index + 2] > 200);
+
+    index += 80;
+    assert_true(data[index] > 200);
+    assert_true(data[index + 1] > 200);
+    assert_true(data[index + 2] < 100);
+}
+
+promise_test(async (test) => {
+    if (window.testRunner)
+        testRunner.setUserMediaPermission(true);
+
+    const localStream = await navigator.mediaDevices.getUserMedia({video: true});
+    const stream = await new Promise((resolve, reject) => {
+        createConnections((firstConnection) => {
+            firstConnection.addTrack(localStream.getVideoTracks()[0], localStream);
+        }, (secondConnection) => {
+            secondConnection.ontrack = (trackEvent) => {
+                resolve(trackEvent.streams[0]);
+            };
+        }, { observeOffer : (offer) => {
+            offer.sdp = offer.sdp.replace("640c1f", "42e01f");
+            return offer;
+        }
+        });
+        setTimeout(() => reject("Test timed out"), 5000);
+    });
+
+    video.srcObject = stream;
+    await video.play();
+
+    testImage();
+}, "Baseline H264");
+
+promise_test(async (test) => {
+    if (window.testRunner)
+        testRunner.setUserMediaPermission(true);
+
+    const localStream = await navigator.mediaDevices.getUserMedia({video: true});
+    const stream = await new Promise((resolve, reject) => {
+        createConnections((firstConnection) => {
+            firstConnection.addTrack(localStream.getVideoTracks()[0], localStream);
+        }, (secondConnection) => {
+            secondConnection.ontrack = (trackEvent) => {
+                resolve(trackEvent.streams[0]);
+            };
+        }, { observeOffer : (offer) => {
+            offer.sdp = offer.sdp.replace("42e01f", "640c1f");
+            return offer;
+        }
+        });
+        setTimeout(() => reject("Test timed out"), 5000);
+    });
+
+    video.srcObject = stream;
+    await video.play();
+
+    testImage();
+}, "High H264");
+        </script>
+    </body>
+</html>
index 8aff98d..32bd438 100644 (file)
@@ -1,3 +1,31 @@
+2019-06-10  Youenn Fablet  <youenn@apple.com>
+
+        Call was negotiated with H264 Base Profile 42e01f but encoded in High Profile
+        https://bugs.webkit.org/show_bug.cgi?id=195124
+        <rdar://problem/48453085>
+
+        Reviewed by Eric Carlson.
+
+        Use VTB directly instead of VCP when baseline is requested.
+        For platforms supporting the VCP-in-VTB API, use VCP for high profile, VTB for baseline.
+        For platforms not supporting the VCP-in-VTB API, use regular VTB for both baseline and high profile.
+        On MacOS, if VTB session creation fails, use VCP as a fallback.
+        Keep VTB-only code path for non internal builds.
+
+        * Source/webrtc/sdk/WebKit/EncoderUtilities.h: Removed.
+        * Source/webrtc/sdk/WebKit/VideoProcessingSoftLink.h:
+        * Source/webrtc/sdk/objc/components/video_codec/RTCVideoEncoderH264.mm:
+        (-[RTCSingleVideoEncoderH264 initWithCodecInfo:simulcastIndex:]):
+        (-[RTCSingleVideoEncoderH264 hasCompressionSession]):
+        (-[RTCSingleVideoEncoderH264 encode:codecSpecificInfo:frameTypes:]):
+        (-[RTCSingleVideoEncoderH264 resetCompressionSessionIfNeededWithFrame:]):
+        (-[RTCSingleVideoEncoderH264 resetCompressionSessionWithPixelFormat:]):
+        (-[RTCSingleVideoEncoderH264 configureCompressionSession]):
+        (-[RTCSingleVideoEncoderH264 destroyCompressionSession]):
+        (-[RTCSingleVideoEncoderH264 setEncoderBitrateBps:]):
+        * Source/webrtc/sdk/objc/components/video_codec/helpers.cc:
+        * Source/webrtc/sdk/objc/components/video_codec/helpers.h:
+
 2019-05-28  Youenn Fablet  <youenn@apple.com>
 
         createAnswer() SDP Rejected by setLocalDescription()
diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/sdk/WebKit/EncoderUtilities.h b/Source/ThirdParty/libwebrtc/Source/webrtc/sdk/WebKit/EncoderUtilities.h
deleted file mode 100644 (file)
index 5b9bdfd..0000000
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * Copyright (C) 2018 Apple Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
- * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
- * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
- * THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#pragma once
-
-#include "VideoProcessingSoftLink.h"
-
-#if ENABLE_VCP_ENCODER
-
-#define CompressionSessionRef VCPCompressionSessionRef
-#define CompressionSessionSetProperty webrtc::VCPCompressionSessionSetProperty
-#define CompressionSessionGetPixelBufferPool webrtc::VCPCompressionSessionGetPixelBufferPool
-#define CompressionSessionEncodeFrame webrtc::VCPCompressionSessionEncodeFrame
-#define CompressionSessionCreate webrtc::VCPCompressionSessionCreate
-#define kCodecTypeH264 kVCPCodecType4CC_H264
-#define CompressionSessionInvalidate webrtc::VCPCompressionSessionInvalidate
-
-#else
-
-#define CompressionSessionRef VTCompressionSessionRef
-#define CompressionSessionSetProperty VTSessionSetProperty
-#define CompressionSessionGetPixelBufferPool VTCompressionSessionGetPixelBufferPool
-#define CompressionSessionEncodeFrame VTCompressionSessionEncodeFrame
-#define CompressionSessionCreate VTCompressionSessionCreate
-#define kCodecTypeH264 kCMVideoCodecType_H264
-#define CompressionSessionInvalidate VTCompressionSessionInvalidate
-
-#endif
index c26c4fd..f9c1f3c 100644 (file)
 // Macro taken from WTF/wtf/Platform.h
 #if defined __has_include && __has_include(<CoreFoundation/CFPriv.h>)
 
-#if (defined(TARGET_IPHONE_SIMULATOR)  && TARGET_IPHONE_SIMULATOR)
+#if (defined(TARGET_IPHONE_SIMULATOR) && TARGET_IPHONE_SIMULATOR)
 #define ENABLE_VCP_ENCODER 0
 #define ENABLE_VCP_VTB_ENCODER 0
-#elif (defined(TARGET_OS_IPHONE)  && TARGET_OS_IPHONE)
-#define ENABLE_VCP_ENCODER __MAC_OS_X_VERSION_MAX_ALLOWED < 101500
+#elif (defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE)
+#define ENABLE_VCP_ENCODER 1
 #define ENABLE_VCP_VTB_ENCODER __MAC_OS_X_VERSION_MIN_REQUIRED >= 101500
 #elif (defined(TARGET_OS_MAC) && TARGET_OS_MAC)
-#define ENABLE_VCP_ENCODER (__MAC_OS_X_VERSION_MIN_REQUIRED >= 101300 && __MAC_OS_X_VERSION_MAX_ALLOWED < 101500)
+#define ENABLE_VCP_ENCODER __MAC_OS_X_VERSION_MIN_REQUIRED >= 101300
 #define ENABLE_VCP_VTB_ENCODER __MAC_OS_X_VERSION_MIN_REQUIRED >= 101500
 #endif
 
@@ -145,6 +145,8 @@ SOFT_LINK_FUNCTION_FOR_HEADER(webrtc, VideoProcessing, VCPCompressionSessionCrea
 SOFT_LINK_FUNCTION_FOR_HEADER(webrtc, VideoProcessing, VCPCompressionSessionInvalidate, void, (VCPCompressionSessionRef session), (session))
 #define VCPCompressionSessionInvalidate softLink_VideoProcessing_VCPCompressionSessionInvalidate
 
+#else
+using VCPCompressionSessionRef = void*;
 #endif // ENABLE_VCP_ENCODER
 
 #endif // __APPLE__
index ef59179..ebe3adf 100644 (file)
@@ -31,7 +31,6 @@
 #include "system_wrappers/include/clock.h"
 #include "third_party/libyuv/include/libyuv/convert_from.h"
 
-#include "sdk/WebKit/EncoderUtilities.h"
 #include "sdk/WebKit/WebKitUtilities.h"
 
 #import <dlfcn.h>
@@ -40,7 +39,7 @@
 VT_EXPORT const CFStringRef kVTVideoEncoderSpecification_Usage;
 VT_EXPORT const CFStringRef kVTCompressionPropertyKey_Usage;
 
-#if !ENABLE_VCP_ENCODER && !defined(WEBRTC_IOS) && !ENABLE_VCP_VTB_ENCODER
+#if defined(WEBRTC_MAC) && !defined(WEBRTC_IOS) && !ENABLE_VCP_ENCODER
 static inline bool isStandardFrameSize(int32_t width, int32_t height)
 {
     // FIXME: Envision relaxing this rule, something like width and height dividable by 4 or 8 should be good enough.
@@ -318,7 +317,9 @@ CFStringRef ExtractProfile(webrtc::SdpVideoFormat videoFormat) {
   RTCVideoEncoderCallback _callback;
   int32_t _width;
   int32_t _height;
-  CompressionSessionRef _compressionSession;
+  bool _useVCP;
+  VTCompressionSessionRef _vtCompressionSession;
+  VCPCompressionSessionRef _vcpCompressionSession;
   CVPixelBufferPoolRef _pixelBufferPool;
   RTCVideoCodecMode _mode;
 
@@ -343,6 +344,11 @@ CFStringRef ExtractProfile(webrtc::SdpVideoFormat videoFormat) {
     _bitrateAdjuster.reset(new webrtc::BitrateAdjuster(.5, .95));
     _packetizationMode = RTCH264PacketizationModeNonInterleaved;
     _profile = ExtractProfile([codecInfo nativeSdpVideoFormat]);
+#if ENABLE_VCP_VTB_ENCODER
+    _useVCP = [(__bridge NSString *)_profile containsString: @"High"];
+#else
+    _useVCP = false;
+#endif
     _simulcastIndex = index;
     RTC_LOG(LS_INFO) << "Using profile " << CFStringToString(_profile);
     RTC_CHECK([codecInfo.name isEqualToString:kRTCVideoCodecH264Name]);
@@ -376,12 +382,17 @@ CFStringRef ExtractProfile(webrtc::SdpVideoFormat videoFormat) {
   return [self resetCompressionSessionWithPixelFormat:kNV12PixelFormat];
 }
 
+- (bool)hasCompressionSession
+{
+    return _vtCompressionSession || _vcpCompressionSession;
+}
+
 - (NSInteger)encode:(RTCVideoFrame *)frame
     codecSpecificInfo:(nullable id<RTCCodecSpecificInfo>)codecSpecificInfo
            frameTypes:(NSArray<NSNumber *> *)frameTypes {
   RTC_DCHECK_EQ(frame.width, _width);
   RTC_DCHECK_EQ(frame.height, _height);
-  if (!_callback || !_compressionSession) {
+  if (!_callback || ![self hasCompressionSession]) {
     return WEBRTC_VIDEO_CODEC_UNINITIALIZED;
   }
   BOOL isKeyframeRequired = NO;
@@ -474,13 +485,28 @@ CFStringRef ExtractProfile(webrtc::SdpVideoFormat videoFormat) {
   // Update the bitrate if needed.
   [self setBitrateBps:_bitrateAdjuster->GetAdjustedBitrateBps()];
 
-  OSStatus status = CompressionSessionEncodeFrame(_compressionSession,
+  OSStatus status;
+  if (_vtCompressionSession) {
+    status = VTCompressionSessionEncodeFrame(_vtCompressionSession,
+                                                    pixelBuffer,
+                                                    presentationTimeStamp,
+                                                    kCMTimeInvalid,
+                                                    frameProperties,
+                                                    encodeParams.release(),
+                                                    nullptr);
+  } else {
+#if ENABLE_VCP_ENCODER
+    status = webrtc::VCPCompressionSessionEncodeFrame(_vcpCompressionSession,
                                                     pixelBuffer,
                                                     presentationTimeStamp,
                                                     kCMTimeInvalid,
                                                     frameProperties,
                                                     encodeParams.release(),
                                                     nullptr);
+#else
+    status = 1;
+#endif
+  }
   if (frameProperties) {
     CFRelease(frameProperties);
   }
@@ -540,7 +566,7 @@ CFStringRef ExtractProfile(webrtc::SdpVideoFormat videoFormat) {
   // configured with, make sure the compression session is reset using the correct pixel format.
   OSType framePixelFormat = [self pixelFormatOfFrame:frame];
 
-  if (_compressionSession) {
+  if ([self hasCompressionSession]) {
 #if defined(WEBRTC_WEBKIT_BUILD)
     if (!_pixelBufferPool) {
       return NO;
@@ -618,60 +644,83 @@ CFStringRef ExtractProfile(webrtc::SdpVideoFormat videoFormat) {
 #endif
   CFDictionarySetValue(encoderSpecs, kVTCompressionPropertyKey_RealTime, kCFBooleanTrue);
 
-#if ENABLE_VCP_ENCODER || ENABLE_VCP_VTB_ENCODER
-  int usageValue = 1;
-  auto usage = CFNumberCreate(nullptr, kCFNumberIntType, &usageValue);
-  CFDictionarySetValue(encoderSpecs, kVTCompressionPropertyKey_Usage, usage);
-  CFRelease(usage);
+#if ENABLE_VCP_ENCODER
+  if (_useVCP) {
+    int usageValue = 1;
+    auto usage = CFNumberCreate(nullptr, kCFNumberIntType, &usageValue);
+    CFDictionarySetValue(encoderSpecs, kVTCompressionPropertyKey_Usage, usage);
+    CFRelease(usage);
+  }
 #endif
 #if ENABLE_VCP_VTB_ENCODER
+  if (_useVCP) {
     CFDictionarySetValue(encoderSpecs, kVTVideoEncoderList_EncoderID, CFSTR("com.apple.videotoolbox.videoencoder.h264.rtvc"));
+  }
 #endif
   OSStatus status =
-      CompressionSessionCreate(nullptr,  // use default allocator
+      VTCompressionSessionCreate(nullptr,  // use default allocator
                                  _width,
                                  _height,
-                                 kCodecTypeH264,
+                                 kCMVideoCodecType_H264,
                                  encoderSpecs,  // use hardware accelerated encoder if available
                                  sourceAttributes,
                                  nullptr,  // use default compressed data allocator
                                  compressionOutputCallback,
                                  nullptr,
-                                 &_compressionSession);
-  if (sourceAttributes) {
-    CFRelease(sourceAttributes);
-    sourceAttributes = nullptr;
-  }
-  if (encoderSpecs) {
-    CFRelease(encoderSpecs);
-    encoderSpecs = nullptr;
-  }
+                                 &_vtCompressionSession);
 
-#if ENABLE_VCP_ENCODER || defined(WEBRTC_IOS)
-  if (status != noErr) {
-    RTC_LOG(LS_ERROR) << "Failed to create compression session: " << status;
-    return WEBRTC_VIDEO_CODEC_ERROR;
-  }
-#endif
 #if defined(WEBRTC_MAC) && !defined(WEBRTC_IOS)
-  CFBooleanRef hwaccl_enabled = nullptr;
-  if (status == noErr) {
-    status = VTSessionCopyProperty(_compressionSession,
+#if ENABLE_VCP_ENCODER
+  if (!_useVCP) {
+    CFBooleanRef hwaccl_enabled = nullptr;
+    if (status == noErr) {
+      status = VTSessionCopyProperty(_vtCompressionSession,
                                  kVTCompressionPropertyKey_UsingHardwareAcceleratedVideoEncoder,
                                  nullptr,
                                  &hwaccl_enabled);
+    }
+    if (status == noErr && (CFBooleanGetValue(hwaccl_enabled))) {
+      RTC_LOG(LS_INFO) << "Compression session created with hw accl enabled";
+    } else {
+      [self destroyCompressionSession];
+
+      // Use VCP instead.
+      int usageValue = 1;
+      auto usage = CFNumberCreate(nullptr, kCFNumberIntType, &usageValue);
+      CFDictionarySetValue(encoderSpecs, kVTCompressionPropertyKey_Usage, usage);
+      CFRelease(usage);
+
+      RTC_LOG(LS_INFO) << "Compression session created with VCP";
+      status =
+          webrtc::VCPCompressionSessionCreate(nullptr,  // use default allocator
+                                 _width,
+                                 _height,
+                                 kVCPCodecType4CC_H264,
+                                 encoderSpecs,
+                                 sourceAttributes,
+                                 nullptr,  // use default compressed data allocator
+                                 compressionOutputCallback,
+                                 nullptr,
+                                 &_vcpCompressionSession);
+    }
   }
-  if (status == noErr && (CFBooleanGetValue(hwaccl_enabled))) {
-    RTC_LOG(LS_INFO) << "Compression session created with hw accl enabled";
-  } else {
-    RTC_LOG(LS_INFO) << "Compression session created with hw accl disabled";
+#else
+  if (status != noErr) {
+    if (encoderSpecs) {
+        CFRelease(encoderSpecs);
+        encoderSpecs = nullptr;
+    }
+    if (sourceAttributes) {
+      CFRelease(sourceAttributes);
+      sourceAttributes = nullptr;
+    }
 
-#if !ENABLE_VCP_ENCODER && !ENABLE_VCP_VTB_ENCODER && !defined(WEBRTC_IOS)
     if (!isStandardFrameSize(_width, _height)) {
       _disableEncoding = true;
       RTC_LOG(LS_ERROR) << "Using H264 software encoder with non standard size is not supported";
       return WEBRTC_VIDEO_CODEC_ERROR;
     }
+    [self destroyCompressionSession];
 
     CFDictionaryRef ioSurfaceValue = CreateCFTypeDictionary(nullptr, nullptr, 0);
     int64_t pixelFormatType = framePixelFormat;
@@ -687,7 +736,7 @@ CFStringRef ExtractProfile(webrtc::SdpVideoFormat videoFormat) {
       kCFBooleanTrue,
       ioSurfaceValue,
       pixelFormat};
-    CFDictionaryRef sourceAttributes = CreateCFTypeDictionary(keys, values, attributesSize);
+    sourceAttributes = CreateCFTypeDictionary(keys, values, attributesSize);
 
     if (ioSurfaceValue) {
       CFRelease(ioSurfaceValue);
@@ -698,61 +747,67 @@ CFStringRef ExtractProfile(webrtc::SdpVideoFormat videoFormat) {
       pixelFormat = nullptr;
     }
 
-    CFMutableDictionaryRef encoderSpecs = CFDictionaryCreateMutable(nullptr, 2, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
+    encoderSpecs = CFDictionaryCreateMutable(nullptr, 2, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
     CFDictionarySetValue(encoderSpecs, kVTVideoEncoderSpecification_EnableHardwareAcceleratedVideoEncoder, kCFBooleanFalse);
     int usageValue = 1;
     CFNumberRef usage = CFNumberCreate(nullptr, kCFNumberIntType, &usageValue);
     CFDictionarySetValue(encoderSpecs, kVTVideoEncoderSpecification_Usage, usage);
-
     if (usage) {
       CFRelease(usage);
       usage = nullptr;
     }
-
-    [self destroyCompressionSession];
-
-    OSStatus status =
-      CompressionSessionCreate(nullptr,  // use default allocator
+    status = VTCompressionSessionCreate(nullptr,  // use default allocator
                                  _width,
                                  _height,
-                                 kCodecTypeH264,
-                                 encoderSpecs,
+                                 kCMVideoCodecType_H264,
+                                 encoderSpecs,  // use hardware accelerated encoder if available
                                  sourceAttributes,
                                  nullptr,  // use default compressed data allocator
                                  compressionOutputCallback,
                                  nullptr,
-                                 &_compressionSession);
-    if (sourceAttributes) {
-      CFRelease(sourceAttributes);
-      sourceAttributes = nullptr;
-    }
-    if (encoderSpecs) {
-      CFRelease(encoderSpecs);
-      encoderSpecs = nullptr;
-    }
-    if (status != noErr) {
-      return WEBRTC_VIDEO_CODEC_ERROR;
-    }
-#endif
+                                 &_vtCompressionSession);
+
   }
-#endif
+#endif // ENABLE_VCP_ENCODER
+#endif // defined(WEBRTC_MAC) && !defined(WEBRTC_IOS)
+  if (sourceAttributes) {
+    CFRelease(sourceAttributes);
+    sourceAttributes = nullptr;
+  }
+  if (encoderSpecs) {
+    CFRelease(encoderSpecs);
+    encoderSpecs = nullptr;
+  }
+
+  if (status != noErr) {
+    RTC_LOG(LS_ERROR) << "Failed to create compression session: " << status;
+    return WEBRTC_VIDEO_CODEC_ERROR;
+  }
+
   [self configureCompressionSession];
 
 #if !defined(WEBRTC_WEBKIT_BUILD)
   // The pixel buffer pool is dependent on the compression session so if the session is reset, the
   // pool should be reset as well.
-  _pixelBufferPool = CompressionSessionGetPixelBufferPool(_compressionSession);
+  if (_vtCompressionSession)
+    _pixelBufferPool = VTCompressionSessionGetPixelBufferPool(_vtCompressionSession);
+#if ENABLE_VCP_ENCODER
+  else
+    _pixelBufferPool = webrtc::VCPCompressionSessionGetPixelBufferPool(_vtCompressionSession);
+#endif
 #endif
   return WEBRTC_VIDEO_CODEC_OK;
 }
 
 - (void)configureCompressionSession {
-  RTC_DCHECK(_compressionSession);
-  SetVTSessionProperty(_compressionSession, kVTCompressionPropertyKey_RealTime, true);
-  SetVTSessionProperty(_compressionSession, kVTCompressionPropertyKey_ProfileLevel, _profile);
-  SetVTSessionProperty(_compressionSession, kVTCompressionPropertyKey_AllowFrameReordering, false);
+  RTC_DCHECK([self hasCompressionSession]);
+  SetVTSessionProperty(_vtCompressionSession, _vcpCompressionSession, kVTCompressionPropertyKey_RealTime, true);
+  SetVTSessionProperty(_vtCompressionSession, _vcpCompressionSession, kVTCompressionPropertyKey_ProfileLevel, _profile);
+  SetVTSessionProperty(_vtCompressionSession, _vcpCompressionSession, kVTCompressionPropertyKey_AllowFrameReordering, false);
 #if ENABLE_VCP_ENCODER
-  SetVTSessionProperty(_compressionSession, kVTCompressionPropertyKey_Usage, 1);
+  if (_useVCP) {
+    SetVTSessionProperty(_vtCompressionSession, _vcpCompressionSession, kVTCompressionPropertyKey_Usage, 1);
+  }
 #endif
   [self setEncoderBitrateBps:_targetBitrateBps];
   // TODO(tkchin): Look at entropy mode and colorspace matrices.
@@ -764,18 +819,24 @@ CFStringRef ExtractProfile(webrtc::SdpVideoFormat videoFormat) {
   //     1);
 
   // Set a relatively large value for keyframe emission (7200 frames or 4 minutes).
-  SetVTSessionProperty(_compressionSession, kVTCompressionPropertyKey_MaxKeyFrameInterval, 7200);
-  SetVTSessionProperty(
-      _compressionSession, kVTCompressionPropertyKey_MaxKeyFrameIntervalDuration, 240);
+  SetVTSessionProperty(_vtCompressionSession, _vcpCompressionSession, kVTCompressionPropertyKey_MaxKeyFrameInterval, 7200);
+  SetVTSessionProperty(_vtCompressionSession, _vcpCompressionSession, kVTCompressionPropertyKey_MaxKeyFrameIntervalDuration, 240);
 }
 
 - (void)destroyCompressionSession {
-  if (_compressionSession) {
-    CompressionSessionInvalidate(_compressionSession);
-    CFRelease(_compressionSession);
-    _compressionSession = nullptr;
-    _pixelBufferPool = nullptr;
+  if (_vtCompressionSession) {
+    VTCompressionSessionInvalidate(_vtCompressionSession);
+    CFRelease(_vtCompressionSession);
+    _vtCompressionSession = nullptr;
   }
+#if ENABLE_VCP_ENCODER
+  if (_vcpCompressionSession) {
+    webrtc::VCPCompressionSessionInvalidate(_vcpCompressionSession);
+    CFRelease(_vcpCompressionSession);
+    _vcpCompressionSession = nullptr;
+  }
+#endif
+  _pixelBufferPool = nullptr;
 }
 
 - (NSString *)implementationName {
@@ -789,8 +850,8 @@ CFStringRef ExtractProfile(webrtc::SdpVideoFormat videoFormat) {
 }
 
 - (void)setEncoderBitrateBps:(uint32_t)bitrateBps {
-  if (_compressionSession) {
-    SetVTSessionProperty(_compressionSession, kVTCompressionPropertyKey_AverageBitRate, bitrateBps);
+  if ([self hasCompressionSession]) {
+    SetVTSessionProperty(_vtCompressionSession, _vcpCompressionSession, kVTCompressionPropertyKey_AverageBitRate, bitrateBps);
 
     // TODO(tkchin): Add a helper method to set array value.
     int64_t dataLimitBytesPerSecondValue =
@@ -802,8 +863,19 @@ CFStringRef ExtractProfile(webrtc::SdpVideoFormat videoFormat) {
         CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt64Type, &oneSecondValue);
     const void *nums[2] = {bytesPerSecond, oneSecond};
     CFArrayRef dataRateLimits = CFArrayCreate(nullptr, nums, 2, &kCFTypeArrayCallBacks);
-    OSStatus status = CompressionSessionSetProperty(
-        _compressionSession, kVTCompressionPropertyKey_DataRateLimits, dataRateLimits);
+
+    OSStatus status = noErr;
+    if (_vtCompressionSession)
+      VTSessionSetProperty(_vtCompressionSession, kVTCompressionPropertyKey_DataRateLimits, dataRateLimits);
+#if ENABLE_VCP_ENCODER
+    else
+      webrtc::VCPCompressionSessionSetProperty(_vcpCompressionSession, kVTCompressionPropertyKey_DataRateLimits, dataRateLimits);
+#endif
+    if (status != noErr) {
+      RTC_LOG(LS_ERROR) << "VTSessionSetProperty failed to set: " << kVTCompressionPropertyKey_DataRateLimits
+        << ": " << status;
+    }
+
     if (bytesPerSecond) {
       CFRelease(bytesPerSecond);
     }
@@ -813,10 +885,6 @@ CFStringRef ExtractProfile(webrtc::SdpVideoFormat videoFormat) {
     if (dataRateLimits) {
       CFRelease(dataRateLimits);
     }
-    if (status != noErr) {
-      RTC_LOG(LS_ERROR) << "Failed to set data rate limit";
-    }
-
     _encoderBitrateBps = bitrateBps;
   }
 }
index 46daf44..a8e2062 100644 (file)
@@ -35,12 +35,19 @@ std::string CFStringToString(const CFStringRef cf_string) {
 }
 
 // Convenience function for setting a VT property.
-void SetVTSessionProperty(CompressionSessionRef session,
+void SetVTSessionProperty(VTCompressionSessionRef vtSession, VCPCompressionSessionRef vcpSession,
                           CFStringRef key,
                           int32_t value) {
+  RTC_DCHECK(vtSession || vcpSession);
   CFNumberRef cfNum =
       CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &value);
-  OSStatus status = CompressionSessionSetProperty(session, key, cfNum);
+  OSStatus status = noErr;
+  if (vtSession)
+    status = VTSessionSetProperty(vtSession, key, cfNum);
+#if ENABLE_VCP_ENCODER
+  else
+    status = webrtc::VCPCompressionSessionSetProperty(vcpSession, key, cfNum);
+#endif
   CFRelease(cfNum);
   if (status != noErr) {
     std::string key_string = CFStringToString(key);
@@ -50,13 +57,20 @@ void SetVTSessionProperty(CompressionSessionRef session,
 }
 
 // Convenience function for setting a VT property.
-void SetVTSessionProperty(CompressionSessionRef session,
+void SetVTSessionProperty(VTCompressionSessionRef vtSession, VCPCompressionSessionRef vcpSession,
                           CFStringRef key,
                           uint32_t value) {
+  RTC_DCHECK(vtSession || vcpSession);
   int64_t value_64 = value;
   CFNumberRef cfNum =
       CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt64Type, &value_64);
-  OSStatus status = CompressionSessionSetProperty(session, key, cfNum);
+  OSStatus status = noErr;
+  if (vtSession)
+    status = VTSessionSetProperty(vtSession, key, cfNum);
+#if ENABLE_VCP_ENCODER
+  else
+    status = webrtc::VCPCompressionSessionSetProperty(vcpSession, key, cfNum);
+#endif
   CFRelease(cfNum);
   if (status != noErr) {
     std::string key_string = CFStringToString(key);
@@ -66,9 +80,16 @@ void SetVTSessionProperty(CompressionSessionRef session,
 }
 
 // Convenience function for setting a VT property.
-void SetVTSessionProperty(CompressionSessionRef session, CFStringRef key, bool value) {
+void SetVTSessionProperty(VTCompressionSessionRef vtSession, VCPCompressionSessionRef vcpSession, CFStringRef key, bool value) {
+  RTC_DCHECK(vtSession || vcpSession);
   CFBooleanRef cf_bool = (value) ? kCFBooleanTrue : kCFBooleanFalse;
-  OSStatus status = CompressionSessionSetProperty(session, key, cf_bool);
+  OSStatus status = noErr;
+  if (vtSession)
+    status = VTSessionSetProperty(vtSession, key, cf_bool);
+#if ENABLE_VCP_ENCODER
+  else
+    status = webrtc::VCPCompressionSessionSetProperty(vcpSession, key, cf_bool);
+#endif
   if (status != noErr) {
     std::string key_string = CFStringToString(key);
     RTC_LOG(LS_ERROR) << "VTSessionSetProperty failed to set: " << key_string
@@ -77,10 +98,17 @@ void SetVTSessionProperty(CompressionSessionRef session, CFStringRef key, bool v
 }
 
 // Convenience function for setting a VT property.
-void SetVTSessionProperty(CompressionSessionRef session,
+void SetVTSessionProperty(VTCompressionSessionRef vtSession, VCPCompressionSessionRef vcpSession,
                           CFStringRef key,
                           CFStringRef value) {
-  OSStatus status = CompressionSessionSetProperty(session, key, value);
+  RTC_DCHECK(vtSession || vcpSession);
+  OSStatus status = noErr;
+  if (vtSession)
+    status = VTSessionSetProperty(vtSession, key, value);
+#if ENABLE_VCP_ENCODER
+  else
+    status = webrtc::VCPCompressionSessionSetProperty(vcpSession, key, value);
+#endif
   if (status != noErr) {
     std::string key_string = CFStringToString(key);
     std::string val_string = CFStringToString(value);
index 0c669e8..c7d79d3 100644 (file)
@@ -16,7 +16,7 @@
 #include <VideoToolbox/VideoToolbox.h>
 #include <string>
 
-#include "sdk/WebKit/EncoderUtilities.h"
+#include "sdk/WebKit/VideoProcessingSoftLink.h"
 
 // Convenience function for creating a dictionary.
 inline CFDictionaryRef CreateCFTypeDictionary(CFTypeRef* keys,
@@ -31,18 +31,18 @@ inline CFDictionaryRef CreateCFTypeDictionary(CFTypeRef* keys,
 std::string CFStringToString(const CFStringRef cf_string);
 
 // Convenience function for setting a VT property.
-void SetVTSessionProperty(CompressionSessionRef session, CFStringRef key, int32_t value);
+void SetVTSessionProperty(VTCompressionSessionRef session, VCPCompressionSessionRef vcpSession,CFStringRef key, int32_t value);
 
 // Convenience function for setting a VT property.
-void SetVTSessionProperty(CompressionSessionRef session,
+void SetVTSessionProperty(VTCompressionSessionRef session, VCPCompressionSessionRef vcpSession,
                           CFStringRef key,
                           uint32_t value);
 
 // Convenience function for setting a VT property.
-void SetVTSessionProperty(CompressionSessionRef session, CFStringRef key, bool value);
+void SetVTSessionProperty(VTCompressionSessionRef session, VCPCompressionSessionRef vcpSession, CFStringRef key, bool value);
 
 // Convenience function for setting a VT property.
-void SetVTSessionProperty(CompressionSessionRef session,
+void SetVTSessionProperty(VTCompressionSessionRef session, VCPCompressionSessionRef vcpSession,
                           CFStringRef key,
                           CFStringRef value);