libavcodec/cinepakenc: Mark no-skip frames as keyframes
Reset curframe whenever we generate a keyframe. Use -g instead of -keyint_min.
This commit is contained in:
parent
61bcd7737d
commit
1cd8596ef4
@ -113,7 +113,7 @@ typedef struct CinepakEncContext {
|
|||||||
enum AVPixelFormat pix_fmt;
|
enum AVPixelFormat pix_fmt;
|
||||||
int w, h;
|
int w, h;
|
||||||
int frame_buf_size;
|
int frame_buf_size;
|
||||||
int curframe, keyint;
|
int curframe;
|
||||||
AVLFG randctx;
|
AVLFG randctx;
|
||||||
uint64_t lambda;
|
uint64_t lambda;
|
||||||
int *codebook_input;
|
int *codebook_input;
|
||||||
@ -215,7 +215,6 @@ static av_cold int cinepak_encode_init(AVCodecContext *avctx)
|
|||||||
s->h = avctx->height;
|
s->h = avctx->height;
|
||||||
s->frame_buf_size = frame_buf_size;
|
s->frame_buf_size = frame_buf_size;
|
||||||
s->curframe = 0;
|
s->curframe = 0;
|
||||||
s->keyint = avctx->keyint_min;
|
|
||||||
s->pix_fmt = avctx->pix_fmt;
|
s->pix_fmt = avctx->pix_fmt;
|
||||||
|
|
||||||
// set up AVFrames
|
// 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,
|
static void write_strip_keyframe(unsigned char *buf, int keyframe)
|
||||||
unsigned char *buf, int strip_size)
|
|
||||||
{
|
{
|
||||||
// actually we are exclusively using intra strip coding (how much can we win
|
// actually we are exclusively using intra strip coding (how much can we win
|
||||||
// otherwise? how to choose which part of a codebook to update?),
|
// 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: )
|
// (besides, the logic here used to be inverted: )
|
||||||
// buf[0] = keyframe ? 0x11: 0x10;
|
// buf[0] = keyframe ? 0x11: 0x10;
|
||||||
buf[0] = keyframe ? 0x10 : 0x11;
|
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_WB24(&buf[1], strip_size + STRIP_HEADER_SIZE);
|
||||||
// AV_WB16(&buf[4], y); /* using absolute y values works -- rl */
|
// AV_WB16(&buf[4], y); /* using absolute y values works -- rl */
|
||||||
AV_WB16(&buf[4], 0); /* using relative values works as well -- 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 *last_data[4], int last_linesize[4],
|
||||||
uint8_t *data[4], int linesize[4],
|
uint8_t *data[4], int linesize[4],
|
||||||
uint8_t *scratch_data[4], int scratch_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;
|
int64_t score = 0;
|
||||||
int best_size = 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,
|
scratch_data, scratch_linesize,
|
||||||
last_data, last_linesize, &info,
|
last_data, last_linesize, &info,
|
||||||
s->strip_buf + STRIP_HEADER_SIZE);
|
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);
|
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,
|
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;
|
int num_strips, strip, i, y, nexty, size, temp_size, best_size;
|
||||||
uint8_t *last_data [4], *data [4], *scratch_data [4];
|
uint8_t *last_data [4], *data [4], *scratch_data [4];
|
||||||
int last_linesize[4], linesize[4], scratch_linesize[4];
|
int last_linesize[4], linesize[4], scratch_linesize[4];
|
||||||
int64_t best_score = 0, score, score_temp;
|
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) {
|
if (s->pix_fmt == AV_PIX_FMT_RGB24) {
|
||||||
int x;
|
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:
|
// would be nice but quite certainly incompatible with vintage players:
|
||||||
// support encoding zero strips (meaning skip the whole frame)
|
// 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++) {
|
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;
|
score = 0;
|
||||||
size = 0;
|
size = 0;
|
||||||
|
|
||||||
for (y = 0, strip = 1; y < s->h; strip++, y = nexty) {
|
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
|
nexty = strip * s->h / num_strips; // <= s->h
|
||||||
// make nexty the next multiple of 4 if not already there
|
// make nexty the next multiple of 4 if not already there
|
||||||
if (nexty & 3)
|
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,
|
if ((temp_size = rd_strip(s, y, strip_height, isakeyframe,
|
||||||
last_data, last_linesize, data, linesize,
|
last_data, last_linesize, data, linesize,
|
||||||
scratch_data, scratch_linesize,
|
scratch_data, scratch_linesize,
|
||||||
s->frame_buf + size + CVID_HEADER_SIZE,
|
s->frame_buf + strip_offsets[strip-1],
|
||||||
&score_temp)) < 0)
|
&score_temp, &no_skip)) < 0)
|
||||||
return temp_size;
|
return temp_size;
|
||||||
|
|
||||||
score += score_temp;
|
score += score_temp;
|
||||||
size += temp_size;
|
size += temp_size;
|
||||||
|
all_no_skip &= no_skip;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (best_score == 0 || score < best_score) {
|
if (best_score == 0 || score < best_score) {
|
||||||
best_score = 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);
|
FFSWAP(AVFrame *, s->best_frame, s->scratch_frame);
|
||||||
memcpy(buf, s->frame_buf, best_size);
|
memcpy(buf, s->frame_buf, best_size);
|
||||||
best_nstrips = num_strips;
|
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
|
// avoid trying too many strip numbers without a real reason
|
||||||
// (this makes the processing of the very first frame faster)
|
// (this makes the processing of the very first frame faster)
|
||||||
@ -1121,6 +1134,11 @@ static int rd_frame(CinepakEncContext *s, const AVFrame *frame,
|
|||||||
break;
|
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,
|
// let the number of strips slowly adapt to the changes in the contents,
|
||||||
// compared to full bruteforcing every time this will occasionally lead
|
// compared to full bruteforcing every time this will occasionally lead
|
||||||
// to some r/d performance loss but makes encoding up to several times faster
|
// 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)
|
const AVFrame *frame, int *got_packet)
|
||||||
{
|
{
|
||||||
CinepakEncContext *s = avctx->priv_data;
|
CinepakEncContext *s = avctx->priv_data;
|
||||||
int ret;
|
int ret, got_keyframe;
|
||||||
|
|
||||||
s->lambda = frame->quality ? frame->quality - 1 : 2 * FF_LAMBDA_SCALE;
|
s->lambda = frame->quality ? frame->quality - 1 : 2 * FF_LAMBDA_SCALE;
|
||||||
|
|
||||||
if ((ret = ff_alloc_packet(avctx, pkt, s->frame_buf_size)) < 0)
|
if ((ret = ff_alloc_packet(avctx, pkt, s->frame_buf_size)) < 0)
|
||||||
return ret;
|
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;
|
pkt->size = ret;
|
||||||
if (s->curframe == 0)
|
if (got_keyframe) {
|
||||||
pkt->flags |= AV_PKT_FLAG_KEY;
|
pkt->flags |= AV_PKT_FLAG_KEY;
|
||||||
|
s->curframe = 0;
|
||||||
|
}
|
||||||
*got_packet = 1;
|
*got_packet = 1;
|
||||||
|
|
||||||
FFSWAP(AVFrame *, s->last_frame, s->best_frame);
|
FFSWAP(AVFrame *, s->last_frame, s->best_frame);
|
||||||
|
|
||||||
if (++s->curframe >= s->keyint)
|
if (++s->curframe >= avctx->gop_size)
|
||||||
s->curframe = 0;
|
s->curframe = 0;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
cd28e47a6ac396240a3fee69f15625d1 *tests/data/fate/vsynth1-cinepak.avi
|
6b9b4d2b32854fd8b0f84ee4d76b1fed *tests/data/fate/vsynth1-cinepak.avi
|
||||||
408616 tests/data/fate/vsynth1-cinepak.avi
|
408910 tests/data/fate/vsynth1-cinepak.avi
|
||||||
e74066a028c708f467272884ecd3f7d3 *tests/data/fate/vsynth1-cinepak.out.rawvideo
|
4acdcc3e664d12facbcefc389079cfa6 *tests/data/fate/vsynth1-cinepak.out.rawvideo
|
||||||
stddev: 61.38 PSNR: 12.37 MAXDIFF: 225 bytes: 7603200/ 921600
|
stddev: 61.38 PSNR: 12.37 MAXDIFF: 223 bytes: 7603200/ 921600
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
663a2804f421709208c76f6e34e7bea5 *tests/data/fate/vsynth2-cinepak.avi
|
675d6a4370c315dc53c219a9271be4c6 *tests/data/fate/vsynth2-cinepak.avi
|
||||||
400402 tests/data/fate/vsynth2-cinepak.avi
|
400720 tests/data/fate/vsynth2-cinepak.avi
|
||||||
2c761c3c8cda083eb8f54b2df72b257b *tests/data/fate/vsynth2-cinepak.out.rawvideo
|
cbf6900b882b484bc531f9b4799c226e *tests/data/fate/vsynth2-cinepak.out.rawvideo
|
||||||
stddev: 80.96 PSNR: 9.96 MAXDIFF: 227 bytes: 7603200/ 921600
|
stddev: 80.96 PSNR: 9.96 MAXDIFF: 229 bytes: 7603200/ 921600
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
a9ea19eb0d239a53af8630d5bc4167d0 *tests/data/fate/vsynth_lena-cinepak.avi
|
a79f907fecb95c8a5b5de670ccda215b *tests/data/fate/vsynth_lena-cinepak.avi
|
||||||
407574 tests/data/fate/vsynth_lena-cinepak.avi
|
407952 tests/data/fate/vsynth_lena-cinepak.avi
|
||||||
e32d4103194665d2ea0f46d5cdd0cdf2 *tests/data/fate/vsynth_lena-cinepak.out.rawvideo
|
2664cdff5f14508e891477b498cc840e *tests/data/fate/vsynth_lena-cinepak.out.rawvideo
|
||||||
stddev: 58.10 PSNR: 12.85 MAXDIFF: 185 bytes: 7603200/ 921600
|
stddev: 58.10 PSNR: 12.85 MAXDIFF: 185 bytes: 7603200/ 921600
|
||||||
|
Loading…
x
Reference in New Issue
Block a user