此代码通过读取YUV数据转换JPEG图片数据,并且存储到磁盘中。
代码如下:
#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);
//获取一帧数据大小
int frameSize=av_image_get_buffer_size(pfmt,frame->width,frame->height,1);
//读取一帧数据
std::unique_ptr<uint8_t*> yuvFrameData=std::make_unique<uint8_t*>(new uint8_t[frameSize]);
ifs.read((char*)*yuvFrameData.get(),frameSize);
//填充图像的平面线尺寸
av_image_fill_linesizes(frame->linesize,pfmt,frame->width);
//将1维数组转换成二维数组,例如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);
//创建AV_PIX_FMT_YUVJ422P的帧
AVFrame *yuvj422pFrame=av_frame_alloc();
yuvj422pFrame->width=frame->width;
yuvj422pFrame->height=frame->height;
yuvj422pFrame->format=AV_PIX_FMT_YUVJ422P;
//初始化buffer数据
av_frame_get_buffer(yuvj422pFrame,0);
//yuv420p转yuvj422p
SwsContext *swsContext= nullptr;
//创建重采样的上下文
swsContext=sws_getCachedContext(
swsContext, //重采样上下文
frame->width, //源yuv宽度
frame->height, //源yuv高度
pfmt, //yuv存储格式
yuvj422pFrame->width,
yuvj422pFrame->height,
AV_PIX_FMT_YUVJ422P,
SWS_BILINEAR, //重采样算法,线性算法
NULL, //源过滤,不使用
NULL, //目标过滤,不使用
0 //过滤参数,不使用
);
//转换
int reH=sws_scale(swsContext, //重采样上下文
frame->data, //yuv数据
frame->linesize, //yuv设置一行大小
0, //设置y,不考虑,设置0
frame->height, //设置yuv高度
yuvj422pFrame->data, //设置rgba的存储空间
yuvj422pFrame->linesize //rgba存储空间
);
std::cout << "reH=" << reH << std::endl;
AVFormatContext *pfctx=avformat_alloc_context();
//通过简称获取输出上下文,通过ffmpeg -formats命令查看
pfctx->oformat=av_guess_format("mjpeg", NULL, NULL);
if (avio_open(&pfctx->pb, "d:\\test.jpg", AVIO_FLAG_READ_WRITE) < 0) //创建并初始化一个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();
//发送到编码器中
ret = avcodec_send_frame(enCodecCtx, yuvj422pFrame);
while (ret >= 0)
{
//接受编码器数据
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;
}
网友评论