Android源碼之Camera系統(tǒng)架構(gòu)

Camera的架構(gòu)與Android系統(tǒng)的整體架構(gòu)保持一致,如下圖所示喉誊,本文主要從以下四個(gè)方面對(duì)其進(jìn)行說(shuō)明。

  1. Framework:Camera.java
  2. Android Runtime:android_hardware_Camera.cpp
  3. Library:Camera Client和Camera Service
  4. HAL:CameraHardwareInterface
Camera系統(tǒng)架構(gòu)

一澳淑、Framework:Camera.java

Camera是應(yīng)用層軟件直接使用的類,涵蓋了啟動(dòng)糙麦、預(yù)覽歇攻、拍攝及關(guān)閉等操作攝像頭的全部接口驮樊。Camera.java在Android源碼中的路徑為:framework/base/core/java/android/hardware粗恢。為了說(shuō)明整個(gè)Camera系統(tǒng)的架構(gòu)柑晒,這里暫不橫向分析Camera.java的功能,下面從open()方法著手:

public static Camera open() {
    int numberOfCameras = getNumberOfCameras();
    CameraInfo cameraInfo = new CameraInfo();
    for (int i = 0; i < numberOfCameras; i++) {
        getCameraInfo(i, cameraInfo);
        if (cameraInfo.facing == CameraInfo.CAMERA_FACING_BACK) {
            return new Camera(i);
        }
    }
    return null;
}

open()方法需要注意以下幾點(diǎn):

  • getNumberOfCameras為native方法眷射,實(shí)現(xiàn)在android_hardware_Camera.cpp中匙赞;
  • CameraInfo是Camera定義的靜態(tài)內(nèi)部類,包含facing妖碉、orientation涌庭、canDisableShutterSound;
  • getCameraInfo內(nèi)部調(diào)用native方法_getCameraInfo獲取攝像頭信息欧宜;
  • open()默認(rèn)啟動(dòng)的是后置攝像頭(CAMERA_FACING_BACK)坐榆。
/** used by Camera#open, Camera#open(int) */
Camera(int cameraId) {
    int err = cameraInitNormal(cameraId);
    if (checkInitErrors(err)) {
        switch(err) {
            case EACCESS:
                throw new RuntimeException("Fail to connect to camera service");
            case ENODEV:
                throw new RuntimeException("Camera initialization failed");
            default:
                // Should never hit this.
                throw new RuntimeException("Unknown camera error");
        }
    }
}

Camera構(gòu)造器的核心實(shí)現(xiàn)在cameraInitNormal中,cameraInitNormal調(diào)用cameraInitVersion鱼鸠,并傳入?yún)?shù)cameraId和CAMERA_HAL_API_VERSION_NORMAL_CONNECT猛拴,后者代表HAL的版本。

private int cameraInitVersion(int cameraId, int halVersion) {
    ……
    String packageName = ActivityThread.currentPackageName();
    return native_setup(new WeakReference<Camera>(this), cameraId, halVersion, packageName);
}

cameraInitNormal調(diào)用本地方法native_setup()蚀狰,由此進(jìn)入到android_hardware_Camera.cpp中,native_setup()的簽名如下:

private native final int native_setup(Object camera_this, int cameraId, int halVersion, String packageName);

二职员、Android Runtime:android_hardware_Camera.cpp

native_setup()被動(dòng)態(tài)注冊(cè)到JNI麻蹋,通過(guò)JNI調(diào)用android_hardware_Camera_native_setup()方法。

static JNINativeMethod camMethods[] = {
    ……
    { "native_setup",    "(Ljava/lang/Object;ILjava/lang/String;)V",
    (void*)android_hardware_Camera_native_setup }
    ……
};

JNI的重點(diǎn)是android_hardware_Camera_native_setup()方法的實(shí)現(xiàn):

