ijkplayer編譯:在2022年使用M1芯片遭受毒打

引言

在接手的一個(gè)舊項(xiàng)目中铐伴,有多處用到視頻播放的能力逝薪,項(xiàng)目中使用的是一個(gè)叫universalvideoview的三方庫踱启,性能確實(shí)差报账,視頻加載得也太慢了,正好碰上項(xiàng)目需求不是很緊張的時(shí)間窗口埠偿,準(zhǔn)備花些時(shí)間換成廣受好評(píng)的ijkplayer透罢。這也讓我開始了逐漸暴躁的旅程。


本來對(duì)ijkplayer了解不多冠蒋,一查發(fā)現(xiàn)有現(xiàn)成的官方依賴羽圃,誰還想要自己編譯啊,直接拿來用唄抖剿。

gradle添加依賴:

    // 這里對(duì)應(yīng)有多個(gè)指令集的支持统屈,依個(gè)人需求添加
    implementation 'tv.danmaku.ijk.media:ijkplayer-java:0.8.8'
    implementation 'tv.danmaku.ijk.media:ijkplayer-armv7a:0.8.8'
    implementation 'tv.danmaku.ijk.media:ijkplayer-arm64:0.8.8'

參考官方github主頁:https://github.com/bilibili/ijkplayer.git

開始調(diào)試,簡(jiǎn)單封一個(gè)View牙躺,掛到Activity上

ijkplayer本身提供的是流加載愁憔、緩存,視頻解碼的能力孽拷,并不負(fù)責(zé)繪制和各種交互吨掌。需要我們自己提供一個(gè) SurfaceView 供其最終渲染,這里搞一個(gè)簡(jiǎn)單的實(shí)現(xiàn):

class IJKVideoPlayer : FrameLayout {
    private val TAG = "IJKVideoPlayer"

    constructor(context: Context): super(context)

    constructor(context: Context, attrs: AttributeSet): super(context, attrs)

    constructor(context: Context, attrs: AttributeSet, styleAttr: Int): super(context, attrs, styleAttr)

    var listener: PlayerListener? = null

    private var mSurfaceView: SurfaceView = SurfaceView(context)

    // mediaPlayer 對(duì)象,通過它來對(duì)視頻進(jìn)行控制膜宋,暫停窿侈、播放、拖動(dòng)時(shí)間等
    private var mediaPlayer: IMediaPlayer? = null

    init {
        mSurfaceView.holder.addCallback(MySurfaceCallback())
        addView(mSurfaceView, LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT))
    }

    // 搞一個(gè)監(jiān)聽秋茫,方便調(diào)試史简,也可以觸發(fā)回調(diào)UI前做一些調(diào)試
    private val internalListener = object : PlayerListener {
        override fun onPrepared(p0: IMediaPlayer?) {
            Log.d(TAG, "onPrepared")
            listener?.onPrepared(p0)
        }

        override fun onInfo(p0: IMediaPlayer?, p1: Int, p2: Int): Boolean {
            Log.d(TAG, "onInfo  --$p1,  --$p2")
            listener?.let {
                return it.onInfo(p0, p1, p2)
            }
            return false
        }

        override fun onSeekComplete(p0: IMediaPlayer?) {
            Log.d(TAG, "onSeekComplete")
            listener?.onSeekComplete(p0)
        }

        override fun onBufferingUpdate(p0: IMediaPlayer?, p1: Int) {
            Log.d(TAG, "onBufferingUpdate  --$p1")
            listener?.onBufferingUpdate(p0, p1)
        }

        override fun onError(p0: IMediaPlayer?, p1: Int, p2: Int): Boolean {
            Log.d(TAG, "onError  --$p1,  --$p2")
            listener?.let {
                return it.onError(p0, p1, p2)
            }
            return false
        }
    }

    /**
     * 加載視頻,開始播放
     * @param videoPath 網(wǎng)絡(luò)地址或本地文件路徑
     */
    fun loadVideo(videoPath: String?) {
        if(mediaPlayer?.dataSource.isNullOrBlank() && videoPath.isNullOrBlank())
            return

        rebuildPlayer()
        try {
            if(!videoPath.isNullOrBlank()) mediaPlayer?.dataSource = videoPath

            //  如果我們的服務(wù)器需要進(jìn)行一些頭信息的認(rèn)證肛著,如User-Agent圆兵、referer,可以使用這個(gè)api加載資源枢贿。
            // if(!videoPath.isNullOrBlank()) mediaPlayer?.setDataSource(context, Uri.parse(videoPath), headerMap)
        } catch (e: IOException) {
            e.printStackTrace()
        }
        mediaPlayer?.setDisplay(mSurfaceView.holder)
        mediaPlayer?.prepareAsync()
    }

    /**
     * 釋放資源
     */
    fun onDestroy() {
        mediaPlayer?.apply {
            stop()
            setDisplay(null)
            release()
        }
    }

    // 釋放上一個(gè)資源殉农,重建 mediaPlayer
    private fun rebuildPlayer() {
        mediaPlayer?.apply {
            stop()
            setDisplay(null)
            release()
        }

        mediaPlayer = IjkMediaPlayer().apply {
            native_setLogLevel(IjkMediaPlayer.IJK_LOG_DEBUG)

            // 硬件解碼
            setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "mediacodec", 1)

            setOnPreparedListener(internalListener)
            setOnInfoListener(internalListener)
            setOnSeekCompleteListener(internalListener)
            setOnBufferingUpdateListener(internalListener)
            setOnErrorListener(internalListener)
        }
    }

    private inner class MySurfaceCallback : SurfaceHolder.Callback {
        override fun surfaceCreated(holder: SurfaceHolder) {
            // do nothing
        }

        override fun surfaceChanged(holder: SurfaceHolder, format: Int, width: Int, height: Int) {
            // view 發(fā)生變化時(shí)需要重新綁定 MediaPlayer
            loadVideo(null)
        }

        override fun surfaceDestroyed(holder: SurfaceHolder) {
            // do nothing
        }
    }

    interface PlayerListener : IMediaPlayer.OnPreparedListener, IMediaPlayer.OnInfoListener,
        IMediaPlayer.OnSeekCompleteListener, IMediaPlayer.OnBufferingUpdateListener, IMediaPlayer.OnErrorListener
}

