|
|
|
@ -6,6 +6,7 @@ import math
|
|
|
|
from enum import Enum
|
|
|
|
from enum import Enum
|
|
|
|
from io import BytesIO
|
|
|
|
from io import BytesIO
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
import cv2
|
|
|
|
import numpy as np
|
|
|
|
import numpy as np
|
|
|
|
from PIL import Image
|
|
|
|
from PIL import Image
|
|
|
|
|
|
|
|
|
|
|
|
@ -43,6 +44,9 @@ class RandomAccessIterator:
|
|
|
|
self.pos = -1
|
|
|
|
self.pos = -1
|
|
|
|
|
|
|
|
|
|
|
|
class FrameProvider:
|
|
|
|
class FrameProvider:
|
|
|
|
|
|
|
|
VIDEO_FRAME_EXT = '.PNG'
|
|
|
|
|
|
|
|
VIDEO_FRAME_MIME = 'image/png'
|
|
|
|
|
|
|
|
|
|
|
|
class Quality(Enum):
|
|
|
|
class Quality(Enum):
|
|
|
|
COMPRESSED = 0
|
|
|
|
COMPRESSED = 0
|
|
|
|
ORIGINAL = 100
|
|
|
|
ORIGINAL = 100
|
|
|
|
@ -129,13 +133,14 @@ class FrameProvider:
|
|
|
|
|
|
|
|
|
|
|
|
return chunk_number_
|
|
|
|
return chunk_number_
|
|
|
|
|
|
|
|
|
|
|
|
@staticmethod
|
|
|
|
@classmethod
|
|
|
|
def _av_frame_to_png_bytes(av_frame):
|
|
|
|
def _av_frame_to_png_bytes(cls, av_frame):
|
|
|
|
pil_img = av_frame.to_image()
|
|
|
|
ext = cls.VIDEO_FRAME_EXT
|
|
|
|
buf = BytesIO()
|
|
|
|
image = av_frame.to_ndarray(format='bgr24')
|
|
|
|
pil_img.save(buf, format='PNG')
|
|
|
|
success, result = cv2.imencode(ext, image)
|
|
|
|
buf.seek(0)
|
|
|
|
if not success:
|
|
|
|
return buf
|
|
|
|
raise Exception("Failed to encode image to '%s' format" % (ext))
|
|
|
|
|
|
|
|
return BytesIO(result.tobytes())
|
|
|
|
|
|
|
|
|
|
|
|
def _convert_frame(self, frame, reader_class, out_type):
|
|
|
|
def _convert_frame(self, frame, reader_class, out_type):
|
|
|
|
if out_type == self.Type.BUFFER:
|
|
|
|
if out_type == self.Type.BUFFER:
|
|
|
|
@ -144,11 +149,11 @@ class FrameProvider:
|
|
|
|
return frame.to_image() if reader_class is VideoReader else Image.open(frame)
|
|
|
|
return frame.to_image() if reader_class is VideoReader else Image.open(frame)
|
|
|
|
elif out_type == self.Type.NUMPY_ARRAY:
|
|
|
|
elif out_type == self.Type.NUMPY_ARRAY:
|
|
|
|
if reader_class is VideoReader:
|
|
|
|
if reader_class is VideoReader:
|
|
|
|
image = np.array(frame.to_image())
|
|
|
|
image = frame.to_ndarray(format='bgr24')
|
|
|
|
else:
|
|
|
|
else:
|
|
|
|
image = np.array(Image.open(frame))
|
|
|
|
image = np.array(Image.open(frame))
|
|
|
|
if len(image.shape) == 3 and image.shape[2] in {3, 4}:
|
|
|
|
if len(image.shape) == 3 and image.shape[2] in {3, 4}:
|
|
|
|
image[:, :, :3] = image[:, :, 2::-1] # RGB to BGR
|
|
|
|
image[:, :, :3] = image[:, :, 2::-1] # RGB to BGR
|
|
|
|
return image
|
|
|
|
return image
|
|
|
|
else:
|
|
|
|
else:
|
|
|
|
raise Exception('unsupported output type')
|
|
|
|
raise Exception('unsupported output type')
|
|
|
|
@ -171,7 +176,7 @@ class FrameProvider:
|
|
|
|
|
|
|
|
|
|
|
|
frame = self._convert_frame(frame, loader.reader_class, out_type)
|
|
|
|
frame = self._convert_frame(frame, loader.reader_class, out_type)
|
|
|
|
if loader.reader_class is VideoReader:
|
|
|
|
if loader.reader_class is VideoReader:
|
|
|
|
return (frame, 'image/png')
|
|
|
|
return (frame, self.VIDEO_FRAME_MIME)
|
|
|
|
return (frame, mimetypes.guess_type(frame_name))
|
|
|
|
return (frame, mimetypes.guess_type(frame_name))
|
|
|
|
|
|
|
|
|
|
|
|
def get_frames(self, quality=Quality.ORIGINAL, out_type=Type.BUFFER):
|
|
|
|
def get_frames(self, quality=Quality.ORIGINAL, out_type=Type.BUFFER):
|
|
|
|
|