Coder Social home page Coder Social logo

mpv-webm's Introduction

mpv-webm

Simple WebM maker for mpv, with no external dependencies.

sample

Installation

Place this in your mpv scripts folder. The scripts folder can be found (or created, if it does not already exist) in the following paths:

  • Linux/macOS: ~/.config/mpv/scripts, where ~ is your user's home folder;
  • Windows: mpv will try to load scripts from %APPDATA%\mpv\scripts, followed by <mpv binary folder>\portable_config\scripts and <mpv binary folder>\mpv\scripts; where %APPDATA% is a Windows-specific directory (typing %APPDATA% on Windows + R should take you to that folder), and <mpv binary folder> is the folder that contains the mpv.exe binary.

Additional details about the folder structure can be found in the mpv's manual.

By default, the script is activated by the W (shift+w) key.

Usage

Follow the on-screen instructions. Encoded WebM files will have audio/subs based on the current playback options (i.e. will be muted if no audio, won't have hardcoded subs if subs aren't visible).

Configuration

You can configure the script's defaults by either changing the options at the beginning of the script, or placing a webm.conf inside the script-opts directory. A sample webm.conf file with the default options can be found here. Note that you don't need to specify all options, only the ones you wish to override.

Building (development)

Building requires moonc, the MoonScript compiler, added to the PATH, and a GNUMake compatible make. Run make on the root directory. The output files will be placed under the build directory.

mpv-webm's People

Contributors

averms avatar batraz90 avatar bepvte avatar defaultxr avatar dsetareh avatar ekisu avatar llyyr avatar oluladef avatar po5 avatar radar-duker avatar seirdy avatar vzaa avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

mpv-webm's Issues

Not encoding

Is there a limit on file size of a file that this plugin can encode from? It won't encode at all from, well, it says encoded successfully but no file.

new template strings for filenames

would be nice if there were template strings for resolution too

i.e. if I create a webm with "scale height" set to 720p, it'll include 720p in the filename

Problem encoding subtitles on vlive.tv

mpv version and platform

kde neon 5.15

mpv git-2019-02-24-5370069 Copyright © 2000-2018 mpv/MPlayer/mplayer2 projects
 built on Sun Mar 10 00:58:59 UTC 2019
ffmpeg library versions:
   libavutil       56.26.100
   libavcodec      58.47.102
   libavformat     58.26.101
   libswscale      5.4.100
   libavfilter     7.48.100
   libswresample   3.4.100
ffmpeg version: git-2019-02-27-4571c7c

Description

When streaming a video with multiple subtitle tracks, a different track than the one displayed is encoded.

example link
https://www.vlive.tv/video/120131

Log file

https://gist.github.com/jamesxmcintosh/c089f2521c849414318e0ae7a45908f6

[Question] Change speed in the output file

I find myself wanting to give a simple slowmo or quick effect to certain clips I make, is it possible to change the speed in the output file? If not could you add this feature, if possible of course, it would help a lot.

Nothing happen after Started encode

mpv version and platform

Windows 8.1 x64

[   0.011][v][cplayer] mpv 0.29.0-343-gc379950ce0 Copyright © 2000-2019 mpv/MPlayer/mplayer2 projects
[   0.011][v][cplayer]  built on Sun Jul  7 10:37:01 +08 2019
[   0.011][v][cplayer] ffmpeg library versions:
[   0.011][v][cplayer]    libavutil       56.30.100
[   0.011][v][cplayer]    libavcodec      58.53.101
[   0.011][v][cplayer]    libavformat     58.28.101
[   0.011][v][cplayer]    libswscale      5.4.101
[   0.011][v][cplayer]    libavfilter     7.56.100
[   0.011][v][cplayer]    libswresample   3.4.100
[   0.011][v][cplayer] ffmpeg version: git-2019-07-06-b7b6ddd5

Description

When i'm trying make webm, i.e pressing W, then 1, 2, and e, i'm see Started encode, but after some time, nothing happen and file not created.

Log file

https://gist.github.com/ChaosPaladin/f4edbcce8b50b919c2916021ad07b500

Encode presets?

How do I create encode presets so that I don't have to fiddle with encode settings every time?

Encode doesn't include external subtitles

The encode doesn't include loaded (and enabled) external subtitles. They are visible in the preview. I loaded them through drag'n'dropping them on the video (different name than the video), format is .ass.

[Request]Possibility to add "leave as/use current format" ?

Hey man,

just a quick question if there's the possibility to add an encoding option to just use the current format?

I.e. I'm mainly converting from .ts files, so for files that just need to be cut and not converted, i could 'abuse' mpv-webm as cutter without switching to another tool.

Greetings broky

mpv-webm ignores currently applied filters, including crop.

This one's pretty simple. The encoding process ignores currently applied filters. The easiest way to reproduce this is to apply an external crop that was not applied with the mpv-webm script, such as adding the following to input.conf and pressing X when watching a 1080p video.

X vf add @crop:crop=767:551:564:246

The end result is expected to follow the applied crop filter, focusing on the center of the video. Instead, the entire resolution is captured, ignoring the filter entirely.

Please help a newbie.

Where is the "script" folder ?

I usually just use mpv for watching movies, and i dont find the "script" folder in my mpv directory. And i cant find this ~/.config/mpv/scripts/ location.

Subtitle delay not taken into account

mpv version and platform

Mac OS X 10.11.6

mpv 0.29.1 Copyright © 2000-2018 mpv/MPlayer/mplayer2 projects
 built on Sun Oct  7 04:03:13 PDT 2018
ffmpeg library versions:
   libavutil       56.14.100
   libavcodec      58.18.100
   libavformat     58.12.100
   libswscale      5.1.100
   libavfilter     7.16.100
   libswresample   3.1.100
ffmpeg version: 4.0.2

Description

"Apply current video filters" disregards subtitle delay. I guess sub delay isn't considered a video track filter, really, so maybe this is intentional/expected behavior, technically speaking. Is there some way to have it take into account this setting during encoding?

'First pass failed' error

When I try to encode a webm using default options I get the error "First pass failed! Check the log for details". If I turn off Two Pass before encoding then it works fine. I don't know if that's related to #6.

Lua error when loading the script

mpv version and platform

Arch Linux x64 - 4.16.8-1-ARCH

mpv 0.28.2 (C) 2000-2017 mpv/MPlayer/mplayer2 projects
 built on Mon Apr 23 21:31:45 CEST 2018
ffmpeg library versions:
   libavutil       56.14.100
   libavcodec      58.18.100
   libavformat     58.12.100
   libswscale      5.1.100
   libavfilter     7.16.100
   libswresample   3.1.100
ffmpeg version: 4.0

Description

mpv can't load the script. I tried running mpv with the --script option and I found this error in the terminal

Log file

[webm] 
[webm] stack traceback:
[webm] 	[C]: in ?
[webm] 	[C]: in ?
[webm] Lua error: /home/leewdch/.config/mpv/scripts/webm.lua:7: unexpected symbol near '<'

Script not working in the latest Windows10

mpv version and platform

mpv-x86_64-20190707-git-c379950
(windows 10 1903 - 18362.239)

Description

webm script is not working, I've downgraded to an older version and still no working

raw_observe_property (string expected, got function)

mpv 0.27.0-416-g386e8cd16d (C) 2000-2017 mpv/MPlayer/mplayer2 projects
 built on Fri Nov 24 16:14:12 EST 2017
ffmpeg library versions:
   libavutil       56.0.100
   libavcodec      58.4.102
   libavformat     58.2.102
   libswscale      5.0.101
   libavfilter     7.2.100
   libswresample   3.0.101
ffmpeg version: N-89178-ga1630b40e8

When trying to start the script with Shift+w I get the following error.

[webm]
[webm] stack traceback:
[webm]  [C]: in function 'raw_observe_property'
[webm]  mp.defaults:351: in function 'observe_property'
[webm]  /home/flat/.config/mpv/scripts/webm.lua:791: in function 'observe_properties'
[webm]  /home/flat/.config/mpv/scripts/webm.lua:813: in function </home/flat/.config/mpv/scripts/webm.lua:811>
[webm]  (tail call): ?
[webm]  mp.defaults:202: in function 'fn'
[webm]  mp.defaults:60: in function 'handler'
[webm]  mp.defaults:339: in function 'handler'
[webm]  mp.defaults:458: in function 'call_event_handlers'
[webm]  mp.defaults:495: in function 'dispatch_events'
[webm]  mp.defaults:451: in function <mp.defaults:450>
[webm]  [C]: ?
[webm]  [C]: ?
[webm] Lua error: mp.defaults:351: bad argument #3 to 'raw_observe_property' (string expected, got function)

Cropping doesnt work

Pretty much title. I press C, put in the two boundaries with 1 and 2 and then enter to confirm, start encode and when it's done the webm isn't cropped. If I preview the webm before encoding it shows it as cropped, but when encoded it's back to full size.

Non ASCII characters in path

mpv version and platform

Windows 10 Pro, Version 1083, Build 17134.648
mpv mpv-x86_64-20190310-git-1d0349d by shinchiro (no output from "mpv --version")

Description

Currently the script is unable to output to same directory as file if the path contains non-ascii characters.

Tested with the following paths

E:\Video\pathtest\√\video.webm
E:\Video\pathtest\あ\video.webm
E:\Video\pathtest\Ą\video.webm

where
= U+221A
= U+3042
Ą = U+0104

Excepted behavior

New files generated in following directories

E:\Video\pathtest\√\
E:\Video\pathtest\あ\
E:\Video\pathtest\Ą\

Observed behavior

New files were generated in user folder

C:\users\moh\

Log file

mpvlog.txt

Encoding fails with static linked ffmpeg

mpv version

mpv 0.28.0-423-g596f66cccf

