diff --git a/src/media/media_recorder.cpp b/src/media/media_recorder.cpp index 20d82977f968060f68385d797193b24db250b9fa..04c0f4f3c7db0dc3f621f375dee169dcfd52c1a9 100644 --- a/src/media/media_recorder.cpp +++ b/src/media/media_recorder.cpp @@ -28,6 +28,7 @@ #include "media_io_handle.h" #include "media_recorder.h" #include "system_codec_container.h" +#include "thread_pool.h" #include "video/video_input.h" #include "video/video_receive_thread.h" @@ -55,18 +56,10 @@ replaceAll(const std::string& str, const std::string& from, const std::string& t } MediaRecorder::MediaRecorder() - : loop_([]{ return true;}, - [this]{ process(); }, - []{}) {} MediaRecorder::~MediaRecorder() -{ - if (loop_.isRunning()) - loop_.join(); - if (isRecording_) - flush(); -} +{} bool MediaRecorder::isRecording() const @@ -122,17 +115,8 @@ MediaRecorder::stopRecording() if (isRecording_) { RING_DBG() << "Stop recording '" << getPath() << "'"; isRecording_ = false; - loop_.join(); - flush(); emitSignal<DRing::CallSignal::RecordPlaybackStopped>(getPath()); } - streams_.clear(); - videoIdx_ = audioIdx_ = -1; - isRecording_ = false; - audioOnly_ = false; - videoFilter_.reset(); - audioFilter_.reset(); - encoder_.reset(); } int @@ -159,7 +143,7 @@ MediaRecorder::addStream(const MediaStream& ms) void MediaRecorder::update(Observable<std::shared_ptr<AudioFrame>>* ob, const std::shared_ptr<AudioFrame>& a) { - if (!isRecording_ || !loop_.isRunning()) + if (!isRecording_) return; std::string name; if (dynamic_cast<AudioReceiveThread*>(ob)) @@ -171,12 +155,11 @@ MediaRecorder::update(Observable<std::shared_ptr<AudioFrame>>* ob, const std::sh clone.copyFrom(*a); clone.pointer()->pts -= streams_[name].firstTimestamp; audioFilter_->feedInput(clone.pointer(), name); - loop_.interrupt(); } void MediaRecorder::update(Observable<std::shared_ptr<VideoFrame>>* ob, const std::shared_ptr<VideoFrame>& v) { - if (!isRecording_ || !loop_.isRunning()) + if (!isRecording_) return; std::string name; if (dynamic_cast<video::VideoReceiveThread*>(ob)) @@ -188,7 +171,6 @@ void MediaRecorder::update(Observable<std::shared_ptr<VideoFrame>>* ob, const st clone.copyFrom(*v); clone.pointer()->pts -= streams_[name].firstTimestamp; videoFilter_->feedInput(clone.pointer(), name); - loop_.interrupt(); } int @@ -273,7 +255,14 @@ MediaRecorder::initRecord() } RING_DBG() << "Recording initialized"; - loop_.start(); + ThreadPool::instance().run([rec = shared_from_this()] { + while (rec->isRecording()) { + rec->filterAndEncode(rec->videoFilter_.get(), rec->videoIdx_); + rec->filterAndEncode(rec->audioFilter_.get(), rec->audioIdx_); + } + rec->flush(); + rec->reset(); // allows recorder to be reused in same call + }); return 0; } @@ -436,35 +425,37 @@ MediaRecorder::buildAudioFilter(const std::vector<MediaStream>& peers, const Med void MediaRecorder::flush() { - if (!isRecording_ || encoder_->getStreamCount() <= 0) - return; - std::lock_guard<std::mutex> lk(mutex_); + filterAndEncode(videoFilter_.get(), videoIdx_); + filterAndEncode(audioFilter_.get(), videoIdx_); encoder_->flush(); } void -MediaRecorder::process() +MediaRecorder::reset() { - AVFrame* output; - if (videoIdx_ >= 0 && videoFilter_) - while ((output = videoFilter_->readOutput())) - sendToEncoder(output, videoIdx_); - if (audioIdx_ >= 0 && audioFilter_) - while ((output = audioFilter_->readOutput())) - sendToEncoder(output, audioIdx_); + streams_.clear(); + videoIdx_ = audioIdx_ = -1; + audioOnly_ = false; + videoFilter_.reset(); + audioFilter_.reset(); + encoder_.reset(); } void -MediaRecorder::sendToEncoder(AVFrame* frame, int streamIdx) +MediaRecorder::filterAndEncode(MediaFilter* filter, int streamIdx) { - try { - std::lock_guard<std::mutex> lk(mutex_); - encoder_->encode(frame, streamIdx); - } catch (const MediaEncoderException& e) { - RING_ERR() << "MediaEncoderException: " << e.what(); + if (filter && streamIdx >= 0) { + while (auto frame = filter->readOutput()) { + try { + std::lock_guard<std::mutex> lk(mutex_); + encoder_->encode(frame, streamIdx); + } catch (const MediaEncoderException& e) { + RING_ERR() << "Failed to record frame: " << e.what(); + } + av_frame_free(&frame); + } } - av_frame_free(&frame); } } // namespace ring diff --git a/src/media/media_recorder.h b/src/media/media_recorder.h index af05553231d176e4c77f75e63c414b6ec64847fa..c4796db8c2cb236a82a74f947e058456165074c1 100644 --- a/src/media/media_recorder.h +++ b/src/media/media_recorder.h @@ -27,7 +27,6 @@ #include "media_stream.h" #include "noncopyable.h" #include "observer.h" -#include "threadloop.h" #ifdef RING_VIDEO #include "video/video_base.h" #endif @@ -46,6 +45,7 @@ class MediaRecorder : public Observer<std::shared_ptr<AudioFrame>> #ifdef RING_VIDEO , public video::VideoFramePassiveReader #endif + , public std::enable_shared_from_this<MediaRecorder> { public: MediaRecorder(); @@ -111,6 +111,7 @@ private: NON_COPYABLE(MediaRecorder); void flush(); + void reset(); int initRecord(); MediaStream setupVideoOutput(); @@ -138,9 +139,7 @@ private: bool isRecording_ = false; bool audioOnly_ = false; - InterruptedThreadLoop loop_; - void process(); - void sendToEncoder(AVFrame* frame, int streamIdx); + void filterAndEncode(MediaFilter* filter, int streamIdx); }; }; // namespace ring diff --git a/src/media/recordable.cpp b/src/media/recordable.cpp index cf4d92ce4c8fa7468a648dd7429d93445b95db41..222f873495db681c88e02a17d8b2dd7cab97e4bf 100644 --- a/src/media/recordable.cpp +++ b/src/media/recordable.cpp @@ -113,6 +113,8 @@ Recordable::stopRecording() recorder_->stopRecording(); recording_ = false; + // new recorder since this one may still be recording + recorder_ = std::make_shared<MediaRecorder>(); } bool