iOS中集成ijkplayer

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/u014084081/article/details/83027981

iOS中集成ijkplayer

步骤按照Bilibili/ijkplayer中的要求来:

git clone https://github.com/Bilibili/ijkplayer.git ijkplayer-ios
cd ijkplayer-ios
git checkout -B latest k0.8.8

./init-ios.sh

cd ios
./compile-ffmpeg.sh clean
./compile-ffmpeg.sh all

# Demo
#     open ios/IJKMediaDemo/IJKMediaDemo.xcodeproj with Xcode
# 
# Import into Your own Application
#     Select your project in Xcode.
#     File -> Add Files to ... -> Select ios/IJKMediaPlayer/IJKMediaPlayer.xcodeproj
#     Select your Application's target.
#     Build Phases -> Target Dependencies -> Select IJKMediaFramework
#     Build Phases -> Link Binary with Libraries -> Add:
#         IJKMediaFramework.framework
#
#         AudioToolbox.framework
#         AVFoundation.framework
#         CoreGraphics.framework
#         CoreMedia.framework
#         CoreVideo.framework
#         libbz2.tbd
#         libz.tbd
#         MediaPlayer.framework
#         MobileCoreServices.framework
#         OpenGLES.framework
#         QuartzCore.framework
#         UIKit.framework
#         VideoToolbox.framework
#
#         ... (Maybe something else, if you get any link error)
#

详细的过程可参考如下的文章:

运行demo过程中遇到的问题:

1.提示./libavutil/arm/asm.S:50:9: error: unknown directive

错误提示

原因是:基于ijkplayer做的直播demo

报错原因是因为xcode对32位的支持弱化了,可以在compile-ffmpeg.sh里面删除armv7 FF_ALL_ARCHS_IOS8_SDK=“arm64 i386 x86_64”
再次执行 ./compile-ffmpeg.sh all

基本使用

可参考:iOS - IJKPlayer二三事

#if DEBUG
    //  设置报告日志
    [IJKFFMoviePlayerController setLogReport:YES];
    //  设置日志的级别为Debug
    [IJKFFMoviePlayerController setLogLevel:k_IJK_LOG_DEBUG];
#else
    //  设置报告日志
    [IJKFFMoviePlayerController setLogReport:NO];
    //  设置日志的级别为Debug
    [IJKFFMoviePlayerController setLogLevel:k_IJK_LOG_DEBUG];
#endif
    
    [IJKFFMoviePlayerController checkIfFFmpegVersionMatch:YES];
    
    // IJKFFOptions 是对视频的配置信息
    IJKFFOptions *options = [IJKFFOptions optionsByDefault];
    
    [options setOptionIntValue:15 forKey:@"max-fps" ofCategory:kIJKFFOptionCategoryPlayer];
    
    //地址:
    // http://devimages.apple.com.edgekey.net/streaming/examples/bipbop_4x3/gear2/prog_index.m3u8
    // rtmp://live.hkstv.hk.lxdns.com/live/hks
    // rtsp://184.72.239.149/vod/mp4://BigBuckBunny_175k.mov

    NSURL *url = [NSURL URLWithString:@"rtsp://184.72.239.149/vod/mp4://BigBuckBunny_175k.mov"];
    
    self.player = [[IJKFFMoviePlayerController alloc] initWithContentURL:url withOptions:options];
    
    self.player.view.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
    
    // 控制视频填充模式
    self.player.scalingMode = IJKMPMovieScalingModeAspectFit;
    
    self.player.view.frame = self.view.bounds;
    
    self.player.shouldAutoplay = YES;
    
    self.view.autoresizesSubviews = YES;
    
    [self.view addSubview:self.player.view];
    
    [self.player prepareToPlay];

效果:
效果

IJK使用通知来反馈播放状态,通常使用的有如下的几个通知:

    /// 准备播放
    [[NSNotificationCenter defaultCenter] addObserver:self
                                             selector:@selector(loadStateDidChange:)
                                                 name:IJKMPMoviePlayerLoadStateDidChangeNotification
                                               object:self.player];
    /// 播放完成或者用户退出
    [[NSNotificationCenter defaultCenter] addObserver:self
                                             selector:@selector(moviePlayBackFinish:)
                                                 name:IJKMPMoviePlayerPlaybackDidFinishNotification
                                               object:self.player];
    /// 准备开始播放了
    [[NSNotificationCenter defaultCenter] addObserver:self
                                             selector:@selector(mediaIsPreparedToPlayDidChange:)
                                                 name:IJKMPMediaPlaybackIsPreparedToPlayDidChangeNotification
                                               object:self.player];
    /// 播放状态改变了
    [[NSNotificationCenter defaultCenter] addObserver:self
                                             selector:@selector(moviePlayBackStateDidChange:)
                                                 name:IJKMPMoviePlayerPlaybackStateDidChangeNotification
                                               object:self.player];

IJKMPMoviePlayerLoadStateDidChangeNotification返回的缓冲的状态,可通过player的loadState属性获取,有如下的几个类型:

  • IJKMPMovieLoadStateUnknown
  • IJKMPMovieLoadStatePlayable
  • IJKMPMovieLoadStatePlaythroughOK – 代表缓冲完成,可以在这里去移除加载视图(Playback will be automatically started in this state when shouldAutoplay is YES)
  • IJKMPMovieLoadStateStalled – 表示正在缓冲中,可以在这个状态下加入加载视图,缓冲动画等(Playback will be automatically paused in this state, if started)

在ZFPlayer中,是这样使用的:

