#!/usr/bin/env python
# -*- coding: utf-8 -*-

import os, sys
import time
import glob
import subprocess
import threading,thread
import textwrap
import tempfile
import urllib
import urllib2
import atexit
import win32pipe,win32file
import win32api
import codecs
import random

from PIL import Image,ImageChops,ImageOps
from PIL import ImageDraw, ImageFont
from optparse import OptionParser
from multiprocessing import Process, Lock, Pipe
from signal import signal

sys.path.append('regzamod')
from Common.RzCmnSubs import dbg,dbg2,dbg0,error,setdbg
from Common.RzCmnSubs import isAudio,isImage,isVideo,isWebVideo,isWebContents,conv_encoding
from Common.RzCmnSubs import gs_encode_sys,gs_debug,gs_verbose,gs_ff_loglev
from Common.RzCmnSubs import gs_python,gs_prog_ytdl,gs_prog_ytdl_s,gs_prog_streamer,gs_streamer_conf
from Common.RzCmnSubs import gs_get_minfo_fp

import RzAAVsubs  # for other module bellows

#----------------------------------------------------------------------------------
# globals
#----------------------------------------------------------------------------------
#--- log levels of me
g_edp=0					# disp error message on screen
g_dummy_disp_on_err=0  	# disp blank screen when read_error of image file
g_error=0				# inner use for disp error message on screen

#--- log levels of external progs 
ytdl_opt="--quiet --no-warnings"

#--- prog path 

#--- processing types
g_proc_mode=2			# process architecture (=1:old,=2:new)
g_auto_play= -1         # default of autoplay mode (<0: use opt.auto_play instead, >=0: force this)
g_multi_pipe=1			# external prog can use multi-pipe_input
g_use_optmuxer=0		# use ffmpeg for muxing to m2ts (now, not usefull)
g_caption=-1			# default of caption on/off (<0: use opt.caption instead, >=0: force this)
g_img_caption_mode=1	# =1: use imglib for image, drawtext for video (good looks for image)
g_img_caption_mode=2	# =2: use drawtext for both image,video (more media info for image)

#--- font for caption texts on video/images
g_font_path="C:/Windows/Fonts/msgothic.ttc"
g_font_path="C:/windows/fonts/arialuni.ttf"
g_font_size=26    # text scale base at 720p
g_font_lfrat=0.8  # linefeed ratio (=LF/font_height)

#--- for video output stream
g_fps_o="30000/1001"  	# output video fps
g_drawtext_file="dummy.wk"

#--- ffmpeg opt for videocat_v (BackGround Video)
# Peak bps may reach 2x of bellow Average bps
# REGZA-Z2 may begin statter on over 40Mbps
# videocat_v always transcode: may cause too high bps(over 40Mbps) on some superHD(4k/8k) videos, if not limitted
g_ff_optv="-q:v 1"      # video quality level (Best quality,Unlimitted bps: may cause statter on REGZA-Z2)
g_ff_optv="-b:v 10M"    # video Average bps limit (10M bps: good for Wireless LAN)
g_ff_optv="-b:v 24M"    # video Average bps limit (24M bps: good for Wired LAN)

#--- ffmpeg opt for videocat_i  (BackGround Image)
g_ff_opti="-q:v 0"      # video quality (same as 1?)

#--- for images used by video output stream
g_imod=Image.ANTIALIAS	# image zoom method (NEAREST,BILINEAR,BICUBIC,ANTIALIAS)
g_svfmt="JPEG"
g_quality=100           # Image(jpeg) compression level(quality)
g_quickResize=0  		# =True: use image.draft() for quick processing
g_fpi=10  				# frames/image
g_fpi=5  				# frames/image
g_selfit_type=0    		# type of fit image to screen =0:use given kickparams,=1:both fit,=2:width fit
g_imgsize_min=13000  	# image size(bytes) too short (seems read url_contents failed)
g_fmax=10   			# image multi-read count
g_tmpid_max=20			# tempid for multi-read , must be enoufgh larger than g_fmax
g_timeout_url=12.0  	# secs timeout for read url_contents(image data)
g_imgtemp_prefix="aav_imgtmp"

#--- for audio output stream
g_abps=256000   		# audio bps
g_abps=448000   		# audio bps
g_asrat=44100   		# audio sampling rate
g_asrat=48000   		# audio sampling rate
#g_audio_inter_gap=3.0  # insert silent_time(sec) between audio-plays, --> instead, use opt.auto_play_igap

#----------------------------------------------------------------------------------
# sub functions
#----------------------------------------------------------------------------------
#---- make uniformed audio-stream from various audio files, for main muxer(aav_trans)
def audiocat (alist,mpos,spos,mmax,out,repeat,tlist):
	if(gs_debug>0): dbg("audiocat: start alist_cnt=%d spos=%d, out=%r" % (len(alist),spos,out))
	if(gs_debug>1): dbg("audiocat: alist=%r" % (alist))
	
	#----------------------------------------------------------------------
	# setup audio list & refer index
	#----------------------------------------------------------------------
	amax=len(alist)
	xpos=spos
	if(xpos>=amax):
		xpos=0
	
	#---- audio list index
	if(g_auto_play==2):  # shuffle play
		#---- prepair order for shuffle play(random)
		#pos=random.randint(0,amax-1)  # random with duplications
		index=random.sample(xrange(amax),amax)  # shuffle (randomize without duplications)
		
		#---- change 1st play to given pos 
		if(index[xpos]!=xpos):
			wpos=index[xpos]
			for i in range(amax):
				if(index[i]==xpos):
					index[i]=wpos
					index[xpos]=xpos
					break
	else:
		index=range(amax)
	
	play_cnt=0
		
	if(gs_debug>1): dbg("audiocat: play index_len=%d index=%r, start_pos=%d" % (len(index),index,xpos))
	#if(gs_debug>0): dbg("audiocat: timeseek=%f, duration=%f" % (opt.timeseek,opt.duration))

	#----------------------------------------------------------------------
	# setup params for exec ffmpeg for audiocat
	#----------------------------------------------------------------------
	#---- pipe for watchdog_pipe (for detect my death)
	pr,pw=Pipe()	
	
	#---- common part of ffmpeg params
	prog=opt.progpath2
	
	#---- timeseek, duration
	seek=""
	dur=""
	if(play_cnt==0): 
		#---- for top play of alist
		#---- consider timeseek,duration on some condition
		if(opt.duration>0):
			#dur="-t %f" % (opt.duration - opt.timeseek)  #opt.duration is not good, use that in tag
			pass
		pos=index[xpos]
		audio_in=alist[pos]
		if(not isWebContents(audio_in)):
			seek="-ss %f" % opt.timeseek
	else:
		#---- ignore timeseek,duration: not supported yet
		#---- ToDO: theoretically can seek inter-multi-audios, if all audio have it's duration info
		pass

	#---- params for top play in alist
	#---- consider timeseek,duration on some condition
	para11="-loglevel %s %s -i" % (gs_ff_loglev,seek)
	para12="-f ac3 -acodec ac3 -ar %d -ab %d %s -map 0:a pipe:1" % (g_asrat,g_abps,dur)
	mpara11=para11.split()
	mpara12=para12.split()
	
	#---- params for 2'nd or later play in alist
	#---- currentry, ignore timeseek,duration: not supported yet
	#---- consider inter_gap (silent time between music play)
	if(opt.auto_play_igap==0.0):
		para21="-loglevel %s -ss 0.0 -i" % (gs_ff_loglev)
		para22="-f ac3 -acodec ac3 -ar %d -ab %d -map 0:a pipe:1" % (g_asrat,g_abps)
		mpara21=para21.split()
		mpara22=para22.split()
	else:
		para21="-loglevel %s -f lavfi -i aevalsrc=0:0:0:0:0:0::d=%d -ss 0.0 -i" % (gs_ff_loglev,opt.auto_play_igap)
		para22="-f ac3 -acodec ac3 -ar %d -ab %d -map [a] pipe:1" % (g_asrat,g_abps)
		mpara21=para21.split()
		mpara22=["-filter_complex", "[0:0] [1:a] concat=n=2:v=0:a=1 [a]"]+para22.split()
	
	#if(gs_debug>0): dbg("audiocat: finally, seek=%s, dur=%s" % (seek,dur))

	#----------------------------------------------------------------------
	# start exec loop 
	#----------------------------------------------------------------------
	top=True
	while(True):
		#---- maint. params for target audio
		pos=index[xpos]
		audio_in=alist[pos]
		
		#---- force shift-jis: what the heck!! exec_prog(subprocess.Popen) args admit only shift-jis
		if(False):
			#in case of given as fullrange-unicode : may have chars that can't be conved to sjis
			#once conv to limitted-unicode that have only chars that can be conved to sjis
			audio_in=win32api.GetShortPathName(audio_in)
		audio_in=audio_in.encode(gs_encode_sys) # anyway, need conv to sjis
		
		if(top): #1st play
			args=[prog]+mpara11+[audio_in]+mpara12
			top=False
			if(gs_debug>0): dbg("audiocat: Start, index_pos=%d, pos=%d, timeseek=%f, file=%s" % (xpos,pos,opt.timeseek,alist[pos]))
			if(gs_debug>0): dbg("audiocat: kick args=%r" % (args))
		else:
			args=[prog]+mpara21+[audio_in]+mpara22
		
		#if(gs_debug>0): dbg("audiocat: play_cnt=%d, index_pos=%d, pos=%d, file=%s" % (play_cnt,xpos,pos,alist[pos]))
		
		#--- chnage mediainfo for videocat
		tag=tlist[pos]
		update_medtags(tag)
		
		#---- exec audiocat
		#if(gs_debug>0): dbg("audiocat: kick ffmpeg for audio Start, alist pos=%d" % pos)
		p_audio=exec_prog(args,sys.stdin,out,sys.stderr,False)
		
		#---- kick watchdog "proc" for kill audiocat when death of myself ------
		Process(target=watchdog_pipe,args=(pr,os.getpid(),p_audio.pid)).start()
		
		#---- get media info of audio stream ------
		get_minfo=True
		if(get_minfo and isWebContents(audio_in)):
			time.sleep(2.0)  # avoid peak load of starting main audiocat
			(rc,fmt,ac,abps,ach)=gs_get_minfo_fp(audio_in)
			if(gs_debug>0): dbg("audiocat: gs_get_minfo_fp end rc=%d, fmt=%s, ac=%s, abps=%d, ach=%d" % (rc,fmt,ac,abps,ach))
			if(rc==0):
				tag["acodec"]=ac
				tag["kbps"]="%.1f" % (abps/1000.0)
				tag["channel"]=str(ach)
				update_medtags(tag)
					
		ret=p_audio.wait()
		pw.send("OK") # send terminate message to watchdog_pipe
		
		#if(gs_debug>0): dbg("audiocat: kick ffmpeg for audio End , alist pos=%d, rc=%d" % (pos,rc))
		if(repeat==0):
			break
		
		#---- judge next play
		xpos+=1
		if(xpos>=amax):
			xpos=0
		play_cnt+=1
		if(play_cnt>=amax):
			play_cnt=0
		
		if(g_auto_play==2):
			#---- shuffle play(random)
			if(play_cnt==0):  #cycled
				index=random.sample(xrange(amax),amax)  # re-shuffle
				#if(gs_debug>0): dbg("audiocat: play_cnt reached max=%d, re-shuffled: index=%r, xpos=%d" % (amax,index,xpos))
		else:
			#---- serial play
			pass

	#--- All end of audios to be played : should terminate all processes
	#if(gs_debug>0): dbg("audiocat: All end")
	os._exit(0)
	#return (ret)
	
