Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/147.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/ios/98.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ AVAssetWriter在重新使用时失败,AVAssetWriterStatusFailed_C++_Ios_Objective C - Fatal编程技术网

C++ AVAssetWriter在重新使用时失败,AVAssetWriterStatusFailed

C++ AVAssetWriter在重新使用时失败,AVAssetWriterStatusFailed,c++,ios,objective-c,C++,Ios,Objective C,我正在尝试使用AVAssetWriter对视频进行编码。我正在使用ARC。我尝试做的是通过套接字流式传输视频 现在问题来了。我的设置是第一次使用如果不先重新启动应用程序,我将无法再次使用AVAssetWriter。如果我不重新启动应用程序,当我调用[m_writer startWriting]时,我会收到以下错误: Error Domain=AVFoundationErrorDomain Code=-11800 "The operation could not be completed" Use

我正在尝试使用AVAssetWriter对视频进行编码。我正在使用ARC。我尝试做的是通过套接字流式传输视频

现在问题来了。我的设置是第一次使用如果不先重新启动应用程序,我将无法再次使用AVAssetWriter。如果我不重新启动应用程序,当我调用[m_writer startWriting]时,我会收到以下错误:

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)}
  • 我确保在调用cleaup方法时删除了该文件。 我使用iExplorer导航到文件所在的临时文件夹 正在创建。我还确保了AVAssetWriter的地位 调用finshWriting后,AVAssetWriterStatusFinished
编辑:即使我使用了不同的文件名,错误仍然存在。

我创建了VideoEncoder类的一个实例(下面的代码),然后将原始图像馈送给它。然后,我等待AVAssetWriter使用dispatch_source_set_event_handler()将某些内容写入输出文件,即:

我已经为AVAssetWriter创建了一个名为VideoEncoder的包装器。以下是初始化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];
  }
}
-(void) finishWritingWithCompletionHandler(void (^)(void))handler
{
  [m_writerInput markAsFinished];
  [m_writer finishWithCompletionHandler: ^{
    handler();
  }
}
这是我给它提供原始图像的方式:

-(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 ++;
  }
}
下面是我如何使用包装。我使用这个包装器形成一个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]);
}
解除锁定:

bool CFrameEncoder::StopDecoding()
{
  [(__bridge VideoEncoder*) m_impl terminate];
  CFRelease(m_impl);
}
(视频编码器类的)终止函数:


AVAssetWriter类只能有有限数量的实例。如果您的应用程序超过此限制,则当您尝试开始编写时,AVAssetWriter开始失败,AVAssetWriterStatusFailed

这意味着我的代码中有某种东西阻止释放AVAssetWriter。有人知道在哪里吗

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];
}