2012-07-30 6 views
4

CameraRipple 효과를 가진 Apple의 샘플 코드를 알고 계십니까? OpenGL이 물의 시원한 효과를 모두 얻은 후에 카메라 출력을 파일에 기록하려고합니다.OpenGL ES에서 iOS 비디오 (텍스처 캐시가있는 텍스처로 렌더링)

void * 버퍼의 모든 픽셀을 읽고, CVPixelBufferRef를 만들고 AVAssetWriterInputPixelBufferAdaptor에 추가하는 glReadPixels를 사용하여 작업을 수행했지만 너무 느리다. coz readPixels는 시간이 오래 걸린다. FBO와 텍스쳐 캐쉬를 사용하면 똑같이 할 수 있지만 빠릅니다.

CVReturn err = CVOpenGLESTextureCacheCreate(kCFAllocatorDefault, NULL, (__bridge void *)_context, NULL, &coreVideoTextureCashe); 
if (err) 
{ 
    NSAssert(NO, @"Error at CVOpenGLESTextureCacheCreate %d"); 
} 


CFDictionaryRef empty; // empty value for attr value. 
CFMutableDictionaryRef attrs2; 
empty = CFDictionaryCreate(kCFAllocatorDefault, // our empty IOSurface properties dictionary 
          NULL, 
          NULL, 
          0, 
          &kCFTypeDictionaryKeyCallBacks, 
          &kCFTypeDictionaryValueCallBacks); 
attrs2 = CFDictionaryCreateMutable(kCFAllocatorDefault, 
            1, 
            &kCFTypeDictionaryKeyCallBacks, 
            &kCFTypeDictionaryValueCallBacks); 

CFDictionarySetValue(attrs2, 
        kCVPixelBufferIOSurfacePropertiesKey, 
        empty); 

//CVPixelBufferPoolCreatePixelBuffer (NULL, [assetWriterPixelBufferInput pixelBufferPool], &renderTarget); 
CVPixelBufferRef pixiel_bufer4e = NULL; 

CVPixelBufferCreate(kCFAllocatorDefault, 
        (int)_screenWidth, 
        (int)_screenHeight, 
        kCVPixelFormatType_32BGRA, 
        attrs2, 
        &pixiel_bufer4e); 
CVOpenGLESTextureRef renderTexture; 
CVOpenGLESTextureCacheCreateTextureFromImage (kCFAllocatorDefault, 
               coreVideoTextureCashe, pixiel_bufer4e, 
               NULL, // texture attributes 
               GL_TEXTURE_2D, 
               GL_RGBA, // opengl format 
               (int)_screenWidth, 
               (int)_screenHeight, 
               GL_BGRA, // native iOS format 
               GL_UNSIGNED_BYTE, 
               0, 
               &renderTexture); 
CFRelease(attrs2); 
CFRelease(empty); 
glBindTexture(CVOpenGLESTextureGetTarget(renderTexture), CVOpenGLESTextureGetName(renderTexture)); 
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); 
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); 

glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, CVOpenGLESTextureGetName(renderTexture), 0); 

CVPixelBufferLockBaseAddress(pixiel_bufer4e, 0); 

if([pixelAdapter appendPixelBuffer:pixiel_bufer4e withPresentationTime:currentTime]) { 
       float result = currentTime.value; 
      NSLog(@"\n\n\4eta danni i current time e : %f \n\n",result); 
       currentTime = CMTimeAdd(currentTime, frameLength); 
     } 

CVPixelBufferUnlockBaseAddress(pixiel_bufer4e, 0); 
CVPixelBufferRelease(pixiel_bufer4e); 
CFRelease(renderTexture); 
CFRelease(coreVideoTextureCashe); 

그것은 비디오를 기록하고 꽤 빠르다, 아직 비디오 내가 textureCasheRef가 올바른 아니라고 생각이나 내가 잘못을 작성하고 단지 검은 색 : 여기에 애플이 사용 drawInRect 방법에 내 코드입니다.

업데이트로, 내가 시도한 또 다른 방법입니다. 나는 뭔가를 놓치고 있어야합니다. 나는 OpenGL을 컨텍스트를 설정 한 후 viewDidLoad에, 나는이 수행

