Compare commits

...

15 Commits

Author SHA1 Message Date
pta b904a10251 Improve documentation in README.md 2023-08-22 14:33:40 -04:00
pta 07de52cd9d Rename condition branch for clarity and organize variables
"simple" was vague: does it still respect looppoints?, filters?
"singlepass" at least conveys what it does
2023-08-22 13:41:59 -04:00
pta 858cac9744 Relocate target bitrate calculations under condition branches 2023-08-22 13:21:57 -04:00
pta ba1dce93dc Move more documentation to README.md 2023-08-22 13:19:06 -04:00
pta 8c6a951662 Move documentation to README.md 2023-08-20 20:53:51 -04:00
pta 9c7018e1d4 Make concatvid take argument files on the command line 2023-08-20 19:59:38 -04:00
pta 72dd66273f Add alias to watch TBS without an initial audio sync
The TBS stream has been having audio timestamp problems that makes
playback impossible. This alias at least makes it playable, though
dumped clips will likely have broken timestamps and thus be difficult or
impossible to transode. I haven't yet learned how to fix those.
2023-08-20 19:27:54 -04:00
pta 7acfc21e63 Add ab-loop points to OSD status message 2023-08-20 18:59:45 -04:00
pta 41a14e7d8d Set bitrate limit on short clips and add new encode modes
Now includes separate ffmpeg command outputs for single and dual pass
encoding and stream copying. Improved variable naming, audio encoding
can be toggled in mpv, and unix niceness variable added to modify
ffmpeg's scheduling priority.
2023-08-20 15:30:45 -04:00
pta 6a916efcc0 Add comment about what the "vft" variable is 2023-08-19 16:10:38 -04:00
pta 7b520391d5 Document and improve readability of crop and filter variables 2023-08-19 16:04:51 -04:00
pta 5447db5011 Fix indentation and remove unnecessary spaces 2023-08-19 16:01:19 -04:00
pta ad4e2a3e58 Remove unnecessary spaces around lua string concatenation operator 2023-08-19 15:56:39 -04:00
pta 9d9b4c6867 Add function and keys to set "a" and "b" loop points separately
Documentation added too
2023-08-19 15:52:13 -04:00
pta f4f162ae37 Relocate original author's code block to place of use 2023-08-19 15:38:00 -04:00
4 changed files with 186 additions and 125 deletions

View File

