打包TS流

做這個(gè)東西很久了,從去年十二月份開(kāi)始的,快5個(gè)月了。。。期間因?yàn)楣ぷ饕恢睌鄶嗬m(xù)續(xù),直到最近才有了些進(jìn)展,也就到此為止吧。

先說(shuō)下我做的是什么吧,總的來(lái)說(shuō),就是把H264視頻流與AAC音頻流封裝成TS格式。要完成這么個(gè)功能首先要解析H264和AAC,獲得視頻幀和音頻幀以及一些關(guān)鍵信息,比如幀率、采樣率什么的為以后的打包做工作。分析到每一幀數(shù)據(jù)后,再加上PES頭,封裝成PES數(shù)據(jù),在這個(gè)過(guò)程要注意打PTS、DTS,以及PES類(lèi)型的設(shè)定,一般來(lái)說(shuō),視頻PTS與DTS都要打,而音頻只需要打PTS。最后一步就是將PES數(shù)據(jù)封裝成TS了,這一步的坑比較多。做完這些,最難個(gè)人感覺(jué)就是音視頻同步了,至今還比較疑惑,視頻播出來(lái)總是有瑕疵。

一、解析h264

H264是以0x00 00 01或0x00 00 00 01作為分割NALU單元分割符的,整個(gè)H264也是以NALU作為基本單元的,NALU的結(jié)構(gòu)如圖一所示:


?圖1

NALU包含頭和負(fù)載RBSP,頭部的句法結(jié)構(gòu)如圖二所示:

·圖2

這一個(gè)字節(jié)便包含了整個(gè)頭部的信息,也就是去除分割符后的頭一個(gè)字節(jié)。nal_unit_type指明的NALU的類(lèi)型,不多說(shuō)了,貼圖吧。。。

圖3

NALU的負(fù)載RBSP在讀取有效數(shù)據(jù)之前首先要做去除競(jìng)爭(zhēng)碼的操作,遇到0x00 00 03將字節(jié)0x03去掉即可。

·0x00 00 00? -----> 0x00 00 03 00

·0x00 00 01? -----> 0x00 00 03 01

·0x00 00 02? -----> 0x00 00 03 02

·0x00 00 03? -----> 0x00 00 03 03

負(fù)載的類(lèi)型由前文nal_unit_type指定,當(dāng)值大于等于1,小于等于5的時(shí)候指明該負(fù)載是片數(shù)據(jù)(slice),去除競(jìng)爭(zhēng)碼后的負(fù)載采用的是哥倫布編碼。在看片數(shù)據(jù)句法結(jié)構(gòu)的時(shí)候可以留意到每個(gè)字段后面都有一些符號(hào)說(shuō)明,如ue(v)se(v),給張圖看的比較清楚

圖4

我貼的是片頭句法的一部分,在合成TS的時(shí)候只要判斷片類(lèi)型就可以了,也就是說(shuō),只要將圖4的slice_type分析出即可,要想完整的解出片還是有點(diǎn)難度的,不過(guò)判斷片的類(lèi)型并不難。

回到前面的哥倫布編碼,這是一種變長(zhǎng)編碼,括號(hào)里面帶v的均是指編碼的長(zhǎng)度不固定。

或根據(jù)哥倫布編碼動(dòng)態(tài)確定,或由前文指定,符號(hào)ue(v)se(v)說(shuō)明解碼的長(zhǎng)度可根據(jù)哥倫布編碼的規(guī)則動(dòng)態(tài)指定,而u(v)這里的解碼長(zhǎng)度得由上文指定,有幾個(gè)字段都是如此,如何由上文確定長(zhǎng)度的資料不太好找,只找到一個(gè)英文的網(wǎng)站,它說(shuō)明了幾個(gè)字段(http://m.blog.csdn.net/article/details?id=40302581)

解碼哥倫布編碼的字段可以選用網(wǎng)上的庫(kù),看起來(lái)還行,但因?yàn)槭窃谘芯繉W(xué)習(xí)這個(gè)東西,

我選擇了自己實(shí)現(xiàn)這個(gè)算法,也不是特別復(fù)雜。首先說(shuō)下無(wú)符號(hào)的哥倫布編碼,按網(wǎng)上的定義,哥倫布的編碼方式有0階、1階、2階...每種好像都不一樣,也沒(méi)有都去研究,因?yàn)镠264用到的只是0階的哥倫布編碼,弄懂這個(gè)就夠用了。

1.1無(wú)符號(hào)0階指數(shù)哥倫布編碼(ue)

按照算法的描述,應(yīng)先將數(shù)據(jù)以二進(jìn)制方式排列,接著連續(xù)讀取M個(gè)0比特位,碰到1比特位結(jié)束讀取,這時(shí)解碼的數(shù)據(jù)長(zhǎng)度就已經(jīng)確定了,為2*M+1個(gè)比特,包含前面已經(jīng)讀取的M個(gè)0比特。再將最后的M位比特轉(zhuǎn)化成十進(jìn)制數(shù)值W,即可獲得解碼結(jié)果為W-1,到此為止,一次完整的無(wú)符號(hào)解碼就完成了。

·無(wú)符號(hào)哥倫布編碼測(cè)試?yán)?

????????????????????????????????????????????????? (解碼后)

0x4C ?0x85 ?0x31 ?0xC4 ?0x09 =====> 1 ?2 ?3 ?4 ?5 ?6 ?7 ?8

1.2有符號(hào)0階指數(shù)哥倫布編碼(se)

有符號(hào)的哥倫布編碼建立在無(wú)符號(hào)的基礎(chǔ)上,按照無(wú)符號(hào)的解碼步驟得到十進(jìn)制數(shù)n后,再實(shí)行以下的動(dòng)作即可。

·獲取n被2除后的商w(注意這個(gè)商是去除了小數(shù)的整數(shù)部分)

·n不能被2整除,w加1為解碼結(jié)果

·n可以被2整除,w的相反數(shù)即為解碼結(jié)果

??????????????????????????????????????????????? (解碼后)

0x4C ?0x85 ?0x31 ?0xC4 ?0x09 =====>1 ?-1 ?2 ?-2 ?3 ?-3 ?4 ?-4

1.3幀類(lèi)型

前面在解析片數(shù)據(jù)的時(shí)候有提到過(guò)片的類(lèi)型,實(shí)際上這里指明的是片所裝載的視頻幀的類(lèi)型,按定義分為I,P,B,SP,SI,圖5給出slice_type與幀類(lèi)型的對(duì)應(yīng)關(guān)系

圖5

我在解碼的時(shí)候只關(guān)心了I,P,B幀,另外的兩種幀的意義感覺(jué)和I,P幀類(lèi)似,所以沒(méi)做過(guò)多的研究。I,P,B幀的差別在于編碼方式的差異,I幀數(shù)據(jù)不依賴(lài)其他的幀數(shù)據(jù),可獨(dú)立解碼,而P幀使用前向預(yù)測(cè)編碼,它的解碼依靠前面解碼的I幀和P幀,B幀用了雙向預(yù)測(cè)編碼,解碼B幀圖像,需要同時(shí)參考前后的幀數(shù)據(jù)。它們壓縮數(shù)據(jù)的能力也依次增強(qiáng),一般來(lái)說(shuō),B幀比較多的網(wǎng)絡(luò)視頻流同等比特量所傳輸?shù)囊曨l質(zhì)量會(huì)更高,但是相應(yīng)的,播放器的解碼壓力也更大。由于P、B幀的解碼需要參考其他幀,所以在解碼的時(shí)候可能會(huì)產(chǎn)生誤碼擴(kuò)散的情況,但由于播放器在遇到I幀的時(shí)候會(huì)丟棄之前解碼的視頻數(shù)據(jù),再以當(dāng)前的I幀作為以后P、B幀的參考幀,因此這一舉措及時(shí)的阻止了錯(cuò)誤的擴(kuò)散,說(shuō)到這里,我得額外提下HLS協(xié)議,這個(gè)協(xié)議在制作切片的時(shí)候總是以I幀開(kāi)頭,不僅是為了在播放視頻的時(shí)候立馬刷出圖像,我想更多的是因?yàn)镠264這種編碼格式的限制而不得不以I幀開(kāi)頭,因?yàn)橹挥蠭幀是可以獨(dú)立解碼的,如果開(kāi)頭的是其他需要參考的幀,他們的解碼毫無(wú)意義。

二、打包PES

PES是對(duì)裸流的一層封裝,H264和AAC就是兩種裸流,他們就像還沒(méi)裝訂的書(shū),隨意的被堆放在角落里,PES的封裝就是將散亂的紙打上頁(yè)碼裝成書(shū)的過(guò)程。這里的頁(yè)碼指的就是PTS與DTS,顯示時(shí)間戳和解碼時(shí)間戳,這個(gè)時(shí)間可以指示播放器何時(shí)顯示一幀圖像或者音頻,一般來(lái)說(shuō)視頻幀PTS、DTS都需要打,尤其是在有B幀的情況下,因?yàn)锽幀需要參考前后兩幀,所以它要等到前后幀都被解碼出后才能解此B幀,因此B幀的顯示時(shí)間和解碼時(shí)間是不一致的,而音頻幀沒(méi)有這種情況,解一幀放一幀即可,它是不需要DTS的。PES頭的句法結(jié)構(gòu)如圖6


?圖6(1)


? 圖6(2)

PES的整結(jié)構(gòu)沒(méi)有完整的貼上來(lái),只貼到PTS、DTS這部分句法,其實(shí)在打包TS的時(shí)候,這部分已經(jīng)夠用了,其他的可以不去關(guān)心。接下來(lái)說(shuō)明一下幾個(gè)重要的字段。

·packet_start_code_prefix

這3個(gè)字節(jié)是PES的起始碼,將PES包一一隔開(kāi),起始是固定的0x00 0x00 0x01

·stream_id

指明PES負(fù)載的類(lèi)型,視頻為0xE0,音頻為0xC0

·PES_packe_length

說(shuō)明在此字段最后一個(gè)字節(jié)之后PES分組的字節(jié)數(shù)?!?’值表明PES分組的長(zhǎng)度既沒(méi)有說(shuō)明也沒(méi)有限制,這種情況只有在PES分組的有效負(fù)載是傳送流分組中的視頻原始流時(shí)才允許。

·PTS_DTS_flag

2位標(biāo)志,若為‘10’,則PES分組首部有PTS字段;若為‘11’,則PES分組首部有PTS和DTS字段;若為’00’則PTS和DTS都不在PES分組首部出現(xiàn);‘01’值被禁止。

·PES_header_data_length

說(shuō)明在此字段最后一個(gè)字節(jié)還剩余的PES頭部分組數(shù)據(jù)量,一般可能指的是PTS與DTS部分編碼的長(zhǎng)度。

PES分組中比較重要的字段就上面這些的,對(duì)于PTS與DTS的編解碼,按照PTS_DTS_flag以及相應(yīng)的句法指示去做即可。

三、合成TS

TS流每個(gè)包的大小都介于188-204字節(jié)之間,一般就是188字節(jié),每個(gè)PES包基本都大于188字節(jié),所以在把PES封裝成TS時(shí),需要將PES分割成多個(gè)TS包,每個(gè)包都有唯一的ID標(biāo)識(shí)它的類(lèi)型,音視頻PES打包成TS包的ID由TS中的PMT表指定,PMT表被單獨(dú)打成一個(gè)TS包,它也有ID標(biāo)識(shí),這個(gè)標(biāo)識(shí)由PAT表指定,與PMT類(lèi)似,PAT也被打成獨(dú)立的包,它的ID是固定的0,所以,不管是解碼還是編碼TS流,都應(yīng)從PAT表入手。

3.1 TS包格式

? 圖7

TS包由頭與負(fù)載組成,頭部占四個(gè)字節(jié),如果還有自適應(yīng)區(qū),那么自適應(yīng)區(qū)的長(zhǎng)度由第五個(gè)字節(jié)指定。這里先簡(jiǎn)要的分析下TS頭的前四個(gè)字節(jié)。

·sync_byte

此處是同步字節(jié),固定為0x47

·transport_error_indicator

這個(gè)比特位我沒(méi)有用到過(guò),一直都是0

·payload_unit_start_indicator

此比特位為1,標(biāo)志著PES包負(fù)載的開(kāi)始,不僅如此,如果是PAT、PMT包,這里也被置為1

·transport_priority

我暫沒(méi)用到,默認(rèn)是0

·PID

每個(gè)包種類(lèi)的標(biāo)識(shí)

·transport_scrambling_control

我暫未使用

·adaptation_field_control

此字段標(biāo)識(shí)是否有自適應(yīng)區(qū)

00:是保留值。

01:負(fù)載中只有有效載荷。

10:負(fù)載中只有自適應(yīng)字段。

11:先有自適應(yīng)字段,再有有效載荷。

如果含有自適應(yīng)區(qū),那么頭四個(gè)字節(jié)后就是自適應(yīng)區(qū)的碼流結(jié)構(gòu),最后才是TS包的負(fù)載部分

·continuity_counter

這個(gè)字段的值從00 - 15反復(fù)連續(xù)變化

3.2自適應(yīng)區(qū)格式

?圖8

·adaptation_field_length

這個(gè)字節(jié)指明了自適應(yīng)區(qū)的長(zhǎng)度,不包含此字節(jié)

·PCR_flag

如果此位被置為1,按照句法格式,接下來(lái)存在PCR值,這個(gè)值按照特定的公式轉(zhuǎn)化成了program_reference_baseprogram_clock_reference_extension兩個(gè)字段的值

PCR是音視頻同步的關(guān)鍵參數(shù),它決定播放器什么時(shí)候播放一幀音頻或視頻,它本質(zhì)上是一個(gè)類(lèi)似于時(shí)間戳的東西,它可以用PES包的PTS或DTS來(lái)賦值,假設(shè)這個(gè)值是timestamp,那么就有

program_clock_reference_base= ?timestamp ??????(mod) ?2^33

program_clock_reference_extension ?= (300 * timestamp) ?(mod) ?300

PCR ?=program_clock_reference_base* 300 ?+program_clock_reference_extension

3.3PAT

?圖9

PAT表指明了PMT表的PID,每個(gè)PMT表又可以指出音視頻包的PID值,從這里可以看出一個(gè)PMT表就代表一個(gè)音視頻流,或者說(shuō)一個(gè)節(jié)目,當(dāng)有多種PMT表時(shí),說(shuō)明在這個(gè)TS流中存在多種音視頻流,多個(gè)節(jié)目,從而實(shí)現(xiàn)了節(jié)目復(fù)用的效果,實(shí)際上PAT表是可以索引多種PMT表的,但我在打流的時(shí)候只上了一種PMT,沒(méi)關(guān)系,東西在精不在多,把一種研究透了,其他的也就是復(fù)制粘貼的效果。

圖10貼的是PAT表負(fù)載的section部分,簡(jiǎn)單的劃分下PAT表四個(gè)區(qū)域,第一個(gè)是頭四個(gè)字節(jié),第二是自適應(yīng)區(qū),不過(guò)這個(gè)自適應(yīng)區(qū)沒(méi)內(nèi)容,因此標(biāo)志自適應(yīng)長(zhǎng)度的那個(gè)字節(jié)為0,第三個(gè)就是這個(gè)section部分,在里面指明了PMT表的PID值,第四個(gè)是填充區(qū)域,嚴(yán)格來(lái)說(shuō),它和section共同組成了ts包負(fù)載的部分,一般填充區(qū)域的比特位都置為1。

·table_id

PAT表此值為0

·section_syntax_indicator

此位置為1

·reserved

像這種標(biāo)志比特位都是置為1的

·section_length

這12位指出了從該字段之后到CRC_32(包含它)為止的字節(jié)數(shù)

·CRC_32

4字節(jié)的循環(huán)校驗(yàn)碼,它根據(jù)section區(qū)域動(dòng)態(tài)計(jì)算得出

3.4 PMT

圖10(1)
?圖10(2)

PMT表的作用是定位音視頻包的PID值,以方便播放器找到并解碼,接下來(lái)說(shuō)下幾個(gè)重要的字段。

·table_id

此處的值固定為0x02

·PCR_PID

這個(gè)字段指明了PCR值所在TS包的PID

·program_info_length

指定了接下來(lái)描述子decriptor()的大小,沒(méi)什么需要描述的就置為0吧

·stream_type

流類(lèi)型,如下圖所示


H264的視頻,流類(lèi)型為0x1b,AAC音頻一般為0x0f,隨后的PID值就是對(duì)應(yīng)的TS包標(biāo)識(shí)了

·ES_info_length

說(shuō)明ES流的附加信息,可有可無(wú),如果沒(méi)有附加信息,這個(gè)字段值為0

·CRC_32

與PAT的校驗(yàn)碼類(lèi)似

3.5打包H264視頻幀

一般來(lái)說(shuō),一個(gè)負(fù)載為I、P、B片的PES包可看做一幀,也許說(shuō)的不太準(zhǔn)確,一幀視頻從概念上說(shuō)是連環(huán)畫(huà)的完整的一頁(yè),而一片呢可能就只是一頁(yè)的局部畫(huà)面了,但我打包的時(shí)候是根據(jù)I、B、P片為單位的,為了好理解也叫一幀吧。

梳理下從H264到TS的過(guò)程,首先H264的單元叫NALU,一個(gè)I、B、P片就對(duì)應(yīng)一個(gè)NALU,NALU加上PES頭打上PTS或DTS后得到一個(gè)PES包,我們現(xiàn)在要做的就是將這個(gè)包含視頻數(shù)據(jù)的PES包分割成一個(gè)又一個(gè)的TS包,也就是打包一幀視頻。

PES包數(shù)據(jù)在打包TS時(shí),均作為T(mén)S包的負(fù)載部分。裝載PES的第一個(gè)TS包,前面說(shuō)過(guò),payload_unit_start_indicator字段要為1,這標(biāo)志著一幀PES數(shù)據(jù)的開(kāi)始。一般打包視頻幀的時(shí)候也會(huì)打上PCR的值,不是每幀都要打,不過(guò)對(duì)于I幀最好還是打上。還有一點(diǎn)要注意的是,在從NALU到PES的時(shí)候,在每幀數(shù)據(jù)前都要加上0x000000 01 09 xx這六個(gè)字節(jié),然后再打PES頭,xx的值好像可以任意選定,如此打出的流蘋(píng)果之類(lèi)的播放器才能支持。

最后再說(shuō)下I幀,在打包I幀的時(shí)候比打包其他兩幀有更多需要注意的問(wèn)題,首先,在I幀的前面最好能打上PAT與PMT表,如此一來(lái),在任意一段的TS流中,只要包含了I幀,那么有很大幾率可以被解碼播放,這也是TS流的一個(gè)特點(diǎn)。H264除開(kāi)包含I、B、P的NALU外,還有兩種包含視頻信息的NALU,SPS與PPS,分別是序列參數(shù)集與圖像參數(shù)集,他們對(duì)于解碼I、B、P片有重要作用,沒(méi)了這兩種NALU播放器是解碼不出視頻的,所以為了保證視頻能正常解碼,在打包TS流時(shí),這兩種NALU被放到了I幀數(shù)據(jù)的前面,它們是與I幀數(shù)據(jù)一起被封裝成PES包再分割成TS的,這與其他幀一個(gè)NALU對(duì)應(yīng)一個(gè)PES包有所不同。

在分割視頻的一個(gè)PES包時(shí),TS頭的continuity_counter值要保持連續(xù),從0-15反復(fù)變化。它接著上一次打包視頻幀時(shí)最后那個(gè)TS包的coutinuity_counter值連續(xù)變化。

3.6打包AAC音頻幀

AAC的格式比較簡(jiǎn)單,它的單元以0xFFF做為起始碼,我們打包的就是一個(gè)以0xFFF開(kāi)頭的AAC單元。我的做法是一個(gè)AAC單元對(duì)應(yīng)一個(gè)PES包,再分割成一個(gè)個(gè)TS包,這樣做可能有些浪費(fèi)數(shù)據(jù)量,因?yàn)橐粋€(gè)AAC單元相比一幀視頻要小得多,在打包成TS時(shí),為了保持每個(gè)TS包都是188字節(jié),在裝載PES數(shù)據(jù)的最后一個(gè)TS包時(shí)往往要加上填充字節(jié),填充字節(jié)是加在自適應(yīng)區(qū)的,由于一個(gè)AAC單元所裝載的數(shù)據(jù)量很小,所以相比于視頻幀來(lái)說(shuō),AAC單元的數(shù)量多,那么最后打成的TS包就含有較多無(wú)用的填充字節(jié),浪費(fèi)傳輸?shù)膸?,我看FFMPEG在打音頻幀的時(shí)候是10多個(gè)AAC單元被同時(shí)包成一個(gè)PES包的,我不知道它這樣打的規(guī)則,所以也沒(méi)有用,而且一個(gè)AAC單元對(duì)應(yīng)一個(gè)PES包的做法實(shí)現(xiàn)起來(lái)比較簡(jiǎn)單并且播放器也能正常解碼,所以就采用了這種打法。

打音頻幀比視頻幀簡(jiǎn)單多了,除了開(kāi)頭包的payload_unit_start_indicator要為1,以及coutinuity_counter值連續(xù)變化之外,沒(méi)有別的要求,不過(guò)還是要提醒一點(diǎn)的是coutinuity_counter值是接著上一次打包音頻數(shù)據(jù)的coutinuity_counter來(lái)的。

3.7音視頻同步

這個(gè)問(wèn)題我也在探究中,所以我這里不做說(shuō)明,只貼出幾個(gè)參考的鏈接,這些鏈接中包含了PTS與DTS的打法,但是沒(méi)有PCR的打法,我目前就是視頻幀PES包的PTS直接就作為T(mén)S包的PCR值了。

[TS流打包總結(jié)]

http://blog.csdn.net/yuan1125/article/details/51540918

[ffmpeg轉(zhuǎn)碼MPEG2-TS的音視頻同步機(jī)制分析]

http://blog.chinaunix.net/uid-26000296-id-3483782.html

四、后記

這次學(xué)習(xí)打TS流的過(guò)程我很滿(mǎn)意,雖然花費(fèi)的時(shí)間比較長(zhǎng),但這也算得上我第一次探究學(xué)習(xí)的經(jīng)歷吧,以前要學(xué)一樣?xùn)|西,資料總是齊備的,看幾眼就能知道個(gè)大概,因?yàn)槭窃趯W(xué)校,有教材與老師領(lǐng)著,但這僅限于教材上的東西,在進(jìn)入社會(huì)工作后,很多知識(shí)與技能都是沒(méi)有完備的教程的,即使有,可能也不一定能找得到。學(xué)習(xí)這些資料缺失的知識(shí)是一次探究學(xué)習(xí)的過(guò)程,因?yàn)橘Y料稀缺,為了了解其中一個(gè)知識(shí)面,不得不借助搜索工具大量查閱,在翻閱了幾十個(gè)網(wǎng)站終于得到一句話(huà)甚至是一個(gè)字的線(xiàn)索時(shí),那時(shí)不得不說(shuō),我是驚喜和滿(mǎn)足的,到最后我能打成一段可以播放的TS流時(shí),我覺(jué)得這五個(gè)月再長(zhǎng)也值了。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 教程一:視頻截圖(Tutorial 01: Making Screencaps) 首先我們需要了解視頻文件的一些基...
    90后的思維閱讀 4,988評(píng)論 0 3
  • [TOC] 音視頻&流媒體 是什么促使我要寫(xiě)這一篇音視頻入門(mén)文章?那是因?yàn)楹鸵幻米哟蛸€碼率的概念,結(jié)果輸了;對(duì)一個(gè)...
    AllenWu閱讀 5,180評(píng)論 1 24
  • 原文地址: http://www.360doc.com/content/16/0531/19/33873500_5...
    rogerwu1228閱讀 3,707評(píng)論 0 9
  • 數(shù)字電視有哪幾種層次的碼流?如何形成?各自特點(diǎn)? ES (Elementary Stream) — 數(shù)字電視各組成...
    Annnnnn閱讀 3,287評(píng)論 0 2
  • 寫(xiě)完“引”已然兩個(gè)半月了,而我總算在國(guó)慶假日的第四天,翻出了“高四”時(shí)的手稿以及那憂(yōu)郁一年的七張素畫(huà),還沒(méi)看...
    合秣閱讀 237評(píng)論 0 0

友情鏈接更多精彩內(nèi)容