實時傳輸協(xié)議 RTP 和 RTCP

為滿多媒體應(yīng)用傳輸實時數(shù)據(jù)的需要, IETF RFC 3550 定義了實時傳輸協(xié)議RTP: A Transport Protocol for Real-Time Applications 即為實時應(yīng)用程序所定義的傳輸協(xié)議, 它為交互式音頻和視頻聊天和會議應(yīng)用提供端到端的傳輸服務(wù).

RTP 解決的問題

讓我們先想想實時傳輸需要解決哪些問題:

  1. 順序 Sequence
    多媒體數(shù)據(jù)包需要保序, 否則就會前言不搭后語, 讓人不知所云, 通常我們可以用 sequenceNumber 來標(biāo)識數(shù)據(jù)包的順序, 通過它我們可以知道:
  • 是否有數(shù)據(jù)包丟失
  • 是否發(fā)生數(shù)據(jù)包亂序
  • 是否需要進(jìn)行無序解碼
  1. 時間和緩存 Timstamp and buffer

我們還需要知道數(shù)據(jù)包的時間, 在回放語音和視頻時需要按規(guī)定的時間線播放并操持音視頻同步, 所以一個 timestamp 是必需的, 通過它我們可以用來

  • 回放
  • 計算網(wǎng)絡(luò)抖動和延遲
  1. 載荷類型辨識 Payload type

我們需要知道數(shù)據(jù)包里承載的是什么內(nèi)容, 媒體內(nèi)容是音頻還是視頻, 是什么編碼類型, 所以還需要一個 payload type

  1. 錯誤隱藏 Error concealment

錯誤總是難以避免的, 特別是在網(wǎng)絡(luò)基于 UDP 的傳輸, 當(dāng)發(fā)現(xiàn)網(wǎng)絡(luò)丟包, 延遲, 亂序時我們要采取一些錯誤隱藏技術(shù), 比如在相鄰幀中添加冗余來掩蓋丟包的錯誤, 或者自動插入一些重復(fù)數(shù)據(jù)包

  1. 服務(wù)質(zhì)量反饋 QoS feedback

當(dāng)語音或視頻質(zhì)量不佳時, 接收端需要告訴發(fā)送端做出調(diào)整, 或者調(diào)整發(fā)送速率或分辨率, 或者重新發(fā)送關(guān)鍵幀等, 這就需要一些度量報告, 比如 接收者報告RR(Receiver Report ) 和發(fā)送者報告SR(Sender Report)。

根據(jù)上述的問題和需求, RTP 協(xié)議由此制訂出來, 它主要包括兩塊

  1. 承載具有實時性質(zhì)的數(shù)據(jù)的實時傳輸協(xié)議RTP实蔽。
  2. 在進(jìn)行的會話中監(jiān)視服務(wù)質(zhì)量并傳輸會話參與者信息的實時傳輸控制協(xié)議RTCP枷颊。

1. RTP

RTP 通忱晕Γ基于 UDP 傳輸, 因為多媒體數(shù)據(jù)可以忍受少量丟包, 卻不能忍受數(shù)據(jù)包延時過大, 如圖所示:

RTP協(xié)議棧

它的數(shù)據(jù)包格式如下:

RTP 數(shù)據(jù)包格式g

包頭詳細(xì)解釋如下:

  • V(version) 版本號, 2 個比特位, 當(dāng)前版本為2
  • P(pad) 填充位, 1個比特位, 當(dāng)它為1時表示在數(shù)據(jù)包的末尾包含一個或多個不屬于載荷的填充字節(jié), 填充的最后一個字節(jié)包含一個計數(shù)值, 表示所填充的字節(jié)數(shù)
  • X (eXtenstion) 擴(kuò)展位, 1個比特位, 當(dāng)它為1時表示存在一個擴(kuò)展頭
  • CC(Contribution Count) , 貢獻(xiàn)源的數(shù)量, 4個比特位, 定義其后的CSRC(Contributing Source) 的數(shù)量, 若無貢獻(xiàn)源(這路多媒體數(shù)據(jù)沒有合并自其他數(shù)據(jù)源), 則此項為零.
  • M(Marker) 標(biāo)記位, 1個比特位, 不同的 RTP Profile 配置有不同定義, 一個應(yīng)用數(shù)據(jù)幀可能分割成若干個RTP 數(shù)據(jù)包, 這個字段用來在某個RTP數(shù)據(jù)包中標(biāo)記應(yīng)用數(shù)據(jù)幀是否開始或結(jié)束
  • PT(Payload Type) 載荷類型, 7個比特位, 標(biāo)識RTP 載荷的格式, 表示一個RTP 數(shù)據(jù)包中所承載的內(nèi)容到底是什么, 是音頻還是視頻, 是什么編碼
  • Sequene Number 順序號, 16個比特位, 順序號的起始值是隨機(jī)的, 發(fā)送者每發(fā)送一個RTP數(shù)據(jù)包, 順序號就會加1, 接收者可以通過它來檢查是否有丟包和亂序, 由應(yīng)用程序來決定如何應(yīng)對
  • Timestamp 時間戳, 32個比特位, 表示 RTP數(shù)據(jù)包中第一個字節(jié)的采樣時間, 采樣時間是單調(diào)和線性增長, 可以通過它來做同步和計算抖動, 它并不是我們通常所說的一天中的某個時間,而是從一個隨機(jī)的時間戳開始以一個相對值不斷增加的采樣個數(shù), 比如最常見的音頻編碼G.711 PCMU的采樣率是8000 Hz, 采樣間隔為125微秒, 一個數(shù)據(jù)包的長度是20ms, 其實包含了20/0.125=160個采樣, 一秒鐘就有1000ms/20ms=50幀, 時間戳每個包就會增長160, 每秒增長160*50=8000, 在多媒體回放時需要以它為參考。
  • SSRC(Synchronization Source) 同步源標(biāo)識符, 32個比特位, 它在一個RTP 會話中唯一表示RTP的一個數(shù)據(jù)源, 比如麥克風(fēng), 攝像頭這樣的信號源, 也可能是一個混合器, 它作為一個中間設(shè)備將多個源混合在一起
  • CSRC(Contribution Source) 貢獻(xiàn)源列表, 是n 個32比特位, n 是前面的 CC 字段指定的, 不超過2^4=16個, 它表示包含在這個數(shù)據(jù)包中的載荷的貢獻(xiàn)源, 比如我們在音頻會議中聽到三個人在討論問題, 這個數(shù)據(jù)包中包含了這三路語音混合在一起的音頻數(shù)據(jù), 這個貢獻(xiàn)源列表就有三個, 包含代表每個人的麥克風(fēng)的同步源析二。

RTP 標(biāo)準(zhǔn)頭之后就是載荷了, 如圖所示:

RTP 數(shù)據(jù)包負(fù)載g

SDP 描述如下:

v=0
o=sample 496886 497562 IN IP4 127.0.0.1
s=sammple_rtp_session
c=IN IP4 127.0.0.1
t=0 0
m=audio 18276 RTP/AVP 102 13 98 99
a=sprop-source:1 csi=932617472;simul=1
a=sprop-simul:1 1 *
a=recv-source 1,2,3
a=rtpmap:102 iLBC/8000
a=rtpmap:13 CN/8000
a=rtpmap:98 CN/16000
a=rtpmap:99 CN/32000
a=extmap:1 urn:ietf:params:rtp-hdrext:ssrc-audio-level
a=extmap:2 urn:ietf:params:rtp-hdrext:toffset
a=ptime:20

由此可知數(shù)據(jù)包長度共為 118 字節(jié), 其中:

  • 數(shù)據(jù)鏈接層: 16 字節(jié)
  • IP 數(shù)據(jù)包頭: 20 字節(jié)
  • UDP 數(shù)據(jù)包頭: 8 字節(jié), 其載荷為RTP數(shù)據(jù)包:
    • RTP 數(shù)據(jù)包: 74 字節(jié)
      • RTP 數(shù)據(jù)包頭: 12 字節(jié)
      • RTP 擴(kuò)展頭: 4字節(jié)
      • RTP 載荷: 58字節(jié)

2. RTCP

RTCP 實時傳輸控制協(xié)議, 它的主要目的就是基于度量來控制 RTP 的傳輸來改善實時傳輸?shù)男阅芎唾|(zhì)量, 它主要有5種類型的RTCP包:

  1. RR接收者報告Receiver Report
  2. SR發(fā)送者報告 Sender Report
  3. SDES數(shù)據(jù)源描述報告 Source DEScription
  4. BYE 告別報告 Goodbye
  5. APP 應(yīng)用程序自定義報告 Application-defined packet

RR, SR, SDES 可用來匯報在數(shù)據(jù)源和目的之間的多媒體傳輸信息, 在報告中包含一些統(tǒng)計信息, 比如 RTP包 發(fā)送的數(shù)量, RTP包丟失的數(shù)量, 數(shù)據(jù)包到達(dá)的抖動, 通過這些報告, 應(yīng)用程序就可以修改發(fā)送速率, 也可做一些其他調(diào)整以及診斷。

RTCP 數(shù)據(jù)包類型

它也是基于 UDP 包進(jìn)行傳輸:

RTCP 數(shù)據(jù)包棧

RTCP 的數(shù)據(jù)包格式如下:

RTCP packet
  • 版本(V):同RTP包頭域。

  • 填充(P):同RTP包頭域钥勋。

  • 接收報告計數(shù)器(RC):5比特,該SR包中的接收報告塊的數(shù)目辆苔,可以為零算灸。

  • 包類型(PT):8比特,SR包是200驻啤。

  • 長度域(Length):16比特菲驴,其中存放的是該SR包以32比特為單位的總長度減一。

  • 同步源(SSRC):SR包發(fā)送者的同步源標(biāo)識符骑冗。與對應(yīng)RTP包中的SSRC一樣赊瞬。

  • NTP Timestamp(Network time protocol)SR包發(fā)送時的絕對時間值先煎。NTP的作用是同步不同的RTP媒體流。1900.1.1至今的秒數(shù)64bits: 32 bits 整數(shù)部分 + 32 bits 小數(shù)部分

  • RTP Timestamp:與NTP時間戳對應(yīng)巧涧,與RTP數(shù)據(jù)包中的RTP時間戳具有相同的單位和隨機(jī)初始值榨婆。

  • Sender’s packet count:從開始發(fā)送包到產(chǎn)生這個SR包這段時間里,發(fā)送者發(fā)送的RTP數(shù)據(jù)包的總數(shù). SSRC改變時褒侧,這個域清零良风。

  • Sender`s octet count:從開始發(fā)送包到產(chǎn)生這個SR包這段時間里,發(fā)送者發(fā)送的凈荷數(shù)據(jù)的總字節(jié)數(shù)(不包括頭部和填充)闷供。發(fā)送者改變其SSRC時烟央,這個域要清零。

  • 同步源n的SSRC標(biāo)識符:該報告塊中包含的是從該源接收到的包的統(tǒng)計信息歪脏。

  • 丟失率(Fraction Lost):表明從上一個SR或RR包發(fā)出以來從同步源n(SSRC_n)來的RTP數(shù)據(jù)包的丟失率疑俭。

  • Cumulative number of packets lost 24bits:
    累計的包丟失數(shù)目:從開始接收到SSRC_n的包到發(fā)送SR,從SSRC_n傳過來的RTP數(shù)據(jù)包的丟失總數(shù)。

  • Extended highest sequence number received: 32 bits
    收到的擴(kuò)展最大序列號:從SSRC_n收到的RTP數(shù)據(jù)包中最大的序列號婿失,EHSN = ROC*2^16, ROC 指 Sequence Number 重置回滾的次數(shù)(因為SN只有16位,很容易就會超過 2^16 的最大值, 只好再從零開始,這個重新回到零的次數(shù)即 ROC - ROll Count)

  • Interarrival jitter: 32 bits
    接收抖動,RTP數(shù)據(jù)包接受時間的統(tǒng)計方差估計

  • Last SR (LSR): 32 bits
    取最近從SSRC_n收到的SR包中的NTP時間戳的中間32比特钞艇。如果目前還沒收到SR包,則該域清零豪硅。

  • Delay since last SR (DLSR) : 32 bits
    上次SR以來的延時, 即上次從SSRC_n收到SR包到發(fā)送本報告的延時哩照。
    RR(n) – SR(n)
    單位: 1/65536 s

3. RTP 協(xié)議的度量要點(diǎn)

通過RTP 數(shù)據(jù)包頭和 RTCP 報告, 我們能夠度量 RTP 傳輸?shù)娜齻€主要度量指標(biāo) 往返延遲RTT, 丟包Packet Loss 和 抖動Jitter

1) 往返延時RTT

往返延時RTT 很好理解, 也就是數(shù)據(jù)包在發(fā)送和接收雙方走一個來回所花費(fèi)的時間.
當(dāng)延時在150ms以下時,通話雙方幾乎不能感覺到延時的存在懒浮,而當(dāng)延時在400ms以下時飘弧,也是用戶能夠接受的,當(dāng)延時進(jìn)一步增大后砚著,達(dá)到800ms以上次伶,正常的通話就無法進(jìn)行.
接受者報告RR可用來估算在發(fā)送者和接收者之間的往返延遲 RTT, 在接收者報告中包含:

  • LSR(Last timestamp Sener Report received) 上一次發(fā)送者報告接收的時間
  • DLSR(Delay since last sender report received) 上一次發(fā)送者報告接收的延遲

往返時延RTT 計算公式如下:

RTT = T1 – LSR - DLSR

看一個例子

[10 Nov 1995 11:33:25.125 UTC]       [10 Nov 1995 11:33:36.5 UTC]
   n                 SR(n)              A=b710:8000 (46864.500 s)
   ---------------------------------------------------------------->
                      v                 ^
   ntp_sec =0xb44db705 v               ^ dlsr=0x0005:4000 (    5.250s)
   ntp_frac=0x20000000  v             ^  lsr =0xb705:2000 (46853.125s)
     (3024992005.125 s)  v           ^
   r                      v         ^ RR(n)
   ---------------------------------------------------------------->
                          |<-DLSR->|
                           (5.250 s)

   A     0xb710:8000 (46864.500 s)
   DLSR -0x0005:4000 (    5.250 s)
   LSR  -0xb705:2000 (46853.125 s)
   -------------------------------
   delay 0x0006:2000 (    6.125 s)
  • A 是 RR 接收的時間, NTP timstamp 的32位表示為 0xb710:8000稽穆, 即 46864.500 s
  • DLSR 上 RR 中所記錄的上次收到 SR 到這次發(fā)送 RR 所經(jīng)歷的時間冠王,單位是 1/65536 秒, 算出為 0x0005:4000 即 5.250 s
  • LSR 是上次 SR 發(fā)送的時間舌镶,ntp_sec =0xb44db705柱彻, ntp_frac=0x20000000, 取中間32bit 為 0xb705:2000 即 46853.125 s

結(jié)果為 A - DLSR -LSR = 46864.500 - 5.250 - 46853.125 = 6.125 s

2) 抖動Jitter

在理想情況下, RTP數(shù)據(jù)包到達(dá)的間隔是固定的, 比如IP電話中最常用的編碼g.711, 每個包的荷載長度為20毫秒, 每秒應(yīng)該有50個數(shù)據(jù)包, 但是實際上網(wǎng)絡(luò)并不總能穩(wěn)定傳輸?shù)? 阻塞,擁塞是常有的事, Jitter 抖動即指數(shù)據(jù)到達(dá)間隔的變化,如圖所示:

抖動的計算要稍微麻煩一點(diǎn), 為避免偶發(fā)的波動造成抖動的計算偏差, 它被定義為 RTP 數(shù)據(jù)包到達(dá)間隔時間的統(tǒng)計方差乎折。

首先計算數(shù)據(jù)包接收與發(fā)送時間間隔的差別绒疗,也就是兩個 packet 傳輸延時的差異侵歇,此時所計算的 jitter 時只用到相鄰兩個 packet 的 delta骂澄, 反映的是某一時刻網(wǎng)絡(luò)延遲的變化情況

而如下的到達(dá)間隔抖動 J 定義為差值的平均偏差(平滑后的絕對值)。之所以要除以 16 是為了減少大的隨機(jī)變化的影響惕虑。 所以到達(dá)間隔時間的變化需要重復(fù)幾次才能顯著地影響抖動的估計

抖動是不可避免的, 在合理區(qū)間的抖動是可以接受, 通常采用抖動緩沖 Jitter Buffer 來解決抖動的問題, 數(shù)據(jù)包接收之后并不馬上解碼, 而是先放在緩沖區(qū)中. 假設(shè)緩沖區(qū)深度是60ms, 那么解碼總是等到緩沖區(qū)中的若干數(shù)據(jù)包總長度達(dá)到60ms時才取出解碼, 在60ms 之內(nèi)的抖動自然沒有任何影響.

3) 丟包 Packet loss

如果一個UDP 包在網(wǎng)絡(luò)上由于擁塞或超時而丟失了坟冲,或者一個TCP數(shù)據(jù)包的延時過大, 超過了最大的抖動緩沖深度, 應(yīng)用程序也就不會再等待, 直接丟棄, 這時候磨镶,我們要么采用丟包補(bǔ)償策略進(jìn)行處理, 要么發(fā)消息讓發(fā)送方重傳.

Packet loss丟包率的公式很簡單

  • 丟失的包數(shù) = 期望的包數(shù) - 收到的包數(shù)
  • 期望的包數(shù) = 最大sequence number – 初始的 sequence number
  • 最大sequence number = sequence number循環(huán)次數(shù) * + 最后收到的 sequence number

根據(jù)上述度量指標(biāo), 多媒體應(yīng)用程序可以即時調(diào)整 Jitter Buffer 長度,編碼參數(shù), 分辨率, 或者發(fā)送速率等, 為用戶提供流暢的體驗.

4. 實例

這里寫一個小程序來打印 RTP 包頭健提,使用 ffmpeg 來推送一個 RTP 流到 8880 端口琳猫,然后寫一個簡單的 UDP 服務(wù)器從這個端口上接收RTP 數(shù)據(jù)并打印包頭。

主要代碼很短

#include <arpa/inet.h>
#include <netinet/in.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <unistd.h>
#include <stdlib.h> 
#include <string.h>

#include <iostream>
#include <string>
#include "rtputil.h"

#define BUFLEN 5120
#define PORT 8880

using namespace std;

void exitWithMsg(const char *str)
{
    perror(str);
    exit(1);
}

int main(void)
{
    struct sockaddr_in my_addr, cli_addr;
    int sockfd; 
    socklen_t slen=sizeof(cli_addr);
    uint8_t buf[BUFLEN];

    if ((sockfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP))==-1)
      exitWithMsg("socket error");
    else 
      printf("Server : Socket() successful\n");

    bzero(&my_addr, sizeof(my_addr));
    my_addr.sin_family = AF_INET;
    my_addr.sin_port = htons(PORT);
    my_addr.sin_addr.s_addr = htonl(INADDR_ANY);
    
    if (::bind(sockfd, (struct sockaddr* ) &my_addr, sizeof(my_addr))==-1)
      exitWithMsg("bind error");
    else
      printf("Server : bind() successful\n");

    int pktCount = 0;
    while(1)
    {
        int pktSize = recvfrom(sockfd, buf, BUFLEN, 0, (struct sockaddr*)&cli_addr, &slen);
        if(pktSize == -1) {
            exitWithMsg("recvfrom()");
        }
            
        printf("The %d packet received %d from %s:%d\n", ++pktCount, pktSize, inet_ntoa(cli_addr.sin_addr), ntohs(cli_addr.sin_port));
        if(pktSize > 12) {
          cout << dump_rtp_packet(buf,  pktSize) <<endl;
        }
    }

    close(sockfd);
    return 0;
}

其中用到的 rtputil 代碼請參見 rtputil.hrtputil.cpp, 主要是借用了 libsrtp 中定義的結(jié)構(gòu)體和工具方法

測試步驟

  1. 編譯上述文件
    拷貝 https://github.com/walterfan/webrtc_primer/tree/main/snippets/media 目錄到本地
mkdir bld
cd bld
cmake ..
make
  1. 啟動 udp server
./udpserver
  1. 找一個mpegts 文件私痹,打開另外一個終端窗口脐嫂,用 ffmpeg 來推送RTP 流到 8880 端口
    (例子文件 https://github.com/walterfan/webrtc_primer/blob/main/material/sintel.ts)
ffmpeg -re -i ./sintel.ts -f rtp_mpegts udp://127.0.0.1:8880

執(zhí)行結(jié)果如下

ffmpeg -re -i ../../material/sintel.ts -f rtp_mpegts udp://127.0.0.1:8880
ffmpeg version 3.3.2 Copyright (c) 2000-2017 the FFmpeg developers
  built with Apple LLVM version 8.1.0 (clang-802.0.42)
  configuration: --prefix=/usr/local/Cellar/ffmpeg/3.3.2 --enable-shared --enable-pthreads --enable-gpl --enable-version3 --enable-hardcoded-tables --enable-avresample --cc=clang --host-cflags= --host-ldflags= --enable-libmp3lame --enable-libx264 --enable-libxvid --enable-opencl --disable-lzma --enable-vda
  libavutil      55. 58.100 / 55. 58.100
  libavcodec     57. 89.100 / 57. 89.100
  libavformat    57. 71.100 / 57. 71.100
  libavdevice    57.  6.100 / 57.  6.100
  libavfilter     6. 82.100 /  6. 82.100
  libavresample   3.  5.  0 /  3.  5.  0
  libswscale      4.  6.100 /  4.  6.100
  libswresample   2.  7.100 /  2.  7.100
  libpostproc    54.  5.100 / 54.  5.100
Input #0, mpegts, from '../../material/sintel.ts':
  Duration: 00:00:26.13, start: 1.446667, bitrate: 1306 kb/s
  Program 1
    Metadata:
      service_name    : Service01
      service_provider: FFmpeg
    Stream #0:0[0x100]: Video: h264 (High) ([27][0][0][0] / 0x001B), yuv420p(progressive), 848x480, 25 fps, 25 tbr, 90k tbn, 50 tbc
    Stream #0:1[0x101]: Audio: aac (LC) ([15][0][0][0] / 0x000F), 48000 Hz, stereo, fltp, 151 kb/s
Stream mapping:
  Stream #0:0 -> #0:0 (h264 (native) -> mpeg4 (native))
  Stream #0:1 -> #0:1 (aac (native) -> aac (native))
Press [q] to stop, [?] for help
Output #0, rtp_mpegts, to 'udp://127.0.0.1:8880':
  Metadata:
    encoder         : Lavf57.71.100
    Stream #0:0: Video: mpeg4, yuv420p, 848x480, q=2-31, 200 kb/s, 25 fps, 90k tbn, 25 tbc
    Metadata:
      encoder         : Lavc57.89.100 mpeg4
    Side data:
      cpb: bitrate max/min/avg: 0/0/200000 buffer size: 0 vbv_delay: -1
    Stream #0:1: Audio: aac (LC), 48000 Hz, stereo, fltp, 128 kb/s
    Metadata:
      encoder         : Lavc57.89.100 aac
frame=  653 fps= 25 q=31.0 Lsize=    2385kB time=00:00:26.19 bitrate= 745.9kbits/s dup=1 drop=0 speed=0.992x
video:1675kB audio:413kB subtitle:0kB other streams:0kB global headers:0kB muxing overhead: 14.238406%
[aac @ 0x7fc976810400] Qavg: 562.469

另外一個窗口顯示總共收到了1845 個 RTP 包

//...
The 1845 packet received 1328 from 127.0.0.1:54824
[rtp] dump_rtp_packet: ssrc=2444272939(0x91B0A52B), seq=3564(0x0DEC), pt=33(0x21), ts=1930119409(0x730B48F1), hdr_ext_len=12, pkt_len=1328, hdr_ext: 80210dec730b48f191b0a52b, tailer: ef3bc778eec0fbc1cf04ee01b0d704eae01709b805c26e3bc31addc8b0c06386db47abbc3196ed9663c50c65f36863bbacb7adbc31d3dc83c31f6dcc31bcff86, tailer_len=64
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
禁止轉(zhuǎn)載,如需轉(zhuǎn)載請通過簡信或評論聯(lián)系作者紊遵。
  • 序言:七十年代末账千,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子暗膜,更是在濱河造成了極大的恐慌匀奏,老刑警劉巖,帶你破解...
    沈念sama閱讀 221,635評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件学搜,死亡現(xiàn)場離奇詭異娃善,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)瑞佩,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,543評論 3 399
  • 文/潘曉璐 我一進(jìn)店門聚磺,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人炬丸,你說我怎么就攤上這事咧最。” “怎么了御雕?”我有些...
    開封第一講書人閱讀 168,083評論 0 360
  • 文/不壞的土叔 我叫張陵矢沿,是天一觀的道長。 經(jīng)常有香客問我酸纲,道長捣鲸,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 59,640評論 1 296
  • 正文 為了忘掉前任闽坡,我火速辦了婚禮栽惶,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘疾嗅。我一直安慰自己外厂,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,640評論 6 397
  • 文/花漫 我一把揭開白布代承。 她就那樣靜靜地躺著汁蝶,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上掖棉,一...
    開封第一講書人閱讀 52,262評論 1 308
  • 那天墓律,我揣著相機(jī)與錄音,去河邊找鬼幔亥。 笑死耻讽,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的帕棉。 我是一名探鬼主播针肥,決...
    沈念sama閱讀 40,833評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼香伴!你這毒婦竟也來了祖驱?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,736評論 0 276
  • 序言:老撾萬榮一對情侶失蹤瞒窒,失蹤者是張志新(化名)和其女友劉穎捺僻,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體崇裁,經(jīng)...
    沈念sama閱讀 46,280評論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡匕坯,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,369評論 3 340
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了拔稳。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片葛峻。...
    茶點(diǎn)故事閱讀 40,503評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖巴比,靈堂內(nèi)的尸體忽然破棺而出术奖,到底是詐尸還是另有隱情,我是刑警寧澤轻绞,帶...
    沈念sama閱讀 36,185評論 5 350
  • 正文 年R本政府宣布采记,位于F島的核電站,受9級特大地震影響政勃,放射性物質(zhì)發(fā)生泄漏唧龄。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,870評論 3 333
  • 文/蒙蒙 一奸远、第九天 我趴在偏房一處隱蔽的房頂上張望既棺。 院中可真熱鬧,春花似錦懒叛、人聲如沸丸冕。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,340評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽胖烛。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間洪己,已是汗流浹背妥凳。 一陣腳步聲響...
    開封第一講書人閱讀 33,460評論 1 272
  • 我被黑心中介騙來泰國打工竟贯, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留答捕,地道東北人。 一個月前我還...
    沈念sama閱讀 48,909評論 3 376
  • 正文 我出身青樓屑那,卻偏偏與公主長得像拱镐,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子持际,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,512評論 2 359

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