summaryrefslogtreecommitdiff
path: root/libavcodec/cinepakenc.c
diff options
context:
space:
mode:
authorTomas Härdin <git@haerdin.se>2022-04-09 14:38:47 +0200
committerTomas Härdin <git@haerdin.se>2022-05-12 11:19:12 +0200
commit1cd8596ef4155347fb9c334b95521b92bd75b6f8 (patch)
treeba837575e9e7faf84c3d31f0ed3775e55c34ebdd /libavcodec/cinepakenc.c
parent61bcd7737dca1f89235a63c97010822896735b09 (diff)
libavcodec/cinepakenc: Mark no-skip frames as keyframes
Reset curframe whenever we generate a keyframe. Use -g instead of -keyint_min.
Diffstat (limited to 'libavcodec/cinepakenc.c')
-rw-r--r--libavcodec/cinepakenc.c50
1 files changed, 35 insertions, 15 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;