Android 微信小視頻錄制功能的實(shí)現(xiàn)

開發(fā)之前

這幾天接觸了一下和視頻相關(guān)的控件, 所以, 繼之前的微信搖一搖, 我想到了來(lái)實(shí)現(xiàn)一下微信小視頻錄制的功能, 它的功能點(diǎn)比較多, 我每天都抽出點(diǎn)時(shí)間來(lái)寫寫, 說實(shí)話, 有些東西還是比較費(fèi)勁, 希望大家認(rèn)真看看, 說得不對(duì)的地方還請(qǐng)大家在評(píng)論中指正. 廢話不多說, 進(jìn)入正題.

開發(fā)環(huán)境

最近剛更新的, 沒更新的小伙伴們抓緊了

  • Android Studio 2.2.2
  • JDK1.7
  • API 24
  • Gradle 2.2.2

相關(guān)知識(shí)點(diǎn)

  • 視頻錄制界面 SurfaceView 的使用

  • Camera的使用

  • 相機(jī)的對(duì)焦, 變焦

  • 視頻錄制控件MediaRecorder的使用

  • 簡(jiǎn)單自定義View

  • GestureDetector(手勢(shì)檢測(cè))的使用

用到的東西真不少, 不過別著急, 咱們一個(gè)一個(gè)來(lái).

開始開發(fā)

案例預(yù)覽

請(qǐng)?jiān)廏if圖的粗糙

微信小視頻

案例分析

大家可以打開自己微信里面的小視頻, 一塊簡(jiǎn)單的分析一下它的功能點(diǎn)有哪些 ?

  • 基本的視頻預(yù)覽功能

  • 長(zhǎng)按 "按住拍" 實(shí)現(xiàn)視頻的錄制

  • 錄制過程中的進(jìn)度條從兩側(cè)向中間變短

  • 當(dāng)松手或者進(jìn)度條走到盡頭視頻停止錄制 并保存

  • 從 "按住拍" 上滑取消視頻的錄制

  • 雙擊屏幕 變焦 放大

根據(jù)上述的分析, 我們一步一步的完成

搭建布局

布局界面的實(shí)現(xiàn)還可以, 難度不大


<?xml version="1.0" encoding="utf-8"?>
<FrameLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <TextView
        android:id="@+id/main_tv_tip"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="bottom|center_horizontal"
        android:layout_marginBottom="150dp"
        android:elevation="1dp"
        android:text="雙擊放大"
        android:textColor="#FFFFFF"/>
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical">
        <SurfaceView
            android:id="@+id/main_surface_view"
            android:layout_width="match_parent"
            android:layout_height="0dp"
            android:layout_weight="3"/>
        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="0dp"
            android:layout_weight="1"
            android:background="@color/colorApp"
            android:orientation="vertical">
            <RelativeLayout
                android:id="@+id/main_press_control"
                android:layout_width="match_parent"
                android:layout_height="match_parent">
                <com.lulu.weichatsamplevideo.BothWayProgressBar
                    android:id="@+id/main_progress_bar"
                    android:layout_width="match_parent"
                    android:layout_height="2dp"
                    android:background="#000"/>
                <TextView
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:layout_centerInParent="true"
                    android:text="按住拍"
                    android:textAppearance="@style/TextAppearance.AppCompat.Large"
                    android:textColor="#00ff00"/>
            </RelativeLayout>
        </LinearLayout>
    </LinearLayout>
</FrameLayout>

視頻預(yù)覽的實(shí)現(xiàn)

step1: 得到SufaceView控件, 設(shè)置基本屬性和相應(yīng)監(jiān)聽(該控件的創(chuàng)建是異步的, 只有在真正"準(zhǔn)備"好之后才能調(diào)用)


mSurfaceView = (SurfaceView) findViewById(R.id.main_surface_view);
 //設(shè)置屏幕分辨率
mSurfaceHolder.setFixedSize(videoWidth, videoHeight);
mSurfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
mSurfaceHolder.addCallback(this);

step2: 實(shí)現(xiàn)接口的方法, surfaceCreated方法中開啟視頻的預(yù)覽, 在surfaceDestroyed中銷毀


