視頻錄制和自定義拍照

最近在學習視頻錄制方面的東西,在網上找了篇博客,寫的非常詳細,這里是對這篇文章的學習

詞匯介紹

  • AVCaptureSession: 媒體(音頻、視頻)捕捉會話,負責把捕捉的音視頻數據輸出到輸出設備,一個捕捉會話可以有多個輸入輸出
  • AVCaptureDevice: 輸入設備 包括攝像頭、話筒等,通過該對象可以設置物理設備的屬性(相機的聚焦白平衡等)
  • AVCaptureDeviceInput: 輸入數據管理對象,可以根據AVCaptureDevice創建對應的AVCaptureDeviceInput對象,該對象將會被添加到AVCaptureSession中管理
  • AVCaptureOutput:輸出數據管理對象,用于接受各類輸出數據,通常使用其子類AVCaptureAudioDataOutput、AVCaptureStillImageOutput、AVCaptureVideoDataOutput、AVCaptureFileOutput,該對象將會被添加到AVCaptureSession中管理。注意:前面幾個對象的輸出數據都是NSData類型,而AVCaptureFileOutput代表數據以文件形式輸出,類似的,AVCcaptureFileOutput也不會直接創建使用,通常會使用其子類:AVCaptureAudioFileOutput、AVCaptureMovieFileOutput。當把一個輸入或者輸出添加到AVCaptureSession
  • AVCaptrueVideoPreviewLayer: 相機拍攝預覽圖層,是CAPlayer的子類,使用該對象可以實時查看拍攝和視頻錄制的效果,創建該對象需要指定對應的AVCaptureSession對象

使用AVFoundation框架實現拍照和視頻錄制的一般步驟

  1. 創建AVCaptureSession對象
  2. 使用AVCaptureDevice靜態方法獲得所需的設備,例如拍照和視頻就需要獲取攝像頭設備,錄音就需要獲取話筒設備
  3. 利用輸入設備AVCaptureDevice創建AVCaptureDeviceInput對象
  4. 初始化數據輸出管理對象,如果要拍照就初始化AVCaptureStillImageOutput對象,如果要錄制視頻就初始化AVCaptureMovieFileOutput對象
  5. 將數據輸入對象(AVCaptureDeviceInput)、數據輸出對象(AVCaptureOutput)添加進媒體會話AVCaptureSession中
  6. 創建視頻預覽圖層AVCaptureVideoPreviewLayer并指定媒體會話,添加圖層到顯示容器中,并調用AVCaptureSession的startRunning方法開始捕捉
  7. 將捕獲的音頻或者視頻保存到指定文件

自定義拍照

我們將實現攝像頭預覽,攝像頭切換,閃光燈設置,對焦,拍照保存等功能

- (void)viewWillAppear:(BOOL)animated {
    [super viewWillAppear:animated];
    
    //1.初始化捕捉會話
    //1.1.初始化
    _session = [[AVCaptureSession alloc] init];
    //1.2.設置分辨率
    if ([_session canSetSessionPreset:AVCaptureSessionPreset1280x720]) {
        [_session setSessionPreset:AVCaptureSessionPreset1280x720];
    }
    
    //2.獲得輸入設備 后置攝像頭
    AVCaptureDevice *captureDevice = [self getCameraDeviceWithPosition:AVCaptureDevicePositionBack];
    if (captureDevice == nil) {
        NSLog(@"獲取后置攝像頭失敗");
        return;
    }
    NSError *error = nil;
    //3.根據輸入設備創建輸入數據管理對象
    AVCaptureDeviceInput *captureInput = [[AVCaptureDeviceInput alloc] initWithDevice:captureDevice error:&error];
    self.captureDeviceInput = captureInput;
    if (error) {
        NSLog(@"取得設備輸入對象時出錯,%@", error.localizedDescription);
        return;
    }
    
    //4.創建輸出數據管理對象 用于獲得輸出數據
    AVCaptureStillImageOutput *imageOutput = [[AVCaptureStillImageOutput alloc] init];
    NSDictionary *outputSettings = @{AVVideoCodecKey:AVVideoCodecJPEG};
    [imageOutput setOutputSettings:outputSettings];//輸出設置
    self.imageOutput = imageOutput;
    
    //5.添加輸入設備管理對象到捕捉會話
    if ([_session canAddInput:_captureDeviceInput]) {
        [_session addInput:_captureDeviceInput];
    }
    
    //6.添加輸出源
    if ([_session canAddOutput:_imageOutput]) {
        [_session addOutput:_imageOutput];
    }
    
    //7.設置預覽圖層
    _previewLayer = [[AVCaptureVideoPreviewLayer alloc] initWithSession:_session];
    _previewLayer.videoGravity=AVLayerVideoGravityResizeAspectFill;//填充模式
    _previewLayer.frame = self.view.bounds;
    [self.view.layer insertSublayer:_previewLayer atIndex:0];
    
    //8.給設備添加通知 監測監控區域的變化
    [self addNotificationToCaptureDevice:captureDevice];
    
    //9.添加手勢
    [self addGestureToView];
}



