Skip to content

Commit 7380761

Browse files
Merge pull request #4 from pysnippet/GH-3/enhance-performance
GH-3: Enhance the performance for 5 times (GH-4)
2 parents 9c0fddc + 9340f25 commit 7380761

File tree

2 files changed

+20
-80
lines changed

2 files changed

+20
-80
lines changed

ffmpeg/ffmpeg.py

Lines changed: 12 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ def cross_platform_popen_params(popen_params):
2727
return popen_params
2828

2929

30-
class FFMPEG:
30+
class Ffmpeg:
3131

3232
def __init__(self, filename, bufsize=None, pixel_format="rgba"):
3333

@@ -51,11 +51,13 @@ def __init__(self, filename, bufsize=None, pixel_format="rgba"):
5151
bufsize = self.depth * w * h + 100
5252

5353
self.bufsize = bufsize
54-
self.initialize()
5554

56-
def initialize(self, start_time=0):
57-
self.close(delete_lastread=False)
55+
@staticmethod
56+
def frame_to_buffer(image):
57+
image = image.astype("uint8")
58+
return Image.fromarray(image)
5859

60+
def get_frame(self, start_time=0):
5961
if start_time != 0:
6062
offset = min(1, start_time)
6163
i_arg = [
@@ -96,84 +98,22 @@ def initialize(self, start_time=0):
9698
"stdin": sp.DEVNULL,
9799
}
98100
)
99-
self.proc = sp.Popen(cmd, **popen_params)
100-
101-
self.pos = self.get_frame_number(start_time)
102-
self.lastread = self.read_frame()
103101

104-
def save_frame(self, filename, t=0):
105-
im = self.get_frame(t)
106-
im = im.astype("uint8")
102+
proc = sp.Popen(cmd, **popen_params)
107103

108-
img = Image.fromarray(im)
109-
img.save(filename)
110-
111-
def skip_frames(self, n=1):
112-
w, h = self.size
113-
for i in range(n):
114-
self.proc.stdout.read(self.depth * w * h)
115-
116-
self.pos += n
117-
118-
def read_frame(self):
119104
w, h = self.size
120105
nbytes = self.depth * w * h
106+
s = proc.stdout.read(nbytes)
121107

122-
s = self.proc.stdout.read(nbytes)
123-
124-
if len(s) != nbytes:
125-
if not hasattr(self, "last_read"):
126-
raise IOError
127-
128-
result = self.last_read
129-
108+
if hasattr(np, "frombuffer"):
109+
result = np.frombuffer(s, dtype="uint8")
130110
else:
131-
if hasattr(np, "frombuffer"):
132-
result = np.frombuffer(s, dtype="uint8")
133-
else:
134-
result = np.fromstring(s, dtype="uint8")
135-
result.shape = (h, w, len(s) // (w * h))
136-
self.last_read = result
111+
result = np.fromstring(s, dtype="uint8")
137112

138-
self.pos += 1
113+
result.shape = (h, w, len(s) // (w * h))
139114

140115
return result
141116

142-
def get_frame(self, t):
143-
pos = self.get_frame_number(t) + 1
144-
145-
if not self.proc:
146-
print("Proc not detected")
147-
self.initialize(t)
148-
return self.last_read
149-
150-
if pos == self.pos:
151-
return self.last_read
152-
elif (pos < self.pos) or (pos > self.pos + 100):
153-
self.initialize(t)
154-
return self.lastread
155-
else:
156-
self.skip_frames(pos - self.pos - 1)
157-
result = self.read_frame()
158-
return result
159-
160-
def get_frame_number(self, t):
161-
return int(self.fps * t + 0.00001)
162-
163-
def close(self, delete_lastread=True):
164-
if self.proc:
165-
if self.proc.poll() is None:
166-
self.proc.terminate()
167-
self.proc.stdout.close()
168-
self.proc.stderr.close()
169-
self.proc.wait()
170-
self.proc = None
171-
if delete_lastread and hasattr(self, "last_read"):
172-
del self.last_read
173-
174-
def __del__(self):
175-
self.close()
176-
177117

178118
class FFMPEGInfos:
179119

thumbnails.py

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,14 @@
44

55
from PIL import Image
66

7-
from ffmpeg import Ffmpeg
7+
from ffmpeg.ffmpeg import Ffmpeg
88

99
width, height = 300, 200
1010
interval = 20
1111
columns = 3
1212

1313
files = ["valerian-1080p.avi", "valerian-1080p.mkv", "valerian-1080p.mov", "valerian-1080p.mp4",
14-
"valerian-1080p.webm", "valerian-1080p.wmv", "valerian-1080p.mpeg", "valerian-1080p.mpg"]
14+
"valerian-1080p.webm", "valerian-1080p.wmv", "valerian-1080p.mpeg", "valerian-1080p.mpg", "valerian-1080p.ogv"]
1515

1616

1717
def worker(video):
@@ -25,9 +25,12 @@ def worker(video):
2525
except IOError:
2626
master = Image.new(mode="RGB", size=(master_width, master_height))
2727

28-
for moment in range(0, int(video.duration), interval):
28+
with concurrent.futures.ThreadPoolExecutor() as executor:
29+
frames = executor.map(video.get_frame, range(0, int(video.duration), interval))
30+
31+
for frame in frames:
2932
x, y = width * column, height * line
30-
image = video.get_frame_buffer(moment)
33+
image = video.frame_to_buffer(frame)
3134
image = image.resize((width, height), Image.ANTIALIAS)
3235
master.paste(image, (x, y))
3336

@@ -43,12 +46,9 @@ def worker(video):
4346
async def main():
4447
fps = [Ffmpeg(fp) for fp in files]
4548

46-
with concurrent.futures.ThreadPoolExecutor() as executor:
49+
with concurrent.futures.ProcessPoolExecutor() as executor:
4750
executor.map(worker, fps)
4851

49-
for fp in fps:
50-
fp.close()
51-
5252

5353
loop = asyncio.get_event_loop()
5454
loop.run_until_complete(main())

0 commit comments

Comments
 (0)