2011-01-28 15 views
5

Tôi cần lấy CMSampleBuffer cho khung OpenGL. Tôi đang sử dụng điều này:CMSampleBuffer từ OpenGL cho đầu ra video với AVAssestWritter

int s = 1; 
     UIScreen * screen = [UIScreen mainScreen]; 
     if ([screen respondsToSelector:@selector(scale)]){ 
      s = (int)[screen scale]; 
     } 
     const int w = viewController.view.frame.size.width/2; 
     const int h = viewController.view.frame.size.height/2; 
     const NSInteger my_data_length = 4*w*h*s*s; 
     // allocate array and read pixels into it. 
     GLubyte * buffer = malloc(my_data_length); 
     glReadPixels(0, 0, w*s, h*s, GL_RGBA, GL_UNSIGNED_BYTE, buffer); 
     // gl renders "upside down" so swap top to bottom into new array. 
     GLubyte * buffer2 = malloc(my_data_length); 
     for(int y = 0; y < h*s; y++){ 
      memcpy(buffer2 + (h*s - 1 - y)*4*w*s, buffer + (4*y*w*s), 4*w*s); 
     } 
     free(buffer); 
     CMBlockBufferRef * cm_block_buffer_ref; 
     CMBlockBufferAccessDataBytes(cm_block_buffer_ref,0,my_data_length,buffer2,*buffer2); 
     CMSampleBufferRef * cm_buffer; 
     CMSampleBufferCreate (kCFAllocatorDefault,cm_block_buffer_ref,true,NULL,NULL,NULL,1,1,NULL,0,NULL,cm_buffer); 

Tôi nhận được EXEC_BAD_ACCESS cho CMSampleBufferTạo.

Bất kỳ trợ giúp nào được đánh giá cao, cảm ơn bạn.

Trả lời

6

Giải pháp là sử dụng lớp AVAssetWriterInputPixelBufferAdaptor.

int s = 1; 
     UIScreen * screen = [UIScreen mainScreen]; 
     if ([screen respondsToSelector:@selector(scale)]){ 
      s = (int)[screen scale]; 
     } 
     const int w = viewController.view.frame.size.width/2; 
     const int h = viewController.view.frame.size.height/2; 
     const NSInteger my_data_length = 4*w*h*s*s; 
     // allocate array and read pixels into it. 
     GLubyte * buffer = malloc(my_data_length); 
     glReadPixels(0, 0, w*s, h*s, GL_RGBA, GL_UNSIGNED_BYTE, buffer); 
     // gl renders "upside down" so swap top to bottom into new array. 
     GLubyte * buffer2 = malloc(my_data_length); 
     for(int y = 0; y < h*s; y++){ 
      memcpy(buffer2 + (h*s - 1 - y)*4*w*s, buffer + (4*y*w*s), 4*w*s); 
     } 
     free(buffer); 
     CVPixelBufferRef pixel_buffer = NULL; 
     CVPixelBufferCreateWithBytes (NULL,w*2,h*2,kCVPixelFormatType_32BGRA,buffer2,4*w*s,NULL,0,NULL,&pixel_buffer); 
     [av_adaptor appendPixelBuffer: pixel_buffer withPresentationTime:CMTimeMakeWithSeconds([[NSDate date] timeIntervalSinceDate: start_time],30)]; 
1

Tại sao tham số thứ ba là CMSampleBufferCreate() đúng trong mã của bạn? Theo documentation:

thông số

cấp phát

Các cấp phát sử dụng để cấp phát bộ nhớ cho đối tượng CMSampleBuffer . Chuyển kCFAllocatorDefault sang sử dụng trình phân bổ mặc định hiện tại.

dataBuffer

Đây có thể là NULL, một CMBlockBuffer không có bộ nhớ sự ủng hộ, một CMBlockBuffer với bộ nhớ ủng hộ nhưng không có dữ liệu nào, hoặc một CMBlockBuffer rằng đã có chứa dữ liệu truyền thông. Chỉ trong trường hợp cuối cùng (hoặc nếu NULL và numSamples là 0) nên dataReady là đúng.

dataReady

Cho biết dataBuffer đã có chứa các phương tiện truyền thông dữ liệu.

bạn cm_block_buffer_ref đang được thông qua tại như một bộ đệm chứa dữ liệu (bạn nên NULL nó cho an toàn, tôi không tin rằng trình biên dịch nào đó theo mặc định), vì vậy bạn nên sử dụng false đây.

Có thể có những điều khác sai với điều này, nhưng đó là mục đầu tiên nhảy ra ngoài với tôi.

+0

Cảm ơn bạn. Làm thế nào để có được cm_block_buffer_ref để chứa dữ liệu OpenGL? –

+0

@Matthew - Nhìn vào nó, tôi nghĩ bạn sẽ cần tạo một tệp CVPixelBuffer, sau đó sử dụng 'CMSampleBufferCreateForImageBuffer()' thay vì 'CMSampleBufferCreate()'. Trong thực tế, có lẽ bạn nên sử dụng AVAssetWriterInputPixelBufferAdaptor: http://developer.apple.com/library/ios/#documentation/AVFoundation/Reference/AVAssetWriterInputPixelBufferAdaptor_Class/Reference/Reference.html –

+0

Ồ vâng, tôi đã thêm một câu trả lời của riêng tôi. Tôi đã quản lý để làm cho nó hoạt động (Một chút chậm nhưng sau đó glReadPixels được cho là). Nhưng cảm ơn bạn. –

0

Tại sao đôi malloc và tại sao không trao đổi tại chỗ thông qua bộ đệm tạm thời?

Something như thế này:

GLubyte * raw = (GLubyte *) wyMalloc(size); 
    LOGD("raw address %p", raw); 
    glReadPixels(x, y, w, h, GL_RGBA, GL_UNSIGNED_BYTE, raw); 
    const size_t end = h/2; 
    const size_t W = 4*w; 
    GLubyte row[4*w]; 
    for (int i=0; i <= end; i++) { 
     void * top = raw + (h - i - 1)*W; 
     void * bottom = raw + i*W; 
     memcpy(row, top, W); 
     memcpy(top, bottom, W); 
     memcpy(bottom, row, W); 
    } 
+0

Tôi thậm chí không malloc nguyên gốc đệm nữa mà thay vào đó tái chế nó.Tôi tạo ra một lớp bộ đệm. Tôi làm những việc hơi khác một chút đối với các vòng lặp ngắn của tôi. Tôi lưu từng hình ảnh vào bộ nhớ, sau đó đọc lại chúng theo thứ tự sau này. – user1524957