好!就這么個(gè)玩意局荚,可以直接拿去用啦超凳!
加到布局文件:

<com.simple.player.IJKVideoPlayer
    android:id="@+id/videoPlayer"
    android:layout_width="match_parent"
    android:layout_height="match_parent"  />

在activity里拿到view實(shí)例,加載資源耀态,就可以看到視頻辣轮傍!

videoPlayer.loadVideo(videoPath)

誒?等了好久首装,還沒有看到東西金麸,是不是那里不對(duì)?
然后發(fā)現(xiàn)我們寫的回調(diào)中簿盅,onError被調(diào)用,其中第二參數(shù) what = 10000揍魂,第三參數(shù) extra = 0桨醋。經(jīng)過查詢,這種情況一般會(huì)出現(xiàn)在找不到資源的情況现斋,
不對(duì)啊喜最,之前用另一個(gè)庫,同一個(gè)資源庄蹋,都能正常播放的啊瞬内。仔細(xì)翻找日志,找到了下面這句:

W/IJKMEDIA: https protocol not found, recompile FFmpeg with openssl, gnutls or securetransport enabled.

提示的已經(jīng)很清楚了限书,不支持 https 協(xié)議虫蝶,請(qǐng)帶著 openssl 重新編譯 FFmpeg。
官方編譯的庫不支持https倦西,需要自己下載源碼重新編譯了能真,那就開始吧。

開始編譯,受苦旅程開始

首先是拿到ijkplayer的基礎(chǔ)代碼粉铐,可以從github上下載壓縮包疼约,
github主頁:https://github.com/bilibili/ijkplayer.git
也可以直接git拉取:

git clone https://github.com/bilibili/ijkplayer.git

然后蝙泼,就開始了一步一個(gè)坑的過程程剥。

本來這是一個(gè)有非常多使用者,也有很多人分享參考經(jīng)驗(yàn)的庫汤踏,應(yīng)該是有非常多避坑心得的织鲸。然而還是太天真,當(dāng)別人的經(jīng)驗(yàn)和自己的操作茎活,之間隔了以年為單位的時(shí)間時(shí)昙沦,各種環(huán)境、硬件的條件下载荔,簡(jiǎn)直沒有一步是順利的盾饮。

0. yasm 環(huán)境安裝(必要性存疑)

