Редактиране на видео под Линукс

[ video  linux  software  ]

Съвети за редактиране на видео под Линукс

Въведение

Тук ще споделя моя опит с приложения и команди за обработка на видео под Линукс. Част от резултатите можете да видите тук: Different ways to improve video using free software in Linux - add telemetry, enhance colors, stabilize video.

Docker

Docker е много удобен инструмент, когато трябва да се работи със сложни взаимовръзки между библиотеките. Препоръчителният начин за инсталация е описан на https://docs.docker.com/engine/install/ubuntu/#install-using-the-convenience-script:

curl -fsSL https://get.docker.com -o get-docker.sh
sudo sh get-docker.sh
sudo usermod -aG docker ВАШИЯТ–ПОТРЕБИТЕЛ

ffmpeg

За определяне на качеството при прекодиране се ползват параметрите -codec:v libx264 -crf 18 -preset slower

Стабилизиране на видео

Резултатът от стабилизирането може да се види тук:

Плъгинът vid.stab не е компилиран стандартно в Ubuntu 18.04 и за това командите се изпълняват в докер.

Прави се на две стъпки - в първата се установява на къде е отместено (векторът на отместването) видеото във всеки един момент от време (симулира жироскоп), а на втората стъпка се променя самото видео (прилага се трансформация с обратния вектор).

  • един файл
docker run --rm  -v "$(pwd)":/data jrottenberg/ffmpeg -i /data/ВИДЕО.MP4 -vf vidstabdetect=accuracy=15:shakiness=10:mincontrast=0.3:show=0:result=/data/transforms.trf -an -f null -
docker run --rm  -v "$(pwd)":/data jrottenberg/ffmpeg -i /data/ВИДЕО.MP4 -vf vidstabtransform=smoothing=20:input="/data/transforms.trf:optzoom=0,unsharp" /data/РЕЗУЛТАТ.mp4
  • всички файлове в директория
#!/bin/bash
set -e
relativeFolder="${1}"
folder=$(cd "${relativeFolder}"; pwd)
for relativeFile in "${folder}"/*.MP4; do
        [ -e "${relativeFile}" ] || continue
        filename="${relativeFile##*/}"
        docker run --rm  -v "${folder}":/data jrottenberg/ffmpeg -i "/data/${filename}" -vf vidstabdetect=accuracy=15:shakiness=10:mincontrast=0.3:show=0:result=/data/transforms.trf -an -f null -
        docker run --rm  -v "${folder}":/data jrottenberg/ffmpeg -i "/data/${filename}" -vf vidstabtransform=smoothing=20:input="/data/transforms.trf:optzoom=0,unsharp" "/data/output-${filename}"
done
rm -rf "${folder}"/transforms.trf

sudo chown "$(whoami)":"$(whoami)" output-*.MP4
  • за ползване на GPU (добавя се :vaapi)

docker run (...) jrottenberg/ffmpeg:vaapi (...)

Телеметрия към видео (Picture in Picture)

  • [GoPro Dashboard Overlay]https://github.com/time4tea/gopro-dashboard-overlay

  • venv/bin/gopro-dashboard.py --profile highquality --layout xml --layout-xml ~/.gopro-graphics/layout.xml --gpx recordedgpx.gpx recordedvideo.MP4 result.MP4

  • ~/.gopro-graphics/ffmpeg-profiles.json

{
  "highquality": {
    "input": [],
    "output": ["-vcodec", "libx264", "-acodec", "copy","-preset", "slower","-crf", "18"]
  }
}
  • ~/.gopro-graphics/layout.xml