viewWillApper:方法里面創建媒體捕捉會話,并添加輸入源、輸出源,添加對輸入設備的通知,監測設備監控區域的變化(拍照對準的區域發生變化等等),添加手勢來聚焦和調整光標位置,在viewDidAppear:方法中開始會話捕捉,在 viewDidDisappear:中停止會話捕捉

- (void)viewDidAppear:(BOOL)animated {
    [super viewDidAppear:animated];
    
    [_session startRunning];
}
- (void)viewDidDisappear:(BOOL)animated {
    [super viewDidDisappear:animated];
    [_session stopRunning];
}

定義閃光燈開閉及自動模式功能,注意無論是設置閃光燈、白平衡還是其他輸入設備屬性,在設置之前必須先鎖定配置,修改完后解鎖。

/* 定義閃光燈開閉及自動模式功能,注意無論是設置閃光燈、白平衡還是其他輸入設備屬性,在設置之前必須先鎖定配置,修改完后解鎖。 */
/* 改變設備屬性 進行的是鎖住設備操作 通過block返回輸入設備 */
- (void)changeDeviceProperty:(PropertyChangeBlock)block {
    //1.獲得設備
    AVCaptureDevice *device = self.captureDeviceInput.device;
    NSError *error;
    //2.鎖住設備
    BOOL success = [device lockForConfiguration:&error];
    if (success) {
        //1.鎖定成功 通過block返回輸入設備
        block(device);
        //2.解鎖
        [device unlockForConfiguration];
    }
    else {
        NSLog(@"設置設備屬性過程發生錯誤,錯誤信息%@", error.localizedDescription);
    }
    
}

添加通知的方法

- (void)addNotificationToCaptureDevice:(AVCaptureDevice *)device {
    //1.先鎖住輸入設備
    [self changeDeviceProperty:^(AVCaptureDevice *device) {
        //添加區域改變捕獲通知必須首先設置設備允許捕獲
        //表明接收方是否應該監控領域的變化(如照明變化,實質移動等) 可以通過AVCaptureDeviceSubjectAreaDidChangeNotification通知監測 我們可以希望重新聚焦,調整曝光白平衡等的主題區域 在設置該屬性之前必須調用lockForConfiguration方法鎖定設備配置
        device.subjectAreaChangeMonitoringEnabled = YES;
    }];
    
    //2.監測通知
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(areaChanged:) name:AVCaptureDeviceSubjectAreaDidChangeNotification object:device];
    
}

在通知方法里打印下log

#pragma mark -設備捕獲區域發生變化
- (void)areaChanged:(NSNotification *)notification {
       NSLog(@"捕獲區域改變...");
}

移除通知的方法

/* 移除監控輸入設備通知 */
- (void)removeNotificationFromCaptureDevice:(AVCaptureDevice *)device {
    [[NSNotificationCenter defaultCenter] removeObserver:self name:AVCaptureDeviceSubjectAreaDidChangeNotification object:device];
}

添加手勢


- (void)addGestureToView {    
 UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(tapScreen:)];
    [self.view addGestureRecognizer:tap];
}
-(void)tapScreen:(UITapGestureRecognizer *)tapGesture {
    CGPoint point = [tapGesture locationInView:self.view];
    //UI坐標轉換成攝像頭坐標
    CGPoint cameraPoint = [self.previewLayer captureDevicePointOfInterestForPoint:point];
    [self setFocusPoint:cameraPoint];
    
    [self focusWithMode:AVCaptureFocusModeAutoFocus exposureMode:AVCaptureExposureModeAutoExpose atPoint:cameraPoint];
}

在手勢方法里面設置光標位置(光標是一個imageView),并設置攝像頭的聚焦模式和曝光模式

設置光標位置的方法

/* 設置光標位置 */
- (void)setFocusPoint:(CGPoint)point {
    self.imageView.center = point;
    
    self.imageView.transform = CGAffineTransformMakeScale(1.5, 1.5);
    self.imageView.alpha = 1;
    
    [UIView animateWithDuration:1.0 animations:^{
        self.imageView.transform = CGAffineTransformIdentity;
    } completion:^(BOOL finished) {
        self.imageView.alpha = 0;
    }];
    
}