我在準(zhǔn)備的初期有看到很多文章中都提到,需要具備yasm環(huán)境懒熙。有用brew命令裝的丘损,有用yum命令的,然而這倆我都沒有??工扎。我這邊使用的是下載源碼自行編譯安裝的方式徘钥。
官方下載: http://www.tortall.net/projects/yasm/releases/
從這個(gè)網(wǎng)頁找到需要的版本下載,很久不維護(hù)了肢娘,最新的就是2014年的1.3.0版本了呈础,mac下載 **yasm-1.3.0.tar.gz **
下載完成后解壓,進(jìn)入解壓后的目錄橱健,依次執(zhí)行以下命令:

sudo ./configure
sudo make
sudo make install

過程中沒有報(bào)錯(cuò)的話而钞,使用 yasm --version 驗(yàn)證是否安裝成功。

我這邊后來試過把 yasm 卸了拘荡,再次編譯也可以成功臼节,所以 ijk 的編譯過程應(yīng)該是不需要這個(gè)東西的?你可以跳過這步進(jìn)行下面的流程珊皿。
是在不行在回頭來安裝嘛??网缝。


1.真實(shí)的源代碼拉取

上面我們下載的代碼,只是一個(gè)殼子蟋定,封裝了一些命令而已粉臊,實(shí)際的源代碼并沒有在里面。最重要的是驶兜,我們的目標(biāo)是集成 openssl维费,重新編譯 FFmpeg果元。所以就需要 openssl 、FFmpeg犀盟、ijkplayer 的源代碼而晒,更不要說 FFmpeg 還需要依賴 libyuv、soundtouch阅畴。

要完成這一步倡怎,我們需要執(zhí)行 ijkplayer 根目錄下的兩個(gè)腳本:

// 進(jìn)入下載的源碼根目錄
cd ijkplayer-source

// 執(zhí)行命令下載 openssl 、FFmpeg贱枣、ijkplayer 源碼和依賴
./init-android-openssl.sh
./init-android.sh

受網(wǎng)絡(luò)因素限制监署,過程會(huì)非常漫長(zhǎng),而且動(dòng)不動(dòng)就會(huì)報(bào)錯(cuò)纽哥,見到下面這些:

這樣的:
== pull openssl base ==
Fetching origin
fatal: unable to access 'https://github.com/Bilibili/openssl.git/': LibreSSL SSL_connect: SSL_ERROR_SYSCALL in connection to github.com:443 
error: Could not fetch origin

或者這樣的:
== pull openssl fork x86_64 ==
Fetching origin
error: RPC failed; curl 28 LibreSSL SSL_read: Operation timed out, errno 60
fatal: expected flush after ref listing
error: Could not fetch origin

看到這些钠乏,別灰心,再試一遍春塌,已經(jīng)下載完的不會(huì)刪除晓避。
可能會(huì)需要一遍又一遍地執(zhí)行,總會(huì)全部下載完的只壳,只有所有庫都下載完俏拱,才能開始下一步的編譯。


2.開始編譯 openssl

這邊文章記錄的是在mac上的編譯過程吼句, gcc锅必、g++、make 環(huán)境的準(zhǔn)備就不在贅述惕艳。
身為一個(gè)android開發(fā)搞隐,ndk環(huán)境已經(jīng)具備,就按照網(wǎng)上教程執(zhí)行了下面的命令:

// 進(jìn)入固定目錄 [源碼根目錄/android/contrib]
cd android/contrib

// 編譯 openssl 和 ffmpeg远搪,這個(gè)命令是所有指令集劣纲,
// 當(dāng)然也可以指定,如:./compile-openssl.sh arm64
./compile-openssl.sh all
./compile-ffmpeg.sh all

// 如果上面的的命令中途失敗终娃,最好清除一下編譯中間物。
./compile-openssl.sh clean
./compile-ffmpeg.sh clean

必須保證 NDK 環(huán)境變量存在蒸甜,否則會(huì)看到這個(gè):

You must define ANDROID_NDK before starting.
They must point to your NDK directories.

可以使用命令臨時(shí)指定:

export ANDROID_NDK=/Users/xxx/env/android-sdk/ndk/23.1.7779620

環(huán)境正常后再次 ./compile-openssl.sh all 棠耕,我看到了這個(gè):

IJK_NDK_REL=23.1.7779620
You need the NDKr10e or later

是我的 NDK 版本低了?好家伙,原來是太高了,高出了好多年或链,根本不支持付秕。
在 /android/contrib 下,有一個(gè) do-detect-env.sh 腳本坪它,編譯前會(huì)通過它檢查ndk版本操刀,它里面可以看到支持的版本:

case "$IJK_NDK_REL" in
    10e*) 
        摔刁、瓤荔、净蚤、、输硝、今瀑、

