1#!/usr/bin/env python 2# Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. 3# 4# Use of this source code is governed by a BSD-style license 5# that can be found in the LICENSE file in the root of the source 6# tree. An additional intellectual property rights grant can be found 7# in the file PATENTS. All contributing project authors may 8# be found in the AUTHORS file in the root of the source tree. 9 10import os 11import gviz_api 12import webrtc.data_helper 13 14def main(): 15 """ 16 This Python script displays a web page with test created with the 17 video_quality_measurement program, which is a tool in WebRTC. 18 19 The script requires on two external files and one Python library: 20 - A HTML template file with layout and references to the json variables 21 defined in this script 22 - A data file in Python format, containing the following: 23 - test_configuration - a dictionary of test configuration names and values. 24 - frame_data_types - a dictionary that maps the different metrics to their 25 data types. 26 - frame_data - a list of dictionaries where each dictionary maps a metric to 27 it's value. 28 - The gviz_api.py of the Google Visualization Python API, available at 29 http://code.google.com/p/google-visualization-python/ 30 31 The HTML file is shipped with the script, while the data file must be 32 generated by running video_quality_measurement with the --python flag 33 specified. 34 """ 35 print 'Content-type: text/html\n' # the newline is required! 36 37 page_template_filename = '../templates/chart_page_template.html' 38 # The data files must be located in the project tree for app engine being 39 # able to access them. 40 data_filenames = ['../data/vp8_sw.py', '../data/vp8_hw.py'] 41 # Will contain info/error messages to be displayed on the resulting page. 42 messages = [] 43 # Load the page HTML template. 44 try: 45 f = open(page_template_filename) 46 page_template = f.read() 47 f.close() 48 except IOError as e: 49 ShowErrorPage('Cannot open page template file: %s<br>Details: %s' % 50 (page_template_filename, e)) 51 return 52 53 # Read data from external Python script files. First check that they exist. 54 for filename in data_filenames: 55 if not os.path.exists(filename): 56 messages.append('Cannot open data file: %s' % filename) 57 data_filenames.remove(filename) 58 59 # Read data from all existing input files. 60 data_list = [] 61 test_configurations = [] 62 names = [] 63 64 for filename in data_filenames: 65 read_vars = {} # empty dictionary to load the data into. 66 execfile(filename, read_vars, read_vars) 67 68 test_configuration = read_vars['test_configuration'] 69 table_description = read_vars['frame_data_types'] 70 table_data = read_vars['frame_data'] 71 72 # Verify the data in the file loaded properly. 73 if not table_description or not table_data: 74 messages.append('Invalid input file: %s. Missing description list or ' 75 'data dictionary variables.' % filename) 76 continue 77 78 # Frame numbers appear as number type in the data, but Chart API requires 79 # values of the X-axis to be of string type. 80 # Change the frame_number column data type: 81 table_description['frame_number'] = ('string', 'Frame number') 82 # Convert all the values to string types: 83 for row in table_data: 84 row['frame_number'] = str(row['frame_number']) 85 86 # Store the unique data from this file in the high level lists. 87 test_configurations.append(test_configuration) 88 data_list.append(table_data) 89 # Name of the test run must be present. 90 test_name = FindConfiguration(test_configuration, 'name') 91 if not test_name: 92 messages.append('Invalid input file: %s. Missing configuration key ' 93 '"name"', filename) 94 continue 95 names.append(test_name) 96 97 # Create data helper and build data tables for each graph. 98 helper = webrtc.data_helper.DataHelper(data_list, table_description, 99 names, messages) 100 101 # Loading it into gviz_api.DataTable objects and create JSON strings. 102 description, data = helper.CreateConfigurationTable(test_configurations) 103 configurations = gviz_api.DataTable(description, data) 104 json_configurations = configurations.ToJSon() # pylint: disable=W0612 105 106 description, data = helper.CreateData('ssim') 107 ssim = gviz_api.DataTable(description, data) 108 # pylint: disable=W0612 109 json_ssim_data = ssim.ToJSon(helper.GetOrdering(description)) 110 111 description, data = helper.CreateData('psnr') 112 psnr = gviz_api.DataTable(description, data) 113 # pylint: disable=W0612 114 json_psnr_data = psnr.ToJSon(helper.GetOrdering(description)) 115 116 description, data = helper.CreateData('packets_dropped') 117 packet_loss = gviz_api.DataTable(description, data) 118 # pylint: disable=W0612 119 json_packet_loss_data = packet_loss.ToJSon(helper.GetOrdering(description)) 120 121 description, data = helper.CreateData('bit_rate') 122 # Add a column of data points for the desired bit rate to be plotted. 123 # (uses test configuration from the last data set, assuming it is the same 124 # for all of them) 125 desired_bit_rate = FindConfiguration(test_configuration, 'bit_rate_in_kbps') 126 if not desired_bit_rate: 127 ShowErrorPage('Cannot configuration field named "bit_rate_in_kbps"') 128 return 129 desired_bit_rate = int(desired_bit_rate) 130 # Add new column data type description. 131 description['desired_bit_rate'] = ('number', 'Desired bit rate (kbps)') 132 for row in data: 133 row['desired_bit_rate'] = desired_bit_rate 134 bit_rate = gviz_api.DataTable(description, data) 135 # pylint: disable=W0612 136 json_bit_rate_data = bit_rate.ToJSon(helper.GetOrdering(description)) 137 138 # Format the messages list with newlines. 139 messages = '\n'.join(messages) 140 141 # Put the variables as JSon strings into the template. 142 print page_template % vars() 143 144def FindConfiguration(configuration, name): 145 """ Finds a configuration value using it's name. 146 Returns the first configuration with a matching name. Returns None if no 147 matching configuration is found. """ 148 return_value = None 149 for row in configuration: 150 if row['name'] == name: 151 return_value = row['value'] 152 break 153 return return_value 154 155def ShowErrorPage(error_message): 156 print '<html><body>%s</body></html>' % error_message 157 158if __name__ == '__main__': 159 main() 160