Skip to content

Commit 11cc9b6

Browse files
committed
libvmaf/motion_v2: add motion_five_frame_window
1 parent 375f9bd commit 11cc9b6

4 files changed

Lines changed: 108 additions & 44 deletions

File tree

libvmaf/src/feature/feature_extractor.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,8 @@ typedef struct VmafFeatureExtractor {
9898
#endif
9999

100100
VmafFrameSyncContext *framesync;
101-
VmafPicture prev_ref; ///< Previous reference picture, set by framework.
101+
VmafPicture prev_ref; ///< Previous reference picture (n-1), set by framework.
102+
VmafPicture prev_prev_ref; ///< Reference picture from two frames ago (n-2), set by framework.
102103

103104
} VmafFeatureExtractor;
104105

libvmaf/src/feature/integer_motion_v2.c

Lines changed: 43 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ typedef struct MotionV2State {
6262
unsigned w, h, bpc;
6363
motion_pipeline_fn pipeline;
6464
double motion_max_val;
65+
bool motion_five_frame_window;
6566
VmafDictionary *feature_name_dict;
6667
} MotionV2State;
6768

@@ -77,6 +78,15 @@ static const VmafOption options[] = {
7778
.flags = VMAF_OPT_FLAG_FEATURE_PARAM,
7879
.alias = "mmxv",
7980
},
81+
{
82+
.name = "motion_five_frame_window",
83+
.alias = "mffw",
84+
.help = "use five-frame temporal window",
85+
.offset = offsetof(MotionV2State, motion_five_frame_window),
86+
.type = VMAF_OPT_TYPE_BOOL,
87+
.default_val.b = false,
88+
.flags = VMAF_OPT_FLAG_FEATURE_PARAM,
89+
},
8090
{ 0 }
8191
};
8292

