Mexicanetz Express вручную редактирует видео

Здравствуйте,

Здесь я расскажу о том, каким образом можно, да и нужно бороться с некондицонными компакт-видеодисками, то есть теми дисками, которые читаться читаются, а копироваться на ваш жёсткий диск отказываются по причине сбоя где-то на носителе.

Каким образом можно помочь себе и другим, сберечь нервы и средства?


Для начала немного теории. Запись на любом (современном) носителе организована посекторно, то есть минимальным читаемым объёмом информации является один сектор. Даже если вы хотите прочитать всего лишь один байт - в буфер должен скопироваться целый сектор.

Таким образом, если где-то на носителе не читается сектор (почему - для нас абсолютно не важно), то вы можете скопировать данные, пропустив этот сектор при чтении, и заменив не считанные данные какой-то "пустышкой" (для мультимедиа это чаще всего байты FFh, хотя можно и пропустить его полностью - не убудет).

Рассматривая самый популярный вариант - VideoCD 1.0, отмечу, что видео там формата MPEG-1 352*288 пикселей, звук - Layer II стерео 44100 Гц. Отличительной особенностью всех современных видеопотоков является то, что их можно "кроить по живому", то есть резать, не обращая внимания на подгонку байт к байту. Это сделано для того, чтобы при сбое потока (с носителя, из сети) поток не прерывался, а сбойный участок обходился.

Естественно, стандартный Windows (а ведь у вас стоит именно он, признавайтесь? От него волосы на ладонях растут, а к сорока годам вы ещё и ослепнете, если не прекратите ЭТИМ заниматься!) не имеет в арсенале никакого способа сделать пропуск хотя бы одного сектора, и тем более замены. Приходится прибегать к помощи драйвера, который можно скачать тут: www.directhands.com. Называется он "прямые ручки" и пригодится много ещё для чего.

 

Итак, поехали. В качестве RAD-а я использую Turbo Pascal 5.5 а пишу с использованием стандартных ассемблерных функций.


 

Uses dos;

 

{Включаем стандартный модуль работы с прерываниями и прочую чепуху;}

Var beg,i:longint; a:array[1..100,1..500]of byte; z:registers; inp,otp:string; desc_in,desc_out:integer;

 

{нам понадобится счётчик байтов для пропуска BEG, внутренний счётчик I, массив для буфера обмена, две строки для имён файлов и два целых числа DESC для дескрипторов этих файлов. Естественно, не обойдётся без регистровой переменной Z. Остальное - добавьте сами, что вам нужно}

 

Begin

inp:='h:\in.mpg'+chr(0);otp:='d:\out.mpg'+chr(0);

 

{задаём стандартные имена файлов. Один - на компакт-диске, второй - у нас на винчестере. Заметьте, что все имена должны кончаться нулевым байтом - внутреннее соглашение DOS}

 

z.ah:=$3D;z.al:=3;z.cx:=0;z.ds:=seg(inp);z.dx:=ofs(inp)+1;MsDos(z);

 

{открываем (функция AH=3Dh) для полного доступа (AL=3) файл, имя которого находится в переменной INP - обратите внимание, переменная строкового типа, поэтому в первом байте у неё находится размер, его нужно опустить (ofs(inp)+1). Тип файла - любой (CX=0)}

 

desc_in:=z.ax;

 

{в AX нам любезно возвращают дескриптор на открытый входной файл}

 

z.ah:=$3C;z.al:=3;z.cx:=0;z.ds:=seg(otp);z.dx:=ofs(otp)+1;MsDos(z);

desc_out:=z.ax;

 

{а теперь то же самое проделываем с выходным файлом - только мы его не открываем как имеющийся, а создаём заново (AH=3Ch)}

 

{Итак, дескрипторы на файлы получены, позиции чтения/записи находятся в самом начале. Теперь давайте сделам системе подлость - выкусим ненужные кусочки видео! Для начала нужно скопировать заголовок:}

 

z.ah:=$3F;z.bx:=desc_in;z.cx:=16384;z.ds:=seg(a);z.dx:=ofs(a);MsDos(z);

z.ah:=$40;z.bx:=desc_out;z.cx:=16384;z.ds:=seg(a);z.dx:=ofs(a);MsDos(z);

 

{Здесь мы функцией AH=3Fh читали, а 40h - писали информацию, которая имеет размер CX=16384 байт (стандартный размер заголовка MPEG-1 файла) через переменную "a"

Настало время пропустить первый ненужный кусок. Расчитайте, сколько байт вам понадобится, только учтите, что для стандартного VideoCD 1 минута = 10 мегабайтам, поэтому в расчётах используйте 32-битные переменные типа LONGINT, а не 16-битные INTEGER.

...................

Итак, вы получили нужное значение в переменной BEG. Давайте её преобразуем к нужному виду:}

 

z.cx:=trunc(beg/65536);z.dx:=beg-z.cx*65536;

 

{теперь вызовем функцию позиционирования в исходном файле сразу за ошибкой:}

 

z.ah:=$42;z.al:=0;z.bx:=desc_in;MsDos(z);

 

{вот и всё. теперь можно производить чтение-запись нужного нам кусочка видео . Получите в переменной BEG размер (в байтах) нужного кусочка, а потом разделим его на размер буфера обмена. (например, 32 килобайта) В переменной BEG у нас число копируемых блоков данных}

 

............

BEG:=BEG/32768;

for i:=0 to BEG do begin

z.ah:=$3F;z.bx:=desc_in;z.cx:=32768;z.ds:=seg(a);z.dx:=ofs(a);MsDos(z);

z.ah:=$40;z.bx:=desc_out;z.cx:= 32768;z.ds:=seg(a);z.dx:=ofs(a);MsDos(z);

end;

 

{производим операцию кусочками по 32 килобайта, чтобы оптимизировать нагрузку на контроллер CD-ROM. Естественно, делаем это в цикле столько раз, сколько нам понадобится, чтобы переписать "вкусный" кусочек видео. Всё. Осталось только пропустить потом опять расчитаное количество байт, чтобы в конце файла дописать верный "конец". Это нужно для того, чтобы конечный файл корректно открывался в видеопроцессорах. Делаем это (опять же последние 16 килобайт) тем же образом, как мы переписывали заголовок.

 

Файл записан. Закрываем файлы (функция 3Eh), очищаем буфера}

 

z.ah:=$3E;z.bx:=desc_in;MsDos(z);

z.ah:=$3E;z.bx:=desc_out;MsDos(z);

z.ah:=$0D;MsDos(z);

 

Ну что, сложно? Не сложнее, чем потратить три миллиона нервных клеток, пытаясь несчастным AdobePremierre выдрать файло с диска или Blaze Media Pro расщепить 5-часовой видеофильм кусочками по 40 минут %)

 

17 мая 2002 года,

Mexicanetz Express