基于FFMPEG将YUV420转为jpg

代码1来自雷神博客,从文件中读取一帧的YUV数据,然后将其进行编码,然后调用av_write_frame函数将AVPacket里面的数据写到输出文件中去,在手敲代码的过程中,对解码后的AVPakcet里面的数据进行测试,发现AVPacket里面的data其实就是一副picture 完整的数据,于是便直接将其写入文件中去,不再采用av_write_frame的方式,如代码2,大体上采用雷博的代码,在一些细节地方做了修改。

代码1:


int YUV_2_JPG1(char* pFile)
{
    if (NULL == pFile) return -1;

    AVFormatContext* pFormatCtx;
    AVOutputFormat*  pOutFmt;
    AVStream* pStream;
    AVCodecContext* pCodecCtx;
    AVCodec* pCodec;
    AVFrame* pFrame;
    AVPacket pkt;

    uint8_t* picture_buf;
    int y_size = 0;
    int size = 0;
    int width = 640;
    int height = 480;
    const char* out_file = "test1.jpg";

    int got_picture = 0;
    int ret = 0;

    FILE* in_file = fopen(pFile, "rb");
    if (NULL == in_file)
    {
        printf("open input file error!\n");
        return -1;
    }

    av_register_all();

    pFormatCtx = avformat_alloc_context();   //分配AVFormatCtx
    pOutFmt = av_guess_format("mjpeg", NULL, NULL); //设置输出文件格式
    pFormatCtx->oformat = pOutFmt;

    if (avio_open(&pFormatCtx->pb, out_file, AVIO_FLAG_READ_WRITE) < 0) //创建并初始化一个AVIOContext
    {
        printf("Could not open output file!\n");
        return -1;
    }

    pStream = avformat_new_stream(pFormatCtx, 0);
    if (NULL == pStream)
        return -1;
    /*设置相关信息*/
    pCodecCtx = pStream->codec;
    pCodecCtx->codec_id = pOutFmt->video_codec;
    pCodecCtx->codec_type = AVMEDIA_TYPE_VIDEO;
    pCodecCtx->pix_fmt = AV_PIX_FMT_YUVJ420P;
    pCodecCtx->width = width;
    pCodecCtx->height = height;
    pCodecCtx->time_base.num = 1;
    pCodecCtx->time_base.den = 25;

    //av_dump_format(pFormatCtx, 0, out_file, 1);

    pCodec = avcodec_find_encoder(pCodecCtx->codec_id); //查找编码器
    if (NULL == pCodec)
    {
        printf("can not find codec!\n");
        return -1;
    }
    if (avcodec_open2(pCodecCtx, pCodec, NULL) < 0)
    {
        printf("con not open codec!\n");
        return -1;
    }

    pFrame = av_frame_alloc();
    size = avpicture_get_size(pCodecCtx->pix_fmt, pCodecCtx->width, pCodecCtx->height);//获取图片的大小
    picture_buf = (uint8_t*)av_malloc(size);
    if (NULL == picture_buf)
    {
        printf("malloc picture buf error!\n");
        return -1;
    }
   avpicture_fill((AVPicture*)pFrame, picture_buf, pCodecCtx->pix_fmt, pCodecCtx->width, pCodecCtx->height);

    avformat_write_header(pFormatCtx, NULL); 

    y_size = pCodecCtx->width * pCodecCtx->height;
    av_new_packet(&pkt, y_size*2);  //给AVPacket申请空间

    if (fread(picture_buf, 1, y_size*3/2,in_file) != (y_size*3/2))
    {
        printf("read input file error!\n");
        return -1;
    }    

    pFrame->width = pCodecCtx->width;  
    pFrame->height =  pCodecCtx->height;
    pFrame->format = pCodecCtx->pix_fmt;
    pFrame->data[0] = picture_buf;
    pFrame->data[1] = picture_buf + y_size;
    pFrame->data[2] = picture_buf + y_size*5/4;

    ret = avcodec_encode_video2(pCodecCtx, &pkt, pFrame, &got_picture);//编码
    if (ret < 0)
    {
        printf("encodec yuv data error!\n");
        return -1;
    }
    if (1 == got_picture)
    {
        pkt.stream_index = pStream->index;
        av_write_frame(pFormatCtx, &pkt); //写数据
    }

    av_write_trailer(pFormatCtx);

    av_free_packet(&pkt);
    av_free(picture_buf);
    av_free(pFrame);
    avcodec_close(pStream->codec);
    avio_close(pFormatCtx->pb);
    avformat_free_context(pFormatCtx);

    fclose(in_file);

    return 0;
}