#---- make uniformed video_stream from various image_files, for main muxer(aav_trans)
def videocat_i (proc,vtype,vlist,mpos,spos,spos_up,mmax,out,tempf):
	#if(gs_debug>0): dbg("videocat_i: start, spos=%d" % (spos))
	if(gs_debug>1): dbg("videocat_i: vlist=%r" % (vlist))
	
	#---- setup videocat_i body params (conv images to video)
	prog=opt.progpath1 #--> old ffmpeg work good (if without drawtext)
	prog=opt.progpath2 #--> new ffmpeg-RZ cause error on img2pipe
	prog=opt.progpath3 #--> new ffmpeg-ZN cause error on img2pipe
	
	para =" -y -f image2pipe -r %s -vcodec mjpeg -i pipe:0" % (fps_img_str)  
	
	# for New ffmpeg, "-f mpegts" cause too long key-interval for image2pipe (that has many same images) 
	#para+=" -q:v 0 -f mpegts -vcodec mpeg2video -g 10 -r %s -aspect %s" % (g_fps_o,g_aspect)
	para+=" %s -f vob -vcodec mpeg2video -r %s -aspect %s" % (g_ff_opti, g_fps_o,g_aspect)
	mpara=para.split()
	
	#--- make drawtext params for disp caption
	ff_drawtext=None
	#if(False and g_caption and g_img_caption_mode==2): 
	if(g_caption and g_img_caption_mode==2): 
		#-----------------------------------------------------------
		# Currentry, don't work well:
		#   old ffmpeg: img2pipe is OK, but error on drawtext (read error textfile, and not supprts reload)
		#   new ffmpeg: drawtext is OK, but error on img2pipe instead
		#-----------------------------------------------------------
		#---- setup vf for disp caption (drawtext) ------------
		dpsize=[opt.dpsize_w,opt.dpsize_h]
		font_file=g_font_path
		font_file=font_file.replace(":","\\\\:")
		font_color="yellow"
		font_color="white"
		font_size=int(g_font_size*dpsize[1]/720.0)
		shift_x=int(15*dpsize[0]/1280.0)
		shift_y=int(15*dpsize[1]/720.0)

		textf=g_drawtext_file.replace("\\","/").replace(":","\\\\:")
		opt_text='textfile=%s:reload=1' % textf
		ff_drawtext='drawtext=%s:fontfile=%s:fontcolor=%s:shadowcolor=0x000000EE:fontsize=%s:shadowx=2:shadowy=2:x=%d:y=h-text_h-%d' % (opt_text,font_file,font_color,font_size,shift_x,shift_y)
	
	if(ff_drawtext==None):
		args=[prog,"-loglevel",gs_ff_loglev]+mpara+["-map","0:v","pipe:1"]
	else:
		args=[prog,"-loglevel",gs_ff_loglev]+mpara+["-vf",ff_drawtext]+["-map","0:v","pipe:1"]

	#---- exec videocat_i body
	p_vcati=exec_prog(args,subprocess.PIPE,out,sys.stderr,False)

	#---- exec imgcat (supply images)
	#if(gs_debug>0): dbg("videocat_i: kick imgcat")
	imgcat(p_vcati,vtype,vlist,mpos,spos,spos_up,mmax,p_vcati.stdin,tempf)
	# will never return
	
	#if(gs_debug>0): dbg("videocat_i: end")

#---- make uniformed video_stream from various video_files, for main muxer(aav_trans)
def videocat_v (proc,vtype,vlist,mpos,spos,spos_up,mmax,out,tempf):
	#if(gs_debug>0): dbg("videocat_v: start, spos=%d" % (spos))
	#if(gs_debug>1): dbg("videocat_v: vlist=%r" % (vlist))
	
	if(g_caption):
		#---- setup vf for disp caption (drawtext) ------------
		dpsize=[opt.dpsize_w,opt.dpsize_h]
		font_file=g_font_path
		font_file=font_file.replace(":","\\\\:")
		font_color="yellow"
		font_color="white"
		font_size=int(g_font_size*dpsize[1]/720.0)
		shift_x=int(15*dpsize[0]/1280.0)
		shift_y=int(15*dpsize[1]/720.0)
		
		#--- final drawtext params
		textf=g_drawtext_file.replace("\\","/").replace(":","\\\\:")
		opt_text='textfile=%s:reload=1' % textf
		ff_drawtext='drawtext=%s:fontfile=%s:fontcolor=%s:shadowcolor=0x000000EE:fontsize=%s:shadowx=2:shadowy=2:x=%d:y=h-text_h-%d' % (opt_text,font_file,font_color,font_size,shift_x,shift_y)
	else:
		ff_drawtext=None
	
	#---- setup all vf(video filter) params (scale, drawtext, etc)
	dpsize_w=opt.dpsize_w
	dpsize_h=opt.dpsize_h
	if(opt.asp_hack>0 and opt.dpsize_h==480):
		dpsize_h=482 # an eazy hack for REGZA that overscan h<=480

	if(ff_drawtext is not None):
		ff_vf="pad=ih*16/9/sar:ih:(ow-iw)/2:(oh-ih)/2,scale=%d:%d,%s" % (dpsize_w,dpsize_h,ff_drawtext)
	else:
		ff_vf="pad=ih*16/9/sar:ih:(ow-iw)/2:(oh-ih)/2,scale=%d:%d" % (dpsize_w,dpsize_h)
	
	#---- start pos
	#spos=random.randint(0,len(vlist)-1)
	if(spos>=len(vlist)):
		spos=0
	
	#---- play videos in vlist, sequensially from spos
	while(True):
		RzAAVsubs.setnxpos(mpos+1,spos+1,mmax)
		bgv=vlist[spos]
		#if(gs_debug>0): dbg("rzAAVPlayer.videocat_v: bgv=%s" % bgv)
		
		#---- setup params & exec progs for video get+transcode
		if(isWebVideo(bgv)):
			bgv=bgv.replace("&","^&").replace("|","^|").replace("(","^(").replace(")","^)")   # escape DOS special chars
			#---- seems to be web video (for many web videos, ffmpeg may can't handle directly)
			#---- use ffmpeg + youtube-dl: piping ffmpeg(transcode video) <--- youtube-dl(get video)
			#if(gs_debug>0): dbg("rzAAVPlayer.videocat_v: isWebVideo=true")
			ffpara_w='-f vob -c:v mpeg2video %s -loglevel %s -y -vf %s -aspect %s' % (g_ff_optv,gs_ff_loglev,ff_vf,"16:9")
			ffpara_v='"%s" -i pipe:0 %s pipe:1' % (opt.progpath3,ffpara_w)
			ytpara_v='%s %s -f "best[height=720]/bestvideo[height<=480]/best" "%s"' % (gs_prog_ytdl_s,ytdl_opt,bgv)
			para_v="%s -o - | %s" % (ytpara_v,ffpara_v)
			
			p_vcatv=exec_prog_sh(para_v,sys.stdin,out,sys.stderr,False)
			p_vcatv.wait()
		else:
			bgvs=win32api.GetShortPathName(bgv) #to pass unicode pathname
			bgvs=bgvs.encode(gs_encode_sys)  # what the heck!! subprocess.Popen args force shift-jis
			#---- seems to be local video file
			#---- use ffmpeg only (get and transcode video) 
			#if(gs_debug>0): dbg("rzAAVPlayer.videocat_v: isWebVideo=false")
			ffpara_v='-f vob -c:v mpeg2video %s -loglevel %s -y -vf %s -aspect %s' % (g_ff_optv,gs_ff_loglev,ff_vf,"16:9")
			para_v='"%s" -i "%s" %s pipe:1' % (opt.progpath3,bgvs,ffpara_v)
			
			p_vcatv=exec_prog_sh(para_v,sys.stdin,out,None,False)
			p_vcatv.wait()
		spos+=1
		if(spos>=len(vlist)):
			spos=0

	#if(gs_debug>0): dbg("videocat_v: End, spos=%d" % (spos))

