此代碼通過(guò)讀取YUV數(shù)據(jù)轉(zhuǎn)換JPEG圖片數(shù)據(jù)宽堆,并且存儲(chǔ)到磁盤(pán)中。
代碼如下:
#include <iostream>
#include <string>
#include <fstream>
#include <thread>
#include <functional>
extern "C"{
#include <libavformat/avformat.h>
#include <libavutil/pixdesc.h>
#include <libavutil/opt.h>
#include <libavutil/imgutils.h>
#include <libswscale/swscale.h>
};
//heliang
int main()
{
AVPixelFormat pfmt=AV_PIX_FMT_YUV420P;
AVFrame *frame=av_frame_alloc();
frame->width=1920;
frame->height=818;
frame->format=pfmt;
std::ifstream ifs("d:\\test.yuv",std::ios::binary);
//獲取一幀數(shù)據(jù)大小
int frameSize=av_image_get_buffer_size(pfmt,frame->width,frame->height,1);
//讀取一幀數(shù)據(jù)
std::unique_ptr<uint8_t*> yuvFrameData=std::make_unique<uint8_t*>(new uint8_t[frameSize]);
ifs.read((char*)*yuvFrameData.get(),frameSize);
//填充圖像的平面線(xiàn)尺寸
av_image_fill_linesizes(frame->linesize,pfmt,frame->width);
//將1維數(shù)組轉(zhuǎn)換成二維數(shù)組践付,例如Y=frame->data[0],U=frame->data[1],V=Y=frame->data[2]
av_image_fill_pointers(frame->data,pfmt,frame->height,*yuvFrameData.get(),frame->linesize);
//創(chuàng)建AV_PIX_FMT_YUVJ422P的幀
AVFrame *yuvj422pFrame=av_frame_alloc();
yuvj422pFrame->width=frame->width;
yuvj422pFrame->height=frame->height;
yuvj422pFrame->format=AV_PIX_FMT_YUVJ422P;
//初始化buffer數(shù)據(jù)
av_frame_get_buffer(yuvj422pFrame,0);
//yuv420p轉(zhuǎn)yuvj422p
SwsContext *swsContext= nullptr;
//創(chuàng)建重采樣的上下文
swsContext=sws_getCachedContext(
swsContext, //重采樣上下文
frame->width, //源yuv寬度
frame->height, //源yuv高度
pfmt, //yuv存儲(chǔ)格式
yuvj422pFrame->width,
yuvj422pFrame->height,
AV_PIX_FMT_YUVJ422P,
SWS_BILINEAR, //重采樣算法愕把,線(xiàn)性算法
NULL, //源過(guò)濾,不使用
NULL, //目標(biāo)過(guò)濾弄匕,不使用
0 //過(guò)濾參數(shù),不使用
);
//轉(zhuǎn)換
int reH=sws_scale(swsContext, //重采樣上下文
frame->data, //yuv數(shù)據(jù)
frame->linesize, //yuv設(shè)置一行大小
0, //設(shè)置y,不考慮沽瞭,設(shè)置0
frame->height, //設(shè)置yuv高度
yuvj422pFrame->data, //設(shè)置rgba的存儲(chǔ)空間
yuvj422pFrame->linesize //rgba存儲(chǔ)空間
);
std::cout << "reH=" << reH << std::endl;
AVFormatContext *pfctx=avformat_alloc_context();
//通過(guò)簡(jiǎn)稱(chēng)獲取輸出上下文,通過(guò)ffmpeg -formats命令查看
pfctx->oformat=av_guess_format("mjpeg", NULL, NULL);
if (avio_open(&pfctx->pb, "d:\\test.jpg", AVIO_FLAG_READ_WRITE) < 0) //創(chuàng)建并初始化一個(gè)AVIOContext
{
std::cout << "avio_open error msg " << std::endl;
return -1;
}
//找到編碼器
AVCodec *codec=avcodec_find_encoder(pfctx->oformat->video_codec);
AVCodecContext *enCodecCtx=avcodec_alloc_context3(codec);
enCodecCtx->codec_id=pfctx->oformat->video_codec;
enCodecCtx->codec_type = AVMEDIA_TYPE_VIDEO;
enCodecCtx->width=frame->width;
enCodecCtx->height=frame->height;
enCodecCtx->pix_fmt=AV_PIX_FMT_YUVJ422P;
enCodecCtx->time_base={1,25};
AVStream* stream = avformat_new_stream(pfctx, 0);
avcodec_parameters_from_context(stream->codecpar,enCodecCtx);
av_dump_format(pfctx, 0, NULL, 1);
int ret=avcodec_open2(enCodecCtx,codec,NULL);
if(ret!=0)
{
char buf[1024]={0};
av_strerror(ret,buf,sizeof(buf));
std::cout << "avcodec_open2 failed error msg :" << buf << std::endl;
return 0;
}
avformat_write_header(pfctx, NULL);
AVPacket *pkt=av_packet_alloc();
//發(fā)送到編碼器中
ret = avcodec_send_frame(enCodecCtx, yuvj422pFrame);
while (ret >= 0)
{
//接受編碼器數(shù)據(jù)
ret = avcodec_receive_packet(enCodecCtx, pkt);
if (ret < 0)
break;
av_write_frame(pfctx, pkt);
//解引用
av_packet_unref(pkt);
}
av_write_trailer(pfctx);
ifs.close();
av_packet_free(&pkt);
av_frame_free(&frame);
av_frame_free(&yuvj422pFrame);
avcodec_free_context(&enCodecCtx);
return 0;
}