FFmpeg音视频核心技术精讲与实战

2020-08-12  本文已影响0人  且须文雅

常见问题

第一章 课程导学与准备工作

1-1 课程导学

1-2 音视频的应用范围与播放器架构讲解

未来+高薪

课程安排

适合人群

学习建议

1-3 音视频的应用范围与播放器架构讲解

音视频的广泛应用

播放器架构

播放器架构

渲染流程

2019_8_16_15_40_52.png

1-4 什么是FFmpeg,它能做什么?

FFmpeg从何而来?

法布里斯·贝拉

FFmpeg都能做啥?

耻辱柱

1-5 FFmpeg下载编译与安装

FFmpeg下载编译与安装

遇到报错:ERROR: videotoolbox requested, but not all dependencies are satisfied: corefoundation coremedia corevideo
解决方法:安装NVIDIA headers

git clone https://git.videolan.org/git/ffmpeg/nv-codec-headers.git
make
sudo make install

遇到报错:
说某个静态库未找到,但你确实可以找到。
解决方法:
/etc/ld.so.conf文件中加入两行:

/usr/local/ffmpeg/lib
/usr/local/lib

这样操作后就正常了

安装过程中还安装了:
fdk-aac
speex
nasm
x264
cmake

tar -xzf  [cmake-3.7.0-rc1.tar.gz](https://cmake.org/files/v3.7/cmake-3.7.0-rc1.tar.gz)
make && make install

x265

tar -xzf x265_2.1.tar.gz

$ cd x265/build/linux
$ ./make-Makefiles.bash
$ make && make install

注:安装中,有些事mac系统特有的库,可不用装或者用替代品

1-6 Windows下安装FFmpeg

https://www.imooc.com/article/247113

1-7 FFmpeg 命令大全文档

第二章 FFmpeg常用命令实战

2-1 FFmpeg常用命令

FFmpeg命令分类

  1. 基本信息查询命令
  2. 录制命令
  3. 分解、复用命令
  4. 处理原始数据命令
  5. 裁剪与合并命令
  6. 图片、视频互转命令
  7. 直播相关命令
  8. 各种滤镜命令

2-2 FFmpeg处理流程

FFmpeg处理音视频流程

FFmpeg处理音视频流程

2-3 FFmpeg基本信息查询命令实战

FFmpeg基本信息查询命令

-version 显示版本

分解与复用命令
-demuxers 显示可用的demuxers
-muxers 显示可用的muxers

查询设备
-devices 显示可用设备

编解码相关
-codecs 显示所有编解码器
-decoders 显示所有的解码器
-encoders 显示所有的编码器

比特流处理
-bsfs 显示比特流filter

格式信息
-formats 显示可用的格式

网络协议
-protocols 显示可用的协议

滤镜
-filters 显示可用的过滤器

像素格式
-pix_fmts 显示可用的像素格式

其他
-sample_fmts 显示可用的采样格式
-layouts 显示channel名称
-colors 显示识别的颜色名称

2-4 FFmpeg录制命令实战

FFmpeg录屏命令

FFmpeg录音命令

ffmpeg -f avfoundation -i :0 out.wav
:0 代表录音设备

课后答疑任务:同时录制视频与音频

2-5 FFmpeg分解与复用命令实战

分解与复用

分解与复用

多媒体格式转换

ffmpeg -i out.mp4 -vcodec copy -acodec copy out.flv
-i:输入文件
-vcodec:设置视频编码处理方式为copy复制
-acodec:设置音频编码处理方式为copy复制

image.png

抽取视频数据:
ffmpeg -i f35.mov -an -vcodec copy out.h264
抽取音频:
ffmpeg -i f35.mov -acodec copy -vn out.aac

2-6 ffmpeg 处理原始数据命令实战

提取YUV数据

ffmpeg -i input.mp4 -an -c:v rawvideo -pix_fmts yuv420p out.yuv
-an: 不提取音频
-c:v: 对视频进行编码,使用rawvideo(原始视频)格式进行编码
-pix_fmt yuv420p: 输出的YUV像素格式

FFmpeg提取PCM数据

ffmpeg -i out.mp4 -vn -ar 44100 -ac 2 -f s16le out.pcm
-ar: audiu rate音频采样率
-ac: audiu channel 音频声道数为2
-f:音频的数据存储格式s16le: s:有符号16位lettle end

2-7 ffmpeg滤镜命令实战

回顾FFmpeg处理音视频流程

ffmpeg滤镜

处理流程

ffmpeg滤镜命令

ffmpeg -i in.mov -vf crop=in_w-200:in_h-200 -c:v libx264 -c:a copy out.mp4
-vf 视频滤镜(video filter)
crop 滤镜名,格式:out_w:out_h:x:y(xy代表剪切的起始位置,默认为视频中心点)
in_w 视频本身宽度
in_h 视频本身高度
-c:v 指定视频解码器为libx264(codec video)
-c:a 指定音频处理方式为copy(codec audio)

2-8 FFmpeg音视频裁剪与合并命令实战

音视频裁剪

ffmpeg -i in.mp4 -ss 00:00:00 -t 10 out.ts
-ss 视频裁剪的起始时间,格式时:分:秒
-t 裁剪的时长s

音视频合并

ffmpeg -f concat -i inputs.txt out.flv
inputs.txt 需要合并的文件列表
格式: file '文件名'
out.flv: 输出的文件名

2-9 ffmpeg 图片与视频互转实战

FFmpeg视频转图片

ffmpeg -i input.flv -r 1 -f image2 image-%3d.jpeg
-r 指定转换图片的帧率
-f 指定输入文件转成的格式
ffmpeg -f image2 -r 1 -i bmp%d.jpeg -loop 1 -pix_fmt yuv420p -video_size 1280x720 -r 10 -c:v libx264 out.mp4

FFmpeg 图片转视频

ffmpeg -i image-%3d.jpeg output.mp4

2-10 ffmpeg 直播相关的命令实战

直播推/拉流

rtmp、rtsp、http视频协议直播流地址
https://blog.csdn.net/github_30662571/article/details/72466091

第三章 基础开发

3-1 FFmpeg 基础开发概述

基础开发内容

3-2 Vim 模式及创建文件

Vim 处理模式

Vim 常用命令

Vim 拷贝、粘贴与删除

Vim 光标移动

Vim 行内光标移动

Vim 查找与替换

Vim 多窗口

第四章 C语言基础

4-1 Hello World

#include <stdio.h>
int main(int argc, char* argv[])
{
    printf("Hello World!\n");
    return 0;
}

编译代码,gcc -g -o helloworld helloworld.c
将helloworld.c编译为helloworld可执行程序

常用基本类型

4-2 C语言中的常量与变量

变量与常量

内存管理

内存管理

实践

#include <stdio.h>
int main (int argc, char* argv[]) {
  int a = 0;
  const int b = 10;
  printf("a=%d\n", a);
  printf("b=%d\n", b);

  a = 10;

  printf("a=%d\n", a);

  return 0;
}

4-3 C语言中的指针

指针与数组

指针

指针

数组

数组

4-4 C语言中的指针-2(实践)

#include<stdio.h>
#include<stdlib.h>
int main(int argc, char *argv[])
{
    int *a, *b;
    printf("addr of a:%p\n", &a);
    printf("addr of b:%p"\n, &b);
    return 0;
}
运行结果
#include <stdio.h>
#include <stdlib.h>

int main (int argc, char *argv[]) {
  int *a, *b;
  a = (int*)malloc(sizeof(int));
  b = (int*)malloc(sizeof(int));

  *a = 1;
  *b = 2;

  int c[3] = {0, 1, 2};
  printf("addr of a: %p, %p, %d\n", &a, a, *a);
  printf("addr of b: %p, %p, %d\n", &b, b, *b);

  printf("addr of c: %p, %d, %d, %d\n", c, c[0], c[1], c[2]);
  return 0;
}
运行结果

C 库函数 void *malloc(size_t size) 分配所需的内存空间,并返回一个指向它的指针。
sizeof()是获得类型的内存大小,字节为单位

4-5 C语言结构体

结构体

struct st{
    int a; // 成员a
    int b; // 成员b
};

枚举类型

#include <stdio.h>

enum e_type {
  red = 0,
  green,
  blue
};

int main (int argc, char* argv[]) {
  enum e_type et;
  et = red;

  printf("the color is %d\n", et);

  return 0;
}

4-6 C语言中的if_else

算术运算与比较运算

if/else 语句

if (a>b){

} else {

}

4-7 C语言中的for_while

for语句

for(int i = 0; i<100;i++){
  
}

while 语句

while(1){

}

4-8 C语言中的函数

函数

void func (int a) {

}

实操:

#include <stdio.h>

int sum (int a, int b) {
 return (a + b);
}

void printInfo () {
  printf("help: this is program of calc a+b \n\n");
}

int main (int argc, char* argv[]) {
  printInfo();

  int result;
  result = sum(3, 5);

  printf("3 + 5 = %d\n", result);
  return 0;
}

4-9 C语言中的文件操作

文件操作

#include<stdio.h>
int main(int argc, char* argv[])
{
    FILE* file;
    char buf[1024] = {0,};
    file = fopen("1.txt", "a+"); // 追加文件; 没有则创建
    fwrite("hello, world!", 1, 13, file); // 写入的内容;每个元素的大小;写入多少个元素
    rewind(file);//将游标放到文件的开头
    fread(buf, 1, 10, file);
    fclose(file);
    printf("buf: %s \n", buf);
    return 0;
}

4-10 再论C语言指针

指针的物理意义

操作系统是如何管理内存的?

内存的分配与释放

内存泄露与野指针

函数指针

int func(int x); /* 声明一个函数 */
int (*f)(int x); /* 声明一个函数指针 */
f = func; /* 将func 函数的首地址赋给指针f */

实践:

#include <stdio.h>

int sum (int a, int b) {
 return (a + b);
}

void printInfo () {
  printf("help: this is program of calc a+b \n\n");
}

int main (int argc, char* argv[]) {
  printInfo();

  int result;
  int (*f)(int, int);

  f = sum;
  result = f(3, 5);

  printf("3 + 5 = %d\n", result);
  return 0;
}

4-11 C语言编译器

GCC/CLANG

编译过程

// add.c
int add (int a, int b) {
  return (a + b);
}

gcc -g -c add.c // 编译库文件
// 生成库文件
libtool -static -o libmylib.a add.o // 命令无效
ar rcs libtestlib.a testlib.o // 在Linux下的命令

// add.h
int add(int a, int b);
// testLib.c
#include <stdio.h>

#include "add.h"

int main(int argc, char* argv[]) {
  printf("add=$d\n", add(3, 3));
  return 0;
}

gcc -g -o testLib add.c -I . -L . -l mylib
方法二:先编译再链接
gcc -g -c testLib.c
gcc -o testLib testLib.o -L . -l mylib

待学习解决
在Linux下生成静态库用ar命令,动态库用gcc;
在Mac下用libtool

4-12 C语言调试器

调试器原理

Gdb/lldb

命令 gdb(Linux) lldb(mac)
设置断点 b b
运行程序 r r
单步执行 n n
跳入函数 s s
跳出函数 finish finish
打印内容 p p
continue c c
退出 q -
gdb testLib
b main
info breakpoints // lldb: break list
实操截图

第五章 ffmpeg 多媒体文件处理

5-1 FFmpeg 初级开发介绍

初级开发内容

FFmpeg代码结构

模块 介绍
libavcodec 提供了一系列编码器的实现
libavformat 实现在流协议,容器格式及其本IO访问
libavutil 包括了hash器,解码器和各种工具函数
libavfilter 提供了各种音视频过滤器
libavdevice 提供了访问捕获设备和回放设备的接口
libswresample 实现了混音和重采样
libswscale 实现了色彩转换和缩放功能

5-2 FFmpeg 日志系统

常用日志级别

#include <stdio.h>

#include <libavutil/log.h>

int main(int argc, char* argv[]) {
  av_log_set_level(AV_LOG_DEBUG);
  av_log(NULL, AV_LOG_DEBUG, "Hello world!%d\n", 2020);

  return 0;
}

gcc -g -o ff_log ff_log.c -I /usr/local/ffmpeg/include -L /usr/local/ffmpeg/lib -l avutil
或:
gcc -g -o ff_log ff_log.c `pkg-config --cflags --libs// 需要事先配置环境变量
--cflags: 获取你所要指定库的地址目录
--libs:指定库的名字

5-3 FFmpeg文件的删除与重命名

FFmpeg文件与目录操作

文件的删除与重命名

#include <libavutil/log.h>
#include <libavformat/avformat.h>

int main(int argc, char* argv[]) {
  int res;
  char* fileName = "./mytestfile.txt";

  res = avpriv_io_move("test1.txt", "test2.txt");
  if (res < 0) {
    av_log(NULL, AV_LOG_ERROR, "Failed to rename\n");
    return -1;
  }
  av_log(NULL, AV_LOG_INFO, "Success to rename\n");
  // url
  res = avpriv_io_delete(fileName);
  if (res < 0) {
    av_log(NULL, AV_LOG_ERROR, "Failed to delete file %s\n", fileName);
    return -1;
  }
  av_log(NULL, AV_LOG_INFO, "Success to delete %s\n", fileName);
  return 0;
}

gcc -g -o ff_file ff_file.c -I /usr/local/ffmpeg/include -L /usr/local/ffmpeg/lib -l avutil -l avformat

5-4~5-5 FFmpeg操作目录及list的实现

操作目录的重要函数

操作目录重要结构体

【实战】简单的ls命令

#include <libavutil/log.h>
#include <libavformat/avformat.h>

int main (int argc, char* argv[]) {
  int res;

  AVIODirContext *ctx = NULL;
  AVIODirEntry *entry = NULL;
  av_log_set_level(AV_LOG_INFO);

  res = avio_open_dir(&ctx, "./", NULL);
  if (res < 0) {
    av_log(NULL, AV_LOG_ERROR, "Can't open dir:%s\n", av_err2str(res));
    goto __fail;
  }

  while (1) {
    res = avio_read_dir(ctx, &entry);
    if (res < 0) {
      av_log(NULL, AV_LOG_ERROR, "Can't read dir: %s\n", av_err2str(res));
      goto __fail;
    }
    if (!entry) {
      break;
    }

    av_log(NULL, AV_LOG_INFO, "%12"PRId64" %s \n", entry -> size, entry -> name);
    avio_free_directory_entry(&entry);
  }
__fail:
  avio_close_dir(&ctx);

  return 0;
}
gcc -g -o ff_dir_list ff_file_list.c -I /usr/local/ffmpeg/include -L /usr/local/ffmpeg/lib -l avutil -l avformat
./ff_dir_list
运行结果

注: PRld:是一种跨平台的书写方式,主要是为了通知支持32位和64位操作系统。PRld64表示64位整数,在32位系统中表示long long int,在64位系统中表示long int。相当于:
printf("%" "ld" "\n", value); // 64 bit OS
printf("%" "lld" "\n", value); // 64 bit OS

5-6 ffmpeg 处理流数据的基本概念

多媒体文件的基本概念

几个重要的结构体

ffmpeg 操作流数据的基本步骤

解复用 --> 获取流 --> 读取数据包 --> 释放资源

5-7 ffmpeg 打印音视频Meta信息

【实战】打印音/视频信息

#include <libavutil/log.h>
#include <libavformat/avformat.h>

int main (int argc, char* argv[]) {
  av_log_set_level(AV_LOG_INFO);

  av_register_all();

  int res;
  AVFormatContext *fmt_ctx = NULL;
  res = avformat_open_input(&fmt_ctx, "./test.mp4", NULL, NULL);
  if (res < 0) {
    av_log(NULL, AV_LOG_ERROR, "Can't open file: %s\n", av_err2str(res));
    return -1;
  }
  av_dump_format(fmt_ctx, 0, "./test.mp4", 0);
  avformat_close_input(&fmt_ctx);

  return 0;
}

结果:

Input #0, mov,mp4,m4a,3gp,3g2,mj2, from './test.mp4':
  Metadata:
    major_brand     : isom
    minor_version   : 512
    compatible_brands: isomiso2avc1mp41
    encoder         : Lavf58.9.100
  Duration: 00:05:26.13, bitrate: N/A
    Stream #0:0(und): Video: h264 (avc1 / 0x31637661), none, 1920x1080, 48 kb/s, 14.90 fps, 15360 tbn (default)
    Metadata:
      handler_name    : VideoHandler
    Stream #0:1(und): Audio: aac (mp4a / 0x6134706D), 44100 Hz, 2 channels, 128 kb/s (default)
    Metadata:
      handler_name    : SoundHandler

5-8 FFmpeg抽取音频数据

【实战】抽取音频数据

#include <stdio.h>
#include <libavutil/log.h>
#include <libavformat/avformat.h>

int main (int argc, char* argv[]) {
  av_log_set_level(AV_LOG_INFO);

  av_register_all();
  AVPacket pkt;
  int audio_index;

  // 1. read two params from console
  char* src = NULL;
  char* dst = NULL;
  if (argc < 3) {
    av_log(NULL, AV_LOG_ERROR, "the count of params should be more than 3!\n");
    return -1;
  }
  src = argv[1];
  dst = argv[2];
  if (!src || !dst) {
    av_log(NULL, AV_LOG_ERROR, "src or dst is null!\n");
    return 1;
  }
  int res;
  AVFormatContext *fmt_ctx = NULL;
  res = avformat_open_input(&fmt_ctx, src, NULL, NULL);
  if (res < 0) {
    av_log(NULL, AV_LOG_ERROR, "Can't open file: %s\n", av_err2str(res));
    avformat_close_input(&fmt_ctx);
    return -1;
  }

  FILE* dst_fd = fopen(dst, "wb");
  if (!dst_fd) {
    av_log(NULL, AV_LOG_ERROR, "Can't open out file!\n");
    return -1;
  }
  av_dump_format(fmt_ctx, 0, src, 0);
  // 2. get stream
  res = av_find_best_stream(fmt_ctx, AVMEDIA_TYPE_AUDIO, -1, -1, NULL, 0);
  if (res < 0) {
    av_log(NULL, AV_LOG_ERROR, "Can't find the best stream!\n");
    avformat_close_input(&fmt_ctx);
    fclose(dst_fd);
    return -1;
  }
  audio_index = res;
  av_init_packet(&pkt);
  while(av_read_frame(fmt_ctx, &pkt) >= 0) {
    if (pkt.stream_index == audio_index) {
      int len = fwrite(pkt.data, 1, pkt.size, dst_fd);
      if (len != pkt.size){
        av_log(NULL, AV_LOG_WARNING, "warning, length of data is not equal size of pkt!\n");
      }
    }

    av_packet_unref(&pkt);
  }
  // 3. write audio data to aac file

  avformat_close_input(&fmt_ctx);
  if (dst_fd) {
    fclose(dst_fd);
  }

  return 0;
}

gcc -g -o ExtraAudio extraAudio.c -I /usr/local/ffmpeg/include -L /usr/local/ffmpeg/lib -l avutil -l avformat -l avcodec

注:抽取出来的aac文件需要加adts头才能正常播放

5-11~5-13 FFmpeg抽取视频H264数据

5-14~5-15 FFmpeg将MP4转成flv

【实战】将MP4转成flv

上一篇 下一篇

猜你喜欢

热点阅读