Вопрос по objective-c, avfoundation, avplayerlayer, avplayer – Как получить видеокадр из AVPlayer?

9

У меня есть класс PlayerView для отображения воспроизведения AVPlayer. Код отдокументация.

#import <UIKit/UIKit.h>
#import <AVFoundation/AVFoundation.h>

@interface PlayerView : UIView
@property (nonatomic) AVPlayer *player;
@end

@implementation PlayerView
+ (Class)layerClass {
    return [AVPlayerLayer class];
}
- (AVPlayer*)player {
    return [(AVPlayerLayer *)[self layer] player];
}
- (void)setPlayer:(AVPlayer *)player {
    [(AVPlayerLayer *)[self layer] setPlayer:player];
}
@end

Я настроил свой AVPlayer (содержит видео актив с размером 320x240) в этом PlayerView (с frame.size.width = 100, frame.size.height = 100), и мое видео изменено в размере. Как я могу получить размер видео после добавления в PlayerView?

Ваш Ответ

5   ответов
26

iOS 7.0 добавлена новая функция:

AVPlayerLayer имеет свойствоvideoRect.

Это не работает, даже если я добавил KVO, чтобы дождаться статуса AVPlayerStatusReadyToPlay. VideoRect по-прежнему возвращает все нули
После очередной попытки все работает. Таким образом, вам нужно KVO для AVPlayerItem, а не AVPlayer, и статус для проверки AVPlayerItemStatus.ReadyToPlay, а не AVPlayerStatusReadyToPlay. Этот подход верен, но комментарий @Yocoh немного вводит в заблуждение.
дождитесь, пока currentItem.status == AVPlayerStatusReadyToPlay, и вы получите кадр
Это работает для аспектаfit но не для аспектаfill, Согласноdocsэто прямоугольник отображения видеоизображенияwithin границы слоя & quot;
Для меня videoRect просто возвращает CGRectZero, хотя я вижу видео на экране. Я пользуюсь iOS 8
2

которое работает для меня, учитывает расположение AVPlayer в представлении. Я только что добавил это в пользовательский класс PlayerView. Я должен был решить это, потому что не кажется, что videoRect работает в 10.7.

- (NSRect) videoRect {
    NSRect theVideoRect = NSMakeRect(0,0,0,0);
    NSRect theLayerRect = self.playerLayer.frame;

    NSSize theNaturalSize = NSSizeFromCGSize([[[self.movie asset] tracksWithMediaType:AVMediaTypeVideo][0] naturalSize]);
    float movieAspectRatio = theNaturalSize.width/theNaturalSize.height;
    float viewAspectRatio = theLayerRect.size.width/theLayerRect.size.height;
    if (viewAspectRatio < movieAspectRatio) {
        theVideoRect.size.width = theLayerRect.size.width;
        theVideoRect.size.height = theLayerRect.size.width/movieAspectRatio;
        theVideoRect.origin.x = 0;
        theVideoRect.origin.y = (theLayerRect.size.height/2) - (theVideoRect.size.height/2);
}
    else if (viewAspectRatio > movieAspectRatio) {

        theVideoRect.size.width = movieAspectRatio * theLayerRect.size.height;
        theVideoRect.size.height = theLayerRect.size.height;
        theVideoRect.origin.x = (theLayerRect.size.width/2) - (theVideoRect.size.width/2);
        theVideoRect.origin.y = 0;
    }
    return theVideoRect;
}
5

Нашел решение:

Добавить в класс PlayerView:

- (CGRect)videoContentFrame {
    AVPlayerLayer *avLayer = (AVPlayerLayer *)[self layer];
    // AVPlayerLayerContentLayer
    CALayer *layer = (CALayer *)[[avLayer sublayers] objectAtIndex:0];
    CGRect transformedBounds = CGRectApplyAffineTransform(layer.bounds, CATransform3DGetAffineTransform(layer.sublayerTransform));
    return transformedBounds;
}
да уж. xcode 4.5.1, базовый sdk 6.0. Andrey Banshchikov
Это не работает для меня в Xcode4.5, iOS6 SDK, сборка цели 4.3. получить размер (0,0). Это все еще работает для вас сейчас?
1

Эрик Бадрос & apos; ответ портирован на iOS. Я также добавил предпочтительную обработку Transform. Это предполагает_player являетсяAVPlayer

- (CGRect) videoRect {
    CGRect theVideoRect = CGRectZero;

    // Replace this with whatever frame your AVPlayer is playing inside of:
    CGRect theLayerRect = self.playerLayer.frame;

    AVAssetTrack *track = [_player.currentItem.asset tracksWithMediaType:AVMediaTypeVideo][0];
    CGSize theNaturalSize = [track naturalSize];
    theNaturalSize = CGSizeApplyAffineTransform(theNaturalSize, track.preferredTransform);
    theNaturalSize.width = fabs(theNaturalSize.width);
    theNaturalSize.height = fabs(theNaturalSize.height);

    CGFloat movieAspectRatio = theNaturalSize.width / theNaturalSize.height;
    CGFloat viewAspectRatio = theLayerRect.size.width / theLayerRect.size.height;

    // Note change this *greater than* to a *less than* if your video will play in aspect fit mode (as opposed to aspect fill mode)
    if (viewAspectRatio > movieAspectRatio) {
        theVideoRect.size.width = theLayerRect.size.width;
        theVideoRect.size.height = theLayerRect.size.width / movieAspectRatio;
        theVideoRect.origin.x = 0;
        theVideoRect.origin.y = (theLayerRect.size.height - theVideoRect.size.height) / 2;
    } else if (viewAspectRatio < movieAspectRatio) {
        theVideoRect.size.width = movieAspectRatio * theLayerRect.size.height;
        theVideoRect.size.height = theLayerRect.size.height;
        theVideoRect.origin.x = (theLayerRect.size.width - theVideoRect.size.width) / 2;
        theVideoRect.origin.y = 0;
    }
    return theVideoRect;
}
Спасибо @tettoffensive
у тебя ошибка и если и еще, если есть & gt; & quot;
0

Это сработало для меня. Когда у вас нет AVPLayerLayer.

- (CGRect)videoRect {
    // @see http://stackoverflow.com/a/6565988/1545158

    AVAssetTrack *track = [[self.player.current,Item.asset tracksWithMediaType:AVMediaTypeVideo] firstObject];
    if (!track) {
        return CGRectZero;
    }

    CGSize trackSize = [track naturalSize];
    CGSize videoViewSize = self.videoView.bounds.size;

    CGFloat trackRatio = trackSize.width / trackSize.height;
    CGFloat videoViewRatio = videoViewSize.width / videoViewSize.height;

    CGSize newSize;

    if (videoViewRatio > trackRatio) {
        newSize = CGSizeMake(trackSize.width * videoViewSize.height / trackSize.height, videoViewSize.height);
    } else {
        newSize = CGSizeMake(videoViewSize.width, trackSize.height * videoViewSize.width / trackSize.width);
    }

    CGFloat newX = (videoViewSize.width - newSize.width) / 2;
    CGFloat newY = (videoViewSize.height - newSize.height) / 2;

    return CGRectMake(newX, newY, newSize.width, newSize.height);

}

Похожие вопросы