設置聚焦模式和曝光模式的方法

/* s設置聚焦和曝光模式 */
- (void)focusWithMode:(AVCaptureFocusMode)focusMode
         exposureMode:(AVCaptureExposureMode)exposeMode
              atPoint:(CGPoint)point
{
    //設置曝光模式和聚焦模式 先鎖住輸入設置
    [self changeDeviceProperty:^(AVCaptureDevice *device) {
        if ([device isFocusModeSupported:focusMode]) {
            [device setFocusMode:focusMode];
        }
        
        if ([device isExposureModeSupported:exposeMode]) {
            [device setExposureMode:exposeMode];
        }
        
        if ([device isFocusPointOfInterestSupported]) {
            [device setFocusPointOfInterest:point];
        }
        
        if ([device isExposurePointOfInterestSupported]) {
            [device setExposurePointOfInterest:point];
        }
        
    }];
}

拍照的方法

#pragma mark -拍照
- (IBAction)takePhoto:(id)sender {
    //1.根據數據輸出管理對象(輸出源)獲得鏈接
    AVCaptureConnection *connection = [self.imageOutput connectionWithMediaType:AVMediaTypeVideo];
    //2.根據連接取得輸出數據
    [self.imageOutput captureStillImageAsynchronouslyFromConnection:connection completionHandler:^(CMSampleBufferRef imageDataSampleBuffer, NSError *error) {
        //獲取圖像數據
        NSData *imageData=[AVCaptureStillImageOutput jpegStillImageNSDataRepresentation:imageDataSampleBuffer];
        UIImage *image=[UIImage imageWithData:imageData];
        //存入相冊
        UIImageWriteToSavedPhotosAlbum(image, nil, nil, nil);
    }];
}

切換攝像頭

切換攝像頭就是移除原有的輸入源,添加新的輸入源

#pragma mark -切換攝像頭
/* 切換攝像頭的過程就是將原有的輸入源移除 添加新的輸入源到會話中 */
- (IBAction)switchCamera:(id)sender {
    //1.獲取原來的輸入設備 根據數據輸入管理對象獲取
    AVCaptureDevice *oldCaptureDevice = [self.captureDeviceInput device];
    //2.移除輸入設備的通知
    [self removeNotificationFromCaptureDevice:oldCaptureDevice];
    
    //3.切換攝像頭的位置
    //3.1.獲取當前的位置
    AVCaptureDevicePosition currentPosition = oldCaptureDevice.position;
    //3.2.獲取要切換的位置
    AVCaptureDevicePosition targetPosition = AVCaptureDevicePositionFront;
    if (currentPosition == AVCaptureDevicePositionFront || AVCaptureDevicePositionUnspecified) {
        targetPosition = AVCaptureDevicePositionBack;
    }
    
    //4.根據攝像頭的位置獲取當前的輸入設備
    AVCaptureDevice *currentCaptureDevice = [self getCameraDeviceWithPosition:targetPosition];
    
    //5.添加對當前輸入設備的通知
    [self addNotificationToCaptureDevice:currentCaptureDevice];
    
    //6.創建當前設備的數據輸入管理對象
    AVCaptureDeviceInput *currentInput = [[AVCaptureDeviceInput alloc] initWithDevice:currentCaptureDevice error:nil];
    
    //7.添加新的數據管理對象到捕捉會話
    //7.1.開始設置
    [_session beginConfiguration];
    //7.2.移除原有的輸入源
    [_session removeInput:self.captureDeviceInput];
    
    //7.3.添加新的輸入源
    if ([_session canAddInput:currentInput]) {
        [_session addInput:currentInput];
        //.標記當前的輸入源
        self.captureDeviceInput = currentInput;
    }
    
    
    //7.4.提交設置
    [_session commitConfiguration];
}

根據攝像頭的位置(前置/后置)創建輸入設備

/* 根據攝像頭位置來獲取攝像頭 */
- (AVCaptureDevice *)getCameraDeviceWithPosition:(AVCaptureDevicePosition)position {
    NSArray *cameras = [AVCaptureDevice devicesWithMediaType:AVMediaTypeVideo];
    for (AVCaptureDevice *device in cameras) {
        if (device.position == position) {
            return device;
        }
    }
    return nil;
}

