虚拟人系统软件结构框架图

虚拟人项目系统软件结构框架图

如下:

 

 

源代码由三部分组成:

1)paddle 引擎以及papache2下载安装部署说明。安装需要LINUX操作系统。 paddle 引擎 安装的根目录为/home/PaddleGAN

2)python 语言接口程序,需要运行在 python3.8及以上 版本。

本接口代码又两个程序组成,分别是住程序run.py  和守护程序run2.py都需要部署在 /var/www/html/  目录下.

  • PHP语言开发的前台操作界面程序。本界面源码文件/var/www/html/index.php 中。需要 PHP服务程序支持。本项目使用了apache2作为php服务,apache2根目录是/var/www/html/

 

具体文档如下:

一. paddle 引擎以及papache2下载安装部署说明:

#####################################################################

第一步 Paddle  引擎安装过程说明。

docker pull paddlepaddle/paddle:2.4.1-gpu-cuda11.7-cudnn8.4-trt8.4

apt-get install -y vim  安装文本编辑工具VIM

 

安装git 工具 用来下载代码

apt-get update -y 先跟新apt, 将来用APT 安装git.

apt-get upgrade -y

apt install git

========================================

下载代码

git clone https://gitee.com/paddlepaddle/PaddleGAN.git

 

cd PaddleGAN

 

git checkout develop

 

# 安装所需安装包

pip install -r requirements.txt

==========================================

执行功能,用来测试安装。 确保

export PYTHONPATH=$PYTHONPATH:/home/PaddleGAN && python /home/PaddleGAN/applications/tools/wav2lip.py –face /home/paddle/input/picture.jpeg –audio /home/paddle/system/temp.wav –outfile /home/paddle/output/output2.mp4

 

 

=================================================

 

 

错误 提示:ImportError: libGL.so.1: cannot open shared object file: No such file or directory

解决:apt install libgl1-mesa-glx

 

========================================

ImportError: libgthread-2.0.so.0: cannot open shared object file: No such file or directory解决方法

 

apt-get install libglib2.0-dev  解决

 

=======================================

OSError: cannot load library ‘libsndfile.so’: libsndfile.so: cannot open shared object file: No such file or directory

 

apt install libsndfile1

=====================================================

/bin/sh: 1: ffmpeg: not found

sudo apt install ffmpeg

 

#####################################################################

第二步 安装 文字转语言 tts

 

pip install paddlespeech

 

安装  nltk , 找到  nltk.data 路径

pip install nltk

# python

>>> import nltk

>>> nltk.data.path

 

wget -P data https://paddlespeech.bj.bcebos.com/Parakeet/tools/nltk_data.tar.gz

tar zxvf data/nltk_data.tar.gz

 

功能测试

paddlespeech tts –am fastspeech2_aishell3 –voc hifigan_aishell3 –input “你好,欢迎使用百度 飞桨深度学习框架!” –spk_id 167 –output /home/paddle/output/temp2.wav

 

paddlespeech tts –am fastspeech2_aishell3 –voc hifigan_aishell3 –input  “/home/paddle/input/msg.txt” –spk_id 167 –output /home/paddle/temp.wav

 

 

安装 C++ 编译环境

sudo apt install build-essential

conda update conda  //好像没有跟新这个。

 

# 安装 develop 版本

pip install paddlepaddle==0.0.0 -f https://www.paddlepaddle.org.cn/whl/linux/cpu-mkl/develop.html

pip install paddlespeech  //这次会安装成功

再次 功能测试

paddlespeech tts –am fastspeech2_aishell3 –voc hifigan_aishell3 –input “你好0307,锄禾日当午000,汗滴禾下土品牌,谁知盘中餐,粒粒皆辛苦!” –spk_id 1 –output /home/paddle/input/test.wav

 

 

////下面是其他可能用的到的安装命令。

安装命令:

pip install scikit-image

(skimage即是Scikit-Image。基于python脚本语言开发的数字图片处理包,直接pip安装就可以)

 

这是由于环境中缺少了tqdm进度条的安装包,需要使用conda或者pip命令进行安装。

三、解决方案

安装命令如下:

pip install tqdm

 

=======================

OSError: cannot load library ‘libsndfile.so

解决方案

apt install libsndfile1

 

 

///////////////////////////////////////

关闭防火墙命令:

ufw disable

安装SFTP 命令

apt install vsftpd

查看状态

# service vsftpd status

启动

service vsftpd start

/////////////////////////////////////////

 

 

 

 

[nltk_data] ror loading 报错卡死问题

import nltk

nltk.data.path  找到 nltk_data 目录把包拷贝进去就OK了

 

#####################################################################

第三步 安装apache////////////////////////////////////////////////////////////

sudo apt-get update

