diff --git a/.gitmodules b/.gitmodules deleted file mode 100644 index 351cbd5..0000000 --- a/.gitmodules +++ /dev/null @@ -1,3 +0,0 @@ -[submodule "macos/Classes/mdkSwift"] - path = darwin/Classes/mdkSwift - url = https://github.com/wang-bin/mdkSwift.git diff --git a/darwin/Assets/.gitkeep b/darwin/Assets/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/darwin/Classes/FvpPlugin.h b/darwin/Classes/FvpPlugin.h new file mode 100644 index 0000000..9793403 --- /dev/null +++ b/darwin/Classes/FvpPlugin.h @@ -0,0 +1,7 @@ +#if __has_include() +#import +#else +#import +#endif +@interface FvpPlugin : NSObject +@end diff --git a/darwin/Classes/FvpPlugin.mm b/darwin/Classes/FvpPlugin.mm new file mode 100644 index 0000000..eb7c187 --- /dev/null +++ b/darwin/Classes/FvpPlugin.mm @@ -0,0 +1,135 @@ +// Copyright 2023 Wang Bin. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#import "FvpPlugin.h" +#import "Metal/Metal.h" +#import "CoreVideo/CoreVideo.h" +#include "mdk/RenderAPI.h" +#include "mdk/Player.h" +#include +#include + +using namespace mdk; +using namespace std; + +@interface MetalTexture : NSObject +@end + +@implementation MetalTexture { + @public + id device; + id cmdQueue; + id texture; + CVPixelBufferRef pixbuf; + CVMetalTextureCacheRef texCache; +} + +- (instancetype)initWithWidth:(int)width height:(int)height +{ + self = [super init]; + device = MTLCreateSystemDefaultDevice(); + cmdQueue = [device newCommandQueue]; + CVMetalTextureCacheCreate(nullptr, nullptr, device, nullptr, &texCache); + auto attr = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); + CFDictionarySetValue(attr, kCVPixelBufferMetalCompatibilityKey, kCFBooleanTrue); + CVPixelBufferCreate(nil, width, height, kCVPixelFormatType_32BGRA, attr, &pixbuf); + CFRelease(attr); + CVMetalTextureRef cvtex; + CVMetalTextureCacheCreateTextureFromImage(nil, texCache, pixbuf, nil, MTLPixelFormatBGRA8Unorm, width, height, 0, &cvtex); + texture = CVMetalTextureGetTexture(cvtex); + CFRelease(cvtex); + return self; +} + +- (void)dealloc { + CVPixelBufferRelease(pixbuf); + CFRelease(texCache); +} + +- (CVPixelBufferRef _Nullable)copyPixelBuffer { + return CVPixelBufferRetain(pixbuf); +} +@end + + +class TexturePlayer final: public Player +{ +public: + TexturePlayer(int64_t handle, int width, int height, NSObject* texReg) + : Player(reinterpret_cast(handle)) + { + mtex_ = [[MetalTexture alloc] initWithWidth:width height:height]; + texId_ = [texReg registerTexture:mtex_]; + MetalRenderAPI ra{}; + ra.device = (__bridge void*)mtex_->device; + ra.cmdQueue = (__bridge void*)mtex_->cmdQueue; + ra.texture = (__bridge void*)mtex_->texture; + setRenderAPI(&ra); + setVideoSurfaceSize(width, height); + + setRenderCallback([this, texReg](void* opaque){ + renderVideo(); + [texReg textureFrameAvailable:texId_]; + }); + } + + ~TexturePlayer() override { + setRenderCallback(nullptr); + setVideoSurfaceSize(-1, -1); + } + + int64_t textureId() const { return texId_;} +private: + int64_t texId_ = 0; + MetalTexture* mtex_ = nil; +}; + + +@interface FvpPlugin () { + unordered_map> players; +} +@property(readonly, strong, nonatomic) NSObject* texRegistry; +@end + +@implementation FvpPlugin ++ (void)registerWithRegistrar:(NSObject*)registrar { +#if TARGET_OS_OSX + auto messenger = registrar.messenger; +#else + auto messenger = [registrar messenger]; +#endif + FlutterMethodChannel* channel = [FlutterMethodChannel methodChannelWithName:@"fvp" binaryMessenger:messenger]; + FvpPlugin* instance = [[FvpPlugin alloc] initWithRegistrar:registrar]; + [registrar addMethodCallDelegate:instance channel:channel]; +} + +- (instancetype)initWithRegistrar:(NSObject*)registrar { + self = [super init]; +#if TARGET_OS_OSX + _texRegistry = registrar.textures; +#else + _texRegistry = [registrar textures]; +#endif + return self; +} + +- (void)handleMethodCall:(FlutterMethodCall*)call result:(FlutterResult)result { + if ([call.method isEqualToString:@"CreateRT"]) { + const auto handle = ((NSNumber*)call.arguments[@"player"]).longLongValue; + const auto width = (int)((NSNumber*)call.arguments[@"width"]).longLongValue; + const auto height = (int)((NSNumber*)call.arguments[@"height"]).longLongValue; + auto player = make_shared(handle, width, height, _texRegistry); + players[player->textureId()] = player; + result(@(player->textureId())); + } else if ([call.method isEqualToString:@"ReleaseRT"]) { + const auto texId = ((NSNumber*)call.arguments[@"texture"]).longLongValue; + [_texRegistry unregisterTexture:texId]; + players.erase(texId); + result(nil); + } else { + result(FlutterMethodNotImplemented); + } +} + +@end diff --git a/darwin/Classes/FvpPlugin.swift b/darwin/Classes/FvpPlugin.swift deleted file mode 100644 index 689cf0c..0000000 --- a/darwin/Classes/FvpPlugin.swift +++ /dev/null @@ -1,127 +0,0 @@ -/* - * Copyright (c) 2023 WangBin - */ -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. -#if canImport(Flutter) -import Flutter -#else -import FlutterMacOS -#endif -import Metal -import CoreVideo -import mdk - -fileprivate class FvpRenderer: NSObject, FlutterTexture { - private var device : MTLDevice! - private var cmdQueue : MTLCommandQueue! - private var texture : MTLTexture! - private var pixbuf : CVPixelBuffer! - private var texCache : CVMetalTextureCache! - private var player : Player! - private var registry: FlutterTextureRegistry - var textureId: Int64 = 0 - - init(player: Player, width: Int, height: Int, textureRegistry: FlutterTextureRegistry) { - registry = textureRegistry - super.init() - self.player = player - self.textureId = registry.register(self) - - self.player.setRenderCallback { [weak self] in - guard let self = self else { return } - _ = self.player.renderVideo() - self.registry.textureFrameAvailable(self.textureId) - } - - device = MTLCreateSystemDefaultDevice() - cmdQueue = device.makeCommandQueue() - CVMetalTextureCacheCreate(kCFAllocatorDefault, nil, device!, nil, &texCache) - createTexture(width:width, height:height) - } - - deinit { - player.setRenderCallback(nil) - player.setVideoSurfaceSize(Int32(-1), Int32(-1)) - } - - func copyPixelBuffer() -> Unmanaged? { - return Unmanaged.passRetained(pixbuf) - } - - private func createTexture(width: Int, height: Int) { - /* - // texture from CVPixelBuffer.iosurface - let desc = MTLTextureDescriptor.texture2DDescriptor(pixelFormat: .bgra8Unorm, width: 1920, height: 1080, mipmapped: false) - desc.storageMode = .private - desc.resourceOptions = .storageModePrivate - desc.usage = [.shaderRead, .renderTarget] - texture = device.makeTexture(descriptor: desc) - */ - - let attrs = [ - kCVPixelBufferMetalCompatibilityKey: true - ] as CFDictionary - CVPixelBufferCreate(kCFAllocatorDefault, width, height, kCVPixelFormatType_32BGRA, attrs, &pixbuf) - - var cvtex : CVMetalTexture? - CVMetalTextureCacheCreateTextureFromImage(nil, texCache, pixbuf!, nil, .bgra8Unorm, width, height, 0, &cvtex) - - texture = CVMetalTextureGetTexture(cvtex!) - - var ra = mdkMetalRenderAPI() - ra.type = MDK_RenderAPI_Metal - ra.device = bridge(obj: device) - ra.cmdQueue = bridge(obj: cmdQueue) - ra.texture = bridge(obj: texture) - player.setRenderAPI(&ra) - player.setVideoSurfaceSize(Int32(width), Int32(height)) // enable renderer - } - -} - -public class FvpPlugin: NSObject, FlutterPlugin { - private var registry: FlutterTextureRegistry; - - private var renderers: [Int64: FvpRenderer] = [:]; - - init(textureRegistry: FlutterTextureRegistry) { - registry = textureRegistry; - super.init() - } - - public static func register(with registrar: FlutterPluginRegistrar) { -#if canImport(Flutter) - let binaryMessenger = registrar.messenger() - let textureRegistry = registrar.textures() -#else - let binaryMessenger = registrar.messenger - let textureRegistry = registrar.textures -#endif - let channel = FlutterMethodChannel(name: "fvp", binaryMessenger: binaryMessenger) - let instance = FvpPlugin(textureRegistry: textureRegistry) - registrar.addMethodCallDelegate(instance, channel: channel) - } - - public func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) { - switch call.method { - case "CreateRT": - let args = call.arguments as! [String: Any] - let handle = args["player"] as! Int64 - let width = Int(args["width"] as! Int64) - let height = Int(args["height"] as! Int64) - let player = Player(UnsafePointer(OpaquePointer(bitPattern: Int(handle)))) - let render = FvpRenderer(player: player, width: width, height: height, textureRegistry: registry) - renderers[render.textureId] = render - result(render.textureId) - case "ReleaseRT": - let args = call.arguments as! [String: Any] - let tex = args["texture"] as! Int64 - registry.unregisterTexture(tex) - renderers.removeValue(forKey: tex) - result(nil) - default: - result(FlutterMethodNotImplemented) - } - } -} diff --git a/darwin/Classes/mdkSwift b/darwin/Classes/mdkSwift deleted file mode 160000 index c0aba3d..0000000 --- a/darwin/Classes/mdkSwift +++ /dev/null @@ -1 +0,0 @@ -Subproject commit c0aba3dd98b5e93eb78a84309f509d603a05d137 diff --git a/darwin/fvp.podspec b/darwin/fvp.podspec index 5d7b78f..ab97fce 100644 --- a/darwin/fvp.podspec +++ b/darwin/fvp.podspec @@ -14,8 +14,10 @@ Flutter video player plugin. s.author = { 'Wang Bin' => 'wbsecg1@gmail.com' } s.compiler_flags = '-Wno-documentation -std=c++20' + s.osx.pod_target_xcconfig = { 'OTHER_LDFLAGS' => '-framework FlutterMacOS' } s.source = { :path => '.' } s.source_files = 'Classes/**/*' + s.public_header_files = 'Classes/**/*.h' s.ios.dependency 'Flutter' s.osx.dependency 'FlutterMacOS' s.ios.deployment_target = '11.0' diff --git a/ios/Classes/FvpPlugin.h b/ios/Classes/FvpPlugin.h new file mode 120000 index 0000000..30d54df --- /dev/null +++ b/ios/Classes/FvpPlugin.h @@ -0,0 +1 @@ +../../darwin/Classes/FvpPlugin.h \ No newline at end of file diff --git a/ios/Classes/FvpPlugin.mm b/ios/Classes/FvpPlugin.mm new file mode 120000 index 0000000..71c0052 --- /dev/null +++ b/ios/Classes/FvpPlugin.mm @@ -0,0 +1 @@ +../../darwin/Classes/FvpPlugin.mm \ No newline at end of file diff --git a/ios/Classes/FvpPlugin.swift b/ios/Classes/FvpPlugin.swift deleted file mode 120000 index 99aed6f..0000000 --- a/ios/Classes/FvpPlugin.swift +++ /dev/null @@ -1 +0,0 @@ -../../darwin/Classes/FvpPlugin.swift \ No newline at end of file diff --git a/ios/Classes/mdkSwift/LICENSE b/ios/Classes/mdkSwift/LICENSE deleted file mode 120000 index 9bef797..0000000 --- a/ios/Classes/mdkSwift/LICENSE +++ /dev/null @@ -1 +0,0 @@ -../../../darwin/Classes/mdkSwift/LICENSE \ No newline at end of file diff --git a/ios/Classes/mdkSwift/MediaInfo.swift b/ios/Classes/mdkSwift/MediaInfo.swift deleted file mode 120000 index dbc7ad3..0000000 --- a/ios/Classes/mdkSwift/MediaInfo.swift +++ /dev/null @@ -1 +0,0 @@ -../../../darwin/Classes/mdkSwift/MediaInfo.swift \ No newline at end of file diff --git a/ios/Classes/mdkSwift/Player.swift b/ios/Classes/mdkSwift/Player.swift deleted file mode 120000 index c77f03d..0000000 --- a/ios/Classes/mdkSwift/Player.swift +++ /dev/null @@ -1 +0,0 @@ -../../../darwin/Classes/mdkSwift/Player.swift \ No newline at end of file diff --git a/ios/Classes/mdkSwift/README.md b/ios/Classes/mdkSwift/README.md deleted file mode 120000 index a03134c..0000000 --- a/ios/Classes/mdkSwift/README.md +++ /dev/null @@ -1 +0,0 @@ -../../../darwin/Classes/mdkSwift/README.md \ No newline at end of file diff --git a/ios/Classes/mdkSwift/VideoFrame.swift b/ios/Classes/mdkSwift/VideoFrame.swift deleted file mode 120000 index 4167294..0000000 --- a/ios/Classes/mdkSwift/VideoFrame.swift +++ /dev/null @@ -1 +0,0 @@ -../../../darwin/Classes/mdkSwift/VideoFrame.swift \ No newline at end of file diff --git a/ios/Classes/mdkSwift/global.swift b/ios/Classes/mdkSwift/global.swift deleted file mode 120000 index 60dfd12..0000000 --- a/ios/Classes/mdkSwift/global.swift +++ /dev/null @@ -1 +0,0 @@ -../../../darwin/Classes/mdkSwift/global.swift \ No newline at end of file diff --git a/macos/Classes/FvpPlugin.h b/macos/Classes/FvpPlugin.h new file mode 120000 index 0000000..30d54df --- /dev/null +++ b/macos/Classes/FvpPlugin.h @@ -0,0 +1 @@ +../../darwin/Classes/FvpPlugin.h \ No newline at end of file diff --git a/macos/Classes/FvpPlugin.mm b/macos/Classes/FvpPlugin.mm new file mode 120000 index 0000000..71c0052 --- /dev/null +++ b/macos/Classes/FvpPlugin.mm @@ -0,0 +1 @@ +../../darwin/Classes/FvpPlugin.mm \ No newline at end of file diff --git a/macos/Classes/FvpPlugin.swift b/macos/Classes/FvpPlugin.swift deleted file mode 120000 index 99aed6f..0000000 --- a/macos/Classes/FvpPlugin.swift +++ /dev/null @@ -1 +0,0 @@ -../../darwin/Classes/FvpPlugin.swift \ No newline at end of file diff --git a/macos/Classes/mdkSwift/LICENSE b/macos/Classes/mdkSwift/LICENSE deleted file mode 120000 index 9bef797..0000000 --- a/macos/Classes/mdkSwift/LICENSE +++ /dev/null @@ -1 +0,0 @@ -../../../darwin/Classes/mdkSwift/LICENSE \ No newline at end of file diff --git a/macos/Classes/mdkSwift/MediaInfo.swift b/macos/Classes/mdkSwift/MediaInfo.swift deleted file mode 120000 index dbc7ad3..0000000 --- a/macos/Classes/mdkSwift/MediaInfo.swift +++ /dev/null @@ -1 +0,0 @@ -../../../darwin/Classes/mdkSwift/MediaInfo.swift \ No newline at end of file diff --git a/macos/Classes/mdkSwift/Player.swift b/macos/Classes/mdkSwift/Player.swift deleted file mode 120000 index c77f03d..0000000 --- a/macos/Classes/mdkSwift/Player.swift +++ /dev/null @@ -1 +0,0 @@ -../../../darwin/Classes/mdkSwift/Player.swift \ No newline at end of file diff --git a/macos/Classes/mdkSwift/README.md b/macos/Classes/mdkSwift/README.md deleted file mode 120000 index a03134c..0000000 --- a/macos/Classes/mdkSwift/README.md +++ /dev/null @@ -1 +0,0 @@ -../../../darwin/Classes/mdkSwift/README.md \ No newline at end of file diff --git a/macos/Classes/mdkSwift/VideoFrame.swift b/macos/Classes/mdkSwift/VideoFrame.swift deleted file mode 120000 index 4167294..0000000 --- a/macos/Classes/mdkSwift/VideoFrame.swift +++ /dev/null @@ -1 +0,0 @@ -../../../darwin/Classes/mdkSwift/VideoFrame.swift \ No newline at end of file diff --git a/macos/Classes/mdkSwift/global.swift b/macos/Classes/mdkSwift/global.swift deleted file mode 120000 index 60dfd12..0000000 --- a/macos/Classes/mdkSwift/global.swift +++ /dev/null @@ -1 +0,0 @@ -../../../darwin/Classes/mdkSwift/global.swift \ No newline at end of file