diff mbox

[FFmpeg-devel,4/4] mpegvideo_enc: add intra_penalty option for p frames

Message ID 20180617042117.3844-4-ramiro.polla@gmail.com
State New
Headers show

Commit Message

Ramiro Polla June 17, 2018, 4:21 a.m. UTC
This option allows more control over the use of intra macroblocks in
predictive frames.

By using '-intra_penalty max', intra macroblocks are never used in
predictive frames.

It is useful for glitch artists to generate input material. This option
allows them to split and merge two video files while maintaining fluid
motion from the second video without having intra macroblocks restoring
chunks of the first video.
---
 libavcodec/motion_est.c                   | 10 ++++----
 libavcodec/motion_est.h                   |  2 +-
 libavcodec/mpegvideo.h                    |  3 +++
 libavcodec/mpegvideo_enc.c                |  6 ++---
 libavcodec/svq1enc.c                      |  2 +-
 tests/fate-run.sh                         |  8 +++++++
 tests/fate/mpeg4.mak                      |  5 ++++
 tests/fate/seek.mak                       |  1 +
 tests/fate/vcodec.mak                     |  4 ++++
 tests/ref/fate/mpeg4-nopimb               |  1 +
 tests/ref/seek/vsynth_lena-mpeg4-nopimb   | 40 +++++++++++++++++++++++++++++++
 tests/ref/vsynth/vsynth1-mpeg4-nopimb     |  4 ++++
 tests/ref/vsynth/vsynth2-mpeg4-nopimb     |  4 ++++
 tests/ref/vsynth/vsynth3-mpeg4-nopimb     |  4 ++++
 tests/ref/vsynth/vsynth_lena-mpeg4-nopimb |  4 ++++
 15 files changed, 88 insertions(+), 10 deletions(-)
 create mode 100644 tests/ref/fate/mpeg4-nopimb
 create mode 100644 tests/ref/seek/vsynth_lena-mpeg4-nopimb
 create mode 100644 tests/ref/vsynth/vsynth1-mpeg4-nopimb
 create mode 100644 tests/ref/vsynth/vsynth2-mpeg4-nopimb
 create mode 100644 tests/ref/vsynth/vsynth3-mpeg4-nopimb
 create mode 100644 tests/ref/vsynth/vsynth_lena-mpeg4-nopimb
diff mbox

Patch

diff --git a/libavcodec/motion_est.c b/libavcodec/motion_est.c
index 8b5ce2117a..fa750e39ec 100644
--- a/libavcodec/motion_est.c
+++ b/libavcodec/motion_est.c
@@ -971,7 +971,7 @@  void ff_estimate_p_frame_motion(MpegEncContext * s,
         int i_score= varc-500+(s->lambda2>>FF_LAMBDA_SHIFT)*20;
         c->scene_change_score+= ff_sqrt(p_score) - ff_sqrt(i_score);
 
-        if (vard*2 + 200*256 > varc)
+        if (vard*2 + 200*256 > varc && !s->intra_penalty)
             mb_type|= CANDIDATE_MB_TYPE_INTRA;
         if (varc*2 + 200*256 > vard || s->qscale > 24){
 //        if (varc*2 + 200*256 + 50*(s->lambda2>>FF_LAMBDA_SHIFT) > vard){
@@ -1040,7 +1040,7 @@  void ff_estimate_p_frame_motion(MpegEncContext * s,
 
             intra_score= s->mecc.mb_cmp[0](s, c->scratchpad, pix, s->linesize, 16);
         }
-        intra_score += c->mb_penalty_factor*16;
+        intra_score += c->mb_penalty_factor*16 + s->intra_penalty;
 
         if(intra_score < dmin){
             mb_type= CANDIDATE_MB_TYPE_INTRA;
@@ -1648,7 +1648,7 @@  int ff_get_best_fcode(MpegEncContext * s, int16_t (*mv_table)[2], int type)
     }
 }
 
-void ff_fix_long_p_mvs(MpegEncContext * s)
+void ff_fix_long_p_mvs(MpegEncContext * s, int type)
 {
     MotionEstContext * const c= &s->me;
     const int f_code= s->f_code;
@@ -1682,8 +1682,8 @@  void ff_fix_long_p_mvs(MpegEncContext * s)
                         if(   mx >=range || mx <-range
                            || my >=range || my <-range){
                             s->mb_type[i] &= ~CANDIDATE_MB_TYPE_INTER4V;
-                            s->mb_type[i] |= CANDIDATE_MB_TYPE_INTRA;
-                            s->current_picture.mb_type[i] = CANDIDATE_MB_TYPE_INTRA;
+                            s->mb_type[i] |= type;
+                            s->current_picture.mb_type[i] = type;
                         }
                     }
                 }
