移動端濾鏡開發(fā)(三)OpenGL實(shí)現(xiàn)預(yù)覽播放效果

寫在前面的話

<p>
上一篇文章簡單介紹了OpenGl的使用麦向,并實(shí)現(xiàn)了OpenGl顯示圖片的效果陨囊,但是濾鏡的效果不僅僅只用在圖片上面苍蔬,一般來說現(xiàn)在視頻和拍照取景也是會有濾鏡的需求的麦牺,所以這一篇惰蜜,就是介紹用OpenGL實(shí)現(xiàn)預(yù)覽效果

攝像預(yù)覽其實(shí)就是Android的Camera開發(fā)昂拂,對于Android的Camera開發(fā),一般有兩種方式抛猖,一種是借助Intent和MediaStroe調(diào)用系統(tǒng)Camera App程序來實(shí)現(xiàn)拍照和攝像功能政钟,另外一種是根據(jù)Camera API自寫Camera程序,自然第一種不能作為我們的濾鏡開發(fā)樟结,所以我們采用第二種方式养交。

視頻播放則是使用了主要用到MediaPlayer。

兩者的實(shí)現(xiàn)方式基本一致

Camera預(yù)覽開發(fā)

<p>
工欲善其事必先利其器,首先我們了解一下Camera API

一.Camera API

<p>

Camera的初始化需要使用靜態(tài)方法通過API calledCamera.open提供并初始化相機(jī)對象

Camera mCamera =  Camera.open(); 

簡單看下Camera類提供的方法

  • getCameraInfo(int cameraId, Camera.CameraInfo cameraInfo) 它返回一個(gè)特定攝像機(jī)信息

  • getNumberOfCameras() 它返回限定的可用的設(shè)備上的照相機(jī)的整數(shù)

  • lock()它被用來鎖定相機(jī)瓢宦,所以沒有其他應(yīng)用程序可以訪問它

  • release() 它被用來釋放在鏡頭鎖定碎连,所以其他應(yīng)用程序可以訪問它

  • open(int cameraId) 它是用來打開特定相機(jī)時(shí),支持多個(gè)攝像機(jī)

  • enableShutterSound(boolean enabled) 它被用來使能/禁止圖像俘獲的默認(rèn)快門聲音

  • startPreview() 開始預(yù)覽

  • startFaceDetection() 此功能啟動人臉檢測相機(jī)

  • stopFaceDetection() 它是用來阻止其通過上述功能啟用的臉部檢測

  • startSmoothZoom(int value) 這需要一個(gè)整數(shù)值驮履,并調(diào)整攝像機(jī)的焦距非常順暢的值

  • stopSmoothZoom() 它是用來阻止攝像機(jī)的變焦

  • stopPreview() 它是用來阻止相機(jī)的預(yù)覽給用戶

  • takePicture(Camera.ShutterCallback shutter, Camera.PictureCallback
    raw, Camera.PictureCallback jpeg)
    它被用來使能/禁止圖像拍攝的默認(rèn)快門聲音

實(shí)現(xiàn)預(yù)覽效果呢其實(shí)有好幾種方法鱼辙,主要都是與SurfaceView,GLSurfaceView,SurfaceTexture,TextureView這幾個(gè)有關(guān)玫镐,那這里就簡單介紹下這幾個(gè)區(qū)別

SurfaceView, GLSurfaceView, SurfaceTexture, TextureView的區(qū)別

由于這里的東西其實(shí)牽扯很多倒戏,就不做太詳細(xì)的介紹,有興趣的可以自行百度恐似,我就做簡單的區(qū)分介紹

關(guān)鍵字:View
SurfaceView
GLSurfaceView
TextureView
這三個(gè)的后綴都是View杜跷,所以這三個(gè)都是用來顯示的

