在目标 c 中以编程方式获取视频的尺寸

Posted

技术标签:

【中文标题】在目标 c 中以编程方式获取视频的尺寸【英文标题】:Get the dimensions of video programmatically in objective c 【发布时间】:2012-02-14 09:02:56 【问题描述】:

我是 ios 开发的初学者。我正在开发一个应用程序,我需要在 MPMoviePlayerController 中播放的视频大小。

我正在使用 MPMoviePlayerController 的 naturalSize 属性来获取正在播放的视频的尺寸。

@property(nonatomic, readonly) CGSize naturalSize;

但问题是,只有在 MPMoviePlayerController 中播放视频时,我才能获得自然大小。

有没有一种方法可以让我在 MPMoviePlayerController 中播放视频之前获取它的尺寸。

-- 编辑--

我还有其他解决方法可以解决这个问题吗?请帮忙。

【问题讨论】:

还有一个duration属性MPMoviePlayerController @tipycalFlow 是的,我已经看到了那个属性,但是我想知道即将在 MPMoviePlayerController 对象中播放的视频在实际播放之前的高度和宽度。 【参考方案1】:

您可以使用AVURLAssetAVAssetTrack 读取视频的尺寸,如下所示:

NSURL *mediaURL; // Your video's URL
AVURLAsset *asset = [AVURLAsset URLAssetWithURL:mediaURL options:nil];
NSArray *tracks = [asset tracksWithMediaType:AVMediaTypeVideo];
AVAssetTrack *track = [tracks objectAtIndex:0];

然后使用AVAssetTrack 的 naturalSize 属性:

CGSize mediaSize = track.naturalSize;

以这种方式获取视频元数据的好处是您可以立即访问它,而无需播放视频或等待它加载。

【讨论】:

请注意:在我的应用程序中,我遇到了与[tracks objectAtIndex:0] 相关的异常,可能是因为轨道数组为空。一定要加上if (tracks.count >= 1)来检查数组是否不为空且索引0处是否存在对象。 我认为使用[tracks firstObject] 会更好。因为当数组为空时会返回nil。【参考方案2】:

MPMoviePlayerController 加载视频元数据需要时间,因此您应该添加一个侦听器并等待加载 naturalSize。像这样的:

[[NSNotificationCenter defaultCenter] addObserver:self
                selector:@selector(movieNaturalSizeAvailable:)
                name:MPMovieNaturalSizeAvailableNotification
                object:myMoviePlayer];

movieNaturalSizeAvailable: 中,myVideoPlayer.naturalSize 会为您提供所需的值,然后您就可以播放视频了。

【讨论】:

【参考方案3】:

只是想为找到此页面的人分享我的经验。

自然大小实际上不是编码分辨率,而是显示分辨率。这可能与编码分辨率不同,例如,如果像素纵横比 != 1 或(更常见)编码视频中有干净的孔径元数据信息。

要获得编码分辨率,我发现的唯一方法是使用例如 AVASsetReaderTrackOutput 解码第一帧,然后使用 CVPixelBufferGetWidth(或 GetHeight)检查生成的像素缓冲区以获得数据分辨率。如果你使用 imageGenerator 你会得到显示分辨率(以及显示分辨率的 rgb 位图)

【讨论】:

【参考方案4】:

这是一个老问题,但它是谷歌搜索结果中的第一个热门问题。

“naturalSize”属性似乎不是分辨率;在我的测试中,它看起来更像纵横比。例如我通常看到 naturalSize.height=9 和 naturalSize.width=16

这里有一些以像素为单位获取尺寸的代码,这可能是你想要的,还有一些其他的东西。

// 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;

【讨论】:

感谢您对周杰伦的支持。不幸的是,此代码未构建,请更新您的答案以帮助他人。最好的。 它构建。将结构放入头文件中。对于该函数,您将需要两个导入: 和 。您还需要链接 AVFoundation 框架。

以上是关于在目标 c 中以编程方式获取视频的尺寸的主要内容,如果未能解决你的问题,请参考以下文章

ffmpeg 如何获取视频尺寸?想把视频尺寸缩小为原尺寸的一半

如何一劳永逸地以编程方式获取android屏幕尺寸?

如何在目标 c 中以编程方式添加约束

在目标 c 中以编程方式替换菜单视图

如何以编程方式添加尺寸类自定义

目标 C:以编程方式添加带有约束的 UI 按钮