I am a beginner in iOS development. I am developing an application where I require the size of a video which is getting played in the MPMoviePlayerController.
I am using the property naturalSize of MPMoviePlayerController to get the dimensions of the video that is played.
@property(nonatomic, readonly) CGSize naturalSize;
But the problem is that I can get the natural size only when the Video gets played in the MPMoviePlayerController.
Is there a way in which I can get the dimensions of the video before it gets played in the MPMoviePlayerController.
-- EDIT --
Is there any other workaround I can approach to solve this problem? Please help.
This is an old question but it's the first hit in google results.
The "naturalSize" property doesn't appear to be the resolution; in my testing it looks more like aspect ratio. For example I usually see naturalSize.height=9 and naturalSize.width=16
Here is some code to get the dimensions in pixels, which is probably what you want, and some other stuff.
// in a header file, perhaps
typedef struct VideoInfo {
size_t width;
size_t height;
CGFloat durationInSeconds;
CGFloat framesPerSecond;
} VideoInfo;
+ (VideoInfo) getVideoInfoFromUrl:(NSURL*)fileUrl
{
VideoInfo vidInfo;
vidInfo.width = vidInfo.height = 0;
vidInfo.durationInSeconds = vidInfo.framesPerSecond = 0;
@try {
// get duration and fps
AVURLAsset *asset = [AVURLAsset URLAssetWithURL:fileUrl options:nil];
vidInfo.durationInSeconds = CMTimeGetSeconds(asset.duration);
vidInfo.framesPerSecond = track.nominalFrameRate;
// get width and height in pixels
// you have to extract a frame from the video and get the dimensions from the frame
AVAsset *avasset = [AVAsset assetWithURL:fileUrl];
AVAssetReader *assetReader = [[AVAssetReader alloc] initWithAsset:avasset error:&error];
if (assetReader) {
NSArray<AVAssetTrack*> *tracks = [avasset tracksWithMediaType:AVMediaTypeVideo];
if (tracks && tracks.count > 0) {
AVAssetTrack* track = [tracks objectAtIndex:0];
NSDictionary *settings = @{(__bridge NSString *)kCVPixelBufferPixelFormatTypeKey: @(kCVPixelFormatType_420YpCbCr8BiPlanarFullRange)};
trackOutput = [AVAssetReaderTrackOutput assetReaderTrackOutputWithTrack:track outputSettings:settings];
[assetReader addOutput:trackOutput];
[assetReader startReading];
CMSampleBufferRef sampleBuffer = [trackOutput copyNextSampleBuffer];
if (sampleBuffer) {
CVImageBufferRef imageBuffer = CMSampleBufferGetImageBuffer(sampleBuffer);
if (imageBuffer && (CFGetTypeID(imageBuffer) == CVPixelBufferGetTypeID())) {
// note on iOS, CVImageBufferRef and CVPixelBufferRef are synonyms via:
// typedef CVImageBufferRef CVPixelBufferRef;
CVPixelBufferLockBaseAddress(imageBuffer, kCVPixelBufferLock_ReadOnly);
vidInfo.height = CVPixelBufferGetHeight(imageBuffer);
vidInfo.width = CVPixelBufferGetWidth(imageBuffer);
CVPixelBufferUnlockBaseAddress(imageBuffer, kCVPixelBufferLock_ReadOnly);
CFRelease(imageBuffer);
}
}
}
}
}
}
@catch (NSException *exception) {
}
return vidInfo;
}
You can read a video's dimensions using AVURLAsset
and AVAssetTrack
, like this:
NSURL *mediaURL; // Your video's URL
AVURLAsset *asset = [AVURLAsset URLAssetWithURL:mediaURL options:nil];
NSArray *tracks = [asset tracksWithMediaType:AVMediaTypeVideo];
AVAssetTrack *track = [tracks objectAtIndex:0];
Then using the AVAssetTrack
's naturalSize property:
CGSize mediaSize = track.naturalSize;
The benefit of getting the video's metadata this way is that you can access it immediately, without having to play the video or waiting for it to load.
Just thought i'd share my experiences for those that find this page.
The natural size is not actually the encoded resolution, it's the display resolution. this can be different from the encoded resolution for example if the pixel aspect ratio != 1 or (more common) there's a clean aperture metadata information in the encoded video.
To get the encoded resolution the only way I've found is to decode the first frame with eg AVASsetReaderTrackOutput then inspect the resulting pixel buffer with CVPixelBufferGetWidth (or GetHeight) to get the data resolution. if you use imageGenerator you get the display resolution (and an rgb bitmap of the display resolution)
It takes time for the MPMoviePlayerController to load the video metadata, so you should add a listener and wait for the naturalSize to be loaded. Something like this:
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(movieNaturalSizeAvailable:)
name:MPMovieNaturalSizeAvailableNotification
object:myMoviePlayer];
And in movieNaturalSizeAvailable:
, myVideoPlayer.naturalSize
gives you the desired value and after that, you can play the video.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With