generate-config-change-tests.py (9595B)
1 #!/usr/bin/python 2 # Copyright (C) 2013 Google Inc. All rights reserved. 3 # 4 # Redistribution and use in source and binary forms, with or without 5 # modification, are permitted provided that the following conditions are 6 # met: 7 # 8 # * Redistributions of source code must retain the above copyright 9 # notice, this list of conditions and the following disclaimer. 10 # * Redistributions in binary form must reproduce the above 11 # copyright notice, this list of conditions and the following disclaimer 12 # in the documentation and/or other materials provided with the 13 # distribution. 14 # * Neither the name of Google Inc. nor the names of its 15 # contributors may be used to endorse or promote products derived from 16 # this software without specific prior written permission. 17 # 18 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21 # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24 # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 30 """ 31 This is a script that generates the content and HTML files for Media Source 32 codec config change LayoutTests. 33 """ 34 import json 35 import os 36 37 DURATION = 2 38 MEDIA_FORMATS = ['webm', 'mp4'] 39 ENCODE_SETTINGS = [ 40 ## Video-only files 41 # Frame rate changes 42 {'fs': '320x240', 'fr': 24, 'kfr': 8, 'c': '#ff0000', 'vbr': 128, 'abr': 0, 'asr': 0, 'ach': 0, 'afreq': 0}, 43 {'fs': '320x240', 'fr': 30, 'kfr': 10, 'c': '#ff0000', 'vbr': 128, 'abr': 0, 'asr': 0, 'ach': 0, 'afreq': 0}, 44 # Frame size change 45 {'fs': '640x480', 'fr': 30, 'kfr': 10, 'c': '#00ff00', 'vbr': 128, 'abr': 0, 'asr': 0, 'ach': 0, 'afreq': 0}, 46 # Bitrate change 47 {'fs': '320x240', 'fr': 30, 'kfr': 10, 'c': '#ff00ff', 'vbr': 256, 'abr': 0, 'asr': 0, 'ach': 0, 'afreq': 0}, 48 49 ## Audio-only files 50 # Bitrate/Codebook changes 51 {'fs': '0x0', 'fr': 0, 'kfr': 0, 'c': '#000000', 'vbr': 0, 'abr': 128, 'asr': 44100, 'ach': 1, 'afreq': 2000}, 52 {'fs': '0x0', 'fr': 0, 'kfr': 0, 'c': '#000000', 'vbr': 0, 'abr': 192, 'asr': 44100, 'ach': 1, 'afreq': 4000}, 53 54 ## Audio-Video files 55 # Frame size change. 56 {'fs': '320x240', 'fr': 30, 'kfr': 10, 'c': '#ff0000', 'vbr': 256, 'abr': 128, 'asr': 44100, 'ach': 1, 'afreq': 2000}, 57 {'fs': '640x480', 'fr': 30, 'kfr': 10, 'c': '#00ff00', 'vbr': 256, 'abr': 128, 'asr': 44100, 'ach': 1, 'afreq': 2000}, 58 # Audio bitrate change. 59 {'fs': '640x480', 'fr': 30, 'kfr': 10, 'c': '#00ff00', 'vbr': 256, 'abr': 192, 'asr': 44100, 'ach': 1, 'afreq': 4000}, 60 # Video bitrate change. 61 {'fs': '640x480', 'fr': 30, 'kfr': 10, 'c': '#00ffff', 'vbr': 512, 'abr': 128, 'asr': 44100, 'ach': 1, 'afreq': 2000}, 62 ] 63 64 CONFIG_CHANGE_TESTS = [ 65 ["v-framerate", 0, 1, "Tests %s video-only frame rate changes."], 66 ["v-framesize", 1, 2, "Tests %s video-only frame size changes."], 67 ["v-bitrate", 1, 3, "Tests %s video-only bitrate changes."], 68 ["a-bitrate", 4, 5, "Tests %s audio-only bitrate changes."], 69 ["av-framesize", 6, 7, "Tests %s frame size changes in multiplexed content."], 70 ["av-audio-bitrate", 7, 8, "Tests %s audio bitrate changes in multiplexed content."], 71 ["av-video-bitrate", 7, 9, "Tests %s video bitrate changes in multiplexed content."] 72 ] 73 74 CODEC_INFO = { 75 "mp4": {"audio": "mp4a.40.2", "video": "avc1.4D4001"}, 76 "webm": {"audio": "vorbis", "video": "vp8"} 77 } 78 79 HTML_TEMPLATE = """<!DOCTYPE html> 80 <html> 81 <head> 82 <script src="/w3c/resources/testharness.js"></script> 83 <script src="/w3c/resources/testharnessreport.js"></script> 84 <script src="mediasource-util.js"></script> 85 <script src="mediasource-config-changes.js"></script> 86 </head> 87 <body> 88 <div id="log"></div> 89 <script> 90 mediaSourceConfigChangeTest("%(media_format)s", "%(idA)s", "%(idB)s", "%(description)s"); 91 </script> 92 </body> 93 </html> 94 """ 95 96 def run(cmd_line): 97 os.system(" ".join(cmd_line)) 98 99 def generate_manifest(filename, media_filename, media_format, has_audio, has_video): 100 major_type = "audio" 101 if has_video: 102 major_type = "video" 103 104 codecs = [] 105 if has_video: 106 codecs.append(CODEC_INFO[media_format]["video"]) 107 108 if has_audio: 109 codecs.append(CODEC_INFO[media_format]["audio"]) 110 111 mimetype = "%s/%s;codecs=\"%s\"" % (major_type, media_format, ",".join(codecs)) 112 113 manifest = { 'url': media_filename, 'type': mimetype} 114 115 f = open(filename, "wb") 116 f.write(json.dumps(manifest, indent=4, separators=(',', ': '))) 117 f.close() 118 119 def generate_test_html(media_format, config_change_tests, encoding_ids): 120 for test_info in config_change_tests: 121 filename = "../../media-source/mediasource-config-change-%s-%s.html" % (media_format, test_info[0]) 122 html = HTML_TEMPLATE % {'media_format': media_format, 123 'idA': encoding_ids[test_info[1]], 124 'idB': encoding_ids[test_info[2]], 125 'description': test_info[3] % (media_format)} 126 f = open(filename, "wb") 127 f.write(html) 128 f.close() 129 130 131 def main(): 132 encoding_ids = [] 133 134 for media_format in MEDIA_FORMATS: 135 run(["mkdir ", media_format]) 136 137 for settings in ENCODE_SETTINGS: 138 video_bitrate = settings['vbr'] 139 has_video = (video_bitrate > 0) 140 141 audio_bitrate = settings['abr'] 142 has_audio = (audio_bitrate > 0) 143 bitrate = video_bitrate + audio_bitrate 144 145 frame_size = settings['fs'] 146 frame_rate = settings['fr'] 147 keyframe_rate = settings['kfr'] 148 color = settings['c'] 149 150 sample_rate = settings['asr'] 151 channels = settings['ach'] 152 frequency = settings['afreq'] 153 154 cmdline = ["ffmpeg", "-y"] 155 156 id_prefix = "" 157 id_params = "" 158 if has_audio: 159 id_prefix += "a" 160 id_params += "-%sHz-%sch" % (sample_rate, channels) 161 162 channel_layout = "FC" 163 sin_func = "sin(%s*2*PI*t)" % frequency 164 func = sin_func 165 if channels == 2: 166 channel_layout += "|BC" 167 func += "|" + sin_func 168 169 cmdline += ["-f", "lavfi", "-i", "aevalsrc=\"%s:s=%s:c=%s:d=%s\"" % (func, sample_rate, channel_layout, DURATION)] 170 171 if has_video: 172 id_prefix += "v" 173 id_params += "-%s-%sfps-%skfr" % (frame_size, frame_rate, keyframe_rate) 174 175 cmdline += ["-f", "lavfi", "-i", "color=%s:duration=%s:size=%s:rate=%s" % (color, DURATION, frame_size, frame_rate)] 176 177 if has_audio: 178 cmdline += ["-b:a", "%sk" % audio_bitrate] 179 180 if has_video: 181 cmdline += ["-b:v", "%sk" % video_bitrate] 182 cmdline += ["-keyint_min", "%s" % keyframe_rate] 183 cmdline += ["-g", "%s" % keyframe_rate] 184 185 186 textOverlayInfo = "'drawtext=fontfile=Mono:fontsize=32:text=Time\\\\:\\\\ %{pts}" 187 textOverlayInfo += ",drawtext=fontfile=Mono:fontsize=32:y=32:text=Size\\\\:\\\\ %s" % (frame_size) 188 textOverlayInfo += ",drawtext=fontfile=Mono:fontsize=32:y=64:text=Bitrate\\\\:\\\\ %s" % (bitrate) 189 textOverlayInfo += ",drawtext=fontfile=Mono:fontsize=32:y=96:text=FrameRate\\\\:\\\\ %s" % (frame_rate) 190 textOverlayInfo += ",drawtext=fontfile=Mono:fontsize=32:y=128:text=KeyFrameRate\\\\:\\\\ %s" % (keyframe_rate) 191 192 if has_audio: 193 textOverlayInfo += ",drawtext=fontfile=Mono:fontsize=32:y=160:text=SampleRate\\\\:\\\\ %s" % (sample_rate) 194 textOverlayInfo += ",drawtext=fontfile=Mono:fontsize=32:y=192:text=Channels\\\\:\\\\ %s" % (channels) 195 196 textOverlayInfo += "'" 197 cmdline += ["-vf", textOverlayInfo] 198 199 encoding_id = "%s-%sk%s" % (id_prefix, bitrate, id_params) 200 201 if len(encoding_ids) < len(ENCODE_SETTINGS): 202 encoding_ids.append(encoding_id) 203 204 filename_base = "%s/test-%s" % (media_format, encoding_id) 205 media_filename = filename_base + "." + media_format 206 manifest_filename = filename_base + "-manifest.json" 207 208 cmdline.append(media_filename) 209 run(cmdline) 210 211 # Remux file so it conforms to MSE bytestream requirements. 212 if media_format == "webm": 213 tmp_filename = media_filename + ".tmp" 214 run(["mse_webm_remuxer", media_filename, tmp_filename]) 215 run(["mv", tmp_filename, media_filename]) 216 elif media_format == "mp4": 217 run(["MP4Box", "-dash", "250", "-rap", media_filename]) 218 run(["mv", filename_base + "_dash.mp4", media_filename]) 219 run(["rm", filename_base + "_dash.mpd"]) 220 221 generate_manifest(manifest_filename, media_filename, media_format, has_audio, has_video) 222 generate_test_html(media_format, CONFIG_CHANGE_TESTS, encoding_ids) 223 224 if '__main__' == __name__: 225 main()