Skip to content

Commit

Permalink
fix: ‘LOAD’ command shows black #1390
Browse files Browse the repository at this point in the history
  • Loading branch information
Julusian committed Dec 22, 2023
1 parent b1ce759 commit 528389a
Show file tree
Hide file tree
Showing 5 changed files with 82 additions and 50 deletions.
1 change: 1 addition & 0 deletions src/core/producer/frame_producer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,7 @@ class destroy_producer_proxy : public frame_producer
draw_frame last_frame(const core::video_field field) override { return producer_->last_frame(field); }
draw_frame first_frame(const core::video_field field) override { return producer_->first_frame(field); }
core::monitor::state state() const override { return producer_->state(); }
bool is_ready() override { return producer_->is_ready(); }
};

spl::shared_ptr<core::frame_producer> create_destroy_proxy(spl::shared_ptr<core::frame_producer> producer)
Expand Down
17 changes: 11 additions & 6 deletions src/core/producer/frame_producer.h
Original file line number Diff line number Diff line change
Expand Up @@ -49,16 +49,13 @@ class frame_producer
uint32_t frame_number_ = 0;
core::draw_frame last_frame_;
core::draw_frame first_frame_;
bool is_ready_ = false;

public:
static const spl::shared_ptr<frame_producer>& empty();

frame_producer(core::draw_frame frame)
: last_frame_(std::move(frame))
{
}
frame_producer() {}
virtual ~frame_producer() {}
frame_producer() = default;
virtual ~frame_producer() = default;

draw_frame receive(const video_field field, int nb_samples)
{
Expand Down Expand Up @@ -110,6 +107,12 @@ class frame_producer
virtual void leading_producer(const spl::shared_ptr<frame_producer>&) {}
virtual spl::shared_ptr<frame_producer> following_producer() const { return core::frame_producer::empty(); }
virtual boost::optional<int64_t> auto_play_delta() const { return boost::none; }

/**
* Some producers take a couple of frames before they produce frames.
* While this returns false, the previous producer will be left running for a limited number of frames.
*/
virtual bool is_ready() { return !!first_frame_; };
};

class const_producer : public core::frame_producer
Expand Down Expand Up @@ -147,6 +150,8 @@ class const_producer : public core::frame_producer
static const monitor::state empty;
return empty;
}

bool is_ready() override { return true; }
};

class frame_producer_registry;
Expand Down
2 changes: 0 additions & 2 deletions src/core/producer/transition/sting_producer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,7 @@
#include "../../monitor/monitor.h"
#include "../frame_producer.h"

#include <common/param.h>
#include <common/scope_exit.h>
#include <protocol/amcp/amcp_args.h>

#include <future>

Expand Down
86 changes: 56 additions & 30 deletions src/core/producer/transition/transition_producer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -43,21 +43,37 @@ class transition_producer : public frame_producer

spl::shared_ptr<frame_producer> dst_producer_ = frame_producer::empty();
spl::shared_ptr<frame_producer> src_producer_ = frame_producer::empty();
bool dst_is_ready_ = false;

public:
transition_producer(const spl::shared_ptr<frame_producer>& dest, const transition_info& info)
: info_(info)
, dst_producer_(dest)
{
dst_is_ready_ = dst_producer_->is_ready();
update_state();
}

// frame_producer

void update_is_ready(const core::video_field field)
{
// Ensure a frame has been attempted
dst_producer_->first_frame(field);

dst_is_ready_ = dst_producer_->is_ready();
}

