Reputation: 546
I found many question about creating DVD menu using ffmpeg but i did not find any one about programmically access to DVD structure information. When i using libav (or FFmpeg) library i can open DVD image (iso file) and access to video, audio and subtitle streams. But i could not find any API.
I can play video and found information using VLC player (and so libvlc library). But I need to do some processing on audio and subtitle stream programmically. I don't want to split VOBs using tools like SmartRipper, and only then do processing.
Does libav(ffmpeg) contain any API for dealing with DVD menus? If not can you recommend any other library which can be used to obtain information about title(chapter) start and end time with one frame(sample, AVPacket) accuracy?
I heard about libdvdnav library but i don't know if it right for me. I'm new to libav and DVD format internals.
Upvotes: 12
Views: 29411
Reputation: 1858
vgtmpeg can be used to create a metadata file with chapter data from DVDs and BDs. This metadata file can then be used as an input file to ffmpeg to mark chapters. vgtmpeg is a fork of ffmpeg but, because it is not updated very often, we'll use it as a separate tool here.
If working with VOBs containing a single title ("program" in ffmpeg terms), you can export the metadata as follows.
For just the main global data:
vgtmpeg -i dvd://VIDEO_TS -f ffmetadata meta.txt
For all the metadata, including stream data (-t 0
is just for shortcutting the copy operation):
vgtmpeg -t 0 -i dvd://VIDEO_TS -c copy -map 0 -map_metadata 0 -f ffmetadata meta.txt
You can then use your preferred version of ffmpeg to work with the VOBs while also bringing in the chapter data and other metadata.
Windows form:
ffmpeg -i concat:"VTS_01_1.VOB|VTS_01_2.VOB" -i meta.txt -c copy -map_metadata 1 foo.mkv
Linux form:
ffmpeg -i "concat:VTS_01_1.VOB\|VTS_01_2.VOB" -i meta.txt -c copy -map_metadata 1 foo.mkv
Add -fflags +genpts
before the -i
if ffmpeg complains about timestamps missing in your VOBs.
-map_metadata 0
is needed to get all the global metadata (like creation_time
) for an unknown reason. Perhaps a bug. Perhaps this will change some day.
Similarly, it is not clear why -c copy
is needed for stream metadata export... but it is likely related to needing -map 0
to select all the streams in input 0 for metadata export. From there -map_metadata 0
is needed to force including stream metadata with the global metadata (again, unknown as to why this is only needed when working with just the metadata).
If you want to limit the streams in the metadata file, map only the streams you want (e.g. -map 0:v -map 0:a
). Use -map_metadata:?:? ?:?:?
only for very unusual cases where needing to map data from one place to another.
If working with VOBs containing multiple titles, you can still export to text files like above but, then, slicing later with ffmpeg becomes a challenge. Thus, we use vgtmpeg to create an intermediate transport file instead. Note: TS files do not support metadata, so use your destination format instead for the intermediate file (or use MKV since it complains the least about VOB streams and metadata).
vgtmpeg -i dvd://VIDEO_TS?title=1 -c copy -map 0 -map -0:d title1.mkv
Add -fflags +genpts
before the -i
if ffmpeg complains about timestamps missing in your VOBs. The dvd_nav_packet
data stream will likely not be welcome in your output file, so we use -map -0:d
to ignore all data streams.
You can then use your preferred version of ffmpeg to work with the intermediate file.
ffmpeg -i title1.mkv -c copy -map 0 done1.mkv
Whether or not -map_metadata 0
is needed here seems to depend on the file formats in use. MKV, by default, does well without i.
Unfortunately, there is no built-in way to add chapter title generation with vgtmpeg/ffmpeg. One could maybe process meta.txt with a sed script (Super-Sed for Windows) to add title=Chapter 1
lines... but that is a task for another day. Alternatively, scripting out a long ffmpeg command with -metadata:c:0 title="Chapter 1" ...
seems possible too.
It would be nice if ffmpeg added IFO input support for program and chapter reading. Or, maybe, just absorb what vgtmpeg has done (but rename the title URL selector to "program" to help keep things straight.)
Windows users can use Chapter-X-tractor with IFO files to generate a metadata file that ffmpeg can use to mark chapters. It's not a great solution for automation but, for one-off jobs, it works well enough. It also allows for very basic chapter title generation.
It doesn't come with a preset for ffmpeg (too old) so you need to add one with the following settings:
Header: ;FFMETADATA1\n
Format: \n[CHAPTER]\nTIMEBASE=1/1000\nSTART=%ams\nEND=%ams\ntitle=Chapter %c\n
Footer: [empty]
Like so:
Save the data to a file such as ch.txt. Then, you can use ffmpeg to write the chapter data like so:
ffmpeg -i concat:"VTS_01_1.VOB|VTS_01_2.VOB" -i ch.txt -c copy -map_chapters 1 foo.mkv
Add -fflags +genpts
before the -i
if ffmpeg complains about timestamps missing in your VOBs.
This creates a metadata file that is not 100% correct according to ffmpeg standards. For some unknown reason, ffmpeg wants a chapter end time and Chapter-X-tractor cannot fill this need elegantly. Thus, this sets START
and END
to the same value. This works fine in VLC and, likely, most other players.
If you're a purist, you can edit the output metadata file and copy chapter start times to the previous chapters' end times. Then, using the Total Film Length found on the RAW Data tab (shown in hh:mm:ss:cc format [cc is hundredths of a seconds]), calculate the last chapter's end time in milliseconds (one zero beyond the cc value).
If you leave out the END=
line, ffmpeg will throw an error message but fills it in anyway with the next chapter's start time... which is good... except, on the last chapter where it sets start and end the same. This error also prevents reading the title=
data. Thus, this is a poor solution overall.
This tool calculates chapter times that can be a few tenths of a second different from vgtmpeg.
Upvotes: 0
Reputation: 51
I use a combination of both of the above to create a DVD chapter file which I can later add with mkvmerge to an encoded mkv file:
#!/bin/bash
if [ $# -lt 1 ]; then
echo "Usage: $0 filename title_no"
exit
fi
i=1
j2=01
filename=$1
echo "Using lsdvd to load chapter info:"
lsdvd -c ./
if [ -z "$2" ]; then
echo -ne "What title number do you want to create chapter info for: "
read title
else
title=$2
fi
IFS=',' read -r -a CHAPTERS <<< `mplayer -identify -frames 0 "./VTS_0"$title"_0.IFO" 2>/dev/null | grep CHAPTERS: | sed 's/CHAPTERS: //'`
for chapter in "${CHAPTERS[@]}"
do
echo "Chapter $i: $chapter"
let i++
done
echo -ne "Creating chapter data file...."
sleep 3
for chapter in "${CHAPTERS[@]}"
do
echo "CHAPTER$j2=$chapter" >> $filename.txt
echo "CHAPTER"$j2"NAME=Chapter $j2" >> $filename.txt
j2=$(printf %02d $((10#$j2 + 1 )))
done
echo "DONE."
echo "Chapter data file: $filename.txt"
Example output:
$ read_chapters.sh whiteglasses_chapters
Using lsdvd to load chapter info:
libdvdread: Couldn't find device name.
Couldn't read enough bytes for title.
Disc Title: unknown
Title: 01, Length: 00:00:21.000 Chapters: 01, Cells: 01, Audio streams: 00, Subpictures: 00
Chapter: 01, Length: 00:00:21.000, Start Cell: 01
Title: 02, Length: 01:52:32.166 Chapters: 11, Cells: 12, Audio streams: 02, Subpictures: 01
Chapter: 01, Length: 00:10:23.200, Start Cell: 01
Chapter: 02, Length: 00:11:53.200, Start Cell: 02
Chapter: 03, Length: 00:08:02.367, Start Cell: 03
Chapter: 04, Length: 00:11:28.533, Start Cell: 04
Chapter: 05, Length: 00:12:55.834, Start Cell: 05
Chapter: 06, Length: 00:12:26.600, Start Cell: 06
Chapter: 07, Length: 00:16:20.766, Start Cell: 07
Chapter: 08, Length: 00:10:31.934, Start Cell: 09
Chapter: 09, Length: 00:09:24.033, Start Cell: 10
Chapter: 10, Length: 00:09:04.767, Start Cell: 11
Chapter: 11, Length: 00:00:00.800, Start Cell: 12
Longest track: 02
What title number do you want to create chapter info for: 2
Chapter 1: 00:00:00.000
Chapter 2: 00:10:23.200
Chapter 3: 00:22:16.400
Chapter 4: 00:30:18.767
Chapter 5: 00:41:47.300
Chapter 6: 00:54:43.134
Chapter 7: 01:07:09.734
Chapter 8: 01:23:30.500
Chapter 9: 01:34:02.434
Chapter 10: 01:43:26.467
Chapter 11: 01:52:31.234
Creating chapter data file....DONE.
Chapter data file: whiteglasses_chapters.txt
Then I simply run:
mkvmerge --chapters chapters.txt -o output.mkv input-file.mkv
Upvotes: 3
Reputation: 1300
I'm not sure about what 1-frame accuracy means in this context. However, I've been using a tool called lsdvd, which is a basic CLI tool that takes as it's only parameter, the block device of your DVD drive. (Without that parameter, it will guess /dev/dvd
, which is lacking on modern Linux, and is usually /dev/sr0
.) It will then give you a nice listing of the chapters on the disc, like so:
$ lsdvd /dev/sr0
Disc Title: METAL_DISC_2
Title: 01, Length: 00:00:00.433 Chapters: 01, Cells: 01, Audio streams: 01, Subpictures: 01
Title: 02, Length: 00:00:11.500 Chapters: 01, Cells: 01, Audio streams: 01, Subpictures: 00
Title: 03, Length: 00:00:00.433 Chapters: 01, Cells: 01, Audio streams: 01, Subpictures: 01
Title: 04, Length: 00:00:00.433 Chapters: 01, Cells: 01, Audio streams: 01, Subpictures: 01
Title: 05, Length: 00:00:09.000 Chapters: 01, Cells: 01, Audio streams: 01, Subpictures: 00
Title: 06, Length: 00:00:10.000 Chapters: 01, Cells: 01, Audio streams: 01, Subpictures: 00
Title: 07, Length: 00:00:00.433 Chapters: 01, Cells: 01, Audio streams: 01, Subpictures: 01
Title: 08, Length: 00:25:02.333 Chapters: 06, Cells: 06, Audio streams: 01, Subpictures: 00
Title: 09, Length: 00:00:00.433 Chapters: 01, Cells: 01, Audio streams: 01, Subpictures: 00
Title: 10, Length: 00:07:48.700 Chapters: 16, Cells: 16, Audio streams: 01, Subpictures: 00
Title: 11, Length: 00:00:00.433 Chapters: 01, Cells: 01, Audio streams: 01, Subpictures: 00
Title: 12, Length: 00:16:43.066 Chapters: 08, Cells: 08, Audio streams: 01, Subpictures: 00
...snip...
Longest track: 20
If you wish to write your own code, I imagine looking at the source for lsdvd
will be instructive. The only library it links against in Fedora 25 (other than standard stuff) is libdvdread.so.4
, which is part of the dvdnav project.
HTH.
Upvotes: 11
Reputation: 7521
Basically you can’t tell, but you can look for the longest title.
one option: use
handbrakecli -scan e:
(part of handbrake)another: use
mplayer -identify dvd:// -dvd-device e:
(mplayer standard)
From: http://betterlogic.com/roger/2011/07/dvd-determine-main-title-from-command-line/
This helped me, as VLC lists the titles and chapters in it's GUI Menu's
Basically, install VLC Media Player, then play your DVD in it. Navigate through till it “is playing the real title”
then go to Playback [menu] -> title and see which one it is currently highlighting.
Now you know which title is the “main” title track.
Upvotes: 4
Reputation: 1
Mplayer can do this. I am not familiar with their library, but this could get you started
mplayer dvd:// -identify
Result
CHAPTERS: 00:00:00.000,00:03:40.200,00:07:29.500,00:12:04.033,00:16:17.199, 00:27:36.499,00:34:26.166,00:43:37.199,00:49:29.533,00:59:46.500,01:12:47.667, 01:17:09.000,01:26:13.700,01:47:15.833,01:50:06.200,01:55:25.500,02:06:42.500, 02:13:03.666,02:20:37.499,02:28:20.832,02:33:26.832,02:37:47.532,02:43:58.665, 02:51:00.165,02:56:36.165,03:01:21.998,03:05:09.331,03:07:14.665,03:11:49.665, 03:16:35.165,
Upvotes: 3