AI: Add utest to cover dvr module.
This commit is contained in:
parent
8ed07e37b4
commit
f0d713e574
|
|
@ -494,6 +494,12 @@ public:
|
|||
virtual bool get_reduce_sequence_header(std::string vhost) = 0;
|
||||
virtual bool get_parse_sps(std::string vhost) = 0;
|
||||
|
||||
public:
|
||||
// DVR config
|
||||
virtual std::string get_dvr_path(std::string vhost) = 0;
|
||||
virtual int get_dvr_time_jitter(std::string vhost) = 0;
|
||||
virtual bool get_dvr_wait_keyframe(std::string vhost) = 0;
|
||||
|
||||
public:
|
||||
// HTTP remux config
|
||||
virtual bool get_vhost_http_remux_enabled(std::string vhost) = 0;
|
||||
|
|
@ -509,6 +515,11 @@ public:
|
|||
virtual std::string get_vhost_edge_protocol(std::string vhost) = 0;
|
||||
virtual bool get_vhost_edge_follow_client(std::string vhost) = 0;
|
||||
virtual std::string get_vhost_edge_transform_vhost(std::string vhost) = 0;
|
||||
virtual SrsConfDirective *get_vhost_on_dvr(std::string vhost) = 0;
|
||||
virtual std::string get_dvr_plan(std::string vhost) = 0;
|
||||
virtual bool get_dvr_enabled(std::string vhost) = 0;
|
||||
virtual SrsConfDirective *get_dvr_apply(std::string vhost) = 0;
|
||||
virtual srs_utime_t get_dvr_duration(std::string vhost) = 0;
|
||||
};
|
||||
|
||||
// The config service provider.
|
||||
|
|
|
|||
|
|
@ -25,9 +25,18 @@ using namespace std;
|
|||
#include <srs_protocol_amf0.hpp>
|
||||
#include <srs_protocol_json.hpp>
|
||||
#include <srs_protocol_rtmp_stack.hpp>
|
||||
#include <srs_app_factory.hpp>
|
||||
|
||||
#define SRS_FWRITE_CACHE_SIZE 65536
|
||||
|
||||
ISrsDvrSegmenter::ISrsDvrSegmenter()
|
||||
{
|
||||
}
|
||||
|
||||
ISrsDvrSegmenter::~ISrsDvrSegmenter()
|
||||
{
|
||||
}
|
||||
|
||||
SrsDvrSegmenter::SrsDvrSegmenter()
|
||||
{
|
||||
req_ = NULL;
|
||||
|
|
@ -39,16 +48,23 @@ SrsDvrSegmenter::SrsDvrSegmenter()
|
|||
fs_ = new SrsFileWriter();
|
||||
jitter_algorithm_ = SrsRtmpJitterAlgorithmOFF;
|
||||
|
||||
_srs_config->subscribe(this);
|
||||
config_ = _srs_config;
|
||||
}
|
||||
|
||||
void SrsDvrSegmenter::assemble()
|
||||
{
|
||||
config_->subscribe(this);
|
||||
}
|
||||
|
||||
SrsDvrSegmenter::~SrsDvrSegmenter()
|
||||
{
|
||||
_srs_config->unsubscribe(this);
|
||||
config_->unsubscribe(this);
|
||||
|
||||
srs_freep(fragment_);
|
||||
srs_freep(jitter_);
|
||||
srs_freep(fs_);
|
||||
|
||||
config_ = NULL;
|
||||
}
|
||||
|
||||
// CRITICAL: This method is called AFTER the source has been added to the source pool
|
||||
|
|
@ -57,13 +73,13 @@ SrsDvrSegmenter::~SrsDvrSegmenter()
|
|||
// IMPORTANT: All field initialization in this method MUST NOT cause coroutine context switches.
|
||||
// This prevents the race condition where multiple coroutines could create duplicate sources
|
||||
// for the same stream when context switches occurred during initialization.
|
||||
srs_error_t SrsDvrSegmenter::initialize(SrsDvrPlan *p, ISrsRequest *r)
|
||||
srs_error_t SrsDvrSegmenter::initialize(ISrsDvrPlan *p, ISrsRequest *r)
|
||||
{
|
||||
req_ = r;
|
||||
plan_ = p;
|
||||
|
||||
jitter_algorithm_ = (SrsRtmpJitterAlgorithm)_srs_config->get_dvr_time_jitter(req_->vhost_);
|
||||
wait_keyframe_ = _srs_config->get_dvr_wait_keyframe(req_->vhost_);
|
||||
jitter_algorithm_ = (SrsRtmpJitterAlgorithm)config_->get_dvr_time_jitter(req_->vhost_);
|
||||
wait_keyframe_ = config_->get_dvr_wait_keyframe(req_->vhost_);
|
||||
|
||||
return srs_success;
|
||||
}
|
||||
|
|
@ -201,7 +217,7 @@ string SrsDvrSegmenter::generate_path()
|
|||
{
|
||||
// the path in config, for example,
|
||||
// /data/[vhost]/[app]/[stream]/[2006]/[01]/[02]/[15].[04].[05].[999].flv
|
||||
std::string path_config = _srs_config->get_dvr_path(req_->vhost_);
|
||||
std::string path_config = config_->get_dvr_path(req_->vhost_);
|
||||
|
||||
// add [stream].[timestamp].flv as filename for dir
|
||||
if (!srs_strings_ends_with(path_config, ".flv", ".mp4")) {
|
||||
|
|
@ -230,11 +246,15 @@ SrsDvrFlvSegmenter::SrsDvrFlvSegmenter()
|
|||
filesize_offset_ = 0;
|
||||
|
||||
has_keyframe_ = false;
|
||||
|
||||
app_factory_ = _srs_app_factory;
|
||||
}
|
||||
|
||||
SrsDvrFlvSegmenter::~SrsDvrFlvSegmenter()
|
||||
{
|
||||
srs_freep(enc_);
|
||||
|
||||
app_factory_ = NULL;
|
||||
}
|
||||
|
||||
srs_error_t SrsDvrFlvSegmenter::refresh_metadata()
|
||||
|
|
@ -297,7 +317,7 @@ srs_error_t SrsDvrFlvSegmenter::open_encoder()
|
|||
filesize_offset_ = 0;
|
||||
|
||||
srs_freep(enc_);
|
||||
enc_ = new SrsFlvTransmuxer();
|
||||
enc_ = app_factory_->create_flv_transmuxer();
|
||||
|
||||
if ((err = enc_->initialize(fs_)) != srs_success) {
|
||||
return srs_error_wrap(err, "init encoder");
|
||||
|
|
@ -414,11 +434,15 @@ srs_error_t SrsDvrFlvSegmenter::close_encoder()
|
|||
SrsDvrMp4Segmenter::SrsDvrMp4Segmenter()
|
||||
{
|
||||
enc_ = new SrsMp4Encoder();
|
||||
|
||||
app_factory_ = _srs_app_factory;
|
||||
}
|
||||
|
||||
SrsDvrMp4Segmenter::~SrsDvrMp4Segmenter()
|
||||
{
|
||||
srs_freep(enc_);
|
||||
|
||||
app_factory_ = NULL;
|
||||
}
|
||||
|
||||
srs_error_t SrsDvrMp4Segmenter::refresh_metadata()
|
||||
|
|
@ -431,7 +455,7 @@ srs_error_t SrsDvrMp4Segmenter::open_encoder()
|
|||
srs_error_t err = srs_success;
|
||||
|
||||
srs_freep(enc_);
|
||||
enc_ = new SrsMp4Encoder();
|
||||
enc_ = app_factory_->create_mp4_encoder();
|
||||
|
||||
if ((err = enc_->initialize(fs_)) != srs_success) {
|
||||
return srs_error_wrap(err, "init encoder");
|
||||
|
|
@ -456,10 +480,7 @@ srs_error_t SrsDvrMp4Segmenter::encode_audio(SrsMediaPacket *audio, SrsFormat *f
|
|||
|
||||
SrsAudioAacFrameTrait ct = format->audio_->aac_packet_type_;
|
||||
if (ct == SrsAudioAacFrameTraitSequenceHeader || ct == SrsAudioMp3FrameTraitSequenceHeader) {
|
||||
enc_->acodec_ = sound_format;
|
||||
enc_->sample_rate_ = sound_rate;
|
||||
enc_->sound_bits_ = sound_size;
|
||||
enc_->channels_ = channels;
|
||||
enc_->set_audio_codec(sound_format, sound_rate, sound_size, channels);
|
||||
}
|
||||
|
||||
uint8_t *sample = (uint8_t *)format->raw_;
|
||||
|
|
@ -515,18 +536,24 @@ SrsDvrAsyncCallOnDvr::SrsDvrAsyncCallOnDvr(SrsContextId c, ISrsRequest *r, strin
|
|||
cid_ = c;
|
||||
req_ = r->copy();
|
||||
path_ = p;
|
||||
|
||||
hooks_ = _srs_hooks;
|
||||
config_ = _srs_config;
|
||||
}
|
||||
|
||||
SrsDvrAsyncCallOnDvr::~SrsDvrAsyncCallOnDvr()
|
||||
{
|
||||
srs_freep(req_);
|
||||
|
||||
hooks_ = NULL;
|
||||
config_ = NULL;
|
||||
}
|
||||
|
||||
srs_error_t SrsDvrAsyncCallOnDvr::call()
|
||||
{
|
||||
srs_error_t err = srs_success;
|
||||
|
||||
if (!_srs_config->get_vhost_http_hooks_enabled(req_->vhost_)) {
|
||||
if (!config_->get_vhost_http_hooks_enabled(req_->vhost_)) {
|
||||
return err;
|
||||
}
|
||||
|
||||
|
|
@ -536,7 +563,7 @@ srs_error_t SrsDvrAsyncCallOnDvr::call()
|
|||
vector<string> hooks;
|
||||
|
||||
if (true) {
|
||||
SrsConfDirective *conf = _srs_config->get_vhost_on_dvr(req_->vhost_);
|
||||
SrsConfDirective *conf = config_->get_vhost_on_dvr(req_->vhost_);
|
||||
if (conf) {
|
||||
hooks = conf->args_;
|
||||
}
|
||||
|
|
@ -544,7 +571,7 @@ srs_error_t SrsDvrAsyncCallOnDvr::call()
|
|||
|
||||
for (int i = 0; i < (int)hooks.size(); i++) {
|
||||
std::string url = hooks.at(i);
|
||||
if ((err = _srs_hooks->on_dvr(cid_, url, req_, path_)) != srs_success) {
|
||||
if ((err = hooks_->on_dvr(cid_, url, req_, path_)) != srs_success) {
|
||||
return srs_error_wrap(err, "callback on_dvr %s", url.c_str());
|
||||
}
|
||||
}
|
||||
|
|
@ -559,6 +586,14 @@ string SrsDvrAsyncCallOnDvr::to_string()
|
|||
return ss.str();
|
||||
}
|
||||
|
||||
ISrsDvrPlan::ISrsDvrPlan()
|
||||
{
|
||||
}
|
||||
|
||||
ISrsDvrPlan::~ISrsDvrPlan()
|
||||
{
|
||||
}
|
||||
|
||||
SrsDvrPlan::SrsDvrPlan()
|
||||
{
|
||||
req_ = NULL;
|
||||
|
|
@ -566,12 +601,18 @@ SrsDvrPlan::SrsDvrPlan()
|
|||
|
||||
dvr_enabled_ = false;
|
||||
segment_ = NULL;
|
||||
|
||||
async_ = _srs_dvr_async;
|
||||
config_ = _srs_config;
|
||||
}
|
||||
|
||||
SrsDvrPlan::~SrsDvrPlan()
|
||||
{
|
||||
srs_freep(segment_);
|
||||
srs_freep(req_);
|
||||
|
||||
async_ = NULL;
|
||||
config_ = NULL;
|
||||
}
|
||||
|
||||
// CRITICAL: This method is called AFTER the source has been added to the source pool
|
||||
|
|
@ -580,7 +621,7 @@ SrsDvrPlan::~SrsDvrPlan()
|
|||
// IMPORTANT: All field initialization in this method MUST NOT cause coroutine context switches.
|
||||
// This prevents the race condition where multiple coroutines could create duplicate sources
|
||||
// for the same stream when context switches occurred during initialization.
|
||||
srs_error_t SrsDvrPlan::initialize(SrsOriginHub *h, SrsDvrSegmenter *s, ISrsRequest *r)
|
||||
srs_error_t SrsDvrPlan::initialize(ISrsOriginHub *h, ISrsDvrSegmenter *s, ISrsRequest *r)
|
||||
{
|
||||
srs_error_t err = srs_success;
|
||||
|
||||
|
|
@ -658,7 +699,7 @@ srs_error_t SrsDvrPlan::on_reap_segment()
|
|||
SrsFragment *fragment = segment_->current();
|
||||
string fullpath = fragment->fullpath();
|
||||
|
||||
if ((err = _srs_dvr_async->execute(new SrsDvrAsyncCallOnDvr(cid, req_, fullpath))) != srs_success) {
|
||||
if ((err = async_->execute(new SrsDvrAsyncCallOnDvr(cid, req_, fullpath))) != srs_success) {
|
||||
return srs_error_wrap(err, "reap segment");
|
||||
}
|
||||
|
||||
|
|
@ -671,9 +712,9 @@ srs_error_t SrsDvrPlan::on_reap_segment()
|
|||
// IMPORTANT: All field initialization in this method MUST NOT cause coroutine context switches.
|
||||
// This prevents the race condition where multiple coroutines could create duplicate sources
|
||||
// for the same stream when context switches occurred during initialization.
|
||||
srs_error_t SrsDvrPlan::create_plan(string vhost, SrsDvrPlan **pplan)
|
||||
srs_error_t SrsDvrPlan::create_plan(ISrsAppConfig *config, string vhost, ISrsDvrPlan **pplan)
|
||||
{
|
||||
std::string plan = _srs_config->get_dvr_plan(vhost);
|
||||
std::string plan = config->get_dvr_plan(vhost);
|
||||
if (srs_config_dvr_is_plan_segment(plan)) {
|
||||
*pplan = new SrsDvrSegmentPlan();
|
||||
} else if (srs_config_dvr_is_plan_session(plan)) {
|
||||
|
|
@ -707,7 +748,7 @@ srs_error_t SrsDvrSessionPlan::on_publish(ISrsRequest *r)
|
|||
return err;
|
||||
}
|
||||
|
||||
if (!_srs_config->get_dvr_enabled(req_->vhost_)) {
|
||||
if (!config_->get_dvr_enabled(req_->vhost_)) {
|
||||
return err;
|
||||
}
|
||||
|
||||
|
|
@ -756,7 +797,7 @@ SrsDvrSegmentPlan::~SrsDvrSegmentPlan()
|
|||
{
|
||||
}
|
||||
|
||||
srs_error_t SrsDvrSegmentPlan::initialize(SrsOriginHub *h, SrsDvrSegmenter *s, ISrsRequest *r)
|
||||
srs_error_t SrsDvrSegmentPlan::initialize(ISrsOriginHub *h, ISrsDvrSegmenter *s, ISrsRequest *r)
|
||||
{
|
||||
srs_error_t err = srs_success;
|
||||
|
||||
|
|
@ -764,9 +805,9 @@ srs_error_t SrsDvrSegmentPlan::initialize(SrsOriginHub *h, SrsDvrSegmenter *s, I
|
|||
return srs_error_wrap(err, "segment plan");
|
||||
}
|
||||
|
||||
wait_keyframe_ = _srs_config->get_dvr_wait_keyframe(req_->vhost_);
|
||||
wait_keyframe_ = config_->get_dvr_wait_keyframe(req_->vhost_);
|
||||
|
||||
cduration_ = _srs_config->get_dvr_duration(req_->vhost_);
|
||||
cduration_ = config_->get_dvr_duration(req_->vhost_);
|
||||
|
||||
return srs_success;
|
||||
}
|
||||
|
|
@ -784,7 +825,7 @@ srs_error_t SrsDvrSegmentPlan::on_publish(ISrsRequest *r)
|
|||
return err;
|
||||
}
|
||||
|
||||
if (!_srs_config->get_dvr_enabled(req_->vhost_)) {
|
||||
if (!config_->get_dvr_enabled(req_->vhost_)) {
|
||||
return err;
|
||||
}
|
||||
|
||||
|
|
@ -919,15 +960,24 @@ SrsDvr::SrsDvr()
|
|||
req_ = NULL;
|
||||
actived_ = false;
|
||||
|
||||
_srs_config->subscribe(this);
|
||||
config_ = _srs_config;
|
||||
app_factory_ = _srs_app_factory;
|
||||
}
|
||||
|
||||
void SrsDvr::assemble()
|
||||
{
|
||||
config_->subscribe(this);
|
||||
}
|
||||
|
||||
SrsDvr::~SrsDvr()
|
||||
{
|
||||
_srs_config->unsubscribe(this);
|
||||
config_->unsubscribe(this);
|
||||
|
||||
srs_freep(plan_);
|
||||
srs_freep(req_);
|
||||
|
||||
config_ = NULL;
|
||||
app_factory_ = NULL;
|
||||
}
|
||||
|
||||
// CRITICAL: This method is called AFTER the source has been added to the source pool
|
||||
|
|
@ -936,28 +986,29 @@ SrsDvr::~SrsDvr()
|
|||
// IMPORTANT: All field initialization in this method MUST NOT cause coroutine context switches.
|
||||
// This prevents the race condition where multiple coroutines could create duplicate sources
|
||||
// for the same stream when context switches occurred during initialization.
|
||||
srs_error_t SrsDvr::initialize(SrsOriginHub *h, ISrsRequest *r)
|
||||
srs_error_t SrsDvr::initialize(ISrsOriginHub *h, ISrsRequest *r)
|
||||
{
|
||||
srs_error_t err = srs_success;
|
||||
|
||||
req_ = r->copy();
|
||||
hub_ = h;
|
||||
|
||||
SrsConfDirective *conf = _srs_config->get_dvr_apply(r->vhost_);
|
||||
SrsConfDirective *conf = config_->get_dvr_apply(r->vhost_);
|
||||
actived_ = srs_config_apply_filter(conf, r);
|
||||
|
||||
srs_freep(plan_);
|
||||
if ((err = SrsDvrPlan::create_plan(r->vhost_, &plan_)) != srs_success) {
|
||||
if ((err = SrsDvrPlan::create_plan(config_, r->vhost_, &plan_)) != srs_success) {
|
||||
return srs_error_wrap(err, "create plan");
|
||||
}
|
||||
|
||||
std::string path = _srs_config->get_dvr_path(r->vhost_);
|
||||
SrsDvrSegmenter *segmenter = NULL;
|
||||
std::string path = config_->get_dvr_path(r->vhost_);
|
||||
ISrsDvrSegmenter *segmenter = NULL;
|
||||
if (srs_strings_ends_with(path, ".mp4")) {
|
||||
segmenter = new SrsDvrMp4Segmenter();
|
||||
segmenter = app_factory_->create_dvr_mp4_segmenter();
|
||||
} else {
|
||||
segmenter = new SrsDvrFlvSegmenter();
|
||||
segmenter = app_factory_->create_dvr_flv_segmenter();
|
||||
}
|
||||
segmenter->assemble();
|
||||
|
||||
if ((err = plan_->initialize(hub_, segmenter, r)) != srs_success) {
|
||||
return srs_error_wrap(err, "plan initialize");
|
||||
|
|
|
|||
|
|
@ -27,17 +27,45 @@ class SrsThread;
|
|||
class SrsMp4Encoder;
|
||||
class SrsFragment;
|
||||
class SrsFormat;
|
||||
class ISrsFileWriter;
|
||||
class ISrsDvrPlan;
|
||||
class ISrsMp4Encoder;
|
||||
class ISrsOriginHub;
|
||||
class ISrsAppConfig;
|
||||
class ISrsAppFactory;
|
||||
class ISrsAsyncCallWorker;
|
||||
|
||||
#include <srs_app_async_call.hpp>
|
||||
#include <srs_app_reload.hpp>
|
||||
#include <srs_app_rtmp_source.hpp>
|
||||
|
||||
// The segmenter for DVR, to write a segment file in flv/mp4.
|
||||
class SrsDvrSegmenter : public ISrsReloadHandler
|
||||
// The segmenter interface.
|
||||
class ISrsDvrSegmenter
|
||||
{
|
||||
public:
|
||||
ISrsDvrSegmenter();
|
||||
virtual void assemble() = 0;
|
||||
virtual ~ISrsDvrSegmenter();
|
||||
|
||||
public:
|
||||
virtual srs_error_t initialize(ISrsDvrPlan *p, ISrsRequest *r) = 0;
|
||||
virtual SrsFragment *current() = 0;
|
||||
virtual srs_error_t open() = 0;
|
||||
virtual srs_error_t write_metadata(SrsMediaPacket *metadata) = 0;
|
||||
virtual srs_error_t write_audio(SrsMediaPacket *shared_audio, SrsFormat *format) = 0;
|
||||
virtual srs_error_t write_video(SrsMediaPacket *shared_video, SrsFormat *format) = 0;
|
||||
virtual srs_error_t close() = 0;
|
||||
};
|
||||
|
||||
// The segmenter for DVR, to write a segment file in flv/mp4.
|
||||
class SrsDvrSegmenter : public ISrsReloadHandler, public ISrsDvrSegmenter
|
||||
{
|
||||
private:
|
||||
ISrsAppConfig *config_;
|
||||
|
||||
protected:
|
||||
// The underlayer file object.
|
||||
SrsFileWriter *fs_;
|
||||
ISrsFileWriter *fs_;
|
||||
// Whether wait keyframe to reap segment.
|
||||
bool wait_keyframe_;
|
||||
// The FLV/MP4 fragment file.
|
||||
|
|
@ -45,7 +73,7 @@ protected:
|
|||
|
||||
private:
|
||||
ISrsRequest *req_;
|
||||
SrsDvrPlan *plan_;
|
||||
ISrsDvrPlan *plan_;
|
||||
|
||||
private:
|
||||
SrsRtmpJitter *jitter_;
|
||||
|
|
@ -53,11 +81,12 @@ private:
|
|||
|
||||
public:
|
||||
SrsDvrSegmenter();
|
||||
void assemble();
|
||||
virtual ~SrsDvrSegmenter();
|
||||
|
||||
public:
|
||||
// Initialize the segment.
|
||||
virtual srs_error_t initialize(SrsDvrPlan *p, ISrsRequest *r);
|
||||
virtual srs_error_t initialize(ISrsDvrPlan *p, ISrsRequest *r);
|
||||
// Get the current framgnet.
|
||||
virtual SrsFragment *current();
|
||||
// Open new segment file.
|
||||
|
|
@ -97,6 +126,9 @@ private:
|
|||
// The FLV segmenter to use FLV encoder to write file.
|
||||
class SrsDvrFlvSegmenter : public SrsDvrSegmenter
|
||||
{
|
||||
private:
|
||||
ISrsAppFactory *app_factory_;
|
||||
|
||||
private:
|
||||
// The FLV encoder, for FLV target.
|
||||
ISrsFlvTransmuxer *enc_;
|
||||
|
|
@ -129,9 +161,12 @@ protected:
|
|||
// The MP4 segmenter to use MP4 encoder to write file.
|
||||
class SrsDvrMp4Segmenter : public SrsDvrSegmenter
|
||||
{
|
||||
private:
|
||||
ISrsAppFactory *app_factory_;
|
||||
|
||||
private:
|
||||
// The MP4 encoder, for MP4 target.
|
||||
SrsMp4Encoder *enc_;
|
||||
ISrsMp4Encoder *enc_;
|
||||
|
||||
public:
|
||||
SrsDvrMp4Segmenter();
|
||||
|
|
@ -151,6 +186,10 @@ protected:
|
|||
// the dvr async call.
|
||||
class SrsDvrAsyncCallOnDvr : public ISrsAsyncCallTask
|
||||
{
|
||||
private:
|
||||
ISrsHttpHooks *hooks_;
|
||||
ISrsAppConfig *config_;
|
||||
|
||||
private:
|
||||
SrsContextId cid_;
|
||||
std::string path_;
|
||||
|
|
@ -165,15 +204,36 @@ public:
|
|||
virtual std::string to_string();
|
||||
};
|
||||
|
||||
// The DVR plan, when and how to reap segment.
|
||||
class SrsDvrPlan : public ISrsReloadHandler
|
||||
// The DVR plan interface.
|
||||
class ISrsDvrPlan
|
||||
{
|
||||
public:
|
||||
ISrsDvrPlan();
|
||||
virtual ~ISrsDvrPlan();
|
||||
|
||||
public:
|
||||
virtual srs_error_t initialize(ISrsOriginHub *h, ISrsDvrSegmenter *s, ISrsRequest *r) = 0;
|
||||
virtual srs_error_t on_publish(ISrsRequest *r) = 0;
|
||||
virtual void on_unpublish() = 0;
|
||||
virtual srs_error_t on_meta_data(SrsMediaPacket *shared_metadata) = 0;
|
||||
virtual srs_error_t on_audio(SrsMediaPacket *shared_audio, SrsFormat *format) = 0;
|
||||
virtual srs_error_t on_video(SrsMediaPacket *shared_video, SrsFormat *format) = 0;
|
||||
virtual srs_error_t on_reap_segment() = 0;
|
||||
};
|
||||
|
||||
// The DVR plan, when and how to reap segment.
|
||||
class SrsDvrPlan : public ISrsReloadHandler, public ISrsDvrPlan
|
||||
{
|
||||
protected:
|
||||
ISrsAsyncCallWorker *async_;
|
||||
ISrsAppConfig *config_;
|
||||
|
||||
public:
|
||||
ISrsRequest *req_;
|
||||
|
||||
protected:
|
||||
SrsOriginHub *hub_;
|
||||
SrsDvrSegmenter *segment_;
|
||||
ISrsOriginHub *hub_;
|
||||
ISrsDvrSegmenter *segment_;
|
||||
bool dvr_enabled_;
|
||||
|
||||
public:
|
||||
|
|
@ -181,7 +241,7 @@ public:
|
|||
virtual ~SrsDvrPlan();
|
||||
|
||||
public:
|
||||
virtual srs_error_t initialize(SrsOriginHub *h, SrsDvrSegmenter *s, ISrsRequest *r);
|
||||
virtual srs_error_t initialize(ISrsOriginHub *h, ISrsDvrSegmenter *s, ISrsRequest *r);
|
||||
virtual srs_error_t on_publish(ISrsRequest *r);
|
||||
virtual void on_unpublish();
|
||||
virtual srs_error_t on_meta_data(SrsMediaPacket *shared_metadata);
|
||||
|
|
@ -193,7 +253,7 @@ public:
|
|||
virtual srs_error_t on_reap_segment();
|
||||
|
||||
public:
|
||||
static srs_error_t create_plan(std::string vhost, SrsDvrPlan **pplan);
|
||||
static srs_error_t create_plan(ISrsAppConfig *config, std::string vhost, ISrsDvrPlan **pplan);
|
||||
};
|
||||
|
||||
// The DVR session plan: reap flv when session complete(unpublish)
|
||||
|
|
@ -223,7 +283,7 @@ public:
|
|||
virtual ~SrsDvrSegmentPlan();
|
||||
|
||||
public:
|
||||
virtual srs_error_t initialize(SrsOriginHub *h, SrsDvrSegmenter *s, ISrsRequest *r);
|
||||
virtual srs_error_t initialize(ISrsOriginHub *h, ISrsDvrSegmenter *s, ISrsRequest *r);
|
||||
virtual srs_error_t on_publish(ISrsRequest *r);
|
||||
virtual void on_unpublish();
|
||||
virtual srs_error_t on_audio(SrsMediaPacket *shared_audio, SrsFormat *format);
|
||||
|
|
@ -238,10 +298,11 @@ class ISrsDvr
|
|||
{
|
||||
public:
|
||||
ISrsDvr();
|
||||
virtual void assemble() = 0;
|
||||
virtual ~ISrsDvr();
|
||||
|
||||
public:
|
||||
virtual srs_error_t initialize(SrsOriginHub *h, ISrsRequest *r) = 0;
|
||||
virtual srs_error_t initialize(ISrsOriginHub *h, ISrsRequest *r) = 0;
|
||||
virtual srs_error_t on_publish(ISrsRequest *r) = 0;
|
||||
virtual void on_unpublish() = 0;
|
||||
virtual srs_error_t on_meta_data(SrsMediaPacket *metadata) = 0;
|
||||
|
|
@ -253,8 +314,12 @@ public:
|
|||
class SrsDvr : public ISrsReloadHandler, public ISrsDvr
|
||||
{
|
||||
private:
|
||||
SrsOriginHub *hub_;
|
||||
SrsDvrPlan *plan_;
|
||||
ISrsAppConfig *config_;
|
||||
ISrsAppFactory *app_factory_;
|
||||
|
||||
private:
|
||||
ISrsOriginHub *hub_;
|
||||
ISrsDvrPlan *plan_;
|
||||
ISrsRequest *req_;
|
||||
|
||||
private:
|
||||
|
|
@ -265,13 +330,14 @@ private:
|
|||
|
||||
public:
|
||||
SrsDvr();
|
||||
void assemble();
|
||||
virtual ~SrsDvr();
|
||||
|
||||
public:
|
||||
// initialize dvr, create dvr plan.
|
||||
// when system initialize(encoder publish at first time, or reload),
|
||||
// initialize the dvr will reinitialize the plan, the whole dvr framework.
|
||||
virtual srs_error_t initialize(SrsOriginHub *h, ISrsRequest *r);
|
||||
virtual srs_error_t initialize(ISrsOriginHub *h, ISrsRequest *r);
|
||||
// publish stream event,
|
||||
// when encoder start to publish RTMP stream.
|
||||
// @param fetch_sequence_header whether fetch sequence from source.
|
||||
|
|
|
|||
|
|
@ -19,6 +19,9 @@
|
|||
#include <srs_protocol_http_client.hpp>
|
||||
#include <srs_protocol_st.hpp>
|
||||
#include <srs_app_rtsp_source.hpp>
|
||||
#include <srs_kernel_flv.hpp>
|
||||
#include <srs_kernel_mp4.hpp>
|
||||
#include <srs_app_dvr.hpp>
|
||||
|
||||
ISrsAppFactory::ISrsAppFactory()
|
||||
{
|
||||
|
|
@ -93,6 +96,7 @@ ISrsFlvDecoder *SrsAppFactory::create_flv_decoder()
|
|||
return new SrsFlvDecoder();
|
||||
}
|
||||
|
||||
#ifdef SRS_RTSP
|
||||
ISrsRtspSendTrack *SrsAppFactory::create_rtsp_audio_send_track(ISrsRtspConnection *session, SrsRtcTrackDescription *track_desc)
|
||||
{
|
||||
return new SrsRtspAudioSendTrack(session, track_desc);
|
||||
|
|
@ -102,6 +106,27 @@ ISrsRtspSendTrack *SrsAppFactory::create_rtsp_video_send_track(ISrsRtspConnectio
|
|||
{
|
||||
return new SrsRtspVideoSendTrack(session, track_desc);
|
||||
}
|
||||
#endif
|
||||
|
||||
ISrsFlvTransmuxer *SrsAppFactory::create_flv_transmuxer()
|
||||
{
|
||||
return new SrsFlvTransmuxer();
|
||||
}
|
||||
|
||||
ISrsMp4Encoder *SrsAppFactory::create_mp4_encoder()
|
||||
{
|
||||
return new SrsMp4Encoder();
|
||||
}
|
||||
|
||||
ISrsDvrSegmenter *SrsAppFactory::create_dvr_flv_segmenter()
|
||||
{
|
||||
return new SrsDvrFlvSegmenter();
|
||||
}
|
||||
|
||||
ISrsDvrSegmenter *SrsAppFactory::create_dvr_mp4_segmenter()
|
||||
{
|
||||
return new SrsDvrMp4Segmenter();
|
||||
}
|
||||
|
||||
SrsFinalFactory::SrsFinalFactory()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -26,6 +26,9 @@ class ISrsHttpResponseReader;
|
|||
class ISrsRtspSendTrack;
|
||||
class ISrsRtspConnection;
|
||||
class SrsRtcTrackDescription;
|
||||
class ISrsFlvTransmuxer;
|
||||
class ISrsMp4Encoder;
|
||||
class ISrsDvrSegmenter;
|
||||
|
||||
// The factory to create app objects.
|
||||
class ISrsAppFactory
|
||||
|
|
@ -46,8 +49,14 @@ public:
|
|||
virtual ISrsHttpClient *create_http_client() = 0;
|
||||
virtual ISrsFileReader *create_http_file_reader(ISrsHttpResponseReader *r) = 0;
|
||||
virtual ISrsFlvDecoder *create_flv_decoder() = 0;
|
||||
#ifdef SRS_RTSP
|
||||
virtual ISrsRtspSendTrack *create_rtsp_audio_send_track(ISrsRtspConnection *session, SrsRtcTrackDescription *track_desc) = 0;
|
||||
virtual ISrsRtspSendTrack *create_rtsp_video_send_track(ISrsRtspConnection *session, SrsRtcTrackDescription *track_desc) = 0;
|
||||
#endif
|
||||
virtual ISrsFlvTransmuxer *create_flv_transmuxer() = 0;
|
||||
virtual ISrsMp4Encoder *create_mp4_encoder() = 0;
|
||||
virtual ISrsDvrSegmenter *create_dvr_flv_segmenter() = 0;
|
||||
virtual ISrsDvrSegmenter *create_dvr_mp4_segmenter() = 0;
|
||||
};
|
||||
|
||||
// The factory to create app objects.
|
||||
|
|
@ -69,8 +78,14 @@ public:
|
|||
virtual ISrsHttpClient *create_http_client();
|
||||
virtual ISrsFileReader *create_http_file_reader(ISrsHttpResponseReader *r);
|
||||
virtual ISrsFlvDecoder *create_flv_decoder();
|
||||
#ifdef SRS_RTSP
|
||||
virtual ISrsRtspSendTrack *create_rtsp_audio_send_track(ISrsRtspConnection *session, SrsRtcTrackDescription *track_desc);
|
||||
virtual ISrsRtspSendTrack *create_rtsp_video_send_track(ISrsRtspConnection *session, SrsRtcTrackDescription *track_desc);
|
||||
#endif
|
||||
virtual ISrsFlvTransmuxer *create_flv_transmuxer();
|
||||
virtual ISrsMp4Encoder *create_mp4_encoder();
|
||||
virtual ISrsDvrSegmenter *create_dvr_flv_segmenter();
|
||||
virtual ISrsDvrSegmenter *create_dvr_mp4_segmenter();
|
||||
};
|
||||
|
||||
extern ISrsAppFactory *_srs_app_factory;
|
||||
|
|
|
|||
|
|
@ -244,7 +244,9 @@ void SrsRtmpConn::assemble()
|
|||
|
||||
SrsRtmpConn::~SrsRtmpConn()
|
||||
{
|
||||
config_->unsubscribe(this);
|
||||
if (config_) {
|
||||
config_->unsubscribe(this);
|
||||
}
|
||||
|
||||
trd_->interrupt();
|
||||
// wakeup the handler which need to notice.
|
||||
|
|
@ -262,6 +264,7 @@ SrsRtmpConn::~SrsRtmpConn()
|
|||
srs_freep(refer_);
|
||||
srs_freep(security_);
|
||||
|
||||
config_ = NULL;
|
||||
manager_ = NULL;
|
||||
stream_publish_tokens_ = NULL;
|
||||
live_sources_ = NULL;
|
||||
|
|
|
|||
|
|
@ -850,7 +850,10 @@ SrsOriginHub::SrsOriginHub()
|
|||
|
||||
hls_ = new SrsHls();
|
||||
dash_ = new SrsDash();
|
||||
|
||||
dvr_ = new SrsDvr();
|
||||
dvr_->assemble();
|
||||
|
||||
encoder_ = new SrsEncoder();
|
||||
#ifdef SRS_HDS
|
||||
hds_ = new SrsHds();
|
||||
|
|
|
|||
|
|
@ -402,6 +402,8 @@ public:
|
|||
virtual srs_error_t on_publish() = 0;
|
||||
// When stop publish stream.
|
||||
virtual void on_unpublish() = 0;
|
||||
// When DVR requests sequence header.
|
||||
virtual srs_error_t on_dvr_request_sh() = 0;
|
||||
};
|
||||
|
||||
// The hub for origin is a collection of utilities for origin only,
|
||||
|
|
|
|||
|
|
@ -30,6 +30,9 @@ public:
|
|||
virtual srs_error_t open(std::string p) = 0;
|
||||
virtual void close() = 0;
|
||||
virtual bool is_open() = 0;
|
||||
virtual srs_error_t set_iobuf_size(int size) = 0;
|
||||
virtual void seek2(int64_t offset) = 0;
|
||||
virtual int64_t tellg() = 0;
|
||||
};
|
||||
|
||||
// file writer, to write to file.
|
||||
|
|
|
|||
|
|
@ -6493,6 +6493,14 @@ srs_error_t SrsMp4Decoder::do_load_next_box(SrsMp4Box **ppbox, uint32_t required
|
|||
return err;
|
||||
}
|
||||
|
||||
ISrsMp4Encoder::ISrsMp4Encoder()
|
||||
{
|
||||
}
|
||||
|
||||
ISrsMp4Encoder::~ISrsMp4Encoder()
|
||||
{
|
||||
}
|
||||
|
||||
SrsMp4Encoder::SrsMp4Encoder()
|
||||
{
|
||||
wsio_ = NULL;
|
||||
|
|
@ -6889,6 +6897,14 @@ srs_error_t SrsMp4Encoder::flush()
|
|||
return err;
|
||||
}
|
||||
|
||||
void SrsMp4Encoder::set_audio_codec(SrsAudioCodecId vcodec, SrsAudioSampleRate sample_rate, SrsAudioSampleBits sound_bits, SrsAudioChannels channels)
|
||||
{
|
||||
acodec_ = vcodec;
|
||||
sample_rate_ = sample_rate;
|
||||
sound_bits_ = sound_bits;
|
||||
channels_ = channels;
|
||||
}
|
||||
|
||||
srs_error_t SrsMp4Encoder::copy_sequence_header(SrsFormat *format, bool vsh, uint8_t *sample, uint32_t nb_sample)
|
||||
{
|
||||
srs_error_t err = srs_success;
|
||||
|
|
|
|||
|
|
@ -2624,8 +2624,27 @@ private:
|
|||
virtual srs_error_t do_load_next_box(SrsMp4Box **ppbox, uint32_t required_box_type);
|
||||
};
|
||||
|
||||
// The MP4 encoder interface.
|
||||
class ISrsMp4Encoder
|
||||
{
|
||||
public:
|
||||
ISrsMp4Encoder();
|
||||
virtual ~ISrsMp4Encoder();
|
||||
|
||||
public:
|
||||
// The video codec of first track.
|
||||
SrsVideoCodecId vcodec_;
|
||||
|
||||
public:
|
||||
virtual srs_error_t initialize(ISrsWriteSeeker *ws) = 0;
|
||||
virtual srs_error_t write_sample(SrsFormat *format, SrsMp4HandlerType ht, uint16_t ft, uint16_t ct,
|
||||
uint32_t dts, uint32_t pts, uint8_t *sample, uint32_t nb_sample) = 0;
|
||||
virtual srs_error_t flush() = 0;
|
||||
virtual void set_audio_codec(SrsAudioCodecId vcodec, SrsAudioSampleRate sample_rate, SrsAudioSampleBits sound_bits, SrsAudioChannels channels) = 0;
|
||||
};
|
||||
|
||||
// The MP4 muxer.
|
||||
class SrsMp4Encoder
|
||||
class SrsMp4Encoder : public ISrsMp4Encoder
|
||||
{
|
||||
private:
|
||||
ISrsWriteSeeker *wsio_;
|
||||
|
|
@ -2694,6 +2713,8 @@ public:
|
|||
// Flush the encoder, to write the moov.
|
||||
virtual srs_error_t flush();
|
||||
|
||||
virtual void set_audio_codec(SrsAudioCodecId vcodec, SrsAudioSampleRate sample_rate, SrsAudioSampleBits sound_bits, SrsAudioChannels channels);
|
||||
|
||||
private:
|
||||
virtual srs_error_t copy_sequence_header(SrsFormat *format, bool vsh, uint8_t *sample, uint32_t nb_sample);
|
||||
virtual srs_error_t do_write_sample(SrsMp4Sample *ps, uint8_t *sample, uint32_t nb_sample);
|
||||
|
|
|
|||
|
|
@ -228,9 +228,6 @@ VOID TEST(SrsServerTest, ListenRtmpSuccess)
|
|||
// - Socket binding succeeded on the random port
|
||||
// - Connection manager started successfully
|
||||
EXPECT_TRUE(server.get() != NULL);
|
||||
|
||||
// Cleanup: restore original config to avoid side effects
|
||||
server->config_ = _srs_config;
|
||||
}
|
||||
|
||||
MockHttpServeMux::MockHttpServeMux()
|
||||
|
|
@ -1713,7 +1710,7 @@ VOID TEST(SrsRtmpConnTest, StreamServiceCycleSelection)
|
|||
// Test srs_get_disk_diskstats_stat() function to verify proper disk statistics
|
||||
// collection from /proc/diskstats. This test covers the major use scenario of
|
||||
// reading disk I/O statistics for configured disk devices. The function uses
|
||||
// the global _srs_config to get disk device configuration.
|
||||
// the global config to get disk device configuration.
|
||||
VOID TEST(SrsUtilityTest, GetDiskDiskstatsStat)
|
||||
{
|
||||
// Test case 1: Call with default config - should return true with ok_ = true
|
||||
|
|
@ -2879,9 +2876,9 @@ VOID TEST(SrsRtmpConnTest, HttpHooksOnClose)
|
|||
EXPECT_EQ(0, mock_hooks->on_close_calls_[1].send_bytes_);
|
||||
EXPECT_EQ(0, mock_hooks->on_close_calls_[1].recv_bytes_);
|
||||
|
||||
// Cleanup: restore original config and hooks to avoid side effects
|
||||
conn->config_ = _srs_config;
|
||||
conn->hooks_ = _srs_hooks;
|
||||
// Clean up injected dependencies to avoid double-free
|
||||
conn->config_ = NULL;
|
||||
conn->hooks_ = NULL;
|
||||
srs_freep(mock_config);
|
||||
srs_freep(mock_hooks);
|
||||
}
|
||||
|
|
@ -3033,9 +3030,9 @@ VOID TEST(SrsRtmpConnTest, HttpHooksOnPublishSuccess)
|
|||
EXPECT_STREQ("http://localhost:8085/api/v1/publish", mock_hooks->on_publish_calls_[1].first.c_str());
|
||||
EXPECT_TRUE(mock_hooks->on_publish_calls_[1].second == conn->info_->req_);
|
||||
|
||||
// Cleanup: restore original config and hooks to avoid side effects
|
||||
conn->config_ = _srs_config;
|
||||
conn->hooks_ = _srs_hooks;
|
||||
// Clean up injected dependencies to avoid double-free
|
||||
conn->config_ = NULL;
|
||||
conn->hooks_ = NULL;
|
||||
srs_freep(mock_config);
|
||||
srs_freep(mock_hooks);
|
||||
}
|
||||
|
|
@ -3114,9 +3111,9 @@ VOID TEST(SrsRtmpConnTest, HttpHooksOnUnpublishSuccess)
|
|||
EXPECT_STREQ("http://localhost:8085/api/v1/unpublish", mock_hooks->on_unpublish_calls_[1].first.c_str());
|
||||
EXPECT_TRUE(mock_hooks->on_unpublish_calls_[1].second == conn->info_->req_);
|
||||
|
||||
// Cleanup: restore original config and hooks to avoid side effects
|
||||
conn->config_ = _srs_config;
|
||||
conn->hooks_ = _srs_hooks;
|
||||
// Clean up injected dependencies to avoid double-free
|
||||
conn->config_ = NULL;
|
||||
conn->hooks_ = NULL;
|
||||
srs_freep(mock_config);
|
||||
srs_freep(mock_hooks);
|
||||
}
|
||||
|
|
@ -3195,9 +3192,9 @@ VOID TEST(SrsRtmpConnTest, HttpHooksOnStopSuccess)
|
|||
EXPECT_STREQ("http://localhost:8085/api/v1/stop", mock_hooks->on_stop_calls_[1].first.c_str());
|
||||
EXPECT_TRUE(mock_hooks->on_stop_calls_[1].second == conn->info_->req_);
|
||||
|
||||
// Cleanup: restore original config and hooks to avoid side effects
|
||||
conn->config_ = _srs_config;
|
||||
conn->hooks_ = _srs_hooks;
|
||||
// Clean up injected dependencies to avoid double-free
|
||||
conn->config_ = NULL;
|
||||
conn->hooks_ = NULL;
|
||||
srs_freep(mock_config);
|
||||
srs_freep(mock_hooks);
|
||||
}
|
||||
|
|
@ -3349,9 +3346,9 @@ VOID TEST(SrsRtmpConnTest, HttpHooksOnPlaySuccess)
|
|||
EXPECT_STREQ("http://localhost:8085/api/v1/play", mock_hooks->on_play_calls_[1].first.c_str());
|
||||
EXPECT_TRUE(mock_hooks->on_play_calls_[1].second == conn->info_->req_);
|
||||
|
||||
// Cleanup: restore original config and hooks to avoid side effects
|
||||
conn->config_ = _srs_config;
|
||||
conn->hooks_ = _srs_hooks;
|
||||
// Clean up injected dependencies to avoid double-free
|
||||
conn->config_ = NULL;
|
||||
conn->hooks_ = NULL;
|
||||
srs_freep(mock_config);
|
||||
srs_freep(mock_hooks);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2452,9 +2452,6 @@ VOID TEST(SrsRtspRtpBuilderTest, InitializePublishUnpublishLifecycle)
|
|||
EXPECT_EQ(15, builder->meta_->previous_ash()->size());
|
||||
EXPECT_EQ(0, memcmp(builder->meta_->previous_vsh()->payload(), video_data, 20));
|
||||
EXPECT_EQ(0, memcmp(builder->meta_->previous_ash()->payload(), audio_data, 15));
|
||||
|
||||
// Restore global config
|
||||
builder->config_ = _srs_config;
|
||||
}
|
||||
|
||||
// Test SrsRtspRtpBuilder::on_frame and on_audio - covers the major use scenario:
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
|
|
@ -13,6 +13,7 @@
|
|||
#include <srs_utest.hpp>
|
||||
|
||||
#include <srs_app_config.hpp>
|
||||
#include <srs_app_dvr.hpp>
|
||||
#include <srs_app_edge.hpp>
|
||||
#include <srs_app_factory.hpp>
|
||||
#include <srs_app_rtc_source.hpp>
|
||||
|
|
@ -22,6 +23,7 @@
|
|||
#include <srs_app_statistic.hpp>
|
||||
#include <srs_kernel_balance.hpp>
|
||||
#include <srs_kernel_flv.hpp>
|
||||
#include <srs_kernel_mp4.hpp>
|
||||
#include <srs_protocol_http_client.hpp>
|
||||
#include <srs_protocol_http_stack.hpp>
|
||||
#include <srs_protocol_json.hpp>
|
||||
|
|
@ -64,6 +66,14 @@ public:
|
|||
virtual int get_chunk_size(std::string vhost);
|
||||
virtual srs_utime_t get_vhost_edge_origin_connect_timeout(std::string vhost);
|
||||
virtual srs_utime_t get_vhost_edge_origin_stream_timeout(std::string vhost);
|
||||
// DVR methods
|
||||
virtual std::string get_dvr_path(std::string vhost);
|
||||
virtual int get_dvr_time_jitter(std::string vhost);
|
||||
virtual bool get_dvr_wait_keyframe(std::string vhost);
|
||||
virtual bool get_dvr_enabled(std::string vhost);
|
||||
virtual srs_utime_t get_dvr_duration(std::string vhost);
|
||||
virtual SrsConfDirective *get_dvr_apply(std::string vhost);
|
||||
virtual std::string get_dvr_plan(std::string vhost);
|
||||
};
|
||||
|
||||
// Mock RTMP client for testing edge upstream
|
||||
|
|
@ -478,4 +488,202 @@ public:
|
|||
void reset();
|
||||
};
|
||||
|
||||
// Mock ISrsDvrPlan for testing SrsDvrSegmenter
|
||||
class MockDvrPlan : public ISrsDvrPlan
|
||||
{
|
||||
public:
|
||||
bool on_publish_called_;
|
||||
bool on_unpublish_called_;
|
||||
srs_error_t on_publish_error_;
|
||||
|
||||
public:
|
||||
MockDvrPlan();
|
||||
virtual ~MockDvrPlan();
|
||||
|
||||
public:
|
||||
virtual srs_error_t initialize(ISrsOriginHub *h, ISrsDvrSegmenter *s, ISrsRequest *r);
|
||||
virtual srs_error_t on_publish(ISrsRequest *r);
|
||||
virtual void on_unpublish();
|
||||
virtual srs_error_t on_meta_data(SrsMediaPacket *shared_metadata);
|
||||
virtual srs_error_t on_audio(SrsMediaPacket *shared_audio, SrsFormat *format);
|
||||
virtual srs_error_t on_video(SrsMediaPacket *shared_video, SrsFormat *format);
|
||||
virtual srs_error_t on_reap_segment();
|
||||
};
|
||||
|
||||
// Mock ISrsHttpHooks for testing SrsDvrAsyncCallOnDvr
|
||||
class MockHttpHooksForDvrAsyncCall : public ISrsHttpHooks
|
||||
{
|
||||
public:
|
||||
struct OnDvrCall {
|
||||
SrsContextId cid_;
|
||||
std::string url_;
|
||||
ISrsRequest *req_;
|
||||
std::string file_;
|
||||
};
|
||||
std::vector<OnDvrCall> on_dvr_calls_;
|
||||
int on_dvr_count_;
|
||||
srs_error_t on_dvr_error_;
|
||||
|
||||
public:
|
||||
MockHttpHooksForDvrAsyncCall();
|
||||
virtual ~MockHttpHooksForDvrAsyncCall();
|
||||
|
||||
public:
|
||||
virtual srs_error_t on_connect(std::string url, ISrsRequest *req);
|
||||
virtual void on_close(std::string url, ISrsRequest *req, int64_t send_bytes, int64_t recv_bytes);
|
||||
virtual srs_error_t on_publish(std::string url, ISrsRequest *req);
|
||||
virtual void on_unpublish(std::string url, ISrsRequest *req);
|
||||
virtual srs_error_t on_play(std::string url, ISrsRequest *req);
|
||||
virtual void on_stop(std::string url, ISrsRequest *req);
|
||||
virtual srs_error_t on_dvr(SrsContextId cid, std::string url, ISrsRequest *req, std::string file);
|
||||
virtual srs_error_t on_hls(SrsContextId cid, std::string url, ISrsRequest *req, std::string file, std::string ts_url,
|
||||
std::string m3u8, std::string m3u8_url, int sn, srs_utime_t duration);
|
||||
virtual srs_error_t on_hls_notify(SrsContextId cid, std::string url, ISrsRequest *req, std::string ts_url, int nb_notify);
|
||||
virtual srs_error_t discover_co_workers(std::string url, std::string &host, int &port);
|
||||
virtual srs_error_t on_forward_backend(std::string url, ISrsRequest *req, std::vector<std::string> &rtmp_urls);
|
||||
|
||||
void reset();
|
||||
};
|
||||
|
||||
// Mock ISrsFlvTransmuxer for testing SrsDvrFlvSegmenter
|
||||
class MockFlvTransmuxer : public ISrsFlvTransmuxer
|
||||
{
|
||||
public:
|
||||
bool write_header_called_;
|
||||
bool write_metadata_called_;
|
||||
char metadata_type_;
|
||||
int metadata_size_;
|
||||
srs_error_t write_metadata_error_;
|
||||
|
||||
public:
|
||||
MockFlvTransmuxer();
|
||||
virtual ~MockFlvTransmuxer();
|
||||
|
||||
public:
|
||||
virtual srs_error_t initialize(ISrsWriter *fw);
|
||||
virtual void set_drop_if_not_match(bool v);
|
||||
virtual bool drop_if_not_match();
|
||||
virtual srs_error_t write_header(bool has_video = true, bool has_audio = true);
|
||||
virtual srs_error_t write_header(char flv_header[9]);
|
||||
virtual srs_error_t write_metadata(char type, char *data, int size);
|
||||
virtual srs_error_t write_audio(int64_t timestamp, char *data, int size);
|
||||
virtual srs_error_t write_video(int64_t timestamp, char *data, int size);
|
||||
virtual srs_error_t write_tags(SrsMediaPacket **msgs, int count);
|
||||
};
|
||||
|
||||
// Mock ISrsMp4Encoder for testing SrsDvrMp4Segmenter
|
||||
class MockMp4Encoder : public ISrsMp4Encoder
|
||||
{
|
||||
public:
|
||||
bool initialize_called_;
|
||||
bool write_sample_called_;
|
||||
bool flush_called_;
|
||||
bool set_audio_codec_called_;
|
||||
SrsMp4HandlerType last_handler_type_;
|
||||
uint16_t last_frame_type_;
|
||||
uint16_t last_codec_type_;
|
||||
uint32_t last_dts_;
|
||||
uint32_t last_pts_;
|
||||
uint32_t last_sample_size_;
|
||||
SrsAudioCodecId last_audio_codec_;
|
||||
SrsAudioSampleRate last_audio_sample_rate_;
|
||||
SrsAudioSampleBits last_audio_sound_bits_;
|
||||
SrsAudioChannels last_audio_channels_;
|
||||
|
||||
public:
|
||||
MockMp4Encoder();
|
||||
virtual ~MockMp4Encoder();
|
||||
|
||||
public:
|
||||
virtual srs_error_t initialize(ISrsWriteSeeker *ws);
|
||||
virtual srs_error_t write_sample(SrsFormat *format, SrsMp4HandlerType ht, uint16_t ft, uint16_t ct,
|
||||
uint32_t dts, uint32_t pts, uint8_t *sample, uint32_t nb_sample);
|
||||
virtual srs_error_t flush();
|
||||
virtual void set_audio_codec(SrsAudioCodecId vcodec, SrsAudioSampleRate sample_rate, SrsAudioSampleBits sound_bits, SrsAudioChannels channels);
|
||||
void reset();
|
||||
};
|
||||
|
||||
// Mock ISrsAppFactory for testing SrsDvrMp4Segmenter
|
||||
class MockDvrAppFactory : public ISrsAppFactory
|
||||
{
|
||||
public:
|
||||
MockMp4Encoder *mock_mp4_encoder_;
|
||||
|
||||
public:
|
||||
MockDvrAppFactory();
|
||||
virtual ~MockDvrAppFactory();
|
||||
|
||||
public:
|
||||
virtual ISrsFileWriter *create_file_writer();
|
||||
virtual ISrsFileWriter *create_enc_file_writer();
|
||||
virtual ISrsFileReader *create_file_reader();
|
||||
virtual SrsPath *create_path();
|
||||
virtual SrsLiveSource *create_live_source();
|
||||
virtual ISrsOriginHub *create_origin_hub();
|
||||
virtual ISrsHourGlass *create_hourglass(const std::string &name, ISrsHourGlassHandler *handler, srs_utime_t interval);
|
||||
virtual ISrsBasicRtmpClient *create_rtmp_client(std::string url, srs_utime_t cto, srs_utime_t sto);
|
||||
virtual ISrsHttpClient *create_http_client();
|
||||
virtual ISrsHttpResponseReader *create_http_response_reader(ISrsHttpResponseReader *r);
|
||||
virtual ISrsFileReader *create_http_file_reader(ISrsHttpResponseReader *r);
|
||||
virtual ISrsFlvDecoder *create_flv_decoder();
|
||||
virtual ISrsBasicRtmpClient *create_basic_rtmp_client(std::string url, srs_utime_t ctm, srs_utime_t stm);
|
||||
#ifdef SRS_RTSP
|
||||
virtual ISrsRtspSendTrack *create_rtsp_audio_send_track(ISrsRtspConnection *session, SrsRtcTrackDescription *track_desc);
|
||||
virtual ISrsRtspSendTrack *create_rtsp_video_send_track(ISrsRtspConnection *session, SrsRtcTrackDescription *track_desc);
|
||||
#endif
|
||||
virtual ISrsFlvTransmuxer *create_flv_transmuxer();
|
||||
virtual ISrsMp4Encoder *create_mp4_encoder();
|
||||
virtual ISrsDvrSegmenter *create_dvr_flv_segmenter();
|
||||
virtual ISrsDvrSegmenter *create_dvr_mp4_segmenter();
|
||||
};
|
||||
|
||||
// Mock ISrsDvrSegmenter for testing SrsDvrPlan
|
||||
class MockDvrSegmenter : public ISrsDvrSegmenter
|
||||
{
|
||||
public:
|
||||
bool write_metadata_called_;
|
||||
bool write_audio_called_;
|
||||
bool write_video_called_;
|
||||
SrsFragment *fragment_;
|
||||
|
||||
public:
|
||||
MockDvrSegmenter();
|
||||
virtual void assemble();
|
||||
virtual ~MockDvrSegmenter();
|
||||
|
||||
public:
|
||||
virtual srs_error_t initialize(ISrsDvrPlan *p, ISrsRequest *r);
|
||||
virtual SrsFragment *current();
|
||||
virtual srs_error_t open();
|
||||
virtual srs_error_t write_metadata(SrsMediaPacket *metadata);
|
||||
virtual srs_error_t write_audio(SrsMediaPacket *shared_audio, SrsFormat *format);
|
||||
virtual srs_error_t write_video(SrsMediaPacket *shared_video, SrsFormat *format);
|
||||
virtual srs_error_t close();
|
||||
};
|
||||
|
||||
// Mock ISrsOriginHub for testing SrsDvrSegmentPlan
|
||||
class MockOriginHubForDvrSegmentPlan : public ISrsOriginHub
|
||||
{
|
||||
public:
|
||||
int on_dvr_request_sh_count_;
|
||||
srs_error_t on_dvr_request_sh_error_;
|
||||
|
||||
public:
|
||||
MockOriginHubForDvrSegmentPlan();
|
||||
virtual ~MockOriginHubForDvrSegmentPlan();
|
||||
|
||||
public:
|
||||
virtual srs_error_t initialize(SrsSharedPtr<SrsLiveSource> s, ISrsRequest *r);
|
||||
virtual void dispose();
|
||||
virtual srs_error_t cycle();
|
||||
virtual bool active();
|
||||
virtual srs_utime_t cleanup_delay();
|
||||
virtual srs_error_t on_meta_data(SrsMediaPacket *shared_metadata, SrsOnMetaDataPacket *packet);
|
||||
virtual srs_error_t on_audio(SrsMediaPacket *shared_audio);
|
||||
virtual srs_error_t on_video(SrsMediaPacket *shared_video, bool is_sequence_header);
|
||||
virtual srs_error_t on_publish();
|
||||
virtual void on_unpublish();
|
||||
virtual srs_error_t on_dvr_request_sh();
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -2195,6 +2195,11 @@ SrsConfDirective *MockAppConfig::get_vhost_on_unpublish(std::string vhost)
|
|||
return on_unpublish_directive_;
|
||||
}
|
||||
|
||||
SrsConfDirective *MockAppConfig::get_vhost_on_dvr(std::string vhost)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bool MockAppConfig::get_rtc_nack_enabled(std::string vhost)
|
||||
{
|
||||
return rtc_nack_enabled_;
|
||||
|
|
|
|||
|
|
@ -337,6 +337,7 @@ public:
|
|||
virtual bool get_vhost_http_hooks_enabled(std::string vhost);
|
||||
virtual SrsConfDirective *get_vhost_on_stop(std::string vhost);
|
||||
virtual SrsConfDirective *get_vhost_on_unpublish(std::string vhost);
|
||||
virtual SrsConfDirective *get_vhost_on_dvr(std::string vhost);
|
||||
virtual bool get_rtc_nack_enabled(std::string vhost);
|
||||
virtual bool get_rtc_nack_no_copy(std::string vhost);
|
||||
virtual bool get_realtime_enabled(std::string vhost, bool is_rtc);
|
||||
|
|
@ -391,6 +392,14 @@ public:
|
|||
virtual bool get_atc_auto(std::string vhost);
|
||||
virtual bool get_reduce_sequence_header(std::string vhost);
|
||||
virtual bool get_parse_sps(std::string vhost);
|
||||
// DVR methods
|
||||
virtual std::string get_dvr_path(std::string vhost) { return "./[vhost]/[app]/[stream]/[2006]/[01]/[02]/[15].[04].[05].[999].flv"; }
|
||||
virtual std::string get_dvr_plan(std::string vhost) { return "session"; }
|
||||
virtual bool get_dvr_enabled(std::string vhost) { return false; }
|
||||
virtual SrsConfDirective *get_dvr_apply(std::string vhost) { return NULL; }
|
||||
virtual srs_utime_t get_dvr_duration(std::string vhost) { return 30 * SRS_UTIME_SECONDS; }
|
||||
virtual int get_dvr_time_jitter(std::string vhost) { return 0; }
|
||||
virtual bool get_dvr_wait_keyframe(std::string vhost) { return true; }
|
||||
virtual bool get_vhost_enabled(SrsConfDirective *conf) { return true; }
|
||||
virtual bool get_vhost_http_remux_enabled(std::string vhost) { return false; }
|
||||
virtual bool get_vhost_http_remux_enabled(SrsConfDirective *vhost) { return false; }
|
||||
|
|
|
|||
|
|
@ -1457,12 +1457,16 @@ MockDvrForOriginHub::MockDvrForOriginHub()
|
|||
on_video_count_ = 0;
|
||||
}
|
||||
|
||||
void MockDvrForOriginHub::assemble()
|
||||
{
|
||||
}
|
||||
|
||||
MockDvrForOriginHub::~MockDvrForOriginHub()
|
||||
{
|
||||
srs_freep(initialize_error_);
|
||||
}
|
||||
|
||||
srs_error_t MockDvrForOriginHub::initialize(SrsOriginHub *h, ISrsRequest *r)
|
||||
srs_error_t MockDvrForOriginHub::initialize(ISrsOriginHub *h, ISrsRequest *r)
|
||||
{
|
||||
initialize_count_++;
|
||||
return srs_error_copy(initialize_error_);
|
||||
|
|
@ -3016,6 +3020,11 @@ void MockOriginHubForLiveSource::on_unpublish()
|
|||
{
|
||||
}
|
||||
|
||||
srs_error_t MockOriginHubForLiveSource::on_dvr_request_sh()
|
||||
{
|
||||
return srs_success;
|
||||
}
|
||||
|
||||
MockAppFactoryForLiveSource::MockAppFactoryForLiveSource()
|
||||
{
|
||||
mock_hub_ = new MockOriginHubForLiveSource();
|
||||
|
|
|
|||
|
|
@ -137,8 +137,9 @@ public:
|
|||
|
||||
public:
|
||||
MockDvrForOriginHub();
|
||||
virtual void assemble();
|
||||
virtual ~MockDvrForOriginHub();
|
||||
virtual srs_error_t initialize(SrsOriginHub *h, ISrsRequest *r);
|
||||
virtual srs_error_t initialize(ISrsOriginHub *h, ISrsRequest *r);
|
||||
virtual srs_error_t on_publish(ISrsRequest *r);
|
||||
virtual void on_unpublish();
|
||||
virtual srs_error_t on_meta_data(SrsMediaPacket *metadata);
|
||||
|
|
@ -336,6 +337,7 @@ public:
|
|||
virtual srs_error_t on_video(SrsMediaPacket *shared_video, bool is_sequence_header);
|
||||
virtual srs_error_t on_publish();
|
||||
virtual void on_unpublish();
|
||||
virtual srs_error_t on_dvr_request_sh();
|
||||
};
|
||||
|
||||
// Mock ISrsAppFactory for testing SrsLiveSource::initialize
|
||||
|
|
|
|||
|
|
@ -150,6 +150,12 @@ void MockSrsFileWriter::close()
|
|||
uf->close();
|
||||
}
|
||||
|
||||
srs_error_t MockSrsFileWriter::set_iobuf_size(int size)
|
||||
{
|
||||
// Mock implementation - just return success
|
||||
return srs_success;
|
||||
}
|
||||
|
||||
bool MockSrsFileWriter::is_open()
|
||||
{
|
||||
return opened;
|
||||
|
|
|
|||
|
|
@ -70,6 +70,7 @@ public:
|
|||
public:
|
||||
virtual srs_error_t open(std::string file);
|
||||
virtual void close();
|
||||
virtual srs_error_t set_iobuf_size(int size);
|
||||
|
||||
public:
|
||||
virtual bool is_open();
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user