// connect to camera service
static jint android_hardware_Camera_native_setup(JNIEnv *env, jobject thiz,
    jobject weak_this, jint cameraId, jint halVersion, jstring clientPackageName)
{
    // Convert jstring to String16
    const char16_t *rawClientName = env->GetStringChars(clientPackageName, NULL);
    jsize rawClientNameLen = env->GetStringLength(clientPackageName);
    String16 clientName(rawClientName, rawClientNameLen);
    env->ReleaseStringChars(clientPackageName, rawClientName);

    sp<Camera> camera;
    if (halVersion == CAMERA_HAL_API_VERSION_NORMAL_CONNECT) {
        // Default path: hal version is don't care, do normal camera connect.
        camera = Camera::connect(cameraId, clientName,
                Camera::USE_CALLING_UID);
    } else {
        jint status = Camera::connectLegacy(cameraId, halVersion, clientName,
                Camera::USE_CALLING_UID, camera);
        if (status != NO_ERROR) {
            return status;
        }
    }

    if (camera == NULL) {
        return -EACCES;
    }

    // make sure camera hardware is alive
    if (camera->getStatus() != NO_ERROR) {
        return NO_INIT;
    }

    jclass clazz = env->GetObjectClass(thiz);
    if (clazz == NULL) {
        // This should never happen
        jniThrowRuntimeException(env, "Can't find android/hardware/Camera");
        return INVALID_OPERATION;
    }

    // We use a weak reference so the Camera object can be garbage collected.
    // The reference is only used as a proxy for callbacks.
    sp<JNICameraContext> context = new JNICameraContext(env, weak_this, clazz, camera);
    context->incStrong((void*)android_hardware_Camera_native_setup);
    camera->setListener(context);

    // save context in opaque field
    env->SetLongField(thiz, fields.context, (jlong)context.get());
    return NO_ERROR;
}

android_hardware_Camera_native_setup()方法通過(guò)調(diào)用Camera::connect()方法請(qǐng)求連接CameraService服務(wù)焊切。入?yún)⒅校?/p>

  • clientName是通過(guò)將clientPackageName從jstring轉(zhuǎn)換為String16格式得到扮授;
  • Camera::USE_CALLING_UID是定義在Camera.h中的枚舉類型芳室,其值為ICameraService::USE_CALLING_UID(同樣為枚舉類型,值為-1)刹勃。

Camera::connect()位于Camera.cpp中堪侯,由此進(jìn)入到Library層。

三荔仁、Library:Camera Client和Camera Service

如上述架構(gòu)圖中所示伍宦,ICameraService.h、ICameraClient.h和ICamera.h三個(gè)類定義了Camera的接口和架構(gòu)乏梁,ICameraService.cpp和Camera.cpp兩個(gè)文件用于Camera架構(gòu)的實(shí)現(xiàn)次洼,Camera的具體功能在下層調(diào)用硬件相關(guān)的接口來(lái)實(shí)現(xiàn)。Camera.h是Camera系統(tǒng)對(duì)上層的接口遇骑。

具體的卖毁,Camera類繼承模板類CameraBase,Camera::connect()調(diào)用了CameraBase.cpp中的connect()方法落萎。

sp<Camera> Camera::connect(int cameraId, const String16& clientPackageName,
        int clientUid)
{
    return CameraBaseT::connect(cameraId, clientPackageName, clientUid);
}

CameraBase實(shí)際上又繼承了IBinder的DeathRecipient內(nèi)部類亥啦,DeathRecipient虛擬繼承自RefBase。RefBase是Android中的引用計(jì)數(shù)基礎(chǔ)類练链,其中定義了incStrong翔脱、decStrong、incWeak和decWeak等涉及sp/wp的指針操作函數(shù)兑宇,當(dāng)然這扯遠(yuǎn)了碍侦。

template <typename TCam>
struct CameraTraits {
};

template <typename TCam, typename TCamTraits = CameraTraits<TCam> >
class CameraBase : public IBinder::DeathRecipient
{
public:
    
