使用ffmpeg pyspark和hadoop进行逐帧视频处理

时间:2019-07-12 18:39:05

标签: hadoop video pyspark hdfs

我想使用spark和hadoop并行处理mp4视频帧。我不想在处理之前提取所有帧。我正在寻找的是一种顺序读取帧数据的方法视频时间,然后使用纱线喂入框架,将框架激发到Hadoop集群上的执行者。 mp4视频文件可以位于本地文件系统上,也可以位于HDFS上。

我可以使用ffmpeg创建管道,然后读取原始帧字节(例如image = np.fromstring(pipe.stdout.read(1920 * 1080 * 3)) ,dtype ='uint8'))。有什么方法可以将数据(即流,因为帧作为可变解码时间的函数)馈送到Spark RDD,并具有执行某些功能(例如计算平均强度)的map函数?

我已经阅读了很长时间的spark文档,却找不到在这种情况下可行的任何东西。我可能会为树木错过森林。即使可以,即使涉及不使用ffmpeg和管道,也请提供帮助。

1 个答案:

答案 0 :(得分:0)

经过反复试验,我有一个可行的解决方案。虽然这可能不适用于每个人,但可能可以帮助一些人,所以去了:

我首先创建了一个从视频中提取帧的脚本,该脚本必须存在于所有工作节点上:

#!/home/hadoop/anaconda2/bin/python

import os
import sys
import subprocess as sp
import numpy as np
import cv2
import copy

# RDD.pipe sends via stdin
i = 0
try:
        i = input()
except:
    sys.exit()



file_name = 'v.mp4'
FFMPEG_BIN = "ffmpeg" # on Linux ans Mac OS
command = [ FFMPEG_BIN,
               '-i', '/home/hadoop/' + file_name,
               '-f', 'image2pipe',
               '-vf', 'select=gte(n\, %d)' % i,
               '-vframes', '1',
               '-pix_fmt', 'rgb24',
               '-loglevel', 'panic',
               '-vcodec', 'png', '-']
pipe = sp.Popen(command, stdout=sp.PIPE, bufsize=10**8)
data = pipe.stdout.read()
pipe.stdout.close()
import base64
print(base64.b64encode(data))

然后,在pyspark脚本中,我使用脚本参数创建一个RDD:

params = [str(i)  for i in range(1, 1001)]
rdd1 = sc.parallelize(params, numSlices=1000)
pipeRDD = rdd1.pipe('/home/hadoop/src/extract_frame.sh')
resizedRDD = pipeRDD.map(resizeMapper)
test = resizedRDD.collect()

test现在具有前1000帧。调整大小的映射器调整每帧的大小,这里是:

def resizeMapper(x):
    import base64
    import cv2
    a = base64.b64decode(x)
    im = cv2.imdecode(np.fromstring(a, dtype=np.uint8), 1)
    im = cv2.resize(im, (200, 200))
    return im

我希望这可以帮助某个人。