2014-01-30 10 views
1

하나의 정지 이미지에서 성공적으로 동영상을 만들 수 있습니다. 그러나 배경 이미지 위에 슈퍼 임 포즈해야하는 더 작은 이미지 배열도 제공됩니다. assetWriter를 사용하여 프레임을 추가하는 과정을 반복하려했지만 이미 작성한 동일한 프레임에 쓸 수 없으므로 오류가 발생합니다.AVAssetWriter - 중첩 된 이미지 용 픽셀 버퍼

그래서 프레임을 작성하기 전에 각 프레임의 전체 픽셀 버퍼를 완전히 작성해야한다고 가정합니다. 하지만 어떻게 할거 니?

가 여기에 하나의 배경 이미지 렌더링 작업 내 코드입니다 : 다시

CGSize renderSize = CGSizeMake(320, 568); 
    NSUInteger fps = 30; 

    self.assetWriter = [[AVAssetWriter alloc] initWithURL: 
            [NSURL fileURLWithPath:videoOutputPath] fileType:AVFileTypeQuickTimeMovie 
                   error:&error]; 
    NSParameterAssert(self.assetWriter); 

    NSDictionary *videoSettings = [NSDictionary dictionaryWithObjectsAndKeys: 
            AVVideoCodecH264, AVVideoCodecKey, 
            [NSNumber numberWithInt:renderSize.width], AVVideoWidthKey, 
            [NSNumber numberWithInt:renderSize.height], AVVideoHeightKey, 
            nil]; 

    AVAssetWriterInput* videoWriterInput = [AVAssetWriterInput 
              assetWriterInputWithMediaType:AVMediaTypeVideo 
              outputSettings:videoSettings]; 


    AVAssetWriterInputPixelBufferAdaptor *adaptor = [AVAssetWriterInputPixelBufferAdaptor 
                assetWriterInputPixelBufferAdaptorWithAssetWriterInput:videoWriterInput 
                sourcePixelBufferAttributes:nil]; 

    NSParameterAssert(videoWriterInput); 
    NSParameterAssert([self.assetWriter canAddInput:videoWriterInput]); 
    videoWriterInput.expectsMediaDataInRealTime = YES; 
    [self.assetWriter addInput:videoWriterInput]; 

    //Start a session: 
    [self.assetWriter startWriting]; 
    [self.assetWriter startSessionAtSourceTime:kCMTimeZero]; 

    CVPixelBufferRef buffer = NULL; 

    NSInteger totalFrames = 90; //3 seconds 

    //process the bg image 
    int frameCount = 0; 

    UIImage* resizedImage = [UIImage resizeImage:self.bgImage size:renderSize]; 
    buffer = [self pixelBufferFromCGImage:[resizedImage CGImage]]; 

    BOOL append_ok = YES; 
    int j = 0; 
    while (append_ok && j < totalFrames) { 
     if (adaptor.assetWriterInput.readyForMoreMediaData) { 

      CMTime frameTime = CMTimeMake(frameCount,(int32_t) fps); 
      append_ok = [adaptor appendPixelBuffer:buffer withPresentationTime:frameTime]; 
      if(!append_ok){ 
       NSError *error = self.assetWriter.error; 
       if(error!=nil) { 
        NSLog(@"Unresolved error %@,%@.", error, [error userInfo]); 
       } 
      } 
     } 
     else { 
      printf("adaptor not ready %d, %d\n", frameCount, j); 
      [NSThread sleepForTimeInterval:0.1]; 
     } 
     j++; 
     frameCount++; 
    } 
    if (!append_ok) { 
     printf("error appending image %d times %d\n, with error.", frameCount, j); 
    } 


    //Finish the session: 
    [videoWriterInput markAsFinished]; 
    [self.assetWriter finishWritingWithCompletionHandler:^() { 
     self.assetWriter = nil; 
    }]; 

- (CVPixelBufferRef)pixelBufferFromCGImage:(CGImageRef)image { 

    CGSize size = CGSizeMake(320,568); 

    NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys: 
          [NSNumber numberWithBool:YES], kCVPixelBufferCGImageCompatibilityKey, 
          [NSNumber numberWithBool:YES], kCVPixelBufferCGBitmapContextCompatibilityKey, 
          nil]; 
    CVPixelBufferRef pxbuffer = NULL; 

    CVReturn status = CVPixelBufferCreate(kCFAllocatorDefault, 
              size.width, 
              size.height, 
              kCVPixelFormatType_32ARGB, 
              (__bridge CFDictionaryRef) options, 
              &pxbuffer); 
    if (status != kCVReturnSuccess){ 
     NSLog(@"Failed to create pixel buffer"); 
    } 

    CVPixelBufferLockBaseAddress(pxbuffer, 0); 
    void *pxdata = CVPixelBufferGetBaseAddress(pxbuffer); 

    CGColorSpaceRef rgbColorSpace = CGColorSpaceCreateDeviceRGB(); 
    CGContextRef context = CGBitmapContextCreate(pxdata, size.width, 
               size.height, 8, 4*size.width, rgbColorSpace, 
               (CGBitmapInfo)kCGImageAlphaPremultipliedFirst); 

    CGContextConcatCTM(context, CGAffineTransformMakeRotation(0)); 
    CGContextDrawImage(context, CGRectMake(0, 0, CGImageGetWidth(image), 
              CGImageGetHeight(image)), image); 
    CGColorSpaceRelease(rgbColorSpace); 
    CGContextRelease(context); 

    CVPixelBufferUnlockBaseAddress(pxbuffer, 0); 

    return pxbuffer; 
} 

을, 문제는 배경 이미지의 픽셀 버퍼와 상부에 적층 될 것이다 N 작은 이미지의 배열을 만드는 방법입니다 bg 이미지의 이 다음 단계는 또한 작은 비디오를 중첩하는 것입니다.

답변

0

이미지 버퍼의 픽셀 정보를 추가 할 수 있습니다. 이 예제 코드는 ARGB 픽셀 버퍼를 통해 BGRA 데이터를 추가하는 방법을 보여줍니다.

// Try to create a pixel buffer with the image mat 
uint8_t* videobuffer = m_imageBGRA.data; 


// From image buffer (BGRA) to pixel buffer 
CVPixelBufferRef pixelBuffer = NULL; 
CVReturn status = CVPixelBufferCreate (NULL, m_width, m_height, kCVPixelFormatType_32ARGB, NULL, &pixelBuffer); 
if ((pixelBuffer == NULL) || (status != kCVReturnSuccess)) 
{ 
    NSLog(@"Error CVPixelBufferPoolCreatePixelBuffer[pixelBuffer=%@][status=%d]", pixelBuffer, status); 
    return; 
} 
else 
{ 
    uint8_t *videobuffertmp = videobuffer; 
    CVPixelBufferLockBaseAddress(pixelBuffer, 0); 
    GLubyte *pixelBufferData = (GLubyte *)CVPixelBufferGetBaseAddress(pixelBuffer); 

    // Add data for all the pixels in the image 
    for(int row=0 ; row<m_width ; ++row) 
    { 
     for(int col=0 ; col<m_height ; ++col) 
     { 
      memcpy(&pixelBufferData[0], &videobuffertmp[3], sizeof(uint8_t));  // alpha 
      memcpy(&pixelBufferData[1], &videobuffertmp[2], sizeof(uint8_t));  // red 
      memcpy(&pixelBufferData[2], &videobuffertmp[1], sizeof(uint8_t));  // green 
      memcpy(&pixelBufferData[3], &videobuffertmp[0], sizeof(uint8_t));  // blue 
      // Move the buffer pointer to the next pixel 
      pixelBufferData += 4*sizeof(uint8_t); 
      videobuffertmp += 4*sizeof(uint8_t); 
     } 
    } 


    CVPixelBufferUnlockBaseAddress(pixelBuffer, 0); 
} 

따라서이 예에서는 이미지 (비디오 버퍼)에 대한 데이터가 픽셀 버퍼에 추가됩니다. 일반적으로 픽셀 데이터는 단일 행에 저장되므로 각 픽셀에 대해 4 바이트 (이 경우 'uint8_t'로 표시)가 있습니다. 먼저 파란색, 녹색, 다음 빨간색 및 마지막 알파 값 (기억 원래 이미지는 BGRA 형식 임). 픽셀 버퍼도 같은 방식으로 작동하므로 데이터는 sigle 행 (이 경우 'kCVPixelFormatType_32ARGB'매개 변수로 정의 된대로 ARGB)에 저장됩니다.

memcpy(&pixelBufferData[0], &videobuffertmp[3], sizeof(uint8_t));  // alpha 
memcpy(&pixelBufferData[1], &videobuffertmp[2], sizeof(uint8_t));  // red 
memcpy(&pixelBufferData[2], &videobuffertmp[1], sizeof(uint8_t));  // green 
memcpy(&pixelBufferData[3], &videobuffertmp[0], sizeof(uint8_t));  // blue 

그리고 우리는 픽셀이 추가되면, 우리는에 의해 픽셀을 앞으로 이동할 수 있습니다 :

// Move the buffer pointer to the next pixel 
pixelBufferData += 4*sizeof(uint8_t); 
videobuffertmp += 4*sizeof(uint8_t); 

이동 포인터 4 코드의이 작품은 pixelbuffer 구성과 일치하는 픽셀 데이터를 재정렬 앞으로 바이트.

이미지가 작 으면 더 작은 영역에 추가하거나 알파 값을 대상 데이터로 사용하여 'if'를 정의 할 수 있습니다. 예 :

// Add data for all the pixels in the image 
for(int row=0 ; row<m_width ; ++row) 
{ 
    for(int col=0 ; col<m_height ; ++col) 
    { 
     if(videobuffertmp[3] > 10) // check alpha channel 
     { 
      memcpy(&pixelBufferData[0], &videobuffertmp[3], sizeof(uint8_t));  // alpha 
      memcpy(&pixelBufferData[1], &videobuffertmp[2], sizeof(uint8_t));  // red 
      memcpy(&pixelBufferData[2], &videobuffertmp[1], sizeof(uint8_t));  // green 
      memcpy(&pixelBufferData[3], &videobuffertmp[0], sizeof(uint8_t));  // blue 
     } 
     // Move the buffer pointer to the next pixel 
     pixelBufferData += 4*sizeof(uint8_t); 
     videobuffertmp += 4*sizeof(uint8_t); 
    } 
}