475 lines
9.9 KiB
C++
475 lines
9.9 KiB
C++
//
|
|
// Copyright (c) 2013-2025 The SRS Authors
|
|
//
|
|
// SPDX-License-Identifier: MIT
|
|
//
|
|
|
|
#include <srs_app_stream_bridge.hpp>
|
|
|
|
#include <srs_app_config.hpp>
|
|
#include <srs_app_factory.hpp>
|
|
#include <srs_app_rtc_source.hpp>
|
|
#include <srs_app_rtmp_source.hpp>
|
|
#include <srs_app_srt_source.hpp>
|
|
#include <srs_core_autofree.hpp>
|
|
#include <srs_kernel_rtc_rtp.hpp>
|
|
#include <srs_protocol_format.hpp>
|
|
#include <srs_protocol_rtmp_stack.hpp>
|
|
#ifdef SRS_RTSP
|
|
#include <srs_app_rtsp_source.hpp>
|
|
#endif
|
|
#include <srs_app_rtc_source.hpp>
|
|
|
|
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<SrsRtcSource> rtc_source)
|
|
{
|
|
rtc_target_ = rtc_source;
|
|
}
|
|
|
|
#ifdef SRS_RTSP
|
|
void SrsRtmpBridge::enable_rtmp2rtsp(SrsSharedPtr<SrsRtspSource> 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<SrsLiveSource> rtmp_source)
|
|
{
|
|
rtmp_target_ = rtmp_source;
|
|
}
|
|
|
|
void SrsSrtBridge::enable_srt2rtc(SrsSharedPtr<SrsRtcSource> 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<SrsLiveSource> 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;
|
|
}
|