iOS - MPMoviePlayerController resets view transform on repeat - ios

Using an MPMoviePlayerController.view as a background (think spotify). A user can tap login or signup and they are taken to the appropriate viewController, which has a clear background so that the moviePlayer.view remains as the background (i.e., user continues to see the video regardless of the currently active viewController) throughout the flow.
On some viewControllers the form needs to be lifted up so that the keyboard doesn't cover the field. I'm doing this using a transform.
The background video of the moviePlayer is set to repeat, so the video is on a continuous loop. Each time the video resets (video status goes from 1 to 2 - paused to playing) the transform resets in the child viewControllers. My initial thought was that the view was being redrawn, but this doesn't appear to be the case based on logs (I put nslogs in the drawRect of the views but it's only ever called once at instantiation).
Has anyone come across this?
My setup in the root viewController:
// lazy load moviePlayer
-(MPMoviePlayerController *)moviePlayer
{
if (_moviePlayer) return _moviePlayer;
NSURL *videoURL = [[NSBundle mainBundle] URLForResource:#"resources.bundle/videos/auth_bg" withExtension:#"mp4"];
_moviePlayer = [[MPMoviePlayerController alloc] initWithContentURL:videoURL];
_moviePlayer.controlStyle = MPMovieControlStyleNone;
_moviePlayer.scalingMode = MPMovieScalingModeAspectFill;
_moviePlayer.repeatMode = MPMovieRepeatModeOne;
_moviePlayer.shouldAutoplay = true;
return _moviePlayer;
}
-(void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
self.moviePlayer.view.frame = self.view.frame;
self.moviePlayer.view.hidden = false;
// 'still' is an imageView of the first frame to show while video loading
[self.navigationController.view insertSubview:self.moviePlayer.view aboveSubview:still];
}

I suspect this has to do with Autolayout -- I found a few other questions where views were being reset (one example here: https://stackoverflow.com/a/17849584/1542275) ... My solution was to adjust the layout constraint constants as opposed to transforming the view coordinates. Things are now staying put.
All of that said, I'm still not sure why the video restart is resetting the transforms.

Related

QT how to change application window z index

I was trying to get native iOS player as a custom QML component and managed to do it thanks to this. However I'm facing a problem with z order of the component.
Component constructor:
MyVideoView::MyVideoView(QQuickItem *parent /*= 0*/)
: QQuickItem(parent)
, m_view(0)
{
connect(this, SIGNAL(windowChanged(QQuickWindow*)), this, SLOT(onWindowChanged(QQuickWindow*)));
connect(this, SIGNAL(visibleChanged()), this, SLOT(onVisibleChanged()));
}
onWindowChanged implementation:
void MyVideoView::onWindowChanged(QQuickWindow* window)
{
if(!m_view) {
}
if (window != 0) {
UIView *parentView = reinterpret_cast<UIView *>(window->winId());
AVPlayer *_player;
AVURLAsset *_asset;
AVPlayerItem *_playerItem;
AVPlayerLayer *m_playerLayer;
_player = [[AVPlayer alloc] init];
NSURL *baseURL = [[NSURL alloc] initWithString: #"http://devimages.apple.com/iphone/samples/bipbop/bipbopall.m3u8"];
_asset = [AVURLAsset assetWithURL:baseURL];
_playerItem = [AVPlayerItem playerItemWithAsset: _asset];
[_player replaceCurrentItemWithPlayerItem:_playerItem];
m_playerLayer = [AVPlayerLayer playerLayerWithPlayer:_player];
m_playerLayer.frame = CGRectMake(this->x(), this->y(), this->width(), this->height());
[parentView.layer addSublayer:m_playerLayer ];
[_player play];
} else {
[m_view removeFromSuperView];
}
}
Whit this I can use the component in my application which is an ApplicationWindow, but the issue is, the component is always on top, covering the whole application even if I set:
MyVideoView {
z:-3
width: 300
height: 200
x:20
y:300
}
Or put z of another component to e.g. 300.
I assume it's because of QQuickWindow or caused by UIView.
Edit: MyVideoView is placed inside an Item component
What I would want to achieve is to:
either make it possible to set the components z order
or get the component "behind" the application (creating transparent part on my app so the video is visible, not the best solution but I'm running out of options)
Is there any way to achieve one of those, or can it be done if the component is something else besides a QQuickItem, since the only part I actually need is the player layer, as I'll create a custom playback control interface?
QQuickWindow is a UIView. The individual QML items are not, so you can't place another UIView(or its layer) "inside" a QML application unless you structure the application as a top level QQuickWindow with additional child QQuickWindow and then sandwich the video layer between those Qt Quick windows (QWindows).
With the hint from Tor, I managed to get it to work.
First I created another UIView to place m_playerLayer inside it.
and then got the player behind:
[playerView.layer addSublayer:m_playerLayer];
[parentView.window addSubview: playerView];
[parentView.window sendSubviewToBack: playerView];
parentView.opaque = NO;
It's important to point out that without parentView.opaque = NO the application would still have a background even with ApplicationWindow color: "transparent"

Embedding video into view controller

I am trying to add a video to a view controller. I tried using the AVPlayerViewController but i was not able to achieve the result i wanted. I do not want the video to open in a new view controller. Instead i want it to be playing in the background. There will be buttons in the foreground and the user can press it. Here is a picture of how the page is supposed to look like.
The globe will be rotating and the user can login or sign-up. From what i have researched i understand that it is only possible through using a gif. But how is youtube able to achieve this? Is it possible for me to do so?
you need to add video first to your main view using Avplayer like following:
NSString *filepath = [[NSBundle mainBundle] pathForResource:#"Untitled" ofType:#"mp4"];
NSURL *fileURL = [NSURL fileURLWithPath:filepath];
avPlayer = [AVPlayer playerWithURL:fileURL];
layer = [AVPlayerLayer playerLayerWithPlayer:avPlayer];
avPlayer.actionAtItemEnd = AVPlayerActionAtItemEndNone;
layer.frame = CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height);
[self.view.layer addSublayer: layer];
Then u need to create UiView with 2 button as you specify "Login" and "Sign-Up" and make Uivew BackgroundColor Property:clear color. and add this code to place view on your main view.
CGRect viewframe=self.buttonView.frame;
viewframe.origin.x=0;
viewframe.origin.y=0;
viewframe.size.height=self.view.frame.size.height;
viewframe.size.width=self.view.frame.size.width;
self.bnuttonView.frame=viewframe;
[self.view addSubview:self.buttonView];
In this way your video will play in background and Login and Sign-up button are working in foreground.

UIImageView+animatedGIF always LOOPS

I used class made by "mayoff" (Rob Mayoff) "UIImageView+animatedGIF" which was proposed in one of the answers here on stackoverflow. UIImageView+animatedGIF
With it I can import animated .gif images in UIImageView on iOS. This class works flawlessly, but the only problem is that .gif is always looping. No matter how I export it (I am exporting image from photoshop - 67 frames, set repeat to "once") it loops forever in UIImageView.
I am importing my .gif with these two lines:
NSURL *url = [[NSBundle mainBundle] URLForResource:#"Loading" withExtension:#"gif"];
self.loadingImageView.image = [UIImage animatedImageWithAnimatedGIFData:[NSData dataWithContentsOfURL:url]];
very simple and it works.
I have tried setting animationRepeatCount property to 1, as recomended by Rob but that didn't do the trick. Also I have tried setting the UIImageView's animationImages property to
gifImage.images too, instead of just setting the view's image property
to gifImage. In that case, .gif is not animating at all.
Any ideas how to play that .gif only once? I can think of many tricks (like setting last frame of the gif to show up after some time but I'd first try something simpler if possible).
I took the test app from that project and changed the viewDidLoad method to this:
- (void)viewDidLoad {
[super viewDidLoad];
NSURL *url = [[NSBundle mainBundle] URLForResource:#"test" withExtension:#"gif"];
UIImage *testImage = [UIImage animatedImageWithAnimatedGIFData:[NSData dataWithContentsOfURL:url]];
self.dataImageView.animationImages = testImage.images;
self.dataImageView.animationDuration = testImage.duration;
self.dataImageView.animationRepeatCount = 1;
self.dataImageView.image = testImage.images.lastObject;
[self.dataImageView startAnimating];
}
When the app launches, it animates the image once and then shows just the last frame. If I connect a button that sends [self.dataImageView startAnimating], then tapping the button runs the animation one more time, then stops again on the last frame.
Make sure you're setting your image view up the way I do above. Make sure you are not setting the image view's image property to the animated image. The image view's image property must be set to a non-animated image if you want the animation to stop.
I have forked "uiimage-from-animated-gif" made by "Dreddik" and added a delegate method
#pragma mark - AnimatedGifDelegate
- (void)animationWillRepeat:(AnimatedGif *)animatedGif
{
NSLog(#"animationWillRepeat");
//[animatedGif stop];
}
So you know the time when animation will repeat and do your own thing in middle of every repetition. You may count the number of times animation repeated and stop animation at a certain number reached.
The forked repository is at https://github.com/rishi420/Animated-GIF-iPhone
Was having issues in start/stp animation & managing animation count
So used this pod
imageViewObject.animate(withGIFNamed: "gif_name", loopCount: 1) {
print("animating image")
}
To start/stop animation :
imageViewObject.isAnimatingGIF ? imageViewObject.stopAnimatingGIF() : imageViewObject.startAnimatingGIF()

MPMoviePlayerController stops and resets the movie when user tries to play fullscreen [iOS]

I embedded a MPMoviePlayerController on my mail view. I can play/pause the movie and seek forward/backward. But when I touch the "fullscreen button" the movie stops and the playback state is set to MPMoviePlaybackStateStopped... Should the movie be played in full screen?
Here is my code:
MPMoviePlayerController *player = [[MPMoviePlayerController alloc] initWithContentURL:videoUrl];
player.shouldAutoplay = NO;
player.movieSourceType = MPMovieSourceTypeFile;
player.controlStyle = MPMovieControlStyleEmbedded;
player.allowsAirPlay = YES;
player.view.frame = CGRectMake(xPos, yPos, width, height);
[self.view addSubview:player.view];
I found my bug: when pressing the full screen toggle button in MPMoviePlayerController's view, the method "viewWillLayoutSubviews" is invoked. I could never imagine this behavior...
I hope my experience can be useful to other developers.
Remember that any containing ViewController will have its viewWillDisappear, viewDidDisappear methods invoked when the MPMoviePlayerController goes full screen. Also, viewWillAppear and viewWillDisappear get called when it comes back from full screen.
If you have any logic in there that affects video playback behavior, it'll get called unless you use some conditional logic to see if the video is still playing.

MPMoviePlayerController showing up late with http url request

I'm developing an iPad app with 4.1 and deployment-target 3.2.
I have a UITableViewController which adds a new View to the main view if a row becomes selected.
In the UIViewController of the new view I've following code in the viewDidLoad method:
- (void)viewDidLoad
{
MPMoviePlayerController* player = [[MPMoviePlayerController alloc] initWithContentURL:movieurl];
[[self.view viewWithTag:1] addSubview:player.view];
player.view.frame = CGRectMake(0, 0, 512, 289);
[player play];
[super viewDidLoad];
}
movieurl is an URL with a http address of our CDN.
the viewWithTag:1 is a simple standard UIView with the same frame like the player.
Now, if I click on the tablerow, the new view appears with the subview (with tag 1) in it.
And the player is not showing up. After some time, when the movie is ready to play, the movieplayer shows up like wanted and starts playing the movie.
The movieplayer works fine, it only appears really lately.
Is there any way to show the movieplayer directly on the view? Just before the movie has finished preloading. The player can be in a loadingstate or something like this.
The mainpoint is, that the player shows up from beginning, so there's no empty space in the view.
Thank you for your help!
I have the same question and a comment that before I upgraded to the most recent XCode that forced me to use 4.2 as base SDK this was working fine for me. I had 4.1 iPhone and the player showed up immediately with Movie Loading... label ...
This is no longer the case after upgrade and 4.2 base sdk selection even with 3.2 as target.

Resources