iOS使用AVPlayer封裝自定義播放器

一罗岖、 前言

  1. AVPlayer本身并不顯示視頻确买!需要一個AVPlayerLayer播放層來顯示視頻,然后添加到父視圖的layer中。
  2. AVPlayer只負責視頻管理和調控候生!而視頻資源是由AVPlayerItem提供的同眯,每個AVPlayerItem對應一個視頻地址。
  3. 待補充...

二唯鸭、 重要屬性和方法

1. AVplayerItem:###

+ (instancetype)playerItemWithURL:(NSURL *)URL; 初始化視頻資源方法
duration視頻總時長 (有光CMTime結構體可以自己查下)
status 視頻資源的狀態(tài) (需要監(jiān)聽的屬性)
loadedTimeRanges 在線視頻的緩沖進度 (需要監(jiān)聽的屬性)
playbackBufferEmpty 進行跳轉后沒數(shù)據(jù) (可選監(jiān)聽)
playbackLikelyToKeepUp 進行跳轉后有數(shù)據(jù) (可選監(jiān)聽)

2. AVplayer:###

rate 播放速度 常用判斷播放狀態(tài) =1播放 =0暫停
- (void)play; - (void)pause; 播放暫停
- (void)seekToTime:(CMTime)time;跳轉到指定時間
- (CMTime)currentTime;獲取當前播放進度
- (id)addPeriodicTimeObserverForInterval:(CMTime)interval queue:(nullable dispatch_queue_t)queue usingBlock:(void (^)(CMTime time))block;監(jiān)聽當前播放進度
- (void)removeTimeObserver:(id)observer;移除監(jiān)聽 (銷毀播放器的時候調用)
- (void)replaceCurrentItemWithPlayerItem:(nullable AVPlayerItem *)item;切換視頻資源

3. AVPlayerLayer###

videoGravity 視頻的填充方式

4. AVQueuePlayer:這個是用于處理播放列表的操作须蜗,待學習...###

三、 剩下的都在代碼里了

LPAVPlayer.h

typedef NS_ENUM(NSInteger, LPAVPlayerStatus) {
    LPAVPlayerStatusReadyToPlay = 0, // 準備好播放
    LPAVPlayerStatusLoadingVideo,    // 加載視頻
    LPAVPlayerStatusPlayEnd,         // 播放結束
    LPAVPlayerStatusCacheData,       // 緩沖視頻
    LPAVPlayerStatusCacheEnd,        // 緩沖結束
    LPAVPlayerStatusPlayStop,        // 播放中斷 (多是沒網(wǎng))
    LPAVPlayerStatusItemFailed,      // 視頻資源問題
    LPAVPlayerStatusEnterBack,       // 進入后臺
    LPAVPlayerStatusBecomeActive,    // 從后臺返回
};

@protocol LPAVPlayerDelegate <NSObject>

@optional
// 數(shù)據(jù)刷新
- (void)refreshDataWith:(NSTimeInterval)totalTime Progress:(NSTimeInterval)currentTime LoadRange:(NSTimeInterval)loadTime;
// 狀態(tài)/錯誤 提示
- (void)promptPlayerStatusOrErrorWith:(LPAVPlayerStatus)status;

@end

@interface LPAVPlayer : UIView

@property (nonatomic, weak) id<LPAVPlayerDelegate>delegate;


// 視頻總長度
@property (nonatomic, assign) NSTimeInterval totalTime;
// 視頻總長度
//@property (nonatomic, assign) NSTimeInterval currentTime;
// 緩存數(shù)據(jù)
@property (nonatomic, assign) NSTimeInterval loadRange;


/**
 準備播放器
 
 @param videoPath 視頻地址
 */
//- (void)setupPlayerWith:(NSString *)videoPath;
- (void)setupPlayerWith:(NSURL *)videoURL;

/** 播放 */
- (void)play;

/** 暫停 */
- (void)pause;

/** 播放|暫停 */
- (void)playOrPause:(void (^)(BOOL isPlay))block;

/** 拖動視頻進度 */
- (void)seekPlayerTimeTo:(NSTimeInterval)time;

/** 跳動中不監(jiān)聽 */
- (void)startToSeek;

/**
 切換視頻
 
 @param videoPath 視頻地址
 */
//- (void)replacePalyerItem:(NSString *)videoPath;
- (void)replacePalyerItem:(NSURL *)videoURL;


@end



LPAVPlayer.m

#import <AVFoundation/AVFoundation.h>

@interface LPAVPlayer ()

/** 播放器 */
@property (nonatomic, strong) AVPlayer *player;
/** 視頻資源 */
@property (nonatomic, strong) AVPlayerItem *currentItem;
/** 播放器觀察者 */
@property (nonatomic ,strong)  id timeObser;
// 拖動進度條的時候停止刷新數(shù)據(jù)
@property (nonatomic ,assign) BOOL isSeeking;
// 是否需要緩沖
@property (nonatomic, assign) BOOL isCanPlay;
// 是否需要緩沖
@property (nonatomic, assign) BOOL needBuffer;

@end

@implementation LPAVPlayer


- (instancetype)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];
    if (self) {
        
        self.backgroundColor = [UIColor lightGrayColor];
        
        self.isCanPlay = NO;
        self.needBuffer = NO;
        self.isSeeking = NO;
        /**
         * 這里view用來做AVPlayer的容器
         * 完成對AVPlayer的二次封裝
         * 要求 : 
         * 1. 暴露視頻輸出的API  視頻時長 當前播放時間 進度
         * 2. 暴露出易于控制的data入口  播放 暫停 進度拖動 音量 亮度 清晰度調節(jié)
         */
        
        
    }
    return self;
}

#pragma mark - 屬性和方法
- (NSTimeInterval)totalTime
{
    return CMTimeGetSeconds(self.player.currentItem.duration);
}



/** 
 準備播放器
 
 @param videoPath 視頻地址
 */
- (void)setupPlayerWith:(NSURL *)videoURL
{
    [self creatPlayer:videoURL];
    
    [_player play];
    [self useDelegateWith:LPAVPlayerStatusLoadingVideo];
}

/**
 avplayer自身有一個rate屬性
 rate ==1.0目溉,表示正在播放明肮;rate == 0.0,暫停缭付;rate == -1.0柿估,播放失敗
 */

/** 播放 */
- (void)play
{
    if (self.player.rate == 0) {
        [self.player play];
    }
}

/** 暫停 */
- (void)pause
{
    if (self.player.rate == 1.0) {
        [self.player pause];
    }
}

/** 播放|暫停 */
- (void)playOrPause:(void (^)(BOOL isPlay))block;
{
    if (self.player.rate == 0) {
        
        [self.player play];
        
        block(YES);
        
    }else if (self.player.rate == 1.0) {
        
        [self.player pause];
        
        block(NO);
        
    }else {
        NSLog(@"播放器出錯");
    }
}

/** 拖動視頻進度 */
- (void)seekPlayerTimeTo:(NSTimeInterval)time
{
    [self pause];
    [self startToSeek];
    __weak typeof(self)weakSelf = self;
    
    [self.player seekToTime:CMTimeMake(time, 1.0) completionHandler:^(BOOL finished) {
        [weakSelf endSeek];
        [weakSelf play];
    }];
    
}

/** 跳動中不監(jiān)聽 */
- (void)startToSeek
{
    self.isSeeking = YES;
}
- (void)endSeek
{
    self.isSeeking = NO;
}

/**
 切換視頻
 
 @param videoURL 視頻地址
 */
- (void)replacePalyerItem:(NSURL *)videoURL
{
    self.isCanPlay = NO;
    
    [self pause];
    [self removeNotification];
    [self removeObserverWithPlayItem:self.currentItem];
    
    self.currentItem = [self getPlayerItem:videoURL];
    [self.player replaceCurrentItemWithPlayerItem:self.currentItem];
    [self addObserverWithPlayItem:self.currentItem];
    [self addNotificatonForPlayer];
    
    [self play];
    
}


/**
  播放狀態(tài)代理調用
  
  @param status 播放狀態(tài)
 */
- (void)useDelegateWith:(LPAVPlayerStatus)status
{
    if (self.isCanPlay == NO) {
        return;
    }
    
    if (self.delegate && [self.delegate respondsToSelector:@selector(promptPlayerStatusOrErrorWith:)]) {
        [self.delegate promptPlayerStatusOrErrorWith:status];
    }
}


#pragma mark - 創(chuàng)建播放器
/**
 獲取播放item
 
 @param videoURL 視頻網(wǎng)址
 
 @return AVPlayerItem 
 */
- (AVPlayerItem *)getPlayerItem:(NSURL *)videoURL
{
    // 轉utf8 防止中文報錯
//    videoPath = [videoPath stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
//    videoPath = [videoPath stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLQueryAllowedCharacterSet]];
    
    // NSURL *url = [NSURL URLWithString:videoPath];
    // 如果播放本地視頻要用 NSURL *url = [NSURL fileURLWithPath:videoURL];
    // 所以替換成URL
    
    AVPlayerItem *item = [AVPlayerItem playerItemWithURL:url];
    
    return item;
}


/**
  創(chuàng)建播放器
 
 
 */
- (void)creatPlayer:(NSURL *)videoURL
{
    if (!_player) {
        
        self.currentItem = [self getPlayerItem:videoURL];
        
        _player = [AVPlayer playerWithPlayerItem:self.currentItem];
        
        [self creatPlayerLayer];
        
        [self addPlayerObserver];
        
        [self addObserverWithPlayItem:self.currentItem];
        
        [self addNotificatonForPlayer];
    }
}

/**
 創(chuàng)建播放器 layer 層
 AVPlayerLayer的videoGravity屬性設置
 AVLayerVideoGravityResize,       // 非均勻模式。兩個維度完全填充至整個視圖區(qū)域
 AVLayerVideoGravityResizeAspect,  // 等比例填充陷猫,直到一個維度到達區(qū)域邊界
 AVLayerVideoGravityResizeAspectFill, // 等比例填充秫舌,直到填充滿整個視圖區(qū)域的妖,其中一個維度的部分區(qū)域會被裁剪
 */
- (void)creatPlayerLayer
{
    AVPlayerLayer *layer = [AVPlayerLayer playerLayerWithPlayer:self.player];
    
    layer.frame = self.bounds;
    
    layer.videoGravity = AVLayerVideoGravityResizeAspect;
    
    [self.layer addSublayer:layer];
}

#pragma mark - 添加 監(jiān)控
/** 給player 添加 time observer */
- (void)addPlayerObserver
{
    __weak typeof(self)weakSelf = self;
    _timeObser = [self.player addPeriodicTimeObserverForInterval:CMTimeMake(1.0, 1.0) queue:dispatch_get_main_queue() usingBlock:^(CMTime time) {
        AVPlayerItem *playerItem = weakSelf.player.currentItem;
        
        float current = CMTimeGetSeconds(time);
        
        float total = CMTimeGetSeconds([playerItem duration]);
        
        if (weakSelf.isSeeking) {
            return;
        }
        
        if (weakSelf.delegate && [weakSelf.delegate respondsToSelector:@selector(refreshDataWith:Progress:LoadRange:)]) {
            [weakSelf.delegate refreshDataWith:total Progress:current LoadRange:weakSelf.loadRange];
        }
//        NSLog(@"當前播放進度 %.2f/%.2f.",current,total);
        
    }];
}
/** 移除 time observer */
- (void)removePlayerObserver
{
    [_player removeTimeObserver:_timeObser];
}

/** 給當前播放的item 添加觀察者 
 
 需要監(jiān)聽的字段和狀態(tài)
 status :  AVPlayerItemStatusUnknown,AVPlayerItemStatusReadyToPlay,AVPlayerItemStatusFailed
 loadedTimeRanges  :  緩沖進度
 playbackBufferEmpty : seekToTime后,緩沖數(shù)據(jù)為空足陨,而且有效時間內數(shù)據(jù)無法補充嫂粟,播放失敗
 playbackLikelyToKeepUp : seekToTime后,可以正常播放,相當于readyToPlay墨缘,一般拖動滑竿菊花轉星虹,到了這個這個狀態(tài)菊花隱藏
 
 */
- (void)addObserverWithPlayItem:(AVPlayerItem *)item
{
    [item addObserver:self forKeyPath:@"status" options:NSKeyValueObservingOptionNew context:nil];
    [item addObserver:self forKeyPath:@"loadedTimeRanges" options:NSKeyValueObservingOptionNew context:nil];
    [item addObserver:self forKeyPath:@"playbackBufferEmpty" options:NSKeyValueObservingOptionNew context:nil];
    [item addObserver:self forKeyPath:@"playbackLikelyToKeepUp" options:NSKeyValueObservingOptionNew context:nil];
}
/** 移除 item 的 observer */
- (void)removeObserverWithPlayItem:(AVPlayerItem *)item
{
    [item removeObserver:self forKeyPath:@"status"];
    [item removeObserver:self forKeyPath:@"loadedTimeRanges"];
    [item removeObserver:self forKeyPath:@"playbackBufferEmpty"];
    [item removeObserver:self forKeyPath:@"playbackLikelyToKeepUp"];
}
/** 數(shù)據(jù)處理 獲取到觀察到的數(shù)據(jù) 并進行處理 */
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context
{
    AVPlayerItem *item = object;
    if ([keyPath isEqualToString:@"status"]) {// 播放狀態(tài)
        
        [self handleStatusWithPlayerItem:item];
        
    } else if ([keyPath isEqualToString:@"loadedTimeRanges"]) {// 緩沖進度
        
        [self handleLoadedTimeRangesWithPlayerItem:item];
        
    } else if ([keyPath isEqualToString:@"playbackBufferEmpty"]) {// 跳轉后沒數(shù)據(jù)
        
        // 轉菊花
        if (self.isCanPlay) {
            NSLog(@"跳轉后沒數(shù)據(jù)");
            self.needBuffer = YES;
            [self useDelegateWith:LPAVPlayerStatusCacheData];
        }
        
        
        
    } else if ([keyPath isEqualToString:@"playbackLikelyToKeepUp"]) {// 跳轉后有數(shù)據(jù)
        
        
        
        // 隱藏菊花
        if (self.isCanPlay && self.needBuffer) {
            
            NSLog(@"跳轉后有數(shù)據(jù)");
            
            self.needBuffer = NO;
            
            [self useDelegateWith:LPAVPlayerStatusCacheEnd];
        }
        
    }
}
/**
  處理 AVPlayerItem 播放狀態(tài)
 AVPlayerItemStatusUnknown           狀態(tài)未知
 AVPlayerItemStatusReadyToPlay       準備好播放
 AVPlayerItemStatusFailed            播放出錯
 */
- (void)handleStatusWithPlayerItem:(AVPlayerItem *)item
{
    AVPlayerItemStatus status = item.status;
    switch (status) {
        case AVPlayerItemStatusReadyToPlay:   // 準備好播放
            
            NSLog(@"AVPlayerItemStatusReadyToPlay");
            self.isCanPlay = YES;
            [self useDelegateWith:LPAVPlayerStatusReadyToPlay];
            
            break;
        case AVPlayerItemStatusFailed:        // 播放出錯
            
            NSLog(@"AVPlayerItemStatusFailed");
            [self useDelegateWith:LPAVPlayerStatusItemFailed];
            
            break;
        case AVPlayerItemStatusUnknown:       // 狀態(tài)未知
            
            NSLog(@"AVPlayerItemStatusUnknown");
            
            break;
            
        default:
            break;
    }
    
}
/** 處理緩沖進度 */
- (void)handleLoadedTimeRangesWithPlayerItem:(AVPlayerItem *)item
{
    NSArray *loadArray = item.loadedTimeRanges;
    
    CMTimeRange range = [[loadArray firstObject] CMTimeRangeValue];
    
    float start = CMTimeGetSeconds(range.start);
    
    float duration = CMTimeGetSeconds(range.duration);
    
    NSTimeInterval totalTime = start + duration;// 緩存總長度
    
    _loadRange = totalTime;
//    NSLog(@"緩沖進度 -- %.2f",totalTime);
    
}


/**
 添加關鍵通知
 
 AVPlayerItemDidPlayToEndTimeNotification     視頻播放結束通知
 AVPlayerItemTimeJumpedNotification           視頻進行跳轉通知
 AVPlayerItemPlaybackStalledNotification      視頻異常中斷通知
 UIApplicationDidEnterBackgroundNotification  進入后臺
 UIApplicationDidBecomeActiveNotification     返回前臺
 
 */
- (void)addNotificatonForPlayer
{
    NSNotificationCenter *center = [NSNotificationCenter defaultCenter];
    
    [center addObserver:self selector:@selector(videoPlayEnd:) name:AVPlayerItemDidPlayToEndTimeNotification object:nil];
//    [center addObserver:self selector:@selector(videoPlayToJump:) name:AVPlayerItemTimeJumpedNotification object:nil];//沒意義
    [center addObserver:self selector:@selector(videoPlayError:) name:AVPlayerItemPlaybackStalledNotification object:nil];
    [center addObserver:self selector:@selector(videoPlayEnterBack:) name:UIApplicationDidEnterBackgroundNotification object:nil];
    [center addObserver:self selector:@selector(videoPlayBecomeActive:) name:UIApplicationDidBecomeActiveNotification object:nil];
}
/** 移除 通知 */
- (void)removeNotification
{
    NSNotificationCenter *center = [NSNotificationCenter defaultCenter];
    
    [center removeObserver:self name:AVPlayerItemDidPlayToEndTimeNotification object:nil];
//    [center removeObserver:self name:AVPlayerItemTimeJumpedNotification object:nil];
    [center removeObserver:self name:AVPlayerItemPlaybackStalledNotification object:nil];
    [center removeObserver:self name:UIApplicationDidEnterBackgroundNotification object:nil];
    [center removeObserver:self name:UIApplicationDidBecomeActiveNotification object:nil];
    [center removeObserver:self];
}

/** 視頻播放結束 */
- (void)videoPlayEnd:(NSNotification *)notic
{
    NSLog(@"視頻播放結束");
    [self useDelegateWith:LPAVPlayerStatusPlayEnd];
    [self.player seekToTime:kCMTimeZero];
}
///** 視頻進行跳轉 */ 沒有意義的方法 會被莫名的多次調動,不清楚機制
//- (void)videoPlayToJump:(NSNotification *)notic
//{
//    NSLog(@"視頻進行跳轉");
//}
/** 視頻異常中斷 */
- (void)videoPlayError:(NSNotification *)notic
{
    NSLog(@"視頻異常中斷");
    [self useDelegateWith:LPAVPlayerStatusPlayStop];
}
/** 進入后臺 */
- (void)videoPlayEnterBack:(NSNotification *)notic
{
    NSLog(@"進入后臺");
    [self useDelegateWith:LPAVPlayerStatusEnterBack];
}
/** 返回前臺 */
- (void)videoPlayBecomeActive:(NSNotification *)notic
{
    NSLog(@"返回前臺");
    [self useDelegateWith:LPAVPlayerStatusBecomeActive];
}

#pragma mark - 銷毀 release
- (void)dealloc
{
    NSLog(@"--- %@ --- 銷毀了",[self class]);
    
    [self removeNotification];
    [self removePlayerObserver];
    [self removeObserverWithPlayItem:self.player.currentItem];
    
}

@end

四镊讼、 在控制器中的調用

因為控制器還有一些其他的代碼搁凸,就不整個貼出來了,截取一部分重要的貼出來狠毯。

1. 創(chuàng)建播放器View

/**
 創(chuàng)建播放器視圖
*/
- (void)buildPlayerView
{
   CGRect rect = CGRectMake(0, 64, self.view.bounds.size.width, 250);
   
   _playView = [[LPAVPlayer alloc] initWithFrame:rect];
   
   _playView.delegate = self;
   
   [self.view addSubview:_playView];
   
   [_playView setupPlayerWith:url];
   
   
}

2. 代理 -- 狀態(tài)提示

// LPAVPlayer delegate  ----- 狀態(tài)提示
- (void)promptPlayerStatusOrErrorWith:(LPAVPlayerStatus)status
{
  switch (status) {
      case LPAVPlayerStatusLoadingVideo:// 開始準備
          
          [self.activity startAnimating];
          
          break;
          
      case LPAVPlayerStatusReadyToPlay:// 準備完成
          
          [self.activity stopAnimating];
          [self.playOrPause setTitle:@"暫停" forState:UIControlStateNormal];
          self.slider.maximumValue = _playView.totalTime;
          self.slider.value = 0;
          self.loadProgress.progress = 0;
          
          break;
          
          
          
      default:
          break;
  }
}

3. 代理 -- 刷新數(shù)據(jù)

// LPAVPlayer delegate  ----- 刷新數(shù)據(jù)
- (void)refreshDataWith:(NSTimeInterval)totalTime Progress:(NSTimeInterval)currentTime LoadRange:(NSTimeInterval)loadTime
{
  
  [self.loadProgress setProgress:(loadTime/totalTime) animated:YES];
  
  [self.slider setValue:currentTime animated:YES];
  
  self.timeLabel.text = [NSString stringWithFormat:@"%@/%@",[self otherConvertTimeFormat:currentTime],[self otherConvertTimeFormat:totalTime]];
}

- (NSString *)otherConvertTimeFormat:(NSInteger)time
{
  NSString *needStr = @"";
  
  if (time < 3600) {
      
      needStr =  [NSString stringWithFormat:@"%02li:%02li",lround(floor(time/60.f)),lround(floor(time/1.f))%60];
      
  } else {
      
      needStr =  [NSString stringWithFormat:@"%02li:%02li:%02li",lround(floor(time/3600.f)),lround(floor(time%3600)/60.f),lround(floor(time/1.f))%60];
      
  }
  return needStr;
}

五护糖、 本文參考的文章

作者:夜千尋墨 - AVPlayer
作者:SomeBoy - iOS開發(fā)AVPlayer深入淺出
作者:KenshinCui iOS開發(fā)系列--音頻播放、錄音嚼松、視頻播放嫡良、拍照、視頻錄制

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末献酗,一起剝皮案震驚了整個濱河市寝受,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌罕偎,老刑警劉巖很澄,帶你破解...
    沈念sama閱讀 222,681評論 6 517
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異颜及,居然都是意外死亡甩苛,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,205評論 3 399
  • 文/潘曉璐 我一進店門俏站,熙熙樓的掌柜王于貴愁眉苦臉地迎上來讯蒲,“玉大人,你說我怎么就攤上這事肄扎∧郑” “怎么了?”我有些...
    開封第一講書人閱讀 169,421評論 0 362
  • 文/不壞的土叔 我叫張陵犯祠,是天一觀的道長旭等。 經(jīng)常有香客問我,道長衡载,這世上最難降的妖魔是什么搔耕? 我笑而不...
    開封第一講書人閱讀 60,114評論 1 300
  • 正文 為了忘掉前任,我火速辦了婚禮月劈,結果婚禮上度迂,老公的妹妹穿的比我還像新娘。我一直安慰自己猜揪,他們只是感情好惭墓,可當我...
    茶點故事閱讀 69,116評論 6 398
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著而姐,像睡著了一般腊凶。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上拴念,一...
    開封第一講書人閱讀 52,713評論 1 312
  • 那天钧萍,我揣著相機與錄音,去河邊找鬼政鼠。 笑死风瘦,一個胖子當著我的面吹牛,可吹牛的內容都是我干的公般。 我是一名探鬼主播万搔,決...
    沈念sama閱讀 41,170評論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼官帘!你這毒婦竟也來了瞬雹?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 40,116評論 0 277
  • 序言:老撾萬榮一對情侶失蹤刽虹,失蹤者是張志新(化名)和其女友劉穎酗捌,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體涌哲,經(jīng)...
    沈念sama閱讀 46,651評論 1 320
  • 正文 獨居荒郊野嶺守林人離奇死亡胖缤,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 38,714評論 3 342
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了阀圾。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片草姻。...
    茶點故事閱讀 40,865評論 1 353
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖稍刀,靈堂內的尸體忽然破棺而出撩独,到底是詐尸還是另有隱情,我是刑警寧澤账月,帶...
    沈念sama閱讀 36,527評論 5 351
  • 正文 年R本政府宣布综膀,位于F島的核電站,受9級特大地震影響局齿,放射性物質發(fā)生泄漏剧劝。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 42,211評論 3 336
  • 文/蒙蒙 一抓歼、第九天 我趴在偏房一處隱蔽的房頂上張望讥此。 院中可真熱鬧拢锹,春花似錦、人聲如沸萄喳。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,699評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽他巨。三九已至充坑,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間染突,已是汗流浹背捻爷。 一陣腳步聲響...
    開封第一講書人閱讀 33,814評論 1 274
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留份企,地道東北人也榄。 一個月前我還...
    沈念sama閱讀 49,299評論 3 379
  • 正文 我出身青樓,卻偏偏與公主長得像司志,于是被迫代替她去往敵國和親手蝎。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 45,870評論 2 361

推薦閱讀更多精彩內容