//////////////////////////////////////////////
// SurfaceView回調(diào)
/////////////////////////////////////////////
@Override
public void surfaceCreated(SurfaceHolder holder) {
    mSurfaceHolder = holder;
    startPreView(holder);
}
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {

}

@Override
public void surfaceDestroyed(SurfaceHolder holder) {
    if (mCamera != null) {
        Log.d(TAG, "surfaceDestroyed: ");
        //停止預(yù)覽并釋放攝像頭資源
        mCamera.stopPreview();
        mCamera.release();
        mCamera = null;
    }
    if (mMediaRecorder != null) {
        mMediaRecorder.release();
        mMediaRecorder = null;
    }
}

step3: 實(shí)現(xiàn)視頻預(yù)覽的方法


/**
 * 開啟預(yù)覽
 *
 * @param holder
 */
private void startPreView(SurfaceHolder holder) {
    Log.d(TAG, "startPreView: ");

    if (mCamera == null) {
        mCamera = Camera.open(Camera.CameraInfo.CAMERA_FACING_BACK);
    }
    if (mMediaRecorder == null) {
        mMediaRecorder = new MediaRecorder();
    }
    if (mCamera != null) {
        mCamera.setDisplayOrientation(90);
        try {
            mCamera.setPreviewDisplay(holder);
            Camera.Parameters parameters = mCamera.getParameters();
            //實(shí)現(xiàn)Camera自動(dòng)對(duì)焦
            List<String> focusModes = parameters.getSupportedFocusModes();
            if (focusModes != null) {
                for (String mode : focusModes) {
                    mode.contains("continuous-video");
                    parameters.setFocusMode("continuous-video");
                }
            }
            mCamera.setParameters(parameters);
            mCamera.startPreview();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

}

Note: 上面添加了自動(dòng)對(duì)焦的代碼, 但是部分手機(jī)可能不支持

自定義雙向縮減的進(jìn)度條

有些像我一樣的初學(xué)者一看到自定義某某View, 就覺得比較牛X. 其實(shí)呢, Google已經(jīng)替我們寫好了很多代碼, 所以我們用就行了.而且咱們的這個(gè)進(jìn)度條也沒啥, 不就是一根線, 今天咱就來(lái)說說.

step1: 繼承View, 完成初始化


private static final String TAG = "BothWayProgressBar";
//取消狀態(tài)為紅色bar, 反之為綠色bar
private boolean isCancel = false;
private Context mContext;
//正在錄制的畫筆
private Paint mRecordPaint;
//上滑取消時(shí)的畫筆
private Paint mCancelPaint;
//是否顯示
private int mVisibility;
// 當(dāng)前進(jìn)度
private int progress;
//進(jìn)度條結(jié)束的監(jiān)聽
private OnProgressEndListener mOnProgressEndListener;

public BothWayProgressBar(Context context) {
     super(context, null);
}
public BothWayProgressBar(Context context, AttributeSet attrs) {
   super(context, attrs);
   mContext = context;
   init();
}
private void init() {
   mVisibility = INVISIBLE;
   mRecordPaint = new Paint();
   mRecordPaint.setColor(Color.GREEN);
   mCancelPaint = new Paint();
   mCancelPaint.setColor(Color.RED);
}

Note: OnProgressEndListener, 主要用于當(dāng)進(jìn)度條走到中間了, 好通知相機(jī)停止錄制, 接口如下:


public interface OnProgressEndListener{
    void onProgressEndListener();
}
/**
 * 當(dāng)進(jìn)度條結(jié)束后的 監(jiān)聽
 * @param onProgressEndListener
 */
public void setOnProgressEndListener(OnProgressEndListener onProgressEndListener) {
    mOnProgressEndListener = onProgressEndListener;
}

step2 :設(shè)置Setter方法用于通知我們的Progress改變狀態(tài)



/**
 * 設(shè)置進(jìn)度
 * @param progress
 */
public void setProgress(int progress) {
    this.progress = progress;
    invalidate();
}

/**
 * 設(shè)置錄制狀態(tài) 是否為取消狀態(tài)
 * @param isCancel
 */
public void setCancel(boolean isCancel) {
    this.isCancel = isCancel;
    invalidate();
}
/**
 * 重寫是否可見方法
 * @param visibility
 */
@Override
public void setVisibility(int visibility) {
    mVisibility = visibility;
    //重新繪制
    invalidate();
}

step3 :最重要的一步, 畫出我們的進(jìn)度條,使用的就是View中的onDraw(Canvas canvas)方法

@Override
protected void onDraw(Canvas canvas) {
    super.onDraw(canvas);
    if (mVisibility == View.VISIBLE) {
        int height = getHeight();
        int width = getWidth();
        int mid = width / 2;


        //畫出進(jìn)度條
        if (progress < mid){
            canvas.drawRect(progress, 0, width-progress, height, isCancel ? mCancelPaint : mRecordPaint);
        } else {
            if (mOnProgressEndListener != null) {
                mOnProgressEndListener.onProgressEndListener();
            }
        }
    } else {
        canvas.drawColor(Color.argb(0, 0, 0, 0));
    }
}

錄制事件的處理

錄制中觸發(fā)的事件包括四個(gè):

  1. 長(zhǎng)按錄制
  2. 抬起保存
  3. 上滑取消
  4. 雙擊放大(變焦)

現(xiàn)在對(duì)這4個(gè)事件逐個(gè)分析:
前三這個(gè)事件, 我都放在了一個(gè)onTouch()回調(diào)方法中了
對(duì)于第4個(gè), 我們待會(huì)談
我們先把onTouch()中局部變量列舉一下:


@Override
public boolean onTouch(View v, MotionEvent event) {
   boolean ret = false;
   int action = event.getAction();
   float ey = event.getY();
   float ex = event.getX();
   //只監(jiān)聽中間的按鈕處
   int vW = v.getWidth();
   int left = LISTENER_START;
   int right = vW - LISTENER_START;
   float downY = 0;
   // ...
}

長(zhǎng)按錄制

長(zhǎng)按錄制我們需要監(jiān)聽ACTION_DOWN事件, 使用線程延遲發(fā)送Handler來(lái)實(shí)現(xiàn)進(jìn)度條的更新

switch (action) {
  case MotionEvent.ACTION_DOWN:
      if (ex > left && ex < right) {
          mProgressBar.setCancel(false);
          //顯示上滑取消
          mTvTip.setVisibility(View.VISIBLE);
          mTvTip.setText("↑ 上滑取消");
          //記錄按下的Y坐標(biāo)
          downY = ey;
          // TODO: 2016/10/20 開始錄制視頻, 進(jìn)度條開始走
          mProgressBar.setVisibility(View.VISIBLE);
          //開始錄制
          Toast.makeText(this, "開始錄制", Toast.LENGTH_SHORT).show();
          startRecord();
          mProgressThread = new Thread() {
              @Override
              public void run() {
                  super.run();
                  try {
                      mProgress = 0;
                      isRunning = true;
                      while (isRunning) {
                          mProgress++;
                          mHandler.obtainMessage(0).sendToTarget();
                          Thread.sleep(20);
                      }
                  } catch (InterruptedException e) {
                      e.printStackTrace();
                  }
              }
          };
          mProgressThread.start();
          ret = true;
      }
      break;
      // ...
      return true;
}

Note: startRecord()這個(gè)方法先不說, 我們只需要知道執(zhí)行了它就可以錄制了, 但是Handler事件還是要說的, 它只負(fù)責(zé)更新進(jìn)度條的進(jìn)度



////////////////////////////////////////////////////
// Handler處理
/////////////////////////////////////////////////////
private static class MyHandler extends Handler {
    private WeakReference<MainActivity> mReference;
    private MainActivity mActivity;

    public MyHandler(MainActivity activity) {
        mReference = new WeakReference<MainActivity>(activity);
        mActivity = mReference.get();
    }

    @Override
    public void handleMessage(Message msg) {
        switch (msg.what) {
            case 0:
                mActivity.mProgressBar.setProgress(mActivity.mProgress);
                break;
        }
    }
}

抬起保存

同樣我們這兒需要監(jiān)聽ACTION_UP事件, 但是要考慮當(dāng)用戶抬起過快時(shí)(錄制的時(shí)間過短), 不需要保存. 而且, 在這個(gè)事件中包含了取消狀態(tài)的抬起, 解釋一下: 就是當(dāng)上滑取消時(shí)抬起的一瞬間取消錄制, 大家看代碼

case MotionEvent.ACTION_UP:
  if (ex > left && ex < right) {
      mTvTip.setVisibility(View.INVISIBLE);
      mProgressBar.setVisibility(View.INVISIBLE);
      //判斷是否為錄制結(jié)束, 或者為成功錄制(時(shí)間過短)
      if (!isCancel) {
          if (mProgress < 50) {
              //時(shí)間太短不保存
              stopRecordUnSave();
              Toast.makeText(this, "時(shí)間太短", Toast.LENGTH_SHORT).show();
              break;
          }
          //停止錄制
          stopRecordSave();
      } else {
          //現(xiàn)在是取消狀態(tài),不保存
          stopRecordUnSave();
          isCancel = false;
          Toast.makeText(this, "取消錄制", Toast.LENGTH_SHORT).show();
          mProgressBar.setCancel(false);
      }

      ret = false;
  }
  break;

Note: 同樣的, 內(nèi)部的stopRecordUnSave()和stopRecordSave();大家先不要考慮, 我們會(huì)在后面介紹, 他倆從名字就能看出 前者用來(lái)停止錄制但不保存, 后者停止錄制并保存

上滑取消

配合上一部分說得抬起取消事件, 實(shí)現(xiàn)上滑取消


case MotionEvent.ACTION_MOVE:
  if (ex > left && ex < right) {
      float currentY = event.getY();
      if (downY - currentY > 10) {
          isCancel = true;
          mProgressBar.setCancel(true);
      }
  }
  break;

Note: 主要原理不難, 只要按下并且向上移動(dòng)一定距離 就會(huì)觸發(fā),當(dāng)手抬起時(shí)視頻錄制取消

雙擊放大(變焦)

這個(gè)事件比較特殊, 使用了Google提供的GestureDetector手勢(shì)檢測(cè) 來(lái)判斷雙擊事件

step1: 對(duì)SurfaceView進(jìn)行單獨(dú)的Touch事件監(jiān)聽, why? 因?yàn)镚estureDetector需要Touch事件的完全托管, 如果只給它傳部分事件會(huì)造成某些事件失效

mDetector = new GestureDetector(this, new ZoomGestureListener());
/**
 * 單獨(dú)處理mSurfaceView的雙擊事件
 */
mSurfaceView.setOnTouchListener(new View.OnTouchListener() {
    @Override
    public boolean onTouch(View v, MotionEvent event) {
        mDetector.onTouchEvent(event);
        return true;
    }
});

step2: 重寫GestureDetector.SimpleOnGestureListener, 實(shí)現(xiàn)雙擊事件


///////////////////////////////////////////////////////////////////////////
// 變焦手勢(shì)處理類
///////////////////////////////////////////////////////////////////////////
class ZoomGestureListener extends GestureDetector.SimpleOnGestureListener {
    //雙擊手勢(shì)事件
    @Override
    public boolean onDoubleTap(MotionEvent e) {
        super.onDoubleTap(e);
        Log.d(TAG, "onDoubleTap: 雙擊事件");
        if (mMediaRecorder != null) {
            if (!isZoomIn) {
                setZoom(20);
                isZoomIn = true;
            } else {
                setZoom(0);
                isZoomIn = false;
            }
        }
        return true;
    }
}

step3: 實(shí)現(xiàn)相機(jī)的變焦的方法


/**
 * 相機(jī)變焦
 *
 * @param zoomValue
 */
public void setZoom(int zoomValue) {
    if (mCamera != null) {
        Camera.Parameters parameters = mCamera.getParameters();
        if (parameters.isZoomSupported()) {//判斷是否支持
            int maxZoom = parameters.getMaxZoom();
            if (maxZoom == 0) {
                return;
            }
            if (zoomValue > maxZoom) {
                zoomValue = maxZoom;
            }
            parameters.setZoom(zoomValue);
            mCamera.setParameters(parameters);
        }
    }

}

Note: 至此我們已經(jīng)完成了對(duì)所有事件的監(jiān)聽, 看到這里大家也許有些疲憊了, 不過不要灰心, 現(xiàn)在完成我們的核心部分, 實(shí)現(xiàn)視頻的錄制

實(shí)現(xiàn)視頻的錄制

說是核心功能, 也只不過是我們不知道某些API方法罷了, 下面代碼中我已經(jīng)加了詳細(xì)的注釋, 部分不能理解的記住就好v

/**
 * 開始錄制
 */
private void startRecord() {
    if (mMediaRecorder != null) {
        //沒有外置存儲(chǔ), 直接停止錄制
        if (!Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
            return;
        }
        try {
            //mMediaRecorder.reset();
            mCamera.unlock();
            mMediaRecorder.setCamera(mCamera);
            //從相機(jī)采集視頻
            mMediaRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA);
            // 從麥克采集音頻信息
            mMediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
            // TODO: 2016/10/20  設(shè)置視頻格式
            mMediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);
            mMediaRecorder.setVideoSize(videoWidth, videoHeight);
            //每秒的幀數(shù)
            mMediaRecorder.setVideoFrameRate(24);
            //編碼格式
            mMediaRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.DEFAULT);
            mMediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
            // 設(shè)置幀頻率,然后就清晰了
            mMediaRecorder.setVideoEncodingBitRate(1 * 1024 * 1024 * 100);
            // TODO: 2016/10/20 臨時(shí)寫個(gè)文件地址, 稍候該!!!
            File targetDir = Environment.
                    getExternalStoragePublicDirectory(Environment.DIRECTORY_MOVIES);
            mTargetFile = new File(targetDir,
                    SystemClock.currentThreadTimeMillis() + ".mp4");
            mMediaRecorder.setOutputFile(mTargetFile.getAbsolutePath());
            mMediaRecorder.setPreviewDisplay(mSurfaceHolder.getSurface());
            //解決錄制視頻, 播放器橫向問題
            mMediaRecorder.setOrientationHint(90);
            mMediaRecorder.prepare();
            //正式錄制
            mMediaRecorder.start();
            isRecording = true;
        } catch (Exception e) {
            e.printStackTrace();
        }

    }
}


