react vr 視頻(video)源碼解析

react vr中文網(wǎng):www.vr-react.com

qq群:481244084

開發(fā)者頭條:react vr 原理解析

開發(fā)者頭條:React VR 視頻源碼解析

開發(fā)者頭條:react vr 消息傳遞原理解析

因?yàn)閞eact vr的視頻組件Video組件在手機(jī)上播放視頻會全屏疑苫,所以前面我寫了篇文章解決此事:解決react vr視頻在微信和瀏覽器上全屏的問題睦疫;

這里我再介紹下video的源碼,希望能幫助到您寻馏,此篇文章較長翘骂,建議對著源碼和本篇文章來閱讀壁熄,否則會暈暈乎乎的哦帚豪,就像蜘蛛網(wǎng)一樣的,首先看下下圖:


react? vr 視頻(video)源碼解析

圖片較大草丧,如果查看原圖志鞍,可以下載:http://www.vr-react.com/images/Video.png,

其中用到的幾個文件如下:

video:react-vr ---> Libraries ---> Video --->Video.js

MediaPlayerState:react-vr ---> Libraries ---> Video --->MediaPlayerState

RCTVideo:react-vr-web ---> js ---> Views ---> Video

RCTVideoPlayer: react-vr-web ---> js ---> Utils ---> RCTVideoPlayer

RCTVideoModule:react-vr-web ---> js --->Modules ---> RCTVideoModule

MediaEvent:react-vr-web ---> js --->Events ---> MediaEvent

VRVideoComponent:react-vr ---> Libraries ---> Video --->VRVideoComponent

BasicVideoPlayer:react-vr ---> Libraries ---> Video --->BasicVideoPlayer

其他的幾個引用文件在此就忽略啦,比如RCTBindedResource資源綁定文件方仿、ReactNativeContext RN的上下文對象固棚、EventEmitter事件發(fā)送、OVRUI.UIView等等仙蚜,后面抽空再給大家講解了此洲。

進(jìn)入正題:

下面就這幾個文件進(jìn)行簡單的講解,

一委粉、Video

1.1呜师、video是一個react 組件,首先創(chuàng)建一個React的class贾节,包含一堆屬性和方法:http://www.vr-react.com/Video.html汁汗,

如下圖:


video屬性和方法

1.2、componentWillMount訂閱監(jiān)聽播放狀態(tài)(play栗涂、pause知牌、seekTo、registerUserGesture斤程、unregisterUserGesture角寸、volumeChange、mutedChange)

這些狀態(tài)會通過UIMannager發(fā)送指令到原生那邊的Video組件(在react-vr-web里面)中忿墅,如下圖:


發(fā)送播放暫停指令

1.3扁藕、調(diào)用requireNativeComponent,把這個組件創(chuàng)建成一個React Native組件疚脐。

1.4亿柑、這個組件在UIManager的Video視圖中,傳下去兩個參數(shù)棍弄,一個是ReactNativeContext望薄,這是RN的上下文對象,一個是GuiSys照卦,這個是在ovrui內(nèi)部式矫,是管理Object3D乡摹、字體役耕、不透明度等等的一個UI工具。

下一步就到RCTVideo中了

二聪廉、RCTVideo

先來看下圖:

RCTVideo

2.1瞬痘、它繼承了BaseView故慈,構(gòu)造函數(shù)中有下面幾個成員:

? ? 2.1.1、實(shí)例化OVRUI的UIView的view

? ? 2.1.2框全、_localResource:綁定資源文件

? ? 2.1.3察绷、_rnctx:RN的上下文對象從UIManager的video實(shí)例化傳過來的參數(shù)

? ? 2.1.4、player是實(shí)例化的RCTVideoPlayer(../Utils/RCTVideoPlayer)津辩,傳進(jìn)去兩個參數(shù)拆撼,一個是上下文對象,一個是view的uuid喘沿,因?yàn)関iew都是OVRUI的uiview都是一個object3d對象闸度,都有一個唯一的uuid

重寫了player兩個方法,一個是onUpdateTexture蚜印,一個是onEmitEvent莺禁,后者是調(diào)用RN上下文的接受通知的事件,前者是回調(diào)函數(shù)窄赋,傳入的是資源哟冬,資源有內(nèi)部有uri,指向視頻對象忆绰,然后更新圖像紋理

? ? 2.1.5浩峡、_videoModule就是調(diào)用上下文中的rnctx.VideoModule,也就是在rnctx中實(shí)例化的RCTVideoModule模塊

? ? 2.1.6错敢、定義一些屬性(source红符、poster、playControl伐债、autoPlay预侯、loop、muted峰锁、volume萎馅、tintColor)

2.2、dispose釋放資源文件虹蒋,釋放player

2.3糜芳、接受指令receiveCommand,有三個指令魄衅,一個是COMMAND_SEEK_TO峭竣、尋找播放點(diǎn),一個是播放指令晃虫,一個是暫停指令皆撩,接收到指令分別調(diào)用player的對應(yīng)的方法

2.4、有一個靜態(tài)的describe方法,包含baseview的(onLayout扛吞、onEnter呻惕、onExit、onInput滥比、onChange亚脆、onHeadPose、onChangeCaptured盲泛、onInputCaptured濒持、onHeadPoseCaptured、onHeadPoseCaptured寺滚,自己的NativeProps(autoPlay弥喉、loop、muted玛迄、playControl由境、volume、source蓖议、poster)和四個Commands指令值(setImmediateOnTouchEnd這個是baseview的指令虏杰、seekTo、play勒虾、pause)

其中最主要的就是實(shí)例化的RCTVideoPlayer和RCTVideoModule纺阔,下面就到了。

三修然、RCTVideoPlayer


RCTVideoPlayer

內(nèi)部包含以下幾個屬性和方法:

3.1笛钝、rnctx = ReactNativeContext RN的上下文對象

3.2、_videoModule = rnctx.VideoModule愕宋,這個是Modules/RCTVideoModule的實(shí)例化:后面再講這個模塊

3.3玻靡、_tag就是上面闖過來的view的uuid全局唯一標(biāo)識

3.4、_counter = 0中贝;

3.5囤捻、_handle 句柄

3.6、_PlayStatus=‘closed’邻寿,這是PlayStatus的一個蝎土,'closed' | 'loading' | 'error' | 'ended' | 'paused' | 'playing' | 'ready'

3.7、_source 資源文件信息绣否,包含視頻格式誊涯、視頻路徑等

3.8、_poster 視頻暫停播放或者緩沖時(shí)的占位符

3.9蒜撮、_playControl 播放控制

3.10暴构、_autoPlay 自動播放

3.11、_loop 循環(huán)播放

3.12、_muted 是否靜音

3.13丹壕、_volume 音量

3.14、onUpdateTexture

3.15薇溃、onEmitEvent? 發(fā)送事件

3.16菌赖、_onCanPlay 能否播放

3.17、_onPlaying 播放中的事件

3.18沐序、_onPause 暫停播放事件

3.19琉用、_onEnded 結(jié)束播放事件

3.20、_onError 錯誤播放事件

3.21策幼、_onDurationChange

3.22邑时、_onTimeUpdate

3.23、RCTVideoPlayer.prototype的原型中定義了幾個方法:

3.23.1特姐、 setSource:

首先用_chooseSupportSource篩選出支持的視頻格式晶丘,

然后定義上一個視頻的url(prevUrl)

再定義當(dāng)前的視頻url(curUrl)

如果兩個url不一樣,剛開始preurl是null的唐含,播放完成了就可以切換視頻的source浅浮,如果當(dāng)前的視頻url(cururl)為空,定義一個prevHandle=this._handle捷枯,

this._handle = null;

如果 prevHandle存在滚秩,就更新紋理(_updateTexture),然后調(diào)用_videoModule的卸載prevHandle淮捆,視頻的狀態(tài)設(shè)置為關(guān)閉狀態(tài)(this._updatePlayStatus('closed');)

如果當(dāng)前的curUrl存在郁油,同樣設(shè)置prevHandle=this._handle,

this._counter += 1;

this._handle = [curUrl, this._tag, this._counter].join('-');定義一個handle標(biāo)識

然后調(diào)用_videoModule的addHandle攀痊、setUrl桐腌、setFormat、如果有元數(shù)據(jù)設(shè)置元數(shù)據(jù)setMetaData苟径、_addMediaEventListener(監(jiān)聽canplay哩掺、playing、pause涩笤、ended嚼吞、error、durationchange蹬碧、timeupdate)

然后調(diào)用_videoModule的加載load(this._handle);

如果原來的prevHandle存在舱禽,就卸載(this._videoModule.unload(prevHandle))

更新播放狀態(tài)為加載中( this._updatePlayStatus('loading');)

如果_poster存在,更新_poster紋理恩沽;

最后_updateVideoStates更新視頻狀態(tài)誊稚,其實(shí)就是設(shè)置靜音、設(shè)置音量

給source添加一個uri標(biāo)識符,然后調(diào)用onUpdateTexture里伯,這個方式Video傳下來的

3.23.2城瞎、 setPoster(url): 如果當(dāng)前的播放狀態(tài)是loading,調(diào)用_updateTextureWithPoster ---> onUpdateTexture(這個方法是上面的video傳下來的)

3.23.3疾瓮、 play: 如果_handle存在脖镀,調(diào)用_videoModule的播放功能

3.23.4、 pause: 如果_handle存在狼电,調(diào)用_videoModule的暫停功能

3.23.5蜒灰、 seekTo: 設(shè)置新的播放起點(diǎn),進(jìn)度條拖拽用的

3.23.6肩碟、 setPlayControl: 如果_handle存在强窖,看輸入的播放控制如果是pause,就調(diào)用_videoModule的暫停功能削祈,如果是play就調(diào)用_videoModule的播放功能

3.23.7翅溺、 setAutoPlay 設(shè)置自動播放

3.23.8、 setLoop 設(shè)置循環(huán)播放

3.23.9髓抑、 setMuted 如果_handle存在未巫,就設(shè)置靜音,this._videoModule.setMuted(this._handle, this._muted);

3.23.10启昧、 setVolume 檢查輸入的音量是否是數(shù)字叙凡,如果不是就是1.如果_handle存在,就設(shè)置音量密末,this._videoModule.setVolume(this._handle, this._volume);

3.23.11握爷、 dispose,如果_handle存在,釋放這個句柄严里,this._videoModule.unload(this._handle);

四新啼、RCTVideoModule


RCTVideoModule

這是個模塊,繼承了Module

4.1刹碾、 構(gòu)造函數(shù)中有下面幾個成員燥撞,supportedFormats支持的視頻格式、_videoDefs(src迷帜、format物舒、metaData)进苍、_players是Video/VRVideoComponent實(shí)例超凳、_rnctx上下文對象峻凫、_mediaEventCallbacks事件回調(diào)

同樣有下面的幾個方法:

4.2蒂教、addHandle(handle)

實(shí)例化播放器對象 const player = new VRVideoComponent(); 并設(shè)置給this._players[handle],

初始化事件回調(diào)對象 this._mediaEventCallbacks[handle] = {};

初始化播放器的onMediaEvent事件:

4.3赫舒、 _onMediaEvent(handle: string, event: Object)蚤霞,這里面主要是處理監(jiān)聽事件的功能镣煮、一個是發(fā)送到react的,一個是發(fā)送到native的悉盆,接受事件啥的都要經(jīng)過這兒盯荤。

4.4、 _addMediaEventListener監(jiān)聽事件焕盟,上面RCTVideoPlayer調(diào)用的秋秤,意思就是把監(jiān)聽的方法都放到 this._mediaEventCallbacks[handle][eventType]本模塊的事件回調(diào)里面統(tǒng)一管理

4.5、 移除某個監(jiān)聽 this._mediaEventCallbacks[handle][eventType]

4.6京髓、 setUrl 設(shè)置視頻地址:this._videoDefs[handle].src = url;

4.7航缀、 setFormat 設(shè)置視頻格式:this._videoDefs[handle].format = format;

4.8商架、 setMetaData 設(shè)置視頻的預(yù)算內(nèi)數(shù)據(jù) this._videoDefs[handle].metaData = metaData;

4.9堰怨、 getVideoTexture 拿到當(dāng)前視頻的紋理,this._players[handle].videoTextures[0];

4.10蛇摸、load 設(shè)置視頻备图,把上面的url、format赶袄、metaData設(shè)置進(jìn)去 this._players[handle].setVideo(this._videoDefs[handle]);

同時(shí)把資源加載到 mono 紋理中揽涮,this._rnctx.RCTResourceManager.addResource('MonoTexture', handle, monoTextureInfo);

4.11、 play? this._players[handle].videoPlayer.play(); 其實(shí)調(diào)用的是VRVideoPlayer的getVideoPlayer(this.videoDef)饿肺,最后調(diào)用的是BasicVideoPlayer蒋困,最后調(diào)用的html的video標(biāo)簽的方法

4.12、 pause this._players[handle].videoPlayer.pause();

4.13敬辣、 seekTo this._players[handle].videoPlayer.seekTo(position);

4.14雪标、 setMuted this._players[handle].videoPlayer.setMuted(muted);

4.15、 setVolume this._players[handle].videoPlayer.setVolume(volume);

4.16溉跃、 unload 移除mono紋理資源村刨、釋放播放器資源、刪除播放器撰茎、刪除_videoDefs的視頻資源嵌牺、刪除回調(diào)事件_mediaEventCallbacks

4.17、 frame 調(diào)用播放器的 frame() 方法龄糊;

五逆粹、MediaEvent


MediaEvent

這里面只有一個構(gòu)造函數(shù),有三個成員炫惩,一個是type枯饿、一個是timeStamp(時(shí)間戳)、一個是target里面的currentTime(當(dāng)前播放時(shí)間)诡必、duration(持續(xù)時(shí)間)奢方、ended(是否播放完畢)搔扁、error(錯誤)

他們的值只不過是提取了event.target的一部分

六、VRVideoComponent


VRVideoComponent

6.1蟋字、 構(gòu)造函數(shù)中有這么幾個成員:videoPlayer(null))稿蹲、videoTextures([])、onMediaEvent鹊奖、_onMediaEvent

6.2苛聘、 setVideo 設(shè)置視頻資源:

_freeVideoPlayer:釋放播放器,如果播放器存在就釋放掉(dispose),然后設(shè)置為null

_freeTexture:釋放紋理忠聚,遍歷videoTextures里面的成員设哗,然后逐個釋放dispose,然后把、videoTextures設(shè)置為[]

_setVideoDef: 設(shè)置視頻两蟀,把上面的url网梢、format、metaData設(shè)置進(jìn)去

videoPlayer:實(shí)例化播放器赂毯,通過new 一個 VRVideoPlayer.getVideoPlayer(this.videoDef)战虏,上面就是繼承了BasicVideoPlayer類,默認(rèn)返回一個BasicVideoPlayer党涕,默認(rèn)的播放器烦感,下面再講這個東東

綁定onMediaEvent,

新建threejs紋理膛堤,const texture = new THREE.Texture(this.videoPlayer.videoElement); 設(shè)置給 this.videoTextures[0] = texture

然后初始化視頻手趣,調(diào)用this.videoPlayer.initializeVideo(videoDef.src, videoDef.metaData)

6.3、 frame 如果播放器存在肥荔,而且有足夠的數(shù)據(jù)hasEnoughData(這個判斷video標(biāo)簽存在绿渣,而且this.videoElement.readyState === this.videoElement.HAVE_ENOUGH_DATA),就遍歷videoTextures次企,并且刷新紋理 調(diào)用this.videoTextures[i].needsUpdate = true;

