When being called by the Indian "Microsoft" department I let them join in on my VirtualBox virtual machine, and started a video capture to catch any details on them. Doing so, VirtualBox creates .webm video files.
However, when I now play back that webm file, I see it got mangled right where I changed the VM's resolution. The session lasted an hour (phew...), and at the end I managed to thwart their futile hack attempts at setting a system password on my machine, and instead logged back into the connection they then broke. I think I then saw some full-screen dashboard environment - maybe theirs? Could have some very handy info it this is true!
The mangling seems like it's just a scanline-length issue in the video stream. Tricky thing here is that the video itself is all correctly in 1024x768 resolution, but the payload is just an 800x600 area in the middle (with black borders around it). That inner area is what got messed up further in the video. The black borders remain OK, so it's just VirtualBox's source data stream for the middle part that got misaligned.
Does anyone know of some procedure or software I could use to try to de-mangle this video? I've already seen that webm video files use a Matroska-based standard and use an EBML coding; I've already tried changing some headers values in the EBML structure to fudge the display resolution (making the black borders misaligned but the middle payload OK), but that led nowhere fast (each 5 secs of video or such has it's own header block as well).
Addition:
To be precise: the video was rendered at 1024x786 pixels, while the virtual machine ran at 800x600. This results in a fat black border surrounding the inner captured content during the entire video. Once I increased the virtual machine's window size (to, say, 1200x650 - really couldn't say exactly), the black border remained the same in size, only the inner content in it gets mangled. With mangled I mean that it looks like it displays the now longer scan lines of 1200 pixels and wraps them in the 800 scanline length, thus each next real scanline gets offset by the horizontal size difference since the previous line is wrapped in it. Or at least, that's what I thought initially, but looking at it again I'm having my doubts on that theory as well.
Well - that's not clear at all :) I've uploaded a frame here:
and a short video fragment here:
short fragment of scam video
(the issue happens halfway through the fragment)
But, to be honest, I think I'd better give up. I start to suspect that the only possible fix is to do pixelgrabbing in the old frames and build a new video out of that, if that's even a fix - i.e. too much effort. Shame, though, since I'd really like to review the content at the end...
Solution:
Thanks to bukkojot, I've come up with the follow (Windows targetted) app that fits in the middle of the ffmpeg cmdline he gave; maybe someone may find it useful? Note that the "RGB24" in the cmdline must be "rgb24" when using the latest ffmpeg version on Windows, which brings the cmdline I used to:
ffmpeg.exe -i scamvideo_problem.webm -f rawvideo -pix_fmt rgb24 pipe: | restorer.exe | ffmpeg -f rawvideo -pix_fmt rgb24 -s 1103x436 -i pipe: -vcodec libx264 resolvedvideo.avi
The video came out legible (apart from color shifts), and all parties dragged into it have been notified (iTunes, gmail, TeamViewer and VICIdial).
Anyway, this is the C++ code I ended up using:
#include <stdio.h>
#include <io.h>
#include <fcntl.h>
#include <Windows.h>
using namespace std;
int main() {
const size_t inLineSize = 1024 * 3;
const size_t inFrameSize = 1024 * 768 * 3;
const size_t outFrameSize = 1103 * 436 * 3;
const size_t inPayloadLineSize = 800 * 3;
const size_t inPayloadNumLines = 600;
const size_t inPayloadFrameSize = inPayloadLineSize * inPayloadNumLines;
const size_t inTopBorderNumLines = 84;
const size_t inLeftBorderNumPixels = 112;
const size_t inPayloadOffset = inLineSize * inTopBorderNumLines + inLeftBorderNumPixels * 3;
const size_t outPadSize = outFrameSize - inPayloadFrameSize;
_setmode(_fileno(stdin), _O_BINARY);
_setmode(_fileno(stdout), _O_BINARY);
char* inFrame = new char[inFrameSize];
char* outPadding = new char[outPadSize];
memset(outPadding, 0, outPadSize);
while (!feof(stdin)) {
size_t sizeLeft = inFrameSize;
char* nextReadPos = inFrame;
while (!feof(stdin) && sizeLeft > 0) {
size_t bytesRead = fread(nextReadPos, 1, sizeLeft, stdin);
sizeLeft -= bytesRead;
nextReadPos += bytesRead;
if (sizeLeft > 0) {
Sleep(100);
}
}
if (!feof(stdin)) {
char* inPayloadPos = inFrame;
inPayloadPos += inPayloadOffset;
for (size_t inLineNr = 0; inLineNr < inPayloadNumLines; ++inLineNr, inPayloadPos += inLineSize) {
fwrite(inPayloadPos, 1, inPayloadLineSize, stdout);
}
fwrite(outPadding, 1, outPadSize, stdout);
}
}
return 0;
}