Skip to content
Snippets Groups Projects
Commit 83ec0cd6 authored by Merov Linden's avatar Merov Linden
Browse files

STORM-746 : add new arguments for precincts and blocks on output, region and...

STORM-746 : add new arguments for precincts and blocks on output, region and level on input, add code for input loading restriction
parent dc00f42d
No related branches found
No related tags found
No related merge requests found
......@@ -53,12 +53,28 @@ static const char USAGE[] = "\n"
" -o, --output <file1 .. file2> OR <type>\n"
" List of image files to create (assumes same order as for input files)\n"
" OR 3 letters file type extension to convert each input file into.\n"
" -r, --region <x0, y0, x1, y1>\n"
" Crop region on the input file in pixel.\n"
" Only used for j2c images. Default is no region cropping.\n"
" -d, --discard_level <n>\n"
" Discard level max used on input. 0 is high resolution. Max discard level is 5.\n"
" This allows the input image to be clamped in resolution when loading.\n"
" Only valid for j2c images. Default is no discard.\n"
" -p, --precincts <n>\n"
" Dimension of precincts in pixels. Precincts are assumed square and identical for\n"
" all levels. Note that this oprion also uses PLT and tile markers, \n"
" as well as RPCL order. Power of 2 must be used.\n"
" Only valid for output j2c images. Default is no precincts used.\n"
" -b, --blocks <n>\n"
" Dimension of coding blocks in pixels. Blocks are assumed square. Power of 2 must\n"
" be used. Blocks must be smaller than precincts.\n"
" Only valid for output j2c images. Default is 64.\n"
" -log, --logmetrics <metric>\n"
" Log performance data for <metric>. Results in <metric>.slp\n"
" Note: so far, only ImageCompressionTester has been tested.\n"
" -r, --analyzeperformance\n"
" -a, --analyzeperformance\n"
" Create a report comparing <metric>_baseline.slp with current <metric>.slp\n"
" Results in <metric>_report.csv"
" Results in <metric>_report.csv\n"
" -s, --image-stats\n"
" Output stats for each input and output image.\n"
"\n";
......@@ -110,10 +126,11 @@ void output_image_stats(LLPointer<LLImageFormatted> image, const std::string &fi
}
// Load an image from file and return a raw (decompressed) instance of its data
LLPointer<LLImageRaw> load_image(const std::string &src_filename, bool output_stats)
LLPointer<LLImageRaw> load_image(const std::string &src_filename, bool output_stats, bool use_discard_level, int discard_level, bool use_region, int* region)
{
LLPointer<LLImageFormatted> image = create_image(src_filename);
// This just load the image file stream into a buffer. No decoding done.
if (!image->load(src_filename))
{
return NULL;
......@@ -131,6 +148,17 @@ LLPointer<LLImageRaw> load_image(const std::string &src_filename, bool output_st
}
LLPointer<LLImageRaw> raw_image = new LLImageRaw;
// Set the image restriction on load in the case of a j2c image
if ((image->getCodec() == IMG_CODEC_J2C) && (use_discard_level || use_region))
{
int discard = (use_discard_level ? discard_level : -1);
int* reg = (use_region ? region : NULL);
// That method doesn't exist (and likely, doesn't make sense) for any other image file format
// hence the required cryptic cast.
((LLImageJ2C*)(image.get()))->initDecode(*raw_image, discard, reg);
}
if (!image->decode(raw_image, 0.0f))
{
return NULL;
......@@ -280,8 +308,17 @@ int main(int argc, char** argv)
// List of input and output files
std::list<std::string> input_filenames;
std::list<std::string> output_filenames;
// Other optional parsed arguments
bool analyze_performance = false;
bool image_stats = false;
bool use_region = false;
int region[4];
bool use_discard_level = false;
int discard_level = 0;
bool use_precincts = false;
int precincts_size;
bool use_blocks = false;
int blocks_size;
// Init whatever is necessary
ll_init_apr();
......@@ -323,6 +360,81 @@ int main(int argc, char** argv)
file_name = argv[arg+1]; // Next argument and loop over
}
}
else if ((!strcmp(argv[arg], "--region") || !strcmp(argv[arg], "-r")) && arg < argc-1)
{
std::string value_str = argv[arg+1];
int index = 0;
while (value_str[0] != '-') // if arg starts with '-', it's the next option
{
int value = atoi(value_str.c_str());
region[index++] = value;
arg += 1; // Definitely skip that arg now we know it's a number
if ((arg + 1) == argc) // Break out of the loop if we reach the end of the arg list
break;
if (index == 4) // Break out of the loop if we captured 4 values already
break;
value_str = argv[arg+1]; // Next argument and loop over
}
if (index == 4)
{
use_region = true;
}
else
{
std::cout << "--region arguments invalid" << std::endl;
}
}
else if (!strcmp(argv[arg], "--discard_level") || !strcmp(argv[arg], "-d"))
{
std::string value_str;
if ((arg + 1) < argc)
{
value_str = argv[arg+1];
}
if (((arg + 1) >= argc) || (value_str[0] == '-'))
{
std::cout << "No valid --discard_level argument given, discard_level ignored" << std::endl;
}
else
{
use_discard_level = true;
discard_level = atoi(value_str.c_str());
}
}
else if (!strcmp(argv[arg], "--precincts") || !strcmp(argv[arg], "-p"))
{
std::string value_str;
if ((arg + 1) < argc)
{
value_str = argv[arg+1];
}
if (((arg + 1) >= argc) || (value_str[0] == '-'))
{
std::cout << "No valid --precincts argument given, precincts ignored" << std::endl;
}
else
{
use_precincts = true;
precincts_size = atoi(value_str.c_str());
}
}
else if (!strcmp(argv[arg], "--blocks") || !strcmp(argv[arg], "-b"))
{
std::string value_str;
if ((arg + 1) < argc)
{
value_str = argv[arg+1];
}
if (((arg + 1) >= argc) || (value_str[0] == '-'))
{
std::cout << "No valid --blocks argument given, blocks ignored" << std::endl;
}
else
{
use_blocks = true;
blocks_size = atoi(value_str.c_str());
}
}
else if (!strcmp(argv[arg], "--logmetrics") || !strcmp(argv[arg], "-log"))
{
// '--logmetrics' needs to be specified with a named test metric argument
......@@ -346,7 +458,7 @@ int main(int argc, char** argv)
break;
}
}
else if (!strcmp(argv[arg], "--analyzeperformance") || !strcmp(argv[arg], "-r"))
else if (!strcmp(argv[arg], "--analyzeperformance") || !strcmp(argv[arg], "-a"))
{
analyze_performance = true;
}
......@@ -364,7 +476,7 @@ int main(int argc, char** argv)
}
if (analyze_performance && !LLFastTimer::sMetricLog)
{
std::cout << "Cannot create perf report if no perf gathered (i.e. use argument -log <perf> with -r) -> exit" << std::endl;
std::cout << "Cannot create perf report if no perf gathered (i.e. use argument -log <perf> with -a) -> exit" << std::endl;
return 0;
}
......@@ -385,7 +497,7 @@ int main(int argc, char** argv)
for (; in_file != in_end; ++in_file)
{
// Load file
LLPointer<LLImageRaw> raw_image = load_image(*in_file, image_stats);
LLPointer<LLImageRaw> raw_image = load_image(*in_file, image_stats, use_discard_level, discard_level, use_region, region);
if (!raw_image)
{
std::cout << "Error: Image " << *in_file << " could not be loaded" << std::endl;
......
......@@ -139,6 +139,10 @@ BOOL LLImageJ2C::updateData()
return res;
}
BOOL LLImageJ2C::initDecode(LLImageRaw &raw_image, int discard_level, int* region)
{
return mImpl->initDecode(*this,raw_image,discard_level,region);
}
BOOL LLImageJ2C::decode(LLImageRaw *raw_imagep, F32 decode_time)
{
......@@ -251,6 +255,9 @@ S32 LLImageJ2C::calcHeaderSizeJ2C()
//static
S32 LLImageJ2C::calcDataSizeJ2C(S32 w, S32 h, S32 comp, S32 discard_level, F32 rate)
{
// Note: this only provides an *estimate* of the size in bytes of an image level
// *TODO: find a way to read the true size (when available) and convey the fact
// that the result is an estimate in the other cases
if (rate <= 0.f) rate = .125f;
while (discard_level > 0)
{
......
......@@ -56,6 +56,7 @@ class LLImageJ2C : public LLImageFormatted
/*virtual*/ void resetLastError();
/*virtual*/ void setLastError(const std::string& message, const std::string& filename = std::string());
BOOL initDecode(LLImageRaw &raw_image, int discard_level, int* region);
// Encode with comment text
BOOL encode(const LLImageRaw *raw_imagep, const char* comment_text, F32 encode_time=0.0);
......@@ -117,6 +118,7 @@ class LLImageJ2CImpl
virtual BOOL decodeImpl(LLImageJ2C &base, LLImageRaw &raw_image, F32 decode_time, S32 first_channel, S32 max_channel_count) = 0;
virtual BOOL encodeImpl(LLImageJ2C &base, const LLImageRaw &raw_image, const char* comment_text, F32 encode_time=0.0,
BOOL reversible=FALSE) = 0;
virtual BOOL initDecode(LLImageJ2C &base, LLImageRaw &raw_image, int discard_level = -1, int* region = NULL) = 0;
friend class LLImageJ2C;
};
......
......@@ -107,6 +107,11 @@ LLImageJ2COJ::~LLImageJ2COJ()
{
}
BOOL LLImageJ2COJ::initDecode(LLImageJ2C &base, LLImageRaw &raw_image, int discard_level, int* region)
{
// No specific implementaion for this method in the OpenJpeg case
return FALSE;
}
BOOL LLImageJ2COJ::decodeImpl(LLImageJ2C &base, LLImageRaw &raw_image, F32 decode_time, S32 first_channel, S32 max_channel_count)
{
......
......@@ -39,6 +39,7 @@ class LLImageJ2COJ : public LLImageJ2CImpl
/*virtual*/ BOOL decodeImpl(LLImageJ2C &base, LLImageRaw &raw_image, F32 decode_time, S32 first_channel, S32 max_channel_count);
/*virtual*/ BOOL encodeImpl(LLImageJ2C &base, const LLImageRaw &raw_image, const char* comment_text, F32 encode_time=0.0,
BOOL reversible = FALSE);
/*virtual*/ BOOL initDecode(LLImageJ2C &base, LLImageRaw &raw_image, int discard_level = -1, int* region = NULL);
};
#endif
......@@ -106,7 +106,11 @@ const char* fallbackEngineInfoLLImageJ2CImpl()
class LLKDUDecodeState
{
public:
LLKDUDecodeState(kdu_tile tile, kdu_byte *buf, S32 row_gap);
~LLKDUDecodeState();
BOOL processTileDecode(F32 decode_time, BOOL limit_time = TRUE);
private:
S32 mNumComponents;
BOOL mUseYCC;
kdu_dims mDims;
......@@ -116,20 +120,10 @@ class LLKDUDecodeState
kdu_pull_ifc mEngines[4];
bool mReversible[4]; // Some components may be reversible and others not
int mBitDepths[4]; // Original bit-depth may be quite different from 8
kdu_tile mTile;
kdu_byte *mBuf;
S32 mRowGap;
LLKDUDecodeState(kdu_tile tile, kdu_byte *buf, S32 row_gap);
~LLKDUDecodeState();
BOOL processTileDecode(F32 decode_time, BOOL limit_time = TRUE);
public:
int *AssignLayerBytes(siz_params *siz, int &num_specs);
void setupCodeStream(BOOL keep_codestream, LLImageJ2CKDU::ECodeStreamMode mode);
BOOL initDecode(LLImageRaw &raw_image, F32 decode_time, LLImageJ2CKDU::ECodeStreamMode mode, S32 first_channel, S32 max_channel_count );
};
void ll_kdu_error( void )
......@@ -327,7 +321,12 @@ void LLImageJ2CKDU::cleanupCodeStream()
mTileIndicesp = NULL;
}
BOOL LLImageJ2CKDU::initDecode(LLImageJ2C &base, LLImageRaw &raw_image, F32 decode_time, ECodeStreamMode mode, S32 first_channel, S32 max_channel_count )
BOOL LLImageJ2CKDU::initDecode(LLImageJ2C &base, LLImageRaw &raw_image, int discard_level, int* region)
{
return initDecode(base,raw_image,0.0f,MODE_FAST,0,4,discard_level,region);
}
BOOL LLImageJ2CKDU::initDecode(LLImageJ2C &base, LLImageRaw &raw_image, F32 decode_time, ECodeStreamMode mode, S32 first_channel, S32 max_channel_count, int discard_level, int* region)
{
base.resetLastError();
......@@ -340,7 +339,20 @@ BOOL LLImageJ2CKDU::initDecode(LLImageJ2C &base, LLImageRaw &raw_image, F32 deco
mRawImagep = &raw_image;
mCodeStreamp->change_appearance(false, true, false);
mCodeStreamp->apply_input_restrictions(first_channel,max_channel_count,base.getRawDiscardLevel(),0,NULL);
// Apply loading discard level and cropping if required
kdu_dims* region_kdu = NULL;
if (region != NULL)
{
region_kdu = new kdu_dims;
region_kdu->pos.x = region[0];
region_kdu->pos.y = region[1];
region_kdu->size.x = region[2] - region[0];
region_kdu->size.y = region[3] - region[1];
}
int discard = (discard_level != -1 ? discard_level : base.getRawDiscardLevel());
mCodeStreamp->apply_input_restrictions( first_channel, max_channel_count, discard, 0, region_kdu);
kdu_dims dims; mCodeStreamp->get_dims(0,dims);
S32 channels = base.getComponents() - first_channel;
......
......@@ -58,11 +58,12 @@ class LLImageJ2CKDU : public LLImageJ2CImpl
/*virtual*/ BOOL decodeImpl(LLImageJ2C &base, LLImageRaw &raw_image, F32 decode_time, S32 first_channel, S32 max_channel_count);
/*virtual*/ BOOL encodeImpl(LLImageJ2C &base, const LLImageRaw &raw_image, const char* comment_text, F32 encode_time=0.0,
BOOL reversible=FALSE);
/*virtual*/ BOOL initDecode(LLImageJ2C &base, LLImageRaw &raw_image, int discard_level = -1, int* region = NULL);
private:
BOOL initDecode(LLImageJ2C &base, LLImageRaw &raw_image, F32 decode_time, ECodeStreamMode mode, S32 first_channel, S32 max_channel_count, int discard_level = -1, int* region = NULL);
void setupCodeStream(LLImageJ2C &base, BOOL keep_codestream, ECodeStreamMode mode);
void cleanupCodeStream();
BOOL initDecode(LLImageJ2C &base, LLImageRaw &raw_image, F32 decode_time, ECodeStreamMode mode, S32 first_channel, S32 max_channel_count );
// Encode variable
LLKDUMemSource *mInputp;
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment