Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -324,6 +324,7 @@ H.266
MPEG2_VIDEO
FFmpeg-MPEG2_VIDEO: FFmpeg MPEG2 VIDEO SW decoder
Fluendo-MPEG2_VIDEO-SW-Gst1.0: Fluendo MPEG2 VIDEO SW decoder for GStreamer 1.0
ISO-MPEG2-VIDEO: ISO MPEG2 Video reference decoder

VP8
FFmpeg-VP8: FFmpeg VP8 SW decoder
Expand Down
5 changes: 3 additions & 2 deletions check/dummy.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,5 +11,6 @@
"output_format": "yuv420p",
"result": "19b8d716307ae8b28c81b21f14f870dc"
}
]
}
],
"test_method": "md5"
}
16 changes: 15 additions & 1 deletion fluster/decoder.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
from abc import ABC, abstractmethod
from functools import lru_cache
from shutil import which
from typing import List, Type
from typing import List, Optional, Type

from fluster.codec import Codec, OutputFormat
from fluster.utils import normalize_binary_cmd
Expand All @@ -32,6 +32,7 @@ class Decoder(ABC):
hw_acceleration = False
description = ""
binary = ""
is_reference = False

def __init__(self) -> None:
if self.binary:
Expand Down Expand Up @@ -76,3 +77,16 @@ def register_decoder(cls: Type[Decoder]) -> Type[Decoder]:
DECODERS.append(cls())
DECODERS.sort(key=lambda dec: dec.name)
return cls


def get_reference_decoder_for_codec(codec: Codec) -> Optional["Decoder"]:
"""Find the reference decoder for a specific codec"""

reference_decoders = [d for d in DECODERS if d.codec == codec and d.is_reference]

if not reference_decoders:
return None
if len(reference_decoders) > 1:
print(f"Multiple reference decoders found for codec {codec.name}")

return reference_decoders[0]
1 change: 1 addition & 0 deletions fluster/decoders/iso_mpeg2_aac.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ class ISOAACDecoder(Decoder):
description = "ISO MPEG2 AAC reference decoder"
codec = Codec.AAC
binary = "aacdec_mc"
is_reference = True

def decode(
self,
Expand Down
85 changes: 85 additions & 0 deletions fluster/decoders/iso_mpeg2_video.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
# Fluster - testing framework for decoders conformance
# Copyright (C) 2024, Fluendo, S.A.
# Author: Rubén Sánchez <rsanchez@fluendo.com>, Fluendo, S.A.
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public License
# as published by the Free Software Foundation, either version 3
# of the License, or (at your option) any later version.
#
# This library 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
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library. If not, see <https://www.gnu.org/licenses/>.
import glob
import os
import tempfile

from fluster.codec import Codec, OutputFormat
from fluster.decoder import Decoder, register_decoder
from fluster.utils import file_checksum, run_command


@register_decoder
class ISOMPEG2VDecoder(Decoder):
"""ISO MPEG2 Video reference decoder implementation"""

name = "ISO-MPEG2-VIDEO"
description = "ISO MPEG2 Video reference decoder"
codec = Codec.MPEG2_VIDEO
binary = "mpeg2decode"
is_reference = True

def decode(
self,
input_filepath: str,
output_filepath: str,
output_format: OutputFormat,
timeout: int,
verbose: bool,
keep_files: bool,
) -> str:
"""Decodes input_filepath in output_filepath"""
with tempfile.TemporaryDirectory() as temp_dir:
run_command(
[self.binary, "-b", input_filepath, "-f", "-r", "-o0", os.path.join(temp_dir, "rec%d")],
timeout=timeout,
verbose=verbose,
)
self._merge_yuv_files(temp_dir, output_filepath)
checksum = file_checksum(output_filepath)

if not keep_files:
os.remove(output_filepath)

return checksum

@staticmethod
def _merge_yuv_files(input_dir: str, output_filepath: str) -> None:
"""Merge YUV frames into an only raw .yuv file for mpeg2 video test suite"""
num_frames = len(glob.glob(os.path.join(input_dir, "rec*.Y")))

if num_frames == 0:
raise ValueError("No frames were decoded")

with open(output_filepath, "wb") as output_file:
for frame_num in range(num_frames):
frame_name = f"rec{frame_num}"
y_file = os.path.join(input_dir, f"{frame_name}.Y")
u_file = os.path.join(input_dir, f"{frame_name}.U")
v_file = os.path.join(input_dir, f"{frame_name}.V")

if not (os.path.exists(y_file) and os.path.exists(u_file) and os.path.exists(v_file)):
print(f"Warning: Files for frame {frame_name} not found in {input_dir}")
continue

chunk_size = 1024
for plane_file in [y_file, u_file, v_file]:
with open(plane_file, "rb") as file:
chunk = file.read(chunk_size)
Comment thread
ylatuya marked this conversation as resolved.
while chunk:
output_file.write(chunk)
chunk = file.read(chunk_size)
1 change: 1 addition & 0 deletions fluster/decoders/iso_mpeg4_aac.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ class ISOAACDecoder(Decoder):
description = "ISO MPEG4 AAC reference decoder"
codec = Codec.AAC
binary = "mp4audec_mc"
is_reference = True

def decode(
self,
Expand Down
1 change: 1 addition & 0 deletions fluster/decoders/iso_mpeg4_aac_er.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ class ISOAACDecoder(Decoder):
description = "ISO MPEG4 AAC ER reference decoder"
codec = Codec.AAC
binary = "mp4audec"
is_reference = True

def decode(
self,
Expand Down
4 changes: 3 additions & 1 deletion fluster/fluster.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@
from fluster.decoders import * # noqa: F403
from fluster.decoders.av1_aom import AV1AOMDecoder
from fluster.test_suite import Context as TestSuiteContext
from fluster.test_suite import TestSuite
from fluster.test_suite import TestMethod, TestSuite
from fluster.test_vector import TestVector, TestVectorResult


Expand Down Expand Up @@ -278,6 +278,8 @@ def run_test_suites(self, ctx: Context) -> None:
decoder.multiple_layers = True
if decoder.codec != test_suite.codec:
continue
if test_suite.test_method == TestMethod.PIXEL and decoder.is_reference:
continue
test_suite_res = test_suite.run(
ctx.to_test_suite_context(
decoder,
Expand Down
Loading