vtskit 0.2.0__tar.gz → 0.3.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (32) hide show
  1. {vtskit-0.2.0/vtskit.egg-info → vtskit-0.3.0}/PKG-INFO +11 -7
  2. {vtskit-0.2.0 → vtskit-0.3.0}/README.md +10 -6
  3. {vtskit-0.2.0 → vtskit-0.3.0}/pyproject.toml +1 -1
  4. {vtskit-0.2.0 → vtskit-0.3.0}/tests/test_lang.py +12 -1
  5. {vtskit-0.2.0 → vtskit-0.3.0}/tests/test_title_buttons.py +44 -7
  6. {vtskit-0.2.0 → vtskit-0.3.0}/vtskit/__init__.py +1 -1
  7. {vtskit-0.2.0 → vtskit-0.3.0}/vtskit/lang.py +9 -7
  8. {vtskit-0.2.0 → vtskit-0.3.0}/vtskit/titleset.py +39 -17
  9. {vtskit-0.2.0 → vtskit-0.3.0/vtskit.egg-info}/PKG-INFO +11 -7
  10. {vtskit-0.2.0 → vtskit-0.3.0}/COPYING +0 -0
  11. {vtskit-0.2.0 → vtskit-0.3.0}/COPYING.LESSER +0 -0
  12. {vtskit-0.2.0 → vtskit-0.3.0}/setup.cfg +0 -0
  13. {vtskit-0.2.0 → vtskit-0.3.0}/tests/test_angles.py +0 -0
  14. {vtskit-0.2.0 → vtskit-0.3.0}/tests/test_ifo.py +0 -0
  15. {vtskit-0.2.0 → vtskit-0.3.0}/tests/test_menu.py +0 -0
  16. {vtskit-0.2.0 → vtskit-0.3.0}/tests/test_nav.py +0 -0
  17. {vtskit-0.2.0 → vtskit-0.3.0}/tests/test_subtitles.py +0 -0
  18. {vtskit-0.2.0 → vtskit-0.3.0}/tests/test_titleset.py +0 -0
  19. {vtskit-0.2.0 → vtskit-0.3.0}/tests/test_vm.py +0 -0
  20. {vtskit-0.2.0 → vtskit-0.3.0}/tests/test_vmg.py +0 -0
  21. {vtskit-0.2.0 → vtskit-0.3.0}/vtskit/errors.py +0 -0
  22. {vtskit-0.2.0 → vtskit-0.3.0}/vtskit/ifo.py +0 -0
  23. {vtskit-0.2.0 → vtskit-0.3.0}/vtskit/menu.py +0 -0
  24. {vtskit-0.2.0 → vtskit-0.3.0}/vtskit/nav.py +0 -0
  25. {vtskit-0.2.0 → vtskit-0.3.0}/vtskit/ps.py +0 -0
  26. {vtskit-0.2.0 → vtskit-0.3.0}/vtskit/spu.py +0 -0
  27. {vtskit-0.2.0 → vtskit-0.3.0}/vtskit/subtitles.py +0 -0
  28. {vtskit-0.2.0 → vtskit-0.3.0}/vtskit/vm.py +0 -0
  29. {vtskit-0.2.0 → vtskit-0.3.0}/vtskit/vmg.py +0 -0
  30. {vtskit-0.2.0 → vtskit-0.3.0}/vtskit.egg-info/SOURCES.txt +0 -0
  31. {vtskit-0.2.0 → vtskit-0.3.0}/vtskit.egg-info/dependency_links.txt +0 -0
  32. {vtskit-0.2.0 → vtskit-0.3.0}/vtskit.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: vtskit
3
- Version: 0.2.0
3
+ Version: 0.3.0
4
4
  Summary: DVD-Video titlesets in pure Python: VOBs, navigation packs and IFO files
5
5
  Author: kajisho5
6
6
  License-Expression: LGPL-3.0-or-later
@@ -146,10 +146,13 @@ oncemore writing its discs with vtskit.
146
146
  to an end, the buttons, the palette entries that draw them): their
147
147
  overlay is a forced subpicture added with `vtskit.subtitles`, and the
148
148
  highlight information goes only into the VOBUs that play during the
149
- stretch, with the stretch's start and end as its start time, end time
149
+ stretch (where two stretches meet inside a VOBU, the one covering more
150
+ of it), with the stretch's start and end as its start time, end time
150
151
  and the end of the selection (dvdinfo's hli_s_ptm, hli_e_ptm,
151
152
  btn_sl_e_ptm). dvdauthor gives a title's buttons the whole title (every
152
- VOBU, never ending), which is what buttons without an end write.
153
+ VOBU, never ending), which is what buttons without an end write. As
154
+ dvdauthor does, a title with buttons starts with its first button
155
+ highlighted (SetHL_BTNN 1 before its own pre commands).
153
156
  * `vtskit.subtitles` adds subtitles to a title's program stream, as spumux
154
157
  does: each cue a picture of up to four colours placed on the screen and
155
158
  shown for a while, as subpicture packs a little before their time.
@@ -157,8 +160,8 @@ oncemore writing its discs with vtskit.
157
160
  `if (g5 != 0) { button = g5; }`, `call menu entry root;`) for the domain
158
161
  a text runs in, to the same commands dvdauthor writes for it: a tool
159
162
  that already speaks the language, as oncemore does, keeps its text. A
160
- button of several commands runs them from the menu's post through a
161
- dispatcher, and a jump to a chapter of another titleset goes through pad
163
+ button of several commands, a menu's or a title's, runs them from the
164
+ program chain's post through a dispatcher, and a jump to a chapter of another titleset goes through pad
162
165
  program chains, as dvdauthor's "jumppads" do.
163
166
  * `vtskit.vmg` writes the video manager: VIDEO_TS.IFO and its BUP, with
164
167
  the first-play commands, the table of titles and the titlesets'
@@ -190,8 +193,9 @@ dvdauthor's (its buttons made with spumux), and a menu's overlay in a
190
193
  normal colour is spumux's unit byte for byte; subtitles muxed by vtskit are
191
194
  spumux's units, placed where spumux places them, and the title written
192
195
  from that stream (4:3, and 16:9 with and without pan-scan or letterbox) is
193
- dvdauthor's; a title with buttons over the whole of it is dvdauthor's
194
- VOB byte for byte. A VIDEO_TS written by vtskit alone plays
196
+ dvdauthor's; a title with buttons over the whole of it (one of them of
197
+ several commands) is dvdauthor's VOB and IFO byte for byte, but for the
198
+ palette. A VIDEO_TS written by vtskit alone plays
195
199
  its titles and chapters in order under libdvdnav, its commands jumping
196
200
  between titles, its menus' buttons lead where they say, and its jumps into
197
201
  another titleset's chapters land; a title with an angle block plays and
@@ -129,10 +129,13 @@ oncemore writing its discs with vtskit.
129
129
  to an end, the buttons, the palette entries that draw them): their
130
130
  overlay is a forced subpicture added with `vtskit.subtitles`, and the
131
131
  highlight information goes only into the VOBUs that play during the
132
- stretch, with the stretch's start and end as its start time, end time
132
+ stretch (where two stretches meet inside a VOBU, the one covering more
133
+ of it), with the stretch's start and end as its start time, end time
133
134
  and the end of the selection (dvdinfo's hli_s_ptm, hli_e_ptm,
134
135
  btn_sl_e_ptm). dvdauthor gives a title's buttons the whole title (every
135
- VOBU, never ending), which is what buttons without an end write.
136
+ VOBU, never ending), which is what buttons without an end write. As
137
+ dvdauthor does, a title with buttons starts with its first button
138
+ highlighted (SetHL_BTNN 1 before its own pre commands).
136
139
  * `vtskit.subtitles` adds subtitles to a title's program stream, as spumux
137
140
  does: each cue a picture of up to four colours placed on the screen and
138
141
  shown for a while, as subpicture packs a little before their time.
@@ -140,8 +143,8 @@ oncemore writing its discs with vtskit.
140
143
  `if (g5 != 0) { button = g5; }`, `call menu entry root;`) for the domain
141
144
  a text runs in, to the same commands dvdauthor writes for it: a tool
142
145
  that already speaks the language, as oncemore does, keeps its text. A
143
- button of several commands runs them from the menu's post through a
144
- dispatcher, and a jump to a chapter of another titleset goes through pad
146
+ button of several commands, a menu's or a title's, runs them from the
147
+ program chain's post through a dispatcher, and a jump to a chapter of another titleset goes through pad
145
148
  program chains, as dvdauthor's "jumppads" do.
146
149
  * `vtskit.vmg` writes the video manager: VIDEO_TS.IFO and its BUP, with
147
150
  the first-play commands, the table of titles and the titlesets'
@@ -173,8 +176,9 @@ dvdauthor's (its buttons made with spumux), and a menu's overlay in a
173
176
  normal colour is spumux's unit byte for byte; subtitles muxed by vtskit are
174
177
  spumux's units, placed where spumux places them, and the title written
175
178
  from that stream (4:3, and 16:9 with and without pan-scan or letterbox) is
176
- dvdauthor's; a title with buttons over the whole of it is dvdauthor's
177
- VOB byte for byte. A VIDEO_TS written by vtskit alone plays
179
+ dvdauthor's; a title with buttons over the whole of it (one of them of
180
+ several commands) is dvdauthor's VOB and IFO byte for byte, but for the
181
+ palette. A VIDEO_TS written by vtskit alone plays
178
182
  its titles and chapters in order under libdvdnav, its commands jumping
179
183
  between titles, its menus' buttons lead where they say, and its jumps into
180
184
  another titleset's chapters land; a title with an angle block plays and
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "vtskit"
7
- version = "0.2.0"
7
+ version = "0.3.0"
8
8
  description = "DVD-Video titlesets in pure Python: VOBs, navigation packs and IFO files"
9
9
  readme = "README.md"
10
10
  license = "LGPL-3.0-or-later"
@@ -138,6 +138,17 @@ class TestForms(unittest.TestCase):
138
138
  self.assertEqual(hexes(self.d.compile("g1 = 0; exit;", "vts", 1)), ["7100000100000000", "3001000000000000"])
139
139
  self.assertEqual(hexes(self.d.compile("call menu entry root resume 3;", "vts", 1)), ["3008000003830000"])
140
140
 
141
+ def test_title_buttons(self):
142
+ # dvdauthor's bytes for the same buttons in a title's <pgc>, with
143
+ # <post>jump title 2;</post>: the same dispatcher as a menu's
144
+ buttons, post = self.d.menu(["g1 = 2; g2 = 3; jump title 2 chapter 1;", "g3 = 4; g4 = 5; jump title 2;"],
145
+ "jump title 2;", "vts", 1)
146
+ self.assertEqual(hexes(buttons), ["7101000f0001000d", "7101000f0002000d"])
147
+ self.assertEqual(hexes(post), ["6100000e000f0000", "7100000f00000000", "00a1000e00010006",
148
+ "00a1000e00020009", "3003000000020000", "7100000100020000",
149
+ "7100000200030000", "3005000100020000", "7100000300040000",
150
+ "7100000400050000", "3003000000020000"])
151
+
141
152
  def test_dead_code_after_a_jump(self):
142
153
  self.assertEqual(hexes(self.d.compile("g1 = 0; resume; g1 = 0; jump title 1 chapter 2; "
143
154
  "subtitle = 65; audio = 1;", "vtsm", 1)),
@@ -191,7 +202,7 @@ class TestForms(unittest.TestCase):
191
202
  with self.assertRaises(VtsError):
192
203
  self.d.menu(["g1 = 1; g2 = 2;"], "g3 = 3;", "vtsm", 1) # post that does not leave
193
204
  with self.assertRaises(VtsError):
194
- self.d.menu(["exit;"], "exit;", "vts", 1)
205
+ self.d.menu(["exit;"], "exit;", "fp") # no buttons in the first play
195
206
 
196
207
 
197
208
  def author(folder, menu_n, menu_h, a, b):
@@ -13,7 +13,7 @@ import sys
13
13
  import tempfile
14
14
  import unittest
15
15
 
16
- from vtskit import VtsError, menu, ps, spu, subtitles, titleset, vm, vmg
16
+ from vtskit import VtsError, lang, menu, ps, spu, subtitles, titleset, vm, vmg
17
17
  from vtskit.menu import Button, TitleButtons
18
18
  from vtskit.titleset import Audio, Title
19
19
 
@@ -104,7 +104,7 @@ class TestTitleButtons(unittest.TestCase):
104
104
  def test_whole_title_as_dvdauthor(self):
105
105
  # spumux's buttons over the whole title, then dvdauthor; vtskit
106
106
  # given the same stream and buttons without an end writes the same
107
- # VOB (dvdauthor writes the HLI in every VOBU, never ending)
107
+ # VOB (dvdauthor writes the HLI in every VOBU, never ending) and IFO
108
108
  t = self.tmp
109
109
  png(f"{t}/hl.png", 720, 480, RECTS, (255, 255, 0))
110
110
  png(f"{t}/sel.png", 720, 480, RECTS, (255, 0, 0))
@@ -118,17 +118,35 @@ class TestTitleButtons(unittest.TestCase):
118
118
  with open(self.plain, "rb") as src, open(sp, "wb") as dst:
119
119
  subprocess.run(["spumux", "-s", "0", f"{t}/spu.xml"], stdin=src, stdout=dst, check=True,
120
120
  stderr=subprocess.DEVNULL, env=ENV)
121
+ texts = ["g1 = 2; g2 = 3; jump title 2 chapter 1;", "exit;"]
121
122
  with open(f"{t}/dvd.xml", "w") as f:
122
123
  f.write(f'<dvdauthor dest="{t}/dvd"><vmgm/><titleset><titles>'
123
124
  '<video format="ntsc" aspect="4:3"/><audio format="ac3" channels="2" lang="en"/>'
124
- f'<pgc><vob file="{sp}"/><button name="b1">jump title 1 chapter 1;</button>'
125
- '<button name="b2">exit;</button></pgc></titles></titleset></dvdauthor>')
125
+ f'<pgc><vob file="{sp}"/><button name="b1">{texts[0]}</button>'
126
+ f'<button name="b2">{texts[1]}</button><post>jump title 2;</post></pgc>'
127
+ f'<pgc><vob file="{self.short}"/></pgc></titles></titleset></dvdauthor>')
126
128
  subprocess.run(["dvdauthor", "-x", f"{t}/dvd.xml"], check=True, capture_output=True, env=ENV)
129
+ # vtskit: the same buttons compiled with vtskit.lang (a button of
130
+ # several commands runs them from the post, through a dispatcher)
131
+ disc = lang.Disc({(1, 1): 1, (1, 2): 2}, titlesets={1: lang.Menus()})
132
+ commands, post = disc.menu(texts, "jump title 2;", "vts", 1)
133
+ tb = buttons(0, None)
134
+ for b, c in zip(tb.buttons, commands):
135
+ b.command = c
127
136
  mine = f"{t}/mine-whole"
128
- titleset.write(mine, 1, [Title(sp, audio=(Audio("en", 2),), buttons=(buttons(0, None),))])
129
- a, b = read(f"{mine}/VTS_01_1.VOB"), read(f"{t}/dvd/VIDEO_TS/VTS_01_1.VOB")
137
+ titleset.write(mine, 1, [Title(sp, audio=(Audio("en", 2),), post=tuple(post), buttons=(tb,)),
138
+ Title(self.short, audio=(Audio("en", 2),))])
139
+ theirs = f"{t}/dvd/VIDEO_TS"
140
+ a, b = read(f"{mine}/VTS_01_1.VOB"), read(f"{theirs}/VTS_01_1.VOB")
130
141
  self.assertEqual([n[2] for n in navs(a)], [n[2] for n in navs(b)])
131
142
  self.assertEqual(a, b)
143
+ # the IFO: the same, the title's pre (SetHL_BTNN 1) and post
144
+ # included, but for the palette (spumux's colours)
145
+ a, b = read(f"{mine}/VTS_01_0.IFO"), read(f"{theirs}/VTS_01_0.IFO")
146
+ self.assertEqual(len(a), len(b))
147
+ pgc = struct.unpack_from(">I", a, 0xCC)[0] * 2048 + 16
148
+ self.assertEqual(a[:pgc + 0xA4], b[:pgc + 0xA4])
149
+ self.assertEqual(a[pgc + 0xE4:], b[pgc + 0xE4:])
132
150
 
133
151
  def stretch_disc(self, start, end):
134
152
  """Title 1 (10 s) with buttons from `start` to `end` (button 1:
@@ -173,10 +191,29 @@ class TestTitleButtons(unittest.TestCase):
173
191
  with self.assertRaisesRegex(VtsError, "overlap"):
174
192
  write(buttons(1, None), buttons(3, 5))
175
193
  with self.assertRaisesRegex(VtsError, "one set of buttons"):
176
- write(buttons(1, 2.8), buttons(2.9, 5)) # in the VOBU from 2.4 s to 3.0 s
194
+ write(buttons(1, 3.0), buttons(3.05, 3.2), buttons(3.25, 5)) # in the VOBU from 3.0 s
177
195
  with self.assertRaisesRegex(VtsError, "after the title ends"):
178
196
  write(buttons(30, 40))
179
197
 
198
+ def test_stretches_meeting_in_a_vobu(self):
199
+ # the VOBUs start every 0.6006 s; where two stretches meet inside a
200
+ # VOBU, it carries the one covering more of it
201
+ def starts(*tbs):
202
+ """{VOBU start (s, rounded): its HLI's start from the title's start}"""
203
+ out = os.path.join(self.tmp, "meeting")
204
+ titleset.write(out, 1, [Title(self.plain, audio=(Audio("en", 2),), buttons=tbs)])
205
+ packs = navs(read(f"{out}/VTS_01_1.VOB"))
206
+ s0 = packs[0][1]
207
+ return {round((s - s0) / 90000, 1): struct.unpack_from(">I", h, 2)[0] - s0 if h[1] else None
208
+ for _, s, h in packs}
209
+ got = starts(buttons(1, 2.8), buttons(2.9, 5))
210
+ self.assertEqual((got[1.8], got[2.4], got[3.0]), (90000, 90000, 261000))
211
+ # buttons that change a frame before or after a VOBU's start (as a
212
+ # film title's frames fall): each VOBU still carries its own
213
+ for edge in (3.003 - 3003 / 90000, 3.003 + 3003 / 90000):
214
+ got = starts(buttons(1, edge), buttons(edge, 5))
215
+ self.assertEqual((got[2.4], got[3.0]), (90000, int(round(edge * 90000))), edge)
216
+
180
217
  @unittest.skipUnless(LIBDVDNAV, "needs libdvdnav")
181
218
  def test_under_libdvdnav(self):
182
219
  out = self.stretch_disc(3.0, 6.0)
@@ -21,5 +21,5 @@ subtitles and angles, and dvdauthor's command language:
21
21
 
22
22
  from .errors import VtsError
23
23
 
24
- __version__ = "0.2.0"
24
+ __version__ = "0.3.0"
25
25
  __all__ = ["VtsError"]
@@ -25,10 +25,10 @@ authored):
25
25
  * `audio = 1; subtitle = 65;` next to each other are one SetSTN; `g1 = 0;
26
26
  jump menu 2;` is one command (vtskit.vm folds a Set and a Link), and
27
27
  what follows an unconditional jump in a block is left out;
28
- * a menu's button runs one command: a button whose text compiles to more
29
- sets GPRM 15 to its number and links to the end of the program chain,
30
- whose post commands start with a dispatcher (`g14 = g15; g15 = 0;` and a
31
- Goto per such button) and end with each button's code;
28
+ * a menu's or a title's button runs one command: a button whose text
29
+ compiles to more sets GPRM 15 to its number and links to the end of the
30
+ program chain, whose post commands start with a dispatcher (`g14 = g15;
31
+ g15 = 0;` and a Goto per such button) and end with each button's code;
32
32
  * a jump into another titleset (dvdauthor's "jumppad") cannot be one
33
33
  command: from the video manager a jump to a chapter sets GPRM 15 to a
34
34
  code naming the title and chapter and jumps to the titleset's chapter
@@ -572,10 +572,12 @@ class Disc:
572
572
  def menu(self, buttons, post, domain="vtsm", vts=0):
573
573
  """A menu's buttons and post commands: ([one command a button],
574
574
  post commands). A button whose text takes several commands runs
575
- them from the post, through a dispatcher, as dvdauthor arranges."""
575
+ them from the post, through a dispatcher, as dvdauthor arranges.
576
+ A title's buttons (domain "vts") are compiled the same way, as
577
+ dvdauthor compiles them."""
576
578
  self._check_domain(domain)
577
- if domain not in ("vtsm", "vmgm"):
578
- raise VtsError("buttons belong to menus")
579
+ if domain not in ("vtsm", "vmgm", "vts"):
580
+ raise VtsError("buttons belong to menus and titles")
579
581
  commands, deferred = [], []
580
582
  for n, text in enumerate(buttons, 1):