drawInRect에서 다음
CVOpenGLESTextureCacheCreate(kCFAllocatorDefault, NULL, (__bridge void *)_context, NULL, &coreVideoTextureCashe); 

    if (err) 
    { 
     NSAssert(NO, @"Error at CVOpenGLESTextureCacheCreate %d"); 
    } 

    //creats the pixel buffer 

    pixel_buffer = NULL; 
    CVPixelBufferPoolCreatePixelBuffer (NULL, [pixelAdapter pixelBufferPool], &pixel_buffer); 

    CVOpenGLESTextureRef renderTexture; 
    CVOpenGLESTextureCacheCreateTextureFromImage (kCFAllocatorDefault, coreVideoTextureCashe, pixel_buffer, 
                NULL, // texture attributes 
                GL_TEXTURE_2D, 
                GL_RGBA, // opengl format 
                (int)screenWidth, 
                (int)screenHeight, 
                GL_BGRA, // native iOS format 
                GL_UNSIGNED_BYTE, 
                0, 
                &renderTexture); 

    glBindTexture(CVOpenGLESTextureGetTarget(renderTexture), CVOpenGLESTextureGetName(renderTexture)); 
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); 
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); 

    glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, CVOpenGLESTextureGetName(renderTexture), 0); 

:

if(isRecording&&writerInput.readyForMoreMediaData) { 
    CVPixelBufferLockBaseAddress(pixel_buffer, 0); 

    if([pixelAdapter appendPixelBuffer:pixel_buffer withPresentationTime:currentTime]) { 
     currentTime = CMTimeAdd(currentTime, frameLength); 
    } 
    CVPixelBufferLockBaseAddress(pixel_buffer, 0); 
    CVPixelBufferRelease(pixel_buffer); 
} 

그러나이 전무가 아니라 0x000000001 renderTexture에 bad_acsess와 충돌 : 나는이 작업을 수행 .

실제로 비디오 파일을 해낼하지만 일부 녹색과 빨간색으로 깜박가 아래의 코드와 UPDATE

. BGRA pixelFormatType을 사용합니다.

CVReturn err2 = CVOpenGLESTextureCacheCreate(kCFAllocatorDefault, NULL, (__bridge void *)_context, NULL, &coreVideoTextureCashe); 
if (err2) 
{ 
    NSLog(@"Error at CVOpenGLESTextureCacheCreate %d", err); 
    return; 
} 

그리고 drawInRect에 나는이 전화 : 내가 여기에이 모든 일을하지 않음으로써 많은이를 최적화 할 수 있습니다 알고

if(isRecording&&writerInput.readyForMoreMediaData) { 
    [self cleanUpTextures]; 



    CFDictionaryRef empty; // empty value for attr value. 
    CFMutableDictionaryRef attrs2; 
    empty = CFDictionaryCreate(kCFAllocatorDefault, // our empty IOSurface properties dictionary 
          NULL, 
          NULL, 
          0, 
          &kCFTypeDictionaryKeyCallBacks, 
          &kCFTypeDictionaryValueCallBacks); 
    attrs2 = CFDictionaryCreateMutable(kCFAllocatorDefault, 
            1, 
            &kCFTypeDictionaryKeyCallBacks, 
            &kCFTypeDictionaryValueCallBacks); 

    CFDictionarySetValue(attrs2, 
        kCVPixelBufferIOSurfacePropertiesKey, 
        empty); 

//CVPixelBufferPoolCreatePixelBuffer (NULL, [assetWriterPixelBufferInput pixelBufferPool], &renderTarget); 
    CVPixelBufferRef pixiel_bufer4e = NULL; 

    CVPixelBufferCreate(kCFAllocatorDefault, 
        (int)_screenWidth, 
        (int)_screenHeight, 
        kCVPixelFormatType_32BGRA, 
        attrs2, 
        &pixiel_bufer4e); 
    CVOpenGLESTextureRef renderTexture; 
    CVOpenGLESTextureCacheCreateTextureFromImage (kCFAllocatorDefault, 
               coreVideoTextureCashe, pixiel_bufer4e, 
               NULL, // texture attributes 
               GL_TEXTURE_2D, 
               GL_RGBA, // opengl format 
               (int)_screenWidth, 
               (int)_screenHeight, 
               GL_BGRA, // native iOS format 
               GL_UNSIGNED_BYTE, 
               0, 
               &renderTexture); 
    CFRelease(attrs2); 
    CFRelease(empty); 
    glBindTexture(CVOpenGLESTextureGetTarget(renderTexture), CVOpenGLESTextureGetName(renderTexture)); 
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); 
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); 

    glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, CVOpenGLESTextureGetName(renderTexture), 0); 

    CVPixelBufferLockBaseAddress(pixiel_bufer4e, 0); 

    if([pixelAdapter appendPixelBuffer:pixiel_bufer4e withPresentationTime:currentTime]) { 
     float result = currentTime.value; 
     NSLog(@"\n\n\4eta danni i current time e : %f \n\n",result); 
     currentTime = CMTimeAdd(currentTime, frameLength); 
    } 

    CVPixelBufferUnlockBaseAddress(pixiel_bufer4e, 0); 
    CVPixelBufferRelease(pixiel_bufer4e); 
    CFRelease(renderTexture); 
    // CFRelease(coreVideoTextureCashe); 
} 