<layout>
    <composite x="260" y="30" name="date_and_time">
        <component type="datetime" x="0" y="0" format="%Y/%m/%d" size="16" align="right"/>
        <component type="datetime" x="0" y="24" format="%H:%M:%S.%f" truncate="5" size="32" align="right"/>
    </composite>

    <composite x="1644" y="36" name="gps_info">
        <component type="text" x="256" y="0" size="16" align="right">GPS INFO</component>
        <component type="text" x="0" y="24" size="16" align="left">Lat: </component>
        <component type="text" x="128" y="24" size="16" align="left">Lon: </component>
        <component type="metric" x="118" y="24" metric="lat" dp="6" size="16" align="right" cache="False"/>
        <component type="metric" x="256"    y="24" metric="lon" dp="6" size="16" align="right" cache="False"/>
    </composite>

    <composite x="16" y="800" name="big_mph">
        <component type="text" x="0" y="0" size="16">MPH</component>
        <component type="metric" x="0" y="0" metric="speed" units="mph" dp="0" size="160" />
    </composite>

    <component type="gradient_chart" name="gradient_chart" x="400" y="980"/>

    <composite x="220" y="980" name="gradient">
        <component type="text" x="70" y="0" size="16">SLOPE(%)</component>
        <component type="icon" x="0" y="0" file="slope-triangle.png" size="64"/>
        <component type="metric" x="70" y="18" metric="gradient" dp="1" size="32" />
    </composite>

    <composite x="16" y="980" name="altitude">
        <component type="text" x="70" y="0" size="16">ALT(m)</component>
        <component type="icon" x="0" y="0" file="mountain.png" size="64"/>
        <component type="metric" x="70" y="18" metric="alt" dp="1" size="32" />
    </composite>

    <composite x="1900" y="820" name="temperature">
        <component type="text" x="-70" y="0" size="16" align="right">TEMP(C)</component>
        <component type="icon" x="-64" y="0" file="thermometer.png" size="64"/>
        <component type="metric" x="-70" y="18" metric="temp" dp="0" size="32" align="right"/>
    </composite>

    <composite x="1900" y="900" name="cadence">
        <component type="text" x="-70" y="0" size="16" align="right">RPM</component>
        <component type="icon" x="-64" y="0" file="gauge.png" size="64"/>
        <component type="metric" x="-70" y="18" metric="cadence" dp="0" size="32" align="right"/>
    </composite>

    <composite x="1900" y="980" name="heartbeat">
        <component type="text" x="-70" y="0" size="16" align="right">BPM</component>
        <component type="icon" x="-64" y="0" file="heartbeat.png" size="64"/>
        <component type="metric" x="-70" y="18" metric="hr" dp="0" size="32" align="right"/>
    </composite>

    <frame x="1644" y="100" width="256" height="256" fo="50" cr="35">
       <component type="journey_map" name="moving_map" x="0" y="0" size="256" zoom="16"/>
    </frame>
    <frame x="1644" y="376" width="256" height="256" fo="50" cr="128">
      <component type="journey_map" name="journey_map" x="0" y="0" size="256" />
    </frame>
    <frame x="1644" y="676" width="256" height="256" fo="50">
      <component type="journey_map" name="journey_map" x="0" y="0" size="256" />
    </frame>
    <frame x="1644" y="976" width="256" height="256" fo="20" opacity="0.6" >
      <component type="journey_map" name="journey_map" x="0" y="0" size="256" />
    </frame>

    <frame x="1044" y="100" width="256" height="256">
       <component type="journey_map" name="moving_map" x="0" y="0" size="256" zoom="16" corner_radius="35"/>
    </frame>
    <frame x="1044" y="376" width="256" height="256">
      <component type="journey_map" name="journey_map" x="0" y="0" size="256" corner_radius="70"/>
    </frame>
    <frame x="1044" y="676" width="256" height="256">
      <component type="journey_map" name="journey_map" x="0" y="0" size="256" />
    </frame>
    <frame x="1044" y="976" width="256" height="256" opacity="0.6" >
      <component type="journey_map" name="journey_map" x="0" y="0" size="256" opacity="0.6" />
    </frame>

    <frame x="1044" y="976" width="256" height="256" opacity="0.6" >
      <component type="journey_map" name="journey_map" x="0" y="0" size="256" opacity="0.6" />
    </frame>
    <frame x="1344" y="976" width="256" height="256">
      <component type="journey_map" name="journey_map" x="0" y="0" size="256" opacity="0.6" />
    </frame>
</layout>

Телеметрия към видео (Picture in Picture), сложния начин

Резултатът от добавянето на телеметрия може да се види тук:

Съществуват множество приложения за добавяне на телеметрични данни (локация, скорост, посока и други) към видео, но те са платени, за Windows, за конкретен модел камера или резултатът не е особено сполучлив. За това тук ще опиша един друг вариант. При него използвам gpx файл от GPS, който качвам на ayvri и записвам видеото посредством SimpleScreenRecorder. Резултатът може да видите тук: резултат, базиран на оригинално видео и телеметрия.

  • добавям gpx файла в ayvri (може и през интеграцията със страва)
  • отварям създаденото видео, преди да зареди натискам пауза, намалявам скоростта до х1, натискам STATS за да се покажат всички телеметрични данни
  • в конзолата на Chromе (Ctrl+Shift+I или F12) изпълнявам document.getElementById('StatsPanelContainer').style = "padding-right: 750px; padding-top: 337px;";document.getElementById("StatsPanelContainer").childNodes[0].childNodes[1].remove();document.getElementById("StatsPanelContainer").childNodes[0].childNodes[0].childNodes[3].remove();
    • имайте предвид че това маха някои от метриките, а тъй като те зависят от зададения тип на записа (туризъм, ски, парапланер) може да се наложи да се промени скрипта по-горе в зависимост от типа на активността
    • по-принцип избягвайте да изпълнявате такива скриптове в браузъра си без да ги разбирате напълно, защото това може да доведе до големи неприятности (открадване на акаунт и други) - в случая (както се вижда - .style = ...; .remove();) само местя и трия разни компоненти, но скриптът може да прави доста повече неща за това бъдете внимателни!
  • пускам SimpleScreenRecorder, настройвам го да записва цял екран, размерите на резултатното видеото да е 0.6 от реалните размери (така или иначе го намаляваме за да се вижда само в края на екрана), отказвам записът на аудио, избирам добро качество
  • пускам видеото на цял екран (от бутона долу-дясно)
  • избирам правилната гледна точка в ayvri така че маршрутът да е някъде в средата на екрана (и да не се закрива от насрещни възвишения/върхове), пускам запис в SimpleScreenRecorder посредством Ctrl+R и натискам Play след това го спирам след края на видеото в ayvri.
  • ffmpeg -i "ВИДЕО.MP4" -i "ТЕЛЕМЕТРИЯ.mkv" -filter_complex "[1]trim=31,setpts=PTS-STARTPTS[telemetry];color=c=white,vignette=angle=PI/2:aspect=4/3:x0=w/2+30:y0=h/2-10[mask];[mask][telemetry]scale2ref[scaledmask][scaledtelemetry];[scaledtelemetry][scaledmask]alphamerge,crop=exact=1:x=0:y=ih/2:w=iw/2+245:h=ih-410[pip]; [0][pip] overlay=main_w-overlay_w:0:eof_action=endall,format=yuv420p" -codec:v libx264 -crf 18 -preset slower -acodec copy РЕЗУЛТАТ.mp4
    • в зависимост от размерите на монитора/прозореца ще трябва да промените w=iw/2+245:h=ih-410 за да позиционирате телеметрията горе-дясно
    • в зависимост от отместването във времето между телеметрията и видеото ще трябва да промените колко да изрежете от началото на телеметрията (trim=31)
    • ако искате телеметрията да избледнява повече или по-малко към краищата променете angle=PI/2:aspect=4/3:x0=w/2+30:y0=h/2-10, където PI/2 контролира колко бързо да избледнява, 4/3 - в коя посока колко да избледнява, x0=w/2+30:y0=h/2-10 от къде да започне избледняването - в случая не е от центъра и по този начин се контролира колко да е избледняло към краищата
  • допълнителна информация: https://www.oodlestechnologies.com/blogs/PICTURE-IN-PICTURE-effect-using-FFMPEG/
  • може да промените изглежда от ayvri като ползвате Chrome и натиснете с десния клавиш на мишката върху елемента и след това Inspect и изтриване/промяна на съответния HTML елемент, това може да стане и с javascript, например: document.getElementById('StatsPanelContainer').style = "padding-right: 750px; padding-top: 337px;";document.getElementById("StatsPanelContainer").childNodes[0].childNodes[1].remove();document.getElementById("StatsPanelContainer").childNodes[0].childNodes[0].childNodes[3].remove();
    • имайте предвид че това маха някои от метриките, а тъй като те зависят от зададения тип на записа (туризъм, ски, парапланер) може да се наложи да се промени скрипта по-горе в зависимост от типа на активността
    • по-принцип избягвайте да изпълнявате такива скриптове в браузъра си без да ги разбирате напълно, защото това може да доведе до големи неприятности (открадване на акаунт и други) - в случая (както се вижда - .style = ...; .remove();) само местя и трия разни компоненти, но скриптът може да прави доста повече неща за това бъдете внимателни!
  • за проба може да се генерира видео с по-лошо качество, но по-бързо и по този начин да се ориентирате дали видеото и телеметрията са синхронизирани: ffmpeg -i "ВИДЕО.MP4" -i "ТЕЛЕМЕТРИЯ.mkv" -filter_complex "[1]copy [pip]; [0][pip] overlay=main_w-overlay_w:0" -profile:v main -preset ultrafast -level 3.1 -b:v 140k -ar 44100 -ab 128k -s 720x400 -vcodec h264 -acodec copy РЕЗУЛТАТ.mp4 или ffmpeg -i "ВИДЕО.MP4" -i "ТЕЛЕМЕТРИЯ.mkv" -filter_complex "[1]copy [pip]; [0][pip] overlay=main_w-overlay_w:0" -vcodec h264 -preset ultrafast -acodec copy РЕЗУЛТАТ.mp4
    • не е нужно да изчакате генерирането до край - в началото го пуснете за няколко секунди с добро качество (спира се с еднократно натискане на Ctrl+C) за да проверите дали всичко е наред (телеметрията дали е на правилното място и дали видеото е в синхрон с телеметрията)
    • най-добре да ползвате .mkv формат за да можете да видите резултатът без да спирате процесът (mp4 поставя moov atom накрая, докато в mkv това не е така и можете да гледате резултатът докато ffmpeg работи): ffmpeg -i "ВИДЕО.MP4" -i "ТЕЛЕМЕТРИЯ.mkv" -filter_complex "[1]trim=31,setpts=PTS-STARTPTS[telemetry];[telemetry]crop=exact=1:x=900+200:y=ih/2-250:w=iw/2+245-900-200:h=ih-1000,scale=w=3*iw:h=3*ih[pip]; [0:v:0][pip] overlay=main_w-overlay_w:0:eof_action=endall" -profile:v main -preset ultrafast -level 3.1 -b:v 2140k -s 1024x768 -vcodec h264 -y ПРОБА.mkv
    • може да се ползва ffmplay вместо ffmpeg
  • за съжаление тази обработка отнема доста време и за това бъдете търпеливи (може да го пуснете през нощта)