    static sp<TCam>      connect(int cameraId,
                                 const String16& clientPackageName,
                                 int clientUid);
    ……
}
class DeathRecipient : public virtual RefBase
{
public:
    virtual void binderDied(const wp<IBinder>& who) = 0;
};

回到Camera::connect()的實(shí)現(xiàn)上,其中隶糕,new TCam(cameraId)生成BnCameraClient對(duì)象瓷产,BnCameraClient定義在ICameraClient.h文件中,繼承自模板類BnInterface枚驻。getCameraService()方法返回CameraService的服務(wù)代理BpCameraService濒旦,BpCameraService同樣繼承自模板類BnInterface。然后通過(guò)Binder通信發(fā)送CONNECT命令再登,當(dāng)BnCameraService收到CONNECT命令后調(diào)用CameraService的connect()成員函數(shù)來(lái)做相應(yīng)的處理尔邓。

template <typename TCam, typename TCamTraits>
sp<TCam> CameraBase<TCam, TCamTraits>::connect(int cameraId,
                                               const String16& clientPackageName,
                                               int clientUid)
{
    ALOGV("%s: connect", __FUNCTION__);
    sp<TCam> c = new TCam(cameraId); // BnCameraClient 
    sp<TCamCallbacks> cl = c;
    status_t status = NO_ERROR;
    const sp<ICameraService>& cs = getCameraService(); // BpCameraService

    if (cs != 0) {
        TCamConnectService fnConnectService = TCamTraits::fnConnectService;
        status = (cs.get()->*fnConnectService)(cl, cameraId, clientPackageName, clientUid,
                                             /*out*/ c->mCamera);
    }
    if (status == OK && c->mCamera != 0) {
        c->mCamera->asBinder()->linkToDeath(c);
        c->mStatus = NO_ERROR;
    } else {
        ALOGW("An error occurred while connecting to camera: %d", cameraId);
        c.clear();
    }
    return c;
}
class BnCameraClient: public BnInterface<ICameraClient>
{
public:
    virtual status_t    onTransact( uint32_t code,
                                    const Parcel& data,
                                    Parcel* reply,
                                    uint32_t flags = 0);
};
class BpCameraService: public BpInterface<ICameraService>
{
public:
    BpCameraService(const sp<IBinder>& impl)
        : BpInterface<ICameraService>(impl)
    {
    }
    ……
}

注:connect()函數(shù)在BpCameraService和BnCameraService的父類ICameraService中聲明為純虛函數(shù),在BpCameraService和CameraService中分別給出了實(shí)現(xiàn)锉矢,BpCameraService作為代理類梯嗽,提供接口給客戶端,真正實(shí)現(xiàn)在BnCameraService的子類CameraService中沽损。

在BpCameraService中灯节,connect()函數(shù)實(shí)現(xiàn)如下:

// connect to camera service (android.hardware.Camera)
    virtual status_t connect(const sp<ICameraClient>& cameraClient, int cameraId,
                             const String16 &clientPackageName, int clientUid,
                             /*out*/
                             sp<ICamera>& device)
    {
        Parcel data, reply;
        data.writeInterfaceToken(ICameraService::getInterfaceDescriptor());
        data.writeStrongBinder(cameraClient->asBinder());
        data.writeInt32(cameraId);
        data.writeString16(clientPackageName);
        data.writeInt32(clientUid);
        // BpBinder的transact()函數(shù)向IPCThreadState實(shí)例發(fā)送消息,通知其有消息要發(fā)送給binder driver
        remote()->transact(BnCameraService::CONNECT, data, &reply); 
        if (readExceptionCode(reply)) return -EPROTO;
        status_t status = reply.readInt32();
        if (reply.readInt32() != 0) {
            device = interface_cast<ICamera>(reply.readStrongBinder()); // client端讀出server返回的bind
        }
        return status;
    }

