Skip to content

Commit ce29c9b

Browse files
committed
encoder: add option for channel remap
refer to GH-102
1 parent 28f3017 commit ce29c9b

File tree

4 files changed

+98
-2
lines changed

4 files changed

+98
-2
lines changed

libgpujpeg/gpujpeg_encoder.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -234,6 +234,15 @@ gpujpeg_encoder_suggest_restart_interval(const struct gpujpeg_image_parameters*
234234
/// input image is vertically flipped (bottom-up): values @ref GPUJPEG_VAL_TRUE or @ref GPUJPEG_VAL_FALSE
235235
#define GPUJPEG_ENC_OPT_FLIPPED_BOOL "enc_opt_flipped"
236236

237+
/**
238+
* remaps input channel order, format "XYZ" or "XYZW" where the letters stand for input channel
239+
* indices (0-indexed) mapped to output position; so eg. remapping from ARGB to RGBA will be
240+
* "1230". If number of channes doesn't equal the length of the string, the characters are invalid
241+
* or out-of bound, the behavior is undefined. set to "" (empty string) to revert this setting.
242+
* Placeholder'Z' or 'F' can be used instead of numbers to fill out channel with zeros or all-ones.
243+
*/
244+
#define GPUJPEG_ENC_OPT_CHANNEL_REMAP "enc_opt_channel_remap"
245+
237246
/**
238247
* sets encoder option
239248
* @retval GPUJPEG_NOERR option was sucessfully set

src/gpujpeg_encoder.c

Lines changed: 39 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -652,6 +652,42 @@ gpujpeg_encoder_set_jpeg_header(struct gpujpeg_encoder *encoder, enum gpujpeg_he
652652
encoder->header_type = header_type;
653653
}
654654

655+
static int
656+
enc_opt_set_channel_remap(struct gpujpeg_encoder* encoder, const char* val)
657+
{
658+
if ( strcmp(val, "help") == 0 ) {
659+
printf("syntax for " GPUJPEG_ENC_OPT_CHANNEL_REMAP ":\n");
660+
printf("\t\"XYZ\" or \"XYZW\" where the letters are input channel indices\n");
661+
printf("\tplaceholder 'Z' or 'F' can be used to set the channel to all-zeros or all-ones\n");
662+
printf("\n");
663+
printf("examples:\n");
664+
printf("\t\"1230\" or \"123F\" to map ARGB to RGBA\n");
665+
return GPUJPEG_ERROR;
666+
}
667+
if ( strlen(val) >= GPUJPEG_MAX_COMPONENT_COUNT ) {
668+
ERROR_MSG("Mapping for more than %d channels specified!\n", GPUJPEG_MAX_COMPONENT_COUNT);
669+
return GPUJPEG_ERROR;
670+
}
671+
encoder->coder.preprocessor.channel_remap = 0; // clear old
672+
while ( *val != '\0' ) {
673+
encoder->coder.preprocessor.channel_remap >>= 4;
674+
int src_chan = *val - '0';
675+
if ( *val == 'F' ) {
676+
src_chan = 4;
677+
}
678+
else if ( *val == 'Z' ) {
679+
src_chan = 5;
680+
}
681+
else if ( src_chan >= GPUJPEG_MAX_COMPONENT_COUNT ) {
682+
ERROR_MSG("Invalid channel %c for " GPUJPEG_ENC_OPT_CHANNEL_REMAP "!\n", *val);
683+
return GPUJPEG_ERROR;
684+
}
685+
encoder->coder.preprocessor.channel_remap |= src_chan << 12;
686+
val++;
687+
}
688+
return GPUJPEG_NOERR;
689+
}
690+
655691
GPUJPEG_API int
656692
gpujpeg_encoder_set_option(struct gpujpeg_encoder* encoder, const char *opt, const char* val)
657693
{
@@ -699,7 +735,9 @@ gpujpeg_encoder_set_option(struct gpujpeg_encoder* encoder, const char *opt, con
699735
ERROR_MSG("Unknown option %s for " GPUJPEG_ENC_OPT_FLIPPED_BOOL "\n", val);
700736
return GPUJPEG_ERROR;
701737
}
702-
return GPUJPEG_NOERR;
738+
}
739+
if ( strcmp(opt, GPUJPEG_ENC_OPT_CHANNEL_REMAP) == 0 ) {
740+
return enc_opt_set_channel_remap(encoder, val);
703741
}
704742
ERROR_MSG("Invalid encoder option: %s!\n", opt);
705743
return GPUJPEG_ERROR;

src/gpujpeg_preprocessor.cu

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -494,6 +494,47 @@ flip_lines(struct gpujpeg_encoder* encoder)
494494
return 0;
495495
}
496496

497+
template <enum gpujpeg_pixel_format>
498+
__global__ void
499+
channel_remap_kernel(uint8_t* data, int width, int height, unsigned int byte_map);
500+
501+
template <>
502+
__global__ void
503+
channel_remap_kernel<GPUJPEG_4444_U8_P0123>(uint8_t* data, int width, int height, unsigned int byte_map)
504+
{
505+
int x = blockIdx.x * blockDim.x + threadIdx.x; // column index
506+
int y = blockIdx.y * blockDim.y + threadIdx.y; // row index
507+
508+
if ( x >= width || y >= height ) {
509+
return;
510+
}
511+
512+
uint32_t* data32 = (uint32_t*)data;
513+
uint32_t val = data32[y * width + x];
514+
data32[y * width + x] = __byte_perm(val, 0xFF, byte_map);
515+
}
516+
517+
static int
518+
channel_remap(struct gpujpeg_encoder* encoder)
519+
{
520+
struct gpujpeg_coder* coder = &encoder->coder;
521+
if ( coder->param_image.pixel_format == GPUJPEG_4444_U8_P0123 ) {
522+
dim3 block(16, 16);
523+
int width = coder->param_image.width;
524+
int height = coder->param_image.height;
525+
dim3 grid((width + block.x - 1) / block.x, (height + block.y - 1) / block.y);
526+
channel_remap_kernel<GPUJPEG_4444_U8_P0123><<<grid, block, 0, encoder->stream>>>(
527+
encoder->coder.d_data_raw, width, height, coder->preprocessor.channel_remap);
528+
}
529+
else {
530+
ERROR_MSG("Pixel format %s currently unsupported for channel remap!\n",
531+
gpujpeg_pixel_format_get_name(coder->param_image.pixel_format));
532+
return -1;
533+
}
534+
gpujpeg_cuda_check_error("channel_remap_kernel failed", return -1);
535+
return 0;
536+
}
537+
497538
/* Documented at declaration */
498539
int
499540
gpujpeg_preprocessor_encode(struct gpujpeg_encoder * encoder)
@@ -503,6 +544,13 @@ gpujpeg_preprocessor_encode(struct gpujpeg_encoder * encoder)
503544
assert(coder->param_image.width_padding == 0 ||
504545
(coder->param_image.pixel_format == GPUJPEG_444_U8_P012 && coder->preprocessor.kernel != nullptr));
505546

547+
if ( coder->preprocessor.channel_remap != 0 ) {
548+
const int ret = channel_remap(encoder);
549+
if ( ret != 0 ) {
550+
return ret;
551+
}
552+
}
553+
506554
int ret = coder->preprocessor.kernel != nullptr ? gpujpeg_preprocessor_encode_interlaced(encoder)
507555
: gpujpeg_preprocessor_encoder_copy_planar_data(encoder);
508556
if (ret != 0) {

src/gpujpeg_preprocessor.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,8 @@ struct gpujpeg_preprocessor_data
6969
struct gpujpeg_preprocessor
7070
{
7171
void* kernel; // function poitner
72-
bool input_flipped; // [preprocess only] input is flipped
72+
bool input_flipped; ///< [preprocess only] input buf is flipped
73+
unsigned int channel_remap; ///< remap input channels if != 0; currently preproecss only
7374
struct gpujpeg_preprocessor_data data;
7475
};
7576

0 commit comments

Comments
 (0)