iOS三種錄制視頻方式詳細(xì)對(duì)比

先附上參考資料

http://www.lxweimin.com/p/16cb14f53933

https://developer.apple.com/library/content/samplecode/AVSimpleEditoriOS/Introduction/Intro.html

https://github.com/objcio/VideoCaptureDemo

https://github.com/gsixxxx/DTSmallVideo

https://github.com/AndyFightting/VideoRecord

卷首吐槽語(yǔ)

這還是第一次接觸自定義界面錄制視頻,包括各種參數(shù)的設(shè)置,不得不說,錄制視頻這塊,各種類,各種方法,蠻復(fù)雜的,網(wǎng)上的資料也是各種雜亂,想要弄清楚還真是得費(fèi)一番功夫,我參考了大量資料,根據(jù)自己的思路整理了一遍,按照我的思路來,保證你看一遍就會(huì),我這里只是簡(jiǎn)單的錄制,壓縮,剪裁,導(dǎo)出等功能,不設(shè)計(jì)濾鏡,添加背景音樂,合并,字幕等等,重要的是這個(gè)流程,主流程會(huì)了,其他也就是錦上添花了。

先附上dome demo地址

我的blog看更加方便,左側(cè)有目錄
點(diǎn)擊進(jìn)入我的blog文章地址

腦圖

方便大家對(duì)三中錄制方式有一個(gè)大概的了解,看一下這張圖片。


基本屬性與類
基本屬性與類

第一種采用系統(tǒng)的錄制較為簡(jiǎn)單,詳細(xì)介紹后面兩種。

效果圖

1
1

2
2

3
3
4
4
5
5

6
6

demo中把三種方式單獨(dú)分開,便于學(xué)習(xí)。支持閃光燈,切換鏡頭,錄制不同尺寸的視頻等。

1.UIImagePickerController

這種方式只能設(shè)置一些簡(jiǎn)單參數(shù),自定義程度不高,只能自定義界面上的操作按鈕,還有視頻的畫質(zhì)等。

- (void)viewDidLoad
{
    [super viewDidLoad];
    
    if ([self isVideoRecordingAvailable]) {
        return;
    }
    self.sourceType = UIImagePickerControllerSourceTypeCamera;
    self.mediaTypes = @[(NSString *)kUTTypeMovie];
    self.delegate = self;
    
    //隱藏系統(tǒng)自帶UI
    self.showsCameraControls = NO;
    //設(shè)置攝像頭
    [self switchCameraIsFront:NO];
    //設(shè)置視頻畫質(zhì)類別
    self.videoQuality = UIImagePickerControllerQualityTypeMedium;
    //設(shè)置散光燈類型
    self.cameraFlashMode = UIImagePickerControllerCameraFlashModeAuto;
    //設(shè)置錄制的最大時(shí)長(zhǎng)
    self.videoMaximumDuration = 20;
}
- (BOOL)isVideoRecordingAvailable
{
    if([UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera]){
        NSArray *availableMediaTypes = [UIImagePickerController availableMediaTypesForSourceType:UIImagePickerControllerSourceTypeCamera];
        if([availableMediaTypes containsObject:(NSString *)kUTTypeMovie]){
            return YES;
        }
    }
    return NO;
}

- (void)switchCameraIsFront:(BOOL)front
{
    if (front) {
        if([UIImagePickerController isCameraDeviceAvailable:UIImagePickerControllerCameraDeviceFront]){
            [self setCameraDevice:UIImagePickerControllerCameraDeviceFront];
            
        }
    } else {
        if([UIImagePickerController isCameraDeviceAvailable:UIImagePickerControllerCameraDeviceRear]){
            [self setCameraDevice:UIImagePickerControllerCameraDeviceRear];
            
        }
    }
}

2.AVCaptureSession+AVCaptureMovieFileOutput

流程:

1. 創(chuàng)建捕捉會(huì)話
2. 設(shè)置視頻的輸入
3. 設(shè)置音頻的輸入
4. 輸出源設(shè)置,這里視頻,音頻數(shù)據(jù)會(huì)合并到一起輸出,在代理方法中國(guó)也可以單獨(dú)拿到視頻或者音頻數(shù)據(jù),給AVCaptureMovieFileOutput指定路徑,開始錄制之后就會(huì)向這個(gè)路徑寫入數(shù)據(jù)
5. 添加視頻預(yù)覽層
6. 開始采集數(shù)據(jù),這個(gè)時(shí)候還沒有寫入數(shù)據(jù),用戶點(diǎn)擊錄制后就可以開始寫入數(shù)據(jù)

0. 創(chuàng)建捕捉會(huì)話

 self.session = [[AVCaptureSession alloc] init];
    if ([_session canSetSessionPreset:AVCaptureSessionPreset640x480]) {//設(shè)置分辨率
        _session.sessionPreset=AVCaptureSessionPreset640x480;
    }

1. 視頻的輸入

   - (void)setUpVideo
{
    // 1.1 獲取視頻輸入設(shè)備(攝像頭)
    AVCaptureDevice *videoCaptureDevice=[self getCameraDeviceWithPosition:AVCaptureDevicePositionBack];//取得后置攝像頭
    
    // 視頻 HDR (高動(dòng)態(tài)范圍圖像)
    // videoCaptureDevice.videoHDREnabled = YES;
    // 設(shè)置最大,最小幀速率
    //videoCaptureDevice.activeVideoMinFrameDuration = CMTimeMake(1, 60);
    // 1.2 創(chuàng)建視頻輸入源
    NSError *error=nil;
    self.videoInput= [[AVCaptureDeviceInput alloc] initWithDevice:videoCaptureDevice error:&error];
    // 1.3 將視頻輸入源添加到會(huì)話
    if ([self.session canAddInput:self.videoInput]) {
        [self.session addInput:self.videoInput];
        
    }
}

2. 音頻的輸入

// 2.1 獲取音頻輸入設(shè)備
    AVCaptureDevice *audioCaptureDevice=[[AVCaptureDevice devicesWithMediaType:AVMediaTypeAudio] firstObject];
    NSError *error=nil;
    // 2.2 創(chuàng)建音頻輸入源
    self.audioInput = [[AVCaptureDeviceInput alloc] initWithDevice:audioCaptureDevice error:&error];
    // 2.3 將音頻輸入源添加到會(huì)話
    if ([self.session canAddInput:self.audioInput]) {
        [self.session addInput:self.audioInput];
    }

3.輸出源設(shè)置

- (void)setUpFileOut
{
    // 3.1初始化設(shè)備輸出對(duì)象,用于獲得輸出數(shù)據(jù)
    self.FileOutput=[[AVCaptureMovieFileOutput alloc]init];
    
    // 3.2設(shè)置輸出對(duì)象的一些屬性
    AVCaptureConnection *captureConnection=[self.FileOutput connectionWithMediaType:AVMediaTypeVideo];
    //設(shè)置防抖
    //視頻防抖 是在 iOS 6 和 iPhone 4S 發(fā)布時(shí)引入的功能。到了 iPhone 6,增加了更強(qiáng)勁和流暢的防抖模式,被稱為影院級(jí)的視頻防抖動(dòng)。相關(guān)的 API 也有所改動(dòng) (目前為止并沒有在文檔中反映出來,不過可以查看頭文件)。防抖并不是在捕獲設(shè)備上配置的,而是在 AVCaptureConnection 上設(shè)置。由于不是所有的設(shè)備格式都支持全部的防抖模式,所以在實(shí)際應(yīng)用中應(yīng)事先確認(rèn)具體的防抖模式是否支持:
    if ([captureConnection isVideoStabilizationSupported ]) {
        captureConnection.preferredVideoStabilizationMode=AVCaptureVideoStabilizationModeAuto;
    }
    //預(yù)覽圖層和視頻方向保持一致
    captureConnection.videoOrientation = [self.previewlayer connection].videoOrientation;
    
    // 3.3將設(shè)備輸出添加到會(huì)話中
    if ([_session canAddOutput:_FileOutput]) {
        [_session addOutput:_FileOutput];
    }
}

4. 視頻預(yù)覽層

一進(jìn)入視頻錄制界面,這個(gè)時(shí)候 session就已經(jīng)在采集數(shù)據(jù)了,并把數(shù)據(jù)顯示在預(yù)覽層上,用戶選擇錄制后,再將采集到的數(shù)據(jù)寫入文件。

    - (void)setUpPreviewLayerWithType:(FMVideoViewType )type
{
    CGRect rect = CGRectZero;
    switch (type) {
        case Type1X1:
            rect = CGRectMake(0, 0, kScreenWidth, kScreenWidth);
            break;
        case Type4X3:
            rect = CGRectMake(0, 0, kScreenWidth, kScreenWidth*4/3);
            break;
        case TypeFullScreen:
            rect = [UIScreen mainScreen].bounds;
            break;
        default:
            rect = [UIScreen mainScreen].bounds;
            break;
    }
    self.previewlayer.frame = rect;
    [_superView.layer insertSublayer:self.previewlayer atIndex:0];
}

5. 開始采集畫面

[self.session startRunning];

6.開始錄制

- (void)writeDataTofile
{
    NSString *videoPath = [self createVideoFilePath];
    self.videoUrl = [NSURL fileURLWithPath:videoPath];
    [self.FileOutput startRecordingToOutputFileURL:self.videoUrl recordingDelegate:self];
    
}

3.AVCaptureSession+AVAssetWriter

流程:

1. 創(chuàng)建捕捉會(huì)話
2. 設(shè)置視頻的輸入 和 輸出
3. 設(shè)置音頻的輸入 和 輸出
4. 添加視頻預(yù)覽層
5. 開始采集數(shù)據(jù),這個(gè)時(shí)候還沒有寫入數(shù)據(jù),用戶點(diǎn)擊錄制后就可以開始寫入數(shù)據(jù)
6. 初始化AVAssetWriter, 我們會(huì)拿到視頻和音頻的數(shù)據(jù)流,用AVAssetWriter寫入文件,這一步需要我們自己實(shí)現(xiàn)。

1. 創(chuàng)建捕捉會(huì)話

需要確保在同一個(gè)隊(duì)列,最好隊(duì)列只創(chuàng)建一次

 self.session = [[AVCaptureSession alloc] init];
    if ([_session canSetSessionPreset:AVCaptureSessionPreset640x480]) {//設(shè)置分辨率
        _session.sessionPreset=AVCaptureSessionPreset640x480;
    }

2.設(shè)置視頻的輸入 和 輸出

- (void)setUpVideo
{
    // 2.1 獲取視頻輸入設(shè)備(攝像頭)
    AVCaptureDevice *videoCaptureDevice=[self getCameraDeviceWithPosition:AVCaptureDevicePositionBack];//取得后置攝像頭
    // 2.2 創(chuàng)建視頻輸入源
    NSError *error=nil;
    self.videoInput= [[AVCaptureDeviceInput alloc] initWithDevice:videoCaptureDevice error:&error];
    // 2.3 將視頻輸入源添加到會(huì)話
    if ([self.session canAddInput:self.videoInput]) {
        [self.session addInput:self.videoInput];
    }
    
    self.videoOutput = [[AVCaptureVideoDataOutput alloc] init];
    self.videoOutput.alwaysDiscardsLateVideoFrames = YES; //立即丟棄舊幀,節(jié)省內(nèi)存,默認(rèn)YES
    [self.videoOutput setSampleBufferDelegate:self queue:self.videoQueue];
    if ([self.session canAddOutput:self.videoOutput]) {
        [self.session addOutput:self.videoOutput];
    }
    
}

3. 設(shè)置音頻的輸入 和 輸出

- (void)setUpAudio
{
    // 2.2 獲取音頻輸入設(shè)備
    AVCaptureDevice *audioCaptureDevice=[[AVCaptureDevice devicesWithMediaType:AVMediaTypeAudio] firstObject];
    NSError *error=nil;
    // 2.4 創(chuàng)建音頻輸入源
    self.audioInput = [[AVCaptureDeviceInput alloc] initWithDevice:audioCaptureDevice error:&error];
    // 2.6 將音頻輸入源添加到會(huì)話
    if ([self.session canAddInput:self.audioInput]) {
        [self.session addInput:self.audioInput];
    }
    
    self.audioOutput = [[AVCaptureAudioDataOutput alloc] init];
    [self.audioOutput setSampleBufferDelegate:self queue:self.videoQueue];
    if([self.session canAddOutput:self.audioOutput]) {
        [self.session addOutput:self.audioOutput];
    }
    
}

