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

feat: Video filters #799

Merged
merged 15 commits into from
Jan 9, 2025
Merged
Original file line number Diff line number Diff line change
@@ -1,11 +1,64 @@
package io.getstream.video.flutter.dogfooding

import android.graphics.Bitmap
import android.graphics.Canvas
import android.graphics.ColorMatrix
import android.graphics.ColorMatrixColorFilter
import android.graphics.Paint

import io.flutter.embedding.android.FlutterActivity
import io.flutter.embedding.engine.FlutterEngine
import io.flutter.embedding.engine.plugins.FlutterPlugin
import io.flutter.embedding.engine.plugins.activity.ActivityAware
import io.flutter.embedding.engine.plugins.activity.ActivityPluginBinding
import io.flutter.plugin.common.MethodChannel
import io.flutter.plugin.common.PluginRegistry

import io.getstream.video.flutter.stream_video_flutter.service.PictureInPictureHelper
import io.getstream.video.flutter.stream_video_flutter.videoFilters.common.VideoFrameProcessorWithBitmapFilter
import io.getstream.video.flutter.stream_video_flutter.videoFilters.common.BitmapVideoFilter
import io.getstream.webrtc.flutter.videoEffects.ProcessorProvider
import io.getstream.webrtc.flutter.videoEffects.VideoFrameProcessor
import io.getstream.webrtc.flutter.videoEffects.VideoFrameProcessorFactoryInterface

class MainActivity: FlutterActivity() {
private val CHANNEL = "io.getstream.video.flutter.dogfooding.channel"

override fun onUserLeaveHint() {
super.onUserLeaveHint()
PictureInPictureHelper.enterPictureInPictureIfInCall(this)
}

override fun configureFlutterEngine(flutterEngine: FlutterEngine) {
super.configureFlutterEngine(flutterEngine)
MethodChannel(flutterEngine.dartExecutor.binaryMessenger, CHANNEL).setMethodCallHandler { call, result ->
if (call.method == "registerGreyscaleEffect") {
ProcessorProvider.addProcessor("grayscale", GrayScaleVideoFilterFactory())
result.success(null)
} else {
result.notImplemented()
}
}
}
}

class GrayScaleVideoFilterFactory : VideoFrameProcessorFactoryInterface {
override fun build(): VideoFrameProcessor {
return VideoFrameProcessorWithBitmapFilter {
GrayScaleFilter()
}
}
}
private class GrayScaleFilter : BitmapVideoFilter() {
override fun applyFilter(videoFrameBitmap: Bitmap) {
val canvas = Canvas(videoFrameBitmap)
val paint = Paint().apply {
val colorMatrix = ColorMatrix().apply {
// map the saturation of the color to grayscale
setSaturation(0f)
}
colorFilter = ColorMatrixColorFilter(colorMatrix)
}
canvas.drawBitmap(videoFrameBitmap, 0f, 0f, paint)
}
}
Binary file added dogfooding/assets/bg1.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added dogfooding/assets/bg2.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added dogfooding/assets/bg3.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
63 changes: 50 additions & 13 deletions dogfooding/ios/Runner/AppDelegate.swift
Original file line number Diff line number Diff line change
@@ -1,38 +1,75 @@
import UIKit
import Flutter
import UIKit
import stream_video_flutter
import stream_video_push_notification
import stream_webrtc_flutter

@UIApplicationMain
@main
@objc class AppDelegate: FlutterAppDelegate {

private let CHANNEL = "io.getstream.video.flutter.dogfooding.channel"

override func application(
_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
) -> Bool {
GeneratedPluginRegistrant.register(with: self)

// Register for push notifications.
StreamVideoPKDelegateManager.shared.registerForPushNotifications()
UNUserNotificationCenter.current().delegate = self


let controller = window?.rootViewController as! FlutterViewController
let channel = FlutterMethodChannel(
name: CHANNEL, binaryMessenger: controller.binaryMessenger)
channel.setMethodCallHandler { [weak self] (call, result) in
self?.handleMethodCall(call: call, result: result)
}

return super.application(application, didFinishLaunchingWithOptions: launchOptions)
}

// This method will be called when notification is received
override func userNotificationCenter(_ center: UNUserNotificationCenter,
willPresent notification: UNNotification,
withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) {
override func userNotificationCenter(
_ center: UNUserNotificationCenter,
willPresent notification: UNNotification,
withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) ->
Void
) {
let streamDict = notification.request.content.userInfo["stream"] as? [String: Any]
if(streamDict?["sender"] as? String != "stream.video") {
if streamDict?["sender"] as? String != "stream.video" {
return completionHandler([])
}

if #available(iOS 14.0, *) {
completionHandler([.list, .banner, .sound])
} else {
completionHandler([.alert])
}
}



func handleMethodCall(call: FlutterMethodCall, result: @escaping FlutterResult) {
if call.method == "registerGreyscaleEffect" {
ProcessorProvider.addProcessor(GrayScaleVideoFrameProcessor(), forName: "grayscale")
result(nil)
} else {
result(FlutterMethodNotImplemented)
}
}
}

final class GrayScaleVideoFrameProcessor: VideoFilter {
@available(*, unavailable)
override public init(
filter: @escaping (Input) -> CIImage
) { fatalError() }
init() {
super.init(
filter: { input in
let filter = CIFilter(name: "CIPhotoEffectMono")
filter?.setValue(input.originalImage, forKey: kCIInputImageKey)
let outputImage: CIImage = filter?.outputImage ?? input.originalImage
return outputImage
}
)
}
}
1 change: 1 addition & 0 deletions dogfooding/ios/fastlane/Fastfile
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ platform :ios do
changelog: 'Lots of amazing new features to test out!',
reject_build_waiting_for_review: false,
skip_waiting_for_build_processing: false,
beta_app_description: 'Beta build of Stream Video Flutter Dogfoofing app for internal and external testers',
)
rescue Exception => e
if e.message.include? 'Another build is in review'
Expand Down
10 changes: 10 additions & 0 deletions dogfooding/lib/dogfooding_app_channel.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import 'package:flutter/services.dart';

class DogfoodingAppChannel {
static const platform =
MethodChannel('io.getstream.video.flutter.dogfooding.channel');

Future<void> registerGreyscaleEffect() async {
await platform.invokeMethod('registerGreyscaleEffect');
}
}
Loading
Loading