音视频开发—FFmpeg处理流数据的基本概念详解

news2024/11/15 20:01:36

文章目录

    • 多媒体文件的基本概念
    • 相关重要的结构体
    • 操作数据流的基本步骤
      • 1.解复用(Demuxing)
      • 2.获取流(Stream)
      • 3. 读取数据包(Packet)
      • 4. 释放资源(Free Resources)
      • 完整示例

多媒体文件的基本概念

  • 多媒体文件其实是个容器

多媒体文件(如MP4、MKV、AVI等)实际上是一个容器格式。容器的作用是将不同类型的数据(如视频、音频、字幕等)封装在一个文件中,方便管理和播放。每种容器格式都有自己的规范,定义了如何组织和存储这些不同类型的数据。

  • 在容器里有很多流

在多媒体容器文件中,可以包含多个不同的流。每个流代表一种媒体数据,例如视频流、音频流、字幕流等。一个典型的多媒体文件通常至少包含一个视频流和一个音频流,但也可以包含多个视频流、多个音频流和其他类型的流(如字幕、章节信息、元数据等)。

  • 每种流是由不同的编码器编码实现的

每个流的数据在存储之前需要经过编码。编码器(如H.264、AAC、MP3等)将原始的多媒体数据(如未压缩的视频和音频)转换成压缩格式,以减少存储空间和传输带宽。不同的编码器适用于不同类型的数据和使用场景。例如,视频流可能使用H.264编码器,音频流可能使用AAC编码器。

  • 从流中读出的数据叫做包

在流中,数据被分成一个个的数据包(packet)。每个包包含一段编码后的多媒体数据,以及一些元数据(如时间戳、流的标识等)。在解码和播放时,播放器会从容器文件中读取这些数据包,并将其传递给相应的解码器进行解码。

  • 在一个包中包含多个帧

数据包中的内容进一步细分为帧。帧是视频或音频数据的最小单位。例如,在视频流中,每一帧代表一个静止的图像,连续播放这些图像可以形成视频。在音频流中,每一帧代表一段音频采样数据。帧的数量和类型(如关键帧、预测帧等)取决于编码器的工作方式和编码参数。

相关重要的结构体

  • AVFormatContext 结构体

AVFormatContext 是 FFmpeg 中用于描述多媒体文件或流的上下文结构体。它包含了文件格式、输入输出协议、文件信息以及多个流等信息。

  • AVStream 结构体

AVStream 是 FFmpeg 中用于描述多媒体文件中的一个流(如视频流、音频流、字幕流等)的结构体。每个 AVStream 包含了流的编解码信息、时间基准等。

  • AVPacket

AVPacket 是 FFmpeg 中用于描述存储在容器中的多媒体数据包的结构体。数据包是编码后的数据,包含一组帧。

操作数据流的基本步骤

在这里插入图片描述

1.解复用(Demuxing)

解复用是指从多媒体容器中提取出独立的音频、视频和其他流的过程。在FFmpeg中,解复用通过打开文件并解析文件头部信息来实现。

主要步骤

  • 注册所有格式和编解码器: 使用 av_register_all() 注册FFmpeg支持的所有格式和编解码器(FFmpeg 4.x及以前版本需要,FFmpeg 5.0及以后版本不需要)。
  • 打开输入文件: 使用 avformat_open_input() 打开输入文件。
  • 读取文件头部信息: 使用 avformat_find_stream_info() 读取文件头部信息。

示例代码

AVFormatContext *fmt_ctx = NULL;
int ret;

// 注册所有格式和编解码器(FFmpeg 4.x及以前版本需要)
av_register_all();

// 打开输入文件
if ((ret = avformat_open_input(&fmt_ctx, "input.mp4", NULL, NULL)) < 0) {
    av_log(NULL, AV_LOG_ERROR, "Cannot open input file: %s\n", av_err2str(ret));
    return ret;
}

// 读取文件头部信息
if ((ret = avformat_find_stream_info(fmt_ctx, NULL)) < 0) {
    av_log(NULL, AV_LOG_ERROR, "Cannot find stream information: %s\n", av_err2str(ret));
    avformat_close_input(&fmt_ctx);
    return ret;
}

// 打印输入文件的信息
av_dump_format(fmt_ctx, 0, "input.mp4", 0);

2.获取流(Stream)

获取流是指从多媒体文件中提取出各个独立的流,例如音频流和视频流。每个流包含了相关的编解码信息。

主要步骤

  • 查找音频和视频流: 遍历 AVFormatContext 中的流,查找音频和视频流。
  • 打印流信息: 打印每个流的信息。

