海沧做网站,常州建设工程交易网,html网页设计作品下载,hk网站域名项目采用工程模式进行构造。
技术解决难点#xff1a;
1.编码后的PTS时间一定要赋值。2.音视频封装同步问题#xff0c;其中涉及到PTS同步问题#xff0c;例如视频25PTS/s 音频43PTS/s#xff08;44100采样率/1024每帧#xff09;#xff0c;音频要慢于视频所以这种情…项目采用工程模式进行构造。
技术解决难点
1.编码后的PTS时间一定要赋值。2.音视频封装同步问题其中涉及到PTS同步问题例如视频25PTS/s 音频43PTS/s44100采样率/1024每帧音频要慢于视频所以这种情况下要进行PTS同步计算处理.
主要代码如下
XVideoWriter.h
#pragma once
#includestring
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 index0);~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
#includeiostream
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;}pav_packet_alloc();//一次发送可能多次接收ret avcodec_receive_packet(vc,p);if (ret ! 0 || p-size0){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 writefilename 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 函数。程序执行将在此处开始并结束。
//
#includeXVideoWriter.h
#include iostreamint 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;
}
项目链接