@ -1901,6 +1901,72 @@ static int mjpeg_decode_app(MJpegDecodeContext *s)
}
}
if ( s - > start_code = = APP2 & & id = = AV_RB32 ( " ICC_ " ) & & len > = 10 ) {
int id2 ;
unsigned seqno ;
unsigned nummarkers ;
id = get_bits_long ( & s - > gb , 32 ) ;
id2 = get_bits_long ( & s - > gb , 24 ) ;
len - = 7 ;
if ( id ! = AV_RB32 ( " PROF " ) | | id2 ! = AV_RB24 ( " ILE " ) ) {
av_log ( s - > avctx , AV_LOG_WARNING , " Invalid ICC_PROFILE header in APP2 \n " ) ;
goto out ;
}
skip_bits ( & s - > gb , 8 ) ;
seqno = get_bits ( & s - > gb , 8 ) ;
len - = 2 ;
if ( seqno = = 0 ) {
av_log ( s - > avctx , AV_LOG_WARNING , " Invalid sequence number in APP2 \n " ) ;
goto out ;
}
nummarkers = get_bits ( & s - > gb , 8 ) ;
len - = 1 ;
if ( nummarkers = = 0 ) {
av_log ( s - > avctx , AV_LOG_WARNING , " Invalid number of markers coded in APP2 \n " ) ;
goto out ;
} else if ( s - > iccnum ! = 0 & & nummarkers ! = s - > iccnum ) {
av_log ( s - > avctx , AV_LOG_WARNING , " Mistmatch in coded number of ICC markers between markers \n " ) ;
goto out ;
} else if ( seqno > nummarkers ) {
av_log ( s - > avctx , AV_LOG_WARNING , " Mismatching sequence number and coded number of ICC markers \n " ) ;
goto out ;
}
/* Allocate if this is the first APP2 we've seen. */
if ( s - > iccnum = = 0 ) {
s - > iccdata = av_mallocz ( nummarkers * sizeof ( * ( s - > iccdata ) ) ) ;
s - > iccdatalens = av_mallocz ( nummarkers * sizeof ( * ( s - > iccdatalens ) ) ) ;
if ( ! s - > iccdata | | ! s - > iccdatalens ) {
av_log ( s - > avctx , AV_LOG_ERROR , " Could not allocate ICC data arrays \n " ) ;
return AVERROR ( ENOMEM ) ;
}
s - > iccnum = nummarkers ;
}
if ( s - > iccdata [ seqno - 1 ] ) {
av_log ( s - > avctx , AV_LOG_WARNING , " Duplicate ICC sequence number \n " ) ;
goto out ;
}
s - > iccdatalens [ seqno - 1 ] = len ;
s - > iccdata [ seqno - 1 ] = av_malloc ( len ) ;
if ( ! s - > iccdata [ seqno - 1 ] ) {
av_log ( s - > avctx , AV_LOG_ERROR , " Could not allocate ICC data buffer \n " ) ;
return AVERROR ( ENOMEM ) ;
}
memcpy ( s - > iccdata [ seqno - 1 ] , align_get_bits ( & s - > gb ) , len ) ;
skip_bits ( & s - > gb , len < < 3 ) ;
len = 0 ;
s - > iccread + + ;
if ( s - > iccread > s - > iccnum )
av_log ( s - > avctx , AV_LOG_WARNING , " Read more ICC markers than are supposed to be coded \n " ) ;
}
out :
/* slow but needed for extreme adobe jpegs */
if ( len < 0 )
@ -2097,6 +2163,20 @@ int ff_mjpeg_find_marker(MJpegDecodeContext *s,
return start_code ;
}
static void reset_icc_profile ( MJpegDecodeContext * s )
{
int i ;
if ( s - > iccdata )
for ( i = 0 ; i < s - > iccnum ; i + + )
av_freep ( & s - > iccdata [ i ] ) ;
av_freep ( & s - > iccdata ) ;
av_freep ( & s - > iccdatalens ) ;
s - > iccread = 0 ;
s - > iccnum = 0 ;
}
int ff_mjpeg_decode_frame ( AVCodecContext * avctx , void * data , int * got_frame ,
AVPacket * avpkt )
{
@ -2117,6 +2197,9 @@ int ff_mjpeg_decode_frame(AVCodecContext *avctx, void *data, int *got_frame,
av_freep ( & s - > stereo3d ) ;
s - > adobe_transform = - 1 ;
if ( s - > iccnum ! = 0 )
reset_icc_profile ( s ) ;
buf_ptr = buf ;
buf_end = buf + buf_size ;
while ( buf_ptr < buf_end ) {
@ -2509,6 +2592,29 @@ the_end:
av_freep ( & s - > stereo3d ) ;
}
if ( s - > iccnum ! = 0 & & s - > iccnum = = s - > iccread ) {
AVFrameSideData * sd ;
size_t offset = 0 ;
int total_size = 0 ;
int i ;
/* Sum size of all parts. */
for ( i = 0 ; i < s - > iccnum ; i + + )
total_size + = s - > iccdatalens [ i ] ;
sd = av_frame_new_side_data ( data , AV_FRAME_DATA_ICC_PROFILE , total_size ) ;
if ( ! sd ) {
av_log ( s - > avctx , AV_LOG_ERROR , " Could not allocate frame side data \n " ) ;
return AVERROR ( ENOMEM ) ;
}
/* Reassemble the parts, which are now in-order. */
for ( i = 0 ; i < s - > iccnum ; i + + ) {
memcpy ( sd - > data + offset , s - > iccdata [ i ] , s - > iccdatalens [ i ] ) ;
offset + = s - > iccdatalens [ i ] ;
}
}
av_dict_copy ( & ( ( AVFrame * ) data ) - > metadata , s - > exif_metadata , 0 ) ;
av_dict_free ( & s - > exif_metadata ) ;
@ -2548,6 +2654,9 @@ av_cold int ff_mjpeg_decode_end(AVCodecContext *avctx)
av_freep ( & s - > last_nnz [ i ] ) ;
}
av_dict_free ( & s - > exif_metadata ) ;
reset_icc_profile ( s ) ;
return 0 ;
}