搜索 社区服务 统计排行 帮助
  • 1024阅读
  • 6回复

[聊天]語法技術探討

楼层直达
级别: 版主
注册时间:
2002-12-02
在线时间:
0小时
发帖:
3002
先發兩個主題討論
1. NTSC <-> PAL 長寬解析值轉換
2. Avisynth 的filter 解碼

其實也沒什麼高深
只是近來看了一些問題帖得到的經驗
先來講 1.
最近看了兩個主題才知道這也是有點學問的
先來看個人做的一個多功能Avisynth腳本
===================================

###########################################################
## 此腳本效果是加上字幕於黑邊上 ##
## 原始影像分辨率需大於 PAL_W*PAL_H,否則會有變形之結果 ##
###########################################################

sClip=avisource("test.avi") #.BilinearResize(512,384) ##測試用
#sClip.Width=512 ##註示用
#sClip.Height=384 ##註示用

## 使用者调整參數 ##
FontSize=20 #字幕大小
SubtitleT= "上字幕"#上字幕
SubtitleB= "test.ssa"#下字幕(文字請勿使用 \ ),亦可填寫的是字幕檔案(此時請註上路徑比如 c:\test.aas)
PAL_W= 352 #水平分辨率,請盡量使用4的倍數
PAL_H= 288 #垂直分辨率,請盡量使用4的倍數
mux_mode="add" #合成模式
BorderRevision=0 #寬度裁減修正值

## 尚未用到的使用者參數 ##
SubtitleFirst_frame=0#字幕顯示的開始"時間"(請以frame編號填寫),預設值 0
SubtitleLast_frame=framecount(sClip)-1 #字幕顯示的結束"時間"(請以frame編號填寫),預設值 framecount(sClip)-1

####################
## A 11:9 = 1.222222
## B 12:9 = 1.333333
## 銀幕寬不變時,
## A->B 要先在A時減少水平分辨率才可以一比一轉換,
## B->A 則反過來在B時增加水平分辨率,
## 反過來說就是一比一轉換後要乘以修正值A->B 是A/B,B->A 是B/A。
## PAR = DAR * (水平分辨率/垂直分辨率)
## 此例PAR 等於 Float(PAL_W)/PAL_H * Float(sClip.Width)/sClip.Height
## 當想使用PAL <-> NTSC 轉換時請除去下方 #PN# ※用於在TV看片時
#PN#sDAR= Float(sClip.Width)/sClip.Height
#PN#dDAR= Float(PAL_W)/PAL_H
#PN#PAR= (sDAR==dDAR) ? 1 : ((sDAR

New_H= PAL_H-((BorderRevision+FontSize)*2) #=248
## for resize filter 作修正
temp= New_H % 4
New_H= (temp == 0) ? New_H : New_H-temp

New_W= Float(New_H)/sClip.Height *sClip.Width#PN# *PAR

## for resize filter 作修正
temp= Ceil(New_W) % 4
New_W= (temp == 0) ? New_W : New_W-temp #=332

b= Ceil((PAL_W-New_W)/2)

#return sClip.subtitle(string(PAR)) ##除錯用
## X= b
## Y= FontSize

## 製作一個空的黑色Clip ##
MainP=NullClip(sClip, sClip.Framecount).BilinearResize(PAL_W,PAL_H).ConvertToYUY2

## 调整原影像使字幕夾擊它 ##
nClip=sClip.BilinearResize(New_W, New_H).ConvertToYUY2

#c=Layer(AudioDub(MainP,sClip), nClip, mux_mode, 255, X, Y)
c=Layer(AudioDub(MainP,sClip), nClip, mux_mode, 255, b,FontSize+BorderRevision)

