May 26, 2020

Перекодирование видео mpeg-2 в h264 mp4 с помощью ffmpeg и хранение на сетевом хранилище NAS DLink-327L

Накопилась на домашнем NAS DLink-327L куча видео со старых Sony камеры и фотоаппарата. Столкнулся с тем, что видео в формате MPEG-PS не читаются на Android-е без костылей и пересжатия.

Решил перекодировать все в mp4 кодеком h264.

Что имеем на входе:

  • девайс NAS DLink-327L + Samba shared
  • Ноут с Win10 Home + WSL Debian (для задействования bash-скрипта)

Все далее делаем только на ноуте.

Монтируем сетевой диск R: на ноут и следом монтируем его в Debian, но помним, что это WSL-версия Debian

sudo mount -t drvfs "r:" /mnt/photo

drvfs - хитрость именно тут

Исходный формат через команду mediainfo MOV07549.MPG выдал:

General
Complete name                            : MOV07549.MPG
Format                                   : MPEG-PS
File size                                : 44.2 MiB
Duration                                 : 35 s 424 ms
Overall bit rate mode                    : Variable
Overall bit rate                         : 10.5 Mb/s
Video
ID                                       : 224 (0xE0)
Format                                   : MPEG Video
Format version                           : Version 1
Format settings, BVOP                    : No
Format settings, Matrix                  : Default
Format settings, GOP                     : N=1
Duration                                 : 35 s 400 ms
Bit rate mode                            : Variable
Bit rate                                 : 10.2 Mb/s
Width                                    : 640 pixels
Height                                   : 480 pixels
Display aspect ratio                     : 4:3
Frame rate                               : 30.000 FPS
Color space                              : YUV
Chroma subsampling                       : 4:2:0
Bit depth                                : 8 bits
Scan type                                : Progressive
Compression mode                         : Lossy
Bits/(Pixel*Frame)                       : 1.107
Time code of first frame                 : 00:00:00:00
Time code source                         : Group of pictures header
GOP, Open/Closed                         : Closed
Stream size                              : 43.0 MiB (97%)
Audio
ID                                       : 192 (0xC0)
Format                                   : MPEG Audio
Format version                           : Version 1
Format profile                           : Layer 2
Duration                                 : 35 s 424 ms
Bit rate mode                            : Constant
Bit rate                                 : 64.0 kb/s
Channel(s)                               : 1 channel
Sampling rate                            : 32.0 kHz
Compression mode                         : Lossy
Stream size                              : 277 KiB (1%)

Конвертирование в mp4 кодеком libx264 тулзой ffmpeg

Пишем скрипт на bash convertpmg.sh для обхода всего каталога смонтированного в /mnt/photo:

#!/bin/bash

tmpIFS=$IFS; IFS=#39;\n'
for file in `find /mnt/photo -type f -iname "*.MPG"`; do

#  выводим что нашли для обработки  
    echo $file
#  меняем только расширение файла на .mp4 и оставляем тот же путь 
	mp4=$(echo $file | sed 's/.MPG/.mp4/g')
#	echo "$mp4"

# делаем проверку если файл еще не конвертировали ранее		
    if [ ! -f "$mp4" ]; then
    
		ffmpeg -i "$file" -f mp4 -vf "yadif=0:-1:0,hqdn3d" -c:v libx264 -crf 18 -preset slow -threads 6 "$mp4"
	fi
done
IFS=$tmpIFS

Небольшие пояснения:

Используем хак bash для "неправильных" названий каталогов типа "Новый год", "23 февраля", т.е. там где есть пробелы или дефис и т.п. символы

tmpIFS=$IFS; IFS=#39;\n'
...
IFS=$tmpIFS

Основной код конвертации через ffmpeg

ffmpeg -i "$file" -f mp4 -vf "yadif=0:-1:0,hqdn3d" -c:v libx264 -crf 18 \
-preset slow -threads 6 "$mp4"

основной параметр, который дал приемлемое качество на выходе

-vf "yadif=0:-1:0,hqdn3d" 

но можно просто:

 -vf yadif

и

-crf 18

это дает неразличимое глазу сжатие

Как видим, кодируем только видео поток, остальное оставляем по умолчанию на действие параметра

 -preset slow

и желаемый на выходе кодек:

-c:v libx264

кодируем 6 потоками (поставил на ночь и забыл):

-threads 6

Замена времени создания, редактирования и доступа силами PowerShell

Далее интереснее - в linux беда с подделкой времени создания файла, поэтому погуглив пришел к тому, что проще на ноуте использовать PowerShell.

После прохода нашим bash-скриптом:

bash -C convertpmg.sh

в каталоге с *.MPG файлами появились *.mp4 файлы и теперь им надо установить такие же даты (это важно для дальнейшего построения галереи по календарю) как у *.MPG.

Пишем файл PowerShell-скрипт updatetime.ps1

$Directory = "r:"

# скрипт устанавливает дату создания, изменения и доступа 
# для mp4 файлов как у MPG файлов
  
