// // Copyright (c) 2013-2025 The SRS Authors // // SPDX-License-Identifier: MIT // #include #include #include #include #include #include #include #include #include #include #ifdef SRS_RTSP #include #endif #include using namespace std; ISrsFrameTarget::ISrsFrameTarget() { } ISrsFrameTarget::~ISrsFrameTarget() { } ISrsRtpTarget::ISrsRtpTarget() { } ISrsRtpTarget::~ISrsRtpTarget() { } ISrsSrtTarget::ISrsSrtTarget() { } ISrsSrtTarget::~ISrsSrtTarget() { } ISrsRtmpBridge::ISrsRtmpBridge() { } ISrsRtmpBridge::~ISrsRtmpBridge() { } SrsRtmpBridge::SrsRtmpBridge(ISrsAppFactory *factory) { #ifdef SRS_FFMPEG_FIT rtp_builder_ = NULL; #endif #ifdef SRS_RTSP rtsp_builder_ = NULL; rtsp_target_ = NULL; #endif rtc_target_ = NULL; app_factory_ = factory; } SrsRtmpBridge::~SrsRtmpBridge() { #ifdef SRS_FFMPEG_FIT srs_freep(rtp_builder_); #endif #ifdef SRS_RTSP srs_freep(rtsp_builder_); rtsp_target_ = NULL; #endif rtc_target_ = NULL; app_factory_ = NULL; } bool SrsRtmpBridge::empty() { if (rtc_target_.get()) { return false; } #ifdef SRS_RTSP if (rtsp_target_.get()) { return false; } #endif return true; } void SrsRtmpBridge::enable_rtmp2rtc(SrsSharedPtr rtc_source) { rtc_target_ = rtc_source; } #ifdef SRS_RTSP void SrsRtmpBridge::enable_rtmp2rtsp(SrsSharedPtr rtsp_source) { rtsp_target_ = rtsp_source; } #endif srs_error_t SrsRtmpBridge::initialize(ISrsRequest *r) { srs_error_t err = srs_success; #ifdef SRS_FFMPEG_FIT if (rtc_target_.get()) { srs_freep(rtp_builder_); rtp_builder_ = new SrsRtcRtpBuilder(app_factory_, rtc_target_.get(), rtc_target_); if ((err = rtp_builder_->initialize(r)) != srs_success) { return srs_error_wrap(err, "rtp builder initialize"); } } #endif #ifdef SRS_RTSP if (rtsp_target_.get()) { srs_freep(rtsp_builder_); rtsp_builder_ = new SrsRtspRtpBuilder(rtsp_target_.get(), rtsp_target_); if ((err = rtsp_builder_->initialize(r)) != srs_success) { return srs_error_wrap(err, "rtsp builder initialize"); } } #endif return err; } srs_error_t SrsRtmpBridge::on_publish() { srs_error_t err = srs_success; // TODO: FIXME: Should sync with bridge? if (rtc_target_.get()) { if ((err = rtc_target_->on_publish()) != srs_success) { return srs_error_wrap(err, "rtc target publish"); } #ifdef SRS_FFMPEG_FIT if ((err = rtp_builder_->on_publish()) != srs_success) { return srs_error_wrap(err, "rtp builder publish"); } #endif } #ifdef SRS_RTSP // TODO: FIXME: Should sync with bridge? if (rtsp_target_.get()) { if ((err = rtsp_target_->on_publish()) != srs_success) { return srs_error_wrap(err, "rtsp target publish"); } if ((err = rtsp_builder_->on_publish()) != srs_success) { return srs_error_wrap(err, "rtsp builder publish"); } } #endif return err; } void SrsRtmpBridge::on_unpublish() { if (rtc_target_.get()) { #ifdef SRS_FFMPEG_FIT rtp_builder_->on_unpublish(); #endif rtc_target_->on_unpublish(); } #ifdef SRS_RTSP if (rtsp_target_.get()) { rtsp_builder_->on_unpublish(); rtsp_target_->on_unpublish(); } #endif // Note that RTMP live source free this rtmp bridge, after on_unpublish() is called. // So there is no need to free its components here. } srs_error_t SrsRtmpBridge::on_frame(SrsMediaPacket *frame) { srs_error_t err = srs_success; #ifdef SRS_FFMPEG_FIT if (rtp_builder_ && (err = rtp_builder_->on_frame(frame)) != srs_success) { return srs_error_wrap(err, "rtp builder on frame"); } #endif #ifdef SRS_RTSP if (rtsp_builder_ && (err = rtsp_builder_->on_frame(frame)) != srs_success) { return srs_error_wrap(err, "rtsp builder on frame"); } #endif return err; } ISrsSrtBridge::ISrsSrtBridge() { } ISrsSrtBridge::~ISrsSrtBridge() { } SrsSrtBridge::SrsSrtBridge(ISrsAppFactory *factory) { frame_builder_ = new SrsSrtFrameBuilder(this); rtmp_target_ = NULL; #ifdef SRS_FFMPEG_FIT rtp_builder_ = NULL; #endif rtc_target_ = NULL; app_factory_ = factory; } SrsSrtBridge::~SrsSrtBridge() { rtmp_target_ = NULL; srs_freep(frame_builder_); rtc_target_ = NULL; #ifdef SRS_FFMPEG_FIT srs_freep(rtp_builder_); #endif app_factory_ = NULL; } bool SrsSrtBridge::empty() { return !rtmp_target_.get() && !rtc_target_.get(); } void SrsSrtBridge::enable_srt2rtmp(SrsSharedPtr rtmp_source) { rtmp_target_ = rtmp_source; } void SrsSrtBridge::enable_srt2rtc(SrsSharedPtr rtc_source) { rtc_target_ = rtc_source; } srs_error_t SrsSrtBridge::initialize(ISrsRequest *r) { srs_error_t err = srs_success; if ((err = frame_builder_->initialize(r)) != srs_success) { return srs_error_wrap(err, "frame builder initialize"); } #ifdef SRS_FFMPEG_FIT if (rtc_target_.get()) { srs_freep(rtp_builder_); rtp_builder_ = new SrsRtcRtpBuilder(app_factory_, rtc_target_.get(), rtc_target_); if ((err = rtp_builder_->initialize(r)) != srs_success) { return srs_error_wrap(err, "rtp builder initialize"); } } #endif return err; } srs_error_t SrsSrtBridge::on_publish() { srs_error_t err = srs_success; if ((err = frame_builder_->on_publish()) != srs_success) { return srs_error_wrap(err, "frame builder publish"); } // TODO: FIXME: Should sync with bridge? if (rtmp_target_.get()) { if ((err = rtmp_target_->on_publish()) != srs_success) { return srs_error_wrap(err, "rtmp target publish"); } } if (rtc_target_.get()) { if ((err = rtc_target_->on_publish()) != srs_success) { return srs_error_wrap(err, "rtc target publish"); } #ifdef SRS_FFMPEG_FIT if ((err = rtp_builder_->on_publish()) != srs_success) { return srs_error_wrap(err, "rtp builder publish"); } #endif } return err; } void SrsSrtBridge::on_unpublish() { frame_builder_->on_unpublish(); if (rtmp_target_.get()) { rtmp_target_->on_unpublish(); } if (rtc_target_.get()) { #ifdef SRS_FFMPEG_FIT rtp_builder_->on_unpublish(); #endif rtc_target_->on_unpublish(); } // Note that SRT source free this srt bridge, after on_unpublish() is called. // So there is no need to free its components here. } srs_error_t SrsSrtBridge::on_srt_packet(SrsSrtPacket *pkt) { srs_error_t err = srs_success; if ((err = frame_builder_->on_srt_packet(pkt)) != srs_success) { return srs_error_wrap(err, "frame builder on packet"); } return err; } srs_error_t SrsSrtBridge::on_frame(SrsMediaPacket *frame) { srs_error_t err = srs_success; // Deliver frame to RTMP target if (rtmp_target_.get() && (err = rtmp_target_->on_frame(frame)) != srs_success) { return srs_error_wrap(err, "rtmp target on frame"); } // Deliver frame to RTP builder, which delivers to RTC target #ifdef SRS_FFMPEG_FIT if (rtp_builder_ && (err = rtp_builder_->on_frame(frame)) != srs_success) { return srs_error_wrap(err, "rtp builder on frame"); } #endif return err; } ISrsRtcBridge::ISrsRtcBridge() { } ISrsRtcBridge::~ISrsRtcBridge() { } SrsRtcBridge::SrsRtcBridge(ISrsAppFactory *factory) { req_ = NULL; #ifdef SRS_FFMPEG_FIT frame_builder_ = NULL; #endif rtmp_target_ = NULL; app_factory_ = factory; } SrsRtcBridge::~SrsRtcBridge() { srs_freep(req_); #ifdef SRS_FFMPEG_FIT srs_freep(frame_builder_); #endif rtmp_target_ = NULL; app_factory_ = NULL; } void SrsRtcBridge::enable_rtc2rtmp(SrsSharedPtr rtmp_target) { rtmp_target_ = rtmp_target; } bool SrsRtcBridge::empty() { return !rtmp_target_.get(); } srs_error_t SrsRtcBridge::initialize(ISrsRequest *r) { srs_error_t err = srs_success; srs_freep(req_); req_ = r->copy(); #ifdef SRS_FFMPEG_FIT srs_assert(rtmp_target_.get()); srs_freep(frame_builder_); frame_builder_ = app_factory_->create_rtc_frame_builder(rtmp_target_.get()); #endif return err; } srs_error_t SrsRtcBridge::setup_codec(SrsAudioCodecId acodec, SrsVideoCodecId vcodec) { srs_error_t err = srs_success; #ifdef SRS_FFMPEG_FIT srs_assert(frame_builder_); if ((err = frame_builder_->initialize(req_, acodec, vcodec)) != srs_success) { return srs_error_wrap(err, "frame builder initialize"); } #endif return err; } srs_error_t SrsRtcBridge::on_publish() { srs_error_t err = srs_success; srs_assert(rtmp_target_.get()); if ((err = rtmp_target_->on_publish()) != srs_success) { return srs_error_wrap(err, "rtmp target publish"); } #ifdef SRS_FFMPEG_FIT srs_assert(frame_builder_); if ((err = frame_builder_->on_publish()) != srs_success) { return srs_error_wrap(err, "frame builder on publish"); } #endif return err; } void SrsRtcBridge::on_unpublish() { #ifdef SRS_FFMPEG_FIT srs_assert(frame_builder_); frame_builder_->on_unpublish(); #endif srs_assert(rtmp_target_.get()); rtmp_target_->on_unpublish(); // Note that RTC source free this rtc bridge, after on_unpublish() is called. // So there is no need to free its components here. } srs_error_t SrsRtcBridge::on_rtp(SrsRtpPacket *pkt) { srs_error_t err = srs_success; #ifdef SRS_FFMPEG_FIT if (frame_builder_ && (err = frame_builder_->on_rtp(pkt)) != srs_success) { return srs_error_wrap(err, "frame builder on rtp"); } #endif return err; }