FFMPEG编译
- 前言
- 一、FFMPEG是什么
- 二、怎么使用
- 1.环境准备
- 1.1源码下载
- 1.2NDK环境下载
- 2.源码编译
- 2.1NDK编译
- 2.2GCC编译
- 3.引用
- 总结
- Demo编译
- 指令
前言
最近想深入了解一下FFMPEG开源库的使用,于是着手从头弄一个轮子,然后按照自己的想法去造。
一、FFMPEG是什么
这个就不解释了,很强大的视频编解码库,初学者就了解到这么多了,很多内容我准备一遍探索一遍去完善笔记。
这里提供一些编解码功能去对视频进行操作。
二、怎么使用
1.环境准备
由于编译好的FFMPEG准备在Android终端上使用,所以准备用NDK编译方式去编译,我这用的是linux编译环境,然后运行的Android终端是Android-9。
1.1源码下载
贴一个官网链接:http://www.ffmpeg.org/olddownload.html ,这里可以去找想要的版本
1.2NDK环境下载
这里使用的NDK环境是android-ndk-r11,NDK环境安装可以参考一下网上的文章,我这里因为是现成的,就没有安装了。=。=
忘记了,还有一个不错的编解码库openh264,记得下载这个不然会报错。
PS:不同的NDK环境,编译FFMPEG的时候,会因为FFMPEG的版本变动而出现报错,需要手动解决。避免踩坑,建议使用已经成功编译的匹配版本,除非有些功能必须使用。
2.源码编译
2.1NDK编译
首先需要编译FFMPEG,根据编译环境,目标机器架构,以及NDK,需要进行配置。FFMPEG有一个配置脚本configure用来根据不同的环境需求进行配置,大概情况就是配置完之后编译,然后安装。这里用脚本来一次搞定。
#!/bin/bash
NDK=/opt/android_build/android-ndk-r11
SYSROOT=$NDK/platforms/android-19/arch-arm/
TOOLCHAIN=$NDK/toolchains/arm-linux-androideabi-4.9/prebuilt/linux-x86_64
CFLAGS="-O3 -Wall -DANDROID -DNDEBUG -nostdlib"
EXTRA_CFLAGS="-march=armv7-a -mfpu=neon \
-mfloat-abi=softfp "
OPTIMIZE_CFLAGS="-marm"
CPU=arm
PREFIX=****/FFmpeg-2.7.2-use-zip/android-21
#ADDI_CFLAGS="-I/home/ndk/arm/x264/include"
#ADDI_LDFLAGS="-L/home/ndk/arm/x264/lib"
ADDI_CFLAGS="-I/home/hzg/mypath/simpleexample_ffmpeg/openh264/include"
ADDI_LDFLAGS="-L/home/hzg/mypath/simpleexample_ffmpeg/openh264/lib"
#--disable-demuxers**
#**--disable-decoders**
#**--disable-devices**
#**--disable-filters**
#**--enable-decoder=h264**
#**--enable-decoder=mp3***
#**--enable-demuxer=mpegts**
function build_one
{
#make distclean
./configure \
--prefix=$PREFIX \
--enable-shared \
--enable-nonfree \
--enable-gpl \
--enable-swscale \
--enable-asm \
--enable-yasm \
--enable-stripping \
--disable-libx264 \
--enable-libopenh264 \
--enable-demuxers \
--enable-decoders \
--disable-yasm \
--disable-devices \
--disable-filters \
--disable-programs \
--disable-doc \
--disable-ffmpeg \
--disable-ffplay \
--disable-ffprobe \
--disable-ffserver \
--disable-avdevice \
--disable-doc \
--disable-symver \
--disable-debug \
--disable-network \
--disable-hwaccels \
--disable-indevs \
--disable-outdevs \
--disable-iconv \
--enable-fast-unaligned \
--cross-prefix=$TOOLCHAIN/bin/arm-linux-androideabi- \
--target-os=linux \
--arch=arm \
--cpu=armv7-a \
--enable-cross-compile \
--sysroot=$SYSROOT \
--extra-cflags="-march=armv7-a -mfpu=neon -mfloat-abi=softfp -DFF_OPT_ZIP -DFF_OPT_LESSDIRTY -DWITH_CHANGE_BY_ZTE -DRECTIFY_YUV422 -DPAL_ENCODE -O0 $ADDI_CFLAGS" \
--extra-ldflags="$ADDI_LDFLAGS"
#$ADDITIONAL_CONFIGURE_FLAG
#--extra-cflags="-Os -fpic -mfpu noen\
#--extra-cflags="-Os -fpic -mfpu neon\
#--extra-cflags="-Os -mfpu neon -fPIC -DANDROID -mfpu=neon -mfloat-abi=softfp ADDI_CFLAGS "
make clean
make -j32
make DESTDIR=/home/hzg/mypath/simpleexample_ffmpeg/FFmpeg-2.7.2-use-zip/android-21 install
}
build_one
在configure文件配置一下如下库名
SLIBNAME_WITH_MAJOR='$(SLIBPREF)$(FULLNAME)-$(LIBMAJOR)$(SLIBSUF)'
LIB_INSTALL_EXTRA_CMD='$$(RANLIB) "$(LIBDIR)/$(LIBNAME)"'
SLIB_INSTALL_NAME='$(SLIBNAME_WITH_MAJOR)'
SLIB_INSTALL_LINKS='$(SLIBNAME)'
编译完FFMPEG之后,会在目标目录下生成对应的库,头文件,以及执行文件。
头文件:
./build/include/libavutil/log.h
./build/include/libavutil/downmix_info.h
./build/include/libavutil/error.h
./build/include/libavutil/ripemd.h
./build/include/libavutil/fifo.h
./build/include/libavutil/imgutils.h
./build/include/libavutil/cpu.h
./build/include/libavutil/base64.h
./build/include/libavutil/random_seed.h
./build/include/libavutil/intreadwrite.h
库:
./android-21/lib/libavcodec-56.so
./android-21/lib/libswresample.so
./android-21/lib/libpostproc-53.so
./android-21/lib/libavcodec.so
./android-21/lib/libavutil-54.so
./android-21/lib/libavfilter.so
./android-21/lib/libpostproc.so
./android-21/lib/libswscale.so
./android-21/lib/libavformat.so
./android-21/lib/libavfilter-5.so
./android-21/lib/libavformat-56.so
./android-21/lib/libswresample-1.so
./android-21/lib/libswscale-3.so
./android-21/lib/libavutil.so
执行程序
ffmpeg
ffprobe
2.2GCC编译
新建一个脚本build_linux.sh。一样的先配置,由于服务器原因,需要禁用x86asm,然后就是编译动态库,再增加一个安装路径。
./configure\
--disable-x86asm\
--enable-shared\
--prefix=./linux-build/
make install -j32
一样的会生成config.h,这个文件保存着编译的配置信息,是**./configure**运行的结果。其次是编译安装出来的程序/库/头文件
-rw-rw-r-- 1 hzg hzg 84419 Apr 25 15:47 config.h
drwxrwxrwx 6 hzg hzg 4096 Apr 25 15:47 linux-build
drwxrwxr-x 12 hzg hzg 12288 Apr 26 15:45 libavutil
drwxrwxr-x 5 hzg hzg 4096 Apr 26 15:45 doc
drwxrwxr-x 6 hzg hzg 4096 Apr 26 15:45 libswresample
drwxrwxr-x 7 hzg hzg 4096 Apr 26 15:45 libswscale
drwxrwxr-x 2 hzg hzg 4096 Apr 26 15:45 fftools
drwxrwxr-x 14 hzg hzg 98304 Apr 26 15:45 libavcodec
drwxrwxr-x 3 hzg hzg 45056 Apr 26 15:45 libavformat
drwxrwxr-x 8 hzg hzg 40960 Apr 26 15:45 libavfilter
drwxrwxr-x 3 hzg hzg 4096 Apr 26 15:45 libavdevice
-rwxrwxr-x 1 hzg hzg 632840 Apr 26 15:45 ffprobe_g
-rwxrwxr-x 1 hzg hzg 158024 Apr 26 15:45 ffprobe
-rwxrwxr-x 1 hzg hzg 1096360 Apr 26 15:45 ffmpeg_g
-rwxrwxr-x 1 hzg hzg 284832 Apr 26 15:45 ffmpeg
然后在使用的时候,引用头文件和库就好了。
gcc -o 264toyuv test.c -I./ffmpeg/linux-build/include -L./ffmpeg/linux-build/lib -lavformat -lavdevice -lavutil -lavcodec -lswresample -lswscale
export LD_LIBRARY_PATH=/home_0421/hzg/mypath/ffmpeg/linux-build/lib:$LD_LIBRARY_PATH
因为是普通用户权限,自己编译生成的so库,编译器默认不会去生成的路径里去找,这样在运行程序的时候,load报错就在所难免了。如果将这些so库加入到变量LD_LIBRARY_PATH中,这样程序每次运行时都会去这里变量的路径里去找。所以需要将安装的库目录通过export LD_LIBRARY_PATH添加到引用路径里面。
这里想去测试一下psnr,去下载了一个yuv测试码流,然后通过ffmpeg将yuv码流编码生成h264压缩流,然后通过ffmpeg库将其解码成yuv,验证一下ffmpeg编解码的损失(编码图像效果)。解码demo:
#include <stdio.h> /* printf, NULL */
#include <stdlib.h> /* strtod */
#include <errno.h> /* err catch */
#include "libavformat/avformat.h"
#include "libswscale/swscale.h"
#include "libavcodec/avcodec.h"
#include "libavdevice/avdevice.h"
#include "libavutil/avutil.h"
#include "libavutil/frame.h"
int h264_to_yuv420p(char* input_file, char* output_file)
{
if(input_file == NULL || output_file == NULL)
{
return -1;
}
char* in_file = input_file;
char* out_file = output_file;
AVFormatContext *fmt_ctx = NULL;
AVCodecContext *cod_ctx = NULL;
AVCodec *cod = NULL;
struct SwsContext *img_convert_ctx = NULL;
int ret = 0;
AVPacket packet;
//第一步创建输入文件AVFormatContext
fmt_ctx = avformat_alloc_context();
if (fmt_ctx == NULL)
{
ret = -1;
printf("alloc fail");
goto __ERROR;
}
if (avformat_open_input(&fmt_ctx, in_file, NULL, NULL) != 0)
{
ret = -1;
printf("open fail");
goto __ERROR;
}
//第二步 查找文件相关流,并初始化AVFormatContext中的流信息
if (avformat_find_stream_info(fmt_ctx, NULL) < 0)
{
ret = -1;
printf("find stream fail");
goto __ERROR;
}
av_dump_format(fmt_ctx, 0, in_file, 0);
//第三步查找视频流索引和解码器
int stream_index = av_find_best_stream(fmt_ctx, AVMEDIA_TYPE_VIDEO, -1, -1, &cod, -1);
//第四步设置解码器上下文并打开解码器
AVCodecParameters *codecpar = fmt_ctx->streams[stream_index]->codecpar;
if (!cod)
{
ret = -1;
printf("find codec fail");
goto __ERROR;
}
cod_ctx = avcodec_alloc_context3(cod);
avcodec_parameters_to_context(cod_ctx, codecpar);
ret = avcodec_open2(cod_ctx, cod, NULL);
if (ret < 0)
{
printf("can't open codec");
goto __ERROR;
}
//第五步打开输出文件
FILE *out_fb = NULL;
out_fb = fopen(out_file, "wb");
if (!out_fb)
{
printf("can't open file");
goto __ERROR;
}
//创建packet,用于存储解码前的数据
av_init_packet(&packet);
//第六步创建Frame,用于存储解码后的数据
AVFrame *frame = av_frame_alloc();
frame->width = codecpar->width;
frame->height = codecpar->height;
frame->format = codecpar->format;
av_frame_get_buffer(frame, 32);
AVFrame *yuv_frame = av_frame_alloc();
yuv_frame->width = codecpar->width;
yuv_frame->height = codecpar->height;
yuv_frame->format = AV_PIX_FMT_YUV420P;
av_frame_get_buffer(yuv_frame, 32);
// size_t writesize = av_image_get_buffer_size(frame->format, frame->width,frame->height, 32);
//第七步重采样初始化与设置参数
// uint8_t **data = (uint8_t **)av_calloc((size_t)out_channels, sizeof(*data))
img_convert_ctx = sws_getContext(codecpar->width,
codecpar->height,
codecpar->format,
codecpar->width,
codecpar->height,
AV_PIX_FMT_YUV420P,
SWS_BICUBIC,
NULL, NULL, NULL);
//while循环,每次读取一帧,并转码
//第八步 读取数据并解码,重采样进行保存
int count = 0;
while (av_read_frame(fmt_ctx, &packet) >= 0)
{
if (packet.stream_index != stream_index)
{
av_packet_unref(&packet);
continue;
}
ret = avcodec_send_packet(cod_ctx, &packet);
if (ret < 0)
{
ret = -1;
printf("decode error");
goto __ERROR;
}
while (avcodec_receive_frame(cod_ctx, frame) >= 0)
{
printf("decode frame count = %d\n" , count++);
sws_scale(img_convert_ctx,
(const uint8_t **)frame->data,
frame->linesize,
0,
codecpar->height,
yuv_frame->data,
yuv_frame->linesize);
int y_size = cod_ctx->width * cod_ctx->height;
fwrite(yuv_frame->data[0], 1, y_size, out_fb);
fwrite(yuv_frame->data[1], 1, y_size/4, out_fb);
fwrite(yuv_frame->data[2], 1, y_size/4, out_fb);
}
av_packet_unref(&packet);
}
__ERROR:
if (fmt_ctx)
{
avformat_close_input(&fmt_ctx);
avformat_free_context(fmt_ctx);
}
if (cod_ctx)
{
avcodec_close(cod_ctx);
avcodec_free_context(&cod_ctx);
}
if (out_fb)
{
fclose(out_fb);
}
if (frame)
{
av_frame_free(&frame);
}
if (yuv_frame)
{
av_frame_free(&yuv_frame);
}
if(img_convert_ctx)
{
sws_freeContext(img_convert_ctx);
}
return ret;
}
int main ()
{
h264_to_yuv420p("carphone_qcif.h264","out.yuv");
return 0;
}
psnr测试
./psnr 176 144 420 ../../old/imagedata/carphone_qcif.yuv ../../old/imagedata/carphone_qcif_h264.yuv >carphone_qcif.txt
测试结果
psnr: 380 frames (CPU: 0 s) mean: 10.69 stdv: 0.86
carphone_qcif.txt
10.018
10.017
9.993
10.000
10.010
10.030
10.019
10.010
...
...
...
10.204
10.176
10.153
10.158
10.153
10.165
10.262
10.147
10.138
3.引用
Android.mk
LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
#include Prebuild_Android.mk
LOCAL_SRC_FILES:= \
main.c
# simpl.c \
BUILD_PATH:=$(LOCAL_PATH)/FFmpeg-2.7.2-use-zip/android-21
LOCAL_C_INCLUDES := \
$(LOCAL_PATH)/FFmpeg-2.7.2-use-zip/build/include \
$(LOCAL_PATH)/openh264/include \
LOCAL_CFLAGS :=
LOCAL_CFLAGS += -fPIC -Wformat-security
LOCAL_CFLAGS += $(CFLAGS) -g -O2 -DENABLE_FFMPEG=1
LOCAL_LDFLAGS :=
LOCAL_LDFLAGS += $(BUILD_PATH)/lib/libavformat.a
LOCAL_LDFLAGS += $(BUILD_PATH)/lib/libavfilter.a
LOCAL_LDFLAGS += $(BUILD_PATH)/lib/libpostproc.a
LOCAL_LDFLAGS += $(BUILD_PATH)/lib/libswscale.a
LOCAL_LDFLAGS += $(LOCAL_PATH)/FFmpeg-2.7.2-use-zip/build/lib/libavdevice.a
LOCAL_LDFLAGS += $(BUILD_PATH)/lib/libavcodec.a
LOCAL_LDFLAGS += $(BUILD_PATH)/lib/libavformat.a
LOCAL_LDFLAGS += $(BUILD_PATH)/lib/libavutil.a
LOCAL_LDFLAGS += $(BUILD_PATH)/lib/libswresample.a
LOCAL_LDFLAGS += $(LOCAL_PATH)/openh264/libopenh264.a
#数学库和libz压缩库依赖
#LOCAL_LDFLAGS += -lswresample
LOCAL_LDFLAGS += -lm -lz
LOCAL_STATIC_LIBRARIES :=
LOCAL_SHARED_LIBRARIES :=
LOCAL_MODULE:= test_ffmpeg
include $(BUILD_EXECUTABLE)
include Prebuild_Android.mk
总结
中途遇到的报错记录一下
链接报错
./FFmpeg-2.7.2-use-zip/build/lib/libavformat.a(id3v2.o):id3v2.c:function id3v2_parse: error: undefined reference to 'uncompress'
./FFmpeg-2.7.2-use-zip/build/lib/libavcodec.a(zip_decoder.o):zip_decoder.c:function zip_decompress.isra.3: error: undefined reference to 'inflateInit_'
./FFmpeg-2.7.2-use-zip/build/lib/libavcodec.a(zip_decoder.o):zip_decoder.c:function zip_decompress.isra.3: error: undefined reference to 'inflate'
./FFmpeg-2.7.2-use-zip/build/lib/libavcodec.a(zip_decoder.o):zip_decoder.c:function zip_decompress.isra.3: error: undefined reference to 'inflateEnd'
./FFmpeg-2.7.2-use-zip/build/lib/libavcodec.a(zip_decoder.o):zip_decoder.c:function zip_decompress.isra.3: error: undefined reference to 'inflateEnd'
./FFmpeg-2.7.2-use-zip/build/lib/libavcodec.a(zip_decoder.o):zip_decoder.c:function zip_decoder_decode_begin: error: undefined reference to 'zlibVersion'
./FFmpeg-2.7.2-use-zip/build/lib/libavcodec.a(zip_decoder.o):zip_decoder.c:function zip_decoder_decode_begin: error: undefined reference to 'zlibVersion'
./FFmpeg-2.7.2-use-zip/build/lib/libavcodec.a(zip_decoder.o):zip_decoder.c:function zip_decoder_decode_begin: error: undefined reference to 'zlibVersion'
./FFmpeg-2.7.2-use-zip/build/lib/libavcodec.a(zip_decoder.o):zip_decoder.c:function zip_decoder_decode_begin: error: undefined reference to 'zlibVersion'
解决办法
It’s because libavcodec includes some math and zlib headers, so you must link to the respective libraries as well
因为使用了math和zlib库,所以编译的时候需要添加相应的库
运行报错
CANNOT LINK EXECUTABLE DEPENDENCIES: library "libavformat.so.56" not found
解决办法
提示找不到libavformat.so.56,这里.56是对应的库版本号,编译的时候,有参照前人的办法,在configure文件中将编译出来的库名字做修改了,但是会出现.a,.so,.so.56,这里我引用动态库都会报错这个,引用静态库就可以了。只是说找到解决办法了,深入原因有大佬清楚可以一起讨论
Demo编译
编译
g++ -o main list_codecinfo.cpp -I /home/hzg/mypath/ffmpeg/Dev/ffmpeg-win64-dev/ffmpeg-20200106-1e3f4b5-win64-dev/include/libavformat -I /home/hzg/mypath/ffmpeg/Dev/ffmpeg-win64-dev/ffmpeg-20200106-1e3f4b5-win64-dev/include -L/home/hzg/mypath/ffmpeg/Dev/ffmpeg-win64-dev/ffmpeg-20200106-1e3f4b5-win64-dev/lib -lavcodec.dll -lavformat.dll
gcc test.c -I ffmpeg/ -Lffmpeg/libavformat -Lffmpeg/libavdevice/ -static -lavformat -lavdevice -o 264toyuv
指令
ffplay https://magiclen.org/ffmpeg-h265/
ffplay -video_size 3840x2160 -i "C:\Users\10257818\Desktop\imagedata\编码视频\kaoya2\ky_683.yuv" 指定分辨率播放YUV
通过FFmpeg输出视觉无损的H.265/HEVC视频的指令如下:
ffmpeg -s 3840x2160 -i C:\Users\10257818\Desktop\imagedata\yuv\ky_685.yuv -vcodec libx265 -crf 18 C:\Users\10257818\Desktop\imagedata\yuv\aaa.h265
ffmpeg -s 3840x2160 -i C:\Users\10257818\Desktop\imagedata\yuv\ky_685.yuv -vcodec libx265 C:\Users\10257818\Desktop\imagedata\yuv\bbb.h265
使用最高的压缩效果来输出视觉无损的H.265/HEVC视频,指令如下:
ffmpeg -i 输入的影音文件路径 -vcodec libx265 -crf 20 -preset placebo 输出的影音文件路径
将H265/H264码流解码成YUV数据
ffmpeg -i C:\Users\10257818\Desktop\imagedata\yuv\bbb.h265 -vcodec libx265 C:\Users\10257818\Desktop\imagedata\yuv\ccc.yuv
ffmpeg -i C:\Users\10257818\Desktop\imagedata\yuv\carphone_qcif.h264 -vcodec libx264 C:\Users\10257818\Desktop\imagedata\yuv\carphone_qcif_h264.yuv
将YUV数据编码成H265/H264码流
ffmpeg -s 3840x2160 -i C:\Users\10257818\Desktop\imagedata\yuv\ky_685.yuv -vcodec libx265 C:\Users\10257818\Desktop\imagedata\yuv\bbb.h265
ffmpeg -s 3840x2160 -i C:\Users\10257818\Desktop\imagedata\yuv\ky_685.yuv -vcodec libx265 -crf 18 C:\Users\10257818\Desktop\imagedata\yuv\aaa.h265
ffmpeg -s 176x144 -i C:\Users\10257818\Desktop\imagedata\yuv\carphone_qcif.yuv -vcodec libx265 -crf 18 C:\Users\10257818\Desktop\imagedata\yuv\carphone_qcif.h265
ffmpeg -s 176x144 -i C:\Users\10257818\Desktop\imagedata\yuv\carphone_qcif.yuv -vcodec libx264 -crf 18 C:\Users\10257818\Desktop\imagedata\yuv\carphone_qcif.h264
无损压缩
ffmpeg -i 输入的影音文件路径 -vcodec libx265 -x265-params lossless=1 -preset placebo 输出的影音文件路径
psnr
./psnr 176 144 420 ../../old/imagedata/carphone_qcif.yuv ../../old/imagedata/carphone_qcif_h264.yuv >carphone_qcif.txt
ffmpeg编码YUV420视频序列
ffmpeg -s 1280x720 -i 720p50_parkrun_ter.yuv -r 50 720p50_parkrun_ter.h264
下面这条命令,实现了从摄像头读取数据并编码为H.264,最后保存成mycamera.mkv。
ffmpeg -f dshow -i video="HD 720P Webcam" -vcodec libx264 mycamera.mkv
使用ffplay可以直接播放摄像头的数据,命令如下
ffplay -f dshow -i video="HD 720P Webcam"
录屏,伴随话筒输入的声音
ffmpeg -f dshow -i video="screen-capture-recorder" -f dshow -i audio="内装麦克风 (Conexant 20672 SmartAudi" -r 5 -vcodec libx264 -preset:v ultrafast -tune:v zerolatency -acodec libmp3lame MyDesktop.mkv
录屏,伴随耳机输入的声音
ffmpeg -f dshow -i video="screen-capture-recorder" -f dshow -i audio="virtual-audio-capturer" -r 5 -vcodec libx264 -preset:v ultrafast -tune:v zerolatency -acodec libmp3lame MyDesktop.mkv
抓屏
ffmpeg -f gdigrab -i desktop out.mpg
从屏幕的(10,20)点处开始,抓取640x480的屏幕,设定帧率为5
ffmpeg -f gdigrab -framerate 5 -offset_x 10 -offset_y 20 -video_size 640x480 -i desktop out.mpg
将两个WAV缝合到一起
ffmpeg -i 1.wav -i 2.wav -i 3.wav ...... -i {n}.wav -filter_complex '[0:0][1:0]......[{n-1}:0]concat=n={n}:v=0:a=1[out]' -map '[out]' final.wav
ffmpeg -i input.avi output.mp4 【视频格式转换/视频容器转换,常用视频格式.avi .mp4 .ts .flv .rmvb .mkv】
ffmpeg -i 晓松奇谈.mp4 -acodec copy -vn output.aac 【提取音频】
ffmpeg -i input.mp4 -vcodec copy -an output.mp4 【提取视频】
ffmpeg -ss 00:00:15 -t 00:00:05 -i input.mp4 -vcodec copy -acodec copy output.mp4 【视频剪切,-ss表示开始切割的时间,-t表示要切多少,从时间为00:00:15开始,截取5秒钟的视频】
ffmpeg -i input.mp4 -b:v 2000k -bufsize 2000k -maxrate 2500k output.mp4 【码率控制,-b:v主要是控制平均码率,配套-bufsize使用,-maxrate,-minrate分别表示最大和最小波动】
ffmpeg -i input.mp4 -vcodec h264 output.mp4 【视频编码格式转换,将MPEG4编码格式的视频转换成H264】
ffmpeg -i input.mp4 -c:v libx265 output.mp4 【视频编码格式转换,ffmpeg编译的时候,添加了外部的x265】
ffmpeg -i input.mp4 –vcodec copy –an –f m4v output.h264 【只提取视频ES数据】
ffmpeg -i 1.ts -vcodec copy -an -f rawvideo es.raw 【只提取视频ES数据,ts流转es流】
ffmpeg -i 1.mp4 -vcodec copy -an -f rawvideo -vbsf h264_mp4toannexb es.raw 【只提取视频ES数据,mp4流转es流】
ffmpeg -i input.mp4 -vf scale=960:540 output.mp4 【过滤器使用,将输入的1920*1082缩放到960*540输出】
./ffmpeg -i input.mp4 -i iQIYI_logo.png -filter_complex overlay output.mp4 【过滤器使用,为视频添加logo,默认左上角】-vf代替的-filer-complex
ffmpeg -i F:\VideoEncDec\ffmpeg\VideoSimple\wuxiannizhuan.mp4 -i C:\Users\10257818\Desktop\ZTE.png -filter_complex
"[1:v][0:v]scale2ref=(W/H)*ih/8/sar:ih/8[wm][base];[base][wm]overlay=10:10"
-pix_fmt yuv420p -c:a copy C:\Users\10257818\Desktop\filterZTEzishiying.mp4
./ffmpeg -i input.mp4 -i logo.png -filter_complex overlay=W-w output.mp4 【过滤器使用,为视频添加logo,右上角】
./ffmpeg -i input.mp4 -i logo.png -filter_complex overlay=0:H-h output.mp4 【过滤器使用,为视频添加logo,左下角】
./ffmpeg -i input.mp4 -i logo.png -filter_complex overlay=W-w:H-h output.mp4 【过滤器使用,为视频添加logo,右下角】
ffmpeg -i input.mp4 -vf delogo=0:0:220:90:100:1 output.mp4 【过滤器使用,去掉视频的logo】
语法:-vf delogo=x:y:w:h[:t[:show]]
x:y 离左上角的坐标
w:h logo的宽和高
t: 矩形边缘的厚度默认值4
show:若设置为1有一个绿色的矩形,默认值0。
ffmpeg -i input.mp4 -r 1 -q:v 2 -f image2 pic-%03d.jpeg 【抓取视频的一些帧,存为jpeg图片】
语法:-r 表示每一秒几帧
-q:v表示存储jpeg的图像质量,一般2是高质量
ffmpeg -i input.mp4 -ss 00:00:20 -t 10 -r 1 -q:v 2 -f image2 pic-%03d.jpeg 【抓取视频的一些帧,存为jpeg图片,设置抓取时间和时间间隔】
语法:-ss 表示开始时间
-t表示共要多少时间
ffmpeg -i input.mp4 output.yuv 【输出YUV420原始数据,可以使用RawPlayer播放】
ffmpeg -i input.mp4 -ss 00:00:20 -t 10 -r 1 -q:v 2 -f image2 pic-%03d.jpeg + ffmpeg -i pic-001.jpeg -s 1440x1440 -pix_fmt yuv420p xxx3.yuv 【抽取某一帧YUV数据,先从视频中抽出jpeg帧图片,然后再将jpeg转换成YUV】
ffmpeg -i input -vf “trim=start_frame=0:end_frame=1” out.yuv 【评论给出的建议】
ffmpeg -i input.mp4 -profile:v baseline -level 3.0 output.mp4 【控制profile&level,以适应于不同的设备,解码能力和文件大小平衡,baseline,main,high,extended】
ffmpeg -i input.mp4 -c:v libx264 -x264-params "profile=high:level=3.0" output.mp4 【控制profile&level,ffmpeg编译时添加了external的libx264】
ffmpeg -i input.mp4 -c:v libx265 -x265-params "profile=high:level=3.0" output.mp4 【H265(HEVC)编码tile&level控制】
ffmpeg -list_devices true -f dshow -i dummy 【列出当前音视频设备】
打开Cmd命令行控制台,进入FFmpeg的Bin目录,输入如下命令:
ffmpeg -list_devices true -f dshow -i dummy
[dshow @ 0000022eb0b2a540] DirectShow video devices (some may be both video and audio devices)
[dshow @ 0000022eb0b2a540] "HD 720P Webcam"
[dshow @ 0000022eb0b2a540] Alternative name "@device_pnp_\\?\usb#vid_0c45&pid_6340&mi_00#6&17bbfbbc&0&0000#{65e8773d-8f56-11d0-a3b9-00a0c9223196}\global"
[dshow @ 0000022eb0b2a540] DirectShow audio devices
[dshow @ 0000022eb0b2a540] "楹﹀厠椋?(2- USB Microphone)"[dshow @ 0000022eb0b2a540] Alternative name "@device_cm_{33D9A762-90C8-11D0-BD43-00A0C911CE86}\wave_{54896F77-1473-4AB0-8A17-109275DBF87B}"
在上面的命令行窗口中列出了两个设备,一个是视频采集设备,另外是一个音频采集设备。另外,我们发现:音频设备的名称有乱码,因为其中有中文名称,后面在讲到用API采集数据的时候会提到解决这个问题的方法。接着我们输入另外一个命令行:
ffmpeg -list_options true -f dshow -i video="HD 720P Webcam"
这个命令行的作用是获取指定视频采集设备支持的分辨率、帧率和像素格式等属性,返回的是一个列表
[dshow @ 0000018e1c16b540] pixel_format=yuyv422 min s=1184x656 fps=10 max s=1184x656 fps=10
[dshow @ 0000018e1c16b540] pixel_format=yuyv422 min s=1184x656 fps=10 max s=1184x656 fps=10
[dshow @ 0000018e1c16b540] vcodec=mjpeg min s=1280x720 fps=15 max s=1280x720 fps=33
[dshow @ 0000018e1c16b540] vcodec=mjpeg min s=1280x720 fps=15 max s=1280x720 fps=33
下面我们执行另外一条命令,将摄像头的图像和麦克风的音频录制保存成一个文件。命令如下:
ffmpeg -f dshow -i video="HD 720P Webcam" -f dshow -i audio="麦克风 (2- USB Microphone)" -vcodec libx264 -acodec aac -strict -2 mycamera.mkv
上面的命令行用video=指定视频设备,用audio=指定音频设备,后面的参数是定义编码器的格式和属性,输出为一个名为mycamera.mkv的文件。命令运行之后,控制台打印FFmpeg的运行日志,按“Q”键则中止命令。这里有些读者可能会问:采集设备不是支持多个分辨率吗?怎么设置采集时用哪一种分辨率输出?答案是用“-s”参数设置,若在上面的命令行加上“-s 720x576”,则FFmpeg就会以720x576的分辨率进行采集,如果不设置,则以默认的分辨率输出。