4. 添加視頻預(yù)覽層

  - (void)setUpPreviewLayerWithType:(FMVideoViewType )type
{
    CGRect rect = CGRectZero;
    switch (type) {
        case Type1X1:
            rect = CGRectMake(0, 0, kScreenWidth, kScreenWidth);
            break;
        case Type4X3:
            rect = CGRectMake(0, 0, kScreenWidth, kScreenWidth*4/3);
            break;
        case TypeFullScreen:
            rect = [UIScreen mainScreen].bounds;
            break;
        default:
            rect = [UIScreen mainScreen].bounds;
            break;
    }
    
    self.previewlayer.frame = rect;
    [_superView.layer insertSublayer:self.previewlayer atIndex:0];
}

5. 開始采集畫面

   [self.session startRunning];

6. 初始化AVAssetWriter

AVAssetWriter 寫入數(shù)據(jù)的過程需要在子線程中執(zhí)行,并且每次寫入數(shù)據(jù)都需要保證在同一個(gè)線程。

- (void)setUpWriter
{
    self.videoUrl = [[NSURL alloc] initFileURLWithPath:[self createVideoFilePath]];
    self.writeManager = [[AVAssetWriteManager alloc] initWithURL:self.videoUrl viewType:_viewType];
    self.writeManager.delegate = self;
    
}

7.拿到數(shù)據(jù)流后處理

視頻數(shù)據(jù)和音頻數(shù)據(jù)需要分開處理

- (void)captureOutput:(AVCaptureOutput *)captureOutput didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer fromConnection:(AVCaptureConnection *)connection
{
    @autoreleasepool {
        
        //視頻
        if (connection == [self.videoOutput connectionWithMediaType:AVMediaTypeVideo]) {
            
            if (!self.writeManager.outputVideoFormatDescription) {
                @synchronized(self) {
                    CMFormatDescriptionRef formatDescription = CMSampleBufferGetFormatDescription(sampleBuffer);
                    self.writeManager.outputVideoFormatDescription = formatDescription;
                }
            } else {
                @synchronized(self) {
                    if (self.writeManager.writeState == FMRecordStateRecording) {
                        [self.writeManager appendSampleBuffer:sampleBuffer ofMediaType:AVMediaTypeVideo];
                    }
                    
                }
            }
            
            
        }
        
        //音頻
        if (connection == [self.audioOutput connectionWithMediaType:AVMediaTypeAudio]) {
            if (!self.writeManager.outputAudioFormatDescription) {
                @synchronized(self) {
                    CMFormatDescriptionRef formatDescription = CMSampleBufferGetFormatDescription(sampleBuffer);
                    self.writeManager.outputAudioFormatDescription = formatDescription;
                }
            }
            @synchronized(self) {
                
                if (self.writeManager.writeState == FMRecordStateRecording) {
                    [self.writeManager appendSampleBuffer:sampleBuffer ofMediaType:AVMediaTypeAudio];
                }
                
            }
            
        }
    }
    
}

我們拿到最原始的數(shù)據(jù)以后,可以對(duì)其進(jìn)行各種參數(shù)的設(shè)置

