Inserting an AVPlayerLayer below GLKView Layer - ios

All I am trying to accomplish is to place an AVPlayerLayer behind an active OpenGL layer.
I am using a GLKViewController (with respective GLKView). I load a video with AVPlayer and establish a corresponding AVPlayerLayer. Both my GL Layer and AVPlayerLayer appear, however, regardless of what form of "insert sublayer" I call (above, below, at index, etc.), the GL Layer always appears behind the AVPlayerLayer.
_videoData = playerItem;
_videoPlayer = [[AVPlayer alloc] initWithPlayerItem:_videoData];
_playerLayer = [AVPlayerLayer playerLayerWithPlayer:_videoPlayer];
_playerLayer.frame = CGRectMake(250, 250, 300, 300);
[self.view.layer insertSublayer:_playerLayer below:self.view.layer];

Solved this by inserted a GLKViewController as a child of a UIView with the video player. After much experimentation it appears you cannot place anything (subviews or layers) behind the GL layer when using GLKViewController independently.

Related

AVPlayerLayer flashes black on AVPlayer.replaceCurrentItem(with:)

I have an AVPlayer object that I am using to play a video. When the user taps a button, the video is swapped out for a different video, which continues playing. Just using replaceCurrentItem(with:) is resulting in a few tenths of a second of a black frame appearing on my AVPlayerLayer that is displaying the video content.
I have code in place to render an image at the current frame before the AVPlayerItem is swapped out, to bridge the gap before the new AVPlayerItem has a frame ready to display, but the black frame is blocking this image from view. Is there any way to control what the AVPlayerLayer will render before it has actual video data to display?
Alternatively, is there a way to be notified that the AVPlayerLayer (or the AVPlayerItem has actually begun displaying video data? Observing for when the state of the item becomes .readyToPlay triggers too early, hiding the image at that point still leaves the black frame visible.
I had the same flash problem with my macOS app. I resolved it by renewing AVPlayerLayer each time I play a new file.
I have an AVPlayer subclass. The function below removes AVPlayerLayer from its super layer and add a new layer to the view.
class MyVideoPlayer: AVPlayer {
func addLayer(view: NSView) {
view.layer!.sublayers?
.filter { $0 is AVPlayerLayer }
.forEach { $0.removeFromSuperlayer() }
let layer = AVPlayerLayer.init(player: self)
layer.videoGravity = AVLayerVideoGravity.resize
layer.frame = view.bounds
view.layer!.addSublayer(layer)
}
}
In my ViewController, I call this before I play a video content.
myVideoPlayer.addLayer(view: self.view)

SceneKit AVPlayer only audio is playing

I am trying to play a video in SceneKit. I can hear the audio but video is not rendering. The way i am using the scene is as follows. Please help.
SCNScene *scene = [SCNScene sceneNamed:#"art.scnassets/plane.scn"];
SCNNode *plane = [scene.rootNode childNodeWithName:#"plane" recursively:YES];
AVPlayer *player = [AVPlayer playerWithURL:[NSURL URLWithString:#"https://sample-videos.com/video123/mp4/720/big_buck_bunny_720p_5mb.mp4"]];
plane.geometry.firstMaterial.diffuse.contents = player;
[player play];
SCNView *scnView = (SCNView *)self.view;
scnView.scene = scene;
scnView.allowsCameraControl = YES;
scnView.showsStatistics = YES;
scnView.backgroundColor = [UIColor blackColor];
You need to use a real iPhone not simulator to enjoy.
Another reason is the shading in the material panel should not be physical based. You may try Blinn. The code has no problem.
If using a physical based, you have to add an extra light to make it work.
you can keep PBR and get glass reflections with a non-rough material. use the emission instead of diffuse for the the video though
plane.geometry.firstMaterial.emission.contents = player

How to add UIView behind CCGLView (Cocos2d-objc)

I'm trying to play a video using MPMoviePlayerController and wanted to show it behind the cocos2d assets. I was able to play the video but it appears on top of the cocos2d assets. Cocos2D-ObjC version is 3.5.0.
Here's my code snippet:
MPMoviePlayerController *moviePlayer = self.moviePlayerController.moviePlayer;
CCDirectorIOS *director = (CCDirectorIOS*)[CCDirector sharedDirector];
CC_VIEW *directorView = [director view];
[directorView addSubview:moviePlayer.view];
[directorView sendSubviewToBack:[moviePlayer view]];
directorView.opaque = NO;
Any help is highly appreciated.
Just for info: there is no way to add it beetween, because cocos2d view controller(with all your images) is a layer added on the directorView.
So cocos2d director is a view controller drawing into a single view, a CCGLView. You can't add a view to a layer, because layers are not views. Layers are just objects used by cocos2d.
As with other views, you can add a view below the cocos2d CCGLView (as a parent or earlier sibling of the GLView) or above the cocos2d CCGLView (as a child or later sibling of the GLView), but not anywhere in-between. Because of this, your UIView can only be logically above or below all Cocos2d drawing.
And for sending back just use:
[viewController.view addSubview:moviePlayer.view];
[viewController.view sendSubviewToBack:moviePlayer.view];

resize AVPlayerItem container view based on aspect ratio from video

I have a container UIView called videoView. I add a AVPLayerLayer to that view. I do not know how to resize the videoView to be of the same proportions as the avplayer layer. Using videoGravity does not have the desired effect.
AVPlayerItem* playerItem = [AVPlayerItem playerItemWithURL:path];
_videoPlayer = [[AVPlayer alloc] initWithPlayerItem:playerItem];
AVPlayerLayer *layer = [AVPlayerLayer layer];
[_avplayerLayer setPlayer:_videoPlayer];
[_avplayerLayer setBackgroundColor:[UIColor whiteColor].CGColor];
[_avplayerLayer setVideoGravity:AVLayerVideoGravityResizeAspectFill];
[_avplayerLayer setFrame:_videoView.bounds];
[_videoView.layer addSublayer:_avplayerLayer];
I am using autolayout, and my layout would accommodate a change in the height of _videoView.
videoGravity will not change the frame of the view, instead it fills the current frame with the video.
i think you should inspect each video's resolution before playing it and adjust videoView's height constraint (which should be an ivar and constrained to videoView's width) multiplier. videoView width should be constrained to the screen width.

Crop Video Into Circle in iOS?

I am trying to crop a video, that has been taken with an iPhone camera and then place it on top of a UIImageView. I have been following this SO Question How to crop a video to a circle in iOS?. And I can now take the video and put it on top of another perviously recorded video. Now I want to have the background be a image and the foreground be the cropped video. My main issue right now is getting video cropped in the part I want cropped. I cannot post all the code here but here is where the github repo is and the class that does the modifying is called CustomVideoCompositor.m https://github.com/mayoff/stackoverflow-28258270-video-in-oval-on-video/tree/master/video. And I am having trouble editing it into the circle I want I want it to be a oval that is in the bottom half and higher than wider.
EDIT
I want to make the cut so that only things in this part of the rounded rectangle would be cropped and available.
If you want only a visual effect of cropped video, without modification of video file, you can simply add a mask to your video layer. I mean CALayer mask property.
You can create circle mask like this: draw black rectangle, then draw transparent circle on it.
You'll need to use AVPlayer as this enables you to play several videos back at once or have your video appear on top of another view. Also, by using AVPlayer and an AVPlayerLayer its easy to then make the video appear circular. (Here's a good tutorial on it to learn more: http://jacopretorius.net/2013/02/playing-video-in-ios.html)
Here's the code (for Objective-C):
In your view controller .h file:
#import <AVFoundation/AVFoundation.h>
Then in viewDidLoad:
[super viewDidLoad];
// Set up the image view first (the imageView is an IBOutlet)
self.imageView.image = [UIImage imageNamed:#"image"];
self.imageView.alpha = 0.2;
NSURL *url = [[NSBundle mainBundle] URLForResource:#"video" withExtension:#"mp4"];
AVPlayer *player = [AVPlayer playerWithURL:url];
CGFloat diameter = MIN(self.view.frame.size.width, self.view.frame.size.height) * 0.8;
AVPlayerLayer *layer = [AVPlayerLayer playerLayerWithPlayer:player];
layer.videoGravity = AVLayerVideoGravityResizeAspectFill;
layer.frame = CGRectMake((self.view.frame.size.width - diameter) / 2,
(self.view.frame.size.height - diameter) / 2,
diameter, diameter);
layer.cornerRadius = diameter / 2;
layer.masksToBounds = YES;
// Put the AVPlayerLayer on top of the image view.
[self.view.layer addSublayer:layer];
[player play];

Resources