2016-03-23 12 views
2

私はビデオを再生できるUITableViewをセットアップしようとしています。以前のSO質問の多くは、MPMoviePlayer(Playing Video into UITableViewPlaying video in UItableView in SWIFTPlaying Video From UITableView)ですが、現在はiOS 9で廃止されています。AVFoundation(私が使っているもの)を使った数少ない人の1人はPlay video on UITableViewCell when it is completely visibleです。私のコードのほとんどを入手しています。ここに私のコードはcellForRowAtIndexPathの内側に、次のとおりです。ビデオをuitableviewセルで再生する

VideoCell *videoCell = (VideoCell *)[self.tableView dequeueReusableCellWithIdentifier:@"VideoCell"]; 

     dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0ul); 
     NSURL *url = [[NSURL alloc] initWithString:urlString]; 

     dispatch_async(queue, ^{ 
     videoCell.item = [AVPlayerItem playerItemWithURL:url]; 

      dispatch_sync(dispatch_get_main_queue(), ^{ 
       videoCell.player = [[AVPlayer alloc] initWithPlayerItem:videoCell.item]; 
       videoCell.player.actionAtItemEnd = AVPlayerActionAtItemEndNone; 

       AVPlayerLayer *playerLayer = [AVPlayerLayer playerLayerWithPlayer:videoCell.player]; 
       playerLayer.frame = CGRectMake(0, 0, videoCell.contentView.frame.size.width, videoCell.contentView.frame.size.height); 
       [videoCell.contentView.layer addSublayer:playerLayer]; 
       playerLayer.videoGravity = AVLayerVideoGravityResize; 
       [videoCell.player play]; 

      }); 
     }); 


     return videoCell; 

私が理解から、私はそれらを再生する前に、非同期の動画をダウンロードする必要があります。私は前に非同期に画像をダウンロードしており、その "ダウンロード"部分には常にNSURL - > NSData - > UIImageの変換が含まれます。そして、あなたがUIImageを持っているとき、あなたはセルにそれを表示する準備ができているので、メインのキューをupにしてdispatch_asyncを呼び出し、cell.imageView.image = yourImageを実行します。メインキューにあります。

ここではNSURLを持っていますが、ここでどのステップをメインキューに置いて、メインスレッドから外すべきかはわかりません。私は上記の質問に示唆されたことを試しましたが、これまでのところうまくいきません。テーブルセルがロードされ、ビデオは決して再生されません。私はちょうど最初のフレームを見る。ときには、最初の1秒間は再生されますが、それ以降はバッファーされ、再生されません。私はテーブルビューで作業していますが、現在はオブジェクトが1つしかないので、再生するビデオは1つだけです。まだ再生されていません。

私は間違って何をしていますか、誰かが私がどのスレッドをメインスレッドに置く必要があるのか​​を正確に説明するのを助けることができますか?私がトップで言及したスレッドのレスポンダには、「そこにチュートリアルがたくさんあります」と言われましたが、Googleをスキャンすると表示されませんでした。 「非同期」と「iOS」の用語は、ほとんどの場合、ビデオではなく画像ダウンロードに関する検索結果を取得します。しかし、チュートリアルがあればそれを見るのが良いでしょう。

おかげ

答えて

2

以下は、私はテーブルビューセルでビデオを再生するために使用されてきた方法です。私はそれがこのための最良の方法であるかどうかわからない、とにかくそれはあなたを助けるかもしれません:)

私はカスタムセルを作成しました。 セッターメソッドでは、AVPlayerを設定するメソッドを呼び出しました。

- (void)setUpAVPlayer 
{ 
    @try { 
     self.videoPlayer = [[AVPlayer alloc]initWithPlayerItem:self.videoPlayerItem]; 
    } 
    @catch (NSException *exception) { 
     NSLog(@"Exception : %@",exception.description); 
     [self.videoPlayer replaceCurrentItemWithPlayerItem:self.videoPlayerItem]; 
    } 


    // Setting player properties. 
    playerLayer = [AVPlayerLayer playerLayerWithPlayer:self.videoPlayer]; 
    playerLayer.videoGravity = AVLayerVideoGravityResize; 
    [self.previewImageView.layer addSublayer:playerLayer]; 
    self.previewImageView.clipsToBounds = YES; 
    playerLayer.hidden = YES; 

    [playerLayer addObserver:self forKeyPath:@"readyForDisplay" options:0 context:nil]; 
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(pauseAllRunningPlayers) name:@"pause" object:nil]; 


    // AVPlayer KVO 

    [self.videoPlayer addObserver:self forKeyPath:@"rate"       options:NSKeyValueObservingOptionNew context:kRateDidChangeKVO]; 
    [self.videoPlayer addObserver:self forKeyPath:@"currentItem.status"    options:NSKeyValueObservingOptionNew context:kStatusDidChangeKVO]; 
    [self.videoPlayer addObserver:self forKeyPath:@"currentItem.duration"   options:NSKeyValueObservingOptionNew context:kDurationDidChangeKVO]; 
    [self.videoPlayer addObserver:self forKeyPath:@"currentItem.loadedTimeRanges" options:NSKeyValueObservingOptionNew context:kTimeRangesKVO]; 
    [self.videoPlayer addObserver:self forKeyPath:@"currentItem.playbackBufferFull" options:NSKeyValueObservingOptionNew context:kBufferFullKVO]; 
    [self.videoPlayer addObserver:self forKeyPath:@"currentItem.playbackBufferEmpty" options:NSKeyValueObservingOptionNew context:kBufferEmptyKVO]; 
    [self.videoPlayer addObserver:self forKeyPath:@"currentItem.error"    options:NSKeyValueObservingOptionNew context:kDidFailKVO]; 

    [videoLoadingIndicator stopAnimating]; 

} 

私はあなたのコードでは、あなたがプレーヤーの状態は「AVPlayerStatusReadyToPlay」になった場合にのみ再生機能を呼び出す必要があり、この[videoCell.player play];

ようtheb再生機能を書かれていることを発見しました。それで私はKVOを使いました。

・ホープ、この5月には、あなたが助け:)

+0

ますので、cellForRowAtIndexPathでこれを呼び出しますか? – joey

+0

いいえ私はカスタムセルクラスを作成しました。私は上記の関数をデータセッターメソッドの中で呼び出しました –

+0

サンプルプロジェクトをゲスできますか?ありがとう –

1

をちょうどあなたのcellForRowAtIndexPathでのコードの下に追加します。ここで

player = [AVPlayer playerWithURL:media.lowResolutionVideoURL]; // 
layer = [AVPlayerLayer layer]; 
[layer setPlayer:player]; 
layer.frame = @"Your Frame"; 
[layer setBackgroundColor:[UIColor clearColor].CGColor]; 
[layer setVideoGravity:AVLayerVideoGravityResizeAspect]; 
[cell.contentView.layer addSublayer:layer]; 
[player play]; 
0
  • 私はかつてあなたのセルがあなたの条件プレイヤーにつきとして表示されますするデモを用意していますが、画像の下の参照して、ストーリーボードを設計することができ、ビデオを再生開始します。

    // 
    // ViewController.swift 
    // RTLDemo 
    // 
    // Created by iOS Test User on 06/01/18. 
    // Copyright © 2018 iOS Test User. All rights reserved. 
    // 
    
    import UIKit 
    import AVKit 
    
    public struct VideoName { 
        static let video1 = "video1" 
        static let video2 = "video2" 
    } 
    
    public struct MediaType { 
        static let video = 1 
        static let image = 2 
    } 
    
    class ViewController: UIViewController { 
    
        @IBOutlet weak var collView: UICollectionView! 
        var timer: Timer? 
        var isVideoPlaying: Bool = false 
    
        // ------------------------------------------------------------------------------------------ 
        // MARK: - 
        // MARK: - Memory management method 
    
        // ------------------------------------------------------------------------------------------ 
    
        override func didReceiveMemoryWarning() { 
         super.didReceiveMemoryWarning() 
         // Dispose of any resources that can be recreated. 
        } 
    
        // ------------------------------------------------------------------------------------------ 
        // MARK: 
        // MARK: - Custom Methods 
    
        // ------------------------------------------------------------------------------------------ 
    
        func initialSetup() { 
         if self.timer == nil { 
          self.timer = Timer.scheduledTimer(timeInterval: 1.0, target: self, selector: #selector(checkForTheVisibleVideo), userInfo: nil, repeats: true) 
         } 
         timer?.fire() 
        } 
    
        // ------------------------------------------------------------------------------------------ 
    
        @objc func checkForTheVisibleVideo() { 
         if !isVideoPlaying { 
          let visibleCell = self.collView.indexPathsForVisibleItems 
          if visibleCell.count > 0 { 
           for indexPath in visibleCell { 
            if self.isVideoPlaying { 
             break 
            } 
            if let cell = self.collView.cellForItem(at: indexPath) as? CustomCell,cell.mediaType == MediaType.video { 
             if cell.player == nil{ 
              cell.player = AVPlayer(url: URL.init(fileURLWithPath: Bundle.main.path(forResource: VideoName.video2, ofType: "mp4")!)) 
              cell.playerLayer = AVPlayerLayer.init(player: cell.player) 
              cell.playerLayer?.frame = cell.imgView.frame 
              cell.imgView.layer.addSublayer(cell.playerLayer!) 
              NotificationCenter.default.addObserver(self, selector: #selector(videoDidFinishPlaying), name: NSNotification.Name.AVPlayerItemDidPlayToEndTime, object: cell.player?.currentItem) 
              cell.player?.addPeriodicTimeObserver(forInterval: CMTime.init(seconds: 1, preferredTimescale: 1), queue: .main, using: { (time) in 
               if cell.player?.currentItem?.status == .readyToPlay { 
    
                let timeDuration : Float64 = CMTimeGetSeconds((cell.player?.currentItem?.asset.duration)!) 
                cell.lblDuration.text = self.getDurationFromTime(time: timeDuration) 
    
                let currentTime : Float64 = CMTimeGetSeconds((cell.player?.currentTime())!) 
                cell.lblStart.text = self.getDurationFromTime(time: currentTime) 
                cell.slider.maximumValue = Float(timeDuration.rounded()) 
                cell.slider.value = Float(currentTime.rounded()) 
               } 
              }) 
             } 
             cell.player?.play() 
             cell.btnPlay.setImage(#imageLiteral(resourceName: "pause_video"), for: .normal) 
             self.isVideoPlaying = true 
            } 
           } 
          } 
         } 
        } 
    
        // ------------------------------------------------------------------------------------------ 
    
        @objc func videoDidFinishPlaying() { 
         self.isVideoPlaying = false 
         let visibleItems: Array = self.collView.indexPathsForVisibleItems 
    
         if visibleItems.count > 0 { 
    
          for currentCell in visibleItems { 
    
           guard let cell = self.collView.cellForItem(at: currentCell) as? CustomCell else { 
            return 
           } 
           if cell.player != nil { 
            cell.player?.seek(to: kCMTimeZero) 
            cell.player?.play() 
           } 
          } 
    
         } 
        } 
    
        // ------------------------------------------------------------------------------------------ 
    
        @objc func onSliderValChanged(slider: UISlider, event: UIEvent) { 
         if let touchEvent = event.allTouches?.first { 
          guard let cell = self.collView.cellForItem(at: IndexPath.init(item: slider.tag, section: 0)) as? CustomCell else { 
           return 
          } 
          switch touchEvent.phase { 
          case .began: 
           cell.player?.pause() 
          case .moved: 
           cell.player?.seek(to: CMTimeMake(Int64(slider.value), 1)) 
          case .ended: 
           cell.player?.seek(to: CMTimeMake(Int64(slider.value), 1)) 
           cell.player?.play() 
          default: 
           break 
          } 
         } 
        } 
    
        // ------------------------------------------------------------------------------------------ 
    
        func getDurationFromTime(time: Float64)-> String { 
    
         let date : Date = Date(timeIntervalSince1970: time) 
         let dateFormatter = DateFormatter() 
         dateFormatter.timeZone = TimeZone.init(identifier: "UTC") 
         dateFormatter.dateFormat = time < 3600 ? "mm:ss" : "HH:mm:ss" 
         return dateFormatter.string(from: date) 
        } 
    
        // ------------------------------------------------------------------------------------------ 
    
        @IBAction func btnPlayTapped(_ sender: UIButton) { 
    
         let indexPath = IndexPath.init(item: sender.tag, section: 0) 
         guard let cell = self.collView.cellForItem(at: indexPath) as? CustomCell else { 
          return 
         } 
         if isVideoPlaying { 
          self.isVideoPlaying = false 
          cell.btnPlay.setImage(#imageLiteral(resourceName: "play_video"), for: .normal) 
          cell.player?.pause() 
         }else{ 
          if cell.player == nil { 
           cell.player = AVPlayer(url: URL.init(fileURLWithPath: Bundle.main.path(forResource: VideoName.video2, ofType: "mp4")!)) 
           cell.playerLayer = AVPlayerLayer(player: cell.player!) 
           cell.playerLayer?.frame = CGRect.init(x: 0, y: 0, width: UIScreen.main.bounds.size.width - 50, height: (UIScreen.main.bounds.size.height - 64) * 0.3) 
           cell.imgView.layer.addSublayer(cell.playerLayer!) 
           NotificationCenter.default.addObserver(self, selector: #selector(videoDidFinishPlaying), name: NSNotification.Name.AVPlayerItemDidPlayToEndTime, object: cell.player?.currentItem) 
          } 
          cell.btnPlay.setImage(#imageLiteral(resourceName: "pause_video"), for: .normal) 
          cell.player?.play() 
          self.isVideoPlaying = true 
         } 
    
        } 
    
        // ------------------------------------------------------------------------------------------ 
        // MARK: - 
        // MARK: - View life cycle methods 
        // ------------------------------------------------------------------------------------------ 
    
        override func viewDidLoad() { 
         super.viewDidLoad() 
         self.initialSetup() 
        } 
    } 
    
    extension ViewController: UICollectionViewDataSource, UICollectionViewDelegate,UICollectionViewDelegateFlowLayout { 
    
        func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { 
         return 10 
        } 
    
        // ------------------------------------------------------------------------------------------ 
    
        func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { 
         let cell = self.collView.dequeueReusableCell(withReuseIdentifier: "CustomCell", for: indexPath) as! CustomCell 
         if indexPath.row % 2 == 0 { 
          cell.mediaType = MediaType.image 
          cell.btnPlay.isHidden = true 
          cell.lblDuration.isHidden = true 
          cell.lblStart.isHidden = true 
          cell.slider.isHidden = true 
          cell.imgView.isHidden = false 
         }else{ 
          cell.mediaType = MediaType.video 
          cell.btnPlay.isHidden = false 
          cell.lblDuration.isHidden = false 
          cell.lblStart.isHidden = false 
          cell.slider.isHidden = false 
          cell.imgView.isHidden = false 
         } 
         cell.btnPlay.tag = indexPath.row 
         cell.slider.tag = indexPath.row 
         cell.btnPlay.addTarget(self, action: #selector(btnPlayTapped(_:)), for: .touchUpInside) 
         cell.slider.addTarget(self, action: #selector(self.onSliderValChanged(slider:event:)), for: .valueChanged) 
    
         return cell 
        } 
    
        // ------------------------------------------------------------------------------------------ 
    
        func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize { 
         return CGSize.init(width: UIScreen.main.bounds.size.width, height: UIScreen.main.bounds.size.height/3) 
        } 
    
        // ------------------------------------------------------------------------------------------ 
    
        func collectionView(_ collectionView: UICollectionView, didEndDisplaying cell: UICollectionViewCell, forItemAt indexPath: IndexPath) { 
    
         guard let cellToHide = cell as? CustomCell else { 
          return 
         } 
    
         if cellToHide.player != nil { 
          cellToHide.player?.pause() 
          cellToHide.playerLayer?.removeFromSuperlayer() 
          cellToHide.player = nil 
          cellToHide.btnPlay.setImage(#imageLiteral(resourceName: "play_video"), for: .normal) 
          self.isVideoPlaying = false 
         } 
    
        } 
    } 
    
    // Custom Cell Class 
    
    class CustomCell: UICollectionViewCell { 
    
        @IBOutlet weak var btnPlay: UIButton! 
        @IBOutlet weak var lblDuration: UILabel! 
        @IBOutlet weak var imgView: UIImageView! 
        @IBOutlet weak var viewBack: UIView! 
        @IBOutlet weak var lblStart: UILabel! 
        @IBOutlet weak var slider: UISlider! 
    
        var player: AVPlayer? 
        var playerLayer: AVPlayerLayer? 
        var mediaType: Int! 
    } 
    
  • 私はコレクションビューのセルを持つ単純なカスタムビデオプレーヤーを作成したストーリーボードの参照画像:

enter image description here

関連する問題