2016-05-06 166 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