欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 新闻 > 焦点 > ffmpeg C语音 读取视频帧源码

ffmpeg C语音 读取视频帧源码

2024/12/21 22:45:05 来源:https://blog.csdn.net/m0_62599305/article/details/144468778  浏览:    关键词:ffmpeg C语音 读取视频帧源码

文章目录

    • 前言
    • 主体
      • 1. `AVPacket`
        • 作用:
        • 相关字段:
        • 作用场景:
      • 2. `av_read_frame`
        • 函数原型:
        • 作用:
        • 参数:
        • 返回值:
        • 相关结构体:
      • 3. `av_packet_unref`
        • 函数原型:
        • 作用:
        • 参数:
        • 返回值:
      • 4. `AVRational`
        • 作用:
        • 相关字段:
        • 作用场景:
      • 5. `r2d(AVRational r)`
        • 作用:
        • 代码实现:
        • 参数:
        • 返回值:
    • 代码分析
      • 打开视频文件
      • 读取视频帧
      • 关闭视频文件
    • 总结


前言

FFmpeg 是一个非常强大的音视频处理库,广泛应用于多媒体流的处理与转换。在本篇文章中,我们将通过一个 C++/Qt 示例,展示如何使用 FFmpeg 打开视频文件,读取视频帧并提取时间戳。文章会重点介绍涉及到的 FFmpeg 函数和结构体,帮助你了解 FFmpeg 的基本用法。

主体

1. AVPacket

作用:

AVPacket 结构体用于存储一个编码后音视频数据包。每个音视频流的帧数据都会以包的形式存在,AVPacket 结构体就存储了这些信息,包括了数据包的时间戳、数据内容等。

相关字段:
  • pts:该字段存储解码时间戳(以流的时间基准单位表示)。它用于标识数据包的时间点。
  • dts:解码时间戳,通常与 PTS 一致,但对于 B 帧可能不同。
  • data:存储实际的音视频数据(例如,视频帧或音频帧)。
  • sizedata 中的数据大小。
作用场景:

在视频解码和播放时,每一帧的音视频数据会被封装成一个 AVPacket 对象。我们可以通过读取这些数据包来获取视频的每一帧,并通过时间戳等信息进行同步。

2. av_read_frame

函数原型:
int av_read_frame(AVFormatContext *s, AVPacket *pkt);
作用:

av_read_frame 函数从媒体文件中读取一帧数据,并将数据封装在 AVPacket 中。此函数对于读取视频或音频的流数据是至关重要的。它会从输入流中读取音视频数据包,直到所有数据都被处理完。

参数:
  • s:指向 AVFormatContext 的指针,表示已打开的媒体文件。
  • pkt:指向 AVPacket 的指针,用于存储读取到的数据包。
返回值:

成功时返回 0,失败时返回负值。

相关结构体:
  • AVFormatContext:表示已打开的媒体文件的上下文。
  • AVPacket:表示存储在数据包中的音视频帧数据。

3. av_packet_unref

函数原型:
void av_packet_unref(AVPacket *pkt);
作用:

av_packet_unref 用于释放 AVPacket 中的内存,清除数据包中的内容。每当我们使用完 AVPacket 后,都应该调用该函数进行内存清理,避免内存泄漏。

参数:
  • pkt:指向 AVPacket 结构体的指针,表示需要清理的 AVPacket
返回值:

4. AVRational

作用:

AVRational 是 FFmpeg 中用于表示有理数的结构体。在视频处理中,AVRational 结构体经常用来表示时间戳与流时间基之间的关系。

相关字段:
  • num:分子。
  • den:分母。
作用场景:

在 FFmpeg 中,许多与时间相关的计算(如帧率、时间基准等)都使用 AVRational 结构体来进行表示和计算。例如,视频的时间基(time_base)就是一个 AVRational,表示每个时间单位的长度。

5. r2d(AVRational r)

作用:

r2d 是一个辅助函数,将 AVRational 转换为 double 类型。它通过将 AVRational 的分子除以分母,返回一个浮动数值。

代码实现:
static double r2d(AVRational r)
{return r.num == 0 || r.den == 0 ? 0. : (double)r.num / (double)r.den;
}
参数:
  • rAVRational 结构体,表示一个有理数。
返回值:

返回 AVRational 的值,转换为 double 类型。

代码分析

打开视频文件

av_register_all();
char *path = "video.mp4";
AVFormatContext *ic = NULL;
int re = avformat_open_input(&ic, path, 0, 0);
if (re != 0)
{char buf[1024] = { 0 };av_strerror(re, buf, sizeof(buf));printf("open %s failed: %s\n", path, buf);getchar();return -1;
}

首先,我们调用 av_register_all() 来初始化 FFmpeg 库。接着,通过 avformat_open_input 打开视频文件。如果打开失败,程序会输出错误信息并退出。

读取视频帧

int totalSec = ic->duration / AV_TIME_BASE;
printf("file totalSec is %d-%d\n", totalSec / 60, totalSec % 60);
for (;;)
{AVPacket pkt;re = av_read_frame(ic, &pkt);if (re != 0) break;int pts = pkt.pts * r2d(ic->streams[pkt.stream_index]->time_base) * 1000;printf("pts = %d\n", pts);av_packet_unref(&pkt);
}

接下来,我们计算视频文件的总时长。通过 av_read_frame 函数,我们逐帧读取视频文件的数据包(AVPacket)。每读取一帧,我们会计算并打印该帧的时间戳(PTS)。使用 r2d 函数将 AVRational 转换为 double 类型后,再乘以 1000 转换为毫秒。最后,调用 av_packet_unref 清除数据包。

关闭视频文件

avformat_close_input(&ic);

读取完所有帧后,我们调用 avformat_close_input 来关闭文件并释放相关资源。

总结

在本篇文章中,我们介绍了如何通过 FFmpeg 打开视频文件,读取视频数据包,并提取时间戳。关键的 FFmpeg 函数如 av_read_frameav_packet_unref 和结构体如 AVPacketAVFormatContext 在此过程中扮演了重要角色。通过这个示例,我们展示了如何结合 FFmpeg 和 Qt 进行音视频处理与播放,并且理解了 FFmpeg 内部的处理流程。这为进一步深入了解 FFmpeg 提供了良好的基础。

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com