【Android FFMPEG 开发】FFMPEG 读取音视频流中的数据到 AVPacket ( 初始化 AVPacket 数据 | 读取 AVPacket )

简介: 【Android FFMPEG 开发】FFMPEG 读取音视频流中的数据到 AVPacket ( 初始化 AVPacket 数据 | 读取 AVPacket )

文章目录

I . FFMPEG 获取 AVPacket 数据前置操作

II . FFMPEG 获取 AVPacket 数据流程

III . FFMPEG AVPacket 结构体

IV . AVPacket 数据读取流程

V . FFMPEG 初始化 AVPacket 数据包 av_packet_alloc ( )

VI . FFMPEG 读取 AVPacket 数据 av_read_frame ( )

VII . FFMPEG 获取 AVPacket 数据流程 代码示例



I . FFMPEG 获取 AVPacket 数据前置操作


FFMPEG 获取 AVPacket 数据前置操作 :



① FFMPEG 初始化 : 参考博客 【Android FFMPEG 开发】FFMPEG 初始化 ( 网络初始化 | 打开音视频 | 查找音视频流 )


② FFMPEG 获取 AVStream 音视频流 : 参考博客 【Android FFMPEG 开发】FFMPEG 获取 AVStream 音视频流 ( AVFormatContext 结构体 | 获取音视频流信息 | 获取音视频流个数 | 获取音视频流 )


③ FFMPEG 获取 AVCodec 编解码器 : 参考博客 【Android FFMPEG 开发】FFMPEG 获取编解码器 ( 获取编解码参数 | 查找编解码器 | 获取编解码器上下文 | 设置上下文参数 | 打开编解码器 )




II . FFMPEG 获取 AVPacket 数据流程


FFMPEG 获取 AVPacket 数据流程 :



〇 前置操作 : FFMPEG 环境初始化 , 获取 AVStream 音视频流 , 获取 AVCodec 编解码器 , 然后才能进行下面的操作 ;



① 初始化 AVPacket 空数据包 : av_packet_alloc ( )


AVPacket *avPacket = av_packet_alloc();



② 读取 AVPacket 数据 : av_read_frame ( AVFormatContext *s , AVPacket *pkt )


int read_frame_result = av_read_frame(formatContext, avPacket);




III . FFMPEG AVPacket 结构体


1 . AVPacket 结构体 : 该结构体用于封装被编码压缩的数据 , 不能直接使用 , 需要解码后才能进行音频视频播放 ;


typedef struct AVPacket {
  ...
} AVPacket;



2 . AVPacket 存储数据 : AVPacket 存放编码后的音视频数据的 , 获取该数据包后 , 需要对该数据进行解码 , 解码后将数据存放在 AVFrame 中 ;



3 . 编码前后数据存放 : AVPacket 是编码后的数据 , AVFrame 是编码前的数据 ;




IV . AVPacket 数据读取流程


1 . 读取音视频流数据到 AVPacket 中 : 首先要在外部声明 AVPacket * 结构体指针 , 并为其初始化 , 然后调用 av_read_frame ( ) 方法 , 将已经初始化好内存的 AVPacket * 结构体指针 传给上述方法 , FFMPEG 将在 av_read_frame ( ) 方法中读取数据 , 并存储到堆内存中的 AVPacket 结构体中 ;



2 . AVPacket 的内存初始化和释放 :



① AVPacket 初始化 : 调用 av_packet_alloc ( ) 方法初始化内存 ;


② AVPacket 释放 : 调用 av_packet_free ( ) 释放内存 ;




V . FFMPEG 初始化 AVPacket 数据包 av_packet_alloc ( )


1 . av_packet_alloc ( ) 函数原型 : 在堆内存中为 AVPacket 分配内存 , 并为 AVPacket 结构体各个字段设置默认值 ;


① 返回值 : 返回一个 AVPacket * 结构体指针 , 如果内存分配失败 , 就会返回 NULL ;


/**
 * Allocate an AVPacket and set its fields to default values.  The resulting
 * struct must be freed using av_packet_free().
 *
 * @return An AVPacket filled with default values or NULL on failure.
 *
 * @note this only allocates the AVPacket itself, not the data buffers. Those
 * must be allocated through other means such as av_new_packet.
 *
 * @see av_new_packet
 */
AVPacket *av_packet_alloc(void);


2 . 代码示例 :


//读取数据包
// AVPacket 存放编码后的音视频数据的 , 获取该数据包后 , 需要对该数据进行解码 , 解码后将数据存放在 AVFrame 中
// AVPacket 是编码后的数据 , AVFrame 是编码前的数据
//创建 AVPacket 空数据包
AVPacket *avPacket = av_packet_alloc();



VI . FFMPEG 读取 AVPacket 数据 av_read_frame ( )


1 . av_read_frame ( ) 函数原型 : 获取音视频流的下一帧数据 ;



① AVFormatContext *s 参数 : 该参数中存储了音视频流格式相关信息 , 该参数是在之前使用 avformat_find_stream_info ( ) 方法获取的 ;


