当前位置:科学 > 正文

FFmpeg 入门学习 02-音视频解封装功能实现

2023-03-27 19:45:53  来源:音视频开发T哥

1、前言

如上图所示,在上一篇文章中介绍了视频播放的基本原理。本文继续使用 FFmpeg 来实现其中音视频解封装功能。

2、背景

2.1 封装格式

封装格式(也叫容器)就是将已经编码压缩好的视频流、音频流及字幕按照一定的方案放到一个文件中,便于播放软件播放。一般来说,视频文件的后缀名就是它的封装格式,如 MP4、flv 等,如下图所示:


(资料图片)

2.2 解封装

解封装就是和视频封装相反的过程,即把一个流媒体文件,拆解成音频数据和视频数据,一般被拆解成 H.264 编码的视频码流和 AAC 编码的音频码流,如下图所示:

2.3 解封装实现流程

使用 FFmpeg 实现解封装就是在在打开视频文件后,使用 av_read_frame 接口不断读取数据包的过程,如下图所示:

3、解封装代码实现

3.1 概述

本文在之前 FFmpegPlayer 类的基础上,进一步完善相关成员变量及方法,以实现解封装功能。

3.2 完善 FFmpegPlayer 类

增加一个成员变量 packet ,用于接收和暂存读取到的数据,完善后的 FFmpegPlayer 类如下:

class FFmpegPlayer {public:    explicit FFmpegPlayer(const char* m_url);    ~FFmpegPlayer();public:    bool        openFile();//打开文件    void        startDecode();//开启循环解码    void        abortDecode();//中断解码private:    int         readOnePacket();//读一个包    int         readPacket();//循环读包private:    std::string       url;//文件路径    AVFormatContext*  formatContext = nullptr;//封装格式上下文    AVPacket          packet{}; //用于读包    std::thread *     read_thread = nullptr;//数据读取线程    bool              abort_request{false};//强制结束    bool              readEof{false};//读包结束    int               video_index{-1};//视频流索引    int               audio_index{-1};//音频流索引};

3.3 readOnePacket 方法实现

readOnePacket 方法用于读取一个数据包,并返回是否读取成功的标记,实现如下:

int FFmpegPlayer::readOnePacket() {    if( abort_request ) return -1;//响应用户中断操作    int ret = av_read_frame( formatContext, &packet); //读取一个数据包    if( ret < 0 )    {        if( ret == AVERROR_EOF )//读包结束        {            readEof = true;        }        else//出错了        {            return  -1;        }    }    else    {        readEof = false;    }    return ret;}

C++音视频学习资料免费获取方法:关注音视频开发T哥,点击「链接」即可免费获取2023年最新C++音视频开发进阶独家免费学习大礼包!

3.4 readPacket 方法实现

readPacket 方法实现了循环读包,调用 readOnePacket 读取数据包并进行处理,实现如下:

int FFmpegPlayer::readPacket() {    while(true)    {        if( abort_request ) break;//用户退出        std::shared_ptr<AVPacket> pktClear(&packet, [](AVPacket *p "")        {            av_packet_unref(p);        });//用来确保每次 av_read_frame 后 pkt 缓存被清理了        int ret = readOnePacket();        if( ret == 0 )        {            if (packet.stream_index == video_index)            {                std::cout << "读取到了一个视频包,pts :" << packet.pts << std::endl;            }            else  if (packet.stream_index == audio_index)            {                std::cout << "读取到了一个音频包,pts :" << packet.pts << std::endl;            }        }    }    return 0;}

3.5 startDecode 方法实现

创建一个线程,用于循环读包,实现如下:

void FFmpegPlayer::startDecode(){    read_thread = new std::thread( &FFmpegPlayer::readPacket, this  );}

3.6 abortDecode 方法实现

用户主动中断视频播放接口,更改中断标记并结束线程,实现如下:

void FFmpegPlayer::abortDecode(){    abort_request = 1;    if( read_thread && read_thread->joinable())        read_thread->join();}

4、代码运行示例

文件打开成功后,调用解复用接口,代码如下:

#include "FFmpegPlayer.h"int main() {    const char  * url = "C:\\Lzc\\WorkCode\\test.mkv";    FFmpegPlayer * player = new FFmpegPlayer(url);    if( player->openFile())    {        std::cout << "文件打开成功!"<<std::endl;        player->startDecode();    }        system("pause");    return 0;}

运行结果如下:


原文链接:FFmpeg 入门学习 02--音视频解封装功能实现

关键词:

推荐阅读

垃圾短信电话号码如何举报?12321官网简介

垃圾短信电话号码如何举报?网页版:搜索12321进入百度不良网络和垃圾短信处理官网。然后选择左边的举报短信进入短信举报界面。然后填写里面 【详细】

pvc是什么 生产pvc的上市公司都有哪些?

pvc是什么pvc中文名是聚氯乙烯,曾是世界上产量最大的通用塑料,在建筑材料、日用品、管材等领域应用,市场十分广泛。那么,A股市场中生产p 【详细】

搜狗正式并入腾讯 搜狗公司简介

搜狗正式并入腾讯前段时间,一直有消息传出,腾讯即将收购搜狗,近日,搜狗正式并入腾讯的消息冲上了热搜榜单,吸引了众多网友关注,具体是 【详细】

中国古代十大名刀是什么 中国古代十大名刀简介

中国几乎所有的朝代都有记载名刀诞生的记录。从初唐大一统战争到盛唐的一切内外战争都出现过冷兵器——唐刀,史上对后世影响很大。中国古代 【详细】

动力天文台最新拍摄到一个超级日冕洞 ​日冕出现在哪里?

动力天文台最新拍摄到一个超级日冕洞据国外媒体报道,天文学家观测到的日冕洞犹如太阳表面蔓延一个巨大的深坑,10月15日,美国宇航局太阳动 【详细】

相关新闻

关于我们  |  联系方式  |  免责条款  |  招聘信息  |  广告服务  |  帮助中心

联系我们:85 572 98@qq.com备案号:粤ICP备18023326号-40

科技资讯网 版权所有