代码2:


int YUV_2_JPG2(char* pFile)
{
    if (NULL == pFile) return -1;

    AVFormatContext* pFormatCtx;
    AVStream* pStream;
    AVCodecContext* pCodecCtx;
    AVCodec* pCodec;
    AVFrame* pFrame;
    AVPacket pkt;

    uint8_t* picture_buf;
    int y_size = 0;
    int size = 0;
    int width = 640;
    int height = 480;

    int got_picture = 0;
    int ret = 0;

    FILE* in_file = fopen(pFile, "rb");
    if (NULL == in_file)
    {
        printf("open input file error!\n");
        return -1;
    }
    FILE* out_file =  fopen("test2.jpg", "wb");
    if (NULL == out_file)
    {
        printf("open output file error!\n");
        return -1;
    }

    av_register_all();

    pFormatCtx = avformat_alloc_context();   //分配AVFormatCtx


    pStream = avformat_new_stream(pFormatCtx, 0);
    if (NULL == pStream)
        return -1;
    /*设置相关信息*/
    pCodecCtx = pStream->codec;
    pCodecCtx->codec_id = AV_CODEC_ID_MJPEG;
    pCodecCtx->codec_type = AVMEDIA_TYPE_VIDEO;
    pCodecCtx->pix_fmt = AV_PIX_FMT_YUVJ420P;
    pCodecCtx->width = width;
    pCodecCtx->height = height;
    pCodecCtx->time_base.num = 1;
    pCodecCtx->time_base.den = 25;

    //av_dump_format(pFormatCtx, 0, out_file, 1);

    pCodec = avcodec_find_encoder(pCodecCtx->codec_id); //查找编码器
    if (NULL == pCodec)
    {
        printf("can not find codec!\n");
        return -1;
    }
    if (avcodec_open2(pCodecCtx, pCodec, NULL) < 0)
    {
        printf("con not open codec!\n");
        return -1;
    }

    pFrame = av_frame_alloc();
    size = avpicture_get_size(pCodecCtx->pix_fmt, pCodecCtx->width, pCodecCtx->height);//获取图片的大小
    picture_buf = (uint8_t*)av_malloc(size);
    if (NULL == picture_buf)
    {
        printf("malloc picture buf error!\n");
        return -1;
    }
   avpicture_fill((AVPicture*)pFrame, picture_buf, pCodecCtx->pix_fmt, pCodecCtx->width, pCodecCtx->height);


    y_size = pCodecCtx->width * pCodecCtx->height;
    av_new_packet(&pkt, y_size*2);  //给AVPacket申请空间

    if (fread(picture_buf, 1, y_size*3/2,in_file) != (y_size*3/2))
    {
        printf("read input file error!\n");
        return -1;
    }    

    pFrame->width = pCodecCtx->width;  
    pFrame->height =  pCodecCtx->height;
    pFrame->format = pCodecCtx->pix_fmt;
    pFrame->data[0] = picture_buf;
    pFrame->data[1] = picture_buf + y_size;
    pFrame->data[2] = picture_buf + y_size*5/4;

    ret = avcodec_encode_video2(pCodecCtx, &pkt, pFrame, &got_picture);//编码
    if (ret < 0)
    {
        printf("encodec yuv data error!\n");
        return -1;
    }
    if (1 == got_picture)
    {
            fwrite(pkt.buf->data, 1, pkt.size, out_file);
    }

    av_free_packet(&pkt);
    av_free(picture_buf);
    av_free(pFrame);
    avcodec_close(pStream->codec);
    avformat_free_context(pFormatCtx);

    fclose(in_file);
    fclose(out_file);
    return 0;
}

文章最底部,领取最新最全C++音视频学习提升资料,内容包括(C/C++Linux 服务器开发,FFmpeg webRTC rtmp hls rtsp ffplay srs

 

猜你喜欢

转载自blog.csdn.net/m0_60259116/article/details/125208187