在Xamarin Android中使用ffmpeg

Ahm*_*aba 7 video android ffmpeg xamarin

我正在使用Xamarin构建一个Android应用程序.该应用程序的要求是从摄像头捕获视频并对视频进行编码以将其发送到服务器.最初我在服务器端使用编码器库对录制的视频进行编码,但事实证明,这对于大型视频文件来说非常不可靠和低效.我已将问题发布在另一个线程上,然后我决定在客户端对视频进行编码,然后将其发送到服务器.我发现编码有点复杂,关于如何做到这一点的信息不多,所以我搜索了解如何使用ffmpeg编解码器对视频进行编码的唯一方法.我找到了一些解决方案.github上有一个项目,演示了如何在Xamarin android项目中使用ffmpeg.但是,运行解决方案不会产生任何输出.该项目有一个二进制ffmpeg文件,使用以下代码安装到手机目录:

_ffmpegBin = InstallBinary(XamarinAndroidFFmpeg.Resource.Raw.ffmpeg, "ffmpeg", false);
Run Code Online (Sandbox Code Playgroud)

下面是将视频编码为不同输出集的示例代码:

            _workingDirectory = Android.OS.Environment.ExternalStorageDirectory.AbsolutePath;
        var sourceMp4 = "cat1.mp4";
        var destinationPathAndFilename = System.IO.Path.Combine (_workingDirectory, "cat1_out.mp4");
        var destinationPathAndFilename2 = System.IO.Path.Combine (_workingDirectory, "cat1_out2.mp4");
        var destinationPathAndFilename4 = System.IO.Path.Combine (_workingDirectory, "cat1_out4.wav");
        if (File.Exists (destinationPathAndFilename))
            File.Delete (destinationPathAndFilename);
        CreateSampleFile(Resource.Raw.cat1, _workingDirectory, sourceMp4);


        var ffmpeg = new FFMpeg (this, _workingDirectory);

        var sourceClip = new Clip (System.IO.Path.Combine(_workingDirectory, sourceMp4));

        var result = ffmpeg.GetInfo (sourceClip);

        var br = System.Environment.NewLine;

        // There are callbacks based on Standard Output and Standard Error when ffmpeg binary is running as a process:

        var onComplete = new MyCommand ((_) => {
            RunOnUiThread(() =>_logView.Append("DONE!" + br + br));
        });

        var onMessage = new MyCommand ((message) => {
            RunOnUiThread(() =>_logView.Append(message + br + br));
        });

        var callbacks = new FFMpegCallbacks (onComplete, onMessage);

        // 1. The idea of this first test is to show that video editing is possible via FFmpeg:
        // It results in a 150x150 movie that eventually zooms on a cat ear. This is desaturated, and there's a fade in.

        var filters = new List<VideoFilter> ();
        filters.Add (new FadeVideoFilter ("in", 0, 100));
        filters.Add(new CropVideoFilter("150","150","0","0"));
        filters.Add(new ColorVideoFilter(1.0m, 1.0m, 0.0m, 0.5m, 1.0m, 1.0m, 1.0m, 1.0m));
        var outputClip = new Clip (destinationPathAndFilename) { videoFilter = VideoFilter.Build (filters)  };
        outputClip.H264_CRF = "18"; // It's the quality coefficient for H264 - Default is 28. I think 18 is pretty good.
        ffmpeg.ProcessVideo(sourceClip, outputClip, true, new FFMpegCallbacks(onComplete, onMessage));

        //2. This is a similar version version in command line only:
        string[] cmds = new string[] {
            "-y",
            "-i",
            sourceClip.path,
            "-strict",
            "-2",
            "-vf",
            "mp=eq2=1:1.68:0.3:1.25:1:0.96:1",
            destinationPathAndFilename2,
            "-acodec",
            "copy",
        };
        ffmpeg.Execute (cmds, callbacks);

        // 3. This lists codecs:
        string[] cmds3 = new string[] {
            "-codecs",
        };
        ffmpeg.Execute (cmds, callbacks);

        // 4. This convers to WAV
        // Note that the cat movie just has some silent house noise.
        ffmpeg.ConvertToWaveAudio(sourceClip, destinationPathAndFilename4, 44100, 2, callbacks, true);