sudo apt-get install apache2

 

apt install vim

修改它的监听端口

sudo vim /etc/apache2/ports.conf

 

修改它的主机端口

sudo vim /etc/apache2/sites-available/000-default.conf

 

(3)apache2 的几个简单命令:启动、停止、重启、状态

sudo /etc/init.d/apache2  start | stop | restart | status ]

service apache2  start  stop | restart | status ]

 

(4)重启apache2 并查看状态

sudo /etc/init.d/apache2 start

sudo /etc/init.d/apache2 status

————————————————

安装PHP服务程序/////////////////////////////////////////////////////////////

php -v 查看版本号。检查php是否安装

sudo apt-get install php

 

vim /etc/apache2/apache2.conf

末尾添加:

AddType application/x-httpd-php .php .htm .html

 

Aapache2 安装完毕

 

 

  • 有python 语言接口程序

a.主程序源代码,文件名run.py

 

import os

# 使用os.system()

os.system(“export PYTHONPATH=$PYTHONPATH:/home/PaddleGAN “)

 

import argparse

import paddle

from ppgan.apps.first_order_predictor import FirstOrderPredictor

 

parser = argparse.ArgumentParser()

parser.add_argument(“–config”, default=None, help=”path to config”)

parser.add_argument(“–weight_path”,

default=None,

help=”path to checkpoint to restore”)

parser.add_argument(“–source_image”, type=str, help=”path to source image”)

parser.add_argument(“–driving_video”, type=str, help=”path to driving video”)

parser.add_argument(“–output”, default=’output’, help=”path to output”)

parser.add_argument(“–filename”,

default=’result.mp4′,

help=”filename to output”)

parser.add_argument(“–relative”,

dest=”relative”,

action=”store_true”,

default=”relative”,# 添加

help=”use relative or absolute keypoint coordinates”)

parser.add_argument(

“–adapt_scale”,

dest=”adapt_scale”,

action=”store_true”,

default=”adapt_scale”, #添加

help=”adapt movement scale based on convex hull of keypoints”)

 

parser.add_argument(

“–find_best_frame”,

dest=”find_best_frame”,

action=”store_true”,

help=

“Generate from the frame that is the most alligned with source. (Only for faces, requires face_aligment lib)”

)

 

parser.add_argument(“–best_frame”,

dest=”best_frame”,

type=int,

default=None,

help=”Set frame to start from.”)

parser.add_argument(“–cpu”, dest=”cpu”, action=”store_true”, help=”cpu mode.”)

parser.add_argument(“–ratio”,

dest=”ratio”,

type=float,

default=0.4,

help=”margin ratio”)

parser.add_argument(

“–face_detector”,

dest=”face_detector”,

type=str,

default=’sfd’,

help=”face detector to be used, can choose s3fd or blazeface”)

parser.add_argument(“–multi_person”,

dest=”multi_person”,

action=”store_true”,

default=False,

help=”whether there is only one person in the image or not”)

parser.add_argument(“–image_size”,

dest=”image_size”,

type=int,

default=256,

help=”size of image”)

parser.add_argument(“–batch_size”,

dest=”batch_size”,

type=int,

default=1,

help=”Batch size for fom model”)

parser.add_argument(

“–face_enhancement”,

dest=”face_enhancement”,

action=”store_true”,

help=”use face enhance for face”)

parser.add_argument(

“–mobile_net”,

dest=”mobile_net”,

action=”store_true”,

help=”use mobile_net for fom”)

parser.set_defaults(relative=True)

parser.set_defaults(adapt_scale=True)

 

#parser.set_defaults(relative=False)

#parser.set_defaults(face_enhancement=False)

parser.set_defaults(mobile_net=False)

 

############################################################################

 

from ppgan.apps.wav2lip_predictor import Wav2LipPredictor

 

parser2 = argparse.ArgumentParser(

description=

‘Inference code to lip-sync videos in the wild using Wav2Lip models’)

 

parser2.add_argument(‘–checkpoint_path’,

type=str,

help=’Name of saved checkpoint to load weights from’,

default=None)

parser2.add_argument(

‘–audio’,

type=str,

help=’Filepath of video/audio file to use as raw audio source’,

required=False , # required=True,

default=’/var/www/html/system/inputwav.wav’)#修改0308

parser2.add_argument(‘–face’,

type=str,

help=’Filepath of video/image that contains faces to use’,

required=False, #required=True,

default=’/var/www/html/system/result.mp4′)#修改0308

parser2.add_argument(‘–outfile’,

type=str,

help=’Video path to save result. See default for an e.g.’,

default=’results/result_voice.mp4′)

 

parser2.add_argument(

‘–static’,

type=bool,

help=’If True, then use only first video frame for inference’,

default=False)

parser2.add_argument(

‘–fps’,

type=float,

help=’Can be specified only if input is a static image (default: 25)’,

default=25.,

required=False)

 

parser2.add_argument(

‘–pads’,

nargs=’+’,

type=int,

default=[0, 10, 0, 0],

help=

‘Padding (top, bottom, left, right). Please adjust to include chin at least’

)

 

parser2.add_argument(‘–face_det_batch_size’,

type=int,

help=’Batch size for face detection’,

default=16)

parser2.add_argument(‘–wav2lip_batch_size’,

type=int,

help=’Batch size for Wav2Lip model(s)’,

default=128)

 

parser2.add_argument(

‘–resize_factor’,

default=1,

type=int,

help=

‘Reduce the resolution by this factor. Sometimes, best results are obtained at 480p or 720p’

)

 

parser2.add_argument(

‘–crop’,

nargs=’+’,

type=int,

default=[0, -1, 0, -1],

help=

‘Crop video to a smaller region (top, bottom, left, right). Applied after resize_factor and rotate arg. ‘

‘Useful if multiple face present. -1 implies the value will be auto-inferred based on height, width’

)

 

parser2.add_argument(

‘–box’,

nargs=’+’,

type=int,

default=[-1, -1, -1, -1],

help=

‘Specify a constant bounding box for the face. Use only as a last resort if the face is not detected.’

‘Also, might work only if the face is not moving around much. Syntax: (top, bottom, left, right).’

)

 

parser2.add_argument(

‘–rotate’,

default=False,

action=’store_true’,

help=

‘Sometimes videos taken from a phone can be flipped 90deg. If true, will flip video right by 90deg.’

‘Use if you get a flipped result, despite feeding a normal looking video’)

 

parser2.add_argument(

‘–nosmooth’,

default=False,

action=’store_true’,

help=’Prevent smoothing face detections over a short temporal window’)

parser2.add_argument(“–cpu”, dest=”cpu”, action=”store_true”, help=”cpu mode.”)

parser2.add_argument(

“–face_detector”,

dest=”face_detector”,

type=str,

default=’sfd’,

help=”face detector to be used, can choose s3fd or blazeface”)

parser2.add_argument(

“–face_enhancement”,

dest=”face_enhancement”,

action=”store_true”,

help=”use face enhance for face”)

parser2.set_defaults(face_enhancement=False)

 

############################################################################

 

import time

import os

n = 100

sum = 0

counter = 1

err1 = 0

err2 = 0

err3 = 0

 

fig1_data_old=”

fig2_data_old=”

fig3_data_old=”

 

str_data1=”

str_data2=”

str_data3=”

 

load_spk_id=”

 

print (‘Start : %s v0308===========================’ % time.ctime() )

if __name__ == “__main__”:

while True : #主循环

 

print (‘Start : %s ver 0308 :19’ % time.ctime() )

time.sleep( 5 )

 

 

#第一步,生成语音

#检查标志文件

 

with open(“/var/www/html/system/fig1.txt”, ‘r’, encoding=”utf-8″) as f:

str_data1 = f.read()

f.close()

 

if str_data1 != fig1_data_old:

fig1_data_old=str_data1  #执行控制

 

print(‘文件不是空的,读取内容’)

read_file = “/var/www/html/input/msg.txt”

with open(read_file, ‘r’, encoding=”utf-8″) as f:

fig1_data_old=str_data = f.read()

f.close()

 

with open(“/var/www/html/system/fig1b.txt”, ‘r’, encoding=”utf-8″) as f:

str_data_gender = f.read() #读取性别数据

f.close()

 

if str_data_gender==”female”:

load_spk_id=1

 

if  str_data_gender==”male”:

load_spk_id=167

 

 

 

from paddlespeech.cli.tts.infer import TTSExecutor

tts = TTSExecutor()

tts(text=str_data, output=”/var/www/html/output1/outwav.wav”,

am=”fastspeech2_aishell3″,

voc=”hifigan_aishell3″,

lang=”zh”,

spk_id=load_spk_id

)

 

 

 

#第二步,生成视频

#检查标志文件fig2

with open(“/var/www/html/system/fig2.txt”, ‘r’, encoding=”utf-8″) as f:

str_data2 = f.read()

f.close()

 

if str_data2 != fig2_data_old:

fig2_data_old=str_data2  #执行控制

 

from PIL import Image

filename = r’/var/www/html/input/picture.jpeg’

img = Image.open(filename)

imgSize = img.size #图片的长和宽  图片觉得不能超限,不然第三步会崩溃

print (imgSize)

maxSize = max(imgSize) #图片的长边

minSize = min(imgSize) #图片的短边

print(maxSize, minSize)

