главная страница
материалы
  ms access и bitmap
  win в ucs-2 на perl
  приложение facebook
  медиа библиотека
  восстановление exif
  netgear stora
  html и javascript
конвертация
  перекодировка для tv
  перекодировка для tvix

Перекодирование видео в 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
    t r0
    r1i
    t r0 r1o  =  t0
    r1i r2i
    количество
    кадров
    tr0
    tr r1o  =  tr2i
    r1i
    tr r1o r2o
    r1i r2i

    С учетом коррекции скорости в сторону увеличения (меньше 1 для уменьшения) продолжительности фильма λ:

    r1i  =  ro r1o
    λ r2i
    При первом преобразовании оставляется необходимое количество кадров и прогоняется со скоростью 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 timecrop=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