FFMPEG读取关键帧(c++)
设法使用 av_read_frame 获得所有框架,其中逐帧地顺序读取,再用AVFrame-> key_frame判断关键帧,将其进行保存。
主要提取代码如下:
//获得帧图大小
PictureSize = avpicture_get_size(AV_PIX_FMT_BGR24, pCodecCtx->width, pCodecCtx->height);
buf = (uint8_t*)av_malloc(PictureSize);
if (buf == NULL) {
printf("av malloc failed!\n");
system("pause");
exit(1);
}
avpicture_fill((AVPicture *)pFrameRGB, buf, AV_PIX_FMT_BGR24, pCodecCtx->width, pCodecCtx->height);
//设置图像转换上下文
pSwsCtx = sws_getContext(pCodecCtx->width, pCodecCtx->height, pCodecCtx->pix_fmt, pCodecCtx->width, pCodecCtx->height, AV_PIX_FMT_BGR24, SWS_BICUBIC, NULL, NULL, NULL);
i = 0;
while (av_read_frame(pFormatCtx, &packet) >= 0) {
if (packet.stream_index == videoStream) {
//解码
avcodec_decode_video2(pCodecCtx, pFrame, &frameFinished, &packet);
if (frameFinished) {
if (pFrame->key_frame) {
//转换图像格式,将解压出来的YUV420P的图像转换为BRG24的图像
sws_scale(pSwsCtx, (const uint8_t* const*)pFrame->data, pFrame->linesize, 0, pCodecCtx->height, pFrameRGB->data, pFrameRGB->linesize);
//保存为bmp图
SaveAsBMP(pFrameRGB, pCodecCtx->width, pCodecCtx->height, i, 24);
i++;
}
}
av_free_packet(&packet);
}
}
注意① ffmpeg 中的函数 av_read_frame 是用来完成解封装的过程,它会从码流里面提取每一个音频、视频帧,它使用了结构体 AVPacket 来记录每一帧的信息。