iPhone SDK:How do you play video inside a view? Rather than fullscreen
Asked Answered
A

9

61

I am trying to play video inside a UIView, so my first step was to add a class for that view and start playing a movie in it using this code:

- (IBAction)movie:(id)sender{
    NSBundle *bundle = [NSBundle mainBundle];
        NSString *moviePath = [bundle pathForResource:@"Movie" ofType:@"m4v"];
    NSURL *movieURL = [[NSURL fileURLWithPath:moviePath] retain];
    MPMoviePlayerController *theMovie = [[MPMoviePlayerController alloc] initWithContentURL:movieURL];
    theMovie.scalingMode = MPMovieScalingModeAspectFill;
    [theMovie play];
}

But this just crashes the app when using this method inside it's own class, but is fine elsewhere. Does anyone know how to play video inside a view? and avoid it being full screen?

Andrews answered 12/8, 2009 at 14:59 Comment(1)
Putting together various solutions in one place to play a Video using iOS 4.2 codevelle.wordpress.com/2011/01/07/videoplayer-for-ios-4-2Aryn
M
83

As of the 3.2 SDK you can access the view property of MPMoviePlayerController, modify its frame and add it to your view hierarchy.

MPMoviePlayerController *player = [[MPMoviePlayerController alloc] initWithContentURL:[NSURL fileURLWithPath:url]];
player.view.frame = CGRectMake(184, 200, 400, 300);
[self.view addSubview:player.view];
[player play];

There's an example here: http://www.devx.com/wireless/Article/44642/1954

Metagenesis answered 29/5, 2010 at 8:45 Comment(3)
Do not work for youtube videos. See an implementation here: iosdevelopertips.com/video/…Deice
MPMoviePlayerController is a bad library if you want specific control in current time in video. Is not exactly, and have bugs. The best way is AVPlayer, using AVPlayerLayer.Accurate
MPMoviePlayerController is deprecated!Sealer
S
34

The best way is to use layers insted of views:

AVPlayer *player = [AVPlayer playerWithURL:[NSURL url...]]; // 

AVPlayerLayer *layer = [AVPlayerLayer layer];

[layer setPlayer:player];
[layer setFrame:CGRectMake(10, 10, 300, 200)];
[layer setBackgroundColor:[UIColor redColor].CGColor];
[layer setVideoGravity:AVLayerVideoGravityResizeAspectFill];

[self.view.layer addSublayer:layer];

[player play];

Don't forget to add frameworks:

#import <QuartzCore/QuartzCore.h>
#import "AVFoundation/AVFoundation.h"
Sammie answered 21/5, 2013 at 21:32 Comment(5)
What is queuePlayer in this?Dubose
I have changed variable name.Sammie
I've done this and all I get is a red coloured box with the audio playing but no video :/Cyclops
This is due to the AVPlayerLayer being behind another view or layer I believeUdder
Why is it better to use a layer than a view?Estimate
E
20

Swift

This is a self contained project so that you can see everything in context.

Layout

Create a layout like the following with a UIView and a UIButton. The UIView will be the container in which we will play our video.

enter image description here

Add a video to the project

If you need a sample video to practice with, you can get one from sample-videos.com. I'm using an mp4 format video in this example. Drag and drop the video file into your project. I also had to add it explicitly into the bundle resources (go to Build Phases > Copy Bundle Resources, see this answer for more).

Code

Here is the complete code for the project.

import UIKit
import AVFoundation

class ViewController: UIViewController {

    var player: AVPlayer?

    @IBOutlet weak var videoViewContainer: UIView!

    override func viewDidLoad() {
        super.viewDidLoad()
        initializeVideoPlayerWithVideo()
    }

    func initializeVideoPlayerWithVideo() {

        // get the path string for the video from assets
        let videoString:String? = Bundle.main.path(forResource: "SampleVideo_360x240_1mb", ofType: "mp4")
        guard let unwrappedVideoPath = videoString else {return}

        // convert the path string to a url
        let videoUrl = URL(fileURLWithPath: unwrappedVideoPath)

        // initialize the video player with the url
        self.player = AVPlayer(url: videoUrl)

        // create a video layer for the player
        let layer: AVPlayerLayer = AVPlayerLayer(player: player)

        // make the layer the same size as the container view
        layer.frame = videoViewContainer.bounds

        // make the video fill the layer as much as possible while keeping its aspect size
        layer.videoGravity = AVLayerVideoGravity.resizeAspectFill

        // add the layer to the container view
        videoViewContainer.layer.addSublayer(layer)
    }

    @IBAction func playVideoButtonTapped(_ sender: UIButton) {
        // play the video if the player is initialized
        player?.play()
    }
}

Notes

  • If you are going to be switching in and out different videos, you can use AVPlayerItem.
  • If you are only using AVFoundation and AVPlayer, then you have to build all of your own controls. If you want full screen video playback, you can use AVPlayerViewController. You will need to import AVKit for that. It comes with a full set of controls for pause, fast forward, rewind, stop, etc. Here and here are some video tutorials.
  • MPMoviePlayerController that you may have seen in other answers is deprecated.

Result

The project should look like this now.

enter image description here

Estimate answered 21/11, 2017 at 13:12 Comment(0)
P
15

Looking at your code, you need to set the frame of the movie player controller's view, and also add the movie player controller's view to your view. Also, don't forget to add MediaPlayer.framework to your target.

Here's some sample code:

#import <MediaPlayer/MediaPlayer.h>

@interface ViewController () {
    MPMoviePlayerController *moviePlayerController;
}

@property (weak, nonatomic) IBOutlet UIView *movieView; // this should point to a view where the movie will play

@end

@implementation ViewController

- (void)viewDidLoad
{
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.

    // Instantiate a movie player controller and add it to your view
    NSString *moviePath = [[NSBundle mainBundle] pathForResource:@"foo" ofType:@"mov"];
    NSURL *movieURL = [NSURL fileURLWithPath:moviePath];    
    moviePlayerController = [[MPMoviePlayerController alloc] initWithContentURL:movieURL];
    [moviePlayerController.view setFrame:self.movieView.bounds];  // player's frame must match parent's
    [self.movieView addSubview:moviePlayerController.view];

    // Configure the movie player controller
    moviePlayerController.controlStyle = MPMovieControlStyleNone;        
    [moviePlayerController prepareToPlay];
}

- (void)viewDidAppear:(BOOL)animated
{
    [super viewDidAppear:animated];

    // Start the movie
    [moviePlayerController play];
}

@end
Pentimento answered 21/2, 2013 at 11:33 Comment(3)
I love you!! Thank you so much, I was searching for at least an hour now and you had the only code that simply worked!Citystate
Xcode 6, iOS 8 and this still works. Key for me was the "prepare to play" addition to the other answer. Thanks!Tachyphylaxis
also take note that [moviePlayerController play]; is in viewDidAppear...if this is in viewDidLoad, you might just see a black background in your "movieView" depending on your Xcode/iOS version.Metalware
L
5
NSString * pathv = [[NSBundle mainBundle] pathForResource:@"vfile" ofType:@"mov"];
playerv = [[MPMoviePlayerViewController alloc] initWithContentURL:[NSURL fileURLWithPath:pathv]];

[self presentMoviePlayerViewControllerAnimated:playerv];
Llama answered 10/2, 2012 at 12:20 Comment(0)
S
2
NSURL *url = [NSURL URLWithString:[exreciesDescription objectForKey:@"exercise_url"]];
moviePlayer =[[MPMoviePlayerController alloc] initWithContentURL: url];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(doneButtonClicked) name:MPMoviePlayerWillExitFullscreenNotification object:nil];
[[moviePlayer view] setFrame: [self.view bounds]];  // frame must match parent view
[self.view addSubview: [moviePlayer view]];
[moviePlayer play];

-(void)playMediaFinished:(NSNotification*)theNotification 
{
    moviePlayer=[theNotification object];
    [[NSNotificationCenter defaultCenter] removeObserver:self
                                                    name:MPMoviePlayerPlaybackDidFinishNotification
                                                  object:moviePlayer];


    [moviePlayer.view removeFromSuperview];
}

-(void)doneButtonClicked
  {
         [moviePlayer stop];
        [moviePlayer.view removeFromSuperview];
         [self.navigationController popViewControllerAnimated:YES];//no need this if you are      opening the player in same screen;
  }
Siliculose answered 7/2, 2013 at 13:17 Comment(0)
L
1

Swift version:

import AVFoundation

func playVideo(url: URL) {

    let player = AVPlayer(url: url)

    let layer: AVPlayerLayer = AVPlayerLayer(player: player)
    layer.backgroundColor = UIColor.white.cgColor
    layer.frame = CGRect(x: 0, y: 0, width: 300, height: 300)
    layer.videoGravity = .resizeAspectFill
    self.view.layer.addSublayer(layer)

    player.play()
}
Liv answered 20/5, 2016 at 19:43 Comment(4)
What is the difference between importing AVFoundation vs AVKit?Estimate
Aren't you adding another layer every single time the user plays the video?Estimate
@Estimate I'm not 100% sure but I think AVKit is build on top on AVFoundation, which is an older and lower level Kit for managing the Camera. And yes it's just an example so it's adding a layer every time but if you have several videos to play just edit the player instead of the entire layerLiv
I looked it up. You need AVKit if you are using AVPlayerViewController with the full video playback controls. If you are building your own controls, then you can use AVFoundation with AVPlayer.Estimate
R
0

Use the following method.

self.imageView_VedioContainer is the container view of your AVPlayer.

- (void)playMedia:(UITapGestureRecognizer *)tapGesture
{
    playerViewController = [[AVPlayerViewController alloc] init];

    playerViewController.player = [AVPlayer playerWithURL:[[NSBundle mainBundle]
                                                 URLForResource:@"VID"
                                                         withExtension:@"3gp"]];
    [playerViewController.player play];
    playerViewController.showsPlaybackControls =YES;
    playerViewController.view.frame=self.imageView_VedioContainer.bounds;
    [playerViewController.view setAutoresizingMask:UIViewAutoresizingNone];// you can comment this line 
    [self.imageView_VedioContainer addSubview: playerViewController.view];
}
Reyesreykjavik answered 22/1, 2016 at 11:3 Comment(0)
S
-5

You cannot play a video inside a view. It has to be played fullscreen.

Singlehearted answered 12/8, 2009 at 15:6 Comment(5)
Ok, well that's a shame, but I have seen other apps on the appstore where video has been played not full screen but in a smaller view inside the main screen, so there must be a way.Andrews
Maybe those examples of video-in-a-view have been sequential images with an extra track of sound.Triacid
I think this answer is outdated, as in SDK 3.2, there are clearly partial-screen videos available in apps that can go to fullscreen with user interaction.Mogador
I agree! Anyone found out, how to do this?Just
I've added another answer outlining how you do this in 3.2Metagenesis

© 2022 - 2024 — McMap. All rights reserved.