Skip to content

load_mpls

PlayList

Bases: NamedTuple

Represents a playlist.

Attributes:

Name Type Description
name str

The name of the playlist.

times list[int]

The list of times associated with the playlist.

load_mpls

load_mpls(f: BinaryIO, fix_overlap: bool = True) -> list[PlayList]

Load and parse an MPLS (Blu-ray playlist) file.

Parameters:

Name Type Description Default
f BinaryIO

The file object representing the MPLS file.

required
fix_overlap bool

Whether to fix overlapping timestamps. Defaults to True.

True

Returns:

Type Description
list[PlayList]

A list of PlayList objects representing the playlists in the MPLS file.

Examples:

>>> [
>>>     PlayList(name="00014", times=[189000000, 194469213, 225901239, 249525465, 253620806]),
>>>     PlayList(name="00015", times=[189000000, 200779267, 223110326, 249510450, 253620806]),
>>> ]
Source code in src/encode_utils_cli/util/load_mpls.py
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
def load_mpls(f: BinaryIO, fix_overlap: bool = True) -> list[PlayList]:
    """Load and parse an MPLS (Blu-ray playlist) file.

    Args:
        f: The file object representing the MPLS file.
        fix_overlap: Whether to fix overlapping timestamps. Defaults to True.

    Returns:
        A list of PlayList objects representing the playlists in the MPLS file.

    Examples:
        >>> [
        >>>     PlayList(name="00014", times=[189000000, 194469213, 225901239, 249525465, 253620806]),
        >>>     PlayList(name="00015", times=[189000000, 200779267, 223110326, 249510450, 253620806]),
        >>> ]
    """

    def int_be(data: bytes) -> int:
        funcs = {
            1: ord,
            2: lambda b: unpack(">H", b)[0],
            4: lambda b: unpack(">I", b)[0],
        }
        return funcs[len(data)](data)

    f.seek(8)
    addr_items, addr_marks = int_be(f.read(4)), int_be(f.read(4))
    f.seek(addr_items + 6)
    item_count = int_be(f.read(2))
    f.seek(2, SEEK_CUR)

    def read_item() -> PlayList:
        block_size = int_be(f.read(2))
        name = f.read(5).decode()
        f.seek(7, SEEK_CUR)
        times = [int_be(f.read(4)), int_be(f.read(4))]
        f.seek(block_size - 20, SEEK_CUR)
        return PlayList(name, times)

    items = [read_item() for _ in range(item_count)]

    f.seek(addr_marks + 4)
    mark_count = int_be(f.read(2))

    def read_mark() -> tuple[int, int]:
        f.seek(2, SEEK_CUR)
        index = int_be(f.read(2))
        time = int_be(f.read(4))
        f.seek(6, SEEK_CUR)
        return (index, time)

    for _ in range(mark_count):
        index, time = read_mark()
        if time > items[index].times[-2]:
            items[index].times.insert(-1, time)

    if fix_overlap:
        b = None
        for item in items:
            a, b = b, item.times
            if a and b[0] < a[-1] < b[-1]:
                a[-1] = b[0]
        if b is not None and len(b) > 1 and b[-1] - b[-2] < 90090:  # noqa: PLR2004
            b.pop()

    return items