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

recorder: fix crashes

This patch prevent to filter a frame multiple time or a frame partially filtered.

Change-Id: Ie120bc2a5a6d263fdc912cab365fc654dd71b0db
Gitlab: #222
parent 0b7a9787
No related branches found
No related tags found
No related merge requests found
...@@ -165,8 +165,26 @@ MediaRecorder::startRecording() ...@@ -165,8 +165,26 @@ MediaRecorder::startRecording()
// start thread after isRecording_ is set to true // start thread after isRecording_ is set to true
dht::ThreadPool::computation().run([rec = shared_from_this()] { dht::ThreadPool::computation().run([rec = shared_from_this()] {
while (rec->isRecording()) { while (rec->isRecording()) {
rec->filterAndEncode(rec->videoFilter_.get(), rec->videoIdx_); std::shared_ptr<MediaFrame> frame;
rec->filterAndEncode(rec->audioFilter_.get(), rec->audioIdx_); // get frame from queue
{
std::unique_lock<std::mutex> lk(rec->mutexFrameBuff_);
rec->cv_.wait(lk, [rec]{ return rec->interrupted_ or not rec->frameBuff_.empty();});
if (rec->interrupted_) {
break;
}
frame = std::move(rec->frameBuff_.front());
rec->frameBuff_.pop_front();
}
try {
// encode frame
if (frame && frame->pointer()) {
bool isVideo = (frame->pointer()->width > 0 && frame->pointer()->height > 0);
rec->encoder_->encode(frame->pointer(), isVideo ? rec->videoIdx_ : rec->audioIdx_);
}
} catch (const MediaEncoderException& e) {
JAMI_ERR() << "Failed to record frame: " << e.what();
}
} }
rec->flush(); rec->flush();
rec->reset(); // allows recorder to be reused in same call rec->reset(); // allows recorder to be reused in same call
...@@ -178,6 +196,8 @@ MediaRecorder::startRecording() ...@@ -178,6 +196,8 @@ MediaRecorder::startRecording()
void void
MediaRecorder::stopRecording() MediaRecorder::stopRecording()
{ {
interrupted_ = true;
cv_.notify_all();
if (isRecording_) { if (isRecording_) {
JAMI_DBG() << "Stop recording '" << getPath() << "'"; JAMI_DBG() << "Stop recording '" << getPath() << "'";
isRecording_ = false; isRecording_ = false;
...@@ -229,13 +249,15 @@ MediaRecorder::onFrame(const std::string& name, const std::shared_ptr<MediaFrame ...@@ -229,13 +249,15 @@ MediaRecorder::onFrame(const std::string& name, const std::shared_ptr<MediaFrame
std::unique_ptr<MediaFrame> clone; std::unique_ptr<MediaFrame> clone;
const auto& ms = streams_[name]->info; const auto& ms = streams_[name]->info;
if (ms.isVideo) { if (ms.isVideo) {
#ifdef RING_ACCEL auto desc = av_pix_fmt_desc_get((AVPixelFormat)(std::static_pointer_cast<VideoFrame>(frame))->format());
clone = video::HardwareAccel::transferToMainMemory(*std::static_pointer_cast<VideoFrame>(frame), if (desc && (desc->flags & AV_PIX_FMT_FLAG_HWACCEL)) {
static_cast<AVPixelFormat>(ms.format)); clone = video::HardwareAccel::transferToMainMemory(*std::static_pointer_cast<VideoFrame>(frame),
#else static_cast<AVPixelFormat>(ms.format));
clone = std::make_unique<MediaFrame>(); }
clone->copyFrom(*frame); else {
#endif clone = std::make_unique<MediaFrame>();
clone->copyFrom(*frame);
}
} else { } else {
clone = std::make_unique<MediaFrame>(); clone = std::make_unique<MediaFrame>();
clone->copyFrom(*frame); clone->copyFrom(*frame);
...@@ -247,10 +269,24 @@ MediaRecorder::onFrame(const std::string& name, const std::shared_ptr<MediaFrame ...@@ -247,10 +269,24 @@ MediaRecorder::onFrame(const std::string& name, const std::shared_ptr<MediaFrame
#else #else
clone->pointer()->pts -= ms.firstTimestamp; clone->pointer()->pts -= ms.firstTimestamp;
#endif #endif
if (ms.isVideo)
std::unique_ptr<MediaFrame> filteredFrame;
if (ms.isVideo) {
std::lock_guard<std::mutex> lk(mutexFilterVideo_);
videoFilter_->feedInput(clone->pointer(), name); videoFilter_->feedInput(clone->pointer(), name);
else filteredFrame = videoFilter_->readOutput();
}
else {
std::lock_guard<std::mutex> lk(mutexFilterAudio_);
audioFilter_->feedInput(clone->pointer(), name); audioFilter_->feedInput(clone->pointer(), name);
filteredFrame = audioFilter_->readOutput();
}
if (filteredFrame) {
std::lock_guard<std::mutex> lk(mutexFrameBuff_);
frameBuff_.emplace_back(std::move(filteredFrame));
cv_.notify_one();
}
} }
int int
...@@ -489,19 +525,25 @@ MediaRecorder::buildAudioFilter(const std::vector<MediaStream>& peers, const Med ...@@ -489,19 +525,25 @@ MediaRecorder::buildAudioFilter(const std::vector<MediaStream>& peers, const Med
void void
MediaRecorder::flush() MediaRecorder::flush()
{ {
std::lock_guard<std::mutex> lk(mutex_); if (videoFilter_) {
if (videoFilter_) std::lock_guard<std::mutex> lk(mutexFilterVideo_);
videoFilter_->flush(); videoFilter_->flush();
if (audioFilter_) }
if (audioFilter_) {
std::lock_guard<std::mutex> lk(mutexFilterAudio_);
audioFilter_->flush(); audioFilter_->flush();
filterAndEncode(videoFilter_.get(), videoIdx_); }
filterAndEncode(audioFilter_.get(), audioIdx_);
encoder_->flush(); encoder_->flush();
} }
void void
MediaRecorder::reset() MediaRecorder::reset()
{ {
{
std::lock_guard<std::mutex> lk(mutexFrameBuff_);
frameBuff_.clear();
}
streams_.clear(); streams_.clear();
videoIdx_ = audioIdx_ = -1; videoIdx_ = audioIdx_ = -1;
audioOnly_ = false; audioOnly_ = false;
...@@ -510,19 +552,4 @@ MediaRecorder::reset() ...@@ -510,19 +552,4 @@ MediaRecorder::reset()
encoder_.reset(); encoder_.reset();
} }
void
MediaRecorder::filterAndEncode(MediaFilter* filter, int streamIdx)
{
if (filter && streamIdx >= 0) {
while (auto frame = filter->readOutput()) {
try {
std::lock_guard<std::mutex> lk(mutex_);
encoder_->encode(frame->pointer(), streamIdx);
} catch (const MediaEncoderException& e) {
JAMI_ERR() << "Failed to record frame: " << e.what();
}
}
}
}
} // namespace jami } // namespace jami
...@@ -35,6 +35,8 @@ ...@@ -35,6 +35,8 @@
#include <stdexcept> #include <stdexcept>
#include <string> #include <string>
#include <utility> #include <utility>
#include <condition_variable>
#include <atomic>
namespace jami { namespace jami {
...@@ -129,7 +131,9 @@ private: ...@@ -129,7 +131,9 @@ private:
MediaStream setupAudioOutput(); MediaStream setupAudioOutput();
std::string buildAudioFilter(const std::vector<MediaStream>& peers, const MediaStream& local) const; std::string buildAudioFilter(const std::vector<MediaStream>& peers, const MediaStream& local) const;
std::mutex mutex_; // protect against concurrent file writes std::mutex mutexFrameBuff_;
std::mutex mutexFilterVideo_;
std::mutex mutexFilterAudio_;
std::map<std::string, std::unique_ptr<StreamObserver>> streams_; std::map<std::string, std::unique_ptr<StreamObserver>> streams_;
...@@ -150,7 +154,10 @@ private: ...@@ -150,7 +154,10 @@ private:
bool isRecording_ = false; bool isRecording_ = false;
bool audioOnly_ = false; bool audioOnly_ = false;
void filterAndEncode(MediaFilter* filter, int streamIdx); std::condition_variable cv_;
std::atomic_bool interrupted_ {false};
std::list<std::shared_ptr<MediaFrame>> frameBuff_;
}; };
}; // namespace jami }; // namespace jami
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment