├── ib-scripts.md ├── message.md ├── op-paste ├── overlay ├── overlay.zsh ├── thread-firstframe-48k.webm ├── thread-firstframe.webm ├── thread-firstframe.xcf ├── thread-tv-clean-19_33-571_350.png └── thread-tv-clean-19_33-571_350.xcf └── tools ├── .zshrc.avenc ├── WebMaster ├── add-preview ├── fit-audio-to-limit ├── mkvsplit ├── mpv └── capture.lua └── qcomp /ib-scripts.md: -------------------------------------------------------------------------------- 1 | ##### Скрипты для репорта пидораторов в /d/ (вставлять в JS-консоль браузера): 2 | 3 | Кол-во удалённых постов на странице: 4 | ``` 5 | alert($('.de-post-deleted').length) 6 | ``` 7 | Заполнить страницу постами: 8 | ``` 9 | $('.post-wrapper').css('display','inline') 10 | ``` 11 | Вернуть: 12 | ``` 13 | $('.post-wrapper').css('display','table') 14 | ``` 15 | Скрыть все посты кроме удалённых: 16 | ``` 17 | $('.post-wrapper').not('.de-post-removed').hide() 18 | ``` 19 | Вернуть: 20 | ``` 21 | $('.post-wrapper').show() 22 | ``` 23 | Отмечать красным посты по клику даты: 24 | ``` 25 | $('.posttime').click(function(event){$(this).parent().parent().parent().css('border-color','red')}); 26 | ``` 27 | 28 | Требуется наличие куклоскрипта. 29 | -------------------------------------------------------------------------------- /message.md: -------------------------------------------------------------------------------- 1 | > Питуз, если ты это читаешь, то вернись. 2 | 3 | На сосач не вернусь — противно. И раньше было противно из-за наплевательской по отношению к анонам политики модерации, но ввод платного увеличения лимита стал последней каплей, после которой я не оставил там ни одного поста. 4 | 5 | Во-первых, это нововведение на корню убивает смысл дроча на эффективность сжатия видео в контексте борды: пропадает состязательность по способности впихивать крутые штуки в ограниченный лимит — заплатив, сосед может запостить видео в два раза сложнее, ещё и пожатое устаревшим кодеком через мокрописечный фронтенд с какой-нибудь глупостью вроде постоянного битрейта видео. 6 | 7 | Во-вторых, сама идея взимания платы за постинг контента с моей точки зрения является дикостью и крайней степенью неуважения к его авторам. Т.е. сосака рассматривает предоставление возможности постинга как услугу и берёт за неё деньги. Возможно, по отношению к большей части контингента его ресурса это и верный подход, но для меня это неприемлемо при взгляде с обоих сторон: на его месте я бы гнал таких посетителей поганой метлой. Он решил делать на них деньги — пожалуйста, но без меня: я к такому ресурсу не хочу иметь никакого отношения. 8 | 9 | В третьих, сейчас любые денежные операции в сети (кроме, возможно, криптовалют) — деанон. 10 | 11 | > Хоть в какой-нибудь тред, сам знаешь, где ещё есть. 12 | 13 | Честно говоря, не знаю. Я пока что тихо аутирую на паре мелкоборд, за пределы которых почти не хожу. 14 | 15 | > Будем вместе вебмстроение развивать, немного осталось. 16 | 17 | Немного осталось до чего? Ты наметил идеальный видеокодек в конце тоннеля? 18 | А так — я не против, конечно. Тема мне по прежнему интересна. 19 | 20 | --- 21 | 22 | Что касается войны за оп-пост в /b/. Не знаю, чем вызваны эти действия администрации. Возможно, это требование со стороны новых хозяев сосаки, или чей-то удачный троллинг пидораторов от моего имени (из оп-поста треда техподдержки пропали ссылки на этот репозиторий и вики, что иначе как личной неприязнью я объяснить не могу). 23 | 24 | Лишение треда его символа, оп-поста — очередное проявление неуважения администрации к пользователям. Единственным адекватным ответом на это является покидание сосача, что я и рекомендую сделать всем сопротивленцам и им сочувствующим. Администратор веб-ресурса является на нём царём и богом, а во власти пользователя есть только одна настоящая свобода — подчиниться администратору и остаться на ресурсе или его покинуть. 25 | 26 | Список борд есть тут: http://lurkmore.to/Отечественные_имиджборды 27 | -------------------------------------------------------------------------------- /op-paste: -------------------------------------------------------------------------------- 1 | **Анимублядский WebM-тред** 2 | для приличных анимублядей и прочих аутистов. 3 | Безграмотное быдло с дубляжом, войсовером, порнографией и котиками, советы мерзких мокрописечников, вниманиебляди всех видов и прочее непотребство отправляется в порнотред <ссылка>. 4 | Для поиска сoуса видео сохраняем кадр (правый клик по видео) и ищем его на http://images.google.com. 5 | 6 | Для воспроизведения **WebM с 10-битным цветом** нужно установить плагин vlc (http://nightlies.videolan.org/ ) и отключить встроенный в браузер плеер (media.webm.enabled=false в firefox). 7 | 8 | **О кодировании WebM** 9 | Доступные кодеки — VP8 и VP9 для видео, Vorbis и Opus для звука, **максимальный размер файла — 10240КБ**, всех файлов в посте — около 40МБ. 10 | **Делать WebM** можно научиться в вики треда: https://github.com/pituz/webm-thread/wiki/ 11 | Там находится подробная информация о выборе и настройке кодеков на примерах использования консольных утилит ffmpeg, vpxenc и mkvmerge. 12 | 13 | **Неочевидные моменты** 14 | — libvorbis при указании битрейта (-b:a) работает в режиме CBR (постоянный битрейт), и это портит качество звука; для режима VBR вместо битрейта надо указывать качество (-q:a); параметр -vbr on работает только для Opus'а; 15 | — в webm'ки не нужно включать софтсаб в формате webvtt (FFmpeg это делает по умолчанию при наличии сабов в контейнере, отключается параметром **-sn**): во-первых, это бесполезно (для его отображения на странице должен быть специальный код), а во-вторых, от этого ролики не воспроизводятся в firefox. 16 | 17 | **Программы и их документация** 18 | http://webmproject.org http://ffmpeg.org http://mpv.io http://www.bunkus.org/videotools/mkvtoolnix/ 19 | 20 | **Фронтенды к ffmpeg для кодирования вебмок** 21 | CLI, бидон: https://pypi.python.org/pypi/webm 22 | CLI, zsh: https://github.com/pituz/webm-thread/tree/master/tools 23 | CLI, дотнет: https://github.com/CherryPerry/ffmpeg-vp9-wrap 24 | GUI, дотнет: https://gitgud.io/nixx/WebMConverter 25 | 26 | **Оп-паста**: https://github.com/pituz/webm-thread/blob/master/op-paste 27 | -------------------------------------------------------------------------------- /overlay/overlay.zsh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env zsh 2 | source ~/.zshrc.avenc 3 | iargs=() 4 | oargs=() 5 | while getopts "s:t:n" o; do 6 | case $o in 7 | s) iargs=(-ss $OPTARG) ;; 8 | t) oargs=(-t $OPTARG); length=$OPTARG;; 9 | n) nofirstframe=1 10 | esac 11 | done 12 | shift $((OPTIND-1)) 13 | [[ -z $length ]] && length=$(ffprobe $1 2>&1|sed -n 's/.*Duration: \([^,]\+\),.*/\1/p') 14 | for pass in 1 2 15 | ffmpeg -hide_banner $iargs -i $1 \ 16 | -i thread-tv-clean-19_33-571_350.png \ 17 | $oargs \ 18 | -filter_complex ' 19 | [0:v] scale=-1:317 [v0], 20 | [v0] pad=600:446:((552-iw)/2+20):35:black [v1], 21 | [v1] [1:v] overlay [v2]' \ 22 | -map '[v2]' -map '0:a' -ac 2 -crf 20 -b:v $(hkbr $length) -pass $pass -y "$(basename $1)-overlay-v.webm" || exit 1 23 | if ! ((nofirstframe)) 24 | then 25 | mkvmerge thread-firstframe.webm + "$(basename $1)-overlay-v.webm" -o "$(basename $1)-overlay.webm" || exit 1 26 | rm "$(basename $1)-overlay-v.webm" 27 | fi 28 | -------------------------------------------------------------------------------- /overlay/thread-firstframe-48k.webm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pituz/webm-thread/cc5eec23f86e1b8b91ab8508e18fe1b1596c4073/overlay/thread-firstframe-48k.webm -------------------------------------------------------------------------------- /overlay/thread-firstframe.webm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pituz/webm-thread/cc5eec23f86e1b8b91ab8508e18fe1b1596c4073/overlay/thread-firstframe.webm -------------------------------------------------------------------------------- /overlay/thread-firstframe.xcf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pituz/webm-thread/cc5eec23f86e1b8b91ab8508e18fe1b1596c4073/overlay/thread-firstframe.xcf -------------------------------------------------------------------------------- /overlay/thread-tv-clean-19_33-571_350.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pituz/webm-thread/cc5eec23f86e1b8b91ab8508e18fe1b1596c4073/overlay/thread-tv-clean-19_33-571_350.png -------------------------------------------------------------------------------- /overlay/thread-tv-clean-19_33-571_350.xcf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pituz/webm-thread/cc5eec23f86e1b8b91ab8508e18fe1b1596c4073/overlay/thread-tv-clean-19_33-571_350.xcf -------------------------------------------------------------------------------- /tools/.zshrc.avenc: -------------------------------------------------------------------------------- 1 | time_to_seconds() { 2 | [[ $1 =~ ^((([0-9]+):)?([0-9]+):)?([0-9.]+)$ ]] 3 | local result=$((match[3]*3600 + match[4]*60 + match[5])) 4 | [[ -n $2 ]] && (($2=result)) || echo $result 5 | } 6 | hkbr() { 7 | if [[ -z $1 ]] 8 | then 9 | cat <320: size, kb 17 | result size - desired size of final file, kb 18 | default - 6144 19 | END 20 | return 1 21 | fi 22 | local fs=${3-6144} 23 | local s=$(time_to_seconds $1) 24 | if [[ -z $2 ]] 25 | then ((as = s * 120 / 8)) 26 | elif [[ -f $2 ]] 27 | then as=$(( $(stat -c '%s' $2) / 1024)) 28 | elif [[ $2 -le 320 ]] 29 | then ((as = s * $s / 8)) 30 | else 31 | as=$2 32 | fi 33 | echo "$(( (fs - as) * 8 / s))k" 34 | } 35 | -------------------------------------------------------------------------------- /tools/WebMaster: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env zsh 2 | programname=$0:t 3 | help() { 4 | cat >&1 <=10: opus bitrate, kbit/s (default: 64) 19 | .: copy audio 20 | n: disable audio 21 | -f - owerwrite files 22 | (othervise conversion with existing results will be skipped) 23 | -w width - scale destination video to given width 24 | . - don't scale (default) 25 | -b - use "best" VP8/VP9 quality setting 26 | -C value - cpu-used (speed) VP8/VP9 setting: 27 | 0..4 for VP8, 0..8 for VP9 28 | 0 - better quality, max - faster speed, default: 1 29 | -c crf - constant rate factor (default: 16) 30 | -m qp - miniumal quantizer scale, qmin (default: 8) 31 | -M qp - qmax (default: 60) 32 | -B bitrate - specify video bitrate, kbit/s 33 | .: calculate bitrate from file size (default) 34 | -n filename - output filename (.webm will be added) 35 | -F size - result size, kilobytes (default: 6144) 36 | -S filename - render subtitles (. to use subs from container) 37 | -A value - audio filters 38 | -V value - video filters 39 | -k - keep temporary files (directory \$output_filename.webm.tmp) 40 | -v - verbose output 41 | Options of prior files will be used as defaults for next. 42 | Exceptions: filename (-n), time options (-s -t -T). 43 | 44 | Environment variables: 45 | FFMPEG - path to ffmpeg binary 46 | PIX_FMT - pixel format to use (default: +yuv420p) 47 | MUX_WITH_FFMPEG - use ffmpeg for muxing instead of mkvmerge 48 | END 49 | exit 1 50 | } 51 | log() { 52 | local prompt="${bg[blue]} i ${reset_color}" 53 | [[ $1 == '-p' ]] && prompt=$2 && shift 2 54 | local fmt=$1 55 | shift 56 | printf "$prompt $fmt\n" $@ 57 | } 58 | time_to_seconds() { 59 | [[ $1 =~ ^((([0-9]+):)?([0-9]+):)?([0-9.]+)$ ]] 60 | local result=$((match[3]*3600 + match[4]*60 + match[5])) 61 | [[ -n $2 ]] && (($2=result)) || echo $result 62 | } 63 | perform() { 64 | ((verbose)) && echo "${fg[red]}> ${reset_color}" "$@" 65 | $@ 66 | } 67 | # defaults 68 | width=. 69 | fsize=6144 70 | audio=64 71 | force=0 72 | vp9=1 73 | typeset -A vencopts # options for 2nd video pass 74 | vencopts=( 75 | -crf 16 76 | -qmin 8 77 | -qmax 60 78 | ) 79 | [[ -n $FFMPEG ]] || FFMPEG=(ffmpeg -hide_banner -v warning -stats) 80 | 81 | # config file 82 | for f in $0.rc ~/.${programname}rc; [[ -f $f ]] && source $f 83 | unset f 84 | 85 | [[ -z $1 ]] && help 86 | set -e 87 | autoload colors; colors 88 | 89 | while [[ ! -z $1 ]] 90 | do 91 | unset output_file 92 | start=. 93 | unset length 94 | OPTIND=1 95 | while getopts "89a:fbC:c:m:M:B:w:s:t:T:n:S:hF:A:V:kv" o 96 | do 97 | case $o in 98 | 8) vp9=0;; 99 | 9) vp9=1;; 100 | a) audio=$OPTARG;; 101 | f) force=1;; 102 | w) width=$OPTARG;; 103 | s) [[ $OPTARG == . ]] && start=$OPTARG || time_to_seconds $OPTARG start;; 104 | t) time_to_seconds $OPTARG length;; 105 | T) length=$(($(time_to_seconds $OPTARG) - start));; 106 | b) vencopts[-quality]="best";; 107 | C) vencopts[-speed]=$OPTARG;; 108 | c) vencopts[-crf]=$OPTARG;; 109 | m) vencopts[-qmin]=$OPTARG;; 110 | M) vencopts[-qmax]=$OPTARG;; 111 | B) force_bitrate=$OPTARG;; 112 | n) output_file="${OPTARG%.webm}.webm";; 113 | S) subs=$OPTARG;; 114 | F) fsize=$OPTARG;; 115 | A) custom_afilters=$OPTARG;; 116 | V) custom_vfilters=$OPTARG;; 117 | k) keeptmp=1;; 118 | v) verbose=1;; 119 | h|?) help;; 120 | esac 121 | done 122 | shift $((OPTIND - 1)) 123 | [[ $1 == . ]] || input_file=$1 124 | [[ -z $input_file ]] && help 125 | shift 126 | 127 | # set output filename 128 | [[ -z $output_file ]] && output_file="${input_file:t:r}.webm" # strip path and extension 129 | [[ $output_file == $input_file ]] && output_file=${input_file/webm/converted.webm} 130 | # without -f skip existing files 131 | ! ((force)) && [[ -f $output_file ]] && continue 132 | 133 | # temporary dir and files 134 | tmpdir="$output_file.tmp" 135 | af="$tmpdir/audio.webm"; af_part="$tmpdir/audio.part.webm" 136 | vf="$tmpdir/video.webm"; vf_part="$tmpdir/video.part.webm" 137 | mkdir -p $tmpdir 138 | 139 | # video output options 140 | vopts=(-pix_fmt ${PIX_FMT-+yuv420p}) 141 | ((vp9)) \ 142 | && vopts+=(-c:v libvpx-vp9) \ 143 | || vopts+=(-c:v libvpx -auto-alt-ref 1 -lag-in-frames 16) 144 | 145 | # audio output options 146 | if [[ $audio == "." ]] 147 | then aopts=(-c:a copy) 148 | elif (($audio >= 10)) 149 | then aopts=(-c:a libopus -b:a "${audio}k") 150 | elif [[ $audio == "n" ]] 151 | then aopts=(-an) 152 | else 153 | aopts=(-c:a libvorbis -q:a $audio) 154 | fi 155 | 156 | # input options 157 | iopts=() 158 | [[ $start == . ]] && start=$( 159 | ffmpeg -i $input_file -vframes 200 -vf blackdetect=d=0.01 -f null -y /dev/null 2>&1 \ 160 | | awk -F'[: ]' '/black_start:0 /{print $9}') 161 | [[ -n $start ]] && iopts+=(-ss $start) || unset start 162 | 163 | # filters 164 | vfilters=( ) 165 | afilters=( ) 166 | [[ $width != . ]] && vfilters+=("scale=${width}:trunc(${width}/dar/2)*2") 167 | if [[ -n $subs ]] 168 | then 169 | [[ $subs == . ]] && subs_file=$input_file || subs_file=$subs 170 | [[ $subs_file =~ ass$ ]] \ 171 | && subs_filter="ass='${subs_file//'\'/'\\'}'" \ 172 | || subs_filter="subtitles='${subs_file//'\'/'\\'}'" 173 | # hack: temporary shift frame timings to render subtitles 174 | (($start)) \ 175 | && vfilters+=( setpts=PTS+$start/TB $subs_filter setpts=PTS-STARTPTS ) \ 176 | || vfilters+=( $subs_filter ) 177 | fi 178 | vfilters+=( $custom_vfilters ) 179 | afilters+=( $custom_afilters ) 180 | ((${#afilters})) && aopts+=(-af ${(j:,:)afilters}) 181 | ((${#vfilters})) && vopts+=(-vf ${(j:,:)vfilters}) 182 | 183 | # general output options 184 | opts=() 185 | time_to_seconds "$(ffprobe $input_file 2>&1|sed -n 's/.*Duration: \([^,]\+\),.*/\1/p')" source_length 186 | [[ -z $length ]] && ((length = source_length - start)) 187 | opts+=(-t $length) 188 | log -p "${fg[green]}==>$reset_color" 'Compressing %s (%d seconds, overall bitrate: %dK)' \ 189 | $output_file $length $((fsize * 8 / length)) 190 | 191 | # first step: audio 192 | counters[1]=$SECONDS 193 | if [[ $audio == "n" ]] 194 | then 195 | unset af 196 | else 197 | if ((force)) || ! [[ -f $af ]] 198 | then 199 | log '%s: encoding audio (%s)' $output_file "$aopts" 200 | perform $FFMPEG $iopts -i $input_file \ 201 | -vn -map 0:a:0 $opts $aopts -strict -2 -y $af_part 202 | mv $af_part $af 203 | fi 204 | ((audio_size = $(stat -c%s $af) / 1024)) 205 | fi 206 | log '%s: audio size: %d KiB, bitrate for video: %dK' \ 207 | $output_file $audio_size $((vbitrate = (fsize - audio_size) * 8 / length)) 208 | ((force_bitrate)) && vbitrate=$force_bitrate 209 | 210 | # second step: first pass of video 211 | counters[2]=$SECONDS 212 | if ((force)) || ! [[ -f "$tmpdir/2pass-0.log" ]] 213 | then 214 | log "$output_file: examining video" 215 | perform $FFMPEG -loglevel error $iopts -i $input_file \ 216 | -an -map 0:v:0 $opts $vopts -pass 1 -passlogfile "$tmpdir/2pass.part" -f null - 217 | mv $tmpdir/2pass{.part,}-0.log 218 | fi 219 | 220 | # third step: second pass of video 221 | counters[3]=$SECONDS 222 | if ((force)) || ! [[ -f $vf ]] 223 | then 224 | log "%s: encoding video (-b:v %dK %s)" $output_file $vbitrate "${(kv)vencopts}" 225 | perform $FFMPEG $iopts -i $input_file \ 226 | -map 0:v:0 $opts $vopts \ 227 | -b:v ${vbitrate}K ${(kv)vencopts} \ 228 | -pass 2 -passlogfile "$tmpdir/2pass" -y $vf_part 229 | mv $vf_part $vf 230 | fi 231 | 232 | # muxing result 233 | if ((MUX_WITH_FFMPEG)) 234 | then 235 | perform $FFMPEG -i $vf ${af+-i} $af -c copy -y $output_file 236 | else 237 | perform mkvmerge -q $vf $af -o $output_file || [[ $? == 1 ]] 238 | fi 239 | 240 | # checking output file size 241 | ofsize="$(stat -c %s $output_file)" 242 | log '%s encoded: size %d KiB, time: total %d | audio %d | pass1 %d | pass2 %d seconds.' \ 243 | $output_file $((ofsize/1024)) $((SECONDS - counters[1])) $((counters[2] - counters[1])) \ 244 | $((counters[3] - counters[2])) $((SECONDS - counters[3])) 245 | ((ofsize > fsize * 1024)) \ 246 | && { 247 | log '%s is too big, bitrate overshoot: %dK' $output_file \ 248 | $((bitrate_overshoot = (ofsize / 1024 - fsize) * 8 / length)) 249 | # lowering opus bitrate with fit-audio-to-limit 250 | ((audio >= 10)) && ((audio - bitrate_overshoot > 4)) \ 251 | && perform ${0:A:h}/fit-audio-to-limit -F $fsize \ 252 | ${start:+-s} $start $input_file $output_file 253 | } || ((keeptmp)) || rm -r $tmpdir 254 | echo "${fg[red]}-----${reset_color}" 255 | done 256 | -------------------------------------------------------------------------------- /tools/add-preview: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env zsh 2 | zparseopts -D -a optlist -A opts s: w: i: 8 3 | if [[ ! -f $1 ]]; then 4 | cat<&2 7 | exit 1 8 | } 9 | time_to_seconds() { 10 | [[ $1 =~ ^((([0-9]+):)?([0-9]+):)?([0-9.]+)$ ]] 11 | local result=$((match[3]*3600 + match[4]*60 + match[5])) 12 | [[ -n $2 ]] && (($2=result)) || echo $result 13 | } 14 | help() { 15 | cat<&1|sed -n 's/.*Duration: \([^,]\+\),.*/\1/p')" duration 51 | video_size=$(( $(ffmpeg -hide_banner -v error -i $video_src -an -c copy -f matroska - | wc -c) )) 52 | result_size=0 53 | ((audio_bitrate = (size_limit - video_size) * 8 / duration)) 54 | try=1; 55 | printf "Fitting %s to %d KiB limit by compressing audio..\n" $video_src $((size_limit/1024)) 56 | printf "video size: %d KiB; space for audio: %d KiB; duration: %d seconds; bitrate: %.2f kbps\n" \ 57 | $((video_size/1024)) $(((size_limit - video_size) / 1024)) $duration $((audio_bitrate / 1024)) 58 | ((audio_bitrate < 0)) && die "Impossiburu: no space for audio" 59 | 60 | while ((result_size > size_limit)) || ((result_size + max_size_skew < size_limit)) 61 | do 62 | ((try > max_tries)) && die "Too many failures, aborting." 63 | if ((result_size)) 64 | then 65 | ((bitrate_diff = size_skew * 8 / duration )) 66 | ((abs(bitrate_diff) < min_bitrate_diff)) && 67 | ((bitrate_diff = size_skew / abs(size_skew) * min_bitrate_diff)) 68 | ((audio_bitrate += bitrate_diff)) 69 | fi 70 | ((audio_bitrate > max_audio_bitrate)) && audio_bitrate=$max_audio_bitrate 71 | 72 | printf "Try %d of %d: bitrate %.2f kbps\n" \ 73 | $((try++)) $max_tries $((audio_bitrate/1024.0)) 74 | ffmpeg -hide_banner -v error -stats -ss $audio_start -i $audio_src -map 0:a:0 -t $duration \ 75 | ${audio_filters:+-af} $audio_filters \ 76 | -c:a libopus -application audio -vbr on -b:a $audio_bitrate -y $audio_file 77 | if ((MUX_WITH_FFMPEG)) 78 | then 79 | ffmpeg -hide_banner -v error -i $video_src -i $audio_file -map 0:v -map 1:a -c copy -y $dst_file 80 | else 81 | mkvmerge -q -A $video_src $audio_file -o $dst_file 82 | fi 83 | result_size=$(( $(stat -c%s $dst_file) )) 84 | ((size_skew = size_limit - result_size )) 85 | printf "Result size: %.3f KiB (%.3f KiB to limit)\n" \ 86 | $((result_size / 1024.0)) $((size_skew / 1024.0)) 87 | 88 | ((audio_bitrate == max_audio_bitrate)) && break 89 | done || : 90 | rm $audio_file 91 | -------------------------------------------------------------------------------- /tools/mkvsplit: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env zsh 2 | zparseopts -D -K q=quiet -quiet=quiet 3 | if [[ $1 -eq 0 ]] || ! [[ -f $2 ]]; then 4 | echo "Usage: $0 [-q|--quiet] limit_in_kb source_file" 5 | exit 1 6 | fi 7 | 8 | input_file=$2 9 | output_file="${2:t:r}-split.${2:e}" 10 | 11 | ((size_limit=$1*1024)) 12 | timecodes=( $( 13 | LANG=C mkvinfo -v -v $input_file | 14 | awk -F'[ ,()]+' ' 15 | !vtrack && /Track number:/ {t=$5} 16 | !vtrack && /Track type: video at/ {vtrack=t} 17 | $3!="SimpleBlock" || $4!="key" || $7!=vtrack {next} 18 | $16-split_pos > '$size_limit' { 19 | printf("%s ", prev_time); 20 | print (prev_pos-split_pos)/1024 > "/dev/stderr"; 21 | split_pos=prev_pos-10240; # 10kb for file header 22 | } 23 | {prev_time=$14; prev_pos=$16}' 24 | ) ) 25 | if ((MUX_WITH_FFMPEG)); then 26 | ffmpeg -hide_banner -v error -i $input_file \ 27 | -c copy -f segment -reset_timestamps 1 -segment_times ${(j:,:)timecodes} \ 28 | "${output_file:r}-%003d.${output_file:e}" 29 | else 30 | mkvmerge ${quiet+-q} --split timecodes:${(j:,:)timecodes} $input_file -o $output_file 31 | fi 32 | [[ -n $quiet ]] || du ${2:t:r}-split*.${2:e} 33 | -------------------------------------------------------------------------------- /tools/mpv/capture.lua: -------------------------------------------------------------------------------- 1 | --[[ 2 | usage: place script into $HOME/.mpv/scripts/ directory (%APPDATA%\mpv\scripts on windows) 3 | or run mpv --lua path/to/capture.lua 4 | or add "lua=/absolute/path/to/capture.lua" to ~/.config/mpv/mpv.conf (%APPDATA%\mpv\mpv.conf on windows) 5 | keybindings: 6 | a - capture fragment: at first press script remembers start position, at second outputs command for encoding 7 | c - crop: first press remembers mouse cursor coords, second outputs crop filter parameters. 8 | ]] 9 | capture = {} 10 | local gp 11 | if mp.get_property == nil then 12 | gp = mp.property_get 13 | else 14 | gp = mp.get_property 15 | end 16 | function capture.handler() 17 | local c = capture 18 | if c.start then 19 | print(string.format("ffmpeg -ss %f -i '%s' -t %f", 20 | c.start, gp("path"), gp("time-pos")-c.start)) 21 | print(string.format("mpv '%s' --start %s --length %s", 22 | gp("path"), c.start, gp("time-pos")-c.start)) 23 | print(string.format("WebMaster -s %s -t %s '%s'", 24 | c.start, gp("time-pos")-c.start, gp("path"))) 25 | c.start = nil 26 | else 27 | c.start = tonumber(gp("time-pos")) 28 | end 29 | end 30 | function capture.crop() 31 | local x, y = mp.get_mouse_pos() 32 | local resX, resY = mp.get_osd_resolution() 33 | -- print(x .. ":" .. y .. " " .. resX .. "x" .. resY ) 34 | local c = capture 35 | if c.pos then 36 | local pos2 = mp.get_mouse_pos() 37 | local w, h = gp('width'), gp('height') 38 | print(string.format("crop=%d:%d:%d:%d", 39 | (x - c.pos[1]) * w / resX, (y - c.pos[2]) * h / resY, 40 | c.pos[1] * w / resX, c.pos[2] * h / resY)) 41 | c.pos = nil 42 | else 43 | c.pos = {x, y} 44 | end 45 | end 46 | --mp.add_key_binding("a", "capture", capture.handler) 47 | mp.set_key_bindings({ 48 | {"c", capture.crop}, 49 | {"a", capture.handler} 50 | }) 51 | mp.enable_key_bindings() 52 | -------------------------------------------------------------------------------- /tools/qcomp: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env zsh 2 | setopt ERR_EXIT 3 | if [[ -z $1 ]] 4 | then 5 | cat < 1)) && printf "-" || printf "+")append" \ 23 | -background wheat1 "label:$( 24 | printf 'QP: %d PSNR: %s dB SIZE: %.2f KiB' $q $psnr $(($(stat -c %s sample.webm)/1024.0)) 25 | )" -gravity Center -append q$q.png 26 | done 27 | convert -background wheat1 label:$codec -gravity Center <(montage -geometry +0+0 q*.png -) -append $codec.png 28 | rm q*.png sample.{webm,png} compare.png 29 | done 30 | rm ref.png 31 | --------------------------------------------------------------------------------