前言
下面代碼是在我的上一篇博客:FFmpeg RGB轉YUV 的代碼的基礎上修改而來的,創建了編碼器並進行 H264 編碼,進一步將 RGB 格式像素數據轉換成 H264 格式像素數據,親測有效。
完整代碼
#include <iostream>
extern "C"
{
#include <libavformat/avformat.h>
#include <libswscale/swscale.h>
}
#pragma comment(lib,"avformat.lib")
#pragma comment(lib,"avcodec.lib")
#pragma comment(lib,"avutil.lib")
#pragma comment(lib,"swscale.lib")
using namespace std;
int main()
{
char infile[] = "dove_BGRA.rgb";
char outfile[] = "out.264";
// 源圖像參數
int width = 640;
int height = 360;
int fps = 25;
//1 打開RGB和H264文件
FILE *fpin = fopen(infile, "rb");
if (!fpin)
{
cout << infile << "open infile failed!" << endl;
getchar();
return -1;
}
FILE *fpout = fopen(outfile, "wb");
if (!fpout)
{
cout << "open outfile failed!" << endl;
exit(1);
}
// 創建RGB緩沖區同時分配內存
unsigned char *rgbBuf = new unsigned char[width*height * 4];
// 注冊所有和編解碼器有關的組件
av_register_all();
/* 2 創建編碼器 */
// 查找編碼器
AVCodec *codec = avcodec_find_encoder(AV_CODEC_ID_H264);
if (!codec)
{
cout << "avcodec_find_encoder AV_CODEC_ID_H264 failed!" << endl;
getchar();
return -1;
}
// 給編碼器分配內存,返回對應編碼器上下文
AVCodecContext *codecCtx = avcodec_alloc_context3(codec);
if (!codecCtx)
{
cout << "avcodec_alloc_context3 failed!" << endl;
getchar();
return -1;
}
// 配置編碼器上下文的成員
codecCtx->width = width; // 設置編碼視頻寬度
codecCtx->height = height; // 設置編碼視頻高度
codecCtx->time_base.num = 1;
codecCtx->time_base.den = 25; // 設置幀率,num為分子,den為分母,如果是1/25則表示25幀/s
codecCtx->pix_fmt = AV_PIX_FMT_YUV420P; // 設置輸出像素格式
// 打開編碼器
int ret = avcodec_open2(codecCtx, codec, NULL);
if (ret < 0)
{
cout << "avcodec_open2 failed!" << endl;
getchar();
return -1;
}
cout << "avcodec_open2 success!" << endl;
// 3 創建視頻重采樣上下文:指定源和目標圖像分辨率、格式
SwsContext *swsCtx = NULL;
swsCtx = sws_getCachedContext(swsCtx,
width, height, AV_PIX_FMT_BGRA,
width, height, AV_PIX_FMT_YUV420P,
SWS_BICUBIC,
NULL, NULL, NULL
);
//4 創建YUV視頻幀並配置
AVFrame *yuvFrame = av_frame_alloc();
yuvFrame->format = AV_PIX_FMT_YUV420P;
yuvFrame->width = width;
yuvFrame->height = height;
ret = av_frame_get_buffer(yuvFrame, 32);
if (ret < 0)
{
cout << "av_frame_get_buffer failed!" << endl;
getchar();
return -1;
}
// 循環寫視頻文件
int pts = 0;
int count = 0;
for (;;)
{
//5 每次讀取一幀RGB數據到rgbBuf,讀取完畢則退出
int len = fread(rgbBuf, 1, width*height * 4, fpin);
if (len <= 0)
{
break;
}
//5 創建RGB視頻幀並綁定RGB緩沖區(avpicture_fill是給rgbFrame初始化一些字段,並且會自動填充data和linesize)
AVFrame *rgbFrame = av_frame_alloc();
avpicture_fill((AVPicture *)rgbFrame, rgbBuf, AV_PIX_FMT_BGRA, width, height);
//7 像素格式轉換,轉換后的YUV數據存放在yuvFrame
int outSliceH = sws_scale(swsCtx, rgbFrame->data, rgbFrame->linesize, 0, height,
yuvFrame->data, yuvFrame->linesize
);
if (outSliceH <= 0)
break;
/* 8 H264編碼 */
// 將未壓縮的AVFrame數據(yuv)給編碼器
yuvFrame->pts = count++ * (codecCtx->time_base.num * 1000 / codecCtx->time_base.den);
ret = avcodec_send_frame(codecCtx, yuvFrame);
if (ret != 0)
{
continue;
}
// 將編碼數據保存在AVPacket
AVPacket pkt;
av_init_packet(&pkt);
ret = avcodec_receive_packet(codecCtx, &pkt);
if (ret != 0)
continue;
//9 寫入H264文件
fwrite(pkt.data, 1, pkt.size, fpout);
//av_packet_unref(&pkt);
cout << "<" << pkt.size << ">";
}
// 關閉RGB和YUV文件
fclose(fpin);
fclose(fpout);
// 釋放RGB緩沖區
delete rgbBuf;
//關閉編碼器
avcodec_close(codecCtx);
//清理編碼器上下文
avcodec_free_context(&codecCtx);
//清理視頻重采樣上下文
sws_freeContext(swsCtx);
cout << "======================end=========================" << endl;
getchar();
return 0;
}