實(shí)現(xiàn)視頻的停止

大家可能會(huì)問, 視頻的停止為什么單獨(dú)抽出來(lái)說呢? 仔細(xì)的同學(xué)看上面代碼會(huì)看到這兩個(gè)方法: stopRecordSave和stopRecordUnSave, 一個(gè)停止保存, 一個(gè)是停止不保存, 接下來(lái)我們就補(bǔ)上這個(gè)坑

停止并保存


private void stopRecordSave() {
    if (isRecording) {
        isRunning = false;
        mMediaRecorder.stop();
        isRecording = false;
        Toast.makeText(this, "視頻已經(jīng)放至" + mTargetFile.getAbsolutePath(), Toast.LENGTH_SHORT).show();
    }
}

停止不保存


private void stopRecordUnSave() {
    if (isRecording) {
        isRunning = false;
        mMediaRecorder.stop();
        isRecording = false;
        if (mTargetFile.exists()) {
            //不保存直接刪掉
            mTargetFile.delete();
        }
    }
}

Note: 這個(gè)停止不保存是我自己的一種想法, 如果大家有更好的想法, 歡迎大家到評(píng)論中指出, 不勝感激

完整代碼

源碼我已經(jīng)放在了github上了, 寫博客真是不易! 寫篇像樣的博客更是不易, 希望大家多多支持

總結(jié)

終于寫完了!!! 這是我最想說得話, 從案例一開始到現(xiàn)在已經(jīng)過去很長(zhǎng)時(shí)間. 這是我寫得最長(zhǎng)的一篇博客, 發(fā)現(xiàn)能表達(dá)清楚自己的想法還是很困難的, 這是我最大的感受!!!
實(shí)話說這個(gè)案例不是很困難, 但是像我這樣的初學(xué)者拿來(lái)練練手還是非常好的, 在這里還要感謝再見杰克的博客, 也給我提供了很多幫助
最后, 希望大家共同進(jìn)步!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市蝙泼,隨后出現(xiàn)的幾起案子裆装,更是在濱河造成了極大的恐慌,老刑警劉巖哨免,帶你破解...
    沈念sama閱讀 211,265評(píng)論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件琢唾,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡懒熙,警方通過查閱死者的電腦和手機(jī)普办,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,078評(píng)論 2 385
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)肢娘,“玉大人,你說我怎么就攤上這事而钞【械矗” “怎么了?”我有些...
    開封第一講書人閱讀 156,852評(píng)論 0 347
  • 文/不壞的土叔 我叫張陵网缝,是天一觀的道長(zhǎng)亮隙。 經(jīng)常有香客問我溢吻,道長(zhǎng),這世上最難降的妖魔是什么促王? 我笑而不...
    開封第一講書人閱讀 56,408評(píng)論 1 283
  • 正文 為了忘掉前任蝇狼,我火速辦了婚禮,結(jié)果婚禮上贱枣,老公的妹妹穿的比我還像新娘颤专。我一直安慰自己,他們只是感情好春塌,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,445評(píng)論 5 384
  • 文/花漫 我一把揭開白布簇捍。 她就那樣靜靜地躺著暑塑,像睡著了一般。 火紅的嫁衣襯著肌膚如雪事格。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,772評(píng)論 1 290
  • 那天,我揣著相機(jī)與錄音么鹤,去河邊找鬼。 笑死棠耕,一個(gè)胖子當(dāng)著我的面吹牛柠新,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播蕊退,決...
    沈念sama閱讀 38,921評(píng)論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼瓤荔,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼钥组!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起程梦,我...
    開封第一講書人閱讀 37,688評(píng)論 0 266
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤屿附,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后衣厘,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體压恒,經(jīng)...
    沈念sama閱讀 44,130評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡探赫,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,467評(píng)論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了妆兑。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,617評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡芯勘,死狀恐怖腺逛,靈堂內(nèi)的尸體忽然破棺而出棍矛,到底是詐尸還是另有隱情,我是刑警寧澤够委,帶...
    沈念sama閱讀 34,276評(píng)論 4 329
  • 正文 年R本政府宣布茁帽,位于F島的核電站,受9級(jí)特大地震影響厌小,放射性物質(zhì)發(fā)生泄漏战秋。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,882評(píng)論 3 312
  • 文/蒙蒙 一癣蟋、第九天 我趴在偏房一處隱蔽的房頂上張望狰闪。 院中可真熱鬧,春花似錦幔欧、人聲如沸丽声。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,740評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)霉撵。三九已至洪囤,卻和暖如春撕氧,著一層夾襖步出監(jiān)牢的瞬間伦泥,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,967評(píng)論 1 265
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留海洼,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 46,315評(píng)論 2 360
  • 正文 我出身青樓域帐,卻偏偏與公主長(zhǎng)得像肖揣,于是被迫代替她去往敵國(guó)和親浮入。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,486評(píng)論 2 348

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

  • 原文鏈接http://www.cnblogs.com/kenshincui/p/4186022.html 音頻在i...
    Hyman0819閱讀 21,682評(píng)論 4 74
  • 2017.02.22 可以練習(xí),每當(dāng)這個(gè)時(shí)候衅胀,腦袋就犯困,我這腦袋真是神奇呀雏门,一說讓你做事情掸掏,你就犯困,你可不要太...
    Carden閱讀 1,331評(píng)論 0 1
  • 云片高閱讀 251評(píng)論 0 0
  • 陋室銘 劉禹錫 山不在高,有仙則名愿待。水不在深,有龍則靈要出。斯是陋室农渊,惟吾德馨。苔痕上階綠况脆,草色入簾青批糟。談笑有鴻儒,往...
    悅悅愛吃魚閱讀 239評(píng)論 0 0
  • 看到這句話時(shí)盛末,突然有一種沖動(dòng)否淤,去老家買一塊地,不必太大石抡,建一棟小小的別墅啰扛,里面有一間小小的廚房嗡贺,小小的書櫥鞍帝,小小的...
    秋之語(yǔ)閱讀 1,132評(píng)論 2 1