簡體   English   中英

有沒有辦法在壓縮視頻並使用 ffmpeg 提取其幀時計算輸出幀尺寸

[英]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作為輸入pipestdout作為輸出pipe
    輸入將是視頻流(內存緩沖區)。
    輸出格式是 BGR 像素格式的原始視頻幀。
  • 將流內容寫入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()

注意:我使用stdinstdout而不是名稱管道,因為我希望代碼在 Windows 和 Linux 中都可以運行。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM