看了半晌 雷霄骅 的 ffmpeg 的视频。待续稍后总结。
一、FFmpeg 简介
FFmpeg 是一个开源免费跨平台的视频和音频流方案,属于自由软件,采用 LGPL 或GPL 许可证(依据你选择的组件)。它提供了录制、转换以及流化音视频的完整解决方案。它包含了非常先进的音频/视频编解码库 libavcodec,为了保证高可移植性和编解码质量, libavcodec 里很多 codec 都是从头开发的。
ffmpeg 项目由以下几部分组成:1、ffmpeg 视频文件转换命令行工具,也支持经过实时电视卡抓取和编码成视频文
件.
2、ffserver 基于 HTTP、 RTSP 用于实时广播的多媒体服务器.也支持时间平移
3、ffplay 用 SDL 和 FFmpeg 库开发的一个简单的媒体播放器
4、libavcodec 一个包含了所有 FFmpeg 音视频编解码器的库.为了保证最优性能和高可复用性,大多数编解码器从头开发的.
5、libavformat 一个包含了所有的普通音视格式的解析器和产生器的库
更多部分
二、下载安装 FFmpeg
下载:Download FFmpeg for Windows 解压后即可使用
该网站中的FFMPEG分为3个版本:Static,Shared,Dev。
前两个版本可以直接在命令行中使用,他们的区别在于:
Static里面只有3个应用程序:ffmpeg.exe,ffplay.exe,ffprobe.exe,每个exe的体积都很大,相关的Dll已经被编译到exe里面去了。
Shared里面除了3个应用程序:ffmpeg.exe,ffplay.exe,ffprobe.exe之外,还有一些Dll,比如说avcodec-54.dll之类的。Shared里面的exe体积很小,他们在运行的时候,到相应的Dll中调用功能。
Dev版本是用于开发的,里面包含了库文件xxx.lib以及头文件xxx.h,这个版本不包含exe文件。打开系统命令行接面,切换到ffmpeg所在的目录,就可以使用这3个应用程序了。
也可以参看下面的链接下个之前的版本。
下载:Index of /builds/win32/static/
下载:Index of /builds/win32/shared/
下载:Index of /builds/win32/dev/
三、使用
将下载完的软件包解压在任意盘中,然后重命名为 ffmpeg。比如存放在 F 盘。
第一、进入进入DOS操作界面
按 WIN + R 键进入运行界面;输入 cmd,进入 DOS 界面。
第二、进入 F 盘中的 ffmpeg\bin文件夹
输入 F: 回车,进入 F 盘;然后 cd ffmepg\bin 即进入该文件夹。
其中DOS指令令和shell指令对比,参看: UNIX For DOS Users
基本的DOS命令
最关键命令打开指定文件夹命令 cd {文件路径}
切换到上一级文件夹 cd ..
切换到当前目录下名为xxx的文件夹 cd xxx
改变当前盘符命令 c:
其他命令查看目录内容命令 dir
创建目录命令 md
文件复制命令 copy
删除文件命令 del
清除屏幕命令 cls
Windows系统提供的额外命令例如ping, ipconfig等等
第三、测试
命令行中输入ffmpeg.exe,查看弹出的信息。(当然也可以不写后缀 .exe )
F:\ffmpeg\bin>ffmpeg
ffmpeg version N-86625-gbbaca6e Copyright (c) 2000-2017 the FFmpeg developers
built with gcc 7.1.0 (GCC)
configuration: --enable-gpl --enable-version3 --enable-cuda --enable-cuvid --enable-d3d11va --enable-dxva2 --enable-libmfx --enable-nvenc --enable-avisynth --enable-bzlib --enable-fontconfig --enable-frei0r --enable-gnutls --enable-iconv --enable-libass --enable-libbluray --enable-libbs2b --enable-libcaca --enable-libfreetype --enable-libgme --enable-libgsm --enable-libilbc --enable-libmodplug --enable-libmp3lame --enable-libopencore-amrnb --enable-libopencore-amrwb --enable-libopenh264 --enable-libopenjpeg --enable-libopus --enable-librtmp --enable-libsnappy --enable-libsoxr --enable-libspeex --enable-libtheora --enable-libtwolame --enable-libvidstab --enable-libvo-amrwbenc --enable-libvorbis --enable-libvpx --enable-libwavpack --enable-libwebp --enable-libx264 --enable-libx265 --enable-libxavs --enable-libxvid --enable-libzimg --enable-lzma --enable-zlib
libavutil 55. 66.100 / 55. 66.100
libavcodec 57. 99.102 / 57. 99.102
libavformat 57. 75.100 / 57. 75.100
libavdevice 57. 7.100 / 57. 7.100
libavfilter 6. 94.100 / 6. 94.100
libswscale 4. 7.101 / 4. 7.101
libswresample 2. 8.100 / 2. 8.100
libpostproc 54. 6.100 / 54. 6.100
Hyper fast Audio and Video encoder
usage: ffmpeg [options] [[infile options] -i infile]... {[outfile options] outfile}...
Use -h to get full help or, even better, run 'man ffmpeg'
测试指令 利用mpeg4编码方式
使用指令 ffmpeg -f image2 -i %02d.jpg -vcodec mpeg4 -s 1920x1080 multi_jpg3.mp4
F:\ffmpegbin>ffmpeg -f image2 -i %02d.jpg -vcodec mpeg4 -s 1920x1080 multi_jpg3.mp4
ffmpeg version N-86625-gbbaca6e Copyright (c) 2000-2017 the FFmpeg developers
built with gcc 7.1.0 (GCC)
configuration: --enable-gpl --enable-version3 --enable-cuda --enable-cuvid --enable-d3d11va --enable-dxva2 --enable-libmfx --enable-nvenc --enable-avisynth --enable-bzlib --enable-fontconfig --enable-frei0r --enable-gnutls --enable-iconv --enable-libass --enable-libbluray --enable-libbs2b --enable-libcaca --enable-libfreetype --enable-libgme --enable-libgsm --enable-libilbc --enable-libmodplug --enable-libmp3lame --enable-libopencore-amrnb --enable-libopencore-amrwb --enable-libopenh264 --enable-libopenjpeg --enable-libopus --enable-librtmp --enable-libsnappy --enable-libsoxr --enable-libspeex --enable-libtheora --enable-libtwolame --enable-libvidstab --enable-libvo-amrwbenc --enable-libvorbis --enable-libvpx --enable-libwavpack --enable-libwebp --enable-libx264 --enable-libx265 --enable-libxavs --enable-libxvid --enable-libzimg --enable-lzma --enable-zlib
libavutil 55. 66.100 / 55. 66.100
libavcodec 57. 99.102 / 57. 99.102
libavformat 57. 75.100 / 57. 75.100
libavdevice 57. 7.100 / 57. 7.100
libavfilter 6. 94.100 / 6. 94.100
libswscale 4. 7.101 / 4. 7.101
libswresample 2. 8.100 / 2. 8.100
libpostproc 54. 6.100 / 54. 6.100
Input #0, image2, from '%02d.jpg':
Duration: 00:00:03.16, start: 0.000000, bitrate: N/A
Stream #0:0: Video: mjpeg, yuvj444p(pc, bt470bg/unknown/unknown), 5184x3456, 25 tbr, 25 tbn, 25 tbc
File 'multi_jpg3.mp4' already exists. Overwrite ? [y/N] y
Stream mapping:
Stream #0:0 -> #0:0 (mjpeg (native) -> mpeg4 (native))
Press [q] to stop, [?] for help
[swscaler @ 000000000250a960] deprecated pixel format used, make sure you did set range correctly
Output #0, mp4, to 'multi_jpg3.mp4':
Metadata:
encoder : Lavf57.75.100
Stream #0:0: Video: mpeg4 ( [0][0][0] / 0x0020), yuv420p, 1920x1080, q=2-31, 200 kb/s, 25 fps, 12800 tbn, 25 tbc
Metadata:
encoder : Lavc57.99.102 mpeg4
Side data:
cpb: bitrate max/min/avg: 0/0/200000 buffer size: 0 vbv_delay: -1
[swscaler @ 0000000006f100a0] deprecated pixel format used, make sure you did set range correctly
Last message repeated 1 times
[swscaler @ 0000000006f100a0] deprecated pixel format used, make sure you did set range correctly
[swscaler @ 0000000006f100a0] deprecated pixel format used, make sure you did set range correctly
frame= 79 fps=4.0 q=24.8 Lsize= 4507kB time=00:00:03.12 bitrate=11833.3kbits/s speed=0.157x
video:4505kB audio:0kB subtitle:0kB other streams:0kB global headers:0kB muxing overhead: 0.033575%
当然也可以使用 bat 脚本来实现
新建一个记事本文件 新建文本文档 .txt,将其改为 ffmpeg.bat 即 bat 脚本。
然后编辑,比如 ffmpeg -i input.avi -b:v 640k output.ts 保存。
然后点击 ffmpeg.bat 即可跳转到 DOS 界面执行。
当然可能有局限性,比如上面那个例子我在脚本上就无法执行,现在还没有找到原因。
再举一个有意思的例子,将MP4转换成gif格式
ffmpeg -ss 00:00:00.000 -i haituoshan.mp4 -pix_fmt rgb24 -r 10 -s 1920x1080 -t 00:00:3.000 output.gif
说明:将输入的文件从(-ss)设定的时间开始以10帧频率,输出到1920x1080大小的 gif 中,时间长度为-t 设定的参数。通过这样转换出来的 gif 一般都比较大,可以使用 ImageMagick 来优化图片的大小。
当然你也可以使用图片压缩工具:在线图片压缩-在线图片压缩软件
常用指令参看:
[FFmpeg] ffmpeg 常用命令
ffmpeg 常用命令汇总
四、修改环境变量
点击 计算机->属性->高级系统设置->高级->环境变量
环境变量我们之前讲过,参看:UNIX再学习 -- 环境变量
将“用户变量”中的 PATH 变量值改为你的 ffmpeg\bin 文件夹位置,点击确定保存更改。
备份一下原来的变量值:
%CDSROOT%\openaccess\bin\win32\opt;%CDSROOT%\tools\capture;%CDSROOT%\tools\pspice;%CDSROOT%\tools\
specctra\bin;%CDSROOT%\tools\fet\bin;%CDSROOT%\tools\libutil\bin;%CDSROOT%\tools\bin;%CDSROOT%\
tools\pcb\bin;;%USERPROFILE%\AppData\Local\Microsoft\WindowsApps
注意
如果在这个窗口输入的内容有误,那么有可能会造成 Windows 无法正常启动。如果在"用户变量"设置下没有 PATH条目,点击新建按钮创建。在变量名栏输入 PATH。
这个方法可以让当前用户能够使用 FFmpeg。其他 Windows 用户不能够使用。如果要使每个用户都能够使用,你需要在 "系统变量" 的PATH条目中添加你的 ffmpeg\bin 文件夹位置。注意不要够删除在变量中原来已有的内容。
测试
修改前,无法运行 ffmpeg 程序
修改后,可以运行 ffmpeg 程序
五、VS 下 FFmpeg 开发环境搭建
参看:VS配置FFmpeg开发环境
首先下载相应的 FFmpeg 开发包
然后新建控制台工程
打开 VS;
文件->新建->项目->Win32控制台应用程序,点击完成。
注意,选择的位置最好不要有 空格或者汉字。
拷贝 FFmpeg 开发文件
头文件( *.h)拷贝至项目文件夹的include子文件夹下
导入库文件( *.lib)拷贝至项目文件夹的lib子文件夹下
动态库文件( *.dll) 拷贝至项目文件夹下
点击右键,选择在资源管理器中打开文件夹,进入项目目录。
(注意,如果手动进入注意文件夹位置,我就是没找好位置,试了半天最后才发现,将上面的这些文件拷贝到错误的文件夹下了)
PS:如果直接使用官网上下载的 FFmpeg 开发文件。则可能还需要将 MinGW 安装目录中的 inttypes.h, stdint.h, _mingw.h 三个文件拷贝至项目文件夹的 include 子文件夹下。
上面的下载配置可是没有这三个文件的,如需要 下载:小练习-FFmpeg配置
配置开发文件
打开属性面板
解决方案资源管理器->右键单击项目->属性
头文件配置
配置属性->C/C++->常规->附加包含目录,输入“ include”(刚才拷贝头文件的目录)
导入库配置
配置属性->链接器->常规->附加库目录,输入“ lib” (刚才拷贝库文件的目录)
配置属性->链接器->输入->附加依赖项,输入“ avcodec.lib; avformat.lib; avutil.lib; avdevice.lib; avfilter.lib; postproc.lib; swresample.lib; swscale.lib”(导入库的文件名)
动态库不用配置
测试
将 FFmpeg.cpp 添加测试代码,改为如下:
// FFmpeg.cpp : 定义控制台应用程序的入口点。
//
#include "stdafx.h"
#define __STDC_CONSTANT_MACROS
extern "C"
{
#include "libavcodec/avcodec.h"
};
int main()
{
printf("%s", avcodec_configuration());
return 0;
}
打断点,如果不打断点,调试的时候一闪而过什么也看不到的。
在return 0; 左边点击一下,出现红点,即为断点。
然后点击本地Windows调试器,出现此项目已经过期,选择 是。
可看到出现结果,说明FFmpeg配置成功。
六、问题分析
有时调试时会出现版本不一致的问题.
查看项目Windows SDK 版本为 8.1
解决方法:
下载并安装:Windows Software Development Kit (SDK) for Windows 8.1
错误 MSB8036 找不到 Windows SDK 版本10.0.16299.0。
下载并安装:
Windows SDK (ver. 10.0.16299.91) and Microsoft Emulator for Windows 10 mobile (ver. 15254.1)
七、示例演示
参看:利用FFmpeg将Jpeg图片转为任意视频容器格式
在一些嵌入式系统中,视频以 jpeg 图像格式传出来,而且数据量非常大。这种情况下如果要对 jpeg 图像进行解码并且重新编码成 264 之类的格式再放入视频容器中会消耗大量的 CPU 资源,若不是性能特别犀利的 CPU 是无法承受的,这个时候有一个折衷的办法,就是直接将jpeg连续保存起来(也就是保存成 mjpeg 视频格式),然后直接放入视频容器中。
这就话就解释了,为什么要用保存成 mjpeg。因为成千上万张图片通过 264 编码确实好慢。
下面是相关的源码:
#include <stdio.h>
#include "stdafx.h"
extern "C"//包含C文件头
{
#include "libavformat/avformat.h"
};
#define DATASIZE 1024*1024
AVStream *add_vidio_stream(AVFormatContext *oc, enum AVCodecID codec_id)//用以初始化一个用于输出的AVFormatContext结构体
{
AVStream *st;
AVCodec *codec;
st = avformat_new_stream(oc, NULL);
if (!st)
{
printf("Could not alloc stream\n");
exit(1);
}
codec = avcodec_find_encoder(codec_id);//查找mjpeg解码器
if (!codec)
{
printf("codec not found\n");
exit(1);
}
avcodec_get_context_defaults3(st->codec, codec);//申请AVStream->codec(AVCodecContext对象)空间并设置默认值(由avcodec_get_context_defaults3()设置
st->codec->bit_rate = 400000;//设置采样参数,即比特率
st->codec->width = 1080;//设置视频宽高,这里跟图片的宽高保存一致即可
st->codec->height = 1800;
st->codec->time_base.den = 10;//设置帧率
st->codec->time_base.num = 1;
st->codec->pix_fmt = PIX_FMT_YUV420P;//设置像素格式
st->codec->codec_tag = 0;
if (oc->oformat->flags & AVFMT_GLOBALHEADER)//一些格式需要视频流数据头分开
st->codec->flags |= CODEC_FLAG_GLOBAL_HEADER;
return st;
}
void main()
{
AVFormatContext *ofmt_ctx = NULL;//其包含码流参数较多,是一个贯穿始终的数据结构,很多函数都要用到它作为参数
const char *out_filename = "out.mkv";//输出文件路径,在这里也可以将mkv改成别的ffmpeg支持的格式,如mp4,flv,avi之类的
int ret;//返回标志
av_register_all();//初始化解码器和复用器
avformat_alloc_output_context2(&ofmt_ctx, NULL, NULL, out_filename);//初始化一个用于输出的AVFormatContext结构体,视频帧率和宽高在此函数里面设置
if (!ofmt_ctx)
{
printf("Could not create output context\n");
return;
}
AVStream *out_stream = add_vidio_stream(ofmt_ctx, AV_CODEC_ID_MJPEG);//创造输出视频流
av_dump_format(ofmt_ctx, 0, out_filename, 1);//该函数会打印出视频流的信息,如果看着不开心可以不要
if (!(ofmt_ctx->oformat->flags & AVFMT_NOFILE))//打开输出视频文件
{
ret = avio_open(&ofmt_ctx->pb, out_filename, AVIO_FLAG_WRITE);
if (ret < 0) {
printf("Could not open output file '%s'", out_filename);
return;
}
}
if (avformat_write_header(ofmt_ctx, NULL) < 0)//写文件头(Write file header)
{
printf("Error occurred when opening output file\n");
return;
}
int frame_index = 0;//放入视频的图像计数
unsigned char *mydata = new unsigned char[DATASIZE];
AVPacket pkt;
av_init_packet(&pkt);
pkt.flags |= AV_PKT_FLAG_KEY;
pkt.stream_index = out_stream->index;//获取视频信息,为压入帧图像做准备
while (frame_index<100)//将图像压入视频中
{
FILE *file;//打开一张jpeg图像并读取其数据,在这里图像最大为1M,如果超过1M,则需要修改1024*1024这里
fopen_s(&file, "1.jpg", "rb");
pkt.size = fread(mydata, 1, DATASIZE, file);
pkt.data = mydata;
fclose(file);
if (av_interleaved_write_frame(ofmt_ctx, &pkt) < 0) //写入图像到视频
{
printf("Error muxing packet\n");
break;
}
printf("Write %8d frames to output file\n", frame_index);//打印出当前压入的帧数
frame_index++;
}
av_free_packet(&pkt);//释放掉帧数据包对象
av_write_trailer(ofmt_ctx);//写文件尾(Write file trailer)
delete[]mydata;//释放数据对象
if (ofmt_ctx && !(ofmt_ctx->oformat->flags & AVFMT_NOFILE))
avio_close(ofmt_ctx->pb);//关闭视频文件
avformat_free_context(ofmt_ctx);//释放输出视频相关数据结构
return;
}
这是我写的工程文件:FFmpeg 工程文件
(PS:参看博文里的工程文件,反正我调式是一直失败的,不过源码还是值得参考的)。
执行结果生成 out.mkv 视频
思考,上面实现的是将一张图片循环100次。如果是有编号顺序的图片呢
例如,将编号从 0001~1000 的图片转为视频。
使用 sprintf 将图片名写入字符串,然后使用 fopen_s 打开。
char bufName[50];
int i = 0;
for (i=1;i<=1000;i++)
//while (frame_index<100)//将图像压入视频中
{
sprintf(bufName, "%04d.jpg", i);
printf("%s\n",bufName);
FILE *file;//打开一张jpeg图像并读取其数据,在这里图像最大为1M,如果超过1M,则需要修改1024*1024这里
fopen_s(&file, bufName, "rb");
pkt.size = fread(mydata, 1, DATASIZE, file);
pkt.data = mydata;
fclose(file);
if (av_interleaved_write_frame(ofmt_ctx, &pkt) < 0) //写入图像到视频
{
printf("Error muxing packet\n");
break;
}
//printf("Write %8d frames to output file\n", frame_index);//打印出当前压入的帧数
//frame_index++;
}
根据实际情况修改 DATASIZE ,应超过图片大小的最大值。
#define DATASIZE 1024*1024*50
然后,还要根据实际情况修改图片的参数信息。
st->codec->bit_rate = 400000;//设置采样参数,即比特率
st->codec->width = 5184;//设置视频宽高,这里跟图片的宽高保存一致即可
st->codec->height = 3456;
st->codec->time_base.den = 2;//设置帧率
st->codec->time_base.num = 1;
到此就 OK,即可调式生成视频。
八、总结
用时一天半,终于把 FFmpeg 在 Windows 下的操作总结清楚了。说实话一开始对于 DOS 命令、VS 创建项目等都是不熟的,再将遇到的问题逐一解决,总的来说收获挺多的。期间 FFmpeg 测试的时候,将图片或视频转为 gif,也是挺有意思。我的微信公众号又要有的新内容了 哈哈。