if maxSize <=480 and minSize <= 480 :

args = parser.parse_args()

paddle.set_device(‘cpu’)

#面部表情迁移

#err2=os.system(“export PYTHONPATH=$PYTHONPATH:/home/PaddleGAN && python -u /home/PaddleGAN/applications/tools/first-order-demo.py  –driving_video /var/www/html/system/driving_video.mp4  –source_image /var/www/html/input/picture.jpeg –ratio 0.4 –relative –adapt_scale –output  /var/www/html/system/”)

predictor = FirstOrderPredictor(output=”/var/www/html/output2/”,

filename=args.filename,

weight_path=args.weight_path,

config=args.config,

relative=args.relative,

adapt_scale=args.adapt_scale,

find_best_frame=args.find_best_frame,

best_frame=args.best_frame,

ratio=args.ratio,

face_detector=args.face_detector,

multi_person=args.multi_person,

image_size=args.image_size,

batch_size=args.batch_size,

face_enhancement=args.face_enhancement,

mobile_net=args.mobile_net)

predictor.run(“/var/www/html/input/picture.jpeg”,  “/var/www/html/system/driving_video.mp4”   )

 

 

#第三步,生成视频

#检查标志文件fig3

with open(“/var/www/html/system/fig3.txt”, ‘r’, encoding=”utf-8″) as f:

str_data3 = f.read()

f.close()

 

if str_data3 != fig3_data_old:

fig3_data_old=str_data3  #执行控制

 

#err3=os.system(“export PYTHONPATH=$PYTHONPATH:/home/PaddleGAN && python  /home/PaddleGAN/applications/tools/wav2lip.py   –face /var/www/html/system/result.mp4  –audio /var/www/html/system/inputwav.wav   –outfile   /var/www/html/output/output.mp4”)

args = parser2.parse_args()

#if args.cpu:

paddle.set_device(‘cpu’)

predictor = Wav2LipPredictor(       checkpoint_path = args.checkpoint_path,

static = args.static,

fps = args.fps,

pads = args.pads,

face_det_batch_size = args.face_det_batch_size,

wav2lip_batch_size = args.wav2lip_batch_size,

resize_factor = args.resize_factor,

crop = args.crop,

box = args.box,

rotate = args.rotate,

nosmooth = args.nosmooth,

face_detector = args.face_detector,

face_enhancement = args.face_enhancement)

predictor.run(“/var/www/html/output2/result.mp4”, “/var/www/html/output1/outwav.wav”, “/var/www/html/output3/output.mp4”)

 

b.守护程序源代码 run2.py

 

def mainwork():

from PIL import Image

import time

import os

n = 100

sum = 0

counter = 1

err1 = 0

err2 = 0

err3 = 0

fig1_data_old = 0

fig2_data_old = 0

fig3_data_old = 0

str_data1 = 0

str_data2 = 0

str_data3 = 0

 

os.system(“export PYTHONPATH=$PYTHONPATH:/home/PaddleGAN && python   /var/www/html/run.py”)

三、PHP语言开发的前台操作界面程序, 文件为:index.php  

#!/usr/bin/env python

#encoding: utf-8

#description: 一个守护进程的简单包装类, 具备常用的start|stop|restart|status功能, 使用方便

#             需要改造为守护进程的程序只需要重写基类的run函数就可以了

#date: 2015-10-29

#usage: 启动: python daemon_class.py start

#       关闭: python daemon_class.py stop

#       状态: python daemon_class.py status

#       重启: python daemon_class.py restart

#       查看: ps -axj | grep daemon_class

 

import atexit, os, sys, time, signal

 

class CDaemon:

”’

a generic daemon class.

usage: subclass the CDaemon class and override the run() method

stderr  表示错误日志文件绝对路径, 收集启动过程中的错误日志

verbose 表示将启动运行过程中的异常错误信息打印到终端,便于调试,建议非调试模式下关闭, 默认为1, 表示开启

save_path 表示守护进程pid文件的绝对路径

”’

def __init__(self, save_path, stdin=os.devnull, stdout=os.devnull, stderr=os.devnull, home_dir=’.’, umask=22, verbose=1):

self.stdin = stdin

self.stdout = stdout

self.stderr = stderr

self.pidfile = save_path #pid文件绝对路径

self.home_dir = home_dir

self.verbose = verbose #调试开关

self.umask = umask

self.daemon_alive = True

 

def daemonize(self):

try:

pid = os.fork()

if pid > 0:

sys.exit(0)

except OSError as e:

