Flutter Engine
The Flutter Engine
Classes | Functions
skottie2movie.cpp File Reference
#include "experimental/ffmpeg/SkVideoEncoder.h"
#include "include/core/SkCanvas.h"
#include "include/core/SkGraphics.h"
#include "include/core/SkStream.h"
#include "include/core/SkSurface.h"
#include "include/private/base/SkTPin.h"
#include "modules/skottie/include/Skottie.h"
#include "modules/skresources/include/SkResources.h"
#include "src/base/SkTime.h"
#include "src/utils/SkOSPath.h"
#include "tools/CodecUtils.h"
#include "tools/flags/CommandLineFlags.h"
#include "tools/gpu/GrContextFactory.h"
#include "include/gpu/GrContextOptions.h"
#include "include/gpu/GrTypes.h"
#include "include/gpu/ganesh/SkSurfaceGanesh.h"
#include "modules/skshaper/utils/FactoryHelpers.h"
#include "include/ports/SkFontMgr_empty.h"

Go to the source code of this file.

Classes

struct  AsyncRec
 

Functions

static DEFINE_string2 (input, i, "", "skottie animation to render")
 
static DEFINE_string2 (output, o, "", "mp4 file to create")
 
static DEFINE_string2 (assetPath, a, "", "path to assets needed for json file")
 
static DEFINE_int_2 (fps, f, 25, "fps")
 
static DEFINE_bool2 (verbose, v, false, "verbose mode")
 
static DEFINE_bool2 (loop, l, false, "loop mode for profiling")
 
static DEFINE_int (set_dst_width, 0, "set destination width (height will be computed)")
 
static DEFINE_bool2 (gpu, g, false, "use GPU for rendering")
 
static void produce_frame (SkSurface *surf, skottie::Animation *anim, double frame)
 
int main (int argc, char **argv)
 

Function Documentation

◆ DEFINE_bool2() [1/3]

static DEFINE_bool2 ( gpu  ,
,
false  ,
"use GPU for rendering"   
)
static

◆ DEFINE_bool2() [2/3]

static DEFINE_bool2 ( loop  ,
,
false  ,
"loop mode for profiling"   
)
static

◆ DEFINE_bool2() [3/3]

static DEFINE_bool2 ( verbose  ,
,
false  ,
"verbose mode"   
)
static

◆ DEFINE_int()

static DEFINE_int ( set_dst_width  ,
,
"set destination width (height will be computed)"   
)
static

◆ DEFINE_int_2()

static DEFINE_int_2 ( fps  ,
,
25  ,
"fps"   
)
static

◆ DEFINE_string2() [1/3]

static DEFINE_string2 ( assetPath  ,
a  ,
""  ,
"path to assets needed for json file"   
)
static

◆ DEFINE_string2() [2/3]

static DEFINE_string2 ( input  ,
i  ,
""  ,
"skottie animation to render  
)
static

◆ DEFINE_string2() [3/3]

static DEFINE_string2 ( output  ,
,
""  ,
"mp4 file to create  
)
static

◆ main()

int main ( int  argc,
char **  argv 
)

Definition at line 56 of file skottie2movie.cpp.