② AVPacket *pkt 参数 : 传入该结构体指针 , 在方法中会按照 AVFormatContext *s 信息读取一帧音视频数据 , 并将该数据存储到 AVPacket 结构体中 ;


③ int 返回值 : 返回 0 代表读取一帧数据 ( 音频 / 视频 ) 成功 , < 0 说明获取数据失败 ;


/**
 * Return the next frame of a stream.
 * This function returns what is stored in the file, and does not validate
 * that what is there are valid frames for the decoder. It will split what is
 * stored in the file into frames and return one for each call. It will not
 * omit invalid data between valid frames so as to give the decoder the maximum
 * information possible for decoding.
 *
 * If pkt->buf is NULL, then the packet is valid until the next
 * av_read_frame() or until avformat_close_input(). Otherwise the packet
 * is valid indefinitely. In both cases the packet must be freed with
 * av_packet_unref when it is no longer needed. For video, the packet contains
 * exactly one frame. For audio, it contains an integer number of frames if each
 * frame has a known fixed size (e.g. PCM or ADPCM data). If the audio frames
 * have a variable size (e.g. MPEG audio), then it contains one frame.
 *
 * pkt->pts, pkt->dts and pkt->duration are always set to correct
 * values in AVStream.time_base units (and guessed if the format cannot
 * provide them). pkt->pts can be AV_NOPTS_VALUE if the video format
 * has B-frames, so it is better to rely on pkt->dts if you do not
 * decompress the payload.
 *
 * @return 0 if OK, < 0 on error or end of file
 */
int av_read_frame(AVFormatContext *s, AVPacket *pkt);



2 . FFMPEG 读取 AVPacket 数据 代码示例 :


/*
    读取数据包 , 并存储到 AVPacket 数据包中
    参数分析 : 一维指针 与 二维指针 参数分析
      ① 注意 : 第二个参数是 AVPacket * 类型的 , 那么传入 AVPacket *avPacket 变量
            不能修改 avPacket 指针的指向 , 即该指针指向的结构体不能改变
            只能修改 avPacket 指向的结构体中的元素的值
              因此 , 传入的 avPacket 结构体指针必须先进行初始化 , 然后再传入
                  av_read_frame 函数内 , 没有修改 AVPacket *avPacket 的值 , 但是修改了结构体中元素的值
      ② 与此相对应的是 avformat_open_input 方法 , 传入 AVFormatContext ** 二维指针
          传入的的 AVFormatContext ** 是没有经过初始化的 , 连内存都没有分配
          在 avformat_open_input 方法中创建并初始化 AVFormatContext * 结构体指针
          然后将该指针地址赋值给 AVFormatContext **
              avformat_open_input 函数内修改了 AVFormatContext ** 参数的值
    返回值 0 说明读取成功 , 小于 0 说明读取失败 , 或者 读取完毕
 */
int read_frame_result = av_read_frame(formatContext, avPacket);



VII . FFMPEG 获取 AVPacket 数据流程 代码示例


//读取数据包
// AVPacket 存放编码后的音视频数据的 , 获取该数据包后 , 需要对该数据进行解码 , 解码后将数据存放在 AVFrame 中
// AVPacket 是编码后的数据 , AVFrame 是编码前的数据
//创建 AVPacket 空数据包
AVPacket *avPacket = av_packet_alloc();
/*
    读取数据包 , 并存储到 AVPacket 数据包中
    参数分析 : 一维指针 与 二维指针 参数分析
      ① 注意 : 第二个参数是 AVPacket * 类型的 , 那么传入 AVPacket *avPacket 变量
            不能修改 avPacket 指针的指向 , 即该指针指向的结构体不能改变
            只能修改 avPacket 指向的结构体中的元素的值
              因此 , 传入的 avPacket 结构体指针必须先进行初始化 , 然后再传入
                  av_read_frame 函数内 , 没有修改 AVPacket *avPacket 的值 , 但是修改了结构体中元素的值
      ② 与此相对应的是 avformat_open_input 方法 , 传入 AVFormatContext ** 二维指针
          传入的的 AVFormatContext ** 是没有经过初始化的 , 连内存都没有分配
          在 avformat_open_input 方法中创建并初始化 AVFormatContext * 结构体指针
          然后将该指针地址赋值给 AVFormatContext **
              avformat_open_input 函数内修改了 AVFormatContext ** 参数的值
    返回值 0 说明读取成功 , 小于 0 说明读取失败 , 或者 读取完毕
 */
int read_frame_result = av_read_frame(formatContext, avPacket);