- (void)setUpWriter
{
    self.assetWriter = [AVAssetWriter assetWriterWithURL:self.videoUrl fileType:AVFileTypeMPEG4 error:nil];
    //寫入視頻大小
    NSInteger numPixels = self.outputSize.width * self.outputSize.height;
    //每像素比特
    CGFloat bitsPerPixel = 6.0;
    NSInteger bitsPerSecond = numPixels * bitsPerPixel;
    
    // 碼率和幀率設(shè)置
    NSDictionary *compressionProperties = @{ AVVideoAverageBitRateKey : @(bitsPerSecond),
                                             AVVideoExpectedSourceFrameRateKey : @(30),
                                             AVVideoMaxKeyFrameIntervalKey : @(30),
                                             AVVideoProfileLevelKey : AVVideoProfileLevelH264BaselineAutoLevel };
    
    //視頻屬性
    self.videoCompressionSettings = @{ AVVideoCodecKey : AVVideoCodecH264,
                                       AVVideoScalingModeKey : AVVideoScalingModeResizeAspectFill,
                                       AVVideoWidthKey : @(self.outputSize.height),
                                       AVVideoHeightKey : @(self.outputSize.width),
                                       AVVideoCompressionPropertiesKey : compressionProperties };

    _assetWriterVideoInput = [AVAssetWriterInput assetWriterInputWithMediaType:AVMediaTypeVideo outputSettings:self.videoCompressionSettings];
    //expectsMediaDataInRealTime 必須設(shè)為yes,需要從capture session 實(shí)時(shí)獲取數(shù)據(jù)
    _assetWriterVideoInput.expectsMediaDataInRealTime = YES;
    _assetWriterVideoInput.transform = CGAffineTransformMakeRotation(M_PI / 2.0);
    
    
    // 音頻設(shè)置
    self.audioCompressionSettings = @{ AVEncoderBitRatePerChannelKey : @(28000),
                                       AVFormatIDKey : @(kAudioFormatMPEG4AAC),
                                       AVNumberOfChannelsKey : @(1),
                                       AVSampleRateKey : @(22050) };
    
    
    _assetWriterAudioInput = [AVAssetWriterInput assetWriterInputWithMediaType:AVMediaTypeAudio outputSettings:self.audioCompressionSettings];
    _assetWriterAudioInput.expectsMediaDataInRealTime = YES;
    
    
    if ([_assetWriter canAddInput:_assetWriterVideoInput]) {
        [_assetWriter addInput:_assetWriterVideoInput];
    }else {
        NSLog(@"AssetWriter videoInput append Failed");
    }
    if ([_assetWriter canAddInput:_assetWriterAudioInput]) {
        [_assetWriter addInput:_assetWriterAudioInput];
    }else {
        NSLog(@"AssetWriter audioInput Append Failed");
    }
    
    
    self.writeState = FMRecordStateRecording;
}

設(shè)置好參數(shù)以后,就可以寫入文件了。AVAssetWriter數(shù)據(jù)寫入的過程有點(diǎn)復(fù)雜,demo中我新建AVAssetWriteManager分離出AVAssetWriter,單獨(dú)處理寫數(shù)據(jù),這樣邏輯會(huì)清晰一點(diǎn)。

fileOut和writer的相同點(diǎn)和不同點(diǎn)

從上面的兩個(gè)流程大致可以看出來,
相同點(diǎn):數(shù)據(jù)采集都在AVCaptureSession中進(jìn)行,視頻和音頻的輸入都一樣,畫面的預(yù)覽一致。
不同點(diǎn):
輸出不一致, AVCaptureMovieFileOutput 只需要一個(gè)輸出即可,指定一個(gè)文件路后,視頻和音頻會(huì)寫入到指定路徑,不需要其他復(fù)雜的操作。
AVAssetWriter 需要 AVCaptureVideoDataOutput 和 AVCaptureAudioDataOutput 兩個(gè)單獨(dú)的輸出,拿到各自的輸出數(shù)據(jù)后,然后自己進(jìn)行相應(yīng)的處理。

可配參數(shù)不一致,AVAssetWriter可以配置更多的參數(shù)。

視頻剪裁不一致,AVCaptureMovieFileOutput 如果要剪裁視頻,因?yàn)橄到y(tǒng)已經(jīng)把數(shù)據(jù)寫到文件中了,我們需要從文件中獨(dú)到一個(gè)完整的視頻,然后處理;而AVAssetWriter我們拿到的是數(shù)據(jù)流,還沒有合成視頻,對(duì)數(shù)據(jù)流進(jìn)行處理,所以兩則剪裁方式也是不一樣。

其他添加背景音樂,水印等也是不一樣的,這里沒有涉及就不介紹了。到這里也差不多了,文章也有點(diǎn)長(zhǎng)了。這些是我自己整理資料總結(jié)出來的,不排除會(huì)有一些錯(cuò)誤之處,供大家學(xué)習(xí)參考,希望有所收獲。如果方便,還請(qǐng)為我star一個(gè),也算是對(duì)我的支持。

demo地址

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

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