第一章 課程導學與準備工作
1-1 課程導學
1-2 音視頻的應用范圍與播放器架構講解
未來+高薪
- 音視頻具有更加廣闊的未來
- 優秀音視頻技術人才奇缺
- 自學成本高
課程安排
-
FFmpeg 常用命令
- 視頻錄制命令
- 多媒體文件的分解、復用命令
- 裁剪與合并命令
- 圖片、視頻互轉命令
- 直播相關命令
- 各種濾鏡命令
-
FFmpeg基本開發
- C語言回顧
- FFmpeg核心概念與常用結構體
- 實戰-多媒體文件的分解與復用
- 實戰-多媒體格式的互轉
- 實戰-從MP4剪一段視頻
- 作業-實現一個簡單的小咖秀
-
音視頻編解碼實戰
- 實戰-H264解碼
- 實戰-H264編碼
- 實戰-音頻AAC解碼
- 實戰-音頻AAC編碼
- 實戰-視頻轉圖片
-
音視頻渲染實戰
- SDL事件處理
- SDL視頻紋理渲染
- SDL音頻渲染
- 實戰1-實現YUV視頻播放器
- 實戰2-YUV視頻倍速播放
- 實戰3-實現PCM播放器
-
FFmpeg開發播放器核心功能
- 實戰-實現MP4文件的視頻播放
- 實戰-實現MP4文件的音頻播放
- 實戰-實現一個初級播放器
- 實戰-音視頻同步
- 實戰-實現播放器內核
-
Android Q中實戰FFmpeg
- 編譯Android端可以使用的FFmpeg
- Java與C語言相互調用
- 實戰-Android調用FFmpeg
適合人群
- 從事音視頻相關工作,想提高技能的人
- 想轉行到音視頻行業的人
- 剛剛畢業或即將畢業還沒有確定未來方向的人
學習建議
- 牢牢抓住音視頻的處理機制,了解其本質
- 勤加練習,熟能生巧
- 帶著問題去學習,事半功倍
1-3 音視頻的應用范圍與播放器架構講解
音視頻的廣泛應用
- 直播類:音視頻會議、教育直播、娛樂/游戲直播等
- 短視頻類:抖音、快手、小咖秀等
- 網絡視頻:優酷、騰訊視頻、愛奇藝等
- 視頻通話:微信、QQ、Skype等
- 視頻監控
- 人工智能:人臉識別,智能音箱等,更關注算法
播放器架構
渲染流程
1-4 什么是FFmpeg,它能做什么?
FFmpeg從何而來?
- 2000年,由法布里斯·貝拉(FabriceBellard)創建
- 2004年,邁克爾(Michael Niedermayer)接管
- 2011年,Libav從FFmpeg分離
法布里斯·貝拉
- 高中就讀期間開發了著名的可執行壓縮程序LzEXE
- 2000年創建了FFmpeg項目
- 2011年,他用JavaScript寫了一個Linux虛擬機(JSLinux)
- 他還是QEMU,TinyCC的作者
FFmpeg都能做啥?
- FFmpeg是一個非常優秀的多媒體框架
- FFmpeg可以運行在Linux,Mac,Windows等品臺上
- 能夠解碼,編碼,轉碼,復用,解復用,過濾音視頻數據
恥辱柱
- 偷用了FFmpeg開源代碼卻違背FFmpeg遵守的開源協議
- GPL的核心思想是基于GPL協議的代碼都必須開源
- QQ影音、暴風影音、格式工廠等都被釘在了恥辱柱上。
1-5 FFmpeg下載編譯與安裝
FFmpeg下載編譯與安裝
- git clone https://git.ffmpeg.org/ffmpeg.git
- config --help
./configure --prefix=/usr/local/ffmpeg --enable-gpl --enable-nonfree --enable-libfdk-aac --enable-libx264 --enable-libx265 --enable-filter=delogo --enable-debug --disable-optimizations --enable-libspeex --enable-videotoolbox --enable-shared --enable-pthreads --enable-version3 --enable-hardcoded-tables --cc=clang --host-cflags= --host-ldflags=
- make && make install
遇到報錯: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
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命令分類
- 基本信息查詢命令
- 錄制命令
- 分解、復用命令
- 處理原始數據命令
- 裁剪與合并命令
- 圖片、視頻互轉命令
- 直播相關命令
- 各種濾鏡命令
2-2 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 -f avfoundation -i 1 -r 30 out.yuv
-f:指定使用 AVfoundation 采集數據
-i:輸入,指定從哪兒采集數據,1是一個文件索引號
-r:指定幀率
實戰:
./ffmpeg -f gdigrab -i desktop -r 30 out.yuv
windows下錄制屏幕
./ffplay -s 3840x1080 -pix_fmt bgra ./out.yuv
播放錄制的文件
-s 輸入播放尺寸
-pix_fmt 像素格式,錄制的時候有顯示查詢可用設備:
ffmpeg -f avfoundation -list_devices true -i ''
試了沒用
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復制
抽取視頻數據:
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 直播相關的命令實戰
直播推/拉流
直播推流
ffmpeg -re -i input.mp4 -c copy -f flv rtmp://server/live/streamName
-re
降低幀率
-c
對音視頻進行編解碼(-a 音頻 -v 視頻)
-f
推出的文件格式直播拉流
ffmpeg -i rtmp://server/live/streamName -c copy dump.flv
rtmp、rtsp、http視頻協議直播流地址
https://blog.csdn.net/github_30662571/article/details/72466091
第三章 基礎開發
3-1 FFmpeg 基礎開發概述
基礎開發內容
- Vim編輯器
- C語言回顧,重點介紹指針概念
- Linux/Mac C語言的編譯與調試
- Linux/Mac 常用開發工具介紹
3-2 Vim 模式及創建文件
Vim 處理模式
-
命令模式
拷貝、刪除、粘貼等,通過i/a等鍵切換到編輯模式 -
編輯模式
編輯字符,通過Esc鍵進行切換
Vim 常用命令
- 創建文件: vim filename
- 保存文件: :w
- 關閉文件: :q
Vim 拷貝、粘貼與刪除
- 拷貝 yy/yw 拷貝一行或一個詞
- 粘貼 p
- 刪除 dd/dw
Vim 光標移動
- 左下上右 h/j/k/l
- 調到文件頭 gg
- 跳到文件尾 G
Vim 行內光標移動
- 移動到行首 ^
- 移動到行尾 $
- 按單詞移動 向前w/ 2w/,向后 b/ 2b
Vim 查找與替換
- 查找關鍵字
/關鍵字
- 查找與替換:
:%s/關鍵字/替換字/gc
% 表示查找文檔內所有的行,如果需要查找某個范圍內的則用:行號,行號
表示
s 代表Search
g 查找所有
c 每次替換需要確認
Vim 多窗口
- 分窗口: :split/vsplit
- 窗口之間的跳轉: Ctrl + ww/w[hjkl]
- 關閉窗口:
:close
- 最大化窗口:Ctrl + w + |
- 上下屏窗口調整: Ctrl + w + _
- 窗口平均分配:Ctrl + w + =
第四章 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可執行程序
常用基本類型
- short、int、long(字節:2,4,4)
- float、double(32bit,32bit,前者精度低,后者精度高)
- char(單個字符)
- void 無符號型
4-2 C語言中的常量與變量
變量與常量
- int a=0; // 變量,可以再賦值
- const int len= 256; // 常量定義
內存管理
實踐
#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語言中的指針
指針與數組
- 指針就是內存地址: void、char
- 數組(連續的同一類型的空間),如: char c[2]、int arr[10]
指針
數組
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語言中的文件操作
文件操作
- 文件類型 FILE* file;
- 打開文件 FILE* fopen(path, mode);
- 關閉文件 fclose(FILE*);
#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語言指針
指針的物理意義
- 它就是內存中的一個地址
- 指針本身運算
- 指針所指向內容的操作
操作系統是如何管理內存的?
- 棧空間,局部變量,如函數內
- 堆空間,存放程序
- 內存映射,數據庫廣泛應用
內存的分配與釋放
- 分配內存 void* mem = malloc(size);
- 釋放內存 free( mem );
內存泄露與野指針
- 不斷的向系統申請內存
- 申請的內存不用,也不釋放
- 釋放看還使用該指針,占用別人的內存稱為野指針
函數指針
- 返回值類型 (*指針變量名)([形參列表]);
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
-
gcc/clang -g -O 2 -o test test.c -I... -L... -l
-g 輸出文件中的調試信息
-O 對輸出文件做指令優化設置優化級別,默認為1;程序發行時使用
-o 輸出的可執行文件名
-I (大寫的i)指定頭文件(位置)
-L 指定庫文件位置
-l (小寫的L)指定使用哪個庫
編譯過程
- 預編譯,拷貝頭文件
- 編譯
- 鏈接,動態鏈接、靜態鏈接
// 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 日志的使用及目錄操作
- 介紹FFmpeg 的基本概念及常用結構體
- 對復用/解復用及流操作的各種實戰
FFmpeg代碼結構
模塊 | 介紹 |
---|---|
libavcodec | 提供了一系列編碼器的實現 |
libavformat | 實現在流協議,容器格式及其本IO訪問 |
libavutil | 包括了hash器,解碼器和各種工具函數 |
libavfilter | 提供了各種音視頻過濾器 |
libavdevice | 提供了訪問捕獲設備和回放設備的接口 |
libswresample | 實現了混音和重采樣 |
libswscale | 實現了色彩轉換和縮放功能 |
5-2 FFmpeg 日志系統
- include <libavutil/log.h> 第一步,引入頭文件
- av_log_set_level(AV_LOG_DEBUG) 第二步,設置日志級別
- av_log(NULL, AV_LOG_INFO, " ...%s\n", op) 第三步,打印日志,第二個參數,日志級別,第三個參數日志模板字符串,
常用日志級別
- AV_LOG_ERROR
- AV_LOG_WARNING
- AV_LOG_INFO
- AV_LOG_DEBUG
實戰:
#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文件與目錄操作
文件的刪除與重命名
- avpriv_io_delete()
- avpriv_io_move()
#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的實現
操作目錄的重要函數
- avio_open_dir(context, path, )
- avio_read_dir()
- avio_close_dir()
操作目錄重要結構體
- AVIODirContext
操作目錄的上下文 - AVIODirEntry
目錄項。用于存放文件名、文件大小等信息
【實戰】簡單的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 處理流數據的基本概念
多媒體文件的基本概念
- 多媒體文件其實是個容器
- 在容器里有很多流(Stream/Track)
- 每種流是由不同的編碼器編碼的
- 從流中讀出的數據稱為包
- 在一個包中包含著一個或多個幀
幾個重要的結構體
- AVFormatContext
- AVStream
- AVPacket
ffmpeg 操作流數據的基本步驟
解復用 --> 獲取流 --> 讀取數據包 --> 釋放資源
5-7 ffmpeg 打印音視頻Meta信息
【實戰】打印音/視頻信息
- av_register_all()
- avformat_open_input()/avformat_close_input()
- av_dump_format()
#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抽取音頻數據
【實戰】抽取音頻數據
- av_init_packet()
- av_find_best_stream()
- av_read_frame() / av_packet_unref()
#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數據
- Start code
- SPS、PPS
- codec -> extradata
5-14~5-15 FFmpeg將MP4轉成flv
【實戰】將MP4轉成flv
- avformat_alloc_output_context2()/
avformat_free_context() - avformat_new_stream()
- avcodec_parameters_copy()
- avformat_write_header()
- av_write_frame()
av_interleaved_write_frame() - av_write_trailer()