File: test_packet.py

package info (click to toggle)
python-av 16.1.0%2Bds-3
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 1,728 kB
  • sloc: python: 8,059; sh: 181; ansic: 174; makefile: 140
file content (165 lines) | stat: -rw-r--r-- 6,755 bytes parent folder | download
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
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
import struct
from typing import get_args
from unittest import SkipTest

import av

from .common import fate_suite, sandboxed


class TestProperties:
    def test_is_keyframe(self) -> None:
        with av.open(fate_suite("h264/interlaced_crop.mp4")) as container:
            stream = container.streams.video[0]
            for i, packet in enumerate(container.demux(stream)):
                if i in (0, 21, 45, 69, 93, 117):
                    assert packet.is_keyframe
                else:
                    assert not packet.is_keyframe

    def test_is_corrupt(self) -> None:
        with av.open(fate_suite("mov/white_zombie_scrunch-part.mov")) as container:
            stream = container.streams.video[0]
            for i, packet in enumerate(container.demux(stream)):
                if i == 65:
                    assert packet.is_corrupt
                else:
                    assert not packet.is_corrupt

    def test_is_discard(self) -> None:
        with av.open(fate_suite("mov/mov-1elist-ends-last-bframe.mov")) as container:
            stream = container.streams.video[0]
            for i, packet in enumerate(container.demux(stream)):
                if i == 46:
                    assert packet.is_discard
                else:
                    assert not packet.is_discard

    def test_is_disposable(self) -> None:
        with av.open(fate_suite("hap/HAPQA_NoSnappy_127x1.mov")) as container:
            stream = container.streams.video[0]
            for i, packet in enumerate(container.demux(stream)):
                if i == 0:
                    assert packet.is_disposable
                else:
                    assert not packet.is_disposable

    def test_set_duration(self) -> None:
        with av.open(fate_suite("h264/interlaced_crop.mp4")) as container:
            for packet in container.demux():
                assert packet.duration is not None
                old_duration = packet.duration
                packet.duration += 10

                assert packet.duration == old_duration + 10


class TestPacketSideData:
    def test_data_types(self) -> None:
        dtypes = get_args(av.packet.PktSideDataT)

        if av.ffmpeg_version_info.startswith("n") or av.ffmpeg_version_info.count(
            "."
        ) not in (1, 2):
            raise SkipTest(f"Expect version to be SemVar: {av.ffmpeg_version_info}")

        ffmpeg_ver = [int(v) for v in av.ffmpeg_version_info.split(".", 2)[:2]]
        for dtype in dtypes:
            av_enum = av.packet.packet_sidedata_type_from_literal(dtype)
            assert dtype == av.packet.packet_sidedata_type_to_literal(av_enum)

            if (ffmpeg_ver[0] < 8 and dtype == "lcevc") or (
                ffmpeg_ver[0] < 9 and dtype == "rtcp_sr"
            ):
                break

    def test_iter(self) -> None:
        with av.open(fate_suite("h264/extradata-reload-multi-stsd.mov")) as container:
            for pkt in container.demux():
                for sdata in pkt.iter_sidedata():
                    assert pkt.dts == 2 and sdata.data_type == "new_extradata"

    def test_palette(self) -> None:
        with av.open(fate_suite("h264/extradata-reload-multi-stsd.mov")) as container:
            iterpackets = container.demux()
            pkt = next(pkt for pkt in iterpackets if pkt.has_sidedata("new_extradata"))

            sdata = pkt.get_sidedata("new_extradata")
            assert sdata.data_type == "new_extradata"
            assert bool(sdata)
            assert sdata.data_size > 0
            assert sdata.data_desc == "New Extradata"

            nxt = next(iterpackets)  # has no palette

            assert not nxt.has_sidedata("new_extradata")

            sdata1 = nxt.get_sidedata("new_extradata")
            assert sdata1.data_type == "new_extradata"
            assert not bool(sdata1)
            assert sdata1.data_size == 0

            nxt.set_sidedata(sdata, move=True)
            assert not bool(sdata)

    def test_buffer_protocol(self) -> None:
        with av.open(fate_suite("h264/extradata-reload-multi-stsd.mov")) as container:
            for pkt in container.demux():
                if pkt.has_sidedata("new_extradata"):
                    sdata = pkt.get_sidedata("new_extradata")

                    raw = bytes(sdata)
                    assert len(raw) == sdata.data_size > 0
                    assert sdata.buffer_size == sdata.data_size
                    assert sdata.buffer_ptr != 0
                    assert bytes(memoryview(sdata)) == raw

                    # Modify and verify changes stick
                    sdata.update(b"\xde\xad\xbe\xef" + raw[4:])
                    assert bytes(sdata)[:4] == b"\xde\xad\xbe\xef"

                    pkt.set_sidedata(sdata)
                    assert (
                        bytes(pkt.get_sidedata("new_extradata"))[:4]
                        == b"\xde\xad\xbe\xef"
                    )
                    return

        raise AssertionError("No packet with new_extradata side data found")

    def test_skip_samples_remux(self) -> None:
        # Source file has skip_end=706 on last packet. Setting to 0 should
        # result in 706 more decoded samples. And the file duration reported by
        # the container should also increase.
        output_path = sandboxed("skip_samples_modified.mkv")

        with av.open(fate_suite("mkv/codec_delay_opus.mkv")) as c:
            original_samples = sum(f.samples for f in c.decode(c.streams.audio[0]))

        with av.open(fate_suite("mkv/codec_delay_opus.mkv")) as inp:
            original_duration = inp.duration
            audio_stream = inp.streams.audio[0]
            with av.open(output_path, "w") as out:
                out_stream = out.add_stream_from_template(audio_stream)
                for pkt in inp.demux(audio_stream):
                    if pkt.dts is None:
                        continue
                    if pkt.has_sidedata("skip_samples"):
                        sdata = pkt.get_sidedata("skip_samples")
                        raw = bytes(sdata)
                        skip_end = struct.unpack("<I", raw[4:8])[0]
                        assert skip_end == 706
                        sdata.update(raw[:4] + struct.pack("<I", 0) + raw[8:])
                        pkt.set_sidedata(sdata)
                    pkt.stream = out_stream
                    out.mux(pkt)

        with av.open(output_path) as c:
            modified_samples = sum(f.samples for f in c.decode(c.streams.audio[0]))
            modified_duration = c.duration

        assert modified_samples - original_samples == 706

        assert original_duration is not None
        assert modified_duration is not None
        assert modified_duration > original_duration