#---- mux video/audio streams supplyed from videocat/audiocat, to single video+audio_stream
def aav_muxer (video_i,audio_i,video_o,tempf,pipe_out):
	#if(gs_debug>0): dbg("aav_muxer: start")
	
	#---- setup aav_muxer params
	#if(gs_debug>0): dbg("aav_muxer: setup params start")
	prog=opt.progpath2
	para="-y -f mpegts -vcodec copy -acodec copy"
	if(pipe_out is not None):
		para+=" -map 0:v -map 1:a pipe:1"
		stdo=subprocess.PIPE
	else:
		para+=" -map 0:v -map 1:a %s" % (video_o)
		stdo=sys.stdout
	mpara=para.split()
	#args=[prog,"-loglevel",gs_ff_loglev,"-i",video_i,"-itsoffset","0","-ss",seek,"-i",audio_i]+mpara
	#args=[prog,"-loglevel",gs_ff_loglev,"-i",video_i,"-i",audio_i]+mpara  # audio_i is pipe: can't pass directly to ffmpeg
	args=[prog,"-loglevel",gs_ff_loglev,"-i",video_i,"-i","pipe:0"]+mpara
	#if(gs_debug>0): dbg("aav_muxer: setup params end")
	
	#---- exec aav_muxer body
	#if(gs_debug>0): dbg("aav_muxer: kick ffmpeg for muxer")
	#p=exec_prog(args,sys.stdin,stdo,sys.stderr,False)
	p=exec_prog(args,audio_i,stdo,sys.stderr,False)
	
	#if(gs_debug>0): dbg("aav_muxer: end, rc=%d" % rc)
	return (p,rc)

#---- make audio playlist/taglist from file
def getAudioPlaylist (path):
	
	alist=[]  	# list of audio file path
	tlist=[]	# list of audio media tags
	tag={}      # dictionaly for tags
	apos=-1
	#if(gs_debug>0): dbg("getAudioPlaylist Start: path=%s" % (path))
	if(os.path.isfile(path)):
		fp=codecs.open(path,"r","utf-8")
		for line in fp:
			line=line.strip()
			if(line.startswith('#') or len(line)<=0):
				continue
			if(line.startswith('path=')):
				#--- new audio
				str=line[len('path='):].strip()
				alist.append(str)
				apos+=1
				
				#--- save tags for previous audio, even if null
				if(apos>0):
					tlist.append(tag)
				#--- init tags for new audio
				tag={}
				
				#if(gs_debug>0): dbg("getAudioPlaylist: got path=%s" % str)
			elif(line.startswith('title=')):
				str=line[len('title='):].strip()
				tag["title"]=str
			elif(line.startswith('artist=')):
				str=line[len('artist='):].strip()
				tag["artist"]=str
			elif(line.startswith('album=')):
				str=line[len('album='):].strip()
				tag["album"]=str
			elif(line.startswith('genre=')):
				str=line[len('genre='):].strip()
				tag["genre"]=str
			elif(line.startswith('duration=')):
				str=line[len('duration='):].strip()
				tag["duration"]=float(str)
			elif(line.startswith('acodec=')):
				str=line[len('acodec='):].strip()
				tag["acodec"]=str
			elif(line.startswith('kbps=')):
				str=line[len('kbps='):].strip()
				tag["kbps"]=str
			elif(line.startswith('channel=')):
				str=line[len('channel='):].strip()
				tag["channel"]=str
		if(apos>=0):
			tlist.append(tag) #flush last entry
		fp.close()
	return (alist,tlist)

#---- make single playlsit/taglist from opt.params
def getAudioPlaylist_s (opt):
	#if(gs_debug>0): dbg("getAudioPlaylist_s: Start")
	alist=[]  	# list of audio file path
	tlist=[]	# list of audio media tags
	tag={}      # dictionaly for tags

	# audio_in_sys that given by prog param may not be utf-8 --> assert utf-8
	audio_in,enc=conv_encoding(audio_in_sys)
	
	alist.append(audio_in)
	tag["title"]=opt.title
	tag["artist"]=opt.artist
	tag["album"]=opt.album
	tag["genre"]=opt.genre
	tag["acodec"]=opt.acodec
	tag["kbps"]=opt.kbps
	tag["channel"]=opt.channel
	tag["duration"]=opt.duration
	tlist.append(tag)
	
	#if(gs_debug>0): dbg("getAudioPlaylist_s: End")
	return (alist,tlist)

#-----------------------------------------------------------------------
# update mediainfo 
# for videocat_v : write tag text to file that refered from videocat_v[ffmpeg drawtext]
# for videocat_i : update global tag variables refered from videocat_i[imgcat]
#-----------------------------------------------------------------------
def update_medtags (tag):
	global g_drawtext_file
	
	#--- set media tags
	if("title" in tag): title=tag["title"]
	else: title="Unknown"
	if("artist" in tag): artist=tag["artist"]
	else: artist="-"
	if("album" in tag): album=tag["album"]
	else: album="-"
	if("genre" in tag): genre=tag["genre"]
	else: genre="-"
	
	#--- set media infos
	if("acodec" in tag): acodec=tag["acodec"]
	else: acodec="-"
	if("kbps" in tag): kbps=tag["kbps"]
	else: kbps="-"
	if("channel" in tag): channel=tag["channel"]
	else: channel="-"
	if("duration" in tag): 
		duration=tag["duration"]  # duration is float, not string
		dur_str="%.0f" % duration
	else: 
		duration= -1.0
		dur_str="-"
	if(channel=="0"): channel="-"
	if(kbps=="0.0"): kbps="-"
		
	if(g_proc_mode==2): # new mode: draw caption by ffmpeg drawtext, atleast if bgv is video
		#--- for videocat_v, update file
		str='Title: %s\n' % (title)
		str+='Artist: %s, Album: %s\n' % (artist,album)
		str+='Genre: %s, Media ac:%s, ch:%s, kbps:%s, dur:%s' % (genre,acodec,channel,kbps,dur_str)
		fo=open(g_drawtext_file,"w")
		fo.write(str)  # update should be "atomic action"
		fo.close()
	
	if(g_proc_mode==1 or g_img_caption_mode==1): # draw caption by imgcat, if bgv is image
		#--- for videocat_i, update globals 
		#--- ToDO: global exchange should be avoided
		opt.title=title
		opt.artist=artist
		opt.album=album
		opt.genre=genre
		opt.acodec=acodec
		opt.kbps=kbps
		opt.channel=channel
		opt.duration=duration
	
	#if(gs_debug>0): dbg("update_medtags: updated title=%s, artist=%s" % (title,artist))

def aav_trans (args,cliptype,cliplist,mpos,spos,spos_up,mmax,opt,tempf,pw):
	#print args
	if(gs_debug>1):
		pass
		#str(args) cause unicode error 
		#dbg("aav_trans: start args="+str(args))
		dbg("aav_trans: start args=%r" % (args))
	
	#---- Python ignore SIGPIPE, let's reset to default, for proc can get SIGPIPE
	# but, windows doesn't have SIGPIPE!!
	#oldsig=signal.signal(signal.SIGPIPE,signal.SIG_DFL)
	
	#---- exec transcoder body
	if(pw is not None):
		stdo=subprocess.PIPE
	else:
		stdo=None
		
	buffered=0
	cwd="./"
	try:
		if(buffered):
			p = subprocess.Popen(args, bufsize=2000000, shell=False, cwd=cwd, stdin=subprocess.PIPE,
		    	stdout=stdo, stderr=None,close_fds=False)	
		else:
			p = subprocess.Popen(args, shell=False, cwd=cwd, stdin=subprocess.PIPE,
		    	stdout=stdo, stderr=None,close_fds=False)	
		    	
	except OSError:
		error(g_edp,"RzAAVplayer: Failed to exec %s" % args)
		return (1)
		
	#---- kick watchdog "proc" for detect death of myself ------
	pr,pw=Pipe()	#---- use pipe for heart beat
	Process(target=watchdog_pipe,args=(pr,os.getpid(),p.pid)).start()

	#---- kick watchdog "thread" for detect death of child proc p
	#wdwait=threading.Thread(target=watchdog_wait, name="watchdog_wait", args=(os.getpid(),p))
	wdwait=threading.Thread(target=watchdog_wait, name="watchdog_wait", args=(0,p))
	wdwait.start()
	
	if(cliptype=="image"):
		imgcat(p,cliptype,cliplist,mpos,spos,spos_up,mmax,p.stdin,tempf)
	else:
		pass
		#videocat(p,cliptype,cliplist,mpos,spos,spos_up,mmax,opt,p.stdin)

	#---- pipe pump
	if(pw is not None):
		#--- read transcoder_body's stdout & write it to pw
		loop=1
		try:
			while (loop):
				#small buffer may cause audio stattering
				buf=p.stdout.read(500000)
				if(buf):
					pw.write(buf)
				else:
					loop=0
			
		except IOError:		
			#seems be killed 
			#if this judge is not defined, python will never die by SIGs in while loop
			error(g_edp,"RzAAVplayer: IOError in pipe read/write --> exit")
			#sys.exit(1)
			os._exit(1)
		
	# caution: can't catch signals while waiting by join/wait
	#if(gs_debug>0): dbg("aav_trans: start waiting child roc")
	while (p.poll() is None):
		time.sleep(1)
	ret=p.wait()
	#if(gs_debug>0): dbg("aav_trans: end, return")
	return (ret)

#---- read url contents & write to outfile, for web image read
def url_read (url,outfile,spos,fname):
	#if(gs_debug>0): dbg("RzAAVplayer.url_read: Start, url=%s outfile=%s" % (url,outfile))
	rc=0
	try:
		fi= urllib.urlopen(url)
		fo=open(outfile,"w+b")
		fo.write(fi.read())
		fo.close()
	except IOError,e:
		error("RzAAVplayer.url_read: IOError, e=%r, clipNo.=%d, image='%s'" % (e,spos,fname))
		rc=-1
	#except Exception,e:
	#	error("RzAAVplayer.url_read: Unknown Exception, e=%r, clipNo.=%d, image='%s'" % ("",spos,fname))
	#	rc=-2
	
	#statinfo = os.stat(outfile)
	#if(gs_debug>0): dbg("RzAAVplayer.url_read: End")
	#exit(rc)
	
