实现VPC功能
概念说明
关于抠图、缩放、叠加、上偏移、下偏移、左偏移、右偏移等概念,请参见VPC功能。
示例1:仅原图缩放
关键参数设置如下:
- 抠图区域宽高跟输入图片的真实宽高相同,抠图区域各偏移值的设置如下:
- 左偏移leftOffset=0
- 上偏移upOffset=0
- 右偏移rightOffset - 左偏移leftOffset+1=输入图片真实宽
- 下偏移downOffset - 上偏移upOffset+1=输入图片真实高
- 贴图区域宽高是缩放后图片的宽高,可指定贴图区域的位置,例如:
若指定贴图区域的位置在输出图片的左上角,则贴图区域各偏移值的设置如下:
- 左偏移leftOffset=0
- 上偏移upOffset=0
- 右偏移rightOffset - 左偏移leftOffset+1=缩放后图片的宽
- 下偏移downOffset - 上偏移upOffset+1=缩放后图片的高
- 如果是8K的原图缩放,则inputFormat和outputFormat只支持依次设置为INPUT_YUV420_SEMI_PLANNER_UV、OUTPUT_YUV420SP_UV或设置为INPUT_YUV420_SEMI_PLANNER_VU、OUTPUT_YUV420SP_VU;如果是非8K的原图缩放,inputFormat和outputFormat的设置可参考表1。
示例代码:
本示例是将yuv420sp格式的图片从1080p缩放到720p。
void NewVpcTest1() { uint32_t inWidthStride = 1920; uint32_t inHeightStride = 1080; uint32_t outWidthStride = 1280; uint32_t outHeightStride = 720; uint32_t inBufferSize = inWidthStride * inHeightStride * 3 / 2; // 1080P yuv420sp Image uint32_t outBufferSize = outWidthStride * outHeightStride * 3 / 2; // 720P yuv420sp bImage uint8_t* inBuffer = static_cast<uint8_t*>(HIAI_DVPP_DMalloc(inBufferSize)); // Construct an input picture. if (inBuffer == nullptr) { HIAI_ENGINE_LOG(HIAI_VPC_CTL_ERROR, "can not alloc input buffer"); return; } uint8_t* outBuffer = static_cast<uint8_t*>(HIAI_DVPP_DMalloc(outBufferSize)); // Construct an output picture. if (outBuffer == nullptr) { HIAI_ENGINE_LOG(HIAI_VPC_CTL_ERROR, "can not alloc output buffer"); HIAI_DVPP_DFree(inBuffer); inBuffer = nullptr; return; } FILE* fp = fopen("dvpp_vpc_1920x1080_nv12.yuv", "rb+"); if (fp == nullptr) { HIAI_ENGINE_LOG(HIAI_ERROR, "fopen file failed"); DFreeInOutBuffer(inBuffer, outBuffer); return; } fread(inBuffer, 1, inBufferSize, fp); fclose(fp); fp = nullptr; // Construct the input picture configuration. std::shared_ptr<VpcUserImageConfigure> imageConfigure(new VpcUserImageConfigure); imageConfigure->bareDataAddr = inBuffer; imageConfigure->bareDataBufferSize = inBufferSize; imageConfigure->widthStride = inWidthStride; imageConfigure->heightStride = inHeightStride; imageConfigure->inputFormat = INPUT_YUV420_SEMI_PLANNER_UV; imageConfigure->outputFormat = OUTPUT_YUV420SP_UV; imageConfigure->yuvSumEnable = false; imageConfigure->cmdListBufferAddr = nullptr; imageConfigure->cmdListBufferSize = 0; std::shared_ptr<VpcUserRoiConfigure> roiConfigure(new VpcUserRoiConfigure); roiConfigure->next = nullptr; VpcUserRoiInputConfigure* inputConfigure = &roiConfigure->inputConfigure; // Set the drawing area, [0,0] in the upper left corner of the area, // and [1919,1079] in the lower right corner. inputConfigure->cropArea.leftOffset = 0; inputConfigure->cropArea.rightOffset = inWidthStride - 1; inputConfigure->cropArea.upOffset = 0; inputConfigure->cropArea.downOffset = inHeightStride - 1; VpcUserRoiOutputConfigure* outputConfigure = &roiConfigure->outputConfigure; outputConfigure->addr = outBuffer; outputConfigure->bufferSize = outBufferSize; outputConfigure->widthStride = outWidthStride; outputConfigure->heightStride = outHeightStride; // Set the map area, coordinate [0,0] in the upper left corner of the map area, // and [1279,719] in the lower right corner. outputConfigure->outputArea.leftOffset = 0; outputConfigure->outputArea.rightOffset = outWidthStride - 1; outputConfigure->outputArea.upOffset = 0; outputConfigure->outputArea.downOffset = outHeightStride - 1; imageConfigure->roiConfigure = roiConfigure.get(); IDVPPAPI *pidvppapi = nullptr; int32_t ret = CreateDvppApi(pidvppapi); if (ret != 0) { HIAI_ENGINE_LOG(HIAI_CREATE_DVPP_ERROR, "create dvpp api fail."); DFreeInOutBuffer(inBuffer, outBuffer); return; } dvppapi_ctl_msg dvppApiCtlMsg; dvppApiCtlMsg.in = static_cast<void*>(imageConfigure.get()); dvppApiCtlMsg.in_size = sizeof(VpcUserImageConfigure); ret = DvppCtl(pidvppapi, DVPP_CTL_VPC_PROC, &dvppApiCtlMsg); if (ret != 0) { HIAI_ENGINE_LOG(HIAI_VPC_CTL_ERROR, "call vpc dvppctl process faild!"); ret = DestroyDvppApi(pidvppapi); DFreeInOutBuffer(inBuffer, outBuffer); return; } else { HIAI_ENGINE_LOG(HIAI_OK, "NewVpcTest1::call vpc dvppctl process success!"); } FILE* outImageFp = fopen("NewVpcTest1Out.yuv", "wb+"); if (outImageFp == nullptr) { HIAI_ENGINE_LOG(HIAI_VPC_CTL_ERROR, "open NewVpcTest1Out.yuv faild!"); ret = DestroyDvppApi(pidvppapi); DFreeInOutBuffer(inBuffer, outBuffer); return; } fwrite(outBuffer, 1, outBufferSize, outImageFp); ret = DestroyDvppApi(pidvppapi); DFreeInOutBuffer(inBuffer, outBuffer); fclose(outImageFp); outImageFp = nullptr; return; }
示例2:抠一张图+缩放
关键参数设置如下:
- 抠图区域宽高是缩放前图片的宽高,可指定抠图区域的位置,例如:
若指定抠图区域的位置在输入图片的中间,则抠图区域各偏移值的设置如下:
- 左偏移leftOffset=100
- 右偏移rightOffset=499
- 上偏移upOffset=100
- 下偏移downOffset=399
- 右偏移rightOffset - 左偏移leftOffset+1=抠图区域图片的宽
- 下偏移downOffset - 上偏移upOffset+1=抠图区域图片的高
- 贴图区域宽高是缩放后图片的宽高,可指定贴图区域的位置,例如:
若指定贴图区域的位置在输出图片的中间,则贴图区域各偏移值的设置如下:
- 左偏移leftOffset=256
- 右偏移rightOffset=399
- 上偏移upOffset=200
- 下偏移downOffset=399
- 右偏移rightOffset - 左偏移leftOffset+1=缩放后图片的宽
- 下偏移downOffset - 上偏移upOffset+1=缩放后图片的高
示例代码:
本示例是从yuv420sp格式、1080p的图片中抠出一张图,经过缩放后,将缩放后的图片贴到720p的输出图片(由用户申请的空输出内存产生的空白图片)中。如果需要将已有图片作为输出图片,用户需在申请输出内存后,将已有图片读入输出内存,代码示例请参考示例5:叠加。
void NewVpcTest2() { uint32_t inWidthStride = 1920; uint32_t inHeightStride = 1080; uint32_t outWidthStride = 1280; uint32_t outHeightStride = 720; uint32_t inBufferSize = inWidthStride * inHeightStride * 3 / 2; // 1080P yuv420sp Image uint32_t outBufferSize = outWidthStride * outHeightStride * 3 / 2; // 720P yuv420sp Image uint8_t* inBuffer = static_cast<uint8_t*>(HIAI_DVPP_DMalloc(inBufferSize)); // Construct an input picture. if (inBuffer == nullptr) { HIAI_ENGINE_LOG(HIAI_VPC_CTL_ERROR, "can not alloc input buffer"); return; } uint8_t* outBuffer = static_cast<uint8_t*>(HIAI_DVPP_DMalloc(outBufferSize)); // Construct an output picture. if (outBuffer == nullptr) { HIAI_ENGINE_LOG(HIAI_VPC_CTL_ERROR, "can not alloc output buffer"); HIAI_DVPP_DFree(inBuffer); inBuffer = nullptr; return; } (void)memset_s(outBuffer, outBufferSize, 0x80, outBufferSize); FILE* fp = fopen("dvpp_vpc_1920x1080_nv12.yuv", "rb+"); if (fp == nullptr) { HIAI_ENGINE_LOG(HIAI_ERROR, "fopen file failed"); DFreeInOutBuffer(inBuffer, outBuffer); return; } fread(inBuffer, 1, inBufferSize, fp); fclose(fp); fp = nullptr; // Construct the input picture configuration std::shared_ptr<VpcUserImageConfigure> imageConfigure(new VpcUserImageConfigure); imageConfigure->bareDataAddr = inBuffer; imageConfigure->bareDataBufferSize = inBufferSize; imageConfigure->widthStride = inWidthStride; imageConfigure->heightStride = inHeightStride; imageConfigure->inputFormat = INPUT_YUV420_SEMI_PLANNER_UV; imageConfigure->outputFormat = OUTPUT_YUV420SP_UV; imageConfigure->yuvSumEnable = false; imageConfigure->cmdListBufferAddr = nullptr; imageConfigure->cmdListBufferSize = 0; std::shared_ptr<VpcUserRoiConfigure> roiConfigure(new VpcUserRoiConfigure); roiConfigure->next = nullptr; VpcUserRoiInputConfigure* inputConfigure = &roiConfigure->inputConfigure; // Set the drawing area, [100,100] in the upper left corner of the area, and [499,499] in the lower right corner. inputConfigure->cropArea.leftOffset = 100; inputConfigure->cropArea.rightOffset = 499; inputConfigure->cropArea.upOffset = 100; inputConfigure->cropArea.downOffset = 499; VpcUserRoiOutputConfigure* outputConfigure = &roiConfigure->outputConfigure; outputConfigure->addr = outBuffer; outputConfigure->bufferSize = outBufferSize; outputConfigure->widthStride = outWidthStride; outputConfigure->heightStride = outHeightStride; // Set the map area, [256,200] in the upper left corner of the map area, and [399,399] in the lower right corner. outputConfigure->outputArea.leftOffset = 256; // The offset value must be 16-pixel-aligned. outputConfigure->outputArea.rightOffset = 399; outputConfigure->outputArea.upOffset = 200; outputConfigure->outputArea.downOffset = 399; imageConfigure->roiConfigure = roiConfigure.get(); IDVPPAPI *pidvppapi = nullptr; int32_t ret = CreateDvppApi(pidvppapi); if (ret != 0) { HIAI_ENGINE_LOG(HIAI_CREATE_DVPP_ERROR, "create dvpp api fail."); DFreeInOutBuffer(inBuffer, outBuffer); return; } dvppapi_ctl_msg dvppApiCtlMsg; dvppApiCtlMsg.in = static_cast<void*>(imageConfigure.get()); dvppApiCtlMsg.in_size = sizeof(VpcUserImageConfigure); ret = DvppCtl(pidvppapi, DVPP_CTL_VPC_PROC, &dvppApiCtlMsg); if (ret != 0) { HIAI_ENGINE_LOG(HIAI_VPC_CTL_ERROR, "call vpc dvppctl process faild!"); ret = DestroyDvppApi(pidvppapi); DFreeInOutBuffer(inBuffer, outBuffer); return; } else { HIAI_ENGINE_LOG(HIAI_OK, "NewVpcTest2::call vpc dvppctl process success!"); } FILE* outImageFp = fopen("NewVpcTest2Out.yuv", "wb+"); if (outImageFp == nullptr) { HIAI_ENGINE_LOG(HIAI_ERROR, "open NewVpcTest2Out.yuv failed"); DestroyDvppApi(pidvppapi); DFreeInOutBuffer(inBuffer, outBuffer); return; } fwrite(outBuffer, 1, outBufferSize, outImageFp); ret = DestroyDvppApi(pidvppapi); DFreeInOutBuffer(inBuffer, outBuffer); fclose(outImageFp); outImageFp = nullptr; return; }
示例3:抠多张图+缩放+拼接
关键参数设置:抠图区域上偏移、下偏移、左偏移、右偏移以及贴图区域上偏移、下偏移、左偏移、右偏移的配置,请参见示例2:抠一张图+缩放中的说明。
示例代码:本示例是从yuv420sp格式、1080p的图片中抠出多张图,经过缩放后,将缩放后的多张图片拼接到720p的输出图片(由用户申请的空输出内存产生的空白图片)中,贴图区域拼接的位置由上偏移、下偏移、左偏移、右偏移的值决定。如果需要将已有图片作为输出图片,用户需在申请输出内存后,将已有图片读入输出内存,代码示例请参考示例5:叠加。
void NewVpcTest3() { uint32_t inWidthStride = 1920; uint32_t inHeightStride = 1080; uint32_t outWidthStride = 1280; uint32_t outHeightStride = 720; uint32_t inBufferSize = inWidthStride * inHeightStride * 3 / 2; // 1080P yuv420sp Image uint32_t outBufferSize = outWidthStride * outHeightStride * 3 / 2; // 720P yuv420sp Image uint8_t* inBuffer = static_cast<uint8_t*>(HIAI_DVPP_DMalloc(inBufferSize)); // Construct an input picture. if (inBuffer == nullptr) { HIAI_ENGINE_LOG(HIAI_VPC_CTL_ERROR, "can not alloc input buffer"); return; } FILE* fp = fopen("dvpp_vpc_1920x1080_nv12.yuv", "rb+"); if (fp == nullptr) { HIAI_ENGINE_LOG(HIAI_ERROR, "fopen file failed"); HIAI_DVPP_DFree(inBuffer); inBuffer = nullptr; return; } fread(inBuffer, 1, inBufferSize, fp); fclose(fp); fp == nullptr; // Construct the input picture configuration. std::shared_ptr<VpcUserImageConfigure> imageConfigure(new VpcUserImageConfigure); imageConfigure->bareDataAddr = inBuffer; imageConfigure->bareDataBufferSize = inBufferSize; imageConfigure->widthStride = inWidthStride; imageConfigure->heightStride = inHeightStride; imageConfigure->inputFormat = INPUT_YUV420_SEMI_PLANNER_UV; imageConfigure->outputFormat = OUTPUT_YUV420SP_UV; imageConfigure->yuvSumEnable = false; imageConfigure->cmdListBufferAddr = nullptr; imageConfigure->cmdListBufferSize = 0; std::shared_ptr<VpcUserRoiConfigure> lastRoi; std::vector<std::shared_ptr<VpcUserRoiConfigure>> roiVector; for (uint32_t i = 0; i < 5; i++) { std::shared_ptr<VpcUserRoiConfigure> roiConfigure(new VpcUserRoiConfigure); roiVector.push_back(roiConfigure); roiConfigure->next = nullptr; VpcUserRoiInputConfigure* inputConfigure = &roiConfigure->inputConfigure; // Set the drawing area. inputConfigure->cropArea.leftOffset = 100 + i * 16; inputConfigure->cropArea.rightOffset = 499 + i * 16; inputConfigure->cropArea.upOffset = 100 + i * 16; inputConfigure->cropArea.downOffset = 499 + i * 16; VpcUserRoiOutputConfigure* outputConfigure = &roiConfigure->outputConfigure; uint8_t* outBuffer = static_cast<uint8_t*>(HIAI_DVPP_DMalloc(outBufferSize)); // Construct an input picture if (outBuffer == nullptr) { HIAI_ENGINE_LOG(HIAI_VPC_CTL_ERROR, "can not alloc output buffer"); HIAI_DVPP_DFree(inBuffer); inBuffer = nullptr; FreeMultipleRio(imageConfigure->roiConfigure); return; } (void)memset_s(outBuffer, outBufferSize, 0x80, outBufferSize); outputConfigure->addr = outBuffer; outputConfigure->bufferSize = outBufferSize; outputConfigure->widthStride = outWidthStride; outputConfigure->heightStride = outHeightStride; // Set the map area. outputConfigure->outputArea.leftOffset = 256 + i * 16; // The offset value must be 16-pixel-aligned. outputConfigure->outputArea.rightOffset = 399 + i * 16; outputConfigure->outputArea.upOffset = 256 + i * 16; outputConfigure->outputArea.downOffset = 399 + i * 16; if (i == 0) { imageConfigure->roiConfigure = roiConfigure.get(); lastRoi = roiConfigure; } else { lastRoi->next = roiConfigure.get(); lastRoi = roiConfigure; } } IDVPPAPI *pidvppapi = nullptr; int32_t ret = CreateDvppApi(pidvppapi); if (ret != 0) { HIAI_ENGINE_LOG(HIAI_CREATE_DVPP_ERROR, "create dvpp api fail."); HIAI_DVPP_DFree(inBuffer); inBuffer = nullptr; FreeMultipleRio(imageConfigure->roiConfigure); return; } dvppapi_ctl_msg dvppApiCtlMsg; dvppApiCtlMsg.in = static_cast<void*>(imageConfigure.get()); dvppApiCtlMsg.in_size = sizeof(VpcUserImageConfigure); ret = DvppCtl(pidvppapi, DVPP_CTL_VPC_PROC, &dvppApiCtlMsg); if (ret != 0) { HIAI_ENGINE_LOG(HIAI_VPC_CTL_ERROR, "call vpc dvppctl process faild!"); ret = DestroyDvppApi(pidvppapi); HIAI_DVPP_DFree(inBuffer); inBuffer = nullptr; FreeMultipleRio(imageConfigure->roiConfigure); return; } else { HIAI_ENGINE_LOG(HIAI_OK, "NewVpcTest3::call vpc dvppctl process success!"); } FILE* outImageFp = nullptr; uint32_t imageCount = 0; char fileName[50] = {0}; while (imageConfigure->roiConfigure != nullptr) { int32_t safeFuncRet = sprintf_s(fileName, sizeof(fileName), "NewVpcTest3_%dOut.yuv", imageCount); if (safeFuncRet == -1) { HIAI_ENGINE_LOG(HIAI_ERROR, "sprintf_s fail, ret = %d", safeFuncRet); DestroyDvppApi(pidvppapi); HIAI_DVPP_DFree(inBuffer); inBuffer = nullptr; FreeMultipleRio(imageConfigure->roiConfigure); return; } outImageFp = fopen(fileName, "wb+"); if (outImageFp == nullptr) { HIAI_ENGINE_LOG(HIAI_ERROR, "open %s faild!", fileName); DestroyDvppApi(pidvppapi); HIAI_DVPP_DFree(inBuffer); inBuffer = nullptr; FreeMultipleRio(imageConfigure->roiConfigure); return; } fwrite(imageConfigure->roiConfigure->outputConfigure.addr, 1, imageConfigure->roiConfigure->outputConfigure.bufferSize, outImageFp); fclose(outImageFp); outImageFp = nullptr; imageConfigure->roiConfigure = imageConfigure->roiConfigure->next; imageCount++; } ret = DestroyDvppApi(pidvppapi); HIAI_DVPP_DFree(inBuffer); inBuffer = nullptr; FreeMultipleRio(imageConfigure->roiConfigure); return; }
示例4,8K缩放功能
对于8K缩放功能,支持缩放、支持YUV420SP NV12与YUV420SP NV21之间的格式转换、不支持抠图。
示例代码:本示例是将yuv420sp格式的图片从8129*8192缩放至4000*4000。
void NewVpcTest4() { uint32_t inWidthStride = 8192; // No need for 128 byte alignment uint32_t inHeightStride = 8192; // No need for 16 byte alignment uint32_t outWidthStride = 4000; // No need for 128 byte alignment uint32_t outHeightStride = 4000; // No need for 16 byte alignment uint32_t inBufferSize = inWidthStride * inHeightStride * 3 / 2; uint32_t outBufferSize = outWidthStride * outHeightStride * 3 / 2; // Construct dummy data uint8_t* inBuffer = (uint8_t*)HIAI_DVPP_DMalloc(inBufferSize); // Construct input image if (inBuffer == nullptr) { HIAI_ENGINE_LOG(HIAI_VPC_CTL_ERROR, "can not alloc roiOutput buffer"); return; } uint8_t* outBuffer = (uint8_t*)HIAI_DVPP_DMalloc(outBufferSize); // Construct output image if (outBuffer == nullptr) { HIAI_ENGINE_LOG(HIAI_VPC_CTL_ERROR, "can not alloc roiOutput buffer"); HIAI_DVPP_DFree(inBuffer); inBuffer = nullptr; return; } FILE* fp = fopen("dvpp_vpc_8192x8192_nv12.yuv", "rb+"); if (fp == nullptr) { HIAI_ENGINE_LOG(HIAI_ERROR, "fopen file failed"); DFreeInOutBuffer(inBuffer, outBuffer); return; } fread(inBuffer, 1, inBufferSize, fp); fclose(fp); fp = nullptr; std::shared_ptr<VpcUserImageConfigure> imageConfigure(new VpcUserImageConfigure); imageConfigure->bareDataAddr = inBuffer; imageConfigure->bareDataBufferSize = inBufferSize; imageConfigure->isCompressData = false; imageConfigure->widthStride = inWidthStride; imageConfigure->heightStride = inHeightStride; imageConfigure->inputFormat = INPUT_YUV420_SEMI_PLANNER_UV; imageConfigure->outputFormat = OUTPUT_YUV420SP_UV; imageConfigure->yuvSumEnable = false; imageConfigure->cmdListBufferAddr = nullptr; imageConfigure->cmdListBufferSize = 0; std::shared_ptr<VpcUserRoiConfigure> roiConfigure(new VpcUserRoiConfigure); roiConfigure->next = nullptr; VpcUserRoiInputConfigure* inputConfigure = &roiConfigure->inputConfigure; // Set the roi area inputConfigure->cropArea.leftOffset = 0; inputConfigure->cropArea.rightOffset = inWidthStride - 1; inputConfigure->cropArea.upOffset = 0; inputConfigure->cropArea.downOffset = inHeightStride - 1; VpcUserRoiOutputConfigure* outputConfigure = &roiConfigure->outputConfigure; outputConfigure->addr = outBuffer; outputConfigure->bufferSize = outBufferSize; outputConfigure->widthStride = outWidthStride; outputConfigure->heightStride = outHeightStride; // Set the map area outputConfigure->outputArea.leftOffset = 0; outputConfigure->outputArea.rightOffset = outWidthStride - 1; outputConfigure->outputArea.upOffset = 0; outputConfigure->outputArea.downOffset = outHeightStride - 1; imageConfigure->roiConfigure = roiConfigure.get(); IDVPPAPI *pidvppapi = nullptr; int32_t ret = CreateDvppApi(pidvppapi); if (ret != 0) { HIAI_ENGINE_LOG(HIAI_CREATE_DVPP_ERROR, "create dvpp api fail."); DFreeInOutBuffer(inBuffer, outBuffer); return; } dvppapi_ctl_msg dvppApiCtlMsg; dvppApiCtlMsg.in = static_cast<void*>(imageConfigure.get()); dvppApiCtlMsg.in_size = sizeof(VpcUserImageConfigure); ret = DvppCtl(pidvppapi, DVPP_CTL_VPC_PROC, &dvppApiCtlMsg); if (ret != 0) { HIAI_ENGINE_LOG(HIAI_VPC_CTL_ERROR, "call vpc dvppctl process faild!"); ret = DestroyDvppApi(pidvppapi); DFreeInOutBuffer(inBuffer, outBuffer); return; } else { HIAI_ENGINE_LOG(HIAI_OK, "NewVpcTest4::call vpc dvppctl process success!"); } FILE* outImageFp = fopen("NewVpcTest4Out.yuv", "wb+"); if (outImageFp == nullptr) { HIAI_ENGINE_LOG(HIAI_VPC_CTL_ERROR, "open NewVpcTest4Out.yuv faild!"); ret = DestroyDvppApi(pidvppapi); DFreeInOutBuffer(inBuffer, outBuffer); return; } fwrite(outBuffer, 1, outBufferSize, outImageFp); fclose(outImageFp); outImageFp = nullptr; ret = DestroyDvppApi(pidvppapi); DFreeInOutBuffer(inBuffer, outBuffer); return; }
示例5:叠加
FILE* fpOut = fopen("vpcOut.yuv", "rb+"); if (fpOut == nullptr) { HIAI_ENGINE_LOG(HIAI_ERROR, "fopen file failed."); fclose(fpOut); return; } fread(outBuffer, 1, outBufferSize, fpOut); fclose(fpOut);