diff --git a/api/source/mk_track.cpp b/api/source/mk_track.cpp index c409ef22e1..296c72bea3 100644 --- a/api/source/mk_track.cpp +++ b/api/source/mk_track.cpp @@ -16,7 +16,7 @@ using namespace std; using namespace toolkit; using namespace mediakit; -class VideoTrackForC : public VideoTrack, public std::enable_shared_from_this { +class VideoTrackForC : public VideoTrack { public: VideoTrackForC(int codec_id, codec_args *args) { _codec_id = (CodecId) codec_id; @@ -61,7 +61,7 @@ class VideoTrackForC : public VideoTrack, public std::enable_shared_from_this { +class AudioTrackForC : public AudioTrackImp { public: AudioTrackForC(int codec_id, codec_args *args) : AudioTrackImp((CodecId) codec_id, args->audio.sample_rate, args->audio.channels, 16) {} diff --git a/src/Extension/Track.cpp b/src/Extension/Track.cpp new file mode 100644 index 0000000000..95a6950d83 --- /dev/null +++ b/src/Extension/Track.cpp @@ -0,0 +1,89 @@ +#include "Track.h" +#include "Codec/Transcode.h" +#include "Extension/Factory.h" +#include "Poller/EventPoller.h" +#include "Util/logger.h" + +namespace mediakit { + +#ifdef ENABLE_FFMPEG + +void Track::setRawFrameCB(RawFrameCB cb) { + std::unique_lock l(_trans_mutex); + _raw_cb = cb; +} + +int Track::trans_size() { + std::unique_lock l(_trans_mutex); + return _trans_tracks.size(); +} + +bool Track::needDecode() { + std::unique_lock l(_trans_mutex); + return _raw_cb != nullptr || _trans_tracks.size() > 0; +} + +bool Track::inputFrame(const Frame::Ptr &frame) { + bool ret = FrameDispatcher::inputFrame(frame); + // 有人读取Raw数据,则解码 + if (needDecode()) { + if (!_decoder) { + _decoder = std::make_shared(shared_from_this()); + InfoL << " open decoder " << getInfo(); + _decoder->setOnDecode([this](const FFmpegFrame::Ptr &frame) { inputRawFrame(frame); }); + } + _decoder->inputFrame(frame, true, true); + } else if (_decoder) { + InfoL << " close decoder " << getInfo(); + _decoder = nullptr; + } + return ret; +} + +void Track::inputRawFrame(const std::shared_ptr &frame) { + std::list tracks; + { + std::unique_lock l(_trans_mutex); + for (auto it : _trans_tracks) { + tracks.push_back(it.second); + } + if (_raw_cb) + _raw_cb(frame); + } + for (auto it : tracks) { + auto track = it; + if (track->_encoder && (track->size() || !track->ready())) { + track->_encoder->inputFrame(frame, true); + } + } +} + +Track::Ptr Track::getTransodeTrack(CodecId id, int arg1, int arg2) { + char key[256]; + int arg3 = (mediakit::getTrackType(id) == TrackVideo) ? 30 : 16; + snprintf(key, sizeof(key), "%s[%dx%dx%d]", mediakit::getCodecName(id), arg1, arg2, arg3); + if (key == getInfo()) { + return shared_from_this(); + } + std::unique_lock l(_trans_mutex); + Ptr ret = _trans_tracks[key]; + if (!ret) { + ret = Factory::getTrackByCodecId(id, arg1, arg2, arg3); + if (ret) { + ret->_parent = this; + // Factory::getTrackByCodecId的宽高参数未必初始化完毕,因此这边立即创建 Encode + Track::Ptr cfg; + if (mediakit::getTrackType(id) == TrackVideo) + cfg.reset(new VideoTrackImp(id, arg1, arg2, arg3)); + else + cfg.reset(new AudioTrackImp(id, arg1, arg2, arg3)); + ret->_encoder = std::make_shared(cfg); + _encoder->setOnEncode([this](const Frame::Ptr &frame) { inputFrame(frame); }); + _trans_tracks[key] = ret; + } + } + return ret; +} +#endif + +} // namespace mediakit diff --git a/src/Extension/Track.h b/src/Extension/Track.h index 8264b3a83b..29777eba07 100644 --- a/src/Extension/Track.h +++ b/src/Extension/Track.h @@ -17,14 +17,16 @@ #include "Rtsp/Rtsp.h" namespace mediakit{ - +class FFmpegDecoder; +class FFmpegEncoder; +class FFmpegFrame; /** * 濯掍綋閫氶亾鎻忚堪绫伙紝涔熸敮鎸佸抚杈撳叆杈撳嚭 */ -class Track : public FrameDispatcher, public CodecInfo { +class Track : public FrameDispatcher, public CodecInfo + , public std::enable_shared_from_this { public: using Ptr = std::shared_ptr; - /** * 榛樿鏋勯 */ @@ -61,7 +63,7 @@ class Track : public FrameDispatcher, public CodecInfo { * @return sdp瀵硅薄 */ virtual Sdp::Ptr getSdp(uint8_t payload_type) const = 0; - + virtual std::string getInfo() const = 0; /** * 鑾峰彇extra data, 涓鑸敤浜巖tmp/mp4鐢熸垚 */ @@ -83,7 +85,27 @@ class Track : public FrameDispatcher, public CodecInfo { * @param bit_rate 姣旂壒鐜 */ virtual void setBitRate(int bit_rate) { _bit_rate = bit_rate; } - +#ifdef ENABLE_FFMPEG + using RawFrameCB = std::function &frame)>; + RawFrameCB _raw_cb; + void setRawFrameCB(RawFrameCB cb); + bool inputFrame(const Frame::Ptr &frame) override; + void inputRawFrame(const std::shared_ptr& frame); + Ptr getTransodeTrack(CodecId code, int arg1, int arg2); + int trans_size(); + bool needDecode(); + +protected: + std::recursive_mutex _trans_mutex; + // 杞爜Map getInfo -> Ptr + std::map _trans_tracks; + // 鎸囧悜杞爜鐨勭埗Track + Track* _parent = nullptr; + // 鐖禩rack璐熻矗瑙g爜 + std::shared_ptr _decoder; + // 姣忎釜瀛怲racker璐熻矗缂栫爜 + std::shared_ptr _encoder; +#endif private: int _bit_rate = 0; }; @@ -109,6 +131,12 @@ class VideoTrack : public Track { * 杩斿洖瑙嗛fps */ virtual float getVideoFps() const { return 0; } + + std::string getInfo() const override { + char buff[256]; + snprintf(buff, sizeof(buff), "%s[%dx%d@%f]", getCodecName(), getVideoWidth(), getVideoHeight(), getVideoFps()); + return buff; + } }; class VideoTrackImp : public VideoTrack { @@ -155,20 +183,26 @@ class AudioTrack : public Track { /** * 杩斿洖闊抽閲囨牱鐜 */ - virtual int getAudioSampleRate() const {return 0;}; + virtual int getAudioSampleRate() const {return 0;} /** * 杩斿洖闊抽閲囨牱浣嶆暟锛屼竴鑸负16鎴8 */ - virtual int getAudioSampleBit() const {return 0;}; + virtual int getAudioSampleBit() const {return 0;} /** * 杩斿洖闊抽閫氶亾鏁 */ - virtual int getAudioChannel() const {return 0;}; + virtual int getAudioChannel() const {return 0;} + + std::string getInfo() const override { + char buff[256]; + snprintf(buff, sizeof(buff), "%s[%dx%d@%d]", getCodecName(), getAudioSampleRate(), getAudioChannel(), getAudioSampleBit()); + return buff; + } }; -class AudioTrackImp : public AudioTrack{ +class AudioTrackImp : public AudioTrack { public: using Ptr = std::shared_ptr;