首先將傳遞過(guò)來(lái)的Camera對(duì)象cameraClient轉(zhuǎn)換成IBinder類型,將調(diào)用的參數(shù)寫到Parcel(可理解為Binder通信的管道)中炎疆,通過(guò)BpBinder的transact()函數(shù)發(fā)送消息卡骂,然后由BnCameraService去響應(yīng)該連接,最后就是等待服務(wù)端返回形入,如果成功則生成一個(gè)BpCamera實(shí)例全跨。

真正的服務(wù)端響應(yīng)實(shí)現(xiàn)在BnCameraService的onTransact()函數(shù)中,其負(fù)責(zé)解包收到的Parcel并執(zhí)行client端的請(qǐng)求的方法亿遂。

status_t BnCameraService::onTransact(
    uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
    switch(code) {
        ……
     case CONNECT: {
            CHECK_INTERFACE(ICameraService, data, reply);
            sp<ICameraClient> cameraClient =
                    interface_cast<ICameraClient>(data.readStrongBinder()); // 使用Camera的Binder對(duì)象生成Camera客戶代理BpCameraClient實(shí)例
              int32_t cameraId = data.readInt32();
            const String16 clientName = data.readString16();
            int32_t clientUid = data.readInt32();
            sp<ICamera> camera;
            status_t status = connect(cameraClient, cameraId,
                    clientName, clientUid, /*out*/camera); // 將生成的BpCameraClient對(duì)象作為參數(shù)傳遞到CameraService的connect()函數(shù)中
              reply->writeNoException();
            reply->writeInt32(status); // 將BpCamera對(duì)象以IBinder的形式打包到Parcel中返回
              if (camera != NULL) {
                reply->writeInt32(1);
                reply->writeStrongBinder(camera->asBinder());
            } else {
                reply->writeInt32(0);
            }
            return NO_ERROR;
        } break;
    ……
    }
}

主要的處理包括:

  1. 通過(guò)data中Camera的Binder對(duì)象生成Camera客戶代理BpCameraClient實(shí)例浓若;
  2. 將生成的BpCameraClient對(duì)象作為參數(shù)傳遞到CameraService(/frameworks/av/services/camera /libcameraservice/CameraService.cpp)的connect()函數(shù)中,該函數(shù)會(huì)返回一個(gè)BpCamera實(shí)例崩掘;
  3. 將在上述實(shí)例對(duì)象以IBinder的形式打包到Parcel中返回七嫌。

最后,BpCamera實(shí)例是通過(guò)CameraService::connect()函數(shù)返回的苞慢。CameraService::connect()實(shí)現(xiàn)的核心是調(diào)用connectHelperLocked()函數(shù)根據(jù)HAL不同API的版本創(chuàng)建不同的client實(shí)例(早期版本中好像沒(méi)有connectHelperLocked()這個(gè)函數(shù)诵原,但功能基本相似)。

