blob: ec508db090a0d9adb2be3fd26f9ed1dbd9c98007 [file] [log] [blame]
Joe Dragoe59e0a82020-10-30 17:32:31 -07001// Copyright 2020 Joe Drago. All rights reserved.
2// SPDX-License-Identifier: BSD-2-Clause
3
4#include "avif/avif.h"
5
6#include <inttypes.h>
7#include <stdio.h>
8#include <string.h>
9
10int main(int argc, char * argv[])
11{
12 if (argc != 3) {
13 fprintf(stderr, "avif_example_encode [encodeYUVDirectly:0/1] [output.avif]\n");
14 return 1;
15 }
16 avifBool encodeYUVDirectly = AVIF_FALSE;
17 if (argv[1][0] == '1') {
18 encodeYUVDirectly = AVIF_TRUE;
19 }
20 const char * outputFilename = argv[2];
21
22 int returnCode = 1;
23 avifEncoder * encoder = NULL;
24 avifRWData avifOutput = AVIF_DATA_EMPTY;
25 avifRGBImage rgb;
26 memset(&rgb, 0, sizeof(rgb));
27
28 avifImage * image = avifImageCreate(128, 128, 8, AVIF_PIXEL_FORMAT_YUV444); // these values dictate what goes into the final AVIF
Yannis Guyonf4a96382023-02-14 09:41:14 +010029 if (!image) {
30 fprintf(stderr, "Out of memory\n");
31 goto cleanup;
32 }
Joe Dragoe59e0a82020-10-30 17:32:31 -070033 // Configure image here: (see avif/avif.h)
34 // * colorPrimaries
35 // * transferCharacteristics
36 // * matrixCoefficients
37 // * avifImageSetProfileICC()
Wan-Teh Changb3e0f312022-10-10 14:09:44 -070038 // * avifImageSetMetadataExif()
Joe Dragoe59e0a82020-10-30 17:32:31 -070039 // * avifImageSetMetadataXMP()
40 // * yuvRange
Wan-Teh Chang53adb6a2021-02-20 16:58:43 -080041 // * alphaPremultiplied
Joe Dragoe59e0a82020-10-30 17:32:31 -070042 // * transforms (transformFlags, pasp, clap, irot, imir)
43
44 if (encodeYUVDirectly) {
45 // If you have YUV(A) data you want to encode, use this path
46 printf("Encoding raw YUVA data\n");
47
Yannis Guyon1ce971e2022-08-01 20:22:04 +020048 const avifResult allocateResult = avifImageAllocatePlanes(image, AVIF_PLANES_ALL);
49 if (allocateResult != AVIF_RESULT_OK) {
50 fprintf(stderr, "Failed to allocate the planes: %s\n", avifResultToString(allocateResult));
51 goto cleanup;
52 }
Joe Dragoe59e0a82020-10-30 17:32:31 -070053
54 // Fill your YUV(A) data here
55 memset(image->yuvPlanes[AVIF_CHAN_Y], 255, image->yuvRowBytes[AVIF_CHAN_Y] * image->height);
56 memset(image->yuvPlanes[AVIF_CHAN_U], 128, image->yuvRowBytes[AVIF_CHAN_U] * image->height);
57 memset(image->yuvPlanes[AVIF_CHAN_V], 128, image->yuvRowBytes[AVIF_CHAN_V] * image->height);
58 memset(image->alphaPlane, 255, image->alphaRowBytes * image->height);
59 } else {
60 // If you have RGB(A) data you want to encode, use this path
61 printf("Encoding from converted RGBA\n");
62
63 avifRGBImageSetDefaults(&rgb, image);
Yannis Guyonb3d441a2022-09-18 12:35:03 +020064 // Override RGB(A)->YUV(A) defaults here:
65 // depth, format, chromaDownsampling, avoidLibYUV, ignoreAlpha, alphaPremultiplied, etc.
Joe Dragoe59e0a82020-10-30 17:32:31 -070066
67 // Alternative: set rgb.pixels and rgb.rowBytes yourself, which should match your chosen rgb.format
68 // Be sure to use uint16_t* instead of uint8_t* for rgb.pixels/rgb.rowBytes if (rgb.depth > 8)
Yannis Guyond48836b2023-04-01 16:09:20 +020069 avifResult allocationResult = avifRGBImageAllocatePixels(&rgb);
70 if (allocationResult != AVIF_RESULT_OK) {
71 fprintf(stderr, "Allocation of RGB samples failed: %s\n", avifResultToString(allocationResult));
72 goto cleanup;
73 }
Joe Dragoe59e0a82020-10-30 17:32:31 -070074
75 // Fill your RGB(A) data here
76 memset(rgb.pixels, 255, rgb.rowBytes * image->height);
77
Yannis Guyonb3d441a2022-09-18 12:35:03 +020078 avifResult convertResult = avifImageRGBToYUV(image, &rgb);
Joe Dragoe59e0a82020-10-30 17:32:31 -070079 if (convertResult != AVIF_RESULT_OK) {
80 fprintf(stderr, "Failed to convert to YUV(A): %s\n", avifResultToString(convertResult));
81 goto cleanup;
82 }
83 }
84
85 encoder = avifEncoderCreate();
Yannis Guyonf4a96382023-02-14 09:41:14 +010086 if (!encoder) {
87 fprintf(stderr, "Out of memory\n");
88 goto cleanup;
89 }
Joe Dragoe59e0a82020-10-30 17:32:31 -070090 // Configure your encoder here (see avif/avif.h):
91 // * maxThreads
Wan-Teh Chang570c42c2022-11-29 15:42:19 -080092 // * quality
93 // * qualityAlpha
Joe Dragoe59e0a82020-10-30 17:32:31 -070094 // * tileRowsLog2
95 // * tileColsLog2
96 // * speed
97 // * keyframeInterval
98 // * timescale
Wan-Teh Chang570c42c2022-11-29 15:42:19 -080099 encoder->quality = 60;
100 encoder->qualityAlpha = AVIF_QUALITY_LOSSLESS;
Joe Dragoe59e0a82020-10-30 17:32:31 -0700101
102 // Call avifEncoderAddImage() for each image in your sequence
103 // Only set AVIF_ADD_IMAGE_FLAG_SINGLE if you're not encoding a sequence
Joe Drago55591852020-12-11 14:29:19 -0800104 // Use avifEncoderAddImageGrid() instead with an array of avifImage* to make a grid image
Joe Dragoe59e0a82020-10-30 17:32:31 -0700105 avifResult addImageResult = avifEncoderAddImage(encoder, image, 1, AVIF_ADD_IMAGE_FLAG_SINGLE);
106 if (addImageResult != AVIF_RESULT_OK) {
107 fprintf(stderr, "Failed to add image to encoder: %s\n", avifResultToString(addImageResult));
108 goto cleanup;
109 }
110
111 avifResult finishResult = avifEncoderFinish(encoder, &avifOutput);
112 if (finishResult != AVIF_RESULT_OK) {
113 fprintf(stderr, "Failed to finish encode: %s\n", avifResultToString(finishResult));
114 goto cleanup;
115 }
116
117 printf("Encode success: %zu total bytes\n", avifOutput.size);
118
119 FILE * f = fopen(outputFilename, "wb");
120 size_t bytesWritten = fwrite(avifOutput.data, 1, avifOutput.size, f);
121 fclose(f);
122 if (bytesWritten != avifOutput.size) {
123 fprintf(stderr, "Failed to write %zu bytes\n", avifOutput.size);
124 goto cleanup;
125 }
126 printf("Wrote: %s\n", outputFilename);
127
128 returnCode = 0;
129cleanup:
130 if (image) {
131 avifImageDestroy(image);
132 }
133 if (encoder) {
134 avifEncoderDestroy(encoder);
135 }
136 avifRWDataFree(&avifOutput);
137 avifRGBImageFreePixels(&rgb); // Only use in conjunction with avifRGBImageAllocatePixels()
138 return returnCode;
139}