Подобряване на цветовете

Резултатът от подобряването на цветовете може да се види тук:

Повечето хора съветват, когато видеото се записва това да се прави с Flat профил и ръчни настройки за да може то да се подобри по-лесно на втори етап. Като цяло настройките по време на заснемане са от особено значение - прегледайте следните видеа: общи съвети, вкл. за GoPro, настройки, YI 4K+ или потърсете нещо конкретно за вашата камера. С две думи - fps трябва да е кратна на честотата на електрическата мрежа в страната (страните в Европа 50 Hz, САЩ - 60 Hz) за да не се получават хоризонтални плуващи черти при снимане на изкуствено осветление (това е и една от причината да има разлика между стандартите PAL/SECAM). Останалите настройки - FOV: (Ultra) Wide, Metering mode: Average, Quality: най-висока, White Balance зависи от светлината - облачно/сняг/6500K+, изгрев/залез/нажежаема крушка/3000K, дневна светлина/5500K, Color: Flat, ISO Max: на светло 400, иначе max 1600 (зависи от камерата), EV: зависи от камерата, стабилизация: включена, Sharpness: low.

Много добри съвети за обработка можете да видите тук: DaVinci Resolve, GIMP/ffmpeg.

За мен ffmpeg вариантът ми е най-удобен: print screen на кадър с най-много цветове. В GIMP>Colors>Levels>Auto и след това копираме съответните min/max стойности за Red/Green/Blue и използваме (заместваме RED_MIN и останалите) ffmpeg -i "ВИДЕО.MP4" -filter_complex "colorlevels=rimin=RED_MIN/255:rimax=RED_MAX/255:gimin=GREEN_MIN/255:gimax=GREEN_MAX/255:bimin=BLUE_MIN/255:bimax=BLUE_MAX/255,format=yuv420p" -codec:v libx264 -crf 18 -preset slower -acodec copy РЕЗУЛТАТ.mp4. Друг вариант (повече възможности, но не толкова автоматичен) е използвайки GIMP>Colors>Curves… или GIMP>Colors>Levels>Auto и бутон “Edit these Settings as Curves”, експорт до файл (Manage presets > Export Current Settings to File) и след това docker run -v "$(pwd):/data" --rm python:2 bash -c "wget https://raw.githubusercontent.com/fehlfarbe/gimp2acv/master/acv.py && wget https://raw.githubusercontent.com/fehlfarbe/gimp2acv/master/gimp2acv.py && pip install numpy && python /gimp2acv.py /data/curves" и ffmpeg -i "ВИДЕО.MP4" -filter_complex "curves=psfile=curves.acv,format=yuv420p" -codec:v libx264 -crf 18 -preset slower -acodec copy РЕЗУЛТАТ.mp4.

