返回顶部
首页 > 资讯 > 后端开发 > 其他教程 >C++ ffmpeg如何实现将视频帧转换成jpg或png等图片
  • 936
分享到

C++ ffmpeg如何实现将视频帧转换成jpg或png等图片

2023-07-05 17:07:46 936人浏览 独家记忆
摘要

本篇内容介绍了“c++ FFmpeg如何实现将视频帧转换成jpg或png等图片”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!一、如

本篇内容介绍了“c++ FFmpeg如何实现将视频帧转换成jpg或png等图片”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!

    一、如何实现

    1、查找编码器

    首先需要查找图片编码器,比如jpg为AV_CODEC_ID_MJPEG,png为AV_CODEC_ID_PNG

    示例代码:

    enum AVCodecID codec = avcodec_find_encoder(AV_CODEC_ID_MJPEG);

    2、构造编码器上下文

    有了编码器就可以构造编码器上下文了。

    AVCodecContext*ctx = avcodec_alloc_context3(codec);ctx->bit_rate = 3000000;ctx->width = frame->width;//视频帧的宽ctx->height = frame->height;//视频帧的高ctx->time_base.num = 1;ctx->time_base.den = 25;ctx->Gop_size = 10;ctx->max_b_frames = 0;ctx->thread_count = 1;ctx->pix_fmt = *codec->pix_fmts;//使用编码器适配的像素格式//打开编码器avcodec_open2(ctx, codec, NULL);

    3、像素格式转换

    如果输入视频帧的像素和编码器的像素格式不相同则需要转换像素格式,我们采用SwsContext 转换即可

    AVFrame*rgbFrame = av_frame_alloc();//转换后的帧swsContext = sws_getContext(frame->width, frame->height, (enum AVPixelFORMat)frame->format, frame->width, frame->height, ctx->pix_fmt, 1, NULL, NULL, NULL);int bufferSize = av_image_get_buffer_size(ctx->pix_fmt, frame->width, frame->height, 1) * 2;buffer = (unsigned char*)av_malloc(bufferSize);//构造帧的缓存av_image_fill_arrays(rgbFrame->data, rgbFrame->linesize, buffer, ctx->pix_fmt, frame->width, frame->height, 1);sws_scale(swsContext, frame->data, frame->linesize, 0, frame->height, rgbFrame->data, rgbFrame->linesize);//构造必要的参数rgbFrame->format = ctx->pix_fmt;rgbFrame->width = ctx->width;rgbFrame->height = ctx->height;

    4、编码

    得到转后的帧就可以编码

    ret = avcodec_send_frame(ctx, rgbFrame);

    5、获取图片数据

    获取解码后的包即可得到图片数据。

    uint8_t* outbuf;//输出图片的缓存size_t outbufSize;//缓存大小AVPacket pkt;av_init_packet(&pkt);//获取解码的包avcodec_receive_packet(ctx, &pkt);//将图片数据拷贝到缓存if (pkt.size > 0 && pkt.size <= outbufSize)memcpy(outbuf, pkt.data, pkt.size);

    6、销毁资源

    将上述步骤使用的对象销毁。

    if (swsContext){    sws_freeContext(swsContext);}if (rgbFrame){    av_frame_unref(rgbFrame);    av_frame_free(&rgbFrame);}if (buffer){    av_free(buffer);}av_packet_unref(&pkt);if (ctx){    avcodec_close(ctx);    avcodec_free_context(&ctx);}

    二、完整代码

    /// <summary>/// 帧转图片/// 如果外部提供的缓存长度不足则不会写入。/// </summary>/// <param name="frame">[in]视频帧</param>/// <param name="codecID">[in]图片编码器ID,如jpg:AV_CODEC_ID_MJPEG,png:AV_CODEC_ID_PNG</param>/// <param name="outbuf">[out]图片缓存,由外部提供</param>/// <param name="outbufSize">[in]图片缓存长度</param>/// <returns>返回图片实际长度</returns>static int frameToImage(AVFrame* frame, enum AVCodecID codecID, uint8_t* outbuf, size_t outbufSize){    int ret = 0;    AVPacket pkt;    AVCodec* codec;    AVCodecContext* ctx = NULL;    AVFrame* rgbFrame = NULL;    uint8_t* buffer = NULL;    struct SwsContext* swsContext = NULL;    av_init_packet(&pkt);    codec = avcodec_find_encoder(codecID);    if (!codec)    {        printf("avcodec_send_frame error %d", codecID);        goto end;    }    if (!codec->pix_fmts)    {        printf("unsupport pix format with codec %s", codec->name);        goto end;    }    ctx = avcodec_alloc_context3(codec);    ctx->bit_rate = 3000000;    ctx->width = frame->width;    ctx->height = frame->height;    ctx->time_base.num = 1;    ctx->time_base.den = 25;    ctx->gop_size = 10;    ctx->max_b_frames = 0;    ctx->thread_count = 1;    ctx->pix_fmt = *codec->pix_fmts;    ret = avcodec_open2(ctx, codec, NULL);    if (ret < 0)    {        printf("avcodec_open2 error %d", ret);        goto end;    }    if (frame->format != ctx->pix_fmt)    {        rgbFrame = av_frame_alloc();        if (rgbFrame == NULL)        {            printf("av_frame_alloc  fail:%d");            goto end;        }        swsContext = sws_getContext(frame->width, frame->height, (enum AVPixelFormat)frame->format, frame->width, frame->height, ctx->pix_fmt, 1, NULL, NULL, NULL);        if (!swsContext)        {            printf("sws_getContext  fail:%d");            goto end;        }        int bufferSize = av_image_get_buffer_size(ctx->pix_fmt, frame->width, frame->height, 1) * 2;        buffer = (unsigned char*)av_malloc(bufferSize);        if (buffer == NULL)        {            printf("buffer alloc fail:%d", bufferSize);            goto end;        }        av_image_fill_arrays(rgbFrame->data, rgbFrame->linesize, buffer, ctx->pix_fmt, frame->width, frame->height, 1);        if ((ret = sws_scale(swsContext, frame->data, frame->linesize, 0, frame->height, rgbFrame->data, rgbFrame->linesize)) < 0)        {            printf("sws_scale error %d", ret);        }        rgbFrame->format = ctx->pix_fmt;        rgbFrame->width = ctx->width;        rgbFrame->height = ctx->height;        ret = avcodec_send_frame(ctx, rgbFrame);    }    else    {        ret = avcodec_send_frame(ctx, frame);    }    if (ret < 0)    {        printf("avcodec_send_frame error %d", ret);        goto end;    }    ret = avcodec_receive_packet(ctx, &pkt);    if (ret < 0)    {        printf("avcodec_receive_packet error %d", ret);        goto end;    }    if (pkt.size > 0 && pkt.size <= outbufSize)        memcpy(outbuf, pkt.data, pkt.size);    ret = pkt.size;end:    if (swsContext)    {        sws_freeContext(swsContext);    }    if (rgbFrame)    {        av_frame_unref(rgbFrame);        av_frame_free(&rgbFrame);    }    if (buffer)    {        av_free(buffer);    }    av_packet_unref(&pkt);    if (ctx)    {        avcodec_close(ctx);        avcodec_free_context(&ctx);    }    return ret;}

    三、使用示例

    1、截取视频帧并保存文件

    void main() {    AVFrame* frame;//视频解码得到的帧    saveFrameToJpg(frame,"snapshot.jpg");}
    /// <summary>/// 将视频帧保存为jpg图片/// </summary>/// <param name="frame">视频帧</param>/// <param name="path">保存的路径</param>void saveFrameToJpg(AVFrame*frame,const char*path) {    //确保缓冲区长度大于图片,使用brga像素格式计算。如果是bmp或tiff依然可能超出长度,需要加一个头部长度,或直接乘以2。    int bufSize = av_image_get_buffer_size(AV_PIX_FMT_BGRA, frame->width, frame->height, 64);    //申请缓冲区    uint8_t* buf = (uint8_t*)av_malloc(bufSize);    //将视频帧转换成图片    int picSize = frameToImage(frame, AV_CODEC_ID_MJPEG, buf, bufSize);    //写入文件    auto f = fopen(path, "wb+");    if (f)    {        fwrite(buf, sizeof(uint8_t), bufSize, f);        fclose(f);    }    //释放缓冲区    av_free(buf);}

    2、自定义数据构造AVFrame

    void main() {    uint8_t*frameData;//解码得到的视频数据    AVFrame* frame=allocFrame(frameData,640,360,AV_PIX_FMT_YUV420P);    saveFrameToJpg(frame,"snapshot.jpg");//此方法定义在示例1中    av_frame_free(&frame);}
    /// <summary>/// 通过裸数据生成avframe/// </summary>/// <param name="frameData">帧数据</param>/// <param name="width">帧宽</param>/// <param name="height">帧高</param>/// <param name="format">像素格式</param>/// <returns>avframe,使用完成后需要调用av_frame_free释放</returns>AVFrame* allocFrame(uint8_t*frameData,int width,int height,AVPixelFormat format) {    AVFrame* frame = av_frame_alloc();    frame->width = width;    frame->height = height;    frame->format = format;    av_image_fill_arrays(frame->data, frame->linesize, frameData, format, frame->width, frame->height, 64);    return frame;}

    “C++ ffmpeg如何实现将视频帧转换成jpg或png等图片”的内容就介绍到这里了,感谢大家的阅读。如果想了解更多行业相关的知识可以关注编程网网站,小编将为大家输出更多高质量的实用文章!

    --结束END--

    本文标题: C++ ffmpeg如何实现将视频帧转换成jpg或png等图片

    本文链接: https://lsjlt.com/news/353918.html(转载时请注明来源链接)

    有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

    猜你喜欢
    • C++ ffmpeg如何实现将视频帧转换成jpg或png等图片
      本篇内容介绍了“C++ ffmpeg如何实现将视频帧转换成jpg或png等图片”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!一、如...
      99+
      2023-07-05
    • Python如何将视频转换为图片
      Python如何将视频转换为图片,针对这个问题,这篇文章详细介绍了相对应的分析和解答,希望可以帮助更多想解决这个问题的小伙伴找到更简单易行的方法。前言代码让人头秃,可是我喜欢上了代码的逻辑感和代码解决问题的力量。(我要对这个专题的图片进行修...
      99+
      2023-06-22
    • Python3如何实现将bytes图片转jpg格式
      本篇内容主要讲解“Python3如何实现将bytes图片转jpg格式”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“Python3如何实现将bytes图片转jpg格式”吧!需求:我爬取的图片是by...
      99+
      2023-06-07
    • python如何实现将JPG、BMP图片转化为bgr
      这篇文章主要介绍“python如何实现将JPG、BMP图片转化为bgr”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“python如何实现将JPG、BMP图片转化为bgr”文章能帮助大家解决问题。py...
      99+
      2023-07-05
    • 如何在PHP中实现视频图片替换
      随着互联网技术的不断发展,多媒体内容已经成为了互联网中不可或缺的一部分。在现如今的互联网世界中,视频内容和图片内容已经成为了网站和应用中最为重要的展示方式,这也就使得图片和视频的处理成为了开发者们必须要面对的问题。而在这方面,PHP作为一种...
      99+
      2023-05-14
    • 基于Python如何实现合并多张图片转成mp4视频
      这篇文章主要介绍“基于Python如何实现合并多张图片转成mp4视频”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“基于Python如何实现合并多张图片转成mp4视频”文章能帮助大家解决问题。一、需要...
      99+
      2023-07-06
    • Python如何实现合并多张图片成视频
      本篇内容介绍了“Python如何实现合并多张图片成视频”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!合并多张图片到视频的方法说明除了使用 O...
      99+
      2023-07-05
    • C语言如何实现将字符串转换成整数
      本文小编为大家详细介绍“C语言如何实现将字符串转换成整数”,内容详细,步骤清晰,细节处理妥当,希望这篇“C语言如何实现将字符串转换成整数”文章能帮助大家解决疑惑,下面跟着小编的思路慢慢深入,一起来学习新知识吧。这是一个很有意思的问题。请不要...
      99+
      2023-07-05
    • PHP如何实现PDF转换成图片时保留字体颜色
      这篇文章主要讲解了“PHP如何实现PDF转换成图片时保留字体颜色”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“PHP如何实现PDF转换成图片时保留字体颜色”吧!一、为什么PDF转图片会改变字...
      99+
      2023-07-05
    软考高级职称资格查询
    编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
    • 官方手机版

    • 微信公众号

    • 商务合作