Rework codec layer to allow avifEncoderAddImage() to choose keyframes. Rework rav1e frame pump to not bail out early
diff --git a/src/codec_aom.c b/src/codec_aom.c
index 7265e60..7802d6d 100644
--- a/src/codec_aom.c
+++ b/src/codec_aom.c
@@ -235,7 +235,12 @@
return fmt;
}
-static avifBool aomCodecEncodeImage(avifCodec * codec, const avifImage * image, avifEncoder * encoder, avifBool alpha, avifCodecEncodeOutput * output)
+static avifBool aomCodecEncodeImage(avifCodec * codec,
+ const avifImage * image,
+ avifEncoder * encoder,
+ avifBool alpha,
+ avifBool forceKeyframe,
+ avifCodecEncodeOutput * output)
{
if (!codec->internal->encoderInitialized) {
// Map encoder speed to AOM usage + CpuUsed:
@@ -303,6 +308,7 @@
if (encoder->maxThreads > 1) {
cfg.g_threads = encoder->maxThreads;
}
+ cfg.kf_mode = AOM_KF_DISABLED;
int minQuantizer = AVIF_CLAMP(encoder->minQuantizer, 0, 63);
int maxQuantizer = AVIF_CLAMP(encoder->maxQuantizer, 0, 63);
@@ -391,7 +397,11 @@
aom_codec_control(&codec->internal->encoder, AV1E_SET_MATRIX_COEFFICIENTS, aomImage->mc);
}
- aom_codec_encode(&codec->internal->encoder, aomImage, 0, 1, 0);
+ aom_enc_frame_flags_t encodeFlags = 0;
+ if (forceKeyframe) {
+ encodeFlags |= AOM_EFLAG_FORCE_KF;
+ }
+ aom_codec_encode(&codec->internal->encoder, aomImage, 0, 1, encodeFlags);
aom_codec_iter_t iter = NULL;
for (;;) {
diff --git a/src/codec_rav1e.c b/src/codec_rav1e.c
index 85e3376..9cdf133 100644
--- a/src/codec_rav1e.c
+++ b/src/codec_rav1e.c
@@ -31,10 +31,13 @@
return AVIF_TRUE;
}
-static avifBool rav1eCodecEncodeImage(avifCodec * codec, const avifImage * image, avifEncoder * encoder, avifBool alpha, avifCodecEncodeOutput * output)
+static avifBool rav1eCodecEncodeImage(avifCodec * codec,
+ const avifImage * image,
+ avifEncoder * encoder,
+ avifBool alpha,
+ avifBool forceKeyframe,
+ avifCodecEncodeOutput * output)
{
- (void)codec; // unused
-
avifBool success = AVIF_FALSE;
RaConfig * rav1eConfig = NULL;
@@ -149,18 +152,29 @@
}
}
+ RaFrameTypeOverride frameType = RA_FRAME_TYPE_OVERRIDE_NO;
+ if (forceKeyframe) {
+ frameType = RA_FRAME_TYPE_OVERRIDE_KEY;
+ }
+ rav1e_frame_set_type(rav1eFrame, frameType);
+
RaEncoderStatus encoderStatus = rav1e_send_frame(codec->internal->rav1eContext, rav1eFrame);
- if (encoderStatus != 0) {
+ if (encoderStatus != RA_ENCODER_STATUS_SUCCESS) {
goto cleanup;
}
RaPacket * pkt = NULL;
for (;;) {
encoderStatus = rav1e_receive_packet(codec->internal->rav1eContext, &pkt);
- if ((encoderStatus != 0) && (encoderStatus != RA_ENCODER_STATUS_NEED_MORE_DATA)) {
+ if (encoderStatus == RA_ENCODER_STATUS_ENCODED) {
+ continue;
+ }
+ if ((encoderStatus != RA_ENCODER_STATUS_SUCCESS) && (encoderStatus != RA_ENCODER_STATUS_NEED_MORE_DATA)) {
goto cleanup;
- } else if (pkt && pkt->data && (pkt->len > 0)) {
- avifCodecEncodeOutputAddSample(output, pkt->data, pkt->len, (pkt->frame_type == RA_FRAME_TYPE_KEY));
+ } else if (pkt) {
+ if (pkt->data && (pkt->len > 0)) {
+ avifCodecEncodeOutputAddSample(output, pkt->data, pkt->len, (pkt->frame_type == RA_FRAME_TYPE_KEY));
+ }
rav1e_packet_unref(pkt);
pkt = NULL;
} else {
@@ -184,7 +198,7 @@
{
for (;;) {
RaEncoderStatus encoderStatus = rav1e_send_frame(codec->internal->rav1eContext, NULL); // flush
- if (encoderStatus != 0) {
+ if (encoderStatus != RA_ENCODER_STATUS_SUCCESS) {
return AVIF_FALSE;
}
@@ -192,13 +206,17 @@
RaPacket * pkt = NULL;
for (;;) {
encoderStatus = rav1e_receive_packet(codec->internal->rav1eContext, &pkt);
- if ((encoderStatus != 0) && (encoderStatus != RA_ENCODER_STATUS_LIMIT_REACHED) &&
- (encoderStatus != RA_ENCODER_STATUS_ENCODED)) {
+ if (encoderStatus == RA_ENCODER_STATUS_ENCODED) {
+ continue;
+ }
+ if ((encoderStatus != RA_ENCODER_STATUS_SUCCESS) && (encoderStatus != RA_ENCODER_STATUS_LIMIT_REACHED)) {
return AVIF_FALSE;
}
- if (pkt && pkt->data && (pkt->len > 0)) {
+ if (pkt) {
gotPacket = AVIF_TRUE;
- avifCodecEncodeOutputAddSample(output, pkt->data, pkt->len, (pkt->frame_type == RA_FRAME_TYPE_KEY));
+ if (pkt->data && (pkt->len > 0)) {
+ avifCodecEncodeOutputAddSample(output, pkt->data, pkt->len, (pkt->frame_type == RA_FRAME_TYPE_KEY));
+ }
rav1e_packet_unref(pkt);
pkt = NULL;
} else {
diff --git a/src/write.c b/src/write.c
index 0c01aae..b666d65 100644
--- a/src/write.c
+++ b/src/write.c
@@ -446,10 +446,15 @@
// -----------------------------------------------------------------------
// Encode AV1 OBUs
+ avifBool forceKeyframe = AVIF_FALSE;
+ if ((encoder->data->frames.count % 8) == 0) { // TODO: make this configurable
+ forceKeyframe = AVIF_TRUE;
+ }
+
for (uint32_t itemIndex = 0; itemIndex < encoder->data->items.count; ++itemIndex) {
avifEncoderItem * item = &encoder->data->items.item[itemIndex];
if (item->codec) {
- if (!item->codec->encodeImage(item->codec, image, encoder, item->alpha, item->encodeOutput)) {
+ if (!item->codec->encodeImage(item->codec, image, encoder, item->alpha, forceKeyframe, item->encodeOutput)) {
return item->alpha ? AVIF_RESULT_ENCODE_ALPHA_FAILED : AVIF_RESULT_ENCODE_COLOR_FAILED;
}
}