示例代码

AVStream *video_stream = NULL;
AVStream *audio_stream = NULL;

for (unsigned int i = 0; i < fmt_ctx->nb_streams; i++) {
    AVStream *stream = fmt_ctx->streams[i];
    if (stream->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {
        video_stream = stream;
    } else if (stream->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) {
        audio_stream = stream;
    }
}

if (!video_stream && !audio_stream) {
    av_log(NULL, AV_LOG_ERROR, "No video or audio stream found\n");
    avformat_close_input(&fmt_ctx);
    return -1;
}

3. 读取数据包(Packet)

读取数据包是指从文件中逐个读取编码后的数据包。数据包可以包含音频、视频或其他类型的数据。

主要步骤

  • 初始化数据包: 使用 av_init_packet() 初始化数据包。
  • 读取数据包: 使用 av_read_frame() 读取数据包。
  • 处理数据包: 根据数据包所属的流进行相应处理。
  • 释放数据包: 使用 av_packet_unref() 释放数据包。

示例代码

AVPacket pkt;
av_init_packet(&pkt);
pkt.data = NULL;
pkt.size = 0;

while (av_read_frame(fmt_ctx, &pkt) >= 0) {
    if (pkt.stream_index == video_stream->index) {
        // 处理视频数据包
        av_log(NULL, AV_LOG_INFO, "Video Packet: PTS=%" PRId64 ", DTS=%" PRId64 ", size=%d\n",
               pkt.pts, pkt.dts, pkt.size);
    } else if (pkt.stream_index == audio_stream->index) {
        // 处理音频数据包
        av_log(NULL, AV_LOG_INFO, "Audio Packet: PTS=%" PRId64 ", DTS=%" PRId64 ", size=%d\n",
               pkt.pts, pkt.dts, pkt.size);
    }
    av_packet_unref(&pkt);
}

4. 释放资源(Free Resources)

释放资源是指在完成数据流操作后,释放分配的所有内存和资源,以避免内存泄漏。

主要步骤

  • 释放数据包: 使用 av_packet_unref() 释放每个数据包。
  • 关闭输入文件: 使用 avformat_close_input() 关闭输入文件并释放 AVFormatContext
  • 释放其他资源: 释放任何其他分配的资源。

示例代码

// 释放数据包
av_packet_unref(&pkt);

// 关闭输入文件并释放AVFormatContext
avformat_close_input(&fmt_ctx);

完整示例

#include <libavformat/avformat.h>
#include <libavutil/log.h>

int main(int argc, char *argv[]) {
    AVFormatContext *fmt_ctx = NULL;
    AVPacket pkt;
    AVStream *video_stream = NULL;
    AVStream *audio_stream = NULL;
    int ret;

    if (argc < 2) {
        fprintf(stderr, "Usage: %s <input file>\n", argv[0]);
        return 1;
    }

    // 注册所有格式和编解码器(FFmpeg 4.x及以前版本需要)
    av_register_all();

    // 打开输入文件
    if ((ret = avformat_open_input(&fmt_ctx, argv[1], NULL, NULL)) < 0) {
        av_log(NULL, AV_LOG_ERROR, "Cannot open input file: %s\n", av_err2str(ret));
        return ret;
    }

    // 读取文件头部信息
    if ((ret = avformat_find_stream_info(fmt_ctx, NULL)) < 0) {
        av_log(NULL, AV_LOG_ERROR, "Cannot find stream information: %s\n", av_err2str(ret));
        avformat_close_input(&fmt_ctx);
        return ret;
    }

    // 打印输入文件的信息
    av_dump_format(fmt_ctx, 0, argv[1], 0);

    // 查找音频和视频流
    for (unsigned int i = 0; i < fmt_ctx->nb_streams; i++) {
        AVStream *stream = fmt_ctx->streams[i];
        if (stream->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {
            video_stream = stream;
        } else if (stream->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) {
            audio_stream = stream;
        }
    }

    if (!video_stream && !audio_stream) {
        av_log(NULL, AV_LOG_ERROR, "No video or audio stream found\n");
        avformat_close_input(&fmt_ctx);
        return -1;
    }

    // 初始化数据包
    av_init_packet(&pkt);
    pkt.data = NULL;
    pkt.size = 0;

    // 读取数据包
    while (av_read_frame(fmt_ctx, &pkt) >= 0) {
        if (pkt.stream_index == video_stream->index) {
            // 处理视频数据包
            av_log(NULL, AV_LOG_INFO, "Video Packet: PTS=%" PRId64 ", DTS=%" PRId64 ", size=%d\n",
                   pkt.pts, pkt.dts, pkt.size);
        } else if (pkt.stream_index == audio_stream->index) {
            // 处理音频数据包
            av_log(NULL, AV_LOG_INFO, "Audio Packet: PTS=%" PRId64 ", DTS=%" PRId64 ", size=%d\n",
                   pkt.pts, pkt.dts, pkt.size);
        }
        av_packet_unref(&pkt);
    }

    // 关闭输入文件并释放AVFormatContext
    avformat_close_input(&fmt_ctx);

    return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1909722.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

聚焦云技术,探讨 AGI 时代的云原生数据计算系统

6月22日&#xff0c;开源中国社区在上海举办了 OSC 源创会活动&#xff0c;本期活动以「云技术」为主题&#xff0c;邀请了来自华为 openEuler、字节跳动、AutoMQ 等厂商的技术大咖进行分享&#xff0c;拓数派作为云原生数据计算领域的引领者&#xff0c;受邀参与了本次活动&am…

智慧城市可视化页面怎么做?免费可视化工具可以帮你

智慧城市是一个综合性的概念&#xff0c;广泛应用于各个领域&#xff0c;如基础设施建设、信息化应用、产业经济发展、市民生活品质等。 可视化页面的制作也是一个综合性的过程&#xff0c;需要确定展示内容、数据收集与处理、设计可视化元素等多个环节紧密配合。 1. 明确展示…

MySQL Innodb存储引擎中,当页默认的大小是16K时,页中最多存放多少行的记录?

1、题目引入 Innodb存储引擎是面向行的(row-oriented)&#xff0c;也就是说数据的存放按行进行&#xff0c;每页存放的行记录是有硬性定义的&#xff0c;当页默认的大小是16K时&#xff0c;页中最多存放多少行的记录&#xff1f; A、1600 行B、8192 行C、16383 行D、7992 行 …

occ geo

随笔 - 12 文章 - 18 评论 - 117 阅读 - 13万 opencascade造型引擎功能介绍 现今的CAD 系统大多通常都基于CAD 系统提供的二次开发包&#xff0c;用户根据要求定制符合自己要求的功能。AutoCAD就提供了AutoLISP、ADS 等都是比较通用的开发工具包。UG 也提供了多种二次开发…

温州海经区管委会主任、乐清市委书记徐建兵带队莅临麒麟信安调研

7月8日上午&#xff0c;温州海经区管委会主任、乐清市委书记徐建兵&#xff0c;乐清市委常委、副市长叶序锋&#xff0c;乐清市委办主任郑志坚一行莅临麒麟信安调研&#xff0c;乐清市投资促进服务中心及湖南省浙江总商会相关人员陪同参加。麒麟信安董事长杨涛、总裁刘文清热情…

grafana数据展示

目录 一、安装步骤 二、如何添加喜欢的界面 三、自动添加注册客户端主机 一、安装步骤 启动成功后 可以查看端口3000是否启动 如果启动了就在浏览器输入IP地址&#xff1a;3000 账号密码默认是admin 然后点击 log in 第一次会让你修改密码 根据自定义密码然后就能登录到界面…

机器学习笔记:初始化0的问题

1 前言 假设我们有这样的两个模型&#xff1a; 第一个是逻辑回归 第二个是神经网络 他们的损失函数都是交叉熵 sigmoid函数的导数&#xff1a; 他们能不能用0初始化呢&#xff1f; 2 逻辑回归 2.1 求偏导 2.1.1 结论 2.1.2 L对a的偏导 2.1.3 对w1&#xff0c;w2求偏导 w2同…

k8s record 20240708

一、PaaS 云平台 web界面 资源利用查看 Rancher 5台 CPU 4核 Mem 4g 100g的机器 映射的目录是指docker重启后&#xff0c;数据还在 Rancher可以创建集群也可以托管已有集群 先docker 部署 Rancher&#xff0c;然后通过 Rancher 部署 k8s 想使用 kubectl 还要yum install 安…

中国AI大模型论文数量全球第一,清华力压麻省理工、斯坦福

论文是研究新技术、开发新产品获取“图纸”的重要途径之一&#xff0c;OpenAI的研究人员正是借鉴了Transformer的论文&#xff08;被引用超过9万次&#xff09;&#xff0c;才开发出了对全球各行业影响巨大的产品ChatGPT。 而论文的数量、通过率和被引用次数是衡量一个国家科技…

电脑文件夹怎么设置密码?让你的文件更安全!

在日常使用电脑的过程中&#xff0c;我们常常会有一些需要保护的个人文件或资料。为了防止这些文件被他人未经授权访问&#xff0c;对重要文件夹设置密码是一种有效的保护措施&#xff0c;可是电脑文件夹怎么设置密码呢&#xff1f;本文将介绍2种简单有效的方法帮助您为电脑文件…

红酒与运动后的恢复:健康的双重助力

在繁忙的都市生活中&#xff0c;运动已成为许多人追求健康与活力的方式。当汗水洒落&#xff0c;肌肉得到锻炼&#xff0c;一场酣畅淋漓的运动后&#xff0c;身心仿佛得到了洗礼。而在这份宁静与满足之余&#xff0c;你是否想过&#xff0c;一杯优雅的红酒也能为你的运动后恢复…

以SGET协会OSM标准首创有662引脚的OSM模组——凌华智能引领嵌入式运算市场

在可焊接的45 x 45mm尺寸上提升功率 开启嵌入式运算发展的新时代 摘要&#xff1a; 1.开放式标准模块(OSM™)&#xff0c;最大尺寸仅45 x 45mm&#xff0c;采用零开销的模块化系统简化生产&#xff0c;并提供662个引脚以增强小型化和物联网应用。 2.凌华智能提供基于NXP i.M…

二叉树中的最大路径和(Java版)

二叉树中的 路径 被定义为一条节点序列&#xff0c;序列中每对相邻节点之间都存在一条边。同一个节点在一条路径序列中 至多出现一次 。该路径 至少包含一个 节点&#xff0c;且不一定经过根节点。 路径和 是路径中各节点值的总和。 给你一个二叉树的根节点 root &#xff0c…

AI自动生成PPT哪个软件好?高效制作PPT就用这4个

学生时期做各种小组作业需要做PPT&#xff0c;毕业后开始上班每周大大小小的各种会议和汇报&#xff0c;也少不了PPT的折磨。 倘若你也刚好有这种烦恼&#xff0c;那么不妨试试下面我给大家安利的这4款AI自动生成PPT免费软件~保准你用上以后可不再为PPT制作而发愁&#xff01;…

面向过程编程详解

目录 前言1. 面向过程编程的定义2. 面向过程编程的特点2.1 过程和函数2.2 顺序执行2.3 全局变量2.4 控制结构 3. 面向过程编程的应用场景3.1 系统级编程3.2 科学计算3.3 小型项目 4. 面向过程编程的优缺点4.1 优点4.2 缺点 5. 代表性的编程语言5.1 C语言5.2 Pascal5.3 Fortran …

【LLM大模型】开发基于云的RAG应用,使用开源 LLM

检索增强生成 (RAG)通常用于开发定制的 AI 应用程序&#xff0c;包括 聊天机器人、推荐系统和其他个性化工具。该系统利用向量数据库和 大型语言模型 (LLM)的优势来提供高质量的结果。 为任何 RAG 模型选择合适的 LLM 非常重要&#xff0c;需要考虑成本、隐私问题和可扩展性等…

仿写SpringMVC

1.创建简单的注解 1.1 Controller package com.heaboy.annotation;import java.lang.annotation.*;Documented Retention(RetentionPolicy.RUNTIME) Target(ElementType.TYPE) public interface Controller { } 1.2 RequestMapping package com.heaboy.annotation;import …

喜讯|华院钢铁行业大模型入选“2024全国企业新质生产力赋能典型案例”

7月2日&#xff0c;由中国科学院主管、科学出版社主办的商业周刊《互联网周刊》&#xff08;CIW&#xff09;联合德本咨询&#xff08;DBC&#xff09;、中国社会科学院信息化研究中心&#xff08;CIS&#xff09;发布了“2024全国企业新质生产力赋能典型案例”。华院计算技术&…

基于FPGA的千兆以太网设计(1)----大白话解释什么是以太网

1、什么是以太网? 还记得初学以太网的时候,我就被一大堆专业名词给整懵了:什么以太网,互联网,MAC,IP,局域网,万维网,网络分层模型等等等等。慢着!我学的不是以太网吗?怎么出来这么一大堆东西? 啊!以太网究竟是什么?别急,我接下来就尽量用通俗的大白话来给你解释…

香港优才计划多少分获批成功率高?一文看懂各分数段获批情况!

有留意香港优才计划的朋友&#xff0c;应该都了解过&#xff0c;申请优才计划采用打分制&#xff0c;得分多少与最终获批有密不可分的关系。但有一点要提前清楚&#xff0c;申请优才不是得分越高就一定能获批&#xff0c;也不是得分低就一定没希望。 香港优才计划能否获批成功…