[英]Is there a way to calculate the output frame dimensions when compressing a video and extracting its frames with ffmpeg
我使用以下代碼壓縮視頻並提取其幀。 請注意,我不想保存生成的視頻。
output_args = {
"vcodec": "libx265",
"crf": 24,
}
out, err = (
ffmpeg
.input(in_filename)
.output('pipe:', format='rawvideo', pix_fmt='rgb24',**output_args)
.run(capture_stdout=True)
)
frames = np.frombuffer(out, np.uint8).reshape(-1,width,height,3)
當我嘗試將輸出緩沖區重塑為原始視頻尺寸時,我收到以下錯誤: cannot reshape array of size 436567 into shape (1920,1080,3)
這是預期的,因為生成的視頻尺寸較小。 有沒有辦法計算壓縮視頻的幀數、寬度和高度,以便從緩沖區重塑幀?
此外,如果我保存壓縮視頻,而不是加載其幀,然后我從壓縮視頻加載視頻幀,這些將具有與原始視頻相同的尺寸。 我懷疑在引擎蓋下發生了某種插值。 有沒有辦法在不保存視頻的情況下應用它?
我找到了一個使用ffmpeg-python的解決方案。
假設:
out
將整個 h265 編碼流保存在內存緩沖區中。該解決方案適用於以下內容:
FFmpeg
,以sdtin
作為輸入pipe
, stdout
作為輸出pipe
。pipe
(到stdin
)。cv2.imshow
) 為了測試解決方案,我創建了一個示例視頻文件,並將其讀入內存緩沖區(編碼為 H.265)。
我使用內存緩沖區作為上述代碼的輸入(你的out
緩沖區)。
這是完整的代碼,包括測試代碼:
import ffmpeg
import numpy as np
import cv2
import io
in_filename = 'in.mp4'
# Build synthetic video, for testing begins:
###############################################
# ffmpeg -y -r 10 -f lavfi -i testsrc=size=192x108:rate=1 -c:v libx265 -crf 24 -t 5 in.mp4
width, height = 192, 108
(
ffmpeg
.input('testsrc=size={}x{}:rate=1'.format(width, height), r=10, f='lavfi')
.output(in_filename, vcodec='libx265', crf=24, t=5)
.overwrite_output()
.run()
)
###############################################
# Use ffprobe to get video frames resolution
###############################################
p = ffmpeg.probe(in_filename, select_streams='v');
width = p['streams'][0]['width']
height = p['streams'][0]['height']
n_frames = int(p['streams'][0]['nb_frames'])
###############################################
# Stream the entire video as one large array of bytes
###############################################
# https://github.com/kkroening/ffmpeg-python/blob/master/examples/README.md
in_bytes, _ = (
ffmpeg
.input(in_filename)
.video # Video only (no audio).
.output('pipe:', format='hevc', crf=24)
.run(capture_stdout=True) # Run asynchronous, and stream to stdout
)
###############################################
# Open In-memory binary streams
stream = io.BytesIO(in_bytes)
# Execute FFmpeg in a subprocess with sdtin as input pipe and stdout as output pipe
# The input is going to be the video stream (memory buffer)
# The output format is raw video frames in BGR pixel format.
# https://github.com/kkroening/ffmpeg-python/blob/master/examples/README.md
# https://github.com/kkroening/ffmpeg-python/issues/156
# http://zulko.github.io/blog/2013/09/27/read-and-write-video-frames-in-python-using-ffmpeg/
process = (
ffmpeg
.input('pipe:', format='hevc')
.video
.output('pipe:', format='rawvideo', pix_fmt='bgr24')
.run_async(pipe_stdin=True, pipe_stdout=True)
)
# https://stackoverflow.com/questions/20321116/can-i-pipe-a-io-bytesio-stream-to-subprocess-popen-in-python
# https://gist.github.com/waylan/2353749
process.stdin.write(stream.getvalue()) # Write stream content to the pipe
process.stdin.close() # close stdin (flush and send EOF)
# Read decoded video (frame by frame), and display each frame (using cv2.imshow)
while(True):
# Read raw video frame from stdout as bytes array.
in_bytes = process.stdout.read(width * height * 3)
if not in_bytes:
break
# transform the byte read into a numpy array
in_frame = (
np
.frombuffer(in_bytes, np.uint8)
.reshape([height, width, 3])
)
# Display the frame
cv2.imshow('in_frame', in_frame)
if cv2.waitKey(100) & 0xFF == ord('q'):
break
process.wait()
cv2.destroyAllWindows()
注意:我使用stdin
和stdout
而不是名稱管道,因為我希望代碼在 Windows 和 Linux 中都可以運行。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.