Skip to content
Snippets Groups Projects
Commit bb3ca5bb authored by Pierre Lespagnol's avatar Pierre Lespagnol Committed by Adrien Béraud
Browse files

mixer: fix the flickering black frames in conference

Before the frame transfer to the CPU could fail during the rendering,
the fix move the transfer part in the update.
This way, the source keep the last rendered frame if the transfer fail

Change-Id: I71848629023720ed09712a8191e556b59c514e1c
GitLab: #388
parent 2b507feb
Branches
No related tags found
No related merge requests found
...@@ -49,12 +49,18 @@ struct VideoMixer::VideoMixerSource ...@@ -49,12 +49,18 @@ struct VideoMixer::VideoMixerSource
Observable<std::shared_ptr<MediaFrame>>* source {nullptr}; Observable<std::shared_ptr<MediaFrame>>* source {nullptr};
int rotation {0}; int rotation {0};
std::unique_ptr<MediaFilter> rotationFilter {nullptr}; std::unique_ptr<MediaFilter> rotationFilter {nullptr};
std::unique_ptr<VideoFrame> update_frame; std::shared_ptr<VideoFrame> render_frame;
std::unique_ptr<VideoFrame> render_frame; void atomic_copy(const VideoFrame& other)
void atomic_swap_render(std::unique_ptr<VideoFrame>& other)
{ {
std::lock_guard<std::mutex> lock(mutex_); std::lock_guard<std::mutex> lock(mutex_);
render_frame.swap(other); auto newFrame = std::make_shared<VideoFrame>();
newFrame->copyFrom(other);
render_frame = newFrame;
}
std::shared_ptr<VideoFrame> getRenderFrame() {
std::lock_guard<std::mutex> lock(mutex_);
return render_frame;
} }
// Current render informations // Current render informations
...@@ -188,6 +194,7 @@ VideoMixer::attached(Observable<std::shared_ptr<MediaFrame>>* ob) ...@@ -188,6 +194,7 @@ VideoMixer::attached(Observable<std::shared_ptr<MediaFrame>>* ob)
auto lock(rwMutex_.write()); auto lock(rwMutex_.write());
auto src = std::unique_ptr<VideoMixerSource>(new VideoMixerSource); auto src = std::unique_ptr<VideoMixerSource>(new VideoMixerSource);
src->render_frame = std::make_shared<VideoFrame>();
src->source = ob; src->source = ob;
sources_.emplace_back(std::move(src)); sources_.emplace_back(std::move(src));
layoutUpdated_ += 1; layoutUpdated_ += 1;
...@@ -220,13 +227,18 @@ VideoMixer::update(Observable<std::shared_ptr<MediaFrame>>* ob, ...@@ -220,13 +227,18 @@ VideoMixer::update(Observable<std::shared_ptr<MediaFrame>>* ob,
for (const auto& x : sources_) { for (const auto& x : sources_) {
if (x->source == ob) { if (x->source == ob) {
if (!x->update_frame) #ifdef RING_ACCEL
x->update_frame.reset(new VideoFrame); std::shared_ptr<VideoFrame> frame;
else try {
x->update_frame->reset(); frame = HardwareAccel::transferToMainMemory(*std::static_pointer_cast<VideoFrame>(frame_p), AV_PIX_FMT_NV12);
x->update_frame->copyFrom(*std::static_pointer_cast<VideoFrame>( } catch (const std::runtime_error& e) {
frame_p)); // copy frame content, it will be destroyed after return JAMI_ERR("Accel failure: %s", e.what());
x->atomic_swap_render(x->update_frame); return;
}
x->atomic_copy(*std::static_pointer_cast<VideoFrame>(frame));
#else
x->atomic_copy(*std::static_pointer_cast<VideoFrame>(frame_p));
#endif
return; return;
} }
} }
...@@ -265,8 +277,7 @@ VideoMixer::process() ...@@ -265,8 +277,7 @@ VideoMixer::process()
if (currentLayout_ != Layout::ONE_BIG or activeSource_ == x->source) { if (currentLayout_ != Layout::ONE_BIG or activeSource_ == x->source) {
// make rendered frame temporarily unavailable for update() // make rendered frame temporarily unavailable for update()
// to avoid concurrent access. // to avoid concurrent access.
std::unique_ptr<VideoFrame> input; std::shared_ptr<VideoFrame> input = x->getRenderFrame();
x->atomic_swap_render(input);
auto wantedIndex = i; auto wantedIndex = i;
if (currentLayout_ == Layout::ONE_BIG) { if (currentLayout_ == Layout::ONE_BIG) {
...@@ -285,7 +296,9 @@ VideoMixer::process() ...@@ -285,7 +296,9 @@ VideoMixer::process()
calc_position(x, wantedIndex); calc_position(x, wantedIndex);
if (input) if (input)
successfullyRendered |= render_frame(output, *input, x); successfullyRendered |= render_frame(output, input, x);
else
JAMI_WARN("Nothing to render for %p", x->source);
auto hasVideo = x->hasVideo; auto hasVideo = x->hasVideo;
x->hasVideo = input && successfullyRendered; x->hasVideo = input && successfullyRendered;
...@@ -293,7 +306,6 @@ VideoMixer::process() ...@@ -293,7 +306,6 @@ VideoMixer::process()
layoutUpdated_ += 1; layoutUpdated_ += 1;
needsUpdate = true; needsUpdate = true;
} }
x->atomic_swap_render(input);
} else if (needsUpdate) { } else if (needsUpdate) {
x->x = 0; x->x = 0;
x->y = 0; x->y = 0;
...@@ -314,7 +326,7 @@ VideoMixer::process() ...@@ -314,7 +326,7 @@ VideoMixer::process()
SourceInfo {x->source, x->x, x->y, x->w, x->h, x->hasVideo}); SourceInfo {x->source, x->x, x->y, x->w, x->h, x->hasVideo});
} }
if (onSourcesUpdated_) if (onSourcesUpdated_)
(onSourcesUpdated_)(std::move(sourcesInfo)); onSourcesUpdated_(std::move(sourcesInfo));
} }
} }
} }
...@@ -330,44 +342,35 @@ VideoMixer::process() ...@@ -330,44 +342,35 @@ VideoMixer::process()
bool bool
VideoMixer::render_frame(VideoFrame& output, VideoMixer::render_frame(VideoFrame& output,
const VideoFrame& input, const std::shared_ptr<VideoFrame>& input,
std::unique_ptr<VideoMixerSource>& source) std::unique_ptr<VideoMixerSource>& source)
{ {
if (!width_ or !height_ or !input.pointer() or input.pointer()->format == -1) if (!width_ or !height_ or !input->pointer() or input->pointer()->format == -1)
return false; return false;
#ifdef RING_ACCEL
std::shared_ptr<VideoFrame> frame;
try {
frame = HardwareAccel::transferToMainMemory(input, AV_PIX_FMT_NV12);
} catch (const std::runtime_error& e) {
JAMI_ERR("Accel failure: %s", e.what());
return false;
}
#else
std::shared_ptr<VideoFrame> frame = input;
#endif
int cell_width = source->w; int cell_width = source->w;
int cell_height = source->h; int cell_height = source->h;
int xoff = source->x; int xoff = source->x;
int yoff = source->y; int yoff = source->y;
int angle = frame->getOrientation(); int angle = input->getOrientation();
const constexpr char filterIn[] = "mixin"; const constexpr char filterIn[] = "mixin";
if (angle != source->rotation) { if (angle != source->rotation) {
source->rotationFilter = video::getTransposeFilter(angle, source->rotationFilter = video::getTransposeFilter(angle,
filterIn, filterIn,
frame->width(), input->width(),
frame->height(), input->height(),
frame->format(), input->format(),
false); false);
source->rotation = angle; source->rotation = angle;
} }
std::shared_ptr<VideoFrame> frame;
if (source->rotationFilter) { if (source->rotationFilter) {
source->rotationFilter->feedInput(frame->pointer(), filterIn); source->rotationFilter->feedInput(input->pointer(), filterIn);
frame = std::static_pointer_cast<VideoFrame>( frame = std::static_pointer_cast<VideoFrame>(
std::shared_ptr<MediaFrame>(source->rotationFilter->readOutput())); std::shared_ptr<MediaFrame>(source->rotationFilter->readOutput()));
} else {
frame = input;
} }
scaler_.scale_and_pad(*frame, output, xoff, yoff, cell_width, cell_height, true); scaler_.scale_and_pad(*frame, output, xoff, yoff, cell_width, cell_height, true);
......
...@@ -92,7 +92,7 @@ private: ...@@ -92,7 +92,7 @@ private:
struct VideoMixerSource; struct VideoMixerSource;
bool render_frame(VideoFrame& output, bool render_frame(VideoFrame& output,
const VideoFrame& input, const std::shared_ptr<VideoFrame>& input,
std::unique_ptr<VideoMixerSource>& source); std::unique_ptr<VideoMixerSource>& source);
void calc_position(std::unique_ptr<VideoMixerSource>& source, int index); void calc_position(std::unique_ptr<VideoMixerSource>& source, int index);
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment