mpv-player / mpv

🎥 Command line video player
https://mpv.io
Other
28.55k stars 2.92k forks source link

Custom playback positions #1171

Closed ThomS8312 closed 6 years ago

ThomS8312 commented 10 years ago

In VLC, they are called "custom bookmarks" and are like virtual chapters. Custom bookmarks can also have descriptions that correspond to them. They are very useful for navigating through lengthy videos and easy to modify. VLC saves custom bookmarks as a playlist to .xspf files to accomplish this, but mpv doesn't support XML playlist formats. Even so, that fact might not matter. VLC's implementation is quite buggy and maybe a simpler approach can be taken with mpv. Can mpv be made to do something similar?

ghost commented 10 years ago

You could write a Lua script.

Custom bookmarks can also have descriptions that correspond to them.

Descriptions would be hard because mpv has no GUI widgets that could be used to enter text.

but mpv doesn't support XML playlist formats.

Surely we could support them; it's just that most XML parser libs are a PITA and parsing XML manually is a PITA as well. Eventually, I'd like to see playlist support being added to ffmpeg.

ghost commented 10 years ago

Also, maybe this would be a good addition to the OSC?

ghost commented 10 years ago

Ping @ChrisK2

ThomS8312 commented 10 years ago
You could write a Lua script.

Learning to write scripts is on my bucket list, but unfortunatey a little too advanced for me at the moment. I imagined something that wouldn't require that level of knowledge though.

Descriptions would be hard because mpv has no GUI widgets that could be used to enter text.

Not sure how much sense this will make, but when I thought of a simplier way to do this, I pictured creating a simple text file that mpv could read, like with .srt files. For example, the text file would have a ".cb" (custom bookmark) extension. This file's contents would consist of a simple format like:

00:00:00:000 Description1 00:30:00:000 Description2 01:00:00:000 Description3

The three digits in italics after the last colon are milliseconds (it was something I was pondering, so I included it). Mpv reads this text file with a corresponding video file (maybe by matching the filename). The .cb file could be modified in a text editor just like the .conf files, instead of a GUI.

Surely we could support them; it's just that most XML parser libs are a PITA and parsing XML manually is a PITA as well. Eventually, I'd like to see playlist support being added to ffmpeg.

Maybe that explains why VLC's implementation is so buggy... I want to see if there are other options first before persuing this one.

Also, maybe this would be a good addition to the OSC?

Hm. What did you have in mind?

ghost commented 10 years ago

I pictured creating a simple text file that mpv could read, like with .srt files. For example, the text file would have a ".cb" (custom bookmark) extension.

Just loading chapters would be easy.

You could also create a mkv file that references the original file via segment linking, and adds different chapters to it. A similar effect could be achieved with mpv EDL (https://github.com/mpv-player/mpv/blob/master/DOCS/edl-mpv.rst), although it doesn't support manipulating chapters yet.

ThomS8312 commented 10 years ago

Creating mkv files crossed my mind, but it's a significant extra step to take.

An idea just came to me, and replaces what I previously said. I'm brainstorming a bit here, some things may be incomplete, but here's the gist of it.

The custom bookmarks in VLC are just time positions with descriptions. Mpv does the time positon part already with --start and --save-position-on-quit, but without the description and it isn't consecutive. What if a new program behavior option were created? Something like:

--virtual-chapters=<time['desc']1,time['desc']2,time['desc']3,...>

time = Absolute time postion ([[hh:]mm:]ss[.ms]). ['desc'] = Optional description consisting of a string that is literal.

An example in action:

mpv --virtual-chapters=00:00:00'Chap 1',00:50:40'Chap 2',01:10:25'Chap 3' FILE

This is the kind of simplicity I mean. No GUI necessary (or even playlist file for that matter) and easy to modify.

ChrisK2 commented 10 years ago

This seems to be a rather specific and (GUI wise) complex feature, so it doesn't really belong into the OSC which aims to offer only basic functionality.

ThomS8312 commented 10 years ago
Just loading chapters would be easy.

I said the new idea replaces the old, but if it's easy to do why not both? Change the option syntax to:

--virtual-chapters=<file.vc|time['desc']1,time['desc']2,time['desc']3,...>

file.vc = File containing virtual chapters (changed from .cb). Taking the example from the previous post, the first three lines in the .vc text file would read:

00:00:00'Chap 1' 00:50:40'Chap 2' 01:10:25'Chap 3'

ThomS8312 commented 10 years ago

I got an opportunity to play with EDL a bit more. I thought I could make something work with it, but it just doesn't work for my use case.

According to the man page, --merge-files "uses timeline/EDL support internally." Does this mean --merge-files is a frontend to EDL?

ghost commented 10 years ago

There's now --chapters-file, which loads chapters from a separate file. But no specific text format yet.

ghost commented 10 years ago

According to the man page, --merge-files "uses timeline/EDL support internally." Does this mean --merge-files is a frontend to EDL?

Yes.

ThomS8312 commented 10 years ago

Great! I hope the format will include these two features:

Borrowing from my previous posts (along with some changes), I would suggest a format of hh:mm:ss.ms[="description"] per line. Each line is a chapter. Absolute time begins each line with a syntax of 00:00:00.000, the description is optional and entered between two double quotes. If double quotes within the double quotes is desired, the user would be able to escape them or add them without confusion as long at there's a beginning and ending double quote.

In addition, separating the chapters on a single line would be a nice alternative option. Using a semicolon ; as a delimiter might be a good choice for that by being intuitive to the user (from input commands).

nokangaroo commented 9 years ago

How about this for a proof of concept? These scripts are for DVD bookmarking, which is more complicated than file bookmarking because DVD bookmarks are at least 2-dimensional (title and time), and they are not very well tested yet (mainly because mpv DVD playback is not very mature yet), but they include a zenity GUI for presenting a bookmark list, which could be used in other scripts, I suppose.

These scripts were originally written for VLC (and the VLC versions work very well).

The dvdplayer wrapper script to start mpv:

#!/bin/bash
# Copyright (C) 2014 nokangaroo nokangaroo@NOSPAM.aon.at

# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.

# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.

# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software Foundation,
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.

#MPV=/usr/bin/mpv
MPV=/usr/local/bin/mpv
#MPV=/home/BUILD/mpv-0.7.1/build/mpv
#MPV=/home/BUILD/mpv-master/build/mpv

# Media folder:
MEDIADIR="$HOME/mpv-DVDdata"
[[ -d $MEDIADIR ]] || mkdir -p $MEDIADIR

# Bookmark folder:
BMDIR="${MEDIADIR}/bookmarks"
[[ -d $BMDIR ]] || mkdir -p $BMDIR

PROG=`basename $0`
rm -f /tmp/${PROG}.${UID}.*
rm -f $MEDIADIR/{audiomap,data,flag,tmp,list,sed*}

# Logfile (not strictly necessary):
# echo 'print_text disctitle=${=disc-title}' > $FIFO
# eval `grep disctitle $LOGFILE | tail -n 1` #should also work with the VLC
# scripts if the prompt is set to "" and cli.lua is modified accordingly
LOGFILE=`mktemp -q /tmp/${PROG}.${UID}.log.XXXXXXXXXX`

# Put dvdread output into a different file:
LOGFILE0=`mktemp -q /tmp/${PROG}.${UID}.dvdread.XXXXXXXXXX`

# Control file (fifo):
FIFO=`mktemp -u /tmp/${PROG}.${UID}.fifo.XXXXXXXXXX`
mkfifo -m 600 $FIFO
#FIFO=$HOME/.config/mpv/fifo
#[[ -p $FIFO ]] || mkfifo -m 600 $FIFO

# Better use a temporary file for retrieving values instead of the logfile:
TMP=`mktemp -q /tmp/${PROG}.${UID}.tmp.XXXXXXXXXX`

# DVD device (this is a DVD player only!):
if [[ "$*" ]]; then
# Drag an iso file or VIDEO_TS folder to the terminal (takes only one
# argument; the $* is for handling filenames with spaces):
DVD_DEVICE="$(echo "$*" | sed s/^\'\|\'$//g)"
else
# Will find external drive if present:
DVD_DEVICE="$(grep "udf" /etc/mtab | awk '{print $1}')"
# Helpful information for editing the data files manually; also needed for
# DVD disc_id:
DISK_LABEL="$(grep "udf" /etc/mtab | awk '{print $2}')"
fi

[[ -z $DISK_LABEL ]] && DISK_LABEL="$DVD_DEVICE"

# Playback start position:
get_data () {
if [[ -f $DEFAULTFILE ]]; then
local j
for j in "$@"; do
if [[ `grep "^resume@$j" $DEFAULTFILE` ]]; then
eval "$j"=`grep -w -o "^resume@$j=.*" $DEFAULTFILE | cut -d \= -f 2`
else
eval "$j"=`grep -w -o "^$j=.*" $DEFAULTFILE | cut -d \= -f 2`
fi
done
fi
}

mpv_command () {
echo "$*" > $FIFO
}

alt_audio () {
# Cycle through audio and commentary track(s)
# This script was written by somebody living in a foreign country who wants to
# watch DVDs in English. Some might find this function redundant:
local lang
local current
local other
local audio
if [[ `grep '^lang' $DEFAULTFILE` ]]; then
lang=`grep '^lang' $DEFAULTFILE | cut -d \= -f 2`
else
lang='en'
fi
if [[ ! -f $AUDIOMAP ]]; then
echo 'run "/bin/sh" "-c" "echo \"${track-list}\"|grep Audio|grep '$lang' > '$AUDIOMAP\" > $FIFO
wait
sleep 0.2
current=`grep '>.*<' $AUDIOMAP | sed 's/[^[:digit:]]//g'`
other=`grep -v '>.*<' $AUDIOMAP | sed 's/[^[:digit:]]//g'`
echo "$other" | tr ' ' '\n' > $AUDIOMAP
echo "$current" >> $AUDIOMAP
fi
audio=`head -n 1 $AUDIOMAP`
if [[ $audio ]]; then
mpv_command set aid $audio
sed -i /"$audio"/d $AUDIOMAP
echo "$audio" >> $AUDIOMAP
fi
}

################################################################################
# DVD disc_id:
# (almost) a replacement for disc_id of libdvdread-0.9.7
# Concatenates the *.IFO files in the VIDEO_TS folder and calculates
# the md5sum of the resulting file, which is unique for every DVD. (The
# Mac OS X DVD Player uses a shorter id string which is not unique enough).
# Unlike disc_id this function concatenates ALL *.IFO files, but is still fast
# enough. ISO images must be mounted before this calculation can be performed,
# so we need fusermount and fuseiso.
#
# A possible (path-independent) id function for media files could be:
#    #!/bin/sh
#    head -c 4096 "$1" | md5sum | cut -d \  -f 1
# (I don't know yet if this is unique enough. head -c 2048 is too short).
################################################################################
TMPFILE=`mktemp -q /tmp/${PROG}.XXXXXXXX`
if [[ "$(echo `file "$DVD_DEVICE" | cut -d \: -f 2 | grep UDF`)" ]]; then
TMPDIR=`mktemp -d -q /tmp/${PROG}.mnt.XXXXXXXX`
fuseiso -p "$DVD_DEVICE" "$TMPDIR"
DISC="$TMPDIR"
else
DISC="$DISK_LABEL"
fi
cat "$DISC"/{VIDEO_TS,video_ts}/*{IFO,ifo} >> $TMPFILE 2>/dev/null
wait
if [[ "$(echo `file "$DVD_DEVICE" | cut -d \: -f 2 | grep UDF`)" ]]; then
fusermount -u "$TMPDIR"
fi
if [[ -s $TMPFILE ]]; then
DISC_ID=`md5sum "$TMPFILE" | cut -d \  -f 1`
rm "$TMPFILE"
else
rm "$TMPFILE"
exit 1
fi

wait

# The bookmark and defaults files:
BOOKMARKFILE=${BMDIR}/${DISC_ID}.mpbmk
touch -c $BOOKMARKFILE #don't create any empty files
DEFAULTFILE=${BMDIR}/${DISC_ID}.mpdef
touch -c $DEFAULTFILE
if [[ -f $DEFAULTFILE ]] && [[ -z `grep "$DISK_LABEL" $DEFAULTFILE` ]]; then
sed -i /device/d $DEFAULTFILE
echo 'device='"$DISK_LABEL" >> $DEFAULTFILE
fi

# Workaround for matedialog, which does not work reliably with piped input.
# Anyway, it seems more efficient to run sed over the bookmark file only when
# it changes, and not every time you open it:
LISTFILE=${MEDIADIR}/list
if [[ -f $BOOKMARKFILE ]]; then
sed -n '/^[0-9]\+\t.*$/ P' $BOOKMARKFILE > $LISTFILE
# These values will be dependent on the gtk theme used (and probably on the
# screen resolution) and have to be found out by experiment. This sucks:
DISPLAY_WIDTH="$(echo "(`wc -L < $LISTFILE` * 7) + 44" | bc)"
DISPLAY_HEIGHT="$(echo "(`wc -l < $LISTFILE` * 23) + 86" | bc)"
fi

AUDIOMAP=${MEDIADIR}/audiomap

# This script:
DVDPLAYER="$0"

# Data for the bookmarking script to source. This will handle spaces in file
# names:
for data in LOGFILE FIFO TMP DVD_DEVICE DISK_LABEL BOOKMARKFILE DEFAULTFILE LISTFILE DISPLAY_WIDTH DISPLAY_HEIGHT AUDIOMAP DVDPLAYER; do
eval echo $data=\$"$data" | sed 's/ /\\ /g' >> $MEDIADIR/data
done

unset disctitle timepos aid sid alang slang monitorpixelaspect videoaspect videozoom custom
get_data disctitle timepos aid sid alang slang monitorpixelaspect videoaspect videozoom

#Why is it --monitoraspect but --video-aspect? That's unintuitive and programmer
#hostile. And underscores would be better than hyphens (no conversion needed)

[[ $timepos ]] && timepos="--start=$timepos"

[[ $aid ]] && aid="--aid=$aid"

[[ $sid ]] && sid="--sid=$sid" || sid="--no-sub" #no-sub can be put in config

[[ $alang ]] && alang="--alang=$alang"

[[ $slang ]] && slang="--slang=$slang"

[[ $monitorpixelaspect ]] && monitorpixelaspect="--monitorpixelaspect=$monitorpixelaspect"

[[ $videoaspect ]] && videoaspect="--video-aspect=$videoaspect"

[[ $videozoom ]] && videozoom="--video-zoom=$videozoom"

# Custom commandline:
if [[ `grep '^custom@' $DEFAULTFILE` ]]; then
custom=`grep '^custom@' $DEFAULTFILE | cut -d \@ -f 2`
else
custom=""
fi

# Starting mpv. The --no-resume-playback option is set because resuming is done
# with explicit 2-dimensional bookmarks (disc-title and time-pos, which is the
# absolute minimum for DVD navigation):
($MPV dvdnav://$disctitle $timepos $aid $sid $alang $slang $monitorpixelaspect $videoaspect $videozoom $custom --dvd-device="$DVD_DEVICE" --input-file=$FIFO --input-cursor --fullscreen --no-resume-playback --quiet --cache=no --chapter-seek-threshold=-1 1>$LOGFILE 2>$LOGFILE0; exit) &

# Executing global commands in the bookmarkfile, such as switching the aspect
# ratio or disabling subtitles for certain titles:
(if [[ `grep '^global_commands@' $BOOKMARKFILE` ]]; then
x=0
# Defensive programming:
until [[ $x -eq 20 ]]; do
if [[ `grep 'libdvdread: Found\|libdvdread: Could' $LOGFILE0` ]]; then
if [[ -z "$*" ]]; then
# Wait for slow DVD drives
sleep 1.5
fi
global_commands="$(grep '^global_commands@' $BOOKMARKFILE | cut -d \@ -f 2)"
wait
eval $global_commands
break
fi
sleep 0.3
x=`expr $x + 1`
done
fi) &

The bookmarking script to be used while mpv (started with the dvdplayer script) is running:

#!/bin/bash
# Copyright (C) 2014 nokangaroo nokangaroo@NOSPAM.aon.at

# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.

# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.

# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software Foundation,
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.

# Bookmark script for use with the dvdplayer script

# Commands can have prefixes, see manpage:
# osd-msg set ...

# Media folder:
MEDIADIR="${HOME}/mpv-DVDdata"
if [[ ! -d $MEDIADIR ]]; then
if [[ $1 == '-h' ]] || [[ $1 == '--help' ]]; then
continue
else
zenity --info --text 'You need to start mpv with the DVD player script first!' --timeout=3
exit
fi
fi

# The file to source for variables:
DATAFILE=${MEDIADIR}/data

# Functions:

mpv_command () {
echo "$*" > $FIFO
}

write_property () {
# Used properties: disc-title time-pos aid sid
# Hyphens don't work with eval, so the variables will have to be:
# disctitle timepos
# DEVELOPERS: Use disc_title, time_pos etc.
local i
for i in "$@"; do
echo -n "${i}"\= | sed 's/-//g' >> $BOOKMARKFILE
echo 'run "/bin/sh" "-c" "echo '\${\=$i}' >> '$BOOKMARKFILE\" > $FIFO
sleep 0.1
done
}

get_var () {
# Used properties: disc-title time-pos aid sid
# disc-title and disctitle will be an endless source for errors :(
local a
local b
for a in "$@"; do
echo 'run "/bin/sh" "-c" "echo '\${\=$a}' > '$TMP\" > $FIFO
sleep 0.1
b=`echo "$a" | sed 's/-//g'`
eval $b=`cat $TMP`
done
}

get_resume () {
local j
for j in "$@"; do
eval "$j"=`grep -w -o "^resume@$j=[0-9]\+" $DEFAULTFILE | cut -d \= -f 2`
sleep 0.1
done
}

get_default () {
local k
for k in "$@"; do
eval "$k"=`grep -w -o "^$k=[0-9]\+" $DEFAULTFILE | cut -d \= -f 2`
sleep 0.1
done
}

set_resume () {
sed -i /'resume@.*'/d $DEFAULTFILE
local l
for l in "$@"; do
echo -n "resume@${l}"\= | sed 's/-//g' >> $DEFAULTFILE
echo 'run "/bin/sh" "-c" "echo '\${\=$l}' >> '$DEFAULTFILE\" > $FIFO
sleep 0.1
done
}

set_default () {
local m
local x
for m in "$@"; do
x=`echo $m | sed 's/-//g'`
sed -i /^$x/d $DEFAULTFILE
sleep 0.1
echo -n "${m}"\= | sed 's/-//g' >> $DEFAULTFILE
echo 'run "/bin/sh" "-c" "echo '\${\=$m}' >> '$DEFAULTFILE\" > $FIFO
sleep 0.1
done
}

check_title () {
if [[ $disctitle != $oldtitle ]]; then
rm -f $AUDIOMAP
mpv_command "set disc-title $disctitle"
if [[ `grep '^aid\|^sid' $DEFAULTFILE` ]] && [[ `grep -w "^disctitle=$disctitle\|^preserve=$disctitle" $DEFAULTFILE` ]]; then
get_default aid sid
wait
mpv_command "set aid $aid"
mpv_command "set sid $sid"
fi
fi
}

set_bookmark () {
echo -e "$(expr `grep -o ^[0-9]* $BOOKMARKFILE | sort -n | tail -n 1` + 1)"'\t'"$BMK" >> $BOOKMARKFILE
wait
write_property "$@"
}

run_global () {
if [[ `grep '^global_commands@' $BOOKMARKFILE` ]]; then
global_commands="$(grep '^global_commands@' $BOOKMARKFILE | cut -d \@ -f 2)"
eval $global_commands
fi
}

alt_audio () {
# Cycle through audio and commentary track(s)
# Could also be used to toggle the audio track in case mpv refuses to find the
# correct one. In this case use a global_command like this:
# global_commands@(if [[ $DVDPLAYER == $0 ]]; then alt_audio; fi) &
local lang
local current
local other
local audio
if [[ `grep '^lang' $DEFAULTFILE` ]]; then
lang=`grep '^lang' $DEFAULTFILE | cut -d \= -f 2`
else
lang='en'
fi
if [[ ! -f $AUDIOMAP ]]; then
echo 'run "/bin/sh" "-c" "echo \"${track-list}\"|grep Audio|grep '$lang' > '$AUDIOMAP\" > $FIFO
wait
sleep 0.2
current=`grep '>.*<' $AUDIOMAP | sed 's/[^[:digit:]]//g'`
other=`grep -v '>.*<' $AUDIOMAP | sed 's/[^[:digit:]]//g'`
echo "$other" | tr ' ' '\n' > $AUDIOMAP
echo "$current" >> $AUDIOMAP
fi
audio=`head -n 1 $AUDIOMAP`
if [[ $audio ]]; then
mpv_command set aid $audio
sed -i /"$audio"/d $AUDIOMAP
echo "$audio" >> $AUDIOMAP
fi
}

quit_mpv () {
set_resume disc-title time-pos #aid sid
sleep 0.1
mpv_command quit
}

sequential () {
# Make bookmark numbers sequential after manual reordering
# This is purely cosmetic; the bookmarks will work as long as the numbers are
# unique
local NUM
local LINES
local i
NUM=1
LINES=`sed -n '/^[0-9]\+\t/ =' $BOOKMARKFILE`
for i in $LINES; do
sed -i "$i s/^[0-9]*/$NUM/" $BOOKMARKFILE
NUM=`expr $NUM + 1`
done
}

################################################################################
# The following function can be used to play text pages in DVDs (Buffy,
# X-Files). The command in the bookmark file is:
# commands@play_text <title> <startchapter>
# startchapter is usually 2
# the "disctitle" and "timepos" lines created by the bookmarking function should
# be deleted, they are not needed (but leave the blank lines in! The commands@
# line must be in the 3rd line after the bookmark)
# mplayer counts DVD titles from 1 so be sure to add 1 to $1
################################################################################
play_text () {
quit_mpv
sleep 0.3
# Yes, still using mplayer, mpv has a ***LONG*** way to go
# VLC could also be used
(mplayer -fs dvd://"$1" -dvd-device "$DVD_DEVICE" -chapter "$2" -speed 0.02 -nocache) &
echo "PLAYER=mplayer" >> $DATAFILE
}

# End of functions block

# Get variables:
[[ -f $DATAFILE ]] && . $DATAFILE

# Restart after watching text files on a DVD:
if [[ $DVDPLAYER ]] && [[ $PLAYER ]]; then
kill `pgrep -U $USER $PLAYER`
sleep 0.3
if [[ $DVD_DEVICE =~ /dev ]]; then
DVD_DEVICE=""
fi
($DVDPLAYER $DVD_DEVICE) &
exit
fi

case $1 in
-h|--help)
cat << EOF
This is a bookmarking and resuming script for mpv. It is intended for use
with the dvdplayer script. Call it with Alt+F2 while mpv (started with the
dvdplayer script) is running or assign shortcuts to its various options.

Some of the options require arguments; they are indicated in angle brackets.

Calling this script without options will create a resume bookmark and close
mpv. The previous resume bookmark will be overwritten.

Options:

-b  --create-default    will create a default bookmark at the
                        current position to start the playback from.
                        Unlike the resume bookmark this will not be
                        overwritten unless you create a new default
                        bookmark.

-c  --create            will prompt for the name of a new bookmark
                        to be created at the current position.

-e  --edit              will open the bookmark and default files in a
                        graphical editor.

-f  --find              will search \$MEDIADIR for DVDs with bookmarks that
                        match the search string.

-l  --list              will open a bookmark menu; choose one by number,
                        scrolling or double-clicking. The numbers will
                        not be consecutive if you deleted bookmarks
                        (it is of course possible to edit them to be
                        consecutive; see below).         

-r  --resume            will start playback from the resume bookmark,
                        if present.

-s  --start             will start playback from the default bookmark,
                        if present.

-u  --unset-resume      will unset the resume bookmark.

-x  --alt-audio         will switch between audio tracks of the language
                        specified in the script (useful for switching to
                        the commentary track(s) and back).

-y  --sequential        will restore consecutive bookmark numbers
                        in the bookmark file of the current DVD
                        after manual reordering of bookmarks.

-A  --set-atrack        will set the current audio track on the
                        current title as default.

-E  --echo              <custom mpv commandline>
                        will write a custom command to the defaults file.
                        An existing custom@ line will be appended to.
                        Requires restarting mpv.

-M  --monitor-par       <monitor pixel aspect ratio>
                        will stretch or pinch the display if necessary.
                        Requires restarting mpv.

-R  --aspect            <aspect ratio>
                        will force the display aspect ratio.
                        Requires restarting mpv.

-S  --set-strack        will set the current subtitle track on the
                        current title as default.

-T  --add-title         will add the current title to the defaults file,
                        so audio and subtitle default settings will be
                        applied to it. Multiple titles can be added. This
                        has no effect on the default playback position.

EOF
;;
-e|--edit)
# Insert your favourite graphical editor here (and force it to open a single
# window):
[[ -f $BOOKMARKFILE ]] && DOCUMENT[0]=$BOOKMARKFILE
[[ -f $DEFAULTFILE ]] && DOCUMENT[1]=$DEFAULTFILE
[[ ${DOCUMENT[@]} ]] && pluma --new-window ${DOCUMENT[@]}
;;
-f|--find)
# Search for DVDs with a bookmark containing the search string:
shift
item=$(grep device `grep -Ri "$*" $MEDIADIR | cut -d \: -f 1 | sed 's/\.mpbmk/\.mpdef/'` | cut -d \= -f 2)
# print to file if started from panel, else to stdout:
if [[ `tty` =~ /dev/pts ]]; then
echo "$*"\: $item
else
echo "$*"\: $item >> $HOME/Desktop/"`basename ${0}`"-found
fi
;;
-m|--menu)
mpv_command discnav prev
;;
-u|--unset-resume)
for x in disctitle timepos; do
sed -i /"resume@$x"/d $DEFAULTFILE
done
;;
-x|--alt-audio)
alt_audio
;;
-y|--sequential)
sequential
;;
-l|--list)
if [[ $BOOKMARKFILE -nt $LISTFILE ]]; then
#reload the file if it changed
sed -n '/^[0-9]\+\t.*$/ P' $BOOKMARKFILE > $LISTFILE
DISPLAY_WIDTH="$(echo "(`wc -L < $LISTFILE` * 7) + 44" | bc)"
DISPLAY_HEIGHT="$(echo "(`wc -l < $LISTFILE` * 23) + 86" | bc)"
sed -i /DISPLAY_.*/d $DATAFILE
echo "DISPLAY_WIDTH=$DISPLAY_WIDTH" >> $DATAFILE
echo "DISPLAY_HEIGHT=$DISPLAY_HEIGHT" >> $DATAFILE
fi
if [[ -s $LISTFILE ]]; then
SELECTION=$(xargs -d '\n' -a "$LISTFILE" zenity --list --width="$DISPLAY_WIDTH" --height="$DISPLAY_HEIGHT" --title="Bookmarks" --text="Select a bookmark:" --column="" --hide-header --timeout=30 | awk '{print $1}')
else
zenity --info --text='No bookmarks yet.' --timeout=2
fi
if [[ $SELECTION ]]; then
get_var disc-title
sleep 0.1
oldtitle=$disctitle
disctitle=$(grep -w -A 1 "^$SELECTION" $BOOKMARKFILE | tail -n 1 | cut -d \= -f 2)
wait
check_title
wait
timepos=$(grep -w -A 2 "^$SELECTION" $BOOKMARKFILE | tail -n 1 | cut -d \= -f 2)
wait
sleep 0.3
#mpv_command "seek $timepos absolute"
mpv_command "set time-pos $timepos"
wait
sleep 0.2
run_global
if [[ `echo $(grep -w -A 3 "^$SELECTION" $BOOKMARKFILE | tail -n 1 | cut -d \@ -f 1)` == 'commands' ]]; then
commands="$(grep -w -A 3 "^$SELECTION" $BOOKMARKFILE | tail -n 1 | cut -d \@ -f 2)"
eval $commands
fi
fi
;;
-A|--set-atrack)
sed -i '/^aid=/d' $DEFAULTFILE
set_default aid
;;
-S|--set-strack)
sed -i '/^sid=/d' $DEFAULTFILE
set_default sid
;;
-E|--echo)
# Add a custom command to the default file (e.g. --sub-forced-only):
STRING=`grep '^custom' $DEFAULTFILE`
if [[ -z "$STRING" ]]; then
echo "custom@$2" >> $DEFAULTFILE
else
sed -i "s/$STRING/$STRING $2/" $DEFAULTFILE
fi
quit_mpv
;;
-M|--mpar)
sed -i /monitorpixelaspect/d $DEFAULTFILE
echo "monitorpixelaspect=$2" >> $DEFAULTFILE
wait
quit_mpv
;;
-R|--aspect)
sed -i /videoaspect/d $DEFAULTFILE
echo "videoaspect=$2" >> $DEFAULTFILE
wait
quit_mpv
;;
-T|--add-title)
# Add default audio and subtitle settings to the present title in DVDs with
# multiple feature titles (TV series):
get_var disc-title
wait
echo "preserve=$disctitle" >> $DEFAULTFILE
;;
-c|--create)
BMK=$(zenity --entry --title="New Bookmark" --text="A new bookmark will be created at the present position. Choose a name for it:")
if [[ $BMK ]]; then
set_bookmark disc-title time-pos
sleep 0.1
if [[ -z `grep '^disctitle=' $DEFAULTFILE` ]] && [[ -z `grep '^disctitle=' $BOOKMARKFILE` ]]; then
set_default disc-title time-pos
sleep 0.1
fi
#mpv_command pause 
fi
;;
-b|--create-default)
set_default disc-title time-pos #aid sid
;;
-s|--start)
if [[ `grep '^disctitle' $DEFAULTFILE` ]]; then
get_default disctitle timepos #aid sid
wait
mpv_command set disc-title $disctitle
sleep 0.3
mpv_command set time-pos $timepos
#sleep 0.1
#mpv_command set aid $aid
#sleep 0.1
#mpv_command set sid $sid
run_global
fi
;;
-r|--resume)
if [[ `grep "resume@" $DEFAULTFILE` ]]; then
get_resume disctitle timepos #aid sid
wait
mpv_command set disc-title $disctitle
sleep 0.3
mpv_command set time-pos $timepos
#sleep 0.1
#mpv_command set aid $aid
#sleep 0.1
#mpv_command set sid $sid
run_global
fi
;;
*)
quit_mpv
;;
esac

Sample bookmark and default files (BUFFY Season 1 Disc 1):

5ec4ea21d15364aa3bb2ce4cdcd3151d.mpdef:

disctitle=0
timepos=0.320000
device=/media/BUFFY_DISC1
custom@--deinterlace=yes
resume@disctitle=2
resume@timepos=60.823899
aid=3

5ec4ea21d15364aa3bb2ce4cdcd3151d.mpbmk: The global command here is to make mpv start with the English audio track instead of the commentary (in case setting aid doesn't work).

#global_commands@(sleep 0.3; if [[ $title -eq 0 || $title -eq 1 ]]; then alt_audio; fi) &
1   Welcome To The Hellmouth (+ Commentary)
disctitle=0
timepos=0.0
2   The Harvest (+ Commentary)
disctitle=1
timepos=0.0
3   Witch
disctitle=2
timepos=0.5
4   Teacher's Pet
disctitle=3
timepos=0.5
5   Original Script "Welcome To The Hellmouth"

commands@play_text 7 2
6   Original Script "The Harvest"

commands@play_text 8 2
7   Interview Joss Whedon & David Boreanaz
disctitle=4
timepos=4.50000
ghost commented 9 years ago

Actually, there's this thing named ffmetadata: https://www.ffmpeg.org/ffmpeg-formats.html#Metadata-1

In combination with --chapters-file, this should give you the thing you requested.

ThomS8312 commented 9 years ago

@wm4 Haven't had much time to get to this, but I briefly looked into ffmetadata. I couldn't get it to work with what I tried, and unsure of a few things.

  1. What's TIMEBASE in layman's terms?
  2. Can this be done with absolute time instead of seconds?
  3. What's line in the [STREAM] section?

@nokangaroo Thanks for the input. It looks a bit complicated, but I'll look into this if the simpler ffmetadata isn't robust enough.

ghost commented 9 years ago

What's TIMEBASE in layman's terms?

It's the resolution of the time values. The example on the ffmpeg website uses TIMEBASE=1/1000, which means 1 tick is 1 millisecond (1 second divided by 1000). The chapter end time is given as END=60000, which with that timebase means 60000 milliseconds (= 60 seconds = 1 minute).

Yeah, this is a bit technical. Maybe it could be improved.

nokangaroo commented 9 years ago

Extracting an ffmetadata file with ffmpeg:

ffmpeg -i /file/with/metadata -f ffmetadata /path/to/ffmetadatafile

But what if the file does not have any metadata?

What's needed is an interface to do it on-the-fly: Read current position and write it into a file. And present an interface to choose between user-set positions (arbitrary positions, not DVD or mp4 chapters). My example code does just that.

nokangaroo commented 9 years ago

Moved: http://www.linuxquestions.org/questions/showthread.php?p=5323258#post5323258

nokangaroo commented 9 years ago

Edit: I moved this to linuxquestions.org, since it does not really belong here; it is about scripting mpv, not a feature request.

ThomS8312 commented 9 years ago

Maybe a frontend can be created for ffmetadata? If it has the desired functionality, a user friendly frontend might work well for this.

Traneptora commented 6 years ago

There is now a way bookmark chapters and save them to an XML chapters file in the User Scripts Repository. See mpv-createchapter.

agreselin commented 2 years ago

FWIW I too would like to have a quick way to make and edit chapters. My use case is guitar tuturials, where the granularity of the splitting changes as I learn the song. So I'd be making and deleting chapters relatively often wrt to, say, splitting a movie into parts. I really like mpv, this is the only thing I'm missing at the moment.

I've tried mpv-bookmarker but that's slower to navigate (it can only jump to the latest bookmark with a single key stroke) and more importantly its bookmarks are global, not a per-file thing.

Being able to load something as simple as this

00:00:00:000 Description1
00:30:00:000 Description2
01:00:00:000 Description3

as chapters would be ideal for me, especially with autoloading of the file like for subtitles.

@thebombzen mpv-createchapter seems great but is there a way to make use of the exported file without burning the chapters onto the video?

Traneptora commented 2 years ago

At the moment the script doesn't support writing to other formats.

Hrxn commented 2 years ago

You could try an EDL-based playlist, I think..

agreselin commented 2 years ago

You could try an EDL-based playlist, I think..

I've written a very simple Awk script to convert a file of timestamps to an EDL file. It's not the ultimate in versatility but it covers my needs and maybe it can cover someone else's too.

Do you know of a way to auto-load it when I open a video, like with subtitles (is there a setting or an extension to use)?

Hrxn commented 2 years ago

Why not open the EDL file directly?

agreselin commented 2 years ago

Because I didn't know I could 😅. Still, is there a way to auto-load it on launching the video from the file manager?

Traneptora commented 2 years ago

put this atop your EDL file, and set the file to be executable. Then you can run it as a script: #!/usr/bin/env -S sh -c 'tail -n +2 "$0" | mpv -'.

So your file looks like this:

#!/usr/bin/env -S sh -c 'tail -n +2 "$0" | mpv -'
# mpv EDL v0
foo.mkv
bar.mkv
baz.mkv
agreselin commented 2 years ago

I was looking for something a bit different. In the file manager often I look for a certain thumbnail and play that file, more than going by file name. If there's an EDL with the same name as the video file (except for the extension) I'd like mpv to load it automatically, like it does for srt subtitles.

Still, interesting use of the shebang, I learned something :-)