📄 ebcot_encoder.c
字号:
/*****************************************************************************/
/* File name: "ebcot_encoder.c" */
/* Author: David Taubman */
/* Copyright 1998, Hewlett-Packard Company */
/* All rights reserved */
/*****************************************************************************/
#include <local_heap.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <time.h>
#include <assert.h>
#include <line_block_ifc.h>
#include <ebcot_common.h>
#include "ebcot_encoder.h"
#include "ebcot_arith_encoder.h"
#include "ebcot_send_bits.h"
/* ========================================================================= */
/* ----------------------- Compressed Bit-Stream Heap ---------------------- */
/* ========================================================================= */
/*****************************************************************************/
/* STATIC codeword_heap__get_unit */
/*****************************************************************************/
static heap_unit_ptr
codeword_heap__get_unit(codeword_heap_ref self)
{
heap_group_ptr scan;
heap_unit_ptr unit;
int i;
for (scan=self->heap; scan != NULL; scan=scan->next)
if (scan->free_units)
break;
if (scan == NULL)
{
scan = (heap_group_ptr)
local_malloc(sizeof(heap_group));
scan->next = self->heap;
self->heap = scan;
scan->free_units = HEAP_GROUP_UNITS;
for (unit=scan->units, i=HEAP_GROUP_UNITS; i > 0; i--, unit++)
{
unit->next = NULL;
unit->group = NULL;
}
}
for (unit=scan->units, i=HEAP_GROUP_UNITS; i > 0; i--, unit++)
if (unit->group == NULL)
break;
assert(i > 0);
scan->free_units--;
unit->group = scan;
unit->next = NULL;
return(unit);
}
/*****************************************************************************/
/* STATIC codeword_heap__return_unit */
/*****************************************************************************/
static void
codeword_heap__return_unit(codeword_heap_ref self, heap_unit_ptr unit)
{
heap_group_ptr group;
group = unit->group;
assert((group != NULL) && (group->free_units < HEAP_GROUP_UNITS));
group->free_units++;
unit->group = NULL;
}
/*****************************************************************************/
/* STATIC codeword_heap__terminate */
/*****************************************************************************/
static void
codeword_heap__terminate(codeword_heap_ref self)
{
heap_group_ptr tmp;
while ((tmp=self->heap) != NULL)
{
self->heap = tmp->next;
local_free(tmp);
}
local_free(self);
}
/*****************************************************************************/
/* STATIC create_codeword_heap */
/*****************************************************************************/
static codeword_heap_ref
create_codeword_heap(void)
{
codeword_heap_ref result;
result = (codeword_heap_ref) local_malloc(sizeof(codeword_heap_obj));
memset(result,0,sizeof(codeword_heap_obj));
result->get_unit = codeword_heap__get_unit;
result->return_unit = codeword_heap__return_unit;
result->terminate = codeword_heap__terminate;
return(result);
}
/* ========================================================================= */
/* -------------------- Configuration Utility Functions -------------------- */
/* ========================================================================= */
/*****************************************************************************/
/* STATIC start_symbol_log */
/*****************************************************************************/
#ifdef LOG_SYMBOLS
static FILE *
start_symbol_log(band_info_ptr band, block_info_ptr block)
{
FILE *fp;
char fname[81];
sprintf(fname,"symbol_log_%d_%d_%d",band->level_idx,band->band_idx,
(int)(block-band->blocks));
fp = fopen(fname,"wb");
assert(fp != NULL);
return(fp);
}
#endif /* LOG_SYMBOLS */
/*****************************************************************************/
/* STATIC process_profile_flags */
/*****************************************************************************/
static int
process_profile_flags(int profile)
/* This function checks that the `profile' flags can be
satisfied and returns a potentially augmented set of profile flags
which will actually be supported. */
{
profile |= PROFILE__RANDOM_ACCESS; /* Always have this feature. */
profile |= PROFILE__RESOLUTION_PARSABLE; /* Always have this too. */
profile |= PROFILE__COMPONENT_PARSABLE; /* Always have this too. */
if (profile & PROFILE__SNR_PROGRESSIVE)
profile |= PROFILE__SNR_PARSABLE; /* Get this for free. */
if (!(profile & PROFILE__SNR_PARSABLE))
profile |= PROFILE__RESOLUTION_PROGRESSIVE; /* 1-pass always has this. */
return(profile);
}
/*****************************************************************************/
/* STATIC get_block_dimensions */
/*****************************************************************************/
static void
get_block_dimensions(int argc, char *argv[],
int *block_dim, int *block_height, int *subblock_dim)
{
int i, dim, sub_dim, height;
dim = 64; sub_dim = 16; height = 0;
for (i=0; i < (argc-1); i++)
if (strcmp(argv[i],"-Cblk") == 0)
{
argv[i] = "";
if (sscanf(argv[i+1],"%d",&dim) == 0)
{
fprintf(stderr,"The \"-Cblk\" argument requires an integer "
"parameter!\n");
exit(-1);
}
argv[i+1] = "";
}
else if (strcmp(argv[i],"-Csub") == 0)
{
argv[i] = "";
if (sscanf(argv[i+1],"%d",&sub_dim) == 0)
{
fprintf(stderr,"The \"-Csub\" argument requires an integer "
"parameter!\n");
exit(-1);
}
argv[i+1] = "";
}
else if (strcmp(argv[i],"-Cheight") == 0)
{
argv[i] = "";
if (sscanf(argv[i+1],"%d",&height) == 0)
{
fprintf(stderr,"The \"-Cheight\" argument requires an integer "
"parameter!\n");
exit(-1);
}
argv[i+1] = "";
}
if (height == 0)
height = dim;
if (sub_dim > dim)
sub_dim = dim;
if ((sub_dim < 1) || (dim > 256) || (sub_dim & 3) || (dim & 3))
{
fprintf(stderr,"Illegal block dimensions supplied via command line "
"arguments\n \"-Cblk\" and/or \"-Csub\"!\n Block dimensions "
"must be positive integers, not exceeding 256, which\n must "
"be divisible by 4.\n");
exit(-1);
}
if ((height < 1) || (height > dim))
{
fprintf(stderr,"Illegal block height supplied via command line "
"argument\n \"-Cheight\"! Block height may not exceed the "
"main block\n dimension supplied via `-Cblk'!\n");
exit(-1);
}
*block_dim = dim;
*subblock_dim = sub_dim;
*block_height = height;
}
/*****************************************************************************/
/* STATIC set_default_scalable_layer_info */
/*****************************************************************************/
static void
set_default_scalable_layer_info(the_encoder_ref self, int dedicated_bytes,
int max_extra_bytes, int rows, int cols)
/* This function sets up the default layer parameters for SNR-scalable
bit-streams. The default settings have been selected so as to avoid
bias toward any particular bit-rates; if the set of desired bit-rates
is known ahead of time, these should be supplied via the `-Clayers'
command line argument; performance can always be improved in this way.
The default is to include 50 layers in the bit-stream for every
resolution level, with the average bit-rate of these layers spaced
approximately logarithmically (no attempt is made to achieve exact
bit-rates) between 0.015 bpp and 2.0 bpp. If the maximum desired bit-rate
is less than 2.0 bpp, some of these default layers are dropped. If the
maximum desired bit-rate is more than 2.0 bpp, some default layers are
added. */
{
int total_layers, n;
double r, log_min, log_spacing, log_max, bytes_to_bpp;
bytes_to_bpp = 8.0 / ((double)(rows*cols));
log_max = log(2.0);
log_min = log(0.015);
log_spacing = (log_max-log_min) / 49.0;
log_max = log(((double)(max_extra_bytes+dedicated_bytes)) * bytes_to_bpp);
total_layers = 1 + (int) floor(0.5 + (log_max-log_min)/log_spacing);
log_spacing = (log_max-log_min) / (total_layers-1);
self->bitstream_layers = total_layers;
self->layer_info = (bitstream_layer_info_ptr)
local_realloc(self->layer_info,
sizeof(bitstream_layer_info)*(size_t) total_layers);
for (r=log_min, n=0; n < (total_layers-1); n++, r += log_spacing)
{
self->layer_info[n].max_cumulative_bytes =
((int) floor(0.5 + exp(r) / bytes_to_bpp)) - dedicated_bytes;
self->layer_info[n].actual_cumulative_bytes = 0;
self->layer_info[n].optimize = (n==0)?1:0;
self->layer_info[n].rd_threshold = 0;
}
self->layer_info[n].max_cumulative_bytes = max_extra_bytes;
self->layer_info[n].actual_cumulative_bytes = 0;
self->layer_info[n].optimize = 1;
self->layer_info[n].rd_threshold = 0;
}
/*****************************************************************************/
/* STATIC rd_optimized_truncation */
/*****************************************************************************/
static int
rd_optimized_truncation_allowed(int argc, char *argv[], int profile)
/* Parses the argument list to see if rate-distortion optimization should
be allowed. If not, the function returns 0, which will ultimately
cause all bit-rate limits to be ignored. */
{
for (; argc > 0; argc--, argv++)
if (strcmp(*argv,"-Cno_rd") == 0)
{
*argv = "";
return(0);
}
return(1);
}
/*****************************************************************************/
/* STATIC get_layer_info */
/*****************************************************************************/
static void
get_layer_info(the_encoder_ref self, int argc, char *argv[],
int dedicated_bytes, int max_extra_bytes,
int rows, int cols)
{
double rate;
int extra_layers, total_layers, max_bytes, last_max_bytes, optimize, n;
for (; argc > 0; argc--, argv++)
if ((strcmp(*argv,"-Clayers") == 0) && (argc > 1))
{
*(argv++) = ""; argc--;
break;
}
self->bitstream_layers = 1;
self->layer_info = (bitstream_layer_info_ptr)
local_malloc(sizeof(bitstream_layer_info));
if (!(self->profile & (PROFILE__SNR_PROGRESSIVE | PROFILE__SNR_PARSABLE)))
{ /* Want only one layer. */
if (argc > 0)
{
fprintf(stderr,"The `-Clayers' argument is only allowed in "
"conjunction with\n the SNR-PROGRESSIVE or SNR-PARSABLE "
"bit-stream profiles!!\n");
exit(-1);
}
self->layer_info->max_cumulative_bytes = max_extra_bytes;
self->layer_info->actual_cumulative_bytes = 0;
self->layer_info->optimize = 1;
self->layer_info->rd_threshold = 0;
return;
}
else if (argc == 0)
{ /* Default SNR-scalable bit-stream. */
set_default_scalable_layer_info(self,dedicated_bytes,
max_extra_bytes,rows,cols);
return;
}
n = 0;
last_max_bytes = 0;
total_layers = 0;
while ((argc > 0) && (sscanf(*argv,"%lf",&rate) == 1))
{
*(argv++) = ""; argc--;
extra_layers = 0;
if ((argc > 0) && ((*argv)[0] == '+'))
{
if ((sscanf((*argv)+1,"%d",&extra_layers)==0) || (extra_layers < 0))
{
fprintf(stderr,"The `-Clayers' argument contains an "
"incorrectly formatted\n parameter identifying "
"extra bit-stream layers!\n");
exit(-1);
}
*(argv++) = ""; argc--;
}
max_bytes = (int)(rate * 0.125 * (double)(rows*cols));
max_bytes -= dedicated_bytes;
if (max_bytes >= max_extra_bytes)
break;
total_layers += 1 + extra_layers;
self->layer_info = (bitstream_layer_info_ptr)
local_realloc(self->layer_info,sizeof(bitstream_layer_info)*
(size_t)(total_layers+1));
if (max_bytes <= last_max_bytes)
{
fprintf(stderr,"The specific rate targets supplied to "
"the `-Clayers'\n argument must be strictly "
"increasing and all less than\n the target bit-rate "
"for the overall bit-stream!\n");
exit(-1);
}
last_max_bytes = max_bytes;
for (optimize=1; extra_layers >= 0; extra_layers--, n++, optimize=0)
{
self->layer_info[n].max_cumulative_bytes = max_bytes;
self->layer_info[n].actual_cumulative_bytes = 0;
self->layer_info[n].optimize = optimize;
self->layer_info[n].rd_threshold = 0;
}
}
max_bytes = max_extra_bytes;
assert((max_bytes > last_max_bytes) && (n == total_layers));
total_layers++; /* Last layer always holds the overall rate target. */
self->layer_info[n].max_cumulative_bytes = max_bytes;
self->layer_info[n].actual_cumulative_bytes = 0;
self->layer_info[n].optimize = 1;
self->layer_info[n].rd_threshold = 0;
self->bitstream_layers = total_layers;
/* Now go through and assign target bit-rates to the layers which are
not marked for optimization. */
for(n=0; n < (total_layers-1); n++)
{
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -