VLC集成与使用

作者: Pocket | 来源:发表于2016-07-04 01:59 被阅读7156次

    VLC的集成和使用

    VLC介绍

    VLC Media Player (VideoLAN) 为 Windows、Linux、OS X、Android、iOS、Windows Phone等平台提供一个视频播放器、解码器。它可以播放来自网络、摄像头、磁盘、光驱的文件,支持包括MPEG 1/2/4, H264, VC-1, DivX, WMV, Vorbis, AC3, AAC等格式的解码。在 Windows 和 Linux 上的 VLC 是使用C++/Qt写成,提供了一致的用户体验。同时 VLC 还专门为 OS X 提供了原生版本,OS X 版的 VLC 的用户界面使用Cocoa框架编写,在 OS X 下拥有卓越的原生体验。

    • VLC还有一个非常好的功能——播放那些没有下载完整的视频文件。
    • VLC几乎覆盖所有媒体格式。

    VLC集成

    在iOS下,我们可以很方便的使用VLC,因为它经行了优秀的封装,源码中最核心的部分被封装成了独立的库(MoblieVLVKit.framework库),它是基于FFmpeg,Live555提供完整的媒体播放库,所以整一个库体积还是比较大(目前已经超过600M了),不过并不会太影响App的大小,经行App打包发布的是会自动超级压缩的。经过测试它比使用FFmpeg库仅仅是多7M左右的大小。

    • VLC cocoapods方式集成

    VLC可以有多种的方式安装,目前最简单的方式就是cocoapods安装,以前需要下载源码后经行编译,编译后的还分模拟器版和真机版,最后还得使用lipo 命令经行合并,比较麻烦,这里我就不进行介绍了,因为没必要(喜欢折腾的可以自行搜索相关资料),最终编译得到的结果一样是MoblieVLCKit.framework库,即使项目不允许使用cocoapods,也可以建立空项目后使用cocoapods得到MoblieVLCKit.framework在经行移植。

    • 步骤
    ```objc
    1.在podfile中写入:pod 'MobileVLCKit'
    2.终端执行pod install即可(成功后会在项目里看到MoblieVLCKit.framework库)
    3.添加依赖库:libz.tbd、libbz2.tbd、libiconv.tbd、libstdc++.6.0.9.tbd
    ```
    

    VLC使用

    MoblieVLCKit为我们提供了很多功能接口,不过我们不需要全部了解,只需要懂得几个常用的API接口就可以轻轻松松的写出一个播放器出来。因为它支持定制化UI,所以有心的开发者可以结合漂亮的UI设计一套专属的播放器

    • MoblieVLCKit 常用API介绍
      • VLCMediaPlayer
        VCL对象,管理着播放的开始暂停等操作,有着几个代理方法可以经行状态和时间的监听回调
        
      • VLCMediaPlayer属性
        // 播放设置,比如设置播放路径是本地播放还是网络播放,以及播放的画面映射到哪个View
        
      @property (NS_NONATOMIC_IOSONLY, strong) VLCMedia *media;
      - VLCMediaPlayer方法
      ```objc
      // 开始播放
      -(BOOL)play;
      // 暂停播放
      - (void)pause;
      // 停止播放
      - (void)stop;
      /**
        *快进播放
        *interval:需要快进的秒数
      */
      - (void)jumpForward:(int)interval;
      /**
        *快退播放
        *interval:需要快退的秒数
      */
      - (void)jumpBackward:(int)interval;
      // 短时间的快退(10秒)
      - (void)shortJumpBackward;
      // 短时间的快进(10秒)
      - (void)shortJumpForward;
      /**
        * 以一定倍速播放
        * rate:倍速
      */
      - (void)fastForwardAtRate:(float)rate;
      
      • VLCMediaPlayer代理
        // 播放状态改变的回调
        - (void)mediaPlayerStateChanged:(NSNotification *)aNotification;
        // 播放时间改变的回调
        - (void)mediaPlayerTimeChanged:(NSNotification *)aNotification;
        
    • MoblieVLCKit使用demo

    我就抛砖迎玉贴上自己写的一份播放器demo封装(有时间我在放进github)


    效果预览

    IMG_1717.jpg
    • VLCPlayer.h和VLCPlayer.m(VLC创建)

          //
      //  VLCPlayer.h
      //  VLCDemo
      //
      //  Created by pocket on 16/6/27.
      //  Copyright © 2016年 pocket. All rights reserved.
      //
      
      // VLC播放对象
      #import <Foundation/Foundation.h>
      #import <MobileVLCKit/MobileVLCKit.h>
      #import <UIKit/UIKit.h>
      
      @interface VLCPlayer : NSObject
      /**
       *  VCL对象
       */
      @property (nonatomic, strong) VLCMediaPlayer *player;
      /**
       *  根据路径初始化VCL对象
       *
       *  @param playView 播放承载View
       *  @param path     本地路径
       *
       *  @return VLCPlayer 类
       */
      - (id)initWithView:(UIView *)playView andMediaPath:(NSString *)path;
      /**
       *  根据URL初始化VCL对象
       *
       *  @param playView 播放承载View
       *  @param url      url路径
       *
       *  @return VLCPlayer 类
       */
      - (id)initWithView:(UIView *)playView andMediaURL:(NSURL *)url;
      
      /**
       *  开始播放
       */
      - (void)playMedia;
      /**
       *  暂停播放
       */
      - (void)stopPlaying;
      @end
      
          //
      //  VLCPlayer.m
      //  VLCDemo
      //
      //  Created by pocket on 16/6/27.
      //  Copyright © 2016年 pocket. All rights reserved.
      //
      
      #import "VLCPlayer.h"
      
      @implementation VLCPlayer
      
      - (id)initWithView:(UIView *)playView andMediaPath:(NSString *)path {
          self = [super init];
          if (self) {
              // 创建VCL对象
              _player = [[VLCMediaPlayer alloc] init];
              // 设置VCL播放界面的View
              _player.drawable = playView;
              // 设置需要加载的路径
              VLCMedia *media = [VLCMedia mediaWithPath:path];
              [_player setMedia:media];
          }
          return self;
      }
      
      - (id)initWithView:(UIView *)playView andMediaURL:(NSURL *)url {
          self = [super init];
          if (self) {
              _player = [[VLCMediaPlayer alloc] init];
              _player.drawable = playView;
              // 设置需要加载的url
              VLCMedia *media = [VLCMedia mediaWithURL:url];
              [_player setMedia:media];
          }
          return self;
      }
      
      // 播放
      - (void)playMedia {
          [_player play];
      }
      
      // 暂停
      - (void)stopPlaying {
          [_player stop];
      }
      @end
      
    • VLCViewController.h/VLCViewController.m(播放控制器)

      //  VLCViewController.h
      //  VLCDemo
      //
      //  Created by pocket on 16/6/27.
      //  Copyright © 2016年 pocket. All rights reserved.
      //
      
      // VLC播放控制器
      #import <UIKit/UIKit.h>
      #import "VLCPlayer.h"
      
      @interface VLCViewController : UIViewController
      /**
       *  文件名字
       */
      @property (nonatomic, strong) NSString *playName;
      /**
       *  文件路径(本地资源路径)
       */
      @property (nonatomic, strong) NSString *playPath;
      /**
       *  网络URL路径
       */
      @property (nonatomic, strong) NSURL *playURL;
      
      @property (nonatomic, strong) VLCPlayer *player;
      @end
      
      
      //  VLCViewController.m
      //  VLCDemo
      //
      //  Created by pocket on 16/6/27.
      //  Copyright © 2016年 pocket. All rights reserved.
      //
      #import "VLCViewController.h"
      #import <AVFoundation/AVFoundation.h>
      #import<MobileVLCKit/MobileVLCKit.h>
      #import "VLCPlayerView.h"
      @interface VLCViewController ()<VLCMediaPlayerDelegate>
      /**
       *  VLC承载视图
       */
      @property (nonatomic,strong) VLCPlayerView *vlcPlayerView;
      /**
       *  是否本地路径
       */
      @property (nonatomic,assign) BOOL isLocal;
      /**
       *  视频总时间(秒)
       */
      @property (nonatomic,assign) int videoAllTime;
      /**
       *  当前播放时间(秒)
       */
      @property (nonatomic,assign) int videoCurrentTime;
      /**
       *  当前进度
       */
      @property (nonatomic,assign) float currentProgress;
      /**
       *  菊花加载
       */
      @property (nonatomic,strong) UIActivityIndicatorView *activityView;
      @end
      
      @implementation VLCViewController
      - (void)viewDidLoad {
        [super viewDidLoad];
      
        self.title = self.playName;
        self.videoAllTime = 0;
      
        [self tarnsformView];
        // 添加播放的承载View
        [self addVLCPalyerView];
        // 菊花
        self.activityView = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhiteLarge];
        self.activityView.center = self.vlcPlayerView.center;
        [self.activityView setHidesWhenStopped:YES]; // 旋转时隐藏
        [self.activityView startAnimating]; // 开始旋转
        [self.view addSubview:self.activityView];
        //视频播放
        if (_playPath) { // 本地
            _player = [[VLCPlayer alloc] initWithView:self.vlcPlayerView.playView andMediaPath:_playPath];
            _player.player.delegate = self;
            [_player playMedia]; // 播放
            self.isLocal = YES;
        }
        if (_playURL) { // 网络
            _player = [[VLCPlayer alloc] initWithView:self.vlcPlayerView.playView andMediaURL:_playURL];
            _player.player.delegate = self;
            [_player playMedia];
            self.isLocal = NO;
        }
      

    }

    • (void)dealloc
      {
      [_player stopPlaying];
      _player = nil;
      }
    + (void)initialize
    {
        AVAudioSession *session = [AVAudioSession sharedInstance];
        [session setCategory:AVAudioSessionCategoryPlayback error:nil];
        [session setActive:YES error:nil];
    }
    
    - (void)viewDidAppear:(BOOL)animated {
        [super viewDidAppear:animated];
    
        [self addObserver];
    }
    
    - (void)viewDidDisappear:(BOOL)animated {
        [super viewDidDisappear:animated];
    
        [self removeObserver];
    }
    
    #pragma mark - -- 屏幕旋转控制处理
    // 这里采用假旋转,因为其他界面并不需要支持横屏(缺点是状态栏不支持转动,所以采取presentView方式最好)
    - (void)tarnsformView
    {
        // 旋转view
        self.view.transform = CGAffineTransformMakeRotation(M_PI/2); // 旋转90°
        CGRect frame = [UIScreen mainScreen].applicationFrame; // 获取当前屏幕大小
        // 重新设置所有view的frame
        self.view.bounds = CGRectMake(0, 0,frame.size.height + 20,frame.size.width);
        self.vlcPlayerView.frame = self.view.bounds;
    }
    // 隐藏状态栏显得和谐
    - (BOOL)prefersStatusBarHidden
    {
        return YES;
    }
    
    #pragma mark - -- 播放的承载View的设置
    - (void)addVLCPalyerView
    {
        //承载播放的视图初始化(自定义播放界面可在这里做UI定制)
        self.vlcPlayerView = [[VLCPlayerView alloc] initWithFrame:self.view.bounds];
        // 设置视频名称
        self.vlcPlayerView.videoName = self.playName;
        // 设置播放监听回调
        __weak typeof(self) weakSelf = self;
        self.vlcPlayerView.playBlock = ^(UIButton *playBtn){
            [weakSelf playClick:playBtn];
        };
        // 设置进度条监听回调
        self.vlcPlayerView.changeSliderBlock = ^(UISlider *sliderView){
            [weakSelf changeProgress:sliderView];
        };
        // 设置屏幕锁监听回调
        self.vlcPlayerView.lockBlock = ^(UIButton *lockBtn){
            // 屏幕锁操作逻辑
            // ...后续
        };
        // 设置返回按钮回调
        self.vlcPlayerView.backBlock = ^{
            // 关闭视图控制器
            [weakSelf.player stopPlaying];
            [weakSelf dismissViewControllerAnimated:YES completion:^{
    
            }];
        };
    
        // 左右滑动手势结束回调
        self.vlcPlayerView.endPanGesture = ^(float progress,int type){
            if (type == 4) { // 快退
                [weakSelf.player.player shortJumpBackward];
            } else if (type == 3) { // 快进
                [weakSelf.player.player shortJumpForward];
            }
        };
    
        [self.view addSubview:self.vlcPlayerView];
    }
        #pragma mark - -- vlcPlayerView播放操作
    // 播放(暂停)监听
    - (void)playClick:(UIButton *)playBtn
    {
        if ([_player.player isPlaying]) { // 正在播放
            [_player.player pause]; // 暂停
        } else {
            [_player.player play]; // 播放
        }
    }
    
    // 倍率速度播放(一般很少使用)
    - (void)fastForwardAtRate:(float)rate
    {
        [_player.player fastForwardAtRate:rate];
    }
    // 进度条拖拽
    - (void)changeProgress:(UISlider *)sliderView
    {
        if (!_player.player.isPlaying) { // 防止暂停状态拖动(拖动触发播放)
            [self.vlcPlayerView changePlayBtnState:YES];
            [_player.player play];
        }
        // 根据拖动比例计算开始到播放节点的总秒数
        int allSec = (int)(self.videoAllTime * sliderView.value);
        // 根据当前播放秒数计算需要seek的秒数
        int sec = abs(allSec - self.videoCurrentTime);
        // 如果为获取到时间信息
        if (sec == 0 && allSec == 0) {
            [[AlertViewManager shareInstance] showPromptText:self.view context:CustomLocalizedString(@"未获取到视频总时间,请尝试手势快进", nil) minSize:CGSizeMake(60,44) afterDelay:2.0];
            return;
        }
        NSLog(@"sec:%d",sec);
        if (sec==0) { // 刚好等于视频总时间
            [_player.player stop];
            return;
        }
        if (self.currentProgress<=sliderView.value) { // 快进滑动
            [_player.player jumpForward:sec]; // 快进播放
        } else {
            [_player.player jumpBackward:sec]; // 快退播放
        }
    
    }
    
    #pragma  mark - -- vlcPlayerView时间和进度刷新
    - (void)updateTime
    {
        // 设置剩余时间
        self.vlcPlayerView.remainingTime = [[_player.player remainingTime] stringValue];
        // 设置当前时间
        self.vlcPlayerView.currentTime = [[_player.player time] stringValue];
        // 设置当前进度
        self.vlcPlayerView.sliderValue = [_player.player position];
    }
    
    #pragma mark - -- KVO监听
    // 添加监听
    - (void)addObserver
    {
        // 监听VLC对象属性(时间和播放)
        [_player.player addObserver:self forKeyPath:@"remainingTime" options:0 context:nil];
        [_player.player addObserver:self forKeyPath:@"isPlaying" options:0 context:nil];
    }
    
    // 移除监听
    - (void)removeObserver
    {
        [_player.player removeObserver:self forKeyPath:@"remainingTime"];
        [_player.player removeObserver:self forKeyPath:@"isPlaying"];
    }
    
    // kvo监听回调
    - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSString *,id> *)change context:(void *)context {
    
        // 可以在这里设置显示的时间和进度
        // position:VLCMediaPlayer对象中的进度比例,可用此值设置播放进度
    //    NSLog(@"[_player.player position]:%lf",[_player.player position]);
        // remainingTime:VLCMediaPlayer对象中的剩余时间,stringValue可以转化为时间格式字符串
    //    NSLog(@"[[_player.player remainingTime] stringValue]:%@",[[_player.player remainingTime] stringValue]);
        // time:VLCMediaPlayer对象中的当前时间
    //    NSLog(@"[[_player.player time] stringValue]:%@", [[_player.player time] stringValue]);
    
    //    NSLog(@"剩余的分钟:%@",[[_player.player remainingTime] minuteStringValue]);
    //    NSLog(@"播放的分钟:%@",[[_player.player time] minuteStringValue]);
        // 记录当前进度
        self.currentProgress = [_player.player position];
        // 根据分钟计算播放的秒数(这里不够严格,还得加上秒数)
        self.videoCurrentTime = [[[_player.player time] minuteStringValue] intValue] * 60;
        // 根据剩余时间和已经播放的计算总秒数(这里不够严格,还得加上秒数)
        self.videoAllTime = [[[_player.player remainingTime] minuteStringValue] intValue]*60 + self.videoCurrentTime;
    
        // 有时候获取不到时间(个人想法是结合定时器和进度比例计算总时间等)
        // ...
    
        // 刷新最新时间和播放进度
        [self updateTime];
        // 停止菊花加载
        if (self.activityView.isAnimating) {
            [self.activityView stopAnimating];
        }
    }
    
    #pragma mark - 监听程序进入前台和后台
    #pragma mark - VLCMediaPlayerDelegate
    // 播放状态改变的回调
    - (void)mediaPlayerStateChanged:(NSNotification *)aNotification
    {
        /**
         *  VLCMediaPlayerStateStopped,        //< Player has stopped
         VLCMediaPlayerStateOpening,        //< Stream is opening
         VLCMediaPlayerStateBuffering,      //< Stream is buffering
         VLCMediaPlayerStateEnded,          //< Stream has ended
         VLCMediaPlayerStateError,          //< Player has generated an error
         VLCMediaPlayerStatePlaying,        //< Stream is playing
         VLCMediaPlayerStatePaused          //< Stream is paused
         */
        NSLog(@"mediaPlayerStateChanged");
        NSLog(@"状态:%ld",(long)_player.player.state);
        switch ((int)_player.player.state) {
            case VLCMediaPlayerStateStopped: // 停止播放(播放完毕或手动stop)
            {
                [_player.player stop]; // 手动调用一次停止(一遍再次点击播放)
                [self.vlcPlayerView changePlayBtnState:NO];
                if (self.activityView.isAnimating) {
                    [self.activityView stopAnimating];
                }
            }
                break;
            case VLCMediaPlayerStateBuffering: // 播放中缓冲状态
            {
                // 显示菊花
                if (!self.activityView.isAnimating) {
                    [self.activityView startAnimating];
                }
            }
                break;
            case VLCMediaPlayerStatePlaying: // 被暂停后开始播放
            {
                if (self.activityView.isAnimating) {
                    [self.activityView stopAnimating];
                }
            }
                break;
            case VLCMediaPlayerStatePaused:  // 播放后被暂停
            {
                if (self.activityView.isAnimating) {
                    [self.activityView stopAnimating];
                }
            }
                break;
    
        }
    }
    
    // 播放时间改变的回调
    - (void)mediaPlayerTimeChanged:(NSNotification *)aNotification
    {
    //    NSLog(@"mediaPlayerTimeChanged");
    }
    
    @end
    
    ```
    
    • VLCPlayerView.h/VLCPlayerView.m(播放View设计)

      //
      //  VLCPlayerView.h
      //  VLCDemo
      //
      //  Created by pocket on 16/6/28.
      //  Copyright © 2016年 pocket. All rights reserved.
      //
      
      // VLC播放界面
      #import <UIKit/UIKit.h>
      
      @interface VLCPlayerView : UIView
      /**
       *  承载视频的View
       */
      @property (nonatomic,strong) UIView *playView;
      /**
       *  视频名称
       */
      @property (nonatomic,copy) NSString *videoName;
      /**
       *  剩余时间
       */
      @property (nonatomic,copy) NSString *remainingTime;
      /**
       *  当前时间
       */
      @property (nonatomic,copy) NSString *currentTime;
      /**
       *  当前进度
       */
      @property (nonatomic,assign) float sliderValue;
      /**
       *  返回按钮监听回调
       */
      @property (nonatomic,copy) void (^backBlock)(void);
      /**
       *  屏幕锁监听回调
       */
      @property (nonatomic,copy) void (^lockBlock)(UIButton *lockBtn);
      /**
       *  播放(暂停)监听回调
       */
      @property (nonatomic,copy) void (^playBlock)(UIButton *playBtn);
      /**
       *  进度条监听回调
       */
      @property (nonatomic,copy) void (^changeSliderBlock)(UISlider *sliderView);
      /**
       *  拖动结束监听(progress:幅度,type: 3:右 ,4:左)
       */
      @property (nonatomic,copy) void (^endPanGesture)(float progress,int type);
      /**
       *  变更播放(暂停)按钮状态
       */
      - (void)changePlayBtnState:(BOOL)select;
      @end
      
      
      //
      //  VLCPlayerView.m
      //  VLCDemo
      //
      //  Created by pocket on 16/6/28.
      //  Copyright © 2016年 pocket. All rights reserved.
      //
      
      #import "VLCPlayerView.h"
      #import "CustomSlider.h"
      
      #define titleFontSize 15.0
      #define titleColor [UIColor whiteColor]
      #define backgroundViewColor RGB(0, 0, 0, 0.6)
      #define space 15.0
      #define alphaDef 0.5
      #define viewHeight 60.0
      #define gestureMinimumTranslation 20.0
      // 定义滑动手势类型
      typedef enum {
          PlayerMoveDirectionNone = 0,
          PlayerMoveDirectionUp,
          PlayerMoveDirectionDown,
          PlayerMoveDirectionRight,
          PlayerMoveDirectionLeft
      }PlayerMoveDirection;
      
      @interface VLCPlayerView()
      /*********************顶部栏*************************************/
      @property (nonatomic,strong) UIView *topView; // 顶部view
      @property (nonatomic,strong) UIButton *backBtn; // 返回按钮
      @property (nonatomic,strong) UILabel *nameLabel; // 名字
      
      /*********************底部栏*************************************/
      @property (nonatomic,strong) UIView *bottomView;// 底部View
      // 开始播放(暂停)按钮
      @property (nonatomic,strong) UIButton *playBtn;
      @property (nonatomic,strong) CustomSlider *sliderView; // 滑动条
      // 当前时间标签
      @property (nonatomic,strong) UILabel *currentTimeLabel;
      // 结束时间标签
      @property (nonatomic,strong) UILabel *endTimeLabel;
      
      /*********************快进/快退显示********************************/
      @property (nonatomic,strong) UIView *baseView;// 快进/快退底View
      @property (nonatomic,strong) UIButton *changeBtn;
      @property (nonatomic,strong) UILabel *progressTitle;
      @property (nonatomic,strong) UIProgressView *progressView;
      
      // 屏幕锁
      @property (nonatomic,strong) UIButton *lockBtn;
      
      // sliderView是否正在滑动
      @property (nonatomic,assign) BOOL isSliding;
      
      // 滑动手势类型
      @property (nonatomic,assign) PlayerMoveDirection moveDirection;
      // 开始拖动的位置
      @property (nonatomic,assign) CGPoint beginPoint;
      // 当前拖动的位置
      @property (nonatomic,assign) CGPoint currentPoint;
      @end
      
      @implementation VLCPlayerView
      
      - (instancetype)initWithFrame:(CGRect)frame
      {
          if (self = [super initWithFrame:frame]) {
              [self setUI];
              // 添加手势
              [self addGesture];
      
              // 5秒后自动隐藏
              dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(5.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
                  if (self.topView.alpha>0.0) {
                      [self oneGestureClick];
                  }
              });
          }
      
          return self;
      }
      
      - (void)setUI
      {
          // 承载视频view
          self.playView = [[UIView alloc] init];
          self.playView.backgroundColor = [UIColor blackColor];
          [self addSubview:self.playView];
      
          // 顶部View
          self.topView = [[UIView alloc] init];
          self.topView.backgroundColor = backgroundViewColor;
          [self addSubview:self.topView];
          // 名字
          self.nameLabel = [[UILabel alloc] init];
          self.nameLabel.textColor = titleColor;
          self.nameLabel.textAlignment = NSTextAlignmentCenter;
          self.nameLabel.font = [UIFont systemFontOfSize:titleFontSize];
          [self.topView addSubview:self.nameLabel];
          // 返回按钮
          self.backBtn = [UIButton buttonWithType:UIButtonTypeCustom];
          [self.backBtn setImage:[UIImage imageNamed:@"ic_jt_bf"] forState:UIControlStateNormal];
          [self.backBtn addTarget:self action:@selector(backClick) forControlEvents:UIControlEventTouchUpInside];
          [self.topView addSubview:self.backBtn];
      
          // 底部view
          self.bottomView = [[UIView alloc] init];
          self.bottomView.backgroundColor = backgroundViewColor;
          [self addSubview:self.bottomView];
          // 暂停
          self.playBtn = [UIButton buttonWithType:UIButtonTypeCustom];
          self.playBtn.selected = YES;
          [self.playBtn setImage:[UIImage imageNamed:@"ic_bf_zt"] forState:UIControlStateSelected];
          [self.playBtn setImage:[UIImage imageNamed:@"ic_bf_zt"] forState:UIControlStateNormal];
          [self.playBtn setAdjustsImageWhenHighlighted:NO]; // 设置无高亮状态
          [self.playBtn addTarget:self action:@selector(playBtnClick) forControlEvents:UIControlEventTouchUpInside];
          [self.bottomView addSubview:self.playBtn];
          // 当前标签
          self.currentTimeLabel = [[UILabel alloc] init];
          self.currentTimeLabel.textColor = titleColor;
          self.currentTimeLabel.text = @"--:--";
          self.currentTimeLabel.textAlignment = NSTextAlignmentLeft;
          self.currentTimeLabel.font = [UIFont systemFontOfSize:titleFontSize];
          [self.bottomView addSubview:self.currentTimeLabel];
          // 结束标签
          self.endTimeLabel = [[UILabel alloc] init];
          self.endTimeLabel.textColor = titleColor;
          self.endTimeLabel.text = @"--:--";
          self.endTimeLabel.textAlignment = NSTextAlignmentRight;
          self.endTimeLabel.font = [UIFont systemFontOfSize:titleFontSize];
          [self.bottomView addSubview:self.endTimeLabel];
          // 滑动条
          self.sliderView = [[CustomSlider alloc] init];
          self.sliderView.minimumTrackTintColor = TedcallStorageProgressColor; // 设置滑动过的颜色
          self.sliderView.maximumTrackTintColor = [UIColor grayColor]; // 设置总长度颜色
          self.sliderView.thumbTintColor = RGB(255, 255, 255, 0.7); // 设置滑块颜色
          [self.sliderView addTarget:self action:@selector(slideringListening) forControlEvents:UIControlEventValueChanged];
          [self.sliderView addTarget:self action:@selector(sliderChange) forControlEvents:UIControlEventTouchUpInside];
          [self.bottomView addSubview:self.sliderView];
      
          // 快进/快退view
          self.baseView = [[UIView alloc] init];
          self.baseView.backgroundColor = backgroundViewColor;
          self.baseView.layer.cornerRadius = 8.0;
          self.baseView.layer.masksToBounds = YES;
          self.baseView.alpha = 0.0;
          [self addSubview:self.baseView];
      
          self.changeBtn = [UIButton buttonWithType:UIButtonTypeCustom];
          [self.changeBtn setImage:[UIImage imageNamed:@"ic_kj_bf"] forState:UIControlStateNormal];
          [self.changeBtn setImage:[UIImage imageNamed:@"ic_kt_bf"] forState:UIControlStateSelected];
          [self.baseView addSubview:self.changeBtn];
      
          self.progressTitle = [[UILabel alloc] init];
          self.progressTitle.textColor = titleColor;
          self.progressTitle.textAlignment = NSTextAlignmentCenter;
          self.progressTitle.font = [UIFont systemFontOfSize:titleFontSize];
      //    self.progressTitle.text = @"30秒";
          [self.baseView addSubview:self.progressTitle];
      
          self.progressView = [[UIProgressView alloc] init];
          self.progressView.trackTintColor = [UIColor clearColor];
          self.progressView.progressTintColor = TedcallStorageProgressColor;
          [self.progressView setProgress:0.0];
          [self.baseView addSubview:self.progressView];
      
          // 屏幕锁
          self.lockBtn = [UIButton buttonWithType:UIButtonTypeCustom];
          [self.lockBtn setImage:[UIImage imageNamed:@"ic_sp_bf"] forState:UIControlStateNormal];
          [self.lockBtn setImage:[UIImage imageNamed:@"ic_ks_bf"] forState:UIControlStateSelected];
          [self.lockBtn addTarget:self action:@selector(lockClick) forControlEvents:UIControlEventTouchUpInside];
          [self addSubview:self.lockBtn];
      }
      
      - (void)setVideoName:(NSString *)videoName
      {
          _videoName = videoName;
          self.nameLabel.text = videoName;
      }
      
      - (void)setCurrentTime:(NSString *)currentTime
      {
          _currentTime = currentTime;
          self.currentTimeLabel.text = currentTime;
      }
      
      - (void)setRemainingTime:(NSString *)remainingTime
      {
          _remainingTime = remainingTime;
          self.endTimeLabel.text = remainingTime;
      }
      
      - (void)setSliderValue:(float)sliderValue
      {
          _sliderValue = sliderValue;
          if (!self.isSliding) { // 防止滑动过程中的手动设值
              [self .sliderView setValue:sliderValue animated:YES];
          }
      }
      
      // 返回按钮监听
      - (void)backClick
      {
          if (self.backBlock) {
              self.backBlock(); // block返回回调
          }
      }
      
      // 播放(暂停)监听
      - (void)playBtnClick
      {
          NSLog(@"twoGesture");
          self.playBtn.selected = !self.playBtn.selected;
          [self changePlayBtnState:self.playBtn.selected];
          if (self.playBlock) {
              self.playBlock(self.playBtn);
          }
      }
      
      // 屏幕锁监听
      - (void)lockClick
      {
          self.lockBtn.selected = !self.lockBtn.selected;
          if (self.lockBtn.selected) {
              self.playView.userInteractionEnabled = NO;
              [UIView transitionWithView:self.lockBtn duration:1.0 options:0 animations:^{
                  self.topView.alpha = 0.0;
                  self.bottomView.alpha = 0.0;
                  self.lockBtn.alpha = 0.0;
              } completion:^(BOOL finished) {
      
              }];
          } else {
              self.topView.alpha = 1.0;
              self.bottomView.alpha = 1.0;
              self.playView.userInteractionEnabled = YES;
              dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(5.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
                  [UIView transitionWithView:self.lockBtn duration:1.0 options:0 animations:^{
                      self.topView.alpha = 0.0;
                      self.bottomView.alpha = 0.0;
                      self.lockBtn.alpha = 0.0;
                  } completion:^(BOOL finished) {
      
                  }];
              });
          }
      }
      
      - (void)changePlayBtnState:(BOOL)select
      {
          self.playBtn.selected = select;
          if (select) {
              [self.playBtn setImage:[UIImage imageNamed:@"ic_bf_zt"] forState:UIControlStateNormal];
          } else {
              [self.playBtn setImage:[UIImage imageNamed:@"ic_bf_ks"] forState:UIControlStateNormal];
          }
      }
      
      // 滑动结束监听
      - (void)sliderChange
      {
      //    NSLog(@"滑动结束");
          self.isSliding = NO;
          if (self.changeSliderBlock) {
              self.changeSliderBlock(self.sliderView);
          }
      }
      
      // 滑动监听
      - (void)slideringListening
      {
      //    NSLog(@"正在滑动");
          if (!self.isSliding) {
              self.isSliding = YES;
          }
      
      }
      
      - (void)layoutSubviews
      {
          [super layoutSubviews];
      
          CGFloat width = self.frame.size.width;
          CGFloat height = self.frame.size.height;
      
          // 承载视频View
          self.playView.frame = self.bounds;
      
          // 顶部view
          CGFloat topX = 0;
          CGFloat topY = 0;
          CGFloat topW = width;
          CGFloat topH = viewHeight - 10;
          self.topView.frame = CGRectMake(topX, topY, topW, topH);
          // 返回按钮
          CGFloat backW = 30.0;
          CGFloat backH = backW;
          CGFloat backX = space;
          CGFloat backY = (topH - backH)/2;
          self.backBtn.frame = CGRectMake(backX, backY, backW, backH);
          // 视频名称
          CGFloat nameX = space + CGRectGetMaxX(self.backBtn.frame);
          CGFloat nameH = 20.0;
          CGFloat nameW = width - 2*nameX;
          CGFloat nameY = (topH - nameH)/2;
          self.nameLabel.frame = CGRectMake(nameX, nameY, nameW, nameH);
          // 底部view
          CGFloat bottomX = 0;
          CGFloat bottomY = height - viewHeight;
          CGFloat bottomW = width;
          CGFloat bottomH = viewHeight;
          self.bottomView.frame = CGRectMake(bottomX, bottomY, bottomW, bottomH);
          // 播放(暂停)按钮
          CGFloat playW = 40.0;
          CGFloat playH = playW;
          CGFloat playX = space;
          CGFloat playY = (viewHeight - playH)/2;
          self.playBtn.frame = CGRectMake(playX, playY, playW, playH);
          // 滑动条
          CGFloat sliderX = space + CGRectGetMaxY(self.playBtn.frame);
          CGFloat sliderH = 6;
          CGFloat sliderW = width - sliderX - space;
          CGFloat sliderY = playY + playH/2 - 4;
          self.sliderView.frame = CGRectMake(sliderX, sliderY, sliderW, sliderH);
          // 当前标签
          CGFloat currentX = sliderX;
          CGFloat currentY = CGRectGetMaxY(self.sliderView.frame);
          CGFloat currentH = 20.0;
          CGFloat currentW = sliderW/2;
          self.currentTimeLabel.frame = CGRectMake(currentX, currentY, currentW, currentH);
          // 结束标签
          CGFloat endW = currentW;
          CGFloat endX = CGRectGetMaxX(self.sliderView.frame) - endW;
          CGFloat endY = currentY;
          CGFloat endH = currentH;
          self.endTimeLabel.frame = CGRectMake(endX, endY, endW, endH);
      
          // 快进/快退view
          CGFloat baseW = 140.0;
          CGFloat baseH = 74.0;
          CGFloat baseY = CGRectGetMaxY(self.topView.frame) + 20.0;
          CGFloat baseX = (width - baseW)/2;
          self.baseView.frame = CGRectMake(baseX, baseY, baseW, baseH);
      
          CGFloat changeW = 30.0;
          CGFloat changeH = 20.0;
          CGFloat changeX = (baseW - changeW)/2;
          CGFloat changeY = 8.0;
          self.changeBtn.frame = CGRectMake(changeX, changeY, changeW, changeH);
      
          CGFloat titleY = 8.0 + CGRectGetMaxY(self.changeBtn.frame);
          CGFloat titleX = 0;
          CGFloat titleW = baseW;
          CGFloat titleH = 20.0;
          self.progressTitle.frame = CGRectMake(titleX, titleY, titleW, titleH);
      
          CGFloat progressX = 3.0;
          CGFloat progressY = 8.0 + CGRectGetMaxY(self.progressTitle.frame);
          CGFloat progressW = baseW - 2*progressX;
          CGFloat progressH = 0.0;
          self.progressView.frame = CGRectMake(progressX, progressY, progressW, progressH);
      
          // 屏幕锁
          CGFloat lockX = space;
          CGFloat lockW = 50.0;
          CGFloat lockH = 50.0;
          CGFloat lockY = (height - lockH)/2;
          self.lockBtn.frame = CGRectMake(lockX, lockY, lockW, lockH);
      }
      #pragma mark - -- 手势操作
      - (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
      {
          NSLog(@"touchesBegan");
          if (self.lockBtn.selected) { // 锁屏状态
              [UIView transitionWithView:self.lockBtn duration:1.0 options:0 animations:^{
                  self.lockBtn.alpha = 1.0;
              } completion:^(BOOL finished) {
                  dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(5.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
                      if (self.lockBtn.selected) {
                          [UIView transitionWithView:self.lockBtn duration:1.0 options:0 animations:^{
                              self.lockBtn.alpha = 0.0;
                          } completion:^(BOOL finished) {
      
                          }];
                      }
                  });
              }];
          }
      }
      // 添加手势处理
      - (void)addGesture
      {
          // 单点
          UITapGestureRecognizer *oneGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(oneGestureClick)];
          oneGesture.numberOfTapsRequired = 1; // 单击
          oneGesture.numberOfTouchesRequired = 1; // 单指单击
          [self.playView addGestureRecognizer:oneGesture];
      
          // 双击
          UITapGestureRecognizer *twoGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(playBtnClick)];
          twoGesture.numberOfTapsRequired = 2; // 双击
          twoGesture.numberOfTouchesRequired = 1; // 单指双击
          [self.playView addGestureRecognizer:twoGesture];
      
          // 长按
          UILongPressGestureRecognizer *longGesture = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(longGestureClick:)];
          longGesture.minimumPressDuration = 3.0; // 长按3秒触发
          [self.playView addGestureRecognizer:longGesture];
      
          // 拖动
          UIPanGestureRecognizer *panGesture = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(panGestureClick:)];
          [self.playView addGestureRecognizer:panGesture];
      
          //解决拖动和长按手势之间的冲突
          [longGesture requireGestureRecognizerToFail:panGesture];
          // 解决单击和双击手势的冲突
          [oneGesture requireGestureRecognizerToFail:twoGesture];
      }
      // 单击手势监听
      - (void)oneGestureClick
      {
          NSLog(@"oneGestureClick");
          if (self.topView.alpha<=0.0) { // 显示
              // 动画显示
              [UIView transitionWithView:self.topView duration:1.0 options:0 animations:^{
                  self.topView.alpha = 1.0;
                  self.bottomView.alpha = 1.0;
                  self.lockBtn.alpha = 1.0;
              } completion:^(BOOL finished) {
                  // 5秒后自动隐藏
                  dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(5.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
                      if (self.topView.alpha>0.0) {
                          [self oneGestureClick];
                      }
                  });
              }];
          } else {
              // 动画隐藏
              [UIView transitionWithView:self.topView duration:1.0 options:0 animations:^{
                  self.topView.alpha = 0.0;
                  self.bottomView.alpha = 0.0;
                  self.lockBtn.alpha = 0.0;
              } completion:^(BOOL finished) {
      
              }];
          }
      }
      
      // 长按监听
      - (void)longGestureClick:(UILongPressGestureRecognizer *)longGesture
      {
          // 长按手势会调用多次监听方法,先判断手势状态
          if (longGesture.state == UIGestureRecognizerStateBegan) {
              NSLog(@"长按开始");
          }
      }
      
      // 拖动监听
      - (void)panGestureClick:(UIPanGestureRecognizer *)panGesture
      {
          CGPoint translation = [panGesture translationInView:self.playView]; // 取得相对位置的偏移点(相对位置为手指第一次在屏幕的点)
          NSLog(@"translation:%@",NSStringFromCGPoint(translation));
          if (panGesture.state == UIGestureRecognizerStateBegan){
              NSLog (@"滑动开始");
              self.beginPoint = translation;
              self.currentPoint = translation;
          }else if (panGesture.state == UIGestureRecognizerStateChanged){
              self.moveDirection = [self determineCameraDirectionIfNeeded:translation];
              switch (self.moveDirection) {
                  case PlayerMoveDirectionDown:
                      NSLog(@"PlayerMoveDirectionDown");
                      break;
                  case PlayerMoveDirectionUp:
                      NSLog(@"PlayerMoveDirectionUp");
                      break;
                  case PlayerMoveDirectionRight:
                  {
                      NSLog(@"PlayerMoveDirectionRight");
                      self.changeBtn.selected = NO;
                      self.progressTitle.text = CustomLocalizedString(@"快进", nil);
                      if (self.baseView.alpha == 0.0) {
                          self.baseView.alpha = 1.0;
                      }
                  }
                      break;
                  case PlayerMoveDirectionLeft:
                  {
                      NSLog(@"PlayerMoveDirectionLeft");
                      self.changeBtn.selected = YES;
                      self.progressTitle.text = CustomLocalizedString(@"快退", nil);
                      if (self.baseView.alpha == 0.0) {
                          self.baseView.alpha = 1.0;
                      }
                  }
                      break;
                  default :
                      break;
              }
              self.currentPoint = translation; // 刷新当前位置
      
          }else if (panGesture.state == UIGestureRecognizerStateEnded){
              NSLog (@"滑动结束");
              [UIView transitionWithView:self.baseView duration:1.0 options:0 animations:^{
                  self.baseView.alpha = 0.0;
              } completion:^(BOOL finished) {
      
              }];
              if (self.endPanGesture) {
                  self.endPanGesture(0.5,self.moveDirection);
              }
          }
      }
      
      - (PlayerMoveDirection) determineCameraDirectionIfNeeded:(CGPoint)translation
      {
          // 设定一个幅度使拖动在不够水平(略微有点偏差)的方向上的处理,上下一般不处理
          if (translation.x > self.currentPoint.x && (fabs(translation.y - self.currentPoint.y) <= gestureMinimumTranslation)){ // 说明水平向右拖动了
              return PlayerMoveDirectionRight;
          }else if(translation.x < self.currentPoint.x && (fabs(translation.y - self.currentPoint.y) <= gestureMinimumTranslation)){ // 说明水平向左
              return PlayerMoveDirectionLeft;
          }else if (translation.x == self.currentPoint.x && translation.y > self.currentPoint.y) { // 向下
              return PlayerMoveDirectionDown;
          } else if (translation.x == self.currentPoint.x && translation.y < self.currentPoint.y) { // 向上
              return PlayerMoveDirectionUp;
          } else{
              return PlayerMoveDirectionNone;
          }
      }
      
      - (void)updateFastImage:(int)type
      {
          if (type == 4) { // 左
      
          } else if (type == 3) { // 右
      
          }
      }
      
      @end
      
      
    • CustomSlider.h/CustomSlider.m(自定义滑块)

      //
      //  CustomSlider.h
      //  TedcallStorage
      //
      //  Created by  tedcall on 16/6/28.
      //  Copyright © 2016年 pocket. All rights reserved.
      //
      
      #import <UIKit/UIKit.h>
      
      @interface CustomSlider : UISlider
      
      @end
      
      
      //
      //  CustomSlider.m
      //  TedcallStorage
      //
      //  Created by  tedcall on 16/6/28.
      //  Copyright © 2016年 pocket. All rights reserved.
      //
      
      #import "CustomSlider.h"
      
      @implementation CustomSlider
      
      - (void)drawRect:(CGRect)rect
      {
          UIImageView *imageView = nil;
          // 取得滑块View
          for (UIView *view in self.subviews) {
              if ([view isKindOfClass:[UIImageView class]]) {
                  if (view.frame.size.width == view.frame.size.height) {
                      imageView = (UIImageView *)view;
                  }
              }
          }
      
          if (imageView) { // 有值
              CGFloat redViewW = 8.0;
              CGFloat redViewH =redViewW;
              CGFloat redViewX = (imageView.frame.size.width - redViewW)/2;
              CGFloat redViewY = (imageView.frame.size.height - redViewH)/2;
              UIView *redView = [[UIView alloc] initWithFrame:CGRectMake(redViewX, redViewY, redViewW, redViewH)];
              redView.backgroundColor = RGB(255, 255, 255, 0.7);
              redView.layer.cornerRadius = redViewW/2;
              redView.layer.masksToBounds = YES;
              [imageView addSubview:redView];
          }
      }
      
      // 重写进度条frame
      - (CGRect)trackRectForBounds:(CGRect)bounds {
          return CGRectMake(0,0,bounds.size.width,6.0);
      }
      
      // 解决两边空隙问题
      - (CGRect)thumbRectForBounds:(CGRect)bounds trackRect:(CGRect)rect value:(float)value
      {
          rect.origin.x = rect.origin.x - 10 ;
          rect.size.width = rect.size.width +20;
          return CGRectInset ([super thumbRectForBounds:bounds trackRect:rect value:value], 10 , 10);
      }
      
      @end
      
      

    VLC Demo

    因为VLC库比较大所以github 上的demo里并不包含这个库以及测试时的视频。我另外提供了下载地址供需要的朋友自行下载。
    demo地址:https://github.com/pocket-live/VLC-Demo
    VLC库和测试资源下载地址:http://pan.baidu.com/s/1pLiBQKb

    相关文章

      网友评论

      • zhhehj:VLC rtsp监控有卡顿延迟怎么解决
      • 这小歌不错:你好,视频播放完后,拖动slider设置position,视频无变化你遇到过嘛?
      • Bana:你好,vlc 不能实时播放 h264 的编码格式吗
      • 豆哥笔记:只有声音 没有画面 楼主知道怎么解决吗
      • 07306af72d6e:在Xcode9 下面加入VLC报错。编译错误
      • 07306af72d6e:报错什么因素
      • 伊织随意写:自己写了个demo,使用play可以播放,但是使用 pause 和 stop后,没有暂停和停止,只是停顿了一下又继续播放了。不清楚为什么。
        用你的demo,就跑的好好地。
        伊织随意写:@Pocket 嗯,是代码不小心的问题。
        不过我发现我和你的demo中,mediaPlayerStateChanged 这个代理方法都走了,但是里面要打印的内容,没有打印出来,你运行时有没有这个问题?
        Pocket:@MelissaShu 好好检查一下代码就好了:blush:
      • c75e79a64f03:打包出现问题 The app references non-public symbols in ****: _locale_charset 是libconv.tbd中出现的“_locale_charset ”,是VLC引用了私有APi了吗?请问该如何解决。
        这个熊孩子不太冷:你好,你解决了吗
      • a076f21b5dc3:iOS11 播放不了
        a076f21b5dc3:avcodec decoder error: more than 5 seconds of late video -> dropping frame (computer too slow ?)
      • 颜思齐:终于找到你的博客啦,昨天看了好几个博客还是觉得你写的比较清晰明了,demo封的也不错,特意来评论感谢下。(framework太大了下了好久,自己编译半天没成功,一会研究下怎么编译取)
      • 62de48dd0dc0:你好,请问下,我在Android 7.0手机上运行为什么会出现黑框了?
      • LightReason:收藏下
      • 最后还是个农:请教下,播放url失败后VLC会有一个弹框提示,这个在哪去掉,找了半天,没有看到,求指教
        辣椒小鱼:请教下 这个弹框 vlc 怎么去掉???
        最后还是个农:@Pocket 好的,非常感谢:smile:
        Pocket:我有时间去看看啊,有可能是写库的人写进去的,没去掉,没找到怕是要自己编译了。
      • Pocket:统一回复需要demo的,demo和库的下载地址链接已经放到文章最底部了,请自行下载,下载完库后放进工程目录即可:blush: ,demo写的不好勿怪啊,只是作为参考。
        ZJS_Sky:谢谢了
      • c4badbcad3f3:复制楼主的 有声音但是图片卡着不动
      • 梅素内:楼主请问一下我是完全按照你上面的代码复制粘贴的,但是它有一个错误提示[[AlertViewManager shareInstance] showPromptText:self.view context:CustomLocalizedString(@"未获取到视频总时间,请尝试手势快进", nil) minSize:CGSizeMake(60,44) afterDelay:2.0];这句话中的AlertViewManager没有定义
      • ducks:https 的mp3 能播放吗 自建证书
      • 大斜的张:终端一直下载不动 MobileVLCKit 楼主能分享个VLCKit包吗
        ZJS_Sky:@ACFl_l 用pod 试试 pod 'MobileVLCKit'
        ACFl_l:你好,请问你拿到那VLC包了么,我这边也是下载不动,能分享一下么
      • PointOne:楼主 M3u8格式你能看么 我怎么看不了啊
      • 3e940d9945b3:我想问一下多个视频同时播放,各个的视频的声音怎么控制
      • 傲雪秋风:你好,请问VLC能够获取 缓冲进度及缓冲速度吗?如果能,如何获取呢。查了好多资料。有的说API没有开放,有的就没说缓冲的事。
        5f3040a1cc26:请问一下你获取缓冲进度实现了吗,VLC好像没有这个接口啊,不知能否赐教,谢谢。。这都18年了,还是找不到获取缓冲进度的方法
      • 云画的跃光:請問這個錯誤是什麼?我是用服務器傳過來的rtsp流
        creating player instance using shared library
        [1cbb9c44] core generic error: option marq-color does not exist
        [1cbb9c44] core generic error: option marq-opacity does not exist
        [1cbb9c44] core generic error: option marq-position does not exist
        [1cbb9c44] core generic error: option marq-refresh does not exist
        [1cbb9c44] core generic error: option marq-size does not exist
        [1cbb9c44] core generic error: option marq-timeout does not exist
        [1cbb9c44] core generic error: option marq-x does not exist
        [1cbb9c44] core generic error: option marq-y does not exist
        [1da3f064] live555 demux error: Failed to connect with rtsp://10.160.83.246:1935/G_LIVE/T0022
        [1cbbde04] core input error: open of `RTSP://10.160.83.246:1935/G_LIVE/T0022' failed
      • 云画的跃光:你好,我想請問下,從服務器得到的地址怎麼傳到播放器去
        62de48dd0dc0:你好,请问下,为什么我集成进去了画面预览在Android7.0下面会出现黑框了?
        云画的跃光:@Pocket rest://什麼的?但是我從服務器得到的是這個,在那裡報錯的是:rtsp:/,變成單斜杆了
        Pocket:@云画的跃光 具体得到的是什么协议的URL呢
      • 杰克道长:我播放网络视频时,为什么画面总会很卡?
        ZJS_Sky:@Pocket 延迟调高什么操作
        Pocket:@杰克道长 具体是什么格式的视频呢,有些格式如果碰到比较卡或者花屏需要稍微把延迟调高一些,使其得到足够的缓存在解码,这样就不容易掉帧。
      • 晓_我想去环游世界:好像不是支持很多格式 视频监控的一个地址rtsp://218.204.223.237:554/live/1/66251FC11353191F/e7ooqwcfbqjoo80j.sdp
        不知道是播放器的问题还是配置问题
        Pocket:@晓_我想去环游世界 后缀是sdp,不知道是什么格式的流,一般内部对格式判断是用文件路径后缀来决定解码器的类型。
      • 银千特iv:是不是进度条及一些时间的状态放delegate里面更新会好一点啊?
        Pocket:@银千特iv 你觉得好可以试着去增加几个代理方法,这个只是抛砖引玉。
      • iOSNoteByNiu:请问楼主,我在做视频的实时监控,VLC播放器与系统的播放器有什么区别吗
        Pocket:@veryGood 那得问你们后台用什么协议传输
        iOSNoteByNiu:@Pocket 哦,实现监控视频的实时播放时,后台给我的视频地址也是类似于以http开头的吗?就像这个http://flv2.bn.netease.com/tvmrepo/2016/11/7/Q/EC5FO5O7Q/SD/EC5FO5O7Q-mobile.mp4
        Pocket:@veryGood 系统的一般是硬解,不过支持的格式不算很多,VLC内部集成了FFMpeg和Live555,是软解,不过基本大部分格式都支持。
      • 晓_我想去环游世界:楼主可否给我一份VLC的静态库呢?990610967@qq.com
        Pocket:@晓_我想去环游世界 静态库有点大,不好发,你自己cocoapods也很快的
      • f324138e5762:请问楼主用这个打包后包的大小增加了多少?3M有没有?
        Pocket:@LimyronChin 整一个lib都几百M,打包后我也忘了增加具体多少M了,不过肯定不止3M吧,印象中打包后的app总大小可以接受。
      • bdb6bf9183c5:还有就是如果我在option这里把host和port设置了。那我启动的时候还用不用传uri
      • bdb6bf9183c5:我是这么设置的 options.add("--rtsp-tcp"); 另外这个文档我也都看过一遍都试过了,。设置port那个命令也试过。没起作用。不知道是option没添加进去还是本身就没用
      • bdb6bf9183c5:能加个qq么530400138,详细说下、 :smile:
      • bdb6bf9183c5:问下楼主。最近在做行车记录仪的对接。android的。一个是rtsp的一个是tcp的。试过vlc,tcp怎么也连接不上,后来改用ijkplayer,虽然2总方式都能播放但是延迟好长,10几秒的延迟。不知道楼主有什么解决办法?vlc 应该支持tcp的吧,应该是我代码设置不对的。所有2个问题:1:Vcl能实现tcp 播放视频流么?2:ijkplayer 怎么降低延迟。
        Pocket:不好意思,那个参数写错了,你改成--rtsp-tcp,vlc貌似一般都基于udp ,所以主动开启一下基于tcp方式
        bdb6bf9183c5:@Pocket rtsp-tcp 我试过。貌似不行。现在问题就是。流地址能够connnect,并且open,然后就没有然后了。我现在还是倾向于解决vlc显示tcp方式的视频流。各种方式也都试过了,技术有限,项目又急,楼主有时间能研究下不。
        Pocket:@mozzieC 支持tcp,记得在创建对象的时候有一个参数,传的字典,里面你设置对应的rtsp-tcp看看可不可以,延迟的话也有对应参数设置,ijk 里也有相应的设置,不过我没怎么去用这个库,你可以百度一下ijk 延迟问题参数设置,都是基于ffmpeg ,延迟参数应该长的差不多
      • FTC陳:你好,您这个有demo吗?
        Pocket:@ttdiOS 好,前段时间太忙,都没看简书,晚上回去把项目里的功能抽出来写个demo 放github 上:blush:
        ttdiOS:@Pocket 麻烦群主尽快出demo工程,【贴的代码很完整啊,复制一下就好了。】和完整的demo时2码事
        Pocket:@FTC晨 不好意思,有几天没光顾简书,我贴的代码很完整啊,复制一下就好了。
      • 失落柒夏: :sparkling_heart: 你好 我最近刚刚开始研究VLC直播 本身就是iOS小白 想请问能不能发一份Demo给我呢? 1042540668@qq.com 非常感谢~~
        ttdiOS:@JackLiaoSir vlc库需要自己去下载,内存太大,,,demo很简单
        Jack_Liao:@ttdiOS 🐶你好 我最近刚刚开始研究VLC直播 本身就是iOS小白 想请问能不能发一份Demo给我呢? 937902524@qq.com 非常感谢~~😂
        ttdiOS:你好 我最近刚刚开始研究VLC直播 本身就是iOS小白 想请问能不能发一份Demo给我呢? 1107214478@qq.com 非常感谢~~
      • coding_Liu:你好,我最近这在做关于直播的,请问 截屏的功能你了解吗 :stuck_out_tongue_winking_eye:
        afa38ae8399f:@Pocket 我最近也在做这个,您能否加我一下qq,一起研究下,1427945373
        coding_Liu:@Pocket 好,我试一下,我vlc基本上也已经做完了,加一下qq有问题可以相互讨论一下。952626944 :smile:
        Pocket:@听雨翎 截屏我没有真的去实现这个功能,不过我看VLC里有一个方法是保存当前视频的快照。你可以试一下。设置一下保存本地路径和快照宽高参数应该就可以理论上。- (void)saveVideoSnapshotAt: (NSString *)path withWidth:(int)width andHeight:(int)height;
      • uncleRX:顶一个

      本文标题:VLC集成与使用

      本文链接:https://www.haomeiwen.com/subject/gghcjttx.html