SurfaceView是Android1.0(API level1)時(shí)期就存在的,雖然是繼承于View矫夷,但是他包含一個(gè)Surface模塊(簡單地說Surface對應(yīng)了一塊屏幕緩沖區(qū)葛闷,每個(gè)window對應(yīng)一個(gè)Surface,任何View都是畫在Surface上的双藕,傳統(tǒng)的view共享一塊屏幕緩沖區(qū)淑趾,所有的繪制必須在UI線程中進(jìn)行),所以SurfaceView與普通View的區(qū)別就在于他的渲染在單獨(dú)的線程的忧陪,這對于一些游戲扣泊、視頻等性能相關(guān)的應(yīng)用非常有益,因?yàn)樗粫绊懼骶€程對事件的響應(yīng)嘶摊。同時(shí)由于這個(gè)特性它的顯示也不受View的屬性控制延蟹,所以不能進(jìn)行平移,縮放等變換更卒,也不能放在其它ViewGroup中等孵,一些View中的特性也無法使用稚照。

GLSurfaceView從Android 1.5(API level 3)開始加入,它的加入是為了解決SurfaceView渲染線程要單獨(dú)寫導(dǎo)致的統(tǒng)一性不好的狀態(tài)蹂空,在SurfaceView的基礎(chǔ)上俯萌,它加入了EGL的管理,并自帶了渲染線程上枕。另外它定義了用戶需要實(shí)現(xiàn)的Render接口咐熙,提供了用Strategy pattern更改具體Render行為的靈活性。作為GLSurfaceView的Client辨萍,只需要將實(shí)現(xiàn)了渲染函數(shù)的Renderer的實(shí)現(xiàn)類設(shè)置給GLSurfaceView即可棋恼。概括一句話就是 使用了模板的 SurfaceView。

TextureView在4.0(API level 14)中引入锈玉。TextureView重載了draw()方法爪飘,其中主要把SurfaceTexture中收到的圖像數(shù)據(jù)作為紋理更新到對應(yīng)的HardwareLayer中。所以TextureView必須在硬件加速的窗口中拉背。因?yàn)門extureView不包含Surface师崎,所以其實(shí)就是一個(gè)普通的View,可以和其它普通View一樣進(jìn)行移動椅棺,旋轉(zhuǎn)犁罩,縮放,動畫等變化两疚。

關(guān)鍵字:Texture
SurfaceTexture

SurfaceTexture從Android 3.0(API level 11)加入床估。和SurfaceView不同的是,它對圖像流的處理并不直接顯示诱渤,而是轉(zhuǎn)為GL外部紋理丐巫,因此可用于圖像流數(shù)據(jù)的二次處理(如Camera濾鏡,桌面特效等)勺美。

接下來就來實(shí)現(xiàn)預(yù)覽效果鞋吉,分別從簡單到復(fù)雜

二.SurfaceView實(shí)現(xiàn)預(yù)覽效果

<p>
首先我們來創(chuàng)建一個(gè)相機(jī)預(yù)覽加載View,該類繼承SurfaceView.Callback接口類,并且需要實(shí)現(xiàn)里面的接口方法以便監(jiān)聽SurfaceView控件的創(chuàng)建以及銷毀事件的回調(diào)励烦,在回調(diào)方法中關(guān)聯(lián)相機(jī)預(yù)覽顯示谓着。

如下

  public class CameraView extends SurfaceView implements SurfaceHolder.Callback{

    private SurfaceHolder holder;
    private Camera mCamera;

    public CameraView(Context context) {
        this(context,null);
    }

    public CameraView(Context context, AttributeSet attrs) {
        super(context, attrs);
        holder = getHolder();
        holder.addCallback(this);
    }

    @Override
    public void surfaceCreated(SurfaceHolder holder) {
        try {
            mCamera = getCameraInstance();
            mCamera.setPreviewDisplay(holder);
            mCamera.startPreview();
        }catch (IOException e){

        }
    }

    public static Camera getCameraInstance(){
        Camera c = null;
        try {
            c = Camera.open(); // attempt to get a Camera instance
        }
        catch (Exception e){
            // Camera is not available (in use or does not exist)
        }
        return c; // returns null if camera is unavailable
    }

    @Override
    public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
    }

    @Override
    public void surfaceDestroyed(SurfaceHolder holder) {
    }

    public void  releaseCamera(){
        mCamera.release();
    }
}

接下來就是將這個(gè)View放到布局文件中,當(dāng)onPause時(shí)候調(diào)用View的releaseCamera方法即可

運(yùn)行如下