을, 아직 여기

나는 텍스쳐 캐시를 만들 나는 그것이 작동하게하고 싶었다.

CVOpenGLESTextureCacheFlush(coreVideoTextureCashe, 0); 

뭔가가 RGBA 물건 잘못 일 수도 있고 나도 몰라하지만 여전히 잘못된 캐시의 종류를 점점 것 같다 : cleanUpTextures에서 나는 함께 textureCache을 세척하십시오.

+0

받는 메모리 경고 또는 충돌 스크린 샷을 제공하십시오. – Dayan

+0

startWriting을 AssetWriter에 호출하는 레코드 버튼을 누르면 두 번째 및 수신 메모리 경고가 고정됩니다. 나타납니다 – user1562826

+0

이 방법을 사용하여 비디오를 녹화하고 화면에 내용을 동시에 표시 할 수 있습니까? –

답변

3

동영상 녹화의 경우이 방법을 사용하지 않습니다. 렌더링 된 각 프레임에 대해 새로운 픽셀 버퍼를 만들고 있습니다. 속도가 느려질 것이고 릴리즈하지 않을 것입니다. 따라서 메모리 경고가 발생하는 것은 놀라운 일이 아닙니다.

대신에 내가 설명한 내용은 this answer입니다. 캐시 된 텍스처를위한 픽셀 버퍼를 한 번 만들고, 그 텍스처를 FBO에 할당 한 다음, 모든 프레임에 AVAssetWriter의 픽셀 버퍼 입력을 사용하여 픽셀 버퍼를 추가합니다. 매 프레임 하나를 재생성하는 것보다 단일 픽셀 버퍼를 사용하는 것이 훨씬 빠릅니다. FBO의 텍스처 타겟과 연결된 픽셀 버퍼를 모든 프레임에 연결하지 않고 그대로 두길 원합니다.

GPImageMovieWriter 내 오픈 소스 GPUImage 프레임 워크에이 녹음 코드를 캡슐화하여 실제로 어떻게 작동하는지보고 싶습니다. 위의 링크 된 대답에서 알 수 있듯이이 방식으로 녹음을하면 매우 빠른 인코딩이됩니다.

+0

좋아요, 여기 drawInRect에서하는 일은 빠르지 만 검은 색 비디오를 기록합니다. 내가 생각하는 textureCasheRef가 비어 있거나 맞지 않습니다. dunno 질문이 업데이트되었습니다. – user1562826

+0

@ user1562826 - 앞으로 새로운 질문으로 원래 질문을 업데이트하십시오. 나는 당신을 위해 여기에서 그것을했다. 렌더링과 다른 스레드에서이 픽셀 버퍼와 바운드 텍스처에 액세스하려고하지 않습니다. 여러 스레드에서 OpenGL ES 컨텍스트에 동시에 액세스하면 충돌이 발생할 수 있습니다. –

+0

아니요, 하나의 스레드 만 사용합니다. 나는 비디오 파일을 얻을 수 있었지만 아직 비디오의 Cache가 OpenGL 컨텍스트에서 적절하게 추출되지 않는다고 생각한다. 왜냐하면 비디오에는 화면의 두 구석에있는이 선이 있고 그 아래에는 선 위에 빨간색이 있고 그 아래에는 약간 녹색이 있기 때문이다. 이 이상한 섬광이 있습니다. 내 질문을 업데이트합니다. 도와 주셔서 감사합니다! – user1562826

관련 문제