Flutter Engine
The Flutter Engine
Functions
convert-to-nia.cpp File Reference
#include <stdio.h>
#include <string.h>
#include "include/codec/SkCodec.h"
#include "include/core/SkBitmap.h"
#include "include/core/SkData.h"
#include "src/base/SkAutoMalloc.h"

Go to the source code of this file.

Functions

static void set_u32le (uint8_t *ptr, uint32_t val)
 
static void set_u64le (uint8_t *ptr, uint64_t val)
 
static void write_nix_header (uint32_t magicU32le, uint32_t width, uint32_t height)
 
static bool write_nia_duration (uint64_t totalDurationMillis)
 
static void write_nie_pixels (uint32_t width, uint32_t height, const SkBitmap &bm)
 
static void write_nia_padding (uint32_t width, uint32_t height)
 
static void write_nia_footer (int repetitionCount, bool stillImage)
 
int main (int argc, char **argv)
 

Function Documentation

◆ main()

int main ( int  argc,
char **  argv 
)

Definition at line 126 of file convert-to-nia.cpp.

126 {
127 bool firstFrameOnly = false;
128 for (int a = 1; a < argc; a++) {
129 if ((strcmp(argv[a], "-1") == 0) || (strcmp(argv[a], "-first-frame-only") == 0)) {
130 firstFrameOnly = true;
131 break;
132 }
133 }
134
135 std::unique_ptr<SkCodec> codec(SkCodec::MakeFromData(SkData::MakeFromFILE(stdin)));
136 if (!codec) {
137 SkDebugf("Decode failed.\n");
138 return 1;
139 }
140 codec->getInfo().makeColorSpace(nullptr);
141 SkBitmap bm;
142 bm.allocPixels(codec->getInfo());
143 size_t bmByteSize = bm.computeByteSize();
144
145 // Cache a frame that future frames may depend on.
146 int cachedFrame = SkCodec::kNoFrame;
147 SkAutoMalloc cachedFramePixels;
148
149 uint64_t totalDurationMillis = 0;
150 const int frameCount = codec->getFrameCount();
151 if (frameCount == 0) {
152 SkDebugf("No frames.\n");
153 return 1;
154 }
155 std::vector<SkCodec::FrameInfo> frameInfos = codec->getFrameInfo();
156 bool stillImage = frameInfos.size() <= 1;
157
158 for (int i = 0; i < frameCount; i++) {
159 SkCodec::Options opts;
160 opts.fFrameIndex = i;
161
162 if (!stillImage) {
163 int durationMillis = frameInfos[i].fDuration;
164 if (durationMillis < 0) {
165 SkDebugf("Negative animation duration.\n");
166 return 1;
167 }
168 totalDurationMillis += static_cast<uint64_t>(durationMillis);
169 if (totalDurationMillis > INT64_MAX) {
170 SkDebugf("Unsupported animation duration.\n");
171 return 1;
172 }
173
174 if ((cachedFrame != SkCodec::kNoFrame) &&
175 (cachedFrame == frameInfos[i].fRequiredFrame) && cachedFramePixels.get()) {
176 opts.fPriorFrame = cachedFrame;
177 memcpy(bm.getPixels(), cachedFramePixels.get(), bmByteSize);
178 }
179 }
180
181 if (!firstFrameOnly) {
182 if (i == 0) {
183 write_nix_header(0x41AFC36E, // "nïA" magic string as a u32le.
184 bm.width(), bm.height());
185 }
186
187 if (!write_nia_duration(totalDurationMillis)) {
188 SkDebugf("Unsupported animation duration.\n");
189 return 1;
190 }
191 }
192
193 const SkCodec::Result result =
194 codec->getPixels(codec->getInfo(), bm.getPixels(), bm.rowBytes(), &opts);
196 SkDebugf("Decode frame pixels #%d failed.\n", i);
197 return 1;
198 }
199
200 // If the next frame depends on this one, store it in cachedFrame. It
201 // is possible that we may discard a frame that future frames depend
202 // on, but the codec will simply redecode the discarded frame.
203 if ((static_cast<size_t>(i + 1) < frameInfos.size()) &&
204 (frameInfos[i + 1].fRequiredFrame == i)) {
205 cachedFrame = i;
206 memcpy(cachedFramePixels.reset(bmByteSize), bm.getPixels(), bmByteSize);
207 }
208
209 int width = bm.width();
210 int height = bm.height();
211 write_nix_header(0x45AFC36E, // "nïE" magic string as a u32le.
212 width, height);
215 SkDebugf("Incomplete input.\n");
216 return 1;
217 }
218 if (firstFrameOnly) {
219 return 0;
220 }
222 }
223 write_nia_footer(codec->getRepetitionCount(), stillImage);
224 return 0;
225}
void SK_SPI SkDebugf(const char format[],...) SK_PRINTF_LIKE(1
void * reset(size_t size=0, OnShrink shrink=kAlloc_OnShrink)
Definition: SkAutoMalloc.h:53
void * get()
Definition: SkAutoMalloc.h:64
void allocPixels(const SkImageInfo &info, size_t rowBytes)
Definition: SkBitmap.cpp:258
size_t computeByteSize() const
Definition: SkBitmap.h:293
int width() const
Definition: SkBitmap.h:149
size_t rowBytes() const
Definition: SkBitmap.h:238
void * getPixels() const
Definition: SkBitmap.h:283
int height() const
Definition: SkBitmap.h:158
static std::unique_ptr< SkCodec > MakeFromData(sk_sp< SkData >, SkSpan< const SkCodecs::Decoder > decoders, SkPngChunkReader *=nullptr)
Definition: SkCodec.cpp:241
Result
Definition: SkCodec.h:76
@ kIncompleteInput
Definition: SkCodec.h:84
@ kSuccess
Definition: SkCodec.h:80
static constexpr int kNoFrame
Definition: SkCodec.h:650
static sk_sp< SkData > MakeFromFILE(FILE *f)
Definition: SkData.cpp:138
static void write_nie_pixels(uint32_t width, uint32_t height, const SkBitmap &bm)
static void write_nia_padding(uint32_t width, uint32_t height)
static bool write_nia_duration(uint64_t totalDurationMillis)
static void write_nix_header(uint32_t magicU32le, uint32_t width, uint32_t height)
static void write_nia_footer(int repetitionCount, bool stillImage)
struct MyStruct a[10]
GAsyncResult * result
char ** argv
Definition: library.h:9
int32_t height
int32_t width

◆ set_u32le()

static void set_u32le ( uint8_t *  ptr,
uint32_t  val 
)
inlinestatic

Definition at line 40 of file convert-to-nia.cpp.

40 {
41 ptr[0] = val >> 0;
42 ptr[1] = val >> 8;
43 ptr[2] = val >> 16;
44 ptr[3] = val >> 24;
45}

◆ set_u64le()

static void set_u64le ( uint8_t *  ptr,
uint64_t  val 
)
inlinestatic

Definition at line 47 of file convert-to-nia.cpp.

47 {
48 ptr[0] = val >> 0;
49 ptr[1] = val >> 8;
50 ptr[2] = val >> 16;
51 ptr[3] = val >> 24;
52 ptr[4] = val >> 32;
53 ptr[5] = val >> 40;
54 ptr[6] = val >> 48;
55 ptr[7] = val >> 56;
56}

◆ write_nia_duration()

static bool write_nia_duration ( uint64_t  totalDurationMillis)
static

Definition at line 67 of file convert-to-nia.cpp.

67 {
68 // Flicks are NIA's unit of time. One flick (frame-tick) is 1 / 705_600_000
69 // of a second. See https://github.com/OculusVR/Flicks
70 static constexpr uint64_t flicksPerMilli = 705600;
71 if (totalDurationMillis > (INT64_MAX / flicksPerMilli)) {
72 // Converting from millis to flicks would overflow.
73 return false;
74 }
75
76 uint8_t data[8];
77 set_u64le(data + 0, totalDurationMillis * flicksPerMilli);
78 fwrite(data, 1, 8, stdout);
79 return true;
80}
static void set_u64le(uint8_t *ptr, uint64_t val)
std::shared_ptr< const fml::Mapping > data
Definition: texture_gles.cc:63

◆ write_nia_footer()

static void write_nia_footer ( int  repetitionCount,
bool  stillImage 
)
static

Definition at line 113 of file convert-to-nia.cpp.

113 {
114 uint8_t data[8];
115 if (stillImage || (repetitionCount == SkCodec::kRepetitionCountInfinite)) {
116 set_u32le(data + 0, 0);
117 } else {
118 // NIA's loop count and Skia's repetition count differ by one. See
119 // https://github.com/google/wuffs/blob/master/doc/spec/nie-spec.md#nii-footer
120 set_u32le(data + 0, 1 + repetitionCount);
121 }
122 set_u32le(data + 4, 0x80000000);
123 fwrite(data, 1, 8, stdout);
124}
static constexpr int kRepetitionCountInfinite
Definition: SkCodec.h:759
static void set_u32le(uint8_t *ptr, uint32_t val)

◆ write_nia_padding()

static void write_nia_padding ( uint32_t  width,
uint32_t  height 
)
static

Definition at line 104 of file convert-to-nia.cpp.

104 {
105 // 4 bytes of padding when the width and height are both odd.
106 if (width & height & 1) {
107 uint8_t data[4];
108 set_u32le(data + 0, 0);
109 fwrite(data, 1, 4, stdout);
110 }
111}

◆ write_nie_pixels()

static void write_nie_pixels ( uint32_t  width,
uint32_t  height,
const SkBitmap bm 
)
static

Definition at line 82 of file convert-to-nia.cpp.

82 {
83 static constexpr size_t kBufferSize = 4096;
84 uint8_t buf[kBufferSize];
85 size_t n = 0;
86 for (uint32_t y = 0; y < height; y++) {
87 for (uint32_t x = 0; x < width; x++) {
88 SkColor c = bm.getColor(x, y);
89 buf[n++] = SkColorGetB(c);
90 buf[n++] = SkColorGetG(c);
91 buf[n++] = SkColorGetR(c);
92 buf[n++] = SkColorGetA(c);
93 if (n == kBufferSize) {
94 fwrite(buf, 1, n, stdout);
95 n = 0;
96 }
97 }
98 }
99 if (n > 0) {
100 fwrite(buf, 1, n, stdout);
101 }
102}
#define SkColorGetR(color)
Definition: SkColor.h:65
#define SkColorGetG(color)
Definition: SkColor.h:69
uint32_t SkColor
Definition: SkColor.h:37
#define SkColorGetA(color)
Definition: SkColor.h:61
#define SkColorGetB(color)
Definition: SkColor.h:73
static const size_t kBufferSize
Definition: SkString.cpp:27
SkColor getColor(int x, int y) const
Definition: SkBitmap.h:874
double y
double x

◆ write_nix_header()

static void write_nix_header ( uint32_t  magicU32le,
uint32_t  width,
uint32_t  height 
)
static

Definition at line 58 of file convert-to-nia.cpp.

58 {
59 uint8_t data[16];
60 set_u32le(data + 0, magicU32le);
61 set_u32le(data + 4, 0x346E62FF); // 4 bytes per pixel non-premul BGRA.
62 set_u32le(data + 8, width);
63 set_u32le(data + 12, height);
64 fwrite(data, 1, 16, stdout);
65}