使用FFmpegCore转换视频
ffmpeger 发布于 2021-02-25

作者:Bohdan Stupak

原文:https://www.codeproject.com/Tips/5295527/Converting-Video-with-FFmpegCore


FFmpegCore是围绕FFMpeg/FFProbe的一个方便的包装器,可以方便地处理视频。在本文中,我们将了解如何利用它进行视频转换。


介绍

对于大多数开发人员来说,使用多媒体是一种莫名其妙的事情,因为在使用通常的业务应用程序时很少遇到这种情况。所以,当我被任务转换为我目前正在进行的项目的视频时,我期待着处理一些旧的维护不好的C++库。所以FFmpegCore是一个惊喜,因为它支持使用.NET核心,这是我的专长领域。

本文中的示例将用F#提供,我非常喜欢F#,但它们非常简单,因此将它们翻译成C#应该没有问题。
虽然文档显示这个核心是“一个.NET标准的FFMpeg/FFProbe包装器”,但这并没有说明FFMpeg/fmprobe应该安装在运行应用程序的机器上。
此外,我认为值得澄清的是,FFMpeg是一个跨平台的命令行工具,允许处理视频。
在Linux上,一旦你安装了apt,你就可以在Windows上运行了,这是一个有趣的问题。在Windows上安装FFmpeg只需下载二进制文件并将其放入文件夹即可,但一旦运行该工具,您可能会遇到以下错误:

system.componentmodel.win32exception: the system cannot find the file specified
在静态类FFMpegOptions的帮助下进行了修复:

 let options = FFMpegOptions()
options.RootDirectory <- "path to your binaries"
FFMpegOptions.Configure(options)


查询视频信息

为了查询视频的相关信息,我们使用了同步和异步API的静态FFProbe进行视频分析。让我们继续使用异步版本并序列化输出,以检查FFProbe提供的丰富信息。

 async {
    let! videoInfo = FFProbe.AnalyseAsync fileName |> Async.AwaitTask
    return JsonSerializer.Serialize videoInfo
}
输出可能如下所示:

 {
   "Path":"D:\\giphy.mp4",
   "Extension":".mp4",
   "Duration":{
      "Ticks":17200000,
      "Days":0,
      "Hours":0,
      "Milliseconds":720,
      "Minutes":0,
      "Seconds":1,
      "TotalDays":1.990740740740741E-05,
      "TotalHours":0.00047777777777777776,
      "TotalMilliseconds":1720,
      "TotalMinutes":0.028666666666666667,
      "TotalSeconds":1.72
   },
   "Format":{
      "Duration":{
         "Ticks":17200000,
         "Days":0,
         "Hours":0,
         "Milliseconds":720,
         "Minutes":0,
         "Seconds":1,
         "TotalDays":1.990740740740741E-05,
         "TotalHours":0.00047777777777777776,
         "TotalMilliseconds":1720,
         "TotalMinutes":0.028666666666666667,
         "TotalSeconds":1.72
      },
      "FormatName":"mov,mp4,m4a,3gp,3g2,mj2",
      "FormatLongName":"QuickTime / MOV",
      "StreamCount":1,
      "ProbeScore":100,
      "BitRate":458339,
      "Tags":{
         "major_brand":"isom",
         "minor_version":"512",
         "compatible_brands":"isomiso2avc1mp41",
         "encoder":"Lavf56.40.101"
      }
   },
   "PrimaryAudioStream":null,
   "PrimaryVideoStream":{
      "AvgFrameRate":25,
      "BitsPerRawSample":8,
      "DisplayAspectRatio":{

      },
      "Profile":"Constrained Baseline",
      "Width":480,
      "Height":264,
      "FrameRate":25,
      "PixelFormat":"yuv420p",
      "Rotation":0,
      "Index":0,
      "CodecName":"h264",
      "CodecLongName":"H.264 / AVC / MPEG-4 AVC / MPEG-4 part 10",
      "BitRate":453744,
      "Duration":{
         "Ticks":17200000,
         "Days":0,
         "Hours":0,
         "Milliseconds":720,
         "Minutes":0,
         "Seconds":1,
         "TotalDays":1.990740740740741E-05,
         "TotalHours":0.00047777777777777776,
         "TotalMilliseconds":1720,
         "TotalMinutes":0.028666666666666667,
         "TotalSeconds":1.72
      },
      "Language":"und",
      "Tags":{
         "language":"und",
         "handler_name":"VideoHandler",
         "vendor_id":"[0][0][0][0]"
      }
   },
   "VideoStreams":[
      {
         "AvgFrameRate":25,
         "BitsPerRawSample":8,
         "DisplayAspectRatio":{

         },
         "Profile":"Constrained Baseline",
         "Width":480,
         "Height":264,
         "FrameRate":25,
         "PixelFormat":"yuv420p",
         "Rotation":0,
         "Index":0,
         "CodecName":"h264",
         "CodecLongName":"H.264 / AVC / MPEG-4 AVC / MPEG-4 part 10",
         "BitRate":453744,
         "Duration":{
            "Ticks":17200000,
            "Days":0,
            "Hours":0,
            "Milliseconds":720,
            "Minutes":0,
            "Seconds":1,
            "TotalDays":1.990740740740741E-05,
            "TotalHours":0.00047777777777777776,
            "TotalMilliseconds":1720,
            "TotalMinutes":0.028666666666666667,
            "TotalSeconds":1.72
         },
         "Language":"und",
         "Tags":{
            "language":"und",
            "handler_name":"VideoHandler",
            "vendor_id":"[0][0][0][0]"
         }
      }
   ],
   "AudioStreams":[

   ]
}

