视频流解码方法

视频流解码方法:
opencv解码、ffmpeg解码、DeFFcode解码
使用前:需要安装opencv-python、ffmpeg-python、DeFFcode等库

1、opencv解码视频流

#导入opencv库
import cv2 as cv
video_path = "video.mp4"  # 读取视频路径
#解码前,使用cv.VideoCapture打开视频文件,并创建一个视频对象
capture = cv.VideoCapture(video_path) 
 
#查看视频文件的宽、高、帧数率以及总帧数
width = int(capture.get(cv.CAP_PROP_FRAME_WIDTH))  # 360
height = int(capture.get(cv.CAP_PROP_FRAME_HEIGHT))  # 480
fps = round(capture.get(cv.CAP_PROP_FPS))  # 30
frameCount = int(capture.get(cv.CAP_PROP_FRAME_COUNT))  # 2313
print(height, width, fps, frameCount)

# 创建写入的视频对象(读取视频,并保存成新的视频)
# fourcc = cv.VideoWriter_fourcc('X', 'V', 'I', 'D')  # 编码器设置 XVID
fourcc = cv.VideoWriter_fourcc(*'XVID')  # 'X','V','I','D' 简写为 *'XVID'
vedioWrite = "video_1.avi"  # 写入视频文件的路径
capWrite = cv.VideoWriter(vedioWrite, fourcc, fps, (width, height), True)

frame_count = 0  #视频帧数初值
timed = 231  #抽帧间隔
timed_1=12   #抽帧间隔
#检查读取是否成功
while capture.isOpened():
	#使用read方法逐帧解码,每次返回两个值:读取是否成功的bool值,一个表示当前帧数据的numpy数组
    ret, frame = capture.read()  # 读取一帧
    if not ret:
        break
    if frame:
	    frame_count += 1
	 	#解码后的帧数据,是以numpy数组的形式呈现的
	    # 设置保存路径和文件名(可以根据需要进行更改)
	    # 为你的图片取名格式化
	    save_path = "save/{}.jpg".format(frame_count)
	    
	    #抽帧条件,并保存一帧为一张图片
	    if(frame_count%timed==0):
	        cv.imwrite(save_path, frame)   
	    #抽帧条件,并把当前帧写入到新的视频文件对象
	    if (frame_count%timed_1==0):
	        capWrite.write(frame)
	    if cv.waitKey(10) & 0xFF == ord('q'):  # 按 'q' 退出
	            break
	 else:
	 	print("Can't receive frame at frameNum {}".format(frame_count))
        break
 
capture.release()  # 关闭读取视频文件
capWrite.release()  # 关闭视频写入对象
cv.destroyAllWindows()  # 关闭显示窗口

2、ffmpeg解码视频流

import ffmpeg
video_path = 'video.mp4'
# 获取视频的详细信息,编码格式,名字,尺寸...
probe = ffmpeg.probe(video_path)
video_stream = next((stream for stream in probe['streams'] if stream['codec_type'] == 'video'), None)
# 获取视频持续时间
duration = float(video_stream['duration'])
# 视频解码
out, _ = (
ffmpeg
.input(video_path)
.output('pipe:', format='rawvideo', pix_fmt='rgb24')
.run(capture_stdout=True)
)
video = (
np
.frombuffer(out, np.uint8)
.reshape([-1, video_stream['height'], video_stream['width'], 3])
)

针对ffmpeg解码视频流,可以通过ffmpeg.probe得到视频的信息。通过以下代码得到视频每个字段的信息。

info = ffmpeg.probe(str(file))
vs = next(c for c in info['streams'] if c['codec_type'] == 'video')
duration_secs = float(vs['duration'])
format = info['format']['format_name']
codec_name = vs['codec_name']
width = vs['width']
height = vs['height']
num_frames = vs['nb_frames']

以下ffmpeg部分参考:https://cloud.tencent.com/developer/article/1568673
ffmpeg对视频流不同处理:

import ffmpeg
# 全抽帧
def get_frames():
    input_file = '/Users/didi/Desktop/ffmpeg/test.mp4'
    output_file = '/Users/didi/Desktop/ffmpeg/image/image-%5d.jpg'
    out, err = (
        ffmpeg
            .input(input_file)
            .output(output_file)
            .run(quiet=False, overwrite_output=True)
    )
    if out == b'':
        print('do nothing')


# 按一定的频率抽帧
def get_frames_by_rate():
    input_file = '/Users/didi/Desktop/ffmpeg/test.mp4'
    output_file = '/Users/didi/Desktop/ffmpeg/image/image-%5d.jpg'
    out, err = (
        ffmpeg
            .input(input_file, ss=0)
            # .output(output_file, r='1', f='image2')
            .output(output_file, vf='fps=fps=1', f='image2')
            .run(quiet=False, overwrite_output=True)
    )
    if out == b'':
        print('do nothing')

# 按指定时间片段抽帧
def get_frames_by_times():
    times = [1, 5, 8, 10]
    for time in times:
        input_file = '/Users/didi/Desktop/ffmpeg/test.mp4'
        output_file = '/Users/didi/Desktop/ffmpeg/image/image-' + str(time) + '.jpg'
        out, err = (
            ffmpeg
                .input(input_file, ss=time)
                .output(output_file, vframes='1', f='image2')
                .run(quiet=False, overwrite_output=True)
        )
        if out == b'':
            print('do nothing')

if __name__ == '__main__':
    get_frames_by_rate()
import ffmpeg
# 视频剪切
def cut_videos():
    input_file = '/Users/didi/Desktop/ffmpeg/test.mp4'
    output_file = '/Users/didi/Desktop/ffmpeg/video/video1.mp4'
    out, err = (
        ffmpeg
            # 注意ss,t的单位都是秒
            .input(input_file, ss=220, t=20)
            .output(output_file, codec="copy")
            .run(quiet=False, overwrite_output=True)
    )
    if out == b'':
        print('do nothing')


# 视频合并
def concat_video():
    # 注意:要合并的视频文件和txt文件需要放在同一个目录下
    input_file = '/Users/didi/Desktop/ffmpeg/video/aa.txt'
    output_file = '/Users/didi/Desktop/ffmpeg/video/Cam.mp4'
    try:
        out, err = (
            ffmpeg
                .input(input_file, f='concat')
                .output(output_file, c='copy')
                .run(quiet=False, overwrite_output=True)
        )
    except Exception as e:
        print(e)


if __name__ == '__main__':
    concat_video()
    #cut_videos()

3、DeFFcode解码
DeFFcode核心功能就是利用ffmpeg进行视频解码。(功能还待完善)

# FFedecoder创建视频源和视频解码规则,formulate在ffmpeg中执行语句
# 本地视频
# decoder = FFdecoder("test.mp4").formulate()
# rtsp流
decoder = FFdecoder("rtsp://wowzaec2demo.streamlock.net/vod/mp4:BigBuckBunny_115k.mp4").formulate()
# 从decoder中抓取RGB图像
for frame in decoder.generateFrame():
    print(frame.shape)
    # 将rgb图像转换为bgr图像,送给opencv展示
    frame_bgr = frame[:, :, ::-1]
    cv2.imshow("Output Frame", frame_bgr)
    key = cv2.waitKey(1) & 0xFF
    if key == ord("q"):
        break
# 安全关闭解码进程
decoder.terminate()
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值