Skip to content

Commit 98e7c9f

Browse files
committed
Merge branch 'master' of github.com:imageio/imageio-ffmpeg
2 parents 6d0aebe + 995cada commit 98e7c9f

File tree

5 files changed

+59
-2
lines changed

5 files changed

+59
-2
lines changed

README.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,8 @@ def write_frames(
169169
ffmpeg_timeout=0,
170170
input_params=None,
171171
output_params=None,
172+
audio_path=None,
173+
audio_codec=None,
172174
):
173175
"""
174176
Create a generator to write frames (bytes objects) into a video file.
@@ -205,6 +207,8 @@ def write_frames(
205207
ffmpeg needs depends on CPU speed, compression, and frame size.
206208
input_params (list): Additional ffmpeg input command line parameters.
207209
output_params (list): Additional ffmpeg output command line parameters.
210+
audio_path (str): A input file path for encoding with an audio stream.
211+
audio_codec (str): The audio codec to use if audio_path is provided.
208212
"""
209213
```
210214

imageio_ffmpeg/_definitions.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ def get_platform():
88
bits = struct.calcsize("P") * 8
99
if sys.platform.startswith("linux"):
1010
return "linux{}".format(bits)
11+
elif sys.platform.startswith("freebsd"):
12+
return "freebsd{}".format(bits)
1113
elif sys.platform.startswith("win"):
1214
return "win{}".format(bits)
1315
elif sys.platform.startswith("cygwin"):
@@ -33,13 +35,15 @@ def get_platform():
3335
"win64": "ffmpeg-win64-v4.2.2.exe",
3436
# "linux32": "ffmpeg-linux32-v4.2.2",
3537
"linux64": "ffmpeg-linux64-v4.2.2", # Kernel 3.2.0+
38+
"linuxaarch64": "ffmpeg-linuxaarch64-v4.2.2",
3639
}
3740

3841
osxplats = "macosx_10_9_intel.macosx_10_9_x86_64.macosx_10_10_intel.macosx_10_10_x86_64"
3942

4043
# Wheel tag -> platform string
4144
WHEEL_BUILDS = {
4245
"py3-none-manylinux2010_x86_64": "linux64",
46+
"py3-none-manylinux2014_aarch64": "linuxaarch64",
4347
"py3-none-" + osxplats: "osx64",
4448
"py3-none-win32": "win32",
4549
"py3-none-win_amd64": "win64",

imageio_ffmpeg/_io.py

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -276,6 +276,8 @@ def write_frames(
276276
ffmpeg_timeout=None,
277277
input_params=None,
278278
output_params=None,
279+
audio_path=None,
280+
audio_codec=None,
279281
):
280282
"""
281283
Create a generator to write frames (bytes objects) into a video file.
@@ -312,6 +314,11 @@ def write_frames(
312314
ffmpeg needs depends on CPU speed, compression, and frame size.
313315
input_params (list): Additional ffmpeg input command line parameters.
314316
output_params (list): Additional ffmpeg output command line parameters.
317+
audio_path (str): A input file path for encoding with an audio stream.
318+
Default None, no audio.
319+
audio_codec (str): The audio codec to use if audio_path is provided.
320+
"copy" will try to use audio_path's audio codec without re-encoding.
321+
Default None, but some formats must have certain codecs specified.
315322
"""
316323

317324
# ----- Input args
@@ -373,11 +380,18 @@ def write_frames(
373380
default_codec = "msmpeg4"
374381
codec = codec or default_codec
375382

383+
audio_params = ["-an"]
384+
if audio_path is not None and not path.lower().endswith(".gif"):
385+
audio_params = ["-i", audio_path]
386+
if audio_codec is not None:
387+
output_params += ["-acodec", audio_codec]
388+
output_params += ["-map", "0:v:0", "-map", "1:a:0"]
389+
376390
# Get command
377391
cmd = [_get_exe(), "-y", "-f", "rawvideo", "-vcodec", "rawvideo", "-s", sizestr]
378392
cmd += ["-pix_fmt", pix_fmt_in, "-r", "{:.02f}".format(fps)] + input_params
379-
cmd += ["-i", "-"]
380-
cmd += ["-an", "-vcodec", codec, "-pix_fmt", pix_fmt_out]
393+
cmd += ["-i", "-"] + audio_params
394+
cmd += ["-vcodec", codec, "-pix_fmt", pix_fmt_out]
381395

382396
# Add fixed bitrate or variable bitrate compression flags
383397
if bitrate is not None:

imageio_ffmpeg/_parsing.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,17 @@ def parse_ffmpeg_header(text):
130130
meta["codec"] = line.split("Video: ", 1)[-1].lstrip().split(" ", 1)[0].strip()
131131
meta["pix_fmt"] = line.split("Video: ", 1)[-1].split(",")[1].strip()
132132

133+
# get the output line that speaks about audio
134+
audiolines = [
135+
l for l in lines if l.lstrip().startswith("Stream ") and " Audio: " in l
136+
]
137+
138+
if len(audiolines) > 0:
139+
audio_line = audiolines[0]
140+
meta["audio_codec"] = (
141+
audio_line.split("Audio: ", 1)[-1].lstrip().split(" ", 1)[0].strip()
142+
)
143+
133144
# get the frame rate.
134145
# matches can be empty, see #171, assume nframes = inf
135146
# the regexp omits values of "1k tbr" which seems a specific edge-case #262

tests/test_io.py

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -349,6 +349,29 @@ def _write_frames(pixfmt, bpp, tout):
349349
assert nframes == n
350350

351351

352+
@no_warnings_allowed
353+
def test_write_audio_path():
354+
# Provide an audio
355+
356+
gen = imageio_ffmpeg.write_frames(
357+
test_file2, (64, 64), audio_path=test_file3, audio_codec="aac"
358+
)
359+
gen.send(None) # seed
360+
for i in range(9):
361+
data = bytes([min(255, 100 + i * 10)] * 64 * 64 * 3)
362+
gen.send(data)
363+
gen.close()
364+
# Check nframes
365+
nframes, nsecs = imageio_ffmpeg.count_frames_and_secs(test_file2)
366+
assert nframes == 9
367+
# Check size
368+
meta = imageio_ffmpeg.read_frames(test_file2).__next__()
369+
audio_codec = meta["audio_codec"]
370+
371+
assert nframes == 9
372+
assert audio_codec == "aac"
373+
374+
352375
if __name__ == "__main__":
353376
setup_module()
354377
test_ffmpeg_version()
@@ -366,3 +389,4 @@ def _write_frames(pixfmt, bpp, tout):
366389
test_write_bitrate()
367390
test_write_macro_block_size()
368391
test_write_big_frames()
392+
test_write_audio_path()

0 commit comments

Comments
 (0)