|  |  | @ -210,24 +210,24 @@ def rgb24toyuv420(rgb): | 
			
		
	
		
		
			
				
					
					|  |  |  |   return yuv420.clip(0,255).astype('uint8') |  |  |  |   return yuv420.clip(0,255).astype('uint8') | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  | def decompress_video_data(rawdat, vid_fmt, w, h, pix_fmt, multithreaded=None): |  |  |  | def decompress_video_data(rawdat, vid_fmt, w, h, pix_fmt): | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  |   # using a tempfile is much faster than proc.communicate for some reason |  |  |  |   # using a tempfile is much faster than proc.communicate for some reason | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |   if multithreaded is None: |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |     multithreaded = not os.getenv('SINGLETHREADED') |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |   with tempfile.TemporaryFile() as tmpf: |  |  |  |   with tempfile.TemporaryFile() as tmpf: | 
			
		
	
		
		
			
				
					
					|  |  |  |     tmpf.write(rawdat) |  |  |  |     tmpf.write(rawdat) | 
			
		
	
		
		
			
				
					
					|  |  |  |     tmpf.seek(0) |  |  |  |     tmpf.seek(0) | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     threads = os.getenv("FFMPEG_THREADS", "0") | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     cuda = os.getenv("FFMPEG_CUDA", "0") == "1" | 
			
		
	
		
		
			
				
					
					|  |  |  |     proc = subprocess.Popen( |  |  |  |     proc = subprocess.Popen( | 
			
		
	
		
		
			
				
					
					|  |  |  |       ["ffmpeg", |  |  |  |       ["ffmpeg", | 
			
		
	
		
		
			
				
					
					|  |  |  |        "-threads", "0" if multithreaded else "1", |  |  |  |        "-threads", threads, | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |        "-c:v", "hevc" if not cuda else "hevc_cuvid", | 
			
		
	
		
		
			
				
					
					|  |  |  |        "-vsync", "0", |  |  |  |        "-vsync", "0", | 
			
		
	
		
		
			
				
					
					|  |  |  |        "-f", vid_fmt, |  |  |  |        "-f", vid_fmt, | 
			
		
	
		
		
			
				
					
					|  |  |  |        "-flags2", "showall", |  |  |  |        "-flags2", "showall", | 
			
		
	
		
		
			
				
					
					|  |  |  |        "-i", "pipe:0", |  |  |  |        "-i", "pipe:0", | 
			
		
	
		
		
			
				
					
					|  |  |  |        "-threads", "0" if multithreaded else "1", |  |  |  |        "-threads", threads, | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  |        "-f", "rawvideo", |  |  |  |        "-f", "rawvideo", | 
			
		
	
		
		
			
				
					
					|  |  |  |        "-pix_fmt", pix_fmt, |  |  |  |        "-pix_fmt", pix_fmt, | 
			
		
	
		
		
			
				
					
					|  |  |  |        "pipe:1"], |  |  |  |        "pipe:1"], | 
			
		
	
	
		
		
			
				
					|  |  | @ -266,14 +266,14 @@ class BaseFrameReader: | 
			
		
	
		
		
			
				
					
					|  |  |  |     raise NotImplementedError |  |  |  |     raise NotImplementedError | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  | def FrameReader(fn, cache_prefix=None, readahead=False, readbehind=False, multithreaded=None, index_data=None): |  |  |  | def FrameReader(fn, cache_prefix=None, readahead=False, readbehind=False, index_data=None): | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  |   frame_type = fingerprint_video(fn) |  |  |  |   frame_type = fingerprint_video(fn) | 
			
		
	
		
		
			
				
					
					|  |  |  |   if frame_type == FrameType.raw: |  |  |  |   if frame_type == FrameType.raw: | 
			
		
	
		
		
			
				
					
					|  |  |  |     return RawFrameReader(fn) |  |  |  |     return RawFrameReader(fn) | 
			
		
	
		
		
			
				
					
					|  |  |  |   elif frame_type in (FrameType.h265_stream,): |  |  |  |   elif frame_type in (FrameType.h265_stream,): | 
			
		
	
		
		
			
				
					
					|  |  |  |     if not index_data: |  |  |  |     if not index_data: | 
			
		
	
		
		
			
				
					
					|  |  |  |       index_data = get_video_index(fn, frame_type, cache_prefix) |  |  |  |       index_data = get_video_index(fn, frame_type, cache_prefix) | 
			
		
	
		
		
			
				
					
					|  |  |  |     return StreamFrameReader(fn, frame_type, index_data, readahead=readahead, readbehind=readbehind, multithreaded=multithreaded) |  |  |  |     return StreamFrameReader(fn, frame_type, index_data, readahead=readahead, readbehind=readbehind) | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  |   else: |  |  |  |   else: | 
			
		
	
		
		
			
				
					
					|  |  |  |     raise NotImplementedError(frame_type) |  |  |  |     raise NotImplementedError(frame_type) | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
	
		
		
			
				
					|  |  | @ -325,15 +325,12 @@ class RawFrameReader(BaseFrameReader): | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  | class VideoStreamDecompressor: |  |  |  | class VideoStreamDecompressor: | 
			
		
	
		
		
			
				
					
					|  |  |  |   def __init__(self, vid_fmt, w, h, pix_fmt, multithreaded=None): |  |  |  |   def __init__(self, vid_fmt, w, h, pix_fmt): | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  |     self.vid_fmt = vid_fmt |  |  |  |     self.vid_fmt = vid_fmt | 
			
		
	
		
		
			
				
					
					|  |  |  |     self.w = w |  |  |  |     self.w = w | 
			
		
	
		
		
			
				
					
					|  |  |  |     self.h = h |  |  |  |     self.h = h | 
			
		
	
		
		
			
				
					
					|  |  |  |     self.pix_fmt = pix_fmt |  |  |  |     self.pix_fmt = pix_fmt | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |     if multithreaded is None: |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |       multithreaded = not os.getenv('SINGLETHREADED') |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |     if pix_fmt == "yuv420p": |  |  |  |     if pix_fmt == "yuv420p": | 
			
		
	
		
		
			
				
					
					|  |  |  |       self.out_size = w*h*3//2 # yuv420p |  |  |  |       self.out_size = w*h*3//2 # yuv420p | 
			
		
	
		
		
			
				
					
					|  |  |  |     elif pix_fmt in ("rgb24", "yuv444p"): |  |  |  |     elif pix_fmt in ("rgb24", "yuv444p"): | 
			
		
	
	
		
		
			
				
					|  |  | @ -343,9 +340,12 @@ class VideoStreamDecompressor: | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |     self.out_q = queue.Queue() |  |  |  |     self.out_q = queue.Queue() | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     threads = os.getenv("FFMPEG_THREADS", "0") | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     cuda = os.getenv("FFMPEG_CUDA", "0") == "1" | 
			
		
	
		
		
			
				
					
					|  |  |  |     self.proc = subprocess.Popen( |  |  |  |     self.proc = subprocess.Popen( | 
			
		
	
		
		
			
				
					
					|  |  |  |       ["ffmpeg", |  |  |  |       ["ffmpeg", | 
			
		
	
		
		
			
				
					
					|  |  |  |        "-threads", "0" if multithreaded else "1", |  |  |  |        "-threads", threads, | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |        "-c:v", "hevc" if not cuda else "hevc_cuvid", | 
			
		
	
		
		
			
				
					
					|  |  |  |        # "-avioflags", "direct", |  |  |  |        # "-avioflags", "direct", | 
			
		
	
		
		
			
				
					
					|  |  |  |        "-analyzeduration", "0", |  |  |  |        "-analyzeduration", "0", | 
			
		
	
		
		
			
				
					
					|  |  |  |        "-probesize", "32", |  |  |  |        "-probesize", "32", | 
			
		
	
	
		
		
			
				
					|  |  | @ -354,7 +354,7 @@ class VideoStreamDecompressor: | 
			
		
	
		
		
			
				
					
					|  |  |  |        "-vsync", "0", |  |  |  |        "-vsync", "0", | 
			
		
	
		
		
			
				
					
					|  |  |  |        "-f", vid_fmt, |  |  |  |        "-f", vid_fmt, | 
			
		
	
		
		
			
				
					
					|  |  |  |        "-i", "pipe:0", |  |  |  |        "-i", "pipe:0", | 
			
		
	
		
		
			
				
					
					|  |  |  |        "-threads", "0" if multithreaded else "1", |  |  |  |        "-threads", threads, | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  |        "-f", "rawvideo", |  |  |  |        "-f", "rawvideo", | 
			
		
	
		
		
			
				
					
					|  |  |  |        "-pix_fmt", pix_fmt, |  |  |  |        "-pix_fmt", pix_fmt, | 
			
		
	
		
		
			
				
					
					|  |  |  |        "pipe:1"], |  |  |  |        "pipe:1"], | 
			
		
	
	
		
		
			
				
					|  |  | @ -479,10 +479,9 @@ class StreamGOPReader(GOPReader): | 
			
		
	
		
		
			
				
					
					|  |  |  | class GOPFrameReader(BaseFrameReader): |  |  |  | class GOPFrameReader(BaseFrameReader): | 
			
		
	
		
		
			
				
					
					|  |  |  |   #FrameReader with caching and readahead for formats that are group-of-picture based |  |  |  |   #FrameReader with caching and readahead for formats that are group-of-picture based | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |   def __init__(self, readahead=False, readbehind=False, multithreaded=None): |  |  |  |   def __init__(self, readahead=False, readbehind=False): | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  |     self.open_ = True |  |  |  |     self.open_ = True | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |     self.multithreaded = multithreaded |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |     self.readahead = readahead |  |  |  |     self.readahead = readahead | 
			
		
	
		
		
			
				
					
					|  |  |  |     self.readbehind = readbehind |  |  |  |     self.readbehind = readbehind | 
			
		
	
		
		
			
				
					
					|  |  |  |     self.frame_cache = LRU(64) |  |  |  |     self.frame_cache = LRU(64) | 
			
		
	
	
		
		
			
				
					|  |  | @ -542,8 +541,7 @@ class GOPFrameReader(BaseFrameReader): | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |       frame_b, num_frames, skip_frames, rawdat = self.get_gop(num) |  |  |  |       frame_b, num_frames, skip_frames, rawdat = self.get_gop(num) | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |       ret = decompress_video_data(rawdat, self.vid_fmt, self.w, self.h, pix_fmt, |  |  |  |       ret = decompress_video_data(rawdat, self.vid_fmt, self.w, self.h, pix_fmt) | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |                                   multithreaded=self.multithreaded) |  |  |  |  | 
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  |       ret = ret[skip_frames:] |  |  |  |       ret = ret[skip_frames:] | 
			
		
	
		
		
			
				
					
					|  |  |  |       assert ret.shape[0] == num_frames |  |  |  |       assert ret.shape[0] == num_frames | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
	
		
		
			
				
					|  |  | @ -573,17 +571,17 @@ class GOPFrameReader(BaseFrameReader): | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  | class StreamFrameReader(StreamGOPReader, GOPFrameReader): |  |  |  | class StreamFrameReader(StreamGOPReader, GOPFrameReader): | 
			
		
	
		
		
			
				
					
					|  |  |  |   def __init__(self, fn, frame_type, index_data, readahead=False, readbehind=False, multithreaded=None): |  |  |  |   def __init__(self, fn, frame_type, index_data, readahead=False, readbehind=False): | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  |     StreamGOPReader.__init__(self, fn, frame_type, index_data) |  |  |  |     StreamGOPReader.__init__(self, fn, frame_type, index_data) | 
			
		
	
		
		
			
				
					
					|  |  |  |     GOPFrameReader.__init__(self, readahead, readbehind, multithreaded) |  |  |  |     GOPFrameReader.__init__(self, readahead, readbehind) | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  | def GOPFrameIterator(gop_reader, pix_fmt, multithreaded=None): |  |  |  | def GOPFrameIterator(gop_reader, pix_fmt): | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  |   # this is really ugly. ill think about how to refactor it when i can think good |  |  |  |   # this is really ugly. ill think about how to refactor it when i can think good | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |   IN_FLIGHT_GOPS = 6  # should be enough that the stream decompressor starts returning data |  |  |  |   IN_FLIGHT_GOPS = 6  # should be enough that the stream decompressor starts returning data | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |   with VideoStreamDecompressor(gop_reader.vid_fmt, gop_reader.w, gop_reader.h, pix_fmt, multithreaded) as dec: |  |  |  |   with VideoStreamDecompressor(gop_reader.vid_fmt, gop_reader.w, gop_reader.h, pix_fmt) as dec: | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  |     read_work = [] |  |  |  |     read_work = [] | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |     def readthing(): |  |  |  |     def readthing(): | 
			
		
	
	
		
		
			
				
					|  |  | @ -621,7 +619,7 @@ def GOPFrameIterator(gop_reader, pix_fmt, multithreaded=None): | 
			
		
	
		
		
			
				
					
					|  |  |  | def FrameIterator(fn, pix_fmt, **kwargs): |  |  |  | def FrameIterator(fn, pix_fmt, **kwargs): | 
			
		
	
		
		
			
				
					
					|  |  |  |   fr = FrameReader(fn, **kwargs) |  |  |  |   fr = FrameReader(fn, **kwargs) | 
			
		
	
		
		
			
				
					
					|  |  |  |   if isinstance(fr, GOPReader): |  |  |  |   if isinstance(fr, GOPReader): | 
			
		
	
		
		
			
				
					
					|  |  |  |     for v in GOPFrameIterator(fr, pix_fmt, kwargs.get("multithreaded", None)): |  |  |  |     for v in GOPFrameIterator(fr, pix_fmt): | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  |       yield v |  |  |  |       yield v | 
			
		
	
		
		
			
				
					
					|  |  |  |   else: |  |  |  |   else: | 
			
		
	
		
		
			
				
					
					|  |  |  |     for i in range(fr.frame_count): |  |  |  |     for i in range(fr.frame_count): | 
			
		
	
	
		
		
			
				
					|  |  | 
 |