Here's a patch I use for profiling video decoding and rendering speed.
It adds a pyglet option "profile_media" which makes sure that
- the video file's frame rate is ignored
- exactly one frame is decoded and rendered in every call to
media_player.py's on_draw()
- the process is terminated after 500 frames of decoded video
- the decoding is done by the main thread
- on_draw() is called as often as possible
The goal is to saturate a single CPU core with the task of video
decoding and color space conversion and to be able to time how long it
takes to render 500 frames.
After having applied this patch, you can run a benchmark like this:
export PYGLET_PROFILE_MEDIA=TRUE
export PYGLET_VSYNC=FALSE
time python examples/media_player.py <video file with at least 500
frames>
(Yes, probably it would have been a good idea to write a separate tool
rather than to modify media_player.py)
Some results will be in the next post.
Jan
Index: pyglet/media/__init__.py
===================================================================
--- pyglet/media/__init__.py (Revision 2539)
+++ pyglet/media/__init__.py (Arbeitskopie)
@@ -83,6 +83,7 @@
import pyglet
_debug = pyglet.options['debug_media']
+_profile = pyglet.options['profile_media']
class MediaException(Exception):
pass
@@ -992,7 +993,10 @@
period = 1. / self.source.video_format.frame_rate
else:
period = 1. / 30.
- pyglet.clock.schedule_interval(self.update_texture,
period)
+ if _profile:
+ pyglet.clock.schedule(lambda dt: None)
+ else:
+ pyglet.clock.schedule_interval
(self.update_texture, period)
else:
if self._audio_player:
self._audio_player.stop()
@@ -1117,23 +1121,26 @@
self.seek(time)
def update_texture(self, dt=None, time=None):
- if time is None:
- time = self._audio_player.get_time()
- if time is None:
- return
+ if _profile:
+ ts = 0
+ else:
+ if time is None:
+ time = self._audio_player.get_time()
+ if time is None:
+ return
- if (self._last_video_timestamp is not None and
- time <= self._last_video_timestamp):
- return
+ if (self._last_video_timestamp is not None and
+ time <= self._last_video_timestamp):
+ return
- ts = self._groups[0].get_next_video_timestamp()
- while ts is not None and ts < time:
- self._groups[0].get_next_video_frame() # Discard frame
ts = self._groups[0].get_next_video_timestamp()
+ while ts is not None and ts < time:
+ self._groups[0].get_next_video_frame() # Discard
frame
+ ts = self._groups[0].get_next_video_timestamp()
- if ts is None:
- self._last_video_timestamp = None
- return
+ if ts is None:
+ self._last_video_timestamp = None
+ return
image = self._groups[0].get_next_video_frame()
if image is not None:
Index: pyglet/media/avbin.py
===================================================================
--- pyglet/media/avbin.py (Revision 2539)
+++ pyglet/media/avbin.py (Arbeitskopie)
@@ -41,6 +41,7 @@
import ctypes
import threading
import time
+import os
import pyglet
from pyglet import gl
@@ -381,8 +382,10 @@
self._video_timestamp = max(self._video_timestamp,
video_packet.timestamp)
self._video_packets.append(video_packet)
- self._decode_thread.put_job(
- lambda: self._decode_video_packet(video_packet))
+
+ if not _profile:
+ self._decode_thread.put_job(
+ lambda: self._decode_video_packet(video_packet))
return 'video', video_packet
@@ -487,6 +490,11 @@
def _decode_video_packet(self, packet):
width = self.video_format.width
height = self.video_format.height
+
+ if _profile and packet.id == 500:
+ print "%dx%d" % (width, height)
+ os.kill(os.getpid(),9)
+
pitch = width * 3
buffer = (ctypes.c_uint8 * (pitch * height))()
result = av.avbin_decode_video(self._video_stream,
@@ -499,10 +507,11 @@
packet.image = image_data
- # Notify get_next_video_frame() that another one is ready.
- self._condition.acquire()
- self._condition.notify()
- self._condition.release()
+ if not _profile:
+ # Notify get_next_video_frame() that another one is
ready.
+ self._condition.acquire()
+ self._condition.notify()
+ self._condition.release()
def _ensure_video_packets(self):
'''Process packets until a video packet has been queued (and
begun
@@ -539,15 +548,22 @@
if self._ensure_video_packets():
packet = self._video_packets.pop(0)
- if _debug:
- print 'Waiting for', packet
+
+ if not _profile:
+ if _debug:
+ print 'Waiting for', packet
- # Block until decoding is complete
- self._condition.acquire()
- while packet.image == 0:
- self._condition.wait()
- self._condition.release()
+ # Block until decoding is complete
+ self._condition.acquire()
+ while packet.image == 0:
+ self._condition.wait()
+ self._condition.release()
+ else:
+ # when we are profiling, the main thread
+ # does all the work
+ self._decode_video_packet(packet)
+
if _debug:
print 'Returning', packet
return packet.image
@@ -560,4 +576,5 @@
_debug = False
av.avbin_set_log_level(AVBIN_LOG_QUIET)
+_profile = pyglet.options['profile_media']
_have_frame_rate = av.avbin_have_feature('frame_rate')
Index: pyglet/__init__.py
===================================================================
--- pyglet/__init__.py (Revision 2539)
+++ pyglet/__init__.py (Arbeitskopie)
@@ -139,6 +139,7 @@
'debug_graphics_batch': False,
'debug_lib': False,
'debug_media': False,
+ 'profile_media': False,
'debug_texture': False,
'debug_trace': False,
'debug_trace_args': False,
@@ -163,6 +164,7 @@
'debug_graphics_batch': bool,
'debug_lib': bool,
'debug_media': bool,
+ 'profile_media': bool,
'debug_texture': bool,
'debug_trace': bool,
'debug_trace_args': bool,
Index: examples/media_player.py
===================================================================
--- examples/media_player.py (Revision 2539)
+++ examples/media_player.py (Arbeitskopie)
@@ -298,6 +298,7 @@
# Video
if self.player.source and self.player.source.video_format:
+ if _profile: self.player.update_texture()
self.player.get_texture().blit(self.video_x,
self.video_y,
width=self.video_width,
@@ -308,6 +309,8 @@
for control in self.controls:
control.draw()
+_profile = pyglet.options['profile_media']
+
if __name__ == '__main__':
if len(sys.argv) < 2:
print 'Usage: media_player.py <filename> [<filename> ...]'
--
You received this message because you are subscribed to the Google Groups
"pyglet-users" group.
To post to this group, send email to [email protected].
To unsubscribe from this group, send email to
[email protected].
For more options, visit this group at
http://groups.google.com/group/pyglet-users?hl=en.