2013-03-06 1 views
6

나는 YUVJ420P에 FFMPEG AVFrame을 가지고 있는데 CVPixelBufferRef으로 바꾸고 싶습니다. CVPixelBufferCreateWithBytes으로 바꾸고 싶습니다. 그 이유는 AVFoundation을 사용하여 프레임을 표시/인코딩하는 것입니다. YUVJ420P의 FFMPEG AVFrame을 AVFoundation cVPixelBufferRef로 변환하는 방법은 무엇입니까?

kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange 선택하고 AVFrame 세 평면 Y480 Cb240 Cr240의 데이터를 갖고 있기 때문에이를 변환 시도. 그리고 제가 조사한 바에 따르면이 선택은 kCVPixelFormatType과 일치합니다. biplanar 됨으로써 나는 그것을 Y480CbCr480 Interleaved를 포함하는 버퍼로 변환해야합니다.

는 I 2 개면과 버퍼를 만들려고 : 제 비행기

  • frame->data[0],
  • frame->data[1]frame->data[2] 및 인터리빙을 제 2 평면 상. 나에게 맞는에서 시작할 수 있습니다 문서에 대한 포인터

    "Invalid function parameter. For example, out of range or the wrong type." 
    

    내가 모든 이미지 처리에 대한 전문 지식이없는, 그래서 :

그러나, 나는 CVPixelBufferCreateWithBytes에서 반환 오류 -6661 (invalid a) 받고 있어요 이 문제에 대한 접근 방식이 인정됩니다. 내 C 스킬이 라인의 상단도 아니므로 아마도 여기에서 기본적인 실수를 저지르고있을 것입니다.

uint8_t **buffer = malloc(2*sizeof(int *)); 
    buffer[0] = frame->data[0]; 
    buffer[1] = malloc(frame->linesize[0]*sizeof(int)); 
    for(int i = 0; i<frame->linesize[0]; i++){ 
     if(i%2){ 
      buffer[1][i]=frame->data[1][i/2]; 
     }else{ 
      buffer[1][i]=frame->data[2][i/2]; 
     } 
    } 

    int ret = CVPixelBufferCreateWithBytes(NULL, frame->width, frame->height, kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange, buffer, frame->linesize[0], NULL, 0, NULL, cvPixelBufferSample) 

프레임은 원시 데이터 FFMPEG 디코딩에서 AVFrame입니다.

+0

'cvPixelBufferSample'은 CVPixelBufferRef입니까? 그렇다면'CVPixelBufferCreateWithBytes()'의 마지막 매개 변수는 대신 새로운 픽셀 버퍼에 대한 포인터가 참조에 의해 리턴 될 수 있도록'& cvPixelBufferSample'이 될 필요가 있습니다. –

답변

6

My C 스킬이 라인의 맨 위에 있지 않으므로 여기에서 기본적인 실수를 저 지르려고합니다.

당신은 몇 가지 만들고있어 : 당신은 CVPixelBufferCreateWithPlanarBytes()를 사용한다

  • . 평면 비디오 프레임을 만드는 데 CVPixelBufferCreateWithBytes()을 사용할 수 있는지 여부는 알 수 없습니다. 그렇다면 "평면 기술자 블록"에 대한 포인터가 필요합니다 (문서에서 구조체를 찾을 수없는 것 같습니다).
  • frame->linesize[0]은 전체 이미지의 크기가 아닌 행당 바이트입니다. 문서는 명확하지 않지만 usage은 매우 모호합니다.
  • frame->linesize[0]은 Y 평면을 나타내고; 당신은 UV 비행기에 관심이 있습니다.
  • sizeof(int) 어디에서 왔습니까?
  • cvPixelBufferSample; &cvPixelBufferSample을 의미 할 수 있습니다.
  • 릴리스 콜백을 전달하지 않습니다. 문서에 NULL을 전달할 수 있다고 명시되어 있지 않습니다.이 같은

시도 뭔가가 :

size_t srcPlaneSize = frame->linesize[1]*frame->height; 
size_t dstPlaneSize = srcPlaneSize *2; 
uint8_t *dstPlane = malloc(dstPlaneSize); 
void *planeBaseAddress[2] = { frame->data[0], dstPlane }; 

// This loop is very naive and assumes that the line sizes are the same. 
// It also copies padding bytes. 
assert(frame->linesize[1] == frame->linesize[2]); 
for(size_t i = 0; i<srcPlaneSize; i++){ 
    // These might be the wrong way round. 
    dstPlane[2*i ]=frame->data[2][i]; 
    dstPlane[2*i+1]=frame->data[1][i]; 
} 

// This assumes the width and height are even (it's 420 after all). 
assert(!frame->width%2 && !frame->height%2); 
size_t planeWidth[2] = {frame->width, frame->width/2}; 
size_t planeHeight[2] = {frame->height, frame->height/2}; 
// I'm not sure where you'd get this. 
size_t planeBytesPerRow[2] = {frame->linesize[0], frame->linesize[1]*2}; 
int ret = CVPixelBufferCreateWithPlanarBytes(
     NULL, 
     frame->width, 
     frame->height, 
     kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange, 
     NULL, 
     0, 
     2, 
     planeBaseAddress, 
     planeWidth, 
     planeHeight, 
     planeBytesPerRow, 
     YOUR_RELEASE_CALLBACK, 
     YOUR_RELEASE_CALLBACK_CONTEXT, 
     NULL, 
     &cvPixelBufferSample); 

메모리 관리는 독자에게 연습으로 남아 있지만, 테스트 코드에 대한 당신은 릴리스 콜백 대신 NULL 전달 멀리 얻을 수 있습니다.

+0

매력처럼 작동합니다! – cahn