165 lines
4.1 KiB
Python
165 lines
4.1 KiB
Python
# People's Video Editor: high quality, GPU accelerated mp4 editor
|
|
# Copyright (C) 2025 Roz K <roz@rozk.net>
|
|
#
|
|
# This file is part of People's Video Editor.
|
|
#
|
|
# People's Video Editor is free software: you can redistribute it and/or modify it under the terms of the
|
|
# GNU General Public License as published by the Free Software Foundation, either version 3 of the License,
|
|
# or (at your option) any later version.
|
|
#
|
|
# People's Video Editor is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
|
# without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
|
# See the GNU General Public License for more details.
|
|
#
|
|
# You should have received a copy of the GNU General Public License along with People's Video Editor.
|
|
# If not, see <https://www.gnu.org/licenses/>.
|
|
|
|
#TODO: split channels
|
|
|
|
import itertools
|
|
from array import array
|
|
|
|
_X, _Y, _U, _V, _Channels = itertools.count(0)
|
|
_Type = 'f'
|
|
_Size = array(_Type).itemsize * _Channels
|
|
|
|
class Vertex:
|
|
__slots__ = 'view'
|
|
|
|
Type = _Type
|
|
Channels = _Channels
|
|
Size = _Size
|
|
|
|
def __init__(self, view):
|
|
assert isinstance(view, memoryview)
|
|
self.view = view
|
|
|
|
def __del__(self):
|
|
del self.view
|
|
|
|
@property
|
|
def xy(self):
|
|
return self.view[_X], self.view[_Y]
|
|
|
|
@xy.setter
|
|
def xy(self, value):
|
|
self.view[_X], self.view[_Y] = value
|
|
|
|
@property
|
|
def x(self):
|
|
return self.view[_X]
|
|
|
|
@x.setter
|
|
def x(self, value):
|
|
self.view[_X] = value
|
|
|
|
@property
|
|
def y(self):
|
|
return self.view[_Y]
|
|
|
|
@y.setter
|
|
def y(self, value):
|
|
self.view[_Y] = value
|
|
|
|
@property
|
|
def uv(self):
|
|
return self.view[_U], self.view[_V]
|
|
|
|
@uv.setter
|
|
def uv(self, value):
|
|
self.view[_U], self.view[_V] = value
|
|
|
|
@property
|
|
def u(self):
|
|
return self.view[_U]
|
|
|
|
@u.setter
|
|
def u(self, value):
|
|
self.view[_U] = value
|
|
|
|
@property
|
|
def v(self):
|
|
return self.view[_V]
|
|
|
|
@v.setter
|
|
def v(self, value):
|
|
self.view[_V] = value
|
|
|
|
class Shape:
|
|
__slots__ = '_array', '_view', '_size', '_cutouts'
|
|
|
|
@classmethod
|
|
def rectangle(cls, geometry):
|
|
shape = cls(size = 4)
|
|
tl = Vertex(shape[0])
|
|
tl.xy = tl.uv = (0.0, 0.0)
|
|
tr = Vertex(shape[1])
|
|
tr.xy = tr.uv = (geometry._width, 0.0)
|
|
br = Vertex(shape[2])
|
|
br.xy = br.uv = (geometry._width, geometry._height)
|
|
bl = Vertex(shape[3])
|
|
bl.xy = bl.uv = (0.0, geometry._height)
|
|
return shape
|
|
|
|
def __init__(self, size = 0, cutouts = None):
|
|
self._array = array(_Type, bytes(size * _Size))
|
|
self._view = memoryview(self._array)
|
|
self._size = size
|
|
self._cutouts = list(cutouts) if cutouts else None
|
|
|
|
def __del__(self):
|
|
del self._view
|
|
del self._array
|
|
del self._cutouts
|
|
|
|
def __len__(self):
|
|
return self._size
|
|
|
|
def __getitem__(self, index):
|
|
index *= _Channels
|
|
return self._view[index:(index + _Channels)]
|
|
|
|
@property
|
|
def size(self):
|
|
return self._size
|
|
|
|
@property
|
|
def view(self):
|
|
return self._view
|
|
|
|
@property
|
|
def cutouts(self):
|
|
return list(self._cutouts) if self._cutouts else []
|
|
|
|
@cutouts.setter
|
|
def cutouts(self, value):
|
|
self._cutouts = list(value) if value else None
|
|
|
|
def append(self, count = 1):
|
|
index = self._size
|
|
self._view.release()
|
|
self._array.frombytes(bytes(count * _Size))
|
|
self._view = memoryview(self._array)
|
|
self._size += count
|
|
return index
|
|
|
|
def insert(self, index, count = 1):
|
|
index *= _Channels
|
|
self._view.release()
|
|
self._array[index:index] = array(_Type, bytes(count * _Size))
|
|
self._view = memoryview(self._array)
|
|
self._size += count
|
|
|
|
def remove(self, index, count = 1):
|
|
index *= _Channels
|
|
self._view.release()
|
|
del self._array[index:(index + count * _Channels)]
|
|
self._view = memoryview(self._array)
|
|
self._size -= count
|
|
|
|
def clear(self):
|
|
self._view.release()
|
|
self._array = array(_Type)
|
|
self._view = memoryview(self._array)
|
|
self._size = 0
|