core::draw_frame last_frame(const core::video_field field) override
{
CASPAR_SCOPE_EXIT { update_state(); };

update_is_ready(field);

if (!dst_is_ready_) {
return src_producer_->last_frame(field);
}

auto src = src_producer_->last_frame(field);
auto dst = dst_producer_->last_frame(field);

Expand All @@ -70,38 +86,48 @@ class transition_producer : public frame_producer

spl::shared_ptr<frame_producer> following_producer() const override
{
return current_frame_ >= info_.duration ? dst_producer_ : core::frame_producer::empty();
return current_frame_ >= info_.duration && dst_is_ready_ ? dst_producer_ : core::frame_producer::empty();
}

boost::optional<int64_t> auto_play_delta() const override { return info_.duration; }

void update_state()
{
state_ = dst_producer_->state();
state_["transition/producer"] = dst_producer_->name();
state_["transition/frame"] = {current_frame_, info_.duration};
state_["transition/type"] = [&]() -> std::string {
switch (info_.type) {
case transition_type::mix:
return "mix";
case transition_type::wipe:
return "wipe";
case transition_type::slide:
return "slide";
case transition_type::push:
return "push";
case transition_type::cut:
return "cut";
default:
return "n/a";
}
}();
if (!dst_is_ready_) {
state_ = src_producer_->state();
} else {
state_ = dst_producer_->state();
state_["transition/producer"] = dst_producer_->name();
state_["transition/frame"] = {current_frame_, info_.duration};
state_["transition/type"] = [&]() -> std::string {
switch (info_.type) {
case transition_type::mix:
return "mix";
case transition_type::wipe:
return "wipe";
case transition_type::slide:
return "slide";
case transition_type::push:
return "push";
case transition_type::cut:
return "cut";
default:
return "n/a";
}
}();
}
}

draw_frame receive_impl(const core::video_field field, int nb_samples) override
{
CASPAR_SCOPE_EXIT { update_state(); };

update_is_ready(field);

if (!dst_is_ready_) {
return src_producer_->receive(field, nb_samples);
}

auto dst = dst_producer_->receive(field, nb_samples);
if (!dst) {
dst = dst_producer_->last_frame(field);
Expand Down Expand Up @@ -193,11 +219,15 @@ bool try_match_transition(const std::wstring& message, transition_info& transiti
return false;
}

auto transition = what["TRANSITION"].str();
transitionInfo.duration = std::stoi(what["DURATION"].str());
auto direction = what["DIRECTION"].matched ? what["DIRECTION"].str() : L"";
auto tween = what["TWEEN"].matched ? what["TWEEN"].str() : L"";
transitionInfo.tweener = tween;
if (transitionInfo.duration == 0) {
return false;
}

auto transition = what["TRANSITION"].str();
auto direction = what["DIRECTION"].matched ? what["DIRECTION"].str() : L"";
auto tween = what["TWEEN"].matched ? what["TWEEN"].str() : L"";
transitionInfo.tweener = tween;

if (transition == L"CUT")
transitionInfo.type = transition_type::cut;
Expand All @@ -210,14 +240,10 @@ bool try_match_transition(const std::wstring& message, transition_info& transiti
else if (transition == L"WIPE")
transitionInfo.type = transition_type::wipe;

if (direction == L"FROMLEFT")
if (direction == L"FROMLEFT" || direction == L"RIGHT")
transitionInfo.direction = transition_direction::from_left;
else if (direction == L"FROMRIGHT")
else if (direction == L"FROMRIGHT" || direction == L"LEFT")
transitionInfo.direction = transition_direction::from_right;
else if (direction == L"LEFT")
transitionInfo.direction = transition_direction::from_right;
else if (direction == L"RIGHT")
transitionInfo.direction = transition_direction::from_left;

return true;
}
Expand Down
26 changes: 14 additions & 12 deletions src/protocol/amcp/AMCPCommandsImpl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -282,26 +282,28 @@ std::wstring loadbg_command(command_context& ctx)
bool auto_play = contains_param(L"AUTO", ctx.parameters);

try {
auto pFP = ctx.static_context->producer_registry->create_producer(get_producer_dependencies(channel, ctx),
ctx.parameters);
auto new_producer = ctx.static_context->producer_registry->create_producer(
get_producer_dependencies(channel, ctx), ctx.parameters);

if (pFP == frame_producer::empty())
CASPAR_THROW_EXCEPTION(file_not_found() << msg_info(ctx.parameters.size() > 0 ? ctx.parameters[0] : L""));
if (new_producer == frame_producer::empty())
CASPAR_THROW_EXCEPTION(file_not_found() << msg_info(!ctx.parameters.empty() ? ctx.parameters[0] : L""));

spl::shared_ptr<frame_producer> transition_producer = frame_producer::empty();
transition_info transitionInfo;
sting_info stingInfo;

if (try_match_sting(ctx.parameters, stingInfo)) {
transition_producer = create_sting_producer(get_producer_dependencies(channel, ctx), pFP, stingInfo);
transition_producer =
create_sting_producer(get_producer_dependencies(channel, ctx), new_producer, stingInfo);
} else {
std::wstring message;
for (size_t n = 0; n < ctx.parameters.size(); ++n)
message += boost::to_upper_copy(ctx.parameters[n]) + L" ";
for (std::wstring& parameter : ctx.parameters) {
message += boost::to_upper_copy(parameter) + L" ";
}

// Always fallback to transition
// Try other transitions
try_match_transition(message, transitionInfo);
transition_producer = create_transition_producer(pFP, transitionInfo);
transition_producer = create_transition_producer(new_producer, transitionInfo);
}

// TODO - we should pass the format into load(), so that we can catch it having changed since the producer was
Expand Down Expand Up @@ -329,11 +331,11 @@ std::wstring load_command(command_context& ctx)
ctx.channel.stage->preview(ctx.layer_index());
} else {
try {
auto pFP = ctx.static_context->producer_registry->create_producer(
auto new_producer = ctx.static_context->producer_registry->create_producer(
get_producer_dependencies(ctx.channel.raw_channel, ctx), ctx.parameters);
auto pFP2 = create_transition_producer(pFP, transition_info{});
auto transition_producer = create_transition_producer(new_producer, transition_info{});

ctx.channel.stage->load(ctx.layer_index(), pFP2, true);
ctx.channel.stage->load(ctx.layer_index(), transition_producer, true);
} catch (file_not_found&) {
if (contains_param(L"CLEAR_ON_404", ctx.parameters)) {
ctx.channel.stage->load(
Expand Down

0 comments on commit 528389a

Please sign in to comment.