ffmpeg C语音 读取视频帧源码

ops/2024/12/17 14:54:41/

文章目录

    • 前言
    • 主体
      • 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 提供了良好的基础。


http://www.ppmy.cn/ops/142667.html

相关文章

游戏引擎学习第48天

仓库: https://gitee.com/mrxiao_com/2d_game 回顾 我们正在进行碰撞检测的工作,昨天我们几乎完成了一部分代码。由于一些原因,昨天的直播结束时未能完成所有内容。今天我们将继续进行,首先回顾一下之前的进展。我们需要让角色能够正确地与…

list comprehension

python列表推导式(list comprehension) 列表推导式是一种简洁且高效的创建列表的方式。它的基本语法如下: [expression for item in iterable if condition]案例如下,实现对第一列加1的操作。 a[(i,i**0.5) for i in range(0,1…

opencv-python的简单应用

opencv-python的简单应用 图片矫正原理代码输出结果 添加水印原理代码输出结果 识别图片颜色并绘制轮廓原理输出结果 图片矫正 原理 通过选取道图片的角点,再通过得到的点来进行变换得到变换矩阵,最后将图片按照变换矩阵进行变换,得到矫正后…

大模型运用-Prompt Engineering(提示工程)

什么是提示工程 提示工程 提示工程也叫指令工程,涉及到如何设计、优化和管理这些Prompt,以确保AI模型能够准确、高效地执行用户的指令,如:讲个笑话、java写个排序算法等 使用目的 1.获得具体问题的具体结果。(如&…

在线设计平台:Axure新手的在线设计助手

Axure是一款在产品设计、用户体验和交互设计领域广泛使用的强大原型设计工具。它使设计师和产品经理能够迅速构建高保真原型,验证设计和功能,并进行用户测试。结合在线设计平台的协作特性,团队可以更高效地创建、分享和优化原型,加…

数据结构速成

1. 数据结构与算法 2. 顺序表 3. 链表 4. 栈与队列 5. 串 6. 树与二叉树(1) 7. 树与二叉树(2) 8. 图 9. 图的应用 10. 查找 11. 排序(1) 12. 排序(2)

因特网的发展三个阶段

因特网的发展大致分为哪几个阶段,这几个阶段的主要特点 第一个阶段——单个网络到互联网 1969年美国创建第一个分组交换的单个网络ARPANET(单个的分组交换网)所有要连接在ARPANET上的主机都直接与就近的节点交换机相连; 20世纪…

C# 和 go 关于can通信得 整理

在C#中开发CAN(Controller Area Network)通信接口时,确实有一些现成的NuGet包可以简化你的开发工作。这些库通常提供了与CAN硬件接口通信所需的基本功能,如发送和接收CAN消息。下面是一些常用的NuGet包: PCANBasic.NET…