// Copyright 2016 Adrien Descamps // Distributed under BSD 3-Clause License // This program demonstrate how to convert a YUV420p image (raw format) to RGB (ppm format), and the reverse operation #include "yuv_rgb.h" #include #include #include #include #include #include #if USE_FFMPEG #include #endif #if USE_IPP #include #endif // read a raw yuv image file // raw yuv files can be generated by ffmpeg, for example, using : // ffmpeg -i test.png -c:v rawvideo -pix_fmt yuv420p test.yuv // the returned image channels are contiguous, and Y stride=width, U and V stride=width/2 // memory must be freed with free int readRawYUV(const char *filename, uint32_t width, uint32_t height, uint8_t **YUV) { FILE *fp = fopen(filename, "rb"); if(!fp) { perror("Error opening yuv image for read"); return 1; } // check file size fseek(fp, 0, SEEK_END); uint32_t size = ftell(fp); if(size!=(width*height + 2*((width+1)/2)*((height+1)/2))) { fprintf(stderr, "Wrong size of yuv image : %d bytes, expected %d bytes\n", size, (width*height + 2*((width+1)/2)*((height+1)/2))); fclose(fp); return 2; } fseek(fp, 0, SEEK_SET); *YUV = malloc(size); size_t result = fread(*YUV, 1, size, fp); if (result != size) { perror("Error reading yuv image"); fclose(fp); return 3; } fclose(fp); return 0; } // write a raw yuv image file int saveRawYUV(const char *filename, uint32_t width, uint32_t height, const uint8_t *YUV, size_t y_stride, size_t uv_stride) { FILE *fp = fopen(filename, "wb"); if(!fp) { perror("Error opening yuv image for write"); return 1; } if(y_stride==width) { fwrite(YUV, 1, width*height, fp); YUV+=width*height; } else { for(uint32_t y=0; y255) { perror("Error reading rgb image header, or invalid values"); fclose(fp); return 3; } size_t size = 3*(*width)*(*height); *RGB = malloc(size); if(!*RGB) { perror("Error allocating rgb image memory"); fclose(fp); return 2; } result = fread(*RGB, 1, size, fp); if(result != size) { perror("Error reading rgb image"); fclose(fp); return 3; } fclose(fp); return 0; } // save a rgb image to ppm binary format int savePPM(const char* filename, uint32_t width, uint32_t height, const uint8_t *RGB, size_t stride) { FILE *fp = fopen(filename, "wb"); if(!fp) { perror("Error opening rgb image for write"); return 1; } fprintf(fp, "P6 %u %u 255\n", width, height); if(stride==(3*width)) { fwrite(RGB, 1, 3*width*height, fp); } else { for(uint32_t i=0; i \n"); printf("Or : test yuv2rgb_nv12 \n"); printf("Or : test yuv2rgb_nv21 \n"); printf("Or : test rgb2yuv \n"); printf("Or : test rgba2yuv \n"); return 1; } const int iteration_number = 100; printf("Time will be measured in each configuration for %d iterations...\n", iteration_number); const YCbCrType yuv_format = YCBCR_601; //const YCbCrType yuv_format = YCBCR_709; //const YCbCrType yuv_format = YCBCR_JPEG; Mode mode; if(strcmp(argv[1], "yuv2rgb")==0) { mode=YUV2RGB; if(argc<6) { printf("Invalid argument number for yuv2rgb mode, call without argument to see usage.\n"); return 1; } } else if(strcmp(argv[1], "yuv2rgb_nv12")==0) { mode=YUV2RGB_NV12; } else if(strcmp(argv[1], "yuv2rgb_nv21")==0) { mode=YUV2RGB_NV21; } else if(strcmp(argv[1], "rgb2yuv")==0) { mode=RGB2YUV; } else if(strcmp(argv[1], "rgba2yuv")==0) { mode=RGBA2YUV; } else { printf("Invalid mode, call without argument to see usage.\n"); return 1; } const char *filename = argv[2]; uint32_t width, height; const char *out; uint8_t *YUV=NULL, *RGB=NULL, *Y=NULL, *U=NULL, *V=NULL, *RGBa=NULL, *YUVa=NULL, *Ya=NULL, *Ua=NULL, *Va=NULL; if(mode==YUV2RGB || mode==YUV2RGB_NV12 || mode==YUV2RGB_NV21) { //parse argument line width = atoi(argv[3]); height = atoi(argv[4]); out = argv[5]; // read input data and allocate output data if(readRawYUV(filename, width, height, &YUV)!=0) { printf("Error reading image file, check that the file exists and has the correct format and resolution.\n"); return 1; } #if USE_FFMPEG yuv2rgb_swscale_ctx = sws_getContext(width, height, AV_PIX_FMT_YUV420P, width, height, AV_PIX_FMT_RGB24, 0, 0, 0, 0); #endif RGB = malloc(3*width*height); Y = YUV; U = YUV+width*height; V = YUV+width*height+((width+1)/2)*((height+1)/2); // allocate aligned data const size_t y_stride = width + (16-width%16)%16; const size_t uv_stride = (mode==YUV2RGB) ? (width+1)/2 + (16-((width+1)/2)%16)%16 : y_stride; const size_t rgb_stride = width*3 +(16-(3*width)%16)%16; const size_t y_size = y_stride*height, uv_size = uv_stride*((height+1)/2); YUVa = _mm_malloc(y_size+2*uv_size, 16); Ya = YUVa; Ua = YUVa+y_size; Va = YUVa+y_size+uv_size; for(unsigned int i=0; i