arthenica / ffmpeg-kit

FFmpeg Kit for applications. Supports Android, Flutter, iOS, Linux, macOS, React Native and tvOS. Supersedes MobileFFmpeg, flutter_ffmpeg and react-native-ffmpeg.
https://arthenica.github.io/ffmpeg-kit
GNU Lesser General Public License v3.0
4.5k stars 602 forks source link

Kotlin Multiplatform Support #681

Open MSDarwish2000 opened 1 year ago

MSDarwish2000 commented 1 year ago

Is your feature request related to a problem? Please describe. Kotlin Multiplatform is going stable this year and seems to be a promising platform. FFmpegKit is suitable to target Kotlin Multiplatform as it has similar API on different platforms and already supports similar multiplatform targets like Flutter and React Native.

Describe the solution you'd like I think it would be great if there was a KMP library that wraps Android, iOS (and Apple platforms), and Linux as well. This would need some effort to implement, but its maintenance effort would be minimal, I think.

Describe alternatives you've considered Alternatives include relying on third-party developers to provide such wrapper. Otherwise, application developers should implement it themselves using expect/actual in their projects as needed.

Platform This wrapper mainly benefit Kotlin Multiplatform Mobile applications, so the most important targets are Android and iOS. Other Apple platforms wouldn't take extra effort if iOS support is already planned, so it would be nice to support them. Linux is also a tier 1 target for KMP so it would be nice to include it if it didn't require much effort.

Additional context More information about KMP can be found on kotlinlang.org

LandryNorris commented 1 year ago

Glancing through import statements, this shouldn't be too hard to do for most classes (and could be a step towards modernizing the android module with coroutines if that's desired). My team uses the expect/actual mechanism currently with FFprobeKit and FFmpegKit's execute methods.

LandryNorris commented 1 year ago

@tanersener I have created a repo where I started prototyping a port of FFmpegKit supporting KMM. If it looks like I'm on the right track, I can try to complete it and open a PR adding support to this repository. Right now, I have FFmpegKit mostly complete for Android (can execute commands and read the output. I still need to test statistics). I'll work on FFprobeKit next if this is something that could be merged in when I'm done. To avoid duplication of compiling the C binaries and simplify building, it pulls Android's FFmpegKit from maven, and iOS's FFmpegKit from cocoapods, but the C binaries could be built and added directly in KMM without dependency on the native Android/iOS FFmpegKit.

Repo: https://github.com/LandryNorris/FFmpegKitKotlin Test App: https://github.com/LandryNorris/FFmpegKitKotlinTestApp

tanersener commented 1 year ago

@LandryNorris Thanks for working on this. If all ffmpeg-kit features are implemented in KMM, then we can consider merging it to main. I'm still not sure if we can maintain KMM support on long term. That's my main concern.

MSDarwish2000 commented 1 year ago

@LandryNorris I really appreciate your interest in implementing this feature request. But, I have a little note to say. If you are looking forward to collaborating with @tanersener in merging this work into the main repository, I think your approach isn't the best one.

Your approach works great as a third-party wrapper for FFmpegKit. But for merging it back into the main repo, it should give the advantage of reducing the work of maintaining the library by sharing as much code as possible between targets, i.e. by starting to convert the Android target to a multiplatform one with single Android target and gradually migrating any common logic to the commonMain source set, then adding other supported targets and exposing the same Apple and Linux APIs.

It is of course a lot of work to do, but it will end in a win-win situation where the library developers benefit from less work to maintain the library and the community benefit from the KMM support.

Of course, we may collaborate in making this true after tanersener's decision as the repo's main contributor, and it is just my opinion and your reply and suggestions are welcome.

LandryNorris commented 1 year ago

That's fair. There's a couple of options for how to implement this.

One solution is to take the approach taken with the Flutter package, where the library provides very lightweight wrappers over the native implementations (I can have the KMM Session classes hold a platform session instance, and each method and variable in the expect/actual class just defers to that platform instance). I'm not the biggest fan of this, due to debugging issues I had with the Flutter package (when ffmpeg or ffprobe errors out, we didn't get much info about why on iOS, just that it failed with no output), but makes maintenance largely identical to the Flutter package (and probably React-Native, but I haven't looked into that implementation as deeply).

The approach of converting the Android target to multiplatform adds some work, and since it requires that the project be translated to Kotlin first (easy to do with IntelliJ), I'd rather have @tanersener 's approval on that front. If the android package were to be converted, it would make KMM possibly the easiest cross-platform technology to support in the long term, since any changes to commonMain (where a lot of logic could live) would affect both Android and iOS, while taking advantage of the fact that Kotlin's the native platform for Android. Given that Google's converted a few of the Java androidx libraries to Kotlin already, and any Compose project essentially has to use Kotlin, it may be good for the project to convert eventually, regardless of whether this includes Kotlin Multiplatform or just Kotlin for Android.

Right now, my current implementation tries to take advantage of the existing platform implementations, while also keeping ease of debugging in mind (it's hard to set breakpoints in a native library on iOS in particular from a cross-platform technology) by writing as much of the processing in Kotlin (in commonMain where possible) as we can. If this makes it too difficult to maintain, I'm willing to switch to the first or second suggestion, or any other ideas. The main advantage here is debugging JSON parsing. Since the JSON parsing is in Kotlin using kotlinx.serialization, you can use IDE navigation to get down to the parser and set breakpoints.

Normally, I'd also be happy to publish my own wrappers over FFmpegKit, but video technology is a minefield of patents and licensing, and I don't particularly want to have to deal with that aspect myself.

In the end, this is @tanersener 's project, and I'm willing to contribute support for KMM in whatever way is best for him to maintain.