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

news2024/12/26 11:25:09

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 av

if __name__ == '__main__':
    video_path = "./D01_20201011131153.mp4"
    out_path = "./frames"
    frame_interval = 500

    container = 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 = 0
    frame_indices = []
    for frame in container.decode(video=0):
        if frame.index % frame_interval == 0:
            counter += 1
            frame_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 cv2

if __name__ == '__main__':
    video_path = "./D01_20201011131153.mp4"
    out_path = "./frames"
    out_type = ".jpg"
    time_interval = 50

    cap = 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 * fps

    total_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))

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1193701.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

测试用例怎么样写?怎么搞懂方法和流程?

前言 作为一个测试新人,刚开始接触测试,对于怎么写测试用例很头疼,无法接触需求,只能根据站在用户的角度去做测试,但是这样情况会导致不能全方位的测试APP,这种情况就需要一份测试用例了,但是不…

java学习part01

15-Java语言概述-单行注释和多行注释的使用_哔哩哔哩_bilibili 1.命令行 javac编译出class文件 然后java运行 2. java文件每个文件最多一个public类 3.java注释 单行注释 // 多行注释 文档注释 文档注释内容可以被JDK提供的工具javadoc所解析,生成一套以网页文…

SQLChat 的 RBAC 之旅

去年 ChatGPT 在科技圈大火,到今年彻底破圈。各个领域都有相应的一些产品,数据库领域集中在 AI SQL,自然语言转 SQL,或者利用自然语言来管理数据库等。今天我们来体验一下该领域的 SQLChat 这款 AI 数据库客户端。 今天我们预设一…

C++智能指针的使用:shared_ptr、weak_ptr、unique_ptr的使用,使用案例说明。

系列文章目录 本章内容: (1)shared_ptr、weak_ptr、unique_ptr的介绍 (2)单独使用share_ptr造成的内存泄漏 (3)shared_ptr和weak_ptr的配合使用 文章目录 系列文章目录前言一、shared_ptr、wea…

PHP编写采集药品官方数据的程序

在 PHP 中编写爬虫程序,首先我们需要引入一些必要的库,如 curl 和 file_get_contents。然后,我们需要设置爬虫ip信息,以便我们可以从指定的爬虫ip服务器上获取数据。 // 引入必要的库 require_once curl.php;// 设置爬虫ip信息 $p…

振南技术干货集:振南当年入门C语言和单片机的那些事儿(3)

注解目录 第一章《振南当年入门 C 语言和单片机的那些事儿》 1、注定堕入单片机 1.1 懵懂好奇的我 (小时候好奇的性格经常让我屁股开花。初中开始对计算机产生兴趣,并一发不可收拾。) 1.2 我的 C 语言学习经历 (上大学后自学…

虚拟机网络没有有效的ip配置

虚拟机网络没有有效的ip配置: 原因猜测:或许是之前使用的操作系统把网络给占了。 解决方法:点击虚拟机的 遍历->网络编辑器->移除不要的网络,然后添加网络。(下面的图就是我把虚拟网络全部移除,然后…

ke10javaweb停更

<jsp:getProperty property"isval" name "username"/> property来修改属性,name是类 所以如果调用tip在前面那么就是没有设置值 证明是先到java里面去运转

JNPF开发平台:加速企业数字化转型,提升业务效率

如今&#xff0c;随着信息化的深入发展&#xff0c;数字化转型已经成为企业生存和发展的关键。为了在竞争激烈的市场中保持领先地位&#xff0c;企业需要快速地适应变化&#xff0c;优化业务流程&#xff0c;并提供优质的用户体验。而在这其中&#xff0c;低代码开发平台JNPF是…

VulnHub Nullbyte

一、信息收集 1.nmap扫描 arp-scan -l扫描内网存活主机 ┌──(root&#x1f480;kali)-[~/桌面] └─# nmap -sS -A -p- 192.168.103.201/24 -sS 半扫描 -A 扫描详细信息 -p- 扫描全端口发现开放了80、111、777、50978端口 且发现777端口开放了ssh服务&#xff0c;说明他把…

SQL Server 2022 安装步骤——SQL Server设置身份验证教程

目录 前言: 安装详细步骤: 第一步: 第二步: 第三步: 第四步: SQL Server 连接的方式: Window验证: SQL Server验证: 两者之间区别: 总结: SQL Server身份验证登录配置教程:​ 第一步: 第二步: 第三步: 番外篇: 前言: 本文讲解&#xff0c;如何安装SQL Server安…

Android修行手册-POI操作Excel实现超链接并且变为蓝色

点击跳转>Unity3D特效百例点击跳转>案例项目实战源码点击跳转>游戏脚本-辅助自动化点击跳转>Android控件全解手册点击跳转>Scratch编程案例点击跳转>软考全系列 &#x1f449;关于作者 专注于Android/Unity和各种游戏开发技巧&#xff0c;以及各种资源分享&…

RESTFUL是什么,为什么使用,有什么优点

ESTful&#xff08;Representational State Transfer&#xff09;是一种软件架构风格&#xff0c;用于设计网络应用程序和服务。它是一种面向资源的设计理念&#xff0c;强调资源的标识、表现层和统一接口。RESTful 架构的设计原则和优点使得它成为构建分布式系统和 Web 服务的…

【CMU 15-445】Proj1 Buffer Pool Manager

Buffer Pool Manager 通关记录Task1 LRU-K Replacement PolicyTask2 Disk SchedulerTask3 Buffer Pool ManagerFlushPageFlushAllPagesUnpinPageNewPageFetchPageDeletePage Optimizations CMU-15445汇总 本文对应的project版本为CMU-Fall-2023的project1 由于Andy要求&#xf…

切换数据库的临时表空间为temp1 / 切换数据库的undo表空间为 undotbs01

目录 ​编辑 一、切换临时表空间 1、登录数据库 2、查询默认临时表空间 3、创建临时表空间temp1&#xff08;我们的目标表空间&#xff09; 4、修改默认temp表空间 5、查询用户默认临时表空间 6、命令总结&#xff1a; 二、切换数据库的undo表空间 1、查询默认undo表…

护眼台灯横评|书客、明基、松下品牌大测评告诉你谁才是最亮的星!

护眼台灯哪个牌子好&#xff1f;随着护眼台灯普及率的日渐提高&#xff0c;护眼台灯市场也是十分火爆&#xff0c;但很多商家为了盈利&#xff0c;总是把重心放在宣传和营销手段上&#xff0c;从而导致护眼台灯的产品质量不过关&#xff0c;在使用过后不仅没有起到缓解眼睛疲劳…

【CASS精品教程】cass 3d基于osgb三维模型生成等高线的两种方法

对于植被、房屋稀少的地方,可以基于osgb模型直接生成等高线。本文讲解在cass11.0 3d中基于osgb三维模型生成等高线的两种方法。 一、加载osgb三维模型 二、生成等高线 1. 绘制等高线 cass11版本提供了绘制单个等高线的功能。 点击【绘制等高线】,提示输入等高距。 输入固定…

JVM中jhat虚拟机堆转储快照分析工具

jhat虚拟机堆转储快照分析工具 1、jhat jhat也是jdk内置的工具之一。主要是用来分析java堆的命令&#xff0c;可以将堆中的对象以html的形式显示出来&#xff0c;包括对 象的数量&#xff0c;大小等等&#xff0c;并支持对象查询语言。 使用jmap等方法生成java的堆文件后&a…

【考研数据结构代码题3】用栈实现十进制数转为八进制数

题目&#xff1a;将十进制数m1348转换成八进制数 难度&#xff1a;★ 算法思路&#xff1a;十进制转八进制的核心原理是“用辗转相除法不断对8取余&#xff0c;最后将余数反向输出”&#xff0c;即先求出来的余数后输出&#xff0c;符合“先进后出”的栈的特性&#xff0c;故设…

七个优秀微服务跟踪工具

随着微服务架构复杂性的增加&#xff0c;在问题出现时确定问题的根本原因变得更具挑战性。日志和指标为我们提供了有用的信息&#xff0c;但并不能提供系统的完整概况。这就是跟踪的用武之地。通过跟踪&#xff0c;开发人员可以监控微服务之间的请求进度&#xff0c;从而使他们…