| #!/usr/bin/env python |
| # Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. |
| # |
| # Use of this source code is governed by a BSD-style license |
| # that can be found in the LICENSE file in the root of the source |
| # tree. An additional intellectual property rights grant can be found |
| # in the file PATENTS. All contributing project authors may |
| # be found in the AUTHORS file in the root of the source tree. |
| |
| import os |
| import gviz_api |
| import webrtc.data_helper |
| |
| def main(): |
| """ |
| This Python script displays a web page with test created with the |
| video_quality_measurement program, which is a tool in WebRTC. |
| |
| The script requires on two external files and one Python library: |
| - A HTML template file with layout and references to the json variables |
| defined in this script |
| - A data file in Python format, containing the following: |
| - test_configuration - a dictionary of test configuration names and values. |
| - frame_data_types - a dictionary that maps the different metrics to their |
| data types. |
| - frame_data - a list of dictionaries where each dictionary maps a metric to |
| it's value. |
| - The gviz_api.py of the Google Visualization Python API, available at |
| http://code.google.com/p/google-visualization-python/ |
| |
| The HTML file is shipped with the script, while the data file must be |
| generated by running video_quality_measurement with the --python flag |
| specified. |
| """ |
| print 'Content-type: text/html\n' # the newline is required! |
| |
| page_template_filename = '../templates/chart_page_template.html' |
| # The data files must be located in the project tree for app engine being |
| # able to access them. |
| data_filenames = ['../data/vp8_sw.py', '../data/vp8_hw.py'] |
| # Will contain info/error messages to be displayed on the resulting page. |
| messages = [] |
| # Load the page HTML template. |
| try: |
| f = open(page_template_filename) |
| page_template = f.read() |
| f.close() |
| except IOError as e: |
| ShowErrorPage('Cannot open page template file: %s<br>Details: %s' % |
| (page_template_filename, e)) |
| return |
| |
| # Read data from external Python script files. First check that they exist. |
| for filename in data_filenames: |
| if not os.path.exists(filename): |
| messages.append('Cannot open data file: %s' % filename) |
| data_filenames.remove(filename) |
| |
| # Read data from all existing input files. |
| data_list = [] |
| test_configurations = [] |
| names = [] |
| |
| for filename in data_filenames: |
| read_vars = {} # empty dictionary to load the data into. |
| execfile(filename, read_vars, read_vars) |
| |
| test_configuration = read_vars['test_configuration'] |
| table_description = read_vars['frame_data_types'] |
| table_data = read_vars['frame_data'] |
| |
| # Verify the data in the file loaded properly. |
| if not table_description or not table_data: |
| messages.append('Invalid input file: %s. Missing description list or ' |
| 'data dictionary variables.' % filename) |
| continue |
| |
| # Frame numbers appear as number type in the data, but Chart API requires |
| # values of the X-axis to be of string type. |
| # Change the frame_number column data type: |
| table_description['frame_number'] = ('string', 'Frame number') |
| # Convert all the values to string types: |
| for row in table_data: |
| row['frame_number'] = str(row['frame_number']) |
| |
| # Store the unique data from this file in the high level lists. |
| test_configurations.append(test_configuration) |
| data_list.append(table_data) |
| # Name of the test run must be present. |
| test_name = FindConfiguration(test_configuration, 'name') |
| if not test_name: |
| messages.append('Invalid input file: %s. Missing configuration key ' |
| '"name"', filename) |
| continue |
| names.append(test_name) |
| |
| # Create data helper and build data tables for each graph. |
| helper = webrtc.data_helper.DataHelper(data_list, table_description, |
| names, messages) |
| |
| # Loading it into gviz_api.DataTable objects and create JSON strings. |
| description, data = helper.CreateConfigurationTable(test_configurations) |
| configurations = gviz_api.DataTable(description, data) |
| json_configurations = configurations.ToJSon() # pylint: disable=W0612 |
| |
| description, data = helper.CreateData('ssim') |
| ssim = gviz_api.DataTable(description, data) |
| # pylint: disable=W0612 |
| json_ssim_data = ssim.ToJSon(helper.GetOrdering(description)) |
| |
| description, data = helper.CreateData('psnr') |
| psnr = gviz_api.DataTable(description, data) |
| # pylint: disable=W0612 |
| json_psnr_data = psnr.ToJSon(helper.GetOrdering(description)) |
| |
| description, data = helper.CreateData('packets_dropped') |
| packet_loss = gviz_api.DataTable(description, data) |
| # pylint: disable=W0612 |
| json_packet_loss_data = packet_loss.ToJSon(helper.GetOrdering(description)) |
| |
| description, data = helper.CreateData('bit_rate') |
| # Add a column of data points for the desired bit rate to be plotted. |
| # (uses test configuration from the last data set, assuming it is the same |
| # for all of them) |
| desired_bit_rate = FindConfiguration(test_configuration, 'bit_rate_in_kbps') |
| if not desired_bit_rate: |
| ShowErrorPage('Cannot configuration field named "bit_rate_in_kbps"') |
| return |
| desired_bit_rate = int(desired_bit_rate) |
| # Add new column data type description. |
| description['desired_bit_rate'] = ('number', 'Desired bit rate (kbps)') |
| for row in data: |
| row['desired_bit_rate'] = desired_bit_rate |
| bit_rate = gviz_api.DataTable(description, data) |
| # pylint: disable=W0612 |
| json_bit_rate_data = bit_rate.ToJSon(helper.GetOrdering(description)) |
| |
| # Format the messages list with newlines. |
| messages = '\n'.join(messages) |
| |
| # Put the variables as JSon strings into the template. |
| print page_template % vars() |
| |
| def FindConfiguration(configuration, name): |
| """ Finds a configuration value using it's name. |
| Returns the first configuration with a matching name. Returns None if no |
| matching configuration is found. """ |
| return_value = None |
| for row in configuration: |
| if row['name'] == name: |
| return_value = row['value'] |
| break |
| return return_value |
| |
| def ShowErrorPage(error_message): |
| print '<html><body>%s</body></html>' % error_message |
| |
| if __name__ == '__main__': |
| main() |