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

技术解决难点:

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;
}

项目链接

【开源项目】基于FFmpeg的PCM和RGB数据统一封装相关推荐

  1. DoNet开源项目-基于jQuery EasyUI的后台管理系统

    本文转载于 石佳劼的博客,有问题请到原文咨询,原文连接. 博主在业余时间开发了一个简单的后台管理系统,其中用到了 jQuery EasyUI 框架,上次分享过系统布局,参考文章:jQuery Easy ...

  2. DoNet开源项目-基于Amaze UI的点餐系统

    本文转载于 石佳劼的博客,有问题请到原文咨询,原文连接. 点餐系统 帮朋友做的点餐系统,主要是为了让顾客在餐桌上,使用微信扫描二维码,就可以直接点菜,吃完使用微信付款. 系统演示地址,账户名和密码均为 ...

  3. 【开源项目】QT播放PCM音频实例详细

    #include<QtCore/QCoreApplication> #include<QAudioFormat> #include<QAudioOutput> #i ...

  4. 开源项目-基于Intel VT技术的Linux内核调试器

    本开源项目将硬件虚拟化技术应用在内核调试器上,使内核调试器成为VMM,将操作系统置于虚拟机中运行,即操作系统成为GuestOS,以这样的一种形式进行调试,最主要的好处就是调试器对操作系统完全透明.如下 ...

  5. Web 自动化解决方案 [开源项目] 基于 Selenium 的 Web 自动化测试框架完美版

    欢迎查阅Selenium(Web自动化测试框架体系) Selenium ) Selenium是一个用于Web应用程序的自动化测试工具,直接运行在浏览器中,就像真正的用户在操作一样• 支持的浏览器包括I ...

  6. 开源项目-基于小熊派STM32红外热成像仪

    点击上方"嵌入式应用研究院",选择"置顶/星标公众号" 干货福利,第一时间送达! 来源 | 嵌入式应用研究院 整理&排版 | 嵌入式应用研究院 中秋假期 ...

  7. 【开源项目】基于FFmpeg的PCM数据编码为AAC

    /* * 一笑奈何 * cn-yixiaonaihe.blog.csdn.net */#include <iostream> #include <thread> extern ...

  8. [开源项目]基于FPGA的视频图像拼接融合

    基于FPGA的视频图像拼接融合 本项目简单来说,就是实时生成视频全景图,该架构经过优化,可以实时视频输出. 算法 下图说明了描述算法每个步骤的系统框图 该系统大致可以分为三个子系统: 预处理 基于 S ...

  9. TestCaseManageSystem 自动化解决方案 [开源项目] 基于 AgileTC 的测试用例自动化框架完美版

    欢迎查阅TestCaseManageSystem(测试用例管理系统) AgileTC  TestCaseManageSystem是一套敏捷的测试用例管理平台,支持测试用例管理.执行计划管理.进度计算. ...

最新文章

  1. 使用VS2019开始第一个C语言程序,环境安装配置+代码实例
  2. 探讨.NET Core数据进行3DES加密和解密问题
  3. JVM的常用配置参数
  4. plsql(轻量版)_基本语法
  5. DjangoORM框架
  6. Linux 终端环境安装 L2TP 客户端
  7. 西安4年java多少时间_西安学习java一般要多久
  8. 一步步编写操作系统 42 用c语言编写内核
  9. [literature]地下铁文本
  10. 枚举值是什么意思_期权的Theta值是什么意思?有什么意义?
  11. 写个脚本快速启动前后端
  12. xg push sdk android,AppCan文档中心-uexXGPush
  13. android截屏与截长图截屏功能的实现
  14. 考勤 指纹 php,折腾中控指纹签到SDK始末(.net监听) | quericy Eden*
  15. leetcode *1818. 绝对差值和(2021.7.14)
  16. FastReport for Delphi
  17. python3*1**3 表达式输出结果为_22 % 3 表达式输出结果为________
  18. 字符版本贪吃蛇游戏设计及算法
  19. 【Spark GraphX】社交网图分析
  20. 计算机测试的论文,软件测试毕业论文-软件工程论文-计算机论文.docx

热门文章

  1. Gradle善良:仅添加包装用于战争
  2. slf4j绑定器_用于ADFLogger的SLF4J绑定–缺少的部分
  3. apache camel_Apache Camel –从头开始开发应用程序(第2部分/第2部分)
  4. Java命令行界面(第14部分):google-options
  5. JavaParser入门:以编程方式分析Java代码
  6. Java 8:再见手册SQL,您好!
  7. akka_Akka的字数统计MapReduce
  8. weblogic最大线程_处理Weblogic卡住的线程
  9. Java TDD简介–第1部分
  10. 计划Java EE 7批处理作业