我将一张大图像切割成许多图块(150,000),然后用FFmpeg以每秒一帧的速度将其编码成.h264文件,并将其放在服务器上。现在我想从.h264文件中随机解码一张图片进行分析。 我本地解码的思路是在剪切图片时记录它们的索引(i,j),然后让解码器根据索引找到.h264中对应的帧,效果还不错。 现在我把.h264放在服务器(minio)上,我只想截取一段码流并解码。这可能吗?
(比如我的.h264总共有10帧,我想解码第5帧并保存。我可以缓存第4到第6帧然后解码吗?)
----------------------这是我用来从服务器捕获一小部分流的代码。--------- --------------------------------------------------
@lru_cache(1024)
def read_small_cached(self, start, length, retry=5):
''' read cached and thread safe, but do not read too large'''
if length == 0:
return b''
resp = None
for _ in range(retry):
try:
_client = minio_get_client()
resp = _client.get_object(
self.bucket, self.filename, offset=start, length=length)
oup = resp.read()
return oup
except:
time.sleep(3)
finally:
if resp is not None:
resp.close()
resp.release_conn()
raise Exception(f'can not read {self.name}')
我尝试了start = 0,length = 10241024100等参数,可以读取部分图片
但是当我使用该函数查找 IDR 帧并获取其位置时,FFmpeg 的解码器认为这是无效资源。
---------------------------------这是我的 find key_frame 的代码-------- ---------------------------------
def get_all_content(file_path, search_bytes):
"""
查找指定文件中所有与 search_bytes 相同的内容,并将其位置记录在 positions 列表中。
:param file_path: 要查找的文件路径
:param search_bytes: 要查找的字节序列
:return: 包含字节序列位置的列表
"""
if not file_path or not search_bytes:
raise ValueError("file_path 和 search_bytes 不能为空")
search_len = len(search_bytes)
positions = []
with open(file_path, 'rb') as fp:
fp.seek(0, 2) # 移动到文件末尾 0表示文件移动的字节数,2表示到末尾,这样是为了获取文件的总大小
file_size = fp.tell() # 文件大小
fp.seek(0) # 回到文件开始
pos = 0
while pos <= (file_size - search_len):
fp.seek(pos)
buf = fp.read(search_len)
if len(buf) < search_len:
break
if buf == search_bytes:
positions.append(pos)
pos += 1
return positions
我最近才开始了解H264。也许我对bitstream和H264有误解。我希望得到一些指导。预先感谢!
抱歉,这是代码。
def get_all_content(file_path, search_bytes):
"""
查找指定文件中所有与 search_bytes 相同的内容,并将其位置记录在 positions 列表中。
:param file_path: 要查找的文件路径
:param search_bytes: 要查找的字节序列
:return: 包含字节序列位置的列表
"""
if not file_path or not search_bytes:
raise ValueError("file_path 和 search_bytes 不能为空")
search_len = len(search_bytes)
positions = []
with open(file_path, 'rb') as fp:
fp.seek(0, 2) # 移动到文件末尾 0表示文件移动的字节数,2表示到末尾,这样是为了获取文件的总大小
file_size = fp.tell() # 文件大小
fp.seek(0) # 回到文件开始
pos = 0
while pos <= (file_size - search_len):
fp.seek(pos)
buf = fp.read(search_len)
if len(buf) < search_len:
break
if buf == search_bytes:
positions.append(pos)
pos += 1
return positions
@lru_cache(1024)
def read_small_cached(self, start, length, retry=5):
''' read cached and thread safe, but do not read too large'''
if length == 0:
return b''
resp = None
for _ in range(retry):
try:
_client = minio_get_client()
resp = _client.get_object(
self.bucket, self.filename, offset=start, length=length)
oup = resp.read()
return oup
except:
time.sleep(3)
finally:
if resp is not None:
resp.close()
resp.release_conn()
raise Exception(f'can not read {self.name}')