2013-03-26 7 views
7

AVAssetWriterInput에 대한 iOS 설명서에서 niloutputSettings 사전에 전달하여 입력 데이터를 다시 인코딩하지 않도록 지정할 수 있습니다.원시 NAL 단위 AVAssetWriter 사용

출력에 미디어 인코딩에 사용되는 설정이 추가됩니다. 추가 된 샘플을 다시 인코딩하지 않도록 지정하려면 nil을 전달하십시오.

나는 원시 H.264의 NAL들의 스트림을 전달하기 위해이 기능을 이용하려면,하지만 난 AVAssetWriterInput의 appendSampleBuffer 방법으로 전달할 수있는 데 문제가 CMSampleBuffer로 내 원시 바이트 스트림을 적응하는 데 문제. 내 NAL 스트림에는 SPS/PPS/IDR/P NAL (1, 5, 7, 8) 만 포함됩니다. AVAssetWriter에서 미리 인코딩 된 H264 데이터를 사용하는 방법에 대한 설명서 또는 결정적인 대답을 찾을 수 없었습니다. 결과 비디오 파일을 재생할 수 없습니다.

NAL 단위를 올바르게 CMSampleBuffers에 포장 할 수 있습니까? 시작 코드 접두사를 사용해야합니까? 길이 접두어? CMSampleBuffer 당 하나의 NAL 만 넣어야하는지 확인해야합니까? 나의 마지막 목표는 H264/AAC로 MP4 또는 MOV 컨테이너를 만드는 것입니다. 나는 내가 실제로 해요 전에 유효한 시간 생각으로 writeSampleBuffer 방법의 내부 샘플 버퍼에 CMSampleBufferSetOutputPresentationTimeStamp를 호출하고있어

-(void)addH264NAL:(NSData *)nal 
{ 
    dispatch_async(recordingQueue, ^{ 
     //Adapting the raw NAL into a CMSampleBuffer 
     CMSampleBufferRef sampleBuffer = NULL; 
     CMBlockBufferRef blockBuffer = NULL; 
     CMFormatDescriptionRef formatDescription = NULL; 
     CMItemCount numberOfSampleTimeEntries = 1; 
     CMItemCount numberOfSamples = 1; 


     CMVideoFormatDescriptionCreate(kCFAllocatorDefault, kCMVideoCodecType_H264, 480, 360, nil, &formatDescription); 
     OSStatus result = CMBlockBufferCreateWithMemoryBlock(kCFAllocatorDefault, NULL, [nal length], kCFAllocatorDefault, NULL, 0, [nal length], kCMBlockBufferAssureMemoryNowFlag, &blockBuffer); 
     if(result != noErr) 
     { 
      NSLog(@"Error creating CMBlockBuffer"); 
      return; 
     } 
     result = CMBlockBufferReplaceDataBytes([nal bytes], blockBuffer, 0, [nal length]); 
     if(result != noErr) 
     { 
      NSLog(@"Error filling CMBlockBuffer"); 
      return; 
     } 
     const size_t sampleSizes = [nal length]; 
     CMSampleTimingInfo timing = { 0 }; 
     result = CMSampleBufferCreate(kCFAllocatorDefault, blockBuffer, YES, NULL, NULL, formatDescription, numberOfSamples, numberOfSampleTimeEntries, &timing, 1, &sampleSizes, &sampleBuffer); 

     if(result != noErr) 
     { 
      NSLog(@"Error creating CMSampleBuffer"); 
     } 
     [self writeSampleBuffer:sampleBuffer ofType:AVMediaTypeVideo]; 
    }); 
} 

참고 : 여기에

내가 함께 놀았 던 코드입니다 그것을 추가하려고합니다.

도움을 주시면 감사하겠습니다.

+0

적어도 내 문제 중 일부는 CMSampleTimingInfo를 처리하는 방법이었습니다.나는 실제 타임 스탬프를 채우기 위해'setOutputPresentationTimeStamp'를 사용하고 있다고 언급했다. 이제 CMSampleTimingInfo의 다른 필드를 채워야한다는 것을 알았습니다. 나는'decodeTimeStamp'을'kCMTimeInvalid'로,'duration'을'CMTimeMake (1, 30)'로 설정하고 있습니다. 적절한 총 시간을 가진 검색 가능한 비디오 컨테이너를 얻었지만 비디오가 없습니다 (VLC에서 테스트). – bsirang

답변

3

VLC에서는 비디오 재생이 가능하지만 QuickTime에서는 작동하지 않습니다. CMSampleBuffers에 H.264 NAL을 얻기 위해 위에서 게시 한 코드와 비슷한 코드를 사용했습니다.

나는 두 가지 문제가 있었다 : 내가 제대로 CMSampleTimingInfo 설정되지 않은

  1. (상태 이상 내 댓글 등).
  2. 원시 NAL 데이터를 올바르게 포장하지 않았습니다 (어디서나 문서화 된 위치가 확실하지 않음).

# 1을 해결하려면 timing.duration = CMTimeMake(1, fps);으로 설정하십시오. 여기서 fps는 예상 프레임 속도입니다. 그런 다음 timing.decodeTimeStamp = kCMTimeInvalid;을 설정하면 샘플이 디코딩 순서로 제공됩니다. 마지막으로 startSessionAtSourceTime과 함께 사용하는 절대 시간을 계산하여 timing.presentationTimeStamp을 설정합니다.

시행 착오를 통해, # 2를 해결하기 위해 나는 다음과 같은 형태로 내 NAL 단위를 제공하는 일을 발견 : 각 NAL 유닛은 32 비트 시작 코드가 0x00000001를 같게하는 접두어입니다

[7 8 5] [1] [1] [1]..... [7 8 5] [1] [1] [1]..... (repeating) 

.

아마도 QuickTime에서 재생되지 않는 것과 같은 이유로 결과 .mov 파일을 사진 앨범으로 옮기는 데 문제가 있습니다. ALAssetLibrary 방법 videoAtPathIsCompatibleWithSavedPhotosAlbum은 "영화를 재생할 수 없습니다."라는 메시지가 표시되지 않습니다. 잘하면 어떤 일이 벌어지고 있는지에 대한 아이디어가있는 사람은 의견을 말할 수 있습니다. 감사합니다.

+0

이것은 VLC에서만 작동한다는 점을 감안할 때, QuickTime이 작동하려면 NAL을 버퍼에 저장하는 방식을 변경해야 할 가능성이 있습니다. 누구든지 아이디어가 있습니까? – bsirang

+0

나는 결과 mov 파일의 hexdump를 가져 왔고 맨 아래쪽에 몇 개의 avc1 원자뿐만 아니라 하나의 mdat 원자뿐만 아니라 avcC 원자도없는 것처럼 보입니다. mdat 아톰 내부에는이 대답에서 설명하는 NAL 스트림 (0x00000001 접두어로 구분)이 있습니다. mdat 아래의 데이터가 Annex-B 형식이고 avcC 아톰이 없으므로 QuickTime에서 파일 재생을 거부한다고 가정합니다. 데이터를 AVAssetWriterInput에 제대로 공급하는 방법을 알아야합니다. – bsirang

+0

나는 모든 것을 작동시킬 수 있었다. 나는 각 NAL (0x00000001 대신)에 NAL 길이를 선행하고 mov 컨테이너에 avcC 데이터를 제대로 전달할 수있었습니다. 내 질문 및 답변보기 : http://stackoverflow.com/questions/15673379/avassetwriterinput-h-264-passthrough-to-quicktime-mov-passing-in-sps-pps-to/ – bsirang