# HLS 協(xié)議詳解

HLS 協(xié)議詳解

HLS 概述

HLS 全稱是 HTTP Live Streaming, 是一個(gè)由 Apple 公司實(shí)現(xiàn)的基于 HTTP 的媒體流傳輸協(xié)議. 他跟 DASH 協(xié)議的原理非常類似. 通過(guò)將整條流切割成一個(gè)小的可以通過(guò) HTTP 下載的媒體文件, 然后提供一個(gè)配套的媒體列表文件, 提供給客戶端, 讓客戶端順序地拉取這些媒體文件播放, 來(lái)實(shí)現(xiàn)看上去是在播放一條流的效果.

由于傳輸層協(xié)議只需要標(biāo)準(zhǔn)的 HTTP 協(xié)議, HLS 可以方便的透過(guò)防火墻或者代理服務(wù)器, 而且可以很方便的利用 CDN 進(jìn)行分發(fā)加速, 并且客戶端實(shí)現(xiàn)起來(lái)也很方便.

HLS 目前廣泛地應(yīng)用于點(diǎn)播和直播領(lǐng)域.

在 HTML5 頁(yè)面上使用 HLS 非常簡(jiǎn)單:

直接:

<video src="example.m3u8" controls></video>

或者:

<video controls>
    <source src="example.m3u8"></source>
</video>

下面, 我將會(huì)概括性地介紹 HLS 協(xié)議的方方面面(暫時(shí)不包括 AES 加密部分的內(nèi)容), 配合 HLS 的 RFC 食用效果更佳.

HLS 協(xié)議詳解

hls_arch

上面是 HLS 整體架構(gòu)圖, 可以看出, 總共有三個(gè)部分: Server, CDN, Client.

其實(shí), HLS 協(xié)議的主要內(nèi)容是關(guān)于 M3U8 這個(gè)文本協(xié)議的, 其實(shí)生成與解析都非常簡(jiǎn)單. 為了更加直接地說(shuō)明這一點(diǎn), 我下面舉兩個(gè)簡(jiǎn)單的例子:

簡(jiǎn)單的 Media Playlist:

#EXTM3U
#EXT-X-VERSION:3
#EXT-X-TARGETDURATION:8
#EXT-X-MEDIA-SEQUENCE:2680

#EXTINF:7.975,
https://priv.example.com/fileSequence2680.ts
#EXTINF:7.941,
https://priv.example.com/fileSequence2681.ts
#EXTINF:7.975,
https://priv.example.com/fileSequence2682.ts

包含多種比特率的 Master Playlist:

#EXTM3U
#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=1280000
http://example.com/low.m3u8
#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=2560000
http://example.com/mid.m3u8
#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=7680000
http://example.com/hi.m3u8
#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=65000,CODECS="mp4a.40.5"
http://example.com/audio-only.m3u8
  • HLS 通過(guò) URI(RFC3986) 指向的一個(gè) Playlist 來(lái)表示一個(gè)媒體流.
  • 一個(gè) Playlist 可以是一個(gè) Media Playlist 或者 Master Playlist, 使用 UTF-8 編碼的文本文件, 包含一些 URI 跟描述性的 tags.
  • 一個(gè) Media Playlist 包含一個(gè) Media Segments 列表,當(dāng)順序播放時(shí), 能播放整個(gè)完整的流.
  • 要想播放這個(gè) Playlist, 客戶端需要首先下載他, 然后播放里面的每一個(gè) Media Segment.
  • 更加復(fù)雜的情況是, Playlist 是一個(gè) Master Playlist, 包含一個(gè) Variant Stream 集合, 通常每個(gè) Variant Stream 里面是同一個(gè)流的多個(gè)不同版本(如: 分辨率, 碼率不同).

HLS Media Segments

  • 每一個(gè) Media Segment 通過(guò)一個(gè) URI 指定, 可能包含一個(gè) byte range.
  • 每一個(gè) Media Segment 的 duration 通過(guò) EXTINF tag 指定.
  • 每一個(gè) Media Segment 有一個(gè)唯一的整數(shù) Media Segment Number.
  • 有些媒體格式需要一個(gè) format-specific sequence 來(lái)初始化一個(gè) parser, 在 Media Segment 被 parse 之前. 這個(gè)字段叫做 Media Initialization Section, 通過(guò) EXT-X-MAP tag 來(lái)指定.

