ffmpeg使用mjpeg把yuvj420p编码为jpg图像

news/2024/7/8 7:44:18 标签: ffmpeg, c语言, 音视频, c++

version

#define LIBAVCODEC_VERSION_MAJOR  60

#define LIBAVCODEC_VERSION_MINOR  15

#define LIBAVCODEC_VERSION_MICRO 100

note

1.

通过*.jpg推测时,out_fmt为image2,打开*.jpg文件时,in_fmt为image2

但是out_fmt为image2时,av_write_frame调用失败

2.

指定short_name为mjpeg,out_fmt为mjpeg

av_write_frame调用成功

code

void CFfmpegOps::EncodeYUVJ420pToMJPEG(const char *infile, const char *width_str, const char *height_str)
{
    if (!infile)
    {
        return;
    }

    int32_t width = 0;
    int32_t height = 0;

    try
    {
        width = std::stoi(width_str);
        height = std::stoi(height_str);
    }
    catch (std::exception& e)
    {
        return;
    }
    
#if 0
    size_t data_bytes = width * height * 3 / 2;
    std::shared_ptr<uint8_t> data(new uint8_t[data_bytes]);
#endif
    FILE *in_fp = nullptr;
    size_t n = 0;
    AVCodecContext *encoder_ctx = nullptr;
    const AVCodec *encoder = nullptr;
    const char *outfile = nullptr;
    int ret = -1;
    AVFormatContext *out_fmt_ctx = nullptr;
    AVStream *mjpeg_stream = nullptr;
    const AVOutputFormat *out_fmt = nullptr;
    AVFrame *avframe = nullptr;
    AVPacket *avpacket = nullptr;
    int frame_bytes = 0;

    in_fp = fopen(infile, "rb");
    if (!in_fp)
    {
        printf("fopen error\n");
        goto end;
    }

    avframe = av_frame_alloc();
    if (!avframe)
    {
        printf("av_frame_alloc error\n");
        goto end;
    }
    avframe->width = width;
    avframe->height = height;
    avframe->format = AV_PIX_FMT_YUVJ420P;
    avframe->pts = 0;

    // 获取单帧yuvj420p的字节数
    frame_bytes = av_image_get_buffer_size((AVPixelFormat)(avframe->format), avframe->width, avframe->height, 1);
#if 0
    if ((int)data_bytes != frame_bytes)
    {
        printf("data_bytes != frame_bytes\n");
        goto end;
    }
#endif

    ret = av_frame_get_buffer(avframe, 0);
    if (ret < 0)
    {
        printf("av_frame_get_buffer error:%s\n", GetFfmpegERR(ret));
        goto end;
    }

    // 读取y分量
    n = fread(avframe->data[0], sizeof(uint8_t), avframe->width * avframe->height, in_fp);
    if ((int)n != (avframe->width * avframe->height))
    {
        printf("n != (avframe->width * avframe->height)\n");
        goto end;
    }

    // 读取u分量
    n = fread(avframe->data[1], sizeof(uint8_t), avframe->width * avframe->height / 4, in_fp);
    if ((int)n != (avframe->width * avframe->height / 4))
    {
        printf("n != (avframe->width * avframe->height / 4)\n");
        goto end;
    }

    // 读取v分量
    n = fread(avframe->data[2], sizeof(uint8_t), avframe->width * avframe->height / 4, in_fp);
    if ((int)n != (avframe->width * avframe->height / 4))
    {
        printf("n != (avframe->width * avframe->height / 4)\n");
        goto end;
    }

#if 0
    n = fread(data.get(), sizeof(uint8_t), data_bytes, in_fp);
    if (n != data_bytes)
    {
        printf("n != data_bytes\n");
        goto end;
    }

    ret = av_image_fill_arrays(avframe->data, avframe->linesize,
                               data.get(),
                               encoder_ctx->pix_fmt, encoder_ctx->width, encoder_ctx->height, 1);
    if (ret < 0)
    {
        printf("av_image_fill_arrays error:%s\n", GetFfmpegERR(ret));
        goto end;
    }
    else
    {
        printf("ret:%d, frame_bytes:%d\n", ret, frame_bytes);
    }
#endif

    avpacket = av_packet_alloc();
    if (!avpacket)
    {
        printf("av_packet_alloc error\n");
        goto end;
    }

    encoder = avcodec_find_encoder(AV_CODEC_ID_MJPEG);
    if (!encoder)
    {
        printf("avcodec_find_encoder error\n");
        goto end;
    }

    encoder_ctx = avcodec_alloc_context3(encoder);
    if (!encoder_ctx)
    {
        printf("avcodec_alloc_context3 error\n");
        goto end;
    }
    // encoder_ctx->colorspace = ;
    // encoder_ctx->color_range = ;
    encoder_ctx->pix_fmt = AV_PIX_FMT_YUVJ420P;
    encoder_ctx->width = width;
    encoder_ctx->height = height;
    encoder_ctx->framerate.num = 25;
    encoder_ctx->framerate.den = 1;
    encoder_ctx->time_base.num = 1;
    encoder_ctx->time_base.den = 25;
    encoder_ctx->bit_rate = frame_bytes * encoder_ctx->framerate.num * 8;

    ret = avcodec_open2(encoder_ctx, encoder, nullptr);
    if (ret < 0)
    {
        printf("avcodec_open2 error:%s\n", GetFfmpegERR(ret));
        goto end;
    }

    out_fmt_ctx = avformat_alloc_context();
    if (!out_fmt_ctx)
    {
        printf("avformat_alloc_context error\n");
        goto end;
    }

    outfile = "image_%03d.jpg";
#if 0
    /*
    通过*.jpg推测时,out_fmt为image2,打开*.jpg文件时,in_fmt为image2
    但是out_fmt为image2时,av_write_frame调用失败
    */
    out_fmt = av_guess_format(nullptr, outfile, nullptr);
    if (!out_fmt)
    {
        printf("av_guess_format error\n");
        goto end;
    }
#else
    /*
    指定short_name为mjpeg,out_fmt为mjpeg
    av_write_frame调用成功
    */
    out_fmt = av_guess_format("mjpeg", nullptr, nullptr);
    if (!out_fmt)
    {
        printf("av_guess_format error\n");
        goto end;
    }
#endif

    out_fmt_ctx->oformat = out_fmt;

    mjpeg_stream = avformat_new_stream(out_fmt_ctx, encoder);
    if (!mjpeg_stream)
    {
        printf("avformat_new_stream error\n");
        goto end;
    }

    ret = avcodec_parameters_from_context(mjpeg_stream->codecpar, encoder_ctx);
    if (ret < 0)
    {
        printf("avcodec_parameters_from_context error:%s\n", GetFfmpegERR(ret));
        goto end;
    }

#if 0
    ret = avio_open(&(out_fmt_ctx->pb), outfile, AVIO_FLAG_WRITE);
    if (ret < 0)
    {
        printf("avio_open error:%s\n", GetFfmpegERR(ret));
        goto end;
    }
#else
    ret = avio_open2(&(out_fmt_ctx->pb), outfile, AVIO_FLAG_READ_WRITE, nullptr, nullptr);
    if (ret < 0)
    {
        printf("avio_open2 error:%s\n", GetFfmpegERR(ret));
        goto end;
    }
#endif

    ret = avformat_write_header(out_fmt_ctx, nullptr);
    if (ret < 0)
    {
        printf("avformat_write_header error:%s\n", GetFfmpegERR(ret));
        goto end;
    }

    ret = avcodec_send_frame(encoder_ctx, avframe);
    if (ret < 0)
    {
        printf("avcodec_send_frame error:%s\n", GetFfmpegERR(ret));
        goto end;
    }

    while (1)
    {
        ret = avcodec_receive_packet(encoder_ctx, avpacket);
        if (ret < 0)
        {
            printf("avcodec_receive_packet error:%s\n", GetFfmpegERR(ret));
            break;
        }
        avpacket->time_base.num = encoder_ctx->time_base.num;
        avpacket->time_base.den = encoder_ctx->time_base.den;

#if 0
        ret = av_interleaved_write_frame(out_fmt_ctx, avpacket);
        if (ret < 0)
        {
            printf("av_interleaved_write_frame error:%s\n", GetFfmpegERR(ret));
            break;
        }
#else
        ret = av_write_frame(out_fmt_ctx, avpacket);
        if (ret < 0)
        {
            printf("av_write_frame error:%s\n", GetFfmpegERR(ret));
            break;
        }
#endif
    }

    // 写元数据
    ret = av_write_trailer(out_fmt_ctx);
    if (ret < 0)
    {
        printf("av_write_trailer error:%s\n", GetFfmpegERR(ret));
        goto end;
    }

end:
    if (avpacket)
    {
        av_packet_free(&avpacket);
        avpacket = nullptr;
    }

    if (avframe)
    {
        av_frame_free(&avframe);
        avframe = nullptr;
    }

    if (out_fmt_ctx->pb)
    {
        avio_close(out_fmt_ctx->pb);
        out_fmt_ctx->pb = nullptr;
    }

    if (out_fmt_ctx)
    {
        avformat_free_context(out_fmt_ctx);
        out_fmt_ctx = nullptr;
    }

    if (encoder_ctx)
    {
        avcodec_free_context(&encoder_ctx);
        encoder_ctx = nullptr;
    }

    if (in_fp)
    {
        fclose(in_fp);
        in_fp = nullptr;
    }
}

perfomance


http://www.niftyadmin.cn/n/5536862.html

相关文章

中英双语介绍美国的州:阿肯色州(Arkansas)

中文版 阿肯色州简介 阿肯色州&#xff08;Arkansas&#xff09;位于美国南部&#xff0c;以其多样的自然景观、丰富的文化遗产和不断发展的经济而闻名。以下是对阿肯色州的详细介绍&#xff0c;包括其地理位置、人口、经济、教育、文化和主要城市。 地理位置 阿肯色州东临…

【经验总结】Springboot打印指定类的日志到指定文件中

原文地址&#xff1a;https://www.cnblogs.com/zeng1994/p/f9bff238b13a0bf8fb8bf88c41db7a34.html 以下内容已经过实践&#xff0c;勘误&#xff0c;总结 环境&#xff1a;Springboot2.5.2 公司有个项目&#xff0c;需要和几个第三方系统对接。这种项目&#xff0c;日志一定要…

C++ | Leetcode C++题解之第214题最短回文串

题目&#xff1a; 题解&#xff1a; class Solution { public:string shortestPalindrome(string s) {int n s.size();vector<int> fail(n, -1);for (int i 1; i < n; i) {int j fail[i - 1];while (j ! -1 && s[j 1] ! s[i]) {j fail[j];}if (s[j 1] …

Vbus 和 Vbat

在嵌入式系统开发中&#xff0c;Vbus 和 Vbat 是两个不同的电源相关术语&#xff0c;它们的区别主要在于它们的用途和连接的电源类型。 Vbus 定义: Vbus 通常是指 USB 总线电压。在 USB 2.0 中&#xff0c;Vbus 通常为 5V 电源。用途: Vbus 提供电源给 USB 设备&#xff0c;确…

3.用户程序与驱动交互

驱动程序请使用第二章https://blog.csdn.net/chenhequanlalala/article/details/140034424 用户app与驱动交互最常见的做法是insmod驱动后&#xff0c;生成一个设备节点&#xff0c;app通过open&#xff0c;read等系统调用去操作这个设备节点&#xff0c;这里先用mknode命令调…

arm_uart4实验

#include "uart4.h" //UART //初始化 void hal_uart4_init() { //rcc_init //…

C#的多线程UI窗体控件显示方案

在C#中&#xff0c;特别是在使用Windows窗体&#xff08;WinForms&#xff09;或WPF&#xff08;Windows Presentation Foundation&#xff09;进行UI开发时&#xff0c;处理多线程与UI控件的交互需要特别小心。由于UI控件不是线程安全的&#xff0c;直接从非UI线程&#xff08…

VS Code解释及快捷键

一、VS Code Visual Studio Code&#xff08;简称 VS Code&#xff09;是由微软开发的一款免费、开源的代码编辑器。它具有丰富的功能和扩展性&#xff0c;广泛应用于各种编程语言的开发环境。以下是对 VS Code 的详细介绍&#xff1a; 主要特性 1. 跨平台 VS Code 支持 Wi…