From 25c99470ee2ea9f8dfacf1c2aad392789f1a6742 Mon Sep 17 00:00:00 2001 From: xia-chu <771730766@qq.com> Date: Sun, 10 Dec 2023 10:21:40 +0800 Subject: [PATCH] feat: add support of codec plugin --- 3rdpart/ZLToolKit | 2 +- CMakeLists.txt | 2 + {src/Extension => ext-codec}/AAC.cpp | 75 ++++++- {src/Extension => ext-codec}/AAC.h | 4 +- {src/Extension => ext-codec}/AACRtmp.cpp | 0 {src/Extension => ext-codec}/AACRtmp.h | 4 +- {src/Extension => ext-codec}/AACRtp.cpp | 0 {src/Extension => ext-codec}/AACRtp.h | 5 +- ext-codec/CMakeLists.txt | 48 ++++ ext-codec/G711.cpp | 188 ++++++++++++++++ {src/Extension => ext-codec}/G711.h | 4 +- {src/Extension => ext-codec}/G711Rtp.cpp | 0 {src/Extension => ext-codec}/G711Rtp.h | 4 +- {src/Extension => ext-codec}/H264.cpp | 60 +++++ {src/Extension => ext-codec}/H264.h | 4 +- {src/Extension => ext-codec}/H264Rtmp.cpp | 0 {src/Extension => ext-codec}/H264Rtmp.h | 4 +- {src/Extension => ext-codec}/H264Rtp.cpp | 0 {src/Extension => ext-codec}/H264Rtp.h | 6 +- {src/Extension => ext-codec}/H265.cpp | 58 +++++ {src/Extension => ext-codec}/H265.h | 4 +- {src/Extension => ext-codec}/H265Rtmp.cpp | 0 {src/Extension => ext-codec}/H265Rtmp.h | 2 +- {src/Extension => ext-codec}/H265Rtp.cpp | 0 {src/Extension => ext-codec}/H265Rtp.h | 4 +- ext-codec/JPEG.cpp | 101 +++++++++ {src/Extension => ext-codec}/JPEG.h | 4 +- {src/Extension => ext-codec}/JPEGRtp.cpp | 0 {src/Extension => ext-codec}/JPEGRtp.h | 4 +- {src/Extension => ext-codec}/L16.cpp | 52 ++++- {src/Extension => ext-codec}/L16.h | 6 +- {src/Extension => ext-codec}/Opus.cpp | 50 ++++- {src/Extension => ext-codec}/Opus.h | 6 +- {src/Extension => ext-codec}/SPSParser.c | 0 {src/Extension => ext-codec}/SPSParser.h | 0 src/Extension/Factory.cpp | 261 ++++++---------------- src/Extension/Factory.h | 28 ++- src/Extension/Frame.cpp | 2 - src/Extension/G711.cpp | 72 ------ src/Extension/JPEG.cpp | 50 ----- src/Rtp/GB28181Process.cpp | 10 +- src/Rtsp/RtspDemuxer.cpp | 4 +- 42 files changed, 772 insertions(+), 356 deletions(-) rename {src/Extension => ext-codec}/AAC.cpp (84%) rename {src/Extension => ext-codec}/AAC.h (94%) rename {src/Extension => ext-codec}/AACRtmp.cpp (100%) rename {src/Extension => ext-codec}/AACRtmp.h (97%) rename {src/Extension => ext-codec}/AACRtp.cpp (100%) rename {src/Extension => ext-codec}/AACRtp.h (96%) create mode 100644 ext-codec/CMakeLists.txt create mode 100644 ext-codec/G711.cpp rename {src/Extension => ext-codec}/G711.h (91%) rename {src/Extension => ext-codec}/G711Rtp.cpp (100%) rename {src/Extension => ext-codec}/G711Rtp.h (94%) rename {src/Extension => ext-codec}/H264.cpp (85%) rename {src/Extension => ext-codec}/H264.h (98%) rename {src/Extension => ext-codec}/H264Rtmp.cpp (100%) rename {src/Extension => ext-codec}/H264Rtmp.h (97%) rename {src/Extension => ext-codec}/H264Rtp.cpp (100%) rename {src/Extension => ext-codec}/H264Rtp.h (98%) rename {src/Extension => ext-codec}/H265.cpp (82%) rename {src/Extension => ext-codec}/H265.h (98%) rename {src/Extension => ext-codec}/H265Rtmp.cpp (100%) rename {src/Extension => ext-codec}/H265Rtmp.h (98%) rename {src/Extension => ext-codec}/H265Rtp.cpp (100%) rename {src/Extension => ext-codec}/H265Rtp.h (98%) create mode 100644 ext-codec/JPEG.cpp rename {src/Extension => ext-codec}/JPEG.h (97%) rename {src/Extension => ext-codec}/JPEGRtp.cpp (100%) rename {src/Extension => ext-codec}/JPEGRtp.h (95%) rename {src/Extension => ext-codec}/L16.cpp (53%) rename {src/Extension => ext-codec}/L16.h (88%) rename {src/Extension => ext-codec}/Opus.cpp (51%) rename {src/Extension => ext-codec}/Opus.h (91%) rename {src/Extension => ext-codec}/SPSParser.c (100%) rename {src/Extension => ext-codec}/SPSParser.h (100%) delete mode 100644 src/Extension/G711.cpp delete mode 100644 src/Extension/JPEG.cpp diff --git a/3rdpart/ZLToolKit b/3rdpart/ZLToolKit index f8471ab1..9a545d7d 160000 --- a/3rdpart/ZLToolKit +++ b/3rdpart/ZLToolKit @@ -1 +1 @@ -Subproject commit f8471ab1e6810358646f39e72f9ea035b1458363 +Subproject commit 9a545d7d09fc4b570c1d29a798622c7923111735 diff --git a/CMakeLists.txt b/CMakeLists.txt index ec958e43..b9dbfa64 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -477,6 +477,8 @@ add_subdirectory(3rdpart) add_subdirectory(src) +add_subdirectory(ext-codec) + if(ENABLE_SRT) add_subdirectory(srt) endif() diff --git a/src/Extension/AAC.cpp b/ext-codec/AAC.cpp similarity index 84% rename from src/Extension/AAC.cpp rename to ext-codec/AAC.cpp index 148504ac..62c443da 100644 --- a/src/Extension/AAC.cpp +++ b/ext-codec/AAC.cpp @@ -9,6 +9,10 @@ */ #include "AAC.h" +#include "AACRtp.h" +#include "AACRtmp.h" +#include "Common/Parser.h" +#include "Extension/Factory.h" #ifdef ENABLE_MP4 #include "mpeg4-aac.h" #endif @@ -357,4 +361,73 @@ Sdp::Ptr AACTrack::getSdp(uint8_t payload_type) const { return std::make_shared(getExtraData()->toString(), payload_type, getAudioSampleRate(), getAudioChannel(), getBitRate() / 1024); } -}//namespace mediakit \ No newline at end of file +namespace { + +CodecId getCodec() { + return CodecAAC; +} + +Track::Ptr getTrackByCodecId(int sample_rate, int channels, int sample_bit) { + return std::make_shared(); +} + +Track::Ptr getTrackBySdp(const SdpTrack::Ptr &track) { + string aac_cfg_str = findSubString(track->_fmtp.data(), "config=", ";"); + if (aac_cfg_str.empty()) { + aac_cfg_str = findSubString(track->_fmtp.data(), "config=", nullptr); + } + if (aac_cfg_str.empty()) { + // 如果sdp中获取不到aac config信息,那么在rtp也无法获取,那么忽略该Track + return nullptr; + } + string aac_cfg; + for (size_t i = 0; i < aac_cfg_str.size() / 2; ++i) { + unsigned int cfg; + sscanf(aac_cfg_str.substr(i * 2, 2).data(), "%02X", &cfg); + cfg &= 0x00FF; + aac_cfg.push_back((char)cfg); + } + return std::make_shared(aac_cfg); +} + +RtpCodec::Ptr getRtpEncoderByCodecId(uint8_t pt) { + return std::make_shared(); +} + +RtpCodec::Ptr getRtpDecoderByCodecId() { + return std::make_shared(); +} + +RtmpCodec::Ptr getRtmpEncoderByTrack(const Track::Ptr &track) { + return std::make_shared(track); +} + +RtmpCodec::Ptr getRtmpDecoderByTrack(const Track::Ptr &track) { + return std::make_shared(track); +} + +size_t aacPrefixSize(const char *data, size_t bytes) { + uint8_t *ptr = (uint8_t *)data; + size_t prefix = 0; + if (!(bytes > ADTS_HEADER_LEN && ptr[0] == 0xFF && (ptr[1] & 0xF0) == 0xF0)) { + return 0; + } + return ADTS_HEADER_LEN; +} + +Frame::Ptr getFrameFromPtr(const char *data, size_t bytes, uint64_t dts, uint64_t pts) { + return std::make_shared(CodecAAC, (char *)data, bytes, dts, pts, aacPrefixSize(data, bytes)); +} + +} // namespace + +CodecPlugin aac_plugin = { getCodec, + getTrackByCodecId, + getTrackBySdp, + getRtpEncoderByCodecId, + getRtpDecoderByCodecId, + getRtmpEncoderByTrack, + getRtmpDecoderByTrack, + getFrameFromPtr }; + +} // namespace mediakit \ No newline at end of file diff --git a/src/Extension/AAC.h b/ext-codec/AAC.h similarity index 94% rename from src/Extension/AAC.h rename to ext-codec/AAC.h index e815d338..0b6eeec1 100644 --- a/src/Extension/AAC.h +++ b/ext-codec/AAC.h @@ -11,8 +11,8 @@ #ifndef ZLMEDIAKIT_AAC_H #define ZLMEDIAKIT_AAC_H -#include "Frame.h" -#include "Track.h" +#include "Extension/Frame.h" +#include "Extension/Track.h" #define ADTS_HEADER_LEN 7 namespace mediakit{ diff --git a/src/Extension/AACRtmp.cpp b/ext-codec/AACRtmp.cpp similarity index 100% rename from src/Extension/AACRtmp.cpp rename to ext-codec/AACRtmp.cpp diff --git a/src/Extension/AACRtmp.h b/ext-codec/AACRtmp.h similarity index 97% rename from src/Extension/AACRtmp.h rename to ext-codec/AACRtmp.h index 80ce66c9..55c3eb34 100644 --- a/src/Extension/AACRtmp.h +++ b/ext-codec/AACRtmp.h @@ -11,11 +11,11 @@ #ifndef ZLMEDIAKIT_AACRTMPCODEC_H #define ZLMEDIAKIT_AACRTMPCODEC_H +#include "AAC.h" #include "Rtmp/RtmpCodec.h" #include "Extension/Track.h" -#include "Extension/AAC.h" -namespace mediakit{ +namespace mediakit { /** * aac Rtmp转adts类 */ diff --git a/src/Extension/AACRtp.cpp b/ext-codec/AACRtp.cpp similarity index 100% rename from src/Extension/AACRtp.cpp rename to ext-codec/AACRtp.cpp diff --git a/src/Extension/AACRtp.h b/ext-codec/AACRtp.h similarity index 96% rename from src/Extension/AACRtp.h rename to ext-codec/AACRtp.h index 2716a066..f4559c27 100644 --- a/src/Extension/AACRtp.h +++ b/ext-codec/AACRtp.h @@ -11,9 +11,10 @@ #ifndef ZLMEDIAKIT_AACRTPCODEC_H #define ZLMEDIAKIT_AACRTPCODEC_H +#include "AAC.h" #include "Rtsp/RtpCodec.h" -#include "Extension/AAC.h" -namespace mediakit{ + +namespace mediakit { /** * aac rtp转adts类 */ diff --git a/ext-codec/CMakeLists.txt b/ext-codec/CMakeLists.txt new file mode 100644 index 00000000..23190fb8 --- /dev/null +++ b/ext-codec/CMakeLists.txt @@ -0,0 +1,48 @@ +# MIT License +# +# Copyright (c) 2016-2022 The ZLMediaKit project authors. All Rights Reserved. +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. +# + +set(COMPILE_DEFINITIONS) +set(INCLUDE_DIRECTORIES) + +file(GLOB EXT_SRC_LIST + ${CMAKE_CURRENT_SOURCE_DIR}/*.c + ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/*.h + ${CMAKE_CURRENT_SOURCE_DIR}/*.hpp) + +add_library(ext-codec STATIC ${EXT_SRC_LIST}) +add_library(ZLMediaKit::ext-codec ALIAS ext-codec) + +target_compile_options(ext-codec PRIVATE ${COMPILE_OPTIONS_DEFAULT}) +target_compile_definitions(ext-codec PUBLIC ${COMPILE_DEFINITIONS}) + +target_link_libraries(ext-codec PRIVATE ZLMediaKit::MediaKit ZLMediaKit::ToolKit ${LINK_LIBRARIES}) + +target_include_directories(ext-codec + PRIVATE + "$" + PUBLIC + "$" + ${INCLUDE_DIRECTORIES}) + +update_cached_list(MK_LINK_LIBRARIES ZLMediaKit::ext-codec ${LINK_LIBRARIES}) diff --git a/ext-codec/G711.cpp b/ext-codec/G711.cpp new file mode 100644 index 00000000..1185bff4 --- /dev/null +++ b/ext-codec/G711.cpp @@ -0,0 +1,188 @@ +/* + * Copyright (c) 2016-present The ZLMediaKit project authors. All Rights Reserved. + * + * This file is part of ZLMediaKit(https://github.com/ZLMediaKit/ZLMediaKit). + * + * Use of this source code is governed by MIT-like 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 "G711.h" +#include "G711Rtp.h" +#include "Extension/Factory.h" +#include "Extension/CommonRtp.h" +#include "Extension/CommonRtmp.h" + +using namespace std; +using namespace toolkit; + +namespace mediakit { + +/** + * G711类型SDP + */ +class G711Sdp : public Sdp { +public: + /** + * G711采样率固定为8000 + * @param codecId G711A G711U + * @param payload_type rtp payload type + * @param sample_rate 音频采样率 + * @param channels 通道数 + * @param bitrate 比特率 + */ + G711Sdp(CodecId codecId, int payload_type, int sample_rate, int channels, int bitrate) + : Sdp(sample_rate, payload_type) { + _printer << "m=audio 0 RTP/AVP " << payload_type << "\r\n"; + if (bitrate) { + _printer << "b=AS:" << bitrate << "\r\n"; + } + _printer << "a=rtpmap:" << payload_type << " " << getCodecName(codecId) << "/" << sample_rate << "/" << channels << "\r\n"; + } + + string getSdp() const override { + return _printer; + } + +private: + _StrPrinter _printer; +}; + +Track::Ptr G711Track::clone() const { + return std::make_shared(*this); +} + +Sdp::Ptr G711Track::getSdp(uint8_t payload_type) const { + if (!ready()) { + WarnL << getCodecName() << " Track未准备好"; + return nullptr; + } + + const auto codec = getCodecId(); + const auto sample_rate = getAudioSampleRate(); + const auto audio_channel = getAudioChannel(); + const auto bitrate = getBitRate() >> 10; + if (sample_rate == 8000 && audio_channel == 1) { + // https://datatracker.ietf.org/doc/html/rfc3551#section-6 + payload_type = (codec == CodecG711U) ? Rtsp::PT_PCMU : Rtsp::PT_PCMA; + } + + return std::make_shared(codec, payload_type, sample_rate, audio_channel, bitrate); +} + + +namespace { + +CodecId getCodecA() { + return CodecG711A; +} + +CodecId getCodecU() { + return CodecG711A; +} + +Track::Ptr getTrackByCodecId_l(CodecId codec, int sample_rate, int channels, int sample_bit) { + return (sample_rate && channels && sample_bit) ? std::make_shared(codec, sample_rate, channels, sample_bit) : nullptr; +} + +Track::Ptr getTrackByCodecIdA(int sample_rate, int channels, int sample_bit) { + return getTrackByCodecId_l(CodecG711A, sample_rate, channels, sample_bit); +} + +Track::Ptr getTrackByCodecIdU(int sample_rate, int channels, int sample_bit) { + return getTrackByCodecId_l(CodecG711U, sample_rate, channels, sample_bit); +} + +Track::Ptr getTrackBySdp_l(CodecId codec, const SdpTrack::Ptr &track) { + return std::make_shared(codec, track->_samplerate, track->_channel, 16); +} + +Track::Ptr getTrackBySdpA(const SdpTrack::Ptr &track) { + return getTrackBySdp_l(CodecG711A, track); +} + +Track::Ptr getTrackBySdpU(const SdpTrack::Ptr &track) { + return getTrackBySdp_l(CodecG711U, track); +} + +RtpCodec::Ptr getRtpEncoderByCodecId_l(CodecId codec, uint8_t pt) { + if (pt == Rtsp::PT_PCMA || pt == Rtsp::PT_PCMU) { + return std::make_shared(codec, 1); + } + return std::make_shared(); +} + +RtpCodec::Ptr getRtpEncoderByCodecIdA(uint8_t pt) { + return getRtpEncoderByCodecId_l(CodecG711A, pt); +} + +RtpCodec::Ptr getRtpEncoderByCodecIdU(uint8_t pt) { + return getRtpEncoderByCodecId_l(CodecG711U, pt); +} + +RtpCodec::Ptr getRtpDecoderByCodecId_l(CodecId codec) { + return std::make_shared(codec); +} + +RtpCodec::Ptr getRtpDecoderByCodecIdA() { + return getRtpDecoderByCodecId_l(CodecG711A); +} + +RtpCodec::Ptr getRtpDecoderByCodecIdU() { + return getRtpDecoderByCodecId_l(CodecG711U); +} + +RtmpCodec::Ptr getRtmpEncoderByTrack(const Track::Ptr &track) { + auto audio_track = dynamic_pointer_cast(track); + if (audio_track->getAudioSampleRate() != 8000 || audio_track->getAudioChannel() != 1 || audio_track->getAudioSampleBit() != 16) { + //rtmp对g711只支持8000/1/16规格,但是ZLMediaKit可以解析其他规格的G711 + WarnL << "RTMP only support G711 with 8000/1/16, now is" + << audio_track->getAudioSampleRate() << "/" + << audio_track->getAudioChannel() << "/" + << audio_track->getAudioSampleBit() + << ", ignored it"; + return nullptr; + } + return std::make_shared(track); +} + +RtmpCodec::Ptr getRtmpDecoderByTrack(const Track::Ptr &track) { + return std::make_shared(track); +} + +Frame::Ptr getFrameFromPtr_l(CodecId codec, const char *data, size_t bytes, uint64_t dts, uint64_t pts) { + return std::make_shared(codec, (char *)data, bytes, dts, pts); +} + +Frame::Ptr getFrameFromPtrA(const char *data, size_t bytes, uint64_t dts, uint64_t pts) { + return getFrameFromPtr_l(CodecG711A, (char *)data, bytes, dts, pts); +} + +Frame::Ptr getFrameFromPtrU(const char *data, size_t bytes, uint64_t dts, uint64_t pts) { + return getFrameFromPtr_l(CodecG711U, (char *)data, bytes, dts, pts); +} + +} // namespace + +CodecPlugin g711a_plugin = { getCodecA, + getTrackByCodecIdA, + getTrackBySdpA, + getRtpEncoderByCodecIdA, + getRtpDecoderByCodecIdA, + getRtmpEncoderByTrack, + getRtmpDecoderByTrack, + getFrameFromPtrA }; + +CodecPlugin g711u_plugin = { getCodecU, + getTrackByCodecIdU, + getTrackBySdpU, + getRtpEncoderByCodecIdU, + getRtpDecoderByCodecIdU, + getRtmpEncoderByTrack, + getRtmpDecoderByTrack, + getFrameFromPtrA }; + +}//namespace mediakit + + diff --git a/src/Extension/G711.h b/ext-codec/G711.h similarity index 91% rename from src/Extension/G711.h rename to ext-codec/G711.h index 05f3e58b..be510553 100644 --- a/src/Extension/G711.h +++ b/ext-codec/G711.h @@ -11,8 +11,8 @@ #ifndef ZLMEDIAKIT_G711_H #define ZLMEDIAKIT_G711_H -#include "Frame.h" -#include "Track.h" +#include "Extension/Frame.h" +#include "Extension/Track.h" namespace mediakit{ diff --git a/src/Extension/G711Rtp.cpp b/ext-codec/G711Rtp.cpp similarity index 100% rename from src/Extension/G711Rtp.cpp rename to ext-codec/G711Rtp.cpp diff --git a/src/Extension/G711Rtp.h b/ext-codec/G711Rtp.h similarity index 94% rename from src/Extension/G711Rtp.h rename to ext-codec/G711Rtp.h index 0ddd40ff..2d709e53 100644 --- a/src/Extension/G711Rtp.h +++ b/ext-codec/G711Rtp.h @@ -11,9 +11,9 @@ #ifndef ZLMEDIAKIT_G711RTP_H #define ZLMEDIAKIT_G711RTP_H -#include "Frame.h" -#include "CommonRtp.h" #include "Rtsp/RtpCodec.h" +#include "Extension/Frame.h" +#include "Extension/CommonRtp.h" namespace mediakit { diff --git a/src/Extension/H264.cpp b/ext-codec/H264.cpp similarity index 85% rename from src/Extension/H264.cpp rename to ext-codec/H264.cpp index c147011e..59471775 100644 --- a/src/Extension/H264.cpp +++ b/ext-codec/H264.cpp @@ -9,10 +9,14 @@ */ #include "H264.h" +#include "H264Rtmp.h" +#include "H264Rtp.h" #include "SPSParser.h" #include "Util/logger.h" #include "Util/base64.h" +#include "Common/Parser.h" #include "Common/config.h" +#include "Extension/Factory.h" #ifdef ENABLE_MP4 #include "mpeg4-avc.h" @@ -346,4 +350,60 @@ Sdp::Ptr H264Track::getSdp(uint8_t payload_type) const { return std::make_shared(_sps, _pps, payload_type, getBitRate() / 1024); } +namespace { + +CodecId getCodec() { + return CodecH264; +} + +Track::Ptr getTrackByCodecId(int sample_rate, int channels, int sample_bit) { + return std::make_shared(); +} + +Track::Ptr getTrackBySdp(const SdpTrack::Ptr &track) { + //a=fmtp:96 packetization-mode=1;profile-level-id=42C01F;sprop-parameter-sets=Z0LAH9oBQBboQAAAAwBAAAAPI8YMqA==,aM48gA== + auto map = Parser::parseArgs(track->_fmtp, ";", "="); + auto sps_pps = map["sprop-parameter-sets"]; + string base64_SPS = findSubString(sps_pps.data(), NULL, ","); + string base64_PPS = findSubString(sps_pps.data(), ",", NULL); + auto sps = decodeBase64(base64_SPS); + auto pps = decodeBase64(base64_PPS); + if (sps.empty() || pps.empty()) { + //如果sdp里面没有sps/pps,那么可能在后续的rtp里面恢复出sps/pps + return std::make_shared(); + } + return std::make_shared(sps, pps, 0, 0); +} + +RtpCodec::Ptr getRtpEncoderByCodecId(uint8_t pt) { + return std::make_shared(); +} + +RtpCodec::Ptr getRtpDecoderByCodecId() { + return std::make_shared(); +} + +RtmpCodec::Ptr getRtmpEncoderByTrack(const Track::Ptr &track) { + return std::make_shared(track); +} + +RtmpCodec::Ptr getRtmpDecoderByTrack(const Track::Ptr &track) { + return std::make_shared(track); +} + +Frame::Ptr getFrameFromPtr(const char *data, size_t bytes, uint64_t dts, uint64_t pts) { + return std::make_shared((char *)data, bytes, dts, pts, prefixSize(data, bytes)); +} + +} // namespace + +CodecPlugin h264_plugin = { getCodec, + getTrackByCodecId, + getTrackBySdp, + getRtpEncoderByCodecId, + getRtpDecoderByCodecId, + getRtmpEncoderByTrack, + getRtmpDecoderByTrack, + getFrameFromPtr }; + } // namespace mediakit diff --git a/src/Extension/H264.h b/ext-codec/H264.h similarity index 98% rename from src/Extension/H264.h rename to ext-codec/H264.h index 238bc927..cf054da0 100644 --- a/src/Extension/H264.h +++ b/ext-codec/H264.h @@ -11,8 +11,8 @@ #ifndef ZLMEDIAKIT_H264_H #define ZLMEDIAKIT_H264_H -#include "Frame.h" -#include "Track.h" +#include "Extension/Frame.h" +#include "Extension/Track.h" #define H264_TYPE(v) ((uint8_t)(v) & 0x1F) diff --git a/src/Extension/H264Rtmp.cpp b/ext-codec/H264Rtmp.cpp similarity index 100% rename from src/Extension/H264Rtmp.cpp rename to ext-codec/H264Rtmp.cpp diff --git a/src/Extension/H264Rtmp.h b/ext-codec/H264Rtmp.h similarity index 97% rename from src/Extension/H264Rtmp.h rename to ext-codec/H264Rtmp.h index 64a6bcfe..f610f47c 100644 --- a/src/Extension/H264Rtmp.h +++ b/ext-codec/H264Rtmp.h @@ -11,11 +11,11 @@ #ifndef ZLMEDIAKIT_H264RTMPCODEC_H #define ZLMEDIAKIT_H264RTMPCODEC_H +#include "H264.h" #include "Rtmp/RtmpCodec.h" #include "Extension/Track.h" -#include "Extension/H264.h" -namespace mediakit{ +namespace mediakit { /** * h264 Rtmp解码类 * 将 h264 over rtmp 解复用出 h264-Frame diff --git a/src/Extension/H264Rtp.cpp b/ext-codec/H264Rtp.cpp similarity index 100% rename from src/Extension/H264Rtp.cpp rename to ext-codec/H264Rtp.cpp diff --git a/src/Extension/H264Rtp.h b/ext-codec/H264Rtp.h similarity index 98% rename from src/Extension/H264Rtp.h rename to ext-codec/H264Rtp.h index c013bf8b..3f98be07 100644 --- a/src/Extension/H264Rtp.h +++ b/ext-codec/H264Rtp.h @@ -11,12 +11,12 @@ #ifndef ZLMEDIAKIT_H264RTPCODEC_H #define ZLMEDIAKIT_H264RTPCODEC_H -#include "Rtsp/RtpCodec.h" -#include "Extension/H264.h" +#include "H264.h" // for DtsGenerator #include "Common/Stamp.h" +#include "Rtsp/RtpCodec.h" -namespace mediakit{ +namespace mediakit { /** * h264 rtp解码类 diff --git a/src/Extension/H265.cpp b/ext-codec/H265.cpp similarity index 82% rename from src/Extension/H265.cpp rename to ext-codec/H265.cpp index e8daf399..3a999255 100644 --- a/src/Extension/H265.cpp +++ b/ext-codec/H265.cpp @@ -9,8 +9,12 @@ */ #include "H265.h" +#include "H265Rtp.h" +#include "H265Rtmp.h" #include "SPSParser.h" #include "Util/base64.h" +#include "Common/Parser.h" +#include "Extension/Factory.h" #ifdef ENABLE_MP4 #include "mpeg4-hevc.h" @@ -263,5 +267,59 @@ Sdp::Ptr H265Track::getSdp(uint8_t payload_type) const { return std::make_shared(_vps, _sps, _pps, payload_type, getBitRate() / 1024); } +namespace { + +CodecId getCodec() { + return CodecH265; +} + +Track::Ptr getTrackByCodecId(int sample_rate, int channels, int sample_bit) { + return std::make_shared(); +} + +Track::Ptr getTrackBySdp(const SdpTrack::Ptr &track) { + // a=fmtp:96 sprop-sps=QgEBAWAAAAMAsAAAAwAAAwBdoAKAgC0WNrkky/AIAAADAAgAAAMBlQg=; sprop-pps=RAHA8vA8kAA= + auto map = Parser::parseArgs(track->_fmtp, ";", "="); + auto vps = decodeBase64(map["sprop-vps"]); + auto sps = decodeBase64(map["sprop-sps"]); + auto pps = decodeBase64(map["sprop-pps"]); + if (sps.empty() || pps.empty()) { + // 如果sdp里面没有sps/pps,那么可能在后续的rtp里面恢复出sps/pps + return std::make_shared(); + } + return std::make_shared(vps, sps, pps, 0, 0, 0); +} + +RtpCodec::Ptr getRtpEncoderByCodecId(uint8_t pt) { + return std::make_shared(); +} + +RtpCodec::Ptr getRtpDecoderByCodecId() { + return std::make_shared(); +} + +RtmpCodec::Ptr getRtmpEncoderByTrack(const Track::Ptr &track) { + return std::make_shared(track); +} + +RtmpCodec::Ptr getRtmpDecoderByTrack(const Track::Ptr &track) { + return std::make_shared(track); +} + +Frame::Ptr getFrameFromPtr(const char *data, size_t bytes, uint64_t dts, uint64_t pts) { + return std::make_shared((char *)data, bytes, dts, pts, prefixSize(data, bytes)); +} + +} // namespace + +CodecPlugin h265_plugin = { getCodec, + getTrackByCodecId, + getTrackBySdp, + getRtpEncoderByCodecId, + getRtpDecoderByCodecId, + getRtmpEncoderByTrack, + getRtmpDecoderByTrack, + getFrameFromPtr }; + }//namespace mediakit diff --git a/src/Extension/H265.h b/ext-codec/H265.h similarity index 98% rename from src/Extension/H265.h rename to ext-codec/H265.h index 2a92a690..50775727 100644 --- a/src/Extension/H265.h +++ b/ext-codec/H265.h @@ -11,9 +11,9 @@ #ifndef ZLMEDIAKIT_H265_H #define ZLMEDIAKIT_H265_H -#include "Frame.h" -#include "Track.h" #include "H264.h" +#include "Extension/Track.h" +#include "Extension/Frame.h" #define H265_TYPE(v) (((uint8_t)(v) >> 1) & 0x3f) diff --git a/src/Extension/H265Rtmp.cpp b/ext-codec/H265Rtmp.cpp similarity index 100% rename from src/Extension/H265Rtmp.cpp rename to ext-codec/H265Rtmp.cpp diff --git a/src/Extension/H265Rtmp.h b/ext-codec/H265Rtmp.h similarity index 98% rename from src/Extension/H265Rtmp.h rename to ext-codec/H265Rtmp.h index 6e25e23a..36c4d846 100644 --- a/src/Extension/H265Rtmp.h +++ b/ext-codec/H265Rtmp.h @@ -11,9 +11,9 @@ #ifndef ZLMEDIAKIT_H265RTMPCODEC_H #define ZLMEDIAKIT_H265RTMPCODEC_H +#include "H265.h" #include "Rtmp/RtmpCodec.h" #include "Extension/Track.h" -#include "Extension/H265.h" namespace mediakit { /** diff --git a/src/Extension/H265Rtp.cpp b/ext-codec/H265Rtp.cpp similarity index 100% rename from src/Extension/H265Rtp.cpp rename to ext-codec/H265Rtp.cpp diff --git a/src/Extension/H265Rtp.h b/ext-codec/H265Rtp.h similarity index 98% rename from src/Extension/H265Rtp.h rename to ext-codec/H265Rtp.h index c46f786a..1a1c4a8b 100644 --- a/src/Extension/H265Rtp.h +++ b/ext-codec/H265Rtp.h @@ -11,12 +11,12 @@ #ifndef ZLMEDIAKIT_H265RTPCODEC_H #define ZLMEDIAKIT_H265RTPCODEC_H +#include "H265.h" #include "Rtsp/RtpCodec.h" -#include "Extension/H265.h" // for DtsGenerator #include "Common/Stamp.h" -namespace mediakit{ +namespace mediakit { /** * h265 rtp解码类 diff --git a/ext-codec/JPEG.cpp b/ext-codec/JPEG.cpp new file mode 100644 index 00000000..df9964f3 --- /dev/null +++ b/ext-codec/JPEG.cpp @@ -0,0 +1,101 @@ +#include "JPEG.h" +#include "JPEGRtp.h" +#include "Rtsp/Rtsp.h" +#include "Util/util.h" +#include "Extension/Factory.h" + +using namespace toolkit; + +namespace mediakit { + +bool JPEGTrack::inputFrame(const Frame::Ptr &frame) { + if (!ready()) { + if (_height > 0 && _width > 0) { + if (_tmp == 0) _tmp = frame->dts(); + else _fps = 1000.0 / (frame->dts() - _tmp); + } else getVideoResolution((uint8_t*)frame->data(), frame->size()); + return false; + } + return VideoTrack::inputFrame(frame); +} + +void JPEGTrack::getVideoResolution(const uint8_t *buf, int len) { + for (int i = 0; i < len - 8; i++) { + if (buf[i] != 0xff) + continue; + if (buf[i + 1] == 0xC0 /*SOF0*/) { + _height = buf[i + 5] * 256 + buf[i + 6]; + _width = buf[i + 7] * 256 + buf[i + 8]; + return; + } + } +} + +class JPEGSdp : public Sdp { +public: + JPEGSdp(int bitrate) : Sdp(90000, Rtsp::PT_JPEG) { + _printer << "m=video 0 RTP/AVP " << (int)getPayloadType() << "\r\n"; + if (bitrate) { + _printer << "b=AS:" << bitrate << "\r\n"; + } + } + + std::string getSdp() const { return _printer; } + +private: + _StrPrinter _printer; +}; + +Sdp::Ptr JPEGTrack::getSdp(uint8_t) const { + return std::make_shared(getBitRate() / 1024); +} + + +namespace { + +CodecId getCodec() { + return CodecJPEG; +} + +Track::Ptr getTrackByCodecId(int sample_rate, int channels, int sample_bit) { + return std::make_shared(); +} + +Track::Ptr getTrackBySdp(const SdpTrack::Ptr &track) { + return std::make_shared(); +} + +RtpCodec::Ptr getRtpEncoderByCodecId(uint8_t pt) { + return std::make_shared(); +} + +RtpCodec::Ptr getRtpDecoderByCodecId() { + return std::make_shared(); +} + +RtmpCodec::Ptr getRtmpEncoderByTrack(const Track::Ptr &track) { + WarnL << "Unsupported jpeg rtmp encoder"; + return nullptr; +} + +RtmpCodec::Ptr getRtmpDecoderByTrack(const Track::Ptr &track) { + WarnL << "Unsupported jpeg rtmp decoder"; + return nullptr; +} + +Frame::Ptr getFrameFromPtr(const char *data, size_t bytes, uint64_t dts, uint64_t pts) { + return std::make_shared>(0, CodecJPEG, (char *)data, bytes, dts, pts); +} + +} // namespace + +CodecPlugin jpeg_plugin = { getCodec, + getTrackByCodecId, + getTrackBySdp, + getRtpEncoderByCodecId, + getRtpDecoderByCodecId, + getRtmpEncoderByTrack, + getRtmpDecoderByTrack, + getFrameFromPtr }; + +} // namespace mediakit diff --git a/src/Extension/JPEG.h b/ext-codec/JPEG.h similarity index 97% rename from src/Extension/JPEG.h rename to ext-codec/JPEG.h index 797bc22b..175699ce 100644 --- a/src/Extension/JPEG.h +++ b/ext-codec/JPEG.h @@ -1,8 +1,8 @@ #ifndef ZLMEDIAKIT_JPEG_H #define ZLMEDIAKIT_JPEG_H -#include "Frame.h" -#include "Track.h" +#include "Extension/Frame.h" +#include "Extension/Track.h" namespace mediakit { diff --git a/src/Extension/JPEGRtp.cpp b/ext-codec/JPEGRtp.cpp similarity index 100% rename from src/Extension/JPEGRtp.cpp rename to ext-codec/JPEGRtp.cpp diff --git a/src/Extension/JPEGRtp.h b/ext-codec/JPEGRtp.h similarity index 95% rename from src/Extension/JPEGRtp.h rename to ext-codec/JPEGRtp.h index db5a4b70..e8d5d81c 100644 --- a/src/Extension/JPEGRtp.h +++ b/ext-codec/JPEGRtp.h @@ -1,10 +1,10 @@ #ifndef ZLMEDIAKIT_JPEGRTP_H #define ZLMEDIAKIT_JPEGRTP_H -#include "Frame.h" #include "Rtsp/RtpCodec.h" +#include "Extension/Frame.h" -namespace mediakit{ +namespace mediakit { /** * RTP/JPEG specific private data. diff --git a/src/Extension/L16.cpp b/ext-codec/L16.cpp similarity index 53% rename from src/Extension/L16.cpp rename to ext-codec/L16.cpp index 70a23da2..e38cc081 100644 --- a/src/Extension/L16.cpp +++ b/ext-codec/L16.cpp @@ -9,11 +9,14 @@ */ #include "L16.h" +#include "Extension/Factory.h" +#include "Extension/CommonRtp.h" +#include "Extension/CommonRtmp.h" using namespace std; using namespace toolkit; -namespace mediakit{ +namespace mediakit { /** * L16类型SDP @@ -54,6 +57,53 @@ Track::Ptr L16Track::clone() const { return std::make_shared(*this); } +namespace { + +CodecId getCodec() { + return CodecL16; +} + +Track::Ptr getTrackByCodecId(int sample_rate, int channels, int sample_bit) { + return std::make_shared(sample_rate, channels); +} + +Track::Ptr getTrackBySdp(const SdpTrack::Ptr &track) { + return std::make_shared(track->_samplerate, track->_channel); +} + +RtpCodec::Ptr getRtpEncoderByCodecId(uint8_t pt) { + return std::make_shared(); +} + +RtpCodec::Ptr getRtpDecoderByCodecId() { + return std::make_shared(CodecL16); +} + +RtmpCodec::Ptr getRtmpEncoderByTrack(const Track::Ptr &track) { + WarnL << "Unsupported L16 rtmp encoder"; + return nullptr; +} + +RtmpCodec::Ptr getRtmpDecoderByTrack(const Track::Ptr &track) { + WarnL << "Unsupported L16 rtmp decoder"; + return nullptr; +} + +Frame::Ptr getFrameFromPtr(const char *data, size_t bytes, uint64_t dts, uint64_t pts) { + return std::make_shared(CodecL16, (char *)data, bytes, dts, pts); +} + +} // namespace + +CodecPlugin l16_plugin = { getCodec, + getTrackByCodecId, + getTrackBySdp, + getRtpEncoderByCodecId, + getRtpDecoderByCodecId, + getRtmpEncoderByTrack, + getRtmpDecoderByTrack, + getFrameFromPtr }; + }//namespace mediakit diff --git a/src/Extension/L16.h b/ext-codec/L16.h similarity index 88% rename from src/Extension/L16.h rename to ext-codec/L16.h index 715749a3..172fccdb 100644 --- a/src/Extension/L16.h +++ b/ext-codec/L16.h @@ -11,10 +11,10 @@ #ifndef ZLMEDIAKIT_L16_H #define ZLMEDIAKIT_L16_H -#include "Frame.h" -#include "Track.h" +#include "Extension/Frame.h" +#include "Extension/Track.h" -namespace mediakit{ +namespace mediakit { /** * L16音频通道 diff --git a/src/Extension/Opus.cpp b/ext-codec/Opus.cpp similarity index 51% rename from src/Extension/Opus.cpp rename to ext-codec/Opus.cpp index 30f0bbc8..9fc116c8 100644 --- a/src/Extension/Opus.cpp +++ b/ext-codec/Opus.cpp @@ -9,11 +9,14 @@ */ #include "Opus.h" +#include "Extension/Factory.h" +#include "Extension/CommonRtp.h" +#include "Extension/CommonRtmp.h" using namespace std; using namespace toolkit; -namespace mediakit{ +namespace mediakit { /** * Opus类型SDP @@ -51,4 +54,49 @@ Sdp::Ptr OpusTrack::getSdp(uint8_t payload_type) const { return std::make_shared(payload_type, getAudioSampleRate(), getAudioChannel(), getBitRate() / 1024); } +namespace { + +CodecId getCodec() { + return CodecOpus; +} + +Track::Ptr getTrackByCodecId(int sample_rate, int channels, int sample_bit) { + return std::make_shared(); +} + +Track::Ptr getTrackBySdp(const SdpTrack::Ptr &track) { + return std::make_shared(); +} + +RtpCodec::Ptr getRtpEncoderByCodecId(uint8_t pt) { + return std::make_shared(); +} + +RtpCodec::Ptr getRtpDecoderByCodecId() { + return std::make_shared(CodecOpus); +} + +RtmpCodec::Ptr getRtmpEncoderByTrack(const Track::Ptr &track) { + return std::make_shared(track); +} + +RtmpCodec::Ptr getRtmpDecoderByTrack(const Track::Ptr &track) { + return std::make_shared(track); +} + +Frame::Ptr getFrameFromPtr(const char *data, size_t bytes, uint64_t dts, uint64_t pts) { + return std::make_shared(CodecOpus, (char *)data, bytes, dts, pts); +} + +} // namespace + +CodecPlugin opus_plugin = { getCodec, + getTrackByCodecId, + getTrackBySdp, + getRtpEncoderByCodecId, + getRtpDecoderByCodecId, + getRtmpEncoderByTrack, + getRtmpDecoderByTrack, + getFrameFromPtr }; + }//namespace mediakit \ No newline at end of file diff --git a/src/Extension/Opus.h b/ext-codec/Opus.h similarity index 91% rename from src/Extension/Opus.h rename to ext-codec/Opus.h index 70ad3962..e154b36e 100644 --- a/src/Extension/Opus.h +++ b/ext-codec/Opus.h @@ -11,10 +11,10 @@ #ifndef ZLMEDIAKIT_OPUS_H #define ZLMEDIAKIT_OPUS_H -#include "Frame.h" -#include "Track.h" +#include "Extension/Frame.h" +#include "Extension/Track.h" -namespace mediakit{ +namespace mediakit { /** * Opus帧音频通道 diff --git a/src/Extension/SPSParser.c b/ext-codec/SPSParser.c similarity index 100% rename from src/Extension/SPSParser.c rename to ext-codec/SPSParser.c diff --git a/src/Extension/SPSParser.h b/ext-codec/SPSParser.h similarity index 100% rename from src/Extension/SPSParser.h rename to ext-codec/SPSParser.h diff --git a/src/Extension/Factory.cpp b/src/Extension/Factory.cpp index 65c8060a..f69eead7 100644 --- a/src/Extension/Factory.cpp +++ b/src/Extension/Factory.cpp @@ -10,155 +10,77 @@ #include "Factory.h" #include "Rtmp/Rtmp.h" -#include "H264Rtmp.h" -#include "H265Rtmp.h" -#include "AACRtmp.h" -#include "CommonRtmp.h" -#include "H264Rtp.h" -#include "JPEGRtp.h" -#include "AACRtp.h" -#include "H265Rtp.h" -#include "CommonRtp.h" -#include "G711Rtp.h" -#include "Opus.h" -#include "G711.h" -#include "L16.h" -#include "JPEG.h" -#include "Util/base64.h" -#include "Common/Parser.h" #include "Common/config.h" using namespace std; using namespace toolkit; -namespace mediakit{ +namespace mediakit { + +static std::unordered_map s_plugins; + +extern CodecPlugin h264_plugin; +extern CodecPlugin h265_plugin; +extern CodecPlugin jpeg_plugin; +extern CodecPlugin aac_plugin; +extern CodecPlugin opus_plugin; +extern CodecPlugin g711a_plugin; +extern CodecPlugin g711u_plugin; +extern CodecPlugin l16_plugin; + +REGISTER_CODEC(h264_plugin); +REGISTER_CODEC(h265_plugin); +REGISTER_CODEC(jpeg_plugin); +REGISTER_CODEC(aac_plugin); +REGISTER_CODEC(opus_plugin); +REGISTER_CODEC(g711a_plugin) +REGISTER_CODEC(g711u_plugin); +REGISTER_CODEC(l16_plugin); + +void Factory::registerPlugin(const CodecPlugin &plugin) { + InfoL << "Load codec: " << getCodecName(plugin.getCodec()); + s_plugins[(int)(plugin.getCodec())] = &plugin; +} Track::Ptr Factory::getTrackBySdp(const SdpTrack::Ptr &track) { auto codec = getCodecId(track->_codec); if (codec == CodecInvalid) { - //根据传统的payload type 获取编码类型以及采样率等信息 + // 根据传统的payload type 获取编码类型以及采样率等信息 codec = RtpPayload::getCodecId(track->_pt); } - switch (codec) { - case CodecG711A: - case CodecG711U: return std::make_shared(codec, track->_samplerate, track->_channel, 16); - case CodecL16: return std::make_shared(track->_samplerate, track->_channel); - case CodecOpus : return std::make_shared(); - - case CodecAAC : { - string aac_cfg_str = findSubString(track->_fmtp.data(), "config=", ";"); - if (aac_cfg_str.empty()) { - aac_cfg_str = findSubString(track->_fmtp.data(), "config=", nullptr); - } - if (aac_cfg_str.empty()) { - //如果sdp中获取不到aac config信息,那么在rtp也无法获取,那么忽略该Track - return nullptr; - } - string aac_cfg; - for (size_t i = 0; i < aac_cfg_str.size() / 2; ++i) { - unsigned int cfg; - sscanf(aac_cfg_str.substr(i * 2, 2).data(), "%02X", &cfg); - cfg &= 0x00FF; - aac_cfg.push_back((char) cfg); - } - return std::make_shared(aac_cfg); - } - - case CodecH264 : { - //a=fmtp:96 packetization-mode=1;profile-level-id=42C01F;sprop-parameter-sets=Z0LAH9oBQBboQAAAAwBAAAAPI8YMqA==,aM48gA== - auto map = Parser::parseArgs(track->_fmtp, ";", "="); - auto sps_pps = map["sprop-parameter-sets"]; - string base64_SPS = findSubString(sps_pps.data(), NULL, ","); - string base64_PPS = findSubString(sps_pps.data(), ",", NULL); - auto sps = decodeBase64(base64_SPS); - auto pps = decodeBase64(base64_PPS); - if (sps.empty() || pps.empty()) { - //如果sdp里面没有sps/pps,那么可能在后续的rtp里面恢复出sps/pps - return std::make_shared(); - } - return std::make_shared(sps, pps, 0, 0); - } - - case CodecH265: { - //a=fmtp:96 sprop-sps=QgEBAWAAAAMAsAAAAwAAAwBdoAKAgC0WNrkky/AIAAADAAgAAAMBlQg=; sprop-pps=RAHA8vA8kAA= - auto map = Parser::parseArgs(track->_fmtp, ";", "="); - auto vps = decodeBase64(map["sprop-vps"]); - auto sps = decodeBase64(map["sprop-sps"]); - auto pps = decodeBase64(map["sprop-pps"]); - if (sps.empty() || pps.empty()) { - //如果sdp里面没有sps/pps,那么可能在后续的rtp里面恢复出sps/pps - return std::make_shared(); - } - return std::make_shared(vps, sps, pps, 0, 0, 0); - } - - case CodecJPEG : return std::make_shared(); - - default: { - //其他codec不支持 - WarnL << "暂不支持该rtsp编码类型:" << track->getName(); - return nullptr; - } + auto it = s_plugins.find(codec); + if (it == s_plugins.end()) { + WarnL << "Unsupported codec: " << track->getName(); + return nullptr; } + return it->second->getTrackBySdp(track); } -Track::Ptr Factory::getTrackByAbstractTrack(const Track::Ptr& track) { +Track::Ptr Factory::getTrackByAbstractTrack(const Track::Ptr &track) { auto codec = track->getCodecId(); - switch (codec) { - case CodecG711A: - case CodecG711U: { - auto audio_track = dynamic_pointer_cast(track); - return std::make_shared(codec, audio_track->getAudioSampleRate(), audio_track->getAudioChannel(), 16); - } - case CodecL16: { - auto audio_track = dynamic_pointer_cast(track); - return std::make_shared(audio_track->getAudioSampleRate(), audio_track->getAudioChannel()); - } - case CodecAAC: return std::make_shared(); - case CodecOpus: return std::make_shared(); - case CodecH265: return std::make_shared(); - case CodecH264: return std::make_shared(); - case CodecJPEG: return std::make_shared(); - - default: { - //其他codec不支持 - WarnL << "暂不支持该该编码类型创建Track:" << track->getCodecName(); - return nullptr; - } + if (track->getTrackType() == TrackVideo) { + return getTrackByCodecId(codec); } + auto audio_track = dynamic_pointer_cast(track); + return getTrackByCodecId(codec, audio_track->getAudioSampleRate(), audio_track->getAudioChannel(), audio_track->getAudioSampleBit()); } -RtpCodec::Ptr Factory::getRtpEncoderByCodecId(CodecId codec_id, uint8_t pt) { - switch (codec_id) { - case CodecH264: return std::make_shared(); - case CodecH265: return std::make_shared(); - case CodecAAC: return std::make_shared(); - case CodecL16: - case CodecOpus: return std::make_shared(); - case CodecG711A: - case CodecG711U: { - if (pt == Rtsp::PT_PCMA || pt == Rtsp::PT_PCMU) { - return std::make_shared(codec_id, 1); - } - return std::make_shared(); - } - case CodecJPEG: return std::make_shared(); - default: WarnL << "暂不支持该CodecId:" << codec_id; return nullptr; +RtpCodec::Ptr Factory::getRtpEncoderByCodecId(CodecId codec, uint8_t pt) { + auto it = s_plugins.find(codec); + if (it == s_plugins.end()) { + WarnL << "Unsupported codec: " << getCodecName(codec); + return nullptr; } + return it->second->getRtpEncoderByCodecId(pt); } -RtpCodec::Ptr Factory::getRtpDecoderByTrack(const Track::Ptr &track) { - switch (track->getCodecId()){ - case CodecH264 : return std::make_shared(); - case CodecH265 : return std::make_shared(); - case CodecAAC : return std::make_shared(); - case CodecL16 : - case CodecOpus : - case CodecG711A : - case CodecG711U : return std::make_shared(track->getCodecId()); - case CodecJPEG: return std::make_shared(); - default : WarnL << "暂不支持该CodecId:" << track->getCodecName(); return nullptr; +RtpCodec::Ptr Factory::getRtpDecoderByCodecId(CodecId codec) { + auto it = s_plugins.find(codec); + if (it == s_plugins.end()) { + WarnL << "Unsupported codec: " << getCodecName(codec); + return nullptr; } + return it->second->getRtpDecoderByCodecId(); } /////////////////////////////rtmp相关/////////////////////////////////////////// @@ -172,7 +94,7 @@ static CodecId getVideoCodecIdByAmf(const AMFValue &val){ if (str == "hev1" || str == "hvc1") { return CodecH265; } - WarnL << "暂不支持该视频Amf:" << str; + WarnL << "Unsupported codec: " << str; return CodecInvalid; } @@ -184,23 +106,19 @@ static CodecId getVideoCodecIdByAmf(const AMFValue &val){ case RtmpVideoCodec::h265: return CodecH265; case RtmpVideoCodec::fourcc_av1: return CodecAV1; case RtmpVideoCodec::fourcc_vp9: return CodecVP9; - default: WarnL << "暂不支持该视频Amf:" << (int)type_id; return CodecInvalid; + default: WarnL << "Unsupported codec: " << (int)type_id; return CodecInvalid; } } return CodecInvalid; } -Track::Ptr Factory::getTrackByCodecId(CodecId codecId, int sample_rate, int channels, int sample_bit) { - 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; - case CodecJPEG : return std::make_shared(); - default : WarnL << "暂不支持该CodecId:" << codecId; return nullptr; +Track::Ptr Factory::getTrackByCodecId(CodecId codec, int sample_rate, int channels, int sample_bit) { + auto it = s_plugins.find(codec); + if (it == s_plugins.end()) { + WarnL << "Unsupported codec: " << getCodecName(codec); + return nullptr; } + return it->second->getTrackByCodecId(sample_rate, channels, sample_bit); } Track::Ptr Factory::getVideoTrackByAmf(const AMFValue &amf) { @@ -217,7 +135,7 @@ static CodecId getAudioCodecIdByAmf(const AMFValue &val) { if (str == "mp4a") { return CodecAAC; } - WarnL << "暂不支持该音频Amf:" << str; + WarnL << "Unsupported codec: " << str; return CodecInvalid; } @@ -228,7 +146,7 @@ static CodecId getAudioCodecIdByAmf(const AMFValue &val) { case RtmpAudioCodec::g711a : return CodecG711A; case RtmpAudioCodec::g711u : return CodecG711U; case RtmpAudioCodec::opus : return CodecOpus; - default : WarnL << "暂不支持该音频Amf:" << (int)type_id; return CodecInvalid; + default : WarnL << "Unsupported codec: " << (int)type_id; return CodecInvalid; } } @@ -244,39 +162,21 @@ Track::Ptr Factory::getAudioTrackByAmf(const AMFValue& amf, int sample_rate, int } RtmpCodec::Ptr Factory::getRtmpDecoderByTrack(const Track::Ptr &track) { - switch (track->getCodecId()){ - case CodecH264 : return std::make_shared(track); - case CodecAAC : return std::make_shared(track); - case CodecH265 : return std::make_shared(track); - case CodecOpus : - case CodecG711A : - case CodecG711U : return std::make_shared(track); - default : WarnL << "暂不支持该CodecId:" << track->getCodecName(); return nullptr; + auto it = s_plugins.find(track->getCodecId()); + if (it == s_plugins.end()) { + WarnL << "Unsupported codec: " << track->getCodecName(); + return nullptr; } + return it->second->getRtmpDecoderByTrack(track); } RtmpCodec::Ptr Factory::getRtmpEncoderByTrack(const Track::Ptr &track) { - switch (track->getCodecId()){ - 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); - if (audio_track->getAudioSampleRate() != 8000 || audio_track->getAudioChannel() != 1 || audio_track->getAudioSampleBit() != 16) { - //rtmp对g711只支持8000/1/16规格,但是ZLMediaKit可以解析其他规格的G711 - WarnL << "RTMP只支持8000/1/16规格的G711,目前规格是:" - << audio_track->getAudioSampleRate() << "/" - << audio_track->getAudioChannel() << "/" - << audio_track->getAudioSampleBit() - << ",该音频已被忽略"; - return nullptr; - } - return std::make_shared(track); - } - default : WarnL << "暂不支持该CodecId:" << track->getCodecName(); return nullptr; + auto it = s_plugins.find(track->getCodecId()); + if (it == s_plugins.end()) { + WarnL << "Unsupported codec: " << track->getCodecName(); + return nullptr; } + return it->second->getRtmpEncoderByTrack(track); } AMFValue Factory::getAmfByCodecId(CodecId codecId) { @@ -294,26 +194,13 @@ AMFValue Factory::getAmfByCodecId(CodecId codecId) { } } -static size_t aacPrefixSize(const char *data, size_t bytes) { - uint8_t *ptr = (uint8_t *)data; - size_t prefix = 0; - if (!(bytes > ADTS_HEADER_LEN && ptr[0] == 0xFF && (ptr[1] & 0xF0) == 0xF0)) { - return 0; - } - return ADTS_HEADER_LEN; -} - Frame::Ptr Factory::getFrameFromPtr(CodecId codec, const char *data, size_t bytes, uint64_t dts, uint64_t pts) { - switch (codec) { - case CodecH264: return std::make_shared((char *)data, bytes, dts, pts, prefixSize(data, bytes)); - case CodecH265: return std::make_shared((char *)data, bytes, dts, pts, prefixSize(data, bytes)); - case CodecJPEG: return std::make_shared>(0, codec, (char *)data, bytes, dts, pts); - case CodecAAC: return std::make_shared(codec, (char *)data, bytes, dts, pts, aacPrefixSize(data, bytes)); - case CodecOpus: - case CodecG711A: - case CodecG711U: return std::make_shared(codec, (char *)data, bytes, dts, pts); - default: return nullptr; + auto it = s_plugins.find(codec); + if (it == s_plugins.end()) { + WarnL << "Unsupported codec: " << getCodecName(codec); + return nullptr; } + return it->second->getFrameFromPtr(data, bytes, dts, pts); } Frame::Ptr Factory::getFrameFromBuffer(CodecId codec, Buffer::Ptr data, uint64_t dts, uint64_t pts) { diff --git a/src/Extension/Factory.h b/src/Extension/Factory.h index 8342d67e..8ec446bc 100644 --- a/src/Extension/Factory.h +++ b/src/Extension/Factory.h @@ -17,11 +17,35 @@ #include "Extension/Frame.h" #include "Rtsp/RtpCodec.h" #include "Rtmp/RtmpCodec.h" +#include "Util/onceToken.h" -namespace mediakit{ +#define REGISTER_STATIC_VAR_INNER(var_name, line) var_name##_##line##__ +#define REGISTER_STATIC_VAR(var_name, line) REGISTER_STATIC_VAR_INNER(var_name, line) + +#define REGISTER_CODEC(plugin) \ +static toolkit::onceToken REGISTER_STATIC_VAR(s_token, __LINE__) ([]() { \ + Factory::registerPlugin(plugin); \ +}); + +namespace mediakit { + +struct CodecPlugin { + CodecId (*getCodec)(); + Track::Ptr (*getTrackByCodecId)(int sample_rate, int channels, int sample_bit); + Track::Ptr (*getTrackBySdp)(const SdpTrack::Ptr &track); + RtpCodec::Ptr (*getRtpEncoderByCodecId)(uint8_t pt); + RtpCodec::Ptr (*getRtpDecoderByCodecId)(); + RtmpCodec::Ptr (*getRtmpEncoderByTrack)(const Track::Ptr &track); + RtmpCodec::Ptr (*getRtmpDecoderByTrack)(const Track::Ptr &track); + Frame::Ptr (*getFrameFromPtr)(const char *data, size_t bytes, uint64_t dts, uint64_t pts); +}; class Factory { public: + /** + * 注册插件,非线程安全的 + */ + static void registerPlugin(const CodecPlugin &plugin); /** * 根据codec_id 获取track @@ -53,7 +77,7 @@ public: /** * 根据Track生成Rtp解包器 */ - static RtpCodec::Ptr getRtpDecoderByTrack(const Track::Ptr &track); + static RtpCodec::Ptr getRtpDecoderByCodecId(CodecId codec); ////////////////////////////////rtmp相关////////////////////////////////// diff --git a/src/Extension/Frame.cpp b/src/Extension/Frame.cpp index 27973f9f..c58ea84b 100644 --- a/src/Extension/Frame.cpp +++ b/src/Extension/Frame.cpp @@ -9,8 +9,6 @@ */ #include "Frame.h" -#include "H264.h" -#include "H265.h" #include "Common/Parser.h" #include "Common/Stamp.h" #include "Common/MediaSource.h" diff --git a/src/Extension/G711.cpp b/src/Extension/G711.cpp deleted file mode 100644 index bdab522b..00000000 --- a/src/Extension/G711.cpp +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Copyright (c) 2016-present The ZLMediaKit project authors. All Rights Reserved. - * - * This file is part of ZLMediaKit(https://github.com/ZLMediaKit/ZLMediaKit). - * - * Use of this source code is governed by MIT-like 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 "G711.h" - -using namespace std; -using namespace toolkit; - -namespace mediakit{ - -/** - * G711类型SDP - */ -class G711Sdp : public Sdp { -public: - /** - * G711采样率固定为8000 - * @param codecId G711A G711U - * @param payload_type rtp payload type - * @param sample_rate 音频采样率 - * @param channels 通道数 - * @param bitrate 比特率 - */ - G711Sdp(CodecId codecId, int payload_type, int sample_rate, int channels, int bitrate) - : Sdp(sample_rate, payload_type) { - _printer << "m=audio 0 RTP/AVP " << payload_type << "\r\n"; - if (bitrate) { - _printer << "b=AS:" << bitrate << "\r\n"; - } - _printer << "a=rtpmap:" << payload_type << " " << getCodecName(codecId) << "/" << sample_rate << "/" << channels << "\r\n"; - } - - string getSdp() const override { - return _printer; - } - -private: - _StrPrinter _printer; -}; - -Track::Ptr G711Track::clone() const { - return std::make_shared(*this); -} - -Sdp::Ptr G711Track::getSdp(uint8_t payload_type) const { - if (!ready()) { - WarnL << getCodecName() << " Track未准备好"; - return nullptr; - } - - const auto codec = getCodecId(); - const auto sample_rate = getAudioSampleRate(); - const auto audio_channel = getAudioChannel(); - const auto bitrate = getBitRate() >> 10; - if (sample_rate == 8000 && audio_channel == 1) { - // https://datatracker.ietf.org/doc/html/rfc3551#section-6 - payload_type = (codec == CodecG711U) ? Rtsp::PT_PCMU : Rtsp::PT_PCMA; - } - - return std::make_shared(codec, payload_type, sample_rate, audio_channel, bitrate); -} - -}//namespace mediakit - - diff --git a/src/Extension/JPEG.cpp b/src/Extension/JPEG.cpp deleted file mode 100644 index 52d98073..00000000 --- a/src/Extension/JPEG.cpp +++ /dev/null @@ -1,50 +0,0 @@ -#include "JPEG.h" -#include "Rtsp/Rtsp.h" -#include "Util/util.h" - -using namespace toolkit; - -namespace mediakit { - -bool JPEGTrack::inputFrame(const Frame::Ptr &frame) { - if (!ready()) { - if (_height > 0 && _width > 0) { - if (_tmp == 0) _tmp = frame->dts(); - else _fps = 1000.0 / (frame->dts() - _tmp); - } else getVideoResolution((uint8_t*)frame->data(), frame->size()); - return false; - } - return VideoTrack::inputFrame(frame); -} - -void JPEGTrack::getVideoResolution(const uint8_t *buf, int len) { - for (int i = 0; i < len - 8; i++) { - if (buf[i] != 0xff) - continue; - if (buf[i + 1] == 0xC0 /*SOF0*/) { - _height = buf[i + 5] * 256 + buf[i + 6]; - _width = buf[i + 7] * 256 + buf[i + 8]; - return; - } - } -} - -class JPEGSdp : public Sdp { -public: - JPEGSdp(int bitrate) : Sdp(90000, Rtsp::PT_JPEG) { - _printer << "m=video 0 RTP/AVP " << (int)getPayloadType() << "\r\n"; - if (bitrate) { - _printer << "b=AS:" << bitrate << "\r\n"; - } - } - - std::string getSdp() const { return _printer; } - -private: - _StrPrinter _printer; -}; - -Sdp::Ptr JPEGTrack::getSdp(uint8_t) const { - return std::make_shared(getBitRate() / 1024); -} -} // namespace mediakit diff --git a/src/Rtp/GB28181Process.cpp b/src/Rtp/GB28181Process.cpp index 82f97c0f..29c9704f 100644 --- a/src/Rtp/GB28181Process.cpp +++ b/src/Rtp/GB28181Process.cpp @@ -89,7 +89,7 @@ bool GB28181Process::inputRtp(bool, const char *data, size_t data_len) { CHECK(track); track->setIndex(pt); _interface->addTrack(track); - _rtp_decoder[pt] = Factory::getRtpDecoderByTrack(track); + _rtp_decoder[pt] = Factory::getRtpDecoderByCodecId(track->getCodecId()); break; } case Rtsp::PT_JPEG: { @@ -99,7 +99,7 @@ bool GB28181Process::inputRtp(bool, const char *data, size_t data_len) { CHECK(track); track->setIndex(pt); _interface->addTrack(track); - _rtp_decoder[pt] = Factory::getRtpDecoderByTrack(track); + _rtp_decoder[pt] = Factory::getRtpDecoderByCodecId(track->getCodecId()); break; } default: { @@ -110,7 +110,7 @@ bool GB28181Process::inputRtp(bool, const char *data, size_t data_len) { CHECK(track); track->setIndex(pt); _interface->addTrack(track); - _rtp_decoder[pt] = Factory::getRtpDecoderByTrack(track); + _rtp_decoder[pt] = Factory::getRtpDecoderByCodecId(track->getCodecId()); } else if (pt == h265_pt) { // H265负载 ref = std::make_shared(90000, [this](RtpPacket::Ptr rtp) { onRtpSorted(std::move(rtp)); }); @@ -118,7 +118,7 @@ bool GB28181Process::inputRtp(bool, const char *data, size_t data_len) { CHECK(track); track->setIndex(pt); _interface->addTrack(track); - _rtp_decoder[pt] = Factory::getRtpDecoderByTrack(track); + _rtp_decoder[pt] = Factory::getRtpDecoderByCodecId(track->getCodecId()); } else if (pt == h264_pt) { // H264负载 ref = std::make_shared(90000, [this](RtpPacket::Ptr rtp) { onRtpSorted(std::move(rtp)); }); @@ -126,7 +126,7 @@ bool GB28181Process::inputRtp(bool, const char *data, size_t data_len) { CHECK(track); track->setIndex(pt); _interface->addTrack(track); - _rtp_decoder[pt] = Factory::getRtpDecoderByTrack(track); + _rtp_decoder[pt] = Factory::getRtpDecoderByCodecId(track->getCodecId()); } else { if (pt != Rtsp::PT_MP2T && pt != ps_pt) { WarnL << "Unknown rtp payload type(" << (int)pt << "), decode it as mpeg-ps or mpeg-ts"; diff --git a/src/Rtsp/RtspDemuxer.cpp b/src/Rtsp/RtspDemuxer.cpp index db4c9c18..1dca605b 100644 --- a/src/Rtsp/RtspDemuxer.cpp +++ b/src/Rtsp/RtspDemuxer.cpp @@ -92,7 +92,7 @@ void RtspDemuxer::makeAudioTrack(const SdpTrack::Ptr &audio) { } setBitRate(audio, _audio_track); //生成RtpCodec对象以便解码rtp - _audio_rtp_decoder = Factory::getRtpDecoderByTrack(_audio_track); + _audio_rtp_decoder = Factory::getRtpDecoderByCodecId(_audio_track->getCodecId()); if (!_audio_rtp_decoder) { //找不到相应的rtp解码器,该track无效 _audio_track.reset(); @@ -114,7 +114,7 @@ void RtspDemuxer::makeVideoTrack(const SdpTrack::Ptr &video) { } setBitRate(video, _video_track); //生成RtpCodec对象以便解码rtp - _video_rtp_decoder = Factory::getRtpDecoderByTrack(_video_track); + _video_rtp_decoder = Factory::getRtpDecoderByCodecId(_video_track->getCodecId()); if (!_video_rtp_decoder) { //找不到相应的rtp解码器,该track无效 _video_track.reset();