@@ -297,6 +297,8 @@ avifEncoder * avifEncoderCreate(void)
297297 encoder -> speed = AVIF_SPEED_DEFAULT ;
298298 encoder -> keyframeInterval = 0 ;
299299 encoder -> timescale = 1 ;
300+ encoder -> width = 0 ;
301+ encoder -> height = 0 ;
300302 encoder -> minQuantizer = AVIF_QUANTIZER_LOSSLESS ;
301303 encoder -> maxQuantizer = AVIF_QUANTIZER_LOSSLESS ;
302304 encoder -> minQuantizerAlpha = AVIF_QUANTIZER_LOSSLESS ;
@@ -332,12 +334,15 @@ static void avifEncoderBackupSettings(avifEncoder * encoder)
332334 lastEncoder -> speed = encoder -> speed ;
333335 lastEncoder -> keyframeInterval = encoder -> keyframeInterval ;
334336 lastEncoder -> timescale = encoder -> timescale ;
337+ lastEncoder -> width = encoder -> width ;
338+ lastEncoder -> height = encoder -> height ;
335339 lastEncoder -> minQuantizer = encoder -> minQuantizer ;
336340 lastEncoder -> maxQuantizer = encoder -> maxQuantizer ;
337341 lastEncoder -> minQuantizerAlpha = encoder -> minQuantizerAlpha ;
338342 lastEncoder -> maxQuantizerAlpha = encoder -> maxQuantizerAlpha ;
339343 lastEncoder -> tileRowsLog2 = encoder -> tileRowsLog2 ;
340344 lastEncoder -> tileColsLog2 = encoder -> tileColsLog2 ;
345+ lastEncoder -> speed = encoder -> speed ;
341346}
342347
343348// This function detects changes made on avifEncoder. It returns true on success (i.e., if every
@@ -355,7 +360,7 @@ static avifBool avifEncoderDetectChanges(const avifEncoder * encoder, avifEncode
355360
356361 if ((lastEncoder -> codecChoice != encoder -> codecChoice ) || (lastEncoder -> maxThreads != encoder -> maxThreads ) ||
357362 (lastEncoder -> speed != encoder -> speed ) || (lastEncoder -> keyframeInterval != encoder -> keyframeInterval ) ||
358- (lastEncoder -> timescale != encoder -> timescale )) {
363+ (lastEncoder -> timescale != encoder -> timescale ) || ( lastEncoder -> width != encoder -> width ) || ( lastEncoder -> height != encoder -> height ) ) {
359364 return AVIF_FALSE ;
360365 }
361366
@@ -694,6 +699,10 @@ static avifResult avifEncoderAddImageInternal(avifEncoder * encoder,
694699 return AVIF_RESULT_NO_CONTENT ;
695700 }
696701
702+ if ((encoder -> width && (encoder -> width < firstCell -> width )) || (encoder -> height && (encoder -> height < firstCell -> height ))) {
703+ return AVIF_RESULT_INCOMPATIBLE_IMAGE ;
704+ }
705+
697706 if ((cellCount > 1 ) && !avifAreGridDimensionsValid (firstCell -> yuvFormat ,
698707 gridCols * firstCell -> width ,
699708 gridRows * firstCell -> height ,
@@ -997,6 +1006,9 @@ avifResult avifEncoderFinish(avifEncoder * encoder, avifRWData * output)
9971006 // Begin write stream
9981007
9991008 const avifImage * imageMetadata = encoder -> data -> imageMetadata ;
1009+ const uint32_t cellWidth = encoder -> width ? encoder -> width : imageMetadata -> width ;
1010+ const uint32_t cellHeight = encoder -> height ? encoder -> height : imageMetadata -> height ;
1011+
10001012 // The epoch for creation_time and modification_time is midnight, Jan. 1,
10011013 // 1904, in UTC time. Add the number of seconds between that epoch and the
10021014 // Unix epoch.
@@ -1200,11 +1212,11 @@ avifResult avifEncoderFinish(avifEncoder * encoder, avifRWData * output)
12001212 }
12011213 }
12021214
1203- uint32_t imageWidth = imageMetadata -> width ;
1204- uint32_t imageHeight = imageMetadata -> height ;
1215+ uint32_t imageWidth = cellWidth ;
1216+ uint32_t imageHeight = cellHeight ;
12051217 if (isGrid ) {
1206- imageWidth = imageMetadata -> width * item -> gridCols ;
1207- imageHeight = imageMetadata -> height * item -> gridRows ;
1218+ imageWidth = imageWidth * item -> gridCols ;
1219+ imageHeight = imageHeight * item -> gridRows ;
12081220 }
12091221
12101222 // Properties all av01 items need
@@ -1361,8 +1373,8 @@ avifResult avifEncoderFinish(avifEncoder * encoder, avifRWData * output)
13611373 avifRWStreamWriteU16 (& s , 0 ); // template int(16) volume = {if track_is_audio 0x0100 else 0};
13621374 avifRWStreamWriteU16 (& s , 0 ); // const unsigned int(16) reserved = 0;
13631375 avifRWStreamWrite (& s , unityMatrix , sizeof (unityMatrix )); // template int(32)[9] matrix= // { 0x00010000,0,0,0,0x00010000,0,0,0,0x40000000 };
1364- avifRWStreamWriteU32 (& s , imageMetadata -> width << 16 ); // unsigned int(32) width;
1365- avifRWStreamWriteU32 (& s , imageMetadata -> height << 16 ); // unsigned int(32) height;
1376+ avifRWStreamWriteU32 (& s , cellWidth << 16 ); // unsigned int(32) width;
1377+ avifRWStreamWriteU32 (& s , cellHeight << 16 ); // unsigned int(32) height;
13661378 avifRWStreamFinishBox (& s , tkhd );
13671379
13681380 if (item -> irefToID != 0 ) {
@@ -1470,21 +1482,21 @@ avifResult avifEncoderFinish(avifEncoder * encoder, avifRWData * output)
14701482 avifBoxMarker stsd = avifRWStreamWriteFullBox (& s , "stsd" , AVIF_BOX_SIZE_TBD , 0 , 0 );
14711483 avifRWStreamWriteU32 (& s , 1 ); // unsigned int(32) entry_count;
14721484 avifBoxMarker av01 = avifRWStreamWriteBox (& s , "av01" , AVIF_BOX_SIZE_TBD );
1473- avifRWStreamWriteZeros (& s , 6 ); // const unsigned int(8)[6] reserved = 0;
1474- avifRWStreamWriteU16 (& s , 1 ); // unsigned int(16) data_reference_index;
1475- avifRWStreamWriteU16 (& s , 0 ); // unsigned int(16) pre_defined = 0;
1476- avifRWStreamWriteU16 (& s , 0 ); // const unsigned int(16) reserved = 0;
1477- avifRWStreamWriteZeros (& s , sizeof (uint32_t ) * 3 ); // unsigned int(32)[3] pre_defined = 0;
1478- avifRWStreamWriteU16 (& s , (uint16_t )imageMetadata -> width ); // unsigned int(16) width;
1479- avifRWStreamWriteU16 (& s , (uint16_t )imageMetadata -> height ); // unsigned int(16) height;
1480- avifRWStreamWriteU32 (& s , 0x00480000 ); // template unsigned int(32) horizresolution
1481- avifRWStreamWriteU32 (& s , 0x00480000 ); // template unsigned int(32) vertresolution
1482- avifRWStreamWriteU32 (& s , 0 ); // const unsigned int(32) reserved = 0;
1483- avifRWStreamWriteU16 (& s , 1 ); // template unsigned int(16) frame_count = 1;
1484- avifRWStreamWriteChars (& s , "\012AOM Coding" , 11 ); // string[32] compressorname;
1485- avifRWStreamWriteZeros (& s , 32 - 11 ); //
1486- avifRWStreamWriteU16 (& s , 0x0018 ); // template unsigned int(16) depth = 0x0018;
1487- avifRWStreamWriteU16 (& s , (uint16_t )0xffff ); // int(16) pre_defined = -1;
1485+ avifRWStreamWriteZeros (& s , 6 ); // const unsigned int(8)[6] reserved = 0;
1486+ avifRWStreamWriteU16 (& s , 1 ); // unsigned int(16) data_reference_index;
1487+ avifRWStreamWriteU16 (& s , 0 ); // unsigned int(16) pre_defined = 0;
1488+ avifRWStreamWriteU16 (& s , 0 ); // const unsigned int(16) reserved = 0;
1489+ avifRWStreamWriteZeros (& s , sizeof (uint32_t ) * 3 ); // unsigned int(32)[3] pre_defined = 0;
1490+ avifRWStreamWriteU16 (& s , (uint16_t )cellWidth ); // unsigned int(16) width;
1491+ avifRWStreamWriteU16 (& s , (uint16_t )cellHeight ); // unsigned int(16) height;
1492+ avifRWStreamWriteU32 (& s , 0x00480000 ); // template unsigned int(32) horizresolution
1493+ avifRWStreamWriteU32 (& s , 0x00480000 ); // template unsigned int(32) vertresolution
1494+ avifRWStreamWriteU32 (& s , 0 ); // const unsigned int(32) reserved = 0;
1495+ avifRWStreamWriteU16 (& s , 1 ); // template unsigned int(16) frame_count = 1;
1496+ avifRWStreamWriteChars (& s , "\012AOM Coding" , 11 ); // string[32] compressorname;
1497+ avifRWStreamWriteZeros (& s , 32 - 11 ); //
1498+ avifRWStreamWriteU16 (& s , 0x0018 ); // template unsigned int(16) depth = 0x0018;
1499+ avifRWStreamWriteU16 (& s , (uint16_t )0xffff ); // int(16) pre_defined = -1;
14881500 writeConfigBox (& s , & item -> av1C );
14891501 if (!item -> alpha ) {
14901502 avifEncoderWriteColorProperties (& s , imageMetadata , NULL , NULL );
0 commit comments