Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Get the dimensions of video programmatically in objective c

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.

like image 893
An1Ba7 Avatar asked Feb 14 '12 09:02

An1Ba7


4 Answers

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;
}
like image 60
Jay Avatar answered Oct 27 '22 17:10

Jay


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.

like image 20
mjwunderlich Avatar answered Oct 27 '22 15:10

mjwunderlich


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)

like image 20
alwaysmpe Avatar answered Oct 27 '22 17:10

alwaysmpe


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.

like image 31
sch Avatar answered Oct 27 '22 15:10

sch