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

news/2024/9/13 23:50:40/ 标签: 音视频, ffmpeg

文章目录

    • 多媒体文件的基本概念
    • 相关重要的结构体
    • 操作数据流的基本步骤
      • 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);}// 关闭输入文件并释放AVFormatContextavformat_close_input(&fmt_ctx);return 0;
}

http://www.ppmy.cn/news/1475493.html

相关文章

【自动驾驶/机器人面试C++八股精选】专栏介绍

目录 一、自动驾驶和机器人技术发展前景二、C在自动驾驶和机器人领域的地位三、专栏介绍四、订阅需知 一、自动驾驶和机器人技术发展前景 随着人工智能、机器学习、传感器技术和计算能力的进步&#xff0c;自动驾驶和机器人的技术水平不断提升&#xff0c;使得它们更加智能、可…

js项目生产环境中移除 console

1、terser-webpack-plugin webpack 构建的项目中安装使用 安装&#xff1a; npm install terser-webpack-plugin --save-dev 配置 在webpack.config.js文件中 new TerserPlugin({terserOptions: {output: {comments: false, // 去除注释},warnings: false, // 去除黄色警告,co…

Python酷库之旅-第三方库Pandas(021)

目录 一、用法精讲 52、pandas.from_dummies函数 52-1、语法 52-2、参数 52-3、功能 52-4、返回值 52-5、说明 52-6、用法 52-6-1、数据准备 52-6-2、代码示例 52-6-3、结果输出 53、pandas.factorize函数 53-1、语法 53-2、参数 53-3、功能 53-4、返回值 53-…

在InternStudio上创建一台GPU服务器

填写配置 创建完成 ssh连接&#xff0c;并测试常用指令 查看开发机信息 查看gpu信息 创建conda环境 跑个test

康谋分享 | 自动驾驶联合仿真——功能模型接口FMI(三)

在之前的两篇文章中&#xff08;文末往期回顾中可查看&#xff09;&#xff0c;我们主要介绍了功能模型接口FMI的主要组成部分和一些使用场景&#xff0c;今天就以康谋自动驾驶仿真软件aiSim为例&#xff0c;来展示一下如何建立一个FMU并实现基于UDP和FMI联合仿真&#xff08;c…

GitHub+Picgo图片上传

Picgo下载&#xff0c;修改安装路径&#xff0c;其他一路下一步&#xff01; 地址 注册GitHub&#xff0c;注册过程不详细展开&#xff0c;不会的百度一下 地址 新建GitHub仓库存放图片 生成Token令牌 点击头像&#xff0c;点击Settings 滑到最后 过期时间&#xff1a;No expi…

MyBatisPlus实现增删改查

文章目录 MyBatisPlus实现增删改查基本操作分页查询配置分页插件 MyBatisPlus实现增删改查 实体类GkUser package com.geekmice.springbootselfexercise.entity;import com.baomidou.mybatisplus.annotation.IdType; import com.baomidou.mybatisplus.annotation.TableField;…

uniapp 初始学习1

uni-app代码基本包括js,vue,css.在app端支持原生渲染nvue&#xff0c;可编译的kotlin和swift 掌握js就可以进行不同应用的开发 页面文件遵循 Vue 单文件组件 (SFC) 规范&#xff0c;即每个页面是一个.vue文件 .vue文件是一个自定义的文件类型&#xff0c;用类HTML语法描述一…

2024年中国网络安全市场全景图 -百度下载

是自2018年开始&#xff0c;数说安全发布的第七版全景图。 企业数智化转型加速已经促使网络安全成为全社会关注的焦点&#xff0c;在网络安全边界不断扩大&#xff0c;新理念、新产品、新技术不断融合发展的进程中&#xff0c;数说安全始终秉承科学的方法论&#xff0c;以遵循…

02:项目二:感应开关盖垃圾桶

感应开关盖垃圾桶 1、PWM开发SG901.1、怎样通过C51单片机输出PWM波&#xff1f;1.2、通过定时器输出PWM波来控制SG90 2、超声波测距模块的使用3、感应开关盖垃圾桶 需要材料&#xff1a; 1、SG90舵机模块 2、HC-SR04超声波模块 3、震动传感器 4、蜂鸣器 5、若干杜邦线 1、PWM开…

【系统架构设计】操作系统(一)

操作系统&#xff08;一&#xff09; 操作系统的类型和结构操作系统基本原理进程管理进程三态模型挂起状态进程互斥 / 进程同步前趋图进程调度死锁 存储管理设备管理文件管理作业管理 操作系统原理的关键在于“一个观点、两条线索”&#xff1a;一个观点是以资源管理的观点来定…

SpringBoot实用篇

一、运维实用篇 1.工程的打包与运行 ①对SpringBoot项目打包&#xff08;执行Maven构建指令package&#xff09; ②运行项目&#xff08;执行启动指令&#xff09; java -jar 工程打包的文件名.jar jar支持命令行启动需要依赖maven插件支持&#xff0c;请确认打包时是否具有…

集成excel工具:自定义导入回调监听器、自定义类型转换器、web中的读

文章目录 I 封装导入导出1.1 定义工具类1.2 自定义读回调监听器: 回调业务层处理导入数据1.3 定义文件导入上下文1.4 定义回调协议II 自定义转换器2.1 自定义枚举转换器2.2 日期转换器2.3 时间、日期、月份之间的互转2.4 LongConverterIII web中的读3.1 使用默认回调监听器3.2…

Python爬虫技术从去哪儿网获取旅游数据,对攻略进行可视化分析,提供全面的旅游攻略和个性化的出行建议

背景 随着信息技术的快速发展和互联网的普及&#xff0c;旅游行业也迎来了数字化和智能化的变革。去哪儿网作为中国领先的在线旅游平台之一&#xff0c;提供了丰富的旅游产品和服务&#xff0c;涵盖了机票、酒店、旅游度假等各个方面。用户通过去哪儿网可以方便地查询、预订和…

Adobe Photoshop 2024(Beta) v 25.11(2675) 旭日 免安装版

Adobe Photoshop 2024(Beta) v 25.11(2675) 旭日 免安装版&#xff0c;直接下载解压即可使用&#xff0c;感兴趣的同学可以下载体验。 文件下载:Photoshop 2024(Beta) .zip 安装报错解决方法 1、由于找不到msvcp140 dll无法继续执行 一、重新注册 msvcp140.dll 运行库文件&…

语言模型演进:从NLP到LLM的跨越之旅

在人工智能的浩瀚宇宙中&#xff0c;自然语言处理&#xff08;NLP&#xff09;一直是一个充满挑战和机遇的领域。随着技术的发展&#xff0c;我们见证了从传统规则到统计机器学习&#xff0c;再到深度学习和预训练模型的演进。如今&#xff0c;我们站在了大型语言模型&#xff…

【持续集成_06课_Jenkins高级pipeline应用】

一、创建项目选择pipeline的风格 它主要是以脚本&#xff08;它自己的语言&#xff09;的方式进行运行&#xff0c;一般由运维去做的事情&#xff0c;作为测试而言。了解即可。 --- 体现形式全部通过脚本去实现&#xff1a;执行之前&#xff08;拉取代码&#xff09;执行&…

C++ | Leetcode C++题解之第232题用栈实现队列

题目&#xff1a; 题解&#xff1a; class MyQueue { private:stack<int> inStack, outStack;void in2out() {while (!inStack.empty()) {outStack.push(inStack.top());inStack.pop();}}public:MyQueue() {}void push(int x) {inStack.push(x);}int pop() {if (outStac…

HttpClient调用SpringBoot项目的文件上传接口实现文件上传

1.导入httpclient的jar包 这里导入了httpclient、httpmime11 <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache.org/POM/4.0.0" xmlns:xsi"http://www.w3.org/2001/XMLSchema-instance"xsi:sch…

【面试题】Golang 之Channel底层原理 (第三篇)

目录 1.常见channel三大坑&#xff1a;死锁、内存泄漏、panic 1.死锁 1.只有生产者&#xff0c;没有消费者&#xff0c;或者反过来 2 生产者和消费者出现在同一个 goroutine 中 3 buffered channel 已满&#xff0c;且在同一个goroutine中 2.内存泄露 1 如何实现 gorout…