From 13b8ecfe44e9d3f5b1a31626ed44099a0224dd01 Mon Sep 17 00:00:00 2001 From: Francois-Olivier Devaux Date: Wed, 8 Dec 2004 12:12:23 +0000 Subject: [PATCH] This tool wraps J2K codestreams into a MJ2 file (designed to work with other codecs than OpenJPEG) --- mj2/wrap_j2k_in_mj2.c | 289 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 289 insertions(+) create mode 100644 mj2/wrap_j2k_in_mj2.c diff --git a/mj2/wrap_j2k_in_mj2.c b/mj2/wrap_j2k_in_mj2.c new file mode 100644 index 00000000..44feefa0 --- /dev/null +++ b/mj2/wrap_j2k_in_mj2.c @@ -0,0 +1,289 @@ +#include +#include +#include +#include + +#include "mj2.h" +#include +#include +#include + +#define MJ2_MJ2 0x6d6a7032 +#define MJ2_MJ2S 0x6d6a3273 +#define JP2_JP2C 0x6a703263 +#define MJ2_MDAT 0x6d646174 + +//MEMORY LEAK +#ifdef _DEBUG +#define _CRTDBG_MAP_ALLOC +#include // Must be included first +#include +#endif +//MEM + +jmp_buf j2k_error; + +void j2k_read_siz_marker(FILE *file, j2k_image_t *j2k_img) +{ + int len,i; + char buf, buf2[2]; + char *siz_buffer; + + fseek(file, 0, SEEK_SET); + do { + fread(&buf,1,1, file); + if (buf==(char)0xff) + fread(&buf,1,1, file); + } + while (!(buf==(char)0x51)); + + fread(buf2,2,1,file); /* Lsiz */ + len = ((buf2[0])<<8) + buf2[1]; + + siz_buffer = (char*) malloc(len * sizeof(char)); + fread(siz_buffer,len, 1, file); + cio_init(siz_buffer,len); + + cio_read(2); /* Rsiz (capabilities) */ + j2k_img->x1 = cio_read(4); /* Xsiz */ + j2k_img->y1 = cio_read(4); /* Ysiz */ + j2k_img->x0 = cio_read(4); /* X0siz */ + j2k_img->y0 = cio_read(4); /* Y0siz */ + cio_skip(16); /* XTsiz, YTsiz, XT0siz, YT0siz */ + + j2k_img->numcomps = cio_read(2); /* Csiz */ + j2k_img->comps = + (j2k_comp_t *) malloc(j2k_img->numcomps * sizeof(j2k_comp_t)); + for (i = 0; i < j2k_img->numcomps; i++) { + int tmp; + tmp = cio_read(1); /* Ssiz_i */ + j2k_img->comps[i].prec = (tmp & 0x7f) + 1; + j2k_img->comps[i].sgnd = tmp >> 7; + j2k_img->comps[i].dx = cio_read(1); /* XRsiz_i */ + j2k_img->comps[i].dy = cio_read(1); /* YRsiz_i */ + j2k_img->comps[i].resno_decoded = 0; /* number of resolution decoded */ + j2k_img->comps[i].factor = 0; /* reducing factor by component */ + } + free(siz_buffer); + fseek(file, 0, SEEK_SET); +} + +void setparams(mj2_movie_t *movie, j2k_image_t *img) { + int i, depth_0, depth, sign; + + movie->tk[0].sample_rate = 25; + movie->tk[0].w = int_ceildiv(img->x1 - img->x0, img->comps[0].dx); + movie->tk[0].h = int_ceildiv(img->y1 - img->y0, img->comps[0].dy); + mj2_init_stdmovie(movie); + + movie->tk[0].depth = img->comps[0].prec; + + if (img->numcomps==3) { + if ((img->comps[0].dx == 1) && (img->comps[1].dx == 1) && (img->comps[1].dx == 1)) + movie->tk[0].CbCr_subsampling_dx = 1; + else if ((img->comps[0].dx == 1) && (img->comps[1].dx == 2) && (img->comps[1].dx == 2)) + movie->tk[0].CbCr_subsampling_dx = 2; + else + fprintf(stderr,"Image component sizes are incoherent\n"); + + if ((img->comps[0].dy == 1) && (img->comps[1].dy == 1) && (img->comps[1].dy == 1)) + movie->tk[0].CbCr_subsampling_dy = 1; + else if ((img->comps[0].dy == 1) && (img->comps[1].dy == 2) && (img->comps[1].dy == 2)) + movie->tk[0].CbCr_subsampling_dy = 2; + else + fprintf(stderr,"Image component sizes are incoherent\n"); + } + + movie->tk[0].sample_rate = 25; + + movie->tk[0].jp2_struct.numcomps = img->numcomps; // NC + jp2_init_stdjp2(&movie->tk[0].jp2_struct); + + movie->tk[0].jp2_struct.w = int_ceildiv(img->x1 - img->x0, img->comps[0].dx); + movie->tk[0].jp2_struct.h = int_ceildiv(img->y1 - img->y0, img->comps[0].dy); + + depth_0 = img->comps[0].prec - 1; + sign = img->comps[0].sgnd; + movie->tk[0].jp2_struct.bpc = depth_0 + (sign << 7); + + for (i = 1; i < img->numcomps; i++) { + depth = img->comps[i].prec - 1; + sign = img->comps[i].sgnd; + if (depth_0 != depth) + movie->tk[0].jp2_struct.bpc = 255; + } + + for (i = 0; i < img->numcomps; i++) + movie->tk[0].jp2_struct.comps[i].bpcc = + img->comps[i].prec - 1 + (img->comps[i].sgnd << 7); + + if ((img->numcomps == 1 || img->numcomps == 3) + && (movie->tk[0].jp2_struct.bpc != 255)) + movie->tk[0].jp2_struct.meth = 1; + else + movie->tk[0].jp2_struct.meth = 2; + + if (img->numcomps == 1) + movie->tk[0].jp2_struct.enumcs = 17; // Grayscale + + else if ((img->comps[0].dx == 1) && (img->comps[1].dx == 1) && (img->comps[1].dx == 1) && + (img->comps[0].dy == 1) && (img->comps[1].dy == 1) && (img->comps[1].dy == 1)) + movie->tk[0].jp2_struct.enumcs = 16; // RGB + + else if ((img->comps[0].dx == 1) && (img->comps[1].dx == 2) && (img->comps[1].dx == 2) && + (img->comps[0].dy == 1) && (img->comps[1].dy == 2) && (img->comps[1].dy == 2)) + movie->tk[0].jp2_struct.enumcs = 18; // YUV + + else + movie->tk[0].jp2_struct.enumcs = 0; // Unkown profile */ +} + +int main(int argc, char *argv[]) { + + unsigned int snum; + mj2_movie_t movie; + mj2_sample_t *sample; + unsigned char* frame_codestream; + FILE *mj2file, *j2kfile; + char j2kfilename[50]; + char *buf; + int offset, mdat_initpos; + j2k_image_t img; + int pos, i; + + if (argc != 3) { + printf("Bad syntax: Usage: MJ2_Wrapper source_location mj2_filename\n"); + printf("Example: MJ2_Wrapper input/input output.mj2\n"); + return 1; + } + + mj2file = fopen(argv[2], "wb"); + + if (!mj2file) { + fprintf(stderr, "failed to open %s for writing\n", argv[2]); + return 1; + } + + // Initialing the movie (parameters used in the JP and FTYP boxes + movie.num_htk = 0; // No hint tracks + movie.num_stk = 0; // No sound tracks + movie.num_vtk = 1; // One video track + movie.tk = (mj2_tk_t*) malloc (sizeof(mj2_tk_t)); //Memory allocation for the video track + movie.tk[0].sample = (mj2_sample_t*) malloc (sizeof(mj2_sample_t)); + movie.tk[0].chunk = (mj2_chunk_t *) malloc(sizeof(mj2_chunk_t)); + movie.tk[0].track_type = 0; // Video track + movie.tk[0].track_ID = 1; // Track ID = 1 + movie.brand = MJ2_MJ2; // One brand: MJ2 + movie.num_cl = 2; // Two compatible brands: MJ2 and MJ2S + movie.cl = (unsigned int *) malloc(movie.num_cl * sizeof(unsigned int)); + movie.cl[0] = MJ2_MJ2; + movie.cl[1] = MJ2_MJ2S; + movie.minversion = 0; // Minimum version: 0 + + // Writing JP, FTYP and MDAT boxes + buf = (char*) malloc (300 * sizeof(char)); // Assuming that the JP and FTYP + // boxes won't be longer than 300 bytes + cio_init(buf , 300); + mj2_write_jp(); + mj2_write_ftyp(&movie); + mdat_initpos = cio_tell(); + cio_skip(4); + cio_write(MJ2_MDAT, 4); + fwrite(buf,cio_tell(),1,mj2file); + free(buf); + + // Insert each j2k codestream in a JP2C box + snum=0; + offset = 0; + while(1) + { + sample = &movie.tk[0].sample[snum]; + sprintf(j2kfilename,"%s_%d.j2k",argv[1],snum); + j2kfile = fopen(j2kfilename, "rb"); + if (!j2kfile) { + if (snum==0) { // Could not open a single codestream + fprintf(stderr, "failed to open %s for reading\n",j2kfilename); + return 1; + } + else { // Tried to open a inexistant codestream + fprintf(stdout,"%d frames created\n",snum); + break; + } + } + // Calculating offset for samples and chunks + offset += cio_tell(); + sample->offset = offset; + movie.tk[0].chunk[snum].offset = offset; // There will be one sample per chunk + + // Calculating sample size + fseek(j2kfile,0,SEEK_END); + sample->sample_size = ftell(j2kfile) + 8; // Sample size is codestream + JP2C box header + fseek(j2kfile,0,SEEK_SET); + + // Reading siz marker of j2k image for the first codestream + if (snum==0) + j2k_read_siz_marker(j2kfile, &img); + + // Writing JP2C box header + frame_codestream = (unsigned char*) malloc (sample->sample_size+8); + cio_init(frame_codestream, sample->sample_size); + cio_write(sample->sample_size, 4); // Sample size + cio_write(JP2_JP2C, 4); // JP2C + + // Writing codestream from J2K file to MJ2 file + fread(frame_codestream+8,sample->sample_size-8,1,j2kfile); + fwrite(frame_codestream,sample->sample_size,1,mj2file); + cio_skip(sample->sample_size-8); + + // Ending loop + fclose(j2kfile); + snum++; + movie.tk[0].sample = realloc(movie.tk[0].sample, (snum+1) * sizeof(mj2_sample_t)); + movie.tk[0].chunk = realloc(movie.tk[0].chunk, (snum+1) * sizeof(mj2_chunk_t)); + free(frame_codestream); + } + + // Writing the MDAT box length in header + offset += cio_tell(); + buf = (char*) malloc (4 * sizeof(char)); + cio_init(buf,4); + cio_write(offset-mdat_initpos,4); // Write MDAT length in MDAT box header + fseek(mj2file,(long)mdat_initpos,SEEK_SET); + fwrite(buf,4,1,mj2file); + fseek(mj2file,0,SEEK_END); + free(buf); + + // Setting movie parameters + movie.tk[0].num_samples=snum; + movie.tk[0].num_chunks=snum; + setparams(&movie, &img); + + // Writing MOOV box + i=1; + buf = (char*) malloc (10000 * sizeof(char)); + cio_init(buf , i*10000); + if (setjmp(j2k_error)) { + i++; + realloc(buf,i*10000* sizeof(char)); + pos = cio_tell(); + cio_init(buf , i*10000); + cio_seek(pos); + } + mj2_write_moov(&movie); + fwrite(buf,cio_tell(),1,mj2file); + + // Ending program + fclose(mj2file); + free(img.comps); + free(buf); + mj2_memory_free(&movie); + + + //MEMORY LEAK + #ifdef _DEBUG + _CrtDumpMemoryLeaks(); + #endif + //MEM + + return 0; +} \ No newline at end of file