diff options
author | Tomas Härdin <git@haerdin.se> | 2022-04-09 14:38:47 +0200 |
---|---|---|
committer | Tomas Härdin <git@haerdin.se> | 2022-05-12 11:19:12 +0200 |
commit | 1cd8596ef4155347fb9c334b95521b92bd75b6f8 (patch) | |
tree | ba837575e9e7faf84c3d31f0ed3775e55c34ebdd /libavcodec/cinepakenc.c | |
parent | 61bcd7737dca1f89235a63c97010822896735b09 (diff) | |
download | ffmpeg-1cd8596ef4155347fb9c334b95521b92bd75b6f8.tar.gz |
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.c | 50 |
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; |