Fixture for tests which run against different input videos.
| 137 | |
| 138 | @pytest.mark.parametrize("test_video", get_test_video_params()) |
| 139 | class TestVideoStream: |
| 140 | """Fixture for tests which run against different input videos.""" |
| 141 | |
| 142 | def test_properties(self, vs_type: ty.Callable[..., VideoStream], test_video: VideoParameters): |
| 143 | """Validate video properties: frame size, frame rate, duration, aspect ratio, etc.""" |
| 144 | stream = vs_type(test_video.path) |
| 145 | assert stream.frame_size == (test_video.width, test_video.height) |
| 146 | assert stream.frame_rate == pytest.approx(test_video.frame_rate, FRAMERATE_TOLERANCE) |
| 147 | assert stream.duration is not None |
| 148 | assert stream.duration.frame_num == test_video.total_frames |
| 149 | file_name = os.path.basename(test_video.path) |
| 150 | last_dot_pos = file_name.rfind(".") |
| 151 | assert stream.name == file_name[:last_dot_pos] |
| 152 | assert stream.aspect_ratio == pytest.approx( |
| 153 | test_video.aspect_ratio, PIXEL_ASPECT_RATIO_TOLERANCE |
| 154 | ) |
| 155 | |
| 156 | def test_read(self, vs_type: ty.Callable[..., VideoStream], test_video: VideoParameters): |
| 157 | """Validate basic `read` functionality.""" |
| 158 | stream = vs_type(test_video.path) |
| 159 | frame = stream.read() |
| 160 | assert isinstance(frame, numpy.ndarray) |
| 161 | # For now hard-code 3 channels/pixel for each test video |
| 162 | assert frame.shape == (test_video.height, test_video.width, 3) |
| 163 | assert stream.frame_number == 1 |
| 164 | |
| 165 | def test_read_no_decode( |
| 166 | self, vs_type: ty.Callable[..., VideoStream], test_video: VideoParameters |
| 167 | ): |
| 168 | """Validate invoking `read` with `decode` set to False.""" |
| 169 | stream = vs_type(test_video.path) |
| 170 | assert stream.read(decode=False) is True |
| 171 | assert stream.frame_number == 1 |
| 172 | |
| 173 | def test_time_invariants( |
| 174 | self, vs_type: ty.Callable[..., VideoStream], test_video: VideoParameters |
| 175 | ): |
| 176 | """Validate the `frame_number`, `position`, and `position_ms` properties.""" |
| 177 | stream = vs_type(test_video.path) |
| 178 | # The video starts "before" the first frame, with everything set to zero. |
| 179 | assert stream.frame_number == 0 |
| 180 | assert stream.position == stream.base_timecode |
| 181 | assert stream.position_ms == pytest.approx(0.0, abs=TIME_TOLERANCE_MS) |
| 182 | # Read the first frame (frame number 1). |
| 183 | assert stream.read() is not False |
| 184 | assert stream.frame_number == 1 |
| 185 | # The `position`/`position_ms` properties represent the presentation time, so they |
| 186 | # should still be zero for the first frame. |
| 187 | assert stream.position == stream.base_timecode |
| 188 | assert stream.position_ms == pytest.approx(0.0, abs=TIME_TOLERANCE_MS) |
| 189 | # Test that the invariants hold for the first few frames. |
| 190 | for i in range(2, 10): |
| 191 | assert stream.read() is not False |
| 192 | assert stream.frame_number == i |
| 193 | assert stream.position == stream.base_timecode + (i - 1) |
| 194 | assert stream.position_ms == pytest.approx( |
| 195 | 1000.0 * (i - 1) / float(stream.frame_rate), abs=TIME_TOLERANCE_MS |
| 196 | ) |
nothing calls this directly
no outgoing calls
no test coverage detected