case "$IJK_NDK_REL" in
    11*|12*|13*|14*) 
        、点把、橘荠、、郎逃、哥童、

然后我選了一個(gè)相對(duì)高一些的版本,r14b褒翰,從下面鏈接可以下載:
歷史版本鏈接:https://developer.android.google.cn/ndk/downloads/older_releases

重設(shè)環(huán)境變量贮懈,重新編譯,于是乎我又看見這個(gè):

making links in crypto/objects...
objects.h => ../../include/openssl/objects.h
obj_mac.h => ../../include/openssl/obj_mac.h
making links in crypto/md4...
make: ../../util/mklink.pl: Command not found
make: *** [links] Error 127
make: *** [links] Error 1
make: *** [links] Error 1

--------------------
[*] compile openssl
--------------------
making depend in crypto...
/bin/sh: /util/domd: No such file or directory
make: *** [local_depend] Error 127
make: *** [depend] Error 1

查了好久也找不到具體原因影暴,老老實(shí)實(shí)下載一個(gè)支持的最低版本错邦,r10e。
重設(shè)環(huán)境變量型宙,重新編譯撬呢,

export ANDROID_NDK=/Users/xxx/env/android-sdk/ndk/android-ndk-r10e
./compile-openssl.sh clean
./compile-openssl.sh all

在這個(gè)過程中,你可能會(huì)遇見這個(gè)彈窗:
自己截的屏妆兑,保證不侵權(quán)??.jpg

相信我魂拦,不要嘗試去設(shè)置里一個(gè)一個(gè)允許了,因?yàn)檫@只是個(gè)開始搁嗓,后面還有無數(shù)這玩意等著你芯勘,執(zhí)行如下命令,跳過這個(gè)檢查:

sudo spctl --master-disable

再次編譯腺逛,在日志的最后荷愕,看見這些就是成功了:

--------------------
[*] link openssl
--------------------

--------------------
[*] Finished
--------------------
# to continue to build ffmpeg, run script below,
sh compile-ffmpeg.sh 
# to continue to build ijkplayer, run script below,
sh compile-ijk.sh 

3.openssl編譯完成后,編譯 ffmpeg

./compile-ffmpeg.sh clean
./compile-ffmpeg.sh all

一頓編譯之后棍矛,出現(xiàn)了如下錯(cuò)誤:

