首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >打印MJPEG帧

打印MJPEG帧
EN

Stack Overflow用户
提问于 2015-04-09 10:30:49
回答 1查看 2.4K关注 0票数 1

我试着做一个mjpeg流光。帧前面的前5个字节给出了它的大小。然后我可以提取帧。我需要检查一下我是否得到了正确的框架。我试图将这个框架写入一个.jpeg文件,但这不起作用。我做得对吗?

代码语言:javascript
复制
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()
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2015-04-09 14:03:26

代码中的长度实际上就是第五个字节的值。您将所有其他求和(至少8位)移到左侧,然后屏蔽除8位以外的所有最小位。由于前面的移位操作,这些位都是零。

可以实现的一个简单的附加测试是,如果帧数据以JPEG图像标记开始(FF D8)开始,以图像标记(DD D9)的结束结束。

下面的函数应该迭代由五个ascii字符长帧长度计数分隔的JPEG图像,比如您正在移植到Python的VideoStream.java

代码语言:javascript
复制
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图像:

代码语言:javascript
复制
ffmpeg -i bowlerhatdancer.sleepytom.SGP.mjpeg.avi \
   -c:v copy -bsf:v mjpeg2jpeg frame_%04d.jpg
票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/29536039

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档