RTCI420Frame 对象到图像或纹理

Pab*_*nez 5 objective-c ios webrtc

我正在开发 iOS 的 WebRTC 应用程序。我的目标是从 WebRTC 对象录制视频。

我有委托 RTCVideoRenderer 为我提供了此方法。

-(void)renderFrame:(RTCI420Frame *)frame{
}
Run Code Online (Sandbox Code Playgroud)

我的问题是:如何将对象 RTCI420Frame 转换为有用的对象以显示图像或保存到磁盘。

wum*_*mbo 3

RTCI420Frames 使用 YUV420 格式。您可以使用 OpenCV 轻松将它们转换为 RGB,然后将它们转换为 UIImage。确保你#import <RTCI420Frame.h>

-(void) processFrame:(RTCI420Frame *)frame {
    cv::Mat mYUV((int)frame.height + (int)frame.chromaHeight,(int)frame.width, CV_8UC1, (void*) frame.yPlane);
    cv::Mat mRGB((int)frame.height, (int)frame.width, CV_8UC1);
    cvtColor(mYUV, mRGB, CV_YUV2RGB_I420);

    UIImage *image = [self UIImageFromCVMat:mRGB];
}

-(UIImage *)UIImageFromCVMat:(cv::Mat)cvMat
{
    NSData *data = [NSData dataWithBytes:cvMat.data length:cvMat.elemSize()*cvMat.total()];
    CGColorSpaceRef colorSpace;

    if (cvMat.elemSize() == 1) {
        colorSpace = CGColorSpaceCreateDeviceGray();
    } else {
        colorSpace = CGColorSpaceCreateDeviceRGB();
    }

    CGDataProviderRef provider = CGDataProviderCreateWithCFData((__bridge CFDataRef)data);

    // Creating CGImage from cv::Mat
    CGImageRef imageRef = CGImageCreate(cvMat.cols,
                                        cvMat.rows,
                                        8,
                                        8 * cvMat.elemSize(),
                                        cvMat.step[0],
                                        colorSpace,
                                        kCGImageAlphaNone|kCGBitmapByteOrderDefault,
                                        provider,
                                        NULL,
                                        false,
                                        kCGRenderingIntentDefault
                                        );


    // Getting UIImage from CGImage
    UIImage *finalImage = [UIImage imageWithCGImage:imageRef];
    CGImageRelease(imageRef);
    CGDataProviderRelease(provider);
    CGColorSpaceRelease(colorSpace);

    return finalImage;
}
Run Code Online (Sandbox Code Playgroud)

您可能希望在单独的线程上执行此操作,特别是当您正在进行任何视频处理时。另外,请记住使用 .mm 文件扩展名,以便您可以使用 C++。

如果您不想使用 OpenCV,也可以手动完成。下面的代码可以工作,但是颜色混乱并且几秒钟后崩溃。

int width = (int)frame.width;
int height = (int)frame.height;

uint8_t *data = (uint8_t *)malloc(width * height * 4);

const uint8_t* yPlane = frame.yPlane;
const uint8_t* uPlane = frame.uPlane;
const uint8_t* vPlane = frame.vPlane;

for (int i = 0; i < width * height; i++) {
    int rgbOffset = i * 4;
    uint8_t y = yPlane[i];
    uint8_t u = uPlane[i/4];
    uint8_t v = vPlane[i/4];

    uint8_t r = y + 1.402 * (v - 128);
    uint8_t g = y - 0.344 * (u - 128) - 0.714 * (v - 128);
    uint8_t b = y + 1.772 * (u - 128);

    data[rgbOffset] = r;
    data[rgbOffset + 1] = g;
    data[rgbOffset + 2] = b;
    data[rgbOffset + 3] = UINT8_MAX;
}

CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
CGContextRef gtx = CGBitmapContextCreate(data, width, height, 8, width * 4, colorSpace, kCGImageAlphaPremultipliedLast);
CGImageRef cgImage = CGBitmapContextCreateImage(gtx);
UIImage *uiImage = [[UIImage alloc] initWithCGImage:cgImage];

free(data);
Run Code Online (Sandbox Code Playgroud)