[FFmpeg-cvslog] libavcodec/cinepakenc: Mark no-skip frames as keyframes

Tomas Härdin git at videolan.org
Thu May 12 13:03:15 EEST 2022


ffmpeg | branch: master | Tomas Härdin <git at haerdin.se> | Sat Apr  9 14:38:47 2022 +0200| [1cd8596ef4155347fb9c334b95521b92bd75b6f8] | committer: Tomas Härdin

libavcodec/cinepakenc: Mark no-skip frames as keyframes

Reset curframe whenever we generate a keyframe.
Use -g instead of -keyint_min.

> http://git.videolan.org/gitweb.cgi/ffmpeg.git/?a=commit;h=1cd8596ef4155347fb9c334b95521b92bd75b6f8
---

 libavcodec/cinepakenc.c              | 50 +++++++++++++++++++++++++-----------
 tests/ref/vsynth/vsynth1-cinepak     |  8 +++---
 tests/ref/vsynth/vsynth2-cinepak     |  8 +++---
 tests/ref/vsynth/vsynth_lena-cinepak |  6 ++---
 4 files changed, 46 insertions(+), 26 deletions(-)

diff --git a/libavcodec/cinepakenc.c b/libavcodec/cinepakenc.c
index 8b32c02780..6cfe8de200 100644
--- a/libavcodec/cinepakenc.c
+++ b/libavcodec/cinepakenc.c
@@ -113,7 +113,7 @@ typedef struct CinepakEncContext {
     enum AVPixelFormat pix_fmt;
     int w, h;
     int frame_buf_size;
-    int curframe, keyint;
+    int curframe;
     AVLFG randctx;
     uint64_t lambda;
     int *codebook_input;
@@ -215,7 +215,6 @@ static av_cold int cinepak_encode_init(AVCodecContext *avctx)
     s->h              = avctx->height;
     s->frame_buf_size = frame_buf_size;
     s->curframe       = 0;
-    s->keyint         = avctx->keyint_min;
     s->pix_fmt        = avctx->pix_fmt;
 
     // set up AVFrames
@@ -835,8 +834,7 @@ static void calculate_skip_errors(CinepakEncContext *s, int h,
         }
 }
 
