Path: blob/develop/rootfs/usr/local/lib/web/backend/vnc/app.py
387 views
from __future__ import (1absolute_import, division, print_function, with_statement2)3import re4import os5from flask import (6Flask,7request,8Response,9jsonify,10abort,11)12from gevent import subprocess as gsp, spawn, sleep13from geventwebsocket.exceptions import WebSocketError14from .response import httperror15from .util import ignored16from .state import state17from .log import log181920# Flask app21app = Flask('novnc2')22app.config.from_object('config.Default')23app.config.from_object(os.environ.get('CONFIG') or 'config.Development')242526@app.route('/api/state')27@httperror28def apistate():29state.wait(int(request.args.get('id', -1)), 30)30state.switch_video(request.args.get('video', 'false') == 'true')31mystate = state.to_dict()32return jsonify({33'code': 200,34'data': mystate,35})363738@app.route('/api/health')39def apihealth():40if state.health:41return 'success'42abort(503, 'unhealthy')434445@app.route('/api/reset')46def reset():47if 'w' in request.args and 'h' in request.args:48args = {49'w': int(request.args.get('w')),50'h': int(request.args.get('h')),51}52state.set_size(args['w'], args['h'])5354state.apply_and_restart()5556# check all running57for i in range(40):58if state.health:59break60sleep(1)61log.info('wait services is ready...')62else:63return jsonify({64'code': 500,65'errorMessage': 'service is not ready, please restart container'66})67return jsonify({'code': 200})686970@app.route('/resize')71@httperror72def apiresize():73state.reset_size()74return '<html><head><script type = "text/javascript">var h=window.location.href;window.location.href=h.substring(0,h.length-6);</script></head></html>'757677@app.route('/api/live.flv')78@httperror79def liveflv():80def generate():81xenvs = {82'DISPLAY': ':1',83}84bufsize = 1024 * 185framerate = 208687# sound88sound_cmd_input = []89sound_cmd_parameters = []90zero_latency_make_sound_not_good = [91'-tune', 'zerolatency',92]9394xenvs['X_WIDTH'] = state.w95xenvs['X_HEIGHT'] = state.h96xenvs['X_WIDTH'] -= state.w % 297xenvs['X_HEIGHT'] -= state.h % 29899pixels_count = xenvs['X_WIDTH'] * xenvs['X_HEIGHT']100# factor (720p)101# 383: 2400k102# 300: 3000k103# 230: 4000k104factor = 265105maxbitrate_cmd = [106'-maxrate', str(int(pixels_count / factor)) + 'k',107'-bufsize', str(int(pixels_count / factor / 3)) + 'k'108]109110# TODO move to global111# get default source112sound_cmd_input = [113'-f', 'alsa',114'-i', 'hw:2,1',115]116sound_cmd_parameters = [117'-ar', '44100',118'-c:a', 'mp3',119]120# flv.js report error if enabling hw acceleration121# hwaccel_dev = ['-vaapi_device', '/dev/dri/renderD128']122# hwaccel_if = ['-vf', 'format=nv12,hwupload']123# vcodec = 'h264_vaapi'124hwaccel_dev = []125hwaccel_if = []126vcodec = 'libx264'127# zero_latency_make_sound_not_good = []128# sound_cmd_parameters = []129# sound_cmd_input = []130cmd = ['/usr/local/ffmpeg/ffmpeg'] + sound_cmd_input + hwaccel_dev + [131'-video_size', '{X_WIDTH}x{X_HEIGHT}'.format(**xenvs),132'-framerate', '{}'.format(framerate),133'-f', 'x11grab', '-draw_mouse', '1',134'-i', '{DISPLAY}'.format(**xenvs),135] + hwaccel_if + [136'-r', '{}'.format(framerate),137'-g', '{}'.format(framerate),138'-flags:v', '+global_header',139'-vcodec', vcodec,140'-preset', 'ultrafast',141'-b_strategy', '0',142'-pix_fmt', 'yuv420p',143'-bsf:v', 'dump_extra=freq=e',144] + maxbitrate_cmd \145+ sound_cmd_parameters + zero_latency_make_sound_not_good + [146'-f', 'flv', 'pipe:1',147]148log.info('command: ' + ' '.join(cmd))149pobj = gsp.Popen(150cmd,151stdout=gsp.PIPE,152stderr=gsp.PIPE,153env={k: str(v) for k, v in xenvs.items()},154)155156def readerr(f):157reobj = re.compile(r'bitrate=(\S+)')158global av_bitrate159try:160while True:161buf = f.read(bufsize)162if len(buf) == 0:163break164patterns = reobj.findall(buf.decode('utf-8', 'ignore'))165if len(patterns) > 0:166av_bitrate = patterns[-1]167# log.info(str(buf))168except Exception as e:169log.exception(e)170171preaderr = None172try:173preaderr = spawn(readerr, pobj.stderr)174try:175while True:176buf = pobj.stdout.read(bufsize)177if len(buf) == 0:178break179# ws.send(buf)180yield buf181except WebSocketError:182pass183except Exception as e:184log.exception(e)185finally:186with ignored(Exception):187pobj.kill()188preaderr.join()189except Exception as e:190log.exception(e)191finally:192log.info('exiting')193with ignored(Exception):194pobj.kill()195with ignored(Exception):196preaderr.kill()197log.info('exited')198return Response(generate(), mimetype='video/x-flv')199200201if __name__ == '__main__':202app.run(host=app.config['ADDRESS'], port=app.config['PORT'])203204205