From 5c3418a4120bb26235d156bc1b3ebc6175bec701 Mon Sep 17 00:00:00 2001 From: xiongziliang <771730766@qq.com> Date: Sat, 18 Apr 2020 18:46:20 +0800 Subject: [PATCH] =?UTF-8?q?=E5=90=88=E5=B9=B6=20#278?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- 3rdpart/ZLToolKit | 2 +- api/include/mk_media.h | 2 +- api/include/mk_player.h | 6 +- api/source/mk_media.cpp | 18 +++-- api/source/mk_player.cpp | 8 +-- src/Common/Device.cpp | 82 +++++++++++------------ src/Common/Device.h | 13 ++-- src/Common/MediaSink.cpp | 25 +++---- src/Extension/AAC.cpp | 3 +- src/Extension/AACRtmp.cpp | 7 +- src/Extension/Factory.cpp | 57 ++++++---------- src/Extension/Factory.h | 24 ------- src/Extension/G711.cpp | 2 +- src/Extension/G711.h | 134 ++++++++++++------------------------- src/Extension/G711Rtmp.cpp | 83 ++++++++++++++++------- src/Extension/G711Rtmp.h | 36 +++------- src/Extension/G711Rtp.cpp | 106 ++++++++++++++--------------- src/Extension/G711Rtp.h | 27 ++++---- src/Extension/H264.cpp | 2 +- src/Extension/H265.cpp | 2 +- src/Rtmp/Rtmp.h | 2 - 21 files changed, 277 insertions(+), 364 deletions(-) diff --git a/3rdpart/ZLToolKit b/3rdpart/ZLToolKit index 2b4eacb2..987683f1 160000 --- a/3rdpart/ZLToolKit +++ b/3rdpart/ZLToolKit @@ -1 +1 @@ -Subproject commit 2b4eacb22604f22d459b1c68195ae13e5cb9d62a +Subproject commit 987683f1045613098e2bcd534bc90a13d16df8a4 diff --git a/api/include/mk_media.h b/api/include/mk_media.h index 3cbee8a8..69f1f0ff 100755 --- a/api/include/mk_media.h +++ b/api/include/mk_media.h @@ -68,7 +68,7 @@ API_EXPORT void API_CALL mk_media_init_aac(mk_media ctx, int channel, int sample /** * 添加g711音频轨道 * @param ctx 对象指针 - * @param au 1.G711A 2.G711U + * @param au 3 : G711A 4: G711U * @param channel 通道数 * @param sample_bit 采样位数,只支持16 * @param sample_rate 采样率 diff --git a/api/include/mk_player.h b/api/include/mk_player.h index f228c845..d93414e2 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 + * @param codec_id 0:H264,1:H265,2:AAC 3.G711A 4.G711U * @param data 数据指针 * @param len 数据长度 * @param dts 解码时间戳,单位毫秒 @@ -98,13 +98,15 @@ API_EXPORT void API_CALL mk_player_set_on_shutdown(mk_player ctx, on_mk_play_eve /** * 设置音视频数据回调函数 - * 该接口只能在播放成功事件触发后才能调用 + * 该接口在播放成功事件触发后才有效 * @param ctx 播放器指针 * @param cb 回调函数指针,不得为null * @param user_data 用户数据指针 */ API_EXPORT void API_CALL mk_player_set_on_data(mk_player ctx, on_mk_play_data cb, void *user_data); +///////////////////////////获取音视频相关信息接口在播放成功回调触发后才有效/////////////////////////////// + /** * 获取视频codec_id -1:不存在 0:H264,1:H265,2:AAC 3.G711A 4.G711U * @param ctx 播放器指针 diff --git a/api/source/mk_media.cpp b/api/source/mk_media.cpp index 3b345164..082816b7 100755 --- a/api/source/mk_media.cpp +++ b/api/source/mk_media.cpp @@ -113,6 +113,7 @@ API_EXPORT void API_CALL mk_media_init_h264(mk_media ctx, int width, int height, assert(ctx); MediaHelper::Ptr *obj = (MediaHelper::Ptr *) ctx; VideoInfo info; + info.codecId = CodecH264; info.iFrameRate = frameRate; info.iWidth = width; info.iHeight = height; @@ -123,16 +124,18 @@ API_EXPORT void API_CALL mk_media_init_h265(mk_media ctx, int width, int height, assert(ctx); MediaHelper::Ptr *obj = (MediaHelper::Ptr *) ctx; VideoInfo info; + info.codecId = CodecH265; info.iFrameRate = frameRate; info.iWidth = width; info.iHeight = height; - (*obj)->getChannel()->initH265Video(info); + (*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) { assert(ctx); MediaHelper::Ptr *obj = (MediaHelper::Ptr *) ctx; AudioInfo info; + info.codecId = CodecAAC; info.iSampleRate = sample_rate; info.iChannel = channel; info.iSampleBit = sample_bit; @@ -140,17 +143,16 @@ API_EXPORT void API_CALL mk_media_init_aac(mk_media ctx, int channel, int sample (*obj)->getChannel()->initAudio(info); } - -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_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; - info.codecId = (CodecId)au; (*obj)->getChannel()->initAudio(info); } @@ -184,12 +186,8 @@ API_EXPORT void API_CALL mk_media_input_aac1(mk_media ctx, void *data, int len, (*obj)->getChannel()->inputAAC((char *) data, len, dts, (char *) adts); } -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_g711(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); } - - - diff --git a/api/source/mk_player.cpp b/api/source/mk_player.cpp index 5f7a681b..b2a01bcd 100755 --- a/api/source/mk_player.cpp +++ b/api/source/mk_player.cpp @@ -101,9 +101,7 @@ API_EXPORT void API_CALL mk_player_set_on_data(mk_player ctx, on_mk_play_data cb }); } - -API_EXPORT int API_CALL mk_player_video_codecId(mk_player ctx) -{ +API_EXPORT int API_CALL mk_player_video_codecId(mk_player ctx){ assert(ctx); MediaPlayer::Ptr& player = *((MediaPlayer::Ptr*)ctx); auto track = dynamic_pointer_cast(player->getTrack(TrackVideo)); @@ -131,9 +129,7 @@ API_EXPORT int API_CALL mk_player_video_fps(mk_player ctx) { return track ? track->getVideoFps() : 0; } - -API_EXPORT int API_CALL mk_player_audio_codecId(mk_player ctx) -{ +API_EXPORT int API_CALL mk_player_audio_codecId(mk_player ctx){ assert(ctx); MediaPlayer::Ptr& player = *((MediaPlayer::Ptr*)ctx); auto track = dynamic_pointer_cast(player->getTrack(TrackAudio)); diff --git a/src/Common/Device.cpp b/src/Common/Device.cpp index 668d06ee..06de6d10 100644 --- a/src/Common/Device.cpp +++ b/src/Common/Device.cpp @@ -8,13 +8,9 @@ * may be found in the AUTHORS file in the root of the source tree. */ -#include -#include #include "Device.h" #include "Util/logger.h" -#include "Util/util.h" #include "Util/base64.h" -#include "Util/TimeTicker.h" #include "Extension/AAC.h" #include "Extension/G711.h" #include "Extension/H264.h" @@ -148,9 +144,7 @@ void DevChannel::inputAAC(const char *pcDataWithoutAdts,int iDataLen, uint32_t u } } - -void DevChannel::inputG711(const char* pcData, int iDataLen, uint32_t uiStamp) -{ +void DevChannel::inputG711(const char* pcData, int iDataLen, uint32_t uiStamp){ if (uiStamp == 0) { uiStamp = (uint32_t)_aTicker[1].elapsedTime(); } @@ -159,47 +153,51 @@ void DevChannel::inputG711(const char* pcData, int iDataLen, uint32_t uiStamp) void DevChannel::initVideo(const VideoInfo& info) { _video = std::make_shared(info); - addTrack(std::make_shared()); + switch (info.codecId){ + case CodecH265 : addTrack(std::make_shared()); break; + case CodecH264 : addTrack(std::make_shared()); break; + default: WarnL << "不支持该类型的视频编码类型:" << info.codecId; break; + } } -void DevChannel::initH265Video(const VideoInfo &info){ - _video = std::make_shared(info); - addTrack(std::make_shared()); +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) { - _audio = std::make_shared(info); - if (info.codecId == CodecAAC) - { - addTrack(std::make_shared()); - - AACFrame adtsHeader; - adtsHeader.syncword = 0x0FFF; - adtsHeader.id = 0; - adtsHeader.layer = 0; - adtsHeader.protection_absent = 1; - adtsHeader.profile = info.iProfile;//audioObjectType - 1; - int i = 0; - for (auto rate : samplingFrequencyTable) { - if (rate == info.iSampleRate) { - adtsHeader.sf_index = i; - }; - ++i; + _audio = std::make_shared(info); + switch (info.codecId) { + case CodecAAC : { + addTrack(std::make_shared()); + makeAdtsHeader(info.iProfile, info.iSampleBit, info.iChannel, _adtsHeader); + break; } - adtsHeader.private_bit = 0; - adtsHeader.channel_configuration = info.iChannel; - 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, _adtsHeader); - } - else if (info.codecId == CodecG711A || info.codecId == CodecG711U) - { - addTrack(std::make_shared(info.codecId, info.iSampleBit, info.iSampleRate)); + + case CodecG711A : + case CodecG711U : addTrack(std::make_shared(info.codecId)); break; + default: WarnL << "不支持该类型的音频编码类型:" << info.codecId; break; } } diff --git a/src/Common/Device.h b/src/Common/Device.h index 175a5ee2..e7a1b24b 100644 --- a/src/Common/Device.h +++ b/src/Common/Device.h @@ -35,13 +35,14 @@ namespace mediakit { class VideoInfo { public: + CodecId codecId = CodecH264; int iWidth; int iHeight; float iFrameRate; }; class AudioInfo { public: - CodecId codecId; + CodecId codecId = CodecAAC; int iChannel; int iSampleBit; int iSampleRate; @@ -69,20 +70,14 @@ public: /** * 初始化h264视频Track * 相当于MultiMediaSourceMuxer::addTrack(H264Track::Ptr ); - * @param info + * @param info 视频相关信息 */ void initVideo(const VideoInfo &info); - /** - * 初始化h265视频Track - * @param info - */ - void initH265Video(const VideoInfo &info); - /** * 初始化aac音频Track * 相当于MultiMediaSourceMuxer::addTrack(AACTrack::Ptr ); - * @param info + * @param info 音频相关信息 */ void initAudio(const AudioInfo &info); diff --git a/src/Common/MediaSink.cpp b/src/Common/MediaSink.cpp index 6cc173f4..aa5e023c 100644 --- a/src/Common/MediaSink.cpp +++ b/src/Common/MediaSink.cpp @@ -34,23 +34,16 @@ void MediaSink::addTrack(const Track::Ptr &track_in) { track->addDelegate(std::make_shared([this](const Frame::Ptr &frame) { if (_allTrackReady) { onTrackFrame(frame); + return; } - else - { - if (frame->getTrackType() == TrackVideo) - { - checkTrackIfReady(nullptr); - if (_allTrackReady) { - onTrackFrame(frame); - } - else - { - ErrorL << " 还有track未准备好,丢帧 codecName: " << frame->getCodecName(); - } - - }else - ErrorL << " 还有track未准备好,丢帧 codecName: " << frame->getCodecName(); + //还有track未准备好,如果是视频的话,如果直接丢帧可能导致丢失I帧 + checkTrackIfReady(nullptr); + if (_allTrackReady) { + //运行至这里说明Track状态由未就绪切换为已就绪状态,那么这帧就不应该丢弃 + onTrackFrame(frame); + } else { + ErrorL << "some track is unready,drop frame of: " << frame->getCodecName(); } })); } @@ -140,7 +133,7 @@ void MediaSink::emitAllTrackReady() { //移除未准备好的Track for (auto it = _track_map.begin(); it != _track_map.end();) { if (!it->second->ready()) { - WarnL << "该track长时间未被初始化,已忽略:" << it->second->getCodecName(); + WarnL << "track not ready for a long time, ignored: " << it->second->getCodecName(); it = _track_map.erase(it); continue; } diff --git a/src/Extension/AAC.cpp b/src/Extension/AAC.cpp index 41e52d2d..686fdd57 100644 --- a/src/Extension/AAC.cpp +++ b/src/Extension/AAC.cpp @@ -98,10 +98,9 @@ void getAACInfo(const AACFrame &adts,int &iSampleRate,int &iChannel){ iChannel = adts.channel_configuration; } - Sdp::Ptr AACTrack::getSdp() { if(!ready()){ - WarnL << "AAC Track未准备好"; + WarnL << getCodecName() << " Track未准备好"; return nullptr; } return std::make_shared(getAacCfg(),getAudioSampleRate()); diff --git a/src/Extension/AACRtmp.cpp b/src/Extension/AACRtmp.cpp index ab34caff..ac66f306 100644 --- a/src/Extension/AACRtmp.cpp +++ b/src/Extension/AACRtmp.cpp @@ -102,10 +102,12 @@ void AACRtmpEncoder::inputFrame(const Frame::Ptr &frame) { RtmpPacket::Ptr rtmpPkt = ResourcePoolHelper::obtainObj(); rtmpPkt->strBuf.clear(); - //////////header + //header uint8_t is_config = false; rtmpPkt->strBuf.push_back(_ui8AudioFlags); rtmpPkt->strBuf.push_back(!is_config); + + //aac data rtmpPkt->strBuf.append(frame->data() + frame->prefixSize(), frame->size() - frame->prefixSize()); rtmpPkt->bodySize = rtmpPkt->strBuf.size(); @@ -150,10 +152,11 @@ void AACRtmpEncoder::makeAudioConfigPkt() { RtmpPacket::Ptr rtmpPkt = ResourcePoolHelper::obtainObj(); rtmpPkt->strBuf.clear(); - //////////header + //header uint8_t is_config = true; rtmpPkt->strBuf.push_back(_ui8AudioFlags); rtmpPkt->strBuf.push_back(!is_config); + //aac config rtmpPkt->strBuf.append(_aac_cfg); rtmpPkt->bodySize = rtmpPkt->strBuf.size(); diff --git a/src/Extension/Factory.cpp b/src/Extension/Factory.cpp index 1fd6c754..5f5e3491 100644 --- a/src/Extension/Factory.cpp +++ b/src/Extension/Factory.cpp @@ -88,7 +88,6 @@ Track::Ptr Factory::getTrackBySdp(const SdpTrack::Ptr &track) { return nullptr; } - Track::Ptr Factory::getTrackByCodecId(CodecId codecId) { switch (codecId){ case CodecH264:{ @@ -169,25 +168,7 @@ RtpCodec::Ptr Factory::getRtpDecoderByTrack(const Track::Ptr &track) { /////////////////////////////rtmp相关/////////////////////////////////////////// -Track::Ptr Factory::getVideoTrackByAmf(const AMFValue &amf) { - CodecId codecId = getCodecIdByAmf(amf); - if(codecId == CodecInvalid){ - return nullptr; - } - return getTrackByCodecId(codecId); -} - - -mediakit::Track::Ptr Factory::getAudioTrackByAmf(const AMFValue& amf) -{ - CodecId codecId = getAudioCodecIdByAmf(amf); - if (codecId == CodecInvalid) { - return nullptr; - } - return getTrackByCodecId(codecId); -} - -CodecId Factory::getCodecIdByAmf(const AMFValue &val){ +static CodecId getVideoCodecIdByAmf(const AMFValue &val){ if (val.type() == AMF_STRING){ auto str = val.as_string(); if(str == "avc1"){ @@ -213,16 +194,20 @@ CodecId Factory::getCodecIdByAmf(const AMFValue &val){ WarnL << "暂不支持该Amf:" << type_id; return CodecInvalid; } - }else{ - WarnL << "Metadata不存在相应的Track"; } return CodecInvalid; } +Track::Ptr Factory::getVideoTrackByAmf(const AMFValue &amf) { + CodecId codecId = getVideoCodecIdByAmf(amf); + if(codecId == CodecInvalid){ + return nullptr; + } + return getTrackByCodecId(codecId); +} -CodecId Factory::getAudioCodecIdByAmf(const AMFValue& val) -{ +static CodecId getAudioCodecIdByAmf(const AMFValue &val) { if (val.type() == AMF_STRING) { auto str = val.as_string(); if (str == "mp4a") { @@ -235,22 +220,24 @@ CodecId Factory::getAudioCodecIdByAmf(const AMFValue& val) if (val.type() != AMF_NULL) { auto type_id = val.as_integer(); switch (type_id) { - 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_AAC : return CodecAAC; + case FLV_CODEC_G711A : return CodecG711A; + case FLV_CODEC_G711U : return CodecG711U; + default : WarnL << "暂不支持该Amf:" << type_id; return CodecInvalid; } } - else { - WarnL << "Metadata不存在相应的Track"; - } return CodecInvalid; } +Track::Ptr Factory::getAudioTrackByAmf(const AMFValue& amf){ + CodecId codecId = getAudioCodecIdByAmf(amf); + if (codecId == CodecInvalid) { + return nullptr; + } + return getTrackByCodecId(codecId); +} + RtmpCodec::Ptr Factory::getRtmpCodecByTrack(const Track::Ptr &track) { switch (track->getCodecId()){ case CodecH264: @@ -270,6 +257,7 @@ RtmpCodec::Ptr Factory::getRtmpCodecByTrack(const Track::Ptr &track) { AMFValue Factory::getAmfByCodecId(CodecId codecId) { switch (codecId){ + //此处用string标明rtmp编码类型目的是为了兼容某些android系统 case CodecAAC: return AMFValue("mp4a"); case CodecH264: return AMFValue("avc1"); case CodecH265: return AMFValue(FLV_CODEC_H265); @@ -279,6 +267,5 @@ AMFValue Factory::getAmfByCodecId(CodecId codecId) { } } - }//namespace mediakit diff --git a/src/Extension/Factory.h b/src/Extension/Factory.h index c8ad09a3..07398637 100644 --- a/src/Extension/Factory.h +++ b/src/Extension/Factory.h @@ -28,7 +28,6 @@ public: /** * 根据CodecId获取Track,该Track的ready()状态一般都为false * @param codecId 编解码器id - * @return */ static Track::Ptr getTrackByCodecId(CodecId codecId); @@ -41,14 +40,11 @@ public: /** * 根据sdp生成rtp编码器 * @param sdp sdp对象 - * @return */ static RtpCodec::Ptr getRtpEncoderBySdp(const Sdp::Ptr &sdp); /** * 根据Track生成Rtp解包器 - * @param track - * @return */ static RtpCodec::Ptr getRtpDecoderByTrack(const Track::Ptr &track); @@ -58,43 +54,23 @@ public: /** * 根据amf对象获取视频相应的Track * @param amf rtmp metadata中的videocodecid的值 - * @return */ static Track::Ptr getVideoTrackByAmf(const AMFValue &amf); /** * 根据amf对象获取音频相应的Track * @param amf rtmp metadata中的audiocodecid的值 - * @return */ static Track::Ptr getAudioTrackByAmf(const AMFValue& amf); - /** - * 根据amf对象获取相应的CodecId - * @param val rtmp metadata中的videocodecid或audiocodecid的值 - * @return - */ - static CodecId getCodecIdByAmf(const AMFValue &val); - - /** - * 根据amf对象获取音频相应的CodecId - * @param val rtmp metadata中的audiocodecid的值 - * @return - */ - static CodecId getAudioCodecIdByAmf(const AMFValue& val); - /** * 根据Track获取Rtmp的编解码器 * @param track 媒体描述对象 - * @return */ static RtmpCodec::Ptr getRtmpCodecByTrack(const Track::Ptr &track); - /** * 根据codecId获取rtmp的codec描述 - * @param codecId - * @return */ static AMFValue getAmfByCodecId(CodecId codecId); }; diff --git a/src/Extension/G711.cpp b/src/Extension/G711.cpp index ee4211a8..23194e2b 100644 --- a/src/Extension/G711.cpp +++ b/src/Extension/G711.cpp @@ -18,7 +18,7 @@ Sdp::Ptr G711Track::getSdp() { WarnL << getCodecName() << " Track未准备好"; return nullptr; } - return std::make_shared(getCodecId(), getAudioSampleRate(), getCodecId() == CodecG711A ? 8 : 0, getAudioSampleBit()); + return std::make_shared(getCodecId()); } }//namespace mediakit diff --git a/src/Extension/G711.h b/src/Extension/G711.h index 94c66975..056ac1dd 100644 --- a/src/Extension/G711.h +++ b/src/Extension/G711.h @@ -16,40 +16,27 @@ namespace mediakit{ -class G711Frame; - -unsigned const samplingFrequencyTableG711[16] = { 96000, 88200, - 64000, 48000, - 44100, 32000, - 24000, 22050, - 16000, 12000, - 11025, 8000, - 7350, 0, 0, 0 }; - -void makeAdtsHeader(const string &strAudioCfg,G711Frame &adts); -void writeAdtsHeader(const G711Frame &adts, uint8_t *pcAdts) ; -string makeG711AdtsConfig(const uint8_t *pcAdts); -void getAACInfo(const G711Frame &adts,int &iSampleRate,int &iChannel); - - /** - * aac帧,包含adts头 + * G711帧 */ class G711Frame : public Frame { public: typedef std::shared_ptr Ptr; char *data() const override{ - return (char *)buffer; + return (char *)buffer.data(); } + uint32_t size() const override { - return frameLength; + return buffer.size(); } + uint32_t dts() const override { return timeStamp; } + uint32_t prefixSize() const override{ - return iPrefixSize; + return 0; } TrackType getTrackType() const override{ @@ -69,17 +56,15 @@ public: } public: CodecId _codecId = CodecG711A; - unsigned int frameLength; // 一个帧的长度包括 raw data block - unsigned char buffer[2 * 1024 + 7]; + string buffer; uint32_t timeStamp; - uint32_t iPrefixSize = 0; } ; class G711FrameNoCacheAble : public FrameNoCacheAble { public: typedef std::shared_ptr Ptr; - G711FrameNoCacheAble(CodecId codecId, char *ptr,uint32_t size,uint32_t dts,int prefixeSize = 7){ + G711FrameNoCacheAble(CodecId codecId, char *ptr,uint32_t size,uint32_t dts,int prefixeSize = 0){ _codecId = codecId; _ptr = ptr; _size = size; @@ -105,91 +90,58 @@ public: private: CodecId _codecId; -} ; - +}; /** - * g711音频通道 + * G711音频通道 */ class G711Track : public AudioTrack{ public: typedef std::shared_ptr Ptr; - /** - * 延后获取adts头信息 - * 在随后的inputFrame中获取adts头信息 - */ - G711Track(){} - /** * G711A G711U */ - G711Track(CodecId codecId, int sampleBit = 16, int sampleRate = 8000){ + G711Track(CodecId codecId){ _codecid = codecId; - _sampleBit = sampleBit; - _sampleRate = sampleRate; - onReady(); } /** * 返回编码类型 - * @return */ CodecId getCodecId() const override{ return _codecid; } /** - * 在获取aac_cfg前是无效的Track - * @return + * G711的Track不需要初始化 */ bool ready() override { return true; } - /** - * 返回音频采样率 - * @return - */ + * 返回音频采样率 + */ int getAudioSampleRate() const override{ - return _sampleRate; + return 8000; } + /** * 返回音频采样位数,一般为16或8 - * @return */ int getAudioSampleBit() const override{ - return _sampleBit; - } - /** - * 返回音频通道数 - * @return - */ - int getAudioChannel() const override{ - return _channel; + return 16; } /** - * 输入数据帧,并获取aac_cfg - * @param frame 数据帧 - */ - void inputFrame(const Frame::Ptr &frame) override{ - AudioTrack::inputFrame(frame); - } -private: - /** - * + * 返回音频通道数 */ - void onReady(){ -/* - if(_cfg.size() < 2){ - return; - } - G711Frame aacFrame; - makeAdtsHeader(_cfg,aacFrame); - getAACInfo(aacFrame,_sampleRate,_channel);*/ + int getAudioChannel() const override{ + return 1; } + +private: Track::Ptr clone() override { return std::make_shared::type >(*this); } @@ -197,34 +149,22 @@ private: //生成sdp Sdp::Ptr getSdp() override ; private: - string _cfg; CodecId _codecid = CodecG711A; - int _sampleRate = 8000; - int _sampleBit = 16; - int _channel = 1; }; - /** -* aac类型SDP -*/ + * G711类型SDP + */ class G711Sdp : public Sdp { public: - /** - * - * @param aac_codecId G711A G711U - * @param sample_rate 音频采样率 - * @param playload_type rtp playload type 默认0为G711U, 8为G711A - * @param bitrate 比特率 + * G711采样率固定为8000 + * @param codecId G711A G711U */ - G711Sdp(CodecId codecId, - int sample_rate, - int playload_type = 0, - int bitrate = 128) : Sdp(sample_rate,playload_type), _codecId(codecId){ - _printer << "m=audio 0 RTP/AVP " << playload_type << "\r\n"; - //_printer << "b=AS:" << bitrate << "\r\n"; - _printer << "a=rtpmap:" << playload_type << (codecId == CodecG711A ? " PCMA/" : " PCMU/") << sample_rate << "\r\n"; + G711Sdp(CodecId codecId) : Sdp(8000,payloadType(codecId)), _codecId(codecId){ + int pt = payloadType(codecId); + _printer << "m=audio 0 RTP/AVP " << pt << "\r\n"; + _printer << "a=rtpmap:" << pt << (codecId == CodecG711A ? " PCMA/" : " PCMU/") << 8000 << "\r\n"; _printer << "a=control:trackID=" << getTrackType() << "\r\n"; } @@ -235,12 +175,22 @@ public: TrackType getTrackType() const override { return TrackAudio; } + CodecId getCodecId() const override { return _codecId; } + + int payloadType(CodecId codecId){ + switch (codecId){ + case CodecG711A : return 8; + case CodecG711U : return 0; + default : return -1; + } + } + private: _StrPrinter _printer; - CodecId _codecId = CodecG711A; + CodecId _codecId; }; }//namespace mediakit diff --git a/src/Extension/G711Rtmp.cpp b/src/Extension/G711Rtmp.cpp index 2381a8ef..854772fc 100644 --- a/src/Extension/G711Rtmp.cpp +++ b/src/Extension/G711Rtmp.cpp @@ -12,57 +12,90 @@ namespace mediakit{ -G711RtmpDecoder::G711RtmpDecoder() { - _adts = obtainFrame(); +G711RtmpDecoder::G711RtmpDecoder(CodecId codecId) { + _frame = obtainFrame(); + _codecId = codecId; } G711Frame::Ptr G711RtmpDecoder::obtainFrame() { //从缓存池重新申请对象,防止覆盖已经写入环形缓存的对象 auto frame = ResourcePoolHelper::obtainObj(); - frame->frameLength = 0; - frame->iPrefixSize = 0; + frame->buffer.clear(); + frame->_codecId = _codecId; return frame; } -bool G711RtmpDecoder::inputRtmp(const RtmpPacket::Ptr &pkt, bool key_pos) { - onGetG711(pkt->strBuf.data() + 2, pkt->strBuf.size() - 2, pkt->timeStamp); +bool G711RtmpDecoder::inputRtmp(const RtmpPacket::Ptr &pkt, bool) { + //拷贝G711负载 + _frame->buffer.assign(pkt->strBuf.data() + 2, pkt->strBuf.size() - 2); + _frame->timeStamp = pkt->timeStamp; + //写入环形缓存 + RtmpCodec::inputFrame(_frame); + _frame = obtainFrame(); return false; } -void G711RtmpDecoder::onGetG711(const char* pcData, int iLen, uint32_t ui32TimeStamp) { - if(iLen + 7 > sizeof(_adts->buffer)){ - WarnL << "Illegal adts data, exceeding the length limit."; +///////////////////////////////////////////////////////////////////////////////////// + +G711RtmpEncoder::G711RtmpEncoder(const Track::Ptr &track) : G711RtmpDecoder(track->getCodecId()) { + auto g711_track = dynamic_pointer_cast(track); + if(!g711_track){ + WarnL << "无效的G711 track, 将忽略打包为RTMP"; return; } - //拷贝aac负载 - memcpy(_adts->buffer, pcData, iLen); - _adts->frameLength = iLen; - _adts->timeStamp = ui32TimeStamp; + auto iSampleRate = g711_track->getAudioSampleRate() ; + auto iChannel = g711_track->getAudioChannel(); + auto iSampleBit = g711_track->getAudioSampleBit(); + uint8_t flvStereoOrMono = (iChannel > 1); + uint8_t flvSampleRate; + switch (iSampleRate) { + case 48000: + case 44100: + flvSampleRate = 3; + break; + case 24000: + case 22050: + flvSampleRate = 2; + break; + case 12000: + case 11025: + flvSampleRate = 1; + break; + default: + flvSampleRate = 0; + break; + } + uint8_t flvSampleBit = iSampleBit == 16; + uint8_t flvAudioType ; + switch (g711_track->getCodecId()){ + case CodecG711A : flvAudioType = FLV_CODEC_G711A; break; + case CodecG711U : flvAudioType = FLV_CODEC_G711U; break; + default: WarnL << "无效的G711 track, 将忽略打包为RTMP"; return ; + } - //写入环形缓存 - RtmpCodec::inputFrame(_adts); - _adts = obtainFrame(); -} -///////////////////////////////////////////////////////////////////////////////////// - -G711RtmpEncoder::G711RtmpEncoder(const Track::Ptr &track) { - _track = dynamic_pointer_cast(track); + _g711_flags = (flvAudioType << 4) | (flvSampleRate << 2) | (flvSampleBit << 1) | flvStereoOrMono; } -void G711RtmpEncoder::inputFrame(const Frame::Ptr& frame) { - +void G711RtmpEncoder::inputFrame(const Frame::Ptr &frame) { + if(!_g711_flags){ + return; + } RtmpPacket::Ptr rtmpPkt = ResourcePoolHelper::obtainObj(); rtmpPkt->strBuf.clear(); - rtmpPkt->strBuf.append(frame->data() + frame->prefixSize(), frame->size() - frame->prefixSize()); + //header + uint8_t is_config = false; + rtmpPkt->strBuf.push_back(_g711_flags); + rtmpPkt->strBuf.push_back(!is_config); + //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 index 3ab29765..74b697e4 100644 --- a/src/Extension/G711Rtmp.h +++ b/src/Extension/G711Rtmp.h @@ -17,13 +17,13 @@ namespace mediakit{ /** - * G711 Rtmp转adts类 + * G711 Rtmp转G711 Frame类 */ class G711RtmpDecoder : public RtmpCodec , public ResourcePoolHelper { public: typedef std::shared_ptr Ptr; - G711RtmpDecoder(); + G711RtmpDecoder(CodecId codecId); ~G711RtmpDecoder() {} /** @@ -37,48 +37,32 @@ public: return TrackAudio; } - void setCodecId(CodecId codecId) - { - _codecid = codecId; - } - CodecId getCodecId() const override{ - return _codecid; + return _codecId; } - -protected: - void onGetG711(const char* pcData, int iLen, uint32_t ui32TimeStamp); +private: G711Frame::Ptr obtainFrame(); -protected: - G711Frame::Ptr _adts; - CodecId _codecid = CodecInvalid; - +private: + G711Frame::Ptr _frame; + CodecId _codecId; }; - /** - * aac adts转Rtmp类 + * G711 RTMP打包类 */ class G711RtmpEncoder : public G711RtmpDecoder , public ResourcePoolHelper { public: typedef std::shared_ptr Ptr; - /** - * 构造函数,track可以为空,此时则在inputFrame时输入adts头 - * 如果track不为空且包含adts头相关信息, - * 那么inputFrame时可以不输入adts头 - * @param track - */ G711RtmpEncoder(const Track::Ptr &track); ~G711RtmpEncoder() {} /** - * 输入aac 数据,可以不带adts头 - * @param frame aac数据 + * 输入G711 数据 */ void inputFrame(const Frame::Ptr &frame) override; private: - G711Track::Ptr _track; + uint8_t _g711_flags = 0; }; }//namespace mediakit diff --git a/src/Extension/G711Rtp.cpp b/src/Extension/G711Rtp.cpp index c55cd956..e4d3329c 100644 --- a/src/Extension/G711Rtp.cpp +++ b/src/Extension/G711Rtp.cpp @@ -12,16 +12,63 @@ namespace mediakit{ +G711RtpDecoder::G711RtpDecoder(const Track::Ptr &track){ + _codecid = track->getCodecId(); + _frame = obtainFrame(); +} + +G711Frame::Ptr G711RtpDecoder::obtainFrame() { + //从缓存池重新申请对象,防止覆盖已经写入环形缓存的对象 + auto frame = ResourcePoolHelper::obtainObj(); + frame->buffer.clear(); + frame->_codecId = _codecid; + frame->timeStamp = 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->timeStamp) { + //时间戳变更,清空上一帧 + onGetG711(_frame); + } + + //追加数据 + _frame->buffer.append(rtp_packet_buf, length); + //赋值时间戳 + _frame->timeStamp = 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(uint32_t ui32Ssrc, - uint32_t ui32MtuSize, - uint32_t ui32SampleRate, - uint8_t ui8PlayloadType, - uint8_t ui8Interleaved) : + uint32_t ui32MtuSize, + uint32_t ui32SampleRate, + uint8_t ui8PlayloadType, + uint8_t ui8Interleaved) : RtpInfo(ui32Ssrc, ui32MtuSize, ui32SampleRate, ui8PlayloadType, - ui8Interleaved){ + ui8Interleaved) { } void G711RtpEncoder::inputFrame(const Frame::Ptr &frame) { @@ -45,56 +92,9 @@ void G711RtpEncoder::inputFrame(const Frame::Ptr &frame) { } void G711RtpEncoder::makeG711Rtp(const void *data, unsigned int len, bool mark, uint32_t uiStamp) { - RtpCodec::inputRtp(makeRtp(getTrackType(),data,len,mark,uiStamp), false); + RtpCodec::inputRtp(makeRtp(getTrackType(), data, len, mark, uiStamp), false); } -///////////////////////////////////////////////////////////////////////////////////// - -G711RtpDecoder::G711RtpDecoder(const Track::Ptr &track){ - auto g711Track = dynamic_pointer_cast(track); - _codecid = g711Track->getCodecId(); - if(!g711Track || !g711Track->ready()){ - WarnL << "该g711 track无效!"; - }else{ - } - _adts = obtainFrame(); -} -G711RtpDecoder::G711RtpDecoder() { - _adts = obtainFrame(); -} - -G711Frame::Ptr G711RtpDecoder::obtainFrame() { - //从缓存池重新申请对象,防止覆盖已经写入环形缓存的对象 - auto frame = ResourcePoolHelper::obtainObj(); - frame->frameLength = 0; - frame->iPrefixSize = 0; - return frame; -} - -bool G711RtpDecoder::inputRtp(const RtpPacket::Ptr &rtppack, bool key_pos) { - // 获取rtp数据长度 - int length = rtppack->size() - rtppack->offset; - - // 获取rtp数据 - const uint8_t *rtp_packet_buf = (uint8_t *)rtppack->data() + rtppack->offset; - - _adts->frameLength = length; - memcpy(_adts->buffer, rtp_packet_buf, length); - _adts->_codecId = _codecid; - if (rtppack->mark == true) { - _adts->timeStamp = rtppack->timeStamp; - onGetG711(_adts); - } - return false; -} - -void G711RtpDecoder::onGetG711(const G711Frame::Ptr &frame) { - //写入环形缓存 - RtpCodec::inputFrame(frame); - _adts = obtainFrame(); -} - - }//namespace mediakit diff --git a/src/Extension/G711Rtp.h b/src/Extension/G711Rtp.h index 2d052720..31547464 100644 --- a/src/Extension/G711Rtp.h +++ b/src/Extension/G711Rtp.h @@ -10,12 +10,12 @@ #ifndef ZLMEDIAKIT_G711RTPCODEC_H #define ZLMEDIAKIT_G711RTPCODEC_H - #include "Rtsp/RtpCodec.h" #include "Extension/G711.h" namespace mediakit{ + /** - * G711 rtp转adts类 + * rtp转G711类 */ class G711RtpDecoder : public RtpCodec , public ResourcePoolHelper { public: @@ -34,19 +34,22 @@ public: TrackType getTrackType() const override{ return TrackAudio; } + CodecId getCodecId() const override{ return _codecid; } + protected: - G711RtpDecoder(); + G711RtpDecoder() {} + private: void onGetG711(const G711Frame::Ptr &frame); G711Frame::Ptr obtainFrame(); -private: - G711Frame::Ptr _adts; - CodecId _codecid = CodecInvalid; -}; +private: + G711Frame::Ptr _frame; + CodecId _codecid; +}; /** * g711 转rtp类 @@ -63,10 +66,10 @@ public: * @param ui8Interleaved rtsp interleaved 值 */ G711RtpEncoder(uint32_t ui32Ssrc, - uint32_t ui32MtuSize, - uint32_t ui32SampleRate, - uint8_t ui8PlayloadType = 0, - uint8_t ui8Interleaved = TrackAudio * 2); + uint32_t ui32MtuSize, + uint32_t ui32SampleRate, + uint8_t ui8PlayloadType = 0, + uint8_t ui8Interleaved = TrackAudio * 2); ~G711RtpEncoder() {} /** @@ -75,8 +78,6 @@ public: void inputFrame(const Frame::Ptr &frame) override; private: void makeG711Rtp(const void *pData, unsigned int uiLen, bool bMark, uint32_t uiStamp); -private: - unsigned char _aucSectionBuf[1600]; }; }//namespace mediakit diff --git a/src/Extension/H264.cpp b/src/Extension/H264.cpp index 73488055..d1f66f9a 100644 --- a/src/Extension/H264.cpp +++ b/src/Extension/H264.cpp @@ -62,7 +62,7 @@ void splitH264(const char *ptr, int len, const std::function(getSps(),getPps()); diff --git a/src/Extension/H265.cpp b/src/Extension/H265.cpp index 54183150..f46a756d 100644 --- a/src/Extension/H265.cpp +++ b/src/Extension/H265.cpp @@ -52,7 +52,7 @@ bool getHEVCInfo(const string &strVps, const string &strSps, int &iVideoWidth, i Sdp::Ptr H265Track::getSdp() { if(!ready()){ - WarnL << "H265 Track未准备好"; + WarnL << getCodecName() << " Track未准备好"; return nullptr; } return std::make_shared(getVps(),getSps(),getPps()); diff --git a/src/Rtmp/Rtmp.h b/src/Rtmp/Rtmp.h index 53df18dd..073f8b04 100644 --- a/src/Rtmp/Rtmp.h +++ b/src/Rtmp/Rtmp.h @@ -209,8 +209,6 @@ public: } }; - - /** * rtmp metadata基类,用于描述rtmp格式信息 */