56 {
58
59 CommandLineFlags::SetUsage("Converts skottie to a mp4");
61
62 if (FLAGS_input.size() == 0) {
63 SkDebugf("-i input_file.json argument required\n");
64 return -1;
65 }
66
67 auto contextType = skgpu::ContextType::kGL;
68 GrContextOptions grCtxOptions;
69 sk_gpu_test::GrContextFactory factory(grCtxOptions);
70
71 SkString assetPath;
72 if (FLAGS_assetPath.size() > 0) {
73 assetPath.set(FLAGS_assetPath[0]);
74 } else {
75 assetPath = SkOSPath::Dirname(FLAGS_input[0]);
76 }
77 SkDebugf("assetPath %s\n", assetPath.c_str());
78
80
81 // If necessary, clients should use a font manager that would load fonts from the system.
82#if defined(SK_BUILD_FOR_MAC) && defined(SK_FONTMGR_CORETEXT_AVAILABLE)
84#elif defined(SK_BUILD_FOR_ANDROID) && defined(SK_FONTMGR_ANDROID_AVAILABLE)
85 sk_sp<SkFontMgr> fontMgr = SkFontMgr_New_Android(nullptr, std::make_unique<SkFontScanner_FreeType>());
86#elif defined(SK_BUILD_FOR_UNIX) && defined(SK_FONTMGR_FONTCONFIG_AVAILABLE)
88#else
90#endif
91
92 auto animation = skottie::Animation::Builder()
93 .setResourceProvider(skresources::FileResourceProvider::Make(assetPath))
94 .setTextShapingFactory(SkShapers::BestAvailable())
95 .setFontManager(fontMgr)
96 .makeFromFile(FLAGS_input[0]);
97 if (!animation) {
98 SkDebugf("failed to load %s\n", FLAGS_input[0]);
99 return -1;
100 }
101
102 SkISize dim = animation->size().toRound();
103 double duration = animation->duration();
104 int fps = SkTPin(FLAGS_fps, 1, 240);
105 double fps_scale = animation->fps() / fps;
106
107 float scale = 1;
108 if (FLAGS_set_dst_width > 0) {
109 scale = FLAGS_set_dst_width / (float)dim.width();
110 dim = { FLAGS_set_dst_width, SkScalarRoundToInt(scale * dim.height()) };
111 }
112
113 const int frames = SkScalarRoundToInt(duration * fps);
114 const double frame_duration = 1.0 / fps;
115
116 if (FLAGS_verbose) {
117 SkDebugf("Size %dx%d duration %g, fps %d, frame_duration %g\n",
118 dim.width(), dim.height(), duration, fps, frame_duration);
119 }
120
122
123 GrDirectContext* grctx = nullptr;
124 sk_sp<SkSurface> surf;
126
127 const auto info = SkImageInfo::MakeN32Premul(dim);
128 do {
129 double loop_start = SkTime::GetSecs();
130
131 if (!encoder.beginRecording(dim, fps)) {
132 SkDEBUGF("Invalid video stream configuration.\n");
133 return -1;
134 }
135
136 // lazily allocate the surfaces
137 if (!surf) {
138 if (FLAGS_gpu) {
139 grctx = factory.getContextInfo(contextType).directContext();
140 surf = SkSurfaces::RenderTarget(grctx,
142 info,
143 0,
145 nullptr);
146 if (!surf) {
147 grctx = nullptr;
148 }
149 }
150 if (!surf) {
151 surf = SkSurfaces::Raster(info);
152 }
153 surf->getCanvas()->scale(scale, scale);
154 }
155
156 for (int i = 0; i <= frames; ++i) {
157 const double frame = i * fps_scale;
158 if (FLAGS_verbose) {
159 SkDebugf("rendering frame %g\n", frame);
160 }
161
162 produce_frame(surf.get(), animation.get(), frame);
163
164 AsyncRec asyncRec = { info, &encoder };
165 if (grctx) {
166 auto read_pixels_cb = [](SkSurface::ReadPixelsContext ctx,
167 std::unique_ptr<const SkSurface::AsyncReadResult> result) {
168 if (result && result->count() == 1) {
169 AsyncRec* rec = reinterpret_cast<AsyncRec*>(ctx);
170 rec->encoder->addFrame({rec->info, result->data(0), result->rowBytes(0)});
171 }
172 };
173 surf->asyncRescaleAndReadPixels(info, {0, 0, info.width(), info.height()},
176 read_pixels_cb, &asyncRec);
177 grctx->submit();
178 } else {
179 SkPixmap pm;
180 SkAssertResult(surf->peekPixels(&pm));
181 encoder.addFrame(pm);
182 }
183 }
184
185 if (grctx) {
186 // ensure all pending reads are completed
188 }
189 data = encoder.endRecording();
190
191 if (FLAGS_loop) {
192 double loop_dur = SkTime::GetSecs() - loop_start;
193 SkDebugf("recording secs %g, frames %d, recording fps %d\n",
194 loop_dur, frames, (int)(frames / loop_dur));
195 }
196 } while (FLAGS_loop);
197
198 if (FLAGS_output.size() == 0) {
199 SkDebugf("missing -o output_file.mp4 argument\n");
200 return 0;
201 }
202
203 SkFILEWStream ostream(FLAGS_output[0]);
204 if (!ostream.isValid()) {
205 SkDebugf("Can't create output file %s\n", FLAGS_output[0]);
206 return -1;
207 }
208 ostream.write(data->data(), data->size());
209 return 0;
210}
static void info(const char *fmt,...) SK_PRINTF_LIKE(1
Definition: DM.cpp:213
SkAssertResult(font.textToGlyphs("Hello", 5, SkTextEncoding::kUTF8, glyphs, std::size(glyphs))==count)
@ kTopLeft_GrSurfaceOrigin
Definition: GrTypes.h:148
void SK_SPI SkDebugf(const char format[],...) SK_PRINTF_LIKE(1
#define SkDEBUGF(...)
Definition: SkDebug.h:24
SK_API sk_sp< SkFontMgr > SkFontMgr_New_Android(const SkFontMgr_Android_CustomFonts *custom)
SK_API sk_sp< SkFontMgr > SkFontMgr_New_Custom_Empty()
SK_API sk_sp< SkFontMgr > SkFontMgr_New_FontConfig(FcConfig *fc)
SK_API sk_sp< SkFontMgr > SkFontMgr_New_CoreText(CTFontCollectionRef)
#define SkScalarRoundToInt(x)
Definition: SkScalar.h:37
static constexpr const T & SkTPin(const T &x, const T &lo, const T &hi)
Definition: SkTPin.h:19
static void Parse(int argc, const char *const *argv)
static void SetUsage(const char *usage)
bool submit(GrSyncCpu sync=GrSyncCpu::kNo)
void flushAndSubmit(GrSyncCpu sync=GrSyncCpu::kNo)
void scale(SkScalar sx, SkScalar sy)
Definition: SkCanvas.cpp:1289
static void Init()
Definition: SkGraphics.cpp:22
static SkString Dirname(const char *fullPath)
Definition: SkOSPath.cpp:36
void set(const SkString &src)
Definition: SkString.h:186
const char * c_str() const
Definition: SkString.h:133
SkCanvas * getCanvas()
Definition: SkSurface.cpp:82
void asyncRescaleAndReadPixels(const SkImageInfo &info, const SkIRect &srcRect, RescaleGamma rescaleGamma, RescaleMode rescaleMode, ReadPixelsCallback callback, ReadPixelsContext context)
Definition: SkSurface.cpp:139
bool peekPixels(SkPixmap *pixmap)
Definition: SkSurface.cpp:121
void * ReadPixelsContext
Definition: SkSurface.h:464
bool addFrame(const SkPixmap &)
T * get() const
Definition: SkRefCnt.h:303
static sk_sp< FileResourceProvider > Make(SkString base_dir, ImageDecodeStrategy=ImageDecodeStrategy::kLazyDecode)
sk_sp< SkFontMgr > fontMgr
Definition: examples.cpp:32
double duration
Definition: examples.cpp:30
double frame
Definition: examples.cpp:31
GAsyncResult * result
char ** argv
Definition: library.h:9
void RegisterAllAvailable()
Definition: CodecUtils.h:60
sk_sp< Factory > BestAvailable()
SK_API sk_sp< SkSurface > Raster(const SkImageInfo &imageInfo, size_t rowBytes, const SkSurfaceProps *surfaceProps)
SK_API sk_sp< SkSurface > RenderTarget(GrRecordingContext *context, skgpu::Budgeted budgeted, const SkImageInfo &imageInfo, int sampleCount, GrSurfaceOrigin surfaceOrigin, const SkSurfaceProps *surfaceProps, bool shouldCreateWithMips=false, bool isProtected=false)
double GetSecs()
Definition: SkTime.h:16
DlVertices::Builder Builder
static void produce_frame(SkSurface *surf, skottie::Animation *anim, double frame)
const Scalar scale
SkImageInfo info
SkVideoEncoder * encoder
Definition: SkSize.h:16
constexpr int32_t width() const
Definition: SkSize.h:36
constexpr int32_t height() const
Definition: SkSize.h:37
static SkImageInfo MakeN32Premul(int width, int height)
std::shared_ptr< const fml::Mapping > data
Definition: texture_gles.cc:63

◆ produce_frame()

static void produce_frame ( SkSurface surf,
skottie::Animation anim,
double  frame 
)
static

Definition at line 45 of file skottie2movie.cpp.

45 {
46 anim->seekFrame(frame);
48 anim->render(surf->getCanvas());
49}
constexpr SkColor SK_ColorWHITE
Definition: SkColor.h:122
void clear(SkColor color)
Definition: SkCanvas.h:1199
void seekFrame(double t, sksg::InvalidationController *ic=nullptr)
Definition: Skottie.cpp:513
void render(SkCanvas *canvas, const SkRect *dst=nullptr) const
Definition: Skottie.cpp:482