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;
}

你可能感兴趣的:(音视频流媒体,ffmpeg,音视频)