| # Copyright 2021 The Chromium Authors |
| # Use of this source code is governed by a BSD-style license that can be |
| # found in the LICENSE file. |
| |
| import os |
| import sys |
| import json |
| import itertools |
| from typing import Any, List |
| import unittest |
| |
| import gpu_path_util |
| from gpu_tests import common_typing as ct |
| from gpu_tests import gpu_integration_test |
| |
| html_path = os.path.join(gpu_path_util.CHROMIUM_SRC_DIR, 'content', 'test', |
| 'data', 'gpu', 'webcodecs') |
| data_path = os.path.join(gpu_path_util.CHROMIUM_SRC_DIR, 'media', 'test', |
| 'data') |
| four_colors_img_path = os.path.join(data_path, 'four-colors.y4m') |
| |
| frame_sources = [ |
| 'camera', 'capture', 'offscreen', 'arraybuffer', 'hw_decoder', 'sw_decoder' |
| ] |
| video_codecs = ['avc1.42001E', 'vp8', 'vp09.00.10.08', 'av01.0.04M.08'] |
| accelerations = ['prefer-hardware', 'prefer-software'] |
| |
| |
| class WebCodecsIntegrationTest(gpu_integration_test.GpuIntegrationTest): |
| @classmethod |
| def Name(cls) -> str: |
| return 'webcodecs' |
| |
| # pylint: disable=too-many-branches |
| |
| @classmethod |
| def GenerateGpuTests(cls, options: ct.ParsedCmdArgs) -> ct.TestGenerator: |
| tests = itertools.chain(cls.GenerateFrameTests(), cls.GenerateVideoTests(), |
| cls.GenerateAudioTests()) |
| for test in tests: |
| yield test |
| |
| @classmethod |
| def GenerateFrameTests(cls) -> ct.TestGenerator: |
| for source_type in frame_sources: |
| yield ('WebCodecs_DrawImage_' + source_type, 'draw-image.html', [{ |
| 'source_type': |
| source_type |
| }]) |
| yield ('WebCodecs_TexImage2d_' + source_type, 'tex-image-2d.html', [{ |
| 'source_type': |
| source_type |
| }]) |
| yield ('WebCodecs_copyTo_' + source_type, 'copyTo.html', [{ |
| 'source_type': |
| source_type |
| }]) |
| yield ('WebCodecs_GPUExternalTexture_expired_' + source_type, |
| 'gpu-external-texture-expired.html', [{ |
| 'source_type': source_type, |
| 'use_worker': False |
| }]) |
| yield ('WebCodecs_GPUExternalTexture_expired_worker_' + source_type, |
| 'gpu-external-texture-expired.html', [{ |
| 'source_type': source_type, |
| 'use_worker': True |
| }]) |
| yield ('WebCodecs_device_destroy_expired_texture_' + source_type, |
| 'gpu-device-destroy-expire-active-external-texture.html', [{ |
| 'source_type': |
| source_type, |
| 'device_destroyed_before_import': |
| False |
| }]) |
| yield ('WebCodecs_texture_expired_from_destroyed_device_' + source_type, |
| 'gpu-device-destroy-expire-active-external-texture.html', [{ |
| 'source_type': |
| source_type, |
| 'device_destroyed_before_import': |
| True |
| }]) |
| |
| @classmethod |
| def GenerateAudioTests(cls) -> ct.TestGenerator: |
| yield ('WebCodecs_AudioEncoding_AAC_LC', 'audio-encode-decode.html', [{ |
| 'codec': |
| 'mp4a.67', |
| 'sample_rate': |
| 48000, |
| 'channels': |
| 2 |
| }]) |
| |
| @classmethod |
| def GenerateVideoTests(cls) -> ct.TestGenerator: |
| yield ('WebCodecs_WebRTCPeerConnection_Window', |
| 'webrtc-peer-connection.html', [{ |
| 'use_worker': False |
| }]) |
| yield ('WebCodecs_WebRTCPeerConnection_Worker', |
| 'webrtc-peer-connection.html', [{ |
| 'use_worker': True |
| }]) |
| |
| for source_type in ['offscreen', 'arraybuffer']: |
| for codec in video_codecs: |
| for acc in accelerations: |
| args = (source_type, codec, acc) |
| yield ('WebCodecs_EncodeDecode_%s_%s_%s' % args, 'encode-decode.html', |
| [{ |
| 'source_type': source_type, |
| 'codec': codec, |
| 'acceleration': acc |
| }]) |
| |
| for source_type in frame_sources: |
| for codec in video_codecs: |
| for acc in accelerations: |
| args = (source_type, codec, acc) |
| yield ('WebCodecs_Encode_%s_%s_%s' % args, 'encode.html', [{ |
| 'source_type': |
| source_type, |
| 'codec': |
| codec, |
| 'acceleration': |
| acc |
| }]) |
| |
| for codec in video_codecs: |
| for acc in accelerations: |
| for bitrate_mode in ['constant', 'variable']: |
| for latency_mode in ['realtime', 'quality']: |
| source_type = 'offscreen' |
| args = (source_type, codec, acc, bitrate_mode, latency_mode) |
| yield ('WebCodecs_EncodingModes_%s_%s_%s_%s_%s' % args, |
| 'encoding-modes.html', [{ |
| 'source_type': source_type, |
| 'codec': codec, |
| 'acceleration': acc, |
| 'bitrate_mode': bitrate_mode, |
| 'latency_mode': latency_mode |
| }]) |
| |
| for codec in video_codecs: |
| for layers in [2, 3]: |
| args = (codec, layers) |
| yield ('WebCodecs_SVC_%s_layers_%d' % args, 'svc.html', [{ |
| 'codec': |
| codec, |
| 'layers': |
| layers |
| }]) |
| |
| for codec in video_codecs: |
| for acc in accelerations: |
| args = (codec, acc) |
| yield ('WebCodecs_EncodeColorSpace_%s_%s' % args, |
| 'encode-color-space.html', [{ |
| 'codec': codec, |
| 'acceleration': acc |
| }]) |
| # pylint: enable=too-many-branches |
| |
| def RunActualGpuTest(self, test_path: str, args: ct.TestArgs) -> None: |
| url = self.UrlOfStaticFilePath(html_path + '/' + test_path) |
| tab = self.tab |
| arg_obj = args[0] |
| os_name = self.platform.GetOSName() |
| arg_obj['validate_camera_frames'] = self.CameraCanShowFourColors(os_name) |
| tab.Navigate(url) |
| tab.action_runner.WaitForJavaScriptCondition( |
| 'document.readyState == "complete"') |
| tab.EvaluateJavaScript('TEST.run(' + json.dumps(arg_obj) + ')') |
| tab.action_runner.WaitForJavaScriptCondition('TEST.finished', timeout=60) |
| if tab.EvaluateJavaScript('TEST.skipped'): |
| self.skipTest('Skipping test:' + tab.EvaluateJavaScript('TEST.summary()')) |
| if not tab.EvaluateJavaScript('TEST.success'): |
| self.fail('Test failure:' + tab.EvaluateJavaScript('TEST.summary()')) |
| |
| @staticmethod |
| def CameraCanShowFourColors(os_name: str) -> bool: |
| return os_name not in ('android', 'chromeos') |
| |
| @classmethod |
| def SetUpProcess(cls) -> None: |
| super(WebCodecsIntegrationTest, cls).SetUpProcess() |
| args = [ |
| '--use-fake-device-for-media-stream', '--use-fake-ui-for-media-stream', |
| '--enable-unsafe-webgpu' |
| ] |
| |
| # If we don't call CustomizeBrowserArgs cls.platform is None |
| cls.CustomizeBrowserArgs(args) |
| platform = cls.platform |
| |
| if cls.CameraCanShowFourColors(platform.GetOSName()): |
| args.append('--use-file-for-fake-video-capture=' + four_colors_img_path) |
| cls.CustomizeBrowserArgs(args) |
| |
| cls.StartBrowser() |
| cls.SetStaticServerDirs([html_path, data_path]) |
| |
| @classmethod |
| def ExpectationsFiles(cls) -> List[str]: |
| return [ |
| os.path.join(os.path.dirname(os.path.abspath(__file__)), |
| 'test_expectations', 'webcodecs_expectations.txt') |
| ] |
| |
| |
| def load_tests(loader: unittest.TestLoader, tests: Any, |
| pattern: Any) -> unittest.TestSuite: |
| del loader, tests, pattern # Unused. |
| return gpu_integration_test.LoadAllTestsInModule(sys.modules[__name__]) |