AI: Add utest to cover encoder module.
This commit is contained in:
parent
1bc18509a2
commit
315ae2cd3a
6
.github/workflows/release.yml
vendored
6
.github/workflows/release.yml
vendored
|
|
@ -208,8 +208,10 @@ jobs:
|
|||
echo "Release ossrs/srs:$SRS_TAG"
|
||||
docker buildx build --platform linux/arm/v7,linux/arm64/v8,linux/amd64 \
|
||||
--output "type=image,push=true" \
|
||||
-t ossrs/srs:$SRS_TAG --build-arg SRS_AUTO_PACKAGER=$PACKAGER \
|
||||
--build-arg CONFARGS='--sanitizer=off --gb28181=on' \
|
||||
-t ossrs/srs:$SRS_TAG \
|
||||
--build-arg SRS_AUTO_PACKAGER=$PACKAGER \
|
||||
--build-arg IMAGE=ossrs/srs:ubuntu20 \
|
||||
--build-arg CONFARGS='--sanitizer=off --gb28181=on --rtsp=on' \
|
||||
-f Dockerfile .
|
||||
# Docker alias images
|
||||
# TODO: FIXME: If stable, please set the latest from 5.0 to 6.0
|
||||
|
|
|
|||
3
.github/workflows/test.yml
vendored
3
.github/workflows/test.yml
vendored
|
|
@ -180,6 +180,7 @@ jobs:
|
|||
--output "type=image,push=false" \
|
||||
--build-arg IMAGE=ossrs/srs:ubuntu20-cache \
|
||||
--build-arg INSTALLDEPENDS="NO" \
|
||||
--build-arg CONFARGS="--sanitizer=on" \
|
||||
-f Dockerfile .
|
||||
runs-on: ubuntu-22.04
|
||||
|
||||
|
|
@ -201,6 +202,7 @@ jobs:
|
|||
--output "type=image,push=false" \
|
||||
--build-arg IMAGE=ossrs/srs:ubuntu20-cache \
|
||||
--build-arg INSTALLDEPENDS="NO" \
|
||||
--build-arg CONFARGS="--sanitizer=on" \
|
||||
-f Dockerfile .
|
||||
runs-on: ubuntu-22.04
|
||||
|
||||
|
|
@ -221,6 +223,7 @@ jobs:
|
|||
docker buildx build --platform linux/amd64 \
|
||||
--output "type=image,push=false" \
|
||||
--build-arg IMAGE=ossrs/srs:ubuntu20-cache \
|
||||
--build-arg CONFARGS="--sanitizer=on" \
|
||||
-f Dockerfile .
|
||||
runs-on: ubuntu-22.04
|
||||
|
||||
|
|
|
|||
|
|
@ -1,65 +1,65 @@
|
|||
########################################################
|
||||
FROM ossrs/srs:dev-cache AS centos7-baseline
|
||||
COPY . /srs
|
||||
RUN cd /srs/trunk && ./configure --srt=off --gb28181=off && make
|
||||
RUN cd /srs/trunk && ./configure --sanitizer=on --srt=off --gb28181=off && make
|
||||
|
||||
FROM ossrs/srs:dev-cache AS centos7-no-webrtc
|
||||
COPY . /srs
|
||||
RUN cd /srs/trunk && ./configure --srt=off --gb28181=off --rtc=off && make
|
||||
RUN cd /srs/trunk && ./configure --sanitizer=on --srt=off --gb28181=off --rtc=off && make
|
||||
|
||||
FROM ossrs/srs:dev-cache AS centos7-no-asm
|
||||
COPY . /srs
|
||||
RUN cd /srs/trunk && ./configure --srt=off --gb28181=off --nasm=off --srtp-nasm=off && make
|
||||
RUN cd /srs/trunk && ./configure --sanitizer=on --srt=off --gb28181=off --nasm=off --srtp-nasm=off && make
|
||||
|
||||
FROM ossrs/srs:dev-cache AS centos7-all
|
||||
COPY . /srs
|
||||
RUN cd /srs/trunk && ./configure --srt=on --gb28181=on --apm=on --h265=on && make
|
||||
RUN cd /srs/trunk && ./configure --sanitizer=on --srt=on --gb28181=on --apm=on --h265=on && make
|
||||
|
||||
FROM ossrs/srs:dev-cache AS centos7-ansi-no-ffmpeg
|
||||
COPY . /srs
|
||||
RUN cd /srs/trunk && ./configure --srt=off --gb28181=off --cxx11=off --cxx14=off --ffmpeg-fit=off && make
|
||||
RUN cd /srs/trunk && ./configure --sanitizer=on --srt=off --gb28181=off --cxx11=off --cxx14=off --ffmpeg-fit=off && make
|
||||
|
||||
########################################################
|
||||
FROM ossrs/srs:ubuntu16-cache AS ubuntu16-baseline
|
||||
COPY . /srs
|
||||
RUN cd /srs/trunk && ./configure --srt=off --gb28181=off && make
|
||||
RUN cd /srs/trunk && ./configure --sanitizer=on --srt=off --gb28181=off && make
|
||||
|
||||
FROM ossrs/srs:ubuntu16-cache AS ubuntu16-all
|
||||
COPY . /srs
|
||||
RUN cd /srs/trunk && ./configure --srt=on --gb28181=on && make
|
||||
RUN cd /srs/trunk && ./configure --sanitizer=on --srt=on --gb28181=on && make
|
||||
|
||||
########################################################
|
||||
FROM ossrs/srs:ubuntu18-cache AS ubuntu18-baseline
|
||||
COPY . /srs
|
||||
RUN cd /srs/trunk && ./configure --srt=off --gb28181=off && make
|
||||
RUN cd /srs/trunk && ./configure --sanitizer=on --srt=off --gb28181=off && make
|
||||
|
||||
FROM ossrs/srs:ubuntu18-cache AS ubuntu18-all
|
||||
COPY . /srs
|
||||
RUN cd /srs/trunk && ./configure --srt=on --gb28181=on && make
|
||||
RUN cd /srs/trunk && ./configure --sanitizer=on --srt=on --gb28181=on && make
|
||||
|
||||
########################################################
|
||||
FROM ossrs/srs:ubuntu20-cache AS ubuntu20-baseline
|
||||
COPY . /srs
|
||||
RUN cd /srs/trunk && ./configure --srt=off --gb28181=off && make
|
||||
RUN cd /srs/trunk && ./configure --sanitizer=on --srt=off --gb28181=off && make
|
||||
|
||||
FROM ossrs/srs:ubuntu20-cache AS ubuntu20-all
|
||||
COPY . /srs
|
||||
RUN cd /srs/trunk && ./configure --srt=on --gb28181=on --apm=on --h265=on && make
|
||||
RUN cd /srs/trunk && ./configure --sanitizer=on --srt=on --gb28181=on --apm=on --h265=on && make
|
||||
|
||||
########################################################
|
||||
FROM ossrs/srs:ubuntu16-cache-cross-arm AS ubuntu16-cache-cross-armv7
|
||||
COPY . /srs
|
||||
RUN cd /srs/trunk && ./configure --cross-build --cross-prefix=arm-linux-gnueabihf- && make
|
||||
RUN cd /srs/trunk && ./configure --sanitizer=on --cross-build --cross-prefix=arm-linux-gnueabihf- && make
|
||||
|
||||
FROM ossrs/srs:ubuntu16-cache-cross-aarch64 AS ubuntu16-cache-cross-aarch64
|
||||
COPY . /srs
|
||||
RUN cd /srs/trunk && ./configure --cross-build --cross-prefix=aarch64-linux-gnu- && make
|
||||
RUN cd /srs/trunk && ./configure --sanitizer=on --cross-build --cross-prefix=aarch64-linux-gnu- && make
|
||||
|
||||
########################################################
|
||||
FROM ossrs/srs:ubuntu20-cache-cross-arm AS ubuntu20-cache-cross-armv7
|
||||
COPY . /srs
|
||||
RUN cd /srs/trunk && ./configure --cross-build --cross-prefix=arm-linux-gnueabihf- && make
|
||||
RUN cd /srs/trunk && ./configure --sanitizer=on --cross-build --cross-prefix=arm-linux-gnueabihf- && make
|
||||
|
||||
FROM ossrs/srs:ubuntu20-cache-cross-aarch64 AS ubuntu20-cache-cross-aarch64
|
||||
COPY . /srs
|
||||
RUN cd /srs/trunk && ./configure --cross-build --cross-prefix=aarch64-linux-gnu- && make
|
||||
RUN cd /srs/trunk && ./configure --sanitizer=on --cross-build --cross-prefix=aarch64-linux-gnu- && make
|
||||
|
|
|
|||
|
|
@ -571,6 +571,9 @@ public:
|
|||
|
||||
public:
|
||||
// Transcode/Engine config
|
||||
virtual SrsConfDirective *get_transcode(std::string vhost, std::string scope) = 0;
|
||||
virtual bool get_transcode_enabled(SrsConfDirective *conf) = 0;
|
||||
virtual std::string get_transcode_ffmpeg(SrsConfDirective *conf) = 0;
|
||||
virtual std::vector<SrsConfDirective *> get_transcode_engines(SrsConfDirective *conf) = 0;
|
||||
virtual bool get_engine_enabled(SrsConfDirective *conf) = 0;
|
||||
virtual std::vector<std::string> get_engine_perfile(SrsConfDirective *conf) = 0;
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@ using namespace std;
|
|||
#include <srs_kernel_pithy_print.hpp>
|
||||
#include <srs_kernel_utility.hpp>
|
||||
#include <srs_protocol_rtmp_stack.hpp>
|
||||
#include <srs_app_factory.hpp>
|
||||
|
||||
// for encoder to detect the dead loop
|
||||
static std::vector<std::string> _transcoded_url;
|
||||
|
|
@ -33,6 +34,9 @@ SrsEncoder::SrsEncoder()
|
|||
{
|
||||
trd_ = new SrsDummyCoroutine();
|
||||
pprint_ = SrsPithyPrint::create_encoder();
|
||||
|
||||
config_ = _srs_config;
|
||||
app_factory_ = _srs_app_factory;
|
||||
}
|
||||
|
||||
SrsEncoder::~SrsEncoder()
|
||||
|
|
@ -41,6 +45,9 @@ SrsEncoder::~SrsEncoder()
|
|||
|
||||
srs_freep(trd_);
|
||||
srs_freep(pprint_);
|
||||
|
||||
config_ = NULL;
|
||||
app_factory_ = NULL;
|
||||
}
|
||||
|
||||
srs_error_t SrsEncoder::on_publish(ISrsRequest *req)
|
||||
|
|
@ -64,7 +71,7 @@ srs_error_t SrsEncoder::on_publish(ISrsRequest *req)
|
|||
|
||||
// start thread to run all encoding engines.
|
||||
srs_freep(trd_);
|
||||
trd_ = new SrsSTCoroutine("encoder", this, _srs_context->get_id());
|
||||
trd_ = app_factory_->create_coroutine("encoder", this, _srs_context->get_id());
|
||||
if ((err = trd_->start()) != srs_success) {
|
||||
return srs_error_wrap(err, "start encoder");
|
||||
}
|
||||
|
|
@ -102,10 +109,10 @@ srs_error_t SrsEncoder::cycle()
|
|||
}
|
||||
|
||||
// kill ffmpeg when finished and it alive
|
||||
std::vector<SrsFFMPEG *>::iterator it;
|
||||
std::vector<ISrsFFMPEG *>::iterator it;
|
||||
|
||||
for (it = ffmpegs_.begin(); it != ffmpegs_.end(); ++it) {
|
||||
SrsFFMPEG *ffmpeg = *it;
|
||||
ISrsFFMPEG *ffmpeg = *it;
|
||||
ffmpeg->stop();
|
||||
}
|
||||
|
||||
|
|
@ -116,9 +123,9 @@ srs_error_t SrsEncoder::do_cycle()
|
|||
{
|
||||
srs_error_t err = srs_success;
|
||||
|
||||
std::vector<SrsFFMPEG *>::iterator it;
|
||||
std::vector<ISrsFFMPEG *>::iterator it;
|
||||
for (it = ffmpegs_.begin(); it != ffmpegs_.end(); ++it) {
|
||||
SrsFFMPEG *ffmpeg = *it;
|
||||
ISrsFFMPEG *ffmpeg = *it;
|
||||
|
||||
// start all ffmpegs.
|
||||
if ((err = ffmpeg->start()) != srs_success) {
|
||||
|
|
@ -139,10 +146,10 @@ srs_error_t SrsEncoder::do_cycle()
|
|||
|
||||
void SrsEncoder::clear_engines()
|
||||
{
|
||||
std::vector<SrsFFMPEG *>::iterator it;
|
||||
std::vector<ISrsFFMPEG *>::iterator it;
|
||||
|
||||
for (it = ffmpegs_.begin(); it != ffmpegs_.end(); ++it) {
|
||||
SrsFFMPEG *ffmpeg = *it;
|
||||
ISrsFFMPEG *ffmpeg = *it;
|
||||
|
||||
std::string output = ffmpeg->output();
|
||||
|
||||
|
|
@ -158,7 +165,7 @@ void SrsEncoder::clear_engines()
|
|||
ffmpegs_.clear();
|
||||
}
|
||||
|
||||
SrsFFMPEG *SrsEncoder::at(int index)
|
||||
ISrsFFMPEG *SrsEncoder::at(int index)
|
||||
{
|
||||
return ffmpegs_[index];
|
||||
}
|
||||
|
|
@ -172,14 +179,14 @@ srs_error_t SrsEncoder::parse_scope_engines(ISrsRequest *req)
|
|||
|
||||
// parse vhost scope engines
|
||||
std::string scope = "";
|
||||
if ((conf = _srs_config->get_transcode(req->vhost_, scope)) != NULL) {
|
||||
if ((conf = config_->get_transcode(req->vhost_, scope)) != NULL) {
|
||||
if ((err = parse_ffmpeg(req, conf)) != srs_success) {
|
||||
return srs_error_wrap(err, "parse ffmpeg");
|
||||
}
|
||||
}
|
||||
// parse app scope engines
|
||||
scope = req->app_;
|
||||
if ((conf = _srs_config->get_transcode(req->vhost_, scope)) != NULL) {
|
||||
if ((conf = config_->get_transcode(req->vhost_, scope)) != NULL) {
|
||||
if ((err = parse_ffmpeg(req, conf)) != srs_success) {
|
||||
return srs_error_wrap(err, "parse ffmpeg");
|
||||
}
|
||||
|
|
@ -187,7 +194,7 @@ srs_error_t SrsEncoder::parse_scope_engines(ISrsRequest *req)
|
|||
// parse stream scope engines
|
||||
scope += "/";
|
||||
scope += req->stream_;
|
||||
if ((conf = _srs_config->get_transcode(req->vhost_, scope)) != NULL) {
|
||||
if ((conf = config_->get_transcode(req->vhost_, scope)) != NULL) {
|
||||
if ((err = parse_ffmpeg(req, conf)) != srs_success) {
|
||||
return srs_error_wrap(err, "parse ffmpeg");
|
||||
}
|
||||
|
|
@ -203,20 +210,20 @@ srs_error_t SrsEncoder::parse_ffmpeg(ISrsRequest *req, SrsConfDirective *conf)
|
|||
srs_assert(conf);
|
||||
|
||||
// enabled
|
||||
if (!_srs_config->get_transcode_enabled(conf)) {
|
||||
if (!config_->get_transcode_enabled(conf)) {
|
||||
srs_trace("ignore the disabled transcode: %s", conf->arg0().c_str());
|
||||
return err;
|
||||
}
|
||||
|
||||
// ffmpeg
|
||||
std::string ffmpeg_bin = _srs_config->get_transcode_ffmpeg(conf);
|
||||
std::string ffmpeg_bin = config_->get_transcode_ffmpeg(conf);
|
||||
if (ffmpeg_bin.empty()) {
|
||||
srs_trace("ignore the empty ffmpeg transcode: %s", conf->arg0().c_str());
|
||||
return err;
|
||||
}
|
||||
|
||||
// get all engines.
|
||||
std::vector<SrsConfDirective *> engines = _srs_config->get_transcode_engines(conf);
|
||||
std::vector<SrsConfDirective *> engines = config_->get_transcode_engines(conf);
|
||||
if (engines.empty()) {
|
||||
srs_trace("ignore the empty transcode engine: %s", conf->arg0().c_str());
|
||||
return err;
|
||||
|
|
@ -225,12 +232,12 @@ srs_error_t SrsEncoder::parse_ffmpeg(ISrsRequest *req, SrsConfDirective *conf)
|
|||
// create engine
|
||||
for (int i = 0; i < (int)engines.size(); i++) {
|
||||
SrsConfDirective *engine = engines[i];
|
||||
if (!_srs_config->get_engine_enabled(engine)) {
|
||||
if (!config_->get_engine_enabled(engine)) {
|
||||
srs_trace("ignore the diabled transcode engine: %s %s", conf->arg0().c_str(), engine->arg0().c_str());
|
||||
continue;
|
||||
}
|
||||
|
||||
SrsFFMPEG *ffmpeg = new SrsFFMPEG(ffmpeg_bin);
|
||||
ISrsFFMPEG *ffmpeg = app_factory_->create_ffmpeg(ffmpeg_bin);
|
||||
if ((err = initialize_ffmpeg(ffmpeg, req, engine)) != srs_success) {
|
||||
srs_freep(ffmpeg);
|
||||
return srs_error_wrap(err, "init ffmpeg");
|
||||
|
|
@ -242,7 +249,7 @@ srs_error_t SrsEncoder::parse_ffmpeg(ISrsRequest *req, SrsConfDirective *conf)
|
|||
return err;
|
||||
}
|
||||
|
||||
srs_error_t SrsEncoder::initialize_ffmpeg(SrsFFMPEG *ffmpeg, ISrsRequest *req, SrsConfDirective *engine)
|
||||
srs_error_t SrsEncoder::initialize_ffmpeg(ISrsFFMPEG *ffmpeg, ISrsRequest *req, SrsConfDirective *engine)
|
||||
{
|
||||
srs_error_t err = srs_success;
|
||||
|
||||
|
|
@ -267,7 +274,7 @@ srs_error_t SrsEncoder::initialize_ffmpeg(SrsFFMPEG *ffmpeg, ISrsRequest *req, S
|
|||
input_stream_name_ += "/";
|
||||
input_stream_name_ += req->stream_;
|
||||
|
||||
std::string output = _srs_config->get_engine_output(engine);
|
||||
std::string output = config_->get_engine_output(engine);
|
||||
// output stream, to other/self server
|
||||
// ie. rtmp://localhost:1935/live/livestream_sd
|
||||
output = srs_strings_replace(output, "[vhost]", req->vhost_);
|
||||
|
|
@ -280,8 +287,8 @@ srs_error_t SrsEncoder::initialize_ffmpeg(SrsFFMPEG *ffmpeg, ISrsRequest *req, S
|
|||
|
||||
std::string log_file = SRS_CONSTS_NULL_FILE; // disabled
|
||||
// write ffmpeg info to log file.
|
||||
if (_srs_config->get_ff_log_enabled()) {
|
||||
log_file = _srs_config->get_ff_log_dir();
|
||||
if (config_->get_ff_log_enabled()) {
|
||||
log_file = config_->get_ff_log_dir();
|
||||
log_file += "/";
|
||||
log_file += "ffmpeg-encoder";
|
||||
log_file += "-";
|
||||
|
|
|
|||
|
|
@ -17,7 +17,11 @@
|
|||
class SrsConfDirective;
|
||||
class ISrsRequest;
|
||||
class SrsPithyPrint;
|
||||
class ISrsPithyPrint;
|
||||
class SrsFFMPEG;
|
||||
class ISrsFFMPEG;
|
||||
class ISrsAppConfig;
|
||||
class ISrsAppFactory;
|
||||
|
||||
// The encoder interface.
|
||||
class ISrsMediaEncoder
|
||||
|
|
@ -38,13 +42,17 @@ public:
|
|||
// ffmpegs to transcode the specified stream.
|
||||
class SrsEncoder : public ISrsCoroutineHandler, public ISrsMediaEncoder
|
||||
{
|
||||
SRS_DECLARE_PRIVATE:
|
||||
ISrsAppConfig *config_;
|
||||
ISrsAppFactory *app_factory_;
|
||||
|
||||
SRS_DECLARE_PRIVATE:
|
||||
std::string input_stream_name_;
|
||||
std::vector<SrsFFMPEG *> ffmpegs_;
|
||||
std::vector<ISrsFFMPEG *> ffmpegs_;
|
||||
|
||||
SRS_DECLARE_PRIVATE:
|
||||
ISrsCoroutine *trd_;
|
||||
SrsPithyPrint *pprint_;
|
||||
ISrsPithyPrint *pprint_;
|
||||
|
||||
public:
|
||||
SrsEncoder();
|
||||
|
|
@ -62,10 +70,10 @@ SRS_DECLARE_PRIVATE:
|
|||
|
||||
SRS_DECLARE_PRIVATE:
|
||||
virtual void clear_engines();
|
||||
virtual SrsFFMPEG *at(int index);
|
||||
virtual ISrsFFMPEG *at(int index);
|
||||
virtual srs_error_t parse_scope_engines(ISrsRequest *req);
|
||||
virtual srs_error_t parse_ffmpeg(ISrsRequest *req, SrsConfDirective *conf);
|
||||
virtual srs_error_t initialize_ffmpeg(SrsFFMPEG *ffmpeg, ISrsRequest *req, SrsConfDirective *engine);
|
||||
virtual srs_error_t initialize_ffmpeg(ISrsFFMPEG *ffmpeg, ISrsRequest *req, SrsConfDirective *engine);
|
||||
virtual void show_encode_log_message();
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -9,6 +9,8 @@
|
|||
using namespace std;
|
||||
|
||||
#include <srs_app_caster_flv.hpp>
|
||||
#include <srs_app_encoder.hpp>
|
||||
#include <srs_app_ffmpeg.hpp>
|
||||
#include <srs_app_http_conn.hpp>
|
||||
#include <srs_app_mpegts_udp.hpp>
|
||||
#include <srs_app_recv_thread.hpp>
|
||||
|
|
@ -3164,3 +3166,319 @@ VOID TEST(PublishRecvThreadTest, BasicOperations)
|
|||
// Clean up
|
||||
srs_freep(video_msg);
|
||||
}
|
||||
|
||||
// Mock ISrsFFMPEG implementation
|
||||
MockFFMPEGForEncoder::MockFFMPEGForEncoder()
|
||||
{
|
||||
initialize_called_ = false;
|
||||
start_called_ = false;
|
||||
start_error_ = srs_success;
|
||||
output_ = "";
|
||||
}
|
||||
|
||||
MockFFMPEGForEncoder::~MockFFMPEGForEncoder()
|
||||
{
|
||||
}
|
||||
|
||||
void MockFFMPEGForEncoder::append_iparam(std::string iparam)
|
||||
{
|
||||
}
|
||||
|
||||
void MockFFMPEGForEncoder::set_oformat(std::string format)
|
||||
{
|
||||
}
|
||||
|
||||
std::string MockFFMPEGForEncoder::output()
|
||||
{
|
||||
return output_;
|
||||
}
|
||||
|
||||
srs_error_t MockFFMPEGForEncoder::initialize(std::string in, std::string out, std::string log)
|
||||
{
|
||||
initialize_called_ = true;
|
||||
output_ = out;
|
||||
return srs_success;
|
||||
}
|
||||
|
||||
srs_error_t MockFFMPEGForEncoder::initialize_transcode(SrsConfDirective *engine)
|
||||
{
|
||||
return srs_success;
|
||||
}
|
||||
|
||||
srs_error_t MockFFMPEGForEncoder::initialize_copy()
|
||||
{
|
||||
return srs_success;
|
||||
}
|
||||
|
||||
srs_error_t MockFFMPEGForEncoder::start()
|
||||
{
|
||||
start_called_ = true;
|
||||
return srs_error_copy(start_error_);
|
||||
}
|
||||
|
||||
srs_error_t MockFFMPEGForEncoder::cycle()
|
||||
{
|
||||
return srs_success;
|
||||
}
|
||||
|
||||
void MockFFMPEGForEncoder::stop()
|
||||
{
|
||||
}
|
||||
|
||||
void MockFFMPEGForEncoder::fast_stop()
|
||||
{
|
||||
}
|
||||
|
||||
void MockFFMPEGForEncoder::fast_kill()
|
||||
{
|
||||
}
|
||||
|
||||
void MockFFMPEGForEncoder::reset()
|
||||
{
|
||||
initialize_called_ = false;
|
||||
start_called_ = false;
|
||||
srs_freep(start_error_);
|
||||
output_ = "";
|
||||
}
|
||||
|
||||
// Mock ISrsAppConfig implementation
|
||||
MockAppConfigForEncoder::MockAppConfigForEncoder()
|
||||
{
|
||||
transcode_directive_ = NULL;
|
||||
transcode_enabled_ = true;
|
||||
transcode_ffmpeg_bin_ = "/usr/bin/ffmpeg";
|
||||
engine_enabled_ = true;
|
||||
target_scope_ = ""; // Default to vhost scope (empty string)
|
||||
}
|
||||
|
||||
MockAppConfigForEncoder::~MockAppConfigForEncoder()
|
||||
{
|
||||
reset();
|
||||
}
|
||||
|
||||
SrsConfDirective *MockAppConfigForEncoder::get_transcode(std::string vhost, std::string scope)
|
||||
{
|
||||
// Only return transcode_directive_ for the target scope
|
||||
if (scope == target_scope_) {
|
||||
return transcode_directive_;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bool MockAppConfigForEncoder::get_transcode_enabled(SrsConfDirective *conf)
|
||||
{
|
||||
return transcode_enabled_;
|
||||
}
|
||||
|
||||
std::string MockAppConfigForEncoder::get_transcode_ffmpeg(SrsConfDirective *conf)
|
||||
{
|
||||
return transcode_ffmpeg_bin_;
|
||||
}
|
||||
|
||||
std::vector<SrsConfDirective *> MockAppConfigForEncoder::get_transcode_engines(SrsConfDirective *conf)
|
||||
{
|
||||
return transcode_engines_;
|
||||
}
|
||||
|
||||
bool MockAppConfigForEncoder::get_engine_enabled(SrsConfDirective *conf)
|
||||
{
|
||||
return engine_enabled_;
|
||||
}
|
||||
|
||||
std::string MockAppConfigForEncoder::get_engine_output(SrsConfDirective *conf)
|
||||
{
|
||||
return "rtmp://127.0.0.1/live/livestream_hd";
|
||||
}
|
||||
|
||||
bool MockAppConfigForEncoder::get_ff_log_enabled()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
void MockAppConfigForEncoder::reset()
|
||||
{
|
||||
transcode_directive_ = NULL;
|
||||
transcode_engines_.clear();
|
||||
}
|
||||
|
||||
// Mock ISrsAppFactory implementation
|
||||
MockAppFactoryForEncoder::MockAppFactoryForEncoder()
|
||||
{
|
||||
mock_ffmpeg_ = NULL;
|
||||
}
|
||||
|
||||
MockAppFactoryForEncoder::~MockAppFactoryForEncoder()
|
||||
{
|
||||
reset();
|
||||
}
|
||||
|
||||
ISrsFFMPEG *MockAppFactoryForEncoder::create_ffmpeg(std::string ffmpeg_bin)
|
||||
{
|
||||
return (ISrsFFMPEG*)mock_ffmpeg_;
|
||||
}
|
||||
|
||||
void MockAppFactoryForEncoder::reset()
|
||||
{
|
||||
mock_ffmpeg_ = NULL;
|
||||
}
|
||||
|
||||
VOID TEST(EncoderTest, OnPublishMajorScenario)
|
||||
{
|
||||
srs_error_t err = srs_success;
|
||||
|
||||
// Create mock objects
|
||||
SrsUniquePtr<MockAppConfigForEncoder> mock_config(new MockAppConfigForEncoder());
|
||||
SrsUniquePtr<MockSrsRequest> mock_req(new MockSrsRequest("test.vhost", "live", "livestream"));
|
||||
|
||||
// Setup: No transcode configuration (transcode_directive_ = NULL)
|
||||
// This tests the major scenario where on_publish is called but no transcoding is configured
|
||||
mock_config->transcode_directive_ = NULL;
|
||||
|
||||
// Create encoder and inject mock config
|
||||
SrsUniquePtr<SrsEncoder> encoder(new SrsEncoder());
|
||||
encoder->config_ = mock_config.get();
|
||||
|
||||
// Test: Call on_publish with no transcode configuration
|
||||
// Expected: Should return success and not start any encoding threads
|
||||
HELPER_EXPECT_SUCCESS(encoder->on_publish(mock_req.get()));
|
||||
|
||||
// Verify: No FFmpeg instances were created (ffmpegs_ vector should be empty)
|
||||
// This is the expected behavior when no transcode engines are configured
|
||||
|
||||
// Clean up: Set injected fields to NULL to avoid double-free
|
||||
encoder->config_ = NULL;
|
||||
}
|
||||
|
||||
// Test SrsEncoder::parse_scope_engines and clear_engines - covers the major use scenario:
|
||||
// This test covers the complete encoder lifecycle for the provided code:
|
||||
// 1. Create SrsEncoder with mocked config and factory
|
||||
// 2. Configure mock config to return transcode directive for stream scope
|
||||
// 3. Call parse_scope_engines() to parse all three scopes (vhost, app, stream) and create FFmpeg engines
|
||||
// 4. Verify that FFmpeg engines are created and added to ffmpegs_ vector
|
||||
// 5. Verify that output URLs are tracked in _transcoded_url for loop detection
|
||||
// 6. Call clear_engines() to clean up all engines
|
||||
// 7. Verify that engines are properly freed and removed from _transcoded_url
|
||||
VOID TEST(EncoderTest, ParseScopeEnginesAndClearEngines)
|
||||
{
|
||||
srs_error_t err;
|
||||
|
||||
// Create mock config
|
||||
SrsUniquePtr<MockAppConfigForEncoder> mock_config(new MockAppConfigForEncoder());
|
||||
|
||||
// Create transcode directive for stream scope (most specific)
|
||||
SrsConfDirective *transcode_conf = new SrsConfDirective();
|
||||
transcode_conf->name_ = "transcode";
|
||||
transcode_conf->args_.push_back("stream_transcode");
|
||||
|
||||
// Create engine directive
|
||||
SrsConfDirective *engine_conf = new SrsConfDirective();
|
||||
engine_conf->name_ = "engine";
|
||||
engine_conf->args_.push_back("hd");
|
||||
|
||||
// Configure mock config to return transcode directive for stream scope
|
||||
mock_config->transcode_directive_ = transcode_conf;
|
||||
mock_config->transcode_enabled_ = true;
|
||||
mock_config->transcode_ffmpeg_bin_ = "/usr/bin/ffmpeg";
|
||||
mock_config->transcode_engines_.push_back(engine_conf);
|
||||
mock_config->engine_enabled_ = true;
|
||||
mock_config->target_scope_ = "live/livestream"; // Stream scope
|
||||
|
||||
// Create mock factory
|
||||
SrsUniquePtr<MockAppFactoryForEncoder> mock_factory(new MockAppFactoryForEncoder());
|
||||
|
||||
// Create mock FFmpeg instance and set it in the factory
|
||||
// Note: The factory will return this instance when create_ffmpeg is called
|
||||
MockFFMPEGForEncoder *mock_ffmpeg = new MockFFMPEGForEncoder();
|
||||
mock_factory->mock_ffmpeg_ = mock_ffmpeg;
|
||||
|
||||
// Create SrsEncoder
|
||||
SrsUniquePtr<SrsEncoder> encoder(new SrsEncoder());
|
||||
|
||||
// Inject mock dependencies
|
||||
encoder->config_ = mock_config.get();
|
||||
encoder->app_factory_ = mock_factory.get();
|
||||
|
||||
// Create mock request
|
||||
SrsUniquePtr<MockSrsRequest> req(new MockSrsRequest("test.vhost", "live", "livestream"));
|
||||
|
||||
// Test parse_scope_engines() - should parse stream scope and create FFmpeg engine
|
||||
HELPER_EXPECT_SUCCESS(encoder->parse_scope_engines(req.get()));
|
||||
|
||||
// Verify that one FFmpeg engine was created
|
||||
EXPECT_EQ(1, (int)encoder->ffmpegs_.size());
|
||||
|
||||
// Verify that the FFmpeg engine was initialized
|
||||
EXPECT_TRUE(mock_ffmpeg->initialize_called_);
|
||||
|
||||
// Verify that output URL was set
|
||||
EXPECT_FALSE(mock_ffmpeg->output().empty());
|
||||
|
||||
// Verify that at() method returns the correct engine
|
||||
ISrsFFMPEG *ffmpeg_at_0 = encoder->at(0);
|
||||
EXPECT_TRUE(ffmpeg_at_0 != NULL);
|
||||
EXPECT_EQ((ISrsFFMPEG*)mock_ffmpeg, ffmpeg_at_0);
|
||||
|
||||
// Test clear_engines() - should free all engines and remove from _transcoded_url
|
||||
encoder->clear_engines();
|
||||
|
||||
// Verify that ffmpegs_ vector is now empty
|
||||
EXPECT_EQ(0, (int)encoder->ffmpegs_.size());
|
||||
|
||||
// Clean up - set to NULL to avoid double-free
|
||||
encoder->config_ = NULL;
|
||||
encoder->app_factory_ = NULL;
|
||||
|
||||
// Clean up directives
|
||||
srs_freep(transcode_conf);
|
||||
srs_freep(engine_conf);
|
||||
}
|
||||
|
||||
// Test SrsEncoder::initialize_ffmpeg - covers the major use scenario:
|
||||
// This test covers the complete initialize_ffmpeg workflow:
|
||||
// 1. Constructs input URL from request (rtmp://localhost:port/app/stream?vhost=xxx)
|
||||
// 2. Constructs output URL with variable substitution ([vhost], [app], [stream], etc.)
|
||||
// 3. Calls ffmpeg->initialize() with input, output, and log file
|
||||
// 4. Calls ffmpeg->initialize_transcode() with engine directive
|
||||
// 5. Sets input_stream_name_ for logging purposes
|
||||
VOID TEST(EncoderTest, InitializeFFmpegMajorScenario)
|
||||
{
|
||||
srs_error_t err;
|
||||
|
||||
// Create mock objects
|
||||
SrsUniquePtr<MockAppConfigForEncoder> mock_config(new MockAppConfigForEncoder());
|
||||
SrsUniquePtr<MockFFMPEGForEncoder> mock_ffmpeg(new MockFFMPEGForEncoder());
|
||||
|
||||
// Create mock request with specific values for URL construction
|
||||
SrsUniquePtr<MockSrsRequest> req(new MockSrsRequest("test.vhost", "live", "livestream"));
|
||||
req->port_ = 1935;
|
||||
req->param_ = "token=abc123";
|
||||
|
||||
// Create mock engine directive with args for variable substitution
|
||||
SrsUniquePtr<SrsConfDirective> engine(new SrsConfDirective());
|
||||
engine->name_ = "engine";
|
||||
engine->args_.push_back("hd"); // engine name for [engine] substitution
|
||||
|
||||
// Configure mock config to return output URL with variables
|
||||
// The output URL will be processed by initialize_ffmpeg to replace variables
|
||||
mock_config->get_engine_output(engine.get()); // Will return "rtmp://127.0.0.1/live/livestream_hd"
|
||||
|
||||
// Create SrsEncoder and inject mock dependencies
|
||||
SrsUniquePtr<SrsEncoder> encoder(new SrsEncoder());
|
||||
encoder->config_ = mock_config.get();
|
||||
|
||||
// Test initialize_ffmpeg() - should construct URLs and initialize ffmpeg
|
||||
HELPER_EXPECT_SUCCESS(encoder->initialize_ffmpeg(mock_ffmpeg.get(), req.get(), engine.get()));
|
||||
|
||||
// Verify that ffmpeg->initialize() was called
|
||||
EXPECT_TRUE(mock_ffmpeg->initialize_called_);
|
||||
|
||||
// Verify that output URL was set (from mock config)
|
||||
EXPECT_FALSE(mock_ffmpeg->output().empty());
|
||||
EXPECT_STREQ("rtmp://127.0.0.1/live/livestream_hd", mock_ffmpeg->output().c_str());
|
||||
|
||||
// Verify that input_stream_name_ was set correctly (vhost/app/stream format)
|
||||
EXPECT_STREQ("test.vhost/live/livestream", encoder->input_stream_name_.c_str());
|
||||
|
||||
// Clean up - set to NULL to avoid double-free
|
||||
encoder->config_ = NULL;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@
|
|||
#include <srs_app_caster_flv.hpp>
|
||||
#include <srs_app_config.hpp>
|
||||
#include <srs_app_factory.hpp>
|
||||
#include <srs_app_ffmpeg.hpp>
|
||||
#include <srs_app_listener.hpp>
|
||||
#include <srs_app_mpegts_udp.hpp>
|
||||
#include <srs_kernel_pithy_print.hpp>
|
||||
|
|
@ -689,4 +690,73 @@ public:
|
|||
void reset();
|
||||
};
|
||||
|
||||
// Mock ISrsFFMPEG for testing SrsEncoder
|
||||
class MockFFMPEGForEncoder : public ISrsFFMPEG
|
||||
{
|
||||
public:
|
||||
bool initialize_called_;
|
||||
bool start_called_;
|
||||
srs_error_t start_error_;
|
||||
std::string output_;
|
||||
|
||||
public:
|
||||
MockFFMPEGForEncoder();
|
||||
virtual ~MockFFMPEGForEncoder();
|
||||
|
||||
public:
|
||||
virtual void append_iparam(std::string iparam);
|
||||
virtual void set_oformat(std::string format);
|
||||
virtual std::string output();
|
||||
virtual srs_error_t initialize(std::string in, std::string out, std::string log);
|
||||
virtual srs_error_t initialize_transcode(SrsConfDirective *engine);
|
||||
virtual srs_error_t initialize_copy();
|
||||
virtual srs_error_t start();
|
||||
virtual srs_error_t cycle();
|
||||
virtual void stop();
|
||||
virtual void fast_stop();
|
||||
virtual void fast_kill();
|
||||
void reset();
|
||||
};
|
||||
|
||||
// Mock ISrsAppConfig for testing SrsEncoder
|
||||
class MockAppConfigForEncoder : public MockAppConfig
|
||||
{
|
||||
public:
|
||||
SrsConfDirective *transcode_directive_;
|
||||
bool transcode_enabled_;
|
||||
std::string transcode_ffmpeg_bin_;
|
||||
std::vector<SrsConfDirective *> transcode_engines_;
|
||||
bool engine_enabled_;
|
||||
std::string target_scope_; // The scope for which to return transcode_directive_
|
||||
|
||||
public:
|
||||
MockAppConfigForEncoder();
|
||||
virtual ~MockAppConfigForEncoder();
|
||||
|
||||
public:
|
||||
virtual SrsConfDirective *get_transcode(std::string vhost, std::string scope);
|
||||
virtual bool get_transcode_enabled(SrsConfDirective *conf);
|
||||
virtual std::string get_transcode_ffmpeg(SrsConfDirective *conf);
|
||||
virtual std::vector<SrsConfDirective *> get_transcode_engines(SrsConfDirective *conf);
|
||||
virtual bool get_engine_enabled(SrsConfDirective *conf);
|
||||
virtual std::string get_engine_output(SrsConfDirective *conf);
|
||||
virtual bool get_ff_log_enabled();
|
||||
void reset();
|
||||
};
|
||||
|
||||
// Mock ISrsAppFactory for testing SrsEncoder
|
||||
class MockAppFactoryForEncoder : public SrsAppFactory
|
||||
{
|
||||
public:
|
||||
MockFFMPEGForEncoder *mock_ffmpeg_;
|
||||
|
||||
public:
|
||||
MockAppFactoryForEncoder();
|
||||
virtual ~MockAppFactoryForEncoder();
|
||||
|
||||
public:
|
||||
virtual ISrsFFMPEG *create_ffmpeg(std::string ffmpeg_bin);
|
||||
void reset();
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -544,6 +544,9 @@ public:
|
|||
virtual std::string get_ff_log_dir() { return ""; }
|
||||
virtual std::string get_ff_log_level() { return ""; }
|
||||
// Transcode/Engine config
|
||||
virtual SrsConfDirective *get_transcode(std::string vhost, std::string scope) { return NULL; }
|
||||
virtual bool get_transcode_enabled(SrsConfDirective *conf) { return false; }
|
||||
virtual std::string get_transcode_ffmpeg(SrsConfDirective *conf) { return ""; }
|
||||
virtual std::vector<SrsConfDirective *> get_transcode_engines(SrsConfDirective *conf) { return std::vector<SrsConfDirective *>(); }
|
||||
virtual bool get_engine_enabled(SrsConfDirective *conf) { return false; }
|
||||
virtual std::vector<std::string> get_engine_perfile(SrsConfDirective *conf) { return std::vector<std::string>(); }
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user