diff --git a/src/Player/PlayerBase.h b/src/Player/PlayerBase.h index 56fa5058..21a52e68 100644 --- a/src/Player/PlayerBase.h +++ b/src/Player/PlayerBase.h @@ -34,9 +34,10 @@ #include "Player.h" #include "Network/Socket.h" #include "Util/mini.h" -#include "Common/MediaSource.h" #include "Util/RingBuffer.h" +#include "Common/MediaSource.h" #include "Frame.h" +#include "Track.h" using namespace std; using namespace ZL::Util; @@ -46,93 +47,6 @@ using namespace ZL::Network; namespace ZL { namespace Player { -class TrackFormat { -public: - typedef std::shared_ptr Ptr; - typedef RingBuffer RingType; - typedef RingType::RingReader::Ptr ReaderType; - - typedef enum { - VideoCodecInvalid = -1, - VideoCodecH264 = 0, - VideoCodecMax - } VideoCodecID; - - typedef enum { - AudioCodecInvalid = -1, - AudioCodecAAC = 0, - AudioCodecMax - } AudioCodecID; - TrackFormat(){ - _ring = std::make_shared(); - } - virtual ~TrackFormat(){} - virtual TrackType getTrackType() const = 0; - virtual int getCodecId() const = 0; - - ReaderType attachReader(bool useBuffer = false){ - return _ring->attach(useBuffer); - } - - void writeFrame(const Frame::Ptr &frame,bool keypos = true){ - _ring->write(frame, keypos); - } -private: - RingType::Ptr _ring; -}; - -class VideoTrackFormat : public TrackFormat { -public: - TrackType getTrackType() const override { return TrackVideo;}; - virtual int getVideoHeight() const = 0; - virtual int getVideoWidth() const = 0; - virtual float getVideoFps() const = 0; -}; - -class AudioTrackFormat : public TrackFormat { -public: - TrackType getTrackType() const override { return TrackAudio;}; - virtual int getAudioSampleRate() const = 0; - virtual int getAudioSampleBit() const = 0; - virtual int getAudioChannel() const = 0; -}; - -class H264TrackFormat : public VideoTrackFormat{ -public: - H264TrackFormat(const string &sps,const string &pps){ - _sps = sps; - _pps = pps; - } - const string &getSps() const{ - return _sps; - } - const string &getPps() const{ - return _pps; - } - int getCodecId() const override{ - return TrackFormat::VideoCodecH264; - } -private: - string _sps; - string _pps; -}; - -class AACTrackFormat : public AudioTrackFormat{ -public: - AACTrackFormat(const string &aac_cfg){ - _cfg = aac_cfg; - } - const string &getAacCfg() const{ - return _cfg; - } - int getCodecId() const override{ - return TrackFormat::AudioCodecAAC; - } -private: - string _cfg; -}; - - class MediaFormat { public: virtual ~MediaFormat(){}; diff --git a/src/Player/Track.cpp b/src/Player/Track.cpp new file mode 100644 index 00000000..43f73ab7 --- /dev/null +++ b/src/Player/Track.cpp @@ -0,0 +1,5 @@ +// +// Created by xzl on 2018/10/21. +// + +#include "Track.h" diff --git a/src/Player/Track.h b/src/Player/Track.h new file mode 100644 index 00000000..b7dff3cc --- /dev/null +++ b/src/Player/Track.h @@ -0,0 +1,100 @@ +// +// Created by xzl on 2018/10/21. +// + +#ifndef ZLMEDIAKIT_TRACK_H +#define ZLMEDIAKIT_TRACK_H + +#include +#include +#include "Frame.h" +#include "Util/RingBuffer.h" +#include "Rtsp/Rtsp.h" + +using namespace std; +using namespace ZL::Util; + +class TrackFormat { +public: + typedef std::shared_ptr Ptr; + typedef RingBuffer RingType; + + typedef enum { + CodecInvalid = -1, + CodecH264 = 0, + CodecAAC = 0x0100, + CodecMax + } CodecID; + + TrackFormat(){ + _ring = std::make_shared(); + } + virtual ~TrackFormat(){} + virtual TrackType getTrackType() const = 0; + virtual int getCodecId() const = 0; + + + void writeFrame(const Frame::Ptr &frame,bool keypos = true){ + _ring->write(frame, keypos); + } + + RingType::Ptr& getRing() { + return _ring; + } +private: + RingType::Ptr _ring; +}; + +class VideoTrackFormat : public TrackFormat { +public: + TrackType getTrackType() const override { return TrackVideo;}; + virtual int getVideoHeight() const = 0; + virtual int getVideoWidth() const = 0; + virtual float getVideoFps() const = 0; +}; + +class AudioTrackFormat : public TrackFormat { +public: + TrackType getTrackType() const override { return TrackAudio;}; + virtual int getAudioSampleRate() const = 0; + virtual int getAudioSampleBit() const = 0; + virtual int getAudioChannel() const = 0; +}; + +class H264TrackFormat : public VideoTrackFormat{ +public: + H264TrackFormat(const string &sps,const string &pps){ + _sps = sps; + _pps = pps; + } + const string &getSps() const{ + return _sps; + } + const string &getPps() const{ + return _pps; + } + int getCodecId() const override{ + return TrackFormat::CodecH264; + } +private: + string _sps; + string _pps; +}; + +class AACTrackFormat : public AudioTrackFormat{ +public: + AACTrackFormat(const string &aac_cfg){ + _cfg = aac_cfg; + } + const string &getAacCfg() const{ + return _cfg; + } + int getCodecId() const override{ + return TrackFormat::CodecAAC; + } +private: + string _cfg; +}; + + +#endif //ZLMEDIAKIT_TRACK_H diff --git a/src/RTP/AACRtpEncoder.cpp b/src/RTP/AACRtpCodec.cpp similarity index 74% rename from src/RTP/AACRtpEncoder.cpp rename to src/RTP/AACRtpCodec.cpp index 141962af..25b0da48 100644 --- a/src/RTP/AACRtpEncoder.cpp +++ b/src/RTP/AACRtpCodec.cpp @@ -2,9 +2,9 @@ // Created by xzl on 2018/10/18. // -#include "AACRtpEncoder.h" +#include "AACRtpCodec.h" -void AACRtpEncoder::inputFame(const Frame::Ptr &frame, bool key_pos) { +void AACRtpCodec::inputFame(const Frame::Ptr &frame, bool key_pos) { RtpCodec::inputFame(frame, key_pos); GET_CONFIG_AND_REGISTER(uint32_t,cycleMS,Config::Rtp::kCycleMS); @@ -37,7 +37,7 @@ void AACRtpEncoder::inputFame(const Frame::Ptr &frame, bool key_pos) { } } -void AACRtpEncoder::makeAACRtp(const void *pData, unsigned int uiLen, bool bMark, uint32_t uiStamp) { +void AACRtpCodec::makeAACRtp(const void *pData, unsigned int uiLen, bool bMark, uint32_t uiStamp) { uint16_t u16RtpLen = uiLen + 12; m_ui32TimeStamp = (m_ui32SampleRate / 1000) * uiStamp; uint32_t ts = htonl(m_ui32TimeStamp); @@ -75,30 +75,32 @@ void AACRtpEncoder::makeAACRtp(const void *pData, unsigned int uiLen, bool bMark ///////////////////////////////////////////////////////////////////////////////////// -void AACRtpDecoder::inputRtp(const RtpPacket::Ptr &rtp, bool key_pos) { - RtpCodec::inputRtp(rtp, key_pos); +void AACRtpCodec::inputRtp(const RtpPacket::Ptr &rtppack, bool key_pos) { + RtpCodec::inputRtp(rtppack, key_pos); - auto &rtppack = *rtp; - char *frame = (char *) rtppack.payload + rtppack.offset; - int length = rtppack.length - rtppack.offset; + char *frame = (char *) rtppack->payload + rtppack->offset; + int length = rtppack->length - rtppack->offset; if (m_adts->aac_frame_length + length - 4 > sizeof(AdtsFrame::buffer)) { m_adts->aac_frame_length = 7; + WarnL << "aac负载数据太长"; return ; } memcpy(m_adts->buffer + m_adts->aac_frame_length, frame + 4, length - 4); m_adts->aac_frame_length += (length - 4); - if (rtppack.mark == true) { - m_adts->sequence = rtppack.sequence; - - //todo(xzl) 完成时间戳转换 -// m_adts->timeStamp = rtppack.timeStamp * (1000.0 / m_iSampleRate); + if (rtppack->mark == true) { + m_adts->sequence = rtppack->sequence; + //todo(xzl) 此处完成时间戳转换 +// m_adts->timeStamp = rtppack->timeStamp * (1000.0 / m_iSampleRate); writeAdtsHeader(*m_adts, m_adts->buffer); - RtpCodec::inputFame(m_adts,false); - m_adts->aac_frame_length = 7; + onGetAdts(m_adts); } + return ; } -AACRtpDecoder::AACRtpDecoder() { - m_adts = std::make_shared(); +void AACRtpCodec::onGetAdts(const AdtsFrame::Ptr &frame) { + RtpCodec::inputFame(frame, false); + m_adts = m_framePool.obtain(); + m_adts->aac_frame_length = 7; } + diff --git a/src/RTP/AACRtpEncoder.h b/src/RTP/AACRtpCodec.h similarity index 75% rename from src/RTP/AACRtpEncoder.h rename to src/RTP/AACRtpCodec.h index de67be64..86ec60c4 100644 --- a/src/RTP/AACRtpEncoder.h +++ b/src/RTP/AACRtpCodec.h @@ -8,34 +8,30 @@ #include "RtpCodec.h" -class AACRtpEncoder : public RtpEncoder { +class AACRtpCodec : public RtpEncoder { public: - AACRtpEncoder(uint32_t ui32Ssrc, + AACRtpCodec(uint32_t ui32Ssrc, uint32_t ui32MtuSize , uint32_t ui32SampleRate, uint8_t ui8PlayloadType = 97, uint8_t ui8Interleaved = TrackAudio * 2) : RtpEncoder(ui32Ssrc,ui32MtuSize,ui32SampleRate,ui8PlayloadType,ui8Interleaved) { + m_framePool.setSize(32); + m_adts = m_framePool.obtain(); } - ~AACRtpEncoder(){} + ~AACRtpCodec(){} void inputFame(const Frame::Ptr &frame,bool key_pos) override; -private: - void makeAACRtp(const void *pData, unsigned int uiLen, bool bMark, uint32_t uiStamp); -private: - unsigned char m_aucSectionBuf[1600]; -}; - - -class AACRtpDecoder : public RtpCodec{ -public: - AACRtpDecoder(); - ~AACRtpDecoder(){} - void inputRtp(const RtpPacket::Ptr &rtp, bool key_pos) override ; private: + void makeAACRtp(const void *pData, unsigned int uiLen, bool bMark, uint32_t uiStamp); + void onGetAdts(const AdtsFrame::Ptr &frame); +private: + unsigned char m_aucSectionBuf[1600]; AdtsFrame::Ptr m_adts; + ResourcePool m_framePool; }; + #endif //ZLMEDIAKIT_AACRTPCODEC_H diff --git a/src/RTP/H264RtpCodec.cpp b/src/RTP/H264RtpCodec.cpp new file mode 100644 index 00000000..f398a581 --- /dev/null +++ b/src/RTP/H264RtpCodec.cpp @@ -0,0 +1,179 @@ +// +// Created by xzl on 2018/10/18. +// + +#include "H264RtpCodec.h" + +void H264RtpCodec::inputFame(const Frame::Ptr &frame, bool key_pos) { + RtpCodec::inputFame(frame, key_pos); + + GET_CONFIG_AND_REGISTER(uint32_t,cycleMS,Config::Rtp::kCycleMS); + auto uiStamp = frame->stamp(); + auto pcData = frame->data(); + auto iLen = frame->size(); + + uiStamp %= cycleMS; + int iSize = m_ui32MtuSize - 2; + if (iLen > iSize) { //超过MTU + const unsigned char s_e_r_Start = 0x80; + const unsigned char s_e_r_Mid = 0x00; + const unsigned char s_e_r_End = 0x40; + //获取帧头数据,1byte + unsigned char naluType = *((unsigned char *) pcData) & 0x1f; //获取NALU的5bit 帧类型 + + unsigned char nal_ref_idc = *((unsigned char *) pcData) & 0x60; //获取NALU的2bit 帧重要程度 00 可以丢 11不能丢 + //nal_ref_idc = 0x60; + //组装FU-A帧头数据 2byte + unsigned char f_nri_type = nal_ref_idc + 28;//F为0 1bit,nri上面获取到2bit,28为FU-A分片类型5bit + unsigned char s_e_r_type = naluType; + bool bFirst = true; + bool mark = false; + int nOffset = 1; + while (!mark) { + if (iLen < nOffset + iSize) { //是否拆分结束 + iSize = iLen - nOffset; + mark = true; + s_e_r_type = s_e_r_End + naluType; + } else { + if (bFirst == true) { + s_e_r_type = s_e_r_Start + naluType; + bFirst = false; + } else { + s_e_r_type = s_e_r_Mid + naluType; + } + } + memcpy(m_aucSectionBuf, &f_nri_type, 1); + memcpy(m_aucSectionBuf + 1, &s_e_r_type, 1); + memcpy(m_aucSectionBuf + 2, (unsigned char *) pcData + nOffset, iSize); + nOffset += iSize; + makeH264Rtp(m_aucSectionBuf, iSize + 2, mark, uiStamp); + } + } else { + makeH264Rtp(pcData, iLen, true, uiStamp); + } +} + +void H264RtpCodec::makeH264Rtp(const void* data, unsigned int len, bool mark, uint32_t uiStamp) { + uint16_t ui16RtpLen = len + 12; + m_ui32TimeStamp = (m_ui32SampleRate / 1000) * uiStamp; + uint32_t ts = htonl(m_ui32TimeStamp); + uint16_t sq = htons(m_ui16Sequence); + uint32_t sc = htonl(m_ui32Ssrc); + + auto pRtppkt = obtainRtp(); + auto &rtppkt = *(pRtppkt.get()); + unsigned char *pucRtp = rtppkt.payload; + pucRtp[0] = '$'; + pucRtp[1] = m_ui8Interleaved; + pucRtp[2] = ui16RtpLen >> 8; + pucRtp[3] = ui16RtpLen & 0x00FF; + pucRtp[4] = 0x80; + pucRtp[5] = (mark << 7) | m_ui8PlayloadType; + memcpy(&pucRtp[6], &sq, 2); + memcpy(&pucRtp[8], &ts, 4); + //ssrc + memcpy(&pucRtp[12], &sc, 4); + //playload + memcpy(&pucRtp[16], data, len); + + rtppkt.PT = m_ui8PlayloadType; + rtppkt.interleaved = m_ui8Interleaved; + rtppkt.mark = mark; + rtppkt.length = len + 16; + rtppkt.sequence = m_ui16Sequence; + rtppkt.timeStamp = m_ui32TimeStamp; + rtppkt.ssrc = m_ui32Ssrc; + rtppkt.type = TrackVideo; + rtppkt.offset = 16; + + uint8_t type = ((uint8_t *) (data))[0] & 0x1F; + RtpCodec::inputRtp(pRtppkt,type == 5); + m_ui16Sequence++; +} + +//////////////////////////////////////////////////////////////////////// + +void H264RtpCodec::inputRtp(const RtpPacket::Ptr &rtp, bool key_pos) { + RtpCodec::inputRtp(rtp, decodeRtp(rtp,key_pos)); +} + +bool H264RtpCodec::decodeRtp(const RtpPacket::Ptr &rtppack, bool key_pos) { + + /** + * h264帧类型 + * Type==1:P/B frame + * Type==5:IDR frame + * Type==6:SEI frame + * Type==7:SPS frame + * Type==8:PPS frame + */ + + const uint8_t *frame = (uint8_t *) rtppack->payload + rtppack->offset; + int length = rtppack->length - rtppack->offset; + NALU nal; + MakeNalu(*frame, nal); + + if (nal.type >= 0 && nal.type < 24) { + //a full frame + m_h264frame->buffer.assign("\x0\x0\x0\x1", 4); + m_h264frame->buffer.append((char *)frame, length); + m_h264frame->type = nal.type; + m_h264frame->timeStamp = rtppack->timeStamp / 90; + m_h264frame->sequence = rtppack->sequence; + auto isIDR = m_h264frame->type == 5; + onGetH264(m_h264frame); + return (isIDR); //i frame + } + + if (nal.type == 28) { + //FU-A + FU fu; + MakeFU(frame[1], fu); + if (fu.S == 1) { + //FU-A start + char tmp = (nal.forbidden_zero_bit << 7 | nal.nal_ref_idc << 5 | fu.type); + m_h264frame->buffer.assign("\x0\x0\x0\x1", 4); + m_h264frame->buffer.push_back(tmp); + m_h264frame->buffer.append((char *)frame + 2, length - 2); + m_h264frame->type = fu.type; + m_h264frame->timeStamp = rtppack->timeStamp / 90; + m_h264frame->sequence = rtppack->sequence; + return (m_h264frame->type == 5); //i frame + } + + if (rtppack->sequence != (uint16_t)(m_h264frame->sequence + 1)) { + m_h264frame->buffer.clear(); + WarnL << "丢包,帧废弃:" << rtppack->sequence << "," << m_h264frame->sequence; + return false; + } + m_h264frame->sequence = rtppack->sequence; + if (fu.E == 1) { + //FU-A end + m_h264frame->buffer.append((char *)frame + 2, length - 2); + m_h264frame->timeStamp = rtppack->timeStamp / 90; + auto isIDR = m_h264frame->type == 5; + onGetH264(m_h264frame); + return isIDR; + } + //FU-A mid + m_h264frame->buffer.append((char *)frame + 2, length - 2); + return false; + } + + WarnL << "不支持的rtp类型:" << nal.type << " " << rtppack->sequence; + return false; + // 29 FU-B 单NAL单元B模式 + // 24 STAP-A 单一时间的组合包 + // 25 STAP-B 单一时间的组合包 + // 26 MTAP16 多个时间的组合包 + // 27 MTAP24 多个时间的组合包 + // 0 udef + // 30 udef + // 31 udef +} + +void H264RtpCodec::onGetH264(const H264Frame::Ptr &frame) { + RtpCodec::inputFame(frame,frame->type == 5); + m_h264frame = m_framePool.obtain(); + m_h264frame->buffer.clear(); +} diff --git a/src/RTP/H264RtpEncoder.h b/src/RTP/H264RtpCodec.h similarity index 58% rename from src/RTP/H264RtpEncoder.h rename to src/RTP/H264RtpCodec.h index 08c97546..3fd4b685 100644 --- a/src/RTP/H264RtpEncoder.h +++ b/src/RTP/H264RtpCodec.h @@ -6,23 +6,33 @@ #define ZLMEDIAKIT_H264RTPCODEC_H #include "RtpCodec.h" +#include "Util/ResourcePool.h" -class H264RtpEncoder : public RtpEncoder { +using namespace ZL::Util; + +class H264RtpCodec : public RtpEncoder { public: - H264RtpEncoder(uint32_t ui32Ssrc, + H264RtpCodec(uint32_t ui32Ssrc, uint32_t ui32MtuSize = 1400, uint32_t ui32SampleRate = 90000, uint8_t ui8PlayloadType = 96, uint8_t ui8Interleaved = TrackVideo * 2) : RtpEncoder(ui32Ssrc,ui32MtuSize,ui32SampleRate,ui8PlayloadType,ui8Interleaved) { + m_framePool.setSize(32); + m_h264frame = m_framePool.obtain(); } - ~H264RtpEncoder(){} + ~H264RtpCodec(){} void inputFame(const Frame::Ptr &frame,bool key_pos) override; + void inputRtp(const RtpPacket::Ptr &rtp, bool key_pos) override ; private: void makeH264Rtp(const void *pData, unsigned int uiLen, bool bMark, uint32_t uiStamp); + bool decodeRtp(const RtpPacket::Ptr &rtp, bool key_pos); + void onGetH264(const H264Frame::Ptr &frame); private: unsigned char m_aucSectionBuf[1600]; + H264Frame::Ptr m_h264frame; + ResourcePool m_framePool; }; diff --git a/src/RTP/H264RtpEncoder.cpp b/src/RTP/H264RtpEncoder.cpp deleted file mode 100644 index 139b2972..00000000 --- a/src/RTP/H264RtpEncoder.cpp +++ /dev/null @@ -1,92 +0,0 @@ -// -// Created by xzl on 2018/10/18. -// - -#include "H264RtpEncoder.h" - -void H264RtpEncoder::inputFame(const Frame::Ptr &frame, bool key_pos) { - RtpCodec::inputFame(frame, key_pos); - - GET_CONFIG_AND_REGISTER(uint32_t,cycleMS,Config::Rtp::kCycleMS); - auto uiStamp = frame->stamp(); - auto pcData = frame->data(); - auto iLen = frame->size(); - - uiStamp %= cycleMS; - int iSize = m_ui32MtuSize - 2; - if (iLen > iSize) { //超过MTU - const unsigned char s_e_r_Start = 0x80; - const unsigned char s_e_r_Mid = 0x00; - const unsigned char s_e_r_End = 0x40; - //获取帧头数据,1byte - unsigned char naluType = *((unsigned char *) pcData) & 0x1f; //获取NALU的5bit 帧类型 - - unsigned char nal_ref_idc = *((unsigned char *) pcData) & 0x60; //获取NALU的2bit 帧重要程度 00 可以丢 11不能丢 - //nal_ref_idc = 0x60; - //组装FU-A帧头数据 2byte - unsigned char f_nri_type = nal_ref_idc + 28;//F为0 1bit,nri上面获取到2bit,28为FU-A分片类型5bit - unsigned char s_e_r_type = naluType; - bool bFirst = true; - bool mark = false; - int nOffset = 1; - while (!mark) { - if (iLen < nOffset + iSize) { //是否拆分结束 - iSize = iLen - nOffset; - mark = true; - s_e_r_type = s_e_r_End + naluType; - } else { - if (bFirst == true) { - s_e_r_type = s_e_r_Start + naluType; - bFirst = false; - } else { - s_e_r_type = s_e_r_Mid + naluType; - } - } - memcpy(m_aucSectionBuf, &f_nri_type, 1); - memcpy(m_aucSectionBuf + 1, &s_e_r_type, 1); - memcpy(m_aucSectionBuf + 2, (unsigned char *) pcData + nOffset, iSize); - nOffset += iSize; - makeH264Rtp(m_aucSectionBuf, iSize + 2, mark, uiStamp); - } - } else { - makeH264Rtp(pcData, iLen, true, uiStamp); - } -} - -void H264RtpEncoder::makeH264Rtp(const void* data, unsigned int len, bool mark, uint32_t uiStamp) { - uint16_t ui16RtpLen = len + 12; - m_ui32TimeStamp = (m_ui32SampleRate / 1000) * uiStamp; - uint32_t ts = htonl(m_ui32TimeStamp); - uint16_t sq = htons(m_ui16Sequence); - uint32_t sc = htonl(m_ui32Ssrc); - - auto pRtppkt = obtainRtp(); - auto &rtppkt = *(pRtppkt.get()); - unsigned char *pucRtp = rtppkt.payload; - pucRtp[0] = '$'; - pucRtp[1] = m_ui8Interleaved; - pucRtp[2] = ui16RtpLen >> 8; - pucRtp[3] = ui16RtpLen & 0x00FF; - pucRtp[4] = 0x80; - pucRtp[5] = (mark << 7) | m_ui8PlayloadType; - memcpy(&pucRtp[6], &sq, 2); - memcpy(&pucRtp[8], &ts, 4); - //ssrc - memcpy(&pucRtp[12], &sc, 4); - //playload - memcpy(&pucRtp[16], data, len); - - rtppkt.PT = m_ui8PlayloadType; - rtppkt.interleaved = m_ui8Interleaved; - rtppkt.mark = mark; - rtppkt.length = len + 16; - rtppkt.sequence = m_ui16Sequence; - rtppkt.timeStamp = m_ui32TimeStamp; - rtppkt.ssrc = m_ui32Ssrc; - rtppkt.type = TrackVideo; - rtppkt.offset = 16; - - uint8_t type = ((uint8_t *) (data))[0] & 0x1F; - RtpCodec::inputRtp(pRtppkt,type == 5); - m_ui16Sequence++; -}