Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Playing Video into UITableView

I have read several posts here about live streaming video/audio. Unfortunately it seems that there is not any "good" solution.

I want same functionality for video which is provided SDWebImageView for images.

Right now, I am using following code:-

NSURL *url=[[NSURL alloc] initWithString:@"http://www.ebookfrenzy.com/ios_book/movie/movie.mov"];
MPMoviePlayerController *moviePlayer=[[MPMoviePlayerController alloc] initWithContentURL:url];
moviePlayer.controlStyle=MPMovieControlStyleDefault;
moviePlayer.shouldAutoplay=YES;

But when I scrolled tableview, all videos download again and again. So How can I stop that downloading?

Is there any better solution for playing video into UITableView? Same Facebook, Instagram, and Vine Apps doing?

like image 762
Meet Doshi Avatar asked Dec 30 '15 09:12

Meet Doshi


3 Answers

Don't use MPMoviePlayerController, use AVFoundation's AVPlayer.

Additionally, don't couple the downloading of your asset to your UITableViewCell subclass. Use an additional data source to download and manage the video assets.

There are a few ways you can do this.

  1. Keep a data source array of AVPlayerItem objects initialized by URL. Instead of loading the asset each time you scroll to a cell, just load the AVPlayerItem into the cell's player, and remove it when you scroll away.

  2. If you need to persist the video data, consider downloading each video to a temporary file in your Documents directory. When the file has finished downloading, load that data into an AVAsset using its initWithURL: method and point the URL to your local file. When ready, you can load your asset into an AVPlayerItem using initWithAsset: and play the video.

like image 174
JAL Avatar answered Oct 16 '22 19:10

JAL


When you scroll table view then method -tableView:cellForRowAtIndexPath: is fired (actually every time when cell will be visible this method is called). I believe that you are allocating and initializing yours MediaPlayer in this method and that's why video is downloaded again. You could try to add array and store already created cells in it (some kind of cache). Then your -tableView:cellForRowAtIndexPath should check if it has sth cached for actual index. If yes then show cached cell. If no then it should create cell, alloc, and init player and then store cell in cache.

My ViewController has property: NSMutableDictionary *cache; and in ViewDidLoad I have: cache = [[NSMutableDictionary alloc] init]; My -tableView:cellForRowAtIndexPath: looks like this:

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    static NSString *cellId = @"myCellId";

    MyTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellId];

    if ([cache objectForKey:[NSString stringWithFormat:@"key%lu", indexPath.row]] != nil) {
        cell = [cache objectForKey:[NSString stringWithFormat:@"key%lu", indexPath.row]];
    } else {
        NSArray *nib = [[NSBundle mainBundle] loadNibNamed:@"MyTableViewCell" owner:self options:nil];
        cell = [nib objectAtIndex:0];

        AVPlayerViewController *playerViewController = [[AVPlayerViewController alloc] init];
        playerViewController.player = [AVPlayer playerWithURL:[[NSURL alloc] initWithString:@"http://www.ebookfrenzy.com/ios_book/movie/movie.mov"]];
        [cell addSubview:playerViewController.view];
        [cache setValue:cell forKey:[NSString stringWithFormat:@"key%lu", indexPath.row]];
    }

    return cell; 
}

It works for me. Of course you need to use your own datasource etc.

like image 22
owocki Avatar answered Oct 16 '22 19:10

owocki


Swift 3

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell : UITableViewCell = tableView.dequeueReusableCell(withIdentifier: "Cell")!
    let videoURL = NSURL(string: "http://www.ebookfrenzy.com/ios_book/movie/movie.mov")
    let player = AVPlayer(url: videoURL! as URL)
    let playerLayer = AVPlayerLayer(player: player)
    playerLayer.frame = cell.bounds
    cell.layer.addSublayer(playerLayer)
    player.play()
    return cell
}
like image 27
Aayushi Avatar answered Oct 16 '22 18:10

Aayushi