2025-10-03 18:08:00 +02:00
|
|
|
# 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.
|
|
|
|
|
#
|
2025-10-03 18:15:25 +02:00
|
|
|
# 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.
|
2025-10-03 18:08:00 +02:00
|
|
|
#
|
2025-10-03 18:15:25 +02:00
|
|
|
# You should have received a copy of the GNU General Public License along with People's Video Editor.
|
2025-10-03 18:08:00 +02:00
|
|
|
# If not, see <https://www.gnu.org/licenses/>.
|
2025-10-03 15:10:49 +02:00
|
|
|
|
|
|
|
|
from . import libav
|
2025-10-03 16:55:38 +02:00
|
|
|
from .packet import Packet
|
2025-10-03 15:10:49 +02:00
|
|
|
from .frame import Frame
|
|
|
|
|
|
|
|
|
|
class Decoder:
|
2025-10-03 17:07:17 +02:00
|
|
|
__slots__ = '_context'
|
2025-10-03 15:10:49 +02:00
|
|
|
|
2025-10-04 17:39:37 +02:00
|
|
|
def __init__(self, stream, thread_count):
|
2025-10-03 16:55:38 +02:00
|
|
|
self._context = libav.codec_alloc_context(stream.codec)
|
|
|
|
|
if not self._context:
|
2025-10-03 15:10:49 +02:00
|
|
|
raise MemoryError
|
2025-10-03 16:55:38 +02:00
|
|
|
errcode = libav.codec_parameters_to_context(self._context, stream.parameters)
|
|
|
|
|
if errcode < 0:
|
|
|
|
|
libav.codec_free_context(self._context)
|
|
|
|
|
raise Exception("Failed to set context parameters")
|
2025-10-04 17:39:37 +02:00
|
|
|
if thread_count > 1:
|
|
|
|
|
self._context.contents.thread_count = thread_count
|
|
|
|
|
self._context.contents.thread_type = libav.FF_THREAD_FRAME
|
2025-10-03 16:55:38 +02:00
|
|
|
errcode = libav.codec_open(self._context, stream.codec)
|
2025-10-03 15:10:49 +02:00
|
|
|
if errcode < 0:
|
2025-10-03 16:55:38 +02:00
|
|
|
libav.codec_free_context(self._context)
|
2025-10-03 15:10:49 +02:00
|
|
|
raise Exception("Failed to open codec context")
|
|
|
|
|
|
|
|
|
|
def __del__(self):
|
2025-10-03 16:55:38 +02:00
|
|
|
if self._context:
|
|
|
|
|
libav.codec_free_context(self._context)
|
2025-10-03 15:10:49 +02:00
|
|
|
|
2025-10-04 04:27:24 +02:00
|
|
|
def decode(self, packet):
|
|
|
|
|
if not self._context:
|
|
|
|
|
return None
|
|
|
|
|
errcode = libav.codec_send_packet(self._context, packet)
|
|
|
|
|
if errcode < 0:
|
|
|
|
|
errstring = libav.strerror(errcode)
|
|
|
|
|
raise Exception(f"Failed to send packet: {errstring}")
|
2025-10-03 16:55:38 +02:00
|
|
|
frames = []
|
2025-10-03 15:10:49 +02:00
|
|
|
while True:
|
|
|
|
|
frame = Frame()
|
2025-10-03 16:55:38 +02:00
|
|
|
errcode = libav.codec_receive_frame(self._context, frame)
|
|
|
|
|
if errcode in (libav.AVERROR_EOF, libav.AVERROR_EAGAIN):
|
2025-10-03 15:10:49 +02:00
|
|
|
break
|
2025-10-03 16:55:38 +02:00
|
|
|
elif errcode < 0:
|
|
|
|
|
errstring = libav.strerror(errcode)
|
2025-10-03 17:16:14 +02:00
|
|
|
raise Exception(f"Failed to receive frame: {errstring}")
|
2025-10-03 16:55:38 +02:00
|
|
|
frames.append(frame)
|
|
|
|
|
return frames
|