2014-02-21 3 views
1

ffmpeg/libav에서 RGB 프레임을 YUV420P 포맷으로 변환하려고합니다. 다음은 변환 코드와 변환 전후의 이미지입니다. 변환 된 이미지는 모든 색상 정보를 잃고 스케일도 크게 변경됩니다. 아무도 이것을 어떻게 처리 할 생각이 있습니까? 나는 완전히 ffmpeg/libav에 익숙하다!ffmpeg : RGB에서 YUV로 변환시 색상과 스케일이 없어집니다.

// Did we get a video frame? 
    if(frameFinished) 
    { 
     i++; 
     sws_scale(img_convert_ctx, (const uint8_t * const *)pFrame->data, 
       pFrame->linesize, 0, pCodecCtx->height, 
       pFrameRGB->data, pFrameRGB->linesize);     

     //============================================================== 
     AVFrame *pFrameYUV = avcodec_alloc_frame(); 
     // Determine required buffer size and allocate buffer 
     int numBytes2 = avpicture_get_size(PIX_FMT_RGB24, pCodecCtx->width,         
              pCodecCtx->height); 
     uint8_t *buffer = (uint8_t *)av_malloc(numBytes2*sizeof(uint8_t)); 

     avpicture_fill((AVPicture *)pFrameYUV, buffer, PIX_FMT_RGB24, 
         pCodecCtx->width, pCodecCtx->height); 


     rgb_to_yuv_ctx = sws_getContext(pCodecCtx->width, pCodecCtx->height, 
             PIX_FMT_RGB24, 
             pCodecCtx->width,pCodecCtx->height, 
             PIX_FMT_RGB24, 
             SWS_BICUBIC, NULL,NULL,NULL); 

     sws_scale(rgb_to_yuv_ctx, pFrameRGB->data, pFrameRGB->linesize, 0, 
       pCodecCtx->height, pFrameYUV->data, pFrameYUV->linesize); 

     sws_freeContext(rgb_to_yuv_ctx); 

     SaveFrame(pFrameYUV, pCodecCtx->width, pCodecCtx->height, i); 

     av_free(buffer); 
     av_free(pFrameYUV); 
    } 

original RGB24 frame

frame after RGB24->YUV420P conversion 우선 잘

+0

이 이미지는 광산과 비슷하지만 수동으로 rgb2yuv를하고 있습니다. 흑백 이미지는 김프에서 열 때 볼 수있는 것과 정확히 같지만 데이터가 정확하므로 카메라가 보내는 것과 동일합니다. 어쩌면 미리보기 문제일까요? 다른 방법으로 데이터를 테스트 할 수 있습니까? – tomasb

답변

10

나는 당신이 어디에 가정합니다 :

rgb_to_yuv_ctx = sws_getContext(pCodecCtx->width, pCodecCtx->height, 
            PIX_FMT_RGB24, 
            pCodecCtx->width,pCodecCtx->height, 
            PIX_FMT_RGB24, 
            SWS_BICUBIC, NULL,NULL,NULL); 

당신은 정말 목적 :

rgb_to_yuv_ctx = sws_getContext(pCodecCtx->width, pCodecCtx->height, 
            PIX_FMT_RGB24, 
            pCodecCtx->width,pCodecCtx->height, 
            PIX_FMT_YUV420P, 
            SWS_BICUBIC, NULL,NULL,NULL); 

swscale을 두 번 호출하는 이유가 확실하지 않습니다.

YUV는 평면 형식입니다. 즉, 세 채널 모두 독립적으로 저장됩니다. RGB가 같은 저장 Whre : RGBRGBRGB

YUV420P 같은 매장입니다 : YYYYYYYYYYYYYYYY..UUUUUUUUUU..VVVVVVVV

그래서 당신은 그에게 세 가지 포인터를 제공해야 swscale.

다음으로 라인 보폭을 16 또는 32의 배수로 설정하여 프로세서의 벡터 단위를 사용할 수 있습니다. 마지막으로 Y 평면의 크기는 2로 나눌 수 있어야합니다 (U 평면과 V 평면은 Y 평면의 1/4 크기이기 때문에). |

#define RNDTO2(X) (((X) & 0xFFFFFFFE) 
#define RNDTO32(X) (((X) % 32) ? (((X) + 32) & 0xFFFFFFE0) : (X)) 




if(frameFinished) 
{ 
    static SwsContext *swsCtx = NULL; 
    int width = RNDTO2 (pCodecCtx->width); 
    int height = RNDTO2 (pCodecCtx->height); 
    int ystride = RNDTO32 (width); 
    int uvstride = RNDTO32 (width/2); 
    int ysize = ystride * height; 
    int vusize = uvstride * (height/2); 
    int size  = ysize + (2 * vusize) 

    void * pFrameYUV = malloc(size); 
    void *plane[] = { pFrameYUV, pFrameYUV + ysize, pFrameYUV + ysize + vusize, 0 }; 
    int *stride[] = { ystride, vustride, vustride, 0 }; 

    swsCtx = sws_getCachedContext (swsCtx, pCodecCtx->width, pCodecCtx->height, 
    pCodecCtx->pixfmt, width, height, AV_PIX_FMT_YUV420P, 
    SWS_LANCZOS | SWS_ACCURATE_RND , NULL, NULL, NULL); 
    sws_scale (swsCtx, pFrameRGB->data, pFrameRGB->linesize, 0, 
    pFrameRGB->height, plane, stride); 
}  

가 나는 또한 SWS_LANCZOS를 사용하도록 알고리즘을 전환 :

그래서,이를 다시 작성할 수 있습니다 SWS_ACCURATE_RND. 이렇게하면 더 나은 이미지를 얻을 수 있습니다. 느린 경우 다시 변경하십시오. 또한 항상 RGB로 가정하는 대신 원본 프레임의 픽셀 형식을 사용했습니다.

+0

답장을 보내 주셔서 감사합니다. 나는 그것을 시도했다. 그러나 어떻게 지금 나는 개조 된 프레임을 보느냐? 이전에 내가 게시 한 코드에 표시된대로 'SaveFrame (pFrameYUV, pCodecCtx-> width, pCodecCtx-> height, i); ' 과 같이 변환 된 프레임을 저장했습니다. 'SaveFrame()'함수는 [dranger 's tutorial] (http://dranger.com/ffmpeg/tutorial01.c) – learner

+0

에서 저장하고 볼 수있는 형식으로 변환합니다. – szatmary

+0

'평면 저장'을 시도했습니다. '나는 변환 된 프레임을 보유하고 있다고 생각한다. 그것은 오류를 제공합니다 : '[mpeg4 @ 0x874020] 유효하지 않은 비효율적 인 vfw-avi 압축 된 B 프레임 감지 됨 어떤 아이디어가 잘못 되었습니까? 감사! – learner