2013-03-06 41 views
6

Tôi có một FFMPEG AVFrame trong YUVJ420P và tôi muốn chuyển đổi nó thành một CVPixelBufferRef với CVPixelBufferCreateWithBytes. Lý do tôi muốn làm điều này là sử dụng AVFoundation để hiển thị/mã hóa các khung hình.Làm thế nào để chuyển đổi một khung hình FFMPEG AVFrame trong YUVJ420P thành AVFoundation cVPixelBufferRef?

tôi chọn kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange và cố gắng chuyển đổi nó kể từ khi AVFrame có dữ liệu trong ba mặt phẳng Y480Cb240Cr240. Và theo những gì tôi đã nghiên cứu này phù hợp với các lựa chọn kCVPixelFormatType. Bởi là biplanar tôi cần phải chuyển đổi nó thành một bộ đệm có chứa Y480CbCr480 xen kẽ.

tôi đã cố gắng để tạo ra một bộ đệm với 2 máy bay:

  • frame->data[0] trên máy bay đầu tiên,
  • frame->data[1]frame->data[2] xen kẽ trên máy bay thứ hai.

Tuy nhiên, tôi nhận được lỗi lại -6661 (invalid a) từ CVPixelBufferCreateWithBytes:

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

Tôi không có chuyên môn về xử lý ảnh nào cả, vì vậy bất kỳ con trỏ đến tài liệu mà có thể làm cho tôi bắt đầu ở bên phải tiếp cận vấn đề này được đánh giá cao. Kỹ năng C của tôi không phải là hàng đầu nên tôi có thể mắc lỗi cơ bản ở đây.

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) 

Khung là AVFrame với rawData từ FFMPEG Giải mã.

+0

Có phải 'cvPixelBufferSample' là CVPixelBufferRef không? Nếu vậy, tham số cuối cùng trong 'CVPixelBufferCreateWithBytes()' sẽ cần phải là '& cvPixelBufferSample' để cho phép con trỏ tới bộ đệm pixel mới được trả về bằng tham chiếu. –

Trả lời

6

Kỹ năng C của tôi không đứng đầu dòng hoặc vì vậy có thể bạn đang mắc lỗi cơ bản ở đây.

Bạn đang làm cho nhiều:

  • Bạn nên sử dụng CVPixelBufferCreateWithPlanarBytes(). Tôi không biết nếu CVPixelBufferCreateWithBytes() có thể được sử dụng để tạo ra một khung video phẳng; nếu vậy, nó sẽ yêu cầu một con trỏ đến một "mô tả máy bay khối" (tôi dường như không thể tìm thấy cấu trúc trong tài liệu).
  • frame->linesize[0]byte mỗi hàng, không phải là kích thước của toàn bộ hình ảnh. Các tài liệu không rõ ràng, nhưng usage là khá rõ ràng.
  • frame->linesize[0] đề cập đến mặt phẳng Y; bạn quan tâm đến các máy bay UV.
  • Địa điểm là sizeof(int) từ đâu?
  • Bạn đang chuyển qua số cvPixelBufferSample; bạn có thể có nghĩa là &cvPixelBufferSample.
  • Bạn hiện không chuyển vùng phát hành. Tài liệu không nói rằng bạn có thể vượt qua NULL.

Hãy thử một cái gì đó như thế này:

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); 

Quản lý bộ nhớ là trái như một bài tập cho người đọc, nhưng đối với mã kiểm tra bạn có thể nhận được ngay với đi qua trong NULL thay vì một callback phát hành.

+0

Hoạt động như một sự quyến rũ! – cahn

Các vấn đề liên quan