Skip to content

Commit 4017c12

Browse files
committed
Fix up video tests
Ought to spend some time making the test suite a bit more flexible (more env-vars for configuring things, like expected camera revision?)
1 parent 96a8c34 commit 4017c12

File tree

2 files changed

+47
-32
lines changed

2 files changed

+47
-32
lines changed

tests/test_record.py

Lines changed: 35 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -80,11 +80,13 @@ def fin():
8080
request.addfinalizer(fin)
8181
return filename1, filename2, request.param.format, request.param.options
8282

83+
8384
# Run tests with a variety of format specs
8485
@pytest.fixture(params=RECORDING_CASES)
8586
def format_options(request):
8687
return request.param.format, request.param.options
8788

89+
8890
def expected_failures(resolution, format, options):
8991
if resolution == (2592, 1944) and 'resize' not in options:
9092
pytest.xfail('Cannot encode video at max resolution')
@@ -126,6 +128,7 @@ def test_record_to_file(camera, previewing, mode, filenames_format_options):
126128
if verify2:
127129
verify_video(filename2, format, resolution)
128130

131+
129132
def test_record_to_stream(camera, previewing, mode, format_options):
130133
format, options = format_options
131134
resolution, framerate = mode
@@ -157,6 +160,7 @@ def test_record_to_stream(camera, previewing, mode, format_options):
157160
stream2.seek(0)
158161
verify_video(stream2, format, resolution)
159162

163+
160164
def test_record_sequence_to_file(camera, mode, tempdir):
161165
resolution, framerate = mode
162166
expected_failures(resolution, 'h264', {})
@@ -166,6 +170,7 @@ def test_record_sequence_to_file(camera, mode, tempdir):
166170
for filename in filenames:
167171
verify_video(filename, 'h264', resolution)
168172

173+
169174
def test_record_sequence_to_stream(camera, mode):
170175
resolution, framerate = mode
171176
expected_failures(resolution, 'h264', {})
@@ -176,6 +181,7 @@ def test_record_sequence_to_stream(camera, mode):
176181
stream.seek(0)
177182
verify_video(stream, 'h264', resolution)
178183

184+
179185
def test_circular_record(camera, mode):
180186
resolution, framerate = mode
181187
expected_failures(resolution, 'h264', {})
@@ -204,6 +210,7 @@ def test_circular_record(camera, mode):
204210
temp.seek(0)
205211
verify_video(temp, 'h264', resolution)
206212

213+
207214
def test_split_and_capture(camera, mode):
208215
resolution, framerate = mode
209216
expected_failures(resolution, 'h264', {})
@@ -225,6 +232,7 @@ def test_split_and_capture(camera, mode):
225232
verify_video(v_stream1, 'h264', resolution)
226233
verify_video(v_stream2, 'h264', resolution)
227234

235+
228236
def test_multi_res_record(camera, mode):
229237
resolution, framerate = mode
230238
expected_failures(resolution, 'h264', {})
@@ -247,6 +255,7 @@ def test_multi_res_record(camera, mode):
247255
verify_video(v_stream1, 'h264', resolution)
248256
verify_video(v_stream2, 'h264', new_res)
249257

258+
250259
def test_macroblock_limit(camera):
251260
res, fps = camera.resolution, camera.framerate
252261
try:
@@ -258,13 +267,15 @@ def test_macroblock_limit(camera):
258267
camera.resolution = res
259268
camera.framerate = fps
260269

261-
class SizeTest(object):
262-
def __init__(self):
263-
self.size = 0
264-
def write(self, s):
265-
self.size += len(s)
266270

267271
def test_multi_res_record_len(camera, mode):
272+
273+
class SizeTest(object):
274+
def __init__(self):
275+
self.size = 0
276+
def write(self, s):
277+
self.size += len(s)
278+
268279
resolution, framerate = mode
269280
expected_failures(resolution, 'h264', {})
270281
output1 = SizeTest()
@@ -284,17 +295,19 @@ def test_multi_res_record_len(camera, mode):
284295
assert output2.size > 0
285296
assert output1.size > output2.size
286297

287-
class MotionTest(object):
288-
def __init__(self, camera):
289-
width, height = camera.resolution
290-
self.rows = (height + 15) // 16
291-
self.cols = (width + 15) // 16
292-
self.cols += 1
293-
def write(self, s):
294-
assert len(s) == self.cols * self.rows * 4
295-
return len(s)
296298

297299
def test_motion_record(camera, mode):
300+
301+
class MotionTest(object):
302+
def __init__(self, camera):
303+
width, height = camera.resolution
304+
self.rows = (height + 15) // 16
305+
self.cols = (width + 15) // 16
306+
self.cols += 1
307+
def write(self, s):
308+
assert len(s) == self.cols * self.rows * 4
309+
return len(s)
310+
298311
resolution, framerate = mode
299312
expected_failures(resolution, 'h264', {})
300313
camera.start_recording(
@@ -305,6 +318,7 @@ def test_motion_record(camera, mode):
305318
finally:
306319
camera.stop_recording()
307320

321+
308322
def test_record_bad_format(camera):
309323
with pytest.raises(picamera.PiCameraValueError):
310324
camera.start_recording('test.foo')
@@ -315,25 +329,22 @@ def test_record_bad_format(camera):
315329
with pytest.raises(picamera.PiCameraValueError):
316330
camera.start_recording('test.h264', format='mp4')
317331

332+
318333
def test_record_bad_timestamp(camera):
319-
# Frame timestamps should be None or positive integers. Prior to #357
334+
# Frame timestamps should be positive integers in all cases. Prior to #357
320335
# getting fixed a None timestamp (from a 0 PTS) would be followed by a
321336
# large negative timestamp (from an unrecognized TIME_UNKNOWN timestamp)
337+
322338
class Timestamps(object):
323339
def __init__(self, camera):
324340
self.camera = camera
325341
self.timestamps = []
326-
self.none_count = 0
327342
def write(self, buf):
328-
if self.camera.frame.complete:
329-
self.timestamps.append(self.camera.frame.timestamp)
330-
if self.camera.frame.timestamp is None:
331-
self.none_count += 1
343+
self.timestamps.append(self.camera.frame.timestamp)
344+
332345
output = Timestamps(camera)
333346
camera.start_recording(output, 'h264')
334-
while output.none_count < 2:
335-
camera.wait_recording(1)
347+
camera.wait_recording(1)
336348
camera.stop_recording()
337349
for timestamp in output.timestamps:
338-
assert timestamp is None or timestamp >= 0
339-
350+
assert timestamp >= 0

tests/verify.py

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,8 @@
4646
from PIL import Image
4747

4848

49+
FFMPEG = os.environ.get('PICAMERA_FFMPEG', 'ffmpeg')
50+
4951
RAW_FORMATS = {
5052
# name bytes-per-pixel
5153
'yuv': 1.5,
@@ -218,37 +220,39 @@ def verify_video(filename_or_obj, format, resolution):
218220
elif format == 'h264':
219221
if isinstance(filename_or_obj, str):
220222
p = subprocess.Popen([
221-
'avconv',
223+
FFMPEG,
222224
'-f', format,
223225
'-i', filename_or_obj,
224226
], stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
225227
else:
226228
p = subprocess.Popen([
227-
'avconv',
229+
FFMPEG,
228230
'-f', format,
229231
'-i', '-',
230232
], stdin=filename_or_obj, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
231233
out = p.communicate()[0]
232-
assert p.returncode == 1, 'avconv returned unexpected code %d' % p.returncode
234+
assert p.returncode == 1, 'ffmpeg returned unexpected code %d' % p.returncode
233235
state = 'start'
234236
for line in out.splitlines():
235237
line = line.decode('utf-8').strip()
236238
if state == 'start' and re.match(r'^Input #0', line):
237239
state = 'input'
238240
elif state == 'input' and re.match(r'^Duration', line):
239241
state = 'dur'
240-
elif state == 'dur' and re.match(r'^Stream #0\.0', line):
242+
elif state == 'dur' and re.match(r'^Stream #0[.:]0', line):
241243
assert re.match(
242-
r'^Stream #0\.0: '
244+
r'^Stream #0[.:]0: '
243245
r'Video: %s( \(.*\))?, '
244-
r'yuvj?420p, '
246+
r'yuvj?420p(\(progressive\))?, '
245247
r'%dx%d( \[PAR \d+:\d+ DAR \d+:\d+\])?, '
246248
r'\d+ fps(, \d+ tbr)?, \d+k? tbn(, \d+k? tbc)?$' % (
247249
format, width, height),
248250
line
249-
), 'Unexpected avconv output: %s' % line
251+
), 'Unexpected ffmpeg output: %s' % line
250252
return
251-
assert False, 'Failed to locate stream analysis in avconv output'
253+
else:
254+
state = 'start'
255+
assert False, 'Failed to locate stream analysis in ffmpeg output'
252256
else:
253257
assert False, 'Unable to verify format %s' % format
254258

0 commit comments

Comments
 (0)