#---- supply imageclips to aav_trans
def imgcat (proc,ctype,imglist ,mpos,spos,spos_up,mmax,file_o,tempf):
	
	# spos indicate start pos in [original imglist] 
	# but [given imglist] is re-ordered to make original spos become top
	# so, you should start always from pos=0 in [given imglist], 
	
	tm_start=time.time()
	aav_statfile="aav_stat.txt"
	dpsize=[opt.dpsize_w,opt.dpsize_h]
	
	#---- fonts
	fh=int(g_font_size*dpsize[1]/720.0)
	#font = ImageFont.truetype("arial.ttf", int(fh))
	#font = ImageFont.truetype('c:\\windows\\fonts\\hgrskp.ttf', int(fh))
	#font = ImageFont.truetype('c:\\windows\\fonts\\VL-PGothic-Regular.ttf',int(fh))
	#font = ImageFont.truetype('c:\\windows\\fonts\\msgothic.ttc', int(fh))
	#font = ImageFont.truetype('c:\\windows\\fonts\\hg5arp.ttf', int(fh))
	
	#---- fonts/mergins
	fontv=1
	if(fontv==1):
		#font = ImageFont.truetype('c:\\windows\\fonts\\arialuni.ttf', int(fh))
		font = ImageFont.truetype(g_font_path, int(fh))
		fw,fh=font.getsize("M")
		#lfv= int(fh*0.8)			#linefeed height
		lfv= int(fh*g_font_lfrat)	#linefeed height

	elif(fontv==2):
		#font = ImageFont.truetype('c:\\windows\\fonts\\hgrge.ttc', int(fh))
		font = ImageFont.truetype(g_font_path, int(fh))
		fw,fh=font.getsize("M")
		lfv= int(fh*1.0)	#linefeed height
	
	sd=2	# text shadow shift
	capt_mergin_x=10 	# caption mergin holizontal in pixcel
	capt_mergin_y=4  	# caption mergin vertical in pixcel 
	if(g_scale <1.0):
		capt_mergin_x += dpsize[0]*(1.0-g_scale)/2 
		capt_mergin_y += dpsize[1]*(1.0-g_scale)/2 
	
	#---- open log files
	#if(gs_debug>0): dbg(">>==== RzAAVplayer.imgcat: Starting mpos=%d spos=%d mmax=%d imgcnt=%d " % (mpos,spos,mmax,len(imglist)))
	
	#---- timeseek
	cnt=0
	if(False and opt.timeseek>0):
		cnt=int(float(opt.timeseek)/opt.selintvl)
	else:
		cnt=0
	
	#if(gs_debug>0): dbg("RzAAVplayer.imgcat: Start dummy out timeseek=%d, cnt=%d" % (opt.timeseek,cnt))
	if(cnt>0):	
		try:		
			#if(gs_debug>0): dbg("timeseek=%f, dummy out cnt=%d" % (opt.timeseek,cnt))
			img=Image.new('RGB',dpsize,(0,0,0))
			for i in range(0,cnt):
				#if(gs_debug>0): dbg("RzAAVplayer.imgcat: Start proc check %d" % (i))
				if(proc.poll() is not None or file_o.closed):
					#if(gs_debug>0): dbg("RzAAVplayer.imgcat: target proc terminated or pipe closed, let's stop")
					return -1
				#if(gs_debug>0): dbg("RzAAVplayer.imgcat: dummy save Start")
				img.save(file_o,g_svfmt,quality=g_quality)
				#if(gs_debug>0): dbg("RzAAVplayer.imgcat: dummy save End" )
				file_o.flush()
				#if(gs_debug>0): dbg("RzAAVplayer.imgcat: End %d" % (i))
		except IOError,e:
			if(True):
				#if(gs_debug>0): dbg("RzAAVplayer.imgcat: dummy cat target proc seems terminated or pipe closed, let's stop")
				return -1
			else:
				if(proc.poll() is not None or file_o.closed):
					# seems can't detect proc.poll(),file.closed 
					#if(gs_debug>0): dbg("RzAAVplayer.imgcat: dummy cat target proc seems terminated or pipe closed, let's stop")
					return -1
				else:
					error(g_edp,"RzAAVplayer.imgcat: IOError(0) , e=%r, clipNo.=%d, image='%s'" % (e,spos,"dummy"))
					# but, continue
		#except:
		#	#except Exception: cause python freeze
		#	error(g_edp,"RzAAVplayer.imgcat: Unknown Exception(0) , e=%r, clipNo.=%d, image='%s'" % ("",spos,"dummy"))
		#	#continue

	#if(gs_debug>0): dbg("RzAAVplayer.imgcat: End dummy out timeseek=%f, cnt=%d" % (opt.timeseek,cnt))

	listsz=len(imglist)
	loop=1
	rc=0
	top=1
	i=0
	cnt=0
	err_str=None	#reset
	err_dpcnt=0
	dummy_dispf=0
	tm_prev=time.time()
	ppos=spos
	tmpid=0
	
	#if(gs_debug>0): dbg("RzAAVplayer.imgcat: Cat Loop Start")
	#signal.signal(signal.SIGALRM, sighandler)

	while loop:
		play_pos=0
		for j in range(0,listsz):
			skip=0
			#if(gs_debug>0): dbg(">>==== RzAAVplayer.imgcat: Loop Start No=%d/%d rpos=%d spos=%d " % (j+1,listsz,i+1,spos))
			cnt+=1
			if(cnt==8):
				#lower cpu load for ffmpeg the slow_starter 
				time.sleep(0.1)
				cnt=0
			
			#count-up play pos
			if(True):
				if(spos_up):
					RzAAVsubs.setnxpos(mpos+1,spos+1,mmax=mmax)

			#file=imglist[i].decode(gs_encode_sys)
			#file=imglist[i]
			#fname=os.path.basename(file)
			
			#if(gs_debug>0): dbg("RzAAVplayer.imgcat: 2 Loop No.%d spos=%d Start" % (cnt,spos))
			skip=0
			g_error=0
			fname="unknown"
			
			try:
				#---- push read_proc for pararell read
				fcnt=fifo_cnt();
				#if(gs_debug>0): dbg("RzAAVplayer.imgcat: fifo_cnt=%d ppos=%d" % (fcnt,ppos))
				for k in range(0,g_fmax-fcnt):
					#file=imglist[ppos].decode(gs_encode_sys)
					file=imglist[ppos]
					fname=os.path.basename(file)
					#fname=fname.decode(gs_encode_sys)
					if(file.startswith("http://") or file.startswith("https://")):
						fname=fname.replace("%2525","%") # for Fool Picasa 
						
						#if(gs_debug>0): dbg("RzAAVplayer.imgcat: No=%d before unquote fname=%s, file=%s " % (k,fname,file))
						
						fname=urllib.unquote(fname)
						fname=fname.encode('raw_unicode_escape').decode('utf-8')  # for head-crashed python unquote
						tempfw="%s-%d.jpg" % (tempf,(tmpid))
						
						#if(gs_debug>0): dbg("RzAAVplayer.imgcat: No=%d after unquote fname=%s, tempfw=%s " % (k,fname,tempfw))
						
						p1=Process(target=url_read,args=(file,tempfw,ppos,fname))
						p1.start()
						
						fifo_push(p1,ppos,fname,file,tempfw,time.time())
						tmpid= tmpid+1
						if(tmpid>g_tmpid_max):
							tmpid=0
					else:
						#fname=fname.decode(gs_encode_sys) # Decoding to Non-UTF Here will cause freeze later: should do just before output string?
						tempfw=file
						fifo_push(None,ppos,fname,file,file,time.time())
					
					if(gs_debug>1):dbg("RzAAVplayer.imgcat: LoopNo=%d push ppos=%d, tempfw=%s, file=%s" % (k,ppos,tempfw,file))
					ppos= ppos+1
					if(ppos>=listsz):
						ppos=0
					
				#---- pop read_proc 
				(rc,p1,spos,fname,file,tempfw,tim1)=fifo_pop()
				tim2=time.time()
				timeout=g_timeout_url-(tim2-tim1)
				if(timeout<0.5):
					timeout=0.5
				
				if(gs_debug>1):
					dbg("RzAAVplayer.imgcat: LoopNo=%d pop ppos=%d, tempfw=%s, file=%s, rc=%d, timeout=%f, p1=%r" % (k,spos,tempfw,file,rc,timeout,p1))
				
				#judge necessity of decode("ms932") when output
				
				decodef=0
				if(file.find("http://")>=0 or file.find("https://")>=0):
					pass
				else:
					decodef=0
				
				
				if(p1 is None):  
					#---- local file
					file=tempfw
				else:
					#---- web contents: wait&terminate read_proc
					file=tempfw
					tm_proc1=time.time()
					#--- timeout check
					if(True):
						# timeout check by join
						p1.join(timeout)        # join does't mean proc terminated, if it timeouted
						p1.terminate() 			# assure proc terminate, but ghost proc may remain in python
						p1.join()               # clear ghost, what the heck!
					else:
						# timeout check by watchdog_timer
						t1=threading.Thread(target=watchdog_timer, name="timer", args=(g_timeout_url,p1.pid))
						t1.start()
						p1.join() 
						t1.terminate()
					
					#--- assure proc terminate 
					# join does't mean proc terminated, if it timeouted
					if(True):
						p1.terminate() 
					elif(False and p1.isAlive()):  # isAlive() freeze, why?
						p1.terminate()
						skip=1
					
					tm_proc2=time.time()
					tm_proc_elapsed=tm_proc2-tm_proc1
					statinfo = os.stat(file)
					#if(gs_debug>0): dbg("RzAAVplayer.imgcat: urlopen proc Ended exit=%d, read_size=%d, time_elapsed=%f, spos=%d, file=%s" % (p1.exitcode,statinfo.st_size,tm_proc_elapsed,spos,fname))
					
					if(p1.exitcode!=0):
						#if(gs_debug>0): dbg("RzAAVplayer.imgcat: read seems failed (exitcode=%d !=0) --> skip" % (p1.exitcode))
						skip=1
					elif(statinfo.st_size<g_imgsize_min):
						#if(gs_debug>0): dbg("RzAAVplayer.imgcat: read seems failed (read_size=%d <%d bytes) --> skip" % (statinfo.st_size,g_imgsize_min))
						skip=1
					elif(tm_proc_elapsed>=g_timeout_url):
						#if(gs_debug>0): dbg("RzAAVplayer.imgcat: read seems failed (elapsed=%f > timeout=%f) --> skip" % (tm_proc_elapsed,g_timeout_url))
						skip=1
					else:
						pass
						#if(gs_debug>0): dbg("RzAAVplayer.imgcat: read seems succeeded")
					
			except IOError,e:
				error(g_edp,"RzAAVplayer.imgcat: IOError(1), e=%r, clipNo.=%d, image='%s'" % (e,spos,fname))
				skip=1
				#dummy_dispf=1
				time.sleep(0.5)
			#except Exception,e:
			#	error(g_edp,"RzAAVplayer.imgcat: Unknown Exception(1), e=%r, clipNo.=%d, image='%s'" % (e,spos,fname))
			#	proc.terminate()
			#	return (-1,spos)
			
			#---- Now image file is ready
			if(skip!=0 or g_error!=0):
				#if(gs_debug>0): dbg("RzAAVplayer.imgcat: Some Error Occurred, but Go-on")
				skip=1
				g_error=0
			elif(g_error==0 and skip==0 and file!=file_o):
				try:
					if(dummy_dispf):
						# use safe-black screen, b/c next image may cause next errors
						img=Image.new('RGB',dpsize,(0,0,0))
						dummy_dispf=0
					else:
						img=Image.open(file)
					imsize=img.size
					if(g_quickResize and imsize[0]*imsize[1]/dpsize[0]/dpsize[1]>=4.0):
						# draft cause unknown Exception
						#if(gs_debug>0): dbg("RzAAVplayer.imgcat: big size image, use draft")
						dpwk=[dpsize[0]*2,dpsize[1]*2]
						img=img.draft('RGB',dpwk)
						imsize=img.size
						
					resize=[opt.dpsize_w,opt.dpsize_h]
					if(opt.selfit==1):  # both fit
						imr=float(imsize[0])/float(imsize[1])
						dpr=float(dpsize[0])/float(dpsize[1])
						dprr=dpr/g_aspect_f
						do_resize=0
						if(imr>dpr):
							do_resize=2
							resize[0]=dpsize[0]
							resize[1]=dpsize[0]/imr/dprr
							pos=(0,int((dpsize[1]-resize[1])/2))
						elif(imr<dpr):
							do_resize=2
							resize[0]=dpsize[1]*imr*dprr
							resize[1]=dpsize[1]
							pos=(int((dpsize[0]-resize[0])/2),0)
						elif(imsize[0]!=dpsize[0]):
							do_resize=1
							resize[0]=dpsize[0]
							resize[1]=dpsize[1]
						# for negate TV's overscan
						if(g_scale!=1.0):
							resize[0]*=g_scale
							resize[1]*=g_scale
							pos=(int((dpsize[0]-resize[0])/2),int((dpsize[1]-resize[1])/2))
							do_resize=2
						
						if(gs_debug>1):
							dbg("imsize=%f,%f" % (imsize[0],imsize[1]))
							dbg("dpsize=%f,%f" % (dpsize[0],dpsize[1]))
							dbg("resize=%f,%f" % (resize[0],resize[1]))
							dbg("imr=%f, dpr=%f, do_resize=%d" % (imr,dpr,do_resize))
						
						if(do_resize>0):
							#if(gs_debug>0): dbg("do_resize start")
							iresize=(int(resize[0]),int(resize[1]))
							img=img.resize(iresize,g_imod)
							#if(gs_debug>0): dbg("do_resize end")
						if(do_resize>1):
							img2=Image.new('RGB',dpsize,(0,0,0))
							img2.paste(img,pos)
							img=img2
					else:
						#img=ImageOps.fit(img,dpsize,Image.BICUBIC,(0.5,0.5))
						img=ImageOps.fit(img,dpsize,g_imod,(0.5,0.5))
					
					#if(gs_debug>0): dbg("draw error msg Start")
					#---- draw error msg ---------
					str=RzAAVsubs.getErrorMsg(1)
					if(str is not None):
						err_str=str
						err_dpcnt=2
					if(err_dpcnt>0 and err_str is not None): 
						err_dpcnt-=1
						lines=textwrap.wrap(err_str, width=80)
						wmax=0
						for line in lines:
							w,h=font.getsize(line)
							if(w>wmax):
								wmax=w
						h=lfv*len(lines)
						xpos=dpsize[0]/2-wmax/2	#centering
						ypos=dpsize[1]/2-h/2	#centering
						for str in lines:
							dr = ImageDraw.Draw(img)
							dr.text((xpos,ypos), 		str,font=font,fill='black')
							dr.text((xpos-sd,ypos-sd),	str,font=font,fill='yellow')
							ypos+=lfv
					else:
						err_str=None	#reset
						err_dpcnt=0
						
					#if(gs_debug>0): dbg("draw captions Start")
					
					#---- draw captions ---------
					if(g_caption and g_img_caption_mode<=1):
						#drawtext=1
						xpos=capt_mergin_x # default: left bottom
						if(((spos+1) % 2 )>0): #odd num
							align_h=0	#left bottom
							ypos=dpsize[1]-fh-capt_mergin_y
							lf=lfv	#line feed
						else:
							align_h=2	#right upper
							ypos=capt_mergin_y
							lf=-lfv	#line feed
						
						dr = ImageDraw.Draw(img)
						dpw=dpsize[0]

						if(True):
							str="Clip No. %d/%d File: %s" % (spos+1,len(imglist),fname)
							#str="Clip No. %d/%d File: %s" % (spos+1,len(imglist))
							if(decodef):
								str=str.decode(gs_encode_sys)
							w,h=font.getsize(str)
							if(align_h==1): #centering
								xpos=dpw/2-w/2
							elif(align_h==2):
								xpos=dpw-w-capt_mergin_x
							dr.text((xpos,ypos), 		str,font=font,fill='black')
							dr.text((xpos-sd,ypos-sd),	str,font=font,fill='white')
							ypos -=lf
						
						str="Title: "+opt.title
						w,h=font.getsize(str)
						if(align_h==1):
							xpos=dpw/2-w/2
						elif(align_h==2):
							xpos=dpw-w-capt_mergin_x
						dr.text((xpos,ypos), 		str,font=font,fill='black')
						dr.text((xpos-sd,ypos-sd),	str,font=font,fill='white')
						ypos -=lf
						
						str="Artist: "+opt.artist
						#str="Artist: "+opt.artist
						w,h=font.getsize(str)
						if(align_h==1):
							xpos=dpw/2-w/2
						elif(align_h==2):
							xpos=dpw-w-capt_mergin_x
						dr.text((xpos,ypos), 		str,font=font,fill='black')
						dr.text((xpos-sd,ypos-sd),	str,font=font,fill='white')
						ypos -=lf

						str="Genre: "+opt.genre
						w,h=font.getsize(str)
						if(align_h==1):	# centering
							xpos=dpw/2-w/2
						elif(align_h==2):
							xpos=dpw-w-capt_mergin_x
						dr.text((xpos,ypos), 		str,font=font,fill='black')
						dr.text((xpos-sd,ypos-sd),	str,font=font,fill='white')
						ypos -=lf

						if(False):
							str="Clip No. %d/%d File: %s" % (spos+1,len(imglist),os.path.basename(file))
							w,h=font.getsize(str)
							if(align_h==1):
								xpos=dpw/2-w/2
							elif(align_h==2):
								xpos=dpw-w-capt_mergin_x
							dr.text((xpos,ypos), 		str,font=font,fill='black')
							dr.text((xpos-sd,ypos-sd),	str,font=font,fill='white')
							ypos -=lf
						
					#---- check proc ---------
					#if(gs_debug>1): ("RzAAVplayer.imgcat: Check Process Start")
					if(False):
						# seems can't detect proc.poll(),file.closed 
						if(proc.poll() is not None or file_o.closed):
							#if(gs_debug>0): dbg("RzAAVplayer.imgcat: target proc terminated or pipe closed, let's stop")
							rc=1
							loop=0
							break
					#if(gs_debug>1): ("RzAAVplayer.imgcat: Check Process End")

					#---- save(write) image ---------
					#if(gs_debug>0): dbg("img.save start");
					for k in range(g_fpi):
						img.save(file_o,g_svfmt,quality=g_quality)
					#file_o.flush()
					#if(gs_debug>0): dbg("img.save end");
					
					# count-up last-played pos
					if(False):
						if(spos_up):
							RzAAVsubs.setnxpos(mpos+1,spos,mmax=mmax)
					tm_now=time.time()
					#if(gs_debug>0): dbg("imgcat: imsize=%d,%d, Time Interval=%f, Elapsed=%f" % (imsize[0],imsize[1],tm_now - tm_prev,tm_now - tm_start))
					tm_prev=tm_now;
					
				except IOError,e :
					if(False and (proc.poll() is not None or file_o.closed)):
						# seems can't detect proc.poll(),file.closed 
						#if(gs_debug>0): dbg("RzAAVplayer.imgcat: target proc seems terminated or pipe closed, let's stop")
						rc=1
						loop=0
						break
					else:
						error(g_edp,"RzAAVplayer.imgcat: IOError(2), e=%r, clipNo.=%d, image='%s'" % (e,spos,fname))
						time.sleep(1)
						if(g_dummy_disp_on_err):
							# disp blank screen
							dummy_dispf=1
							continue  #for don't countup list_pos
				except :
					rc=1
					error(g_edp,"RzAAVplayer.imgcat: Unknown Exception(2), e=%r, clipNo.=%d, image='%s'" % ("",spos,fname))
					time.sleep(1)
					spos+=1
					RzAAVsubs.setnxpos(mpos+1,spos,mmax=mmax)
					#pass
					#loop=0
					break
			#--- loop tail start
			#if(gs_debug>0): dbg(">>==== RzAAVplayer.imgcat: Loop End No=%d/%d rpos=%d spos=%d " % (j+1,listsz,i+1,spos))
			i+=1
			#spos+=1
			#if(i>=listsz):
			#	i=0
			#if(spos>=listsz):
			#	spos=0
			#--- for loop tail end
		#--- while loop tail end
			
	#if(gs_debug>0): dbg("RzAAVplayer.imgcat: Cat Loop End")

	#---- ending
	#file_o.close()
	tm_now=time.time()
	#if(gs_debug>0): dbg(">>==== RzAAVplayer.imgcat: Stopping, mpos=%d spos=%d rc=%d timeElapsed=%.2f" % (mpos,spos,rc,tm_now - tm_start))
	#if(g_ppos is not None):
	#	fifo_unpop()
	return rc

