iphone - Codificación de video usando AVAssetWriter-CRASHES
objective-c ipad (1)
-copyNextSampleBuffer devuelve un CMSampleBufferRef con +1 retener (los métodos de copia lo hacen). Esto significa que debe liberar el objeto. Como no lo está haciendo, tendrá que filtrar una copia de cada pasada a través de su ciclo while ().
Además, está ejecutando ese bucle estrechamente sin administrar un grupo de autorrelease. Si hay objetos que se lanzan de forma automática en cualquiera de las rutinas a las que llamas, no se liberarán hasta que el grupo de autorrelease que está sobre ti se agote. Como la duración del ciclo while () se basa en la entrada, es un buen candidato para agregar un grupo de autorrelease manual.
Otra cosa a considerar: como está ejecutando esto sincrónicamente con un ciclo while (), bloqueará el hilo y posiblemente girará innecesariamente sobre su condición de continuar varias veces. AVAssetWriterInput proporciona un mecanismo alternativo para usar libdispatch para procesar datos de manera asincrónica a medida que los recursos estén disponibles: -requestMediaDataWhenReadyOnQueue: usingBlock:
Tengo una función que se supone que vuelve a codificar un video a una tasa de bits manejable en iphone / ipad. Aquí está: * CÓDIGO DE TRABAJO ACTUALIZADO, ¡AHORA CON AUDIO! :) *
-(void)resizeVideo:(NSString*)pathy{
NSString *newName = [pathy stringByAppendingString:@".down.mov"];
NSURL *fullPath = [NSURL fileURLWithPath:newName];
NSURL *path = [NSURL fileURLWithPath:pathy];
NSLog(@"Write Started");
NSError *error = nil;
AVAssetWriter *videoWriter = [[AVAssetWriter alloc] initWithURL:fullPath fileType:AVFileTypeQuickTimeMovie error:&error];
NSParameterAssert(videoWriter);
AVAsset *avAsset = [[[AVURLAsset alloc] initWithURL:path options:nil] autorelease];
NSDictionary *videoSettings = [NSDictionary dictionaryWithObjectsAndKeys:
AVVideoCodecH264, AVVideoCodecKey,
[NSNumber numberWithInt:1280], AVVideoWidthKey,
[NSNumber numberWithInt:720], AVVideoHeightKey,
nil];
AVAssetWriterInput* videoWriterInput = [[AVAssetWriterInput
assetWriterInputWithMediaType:AVMediaTypeVideo
outputSettings:videoSettings] retain];
NSParameterAssert(videoWriterInput);
NSParameterAssert([videoWriter canAddInput:videoWriterInput]);
videoWriterInput.expectsMediaDataInRealTime = YES;
[videoWriter addInput:videoWriterInput];
NSError *aerror = nil;
AVAssetReader *reader = [[AVAssetReader alloc] initWithAsset:avAsset error:&aerror];
AVAssetTrack *videoTrack = [[avAsset tracksWithMediaType:AVMediaTypeVideo]objectAtIndex:0];
videoWriterInput.transform = videoTrack.preferredTransform;
NSDictionary *videoOptions = [NSDictionary dictionaryWithObject:[NSNumber numberWithInt:kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange] forKey:(id)kCVPixelBufferPixelFormatTypeKey];
AVAssetReaderTrackOutput *asset_reader_output = [[AVAssetReaderTrackOutput alloc] initWithTrack:videoTrack outputSettings:videoOptions];
[reader addOutput:asset_reader_output];
//audio setup
AVAssetWriterInput* audioWriterInput = [[AVAssetWriterInput
assetWriterInputWithMediaType:AVMediaTypeAudio
outputSettings:nil] retain];
AVAssetReader *audioReader = [[AVAssetReader assetReaderWithAsset:avAsset error:&error] retain];
AVAssetTrack* audioTrack = [[avAsset tracksWithMediaType:AVMediaTypeAudio] objectAtIndex:0];
AVAssetReaderOutput *readerOutput = [AVAssetReaderTrackOutput assetReaderTrackOutputWithTrack:audioTrack outputSettings:nil];
[audioReader addOutput:readerOutput];
NSParameterAssert(audioWriterInput);
NSParameterAssert([videoWriter canAddInput:audioWriterInput]);
audioWriterInput.expectsMediaDataInRealTime = NO;
[videoWriter addInput:audioWriterInput];
[videoWriter startWriting];
[videoWriter startSessionAtSourceTime:kCMTimeZero];
[reader startReading];
dispatch_queue_t _processingQueue = dispatch_queue_create("assetAudioWriterQueue", NULL);
[videoWriterInput requestMediaDataWhenReadyOnQueue:_processingQueue usingBlock:
^{
[self retain];
while ([videoWriterInput isReadyForMoreMediaData]) {
CMSampleBufferRef sampleBuffer;
if ([reader status] == AVAssetReaderStatusReading &&
(sampleBuffer = [asset_reader_output copyNextSampleBuffer])) {
BOOL result = [videoWriterInput appendSampleBuffer:sampleBuffer];
CFRelease(sampleBuffer);
if (!result) {
[reader cancelReading];
break;
}
} else {
[videoWriterInput markAsFinished];
switch ([reader status]) {
case AVAssetReaderStatusReading:
// the reader has more for other tracks, even if this one is done
break;
case AVAssetReaderStatusCompleted:
// your method for when the conversion is done
// should call finishWriting on the writer
//hook up audio track
[audioReader startReading];
[videoWriter startSessionAtSourceTime:kCMTimeZero];
dispatch_queue_t mediaInputQueue = dispatch_queue_create("mediaInputQueue", NULL);
[audioWriterInput requestMediaDataWhenReadyOnQueue:mediaInputQueue usingBlock:^
{
NSLog(@"Request");
NSLog(@"Asset Writer ready :%d",audioWriterInput.readyForMoreMediaData);
while (audioWriterInput.readyForMoreMediaData) {
CMSampleBufferRef nextBuffer;
if ([audioReader status] == AVAssetReaderStatusReading &&
(nextBuffer = [readerOutput copyNextSampleBuffer])) {
NSLog(@"Ready");
if (nextBuffer) {
NSLog(@"NextBuffer");
[audioWriterInput appendSampleBuffer:nextBuffer];
}
}else{
[audioWriterInput markAsFinished];
switch ([audioReader status]) {
case AVAssetReaderStatusCompleted:
[videoWriter finishWriting];
[self hookUpVideo:newName];
break;
}
}
}
}
];
break;
case AVAssetReaderStatusFailed:
[videoWriter cancelWriting];
break;
}
break;
}
}
}
];
NSLog(@"Write Ended");
}
Desafortunadamente, si paso un video por más de 2 segundos, ¡la aplicación absorbe la memoria como loca y se cuelga! El código parece bastante simple, ¡pero parece que no puedo hacerlo funcionar!
¿Se supone que debo liberar el búfer allí después de haberlo escrito? Estaría muy agradecido a cualquiera que tenga alguna aportación.