Skip to content

Commit f8dbdb7

Browse files
committed
Fixed converting between various time bases
Also fixed some bugs introduced by switching animations from pts to frame duration
1 parent 56f03fc commit f8dbdb7

File tree

10 files changed

+113
-114
lines changed

10 files changed

+113
-114
lines changed

examples/showanim.c

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -53,19 +53,17 @@ static void draw_background(SDL_Renderer *renderer, int w, int h)
5353
static void SaveAnimation(IMG_Animation *anim, const char *file)
5454
{
5555
int i;
56-
Uint64 pts = 0;
5756
IMG_AnimationEncoder *encoder = IMG_CreateAnimationEncoder(file);
5857
if (!encoder) {
5958
SDL_Log("Couldn't save anim: %s\n", SDL_GetError());
6059
return;
6160
}
6261

6362
for (i = 0; i < anim->count; ++i) {
64-
if (!IMG_AddAnimationEncoderFrame(encoder, anim->frames[i], pts)) {
63+
if (!IMG_AddAnimationEncoderFrame(encoder, anim->frames[i], anim->delays[i])) {
6564
SDL_Log("Couldn't add anim frame: %s\n", SDL_GetError());
6665
break;
6766
}
68-
pts += anim->delays[i];
6967
}
7068
IMG_CloseAnimationEncoder(encoder);
7169
}

src/IMG.c

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -410,3 +410,10 @@ bool IMG_SaveTyped_IO(SDL_Surface *surface, SDL_IOStream *dst, bool closeio, con
410410
}
411411
return result;
412412
}
413+
414+
Uint64 IMG_TimebaseDuration(Uint64 pts, Uint64 duration, Uint64 src_numerator, Uint64 src_denominator, Uint64 dst_numerator, Uint64 dst_denominator)
415+
{
416+
Uint64 a = ( ( ( ( pts + duration ) * 2 ) + 1 ) * src_numerator * dst_denominator ) / ( 2 * src_denominator * dst_numerator );
417+
Uint64 b = ( ( ( pts * 2 ) + 1 ) * src_numerator * dst_denominator ) / ( 2 * src_denominator * dst_numerator );
418+
return (a - b);
419+
}

src/IMG_anim_decoder.c

Lines changed: 30 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -202,9 +202,7 @@ bool IMG_GetAnimationDecoderFrame(IMG_AnimationDecoder *decoder, SDL_Surface **f
202202
SDL_DestroySurface(temp_frame);
203203
}
204204

205-
if (result) {
206-
decoder->accumulated_pts += *duration;
207-
} else {
205+
if (!result) {
208206
if (decoder->status == IMG_DECODER_STATUS_COMPLETE) {
209207
SDL_ClearError();
210208
} else {
@@ -216,6 +214,23 @@ bool IMG_GetAnimationDecoderFrame(IMG_AnimationDecoder *decoder, SDL_Surface **f
216214
return result;
217215
}
218216

217+
IMG_AnimationDecoderStatus IMG_GetAnimationDecoderStatus(IMG_AnimationDecoder* decoder)
218+
{
219+
if (!decoder) {
220+
return IMG_DECODER_STATUS_INVALID;
221+
}
222+
return decoder->status;
223+
}
224+
225+
bool IMG_ResetAnimationDecoder(IMG_AnimationDecoder *decoder)
226+
{
227+
if (!decoder) {
228+
return SDL_InvalidParamError("decoder");
229+
}
230+
231+
return decoder->Reset(decoder);
232+
}
233+
219234
bool IMG_CloseAnimationDecoder(IMG_AnimationDecoder *decoder)
220235
{
221236
if (!decoder) {
@@ -237,30 +252,11 @@ bool IMG_CloseAnimationDecoder(IMG_AnimationDecoder *decoder)
237252
return result;
238253
}
239254

240-
bool IMG_ResetAnimationDecoder(IMG_AnimationDecoder *decoder)
241-
{
242-
if (!decoder) {
243-
return SDL_InvalidParamError("decoder");
244-
}
245-
246-
return decoder->Reset(decoder);
247-
}
248-
249-
Uint64 IMG_CalculateDuration(IMG_AnimationDecoder* decoder, int delay_num, int delay_den)
255+
Uint64 IMG_GetDecoderDuration(IMG_AnimationDecoder *decoder, Uint64 duration, Uint64 timebase_denominator)
250256
{
251-
if (delay_den < 1) {
252-
delay_den = 100;
253-
}
254-
255-
return (Uint64)SDL_round(((double)delay_num / delay_den) * ((double)decoder->timebase_denominator / (double)decoder->timebase_numerator));
256-
}
257-
258-
IMG_AnimationDecoderStatus IMG_GetAnimationDecoderStatus(IMG_AnimationDecoder* decoder)
259-
{
260-
if (!decoder) {
261-
return IMG_DECODER_STATUS_INVALID;
262-
}
263-
return decoder->status;
257+
Uint64 value = IMG_TimebaseDuration(decoder->accumulated_pts, duration, 1, timebase_denominator, decoder->timebase_numerator, decoder->timebase_denominator);
258+
decoder->accumulated_pts += duration;
259+
return value;
264260
}
265261

266262
IMG_Animation *IMG_DecodeAsAnimation(SDL_IOStream *src, const char *format, int maxFrames)
@@ -290,14 +286,13 @@ IMG_Animation *IMG_DecodeAsAnimation(SDL_IOStream *src, const char *format, int
290286
break;
291287
}
292288

293-
Uint64 pts = 0;
294-
SDL_Surface *nextFrame;
295-
if (!IMG_GetAnimationDecoderFrame(decoder, &nextFrame, &pts)) {
296-
goto error;
297-
}
298-
299-
if (!nextFrame) {
300-
// No more frames available or an error occurred.
289+
Uint64 duration = 0;
290+
SDL_Surface *nextFrame = NULL;
291+
if (!IMG_GetAnimationDecoderFrame(decoder, &nextFrame, &duration)) {
292+
if (IMG_GetAnimationDecoderStatus(decoder) == IMG_DECODER_STATUS_FAILED) {
293+
goto error;
294+
}
295+
// Decoding complete
301296
break;
302297
}
303298

@@ -317,7 +312,7 @@ IMG_Animation *IMG_DecodeAsAnimation(SDL_IOStream *src, const char *format, int
317312
}
318313

319314
frames[actualCount] = nextFrame;
320-
delays[actualCount] = pts;
315+
delays[actualCount] = duration;
321316
++actualCount;
322317
}
323318

src/IMG_anim_decoder.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,5 +39,7 @@ struct IMG_AnimationDecoder
3939
IMG_AnimationDecoderContext *ctx;
4040
};
4141

42-
extern Uint64 IMG_CalculateDuration(IMG_AnimationDecoder *decoder, int delay_num, int delay_den);
42+
extern Uint64 IMG_TimebaseDuration(Uint64 pts, Uint64 duration, Uint64 src_numerator, Uint64 src_denominator, Uint64 dst_numerator, Uint64 dst_denominator);
43+
extern Uint64 IMG_GetDecoderDuration(IMG_AnimationDecoder *decoder, Uint64 duration, Uint64 timebase_denominator);
44+
4345
extern IMG_Animation *IMG_DecodeAsAnimation(SDL_IOStream *src, const char *format, int maxFrames);

src/IMG_anim_encoder.c

Lines changed: 5 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -172,12 +172,7 @@ bool IMG_AddAnimationEncoderFrame(IMG_AnimationEncoder *encoder, SDL_Surface *su
172172
return SDL_InvalidParamError("surface");
173173
}
174174

175-
bool result = encoder->AddFrame(encoder, surface, duration);
176-
if (result) {
177-
encoder->accumulated_pts += duration;
178-
encoder->last_duration = duration;
179-
}
180-
return result;
175+
return encoder->AddFrame(encoder, surface, duration);
181176
}
182177

183178
bool IMG_CloseAnimationEncoder(IMG_AnimationEncoder *encoder)
@@ -194,12 +189,9 @@ bool IMG_CloseAnimationEncoder(IMG_AnimationEncoder *encoder)
194189
return result;
195190
}
196191

197-
Uint64 IMG_GetResolvedDuration(IMG_AnimationEncoder* encoder, Uint64 duration, int factor)
198-
{
199-
return (Uint64)(SDL_round(((double)encoder->accumulated_pts + duration) * factor * encoder->timebase_numerator / encoder->timebase_denominator) - SDL_round(((double)encoder->accumulated_pts * factor) * encoder->timebase_numerator / encoder->timebase_denominator));
200-
}
201-
202-
Uint64 IMG_GetCurrentTimestamp(IMG_AnimationEncoder* encoder, Uint64 duration, int factor)
192+
Uint64 IMG_GetEncoderDuration(IMG_AnimationEncoder *encoder, Uint64 duration, Uint64 timebase_denominator)
203193
{
204-
return (Uint64)SDL_round(((double)encoder->accumulated_pts + (double)duration) * factor * encoder->timebase_numerator / encoder->timebase_denominator);
194+
Uint64 value = IMG_TimebaseDuration(encoder->accumulated_pts, duration, encoder->timebase_numerator, encoder->timebase_denominator, 1, timebase_denominator);
195+
encoder->accumulated_pts += duration;
196+
return value;
205197
}

src/IMG_anim_encoder.h

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -30,13 +30,12 @@ struct IMG_AnimationEncoder
3030
int timebase_numerator;
3131
int timebase_denominator;
3232
Uint64 accumulated_pts;
33-
Uint64 last_duration;
3433

3534
bool (*AddFrame)(IMG_AnimationEncoder *encoder, SDL_Surface *surface, Uint64 duration);
3635
bool (*Close)(IMG_AnimationEncoder *encoder);
3736

3837
IMG_AnimationEncoderContext *ctx;
3938
};
4039

