Crop Video Into Circle in iOS? - 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];

Related

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.

Inserting an AVPlayerLayer below GLKView Layer

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.

Clear Mask on UIView (actually a video view)

I'm using OpenTok which is a webRTC framework. What I need to do is take the displayed video view and crop it to a circle. Problem is, since this video avatar view will be placed in a view with a clear background, I can't just use a mask as shown in this S.O. question:
Cut Out Shape with Animation
I've also tried to use layer.radius in a UIView category:
-(void)setRoundedViewToDiameter:(float)newSize;
{
CGPoint saveCenter = self.center;
CGRect newFrame = CGRectMake(self.frame.origin.x, self.frame.origin.y, newSize, newSize);
self.frame = newFrame;
self.layer.cornerRadius = newSize / 2.0;
self.center = saveCenter;
}
And then applied like so:
- (void) setUserVideoView:(UIView *)view {
[view setRoundedViewToDiameter:[WSUserView dimForUserAvatar:_sizeIndex]];
self.userVideo = view;
[self.userVideo setRoundedViewToDiameter:[WSUserView dimForUserAvatar:_sizeIndex]];
[self addSubview:self.userVideo];
[self sendSubviewToBack:self.userVideo];
[self layoutSubviews];
}
But it's still an uncropped rectangle. Here's the portion of the video view. I'm showing user image avatars at first, but then when a video stream connects I want to replace the image with the video view, but as a circle. The left image is the stream view that I need make a circle.
Also, here's the inspector view of the video view I'm trying to crop. As you can see, it's a OTGLKVideoView class.
Migrated from my comment:
You should set self.layer.masksToBounds = YES because this ensures that the layer's sublayers are clipped with the corner radius too. I'm assuming that the problem is arising because the ever-changing sublayer that is updated whenever the video's frame changes is thereby ignoring the corner radius.
More details can be found through this answer which solves a similar problem: https://stackoverflow.com/a/11325605/556479

Flip video around arbitrary axis

I have a video recorded by the user. I want the user to be able to define an arbitrary axis of rotation, and flip the video along that axis. I also want the final flipped video to crop to the original size.
I have used the CGAffineTransformMakeScale(-1, 1) to flip the video along the horizontal axis, but that's around the center point.
I'm already using an AVMutableComposition to do some compositing. Are there any AVMutableVideoCompositionLayerInstruction that would help?
_mike
You should calculate where the user set the axis or how far the image is off set, flip the image and re-apply this offset in the opposite direction. Then you just need to get a subimage of an image.
Which you can do by doing this:
CGRect fromRect = CGRectMake(0, 0, 320, 480); // or whatever rectangle
CGImageRef drawImage = CGImageCreateWithImageInRect(image.CGImage, fromRect);
UIImage *newImage = [UIImage imageWithCGImage:drawImage];
CGImageRelease(drawImage);
Code Reference Subimage of Image

Can't remove a black line that is over a picture

I'm using [BJImageCropper]1 and trying to figure out how to remove the squares effect around the crop area. I want to have a full area of black alpha around the crop area. Sounds easy, so the only thing I changed in the above project was changing the alpha to 0.75 in BJImageCropper.m:
- (UIView*)newEdgeView {
UIView *view = [[UIView alloc] init];
view.backgroundColor = [UIColor blackColor];
view.alpha = 0.75; //(was 0.5)
[self.imageView addSubview:view];
return view;
}
My problem is that there's a black line that's following me around in the top right corner of the crop area. matter what I changed in the code - I can't get rid of.

Resources