diff --git a/api/include/mk_media.h b/api/include/mk_media.h index 87b8836d..8b7b5974 100755 --- a/api/include/mk_media.h +++ b/api/include/mk_media.h @@ -54,7 +54,7 @@ API_EXPORT void API_CALL mk_media_init_video(mk_media ctx, int track_id, int wid /** * 添加音频轨道 * @param ctx 对象指针 - * @param track_id 2:CodecAAC/3:CodecG711A/4:CodecG711U + * @param track_id 2:CodecAAC/3:CodecG711A/4:CodecG711U/5:OPUS * @param channel 通道数 * @param sample_bit 采样位数,只支持16 * @param sample_rate 采样率 @@ -95,7 +95,7 @@ API_EXPORT void API_CALL mk_media_input_h265(mk_media ctx, void *data, int len, * @param data 不包含adts头的单帧AAC数据 * @param len 单帧AAC数据字节数 * @param dts 时间戳,毫秒 - * @param adts adts头 + * @param adts adts头,可以为null */ API_EXPORT void API_CALL mk_media_input_aac(mk_media ctx, void *data, int len, uint32_t dts, void *adts); @@ -109,13 +109,13 @@ API_EXPORT void API_CALL mk_media_input_aac(mk_media ctx, void *data, int len, u API_EXPORT void API_CALL mk_media_input_pcm(mk_media ctx, void *data, int len, uint32_t pts); /** - * 输入单帧G711音频 + * 输入单帧OPUS/G711音频帧 * @param ctx 对象指针 - * @param data 单帧G711数据 - * @param len 单帧G711数据字节数 + * @param data 单帧音频数据 + * @param len 单帧音频数据字节数 * @param dts 时间戳,毫秒 */ -API_EXPORT void API_CALL mk_media_input_g711(mk_media ctx, void* data, int len, uint32_t dts); +API_EXPORT void API_CALL mk_media_input_audio(mk_media ctx, void* data, int len, uint32_t dts); /** * MediaSource.close()回调事件 diff --git a/api/include/mk_player.h b/api/include/mk_player.h index 342bf80a..555116a5 100755 --- a/api/include/mk_player.h +++ b/api/include/mk_player.h @@ -31,7 +31,7 @@ typedef void(API_CALL *on_mk_play_event)(void *user_data,int err_code,const char * 收到音视频数据回调 * @param user_data 用户数据指针 * @param track_type 0:视频,1:音频 - * @param codec_id 0:H264,1:H265,2:AAC 3.G711A 4.G711U + * @param codec_id 0:H264,1:H265,2:AAC 3.G711A 4.G711U 5.OPUS * @param data 数据指针 * @param len 数据长度 * @param dts 解码时间戳,单位毫秒 diff --git a/api/source/mk_media.cpp b/api/source/mk_media.cpp index bad5bf51..73f7b07b 100755 --- a/api/source/mk_media.cpp +++ b/api/source/mk_media.cpp @@ -188,8 +188,8 @@ API_EXPORT void API_CALL mk_media_input_pcm(mk_media ctx, void *data , int len, #endif //ENABLE_FAAC } -API_EXPORT void API_CALL mk_media_input_g711(mk_media ctx, void* data, int len, uint32_t dts){ +API_EXPORT void API_CALL mk_media_input_audio(mk_media ctx, void* data, int len, uint32_t dts){ assert(ctx && data && len > 0); MediaHelper::Ptr* obj = (MediaHelper::Ptr*) ctx; - (*obj)->getChannel()->inputG711((char*)data, len, dts); + (*obj)->getChannel()->inputAudio((char*)data, len, dts); } diff --git a/src/Common/Device.cpp b/src/Common/Device.cpp index 37a0056b..0231600f 100644 --- a/src/Common/Device.cpp +++ b/src/Common/Device.cpp @@ -12,22 +12,16 @@ #include "Util/logger.h" #include "Util/base64.h" #include "Extension/AAC.h" +#include "Extension/Opus.h" #include "Extension/G711.h" #include "Extension/H264.h" #include "Extension/H265.h" - using namespace toolkit; namespace mediakit { -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) : +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() {} @@ -109,11 +103,12 @@ void DevChannel::inputH265(const char *data, int len, uint32_t dts, uint32_t pts inputFrame(frame); } -class AACFrameCacheAble : public AACFrameNoCacheAble{ +class FrameAutoDelete : public FrameFromPtr{ public: template - AACFrameCacheAble(ARGS && ...args) : AACFrameNoCacheAble(std::forward(args)...){}; - virtual ~AACFrameCacheAble() { + FrameAutoDelete(ARGS && ...args) : FrameFromPtr(std::forward(args)...){} + + ~FrameAutoDelete() override { delete [] _ptr; }; @@ -123,31 +118,32 @@ public: }; 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 (dts == 0) { + dts = (uint32_t) _aTicker[1].elapsedTime(); } - if(adts_header){ - if(adts_header + 7 == data_without_adts){ + if (adts_header) { + if (adts_header + ADTS_HEADER_LEN == data_without_adts) { //adts头和帧在一起 - inputFrame(std::make_shared((char *)data_without_adts - 7, len + 7, dts, 0, 7)); - }else{ + inputFrame(std::make_shared(_audio->codecId, (char *) data_without_adts - ADTS_HEADER_LEN, len + ADTS_HEADER_LEN, dts, 0, ADTS_HEADER_LEN)); + } 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)); + char *data_with_adts = new char[len + ADTS_HEADER_LEN]; + memcpy(data_with_adts, adts_header, ADTS_HEADER_LEN); + memcpy(data_with_adts + ADTS_HEADER_LEN, data_without_adts, len); + inputFrame(std::make_shared(_audio->codecId, data_with_adts, len + ADTS_HEADER_LEN, dts, 0, ADTS_HEADER_LEN)); } + } else { + //没有adts头 + inputFrame(std::make_shared(_audio->codecId, (char *) data_without_adts, len, dts, 0, 0)); } } -void DevChannel::inputG711(const char *data, int len, uint32_t dts){ +void DevChannel::inputAudio(const char *data, int len, uint32_t dts){ if (dts == 0) { - dts = (uint32_t)_aTicker[1].elapsedTime(); + dts = (uint32_t) _aTicker[1].elapsedTime(); } - auto frame = std::make_shared((char*)data, len, dts, 0); - frame->setCodec(_audio->codecId); - inputFrame(frame); + inputFrame(std::make_shared(_audio->codecId, (char *) data, len, dts, 0)); } void DevChannel::initVideo(const VideoInfo &info) { @@ -165,6 +161,7 @@ void DevChannel::initAudio(const AudioInfo &info) { case CodecAAC : addTrack(std::make_shared()); break; case CodecG711A : case CodecG711U : addTrack(std::make_shared(info.codecId, info.iSampleRate, info.iChannel, info.iSampleBit)); break; + case CodecOpus : addTrack(std::make_shared()); break; default: WarnL << "不支持该类型的音频编码类型:" << info.codecId; break; } } diff --git a/src/Common/Device.h b/src/Common/Device.h index a2129d98..dbff5424 100644 --- a/src/Common/Device.h +++ b/src/Common/Device.h @@ -17,11 +17,9 @@ #include "Util/util.h" #include "Util/TimeTicker.h" #include "Common/MultiMediaSourceMuxer.h" - using namespace std; using namespace toolkit; - #ifdef ENABLE_FAAC #include "Codec/AACEncoder.h" #endif //ENABLE_FAAC @@ -55,16 +53,10 @@ class DevChannel : public MultiMediaSourceMuxer{ public: typedef std::shared_ptr Ptr; //fDuration<=0为直播,否则为点播 - 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); + 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(); + ~DevChannel() override ; /** * 初始化视频Track @@ -108,12 +100,12 @@ public: void inputAAC(const char *data_without_adts, int len, uint32_t dts, const char *adts_header); /** - * G711音频帧 + * 输入OPUS/G711音频帧 * @param data 音频帧 * @param len 帧数据长度 * @param dts 时间戳,单位毫秒 */ - void inputG711(const char* data, int len, uint32_t dts); + void inputAudio(const char *data, int len, uint32_t dts); #ifdef ENABLE_X264 /** diff --git a/src/Extension/AAC.h b/src/Extension/AAC.h index aa9dbb1e..21fa4322 100644 --- a/src/Extension/AAC.h +++ b/src/Extension/AAC.h @@ -21,41 +21,6 @@ string makeAacConfig(const uint8_t *hex, int length); int dumpAacConfig(const string &config, int length, uint8_t *out, int out_size); bool parseAacConfig(const string &config, int &samplerate, int &channels); -/** - * aac帧,包含adts头 - */ -class AACFrame : public FrameImp { -public: - typedef std::shared_ptr Ptr; - AACFrame(){ - _codecid = CodecAAC; - } -}; - -class AACFrameNoCacheAble : public FrameFromPtr { -public: - typedef std::shared_ptr Ptr; - - AACFrameNoCacheAble(char *ptr,uint32_t size,uint32_t dts,uint32_t pts = 0,int prefix_size = ADTS_HEADER_LEN){ - _ptr = ptr; - _size = size; - _dts = dts; - _prefix_size = prefix_size; - } - - CodecId getCodecId() const override{ - return CodecAAC; - } - - bool keyFrame() const override { - return false; - } - - bool configFrame() const override{ - return false; - } -}; - /** * aac音频通道 */ diff --git a/src/Extension/AACRtmp.cpp b/src/Extension/AACRtmp.cpp index c2e5de6c..30e60e02 100644 --- a/src/Extension/AACRtmp.cpp +++ b/src/Extension/AACRtmp.cpp @@ -43,7 +43,9 @@ bool AACRtmpDecoder::inputRtmp(const RtmpPacket::Ptr &pkt, bool) { } void AACRtmpDecoder::onGetAAC(const char* data, int len, uint32_t stamp) { - auto frame = ResourcePoolHelper::obtainObj(); + auto frame = ResourcePoolHelper::obtainObj(); + frame->_codec_id = CodecAAC; + //生成adts头 char adts_header[32] = {0}; auto size = dumpAacConfig(_aac_cfg, len, (uint8_t *) adts_header, sizeof(adts_header)); diff --git a/src/Extension/AACRtmp.h b/src/Extension/AACRtmp.h index dc7f0d62..2e4ef271 100644 --- a/src/Extension/AACRtmp.h +++ b/src/Extension/AACRtmp.h @@ -19,7 +19,7 @@ namespace mediakit{ /** * aac Rtmp转adts类 */ -class AACRtmpDecoder : public RtmpCodec , public ResourcePoolHelper { +class AACRtmpDecoder : public RtmpCodec , public ResourcePoolHelper { public: typedef std::shared_ptr Ptr; diff --git a/src/Extension/AACRtp.cpp b/src/Extension/AACRtp.cpp index 0140e277..8790cfeb 100644 --- a/src/Extension/AACRtp.cpp +++ b/src/Extension/AACRtp.cpp @@ -67,19 +67,19 @@ AACRtpDecoder::AACRtpDecoder(const Track::Ptr &track) { } else { _aac_cfg = aacTrack->getAacCfg(); } - _frame = obtainFrame(); + obtainFrame(); } AACRtpDecoder::AACRtpDecoder() { - _frame = obtainFrame(); + obtainFrame(); } -AACFrame::Ptr AACRtpDecoder::obtainFrame() { +void AACRtpDecoder::obtainFrame() { //从缓存池重新申请对象,防止覆盖已经写入环形缓存的对象 - auto frame = ResourcePoolHelper::obtainObj(); - frame->_prefix_size = 0; - frame->_buffer.clear(); - return frame; + _frame = ResourcePoolHelper::obtainObj(); + _frame->_prefix_size = 0; + _frame->_buffer.clear(); + _frame->_codec_id = CodecAAC; } bool AACRtpDecoder::inputRtp(const RtpPacket::Ptr &rtppack, bool key_pos) { @@ -143,11 +143,7 @@ void AACRtpDecoder::flushData() { _frame->_prefix_size = size; } RtpCodec::inputFrame(_frame); - _frame = obtainFrame(); + obtainFrame(); } - -}//namespace mediakit - - - +}//namespace mediakit \ No newline at end of file diff --git a/src/Extension/AACRtp.h b/src/Extension/AACRtp.h index fb9442a4..7e284c8e 100644 --- a/src/Extension/AACRtp.h +++ b/src/Extension/AACRtp.h @@ -17,7 +17,7 @@ namespace mediakit{ /** * aac rtp转adts类 */ -class AACRtpDecoder : public RtpCodec , public ResourcePoolHelper { +class AACRtpDecoder : public RtpCodec , public ResourcePoolHelper { public: typedef std::shared_ptr Ptr; @@ -39,11 +39,11 @@ protected: AACRtpDecoder(); private: - AACFrame::Ptr obtainFrame(); + void obtainFrame(); void flushData(); private: - AACFrame::Ptr _frame; + FrameImp::Ptr _frame; string _aac_cfg; uint32_t _last_dts = 0; }; diff --git a/src/Extension/CommonRtmp.cpp b/src/Extension/CommonRtmp.cpp new file mode 100644 index 00000000..db6bcbfd --- /dev/null +++ b/src/Extension/CommonRtmp.cpp @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved. + * + * This file is part of ZLMediaKit(https://github.com/xiongziliang/ZLMediaKit). + * + * Use of this source code is governed by MIT license that can be found in the + * LICENSE file in the root of the source tree. All contributing project authors + * may be found in the AUTHORS file in the root of the source tree. + */ + +#include "CommonRtmp.h" + +namespace mediakit{ + +CommonRtmpDecoder::CommonRtmpDecoder(CodecId codec) { + _codec = codec; + obtainFrame(); +} + +CodecId CommonRtmpDecoder::getCodecId() const { + return _codec; +} + +void CommonRtmpDecoder::obtainFrame() { + //从缓存池重新申请对象,防止覆盖已经写入环形缓存的对象 + _frame = ResourcePoolHelper::obtainObj(); + _frame->_buffer.clear(); + _frame->_codec_id = _codec; + _frame->_prefix_size = 0; +} + +bool CommonRtmpDecoder::inputRtmp(const RtmpPacket::Ptr &rtmp, bool) { + //拷贝负载 + _frame->_buffer.assign(rtmp->strBuf.data() + 1, rtmp->strBuf.size() - 1); + _frame->_dts = rtmp->timeStamp; + //写入环形缓存 + RtmpCodec::inputFrame(_frame); + //创建下一帧 + obtainFrame(); + return false; +} + +///////////////////////////////////////////////////////////////////////////////////// + +CommonRtmpEncoder::CommonRtmpEncoder(const Track::Ptr &track) : CommonRtmpDecoder(track->getCodecId()) { + _audio_flv_flags = getAudioRtmpFlags(track); +} + +void CommonRtmpEncoder::inputFrame(const Frame::Ptr &frame) { + if (!_audio_flv_flags) { + return; + } + RtmpPacket::Ptr rtmp = ResourcePoolHelper::obtainObj(); + rtmp->strBuf.clear(); + //header + rtmp->strBuf.push_back(_audio_flv_flags); + //data + rtmp->strBuf.append(frame->data() + frame->prefixSize(), frame->size() - frame->prefixSize()); + rtmp->bodySize = rtmp->strBuf.size(); + rtmp->chunkId = CHUNK_AUDIO; + rtmp->streamId = STREAM_MEDIA; + rtmp->timeStamp = frame->dts(); + rtmp->typeId = MSG_AUDIO; + RtmpCodec::inputRtmp(rtmp, false); +} + +}//namespace mediakit \ No newline at end of file diff --git a/src/Extension/CommonRtmp.h b/src/Extension/CommonRtmp.h new file mode 100644 index 00000000..6624a474 --- /dev/null +++ b/src/Extension/CommonRtmp.h @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved. + * + * This file is part of ZLMediaKit(https://github.com/xiongziliang/ZLMediaKit). + * + * Use of this source code is governed by MIT license that can be found in the + * LICENSE file in the root of the source tree. All contributing project authors + * may be found in the AUTHORS file in the root of the source tree. + */ + +#ifndef ZLMEDIAKIT_COMMONRTMP_H +#define ZLMEDIAKIT_COMMONRTMP_H + +#include "Frame.h" +#include "Rtmp/RtmpCodec.h" + +namespace mediakit{ + +/** + * 通用 rtmp解码类 + */ +class CommonRtmpDecoder : public RtmpCodec , public ResourcePoolHelper { +public: + typedef std::shared_ptr Ptr; + + ~CommonRtmpDecoder() override {} + + /** + * 构造函数 + * @param codec 编码id + */ + CommonRtmpDecoder(CodecId codec); + + /** + * 返回编码类型ID + */ + CodecId getCodecId() const override; + + /** + * 输入Rtmp并解码 + * @param rtmp Rtmp数据包 + * @param key_pos 此参数内部强制转换为false,请忽略之 + */ + bool inputRtmp(const RtmpPacket::Ptr &rtmp, bool key_pos = false) override; + +private: + void obtainFrame(); + +private: + CodecId _codec; + FrameImp::Ptr _frame; +}; + +/** + * 通用 rtmp编码类 + */ +class CommonRtmpEncoder : public CommonRtmpDecoder , public ResourcePoolHelper { +public: + typedef std::shared_ptr Ptr; + + CommonRtmpEncoder(const Track::Ptr &track); + ~CommonRtmpEncoder() override{} + + /** + * 输入帧数据 + */ + void inputFrame(const Frame::Ptr &frame) override; + +private: + uint8_t _audio_flv_flags = 0; +}; + +}//namespace mediakit +#endif //ZLMEDIAKIT_COMMONRTMP_H diff --git a/src/Extension/CommonRtp.cpp b/src/Extension/CommonRtp.cpp new file mode 100644 index 00000000..243b96c9 --- /dev/null +++ b/src/Extension/CommonRtp.cpp @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved. + * + * This file is part of ZLMediaKit(https://github.com/xiongziliang/ZLMediaKit). + * + * Use of this source code is governed by MIT license that can be found in the + * LICENSE file in the root of the source tree. All contributing project authors + * may be found in the AUTHORS file in the root of the source tree. + */ + +#include "CommonRtp.h" + +#define MAX_FRAME_SIZE 2 * 1024 + +CommonRtpDecoder::CommonRtpDecoder(CodecId codec){ + _codec = codec; + obtainFrame(); +} + +CodecId CommonRtpDecoder::getCodecId() const { + return _codec; +} + +void CommonRtpDecoder::obtainFrame() { + _frame = ResourcePoolHelper::obtainObj(); + _frame->_buffer.clear(); + _frame->_prefix_size = 0; + _frame->_dts = 0; + _frame->_codec_id = _codec; +} + +bool CommonRtpDecoder::inputRtp(const RtpPacket::Ptr &rtp, bool){ + auto payload = rtp->data() + rtp->offset; + auto size = rtp->size() - rtp->offset; + if (size <= 0) { + //无实际负载 + return false; + } + + if (_frame->_dts != rtp->timeStamp || _frame->_buffer.size() > MAX_FRAME_SIZE) { + //时间戳发生变化或者缓存超过MAX_FRAME_SIZE,则清空上帧数据 + if (!_frame->_buffer.empty()) { + //有有效帧,则输出 + RtpCodec::inputFrame(_frame); + } + + //新的一帧数据 + obtainFrame(); + _frame->_dts = rtp->timeStamp; + _drop_flag = false; + } else if (_last_seq != 0 && _last_seq + (uint16_t) 1 != rtp->sequence) { + //时间戳未发生变化,但是seq却不连续,说明中间rtp丢包了,那么整帧应该废弃 + WarnL << "rtp丢包:" << _last_seq << " -> " << rtp->sequence; + _drop_flag = true; + _frame->_buffer.clear(); + } + + if (!_drop_flag) { + _frame->_buffer.append(payload, size); + } + + _last_seq = rtp->sequence; + return false; +} + +//////////////////////////////////////////////////////////////// + +CommonRtpEncoder::CommonRtpEncoder(CodecId codec, uint32_t ssrc, uint32_t mtu_size, + uint32_t sample_rate, uint8_t payload_type, uint8_t interleaved) + : CommonRtpDecoder(codec), RtpInfo(ssrc, mtu_size, sample_rate, payload_type, interleaved) { +} + +void CommonRtpEncoder::inputFrame(const Frame::Ptr &frame){ + GET_CONFIG(uint32_t, cycleMS, Rtp::kCycleMS); + auto stamp = frame->dts() % cycleMS; + auto ptr = frame->data() + frame->prefixSize(); + auto len = frame->size() - frame->prefixSize(); + auto remain_size = len; + const auto max_rtp_size = _ui32MtuSize - 20; + + while (remain_size > 0) { + auto rtp_size = remain_size > max_rtp_size ? max_rtp_size : remain_size; + RtpCodec::inputRtp(makeRtp(getTrackType(), ptr, rtp_size, false, stamp), false); + ptr += rtp_size; + remain_size -= rtp_size; + } +} \ No newline at end of file diff --git a/src/Extension/CommonRtp.h b/src/Extension/CommonRtp.h new file mode 100644 index 00000000..22c89ad1 --- /dev/null +++ b/src/Extension/CommonRtp.h @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved. + * + * This file is part of ZLMediaKit(https://github.com/xiongziliang/ZLMediaKit). + * + * Use of this source code is governed by MIT license that can be found in the + * LICENSE file in the root of the source tree. All contributing project authors + * may be found in the AUTHORS file in the root of the source tree. + */ + +#ifndef ZLMEDIAKIT_COMMONRTP_H +#define ZLMEDIAKIT_COMMONRTP_H + +#include "Frame.h" +#include "Rtsp/RtpCodec.h" + +namespace mediakit{ + +/** + * 通用 rtp解码类 + */ +class CommonRtpDecoder : public RtpCodec, public ResourcePoolHelper { +public: + typedef std::shared_ptr Ptr; + + ~CommonRtpDecoder() override {} + + /** + * 构造函数 + * @param codec 编码id + */ + CommonRtpDecoder(CodecId codec); + + /** + * 返回编码类型ID + */ + CodecId getCodecId() const override; + + /** + * 输入rtp并解码 + * @param rtp rtp数据包 + * @param key_pos 此参数内部强制转换为false,请忽略之 + */ + bool inputRtp(const RtpPacket::Ptr &rtp, bool key_pos = false) override; + +private: + void obtainFrame(); + +private: + CodecId _codec; + FrameImp::Ptr _frame; + uint16_t _last_seq = 0; + bool _drop_flag = false; +}; + +/** + * 通用 rtp编码类 + */ +class CommonRtpEncoder : public CommonRtpDecoder, public RtpInfo { +public: + typedef std::shared_ptr Ptr; + + ~CommonRtpEncoder() override {} + + /** + * 构造函数 + * @param codec 编码类型 + * @param ssrc ssrc + * @param mtu_size mtu 大小 + * @param sample_rate 采样率 + * @param payload_type pt类型 + * @param interleaved rtsp interleaved 值 + */ + CommonRtpEncoder(CodecId codec, uint32_t ssrc, uint32_t mtu_size, uint32_t sample_rate, uint8_t payload_type, uint8_t interleaved); + + /** + * 输入帧数据并编码成rtp + */ + void inputFrame(const Frame::Ptr &frame) override; +}; + +}//namespace mediakit +#endif //ZLMEDIAKIT_COMMONRTP_H diff --git a/src/Extension/Factory.cpp b/src/Extension/Factory.cpp index 92771f38..fba7109b 100644 --- a/src/Extension/Factory.cpp +++ b/src/Extension/Factory.cpp @@ -13,11 +13,13 @@ #include "H264Rtmp.h" #include "H265Rtmp.h" #include "AACRtmp.h" -#include "G711Rtmp.h" +#include "CommonRtmp.h" #include "H264Rtp.h" #include "AACRtp.h" -#include "G711Rtp.h" #include "H265Rtp.h" +#include "CommonRtp.h" +#include "Opus.h" +#include "G711.h" #include "Common/Parser.h" namespace mediakit{ @@ -42,6 +44,10 @@ Track::Ptr Factory::getTrackBySdp(const SdpTrack::Ptr &track) { return std::make_shared(aac_cfg); } + if (strcasecmp(track->_codec.data(), "opus") == 0) { + return std::make_shared(); + } + if (strcasecmp(track->_codec.data(), "PCMA") == 0) { return std::make_shared(CodecG711A, track->_samplerate, track->_channel, 16); } @@ -114,11 +120,12 @@ RtpCodec::Ptr Factory::getRtpEncoderBySdp(const Sdp::Ptr &sdp) { auto interleaved = sdp->getTrackType() * 2; auto codec_id = sdp->getCodecId(); switch (codec_id){ - case CodecH264 : return std::make_shared(ssrc,mtu,sample_rate,pt,interleaved); - case CodecH265 : return std::make_shared(ssrc,mtu,sample_rate,pt,interleaved); - case CodecAAC : return std::make_shared(ssrc,mtu,sample_rate,pt,interleaved); + case CodecH264 : return std::make_shared(ssrc, mtu, sample_rate, pt, interleaved); + case CodecH265 : return std::make_shared(ssrc, mtu, sample_rate, pt, interleaved); + case CodecAAC : return std::make_shared(ssrc, mtu, sample_rate, pt, interleaved); + case CodecOpus : case CodecG711A : - case CodecG711U : return std::make_shared(codec_id, ssrc, mtu, sample_rate, pt, interleaved); + case CodecG711U : return std::make_shared(codec_id, ssrc, mtu, sample_rate, pt, interleaved); default : WarnL << "暂不支持该CodecId:" << codec_id; return nullptr; } } @@ -128,8 +135,9 @@ RtpCodec::Ptr Factory::getRtpDecoderByTrack(const Track::Ptr &track) { case CodecH264 : return std::make_shared(); case CodecH265 : return std::make_shared(); case CodecAAC : return std::make_shared(track->clone()); + case CodecOpus : case CodecG711A : - case CodecG711U : return std::make_shared(track->getCodecId()); + case CodecG711U : return std::make_shared(track->getCodecId()); default : WarnL << "暂不支持该CodecId:" << track->getCodecName(); return nullptr; } } @@ -137,40 +145,35 @@ RtpCodec::Ptr Factory::getRtpDecoderByTrack(const Track::Ptr &track) { /////////////////////////////rtmp相关/////////////////////////////////////////// static CodecId getVideoCodecIdByAmf(const AMFValue &val){ - if (val.type() == AMF_STRING){ + if (val.type() == AMF_STRING) { auto str = val.as_string(); - if(str == "avc1"){ + if (str == "avc1") { return CodecH264; } - if(str == "mp4a"){ - return CodecAAC; - } - if(str == "hev1" || str == "hvc1"){ + if (str == "hev1" || str == "hvc1") { return CodecH265; } - WarnL << "暂不支持该Amf:" << str; + WarnL << "暂不支持该视频Amf:" << str; return CodecInvalid; } - if (val.type() != AMF_NULL){ + if (val.type() != AMF_NULL) { auto type_id = val.as_integer(); - switch (type_id){ - case FLV_CODEC_H264: return CodecH264; - case FLV_CODEC_AAC: return CodecAAC; - case FLV_CODEC_H265: return CodecH265; - default : WarnL << "暂不支持该Amf:" << type_id; return CodecInvalid; + switch (type_id) { + case FLV_CODEC_H264 : return CodecH264; + case FLV_CODEC_H265 : return CodecH265; + default : WarnL << "暂不支持该视频Amf:" << type_id; return CodecInvalid; } } - return CodecInvalid; } - Track::Ptr getTrackByCodecId(CodecId codecId, int sample_rate = 0, int channels = 0, int sample_bit = 0) { switch (codecId){ case CodecH264 : return std::make_shared(); case CodecH265 : return std::make_shared(); case CodecAAC : return std::make_shared(); + case CodecOpus: return std::make_shared(); case CodecG711A : case CodecG711U : return (sample_rate && channels && sample_bit) ? std::make_shared(codecId, sample_rate, channels, sample_bit) : nullptr; default : WarnL << "暂不支持该CodecId:" << codecId; return nullptr; @@ -191,7 +194,7 @@ static CodecId getAudioCodecIdByAmf(const AMFValue &val) { if (str == "mp4a") { return CodecAAC; } - WarnL << "暂不支持该Amf:" << str; + WarnL << "暂不支持该音频Amf:" << str; return CodecInvalid; } @@ -201,7 +204,8 @@ static CodecId getAudioCodecIdByAmf(const AMFValue &val) { case FLV_CODEC_AAC : return CodecAAC; case FLV_CODEC_G711A : return CodecG711A; case FLV_CODEC_G711U : return CodecG711U; - default : WarnL << "暂不支持该Amf:" << type_id; return CodecInvalid; + case FLV_CODEC_OPUS : return CodecOpus; + default : WarnL << "暂不支持该音频Amf:" << type_id; return CodecInvalid; } } @@ -221,6 +225,7 @@ RtmpCodec::Ptr Factory::getRtmpCodecByTrack(const Track::Ptr &track, bool is_enc case CodecH264 : return std::make_shared(track); case CodecAAC : return std::make_shared(track); case CodecH265 : return std::make_shared(track); + case CodecOpus : return std::make_shared(track); case CodecG711A : case CodecG711U : { auto audio_track = dynamic_pointer_cast(track); @@ -235,7 +240,7 @@ RtmpCodec::Ptr Factory::getRtmpCodecByTrack(const Track::Ptr &track, bool is_enc << ",该音频已被忽略"; return nullptr; } - return std::make_shared(track); + return std::make_shared(track); } default : WarnL << "暂不支持该CodecId:" << track->getCodecName(); return nullptr; } @@ -248,6 +253,7 @@ AMFValue Factory::getAmfByCodecId(CodecId codecId) { case CodecH265: return AMFValue(FLV_CODEC_H265); case CodecG711A: return AMFValue(FLV_CODEC_G711A); case CodecG711U: return AMFValue(FLV_CODEC_G711U); + case CodecOpus: return AMFValue(FLV_CODEC_OPUS); default: return AMFValue(AMF_NULL); } } diff --git a/src/Extension/Frame.cpp b/src/Extension/Frame.cpp index 1a5f8fd3..ec8a3608 100644 --- a/src/Extension/Frame.cpp +++ b/src/Extension/Frame.cpp @@ -35,12 +35,12 @@ public: _dts = frame->dts(); _pts = frame->pts(); _prefix_size = frame->prefixSize(); - _codecid = frame->getCodecId(); + _codec_id = frame->getCodecId(); _key = frame->keyFrame(); _config = frame->configFrame(); } - virtual ~FrameCacheAble() = default; + ~FrameCacheAble() override = default; /** * 可以被缓存 @@ -49,10 +49,6 @@ public: return true; } - CodecId getCodecId() const override{ - return _codecid; - } - bool keyFrame() const override{ return _key; } @@ -60,10 +56,10 @@ public: bool configFrame() const override{ return _config; } + private: Frame::Ptr _frame; BufferRaw::Ptr _buffer; - CodecId _codecid; bool _key; bool _config; }; diff --git a/src/Extension/Frame.h b/src/Extension/Frame.h index 5b34654b..6066d370 100644 --- a/src/Extension/Frame.h +++ b/src/Extension/Frame.h @@ -148,7 +148,7 @@ public: } CodecId getCodecId() const override{ - return _codecid; + return _codec_id; } bool keyFrame() const override { @@ -160,7 +160,7 @@ public: } public: - CodecId _codecid = CodecInvalid; + CodecId _codec_id = CodecInvalid; string _buffer; uint32_t _dts = 0; uint32_t _pts = 0; @@ -314,9 +314,19 @@ private: class FrameFromPtr : public Frame{ public: typedef std::shared_ptr Ptr; + FrameFromPtr(CodecId codec_id, char *ptr, uint32_t size, uint32_t dts, uint32_t pts = 0, int prefix_size = 0){ + _codec_id = codec_id; + _ptr = ptr; + _size = size; + _dts = dts; + _pts = pts; + _prefix_size = prefix_size; + } + char *data() const override{ return _ptr; } + uint32_t size() const override { return _size; } @@ -336,12 +346,29 @@ public: bool cacheAble() const override { return false; } + + CodecId getCodecId() const override{ + return _codec_id; + } + + bool keyFrame() const override { + return false; + } + + bool configFrame() const override{ + return false; + } + +protected: + FrameFromPtr() {} + protected: char *_ptr; uint32_t _size; uint32_t _dts; uint32_t _pts = 0; uint32_t _prefix_size; + CodecId _codec_id = CodecInvalid; }; }//namespace mediakit diff --git a/src/Extension/G711.h b/src/Extension/G711.h index 04e11b6a..72273831 100644 --- a/src/Extension/G711.h +++ b/src/Extension/G711.h @@ -16,47 +16,6 @@ namespace mediakit{ -/** - * G711帧 - */ -class G711Frame : public FrameImp { -public: - G711Frame(){ - _codecid = CodecG711A; - } -}; - -class G711FrameNoCacheAble : public FrameFromPtr { -public: - typedef std::shared_ptr Ptr; - - G711FrameNoCacheAble(char *ptr,uint32_t size,uint32_t dts, uint32_t pts = 0,int prefix_size = 0){ - _ptr = ptr; - _size = size; - _dts = dts; - _prefix_size = prefix_size; - } - - void setCodec(CodecId codecId){ - _codecId = codecId; - } - - CodecId getCodecId() const override{ - return _codecId; - } - - bool keyFrame() const override { - return false; - } - - bool configFrame() const override{ - return false; - } - -private: - CodecId _codecId; -}; - /** * G711音频通道 */ diff --git a/src/Extension/G711Rtmp.cpp b/src/Extension/G711Rtmp.cpp deleted file mode 100644 index 7ffca2f0..00000000 --- a/src/Extension/G711Rtmp.cpp +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved. - * - * This file is part of ZLMediaKit(https://github.com/xiongziliang/ZLMediaKit). - * - * Use of this source code is governed by MIT license that can be found in the - * LICENSE file in the root of the source tree. All contributing project authors - * may be found in the AUTHORS file in the root of the source tree. - */ - -#include "G711Rtmp.h" - -namespace mediakit{ - -G711RtmpDecoder::G711RtmpDecoder(CodecId codecId) { - _frame = obtainFrame(); - _codecId = codecId; -} - -G711Frame::Ptr G711RtmpDecoder::obtainFrame() { - //从缓存池重新申请对象,防止覆盖已经写入环形缓存的对象 - auto frame = ResourcePoolHelper::obtainObj(); - frame->_buffer.clear(); - frame->_codecid = _codecId; - return frame; -} - -bool G711RtmpDecoder::inputRtmp(const RtmpPacket::Ptr &pkt, bool) { - //拷贝G711负载 - _frame->_buffer.assign(pkt->strBuf.data() + 1, pkt->strBuf.size() - 1); - _frame->_dts = pkt->timeStamp; - //写入环形缓存 - RtmpCodec::inputFrame(_frame); - _frame = obtainFrame(); - return false; -} - -///////////////////////////////////////////////////////////////////////////////////// - -G711RtmpEncoder::G711RtmpEncoder(const Track::Ptr &track) : G711RtmpDecoder(track->getCodecId()) { - _audio_flv_flags = getAudioRtmpFlags(track); -} - -void G711RtmpEncoder::inputFrame(const Frame::Ptr &frame) { - if(!_audio_flv_flags){ - return; - } - RtmpPacket::Ptr rtmpPkt = ResourcePoolHelper::obtainObj(); - rtmpPkt->strBuf.clear(); - //header - rtmpPkt->strBuf.push_back(_audio_flv_flags); - - //g711 data - rtmpPkt->strBuf.append(frame->data() + frame->prefixSize(), frame->size() - frame->prefixSize()); - rtmpPkt->bodySize = rtmpPkt->strBuf.size(); - rtmpPkt->chunkId = CHUNK_AUDIO; - rtmpPkt->streamId = STREAM_MEDIA; - rtmpPkt->timeStamp = frame->dts(); - rtmpPkt->typeId = MSG_AUDIO; - RtmpCodec::inputRtmp(rtmpPkt, false); -} - -}//namespace mediakit \ No newline at end of file diff --git a/src/Extension/G711Rtmp.h b/src/Extension/G711Rtmp.h deleted file mode 100644 index c2fea41b..00000000 --- a/src/Extension/G711Rtmp.h +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved. - * - * This file is part of ZLMediaKit(https://github.com/xiongziliang/ZLMediaKit). - * - * Use of this source code is governed by MIT license that can be found in the - * LICENSE file in the root of the source tree. All contributing project authors - * may be found in the AUTHORS file in the root of the source tree. - */ - -#ifndef ZLMEDIAKIT_G711RTMPCODEC_H -#define ZLMEDIAKIT_G711RTMPCODEC_H - -#include "Rtmp/RtmpCodec.h" -#include "Extension/Track.h" -#include "Extension/G711.h" - -namespace mediakit{ -/** - * G711 Rtmp转G711 Frame类 - */ -class G711RtmpDecoder : public RtmpCodec , public ResourcePoolHelper { -public: - typedef std::shared_ptr Ptr; - - G711RtmpDecoder(CodecId codecId); - ~G711RtmpDecoder() {} - - /** - * 输入Rtmp并解码 - * @param Rtmp Rtmp数据包 - * @param key_pos 此参数内部强制转换为false,请忽略之 - */ - bool inputRtmp(const RtmpPacket::Ptr &Rtmp, bool key_pos = false) override; - - CodecId getCodecId() const override{ - return _codecId; - } -private: - G711Frame::Ptr obtainFrame(); -private: - G711Frame::Ptr _frame; - CodecId _codecId; -}; - -/** - * G711 RTMP打包类 - */ -class G711RtmpEncoder : public G711RtmpDecoder , public ResourcePoolHelper { -public: - typedef std::shared_ptr Ptr; - - G711RtmpEncoder(const Track::Ptr &track); - ~G711RtmpEncoder() {} - - /** - * 输入G711 数据 - */ - void inputFrame(const Frame::Ptr &frame) override; -private: - uint8_t _audio_flv_flags = 0; -}; - -}//namespace mediakit - -#endif //ZLMEDIAKIT_G711RTMPCODEC_H diff --git a/src/Extension/G711Rtp.cpp b/src/Extension/G711Rtp.cpp deleted file mode 100644 index 48238db5..00000000 --- a/src/Extension/G711Rtp.cpp +++ /dev/null @@ -1,92 +0,0 @@ -/* - * Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved. - * - * This file is part of ZLMediaKit(https://github.com/xiongziliang/ZLMediaKit). - * - * Use of this source code is governed by MIT license that can be found in the - * LICENSE file in the root of the source tree. All contributing project authors - * may be found in the AUTHORS file in the root of the source tree. - */ - -#include "G711Rtp.h" - -namespace mediakit{ - -G711RtpDecoder::G711RtpDecoder(CodecId codecid){ - _codecid = codecid; - _frame = obtainFrame(); -} - -G711Frame::Ptr G711RtpDecoder::obtainFrame() { - //从缓存池重新申请对象,防止覆盖已经写入环形缓存的对象 - auto frame = ResourcePoolHelper::obtainObj(); - frame->_buffer.clear(); - frame->_codecid = _codecid; - frame->_dts = 0; - return frame; -} - -bool G711RtpDecoder::inputRtp(const RtpPacket::Ptr &rtppack, bool) { - // 获取rtp数据长度 - int length = rtppack->size() - rtppack->offset; - // 获取rtp数据 - const char *rtp_packet_buf = rtppack->data() + rtppack->offset; - - if (rtppack->timeStamp != _frame->_dts) { - //时间戳变更,清空上一帧 - onGetG711(_frame); - } - - //追加数据 - _frame->_buffer.append(rtp_packet_buf, length); - //赋值时间戳 - _frame->_dts = rtppack->timeStamp; - - if (rtppack->mark || _frame->_buffer.size() > 10 * 1024) { - //标记为mark时,或者内存快溢出时,我们认为这是该帧最后一个包 - onGetG711(_frame); - } - return false; -} - -void G711RtpDecoder::onGetG711(const G711Frame::Ptr &frame) { - if(!frame->_buffer.empty()){ - //写入环形缓存 - RtpCodec::inputFrame(frame); - _frame = obtainFrame(); - } -} - -///////////////////////////////////////////////////////////////////////////////////// - -G711RtpEncoder::G711RtpEncoder(CodecId codecid, uint32_t ui32Ssrc, uint32_t ui32MtuSize, - uint32_t ui32SampleRate, uint8_t ui8PayloadType, uint8_t ui8Interleaved) : - G711RtpDecoder(codecid), - RtpInfo(ui32Ssrc, ui32MtuSize, ui32SampleRate, ui8PayloadType, ui8Interleaved) { -} - -void G711RtpEncoder::inputFrame(const Frame::Ptr &frame) { - GET_CONFIG(uint32_t, cycleMS, Rtp::kCycleMS); - auto uiStamp = frame->dts(); - auto pcData = frame->data() + frame->prefixSize(); - auto iLen = frame->size() - frame->prefixSize(); - - uiStamp %= cycleMS; - char *ptr = (char *) pcData; - int iSize = iLen; - while (iSize > 0) { - if (iSize <= _ui32MtuSize - 20) { - makeG711Rtp(ptr, iSize, true, uiStamp); - break; - } - makeG711Rtp(ptr, _ui32MtuSize - 20, false, uiStamp); - ptr += (_ui32MtuSize - 20); - iSize -= (_ui32MtuSize - 20); - } -} - -void G711RtpEncoder::makeG711Rtp(const void *data, unsigned int len, bool mark, uint32_t uiStamp) { - RtpCodec::inputRtp(makeRtp(getTrackType(), data, len, mark, uiStamp), false); -} - -}//namespace mediakit diff --git a/src/Extension/G711Rtp.h b/src/Extension/G711Rtp.h deleted file mode 100644 index aca08e6d..00000000 --- a/src/Extension/G711Rtp.h +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved. - * - * This file is part of ZLMediaKit(https://github.com/xiongziliang/ZLMediaKit). - * - * Use of this source code is governed by MIT license that can be found in the - * LICENSE file in the root of the source tree. All contributing project authors - * may be found in the AUTHORS file in the root of the source tree. - */ - -#ifndef ZLMEDIAKIT_G711RTPCODEC_H -#define ZLMEDIAKIT_G711RTPCODEC_H -#include "Rtsp/RtpCodec.h" -#include "Extension/G711.h" -namespace mediakit{ - -/** - * rtp转G711类 - */ -class G711RtpDecoder : public RtpCodec , public ResourcePoolHelper { -public: - typedef std::shared_ptr Ptr; - - G711RtpDecoder(CodecId codecid); - ~G711RtpDecoder() {} - - /** - * 输入rtp并解码 - * @param rtp rtp数据包 - * @param key_pos 此参数内部强制转换为false,请忽略之 - */ - bool inputRtp(const RtpPacket::Ptr &rtp, bool key_pos = false) override; - - CodecId getCodecId() const override{ - return _codecid; - } - -private: - void onGetG711(const G711Frame::Ptr &frame); - G711Frame::Ptr obtainFrame(); - -private: - G711Frame::Ptr _frame; - CodecId _codecid; -}; - -/** - * g711 转rtp类 - */ -class G711RtpEncoder : public G711RtpDecoder , public RtpInfo { -public: - typedef std::shared_ptr Ptr; - - /** - * @param ui32Ssrc ssrc - * @param ui32MtuSize mtu 大小 - * @param ui32SampleRate 采样率 - * @param ui8PayloadType pt类型 - * @param ui8Interleaved rtsp interleaved 值 - */ - G711RtpEncoder(CodecId codecid, - uint32_t ui32Ssrc, - uint32_t ui32MtuSize, - uint32_t ui32SampleRate, - uint8_t ui8PayloadType = 0, - uint8_t ui8Interleaved = TrackAudio * 2); - ~G711RtpEncoder() {} - - /** - * @param frame g711数据 - */ - void inputFrame(const Frame::Ptr &frame) override; -private: - void makeG711Rtp(const void *pData, unsigned int uiLen, bool bMark, uint32_t uiStamp); -}; - -}//namespace mediakit - -#endif //ZLMEDIAKIT_G711RTPCODEC_H diff --git a/src/Extension/H264.h b/src/Extension/H264.h index a7fca526..34b8dffb 100644 --- a/src/Extension/H264.h +++ b/src/Extension/H264.h @@ -37,7 +37,7 @@ public: } NalType; H264Frame(){ - _codecid = CodecH264; + _codec_id = CodecH264; } bool keyFrame() const override { diff --git a/src/Extension/H265.h b/src/Extension/H265.h index 5279908b..94d934e8 100644 --- a/src/Extension/H265.h +++ b/src/Extension/H265.h @@ -61,7 +61,7 @@ public: } NaleType; H265Frame(){ - _codecid = CodecH265; + _codec_id = CodecH265; } bool keyFrame() const override { diff --git a/src/Extension/Opus.h b/src/Extension/Opus.h index 0a6e56d3..144afb77 100644 --- a/src/Extension/Opus.h +++ b/src/Extension/Opus.h @@ -16,52 +16,13 @@ namespace mediakit{ -/** - * Opus帧 - */ -class OpusFrame : public FrameImp { -public: - typedef std::shared_ptr Ptr; - - OpusFrame(){ - _codecid = CodecOpus; - } -}; - -/** - * 不可缓存的Opus帧 - */ -class OpusFrameNoCacheAble : public FrameFromPtr { -public: - typedef std::shared_ptr Ptr; - - OpusFrameNoCacheAble(char *ptr,uint32_t size,uint32_t dts, uint32_t pts = 0,int prefix_size = 0){ - _ptr = ptr; - _size = size; - _dts = dts; - _prefix_size = prefix_size; - } - - CodecId getCodecId() const override{ - return CodecOpus; - } - - bool keyFrame() const override { - return false; - } - - bool configFrame() const override{ - return false; - } -}; - /** * Opus帧音频通道 */ class OpusTrack : public AudioTrackImp{ public: typedef std::shared_ptr Ptr; - OpusTrack(int sample_rate, int channels, int sample_bit) : AudioTrackImp(CodecOpus,sample_rate,channels,sample_bit){} + OpusTrack() : AudioTrackImp(CodecOpus,48000,2,16){} private: //克隆该Track diff --git a/src/Player/PlayerProxy.cpp b/src/Player/PlayerProxy.cpp index 6b726228..571a0019 100644 --- a/src/Player/PlayerProxy.cpp +++ b/src/Player/PlayerProxy.cpp @@ -46,31 +46,25 @@ static uint8_t s_mute_adts[] = {0xff, 0xf1, 0x6c, 0x40, 0x2d, 0x3f, 0xfc, 0x00, #define MUTE_ADTS_DATA_LEN sizeof(s_mute_adts) #define MUTE_ADTS_DATA_MS 130 -PlayerProxy::PlayerProxy(const string &strVhost, - const string &strApp, - const string &strSrc, - bool bEnableRtsp, - bool bEnableRtmp, - bool bEnableHls, - bool bEnableMp4, - int iRetryCount, - const EventPoller::Ptr &poller) : MediaPlayer(poller){ - _strVhost = strVhost; - _strApp = strApp; - _strSrc = strSrc; - _bEnableRtsp = bEnableRtsp; - _bEnableRtmp = bEnableRtmp; - _bEnableHls = bEnableHls; - _bEnableMp4 = bEnableMp4; - _iRetryCount = iRetryCount; +PlayerProxy::PlayerProxy(const string &vhost, const string &app, const string &stream_id, + bool enable_rtsp, bool enable_rtmp, bool enable_hls, bool enable_mp4, + int retry_count, const EventPoller::Ptr &poller) : MediaPlayer(poller){ + _vhost = vhost; + _app = app; + _stream_id = stream_id; + _enable_rtsp = enable_rtsp; + _enable_rtmp = enable_rtmp; + _enable_hls = enable_hls; + _enable_mp4 = enable_mp4; + _retry_count = retry_count; } void PlayerProxy::setPlayCallbackOnce(const function &cb){ - _playCB = cb; + _on_play = cb; } void PlayerProxy::setOnClose(const function &cb){ - _onClose = cb; + _on_close = cb; } void PlayerProxy::play(const string &strUrlTmp) { @@ -82,16 +76,16 @@ void PlayerProxy::play(const string &strUrlTmp) { return; } - if(strongSelf->_playCB) { - strongSelf->_playCB(err); - strongSelf->_playCB = nullptr; + if(strongSelf->_on_play) { + strongSelf->_on_play(err); + strongSelf->_on_play = nullptr; } if(!err) { // 播放成功 *piFailedCnt = 0;//连续播放失败次数清0 strongSelf->onPlaySuccess(); - }else if(*piFailedCnt < strongSelf->_iRetryCount || strongSelf->_iRetryCount < 0) { + }else if(*piFailedCnt < strongSelf->_retry_count || strongSelf->_retry_count < 0) { // 播放失败,延时重试播放 strongSelf->rePlay(strUrlTmp,(*piFailedCnt)++); } @@ -101,21 +95,21 @@ void PlayerProxy::play(const string &strUrlTmp) { if(!strongSelf) { return; } - if(strongSelf->_mediaMuxer) { + if(strongSelf->_muxer) { auto tracks = strongSelf->getTracks(false); for (auto & track : tracks){ - track->delDelegate(strongSelf->_mediaMuxer.get()); + track->delDelegate(strongSelf->_muxer.get()); } GET_CONFIG(bool,resetWhenRePlay,General::kResetWhenRePlay); if (resetWhenRePlay) { - strongSelf->_mediaMuxer.reset(); + strongSelf->_muxer.reset(); } else { - strongSelf->_mediaMuxer->resetTracks(); + strongSelf->_muxer->resetTracks(); } } //播放异常中断,延时重试播放 - if(*piFailedCnt < strongSelf->_iRetryCount || strongSelf->_iRetryCount < 0) { + if(*piFailedCnt < strongSelf->_retry_count || strongSelf->_retry_count < 0) { strongSelf->rePlay(strUrlTmp,(*piFailedCnt)++); } }); @@ -125,13 +119,14 @@ void PlayerProxy::play(const string &strUrlTmp) { if(dynamic_pointer_cast(_delegate)){ //rtsp拉流 GET_CONFIG(bool,directProxy,Rtsp::kDirectProxy); - if(directProxy && _bEnableRtsp){ - mediaSource = std::make_shared(_strVhost,_strApp,_strSrc); + if(directProxy && _enable_rtsp){ + mediaSource = std::make_shared(_vhost, _app, _stream_id); } } else if(dynamic_pointer_cast(_delegate)){ //rtmp拉流 - if(_bEnableRtmp){ - mediaSource = std::make_shared(_strVhost,_strApp,_strSrc); + if(_enable_rtmp){ + //rtmp强制直接代理 + mediaSource = std::make_shared(_vhost, _app, _stream_id); } } if(mediaSource){ @@ -143,6 +138,7 @@ void PlayerProxy::play(const string &strUrlTmp) { PlayerProxy::~PlayerProxy() { _timer.reset(); } + void PlayerProxy::rePlay(const string &strUrl,int iFailedCnt){ auto iDelay = MAX(2 * 1000, MIN(iFailedCnt * 3000, 60*1000)); weak_ptr weakSelf = shared_from_this(); @@ -164,16 +160,17 @@ bool PlayerProxy::close(MediaSource &sender,bool force) { } //通知其停止推流 - weak_ptr weakSlef = dynamic_pointer_cast(shared_from_this()); - getPoller()->async_first([weakSlef]() { - auto stronSelf = weakSlef.lock(); - if (stronSelf) { - stronSelf->_mediaMuxer.reset(); - stronSelf->setMediaSouce(nullptr); - stronSelf->teardown(); - if(stronSelf->_onClose){ - stronSelf->_onClose(); - } + weak_ptr weakSelf = dynamic_pointer_cast(shared_from_this()); + getPoller()->async_first([weakSelf]() { + auto strongSelf = weakSelf.lock(); + if (!strongSelf) { + return; + } + strongSelf->_muxer.reset(); + strongSelf->setMediaSouce(nullptr); + strongSelf->teardown(); + if (strongSelf->_on_close) { + strongSelf->_on_close(); } }); WarnL << sender.getSchema() << "/" << sender.getVhost() << "/" << sender.getApp() << "/" << sender.getId() << " " << force; @@ -181,7 +178,7 @@ bool PlayerProxy::close(MediaSource &sender,bool force) { } int PlayerProxy::totalReaderCount(){ - return (_mediaMuxer ? _mediaMuxer->totalReaderCount() : 0) + (_pMediaSrc ? _pMediaSrc->readerCount() : 0); + return (_muxer ? _muxer->totalReaderCount() : 0) + (_pMediaSrc ? _pMediaSrc->readerCount() : 0); } int PlayerProxy::totalReaderCount(MediaSource &sender) { @@ -193,88 +190,89 @@ public: typedef std::shared_ptr Ptr; MuteAudioMaker(){}; - virtual ~MuteAudioMaker(){} + ~MuteAudioMaker() override {} + void inputFrame(const Frame::Ptr &frame) override { if(frame->getTrackType() == TrackVideo){ - auto iAudioIndex = frame->dts() / MUTE_ADTS_DATA_MS; - if(_iAudioIndex != iAudioIndex){ - _iAudioIndex = iAudioIndex; - auto aacFrame = std::make_shared((char *)MUTE_ADTS_DATA, MUTE_ADTS_DATA_LEN, _iAudioIndex * MUTE_ADTS_DATA_MS, 0); + auto audio_idx = frame->dts() / MUTE_ADTS_DATA_MS; + if(_audio_idx != audio_idx){ + _audio_idx = audio_idx; + auto aacFrame = std::make_shared(CodecAAC, (char *)MUTE_ADTS_DATA, MUTE_ADTS_DATA_LEN, _audio_idx * MUTE_ADTS_DATA_MS); FrameDispatcher::inputFrame(aacFrame); } } } private: - class AACFrameCacheAble : public AACFrameNoCacheAble{ + class FrameFromStaticPtr : public FrameFromPtr{ public: template - AACFrameCacheAble(ARGS && ...args) : AACFrameNoCacheAble(std::forward(args)...){}; - virtual ~AACFrameCacheAble() = default; + FrameFromStaticPtr(ARGS && ...args) : FrameFromPtr(std::forward(args)...) {}; + ~FrameFromStaticPtr() override = default; bool cacheAble() const override { return true; } }; + private: - int _iAudioIndex = 0; + int _audio_idx = 0; }; void PlayerProxy::onPlaySuccess() { GET_CONFIG(bool,resetWhenRePlay,General::kResetWhenRePlay); if (dynamic_pointer_cast(_pMediaSrc)) { //rtsp拉流代理 - if (resetWhenRePlay || !_mediaMuxer) { - _mediaMuxer.reset(new MultiMediaSourceMuxer(_strVhost, _strApp, _strSrc, getDuration(), false, _bEnableRtmp, _bEnableHls, _bEnableMp4)); + if (resetWhenRePlay || !_muxer) { + _muxer.reset(new MultiMediaSourceMuxer(_vhost, _app, _stream_id, getDuration(), false, _enable_rtmp, _enable_hls, _enable_mp4)); } } else if (dynamic_pointer_cast(_pMediaSrc)) { //rtmp拉流代理 - if (resetWhenRePlay || !_mediaMuxer) { - _mediaMuxer.reset(new MultiMediaSourceMuxer(_strVhost, _strApp, _strSrc, getDuration(), _bEnableRtsp, false, _bEnableHls, _bEnableMp4)); + if (resetWhenRePlay || !_muxer) { + _muxer.reset(new MultiMediaSourceMuxer(_vhost, _app, _stream_id, getDuration(), _enable_rtsp, false, _enable_hls, _enable_mp4)); } } else { //其他拉流代理 - if (resetWhenRePlay || !_mediaMuxer) { - _mediaMuxer.reset(new MultiMediaSourceMuxer(_strVhost, _strApp, _strSrc, getDuration(), _bEnableRtsp, _bEnableRtmp, _bEnableHls, _bEnableMp4)); + if (resetWhenRePlay || !_muxer) { + _muxer.reset(new MultiMediaSourceMuxer(_vhost, _app, _stream_id, getDuration(), _enable_rtsp, _enable_rtmp, _enable_hls, _enable_mp4)); } } - _mediaMuxer->setMediaListener(shared_from_this()); + _muxer->setMediaListener(shared_from_this()); - auto videoTrack = getTrack(TrackVideo,false); - if(videoTrack){ + auto videoTrack = getTrack(TrackVideo, false); + if (videoTrack) { //添加视频 - _mediaMuxer->addTrack(videoTrack); + _muxer->addTrack(videoTrack); //视频数据写入_mediaMuxer - videoTrack->addDelegate(_mediaMuxer); + videoTrack->addDelegate(_muxer); } //是否添加静音音频 - GET_CONFIG(bool,addMuteAudio,General::kAddMuteAudio); + GET_CONFIG(bool, addMuteAudio, General::kAddMuteAudio); auto audioTrack = getTrack(TrackAudio, false); - if(audioTrack){ + if (audioTrack) { //添加音频 - _mediaMuxer->addTrack(audioTrack); + _muxer->addTrack(audioTrack); //音频数据写入_mediaMuxer - audioTrack->addDelegate(_mediaMuxer); - }else if(addMuteAudio && videoTrack){ + audioTrack->addDelegate(_muxer); + } else if (addMuteAudio && videoTrack) { //没有音频信息,产生一个静音音频 MuteAudioMaker::Ptr audioMaker = std::make_shared(); //videoTrack把数据写入MuteAudioMaker videoTrack->addDelegate(audioMaker); //添加一个静音Track至_mediaMuxer - _mediaMuxer->addTrack(std::make_shared()); + _muxer->addTrack(std::make_shared()); //MuteAudioMaker生成静音音频然后写入_mediaMuxer; - audioMaker->addDelegate(_mediaMuxer); + audioMaker->addDelegate(_muxer); } //添加完毕所有track,防止单track情况下最大等待3秒 - _mediaMuxer->addTrackCompleted(); + _muxer->addTrackCompleted(); - if(_pMediaSrc){ - _pMediaSrc->setTrackSource(_mediaMuxer); + if (_pMediaSrc) { + _pMediaSrc->setTrackSource(_muxer); } } - } /* namespace mediakit */ diff --git a/src/Player/PlayerProxy.h b/src/Player/PlayerProxy.h index 4437a68a..999786f4 100644 --- a/src/Player/PlayerProxy.h +++ b/src/Player/PlayerProxy.h @@ -15,32 +15,22 @@ #include "Common/Device.h" #include "Player/MediaPlayer.h" #include "Util/TimeTicker.h" - using namespace std; using namespace toolkit; - namespace mediakit { -class PlayerProxy :public MediaPlayer, - public std::enable_shared_from_this , - public MediaSourceEvent{ +class PlayerProxy : public MediaPlayer, public MediaSourceEvent, public std::enable_shared_from_this { public: typedef std::shared_ptr Ptr; - //如果iRetryCount<0,则一直重试播放;否则重试iRetryCount次数 + //如果retry_count<0,则一直重试播放;否则重试retry_count次数 //默认一直重试 - PlayerProxy(const string &strVhost, - const string &strApp, - const string &strSrc, - bool bEnableRtsp = true, - bool bEnableRtmp = true, - bool bEnableHls = true, - bool bEnableMp4 = false, - int iRetryCount = -1, - const EventPoller::Ptr &poller = nullptr); + PlayerProxy(const string &vhost, const string &app, const string &stream_id, + bool enable_rtsp = true, bool enable_rtmp = true, bool enable_hls = true, bool enable_mp4 = false, + int retry_count = -1, const EventPoller::Ptr &poller = nullptr); - virtual ~PlayerProxy(); + ~PlayerProxy() override; /** * 设置play结果回调,只触发一次;在play执行之前有效 @@ -64,27 +54,28 @@ public: * 获取观看总人数 */ int totalReaderCount() ; + private: //MediaSourceEvent override bool close(MediaSource &sender,bool force) override; int totalReaderCount(MediaSource &sender) override; void rePlay(const string &strUrl,int iFailedCnt); void onPlaySuccess(); + private: - bool _bEnableRtsp; - bool _bEnableRtmp; - bool _bEnableHls; - bool _bEnableMp4; - int _iRetryCount; - MultiMediaSourceMuxer::Ptr _mediaMuxer; - string _strVhost; - string _strApp; - string _strSrc; + bool _enable_rtsp; + bool _enable_rtmp; + bool _enable_hls; + bool _enable_mp4; + int _retry_count; + string _vhost; + string _app; + string _stream_id; Timer::Ptr _timer; - function _playCB; - function _onClose; + function _on_close; + function _on_play; + MultiMediaSourceMuxer::Ptr _muxer; }; } /* namespace mediakit */ - #endif /* SRC_DEVICE_PLAYERPROXY_H_ */ diff --git a/src/Record/MP4Demuxer.cpp b/src/Record/MP4Demuxer.cpp index 7b0fadd4..d77e1734 100644 --- a/src/Record/MP4Demuxer.cpp +++ b/src/Record/MP4Demuxer.cpp @@ -15,6 +15,7 @@ #include "Extension/H264.h" #include "Extension/AAC.h" #include "Extension/G711.h" +#include "Extension/Opus.h" using namespace toolkit; namespace mediakit { @@ -119,14 +120,22 @@ void MP4Demuxer::onAudioTrack(uint32_t track_id, uint8_t object, int channel_cou case MOV_OBJECT_AAC:{ auto audio = std::make_shared(bytes > 0 ? string((char *)extra,bytes) : ""); _track_to_codec.emplace(track_id, audio); - } break; + } + case MOV_OBJECT_G711a: case MOV_OBJECT_G711u:{ auto audio = std::make_shared(object == MOV_OBJECT_G711a ? CodecG711A : CodecG711U, sample_rate, channel_count, bit_per_sample / channel_count ); _track_to_codec.emplace(track_id, audio); - } break; + } + + case MOV_OBJECT_OPUS: { + auto audio = std::make_shared(); + _track_to_codec.emplace(track_id, audio); + break; + } + default: WarnL << "不支持该编码类型的MP4,已忽略:" << getObjectName(object); break; @@ -196,6 +205,11 @@ public: FrameWrapper(const Buffer::Ptr &buf, int64_t pts, int64_t dts, int prefix) : Parent(buf->data(), buf->size(), dts, pts, prefix){ _buf = buf; } + + FrameWrapper(CodecId codec,const Buffer::Ptr &buf, int64_t pts, int64_t dts, int prefix) : Parent(codec, buf->data(), buf->size(), dts, pts, prefix){ + _buf = buf; + } + bool cacheAble() const override { return true; } @@ -231,14 +245,11 @@ Frame::Ptr MP4Demuxer::makeFrame(uint32_t track_id, const Buffer::Ptr &buf, int6 return std::make_shared >(buf, pts, dts, 4); } - case CodecAAC : - return std::make_shared >(buf, pts, dts, 0); - + case CodecOpus: + case CodecAAC: case CodecG711A: case CodecG711U: { - auto frame = std::make_shared >(buf, pts, dts, 0); - frame->setCodec(codec); - return frame; + return std::make_shared >(codec, buf, pts, dts, 0); } default: return nullptr; diff --git a/src/Rtmp/Rtmp.cpp b/src/Rtmp/Rtmp.cpp index db0078f4..b7046163 100644 --- a/src/Rtmp/Rtmp.cpp +++ b/src/Rtmp/Rtmp.cpp @@ -58,6 +58,14 @@ uint8_t getAudioRtmpFlags(const Track::Ptr &track){ switch (track->getCodecId()){ case CodecG711A : flvAudioType = FLV_CODEC_G711A; break; case CodecG711U : flvAudioType = FLV_CODEC_G711U; break; + case CodecOpus : { + flvAudioType = FLV_CODEC_OPUS; + //opus不通过flags获取音频相关信息 + iSampleRate = 44100; + iSampleBit = 16; + iChannel = 2; + break; + } case CodecAAC : { flvAudioType = FLV_CODEC_AAC; //aac不通过flags获取音频相关信息 diff --git a/src/Rtmp/Rtmp.h b/src/Rtmp/Rtmp.h index 3df5240e..ccf94b2d 100644 --- a/src/Rtmp/Rtmp.h +++ b/src/Rtmp/Rtmp.h @@ -1,4 +1,4 @@ -/* +/* * Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved. * * This file is part of ZLMediaKit(https://github.com/xiongziliang/ZLMediaKit). @@ -74,10 +74,12 @@ using namespace toolkit; #define FLV_CODEC_AAC 10 #define FLV_CODEC_H264 7 +//金山扩展: https://github.com/ksvc/FFmpeg/wiki #define FLV_CODEC_H265 12 #define FLV_CODEC_G711A 7 #define FLV_CODEC_G711U 8 - +//参考学而思网校: https://github.com/notedit/rtmp/commit/6e314ac5b29611431f8fb5468596b05815743c10 +#define FLV_CODEC_OPUS 13 namespace mediakit { diff --git a/src/Rtp/Decoder.cpp b/src/Rtp/Decoder.cpp index 92402a95..3b86a64d 100644 --- a/src/Rtp/Decoder.cpp +++ b/src/Rtp/Decoder.cpp @@ -175,7 +175,7 @@ void DecoderImp::onDecode(int stream,int codecid,int flags,int64_t pts,int64_t d WarnL<< "audio track change to AAC from codecid:" << getCodecName(_codecid_audio); return; } - onFrame(std::make_shared((char *) data, bytes, dts, 0, 7)); + onFrame(std::make_shared(CodecAAC, (char *) data, bytes, dts, 0, ADTS_HEADER_LEN)); break; } @@ -195,9 +195,7 @@ void DecoderImp::onDecode(int stream,int codecid,int flags,int64_t pts,int64_t d WarnL<< "audio track change to G711 from codecid:" << getCodecName(_codecid_audio); return; } - auto frame = std::make_shared((char *) data, bytes, dts); - frame->setCodec(codec); - onFrame(frame); + onFrame(std::make_shared(codec, (char *) data, bytes, dts)); break; } default: diff --git a/src/Rtsp/RtpCodec.h b/src/Rtsp/RtpCodec.h index 16a6f88a..ef4bed35 100644 --- a/src/Rtsp/RtpCodec.h +++ b/src/Rtsp/RtpCodec.h @@ -106,6 +106,7 @@ public: return _ui32MtuSize; } RtpPacket::Ptr makeRtp(TrackType type,const void *pData, unsigned int uiLen, bool bMark, uint32_t uiStamp); + protected: uint32_t _ui32Ssrc; uint32_t _ui32SampleRate;