- (void)loadStateDidChange:(NSNotification*)notification {
    IJKMPMovieLoadState loadState = self.player.loadState;
    if ((loadState & IJKMPMovieLoadStatePlayable)) {
        NSLog(@"加载状态变成了缓存数据足够开始播放,但是视频并没有缓存完全");
    } else if ((loadState & IJKMPMovieLoadStatePlaythroughOK)) {
        // 加载完成,即将播放,停止加载的动画,并将其移除
        NSLog(@"加载状态变成了已经缓存完成,如果设置了自动播放, 会自动播放");
    } else if ((loadState & IJKMPMovieLoadStateStalled)) {
        // 可能由于网速不好等因素导致了暂停,重新添加加载的动画
        NSLog(@"网速不好等因素导致了暂停");
    } else {
        NSLog(@"加载状态变成了未知状态");
    
    }
}

IJKMPMediaPlaybackIsPreparedToPlayDidChangeNotification会在准备播放完毕后调用

// 准备开始播放了
- (void)mediaIsPreparedToPlayDidChange:(NSNotification *)notification {
    ZFPlayerLog(@"加载状态变成了已经缓存完成,如果设置了自动播放, 会自动播放");
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.4 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        self.loadState = ZFPlayerLoadStatePlaythroughOK;
    });
    [self play];
    self.muted = self.muted;
    ZFPlayerLog(@"mediaIsPrepareToPlayDidChange");
    if (self.playerPrepareToPlay) self.playerReadyToPlay(self, self.assetURL);
}

IJKMPMoviePlayerPlaybackStateDidChangeNotification会返回播放状态,通过playbackState获取播放的状态,有如下的值:

typedef NS_ENUM(NSInteger, IJKMPMoviePlaybackState) {
    IJKMPMoviePlaybackStateStopped,
    IJKMPMoviePlaybackStatePlaying,
    IJKMPMoviePlaybackStatePaused,
    IJKMPMoviePlaybackStateInterrupted,
    IJKMPMoviePlaybackStateSeekingForward,
    IJKMPMoviePlaybackStateSeekingBackward
};

ZFPlayer中实现如下:

// 播放状态改变
- (void)moviePlayBackStateDidChange:(NSNotification *)notification {
    if (self.player.playbackState == IJKMPMoviePlaybackStatePlaying) {
        // 视频开始播放的时候开启计时器
        if (!self.timer) {
            self.timer = [NSTimer scheduledTimerWithTimeInterval:0.5 target:self selector:@selector(update) userInfo:nil repeats:YES];
            [[NSRunLoop mainRunLoop] addTimer:self.timer forMode:NSRunLoopCommonModes];
        }
    }
    
    switch (self.player.playbackState) {
        case IJKMPMoviePlaybackStateStopped: {
            ZFPlayerLog(@"播放器的播放状态变了,现在是停止状态 %d: stoped", (int)_player.playbackState);
            // 这里的回调也会来多次(一次播放完成, 会回调三次), 所以, 这里不设置
            self.playState = ZFPlayerPlayStatePlayStopped;
        }
            break;
            
        case IJKMPMoviePlaybackStatePlaying: {
            ZFPlayerLog(@"播放器的播放状态变了,现在是播放状态 %d: playing", (int)_player.playbackState);
            self.playState = ZFPlayerPlayStatePlaying;
            if (self.seekTime) {
                [self seekToTime:self.seekTime completionHandler:nil];
                self.seekTime = 0; // 滞空, 防止下次播放出错
                [self play];
            }
        }
            break;
            
        case IJKMPMoviePlaybackStatePaused: {
            ZFPlayerLog(@"播放器的播放状态变了,现在是暂停状态 %d: paused", (int)_player.playbackState);
        }
            break;
            
        case IJKMPMoviePlaybackStateInterrupted: {
            ZFPlayerLog(@"播放器的播放状态变了,现在是中断状态 %d: interrupted", (int)_player.playbackState);
        }
            break;
            
        case IJKMPMoviePlaybackStateSeekingForward: {
            ZFPlayerLog(@"播放器的播放状态变了,现在是向前拖动状态:%d forward",(int)self.player.playbackState);
        }
            break;
        case IJKMPMoviePlaybackStateSeekingBackward: {
            ZFPlayerLog(@"放器的播放状态变了,现在是向后拖动状态 %d: backward", (int)_player.playbackState);
        }
            break;
            
        default: {
            ZFPlayerLog(@"播放器的播放状态变了,现在是未知状态 %d: unknown", (int)_player.playbackState);
        }
            break;
    }
}

IJKMPMoviePlayerPlaybackDidFinishNotification返回的是播放结束

/// 播放完成
- (void)moviePlayBackFinish:(NSNotification *)notification {
    int reason = [[[notification userInfo] valueForKey:IJKMPMoviePlayerPlaybackDidFinishReasonUserInfoKey] intValue];
    switch (reason) {
        case IJKMPMovieFinishReasonPlaybackEnded: {
            ZFPlayerLog(@"playbackStateDidChange: 播放完毕: %d\n", reason);
            self.playState = ZFPlayerPlayStatePlayStopped;
            if (self.playerDidToEnd) self.playerDidToEnd(self);
        }
            break;
            
        case IJKMPMovieFinishReasonUserExited: {
            ZFPlayerLog(@"playbackStateDidChange: 用户退出播放: %d\n", reason);
        }
            break;
            
        case IJKMPMovieFinishReasonPlaybackError: {
            ZFPlayerLog(@"playbackStateDidChange: 播放出现错误: %d\n", reason);
            self.playState = ZFPlayerPlayStatePlayFailed;
            if (self.playerPlayFailed) self.playerPlayFailed(self, @(reason));
        }
            break;
            
        default:
            ZFPlayerLog(@"playbackPlayBackDidFinish: ???: %d\n", reason);
            break;
    }
}

猜你喜欢

转载自blog.csdn.net/u014084081/article/details/83027981