Погледнете още и следните филтри и линкове: Color Correct Scuba Diving, colorbalance, manupilation of video colors, GIMP 2.10 Curves, GIMP 2.10 Shadows and Highlights.

Телеметрия, стабилизиране, цветове

Описаните по-горе подобрения могат да бъдат обединени, ето и резултатът:

docker run --rm  -v "$(pwd)":/data jrottenberg/ffmpeg -i /data/ВИДЕО.MP4 -vf vidstabdetect=accuracy=15:shakiness=10:mincontrast=0.3:show=0:result=/data/transforms.trf -an -f null -
docker run --rm  -v "$(pwd)":/data jrottenberg/ffmpeg -i "/data/ВИДЕО.MP4" -i "/data/ТЕЛЕМЕТРИЯ.mkv" -filter_complex "[0]vidstabtransform=smoothing=20:input=/data/transforms.trf:optzoom=0,unsharp,colorlevels=rimin=RED_MIN/255:rimax=RED_MAX/255:gimin=GREEN_MIN/255:gimax=GREEN_MAX/255:bimin=BLUE_MIN/255:bimax=BLUE_MAX/255 [stabilized];[1]trim=31,setpts=PTS-STARTPTS[telemetry];color=c=white,vignette=angle=PI/2:aspect=4/3:x0=w/2+30:y0=h/2-10[mask];[mask][telemetry]scale2ref[scaledmask][scaledtelemetry];[scaledtelemetry][scaledmask]alphamerge,crop=exact=1:x=0:y=ih/2:w=iw/2+245:h=ih-410[pip]; [stabilized][pip] overlay=main_w-overlay_w:0:eof_action=endall,format=yuv420p" -codec:v libx264 -crf 18 -preset slower -acodec copy /data/РЕЗУЛТАТ.mp4
  • сравненията са генериране посредством
    • половин екран: docker run --rm -v "$(pwd)":/data jrottenberg/ffmpeg -i "/data/ВИДЕО.MP4" -i "/data/ТЕЛЕМЕТРИЯ.mkv" -i "/data/СЪЩОТОВИДЕОВТОРИПЪТ.MP4" -filter_complex "[0]vidstabtransform=smoothing=20:input=/data/transforms.trf:optzoom=0,unsharp,colorlevels=rimin=RED_MIN/255:rimax=RED_MAX/255:gimin=GREEN_MIN/255:gimax=GREEN_MAX/255:bimin=BLUE_MIN/255:bimax=BLUE_MAX/255 [stabilized];[1]trim=ОФСЕТ,setpts=PTS-STARTPTS[telemetry];color=c=white,vignette=angle=PI/2:aspect=4/3:x0=w/2+30:y0=h/2-10[mask];[mask][telemetry]scale2ref[scaledmask][scaledtelemetry];[scaledtelemetry][scaledmask]alphamerge,crop=exact=1:x=0:y=ih/2:w=iw/2+245:h=ih-410[pip]; [stabilized][pip] overlay=main_w-overlay_w:0:eof_action=endall,crop=exact=1:x=iw/2:y=0:w=iw/2:h=ih[right];[2:v:0][right]overlay=main_w/2:0" -vcodec h264 -acodec copy /data/РЕЗУЛТАТ.mp4
    • цял екран: docker run --rm -v "$(pwd)":/data jrottenberg/ffmpeg -i "/data/ВИДЕО.MP4" -i "/data/ТЕЛЕМЕТРИЯ.mkv" -i "/data/СЪЩОТОВИДЕОВТОРИПЪТ.MP4" -filter_complex "[0]vidstabtransform=smoothing=20:input=/data/transforms.trf:optzoom=0,unsharp,colorlevels=rimin=RED_MIN/255:rimax=RED_MAX/255:gimin=GREEN_MIN/255:gimax=GREEN_MAX/255:bimin=BLUE_MIN/255:bimax=BLUE_MAX/255 [stabilized];[1]trim=ОФСЕТ,setpts=PTS-STARTPTS[telemetry];color=c=white,vignette=angle=PI/2:aspect=4/3:x0=w/2+30:y0=h/2-10[mask];[mask][telemetry]scale2ref[scaledmask][scaledtelemetry];[scaledtelemetry][scaledmask]alphamerge,crop=exact=1:x=0:y=ih/2:w=iw/2+245:h=ih-410[pip]; [stabilized][pip] overlay=main_w-overlay_w:0:eof_action=endall[right];[2:v:0]pad=iw*2:ih[original];[original][right]overlay=w" -vcodec h264 -acodec copy /data/РЕЗУЛТАТ.mp4
    • вместо СЪЩОТОВИДЕОВТОРИПЪТ може да се ползва split
  • за съжаление тази обработка отнема доста време и за това бъдете търпеливи (може да го пуснете през нощта)