41-
extern Uint64 IMG_GetResolvedDuration(IMG_AnimationEncoder *encoder, Uint64 duration, int factor);
42-
extern Uint64 IMG_GetCurrentTimestamp(IMG_AnimationEncoder *encoder, Uint64 duration, int factor);
40+
extern Uint64 IMG_TimebaseDuration(Uint64 pts, Uint64 duration, Uint64 src_numerator, Uint64 src_denominator, Uint64 dst_numerator, Uint64 dst_denominator);
41+
extern Uint64 IMG_GetEncoderDuration(IMG_AnimationEncoder *encoder, Uint64 duration, Uint64 timebase_denominator);

src/IMG_avif.c

Lines changed: 42 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -829,7 +829,6 @@ struct IMG_AnimationDecoderContext
829829

830830
int width; /* Width of the animation */
831831
int height; /* Height of the animation */
832-
uint64_t timescale; /* Timescale of the media (Hz) */
833832
int repetitionCount; /* Number of repetitions */
834833
};
835834

@@ -1052,7 +1051,7 @@ bool IMG_CreateAVIFAnimationDecoder(IMG_AnimationDecoder *decoder, SDL_Propertie
10521051
return false;
10531052
}
10541053

1055-
IMG_AnimationDecoderContext *ctx = (IMG_AnimationDecoderContext *)SDL_calloc(1, sizeof(IMG_AnimationDecoderContext));
1054+
IMG_AnimationDecoderContext *ctx = (IMG_AnimationDecoderContext *)SDL_calloc(1, sizeof(*ctx));
10561055
if (!ctx) {
10571056
return SDL_SetError("Out of memory for AVIF decoder context");
10581057
}
@@ -1119,7 +1118,6 @@ bool IMG_CreateAVIFAnimationDecoder(IMG_AnimationDecoder *decoder, SDL_Propertie
11191118

11201119
ctx->width = ctx->decoder->image->width;
11211120
ctx->height = ctx->decoder->image->height;
1122-
ctx->timescale = ctx->decoder->timescale;
11231121
ctx->total_frames = ctx->decoder->imageCount;
11241122
ctx->repetitionCount = ctx->decoder->repetitionCount;
11251123

@@ -1547,73 +1545,73 @@ bool IMG_CreateAVIFAnimationEncoder(IMG_AnimationEncoder *encoder, SDL_Propertie
15471545
return false;
15481546
}
15491547

1550-
encoder->ctx = (IMG_AnimationEncoderContext *)SDL_calloc(1, sizeof(IMG_AnimationEncoderContext));
1551-
if (!encoder->ctx) {
1548+
IMG_AnimationEncoderContext *ctx = (IMG_AnimationEncoderContext *)SDL_calloc(1, sizeof(*ctx));
1549+
if (!ctx) {
15521550
return SDL_SetError("Out of memory for AVIF context");
15531551
}
15541552

1555-
if (encoder->quality < 0)
1553+
ctx->encoder = lib.avifEncoderCreate();
1554+
if (!ctx->encoder) {
1555+
SDL_free(ctx);
1556+
return SDL_SetError("Couldn't create AVIF encoder");
1557+
}
1558+
1559+
if (encoder->quality < 0) {
15561560
encoder->quality = 75;
1557-
else if (encoder->quality > 100)
1561+
} else if (encoder->quality > 100) {
15581562
encoder->quality = 100;
1559-
1560-
encoder->ctx->encoder = lib.avifEncoderCreate();
1561-
if (!encoder->ctx->encoder) {
1562-
SDL_free(encoder->ctx);
1563-
encoder->ctx = NULL;
1564-
return SDL_SetError("Couldn't create AVIF encoder");
15651563
}
15661564

15671565
int availableLCores = SDL_GetNumLogicalCPUCores();
1568-
int mThreads = (int)SDL_GetNumberProperty(props, "maxthreads", availableLCores / 2);
1569-
mThreads = SDL_clamp(mThreads, 1, availableLCores);
1566+
int threads = (int)SDL_GetNumberProperty(props, "maxthreads", availableLCores / 2);
1567+
threads = SDL_clamp(threads, 1, availableLCores);
15701568

15711569
int keyFrameInterval = (int)SDL_GetNumberProperty(props, "keyframeinterval", 0);
15721570

1573-
encoder->ctx->encoder->maxThreads = mThreads;
1574-
encoder->ctx->encoder->quality = encoder->quality;
1571+
ctx->encoder->maxThreads = threads;
1572+
ctx->encoder->quality = encoder->quality;
15751573

1576-
encoder->ctx->encoder->qualityAlpha = AVIF_QUALITY_DEFAULT;
1577-
encoder->ctx->encoder->speed = AVIF_SPEED_FASTEST;
1574+
ctx->encoder->qualityAlpha = AVIF_QUALITY_DEFAULT;
1575+
ctx->encoder->speed = AVIF_SPEED_FASTEST;
15781576

1579-
if (encoder->ctx->encoder->quality >= 100) {
1580-
encoder->ctx->encoder->keyframeInterval = SDL_min(1, keyFrameInterval);
1581-
encoder->ctx->encoder->minQuantizer = 0;
1582-
encoder->ctx->encoder->maxQuantizer = 0;
1577+
if (ctx->encoder->quality >= 100) {
1578+
ctx->encoder->keyframeInterval = SDL_min(1, keyFrameInterval);
1579+
ctx->encoder->minQuantizer = 0;
1580+
ctx->encoder->maxQuantizer = 0;
15831581

1584-
encoder->ctx->encoder->minQuantizerAlpha = 0;
1585-
encoder->ctx->encoder->maxQuantizerAlpha = 0;
1586-
encoder->ctx->encoder->autoTiling = AVIF_FALSE;
1582+
ctx->encoder->minQuantizerAlpha = 0;
1583+
ctx->encoder->maxQuantizerAlpha = 0;
1584+
ctx->encoder->autoTiling = AVIF_FALSE;
15871585
} else {
1588-
encoder->ctx->encoder->keyframeInterval = keyFrameInterval;
1589-
encoder->ctx->encoder->minQuantizer = 8;
1590-
encoder->ctx->encoder->maxQuantizer = 63;
1586+
ctx->encoder->keyframeInterval = keyFrameInterval;
1587+
ctx->encoder->minQuantizer = 8;
1588+
ctx->encoder->maxQuantizer = 63;
15911589

1592-
encoder->ctx->encoder->minQuantizerAlpha = 0;
1593-
encoder->ctx->encoder->maxQuantizerAlpha = 63;
1594-
encoder->ctx->encoder->autoTiling = AVIF_TRUE;
1590+
ctx->encoder->minQuantizerAlpha = 0;
1591+
ctx->encoder->maxQuantizerAlpha = 63;
1592+
ctx->encoder->autoTiling = AVIF_TRUE;
15951593
}
15961594

1597-
encoder->ctx->encoder->tileRowsLog2 = 0;
1598-
encoder->ctx->encoder->tileColsLog2 = 0;
1595+
ctx->encoder->tileRowsLog2 = 0;
1596+
ctx->encoder->tileColsLog2 = 0;
15991597

1600-
encoder->ctx->encoder->timescale = (uint32_t)encoder->timebase_denominator;
1598+
ctx->encoder->timescale = encoder->timebase_denominator;
16011599

16021600
bool ignoreProps = SDL_GetBooleanProperty(props, IMG_PROP_METADATA_IGNORE_PROPS_BOOLEAN, false);
16031601
if (!ignoreProps) {
1604-
encoder->ctx->encoder->repetitionCount = (int)SDL_GetNumberProperty(props, IMG_PROP_METADATA_LOOP_COUNT_NUMBER, -1);
1605-
if (encoder->ctx->encoder->repetitionCount < 1 && encoder->ctx->encoder->repetitionCount != -1) {
1606-
encoder->ctx->encoder->repetitionCount = -1;
1602+
ctx->encoder->repetitionCount = (int)SDL_GetNumberProperty(props, IMG_PROP_METADATA_LOOP_COUNT_NUMBER, -1);
1603+
if (ctx->encoder->repetitionCount < 1 && ctx->encoder->repetitionCount != -1) {
1604+
ctx->encoder->repetitionCount = -1;
16071605
}
16081606

1609-
encoder->ctx->desc = SDL_GetStringProperty(props, IMG_PROP_METADATA_DESCRIPTION_STRING, NULL);
1610-
encoder->ctx->rights = SDL_GetStringProperty(props, IMG_PROP_METADATA_COPYRIGHT_STRING, NULL);
1611-
encoder->ctx->title = SDL_GetStringProperty(props, IMG_PROP_METADATA_TITLE_STRING, NULL);
1612-
encoder->ctx->creator = SDL_GetStringProperty(props, IMG_PROP_METADATA_AUTHOR_STRING, NULL);
1613-
encoder->ctx->createdate = SDL_GetStringProperty(props, IMG_PROP_METADATA_CREATION_TIME_STRING, NULL);
1607+
ctx->desc = SDL_GetStringProperty(props, IMG_PROP_METADATA_DESCRIPTION_STRING, NULL);
1608+
ctx->rights = SDL_GetStringProperty(props, IMG_PROP_METADATA_COPYRIGHT_STRING, NULL);
1609+
ctx->title = SDL_GetStringProperty(props, IMG_PROP_METADATA_TITLE_STRING, NULL);
1610+
ctx->creator = SDL_GetStringProperty(props, IMG_PROP_METADATA_AUTHOR_STRING, NULL);
1611+
ctx->createdate = SDL_GetStringProperty(props, IMG_PROP_METADATA_CREATION_TIME_STRING, NULL);
16141612
}
16151613

1616-
encoder->ctx->first_frame_added = false;
1614+
encoder->ctx = ctx;
16171615
encoder->AddFrame = AnimationEncoder_AddFrame;
16181616
encoder->Close = AnimationEncoder_End;
16191617

0 commit comments

Comments
 (0)