FFmpeg-- c++实现:音频流aac和视频流h264封装

文章目录

      • 流程
      • api
      • 核心代码
        • muxer.h
        • muxer.cpp

aac 和 h264 封装为视频流,封装为c++的Muxter类

流程

  • 分配视频文件上下文
    int Init(const char *url);

  • 创建流,赋值给视频的音频流和视频流
    int AddStream(AVCodecContext *codec_ctx);

  • 写视频流的head
    int SendHeader();

  • 写视频流的packet,需要转换packet的pts和dts , 值为 原有pts * 编码时间基/ 视频流的时间基
    int SendPacket(AVPacket *packet)

  • 写视频流的trail
    int SendTrailer();

  • 释放资源
    void DeInit();

api

int64_t av_rescale_q(int64_t a, AVRational bq, AVRational cq) av_const
// 时间基转换函数 , 计算结果为 a * bq / cq

核心代码

muxer.h
#ifndef MUXER_H
#define MUXER_H
#include <iostream>
extern "C"
{
#include "libavformat/avformat.h"
#include "libavcodec/avcodec.h"
}


class Muxer
{
public:
    Muxer();
    ~Muxer();
    // 输出文件 返回<0值异常
    // 初始化
    int Init(const char *url);
    // 资源释放
    void DeInit();
    // 创建流
    int AddStream(AVCodecContext *codec_ctx);

    // 写流
    int SendHeader();
    int SendPacket(AVPacket *packet);
    int SendTrailer();

    int Open(); // avio open
private:
    AVFormatContext *fmt_ctx_ = NULL;
    std::string url_ = "";

    // 编码器上下文
    AVCodecContext *aud_codec_ctx_= NULL;
    AVStream *aud_stream_ = NULL;
    AVCodecContext *vid_codec_ctx_= NULL;
    AVStream *vid_stream_ = NULL;

    int audio_index_ = -1;
    int video_index_ = -1;
};

#endif // MUXER_H

muxer.cpp
 #include "muxer.h"


Muxer::Muxer()
{

}

Muxer::~Muxer()
{

}

int Muxer::Init(const char *url)
{
    int ret = avformat_alloc_output_context2(&fmt_ctx_, NULL, NULL,url);
    if(ret != 0) {
        char errbuf[1024] = {0};
        av_strerror(ret, errbuf, sizeof(errbuf) - 1);
        printf("avformat_alloc_output_context2 failed:%s\n", ret);
        return -1;
    }
    url_ = url;
    return 0;
}

void Muxer::DeInit()
{
    if(fmt_ctx_) {
        avformat_close_input(&fmt_ctx_);
    }
    url_ = "";
    aud_codec_ctx_ = NULL;
    aud_stream_ = NULL;
    audio_index_ = -1;

    vid_codec_ctx_ = NULL;
    vid_stream_ = NULL;
    video_index_ = -1;
}

int Muxer::AddStream(AVCodecContext *codec_ctx)
{
    if(!fmt_ctx_) {
        printf("fmt ctx is NULL\n");
        return -1;
    }
    if(!codec_ctx) {
        printf("codec ctx is NULL\n");
        return -1;
    }
    AVStream *st = avformat_new_stream(fmt_ctx_, NULL);
    if(!st) {
        printf("avformat_new_stream failed\n");
        return -1;
    }
    //    st->codecpar->codec_tag = 0;
    // 从编码器上下文复制, 根据提供的编解码器的值填充参数结构
    avcodec_parameters_from_context(st->codecpar, codec_ctx);
    av_dump_format(fmt_ctx_, 0, url_.c_str(), 1);

    // 判断当前的是视频流还是音频流
    if(codec_ctx->codec_type == AVMEDIA_TYPE_AUDIO) {
        aud_codec_ctx_ = codec_ctx;
        aud_stream_ = st;
        audio_index_ = st->index;
    }  else if(codec_ctx->codec_type == AVMEDIA_TYPE_VIDEO) {
        vid_codec_ctx_ = codec_ctx;
        vid_stream_ = st;
        video_index_ = st->index;
    }
    return 0;
}

int Muxer::SendHeader()
{
    if(!fmt_ctx_) {
        printf("fmt ctx is NULL\n");
        return -1;
    }
    int ret = avformat_write_header(fmt_ctx_, NULL);
    if(ret != 0) {
        char errbuf[1024] = {0};
        av_strerror(ret, errbuf, sizeof(errbuf) - 1);
        printf("avformat_write_header failed:%s\n", ret);
        return -1;
    }
    return 0;
}

int Muxer::SendPacket(AVPacket *packet)
{
    int stream_index = packet->stream_index;

    if(!packet || packet->size <= 0 || !packet->data) {
        printf("packet is null\n");
        if(packet)
            av_packet_free(&packet);

        return -1;
    }

    AVRational src_time_base;   // 编码后的包
    AVRational dst_time_base;   // mp4输出文件对应流的time_base
    if(vid_stream_ && vid_codec_ctx_ && stream_index == video_index_) {

        src_time_base = vid_codec_ctx_->time_base;
        dst_time_base = vid_stream_->time_base;

    } else if(aud_stream_ && aud_codec_ctx_ && stream_index == audio_index_) {

        src_time_base = aud_codec_ctx_->time_base;
        dst_time_base = aud_stream_->time_base;

    }
    // 时间基转换
    // int64_t av_rescale_q(int64_t a, AVRational bq, AVRational cq) av_const;
    // 时间基转换函数  a * bq / cq
    packet->pts = av_rescale_q(packet->pts, src_time_base, dst_time_base);

    packet->dts = av_rescale_q(packet->dts, src_time_base, dst_time_base);

    packet->duration = av_rescale_q(packet->duration, src_time_base, dst_time_base);

    int ret = 0;

    //写packet
    ret = av_interleaved_write_frame(fmt_ctx_, packet); // 不是立即写入文件,内部缓存,主要是对pts进行排序
    //    ret = av_write_frame(fmt_ctx_, packet);

    av_packet_free(&packet);
    if(ret == 0) {
        return 0;
    }
    else {
        char errbuf[1024] = {0};
        av_strerror(ret, errbuf, sizeof(errbuf) - 1);
        printf("avformat_write_header failed:%s\n", ret);
        return -1;
    }
}