Добавяне на музика за фон

ffmpeg -f concat -safe 0 -i <(printf "file '$(pwd)/music1.mp3'\nfile '$(pwd)/music2.mp3'\nfile '$(pwd)/music3.mp3'") -c copy output.mp3
ffmpeg -i video.mp4 -i output.mp3 -c copy -map 0:v -map 1:a -shortest output-different-autio.mp4
ffmpeg -i video.mp4 -i output.mp3 -filter_complex "[0:a]volume=0.7,apad[V];[1:a][V]amix[out]" -c:v copy -map 0:v -map [out] -shortest output-final.mp4

Добавяне на снимки към видео

ffmpeg -loop 1 -framerate 50 -t 2 -i image1.png \
	-loop 1 -framerate 50 -t 2 -i image2.png \
	-f lavfi -i anullsrc=cl=stereo:r=48000 -map 2:a \
	-filter_complex "[0][1]concat=n=2:v=1:a=0,format=yuv420p" \
	-codec:v libx264 -crf 18 -preset slow \
	-ar 48000 -ab 128k \
	-y -shortest images.mp4

Разделяне на отделни клипове

Взимане на определени моменти от клип и обединяването им

  • необходими са името на файла, от който ще вземем частите (ВИДЕО.mp4) и моментите, които трябва да останат (начало-край, в променливата INCLUDE)
  • записвам си такъв файл за всяко видео
set -xe

INPUT="${INPUT:-ВИДЕО.mp4}"
INCLUDE="${INCLUDE:-
${INPUT}
00:00:17 00:01:22
00:04:10 00:05:10
# if you want to add images to video here or at the beginning:
images.mp4
00:00:00 00:00:04
}"

# тук обикновено слагам като коментар всички команди, които съм изпълнил за стабилизация, телеметрия, цветове, curve и т.н.
#https://ayvri.com/scene/.../...

