FFMPEG 编译


前言

最近想深入了解一下FFMPEG开源库的使用,于是着手从头弄一个轮子,然后按照自己的想法去造。


一、FFMPEG是什么

这个就不解释了,很强大的视频编解码库,初学者就了解到这么多了,很多内容我准备一遍探索一遍去完善笔记。
这里提供一些编解码功能去对视频进行操作。

二、怎么使用

1.环境准备

由于编译好的FFMPEG准备在Android终端上使用,所以准备用NDK编译方式去编译,我这用的是linux编译环境,然后运行的Android终端是Android-9。

1.1源码下载

贴一个官网链接:http://www.ffmpeg.org/olddownload.html ,这里可以去找想要的版本
这里可以选择自己想要的版本,需要注意的是不同的版本需要匹配不同的NDK环境,否则编译会报错。4.0以上版本需要NDK17,我这个2.7的版本NDKr11可以编译。

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的分辨率进行采集,如果不设置,则以默认的分辨率输出。

猜你喜欢

转载自blog.csdn.net/qq_38750519/article/details/119940016