diff --git a/api/include/mk_media.h b/api/include/mk_media.h index 69f1f0ff..4936daf1 100755 --- a/api/include/mk_media.h +++ b/api/include/mk_media.h @@ -38,42 +38,24 @@ API_EXPORT mk_media API_CALL mk_media_create(const char *vhost, const char *app, API_EXPORT void API_CALL mk_media_release(mk_media ctx); /** - * 添加h264视频轨道 + * 添加视频轨道 * @param ctx 对象指针 + * @param track_id 0:CodecH264/1:CodecH265 * @param width 视频宽度 * @param height 视频高度 * @param fps 视频fps */ -API_EXPORT void API_CALL mk_media_init_h264(mk_media ctx, int width, int height, int fps); +API_EXPORT void API_CALL mk_media_init_video(mk_media ctx, int track_id, int width, int height, int fps); /** - * 添加h265视频轨道 + * 添加音频轨道 * @param ctx 对象指针 - * @param width 视频宽度 - * @param height 视频高度 - * @param fps 视频fps - */ -API_EXPORT void API_CALL mk_media_init_h265(mk_media ctx, int width, int height, int fps); - -/** - * 添加aac音频轨道 - * @param ctx 对象指针 - * @param channel 通道数 - * @param sample_bit 采样位数,只支持16 - * @param sample_rate 采样率 - * @param profile aac编码profile,在不输入adts头时用于生产adts头 - */ -API_EXPORT void API_CALL mk_media_init_aac(mk_media ctx, int channel, int sample_bit, int sample_rate, int profile); - -/** - * 添加g711音频轨道 - * @param ctx 对象指针 - * @param au 3 : G711A 4: G711U + * @param track_id 2:CodecAAC/3:CodecG711A/4:CodecG711U * @param channel 通道数 * @param sample_bit 采样位数,只支持16 * @param sample_rate 采样率 */ -API_EXPORT void API_CALL mk_media_init_g711(mk_media ctx, int au, int sample_bit, int sample_rate); +API_EXPORT void API_CALL mk_media_init_audio(mk_media ctx, int track_id, int sample_rate, int channels, int sample_bit); /** * 初始化h264/h265/aac完毕后调用此函数, @@ -103,16 +85,6 @@ API_EXPORT void API_CALL mk_media_input_h264(mk_media ctx, void *data, int len, */ API_EXPORT void API_CALL mk_media_input_h265(mk_media ctx, void *data, int len, uint32_t dts, uint32_t pts); -/** - * 输入单帧AAC音频 - * @param ctx 对象指针 - * @param data 单帧AAC数据 - * @param len 单帧AAC数据字节数 - * @param dts 时间戳,毫秒 - * @param with_adts_header data中是否包含7个字节的adts头 - */ -API_EXPORT void API_CALL mk_media_input_aac(mk_media ctx, void *data, int len, uint32_t dts, int with_adts_header); - /** * 输入单帧AAC音频(单独指定adts头) * @param ctx 对象指针 @@ -121,7 +93,7 @@ API_EXPORT void API_CALL mk_media_input_aac(mk_media ctx, void *data, int len, u * @param dts 时间戳,毫秒 * @param adts adts头 */ -API_EXPORT void API_CALL mk_media_input_aac1(mk_media ctx, void *data, int len, uint32_t dts, void *adts); +API_EXPORT void API_CALL mk_media_input_aac(mk_media ctx, void *data, int len, uint32_t dts, void *adts); /** * 输入单帧G711音频 diff --git a/api/source/mk_media.cpp b/api/source/mk_media.cpp index 082816b7..4e92e594 100755 --- a/api/source/mk_media.cpp +++ b/api/source/mk_media.cpp @@ -109,50 +109,25 @@ API_EXPORT void API_CALL mk_media_release(mk_media ctx) { delete obj; } -API_EXPORT void API_CALL mk_media_init_h264(mk_media ctx, int width, int height, int frameRate) { +API_EXPORT void API_CALL mk_media_init_video(mk_media ctx, int track_id, int width, int height, int fps){ assert(ctx); MediaHelper::Ptr *obj = (MediaHelper::Ptr *) ctx; VideoInfo info; - info.codecId = CodecH264; - info.iFrameRate = frameRate; + info.codecId = (CodecId)track_id; + info.iFrameRate = fps; info.iWidth = width; info.iHeight = height; (*obj)->getChannel()->initVideo(info); } -API_EXPORT void API_CALL mk_media_init_h265(mk_media ctx, int width, int height, int frameRate) { - assert(ctx); - MediaHelper::Ptr *obj = (MediaHelper::Ptr *) ctx; - VideoInfo info; - info.codecId = CodecH265; - info.iFrameRate = frameRate; - info.iWidth = width; - info.iHeight = height; - (*obj)->getChannel()->initVideo(info); -} - -API_EXPORT void API_CALL mk_media_init_aac(mk_media ctx, int channel, int sample_bit, int sample_rate, int profile) { +API_EXPORT void API_CALL mk_media_init_audio(mk_media ctx, int track_id, int sample_rate, int channels, int sample_bit){ assert(ctx); MediaHelper::Ptr *obj = (MediaHelper::Ptr *) ctx; AudioInfo info; - info.codecId = CodecAAC; + info.codecId = (CodecId)track_id; info.iSampleRate = sample_rate; - info.iChannel = channel; + info.iChannel = channels; info.iSampleBit = sample_bit; - info.iProfile = profile; - (*obj)->getChannel()->initAudio(info); -} - -API_EXPORT void API_CALL mk_media_init_g711(mk_media ctx, int au, int sample_bit, int sample_rate){ - assert(ctx); - assert(au == CodecG711A || au == CodecG711U); - MediaHelper::Ptr* obj = (MediaHelper::Ptr*) ctx; - AudioInfo info; - info.codecId = (CodecId)au; - info.iSampleRate = sample_rate; - info.iChannel = 1; - info.iSampleBit = sample_bit; - info.iProfile = 0; (*obj)->getChannel()->initAudio(info); } @@ -174,13 +149,7 @@ API_EXPORT void API_CALL mk_media_input_h265(mk_media ctx, void *data, int len, (*obj)->getChannel()->inputH265((char *) data, len, dts, pts); } -API_EXPORT void API_CALL mk_media_input_aac(mk_media ctx, void *data, int len, uint32_t dts, int with_adts_header) { - assert(ctx && data && len > 0); - MediaHelper::Ptr *obj = (MediaHelper::Ptr *) ctx; - (*obj)->getChannel()->inputAAC((char *) data, len, dts, with_adts_header); -} - -API_EXPORT void API_CALL mk_media_input_aac1(mk_media ctx, void *data, int len, uint32_t dts, void *adts) { +API_EXPORT void API_CALL mk_media_input_aac(mk_media ctx, void *data, int len, uint32_t dts, void *adts) { assert(ctx && data && len > 0 && adts); MediaHelper::Ptr *obj = (MediaHelper::Ptr *) ctx; (*obj)->getChannel()->inputAAC((char *) data, len, dts, (char *) adts); diff --git a/src/Common/Device.cpp b/src/Common/Device.cpp index 4ca91fac..e67578da 100644 --- a/src/Common/Device.cpp +++ b/src/Common/Device.cpp @@ -20,15 +20,15 @@ using namespace toolkit; namespace mediakit { -DevChannel::DevChannel(const string &strVhost, - const string &strApp, - const string &strId, - float fDuration, - bool bEanbleRtsp, - bool bEanbleRtmp, - bool bEanbleHls, - bool bEnableMp4) : - MultiMediaSourceMuxer(strVhost, strApp, strId, fDuration, bEanbleRtsp, bEanbleRtmp, bEanbleHls, bEnableMp4) {} +DevChannel::DevChannel(const string &vhost, + const string &app, + const string &stream_id, + float duration, + bool enable_rtsp, + bool enable_rtmp, + bool enable_hls, + bool enable_mp4) : + MultiMediaSourceMuxer(vhost, app, stream_id, duration, enable_rtsp, enable_rtmp, enable_hls, enable_mp4) {} DevChannel::~DevChannel() {} @@ -65,13 +65,13 @@ void DevChannel::inputPCM(char* pcData, int iDataLen, uint32_t uiStamp) { unsigned char *pucOut; int iRet = _pAacEnc->inputData(pcData, iDataLen, &pucOut); if (iRet > 0) { - inputAAC((char *) pucOut, iRet, uiStamp); + inputAAC((char *) pucOut + 7, iRet, uiStamp, pucOut); } } } #endif //ENABLE_FAAC -void DevChannel::inputH264(const char* pcData, int iDataLen, uint32_t dts,uint32_t pts) { +void DevChannel::inputH264(const char *data, int len, uint32_t dts, uint32_t pts) { if(dts == 0){ dts = (uint32_t)_aTicker[0].elapsedTime(); } @@ -79,24 +79,27 @@ void DevChannel::inputH264(const char* pcData, int iDataLen, uint32_t dts,uint32 pts = dts; } int prefixeSize; - if (memcmp("\x00\x00\x00\x01", pcData, 4) == 0) { + if (memcmp("\x00\x00\x00\x01", data, 4) == 0) { prefixeSize = 4; - } else if (memcmp("\x00\x00\x01", pcData, 3) == 0) { + } else if (memcmp("\x00\x00\x01", data, 3) == 0) { prefixeSize = 3; } else { prefixeSize = 0; } + //由于rtmp/hls/mp4需要缓存时间戳相同的帧, + //所以使用FrameNoCacheAble类型的帧反而会在转换成FrameCacheAble时多次内存拷贝 + //在此处只拷贝一次,性能开销更低 H264Frame::Ptr frame = std::make_shared(); frame->_dts = dts; frame->_pts = pts; frame->_buffer.assign("\x00\x00\x00\x01",4); - frame->_buffer.append(pcData + prefixeSize, iDataLen - prefixeSize); + frame->_buffer.append(data + prefixeSize, len - prefixeSize); frame->_prefix_size = 4; inputFrame(frame); } -void DevChannel::inputH265(const char* pcData, int iDataLen, uint32_t dts,uint32_t pts) { +void DevChannel::inputH265(const char *data, int len, uint32_t dts, uint32_t pts) { if(dts == 0){ dts = (uint32_t)_aTicker[0].elapsedTime(); } @@ -104,54 +107,66 @@ void DevChannel::inputH265(const char* pcData, int iDataLen, uint32_t dts,uint32 pts = dts; } int prefixeSize; - if (memcmp("\x00\x00\x00\x01", pcData, 4) == 0) { + if (memcmp("\x00\x00\x00\x01", data, 4) == 0) { prefixeSize = 4; - } else if (memcmp("\x00\x00\x01", pcData, 3) == 0) { + } else if (memcmp("\x00\x00\x01", data, 3) == 0) { prefixeSize = 3; } else { prefixeSize = 0; } + //由于rtmp/hls/mp4需要缓存时间戳相同的帧, + //所以使用FrameNoCacheAble类型的帧反而会在转换成FrameCacheAble时多次内存拷贝 + //在此处只拷贝一次,性能开销更低 H265Frame::Ptr frame = std::make_shared(); frame->_dts = dts; frame->_pts = pts; frame->_buffer.assign("\x00\x00\x00\x01",4); - frame->_buffer.append(pcData + prefixeSize, iDataLen - prefixeSize); + frame->_buffer.append(data + prefixeSize, len - prefixeSize); frame->_prefix_size = 4; inputFrame(frame); } -void DevChannel::inputAAC(const char* pcData, int iDataLen, uint32_t uiStamp,bool withAdtsHeader) { - if(withAdtsHeader){ - inputAAC(pcData+7,iDataLen-7,uiStamp,pcData); - } else if(_audio) { - inputAAC(pcData,iDataLen,uiStamp,(char *)_adtsHeader); +class AACFrameCacheAble : public AACFrameNoCacheAble{ +public: + template + AACFrameCacheAble(ARGS && ...args) : AACFrameNoCacheAble(std::forward(args)...){}; + virtual ~AACFrameCacheAble() { + delete [] _ptr; + }; + + bool cacheAble() const override { + return true; + } +}; + +void DevChannel::inputAAC(const char *data_without_adts, int len, uint32_t dts, const char *adts_header){ + if(dts == 0){ + dts = (uint32_t)_aTicker[1].elapsedTime(); + } + + if(adts_header){ + if(adts_header + 7 == data_without_adts){ + //adts头和帧再一起 + inputFrame(std::make_shared((char *)data_without_adts - 7, len + 7, dts, 0, 7)); + }else{ + //adts头和帧不再一起 + char *dataWithAdts = new char[len + 7]; + memcpy(dataWithAdts, adts_header, 7); + memcpy(dataWithAdts + 7 , data_without_adts , len); + inputFrame(std::make_shared(dataWithAdts, len + 7, dts, 0, 7)); + } } } -void DevChannel::inputAAC(const char *pcDataWithoutAdts,int iDataLen, uint32_t uiStamp,const char *pcAdtsHeader){ - if(uiStamp == 0){ - uiStamp = (uint32_t)_aTicker[1].elapsedTime(); - } - if(pcAdtsHeader + 7 == pcDataWithoutAdts){ - inputFrame(std::make_shared((char *)pcDataWithoutAdts - 7,iDataLen + 7,uiStamp,0,7)); - } else { - char *dataWithAdts = new char[iDataLen + 7]; - memcpy(dataWithAdts,pcAdtsHeader,7); - memcpy(dataWithAdts + 7 , pcDataWithoutAdts , iDataLen); - inputFrame(std::make_shared(dataWithAdts,iDataLen + 7,uiStamp,0,7)); - delete [] dataWithAdts; +void DevChannel::inputG711(const char *data, int len, uint32_t dts){ + if (dts == 0) { + dts = (uint32_t)_aTicker[1].elapsedTime(); } + inputFrame(std::make_shared(_audio->codecId, (char*)data, len, dts, 0)); } -void DevChannel::inputG711(const char* pcData, int iDataLen, uint32_t uiStamp){ - if (uiStamp == 0) { - uiStamp = (uint32_t)_aTicker[1].elapsedTime(); - } - inputFrame(std::make_shared(_audio->codecId, (char*)pcData, iDataLen, uiStamp, 0)); -} - -void DevChannel::initVideo(const VideoInfo& info) { +void DevChannel::initVideo(const VideoInfo &info) { _video = std::make_shared(info); switch (info.codecId){ case CodecH265 : addTrack(std::make_shared()); break; @@ -160,41 +175,10 @@ void DevChannel::initVideo(const VideoInfo& info) { } } -static void makeAdtsHeader(int profile, int sampleRate, int channels,uint8_t *out){ - AACFrame adtsHeader; - adtsHeader.syncword = 0x0FFF; - adtsHeader.id = 0; - adtsHeader.layer = 0; - adtsHeader.protection_absent = 1; - adtsHeader.profile = profile;//audioObjectType - 1; - int i = 0; - for (auto rate : samplingFrequencyTable) { - if (rate == sampleRate) { - adtsHeader.sf_index = i; - }; - ++i; - } - adtsHeader.private_bit = 0; - adtsHeader.channel_configuration = channels; - adtsHeader.original = 0; - adtsHeader.home = 0; - adtsHeader.copyright_identification_bit = 0; - adtsHeader.copyright_identification_start = 0; - adtsHeader.aac_frame_length = 7; - adtsHeader.adts_buffer_fullness = 2047; - adtsHeader.no_raw_data_blocks_in_frame = 0; - writeAdtsHeader(adtsHeader, out); -} - -void DevChannel::initAudio(const AudioInfo& info) { +void DevChannel::initAudio(const AudioInfo &info) { _audio = std::make_shared(info); switch (info.codecId) { - case CodecAAC : { - addTrack(std::make_shared()); - makeAdtsHeader(info.iProfile, info.iSampleBit, info.iChannel, _adtsHeader); - break; - } - + case CodecAAC : addTrack(std::make_shared()); break; case CodecG711A : case CodecG711U : addTrack(std::make_shared(info.codecId, info.iSampleRate, info.iChannel, info.iSampleBit)); break; default: WarnL << "不支持该类型的音频编码类型:" << info.codecId; break; diff --git a/src/Common/Device.h b/src/Common/Device.h index e7a1b24b..2e2d61f5 100644 --- a/src/Common/Device.h +++ b/src/Common/Device.h @@ -30,7 +30,6 @@ using namespace toolkit; #include "Codec/H264Encoder.h" #endif //ENABLE_X264 - namespace mediakit { class VideoInfo { @@ -40,90 +39,82 @@ public: int iHeight; float iFrameRate; }; + class AudioInfo { public: CodecId codecId = CodecAAC; int iChannel; int iSampleBit; int iSampleRate; - int iProfile; }; /** - * 该类已经废弃,保留只为兼容旧代码,请直接使用MultiMediaSourceMuxer类! + * MultiMediaSourceMuxer类的包装,方便初学者使用 */ class DevChannel : public MultiMediaSourceMuxer{ public: typedef std::shared_ptr Ptr; //fDuration<=0为直播,否则为点播 - DevChannel(const string &strVhost, - const string &strApp, - const string &strId, - float fDuration = 0, - bool bEanbleRtsp = true, - bool bEanbleRtmp = true, - bool bEanbleHls = true, - bool bEnableMp4 = false); + DevChannel(const string &vhost, + const string &app, + const string &stream_id, + float duration = 0, + bool enable_rtsp = true, + bool enable_rtmp = true, + bool enable_hls = true, + bool enable_mp4 = false); virtual ~DevChannel(); /** - * 初始化h264视频Track - * 相当于MultiMediaSourceMuxer::addTrack(H264Track::Ptr ); + * 初始化视频Track + * 相当于MultiMediaSourceMuxer::addTrack(VideoTrack::Ptr ); * @param info 视频相关信息 */ void initVideo(const VideoInfo &info); /** - * 初始化aac音频Track - * 相当于MultiMediaSourceMuxer::addTrack(AACTrack::Ptr ); + * 初始化音频Track + * 相当于MultiMediaSourceMuxer::addTrack(AudioTrack::Ptr ); * @param info 音频相关信息 */ void initAudio(const AudioInfo &info); /** * 输入264帧 - * @param pcData 264单帧数据指针 - * @param iDataLen 数据指针长度 + * @param data 264单帧数据指针 + * @param len 数据指针长度 * @param dts 解码时间戳,单位毫秒;等于0时内部会自动生成时间戳 * @param pts 播放时间戳,单位毫秒;等于0时内部会赋值为dts */ - void inputH264(const char *pcData, int iDataLen, uint32_t dts,uint32_t pts = 0); + void inputH264(const char *data, int len, uint32_t dts, uint32_t pts = 0); /** * 输入265帧 - * @param pcData 265单帧数据指针 - * @param iDataLen 数据指针长度 + * @param data 265单帧数据指针 + * @param len 数据指针长度 * @param dts 解码时间戳,单位毫秒;等于0时内部会自动生成时间戳 * @param pts 播放时间戳,单位毫秒;等于0时内部会赋值为dts */ - void inputH265(const char *pcData, int iDataLen, uint32_t dts,uint32_t pts = 0); + void inputH265(const char *data, int len, uint32_t dts, uint32_t pts = 0); /** - * 输入可能带adts头的aac帧 - * @param pcDataWithAdts 可能带adts头的aac帧 - * @param iDataLen 帧数据长度 - * @param uiStamp 时间戳,单位毫秒,等于0时内部会自动生成时间戳 - * @param withAdtsHeader 是否带adts头 + * 输入aac帧 + * @param data_without_adts 不带adts头的aac帧 + * @param len 帧数据长度 + * @param dts 时间戳,单位毫秒 + * @param adts_header adts头 */ - void inputAAC(const char *pcDataWithAdts, int iDataLen, uint32_t uiStamp, bool withAdtsHeader = true); - - /** - * 输入不带adts头的aac帧 - * @param pcDataWithoutAdts 不带adts头的aac帧 - * @param iDataLen 帧数据长度 - * @param uiStamp 时间戳,单位毫秒 - * @param pcAdtsHeader adts头 - */ - void inputAAC(const char *pcDataWithoutAdts,int iDataLen, uint32_t uiStamp,const char *pcAdtsHeader); + void inputAAC(const char *data_without_adts, int len, uint32_t dts, const char *adts_header); /** * G711音频帧 - * @param pcData 音频帧 - * @param iDataLen 帧数据长度 - * @param uiStamp 时间戳,单位毫秒 + * @param data 音频帧 + * @param len 帧数据长度 + * @param dts 时间戳,单位毫秒 */ - void inputG711(const char* pcData, int iDataLen, uint32_t uiStamp); + void inputG711(const char* data, int len, uint32_t dts); + #ifdef ENABLE_X264 /** * 输入yuv420p视频帧,内部会完成编码并调用inputH264方法 @@ -146,6 +137,7 @@ public: #endif //ENABLE_FAAC private: + #ifdef ENABLE_X264 std::shared_ptr _pH264Enc; #endif //ENABLE_X264 @@ -155,9 +147,7 @@ private: #endif //ENABLE_FAAC std::shared_ptr _video; std::shared_ptr _audio; - SmoothTicker _aTicker[2]; - uint8_t _adtsHeader[7]; }; } /* namespace mediakit */