#include "video_recorder.h" #include "avrecorder/capturer/video/VideoCaptureManager.h" #include #include using namespace avrecorder::video; bool VideoRecorder::Open(HWND srcHwnd, Encoder::Param& param, CaptureMethod method) { CaptureTarget target; target.type = CaptureTargetType::Window; target.hwnd = srcHwnd; RECT clientRect; if (!GetClientRect(srcHwnd, &clientRect)) return false; int width = clientRect.right - clientRect.left; int height = clientRect.bottom - clientRect.top; _capturer.open(target, method, width, height); return _Open(param); } bool VideoRecorder::Open(int monitorIdx, Encoder::Param& param, CaptureMethod method) { CaptureTarget target; target.type = CaptureTargetType::Monitor; target.monitorIdx = monitorIdx; auto monitorInfo = MonitorFinder::GetList()[monitorIdx]; RECT rect = monitorInfo.rect; int width = rect.right - rect.left; int height = rect.bottom - rect.top; _capturer.open(target, method, width, height); return _Open(param); } bool VideoRecorder::_Open(Encoder::Param& param) { __CheckBool(_encodeFrame = Frame::Alloc(AV_PIX_FMT_NV12, _capturer.getFrame() ? _capturer.getFrame()->width : param.width, _capturer.getFrame() ? _capturer.getFrame()->height : param.height)); { std::lock_guard renderLk(_renderMtx); __CheckBool(_renderFrame = Frame::Alloc(AV_PIX_FMT_NV12, _capturer.getFrame() ? _capturer.getFrame()->width : param.width, _capturer.getFrame() ? _capturer.getFrame()->height : param.height)); } // 捕获定时器和帧获取逻辑 _captureTimer.Start(param.fps, [this] { auto srcFrame = _capturer.getFrame(); if (srcFrame != nullptr) { std::lock_guard muxLk(__mtx); if (srcFrame->format != _encodeFrame->format) { std::lock_guard renderLk(_renderMtx); Free(_encodeFrame, [this] { av_frame_free(&_encodeFrame); }); __CheckNo( _encodeFrame = Frame::Alloc(AVPixelFormat(srcFrame->format), srcFrame->width, srcFrame->height)); } av_frame_copy(_encodeFrame, srcFrame); } }); param.width = _capturer.getFrame() ? _capturer.getFrame()->width : param.width; param.height = _capturer.getFrame() ? _capturer.getFrame()->height : param.height; _param = param; return true; } AVFrame* VideoRecorder::GetRenderFrame() { std::lock_guard renderLk(_renderMtx); if (_encodeFrame == nullptr) { return nullptr; } if (_renderFrame->format != _encodeFrame->format) { Free(_renderFrame, [this] { av_frame_free(&_renderFrame); }); _renderFrame = Frame::Alloc(AVPixelFormat(_encodeFrame->format), _encodeFrame->width, _encodeFrame->height); } av_frame_copy(_renderFrame, _encodeFrame); return _renderFrame; } bool VideoRecorder::LoadMuxer(AvMuxer& muxer) { _muxer = &muxer; __CheckBool((_streamIndex = muxer.AddVideoStream(_param)) != -1); return true; } bool VideoRecorder::StartRecord() { _totalPts = 0; _lossPts = 0; _lossHistory.clear(); _muxTimer.Start(_param.fps, [this] { ++_totalPts; bool loss = !_muxer->Write(_encodeFrame, _streamIndex); if (loss) ++_lossPts; _lossHistory.push_back(loss); if (_lossHistory.size() > LOSS_WINDOW) _lossHistory.pop_front(); }); _isRecord = true; return true; } void VideoRecorder::StopRecord() { _isRecord = false; _muxTimer.Stop(); } double VideoRecorder::GetLossRate() { if (_lossHistory.size() < LOSS_WINDOW) return -1.0; // 统计中 int lossCount = std::count(_lossHistory.begin(), _lossHistory.end(), true); return double(lossCount) / _lossHistory.size(); } void VideoRecorder::Close() { StopRecord(); _captureTimer.Stop(); _capturer.close(); Free(_encodeFrame, [this] { av_frame_free(&_encodeFrame); }); Free(_renderFrame, [this] { av_frame_free(&_renderFrame); }); } void VideoRecorder::SetCaptureSource(HWND srcHwnd, CaptureMethod method) { // 只切换采集源,不重启编码器和推流 CaptureTarget target; target.type = CaptureTargetType::Window; target.hwnd = srcHwnd; RECT clientRect; if (!GetClientRect(srcHwnd, &clientRect)) return; int width = clientRect.right - clientRect.left; int height = clientRect.bottom - clientRect.top; _capturer.open(target, method, width, height); } void VideoRecorder::SetCaptureSource(int monitorIdx, CaptureMethod method) { // 只切换采集源,不重启编码器和推流 CaptureTarget target; target.type = CaptureTargetType::Monitor; target.monitorIdx = monitorIdx; auto monitorInfo = MonitorFinder::GetList()[monitorIdx]; RECT rect = monitorInfo.rect; int width = rect.right - rect.left; int height = rect.bottom - rect.top; _capturer.open(target, method, width, height); }