【FFMPEG应用篇】基于FFmpeg的PCM和RGB数据统一封装

项目采用工程模式进行构造。

技术解决难点:

1.编码后的PTS时间一定要赋值。2.音视频封装同步问题,其中涉及到PTS同步问题,例如视频25PTS/s  音频43PTS/s(44100采样率/1024每帧),音频要慢于视频所以这种情况下要进行PTS同步计算处理.

主要代码如下

XVideoWriter.h

#pragma once
#include<string>
class AVPacket;
enum XSAMPLEFMT
{X_S16 = 1,X_FLATP = 8
};class XVideoWriter
{
public:virtual bool Init(const char* file)=0;virtual void Close() = 0;virtual bool AddVideoStream()=0;virtual bool AddAudeoStream() = 0;virtual AVPacket* EncodeVideo(const unsigned char *rgb)=0;virtual AVPacket* EncodeAudeo(const unsigned char *pcm) = 0;virtual bool WriteHead() = 0;//会释放PKT空间virtual bool WriteFrame(AVPacket *pkt) = 0;virtual bool WriteEnd() = 0;virtual bool IsVideoBefore() = 0;static XVideoWriter *Get(unsigned short index=0);~XVideoWriter();
protected:XVideoWriter();
public:std::string filename;//视频输入参数int inWidth = 1920;int inHeight = 1080;int inPixFmt = 30;//音频输入参数int inSampleRate = 44100;int inChannels = 2;XSAMPLEFMT inSampleFmt = X_S16;//视频输出参数int vBitrate = 400000000;int outwidth = 1920;int outheight = 1080;int outfps = 25;//音频输出参数int aBitrate = 64000;int sample_rate = 44100;int channels = 2;int outSampleType = X_FLATP;int nb_Asample = 1024;//每帧输出样本数量
};

rgb_pcm_to_mp4.cpp

