|
|
@@ -275,9 +275,101 @@ static int add_metadata(int count, int type, |
|
|
|
}; |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
|
* Map stored raw sensor values into linear reference values (see: DNG Specification - Chapter 5) |
|
|
|
*/ |
|
|
|
static uint16_t av_always_inline dng_process_color16(uint16_t value, |
|
|
|
const uint16_t *lut, |
|
|
|
uint16_t black_level, |
|
|
|
float scale_factor) |
|
|
|
{ |
|
|
|
float value_norm; |
|
|
|
|
|
|
|
// Lookup table lookup |
|
|
|
if (lut) |
|
|
|
value = lut[value]; |
|
|
|
|
|
|
|
// Black level subtraction |
|
|
|
value = av_clip_uint16_c((unsigned)value - black_level); |
|
|
|
|
|
|
|
// Color scaling |
|
|
|
value_norm = (float)value * scale_factor; |
|
|
|
|
|
|
|
value = av_clip_uint16_c(value_norm * 65535); |
|
|
|
|
|
|
|
return value; |
|
|
|
} |
|
|
|
|
|
|
|
static uint16_t av_always_inline dng_process_color8(uint16_t value, |
|
|
|
const uint16_t *lut, |
|
|
|
uint16_t black_level, |
|
|
|
float scale_factor) |
|
|
|
{ |
|
|
|
return dng_process_color16(value, lut, black_level, scale_factor) >> 8; |
|
|
|
} |
|
|
|
|
|
|
|
static void av_always_inline dng_blit(TiffContext *s, uint8_t *dst, int dst_stride, |
|
|
|
const uint8_t *src, int src_stride, int width, int height, |
|
|
|
int is_single_comp, int is_u16); |
|
|
|
int is_single_comp, int is_u16) |
|
|
|
{ |
|
|
|
int line, col; |
|
|
|
float scale_factor; |
|
|
|
|
|
|
|
scale_factor = 1.0f / (s->white_level - s->black_level); |
|
|
|
|
|
|
|
if (is_single_comp) { |
|
|
|
if (!is_u16) |
|
|
|
return; /* <= 8bpp unsupported */ |
|
|
|
|
|
|
|
/* Image is double the width and half the height we need, each row comprises 2 rows of the output |
|
|
|
(split vertically in the middle). */ |
|
|
|
for (line = 0; line < height / 2; line++) { |
|
|
|
uint16_t *dst_u16 = (uint16_t *)dst; |
|
|
|
uint16_t *src_u16 = (uint16_t *)src; |
|
|
|
|
|
|
|
/* Blit first half of input row row to initial row of output */ |
|
|
|
for (col = 0; col < width; col++) |
|
|
|
*dst_u16++ = dng_process_color16(*src_u16++, s->dng_lut, s->black_level, scale_factor); |
|
|
|
|
|
|
|
/* Advance the destination pointer by a row (source pointer remains in the same place) */ |
|
|
|
dst += dst_stride * sizeof(uint16_t); |
|
|
|
dst_u16 = (uint16_t *)dst; |
|
|
|
|
|
|
|
/* Blit second half of input row row to next row of output */ |
|
|
|
for (col = 0; col < width; col++) |
|
|
|
*dst_u16++ = dng_process_color16(*src_u16++, s->dng_lut, s->black_level, scale_factor); |
|
|
|
|
|
|
|
dst += dst_stride * sizeof(uint16_t); |
|
|
|
src += src_stride * sizeof(uint16_t); |
|
|
|
} |
|
|
|
} else { |
|
|
|
/* Input and output image are the same size and the MJpeg decoder has done per-component |
|
|
|
deinterleaving, so blitting here is straightforward. */ |
|
|
|
if (is_u16) { |
|
|
|
for (line = 0; line < height; line++) { |
|
|
|
uint16_t *dst_u16 = (uint16_t *)dst; |
|
|
|
uint16_t *src_u16 = (uint16_t *)src; |
|
|
|
|
|
|
|
for (col = 0; col < width; col++) |
|
|
|
*dst_u16++ = dng_process_color16(*src_u16++, s->dng_lut, s->black_level, scale_factor); |
|
|
|
|
|
|
|
dst += dst_stride * sizeof(uint16_t); |
|
|
|
src += src_stride * sizeof(uint16_t); |
|
|
|
} |
|
|
|
} else { |
|
|
|
for (line = 0; line < height; line++) { |
|
|
|
uint8_t *dst_u8 = dst; |
|
|
|
const uint8_t *src_u8 = src; |
|
|
|
|
|
|
|
for (col = 0; col < width; col++) |
|
|
|
*dst_u8++ = dng_process_color8(*src_u8++, s->dng_lut, s->black_level, scale_factor); |
|
|
|
|
|
|
|
dst += dst_stride; |
|
|
|
src += src_stride; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
static void av_always_inline horizontal_fill(TiffContext *s, |
|
|
|
unsigned int bpp, uint8_t* dst, |
|
|
@@ -553,7 +645,108 @@ static int tiff_unpack_fax(TiffContext *s, uint8_t *dst, int stride, |
|
|
|
return ret; |
|
|
|
} |
|
|
|
|
|
|
|
static int dng_decode_strip(AVCodecContext *avctx, AVFrame *frame); |
|
|
|
static int dng_decode_jpeg(AVCodecContext *avctx, AVFrame *frame, |
|
|
|
int tile_byte_count, int dst_x, int dst_y, int w, int h) |
|
|
|
{ |
|
|
|
TiffContext *s = avctx->priv_data; |
|
|
|
uint8_t *dst_data, *src_data; |
|
|
|
uint32_t dst_offset; /* offset from dst buffer in pixels */ |
|
|
|
int is_single_comp, is_u16, pixel_size; |
|
|
|
int ret; |
|
|
|
|
|
|
|
if (tile_byte_count < 0 || tile_byte_count > bytestream2_get_bytes_left(&s->gb)) |
|
|
|
return AVERROR_INVALIDDATA; |
|
|
|
|
|
|
|
/* Prepare a packet and send to the MJPEG decoder */ |
|
|
|
av_packet_unref(s->jpkt); |
|
|
|
s->jpkt->data = (uint8_t*)s->gb.buffer; |
|
|
|
s->jpkt->size = tile_byte_count; |
|
|
|
|
|
|
|
if (s->is_bayer) { |
|
|
|
MJpegDecodeContext *mjpegdecctx = s->avctx_mjpeg->priv_data; |
|
|
|
/* We have to set this information here, there is no way to know if a given JPEG is a DNG-embedded |
|
|
|
image or not from its own data (and we need that information when decoding it). */ |
|
|
|
mjpegdecctx->bayer = 1; |
|
|
|
} |
|
|
|
|
|
|
|
ret = avcodec_send_packet(s->avctx_mjpeg, s->jpkt); |
|
|
|
if (ret < 0) { |
|
|
|
av_log(avctx, AV_LOG_ERROR, "Error submitting a packet for decoding\n"); |
|
|
|
return ret; |
|
|
|
} |
|
|
|
|
|
|
|
ret = avcodec_receive_frame(s->avctx_mjpeg, s->jpgframe); |
|
|
|
if (ret < 0) { |
|
|
|
av_log(avctx, AV_LOG_ERROR, "JPEG decoding error: %s.\n", av_err2str(ret)); |
|
|
|
|
|
|
|
/* Normally skip, error if explode */ |
|
|
|
if (avctx->err_recognition & AV_EF_EXPLODE) |
|
|
|
return AVERROR_INVALIDDATA; |
|
|
|
else |
|
|
|
return 0; |
|
|
|
} |
|
|
|
|
|
|
|
is_u16 = (s->bpp > 8); |
|
|
|
|
|
|
|
/* Copy the outputted tile's pixels from 'jpgframe' to 'frame' (final buffer) */ |
|
|
|
|
|
|
|
if (s->jpgframe->width != s->avctx_mjpeg->width || |
|
|
|
s->jpgframe->height != s->avctx_mjpeg->height || |
|
|
|
s->jpgframe->format != s->avctx_mjpeg->pix_fmt) |
|
|
|
return AVERROR_INVALIDDATA; |
|
|
|
|
|
|
|
/* See dng_blit for explanation */ |
|
|
|
if (s->avctx_mjpeg->width == w * 2 && |
|
|
|
s->avctx_mjpeg->height == h / 2 && |
|
|
|
s->avctx_mjpeg->pix_fmt == AV_PIX_FMT_GRAY16LE) { |
|
|
|
is_single_comp = 1; |
|
|
|
} else if (s->avctx_mjpeg->width >= w && |
|
|
|
s->avctx_mjpeg->height >= h && |
|
|
|
s->avctx_mjpeg->pix_fmt == (is_u16 ? AV_PIX_FMT_GRAY16 : AV_PIX_FMT_GRAY8) |
|
|
|
) { |
|
|
|
is_single_comp = 0; |
|
|
|
} else |
|
|
|
return AVERROR_INVALIDDATA; |
|
|
|
|
|
|
|
pixel_size = (is_u16 ? sizeof(uint16_t) : sizeof(uint8_t)); |
|
|
|
|
|
|
|
if (is_single_comp && !is_u16) { |
|
|
|
av_log(s->avctx, AV_LOG_ERROR, "DNGs with bpp <= 8 and 1 component are unsupported\n"); |
|
|
|
av_frame_unref(s->jpgframe); |
|
|
|
return AVERROR_PATCHWELCOME; |
|
|
|
} |
|
|
|
|
|
|
|
dst_offset = dst_x + frame->linesize[0] * dst_y / pixel_size; |
|
|
|
dst_data = frame->data[0] + dst_offset * pixel_size; |
|
|
|
src_data = s->jpgframe->data[0]; |
|
|
|
|
|
|
|
dng_blit(s, |
|
|
|
dst_data, |
|
|
|
frame->linesize[0] / pixel_size, |
|
|
|
src_data, |
|
|
|
s->jpgframe->linesize[0] / pixel_size, |
|
|
|
w, |
|
|
|
h, |
|
|
|
is_single_comp, |
|
|
|
is_u16); |
|
|
|
|
|
|
|
av_frame_unref(s->jpgframe); |
|
|
|
|
|
|
|
return 0; |
|
|
|
} |
|
|
|
|
|
|
|
static int dng_decode_strip(AVCodecContext *avctx, AVFrame *frame) |
|
|
|
{ |
|
|
|
TiffContext *s = avctx->priv_data; |
|
|
|
|
|
|
|
s->jpgframe->width = s->width; |
|
|
|
s->jpgframe->height = s->height; |
|
|
|
|
|
|
|
s->avctx_mjpeg->width = s->width; |
|
|
|
s->avctx_mjpeg->height = s->height; |
|
|
|
|
|
|
|
return dng_decode_jpeg(avctx, frame, s->stripsize, 0, 0, s->width, s->height); |
|
|
|
} |
|
|
|
|
|
|
|
static int tiff_unpack_strip(TiffContext *s, AVFrame *p, uint8_t *dst, int stride, |
|
|
|
const uint8_t *src, int size, int strip_start, int lines) |
|
|
@@ -780,190 +973,6 @@ static int tiff_unpack_strip(TiffContext *s, AVFrame *p, uint8_t *dst, int strid |
|
|
|
return 0; |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
|
* Map stored raw sensor values into linear reference values (see: DNG Specification - Chapter 5) |
|
|
|
*/ |
|
|
|
static uint16_t av_always_inline dng_process_color16(uint16_t value, |
|
|
|
const uint16_t *lut, |
|
|
|
uint16_t black_level, |
|
|
|
float scale_factor) { |
|
|
|
float value_norm; |
|
|
|
|
|
|
|
// Lookup table lookup |
|
|
|
if (lut) |
|
|
|
value = lut[value]; |
|
|
|
|
|
|
|
// Black level subtraction |
|
|
|
value = av_clip_uint16_c((unsigned)value - black_level); |
|
|
|
|
|
|
|
// Color scaling |
|
|
|
value_norm = (float)value * scale_factor; |
|
|
|
|
|
|
|
value = av_clip_uint16_c(value_norm * 65535); |
|
|
|
|
|
|
|
return value; |
|
|
|
} |
|
|
|
|
|
|
|
static uint16_t av_always_inline dng_process_color8(uint16_t value, |
|
|
|
const uint16_t *lut, |
|
|
|
uint16_t black_level, |
|
|
|
float scale_factor) { |
|
|
|
return dng_process_color16(value, lut, black_level, scale_factor) >> 8; |
|
|
|
} |
|
|
|
|
|
|
|
static void dng_blit(TiffContext *s, uint8_t *dst, int dst_stride, |
|
|
|
const uint8_t *src, int src_stride, |
|
|
|
int width, int height, int is_single_comp, int is_u16) |
|
|
|
{ |
|
|
|
int line, col; |
|
|
|
float scale_factor; |
|
|
|
|
|
|
|
scale_factor = 1.0f / (s->white_level - s->black_level); |
|
|
|
|
|
|
|
if (is_single_comp) { |
|
|
|
if (!is_u16) |
|
|
|
return; /* <= 8bpp unsupported */ |
|
|
|
|
|
|
|
/* Image is double the width and half the height we need, each row comprises 2 rows of the output |
|
|
|
(split vertically in the middle). */ |
|
|
|
for (line = 0; line < height / 2; line++) { |
|
|
|
uint16_t *dst_u16 = (uint16_t *)dst; |
|
|
|
uint16_t *src_u16 = (uint16_t *)src; |
|
|
|
|
|
|
|
/* Blit first half of input row row to initial row of output */ |
|
|
|
for (col = 0; col < width; col++) |
|
|
|
*dst_u16++ = dng_process_color16(*src_u16++, s->dng_lut, s->black_level, scale_factor); |
|
|
|
|
|
|
|
/* Advance the destination pointer by a row (source pointer remains in the same place) */ |
|
|
|
dst += dst_stride * sizeof(uint16_t); |
|
|
|
dst_u16 = (uint16_t *)dst; |
|
|
|
|
|
|
|
/* Blit second half of input row row to next row of output */ |
|
|
|
for (col = 0; col < width; col++) |
|
|
|
*dst_u16++ = dng_process_color16(*src_u16++, s->dng_lut, s->black_level, scale_factor); |
|
|
|
|
|
|
|
dst += dst_stride * sizeof(uint16_t); |
|
|
|
src += src_stride * sizeof(uint16_t); |
|
|
|
} |
|
|
|
} else { |
|
|
|
/* Input and output image are the same size and the MJpeg decoder has done per-component |
|
|
|
deinterleaving, so blitting here is straightforward. */ |
|
|
|
if (is_u16) { |
|
|
|
for (line = 0; line < height; line++) { |
|
|
|
uint16_t *dst_u16 = (uint16_t *)dst; |
|
|
|
uint16_t *src_u16 = (uint16_t *)src; |
|
|
|
|
|
|
|
for (col = 0; col < width; col++) |
|
|
|
*dst_u16++ = dng_process_color16(*src_u16++, s->dng_lut, s->black_level, scale_factor); |
|
|
|
|
|
|
|
dst += dst_stride * sizeof(uint16_t); |
|
|
|
src += src_stride * sizeof(uint16_t); |
|
|
|
} |
|
|
|
} else { |
|
|
|
for (line = 0; line < height; line++) { |
|
|
|
uint8_t *dst_u8 = dst; |
|
|
|
const uint8_t *src_u8 = src; |
|
|
|
|
|
|
|
for (col = 0; col < width; col++) |
|
|
|
*dst_u8++ = dng_process_color8(*src_u8++, s->dng_lut, s->black_level, scale_factor); |
|
|
|
|
|
|
|
dst += dst_stride; |
|
|
|
src += src_stride; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
static int dng_decode_jpeg(AVCodecContext *avctx, AVFrame *frame, |
|
|
|
int tile_byte_count, int dst_x, int dst_y, int w, int h) |
|
|
|
{ |
|
|
|
TiffContext *s = avctx->priv_data; |
|
|
|
uint8_t *dst_data, *src_data; |
|
|
|
uint32_t dst_offset; /* offset from dst buffer in pixels */ |
|
|
|
int is_single_comp, is_u16, pixel_size; |
|
|
|
int ret; |
|
|
|
|
|
|
|
if (tile_byte_count < 0 || tile_byte_count > bytestream2_get_bytes_left(&s->gb)) |
|
|
|
return AVERROR_INVALIDDATA; |
|
|
|
|
|
|
|
/* Prepare a packet and send to the MJPEG decoder */ |
|
|
|
av_packet_unref(s->jpkt); |
|
|
|
s->jpkt->data = (uint8_t*)s->gb.buffer; |
|
|
|
s->jpkt->size = tile_byte_count; |
|
|
|
|
|
|
|
if (s->is_bayer) { |
|
|
|
MJpegDecodeContext *mjpegdecctx = s->avctx_mjpeg->priv_data; |
|
|
|
/* We have to set this information here, there is no way to know if a given JPEG is a DNG-embedded |
|
|
|
image or not from its own data (and we need that information when decoding it). */ |
|
|
|
mjpegdecctx->bayer = 1; |
|
|
|
} |
|
|
|
|
|
|
|
ret = avcodec_send_packet(s->avctx_mjpeg, s->jpkt); |
|
|
|
if (ret < 0) { |
|
|
|
av_log(avctx, AV_LOG_ERROR, "Error submitting a packet for decoding\n"); |
|
|
|
return ret; |
|
|
|
} |
|
|
|
|
|
|
|
ret = avcodec_receive_frame(s->avctx_mjpeg, s->jpgframe); |
|
|
|
if (ret < 0) { |
|
|
|
av_log(avctx, AV_LOG_ERROR, "JPEG decoding error: %s.\n", av_err2str(ret)); |
|
|
|
|
|
|
|
/* Normally skip, error if explode */ |
|
|
|
if (avctx->err_recognition & AV_EF_EXPLODE) |
|
|
|
return AVERROR_INVALIDDATA; |
|
|
|
else |
|
|
|
return 0; |
|
|
|
} |
|
|
|
|
|
|
|
is_u16 = (s->bpp > 8); |
|
|
|
|
|
|
|
/* Copy the outputted tile's pixels from 'jpgframe' to 'frame' (final buffer) */ |
|
|
|
|
|
|
|
if (s->jpgframe->width != s->avctx_mjpeg->width || |
|
|
|
s->jpgframe->height != s->avctx_mjpeg->height || |
|
|
|
s->jpgframe->format != s->avctx_mjpeg->pix_fmt) |
|
|
|
return AVERROR_INVALIDDATA; |
|
|
|
|
|
|
|
/* See dng_blit for explanation */ |
|
|
|
if (s->avctx_mjpeg->width == w * 2 && |
|
|
|
s->avctx_mjpeg->height == h / 2 && |
|
|
|
s->avctx_mjpeg->pix_fmt == AV_PIX_FMT_GRAY16LE) { |
|
|
|
is_single_comp = 1; |
|
|
|
} else if (s->avctx_mjpeg->width >= w && |
|
|
|
s->avctx_mjpeg->height >= h && |
|
|
|
s->avctx_mjpeg->pix_fmt == (is_u16 ? AV_PIX_FMT_GRAY16 : AV_PIX_FMT_GRAY8) |
|
|
|
) { |
|
|
|
is_single_comp = 0; |
|
|
|
} else |
|
|
|
return AVERROR_INVALIDDATA; |
|
|
|
|
|
|
|
pixel_size = (is_u16 ? sizeof(uint16_t) : sizeof(uint8_t)); |
|
|
|
|
|
|
|
if (is_single_comp && !is_u16) { |
|
|
|
av_log(s->avctx, AV_LOG_ERROR, "DNGs with bpp <= 8 and 1 component are unsupported\n"); |
|
|
|
av_frame_unref(s->jpgframe); |
|
|
|
return AVERROR_PATCHWELCOME; |
|
|
|
} |
|
|
|
|
|
|
|
dst_offset = dst_x + frame->linesize[0] * dst_y / pixel_size; |
|
|
|
dst_data = frame->data[0] + dst_offset * pixel_size; |
|
|
|
src_data = s->jpgframe->data[0]; |
|
|
|
|
|
|
|
dng_blit(s, |
|
|
|
dst_data, |
|
|
|
frame->linesize[0] / pixel_size, |
|
|
|
src_data, |
|
|
|
s->jpgframe->linesize[0] / pixel_size, |
|
|
|
w, |
|
|
|
h, |
|
|
|
is_single_comp, |
|
|
|
is_u16); |
|
|
|
|
|
|
|
av_frame_unref(s->jpgframe); |
|
|
|
|
|
|
|
return 0; |
|
|
|
} |
|
|
|
|
|
|
|
static int dng_decode_tiles(AVCodecContext *avctx, AVFrame *frame, |
|
|
|
const AVPacket *avpkt) |
|
|
|
{ |
|
|
@@ -1040,19 +1049,6 @@ static int dng_decode_tiles(AVCodecContext *avctx, AVFrame *frame, |
|
|
|
return avpkt->size; |
|
|
|
} |
|
|
|
|
|
|
|
static int dng_decode_strip(AVCodecContext *avctx, AVFrame *frame) |
|
|
|
{ |
|
|
|
TiffContext *s = avctx->priv_data; |
|
|
|
|
|
|
|
s->jpgframe->width = s->width; |
|
|
|
s->jpgframe->height = s->height; |
|
|
|
|
|
|
|
s->avctx_mjpeg->width = s->width; |
|
|
|
s->avctx_mjpeg->height = s->height; |
|
|
|
|
|
|
|
return dng_decode_jpeg(avctx, frame, s->stripsize, 0, 0, s->width, s->height); |
|
|
|
} |
|
|
|
|
|
|
|
static int init_image(TiffContext *s, ThreadFrame *frame) |
|
|
|
{ |
|
|
|
int ret; |
|
|
|