[FFmpeg-devel] mpegvideo_enc: add option to disable intra mbs in p frames

Submitted by Ramiro Polla on June 9, 2018, 3:09 p.m.

Details

Message ID CALweWgA3=A1kq3O2c9GvGUZA97YDig1FbJsZeZCB8=O1NSJwSg@mail.gmail.com
State New
Headers show

Commit Message

Ramiro Polla June 9, 2018, 3:09 p.m.
Hi Michael,

On Thu, May 10, 2018 at 11:01 PM, Michael Niedermayer
<michael@niedermayer.cc> wrote:
> On Wed, May 09, 2018 at 08:44:25PM +0200, Ramiro Polla wrote:
>> This option prevents the mpv encoders from using intra macroblocks 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.
>
> maybe a continuous variable like snows intra_penalty could achieve this
> too but give more flexibility in doing it also just partially if wanted

I like this idea better. I wanted a simple way to be able to entirely
disable intra macroblocks, but "-intra_penalty max" could cause an
overflow, so I set the max value to INT_MAX/2.

New patch attached.

Comments

Michael Niedermayer June 10, 2018, 12:32 a.m.
On Sat, Jun 09, 2018 at 05:09:13PM +0200, Ramiro Polla wrote:
> Hi Michael,
> 
> On Thu, May 10, 2018 at 11:01 PM, Michael Niedermayer
> <michael@niedermayer.cc> wrote:
> > On Wed, May 09, 2018 at 08:44:25PM +0200, Ramiro Polla wrote:
> >> This option prevents the mpv encoders from using intra macroblocks 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.
> >
> > maybe a continuous variable like snows intra_penalty could achieve this
> > too but give more flexibility in doing it also just partially if wanted
> 
> I like this idea better. I wanted a simple way to be able to entirely
> disable intra macroblocks, but "-intra_penalty max" could cause an
> overflow, so I set the max value to INT_MAX/2.
> 
> New patch attached.

LGTM

a fate test may also make sense

thx

[...]
Ramiro Polla June 17, 2018, 4:23 a.m.
On Sun, Jun 10, 2018 at 2:32 AM, Michael Niedermayer
<michael@niedermayer.cc> wrote:
> On Sat, Jun 09, 2018 at 05:09:13PM +0200, Ramiro Polla wrote:
>> On Thu, May 10, 2018 at 11:01 PM, Michael Niedermayer
>> <michael@niedermayer.cc> wrote:
>> > On Wed, May 09, 2018 at 08:44:25PM +0200, Ramiro Polla wrote:
>> >> This option prevents the mpv encoders from using intra macroblocks 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.
>> >
>> > maybe a continuous variable like snows intra_penalty could achieve this
>> > too but give more flexibility in doing it also just partially if wanted
>>
>> I like this idea better. I wanted a simple way to be able to entirely
>> disable intra macroblocks, but "-intra_penalty max" could cause an
>> overflow, so I set the max value to INT_MAX/2.
>>
>> New patch attached.
>
> LGTM
>
> a fate test may also make sense

I sent a new patch set that includes a fate test.

Patch hide | download patch | download mbox

From d2c1da02c28be5519f0ba84aa22f519a296a6d04 Mon Sep 17 00:00:00 2001
From: Ramiro Polla <ramiro.polla@gmail.com>
Date: Sat, 9 Jun 2018 17:00:26 +0200
Subject: [PATCH] mpegvideo_enc: add intra_penalty option for p frames

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 +-
 5 files changed, 13 insertions(+), 10 deletions(-)

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);
     }
-- 
2.11.0