Когда мне позвонил индийский отдел «Microsoft», я позволил им присоединиться к моей виртуальной машине VirtualBox и начал захват видео, чтобы узнать о них какие-либо подробности. При этом VirtualBox создает видеофайлы .webm.
Однако, когда я теперь воспроизвожу этот файл webm, я вижу, что он был искажен именно там, где я изменил разрешение виртуальной машины. Сессия длилась час (уф...), и в конце мне удалось помешать их тщетным попыткам взлома установить системный пароль на моем компьютере, и вместо этого я снова вошел в соединение, которое они затем прервали. Я думаю, что тогда я увидел какую-то полноэкранную среду панели инструментов - может быть, их? Может быть, есть очень полезная информация, это правда!
Искажение кажется, что это просто проблема с длиной строки развертки в видеопотоке. Хитрость здесь в том, что само видео все правильно в разрешении 1024x768, но полезная нагрузка представляет собой просто область 800x600 посередине (с черными рамками вокруг нее). Эта внутренняя область - то, что еще больше испортилось в видео. Черные границы остаются в порядке, так что это просто исходный поток данных VirtualBox для средней части, который сместился.
Кто-нибудь знает о какой-то процедуре или программном обеспечении, которое я мог бы использовать, чтобы попытаться исправить это видео? Я уже видел, что видеофайлы webm используют стандарт, основанный на Matroska, и используют кодирование EBML; Я уже пытался изменить некоторые значения заголовков в структуре EBML, чтобы подделать разрешение экрана (чтобы черные границы сместились, но средняя полезная нагрузка была в порядке), но это ни к чему не привело (каждые 5 секунд видео или что-то подобное имеют свой собственный блок заголовка, например хорошо).
Добавление:
Если быть точным: видео рендерилось в разрешении 1024x786 пикселей, а виртуальная машина работала в разрешении 800x600. Это приводит к жирной черной рамке, окружающей внутренний захваченный контент на протяжении всего видео. После того, как я увеличил размер окна виртуальной машины (скажем, до 1200х650 - точно не могу сказать), черная рамка осталась прежней по размеру, только внутреннее содержимое в ней искажается. С искаженным я имею в виду, что он выглядит так, как будто он отображает теперь более длинные строки развертки в 1200 пикселей и оборачивает их длиной 800 строк развертки, таким образом, каждая следующая реальная строка развертки смещается на разницу в горизонтальном размере, поскольку предыдущая строка завернута в нее. По крайней мере, так я думал изначально, но, глядя на это снова, у меня возникают сомнения и в этой теории.
Ну вообще непонятно :) Кадр закачал сюда: а короткий фрагмент видео сюда: короткий фрагмент скам-видео (проблема возникает на середине фрагмента)
Но, если честно, я думаю, что лучше сдаться. Я начинаю подозревать, что единственное возможное исправление - это сделать пиксельный захват в старых кадрах и построить из этого новое видео, если это вообще исправление - т.е. слишком много усилий. Позор, однако, так как я действительно хотел бы просмотреть содержание в конце...
Решение:
Благодаря bukkojot я придумал следующее (ориентированное на Windows) приложение, которое помещается в середину командной строки ffmpeg, которую он дал; может кому пригодится? Обратите внимание, что «RGB24» в командной строке должно быть «rgb24» при использовании последней версии ffmpeg в Windows, что приводит к командной строке, которую я использовал для:
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
Видео получилось разборчивым (не считая изменения цвета), и все вовлеченные в него стороны были уведомлены (iTunes, gmail, TeamViewer и VICIdial).
Во всяком случае, это код C++, который я использовал:
#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;
}
После небольшой манипуляции... Видите ли...
Самый простой способ для вас:
Напишите очень простое приложение на C, которое будет читать 1024*768*3 байта и дополнять нулями до 1327*768*3 байта. Вам легко.
Сбрасывать необработанные пиксели с помощью ffmpeg, передавать данные в ваше приложение, передавать данные обратно в ffmpeg
Что-то вроде:
ffmpeg -i scamvideo.avi -f rawvideo -pix_fmt RGB24 - | ./a.out | ffmpeg -f rawvideo -pix_fmt RGB24 -s 1327x768 -i - -vcodec libx264 newvideo.avi
Все остальные варианты на ваш вкус. Я думаю, вы поняли.
Гьян
Карл Колейн