#---- fifo funcs
ls_proc=[]
ls_ppos=[]
ls_fname=[]
ls_file=[]
ls_tempf=[]
ls_time=[]

g_proc=None
g_ppos=None
g_fname=None
g_file=None
g_tempf=None
g_time=None

def fifo_push (proc,ppos,fname,file,tempf,time):
	if(len(ls_proc)>=g_fmax):
		return -1
	ls_proc.append(proc)
	ls_ppos.append(ppos)
	ls_fname.append(fname)
	ls_file.append(file)
	ls_tempf.append(tempf)
	ls_time.append(time)
	return 0
	#return (len(ls_proc)-1)  #pushed posision

def fifo_pop ():
	global g_proc,g_ppos,g_fname,g_file,g_tempf,g_time
	if(len(ls_proc)<=0):
		return (-1,None,None,None,None,None,None)
	p=0
	g_proc=ls_proc.pop(p)
	g_ppos=ls_ppos.pop(p)
	g_fname=ls_fname.pop(p)
	g_file=ls_file.pop(p)
	g_tempf=ls_tempf.pop(p)
	g_time=ls_time.pop(p)
	return (0,g_proc,g_ppos,g_fname,g_file,g_tempf,g_time)

def fifo_unpop ():
	global g_proc,g_ppos,g_fname,g_file,g_tempf,g_time
	
	#if(gs_debug>0): dbg("RzAAVplayer.fifo_unpop: spos=%d " % (g_ppos))
	
	ls_proc.insert(0,g_proc)
	ls_ppos.insert(0,g_ppos)
	ls_fname.insert(0,g_fname)
	ls_file.insert(0,g_file)
	ls_tempf.insert(0,g_tempf)
	ls_time.insert(0,time.time())