diff --git a/libavcodec/motion_est.h b/libavcodec/motion_est.h
index 3b3a8d7341..817220f340 100644
--- a/libavcodec/motion_est.h
+++ b/libavcodec/motion_est.h
@@ -127,7 +127,7 @@  int ff_get_mb_score(struct MpegEncContext *s, int mx, int my, int src_index,
 int ff_get_best_fcode(struct MpegEncContext *s,
                       int16_t (*mv_table)[2], int type);
 
-void ff_fix_long_p_mvs(struct MpegEncContext *s);
+void ff_fix_long_p_mvs(struct MpegEncContext *s, int type);
 void ff_fix_long_mvs(struct MpegEncContext *s, uint8_t *field_select_table,
                      int field_select, int16_t (*mv_table)[2], int f_code,
                      int type, int truncate);
diff --git a/libavcodec/mpegvideo.h b/libavcodec/mpegvideo.h
index e16deb64e7..7eda962ba7 100644
--- a/libavcodec/mpegvideo.h
+++ b/libavcodec/mpegvideo.h
@@ -577,6 +577,8 @@  typedef struct MpegEncContext {
 
     int scenechange_threshold;
     int noise_reduction;
+
+    int intra_penalty;
 } MpegEncContext;
 
 /* mpegvideo_enc common options */
@@ -661,6 +663,7 @@  FF_MPV_OPT_CMP_FUNC, \
 {"ps", "RTP payload size in bytes",                             FF_MPV_OFFSET(rtp_payload_size), AV_OPT_TYPE_INT, {.i64 = 0 }, INT_MIN, INT_MAX, FF_MPV_OPT_FLAGS }, \
 {"mepc", "Motion estimation bitrate penalty compensation (1.0 = 256)", FF_MPV_OFFSET(me_penalty_compensation), AV_OPT_TYPE_INT, {.i64 = 256 }, INT_MIN, INT_MAX, FF_MPV_OPT_FLAGS }, \
 {"mepre", "pre motion estimation", FF_MPV_OFFSET(me_pre), AV_OPT_TYPE_INT, {.i64 = 0 }, INT_MIN, INT_MAX, FF_MPV_OPT_FLAGS }, \
+{"intra_penalty", "Penalty for intra blocks in block decision", FF_MPV_OFFSET(intra_penalty), AV_OPT_TYPE_INT, {.i64 = 0 }, 0, INT_MAX/2, FF_MPV_OPT_FLAGS }, \
 
 extern const AVOption ff_mpv_generic_options[];
 
diff --git a/libavcodec/mpegvideo_enc.c b/libavcodec/mpegvideo_enc.c
index 9fdab31a25..94e31e01eb 100644
--- a/libavcodec/mpegvideo_enc.c
+++ b/libavcodec/mpegvideo_enc.c
@@ -3761,14 +3761,14 @@  static int encode_picture(MpegEncContext *s, int picture_number)
                 s->f_code= FFMAX3(s->f_code, a, b);
             }
 
-            ff_fix_long_p_mvs(s);
-            ff_fix_long_mvs(s, NULL, 0, s->p_mv_table, s->f_code, CANDIDATE_MB_TYPE_INTER, 0);
+            ff_fix_long_p_mvs(s, s->intra_penalty ? CANDIDATE_MB_TYPE_INTER : CANDIDATE_MB_TYPE_INTRA);
+            ff_fix_long_mvs(s, NULL, 0, s->p_mv_table, s->f_code, CANDIDATE_MB_TYPE_INTER, !!s->intra_penalty);
             if (s->avctx->flags & AV_CODEC_FLAG_INTERLACED_ME) {
                 int j;
                 for(i=0; i<2; i++){
                     for(j=0; j<2; j++)
                         ff_fix_long_mvs(s, s->p_field_select_table[i], j,
-                                        s->p_field_mv_table[i][j], s->f_code, CANDIDATE_MB_TYPE_INTER_I, 0);
+                                        s->p_field_mv_table[i][j], s->f_code, CANDIDATE_MB_TYPE_INTER_I, !!s->intra_penalty);
                 }
             }
         }
