X-Git-Url: https://git.carlh.net/gitweb/?a=blobdiff_plain;f=src%2Fbin%2Fjp2%2Fopj_compress.c;h=8ba3b6d772e093d8c2e7618e4a6f8509fff98907;hb=c06632c6f6d0a3e106374fe462869b131366c2d0;hp=cd3953e99d63df69ca0e1e50444c99483629fd57;hpb=563ecfb55ca77c0fc5ea19e4885e00f55ec82ca9;p=openjpeg.git diff --git a/src/bin/jp2/opj_compress.c b/src/bin/jp2/opj_compress.c index cd3953e9..8ba3b6d7 100644 --- a/src/bin/jp2/opj_compress.c +++ b/src/bin/jp2/opj_compress.c @@ -44,6 +44,7 @@ #include #include #include +#include #ifdef _WIN32 #include "windirent.h" @@ -141,7 +142,7 @@ static void encode_help_display(void) fprintf(stdout, "-i \n"); fprintf(stdout, " Input file\n"); fprintf(stdout, - " Known extensions are \n"); + " Known extensions are \n"); fprintf(stdout, " If used, '-o ' must be provided\n"); fprintf(stdout, "-o \n"); fprintf(stdout, " Output file (accepted extensions are j2k or jp2).\n"); @@ -153,12 +154,12 @@ static void encode_help_display(void) fprintf(stdout, " Required only if -ImgDir is used\n"); fprintf(stdout, "-F ,,,,{s,u}@x:...:x\n"); - fprintf(stdout, " Characteristics of the raw input image\n"); + fprintf(stdout, " Characteristics of the raw or yuv input image\n"); fprintf(stdout, " If subsampling is omitted, 1x1 is assumed for all components\n"); - fprintf(stdout, " Example: -F 512,512,3,8,u@1x1:2x2:2x2\n"); + fprintf(stdout, " Example: -F 512,512,3,8,u@1x1:2x2:2x2\n"); fprintf(stdout, - " for raw 512x512 image with 4:2:0 subsampling\n"); + " for raw or yuv 512x512 size with 4:2:0 subsampling\n"); fprintf(stdout, " Required only if RAW or RAWL input file is provided.\n"); fprintf(stdout, "\n"); fprintf(stdout, "Optional Parameters:\n"); @@ -186,6 +187,11 @@ static void encode_help_display(void) fprintf(stdout, " It corresponds to the number of DWT decompositions +1. \n"); fprintf(stdout, " Default: 6.\n"); + fprintf(stdout, "-TargetBitDepth \n"); + fprintf(stdout, " Target bit depth.\n"); + fprintf(stdout, " Number of bits per component to use from input image\n"); + fprintf(stdout, " if all bits are unwanted.\n"); + fprintf(stdout, " (Currently only implemented for TIF.)\n"); fprintf(stdout, "-b ,\n"); fprintf(stdout, " Code-block size. The dimension must respect the constraint \n"); @@ -229,6 +235,10 @@ static void encode_help_display(void) fprintf(stdout, " Write SOP marker before each packet.\n"); fprintf(stdout, "-EPH\n"); fprintf(stdout, " Write EPH marker after each header packet.\n"); + fprintf(stdout, "-PLT\n"); + fprintf(stdout, " Write PLT marker in tile-part header.\n"); + fprintf(stdout, "-TLM\n"); + fprintf(stdout, " Write TLM marker in main header.\n"); fprintf(stdout, "-M \n"); fprintf(stdout, " Mode switch.\n"); fprintf(stdout, " [1=BYPASS(LAZY) 2=RESET 4=RESTART(TERMALL)\n"); @@ -294,11 +304,18 @@ static void encode_help_display(void) fprintf(stdout, " Y >= 0 and Y <= 9.\n"); fprintf(stdout, " framerate > 0 may be specified to enhance checks and set maximum bit rate when Y > 0.\n"); + fprintf(stdout, "-GuardBits value\n"); + fprintf(stdout, + " Number of guard bits in [0,7] range. Usually 1 or 2 (default value).\n"); fprintf(stdout, "-jpip\n"); fprintf(stdout, " Write jpip codestream index box in JP2 output file.\n"); fprintf(stdout, " Currently supports only RPCL order.\n"); fprintf(stdout, "-C \n"); fprintf(stdout, " Add in the comment marker segment.\n"); + if (opj_has_thread_support()) { + fprintf(stdout, "-threads \n" + " Number of threads to use for encoding or ALL_CPUS for all available cores.\n"); + } /* UniPG>> */ #ifdef USE_JPWL fprintf(stdout, "-W \n"); @@ -320,7 +337,7 @@ static void encode_help_display(void) JPWL_MAX_NO_TILESPECS); fprintf(stdout, " p selects the packet error protection (EEP/UEP with EPBs)\n"); - fprintf(stdout, " to be applied to raw data: 'type' can be\n"); + fprintf(stdout, " to be applied to raw or yuv data: 'type' can be\n"); fprintf(stdout, " [0=none 1,absent=predefined 16=CRC-16 32=CRC-32 37-128=RS]\n"); fprintf(stdout, @@ -472,6 +489,11 @@ static unsigned int get_num_images(char *imgdirpath) if (strcmp(".", content->d_name) == 0 || strcmp("..", content->d_name) == 0) { continue; } + if (num_images == UINT_MAX) { + fprintf(stderr, "Too many files in folder %s\n", imgdirpath); + num_images = 0; + break; + } num_images++; } closedir(dir); @@ -510,10 +532,10 @@ static int get_file_format(char *filename) { unsigned int i; static const char *extension[] = { - "pgx", "pnm", "pgm", "ppm", "pbm", "pam", "bmp", "tif", "raw", "rawl", "tga", "png", "j2k", "jp2", "j2c", "jpc" + "pgx", "pnm", "pgm", "ppm", "pbm", "pam", "bmp", "tif", "tiff", "raw", "yuv", "rawl", "tga", "png", "j2k", "jp2", "j2c", "jpc" }; static const int format[] = { - PGX_DFMT, PXM_DFMT, PXM_DFMT, PXM_DFMT, PXM_DFMT, PXM_DFMT, BMP_DFMT, TIF_DFMT, RAW_DFMT, RAWL_DFMT, TGA_DFMT, PNG_DFMT, J2K_CFMT, JP2_CFMT, J2K_CFMT, J2K_CFMT + PGX_DFMT, PXM_DFMT, PXM_DFMT, PXM_DFMT, PXM_DFMT, PXM_DFMT, BMP_DFMT, TIF_DFMT, TIF_DFMT, RAW_DFMT, RAW_DFMT, RAWL_DFMT, TGA_DFMT, PNG_DFMT, J2K_CFMT, JP2_CFMT, J2K_CFMT, J2K_CFMT }; char * ext = strrchr(filename, '.'); if (ext == NULL) { @@ -534,7 +556,8 @@ static char * get_file_name(char *name) return fname; } -static char get_next_file(int imageno, dircnt_t *dirptr, img_fol_t *img_fol, +static char get_next_file(unsigned int imageno, dircnt_t *dirptr, + img_fol_t *img_fol, opj_cparameters_t *parameters) { char image_filename[OPJ_PATH_LEN], infilename[OPJ_PATH_LEN], @@ -542,12 +565,18 @@ static char get_next_file(int imageno, dircnt_t *dirptr, img_fol_t *img_fol, char *temp_p, temp1[OPJ_PATH_LEN] = ""; strcpy(image_filename, dirptr->filename[imageno]); - fprintf(stderr, "File Number %d \"%s\"\n", imageno, image_filename); + fprintf(stderr, "File Number %u \"%s\"\n", imageno, image_filename); parameters->decod_format = get_file_format(image_filename); if (parameters->decod_format == -1) { return 1; } - sprintf(infilename, "%s/%s", img_fol->imgdirpath, image_filename); + if (strlen(img_fol->imgdirpath) + 1 + strlen(image_filename) + 1 > sizeof( + infilename)) { + return 1; + } + strcpy(infilename, img_fol->imgdirpath); + strcat(infilename, "/"); + strcat(infilename, image_filename); if (opj_strcpy_s(parameters->infile, sizeof(parameters->infile), infilename) != 0) { return 1; @@ -560,8 +589,15 @@ static char get_next_file(int imageno, dircnt_t *dirptr, img_fol_t *img_fol, sprintf(temp1, ".%s", temp_p); } if (img_fol->set_out_format == 1) { - sprintf(outfilename, "%s/%s.%s", img_fol->imgdirpath, temp_ofname, - img_fol->out_format); + if (strlen(img_fol->imgdirpath) + 1 + strlen(temp_ofname) + 1 + strlen( + img_fol->out_format) + 1 > sizeof(outfilename)) { + return 1; + } + strcpy(outfilename, img_fol->imgdirpath); + strcat(outfilename, "/"); + strcat(outfilename, temp_ofname); + strcat(outfilename, "."); + strcat(outfilename, img_fol->out_format); if (opj_strcpy_s(parameters->outfile, sizeof(parameters->outfile), outfilename) != 0) { return 1; @@ -576,7 +612,12 @@ static int parse_cmdline_encoder(int argc, char **argv, opj_cparameters_t *parameters, img_fol_t *img_fol, raw_cparameters_t *raw_cp, char *indexfilename, size_t indexfilename_size, - int* pOutFramerate) + int* pOutFramerate, + OPJ_BOOL* pOutPLT, + OPJ_BOOL* pOutTLM, + int* pOutGuardBits, + int* pOutNumThreads, + unsigned int* pTarget_bitdepth) { OPJ_UINT32 i, j; int totlen, c; @@ -592,11 +633,16 @@ static int parse_cmdline_encoder(int argc, char **argv, {"ROI", REQ_ARG, NULL, 'R'}, {"jpip", NO_ARG, NULL, 'J'}, {"mct", REQ_ARG, NULL, 'Y'}, - {"IMF", REQ_ARG, NULL, 'Z'} + {"IMF", REQ_ARG, NULL, 'Z'}, + {"PLT", NO_ARG, NULL, 'A'}, + {"threads", REQ_ARG, NULL, 'B'}, + {"TLM", NO_ARG, NULL, 'D'}, + {"TargetBitDepth", REQ_ARG, NULL, 'X'}, + {"GuardBits", REQ_ARG, NULL, 'G'} }; /* parse the command line */ - const char optlist[] = "i:o:r:q:n:b:c:t:p:s:SEM:x:R:d:T:If:P:C:F:u:JY:" + const char optlist[] = "i:o:r:q:n:b:c:t:p:s:SEM:x:R:d:T:If:P:C:F:u:JY:X:G:" #ifdef USE_JPWL "W:" #endif /* USE_JPWL */ @@ -628,7 +674,7 @@ static int parse_cmdline_encoder(int argc, char **argv, default: fprintf(stderr, "[ERROR] Unknown input file format: %s \n" - " Known file formats are *.pnm, *.pgm, *.ppm, *.pgx, *png, *.bmp, *.tif, *.raw or *.tga\n", + " Known file formats are *.pnm, *.pgm, *.ppm, *.pgx, *png, *.bmp, *.tif(f), *.raw, *.yuv or *.tga\n", infile); return 1; } @@ -782,7 +828,7 @@ static int parse_cmdline_encoder(int argc, char **argv, } free(substr1); if (wrong) { - fprintf(stderr, "\nError: invalid raw image parameters\n"); + fprintf(stderr, "\nError: invalid raw or yuv image parameters\n"); fprintf(stderr, "Please use the Format option -F:\n"); fprintf(stderr, "-F ,,,,{s,u}@x:...:x\n"); @@ -790,7 +836,8 @@ static int parse_cmdline_encoder(int argc, char **argv, "If subsampling is omitted, 1x1 is assumed for all components\n"); fprintf(stderr, "Example: -i image.raw -o image.j2k -F 512,512,3,8,u@1x1:2x2:2x2\n"); - fprintf(stderr, " for raw 512x512 image with 4:2:0 subsampling\n"); + fprintf(stderr, + " for raw or yuv 512x512 size with 4:2:0 subsampling\n"); fprintf(stderr, "Aborting.\n"); return 1; } @@ -799,7 +846,7 @@ static int parse_cmdline_encoder(int argc, char **argv, /* ----------------------------------------------------- */ - case 'q': { /* add fixed_quality */ + case 'q': { /* layer allocation by distortion ratio (PSNR) */ char *s = opj_optarg; while (sscanf(s, "%f", ¶meters->tcp_distoratio[parameters->tcp_numlayers]) == 1) { @@ -819,7 +866,7 @@ static int parse_cmdline_encoder(int argc, char **argv, /* dda */ /* ----------------------------------------------------- */ - case 'f': { /* mod fixed_quality (before : -q) */ + case 'f': { /* layer allocation by fixed layer */ int *row = NULL, *col = NULL; OPJ_UINT32 numlayers = 0, numresolution = 0, matrix_width = 0; @@ -880,6 +927,24 @@ static int parse_cmdline_encoder(int argc, char **argv, } break; + /* ----------------------------------------------------- */ + case 'X': { /* target bitdepth */ + char *s = opj_optarg; + sscanf(s, "%u", pTarget_bitdepth); + if (*pTarget_bitdepth == 0) { + fprintf(stderr, "Target bitdepth must be at least 1 bit.\n"); + return 1; + } + } + break; + + /* ----------------------------------------------------- */ + case 'G': { /* guard bits */ + char *s = opj_optarg; + sscanf(s, "%d", pOutGuardBits); + } + break; + /* ----------------------------------------------------- */ case 'n': { /* resolution */ @@ -947,9 +1012,10 @@ static int parse_cmdline_encoder(int argc, char **argv, /* ----------------------------------------------------- */ case 'p': { /* progression order */ - char progression[4]; + char progression[5]; strncpy(progression, opj_optarg, 4); + progression[4] = 0; parameters->prog_order = give_progression(progression); if (parameters->prog_order == -1) { fprintf(stderr, "Unrecognized progression order " @@ -1670,6 +1736,32 @@ static int parse_cmdline_encoder(int argc, char **argv, break; /* ------------------------------------------------------ */ + case 'A': { /* PLT markers */ + *pOutPLT = OPJ_TRUE; + } + break; + + /* ----------------------------------------------------- */ + case 'B': { /* Number of threads */ + if (strcmp(opj_optarg, "ALL_CPUS") == 0) { + *pOutNumThreads = opj_get_num_cpus(); + if (*pOutNumThreads == 1) { + *pOutNumThreads = 0; + } + } else { + sscanf(opj_optarg, "%d", pOutNumThreads); + } + } + break; + /* ------------------------------------------------------ */ + + case 'D': { /* TLM markers */ + *pOutTLM = OPJ_TRUE; + } + break; + + /* ------------------------------------------------------ */ + default: fprintf(stderr, "[WARNING] An invalid option has been ignored\n"); @@ -1702,9 +1794,10 @@ static int parse_cmdline_encoder(int argc, char **argv, } } - if ((parameters->decod_format == RAW_DFMT && raw_cp->rawWidth == 0) - || (parameters->decod_format == RAWL_DFMT && raw_cp->rawWidth == 0)) { - fprintf(stderr, "[ERROR] invalid raw image parameters\n"); + if ((parameters->decod_format == RAW_DFMT || + parameters->decod_format == RAWL_DFMT) + && (raw_cp->rawWidth == 0)) { + fprintf(stderr, "[ERROR] invalid raw or yuv image parameters\n"); fprintf(stderr, "Please use the Format option -F:\n"); fprintf(stderr, "-F rawWidth,rawHeight,rawComp,rawBitDepth,s/u (Signed/Unsigned)\n"); @@ -1719,7 +1812,7 @@ static int parse_cmdline_encoder(int argc, char **argv, parameters->cp_fixed_quality))) { fprintf(stderr, "[ERROR] options -r -q and -f cannot be used together !!\n"); return 1; - } /* mod fixed_quality */ + } /* if no rate entered, lossless by default */ @@ -1848,6 +1941,14 @@ int main(int argc, char **argv) int framerate = 0; OPJ_FLOAT64 t = opj_clock(); + OPJ_BOOL PLT = OPJ_FALSE; + OPJ_BOOL TLM = OPJ_FALSE; + int num_threads = 0; + int guard_bits = -1; + + /** desired bitdepth from input file */ + unsigned int target_bitdepth = 0; + /* set encoding parameters to default values */ opj_set_default_encoder_parameters(¶meters); @@ -1867,7 +1968,8 @@ int main(int argc, char **argv) parameters.tcp_mct = (char) 255; /* This will be set later according to the input image or the provided option */ if (parse_cmdline_encoder(argc, argv, ¶meters, &img_fol, &raw_cp, - indexfilename, sizeof(indexfilename), &framerate) == 1) { + indexfilename, sizeof(indexfilename), &framerate, &PLT, &TLM, + &guard_bits, &num_threads, &target_bitdepth) == 1) { ret = 1; goto fin; } @@ -1875,28 +1977,29 @@ int main(int argc, char **argv) /* Read directory if necessary */ if (img_fol.set_imgdir == 1) { num_images = get_num_images(img_fol.imgdirpath); + if (num_images == 0) { + fprintf(stdout, "Folder is empty\n"); + ret = 0; + goto fin; + } dirptr = (dircnt_t*)malloc(sizeof(dircnt_t)); if (dirptr) { - dirptr->filename_buf = (char*)malloc(num_images * OPJ_PATH_LEN * sizeof( + dirptr->filename_buf = (char*)calloc(num_images, OPJ_PATH_LEN * sizeof( char)); /* Stores at max 10 image file names*/ - dirptr->filename = (char**) malloc(num_images * sizeof(char*)); + dirptr->filename = (char**) calloc(num_images, sizeof(char*)); if (!dirptr->filename_buf) { ret = 0; goto fin; } for (i = 0; i < num_images; i++) { - dirptr->filename[i] = dirptr->filename_buf + i * OPJ_PATH_LEN; + dirptr->filename[i] = dirptr->filename_buf + (size_t)i * OPJ_PATH_LEN; } } if (load_images(dirptr, img_fol.imgdirpath) == 1) { ret = 0; goto fin; } - if (num_images == 0) { - fprintf(stdout, "Folder is empty\n"); - ret = 0; - goto fin; - } + } else { num_images = 1; } @@ -1906,7 +2009,7 @@ int main(int argc, char **argv) fprintf(stderr, "\n"); if (img_fol.set_imgdir == 1) { - if (get_next_file((int)imageno, dirptr, &img_fol, ¶meters)) { + if (get_next_file(imageno, dirptr, &img_fol, ¶meters)) { fprintf(stderr, "skipping file...\n"); continue; } @@ -1914,18 +2017,12 @@ int main(int argc, char **argv) switch (parameters.decod_format) { case PGX_DFMT: - break; case PXM_DFMT: - break; case BMP_DFMT: - break; case TIF_DFMT: - break; case RAW_DFMT: case RAWL_DFMT: - break; case TGA_DFMT: - break; case PNG_DFMT: break; default: @@ -1966,9 +2063,9 @@ int main(int argc, char **argv) #ifdef OPJ_HAVE_LIBTIFF case TIF_DFMT: - image = tiftoimage(parameters.infile, ¶meters); + image = tiftoimage(parameters.infile, ¶meters, target_bitdepth); if (!image) { - fprintf(stderr, "Unable to load tiff file\n"); + fprintf(stderr, "Unable to load tif(f) file\n"); ret = 1; goto fin; } @@ -1978,7 +2075,7 @@ int main(int argc, char **argv) case RAW_DFMT: image = rawtoimage(parameters.infile, ¶meters, &raw_cp); if (!image) { - fprintf(stderr, "Unable to load raw file\n"); + fprintf(stderr, "Unable to load raw or yuv file\n"); ret = 1; goto fin; } @@ -2014,7 +2111,7 @@ int main(int argc, char **argv) #endif /* OPJ_HAVE_LIBPNG */ } - /* Can happen if input file is TIFF or PNG + /* Can happen if input file is TIF(F) or PNG * and OPJ_HAVE_LIBTIF or OPJ_HAVE_LIBPNG is undefined */ if (!image) { @@ -2117,6 +2214,38 @@ int main(int argc, char **argv) goto fin; } + { + const char* options[4] = { NULL, NULL, NULL, NULL }; + int iOpt = 0; + char szGuardBits[32]; + if (PLT) { + options[iOpt++] = "PLT=YES"; + } + if (TLM) { + options[iOpt++] = "TLM=YES"; + } + if (guard_bits >= 0) { + sprintf(szGuardBits, "GUARD_BITS=%d", guard_bits); + options[iOpt++] = szGuardBits; + } + if (iOpt > 0 && !opj_encoder_set_extra_options(l_codec, options)) { + fprintf(stderr, "failed to encode image: opj_encoder_set_extra_options\n"); + opj_destroy_codec(l_codec); + opj_image_destroy(image); + ret = 1; + goto fin; + } + } + + if (num_threads >= 1 && + !opj_codec_set_threads(l_codec, num_threads)) { + fprintf(stderr, "failed to set number of threads\n"); + opj_destroy_codec(l_codec); + opj_image_destroy(image); + ret = 1; + goto fin; + } + /* open a byte stream for writing and allocate memory for all tiles */ l_stream = opj_stream_create_default_file_stream(parameters.outfile, OPJ_FALSE); if (! l_stream) { @@ -2139,7 +2268,7 @@ int main(int argc, char **argv) } for (i = 0; i < l_nb_tiles; ++i) { if (! opj_write_tile(l_codec, i, l_data, l_data_size, l_stream)) { - fprintf(stderr, "ERROR -> test_tile_encoder: failed to write the tile %d!\n", + fprintf(stderr, "ERROR -> test_tile_encoder: failed to write the tile %u!\n", i); opj_stream_destroy(l_stream); opj_destroy_codec(l_codec);