Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

avfilter/transpose_vt: select implementation based on macOS version #431

Merged
merged 2 commits into from
Aug 10, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .github/workflows/_meta_mac_portable.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,9 @@ jobs:
strategy:
fail-fast: true
matrix:
# Currently, macOS 12 is x86 exclusive and macOS 14 is arm exclusive and we have no other way to specify arch
# Currently, macOS 13 is x86 exclusive and macOS 14 is arm exclusive and we have no other way to specify arch
os:
- name: macos-12
- name: macos-13
arch: x86_64
- name: macos-14
arch: arm64
Expand Down
1 change: 1 addition & 0 deletions builder/variants/defaults-mac.sh
Original file line number Diff line number Diff line change
Expand Up @@ -20,3 +20,4 @@ export PKG_CONFIG_LIBDIR="/usr/lib/pkgconfig:/opt/homebrew/Library/Homebrew/os/m
export CMAKE_PREFIX_PATH=""$FFBUILD_PREFIX""
export PKG_CONFIG_PATH=""$FFBUILD_PREFIX"/lib/pkgconfig"
export RANLIB="/usr/bin/ranlib"
export MACOSX_DEPLOYMENT_TARGET="12.0"
212 changes: 164 additions & 48 deletions debian/patches/0051-add-coreimage-based-vf-transpose-vt-filter.patch
Original file line number Diff line number Diff line change
Expand Up @@ -305,8 +305,9 @@ Index: FFmpeg/libavfilter/vf_transpose_vt.m
===================================================================
--- /dev/null
+++ FFmpeg/libavfilter/vf_transpose_vt.m
@@ -0,0 +1,265 @@
@@ -0,0 +1,381 @@
+/*
+ * Copyright (c) 2023 Zhao Zhili <zhilizhao@tencent.com>
+ * Copyright (c) 2024 Gnattu OC <gnattuoc@me.com>
+ *
+ * This file is part of FFmpeg.
Expand All @@ -327,17 +328,31 @@ Index: FFmpeg/libavfilter/vf_transpose_vt.m
+ */
+
+#include <CoreImage/CoreImage.h>
+#include <VideoToolbox/VideoToolbox.h>
+
+#include "libavutil/hwcontext.h"
+#include "libavutil/opt.h"
+#include "libavutil/objc.h"
+#include "internal.h"
+#include "transpose.h"
+#include "video.h"
+
+// Declaration for SDKs not having VTPixelRotationSession
+#if (TARGET_OS_OSX && (!defined(__MAC_13_0))) || \
+ (TARGET_OS_IOS && (!defined(__IPHONE_16_0))) || \
+ (TARGET_OS_TV && (!defined(__TVOS_16_0)))
+ #define LEGACY_VT_SDK
+#endif
+
+#ifdef LEGACY_VT_SDK
+typedef void* VTPixelRotationSessionRef;
+#endif
+
+typedef struct TransposeVtContext {
+ AVClass *class;
+ CIContext *ci_ctx;
+ CGImagePropertyOrientation orientation;
+ VTPixelRotationSessionRef session;
+
+ int dir;
+ int passthrough;
Expand All @@ -346,10 +361,28 @@ Index: FFmpeg/libavfilter/vf_transpose_vt.m
+static av_cold int transpose_vt_init(AVFilterContext *avctx)
+{
+ TransposeVtContext *s = avctx->priv;
+ s->ci_ctx = CFBridgingRetain([CIContext context]);
+ if (!s->ci_ctx) {
+ av_log(avctx, AV_LOG_ERROR, "CoreImage Context create failed\n");
+ return AVERROR_EXTERNAL;
+#ifndef LEGACY_VT_SDK
+ if (@available(macOS 13.0, iOS 16, *)) {
+ int ret;
+
+ ret = VTPixelRotationSessionCreate(kCFAllocatorDefault, &s->session);
+ if (ret != noErr) {
+ av_log(avctx, AV_LOG_ERROR, "Rotation session create failed, %d\n", ret);
+ return AVERROR_EXTERNAL;
+ } else {
+ av_log(avctx, AV_LOG_DEBUG, "VT Rotation session created\n");
+ }
+ }
+ else
+#endif
+ {
+ s->ci_ctx = CFBridgingRetain([CIContext context]);
+ if (!s->ci_ctx) {
+ av_log(avctx, AV_LOG_ERROR, "CoreImage Context create failed\n");
+ return AVERROR_EXTERNAL;
+ } else {
+ av_log(avctx, AV_LOG_DEBUG, "CoreImage Context created\n");
+ }
+ }
+
+ return 0;
Expand All @@ -362,6 +395,15 @@ Index: FFmpeg/libavfilter/vf_transpose_vt.m
+ CFRelease(s->ci_ctx);
+ s->ci_ctx = NULL;
+ }
+#ifndef LEGACY_VT_SDK
+ if (@available(macOS 13.0, iOS 16, *)) {
+ if (s->session) {
+ VTPixelRotationSessionInvalidate(s->session);
+ CFRelease(s->session);
+ s->session = NULL;
+ }
+ }
+#endif
+}
+
+static int transpose_vt_filter_frame(AVFilterLink *link, AVFrame *in)
Expand All @@ -373,8 +415,6 @@ Index: FFmpeg/libavfilter/vf_transpose_vt.m
+ CVPixelBufferRef src;
+ CVPixelBufferRef dst;
+ AVFrame *out;
+ CIImage *source_image = NULL;
+ CIImage *transposed_image = NULL;
+
+ if (s->passthrough)
+ return ff_filter_frame(outlink, in);
Expand All @@ -391,19 +431,33 @@ Index: FFmpeg/libavfilter/vf_transpose_vt.m
+
+ src = (CVPixelBufferRef)in->data[3];
+ dst = (CVPixelBufferRef)out->data[3];
+
+ source_image = CFBridgingRetain([CIImage imageWithCVPixelBuffer: src]);
+ transposed_image = CFBridgingRetain([source_image imageByApplyingCGOrientation: s->orientation]);
+ if (!transposed_image) {
+ CFRelease(source_image);
+ av_log(ctx, AV_LOG_ERROR, "transpose image failed, %d\n", ret);
+ ret = AVERROR_EXTERNAL;
+ goto fail;
+#ifndef LEGACY_VT_SDK
+ if (@available(macOS 13.0, iOS 16, *)) {
+ ret = VTPixelRotationSessionRotateImage(s->session, src, dst);
+ if (ret != noErr) {
+ av_log(ctx, AV_LOG_ERROR, "transfer image failed, %d\n", ret);
+ ret = AVERROR_EXTERNAL;
+ goto fail;
+ }
+ }
+ else
+#endif
+ {
+ @autoreleasepool {
+ CIImage *source_image = NULL;
+ CIImage *transposed_image = NULL;
+ source_image = [CIImage imageWithCVPixelBuffer:src];
+ transposed_image = [source_image imageByApplyingCGOrientation:s->orientation];
+ if (!transposed_image) {
+ ff_objc_release(&source_image);
+ av_log(ctx, AV_LOG_ERROR, "transpose image failed, %d\n", ret);
+ ret = AVERROR_EXTERNAL;
+ goto fail;
+ }
+ CVBufferPropagateAttachments(src, dst);
+ [(__bridge CIContext *) s->ci_ctx render:transposed_image toCVPixelBuffer:dst];
+ }
+ }
+ [(__bridge CIContext*)s->ci_ctx render: (__bridge CIImage*)transposed_image toCVPixelBuffer: dst];
+ CFRelease(source_image);
+ CFRelease(transposed_image);
+ CVBufferPropagateAttachments(src, dst);
+
+ av_frame_free(&in);
+
Expand Down Expand Up @@ -470,35 +524,97 @@ Index: FFmpeg/libavfilter/vf_transpose_vt.m
+
+ s->passthrough = TRANSPOSE_PT_TYPE_NONE;
+
+ switch (s->dir) {
+ case TRANSPOSE_CCLOCK_FLIP:
+ s->orientation = kCGImagePropertyOrientationLeftMirrored;
+ swap_w_h = 1;
+ break;
+ case TRANSPOSE_CCLOCK:
+ s->orientation = kCGImagePropertyOrientationLeft;
+ swap_w_h = 1;
+ break;
+ case TRANSPOSE_CLOCK:
+ s->orientation = kCGImagePropertyOrientationRight;
+ swap_w_h = 1;
+ break;
+ case TRANSPOSE_CLOCK_FLIP:
+ s->orientation = kCGImagePropertyOrientationRightMirrored;
+ swap_w_h = 1;
+ break;
+ case TRANSPOSE_REVERSAL:
+ s->orientation = kCGImagePropertyOrientationDown;
+ break;
+ case TRANSPOSE_HFLIP:
+ s->orientation = kCGImagePropertyOrientationUpMirrored;
+ break;
+ case TRANSPOSE_VFLIP:
+ s->orientation = kCGImagePropertyOrientationDownMirrored;
+ break;
+ default:
+ av_log(avctx, AV_LOG_ERROR, "Failed to set direction to %d\n", s->dir);
+ return AVERROR(EINVAL);
+#ifndef LEGACY_VT_SDK
+ if (@available(macOS 13.0, iOS 16, *)) {
+ CFStringRef rotation = kVTRotation_0;
+ CFBooleanRef vflip = kCFBooleanFalse;
+ CFBooleanRef hflip = kCFBooleanFalse;
+
+ switch (s->dir) {
+ case TRANSPOSE_CCLOCK_FLIP:
+ rotation = kVTRotation_CCW90;
+ vflip = kCFBooleanTrue;
+ swap_w_h = 1;
+ break;
+ case TRANSPOSE_CCLOCK:
+ rotation = kVTRotation_CCW90;
+ swap_w_h = 1;
+ break;
+ case TRANSPOSE_CLOCK:
+ rotation = kVTRotation_CW90;
+ swap_w_h = 1;
+ break;
+ case TRANSPOSE_CLOCK_FLIP:
+ rotation = kVTRotation_CW90;
+ vflip = kCFBooleanTrue;
+ swap_w_h = 1;
+ break;
+ case TRANSPOSE_REVERSAL:
+ rotation = kVTRotation_180;
+ break;
+ case TRANSPOSE_HFLIP:
+ hflip = kCFBooleanTrue;
+ break;
+ case TRANSPOSE_VFLIP:
+ vflip = kCFBooleanTrue;
+ break;
+ default:
+ av_log(avctx, AV_LOG_ERROR, "Failed to set direction to %d\n", s->dir);
+ return AVERROR(EINVAL);
+ }
+
+ err = VTSessionSetProperty(s->session, kVTPixelRotationPropertyKey_Rotation,
+ rotation);
+ if (err != noErr) {
+ av_log(avctx, AV_LOG_ERROR, "Set rotation property failed, %d\n", err);
+ return AVERROR_EXTERNAL;
+ }
+ err = VTSessionSetProperty(s->session, kVTPixelRotationPropertyKey_FlipVerticalOrientation,
+ vflip);
+ if (err != noErr) {
+ av_log(avctx, AV_LOG_ERROR, "Set vertical flip property failed, %d\n", err);
+ return AVERROR_EXTERNAL;
+ }
+ err = VTSessionSetProperty(s->session, kVTPixelRotationPropertyKey_FlipHorizontalOrientation,
+ hflip);
+ if (err != noErr) {
+ av_log(avctx, AV_LOG_ERROR, "Set horizontal flip property failed, %d\n", err);
+ return AVERROR_EXTERNAL;
+ }
+ }
+ else
+#endif
+ {
+ switch (s->dir) {
+ case TRANSPOSE_CCLOCK_FLIP:
+ s->orientation = kCGImagePropertyOrientationLeftMirrored;
+ swap_w_h = 1;
+ break;
+ case TRANSPOSE_CCLOCK:
+ s->orientation = kCGImagePropertyOrientationLeft;
+ swap_w_h = 1;
+ break;
+ case TRANSPOSE_CLOCK:
+ s->orientation = kCGImagePropertyOrientationRight;
+ swap_w_h = 1;
+ break;
+ case TRANSPOSE_CLOCK_FLIP:
+ s->orientation = kCGImagePropertyOrientationRightMirrored;
+ swap_w_h = 1;
+ break;
+ case TRANSPOSE_REVERSAL:
+ s->orientation = kCGImagePropertyOrientationDown;
+ break;
+ case TRANSPOSE_HFLIP:
+ s->orientation = kCGImagePropertyOrientationUpMirrored;
+ break;
+ case TRANSPOSE_VFLIP:
+ s->orientation = kCGImagePropertyOrientationDownMirrored;
+ break;
+ default:
+ av_log(avctx, AV_LOG_ERROR, "Failed to set direction to %d\n", s->dir);
+ return AVERROR(EINVAL);
+ }
+ }
+
+ if (!swap_w_h)
Expand Down
Loading