0
点赞
收藏
分享

微信扫一扫

【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);



举报

相关推荐

0 条评论