美文网首页
nv12 yuv420p的相互转换

nv12 yuv420p的相互转换

作者: 未来的路就在那 | 来源:发表于2019-01-11 12:10 被阅读19次
    //初始化输入,输出的类型
    -(void)initCapureSession{
        //创建AVCaptureDevice的视频设备对象
        AVCaptureDevice* videoDevice = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];
        
        NSError* error;
        //创建视频输入端对象
        AVCaptureDeviceInput* input = [AVCaptureDeviceInput deviceInputWithDevice:videoDevice error:&error];
        if (error) {
            NSLog(@"创建输入端失败,%@",error);
            return;
        }
        
        //创建功能会话对象
        self.captureSession = [[AVCaptureSession alloc] init];
        //设置会话输出的视频分辨率
        [self.captureSession setSessionPreset:AVCaptureSessionPreset1280x720];
        
        //添加输入端
        if (![self.captureSession canAddInput:input]) {
            NSLog(@"输入端添加失败");
            return;
        }
        [self.captureSession addInput:input];
        
        //显示摄像头捕捉到的数据
        AVCaptureVideoPreviewLayer* layer = [[AVCaptureVideoPreviewLayer alloc] initWithSession:self.captureSession];
        layer.frame = CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height - 100);
        [self.view.layer addSublayer:layer];
        
        //创建输出端
        
        AVCaptureVideoDataOutput *videoDataOutput = [[AVCaptureVideoDataOutput alloc] init];
        NSString* key = (NSString*)kCVPixelBufferPixelFormatTypeKey;
        NSNumber* value = [NSNumber
                           numberWithUnsignedInt:kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange];
        NSDictionary* videoSettings = [NSDictionary
                                       dictionaryWithObject:value forKey:key];
        [videoDataOutput setVideoSettings:videoSettings];
        //会话对象添加输出端
        if ([self.captureSession canAddOutput:videoDataOutput]) {
            [self.captureSession addOutput:videoDataOutput];
            self.videoDataOutput = videoDataOutput;
            //创建输出调用的队列
            dispatch_queue_t videoDataOutputQueue = dispatch_queue_create("videoDataOutputQueue", DISPATCH_QUEUE_SERIAL);
            self.videoDataOutputQueue = videoDataOutputQueue;
            //设置代理和调用的队列
            [self.videoDataOutput setSampleBufferDelegate:self queue:videoDataOutputQueue];
            //设置延时丢帧
            self.videoDataOutput.alwaysDiscardsLateVideoFrames = NO;
        }
    }
    
    
    #pragma mark - AVCaptureVideoDataOutputSampleBufferDelegate
    - (void)captureOutput:(AVCaptureOutput *)output didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer fromConnection:(AVCaptureConnection *)connection {
        NSLog(@"did get %@",output);
        NSData *data22 = [self convertVideoSmapleBufferToYuvData:sampleBuffer];
        [self.h264Tool addFrame:sampleBuffer];
    }
    // CMSampleBufferRef代表一帧图像,调用苹果提供的api可以获取具体的yuv的数据
    -(NSData *) convertVideoSmapleBufferToYuvData:(CMSampleBufferRef) videoSample{
        // 获取yuv数据
        // 通过CMSampleBufferGetImageBuffer方法,获得CVImageBufferRef。
        // 这里面就包含了yuv420(NV12)数据的指针
        CVImageBufferRef pixelBuffer = CMSampleBufferGetImageBuffer(videoSample);
        
        //表示开始操作数据
        CVPixelBufferLockBaseAddress(pixelBuffer, 0);
        
        //图像宽度(像素)
        size_t pixelWidth = CVPixelBufferGetWidth(pixelBuffer);
        //图像高度(像素)
        size_t pixelHeight = CVPixelBufferGetHeight(pixelBuffer);
        //yuv中的y所占字节数
        size_t y_size = pixelWidth * pixelHeight;
        //yuv中的uv所占的字节数
        size_t uv_size = y_size / 2;
        
        uint8_t *yuv_frame = malloc(uv_size + y_size);
        
        //获取CVImageBufferRef中的y数据
        uint8_t *y_frame = CVPixelBufferGetBaseAddressOfPlane(pixelBuffer, 0);
        memcpy(yuv_frame, y_frame, y_size);
        
        //获取CMVImageBufferRef中的uv数据
        uint8_t *uv_frame = CVPixelBufferGetBaseAddressOfPlane(pixelBuffer, 1);
        memcpy(yuv_frame + y_size, uv_frame, uv_size);
        
        CVPixelBufferUnlockBaseAddress(pixelBuffer, 0);
        uint8_t *I420 = malloc(uv_size + y_size);
        NSString *path = [self getHomePath];
        const char *resultCString = NULL;
        if ([path canBeConvertedToEncoding:NSUTF8StringEncoding]) {
            resultCString = [path cStringUsingEncoding:NSUTF8StringEncoding];
        }
        NSString *path2 = [self getHome2Path];
        const char *resultCString2 = NULL;
        if ([path2 canBeConvertedToEncoding:NSUTF8StringEncoding]) {
            resultCString2 = [path2 cStringUsingEncoding:NSUTF8StringEncoding];
        }
        dispatch_sync(dispatch_get_main_queue(), ^{
            func(yuv_frame, I420,pixelWidth,pixelHeight,resultCString,resultCString2);
            func5(yuv_frame, I420,pixelWidth,pixelHeight,resultCString,resultCString2);
        });
        
        //返回数据
        return [NSData dataWithBytesNoCopy:yuv_frame length:y_size + uv_size];
    }
    // nv12 写入本地
    void func0(uint8_t *NV12, uint8_t *I420,size_t pixelWidth,size_t pixelHeight,const char *resultCString,const char *resultCString2){
        NSLog(@"start");
        int len = (int)pixelHeight * pixelWidth + pixelHeight * pixelWidth / 2;
        FILE* fpyuv = fopen(resultCString, "wb");
        for (int i = 0; i < len; i ++) {
            fwrite(NV12, 1, 1, fpyuv);
            NV12 ++;
        }
        fclose(fpyuv);
        free(NV12);
        NSLog(@"end");
    }
    // nv12 转 yuv 并写入本地
    void func(uint8_t *NV12, uint8_t *I420,size_t pixelWidth,size_t pixelHeight,const char *resultCString,const char *resultCString2){
        unsigned char *ybuf = (unsigned char *)malloc(pixelHeight * pixelWidth);
        unsigned char *ubuf = (unsigned char *)malloc((pixelHeight/2) * (pixelWidth/2));
        unsigned char *vbuf = (unsigned char *)malloc((pixelHeight/2) * (pixelWidth/2));
        unsigned char *y = ybuf;
        unsigned char *u = ubuf;
        unsigned char *v = vbuf;
        int len = (int)pixelHeight * pixelWidth + pixelHeight * pixelWidth / 2;
        FILE* fpyuv = fopen(resultCString, "wb");
        for (int i = 0; i < len; i ++) {
            if (i < (pixelWidth * pixelHeight)) {  //yyyyy
                *y = *NV12;
                y++;
            }
            else{//uvuvuv
                if (i % 2 == 0) {//uuuuu
                    *u = *NV12;
                    u ++;
                }else{//vvvvv
                    *v = *NV12;
                    v ++;
                }
            }
            NV12 ++;
        }
        fwrite(ybuf, 1, pixelWidth*pixelHeight, fpyuv);
        fwrite(ubuf, 1, pixelWidth*pixelHeight/4, fpyuv);
        fwrite(vbuf, 1, pixelWidth*pixelHeight/4, fpyuv);
        fclose(fpyuv);
        free(ybuf);
        free(ubuf);
        free(vbuf);
    }
    // 从本地文件获取yuv的数据 并实现180度的翻转 并写入本地
    void func2(uint8_t *NV12, uint8_t *I420,size_t pixelWidth,size_t pixelHeight,const char *resultCString,const char *resultCString2){
        unsigned char *ybuf = (unsigned char *)malloc(pixelHeight * pixelWidth);
        unsigned char *ubuf = (unsigned char *)malloc((pixelHeight/2) * (pixelWidth/2));
        unsigned char *vbuf = (unsigned char *)malloc((pixelHeight/2) * (pixelWidth/2));
        unsigned char *y = ybuf;
        unsigned char *u = ubuf;
        unsigned char *v = vbuf;
        FILE* fpyuv = fopen(resultCString, "rb");
        FILE* fpyuv2 = fopen(resultCString2, "wb");
        uint8_t* yuvbuf = malloc(pixelHeight * pixelWidth * 3 / 2);
        fread(yuvbuf, pixelWidth*pixelHeight * 3 / 2, 1, fpyuv);
        fclose(fpyuv);
        // y
        for (int i = pixelHeight -1; i >= 0; i --) {
            for (int j = pixelWidth - 1; j >= 0; j--) {
                *(y++) = *(yuvbuf +(i*pixelWidth + j));
            }
        }
        //U
        uint8_t* uheader = yuvbuf + pixelWidth*pixelHeight;
        for (int i = pixelHeight/2 - 1; i >= 0; i--){
            for (int j = pixelWidth/2-1 ; j >= 0; j--){
                *(u++) = *(uheader +(i*pixelWidth/2 + j));
            }
        }
        //v
        uint8_t* vheader = uheader + pixelWidth*pixelHeight/4;
        for (int i = pixelHeight/2 - 1; i >= 0; i--){
            for (int j = pixelWidth/2-1 ; j >= 0; j--){
                *(v++) = *(vheader +(i*pixelWidth/2 + j));
            }
        }
        fwrite(ybuf, 1, pixelWidth*pixelHeight, fpyuv2);
        fwrite(ubuf, 1, pixelWidth*pixelHeight/4, fpyuv2);
        fwrite(vbuf, 1, pixelWidth*pixelHeight/4, fpyuv2);
        fclose(fpyuv2);
        free(ybuf);
        free(ubuf);
        free(vbuf);
    }
    // 从本地文件获取yuv的数据 并实现逆时针90度的翻转 并写入本地
    void func3(uint8_t *NV12, uint8_t *I420,size_t pixelWidth,size_t pixelHeight,const char *resultCString,const char *resultCString2){
        unsigned char *ybuf = (unsigned char *)malloc(pixelHeight * pixelWidth);
        unsigned char *ubuf = (unsigned char *)malloc((pixelHeight/2) * (pixelWidth/2));
        unsigned char *vbuf = (unsigned char *)malloc((pixelHeight/2) * (pixelWidth/2));
        unsigned char *y = ybuf;
        unsigned char *u = ubuf;
        unsigned char *v = vbuf;
        FILE* fpyuv = fopen(resultCString, "rb");
        FILE* fpyuv2 = fopen(resultCString2, "wb");
        uint8_t* yuvbuf = malloc(pixelHeight * pixelWidth * 3 / 2);
        fread(yuvbuf, pixelWidth*pixelHeight * 3 / 2, 1, fpyuv);
        fclose(fpyuv);
        for (int i = 0; i < pixelWidth; i ++) {
            for (int j = pixelHeight - 1; j >= 0; j --) {
                *(y++) = *(yuvbuf +(j*pixelWidth +i));
            }
        }
        uint8_t* uheader = yuvbuf + pixelWidth*pixelHeight;
        for (int i = 0; i < pixelWidth/2; i ++) {
            for (int j = pixelHeight/2 - 1; j >= 0; j --) {
                *(u++) = *(uheader +(j*pixelWidth/2 + i));
            }
        }
        uint8_t* vheader = uheader + pixelWidth*pixelHeight/4;
        for (int i = 0; i < pixelWidth/2; i ++) {
            for (int j = pixelHeight/2 - 1; j >= 0; j --) {
                *(v++) = *(vheader +(j*pixelWidth/2 + i));
            }
        }
        fwrite(ybuf, 1, pixelWidth*pixelHeight, fpyuv2);
        fwrite(ubuf, 1, pixelWidth*pixelHeight/4, fpyuv2);
        fwrite(vbuf, 1, pixelWidth*pixelHeight/4, fpyuv2);
        fclose(fpyuv2);
        free(ybuf);
        free(ubuf);
        free(vbuf);
    }
    // 从本地文件获取yuv的数据 并实现顺时针90度的翻转 并写入本地
    void func4(uint8_t *NV12, uint8_t *I420,size_t pixelWidth,size_t pixelHeight,const char *resultCString,const char *resultCString2){
        unsigned char *ybuf = (unsigned char *)malloc(pixelHeight * pixelWidth);
        unsigned char *ubuf = (unsigned char *)malloc((pixelHeight/2) * (pixelWidth/2));
        unsigned char *vbuf = (unsigned char *)malloc((pixelHeight/2) * (pixelWidth/2));
        unsigned char *y = ybuf;
        unsigned char *u = ubuf;
        unsigned char *v = vbuf;
        FILE* fpyuv = fopen(resultCString, "rb");
        FILE* fpyuv2 = fopen(resultCString2, "wb");
        uint8_t* yuvbuf = malloc(pixelHeight * pixelWidth * 3 / 2);
        fread(yuvbuf, pixelWidth*pixelHeight * 3 / 2, 1, fpyuv);
        fclose(fpyuv);
        for (int i = pixelWidth - 1; i >= 0; i --) {
            for (int j = 0; j < pixelHeight; j ++) {
                *(y++) = *(yuvbuf +(j*pixelWidth +i));
            }
        }
        uint8_t* uheader = yuvbuf + pixelWidth*pixelHeight;
        for (int i = pixelWidth/2 - 1; i >= 0; i --) {
            for (int j = 0; j < pixelHeight/2; j ++) {
                *(u++) = *(uheader +(j*pixelWidth/2 +i));
            }
        }
        uint8_t* vheader = uheader + pixelWidth*pixelHeight/4;
        for (int i = pixelWidth/2 - 1; i >= 0; i --) {
            for (int j = 0; j < pixelHeight/2; j ++) {
                *(v++) = *(vheader +(j*pixelWidth/2 +i));
            }
        }
        fwrite(ybuf, 1, pixelWidth*pixelHeight, fpyuv2);
        fwrite(ubuf, 1, pixelWidth*pixelHeight/4, fpyuv2);
        fwrite(vbuf, 1, pixelWidth*pixelHeight/4, fpyuv2);
        fclose(fpyuv2);
        free(ybuf);
        free(ubuf);
        free(vbuf);
    }
    // 从本地文件获取yuv的数据 制作水平方向的镜像 并写入本地
    void func5(uint8_t *NV12, uint8_t *I420,size_t pixelWidth,size_t pixelHeight,const char *resultCString,const char *resultCString2){
        unsigned char *ybuf = (unsigned char *)malloc(pixelHeight * pixelWidth);
        unsigned char *ubuf = (unsigned char *)malloc((pixelHeight/2) * (pixelWidth/2));
        unsigned char *vbuf = (unsigned char *)malloc((pixelHeight/2) * (pixelWidth/2));
        unsigned char *y = ybuf;
        unsigned char *u = ubuf;
        unsigned char *v = vbuf;
        FILE* fpyuv = fopen(resultCString, "rb");
        FILE* fpyuv2 = fopen(resultCString2, "wb");
        uint8_t* yuvbuf = malloc(pixelHeight * pixelWidth * 3 / 2);
        fread(yuvbuf, pixelWidth*pixelHeight * 3 / 2, 1, fpyuv);
        fclose(fpyuv);
        for (int i = 0; i < pixelHeight - 1; i ++) {
            for (int j = pixelWidth - 1; j >= 0; j --) {
                *(y++) = *(yuvbuf +(i*pixelWidth +j));
            }
        }
        uint8_t* uheader = yuvbuf + pixelWidth*pixelHeight;
        for (int i = 0; i < pixelHeight/2 - 1; i ++) {
            for (int j = pixelWidth/2 - 1; j >= 0; j --) {
                *(u++) = *(uheader +(i*pixelWidth/2 +j));
            }
        }
        uint8_t* vheader = uheader + pixelWidth*pixelHeight/4;
        for (int i = 0; i < pixelHeight/2 - 1; i ++) {
            for (int j = pixelWidth/2 - 1; j >= 0; j --) {
                *(v++) = *(vheader +(i*pixelWidth/2 +j));
            }
        }
        fwrite(ybuf, 1, pixelWidth*pixelHeight, fpyuv2);
        fwrite(ubuf, 1, pixelWidth*pixelHeight/4, fpyuv2);
        fwrite(vbuf, 1, pixelWidth*pixelHeight/4, fpyuv2);
        fclose(fpyuv2);
        free(ybuf);
        free(ubuf);
        free(vbuf);
    }
    - (NSString *)getHomePath{
        NSString *path = NSHomeDirectory();
        
        NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
        NSString *docDir = [paths objectAtIndex:0];
        return [NSString stringWithFormat:@"%@/outforyuv420p_new_new.yuv",docDir];
    }
    - (NSString *)getHome2Path{
        NSString *path = NSHomeDirectory();
        
        NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
        NSString *docDir = [paths objectAtIndex:0];
        return [NSString stringWithFormat:@"%@/outforyuv420p_new_new_rala.yuv",docDir];
    }
    

    相关文章

      网友评论

          本文标题:nv12 yuv420p的相互转换

          本文链接:https://www.haomeiwen.com/subject/vvotdqtx.html