OLD | NEW |
(Empty) | |
| 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': 12
8, 'asr': 44100, 'ach': 1, 'afreq': 2000}, |
| 57 {'fs': '640x480', 'fr': 30, 'kfr': 10, 'c': '#00ff00', 'vbr': 256, 'abr': 12
8, 'asr': 44100, 'ach': 1, 'afreq': 2000}, |
| 58 # Audio bitrate change. |
| 59 {'fs': '640x480', 'fr': 30, 'kfr': 10, 'c': '#00ff00', 'vbr': 256, 'abr': 19
2, 'asr': 44100, 'ach': 1, 'afreq': 4000}, |
| 60 # Video bitrate change. |
| 61 {'fs': '640x480', 'fr': 30, 'kfr': 10, 'c': '#00ffff', 'vbr': 512, 'abr': 12
8, '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 co
ntent."], |
| 71 ["av-video-bitrate", 7, 9, "Tests %s video bitrate changes in multiplexed co
ntent."] |
| 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 <link rel="stylesheet" href="/w3c/resources/testharness.css"> |
| 87 </head> |
| 88 <body> |
| 89 <div id="log"></div> |
| 90 <script> |
| 91 mediaSourceConfigChangeTest("%(media_format)s", "%(idA)s", "%(idB)s"
, "%(description)s"); |
| 92 </script> |
| 93 </body> |
| 94 </html> |
| 95 """ |
| 96 |
| 97 def run(cmd_line): |
| 98 os.system(" ".join(cmd_line)) |
| 99 |
| 100 def generate_manifest(filename, media_filename, media_format, has_audio, has_vid
eo): |
| 101 major_type = "audio" |
| 102 if has_video: |
| 103 major_type = "video" |
| 104 |
| 105 codecs = [] |
| 106 if has_video: |
| 107 codecs.append(CODEC_INFO[media_format]["video"]) |
| 108 |
| 109 if has_audio: |
| 110 codecs.append(CODEC_INFO[media_format]["audio"]) |
| 111 |
| 112 mimetype = "%s/%s;codecs=\"%s\"" % (major_type, media_format, ",".join(codec
s)) |
| 113 |
| 114 manifest = { 'url': media_filename, 'type': mimetype} |
| 115 |
| 116 f = open(filename, "wb") |
| 117 f.write(json.dumps(manifest, indent=4, separators=(',', ': '))) |
| 118 f.close() |
| 119 |
| 120 def generate_test_html(media_format, config_change_tests, encoding_ids): |
| 121 for test_info in config_change_tests: |
| 122 filename = "../../media-source/mediasource-config-change-%s-%s.html" % (
media_format, test_info[0]) |
| 123 html = HTML_TEMPLATE % {'media_format': media_format, |
| 124 'idA': encoding_ids[test_info[1]], |
| 125 'idB': encoding_ids[test_info[2]], |
| 126 'description': test_info[3] % (media_format)} |
| 127 f = open(filename, "wb") |
| 128 f.write(html) |
| 129 f.close() |
| 130 |
| 131 |
| 132 def main(): |
| 133 encoding_ids = [] |
| 134 |
| 135 for media_format in MEDIA_FORMATS: |
| 136 run(["mkdir ", media_format]) |
| 137 |
| 138 for settings in ENCODE_SETTINGS: |
| 139 video_bitrate = settings['vbr'] |
| 140 has_video = (video_bitrate > 0) |
| 141 |
| 142 audio_bitrate = settings['abr'] |
| 143 has_audio = (audio_bitrate > 0) |
| 144 bitrate = video_bitrate + audio_bitrate |
| 145 |
| 146 frame_size = settings['fs'] |
| 147 frame_rate = settings['fr'] |
| 148 keyframe_rate = settings['kfr'] |
| 149 color = settings['c'] |
| 150 |
| 151 sample_rate = settings['asr'] |
| 152 channels = settings['ach'] |
| 153 frequency = settings['afreq'] |
| 154 |
| 155 cmdline = ["ffmpeg", "-y"] |
| 156 |
| 157 id_prefix = "" |
| 158 id_params = "" |
| 159 if has_audio: |
| 160 id_prefix += "a" |
| 161 id_params += "-%sHz-%sch" % (sample_rate, channels) |
| 162 |
| 163 channel_layout = "FC" |
| 164 sin_func = "sin(%s*2*PI*t)" % frequency |
| 165 func = sin_func |
| 166 if channels == 2: |
| 167 channel_layout += "|BC" |
| 168 func += "|" + sin_func |
| 169 |
| 170 cmdline += ["-f", "lavfi", "-i", "aevalsrc=\"%s:s=%s:c=%s:d=%s\"
" % (func, sample_rate, channel_layout, DURATION)] |
| 171 |
| 172 if has_video: |
| 173 id_prefix += "v" |
| 174 id_params += "-%s-%sfps-%skfr" % (frame_size, frame_rate, keyfra
me_rate) |
| 175 |
| 176 cmdline += ["-f", "lavfi", "-i", "color=%s:duration=%s:size=%s:r
ate=%s" % (color, DURATION, frame_size, frame_rate)] |
| 177 |
| 178 if has_audio: |
| 179 cmdline += ["-b:a", "%sk" % audio_bitrate] |
| 180 |
| 181 if has_video: |
| 182 cmdline += ["-b:v", "%sk" % video_bitrate] |
| 183 cmdline += ["-keyint_min", "%s" % keyframe_rate] |
| 184 cmdline += ["-g", "%s" % keyframe_rate] |
| 185 |
| 186 |
| 187 textOverlayInfo = "'drawtext=fontfile=Mono:fontsize=32:text=Time
\\\\:\\\\ %{pts}" |
| 188 textOverlayInfo += ",drawtext=fontfile=Mono:fontsize=32:y=32:tex
t=Size\\\\:\\\\ %s" % (frame_size) |
| 189 textOverlayInfo += ",drawtext=fontfile=Mono:fontsize=32:y=64:tex
t=Bitrate\\\\:\\\\ %s" % (bitrate) |
| 190 textOverlayInfo += ",drawtext=fontfile=Mono:fontsize=32:y=96:tex
t=FrameRate\\\\:\\\\ %s" % (frame_rate) |
| 191 textOverlayInfo += ",drawtext=fontfile=Mono:fontsize=32:y=128:te
xt=KeyFrameRate\\\\:\\\\ %s" % (keyframe_rate) |
| 192 |
| 193 if has_audio: |
| 194 textOverlayInfo += ",drawtext=fontfile=Mono:fontsize=32:y=16
0:text=SampleRate\\\\:\\\\ %s" % (sample_rate) |
| 195 textOverlayInfo += ",drawtext=fontfile=Mono:fontsize=32:y=19
2:text=Channels\\\\:\\\\ %s" % (channels) |
| 196 |
| 197 textOverlayInfo += "'" |
| 198 cmdline += ["-vf", textOverlayInfo] |
| 199 |
| 200 encoding_id = "%s-%sk%s" % (id_prefix, bitrate, id_params) |
| 201 |
| 202 if len(encoding_ids) < len(ENCODE_SETTINGS): |
| 203 encoding_ids.append(encoding_id) |
| 204 |
| 205 filename_base = "%s/test-%s" % (media_format, encoding_id) |
| 206 media_filename = filename_base + "." + media_format |
| 207 manifest_filename = filename_base + "-manifest.json" |
| 208 |
| 209 cmdline.append(media_filename) |
| 210 run(cmdline) |
| 211 |
| 212 # Remux file so it conforms to MSE bytestream requirements. |
| 213 if media_format == "webm": |
| 214 tmp_filename = media_filename + ".tmp" |
| 215 run(["mse_webm_remuxer", media_filename, tmp_filename]) |
| 216 run(["mv", tmp_filename, media_filename]) |
| 217 elif media_format == "mp4": |
| 218 run(["MP4Box", "-dash", "250", "-rap", media_filename]) |
| 219 run(["mv", filename_base + "_dash.mp4", media_filename]) |
| 220 run(["rm", filename_base + "_dash.mpd"]) |
| 221 |
| 222 generate_manifest(manifest_filename, media_filename, media_format, h
as_audio, has_video) |
| 223 generate_test_html(media_format, CONFIG_CHANGE_TESTS, encoding_ids) |
| 224 |
| 225 if '__main__' == __name__: |
| 226 main() |
OLD | NEW |