This filter, when used in the "pad" mode, currently makes the distinction between limited and full range solely by testing for YUVJ pixel formats at link setup time. This is deprecated and should be improved to perform the detection based on the per-frame metadata. In order to make this distinction based on color range metadata, which is only known at the time of filtering frames, for simplicity, we simply allocate two copies of the "black" frame - one for limited range and the other for full range metadata. This could be done more dynamically (e.g. as-needed or simply by blitting the appropriate pixel value directly), but this change is relatively simple and preserves the structure of the existing code. This commit actually fixes a bug in FATE - the new output is correct for the first time. The previous md5 ref was of a frame that incorrectly combined full-range pixel data with limited-range black fields. The corresponding result has been updated.
Showing the changes to libavfilter (2 of 3 files). Show all
Unified · Split
| @@ -70,7 +70,7 @@ typedef struct TInterlaceContext { · 69 unmodified lines | |||
| 70 | int vsub; ///< chroma vertical subsampling | 70 | int vsub; ///< chroma vertical subsampling |
| 71 | AVFrame *cur; | 71 | AVFrame *cur; |
| 72 | AVFrame *next; | 72 | AVFrame *next; |
| 73 | uint8_t *black_data[4]; ///< buffer used to fill padded lines | 73 | uint8_t *black_data[2][4]; ///< buffer used to fill padded lines (limited/full) |
| 74 | int black_linesize[4]; | 74 | int black_linesize[4]; |
| 75 | FFDrawContext draw; | 75 | FFDrawContext draw; |
| 76 | FFDrawColor color; | 76 | FFDrawColor color; |
| @@ -201,7 +201,8 @@ static av_cold void uninit(AVFilterContext *ctx) · 200 unmodified lines | |||
| 201 | 201 | ||
| 202 | av_frame_free(&tinterlace->cur ); | 202 | av_frame_free(&tinterlace->cur ); |
| 203 | av_frame_free(&tinterlace->next); | 203 | av_frame_free(&tinterlace->next); |
| 204 | av_freep(&tinterlace->black_data[0]); | 204 | av_freep(&tinterlace->black_data[0][0]); |
| 205 | av_freep(&tinterlace->black_data[1][0]); | ||
| 205 | } | 206 | } |
| 206 | 207 | ||
| 207 | static int config_out_props(AVFilterLink *outlink) | 208 | static int config_out_props(AVFilterLink *outlink) |
| @@ -225,14 +226,22 @@ static int config_out_props(AVFilterLink *outlink) · 17 unmodified lines | |||
| 225 | int ret; | 226 | int ret; |
| 226 | ff_draw_init(&tinterlace->draw, outlink->format, 0); | 227 | ff_draw_init(&tinterlace->draw, outlink->format, 0); |
| 227 | ff_draw_color(&tinterlace->draw, &tinterlace->color, black); | 228 | ff_draw_color(&tinterlace->draw, &tinterlace->color, black); |
| 228 | if (ff_fmt_is_in(outlink->format, full_scale_yuvj_pix_fmts)) | 229 | /* limited range */ |
| 229 | tinterlace->color.comp[0].u8[0] = 0; | 230 | if (!ff_fmt_is_in(outlink->format, full_scale_yuvj_pix_fmts)) { |
| 230 | ret = av_image_alloc(tinterlace->black_data, tinterlace->black_linesize, | 231 | ret = av_image_alloc(tinterlace->black_data[0], tinterlace->black_linesize, |
| 232 | outlink->w, outlink->h, outlink->format, 16); | ||
| 233 | if (ret < 0) | ||
| 234 | return ret; | ||
| 235 | ff_fill_rectangle(&tinterlace->draw, &tinterlace->color, tinterlace->black_data[0], | ||
| 236 | tinterlace->black_linesize, 0, 0, outlink->w, outlink->h); | ||
| 237 | } | ||
| 238 | /* full range */ | ||
| 239 | tinterlace->color.comp[0].u8[0] = 0; | ||
| 240 | ret = av_image_alloc(tinterlace->black_data[1], tinterlace->black_linesize, | ||
| 231 | outlink->w, outlink->h, outlink->format, 16); | 241 | outlink->w, outlink->h, outlink->format, 16); |
| 232 | if (ret < 0) | 242 | if (ret < 0) |
| 233 | return ret; | 243 | return ret; |
| 234 | 244 | ff_fill_rectangle(&tinterlace->draw, &tinterlace->color, tinterlace->black_data[1], | |
| 235 | ff_fill_rectangle(&tinterlace->draw, &tinterlace->color, tinterlace->black_data, | ||
| 236 | tinterlace->black_linesize, 0, 0, outlink->w, outlink->h); | 245 | tinterlace->black_linesize, 0, 0, outlink->w, outlink->h); |
| 237 | } | 246 | } |
| 238 | if (tinterlace->flags & (TINTERLACE_FLAG_VLPF | TINTERLACE_FLAG_CVLPF) | 247 | if (tinterlace->flags & (TINTERLACE_FLAG_VLPF | TINTERLACE_FLAG_CVLPF) |
| @@ -360,7 +369,7 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *picref) · 121 unmodified lines | |||
| 360 | AVFilterLink *outlink = ctx->outputs[0]; | 369 | AVFilterLink *outlink = ctx->outputs[0]; |
| 361 | TInterlaceContext *tinterlace = ctx->priv; | 370 | TInterlaceContext *tinterlace = ctx->priv; |
| 362 | AVFrame *cur, *next, *out; | 371 | AVFrame *cur, *next, *out; |
| 363 | int field, tff, ret; | 372 | int field, tff, full, ret; |
| 364 | 373 | ||
| 365 | av_frame_free(&tinterlace->cur); | 374 | av_frame_free(&tinterlace->cur); |
| 366 | tinterlace->cur = tinterlace->next; | 375 | tinterlace->cur = tinterlace->next; |
| @@ -418,6 +427,7 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *picref) · 51 unmodified lines | |||
| 418 | out->sample_aspect_ratio = av_mul_q(cur->sample_aspect_ratio, av_make_q(2, 1)); | 427 | out->sample_aspect_ratio = av_mul_q(cur->sample_aspect_ratio, av_make_q(2, 1)); |
| 419 | 428 | ||
| 420 | field = (1 + outlink->frame_count_in) & 1 ? FIELD_UPPER : FIELD_LOWER; | 429 | field = (1 + outlink->frame_count_in) & 1 ? FIELD_UPPER : FIELD_LOWER; |
| 430 | full = out->color_range == AVCOL_RANGE_JPEG || ff_fmt_is_in(out->format, full_scale_yuvj_pix_fmts); | ||
| 421 | /* copy upper and lower fields */ | 431 | /* copy upper and lower fields */ |
| 422 | copy_picture_field(tinterlace, out->data, out->linesize, | 432 | copy_picture_field(tinterlace, out->data, out->linesize, |
| 423 | (const uint8_t **)cur->data, cur->linesize, | 433 | (const uint8_t **)cur->data, cur->linesize, |
| @@ -425,7 +435,7 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *picref) · 1 unmodified line | |||
| 425 | FIELD_UPPER_AND_LOWER, 1, field, tinterlace->flags); | 435 | FIELD_UPPER_AND_LOWER, 1, field, tinterlace->flags); |
| 426 | /* pad with black the other field */ | 436 | /* pad with black the other field */ |
| 427 | copy_picture_field(tinterlace, out->data, out->linesize, | 437 | copy_picture_field(tinterlace, out->data, out->linesize, |
| 428 | (const uint8_t **)tinterlace->black_data, tinterlace->black_linesize, | 438 | (const uint8_t **)tinterlace->black_data[full], tinterlace->black_linesize, |
| 429 | inlink->format, inlink->w, inlink->h, | 439 | inlink->format, inlink->w, inlink->h, |
| 430 | FIELD_UPPER_AND_LOWER, 1, !field, tinterlace->flags); | 440 | FIELD_UPPER_AND_LOWER, 1, !field, tinterlace->flags); |
| 431 | break; | 441 | break; |