Skip to content

Commit f3adf8f

Browse files
Accept arbitrary scale ratio in layer config
1 parent 29189e4 commit f3adf8f

File tree

3 files changed

+233
-158
lines changed

3 files changed

+233
-158
lines changed

apps/avifenc.c

Lines changed: 121 additions & 125 deletions
Original file line numberDiff line numberDiff line change
@@ -260,243 +260,244 @@ static avifBool convertCropToClap(uint32_t srcW, uint32_t srcH, avifPixelFormat
260260
return AVIF_TRUE;
261261
}
262262

263+
#define CHECK(condition, reason) \
264+
do { \
265+
if (!(condition)) { \
266+
fprintf(stderr, "ERROR: Failed reading progressive config: %s\n", reason); \
267+
return AVIF_FALSE; \
268+
} \
269+
} while (0)
270+
263271
struct avifEncoderLayerConfig
264272
{
265-
uint8_t layerCount; // Image layers for color sub image; 0 to disable layer image (default).
273+
uint8_t layerCount; // Image layers for color sub image; 0 to disable layer image (default).
266274
uint8_t layerCountAlpha; // Image layers for alpha sub image; 0 to disable layer image (default).
267275
avifLayerConfig layers[MAX_AV1_LAYER_COUNT];
268276
avifLayerConfig layersAlpha[MAX_AV1_LAYER_COUNT];
269277
};
270278

271-
struct avifOptionEnumList
272-
{
273-
const char * name;
274-
int val;
275-
};
276-
277-
static const struct avifOptionEnumList scalingModeList[] = { //
278-
{ "1/2", AVIF_SCALING_ONETWO }, { "1/4", AVIF_SCALING_ONEFOUR },
279-
{ "1/8", AVIF_SCALING_ONEEIGHT }, { "3/4", AVIF_SCALING_THREEFOUR },
280-
{ "3/5", AVIF_SCALING_THREEFIVE }, { "4/5", AVIF_SCALING_FOURFIVE },
281-
{ "1", AVIF_SCALING_NORMAL }, { NULL, 0 }
282-
};
279+
static const avifScalingMode avifScalingModeNormal = { 1, 1 };
283280

284281
static avifBool avifParseScalingMode(const char ** pArg, avifScalingMode * mode)
285282
{
286-
const struct avifOptionEnumList * listptr;
287-
for (listptr = scalingModeList; listptr->name; ++listptr) {
288-
size_t matchLength = strlen(listptr->name);
289-
if (!strncmp(*pArg, listptr->name, matchLength)) {
290-
*mode = (avifScalingMode)listptr->val;
291-
*pArg += matchLength;
283+
char * end;
284+
uint64_t value = strtoull(*pArg, &end, 10);
285+
CHECK(errno != ERANGE, "overflowed while reading scale nominator");
286+
CHECK(end != *pArg, "can't parse scale nominator");
287+
if (*end != '/') {
288+
if (value == 1) {
289+
*mode = avifScalingModeNormal;
290+
*pArg = end;
292291
return AVIF_TRUE;
293292
}
293+
return AVIF_FALSE;
294294
}
295-
296-
return AVIF_FALSE;
295+
mode->numerator = value;
296+
*pArg = end + 1;
297+
value = strtoull(*pArg, &end, 10);
298+
CHECK(errno != ERANGE, "overflowed while reading scale denominator");
299+
CHECK(end != *pArg, "can't parse scale denominator");
300+
mode->denominator = value;
301+
*pArg = end;
302+
return AVIF_TRUE;
297303
}
298304

299-
#define FAIL_IF(condition, reason) \
300-
do { \
301-
if (condition) { \
302-
failReason = reason; \
303-
goto finish; \
304-
} \
305-
} while (0)
305+
enum avifProgressiveConfigScannerState
306+
{
307+
AVIF_PROGRESSIVE_SCANNER_STATE_VALUE,
308+
AVIF_PROGRESSIVE_SCANNER_STATE_COMMA,
309+
AVIF_PROGRESSIVE_SCANNER_STATE_HYPHEN,
310+
AVIF_PROGRESSIVE_SCANNER_STATE_COLON,
311+
AVIF_PROGRESSIVE_SCANNER_STATE_SEMICOLON
312+
};
313+
314+
enum avifProgressiveConfigValueType
315+
{
316+
AVIF_PROGRESSIVE_VALUE_TYPE_NONE,
317+
AVIF_PROGRESSIVE_VALUE_TYPE_MIN_Q,
318+
AVIF_PROGRESSIVE_VALUE_TYPE_MAX_Q,
319+
AVIF_PROGRESSIVE_VALUE_TYPE_H_SCALE,
320+
AVIF_PROGRESSIVE_VALUE_TYPE_V_SCALE,
321+
};
306322

307323
static avifBool avifParseProgressiveConfig(struct avifEncoderLayerConfig * config, const char * arg)
308324
{
309325
uint8_t * currLayerCount = &config->layerCount;
310326
avifLayerConfig * currLayers = config->layers;
311327
uint8_t currLayer = 0;
312-
const char * failReason = NULL;
313-
314-
enum scanState
315-
{
316-
VALUE,
317-
COMMA,
318-
HYPHEN,
319-
COLON,
320-
SEMICOLON
321-
};
322-
enum scanState currState = *arg == ';' ? SEMICOLON : VALUE;
323-
enum scanState targetState = SEMICOLON;
324-
325-
enum
326-
{
327-
NONE,
328-
MIN_Q,
329-
MAX_Q,
330-
H_SCALE,
331-
V_SCALE,
332-
} prevReadValue = NONE;
328+
329+
enum avifProgressiveConfigScannerState currState = *arg == ';' ? AVIF_PROGRESSIVE_SCANNER_STATE_SEMICOLON
330+
: AVIF_PROGRESSIVE_SCANNER_STATE_VALUE;
331+
enum avifProgressiveConfigScannerState targetState = AVIF_PROGRESSIVE_SCANNER_STATE_SEMICOLON;
332+
333+
enum avifProgressiveConfigValueType prevReadValue = AVIF_PROGRESSIVE_VALUE_TYPE_NONE;
333334

334335
for (;;) {
335336
switch (currState) {
336-
case VALUE: {
337+
case AVIF_PROGRESSIVE_SCANNER_STATE_VALUE: {
337338
int64_t value;
338339
avifScalingMode mode;
339340
char * end;
340341
switch (prevReadValue) {
341-
case NONE:
342+
case AVIF_PROGRESSIVE_VALUE_TYPE_NONE:
342343
value = strtoll(arg, &end, 10);
343-
FAIL_IF(errno == ERANGE, "overflowed while reading min quantizer");
344-
FAIL_IF(end == arg, "can't parse min quantizer");
345-
FAIL_IF(value > 63, "min quantizer too big");
344+
CHECK(errno != ERANGE, "overflowed while reading min quantizer");
345+
CHECK(end != arg, "can't parse min quantizer");
346+
CHECK(value <= 63, "min quantizer too big");
346347

347348
arg = end;
348349
currLayers[currLayer].minQuantizer = (int)value;
349-
currState = COMMA;
350-
prevReadValue = MIN_Q;
350+
currState = AVIF_PROGRESSIVE_SCANNER_STATE_COMMA;
351+
prevReadValue = AVIF_PROGRESSIVE_VALUE_TYPE_MIN_Q;
351352
break;
352353

353-
case MIN_Q:
354+
case AVIF_PROGRESSIVE_VALUE_TYPE_MIN_Q:
354355
value = strtoll(arg, &end, 10);
355-
FAIL_IF(errno == ERANGE, "overflowed while reading max quantizer");
356-
FAIL_IF(end == arg, "can't parse max quantizer");
357-
FAIL_IF(value > 63, "max quantizer too big");
356+
CHECK(errno != ERANGE, "overflowed while reading max quantizer");
357+
CHECK(end != arg, "can't parse max quantizer");
358+
CHECK(value <= 63, "max quantizer too big");
358359

359360
arg = end;
360361
currLayers[currLayer].maxQuantizer = (int)value;
361-
currState = HYPHEN;
362-
prevReadValue = MAX_Q;
362+
currState = AVIF_PROGRESSIVE_SCANNER_STATE_HYPHEN;
363+
prevReadValue = AVIF_PROGRESSIVE_VALUE_TYPE_MAX_Q;
363364
break;
364365

365-
case MAX_Q:
366-
FAIL_IF(!avifParseScalingMode(&arg, &mode), "unknown scaling mode");
366+
case AVIF_PROGRESSIVE_VALUE_TYPE_MAX_Q:
367+
CHECK(avifParseScalingMode(&arg, &mode), "unknown scaling mode");
367368

368369
currLayers[currLayer].horizontalMode = mode;
369-
currState = COMMA;
370-
prevReadValue = H_SCALE;
370+
currState = AVIF_PROGRESSIVE_SCANNER_STATE_COMMA;
371+
prevReadValue = AVIF_PROGRESSIVE_VALUE_TYPE_H_SCALE;
371372
break;
372373

373-
case H_SCALE:
374-
FAIL_IF(!avifParseScalingMode(&arg, &mode), "unknown scaling mode");
374+
case AVIF_PROGRESSIVE_VALUE_TYPE_H_SCALE:
375+
CHECK(avifParseScalingMode(&arg, &mode), "unknown scaling mode");
375376

376377
currLayers[currLayer].verticalMode = mode;
377-
currState = COLON;
378-
prevReadValue = V_SCALE;
378+
currState = AVIF_PROGRESSIVE_SCANNER_STATE_COLON;
379+
prevReadValue = AVIF_PROGRESSIVE_VALUE_TYPE_V_SCALE;
379380
break;
380381

381-
case V_SCALE:
382-
FAIL_IF(AVIF_TRUE, "too many values in layer config");
382+
case AVIF_PROGRESSIVE_VALUE_TYPE_V_SCALE:
383+
CHECK(AVIF_FALSE, "too many values in layer config");
383384
}
384385
break;
385386
}
386387

387-
case COMMA:
388-
case HYPHEN:
389-
case COLON:
390-
case SEMICOLON:
388+
case AVIF_PROGRESSIVE_SCANNER_STATE_COMMA:
389+
case AVIF_PROGRESSIVE_SCANNER_STATE_HYPHEN:
390+
case AVIF_PROGRESSIVE_SCANNER_STATE_COLON:
391+
case AVIF_PROGRESSIVE_SCANNER_STATE_SEMICOLON:
391392
switch (*arg) {
392393
case ',':
393-
targetState = COMMA;
394+
targetState = AVIF_PROGRESSIVE_SCANNER_STATE_COMMA;
394395
break;
395396
case '-':
396-
targetState = HYPHEN;
397+
targetState = AVIF_PROGRESSIVE_SCANNER_STATE_HYPHEN;
397398
break;
398399
case ':':
399-
targetState = COLON;
400+
targetState = AVIF_PROGRESSIVE_SCANNER_STATE_COLON;
400401
break;
401402
case ';':
402403
case '\0':
403-
targetState = SEMICOLON;
404+
targetState = AVIF_PROGRESSIVE_SCANNER_STATE_SEMICOLON;
404405
break;
405406
default:
406-
FAIL_IF(AVIF_TRUE, "unexpected separator");
407+
CHECK(AVIF_FALSE, "unexpected separator");
407408
}
408409

409-
FAIL_IF(currState > targetState, "too many config entries");
410+
CHECK(currState <= targetState, "too many config entries");
410411

411412
avifBool earlyEnd = currState < targetState;
412413
switch (targetState) {
413-
case VALUE:
414-
FAIL_IF(AVIF_TRUE, "unknown state");
414+
case AVIF_PROGRESSIVE_SCANNER_STATE_VALUE:
415+
CHECK(AVIF_FALSE, "unknown state");
415416
break;
416417

417-
case COMMA:
418-
FAIL_IF(earlyEnd, "unknown state");
418+
case AVIF_PROGRESSIVE_SCANNER_STATE_COMMA:
419+
CHECK(!earlyEnd, "unknown state");
419420
break;
420421

421-
case HYPHEN:
422+
case AVIF_PROGRESSIVE_SCANNER_STATE_HYPHEN:
422423
if (!earlyEnd) {
423-
FAIL_IF(prevReadValue != MAX_Q, "unknown state");
424+
CHECK(prevReadValue == AVIF_PROGRESSIVE_VALUE_TYPE_MAX_Q, "unknown state");
424425
break;
425426
}
426427

427-
FAIL_IF(prevReadValue != MIN_Q, "unknown state");
428+
CHECK(prevReadValue == AVIF_PROGRESSIVE_VALUE_TYPE_MIN_Q, "unknown state");
428429
currLayers[currLayer].maxQuantizer = currLayers[currLayer].minQuantizer;
429-
prevReadValue = MAX_Q;
430+
prevReadValue = AVIF_PROGRESSIVE_VALUE_TYPE_MAX_Q;
430431
break;
431432

432-
case COLON:
433+
case AVIF_PROGRESSIVE_SCANNER_STATE_COLON:
433434
if (earlyEnd) {
434435
switch (prevReadValue) {
435-
case MIN_Q:
436+
case AVIF_PROGRESSIVE_VALUE_TYPE_MIN_Q:
436437
currLayers[currLayer].maxQuantizer = currLayers[currLayer].minQuantizer;
437-
currLayers[currLayer].horizontalMode = AVIF_SCALING_NORMAL;
438-
currLayers[currLayer].verticalMode = AVIF_SCALING_NORMAL;
438+
currLayers[currLayer].horizontalMode = avifScalingModeNormal;
439+
currLayers[currLayer].verticalMode = avifScalingModeNormal;
439440
break;
440441

441-
case MAX_Q:
442-
currLayers[currLayer].horizontalMode = AVIF_SCALING_NORMAL;
443-
currLayers[currLayer].verticalMode = AVIF_SCALING_NORMAL;
442+
case AVIF_PROGRESSIVE_VALUE_TYPE_MAX_Q:
443+
currLayers[currLayer].horizontalMode = avifScalingModeNormal;
444+
currLayers[currLayer].verticalMode = avifScalingModeNormal;
444445
break;
445446

446-
case H_SCALE:
447-
currLayers[currLayer].verticalMode = AVIF_SCALING_NORMAL;
447+
case AVIF_PROGRESSIVE_VALUE_TYPE_H_SCALE:
448+
currLayers[currLayer].verticalMode = currLayers[currLayer].horizontalMode;
448449
break;
449450

450-
case V_SCALE:
451-
case NONE:
452-
FAIL_IF(AVIF_TRUE, "unknown state");
451+
case AVIF_PROGRESSIVE_VALUE_TYPE_V_SCALE:
452+
case AVIF_PROGRESSIVE_VALUE_TYPE_NONE:
453+
CHECK(AVIF_FALSE, "unknown state");
453454
}
454455
}
455456

456457
++currLayer;
457-
FAIL_IF(currLayer >= MAX_AV1_LAYER_COUNT, "too many layers");
458-
prevReadValue = NONE;
458+
CHECK(currLayer < MAX_AV1_LAYER_COUNT, "too many layers");
459+
prevReadValue = AVIF_PROGRESSIVE_VALUE_TYPE_NONE;
459460
break;
460461

461-
case SEMICOLON:
462+
case AVIF_PROGRESSIVE_SCANNER_STATE_SEMICOLON:
462463
if (earlyEnd) {
463464
switch (prevReadValue) {
464-
case MIN_Q:
465+
case AVIF_PROGRESSIVE_VALUE_TYPE_MIN_Q:
465466
currLayers[currLayer].maxQuantizer = currLayers[currLayer].minQuantizer;
466-
currLayers[currLayer].horizontalMode = AVIF_SCALING_NORMAL;
467-
currLayers[currLayer].verticalMode = AVIF_SCALING_NORMAL;
467+
currLayers[currLayer].horizontalMode = avifScalingModeNormal;
468+
currLayers[currLayer].verticalMode = avifScalingModeNormal;
468469
break;
469470

470-
case MAX_Q:
471-
currLayers[currLayer].horizontalMode = AVIF_SCALING_NORMAL;
472-
currLayers[currLayer].verticalMode = AVIF_SCALING_NORMAL;
471+
case AVIF_PROGRESSIVE_VALUE_TYPE_MAX_Q:
472+
currLayers[currLayer].horizontalMode = avifScalingModeNormal;
473+
currLayers[currLayer].verticalMode = avifScalingModeNormal;
473474
break;
474475

475-
case H_SCALE:
476-
currLayers[currLayer].verticalMode = AVIF_SCALING_NORMAL;
476+
case AVIF_PROGRESSIVE_VALUE_TYPE_H_SCALE:
477+
currLayers[currLayer].verticalMode = currLayers[currLayer].horizontalMode;
477478
break;
478479

479-
case V_SCALE:
480+
case AVIF_PROGRESSIVE_VALUE_TYPE_V_SCALE:
480481
break;
481482

482-
case NONE:
483-
FAIL_IF(AVIF_TRUE, "unknown state");
483+
case AVIF_PROGRESSIVE_VALUE_TYPE_NONE:
484+
CHECK(AVIF_FALSE, "unknown state");
484485
}
485486

486487
++currLayer;
487488
}
488489

489490
*currLayerCount = currLayer;
490491
if (*arg == ';') {
491-
FAIL_IF(currLayers != config->layers, "too many sub image configurations");
492+
CHECK(currLayers == config->layers, "too many sub image configurations");
492493
currLayers = config->layersAlpha;
493494
currLayerCount = &config->layerCountAlpha;
494495

495496
if (*(arg + 1) == '\0') {
496497
goto finish;
497498
}
498499

499-
prevReadValue = NONE;
500+
prevReadValue = AVIF_PROGRESSIVE_VALUE_TYPE_NONE;
500501
currLayer = 0;
501502
} else {
502503
// reached \0
@@ -511,18 +512,13 @@ static avifBool avifParseProgressiveConfig(struct avifEncoderLayerConfig * confi
511512
}
512513

513514
++arg;
514-
currState = VALUE;
515+
currState = AVIF_PROGRESSIVE_SCANNER_STATE_VALUE;
515516
break;
516517
}
517518
}
518519

519520
finish:
520-
if (failReason == NULL) {
521-
return AVIF_TRUE;
522-
}
523-
524-
fprintf(stderr, "ERROR: Failed reading progressive config: %s", failReason);
525-
return AVIF_FALSE;
521+
return AVIF_TRUE;
526522
}
527523

528524
static avifInputFile * avifInputGetNextFile(avifInput * input)

0 commit comments

Comments
 (0)