## 加上下字幕 ##
c= (SubtitleT=="") ? c : c.Subtitle(SubtitleT, font="Arial", size=FontSize, align=8)
return (SubtitleB=="")||(Findstr(SubtitleB,"\")>0) ? Get_Sub_File(c,"",SubtitleB,"Auto") : c.Subtitle(SubtitleB, font="華康細圓", size=FontSize-2,align=2)


function NullClip(clip "template", Int "Len")
{
Len = Default(Len, 0)
return Blackness(template, length= Len)
}

#EX: Get_Sub_File(Video, File_Path, File_Name, Subtitle_Style)
Function Get_Sub_File (clip v, String F_P, String F_N, String S_S) {
Loadplugin("VSfilter.dll")
Function Auto_Subtitle_Load (String A_Sub_Name) {
A_Sub_Style =
\ Exist(A_Sub_Name + "IDX") ? "IDX" :
\ Exist(A_Sub_Name + "SRT") ? "SRT" :
\ Exist(A_Sub_Name + "SSA") ? "SSA" :
\ Exist(A_Sub_Name + "ASS") ? "ASS" :
\ Exist(A_Sub_Name + "SMI") ? "SMI" : "NOS"
return A_Sub_Style
}
## 求Subtitle 檔名、副檔名##
S_S_FrontNameChrNum = Get_File_Name_Info(S_S, ".")
F_N_FrontNameChrNum = Get_File_Name_Info(F_N, ".") #Findstr
S_N_Temp = LeftStr(F_N, F_N_FrontNameChrNum)

Sub_Style =
\ (UCase(S_S) == "AUTO") ?
\ Auto_Subtitle_Load(F_P + S_N_Temp) :
\ (S_S_FrontNameChrNum != 0) ?
\ UCase(RightStr(S_S, 3)) :
\ UCase(S_S)

Sub_Name =
\ (S_S_FrontNameChrNum == 0) ?
\ F_P + S_N_Temp + Sub_Style :
\ (Findstr(S_S, ":") > 0) ?
\ S_S :
\ F_P + S_S
## Subtitle File存在 #######
Temp_Sub_IDX = (Sub_Style == "IDX") ? v.VobSub(Sub_Name) : nop
Temp_Sub_SRT = (Sub_Style == "SRT") ? v.TextSub(Sub_Name) : nop
Temp_Sub_SSA = (Sub_Style == "SSA") ? v.TextSub(Sub_Name) : nop
Temp_Sub_ASS = (Sub_Style == "ASS") ? v.TextSub(Sub_Name) : nop
Temp_Sub_SMI = (Sub_Style == "SMI") ? v.TextSub(Sub_Name) : nop
#Temp_Sub_ = (Sub_Style == "") ? v.ConvertToRGB.VD_Subtitler(Sub_Name) : nop
Temp_Sub_NOS = (Sub_Style == "NOS") ? v : nop
File_Subtitle = (Sub_Style <> "") ? Eval("Temp_Sub_"+ Sub_Style) : v

return(File_Subtitle) #string().Subtitle(Sub_Name)
}

#EX: Get_File_Name_Info(StrS, "name") m:\abc.avi
Function Get_File_Name_Info (String ExWork_Movie_File, String Path_Or_Name) {
Function Do_GetStr (String ExWork_Movie_File, Int Str_Len_Num, Int Str_FilePath_necessary_word_Num, String Path_Or_Name) {
F_Str_Num = Str_Len_Num - Str_FilePath_necessary_word_Num + 1
F_Str = LeftStr(ExWork_Movie_File, F_Str_Num)
B_Str_Num = Str_FilePath_necessary_word_Num - 1
B_Str = RightStr(ExWork_Movie_File, B_Str_Num)
Return (Path_Or_Name == "PATH"?F_Str:(Path_Or_Name == "NAME")?B_Str:"")
}
Path_Or_Name = UCase(Path_Or_Name)

Str_Len_Num = StrLen(ExWork_Movie_File)
Str_FilePath_necessary_word_Num = Findstr(RevStr(ExWork_Movie_File), "\")
Str_FrontNameChrNum = (Findstr(RevStr(ExWork_Movie_File), ".") > 0)? Str_Len_Num - Findstr(RevStr(ExWork_Movie_File), ".") + 1 : 0

Return_Word =
\ (Str_FilePath_necessary_word_Num != 0) ?
\ Do_GetStr(ExWork_Movie_File, Str_Len_Num, Str_FilePath_necessary_word_Num, Path_Or_Name) : 0

return ((Path_Or_Name == ".")? Str_FrontNameChrNum : Return_Word)
}

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

這個腳本與主題 1. 所要探討的就是New_W及New_H
分別代表 轉換後的水平及垂直分辨率

見蓝字體
我們知道雖然有這麼個公式 PAR = DAR * (水平分辨率/垂直分辨率)
但對本例實際的應用不高

我們要講的是:
大家都知道 垂直解析度(分辨率)比水平解析度 來的小
因此在轉換時大多希望寧可捨去 水平 進而維持 垂直 不變
此時就會形成一個反相的轉換概念(如下圖)與實際的狀況相反


假設 源高以sH,源寬以sW 表示
因此實際應用上欲達到 設定新高(H),求得新寬(W)
可以得到一個公式
W=h*sW*[轉換比值]
這裡的 h=H/sH 為 新高 對 源高 的增減百分比

當W:H=sW:sH 時 [轉換比值]=1
當W:H≠sW:sH 時 [轉換比值]=(W/H)與(sW/sH)相除
至於誰除以誰:
當 W/H 比 sW/sH 大時為 (W/H) / (sW/sH),反之 (sW/sH) / (W/H)

相互轉換後的結果
<->

级别: 侠客
注册时间:
2003-12-25
在线时间:
0小时
发帖:
486
只看该作者 6楼 发表于: 2005-01-05
楼上可是笨笨???

级别: 新手上路
注册时间:
2004-05-05
在线时间:
0小时
发帖:
56
只看该作者 5楼 发表于: 2005-01-05
精品!精品!就是图看不到!遗憾!
级别: 侠客
注册时间:
2003-12-25
在线时间:
0小时
发帖:
486
只看该作者 4楼 发表于: 2005-01-05
看WEILAI的图老看不到的说……

级别: 超级版主
注册时间:
2002-08-18
在线时间:
181小时
发帖:
14839
只看该作者 3楼 发表于: 2005-01-05
X燒包好多 = =.....

FREEWIND台湾,日本商品团购MSN群: group130599@xiaoi.com 欢迎入群讨论!!
贩售台湾正版CD,DVD,漫畫,輕小說,及台灣各種商品,采Door to Door服务有保障!!请大家告诉大家!!
※FREEWIND工作室官方掏宝店铺,请点我!!!※

※漫游FREEWIND工作室招募人才 請點我!※
※漫游FREEWIND工作室作品汇总 請點我!※
※漫游FREEWIND工作室招募分流FTP&P2P分流员 請點我!※

级别: 版主
注册时间:
2002-12-02
在线时间:
0小时
发帖:
3002
只看该作者 2楼 发表于: 2005-01-05
2. Avisynth 的filter 解碼

Avisynth 隨filter性質分為
.Source filters for producing a clip
.Filters for image processing
.Filters for Editing
.Filters for treating interlaced video
.Audio filters
.Special and exotic filters
.Debug filters

接下來我們藉由自由取得的Avisynth 程式碼來解開Source filters的秘密,進而化解一些對Avisynth的使用疑慮
一般使用下我們或許根本不需知道Avisynth 是如何運作的

但大家有沒有想過Avisynth 是個什麼樣的東西,能幫我們做到什麼地步的影音流服務
首先要知道的是Avisynth是對frame做工而frame是屬於視訊的範疇
所以Avisynth才一定要有個視訊流
而不能單純拿來處理音訊用
既然是個視訊流為主的服務器那基本就要有個 視訊源
最後也要有個 輸出
在獲得 視訊源 方面,我們常用到的兩個 filter 不外呼是 avisource 及 directshowsource
那這兩個 Source filters for producing a clip 有什麼不同
外觀上當然是可填的參數有一些不同
那內部呢?
差別在avisource 使用的是 DirectX的前身 MCI(Media Control Interface)
是程式寫作時調用多媒體功能的windows function
這些功能從原始的 winmm.dll之類的 windows系統檔使用 API 方式獲得
而directshowsource 使用的就是MS大力推舉的 DirectX,這個東西在多媒體方面使用的是DirectShow而使用方法是用 filter graph manager 當管理器

filter graph的好處是使用者可透過windows的註冊機制連接組合filter構成一個流程
而 MCI 就比較死了,程式怎麼寫就是怎麼做工,也因為filter graph的這項特點 directshowsource 能解碼的影音流較多
P.S. 但因此流程及記憶體等資源的使用量會比較多

得到Clip以後(Clip在這裡可泛指視訊、音訊、frame)接著就會用到一些 image processing或 Editing 的 filter
那這些 filter與 Source filter如何連串
其流程是 player 要求 Avisynth server
Avisynth server的 Source filter定位出的Clip結構
再由Script Execute器(Avisynth's filter engine)來重組
Avisynth的內部運作機制(或被機制拉動)
而這些filter(image processing、Editing...)就是 Avisynth內部運作機制的成員
最後Avisynth server 解碼的資料流
將會回到windows directshow 的 filter graph 流程上
這樣才可以被其他程式使用及連結
P.S. 此時Avisynth server 對外就像是個 filter一般

到此只是大概解釋,細部上要講解整個解說會越扯越多,因此這裡找個大家比較可能感興趣的運作機制來討論結語
AviSource("test.avi")
changeFPS(n)

再看看 Avisynth server 的解析流程圖


因此可知
雖然 changeFPS 寫在 AviSource 之後
但解碼上並不是 AviSource -> changeFPS 的絕對順序
而是由語法分析引擎來主導
所以解釋一個帶有 null frame 的視訊如何被處理就不能單純的看AviSource 或 changeFPS來解釋
第二帖先講到這
~待續~

P.S. 以下兩點 與 Avisynth原始碼 不謀而合
1.由 changeFPS原始碼可發現沒有frame解碼過程進而得證,雖然事實上一定先有AviSource才可changeFPS
2.Avisynth server使用的是拉模式:
source filter與一個parser filter連接,
parser filter向source filter請求數據,source filter回應請求並傳遞數據。
parser filter也向 changefps filter請求數據
所以再次解說了 "解碼上並不是 AviSource -> changeFPS 的絕對順序"

P.S. 詳細多媒體Directshow運作原理可看 http://www.mblogger.cn/ms.mblogger.cn/eyes4/default.htm

圖是沒問題
可能是 ISP 或其他因素導致 http://www.2and2.net 該站點無法及時回應而逾時
想看圖的話也可試試用 Flashget 下載看看
P.S. 目前沒有什麼好的貼圖地點還請多擔待 ^^

级别: 新手上路
注册时间:
2004-11-20
在线时间:
0小时
发帖:
15
只看该作者 1楼 发表于: 2005-01-04
我认为还是Keep Aspect Ratio好~
快速回复

限150 字节
上一个 下一个