vault backup: 2023-12-20 10:04:53

This commit is contained in:
2023-12-20 10:04:54 +08:00
parent c55ce0ddc4
commit ae5ca1eac8
3 changed files with 215 additions and 14 deletions

View File

@@ -41,7 +41,7 @@
"state": {
"type": "markdown",
"state": {
"file": "01. 個人/00. Informations/Datas.md",
"file": "04. Programming/FFMPEG/Structure.md",
"mode": "source",
"source": true
}
@@ -77,7 +77,7 @@
"state": {
"type": "search",
"state": {
"query": "numpy",
"query": "ffmpeg",
"matchingCase": false,
"explainSearch": false,
"collapseAll": false,
@@ -114,7 +114,7 @@
"state": {
"type": "backlink",
"state": {
"file": "01. 個人/00. Informations/Datas.md",
"file": "04. Programming/FFMPEG/Structure.md",
"collapseAll": false,
"extraContext": false,
"sortOrder": "alphabetical",
@@ -139,7 +139,7 @@
"state": {
"type": "outline",
"state": {
"file": "01. 個人/00. Informations/Datas.md"
"file": "04. Programming/FFMPEG/Structure.md"
}
}
},
@@ -167,7 +167,7 @@
"state": {
"type": "file-properties",
"state": {
"file": "01. 個人/00. Informations/Datas.md"
"file": "04. Programming/FFMPEG/Structure.md"
}
}
}
@@ -212,6 +212,15 @@
},
"active": "d5379d7d99bdf586",
"lastOpenFiles": [
"attachments/Pasted image 20231220095827.png",
"04. Programming/FFMPEG/FFMpeg.md",
"04. Programming/FFMPEG/Structure.md",
"04. Programming/FFMPEG/01. Setup.md",
"04. Programming/FFMPEG/00. Introduction.md",
"05. 資料收集/Tool Setup/Software/Windows 11 Setup.md",
"05. 資料收集/Tool Setup/Software/Windows 10 Setup.md",
"04. Programming/OpenCV.md",
"01. 個人/00. Informations/Datas.md",
"01. 個人/01. Daily/2023-12-18(週一).md",
"00. Inbox/01. TODO.md",
"00. Inbox/numpy axis 運算.md",
@@ -232,18 +241,9 @@
"00. Inbox/White noise.md",
"06. Archives歸檔/想要的鏡頭/變焦/Fujifilm XF 16-80mm F4 R OIS WR.md",
"06. Archives歸檔/想要的鏡頭/定焦/Fujifilm XF18mm F1.4 R LM WR.md",
"README.md",
"未命名 1.canvas",
"未命名.canvas",
"01. 個人/01. Daily/2023-12-08(週五).md",
"04. Programming/Machine Learning.md",
"01. 個人/01. Daily/2023-12-05(週二).md",
"01. 個人/01. Daily/2023-12-01(週五).md",
"01. 個人/01. Daily/2023/11/2023-11-01(週三).md",
"01. 個人/01. Daily/2023/11",
"01. 個人/01. Daily/2023/未命名.md",
"01. 個人/01. Daily/2023/11/2023-11-30(週四).md",
"01. 個人/01. Daily/2023/11/2023-11-29(週三).md",
"01. 個人/01. Daily/2023/10",
"00. Inbox/vc-fwUpdate code trace(Meetup).canvas",
"01. 個人/01. Daily/2023/09",

View File

@@ -0,0 +1,201 @@
- [FFmpeg 使用筆記 - 爱吃土豆的男孩 - 博客园](https://www.cnblogs.com/dk666/articles/7327265.html)
## AVInputFormat/AVOutputFormat
multimedia 檔案的 Muxer/Demuxer將多個 stream如 auodi 、video 等以單個媒體承載。媒體可以是檔案、 network session 等等。每一個 `AVFormat` 代表一種格式,像是`.avi``.wmv``.dat` 等等各種格式,使用不同的方式 mux/demux 多個 stream。每一 `AVFormat` 都實作特定的格式,使用時必需選擇和目的格式相符的 AVFormat 實作,才能正確的讀取 stream 的內容。
## AVFormatContext
`AVFormatContext``AVFormat` 的一個 instance ,用以存放 `AVFormat` 的執行狀態。使用 FFmpeg 處理檔案時,必需為 `AVInputFormat`/`AVOutputFormat` 建立一個 `AVFormatContext` 。同一個 format 可以建立多個 `AVFormatContext` ,各立獨立,不相互干擾,以同時處理多個檔案。
## AVStream
`AVStream` 用以對應到 `AVFormatContext` 裡的一個 stream 。因此同一個 `AVFormatContext` 管理了多個 `AVStream` 以對應到存在檔案或透過 network session 傳送的數個 stream。
## AVPacket
在 stream 裡的資料,是以 packet 為單位進行傳送/儲存。因此一般多媒體檔是將檔案當成 network session 一般處理。每一個 `AVPacket` 標注了所屬的 stream ,透過 `AVPacket` 的包裝,多個 stream 可以同時在一個媒介上傳送/儲存。因此,我們可以讀 stream 是由一系列的 packet 所組成。
## AVCodec
一個影音媒體檔裡,可以承載多個 stream。而 stream 內有 packet。 packet 的 payload ,也就是資料,是透過 codec 編碼/壓縮的。因此,必需透過 codec 進行讀取/寫入時的 decode/encode。AVCodec 就是實作 codec 演算法。同樣的codec 的演算法有各式各樣。使用時,必需選正確的 `AVCodec` ,才能正確的 decode/encode。
## AVCodecContext
`AVCodecContext``AVCodec` 的一個 instance ,用以存放 `AVCodec` 的執行狀態。同樣可以建立多個 `AVCodecContext` ,同時處理多個相同格式、不同格式的 stream 。
## AVFrame
`AVFrame` 的頭幾個欄位和 `AVPicture` 相同,也就是 `AVPicture``AVFrame` 的一小部分。
## 寫入多媒體檔
步驟
- Select an `AVFormat`
- allocate a `AVFormatContext`
- initialize `AVFormatContext` with selected `AVFormat`
- create and initialize an `AVStream` with SVGFormatContext and codec_id specified by `AVFormat`
- AVStream::codec is `AVCodecContext`
- initialize `AVCodecContext` with the `AVCodec` specified by codec_id
- `avcodec_open()`
- initialize output stream of `AVFormatContext`
- `av_write_header()`
- write frames
- create an `AVFrame`
- initialize an `AVPacket` with `AVFrame`
- `av_write_frame()`
- close streams
- `av_write_trailer()`
- free streams
- close output stream
- free `AVFromatContext`
## 讀取多媒體檔
產生檔案時,目的格式是由我們所選擇,因此問題往往較單純一點。但讀取檔案時,我們不確定檔案的格式,必需進行格式判斷後,才確定使用哪一個 AVInputFormat 。
- `av_open_input_file()`
- Read probe buffer
- `get_buffer()`
- `av_probe_input_format()` or `av_probe_input_format2()`
- return `AVFormat`
- Allocate `AVFormatContext`
- `av_open_input_stream()`
- av_find_stream_info
- setup codec for streams
- `avcodec_find_decoder()`
- `avcodec_open()`
- 讀取 frames
- `av_read_frame()`
- prepare an `AVFrame`
- `avcodec_get_frame_defaults()`
- decode the frame in pkt to `AVFrame`
- `avcodec_decode_video()`
- got_picture is true if a picture being returned by the AVFrame.
- close codec
## 範例:影片讀取
```cpp
#include <stdio.h>;
#include <string.h>
#include <libavformat/avformat.h>
#include <libavcodec/avcodec.h>
int main(int argc, const char *argv[]) {
const char *fname;
AVFormatContext *ic;
AVStream *is, *tis;
AVCodec *codec;
AVFormatParameters params, *ap = &params;
AVPacket pkt;
AVFrame frame;
AVPicture *pic;
int got_picture;
int i, r;
av_register_all();
if(argc != 2) {
fprintf(stderr, "Usage: %s <media file>\n", argv[0]);
return 1;
}
fname = argv[1];
memset(ap, 0, sizeof(AVFormatParameters));
ap->video_codec_id = CODEC_ID_NONE;
printf("codec id %X\n", ap->video_codec_id);
r = av_open_input_file(&ic, fname, NULL, 0, ap);
if(r != 0 || ic == NULL) {
fprintf(stderr, "can not open input file %s\n", fname);
return 1;
}
av_find_stream_info(ic);
is = NULL;
for(i = 0; i < ic->nb_streams; i++) {
tis = ic->streams[i];
if(tis->codec->codec_type == CODEC_TYPE_VIDEO) {
printf("channel %d of %d\n", i, ic->nb_streams);
is = tis;
}
}
codec = avcodec_find_decoder(is->codec->codec_id);
if(codec == NULL) {
fprintf(stderr, "can not find codec %s\n", is->codec->codec_name);
return 1;
}
r = avcodec_open(is->codec, codec);
if(r != 0) {
fprintf(stderr, "can not initialize a AVCodecContext for codec %s\n",
codec->name);
return 1;
}
printf("Codec %s (%d x %d)\n", codec->name, is->codec->width,
is->codec->height);
for(i = 0; i < 10;) {
r = av_read_frame(ic, &pkt);
if(r != 0) {
fprintf(stderr, "no more frame\n");
return 1;
}
if(pkt.stream_index != is->index)
continue;
if(pkt.pts != AV_NOPTS_VALUE)
printf("Frame %d@%d: pts=%lld, dts=%lld, size=%d, data=%x\n",
i, pkt.stream_index, pkt.pts, pkt.dts, pkt.size, pkt.data);
else
printf("Frame %d@%d: pts=N/A, dts=%lld, size=%d, data=%x\n",
i, pkt.stream_index, pkt.dts, pkt.size, pkt.data);
av_pkt_dump(stdout, &pkt, 0);
avcodec_get_frame_defaults(&frame);
r = avcodec_decode_video(is->codec, &frame, &got_picture,
pkt.data, pkt.size);
if(r < 0) {
printf("decoding error\n");
return 1;
}
if(got_picture) {
printf("\tlinesize[4]={%d %d %d %d}, data[4]={%x %x %x %x)}\n",
frame.linesize[0], frame.linesize[1],
frame.linesize[2], frame.linesize[3],
frame.data[0], frame.data[1],
frame.data[2], frame.data[3]);
}
av_free_packet(&pkt);
i++;
}
avcodec_close(is->codec);
return 0;
}
```
FFMPEG中结构体很多。最关键的结构体可以分成以下几类
1. 解协议http,rtsp,rtmp,mms
AVIOContextURLProtocolURLContext主要存储视音频使用的协议的类型以及状态。URLProtocol存储输入视音频使用的封装格式。每种协议都对应一个URLProtocol结构。注意FFMPEG中文件也被当做一种协议“file”
2. 解封装flv,avi,rmvb,mp4
AVFormatContext主要存储视音频封装格式中包含的信息AVInputFormat存储输入视音频使用的封装格式。每种视音频封装格式都对应一个AVInputFormat 结构。
3. 解码h264,mpeg2,aac,mp3
每个AVStream存储一个视频/音频流的相关数据每个AVStream对应一个AVCodecContext存储该视频/音频流使用解码方式的相关数据每个AVCodecContext中对应一个AVCodec包含该视频/音频对应的解码器。每种解码器都对应一个AVCodec结构。
4. 存数据
视频的话,每个结构一般是存一帧;音频可能有好几帧
解码前数据AVPacket
解码后数据AVFrame
他们之间的对应关系如下所示:
![[Pasted image 20231220095827.png]]

Binary file not shown.

After

Width:  |  Height:  |  Size: 117 KiB