-static void write_strip_header(CinepakEncContext *s, int y, int h, int keyframe,
-                               unsigned char *buf, int strip_size)
+static void write_strip_keyframe(unsigned char *buf, int keyframe)
 {
     // actually we are exclusively using intra strip coding (how much can we win
     // otherwise? how to choose which part of a codebook to update?),
@@ -844,6 +842,12 @@ static void write_strip_header(CinepakEncContext *s, int y, int h, int keyframe,
     // (besides, the logic here used to be inverted: )
     //    buf[0] = keyframe ? 0x11: 0x10;
     buf[0] = keyframe ? 0x10 : 0x11;
+}
+
+static void write_strip_header(CinepakEncContext *s, int y, int h, int keyframe,
+                               unsigned char *buf, int strip_size)
+{
+    write_strip_keyframe(buf, keyframe);
     AV_WB24(&buf[1], strip_size + STRIP_HEADER_SIZE);
     // AV_WB16(&buf[4], y); /* using absolute y values works -- rl */
     AV_WB16(&buf[4], 0); /* using relative values works as well -- rl */
@@ -857,7 +861,7 @@ static int rd_strip(CinepakEncContext *s, int y, int h, int keyframe,
                     uint8_t *last_data[4], int last_linesize[4],
                     uint8_t *data[4], int linesize[4],
                     uint8_t *scratch_data[4], int scratch_linesize[4],
-                    unsigned char *buf, int64_t *best_score)
+                    unsigned char *buf, int64_t *best_score, int *no_skip)
 {
     int64_t score = 0;
     int best_size = 0;
@@ -973,6 +977,9 @@ static int rd_strip(CinepakEncContext *s, int y, int h, int keyframe,
                                             scratch_data, scratch_linesize,
                                             last_data, last_linesize, &info,
                                             s->strip_buf + STRIP_HEADER_SIZE);
+                    // in theory we could have MODE_MC without ENC_SKIP,
+                    // but MODE_V1_V4 will always be more efficient
+                    *no_skip = info.mode != MODE_MC;
 
                     write_strip_header(s, y, h, keyframe, s->strip_buf, best_size);
                 }
@@ -999,13 +1006,13 @@ static int write_cvid_header(CinepakEncContext *s, unsigned char *buf,
 }
 
 static int rd_frame(CinepakEncContext *s, const AVFrame *frame,
-                    int isakeyframe, unsigned char *buf, int buf_size)
+                    int isakeyframe, unsigned char *buf, int buf_size, int *got_keyframe)
 {
     int num_strips, strip, i, y, nexty, size, temp_size, best_size;
     uint8_t *last_data    [4], *data    [4], *scratch_data    [4];
     int      last_linesize[4],  linesize[4],  scratch_linesize[4];
     int64_t best_score = 0, score, score_temp;
-    int best_nstrips;
+    int best_nstrips, best_strip_offsets[MAX_STRIPS];
 
     if (s->pix_fmt == AV_PIX_FMT_RGB24) {
         int x;
@@ -1064,12 +1071,15 @@ static int rd_frame(CinepakEncContext *s, const AVFrame *frame,
     // would be nice but quite certainly incompatible with vintage players:
     // support encoding zero strips (meaning skip the whole frame)
     for (num_strips = s->min_strips; num_strips <= s->max_strips && num_strips <= s->h / MB_SIZE; num_strips++) {
+        int strip_offsets[MAX_STRIPS];
+        int all_no_skip = 1;
         score = 0;
         size  = 0;
 
         for (y = 0, strip = 1; y < s->h; strip++, y = nexty) {
-            int strip_height;
+            int strip_height, no_skip;
 
+            strip_offsets[strip-1] = size + CVID_HEADER_SIZE;
             nexty = strip * s->h / num_strips; // <= s->h
             // make nexty the next multiple of 4 if not already there
             if (nexty & 3)
@@ -1099,21 +1109,24 @@ static int rd_frame(CinepakEncContext *s, const AVFrame *frame,
             if ((temp_size = rd_strip(s, y, strip_height, isakeyframe,
                                       last_data, last_linesize, data, linesize,
                                       scratch_data, scratch_linesize,
-                                      s->frame_buf + size + CVID_HEADER_SIZE,
-                                      &score_temp)) < 0)
+                                      s->frame_buf + strip_offsets[strip-1],
+                                      &score_temp, &no_skip)) < 0)
                 return temp_size;
 
             score += score_temp;
             size += temp_size;
+            all_no_skip &= no_skip;
         }
 
         if (best_score == 0 || score < best_score) {
             best_score = score;
-            best_size = size + write_cvid_header(s, s->frame_buf, num_strips, size, isakeyframe);
+            best_size = size + write_cvid_header(s, s->frame_buf, num_strips, size, all_no_skip);
 
             FFSWAP(AVFrame *, s->best_frame, s->scratch_frame);
             memcpy(buf, s->frame_buf, best_size);
             best_nstrips = num_strips;
+            *got_keyframe = all_no_skip; // no skip MBs in any strip -> keyframe
+            memcpy(best_strip_offsets, strip_offsets, sizeof(strip_offsets));
         }
         // avoid trying too many strip numbers without a real reason
         // (this makes the processing of the very first frame faster)
@@ -1121,6 +1134,11 @@ static int rd_frame(CinepakEncContext *s, const AVFrame *frame,
             break;
     }
 
+    // update strip headers
+    for (i = 0; i < best_nstrips; i++) {
+        write_strip_keyframe(s->frame_buf + best_strip_offsets[i], *got_keyframe);
+    }
+
     // let the number of strips slowly adapt to the changes in the contents,
     // compared to full bruteforcing every time this will occasionally lead
     // to some r/d performance loss but makes encoding up to several times faster
@@ -1151,21 +1169,23 @@ static int cinepak_encode_frame(AVCodecContext *avctx, AVPacket *pkt,
                                 const AVFrame *frame, int *got_packet)
 {
     CinepakEncContext *s = avctx->priv_data;
-    int ret;
+    int ret, got_keyframe;
 
     s->lambda = frame->quality ? frame->quality - 1 : 2 * FF_LAMBDA_SCALE;
 
     if ((ret = ff_alloc_packet(avctx, pkt, s->frame_buf_size)) < 0)
         return ret;
-    ret       = rd_frame(s, frame, (s->curframe == 0), pkt->data, s->frame_buf_size);
+    ret       = rd_frame(s, frame, (s->curframe == 0), pkt->data, s->frame_buf_size, &got_keyframe);
     pkt->size = ret;
-    if (s->curframe == 0)
+    if (got_keyframe) {
         pkt->flags |= AV_PKT_FLAG_KEY;
+        s->curframe = 0;
+    }
     *got_packet = 1;
 
     FFSWAP(AVFrame *, s->last_frame, s->best_frame);
 
-    if (++s->curframe >= s->keyint)
+    if (++s->curframe >= avctx->gop_size)
         s->curframe = 0;
 
     return 0;
diff --git a/tests/ref/vsynth/vsynth1-cinepak b/tests/ref/vsynth/vsynth1-cinepak
index e47ae26b6d..7cb33220e7 100644
--- a/tests/ref/vsynth/vsynth1-cinepak
+++ b/tests/ref/vsynth/vsynth1-cinepak
@@ -1,4 +1,4 @@
-cd28e47a6ac396240a3fee69f15625d1 *tests/data/fate/vsynth1-cinepak.avi
-408616 tests/data/fate/vsynth1-cinepak.avi
-e74066a028c708f467272884ecd3f7d3 *tests/data/fate/vsynth1-cinepak.out.rawvideo
-stddev:   61.38 PSNR: 12.37 MAXDIFF:  225 bytes:  7603200/   921600
+6b9b4d2b32854fd8b0f84ee4d76b1fed *tests/data/fate/vsynth1-cinepak.avi
+408910 tests/data/fate/vsynth1-cinepak.avi
+4acdcc3e664d12facbcefc389079cfa6 *tests/data/fate/vsynth1-cinepak.out.rawvideo
+stddev:   61.38 PSNR: 12.37 MAXDIFF:  223 bytes:  7603200/   921600
diff --git a/tests/ref/vsynth/vsynth2-cinepak b/tests/ref/vsynth/vsynth2-cinepak
index 835de78d16..72b8794116 100644
--- a/tests/ref/vsynth/vsynth2-cinepak
+++ b/tests/ref/vsynth/vsynth2-cinepak
@@ -1,4 +1,4 @@
-663a2804f421709208c76f6e34e7bea5 *tests/data/fate/vsynth2-cinepak.avi
-400402 tests/data/fate/vsynth2-cinepak.avi
-2c761c3c8cda083eb8f54b2df72b257b *tests/data/fate/vsynth2-cinepak.out.rawvideo
-stddev:   80.96 PSNR:  9.96 MAXDIFF:  227 bytes:  7603200/   921600
+675d6a4370c315dc53c219a9271be4c6 *tests/data/fate/vsynth2-cinepak.avi
+400720 tests/data/fate/vsynth2-cinepak.avi
+cbf6900b882b484bc531f9b4799c226e *tests/data/fate/vsynth2-cinepak.out.rawvideo
+stddev:   80.96 PSNR:  9.96 MAXDIFF:  229 bytes:  7603200/   921600
diff --git a/tests/ref/vsynth/vsynth_lena-cinepak b/tests/ref/vsynth/vsynth_lena-cinepak
index 6b021673a0..c9cb2cfaba 100644
--- a/tests/ref/vsynth/vsynth_lena-cinepak
+++ b/tests/ref/vsynth/vsynth_lena-cinepak
@@ -1,4 +1,4 @@
-a9ea19eb0d239a53af8630d5bc4167d0 *tests/data/fate/vsynth_lena-cinepak.avi
-407574 tests/data/fate/vsynth_lena-cinepak.avi
-e32d4103194665d2ea0f46d5cdd0cdf2 *tests/data/fate/vsynth_lena-cinepak.out.rawvideo
+a79f907fecb95c8a5b5de670ccda215b *tests/data/fate/vsynth_lena-cinepak.avi
+407952 tests/data/fate/vsynth_lena-cinepak.avi
+2664cdff5f14508e891477b498cc840e *tests/data/fate/vsynth_lena-cinepak.out.rawvideo
 stddev:   58.10 PSNR: 12.85 MAXDIFF:  185 bytes:  7603200/   921600



More information about the ffmpeg-cvslog mailing list