Run Code Online (Sandbox Code Playgroud)

我尝试了不同的命令,但没有生成输出文件.我试图使用这里找到的另一个项目,但这个问题也有同样的问题.我没有得到任何错误,但没有生成输出文件.我真的希望有人可以帮我找到一种方法,我可以设法在我的项目中使用ffmpeg,或以某种方式压缩视频以将其传输到服务器.

如果有人能指出我正确的方向,我将非常感激.

Aka*_*ava 0

请阅读存储库上的更新,它说有第二个包,Xamarin.Android.MP4Transcoder适用于 Android 6.0 及以上版本。

安装 NuGet https://www.nuget.org/packages/Xamarin.Android.MP4Transcoder/

await Xamarin.MP4Transcoder.Transcoder
    .For720pFormat()
    .ConvertAsync(inputFile, ouputFile, f => {
            onProgress?.Invoke((int)(f * (double)100), 100);
     });
return ouputFile;
Run Code Online (Sandbox Code Playgroud)

对于以前的 Android 版本

源代码https://github.com/neurospeech/xamarin-android-ffmpeg

Install-Package Xamarin.Android.FFmpeg
Run Code Online (Sandbox Code Playgroud)

使用它作为模板,这可以让您记录输出并计算进度。

你可以看一下源代码,这个下载了 ffmpeg 并在第一次使用时验证 sha1 哈希值。

public class VideoConverter 
{

    public VideoConverter()
    {

    }

    public File ConvertFile(Context contex,
        File inputFile, 
        Action<string> logger = null, 
        Action<int,int> onProgress = null)
    {
        File ouputFile = new File(inputFile.CanonicalPath + ".mpg");

        ouputFile.DeleteOnExit();

        List<string> cmd = new List<string>();
        cmd.Add("-y");
        cmd.Add("-i");
        cmd.Add(inputFile.CanonicalPath);

        MediaMetadataRetriever m = new MediaMetadataRetriever();
        m.SetDataSource(inputFile.CanonicalPath);

        string rotate = m.ExtractMetadata(Android.Media.MetadataKey.VideoRotation);

        int r = 0;

        if (!string.IsNullOrWhiteSpace(rotate)) {
            r = int.Parse(rotate);
        }

        cmd.Add("-b:v");
        cmd.Add("1M");

        cmd.Add("-b:a");
        cmd.Add("128k");


        switch (r)
        {
            case 270:
                cmd.Add("-vf scale=-1:480,transpose=cclock");
                break;
            case 180:
                cmd.Add("-vf scale=-1:480,transpose=cclock,transpose=cclock");
                break;
            case 90:
                cmd.Add("-vf scale=480:-1,transpose=clock");
                break;
            case 0:
                cmd.Add("-vf scale=-1:480");
                break;
            default:

                break;
        }

        cmd.Add("-f");
        cmd.Add("mpeg");

        cmd.Add(ouputFile.CanonicalPath);

        string cmdParams = string.Join(" ", cmd);

        int total = 0;
        int current = 0;

        await FFMpeg.Xamarin.FFMpegLibrary.Run(
            context,
             cmdParams 
            , (s) => {
                logger?.Invoke(s);
                int n = Extract(s, "Duration:", ",");
                if (n != -1) {
                    total = n;
                }
                n = Extract(s, "time=", " bitrate=");
                if (n != -1) {
                    current = n;
                    onProgress?.Invoke(current, total);
                }
            });

        return ouputFile;
    }

    int Extract(String text, String start, String end)
    {
        int i = text.IndexOf(start);
        if (i != -1)
        {
            text = text.Substring(i + start.Length);
            i = text.IndexOf(end);
            if (i != -1)
            {
                text = text.Substring(0, i);
                return parseTime(text);
            }
        }
        return -1;
    }

    public static int parseTime(String time)
    {
        time = time.Trim();
        String[] tokens = time.Split(':');
        int hours = int.Parse(tokens[0]);
        int minutes = int.Parse(tokens[1]);
        float seconds = float.Parse(tokens[2]);
        int s = (int)seconds * 100;
        return hours * 360000 + minutes * 60100 + s;
    }

}
Run Code Online (Sandbox Code Playgroud)