2016-05-06 124 views
4

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

_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 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,或者以某种方式压缩视频以将其传输到服务器。

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

回答

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

} 
+0

我也试过这个项目。同样的问题,目标路径上不会生成输出。 –

+0

你的目标路径必须是可写路径,也请检查日志,可能会给你一些错误,说不能读取文件,文件已经存在或一些编解码相关的问题?你想要什么命令? –

+0

我正在尝试将输出写入具有可写权限集的外部存储器。我可以将文件写入该位置,但ffmpeg编解码器不会向该位置输出任何输出。我没有使用记录器和进度条。我将使用记录器来查看它是否产生正确的结果 –

0

只是想通过在AndroidManifest文件中添加权限来获得输出。

android.permission.WRITE_EXTERNAL_STORAG