转换视频

为了转换视频,可以使用静态FFMpegArguments类,该类支持某种静态生成器模式。同样,它展示了同步和异步API,我们将继续使用后者。

 async {
    let! _ =
        FFMpegArguments
            .FromFileInput(fileName)
            .OutputToFile(outputFileName,
                true,
                fun options -> options
                                .WithVideoCodec(VideoCodec.LibX264)
                                .WithAudioCodec(AudioCodec.Aac)
                                .WithVariableBitrate(4)
                                .Resize(newWidth, newHeight)
                                |> ignore)
            .ProcessAsynchronously() |> Async.AwaitTask
    ()
}
在某些情况下,FFMpeg可能会返回错误。

 "ffmpeg version 2021-01-24-git-1775688292-full_build-www.gyan.dev Copyright (c) 2000-2021 
the FFmpeg developers\n  built with gcc 10.2.0 (Rev6, Built by MSYS2 project)\n  
configuration: --enable-gpl --enable-version3 --enable-static --disable-w32threads 
--disable-autodetect --enable-fontconfig --enable-iconv --enable-gnutls --enable-libxml2 
--enable-gmp --enable-lzma --enable-libsnappy --enable-zlib --enable-libsrt --enable-libssh 
--enable-libzmq --enable-avisynth --enable-libbluray --enable-libcaca --enable-sdl2 
--enable-libdav1d --enable-libzvbi --enable-librav1e --enable-libsvtav1 --enable-libwebp 
--enable-libx264 --enable-libx265 --enable-libxvid --enable-libaom --enable-libopenjpeg 
--enable-libvpx --enable-libass --enable-frei0r --enable-libfreetype --enable-libfribidi 
--enable-libvidstab --enable-libvmaf --enable-libzimg --enable-amf --enable-cuda-llvm 
--enable-cuvid --enable-ffnvcodec --enable-nvdec --enable-nvenc --enable-d3d11va 
--enable-dxva2 --enable-libmfx --enable-libglslang --enable-vulkan --enable-opencl 
--enable-libcdio --enable-libgme --enable-libmodplug --enable-libopenmpt 
--enable-libopencore-amrwb --enable-libmp3lame --enable-libshine --enable-libtheora 
--enable-libtwolame --enable-libvo-amrwbenc --enable-libilbc --enable-libgsm 
--enable-libopencore-amrnb --enable-libopus --enable-libspeex --enable-libvorbis 
--enable-ladspa --enable-libbs2b --enable-libflite --enable-libmysofa --enable-librubberband 
--enable-libsoxr --enable-chromaprint\n  libavutil      
56. 63.101 / 56. 63.101\n  libavcodec     58.117.101 / 58.117.101\n  libavformat    
58. 65.101 / 58. 65.101\n  libavdevice    58. 11.103 / 58. 11.103\n  libavfilter     
7. 96.100 /  7. 96.100\n  libswscale      5.  8.100 /  5.  8.100\n  libswresample   
3.  8.100 /  3.  8.100\n  libpostproc    55.  8.100 / 55.  
8.100\nInput #0, mov,mp4,m4a,3gp,3g2,mj2, from 'D:\\giphy.mp4':\n  Metadata:\n    
major_brand     : isom\n    minor_version   : 512\n    compatible_brands: isomiso2avc1mp41\n
    encoder         : Lavf56.40.101\n  Duration: 00:00:01.72, start: 0.000000, 
bitrate: 458 kb/s\n    Stream #0:0(und): Video: h264 (Constrained Baseline) 
(avc1 / 0x31637661), yuv420p, 480x264 [SAR 1:1 DAR 20:11], 453 kb/s, 25 fps, 25 tbr, 
12800 tbn, 50 tbc (default)\n    Metadata:\n      handler_name    : VideoHandler\n
      vendor_id       : [0][0][0][0]\nCodec AVOption vbr (Variable bit rate mode) 
specified for output file #0 (D:\\kek.mp4) has not been used for any stream. 
The most likely reason is either wrong type (e.g. a video option with no video streams) 
or that it is a private option of some encoder which was not actually used for any stream.
\nStream mapping:\n  Stream #0:0 -> #0:0 (h264 (native) -> h264 (libx264))\nPress [q] to stop, 
[?] for help\n[libx264 @ 000001cd5ac43100] width not divisible by 2 
(101x101)\nError initializing output stream 0:0 -- Error while opening encoder for 
output stream #0:0 - maybe incorrect parameters such as bit_rate, rate, width or 
height\nConversion failed!"
虽然stacktrace相当吓人,但“width not divisible by 2”表明FFMpeg具有奇数宽度和高度的特性。我用这个简单的黑客欺骗它,强迫它转换我的视频。

 let newWidth =
    if videoInfo.PrimaryVideoStream.Height % 2 = 0 then
        videoInfo.PrimaryVideoStream.Height
    else videoInfo.PrimaryVideoStream.Height - 1

这里的videoInfo是上面几段工作的结果。
FFmpegCore可以做更多的事情,比如捕捉屏幕截图,改变视频缩略图等等,但是我会把它留给好奇的读者去研究。


ffmpeger
关注 私信
文章
63
关注
0
粉丝
0