You've already forked FFmpeg
							
							
				mirror of
				https://github.com/FFmpeg/FFmpeg.git
				synced 2025-10-30 23:18:11 +02:00 
			
		
		
		
	avcodec/fflcms2: add ff_icc_profile_sanitize
Buggy ICCv4 profiles are unfortunately used in the wild, and it's quite easy to work around them by just forcing the white point to the correct value. Display a warning just in case. See-Also: https://trac.ffmpeg.org/ticket/9673
This commit is contained in:
		| @@ -201,6 +201,57 @@ static av_always_inline void XYZ_xy(cmsCIEXYZ XYZ, AVCIExy *xy) | ||||
|     xy->y = av_d2q(k * XYZ.Y, 100000); | ||||
| } | ||||
|  | ||||
| static av_always_inline AVRational abs_sub_q(AVRational r1, AVRational r2) | ||||
| { | ||||
|     AVRational diff = av_sub_q(r1, r2); | ||||
|     /* denominator assumed to be positive */ | ||||
|     return av_make_q(abs(diff.num), diff.den); | ||||
| } | ||||
|  | ||||
| static const AVCIExy wp_d50 = { {3457, 10000}, {3585, 10000} }; /* CIE D50 */ | ||||
|  | ||||
| int ff_icc_profile_sanitize(FFIccContext *s, cmsHPROFILE profile) | ||||
| { | ||||
|     cmsCIEXYZ *white, fixed; | ||||
|     AVCIExy wpxy; | ||||
|     AVRational diff, z; | ||||
|     if (!profile) | ||||
|         return 0; | ||||
|  | ||||
|     if (cmsGetEncodedICCversion(profile) >= 0x4000000) { // ICC v4 | ||||
|         switch (cmsGetHeaderRenderingIntent(profile)) { | ||||
|         case INTENT_RELATIVE_COLORIMETRIC: | ||||
|         case INTENT_ABSOLUTE_COLORIMETRIC: ; | ||||
|             /* ICC v4 colorimetric profiles are specified to always use D50 | ||||
|              * media white point, anything else is a violation of the spec. | ||||
|              * Sadly, such profiles are incredibly common (Apple...), so make | ||||
|              * an effort to fix them. */ | ||||
|             if (!(white = cmsReadTag(profile, cmsSigMediaWhitePointTag))) | ||||
|                 return AVERROR_INVALIDDATA; | ||||
|             XYZ_xy(*white, &wpxy); | ||||
|             diff = av_add_q(abs_sub_q(wpxy.x, wp_d50.x), abs_sub_q(wpxy.y, wp_d50.y)); | ||||
|             if (av_cmp_q(diff, av_make_q(1, 1000)) > 0) { | ||||
|                 av_log(s->avctx, AV_LOG_WARNING, "Invalid colorimetric ICCv4 " | ||||
|                        "profile media white point tag (expected %.4f %.4f, " | ||||
|                        "got %.4f %.4f)\n", | ||||
|                        av_q2d(wp_d50.x), av_q2d(wp_d50.y), | ||||
|                        av_q2d(wpxy.x), av_q2d(wpxy.y)); | ||||
|                 /* x+y+z = 1 */ | ||||
|                 z = av_sub_q(av_sub_q(av_make_q(1, 1), wp_d50.x), wp_d50.y); | ||||
|                 fixed.X = av_q2d(av_div_q(wp_d50.x, wp_d50.y)) * white->Y; | ||||
|                 fixed.Y = white->Y; | ||||
|                 fixed.Z = av_q2d(av_div_q(z, wp_d50.y)) * white->Y; | ||||
|                 if (!cmsWriteTag(profile, cmsSigMediaWhitePointTag, &fixed)) | ||||
|                     return AVERROR_EXTERNAL; | ||||
|             } | ||||
|             break; | ||||
|         default: break; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     return 0; | ||||
| } | ||||
|  | ||||
| int ff_icc_profile_read_primaries(FFIccContext *s, cmsHPROFILE profile, | ||||
|                                   AVColorPrimariesDesc *out_primaries) | ||||
| { | ||||
|   | ||||
| @@ -65,6 +65,13 @@ int ff_icc_profile_generate(FFIccContext *s, | ||||
|  */ | ||||
| int ff_icc_profile_attach(FFIccContext *s, cmsHPROFILE profile, AVFrame *frame); | ||||
|  | ||||
| /** | ||||
|  * Sanitize an ICC profile to try and fix badly broken values. | ||||
|  * | ||||
|  * Returns 0 on success, or a negative error code. | ||||
|  */ | ||||
| int ff_icc_profile_sanitize(FFIccContext *s, cmsHPROFILE profile); | ||||
|  | ||||
| /** | ||||
|  * Read the color primaries and white point coefficients encoded by an ICC | ||||
|  * profile, and return the raw values in `out_primaries`. | ||||
|   | ||||
		Reference in New Issue
	
	Block a user