|
| 1 | +import struct |
1 | 2 | from typing import get_args |
2 | 3 | from unittest import SkipTest |
3 | 4 |
|
4 | 5 | import av |
5 | 6 |
|
6 | | -from .common import fate_suite |
| 7 | +from .common import fate_suite, sandboxed |
7 | 8 |
|
8 | 9 |
|
9 | 10 | class TestProperties: |
@@ -100,3 +101,65 @@ def test_palette(self) -> None: |
100 | 101 |
|
101 | 102 | nxt.set_sidedata(sdata, move=True) |
102 | 103 | assert not bool(sdata) |
| 104 | + |
| 105 | + def test_buffer_protocol(self) -> None: |
| 106 | + with av.open(fate_suite("h264/extradata-reload-multi-stsd.mov")) as container: |
| 107 | + for pkt in container.demux(): |
| 108 | + if pkt.has_sidedata("new_extradata"): |
| 109 | + sdata = pkt.get_sidedata("new_extradata") |
| 110 | + |
| 111 | + raw = bytes(sdata) |
| 112 | + assert len(raw) == sdata.data_size > 0 |
| 113 | + assert sdata.buffer_size == sdata.data_size |
| 114 | + assert sdata.buffer_ptr != 0 |
| 115 | + assert bytes(memoryview(sdata)) == raw |
| 116 | + |
| 117 | + # Modify and verify changes stick |
| 118 | + sdata.update(b"\xde\xad\xbe\xef" + raw[4:]) |
| 119 | + assert bytes(sdata)[:4] == b"\xde\xad\xbe\xef" |
| 120 | + |
| 121 | + pkt.set_sidedata(sdata) |
| 122 | + assert ( |
| 123 | + bytes(pkt.get_sidedata("new_extradata"))[:4] |
| 124 | + == b"\xde\xad\xbe\xef" |
| 125 | + ) |
| 126 | + return |
| 127 | + |
| 128 | + raise AssertionError("No packet with new_extradata side data found") |
| 129 | + |
| 130 | + def test_skip_samples_remux(self) -> None: |
| 131 | + # Source file has skip_end=706 on last packet. Setting to 0 should |
| 132 | + # result in 706 more decoded samples. And the file duration reported by |
| 133 | + # the container should also increase. |
| 134 | + output_path = sandboxed("skip_samples_modified.mkv") |
| 135 | + |
| 136 | + with av.open(fate_suite("mkv/codec_delay_opus.mkv")) as c: |
| 137 | + original_samples = sum(f.samples for f in c.decode(c.streams.audio[0])) |
| 138 | + |
| 139 | + with av.open(fate_suite("mkv/codec_delay_opus.mkv")) as inp: |
| 140 | + original_duration = inp.duration |
| 141 | + audio_stream = inp.streams.audio[0] |
| 142 | + with av.open(output_path, "w") as out: |
| 143 | + out_stream = out.add_stream_from_template(audio_stream) |
| 144 | + for pkt in inp.demux(audio_stream): |
| 145 | + if pkt.dts is None: |
| 146 | + continue |
| 147 | + if pkt.has_sidedata("skip_samples"): |
| 148 | + sdata = pkt.get_sidedata("skip_samples") |
| 149 | + raw = bytes(sdata) |
| 150 | + skip_end = struct.unpack("<I", raw[4:8])[0] |
| 151 | + assert skip_end == 706 |
| 152 | + sdata.update(raw[:4] + struct.pack("<I", 0) + raw[8:]) |
| 153 | + pkt.set_sidedata(sdata) |
| 154 | + pkt.stream = out_stream |
| 155 | + out.mux(pkt) |
| 156 | + |
| 157 | + with av.open(output_path) as c: |
| 158 | + modified_samples = sum(f.samples for f in c.decode(c.streams.audio[0])) |
| 159 | + modified_duration = c.duration |
| 160 | + |
| 161 | + assert modified_samples - original_samples == 706 |
| 162 | + |
| 163 | + assert original_duration is not None |
| 164 | + assert modified_duration is not None |
| 165 | + assert modified_duration > original_duration |
0 commit comments