581
583
  items = self.instructions(text, domain, vts)
@@ -63,7 +63,7 @@ import os
63
63
  import struct
64
64
  from dataclasses import dataclass, field
65
65
 
66
- from . import menu as menus_, nav, ps, spu
66
+ from . import menu as menus_, nav, ps, spu, vm
67
67
  from .errors import VtsError
68
68
 
69
69
  SECTOR = ps.SECTOR
@@ -748,12 +748,25 @@ def _lay_title(number, title, offset, vob_id, loaded):
748
748
  return w, sector, vob_id
749
749
 
750
750
 
751
+ def _pre(title):
752
+ """A title's pre commands: with buttons, first the first button
753
+ highlighted (SetHL_BTNN 1), as dvdauthor writes it for a title with
754
+ buttons (tests/test_title_buttons.py)."""
755
+ if not title.buttons:
756
+ return tuple(title.pre)
757
+ return (vm.set_hl_btnn(1 << 10).encode(),) + tuple(title.pre)
758
+
759
+
751
760
  def _title_buttons(number, title, loaded, part_start):
752
761
  """The HLI of the title's buttons: {(part, angle): {VOBU: HLI}}, in the
753
762
  VOBUs that play during each stretch (every angle's), shown from the
754
763
  stretch's start to its end in the VOB's time (a stretch that began in
755
764
  an earlier part from the VOB's start; one that goes on into a later
756
- part to the VOB's end; one without an end never ending)."""
765
+ part to the VOB's end; one without an end never ending). Where two
766
+ stretches meet inside a VOBU, it carries the one that covers more of
767
+ it: buttons that change between VOBUs (oncemore starts a VOBU there)
768
+ are not lost to a picture's difference between a time and the VOBU's
769
+ start, as in a film title with pulldown."""
757
770
  if not title.buttons:
758
771
  return {}
759
772
  width, height = loaded[0][0][0].sequence[:2]
@@ -768,26 +781,35 @@ def _title_buttons(number, title, loaded, part_start):
768
781
  if e1 is None or e1 > s2:
769
782
  raise VtsError(f"{w1} and {w2} overlap in time")
770
783
  out = {}
771
- used = set()
784
+ touched, used = set(), set()
772
785
  for k, part in enumerate(loaded):
773
786
  for a, (_, vs, _) in enumerate(part):
774
787
  base, vob_end = vs[0].s_ptm, vs[-1].e_ptm
775
788
  table = out[(k, a)] = {}
776
- for s, e, tb, what in stretches:
777
- for i, v in enumerate(vs):
778
- t0 = part_start[k] + v.s_ptm - base
779
- t1 = part_start[k] + v.e_ptm - base
780
- if t1 <= s or e is not None and t0 >= e:
781
- continue
782
- if i in table:
783
- raise VtsError(f"{what} start in the VOBU (part {k + 1}, VOBU {i + 1}) where "
784
- "the buttons before end: a VOBU carries one set of buttons")
785
- he = 0xFFFFFFFF if e is None else min(base + e - part_start[k], vob_end)
786
- table[i] = tb.hli(base + max(s - part_start[k], 0), he)
787
- used.add(what)
789
+ for i, v in enumerate(vs):
790
+ t0 = part_start[k] + v.s_ptm - base
791
+ t1 = part_start[k] + v.e_ptm - base
792
+ # (two stretches in a VOBU: the one covering more of it, the
793
+ # later on a tie; a VOBU carries one set of buttons)
794
+ best = None
795
+ for s, e, tb, what in stretches:
796
+ cover = min(t1, e if e is not None else t1) - max(t0, s)
797
+ if cover > 0:
798
+ touched.add(what)
799
+ if best is None or cover >= best[0]:
800
+ best = (cover, s, e, tb, what)
801
+ if best is None:
802
+ continue
803
+ _, s, e, tb, what = best
804
+ he = 0xFFFFFFFF if e is None else min(base + e - part_start[k], vob_end)
805
+ table[i] = tb.hli(base + max(s - part_start[k], 0), he)
806
+ used.add(what)
788
807
  for _, _, _, what in stretches:
789
- if what not in used:
808
+ if what not in touched:
790
809
  raise VtsError(f"{what} start after the title ends")
810
+ if what not in used:
811
+ raise VtsError(f"{what} are shown for less of each VOBU they fall in than the buttons "
812
+ "beside them: a VOBU carries one set of buttons")
791
813
  return out
792
814
 
793
815
 
@@ -955,7 +977,7 @@ def _write(folder, vts, titles, written, menus, language, pan_scan, letterbox, c
955
977
  for name in ("next_pgc", "prev_pgc", "up_pgc"):
956
978
  if not 0 <= getattr(t, name) <= len(titles):
957
979
  raise VtsError(f"title {n}: {name} {getattr(t, name)}: the titleset has {len(titles)} program chains")
958
- pgcs = [_pgc((t.pre, t.post, t.cell_commands), w, frame, sorted(w.stream.subpictures), t.palette,
980
+ pgcs = [_pgc((_pre(t), t.post, t.cell_commands), w, frame, sorted(w.stream.subpictures), t.palette,
959
981
  stills=t.stills, uops=t.uops, video=video, links=(t.next_pgc, t.prev_pgc, t.up_pgc))
960
982
  for t, w in zip(titles, written)]
961
983
  pgci = struct.pack(">HHI", len(pgcs), 0, 0)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: vtskit
3
- Version: 0.2.0
3
+ Version: 0.3.0
4
4
  Summary: DVD-Video titlesets in pure Python: VOBs, navigation packs and IFO files
5
5
  Author: kajisho5
6
6
  License-Expression: LGPL-3.0-or-later
@@ -146,10 +146,13 @@ oncemore writing its discs with vtskit.
146
146
  to an end, the buttons, the palette entries that draw them): their
147
147
  overlay is a forced subpicture added with `vtskit.subtitles`, and the
148
148
  highlight information goes only into the VOBUs that play during the
149
- stretch, with the stretch's start and end as its start time, end time
149
+ stretch (where two stretches meet inside a VOBU, the one covering more
150
+ of it), with the stretch's start and end as its start time, end time
150
151
  and the end of the selection (dvdinfo's hli_s_ptm, hli_e_ptm,
151
152
  btn_sl_e_ptm). dvdauthor gives a title's buttons the whole title (every
152
- VOBU, never ending), which is what buttons without an end write.
153
+ VOBU, never ending), which is what buttons without an end write. As
154
+ dvdauthor does, a title with buttons starts with its first button
155
+ highlighted (SetHL_BTNN 1 before its own pre commands).
153
156
  * `vtskit.subtitles` adds subtitles to a title's program stream, as spumux
154
157
  does: each cue a picture of up to four colours placed on the screen and
155
158
  shown for a while, as subpicture packs a little before their time.
@@ -157,8 +160,8 @@ oncemore writing its discs with vtskit.
157
160
  `if (g5 != 0) { button = g5; }`, `call menu entry root;`) for the domain
158
161
  a text runs in, to the same commands dvdauthor writes for it: a tool
159
162
  that already speaks the language, as oncemore does, keeps its text. A
160
- button of several commands runs them from the menu's post through a
161
- dispatcher, and a jump to a chapter of another titleset goes through pad
163
+ button of several commands, a menu's or a title's, runs them from the
164
+ program chain's post through a dispatcher, and a jump to a chapter of another titleset goes through pad
162
165
  program chains, as dvdauthor's "jumppads" do.
163
166
  * `vtskit.vmg` writes the video manager: VIDEO_TS.IFO and its BUP, with
164
167
  the first-play commands, the table of titles and the titlesets'
@@ -190,8 +193,9 @@ dvdauthor's (its buttons made with spumux), and a menu's overlay in a
190
193
  normal colour is spumux's unit byte for byte; subtitles muxed by vtskit are
191
194
  spumux's units, placed where spumux places them, and the title written
192
195
  from that stream (4:3, and 16:9 with and without pan-scan or letterbox) is
193
- dvdauthor's; a title with buttons over the whole of it is dvdauthor's
194
- VOB byte for byte. A VIDEO_TS written by vtskit alone plays
196
+ dvdauthor's; a title with buttons over the whole of it (one of them of
197
+ several commands) is dvdauthor's VOB and IFO byte for byte, but for the
198
+ palette. A VIDEO_TS written by vtskit alone plays
195
199
  its titles and chapters in order under libdvdnav, its commands jumping
196
200
  between titles, its menus' buttons lead where they say, and its jumps into
197
201
  another titleset's chapters land; a title with an angle block plays and
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes