ksvc / KSYMediaPlayer_iOS

金山云iOS播放SDK(KSYUN Live Streaming player SDK),支持RTMP HTTP-FLV HLS 协议(supporting RTMP HTTP-FLV HLS protocol),直播延时2-3秒(Living delay 2 or 3 seconds)
http://v.ksyun.com/
Apache License 2.0
561 stars 143 forks source link

首帧 隐藏封面 #82

Closed nyz110 closed 6 years ago

nyz110 commented 6 years ago

播放视频, 在视频首帧渲染的时候,动画的方式隐藏视频封面,发现动画被取消了,导致封面切换到播放,会闪一下,不知道什么问题? 非动画的方式隐藏封面 也是如此

mayudong1 commented 6 years ago

如何操作的呢,能有个示例代码吗,我们这里看看什么效果

nyz110 commented 6 years ago

主要代码如下,在第一帧视频渲染的时候隐藏封面 你可以延迟调用下play 方法,我们是列表滚动结束,手动调的play

-(instancetype)initWithFrame:(CGRect)frame{
    self = [super initWithFrame:frame];
    if (self) {
        [self setupSubViews];
        [self addPlayerObserver];
    }
    return self;
}

-(void)dealloc{
    [self removePlayerObserver];
}

-(void)setupSubViews{
    [self addSubview:self.videoPlayer.view];
    [self.videoPlayer.view mas_makeConstraints:^(MASConstraintMaker *make) {
        make.edges.mas_equalTo(UIEdgeInsetsZero);
    }];

    [self addSubview:self.containerView];
    [self.containerView mas_makeConstraints:^(MASConstraintMaker *make) {
        make.edges.mas_equalTo(UIEdgeInsetsZero);
    }];

    [self.containerView addSubview:self.coverView];
    [self.coverView mas_makeConstraints:^(MASConstraintMaker *make) {
        make.edges.mas_equalTo(UIEdgeInsetsZero);
    }];
    [self layoutIfNeeded];

}

-(void)addPlayerObserver{
    [self setupObservers:self.videoPlayer];
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(appWillResignActive:) name:UIApplicationWillResignActiveNotification object:nil];
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(appDidBecomeActive:) name:UIApplicationDidBecomeActiveNotification object:nil];
}

-(void)removePlayerObserver{

    [[NSNotificationCenter defaultCenter] removeObserver:self];

}

-(void)reloadPlayerUrl:(NSString *)playerUrl coverUrl:(NSString *)coverUrl{

    //暂停播放器
    if (!self.videoPlayer) {
        //播放器未初始化
        return;
    }

    //set cover image
    [self.coverView mmb_setImageWithURL:[NSURL URLWithString:coverUrl] placeholderImage:[MMBangUtil createDefaultO2OImageInView:self.coverView]];

    //转化video url
    playerUrl = [[KSYHTTPProxyService sharedInstance] getProxyUrl:playerUrl newCache:NO];

    if ([self.videoURL isEqualToString:playerUrl] && self.videoURL) {
        //url 一样不播放

        return;
    }

    self.coverView.hidden = NO;
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^(){
        if (self.videoURL) {
            if (self.videoPlayer.isPlaying) {
                [self.videoPlayer pause];
            }
            [self.videoPlayer reset:NO];
        }
        self.videoURL = playerUrl;
        [self.videoPlayer setUrl:[NSURL URLWithString:playerUrl]];

        [self.videoPlayer prepareToPlay];
    });

}

-(BOOL)isPlaying{
    return self.videoPlayer.isPlaying;
}

#pragma mark ---- add player notification

- (void)registerObserver:(NSString *)notification player:(KSYMoviePlayerController*)player {
    [[NSNotificationCenter defaultCenter]addObserver:self
                                            selector:@selector(notifyHandler:)
                                                name:(notification)
                                              object:player];
}

- (void)setupObservers:(KSYMoviePlayerController*)player {
    [self registerObserver:MPMediaPlaybackIsPreparedToPlayDidChangeNotification player:player];
    [self registerObserver:MPMoviePlayerPlaybackStateDidChangeNotification player:player];
    [self registerObserver:MPMoviePlayerPlaybackDidFinishNotification player:player];
    [self registerObserver:MPMoviePlayerLoadStateDidChangeNotification player:player];
    [self registerObserver:MPMoviePlayerFirstVideoFrameRenderedNotification player:player];
    [self registerObserver:MPMoviePlayerFirstAudioFrameRenderedNotification player:player];

}

#pragma mark ---------- notification

- (void)notifyHandler:(NSNotification*)notify {
    if (!self.videoPlayer) {
        return;
    }
    if (MPMediaPlaybackIsPreparedToPlayDidChangeNotification ==  notify.name) {

        [self playerPrepareFinish];

    }
    if (MPMoviePlayerPlaybackStateDidChangeNotification ==  notify.name) {
        NSLog(@"------------------------");
        NSLog(@"player playback state: %ld", (long)self.videoPlayer.playbackState);
        NSLog(@"------------------------");
        [self playerPlayStatusDidChange];

    }
    if (MPMoviePlayerLoadStateDidChangeNotification ==  notify.name) {
        NSLog(@"player load state: %ld", (long)self.videoPlayer.loadState);
        [self playerLoadStatusDidChange];
    }
    if (MPMoviePlayerPlaybackDidFinishNotification ==  notify.name) {
        NSDictionary *userInfo = notify.userInfo;
        MPMovieFinishReason reason = [[userInfo valueForKey:MPMoviePlayerPlaybackDidFinishReasonUserInfoKey] intValue];
        [self playerDidFinishWithReason:reason];
        //结束播放的原因
        if (reason ==  MPMovieFinishReasonPlaybackEnded) {
            NSLog(@"player finish");
        }else if (reason == MPMovieFinishReasonPlaybackError){
            NSLog(@"%@",[NSString stringWithFormat:@"player Error : %@", [userInfo valueForKey:@"error"]]);
        }else if (reason == MPMovieFinishReasonUserExited){
            NSLog(@"player userExited");
        }
    }
    if (MPMoviePlayerFirstVideoFrameRenderedNotification == notify.name)
    {
        [self playerDidBeginRender];
    }
}

-(void)playerDidBeginRender{
    if (!self.coverView.hidden) {
//        self.coverView.hidden = YES;
        [UIView transitionWithView:self.coverView duration:.1 options:UIViewAnimationOptionCurveLinear|UIViewAnimationOptionTransitionCrossDissolve animations:^{
            self.coverView.hidden = YES;
        } completion:^(BOOL finished) {

        }];
    }
}

#pragma mark --------- setter and getter

-(void)setShouldLoop:(BOOL)shouldLoop{
    self.videoPlayer.shouldLoop = shouldLoop;
}

-(void)setFillOrFit:(BOOL)fillOrFit{
    _fillOrFit = fillOrFit;
    if (fillOrFit) {
        self.videoPlayer.scalingMode = MPMovieScalingModeAspectFill;
        self.coverView.contentMode = UIViewContentModeScaleAspectFill;
    } else {
        self.videoPlayer.scalingMode = MPMovieScalingModeAspectFit;
        self.coverView.contentMode = UIViewContentModeScaleAspectFit;
    }
}

-(KSYMoviePlayerController *)videoPlayer{
    if (!_videoPlayer) {
        _videoPlayer = [[KSYMoviePlayerController alloc] initWithContentURL:nil];
        _videoPlayer.shouldLoop = YES;
        _videoPlayer.shouldAutoplay = NO;
        _videoPlayer.shouldEnableKSYStatModule = NO;
        _videoPlayer.bufferTimeMax = bufferDuration;
        _videoPlayer.scalingMode = MPMovieScalingModeAspectFill;
    }
    return _videoPlayer;
}

-(UIView *)containerView{
    if (!_containerView) {
        _containerView = [UIView new];
        _containerView.backgroundColor = [UIColor clearColor];
    }
    return _containerView;
}

-(UIImageView *)coverView{
    if (!_coverView) {
        _coverView = [UIImageView new];
        _coverView.contentMode = UIViewContentModeScaleAspectFit;
        _coverView.layer.masksToBounds = YES;
        _coverView.backgroundColor = [UIColor clearColor];
    }
    return _coverView;
}
nyz110 commented 6 years ago

效果图 test

mayudong1 commented 6 years ago

没有动画效果是你那个duration参数设置的是0.1 我用同样的代码测试了下,没出现闪的现象 不如你检查一下播放的视频的第一帧是不是黑屏,或者换一个其他的视频地址试试,例如rtmp://live.hkstv.hk.lxdns.com/live/hks 这个

nyz110 commented 6 years ago

之前设置duration 5s 也是没有效果的;优化了一下代码 1、列表滚动复用的时候只修改封面信息,滚动结束的时候,再去操作player,更新url 之类的操作,最后播放,之前 在复用的时候更新操作player ,滚动结束播放 2、播放器相关操作都放到主线程中 然后没有闪屏了,滚动也流畅了,感觉 player reset 和 seturl 的调用应该也挺占资源的