[cplayer] Command line options: '-v'                                                                                 
[cplayer] mpv 0.28.0-423-g596f66cccf Copyright © 2000-2018 mpv/MPlayer/mplayer2 projects                             
[cplayer]  built on UNKNOWN                                                                                          
[cplayer] ffmpeg library versions:                                                                                   
[cplayer]    libavutil       56.13.100                                                                               
[cplayer]    libavcodec      58.17.100                                                                               
[cplayer]    libavformat     58.10.100                                                                               
[cplayer]    libswscale      5.0.102                                                                                 
[cplayer]    libavfilter     7.14.100                                                                                
[cplayer]    libswresample   3.0.101                                                                                 
[cplayer] ffmpeg version: N-90610-g2accdd3871                                                                        
[cplayer]                                                                                                            
[cplayer] Configuration: ./waf configure --prefix=/usr --confdir=/etc/mpv --htmldir=/usr/share/doc/mpv/html --disable
-test --disable-build-date --disable-vapoursynth-lazy --lua=luajit --enable-cdda --enable-dvbin --enable-dvdnav --ena
ble-dvdread --enable-html-build --enable-libarchive --enable-libmpv-shared --enable-libsmbclient --enable-openal --en
able-sdl2 --enable-tv --enable-zsh-comp                                                                              
[cplayer] List of enabled features: alsa asm atomics audio-input caca cdda cplayer cplugins crossc cuda-hwaccel debug
-build drm drmprime dvbin dvdnav dvdread dvdread-common egl-drm egl-helpers egl-x11 encoding fchmod ffmpeg gbm gbm.h 
gl gl-wayland gl-x11 glibc-thread-name glob glob-posix gnuc gpl iconv jack javascript jpeg lcms2 libaf libarchive lib
ass libass-osd libav-any libavcodec libavdevice libbluray libdl libm libmpv-shared librt libsmbclient libv4l2 linux-f
statfs lua luajit openal optimize oss-audio plain-gl posix posix-or-mingw posix-spawn posix-spawn-native pthreads pul
se rsound rubberband sdl2 shaderc shaderc-shared stdatomic tv tv-v4l2 uchardet vaapi vaapi-drm vaapi-egl vaapi-glx va
api-wayland vaapi-x-egl vaapi-x11 vdpau vdpau-gl-x11 videodev vt.h vulkan wayland wayland-protocols x11 xv zlib zsh-c
omp                                                                                                                  
[cplayer] Reading config file /etc/mpv/encoding-profiles.conf
[cplayer] Reading config file /home/greymon/.config/mpv/config
[ifo] Opening /home/greymon/.config/mpv/input.conf
[ifo_dvdnav] Opening /home/greymon/.config/mpv/input.conf
[bdmv/bluray] Opening /home/greymon/.config/mpv/input.conf
[file] Opening /home/greymon/.config/mpv/input.conf
[input] Parsing input config file /home/greymon/.config/mpv/input.conf
[input] Input config file /home/greymon/.config/mpv/input.conf parsed: 12 binds
[cplayer] mpv 0.28.0-423-g596f66cccf Copyright © 2000-2018 mpv/MPlayer/mplayer2 projects
[cplayer]  built on UNKNOWN
[cplayer] ffmpeg library versions:
[cplayer]    libavutil       56.13.100
[cplayer]    libavcodec      58.17.100
[cplayer]    libavformat     58.10.100
[cplayer]    libswscale      5.0.102
[cplayer]    libavfilter     7.14.100
[cplayer]    libswresample   3.0.101
[cplayer] ffmpeg version: N-90610-g2accdd3871
[cplayer] 
[cplayer] Configuration: ./waf configure --prefix=/usr --confdir=/etc/mpv --htmldir=/usr/share/doc/mpv/html --disable-test --disable-build-date --disable-vapoursynth-lazy --lua=luajit --enable-cdda --enable-dvbin --enable-dvdnav --enable-dvdread --enable-html-build --enable-libarchive --enable-libmpv-shared --enable-libsmbclient --enable-openal --enable-sdl2 --enable-tv --enable-zsh-comp
[cplayer] List of enabled features: alsa asm atomics audio-input caca cdda cplayer cplugins crossc cuda-hwaccel debug-build drm drmprime dvbin dvdnav dvdread dvdread-common egl-drm egl-helpers egl-x11 encoding fchmod ffmpeg gbm gbm.h gl gl-wayland gl-x11 glibc-thread-name glob glob-posix gnuc gpl iconv jack javascript jpeg lcms2 libaf libarchive libass libass-osd libav-any libavcodec libavdevice libbluray libdl libm libmpv-shared librt libsmbclient libv4l2 linux-fstatfs lua luajit openal optimize oss-audio plain-gl posix posix-or-mingw posix-spawn posix-spawn-native pthreads pulse rsound rubberband sdl2 shaderc shaderc-shared stdatomic tv tv-v4l2 uchardet vaapi vaapi-drm vaapi-egl vaapi-glx vaapi-wayland vaapi-x-egl vaapi-x11 vdpau vdpau-gl-x11 videodev vt.h vulkan wayland wayland-protocols x11 xv zlib zsh-comp
[osd/libass] Shaper: FriBidi 1.0.1 (SIMPLE) HarfBuzz-ng 1.7.6 (COMPLEX)
[osd/libass] Setting up fonts...
[ytdl_hook] lua-settings/ytdl_hook.conf not found. 
[stats] lua-settings/stats.conf not found. 
[cplayer] mpv 0.28.0-423-g596f66cccf Copyright © 2000-2018 mpv/MPlayer/mplayer2 projects
[cplayer]  built on UNKNOWN
[cplayer] ffmpeg library versions:
[cplayer]    libavutil       56.13.100
[cplayer]    libavcodec      58.17.100
[cplayer]    libavformat     58.10.100
[cplayer]    libswscale      5.0.102
[cplayer]    libavfilter     7.14.100
[cplayer]    libswresample   3.0.101
[cplayer] ffmpeg version: N-90610-g2accdd3871
[cplayer]
[cplayer] Usage:   mpv [options] [url|path/]filename
[cplayer]
[cplayer] Basic options:
[cplayer]  --start=<time>    seek to given (percent, seconds, or hh:mm:ss) position
[cplayer]  --no-audio        do not play sound
[cplayer]  --no-video        do not play video
[cplayer]  --fs              fullscreen playback
[cplayer]  --sub-file=<file> specify subtitle file to use
[cplayer]  --playlist=<file> specify playlist file
[cplayer]
[cplayer]  --list-options    list all mpv options
[cplayer]  --h=<string>      print options which contain the given string in their name
[cplayer]
[ytdl_hook] Exiting...
[stats] Exiting...
[osd/libass] Using font provider fontconfig
[osd/libass] Done.
[osc] Exiting...

Description

running the script returns "Encode Failed!"

Log file

[ 10.147][v][webm] Command failed! Reason: nil Killed by us? no
[ 10.147][v][webm] Command stdout:
[ 10.147][v][webm] [encode-lavc] neither audio nor video codec was found
[ 10.147][v][webm] [encode-lavc] vo-lavc: encoded 0 bytes
[ 10.147][v][webm] [encode-lavc] ao-lavc: encoded 0 bytes
[ 10.147][v][webm] Encoding initialization failed.
[ 10.147][v][webm]
[ 10.147][v][webm] Exiting... (Fatal error)
[ 10.147][v][webm]

Append metadata title during encoding

Here is a suggestion: an option (toggled on by default if possible) that copies the filename and uses it during the video encoding to add a metadata title. This is useful for those video that lost the original name title. Thanks to this you can track down the origin of a file even after multiple encoding since the metadata title should be preserved even after additional encodings with ffmpeg. Right now I have to do this with a bash script like this:

filename=$(basename -- "$i")
tempname=${filename%.*}_tmp.${filename##*.}

mv "$filename" "$tempname"
ffmpeg -i "$tempname" -c copy -metadata title="$filename" "$filename"
rm "$tempname"

but I would rather do the job during video encoding so I don't need to make and remove useless temp files

Webm encoding fails with ffmpeg

mpv version and platform

OS: Ubuntu Linux 19.04 amd
mpv:

mpv 0.29.0-326-g91c1691b35 Copyright © 2000-2019 mpv/MPlayer/mplayer2 projects
 built on Thu May  9 01:10:57 CEST 2019
ffmpeg library versions:
   libavutil       56.26.101
   libavcodec      58.52.101
   libavformat     58.27.103
   libswscale      5.4.100
   libavfilter     7.50.100
   libswresample   3.4.100
ffmpeg version: N-93814-g48539b62fc

ffmpeg binary:

ffmpeg version N-93799-gc636dc9 Copyright (c) 2000-2019 the FFmpeg developers
built with clang version 8.0.0-3 (tags/RELEASE_800/final)
configuration: --prefix=/home/adriaan/ffmpeg_build --pkg-config-flags=--static --extra-cflags=-I/home/adriaan/ffmpeg_build/include --extra-ldflags=-L/home/adriaan/ffmpeg_build/lib --extra-libs='-lpthread -lm' --bindir=/home/adriaan/bin --enable-gpl --enable-libaom --enable-libass --enable-libfdk-aac --enable-libfreetype --enable-libmp3lame --enable-libopus --enable-libvorbis --enable-libvpx --enable-libx264 --enable-libx265 --cc=clang --enable-nonfree
libavutil      56. 26.101 / 56. 26.101
libavcodec     58. 52.101 / 58. 52.101
libavformat    58. 27.103 / 58. 27.103
libavdevice    58.  7.100 / 58.  7.100
libavfilter     7. 50.100 /  7. 50.100
libswscale      5.  4.100 /  5.  4.100
libswresample   3.  4.100 /  3.  4.100
libpostproc    55.  4.100 / 55.  4.100

Description

Thanks to your earlier help, encoding to mp4 using ffmpeg works. I noticed that encoding to vp8/vp9 webm's fails

[webm_ffmpeg] Command subprocess: argument args has incompatible type.
[webm_ffmpeg] Command failed! Reason:  invalid parameter  Killed by us?  no 
[webm_ffmpeg] Command stdout:  
[webm_ffmpeg] nil 

Log file

log.txt

Encode fails when launching mpv through Finder

I'm getting the first pass failed error when trying this script for the first time.

Checking logs didn't reveal anything useful but when running the encoding command from the terminal I got

[encode-lavc] neither audio nor video codec was found
[encode-lavc] vo-lavc: encoded 0 bytes
[encode-lavc] ao-lavc: encoded 0 bytes
Encoding initialization failed.

Any ideas? I'm on macOS High Sierra and it looks like the script tries to use libvpx and libvorbis codecs.

Fix stream order

Can you enforce proper stream order? I.e. video first and then audio?
Can probably be done by adding -map 0:v -map 0:a somewhere to the command.

Output as same filetype as input?

Hi,

Would it be possible to add an option to output to the same format as the input file, e.g. if playing an mp4, the crop, timestamp, and selected mute/subtitle/etc. filters would still be applied, but the video wouldn't be changed into a webm or avi? This would be super helpful (and possibly easy to do – similar to the webm option just without the passing the -c:v filter?) Thanks!

I can't use my mouse to click on the osc anymore if this is in my scripts.

ver. 2.0.0.0 (mpv-x86_64-20181230-git-d6d6da4) Win10

Okay since I've finally figured out how to do the log file command I can ask for a proper diagnostics. I recently added your script to my setup and it works and everything but the problem is now I can't access my osc with my mouse anymore, it pops up but I can't move the cursor or pause and play it. Tried updating the mpv.exe and it still won't work.
log.txt

Encoding mpv process doesn't inherit --ytdl-format

mpv version

mpv 0.28.2

Description

with ytdl-format=bestvideo[height<=?720]+bestaudio/best set in my mpv.conf, mpv will select the best <=720p video to play from youtube. However the encoding mpv process seems to get the highest resolution version youtube has. If the highest resolution version is greater than 720p, the result is the encode takes far longer than it should, takes more bandwidth than it should, and is cropped incorrectly (getting only the upper-left corner of the video.)

For instance this youtube video has a 2160p version available. When I play it with my mpv config, youtube-dl gets the 720p version of it:

mpv-shot0002

If I encode a second of video at the same point with mpv-webm, the resulting webm looks like this:

mpv-shot0003

The resulting webm is 720p... but it's only a 720p crop of the top left of the 2160p version.

(This all used to work properly, I think maybe it changed with 0.28.2)

Logs

They don't seem to tell me much, but for what they're worth:
https://gist.github.com/jgreco/64d194443fc2670dabb7ff45dddcb365

[Suggestion] Option to copy video instead of encoding it

When trying to quickly make a clip of something that doesn't have to be cut frame-perfect. It's often better to just cut to the key-frames and save the video without encoding it, obviously this won't work with every codec. But it would be really nice if I could use this script as a quick way to do this instead of opening ffmpeg and putting in the command. It would probably need an option to copy subtitles over as well, since this method obviously won't let you burn them in.

Script not working after changing output directory

mpv version and platform

(write OS and version)
Windows 8.1 Pro N, 64bit, Build 9600
paste output of "mpv --version" here.
Not sure what is meant by this. (cmd?)

Description

Describe the problem, what steps you did, what happened and what you expected to happen.
After downloading the latest version of MPV, I had a previous .lua file I was using on a different OS. After transferring the .lua file to that this OS, changing the file directory, the script no longer worked. The default keybind would just be increasing panscan. So I changed the Keybind, which yielded no result. I used mpv before editing the .lua file and it worked, but there was no file output on my computer. (Or at least from what I could tell, I checked where the media file directory was, but nothing new was created.)
If possible/applicable, attach a sample file (especially if the problem seems specific to that file).
local mp = require("mp")
local assdraw = require("mp.assdraw")
local msg = require("mp.msg")
local utils = require("mp.utils")
local mpopts = require("mp.options")
local mpopts = require("mp.options")
local options = {
-- Defaults to shift+w
keybind = "`",
-- If empty, saves on the same directory of the playing video.
-- A starting "~" will be replaced by the home dir.
output_directory = "C:\Users\Anonymous\Pictures\screens\mpv\webms",
run_detached = false,
-- Template string for the output file
-- %f - Filename, with extension
-- %F - Filename, without extension
-- %T - Media title, if it exists, or filename, with extension (useful for some streams, such as YouTube).
-- %s, %e - Start and end time, with milliseconds
-- %S, %E - Start and time, without milliseconds
-- %M - "-audio", if audio is enabled, empty otherwise
output_template = "%T-[%s-%e]%M",
-- Scale video to a certain height, keeping the aspect ratio. -1 disables it.
scale_height = -1,
-- Target filesize, in kB. This will be used to calculate the bitrate
-- used on the encode. If this is set to <= 0, the video bitrate will be set
-- to 0, which might enable constant quality modes, depending on the
-- video codec that's used (VP8 and VP9, for example).
target_filesize = 5000,
-- If true, will use stricter flags to ensure the resulting file doesn't
-- overshoot the target filesize. Not recommended, as constrained quality
-- mode should work well, unless you're really having trouble hitting
-- the target size.
strict_filesize_constraint = false,
strict_bitrate_multiplier = 1,
-- In kilobits.
strict_audio_bitrate = 160,
-- Sets the output format, from a few predefined ones.
-- Currently we have webm-vp8 (libvpx/libvorbis), webm-vp9 (libvpx-vp9/libvorbis)
-- and raw (rawvideo/pcm_s16le).
output_format = "webm-vp8",
twopass = true,
-- If set, applies the video filters currently used on the playback to the encode.
apply_current_filters = true,
-- If set, writes the video's filename to the "Title" field on the metadata.
write_filename_on_metadata = false,
-- Set the number of encoding threads, for codecs libvpx and libvpx-vp9
libvpx_threads = 4,
additional_flags = "",
-- Useful for flags that may impact output filesize, such as crf, qmin, qmax etc
-- Won't be applied when strict_filesize_constraint is on.
non_strict_additional_flags = "--ovcopts-add=crf=10",
-- Display the encode progress, in %. Requires run_detached to be disabled.
-- On Windows, it shows a cmd popup. "auto" will display progress on non-Windows platforms.
display_progress = "auto",
-- The font size used in the menu. Isn't used for the notifications (started encode, finished encode etc)
font_size = 28,
margin = 10,
message_duration = 5
}

mpopts.read_options(options)
local bold
bold = function(text)
return "{\b1}" .. tostring(text) .. "{\b0}"
end
local message
message = function(text, duration)
local ass = mp.get_property_osd("osd-ass-cc/0")
ass = ass .. text
return mp.osd_message(ass, duration or options.message_duration)
end
local append
append = function(a, b)
for _, val in ipairs(b) do
a[#a + 1] = val
end
return a
end
local seconds_to_time_string
seconds_to_time_string = function(seconds, no_ms, full)
if seconds < 0 then
return "unknown"
end
local ret = ""
if not (no_ms) then
ret = string.format(".%03d", seconds * 1000 % 1000)
end
ret = string.format("%02d:%02d%s", math.floor(seconds / 60) % 60, math.floor(seconds) % 60, ret)
if full or seconds > 3600 then
ret = string.format("%d:%s", math.floor(seconds / 3600), ret)
end
return ret
end
local seconds_to_path_element
seconds_to_path_element = function(seconds, no_ms, full)
local time_string = seconds_to_time_string(seconds, no_ms, full)
local _
time_string, _ = time_string:gsub(":", ".")
return time_string
end
local file_exists
file_exists = function(name)
local f = io.open(name, "r")
if f = nil then
io.close(f)
return true
end
return false
end
local format_filename
format_filename = function(startTime, endTime, videoFormat)
local replaceTable = {
["%%f"] = mp.get_property("filename"),
["%%F"] = mp.get_property("filename/no-ext"),
["%%s"] = seconds_to_path_element(startTime),
["%%S"] = seconds_to_path_element(startTime, true),
["%%e"] = seconds_to_path_element(endTime),
["%%E"] = seconds_to_path_element(endTime, true),
["%%T"] = mp.get_property("media-title"),
["%%M"] = (mp.get_property_native('aid') and not mp.get_property_native('mute')) and '-audio' or ''
}
local filename = options.output_template
for format, value in pairs(replaceTable) do
local _
filename, _ = filename:gsub(format, value)
end
local _
filename, _ = filename:gsub("[<>:"/\|?*]", "")
return tostring(filename) .. "." .. tostring(videoFormat.outputExtension)
end
local parse_directory
parse_directory = function(dir)
local home_dir = os.getenv("HOME")
if not home_dir then
home_dir = os.getenv("USERPROFILE")
end
if not home_dir then
local drive = os.getenv("HOMEDRIVE")
local path = os.getenv("HOMEPATH")
if drive and path then
home_dir = utils.join_path(drive, path)
else
msg.warn("Couldn't find home dir.")
home_dir = ""
end
end
local _
dir, _ = dir:gsub("^
", home_dir)
return dir
end
local is_windows = type(package) == "table" and type(package.config) == "string" and package.config:sub(1, 1) == "\"
local trim
trim = function(s)
return s:match("^%s*(.-)%s*$")
end
local get_mpv_path
get_mpv_path = function()
if not is_windows then
return "mpv"
end
local pid = utils.getpid()
local res = utils.subprocess({
args = {
"wmic",
"process",
"where",
"processid=" .. tostring(pid),
"get",
"ExecutablePath",
"/VALUE"
}
})
local key_value = trim(res.stdout)
return key_value:sub(string.len("ExecutablePath=") + 1)
end
local get_null_path
get_null_path = function()
if file_exists("/dev/null") then
return "/dev/null"
end
return "NUL"
end
local run_subprocess
run_subprocess = function(params)
local res = utils.subprocess(params)
if res.status ~= 0 then
msg.verbose("Command failed! Reason: ", res.error, " Killed by us? ", res.killed_by_us and "yes" or "no")
msg.verbose("Command stdout: ")
msg.verbose(res.stdout)
return false
end
return true
end
local shell_escape
shell_escape = function(args)
local ret = { }
for i, a in ipairs(args) do
local s = tostring(a)
if string.match(s, "[^A-Za-z0-9_/:=-]") then
if is_windows then
s = '"' .. string.gsub(s, '"', '"\""') .. '"'
else
s = "'" .. string.gsub(s, "'", "'\''") .. "'"
end
end
table.insert(ret, s)
end
local concat = table.concat(ret, " ")
if is_windows then
concat = '"' .. concat .. '"'
end
return concat
end
local run_subprocess_popen
run_subprocess_popen = function(command_line)
local command_line_string = shell_escape(command_line)
command_line_string = command_line_string .. " 2>&1"
msg.verbose("run_subprocess_popen: running " .. tostring(command_line_string))
return io.popen(command_line_string)
end
local calculate_scale_factor
calculate_scale_factor = function()
local baseResY = 720
local osd_w, osd_h = mp.get_osd_size()
return osd_h / baseResY
end
local should_display_progress
should_display_progress = function()
if options.display_progress == "auto" then
return not is_windows
end
return options.display_progress
end
local dimensions_changed = true
local _video_dimensions = { }
local get_video_dimensions
get_video_dimensions = function()
if not (dimensions_changed) then
return _video_dimensions
end
local video_params = mp.get_property_native("video-out-params")
if not video_params then
return nil
end
dimensions_changed = false
local keep_aspect = mp.get_property_bool("keepaspect")
local w = video_params["w"]
local h = video_params["h"]
local dw = video_params["dw"]
local dh = video_params["dh"]
if mp.get_property_number("video-rotate") % 180 == 90 then
w, h = h, w
dw, dh = dh, dw
end
_video_dimensions = {
top_left = { },
bottom_right = { },
ratios = { }
}
local window_w, window_h = mp.get_osd_size()
if keep_aspect then
local unscaled = mp.get_property_native("video-unscaled")
local panscan = mp.get_property_number("panscan")
local fwidth = window_w
local fheight = math.floor(window_w / dw * dh)
if fheight > window_h or fheight < h then
local tmpw = math.floor(window_h / dh * dw)
if tmpw <= window_w then
fheight = window_h
fwidth = tmpw
end
end
local vo_panscan_area = window_h - fheight
local f_w = fwidth / fheight
local f_h = 1
if vo_panscan_area == 0 then
vo_panscan_area = window_h - fwidth
f_w = 1
f_h = fheight / fwidth
end
if unscaled or unscaled == "downscale-big" then
vo_panscan_area = 0
if unscaled or (dw <= window_w and dh <= window_h) then
fwidth = dw
fheight = dh
end
end
local scaled_width = fwidth + math.floor(vo_panscan_area * panscan * f_w)
local scaled_height = fheight + math.floor(vo_panscan_area * panscan * f_h)
local split_scaling
split_scaling = function(dst_size, scaled_src_size, zoom, align, pan)
scaled_src_size = math.floor(scaled_src_size * 2 ^ zoom)
align = (align + 1) / 2
local dst_start = math.floor((dst_size - scaled_src_size) * align + pan * scaled_src_size)
if dst_start < 0 then
dst_start = dst_start + 1
end
local dst_end = dst_start + scaled_src_size
if dst_start >= dst_end then
dst_start = 0
dst_end = 1
end
return dst_start, dst_end
end
local zoom = mp.get_property_number("video-zoom")
local align_x = mp.get_property_number("video-align-x")
local pan_x = mp.get_property_number("video-pan-x")
_video_dimensions.top_left.x, _video_dimensions.bottom_right.x = split_scaling(window_w, scaled_width, zoom, align_x, pan_x)
local align_y = mp.get_property_number("video-align-y")
local pan_y = mp.get_property_number("video-pan-y")
_video_dimensions.top_left.y, _video_dimensions.bottom_right.y = split_scaling(window_h, scaled_height, zoom, align_y, pan_y)
else
_video_dimensions.top_left.x = 0
_video_dimensions.bottom_right.x = window_w
_video_dimensions.top_left.y = 0
_video_dimensions.bottom_right.y = window_h
end
_video_dimensions.ratios.w = w / (_video_dimensions.bottom_right.x - _video_dimensions.top_left.x)
_video_dimensions.ratios.h = h / (_video_dimensions.bottom_right.y - _video_dimensions.top_left.y)
return _video_dimensions
end
local set_dimensions_changed
set_dimensions_changed = function()
dimensions_changed = true
end
local monitor_dimensions
monitor_dimensions = function()
local properties = {
"keepaspect",
"video-out-params",
"video-unscaled",
"panscan",
"video-zoom",
"video-align-x",
"video-pan-x",
"video-align-y",
"video-pan-y",
"osd-width",
"osd-height"
}
for _, p in ipairs(properties) do
mp.observe_property(p, "native", set_dimensions_changed)
end
end
local clamp
clamp = function(min, val, max)
if val <= min then
return min
end
if val >= max then
return max
end
return val
end
local clamp_point
clamp_point = function(top_left, point, bottom_right)
return {
x = clamp(top_left.x, point.x, bottom_right.x),
y = clamp(top_left.y, point.y, bottom_right.y)
}
end
local VideoPoint
do
local _class_0
local _base_0 = {
set_from_screen = function(self, sx, sy)
local d = get_video_dimensions()
local point = clamp_point(d.top_left, {
x = sx,
y = sy
}, d.bottom_right)
self.x = math.floor(d.ratios.w * (point.x - d.top_left.x) + 0.5)
self.y = math.floor(d.ratios.h * (point.y - d.top_left.y) + 0.5)
end,
to_screen = function(self)
local d = get_video_dimensions()
return {
x = math.floor(self.x / d.ratios.w + d.top_left.x + 0.5),
y = math.floor(self.y / d.ratios.h + d.top_left.y + 0.5)
}
end
}
_base_0.__index = _base_0
_class_0 = setmetatable({
__init = function(self)
self.x = -1
self.y = -1
end,
__base = _base_0,
__name = "VideoPoint"
}, {
__index = _base_0,
__call = function(cls, ...)
local _self_0 = setmetatable({}, _base_0)
cls.__init(_self_0, ...)
return _self_0
end
})
_base_0.__class = _class_0
VideoPoint = _class_0
end
local Region
do
local _class_0
local _base_0 = {
is_valid = function(self)
return self.x > -1 and self.y > -1 and self.w > -1 and self.h > -1
end,
set_from_points = function(self, p1, p2)
self.x = math.min(p1.x, p2.x)
self.y = math.min(p1.y, p2.y)
self.w = math.abs(p1.x - p2.x)
self.h = math.abs(p1.y - p2.y)
end
}
_base_0.__index = _base_0
_class_0 = setmetatable({
__init = function(self)
self.x = -1
self.y = -1
self.w = -1
self.h = -1
end,
__base = _base_0,
__name = "Region"
}, {
__index = _base_0,
__call = function(cls, ...)
local _self_0 = setmetatable({}, _base_0)
cls.__init(_self_0, ...)
return _self_0
end
})
_base_0.__class = _class_0
Region = _class_0
end
local make_fullscreen_region
make_fullscreen_region = function()
local r = Region()
local d = get_video_dimensions()
local a = VideoPoint()
local b = VideoPoint()
local xa, ya
do
local _obj_0 = d.top_left
xa, ya = _obj_0.x, _obj_0.y
end
a:set_from_screen(xa, ya)
local xb, yb
do
local _obj_0 = d.bottom_right
xb, yb = _obj_0.x, _obj_0.y
end
b:set_from_screen(xb, yb)
r:set_from_points(a, b)
return r
end
local formats = { }
local Format
do
local _class_0
local _base_0 = {
getPreFilters = function(self)
return { }
end,
getPostFilters = function(self)
return { }
end,
getFlags = function(self)
return { }
end
}
_base_0.__index = _base_0
_class_0 = setmetatable({
__init = function(self)
self.displayName = "Basic"
self.supportsTwopass = true
self.videoCodec = ""
self.audioCodec = ""
self.outputExtension = ""
self.acceptsBitrate = true
end,
__base = _base_0,
__name = "Format"
}, {
__index = _base_0,
__call = function(cls, ...)
local _self_0 = setmetatable({}, _base_0)
cls.__init(_self_0, ...)
return _self_0
end
})
_base_0.__class = _class_0
Format = _class_0
end
local RawVideo
do
local _class_0
local _parent_0 = Format
local _base_0 = {
getColorspace = function(self)
local csp = mp.get_property("colormatrix")
local _exp_0 = csp
if "bt.601" == _exp_0 then
return "bt601"
elseif "bt.709" == _exp_0 then
return "bt709"
elseif "bt.2020" == _exp_0 then
return "bt2020"
elseif "smpte-240m" == _exp_0 then
return "smpte240m"
else
msg.info("Warning, unknown colorspace " .. tostring(csp) .. " detected, using bt.601.")
return "bt601"
end
end,
getPostFilters = function(self)
return {
"format=yuv444p16",
"lavfi-scale=in_color_matrix=" .. self:getColorspace(),
"format=bgr24"
}
end
}
_base_0.__index = _base_0
setmetatable(_base_0, _parent_0.__base)
_class_0 = setmetatable({
__init = function(self)
self.displayName = "Raw"
self.supportsTwopass = false
self.videoCodec = "rawvideo"
self.audioCodec = "pcm_s16le"
self.outputExtension = "avi"
self.acceptsBitrate = false
end,
__base = _base_0,
__name = "RawVideo",
__parent = _parent_0
}, {
__index = function(cls, name)
local val = rawget(_base_0, name)
if val == nil then
local parent = rawget(cls, "__parent")
if parent then
return parent[name]
end
else
return val
end
end,
__call = function(cls, ...)
local _self_0 = setmetatable({}, _base_0)
cls.__init(_self_0, ...)
return _self_0
end
})
_base_0.__class = _class_0
if _parent_0.__inherited then
_parent_0.__inherited(_parent_0, _class_0)
end
RawVideo = _class_0
end
formats["raw"] = RawVideo()
local WebmVP8
do
local _class_0
local _parent_0 = Format
local _base_0 = {
getPreFilters = function(self)
local colormatrixFilter = {
["bt.709"] = "bt709",
["bt.2020"] = "bt2020",
["smpte-240m"] = "smpte240m"
}
local ret = { }
local colormatrix = mp.get_property_native("video-params/colormatrix")
if colormatrixFilter[colormatrix] then
append(ret, {
"lavfi-colormatrix=" .. tostring(colormatrixFilter[colormatrix]) .. ":bt601"
})
end
return ret
end,
getFlags = function(self)
return {
"--ovcopts-add=threads=" .. tostring(options.libvpx_threads)
}
end
}
_base_0.__index = _base_0
setmetatable(_base_0, _parent_0.__base)
_class_0 = setmetatable({
__init = function(self)
self.displayName = "WebM"
self.supportsTwopass = true
self.videoCodec = "libvpx"
self.audioCodec = "libvorbis"
self.outputExtension = "webm"
self.acceptsBitrate = true
end,
__base = _base_0,
__name = "WebmVP8",
__parent = _parent_0
}, {
__index = function(cls, name)
local val = rawget(_base_0, name)
if val == nil then
local parent = rawget(cls, "__parent")
if parent then
return parent[name]
end
else
return val
end
end,
__call = function(cls, ...)
local _self_0 = setmetatable({}, _base_0)
cls.__init(_self_0, ...)
return _self_0
end
})
_base_0.__class = _class_0
if _parent_0.__inherited then
_parent_0.__inherited(_parent_0, _class_0)
end
WebmVP8 = _class_0
end
formats["webm-vp8"] = WebmVP8()
local WebmVP9
do
local _class_0
local _parent_0 = Format
local _base_0 = {
getFlags = function(self)
return {
"--ovcopts-add=threads=" .. tostring(options.libvpx_threads)
}
end
}
_base_0.__index = _base_0
setmetatable(_base_0, _parent_0.__base)
_class_0 = setmetatable({
__init = function(self)
self.displayName = "WebM (VP9)"
self.supportsTwopass = true
self.videoCodec = "libvpx-vp9"
self.audioCodec = "libvorbis"
self.outputExtension = "webm"
self.acceptsBitrate = true
end,
__base = _base_0,
__name = "WebmVP9",
__parent = _parent_0
}, {
__index = function(cls, name)
local val = rawget(_base_0, name)
if val == nil then
local parent = rawget(cls, "__parent")
if parent then
return parent[name]
end
else
return val
end
end,
__call = function(cls, ...)
local _self_0 = setmetatable({}, _base_0)
cls.__init(_self_0, ...)
return _self_0
end
})
_base_0.__class = _class_0
if _parent_0.__inherited then
_parent_0.__inherited(_parent_0, _class_0)
end
WebmVP9 = _class_0
end
formats["webm-vp9"] = WebmVP9()
local MP4
do
local _class_0
local _parent_0 = Format
local _base_0 = { }
_base_0.__index = _base_0
setmetatable(_base_0, _parent_0.__base)
_class_0 = setmetatable({
__init = function(self)
self.displayName = "MP4 (h264/AAC)"
self.supportsTwopass = true
self.videoCodec = "libx264"
self.audioCodec = "aac"
self.outputExtension = "mp4"
self.acceptsBitrate = true
end,
__base = _base_0,
__name = "MP4",
__parent = _parent_0
}, {
__index = function(cls, name)
local val = rawget(_base_0, name)
if val == nil then
local parent = rawget(cls, "__parent")
if parent then
return parent[name]
end
else
return val
end
end,
__call = function(cls, ...)
local _self_0 = setmetatable({}, _base_0)
cls.__init(_self_0, ...)
return _self_0
end
})
_base_0.__class = _class_0
if _parent_0.__inherited then
_parent_0.__inherited(_parent_0, _class_0)
end
MP4 = _class_0
end
formats["mp4"] = MP4()
local Page
do
local _class_0
local _base_0 = {
add_keybinds = function(self)
if not self.keybinds then
return
end
for key, func in pairs(self.keybinds) do
mp.add_forced_key_binding(key, key, func, {
repeatable = true
})
end
end,
remove_keybinds = function(self)
if not self.keybinds then
return
end
for key, _ in pairs(self.keybinds) do
mp.remove_key_binding(key)
end
end,
observe_properties = function(self)
self.sizeCallback = function()
return self:draw()
end
local properties = {
"keepaspect",
"video-out-params",
"video-unscaled",
"panscan",
"video-zoom",
"video-align-x",
"video-pan-x",
"video-align-y",
"video-pan-y",
"osd-width",
"osd-height"
}
for _index_0 = 1, #properties do
local p = properties[_index_0]
mp.observe_property(p, "native", self.sizeCallback)
end
end,
unobserve_properties = function(self)
if self.sizeCallback then
mp.unobserve_property(self.sizeCallback)
self.sizeCallback = nil
end
end,
clear = function(self)
local window_w, window_h = mp.get_osd_size()
mp.set_osd_ass(window_w, window_h, "")
return mp.osd_message("", 0)
end,
prepare = function(self)
return nil
end,
dispose = function(self)
return nil
end,
show = function(self)
self.visible = true
self:observe_properties()
self:add_keybinds()
self:prepare()
self:clear()
return self:draw()
end,
hide = function(self)
self.visible = false
self:unobserve_properties()
self:remove_keybinds()
self:clear()
return self:dispose()
end,
setup_text = function(self, ass)
local scale = calculate_scale_factor()
local margin = options.margin * scale
ass:pos(margin, margin)
return ass:append("{\fs" .. tostring(options.font_size * scale) .. "}")
end
}
_base_0.__index = _base_0
_class_0 = setmetatable({
__init = function() end,
__base = _base_0,
__name = "Page"
}, {
__index = _base_0,
__call = function(cls, ...)
local _self_0 = setmetatable({}, _base_0)
cls.__init(_self_0, ...)
return _self_0
end
})
_base_0.__class = _class_0
Page = _class_0
end
local EncodeWithProgress
do
local _class_0
local _parent_0 = Page
local _base_0 = {
draw = function(self)
local progress = 100 * ((self.currentTime - self.startTime) / self.duration)
local progressText = string.format("%d%%", progress)
local window_w, window_h = mp.get_osd_size()
local ass = assdraw.ass_new()
ass:new_event()
self:setup_text(ass)
ass:append("Encoding (" .. tostring(bold(progressText)) .. ")\N")
return mp.set_osd_ass(window_w, window_h, ass.text)
end,
parseLine = function(self, line)
local matchTime = string.match(line, "Encode time[-]pos: ([0-9.]+)")
local matchExit = string.match(line, "Exiting... [(]([%a ]+)[)]")
if matchTime == nil and matchExit == nil then
return
end
if matchTime ~= nil and tonumber(matchTime) > self.currentTime then
self.currentTime = tonumber(matchTime)
end
if matchExit ~= nil then
self.finished = true
self.finishedReason = matchExit
end
end,
startEncode = function(self, command_line)
local copy_command_line
do
local _accum_0 = { }
local _len_0 = 1
for _index_0 = 1, #command_line do
local arg = command_line[_index_0]
_accum_0[_len_0] = arg
_len_0 = _len_0 + 1
end
copy_command_line = _accum_0
end
append(copy_command_line, {
'--term-status-msg=Encode time-pos: ${=time-pos}'
})
self:show()
local processFd = run_subprocess_popen(copy_command_line)
for line in processFd:lines() do
msg.verbose(string.format('%q', line))
self:parseLine(line)
self:draw()
end
processFd:close()
self:hide()
if self.finishedReason == "End of file" then
return true
end
return false
end
}
_base_0.__index = _base_0
setmetatable(_base_0, _parent_0.__base)
_class_0 = setmetatable({
__init = function(self, startTime, endTime)
self.startTime = startTime
self.endTime = endTime
self.duration = endTime - startTime
self.currentTime = startTime
end,
__base = _base_0,
__name = "EncodeWithProgress",
__parent = _parent_0
}, {
__index = function(cls, name)
local val = rawget(_base_0, name)
if val == nil then
local parent = rawget(cls, "__parent")
if parent then
return parent[name]
end
else
return val
end
end,
__call = function(cls, ...)
local _self_0 = setmetatable({}, _base_0)
cls.__init(_self_0, ...)
return _self_0
end
})
_base_0.__class = _class_0
if _parent_0.__inherited then
_parent_0.__inherited(_parent_0, _class_0)
end
EncodeWithProgress = _class_0
end
local get_active_tracks
get_active_tracks = function()
local accepted = {
video = true,
audio = not mp.get_property_bool("mute"),
sub = mp.get_property_bool("sub-visibility")
}
local active = { }
for _, track in ipairs(mp.get_property_native("track-list")) do
if track["selected"] and accepted[track["type"]] then
active[#active + 1] = track
end
end
return active
end
local get_scale_filters
get_scale_filters = function()
if options.scale_height > 0 then
return {
"lavfi-scale=-2:" .. tostring(options.scale_height)
}
end
return { }
end
local append_property
append_property = function(out, property_name, option_name)
option_name = option_name or property_name
local prop = mp.get_property(property_name)
if prop and prop = "" then
return append(out, {
"--" .. tostring(option_name) .. "=" .. tostring(prop)
})
end
end
local append_list_options
append_list_options = function(out, property_name, option_prefix)
option_prefix = option_prefix or property_name
local prop = mp.get_property_native(property_name)
if prop then
for _index_0 = 1, #prop do
local value = prop[_index_0]
append(out, {
"--" .. tostring(option_prefix) .. "-append=" .. tostring(value)
})
end
end
end
local get_playback_options
get_playback_options = function()
local ret = { }
append_property(ret, "sub-ass-override")
append_property(ret, "sub-ass-force-style")
append_property(ret, "sub-auto")
append_property(ret, "video-rotate")
for _, track in ipairs(mp.get_property_native("track-list")) do
if track["type"] == "sub" and track["external"] then
append(ret, {
"--sub-files-append=" .. tostring(track['external-filename'])
})
end
end
return ret
end
local get_metadata_flags
get_metadata_flags = function()
local title = mp.get_property("filename/no-ext")
return {
"--oset-metadata=title=%" .. tostring(string.len(title)) .. "%" .. tostring(title)
}
end
local apply_current_filters
apply_current_filters = function(filters)
local vf = mp.get_property_native("vf")
msg.verbose("apply_current_filters: got " .. tostring(#vf) .. " currently applied.")
for _index_0 = 1, #vf do
local _continue_0 = false
repeat
local filter = vf[_index_0]
msg.verbose("apply_current_filters: filter name: " .. tostring(filter['name']))
if filter["enabled"] == false then
_continue_0 = true
break
end
local str = filter["name"]
local params = filter["params"] or { }
for k, v in pairs(params) do
str = str .. ":" .. tostring(k) .. "=%" .. tostring(string.len(v)) .. "%" .. tostring(v)
end
append(filters, {
str
})
_continue_0 = true
until true
if not _continue_0 then
break
end
end
end
local encode
encode = function(region, startTime, endTime)
local format = formats[options.output_format]
local path = mp.get_property("path")
if not path then
message("No file is being played")
return
end
local is_stream = not file_exists(path)
local command = {
get_mpv_path(),
path,
"--start=" .. seconds_to_time_string(startTime, false, true),
"--end=" .. seconds_to_time_string(endTime, false, true),
"--ovc=" .. tostring(format.videoCodec),
"--oac=" .. tostring(format.audioCodec),
"--loop-file=no"
}
local vid = -1
local aid = -1
local sid = -1
for _, track in ipairs(get_active_tracks()) do
local _exp_0 = track["type"]
if "video" == _exp_0 then
vid = track['id']
elseif "audio" == _exp_0 then
aid = track['id']
elseif "sub" == _exp_0 then
sid = track['id']
end
end
append(command, {
"--vid=" .. (vid >= 0 and tostring(vid) or "no"),
"--aid=" .. (aid >= 0 and tostring(aid) or "no"),
"--sid=" .. (sid >= 0 and tostring(sid) or "no")
})
append(command, get_playback_options())
local filters = { }
append(filters, format:getPreFilters())
if options.apply_current_filters then
apply_current_filters(filters)
end
if region and region:is_valid() then
append(filters, {
"lavfi-crop=" .. tostring(region.w) .. ":" .. tostring(region.h) .. ":" .. tostring(region.x) .. ":" .. tostring(region.y)
})
end
append(filters, get_scale_filters())
append(filters, format:getPostFilters())
for _index_0 = 1, #filters do
local f = filters[_index_0]
append(command, {
"--vf-add=" .. tostring(f)
})
end
append(command, format:getFlags())
if options.write_filename_on_metadata then
append(command, get_metadata_flags())
end
if options.target_filesize > 0 and format.acceptsBitrate then
local dT = endTime - startTime
if options.strict_filesize_constraint then
local video_kilobits = options.target_filesize * 8
if aid >= 0 then
video_kilobits = video_kilobits - dT * options.strict_audio_bitrate
append(command, {
"--oacopts-add=b=" .. tostring(options.strict_audio_bitrate) .. "k"
})
end
video_kilobits = video_kilobits * options.strict_bitrate_multiplier
local bitrate = math.floor(video_kilobits / dT)
append(command, {
"--ovcopts-add=b=" .. tostring(bitrate) .. "k",
"--ovcopts-add=minrate=" .. tostring(bitrate) .. "k",
"--ovcopts-add=maxrate=" .. tostring(bitrate) .. "k"
})
else
local bitrate = math.floor(options.target_filesize * 8 / dT)
append(command, {
"--ovcopts-add=b=" .. tostring(bitrate) .. "k"
})
end
elseif options.target_filesize <= 0 and format.acceptsBitrate then
append(command, {
"--ovcopts-add=b=0"
})
end
for token in string.gmatch(options.additional_flags, "[^%s]+") do
command[#command + 1] = token
end
if not options.strict_filesize_constraint then
for token in string.gmatch(options.non_strict_additional_flags, "[^%s]+") do
command[#command + 1] = token
end
end
if options.twopass and format.supportsTwopass and not is_stream then
local first_pass_cmdline
do
local _accum_0 = { }
local _len_0 = 1
for _index_0 = 1, #command do
local arg = command[_index_0]
_accum_0[_len_0] = arg
_len_0 = _len_0 + 1
end
first_pass_cmdline = _accum_0
end
append(first_pass_cmdline, {
"--ovcopts-add=flags=+pass1",
"-of=" .. tostring(format.outputExtension),
"-o=" .. tostring(get_null_path())
})
message("Starting first pass...")
msg.verbose("First-pass command line: ", table.concat(first_pass_cmdline, " "))
local res = run_subprocess({
args = first_pass_cmdline,
cancellable = false
})
if not res then
message("First pass failed! Check the logs for details.")
return
end
append(command, {
"--ovcopts-add=flags=+pass2"
})
end
local dir = ""
if is_stream then
dir = parse_directory("
")
else
local _
dir, _ = utils.split_path(path)
end
if options.output_directory ~= "" then
dir = parse_directory(options.output_directory)
end
local formatted_filename = format_filename(startTime, endTime, format)
local out_path = utils.join_path(dir, formatted_filename)
append(command, {
"-o=" .. tostring(out_path)
})
msg.info("Encoding to", out_path)
msg.verbose("Command line:", table.concat(command, " "))
if options.run_detached then
message("Started encode, process was detached.")
return utils.subprocess_detached({
args = command
})
else
local res = false
if not should_display_progress() then
message("Started encode...")
res = run_subprocess({
args = command,
cancellable = false
})
else
local ewp = EncodeWithProgress(startTime, endTime)
res = ewp:startEncode(command)
end
if res then
return message("Encoded successfully! Saved to\N" .. tostring(bold(out_path)))
else
return message("Encode failed! Check the logs for details.")
end
end
end
local CropPage
do
local _class_0
local _parent_0 = Page
local _base_0 = {
reset = function(self)
local dimensions = get_video_dimensions()
local xa, ya
do
local _obj_0 = dimensions.top_left
xa, ya = _obj_0.x, _obj_0.y
end
self.pointA:set_from_screen(xa, ya)
local xb, yb
do
local _obj_0 = dimensions.bottom_right
xb, yb = _obj_0.x, _obj_0.y
end
self.pointB:set_from_screen(xb, yb)
if self.visible then
return self:draw()
end
end,
setPointA = function(self)
local posX, posY = mp.get_mouse_pos()
self.pointA:set_from_screen(posX, posY)
if self.visible then
return self:draw()
end
end,
setPointB = function(self)
local posX, posY = mp.get_mouse_pos()
self.pointB:set_from_screen(posX, posY)
if self.visible then
return self:draw()
end
end,
cancel = function(self)
self:hide()
return self.callback(false, nil)
end,
finish = function(self)
local region = Region()
region:set_from_points(self.pointA, self.pointB)
self:hide()
return self.callback(true, region)
end,
draw_box = function(self, ass)
local region = Region()
region:set_from_points(self.pointA:to_screen(), self.pointB:to_screen())
local d = get_video_dimensions()
ass:new_event()
ass:pos(0, 0)
ass:append('{\bord0}')
ass:append('{\shad0}')
ass:append('{\c&H000000&}')
ass:append('{\alpha&H77}')
ass:draw_start()
ass:rect_cw(d.top_left.x, d.top_left.y, region.x, region.y + region.h)
ass:rect_cw(region.x, d.top_left.y, d.bottom_right.x, region.y)
ass:rect_cw(d.top_left.x, region.y + region.h, region.x + region.w, d.bottom_right.y)
ass:rect_cw(region.x + region.w, region.y, d.bottom_right.x, d.bottom_right.y)
return ass:draw_stop()
end,
draw = function(self)
local window = { }
window.w, window.h = mp.get_osd_size()
local ass = assdraw.ass_new()
self:draw_box(ass)
ass:new_event()
self:setup_text(ass)
ass:append(tostring(bold('Crop:')) .. "\N")
ass:append(tostring(bold('1:')) .. " change point A (" .. tostring(self.pointA.x) .. ", " .. tostring(self.pointA.y) .. ")\N")
ass:append(tostring(bold('2:')) .. " change point B (" .. tostring(self.pointB.x) .. ", " .. tostring(self.pointB.y) .. ")\N")
ass:append(tostring(bold('r:')) .. " reset to whole screen\N")
ass:append(tostring(bold('ESC:')) .. " cancel crop\N")
ass:append(tostring(bold('ENTER:')) .. " confirm crop\N")
return mp.set_osd_ass(window.w, window.h, ass.text)
end
}
_base_0.__index = _base_0
setmetatable(_base_0, _parent_0.__base)
_class_0 = setmetatable({
__init = function(self, callback, region)
self.pointA = VideoPoint()
self.pointB = VideoPoint()
self.keybinds = {
["1"] = (function()
local _base_1 = self
local _fn_0 = _base_1.setPointA
return function(...)
return _fn_0(_base_1, ...)
end
end)(),
["2"] = (function()
local _base_1 = self
local _fn_0 = _base_1.setPointB
return function(...)
return _fn_0(_base_1, ...)
end
end)(),
["r"] = (function()
local _base_1 = self
local _fn_0 = _base_1.reset
return function(...)
return _fn_0(_base_1, ...)
end
end)(),
["ESC"] = (function()
local _base_1 = self
local _fn_0 = _base_1.cancel
return function(...)
return _fn_0(_base_1, ...)
end
end)(),
["ENTER"] = (function()
local _base_1 = self
local _fn_0 = _base_1.finish
return function(...)
return _fn_0(_base_1, ...)
end
end)()
}
self:reset()
self.callback = callback
if region and region:is_valid() then
self.pointA.x = region.x
self.pointA.y = region.y
self.pointB.x = region.x + region.w
self.pointB.y = region.y + region.h
end
end,
__base = _base_0,
__name = "CropPage",
__parent = _parent_0
}, {
__index = function(cls, name)
local val = rawget(_base_0, name)
if val == nil then
local parent = rawget(cls, "__parent")
if parent then
return parent[name]
end
else
return val
end
end,
__call = function(cls, ...)
local _self_0 = setmetatable({}, _base_0)
cls.__init(_self_0, ...)
return _self_0
end
})
_base_0.__class = _class_0
if _parent_0.__inherited then
_parent_0.__inherited(_parent_0, _class_0)
end
CropPage = _class_0
end
local Option
do
local _class_0
local _base_0 = {
hasPrevious = function(self)
local _exp_0 = self.optType
if "bool" == _exp_0 then
return true
elseif "int" == _exp_0 then
if self.opts.min then
return self.value > self.opts.min
else
return true
end
elseif "list" == _exp_0 then
return self.value > 1
end
end,
hasNext = function(self)
local _exp_0 = self.optType
if "bool" == _exp_0 then
return true
elseif "int" == _exp_0 then
if self.opts.max then
return self.value < self.opts.max
else
return true
end
elseif "list" == _exp_0 then
return self.value < #self.opts.possibleValues
end
end,
leftKey = function(self)
local _exp_0 = self.optType
if "bool" == _exp_0 then
self.value = not self.value
elseif "int" == _exp_0 then
self.value = self.value - self.opts.step
if self.opts.min and self.opts.min > self.value then
self.value = self.opts.min
end
elseif "list" == _exp_0 then
if self.value > 1 then
self.value = self.value - 1
end
end
end,
rightKey = function(self)
local _exp_0 = self.optType
if "bool" == _exp_0 then
self.value = not self.value
elseif "int" == _exp_0 then
self.value = self.value + self.opts.step
if self.opts.max and self.opts.max < self.value then
self.value = self.opts.max
end
elseif "list" == _exp_0 then
if self.value < #self.opts.possibleValues then
self.value = self.value + 1
end
end
end,
getValue = function(self)
local _exp_0 = self.optType
if "bool" == _exp_0 then
return self.value
elseif "int" == _exp_0 then
return self.value
elseif "list" == _exp_0 then
local value, _
do
local _obj_0 = self.opts.possibleValues[self.value]
value, _ = _obj_0[1], _obj_0[2]
end
return value
end
end,
setValue = function(self, value)
local _exp_0 = self.optType
if "bool" == _exp_0 then
self.value = value
elseif "int" == _exp_0 then
self.value = value
elseif "list" == _exp_0 then
local set = false
for i, possiblePair in ipairs(self.opts.possibleValues) do
local possibleValue, _
possibleValue, _ = possiblePair[1], possiblePair[2]
if possibleValue == value then
set = true
self.value = i
break
end
end
if not set then
return msg.warn("Tried to set invalid value " .. tostring(value) .. " to " .. tostring(self.displayText) .. " option.")
end
end
end,
getDisplayValue = function(self)
local _exp_0 = self.optType
if "bool" == _exp_0 then
return self.value and "yes" or "no"
elseif "int" == _exp_0 then
if self.opts.altDisplayNames and self.opts.altDisplayNames[self.value] then
return self.opts.altDisplayNames[self.value]
else
return tostring(self.value)
end
elseif "list" == _exp_0 then
local value, displayValue
do
local _obj_0 = self.opts.possibleValues[self.value]
value, displayValue = _obj_0[1], _obj_0[2]
end
return displayValue or value
end
end,
draw = function(self, ass, selected)
if selected then
ass:append(tostring(bold(self.displayText)) .. ": ")
else
ass:append(tostring(self.displayText) .. ": ")
end
if self:hasPrevious() then
ass:append("◀ ")
end
ass:append(self:getDisplayValue())
if self:hasNext() then
ass:append(" ▶")
end
return ass:append("\N")
end
}
_base_0.__index = _base_0
_class_0 = setmetatable({
__init = function(self, optType, displayText, value, opts)
self.optType = optType
self.displayText = displayText
self.opts = opts
self.value = 1
return self:setValue(value)
end,
__base = _base_0,
__name = "Option"
}, {
__index = _base_0,
__call = function(cls, ...)
local _self_0 = setmetatable({}, _base_0)
cls.__init(_self_0, ...)
return _self_0
end
})
_base_0.__class = _class_0
Option = _class_0
end
local EncodeOptionsPage
do
local _class_0
local _parent_0 = Page
local _base_0 = {
getCurrentOption = function(self)
return self.options[self.currentOption][2]
end,
leftKey = function(self)
(self:getCurrentOption()):leftKey()
return self:draw()
end,
rightKey = function(self)
(self:getCurrentOption()):rightKey()
return self:draw()
end,
prevOpt = function(self)
self.currentOption = math.max(1, self.currentOption - 1)
return self:draw()
end,
nextOpt = function(self)
self.currentOption = math.min(#self.options, self.currentOption + 1)
return self:draw()
end,
confirmOpts = function(self)
for _, optPair in ipairs(self.options) do
local optName, opt
optName, opt = optPair[1], optPair[2]
options[optName] = opt:getValue()
end
self:hide()
return self.callback(true)
end,
cancelOpts = function(self)
self:hide()
return self.callback(false)
end,
draw = function(self)
local window_w, window_h = mp.get_osd_size()
local ass = assdraw.ass_new()
ass:new_event()
self:setup_text(ass)
ass:append(tostring(bold('Options:')) .. "\N\N")
for i, optPair in ipairs(self.options) do
local opt = optPair[2]
opt:draw(ass, self.currentOption == i)
end
ass:append("\N▲ / ▼: navigate\N")
ass:append(tostring(bold('ENTER:')) .. " confirm options\N")
ass:append(tostring(bold('ESC:')) .. " cancel\N")
return mp.set_osd_ass(window_w, window_h, ass.text)
end
}
_base_0.__index = _base_0
setmetatable(_base_0, _parent_0.__base)
_class_0 = setmetatable({
__init = function(self, callback)
self.callback = callback
self.currentOption = 1
local scaleHeightOpts = {
possibleValues = {
{
-1,
"no"
},
{
240
},
{
360
},
{
480
},
{
720
},
{
1080
},
{
1440
},
{
2160
}
}
}
local filesizeOpts = {
step = 250,
min = 0,
altDisplayNames = {
[0] = "0 (constant quality)"
}
}
local formatIds = {
"webm-vp8",
"webm-vp9",
"mp4",
"raw"
}
local formatOpts = {
possibleValues = (function()
local _accum_0 = { }
local _len_0 = 1
for _index_0 = 1, #formatIds do
local fId = formatIds[_index_0]
_accum_0[_len_0] = {
fId,
formats[fId].displayName
}
_len_0 = _len_0 + 1
end
return _accum_0
end)()
}
self.options = {
{
"output_format",
Option("list", "Output Format", options.output_format, formatOpts)
},
{
"twopass",
Option("bool", "Two Pass", options.twopass)
},
{
"apply_current_filters",
Option("bool", "Apply Current Video Filters", options.apply_current_filters)
},
{
"scale_height",
Option("list", "Scale Height", options.scale_height, scaleHeightOpts)
},
{
"strict_filesize_constraint",
Option("bool", "Strict Filesize Constraint", options.strict_filesize_constraint)
},
{
"write_filename_on_metadata",
Option("bool", "Write Filename on Metadata", options.write_filename_on_metadata)
},
{
"target_filesize",
Option("int", "Target Filesize", options.target_filesize, filesizeOpts)
}
}
self.keybinds = {
["LEFT"] = (function()
local _base_1 = self
local _fn_0 = _base_1.leftKey
return function(...)
return _fn_0(_base_1, ...)
end
end)(),
["RIGHT"] = (function()
local _base_1 = self
local _fn_0 = _base_1.rightKey
return function(...)
return _fn_0(_base_1, ...)
end
end)(),
["UP"] = (function()
local _base_1 = self
local _fn_0 = _base_1.prevOpt
return function(...)
return _fn_0(_base_1, ...)
end
end)(),
["DOWN"] = (function()
local _base_1 = self
local _fn_0 = _base_1.nextOpt
return function(...)
return _fn_0(_base_1, ...)
end
end)(),
["ENTER"] = (function()
local _base_1 = self
local _fn_0 = _base_1.confirmOpts
return function(...)
return _fn_0(_base_1, ...)
end
end)(),
["ESC"] = (function()
local _base_1 = self
local _fn_0 = _base_1.cancelOpts
return function(...)
return _fn_0(_base_1, ...)
end
end)()
}
end,
__base = _base_0,
__name = "EncodeOptionsPage",
__parent = _parent_0
}, {
__index = function(cls, name)
local val = rawget(_base_0, name)
if val == nil then
local parent = rawget(cls, "__parent")
if parent then
return parent[name]
end
else
return val
end
end,
__call = function(cls, ...)
local _self_0 = setmetatable({}, _base_0)
cls.__init(_self_0, ...)
return _self_0
end
})
_base_0.__class = _class_0
if _parent_0.__inherited then
_parent_0.__inherited(_parent_0, _class_0)
end
EncodeOptionsPage = _class_0
end
local PreviewPage
do
local _class_0
local _parent_0 = Page
local _base_0 = {
prepare = function(self)
local vf = mp.get_property_native("vf")
vf[#vf + 1] = {
name = "sub"
}
if self.region:is_valid() then
vf[#vf + 1] = {
name = "crop",
params = {
w = tostring(self.region.w),
h = tostring(self.region.h),
x = tostring(self.region.x),
y = tostring(self.region.y)
}
}
end
mp.set_property_native("vf", vf)
if self.startTime > -1 and self.endTime > -1 then
mp.set_property_native("ab-loop-a", self.startTime)
mp.set_property_native("ab-loop-b", self.endTime)
mp.set_property_native("time-pos", self.startTime)
end
return mp.set_property_native("pause", false)
end,
dispose = function(self)
mp.set_property("ab-loop-a", "no")
mp.set_property("ab-loop-b", "no")
for prop, value in pairs(self.originalProperties) do
mp.set_property_native(prop, value)
end
end,
draw = function(self)
local window_w, window_h = mp.get_osd_size()
local ass = assdraw.ass_new()
ass:new_event()
self:setup_text(ass)
ass:append("Press " .. tostring(bold('ESC')) .. " to exit preview.\N")
return mp.set_osd_ass(window_w, window_h, ass.text)
end,
cancel = function(self)
self:hide()
return self.callback()
end
}
_base_0.__index = _base_0
setmetatable(_base_0, _parent_0.__base)
_class_0 = setmetatable({
__init = function(self, callback, region, startTime, endTime)
self.callback = callback
self.originalProperties = {
["vf"] = mp.get_property_native("vf"),
["time-pos"] = mp.get_property_native("time-pos"),
["pause"] = mp.get_property_native("pause")
}
self.keybinds = {
["ESC"] = (function()
local _base_1 = self
local _fn_0 = _base_1.cancel
return function(...)
return _fn_0(_base_1, ...)
end
end)()
}
self.region = region
self.startTime = startTime
self.endTime = endTime
self.isLoop = false
end,
__base = _base_0,
__name = "PreviewPage",
__parent = _parent_0
}, {
__index = function(cls, name)
local val = rawget(_base_0, name)
if val == nil then
local parent = rawget(cls, "__parent")
if parent then
return parent[name]
end
else
return val
end
end,
__call = function(cls, ...)
local _self_0 = setmetatable({}, _base_0)
cls.__init(_self_0, ...)
return _self_0
end
})
_base_0.__class = _class_0
if _parent_0.__inherited then
_parent_0.__inherited(_parent_0, _class_0)
end
PreviewPage = _class_0
end
local MainPage
do
local _class_0
local _parent_0 = Page
local _base_0 = {
setStartTime = function(self)
self.startTime = mp.get_property_number("time-pos")
if self.visible then
self:clear()
return self:draw()
end
end,
setEndTime = function(self)
self.endTime = mp.get_property_number("time-pos")
if self.visible then
self:clear()
return self:draw()
end
end,
draw = function(self)
local window_w, window_h = mp.get_osd_size()
local ass = assdraw.ass_new()
ass:new_event()
self:setup_text(ass)
ass:append(tostring(bold('WebM maker')) .. "\N\N")
ass:append(tostring(bold('c:')) .. " crop\N")
ass:append(tostring(bold('1:')) .. " set start time (current is " .. tostring(seconds_to_time_string(self.startTime)) .. ")\N")
ass:append(tostring(bold('2:')) .. " set end time (current is " .. tostring(seconds_to_time_string(self.endTime)) .. ")\N")
ass:append(tostring(bold('o:')) .. " change encode options\N")
ass:append(tostring(bold('p:')) .. " preview\N")
ass:append(tostring(bold('e:')) .. " encode\N\N")
ass:append(tostring(bold('ESC:')) .. " close\N")
return mp.set_osd_ass(window_w, window_h, ass.text)
end,
onUpdateCropRegion = function(self, updated, newRegion)
if updated then
self.region = newRegion
end
return self:show()
end,
crop = function(self)
self:hide()
local cropPage = CropPage((function()
local _base_1 = self
local _fn_0 = _base_1.onUpdateCropRegion
return function(...)
return _fn_0(_base_1, ...)
end
end)(), self.region)
return cropPage:show()
end,
onOptionsChanged = function(self, updated)
return self:show()
end,
changeOptions = function(self)
self:hide()
local encodeOptsPage = EncodeOptionsPage((function()
local _base_1 = self
local _fn_0 = _base_1.onOptionsChanged
return function(...)
return _fn_0(_base_1, ...)
end
end)())
return encodeOptsPage:show()
end,
onPreviewEnded = function(self)
return self:show()
end,
preview = function(self)
self:hide()
local previewPage = PreviewPage((function()
local _base_1 = self
local _fn_0 = _base_1.onPreviewEnded
return function(...)
return _fn_0(_base_1, ...)
end
end)(), self.region, self.startTime, self.endTime)
return previewPage:show()
end,
encode = function(self)
self:hide()
if self.startTime < 0 then
message("No start time, aborting")
return
end
if self.endTime < 0 then
message("No end time, aborting")
return
end
if self.startTime >= self.endTime then
message("Start time is ahead of end time, aborting")
return
end
return encode(self.region, self.startTime, self.endTime)
end
}
_base_0.__index = _base_0
setmetatable(_base_0, _parent_0.__base)
_class_0 = setmetatable({
__init = function(self)
self.keybinds = {
["c"] = (function()
local _base_1 = self
local _fn_0 = _base_1.crop
return function(...)
return _fn_0(_base_1, ...)
end
end)(),
["1"] = (function()
local _base_1 = self
local _fn_0 = _base_1.setStartTime
return function(...)
return _fn_0(_base_1, ...)
end
end)(),
["2"] = (function()
local _base_1 = self
local _fn_0 = _base_1.setEndTime
return function(...)
return _fn_0(_base_1, ...)
end
end)(),
["o"] = (function()
local _base_1 = self
local _fn_0 = _base_1.changeOptions
return function(...)
return _fn_0(_base_1, ...)
end
end)(),
["p"] = (function()
local _base_1 = self
local _fn_0 = _base_1.preview
return function(...)
return _fn_0(_base_1, ...)
end
end)(),
["e"] = (function()
local _base_1 = self
local _fn_0 = _base_1.encode
return function(...)
return _fn_0(_base_1, ...)
end
end)(),
["ESC"] = (function()
local _base_1 = self
local _fn_0 = _base_1.hide
return function(...)
return _fn_0(_base_1, ...)
end
end)()
}
self.startTime = -1
self.endTime = -1
self.region = Region()
end,
__base = _base_0,
__name = "MainPage",
__parent = _parent_0
}, {
__index = function(cls, name)
local val = rawget(_base_0, name)
if val == nil then
local parent = rawget(cls, "__parent")
if parent then
return parent[name]
end
else
return val
end
end,
__call = function(cls, ...)
local _self_0 = setmetatable({}, _base_0)
cls.__init(_self_0, ...)
return _self_0
end
})
_base_0.__class = _class_0
if _parent_0.__inherited then
_parent_0.__inherited(_parent_0, _class_0)
end
MainPage = _class_0
end
monitor_dimensions()
local mainPage = MainPage()
return mp.add_key_binding(options.keybind, "display-webm-encoder", (function()
local _base_0 = mainPage
local _fn_0 = _base_0.show
return function(...)
return _fn_0(_base_0, ...)
end
end)(), {
repeatable = false
})

Log file

Attach the log file here. To generate a log file, you can add log-file=log.txt temporarily to your mpv.conf, or add --log-file=log.txt to the command line (it will be placed on the same location of the video file). You can use services like pastebin or similar ones to upload the file.
Again, could not find a log.txt in the location of the media file.

Sorry if this is vague or bad, this is my first time using Github.

Nothing happens after pressing E

Version: mpv-x86_64-20171209-git-3723e61

Everything works fine until I press E, where none of the text appears (and no encoding happens too). I remember it saying something when the encoding starts.

It used to work perfectly fine for me but I did a reinstall of Windows and I didn't back up the lua file so I guess the newest version is giving me problems but I'm not sure why. I also tried removing my config in case something was conflicting but to no avail.

log.txt

Feature request: skip encoding

I know it doesn't really fit with the script's tagline/name but I would love an option to just slice the video without doing any encoding.
Your UI is just way better than mpv_slicing

Make 2-pass encoding actually work.

It turns out that the script is using an incorrect way to 2-pass encode. The correct way shouldn't output to NUL or /dev/null on the first pass, but instead output to the same file of the second pass call, only adding flags=+pass1 and flags=+pass2 to ovcopts on each call.

As it turns out though, using 2-pass encoding (at least with libvpx) with mpv actually results in terrible video quality, way worse than a simple single pass encode. I'm not sure if this is a mpv bug, or I'm just doing it wrong.

"correct" two pass encode
single pass encode

[Suggestion] Default empty start/end to file start/end

Currently if start or end time is not given, the script will simply refuse to encode. This is sensible behavior. However, encoding to the end of the video can be difficult, since mpv can close (if --keep-open is not set) or go to the next item in the playlist. I suggest making it at least configurable to default an empty end timestamp to mean "until the end of the video".

Encoding with CRF does not work as expected

mpv version and platform

git commit d828887 and macOS
(write OS and version)

mpv d828887 Copyright © 2000-2018 mpv/MPlayer/mplayer2 projects
 built on Thu May 24 10:23:23 EDT 2018
ffmpeg library versions:
   libavutil       56.18.102
   libavcodec      58.19.102
   libavformat     58.16.100
   libswscale      5.2.100
   libavfilter     7.24.100
   libswresample   3.2.100
ffmpeg version: N-45620-g50df4c958

Description

VP9 has a constant quality mode that should be enabled when one uses 0 for target_filesize.
According to the ffmpeg wiki

To trigger this mode, you must use a combination of -crf and -b:v 0. -b:v MUST be 0

Describe the problem, what steps you did, what happened and what you expected to happen.

I noticed that in my encodes using 0 for target_filesize, the bitrate option was not passed to mpv's encode. I solved it on my own by editing around line 774 in webm.lua.

Expected: pass in ovcopts-add=b=0 to mpv in the command
Outcome: mpv Shelter.mkv --start=0:00:02.586 --end=0:00:03.045 --ovc=libvpx-vp9 --oac=libopus --loop-file=no --vid=1 --aid=1 --sid=1 --sub-ass-override=yes --sub-auto=exact --vf-add=lavfi-crop=1920:1080:0:0 --ovcopts-add=threads=4 --oset-metadata=title=%7%Shelter --ovcopts-add=crf=10,qmax=40 -o=./Shelter-[00.02.586-00.03.045]-audio.webm

Note that I did change the script to use opus but that shouldn't have an impact on the issue.

Log file

https://pastebin.com/TiAA3FDm

Encode failed

mpv version and platform

windows 10

mpv-x86_64-20190120-git-73fe061

Description

Tried to make a webm with default options but after I try to encode it says that "Encode failed! Check the logs for details."

Log file

https://pastebin.com/Fz9WJc3K

"loop-file=inf" causes infinite encode

loop-file=inf set causes an infinite concatenated encode. Terminating the process or CTRL+C in terminal outputs "Encode failed! Check the logs for details", but no sign of any log or logs (checked home directory, working directory, and mpv config directory, and also grepped recursively for filename). Haven't looked at the source, but the lua script doesn't appear to save a log?
Using webm.lua from git, mpv git.

Division error in scaling videos & incorrect output

mpv version and platform

mpv 0.28.2 (C) 2000-2017 mpv/MPlayer/mplayer2 projects
 built on Sat Apr 21 19:39:49 BST 2018
ffmpeg library versions:
   libavutil       56.14.100
   libavcodec      58.18.100
   libavformat     58.12.100
   libswscale      5.1.100
   libavfilter     7.16.100
   libswresample   3.1.100
ffmpeg version: 4.0

Description

When scaling the height on some videos, mpv fails as the new width is not divisible by 2, e.g. scaling a 1280x720 video to be 480px in height. However, the output is still "Encoded successfully!" even though no file is created.

The underlying problem of being unable to scale it due to the new dimensions should be fixed by using lavfi-scale=-2:480 instead of -1:.

Log file

https://pastebin.com/r5eYzpUW

But if I run the command manually in Terminal, I get the following output:

[encode-lavc] Opening video encoder: libx264 H.264 / AVC / MPEG-4 AVC / MPEG-4 part 10 [libx264]
[ffmpeg] libx264: width not divisible by 2 (853x480)
[encode-lavc] unable to open encoder (see above for the cause)
[encode-lavc] vo-lavc: encoded 0 bytes
[encode-lavc] ao-lavc: encoded 0 bytes
Could not initialize video chain.
Video: no video

Exiting... (Quit)
[encode-lavc] Called a function on a failed encoding context. Bailing out.
[ao/lavc] not even ready to encode audio at end -> dropped

Additional Flags: Add Metadata Title

I'm trying to have the script add the filename of the source video to the metadata of the created webm as a "Title", so people don't have to ask for sources as often.
I added an "--oset-metadata=title=" flag into the additional_flags line so that it reads additional_flags = "--oset-metadata=title=" .. mp.get_property("filename/no-ext"), but it doesn't seem to affect anything. Only using a text string as an argument for "--oset-metadata=title=" doesn't actually influence the metadata either.
Is this not what the additional_flags line is for, or am I doing it incorrectly?

NUL-video-pass1.log

is there a way to make the "NUL-video-pass1.log" get automatically deleted when no longer needed? right now the log file is created in the source folder of any video file used.

Fails to encode

mpv version and platform

macOS 10.12.6
mpv 0.29.1

mpv 0.29.1 Copyright © 2000-2018 mpv/MPlayer/mplayer2 projects
 built on Fri Oct  5 00:01:23 CEST 2018
ffmpeg library versions:
   libavutil       56.14.100
   libavcodec      58.18.100
   libavformat     58.12.100
   libswscale      5.1.100
   libavfilter     7.16.100
   libswresample   3.1.100
ffmpeg version: 4.0.2

Description

Encoding fails. "No video", despite MPV playing it fine.

Log file

https://pastebin.com/9VjGG98a

Webm encodes fail on macOS.

Similar to #2, I'm on macOS High Sierra.
Unlike #2, neither webm-vp8 nor webm-vp9 can create a file.
However, raw works as intended.

I started by building ffmpeg from Homebrew. Here is the formula used:
https://github.com/Homebrew/homebrew-core/blob/master/Formula/ffmpeg.rb

My ffmpeg build options:

brew install ffmpeg --with-vpx --with-vorbis --with-libvorbis --with-vpx --with-vorbis --with-theora --with-libogg --with-libvorbis --with-gpl --with-version3 --with-nonfree --with-postproc --with-libaacplus --with-libass --with-libcelt --with-libfaac --with-libfdk-aac --with-libfreetype --with-libmp3lame --with-libopencore-amrnb --with-libopencore-amrwb --with-libopenjpeg --with-openssl --with-libopus --with-libschroedinger --with-libspeex --with-libtheora --with-libvo-aacenc --with-libvpx --with-libx264 --with-libxvid --with-cuvid --with-nvenc --with-cuda --with-opencl --with-vdpau --with-lavc

My ffmpeg configuration shows both libvorbis and libvpx enabled, and I can make webms just fine:

configuration: --prefix=/usr/local/Cellar/ffmpeg/3.4.2 --enable-shared --enable-pthreads --enable-version3 --enable-hardcoded-tables --enable-avresample --cc=clang --host-cflags= --host-ldflags= --disable-jack --enable-gpl --enable-libass --enable-libmp3lame --enable-libtheora --enable-libvorbis --enable-libvpx --enable-libx264 --enable-libxvid --enable-opencl --enable-videotoolbox --enable-openssl --disable-lzma --enable-nonfree

ffmpeg is in my PATH and works perfectly fine with the encode.lua mpv script.

I also built mpv from Homebrew. Here is the formula used:
https://github.com/Homebrew/homebrew-core/blob/master/Formula/mpv.rb

My mpv build options:

brew install mpv --with-bundle --with-jack --with-libaacs --with-libarchive --with-libbluray --with-libcaca --with-libdvdnav --with-libdvdread --with-pulseaudio --with-rubberband --with-uchardet --with-vapoursynth 

mpv's brew formula does not offer --enable-libvpx or --enable-libvorbis as options.
Manually adding them to the formula causes the build to fail, as neither are valid options.

mpv --ovc=help doesn't list --ovc=libvpx.
Likewise, mpv --oac=help doesn't list --oac=libvorbis.

Neither webm-vp8 nor webm-vp9 can create a file:

mpv /Users/test/Desktop/testfile.mkv --start=0:00:00.000 --end=0:00:43.585 --ovc=libvpx-vp9 --oac=libvorbis --loop-file=no --vid=1 --aid=1 --sid=1 --sub-ass-override=yes --sub-ass-force-style=Kerning=yes --sub-auto=fuzzy --ovcopts-add=threads=4 --ovcopts-add=b=458k --ovcopts-add=crf=10 -o=/Users/test/.vlc/testfile-[00.00.000-00.43.585]-audio.webm 

[13.022][v][webm] Command failed! Reason:  nil  Killed by us?  no 
[13.022][v][webm] Command stdout:  
[13.022][v][webm] [encode-lavc] neither audio nor video codec was found
[13.022][v][webm] [encode-lavc] vo-lavc: encoded 0 bytes
[13.022][v][webm] [encode-lavc] ao-lavc: encoded 0 bytes
[13.022][v][webm] Encoding initialization failed.
[13.022][v][webm] 
[13.022][v][webm] Exiting... (Fatal error)
[13.022][v][webm]  

Raw video works perfectly fine.

mpv --ovc=help lists --ovc=rawvideo, which is why I believe it succeeds.
mpv --ovc=help does not include --ovc=libvpx or --oac=libvorbis

I believe the solution is to somehow build mpv with libvpx and libvorbis, but I'm not sure if that's possible, or if that's even the correct solution. Any advice would be appreciated.

Issue with default inputs

mpv version and platform

mpv version 0.29.1 (current)
Windows

Description

Currently I am using the line: --no-input-default-bindings

What I'd like to do is add a command in the input.conf to change the current webm default hotkey (Shift+W). That way I can use my no input command again (I like to have only a few hotkeys active to avoid accidentally pressing one). Any help is appreciated, thanks :)

Bug & Feature request: video-rotate support

mpv version

mpv 0.28.2

Description

I set video-rotate to 90 and expected the output webm to be rotated. Instead, the encoding process (mpv, not ffmpeg) started using 100% of one of my cores and failed to terminate.

If I try cropping the video such that the cropped region would be in bounds no matter which way the video is rotated then the encoding process no longer hangs, however the resultant webm is not rotated.

It would be nice if video-rotate would apply to the output webm. I'm not sure if that's feasible, but if not maybe have mpv-webm simply abort the encode with an error message if video-rotate is set?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.