VOGONS


Multithreaded video capturing

Topic actions

Reply 21 of 47, by xcomcmdr

User metadata
Rank Oldbie
Rank
Oldbie

As we know, DOSBox outputs 70 FPS, in wich second there is a lot of frame that are the same, and follow each other.

I have tried to avoid compressing the frame if it was the same as the previous frame (if it is, just use the old compressed frame).

In order to achieve this, I have tried to keep the resulting compressed and uncompressed frames in memory, and test if the current uncompressed frame is the same as the old compressed frame, but failed everywhere... Every time, I borked the encoding after the first frame...

All of it was inside hardware.cpp... (I discarded it all since nothing worked). I've tried with the 'official' hardware.cpp and the multithreaded version. For a long time, I may add. 😵

I still think it's possible, but I a am asking if someone else (kekko ?) may be able to do it ? 😉

The resulting speed gain can be very good, I think. It may even stop the pauses in the current multithreaded video capturing method.

PS : I am unable, in fact, to run multithreaded video capturing (let's name it MVC)-patched DOSBox I produced with VS 2008 SP1 without a crash soon after I started recording... =(

I think that, once the 400 waiting frames limit is hit, it crashes... My Windows 7 x64 says "DOSBox stopped to run".

I've disabled Windows' DEP (data execution prevention), recompiled SDL.dll, SDL_net.dll, all the libs, and DOSBox with and without any optimization (in Project -> Properties -> Linker, mainly, plus SSE2 optimization), without any effect... I don't know what to do. It seemed to work fine for a time. 😢

And now, I'm back to the not-MVC-patched DOSBox.exe (compiled with all optimizations though, but it doesn't make much difference with video capturing)... 🙁

Reply 23 of 47, by xcomcmdr

User metadata
Rank Oldbie
Rank
Oldbie

zmbv already uses difference-encoding, so how much would additionally checking for unchanged frames help?

mhh, it stills deflates (compress) it. Avoid compression and simply copy once again the previous same compressed frame (keept in memory), is the idea. Would it not speed up things ?

It may have more to do with zmbv.cpp than hardware.cpp, or it may involve a modification of both..

