美文网首页
FFMPEG YUV转JPEG图片

FFMPEG YUV转JPEG图片

作者: 何亮hook_8285 | 来源:发表于2022-12-18 16:05 被阅读0次

此代码通过读取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;
}

相关文章

网友评论

      本文标题:FFMPEG YUV转JPEG图片

      本文链接:https://www.haomeiwen.com/subject/uoseqdtx.html