Перекодирование видео в VLC
и HMS
для Tvix-6500M
VLC и Tvix-6500M
| MPEG-1
| MPEG-2
| MPEG-4
| DIVX-2
| DIVX-3
| H-264
|
---|
| 0:24 мин.
| | | | 5:33 мин.
AVI
| |
| |
| |
|
---|
MPEG-1 (.mpeg)
| 11.05MB
| 11.58MB
|
|
|
|
|
---|
TS
| REBOOT
| REBOOT
| 3.99MB
|
---|
PS (.ts)
| 11.05MB
| 11.57MB
| REBOOT
|
|
| 6.31MB
|
---|
|
Субтитры в HMS
-vhook "hmssubst.dll имя файла , шрифт , размер ,
стиль , цвет , цвет контура , толщина контура ,
фон , ? , ? ,
правый край, нижний край ,
частота кадров , ? , ? , ? , язык ,
? , формат 3D , смещение 3D"
|
где
стиль = жирный + 2 * курсив + 4 * подчеркивание + 8 * зачеркивание
цвет = R + 256 * G + 256 * 256 * B
края считаются от левого верхнего угла
Обнаружилась досадная ошибка в hmssubst.dll: При установке контура в 1 px
возможное пространство для субтитров уменьшается примерно на 20% экрана.
А при увеличении толщины - еще больше и верхняя часть экрана остается
не занятой текстом. Решений, пока, только два
Отказаться от контура
- На светлом фоне текст будет не читаем
Наложить титры в VLC
+ Прогон через HMS для преобразовании соотношения сторон
+ Прогон через VLC для наложения субтитров
Титры добавляется и выбирается
стандартным образом через меню по правой клавише или в
Информации о фильме.
Стоп-кадры (для ffmpeg)
| исх.
|
| → in
| out →
|
| → in
| out →
|
---|
частота
| r0
| r1i
| r1o
| r2i
| r2o
|
---|
| | вычисляется
| | = 0.2 для 5 сек./кадр |
| время
| t0
|
|
|
|
|
---|
количество кадров
| t0 r0
|
|
|
|
|
---|
С учетом коррекции скорости в сторону
увеличения (меньше 1 для уменьшения)
продолжительности фильма λ:
При первом преобразовании оставляется необходимое количество кадров
и прогоняется со скоростью r1o fps.
При втором преобразовании кадры тиражируются
и прогоняются со скоростью r2o fps,
которая стандартно может равняться r1o fps и 25 fps.
Например, при желании сделать стоп-кары с интервалом 5 сек./кадр
(r2i= 0.2 fps) при
начальном r0= 25 fps и
r1o= r2o= 25 fps:
r1i= 3125 fps.
Данные преобразования можно сделать через HMS.
Для указания параметров использовал поле комментария в Информации о фильме,
через пробел могут указываются только те параметры, которые отличаются от
стандартных:
fps=r2i|dt=1/r2i
time=λ
crop=yes|no|pad
center=yes|no
maxs=number
cropr=part
start=seconds|hh:mm:ss[.xxx]
|
fps - по-умолчанию - 0.1 (10 секунд на кадр)
time - по-умолчанию - 1
crop - вырезается кусок кадра, соответствующий экрану 16:9,
в случае crop=pad - дополняется, по умолчанию - pad
center - вырезается или дополняется по центру,
по-умолчанию - no
(картинка справа, титры слева)
maxs - максимальное количество букв в титрах для того,
чтобы титры были как можно левее,
по-умолчанию - 0 (титры занимают ширину изначального кадра)
cropr - часть удаляемого кадра справа, по-умолчанию - 0
Кадры
Между первым и вторым прогоном добавил создание картинок с титрами
HmsFileTranscoding(sDestScTempFileName,
sDestJpgDir+'\%3d.jpg','Без параметров');
|
Три прогона (вторая версия)
Для того, чтобы титры появлялись в тот момент, когда они и должны, а не
с началом следующего кадра, сделал преобразование в три прогона.
Первый и второй делает стоп-кадры, как и в предыдущей версии, но без
субтитров. В третьем прогоне накладываются субтитры и корректируется скорость.
+ Титры появляются без задержки
+ Для корректировки скорости необходим только третий прогон.
+ Также нет необходимости в переделке титров под скорость.
- Не сделаешь картинки (набор кадров еще без титров)
- Появление титров не сявзано с появлением кадров
Обработка
procedure ProcessFile
...
// Имя темпового файла
var sDestTempFileName : String
...
// Имена конечного и темпового файла
sDestFileName := IncludeTrailingBackslash(aDestDirectory) +
ChangeFileExt(ExtractFileName(aSourceFileName), '.sc.mpg');
sDestTempFileName := IncludeTrailingBackslash(aDestDirectory) +
ChangeFileExt(ExtractFileName(aSourceFileName), '.temp.mpg');
...
// Первый прогон
if HmsFileTranscoding(aSourceFileName, sDestTempFileName,
'Стоп-кадры (первый прогон)') and
// Второй прогон
HmsFileTranscoding(sDestTempFileName, sDestFileName,
'Стоп-кадры (второй прогон)') then begin
...
begin
...
// Комментарии передаются в скрипт транскодера
if MediaItem <> nil then begin
gsUserVariable1 := MediaItem.Properties[mpiComment];
...
|
Первый прогон
const
r1o = 25;
var
iWidth,iHeight : Integer;
sWidth,sHeight,iWidthSub,cWidth : Integer;
r,t,r2i : Extended;
crop, center, start : String;
cropr : Extended;
maxs : Integer;
sSubt, sCrop : String;
begin
r2i:= 1/StrToFloat(ExtractParam(gsUserVariable1,'dt','10'));
if r2i=0.1 then
r2i:= StrToFloat(ExtractParam(gsUserVariable1,'fps','0.1'));
t:= StrToFloat(ExtractParam(gsUserVariable1,'time','1'));
crop:= ExtractParam(gsUserVariable1,'crop','pad');
center:= ExtractParam(gsUserVariable1,'center','no');
maxs:= StrToInt(ExtractParam(gsUserVariable1,'maxs','0'));
cropr:= StrToFloat(ExtractParam(gsUserVariable1,'cropr','0'));
start:= ExtractParam(gsUserVariable1,'start','');
sSubt:= CurrentMediaItem.Properties[mpiSubtitleLanguage];
r:= mpFrameRate * r1o / t / r2i;
iWidth:= mpWidth; iHeight:= mpHeight;
iWidthSub:= mpWidth;cWidth:= 0;
sWidth:= 0; sHeight:= 0; sCrop:='';
if crop = 'yes' then begin
if iWidth * 9 < iHeight * 16 then begin
iHeight:=iWidth * 9 div 16;
if center = 'yes' then
sHeight:=(mpHeight - iHeight) div 2;
end else begin
iWidth:=iHeight * 16 div 9;
sWidth:=(mpWidth - iWidth) div 2;
iWidthSub:=iWidth;
end;
sCrop:=' -vf "crop=' +
IntToStr(iWidth) + ':' + IntToStr(iHeight) + ':' +
IntToStr(sWidth) + ':' + IntToStr(sHeight) + '"'
end;
if crop = 'pad' then begin
sCrop:=' -vf "';
if (cropr > 0) then begin
cWidth:= Int(mpWidth * cropr);
sCrop:= sCrop + 'crop=' +
IntToStr(mpWidth - cWidth) + ':' +
IntToStr(mpHeight) + ':0:0,';
end;
if iWidth * 9 < iHeight * 16 then begin
iWidth:=iHeight * 16 div 9;
if center = 'yes' then begin
sWidth:=(iWidth + cWidth - mpWidth) div 2;
iWidthSub:=iWidth;
end else
sWidth:=(iWidth + cWidth - mpWidth);
end else begin
iHeight:=iWidth * 9 div 16;
if center = 'yes' then
sHeight:=(iHeight - mpHeight) div 2
else
sWidth:=(iWidth + cWidth - mpWidth);
end;
// Ширина титров в зависимости
// от количества букв, подобранно
if (maxs > 0) then iWidthSub := maxs * iHeight div 40;
sCrop:=sCrop + 'pad=' +
IntToStr(iWidth) + ':' + IntToStr(iHeight) + ':' +
IntToStr(sWidth) + ':' + IntToStr(sHeight) + ':black"'
end;
if (sSubt <> '') then begin
Delete(sSubt,1,1);
Delete(sSubt,Length(sSubt),1);
sSubt:=
' -vhook "hmssubt.dll ' + sSubt +
// ~1.5 * колмчество строк
',Arial Narrow,' + IntToStr(iHeight div 22) +
',0,16777215,0,0,0,,,' +
Str(iWidthSub) + ',' +
// Небольшой сдвиг титров вверх, подобранно
Str(Int(iHeight - (iHeight/21.2 - (iHeight div 22)) * 11)) +
"," + FloatToStr(mpFrameRate) + ',,,,rus"';
end;
if (start <> '') then start:=' -ss '+ start;
TranscodingParams :=
'-r ' + FloatToStr(r) + start + ' ' +
HmsTranscodingInputParams + sCrop + sSubt +
// Изменение битрейта
' -b:v ' + Str(Int(mpDataRate / r2i)) +
// ключевой каждый кадр
' -force_key_frames expr:1' +
' -an -r ' + IntToStr(r1o);
end.
|
Второй прогон
const
r2o = 25;
var
r2i : Extended;
begin
r2i:=StrToFloat(ExtractParam(gsUserVariable1,'fps','0.1'));
TranscodingParams :=
' -r ' + FloatToStr(r2i) + ' ' +
HmsTranscodingInputParams +
// Восстанавливаем нормальный битрейт
' -b:v ' + Str(Int(mpDataRate * r2i)) +
' -an -r ' + Str(r2o) +
// Ключевой - первый кадр из тиражуруемых
' -force_key_frames expr:gte(n,n_forced*'+FloatToStr(r2o/r2i)+')'
end.
|
Переделка титров на 14 строк
# [time|tvix [dt]] # dt - продолжительность кадра
# По умолчанию - vlc, dt=10 сек.
# v2: Добавлено отсутствие титров при большом перерыве
# v3: При большом перерыве (2/fps+2) повтор последних строк
# старых титров и только следующие dt/2 сек.
# Функционал subtnew() расписан по программе
# v4: Перерыв считается между началом и концом предыдущих
# Соответственно, большой перерыв - кадр + 1 сек.
# В случае повтора, начало новых титров = концу прошлых
# Если оставшихся титров до перерыва меньше кадра,
# то увеличиваем его на кадр без повтора
# v5: Общий скрипт для vlc и tvix
# вторым параметром может быть "tvix": 6 строк без повтора
# v6: Повтор только когда строчек > 5
# Вернулся к большому перерыву в 2 кадра
# v7: Склейка конца с началом, а не наоборот
# Снова разрыв лля перерыва в один кадр,
# При f=0 набор проверяется только при s>x, не=x
# v8: Добавление титров ровно на dt/time
# Повтор только когда строчек > 7
if test "$1" == ""; then
echo "titles [time|tvix [dt]]"
else
if test "$2" == "tvix"; then
titles=`echo $1 | sed s/.srt$/.tvix.srt/`
else
titles=`echo $1 | sed s/.srt$/.vlc.srt/`
fi
echo $titles
printf "maxs=" >&2
n=`cat "$1" | iconv -f WINDOWS-1251 -t ASCII//TRANSLIT | wc -L`
n=`expr $n + 2`
echo $n >&2
cat "$1" |
awk -v n=$n -v da=$2 -v db=$3 'BEGIN {
f=0; s=0; # текущих строк
k=0; # номер текущих титров
beg=""; # начало титров
bgt=""; # начало последних субтитров
ets=0; # конец последних субтитров
dt=10; # большой перерыв
if (da=="tvix") {
vlc=0; x=6; # количество строк
if (db>0) dt=db; # большой перерыв
} else {
vlc=1; x=14 # количество строк
if (db>0) dt=db; # большой перерыв
if (da>0) dt=dt/da # корректировка по времени
}
separate="\r";
for (i=1;i<=n/1.3;i++) separate="="separate;
}
function subt(s,beg,end) { # печать титров
print beg" --> "end"\r";
for (i=1;i<=s;i++) print str[i];
print "\r";
}
function sec(bg) { # секунд
gsub(",",".",bg);
split(bg,ba,":");
return ((ba[1]*60)+ba[2])*60+ba[3];
}
function tform(bg) { # формат времени
bg=sprintf("%02d:%02d:%06.3f",
bg/3600,bg%3600/60,bg%60);
gsub("\\.",",",bg);
return bg;
}
{
if ($0=="" || $0=="\r") f=0; else f++;
if (f==0 && s>x) {
subt(x,beg,bgt);
if (vlc) { # повтор титров
for (i=1;i<=2;i++) str[i]=str[x-2+i];
str[3]=separate;
for (i=1;i<=s-x;i++) str[i+3]=str[x+i];
s=s-x+3;
} else {
for (i=1;i<=s-x;i++) str[i]=str[x+i];
s=s-x;
} print k; bts=sec(beg=bgt);
# продолжение титров на кадр
if (ets-bts < dt) ets=bts+dt;
}
if (f==1) { # номер
if (!k) print $0; else k=$0; }
if (f==2) { # время
bts=sec(bgt=$1);
if (!k) beg=$1; # начало титров
else {
if (bts-ets >= dt) { # перерыв больше кадра
subt(s,beg,tform(ets));
if (vlc && s>7) {
# повтор титров при большом перерыве
print k-1"\r";
for (i=1;i<=2;i++) str[i+1]=str[s-2+i];
str[1]=separate;
subt(3,tform(ets),tform(ets+dt));
}
s=0; print k; k=0; beg=bgt;
} }
bts=sec(beg); ets=sec($3);
# продолжение титров на кадр
if (ets-bts < dt) ets=bts+dt;
}
if (f==3) { # начало титра
if (k) t="* "; else k=1; }
if (f>=3) { s++; str[s]=t$0; t=""; }
} END { if (k) subt(s,beg,tform(ets)); }' > "$titles"
difftimes "$titles" $2 $3
fi
|
|