status_t CameraService::connectHelperLocked(
        /*out*/
        sp<Client>& client,
        /*in*/
        const sp<ICameraClient>& cameraClient,
        int cameraId,
        const String16& clientPackageName,
        int clientUid,
        int callingPid,
        int halVersion,
        bool legacyMode) {

    int facing = -1;
    int deviceVersion = getDeviceVersion(cameraId, &facing);

    if (halVersion < 0 || halVersion == deviceVersion) {
        // Default path: HAL version is unspecified by caller, create CameraClient
        // based on device version reported by the HAL.
        switch(deviceVersion) {
          case CAMERA_DEVICE_API_VERSION_1_0:
            client = new CameraClient(this, cameraClient,
                    clientPackageName, cameraId,
                    facing, callingPid, clientUid, getpid(), legacyMode);
            break;
          case CAMERA_DEVICE_API_VERSION_2_0:
          case CAMERA_DEVICE_API_VERSION_2_1:
          case CAMERA_DEVICE_API_VERSION_3_0:
          case CAMERA_DEVICE_API_VERSION_3_1:
          case CAMERA_DEVICE_API_VERSION_3_2:
            client = new Camera2Client(this, cameraClient,
                    clientPackageName, cameraId,
                    facing, callingPid, clientUid, getpid(), legacyMode);
            break;
          case -1:
            ALOGE("Invalid camera id %d", cameraId);
            return BAD_VALUE;
          default:
            ALOGE("Unknown camera device HAL version: %d", deviceVersion);
            return INVALID_OPERATION;
        }
    } else {
        // A particular HAL version is requested by caller. Create CameraClient
        // based on the requested HAL version.
        if (deviceVersion > CAMERA_DEVICE_API_VERSION_1_0 &&
            halVersion == CAMERA_DEVICE_API_VERSION_1_0) {
            // Only support higher HAL version device opened as HAL1.0 device.
            client = new CameraClient(this, cameraClient,
                    clientPackageName, cameraId,
                    facing, callingPid, clientUid, getpid(), legacyMode);
        } else {
            // Other combinations (e.g. HAL3.x open as HAL2.x) are not supported yet.
            ALOGE("Invalid camera HAL version %x: HAL %x device can only be"
                    " opened as HAL %x device", halVersion, deviceVersion,
                    CAMERA_DEVICE_API_VERSION_1_0);
            return INVALID_OPERATION;
        }
    }

    status_t status = connectFinishUnsafe(client, client->getRemote());
    if (status != OK) {
        // this is probably not recoverable.. maybe the client can try again
        return status;
    }

    mClient[cameraId] = client;
    LOG1("CameraService::connect X (id %d, this pid is %d)", cameraId,
         getpid());

    return OK;
}

可見挽放,在CAMERA_DEVICE_API_VERSION_2_0之前使用CameraClient進(jìn)行實(shí)例化绍赛,之后則采用Camera2Client進(jìn)行實(shí)例化。以CameraClient為例辑畦,其initialize()函數(shù)如下:

status_t CameraClient::initialize(camera_module_t *module) {
    int callingPid = getCallingPid();
    status_t res;

    LOG1("CameraClient::initialize E (pid %d, id %d)", callingPid, mCameraId);

    // Verify ops permissions
    res = startCameraOps();
    if (res != OK) {
        return res;
    }

    char camera_device_name[10];
    snprintf(camera_device_name, sizeof(camera_device_name), "%d", mCameraId);

    mHardware = new CameraHardwareInterface(camera_device_name);
    res = mHardware->initialize(&module->common);
    if (res != OK) {
        ALOGE("%s: Camera %d: unable to initialize device: %s (%d)",
                __FUNCTION__, mCameraId, strerror(-res), res);
        mHardware.clear();
        return res;
    }

    mHardware->setCallbacks(notifyCallback,
            dataCallback,
            dataCallbackTimestamp,
            (void *)(uintptr_t)mCameraId);

    // Enable zoom, error, focus, and metadata messages by default
    enableMsgType(CAMERA_MSG_ERROR | CAMERA_MSG_ZOOM | CAMERA_MSG_FOCUS |
                  CAMERA_MSG_PREVIEW_METADATA | CAMERA_MSG_FOCUS_MOVE);

    LOG1("CameraClient::initialize X (pid %d, id %d)", callingPid, mCameraId);
    return OK;
}

上述函數(shù)中吗蚌,主要注意以下流程:

加粗的代碼CameraHardwareInterface新建了了一個(gè)Camera硬件接口,當(dāng)然纯出,camera_device_name為攝像頭設(shè)備名蚯妇;

  1. mHardware->initialize(&module->common)調(diào)用底層硬件的初始化方法;
  2. mHardware->setCallbacks將CamerService處的回調(diào)函數(shù)注冊(cè)到HAL處暂筝。
  3. CameraHardwareInterface定義了Camera的硬件抽象特征箩言,由此進(jìn)入到HAL。

四焕襟、HAL:CameraHardwareInterface

CameraHardwareInterface的作用在于鏈接Camera Server和V4L2陨收,通過(guò)實(shí)現(xiàn)CameraHardwareInterface可以屏蔽不同的driver對(duì)Camera Server的影響。CameraHardwareInterface同樣虛擬繼承自RefBase鸵赖。