def fifo_cnt ():
	return len(ls_proc)

def sighandler (signum, frame):
	#if(gs_debug>0): dbg("sighandler: caught signal=%r" % signum)
	#raise IOError("Time Out")
	pass
	
def watchdog_timer (tim,pid):
	global g_error
	
	#if(gs_debug>0): dbg("watchdog_timer start timer=%f" % tim)
	try:
		time.sleep(tim)
		#if(gs_debug>0): dbg("watchdog_timer :Sleep Ended, interrupt")
		g_error=1
		os.kill(pid,4)
	except RuntimeError,e:
		#if(gs_debug>0): dbg("watchdog_timer :RuntimeError, pass")
		pass
	except:
		pass
		#if(gs_debug>0): dbg("watchdog_timer :Unknown Error, pass")
		

def watchdog_lock (l,ppid,pid):
	#if(gs_debug>0): dbg("===== watchdog: started, mypid=%d parent pid=%d target_pid=%d" % (os.getpid(),ppid,pid))
	rc=l.acquire()
	#if(gs_debug>0): dbg("===== watchdog: kill pid=%d" % pid)
	try:
		os.kill(pid,9)
	except WindowsError:
		pass
		#if(gs_debug>0): dbg("WindowsError: pid=%d may not exists" % pid)
	l.release()
	#sys.exit()
	os._exit(0)

def watchdog_wait (kill_pid,wait_proc):
	#if(gs_debug>0): dbg("watchdog_wait: Start, kill_proc=%d, wait_proc=%d" % (kill_pid,wait_proc.pid))
	wait_proc.wait()
	
	#if(gs_debug>0): dbg("watchdog_wait: Detected wait_proc terminated")
	time.sleep(2.0)
	
	if(kill_pid>0):
		# kill will cause error messasge on PMS
		os.kill(kill_pid,9) 
	else:
		# kill target must be me
		#sys.exit(0)  # seems can't exit
		os._exit(0)  # force exit

def watchdog_pipe (pc,ppid,pid):
	import time
	# this mechanism work well, to know the parent death
	#if(gs_debug>0): dbg("===== watchdog: started, mypid=%d ppid=%d pid=%d" % (os.getpid(),ppid,pid))
	
	time1=time.time()
	
	try:
		#read pipe in blocking mode
		#i.e. wait untill parent die, b/c parent never send to the pipe
		pc.recv()
		#good end (some data send from parent)
		os._exit(0)
	except EOFError:
		#if(gs_debug>0): dbg("===== watchdog: EOFError on pipe.recv")
		#parent seems to be killed
		pass	#Noop
	except IOError:
		#if(gs_debug>0): dbg("===== watchdog: IOError on pipe.recv")
		pass	#Noop
	
	#if(gs_debug>0): dbg("===== watchdog: kill ppid=%d, pid=%d" % (ppid,pid))
	try:
		#os.kill(pid,signal.SIGKILL)
		os.kill(pid,9)
		#os.kill(ppid,9)
	except WindowsError:
		#if(gs_debug>0): dbg("WindowsError: pid=%d may not exists" % pid)
		pass

	time2=time.time()
	time=time2-time1
	#if(gs_debug>0): dbg("watchdog: play time=%f" % time)
	
	if(False and time<5.0):
		#can't handle aav_ctl file, b/c I'm running as a dependent process
		#--- too short play, reset count-ups
		#if(gs_debug>0): dbg("watchdog: too short play time=%f, reset count-ups" % time)
		(mpos,spos)=RzAAVsubs.getnxpos(0,0,None)
		RzAAVsubs.setnxpos(mpos,spos)
	
	#sys.exit()
	os._exit(0)

def named_pipe (name):
	millis = int(round(time.time() * 1000))
	pname="\\\\.\\pipe\\%s(%d)" % (name,millis)
	#if(gs_debug>0): dbg("pname=%s" % pname)
	
	fh = win32pipe.CreateNamedPipe(pname,
              win32pipe.PIPE_ACCESS_DUPLEX,
              win32pipe.PIPE_TYPE_MESSAGE | win32pipe.PIPE_WAIT,
              1,65536,65536,300,None)
	return fh,pname

def pipe_win (fi,fo):
	#if(gs_debug>0): dbg("pipe_win: Start")
	bufsz=50000
	while True:
		#if(gs_debug>0): dbg("pipe_rw: read start")
		data=fi.read(bufsz)
		#if(gs_debug>0): dbg("pipe_rw: read end")
		if(data):
			rc,data=win32file.WriteFile(fo,data,None)
		else:
			break
	#if(gs_debug>0): dbg("pipe_win: End")
	fi.close()


def guess_charset(data):
    f = lambda d, enc: d.decode(enc) and enc

    try: return f(data, 'utf-8')
    except: pass
    try: return f(data, 'cp932')
    except: pass
    try: return f(data, 'shift-jis')
    except: pass
    try: return f(data, 'euc-jp')
    except: pass
    try: return f(data, 'iso2022-jp')
    except: pass
    return None
    
def exec_prog (args,stdi,stdo,stde,sh):
	if(gs_debug>0): dbg("rzAAVplayer: exec_prog: args=%s" % args)
	p=None
	try:
		cwd="./"
		p = subprocess.Popen(args, shell=sh, cwd=cwd, stdin=stdi, stdout=stdo,
			stderr=stde, close_fds=False)
	except OSError:
		#if(gs_debug>0): dbg("rzAAVplayer: exec_prog: Failed to exec %s" % args)
		pass
	return p

def exec_prog_sh (args,stdi,stdo,stde,clfd):
	#if(gs_debug>0): dbg("rzAAVplayer: exec_prog_sh args=%r" % args)
	p=None
	try:
		cwd="./"
		p = subprocess.Popen(args, shell=True, cwd=cwd, stdin=stdi, stdout=stdo,
			stderr=stde, close_fds=clfd)
	except OSError:
		#if(gs_debug>0): dbg("rzAAVplayer: exec_prog_sh: Failed to exec %s" % args)
		pass
	return p