diff --git a/libavcodec/svq1enc.c b/libavcodec/svq1enc.c
index 80a8af1ef7..651013588f 100644
--- a/libavcodec/svq1enc.c
+++ b/libavcodec/svq1enc.c
@@ -345,7 +345,7 @@  static int svq1_encode_plane(SVQ1EncContext *s, int plane,
             s->m.first_slice_line = 0;
         }
 
-        ff_fix_long_p_mvs(&s->m);
+        ff_fix_long_p_mvs(&s->m, CANDIDATE_MB_TYPE_INTRA);
         ff_fix_long_mvs(&s->m, NULL, 0, s->m.p_mv_table, s->m.f_code,
                         CANDIDATE_MB_TYPE_INTER, 0);
     }
diff --git a/tests/fate-run.sh b/tests/fate-run.sh
index 457761c152..c70c422b88 100755
--- a/tests/fate-run.sh
+++ b/tests/fate-run.sh
@@ -120,6 +120,14 @@  probegaplessinfo(){
     tail -n 9 "$framefile1"
 }
 
+probenopimb(){
+    mb_types_file="${outdir}/${test}.mb_types"
+    run ffprobe${PROGSUF} -bitexact -flags2 +export_mb_types -show_frames -v 0 "$@"        \
+        | awk '/mb_types/ { if (!skip) { skip=1 } else { gsub(".*mb_types",""); print } }' \
+        > "$mb_types_file"
+    grep "[iI]" "$mb_types_file" || echo "No intra macroblocks found in P frames"
+}
+
 ffmpeg(){
     dec_opts="-hwaccel $hwaccel -threads $threads -thread_type $thread_type"
     ffmpeg_args="-nostdin -nostats -cpuflags $cpuflags"
diff --git a/tests/fate/mpeg4.mak b/tests/fate/mpeg4.mak
index ed6a2fac20..3a50e8a9b2 100644
--- a/tests/fate/mpeg4.mak
+++ b/tests/fate/mpeg4.mak
@@ -15,5 +15,10 @@  FATE_MPEG4-$(call DEMDEC, M4V, MPEG4) += fate-m4v  fate-m4v-cfr
 fate-m4v:     CMD = framecrc -flags +bitexact -idct simple -i $(TARGET_SAMPLES)/mpeg4/demo.m4v
 fate-m4v-cfr: CMD = framecrc -flags +bitexact -idct simple -i $(TARGET_SAMPLES)/mpeg4/demo.m4v -vf fps=5
 
+FATE_MPEG4-$(call ENCDEC, MPEG4, AVI) += fate-mpeg4-nopimb
+fate-mpeg4-nopimb: ffprobe$(PROGSSUF)$(EXESUF)
+fate-mpeg4-nopimb: $(TARGET_PATH)/tests/data/fate/vsynth_lena-mpeg4-nopimb.avi
+fate-mpeg4-nopimb: CMD = probenopimb $(TARGET_PATH)/tests/data/fate/vsynth_lena-mpeg4-nopimb.avi
+
 FATE_SAMPLES_AVCONV += $(FATE_MPEG4-yes)
 fate-mpeg4: $(FATE_MPEG4-yes)
diff --git a/tests/fate/seek.mak b/tests/fate/seek.mak
index 6a9f843d82..01b69c1a43 100644
--- a/tests/fate/seek.mak
+++ b/tests/fate/seek.mak
@@ -144,6 +144,7 @@  fate-seek-vsynth_lena-mpeg4-qpel:        SRC = fate/vsynth_lena-mpeg4-qpel.avi
 fate-seek-vsynth_lena-mpeg4-qprd:        SRC = fate/vsynth_lena-mpeg4-qprd.avi
 fate-seek-vsynth_lena-mpeg4-rc:          SRC = fate/vsynth_lena-mpeg4-rc.avi
 fate-seek-vsynth_lena-mpeg4-thread:      SRC = fate/vsynth_lena-mpeg4-thread.avi
+fate-seek-vsynth_lena-mpeg4-nopimb:      SRC = fate/vsynth_lena-mpeg4-nopimb.avi
 fate-seek-vsynth_lena-msmpeg4:           SRC = fate/vsynth_lena-msmpeg4.avi
 fate-seek-vsynth_lena-msmpeg4v2:         SRC = fate/vsynth_lena-msmpeg4v2.avi
 fate-seek-vsynth_lena-rgb:               SRC = fate/vsynth_lena-rgb.avi
diff --git a/tests/fate/vcodec.mak b/tests/fate/vcodec.mak
index bbcf25d72a..a26dd55a1e 100644
--- a/tests/fate/vcodec.mak
+++ b/tests/fate/vcodec.mak
@@ -274,6 +274,7 @@  FATE_MPEG4_AVI = mpeg4-rc                                               \
                  mpeg4-qpel                                             \
                  mpeg4-thread                                           \
                  mpeg4-error                                            \
+                 mpeg4-nopimb                                           \
                  mpeg4-nr                                               \
                  mpeg4-nsse
 
@@ -317,6 +318,9 @@  fate-vsynth%-mpeg4-thread:       ENCOPTS = -b 500k -flags +mv4+aic         \
                                            -mbd bits -ps 200 -bf 2         \
                                            -threads 2 -slices 2
 
+fate-vsynth%-mpeg4-nopimb:       ENCOPTS = -q 0 -g 600 -flags +mv4 \
+                                           -intra_penalty max
+
 FATE_VCODEC-$(call ENCDEC, MSMPEG4V3, AVI) += msmpeg4
 fate-vsynth%-msmpeg4:            ENCOPTS = -qscale 10
 
diff --git a/tests/ref/fate/mpeg4-nopimb b/tests/ref/fate/mpeg4-nopimb
new file mode 100644
index 0000000000..e5d4f4ebb9
--- /dev/null
+++ b/tests/ref/fate/mpeg4-nopimb
@@ -0,0 +1 @@ 
+No intra macroblocks found in P frames
diff --git a/tests/ref/seek/vsynth_lena-mpeg4-nopimb b/tests/ref/seek/vsynth_lena-mpeg4-nopimb
new file mode 100644
index 0000000000..c995eaaf8e
--- /dev/null
+++ b/tests/ref/seek/vsynth_lena-mpeg4-nopimb
@@ -0,0 +1,40 @@ 
+ret: 0         st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos:   5652 size: 32508
+ret: 0         st:-1 flags:0  ts:-1.000000
+ret: 0         st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos:   5652 size: 32508
+ret: 0         st:-1 flags:1  ts: 1.894167
+ret: 0         st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos:   5652 size: 32508
+ret:-1         st: 0 flags:0  ts: 0.800000
+ret:-1         st: 0 flags:1  ts:-0.320000
+ret:-1         st:-1 flags:0  ts: 2.576668
+ret: 0         st:-1 flags:1  ts: 1.470835
+ret: 0         st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos:   5652 size: 32508
+ret:-1         st: 0 flags:0  ts: 0.360000
+ret:-1         st: 0 flags:1  ts:-0.760000
+ret:-1         st:-1 flags:0  ts: 2.153336
+ret: 0         st:-1 flags:1  ts: 1.047503
+ret: 0         st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos:   5652 size: 32508
+ret: 0         st: 0 flags:0  ts:-0.040000
+ret: 0         st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos:   5652 size: 32508
+ret: 0         st: 0 flags:1  ts: 2.840000
+ret: 0         st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos:   5652 size: 32508
+ret:-1         st:-1 flags:0  ts: 1.730004
+ret: 0         st:-1 flags:1  ts: 0.624171
+ret: 0         st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos:   5652 size: 32508
+ret: 0         st: 0 flags:0  ts:-0.480000
+ret: 0         st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos:   5652 size: 32508
+ret: 0         st: 0 flags:1  ts: 2.400000
+ret: 0         st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos:   5652 size: 32508
+ret:-1         st:-1 flags:0  ts: 1.306672
+ret: 0         st:-1 flags:1  ts: 0.200839
+ret: 0         st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos:   5652 size: 32508
+ret: 0         st: 0 flags:0  ts:-0.920000
+ret: 0         st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos:   5652 size: 32508
+ret: 0         st: 0 flags:1  ts: 2.000000
+ret: 0         st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos:   5652 size: 32508
+ret:-1         st:-1 flags:0  ts: 0.883340
+ret:-1         st:-1 flags:1  ts:-0.222493
+ret:-1         st: 0 flags:0  ts: 2.680000
+ret: 0         st: 0 flags:1  ts: 1.560000
+ret: 0         st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos:   5652 size: 32508
+ret:-1         st:-1 flags:0  ts: 0.460008
+ret:-1         st:-1 flags:1  ts:-0.645825
diff --git a/tests/ref/vsynth/vsynth1-mpeg4-nopimb b/tests/ref/vsynth/vsynth1-mpeg4-nopimb
new file mode 100644
index 0000000000..130a11e2bf
--- /dev/null
+++ b/tests/ref/vsynth/vsynth1-mpeg4-nopimb
@@ -0,0 +1,4 @@ 
+680d1f6781b56b84511f44a2a6cdc8ee *tests/data/fate/vsynth1-mpeg4-nopimb.avi
+2269928 tests/data/fate/vsynth1-mpeg4-nopimb.avi
+edc9040556f8b6dde2d56bda1fce6fbd *tests/data/fate/vsynth1-mpeg4-nopimb.out.rawvideo
+stddev:    2.05 PSNR: 41.88 MAXDIFF:   21 bytes:  7603200/  7603200
diff --git a/tests/ref/vsynth/vsynth2-mpeg4-nopimb b/tests/ref/vsynth/vsynth2-mpeg4-nopimb
new file mode 100644
index 0000000000..ecfe89679f
--- /dev/null
+++ b/tests/ref/vsynth/vsynth2-mpeg4-nopimb
@@ -0,0 +1,4 @@ 
+6cecfca24ed27930d41ebb246ec876d9 *tests/data/fate/vsynth2-mpeg4-nopimb.avi
+989664 tests/data/fate/vsynth2-mpeg4-nopimb.avi
+10e4986c94cacfdcc210af1a76f1f798 *tests/data/fate/vsynth2-mpeg4-nopimb.out.rawvideo
+stddev:    2.01 PSNR: 42.04 MAXDIFF:   20 bytes:  7603200/  7603200
diff --git a/tests/ref/vsynth/vsynth3-mpeg4-nopimb b/tests/ref/vsynth/vsynth3-mpeg4-nopimb
new file mode 100644
index 0000000000..1d4e424fce
--- /dev/null
+++ b/tests/ref/vsynth/vsynth3-mpeg4-nopimb
@@ -0,0 +1,4 @@ 
+0f568ae3bb45f86e9aa759440361b1c5 *tests/data/fate/vsynth3-mpeg4-nopimb.avi
+101148 tests/data/fate/vsynth3-mpeg4-nopimb.avi
+020d49b3b551ce6eef32b2e077a07e74 *tests/data/fate/vsynth3-mpeg4-nopimb.out.rawvideo
+stddev:    2.40 PSNR: 40.51 MAXDIFF:   17 bytes:    86700/    86700
diff --git a/tests/ref/vsynth/vsynth_lena-mpeg4-nopimb b/tests/ref/vsynth/vsynth_lena-mpeg4-nopimb
new file mode 100644
index 0000000000..03fb7dcf68
--- /dev/null
+++ b/tests/ref/vsynth/vsynth_lena-mpeg4-nopimb
@@ -0,0 +1,4 @@ 
+2808db89fee897cba848e20bf11a1712 *tests/data/fate/vsynth_lena-mpeg4-nopimb.avi
+738170 tests/data/fate/vsynth_lena-mpeg4-nopimb.avi
+c5bf55f93024605d507209ef1c69783d *tests/data/fate/vsynth_lena-mpeg4-nopimb.out.rawvideo
+stddev:    1.91 PSNR: 42.50 MAXDIFF:   19 bytes:  7603200/  7603200