1
0
Fork 0
mirror of https://github.com/ossrs/srs.git synced 2025-03-09 15:49:59 +00:00
srs/trunk/src/app/srs_app_stream_bridge.cpp
2025-02-16 09:19:48 +08:00

248 lines
6.2 KiB
C++

//
// Copyright (c) 2013-2025 The SRS Authors
//
// SPDX-License-Identifier: MIT
//
#include <srs_app_stream_bridge.hpp>
#include <srs_app_source.hpp>
#include <srs_protocol_format.hpp>
#include <srs_app_rtc_source.hpp>
#include <srs_app_config.hpp>
#include <srs_protocol_rtmp_stack.hpp>
#include <srs_kernel_rtc_rtp.hpp>
#include <srs_core_autofree.hpp>
#include <srs_protocol_utility.hpp>
#include <vector>
using namespace std;
ISrsStreamBridge::ISrsStreamBridge()
{
}
ISrsStreamBridge::~ISrsStreamBridge()
{
}
SrsFrameToRtmpBridge::SrsFrameToRtmpBridge(SrsSharedPtr<SrsLiveSource> source)
{
source_ = source;
}
SrsFrameToRtmpBridge::~SrsFrameToRtmpBridge()
{
}
srs_error_t SrsFrameToRtmpBridge::initialize(SrsRequest* r)
{
return srs_success;
}
srs_error_t SrsFrameToRtmpBridge::on_publish()
{
srs_error_t err = srs_success;
// TODO: FIXME: Should sync with bridge?
if ((err = source_->on_publish()) != srs_success) {
return srs_error_wrap(err, "source publish");
}
return err;
}
void SrsFrameToRtmpBridge::on_unpublish()
{
// TODO: FIXME: Should sync with bridge?
source_->on_unpublish();
}
srs_error_t SrsFrameToRtmpBridge::on_frame(SrsSharedPtrMessage* frame)
{
return source_->on_frame(frame);
}
#ifdef SRS_RTC
SrsFrameToRtcBridge::SrsFrameToRtcBridge(SrsSharedPtr<SrsRtcSource> source)
{
source_ = source;
#if defined(SRS_FFMPEG_FIT)
uint32_t audio_ssrc = 0;
uint8_t audio_payload_type = 0;
uint32_t video_ssrc = 0;
uint8_t video_payload_type = 0;
// audio track ssrc
if (true) {
std::vector<SrsRtcTrackDescription*> descs = source->get_track_desc("audio", "opus");
if (!descs.empty()) {
audio_ssrc = descs.at(0)->ssrc_;
}
// Note we must use the PT of source, see https://github.com/ossrs/srs/pull/3079
audio_payload_type = descs.empty() ? kAudioPayloadType : descs.front()->media_->pt_;
}
// video track ssrc
if (true) {
std::vector<SrsRtcTrackDescription*> descs = source->get_track_desc("video", "");
if (!descs.empty()) {
video_ssrc = descs.at(0)->ssrc_;
}
// Note we must use the PT of source, see https://github.com/ossrs/srs/pull/3079
video_payload_type = descs.empty() ? kVideoPayloadType : descs.front()->media_->pt_;
}
rtp_builder_ = new SrsRtcRtpBuilder(this, audio_ssrc, audio_payload_type, video_ssrc, video_payload_type);
#endif
}
SrsFrameToRtcBridge::~SrsFrameToRtcBridge()
{
#ifdef SRS_FFMPEG_FIT
srs_freep(rtp_builder_);
#endif
}
srs_error_t SrsFrameToRtcBridge::initialize(SrsRequest* r)
{
#ifdef SRS_FFMPEG_FIT
return rtp_builder_->initialize(r);
#else
return srs_success;
#endif
}
srs_error_t SrsFrameToRtcBridge::on_publish()
{
srs_error_t err = srs_success;
// TODO: FIXME: Should sync with bridge?
if ((err = source_->on_publish()) != srs_success) {
return srs_error_wrap(err, "source 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 SrsFrameToRtcBridge::on_unpublish()
{
#ifdef SRS_FFMPEG_FIT
rtp_builder_->on_unpublish();
#endif
// @remark This bridge might be disposed here, so never use it.
// TODO: FIXME: Should sync with bridge?
source_->on_unpublish();
}
srs_error_t SrsFrameToRtcBridge::on_frame(SrsSharedPtrMessage* frame)
{
#ifdef SRS_FFMPEG_FIT
return rtp_builder_->on_frame(frame);
#else
return srs_success;
#endif
}
srs_error_t SrsFrameToRtcBridge::on_rtp(SrsRtpPacket* pkt)
{
return source_->on_rtp(pkt);
}
srs_error_t SrsFrameToRtcBridge::update_codec(SrsVideoCodecId id)
{
// init with H264 default, so we need check if it's H265 only.
if (id == SrsVideoCodecIdHEVC) {
if (source_->get_track_desc("video", "H265").empty()) {
std::vector<SrsRtcTrackDescription*> video_track_descs = source_->get_track_desc("video", "H264");
if (!video_track_descs.empty()) {
SrsRtcTrackDescription* video_track_desc = video_track_descs.at(0);
SrsVideoPayload* video_payload = (SrsVideoPayload*)video_track_desc->media_;
video_payload->name_ = "H265";
video_payload->set_h265_param_desc("level-id=180;profile-id=1;tier-flag=0;tx-mode=SRST");
srs_trace("RTC: Switch video codec %d(%s) to %d(%s)", SrsVideoCodecIdAVC, srs_video_codec_id2str(SrsVideoCodecIdAVC).c_str(),
id, srs_video_codec_id2str(id).c_str());
}
}
}
return srs_success;
}
#endif
SrsCompositeBridge::SrsCompositeBridge()
{
}
SrsCompositeBridge::~SrsCompositeBridge()
{
for (vector<ISrsStreamBridge*>::iterator it = bridges_.begin(); it != bridges_.end(); ++it) {
ISrsStreamBridge* bridge = *it;
srs_freep(bridge);
}
}
srs_error_t SrsCompositeBridge::initialize(SrsRequest* r)
{
srs_error_t err = srs_success;
for (vector<ISrsStreamBridge*>::iterator it = bridges_.begin(); it != bridges_.end(); ++it) {
ISrsStreamBridge* bridge = *it;
if ((err = bridge->initialize(r)) != srs_success) {
return err;
}
}
return err;
}
srs_error_t SrsCompositeBridge::on_publish()
{
srs_error_t err = srs_success;
for (vector<ISrsStreamBridge*>::iterator it = bridges_.begin(); it != bridges_.end(); ++it) {
ISrsStreamBridge* bridge = *it;
if ((err = bridge->on_publish()) != srs_success) {
return err;
}
}
return err;
}
void SrsCompositeBridge::on_unpublish()
{
for (vector<ISrsStreamBridge*>::iterator it = bridges_.begin(); it != bridges_.end(); ++it) {
ISrsStreamBridge* bridge = *it;
bridge->on_unpublish();
}
}
srs_error_t SrsCompositeBridge::on_frame(SrsSharedPtrMessage* frame)
{
srs_error_t err = srs_success;
for (vector<ISrsStreamBridge*>::iterator it = bridges_.begin(); it != bridges_.end(); ++it) {
ISrsStreamBridge* bridge = *it;
if ((err = bridge->on_frame(frame)) != srs_success) {
return err;
}
}
return err;
}
SrsCompositeBridge* SrsCompositeBridge::append(ISrsStreamBridge* bridge)
{
bridges_.push_back(bridge);
return this;
}