#include "XVideoWriter.h"
#include<iostream>
extern "C" {
#include "libavformat/avformat.h"
#include "libavcodec/avcodec.h"
#include "libswscale/swscale.h"
#include "libswresample/swresample.h"
}using namespace std;class CXVideoWriter :public XVideoWriter
{
public:AVFormatContext *ic = NULL;//封装MP4输出上下文AVCodecContext  *vc = NULL;//视频编码器AVCodecContext  *ac = NULL;//音频编码器AVStream *vs = NULL;//视频流AVStream *as = NULL;//音频流SwsContext *ctx = NULL;	//像素转换上下文SwrContext *actx = NULL;//音频重采样上下文AVFrame *yuv = NULL;//输出YUV空间AVFrame *pcm = NULL;//输出YUV空间int vpts = 0;//视频的ptsint apts = 0;//音频的ptsvoid Close(){if (ic)avformat_close_input(&ic);if (vc){avcodec_close(vc);avcodec_free_context(&vc);}if (ac){avcodec_close(ac);avcodec_free_context(&ac);}if (ctx){sws_freeContext(ctx);ctx = nullptr;}if (yuv){av_frame_free(&yuv);}if (pcm){av_frame_free(&pcm);}if (actx){swr_free(&actx);}}bool Init(const char* file){Close();//封装文件输出上下文avformat_alloc_output_context2(&ic, 0, 0, file);if (!ic){cout<< "avformat_alloc_output_context2 NO" << endl;return false;}filename = file;return true;}bool AddVideoStream(){if (!ic)return false;//1 创建视频编码器AVCodec *codec = avcodec_find_encoder(AV_CODEC_ID_H264);if (!codec){cout << "avcodec_find_encoder No" << endl;return false;}vc = avcodec_alloc_context3(codec);if (!vc){cout << "avcodec_alloc_context3 No" << endl;return false;}vc->bit_rate = vBitrate;vc->width = outwidth;vc->height = outheight;vc->time_base = { 1,outfps };vc->framerate = { outfps,1 };vc->gop_size = 50;vc->max_b_frames = 0;vc->pix_fmt = AV_PIX_FMT_YUV420P;vc->codec_id = AV_CODEC_ID_H264;vc->thread_count = 8;//全局编码vc->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;//打开编码器int ret = avcodec_open2(vc, codec, 0);if (ret < 0){cout << "avcodec_open2 No" << endl;return false;}cout << "avcodec_open2 OK" << endl;//添加视频流到输出上下文vs = avformat_new_stream(ic, NULL);vs->id = 0;vs->codecpar->codec_tag = 0;avcodec_parameters_from_context(vs->codecpar, vc);cout << "========================" << endl;av_dump_format(ic, 0, filename.c_str(), 1);cout << "========================" << endl;ctx = sws_getCachedContext(ctx,outwidth, outheight, AV_PIX_FMT_BGRA,outwidth, outheight, AV_PIX_FMT_YUV420P,SWS_BICUBIC, NULL, NULL, NULL);if (!ctx){cout << "sws_getCachedContext No" << endl;return false;}//输入的空间unsigned char *rgb = new unsigned char[outwidth * outheight * 4];//输出的空间if (!yuv){yuv = av_frame_alloc();yuv->format = AV_PIX_FMT_YUV420P;yuv->width = outwidth;yuv->height = outheight;yuv->pts = 0;//分配frame空间ret = av_frame_get_buffer(yuv, 32);if (ret < 0){cout << "av_frame_get_buffer No" << endl;return false;}return true;}}bool AddAudeoStream(){if (!ic)return false;//1 找到音频编码器AVCodec *codec = avcodec_find_encoder(AV_CODEC_ID_AAC);if (!codec){cout << "audio avcodec_find_encoder NO" << endl;return false;}//2 创建并打开音频编码器ac = avcodec_alloc_context3(codec);if (!codec){cout << "audio avcodec_alloc_context3 NO" << endl;return false;}ac->bit_rate = aBitrate;ac->sample_rate = sample_rate;ac->sample_fmt = AVSampleFormat(outSampleType);ac->channels = channels;ac->channel_layout = av_get_default_channel_layout(channels);ac->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;int ret = avcodec_open2(ac, codec, NULL);if (ret < 0){cout << "avcodec_open2 NO" << endl;avcodec_free_context(&ac);return false;}cout << "audio avcodec_open2 OK" << endl;//3 新增音频流as = avformat_new_stream(ic, NULL);if (!as){cout << "avformat_new_stream NO" << endl;return false;}as->codecpar->codec_tag = 0;avcodec_parameters_from_context(as->codecpar, ac);av_dump_format(ic, 0, filename.c_str(), 1);//4 音频重采样actx = swr_alloc();actx = swr_alloc_set_opts(actx,ac->channel_layout,	//输出格式ac->sample_fmt,					//输出样本格式ac->sample_rate,					//输出采样率av_get_default_channel_layout(inChannels),//输入格式(AVSampleFormat)inSampleFmt,inSampleRate,0, 0);ret = swr_init(actx);if (ret != 0){char buf[1024] = { 0 };av_strerror(ret, buf, sizeof(buf) - 1);cout << "swr_init  failed! :" << buf << endl;return false;}//5 音频输出AVFrameif (!pcm){pcm = av_frame_alloc();pcm->format = ac->sample_fmt;pcm->channels = ac->channels;pcm->channel_layout = ac->channel_layout;pcm->nb_samples = nb_Asample; //一帧音频存放的样本数量ret = av_frame_get_buffer(pcm, 0);if (ret < 0){cout << "av_frame_get_buffer No :" << endl;return false;}cout << "audio AVFrame Create OK" << endl;}return true;}AVPacket* EncodeVideo(const unsigned char *rgb){AVPacket *p = NULL;//rgb to yuvuint8_t *indata[AV_NUM_DATA_POINTERS] = { 0 };indata[0] = (uint8_t*)rgb;int inlinesize[AV_NUM_DATA_POINTERS] = { 0 };inlinesize[0] = outwidth * 4;//*4字节数int h = sws_scale(ctx, indata, inlinesize, 0, outheight,yuv->data,yuv->linesize);if (h <= 0)return p;//cout << h << "|";yuv->pts = vpts;vpts++;//encoderint ret = avcodec_send_frame(vc, yuv);if (ret != 0){return NULL;}p=av_packet_alloc();//一次发送可能多次接收ret = avcodec_receive_packet(vc,p);if (ret != 0 || p->size<=0){av_packet_free(&p);return NULL;}//自动计算ptsav_packet_rescale_ts(p, vc->time_base, vs->time_base);p->stream_index = vs->index;return p;}AVPacket* EncodeAudeo(const unsigned char *d){//1 音频重采样const uint8_t *data[AV_NUM_DATA_POINTERS] = { 0 };data[0] = (uint8_t*)d;int len = swr_convert(actx,pcm->data, pcm->nb_samples,		//输出data, pcm->nb_samples);	//输入cout << len << "*";//2 音频编码int ret = avcodec_send_frame(ac, pcm);if (ret != 0)return nullptr;AVPacket* pkt = av_packet_alloc();av_init_packet(pkt);ret = avcodec_receive_packet(ac, pkt);if (ret != 0){av_packet_free(&pkt);return nullptr;}cout << pkt->size << "|";pkt->stream_index = as->index;pkt->pts = apts;pkt->dts = pkt->pts;apts += av_rescale_q(pcm->nb_samples, { 1,ac->sample_rate },ac->time_base);//可以根据音频样本大小推算PTSreturn pkt;}bool WriteHead(){if (!ic)return false;//打开IOint ret = avio_open(&ic->pb, filename.c_str(), AVIO_FLAG_WRITE);//打开输出文件IOif (ret!=0){cout << "avio_open failed" << endl;return false;}//写入封装头ret = avformat_write_header(ic, NULL);if (ret!=0){cout << "avformat_write_header failed" << endl;return false;}cout << "write"<<filename<<" OK "<< endl;return true;}bool WriteFrame(AVPacket *pkt){if (!ic || !pkt || pkt->size <= 0)return false;if (av_interleaved_write_frame(ic, pkt) != 0)return false;return true;}bool WriteEnd(){if (!ic || !ic->pb)return false;//写入视频索引尾部信息if (av_write_trailer(ic) != 0){cout << "av_write_trailer No" << endl;return false;}if (avio_close(ic->pb) != 0){cout << "avio_close No" << endl;return false;}cout << "Write End OK" << endl;}/*如果视频在前,先写入视频信息,反之先写入音频数据*/bool IsVideoBefore(){if (!ic || !as || !vs)return false;int re = av_compare_ts(vpts,vc->time_base,apts,ac->time_base);if (re <= 0){return true;}return false;}};bool XVideoWriter::Init(const char * file)
{return true;
}XVideoWriter * XVideoWriter::Get(unsigned short index)
{static bool isfirst = true;if (isfirst){//初始化封装库av_register_all();//初始化网络库 (可以打开rtsp rtmp http 协议的流媒体视频)avformat_network_init();//注册解码器avcodec_register_all();isfirst = false;}static CXVideoWriter wrs[65535];return &wrs[index];
}XVideoWriter::~XVideoWriter()
{
}XVideoWriter::XVideoWriter()
{
}

rgb_pcm_to_mp4.cpp

// rgb_pcm_to_mp4.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//
#include"XVideoWriter.h"
#include <iostream>int main()
{char outfile[] = "rgb_pcm_to_mp4.mp4";char rgbfile[] = "test.rgb";char pcmfile[] = "test.pcm";XVideoWriter *xw = XVideoWriter::Get(0);xw->Init(outfile);xw->AddVideoStream();xw->AddAudeoStream();FILE *fp = fopen(rgbfile, "rb");if (!fp){std::cout << "fopen rgbfile NO" << std::endl;return -1;}int size = xw->outwidth * xw->outheight * 4;unsigned char *rgb = new unsigned char[size];int asize = xw->nb_Asample * xw->inChannels * 2;unsigned char *pcm = new unsigned char[asize];FILE *fa = fopen(pcmfile, "rb");if (!fa){std::cout << "fopen pcmfile NO" << std::endl;return -1;}xw->WriteHead();AVPacket *pkt = NULL;int len = 0;for (;;){if (xw->IsVideoBefore())//视频在前{int len = fread(rgb, 1, size, fp);if (len <= 0)break;pkt = xw->EncodeVideo(rgb);if (pkt)std::cout << ".";else{std::cout << "-";continue;}if (xw->WriteFrame(pkt)){std::cout << "+";}}else{len = fread(pcm, 1, asize, fa);if (len <= 0)break;pkt = xw->EncodeAudeo(pcm);xw->WriteFrame(pkt);}}xw->WriteEnd();delete rgb;rgb = nullptr;std::cout << "*******************end***************" << std::endl;return 0;
}

项目链接

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

windows数据自动上传服务器,windows服务器间自动传输文件

日常运维工作中需要在windows服务器间传输文件的使用场景比较多&#xff0c;比较典型的例子为应用程序的离线自动备份&#xff0c;下面分享笔者日常使用的服务器间自动传输文件脚本rem 设置共享net use \\**IP**\程序配置和数据备份 "******(密码)" /user:"admi…

python模块使用_一文让你学会所有的python模块使用

部分高等技能:为了削减一个编译模块的大年夜小&#xff0c;你可以在 Python 敕令行中应用 -O 或者 -OO。-O 参数删除了断言语句&#xff0c;-OO 参数删除了断言语句和 __doc__ 字符串。 因为某些法度榜样依附于这些变量的可用性&#xff0c;你应当只在肯定无误的场合应用这一选…

rest web服务_在WildFly的REST Web服务中与Jackson的双向关系

rest web服务这是使用Jackson的REST Web服务中Java实体之间的双向关系的示例。 假设我们在两个实体Parent和Child之间存在双向关系。 使用MySQL工作台为这两个表生成SQL模式文件。 DROP SCHEMA IF EXISTS bidirectional_schema ; CREATE SCHEMA IF NOT EXISTS bidirectional…

【开源项目】基于Directx屏幕录制

#include<d3d9.h> #include<iostream> #pragma comment(lib,"d3d9.lib") using namespace std; //截取全屏 void CaptureScreen(void *data) {//1 创建directx3d对象static IDirect3D9 *d3d nullptr;if (!d3d){d3d Direct3DCreate9(D3D_SDK_VERSION);…

git 修改分支名字_基础Git操作与GitHub协作吐血整理,收好!| 原力计划

作者 | 光子俊来源 | CSDN博客出品 | CSDN(ID:CSDNnews)Git介绍Git是目前世界上最先进的分布式版本控制系统&#xff0c;可以为我们管理项目、构建工程、多人协作提供便利&#xff0c;作为一个爱技术的你可以是必须要掌握的呀&#xff01;&#xff01;&#xff01;Git安装(inst…

Win7system登录打开计算机,Windows7系统system文件丢失导致开机黑屏如何解决

最近有windows7系统用户在开机的时候遇到了黑屏的问题&#xff0c;却提示“因以下文件的损坏或丢失&#xff0c;Windows无法启动windows/system32/config/system”的错误&#xff0c;导致无法开机&#xff0c;针对Windows7系统system文件丢失导致开机黑屏问题&#xff0c;本文就…

javafx阴影_JavaFX技巧来节省内存! 属性和可观察对象的阴影场

javafx阴影在 JavaFX的世界中&#xff0c; Properties API允许UI开发人员将值绑定到UI控件。 这种功能出奇的简单&#xff0c;但是当对象模型经常使用属性时&#xff0c;应用程序可能会很快耗尽内存。 我通常会编写两个单独的对象&#xff0c;例如pojo类和表示模型对象。 此技术…

【开源项目】基于QT录制PCM音频实例详细

#include "QtAudio_input.h" #include <QtWidgets/QApplication> #include<QAudioInput> #include<iostream> using namespace std; int main(int argc, char *argv[]) {QAudioFormat fmt;fmt.setSampleRate(44100);//样本率fmt.setSampleSize(16)…

工业计算机改造报告,工业计算机实验报告..docx

实验一 A/D、D/A 转换实验一、实验目的1.了解温控系统的组成。2.了解NI 测量及自动化浏览器的使用并对数据采集卡进行设置。3.了解Dasylab 软件的各项功能&#xff0c;并会简单的应用。4.通过实验了解计算机是如何进行数据采集、控制的。二、实验设备微型计算机、NI USB 6008 数…

yum install -y 是什么意思_为什么你应该在docker 中使用gosu?

为什么要使用gosu&#xff1f;Docker容器中运行的进程&#xff0c;如果以root身份运行话会有安全隐患&#xff0c;该进程拥有容器内的全部权限&#xff0c;更可怕的是如果有数据卷映射到宿主机&#xff0c;那么通过该容器就能操作宿主机的文件夹了&#xff0c;一旦该容器的进程…

openshift_Openshift源中的高可用性Drools无状态服务

openshift嗨&#xff0c;大家好&#xff01; 在这篇博客文章中&#xff0c;我想举一个简单的示例&#xff0c;展示使用Openshift 3&#xff08;Docker和Kubernetes&#xff09;扩展我们的Drools Stateless服务有多么容易。 我将展示如何通过按需提供新实例来扩展我们的服务&…

【WebRTC---源码篇】(一)全局初始化

一&#xff0c;任何平台的客户端在使用WebRTC的API之前都需要进行一些初始化操作&#xff0c;主要是设置实验性功能开关&#xff0c;初始化SSL&#xff0c;当然也可以启用trace,设置日志输出等。 Windows和Linux端的初始化 rtc::WinsockInitializer winsock_init;rtc::Win32So…

ibm服务器芯片架构,IBM x366 服务器技术详解

背景资料IBM eServer x366 提供了突破性的 4 路性能&#xff0c;采用机架优化的 3U服务器设计&#xff0c;结合了源自大型机灵感的 eServer X3技术的高可用性&#xff0c;具有最新 64 位Intel Xeon MP 处理器带来的 64位性能&#xff0c;可创建面向商业企业应用程序、虚拟化及 …

python函数调用自身后果_python 写函数在一定条件下需要调用自身时的写法说明...

例如以下这个函数&#xff1a;state 1 def set_state(state): while state: set int(input(请输入9或5,显示"hello world"\n)) if set 9 or set 5: print(hello world) state int(input(输入1继续&#xff0c;输入0停止&#xff01;\n)) else: print(请输入要求…

python antlr_使用ANTLR在5分钟内用Java解析任何语言:例如Python

python antlr我喜欢出于多种目的处理代码&#xff0c;例如静态分析或自动重构。 对我来说&#xff0c;有趣的部分是推理从抽象语法树&#xff08;AST&#xff09;构建的模型。 为此&#xff0c;您需要一种从源文件中获取AST的方法。 可以使用ANTLR轻松完成此操作&#xff0c;并…

【WebRTC---源码篇】(二)PeerConnectionFactory

在初始化之后,使用PC之前需要先创建和初始化PeerConnectionFactory对象,因为PC的创建使用了工厂模式。实现在InitializePeerConnection()中实现,其中还调用了 PC的创建以及添加相关轨 //创建PC Factory,这个函数会在用户呼叫对方,或者收到对方呼叫信息时调用 bool Conducto…

服务器安装虚拟交换机,虚拟交换机配置如何操作?虚拟交换机配置步骤有哪些...

很多朋友在做虚拟交换机配置的时候&#xff0c;不知道如具体的操作方法&#xff0c;下面新网就给大家详细的介绍下虚拟交换机配置如何操作以及虚拟交换机配置步骤有哪些等问题&#xff0c;以供参考。虚拟交换机配置方法1.先安装驱动D:\Company\S5700S-28P-LI-AC\驱动\S5700系列…

rostcm6情感分析案例分析_卷积情感分析

这是一个面向小白(比如&#xff0c;本人)的关于情感分析的系列教程 [1]。老鸽子整理了“4 - Convolutional Sentiment Analysis.ipynb”中的内容。本文任务&#xff1a;使用卷积神经网络(CNN)来实现句子分类。简介CNN用于分析图像&#xff0c;包含一个或多个卷积层&#xff0c;…

java jigsaw_60秒内使用Java 9的Project Jigsaw的JavaFX HelloWorld

java jigsaw到目前为止&#xff0c;您可能已经听说过Java 9的新模块系统&#xff0c;即项目Jigsaw。 如果您不了解Java 9的新模块系统&#xff0c;则应该访问Mark Reinhold的论文“模块系统的状态” 。 另外&#xff0c;您应该在nipafx上查看 Nicolai Parlog的优秀博客&#xf…

C++ 11 深度学习(三)范围for、new内存动态分配、nullptr

1.范围for 作用&#xff1a;用于遍历一个序列&#xff0c;例&#xff1a; int v[]{ 1,2,3,4,5,6 };for (auto x : v)//数组v中每个元素&#xff0c;依次放入x中;cout << x << endl; 2.new和delete new和delete是C中的两个关键字&#xff0c;其中new 先执行mallo…