目录
相关文章
|
10天前
|
开发工具 Android开发
X Android SDK file not found: adb.安卓开发常见问题-Android SDK 缺少 `adb`(Android Debug Bridge)-优雅草卓伊凡
X Android SDK file not found: adb.安卓开发常见问题-Android SDK 缺少 `adb`(Android Debug Bridge)-优雅草卓伊凡
150 11
X Android SDK file not found: adb.安卓开发常见问题-Android SDK 缺少 `adb`(Android Debug Bridge)-优雅草卓伊凡
|
20天前
|
Java 开发工具 Maven
【01】完整的安卓二次商业实战-详细的初级步骤同步项目和gradle配置以及开发思路-优雅草伊凡
【01】完整的安卓二次商业实战-详细的初级步骤同步项目和gradle配置以及开发思路-优雅草伊凡
79 6
|
3月前
|
安全 数据库 Android开发
在Android开发中实现两个Intent跳转及数据交换的方法
总结上述内容,在Android开发中,Intent不仅是活动跳转的桥梁,也是两个活动之间进行数据交换的媒介。运用Intent传递数据时需注意数据类型、传输大小限制以及安全性问题的处理,以确保应用的健壯性和安全性。
170 11
|
3月前
|
移动开发 Java 编译器
Kotlin与Jetpack Compose:Android开发生态的演进与架构思考
本文从资深Android工程师视角深入分析Kotlin与Jetpack Compose在Android系统中的技术定位。Kotlin通过空安全、协程等特性解决了Java在移动开发中的痛点,成为Android官方首选语言。Jetpack Compose则引入声明式UI范式,通过重组机制实现高效UI更新。两者结合不仅提升开发效率,更为跨平台战略和现代架构模式提供技术基础,代表了Android开发生态的根本性演进。
112 0
|
4月前
|
安全 Java Android开发
为什么大厂要求安卓开发者掌握Kotlin和Jetpack?深度解析现代Android开发生态优雅草卓伊凡
为什么大厂要求安卓开发者掌握Kotlin和Jetpack?深度解析现代Android开发生态优雅草卓伊凡
183 0
为什么大厂要求安卓开发者掌握Kotlin和Jetpack?深度解析现代Android开发生态优雅草卓伊凡
|
12月前
|
Linux 开发工具 Android开发
FFmpeg开发笔记(六十)使用国产的ijkplayer播放器观看网络视频
ijkplayer是由Bilibili基于FFmpeg3.4研发并开源的播放器,适用于Android和iOS,支持本地视频及网络流媒体播放。本文详细介绍如何在新版Android Studio中导入并使用ijkplayer库,包括Gradle版本及配置更新、导入编译好的so文件以及添加直播链接播放代码等步骤,帮助开发者顺利进行App调试与开发。更多FFmpeg开发知识可参考《FFmpeg开发实战:从零基础到短视频上线》。
1103 2
FFmpeg开发笔记(六十)使用国产的ijkplayer播放器观看网络视频
|
12月前
|
编解码 语音技术 内存技术
FFmpeg开发笔记(五十八)把32位采样的MP3转换为16位的PCM音频
《FFmpeg开发实战:从零基础到短视频上线》一书中的“5.1.2 把音频流保存为PCM文件”章节介绍了将媒体文件中的音频流转换为原始PCM音频的方法。示例代码直接保存解码后的PCM数据,保留了原始音频的采样频率、声道数量和采样位数。但在实际应用中,有时需要特定规格的PCM音频。例如,某些语音识别引擎仅接受16位PCM数据,而标准MP3音频通常采用32位采样,因此需将32位MP3音频转换为16位PCM音频。
295 0
FFmpeg开发笔记(五十八)把32位采样的MP3转换为16位的PCM音频
|
XML Java Android开发
FFmpeg开发笔记(五十二)移动端的国产视频播放器GSYVideoPlayer
GSYVideoPlayer是一款国产移动端视频播放器,支持弹幕、滤镜、广告等功能,采用IJKPlayer、Media3(EXOPlayer)、MediaPlayer及AliPlayer多种内核。截至2024年8月,其GitHub星标数达2万。集成时需使用新版Android Studio,并按特定步骤配置依赖与权限。提供了NormalGSYVideoPlayer、GSYADVideoPlayer及ListGSYVideoPlayer三种控件,支持HLS、RTMP等多种直播链接。
407 18
FFmpeg开发笔记(五十二)移动端的国产视频播放器GSYVideoPlayer
|
12月前
|
XML 开发工具 Android开发
FFmpeg开发笔记(五十六)使用Media3的Exoplayer播放网络视频
ExoPlayer最初是为了解决Android早期MediaPlayer控件对网络视频兼容性差的问题而推出的。现在,Android官方已将其升级并纳入Jetpack的Media3库,使其成为音视频操作的统一引擎。新版ExoPlayer支持多种协议,解决了设备和系统碎片化问题,可在整个Android生态中一致运行。通过修改`build.gradle`文件、布局文件及Activity代码,并添加必要的权限,即可集成并使用ExoPlayer进行网络视频播放。具体步骤包括引入依赖库、配置播放界面、编写播放逻辑以及添加互联网访问权限。
774 1
FFmpeg开发笔记(五十六)使用Media3的Exoplayer播放网络视频

热门文章

最新文章