圖1 Camera預(yù)覽圖

雖然是顯示出來了坛掠,但是顯示的界面確實(shí)不正常的赊锚,這是為什么呢?

手機(jī)Camera的圖像數(shù)據(jù)都是來自于攝像頭硬件的圖像傳感器(Image Sensor)屉栓,這個(gè)Sensor被固定到手機(jī)之后是有一個(gè)默認(rèn)的取景方向的舷蒲,這個(gè)方向如下圖所示,坐標(biāo)原點(diǎn)位于手機(jī)橫放時(shí)的左上角:

圖2 Camera的圖像數(shù)據(jù)方向

所以呢我們需要使用camera的setDisplayOrientation方法來調(diào)整方向友多,在初始化的時(shí)候mCamera.setDisplayOrientation(90);即可

運(yùn)行如下:

圖3 Camera預(yù)覽圖
三.TextureView實(shí)現(xiàn)預(yù)覽效果

<p>

同樣我們創(chuàng)建一個(gè)相機(jī)預(yù)覽加載View牲平,該類繼承TextureView與TextureView.SurfaceTextureListener接口類,在onSurfaceTextureAvailable方法內(nèi)域滥,初始化Camera類纵柿,并設(shè)置Camera的setPreviewTexture方法為onSurfaceTextureAvailable方法參數(shù)中的SurfaceTexture即可

代碼如下:

public class CameraTextureView extends TextureView implements TextureView.SurfaceTextureListener{

    Context mContext;
    private Camera mCamera;


    public CameraTextureView(Context context){
        super(context);
        mContext = context;
        this.setSurfaceTextureListener(this);
    }

    @Override
    public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) {

        try {
            mCamera = Camera.open();
            mCamera.setDisplayOrientation(90);
            mCamera.setPreviewTexture(surface);
            mCamera.startPreview();

        } catch (IOException t) {
        }
    }

    @Override
    public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) {

    }

    @Override
    public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) {
        mCamera.stopPreview();
        mCamera.release();
        return false;
    }

    @Override
    public void onSurfaceTextureUpdated(SurfaceTexture surface) {

    }
}

接下來就是將這個(gè)View放到布局文件中

運(yùn)行如下

圖4 Camera預(yù)覽圖
四.GLSurfaceView實(shí)現(xiàn)預(yù)覽效果

<p>

GLSurfaceView和前面兩個(gè)預(yù)覽View不同的是蜈抓,他需要拿到數(shù)據(jù)自己進(jìn)行渲染預(yù)覽,大致流程如下:

GLSurfaceView->setRender->onSurfaceCreated回調(diào)方法中構(gòu)造一個(gè)SurfaceTexture對象昂儒,然后設(shè)置到Camera預(yù)覽中->SurfaceTexture中的回調(diào)方法onFrameAvailable來得知一幀的數(shù)據(jù)準(zhǔn)備好了->requestRender通知Render來繪制數(shù)據(jù)->在Render的回調(diào)方法onDrawFrame中調(diào)用SurfaceTexture的updateTexImage方法獲取一幀數(shù)據(jù)沟使,然后開始使用GL來進(jìn)行繪制預(yù)覽。

OK接下來就是用代碼來實(shí)現(xiàn)這個(gè)流程了

其實(shí)這里就是將之前的OpenGl繪制圖片與上面的Camera相關(guān)的應(yīng)用結(jié)合到一起就可以實(shí)現(xiàn)相關(guān)的功能

在OpenGl繪制圖片基礎(chǔ)上我們進(jìn)行相關(guān)修改

1.添加Camera相關(guān)

Camera相關(guān)其實(shí)和前面一樣我們這里要給Camera對象一個(gè)SurfaceTexture渊跋,這個(gè)SurfaceTexture我們需要自己創(chuàng)建腊嗡,在onSurfaceCreated中出創(chuàng)建這個(gè)對象,并設(shè)置當(dāng)Camera有新數(shù)據(jù)的回調(diào)函數(shù),如下

@Override
public void onSurfaceCreated(GL10 gl, EGLConfig config) {
    ...
    surfaceTexture = new SurfaceTexture(0);
    surfaceTexture.setOnFrameAvailableListener(onFrameAvailableListener);
}

private SurfaceTexture.OnFrameAvailableListener onFrameAvailableListener = new SurfaceTexture.OnFrameAvailableListener() {

    @Override
    public void onFrameAvailable(SurfaceTexture surfaceTexture) {
        requestRender();
    }
};

這個(gè)回調(diào)函數(shù)作用是當(dāng)有新的Camera數(shù)據(jù)時(shí)候去讓OpenGl的onDrawFrame調(diào)用拾酝,進(jìn)行重新繪制

接下來就是在onSurfaceChanged去打開Camera燕少,如下

@Override
public void onSurfaceChanged(GL10 gl, int width, int height) {

  openCamera();

}

private Camera mCamera;

private void openCamera(){
    try {
        mCamera = getCameraInstance();
        mCamera.setPreviewTexture(surfaceTexture);
        mCamera.startPreview();
    }catch (IOException e){

    }
}

public static Camera getCameraInstance(){
    Camera c = null;
    try {
        c = Camera.open(); // attempt to get a Camera instance
    }
    catch (Exception e){
        // Camera is not available (in use or does not exist)
    }
    return c; // returns null if camera is unavailable
}

到這里關(guān)于Camera相關(guān)的設(shè)置就已經(jīng)完畢了,接下來就是獲取數(shù)據(jù)去顯示了

2.片段著色器程序修改

當(dāng)Camera有新的數(shù)據(jù)則會通過OnFrameAvailableListener通知到我們蒿囤,然后我們會通過requestRender()來觸發(fā)OpenGl的重繪

我們通過surfaceTexture.updateTexImage()來獲取新的Camera預(yù)覽數(shù)據(jù)

這個(gè)方法的官網(wǎng)解釋如下:

Update the texture image to the most recent frame from the image stream. This may only be called while the OpenGL ES context that owns the texture is current on the calling thread. It will implicitly bind its texture to the GL_TEXTURE_EXTERNAL_OES texture target

大意是棺亭,從圖像流中更新紋理圖像到最近的幀中。這個(gè)函數(shù)僅僅當(dāng)擁有這個(gè)紋理的Opengl ES上下文當(dāng)前正處在繪制線程時(shí)被調(diào)用蟋软。它將隱式的綁定到這個(gè)擴(kuò)展的GL_TEXTURE_EXTERNAL_OES 目標(biāo)紋理

所以我們需要更改我們的片段著色器程序如下

#extension GL_OES_EGL_image_external : require

precision mediump float;
varying vec2 v_texCoord;
uniform samplerExternalOES s_texture;

void main() 
  gl_FragColor = texture2D( s_texture, v_texCoord )
}

并且在onDrawFrame()方法內(nèi)部調(diào)用surfaceTexture.updateTexImage(),即可以達(dá)到預(yù)覽效果

@Override
public void onDrawFrame(GL10 gl) {
  ...
  if (surfaceTexture == null)
      return;
  surfaceTexture.updateTexImage();
  ...
}       

運(yùn)行如下

圖5 camera預(yù)覽圖

可以看到這里視頻是不對的镶摘,通過設(shè)置setDisplayOrientation也沒有效果,我們只能通過去修改頂點(diǎn)著色器位置與片段著色器位置來進(jìn)行修正了

修改如下

private static final float[] VERTEX = {
    -1.0f, 1.0f, 0.0f,
    -1.0f, -1.0f, 0.0f,
    1.0f, -1.0f, 0.0f,
    1.0f, 1.0f, 0.0f,
};  

private static final float[] UV_TEX_VERTEX = {  
    0.0f, 1.0f,
    1.0f, 1.0f,
    1.0f, 0.0f,
    0.0f, 0.0f,
};

GLES20.glDrawArrays(GLES20.GL_TRIANGLE_FAN, 0, 4);

接下來運(yùn)行岳守,如下

圖6 正確的camera預(yù)覽圖

到這里GLSurfaceView實(shí)現(xiàn)預(yù)覽效果就完成啦

視頻播放開發(fā)

