看了半晌 雷霄骅 的 ffmpeg 的视频。待续稍后总结。
FFmpeg 是一个开源免费跨平台的视频和音频流方案,属于自由软件,采用 LGPL 或GPL 许可证(依据你选择的组件)。它提供了录制、转换以及流化音视频的完整解决方案。它包含了非常先进的音频/视频编解码库 libavcodec,为了保证高可移植性和编解码质量, libavcodec 里很多 codec 都是从头开发的。
ffmpeg 项目由以下几部分组成:
1、ffmpeg 视频文件转换命令行工具,也支持经过实时电视卡抓取和编码成视频文
件.
2、ffserver 基于 HTTP、 RTSP 用于实时广播的多媒体服务器.也支持时间平移
3、ffplay 用 SDL 和 FFmpeg 库开发的一个简单的媒体播放器
4、libavcodec 一个包含了所有 FFmpeg 音视频编解码器的库.为了保证最优性能和高可复用性,大多数编解码器从头开发的.
5、libavformat 一个包含了所有的普通音视格式的解析器和产生器的库
更多部分
参看:ffmpeg Documentation
下载: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个应用程序了。
也可以参看下面的链接下个之前的版本。
将下载完的软件包解压在任意盘中,然后重命名为 ffmpeg。比如存放在 F 盘。
按 WIN + R 键进入运行界面;输入 cmd,进入 DOS 界面。
输入 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等等
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'
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%
新建一个记事本文件 新建文本文档 .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] ffmpeg 常用命令
FFmpeg功能命令集合
wiki:Encode/H.264
wiki:Slideshow
ffmpeg 常用命令汇总
环境变量我们之前讲过,参看:UNIX再学习 -- 环境变量
备份一下原来的变量值:
%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.cpp : 定义控制台应用程序的入口点。
//
#include "stdafx.h"
#define __STDC_CONSTANT_MACROS
extern "C"
{
#include "libavcodec/avcodec.h"
};
int main()
{
printf("%s", avcodec_configuration());
return 0;
}
打断点,如果不打断点,调试的时候一闪而过什么也看不到的。
错误 MSB8036 找不到 Windows SDK 版本10.0.16299.0。
下载并安装:
Windows SDK (ver. 10.0.16299.91) and Microsoft Emulator for Windows 10 mobile (ver. 15254.1)
#include
#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 工程文件
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;