#!/usr/bin/env python import sys import xml.etree.ElementTree as ET import xml.dom.minidom as minidom import os import datetime from optparse import OptionParser def cal_crop(source, target): ratio_src = source['W'] * 1.0 / source['H'] ratio_dst = target['W'] * 1.0 / target['H'] ret = {} if ratio_src == ratio_dst: height = source['H'] width = source['W'] elif ratio_src > ratio_dst: height = source['H'] width = int(height * ratio_dst) else: width = source['W'] height = int(width / ratio_dst) height = height - height % 2 return {'W': width, 'H': height} def cal_reso(reso, sp_reso, mp_reso): ret = {} """ sp_reso always smaller than mp_reso""" if mp_reso: ret['sensor'] = reso[0] if len(reso) == 1 or mp_reso['W'] > reso[1]['W'] else reso[1] elif sp_reso: ret['sensor'] = reso[0] if len(reso) == 1 or sp_reso['W'] > reso[1]['W'] else reso[1] else: raise Exception('Mp and SP both are NULL') if mp_reso: ret['mp_crop'] = cal_crop(ret['sensor'], mp_reso) if sp_reso: ret['sp_crop'] = cal_crop(ret['sensor'], sp_reso) return ret def gen_settings(root, key, sensor, sp_crop, sp, mp_crop, mp, mode): """ for one stream, the sp and sp_crop are None """ active_outputs = 2 if sp else 1 setting = ET.SubElement(root, 'settings', attrib={'key': str(key), 'id' : str(1), 'fps': str(sensor['FPS']), 'active_outputs': str(active_outputs)}) video = ET.SubElement(setting, 'video', attrib={'width': str(mp['W']), 'height': str(mp['H']), 'stream_id': str(1), 'format': 'NV12', 'peer': 'output'}) v_crp = ET.SubElement(video, 'pcrp', attrib={'width': str(mp_crop['W']), 'height': str(mp_crop['H'])}) v_rsz = ET.SubElement(video, 'prsz', attrib={'width': str(mp['W']), 'height': str(mp['H'])}) if sp and sp_crop: preview = ET.SubElement(setting, 'preview', attrib={'width': str(sp['W']), 'height': str(sp['H']), 'stream_id': str(1), 'format': 'NV12', 'peer': 'output'}) p_crp = ET.SubElement(preview, 'pcrp', attrib={'width': str(sp_crop['W']), 'height': str(sp_crop['H'])}) p_rsz = ET.SubElement(preview, 'prsz', attrib={'width': str(sp['W']), 'height': str(sp['H'])}) else: preview = ET.SubElement(setting, 'preview', attrib={'enabled': str(0)}) still = ET.SubElement(setting, 'still', attrib={'enabled': str(0)}) et_sensor = ET.SubElement(setting, 'sensor', attrib={'stream_id': str(1), 'vflip': str(0), 'hflip': str(0), 'mode_id': str(sensor['W']) + 'x' + str(sensor['H']), 'analogue_gain': str(100), 'exposure': str(500)}) et_sensor_port = ET.SubElement(et_sensor, 'port_0', attrib={'type': 'port', 'width': str(sensor['W']), 'height': str(sensor['H']), 'format': mode['sensor_fmt']}) csi = ET.SubElement(setting, 'csi_be_soc') csi_output = ET.SubElement(csi, 'output', attrib={'width': str(sensor['W']), 'height': str(sensor['H']), 'format': mode['sensor_fmt']}) imgu = ET.SubElement(setting, 'imgu', attrib={'stream_id': str(1)}) imgu_input = ET.SubElement(imgu, 'input', attrib={'width': str(sensor['W']), 'height': str(sensor['H']), 'format': mode['sensor_fmt']}) iac = ET.SubElement(imgu_input, 'iac', attrib={'width': str(sensor['W']), 'height': str(sensor['H'])}) imgu_output = ET.SubElement(imgu, 'output', attrib={'width': str(sensor['W']), 'height': str(sensor['H']), 'format': 'NV16', 'pipe_output_id': str(0)}) ism = ET.SubElement(imgu_output, 'ism', attrib={'width': str(sensor['W']), 'height': str(sensor['H'])}) def gen_sensor_modes(root, reso, mode): et_mode = ET.SubElement(root, 'sensor_modes', attrib={'sensor_name': mode['name'], 'i2c_address': mode['i2c_address'], 'csi_port': '0', 'metadata': '0', 'bayer_order': mode['bayer_order']}) et_bpp = ET.SubElement(et_mode, 'available_bit_per_pixel') et_bpp_value = ET.SubElement(et_bpp, 'bpp', attrib={'value': str(mode['bpp'])}) et_pll = ET.SubElement(et_mode, 'pll_configs') et_pll_item = ET.SubElement(et_pll, 'pll_config', attrib={'id': '0', 'pixel_rate': str(mode['pixel_rate']), 'pixel_rate_csi': str(mode['pixel_rate']), 'bpp': str(mode['bpp'])}) i = 0 item_max = reso[0] for item in reso: et_item = ET.SubElement(et_mode, 'sensor_mode', attrib={'name': str(item['W']) + 'x' + str(item['H']), 'id': str(i), 'width': str(item['W']), 'height': str(item['H']), 'fps': str(item['FPS']), 'csi_port': '0', 'scaler_pad': '1', 'target': '0', 'min_fll': '0', 'min_llp': '0'}) i = i + 1 et_pixel = ET.SubElement(et_item, 'pixel_array') et_pixel_input = ET.SubElement(et_pixel, 'input', attrib={'width': str(item_max['W']), 'height': str(item_max['H']), 'left': '0', 'top': '0'}) et_pixel_output = ET.SubElement(et_pixel, 'output', attrib={'width': str(item['W']), 'height': str(item['H']), 'left': '0', 'top': '0'}) et_binner = ET.SubElement(et_item, 'binner', attrib={'h_factor': str(item['binner_h']), 'v_factor': str(item['binner_w'])}) # binner input === max reso ? et_binner_input = ET.SubElement(et_binner, 'input', attrib={'width': str(item_max['W']), 'height': str(item_max['H']), 'left': '0', 'top': '0'}) et_binner_output = ET.SubElement(et_binner, 'output', attrib={'width': str(item['W']), 'height': str(item['H']), 'left': '0', 'top': '0'}) def generate_xml(fn, reso, mode, target): sp_max = {'W': 1920, 'H': 1080} root = ET.Element('graph_settings') gen_sensor_modes(root, reso, mode) key = 7000 for mp in target: for sp in target: if sp['W'] > mp['W'] or sp['W'] > sp_max['W']: continue ret = cal_reso(reso, sp, mp) gen_settings(root, key, ret['sensor'], ret['sp_crop'], sp, ret['mp_crop'], mp, mode) key = key + 1 key = 8000 for mp in target: ret = cal_reso(reso, None, mp) gen_settings(root, key, ret['sensor'], None, None, ret['mp_crop'], mp, mode) key = key + 1 # ET.dump(root) xml = minidom.parseString(ET.tostring(root)).toprettyxml(indent=' ') with open(fn, 'w') as f: f.write(xml) def get_user_paras(): try: opt = OptionParser() opt.add_option('--name', dest="name", type=str, default="none", help="sensor name which could be got from sys/class/video4linux/v4l-subdev2/name or cmd: media-ctl -p") opt.add_option('--i2c_address', dest="i2c_address", type=str, default="0-0000", help="sensor i2c_address which could be got from sys/class/video4linux/v4l-subdev2/name or cmd: media-ctl -p") opt.add_option('--bayer_order', dest="bayer_order", type=str, default="BGGR", help="sensor bayer_order which could be got from cmd: media-ctl -p") opt.add_option('--sensor_fmt', dest="sensor_fmt", type=str, default="BG10", help="sensor fmt which could be got from cmd: media-ctl -p") opt.add_option('--bpp', dest="bpp", type=int, default=10, help="sensor bpp") opt.add_option('--pixel_rate', dest="pixel_rate", type=int, default=180000000, help="sensor pixel_rate ") opt.add_option('--width', dest="width", type=int, default=0, help="sensor output width") opt.add_option('--height', dest="height", type=int, default=0, help="sensor output height") opt.add_option('--binner_width', dest="binner_width", type=int, default=0, help="sensor output binner width") opt.add_option('--binner_height', dest="binner_height", type=int, default=0, help="sensor output binner height") (options, args) = opt.parse_args() is_valid_paras = True error_messages = ["Config Err:"] if not options.name: error_messages.append("--name must be set;") is_valid_paras = False if not options.width: error_messages.append("--width must be set;") is_valid_paras = False if not options.height: error_messages.append("--height must be set;") error_messages.append("if you do not clear how to config all the options, just config name, width, height") is_valid_paras = False if is_valid_paras: return options else: for error_message in error_messages: print(error_message) opt.print_help() return None except Exception as ex: print("exception :{0}".format(str(ex))) return None def main(argv): opts = get_user_paras() if not opts: return None else: reso = [{'W': opts.width, 'H': opts.height, 'FPS': 30, 'binner_h': 1, 'binner_w': 1}] if opts.binner_width and opts.binner_height: reso.append({'W': opts.binner_width, 'H': opts.binner_height, 'FPS': 60, 'binner_h': 2, 'binner_w': 2}) mode = {'name': opts.name, 'i2c_address': opts.i2c_address, 'bayer_order': opts.bayer_order, 'bpp': opts.bpp, 'pixel_rate': opts.pixel_rate, 'sensor_fmt': opts.sensor_fmt} settings = [{'W': 1920, 'H': 1080}, {'W': 1280, 'H': 960}, {'W': 1280, 'H': 720}, {'W': 800, 'H': 600}, {'W': 640, 'H': 480}, {'W': 352, 'H': 288}, {'W': 320, 'H': 240}, {'W': 176, 'H': 144}] target = [] for s in settings: if opts.width > s["W"] and opts.height > s["H"]: target.append(s) target.insert(0, {'W': opts.width, 'H': opts.height}) if opts.binner_width and opts.binner_height: binners = {'W': opts.binner_width, 'H': opts.binner_height} if binners not in target: target.insert(0, binners) target.sort(reverse=True) print reso print mode print target generate_xml('./graph_settings_' + opts.name + '.xml', reso, mode, target) print "generate " + './graph_settings_' + opts.name + '.xml' if __name__ == '__main__': main(sys.argv)