Files
gommi/plugin/ffmpeg/plugin.py
2022-04-21 19:23:01 +09:00

323 lines
14 KiB
Python
Executable File

# -*- coding: utf-8 -*-
#########################################################
# python
import os
import traceback
import time
from datetime import datetime
from pytz import timezone
# third-party
import requests
from flask import Blueprint, request, Response, send_file, render_template, redirect, jsonify, session, send_from_directory, stream_with_context
from flask_socketio import SocketIO, emit, send
from flask_login import login_user, logout_user, current_user, login_required
# sjva 공용
from framework import app, db, scheduler, path_app_root, socketio, path_data
from framework.logger import get_logger
from framework.util import Util
# 패키지
package_name = __name__.split('.')[0]
logger = get_logger(package_name)
from ffmpeg.logic import Logic
from ffmpeg.model import ModelSetting
from ffmpeg.interface_program_ffmpeg import Ffmpeg
from system.model import ModelSetting as SystemModelSetting
#########################################################
#########################################################
# 플러그인 공용
#########################################################
blueprint = Blueprint(package_name, package_name, url_prefix='/%s' % package_name, template_folder='templates')
menu = {
'main' : [package_name, u'FFMPEG'],
'sub' : [
['setting', u'설정'], ['download', u'다운로드'], ['list', u'목록'], ['log', u'로그'],
]
}
def plugin_load():
Logic.plugin_load()
def plugin_unload():
Logic.plugin_unload()
streaming_kill()
def streaming_kill():
logger.debug('streaming_kill...')
global process_list
try:
for p in process_list:
if p is not None and p.poll() is None:
import psutil
process = psutil.Process(p.pid)
for proc in process.children(recursive=True):
proc.kill()
process.kill()
except Exception as e:
logger.error('Exception:%s', e)
logger.error(traceback.format_exc())
#########################################################
# WEB Menu
#########################################################
@blueprint.route('/')
def home():
return redirect('/%s/list' % package_name)
@blueprint.route('/<sub>')
@login_required
def detail(sub):
arg = ModelSetting.to_dict()
if sub == 'setting':
return render_template('{package_name}_{sub}.html'.format(package_name=package_name, sub=sub), arg=arg)
elif sub == 'download':
now = str(datetime.now(timezone('Asia/Seoul'))).replace(':', '').replace('-', '').replace(' ', '-')
arg['temp_filename'] = ('%s' % now).split('.')[0] + '.mp4'
return render_template('{package_name}_{sub}.html'.format(package_name=package_name, sub=sub), arg=arg)
elif sub == 'list':
return render_template('{package_name}_{sub}.html'.format(package_name=package_name, sub=sub), arg=arg)
elif sub == 'log':
return render_template('log.html', package=package_name)
return render_template('sample.html', title='%s - %s' % (package_name, sub))
#########################################################
# For UI
#########################################################
@blueprint.route('/ajax/<sub>', methods=['GET', 'POST'])
@login_required
def ajax(sub):
try:
if sub == 'setting_save':
ret = ModelSetting.setting_save(request)
return jsonify(ret)
elif sub == 'ffmpeg_version':
ret = Ffmpeg.get_version()
return jsonify(ret)
elif sub == 'download':
url = request.form['url']
filename = request.form['filename']
ffmpeg = Ffmpeg(url, filename, call_plugin=package_name)
data = ffmpeg.start()
return jsonify([])
elif sub == 'stop':
idx = request.form['idx']
Ffmpeg.stop_by_idx(idx)
return jsonify([])
elif sub == 'play':
idx = request.form['idx']
ffmpeg = Ffmpeg.ffmpeg_by_idx(idx)
tmp = ffmpeg.save_fullpath.replace(path_app_root, '')
tmp = tmp.replace('\\', '/')
logger.debug('play : %s', tmp)
#return redirect('/open_file%s', tmp)
#return send_from_directory('', tmp[1:])
return jsonify(tmp)
elif sub == 'list':
ret = []
for ffmpeg in Ffmpeg.instance_list:
ret.append(ffmpeg.get_data())
return jsonify(ret)
elif sub == 'streaming_kill':
streaming_kill()
return jsonify('')
except Exception as exception:
logger.error('Exception:%s', exception)
logger.error(traceback.format_exc())
#http://192.168.0.11:9999/ffmpeg/api/download?url=https%3a%2f%2fani24zo.com%2fani%2fdownload.php%3fid%3d38912&filename=test.mp4&id=0&caller=ani24&save_path=D:\
#http://192.168.0.11:9999/ffmpeg/api/status?id=0&caller=ani24
#http://192.168.0.11:9999/ffmpeg/api/stop?id=0&caller=ani24
@blueprint.route('/api/<sub>', methods=['GET', 'POST'])
def api(sub):
sjva_token = request.args.get('token')
if sjva_token != SystemModelSetting.get('unique'):
ret = {}
ret['ret'] = 'wrong_token'
return jsonify(ret)
if sub == 'download':
ret = {}
try:
max_pf_count = ModelSetting.get('max_pf_count')
url = request.args.get('url')
filename = request.args.get('filename')
caller_id = request.args.get('id')
package_name = request.args.get('caller')
save_path = request.args.get('save_path')
if save_path is None:
save_path = ModelSetting.get('save_path')
else:
if not os.path.exists(save_path):
os.makedirs(save_path)
logger.debug('url : %s', url)
logger.debug('filename : %s', filename)
logger.debug('caller_id : %s', caller_id)
logger.debug('caller : %s', package_name)
logger.debug('save_path : %s', save_path)
f = Ffmpeg(url, filename, plugin_id=caller_id, listener=None, max_pf_count=max_pf_count, call_plugin=package_name, save_path=save_path)
f.start()
ret['ret'] = 'success'
ret['data'] = f.get_data()
except Exception as exception:
logger.error('Exception:%s', exception)
logger.error(traceback.format_exc())
ret['ret'] = 'exception'
ret['log'] = traceback.format_exc()
return jsonify(ret)
elif sub == 'stop':
ret = {}
try:
caller_id = request.args.get('id')
package_name = request.args.get('caller')
f = Ffmpeg.get_ffmpeg_by_caller(package_name, caller_id)
Ffmpeg.stop_by_idx(f.idx)
ret['ret'] = 'success'
ret['data'] = f.get_data()
except Exception as exception:
logger.error('Exception:%s', exception)
logger.error(traceback.format_exc())
ret['ret'] = 'exception'
ret['log'] = traceback.format_exc()
return jsonify(ret)
elif sub == 'status':
ret = {}
try:
caller_id = request.args.get('id')
package_name = request.args.get('caller')
f = Ffmpeg.get_ffmpeg_by_caller(package_name, caller_id)
ret['ret'] = 'success'
ret['data'] = f.get_data()
except Exception as exception:
logger.error('Exception:%s', exception)
logger.error(traceback.format_exc())
ret['ret'] = 'exception'
ret['log'] = traceback.format_exc()
return jsonify(ret)
@socketio.on('connect', namespace='/%s' % package_name)
def connect():
logger.debug('ffmpeg socketio connect')
@socketio.on('disconnect', namespace='/%s' % package_name)
def disconnect():
logger.debug('ffmpeg socketio disconnect')
process_list = []
@blueprint.route('/streaming', methods=['GET'])
def streaming():
mode = request.args.get('mode')
if mode == 'file':
try:
import subprocess
filename = request.args.get('value')
if filename.endswith('mp4'):
"""
output = os.path.join(path_data, 'tmp', 'index.m3u8')
#ffmpeg_command = ['ffmpeg', "-loglevel", "quiet", "-i", filename, '-ss', '00:00:03', '-t', '00:03:00', "-vcodec", 'libx264', '-vf', 'scale=160:-1', '-qscale:v', '1', '-acodec', 'aac', '-qscale:a', '1', '-f', 'mp4', output, '-y']
ffmpeg_command = ['ffmpeg', "-loglevel", "quiet", "-i", filename, '-ss', '00:00:03', '-t', '00:03:00', "-start_number", '0', '-vf', 'scale=320:-1', '-hls_list_size', '0', '-hls_time', '10', '-f', 'hls', output, '-y']
logger.warning(' '.join(ffmpeg_command))
#subprocess.check_output(ffmpeg_command)
subprocess.Popen(ffmpeg_command)
time.sleep(5)
filename = output
"""
url = '/open_file%s' % filename
logger.debug(url)
return redirect(url)
except Exception as exception:
logger.error('Exception:%s', exception)
logger.error(traceback.format_exc())
def generate():
startTime = time.time()
buffer = []
sentBurst = False
path_ffmpeg = 'ffmpeg'
#filename = '/home/coder/project/SJ/mnt/soju6janm/AV/censored/library2/vr/C/CBIKMV/CBIKMV-093/cbikmv-093cd1.mp4'
#filename = '/home/coder/project/SJ/mnt/soju6janw/1.mp4'
#ffmpeg_command = [path_ffmpeg, "-loglevel", "quiet", "-i", filename, "-c:v", "copy", "-c:a", "aac", "-b:a", "128k", "-f", "mpegts", "-tune", "zerolatency", "pipe:stdout"]
ffmpeg_command = [path_ffmpeg, "-loglevel", "quiet", "-i", filename, '-ss', '00:00:03', '-t', '00:03:00', "-vcodec", "libvpx", '-vf', 'scale=320:-1', "-qmin", "0", "-qmax", "50", "-crf", "50", "-b:v", "0.1M", '-acodec', 'libvorbis', '-f', 'webm', "pipe:stdout"]
#ffmpeg_command = [path_ffmpeg, "-loglevel", "quiet", "-i", filename, "-vcodec", "libtheora", '-vf', 'scale=320:-1', "-qscale:v", '1', '-acodec', 'libvorbis', '-qscale:a', '1', '-f', 'ogv', "pipe:stdout"]
#ffmpeg_command = [path_ffmpeg, "-loglevel", "quiet", "-i", filename, "-vcodec", 'libx264', '-acodec', 'aac ', '-f', 'mp4', "pipe:stdout"]
logger.debug(' '.join(ffmpeg_command))
#logger.debug('command : %s', ffmpeg_command)
#process = subprocess.Popen(ffmpeg_command, stdout = subprocess.PIPE, stderr = subprocess.STDOUT, bufsize = -1)
process = subprocess.Popen(ffmpeg_command, stdout = subprocess.PIPE, stderr = subprocess.STDOUT, encoding='utf8')
global process_list
process_list.append(process)
while True:
#if time.time() - startTime > 120:
# break
line = process.stdout.read(1024)
buffer.append(line)
if sentBurst is False and time.time() > startTime + 1 and len(buffer) > 0:
sentBurst = True
for i in range(0, len(buffer) - 2):
yield buffer.pop(0)
elif time.time() > startTime + 1 and len(buffer) > 0:
yield buffer.pop(0)
process.poll()
if isinstance(process.returncode, int):
if process.returncode > 0:
logger.debug('FFmpeg Error :%s', process.returncode)
break
if process is not None and process.poll() is None:
process.kill()
return Response(stream_with_context(generate()), mimetype = "video/MP2T")
def get_video_info(filepath):
try:
from system.logic_command import SystemLogicCommand
command = ['ffprobe', '-v', 'error', '-print_format', 'json', '-show_format', '-show_streams', "%s" % filepath]
ret = SystemLogicCommand.execute_command_return(command, format='json')
return ret
except Exception as exception:
logger.error('Exception:%s', exception)
logger.error(traceback.format_exc())
"""
ffmpeg version 3.4.8-0ubuntu0.2 Copyright (c) 2000-2020 the FFmpeg developers
built with gcc 7 (Ubuntu 7.5.0-3ubuntu1~18.04)
configuration: --prefix=/usr --extra-version=0ubuntu0.2 --toolchain=hardened --libdir=/usr/lib/x86_64-linux-gnu --incdir=/usr/include/x86_64-linux-gnu --enable-gpl --disable-stripping --enable-avresample --enable-avisynth --enable-gnutls --enable-ladspa --enable-libass --enable-libbluray --enable-libbs2b --enable-libcaca --enable-libcdio --enable-libflite --enable-libfontconfig --enable-libfreetype --enable-libfribidi --enable-libgme --enable-libgsm --enable-libmp3lame --enable-libmysofa --enable-libopenjpeg --enable-libopenmpt --enable-libopus --enable-libpulse --enable-librubberband --enable-librsvg --enable-libshine --enable-libsnappy --enable-libsoxr --enable-libspeex --enable-libssh --enable-libtheora --enable-libtwolame --enable-libvorbis --enable-libvpx --enable-libwavpack --enable-libwebp --enable-libx265 --enable-libxml2 --enable-libxvid --enable-libzmq --enable-libzvbi --enable-omx --enable-openal --enable-opengl --enable-sdl2 --enable-libdc1394 --enable-libdrm --enable-libiec61883 --enable-chromaprint --enable-frei0r --enable-libopencv --enable-libx264 --enable-shared
libavutil 55. 78.100 / 55. 78.100
libavcodec 57.107.100 / 57.107.100
libavformat 57. 83.100 / 57. 83.100
libavdevice 57. 10.100 / 57. 10.100
libavfilter 6.107.100 / 6.107.100
libavresample 3. 7. 0 / 3. 7. 0
libswscale 4. 8.100 / 4. 8.100
libswresample 2. 9.100 / 2. 9.100
libpostproc 54. 7.100 / 54. 7.100
Hyper fast Audio and Video encoder
usage: ffmpeg [options] [[infile options] -i infile]... {[outfile options] outfile}...
"""