Skip to content

Commit 891887a

Browse files
committed
AVI write thread
1 parent 4168a5f commit 891887a

File tree

4 files changed

+180
-9
lines changed

4 files changed

+180
-9
lines changed

MLDX12VideoCapture/MLAviWriter.cpp

Lines changed: 140 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
#include "MLAviWriter.h"
22
#include <assert.h>
3+
#include "WinApp.h"
34

45
namespace {
56
struct AviMainHeader {
@@ -104,10 +105,26 @@ namespace {
104105

105106
MLAviWriter::MLAviWriter(void)
106107
: mFp(nullptr), mLastRiffIdx(-1), mLastMoviIdx(-1)
107-
{}
108+
{
109+
mState = AVIS_Init;
110+
m_thread = nullptr;
111+
m_shutdownEvent = CreateEventEx(nullptr, nullptr, 0, EVENT_MODIFY_STATE | SYNCHRONIZE);
112+
m_readyEvent = CreateEventEx(nullptr, nullptr, 0, EVENT_MODIFY_STATE | SYNCHRONIZE);
113+
}
108114

109115

110-
MLAviWriter::~MLAviWriter(void) {}
116+
MLAviWriter::~MLAviWriter(void)
117+
{
118+
if (nullptr != m_readyEvent) {
119+
CloseHandle(m_readyEvent);
120+
m_readyEvent = nullptr;
121+
}
122+
123+
if (nullptr != m_shutdownEvent) {
124+
CloseHandle(m_shutdownEvent);
125+
m_shutdownEvent = nullptr;
126+
}
127+
}
111128

112129
void MLAviWriter::WriteFccHeader(const char *fccS, int bytes) {
113130
uint32_t fcc = StringToFourCC(fccS);
@@ -164,27 +181,37 @@ bool MLAviWriter::Init(std::wstring path, int width, int height, int fps, ImageF
164181

165182
mTotalFrames = 0;
166183

184+
StartThread();
167185
return true;
168186
}
169187

170188
static const uint32_t FCC_00db = 0x62643030;
171189

172190
void MLAviWriter::AddImage(const uint32_t * img, int bytes) {
173191
assert(mFp != nullptr);
192+
assert(m_readyEvent != nullptr);
174193

175-
if ((mTotalFrames % 30) == 29) {
176-
RestartRiff();
194+
if (mState != AVIS_Writing) {
195+
return;
177196
}
178197

179-
WriteStreamDataHeader(FCC_00db, bytes);
180-
fwrite(img, 1, bytes, mFp);
198+
ImageItem ii;
199+
ii.buf = new uint32_t[bytes / 4];
200+
ii.bytes = bytes;
201+
memcpy(ii.buf, img, bytes);
181202

182-
++mTotalFrames;
203+
m_mutex.lock();
204+
mImageList.push_back(ii);
205+
m_mutex.unlock();
206+
207+
SetEvent(m_readyEvent);
183208
}
184209

185210
void MLAviWriter::Term(void) {
186211
assert(mFp != nullptr);
187212

213+
StopThread();
214+
188215
FinishList(mLastMoviIdx);
189216
FinishRiff(mLastRiffIdx);
190217

@@ -198,6 +225,14 @@ void MLAviWriter::Term(void) {
198225
mFp = nullptr;
199226
}
200227

228+
int MLAviWriter::RecQueueSize(void) {
229+
int count;
230+
m_mutex.lock();
231+
count = (int)mImageList.size();
232+
m_mutex.unlock();
233+
return count;
234+
235+
}
201236

202237
int MLAviWriter::WriteRiff(const char *fccS) {
203238
uint32_t fcc = StringToFourCC(fccS);
@@ -364,4 +399,101 @@ void MLAviWriter::RestartRiff(void) {
364399

365400
mLastRiffIdx = WriteRiff("AVIX");
366401
mLastMoviIdx = WriteList("movi");
367-
}
402+
}
403+
404+
// ============================================================
405+
// thread
406+
407+
void MLAviWriter::StartThread(void)
408+
{
409+
if (m_thread != nullptr) {
410+
return;
411+
}
412+
413+
mState = AVIS_Writing;
414+
m_thread = CreateThread(nullptr, 0, AviWriterEntry, this, 0, nullptr);
415+
}
416+
417+
void MLAviWriter::StopThread(void) {
418+
if (m_thread == nullptr) {
419+
return;
420+
}
421+
422+
mState = AVIS_Init;
423+
424+
assert(m_shutdownEvent != nullptr);
425+
SetEvent(m_shutdownEvent);
426+
WaitForSingleObject(m_thread, INFINITE);
427+
CloseHandle(m_thread);
428+
m_thread = nullptr;
429+
}
430+
431+
432+
DWORD WINAPI
433+
MLAviWriter::AviWriterEntry(LPVOID param) {
434+
MLAviWriter *self = (MLAviWriter *)param;
435+
436+
return self->ThreadMain();
437+
}
438+
439+
DWORD
440+
MLAviWriter::ThreadMain(void) {
441+
DWORD rv = 0;
442+
CoInitializeEx(nullptr, COINIT_MULTITHREADED);
443+
HANDLE waitAry[2] = {m_shutdownEvent, m_readyEvent};
444+
DWORD waitRv;
445+
446+
while (true) {
447+
waitRv = WaitForMultipleObjects(2, waitAry, FALSE, INFINITE);
448+
if (waitRv == WAIT_OBJECT_0) {
449+
// flush remaining items.
450+
WriteAll();
451+
OutputDebugStringA("MLAviWriter::ThreadMain() exit\n");
452+
break;
453+
}
454+
455+
// ready event
456+
WriteAll();
457+
}
458+
459+
CoUninitialize();
460+
return rv;
461+
}
462+
463+
void
464+
MLAviWriter::WriteAll(void) {
465+
ImageItem ii;
466+
467+
m_mutex.lock();
468+
int count = (int)mImageList.size();
469+
m_mutex.unlock();
470+
471+
while (0 < count) {
472+
m_mutex.lock();
473+
ii = mImageList.front();
474+
mImageList.pop_front();
475+
m_mutex.unlock();
476+
477+
WriteOne(ii);
478+
delete[] ii.buf;
479+
ii.buf = nullptr;
480+
481+
m_mutex.lock();
482+
count = (int)mImageList.size();
483+
m_mutex.unlock();
484+
}
485+
}
486+
487+
void
488+
MLAviWriter::WriteOne(ImageItem& ii)
489+
{
490+
if ((mTotalFrames % 30) == 29) {
491+
RestartRiff();
492+
}
493+
494+
WriteStreamDataHeader(FCC_00db, ii.bytes);
495+
fwrite(ii.buf, 1, ii.bytes, mFp);
496+
497+
++mTotalFrames;
498+
}
499+

MLDX12VideoCapture/MLAviWriter.h

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,9 @@
44
#include <stdint.h>
55
#include <vector>
66
#include <stdio.h>
7+
#include "Common.h"
8+
#include <list>
9+
#include <mutex>
710

811
class MLAviWriter {
912
public:
@@ -22,13 +25,22 @@ class MLAviWriter {
2225

2326
bool IsOpen(void) const { return mFp != nullptr; }
2427

28+
int RecQueueSize(void);
29+
2530
private:
2631

2732
int mWidth;
2833
int mHeight;
2934
int mFps;
3035
int mImgFmt;
3136

37+
enum AVIState {
38+
AVIS_Init,
39+
AVIS_Writing,
40+
};
41+
42+
AVIState mState;
43+
3244
struct RiffChunk {
3345
uint64_t pos;
3446
uint64_t size;
@@ -44,6 +56,13 @@ class MLAviWriter {
4456
std::vector<RiffChunk> mRiffChunks;
4557
std::vector<ListChunk> mListChunks;
4658

59+
struct ImageItem {
60+
uint32_t *buf;
61+
int bytes;
62+
};
63+
64+
std::list<ImageItem> mImageList;
65+
4766
int mLastRiffIdx;
4867
int mLastMoviIdx;
4968

@@ -71,5 +90,17 @@ class MLAviWriter {
7190
void RestartRiff(void);
7291

7392
FILE *mFp;
93+
94+
std::mutex m_mutex;
95+
HANDLE m_thread;
96+
HANDLE m_shutdownEvent;
97+
HANDLE m_readyEvent;
98+
static DWORD WINAPI AviWriterEntry(LPVOID param);
99+
DWORD ThreadMain(void);
100+
void WriteAll(void);
101+
void WriteOne(ImageItem& ii);
102+
void StartThread(void);
103+
void StopThread(void);
104+
74105
};
75106

MLDX12VideoCapture/MLDX12App.cpp

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ MLDX12App::MLDX12App(UINT width, UINT height) :
3939
m_frameSkipCount(0)
4040
{
4141
strcpy_s(m_writePath, "c:/data/output.avi");
42+
m_msg[0] = 0;
4243
}
4344

4445
void MLDX12App::OnInit()
@@ -750,6 +751,7 @@ MLDX12App::ImGuiCommands(void)
750751
BMDPixelFormat pixFmt = m_videoCapture.PixelFormat();
751752
if (bmdFormat10BitYUV == pixFmt) {
752753
ImGui::InputText("Record filename", m_writePath, sizeof m_writePath - 1);
754+
ImGui::Text(m_msg);
753755
if (ImGui::Button("Record")) {
754756
wchar_t path[512];
755757
memset(path, 0, sizeof path);
@@ -760,6 +762,9 @@ MLDX12App::ImGuiCommands(void)
760762
MLAviWriter::IF_YUV422v210);
761763
if (bRv) {
762764
m_state = S_Recording;
765+
m_msg[0] = 0;
766+
} else {
767+
sprintf_s(m_msg, "File open error : %s", m_writePath);
763768
}
764769
}
765770
}
@@ -775,11 +780,12 @@ MLDX12App::ImGuiCommands(void)
775780
}
776781
m_mutex.unlock();
777782

778-
ImGui::Text("Queue size : %d", queueSize);
783+
ImGui::Text("Draw Queue size : %d", queueSize);
779784
ImGui::Text("Frame skip count : %lld", m_frameSkipCount);
780785

781786
if (m_state == S_Recording) {
782787
ImGui::Text("Now Recording...");
788+
ImGui::Text("Rec Queue size : %d", m_aviWriter.RecQueueSize());
783789
if (ImGui::Button("Stop Recording")) {
784790
m_state = S_Capturing;
785791

MLDX12VideoCapture/MLDX12App.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,8 @@ class MLDX12App : public MLDX12, IMLVideoCaptureCallback {
142142

143143
char m_writePath[512];
144144

145+
char m_msg[512];
146+
145147
void LoadPipeline(void);
146148
void LoadAssets(void);
147149
void PopulateCommandList(void);

0 commit comments

Comments
 (0)