libavcodec/hevc_mvs.c:207:15: error: 'x0000000' undeclared (first use in this function)
     TAB_MVF(((x ## v) >> s->ps.sps->log2_min_pu_size),                     \
               ^
libavcodec/hevc_mvs.c:204:34: note: in definition of macro 'TAB_MVF'
     tab_mvf[(y) * min_pu_width + x]
                                  ^
libavcodec/hevc_mvs.c:274:16: note: in expansion of macro 'TAB_MVF_PU'
     (cand && !(TAB_MVF_PU(v).pred_flag == PF_INTRA))
                ^
libavcodec/hevc_mvs.c:683:24: note: in expansion of macro 'AVAILABLE'
     is_available_b0 =  AVAILABLE(cand_up_right, B0) &&
                        ^
make: *** [libavcodec/hevc_mvs.o] Error 1
make: *** Waiting for unfinished jobs....

這都是什么鬼安疗?簡(jiǎn)直心態(tài)爆炸!9晃荐类!
多方查詢、試錯(cuò)后茁帽,終于找到一個(gè)解決方案:把我們要編譯的對(duì)應(yīng)指令集下的玉罐,libavcodec/hevc_mvs.c 中所有名為 B0屈嗤、xB0、yB0 的變量及引用吊输,改成小寫 b0 xb0 yb0饶号。
例如我們只編譯arm64,需要修改文件就在:
源碼根目錄/android/contrib/ffmpeg-arm64/libavcodec/hevc_mvs.c
璧亚,
如果要編譯 all讨韭,就需要修改所有指令集對(duì)應(yīng)文件。

修改后再次clean并執(zhí)行編譯癣蟋,看到下面的日志透硝,就是成功了:

--------------------
[*] create files for shared ffmpeg
--------------------

--------------------
[*] Finished
--------------------
# to continue to build ijkplayer, run script below,
sh compile-ijk.sh 

3.編譯 ijkplayer,輸出成功成果物

openssl 和 ffmpeg 都編譯成功后疯搅,會(huì)產(chǎn)生靜態(tài)鏈接庫 .a 文件供 ijkplayer 編譯使用濒生,有興趣的可以去 /android/contrib/build/xxxx/output/lib 路徑下查看。

執(zhí)行腳本編譯 ijkplayer :

// 上面我們是在 /android/contrib 下幔欧,需要退回到 /android 目錄
cd ..

// 同樣也可以指定具體的指令集罪治,如 ./compile-ijk.sh arm64
./compile-ijk.sh all

正常情況下到這里根本沒有懸念的成功了,但我感覺這玩意就是來搞我心態(tài)的礁蔗,出現(xiàn)了:

xxxx-xxxxx android % ./compile-ijk.sh all  
profiler build: NO
ERROR: Unknown host CPU architecture: arm64
/Users/wwf/Desktop/projects/ijkplayer/android
profiler build: NO
ERROR: Unknown host CPU architecture: arm64
/Users/wwf/Desktop/projects/ijkplayer/android
profiler build: NO
ERROR: Unknown host CPU architecture: arm64
/Users/wwf/Desktop/projects/ijkplayer/android
profiler build: NO
ERROR: Unknown host CPU architecture: arm64
/Users/wwf/Desktop/projects/ijkplayer/android
profiler build: NO
ERROR: Unknown host CPU architecture: arm64

焯觉义!我這mac是 M1 芯片的,arm64 的指令集浴井!
到最后一步了晒骇,不認(rèn)cpu了,我直接好家伙磺浙!螺旋升天洪囤,原地爆炸!K貉酢瘤缩!

既然開始了,含著淚也要走完啊伦泥,又是一頓查剥啤,發(fā)現(xiàn)可以指定為兼容模式以 x86_64模式運(yùn)行,需要修改ndk目錄下的 ndk-build 文件:

原文件內(nèi)容:
#!/bin/sh
DIR="$(cd "$(dirname "$0")" && pwd)"
$DIR/build/ndk-build "$@"

修改為:
#!/bin/sh
DIR="$(cd "$(dirname "$0")" && pwd)"
arch -x86_64 /bin/bash $DIR/build/ndk-build "$@"

文件路徑:/Users/xxx/env/android-sdk/ndk/android-ndk-r10e/ndk-build
但是我打開我的文件一看不脯,傻眼了府怯,這些是啥玩意,跟說的根本不一樣啊跨新,這怎么改富腊?

別看了坏逢,這圖沒用.jpg

別人的文件只有三行域帐,我的卻有三百多行...
硬著頭皮讀一讀吧赘被,看有什么指令集相關(guān)的代碼,發(fā)現(xiàn)了在140多行處肖揣,有如下邏輯:

HOST_ARCH=$(uname -m)
case $HOST_ARCH in
    i?86) HOST_ARCH=x86;;
    x86_64|amd64) HOST_ARCH=x86_64;;
    *) echo "ERROR: Unknown host CPU architecture: $HOST_ARCH"
       exit 1
esac
log "HOST_ARCH=$HOST_ARCH"

x86_64|amd64) 這里加一個(gè)民假,改成 x86_64|amd64|arm64)
重新編譯 ijk ,成功龙优。我這里只編了一個(gè)指令集羊异,./compile-ijk.sh arm64,日志如下:

[arm64-v8a] Compile++      : ijksoundtouch <= BPMDetect.cpp
[arm64-v8a] Compile++      : ijksoundtouch <= PeakFinder.cpp
[arm64-v8a] Compile++      : ijksoundtouch <= SoundTouch.cpp
[arm64-v8a] Compile++      : ijksoundtouch <= mmx_optimized.cpp
[arm64-v8a] Compile++      : ijksoundtouch <= ijksoundtouch_wrap.cpp
[arm64-v8a] StaticLibrary  : libcpufeatures.a
[arm64-v8a] StaticLibrary  : libijkj4a.a
[arm64-v8a] StaticLibrary  : libandroid-ndk-profiler.a
[arm64-v8a] StaticLibrary  : libijksoundtouch.a
[arm64-v8a] StaticLibrary  : libyuv_static.a
[arm64-v8a] SharedLibrary  : libijksdl.so
[arm64-v8a] SharedLibrary  : libijkplayer.so
[arm64-v8a] Install        : libijksdl.so => libs/arm64-v8a/libijksdl.so
[arm64-v8a] Install        : libijkplayer.so => libs/arm64-v8a/libijkplayer.so

附:如果使用的是較 r10e 高的ndk版本彤断,可能會(huì)遇到 Host 'awk' tool is outdated

