Skip to content
Snippets Groups Projects
Commit 12ec77a2 authored by Alexandre Lision's avatar Alexandre Lision Committed by Edric Milaret
Browse files

video: fix concurrent access in sink direct rendering


This patchset prevents client from reading a frame that is being written
by the daemon using a push/pull mechanism.

**WARNING** This breaks the direct rendering API

Issue: #81542
Change-Id: I55d4ee9b986ac682903b326fd86c32d8f5f68825
Signed-off-by: default avatarGuillaume Roguez <guillaume.roguez@savoirfairelinux.com>
parent 0b08a64f
Branches
Tags
No related merge requests found
...@@ -138,30 +138,15 @@ hasCameraStarted() ...@@ -138,30 +138,15 @@ hasCameraStarted()
return videoManager.started; return videoManager.started;
} }
template <class T> void
static void registerSinkTarget(const std::string& sinkId, const SinkTarget& target)
registerSinkTarget_(const std::string& sinkId, std::vector<unsigned char>& frameBuffer, T&& cb)
{ {
if (auto sink = ring::Manager::instance().getSinkClient(sinkId)) if (auto sink = ring::Manager::instance().getSinkClient(sinkId))
sink->registerTarget(std::forward<T>(cb), frameBuffer); sink->registerTarget(target);
else else
RING_WARN("No sink found for id '%s'", sinkId.c_str()); RING_WARN("No sink found for id '%s'", sinkId.c_str());
} }
void
registerSinkTarget(const std::string& sinkId, std::vector<unsigned char>& frameBuffer,
const std::function<void(int, int)>& cb)
{
registerSinkTarget_(sinkId, frameBuffer, cb);
}
void
registerSinkTarget(const std::string& sinkId, std::vector<unsigned char>& frameBuffer,
std::function<void(int, int)>&& cb)
{
registerSinkTarget_(sinkId, frameBuffer, cb);
}
#ifdef __ANDROID__ #ifdef __ANDROID__
void void
addVideoDevice(const std::string &node) addVideoDevice(const std::string &node)
......
/* /*
* Copyright (C) 2012-2015 Savoir-faire Linux Inc. * Copyright (C) 2012-2015 Savoir-faire Linux Inc.
* *
* Author: Guillaume Roguez <guillaume.roguez@savoirfairelinux.com>
*
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or * the Free Software Foundation; either version 3 of the License, or
...@@ -24,11 +26,29 @@ ...@@ -24,11 +26,29 @@
#include <map> #include <map>
#include <string> #include <string>
#include <functional> #include <functional>
#include <cstdint>
#include <cstdlib>
#include "dring.h" #include "dring.h"
namespace DRing { namespace DRing {
/* FrameBuffer is a generic video frame container */
struct FrameBuffer {
uint8_t* ptr {nullptr}; // data as a plain raw pointer
std::size_t ptrSize {0}; // size in byte of ptr array
int format {0}; // as listed by AVPixelFormat (avutils/pixfmt.h)
int width {0}; // frame width
int height {0}; // frame height
std::vector<uint8_t> storage;
};
struct SinkTarget {
using FrameBufferPtr = std::unique_ptr<FrameBuffer>;
std::function<FrameBufferPtr(std::size_t bytes)> pull;
std::function<void(FrameBufferPtr)> push;
};
using VideoCapabilities = std::map<std::string, std::map<std::string, std::vector<std::string>>>; using VideoCapabilities = std::map<std::string, std::map<std::string, std::vector<std::string>>>;
void registerVideoHandlers(const std::map<std::string, std::shared_ptr<CallbackWrapperBase>>&); void registerVideoHandlers(const std::map<std::string, std::shared_ptr<CallbackWrapperBase>>&);
...@@ -48,8 +68,8 @@ void stopCamera(); ...@@ -48,8 +68,8 @@ void stopCamera();
bool hasCameraStarted(); bool hasCameraStarted();
bool switchInput(const std::string& resource); bool switchInput(const std::string& resource);
bool switchToCamera(); bool switchToCamera();
void registerSinkTarget(const std::string& sinkId, std::vector<unsigned char>& frameBuffer, const std::function<void(int, int)>& cb); void registerSinkTarget(const std::string& sinkId, const SinkTarget& target);
void registerSinkTarget(const std::string& sinkId, std::vector<unsigned char>& frameBuffer, std::function<void(int, int)>&& cb);
#ifdef __ANDROID__ #ifdef __ANDROID__
void addVideoDevice(const std::string &node); void addVideoDevice(const std::string &node);
void removeVideoDevice(const std::string &node); void removeVideoDevice(const std::string &node);
......
...@@ -20,6 +20,7 @@ ...@@ -20,6 +20,7 @@
#include "libav_deps.h" // MUST BE INCLUDED FIRST #include "libav_deps.h" // MUST BE INCLUDED FIRST
#include "media_buffer.h" #include "media_buffer.h"
#include "dring/videomanager_interface.h"
#include <new> #include <new>
#include <cstdlib> #include <cstdlib>
...@@ -107,7 +108,7 @@ VideoFrame::reserve(int format, int width, int height) ...@@ -107,7 +108,7 @@ VideoFrame::reserve(int format, int width, int height)
} }
void void
VideoFrame::setFromMemory(void* ptr, int format, int width, int height) noexcept VideoFrame::setFromMemory(uint8_t* ptr, int format, int width, int height)
{ {
reset(); reset();
setGeometry(format, width, height); setGeometry(format, width, height);
......
...@@ -26,6 +26,10 @@ ...@@ -26,6 +26,10 @@
class AVFrame; class AVFrame;
namespace DRing {
class FrameBuffer; // from dring/videomanager_interface.h
}
namespace ring { namespace ring {
class MediaFrame { class MediaFrame {
...@@ -74,7 +78,7 @@ class VideoFrame: public MediaFrame { ...@@ -74,7 +78,7 @@ class VideoFrame: public MediaFrame {
// Set internal pixel buffers on given memory buffer // Set internal pixel buffers on given memory buffer
// This buffer must follow given specifications. // This buffer must follow given specifications.
void setFromMemory(void* ptr, int format, int width, int height) noexcept; void setFromMemory(uint8_t* data, int format, int width, int height);
void noise(); void noise();
......
...@@ -21,6 +21,7 @@ ...@@ -21,6 +21,7 @@
#ifndef SHM_HEADER_H_ #ifndef SHM_HEADER_H_
#define SHM_HEADER_H_ #define SHM_HEADER_H_
#include <cstdint>
#include <semaphore.h> #include <semaphore.h>
// Implementation note: double-buffering // Implementation note: double-buffering
...@@ -37,7 +38,7 @@ struct SHMHeader { ...@@ -37,7 +38,7 @@ struct SHMHeader {
unsigned mapSize; // size to map if you need to see all data unsigned mapSize; // size to map if you need to see all data
unsigned readOffset; // offset of readable frame in data unsigned readOffset; // offset of readable frame in data
unsigned writeOffset; // offset of writable frame in data unsigned writeOffset; // offset of writable frame in data
char data[]; // the whole shared memory uint8_t data[]; // the whole shared memory
}; };
#endif #endif
...@@ -3,6 +3,7 @@ ...@@ -3,6 +3,7 @@
* *
* Author: Tristan Matthews <tristan.matthews@savoirfairelinux.com> * Author: Tristan Matthews <tristan.matthews@savoirfairelinux.com>
* Author: Guillaume Roguez <guillaume.roguez@savoirfairelinux.com> * Author: Guillaume Roguez <guillaume.roguez@savoirfairelinux.com>
* Author: Alexandre Lision <alexandre.lision@savoirfairelinux.com>
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
...@@ -35,6 +36,7 @@ ...@@ -35,6 +36,7 @@
#include "noncopyable.h" #include "noncopyable.h"
#include "client/ring_signal.h" #include "client/ring_signal.h"
#include "dring/videomanager_interface.h" #include "dring/videomanager_interface.h"
#include "libav_utils.h"
#ifndef _WIN32 #ifndef _WIN32
#include <sys/mman.h> #include <sys/mman.h>
...@@ -323,7 +325,7 @@ SinkClient::update(Observable<std::shared_ptr<VideoFrame>>* /*obs*/, ...@@ -323,7 +325,7 @@ SinkClient::update(Observable<std::shared_ptr<VideoFrame>>* /*obs*/,
shm_->renderFrame(*f.get()); shm_->renderFrame(*f.get());
#endif #endif
if (targetData_) { if (target_.pull) {
VideoFrame dst; VideoFrame dst;
VideoScaler scaler; VideoScaler scaler;
const int width = f->width(); const int width = f->width();
...@@ -336,12 +338,14 @@ SinkClient::update(Observable<std::shared_ptr<VideoFrame>>* /*obs*/, ...@@ -336,12 +338,14 @@ SinkClient::update(Observable<std::shared_ptr<VideoFrame>>* /*obs*/,
const auto bytes = videoFrameSize(format, width, height); const auto bytes = videoFrameSize(format, width, height);
if (bytes > 0) { if (bytes > 0) {
targetData_->resize(bytes); if (auto buffer_ptr = target_.pull(bytes)) {
auto data = targetData_->data(); buffer_ptr->format = libav_utils::libav_pixel_format(format);
buffer_ptr->width = width;
dst.setFromMemory(data, format, width, height); buffer_ptr->height = height;
dst.setFromMemory(buffer_ptr->ptr, format, width, height);
scaler.scale(*f, dst); scaler.scale(*f, dst);
target_(width, height); target_.push(std::move(buffer_ptr));
}
} }
} }
} }
......
...@@ -2,6 +2,8 @@ ...@@ -2,6 +2,8 @@
* Copyright (C) 2012-2015 Savoir-faire Linux Inc. * Copyright (C) 2012-2015 Savoir-faire Linux Inc.
* *
* Author: Tristan Matthews <tristan.matthews@savoirfairelinux.com> * Author: Tristan Matthews <tristan.matthews@savoirfairelinux.com>
* Author: Guillaume Roguez <guillaume.roguez@savoirfairelinux.com>
* Author: Alexandre Lision <alexandre.lision@savoirfairelinux.com>
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
...@@ -25,6 +27,7 @@ ...@@ -25,6 +27,7 @@
#endif #endif
#include "video_base.h" #include "video_base.h"
#include <videomanager_interface.h>
#include <string> #include <string>
#include <vector> #include <vector>
...@@ -56,18 +59,15 @@ class SinkClient : public VideoFramePassiveReader ...@@ -56,18 +59,15 @@ class SinkClient : public VideoFramePassiveReader
void setFrameSize(int width, int height); void setFrameSize(int width, int height);
template <class T> void registerTarget(const DRing::SinkTarget& target) noexcept {
void registerTarget(T&& cb, std::vector<unsigned char>& frameBuffer) noexcept { target_ = target;
target_ = std::forward<T>(cb);
targetData_ = &frameBuffer;
} }
private: private:
const std::string id_; const std::string id_;
const bool mixer_; const bool mixer_;
bool started_ {false}; // used to arbitrate client's stop signal. bool started_ {false}; // used to arbitrate client's stop signal.
std::function<void(int, int)> target_; DRing::SinkTarget target_;
std::vector<unsigned char>* targetData_ {nullptr}; // filled by registerTarget, user owned
#ifdef DEBUG_FPS #ifdef DEBUG_FPS
unsigned frameCount_; unsigned frameCount_;
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment