Spencer
Spencer

Reputation: 113

How do I properly use Flutter FFmpegKit to convert video file formats to H.264?

I've been using GPT and publications from Medium to help with my how I'm supposed to use the FFmpeg kit for Flutter but they have been no help. Perhaps I need clarification on what the tool is supposed to do because links like these below have not been of any help and are very outdated:

https://dev.to/usp/flutter-live-streaming-a-complete-guide-2634

https://medium.com/itnext/how-to-make-a-serverless-flutter-video-sharing-app-with-firebase-storage-including-hls-and-411e4fff68fa

https://github.com/arthenica/ffmpeg-kit/blob/main/flutter/flutter/README.md

This is the code i've been trying to run to convert a video file before I upload to Firestore Database.

Future<Uint8List?> convertToH264(Uint8List bytes) async {
  try {
    final filename = const Uuid().v4();
    final tempDir = await getTemporaryDirectory();
    final tempVideoFile = File('${tempDir.path}/$filename.mp4');
    await tempVideoFile.writeAsBytes(bytes);
    final outputPath = '${tempDir.path}/$filename-aac.mp4';

    await FFmpegKit.execute(
      '-i ${tempVideoFile.path} -c:v libx264 -c:a aac $outputPath',
    );
    return await File(outputPath).readAsBytes();
  } catch (e) {
    rethrow;
  }
} 

Upvotes: 0

Views: 541

Answers (1)

Rico
Rico

Reputation: 370

Here is a copy in Java may help you and the most important thing is to make sure that your input if it is a valid video in Uint8List (strongly advice you to use File or filePath if it is possible instead of Uint8List in case of causing OutOfMemory). Obviously the key is the freaking command line, lol. Referring to https://ffmpeg.org/ffmpeg.html.

By the way, you may have to know about the difference among variety of release versions in case of runtime converting error or unnecessary apk size increasing. Therefore, I recommend you choose the version min-gpl on Android (implementation 'com.arthenica:ffmpeg-kit-min-gpl:6.0-2').

  • min: Includes only ffmpeg
  • min-gpl: Includes ffmpeg with all GPL licensed external libraries (libvid.stab, x264, x265, xvidcore) enabled except rubberband
  • https: Includes ffmpeg with gmp and gnutls enabled
  • https-gpl: Includes ffmpeg with gmp, gnutls and all GPL licensed external libraries (libvid.stab, x264, x265, xvidcore) enabled except rubberband
  • audio: Includes ffmpeg with audio libraries (lame, libilbc, libvorbis, opencore-amr, opus, shine, soxr, speex, twolame, vo-amrwbenc) enabled
  • video: Includes ffmpeg with video libraries without GPL license (dav1d, fontconfig, freetype, fribidi, kvazaar, libass, libiconv, libtheora, libvpx, libwebp, snappy, zimg) enabled
  • full: Includes ffmpeg with all external libraries without GPL license (excluding chromaprint, libaom, openh264, openssl, sdl, srt and tesseract) enabled
  • full-gpl: Includes ffmpeg with all external libraries, with or without GPL license, enabled excluding chromaprint, libaom, openh264, openssl, sdl, srt, tesseract and rubberband

See https://github.com/arthenica/ffmpeg-kit/releases and https://github.com/arthenica/ffmpeg-kit/wiki/Versions if you want for more detail.

class Test {
    class final class CompressArgs {
        public String sourcePath;
        public String targetPath;
        /* pixel */
        public Integer width;
        /* pixel */
        public Integer height;
        public Boolean autoResolution;
        /* byte */
        public Long maxSize;
        /* fps */
        public Integer frameRate;
        public String videoCodec;
        /* kb/s */
        public Long videoBitRate;
        public String audioCodec;
        /* kb/s */
        public Long audioBitRate;
        /* hz */
        public Integer audioSampleRate;
        public Integer audioChannel;
    }

    public static void main(String[] args_) { 
        final String BLANK = " ";
        CompressArgs args;
        String command = "-y" + BLANK + // Overwrite output files without asking
//                          "-an -hwaccel mediacodec" + BLANK + // hardware-accelerated HEVC video encoding
                         "-i" + BLANK + args.sourcePath + BLANK + // input file url
                         "-nostats" + BLANK + // Don't print encoding progress or statistics
//                          (args.maxSize != null ? ("-fs" + BLANK + args.maxSize + BLANK) : "") + // the file size limit, expressed in bytes

                         "-c:v copy -preset ultrafast" + BLANK +
                         "-vcodec" + BLANK + (args.videoCodec != null ? args.videoCodec : "libx264") + BLANK + // video codec
                         (args.frameRate != null ? ("-r" + BLANK + args.frameRate + BLANK) : "") + // frame rate
                         (args.videoBitRate != null ? ("-b:v" + BLANK + args.videoBitRate + BLANK) : "") + // video bitrate
//                          (args.width != null && args.height != null ? ("-vf scale=" + args.width + ":" + args.height + BLANK) : "") +

                         "-c:a copy -preset ultrafast" + BLANK +
                         "-acodec" + BLANK + (args.audioCodec != null ? args.audioCodec : "aac") + BLANK + // audio codec
                         (args.audioBitRate != null ? ("-b:a" + BLANK + args.audioBitRate + BLANK) : "") + // audio bitrate
                         (args.audioChannel != null ? ("-ac" + BLANK + args.audioChannel + BLANK) : "") + // the number of audio channels
                         (args.audioSampleRate != null ? ("-ar" + BLANK + args.audioSampleRate + BLANK) : "") + // audio sampling frequency

                         args.targetPath; // output file url
        FFmpegKitConfig.enableLogCallback(log -> {
            Log.i("FFmpegKit", log);
        });
        FFmpegKit.execute(command);
    }
}

Upvotes: 0

Related Questions