@@ -239,21 +249,25 @@ static int extract(VmafFeatureExtractor *fex,
239249
(void) ref_pic_90;
240250
(void) dist_pic_90;
241251

242-
if (index == 0) {
252+
const unsigned min_idx = s->motion_five_frame_window ? 2 : 1;
253+
if (index < min_idx) {
243254
return vmaf_feature_collector_append_with_dict(feature_collector,
244255
s->feature_name_dict,
245256
"VMAF_integer_feature_motion_v2_sad_score", 0., index);
246257
}
247258

248-
if (!fex->prev_ref.ref)
259+
const VmafPicture *prev = s->motion_five_frame_window
260+
? &fex->prev_prev_ref
261+
: &fex->prev_ref;
262+
if (!prev->ref)
249263
return -EINVAL;
250264

251265
const unsigned w = s->w;
252266
const unsigned h = s->h;
253-
const uint8_t *prev_data = (const uint8_t *)fex->prev_ref.data[0];
267+
const uint8_t *prev_data = (const uint8_t *)prev->data[0];
254268
const uint8_t *cur_data = (const uint8_t *)ref_pic->data[0];
255269

256-
uint64_t sad = s->pipeline(prev_data, fex->prev_ref.stride[0],
270+
uint64_t sad = s->pipeline(prev_data, prev->stride[0],
257271
cur_data, ref_pic->stride[0],
258272
s->y_row, w, h, s->bpc);
259273

@@ -276,6 +290,12 @@ static int flush(VmafFeatureExtractor *fex,
276290
{
277291
MotionV2State *s = fex->priv;
278292

293+
if (!s->feature_name_dict) {
294+
s->feature_name_dict = vmaf_feature_name_dict_from_provided_features(
295+
fex->provided_features, fex->options, s);
296+
if (!s->feature_name_dict) return -ENOMEM;
297+
}
298+
279299
VmafDictionaryEntry *e_sad = vmaf_dictionary_get(&s->feature_name_dict,
280300
"VMAF_integer_feature_motion_v2_sad_score", 0);
281301
const char *sad_name =
@@ -287,20 +307,29 @@ static int flush(VmafFeatureExtractor *fex,
287307
sad_name, &dummy, n_frames))
288308
n_frames++;
289309

290-
if (n_frames < 2) return 1;
310+
const unsigned stride = s->motion_five_frame_window ? 2 : 1;
311+
const unsigned min_idx = s->motion_five_frame_window ? 2 : 1;
312+
if (n_frames == 0) return 1;
291313

292314
for (unsigned i = 0; i < n_frames; i++) {
293-
double score_cur, score_next;
294-
vmaf_feature_collector_get_score(feature_collector,
295-
sad_name, &score_cur, i);
296-
297315
double motion2;
298-
if (i + 1 < n_frames) {
299-
vmaf_feature_collector_get_score(feature_collector,
300-
sad_name, &score_next, i + 1);
301-
motion2 = score_cur < score_next ? score_cur : score_next;
316+
317+
if (i < min_idx) {
318+
motion2 = 0.;
319+
} else if (i == n_frames - 1) {
320+
vmaf_feature_collector_get_score(feature_collector, sad_name, &motion2, i);
302321
} else {
303-
motion2 = score_cur;
322+
const int lo_idx = (int)i - (int)(stride - 1);
323+
const int hi_idx = (int)i + 1;
324+
double hi;
325+
vmaf_feature_collector_get_score(feature_collector, sad_name, &hi, hi_idx);
326+
if (lo_idx >= (int)min_idx) {
327+
double lo;
328+
vmaf_feature_collector_get_score(feature_collector, sad_name, &lo, lo_idx);
329+
motion2 = lo < hi ? lo : hi;
330+
} else {
331+
motion2 = hi;
332+
}
304333
}
305334

306335
vmaf_feature_collector_append_with_dict(feature_collector,

libvmaf/src/libvmaf.c

Lines changed: 62 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,8 @@ typedef struct VmafContext {
9090
} pic_params;
9191
unsigned pic_cnt;
9292
bool flushed;
93-
VmafPicture prev_ref; // previous ref pic for PREV_REF extractors (in-order only)
93+
VmafPicture prev_ref; // n-1 ref pic for PREV_REF extractors (in-order only)
94+
VmafPicture prev_prev_ref; // n-2 ref pic for PREV_REF extractors (in-order only)
9495
} VmafContext;
9596

9697
#ifdef VMAF_BATCH_THREADING
@@ -299,8 +300,7 @@ static int check_picture_pool(VmafContext *vmaf)
299300
if (!vmaf->thread_pool) return 0;
300301
if (vmaf->picture_pool) return 0;
301302

302-
// Default to 2x thread count if not explicitly preallocated
303-
const unsigned pic_cnt = vmaf->cfg.n_threads * 2;
303+
const unsigned pic_cnt = vmaf->cfg.n_threads * 2 + 2;
304304

305305
int err = prepare_picture_pool(vmaf, pic_cnt,
306306
vmaf->pic_params.w,
@@ -351,6 +351,8 @@ int vmaf_close(VmafContext *vmaf)
351351
vmaf_thread_pool_wait(vmaf->thread_pool);
352352
if (vmaf->prev_ref.ref)
353353
vmaf_picture_unref(&vmaf->prev_ref);
354+
if (vmaf->prev_prev_ref.ref)
355+
vmaf_picture_unref(&vmaf->prev_prev_ref);
354356
vmaf_framesync_destroy(vmaf->framesync);
355357
feature_extractor_vector_destroy(&(vmaf->registered_feature_extractors));
356358
vmaf_feature_collector_destroy(vmaf->feature_collector);
@@ -486,7 +488,7 @@ int vmaf_use_features_from_model_collection(VmafContext *vmaf,
486488

487489
struct ThreadData {
488490
VmafFeatureExtractorContext *fex_ctx;
489-
VmafPicture ref, dist, prev_ref;
491+
VmafPicture ref, dist, prev_ref, prev_prev_ref;
490492
unsigned index;
491493
VmafFeatureCollector *feature_collector;
492494
VmafFeatureExtractorContextPool *fex_ctx_pool;
@@ -500,15 +502,21 @@ static void threaded_extract_func(void *e, void **thread_data)
500502

501503
if (f->prev_ref.ref)
502504
f->fex_ctx->fex->prev_ref = f->prev_ref;
505+
if (f->prev_prev_ref.ref)
506+
f->fex_ctx->fex->prev_prev_ref = f->prev_prev_ref;
503507

504508
f->err = vmaf_feature_extractor_context_extract(f->fex_ctx, &f->ref, NULL,
505509
&f->dist, NULL, f->index,
506510
f->feature_collector);
507511

508512
if (f->prev_ref.ref) {
509-
memset(&f->fex_ctx->fex->prev_ref, 0, sizeof(f->fex_ctx->fex->prev_ref));
513+
f->fex_ctx->fex->prev_ref = (VmafPicture){0};
510514
vmaf_picture_unref(&f->prev_ref);
511515
}
516+
if (f->prev_prev_ref.ref) {
517+
f->fex_ctx->fex->prev_prev_ref = (VmafPicture){0};
518+
vmaf_picture_unref(&f->prev_prev_ref);
519+
}
512520

513521
f->err = vmaf_fex_ctx_pool_release(f->fex_ctx_pool, f->fex_ctx);
514522
vmaf_picture_unref(&f->ref);
@@ -517,7 +525,7 @@ static void threaded_extract_func(void *e, void **thread_data)
517525

518526
#ifdef VMAF_BATCH_THREADING
519527
struct ThreadDataBatch {
520-
VmafPicture ref, dist, prev_ref;
528+
VmafPicture ref, dist, prev_ref, prev_prev_ref;
521529
unsigned index;
522530
VmafFeatureCollector *feature_collector;
523531
RegisteredFeatureExtractors *registered_fex;
@@ -567,6 +575,8 @@ static void threaded_extract_batch_func(void *e, void **thread_data)
567575
if (fex->flags & VMAF_FEATURE_EXTRACTOR_PREV_REF) {
568576
if (f->prev_ref.ref)
569577
td->fex_ctx[i]->fex->prev_ref = f->prev_ref;
578+
if (f->prev_prev_ref.ref)
579+
td->fex_ctx[i]->fex->prev_prev_ref = f->prev_prev_ref;
570580
}
571581

572582
int err = vmaf_feature_extractor_context_extract(td->fex_ctx[i],
@@ -575,9 +585,10 @@ static void threaded_extract_batch_func(void *e, void **thread_data)
575585
f->index,
576586
f->feature_collector);
577587

578-
if (fex->flags & VMAF_FEATURE_EXTRACTOR_PREV_REF)
579-
memset(&td->fex_ctx[i]->fex->prev_ref, 0,
580-
sizeof(td->fex_ctx[i]->fex->prev_ref));
588+
if (fex->flags & VMAF_FEATURE_EXTRACTOR_PREV_REF) {
589+
td->fex_ctx[i]->fex->prev_ref = (VmafPicture){0};
590+
td->fex_ctx[i]->fex->prev_prev_ref = (VmafPicture){0};
591+
}
581592

582593
if (err) {
583594
f->err = err;
@@ -588,6 +599,8 @@ static void threaded_extract_batch_func(void *e, void **thread_data)
588599
unref:
589600
if (f->prev_ref.ref)
590601
vmaf_picture_unref(&f->prev_ref);
602+
if (f->prev_prev_ref.ref)
603+
vmaf_picture_unref(&f->prev_prev_ref);
591604
vmaf_picture_unref(&f->ref);
592605
vmaf_picture_unref(&f->dist);
593606
}
@@ -622,21 +635,23 @@ static int threaded_read_pictures(VmafContext *vmaf, VmafPicture *ref,
622635
&fex_ctx);
623636
if (err) return err;
624637

625-
VmafPicture pic_a, pic_b, prev_ref = { 0 };
638+
VmafPicture pic_a, pic_b, prev_ref = { 0 }, prev_prev_ref = { 0 };
626639
vmaf_picture_ref(&pic_a, ref);
627640
vmaf_picture_ref(&pic_b, dist);
628641

629-
if ((fex->flags & VMAF_FEATURE_EXTRACTOR_PREV_REF) &&
630-
vmaf->prev_ref.ref)
631-
{
632-
vmaf_picture_ref(&prev_ref, &vmaf->prev_ref);
642+
if (fex->flags & VMAF_FEATURE_EXTRACTOR_PREV_REF) {
643+
if (vmaf->prev_ref.ref)
644+
vmaf_picture_ref(&prev_ref, &vmaf->prev_ref);
645+
if (vmaf->prev_prev_ref.ref)
646+
vmaf_picture_ref(&prev_prev_ref, &vmaf->prev_prev_ref);
633647
}
634648

635649
struct ThreadData data = {
636650
.fex_ctx = fex_ctx,
637651
.ref = pic_a,
638652
.dist = pic_b,
639653
.prev_ref = prev_ref,
654+
.prev_prev_ref = prev_prev_ref,
640655
.index = index,
641656
.feature_collector = vmaf->feature_collector,
642657
.fex_ctx_pool = vmaf->fex_ctx_pool,
@@ -649,12 +664,17 @@ static int threaded_read_pictures(VmafContext *vmaf, VmafPicture *ref,
649664
vmaf_picture_unref(&pic_a);
650665
vmaf_picture_unref(&pic_b);
651666
if (prev_ref.ref) vmaf_picture_unref(&prev_ref);
667+
if (prev_prev_ref.ref) vmaf_picture_unref(&prev_prev_ref);
652668
return err;
653669
}
654670
}
655671

656-
if (vmaf->prev_ref.ref)
657-
vmaf_picture_unref(&vmaf->prev_ref);
672+
if (vmaf->prev_prev_ref.ref)
673+
vmaf_picture_unref(&vmaf->prev_prev_ref);
674+
if (vmaf->prev_ref.ref) {
675+
vmaf->prev_prev_ref = vmaf->prev_ref;
676+
vmaf->prev_ref = (VmafPicture){0};
677+
}
658678
vmaf_picture_ref(&vmaf->prev_ref, ref);
659679

660680
return vmaf_picture_unref(ref) | vmaf_picture_unref(dist);
@@ -670,17 +690,20 @@ static int threaded_read_pictures_batch(VmafContext *vmaf, VmafPicture *ref,
670690

671691
int err = 0;
672692

673-
VmafPicture pic_a, pic_b, prev_ref = { 0 };
693+
VmafPicture pic_a, pic_b, prev_ref = { 0 }, prev_prev_ref = { 0 };
674694
vmaf_picture_ref(&pic_a, ref);
675695
vmaf_picture_ref(&pic_b, dist);
676696

677697
if (vmaf->prev_ref.ref)
678698
vmaf_picture_ref(&prev_ref, &vmaf->prev_ref);
699+
if (vmaf->prev_prev_ref.ref)
700+
vmaf_picture_ref(&prev_prev_ref, &vmaf->prev_prev_ref);
679701

680702
struct ThreadDataBatch data = {
681703
.ref = pic_a,
682704
.dist = pic_b,
683705
.prev_ref = prev_ref,
706+
.prev_prev_ref = prev_prev_ref,
684707
.index = index,
685708
.feature_collector = vmaf->feature_collector,
686709
.registered_fex = &vmaf->registered_feature_extractors,
@@ -694,11 +717,16 @@ static int threaded_read_pictures_batch(VmafContext *vmaf, VmafPicture *ref,
694717
vmaf_picture_unref(&pic_a);
695718
vmaf_picture_unref(&pic_b);
696719
if (prev_ref.ref) vmaf_picture_unref(&prev_ref);
720+
if (prev_prev_ref.ref) vmaf_picture_unref(&prev_prev_ref);
697721
return err;
698722
}
699723

700-
if (vmaf->prev_ref.ref)
701-
vmaf_picture_unref(&vmaf->prev_ref);
724+
if (vmaf->prev_prev_ref.ref)
725+
vmaf_picture_unref(&vmaf->prev_prev_ref);
726+
if (vmaf->prev_ref.ref) {
727+
vmaf->prev_prev_ref = vmaf->prev_ref;
728+
vmaf->prev_ref = (VmafPicture){0};
729+
}
702730
vmaf_picture_ref(&vmaf->prev_ref, ref);
703731

704732
return vmaf_picture_unref(ref) | vmaf_picture_unref(dist);
@@ -980,18 +1008,21 @@ int vmaf_read_pictures(VmafContext *vmaf, VmafPicture *ref, VmafPicture *dist,
9801008
&dist_device : &dist_host;
9811009
#endif
9821010

983-
if ((fex_ctx->fex->flags & VMAF_FEATURE_EXTRACTOR_PREV_REF) &&
984-
vmaf->prev_ref.ref)
985-
{
986-
fex_ctx->fex->prev_ref = vmaf->prev_ref;
1011+
if (fex_ctx->fex->flags & VMAF_FEATURE_EXTRACTOR_PREV_REF) {
1012+
if (vmaf->prev_ref.ref)
1013+
fex_ctx->fex->prev_ref = vmaf->prev_ref;
1014+
if (vmaf->prev_prev_ref.ref)
1015+
fex_ctx->fex->prev_prev_ref = vmaf->prev_prev_ref;
9871016
}
9881017

9891018
err = vmaf_feature_extractor_context_extract(fex_ctx, ref, NULL, dist,
9901019
NULL, index,
9911020
vmaf->feature_collector);
9921021

993-
if (fex_ctx->fex->flags & VMAF_FEATURE_EXTRACTOR_PREV_REF)
994-
memset(&fex_ctx->fex->prev_ref, 0, sizeof(fex_ctx->fex->prev_ref));
1022+
if (fex_ctx->fex->flags & VMAF_FEATURE_EXTRACTOR_PREV_REF) {
1023+
fex_ctx->fex->prev_ref = (VmafPicture){0};
1024+
fex_ctx->fex->prev_prev_ref = (VmafPicture){0};
1025+
}
9951026

9961027
if (err) return err;
9971028
}
@@ -1011,9 +1042,12 @@ int vmaf_read_pictures(VmafContext *vmaf, VmafPicture *ref, VmafPicture *dist,
10111042
#endif
10121043
}
10131044

1014-
if (vmaf->prev_ref.ref)
1015-
vmaf_picture_unref(&vmaf->prev_ref);
1016-
1045+
if (vmaf->prev_prev_ref.ref)
1046+
vmaf_picture_unref(&vmaf->prev_prev_ref);
1047+
if (vmaf->prev_ref.ref) {
1048+
vmaf->prev_prev_ref = vmaf->prev_ref;
1049+
vmaf->prev_ref = (VmafPicture){0};
1050+
}
10171051
if (ref && ref->ref)
10181052
vmaf_picture_ref(&vmaf->prev_ref, ref);
10191053
#ifdef HAVE_CUDA

libvmaf/tools/vmaf.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -291,7 +291,7 @@ int main(int argc, char *argv[])
291291
.bpc = common_bitdepth,
292292
.pix_fmt = pix_fmt_map(info.pixel_fmt),
293293
},
294-
.pic_cnt = c.thread_cnt > 0 ? (c.thread_cnt + 1) * 2 : 3,
294+
.pic_cnt = c.thread_cnt > 0 ? (c.thread_cnt + 1) * 2 + 1 : 4,
295295
};
296296

297297
err = vmaf_preallocate_pictures(vmaf, pic_cfg);

0 commit comments

Comments
 (0)