需要說明的是在beginConfiguration方法需要和commitConfiguration方法配套使用,我們可以在這之間可以添加或刪除輸出,更改sessionPreset或配置單個AVCaptureInput或Output屬性

這里基本上就已經實現了拍照功能,還有一些就是設置閃光燈的模式了
這里閃光模式一共有三種


typedef NS_ENUM(NSInteger, AVCaptureFlashMode) {
    AVCaptureFlashModeOff  = 0,
    AVCaptureFlashModeOn   = 1,
    AVCaptureFlashModeAuto = 2
} NS_AVAILABLE(10_7, 4_0) __TVOS_PROHIBITED;

設置閃光模式

#pragma mark - 設置閃光燈模式
- (void)setFlashMode:(AVCaptureFlashMode)mode {
    //先鎖住設備
    [self changeDeviceProperty:^(AVCaptureDevice *device) {
        if ([device isFlashModeSupported:mode]) {//如果支持該模式
            [device setFlashMode:mode];
        }
    }];
}

大致效果為

拍照.gif

錄制視頻

錄制視頻跟拍照大致差不多,比拍照要多一個麥克風的數據輸入管理對象(麥克風輸入源),拍照的話是創建AVCaptureStillImageOutput類型的輸出緣,錄制視頻的話是AVCaptureMovieFileOutput類型

- (void)viewWillAppear:(BOOL)animated {
    [super viewWillAppear:animated];
    //初始化捕捉會話
    _session = [[AVCaptureSession alloc] init];
    if ([_session canSetSessionPreset:AVCaptureSessionPreset1280x720]) {
        [_session setSessionPreset:AVCaptureSessionPreset1280x720];
    }
    
    //獲得相機輸入設備
    AVCaptureDevice *cameraDevice = [self getCameraDeviceWithPosition:AVCaptureDevicePositionBack];
    if (cameraDevice == nil) {
        NSLog(@"獲取后置攝像頭失敗");
        return;
    }
    
    //根據相機輸入設備創建相機輸入源
    NSError *error = nil;
    _cameraDeviceInput = [AVCaptureDeviceInput deviceInputWithDevice:cameraDevice error:&error];
    if (error) {
        NSLog(@"%@", error.localizedDescription);
        return;
    }
    
    //獲得話筒輸入設備
    AVCaptureDevice *audioDevice = [AVCaptureDevice devicesWithMediaType:AVMediaTypeAudio].firstObject;
    //創建話筒輸入源
    _audioDeviceInput = [AVCaptureDeviceInput deviceInputWithDevice:audioDevice error:nil];
    
    //創建數據輸出管理對象
    _movieFileOutput = [[AVCaptureMovieFileOutput alloc] init];
    
    //添加輸入源
    if ([_session canAddInput:_cameraDeviceInput]) {
        [_session addInput:_cameraDeviceInput];
    }
    AVCaptureConnection *connection = [_movieFileOutput connectionWithMediaType:AVMediaTypeVideo];
    if ([connection isVideoStabilizationSupported]) {
        
        connection.preferredVideoStabilizationMode=AVCaptureVideoStabilizationModeAuto;//通過將preferredVideoStabilizationMode屬性設置為AVCaptureVideoStabilizationModeOff以外的值,當模式可用時,流經接收器的視頻會穩定
    }
    
    if ([_session canAddInput:_audioDeviceInput]) {
        [_session addInput:_audioDeviceInput];
    }
    
    //添加輸出源
    if ([_session canAddOutput:_movieFileOutput]) {
        [_session addOutput:_movieFileOutput];
    }
    //創建預覽圖層
    _previewLayer = [[AVCaptureVideoPreviewLayer alloc] initWithSession:_session];
    _previewLayer.frame = self.view.bounds;
    _previewLayer.videoGravity=AVLayerVideoGravityResizeAspectFill;//填充模式
    
    [self.view.layer insertSublayer:_previewLayer atIndex:0];
    
}


開始錄制視頻

- (IBAction)startRecording:(UIButton *)sender {
   
   if ([self.movieFileOutput isRecording]) {
       [self.movieFileOutput stopRecording];
       sender.selected = YES;
       return;
   }
   
   //獲得連接
   AVCaptureConnection *connection = [self.movieFileOutput connectionWithMediaType:AVMediaTypeVideo];
   connection.videoOrientation = self.previewLayer.connection.videoOrientation;
   
   NSString *filePath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES).lastObject stringByAppendingPathComponent:@"myVideo.mp4"];
   NSURL *url = [NSURL fileURLWithPath:filePath];
   //開始錄制 并設置代理
   [self.movieFileOutput startRecordingToOutputFileURL:url recordingDelegate:self];
}