<p>
前面實(shí)現(xiàn)了相機(jī)預(yù)覽效果凄敢,這里則是來實(shí)現(xiàn)視頻播放效果,其實(shí)SurfaceView這些設(shè)計(jì)之初就是為了解決視頻播放湿痢,游戲等問題涝缝,所以我們可以來看一下之前相機(jī)預(yù)覽的方法是否適用于這里。如果可以適用的話譬重,那么就簡單很多了拒逮。

我們看上面的三種方式,主要是用了Camera的方法mCamera.setPreviewTexture(surface)與mCamera.setPreviewDisplay(holder)臀规,所以只要視頻播放也有相同的方法就可以了滩援。

視頻播放主要用到MediaPlayer,值得高興的是MediaPlayer中確實(shí)是有上述的兩種方法塔嬉,那么這樣我們就可以用上一篇文章相同的方式來實(shí)現(xiàn)播放效果了

一.SurfaceView實(shí)現(xiàn)視頻播放效果

<p>

這里其實(shí)和之前的流程一樣玩徊,只是將之前的相機(jī)預(yù)覽相關(guān)改成視頻播放,這里就直接將代碼貼上來了谨究,不做過多的介紹

public class CameraSurfaceView extends SurfaceView implements SurfaceHolder.Callback{

    private SurfaceHolder holder;

    private MediaPlayer mediaPlayer;

    public final String videoPath = Environment.getExternalStorageDirectory().getPath()+"/one.mp4";

    public CameraSurfaceView(Context context) {
        this(context, null);
    }

    public CameraSurfaceView(Context context, AttributeSet attrs) {
        super(context, attrs);
        holder = getHolder();
        holder.addCallback(this);
    }

    @Override
    public void surfaceCreated(SurfaceHolder holder) {
        if (mediaPlayer == null) {
            mediaPlayer = new MediaPlayer();
            mediaPlayer.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
                @Override
                public void onPrepared(MediaPlayer mp) {
                    mp.start();
                }
            });
            mediaPlayer.setDisplay(holder);
            try {
                mediaPlayer.setDataSource(videoPath);
                mediaPlayer.prepareAsync();
            } catch (IOException e) {
                e.printStackTrace();
            }
        } else {
            mediaPlayer.start();
        }
    }


    @Override
    public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {

    }

    @Override
    public void surfaceDestroyed(SurfaceHolder holder) {

    }

}

運(yùn)行如下

圖1 SurfaceView 實(shí)現(xiàn)視頻播放
二.TextureView實(shí)現(xiàn)視頻播放效果

<p>

同上恩袱,代碼如下

public class CameraTextureView extends TextureView implements TextureView.SurfaceTextureListener{

    Context mContext;

    private MediaPlayer mediaPlayer;

    public final String videoPath = Environment.getExternalStorageDirectory().getPath()+"/one.mp4";


    public CameraTextureView(Context context){
        super(context);
        mContext = context;
        this.setSurfaceTextureListener(this);
    }

    @Override
    public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) {

        if (mediaPlayer == null) {
            mediaPlayer = new MediaPlayer();
            mediaPlayer.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
                @Override
                public void onPrepared(MediaPlayer mp) {
                    mp.start();
                }
            });
            Surface surfaces = new Surface(surface);
            mediaPlayer.setSurface(surfaces);
            surfaces.release();
            try {
                mediaPlayer.setDataSource(videoPath);
                mediaPlayer.prepareAsync();
            } catch (IOException e) {
                e.printStackTrace();
            }
        } else {
            mediaPlayer.start();
        }
    }

    @Override
    public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) {

    }

    @Override
    public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) {

        return false;
    }

    @Override
    public void onSurfaceTextureUpdated(SurfaceTexture surface) {

    }
}

運(yùn)行如下

圖2 TextureView實(shí)現(xiàn)視頻播放
三.GLSurfaceView實(shí)現(xiàn)視頻播放效果

<p>

這里和之前基本一樣只需要將OpenCamera部分的代碼改成打開MediaPlayer就好了,這里我就貼上這一部分的代碼胶哲,如下

private MediaPlayer mediaPlayer;

public final String videoPath = Environment.getExternalStorageDirectory().getPath()+"/one.mp4";