int Muxer::SendTrailer()
{
    if(!fmt_ctx_) {
        printf("fmt ctx is NULL\n");
        return -1;
    }
    int ret = av_write_trailer(fmt_ctx_);
    if(ret != 0) {
        char errbuf[1024] = {0};
        av_strerror(ret, errbuf, sizeof(errbuf) - 1);
        printf("av_write_trailer failed:%s\n", ret);
        return -1;
    }
    return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.kler.cn/a/274543.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

机器人离散化阻抗控制

机器人离散化阻抗控制是一种控制策略&#xff0c;它结合了阻抗控制的思想与离散化方法&#xff0c;以实现对机器人运动与外力之间动态关系的精细调节。这种控制方法旨在使机器人在与环境交互时能够表现出期望的阻抗特性&#xff0c;从而实现对接触力和位置的精确控制。 在离散…

【源码&教程】基于GAN的动漫头像生成系统

1.研究背景 我们都喜欢动漫角色&#xff0c;并试图创造我们的定制角色。然而&#xff0c;要掌握绘画技巧需要巨大的努力&#xff0c;之后我们首先有能力设计自己的角色。为了弥补这一差距&#xff0c;动画角色的自动生成提供了一个机会&#xff0c;在没有专业技能的情况下引入定…

Word为图表设置图注并在图表清单中自动生成

1如果需要自动插入题注&#xff0c;请不要自己为文件增加新的标题样式或删除自带的标题1样式 2章节大标题最好是标题1&#xff0c;2,3而不要设置标题一、二、三&#xff0c;否则图例在自动生成时会显示 图一 -1&#xff0c;调整起来会非常不方便 若实在要使用大写中文标题&…

解决由于历史原因解析tflite失败的问题

文章目录 0. 背景1. tflite 历史遗留问题2. schema3. flatbuffers 编译器3.1 安装 FlatBuffers 编译器3.2. 编译 FlatBuffers schema 文件3.3 使用生成的 Python 文件 4 问题未解决终极解决方案 写在最前面&#xff1a;解决方法是升级tensorflow版本&#xff0c;重新生成tflite…

一款非常流行的数字音乐工作站软件FL Studio for Mac 21.2.3.3586中文版新功能特色

FL Studio&#xff08;Fruity Loops&#xff09;是一款非常流行的数字音乐工作站软件&#xff0c;它可以让用户轻松地制作各种类型的音乐。前不久&#xff0c;FL Studio发布了最新的Mac版21.2.3.3586中文版&#xff0c;这个新版本的发布让广大Mac用户感到非常兴奋。 本文将介绍…

VMware的安装和Ubuntu的配置安装

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言一、linux是什么&#xff1f;二、基础知识虚拟机 三、安装VMware总结 前言 提示&#xff1a;这里可以添加本文要记录的大概内容&#xff1a; Linux是一个功能…

奥特曼剧透GPT-5,将在高级推理功能上实现重大进步

奥特曼&#xff1a;“GPT-5的能力提升幅度将超乎人们的想象...” 自 Claude 3 发布以来&#xff0c;外界对 GPT-5 的期待越来越强。毕竟Claude 3已经全面超越了 GPT-4&#xff0c;成为迄今为止最强大模型。 而且距离 GPT-4 发布已经过去了整整一年时间&#xff0c;2023年3月1…

Spring Boot 自动化单元测试类的编写过程

前言 Web环境模拟测试 企业开发不仅要保障业务层与数据层的功能安全有效&#xff0c;也要保障表现层的功能正常。但是我们一般对表现层的测试都是通过postman手工测试的&#xff0c;并没有在打包过程中代码体现表现层功能被测试通过。那么能否在测试用例中对表现层进行功能测…

C#,图论与图算法,有向图(Graph)之环(Cycle)判断的颜色算法与源代码

1 检查该图是否包含循环 给定一个有向图,检查该图是否包含循环。如果给定的图形至少包含一个循环,则函数应返回true,否则返回false。 方法:深度优先遍历可用于检测图中的循环。连接图的DFS生成树。只有当图中存在后缘时,图中才存在循环。后边是从节点到自身(自循环)或…

WiFi是可以连接网络,但是在Pixel 手机上就连接提示受阻,无法上网-解决方法

1&#xff0c;通过USB连接手机&#xff0c;然后通过adb命令执行 adb shell settings delete global captive_portal_mode adb shell settings put global captive_portal_mode 0 adb shell settings get global captive_portal_mode adb shell settings delete global capti…

大数据面试题 —— HBase

目录 什么是HBase简述HBase 的数据模型HBase 的读写流程HBase 在写的过程中的region的split的时机HBase 和 HDFS 各自的使用场景HBase 的存储结构HBase 中的热现象&#xff08;数据倾斜&#xff09;是怎么产生的&#xff0c;以及解决办法有哪些HBase rowkey的设计原则HBase 的列…

[LLM] 大模型基础|预训练|有监督微调SFT | 推理

现在的大模型在进行预训练时大部分都采用了GPT的预训练任务&#xff0c;即 Next token prediction。 要理解大语言模型&#xff08;LLM&#xff09;&#xff0c;首先要理解它的本质&#xff0c;无论预训练、微调还是在推理阶段&#xff0c;核心都是next token prediction&#…

SLAM 求解IPC算法

基础知识&#xff1a;方差&#xff0c;协方差&#xff0c;协方差矩阵 方差&#xff1a;描述了一组随机变量的离散程度 方差 每个样本值 与 全部样本的平均值 相差的平方和 再求平均数&#xff0c;记作&#xff1a; 例如&#xff1a;计算数字1-5的方差&#xff0c;如下 去中心化…

.NET 异步编程(异步方法、异步委托、CancellationToken、WhenAll、yield)

文章目录 异步方法异步委托async方法缺点CancellationTokenWhenAllyield 异步方法 “异步方法”&#xff1a;用async关键字修饰的方法 异步方法的返回值一般是Task<T>&#xff0c;T是真正的返回值类型&#xff0c;Task<int>。惯例&#xff1a;异步方法名字以 Asy…

键盘映射工具KeyTweak的使用,把F9和F10改为 Home、End

如果你的笔记本没有Home、End键 对于写文字和写代码影响还是比较大的 下面使用键盘映射工具KeyTweak 把F9和F10分别改为 Home、End 然后点击ok 电脑重启后 就生效了 很好用 完美解决 小尺寸笔记本 的按键少的烦恼 可以自己再琢磨琢磨 去映射 符合自己需求的按键 软件下载链接&…

[PwnThyBytes 2019]Baby_SQL

[PwnThyBytes 2019]Baby_SQL 查看源码发现 下载源码&#xff0c;首先观察index.php 首先进入index.php&#xff0c;会执行session_start();启动session这里通过foreach将所有的环境变量的值都遍历了一遍&#xff0c;并且都使用了addslashes()进行转义&#xff0c;然后就定义了…

【智能家居】东胜物联提供软硬一体化智能家居解决方案,助企业提高市场占有率

背景 随着智能家居市场的不断壮大&#xff0c;越来越多的消费者开始享受到它带来的便捷和效益。现在&#xff0c;他们可以通过远程或语音控制设备进行个性化设置&#xff0c;比如调节照明和温度&#xff0c;让生活变得更加舒适和智能化。 根据SPER市场研究&#xff0c;预计秘…

【计算机网络_网络层】IP协议

文章目录 1. IP的基本概念1.1 什么是IP协议1.2 为什么要有IP协议 2. IP的协议格式3. 网段划分&#xff08;重要&#xff09;3.1 为什么要进行网段划分3.2 网段划分的规则3.2.1 古老的划分方案3.2.2 现代的划分方案 4. 特殊的IP地址5. 解决IP地址的数量限制问题6. 私有IP和公网I…

BUUCTF-Misc10

秘密文件1 1.打开附件 是一个流量包 2.Wireshark 用Wireshark打开 右键追踪tcp追踪流&#xff0c;发现一个以.rar结尾的压缩包 3.foremost 用foremost分离文件 发现有一个rar的文件夹 文件夹内有个加密的压缩包 4.ARCHPR 用ARCHPR工具对压缩包进行解密 5.得到flag [BJDCTF2…

搭建基于 Snowflake 的 CI/CD 最佳实践!

Snowflake 提供了可扩展的计算和存储资源&#xff0c;和基于 SQL 的界面 Snowsight&#xff0c;方便用户进行数据操作和分析。然而&#xff0c;如果用户想将自己的 CI/CD 流程与 Snowflake 集成时&#xff0c;会发现一些不便之处&#xff08;尤其相比其 SnowSight 优秀的查询能…
最新文章