6.4怯晕、 dispose:釋放播放器 _freeVideoPlayer,釋放紋理_freeTexture缸棵,釋放onMediaEvent

七舟茶、BasicVideoPlayer


BasicVideoPlayer

7.1、 構(gòu)造函數(shù)

videoElement就是創(chuàng)建了一個html的video dom標(biāo)簽堵第,并把這個標(biāo)簽加到document.body上

_volume=1.0

this._muted = false;

this.onMediaEvent = undefined;

(this: any)._onMediaEvent = this._onMediaEvent.bind(this);

7.2吧凉、 初始化視頻 initializeVideo

設(shè)置video的src、crossOrigin(跨域)踏志、給video標(biāo)簽綁定事件_bindMediaEvents(監(jiān)聽canplay阀捅、playing、pause针余、ended饲鄙、error凄诞、durationchange、timeupdate)忍级、調(diào)用video的load方法

7.3帆谍、 hasEnoughData

判斷video標(biāo)簽存在,而且this.videoElement.readyState === this.videoElement.HAVE_ENOUGH_DATA

7.4轴咱、 setVolume汛蝙、setMuted、play朴肺、pause窖剑、seekTo都是調(diào)用video標(biāo)簽的相應(yīng)功能

7.5、 dispose 暫停播放pause戈稿、從document.body移除video西土,src設(shè)置為'',移除監(jiān)聽事件

