| # Copyright 2021 The Chromium Authors. All rights reserved. | 
 | # 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 codec in video_codecs: | 
 |       yield ('WebCodecs_EncodeDecode_' + codec, 'encode-decode.html', [{ | 
 |           'codec': | 
 |           codec | 
 |       }]) | 
 |  | 
 |     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__]) |