【问题标题】:Output file using FFmpeg in Xamarin Android在 Xamarin Android 中使用 FFmpeg 输出文件
【发布时间】:2016-05-06 07:02:49
【问题描述】:

我正在使用 Xamarin 构建一个 Android 应用程序。该应用程序的要求是从相机捕获视频并将视频编码以将其发送到服务器。

最初,我在服务器端使用编码器库对录制的视频进行编码,但事实证明它极其不可靠且效率低下,尤其是对于大型视频文件。我已将我的问题发布到另一个线程 here

然后我决定在客户端对视频进行编码,然后将其发送到服务器。我发现编码有点复杂,并且没有太多关于如何做到这一点的信息。因此,我搜索了我知道如何使用 FFmpeg 编解码器对视频进行编码的唯一方法。我找到了一些解决方案。 GitHub 上有一个项目演示了如何在 Xamarin android 项目中使用 FFmpeg。但是,运行该解决方案不会提供任何输出。该项目有一个二进制FFmpeg文件,使用以下代码安装到手机目录:

_ffmpegBin = InstallBinary(XamarinAndroidFFmpeg.Resource.Raw.ffmpeg, "ffmpeg", false);

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

_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 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);

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

如果有人能指出我正确的方向,我将不胜感激。

【问题讨论】:

    标签: android video xamarin ffmpeg


    【解决方案1】:

    试试这个项目,https://github.com/neurospeech/xamarin-android-ffmpeg

    Install-Package Xamarin.Android.FFmpeg
    

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

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

    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;
        }
    
    }
    

    【讨论】:

    • 我也试过这个项目。同样的问题,在目标路径没有生成输出。
    • 您的目标路径必须是可写路径,也请检查日志,可能是它给您一些错误说无法读取文件,文件已经存在或一些编解码器相关的问题?你在尝试什么命令?
    • 我正在尝试将输出写入具有可写权限集的外部存储。我可以将文件写入该位置,但 ffmpeg 编解码器不会对该位置产生任何输出。我没有使用记录器和进度条。我将使用记录器查看它是否产生正确的结果
    • 您好,您找到如何使用 ffmpeg 的解决方案了吗?我有相同的解决方案,但没有出路。
    • @AkashKava 我无法安装您的软件包。我收到以下错误:“包 Xamarin.Android.FFmpeg 1.0.32 与 monoandroid90 (MonoAndroid,Version=v9.0) 不兼容。包 Xamarin.Android.FFmpeg 1.0.32 支持:net (.NETFramework,Version =v0.0)" 你能更新你的包吗?
    【解决方案2】:

    只需在 AndroidManifest 文件中添加权限即可了解如何获取输出。

    android.permission.WRITE_EXTERNAL_STORAG

    【讨论】:

      猜你喜欢
      • 2017-08-10
      • 2018-11-25
      • 2018-09-10
      • 2020-08-17
      • 1970-01-01
      • 1970-01-01
      • 2019-10-30
      • 1970-01-01
      • 2016-11-14
      相关资源
      最近更新 更多