遵守AVCaptureFileOutputRecordingDelegate協議并實現代理方法

下面這個方法是必須實現的

#pragma mark - AVCaptureFileOutputRecordingDelegate
- (void)captureOutput:(AVCaptureFileOutput *)captureOutput didFinishRecordingToOutputFileAtURL:(NSURL *)outputFileURL fromConnections:(NSArray *)connections error:(NSError *)error
{
    NSLog(@"視頻錄制完成");
    //將視頻存入到相簿
    ALAssetsLibrary *assetsLibrary=[[ALAssetsLibrary alloc]init];
    [assetsLibrary writeVideoAtPathToSavedPhotosAlbum:outputFileURL completionBlock:^(NSURL *assetURL, NSError *error) {
        if (error) {
            NSLog(@"保存視頻到相簿過程中發生錯誤,錯誤信息:%@",error.localizedDescription);
        }
        
        NSLog(@"成功保存視頻到相簿.");
    }];
}

官方文檔是這么介紹該方法的

This method is called when the file output has finished writing all data to a file whose recording was stopped, either because startRecordingToOutputFileURL:recordingDelegate: or stopRecording were called, or because an error, described by the error parameter, occurred (if no error occurred, the error parameter will be nil). This method will always be called for each recording request, even if no data is successfully written to the file.

大致意思是

當文件輸出已完成將所有數據寫入記錄已停止的文件時,或者因為調用了startRecordingToOutputFileURL:recordingDelegate:或stopRecording,或者因為發生了由錯誤參數描述的錯誤(如果沒有發生錯誤, 錯誤參數將為nil)。 即使沒有數據成功寫入文件,也會為每個記錄請求調用此方法。

開始錄制時的代理方法

- (void)captureOutput:(AVCaptureFileOutput *)captureOutput didStartRecordingToOutputFileAtURL:(NSURL *)fileURL fromConnections:(NSArray *)connections
{
    NSLog(@"開始錄制視頻");
}

切換攝像頭的方法

- (IBAction)switchCamera:(id)sender {
    //1.獲得原來的輸入設備
    AVCaptureDevice *oldCaptureDevice = [self.cameraDeviceInput device];
    //2.移除原來輸入設備的通知
    [self removeNotificationFromDevice:oldCaptureDevice];
    //3.獲得現在的輸入設備
    //3.1.獲得原來的設備的位置
    AVCaptureDevicePosition oldPosition = oldCaptureDevice.position;
    //3.2.獲得現在的設備的位置
    AVCaptureDevicePosition currentPosition = AVCaptureDevicePositionFront;
    if (oldPosition == AVCaptureDevicePositionFront || oldPosition == AVCaptureDevicePositionUnspecified) {
        currentPosition = AVCaptureDevicePositionBack;
    }
    //3.3.根據位置創建當前的輸入設備
    AVCaptureDevice *currnetCaptureDevice = [self getCameraDeviceWithPosition:currentPosition];
    //3.4.給當前設備添加通知
    [self addNotificationToCaptureDevice:currnetCaptureDevice];
    
    //4.根據現在的輸入設備創建輸入源
    NSError *error = nil;
    AVCaptureDeviceInput *currentInput = [AVCaptureDeviceInput deviceInputWithDevice:currnetCaptureDevice error:&error];
    if (error) {
        NSLog(@"%@",error.localizedDescription);
        return;
    }
    
    //5.更換輸入源
    //5.1.開啟設置
    [_session beginConfiguration];
    //5.2.移除原來的輸入源
    [_session removeInput:self.cameraDeviceInput];
    //5.3.添加現在的輸入源
    if ([_session canAddInput:currentInput]) {
        [_session addInput:currentInput];
        self.cameraDeviceInput = currentInput;
    }
    //5.4.提交設置
    [_session commitConfiguration];
}

可以看出跟拍照的切換是一致的

大致效果

視頻.gif

還有一點需要注意的是因為這里調用了相機和話筒設備,所以需要在info.plist中添加相應的字段

CCF99CA8-86F7-4721-A89C-9A3F7986CD74.png

代碼地址:點擊這里

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,461評論 6 532
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,538評論 3 417
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,423評論 0 375
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,991評論 1 312
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,761評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,207評論 1 324
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,268評論 3 441
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,419評論 0 288
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,959評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,782評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,983評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,528評論 5 359
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,222評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,653評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,901評論 1 286
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,678評論 3 392
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,978評論 2 374

推薦閱讀更多精彩內容