From 90725df206ce806573611c4f2b506234a055646f Mon Sep 17 00:00:00 2001 From: Antonin Descampe Date: Sun, 23 Jan 2011 18:33:06 +0000 Subject: [PATCH] MJ2 module: Add two components to mj2.h: meth, enumcs ; Define or reset all components of mj2_cparameters_t before its usage ; Add argument -D prec to frames_to_mj2.c and use the precision in mj2_convert.c (solves Issue 49) --- CHANGES | 4 + mj2/extract_j2k_from_mj2.c | 3 +- mj2/frames_to_mj2.c | 352 ++++++++++++++++++++----------------- mj2/mj2.c | 49 ++++-- mj2/mj2.h | 2 + mj2/mj2_convert.c | 39 ++-- mj2/mj2_to_frames.c | 3 +- mj2/wrap_j2k_in_mj2.c | 157 ++++++++++++++++- 8 files changed, 410 insertions(+), 199 deletions(-) diff --git a/CHANGES b/CHANGES index f83432e3..7ba7b7da 100644 --- a/CHANGES +++ b/CHANGES @@ -6,6 +6,10 @@ What's New for OpenJPEG + : added January 23, 2011 +! [antonin] MJ2 module: + - Add two components to mj2.h: meth, enumcs. + - Define or reset all components of mj2_cparameters_t before its usage. + - Add argument '-D prec' to frames_to_mj2.c and use the precision in mj2_convert.c (solves Issue 49). * [antonin] move 'KK' definition from rs.h to rs.c to prevent duplicate symbol error when building jpwl with autotools. January 18, 2011 diff --git a/mj2/extract_j2k_from_mj2.c b/mj2/extract_j2k_from_mj2.c index 5c1441ad..0872df1d 100644 --- a/mj2/extract_j2k_from_mj2.c +++ b/mj2/extract_j2k_from_mj2.c @@ -104,8 +104,9 @@ int main(int argc, char *argv[]) { opj_set_event_mgr((opj_common_ptr)dinfo, &event_mgr, stderr); /* setup the decoder decoding parameters using user parameters */ + memset(¶meters, 0, sizeof(mj2_dparameters_t)); movie = (opj_mj2_t*) dinfo->mj2_handle; - mj2_setup_decoder((opj_mj2_t*)dinfo->mj2_handle, ¶meters); + mj2_setup_decoder(movie, ¶meters); if (mj2_read_struct(file, movie)) // Creating the movie structure return 1; diff --git a/mj2/frames_to_mj2.c b/mj2/frames_to_mj2.c index 6b1fd536..f689b00d 100644 --- a/mj2/frames_to_mj2.c +++ b/mj2/frames_to_mj2.c @@ -43,6 +43,10 @@ Size of memory first allocated for MOOV box */ #define TEMP_BUF 10000 +#define ENUMCS_GRAY 16 +#define ENUMCS_SRGB 17 +#define ENUMCS_SYCC 18 + /* -------------------------------------------------------------------------- */ /** @@ -111,60 +115,60 @@ void help_display() fprintf (stdout,"Required Parameters (except with -h):\n"); fprintf - (stdout,"-i : source file (-i source.yuv) \n"); + (stdout,"-i : source file (-i source.yuv) \n"); fprintf - (stdout,"-o : destination file (-o dest.mj2) \n"); + (stdout,"-o : destination file (-o dest.mj2) \n"); fprintf (stdout,"Optional Parameters:\n"); - fprintf(stdout,"-h : display the help information \n"); - fprintf(stdout,"-r : different compression ratios for successive layers (-r 20,10,5)\n "); - fprintf(stdout," - The rate specified for each quality level is the desired \n"); - fprintf(stdout," compression factor.\n"); - fprintf(stdout," Example: -r 20,10,1 means quality 1: compress 20x, \n"); - fprintf(stdout," quality 2: compress 10x and quality 3: compress lossless\n"); - fprintf(stdout," (options -r and -q cannot be used together)\n "); + fprintf(stdout,"-h : display the help information \n"); + fprintf(stdout,"-r : different compression ratios for successive layers (-r 20,10,5)\n"); + fprintf(stdout," - The rate specified for each quality level is the desired \n"); + fprintf(stdout," compression factor.\n"); + fprintf(stdout," Example: -r 20,10,1 means quality 1: compress 20x, \n"); + fprintf(stdout," quality 2: compress 10x and quality 3: compress lossless\n"); + fprintf(stdout," (options -r and -q cannot be used together)\n"); - fprintf(stdout,"-q : different psnr for successive layers (-q 30,40,50) \n "); + fprintf(stdout,"-q : different psnr for successive layers (-q 30,40,50) \n"); + fprintf(stdout," (options -r and -q cannot be used together)\n"); - fprintf(stdout," (options -r and -q cannot be used together)\n "); - - fprintf(stdout,"-n : number of resolutions (-n 3) \n"); - fprintf(stdout,"-b : size of code block (-b 32,32) \n"); - fprintf(stdout,"-c : size of precinct (-c 128,128) \n"); - fprintf(stdout,"-t : size of tile (-t 512,512) \n"); + fprintf(stdout,"-n : number of resolutions (-n 3) \n"); + fprintf(stdout,"-b : size of code block (-b 32,32) \n"); + fprintf(stdout,"-c : size of precinct (-c 128,128) \n"); + fprintf(stdout,"-t : size of tile (-t 512,512) \n"); fprintf - (stdout,"-p : progression order (-p LRCP) [LRCP, RLCP, RPCL, PCRL, CPRL] \n"); + (stdout,"-p : progression order (-p LRCP) [LRCP, RLCP, RPCL, PCRL, CPRL] \n"); fprintf - (stdout,"-s : subsampling factor (-s 2,2) [-s X,Y] \n"); - fprintf(stdout," Remark: subsampling bigger than 2 can produce error\n"); + (stdout,"-s : subsampling factor (-s 2,2) [-s X,Y] \n"); + fprintf(stdout," Remark: subsampling bigger than 2 can produce error\n"); fprintf - (stdout,"-SOP : write SOP marker before each packet \n"); + (stdout,"-S : write SOP marker before each packet \n"); fprintf - (stdout,"-EPH : write EPH marker after each header packet \n"); + (stdout,"-E : write EPH marker after each header packet \n"); fprintf - (stdout,"-M : mode switch (-M 3) [1=BYPASS(LAZY) 2=RESET 4=RESTART(TERMALL)\n"); + (stdout,"-M : mode switch (-M 3) [1=BYPASS(LAZY) 2=RESET 4=RESTART(TERMALL)\n"); fprintf - (stdout," 8=VSC 16=ERTERM(SEGTERM) 32=SEGMARK(SEGSYM)] \n"); + (stdout," 8=VSC 16=ERTERM(SEGTERM) 32=SEGMARK(SEGSYM)] \n"); fprintf - (stdout," Indicate multiple modes by adding their values. \n"); + (stdout," Indicate multiple modes by adding their values. \n"); fprintf - (stdout," ex: RESTART(4) + RESET(2) + SEGMARK(32) = -M 38\n"); + (stdout," Example: RESTART(4) + RESET(2) + SEGMARK(32) = -M 38\n"); fprintf - (stdout,"-ROI : c=%%d,U=%%d : quantization indices upshifted \n"); + (stdout,"-R : c=%%d,U=%%d : quantization indices upshifted \n"); fprintf - (stdout," for component c=%%d [%%d = 0,1,2]\n"); + (stdout," for component c=%%d [%%d = 0,1,2]\n"); fprintf - (stdout," with a value of U=%%d [0 <= %%d <= 37] (i.e. -ROI:c=0,U=25) \n"); + (stdout," with a value of U=%%d [0 <= %%d <= 37] (i.e. -ROI:c=0,U=25) \n"); fprintf - (stdout,"-d : offset of the origin of the image (-d 150,300) \n"); + (stdout,"-d : offset of the origin of the image (-d 150,300) \n"); fprintf - (stdout,"-T : offset of the origin of the tiles (-T 100,75) \n"); - fprintf(stdout,"-I : use the irreversible DWT 9-7 (-I) \n"); - fprintf(stdout,"-W : image width, height and the dx and dy subsampling \n"); - fprintf(stdout," of the Cb and Cr components for YUV files \n"); - fprintf(stdout," (default is '352,288,2,2' for CIF format's 352x288 and 4:2:0)\n"); - fprintf(stdout,"-F : video frame rate (set to 25 by default)\n"); - + (stdout,"-T : offset of the origin of the tiles (-T 100,75) \n"); + fprintf(stdout,"-I : use the irreversible DWT 9-7 (-I) \n"); + fprintf(stdout,"-W : image width, height and the dx and dy subsampling \n"); + fprintf(stdout," of the Cb and Cr components for YUV files \n"); + fprintf(stdout," (default is '352,288,2,2' for CIF format's 352x288 and 4:2:0)\n"); + fprintf(stdout,"-F : video frame rate (set to 25 by default)\n"); + fprintf(stdout,"-D : depth, precision in bits [8 .. 16]; default:8\n"); + fprintf(stdout,"-C : comment\n"); fprintf(stdout,"\n"); fprintf(stdout,"IMPORTANT:\n"); fprintf(stdout,"-----------\n"); @@ -235,33 +239,37 @@ int main(int argc, char **argv) opj_event_mgr_t event_mgr; /* event manager */ opj_cio_t *cio; int value; - opj_mj2_t *movie; + opj_mj2_t *movie; opj_image_t *img; - int i, j; - char *s, S1, S2, S3; - unsigned char *buf; - int x1, y1, len; - long mdat_initpos, offset; - FILE *mj2file; - int sampleno; + int i, j; + char *s, S1, S2, S3; + unsigned char *buf; + int x1, y1, len; + long mdat_initpos, offset; + FILE *mj2file; + int sampleno; opj_cinfo_t* cinfo; - bool bSuccess; + bool bSuccess; int numframes; + int prec = 0; double total_time = 0; + memset(&mj2_parameters, 0, sizeof(mj2_cparameters_t)); /* default value */ /* ------------- */ - mj2_parameters.Dim[0] = 0; - mj2_parameters.Dim[1] = 0; - mj2_parameters.w = 352; // CIF default value - mj2_parameters.h = 288; // CIF default value - mj2_parameters.CbCr_subsampling_dx = 2; // CIF default value - mj2_parameters.CbCr_subsampling_dy = 2; // CIF default value - mj2_parameters.frame_rate = 25; - /* + mj2_parameters.w = 352; // CIF default value + mj2_parameters.h = 288; // CIF default value + mj2_parameters.CbCr_subsampling_dx = 2; // CIF default value + mj2_parameters.CbCr_subsampling_dy = 2; // CIF default value + mj2_parameters.frame_rate = 25; + mj2_parameters.prec = 8; /* DEFAULT */ + mj2_parameters.enumcs = ENUMCS_SYCC; /* FIXME: ENUMCS_YUV420 */ + mj2_parameters.meth = 1; /* enumerated color space */ + +/* configure the event callbacks (not required) setting of each callback is optionnal - */ +*/ memset(&event_mgr, 0, sizeof(opj_event_mgr_t)); event_mgr.error_handler = error_callback; event_mgr.warning_handler = warning_callback; @@ -280,12 +288,9 @@ int main(int argc, char **argv) sprintf(j2k_parameters->cp_comment,"%s%s", comment, version); } - mj2_parameters.decod_format = 0; - mj2_parameters.cod_format = 0; - while (1) { int c = getopt(argc, argv, - "i:o:r:q:f:t:n:c:b:p:s:d:P:S:E:M:R:T:C:I:W:F:h"); + "i:o:r:q:f:t:n:c:b:p:s:d:P:S:E:M:R:T:C:I:W:F:D:h"); if (c == -1) break; switch (c) { @@ -602,6 +607,10 @@ int main(int argc, char **argv) } break; /* ------------------------------------------------------ */ + case 'D': /* Depth: the precision */ + if(sscanf(optarg, "%d", &prec) != 1) prec = 0; + break; + default: return 1; } @@ -657,17 +666,21 @@ int main(int argc, char **argv) + 1 : mj2_parameters.Dim[0] + (mj2_parameters.w - 1) * j2k_parameters->subsampling_dx + 1; y1 = !mj2_parameters.Dim[1] ? (mj2_parameters.h - 1) * j2k_parameters->subsampling_dy + 1 : mj2_parameters.Dim[1] + (mj2_parameters.h - 1) * j2k_parameters->subsampling_dy + 1; - mj2_parameters.numcomps = 3; /* Because YUV files only have 3 components */ - mj2_parameters.prec = 8; /* Because in YUV files, components have 8-bit depth */ + mj2_parameters.numcomps = 3; /* YUV files only have 3 components */ + + + if(prec < 1 || prec > 32) prec = 8; /* DEFAULT */ + + mj2_parameters.prec = prec; j2k_parameters->tcp_mct = 0; - mj2file = fopen(mj2_parameters.outfile, "wb"); + mj2file = fopen(mj2_parameters.outfile, "wb"); - if (!mj2file) { + if (!mj2file) { fprintf(stderr, "failed to open %s for writing\n", argv[2]); return 1; - } + } /* get a MJ2 decompressor handle */ cinfo = mj2_create_compress(); @@ -679,128 +692,151 @@ int main(int argc, char **argv) /* setup encoder parameters */ mj2_setup_encoder(movie, &mj2_parameters); - movie->tk[0].num_samples = yuv_num_frames(&movie->tk[0],mj2_parameters.infile); - if (movie->tk[0].num_samples == -1) { + movie->tk[0].num_samples = + yuv_num_frames(&movie->tk[0],mj2_parameters.infile); + + if (movie->tk[0].num_samples == -1) { return 1; - } - + } + // One sample per chunk - movie->tk[0].chunk = (mj2_chunk_t*) malloc(movie->tk[0].num_samples * sizeof(mj2_chunk_t)); - movie->tk[0].sample = (mj2_sample_t*) malloc(movie->tk[0].num_samples * sizeof(mj2_sample_t)); + movie->tk[0].chunk = (mj2_chunk_t*) + malloc(movie->tk[0].num_samples * sizeof(mj2_chunk_t)); + movie->tk[0].sample = (mj2_sample_t*) + malloc(movie->tk[0].num_samples * sizeof(mj2_sample_t)); - if (mj2_init_stdmovie(movie)) { + if (mj2_init_stdmovie(movie)) { fprintf(stderr, "Error with movie initialization"); return 1; - }; + } - // Writing JP, FTYP and MDAT boxes - buf = (unsigned char*) malloc (300 * sizeof(unsigned char)); // Assuming that the JP and FTYP - // boxes won't be longer than 300 bytes +// Writing JP, FTYP and MDAT boxes +// Assuming that the JP and FTYP boxes won't be longer than 300 bytes: + buf = (unsigned char*) + malloc (300 * sizeof(unsigned char)); + cio = opj_cio_open((opj_common_ptr)movie->cinfo, buf, 300); - mj2_write_jp(cio); - mj2_write_ftyp(movie, cio); - mdat_initpos = cio_tell(cio); - cio_skip(cio, 4); - cio_write(cio, MJ2_MDAT, 4); - fwrite(buf,cio_tell(cio),1,mj2file); - offset = cio_tell(cio); - opj_cio_close(cio); - free(buf); - for (i = 0; i < movie->num_stk + movie->num_htk + movie->num_vtk; i++) { - if (movie->tk[i].track_type != 0) { - fprintf(stderr, "Unable to write sound or hint tracks\n"); - } else { - mj2_tk_t *tk; - int buflen = 0; - - tk = &movie->tk[i]; - tk->num_chunks = tk->num_samples; - numframes = tk->num_samples; + mj2_write_jp(cio); + mj2_write_ftyp(movie, cio); - fprintf(stderr, "Video Track number %d\n", i + 1); - - img = mj2_image_create(tk, j2k_parameters); - buflen = 2 * (tk->w * tk->h * 8); - buf = (unsigned char *) malloc(buflen*sizeof(unsigned char)); + mdat_initpos = cio_tell(cio); + cio_skip(cio, 4); - for (sampleno = 0; sampleno < numframes; sampleno++) { - double init_time = opj_clock(); - double elapsed_time; - if (yuvtoimage(tk, img, sampleno, j2k_parameters, mj2_parameters.infile)) { - fprintf(stderr, "Error with frame number %d in YUV file\n", sampleno); - return 1; - } + cio_write(cio, MJ2_MDAT, 4); - /* setup the encoder parameters using the current image and user parameters */ - opj_setup_encoder(cinfo, j2k_parameters, img); + fwrite(buf,cio_tell(cio),1,mj2file); - cio = opj_cio_open((opj_common_ptr)movie->cinfo, buf, buflen); - - cio_skip(cio, 4); - cio_write(cio, JP2_JP2C, 4); // JP2C + offset = cio_tell(cio); + opj_cio_close(cio); + free(buf); - /* encode the image */ - bSuccess = opj_encode(cinfo, cio, img, NULL); - if (!bSuccess) { - opj_cio_close(cio); - fprintf(stderr, "failed to encode image\n"); - return 1; - } - - len = cio_tell(cio) - 8; - cio_seek(cio, 0); - cio_write(cio, len+8,4); - opj_cio_close(cio); - tk->sample[sampleno].sample_size = len+8; - tk->sample[sampleno].offset = offset; - tk->chunk[sampleno].offset = offset; // There is one sample per chunk - fwrite(buf, 1, len+8, mj2file); - offset += len+8; - elapsed_time = opj_clock()-init_time; - fprintf(stderr, "Frame number %d/%d encoded in %.2f mseconds\n", sampleno + 1, numframes, elapsed_time*1000); - total_time += elapsed_time; - - } - /* free buffer data */ - free(buf); - /* free image data */ - opj_image_destroy(img); - } + for(i = 0; i < movie->num_stk + movie->num_htk + movie->num_vtk; i++) + { + if(movie->tk[i].track_type != 0) + { + fprintf(stderr, "Unable to write sound or hint tracks\n"); } + else + { + mj2_tk_t *tk; + int buflen = 0; - fseek(mj2file, mdat_initpos, SEEK_SET); + tk = &movie->tk[i]; + tk->num_chunks = tk->num_samples; + numframes = tk->num_samples; + tk->depth = prec; + + fprintf(stderr, "Video Track number %d\n", i); + + img = mj2_image_create(tk, j2k_parameters); + + buflen = 2 * (tk->w * tk->h * 8); + buf = (unsigned char *) malloc(buflen*sizeof(unsigned char)); + + for(sampleno = 0; sampleno < numframes; sampleno++) + { + double init_time = opj_clock(); + double elapsed_time; + + if(yuvtoimage(tk, img, sampleno, j2k_parameters, + mj2_parameters.infile)) + { + fprintf(stderr, "Error with frame number %d in YUV file\n", sampleno); + return 1; + } + +/* setup the encoder parameters using the current image and user parameters */ + opj_setup_encoder(cinfo, j2k_parameters, img); + + cio = opj_cio_open((opj_common_ptr)movie->cinfo, buf, buflen); + + cio_skip(cio, 4); + cio_write(cio, JP2_JP2C, 4); // JP2C + +/* encode the image */ + bSuccess = opj_encode(cinfo, cio, img, NULL); + + if (!bSuccess) { + opj_cio_close(cio); + fprintf(stderr, "failed to encode image\n"); + return 1; + } + + len = cio_tell(cio) - 8; + cio_seek(cio, 0); + cio_write(cio, len+8,4); + opj_cio_close(cio); + + tk->sample[sampleno].sample_size = len+8; + tk->sample[sampleno].offset = offset; + tk->chunk[sampleno].offset = offset; // There is one sample per chunk + fwrite(buf, 1, len+8, mj2file); + offset += len+8; + + elapsed_time = opj_clock()-init_time; + fprintf(stderr, "Frame number %d/%d encoded in %.2f mseconds\n", + sampleno + 1, numframes, elapsed_time*1000); + total_time += elapsed_time; + } /* for(sampleno */ + + free(buf); + opj_image_destroy(img); + } + }/* for(i */ + + fseek(mj2file, mdat_initpos, SEEK_SET); - buf = (unsigned char*) malloc(4*sizeof(unsigned char)); + buf = (unsigned char*) malloc(4*sizeof(unsigned char)); - // Init a cio to write box length variable in a little endian way +// Init a cio to write box length variable in a little endian way cio = opj_cio_open(NULL, buf, 4); - cio_write(cio, offset - mdat_initpos, 4); - fwrite(buf, 4, 1, mj2file); - fseek(mj2file,0,SEEK_END); - free(buf); + cio_write(cio, offset - mdat_initpos, 4); + fwrite(buf, 4, 1, mj2file); + fseek(mj2file,0,SEEK_END); + free(buf); - // Writing MOOV box - buf = (unsigned char*) malloc ((TEMP_BUF+numframes*20) * sizeof(unsigned char)); +// Writing MOOV box + buf = (unsigned char*) + malloc ((TEMP_BUF+numframes*20) * sizeof(unsigned char)); cio = opj_cio_open(movie->cinfo, buf, (TEMP_BUF+numframes*20)); mj2_write_moov(movie, cio); - fwrite(buf,cio_tell(cio),1,mj2file); - free(buf); + fwrite(buf,cio_tell(cio),1,mj2file); + free(buf); + + fprintf(stdout,"Total encoding time: %.2f s for %d frames (%.1f fps)\n", + total_time, numframes, (float)numframes/total_time); - fprintf(stdout,"Total encoding time: %.2f s for %d frames (%.1f fps)\n", total_time, numframes, (float)numframes/total_time); - // Ending program - fclose(mj2file); - /* free remaining compression structures */ + fclose(mj2file); +/* free remaining compression structures */ mj2_destroy_compress(movie); free(cinfo); - /* free user parameters structure */ - if(j2k_parameters->cp_comment) free(j2k_parameters->cp_comment); + + if(j2k_parameters->cp_comment) free(j2k_parameters->cp_comment); if(j2k_parameters->cp_matrice) free(j2k_parameters->cp_matrice); opj_cio_close(cio); - return 0; + return 0; } - - diff --git a/mj2/mj2.c b/mj2/mj2.c index 01ee90c5..131eacea 100644 --- a/mj2/mj2.c +++ b/mj2/mj2.c @@ -90,7 +90,8 @@ int mj2_read_boxhdr(mj2_box_t * box, opj_cio_t *cio) int mj2_init_stdmovie(opj_mj2_t * movie) { - int i; + mj2_tk_t *tk0; + int i, w, h, prec; unsigned int j; time_t ltime; @@ -117,17 +118,24 @@ int mj2_init_stdmovie(opj_mj2_t * movie) movie->trans_matrix[7] = 0; movie->trans_matrix[8] = 0x40000000; movie->next_tk_id = 1; - - for (i = 0; i < movie->num_htk + movie->num_stk + movie->num_vtk; i++) { + + tk0 = &movie->tk[0]; + w = tk0->w; h = tk0->h; prec = tk0->depth; + + for (i = 0; i < movie->num_htk + movie->num_stk + movie->num_vtk; i++) + { mj2_tk_t *tk = &movie->tk[i]; + movie->next_tk_id++; tk->jp2_struct.comps = NULL; tk->jp2_struct.cl = NULL; - - if (tk->track_type == 0) { - if (tk->num_samples == 0) + + if (tk->track_type == 0) /* no sound or hint track */ + { + if (tk->num_samples == 0) return 1; + tk->w = w; tk->h = h; tk->depth = prec; tk->Dim[0] = 0; tk->Dim[1] = 0; @@ -138,22 +146,24 @@ int mj2_init_stdmovie(opj_mj2_t * movie) tk->same_sample_size = 0; - tk->num_samplestochunk = 1; /* One sample per chunk */ + tk->num_samplestochunk = 1; /* One sample per chunk */ tk->sampletochunk = (mj2_sampletochunk_t*) opj_malloc(tk->num_samplestochunk * sizeof(mj2_sampletochunk_t)); tk->sampletochunk[0].first_chunk = 1; tk->sampletochunk[0].samples_per_chunk = 1; tk->sampletochunk[0].sample_descr_idx = 1; - if (tk->sample_rate == 0) { - opj_event_msg(tk->cinfo, EVT_ERROR, - "Error while initializing MJ2 movie: Sample rate of track %d must be different from zero\n", - tk->track_ID); - return 1; - } + if (tk->sample_rate == 0) + { + opj_event_msg(tk->cinfo, EVT_ERROR, + "Error while initializing MJ2 movie: Sample rate of track" + " %d must be different from zero\n", tk->track_ID); + return 1; + } - for (j = 0; j < tk->num_samples; j++) { - tk->sample[j].sample_delta = tk->timescale / tk->sample_rate; - } + for (j = 0; j < tk->num_samples; j++) + { + tk->sample[j].sample_delta = tk->timescale / tk->sample_rate; + } tk->num_tts = 1; tk->tts = (mj2_tts_t*) opj_malloc(tk->num_tts * sizeof(mj2_tts_t)); @@ -2842,9 +2852,10 @@ void mj2_setup_encoder(opj_mj2_t *movie, mj2_cparameters_t *parameters) { movie->tk[0].name_size = 0; movie->tk[0].chunk = (mj2_chunk_t*) opj_malloc(sizeof(mj2_chunk_t)); movie->tk[0].sample = (mj2_sample_t*) opj_malloc(sizeof(mj2_sample_t)); + movie->tk[0].depth = parameters->prec; jp2_struct = &movie->tk[0].jp2_struct; - jp2_struct->numcomps = 3; // NC + jp2_struct->numcomps = parameters->numcomps; // NC jp2_struct->comps = (opj_jp2_comps_t*) opj_malloc(jp2_struct->numcomps * sizeof(opj_jp2_comps_t)); jp2_struct->precedence = 0; /* PRECEDENCE*/ jp2_struct->approx = 0; /* APPROX*/ @@ -2859,8 +2870,8 @@ void mj2_setup_encoder(opj_mj2_t *movie, mj2_cparameters_t *parameters) { jp2_struct->w = parameters->w; jp2_struct->h = parameters->h; jp2_struct->bpc = 7; - jp2_struct->meth = 1; - jp2_struct->enumcs = 18; // YUV + jp2_struct->meth = parameters->meth; + jp2_struct->enumcs = parameters->enumcs; } } diff --git a/mj2/mj2.h b/mj2/mj2.h index 97cf8ede..0ddb6b89 100644 --- a/mj2/mj2.h +++ b/mj2/mj2.h @@ -295,6 +295,8 @@ typedef struct mj2_cparameters { int numcomps; /* In YUV files, precision always considered as 8 */ int prec; + unsigned int meth; + unsigned int enumcs; } mj2_cparameters_t; diff --git a/mj2/mj2_convert.c b/mj2/mj2_convert.c index 3f4c2e75..d0c1860f 100644 --- a/mj2/mj2_convert.c +++ b/mj2/mj2_convert.c @@ -39,7 +39,7 @@ int yuv_num_frames(mj2_tk_t * tk, char *infile) { - int numimages, frame_size; + int numimages, frame_size, prec_size; long end_of_f; FILE *f; @@ -48,8 +48,10 @@ int yuv_num_frames(mj2_tk_t * tk, char *infile) fprintf(stderr, "failed to open %s for reading\n",infile); return -1; } - + prec_size = (tk->depth + 7)/8;/* bytes of precision */ + frame_size = (int) (tk->w * tk->h * (1.0 + (double) 2 / (double) (tk->CbCr_subsampling_dx * tk->CbCr_subsampling_dy))); /* Calculate frame size */ + frame_size *= prec_size; fseek(f, 0, SEEK_END); end_of_f = ftell(f); /* Calculate file size */ @@ -86,8 +88,8 @@ opj_image_t *mj2_image_create(mj2_tk_t * tk, opj_cparameters_t *parameters) /* initialize image components */ memset(&cmptparm[0], 0, 3 * sizeof(opj_image_cmptparm_t)); for(i = 0; i < numcomps; i++) { - cmptparm[i].prec = 8; - cmptparm[i].bpp = 8; + cmptparm[i].prec = tk->depth; + cmptparm[i].bpp = tk->depth; cmptparm[i].sgnd = 0; cmptparm[i].dx = i ? subsampling_dx * tk->CbCr_subsampling_dx : subsampling_dx; cmptparm[i].dy = i ? subsampling_dy * tk->CbCr_subsampling_dy : subsampling_dy; @@ -102,7 +104,7 @@ opj_image_t *mj2_image_create(mj2_tk_t * tk, opj_cparameters_t *parameters) char yuvtoimage(mj2_tk_t * tk, opj_image_t * img, int frame_num, opj_cparameters_t *parameters, char* infile) { int i, compno; - int offset; + int offset, size, max, prec_size; long end_of_f, position; int numcomps = 3; int subsampling_dx = parameters->subsampling_dx; @@ -114,9 +116,12 @@ char yuvtoimage(mj2_tk_t * tk, opj_image_t * img, int frame_num, opj_cparameters fprintf(stderr, "failed to open %s for readings\n",parameters->infile); return 1; } + prec_size = (tk->depth + 7)/8;/* bytes of precision */ offset = (int) ((double) (frame_num * tk->w * tk->h) * (1.0 + 1.0 * (double) 2 / (double) (tk->CbCr_subsampling_dx * tk->CbCr_subsampling_dy))); + offset *= prec_size; + fseek(yuvfile, 0, SEEK_END); end_of_f = ftell(yuvfile); fseek(yuvfile, sizeof(unsigned char) * offset, SEEK_SET); @@ -134,16 +139,22 @@ char yuvtoimage(mj2_tk_t * tk, opj_image_t * img, int frame_num, opj_cparameters (tk->w - 1) * subsampling_dx + 1; img->y1 = !tk->Dim[1] ? (tk->h - 1) * subsampling_dy + 1 : tk->Dim[1] + (tk->h - 1) * subsampling_dy + 1; + + size = tk->w * tk->h * prec_size; - for(compno = 0; compno < numcomps; compno++) { - for (i = 0; i < (tk->w * tk->h / (img->comps[compno].dx * img->comps[compno].dy)) - && !feof(yuvfile); i++) { - if (!fread(&img->comps[compno].data[i], 1, 1, yuvfile)) { - fprintf(stderr, "Error reading %s file !!\n", infile); - return 1; - } - } - } + for(compno = 0; compno < numcomps; compno++) + { + max = size/(img->comps[compno].dx * img->comps[compno].dy); + + for (i = 0; i < max && !feof(yuvfile); i++) + { + if (!fread(&img->comps[compno].data[i], 1, 1, yuvfile)) + { + fprintf(stderr, "Error reading %s file !!\n", infile); + return 1; + } + } + } fclose(yuvfile); return 0; diff --git a/mj2/mj2_to_frames.c b/mj2/mj2_to_frames.c index 63869ea9..156a101c 100644 --- a/mj2/mj2_to_frames.c +++ b/mj2/mj2_to_frames.c @@ -124,11 +124,12 @@ int main(int argc, char *argv[]) { /* catch events using our callbacks and give a local context */ opj_set_event_mgr((opj_common_ptr)dinfo, &event_mgr, stderr); + memset(&mj2_parameters, 0, sizeof(mj2_dparameters_t)); /* set J2K decoding parameters to default values */ opj_set_default_decoder_parameters(&mj2_parameters.j2k_parameters); /* setup the decoder decoding parameters using user parameters */ - mj2_setup_decoder((opj_mj2_t*)dinfo->mj2_handle, &mj2_parameters); + mj2_setup_decoder(movie, &mj2_parameters); if (mj2_read_struct(file, movie)) // Creating the movie structure return 1; diff --git a/mj2/wrap_j2k_in_mj2.c b/mj2/wrap_j2k_in_mj2.c index 77b49598..7766dd37 100644 --- a/mj2/wrap_j2k_in_mj2.c +++ b/mj2/wrap_j2k_in_mj2.c @@ -45,9 +45,143 @@ Size of memory first allocated for MOOV box */ #define TEMP_BUF 10000 +#define ENUMCS_GRAY 16 +#define ENUMCS_SRGB 17 +#define ENUMCS_SYCC 18 + +#define J2K_CODESTREAM_MAGIC "\xff\x4f\xff\x51" /* -------------------------------------------------------------------------- */ +static int test_image(const char *fname, mj2_cparameters_t *cp) +{ + FILE *reader; + opj_image_t *image; + unsigned char *src; + opj_dinfo_t *dinfo; + opj_cio_t *cio; + opj_dparameters_t dparameters; + int success; + long src_len; + + success = 0; + + if((reader = fopen(fname, "rb")) == NULL) return success; + + fseek(reader, 0, SEEK_END); + src_len = ftell(reader); + fseek(reader, 0, SEEK_SET); + src = (unsigned char*) malloc(src_len); + fread(src, 1, src_len, reader); + fclose(reader); + + if(memcmp(src, J2K_CODESTREAM_MAGIC, 4) != 0) + { + free(src); return success; + } + memset(&dparameters, 0, sizeof(opj_dparameters_t)); + + opj_set_default_decoder_parameters(&dparameters); + + dinfo = opj_create_decompress(CODEC_J2K); + + opj_setup_decoder(dinfo, &dparameters); + + cio = opj_cio_open((opj_common_ptr)dinfo, src, src_len); + + image = opj_decode(dinfo, cio); + + free(src); cio->buffer = NULL; + opj_cio_close(cio); + + if(image == NULL) goto fin; + + cp->numcomps = image->numcomps; + cp->w = image->comps[0].w; + cp->h = image->comps[0].h; + cp->prec = image->comps[0].prec; + + if(image->numcomps > 2 ) + { + if((image->comps[0].dx == 1) + && (image->comps[1].dx == 2) + && (image->comps[2].dx == 2) + && (image->comps[0].dy == 1) + && (image->comps[1].dy == 2) + && (image->comps[2].dy == 2))// horizontal and vertical + { +// Y420 + cp->enumcs = ENUMCS_SYCC; + cp->CbCr_subsampling_dx = 2; + cp->CbCr_subsampling_dy = 2; + } + else + if((image->comps[0].dx == 1) + && (image->comps[1].dx == 2) + && (image->comps[2].dx == 2) + && (image->comps[0].dy == 1) + && (image->comps[1].dy == 1) + && (image->comps[2].dy == 1))// horizontal only + { +// Y422 + cp->enumcs = ENUMCS_SYCC; + cp->CbCr_subsampling_dx = 2; + cp->CbCr_subsampling_dy = 1; + } + else + if((image->comps[0].dx == 1) + && (image->comps[1].dx == 1) + && (image->comps[2].dx == 1) + && (image->comps[0].dy == 1) + && (image->comps[1].dy == 1) + && (image->comps[2].dy == 1)) + { +// Y444 or RGB + + if(image->color_space == CLRSPC_SRGB) + { + cp->enumcs = ENUMCS_SRGB; + +// cp->CbCr_subsampling_dx = 0; +// cp->CbCr_subsampling_dy = 0; + } + else + { + cp->enumcs = ENUMCS_SYCC; + + cp->CbCr_subsampling_dx = 1; + cp->CbCr_subsampling_dy = 1; + } + } + else + { + goto fin; + } + } + else + { + cp->enumcs = ENUMCS_GRAY; +// cp->CbCr_subsampling_dx = 0; +// cp->CbCr_subsampling_dy = 0; + } + if(image->icc_profile_buf) + { + cp->meth = 2; + free(image->icc_profile_buf); image->icc_profile_buf = NULL; + } + else cp->meth = 1; + + success = 1; +fin: + if(dinfo) + opj_destroy_decompress(dinfo); + + if(image) + opj_image_destroy(image); + + return success; +} + /** sample error callback expecting a FILE* client object */ @@ -125,7 +259,6 @@ static void read_siz_marker(FILE *file, opj_image_t *image) static void setparams(opj_mj2_t *movie, opj_image_t *image) { int i, depth_0, depth, sign; - movie->tk[0].sample_rate = 25; movie->tk[0].w = int_ceildiv(image->x1 - image->x0, image->comps[0].dx); movie->tk[0].h = int_ceildiv(image->y1 - image->y0, image->comps[0].dy); mj2_init_stdmovie(movie); @@ -233,7 +366,7 @@ int main(int argc, char *argv[]) { mj2_sample_t *sample; unsigned char* frame_codestream; FILE *mj2file, *j2kfile; - char j2kfilename[50]; + char *j2kfilename; unsigned char *buf; int offset, mdat_initpos; opj_image_t img; @@ -252,7 +385,7 @@ int main(int argc, char *argv[]) { fprintf(stderr, "failed to open %s for writing\n", argv[2]); return 1; } - + memset(&img, 0, sizeof(opj_image_t)); /* configure the event callbacks (not required) setting of each callback is optionnal @@ -269,8 +402,17 @@ int main(int argc, char *argv[]) { opj_set_event_mgr((opj_common_ptr)cinfo, &event_mgr, stderr); /* setup the decoder encoding parameters using user parameters */ + memset(¶meters, 0, sizeof(mj2_cparameters_t)); movie = (opj_mj2_t*) cinfo->mj2_handle; - mj2_setup_encoder((opj_mj2_t*)cinfo->mj2_handle, ¶meters); + + j2kfilename = (char*)malloc(strlen(argv[1]) + 12);/* max. '%6d' */ + sprintf(j2kfilename, "%s_00001.j2k",argv[1]); + + if(test_image(j2kfilename, ¶meters) == 0) goto fin; + + parameters.frame_rate = 25; /* DEFAULT */ + + mj2_setup_encoder(movie, ¶meters); /* Writing JP, FTYP and MDAT boxes @@ -362,10 +504,13 @@ int main(int argc, char *argv[]) { fwrite(buf,cio_tell(cio),1,mj2file); // Ending program - fclose(mj2file); free(img.comps); opj_cio_close(cio); + +fin: + fclose(mj2file); mj2_destroy_compress(movie); - + free(j2kfilename); + return 0; }