ios - 如何创建一个具有真实持续时间的虚拟 AVPlayerItem?

标签 ios iphone avfoundation

我正在使用 AVPlayerAVSynchronizedLayer 上播放 CAKeyFrameAnimations。为了让播放器保持播放状态,因为我在动画期间不播放 AVAsset,我将 AVPlayerItemforwardPlaybackEndTime 设置为所需动画的期间。很遗憾。在 forwardPlaybackEndTime 期间似乎不可能 seekToTime:,因为 AVPlayer 总是回到开头。可能是因为它试图寻找 AVplayerItem 的持续时间。

我如何创建一个具有真实持续时间的虚拟 AVPlayerItem 来欺骗 AVPlayer 播放一些空的 AVPlayerItem 并让我seekToTime

最佳答案

不幸的是,seekToTime 只会搜索 AVPlayerItem 的持续时间。因此,需要创建一个虚拟播放器项目来生成可查找的持续时间。为了快速完成此操作,需要创建一个虚拟 AVplayerItem。下面是生成此类项目的实现示例。虽然很长,但这是必需的。祝你好运!

@interface FakeAsset ()

+ (CVPixelBufferRef)blackImagePixelBuffer;

@end

@implementation FakeAsset

+ (void)assetWithDuration:(CMTime)duration
        completitionBlock:(void (^)(AVAsset *))callBack
{
    NSError * error      = nil;
    NSString * assetPath = nil;
    NSUInteger i         = 0;
    do
    {
        assetPath =
        [NSTemporaryDirectory() stringByAppendingPathComponent:[NSString stringWithFormat:@"dummyAsset%i.m4v",i]];
        i++;
    }
    while ([[NSFileManager defaultManager] fileExistsAtPath:assetPath
                                                isDirectory:NO]);

    NSURL * fileURL = [NSURL fileURLWithPath:assetPath];

    NSParameterAssert(fileURL);

    AVAssetWriter * videoWriter =
    [[AVAssetWriter alloc] initWithURL:fileURL
                              fileType:AVFileTypeAppleM4V
                                 error:&error];
    NSParameterAssert(videoWriter);

    NSDictionary * compression  =
  @{
    AVVideoAverageBitRateKey      : @10,
    AVVideoProfileLevelKey        : AVVideoProfileLevelH264Main31,
    AVVideoMaxKeyFrameIntervalKey : @300
    };

    NSDictionary * outputSettings =
  @{
    AVVideoCodecKey                 : AVVideoCodecH264,
    AVVideoCompressionPropertiesKey : compression,
    AVVideoWidthKey                 : @120,
    AVVideoHeightKey                : @80
    };

    AVAssetWriterInput * videoWriterInput =
    [AVAssetWriterInput assetWriterInputWithMediaType:AVMediaTypeVideo
                                       outputSettings:outputSettings];
    NSParameterAssert(videoWriterInput);

    NSDictionary * parameters =
    @{(NSString *)kCVPixelBufferPixelFormatTypeKey : @(kCVPixelFormatType_32ARGB),
      (NSString *)kCVPixelBufferWidthKey           : @120,
      (NSString *)kCVPixelBufferHeightKey          : @80
      };

    AVAssetWriterInputPixelBufferAdaptor * adaptor =
    [AVAssetWriterInputPixelBufferAdaptor assetWriterInputPixelBufferAdaptorWithAssetWriterInput:videoWriterInput
                                                                     sourcePixelBufferAttributes:parameters];
    NSParameterAssert(adaptor);
    NSParameterAssert([videoWriter canAddInput:videoWriterInput]);

    videoWriterInput.expectsMediaDataInRealTime = NO;

    [videoWriter addInput:videoWriterInput];

    NSParameterAssert([videoWriter startWriting]);

    [videoWriter startSessionAtSourceTime:kCMTimeZero];

    dispatch_queue_t dispatchQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);

    [videoWriterInput requestMediaDataWhenReadyOnQueue:dispatchQueue
                                            usingBlock:^
    {
        int frame = 0;
        while (videoWriterInput.isReadyForMoreMediaData)
        {
            if (frame < 2)
            {
                CMTime frameTime = frame ? duration : kCMTimeZero;
                CVPixelBufferRef buffer = [self blackImagePixelBuffer];

                [adaptor appendPixelBuffer:buffer
                      withPresentationTime:frameTime];

                CVBufferRelease(buffer);

                ++frame;
            }
            else
            {
                [videoWriterInput markAsFinished];
                [videoWriter endSessionAtSourceTime:duration];

                dispatch_async(dispatch_get_main_queue(), ^
                {
                    [videoWriter finishWritingWithCompletionHandler:^()
                     {
                         NSLog(@"did finish writing the video!");
                         AVURLAsset * asset =
                         [AVURLAsset assetWithURL:videoWriter.outputURL];
                         callBack(asset);
                     }];
                });
                break;
            }
        }
    }];
}

+ (CVPixelBufferRef)blackImagePixelBuffer
{
    NSDictionary * options =
    @{
      (id)kCVPixelBufferCGImageCompatibilityKey         : @YES,
      (id)kCVPixelBufferCGBitmapContextCompatibilityKey : @YES
      };

    CVPixelBufferRef pxbuffer = NULL;
    CVReturn status =
    CVPixelBufferCreate(kCFAllocatorDefault, 120, 80, kCVPixelFormatType_32ARGB, (__bridge CFDictionaryRef)options, &pxbuffer);

    NSParameterAssert(status == kCVReturnSuccess && pxbuffer != NULL);

    CVPixelBufferLockBaseAddress(pxbuffer, 0);

    void * pxdata = CVPixelBufferGetBaseAddress(pxbuffer);
    NSParameterAssert(pxdata != NULL);

    CGColorSpaceRef rgbColorSpace = CGColorSpaceCreateDeviceRGB();
    //kCGImageAlphaPremultipliedFirst
    CGContextRef context = CGBitmapContextCreate(pxdata, 120, 80, 8, 4*120, rgbColorSpace, (CGBitmapInfo)kCGImageAlphaNoneSkipFirst);

    NSParameterAssert(context);
    CGContextSetFillColorWithColor(context, [UIColor blackColor].CGColor);
    CGContextFillRect(context,CGRectMake(0.f, 0.f, 120.f, 80.f));
    CGColorSpaceRelease(rgbColorSpace);
    CGContextRelease(context);

    CVPixelBufferUnlockBaseAddress(pxbuffer, 0);

    return pxbuffer;
}

关于ios - 如何创建一个具有真实持续时间的虚拟 AVPlayerItem?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21245182/

相关文章:

ios - UITableViewControllers 上的 prepareforSegue 方法

iphone - 使用 CoreData 与内存中的内存占用优势不明显/不明显 - 意见?

objective-c - Xcode 6.4 挂起 "Timed out waiting to acquire lock file for module ' AVFoundation'"for Release 配置

ios - 适用于 iPhone 和 iPad 的 iOS 实时视频聊天应用程序

iOS Storyboards 我应该使用它们吗?

ios - 与桌面应用程序一样在登录时获取用户 ID 选择屏幕,而不是每次都输入用户 ID

ios - Objective-C 常量 : Xcode build failure for simulator while success in iPhone

ios - 播放广播流时如何设置AVPLayer的音量

ios - AVFoundation:isExposureModeSupported 为 AVCaptureExposureModeAutoExpose 返回 FALSE

ios - 导航栏与 iphone 8 模拟器的 swift xcode 中的状态栏发生碰撞