#----------------------------------------------------------------------------------
# main prog
#----------------------------------------------------------------------------------
if __name__ == '__main__':
	
	setdbg(gs_debug)
	#if(gs_debug>0): dbg("RzAAVplayer: Start, argv=%r" % sys.argv)
	tm_start0=time.time()
	
	#---- change default encoding
	if(True):
		#if(gs_debug>0): dbg("RzAAVplayer.main: defaultencoding=%s" % sys.getdefaultencoding())
		reload(sys)
		sys.setdefaultencoding('utf-8')
		#if(gs_debug>0): dbg("RzAAVplayer.main: changed defaultencoding=%s" % sys.getdefaultencoding())
	
	#---- get main args 
	if(len(sys.argv)<3):
		print "usage: RzAAVplayer.py {audio_in} {video_out} {opt}"
		sys.exit(1)
	myprog=sys.argv[0]
	audio_in=sys.argv[1]
	video_out=sys.argv[2]
	
	#---- get options
	parser = OptionParser()
	
	parser.add_option("--temp",		action="store",	dest="temp",		type="string", default=".")
	parser.add_option("--sess_id",	action="store",	dest="sess_id",		type="string", default="0")

	#---- audio media tags
	parser.add_option("--filename",	action="store",	dest="filename",default="-")
	parser.add_option("--title",	action="store",	dest="title",	default="-")
	parser.add_option("--artist",	action="store",	dest="artist",	default="-")
	parser.add_option("--album",	action="store",	dest="album",	default="-")
	parser.add_option("--genre",	action="store",	dest="genre",	default="-")
	parser.add_option("--acodec",	action="store",	dest="acodec",	default="-")
	parser.add_option("--channel",	action="store",	dest="channel",	default="-")
	parser.add_option("--kbps",		action="store",	dest="kbps",	default="-")
	parser.add_option("--alist",	action="store",	dest="alist",	default=None)
	
	#---- image/video clips
	parser.add_option("--clippath",	action="store",	dest="clippath",	type="string",	default="")
	parser.add_option("--clippath2",action="store",	dest="clippath2",	type="string",	default="")
	parser.add_option("--dbmode",	action="store",	dest="dbmode",		type="string",	default="simple")
	parser.add_option("--seltype",	action="store",	dest="seltype",		type="string",	default="")
	parser.add_option("--selct",	action="store",	dest="selcnt",		type="int",		default=-1)
	parser.add_option("--selintvl",	action="store",	dest="selintvl",	type="int",		default=10)
	parser.add_option("--selsort",	action="store",	dest="selsort",		type="string",	default="name")
	parser.add_option("--selfit",	action="store",	dest="selfit",		type="int",		default=1)
	parser.add_option("--selmedia",	action="store",	dest="selmedia",	type="string",	default="image")
	
	#---- display info
	parser.add_option("--timeseek",	action="store",	dest="timeseek",	type="float",	default=0.0)
	parser.add_option("--duration",	action="store",	dest="duration",	type="float",	default=0.0)
	parser.add_option("--m2ts",		action="store",	dest="m2ts",		type="int"	,	default=0)
	parser.add_option("--h264",		action="store",	dest="h264",		type="int"	,	default=0)
	parser.add_option("--remux",	action="store",	dest="remux",		type="int"	,	default=0)
	parser.add_option("--asp_hack",	action="store",	dest="asp_hack",	type="int"	,	default=0)
	parser.add_option("--dpsize_w",	action="store",	dest="dpsize_w",	type="int"	,	default=856)
	parser.add_option("--dpsize_h",	action="store",	dest="dpsize_h",	type="int"	,	default=482)
	parser.add_option("--caption",	action="store",	dest="caption",		type="int"	,	default=1)
	parser.add_option("--progpath1",action="store",	dest="progpath1",	type="string",	default="win32/ffmpeg.exe")
	parser.add_option("--progpath2",action="store",	dest="progpath2",	type="string",	default="win32/ffmpeg-RZ.exe")
	parser.add_option("--progpath3",action="store",	dest="progpath3",	type="string",	default="win32/ffmpeg-RZ.exe")
	
	#---- auto play
	parser.add_option("--auto_play"		,action="store",	dest="auto_play",		type="int",		default=0)
	parser.add_option("--auto_play_spos",action="store",	dest="auto_play_spos",	type="int",		default=0)
	parser.add_option("--auto_play_list",action="store",	dest="auto_play_list",	type="string",	default=None)
	parser.add_option("--auto_play_igap",action="store",	dest="auto_play_igap",	type="float",	default=3.0)
	
	(opt,args) = parser.parse_args()

	audio_in_sys=audio_in

	#---- test settings start -----------
	test=False
	if(test):
		clippath="C:/Documents and Settings/papa/My Documents/My Pictures/SceneClips"
		opt.dpsize_w=720
		opt.dpsize_h=482
		opt.dpsize_w=856
		opt.dpsize_h=482
		opt.dpsize_w=1280
		opt.dpsize_h=720
	#---- test settings end -----------
	
	#---- init/default settings -----------
	#opt.temp=opt.temp+"/aav"
	opt.temp=opt.temp+"\\aav"  # slash cause confusion on ffmpeg 
	
	RzAAVsubs.init(opt.temp,opt.sess_id) #tempf
	#tempf=os.tempnam(tempfile.gettempdir(),g_imgtemp_prefix)
	tempf=opt.temp+"/"+g_imgtemp_prefix+"("+opt.sess_id+")"
	#atexit.register(lambda: os.remove(tempf))
	g_drawtext_file=opt.temp+("/drawtext(%s).txt" % opt.sess_id)
	
	g_scale=1.0
	g_aspect="16:9"
	g_aspect_f=1.77778 
	if(opt.asp_hack>0):# for like REGZA that always expand any size to it's full screen (16:9)
		if(opt.dpsize_h>480 and opt.asp_hack>0):
			g_aspect="4:3"  		# REGZA can't display mpeg2video of aspect 16/9 when over 480p,
		if(opt.dpsize_w==720 and opt.dpsize_h==480):
			g_aspect="16:9"
			g_scale=0.95 # for negate TV's overscan
	
	if(opt.clippath==""):
		opt.clippath="./"
	if(opt.title==""):
		opt.title=opt.filename
	
	opt.selmedia="video"
	opt.selmedia="image"
	if(g_selfit_type!=0):
		opt.selfit=g_selfit_type
	
	size=(opt.dpsize_w,opt.dpsize_h)
	#fps_img=1.0/opt.selintvl
	fps_img_str="%d/%d" % (g_fpi,int(opt.selintvl))
	
	if(g_caption<0):
		g_caption=opt.caption
	if(g_auto_play<0):
		g_auto_play=opt.auto_play

	if(gs_debug>1):
		dbg("======== %s.main: Start =======================" % os.path.basename(myprog))
		dbg("audio_in="+audio_in)
		dbg("video_out="+video_out)
		dbg("clippath="+opt.clippath)
		dbg("clippath2="+opt.clippath2)
		dbg("selmedia=%s, selfit=%d, size=(%d,%d)" % (opt.selmedia,opt.selfit,size[0],size[1]))
		dbg("selintvl=%d, fps_img=%s" % (opt.selintvl,fps_img_str))
		dbg("opt="+str(opt))
	
	#---- force audio tag encode utf-8 (tags may not be encoded by unicode)
	opt.title,enc1=conv_encoding(opt.title)
	opt.artist,enc2=conv_encoding(opt.artist)
	opt.genre,enc3=conv_encoding(opt.genre)
	opt.album,enc4=conv_encoding(opt.album)
	opt.clippath,enc5=conv_encoding(opt.clippath)
	
	if(gs_debug>1):
		dbg("enc_title   =%r, title =%s" % (enc1,opt.title))
		dbg("enc_artist  =%r, artist=%s" % (enc2,opt.artist))
		dbg("enc_genre   =%r, genre =%s" % (enc3,opt.genre))
		dbg("enc_album   =%r, album =%s" % (enc4,opt.album))
		dbg("enc_clippath=%r, opt.clippath=%s" % (enc5,opt.clippath))

	#-----------------------------------------------------------------------------
	# BEGIN get BGV clippath to play (TODO: should pack thiese part to a function)
	#-----------------------------------------------------------------------------
	sort=opt.selsort
	find=""
	if(opt.seltype!=""):
		if(opt.seltype=="Genre"):
			find=opt.genre
		elif(opt.seltype=="Artist"):
			find=opt.artist
		elif(opt.seltype=="Album"):
			find=opt.album
		elif(opt.seltype=="Title"):
			find=opt.title

	#---- try path1
	clippath=opt.clippath
	base_path,env=conv_encoding(os.path.dirname(audio_in))
	if(os.path.abspath(clippath)!=clippath):
		# relative path
		clippath=os.path.join(base_path,clippath)
	if(opt.seltype!=""):
		if(os.path.isdir(clippath+"/"+opt.seltype+"/"+find)):
			# has classified sub-dir
			clippath=clippath+"/"+opt.seltype+"/"+find
			find=""
		elif(os.path.isdir(clippath+"/"+opt.seltype)):
			clippath=clippath+"/"+opt.seltype
	list=RzAAVsubs.getFilelist(clippath,sort,find)
	#if(gs_debug>0): dbg("path1 clippath1=%s, find=%s, count=%d" % (clippath,find,len(list)))
	
	#---- try path2
	if(len(list)<=0 and len(opt.clippath2)>0):
		clippath=opt.clippath2
		if(os.path.abspath(clippath)!=clippath):
			clippath=os.path.join(base_path,clippath)
		list=RzAAVsubs.getFilelist(clippath,sort,"")
		#if(gs_debug>0): dbg("path2 clippath="+clippath+", len="+str(len(list)))
	
	#---- try defaults
	if(len(list)<=0):
		#error(g_edp,"getFilelist: clippath=%s, No clipfile found. use default clips" % clippath)
		#if(gs_debug>0): dbg("VisualClips: clippath=%s, not found. use default clips" % clippath.decode(gs_encode_sys))
		clippath="regzamod/RzAAVplayer/DefaultClips"
		list=RzAAVsubs.getFilelist(clippath,sort,"")
	
	#---- test dump list
	if(gs_debug>100):
		wkf=opt.temp+("\\aav_dump_vlist(%s).txt" % opt.sess_id)
		fp=open(wkf,"w")
		for str in list:
			print >>fp, str
		fp.close()
	
	#---- get start pos in list
	# mpos: play pos in mainlist (whole list for select sublist from)
	#       mainlist may contain multi-mediatype image/videos.
	# spos: play pos in sublist (real list for single-audio-play)
	#       sublist must contains single-mediatype. i.e. image or video only.
	mmax=len(list)
	(mpos,spos)=RzAAVsubs.getnxpos(1,mmax,clippath)
	
	#---- get sublist to play & maint. mpos,spos
	# don't change spos: b/c it will be maintained by transcoder
	#(rc,cliptype,cliplist,mpos,spos,spos_up)=RzAAVsubs.getPlaylist(list,clippath,mpos,spos,g_multi_pipe)
	(rc,cliptype,cliplist,mpos,sposw,spos_up)=RzAAVsubs.getPlaylist(list,clippath,mpos,spos,g_multi_pipe)
	if(rc<0):
		error(g_edp,"getPlaylist: clipfile=%s not found. use default clips" % clippath)
		# you are in temporaly emergency sublist, save pos in mainlist
		mpos_sv=mpos
		clippath="regzamod/RzAAVplayer/DefaultClips"
		list=RzAAVsubs.getFilelist(clippath,sort,"")
		(rc,cliptype,cliplist,mpos,spos,spos_up)=RzAAVsubs.getPlaylist(list,clippath,mpos,spos,g_multi_pipe)
		# you are in temporaly emergency sublist, recover & don't count-up last played in mainlist
		spos_up=0
		mpos=mpos_sv
	
	if(not spos_up):
		#indicates playing in some sublist --> don't count-up last-played pos in mainlist
		RzAAVsubs.setnxpos(mpos+1,spos,mmax=mmax)
		spos=0	# in this case, spos is pos in sublist
	
	#mmax=len(cliplist) #shouldn't change original list size
	#-----------------------------------------------------------------------------
	# END get BGV clippath to play (TODO: should pack thiese part to a function)
	#-----------------------------------------------------------------------------

	#-----------------------------------------------------------------------------
	# prepair params and exec aav procs
	#-----------------------------------------------------------------------------
	#---- kick opt_muxer
	pipe_w=None
	if(g_use_optmuxer):
		#---- kick muxer(old_ffmpeg) that can mux to sane m2ts (b/c main_transcoder(new ffmpeg) can't)
		#para0=" -i pipe:0 -f mpegts -vcodec copy -acodec ac3 -ab %d" % (g_abps)
		para0=" -i pipe:0 -f mpegts -vcodec copy -acodec copy"
		para0+=" -loglevel %s -y %s" % (gs_ff_loglev,video_out)
		args0=para0.split()
		args0=[opt.progpath2]+args0  #use new ffmpeg
		p0=exec_prog(args0,subprocess.PIPE,None,None,False)
		pipe_w=p0.stdin
	
	#if(g_auto_play>0):
	if(g_proc_mode==2): # new mode
		#-----------------------------------------------------------------------------
		# New Architectture: can handle sequencial play of audios without inter-audio gap time
		#-----------------------------------------------------------------------------
		#--- prepair alist(audio list)
		#if(gs_debug>0): dbg("=== RzAAVplayer.main: setup alist Start")
		alist=[]
		tlist=[]
		tag={}
		apos=0
		repeat=0
		if(opt.auto_play>0):
			#--- auto repeat in given playlist
			#--- auto_play =1:serilal, =2:random
			repeat=1
			apos=opt.auto_play_spos
			(alist,tlist)=getAudioPlaylist(opt.auto_play_list)
			if(gs_debug>1):
				dbg("getAudioPlaylist: alist=%r" % alist)
				dbg("getAudioPlaylist: tlist=%r" % tlist)
			
			#--- for single audio without sane media info
			if(apos>=0 and apos <len(tlist)):
				tag=tlist[apos]
				if("genre" not in tag):
					tag["genre"]=opt.genre
					tlist[apos]=tag
		else:
			#--- play single audio
			(alist,tlist)=getAudioPlaylist_s(opt)
			if(gs_debug>1):
				dbg("getAudioPlaylist: alist=%r" % alist)
				dbg("getAudioPlaylist: tlist=%r" % tlist)
		
		#--- prepair audio pipe (audiocat out --> aav_muxer in)
		#if(gs_debug>0): dbg("=== RzAAVplayer.main: create std_pipes Start")
		pr_a,pw_a=os.pipe()
		fr_a= os.fdopen(pr_a)
		fw_a= os.fdopen(pw_a)
		
		#--- prepair video pipe1 (videocat out)
		pr_v,pw_v=os.pipe()
		fr_v= os.fdopen(pr_v)
		fw_v= os.fdopen(pw_v)
		
		#--- prepair video pipe2 (aav_muxer in)
		bgm_fdh,bgm_fdn= named_pipe("pipe_win")  # pipe for bgv producer output --> main transcoder
		#if(gs_debug>0): dbg("=== RzAAVplayer.main: created named_pipe handle=%r, name=%r" % (bgm_fdh,bgm_fdn))
		p=None
		
		#---- exec audiocat()
		#if(gs_debug>0): dbg("=== RzAAVplayer.main: kick audiocat")
		tt2=threading.Thread(target=audiocat, name="audiocat", args=(alist,mpos,apos,mmax,fw_a,repeat,tlist))
		tt2.start()
		
		#---- exec videocat_i()/videocat_v()
		#if(gs_debug>0): dbg("=== RzAAVplayer.main: kick videocat")
		if(cliptype=="image"):
			tt3=threading.Thread(target=videocat_i, name="videocat_i", args=(p,cliptype,cliplist,mpos,spos,spos_up,mmax,fw_v,tempf))
			tt3.start()
		else: 
			tt3=threading.Thread(target=videocat_v, name="videocat_v", args=(p,cliptype,cliplist,mpos,spos,spos_up,mmax,fw_v,tempf))
			tt3.start()
		
		#--- join-pipe: video pipe1 and video pipe2
		#if(gs_debug>0): dbg("RzAAVplayer.main: kick pipe_win")
		tt1=threading.Thread(target=pipe_win, name="pipe_win", args=(fr_v,bgm_fdh))
		tt1.start()
		
		#---- exec aav_muxer : --> bad: freeze within, not return!!
		#if(gs_debug>0): dbg("=== RzAAVplayer.main: kick aav_muxer")
		(p_muxer,rc)=aav_muxer(bgm_fdn,fr_a,video_out,tempf,pipe_w)

		#---- kick watchdog for kill aav_muxer when I died ------
		pr,pw=Pipe()
		Process(target=watchdog_pipe,args=(pr,os.getpid(),p_muxer.pid)).start()
		
		#---- wait aav_muxer stops
		#if(gs_debug>0): dbg("=== RzAAVplayer.main: aav_muxer wait Start")
		p_muxer.wait()
		pw.send("OK") # send terminate message to watchdog_pipe

	else:
		#-----------------------------------------------------------------------------
		# Old Architectture: can't handle sequencial play of audios without inter-audio gap time
		#-----------------------------------------------------------------------------
		#---- setup transcoder params
		#ffopt=" -user-agent Firefox/26.0"
		if(opt.duration>0):
			dur="-t %f" % (opt.duration - opt.timeseek)
		else:
			dur="-shortest"
		if(isWebContents(audio_in)):
			#currently, can't seek (b/c using yutube-dl)
			seek="0.00"
		else:
			seek="%f" % opt.timeseek
		
		#---- setup main_transcoder params
		if(cliptype=="image"):
			prog=opt.progpath2  #---- use New ffmpeg
			para =" -y -f image2pipe -r %s -vcodec mjpeg -i pipe:0" % (fps_img_str)  # new ffmpeg cause error on seek pipe

			#---- for New ffmpeg, "-f mpegts" cause too long key-interval for image2pipe (that has many same images) 
			#para+=" -q:v 0 -f mpegts -vcodec mpeg2video -acodec ac3 -ar %d -ab %d -r %s " % (g_asrat,g_abps,g_fps_o)
			para+=" -q:v 0 -f vob -vcodec mpeg2video -acodec ac3 -ar %d -ab %d -r %s " % (g_asrat,g_abps,g_fps_o)
			para+=" -aspect %s %s %s" % (g_aspect,dur,video_out)
			
			mpara=para.split()
			# short probesize/analyzeduration will cause play failure
			#args=[prog,"-probesize","32","-analyzeduration","0","-ss",seek,"-i",audio_in_sys]+mpara
			args=[prog,"-loglevel",gs_ff_loglev,"-itsoffset","0","-ss",seek,"-i",audio_in_sys]+mpara
		else:
			if(g_multi_pipe):
				#--- bgv by pipe + bgv producer
				prog=opt.progpath2
				para=" -loglevel %s -y -f mpegts -vcodec copy " % (gs_ff_loglev)
				para+=" -acodec ac3 -ar %d -ab %d %s" % (g_asrat,g_abps,dur)
				
				if(g_use_optmuxer):
					para+=" -map 0:v -map 1:a pipe:1"
				else:
					para+=" -map 0:v -map 1:a %s" % (video_out)
				mpara=para.split()
				bgm_fdh,bgm_fdn= named_pipe("pipe_win")  # pipe for bgv producer output --> main transcoder
				args=[prog,"-loglevel",gs_ff_loglev,"-i",bgm_fdn,"-itsoffset","0","-ss",seek,"-i",audio_in_sys]+mpara
				#args=[prog,"-i",bgm_fdn,"-i",audio_in_sys]+mpara
				RzAAVsubs.setnxpos(mpos+1,spos+1,mmax)
			else:
				#--- bgv by concat_file
				prog=opt.progpath2
				para=" -loglevel %s -y -f mpegts -vcodec mpeg2video " % (gs_ff_loglev)
				para+=" -acodec ac3 -ar %d -ab %d %s" % (g_asrat,g_abps,dur)
				#para+=" -q:v 1 -vf scale=%d:%d -aspect %s" % (opt.dpsize_w,opt.dpsize_h,"16:9")
				para+=" -q:v 1 -vf pad=ih*16/9/sar:ih:(ow-iw)/2:(oh-ih)/2,scale=%d:%d -aspect %s" % (opt.dpsize_w,opt.dpsize_h,"16:9")
				if(g_use_optmuxer):
					para+=" -map 1:v -map 0:a pipe:1"
				else:
					para+=" -map 1:v -map 0:a %s" % (video_out)
				mpara=para.split()
				concatf=opt.temp+("\\concat(%s).txt" % opt.sess_id)
				max=len(cliplist)
				if(max<20):
					max=20   # avr. 3min * 20 = 60 min
				RzAAVsubs.mkconcat(cliplist,spos,concatf,max)
				
				#args=[prog,"-user-agent","Firefox/26.0","-itsoffset","0","-ss",seek,"-i",audio_in_sys,"-safe","0","-f","concat","-i",concatf]+mpara
				args=[prog,"-loglevel",gs_ff_loglev,"-itsoffset","0","-ss",seek,"-i",audio_in_sys,"-safe","0","-f","concat","-i",concatf]+mpara
				#RzAAVsubs.setnxpos(mpos+1,spos+1,mmax)
			
		#---- exec bgv producer
		#if(gs_debug>0): dbg("g_multi_pipe=%d, cliptype=%s" % (g_multi_pipe,cliptype))
		if(g_multi_pipe and not cliptype=="image"):
			pr2,pw2=os.pipe()
			fr2= os.fdopen(pr2)
			fw2= os.fdopen(pw2)
			#if(gs_debug>0): dbg("call videocat")
			t3=threading.Thread(target=videocat_v, name="videocat_v", args=(None,cliptype,cliplist,mpos,spos,spos_up,mmax,fw2,tempf))
			t3.start()

			#--- pump-pipe videocat's output(fr2:std_pipe) to main_muxer's input(bgm_fdh:named_pipe)
			t2=threading.Thread(target=pipe_win, name="pipe_win", args=(fr2,bgm_fdh))
			t2.start()
			
		#---- exec transcoder
		# to start from next to the last pos of prev play
		#spos= spos+1
		#spos= spos-1  
		if(spos <0 or spos>=mmax):
			spos=0
		rc=aav_trans(args,cliptype,cliplist,mpos,spos,spos_up,mmax,opt,tempf,pipe_w)

	tm_end0=time.time()
	#if(gs_debug>0): dbg("RzAAVplayer.main: All End rc=%d, time elapsed=%.2f" % (rc,tm_end0-tm_start0))