foreach ($file in (Get-ChildItem -Path $Directory -Recurse -Filter *.MPG)){
	$fullName = $file.FullName.ToString().Replace( ".MPG", ".mp4")

# делаем проверку на существование mp4-файла		
    if(Test-Path $fullName -PathType Leaf){
		$mp4File = (Get-Item -Path $fullName)
		$mp4File.CreationTime = $file.CreationTime
		$mp4File.LastAccessTime = $file.LastAccessTime
		$mp4File.LastWriteTime = $file.LastWriteTime
# печатаем что обработали
		$fullName
	}
}
Заметка файл updatetime.ps1 запускать с локального диска, a не с shared samba - R:

Теперь осталось почистить исходные MPG, удалив их с диска (если они больше не нужны ... совсем... никогда :) )

Пишем на bash такой скрипт removeMPG.sh :

#!/bin/bash
# удалить исходник несжатого видео при наличии сжатой копии
tmpIFS=$IFS; IFS=#39;\n'
for file in find /mnt/photo -type f -iname "*.MPG"; do
	mp4=$(echo $file | sed 's/.MPG/.mp4/g')
	
	if [ -f $mp4 ]; then
       echo $file
	   rm $file
	fi
done
IFS=$tmpIFS
для bash критично использование регистра MPG и mpg это разные файлы, поэтому про это тоже помним ))

Вызываем:

bash -C removeMPG.sh

и слезно плачем по безвозвратно удаленным файлам...

Смотрим что теперь выдает mediainfo для сконвертированного mp4 файла:

General
Complete name                            : MOV07549.mp4
Format                                   : MPEG-4
Format profile                           : Base Media
Codec ID                                 : isom (isom/iso2/avc1/mp41)
File size                                : 20.7 MiB
Duration                                 : 35 s 456 ms
Overall bit rate                         : 4 887 kb/s
Encoded date                             : UTC 1904-01-01 00:00:00
Tagged date                              : UTC 1904-01-01 00:00:00
Writing application                      : Lavf57.56.101
Video
ID                                       : 1
Format                                   : AVC
Format/Info                              : Advanced Video Codec
Format profile                           : High@L3
Format settings, CABAC                   : Yes
Format settings, ReFrames                : 5 frames
Codec ID                                 : avc1
Codec ID/Info                            : Advanced Video Coding
Duration                                 : 35 s 400 ms
Bit rate                                 : 4 819 kb/s
Width                                    : 640 pixels
Height                                   : 480 pixels
Display aspect ratio                     : 4:3
Frame rate mode                          : Constant
Frame rate                               : 30.000 FPS
Color space                              : YUV
Chroma subsampling                       : 4:2:0
Bit depth                                : 8 bits
Scan type                                : Progressive
Bits/(Pixel*Frame)                       : 0.523
Stream size                              : 20.3 MiB (98%)
Writing library                          : x264 core 148 r2748 97eaef2
Encoding settings                        : cabac=1 / ref=5 / deblock=1:0:0 / analyse=0x3:0x113 / me=hex / subme=8 / psy=1 / psy_rd=1.00:0.00 / mixed_ref=1 / me_range=16 / chroma_me=1 / trellis=2 / 8x8dct=1 / cqm=0 / deadzone=21,11 / fast_pskip=1 / chroma_qp_offset=-2 / threads=6 / lookahead_threads=1 / sliced_threads=0 / nr=0 / decimate=1 / interlaced=0 / bluray_compat=0 / constrained_intra=0 / bframes=3 / b_pyramid=2 / b_adapt=1 / b_bias=0 / direct=3 / weightb=1 / open_gop=0 / weightp=2 / keyint=250 / keyint_min=25 / scenecut=40 / intra_refresh=0 / rc_lookahead=50 / rc=crf / mbtree=1 / crf=18.0 / qcomp=0.60 / qpmin=0 / qpmax=69 / qpstep=4 / ip_ratio=1.40 / aq=1:1.00
Encoded date                             : UTC 1904-01-01 00:00:00
Tagged date                              : UTC 1904-01-01 00:00:00
Audio
ID                                       : 2
Format                                   : AAC
Format/Info                              : Advanced Audio Codec
Format profile                           : LC
Codec ID                                 : 40
Duration                                 : 35 s 456 ms
Bit rate mode                            : Constant
Bit rate                                 : 69.4 kb/s
Channel(s)                               : 2 channels
Channel(s)_Original                      : 1 channel
Channel positions                        : Front: C
Sampling rate                            : 32.0 kHz
Frame rate                               : 31.250 FPS (1024 spf)
Compression mode                         : Lossy
Stream size                              : 300 KiB (1%)
Default                                  : Yes
Alternate group                          : 1
Encoded date                             : UTC 1904-01-01 00:00:00
Tagged date                              : UTC 1904-01-01 00:00:00

И вот собственно все!

Хотя нет...

Забыл что есть еще DVD видео 3-4 диска на NAS, тут уже руками можно ))

Из текущего каталога VIDEO_TS в bash вызываем:

cat VTS0**VOB | ffmpeg -i - -f mp4 -vf "yadif=0:-1:0,hqdn3d" -c:v libx264 -crf 18 -preset slow -threads 6 filenameXXX.mp4

P.S. Все писалось для себя, чтобы не забыть как и что делал и может это кому-то пригодится еще.

Если бы знал все про подводные камни с монтированием диска WSL Debian, про траблы с неправильными именами директорий, то сразу бы сделал все на PowerShell, используя консольный вариант ffmpeg для windows. Может кто предложит в комментах другие варианты.