FFmpeg解封装

结构

AVFormatContext

    1> AVIOContext *pb:文件IO的上下文,自定义格式时使用

    2> char filename[1024]:保存打开的文件名,经常用到,例如断开重连

    3> unsigned int nb_streams:流数量

    4> AVStream **streams:具体流内容,通常只有视频、音频,偶尔也会有字幕之类的

    5> int64_t duration:总长度,以AV_TIME_BASE(通常为1000000)为单位,相当于使用微秒(us)为单位,注意这个值不一定能够获取到,如果获取不到可以通过帧数计算

    6> int64_t bit_rate:比特率 1s中有多少bit

AVStream

    1> AVCodecContext *codec:解码器,该参数已经过时

    2> AVRational time_base:时间基数,分数,通常分子=>1,分母=>9000

    3> int64_t duration:时长,duration * (time_base.num / time_base.den) 需要考虑除零

    4> AVRational avg_frame_rate:帧率,对于视频来说一帧数据就是一张图片,对于音频来说就是一定量的样本数,具体一帧数据存多少样本数由codecpar->frame_size决定

    5> AVCodecParameters *codecpar:音视频参数,主要用于替代codec

AVCodecParameters

    1> enum AVMediaType codec_type:编码类型,音频/视频

    2> enum AVCodecID codec_id:编码格式,H264格式等

    3> uint32_t codec_tag:用四个字节表示编码器,通常用不到

    4> int format:视频像素格式/音频采样格式

    5> int width, int height:视频宽高,仅视频有;不一定有,如果没有可以使用解码后的frame中的宽高

    6> uint64_t channel_layout,int channels,int sample_rate,int frame_size:声道,如三声道(数值与channels二进制十进制数相同),声道数,样本率,样本大小(单通道样本数),仅音频有

AVPacket

    1> AVBufferRef *buf:用于存储引用计数的一块空间,packet增加的时候引用计数+1,减少的时候引用计数-1

    2> int64_t pts:显示时间

    3> int64_t dts:解码时间

    4> uint8_t *data, int size:由ffmpeg创建和删除(不同帧数据量不同),保存帧数据

    注意:在没有B帧的情况下pts = dts

    AVPacket相关函数:av_packet_alloc(创建并初始化一个packet)、av_packet_clone(复制并增加一次引用计数)、av_packet_ref(手动加一次引用)、av_packet_unref(手动减一次引用)、av_packet_free(空间清理)、av_init_packet(为packet设置默认值)、av_packet_from_data(给定数据生成一个packet)、av_copy_packet(废弃的函数,注意不要再使用)

函数

1> av_register_all:注册所有的解封装和加封装格式,新版本的ffmpeg已经废弃该函数,可以不需要再调用

2> avformat_network_init:支持网络rtsp/rtmp/http数据流

3> avformat_open_input:打开音视频文件

    @param AVFormatContext **ps:需要注意ps不能为空,*ps可以为空,当*ps为空,会在内部创建存储空间,如果不传空可在外部先创建好空间但清理需要在外部处理

    @param const char *url:支持网络rtsp、http、本地路径

    @AVInputFormat *fmt:输入文件的格式,通常不需要指定,不指定的情况下由ffmpeg自己检测输入文件格式

    @AVDictionary **options:输入参数字典,具体有哪些参数可以参考源码ffmpeg-4.3.1\libavcodec\options_table.h里面的定义;可以使用方法av_dict_set设置参数,比如设置rtsp超时时间

    @return:0表示正常,非0返回错误码

4> avformat_find_stream_info:获取流信息

5> av_dump_format:打印流详细信息

    @param AVFormatContext **ps

    @param int index:用于打印(没啥用)

    @param const char *url:用于打印(没啥用)

    @param int is_output:context是输入(0)或输出(1)

    

6> av_find_best_stream:获取音视频流信息

    @param AVFormatContext **ps

    @param enum AVMediaType type

    @param  int wanted_stream_nb:通常设为-1,自动选择

    @param  int ratedstream:相关流,通常用不到,设为-1

    @param   AVCodec **decoder_ret:解码时用到,通常也不设置

    @param   int flags:保留字段

7> av_read_frame:读取一帧数据

    @param AVFormatContext **ps

    @param AVPacket *pkt:不能传null,需要预分配空间作为输出参数

8> av_seek_frame:移动到索引的frame

    @param AVFormatContext **ps

    @param stream_index:索引,-1表示default,通常使用视频来做seek,使用音频seek有可能移到视频某个非关键帧的位置

    @int64_t timestamp:移动到位置的时间戳

    @int flags:标志位 AV_SEEKFLAG_BACKWARD[1]:往后找  AV_SEEKFLAG_FRAME[8]:只跳到关键帧

9> avformat_close_input:关闭打开的音视频文件

10> av_strerror:失败时存放错误信息

示例程序

代码:

#include <QCoreApplication>

#include <iostream>
using namespace std;

#include <thread>

extern "C" {
    #include <libavformat/avformat.h>
}

#pragma comment(lib, "avformat.lib")
#pragma comment(lib, "avutil.lib")
#pragma comment(lib, "avcodec.lib")

static double r2d(AVRational r)
{
    return r.den == 0 ? 0 : r.num / r.den;
}

void xsleep(uint32_t ms)
{
    chrono::milliseconds du(ms);
    this_thread::sleep_for(du);
}

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);

    // 初始化封装库 @deprecated
    // av_register_all();

    // 初始化网络库
    avformat_network_init();

    // 解封装上下文
    AVFormatContext *ic = nullptr;
    const char *path = "1080.mp4";
    // 参数设置
    AVDictionary *opts = nullptr;
    // 设置rtsp以tcp方式传输
    av_dict_set(&opts, "rtsp_transport", "tcp", 0);
    // 设置网络超时时间
    av_dict_set(&opts, "max_delay", "500", 0);
    // 打开解封装的音视频文件
    int ret = avformat_open_input(&ic, path, nullptr, &opts);
    if (0 != ret) {
        char buf[1024] = {0};
        av_strerror(ret, buf, sizeof(buf) - 1);
        cout << "file open failed:" << buf << endl;
        return -1;
    }

    // 获取流信息
    avformat_find_stream_info(ic, nullptr);

    // 打印时长 s
    int nTime = ic->duration / AV_TIME_BASE;
    cout << "total time : " << nTime << endl;

    // 打印流详细信息
    av_dump_format(ic, 0, nullptr, 0);

    // 打印分割
    cout << endl;

    // 记录音视频索引号,便于读取frame
    int VideoStreamIndex = 0;
    int AudioStreamIndex = 1;

    // 获取音视频流信息(遍历方式)
    for (uint32_t i = 0; i < ic->nb_streams; ++i) {
        AVStream *stream = ic->streams[i];
        // 音频
        if (stream->codecpar->codec_type == AVMediaType::AVMEDIA_TYPE_AUDIO) {
            AudioStreamIndex = i;
            cout << i << "#Audio" << endl;
            cout << "codecid:" << stream->codecpar->codec_id << endl;
            cout << "channels:" << stream->codecpar->channels << endl;
            cout << "channel_layout:" << stream->codecpar->channel_layout << endl;
            cout << "format:" << stream->codecpar->format << endl;
            cout << "samplerate:" << stream->codecpar->sample_rate << endl;
            // 帧率
            cout << "av_rate:" << r2d(stream->avg_frame_rate) << endl;
            cout << "frame_size:" << stream->codecpar->frame_size << endl;
            // fps
            cout << "fps:" << stream->codecpar->sample_rate / stream->codecpar->frame_size << endl;

        }
        // 视频
        if (stream->codecpar->codec_type == AVMediaType::AVMEDIA_TYPE_VIDEO) {
            VideoStreamIndex = i;
            cout << i << "#Video" << endl;
            cout << "codecid:" << stream->codecpar->codec_id << endl;
            cout << "width:" << stream->codecpar->width << endl;
            cout << "height:" << stream->codecpar->height << endl;
            cout << "format:" << stream->codecpar->format << endl;
            // 帧率 fps
            cout << "av_rate:" << r2d(stream->avg_frame_rate) << endl;
            cout << "frame_size:" << stream->codecpar->frame_size << endl;
        }

        // 打印分割
        cout << endl;
    }

    // 获取音视频流信息(索引方式)
    AudioStreamIndex = av_find_best_stream(ic, AVMediaType::AVMEDIA_TYPE_AUDIO, -1, -1, 0, 0);
    // AVStream *auStream = ic->streams[AudioStreamIndex];
    // VideoStreamIndex = av_find_best_stream(ic, AVMediaType::AVMEDIA_TYPE_VIDEO, -1, -1, 0, 0);

    // 分配并初始化AVPacket
    AVPacket *pkt = av_packet_alloc();
    while(1) {
        // 读取帧数据
        ret = av_read_frame(ic, pkt);
        if (0 != ret) {
            cout << "Read Frame End!" << endl;
            getchar();

            // 播放结束从3s处重新播放
            int ms = 3000; // 3s位置
            long long pos = ms / 1000.0 * r2d(ic->streams[pkt->stream_index]->time_base);
            av_seek_frame(ic, VideoStreamIndex, pos, AVSEEK_FLAG_BACKWARD | AVSEEK_FLAG_FRAME);
            continue;
        }
        // 大小
        cout << "size = " << pkt->size << endl;
        // 显示时间
        cout << "pts = " << pkt->pts << endl;
        cout << "pts ms = " << pkt->pts * (r2d(ic->streams[pkt->stream_index]->time_base) * 1000) << endl;
        // 解码时间
        cout << "dts = " << pkt->dts << endl;
        if (pkt->stream_index == AudioStreamIndex) {
            cout << "Audio Frame" << endl;
        }
        if (pkt->stream_index == VideoStreamIndex) {
            cout << "Video Frame" << endl;
        }
        cout << endl;

        // 线程延迟,不要打印太快
        xsleep(500);

        // 引用计数减1,为0时释放空间
        av_packet_unref(pkt);
    }
    av_packet_free(&pkt);

    // 关闭解封装的音视频文件
    if (nullptr != ic) {
        avformat_close_input(&ic);
        ic = nullptr;
    }

    return a.exec();
}

输出:

  • 3
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
根据引用和引用的内容,使用FFmpeg可以实现封装H.264和AAC音频。具体的步骤如下: 1. 准备FFmpeg:确保已经下载并安装最新版本的FFmpeg,并将其添加到系统的环境变量中。 2. 打开命令行终端:在命令行中输入以下命令以封装H.264和AAC音频: ``` ffmpeg -i input.mp4 -c:v copy -c:a copy output.h264 ffmpeg -i input.mp4 -vn -c:a copy output.aac ``` 其中,`input.mp4`是要封装的文件名,`output.h264`是输出的H.264视频文件名,`output.aac`是输出的AAC音频文件名。 3. 执行命令:按下Enter键执行命令,FFmpeg会开始封装过程。 4. 等待完成:等待命令行显示封装过程的进度,并等待封装过程完成。 5. 完成封装:完成后,你将得到一个H.264视频文件和一个AAC音频文件,用于进一步处理或播放。 需要注意的是,如果要模拟实时视频发送,需要安装FFmpeg并将其放置在可以连接到国标平台网络的位置。详细的安装步骤可以参考引用中提供的链接。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* [Hi3531D调试手记(四):使用ffmpeg实时封装H264视频为MP4](https://blog.csdn.net/qq_38940316/article/details/114577809)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] - *3* [GB28181国标平台测试软件,模拟监控摄像头,实现了注册、注销、目录、INVITE,BYE、KEEPLIVE、OPTION信令](https://download.csdn.net/download/SE_JW/88241318)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

SuperYang_

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值