Commit 50ed73f0 authored by Tristan Matthews's avatar Tristan Matthews
Browse files

* #9037: shared memory moved out of video_receive_thread

parent dbcabb34
......@@ -68,13 +68,24 @@ class VideoControls : public org::sflphone::SFLphone::VideoControls_adaptor,
std::vector<std::string> getCodecList();
std::vector<std::string> getCodecDetails(const std::string& payload);
std::vector<std::string> getActiveCodecList(const std::string& accountID);
void setActiveCodecList(const std::vector<std::string>& list, const std::string& accountID);
std::vector<std::string>
getActiveCodecList(const std::string& accountID);
void setActiveCodecList(const std::vector<std::string>& list,
const std::string& accountID);
std::vector<std::string> getInputDeviceList();
std::vector<std::string> getInputDeviceChannelList(const std::string &dev);
std::vector<std::string> getInputDeviceSizeList(const std::string &dev, const std::string &channel);
std::vector<std::string> getInputDeviceRateList(const std::string &dev, const std::string &channel, const std::string &size);
std::vector<std::string>
getInputDeviceChannelList(const std::string &dev);
std::vector<std::string>
getInputDeviceSizeList(const std::string &dev,
const std::string &channel);
std::vector<std::string>
getInputDeviceRateList(const std::string &dev,
const std::string &channel,
const std::string &size);
std::map<std::string, std::string> getSettings() const;
void setInputDevice(const std::string& api);
void setInputDeviceChannel(const std::string& api);
......@@ -86,7 +97,8 @@ class VideoControls : public org::sflphone::SFLphone::VideoControls_adaptor,
std::string getInputDeviceRate();
std::string getCurrentCodecName(const std::string &callID);
void startPreview(int32_t &width, int32_t &height, int32_t &shmKey, int32_t &semKey, int32_t &bufferSize);
void startPreview(int32_t &width, int32_t &height, int32_t &shmKey,
int32_t &semKey, int32_t &bufferSize);
void stopPreview();
};
......
......@@ -40,7 +40,6 @@
#include <cstdlib>
#include "manager.h"
#include "dbus/callmanager.h"
#include "dbus/video_controls.h"
#include "fileutils.h"
......@@ -80,7 +79,7 @@ void sem_signal(int semaphoreSetID)
}
/* join and/or create a shared memory segment */
int createShm(unsigned numBytes)
int createShmKey()
{
/* connect to and possibly create a segment with 644 permissions
(rw-r--r--) */
......@@ -89,7 +88,8 @@ int createShm(unsigned numBytes)
return ftok(fileutils::get_program_dir(), proj_id);
}
int createShmID(int key) {
int createShmID(int key, int numBytes)
{
int shm_id = shmget(key, numBytes, 0644 | IPC_CREAT);
if (shm_id == -1)
......@@ -129,24 +129,6 @@ void cleanupShm(int shm_id, uint8_t *data)
destroyShm(shm_id);
}
string openTemp(string path, std::ofstream& f)
{
path += "/XXXXXX";
std::vector<char> dst_path(path.begin(), path.end());
dst_path.push_back('\0');
int fd = -1;
while (fd == -1) {
fd = mkstemp(&dst_path[0]);
if (fd != -1) {
path.assign(dst_path.begin(), dst_path.end() - 1);
f.open(path.c_str(), std::ios_base::trunc | std::ios_base::out);
close(fd);
}
}
return path;
}
int createSemaphoreKey(int shmKey)
{
key_t key;
......@@ -160,10 +142,10 @@ int createSemaphoreSetID(int semaphoreKey)
{
/* first we create a semaphore set with a single semaphore,
whose counter is initialized to '0'. */
int sempahoreSetID = semget(semaphoreKey, 1, 0600 | IPC_CREAT);
int semaphoreSetID = semget(semaphoreKey, 1, 0600 | IPC_CREAT);
if (semaphoreSetID == -1) {
ERROR("%s:semget:%m", __PRETTY_FUNCTION__);
ost::Thread::exit();
throw std::runtime_error("Could not create semaphore set");
}
/* semaphore value, for semctl(). */
......@@ -174,19 +156,34 @@ int createSemaphoreSetID(int semaphoreKey)
}
} // end anonymous namespace
SharedMemory(int bufferSize) :
bufferSize_(bufferSize),
shmKey_(createShmKey(bufferSize_)),
shmID_(createShmID(shmKey_)),
shmBuffer_(attachShm(shmID_)),
semaphoreKey_(createSemaphoreKey(shmKey_)),
semaphoreSetID_(createSemaphoreSet(semaphoreKey_))
SharedMemory::SharedMemory(VideoControls &controls) :
videoControls_(controls),
shmKey_(0),
shmID_(0),
shmBuffer_(0),
semaphoreSetID_(0),
semaphoreKey_(0),
dstWidth_(0),
dstHeight_(0),
bufferSize_(0),
shmReady_()
{}
void SharedMemory::allocateBuffer(int width, int height, int size)
{
dstWidth_ = width;
dstHeight_ = height;
bufferSize_ = size;
shmKey_ = createShmKey();
shmID_ = createShmID(shmKey_, bufferSize_);
shmBuffer_ = attachShm(shmID_);
semaphoreKey_ = createSemaphoreKey(shmKey_);
semaphoreSetID_ = createSemaphoreSetID(semaphoreKey_);
shmReady_.signal();
DEBUG("Publishing shm: %d sem: %d size: %d", shmKey_, semaphoreKey_,
bufferSize_);
Manager::instance().getDbusManager()->getVideoControls()->receivingEvent(shmKey_,
semaphoreKey_, bufferSize_, dstWidth_, dstHeight_);
videoControls_.receivingEvent(shmKey_, semaphoreKey_, bufferSize_,
dstWidth_, dstHeight_);
}
void SharedMemory::waitForShm()
......@@ -203,7 +200,7 @@ void SharedMemory::frameUpdatedCallback()
SharedMemory::~SharedMemory()
{
// free shared memory resources
Manager::instance().getDbusManager()->getVideoControls()->stoppedReceivingEvent(shmKey_, semaphoreKey_);
videoControls_.stoppedReceivingEvent(shmKey_, semaphoreKey_);
// make sure no one is waiting for the SHM event which will never come if we've error'd out
shmReady_.signal();
......
......@@ -34,6 +34,8 @@
#include <cc++/thread.h>
#include "noncopyable.h"
class VideoControls;
namespace sfl_video {
class SharedMemory {
private:
......@@ -42,7 +44,7 @@ class SharedMemory {
/*-------------------------------------------------------------*/
/* These variables should be used in thread (i.e. run()) only! */
/*-------------------------------------------------------------*/
int bufferSize_;
VideoControls &videoControls_;
int shmKey_;
int shmID_;
uint8_t *shmBuffer_;
......@@ -51,16 +53,20 @@ class SharedMemory {
int dstWidth_;
int dstHeight_;
int bufferSize_;
ost::Event shmReady_;
public:
SharedMemory(VideoControls &controls);
~SharedMemory();
void frameUpdatedCallback();
void waitForShm();
// Returns a pointer to the memory where frames should be copied
void *getTargetBuffer();
uint8_t *getTargetBuffer() { return shmBuffer_; }
int getShmKey() const { return shmKey_; }
int getSemaphoreKey() const { return sempahoreKey_; }
int getSemaphoreKey() const { return semaphoreKey_; }
int getBufferSize() const { return bufferSize_; }
void allocateBuffer(int width, int height, int size);
};
}
......
......@@ -31,20 +31,28 @@
#include "video_preview.h"
#include <map>
#include <string>
#include "manager.h"
#include "shared_memory.h"
#include "video_receive_thread.h"
class VideoControls;
namespace sfl_video {
VideoPreview::VideoPreview(const std::map<std::string, std::string> &args) : args_(args), receiveThread_(new VideoReceiveThread(args_))
VideoPreview::VideoPreview(const std::map<std::string, std::string> &args) :
args_(args), sharedMemory_(), receiveThread_()
{
VideoControls *controls(Manager::instance().getDbusManager()->getVideoControls());
sharedMemory_.reset(new SharedMemory(*controls));
receiveThread_.reset(new VideoReceiveThread(args_, *sharedMemory_));
receiveThread_->start();
receiveThread_->waitForShm();
sharedMemory_->waitForShm();
}
void VideoPreview::getShmInfo(int &shmKey, int &semaphoreKey, int &bufferSize)
{
shmKey = receiveThread_->getShmKey();
semaphoreKey = receiveThread_->getSemKey();
bufferSize = receiveThread_->getVideoBufferSize();
shmKey = sharedMemory_->getShmKey();
semaphoreKey = sharedMemory_->getSemaphoreKey();
bufferSize = sharedMemory_->getBufferSize();
}
} // end namspace sfl_video
......@@ -37,6 +37,7 @@
namespace sfl_video {
class SharedMemory;
class VideoReceiveThread;
class VideoPreview {
......@@ -46,6 +47,7 @@ class VideoPreview {
private:
std::map<std::string, std::string> args_;
std::tr1::shared_ptr<SharedMemory> sharedMemory_;
std::tr1::shared_ptr<VideoReceiveThread> receiveThread_;
};
}
......
......@@ -46,11 +46,10 @@ extern "C" {
#include <cstdlib>
#include "manager.h"
#include "dbus/callmanager.h"
#include "dbus/video_controls.h"
#include "fileutils.h"
#include "shared_memory.h"
static const enum PixelFormat video_rgb_format = PIX_FMT_BGRA;
static const enum PixelFormat VIDEO_RGB_FORMAT = PIX_FMT_BGRA;
namespace sfl_video {
......@@ -59,7 +58,7 @@ using std::string;
namespace { // anonymous namespace
int bufferSize(int width, int height, int format)
int getBufferSize(int width, int height, int format)
{
enum PixelFormat fmt = (enum PixelFormat) format;
// determine required buffer size and allocate buffer
......@@ -71,10 +70,8 @@ int bufferSize(int width, int height, int format)
void VideoReceiveThread::loadSDP()
{
assert(not args_["receiving_sdp"].empty());
// this memory will be released on next call to tmpnam
std::ofstream os;
sdpFilename_ = openTemp("/tmp", os);
std::ofstream os;
os << args_["receiving_sdp"];
DEBUG("%s:loaded SDP %s", __PRETTY_FUNCTION__,
args_["receiving_sdp"].c_str());
......@@ -82,6 +79,8 @@ void VideoReceiveThread::loadSDP()
os.close();
}
// We do this setup here instead of the constructor because we don't want the
// main thread to block while this executes, so it happens in the video thread.
void VideoReceiveThread::setup()
{
dstWidth_ = atoi(args_["width"].c_str());
......@@ -91,7 +90,6 @@ void VideoReceiveThread::setup()
if (args_["input"].empty()) {
loadSDP();
args_["input"] = sdpFilename_;
file_iformat = av_find_input_format("sdp");
if (!file_iformat) {
ERROR("%s:Could not find format \"sdp\"", __PRETTY_FUNCTION__);
......@@ -136,7 +134,7 @@ void VideoReceiveThread::setup()
}
// find the first video stream from the input
for (unsigned i = 0; i < inputCtx_->nb_streams; i++) {
for (size_t i = 0; i < inputCtx_->nb_streams; i++) {
if (inputCtx_->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO) {
videoStreamIndex_ = i;
break;
......@@ -179,7 +177,13 @@ void VideoReceiveThread::setup()
}
// determine required buffer size and allocate buffer
videoBufferSize_ = bufferSize(dstWidth_, dstHeight_, video_rgb_format);
const int bufferSize = getBufferSize(dstWidth_, dstHeight_, VIDEO_RGB_FORMAT);
try {
sharedMemory_.allocateBuffer(dstWidth_, dstHeight_, bufferSize);
} catch (const std::runtime_error &e) {
ERROR("%s:%s", __PRETTY_FUNCTION__, e.what());
ost::Thread::exit();
}
// allocate video frame
rawFrame_ = avcodec_alloc_frame();
......@@ -191,7 +195,7 @@ void VideoReceiveThread::createScalingContext()
imgConvertCtx_ = sws_getCachedContext(imgConvertCtx_, decoderCtx_->width,
decoderCtx_->height,
decoderCtx_->pix_fmt, dstWidth_,
dstHeight_, video_rgb_format,
dstHeight_, VIDEO_RGB_FORMAT,
SWS_BICUBIC, NULL, NULL, NULL);
if (imgConvertCtx_ == 0) {
ERROR("Cannot init the conversion context!");
......@@ -199,7 +203,8 @@ void VideoReceiveThread::createScalingContext()
}
}
VideoReceiveThread::VideoReceiveThread(const map<string, string> &args) :
VideoReceiveThread::VideoReceiveThread(const map<string, string> &args,
sfl_video::SharedMemory &handle) :
args_(args),
frameNumber_(0),
decoderCtx_(0),
......@@ -210,7 +215,7 @@ VideoReceiveThread::VideoReceiveThread(const map<string, string> &args) :
imgConvertCtx_(0),
dstWidth_(-1),
dstHeight_(-1),
sdpFilename_()
sharedMemory_(handle)
{
setCancel(cancelDeferred);
}
......@@ -225,7 +230,7 @@ void VideoReceiveThread::run()
int ret = 0;
if ((ret = av_read_frame(inputCtx_, &inpacket)) < 0) {
ERROR("Couldn't read frame : %s\n", perror(ret));
ERROR("Couldn't read frame : %s\n", strerror(ret));
break;
}
PacketHandle inpacket_handle(inpacket);
......@@ -236,8 +241,8 @@ void VideoReceiveThread::run()
avcodec_decode_video2(decoderCtx_, rawFrame_, &frameFinished, &inpacket);
if (frameFinished) {
avpicture_fill(reinterpret_cast<AVPicture *>(scaledPicture_),
targetBuffer_, video_rgb_format, dstWidth_,
dstHeight_);
sharedMemory_.getTargetBuffer(),
VIDEO_RGB_FORMAT, dstWidth_, dstHeight_);
sws_scale(imgConvertCtx_, rawFrame_->data, rawFrame_->linesize,
0, decoderCtx_->height, scaledPicture_->data,
......@@ -252,7 +257,6 @@ void VideoReceiveThread::run()
VideoReceiveThread::~VideoReceiveThread()
{
ost::Thread::terminate();
sharedMemory_.unsubscribe(this);
if (imgConvertCtx_)
sws_freeContext(imgConvertCtx_);
......
......@@ -44,6 +44,8 @@ class AVFormatContext;
class AVFrame;
namespace sfl_video {
class SharedMemory;
class VideoReceiveThread : public ost::Thread {
private:
NON_COPYABLE(VideoReceiveThread);
......@@ -53,7 +55,6 @@ class VideoReceiveThread : public ost::Thread {
/*-------------------------------------------------------------*/
/* These variables should be used in thread (i.e. run()) only! */
/*-------------------------------------------------------------*/
int videoBufferSize_;
AVCodecContext *decoderCtx_;
AVFrame *rawFrame_;
......@@ -64,17 +65,17 @@ class VideoReceiveThread : public ost::Thread {
int dstWidth_;
int dstHeight_;
ost::Event shmReady_;
std::string sdpFilename_;
SharedMemory &sharedMemory_;
void setup();
void createScalingContext();
void loadSDP();
public:
explicit VideoReceiveThread(const std::map<std::string, std::string> &args);
VideoReceiveThread(const std::map<std::string, std::string> &args,
SharedMemory &handle);
virtual ~VideoReceiveThread();
virtual void run();
void waitForShm();
};
}
......
......@@ -33,10 +33,12 @@
#include <sstream>
#include <map>
#include <string>
#include "shared_memory.h"
#include "video_send_thread.h"
#include "video_receive_thread.h"
#include "sip/sdp.h"
#include "libav_utils.h"
#include "manager.h"
namespace sfl_video {
......@@ -44,16 +46,17 @@ using std::map;
using std::string;
VideoRtpSession::VideoRtpSession(const map<string, string> &txArgs) :
sendThread_(), receiveThread_(), txArgs_(txArgs), rxArgs_(),
sending_(true), receiving_(true)
sharedMemory_(), sendThread_(), receiveThread_(), txArgs_(txArgs),
rxArgs_(), sending_(true), receiving_(true)
{
// FIXME: bitrate must be configurable
txArgs_["bitrate"] = "500000";
}
VideoRtpSession::VideoRtpSession(const map<string, string> &txArgs,
const map<string, string> &rxArgs) :
sendThread_(), receiveThread_(), txArgs_(txArgs), rxArgs_(rxArgs),
sending_(true), receiving_(true)
sharedMemory_(), sendThread_(), receiveThread_(), txArgs_(txArgs),
rxArgs_(rxArgs), sending_(true), receiving_(true)
{}
void VideoRtpSession::updateSDP(const Sdp &sdp)
......@@ -144,8 +147,9 @@ void VideoRtpSession::test_loopback()
sendThread_->waitForSDP();
rxArgs_["input"] = "test.sdp";
receiveThread_.reset(new VideoReceiveThread(rxArgs_));
VideoControls *controls(Manager::instance().getDbusManager()->getVideoControls());
sharedMemory_.reset(new SharedMemory(*controls));
receiveThread_.reset(new VideoReceiveThread(rxArgs_, *sharedMemory_));
receiveThread_->start();
}
......@@ -163,7 +167,9 @@ void VideoRtpSession::start()
if (receiving_) {
if (receiveThread_.get())
WARN("Restarting video receiver");
receiveThread_.reset(new VideoReceiveThread(rxArgs_));
VideoControls *controls(Manager::instance().getDbusManager()->getVideoControls());
sharedMemory_.reset(new SharedMemory(*controls));
receiveThread_.reset(new VideoReceiveThread(rxArgs_, *sharedMemory_));
receiveThread_->start();
}
else
......
......@@ -39,6 +39,7 @@ class Sdp;
namespace sfl_video {
class SharedMemory;
class VideoSendThread;
class VideoReceiveThread;
......@@ -57,6 +58,7 @@ class VideoRtpSession {
void updateSDP(const Sdp &sdp);
private:
std::tr1::shared_ptr<SharedMemory> sharedMemory_;
std::tr1::shared_ptr<VideoSendThread> sendThread_;
std::tr1::shared_ptr<VideoReceiveThread> receiveThread_;
std::map<std::string, std::string> txArgs_;
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment