2016-12-19 12 views
3

AVAssetWriterを使用してビデオをエンコードしようとしています。私はARCを使用しています。私がしようとしているのは、ソケットを介してストリームビデオです。AVAssetWriterは、再利用時にAVAssetWriterStatusFailedで失敗します。

ここで問題はです。私が行ったセットアップは初めてです。 AVAssetWriterをもう一度使用することはできません。最初にアプリケーションを再起動する必要はありません。私は自分のアプリケーションを再起動しない場合は、私が呼ぶとき、[m_writer startWriting]私は、次のエラーが表示されます。

私はcleaupメソッドが呼び出されたときに、ファイルが削除されたことを確認しました
Error Domain=AVFoundationErrorDomain Code=-11800 "The operation could not be completed" UserInfo={NSLocalizedDescription=The operation could not be completed, NSUnderlyingError=0x14d06fe0 {Error Domain=NSOSStatusErrorDomain Code=-12983 "(null)"}, NSLocalizedFailureReason=An unknown error occurred (-12983)} 
  • 。 ファイルが であるtempフォルダにiExplorerを使って移動しました。また、finshWritingを呼び出した後のAVAssetWriter のステータスがAVAssetWriterStatusFinishedであることを確認しました。

編集:別のファイル名を使用してもエラーが発生します。

私はVideoEncoderクラス(以下のコード)のインスタンスを作成し、それから生のイメージを送ります。それから私はAVAssetWriterは、ビデオエンコーダと呼ばれるために、私はラッパーを作成したdispatch_source_set_event_handler()を使用してAVAssetWriter、すなわち:

m_inputFile = [NSFileHandle fileHandleForReadingAtPath: m_writer.path]; 
m_readSource = dispatch_source_create(DISPATCH_SOURCE_TYPE_READ, [m_inputFile fileDescriptor], 0, m_readQueue); 
dispatch_source_set_event_handler(m_readSource, ^{ 
    // Read bytes from file and send over socket 
} 
dispatch_source_set_cancel_handler(m_readSource, ^{ 
    [self cleanup]; 
} 
dispatch_resume(m_readSource); 

によって出力ファイルに書き込まれるように、何かを待ちます。ここで私はAVAssetWriterを初期化する方法である:

@implementation VideoEncoder : NSObject 
{ 
    AVAssetWriter* m_writer; 
    AVAssetWriterInput* m_writerInput; 
    AVAssetWriterInputPixelBufferAdaptor* m_pixelBufferAdaptor; 
} 
-(id) initWithPath:(NSString*)path width:(int)width height:(int)height parameters:(NSDictionary*) parameters 
{ 
    if (self = [super init]) 
    { 
    self.path = path; 
    [[NSFileManager defaultManager] removeItemAtPath:self.path error:nil]; 
    NSURL* url = [NSURL fileURLWithPath: self.path]; 

    m_writer = [[AVAssetWriter alloc] initWithURL:url fileType:AVFileTypeQuickTimeMovie error: nil]; 

    NSDictionary* settings = [NSDictionary dictionaryWithObjectsAndKeys: 
          AVVideoCodecH264, AVVideoCodecKey, 
          [NSNumber numberWithInt: width], AVVideoWidthKey, 
          [NSNumber numberWithInt:height], AVVideoHeightKey, 
          parameters,      AVVideoCompressionPropertiesKey, 
          nil]; 
    m_writerInput = [AVAssetWriterInput assetWriterInputWithMediaType:AVMediaTypeVideo outputSettings:settings]; 
    m_writerInput.expectsMediaDataInRealTime = YES; 

    [m_writer addInput:m_writerInput]; 

    NSDictionary* pixelBufferOptions = [[NSDictionary alloc] initWithObjectsAndKeys: 
             [NSNumber numberWithInt: kCVPixelFormatType_32BGRA], kCVPixelBufferPixelFormatTypeKey, 
             [NSNumber numberWithInt: width*4],     kCVPixelBufferBytesPerRowAllignmentKey, 
             [NSNumber numberWithInt; width],      kCVPixelBufferWidthKey, 
             [NSNumber numberWithInt; height],      kCVPixelBufferHeightKey, 
             nil]; 

    m_pixelBufferAdaptor = [[AVAssetWriterInputPixelBufferAdaptor alloc] 
          initWithAssetWriterInput: m_writerInput 
          sourcePixelBufferAttributes: pixelBufferOptions]; 

    [m_writer startWriting]; 
    [m_writer startSessionAtSourceTime: kCMTimeZero]; 
    } 
} 

これは私が生のイメージ、それを養う方法です:

-(BOOL) encodeFrame:(CVPixelBufferRead)pixelBuffer time(CMTime)time; 
{ 
    if (m_writer.status == AVAssetWriterStatusFailed) 
    { 
    return NO; 
    } 
    if (m_writerInput.readyForMoreMediaData == YES) 
    { 
    if ([m_pixelBufferAdaptor appendPixelBuffer:pixelBuffer withPresentationTime:time]) 
    { 
     return YES: 
    } 
    } 
    return NO; 
} 

これは、ピクセルバッファが生成される方法です。

-(bool) encodeImage:(const char*) frameBuffer width:(int)width height:(int)height 
{ 
    CVPixelBufferRef pixelBuffer = NULL; 
    CVReturn ret; 

    ret = CVPixelBufferCraeteWithBytes( 
      kCFAllocatorDefault, 
      with, 
      height, 
      kCVPixelFormatType_32BGRA, 
      (void*) frameBuffer, 
      width * 4, 
      NULL, NULL, NULL, NULL, &pixelBuffer); 
    if (ret == kCVReturnSuccess && pixelBuffer) 
    { 
    CFTimeInterval currTime = CACurrentMediaTime(); 
    if (m_frameIndex > 0) 
    { 
     int ticks = (int)((currTime - m_prevTime) * 1000)/30; 
     CMTime addTime; 

     ticks = ticks <= 0 ? 1 : ticks; 
     addTime = CMTimeMake(ticks, 30); 
     m_timestamp = CMTimeAdd(m_timestamp, addTime); 
    } 
    m_prevTime = currTime; 
    [m_impl encodeFrame: pixelBuffer time: m_timestamp]; 

    CVBufferRelease(pixelBuffer); 
    m_frameIndex ++; 
    } 
} 

これはどのようにあります私はAVAssetWriterを終了します:

-(void) finishWritingWithCompletionHandler(void (^)(void))handler 
{ 
    [m_writerInput markAsFinished]; 
    [m_writer finishWithCompletionHandler: ^{ 
    handler(); 
    } 
} 

そして、ここで私はラッパーをどのように使用しています。このラッパーフォームをC++クラスとして使用します。インスタンス化:

-(void) makeFilename 
{ 
    NSString* filename = [NSString* stringWithFormat: @"temp%d.tmp", 1]; 
    NSString* path = [NSTemporaryDirectory() stringByAppendingPathComponent: filename]; 
    return path; 
} 

bool CFrameEncoder::StartEncoding() 
{ 
    m_impl = CFRetain((__bridge*void)[[VideoEncoder alloc] initWithPath:[self makeFilepath] width:800 height:480 parameters: params]); 
} 

DEALLOC:

bool CFrameEncoder::StopDecoding() 
{ 
    [(__bridge VideoEncoder*) m_impl terminate]; 
    CFRelease(m_impl); 
} 

(ビデオエンコーダクラスの)停止機能:

-(void) terminate 
{ 
    if (m_readSource) 
    { 
    dispatch_source_cancel(m_readSource); 
    } 
} 
// The dispatch source cancel handler 
-(void) cleanup 
{ 
    m_readQueue = nil; 
    m_readSource = nil; 

    [m_inputFile closeFile]; 

    NSString* path = m_writer.path; 
    dispatch_semaphore_t semaphore = dispatch_semaphore_create(0); 

    [m_writer finishWithCompletionHandler:^{ 
    dispatch_semaphore_signal(semaphore); 
    }]; 

    dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER); 
    m_writer = nil; 
    [[NSFileManager defaultManager] removeItemAtPath: path error: nil]; 
} 

答えて

1

AVAssetWriterクラスは、インスタンスの限られた数を有することができます。アプリケーションがこの制限を超えた場合、startWritingを試みるときにAVAssetWriterがAVAssetWriterStatusFailedで失敗し始めます。

これは、コード内にAVAssetWriterの割り当てが解除されないようにする何かがあることを意味します。誰がどこを知っていますか?

関連する問題