代碼如下:
#include <iostream> #include <fstream> using namespace std; extern "C" { // 指定函數是C語言函數,以C語言的方式去編譯 #include <libavcodec/avcodec.h> } // 以預處理指令的方式導入庫 #pragma comment(lib, "avcodec.lib") #pragma comment(lib, "avutil.lib") int main(int argc, char *argv[]) { string filename = "400_300_25"; AVCodecID codec_id = AV_CODEC_ID_H264; if (argc > 1) { string codec = argv[1]; if (codec == "h265" || codec == "hevc") { codec_id = AV_CODEC_ID_HEVC; } } if (codec_id == AV_CODEC_ID_H264) { filename += ".h264"; } else if (codec_id == AV_CODEC_ID_HEVC) { filename += ".h265"; } ofstream ofs; ofs.open(filename, ios::binary); // 1. 查找編碼器 AV_CODEC_ID_H264(h264) AV_CODEC_ID_HEVC(h265) auto codec = avcodec_find_encoder(codec_id); if (!codec) { cerr << "codec not found" << endl; return -1; } // 2. 創建上下文 auto c = avcodec_alloc_context3(codec); if (!c) { cerr << "avcodec_alloc_context3 failed" << endl; return -1; } // 3. 設定編碼器的上下文參數 c->width = 400; // 視頻幀的寬度 c->height = 300; // 視頻幀的高度 c->time_base = { 1, 25 }; // 時間基數,即時間戳的顯示單位,可以認為是1秒內顯示25幀 c->pix_fmt = AV_PIX_FMT_YUV420P; // 指定源數據的像素格式,跟編碼格式有關,如果編碼格式是h264, 這里就不能指定為RGBA c->thread_count = 16; // 編碼線程數,可以通過調用系統接口獲取CPU的核心數量 // 4. 打開編碼上下文 int re = avcodec_open2(c, codec, nullptr); if (re != 0) { char buf[1024] = { 0 }; av_strerror(re, buf, sizeof(buf) - 1); cerr << "avcodec_open2 failed" << buf << endl; return -1; } cout << "avcodec_open2 success" << endl; // 創建AVFrame空間,用於表示一幀數據 auto frame = av_frame_alloc(); frame->width = c->width; frame->height = c->height; frame->format = c->pix_fmt; re = av_frame_get_buffer(frame, 0); if (re != 0) { char buf[1024] = {0}; av_strerror(re, buf, sizeof(buf) - 1); cerr << "av_frame_get_buffer() failed" << endl; return -1; } auto pkt = av_packet_alloc(); // 創建一個10s的視頻,共250幀 for (int i = 0; i < 250; i++) { // 生成一幀圖像 每幀數據都不同 // Y for (int y = 0; y < frame->height; y++) { for (int x = 0; x < frame->width; x++) { frame->data[0][y * frame->linesize[0] + x] = x + y + i * 3; } } // UV for (int y = 0; y < frame->height / 2; y++) { for (int x = 0; x < frame->width / 2; x++) { frame->data[1][y * frame->linesize[1] + x] = 128 + y + i * 2; frame->data[2][y * frame->linesize[2] + x] = 64 + x + i * 5; } } // 顯示的時間 frame->pts = i; re = avcodec_send_frame(c, frame); if (re != 0) { cerr << "avcodec_send_frame() failed" << endl; break; } // >=0 表示有數據返回,編碼一個AVFrame 可能會返回多個AVPacket while (re >= 0) { // 接收壓縮幀 一般前幾次調用會返回空的 (緩沖,立即返回,編碼未完成) // 編碼是在獨立的線程中完成的 // 每次調用會重新分配pkt的數據空間,並改變內部的指針指向 re = avcodec_receive_packet(c, pkt); if (re == AVERROR(EAGAIN) || re == AVERROR_EOF) break; if (re < 0) { char buf[1024] = { 0 }; av_strerror(re, buf, sizeof(buf) - 1); cerr << "avcodec_receive_packet() failed" << endl; return -1; } cout << pkt->size << " " << flush; // 寫入編碼后的壓縮數據 ofs.write((char *)pkt->data, pkt->size); // 注意 一定要調用 av_packet_unref() 刪除已申請的數據空間,若不刪除,下次還會重新申請,這樣會造成內存泄漏 av_packet_unref(pkt); } } // 釋放AVPacket av_packet_free(&pkt); // 釋放AVFrame av_frame_free(&frame); // 釋放上下文 avcodec_free_context(&c); }
直接運行程序,會生成一個名為"400_300_25.h264"的h264文件,使用VLC打開:
回到工作目錄,執行:first_ffmpeg.exe h265, 會緊接着生成一個名為: 400_300_25.h265 的h265文件,雙擊使用VLC打開: