FFmpeg视频缩略图与图像转换接口分析

介绍

FFmpeg制作视频缩略图思路以及图像转换接口的具体分析,已经录制了讲解视频放到了B站可以移步观看【FFmpeg视频缩略图与图像转换分析】 https://www.bilibili.com/video/BV1pG411i7rH/?share_source=copy_web&vd_source=e89a0faea91d9f4d36966a27ca0bd3e4,这里直接上代码。

核心代码

将得到的QImage自行选择渲染方式显示即可

//生成视频缩略图
bool WidgetMediaPreview::generateVideoPreview(const QString &videoPath)
{
   
    std::string temp = videoPath.toStdString();
    AVFormatContext *inFmtCtx = avformat_alloc_context();
    int ret = avformat_open_input(&inFmtCtx, temp.c_str(), NULL, NULL);
    if (ret < 0)
    {
   
        qDebug() << "open input error";
        return false;
    }

    //获取流信息
    ret = avformat_find_stream_info(inFmtCtx, NULL);
    if (ret < 0)
    {
   
        qDebug() << "find stream info error";
        return false;
    }

    //获取视频流信息
    bool getVideo = false;
    int videoIndex = av_find_best_stream(inFmtCtx, AVMEDIA_TYPE_VIDEO, -1, -1, NULL, 0);
    AVStream *videoStream = NULL;
    AVCodec *videoDecoder = NULL;
    AVCodecContext *videoDeCodecCtx = NULL;
    if (videoIndex >= 0)
    {
   
        videoStream = inFmtCtx->streams[videoIndex];

        //初始化解码器
        videoDecoder = avcodec_find_decoder(videoStream->codecpar->codec_id);
        videoDeCodecCtx = avcodec_alloc_context3(videoDecoder);
        if(videoDeCodecCtx != NULL)
        {
   
            avcodec_parameters_to_context(videoDeCodecCtx, videoStream->codecpar);
            ret = avcodec_open2(videoDeCodecCtx, videoDecoder, NULL);
            if(ret < 0)
                avcodec_free_context(&videoDeCodecCtx);
            else
                getVideo = true;
        }
    }

    if(!getVideo)
    {
   
        avformat_close_input(&inFmtCtx);
        return false;
    }

    //输出视频参数信息
    if(getVideo)
    {
   
        int videoWidth = videoStream->codecpar->width;
        int videoHeight = videoStream->codecpar->height;
        int videoFPS = av_q2d(videoStream->avg_frame_rate);
        AVPixelFormat format = videoDeCodecCtx->pix_fmt;
        m_videoDuration = inFmtCtx->duration / AV_TIME_BASE;
        qDebug() << "Video" << videoWidth << videoHeight << videoFPS << format << m_videoDuration;
    }

    AVPacket *packet = av_packet_alloc();
    AVFrame *videoFrame = av_frame_alloc();
    while(true)
    {
   
        //不断读取packet
        ret = av_read_frame(inFmtCtx, packet);
        if (ret == AVERROR_EOF)
        {
   
            break;
        }

        if(packet->stream_index == videoIndex)
        {
   
            //编码数据进行解码
            ret = avcodec_send_packet(videoDeCodecCtx, packet);
            if (ret < 0)
            {
   
                av_packet_unref(packet);
                continue;
            }
            ret = avcodec_receive_frame(videoDeCodecCtx, videoFrame);
            if (ret < 0)
            {
   
                av_packet_unref(packet);
                continue;
            }

            //将得到的首帧图像转为Image
            int srcW = videoFrame->width;
            int srcH = videoFrame->height;

            //将解码后的frame数据转换
            int byte = av_image_get_buffer_size(AV_PIX_FMT_RGB32, srcW, srcH, 1);
            uint8_t *videoData = (uint8_t *)av_malloc(byte * sizeof(uint8_t));     
            AVFrame *swsFrame = av_frame_alloc();
            av_image_fill_arrays(swsFrame->data, swsFrame->linesize, videoData, (AVPixelFormat)AV_PIX_FMT_RGB32, srcW, srcH, 1);

            SwsContext *swsCtx = sws_getContext(srcW, srcH, (AVPixelFormat)videoFrame->format, srcW, srcH, (AVPixelFormat)AV_PIX_FMT_RGB32, SWS_FAST_BILINEAR, NULL, NULL, NULL);
            sws_scale(swsCtx, (const uint8_t *const *)videoFrame->data, videoFrame->linesize, 0, srcH, swsFrame->data, swsFrame->linesize);

            //构造QImage swsFrame->data[0]指向的就是videoData,二者等同
            QImage image((uchar *)videoData, srcW, srcH, QImage::Format_RGB32);
            m_image = image.copy();
            av_frame_free(&swsFrame);

            break;
        }

        av_packet_unref(packet);
    }

    //释放资源
    av_packet_free(&packet);
    av_frame_free(&videoFrame);
    if(videoDeCodecCtx)
        avcodec_free_context(&videoDeCodecCtx);

    avformat_close_input(&inFmtCtx);
    return true;
}

相关推荐

  1. FFmpeg视频略图图像转换接口分析

    2023-12-07 02:44:02       34 阅读
  2. Android 获取视频略图

    2023-12-07 02:44:02       8 阅读
  3. Android获取图片略图尺寸问题

    2023-12-07 02:44:02       25 阅读
  4. C# 生成指定图片略图

    2023-12-07 02:44:02       11 阅读
  5. ffmpeg 视频格式转换

    2023-12-07 02:44:02       15 阅读
  6. ffmpeg视频转换 webp

    2023-12-07 02:44:02       15 阅读

最近更新

  1. TCP协议是安全的吗?

    2023-12-07 02:44:02       18 阅读
  2. 阿里云服务器执行yum,一直下载docker-ce-stable失败

    2023-12-07 02:44:02       19 阅读
  3. 【Python教程】压缩PDF文件大小

    2023-12-07 02:44:02       18 阅读
  4. 通过文章id递归查询所有评论(xml)

    2023-12-07 02:44:02       20 阅读

热门阅读

  1. 重叠AMR的应用及编程实现

    2023-12-07 02:44:02       35 阅读
  2. MySQL - 索引类型详解

    2023-12-07 02:44:02       37 阅读
  3. 前端新趋势?有了Web Component,还在纠结vue或react

    2023-12-07 02:44:02       35 阅读
  4. Django大回顾 - 8 中间件、csrf认证相关

    2023-12-07 02:44:02       31 阅读
  5. Android Camera2使用

    2023-12-07 02:44:02       27 阅读
  6. 责任链模式

    2023-12-07 02:44:02       33 阅读
  7. ARMV8 - A64 - 跳转和返回指令

    2023-12-07 02:44:02       29 阅读
  8. 一天一个设计模式---责任链模式

    2023-12-07 02:44:02       33 阅读
  9. koa2项目jwt结合jsonwebtoken进行加密和验签

    2023-12-07 02:44:02       36 阅读
  10. redis的缓存击穿,缓存穿透,缓存雪崩

    2023-12-07 02:44:02       31 阅读