2011-05-31 11 views
12

मैं छवियों से वीडियो बनाने के लिए फ़ाइल में CGImages लिखने के लिए AVAssetWriter का उपयोग करने का प्रयास कर रहा हूं।AVAssetWriter Woes

मुझे यह सिम्युलेटर पर तीन अलग-अलग तरीकों से सफलतापूर्वक काम करने के लिए मिला है, लेकिन प्रत्येक विधि आईओएस 4 पर आईफोन 4 चलाने में विफल रही है।

यह सब पिक्सेल बफर के साथ करना है।

मेरी पहली विधि केवल पूल का उपयोग किये बिना पिक्सेल बफर बनाने की आवश्यकता थी। यह काम करता है, लेकिन डिवाइस पर काम करने के लिए बहुत स्मृति गहन है।

मेरी दूसरी विधि अनुशंसित AVAssetWriterInputPixelBufferAdaptor का उपयोग करना था और उसके बाद एडाप्टर पिक्सेलबफरपूल से पिक्सेल बफर खींचें CVPixelBufferPoolCreatePixelBuffer के साथ।

यह सिम्युलेटर पर भी काम करता है, लेकिन डिवाइस पर विफल रहता है क्योंकि एडाप्टर के पिक्सेल बफर पूल को आवंटित नहीं किया जाता है। मुझे कोई त्रुटि संदेश नहीं मिला।

आखिरकार, मैंने अपने पिक्सेल बफर पूल द्वारा CVPixelBufferPoolCreate के साथ बनाने का प्रयास किया। यह सिम्युलेटर में भी काम करता है लेकिन डिवाइस पर, जब तक मैं पिक्सेल बफर को एपेंड पिक्सेलबफर के साथ जोड़ने की कोशिश नहीं करता तब तक सब कुछ ठीक काम करता है जो हर बार विफल रहता है।

मुझे वेब पर इस पर बहुत कम जानकारी मिली है। मैंने अपने उदाहरणों को मेरे द्वारा प्राप्त किए गए उदाहरणों पर आधारित किया है, लेकिन अब दिनों के लिए कोई भाग्य नहीं है। अगर किसी को AVAssetWriter के साथ सफलतापूर्वक ऐसा करने का अनुभव है, तो कृपया एक नज़र डालें और मुझे बताएं कि क्या आप जगह से कुछ भी देखते हैं।

नोट: आप प्रयासों के ब्लॉक पर टिप्पणी देखेंगे।

पहले, सेटअप

- (BOOL) openVideoFile: (NSString *) path withSize:(CGSize)imageSize { 
size = CGSizeMake (480.0, 320.0);//imageSize; 

NSError *error = nil; 
videoWriter = [[AVAssetWriter alloc] initWithURL: 
           [NSURL fileURLWithPath:path] fileType:AVFileTypeQuickTimeMovie 
                  error:&error]; 
if (error != nil) 
    return NO; 

NSDictionary *videoCleanApertureSettings = [NSDictionary dictionaryWithObjectsAndKeys: 
              [NSNumber numberWithDouble:size.width], AVVideoCleanApertureWidthKey, 
              [NSNumber numberWithDouble:size.height], AVVideoCleanApertureHeightKey, 
              [NSNumber numberWithInt:10], AVVideoCleanApertureHorizontalOffsetKey, 
              [NSNumber numberWithInt:10], AVVideoCleanApertureVerticalOffsetKey, 
              nil]; 


NSDictionary *videoAspectRatioSettings = [NSDictionary dictionaryWithObjectsAndKeys: 
              [NSNumber numberWithInt:1], AVVideoPixelAspectRatioHorizontalSpacingKey, 
              [NSNumber numberWithInt:1],AVVideoPixelAspectRatioVerticalSpacingKey, 
              nil]; 



NSDictionary *codecSettings = [NSDictionary dictionaryWithObjectsAndKeys: 
           //[NSNumber numberWithInt:960000], AVVideoAverageBitRateKey, 
           // [NSNumber numberWithInt:1],AVVideoMaxKeyFrameIntervalKey, 
           videoCleanApertureSettings, AVVideoCleanApertureKey, 
           videoAspectRatioSettings, AVVideoPixelAspectRatioKey, 
           //AVVideoProfileLevelH264Main31, AVVideoProfileLevelKey, 
           nil]; 

NSDictionary *videoSettings = [NSDictionary dictionaryWithObjectsAndKeys: 
           AVVideoCodecH264, AVVideoCodecKey, 
           codecSettings,AVVideoCompressionPropertiesKey, 
           [NSNumber numberWithDouble:size.width], AVVideoWidthKey, 
           [NSNumber numberWithDouble:size.height], AVVideoHeightKey, 
           nil]; 
writerInput = [[AVAssetWriterInput 
            assetWriterInputWithMediaType:AVMediaTypeVideo 
            outputSettings:videoSettings] retain]; 
NSMutableDictionary * bufferAttributes = [[NSMutableDictionary alloc] init]; 
[bufferAttributes setObject: [NSNumber numberWithInt: kCVPixelFormatType_32ARGB] 
        forKey: (NSString *) kCVPixelBufferPixelFormatTypeKey]; 
[bufferAttributes setObject: [NSNumber numberWithInt: 480] 
        forKey: (NSString *) kCVPixelBufferWidthKey]; 
[bufferAttributes setObject: [NSNumber numberWithInt: 320] 
        forKey: (NSString *) kCVPixelBufferHeightKey]; 


//NSDictionary *bufferAttributes = [NSDictionary dictionaryWithObjectsAndKeys: [NSNumber numberWithInt:kCVPixelFormatType_32ARGB], kCVPixelBufferPixelFormatTypeKey, nil]; 
//[bufferAttributes setObject: [NSNumber numberWithInt: 640] 
//     forKey: (NSString *) kCVPixelBufferWidthKey]; 
//[bufferAttributes setObject: [NSNumber numberWithInt: 480] 
//     forKey: (NSString *) kCVPixelBufferHeightKey]; 
adaptor = [[AVAssetWriterInputPixelBufferAdaptor 
      assetWriterInputPixelBufferAdaptorWithAssetWriterInput:writerInput 
      sourcePixelBufferAttributes:nil] retain]; 

//CVPixelBufferPoolCreate (kCFAllocatorSystemDefault,NULL,(CFDictionaryRef)bufferAttributes,&pixelBufferPool); 
//Create buffer pool 
NSMutableDictionary*  attributes; 
attributes = [NSMutableDictionary dictionary]; 

int width = 480; 
int height = 320; 

[attributes setObject:[NSNumber numberWithInt:kCVPixelFormatType_32ARGB] forKey:(NSString*)kCVPixelBufferPixelFormatTypeKey]; 
[attributes setObject:[NSNumber numberWithInt:width] forKey: (NSString*)kCVPixelBufferWidthKey]; 
[attributes setObject:[NSNumber numberWithInt:height] forKey: (NSString*)kCVPixelBufferHeightKey]; 
CVReturn theError = CVPixelBufferPoolCreate(kCFAllocatorDefault, NULL, (CFDictionaryRef) attributes, &pixelBufferPool);           


NSParameterAssert(writerInput); 
NSParameterAssert([videoWriter canAddInput:writerInput]); 
[videoWriter addInput:writerInput]; 

writerInput.expectsMediaDataInRealTime = YES; 

//Start a session: 
[videoWriter startWriting]; 
[videoWriter startSessionAtSourceTime:kCMTimeZero]; 

buffer = NULL; 
lastTime = kCMTimeZero; 
presentTime = kCMTimeZero; 

return YES; 
} 

इसके बाद, दो तरीकों कि लेखक संलग्न करें और संलग्न करने के लिए पिक्सेल बफर पैदा करते हैं।

- (void) writeImageToMovie:(CGImageRef)image 
{ 
    if([writerInput isReadyForMoreMediaData]) 
    { 
//   CMTime frameTime = CMTimeMake(1, 20); 
//   CMTime lastTime=CMTimeMake(i, 20); //i is from 0 to 24 of the loop above 
//   CMTime presentTime=CMTimeAdd(lastTime, frameTime); 

     buffer = [self pixelBufferFromCGImage:image]; 
     BOOL success = [adaptor appendPixelBuffer:buffer withPresentationTime:presentTime]; 
     if (!success) NSLog(@"Failed to appendPixelBuffer"); 
     CVPixelBufferRelease(buffer); 

     presentTime = CMTimeAdd(lastTime, CMTimeMake(5, 1000)); 
     lastTime = presentTime; 
    } 
    else 
    { 
     NSLog(@"error - writerInput not ready"); 
    } 
} 

- (CVPixelBufferRef)pixelBufferFromCGImage:(CGImageRef)image 
{ 
CVPixelBufferRef pxbuffer; 
NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys: 
         [NSNumber numberWithBool:YES], kCVPixelBufferCGImageCompatibilityKey, 
         [NSNumber numberWithBool:YES], kCVPixelBufferCGBitmapContextCompatibilityKey, 
         nil]; 
if (pixelBufferPool == NULL) NSLog(@"pixelBufferPool is null!"); 
CVReturn status = CVPixelBufferPoolCreatePixelBuffer (NULL, pixelBufferPool, &pxbuffer); 
/*if (pxbuffer == NULL) { 
    CVReturn status = CVPixelBufferCreate(kCFAllocatorDefault, size.width, 
             size.height, kCVPixelFormatType_32ARGB, (CFDictionaryRef) options, 
             &pxbuffer); 

}*/ 
//NSParameterAssert(status == kCVReturnSuccess && pxbuffer != NULL); 


CVPixelBufferLockBaseAddress(pxbuffer, 0); 
void *pxdata = CVPixelBufferGetBaseAddress(pxbuffer); 
//NSParameterAssert(pxdata != NULL); 

CGColorSpaceRef rgbColorSpace = CGColorSpaceCreateDeviceRGB(); 
CGContextRef context = CGBitmapContextCreate(pxdata, size.width, 
              size.height, 8, 4*size.width, rgbColorSpace, 
              kCGImageAlphaNoneSkipFirst); 
//NSParameterAssert(context); 
CGContextConcatCTM(context, CGAffineTransformMakeRotation(0)); 
CGContextDrawImage(context, CGRectMake(90, 10, CGImageGetWidth(image), 
             CGImageGetHeight(image)), image); 
CGColorSpaceRelease(rgbColorSpace); 
CGContextRelease(context); 

CVPixelBufferUnlockBaseAddress(pxbuffer, 0); 

return pxbuffer; 
} 
+0

वाह, यह dissapointing है। किसी के पास कोई सुराग नहीं है? –

उत्तर

2

मुझे इस मुद्दे का समाधान मिला है।

यदि आप AVAudioPlayer और AVAssetWriter सही ढंग से व्यवहार करना चाहते हैं, तो आपके पास 'मिश्रित' श्रेणी और ऑडियो सत्र श्रेणी होनी चाहिए।

आप एक श्रेणी का उपयोग कर सकते हैं जो AVAudioSessionCategoryAmbient की तरह मिश्रित है।

हालांकि, मुझे AVAudioSessionCategoryPlayAndRecord का उपयोग करने की आवश्यकता है।

आप इस लागू करने से mixable होने के लिए किसी भी वर्ग के लिए सेट कर सकते हैं:

OSStatus propertySetError = 0; 

UInt32 allowMixing = true; 

propertySetError = AudioSessionSetProperty (
         kAudioSessionProperty_OverrideCategoryMixWithOthers, // 1 
         sizeof (allowMixing),         // 2 
         &allowMixing           // 3 
        ); 
+4

मुझे समझ में नहीं आता कि यह समाधान आपके मूल कोड से कैसे संबंधित है। – ninjudd

1

ठीक है, पहले आप जब कि अनुकूलक वस्तु बनाने कुछ bufferAttributes पारित करने के लिए की जरूरत है:

NSDictionary *bufferAttributes = [NSDictionary dictionaryWithObjectsAndKeys: [NSNumber numberWithInt:kCVPixelFormatType_32BGRA], kCVPixelBufferPixelFormatTypeKey, nil]; 

AVAssetWriterInputPixelBufferAdaptor *adaptor = [AVAssetWriterInputPixelBufferAdaptor 
               assetWriterInputPixelBufferAdaptorWithAssetWriterInput:_videoWriterInput 
               sourcePixelBufferAttributes:bufferAttributes]; 

फिर CVPixelBufferPoolCreate करने के लिए कि कॉल निकालने के लिए, वहाँ पहले से ही एक पिक्सेल बफर एडाप्टर वस्तु में बनाए गए पूल, इसलिए कॉल है सिर्फ इस बजाय:

   CVPixelBufferRef pixelBuffer = NULL; 
      CVPixelBufferPoolCreatePixelBuffer(NULL, adaptor.pixelBufferPool, &pixelBuffer); 
      CVPixelBufferLockBaseAddress(pixelBuffer, 0); 

      // ...fill the pixelbuffer here 

      CVPixelBufferUnlockBaseAddress(pixelBuffer, 0); 

      CMTime frameTime = CMTimeMake(frameCount,(int32_t) 30); 

      BOOL res = [adaptor appendPixelBuffer:pixelBuffer withPresentationTime:frameTime]; 
      CVPixelBufferRelease(pixelBuffer); 
      CFRelease(sampleBuffer); 

मुझे लगता है कि यह करना चाहिए, मैं एक ऐसी ही त्रुटि कुछ बिंदु पर किया है और मैं एडाप्टर और pix बनाने के द्वारा इसे हल एल बफर जैसा कि यहां दिखाया गया है ..

+0

उपर्युक्त सुझाव के अलावा, आपको यह सुनिश्चित करने के लिए परीक्षण करना चाहिए कि पिक्सेल बफर को सफलतापूर्वक आपके कोड में startSessionAtSourceTime को कॉल करने के बाद बनाया गया था। आपके कोड को "अगर (adaptor.pixelBufferPool == nil)" जांचना चाहिए और फिर एन्कोड फ्रेम लूप में जाने से पहले विफलता केस को संभालना चाहिए। – MoDJ

संबंधित मुद्दे