支持的 Media Segment 格式

MPEG-2 Transport Streams
  • 即最常見(jiàn)的 TS 文件.
  • RFC: ISO_13818.
  • Media Initialization Section: PAT(Program Association Table) 跟 PMT(Program Map Table).
  • 每個(gè) TS segment 必須值含一個(gè) MPEG-2 Program.
  • 每一個(gè) TS segment 包含一個(gè) PAT 和 PMT, 最好在 segment 的開(kāi)始處, 或者通過(guò)一個(gè) EXT-X-MAP tag 來(lái)指定.
Fragmented MPEG-4
  • 即常提到的 fMP4.
  • RFC: ISOBMFF.
  • Media Initialization Section: ftyp box(包含一個(gè)高于 ios6 的 brand), ftypbox 必須緊跟在 moov box 之后. moov box 必須包含一個(gè) trak box(對(duì)于每個(gè) fMP4 segment 里面的 traf box, 包含匹配的 track_ID). 每個(gè) trakbox 應(yīng)該包含一個(gè) sample table, 但是他的 sample count 必須為 0. mvhd box 跟 tkhd 的 duration 必須為 0. mvex box 必須跟在上一個(gè) trak box 后面.
  • 不像普通的 MP4 文件包含一個(gè) moov box(包含 sample tables) 和一個(gè) mdatbox(包含對(duì)應(yīng)的 samples), 一個(gè) fMP4 包含一個(gè) moof box (包含 sample table 的子集), 和一個(gè) mdat box(包含對(duì)應(yīng)的 samples).
  • 在每一個(gè) fMP4 segment 里面, 每一個(gè) traf box 必須包含一個(gè) tfdt box, fMP4 segment 必須使用 movie-fragment relative addressing. fMP4 segments 絕對(duì)不能使用外部的 data references.
  • 每一個(gè) fMP4 segment 必須有一個(gè) EXT-X-MAP tag.
Packed Audio
  • 一個(gè) Packed Audio Segment 包含編碼的 audio samples 和 ID3 tags. 簡(jiǎn)單的打包到一起, 包含最小的 framing, 并且沒(méi)有 per-sample timestamp.
  • 支持的 Packed Audio: AAC with ADTS framing [ISO_13818_7], MP3 [ISO_13818_3], AC-3 [AC_3], Enhanced AC-3 [AC_3].
  • 一個(gè) Packed Audio Segment 沒(méi)有 Media Initialization Section.
  • 每一個(gè) Packed Audio Segment 必須在他的第一個(gè) sample 指定 timestamp 通過(guò)一個(gè) ID3 PRIV tag.
  • ID3 PRIV owner identifier 必須是 com.apple.streaming.transportStreamTimestamp.
  • ID3 payload 必須是一個(gè) 33-bit MPEG-2 Program Elementary Stream timestamp 的大端 eight-octet number, 高 31 為設(shè)置為 0.
WebVTT
  • 一個(gè) WebVTT Segment 是一個(gè) WebVTT 文件的一個(gè) section, WebVTT Segment 包含 subtitles.
  • Media Initialization Section: WebVTT header.
  • 每一個(gè) WebVTT Segment 必須有以一個(gè) WebVTT header 開(kāi)始, 或者有一個(gè) EXT-X-MAP tag 來(lái)指定.
  • 每一個(gè) WebVTT header 應(yīng)該有一個(gè) X-TIMESTAMP-MAP 來(lái)保證音視頻同步.

HLS Playlists

  • Playlist 文件的格式是起源于 M3U, 并且繼承兩個(gè) tag: EXTM3UEXTINF
  • 下面的 tags 通過(guò) BNF-style 語(yǔ)法來(lái)指定.
  • 一個(gè) Playlist 文件必須通過(guò) URI(.m3u8 或 m3u) 或者 HTTP Content-Type 來(lái)識(shí)別(application/vnd.apple.mpegurl 或 audio/mpegurl).
  • 換行符可以用 \n 或者 \r\n.
  • # 開(kāi)頭的是 tag 或者注釋, 以 #EXT 開(kāi)頭的是 tag, 其余的為注釋, 在解析時(shí)應(yīng)該忽略.
  • Playlist 里面的 URI 可以用絕對(duì)地址或者相對(duì)地址, 如果使用相對(duì)地址, 那么是相對(duì)于 Playlist 文件的地址.

Attribute Lists

  • 有的 tags 的值是 Attribute Lists.
  • 一個(gè) Attribute List 是一個(gè)用逗號(hào)分隔的 attribute/value 對(duì)列表.
  • 格式為: AttributeName=AttributeValue.

Basic Tags

Basic Tags 可以用在 Media Playlist 和 Master Playlist 里面.

  • EXTM3U: 必須在文件的第一行, 標(biāo)識(shí)是一個(gè) Extended M3U Playlist 文件.
  • EXT-X-VERSION: 表示 Playlist 兼容的版本.

Media Segment Tags

每一個(gè) Media Segment 通過(guò)一系列的 Media Segment tags 跟一個(gè) URI 來(lái)指定. 有的 Media Segment tags 只應(yīng)用與下一個(gè) segment, 有的則是應(yīng)用所有下面的 segments. 一個(gè) Media Segment tag 只能出現(xiàn)在 Media Playlist 里面.

  • EXTINF: 用于指定 Media Segment 的 duration
  • EXT-X-BYTERANGE: 用于指定 URI 的 sub-range
  • EXT-X-DISCONTINUITY: 表示不連續(xù).
  • EXT-X-KEY: 表示 Media Segment 已加密, 該值用于解密.
  • EXT-X-MAP: 用于指定 Media Initialization Section.
  • EXT-X-PROGRAM-DATE-TIME: 和 Media Segment 的第一個(gè) sample 一起來(lái)確定時(shí)間戳.
  • EXT-X-DATERANGE: 將一個(gè)時(shí)間范圍和一組屬性鍵值對(duì)結(jié)合到一起.

Media Playlist Tags

Media Playlist tags 描述 Media Playlist 的全局參數(shù). 同樣地, Media Playlist tags 只能出現(xiàn)在 Media Playlist 里面.

  • EXT-X-TARGETDURATION: 用于指定最大的 Media Segment duration.
  • EXT-X-MEDIA-SEQUENCE: 用于指定第一個(gè) Media Segment 的 Media Sequence Number.
  • EXT-X-DISCONTINUITY-SEQUENCE: 用于不同 Variant Stream 之間同步.
  • EXT-X-ENDLIST: 表示結(jié)束.
  • EXT-X-PLAYLIST-TYPE: 可選, 指定整個(gè) Playlist 的類型.
  • EXT-X-I-FRAMES-ONLY: 表示每個(gè) Media Segment 描述一個(gè)單一的 I-frame.

Master Playlist Tags

Master Playlist tags 定義 Variant Streams, Renditions 和 其他顯示的全局參數(shù). Master Playlist tags 只能出現(xiàn)在 Master Playlist 中.

  • EXT-X-MEDIA: 用于關(guān)聯(lián)同一個(gè)內(nèi)容的多個(gè) Media Playlist 的多種 renditions.
  • EXT-X-STREAM-INF: 用于指定一個(gè) Variant Stream.
  • EXT-X-I-FRAME-STREAM-INF: 用于指定一個(gè) Media Playlist 包含媒體的 I-frames.
  • EXT-X-SESSION-DATA: 存放一些 session 數(shù)據(jù).
  • EXT-X-SESSION-KEY: 用于解密.

Media or Master Playlist Tags

這里的 tags 可以出現(xiàn)在 Media Playlist 或者 Master Playlist 中. 但是如果同時(shí)出現(xiàn)在同一個(gè) Master Playlist 和 Media Playlist 中時(shí), 必須為相同值.

  • EXT-X-INDEPENDENT-SEGMENTS: 表示每個(gè) Media Segment 可以獨(dú)立解碼.
  • EXT-X-START: 標(biāo)識(shí)一個(gè)優(yōu)選的點(diǎn)來(lái)播放這個(gè) Playlist.

服務(wù)器端與客戶端邏輯

以下流程僅供參考, 其實(shí)不同的播放器客戶端以及服務(wù)器端的拉取規(guī)則都有很多細(xì)節(jié)差異.

服務(wù)器端邏輯

  1. 將媒體源切片成 Media Segment, 應(yīng)該優(yōu)先從可以高效解碼的時(shí)間點(diǎn)來(lái)進(jìn)行切片(如: I-frame).
  2. 為每一個(gè) Media Segment 生成 URI.
  3. Server 需要支持 “gzip” 方式壓縮文本內(nèi)容.
  4. 創(chuàng)建一個(gè) Media Playlist 索引文件, EXT-X-VERSION 不要高于他需要的版本, 來(lái)提供更好的兼容性.
  5. Server 不能隨便修改 Media Playlist, 除了 Append 文本到文件末尾, 按順序移除 Media Segment URIs, 增長(zhǎng) EXT-X-MEDIA-SEQUENCEEXT-X-DISCONTINUITY-SEQUENCE, 添加 EXT-X-ENDLIST 到文件尾.
  6. 在最后添加 EXT-X-ENDLIST tag, 來(lái)減少 Client reload Playlist 的次數(shù).
  7. 注意點(diǎn)播與直播服務(wù)器不同的地方是, 直播的 m3u8 文件會(huì)不斷更新, 而點(diǎn)播的 m3u8 文件是不會(huì)變的, 只需要客戶端在開(kāi)始時(shí)請(qǐng)求一次即可.

客戶端邏輯

  1. 客戶端通過(guò) URI 獲取 Playlist. 如果是 Master Playlist, 客戶端可以選擇一個(gè) Variant Stream 來(lái)播放.
  2. 客戶端檢查 EXT-X-VERSION 版本是否滿足.
  3. 客戶端應(yīng)該忽略不可識(shí)別的 tags, 忽略不可識(shí)別的屬性鍵值對(duì).
  4. 加載 Media Playlist file.
  5. 播放 Media Playlist file.
  6. 重加載 Media Playlist file.
  7. 決定下一次要加載的 Media Segment.

HLS 的優(yōu)勢(shì)

  • 客戶端支持簡(jiǎn)單, 只需要支持 HTTP 請(qǐng)求即可, HTTP 協(xié)議無(wú)狀態(tài), 只需要按順序下載媒體片段即可.
  • 使用 HTTP 協(xié)議網(wǎng)絡(luò)兼容性好, HTTP 數(shù)據(jù)包也可以方便地通過(guò)防火墻或者代理服務(wù)器, CDN 支持良好.
  • Apple 的全系列產(chǎn)品支持, 由于 HLS 是蘋果提出的, 所以在 Apple 的全系列產(chǎn)品包括 iphone, ipad, safari 都不需要安裝任何插件就可以原生支持播放 HLS, 現(xiàn)在, Android 也加入了對(duì) HLS 的支持.
  • 自帶多碼率自適應(yīng), Apple 在提出 HLS 時(shí), 就已經(jīng)考慮了碼流自適應(yīng)的問(wèn)題.

HLS 的劣勢(shì)

  • 相比 RTMP 這類長(zhǎng)連接協(xié)議, 延時(shí)較高, 難以用到互動(dòng)直播場(chǎng)景.
  • 對(duì)于點(diǎn)播服務(wù)來(lái)說(shuō), 由于 TS 切片通常較小, 海量碎片在文件分發(fā), 一致性緩存, 存儲(chǔ)等方面都有較大挑戰(zhàn).

改進(jìn)的 HLS 技術(shù)

由于客戶端每次請(qǐng)求 TS 或 M3U8 有可能都是一個(gè)新的連接請(qǐng)求, 所以, 我們無(wú)法有效的標(biāo)識(shí)客戶端, 一旦出現(xiàn)問(wèn)題, 基本無(wú)法有效的定位問(wèn)題, 所以, 一般工業(yè)級(jí)的服務(wù)器都會(huì)對(duì)傳統(tǒng)的 HLS 做一些改進(jìn).

這里主要介紹網(wǎng)宿的 Variant HLS 與又拍云的 HLS+.

網(wǎng)宿的 Variant HLS

首先, 我們可以下載一條網(wǎng)宿的 M3U8 文件:

wget http://bililive.kksmg.com/hls/stvd6edb9a6_45b34047833af658bf4945a8/playlist.m3u8

然后, 打開(kāi)下載得到的 playlist 文件:

#EXTM3U
#EXT-X-STREAM-INF:PROGRAM-ID=1, BANDWIDTH=781000
http://bililive.kksmg.com/hls/stvd6edb9a6_45b34047833af658bf4945a8/playlist.m3u8?wsSession=0105cb4e8fe63bccab511a4a-149017212774715&wsIPSercert=b80d38c068c9e3634a7ebb2f2bbf9b89&wsMonitor=-1

可以看出這是一個(gè) Master Playlist, 里面嵌套了一層 M3U8, 同時(shí)可以看出網(wǎng)宿采用 wsSession 來(lái)標(biāo)識(shí)一條播放連接.

又拍云的 HLS+

Variant HLS

首先, 我們可以下載一條又拍云的 M3U8 文件:

wget http://uplive.b0.upaiyun.com/live/loading.m3u8

然后, 打開(kāi)下載得到的 playlist 文件:

#EXTM3U
#EXT-X-VERSION:3
#EXT-X-ALLOW-CACHE:YES
#EXT-X-MEDIA-SEQUENCE:0
#EXT-X-TARGETDURATION:1
#EXTINF:0.998, no desc
http://183.158.35.12:8080/uplive.b0.upaiyun.com/live/loading-0.ts?shp_uuid=e4989f34fcab282e21ef1fd2980284cb&shp_ts=1490172420851&shp_cid=17906&shp_pid=3370578&shp_sip0=127.0.0.1&shp_sip1=183.158.35.12&domain=uplive.b0.upaiyun.com&shp_seqno=0

可以看出又拍云的 HLS+ 也支持這種 Variant HLS 方式來(lái)標(biāo)識(shí)一條 HLS 連接, 可以看出, 又拍云使用 uuid 來(lái)表示一條 HLS 連接.

HTTP 302

首先, 以 HTTP 302 方式來(lái)請(qǐng)求播放地址.

? curl -v http://uplive.b0.upaiyun.com/live/loading.m3u8\?shp_identify\=302 -o playlist
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
  0     0    0     0    0     0      0      0 --:--:-- --:--:-- --:--:--     0*   Trying 183.158.35.59...
