1、FFmpeg下载
1)Windows 64位
下载地址:https://ffmpeg.zeranoe.com/builds/win64/static/ffmpeg-20190107-e9564f7-win64-static.zip
2)Windows 32位
下载地址:https://ffmpeg.zeranoe.com/builds/win32/static/ffmpeg-20190107-e9564f7-win32-static.zip
3)MacOS 64位
下载地址:https://ffmpeg.zeranoe.com/builds/macos64/static/ffmpeg-20190107-e9564f7-macos64-static.zip
2、Linux下安装
其它系统中下载下来可以直接使用,Linux下需要安装一下,具体步骤如下,
安装依赖包:
yum install libtheora-devel libvorbis-devel
FFmpeg编译安装:
由于系统不同,会导致依赖也不尽相同,需根据报错信息逐渐安装依赖
wget http://ffmpeg.org/releases/ffmpeg-3.3.2.tar.bz2
tar jxvf ffmpeg-3.3.2.tar.bz2
cd ffmpeg-3.3.2
# 如下是个人需要的编译参数,可以根据实际情况增减
./configure --prefix=/usr/local/ffmpeg \
--enable-shared \
--enable-libfdk-aac \
--enable-gpl \
--enable-nonfree \
--enable-postproc \
--enable-avfilter \
--enable-pthreads \
--enable-libmp3lame \
--enable-libtheora \
--enable-libvorbis \
--enable-libx264 \
--enable-libxvid \
--enable-decoder=libx264 \
--enable-encoder=libx264
安装FFmpeg
make && make install
安装后,查看版本
./bin/ffmpeg -version
3、使用FFmpeg转换代码
1)读取视频文件和输出帧Jpeg图片(不涉及管道或内存/文件流)
string str_MyProg = "C:/FFmpeg/bin/ffmpeg.exe";
string VideoPath = "C:/someFolder/test_vid.mp4";
string save_folder = "C:/someOutputFolder/";
//#设置参数以直接输出图像序列(帧)
string str_CommandArgs = "-i " + VideoPath + " -vf fps=25/1 " + save_folder + "n_%03d.jpg"; //the n_%03d replaces "n++" count
System.Diagnostics.ProcessStartInfo cmd_StartInfo = new System.Diagnostics.ProcessStartInfo(str_MyProg, str_CommandArgs);
cmd_StartInfo.RedirectStandardError = false; //set false
cmd_StartInfo.RedirectStandardOutput = false; //set false
cmd_StartInfo.UseShellExecute = true; //set true
cmd_StartInfo.CreateNoWindow = true; //don't need the black window
//创建一个进程,分配它的ProcessStartInfo并启动它
System.Diagnostics.Process cmd = new System.Diagnostics.Process();
cmd.StartInfo = cmd_StartInfo;
cmd.Start();
2)管道方法
using System;
using System.IO;
using System.Net;
using System.Drawing;
using System.Diagnostics;
using System.Collections.Generic;
namespace FFmpeg_Vid_to_JPEG //replace with your own project "namespace"
{
class Program
{
public static void Main(string[] args)
{
ExtractFrames();
}
public static void ExtractFrames()
{
string FFmpegPath = "C:/FFmpeg/bin/ffmpeg.exe";
string VideoPath = "C:/someFolder/test_vid.mp4";
//# FFmpeg 使用命令参数
string str_myCommandArgs = "-i " + VideoPath + " -f image2pipe -c:v mjpeg -q:v 2 -vf fps=25/1 pipe:1";
//# 保存图片路径
string save_folder = "C:/someOutputFolder/";
string save_filename = "";
MemoryStream mStream = new MemoryStream(); //创建一次,循环相同的每帧
bool got_current_JPG_End = false; //标记开始提取流中的图像字节
int pos_in_Buffer = 0; //缓冲区中的pos(在检查Jpeg开始/结束字节时)
int this_jpeg_len = 0; // 保存单个jpeg图像字节以保存…长度正确,避免裁切效果
int pos_jpeg_start = 0; int pos_jpeg_end = 0; //在整个流中标记一个图像的开始/结束pos
int jpeg_count = 0; //导出Jpeg文件的计数(替换“n++”计数)
int frames_expected_Total = 0; //停止前要获得的帧数
//# 使用输入视频的宽度x高度作为缓冲区大小 //eg: size 921600 = 1280 W x 720H
int BufferSize = 921600;
byte[] buffer = new byte[BufferSize + 1];
// 创建一个进程,分配它的ProcessStartInfo并启动它
ProcessStartInfo cmd_StartInfo = new ProcessStartInfo(FFmpegPath, str_myCommandArgs);
cmd_StartInfo.RedirectStandardError = true;
cmd_StartInfo.RedirectStandardOutput = true; //设置为true将进程stdout重定向到进程。StandardOutput StreamReader
cmd_StartInfo.UseShellExecute = false;
cmd_StartInfo.CreateNoWindow = true; //不创建黑窗口
Process cmd = new System.Diagnostics.Process();
cmd.StartInfo = cmd_StartInfo;
cmd.Start();
if (cmd.Start())
{
//# holds FFmpeg output bytes stream...
var ffmpeg_Output = cmd.StandardOutput.BaseStream; //replaces: fStream = cmd.StandardOutput.BaseStream as FileStream;
cmd.BeginErrorReadLine(); //# 开始接收FFmpeg输出字节流
//# 获取(读取)流中的前两个字节,因此可以检查jpeg的SOI (xFF xD8)
//#每个“读取”自动前进读取“数量”…
ffmpeg_Output.Read(buffer, 0, 1);
ffmpeg_Output.Read(buffer, 1, 1);
pos_in_Buffer = this_jpeg_len = 2; //更新读取的pos
//# 首先我们知道jpeg的SOI总是处于缓冲pos:[0]和[1]
pos_jpeg_start = 0; got_current_JPG_End = false;
//# testing amount... Duration 4.88 sec, FPS 25 --> (25 x 4.88) = 122 frames
frames_expected_Total = 122; //122; //number of Jpegs to get before stopping.
while(true)
{
//# 对于管道视频,您必须手动退出流
if ( jpeg_count == (frames_expected_Total + 1) )
{
cmd.Close(); cmd.Dispose(); //退出进程
break; //如果获取到所需的帧jpeg数,则退出
}
//#否则正常读取
ffmpeg_Output.Read(buffer, pos_in_Buffer, 1);
this_jpeg_len +=1; //add 1 to expected jpeg bytes length
//#查找JPEG start (SOI是字节0xFF 0xD8)
if ( (buffer[pos_in_Buffer] == 0xD8) && (buffer[pos_in_Buffer-1] == 0xFF) )
{
if (got_current_JPG_End == true)
{
pos_jpeg_start = (pos_in_Buffer-1);
got_current_JPG_End = false;
}
}
//# 查找JPEG结束符(EOI是字节0xFF 0xD9),然后保存文件
if ( (buffer[pos_in_Buffer] == 0xD9) && (buffer[pos_in_Buffer-1] == 0xFF) )
{
if (got_current_JPG_End == false)
{
pos_jpeg_end = pos_in_Buffer; got_current_JPG_End = true;
//# 更新保存的文件名
save_filename = save_folder + "n_" + (jpeg_count).ToString() + ".jpg";
try
{
//# 如果Jpeg保存文件夹不存在,则创建它。
if ( !Directory.Exists( save_folder ) ) { Directory.CreateDirectory( save_folder ); }
}
catch (Exception)
{
//# 处理任何文件夹创建错误在这里。
}
mStream.Write(buffer, pos_jpeg_start, this_jpeg_len); //
//# 保存到磁盘
File.WriteAllBytes(@save_filename, mStream.ToArray());
//recycle MemoryStream, avoids creating multiple = new MemoryStream();
mStream.SetLength(0); mStream.Position = 0;
//# 下一个pic重置
jpeg_count +=1; this_jpeg_len=0;
pos_in_Buffer = -1; //使其在递增部分变为0 pos
}
}
pos_in_Buffer += 1; //增量以在stdOut流中存储下一个字节
} //# end While
}
else
{
// 这里的处理程序代码用于“进程未运行”的情况
}
} //end ExtractFrame function
} //end class
} //end program