FFmpeg adalah proyek Open Source besar, semacam ensiklopedia multimedia. Dengan FFmpeg Anda dapat menyelesaikan banyak tugas multimedia komputer. Namun tetap saja, terkadang ada kebutuhan untuk memperluas FFmpeg. Cara standar adalah membuat perubahan pada kode proyek dan kemudian mengkompilasi versi baru. Artikel ini menjelaskan cara menambahkan codec baru. Beberapa fitur untuk menghubungkan fungsi eksternal ke FFmpeg juga dipertimbangkan. Jika tidak perlu menambahkan codec, maka artikel tersebut mungkin berguna untuk pemahaman yang lebih baik tentang arsitektur codec FFmpeg dan pengaturannya. Diasumsikan bahwa pembaca akrab dengan arsitektur FFmpeg, proses kompilasi FFmpeg, dan juga memiliki pengalaman pemrograman menggunakan FFmpeg API. Deskripsi ini berlaku untuk FFmpeg 4.2 "Ada", Agustus 2019.
Daftar isi
Pendahuluan
Codec (codec, berasal dari kombinasi istilah COder dan DECoder) adalah istilah yang sangat umum dan, seperti yang sering terjadi dalam kasus seperti itu, maknanya sedikit bervariasi tergantung pada konteksnya. Arti utama adalah perangkat lunak atau perangkat keras untuk mengompresi / mendekompresi data media. Alih-alih istilah kompresi / dekompresi, istilah pengkodean / decoding sering digunakan. Tetapi dalam beberapa kasus, codec biasanya dipahami hanya berarti format kompresi (mereka juga mengatakan format codec), terlepas dari cara yang digunakan untuk kompresi / dekompresi. Mari kita lihat bagaimana istilah codec digunakan dalam FFmpeg.
1. Identifikasi codec
Codec FFmpeg dikompilasi di perpustakaan libavcodec .
1.1. ID codec
enum AVCodecID
didefinisikan dalam file libavcodec/avcodec.h
. Setiap elemen enumerasi ini mengidentifikasi format kompresi. Elemen enumerasi ini harus dalam bentuk AV_CODEC_ID_XXX
, di mana XXX
nama pengenal codec unik dalam huruf besar. Berikut adalah contoh pengidentifikasi codec: AV_CODEC_ID_H264
, AV_CODEC_ID_AAC
. Untuk deskripsi yang lebih rinci tentang pengenal codec, gunakan struktur AVCodecDescriptor
(dideklarasikan dalam libavcodec/avcodec.h
, diberikan dalam bentuk singkatan):
typedef struct AVCodecDescriptor { enum AVCodecID id; enum AVMediaType type; const char *name; const char *long_name;
Anggota kunci dari struktur ini adalah id
, anggota lainnya memberikan informasi tambahan tentang pengenal codec. Setiap pengenal codec secara unik dikaitkan dengan jenis media ( type
anggota) dan memiliki nama unik ( name
anggota), ditulis dalam huruf kecil. Array tipe AVCodecDescriptor
didefinisikan dalam file libavcodec/codec_desc.c
AVCodecDescriptor
. Untuk setiap pengenal codec, ada elemen array yang sesuai. Elemen array ini harus dipesan oleh nilai id
, karena pencarian biner digunakan untuk mencari elemen. Untuk mendapatkan informasi tentang pengenal codec, Anda dapat menggunakan fungsi:
const AVCodecDescriptor* avcodec_descriptor_get(enum AVCodecID id); const AVCodecDescriptor* avcodec_descriptor_get_by_name(const char *name); enum AVMediaType avcodec_get_type(enum AVCodecID codec_id); const char* avcodec_get_name(enum AVCodecID id);
1.2. Codec
Codec itu sendiri - seperangkat alat yang diperlukan untuk melakukan encoding / decoding data media, menggabungkan struktur AVCodec
(dideklarasikan dalam libavcodec/avcodec.h
). Ini versi singkatnya, lebih lengkap akan dibahas di bawah.
typedef struct AVCodec { const char *name; const char *long_name; enum AVMediaType type; enum AVCodecID id;
Anggota terpenting dari struktur ini adalah id
, pengenal codec, ada juga anggota yang mendefinisikan jenis media ( type
), tetapi nilainya harus sesuai dengan nilai anggota yang sama dari AVCodecDescriptor
. Codec dibagi menjadi dua kategori: encoders, yang memampatkan atau menyandikan media, dan decoder, yang melakukan operasi yang berlawanan - dekompresi atau dekode. (Kadang-kadang dalam teks Rusia, alih-alih istilah, encoder menggunakan kertas kalkir dari bahasa Inggris - encoder.) Tidak ada anggota khusus dalam AVCodec
yang mendefinisikan kategori codec (meskipun kategori dapat ditentukan secara tidak langsung menggunakan fungsi av_codec_is_decoder()
, kategori ini ditentukan saat pendaftaran. Bagaimana ini akan dilakukan akan ditunjukkan di bawah ini: Beberapa codec dapat memiliki pengidentifikasi codec yang sama. Jika mereka memiliki kategori yang sama, mereka harus berbeda dengan nama ( name
anggota). Sebuah encoder dan decoder yang memiliki pengidentifikasi codec yang sama dapat untuk memilikinya nama yang sama, yang mungkin juga bertepatan dengan nama pengenal codec (tetapi kecocokan ini opsional). Situasi seperti itu dapat menyebabkan beberapa kebingungan, tetapi tidak ada yang harus dilakukan, Anda harus dengan jelas memahami entitas apa nama itu dimiliki. Dalam satu kategori, nama Codec harus unik. Untuk mencari codec terdaftar, ada fungsi:
AVCodec* avcodec_find_encoder_by_name(const char *name); AVCodec* avcodec_find_decoder_by_name(const char *name); AVCodec* avcodec_find_encoder(enum AVCodecID id); AVCodec* avcodec_find_decoder(enum AVCodecID id);
Karena beberapa codec dapat memiliki pengidentifikasi yang sama, dua fungsi terakhir mengembalikan salah satunya, yang dapat dianggap sebagai codec default untuk pengenal codec yang diberikan.
Daftar semua codec terdaftar dapat diminta dengan perintah
ffmpeg -codecs >codecs.txt
Setelah menjalankan perintah, file codecs.txt
akan berisi daftar ini. Setiap pengenal codec akan diwakili oleh catatan (baris) terpisah. Di sini, misalnya, entri untuk pengenal codec AV_CODEC_ID_H264
:
DEV.LS
h264
H.264 / AVC / MPEG-4 AVC / MPEG-4 part 10
(decoders: h264 h264_qsv h264_cuvid)
(encoders: libx264 libx264rgb h264_amf h264_nvenc h264_qsv nvenc nvenc_h264)
Pada awal rekaman, ada karakter khusus yang menentukan fitur umum yang tersedia untuk pengenal codec ini: D
- decoder terdaftar, E
- encoders terdaftar, V
- digunakan untuk video, L
- ada kemungkinan kompresi lossy, S
- ada kemungkinan kompresi lossless. Berikutnya adalah nama pengenal kodek ( h264
), diikuti oleh nama pengenal kodek yang panjang ( H.264 / AVC / MPEG-4 AVC / MPEG-4 part 10
), dan kemudian daftar nama decoder dan enkoder terdaftar.
2. Menambahkan codec baru ke FFmpeg
Kami akan mempertimbangkan prosedur untuk menambahkan codec baru ke FFmpeg menggunakan contoh codec audio, yang akan kita sebut FROX
.
Langkah 1. Tambahkan elemen baru ke enum AVCodecID
.
Daftar ini ada di file libavcodec/avcodec.h
. Saat menambahkan, Anda harus mengikuti aturan:
- Nilai suatu elemen tidak harus bertepatan dengan nilai-nilai elemen enumerasi yang ada;
- Jangan mengubah nilai elemen enumerasi yang ada;
- Posting nilai baru dalam kelompok codec yang sama.
Menurut templat, pengidentifikasi elemen ini harus AV_CODEC_ID_FROX
. Tempatkan sebelum AV_CODEC_ID_PCM_S64LE
dan berikan nilai 0x10700
.
Langkah 2. Tambahkan item ke array codec_descriptors
(file libavcodec/codec_desc.c
).
static const AVCodecDescriptor codec_descriptors[] = {
Anda perlu menambahkan elemen ke tempat "kanan", monotonitas elemen array dengan nilai id
tidak boleh dilanggar.
Langkah 3. Tetapkan instance AVCodec
secara terpisah untuk encoder dan decoder.
Untuk melakukan ini, pertama-tama Anda perlu menentukan struktur untuk konteks codec dan beberapa fungsi yang akan melakukan pengkodean / decoding aktual dan beberapa operasi lain yang diperlukan. Pada bagian ini, definisi-definisi ini akan dibuat secara sangat skematis, deskripsi yang lebih rinci akan dibuat nanti. Kami akan menempatkan kode di file libavcodec/frox.c
#include "avcodec.h"
Untuk kesederhanaan, dalam contoh ini, encoder dan decoder memiliki konteks yang sama - FroxContext
, tetapi paling sering encoder dan decoder memiliki konteks yang berbeda. Perhatikan juga bahwa AVCodec
instance AVCodec
harus mengikuti pola khusus.
Langkah 4. Tambahkan instance AVCodec
ke daftar registrasi.
Pergi ke file libavcodec/allcodecs.c
. Pada awal file ini adalah daftar deklarasi semua codec terdaftar. Tambahkan codec kami ke daftar ini:
extern AVCodec ff_frox_decoder; extern AVCodec ff_frox_encoder;
Selama eksekusi, skrip configure
menemukan semua deklarasi tersebut dan menghasilkan file libavcodec/codec_list.c
, yang berisi array pointer ke codec yang dideklarasikan di libavcodec/allcodecs.c
. Setelah menjalankan skrip di file libavcodec/codec_list.c
kita akan melihat:
static const AVCodec * const codec_list[] = {
Juga, selama eksekusi skrip configure
, file config.h
, di mana kita menemukan deklarasi
#define CONFIG_FROX_DECODER 1 #define CONFIG_FROX_ENCODER 1
Langkah 5. Edit libavcodec/Makefile
Buka libavcodec/Makefile
. Kami menemukan bagian # decoders/encoders
, dan tambahkan di sana
OBJS-$(CONFIG_FROX_DECODER) += frox.o OBJS-$(CONFIG_FROX_ENCODER) += frox.o
Langkah 6. Edit kode multiplexer dan demultiplexer.
Multiplexer (muxer) dan demultiplexer (demuxer) harus "mengetahui" codec baru. Saat merekam, perlu untuk mencatat informasi pengidentifikasian codec ini, saat membaca, menentukan pengenal codec dari informasi pengidentifikasi. Inilah yang perlu Anda lakukan untuk format matroska
( *.mkv
).
1. Dalam file libavformat/matroska.c
, tambahkan elemen untuk codec baru ke array libavformat/matroska.c
:
const CodecTags ff_mkv_codec_tags[] = {
String "A_FROX"
dan akan ditulis oleh multiplexer ke file sebagai informasi pengenal. Dalam array ini, ia dikaitkan dengan pengenal codec, oleh karena itu, ketika membaca, demultiplexer dapat dengan mudah menentukannya. Demultiplexer menulis pengenal codec ke anggota codec_id
dari struktur codec_id
. Pointer ke struktur ini adalah anggota struktur AVStream
.
2. Dalam file libavformat/matroskaenc.c
, tambahkan elemen ke array additional_audio_tags
:
static const AVCodecTag additional_audio_tags[] = {
Jadi semuanya sudah siap. Pertama, jalankan skrip configure
. Setelah itu, Anda perlu memastikan bahwa perubahan yang dijelaskan di atas dalam file libavcodec/codec_list.c
dan config.h
dilakukan. Kemudian Anda dapat menjalankan kompilasi:
make clean
make
Jika kompilasi berjalan ffmpeg.exe
, ffmpeg
dieksekusi (atau ffmpeg.exe
, jika OS targetnya adalah Windows) muncul. Jalankan perintah
./ffmpeg -codecs >codecs.txt
dan pastikan FFmpeg "melihat" codec baru kami, kami menemukan entri dalam file codecs.txt
DEA..S frox FROX audio (decoders: frox_dec) (encoders: frox_enc)
3. Deskripsi terperinci dari konteks dan fungsi yang diperlukan
Pada bagian ini, kami menjelaskan secara lebih rinci seperti apa struktur konteks codec dan fungsi yang diperlukan.
3.1. Konteks codec
Konteks codec dapat mendukung pemasangan opsi. Untuk pembuat enkode, dukungan ini cukup sering digunakan, untuk decoder lebih jarang. Struktur yang mendukung instalasi opsi harus memiliki pointer ke struktur AVClass
sebagai anggota pertama dan kemudian opsi itu sendiri.
#include "libavutil/opt.h" typedef struct FroxContext { const AVClass *av_class; int frox_int; char *frox_str; uint8_t *frox_bin; int bin_size; } FroxContext;
Selanjutnya, Anda perlu menentukan larik tipe AVOption
, yang masing-masing elemen menjelaskan opsi tertentu.
static const AVOption frox_options[] = { { "frox_int", "This is a demo option of int type.", offsetof(FroxContext, frox_int), AV_OPT_TYPE_INT, { .i64 = -1 }, 1, SHRT_MAX }, { "frox_str", "This is a demo option of string type.", offsetof(FroxContext, frox_str), AV_OPT_TYPE_STRING }, { "frox_bin", "This is a demo option of binary type.", offsetof(FroxContext, frox_bin), AV_OPT_TYPE_BINARY }, { NULL }, };
Untuk setiap opsi, Anda harus menentukan nama, deskripsi, offset dalam struktur, ketik. Anda juga dapat menentukan nilai default dan untuk opsi integer kisaran nilai yang valid.
Selanjutnya, Anda perlu mendefinisikan instance dari jenis AVClass
.
static const AVClass frox_class = { .class_name = "FroxContext", .item_name = av_default_item_name, .option = frox_options, .version = LIBAVUTIL_VERSION_INT, };
Pointer ke instance ini harus digunakan untuk menginisialisasi anggota AVCodec
sesuai.
AVCodec ff_frox_decoder = {
Sekarang ketika menjalankan fungsi
AVCodecContext *avcodec_alloc_context3(const AVCodec *codec);
sebuah instance dari struktur AVCodecContext
dan anggota codec
diinisialisasi. Selanjutnya, berdasarkan nilai codec->priv_data_size
, memori yang diperlukan akan dialokasikan untuk instance FroxContext
, menggunakan nilai codec->priv_class
anggota pertama dari instance ini akan diinisialisasi dan kemudian fungsi av_opt_set_defaults()
akan dipanggil, yang akan mengatur nilai default untuk opsi. Sebuah penunjuk ke instance FroxContext
akan tersedia melalui anggota priv_data
dari struktur priv_data
.
Saat bekerja dengan FFmpeg API, nilai untuk opsi dapat diatur secara langsung.
const AVCodec *codec;
Cara lain adalah dengan menggunakan kamus opsi, yang akan diteruskan sebagai argumen ketiga saat memanggil avcodec_open2()
(lihat di bawah).
Menggunakan fungsi
const AVOption* av_opt_next(const void* ctx, const AVOption* prev);
Anda bisa mendapatkan daftar semua opsi yang didukung oleh konteks codec. Ini berguna saat memeriksa codec. Tetapi sebelum itu, Anda harus memastikan bahwa codec_ctx->codec->priv_class
diatur ke nilai yang tidak nol, jika konteksnya tidak mendukung opsi dan operasi apa pun dengan opsi akan merusak program.
3.2. Fungsi
Mari kita periksa lebih detail bagaimana fungsi yang digunakan dalam inisialisasi codec dan encoding / decoding yang sebenarnya diatur. Mereka biasanya selalu perlu mendapatkan pointer ke FroxContext
.
AVCodecContext *codec_ctx;
Fungsi frox_decode_init()
dan frox_encode_init()
akan dipanggil ketika fungsi dieksekusi
int avcodec_open2( AVCodecContext *codec_ctx, const AVCodec *codec, AVDictionary **options);
Mereka perlu mengalokasikan sumber daya yang diperlukan agar codec berfungsi, dan jika perlu, menginisialisasi beberapa anggota struktur AVCodecContext
, misalnya frame_size
untuk frame_size
audio.
Fungsi frox_decode_close()
dan frox_encode_close()
akan dipanggil ketika dieksekusi
int avcodec_close(AVCodecContext *codec_ctx);
Mereka perlu membebaskan sumber daya yang dialokasikan.
Pertimbangkan fungsi untuk mengimplementasikan decoding
int frox_decode( AVCodecContext *codec_ctx, void *outdata, int *outdata_size, AVPacket *pkt);
Dia harus mengimplementasikan operasi berikut:
- Decoding aktual;
- Alokasi buffer yang diperlukan untuk kerangka output;
- Salin data yang diterjemahkan ke buffer bingkai.
Pertimbangkan cara mengalokasikan buffer yang diperlukan untuk kerangka output. Parameter outdata
sebenarnya menunjuk ke AVFrame
, jadi Anda harus terlebih dahulu melakukan konversi jenis:
AVFrame* frm = outdata;
Selanjutnya, Anda perlu mengalokasikan buffer untuk menyimpan data frame. Untuk melakukan ini, inisialisasi anggota AVFrame
yang menentukan ukuran buffer bingkai. Untuk audio, ini adalah nb_samples
, channel_layout
, format
(untuk width
, height
, format
video).
Setelah itu, Anda perlu memanggil fungsi
int av_frame_get_buffer(AVFrame* frm, int alignment);
Pointer ke frame, yang merupakan parameter outdata
dikonversi, digunakan sebagai argumen pertama, disarankan untuk meneruskan nol sebagai argumen kedua. Setelah menggunakan frame (ini sudah terjadi di luar codec), buffer yang dialokasikan oleh fungsi ini dibebaskan oleh fungsi
void av_frame_unref(AVFrame* frm);
Fungsi frox_decode()
harus mengembalikan jumlah byte yang digunakan untuk decoding dari paket yang ditunjuk oleh pkt
. Jika pembentukan frame selesai, maka variabel yang ditunjuk oleh outdata_size
diberi nilai bukan nol, jika variabel ini mendapat nilai 0
.
Pertimbangkan fungsi untuk mengimplementasikan pengkodean
int frox_encode( AVCodecContext *codec_ctx, AVPacket *pkt, const AVFrame *frame, int *got_pkt_ptr);
Dia harus mengimplementasikan operasi berikut:
- Pengodean aktual;
- Alokasi buffer yang diperlukan untuk paket output;
- Salin data yang disandikan ke buffer paket.
Untuk memilih buffer yang diperlukan, gunakan fungsinya
int av_new_packet(AVPacket *pkt, int pack_size);
Parameter pkt
digunakan sebagai argumen pertama, dan ukuran data yang disandikan adalah yang kedua. Setelah menggunakan paket (ini sudah terjadi di luar codec), buffer yang dialokasikan oleh fungsi ini dibebaskan oleh fungsi
void av_packet_unref(AVPacket *pkt);
Jika paket selesai, maka variabel yang ditunjuk oleh got_pkt_ptr
diberi nilai bukan nol, jika variabel ini mendapat nilai 0
. Jika tidak ada kesalahan, fungsi mengembalikan nol, jika tidak kode kesalahan.
Saat mengimplementasikan codec, logging biasanya digunakan (untuk kesalahan ini dapat dianggap sebagai persyaratan wajib). Berikut ini sebuah contoh:
static int frox_decode_close(AVCodecContext *codec_ctx) { av_log(codec_ctx, AV_LOG_INFO, "FROX decode close\n");
Dalam hal ini, saat mengeluarkan ke log, nama codec akan digunakan sebagai nama konteks.
3.3. Prangko waktu
Untuk mengatur waktu dalam FFmpeg, basis waktu digunakan, ditentukan dalam detik menggunakan nomor rasional yang diwakili oleh jenis AVRational
. (Pendekatan serupa digunakan dalam C ++ 11. Misalnya, 1/1000 menetapkan milidetik.) Frame dan paket memiliki cap waktu tipe int64_t
, nilainya berisi waktu dalam unit waktu yang sesuai. Bingkai, yaitu, struktur AVFrame
, memiliki pts
anggota (cap waktu presentasi), nilai yang menentukan waktu relatif adegan yang diambil dalam bingkai. Paket, yaitu struktur AVPacket
, memiliki anggota pts
(cap waktu presentasi) dan dts
(cap waktu dekompresi). Nilai dts
menentukan waktu relatif pengiriman paket untuk decoding. Untuk codec sederhana, itu sama dengan pts
, tetapi untuk codec kompleks bisa berbeda (misalnya, untuk h264
ketika menggunakan B-frame), yaitu, paket dapat didekodekan dalam urutan yang salah di mana frame harus digunakan.
Unit waktu didefinisikan untuk aliran dan codec, struktur AVStream
memiliki anggota yang sesuai - time_base
, anggota yang sama memiliki struktur AVCodecContext
.
Stempel waktu paket yang diekstrak dari aliran menggunakan av_read_frame()
akan ditentukan dalam satuan waktu aliran ini. Saat decoding, satuan waktu codec tidak digunakan. Untuk video decoder, biasanya tidak disetel, untuk audio decoder memiliki nilai standar - kebalikan dari frekuensi pengambilan sampel. Decoder harus menetapkan cap waktu untuk kerangka output berdasarkan cap waktu paket. FFmpeg secara independen mendefinisikan label seperti itu dan menulisnya ke anggota best_effort_timestamp
dari struktur best_effort_timestamp
. Semua cap waktu ini akan menggunakan satuan waktu aliran dari mana paket diekstraksi.
Untuk pembuat enkode, Anda harus menentukan satuan waktu. Dalam kode klien yang mengatur penguraian kode, Anda harus menetapkan nilai untuk anggota time_base
dari struktur time_base
sebelum memanggil avcodec_open2()
. Biasanya mengambil satuan waktu yang digunakan untuk prangko waktu dari frame yang dikodekan. Jika ini tidak dilakukan, maka video encoders biasanya memberikan kesalahan, audio encoders menetapkan nilai default - kebalikan dari frekuensi sampling. Apakah codec dapat mengubah satuan waktu tertentu tidak sepenuhnya jelas. Untuk berjaga-jaga, lebih baik untuk selalu memeriksa nilai time_base
setelah memanggil avcodec_open2()
dan, jika sudah berubah, avcodec_open2()
ulang cap waktu frame input per unit waktu codec. Dalam proses pengkodean, Anda harus menginstal pts
dan dts
paket. Setelah pengkodean, sebelum menulis paket ke aliran output, perlu untuk menghitung ulang cap waktu paket dari unit waktu codec ke unit waktu aliran. Untuk melakukan ini, gunakan fungsinya
void av_packet_rescale_ts( AVPacket *pkt, AVRational tb_src, AVRational tb_dst);
Saat menulis paket ke stream, perlu untuk memastikan bahwa nilai dts
benar-benar meningkat, jika tidak maka multiplexer akan melempar kesalahan. (Untuk informasi lebih lanjut, lihat dokumentasi untuk fungsi av_interleaved_write_frame()
.)
3.4. Fungsi lain yang digunakan oleh codec
Saat Anda menginisialisasi instance AVCodec
, dua fungsi lagi dapat didaftarkan. Berikut adalah anggota AVCodec
relevan:
typedef struct AVCodec {
Yang pertama dari mereka dipanggil sekali pada saat pendaftaran codec.
Yang kedua me-reset keadaan internal codec, itu akan dipanggil selama eksekusi fungsi
void avcodec_flush_buffers(AVCodecContext *codec_ctx);
Panggilan ini diperlukan, misalnya, ketika secara paksa mengubah posisi pemutaran saat ini.
4. Implementasi eksternal dari codec
4.1. Koneksi fungsi eksternal
Pertimbangkan organisasi codec berikut: codec yang terdaftar di FFmpeg memainkan peran kerangka kerja, dan mendelegasikan prosedur pengodean / dekode aktual ke fungsi eksternal (semacam plugin) yang diterapkan di luar FFmpeg.
. Inilah beberapa di antaranya:
- , FFmpeg ;
- C, , C++;
- framework, FFmpeg.
, FFmpeg «», FFmpeg API. «» FFmpeg ( , ), . — . .
typedef int(*dec_extern_t)(const void*, int, void*); static int frox_decode( AVCodecContext* codec_ctx, void* outdata, int *outdata_size, AVPacket* pkt) { int ret = -1; void* out_buff;
FFmpeg API ( C++) .
extern "C" { int DecodeFroxData(const void* buff, int size, void* outBuff); typedef int(*dec_extern_t)(const void*, int, void*); #include <libavcodec/avcodec.h> #include <libavutil/opt.h> } // ... AVCodecContext* ctx; // ... dec_extern_t dec = DecodeFroxData; void* pv = &dec; auto pb = static_cast<const uint8_t*>(pv); auto sz = sizeof(dec); av_opt_set_bin(ctx->priv_data, "frox_bin", pb, sz, 0);
4.2.
— . , . , . , , FFmpeg , «» , . . , . FFmpeg API - , , . . , . PC (Windows) DirectShow AVI . PC - DirectShow. 32- FourCC. ( biCompression
BITMAPINFOHEADER
.) , DirectShow , PC -. FFmpeg , , , codec_tag
AVCodecParameters
FourCC, . FFmpeg API , . FFmpeg FFmpeg API.
, *.mkv
FFmpeg ( ENCODER
).
Kesimpulan
, , FFmpeg: , changelog, .. «» FFmpeg, , .
Sumber daya
FFmpeg
[1] FFmpeg —
[2] FFmpeg —
[3] FFmpeg —
[4] FFmpeg — Ubuntu
[5] FFmpeg Compilation Guide
[6] Compilation of FFmpeg 4.0 in Windows 10
FFmpeg API
[7] ffmpeg
[8] FFmpeg codec HOWTO
[9] FFmpeg video codec tutorial