private void openMediaPlayer(){
    if (mediaPlayer == null) {
        mediaPlayer = new MediaPlayer();
        mediaPlayer.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
            @Override
            public void onPrepared(MediaPlayer mp) {
                mp.start();
            }
        });
        Surface surface = new Surface(surfaceTexture);
        mediaPlayer.setSurface(surface);
        surface.release();
        try {
            mediaPlayer.setDataSource(videoPath);
            mediaPlayer.prepareAsync();
        } catch (IOException e) {
            e.printStackTrace();
        }
    } else {
        mediaPlayer.start();
    }
}

接下來運(yùn)行如下

圖2 GLSurfaceView實(shí)現(xiàn)視頻播放

寫在后面的話

<p>

這里基本把所有的實(shí)現(xiàn)預(yù)覽相關(guān)的方式都講解過了畔塔,但是基于要對Camera預(yù)覽的與視頻播放數(shù)據(jù)要進(jìn)行處理,所以我們采用最后一種GLSurfaceView方式來作為濾鏡開發(fā)的主要方式,到這里基本就完成了所以的準(zhǔn)備工作澈吨,包括圖片把敢,相機(jī)預(yù)覽,視頻播放這三者都通過OpenGL方式實(shí)現(xiàn)了棚辽,接下來就可以開始我們的濾鏡開發(fā)了,然而OpenGL自帶的媒體效果框架就可以實(shí)現(xiàn)濾鏡的效果冰肴?這不是在逗我們嘛屈藐,好吧好吧,下一篇見熙尉,peace~~~~

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末联逻,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子检痰,更是在濱河造成了極大的恐慌包归,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,755評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件铅歼,死亡現(xiàn)場離奇詭異公壤,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)椎椰,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,305評論 3 395
  • 文/潘曉璐 我一進(jìn)店門厦幅,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人慨飘,你說我怎么就攤上這事确憨。” “怎么了瓤的?”我有些...
    開封第一講書人閱讀 165,138評論 0 355
  • 文/不壞的土叔 我叫張陵休弃,是天一觀的道長。 經(jīng)常有香客問我圈膏,道長塔猾,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,791評論 1 295
  • 正文 為了忘掉前任稽坤,我火速辦了婚禮桥帆,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘慎皱。我一直安慰自己老虫,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,794評論 6 392
  • 文/花漫 我一把揭開白布茫多。 她就那樣靜靜地躺著祈匙,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上夺欲,一...
    開封第一講書人閱讀 51,631評論 1 305
  • 那天跪帝,我揣著相機(jī)與錄音,去河邊找鬼些阅。 笑死伞剑,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的市埋。 我是一名探鬼主播黎泣,決...
    沈念sama閱讀 40,362評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼缤谎!你這毒婦竟也來了抒倚?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,264評論 0 276
  • 序言:老撾萬榮一對情侶失蹤坷澡,失蹤者是張志新(化名)和其女友劉穎托呕,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體频敛,經(jīng)...
    沈念sama閱讀 45,724評論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡项郊,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,900評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了斟赚。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片呆抑。...
    茶點(diǎn)故事閱讀 40,040評論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖汁展,靈堂內(nèi)的尸體忽然破棺而出鹊碍,到底是詐尸還是另有隱情,我是刑警寧澤食绿,帶...
    沈念sama閱讀 35,742評論 5 346
  • 正文 年R本政府宣布侈咕,位于F島的核電站,受9級特大地震影響器紧,放射性物質(zhì)發(fā)生泄漏耀销。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,364評論 3 330
  • 文/蒙蒙 一铲汪、第九天 我趴在偏房一處隱蔽的房頂上張望熊尉。 院中可真熱鬧,春花似錦掌腰、人聲如沸狰住。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,944評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽催植。三九已至肮蛹,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間创南,已是汗流浹背伦忠。 一陣腳步聲響...
    開封第一講書人閱讀 33,060評論 1 270
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留稿辙,地道東北人昆码。 一個(gè)月前我還...
    沈念sama閱讀 48,247評論 3 371
  • 正文 我出身青樓,卻偏偏與公主長得像邻储,于是被迫代替她去往敵國和親赋咽。 傳聞我的和親對象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,979評論 2 355

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