/*
* Copyright ( c ) 2006 Konstantin Shishkov
*
* This file is part of FFmpeg .
*
* FFmpeg is free software ; you can redistribute it and / or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation ; either
* version 2.1 of the License , or ( at your option ) any later version .
*
* FFmpeg is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the GNU
* Lesser General Public License for more details .
*
* You should have received a copy of the GNU Lesser General Public
* License along with FFmpeg ; if not , write to the Free Software
* Foundation , Inc . , 51 Franklin Street , Fifth Floor , Boston , MA 02110 - 1301 USA
*/
/**
* @ file
* TIFF image decoder
* @ author Konstantin Shishkov
*/
# include "config.h"
# if CONFIG_ZLIB
# include <zlib.h>
# endif
# if CONFIG_LZMA
# define LZMA_API_STATIC
# include <lzma.h>
# endif
# include "libavutil/attributes.h"
# include "libavutil/avstring.h"
# include "libavutil/error.h"
# include "libavutil/intreadwrite.h"
# include "libavutil/imgutils.h"
# include "libavutil/opt.h"
# include "avcodec.h"
# include "bytestream.h"
# include "faxcompr.h"
# include "internal.h"
# include "lzw.h"
# include "mathops.h"
# include "tiff.h"
# include "tiff_data.h"
# include "mjpegdec.h"
# include "thread.h"
# include "get_bits.h"
typedef struct TiffContext {
AVClass * class ;
AVCodecContext * avctx ;
GetByteContext gb ;
/* JPEG decoding for DNG */
AVCodecContext * avctx_mjpeg ; // wrapper context for MJPEG
AVFrame * jpgframe ; // decoded JPEG tile
int get_subimage ;
uint16_t get_page ;
int get_thumbnail ;
enum TiffType tiff_type ;
int width , height ;
unsigned int bpp , bppcount ;
uint32_t palette [ 256 ] ;
int palette_is_set ;
int le ;
enum TiffCompr compr ;
enum TiffPhotometric photometric ;
int planar ;
int subsampling [ 2 ] ;
int fax_opts ;
int predictor ;
int fill_order ;
uint32_t res [ 4 ] ;
int is_thumbnail ;
int is_bayer ;
uint8_t pattern [ 4 ] ;
unsigned black_level ;
unsigned white_level ;
uint16_t dng_lut [ 65536 ] ;
uint32_t sub_ifd ;
uint16_t cur_page ;
int strips , rps , sstype ;
int sot ;
int stripsizesoff , stripsize , stripoff , strippos ;
LZWState * lzw ;
/* Tile support */
int is_tiled ;
int tile_byte_counts_offset , tile_offsets_offset ;
int tile_width , tile_length ;
int tile_count ;
int is_jpeg ;
uint8_t * deinvert_buf ;
int deinvert_buf_size ;
uint8_t * yuv_line ;
unsigned int yuv_line_size ;
uint8_t * fax_buffer ;
unsigned int fax_buffer_size ;
int geotag_count ;
TiffGeoTag * geotags ;
} TiffContext ;
static void tiff_set_type ( TiffContext * s , enum TiffType tiff_type ) {
if ( s - > tiff_type < tiff_type ) // Prioritize higher-valued entries
s - > tiff_type = tiff_type ;
}
static void free_geotags ( TiffContext * const s )
{
int i ;
for ( i = 0 ; i < s - > geotag_count ; i + + ) {
if ( s - > geotags [ i ] . val )
av_freep ( & s - > geotags [ i ] . val ) ;
}
av_freep ( & s - > geotags ) ;
s - > geotag_count = 0 ;
}
# define RET_GEOKEY(TYPE, array, element)\
if ( key > = TIFF_ # # TYPE # # _KEY_ID_OFFSET & & \
key - TIFF_ # # TYPE # # _KEY_ID_OFFSET < FF_ARRAY_ELEMS ( ff_tiff_ # # array # # _name_type_map ) ) \
return ff_tiff_ # # array # # _name_type_map [ key - TIFF_ # # TYPE # # _KEY_ID_OFFSET ] . element ;
static const char * get_geokey_name ( int key )
{
RET_GEOKEY ( VERT , vert , name ) ;
RET_GEOKEY ( PROJ , proj , name ) ;
RET_GEOKEY ( GEOG , geog , name ) ;
RET_GEOKEY ( CONF , conf , name ) ;
return NULL ;
}
static int get_geokey_type ( int key )
{
RET_GEOKEY ( VERT , vert , type ) ;
RET_GEOKEY ( PROJ , proj , type ) ;
RET_GEOKEY ( GEOG , geog , type ) ;
RET_GEOKEY ( CONF , conf , type ) ;
return AVERROR_INVALIDDATA ;
}
static int cmp_id_key ( const void * id , const void * k )
{
return * ( const int * ) id - ( ( const TiffGeoTagKeyName * ) k ) - > key ;
}
static const char * search_keyval ( const TiffGeoTagKeyName * keys , int n , int id )
{
TiffGeoTagKeyName * r = bsearch ( & id , keys , n , sizeof ( keys [ 0 ] ) , cmp_id_key ) ;
if ( r )
return r - > name ;
return NULL ;
}
static char * get_geokey_val ( int key , int val )
{
char * ap ;
if ( val = = TIFF_GEO_KEY_UNDEFINED )
return av_strdup ( " undefined " ) ;
if ( val = = TIFF_GEO_KEY_USER_DEFINED )
return av_strdup ( " User-Defined " ) ;
# define RET_GEOKEY_VAL(TYPE, array)\
if ( val > = TIFF_ # # TYPE # # _OFFSET & & \
val - TIFF_ # # TYPE # # _OFFSET < FF_ARRAY_ELEMS ( ff_tiff_ # # array # # _codes ) ) \
return av_strdup ( ff_tiff_ # # array # # _codes [ val - TIFF_ # # TYPE # # _OFFSET ] ) ;
switch ( key ) {
case TIFF_GT_MODEL_TYPE_GEOKEY :
RET_GEOKEY_VAL ( GT_MODEL_TYPE , gt_model_type ) ;
break ;
case TIFF_GT_RASTER_TYPE_GEOKEY :
RET_GEOKEY_VAL ( GT_RASTER_TYPE , gt_raster_type ) ;
break ;
case TIFF_GEOG_LINEAR_UNITS_GEOKEY :
case TIFF_PROJ_LINEAR_UNITS_GEOKEY :
case TIFF_VERTICAL_UNITS_GEOKEY :
RET_GEOKEY_VAL ( LINEAR_UNIT , linear_unit ) ;
break ;
case TIFF_GEOG_ANGULAR_UNITS_GEOKEY :
case TIFF_GEOG_AZIMUTH_UNITS_GEOKEY :
RET_GEOKEY_VAL ( ANGULAR_UNIT , angular_unit ) ;
break ;
case TIFF_GEOGRAPHIC_TYPE_GEOKEY :
RET_GEOKEY_VAL ( GCS_TYPE , gcs_type ) ;
RET_GEOKEY_VAL ( GCSE_TYPE , gcse_type ) ;
break ;
case TIFF_GEOG_GEODETIC_DATUM_GEOKEY :
RET_GEOKEY_VAL ( GEODETIC_DATUM , geodetic_datum ) ;
RET_GEOKEY_VAL ( GEODETIC_DATUM_E , geodetic_datum_e ) ;
break ;
case TIFF_GEOG_ELLIPSOID_GEOKEY :
RET_GEOKEY_VAL ( ELLIPSOID , ellipsoid ) ;
break ;
case TIFF_GEOG_PRIME_MERIDIAN_GEOKEY :
RET_GEOKEY_VAL ( PRIME_MERIDIAN , prime_meridian ) ;
break ;
case TIFF_PROJECTED_CS_TYPE_GEOKEY :
ap = av_strdup ( search_keyval ( ff_tiff_proj_cs_type_codes , FF_ARRAY_ELEMS ( ff_tiff_proj_cs_type_codes ) , val ) ) ;
if ( ap ) return ap ;
break ;
case TIFF_PROJECTION_GEOKEY :
ap = av_strdup ( search_keyval ( ff_tiff_projection_codes , FF_ARRAY_ELEMS ( ff_tiff_projection_codes ) , val ) ) ;
if ( ap ) return ap ;
break ;
case TIFF_PROJ_COORD_TRANS_GEOKEY :
RET_GEOKEY_VAL ( COORD_TRANS , coord_trans ) ;
break ;
case TIFF_VERTICAL_CS_TYPE_GEOKEY :
RET_GEOKEY_VAL ( VERT_CS , vert_cs ) ;
RET_GEOKEY_VAL ( ORTHO_VERT_CS , ortho_vert_cs ) ;
break ;
}
ap = av_malloc ( 14 ) ;
if ( ap )
snprintf ( ap , 14 , " Unknown-%d " , val ) ;
return ap ;
}
static char * doubles2str ( double * dp , int count , const char * sep )
{
int i ;
char * ap , * ap0 ;
uint64_t component_len ;
if ( ! sep ) sep = " , " ;
component_len = 24LL + strlen ( sep ) ;
if ( count > = ( INT_MAX - 1 ) / component_len )
return NULL ;
ap = av_malloc ( component_len * count + 1 ) ;
if ( ! ap )
return NULL ;
ap0 = ap ;
ap [ 0 ] = ' \0 ' ;
for ( i = 0 ; i < count ; i + + ) {
unsigned l = snprintf ( ap , component_len , " %.15g%s " , dp [ i ] , sep ) ;
if ( l > = component_len ) {
av_free ( ap0 ) ;
return NULL ;
}
ap + = l ;
}
ap0 [ strlen ( ap0 ) - strlen ( sep ) ] = ' \0 ' ;
return ap0 ;
}
static int add_metadata ( int count , int type ,
const char * name , const char * sep , TiffContext * s , AVFrame * frame )
{
switch ( type ) {
case TIFF_DOUBLE : return ff_tadd_doubles_metadata ( count , name , sep , & s - > gb , s - > le , & frame - > metadata ) ;
case TIFF_SHORT : return ff_tadd_shorts_metadata ( count , name , sep , & s - > gb , s - > le , 0 , & frame - > metadata ) ;
case TIFF_STRING : return ff_tadd_string_metadata ( count , name , & s - > gb , s - > le , & frame - > metadata ) ;
default : return AVERROR_INVALIDDATA ;
} ;
}
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 ) ;
static void av_always_inline horizontal_fill ( TiffContext * s ,
unsigned int bpp , uint8_t * dst ,
int usePtr , const uint8_t * src ,
uint8_t c , int width , int offset )
{
switch ( bpp ) {
case 1 :
while ( - - width > = 0 ) {
dst [ ( width + offset ) * 8 + 7 ] = ( usePtr ? src [ width ] : c ) & 0x1 ;
dst [ ( width + offset ) * 8 + 6 ] = ( usePtr ? src [ width ] : c ) > > 1 & 0x1 ;
dst [ ( width + offset ) * 8 + 5 ] = ( usePtr ? src [ width ] : c ) > > 2 & 0x1 ;
dst [ ( width + offset ) * 8 + 4 ] = ( usePtr ? src [ width ] : c ) > > 3 & 0x1 ;
dst [ ( width + offset ) * 8 + 3 ] = ( usePtr ? src [ width ] : c ) > > 4 & 0x1 ;
dst [ ( width + offset ) * 8 + 2 ] = ( usePtr ? src [ width ] : c ) > > 5 & 0x1 ;
dst [ ( width + offset ) * 8 + 1 ] = ( usePtr ? src [ width ] : c ) > > 6 & 0x1 ;
dst [ ( width + offset ) * 8 + 0 ] = ( usePtr ? src [ width ] : c ) > > 7 ;
}
break ;
case 2 :
while ( - - width > = 0 ) {
dst [ ( width + offset ) * 4 + 3 ] = ( usePtr ? src [ width ] : c ) & 0x3 ;
dst [ ( width + offset ) * 4 + 2 ] = ( usePtr ? src [ width ] : c ) > > 2 & 0x3 ;
dst [ ( width + offset ) * 4 + 1 ] = ( usePtr ? src [ width ] : c ) > > 4 & 0x3 ;
dst [ ( width + offset ) * 4 + 0 ] = ( usePtr ? src [ width ] : c ) > > 6 ;
}
break ;
case 4 :
while ( - - width > = 0 ) {
dst [ ( width + offset ) * 2 + 1 ] = ( usePtr ? src [ width ] : c ) & 0xF ;
dst [ ( width + offset ) * 2 + 0 ] = ( usePtr ? src [ width ] : c ) > > 4 ;
}
break ;
case 10 :
case 12 :
case 14 : {
uint16_t * dst16 = ( uint16_t * ) dst ;
int is_dng = ( s - > tiff_type = = TIFF_TYPE_DNG | | s - > tiff_type = = TIFF_TYPE_CINEMADNG ) ;
uint8_t shift = is_dng ? 0 : 16 - bpp ;
GetBitContext gb ;
init_get_bits8 ( & gb , src , width ) ;
for ( int i = 0 ; i < s - > width ; i + + ) {
dst16 [ i ] = get_bits ( & gb , bpp ) < < shift ;
}
}
break ;
default :
if ( usePtr ) {
memcpy ( dst + offset , src , width ) ;
} else {
memset ( dst + offset , c , width ) ;
}
}
}
static int deinvert_buffer ( TiffContext * s , const uint8_t * src , int size )
{
int i ;
av_fast_padded_malloc ( & s - > deinvert_buf , & s - > deinvert_buf_size , size ) ;
if ( ! s - > deinvert_buf )
return AVERROR ( ENOMEM ) ;
for ( i = 0 ; i < size ; i + + )
s - > deinvert_buf [ i ] = ff_reverse [ src [ i ] ] ;
return 0 ;
}
static void unpack_gray ( TiffContext * s , AVFrame * p ,
const uint8_t * src , int lnum , int width , int bpp )
{
GetBitContext gb ;
uint16_t * dst = ( uint16_t * ) ( p - > data [ 0 ] + lnum * p - > linesize [ 0 ] ) ;
init_get_bits8 ( & gb , src , width ) ;
for ( int i = 0 ; i < s - > width ; i + + ) {
dst [ i ] = get_bits ( & gb , bpp ) ;
}
}
static void unpack_yuv ( TiffContext * s , AVFrame * p ,
const uint8_t * src , int lnum )
{
int i , j , k ;
int w = ( s - > width - 1 ) / s - > subsampling [ 0 ] + 1 ;
uint8_t * pu = & p - > data [ 1 ] [ lnum / s - > subsampling [ 1 ] * p - > linesize [ 1 ] ] ;
uint8_t * pv = & p - > data [ 2 ] [ lnum / s - > subsampling [ 1 ] * p - > linesize [ 2 ] ] ;
if ( s - > width % s - > subsampling [ 0 ] | | s - > height % s - > subsampling [ 1 ] ) {
for ( i = 0 ; i < w ; i + + ) {
for ( j = 0 ; j < s - > subsampling [ 1 ] ; j + + )
for ( k = 0 ; k < s - > subsampling [ 0 ] ; k + + )
p - > data [ 0 ] [ FFMIN ( lnum + j , s - > height - 1 ) * p - > linesize [ 0 ] +
FFMIN ( i * s - > subsampling [ 0 ] + k , s - > width - 1 ) ] = * src + + ;
* pu + + = * src + + ;
* pv + + = * src + + ;
}
} else {
for ( i = 0 ; i < w ; i + + ) {
for ( j = 0 ; j < s - > subsampling [ 1 ] ; j + + )
for ( k = 0 ; k < s - > subsampling [ 0 ] ; k + + )
p - > data [ 0 ] [ ( lnum + j ) * p - > linesize [ 0 ] +
i * s - > subsampling [ 0 ] + k ] = * src + + ;
* pu + + = * src + + ;
* pv + + = * src + + ;
}
}
}
# if CONFIG_ZLIB
static int tiff_uncompress ( uint8_t * dst , unsigned long * len , const uint8_t * src ,
int size )
{
z_stream zstream = { 0 } ;
int zret ;
zstream . next_in = ( uint8_t * ) src ;
zstream . avail_in = size ;
zstream . next_out = dst ;
zstream . avail_out = * len ;
zret = inflateInit ( & zstream ) ;
if ( zret ! = Z_OK ) {
av_log ( NULL , AV_LOG_ERROR , " Inflate init error: %d \n " , zret ) ;
return zret ;
}
zret = inflate ( & zstream , Z_SYNC_FLUSH ) ;
inflateEnd ( & zstream ) ;
* len = zstream . total_out ;
return zret = = Z_STREAM_END ? Z_OK : zret ;
}
static int tiff_unpack_zlib ( TiffContext * s , AVFrame * p , uint8_t * dst , int stride ,
const uint8_t * src , int size , int width , int lines ,
int strip_start , int is_yuv )
{
uint8_t * zbuf ;
unsigned long outlen ;
int ret , line ;
outlen = width * lines ;
zbuf = av_malloc ( outlen ) ;
if ( ! zbuf )
return AVERROR ( ENOMEM ) ;
if ( s - > fill_order ) {
if ( ( ret = deinvert_buffer ( s , src , size ) ) < 0 ) {
av_free ( zbuf ) ;
return ret ;
}
src = s - > deinvert_buf ;
}
ret = tiff_uncompress ( zbuf , & outlen , src , size ) ;
if ( ret ! = Z_OK ) {
av_log ( s - > avctx , AV_LOG_ERROR ,
" Uncompressing failed (%lu of %lu) with error %d \n " , outlen ,
( unsigned long ) width * lines , ret ) ;
av_free ( zbuf ) ;
return AVERROR_UNKNOWN ;
}
src = zbuf ;
for ( line = 0 ; line < lines ; line + + ) {
if ( s - > bpp < 8 & & s - > avctx - > pix_fmt = = AV_PIX_FMT_PAL8 ) {
horizontal_fill ( s , s - > bpp , dst , 1 , src , 0 , width , 0 ) ;
} else {
memcpy ( dst , src , width ) ;
}
if ( is_yuv ) {
unpack_yuv ( s , p , dst , strip_start + line ) ;
line + = s - > subsampling [ 1 ] - 1 ;
}
dst + = stride ;
src + = width ;
}
av_free ( zbuf ) ;
return 0 ;
}
# endif
# if CONFIG_LZMA
static int tiff_uncompress_lzma ( uint8_t * dst , uint64_t * len , const uint8_t * src ,
int size )
{
lzma_stream stream = LZMA_STREAM_INIT ;
lzma_ret ret ;
stream . next_in = ( uint8_t * ) src ;
stream . avail_in = size ;
stream . next_out = dst ;
stream . avail_out = * len ;
ret = lzma_stream_decoder ( & stream , UINT64_MAX , 0 ) ;
if ( ret ! = LZMA_OK ) {
av_log ( NULL , AV_LOG_ERROR , " LZMA init error: %d \n " , ret ) ;
return ret ;
}
ret = lzma_code ( & stream , LZMA_RUN ) ;
lzma_end ( & stream ) ;
* len = stream . total_out ;
return ret = = LZMA_STREAM_END ? LZMA_OK : ret ;
}
static int tiff_unpack_lzma ( TiffContext * s , AVFrame * p , uint8_t * dst , int stride ,
const uint8_t * src , int size , int width , int lines ,
int strip_start , int is_yuv )
{
uint64_t outlen = width * ( uint64_t ) lines ;
int ret , line ;
uint8_t * buf = av_malloc ( outlen ) ;
if ( ! buf )
return AVERROR ( ENOMEM ) ;
if ( s - > fill_order ) {
if ( ( ret = deinvert_buffer ( s , src , size ) ) < 0 ) {
av_free ( buf ) ;
return ret ;
}
src = s - > deinvert_buf ;
}
ret = tiff_uncompress_lzma ( buf , & outlen , src , size ) ;
if ( ret ! = LZMA_OK ) {
av_log ( s - > avctx , AV_LOG_ERROR ,
" Uncompressing failed (% " PRIu64 " of % " PRIu64 " ) with error %d \n " , outlen ,
( uint64_t ) width * lines , ret ) ;
av_free ( buf ) ;
return AVERROR_UNKNOWN ;
}
src = buf ;
for ( line = 0 ; line < lines ; line + + ) {
if ( s - > bpp < 8 & & s - > avctx - > pix_fmt = = AV_PIX_FMT_PAL8 ) {
horizontal_fill ( s , s - > bpp , dst , 1 , src , 0 , width , 0 ) ;
} else {
memcpy ( dst , src , width ) ;
}
if ( is_yuv ) {
unpack_yuv ( s , p , dst , strip_start + line ) ;
line + = s - > subsampling [ 1 ] - 1 ;
}
dst + = stride ;
src + = width ;
}
av_free ( buf ) ;
return 0 ;
}
# endif
static int tiff_unpack_fax ( TiffContext * s , uint8_t * dst , int stride ,
const uint8_t * src , int size , int width , int lines )
{
int i , ret = 0 ;
int line ;
uint8_t * src2 ;
av_fast_padded_malloc ( & s - > fax_buffer , & s - > fax_buffer_size , size ) ;
src2 = s - > fax_buffer ;
if ( ! src2 ) {
av_log ( s - > avctx , AV_LOG_ERROR ,
" Error allocating temporary buffer \n " ) ;
return AVERROR ( ENOMEM ) ;
}
if ( ! s - > fill_order ) {
memcpy ( src2 , src , size ) ;
} else {
for ( i = 0 ; i < size ; i + + )
src2 [ i ] = ff_reverse [ src [ i ] ] ;
}
memset ( src2 + size , 0 , AV_INPUT_BUFFER_PADDING_SIZE ) ;
ret = ff_ccitt_unpack ( s - > avctx , src2 , size , dst , lines , stride ,
s - > compr , s - > fax_opts ) ;
if ( s - > bpp < 8 & & s - > avctx - > pix_fmt = = AV_PIX_FMT_PAL8 )
for ( line = 0 ; line < lines ; line + + ) {
horizontal_fill ( s , s - > bpp , dst , 1 , dst , 0 , width , 0 ) ;
dst + = stride ;
}
return ret ;
}
static int dng_decode_strip ( AVCodecContext * avctx , AVFrame * frame ) ;
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 )
{
PutByteContext pb ;
int c , line , pixels , code , ret ;
const uint8_t * ssrc = src ;
int width = ( ( s - > width * s - > bpp ) + 7 ) > > 3 ;
const AVPixFmtDescriptor * desc = av_pix_fmt_desc_get ( p - > format ) ;
int is_yuv = ! ( desc - > flags & AV_PIX_FMT_FLAG_RGB ) & &
( desc - > flags & AV_PIX_FMT_FLAG_PLANAR ) & &
desc - > nb_components > = 3 ;
int is_dng ;
if ( s - > planar )
width / = s - > bppcount ;
if ( size < = 0 )
return AVERROR_INVALIDDATA ;
if ( is_yuv ) {
int bytes_per_row = ( ( ( s - > width - 1 ) / s - > subsampling [ 0 ] + 1 ) * s - > bpp *
s - > subsampling [ 0 ] * s - > subsampling [ 1 ] + 7 ) > > 3 ;
av_fast_padded_malloc ( & s - > yuv_line , & s - > yuv_line_size , bytes_per_row ) ;
if ( s - > yuv_line = = NULL ) {
av_log ( s - > avctx , AV_LOG_ERROR , " Not enough memory \n " ) ;
return AVERROR ( ENOMEM ) ;
}
dst = s - > yuv_line ;
stride = 0 ;
width = ( s - > width - 1 ) / s - > subsampling [ 0 ] + 1 ;
width = width * s - > subsampling [ 0 ] * s - > subsampling [ 1 ] + 2 * width ;
av_assert0 ( width < = bytes_per_row ) ;
av_assert0 ( s - > bpp = = 24 ) ;
}
if ( s - > is_bayer ) {
width = ( s - > bpp * s - > width + 7 ) > > 3 ;
}
if ( p - > format = = AV_PIX_FMT_GRAY12 ) {
av_fast_padded_malloc ( & s - > yuv_line , & s - > yuv_line_size , width ) ;
if ( s - > yuv_line = = NULL ) {
av_log ( s - > avctx , AV_LOG_ERROR , " Not enough memory \n " ) ;
return AVERROR ( ENOMEM ) ;
}
dst = s - > yuv_line ;
stride = 0 ;
}
if ( s - > compr = = TIFF_DEFLATE | | s - > compr = = TIFF_ADOBE_DEFLATE ) {
# if CONFIG_ZLIB
return tiff_unpack_zlib ( s , p , dst , stride , src , size , width , lines ,
strip_start , is_yuv ) ;
# else
av_log ( s - > avctx , AV_LOG_ERROR ,
" zlib support not enabled, "
" deflate compression not supported \n " ) ;
return AVERROR ( ENOSYS ) ;
# endif
}
if ( s - > compr = = TIFF_LZMA ) {
# if CONFIG_LZMA
return tiff_unpack_lzma ( s , p , dst , stride , src , size , width , lines ,
strip_start , is_yuv ) ;
# else
av_log ( s - > avctx , AV_LOG_ERROR ,
" LZMA support not enabled \n " ) ;
return AVERROR ( ENOSYS ) ;
# endif
}
if ( s - > compr = = TIFF_LZW ) {
if ( s - > fill_order ) {
if ( ( ret = deinvert_buffer ( s , src , size ) ) < 0 )
return ret ;
ssrc = src = s - > deinvert_buf ;
}
if ( size > 1 & & ! src [ 0 ] & & ( src [ 1 ] & 1 ) ) {
av_log ( s - > avctx , AV_LOG_ERROR , " Old style LZW is unsupported \n " ) ;
}
if ( ( ret = ff_lzw_decode_init ( s - > lzw , 8 , src , size , FF_LZW_TIFF ) ) < 0 ) {
av_log ( s - > avctx , AV_LOG_ERROR , " Error initializing LZW decoder \n " ) ;
return ret ;
}
for ( line = 0 ; line < lines ; line + + ) {
pixels = ff_lzw_decode ( s - > lzw , dst , width ) ;
if ( pixels < width ) {
av_log ( s - > avctx , AV_LOG_ERROR , " Decoded only %i bytes of %i \n " ,
pixels , width ) ;
return AVERROR_INVALIDDATA ;
}
if ( s - > bpp < 8 & & s - > avctx - > pix_fmt = = AV_PIX_FMT_PAL8 )
horizontal_fill ( s , s - > bpp , dst , 1 , dst , 0 , width , 0 ) ;
if ( is_yuv ) {
unpack_yuv ( s , p , dst , strip_start + line ) ;
line + = s - > subsampling [ 1 ] - 1 ;
} else if ( p - > format = = AV_PIX_FMT_GRAY12 ) {
unpack_gray ( s , p , dst , strip_start + line , width , s - > bpp ) ;
}
dst + = stride ;
}
return 0 ;
}
if ( s - > compr = = TIFF_CCITT_RLE | |
s - > compr = = TIFF_G3 | |
s - > compr = = TIFF_G4 ) {
if ( is_yuv | | p - > format = = AV_PIX_FMT_GRAY12 )
return AVERROR_INVALIDDATA ;
return tiff_unpack_fax ( s , dst , stride , src , size , width , lines ) ;
}
bytestream2_init ( & s - > gb , src , size ) ;
bytestream2_init_writer ( & pb , dst , is_yuv ? s - > yuv_line_size : ( stride * lines ) ) ;
is_dng = ( s - > tiff_type = = TIFF_TYPE_DNG | | s - > tiff_type = = TIFF_TYPE_CINEMADNG ) ;
/* Decode JPEG-encoded DNGs with strips */
if ( s - > compr = = TIFF_NEWJPEG & & is_dng ) {
if ( s - > strips > 1 ) {
av_log ( s - > avctx , AV_LOG_ERROR , " More than one DNG JPEG strips unsupported \n " ) ;
return AVERROR_PATCHWELCOME ;
}
if ( ( ret = dng_decode_strip ( s - > avctx , p ) ) < 0 )
return ret ;
return 0 ;
}
for ( line = 0 ; line < lines ; line + + ) {
if ( src - ssrc > size ) {
av_log ( s - > avctx , AV_LOG_ERROR , " Source data overread \n " ) ;
return AVERROR_INVALIDDATA ;
}
if ( bytestream2_get_bytes_left ( & s - > gb ) = = 0 | | bytestream2_get_eof ( & pb ) )
break ;
bytestream2_seek_p ( & pb , stride * line , SEEK_SET ) ;
switch ( s - > compr ) {
case TIFF_RAW :
if ( ssrc + size - src < width )
return AVERROR_INVALIDDATA ;
if ( ! s - > fill_order ) {
horizontal_fill ( s , s - > bpp * ( s - > avctx - > pix_fmt = = AV_PIX_FMT_PAL8 | | s - > is_bayer ) ,
dst , 1 , src , 0 , width , 0 ) ;
} else {
int i ;
for ( i = 0 ; i < width ; i + + )
dst [ i ] = ff_reverse [ src [ i ] ] ;
}
/* Color processing for DNG images with uncompressed strips (non-tiled) */
if ( is_dng ) {
int is_u16 , pixel_size_bytes , pixel_size_bits ;
is_u16 = ( s - > bpp > 8 ) ;
pixel_size_bits = ( is_u16 ? 16 : 8 ) ;
pixel_size_bytes = ( is_u16 ? sizeof ( uint16_t ) : sizeof ( uint8_t ) ) ;
dng_blit ( s ,
dst ,
0 , // no stride, only 1 line
dst ,
0 , // no stride, only 1 line
width / pixel_size_bytes * pixel_size_bits / s - > bpp * s - > bppcount , // need to account for [1, 16] bpp
1 ,
0 , // single-component variation is only preset in JPEG-encoded DNGs
is_u16 ) ;
}
src + = width ;
break ;
case TIFF_PACKBITS :
for ( pixels = 0 ; pixels < width ; ) {
if ( ssrc + size - src < 2 ) {
av_log ( s - > avctx , AV_LOG_ERROR , " Read went out of bounds \n " ) ;
return AVERROR_INVALIDDATA ;
}
code = s - > fill_order ? ( int8_t ) ff_reverse [ * src + + ] : ( int8_t ) * src + + ;
if ( code > = 0 ) {
code + + ;
if ( pixels + code > width | |
ssrc + size - src < code ) {
av_log ( s - > avctx , AV_LOG_ERROR ,
" Copy went out of bounds \n " ) ;
return AVERROR_INVALIDDATA ;
}
horizontal_fill ( s , s - > bpp * ( s - > avctx - > pix_fmt = = AV_PIX_FMT_PAL8 ) ,
dst , 1 , src , 0 , code , pixels ) ;
src + = code ;
pixels + = code ;
} else if ( code ! = - 128 ) { // -127..-1
code = ( - code ) + 1 ;
if ( pixels + code > width ) {
av_log ( s - > avctx , AV_LOG_ERROR ,
" Run went out of bounds \n " ) ;
return AVERROR_INVALIDDATA ;
}
c = * src + + ;
horizontal_fill ( s , s - > bpp * ( s - > avctx - > pix_fmt = = AV_PIX_FMT_PAL8 ) ,
dst , 0 , NULL , c , code , pixels ) ;
pixels + = code ;
}
}
if ( s - > fill_order ) {
int i ;
for ( i = 0 ; i < width ; i + + )
dst [ i ] = ff_reverse [ dst [ i ] ] ;
}
break ;
}
if ( is_yuv ) {
unpack_yuv ( s , p , dst , strip_start + line ) ;
line + = s - > subsampling [ 1 ] - 1 ;
} else if ( p - > format = = AV_PIX_FMT_GRAY12 ) {
unpack_gray ( s , p , dst , strip_start + line , width , s - > bpp ) ;
}
dst + = stride ;
}
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 + + ) {
for ( col = 0 ; col < width ; col + + )
* dst + + = dng_process_color8 ( * src + + , 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 ;
AVPacket jpkt ;
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 ;
/* Prepare a packet and send to the MJPEG decoder */
av_init_packet ( & jpkt ) ;
jpkt . data = ( uint8_t * ) s - > gb . buffer ;
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 , & 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 ;
}
/* Copy the outputted tile's pixels from 'jpgframe' to 'frame' (final buffer) */
/* See dng_blit for explanation */
is_single_comp = ( s - > avctx_mjpeg - > width = = w * 2 & & s - > avctx_mjpeg - > height = = h / 2 ) ;
is_u16 = ( s - > bpp > 8 ) ;
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 , AVPacket * avpkt )
{
TiffContext * s = avctx - > priv_data ;
int tile_idx ;
int tile_offset_offset , tile_offset ;
int tile_byte_count_offset , tile_byte_count ;
int tile_count_x , tile_count_y ;
int tile_width , tile_length ;
int has_width_leftover , has_height_leftover ;
int tile_x = 0 , tile_y = 0 ;
int pos_x = 0 , pos_y = 0 ;
int ret ;
s - > jpgframe - > width = s - > tile_width ;
s - > jpgframe - > height = s - > tile_length ;
s - > avctx_mjpeg - > width = s - > tile_width ;
s - > avctx_mjpeg - > height = s - > tile_length ;
has_width_leftover = ( s - > width % s - > tile_width ! = 0 ) ;
has_height_leftover = ( s - > height % s - > tile_length ! = 0 ) ;
/* Calculate tile counts (round up) */
tile_count_x = ( s - > width + s - > tile_width - 1 ) / s - > tile_width ;
tile_count_y = ( s - > height + s - > tile_length - 1 ) / s - > tile_length ;
/* Iterate over the number of tiles */
for ( tile_idx = 0 ; tile_idx < s - > tile_count ; tile_idx + + ) {
tile_x = tile_idx % tile_count_x ;
tile_y = tile_idx / tile_count_x ;
if ( has_width_leftover & & tile_x = = tile_count_x - 1 ) // If on the right-most tile
tile_width = s - > width % s - > tile_width ;
else
tile_width = s - > tile_width ;
if ( has_height_leftover & & tile_y = = tile_count_y - 1 ) // If on the bottom-most tile
tile_length = s - > height % s - > tile_length ;
else
tile_length = s - > tile_length ;
/* Read tile offset */
tile_offset_offset = s - > tile_offsets_offset + tile_idx * sizeof ( int ) ;
bytestream2_seek ( & s - > gb , tile_offset_offset , SEEK_SET ) ;
tile_offset = ff_tget_long ( & s - > gb , s - > le ) ;
/* Read tile byte size */
tile_byte_count_offset = s - > tile_byte_counts_offset + tile_idx * sizeof ( int ) ;
bytestream2_seek ( & s - > gb , tile_byte_count_offset , SEEK_SET ) ;
tile_byte_count = ff_tget_long ( & s - > gb , s - > le ) ;
/* Seek to tile data */
bytestream2_seek ( & s - > gb , tile_offset , SEEK_SET ) ;
/* Decode JPEG tile and copy it in the reference frame */
ret = dng_decode_jpeg ( avctx , frame , tile_byte_count , pos_x , pos_y , tile_width , tile_length ) ;
if ( ret < 0 )
return ret ;
/* Advance current positions */
pos_x + = tile_width ;
if ( tile_x = = tile_count_x - 1 ) { // If on the right edge
pos_x = 0 ;
pos_y + = tile_length ;
}
}
/* Frame is ready to be output */
frame - > pict_type = AV_PICTURE_TYPE_I ;
frame - > key_frame = 1 ;
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 ;
int create_gray_palette = 0 ;
// make sure there is no aliasing in the following switch
if ( s - > bpp > = 100 | | s - > bppcount > = 10 ) {
av_log ( s - > avctx , AV_LOG_ERROR ,
" Unsupported image parameters: bpp=%d, bppcount=%d \n " ,
s - > bpp , s - > bppcount ) ;
return AVERROR_INVALIDDATA ;
}
switch ( s - > planar * 1000 + s - > bpp * 10 + s - > bppcount + s - > is_bayer * 10000 ) {
case 11 :
if ( ! s - > palette_is_set ) {
s - > avctx - > pix_fmt = AV_PIX_FMT_MONOBLACK ;
break ;
}
case 21 :
case 41 :
s - > avctx - > pix_fmt = AV_PIX_FMT_PAL8 ;
if ( ! s - > palette_is_set ) {
create_gray_palette = 1 ;
}
break ;
case 81 :
s - > avctx - > pix_fmt = s - > palette_is_set ? AV_PIX_FMT_PAL8 : AV_PIX_FMT_GRAY8 ;
break ;
case 121 :
s - > avctx - > pix_fmt = AV_PIX_FMT_GRAY12 ;
break ;
case 10081 :
switch ( AV_RL32 ( s - > pattern ) ) {
case 0x02010100 :
s - > avctx - > pix_fmt = AV_PIX_FMT_BAYER_RGGB8 ;
break ;
case 0x00010102 :
s - > avctx - > pix_fmt = AV_PIX_FMT_BAYER_BGGR8 ;
break ;
case 0x01000201 :
s - > avctx - > pix_fmt = AV_PIX_FMT_BAYER_GBRG8 ;
break ;
case 0x01020001 :
s - > avctx - > pix_fmt = AV_PIX_FMT_BAYER_GRBG8 ;
break ;
default :
av_log ( s - > avctx , AV_LOG_ERROR , " Unsupported Bayer pattern: 0x%X \n " ,
AV_RL32 ( s - > pattern ) ) ;
return AVERROR_PATCHWELCOME ;
}
break ;
case 10101 :
case 10121 :
case 10141 :
case 10161 :
switch ( AV_RL32 ( s - > pattern ) ) {
case 0x02010100 :
s - > avctx - > pix_fmt = AV_PIX_FMT_BAYER_RGGB16 ;
break ;
case 0x00010102 :
s - > avctx - > pix_fmt = AV_PIX_FMT_BAYER_BGGR16 ;
break ;
case 0x01000201 :
s - > avctx - > pix_fmt = AV_PIX_FMT_BAYER_GBRG16 ;
break ;
case 0x01020001 :
s - > avctx - > pix_fmt = AV_PIX_FMT_BAYER_GRBG16 ;
break ;
default :
av_log ( s - > avctx , AV_LOG_ERROR , " Unsupported Bayer pattern: 0x%X \n " ,
AV_RL32 ( s - > pattern ) ) ;
return AVERROR_PATCHWELCOME ;
}
break ;
case 243 :
if ( s - > photometric = = TIFF_PHOTOMETRIC_YCBCR ) {
if ( s - > subsampling [ 0 ] = = 1 & & s - > subsampling [ 1 ] = = 1 ) {
s - > avctx - > pix_fmt = AV_PIX_FMT_YUV444P ;
} else if ( s - > subsampling [ 0 ] = = 2 & & s - > subsampling [ 1 ] = = 1 ) {
s - > avctx - > pix_fmt = AV_PIX_FMT_YUV422P ;
} else if ( s - > subsampling [ 0 ] = = 4 & & s - > subsampling [ 1 ] = = 1 ) {
s - > avctx - > pix_fmt = AV_PIX_FMT_YUV411P ;
} else if ( s - > subsampling [ 0 ] = = 1 & & s - > subsampling [ 1 ] = = 2 ) {
s - > avctx - > pix_fmt = AV_PIX_FMT_YUV440P ;
} else if ( s - > subsampling [ 0 ] = = 2 & & s - > subsampling [ 1 ] = = 2 ) {
s - > avctx - > pix_fmt = AV_PIX_FMT_YUV420P ;
} else if ( s - > subsampling [ 0 ] = = 4 & & s - > subsampling [ 1 ] = = 4 ) {
s - > avctx - > pix_fmt = AV_PIX_FMT_YUV410P ;
} else {
av_log ( s - > avctx , AV_LOG_ERROR , " Unsupported YCbCr subsampling \n " ) ;
return AVERROR_PATCHWELCOME ;
}
} else
s - > avctx - > pix_fmt = AV_PIX_FMT_RGB24 ;
break ;
case 161 :
s - > avctx - > pix_fmt = s - > le ? AV_PIX_FMT_GRAY16LE : AV_PIX_FMT_GRAY16BE ;
break ;
case 162 :
s - > avctx - > pix_fmt = AV_PIX_FMT_YA8 ;
break ;
case 322 :
s - > avctx - > pix_fmt = s - > le ? AV_PIX_FMT_YA16LE : AV_PIX_FMT_YA16BE ;
break ;
case 324 :
s - > avctx - > pix_fmt = s - > photometric = = TIFF_PHOTOMETRIC_SEPARATED ? AV_PIX_FMT_RGB0 : AV_PIX_FMT_RGBA ;
break ;
case 405 :
if ( s - > photometric = = TIFF_PHOTOMETRIC_SEPARATED )
s - > avctx - > pix_fmt = AV_PIX_FMT_RGBA ;
else {
av_log ( s - > avctx , AV_LOG_ERROR ,
" bpp=40 without PHOTOMETRIC_SEPARATED is unsupported \n " ) ;
return AVERROR_PATCHWELCOME ;
}
break ;
case 483 :
s - > avctx - > pix_fmt = s - > le ? AV_PIX_FMT_RGB48LE : AV_PIX_FMT_RGB48BE ;
break ;
case 644 :
s - > avctx - > pix_fmt = s - > le ? AV_PIX_FMT_RGBA64LE : AV_PIX_FMT_RGBA64BE ;
break ;
case 1243 :
s - > avctx - > pix_fmt = AV_PIX_FMT_GBRP ;
break ;
case 1324 :
s - > avctx - > pix_fmt = AV_PIX_FMT_GBRAP ;
break ;
case 1483 :
s - > avctx - > pix_fmt = s - > le ? AV_PIX_FMT_GBRP16LE : AV_PIX_FMT_GBRP16BE ;
break ;
case 1644 :
s - > avctx - > pix_fmt = s - > le ? AV_PIX_FMT_GBRAP16LE : AV_PIX_FMT_GBRAP16BE ;
break ;
default :
av_log ( s - > avctx , AV_LOG_ERROR ,
" This format is not supported (bpp=%d, bppcount=%d) \n " ,
s - > bpp , s - > bppcount ) ;
return AVERROR_INVALIDDATA ;
}
if ( s - > photometric = = TIFF_PHOTOMETRIC_YCBCR ) {
const AVPixFmtDescriptor * desc = av_pix_fmt_desc_get ( s - > avctx - > pix_fmt ) ;
if ( ( desc - > flags & AV_PIX_FMT_FLAG_RGB ) | |
! ( desc - > flags & AV_PIX_FMT_FLAG_PLANAR ) | |
desc - > nb_components < 3 ) {
av_log ( s - > avctx , AV_LOG_ERROR , " Unsupported YCbCr variant \n " ) ;
return AVERROR_INVALIDDATA ;
}
}
if ( s - > width ! = s - > avctx - > width | | s - > height ! = s - > avctx - > height ) {
ret = ff_set_dimensions ( s - > avctx , s - > width , s - > height ) ;
if ( ret < 0 )
return ret ;
}
if ( ( ret = ff_thread_get_buffer ( s - > avctx , frame , 0 ) ) < 0 )
return ret ;
if ( s - > avctx - > pix_fmt = = AV_PIX_FMT_PAL8 ) {
if ( ! create_gray_palette )
memcpy ( frame - > f - > data [ 1 ] , s - > palette , sizeof ( s - > palette ) ) ;
else {
/* make default grayscale pal */
int i ;
uint32_t * pal = ( uint32_t * ) frame - > f - > data [ 1 ] ;
for ( i = 0 ; i < 1 < < s - > bpp ; i + + )
pal [ i ] = 0xFFU < < 24 | i * 255 / ( ( 1 < < s - > bpp ) - 1 ) * 0x010101 ;
}
}
return 0 ;
}
static void set_sar ( TiffContext * s , unsigned tag , unsigned num , unsigned den )
{
int offset = tag = = TIFF_YRES ? 2 : 0 ;
s - > res [ offset + + ] = num ;
s - > res [ offset ] = den ;
if ( s - > res [ 0 ] & & s - > res [ 1 ] & & s - > res [ 2 ] & & s - > res [ 3 ] ) {
uint64_t num = s - > res [ 2 ] * ( uint64_t ) s - > res [ 1 ] ;
uint64_t den = s - > res [ 0 ] * ( uint64_t ) s - > res [ 3 ] ;
if ( num > INT64_MAX | | den > INT64_MAX ) {
num = num > > 1 ;
den = den > > 1 ;
}
av_reduce ( & s - > avctx - > sample_aspect_ratio . num , & s - > avctx - > sample_aspect_ratio . den ,
num , den , INT32_MAX ) ;
if ( ! s - > avctx - > sample_aspect_ratio . den )
s - > avctx - > sample_aspect_ratio = ( AVRational ) { 0 , 1 } ;
}
}
static int tiff_decode_tag ( TiffContext * s , AVFrame * frame )
{
unsigned tag , type , count , off , value = 0 , value2 = 1 ; // value2 is a denominator so init. to 1
int i , start ;
int pos ;
int ret ;
double * dp ;
ret = ff_tread_tag ( & s - > gb , s - > le , & tag , & type , & count , & start ) ;
if ( ret < 0 ) {
goto end ;
}
off = bytestream2_tell ( & s - > gb ) ;
if ( count = = 1 ) {
switch ( type ) {
case TIFF_BYTE :
case TIFF_SHORT :
case TIFF_LONG :
value = ff_tget ( & s - > gb , type , s - > le ) ;
break ;
case TIFF_RATIONAL :
value = ff_tget ( & s - > gb , TIFF_LONG , s - > le ) ;
value2 = ff_tget ( & s - > gb , TIFF_LONG , s - > le ) ;
break ;
case TIFF_STRING :
if ( count < = 4 ) {
break ;
}
default :
value = UINT_MAX ;
}
}
switch ( tag ) {
case TIFF_SUBFILE :
s - > is_thumbnail = ( value ! = 0 ) ;
break ;
case TIFF_WIDTH :
s - > width = value ;
break ;
case TIFF_HEIGHT :
s - > height = value ;
break ;
case TIFF_BPP :
if ( count > 5U ) {
av_log ( s - > avctx , AV_LOG_ERROR ,
" This format is not supported (bpp=%d, %d components) \n " ,
value , count ) ;
return AVERROR_INVALIDDATA ;
}
s - > bppcount = count ;
if ( count = = 1 )
s - > bpp = value ;
else {
switch ( type ) {
case TIFF_BYTE :
case TIFF_SHORT :
case TIFF_LONG :
s - > bpp = 0 ;
if ( bytestream2_get_bytes_left ( & s - > gb ) < type_sizes [ type ] * count )
return AVERROR_INVALIDDATA ;
for ( i = 0 ; i < count ; i + + )
s - > bpp + = ff_tget ( & s - > gb , type , s - > le ) ;
break ;
default :
s - > bpp = - 1 ;
}
}
break ;
case TIFF_SAMPLES_PER_PIXEL :
if ( count ! = 1 ) {
av_log ( s - > avctx , AV_LOG_ERROR ,
" Samples per pixel requires a single value, many provided \n " ) ;
return AVERROR_INVALIDDATA ;
}
if ( value > 5U ) {
av_log ( s - > avctx , AV_LOG_ERROR ,
" Samples per pixel %d is too large \n " , value ) ;
return AVERROR_INVALIDDATA ;
}
if ( s - > bppcount = = 1 )
s - > bpp * = value ;
s - > bppcount = value ;
break ;
case TIFF_COMPR :
s - > compr = value ;
av_log ( s - > avctx , AV_LOG_DEBUG , " compression: %d \n " , s - > compr ) ;
s - > predictor = 0 ;
switch ( s - > compr ) {
case TIFF_RAW :
case TIFF_PACKBITS :
case TIFF_LZW :
case TIFF_CCITT_RLE :
break ;
case TIFF_G3 :
case TIFF_G4 :
s - > fax_opts = 0 ;
break ;
case TIFF_DEFLATE :
case TIFF_ADOBE_DEFLATE :
# if CONFIG_ZLIB
break ;
# else
av_log ( s - > avctx , AV_LOG_ERROR , " Deflate: ZLib not compiled in \n " ) ;
return AVERROR ( ENOSYS ) ;
# endif
case TIFF_JPEG :
case TIFF_NEWJPEG :
s - > is_jpeg = 1 ;
break ;
case TIFF_LZMA :
# if CONFIG_LZMA
break ;
# else
av_log ( s - > avctx , AV_LOG_ERROR , " LZMA not compiled in \n " ) ;
return AVERROR ( ENOSYS ) ;
# endif
default :
av_log ( s - > avctx , AV_LOG_ERROR , " Unknown compression method %i \n " ,
s - > compr ) ;
return AVERROR_INVALIDDATA ;
}
break ;
case TIFF_ROWSPERSTRIP :
if ( ! value | | ( type = = TIFF_LONG & & value = = UINT_MAX ) )
value = s - > height ;
s - > rps = FFMIN ( value , s - > height ) ;
break ;
case TIFF_STRIP_OFFS :
if ( count = = 1 ) {
if ( value > INT_MAX ) {
av_log ( s - > avctx , AV_LOG_ERROR ,
" strippos %u too large \n " , value ) ;
return AVERROR_INVALIDDATA ;
}
s - > strippos = 0 ;
s - > stripoff = value ;
} else
s - > strippos = off ;
s - > strips = count ;
if ( s - > strips = = 1 )
s - > rps = s - > height ;
s - > sot = type ;
break ;
case TIFF_STRIP_SIZE :
if ( count = = 1 ) {
if ( value > INT_MAX ) {
av_log ( s - > avctx , AV_LOG_ERROR ,
" stripsize %u too large \n " , value ) ;
return AVERROR_INVALIDDATA ;
}
s - > stripsizesoff = 0 ;
s - > stripsize = value ;
s - > strips = 1 ;
} else {
s - > stripsizesoff = off ;
}
s - > strips = count ;
s - > sstype = type ;
break ;
case TIFF_XRES :
case TIFF_YRES :
set_sar ( s , tag , value , value2 ) ;
break ;
case TIFF_TILE_OFFSETS :
s - > tile_offsets_offset = off ;
s - > tile_count = count ;
s - > is_tiled = 1 ;
break ;
case TIFF_TILE_BYTE_COUNTS :
s - > tile_byte_counts_offset = off ;
break ;
case TIFF_TILE_LENGTH :
s - > tile_length = value ;
break ;
case TIFF_TILE_WIDTH :
s - > tile_width = value ;
break ;
case TIFF_PREDICTOR :
s - > predictor = value ;
break ;
case TIFF_SUB_IFDS :
if ( count = = 1 )
s - > sub_ifd = value ;
else if ( count > 1 )
s - > sub_ifd = ff_tget ( & s - > gb , TIFF_LONG , s - > le ) ; /** Only get the first SubIFD */
break ;
case DNG_LINEARIZATION_TABLE :
for ( int i = 0 ; i < FFMIN ( count , 1 < < s - > bpp ) ; i + + )
s - > dng_lut [ i ] = ff_tget ( & s - > gb , type , s - > le ) ;
break ;
case DNG_BLACK_LEVEL :
if ( count > 1 ) { /* Use the first value in the pattern (assume they're all the same) */
if ( type = = TIFF_RATIONAL ) {
value = ff_tget ( & s - > gb , TIFF_LONG , s - > le ) ;
value2 = ff_tget ( & s - > gb , TIFF_LONG , s - > le ) ;
s - > black_level = value / value2 ;
} else
s - > black_level = ff_tget ( & s - > gb , type , s - > le ) ;
av_log ( s - > avctx , AV_LOG_WARNING , " Assuming black level pattern values are identical \n " ) ;
} else {
s - > black_level = value / value2 ;
}
break ;
case DNG_WHITE_LEVEL :
s - > white_level = value ;
break ;
case TIFF_CFA_PATTERN_DIM :
if ( count ! = 2 | | ( ff_tget ( & s - > gb , type , s - > le ) ! = 2 & &
ff_tget ( & s - > gb , type , s - > le ) ! = 2 ) ) {
av_log ( s - > avctx , AV_LOG_ERROR , " CFA Pattern dimensions are not 2x2 \n " ) ;
return AVERROR_INVALIDDATA ;
}
break ;
case TIFF_CFA_PATTERN :
s - > is_bayer = 1 ;
s - > pattern [ 0 ] = ff_tget ( & s - > gb , type , s - > le ) ;
s - > pattern [ 1 ] = ff_tget ( & s - > gb , type , s - > le ) ;
s - > pattern [ 2 ] = ff_tget ( & s - > gb , type , s - > le ) ;
s - > pattern [ 3 ] = ff_tget ( & s - > gb , type , s - > le ) ;
break ;
case TIFF_PHOTOMETRIC :
switch ( value ) {
case TIFF_PHOTOMETRIC_WHITE_IS_ZERO :
case TIFF_PHOTOMETRIC_BLACK_IS_ZERO :
case TIFF_PHOTOMETRIC_RGB :
case TIFF_PHOTOMETRIC_PALETTE :
case TIFF_PHOTOMETRIC_SEPARATED :
case TIFF_PHOTOMETRIC_YCBCR :
case TIFF_PHOTOMETRIC_CFA :
case TIFF_PHOTOMETRIC_LINEAR_RAW : // Used by DNG images
s - > photometric = value ;
break ;
case TIFF_PHOTOMETRIC_ALPHA_MASK :
case TIFF_PHOTOMETRIC_CIE_LAB :
case TIFF_PHOTOMETRIC_ICC_LAB :
case TIFF_PHOTOMETRIC_ITU_LAB :
case TIFF_PHOTOMETRIC_LOG_L :
case TIFF_PHOTOMETRIC_LOG_LUV :
avpriv_report_missing_feature ( s - > avctx ,
" PhotometricInterpretation 0x%04X " ,
value ) ;
return AVERROR_PATCHWELCOME ;
default :
av_log ( s - > avctx , AV_LOG_ERROR , " PhotometricInterpretation %u is "
" unknown \n " , value ) ;
return AVERROR_INVALIDDATA ;
}
break ;
case TIFF_FILL_ORDER :
if ( value < 1 | | value > 2 ) {
av_log ( s - > avctx , AV_LOG_ERROR ,
" Unknown FillOrder value %d, trying default one \n " , value ) ;
value = 1 ;
}
s - > fill_order = value - 1 ;
break ;
case TIFF_PAL : {
GetByteContext pal_gb [ 3 ] ;
off = type_sizes [ type ] ;
if ( count / 3 > 256 | |
bytestream2_get_bytes_left ( & s - > gb ) < count / 3 * off * 3 )
return AVERROR_INVALIDDATA ;
pal_gb [ 0 ] = pal_gb [ 1 ] = pal_gb [ 2 ] = s - > gb ;
bytestream2_skip ( & pal_gb [ 1 ] , count / 3 * off ) ;
bytestream2_skip ( & pal_gb [ 2 ] , count / 3 * off * 2 ) ;
off = ( type_sizes [ type ] - 1 ) < < 3 ;
if ( off > 31U ) {
av_log ( s - > avctx , AV_LOG_ERROR , " palette shift %d is out of range \n " , off ) ;
return AVERROR_INVALIDDATA ;
}
for ( i = 0 ; i < count / 3 ; i + + ) {
uint32_t p = 0xFF000000 ;
p | = ( ff_tget ( & pal_gb [ 0 ] , type , s - > le ) > > off ) < < 16 ;
p | = ( ff_tget ( & pal_gb [ 1 ] , type , s - > le ) > > off ) < < 8 ;
p | = ff_tget ( & pal_gb [ 2 ] , type , s - > le ) > > off ;
s - > palette [ i ] = p ;
}
s - > palette_is_set = 1 ;
break ;
}
case TIFF_PLANAR :
s - > planar = value = = 2 ;
break ;
case TIFF_YCBCR_SUBSAMPLING :
if ( count ! = 2 ) {
av_log ( s - > avctx , AV_LOG_ERROR , " subsample count invalid \n " ) ;
return AVERROR_INVALIDDATA ;
}
for ( i = 0 ; i < count ; i + + ) {
s - > subsampling [ i ] = ff_tget ( & s - > gb , type , s - > le ) ;
if ( s - > subsampling [ i ] < = 0 ) {
av_log ( s - > avctx , AV_LOG_ERROR , " subsampling %d is invalid \n " , s - > subsampling [ i ] ) ;
s - > subsampling [ i ] = 1 ;
return AVERROR_INVALIDDATA ;
}
}
break ;
case TIFF_T4OPTIONS :
if ( s - > compr = = TIFF_G3 )
s - > fax_opts = value ;
break ;
case TIFF_T6OPTIONS :
if ( s - > compr = = TIFF_G4 )
s - > fax_opts = value ;
break ;
# define ADD_METADATA(count, name, sep)\
if ( ( ret = add_metadata ( count , type , name , sep , s , frame ) ) < 0 ) { \
av_log ( s - > avctx , AV_LOG_ERROR , " Error allocating temporary buffer \n " ) ; \
goto end ; \
}
case TIFF_MODEL_PIXEL_SCALE :
ADD_METADATA ( count , " ModelPixelScaleTag " , NULL ) ;
break ;
case TIFF_MODEL_TRANSFORMATION :
ADD_METADATA ( count , " ModelTransformationTag " , NULL ) ;
break ;
case TIFF_MODEL_TIEPOINT :
ADD_METADATA ( count , " ModelTiepointTag " , NULL ) ;
break ;
case TIFF_GEO_KEY_DIRECTORY :
if ( s - > geotag_count ) {
avpriv_request_sample ( s - > avctx , " Multiple geo key directories \n " ) ;
return AVERROR_INVALIDDATA ;
}
ADD_METADATA ( 1 , " GeoTIFF_Version " , NULL ) ;
ADD_METADATA ( 2 , " GeoTIFF_Key_Revision " , " . " ) ;
s - > geotag_count = ff_tget_short ( & s - > gb , s - > le ) ;
if ( s - > geotag_count > count / 4 - 1 ) {
s - > geotag_count = count / 4 - 1 ;
av_log ( s - > avctx , AV_LOG_WARNING , " GeoTIFF key directory buffer shorter than specified \n " ) ;
}
if ( bytestream2_get_bytes_left ( & s - > gb ) < s - > geotag_count * sizeof ( int16_t ) * 4
| | s - > geotag_count = = 0 ) {
s - > geotag_count = 0 ;
return - 1 ;
}
s - > geotags = av_mallocz_array ( s - > geotag_count , sizeof ( TiffGeoTag ) ) ;
if ( ! s - > geotags ) {
av_log ( s - > avctx , AV_LOG_ERROR , " Error allocating temporary buffer \n " ) ;
s - > geotag_count = 0 ;
goto end ;
}
for ( i = 0 ; i < s - > geotag_count ; i + + ) {
s - > geotags [ i ] . key = ff_tget_short ( & s - > gb , s - > le ) ;
s - > geotags [ i ] . type = ff_tget_short ( & s - > gb , s - > le ) ;
s - > geotags [ i ] . count = ff_tget_short ( & s - > gb , s - > le ) ;
if ( ! s - > geotags [ i ] . type )
s - > geotags [ i ] . val = get_geokey_val ( s - > geotags [ i ] . key , ff_tget_short ( & s - > gb , s - > le ) ) ;
else
s - > geotags [ i ] . offset = ff_tget_short ( & s - > gb , s - > le ) ;
}
break ;
case TIFF_GEO_DOUBLE_PARAMS :
if ( count > = INT_MAX / sizeof ( int64_t ) )
return AVERROR_INVALIDDATA ;
if ( bytestream2_get_bytes_left ( & s - > gb ) < count * sizeof ( int64_t ) )
return AVERROR_INVALIDDATA ;
dp = av_malloc_array ( count , sizeof ( double ) ) ;
if ( ! dp ) {
av_log ( s - > avctx , AV_LOG_ERROR , " Error allocating temporary buffer \n " ) ;
goto end ;
}
for ( i = 0 ; i < count ; i + + )
dp [ i ] = ff_tget_double ( & s - > gb , s - > le ) ;
for ( i = 0 ; i < s - > geotag_count ; i + + ) {
if ( s - > geotags [ i ] . type = = TIFF_GEO_DOUBLE_PARAMS ) {
if ( s - > geotags [ i ] . count = = 0
| | s - > geotags [ i ] . offset + s - > geotags [ i ] . count > count ) {
av_log ( s - > avctx , AV_LOG_WARNING , " Invalid GeoTIFF key %d \n " , s - > geotags [ i ] . key ) ;
} else if ( s - > geotags [ i ] . val ) {
av_log ( s - > avctx , AV_LOG_WARNING , " Duplicate GeoTIFF key %d \n " , s - > geotags [ i ] . key ) ;
} else {
char * ap = doubles2str ( & dp [ s - > geotags [ i ] . offset ] , s - > geotags [ i ] . count , " , " ) ;
if ( ! ap ) {
av_log ( s - > avctx , AV_LOG_ERROR , " Error allocating temporary buffer \n " ) ;
av_freep ( & dp ) ;
return AVERROR ( ENOMEM ) ;
}
s - > geotags [ i ] . val = ap ;
}
}
}
av_freep ( & dp ) ;
break ;
case TIFF_GEO_ASCII_PARAMS :
pos = bytestream2_tell ( & s - > gb ) ;
for ( i = 0 ; i < s - > geotag_count ; i + + ) {
if ( s - > geotags [ i ] . type = = TIFF_GEO_ASCII_PARAMS ) {
if ( s - > geotags [ i ] . count = = 0
| | s - > geotags [ i ] . offset + s - > geotags [ i ] . count > count ) {
av_log ( s - > avctx , AV_LOG_WARNING , " Invalid GeoTIFF key %d \n " , s - > geotags [ i ] . key ) ;
} else {
char * ap ;
bytestream2_seek ( & s - > gb , pos + s - > geotags [ i ] . offset , SEEK_SET ) ;
if ( bytestream2_get_bytes_left ( & s - > gb ) < s - > geotags [ i ] . count )
return AVERROR_INVALIDDATA ;
if ( s - > geotags [ i ] . val )
return AVERROR_INVALIDDATA ;
ap = av_malloc ( s - > geotags [ i ] . count ) ;
if ( ! ap ) {
av_log ( s - > avctx , AV_LOG_ERROR , " Error allocating temporary buffer \n " ) ;
return AVERROR ( ENOMEM ) ;
}
bytestream2_get_bufferu ( & s - > gb , ap , s - > geotags [ i ] . count ) ;
ap [ s - > geotags [ i ] . count - 1 ] = ' \0 ' ; //replace the "|" delimiter with a 0 byte
s - > geotags [ i ] . val = ap ;
}
}
}
break ;
case TIFF_ARTIST :
ADD_METADATA ( count , " artist " , NULL ) ;
break ;
case TIFF_COPYRIGHT :
ADD_METADATA ( count , " copyright " , NULL ) ;
break ;
case TIFF_DATE :
ADD_METADATA ( count , " date " , NULL ) ;
break ;
case TIFF_DOCUMENT_NAME :
ADD_METADATA ( count , " document_name " , NULL ) ;
break ;
case TIFF_HOST_COMPUTER :
ADD_METADATA ( count , " computer " , NULL ) ;
break ;
case TIFF_IMAGE_DESCRIPTION :
ADD_METADATA ( count , " description " , NULL ) ;
break ;
case TIFF_MAKE :
ADD_METADATA ( count , " make " , NULL ) ;
break ;
case TIFF_MODEL :
ADD_METADATA ( count , " model " , NULL ) ;
break ;
case TIFF_PAGE_NAME :
ADD_METADATA ( count , " page_name " , NULL ) ;
break ;
case TIFF_PAGE_NUMBER :
ADD_METADATA ( count , " page_number " , " / " ) ;
// need to seek back to re-read the page number
bytestream2_seek ( & s - > gb , - count * sizeof ( uint16_t ) , SEEK_CUR ) ;
// read the page number
s - > cur_page = ff_tget ( & s - > gb , TIFF_SHORT , s - > le ) ;
// get back to where we were before the previous seek
bytestream2_seek ( & s - > gb , count * sizeof ( uint16_t ) - sizeof ( uint16_t ) , SEEK_CUR ) ;
break ;
case TIFF_SOFTWARE_NAME :
ADD_METADATA ( count , " software " , NULL ) ;
break ;
case DNG_VERSION :
if ( count = = 4 ) {
unsigned int ver [ 4 ] ;
ver [ 0 ] = ff_tget ( & s - > gb , type , s - > le ) ;
ver [ 1 ] = ff_tget ( & s - > gb , type , s - > le ) ;
ver [ 2 ] = ff_tget ( & s - > gb , type , s - > le ) ;
ver [ 3 ] = ff_tget ( & s - > gb , type , s - > le ) ;
av_log ( s - > avctx , AV_LOG_DEBUG , " DNG file, version %u.%u.%u.%u \n " ,
ver [ 0 ] , ver [ 1 ] , ver [ 2 ] , ver [ 3 ] ) ;
tiff_set_type ( s , TIFF_TYPE_DNG ) ;
}
break ;
case CINEMADNG_TIME_CODES :
case CINEMADNG_FRAME_RATE :
case CINEMADNG_T_STOP :
case CINEMADNG_REEL_NAME :
case CINEMADNG_CAMERA_LABEL :
tiff_set_type ( s , TIFF_TYPE_CINEMADNG ) ;
break ;
default :
if ( s - > avctx - > err_recognition & AV_EF_EXPLODE ) {
av_log ( s - > avctx , AV_LOG_ERROR ,
" Unknown or unsupported tag %d/0x%0X \n " ,
tag , tag ) ;
return AVERROR_INVALIDDATA ;
}
}
end :
if ( s - > bpp > 64U ) {
av_log ( s - > avctx , AV_LOG_ERROR ,
" This format is not supported (bpp=%d, %d components) \n " ,
s - > bpp , count ) ;
s - > bpp = 0 ;
return AVERROR_INVALIDDATA ;
}
bytestream2_seek ( & s - > gb , start , SEEK_SET ) ;
return 0 ;
}
static int decode_frame ( AVCodecContext * avctx ,
void * data , int * got_frame , AVPacket * avpkt )
{
TiffContext * const s = avctx - > priv_data ;
AVFrame * const p = data ;
ThreadFrame frame = { . f = data } ;
unsigned off , last_off ;
int le , ret , plane , planes ;
int i , j , entries , stride ;
unsigned soff , ssize ;
uint8_t * dst ;
GetByteContext stripsizes ;
GetByteContext stripdata ;
int retry_for_subifd , retry_for_page ;
int is_dng ;
bytestream2_init ( & s - > gb , avpkt - > data , avpkt - > size ) ;
// parse image header
if ( ( ret = ff_tdecode_header ( & s - > gb , & le , & off ) ) ) {
av_log ( avctx , AV_LOG_ERROR , " Invalid TIFF header \n " ) ;
return ret ;
} else if ( off > = UINT_MAX - 14 | | avpkt - > size < off + 14 ) {
av_log ( avctx , AV_LOG_ERROR , " IFD offset is greater than image size \n " ) ;
return AVERROR_INVALIDDATA ;
}
s - > le = le ;
// TIFF_BPP is not a required tag and defaults to 1
s - > tiff_type = TIFF_TYPE_TIFF ;
again :
s - > is_thumbnail = 0 ;
s - > bppcount = s - > bpp = 1 ;
s - > photometric = TIFF_PHOTOMETRIC_NONE ;
s - > compr = TIFF_RAW ;
s - > fill_order = 0 ;
s - > white_level = 0 ;
s - > is_bayer = 0 ;
s - > is_tiled = 0 ;
s - > is_jpeg = 0 ;
s - > cur_page = 0 ;
for ( i = 0 ; i < 65536 ; i + + )
s - > dng_lut [ i ] = i ;
free_geotags ( s ) ;
// Reset these offsets so we can tell if they were set this frame
s - > stripsizesoff = s - > strippos = 0 ;
/* parse image file directory */
bytestream2_seek ( & s - > gb , off , SEEK_SET ) ;
entries = ff_tget_short ( & s - > gb , le ) ;
if ( bytestream2_get_bytes_left ( & s - > gb ) < entries * 12 )
return AVERROR_INVALIDDATA ;
for ( i = 0 ; i < entries ; i + + ) {
if ( ( ret = tiff_decode_tag ( s , p ) ) < 0 )
return ret ;
}
if ( s - > get_thumbnail & & ! s - > is_thumbnail ) {
av_log ( avctx , AV_LOG_INFO , " No embedded thumbnail present \n " ) ;
return AVERROR_EOF ;
}
/** whether we should process this IFD's SubIFD */
retry_for_subifd = s - > sub_ifd & & ( s - > get_subimage | | ( ! s - > get_thumbnail & & s - > is_thumbnail ) ) ;
/** whether we should process this multi-page IFD's next page */
retry_for_page = s - > get_page & & s - > cur_page + 1 < s - > get_page ; // get_page is 1-indexed
last_off = off ;
if ( retry_for_page ) {
// set offset to the next IFD
off = ff_tget_long ( & s - > gb , le ) ;
} else if ( retry_for_subifd ) {
// set offset to the SubIFD
off = s - > sub_ifd ;
}
if ( retry_for_subifd | | retry_for_page ) {
if ( ! off ) {
av_log ( avctx , AV_LOG_ERROR , " Requested entry not found \n " ) ;
return AVERROR_INVALIDDATA ;
}
if ( off < = last_off ) {
avpriv_request_sample ( s - > avctx , " non increasing IFD offset \n " ) ;
return AVERROR_INVALIDDATA ;
}
if ( off > = UINT_MAX - 14 | | avpkt - > size < off + 14 ) {
av_log ( avctx , AV_LOG_ERROR , " IFD offset is greater than image size \n " ) ;
return AVERROR_INVALIDDATA ;
}
s - > sub_ifd = 0 ;
goto again ;
}
/* At this point we've decided on which (Sub)IFD to process */
is_dng = ( s - > tiff_type = = TIFF_TYPE_DNG | | s - > tiff_type = = TIFF_TYPE_CINEMADNG ) ;
for ( i = 0 ; i < s - > geotag_count ; i + + ) {
const char * keyname = get_geokey_name ( s - > geotags [ i ] . key ) ;
if ( ! keyname ) {
av_log ( avctx , AV_LOG_WARNING , " Unknown or unsupported GeoTIFF key %d \n " , s - > geotags [ i ] . key ) ;
continue ;
}
if ( get_geokey_type ( s - > geotags [ i ] . key ) ! = s - > geotags [ i ] . type ) {
av_log ( avctx , AV_LOG_WARNING , " Type of GeoTIFF key %d is wrong \n " , s - > geotags [ i ] . key ) ;
continue ;
}
ret = av_dict_set ( & p - > metadata , keyname , s - > geotags [ i ] . val , 0 ) ;
if ( ret < 0 ) {
av_log ( avctx , AV_LOG_ERROR , " Writing metadata with key '%s' failed \n " , keyname ) ;
return ret ;
}
}
if ( is_dng ) {
if ( s - > white_level = = 0 )
s - > white_level = ( 1 < < s - > bpp ) - 1 ; /* Default value as per the spec */
if ( s - > white_level < = s - > black_level ) {
av_log ( avctx , AV_LOG_ERROR , " BlackLevel (% " PRId32 " ) must be less than WhiteLevel (% " PRId32 " ) \n " ,
s - > black_level , s - > white_level ) ;
return AVERROR_INVALIDDATA ;
}
}
if ( ! s - > is_tiled & & ! s - > strippos & & ! s - > stripoff ) {
av_log ( avctx , AV_LOG_ERROR , " Image data is missing \n " ) ;
return AVERROR_INVALIDDATA ;
}
/* now we have the data and may start decoding */
if ( ( ret = init_image ( s , & frame ) ) < 0 )
return ret ;
if ( ! s - > is_tiled ) {
if ( s - > strips = = 1 & & ! s - > stripsize ) {
av_log ( avctx , AV_LOG_WARNING , " Image data size missing \n " ) ;
s - > stripsize = avpkt - > size - s - > stripoff ;
}
if ( s - > stripsizesoff ) {
if ( s - > stripsizesoff > = ( unsigned ) avpkt - > size )
return AVERROR_INVALIDDATA ;
bytestream2_init ( & stripsizes , avpkt - > data + s - > stripsizesoff ,
avpkt - > size - s - > stripsizesoff ) ;
}
if ( s - > strippos ) {
if ( s - > strippos > = ( unsigned ) avpkt - > size )
return AVERROR_INVALIDDATA ;
bytestream2_init ( & stripdata , avpkt - > data + s - > strippos ,
avpkt - > size - s - > strippos ) ;
}
if ( s - > rps < = 0 | | s - > rps % s - > subsampling [ 1 ] ) {
av_log ( avctx , AV_LOG_ERROR , " rps %d invalid \n " , s - > rps ) ;
return AVERROR_INVALIDDATA ;
}
}
if ( s - > photometric = = TIFF_PHOTOMETRIC_LINEAR_RAW | |
s - > photometric = = TIFF_PHOTOMETRIC_CFA ) {
p - > color_trc = AVCOL_TRC_LINEAR ;
} else if ( s - > photometric = = TIFF_PHOTOMETRIC_BLACK_IS_ZERO ) {
p - > color_trc = AVCOL_TRC_GAMMA22 ;
}
/* Handle DNG images with JPEG-compressed tiles */
if ( is_dng & & s - > is_tiled ) {
if ( ! s - > is_jpeg ) {
avpriv_report_missing_feature ( avctx , " DNG uncompressed tiled images " ) ;
return AVERROR_PATCHWELCOME ;
} else if ( ! s - > is_bayer ) {
avpriv_report_missing_feature ( avctx , " DNG JPG-compressed tiled non-bayer-encoded images " ) ;
return AVERROR_PATCHWELCOME ;
} else {
if ( ( ret = dng_decode_tiles ( avctx , ( AVFrame * ) data , avpkt ) ) > 0 )
* got_frame = 1 ;
return ret ;
}
}
/* Handle TIFF images and DNG images with uncompressed strips (non-tiled) */
planes = s - > planar ? s - > bppcount : 1 ;
for ( plane = 0 ; plane < planes ; plane + + ) {
uint8_t * five_planes = NULL ;
int remaining = avpkt - > size ;
int decoded_height ;
stride = p - > linesize [ plane ] ;
dst = p - > data [ plane ] ;
if ( s - > photometric = = TIFF_PHOTOMETRIC_SEPARATED & &
s - > avctx - > pix_fmt = = AV_PIX_FMT_RGBA ) {
stride = stride * 5 / 4 ;
five_planes =
dst = av_malloc ( stride * s - > height ) ;
if ( ! dst )
return AVERROR ( ENOMEM ) ;
}
for ( i = 0 ; i < s - > height ; i + = s - > rps ) {
if ( i )
dst + = s - > rps * stride ;
if ( s - > stripsizesoff )
ssize = ff_tget ( & stripsizes , s - > sstype , le ) ;
else
ssize = s - > stripsize ;
if ( s - > strippos )
soff = ff_tget ( & stripdata , s - > sot , le ) ;
else
soff = s - > stripoff ;
if ( soff > avpkt - > size | | ssize > avpkt - > size - soff | | ssize > remaining ) {
av_log ( avctx , AV_LOG_ERROR , " Invalid strip size/offset \n " ) ;
av_freep ( & five_planes ) ;
return AVERROR_INVALIDDATA ;
}
remaining - = ssize ;
if ( ( ret = tiff_unpack_strip ( s , p , dst , stride , avpkt - > data + soff , ssize , i ,
FFMIN ( s - > rps , s - > height - i ) ) ) < 0 ) {
if ( avctx - > err_recognition & AV_EF_EXPLODE ) {
av_freep ( & five_planes ) ;
return ret ;
}
break ;
}
}
decoded_height = FFMIN ( i , s - > height ) ;
if ( s - > predictor = = 2 ) {
if ( s - > photometric = = TIFF_PHOTOMETRIC_YCBCR ) {
av_log ( s - > avctx , AV_LOG_ERROR , " predictor == 2 with YUV is unsupported " ) ;
return AVERROR_PATCHWELCOME ;
}
dst = five_planes ? five_planes : p - > data [ plane ] ;
soff = s - > bpp > > 3 ;
if ( s - > planar )
soff = FFMAX ( soff / s - > bppcount , 1 ) ;
ssize = s - > width * soff ;
if ( s - > avctx - > pix_fmt = = AV_PIX_FMT_RGB48LE | |
s - > avctx - > pix_fmt = = AV_PIX_FMT_RGBA64LE | |
s - > avctx - > pix_fmt = = AV_PIX_FMT_GRAY16LE | |
s - > avctx - > pix_fmt = = AV_PIX_FMT_YA16LE | |
s - > avctx - > pix_fmt = = AV_PIX_FMT_GBRP16LE | |
s - > avctx - > pix_fmt = = AV_PIX_FMT_GBRAP16LE ) {
for ( i = 0 ; i < decoded_height ; i + + ) {
for ( j = soff ; j < ssize ; j + = 2 )
AV_WL16 ( dst + j , AV_RL16 ( dst + j ) + AV_RL16 ( dst + j - soff ) ) ;
dst + = stride ;
}
} else if ( s - > avctx - > pix_fmt = = AV_PIX_FMT_RGB48BE | |
s - > avctx - > pix_fmt = = AV_PIX_FMT_RGBA64BE | |
s - > avctx - > pix_fmt = = AV_PIX_FMT_GRAY16BE | |
s - > avctx - > pix_fmt = = AV_PIX_FMT_YA16BE | |
s - > avctx - > pix_fmt = = AV_PIX_FMT_GBRP16BE | |
s - > avctx - > pix_fmt = = AV_PIX_FMT_GBRAP16BE ) {
for ( i = 0 ; i < decoded_height ; i + + ) {
for ( j = soff ; j < ssize ; j + = 2 )
AV_WB16 ( dst + j , AV_RB16 ( dst + j ) + AV_RB16 ( dst + j - soff ) ) ;
dst + = stride ;
}
} else {
for ( i = 0 ; i < decoded_height ; i + + ) {
for ( j = soff ; j < ssize ; j + + )
dst [ j ] + = dst [ j - soff ] ;
dst + = stride ;
}
}
}
if ( s - > photometric = = TIFF_PHOTOMETRIC_WHITE_IS_ZERO ) {
int c = ( s - > avctx - > pix_fmt = = AV_PIX_FMT_PAL8 ? ( 1 < < s - > bpp ) - 1 : 255 ) ;
dst = p - > data [ plane ] ;
for ( i = 0 ; i < s - > height ; i + + ) {
for ( j = 0 ; j < stride ; j + + )
dst [ j ] = c - dst [ j ] ;
dst + = stride ;
}
}
if ( s - > photometric = = TIFF_PHOTOMETRIC_SEPARATED & &
( s - > avctx - > pix_fmt = = AV_PIX_FMT_RGB0 | | s - > avctx - > pix_fmt = = AV_PIX_FMT_RGBA ) ) {
int x = s - > avctx - > pix_fmt = = AV_PIX_FMT_RGB0 ? 4 : 5 ;
uint8_t * src = five_planes ? five_planes : p - > data [ plane ] ;
dst = p - > data [ plane ] ;
for ( i = 0 ; i < s - > height ; i + + ) {
for ( j = 0 ; j < s - > width ; j + + ) {
int k = 255 - src [ x * j + 3 ] ;
int r = ( 255 - src [ x * j ] ) * k ;
int g = ( 255 - src [ x * j + 1 ] ) * k ;
int b = ( 255 - src [ x * j + 2 ] ) * k ;
dst [ 4 * j ] = r * 257 > > 16 ;
dst [ 4 * j + 1 ] = g * 257 > > 16 ;
dst [ 4 * j + 2 ] = b * 257 > > 16 ;
dst [ 4 * j + 3 ] = s - > avctx - > pix_fmt = = AV_PIX_FMT_RGBA ? src [ x * j + 4 ] : 255 ;
}
src + = stride ;
dst + = p - > linesize [ plane ] ;
}
av_freep ( & five_planes ) ;
} else if ( s - > photometric = = TIFF_PHOTOMETRIC_SEPARATED & &
s - > avctx - > pix_fmt = = AV_PIX_FMT_RGBA64BE ) {
dst = p - > data [ plane ] ;
for ( i = 0 ; i < s - > height ; i + + ) {
for ( j = 0 ; j < s - > width ; j + + ) {
uint64_t k = 65535 - AV_RB16 ( dst + 8 * j + 6 ) ;
uint64_t r = ( 65535 - AV_RB16 ( dst + 8 * j ) ) * k ;
uint64_t g = ( 65535 - AV_RB16 ( dst + 8 * j + 2 ) ) * k ;
uint64_t b = ( 65535 - AV_RB16 ( dst + 8 * j + 4 ) ) * k ;
AV_WB16 ( dst + 8 * j , r * 65537 > > 32 ) ;
AV_WB16 ( dst + 8 * j + 2 , g * 65537 > > 32 ) ;
AV_WB16 ( dst + 8 * j + 4 , b * 65537 > > 32 ) ;
AV_WB16 ( dst + 8 * j + 6 , 65535 ) ;
}
dst + = p - > linesize [ plane ] ;
}
}
}
if ( s - > planar & & s - > bppcount > 2 ) {
FFSWAP ( uint8_t * , p - > data [ 0 ] , p - > data [ 2 ] ) ;
FFSWAP ( int , p - > linesize [ 0 ] , p - > linesize [ 2 ] ) ;
FFSWAP ( uint8_t * , p - > data [ 0 ] , p - > data [ 1 ] ) ;
FFSWAP ( int , p - > linesize [ 0 ] , p - > linesize [ 1 ] ) ;
}
if ( s - > is_bayer & & s - > white_level & & s - > bpp = = 16 & & ! is_dng ) {
uint16_t * dst = ( uint16_t * ) p - > data [ 0 ] ;
for ( i = 0 ; i < s - > height ; i + + ) {
for ( j = 0 ; j < s - > width ; j + + )
dst [ j ] = FFMIN ( ( dst [ j ] / ( float ) s - > white_level ) * 65535 , 65535 ) ;
dst + = stride / 2 ;
}
}
* got_frame = 1 ;
return avpkt - > size ;
}
static av_cold int tiff_init ( AVCodecContext * avctx )
{
TiffContext * s = avctx - > priv_data ;
const AVCodec * codec ;
int ret ;
s - > width = 0 ;
s - > height = 0 ;
s - > subsampling [ 0 ] =
s - > subsampling [ 1 ] = 1 ;
s - > avctx = avctx ;
ff_lzw_decode_open ( & s - > lzw ) ;
if ( ! s - > lzw )
return AVERROR ( ENOMEM ) ;
ff_ccitt_unpack_init ( ) ;
/* Allocate JPEG frame */
s - > jpgframe = av_frame_alloc ( ) ;
if ( ! s - > jpgframe )
return AVERROR ( ENOMEM ) ;
/* Prepare everything needed for JPEG decoding */
codec = avcodec_find_decoder ( AV_CODEC_ID_MJPEG ) ;
if ( ! codec )
return AVERROR_BUG ;
s - > avctx_mjpeg = avcodec_alloc_context3 ( codec ) ;
if ( ! s - > avctx_mjpeg )
return AVERROR ( ENOMEM ) ;
s - > avctx_mjpeg - > flags = avctx - > flags ;
s - > avctx_mjpeg - > flags2 = avctx - > flags2 ;
s - > avctx_mjpeg - > dct_algo = avctx - > dct_algo ;
s - > avctx_mjpeg - > idct_algo = avctx - > idct_algo ;
ret = ff_codec_open2_recursive ( s - > avctx_mjpeg , codec , NULL ) ;
if ( ret < 0 ) {
av_frame_free ( & s - > jpgframe ) ;
avcodec_free_context ( & s - > avctx_mjpeg ) ;
return ret ;
}
return 0 ;
}
static av_cold int tiff_end ( AVCodecContext * avctx )
{
TiffContext * const s = avctx - > priv_data ;
free_geotags ( s ) ;
ff_lzw_decode_close ( & s - > lzw ) ;
av_freep ( & s - > deinvert_buf ) ;
s - > deinvert_buf_size = 0 ;
av_freep ( & s - > yuv_line ) ;
s - > yuv_line_size = 0 ;
av_freep ( & s - > fax_buffer ) ;
s - > fax_buffer_size = 0 ;
av_frame_free ( & s - > jpgframe ) ;
avcodec_free_context ( & s - > avctx_mjpeg ) ;
return 0 ;
}
# define OFFSET(x) offsetof(TiffContext, x)
static const AVOption tiff_options [ ] = {
{ " subimage " , " decode subimage instead if available " , OFFSET ( get_subimage ) , AV_OPT_TYPE_BOOL , { . i64 = 0 } , 0 , 1 , AV_OPT_FLAG_DECODING_PARAM | AV_OPT_FLAG_VIDEO_PARAM } ,
{ " thumbnail " , " decode embedded thumbnail subimage instead if available " , OFFSET ( get_thumbnail ) , AV_OPT_TYPE_BOOL , { . i64 = 0 } , 0 , 1 , AV_OPT_FLAG_DECODING_PARAM | AV_OPT_FLAG_VIDEO_PARAM } ,
{ " page " , " page number of multi-page image to decode (starting from 1) " , OFFSET ( get_page ) , AV_OPT_TYPE_INT , { . i64 = 0 } , 0 , UINT16_MAX , AV_OPT_FLAG_DECODING_PARAM | AV_OPT_FLAG_VIDEO_PARAM } ,
{ NULL } ,
} ;
static const AVClass tiff_decoder_class = {
. class_name = " TIFF decoder " ,
. item_name = av_default_item_name ,
. option = tiff_options ,
. version = LIBAVUTIL_VERSION_INT ,
} ;
AVCodec ff_tiff_decoder = {
. name = " tiff " ,
. long_name = NULL_IF_CONFIG_SMALL ( " TIFF image " ) ,
. type = AVMEDIA_TYPE_VIDEO ,
. id = AV_CODEC_ID_TIFF ,
. priv_data_size = sizeof ( TiffContext ) ,
. init = tiff_init ,
. close = tiff_end ,
. decode = decode_frame ,
. init_thread_copy = ONLY_IF_THREADS_ENABLED ( tiff_init ) ,
. capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_FRAME_THREADS ,
. priv_class = & tiff_decoder_class ,
} ;