基于Python的pyAV读取H265(HEVC)编码的视频文件

编程入门 行业动态 更新时间:2024-10-26 08:26:27

基于Python的pyAV读取H265(HEVC)编码的<a href=https://www.elefans.com/category/jswz/34/1762933.html style=视频文件"/>

基于Python的pyAV读取H265(HEVC)编码的视频文件

1.问题出现        

        利用海康威视相机拍出来的视频是H265格式的,相比于常规的H264编码,压缩率更高,但因此如果直接用之前的方法读取,会出现无法读取的情况,如下。

        可以看到,对于帧间没有改变的部分,H265编码就只保存一份,因此直接解析出来就都是空白的,只保存了当前帧中运动(不同的部分)。这样的话,采用常规的OpenCV读取视频的方式就行不通了。因此本篇博客主要介绍另一种更“专业”的视频读取方法:利用PyAV读取视频。另外也对之前的OpenCV读取视频文件代码进行了优化,效率会高很多。具体来说就是直接使用get()函数根据索引直接获取到指定帧即可,而不再需要逐帧遍历。

2.PyAV简介与安装

        简单来说,PyAV是对FFmpeg的Python封装,集成了FFmpeg的全部功能,使用起来十分方便。如果对视频处理稍微有点了解的话,应该听过FFmpeg,官网是这里,它是一个跨平台的多媒体处理工具,很多一些小的视频播放器都是基于它开发的。PyAV的官网是这里。相比于前面提到的OpenCV,它是一个专门用来处理视频的库,因此各种功能十分专业,包括转码、读取音频等。它的安装也十分简单,pip即可。

pip install av

        对,它的简写就是av,安装好以后就可以愉快地写代码了。

3.H265视频读取代码

        利用PyAV读取H265视频文件的核心代码如下。

import avif __name__ == '__main__':video_path = "./D01_20201011131153.mp4"out_path = "./frames"frame_interval = 500container = av.open(video_path)# 获取要提取的视频流对象stream = container.streams.video[0]fps = stream.base_rate  # 帧率frame_width = stream.width  # 帧宽frame_height = stream.height  # 帧高total_time_in_second = stream.duration * 1.0 * stream.time_base  # 视频总长total_frame = int(total_time_in_second * fps) + 1  # 视频总帧数iter_time = int(total_frame / frame_interval) + 1  # 需要迭代的次数print('Total time in second:', round(total_time_in_second, 3))counter = 0frame_indices = []for frame in container.decode(video=0):if frame.index % frame_interval == 0:counter += 1frame_indices.append(frame.index)print(counter, '/', iter_time)# to_image()函数返回的其实是PIL类型的影像,因此,这里的save()函数其实是PIL的Image类型的成员函数,和PyAV无关# 因此,如果需要修改什么保存相关设置的话,按照PIL的API进行frame.to_image().save(out_path + "/frame-%05d.jpg" % frame.index)fout = open(out_path + "/summary.txt", 'w')fout.write("Video name:" + video_path + "\n")fout.write("Frames in total:" + total_frame.__str__() + "\n")fout.write("FPS:" + fps.__str__() + "\n")fout.write("Seconds in total:" + round(total_time_in_second, 3).__str__() + "\n")fout.write("Frame width:" + frame_width.__str__() + "\n")fout.write("Frame height:" + frame_height.__str__() + "\n")fout.write("Output frame number:" + iter_time.__str__() + "\n")for i in range(len(frame_indices)):fout.write(frame_indices[i].__str__() + "\t" + round(frame_indices[i] * 1.0 / fps, 3).__str__() + "\n")fout.close()print("\n==========Summary Info==========")print('Frames in total:', total_frame)print('FPS:', fps)print('Frame width:', frame_width)print('Frame height', frame_height)print("Output frame number:", len(frame_indices))

        输出的帧如下。

        除了输出的帧影像,还会保存输出的每一帧所对应的时间,方便其它后续应用。当然,如果仔细研究的话可以看到,这里其实还是非常简单粗暴地读取每一帧,然后选择指定帧保存。因为目前我并不知道如何根据索引来定位某一帧,因此只能用这样的办法了。如果以后了解的话,会及时更新。

4.优化版OpenCV代码

        把之前循环遍历的步骤简化了,这样就不用逐帧读取,直接获取指定位置的帧内容就好了。

import cv2if __name__ == '__main__':video_path = "./D01_20201011131153.mp4"out_path = "./frames"out_type = ".jpg"time_interval = 50cap = cv2.VideoCapture(video_path)frames = int(cap.get(7))fps = int(cap.get(5))video_width = int(cap.get(3))video_height = int(cap.get(4))frame_interval = time_interval * fpstotal_number = int(round(frames / frame_interval, 0))frame_indices = []for i in range(0, frames, frame_interval):cap.set(cv2.CAP_PROP_POS_FRAMES, i)ret, frame = cap.read()print('Total frame number:' + total_number.__str__(), ', complete', round((i * 1.0 / frames) * 100, 3), '%')cv2.imwrite(out_path + "/frame_" + i.__str__().zfill(5) + out_type, frame)frame_indices.append(i)cap.release()fout = open(out_path + "/summary.txt", 'w')fout.write("Video name:" + video_path + "\n")fout.write("Frames in total:" + frames.__str__() + "\n")fout.write("FPS:" + fps.__str__() + "\n")fout.write("Seconds in total:" + round(frames * 1.0 / fps, 3).__str__() + "\n")fout.write("Frame width:" + video_width.__str__() + "\n")fout.write("Frame height:" + video_height.__str__() + "\n")fout.write("Output frame number:" + len(frame_indices).__str__() + "\n")for i in range(len(frame_indices)):fout.write(frame_indices[i].__str__() + "\t" + round(frame_indices[i] * 1.0 / fps, 3).__str__() + "\n")fout.close()print("\n==========Summary Info==========")print('Frames in total:', frames)print('FPS:', fps)print('Frame width:', video_width)print('Frame height', video_height)print("Output frame number:", len(frame_indices))

更多推荐

基于Python的pyAV读取H265(HEVC)编码的视频文件

本文发布于:2023-11-15 12:58:34,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1600054.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:视频文件   pyAV   Python   HEVC

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!