diff --git a/src/media/audio/audio_rtp_session.cpp b/src/media/audio/audio_rtp_session.cpp index fb98bb2da6d5fc3f54ed17940e38d0c18c298023..4539793540f96b62168e20029538b6bff295ea9f 100644 --- a/src/media/audio/audio_rtp_session.cpp +++ b/src/media/audio/audio_rtp_session.cpp @@ -233,6 +233,9 @@ class AudioReceiveThread void openDecoder(); bool decodeFrame(); + std::weak_ptr<MediaRecorder> recorder_; + bool recordingStarted_{false}; + /*-----------------------------------------------------------------*/ /* These variables should be used in thread (i.e. process()) only! */ /*-----------------------------------------------------------------*/ @@ -273,6 +276,8 @@ AudioReceiveThread::AudioReceiveThread(const std::string& id, AudioReceiveThread::~AudioReceiveThread() { + if (auto rec = recorder_.lock()) + rec->stopRecording(); loop_.join(); } @@ -309,6 +314,20 @@ AudioReceiveThread::process() switch (audioDecoder_->decode(decodedFrame)) { case MediaDecoder::Status::FrameFinished: + if (auto rec = recorder_.lock()) { + if (!recordingStarted_) { + if (rec->addStream(false, true, audioDecoder_->getStream()) >= 0) { + recordingStarted_ = true; + } else { + recorder_ = std::weak_ptr<MediaRecorder>(); + } + } + if (recordingStarted_) + rec->recordData(decodedFrame.pointer(), false, true); + } else { + recordingStarted_ = false; + recorder_ = std::weak_ptr<MediaRecorder>(); + } audioDecoder_->writeToRingBuffer(decodedFrame, *ringbuffer_, mainBuffFormat); // Refresh the remote audio codec in the callback SmartInfo @@ -384,8 +403,8 @@ AudioReceiveThread::startLoop() void AudioReceiveThread::initRecorder(std::shared_ptr<MediaRecorder>& rec) { - if (audioDecoder_) - audioDecoder_->initRecorder(rec); + rec->incrementStreams(1); + recorder_ = rec; } AudioRtpSession::AudioRtpSession(const std::string& id) diff --git a/src/media/media_decoder.cpp b/src/media/media_decoder.cpp index 373eff8289511caec8b12bcfad4a55628eb2b9e3..96678dc51965a05c351bdf5d7fa79449b2d78927 100644 --- a/src/media/media_decoder.cpp +++ b/src/media/media_decoder.cpp @@ -28,7 +28,6 @@ #include "audio/resampler.h" #include "decoder_finder.h" #include "manager.h" -#include "media_recorder.h" #ifdef RING_ACCEL #include "video/accel.h" @@ -60,8 +59,6 @@ MediaDecoder::MediaDecoder() : MediaDecoder::~MediaDecoder() { - if (auto rec = recorder_.lock()) - rec->stopRecording(); #ifdef RING_ACCEL if (decoderCtx_ && decoderCtx_->hw_device_ctx) av_buffer_unref(&decoderCtx_->hw_device_ctx); @@ -293,20 +290,7 @@ MediaDecoder::decode(VideoFrame& result) frame->pts = av_rescale_q_rnd(av_gettime() - startTime_, {1, AV_TIME_BASE}, decoderCtx_->time_base, static_cast<AVRounding>(AV_ROUND_NEAR_INF|AV_ROUND_PASS_MINMAX)); - - if (auto rec = recorder_.lock()) { - bool fromPeer = (inputCtx_->iformat->name == std::string("sdp")); - if (!recordingStarted_) { - auto ms = MediaStream("", decoderCtx_, frame->pts); - ms.format = frame->format; // might not match avStream_ if accel is used - if (rec->addStream(true, fromPeer, ms) >= 0) - recordingStarted_ = true; - else - recorder_ = std::weak_ptr<MediaRecorder>(); - } - if (recordingStarted_) - rec->recordData(frame, true, fromPeer); - } + lastTimestamp_ = frame->pts; if (emulateRate_ and packetTimestamp != AV_NOPTS_VALUE) { auto frame_time = getTimeBase()*(packetTimestamp - avStream_->start_time); @@ -365,18 +349,7 @@ MediaDecoder::decode(const AudioFrame& decodedFrame) // NOTE don't use clock to rescale audio pts, it may create artifacts frame->pts = av_rescale_q_rnd(frame->pts, avStream_->time_base, decoderCtx_->time_base, static_cast<AVRounding>(AV_ROUND_NEAR_INF|AV_ROUND_PASS_MINMAX)); - - if (auto rec = recorder_.lock()) { - if (!recordingStarted_) { - auto ms = MediaStream("", decoderCtx_, frame->pts); - if (rec->addStream(false, true, ms) >= 0) - recordingStarted_ = true; - else - recorder_ = std::weak_ptr<MediaRecorder>(); - } - if (recordingStarted_) - rec->recordData(frame, false, true); - } + lastTimestamp_ = frame->pts; if (emulateRate_ and packetTimestamp != AV_NOPTS_VALUE) { auto frame_time = getTimeBase()*(packetTimestamp - avStream_->start_time); @@ -525,15 +498,15 @@ MediaDecoder::correctPixFmt(int input_pix_fmt) { return pix_fmt; } -void -MediaDecoder::initRecorder(std::shared_ptr<MediaRecorder>& rec) +MediaStream +MediaDecoder::getStream() const { - // recording will start once we can send an AVPacket to the recorder - recordingStarted_ = false; - recorder_ = rec; - if (auto r = recorder_.lock()) { - r->incrementStreams(1); - } + auto ms = MediaStream("", decoderCtx_, lastTimestamp_); +#ifdef RING_ACCEL + if (decoderCtx_->codec_type == AVMEDIA_TYPE_VIDEO && enableAccel_ && !accel_.name.empty()) + ms.format = AV_PIX_FMT_NV12; // TODO option me! +#endif + return ms; } } // namespace ring diff --git a/src/media/media_decoder.h b/src/media/media_decoder.h index 56ab9c3f4a7b06d6185d9824c244386f50bb500e..f1b4a10c4eecfa01b5bbfe253c5bf7540b3a52d1 100644 --- a/src/media/media_decoder.h +++ b/src/media/media_decoder.h @@ -34,6 +34,7 @@ #include "audio/audiobuffer.h" +#include "media_stream.h" #include "rational.h" #include "noncopyable.h" @@ -57,7 +58,6 @@ class RingBuffer; class Resampler; class MediaIOHandle; struct DeviceParams; -class MediaRecorder; class MediaDecoder { public: @@ -100,7 +100,7 @@ class MediaDecoder { void enableAccel(bool enableAccel); #endif - void initRecorder(std::shared_ptr<MediaRecorder>& rec); + MediaStream getStream() const; private: NON_COPYABLE(MediaDecoder); @@ -115,6 +115,7 @@ class MediaDecoder { int streamIndex_ = -1; bool emulateRate_ = false; int64_t startTime_; + int64_t lastTimestamp_; AudioBuffer decBuff_; AudioBuffer resamplingBuff_; @@ -131,9 +132,6 @@ class MediaDecoder { unsigned short accelFailures_ = 0; #endif - std::weak_ptr<MediaRecorder> recorder_; - bool recordingStarted_ = false; - protected: AVDictionary *options_ = nullptr; }; diff --git a/src/media/media_encoder.cpp b/src/media/media_encoder.cpp index f90221288cd69fb987892c61591e48b485007339..51b4e56680277c7b6f28a6f8db75c0ce3088b67c 100644 --- a/src/media/media_encoder.cpp +++ b/src/media/media_encoder.cpp @@ -446,13 +446,17 @@ int MediaEncoder::encode_audio(const AudioBuffer &buffer) if (auto rec = recorder_.lock()) { if (!recordingStarted_) { auto ms = MediaStream("", encoders_[currentStreamIdx_], frame->pts); - if (rec->addStream(false, false, ms) >= 0) + if (rec->addStream(false, false, ms) >= 0) { recordingStarted_ = true; - else + } else { recorder_ = std::weak_ptr<MediaRecorder>(); + } } if (recordingStarted_) rec->recordData(frame, false, false); + } else { + recordingStarted_ = false; + recorder_ = std::weak_ptr<MediaRecorder>(); } encode(frame, currentStreamIdx_); diff --git a/src/media/media_recorder.cpp b/src/media/media_recorder.cpp index 472555f895d634436ba47fc0f78887dfc7735e8e..f2d63abc11f4cab4c5d29ee2df03288e31bd2442 100644 --- a/src/media/media_recorder.cpp +++ b/src/media/media_recorder.cpp @@ -19,6 +19,7 @@ */ #include "libav_deps.h" // MUST BE INCLUDED FIRST +#include "client/ring_signal.h" #include "fileutils.h" #include "logger.h" #include "media_io_handle.h" @@ -179,6 +180,7 @@ MediaRecorder::stopRecording() isRecording_ = false; loop_.join(); flush(); + emitSignal<DRing::CallSignal::RecordPlaybackStopped>(getPath()); } resetToDefaults(); } @@ -220,7 +222,7 @@ MediaRecorder::recordData(AVFrame* frame, bool isVideo, bool fromPeer) return 0; // save a copy of the frame, will be filtered/encoded in another thread - const MediaStream& ms = streams_[isVideo][fromPeer]; + MediaStream& ms = streams_[isVideo][fromPeer]; AVFrame* input = av_frame_clone(frame); input->pts = input->pts - ms.firstTimestamp; // stream has to start at 0 diff --git a/src/media/video/video_input.cpp b/src/media/video/video_input.cpp index b8570340c24748623c5a9be603f692bc72ad6a8c..7542838d4e05fd731d12b456a2b02be979d84294 100644 --- a/src/media/video/video_input.cpp +++ b/src/media/video/video_input.cpp @@ -63,6 +63,8 @@ VideoInput::VideoInput() VideoInput::~VideoInput() { + if (auto rec = recorder_.lock()) + rec->stopRecording(); #if defined(__ANDROID__) || defined(RING_UWP) || (defined(TARGET_OS_IOS) && TARGET_OS_IOS) /* we need to stop the loop and notify the condition variable * to unblock the process loop */ @@ -206,7 +208,8 @@ bool VideoInput::captureFrame() if (not decoder_) return false; - const auto ret = decoder_->decode(getNewFrame()); + auto& frame = getNewFrame(); + const auto ret = decoder_->decode(frame); switch (ret) { case MediaDecoder::Status::ReadError: return false; @@ -229,6 +232,20 @@ bool VideoInput::captureFrame() return static_cast<bool>(decoder_); case MediaDecoder::Status::FrameFinished: + if (auto rec = recorder_.lock()) { + if (!recordingStarted_) { + if (rec->addStream(true, false, decoder_->getStream()) >= 0) { + recordingStarted_ = true; + } else { + recorder_ = std::weak_ptr<MediaRecorder>(); + } + } + if (recordingStarted_) + rec->recordData(frame.pointer(), true, false); + } else { + recordingStarted_ = false; + recorder_ = std::weak_ptr<MediaRecorder>(); + } publishFrame(); return true; // continue decoding @@ -590,8 +607,8 @@ VideoInput::foundDecOpts(const DeviceParams& params) void VideoInput::initRecorder(std::shared_ptr<MediaRecorder>& rec) { - if (decoder_) - decoder_->initRecorder(rec); + rec->incrementStreams(1); + recorder_ = rec; } }} // namespace ring::video diff --git a/src/media/video/video_input.h b/src/media/video/video_input.h index 4561b4e83b30501c81a31638107278d73589c0ca..a5871cceda0747f2d0388b12c87957d52b791b2e 100644 --- a/src/media/video/video_input.h +++ b/src/media/video/video_input.h @@ -143,6 +143,9 @@ private: void releaseBufferCb(uint8_t* ptr); std::array<struct VideoFrameBuffer, 8> buffers_; #endif + + std::weak_ptr<MediaRecorder> recorder_; + bool recordingStarted_{false}; }; }} // namespace ring::video diff --git a/src/media/video/video_receive_thread.cpp b/src/media/video/video_receive_thread.cpp index e7a83c4358bc81700d4437191f5fde88f0d49802..b03b106c7bd05443de6507142beabdb6000c0697 100644 --- a/src/media/video/video_receive_thread.cpp +++ b/src/media/video/video_receive_thread.cpp @@ -56,6 +56,8 @@ VideoReceiveThread::VideoReceiveThread(const std::string& id, VideoReceiveThread::~VideoReceiveThread() { + if (auto rec = recorder_.lock()) + rec->stopRecording(); loop_.join(); } @@ -166,10 +168,25 @@ void VideoReceiveThread::addIOContext(SocketPair& socketPair) bool VideoReceiveThread::decodeFrame() { - const auto ret = videoDecoder_->decode(getNewFrame()); + auto& frame = getNewFrame(); + const auto ret = videoDecoder_->decode(frame); switch (ret) { case MediaDecoder::Status::FrameFinished: + if (auto rec = recorder_.lock()) { + if (!recordingStarted_) { + if (rec->addStream(true, true, videoDecoder_->getStream()) >= 0) { + recordingStarted_ = true; + } else { + recorder_ = std::weak_ptr<MediaRecorder>(); + } + } + if (recordingStarted_) + rec->recordData(frame.pointer(), true, true); + } else { + recordingStarted_ = false; + recorder_ = std::weak_ptr<MediaRecorder>(); + } publishFrame(); return true; @@ -241,8 +258,8 @@ VideoReceiveThread::triggerKeyFrameRequest() void VideoReceiveThread::initRecorder(std::shared_ptr<ring::MediaRecorder>& rec) { - if (videoDecoder_) - videoDecoder_->initRecorder(rec); + rec->incrementStreams(1); + recorder_ = rec; } }} // namespace ring::video diff --git a/src/media/video/video_receive_thread.h b/src/media/video/video_receive_thread.h index 2c884d067bd309698517a7e0426b6dbce7b7641f..bc13ccd68706beecabb12ad6204f16fba2310583 100644 --- a/src/media/video/video_receive_thread.h +++ b/src/media/video/video_receive_thread.h @@ -89,6 +89,9 @@ private: static int interruptCb(void *ctx); static int readFunction(void *opaque, uint8_t *buf, int buf_size); + std::weak_ptr<MediaRecorder> recorder_; + bool recordingStarted_{false}; + ThreadLoop loop_; // used by ThreadLoop