* TCP_NODELAY set
* Connected to uplive.b0.upaiyun.com (183.158.35.59) port 80 (#0)
> GET /live/loading.m3u8?shp_identify=302 HTTP/1.1
> Host: uplive.b0.upaiyun.com
> User-Agent: curl/7.51.0
> Accept: */*
>
< HTTP/1.1 302 Found
< Server: marco/0.26
< Date: Wed, 22 Mar 2017 08:54:11 GMT
< Content-Type: text/plain; charset=utf-8
< Content-Length: 259
< Connection: keep-alive
< Access-Control-Allow-Methods: GET
< Access-Control-Allow-Origin: *
< Location: http://183.158.35.19:8080/uplive.b0.upaiyun.com/live/loading.m3u8?shp_uuid=2862b1b817a74cf719b1cd8f554616cd&shp_ts=1490172851450&shp_cid=59553&shp_pid=1730488&shp_sip0=127.0.0.1&shp_sip1=183.158.35.19&domain=uplive.b0.upaiyun.com&shp_identify=302
<
{ [259 bytes data]
* Curl_http_done: called premature == 0
100   259  100   259    0     0   4813      0 --:--:-- --:--:-- --:--:--  4886
* Connection #0 to host uplive.b0.upaiyun.com left intact

打開(kāi) playlist 內(nèi)容:

Redirect to http://183.158.35.19:8080/uplive.b0.upaiyun.com/live/loading.m3u8?shp_uuid=2862b1b817a74cf719b1cd8f554616cd&shp_ts=1490172851450&shp_cid=59553&shp_pid=1730488&shp_sip0=127.0.0.1&shp_sip1=183.158.35.19&domain=uplive.b0.upaiyun.com&shp_identify=302

在跳轉(zhuǎn)之后的地址存放真正的 playlist, 同時(shí), 也能夠?qū)?uuid 加入到了連接上.

總地來(lái)說(shuō), 不管通過(guò)哪種方式, 最終我們都能通過(guò)一個(gè)唯一的 id 來(lái)標(biāo)識(shí)一條流, 這樣在排查問(wèn)題時(shí)就可以根據(jù)這個(gè) id 來(lái)定位播放過(guò)程中的問(wèn)題.

HLS 延時(shí)分析

HLS 理論延時(shí) = 1 個(gè)切片的時(shí)長(zhǎng) + 0-1個(gè) td (td 是 EXT-X-TARGETDURATION, 可簡(jiǎn)單理解為播放器取片的間隔時(shí)間) + 0-n 個(gè)啟動(dòng)切片(蘋果官方建議是請(qǐng)求到 3 個(gè)片之后才開(kāi)始播放) + 播放器最開(kāi)始請(qǐng)求的片的網(wǎng)絡(luò)延時(shí)(網(wǎng)絡(luò)連接耗時(shí))

為了追求低延時(shí)效果, 可以將切片切的更小, 取片間隔做的更小, 播放器未取到 3 個(gè)片就啟動(dòng)播放. 但是, 這些優(yōu)化方式都會(huì)增加 HLS 不穩(wěn)定和出現(xiàn)錯(cuò)誤的風(fēng)險(xiǎn).

Demo

Refs

轉(zhuǎn)自:http://akagi201.org/post/hls-explained/?hmsr=toutiao.io&utm_medium=toutiao.io&utm_source=toutiao.io

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市惶傻,隨后出現(xiàn)的幾起案子孔厉,更是在濱河造成了極大的恐慌最筒,老刑警劉巖幸海,帶你破解...
    沈念sama閱讀 206,214評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件逢渔,死亡現(xiàn)場(chǎng)離奇詭異热凹,居然都是意外死亡赐俗,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,307評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門众眨,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)握牧,“玉大人,你說(shuō)我怎么就攤上這事娩梨⊙匮” “怎么了?”我有些...
    開(kāi)封第一講書人閱讀 152,543評(píng)論 0 341
  • 文/不壞的土叔 我叫張陵狈定,是天一觀的道長(zhǎng)颂龙。 經(jīng)常有香客問(wèn)我,道長(zhǎng)掸冤,這世上最難降的妖魔是什么厘托? 我笑而不...
    開(kāi)封第一講書人閱讀 55,221評(píng)論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮稿湿,結(jié)果婚禮上铅匹,老公的妹妹穿的比我還像新娘。我一直安慰自己饺藤,他們只是感情好包斑,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,224評(píng)論 5 371
  • 文/花漫 我一把揭開(kāi)白布流礁。 她就那樣靜靜地躺著,像睡著了一般罗丰。 火紅的嫁衣襯著肌膚如雪神帅。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書人閱讀 49,007評(píng)論 1 284
  • 那天萌抵,我揣著相機(jī)與錄音找御,去河邊找鬼。 笑死绍填,一個(gè)胖子當(dāng)著我的面吹牛霎桅,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播讨永,決...
    沈念sama閱讀 38,313評(píng)論 3 399
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼滔驶,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了卿闹?” 一聲冷哼從身側(cè)響起揭糕,我...
    開(kāi)封第一講書人閱讀 36,956評(píng)論 0 259
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎锻霎,沒(méi)想到半個(gè)月后著角,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,441評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡量窘,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,925評(píng)論 2 323
  • 正文 我和宋清朗相戀三年雇寇,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片蚌铜。...
    茶點(diǎn)故事閱讀 38,018評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖嫩海,靈堂內(nèi)的尸體忽然破棺而出冬殃,到底是詐尸還是另有隱情,我是刑警寧澤叁怪,帶...
    沈念sama閱讀 33,685評(píng)論 4 322
  • 正文 年R本政府宣布审葬,位于F島的核電站,受9級(jí)特大地震影響奕谭,放射性物質(zhì)發(fā)生泄漏涣觉。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,234評(píng)論 3 307
  • 文/蒙蒙 一血柳、第九天 我趴在偏房一處隱蔽的房頂上張望官册。 院中可真熱鬧,春花似錦难捌、人聲如沸膝宁。這莊子的主人今日做“春日...
    開(kāi)封第一講書人閱讀 30,240評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)员淫。三九已至合蔽,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間介返,已是汗流浹背拴事。 一陣腳步聲響...
    開(kāi)封第一講書人閱讀 31,464評(píng)論 1 261
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留圣蝎,地道東北人挤聘。 一個(gè)月前我還...
    沈念sama閱讀 45,467評(píng)論 2 352
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像捅彻,于是被迫代替她去往敵國(guó)和親组去。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,762評(píng)論 2 345

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