我试着做一个mjpeg流光。帧前面的前5个字节给出了它的大小。然后我可以提取帧。我需要检查一下我是否得到了正确的框架。我试图将这个框架写入一个.jpeg文件,但这不起作用。我做得对吗?
import os
from array import array
class VideoStream:
def __init__(self,filename):
self.fis = open(filename,'r')
self.frame_nb = 0
def getnextframe(self):
length = 0
frame_length = bytearray(5)
frame_length = self.fis.read(5)
fm = array('B',frame_length[:5])
length = fm[4]+((fm[3]<<8)&0xFF)+((fm[2]<<16)&0xFF)+((fm[1]<<24)&0xFF)+((fm[0]<<32)&0xFF)
frame = self.fis.read(length)
print 'len=',length
test = open("test.jpeg",'w')
test.write(frame)
test.close()
print 'frame=',frame
if __name__=='__main__':
vs = VideoStream("Movie.mjpeg")
vs.getnextframe()发布于 2015-04-09 14:03:26
代码中的长度实际上就是第五个字节的值。您将所有其他求和(至少8位)移到左侧,然后屏蔽除8位以外的所有最小位。由于前面的移位操作,这些位都是零。
可以实现的一个简单的附加测试是,如果帧数据以JPEG图像标记开始(FF D8)开始,以图像标记(DD D9)的结束结束。
下面的函数应该迭代由五个ascii字符长帧长度计数分隔的JPEG图像,比如您正在移植到Python的VideoStream.java:
def iter_frames(filename):
with open(filename, 'rb') as mjpeg_file:
while True:
frame_length_bytes = mjpeg_file.read(5)
if len(frame_length_bytes) != 5:
if frame_length_bytes:
raise ValueError('incomplete length')
else:
break
frame_length = int(frame_length_bytes)
frame = mjpeg_file.read(frame_length)
if len(frame) != frame_length:
raise ValueError('incomplete frame data')
if not (
frame.startswith(b'\xff\xd8') and frame.endswith(b'\xff\xd9')
):
raise ValueError('invalid jpeg')
yield frame
def main():
frames = iter_frames('Movie.mjpeg')
frame = next(frames)
with open('test.jpg', 'wb') as jpeg_file:
jpeg_file.write(frame)
if __name__ == '__main__':
main()它检查字节计数值和JPEG数据是否都完成,以及是否存在JPEG开始标记和结束标记。
比你想象的简单多了,我猜。但是有一个问题:这种格式很可能是由Java类的作者组成的。
MJPEG只是一个视频编解码器,基本上只是JPEG图像的级联。但它很少采用那种“原始”格式,而是嵌入到容器格式中,其中包含MJPEG数据、帧速率、可能是音频等元信息。
AVI就是这样的一种格式,就像您在评论中引用的示例MJPEG avi一样。
将这种文件中的帧提取到单个JPEG图像中比读取以简单长度信息为前缀的JPEG图像,然后在一个文件中连接起来要多一些。需要实现一个AVI读取器,它对AVI格式有足够的了解,可以获取帧数据。然后,一个JPEG阅读器了解足够的JPEG格式来读取一个完整的帧,因为它们被保存到后面,没有任何长度信息。
下一个问题是,并非所有MJPEG都包含可作为单独JPEG图像使用的帧。有些人缺少解压缩图像数据所需的数据表(huffman表)。在AVI规范中有一个固定表用于MJPEG编解码器。该表被软件用于解码,并在保存为JPEG文件时必须注入到帧中。
最后一件“事情”:有交错的视频不包含完整的图像,但两个连续的图像需要合并为一个。每个图像包含每一行。你给定的示例MJPEG avi就是这样一个视频。在不需要解码、隔行和重编码的情况下提取帧时,每幅图像的高度仅为视频高度的一半。
为了更好地了解单个图像的样子,这个ffmpeg命令行提取框架数据并注入丢失的数据表,以获得独立的JPEG图像:
ffmpeg -i bowlerhatdancer.sleepytom.SGP.mjpeg.avi \
-c:v copy -bsf:v mjpeg2jpeg frame_%04d.jpghttps://stackoverflow.com/questions/29536039
复制相似问题