#ffmpeg -i "/media/....MP4" -i "ayvri.mkv" -filter_complex "[1]trim=42,setpts=PTS-STARTPTS[telemetry];[telemetry]crop=exact=1:x=900:y=ih/2-100:w=iw/2+245-900:h=ih-900[pip]; [0:v:0][pip] overlay=main_w-overlay_w:0:eof_action=endall" -profile:v main -preset ultrafast -level 3.1 -b:v 2140k -s 1024x768 -vcodec h264 -y result.mkv

#docker run --rm -v "/media/....MP4":"/....MP4" -v "$(pwd)":/data jrottenberg/ffmpeg -i "/media/....MP4" -vf vidstabdetect=accuracy=15:shakiness=10:mincontrast=0.3:show=0:result=/data/transforms.trf -an -f null -
#docker run --rm -v "/media/....MP4":"/media/....MP4" -v "$(pwd)":/data jrottenberg/ffmpeg -i "/media/....MP4" -i "/data/ayvri.mkv" -filter_complex "[0]vidstabtransform=smoothing=20:input=/data/transforms.trf:optzoom=0,unsharp,colorlevels=rimin=1/255:rimax=172/255:gimin=1/255:gimax=169/255:bimin=4/255:bimax=167/255 [stabilized];[1]trim=42,setpts=PTS-STARTPTS[telemetry];color=c=white,vignette=angle=PI/2:aspect=4/3:x0=w/2+30:y0=h/2-10[mask];[mask][telemetry]scale2ref[scaledmask][scaledtelemetry];[scaledtelemetry][scaledmask]alphamerge,crop=exact=1:x=0:y=ih/2:w=iw/2+245:h=ih-410[pip]; [stabilized][pip] overlay=main_w-overlay_w:0:eof_action=endall,format=yuv420p" -codec:v libx264 -crf 18 -preset slower -acodec copy /data/last.mp4

CURRENT_FILE="${INPUT}"
CONCAT_LIST=""

function extract() {
# based on https://stackoverflow.com/questions/18444194/cutting-the-videos-based-on-start-and-end-time-using-ffmpeg
	function toSeconds() {
		awk -F: 'NF==3 { print ($1 * 3600) + ($2 * 60) + $3 } NF==2 { print ($1 * 60) + $2 } NF==1 { print 0 + $1 }' <<< ${1}
	}

	local start="${1}"
	local end="${2}"
	local inputFile="$(realpath "${3:-${CURRENT_FILE}}")"

	local startSeconds=$(toSeconds "${start}")
	local endSeconds=$(toSeconds "${end}")

	CONCAT_LIST="$(printf "%s\nfile '%s'\ninpoint %s\noutpoint %s" "${CONCAT_LIST}" "${inputFile}" "${startSeconds}" "${endSeconds}")"
}

IFS=$'\n'
for next in ${INCLUDE}; do
	if [[ "${next}" =~ [A-Za-z_] ]]; then
		CURRENT_FILE="${next}"
		continue
	fi
	extract "${next% *}" "${next##* }"
done

# if you want to add images to video - put images.mp4 and 00:00:00 00:00:04 to INCLUDE on line 5
# https://stackoverflow.com/questions/43958438/merge-videos-and-images-using-ffmpeg
# https://superuser.com/questions/1096921/concatenating-videos-with-ffmpeg-produces-silent-video-when-the-first-video-has

ffmpeg -loop 1 -framerate 50 -t 2 -i image1.png \
	-loop 1 -framerate 50 -t 2 -i image2.png \
	-f lavfi -i anullsrc=cl=stereo:r=48000 -map 2:a \
	-filter_complex "[0][1]concat=n=2:v=1:a=0,format=yuv420p" \
	-codec:v libx264 -crf 18 -preset slow \
	-ar 48000 -ab 128k \
	-y -shortest images.mp4

# check https://superuser.com/questions/1059245/ffmpeg-join-two-mp4-files-with-ffmpeg-on-command-line and https://stackoverflow.com/questions/7333232/how-to-concatenate-two-mp4-files-using-ffmpeg
ffmpeg -f concat -safe 0 -fflags +discardcorrupt -fflags +fastseek -fflags +genpts -avoid_negative_ts 1 -i <(echo "${CONCAT_LIST}") -c copy "${INPUT%.*}-final.${INPUT##*.}"
# even if there are some squelch in video in vlc, it will be overcome by players like youtube or mpv

