2015-02-26 3 views
1

Мне нужно создать бесшумное «видео» переменной длины (то есть его просто изображение), которое я могу использовать в AVPlayer на ios.AVPlayerItem, который состоит из изображения

Кто-нибудь знает, как я могу создать AVPlayerItem, который просто состоит из изображения, которое длится в течение n секунд?

Если мне нужно сгенерировать файл .mov, мне понадобится, чтобы этот файл был очень маленьким.

ответ

2

Хорошо, я пошел писать собственное видео. Оказывается, если вы пишете видео с изображением, которое вы хотите в первом и последнем ключевых кадрах (и это единственные ключевые кадры), тогда вы получите приятное компактное видео, которое не займет слишком много времени, чтобы писать.

Мой код выглядит следующим образом:

- (CVPixelBufferRef) createPixelBufferOfSize: (CGSize) size fromUIImage: (UIImage*) pImage 
{ 
    NSNumber*   numYes  = [NSNumber numberWithBool: YES]; 
    NSDictionary*  pOptions = [NSDictionary dictionaryWithObjectsAndKeys: numYes, kCVPixelBufferCGImageCompatibilityKey, 
                      numYes, kCVPixelBufferCGBitmapContextCompatibilityKey, 
                      nil]; 

    CVPixelBufferRef retBuffer = NULL; 
    CVReturn   status  = CVPixelBufferCreate(kCFAllocatorDefault, size.width, size.height, kCVPixelFormatType_32ARGB, (__bridge CFDictionaryRef)pOptions, &retBuffer); 

    CVPixelBufferLockBaseAddress(retBuffer, 0); 
    void*    pPixelData = CVPixelBufferGetBaseAddress(retBuffer); 

    CGColorSpaceRef  colourSpace = CGColorSpaceCreateDeviceRGB(); 
    CGContextRef  context  = CGBitmapContextCreate(pPixelData, size.width, size.height, 8, 4 * size.width, colourSpace, (CGBitmapInfo)kCGImageAlphaNoneSkipFirst); 

    CGSize    inSize  = pImage.size; 
    float    inAspect = inSize.width/inSize.height; 
    float    outAspect = size.width /size.height; 

    CGRect drawRect; 
    if (inAspect > outAspect) 
    { 
     float scale = inSize.width/size.width; 
     CGSize outSize = CGSizeMake(size.width, inSize.height/scale); 

     drawRect  = CGRectMake(0, (size.height/2) - (outSize.height/2), outSize.width, outSize.height); 
    } 
    else 
    { 
     float scale = inSize.height/size.height; 
     CGSize outSize = CGSizeMake(inSize.width/scale, size.height); 

     drawRect  = CGRectMake((size.width/2) - (outSize.width/2), 0, outSize.width, outSize.height); 
    } 

    CGContextDrawImage(context, drawRect, [pImage CGImage]); 

    CGColorSpaceRelease(colourSpace); 
    CGContextRelease(context); 

    CVPixelBufferUnlockBaseAddress(retBuffer, 0); 

    return retBuffer; 
} 

- (void) writeVideo: (NSURL*) pURL withImage: (UIImage*) pImage ofLength: (NSTimeInterval) length 
{ 
    [[NSFileManager defaultManager] removeItemAtURL: pURL error: nil]; 

    NSError*    pError    = nil; 
    AVAssetWriter*   pAssetWriter  = [AVAssetWriter assetWriterWithURL: pURL fileType: AVFileTypeQuickTimeMovie error: &pError]; 

    const int    kVidWidth   = 1920;//pImage.size.width; 
    const int    kVidHeight   = 1080;//pImage.size.height; 

    NSNumber*    numVidWidth   = [NSNumber numberWithInt: kVidWidth]; 
    NSNumber*    numVidHeight  = [NSNumber numberWithInt: kVidHeight]; 

    NSDictionary*   pVideoSettings  = [NSDictionary dictionaryWithObjectsAndKeys: AVVideoCodecH264, AVVideoCodecKey, 
                           numVidWidth,  AVVideoWidthKey, 
                           numVidHeight,  AVVideoHeightKey, 
                           nil]; 

    AVAssetWriterInput*  pAssetWriterInput = [AVAssetWriterInput assetWriterInputWithMediaType: AVMediaTypeVideo 
                        outputSettings: pVideoSettings]; 
    [pAssetWriter addInput: pAssetWriterInput]; 

    AVAssetWriterInputPixelBufferAdaptor* pAssetWriterInputPixelBufferAdaptor = 
               [AVAssetWriterInputPixelBufferAdaptor assetWriterInputPixelBufferAdaptorWithAssetWriterInput: pAssetWriterInput 
                               sourcePixelBufferAttributes: pVideoSettings]; 

    __block volatile int finished = 0; 

    [pAssetWriter startWriting]; 
    [pAssetWriter startSessionAtSourceTime: kCMTimeZero]; 

    // Write the image. 
    CVPixelBufferRef  pixelBuffer  = [self createPixelBufferOfSize: CGSizeMake(kVidWidth, kVidHeight) fromUIImage: pImage]; 

    [pAssetWriterInputPixelBufferAdaptor appendPixelBuffer: pixelBuffer withPresentationTime: kCMTimeZero]; 
    [pAssetWriterInputPixelBufferAdaptor appendPixelBuffer: pixelBuffer withPresentationTime: CMTimeMake(length * 1000000, 1000000)]; 

    CVPixelBufferRelease(pixelBuffer); 

    [pAssetWriterInput markAsFinished]; 

    // Set end time accurate to micro-seconds. 
    [pAssetWriter endSessionAtSourceTime: CMTimeMake(length * 1000000, 1000000)]; 
    [pAssetWriter finishWritingWithCompletionHandler:^
     { 
      OSAtomicIncrement32(&finished); 
     }]; 

    // Wait for the writing to complete. 
    while(finished == 0) 
    { 
     [NSThread sleepForTimeInterval: 0.01]; 
    } 
} 

Вы можете заметить, что я устанавливаю видео, чтобы всегда быть 1920х1080 и Letterboxing изображение на месте.

1

Вы можете создать .mov видео с этим образом, который играет очень короткий промежуток времени, скажем, второй, и цикл видео с

yourplayer.actionAtItemEnd = AVPlayerActionAtItemEndNone; 

[[NSNotificationCenter defaultCenter] addObserver:self 
              selector:@selector(playerItemDidReachEnd:) 
               name:AVPlayerItemDidPlayToEndTimeNotification 
               object:[yourplayer currentItem]]; 


- (void)playerItemDidReachEnd:(NSNotification *)notification { 
     [[yourplayer currentItem] seekToTime:kCMTimeZero]; 
} 

Если видео имеет длительность n секунд, затем вы можете использовать счетчик в своем методе playerItemDidReachEnd и установить лимит.

+0

Хорошая идея. Как бы я это сделал, если бы это было не кратно 1 секунде? – Goz

+0

Почему бы вам просто не использовать и UIImageView для показа изображения? – kchromik

+0

Не вариант к сожалению. – Goz