亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁(yè) > 學(xué)院 > 編程設(shè)計(jì) > 正文

bilibili彈幕轉(zhuǎn)ass程序制作思路及過(guò)程

2020-02-02 19:01:04
字體:
來(lái)源:轉(zhuǎn)載
供稿:網(wǎng)友

b站的彈幕,線下播放還是挺麻煩的,專用的彈幕播放器對(duì)其他格式的視頻支持不好。我也試著弄個(gè)彈幕轉(zhuǎn)字幕的小程序出來(lái)。

抓取xml文件的工作就不多說(shuō)了,很簡(jiǎn)單的事,只要在播放頁(yè)面看看源文件就能確定xml文件的地址進(jìn)行抓取了。

本文主要是講述xml內(nèi)的彈幕轉(zhuǎn)字幕的過(guò)程。

除去xml文件開頭結(jié)尾的一些七七八八的東西,彈幕主體是這樣的:

<d p="51.593,5,25,16711680,1408852480,0,7fa769b4,576008622">怒求 up 自己配音!</d><d p="10.286,1,25,16777215,1408852600,0,a3af4d0d,576011065">顏藝?</d><d p="12.65,1,25,16777215,1408852761,0,24570b5a,576014281">我的女神!</d><d p="19.033,1,25,16777215,1408852789,0,cb20d1c7,576014847">前!??!</d><d p="66.991,1,25,16777215,1408852886,0,a78e484d,576016806">已擼</d>

如果它把彈幕的各種屬性分開表示,我就用encoding/xml包來(lái)解碼,但是丫把彈幕的屬性都放在p里面了,所以我使用正則表達(dá)式來(lái)提取的。

以上表第一條彈幕為例。很明顯的,p屬性開始的浮點(diǎn)數(shù),與播放時(shí)一比對(duì),就能知道,表示的是彈幕應(yīng)該出現(xiàn)的播放時(shí)間。隨后的1和25先不管;16777215,目測(cè)應(yīng)該是顏色(因?yàn)樵撝当硎緸槭M(jìn)制是FFFFFF);1408852480,在彈幕中是遞增的,感覺應(yīng)該是個(gè)unix時(shí)間,用這個(gè)數(shù)(d),求:d/86400/365.2425+1970,結(jié)果約為2014.6??磥?lái)確實(shí)是unix時(shí)間。估計(jì)是創(chuàng)建彈幕的時(shí)間。0,不知道,抓取了很多視頻的彈幕,這個(gè)位置都是0,暫且不管它。7fa769b4,估計(jì)是創(chuàng)建者的ID,因?yàn)橥粁ml文件會(huì)出現(xiàn)多次,而且看起來(lái)是十六進(jìn)制數(shù),恰好有些hash函數(shù)就是返回4字節(jié)整數(shù)。576008622,也是遞增的,不用猜也知道,這個(gè)肯定就是彈幕的ID了。

事后再核對(duì)一下,果然,1代表彈幕的類型(從右向左移動(dòng)啊,出現(xiàn)在下方或者上方啊……),25是字體大小,16777125是字體顏色。

所以,我們就只要捕獲每條彈幕的時(shí)間、類型、大小、顏色、文本就行了。

正則表達(dá)式:

<d/sp="([/d/.]+),([145]),(/d+),(/d+),/d+,/d+,/w+,/d+">([^<>]+?)</d>


捕獲彈幕很簡(jiǎn)單,關(guān)鍵是排布彈幕為字幕的算法。
關(guān)于這個(gè)算法我就很坑爹的弄了個(gè)亂七八糟的算法,采用的是固定移動(dòng)速度,最小重疊的排布原則。

對(duì)游動(dòng)彈幕,會(huì)傾向于選擇下面一行的位置,如果會(huì)重疊,則選擇更下一行(最低行會(huì)循環(huán)到最上面一行),如果沒有不重疊的行,會(huì)選擇重疊文本最少的行。

對(duì)上現(xiàn)隱/下現(xiàn)隱的固定彈幕,會(huì)選擇最接近上方/下方,且不重疊的行;如果沒有不重疊的行,則選擇重疊時(shí)間最短的行,居中放置字幕。

默認(rèn)字體微軟雅黑,默認(rèn)大小25,默認(rèn)白色黑邊;默認(rèn)占滿整個(gè)屏幕,共計(jì)12行;默認(rèn)屏幕大小640x360。

這么弄,主要是為了讓ass字幕的效果更接近原始彈幕的效果。

高級(jí)彈幕真的超出我的能力范圍了,全部忽略掉。

go源代碼如下:

// 將bilibili的xml彈幕文件轉(zhuǎn)換為ass字幕文件。// xml文件中,彈幕的格式如下:// <d p="32.066,1,25,16777215,1409046965,0,017d3f58,579516441">地板好評(píng)</d>// p的屬性為時(shí)間、彈幕類型、字體大小、字體顏色、創(chuàng)建時(shí)間、?、創(chuàng)建者ID、彈幕ID。// p的屬性中,后4項(xiàng)對(duì)ass字幕無(wú)用,舍棄。被<d>和</d>包圍的是彈幕文本。// 只處理右往左、上現(xiàn)隱、下現(xiàn)隱三種類型的普通彈幕。package main import (  "fmt"  "io"  "io/ioutil"  "math"  "os"  "regexp"  "sort"  "strconv"  "strings") // ass文件的頭部const header = `[Script Info]ScriptType: v4.00+Collisions: NormalplayResX: 640playResY: 360 [V4+ Styles]Format: Name, Fontname, Fontsize, primaryColour, SecondaryColour, OutlineColour, BackColour, Bold, Italic, Underline, StrikeOut, ScaleX, ScaleY, Spacing, Angle, BorderStyle, Outline, Shadow, Alignment, MarginL, MarginR, MarginV, EncodingStyle: Default, Microsoft YaHei, 28, &H00FFFFFF, &H00FFFFFF, &H00000000, &H00000000, 0, 0, 0, 0, 100, 100, 0.00, 0.00, 1, 1, 0, 2, 10, 10, 10, 0 [Events]Format: Layer, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text` // 正則匹配獲取彈幕原始信息var line = regexp.MustCompile(`<d/sp="([/d/.]+),([145]),(/d+),(/d+),/d+,/d+,/w+,/d+">([^<>]+?)</d>`) // 用來(lái)保管彈幕的信息type Danmu struct {  text string  time float64  kind byte  size int  color int} // 使[]Danmu實(shí)現(xiàn)sort.Interface接口,以便排序type Danmus []Danmu func (d Danmus) Len() int {  return len(d)}func (d Danmus) Less(i, j int) bool {  return d[i].time < d[j].time}func (d Danmus) Swap(i, j int) {  d[i], d[j] = d[j], d[i]} // 將正則匹配到的數(shù)據(jù)填寫入Danmu類型里func fill(d *Danmu, s [][]byte) {  d.time, _ = strconv.ParseFloat(string(s[1]), 64)  d.kind = s[2][0] - '0'  d.size, _ = strconv.Atoi(string(s[3]))  bgr, _ := strconv.Atoi(string(s[4]))  d.color = ((bgr >> 16) & 255) | (bgr & (255 << 8)) | ((bgr & 255) << 16)  d.text = string(s[5])} // 返回文本的長(zhǎng)度,假設(shè)ascii字符都是0.5個(gè)字長(zhǎng),其余都是1個(gè)字長(zhǎng)func length(s string) float64 {  l := 0.0  for _, r := range s {    if r < 127 {      l += 0.5    } else {      l += 1    }  }  return l} // 生成時(shí)間點(diǎn)的ass格式表示:`0:00:00.00`func timespot(f float64) string {  h, f := math.Modf(f / 3600)  m, f := math.Modf(f * 60)  return fmt.Sprintf("%d:%02d:%05.2f", int(h), int(m), f*60)} // 讀取文件并獲取其中的彈幕func open(name string) ([]Danmu, error) {  data, err := ioutil.ReadFile(name)  if err != nil {    return nil, err  }  dan := line.FindAllSubmatch(data, -1)  ans := make([]Danmu, len(dan))  for i := len(dan) - 1; i >= 0; i-- {    fill(&ans[i], dan[i])  }  return ans, nil} // 將彈幕排布并寫入w,采用的簡(jiǎn)單的固定移速、最小重疊排布算法func save(w io.Writer, dans []Danmu) {  p1 := make([]float64, 36)  p2 := make([]float64, 36)  p3 := make([]float64, 36)  t := 0  max := func(x []float64) float64 {    i := x[0]    for _, j := range x[1:] {      if i < j {        i = j      }    }    return i  }  set := func(x []float64, f float64) {    for i, _ := range x {      x[i] = f    }  }  find := func(p []float64, f float64, i, d int) int {    i = (i/d + 1) * d % 36    m, k := f+10000, 0    for j := 0; j < 36; j += d {      t := (i + j) % 36      if n := max(p[t : t+d]); n <= f {        k = t        break      } else if m > n {        k = t        m = n      }    }    return k  }  for _, dan := range dans {    s, l := "", length(dan.text)    if l == 0 {      continue    }    switch {    case dan.size < 25:      dan.size, l, s = 2, l*18, "http://fs18"    case dan.size == 25:      dan.size, l = 3, l*28    case dan.size > 25:      dan.size, l, s = 4, l*38, "http://fs38"    }    if dan.color != 0x00FFFFFF {      s += fmt.Sprintf("http://c&H%06X", dan.color)    }    switch dan.kind {    case 1: // 右往左      t := find(p1, dan.time, t, dan.size)      set(p1[t:t+dan.size], dan.time+8)      h := (t+dan.size)*10 - 1      s += fmt.Sprintf("http://move(%d,%d,%d,%d)", 640+int(l/2), h, -int(l/2), h)      fmt.Fprintf(w, "Dialogue: 1,%s,%s,Default,,0000,0000,0000,,{%s}%s/n",        timespot(dan.time+0),        timespot(dan.time+8), s, dan.text)    case 4: // 下現(xiàn)隱      j := find(p2, dan.time, 35, dan.size)      set(p2[j:j+dan.size], dan.time+4)      s += fmt.Sprintf("http://pos(%d,%d)", 320, (36-j)*10-1)      fmt.Fprintf(w, "Dialogue: 2,%s,%s,Default,,0000,0000,0000,,{%s}%s/n",        timespot(dan.time+0),        timespot(dan.time+4), s, dan.text)    case 5: // 上現(xiàn)隱      j := find(p3, dan.time, 35, dan.size)      set(p3[j:j+dan.size], dan.time+4)      s += fmt.Sprintf("http://pos(%d,%d)", 320, (j+dan.size)*10-1)      fmt.Fprintf(w, "Dialogue: 3,%s,%s,Default,,0000,0000,0000,,{%s}%s/n",        timespot(dan.time+0),        timespot(dan.time+4), s, dan.text)    }  }} // 主函數(shù),實(shí)現(xiàn)了命令行func main() {  if len(os.Args) <= 1 {    os.Exit(0)  }  for _, name := range os.Args[1:] {    dans, err := open(name)    if err != nil {      os.Exit(1)    }    if n := strings.LastIndex(name, "."); n != -1 {      name = name[:n]    }    name += ".ass"    file, err := os.Create(name)    if err != nil {      os.Exit(2)    }    file.WriteString(header)    sort.Sort(Danmus(dans))    save(file, dans)    file.Close()  }}


2014.9.2 9:30am更新:對(duì)字體排布進(jìn)行了修正。

2014.9.2 9:50am更新:算法修改為固定出現(xiàn)時(shí)間,最小重疊排布,最終版本。

over。歡迎各位評(píng)論,倒不如各位多多評(píng)論啊。

發(fā)表評(píng)論 共有條評(píng)論
用戶名: 密碼:
驗(yàn)證碼: 匿名發(fā)表

圖片精選

欧美国产一级片| 四虎影视最新网址| 国内精品久久久久久久影视麻豆| 欧美日韩国产二区| 污网站在线免费看| 欧美在线免费视频| 国产麻豆一级片| 成人激情电影一区二区| 日本一区二区三区电影免费观看| 99久久久精品免费观看国产蜜| 天天综合网色中文字幕| 日韩中出av| 日本中文字幕中出在线| 久久久噜噜噜www成人网| 国产毛片毛片毛片毛片毛片毛片| 嫩草影院在线观看网站成人| 黄色片视频免费| 无码人妻丰满熟妇精品| 婷婷久久综合网| 国产午夜精品一区二区理论影院| 制服.丝袜.亚洲.另类.中文| 亚洲一区二区在线播放| 久久久av亚洲男天堂| 蜜臀av一区二区在线免费观看| 国产免费av一区| 成全视频在线播放大地| 污污网站在线观看| 日本aⅴ免费视频一区二区三区| av超碰免费在线| 亚洲欧洲视频在线观看| h视频网站在线观看| 国产女同互慰高潮91漫画| 无码国精品一区二区免费蜜桃| 亚洲精品乱码久久久久久蜜桃动漫| 欧美性生活久久| 视频在线观看一区二区| 久色视频在线观看| 欧美老年两性高潮| 99国产精品久久一区二区三区| 在线观看黄色av网站| 国产乱了高清露脸对白| 欧美gv在线观看| 成人在线高清| 亚洲熟妇国产熟妇肥婆| 欧美人在线视频| 77777亚洲午夜久久多人| 九九热在线视频观看| 精品少妇人欧美激情在线观看| 成人在线不卡| avav在线看| 欧美一区二区三级| 午夜理伦三级做爰电影| 2222www色视频在线观看| 欧美日韩国产在线播放| 国产精品制服诱惑| 欧美高清性粉嫩交| 欧美日韩精品欧美日韩精品一| 美国av免费观看| 亚洲天堂黄色| 性欧美高清强烈性视频| 97国产成人无码精品久久久| 在线观看成人一级片| 精品毛片网大全| 亚洲女同性videos| 欧美最猛黑人xxxxx猛交| 精品无码在线视频| 欧美一级精品片在线看| 深夜福利视频网站| 四虎884aa成人精品最新| 久久婷婷国产综合国色天香| 国产日韩欧美中文在线| 欧美风情在线视频| 中文人妻熟女乱又乱精品| 欧美成人嫩草网站| 亚洲va欧美va天堂v国产综合| 国产精品免费人成网站| 久久裸体视频| 国产精品揄拍一区二区| 66久久国产| 亚洲淫成人影院| 日韩天天综合| av大片免费观看| 最近中文字幕2019第二页视频| 亚洲欧美久久精品| 欧美午夜精品久久久久久久| 国产精品视频一区二区三区综合| 青青青草网站免费视频在线观看| 久88久久88久久久| 欧美华人在线视频| 18深夜在线观看免费视频| 久久久久久久久99精品| 免费人成又黄又爽又色| 中文字幕日韩精品久久| 国内精品福利| 欧美日韩精品高清| wwwxxx黄色片| 亚洲a区在线视频| 色呦呦在线播放| 日韩经典中文字幕一区| 成人在线免费观看91| 免费在线黄色网址| 草草久久久无码国产专区| 在线精品一区二区| 久久婷婷一区二区| 亚洲欧美精品在线观看| 免费国产麻豆传| 欧美xxxx在线| 另类色图亚洲色图| 欧美一激情一区二区三区| 一区在线观看免费| 少妇精品久久久久久久久久| 久久久亚洲欧洲日产| 先锋影音国产一区| av无码精品一区二区三区宅噜噜| 性xxxx18| 久久亚洲私人国产精品va| 中文字幕一区二区人妻痴汉电车| 久久成人免费观看| 成人午夜精品久久久久久久蜜臀| 精产国品一区二区| 日韩精品一页| 免费播放片a高清在线观看| 日韩av在线中文字幕| eeuss影院130020部| 日韩久久久久| 国产精品专区免费| 在线观看免费毛片| 久久激情中文| 日韩.com| 日韩欧美在线视频日韩欧美在线视频| 久草精品在线观看| 人妻换人妻a片爽麻豆| 日本视频一区二区| 日韩精品看片| 美日韩一二三区| 久久久99精品免费观看不卡| 日韩福利视频导航| 免费黄色一级大片| 性色av一区| 五月婷婷丁香网| 国内精品国产成人国产三级| 在线免费观看羞羞视频一区二区| 亚洲成人精品视频| 国产在线观看精品| av中文字幕一区二区| 亚洲成人中文字幕在线| 亚洲日本中文| 日本成人在线免费| 91电影在线播放| 亚洲欧美精品伊人久久| 国内精品伊人久久久久av一坑| 夜夜夜夜夜夜操| 亚洲国产婷婷| 日韩视频专区| 卡通动漫精品一区二区三区| 日本三级电影在线看| 精品视频一二区| 丁香啪啪综合成人亚洲小说| 国产在线播放不卡| 国产性天天综合网| 国产精品不卡在线观看| 欧美亚洲视频一区| 97在线观看免费高清视频| 日韩综合网站| 国产在线观看网站| 一区二区三区视频网| 婷婷五月色综合| 欧洲杯半决赛直播| 8x8x最新地址| 免费欧美电影| 91视频综合| 任我爽精品视频在线播放| 国产乱子伦精品无码专区| 亚洲免费精品视频| 婷婷国产在线综合| 国产乱码久久久久久| 777国产偷窥盗摄精品视频| 欧美激情护士| 亚洲图片制服诱惑| 97在线观看免费观看高清| gogogo免费高清日本写真| 91最新在线观看| 成全电影播放在线观看国语| 少妇av在线播放| 在线综合亚洲欧美在线视频| 经典一区二区三区| 日韩天堂在线| 欧美日韩一区二区三区在线观看免| 在线观看免费黄色小视频| 国产精品对白刺激久久久| 精品欧美一区二区三区免费观看| 亚洲午夜精品久久久中文影院av| а√天堂中文资源在线bt| 色偷偷888欧美精品久久久| 欧美mv日韩mv国产网站| 91亚洲国产高清| 免费大片在线观看| 欧美精品一区二区三区在线| 国产视频精选在线| 久久亚洲欧美日韩精品专区| 久久久久久久少妇| 国产精品你懂的在线| 欧美日韩综合在线| 亚洲最大成人在线视频| 精品处破学生在线二十三| 亚洲人成电影网站色mp4| 国产精品羞羞答答在线| 亚洲人成啪啪网站| 日韩精品电影一区二区| 久久亚洲国产成人精品性色| 亚洲视频一起| 国产91免费观看| 污软件在线观看| 国产三级在线观看| 国产精选在线视频拍拍拍| 9i精品福利一区二区三区| 亚洲第一成人在线视频| 国产伦精品一区二区三| 岳乳丰满一区二区三区| 久草在线资源站手机版| 领导边摸边吃奶边做爽在线观看| 人妖一区二区三区| 一区二区在线观看视频在线| 成人综合网址| 欧美国产一区二区三区| 高清免费电影在线观看| 18视频在线观看娇喘| 乱子伦在线视频| 波多野结衣家庭主妇| a中文字幕www| 中国女人久久久| 国产高清不卡一区| 精品福利影院| 久久久久久久久久久久av| 日本一区二区不卡在线| 欧美日韩破处视频| 成人a在线视频免费观看| 日韩精品影院| 欧美三级日本三级| 亚洲精品一区二区在线看| 国产区欧美区日韩区| 中文.日本.精品| 欧美国产精品va在线观看| 1024精品合集| 黄色网页免费看| 国产精品专区h在线观看| 国产成人3p视频免费观看| 日韩高清在线播放| 韩国中文字幕hd久久精品| 欧美大片免费播放器| 5g影院5g天天爽永久免费影院| 麻豆传媒在线免费| 欧美人与物videos| 美女网站视频色| 可以看污的网站| 欧美一区二区三区公司| 国产h视频在线观看| 欧美做受高潮6| 欧美日韩123区| 国产精品日韩在线| 蜜臀91精品国产高清在线观看| 最近最新mv在线观看免费高清| 人妻有码中文字幕| 成人黄色一级大片| 精品99在线观看| 久久全国免费视频| 羞羞答答国产精品www一本| 午夜视频一区二区三区| 97视频免费| 国产精品45p| 国产网站一区二区三区| 欧美精品久久久| av资源亚洲| 特一级黄色大片| 欧美日韩成人一区二区三区| 国产电影一区二区| 日韩大陆欧美高清视频区| 手机在线看片日韩| 亚洲精品日韩综合观看成人91| 亚洲精品乱码久久久久久按摩观| 中文字幕人妻熟女人妻洋洋| 国产欧美视频一区二区三区| 日韩电影免费观看高清完整版在线观看| 成人精品在线| 亚洲美女精品视频| 50度灰在线观看| 欧美一级网站| 成人小说亚洲一区二区三区| 亚洲啊啊啊啊啊| 青青艹视频在线| 日本精品久久久久久| 国产精品 日产精品 欧美精品| 天天影视欧美综合在线观看| 日韩中文字幕亚洲精品欧美| 中文字幕av一区二区三区谷原希美| 免费黄色影片在线| 成人免费毛片app| 五月婷婷色综合| 极品一区美女高清| 午夜亚洲成人| 免费久久精品| 国产99久久久| 精品亚洲aⅴ乱码一区二区三区| 久久av一区二区三区漫画| 亚洲精品中文字幕乱码三区不卡| 91精品小视频| 亚洲激情自拍偷拍| 国产精品狼人久久影院观看方式| 九九在线高清精品视频| 久久久久亚洲精品国产| 精品在线免费观看视频| 四虎成人免费观看在线网址| 欧洲美女和动交zoz0z| 少妇性l交大片7724com| 亚洲精品在线a| 真实原创一区二区影院| 偷拍精品精品一区二区三区| 一区二区成人国产精品| 亚洲国产精品高清久久久| 99九九99九九九视频精品| 97cao在线| 欧美白嫩的18sex少妇| 国产在线观看免费视频软件| 欧美丰满艳妇bbwbbw| 欧美成人一级| seseavlu视频在线| 亚洲性受xxx喷奶水| 交100部在线观看|