介绍
FFmpeg制作视频缩略图思路以及图像转换接口的具体分析,已经录制了讲解视频放到了B站可以移步观看【FFmpeg视频缩略图与图像转换分析】 https://www.bilibili.com/video/BV1pG411i7rH/?share_source=copy_web&vd_source=e89a0faea91d9f4d36966a27ca0bd3e4,这里直接上代码。
核心代码
//生成视频缩略图
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;
}
原文地址:https://blog.csdn.net/T__zxt/article/details/134723242
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.7code.cn/show_29276.html
如若内容造成侵权/违法违规/事实不符,请联系代码007邮箱:suwngjj01@126.com进行投诉反馈,一经查实,立即删除!
声明:本站所有文章,如无特殊说明或标注,均为本站原创发布。任何个人或组织,在未征得本站同意时,禁止复制、盗用、采集、发布本站内容到任何网站、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理。