44#include < MulNXExtensions/MediaSystem/AudioCapturer/AudioCapturer.hpp>
55#include < MulNXExtensions/MediaSystem/AEncodeHelper/AEncodeHelper.hpp>
66#include < MulNXExtensions/MediaSystem/VEncodeHelper/VEncodeHelper.hpp>
7+ #include < MulNXExtensions/MediaSystem/VCD3D11Manager/VCD3D11Manager.hpp>
8+ #include < MulNXExtensions/MediaSystem/MediaParamManager/MediaParamManager.hpp>
79
810void MediaRecorder::CaptureCallback (MulNX::UINode* node) {
9- ImGui::GetBackgroundDrawList ()->AddCallback ([](const ImDrawList* parent_list , const ImDrawCmd* cmd) {
11+ ImGui::GetBackgroundDrawList ()->AddCallback ([](const ImDrawList*, const ImDrawCmd* cmd) {
1012 static_cast <MediaRecorder*>(cmd->UserCallbackData )->PublishSync (" Hook/BeforePresent" _hash);
11- }, this , 0 );
13+ }, this , 0 );
1214}
1315
1416bool MediaRecorder::Init () {
15- this ->pVideoCapturer = this ->Core ->ModuleManager ()->FindModule <VideoCapturer>(" VideoCapturer" );
16- this ->pAudioCapturer = this ->Core ->ModuleManager ()->FindModule <AudioCapturer>(" AudioCapturer" );
17- this ->pVEncodeHelper = this ->Core ->ModuleManager ()->FindModule <VEncodeHelper>(" VEncodeHelper" );
18- this ->pAEncodeHelper = this ->Core ->ModuleManager ()->FindModule <AEncodeHelper>(" AEncodeHelper" );
17+ this ->pVideoCapturer = this ->Core ->ModuleManager ()->FindModule <VideoCapturer>(" VideoCapturer" );
18+ this ->pAudioCapturer = this ->Core ->ModuleManager ()->FindModule <AudioCapturer>(" AudioCapturer" );
19+ this ->pVEncodeHelper = this ->Core ->ModuleManager ()->FindModule <VEncodeHelper>(" VEncodeHelper" );
20+ this ->pAEncodeHelper = this ->Core ->ModuleManager ()->FindModule <AEncodeHelper>(" AEncodeHelper" );
21+ this ->pVCD3D11Manager = this ->Core ->ModuleManager ()->FindModule <VCD3D11Manager>(" VCD3D11Manager" );
22+ this ->pMediaParamManager = this ->Core ->ModuleManager ()->FindModule <MediaParamManager>(" MediaParamManager" );
1923
2024 this ->dirVedios = this ->Path ()->PathGetForShared (" Vedios" );
25+ (*this ).SubscribeAsync (" Media/Record/Start" ).SubscribeAsync (" Media/Record/Stop" );
2126
22- (*this )
23- .SubscribeAsync (" Media/Record/Start" )
24- .SubscribeAsync (" Media/Record/Stop" );
25-
26- this ->SendTask (" Main" , " Media" , [this ]() {
27- this ->Main ();
28- return true ;
29- });
30-
31- this ->SendUIRoot (" 捕获以上所有根触发的UI渲染" , [this ](MulNX::UINode* node) {return this ->CaptureCallback (node);});
32-
27+ this ->SendTask (" Main" , " Media" , [this ]() { this ->Main (); return true ; });
28+ this ->SendUIRoot (" 捕获以上所有根触发的UI渲染" ,
29+ [this ](MulNX::UINode* node) { this ->CaptureCallback (node); return true ; });
3330 return true ;
3431}
3532
3633void MediaRecorder::ProcessMsg (MulNX::Message& msg) {
3734 switch (msg.type ) {
38- case " Media/Record/Start" _hash: {
39- auto path = msg.asp .get <MulNX::NetExt>()->str1 ;
40- auto outFile = path + " .mp4" ;
41- this ->StartRecording (outFile, 1920 , 1080 );
35+ case " Media/Record/Start" _hash:
36+ this ->StartRecording (msg.asp .get <MulNX::NetExt>()->str1 );
4237 break ;
43- }
44- case " Media/Record/Stop" _hash: {
38+ case " Media/Record/Stop" _hash:
4539 this ->StopRecording ();
4640 break ;
4741 }
48- }
4942}
5043
51- bool MediaRecorder::StartRecording (const std::string& filename, int w, int h ) {
52- if (this ->runFlag1 ) {
53- this ->LogWarning ( " 已在录制中,StartRecording 被忽略 " );
54- return false ;
44+ bool MediaRecorder::StartRecording (const std::string& pathNoExt ) {
45+ if (this ->runFlag1 ) { this -> LogWarning ( " 已在录制中 " ); return false ; }
46+ if (! this -> pVCD3D11Manager || ! this ->pVideoCapturer || ! this -> pVEncodeHelper ) {
47+ this -> LogError ( " 模块缺失 " ); return false ;
5548 }
5649
57- if (!this ->pAudioCapturer || !this ->pVideoCapturer || !this ->pAEncodeHelper || !this ->pVEncodeHelper ) {
58- this ->LogError (" 录制启动失败:缺少音视频模块" );
59- return false ;
50+ RecordParams rp;
51+ if (this ->pMediaParamManager ) rp = this ->pMediaParamManager ->Params ();
52+
53+ std::string outFile = pathNoExt + " .mp4" ;
54+ int srcW = this ->pVCD3D11Manager ->srcWidth ;
55+ int srcH = this ->pVCD3D11Manager ->srcHeight ;
56+ av::PixelFormat srcFmt = DXGIFormatToAvPixelFormat (this ->pVCD3D11Manager ->srcDxgiFormat );
57+ if (srcW <= 0 || srcH <= 0 || srcFmt == AV_PIX_FMT_NONE ) {
58+ this ->LogError (" 源纹理参数无效" ); return false ;
6059 }
6160
62- // 清理旧缓存,保持录制起点对齐
61+ this -> pVCD3D11Manager -> SetCaptureFpsCap (rp. captureFpsCap );
6362 this ->pAudioCapturer ->ClearBuffer ();
6463 this ->pVideoCapturer ->ClearBuffer ();
6564 this ->pVideoCapturer ->Reset ();
6665 this ->pAEncodeHelper ->Reset ();
66+ this ->pVEncodeHelper ->Reset ();
6767
6868 try {
69- this ->ofctx .openOutput (filename );
69+ this ->ofctx .openOutput (outFile );
7070 this ->recordStartTime = std::chrono::steady_clock::now ();
71- this ->pVideoCapturer -> StartCapture (this ->recordStartTime );
71+ this ->pVCD3D11Manager -> SetRecordStart (this ->recordStartTime );
7272
73- this ->pVEncodeHelper ->SetOn (&this ->ofctx , w, h, this ->timeBase );
73+ this ->pVEncodeHelper ->SetOn (&this ->ofctx , rp, srcW, srcH, srcFmt,
74+ this ->pVCD3D11Manager ->pDevice .Get (),
75+ rp.captureFpsCap > 0 ? rp.captureFpsCap : 0 );
7476 this ->pAEncodeHelper ->SetOn (&this ->ofctx , this ->pAudioCapturer ->GetSampleRate ());
7577
76- // 写文件头(即使只有视频流)
7778 this ->ofctx .writeHeader ();
78- this ->LogWarning (std::format (" 输出文件头已写入,流数量={}" , this ->ofctx .streamsCount ()));
79-
79+ this ->LogInfo (std::format (" 输出头已写入, 流数={}" , this ->ofctx .streamsCount ()));
80+
81+ bool hwPath = this ->pVEncodeHelper ->IsHwAccel ();
82+ this ->pVideoCapturer ->StartCapture (this ->recordStartTime , hwPath);
83+ this ->LogSucc (std::format (" 开始录制: {} ({}x{} {}{})" , outFile,
84+ rp.width > 0 ? rp.width : srcW, rp.height > 0 ? rp.height : srcH,
85+ rp.captureFpsCap > 0 ? std::to_string (rp.captureFpsCap )+" fps " : " " ,
86+ hwPath ? " 零拷贝" : " CPU读回" ));
8087 this ->runFlag1 = true ;
81- this ->LogSucc (" 已开始录制: " + filename);
8288 return true ;
83- }
84- catch (const std::exception& e) {
85- this ->LogError (std::string (" 录制启动失败: " ) + e.what ());
89+ } catch (const std::exception& e) {
90+ this ->LogError (std::format (" 启动失败: {}" , e.what ()));
8691 this ->ofctx .close ();
8792 return false ;
8893 }
@@ -91,95 +96,69 @@ bool MediaRecorder::StartRecording(const std::string& filename, int w, int h) {
9196void MediaRecorder::Main () {
9297 this ->Update ();
9398 if (!this ->runFlag1 ) return ;
94-
9599 this ->Encode ();
96100}
97101
98- static int64_t TimestampInMicroseconds (const av::Timestamp & ts) {
99- return ts.isValid () ? ts.timestamp ({1 , 1000000 }) : std::numeric_limits< int64_t >:: max () ;
102+ static int64_t PtsUs (const av::Timestamp& ts) {
103+ return ts.isValid () ? ts.timestamp ({1 ,1000000 }) : INT64_MAX ;
100104}
101105
102106void MediaRecorder::Encode () {
103107 std::vector<av::Packet> packets;
104108
105- // 视频编码
106- while (auto opFrame = this ->pVideoCapturer ->TryPop ()) {
107- this ->pVEncodeHelper ->CheckRescaler (
108- this ->pVideoCapturer ->stagingWidth , this ->pVideoCapturer ->stagingHeight ,
109- this ->pVideoCapturer ->srcPixelFormat );
109+ while (auto f = this ->pVideoCapturer ->TryPop ())
110+ if (auto p = this ->pVEncodeHelper ->Encode (std::move (*f)))
111+ packets.push_back (std::move (*p));
110112
111- if (auto pkt = this ->pVEncodeHelper ->Encode (*opFrame)) {
112- packets.push_back (std::move (*pkt));
113- }
113+ while (auto a = this ->pAudioCapturer ->TryPop ()) {
114+ if (a->samplesCount () > 0 )
115+ if (auto p = this ->pAEncodeHelper ->Encode (std::move (*a)))
116+ packets.push_back (std::move (*p));
114117 }
115118
116- // 音频编码
117- while (auto opAudio = this ->pAudioCapturer ->TryPop ()) {
118- if (opAudio->samplesCount () > 0 ) {
119- if (auto pkt = this ->pAEncodeHelper ->Encode (std::move (*opAudio))) {
120- packets.push_back (std::move (*pkt));
121- }
122- }
123- }
119+ if (packets.empty ()) return ;
120+ std::sort (packets.begin (), packets.end (),
121+ [](const av::Packet& l, const av::Packet& r) { return PtsUs (l.dts ()) < PtsUs (r.dts ()); });
124122
125- if (packets.empty ()) {
126- return ;
127- }
128-
129- std::sort (packets.begin (), packets.end (), [](const av::Packet &left, const av::Packet &right) {
130- return TimestampInMicroseconds (left.pts ()) < TimestampInMicroseconds (right.pts ());
131- });
132-
133- for (auto &pkt : packets) {
134- try {
135- this ->ofctx .writePacket (pkt);
136- }
123+ for (auto & pkt : packets) {
124+ try { this ->ofctx .writePacket (pkt); }
137125 catch (const std::exception& e) {
138- this ->LogWarning (std::format (" 写入 packet 失败 : {}, 跳过该包 " , e.what ()));
126+ this ->LogWarning (std::format (" 写包失败 : {}" , e.what ()));
139127 }
140128 }
141129}
142130
143131bool MediaRecorder::StopRecording () {
144132 if (!this ->runFlag1 ) return false ;
145-
146133 this ->runFlag1 = false ;
147134 this ->pVideoCapturer ->StopCapture ();
148135
149136 try {
150- // Drain pending captured video frames before flushing the encoder.
151- while (auto opFrame = this ->pVideoCapturer ->TryPop ()) {
152- if (auto pkt = this ->pVEncodeHelper ->Encode (*opFrame)) {
153- this ->ofctx .writePacket (*pkt);
154- }
155- }
156-
157- while (auto pkt = this ->pVEncodeHelper ->TrySetOff ()) {
158- this ->ofctx .writePacket (*pkt);
159- }
160-
161- while (auto opAudio = this ->pAudioCapturer ->TryPop ()) {
162- if (opAudio->samplesCount () > 0 ) {
163- if (auto pkt = this ->pAEncodeHelper ->Encode (std::move (*opAudio))) {
164- this ->ofctx .writePacket (*pkt);
165- }
166- }
167- }
168-
169- while (auto pkt = this ->pAEncodeHelper ->TrySetOff ()) {
170- this ->ofctx .writePacket (*pkt);
171- }
172- }
173- catch (const std::exception& e) {
174- this ->LogWarning (std::string (" 停止录制时捕获到异常: " ) + e.what ());
137+ while (auto f = this ->pVideoCapturer ->TryPop ())
138+ if (auto p = this ->pVEncodeHelper ->Encode (std::move (*f)))
139+ this ->ofctx .writePacket (*p);
140+ while (auto p = this ->pVEncodeHelper ->TrySetOff ())
141+ this ->ofctx .writePacket (*p);
142+ while (auto a = this ->pAudioCapturer ->TryPop ())
143+ if (a->samplesCount () > 0 )
144+ if (auto p = this ->pAEncodeHelper ->Encode (std::move (*a)))
145+ this ->ofctx .writePacket (*p);
146+ while (auto p = this ->pAEncodeHelper ->TrySetOff ())
147+ this ->ofctx .writePacket (*p);
148+ } catch (const std::exception& e) {
149+ this ->LogWarning (std::format (" 停止时异常: {}" , e.what ()));
175150 }
176151
177152 this ->ofctx .writeTrailer ();
178-
153+ uint64_t dropped = this ->pVCD3D11Manager ->droppedFrames .load ();
154+ if (dropped > 0 )
155+ this ->LogWarning (std::format (" 丢帧: {}" , dropped));
156+ else
157+ this ->LogSucc (" 无丢帧" );
158+ this ->pVCD3D11Manager ->droppedFrames .store (0 );
179159 this ->pVideoCapturer ->Reset ();
180-
181160 this ->pAEncodeHelper ->Reset ();
182-
161+ this -> pVEncodeHelper -> Reset ();
183162 this ->ofctx .close ();
184163 return true ;
185- }
164+ }
0 commit comments