python处理字节流形式的视频

python处理内存中字节流形式的视频

在使用python的streamlit库处理上传的文件时碰到一个问题,文件上传后是以字节数组的形式存在内存中,我在后续需要使用cv2库逐帧操作上传的视频,这里就产生一个问题,cv2怎么读取到内存中字节形式的视频?
经过多次查找,发现可以使用ffmpeg从内存中将字节流解码,然后再由cv2处理。

代码如下:

import streamlit as st
# streamlit中上传文件的函数
@st.cache(allow_output_mutation=True,show_spinner=False)
def load_local_video(uploaded_video):
    bytes_data = uploaded_video.getvalue()  
    print(uploaded_video.name)
    
    return bytes_data    
    
uploaded_video = st.sidebar.file_uploader(" ")
video = load_local_video(uploaded_video)

处理逻辑就是使用ffprobe获取字节流中内存相关信息,然后使用ffmpeg解码。随后从字节流中逐帧获取视频。

import numpy as np
import cv2
import io
import subprocess as sp
import threading
import json
from functools import partial
import shlex

# Write to stdin in chunks of 1024 bytes.
def writer(stream,process):
    for chunk in iter(partial(stream.read, 1024),b''):
        process.stdin.write(chunk)
    try:
        process.stdin.close()
    except (BrokenPipeError):
        pass  # For unknown reason there is a Broken Pipe Error when executing FFprobe.


def do(video):
    
    bytes_stream = io.BytesIO(video)
        
    #执行子进程并定到输入输出的接口,这里使用ffprobe检测视频的信息
    # 注意,这里的路径是我本地的路径,运行代码的时候需要更改路径,并且确保你的电脑装上了ffmpeg
    process = sp.Popen(shlex.split('E:/ffmpeg-4.3.1-2020-11-19-essentials_build/bin/ffprobe -v error -i pipe: -select_streams v -print_format json -show_streams'), stdin=sp.PIPE, stdout=sp.PIPE, bufsize=10**8)

    pthread = threading.Thread(target=writer,args=(bytes_stream,process))
    pthread.start()
        
    pthread.join()
    
    #从标准输入输出流中获取视频信息
    in_bytes = process.stdout.read()

    process.wait()
        
    p = json.loads(in_bytes)
    
    #得到视频的分辨率         
    width = (p['streams'][0])['width']
    height = (p['streams'][0])['height']
    
    bytes_stream.seek(0)
    
    process = sp.Popen(shlex.split('E:/ffmpeg-4.3.1-2020-11-19-essentials_build/bin/ffmpeg -i pipe: -f rawvideo -pix_fmt bgr24 -an -sn pipe:'), stdin=sp.PIPE, stdout=sp.PIPE, bufsize=10**8)

    thread = threading.Thread(target=writer,args=(bytes_stream,process))
    thread.start()
    
    #将视频解码完毕
         
    all_bytes = process.stdout.read()#将视频字节从内存中读取出来
    counter = len(all_bytes)/(width * height * 3)
    #print(str(counter)+' 帧')
    l = 0
    my_bar = st.progress(0)
    with st.spinner(text="视频检测中"):
        while l < counter:
            in_bytes = all_bytes[:width * height * 3]
            all_bytes = all_bytes[width * height * 3:]
            
            if not in_bytes:
                break  # Break loop if no more bytes.
            
            # Transform the byte read into a NumPy array
            in_frame = (np.frombuffer(in_bytes, np.uint8).reshape([height, width, 3]))
            #完成视频逐帧获取,可以使用cv2操作in_frame图像
            # TODO
            l = l+1

我需要逐帧解析视频并完成相对应的操作,以上操作就可以做到了。但是需要注意,此处代码并没有针对帧率处理。

文章参考:
https://stackoverflow.com/questions/60558412/how-to-decode-a-video-memory-file-byte-string-and-step-through-it-frame-by-f

你可能感兴趣的:(python,视频处理)