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



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

长版本:

大家好。

在 Python 中工作,我正在尝试以一种允许我在需要时捕获帧并将其与 OpenCV 一起使用的方式从 adb 屏幕录制中获取输出。据我了解,我需要不断阅读流,因为它是 h264。

我已经尝试了多种方法来使其正常工作,并得出结论,我需要寻求特定的帮助。

下面为我提供了我需要的流,并且在我打印stream.stdout.read(n)时运行良好。

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

通用换行符是让它在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
  • 您没有提供有关输入的太多信息,因此可能需要添加其他输入选项。

  • 您没有指定所需的输出格式,所以我只选择了原始视频。您可以查看支持的输出格式(复用器)列表,其中包含ffmpeg -muxers(如果您的ffmpeg已过时,则ffmpeg -formats)。并非所有管道都适合管道,例如MP4。

  • 请参阅 FFmpeg 协议:管道。

它运行良好,只需稍作更改: 这将循环读取流,并在每次显示最后一个图像

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)

最新更新