Python 将h264字节字符串转换为OpenCV图像

Python 将h264字节字符串转换为OpenCV图像,python,opencv,ffmpeg,stream,h.264,Python,Opencv,Ffmpeg,Stream,H.264,在Python中,如何将h264字节的字符串转换为OpenCV可以读取的图像,只保留最新的图像 长版本: 大家好 在Python中工作时,我试图通过管道从adb screenrecord获取输出,以便在需要时捕获帧并与OpenCV一起使用。据我所知,我需要不断地阅读流,因为它是h264 我尝试了多种方法来让它工作,并得出结论,我需要寻求具体的帮助 下面得到了我需要的流,并且在打印stream.stdout.read(n)时效果非常好 通用换行是使其在Windows上工作所必需的 做: sp.ca

在Python中,如何将h264字节的字符串转换为OpenCV可以读取的图像,只保留最新的图像

长版本:

大家好

在Python中工作时,我试图通过管道从adb screenrecord获取输出,以便在需要时捕获帧并与OpenCV一起使用。据我所知,我需要不断地阅读流,因为它是h264

我尝试了多种方法来让它工作,并得出结论,我需要寻求具体的帮助

下面得到了我需要的流,并且在打印stream.stdout.read(n)时效果非常好

通用换行是使其在Windows上工作所必需的

做:

sp.call(['ffplay', '-'], stdin = stream.stdout, universal_newlines = True)
工作

问题是我现在尝试使用ffmpeg获取输入h264流并输出尽可能多的帧,如果需要,覆盖最后一帧

ffmpegCmd = ['ffmpeg', '-f', 'image2pipe', '-pix_fmt', 'bgr24', '-vcodec', 'h264', 'fps=30', '-']
ffmpeg = sp.Popen(ffmpegCmd, stdin = stream.stdout, stdout = sp.PIPE, universal_newlines = True)
这是我认为应该使用的,但我总是得到错误“输出文件#0不包含任何流”

编辑:

最终答案 结果是universal_newlines选项破坏了行的结尾,并逐渐破坏了输出。此外,ffmpeg命令是错误的,请参见LordNeckbeard的回答

下面是正确的ffmpeg命令,以实现所使用的功能:

ffmpegCmd = ['ffmpeg', '-i', '-', '-f', 'rawvideo', '-vcodec', 'bmp', '-vf', 'fps=5', '-']
ffmpeg = sp.Popen(ffmpegCmd, stdin = stream.stdout, stdout = sp.PIPE)
然后,要将结果转换为OpenCV图像,请执行以下操作:

fileSizeBytes = ffmpeg.stdout.read(6)
fileSize = 0
for i in xrange(4):
    fileSize += fileSizeBytes[i + 2] * 256 ** i
bmpData = fileSizeBytes + ffmpeg.stdout.read(fileSize - 6)
image = cv2.imdecode(np.fromstring(bmpData, dtype = np.uint8), 1)
这将获得流的每一帧作为OpenCV图像。

使用以下任一选项:

ffmpeg -i - -pix_fmt bgr24 -f rawvideo -
ffmpeg -i pipe: -pix_fmt bgr24 -f rawvideo pipe:
ffmpeg -i pipe:0 -pix_fmt bgr24 -f rawvideo pipe:1
  • 您没有提供有关输入的太多信息,因此可能需要添加其他输入选项

  • 您没有指定所需的输出格式,所以我选择了rawvideo。您可以使用
    ffmpeg-muxers
    (或者
    ffmpeg-formats
    查看受支持的输出格式(muxer)列表(如果
    ffmpeg
    已过时)。并非所有都适用于管道,如MP4


它运行良好,只是做了一些小改动: 这将在循环中读取流,并在每次显示最后一个图像时显示

adbCmd = ['adb', 'exec-out', 'screenrecord', '--output-format=h264', '-']
stream = sp.Popen(adbCmd, stdout = sp.PIPE)

ffmpegCmd =['ffmpeg', '-i', '-', '-f', 'rawvideo', '-vf', 'scale=324:576', 
'-vcodec', 'bmp',  '-']
ffmpeg = sp.Popen(ffmpegCmd, stdin = stream.stdout, stdout = sp.PIPE)

while True:
    fileSizeBytes = ffmpeg.stdout.read(6)
    fileSize = 0
    for i in xrange(4):
        fileSize += array.array('B',fileSizeBytes[i + 2])[0] * 256 ** i
    bmpData = fileSizeBytes + ffmpeg.stdout.read(fileSize - 6)
    image = cv2.imdecode(np.fromstring(bmpData, dtype = np.uint8), 1)
    cv2.imshow("im",image) 
    cv2.waitKey(25)

脚本实际执行的
ffmpeg
命令是什么?完整的
ffmpeg
控制台输出/日志也将提供信息。如果您不编写脚本手动运行,
ffmpeg
是否有效?ffmpeg命令是最后一段代码中ffmpegCmd字符串数组的内容。我问这个问题是因为
ffmpeg-f image2pipe-pix_fmt bgr24-vcodec h264 fps=30-
不是有效的命令。对于从管道输入输出图像,我希望类似于
ffmpeg-I-output_u%03d.png
是的,我从错误中得出了结论。要实现我的目标,正确的ffmpeg命令是什么?我正在尝试从stdin获取流,并将图像(如果可能,为bgr24格式)输出到stdout。我算出了-I管道:对于stdin,现在我只需要算出stdout。这些都起作用了,但我最后添加了-vcodec bmp和-vf fps=5作为最后一个命令:
ffmpeg-I--f rawvideo-vcodec bmp-vf fps=5-
。对于cv2部分,我使用BMP标题自动查找分辨率和帧大小,并从stdout和cv2.imdecode中读取适当的字节数,因为它是标准BMP。@FredDufresne很高兴听到您找到了适合您的解决方案。请注意,强制帧速率可能会导致丢失或复制帧id,因为输入不同。
adbCmd = ['adb', 'exec-out', 'screenrecord', '--output-format=h264', '-']
stream = sp.Popen(adbCmd, stdout = sp.PIPE)

ffmpegCmd =['ffmpeg', '-i', '-', '-f', 'rawvideo', '-vf', 'scale=324:576', 
'-vcodec', 'bmp',  '-']
ffmpeg = sp.Popen(ffmpegCmd, stdin = stream.stdout, stdout = sp.PIPE)

while True:
    fileSizeBytes = ffmpeg.stdout.read(6)
    fileSize = 0
    for i in xrange(4):
        fileSize += array.array('B',fileSizeBytes[i + 2])[0] * 256 ** i
    bmpData = fileSizeBytes + ffmpeg.stdout.read(fileSize - 6)
    image = cv2.imdecode(np.fromstring(bmpData, dtype = np.uint8), 1)
    cv2.imshow("im",image) 
    cv2.waitKey(25)