@ -1,7 +1,59 @@
# My mpv config directory
Only the parts I actually use. I use mpv just to watch, clip, and listen to live streams, downloaded idol music and concerts, and videos from any site yt-dlp can handle.
## Pro tip: use mpv to stream albums from Youtube Music ad-free
# 4chan webm spammer's mpv config directory
Includes lua scripts for dumping portions of network streams to files, cropping those videos, and, to your clipboard, copying ffmpeg command lines for making webms.
Also, some shell aliases and functions for:
- making audioless copies of webms
- concatenating video files that use the same codec
- converting youtube live stream URLs into their chat window URLs
- taking screenshots with ffmpeg
- watching Japanese news channels
## Key bindings
### Generally used
- `l`: set ab-loop points; see mpv man page
- `,`, `.`: frame stepping
- `a`, `b`: adjust ab-loop points separately
- `s`: screenshot
- `O`: show playback time, estimated frame number, mouse position, crop filters, and ab-loop points
### Save portions of a live stream to disk
- `Ctrl-a`: dumps the contents of the demuxer cache that's inside your selected ab-loop to a file in a configured directory. Intended for network streams. No reason to use this on local files since ffmpeg can operate on those. I have "demuxer-max-bytes=128M" in my mpv.conf, which usually keeps the last 3-15 minutes of the stream in memory, depending on the bitrate, so I have that much time to rewind the streams and clip something. Be careful when dumping. If you have the a-point but not the b-point set, it will continuously dump the entire cache up to the present and I haven't found out how to stop it besides closing mpv. Look up `ab-loop` in the mpv man page for details.
### Make webms
- `c`: begin crop selection, then select two corners of crop area with mouse
- arrow keys can be used to make coarse adjustments to crop area
- alt+arrow keys to make fine adjustments
- `d`: remove the crop filter
- `m`: toggle mute; excludes audio from generated webm
The next four keys put a string like this into your clipboard.
```bash
nice ffmpeg -i 'file:/home/anon/動画/切り抜き/watch?v=MgqP9WWvH0w23082108:55:4545.mkv' -vf crop=749:909:574:51 -c:v libvpx-vp9 -b:v 1555.7355991503k -pass 1 -ss 0.004 -to 6.104 -an -f null /dev/null && nice ffmpeg -hide_banner -y -i 'file:/home/anon/動画/切り抜き/watch?v=MgqP9WWvH0w23082108:55:4545.mkv' -vf crop=749:909:574:51 -c:v libvpx-vp9 -b:v 1555.7355991503k -pass 2 -ss 0.004 -to 6.104 -c:a libopus /tmp/a.webm; rm -f ffmpeg2pass-0.log
```
Just paste it into a terminal and run it. Default output file is /tmp/a.webm. Rename it when done. Use on local video files, not on network streams. All of them use ab-loop points, if set, and mute setting. If unset, the a-point defaults to start-of-video. If unset, the b-point defaults to end-of-video. Tip: pause and use the `,` and `.` keys to skip frames to the exact loop points you want for the webm, then hit `l` to set the loop points. Points can be reset separately with `a` or `b` keys.
- `Ctrl-s`: get ffmpeg command for single-pass encoding. Works only on files
- `Ctrl-d`: get ffmpeg command for dual-pass encoding. Works only on files
- `Ctrl-t`: like `Ctrl-d` but covers the ticker on 1080p WNI clips
- `Ctrl-c`: get ffmpeg command for stream copying. Works only on files. For copying a clip from a preexisting webm. Doesn't preserve a crop since that requires a re-encode.
`Ctrl-d` and `Ctrl-t` restrict the video portion of the result webm to 4chan's 4 megabyte file limit while preserving as much image quality as possible.
I usually run mpv from Dired in emacs, using the `openwith` package, which calls mpv with the video's absolute path, so the copied ffmpeg command can find the file from any working-directory. Running mpv from the shell sets the mpv's `path` property to whatever path you used on the command line.
## dump.lua
Edit the cache dumps directory to your preferred directory before using.
### Similar scripts
https://github.com/occivink/mpv-scripts/blob/master/scripts/encode.lua
https://github.com/ekisu/mpv-webm/releases/download/latest/webm.lua
webm.lua doesn't work on one of my machines for some reason, and I prefer encoding on the command line anyways, where I can use bash's line editing and history navigation and see ffmpeg's status messages.
## crop.lua
Found on https://github.com/occivink/mpv-scripts#croplua. Useful for the rare occasion that I want mpv to show only part of the video. Also now used to crop videos before making a webm. Supports recursive cropping by chaining crop filters, though my webm script works only with filter chains length 0 or 1.
To screenshot just part of the video, set a crop first, then press your screenshot key. Only the cropped portion will be screenshot.
## Use mpv to stream albums from Youtube Music ad-free
### Example:
1. Go to an album's page. It should be of the form "/playlist?list=<playlist id>"
https://music.youtube.com/playlist?list=OLAK5uy_nscRtcc2KZcydiVY7q0feukzm177h8yyw
@ -10,6 +62,3 @@ https://music.youtube.com/playlist?list=OLAK5uy_nscRtcc2KZcydiVY7q0feukzm177h8yy
mpv 'https://music.youtube.com/playlist?list=OLAK5uy_nscRtcc2KZcydiVY7q0feukzm177h8yyw'
```
You can even skip songs forwards and backwards like you can with local files using the < and > keys.
## crop.lua
Found on https://github.com/occivink/mpv-scripts#croplua. Useful for the rare occasion that I want mpv to show only part of the screen.

View File

@ -1,6 +1,6 @@
# taken from https://github.com/mpv-player/mpv/issues/3428
# mouse position added to ease getting coordinates for overlay filters in ffmpeg
osd-status-msg=${playback-time/full} / ${duration} (${percent-pos}%)\nframe: ${estimated-frame-number} / ${estimated-frame-count} / ${mouse-pos} / ${vf}
osd-status-msg=${playback-time/full} / ${duration} (${percent-pos}%)\nframe: ${estimated-frame-number} / ${estimated-frame-count}\nmouse-pos:${mouse-pos}\nfilters: ${vf}\nloop-start: ${=ab-loop-a}\nloop-end: ${=ab-loop-b}
vo=gpu
ao=alsa
screenshot-template="~/ダウンロード/%F%P%#n"

View File

@ -1,59 +1,29 @@
-- TL;DR
-- Ctrl-a to dump ab-loop. Intended for network streams.
-- Ctrl-c to get ffmpeg command for terminal. Works only on files
-- Ctrl-t: like Ctrl-c but covers the ticker on 1080p WNI clips
-- But first change the cache dumps directory to your preferred directory
-- Dumps the contents of the demuxer cache that's inside your selected ab-loop to a file
-- in a configured directory. No reason to use this on local files since ffmpeg can
-- operate on those.
--
-- I have "demuxer-max-bytes=128M" in my mpv.conf, which usually keeps the last 3-15
-- minutes of the stream in memory, depending on the bitrate, so I have that much time to
-- rewind the streams and clip something. I'm sure the clip channels on youtube use a larger
-- cache setting or even save the whole stream to a file for editing and uploading
-- quickly. Their workflow is likely more efficient.
--
-- The key to set the ab-loop is by default set to "l". Be careful when dumping. If you
-- have the a-point but not the b-point set, it will continuously dump the entire cache up
-- to the present and I haven't found out how to stop it besides closing mpv. Look up
-- "ab-loop" in the mpv man page for further information.
-- dump ab-loop to a file in configured directory
function dumploop()
mp.command("ab-loop-align-cache")
mp.command("ab-loop-dump-cache "
-- the following 2 lines won't work on Windows, I think.
.. os.getenv("HOME")
.. "/動画/切り抜き/" -- my cache dumps directory. Adjust to your system.
..os.getenv("HOME")
.."/動画/切り抜き/" -- my cache dumps directory. Adjust to your system.
-- spaces in filenames replaced with an underscore (or any non-space char),
-- needed because lua splits filenames on spaces
.. string.gsub(mp.get_property("filename"), "%s", "_")
.. os.date("%y%m%d%X%S")
.. ".mkv");
..string.gsub(mp.get_property("filename"), "%s", "_")
..os.date("%y%m%d%X%S")
..".mkv");
end
mp.add_key_binding("ctrl+a", dumploop)
-- All code below copied from https://github.com/Arieleg/mpv-copyTime and modified
-- Copies the ffmpeg command for the selected ab-loop to the clipboard. Use on local video
-- files, not on network streams
--
-- This script puts a string like this into your clipboard, so just paste into a terminal
-- and run it. Add "-an" before the first "-i" to not include audio. Adjust other
-- parameters if needed, like the output file, which is /tmp/a.webm by default.
-- ffmpeg -i 'file:/home/anon/動画/切り抜き/watch?v=El1YV9tTRAw23080409:45:1717.mkv' -f lavfi -i color=white:s=1698x102 -filter_complex overlay=33:961, -crf 32 -b:v 2200k -ss 2.747000 -to 4.647000 /tmp/a.webm
--
-- If you set only the a-point, the copied command won't have the "-to" setting, so the
-- result webm will start from the a-point and end at end-of-file. And if you don't set
-- the loop at all, the command will transcode the entire clip
-- Tip: pause and use the , and . keys to skip frames to the exact loop points you want for
-- the webm, then hit "l" to set the loop point.
--
-- TODO: copy the code to set start and end points separately at any time from
-- https://github.com/ekisu/mpv-webm/releases/download/latest/webm.lua or
-- https://github.com/occivink/mpv-scripts/blob/master/scripts/encode.lua
-- Yes, I know these scripts are more convenient overall, but webm.lua doesn't work on one
-- of my machines for some reason. And I prefer encoding on the command line anyways,
-- where I can use bash's line editing and history navigation, and see ffmpeg's output.
-- set ab-loop start and end points separately at any time
function setpoint(x)
mp.set_property_number(x, mp.get_property_number("time-pos"))
end
function setstart() setpoint("ab-loop-a") end
function setend() setpoint("ab-loop-b") end
mp.add_key_binding("a", "setstart", setstart)
mp.add_key_binding("b", "setend", setend)
-- All code below copied from https://github.com/Arieleg/mpv-copyTime and modified
-- Copies the ffmpeg webm command for the selected ab-loop to the clipboard.
require 'mp'
require 'mp.msg'
@ -71,7 +41,7 @@ local function platform_type()
end
local function command_exists(cmd)
local pipe = io.popen("type " .. cmd .. " > /dev/null 2> /dev/null; printf \"$?\"", "r")
local pipe = io.popen("type "..cmd.." > /dev/null 2> /dev/null; printf \"$?\"", "r")
exists = pipe:read() == "0"
pipe:close()
return exists
@ -90,6 +60,11 @@ local function get_clipboard_cmd()
end
end
platform = platform_type()
if platform == UNIX then
clipboard_cmd = get_clipboard_cmd()
end
-- Not used anywhere
-- local function divmod(a, b)
-- return a / b, a % b
@ -110,77 +85,109 @@ local function set_clipboard(text)
end
end
local function isto(x)
if x == "no"
then return ""
else return " -to " .. x
end
end
local function isss(x)
if x == "no"
then return ""
else return " -ss " .. x
end
end
local function cliplength(start, finish)
return finish - start
end
local targetsize = 32000 -- 4ch's 4M filesize limit in kilobits
local fourchsizelimit = 32000 -- 4ch's 4M filesize limit in kilobits
local function copyff(x)
-- functional style code but mpv's lua version doesn't support anonymous functions
-- local a = (function(x) if type(x) == "number" then return x else return 0 end)(mp.get_property("ab-loop-a"))
-- local b = (function(x) if type(x) == "number" then return x else return mp.get_property("duration") end)(mp.get_property("ab-loop-b"))
local a = mp.get_property_native("ab-loop-a")
local a = (type(a) == "number") and a or 0
local b = mp.get_property_native("ab-loop-b")
local b = (type(b) == "number") and b or mp.get_property_native("duration")
local duration = cliplength(a, b)
local targetbitrate = targetsize / duration -- kilobits/s
local targetbitratestring = " -b:v " .. targetbitrate .. "k "
-- vft will be a non-empty lua table if a crop was set with crop.lua
local vft = mp.get_property_native("vf")
local crop_was_set = (#vft > 0)
-- added following crop condition check because when manually cropping, placing the
-- mouse at the very bottom or right of the fullscreened video doesn't select the last
-- row or column of pixels. So this automatically updates the crop to include the
-- unselected pixels when within 2 pixels of the bottom or right edge
if crop_was_set
then
if crop_was_set then
local w = mp.get_property_native("width")
print(w .. " - (" .. vft[1].params.y .. " + " .. vft[1].params.w .. ")")
print(w.." - (".. vft[1].params.y.." + "..vft[1].params.w..")")
local wdiff = w - (vft[1].params.x + vft[1].params.w)
print("wdiff: " .. wdiff)
if wdiff < 3
then vft[1].params.w = vft[1].params.w + wdiff
print("wdiff: "..wdiff)
if wdiff < 3 then
vft[1].params.w = vft[1].params.w + wdiff
end
local h = mp.get_property_native("height")
print(h .. " - (" .. vft[1].params.x .. " + " .. vft[1].params.h .. ")")
print(h.." - (".. vft[1].params.x.." + "..vft[1].params.h..")")
local hdiff = h - (vft[1].params.y + vft[1].params.h)
print("hdiff: " .. hdiff)
if hdiff < 3
then vft[1].params.h = vft[1].params.h + hdiff
print("hdiff: "..hdiff)
if hdiff < 3 then
vft[1].params.h = vft[1].params.h + hdiff
end
end
local c = crop_was_set and ("crop=" .. vft[1].params.w .. ":" .. vft[1].params.h .. ":"
.. vft[1].params.x .. ":" .. vft[1].params.y) or ""
local vf = not x and crop_was_set and " -vf " .. c or ""
local fc = x and " -f lavfi -i color=white:s=1698x102 -filter_complex overlay=33:961," .. c or ""
-- constrained quality https://trac.ffmpeg.org/wiki/Encode/VP9#constrainedq
-- I usually run mpv from Dired in emacs, using the "openwith" package, which calls mpv
-- with the full path to the video, so the copied ffmpeg command can find the file from
-- any working-directory. Running mpv from the shell sets the mpv's "path" property to
-- whatever path you used on the command line.
-- assemble the crop settings string
-- crop.lua supports recursive cropping by building a chain of crop filters. This
-- script does not support chains longer than 1.
local c = crop_was_set
and ("crop="..vft[1].params.w..":"..vft[1].params.h..":"..
vft[1].params.x..":"..vft[1].params.y)
or ""
-- set a vf parameter when ticker overlay isn't requested
if x ~= "ticker" and crop_was_set then
vf = " -vf "..c
else
vf = ""
end
-- fc for filter_complex: this adds the white ticker overlay
local fc = x == "ticker"
and " -f lavfi -i color=white:s=1698x102 -filter_complex overlay=33:961,"..c
or ""
-- Get loop start and end points. Set defaults if unset
local clip_start = mp.get_property_native("ab-loop-a")
local clip_start = type(clip_start) == "number" and clip_start or 0
local clip_end = mp.get_property_native("ab-loop-b")
local sourceduration = mp.get_property_native("duration") -- clip source file duration in seconds
local clip_end = type(clip_end) == "number" and clip_end or sourceduration
local start_end = " -ss "..clip_start.." -to "..clip_end
local f = mp.get_property("path")
-- local cmd = "ffmpeg " .. " -i " .. "'file:" .. f .. "'" .. vf .. fc .. cq .. isss(a) .. isto(b) .. " /tmp/a.webm"
local cmd = "ffmpeg -i 'file:" .. f .. "'" ..
vf .. fc .. " -c:v libvpx-vp9" .. targetbitratestring .. "-pass 1" .. isss(a) .. isto(b) ..
" -an -f null /dev/null && ffmpeg -hide_banner -y -i 'file:" .. f .. "'" ..
vf .. fc .. " -c:v libvpx-vp9" .. targetbitratestring .. "-pass 2" .. isss(a) .. isto(b) ..
" -c:a libopus /tmp/a.webm; rm -f ffmpeg2pass-0.log"
-- don't include audio in webm if mpv is muted
local mute = mp.get_property_native("mute") and " -an " or ""
-- unix niceness: see manpage for "nice". Transcoding is intensive and can slow down
-- other programs on weak systems. Make this an empty string if you don't need it.
local nice = " nice "
-- assemble the ffmpeg command
if x == "singlepass" then
cmd = nice.."ffmpeg "..mute.." -i ".."'file:"..f.."'"..vf..fc..start_end.." /tmp/a.webm"
elseif x == "copy" then
cmd = "ffmpeg "..mute.." -i ".."'file:"..f.."' -c copy"..start_end.." /tmp/a.webm"
elseif x == "twopass" or x == "ticker" then
-- Reference: https://trac.ffmpeg.org/wiki/Encode/VP9
local clipduration = clip_end - clip_start
local sourcebits = (mp.get_property_native("file-size")) * 8
-- multiply denominator by 1000 here rather than divide sourcebits by 1000 above to
-- minimize divisions, which is lossy in floating-point operations
local sourcebitrate = sourcebits / (sourceduration * 1000) -- result is kilobits/s
if sourcebitrate * clipduration <= fourchsizelimit then
if crop_was_set then
crop_area = vft[1].params.w * vft[1].params.h
og_area = mp.get_property_native("width") * mp.get_property_native("height")
end
if crop_was_set and crop_area < og_area / 4 then
targetbitratestring = " -b:v 0 -crf 18 "
print("crop_area: "..crop_area..
"\nog_area: "..og_area..
"\nUsing constant quality 2-pass")
else targetbitratestring = " -b:v "..sourcebitrate.."k "
print("Using source's average bitrate 2-pass")
end
else
local targetbitrate = fourchsizelimit / clipduration -- kilobits/s
targetbitratestring = " -b:v "..targetbitrate.."k "
print("Using calculated target bitrate")
end
cmd = nice.."ffmpeg -i 'file:"..f.."'" ..
vf..fc.." -c:v libvpx-vp9"..targetbitratestring.."-pass 1"..start_end..
" -an -f null /dev/null && "..nice.." ffmpeg "..mute.." -hide_banner -y -i 'file:"..f.."'" ..
vf..fc.." -c:v libvpx-vp9"..targetbitratestring.."-pass 2"..start_end..
" -c:a libopus /tmp/a.webm; rm -f ffmpeg2pass-0.log"
end
if set_clipboard(cmd) then
mp.osd_message(string.format("Copied to Clipboard: %s", cmd))
else
@ -188,19 +195,12 @@ local function copyff(x)
end
end
platform = platform_type()
if platform == UNIX then
clipboard_cmd = get_clipboard_cmd()
end
function copyffcopy() copyff("copy") end
function copyffsinglepass() copyff("singlepass") end
function copyfftwopass() copyff("twopass") end
function copyffticker() copyff("ticker") end
function copyffn() copyff(nil) end
function copyfft() copyff(true) end
mp.add_key_binding("Ctrl+c", "copyffn", copyffn) -- doesn't include overlay for ticker
mp.add_key_binding("Ctrl+t", "copyfft", copyfft) -- "t" for ticker; includes overlay for ticker
-- Extra: This example command includes options to cover the ticker with solid
-- white. Sometimes used when I want to preserve the very bottom of the clip and crop the
-- sides at the same time (Covering the ticker saves file size since encoding movement
-- uses more data than static pixels)
-- ffmpeg -an -i "watch?v=fEVgqziY5RM23062707:28:3333.mkv" -f lavfi -i "color=white:s=1698x102" -filter_complex "overlay=33:961,crop=650:ih:1100:0" /tmp/a.webm
mp.add_key_binding("ctrl+c", "copyffcopy", copyffcopy) -- just cut and copy the video stream
mp.add_key_binding("ctrl+s", "copyffsinglepass", copyffsinglepass) -- single pass default encode
mp.add_key_binding("ctrl+d", "copyfftwopass", copyfftwopass) -- dual pass encode
mp.add_key_binding("ctrl+t", "copyffticker", copyffticker) -- "t" for ticker; includes overlay for ticker

View File

@ -6,6 +6,7 @@
# aqstream tv channel aliases
alias tbs='mpv https://tbs3.mov3.co/hls/tbs.m3u8' \
tbsaudio='mpv --no-initial-audio-sync https://tbs3.mov3.co/hls/tbs.m3u8' \
ntv='mpv https://ntv4.mov3.co/hls/ntv.m3u8' \
fujitv='mpv https://fujitv4.mov3.co/hls/fujitv.m3u8'
@ -49,4 +50,15 @@ ytchat() {
# wait;
# ffmpeg -f concat -i filelist -c copy output.mp4;
# rm filelist;
alias concatvid="cd /tmp/; ffmpeg -y -f concat -i a -c copy /tmp/concat.webm; cd -"
concatvid() {
# reference: https://trac.ffmpeg.org/wiki/Concatenate
>concatvidlist # clear list file if it exists
for f in "$@"; do
echo file "'file:${f}'" >> concatvidlist
done
[ file -b $1 -eq "WebM" ] && EXT=webm || EXT=mkv
# safe 0 tells it to accept absolute paths
ffmpeg -y -f concat -safe 0 -i concatvidlist -c copy /tmp/concat.$EXT
unset EXT
rm -f concatvidlist
}