sys.stderr.write(‘fork #1 failed: %d (%s)\n’ % (e.errno, e.strerror))

sys.exit(1)

 

os.chdir(self.home_dir)

os.setsid()

os.umask(self.umask)

 

try:

pid = os.fork()

if pid > 0:

sys.exit(0)

except OSError as e:

sys.stderr.write(‘fork #2 failed: %d (%s)\n’ % (e.errno, e.strerror))

sys.exit(1)

 

sys.stdout.flush()

sys.stderr.flush()

 

si = open(self.stdin, ‘r’)

so = open(self.stdout, ‘a+’)

if self.stderr:

se = open(self.stderr, ‘a+’)

else:

se = so

 

os.dup2(si.fileno(), sys.stdin.fileno())

os.dup2(so.fileno(), sys.stdout.fileno())

os.dup2(se.fileno(), sys.stderr.fileno())

 

def sig_handler(signum, frame):

self.daemon_alive = False

signal.signal(signal.SIGTERM, sig_handler)

signal.signal(signal.SIGINT, sig_handler)

 

if self.verbose >= 1:

print(“daemon process started …”)

 

atexit.register(self.del_pid)

pid = str(os.getpid())

open(self.pidfile, ‘w+’).write(‘%s\n’ % pid)

 

def get_pid(self):

try:

pf = open(self.pidfile, ‘r’)

pid = int(pf.read().strip())

pf.close()

except IOError:

pid = None

except SystemExit:

pid = None

return pid

 

def del_pid(self):

if os.path.exists(self.pidfile):

os.remove(self.pidfile)

 

def start(self, *args, **kwargs):

if self.verbose >= 1:

print( ‘ready to starting ……’)

#check for a pid file to see if the daemon already runs

pid = self.get_pid()

if pid:

msg = ‘pid file %s already exists, is it already running?\n’

sys.stderr.write(msg % self.pidfile)

sys.exit(1)

#start the daemon

self.daemonize()

self.run(*args, **kwargs)

 

def stop(self):

if self.verbose >= 1:

print (‘stopping …’)

pid = self.get_pid()

if not pid:

msg = ‘pid file [%s] does not exist. Not running?\n’ % self.pidfile

sys.stderr.write(msg)

if os.path.exists(self.pidfile):

os.remove(self.pidfile)

return

#try to kill the daemon process

try:

i = 0

while 1:

os.kill(pid, signal.SIGTERM)

time.sleep(0.1)

i = i + 1

if i % 10 == 0:

os.kill(pid, signal.SIGHUP)

except OSError as err:

err = str(err)

if err.find(‘No such process’) > 0:

if os.path.exists(self.pidfile):

os.remove(self.pidfile)

else:

print (“str err”)

sys.exit(1)

if self.verbose >= 1:

print (‘Stopped!’)

 

def restart(self, *args, **kwargs):

self.stop()

self.start(*args, **kwargs)

 

def is_running(self):

pid = self.get_pid()

#print(pid)

return pid and os.path.exists(‘/proc/%d’ % pid)

 

def run(self, *args, **kwargs):

‘NOTE: override the method in subclass’

print (‘base class run()’)

 

class ClientDaemon(CDaemon):

def __init__(self, name, save_path, stdin=os.devnull, stdout=os.devnull, stderr=os.devnull, home_dir=’.’, umask=22, verbose=1):

CDaemon.__init__(self, save_path, stdin, stdout, stderr, home_dir, umask, verbose)

self.name = name #派生守护进程类的名称

 

def run(self, output_fn, **kwargs):

fd = open(output_fn, ‘w’)

while True:

line = time.ctime() + ‘\n’

fd.write(line)

fd.flush()

time.sleep(1)

mainwork()

fd.close()

 

if __name__ == ‘__main__’:

help_msg = ‘Usage: python %s <start|stop|restart|status>’ % sys.argv[0]

if len(sys.argv) != 2:

print (help_msg)

sys.exit(1)

p_name = ‘clientd’ #守护进程名称

pid_fn = ‘/tmp/daemon_class.pid’ #守护进程pid文件的绝对路径

log_fn = ‘/tmp/daemon_class.log’ #守护进程日志文件的绝对路径

err_fn = ‘/tmp/daemon_class.err.log’ #守护进程启动过程中的错误日志,内部出错能从这里看到

 

cD = ClientDaemon(p_name, pid_fn, stderr=err_fn, verbose=1)

 

if sys.argv[1] == ‘start’:

cD.start(log_fn)

elif sys.argv[1] == ‘stop’:

cD.stop()

elif sys.argv[1] == ‘restart’:

cD.restart(log_fn)

elif sys.argv[1] == ‘status’:

alive = cD.is_running()

if alive:

print (‘process [%s] is running ……’) % cD.get_pid()

else:

print (‘daemon process [%s] stopped’) %cD.name

else:

print (‘invalid argument!’)

print (help_msg)

##################################################################################################

<!DOCTYPE HTML>

<html>

<head>

<meta charset=”utf-8″>

<title>虚拟人 接口界面</title>

<style>

.error {color: #FF0000;}

</style>

</head>

<body>

<h2>虚拟人 接口界面</h2>

<p><span class=”error”> </span></p>

 

 

<?php // 第一步的程序===

 

// 定义变量并默认设置为空值

$nameErr = $emailErr = $genderErr = $websiteErr = “”;

$name = $email = $gender = $comment = $website = “”;

 

if ($_SERVER[“REQUEST_METHOD”] == “POST”)

{

 

if (!empty($_POST[“submit1”]))

{

if (empty($_POST[“comment”]))

{

$comment = “”;

}

else

{

$comment = test_input($_POST[“comment”]);

$str = $_POST[“comment”];

// $str=$_GET[text];//此处可以使用POST/GET text可以自定

$save = $str.”\n”;

unlink(“input/msg.txt”);

file_put_contents(“input/msg.txt”,$comment); //txt.txt可以自定文件名

 

unlink(“system/fig1.txt”);

$uniqid = md5(uniqid(microtime(true),true));//随机字符串 标志

file_put_contents(“system/fig1.txt”,$uniqid); //fig1.txt 第一步操作标志,给run

echo “语音内容为:”. $comment ;

}

 

if (empty($_POST[“gender”]))

{

$genderErr = “性别是必需的”;

}

else

{

$gender = test_input($_POST[“gender”]);

 

unlink(“system/fig1b.txt”);

file_put_contents(“system/fig1b.txt”,$gender); //fig1.txt 第一步操作标志,给run

 

}

}

 

else  if (!empty($_POST[“submit2”]))

{

;

 

}else if (!empty($_POST[“submit3”]))

{

//  pcntl_exec( “/bin/bash” , array(“whoami”));

// pcntl_exec(‘bash /var/www/html/run1.sh’);

 

unlink(“system/fig3.txt”);

$uniqid = md5(uniqid(microtime(true),true));//随机字符串 标志

file_put_contents(“system/fig3.txt”,$uniqid,FILE_APPEND ); //fig3.txt 第三步操作标志,给run

 

}

 

}

 

function test_input($data)

{

$data = trim($data);

$data = stripslashes($data);

$data = htmlspecialchars($data);

return $data;

}

?>

 

<!–第一步的图表  –>

<form enctype=”multipart/form-data” method=”post” action=”<?php echo htmlspecialchars($_SERVER[“PHP_SELF”]);?>”>

 

一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一

<br>

请输入话语内容:  <br>

<textarea name=”comment” rows=”5″ cols=”40″><?php echo $comment;?></textarea>

<br><br>

请选择虚拟人的性别:

<input type=”radio” name=”gender” <?php if (isset($gender) && $gender==”1″) echo “checked”;?>  value=”female”>女

<input type=”radio” name=”gender” <?php if (isset($gender) && $gender==”167″) echo “checked”;?>  value=”male”>男

<span class=”error”><?php echo $genderErr;?></span>

<br><br>

<input type=”submit” name=”submit1″ value=”第1步:生成虚拟人:语音”> <br>

 

 

<?php   // 结果列表

$down=’file_dowm.php’;

$path=’output1/’;

$url=$_SERVER[‘REQUEST_URI’];//访问此页面所需的 URI

if (isset($_GET[‘dir’])) {//判断是否存在目录

$path=$path.$_GET[‘dir’].’/’;

}else{

$url=$url.’?dir=’;

}

$fh=opendir($path);

$data=array();

while (($row=readdir($fh))!==false) {

if ($row==’.’ || $row==’..’) {

continue;

}

$row=iconv(“gb2312”, “utf-8″,$row);

$data[]=$row;

}

?>

<table border=”1″>

<tr>

<td>生成结果文件</td>

<td>操作</td>

</tr>

<?php foreach ($data as $v) { ?>

<tr>

<td><?php echo $v; ?></td>

<td>

<?php if(is_dir($path.$v)){ ?>

<a href=”<?php echo%20$url.’/’.$v;%20?>”>打开</a>

<a href=”<?php echo%20$down.’?’.’id1′.’=’.$v%20?>”>下载</a>

<?php }else{ ?>

<a href=”<?php echo%20$path.$v;%20?>”>查看</a>

<a href=”<?php echo%20$down.’?’.’id1′.’=’.$path.$v%20?>”>下载</a>

<?php } ?>

</td>

</tr>

<?php } ?>

</table>

一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一

</form>

<br>

请上传虚拟人外貌照片(注:必须是五官清晰的正面人物照片。 照片格式为.JPG 或.JPEG。<br>

照片尺寸需小宽480像素 * 高480像素照片文件必须小于80KB) <br>

<br>

<?php   //第二步 的程序

$uptypes=array(‘image/jpg’,’image/jpeg’);

$addtime=date(“Ym”,time());

$testdir=”./input/”;

if(file_exists($testdir)):

else:

mkdir($testdir,0777);

endif;

$max_file_size=2097152;     //上传文件大小限制, 单位BYTE

$destination_folder=$testdir; //上传文件路径

$imgpreview=1;      //是否生成预览图(1为生成,其他为不生成);

$imgpreviewsize=1/2;    //缩略图比例

?>

 

<?php

 

if ($_SERVER[‘REQUEST_METHOD’] == ‘POST’)

{

if (!empty($_POST[“submit2”]))

{

$file = $_FILES[“upfile”];

$filename=$file[“tmp_name”];

$image_size=getimagesize($filename);

$width = $image_size[0];

$height = $image_size[1];

 

if (!is_uploaded_file($file[“tmp_name”]))

//是否存在文件

{

echo “图片不存在!”;

// exit;

}

// $file = $_FILES[“upfile”];

else if($max_file_size < $file[“size”])

//检查文件大小

{

echo “文件太大!”;

// exit;

}

else if(!in_array($file[“type”], $uptypes))

//检查文件类型

{

echo “文件类型不符!”.$file[“type”];

// exit;

}

else if($width > 480)

{

echo’错误 :图片宽长度超过限制 480′;

}

else if($height > 480)

{

echo’错误 :图片高长度超过限制 480′;

}

else if( $file[“size”] >80*1024  )

{

echo”错误 :图片文件大小超过 80kb”;

 

}else{

 

$pinfo=pathinfo($file[“name”]);

$ftype=$pinfo[‘extension’];

$destination =$destination_folder.”picture”.”.”.$ftype; //组合出路径和文件名

if (file_exists($destination) && $overwrite != true)

{

//     echo “同名文件已经存在了”;

unlink(destination); //删除一存在的文件

 

// exit;

 

}

if(!move_uploaded_file ($filename, $destination))

{

//    echo “移动文件出错”;

//  exit;

}

$pinfo=pathinfo($destination);

$fname=$pinfo[“basename”];

echo ” <font color=red>已经成功上传</font><br>文件名:  <font color=blue>”.$destination_folder.$fname.”</font><br>”;

echo ” 宽度:”.$image_size[0];

echo ” 长度:”.$image_size[1];

echo “<br> 大小:”.$file[“size”].” bytes”;

if($imgpreview==1)

{;

echo “<br>图片预览:<br>”;

echo “<img src=\””.$destination.”\” width=”.($image_size[0]*$imgpreviewsize).” height=”.($image_size[1]*$imgpreviewsize);

echo ” title=\”图片预览:\r文件名:”.$destination.”\r上传时间:\”>”;

}

////图片上传成功后  上传操作标志 2

unlink(“system/fig2.txt”); //删除文件

$uniqid = md5(uniqid(microtime(true),true));//随机字符串 标志

file_put_contents(“system/fig2.txt”,$uniqid); //fig2.txt 第二步操作标志,给run

 

}

}

 

}

?>

 

<!–  第二步的图表 –>

<form enctype=”multipart/form-data” method=”post” action=”<?php echo htmlspecialchars($_SERVER[“PHP_SELF”]);?>”>

选择上传图片:

<input name=”upfile” type=”file”> <br>

 

<input type=”submit” name=”submit2″ value=”第2步:生成虚拟人:视频”> <br>

<?php   // 结果列表

$down=’file_dowm.php’;

$path=’output2/’;

$url=$_SERVER[‘REQUEST_URI’];//访问此页面所需的 URI

if (isset($_GET[‘dir’])) {//判断是否存在目录

$path=$path.$_GET[‘dir’].’/’;

}else{

$url=$url.’?dir=’;

}

$fh=opendir($path);

$data=array();

while (($row=readdir($fh))!==false) {

if ($row==’.’ || $row==’..’) {

continue;

}

$row=iconv(“gb2312”, “utf-8″,$row);

$data[]=$row;

}

?>

<table border=”1″>

<tr>

<td>生成结果文件</td>

<td>操作</td>

</tr>

<?php foreach ($data as $v) { ?>

<tr>

<td><?php echo $v; ?></td>

<td>

<?php if(is_dir($path.$v)){ ?>

<a href=”<?php echo%20$url.’/’.$v;%20?>”>打开</a>

<a href=”<?php echo%20$down.’?’.’id1′.’=’.$v%20?>”>下载</a>

<?php }else{ ?>

<a href=”<?php echo%20$path.$v;%20?>”>查看</a>

<a href=”<?php echo%20$down.’?’.’id1′.’=’.$path.$v%20?>”>下载</a>

<?php } ?>

</td>

</tr>

<?php } ?>

</table>

一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一

 

</form>

 

<!– 第三步的程序 无 –>

 

<!– 第三步的图表 –>

<form enctype=”multipart/form-data” method=”post” action=”<?php echo htmlspecialchars($_SERVER[“PHP_SELF”]);?>”>

 

将第一步生成的音频与第二步生成的视频合成,生成最终的虚拟人。<br>

提交前请确保第一和第二步生成了您想要的效果。<br>

合成可能花费数分钟的时间,请耐心等待。<br>

<br><br>

<input type=”submit” name=”submit3″ value=”第3步:生成成虚拟人:视频+语音”> <br>

 

<?php   // 结果列表

$down=’file_dowm.php’;

$path=’output3/’;

$url=$_SERVER[‘REQUEST_URI’];//访问此页面所需的 URI

if (isset($_GET[‘dir’])) {//判断是否存在目录

$path=$path.$_GET[‘dir’].’/’;

}else{

$url=$url.’?dir=’;

}

$fh=opendir($path);

$data=array();

while (($row=readdir($fh))!==false) {

if ($row==’.’ || $row==’..’) {

continue;

}

$row=iconv(“gb2312”, “utf-8″,$row);

$data[]=$row;

}

?>

<table border=”1″>

<tr>

<td>生成结果文件</td>

<td>操作</td>

</tr>

<?php foreach ($data as $v) { ?>

<tr>

<td><?php echo $v; ?></td>

<td>

<?php if(is_dir($path.$v)){ ?>

<a href=”<?php echo%20$url.’/’.$v;%20?>”>打开</a>

<a href=”<?php echo%20$down.’?’.’id1′.’=’.$v%20?>”>下载</a>

<?php }else{ ?>

<a href=”<?php echo%20$path.$v;%20?>”>查看</a>

<a href=”<?php echo%20$down.’?’.’id1′.’=’.$path.$v%20?>”>下载</a>

<?php } ?>

</td>

</tr>

<?php } ?>

</table>

一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一

</form>

 

</body>

</html>

本文为原创文章,转载请注明出处!

完成式端口如何区分接收方和发送方。

结合 mproxysvr3 源代码,可以分析出具体实现的过程。

首先是 结构定义

typedef struct TagLPWSAOVERLAPPEDEX
{
WSAOVERLAPPED Overlapped; //重叠结构
WSABUF WSABuf;//socket数据缓冲
char Buffer[DATA_BUFSIZE];//wsaBuf指向的真实数据位置
SOCKET hSocket;//socket 句柄
SOCKET hSocketPair;//相关的socket句柄
LPVOID pProxy3;//指向代理对象
int nSocketType;
int nIOType;
TagLPWSAOVERLAPPEDEX *pPair;//指向相关socket的重叠扩展结构

}WSAOVERLAPPEDEX, *LPWSAOVERLAPPEDEX;//重叠扩展结构

 

ehSocket == lpOvlpEx->hSocketPair
一、内部的 WSASend WSARecv 和外部的 Recv Send 是一样的。

二、完成端口是独立的封闭的,收发的数据,他里面都存着, 他处理完了,发完成消息 出来。。

三、无论内部还是外部往完成端口里面的SOCKET甲 发送一个字符串 那么 内部和外部都可以 RECV SOCKET甲 得到这个字符串。

四、完成端口, 客户端RECV 服务器是没有响应的。

数据发送完,转入接收状态
// lpOvlpEx->WSABuf 缓冲是公用的 是参照物。 lpOvlpEx重叠块 是参照物
//当前的 hSocket 和 重叠块中的lpOvlpEx->hSocketPair 相同 ,则从 lpOvlpEx->hSocket 中读取数据
//其实是从当前的链接中读取数据

( hSocket ) 是链接的 SOCKET 是参照物, lpOvlpEx->hSocketPair 和 lpOvlpEx->hSocket 都是相对的,/ hSocket 和 lpOvlpEx->hSocket 不对应,

第二种情况 hSocket == lpOvlpEx->hSocketPair ; 是有第一种情况完成后 出发的,
是服务器内的动作 WSASend(lpOvlpEx->hSocketPai产生的 触发事件

第二种情况的完成 也会触发第一种情况

整套系统,过滤掉了外部触发事件。这个不正确;

由于( hSocket ) 分两种,所以 一共有4中情况的,
上面的过程相反, 到最后是 往 伴侣的SOCK 中发送///

 

最后总结只要在重叠结构里定义一对嵌套字,针对嵌套字在处理线程里识别嵌套字,并且处理即可。

本文为原创文章,转载请注明出处!