rm images.mp4

# background music to video:
curl https://assets.mixkit.co/music/download/mixkit-deep-urban-623.mp3 -o background.mp3
ffmpeg -f concat -safe 0 -i <(printf "file '$(pwd)/background.mp3'\nfile '$(pwd)/background.mp3'") -c copy background-full.mp3
# aresample is because of https://stackoverflow.com/questions/35416110/ffmpeg-concat-video-and-audio-out-of-sync
ffmpeg -i "${INPUT%.*}-final.${INPUT##*.}" -i background-full.mp3 -filter_complex "[0:a]aresample=async=1000,volume=0.7,apad[V];[1:a]volume=1[A];[A][V]amix[out]" -c:v copy -c:a aac -map 0:v -map [out] -ar 48000 -ab 128k -shortest "${INPUT%.*}-final-background.${INPUT##*.}"
rm background-full.mp3

Преглед frame-by-frame

  • mpv ВИДЕО.mp4 и след това . и ,
  • между 10 и 15 (вкл.) фрейм към файл: ffmpeg -i ВИДЕО.mp4 -vf select='between(n\,10\,15)' -vsync 0 frames%d.png

Сваляне на видео от youtube

  • docker run -it --rm -v "$(pwd):/data" vimagick/youtube-dl -i -f 'bestvideo[ext=mp4]+bestaudio[ext=m4a]' -i --audio-format=mp3 -o "%(title)s.%(ext)s" 'https://www.youtube.com/watch?v=(...)'
  • сваляне само на аудио: docker run -it --rm -v "$(pwd):/data" vimagick/youtube-dl -i -f 'bestvideo[ext=mp4]+bestaudio[ext=m4a]' -x -i --audio-format=mp3 -o "%(title)s.%(ext)s" 'https://www.youtube.com/watch?v=(...)'

  • ако не работи - обновете до най-новата версия: docker pull vimagick/youtube-dl

Забързване на видео

ffmpeg -i ВИДЕО.MP4 -filter:v "setpts=0.1*PTS" -an РЕЗУЛТАТ-fast.MP4

Завъртане на видео portrait landscape, lanscape video in instagram

Използвам https://humanpoint.eu/images/giphy.gif (взето от тук: https://www.youtube.com/watch?v=vr8c_TsaYPc). Добавям го за 1 секунда в началото на клипа заедно със следния ефект:

<effectgroup id="rotatephone" parentIn="0">
 <effect id="mirror">
  <property name="reverse">0</property>
  <property name="mirror">flip</property>
 </effect>
 <effect id="fade_to_black">
  <property name="out">30</property>
  <property name="level&#xa;alpha">1
0=1;31=0.537313</property>
  <property name="in">0</property>
 </effect>
 <effect id="qtblend">
  <property name="rotate_center">1</property>
  <property name="distort">0</property>
  <property name="compositing">0</property>
  <property name="rotation">0=0</property>
  <property name="rect">0=480 270 2880 1620 1.000000</property>
 </effect>
</effectgroup>
  • ffmpeg -i "sourc.mp4" -metadata:s:v rotate="-90" -codec copy "destination.mp4"
  • #not working: exiftool -rotation=0 -api largefilesupport=1 $INPUTVIDEO

Филтър за определен период от време

Ако искаме да приложим различна корекция на цветовете в различни периоди от клипчето:

Графичен интерфейс

Повечето от нещата тук могат да се направят и през графични програми като kdenlive - например Overlay Video Picture in Picture и Stabilize Shaky Videos Using Kdenlive Free Editing Software, shotcut, pitivi, DaVinci Resolve, изрязване на видео - LosslessCut

KDEnlive

Понякога файлът се разваля, за това обикновено пускам while true; do git add .; git commit --no-gpg-sign -m wip; sleep 10; done, а в последствие git rebase -i origin/master с f на всеки ред.

Аудио обработка


Натиснете бутона "watch" в github или се абонирайте с RSS четец ако искате да научавате за обновления или нови статии.

Written on November 7, 2020