上面就是這幾個文件的方法和屬性及相互調(diào)用關(guān)系器瘪,但是我們?nèi)绾问褂胿ideo的其他事件呢翠储?

八绘雁、監(jiān)聽video的其他的功能


BasicVideoPlayer

8.1橡疼、首先在BasicVideoPlayer上,添加以上添加備注的東東庐舟,因?yàn)闉g覽器的video標(biāo)簽監(jiān)聽事件還有這些東東欣除;

8.2、監(jiān)聽事件的回調(diào)就是VRVideoComponent的onMediaEvent挪略,同樣再次會回調(diào)給RCTVideoModule的_onMediaEvent的方法內(nèi)历帚;

在RCTVideoModule內(nèi)部的加上剩余的東東:


RCTVideoModule

8.3、加上上面的東東杠娱,就可以增加其他的監(jiān)聽事件了挽牢,這里面會調(diào)向react 和 native各發(fā)送 監(jiān)聽回調(diào)事件,

react這個方法是調(diào)用想下文的callFunction摊求,調(diào)用RCTDeviceEventEmitter的emit方法禽拔,this._rnctx.callFunction('RCTDeviceEventEmitter','emit', [callbackName,handle,mediaEvent]);

另外一個是在native上增加監(jiān)聽

8.4、在RCTVideoPlayer中加入下面的代碼

1

8.5室叉、在setSource的方法內(nèi)增加其他的上面的監(jiān)聽睹栖,還要添加下面的代碼,我這里只是監(jiān)聽了loadstart這個狀態(tài),取得值是readyState的值茧痕。你也可以監(jiān)聽上面的其他狀態(tài)


setSource添加監(jiān)聽

同時(shí)還要在上面寫一個_newEmitter的方法野来,


添加_newEmitter方法

最后在最上面的RCTVideoPlayer的方法體內(nèi)綁定這個事件:


把_newEmitter綁定到RCTVideoPlayer

8.6、剛剛我們在_newEmitter方法內(nèi)部發(fā)送了一個topLoadStart的監(jiān)聽事件踪旷,為了讓這個事件綁定到react組件上曼氛,需要在UIManager上添加注冊自定義的事件類型:

也就是找到 react-vr-web ---> js ---> Modules ---> UIManager里面的this.customDirectEventTypes豁辉,

然后在最后添加事件注冊名字,也就是下圖的最后一行代碼:


注冊事件類型

8.7舀患、為了驗(yàn)證我們能收到信息秋忙,可以在react-vr ---> Librearies ---> video的里面添加如下的代碼:

首先在propTypes內(nèi)部添加一個屬性:


添加屬性
在render中添加具體的屬性綁定

8.8、最后在index.vr.js里面的video組件下面添加newEmitter屬性构舟,內(nèi)部是回調(diào)方法灰追,就可以拿到html的video標(biāo)簽在loadstart狀態(tài)下的數(shù)據(jù)了。


業(yè)務(wù)添加newEmitter屬性

8.9狗超、最后重新打開服務(wù)弹澎,npm? start,打開瀏覽器,輸入http://localhost:8081/vr/努咐,查看調(diào)試console打印


看上圖的index.vr.js 104行打印的東西苦蒿,readyStart為0,也就是在loadstart剛開始加載數(shù)據(jù)的之前渗稍,沒有音視頻信息佩迟;

你也可以監(jiān)聽下圖的其他狀態(tài):


新增的video監(jiān)聽的狀態(tài)

下面這幾個對應(yīng)的信息是video的readyStart對應(yīng)的狀態(tài):

0 = HAVE_NOTHING - 沒有關(guān)于音頻/視頻是否就緒的信息

1 = HAVE_METADATA - 關(guān)于音頻/視頻就緒的元數(shù)據(jù)

2 = HAVE_CURRENT_DATA - 關(guān)于當(dāng)前播放位置的數(shù)據(jù)是可用的,但沒有足夠的數(shù)據(jù)來播放下一幀/毫秒

3 = HAVE_FUTURE_DATA - 當(dāng)前及至少下一幀的數(shù)據(jù)是可用的

4 = HAVE_ENOUGH_DATA - 可用數(shù)據(jù)足以開始播放

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末竿屹,一起剝皮案震驚了整個濱河市报强,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌拱燃,老刑警劉巖秉溉,帶你破解...
    沈念sama閱讀 217,826評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異碗誉,居然都是意外死亡召嘶,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,968評論 3 395
  • 文/潘曉璐 我一進(jìn)店門哮缺,熙熙樓的掌柜王于貴愁眉苦臉地迎上來弄跌,“玉大人,你說我怎么就攤上這事尝苇☆踔唬” “怎么了?”我有些...
    開封第一講書人閱讀 164,234評論 0 354
  • 文/不壞的土叔 我叫張陵茎匠,是天一觀的道長格仲。 經(jīng)常有香客問我,道長诵冒,這世上最難降的妖魔是什么凯肋? 我笑而不...
    開封第一講書人閱讀 58,562評論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮汽馋,結(jié)果婚禮上侮东,老公的妹妹穿的比我還像新娘圈盔。我一直安慰自己,他們只是感情好悄雅,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,611評論 6 392
  • 文/花漫 我一把揭開白布驱敲。 她就那樣靜靜地躺著,像睡著了一般宽闲。 火紅的嫁衣襯著肌膚如雪众眨。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,482評論 1 302
  • 那天容诬,我揣著相機(jī)與錄音娩梨,去河邊找鬼。 笑死览徒,一個胖子當(dāng)著我的面吹牛狈定,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播习蓬,決...
    沈念sama閱讀 40,271評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼纽什,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了躲叼?” 一聲冷哼從身側(cè)響起芦缰,我...
    開封第一講書人閱讀 39,166評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎押赊,沒想到半個月后饺藤,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體包斑,經(jīng)...
    沈念sama閱讀 45,608評論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡流礁,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,814評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了罗丰。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片神帅。...
    茶點(diǎn)故事閱讀 39,926評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖萌抵,靈堂內(nèi)的尸體忽然破棺而出找御,到底是詐尸還是另有隱情,我是刑警寧澤绍填,帶...
    沈念sama閱讀 35,644評論 5 346
  • 正文 年R本政府宣布霎桅,位于F島的核電站,受9級特大地震影響讨永,放射性物質(zhì)發(fā)生泄漏滔驶。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,249評論 3 329
  • 文/蒙蒙 一卿闹、第九天 我趴在偏房一處隱蔽的房頂上張望揭糕。 院中可真熱鬧萝快,春花似錦、人聲如沸著角。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,866評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽吏口。三九已至奄容,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間产徊,已是汗流浹背嫩海。 一陣腳步聲響...
    開封第一講書人閱讀 32,991評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留囚痴,地道東北人叁怪。 一個月前我還...
    沈念sama閱讀 48,063評論 3 370
  • 正文 我出身青樓,卻偏偏與公主長得像深滚,于是被迫代替她去往敵國和親奕谭。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,871評論 2 354

推薦閱讀更多精彩內(nèi)容