aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/livestreamer/packages/flashmedia/amf0.py
blob: fa4368e06bca55bfb67eb7391329a599518f52f6 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
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
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
from .compat import *
from .error import *
from .packet import *
from .util import *

class AMF0Header(Packet):
    def __init__(self, name, value, must_understand=False):
        self.name = name
        self.value = value
        self.must_understand = must_understand

    @property
    def size(self):
        size = 4+1
        size += PacketIO.script_string_size(self.name)
        size += PacketIO.script_value_size(self.value)

        return size

    def _serialize(self, packet):
        packet.write_script_string(self.name)
        packet.write_u8(int(self.must_understand))
        packet.write_u32(self.size)
        packet.write_script_value(self.value)

    @classmethod
    def _deserialize(cls, io):
        name = io.read_script_string()
        must_understand = bool(io.read_u8())
        length = io.read_u32()
        value = io.read_script_value()

        return cls(name, value, must_understand)


class AMF0Message(Packet):
    def __init__(self, target_uri, response_uri, value):
        self.target_uri = target_uri
        self.response_uri = response_uri
        self.value = value

    @property
    def size(self):
        size = 4
        size += PacketIO.script_string_size(self.target_uri)
        size += PacketIO.script_string_size(self.response_uri)
        size += PacketIO.script_value_size(self.value)

        return size

    def _serialize(self, packet):
        packet.write_script_string(self.target_uri)
        packet.write_script_string(self.response_uri)
        packet.write_u32(self.size)
        packet.write_script_value(self.value)

    @classmethod
    def _deserialize(cls, io):
        target_uri = io.read_script_string()
        response_uri = io.read_script_string()
        length = io.read_u32()
        value = io.read_script_value()


        return cls(target_uri, response_uri, value)


class AMF0Packet(Packet):
    def __init__(self, version, headers=[], messages=[]):
        self.version = version
        self.headers = headers
        self.messages = messages

    @property
    def size(self):
        size = 2+2+2

        for header in self.headers:
            size += header.size

        for message in self.messages:
            size += message.size

        return size

    def _serialize(self, packet):
        packet.write_u16(self.version)
        packet.write_u16(len(self.headers))

        for header in self.headers:
            header.serialize(packet)

        packet.write_u16(len(self.messages))
        for message in self.messages:
            message.serialize(packet)

    @classmethod
    def _deserialize(cls, io):
        version = io.read_u16()

        if version != 0:
            raise AMFError("AMF version must be 0")

        headers = []
        header_count = io.read_u16()

        for i in range(header_count):
            header = AMF0Header.deserialize(io=io)
            headers.append(header)

        messages = []
        message_count = io.read_u16()
        for i in range(message_count):
            message = AMF0Message.deserialize(io=io)
            messages.append(message)

        return cls(version, headers, messages)

__all__ = ["AMF0Packet", "AMF0Header", "AMF0Message"]