class CameraHardwareInterface : public virtual RefBase {
public:
    CameraHardwareInterface(const char *name)
    {
        mDevice = 0;
        mName = name;
    }
    ……
}

CameraHardwareInterface中包含了控制通道和數(shù)據(jù)通道务漩,控制通道用于處理預(yù)覽和視頻獲取的開始/停止、拍攝照片它褪、自動(dòng)對(duì)焦等功能饵骨,數(shù)據(jù)通道通過(guò)回調(diào)函數(shù)來(lái)獲得預(yù)覽、視頻錄制茫打、自動(dòng)對(duì)焦等數(shù)據(jù)宏悦。當(dāng)需要支持新的硬件時(shí)就需要繼承于CameraHardwareInterface 镐确,來(lái)實(shí)現(xiàn)對(duì)應(yīng)的功能包吝。CameraHardwareInterface提供的public方法如下:

CameraHardwareInterface

在前一節(jié)中饼煞,initialize()函數(shù)調(diào)用了mHardware->initialize和mHardware->setCallbacks,下面來(lái)看下CameraHardwareInterface.h對(duì)其的實(shí)現(xiàn)诗越。

status_t initialize(hw_module_t *module)
    {
        ALOGI("Opening camera %s", mName.string());
        camera_module_t *cameraModule = reinterpret_cast<camera_module_t *>(module);
        camera_info info;
        status_t res = cameraModule->get_camera_info(atoi(mName.string()), &info);
        if (res != OK) return res;

        int rc = OK;
        if (module->module_api_version >= CAMERA_MODULE_API_VERSION_2_3 &&
            info.device_version > CAMERA_DEVICE_API_VERSION_1_0) {
            // Open higher version camera device as HAL1.0 device.
            rc = cameraModule->open_legacy(module, mName.string(),
                                               CAMERA_DEVICE_API_VERSION_1_0,
                                               (hw_device_t **)&mDevice);
        } else {
            rc = CameraService::filterOpenErrorCode(module->methods->open(
                module, mName.string(), (hw_device_t **)&mDevice));
        }
        if (rc != OK) {
            ALOGE("Could not open camera %s: %d", mName.string(), rc);
            return rc;
        }
        initHalPreviewWindow();
        return rc;
    }

在initialize()方法中砖瞧,通過(guò)cameraModule->open_legacy打開攝像頭模組,initHalPreviewWindow()用于初始化Preview的相關(guān)流opspreview_stream_ops嚷狞,初始化hal的預(yù)覽窗口块促。

void initHalPreviewWindow()
    {
        mHalPreviewWindow.nw.cancel_buffer = __cancel_buffer;
        mHalPreviewWindow.nw.lock_buffer = __lock_buffer;
        mHalPreviewWindow.nw.dequeue_buffer = __dequeue_buffer;
        mHalPreviewWindow.nw.enqueue_buffer = __enqueue_buffer;
        mHalPreviewWindow.nw.set_buffer_count = __set_buffer_count;
        mHalPreviewWindow.nw.set_buffers_geometry = __set_buffers_geometry;
        mHalPreviewWindow.nw.set_crop = __set_crop;
        mHalPreviewWindow.nw.set_timestamp = __set_timestamp;
        mHalPreviewWindow.nw.set_usage = __set_usage;
        mHalPreviewWindow.nw.set_swap_interval = __set_swap_interval;

        mHalPreviewWindow.nw.get_min_undequeued_buffer_count =
                __get_min_undequeued_buffer_count;
    }
/** Set the notification and data callbacks */
    void setCallbacks(notify_callback notify_cb,
                      data_callback data_cb,
                      data_callback_timestamp data_cb_timestamp,
                      void* user)
    {
        mNotifyCb = notify_cb;
        mDataCb = data_cb;
        mDataCbTimestamp = data_cb_timestamp;
        mCbUser = user;

        ALOGV("%s(%s)", __FUNCTION__, mName.string());

        if (mDevice->ops->set_callbacks) {
            mDevice->ops->set_callbacks(mDevice,
                                   __notify_cb,
                                   __data_cb,
                                   __data_cb_timestamp,
                                   __get_memory,
                                   this);
        }
    }

set_callbacks中,__notify_cb床未、__data_cb竭翠、__data_cb_timestamp和__get_memory分別消息回調(diào),數(shù)據(jù)回調(diào)薇搁,時(shí)間戳回調(diào)斋扰,以及內(nèi)存相關(guān)操作的回調(diào)。

以上通過(guò)簡(jiǎn)略分析應(yīng)用層調(diào)用Camera.open()之后在Framework啃洋、ART传货、Library以及HAL層的響應(yīng),來(lái)說(shuō)明Android中Camera系統(tǒng)的整體架構(gòu)宏娄,希望對(duì)讀者能有一定的幫助问裕。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市孵坚,隨后出現(xiàn)的幾起案子粮宛,更是在濱河造成了極大的恐慌,老刑警劉巖卖宠,帶你破解...
    沈念sama閱讀 211,042評(píng)論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件巍杈,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡逗堵,警方通過(guò)查閱死者的電腦和手機(jī)秉氧,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 89,996評(píng)論 2 384
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)蜒秤,“玉大人汁咏,你說(shuō)我怎么就攤上這事∽髅模” “怎么了攘滩?”我有些...
    開封第一講書人閱讀 156,674評(píng)論 0 345
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)纸泡。 經(jīng)常有香客問(wèn)我漂问,道長(zhǎng),這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,340評(píng)論 1 283
  • 正文 為了忘掉前任蚤假,我火速辦了婚禮栏饮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘磷仰。我一直安慰自己袍嬉,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,404評(píng)論 5 384
  • 文/花漫 我一把揭開白布灶平。 她就那樣靜靜地躺著伺通,像睡著了一般。 火紅的嫁衣襯著肌膚如雪逢享。 梳的紋絲不亂的頭發(fā)上罐监,一...
    開封第一講書人閱讀 49,749評(píng)論 1 289
  • 那天,我揣著相機(jī)與錄音瞒爬,去河邊找鬼弓柱。 笑死,一個(gè)胖子當(dāng)著我的面吹牛疮鲫,可吹牛的內(nèi)容都是我干的吆你。 我是一名探鬼主播,決...
    沈念sama閱讀 38,902評(píng)論 3 405
  • 文/蒼蘭香墨 我猛地睜開眼俊犯,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼妇多!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起燕侠,我...
    開封第一講書人閱讀 37,662評(píng)論 0 266
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤者祖,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后绢彤,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體七问,經(jīng)...
    沈念sama閱讀 44,110評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,451評(píng)論 2 325
  • 正文 我和宋清朗相戀三年茫舶,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了械巡。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,577評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡饶氏,死狀恐怖讥耗,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情疹启,我是刑警寧澤古程,帶...
    沈念sama閱讀 34,258評(píng)論 4 328
  • 正文 年R本政府宣布,位于F島的核電站喊崖,受9級(jí)特大地震影響挣磨,放射性物質(zhì)發(fā)生泄漏雇逞。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,848評(píng)論 3 312
  • 文/蒙蒙 一茁裙、第九天 我趴在偏房一處隱蔽的房頂上張望塘砸。 院中可真熱鬧,春花似錦呜达、人聲如沸谣蠢。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,726評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至挤忙,卻和暖如春霜威,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背册烈。 一陣腳步聲響...
    開封第一講書人閱讀 31,952評(píng)論 1 264
  • 我被黑心中介騙來(lái)泰國(guó)打工戈泼, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人赏僧。 一個(gè)月前我還...
    沈念sama閱讀 46,271評(píng)論 2 360
  • 正文 我出身青樓大猛,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親淀零。 傳聞我的和親對(duì)象是個(gè)殘疾皇子挽绩,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,452評(píng)論 2 348

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