xxxx-xxxxx android % ./compile-ijk.sh all
profiler build: NO
Android NDK: Host 'awk' tool is outdated. Please define NDK_HOST_AWK to point to Gawk or Nawk !    
/Users/wwf/Desktop/env/android-sdk/ndk/android-ndk-r14b/build/core/init.mk:391: *** Android NDK: Aborting.    .  Stop.

這種情況就需要?jiǎng)h除 ndk/prebuilt 下平臺(tái)指令集中的 awk 程序野舶。
示例路徑:/Users/xxx/env/android-sdk/ndk/android-ndk-r14b/prebuilt/darwin-x86_64/bin/awk
找到文件,把它刪除或改個(gè)名字都行宰衙。


最后平道,編譯完成,成果物的簡(jiǎn)化使用

我看到的其他文章供炼,基本在編譯完成后都是在 android gradle 項(xiàng)目中引入編譯輸出的模塊使用一屋,如果我們不要對(duì) ijkplayer 的java層進(jìn)行定制的話,可以直接使用官方的java層袋哼,同時(shí)使用我們編譯的so庫就行了冀墨。

    // 只添加 java 庫依賴,把我們自己編譯的so庫打包里就行
    implementation 'tv.danmaku.ijk.media:ijkplayer-java:0.8.8'

so的輸出路徑:源碼根目錄/android/ijkplayer/ijkplayer-arm64/src/main/libs/arm64-v8a
其他指令集同理涛贯。

完結(jié)诽嘉,編譯 ijkplayer 真有意思,以后再也不想編了疫蔓。

轉(zhuǎn)載請(qǐng)注明出處含懊,@via 小風(fēng)風(fēng)吖-ijkplayer編譯:在2022年使用M1芯片遭受毒打 蟹蟹。
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末衅胀,一起剝皮案震驚了整個(gè)濱河市岔乔,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌滚躯,老刑警劉巖雏门,帶你破解...
    沈念sama閱讀 206,723評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異掸掏,居然都是意外死亡茁影,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,485評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門丧凤,熙熙樓的掌柜王于貴愁眉苦臉地迎上來募闲,“玉大人,你說我怎么就攤上這事愿待『坡荩” “怎么了靴患?”我有些...
    開封第一講書人閱讀 152,998評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)要出。 經(jīng)常有香客問我鸳君,道長(zhǎng),這世上最難降的妖魔是什么患蹂? 我笑而不...
    開封第一講書人閱讀 55,323評(píng)論 1 279
  • 正文 為了忘掉前任或颊,我火速辦了婚禮,結(jié)果婚禮上传于,老公的妹妹穿的比我還像新娘囱挑。我一直安慰自己,他們只是感情好沼溜,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,355評(píng)論 5 374
  • 文/花漫 我一把揭開白布看铆。 她就那樣靜靜地躺著,像睡著了一般盛末。 火紅的嫁衣襯著肌膚如雪弹惦。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,079評(píng)論 1 285
  • 那天悄但,我揣著相機(jī)與錄音棠隐,去河邊找鬼。 笑死檐嚣,一個(gè)胖子當(dāng)著我的面吹牛助泽,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播嚎京,決...
    沈念sama閱讀 38,389評(píng)論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼嗡贺,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了鞍帝?” 一聲冷哼從身側(cè)響起诫睬,我...
    開封第一講書人閱讀 37,019評(píng)論 0 259
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎帕涌,沒想到半個(gè)月后摄凡,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,519評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡蚓曼,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,971評(píng)論 2 325
  • 正文 我和宋清朗相戀三年亲澡,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片纫版。...
    茶點(diǎn)故事閱讀 38,100評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡床绪,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情癞己,我是刑警寧澤裹匙,帶...
    沈念sama閱讀 33,738評(píng)論 4 324
  • 正文 年R本政府宣布,位于F島的核電站末秃,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏籽御。R本人自食惡果不足惜练慕,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,293評(píng)論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望技掏。 院中可真熱鬧铃将,春花似錦、人聲如沸哑梳。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,289評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽鸠真。三九已至悯仙,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間吠卷,已是汗流浹背锡垄。 一陣腳步聲響...
    開封第一講書人閱讀 31,517評(píng)論 1 262
  • 我被黑心中介騙來泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留祭隔,地道東北人货岭。 一個(gè)月前我還...
    沈念sama閱讀 45,547評(píng)論 2 354
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像疾渴,于是被迫代替她去往敵國(guó)和親千贯。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,834評(píng)論 2 345

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