I may be saying crappy things here (I still don't understand fully hardware.cpp and zmbv.cpp..), I'm just guessing since video compression is my hobby (along with coding)...

Reply 25 of 47, by xcomcmdr

User metadata
Rank Oldbie
Rank
Oldbie

that's fast with 320x200 games sure. But not that much with 3D games. Even with the multithreaded video capturing patch by kekko, 3D games (especially thoses in 640x400 / SVGA) hit the 400 waiting frames limit quite often during a recording (wich, every time, stops emulation for a few seconds).

At least that's the case on my machine.

Again, I've tried to hack that myself, but failed. I'm still pretty sure that it's possible, so I'm giving the idea to anyone who wants and has the time. 😉

Reply 26 of 47, by wd

User metadata
Rank DOSBox Author
Rank
DOSBox Author

that's fast with 320x200 games sure. But not that much with 3D games.

Well are you sure that "detecting that frame x equals x-1" is cheaper than "just have zlib compress those zeros"?
Imo this should not be a problem, but don't know.

Reply 27 of 47, by xcomcmdr

User metadata
Rank Oldbie
Rank
Oldbie

I was hoping to detect it fast enough (memory compare with rowPointer in hardware.cpp, or something). But all I did was garbage. Someone more qualified may find a way.

Because, 2D games only use 10 FPS, or 15 for most recent 3D ones (Quake, Screamer Rally...). I don't want to change DOSBox 70 FPS output to a lower FPS, but :

You can see it if you record, for example, Day of the Tentacle. Not a single unique frame is lost when doing an AviSynth script as follow :

AVISource("D:\DOTT_000.AVI")
ChangeFPS(10)
ConverttoYV12()

(see http://avisynth.org/mediawiki/AssumeFPS#ChangeFPS )
(see this page and post on Doom9 : http://forum.doom9.org/showpost.php?p=1325028&postcount=344 )

That's why I feel that avoiding compression would be beneficial. But I don't know for sure. I don't master at all DOSBox' hardware/zmbv code despite my numerous retries.

Reply 28 of 47, by xcomcmdr

User metadata
Rank Oldbie
Rank
Oldbie

If someone has the same problem, wich is :

PS : I am unable, in fact, to run multithreaded video capturing (let's name it MVC)-patched DOSBox I produced with VS 2008 SP1 without a crash soon after I started recording... =( [...]

Somehow, compiling DOSBox with the multithreaded hardware.cpp patch and all the libs (libpng, zmbv, SDL, SDL_sound, SDL_net, zlib) with Visual Studio 2010 C++ Express fixed it. Used all the optimization options (such as using SSE2) for the compiler and linker in the Properties sheet.

I had also to change thoses lines :

			if (abs(target-et4k.clockFreq[i]) < dist) {
best = i;
dist = abs(target-et4k.clockFreq[i]);
}
}

to :

			if (abs(long(target-et4k.clockFreq[i])) < dist) {
best = i;
dist = abs(long(target-et4k.clockFreq[i]));
}
}

in vga_tseng.cpp so it resolved an ambiguous call of std::abs.

Reply 29 of 47, by Kisai

User metadata
Rank Member
Rank
Member

Sorry if I'm coming out of nowhere to reply.

I've been trying to assemble a version of dosbox that is "safe for youtube,etc" (10 minute avi auto-limits, and some other ideas I want to try,) and I tried this patch and discovered that enabling it results in handles leaking, where as turning it back off (C_THREADED_CAPTURE=0) eliminates the handles leaking.

Running a game for about 20 minutes, results in no net gain in handles when turned off.

Running the same game with the same configuration but the threaded capture on, results in leaking more than 50 handles per second. This is just looking at task manager in windows.

Threading's not my forte, but I think this explains the crashing.

Reply 30 of 47, by kekko

User metadata
Rank Oldbie
Rank
Oldbie

Thank you for reporting. That happens when you capture a low res video; dosbox ends the frame capturing too soon, thus at the next frame another thread is started, but the resources of the previous thread are not fully released.
I'm not sure this is related to any crash, though.
An option would be implementing some sort of thread pool, or maybe this would be enough:

		if (!capture.video.thread_running) {
SDL_WaitThread(video_thread, NULL);
video_thread = SDL_CreateThread(CAPTURE_VideoThread, (void*)&capture.video);
}

Reply 32 of 47, by xcomcmdr

User metadata
Rank Oldbie
Rank
Oldbie

Thanks Kekko for your patch, I will try that right away ('cause in fact, compiling with VS 2010 changed nearly nothing, despites my first few tests wich were unbelievably crash free)

@Kisai : try 3D games (or even 3D fast racing games, like Screamer 1, 2, or Screamer Rally).

Reply 33 of 47, by Kisai

User metadata
Rank Member
Rank
Member

hmm among other things, I think the problem may actually be in the codec itself.

I compiled a 32bit (and a 64bit), with and without the zlib asm version of the ZMBV codec and ran it through virtualdub using footage from the same game it was captured from, and it only uses one core.

Also of a trivial nature, using zmbv with something like camstudio also only uses one core (I get at most 13fps compared to LZO based camstudio codec at 15 when trying to grab a HD sized frame), and the exact same code is used by dosbox. So offloading to the thread, acts as an asynchronous compression buffer within dosbox, but the codec itself needs to be re-engineered to take advantage of threading too.

Reply 34 of 47, by xcomcmdr

User metadata
Rank Oldbie
Rank
Oldbie

I *think* I have finally squashed that ever lasting crash bug that affected (since the beginning) my builds of your patch, kekko, if you allow me to say so ( ^^ ), with that if statement:

int CAPTURE_VideoThread(void *videohandleptr){
[...]
if(videohandle->q.size()>0)
{
free(videohandle->q.front().videobuf);
free(videohandle->q.front().audiobuf);
free(videohandle->q.front().pal);
}
[...]
}

I was able to record the full intro of Z (RTS game by the Bitmap Brothers, 1996), where as before it crashed early on.

It seems to only have affected my computer, and judging by the code, my (noobish) *theory* is that sometimes during recording (or when DOSBox window isn't focused) the emulation of DOSBox stops for split-seconds, almost on a regular basis. And when it happens, the queue of the videohandle is empty. Therefore, it crashed when attempting to free the top.

Anyway, just reporting... 😉

edit: BTW, if along with the previous added code, I don't replace this:

if (!capture.video.thread_running) {
SDL_WaitThread(video_thread, NULL);
video_thread = SDL_CreateThread(CAPTURE_VideoThread, (void*)&capture.video);
}

by the old code, wich is :

if (!capture.video.thread_running) {
video_thread = SDL_CreateThread(CAPTURE_VideoThread, (void*)&capture.video);
}

It will continue to crash.

And DOSBox's memory usage is kind of huge (110 Mb after 20 seconds of recording), but stable (100 Mb now and still recording since 3 minutes!) 😁

edit2: Fix confirmed I guess. I was able to record Dune 2 for 5 minutes. 😊

edit3 : Building configuration : VS 2010 Ultimate RTM x86, DOSBox 0.74 source code + latest multithreaded hardware.cpp patch.

Reply 35 of 47, by wd

User metadata
Rank DOSBox Author
Rank
DOSBox Author

There are tools/lib configurations around to check for such invalid operations.
See for example http://msdn.microsoft.com/en-us/library/Aa271695
(_CrtCheckMemory comes handy to manually encircle memory overwriting).

Reply 36 of 47, by xcomcmdr

User metadata
Rank Oldbie
Rank
Oldbie

Thanks wd. ^^

But don't mind my previous "fix". Crashes occured after a while if the player was actually playing, not staring. 😁

Besides, that "if(videohandle->q.size()>0)" was useless 'cause the loop says "while (!videohandle->q.empty())"

However, I don't know how it made me record for so long. 😮

Anyway, I finally managed to make DOSBox only record 10 frames per second (wich is OK for DOS games, and makes recording 3D racing games possible), without having to lower the rendering fps, or even touch anything else than hardware.cpp. It's dirty (I use a global-scope variable and a big if statement), but it's only 5/6 lines of code, and it works!

With only 10 frames per second to record, there is no more emulation stops because of a full queue. Some "split-second-with-no-messages-stops" are still there though, but that's another riddle for another day.

Code is attached to this post. Sample video here
diff (WinDiff output, I could not save it to a text file! 😕 ) :
diffy.th.jpg
PS : So far, no crashes while recording and playing at the same time.

Attachments

  • Filename
    hardware.cpp
    File size
    29 KiB
    Downloads
    163 downloads
    File comment
    10 FPS recording version.
    File license
    Fair use/fair dealing exception

Reply 38 of 47, by xcomcmdr

User metadata
Rank Oldbie
Rank
Oldbie

that's an option to use if the emulation is too slow, isn't it ? Not my case. 😉

My problem was a double one : video recording was in the same thread as emulation - second CPU core unused - (hence this thread that I found).
And I had to use AviSynth to process the recorded videos with "ChangeFPS(10)" (and that low framerate didn't skip any unique frame, so that meant recording at 70 FPS was too much).

😉

Reply 39 of 47, by Qbix

User metadata
Rank DOSBox Author
Rank
DOSBox Author

frameskip skips frames from being rendered.
Which might be the same as what you want.

Water flows down the stream
How to ask questions the smart way!