472 {
476
477 if (FLAGS_input.isEmpty() || FLAGS_writePath.isEmpty()) {
478 SkDebugf(
"Missing required 'input' and 'writePath' args.\n");
479 return 1;
480 }
481
483 if (0 == std::strcmp(FLAGS_format[0], "png")) {
484 fmt = OutputFormat::kPNG;
485 } else if (0 == std::strcmp(FLAGS_format[0], "skp")) {
486 fmt = OutputFormat::kSKP;
487 } else if (0 == std::strcmp(FLAGS_format[0], "null")) {
489#if defined(HAVE_VIDEO_ENCODER)
490 } else if (0 == std::strcmp(FLAGS_format[0], "mp4")) {
491 fmt = OutputFormat::kMP4;
492#endif
493 } else {
494 fprintf(stderr, "Unknown format: %s\n", FLAGS_format[0]);
495 return 1;
496 }
497
498 if (
fmt != OutputFormat::kMP4 && !
sk_mkdir(FLAGS_writePath[0])) {
499 return 1;
500 }
501
505
506
507#if defined(SK_BUILD_FOR_MAC) && defined(SK_FONTMGR_CORETEXT_AVAILABLE)
509#elif defined(SK_BUILD_FOR_ANDROID) && defined(SK_FONTMGR_ANDROID_AVAILABLE)
511#elif defined(SK_BUILD_FOR_UNIX) && defined(SK_FONTMGR_FONTCONFIG_AVAILABLE)
513#else
515#endif
516
518 auto logger = sk_make_sp<Logger>();
522 predecode),
523 predecode,
526 auto precomp_interceptor =
527 sk_make_sp<skottie_utils::ExternalAnimationPrecompInterceptor>(rp, "__");
528
530 SkDebugf(
"Could not load %s.\n", FLAGS_input[0]);
531 return 1;
532 }
533
534
535
536
540 .setResourceProvider(rp)
542 .make(
static_cast<const char*
>(
data->data()),
data->size());
543 if (!anim) {
544 SkDebugf(
"Could not parse animation: '%s'.\n", FLAGS_input[0]);
545 return 1;
546 }
547
552
553 const auto t0 =
SkTPin(FLAGS_t0, 0.0, 1.0),
554 t1 =
SkTPin(FLAGS_t1, t0, 1.0),
555 native_fps = anim->fps(),
556 frame0 = anim->duration() * t0 * native_fps,
557 duration = anim->duration() * (t1 - t0);
558
559 double fps = FLAGS_fps > 0 ? FLAGS_fps : native_fps;
560 if (fps <= 0) {
561 SkDebugf(
"Invalid fps: %f.\n", fps);
562 return 1;
563 }
564
565 auto frame_count =
static_cast<int>(
duration * fps);
566 static constexpr int kMaxFrames = 10000;
567 if (frame_count > kMaxFrames) {
568 frame_count = kMaxFrames;
570 }
571 const auto fps_scale = native_fps / fps;
572
573 printf(
"Rendering %f seconds (%d frames @%f fps).\n",
duration, frame_count, fps);
574
576
577 std::vector<double> frames_ms(frame_count);
578
579 const auto thread_count = FLAGS_gpu ? 0 : FLAGS_threads - 1;
581
583 {
584
585
586
587
588 std::unique_ptr<FrameGenerator> singleton_generator;
589 if (FLAGS_gpu) {
591 }
592
593 tg.
batch(frame_count, [&](
int i) {
594
595
596 i = frame_count - 1 -
i;
597
598 const auto start = std::chrono::steady_clock::now();
599 thread_local static auto* anim =
601 .setResourceProvider(rp)
602 .setPrecompInterceptor(precomp_interceptor)
603 .make(
static_cast<const char*
>(
data->data()),
data->size())
604 .release();
605 thread_local static auto*
gen = singleton_generator
606 ? singleton_generator.get()
608
610 anim->seekFrame(frame0 +
i * fps_scale);
612 } else {
614 }
615
616 frames_ms[
i] = ms_since(
start);
617 });
618 }
619
620 sink->finalize(fps);
622
623
624 std::sort(frames_ms.begin(), frames_ms.end());
625 double sum = std::accumulate(frames_ms.begin(), frames_ms.end(), 0);
626 printf(
"Frame time stats: min %gms, med %gms, avg %gms, max %gms, sum %gms\n",
627 frames_ms[0], frames_ms[frame_count/2], sum/frame_count, frames_ms.back(), sum);
628
629 return 0;
630}
void SK_SPI SkDebugf(const char format[],...) SK_PRINTF_LIKE(1
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)
bool sk_mkdir(const char *path)
static std::vector< SkPDFIndirectReference > sort(const THashSet< SkPDFIndirectReference > &src)
static constexpr const T & SkTPin(const T &x, const T &lo, const T &hi)
constexpr size_t SkToSizeT(S x)
static void Parse(int argc, const char *const *argv)
static sk_sp< SkData > MakeFromFileName(const char path[])
static SkMatrix RectToRect(const SkRect &src, const SkRect &dst, ScaleToFit mode=kFill_ScaleToFit)
@ kCenter_ScaleToFit
scales and aligns to center
static SkString Dirname(const char *fullPath)
void batch(int N, std::function< void(int)> fn)
static sk_sp< CachingResourceProvider > Make(sk_sp< ResourceProvider > rp)
static sk_sp< DataURIResourceProviderProxy > Make(sk_sp< ResourceProvider > rp, ImageDecodeStrategy=ImageDecodeStrategy::kLazyDecode, sk_sp< const SkFontMgr > fontMgr=nullptr)
static sk_sp< FileResourceProvider > Make(SkString base_dir, ImageDecodeStrategy=ImageDecodeStrategy::kLazyDecode)
sk_sp< SkFontMgr > fontMgr
void SK_API Register(Decoder d)
constexpr SkCodecs::Decoder Decoder()
SK_API sk_sp< SkDocument > Make(SkWStream *dst, const SkSerialProcs *=nullptr, std::function< void(const SkPicture *)> onEndPage=nullptr)
constexpr SkCodecs::Decoder Decoder()
std::string printf(const char *fmt,...) SK_PRINTF_LIKE(1
sk_sp< Factory > BestAvailable()
constexpr SkCodecs::Decoder Decoder()
DlVertices::Builder Builder
static SkString fmt(SkColor4f c)
static SkRect MakeIWH(int w, int h)
static constexpr SkRect MakeSize(const SkSize &size)
std::shared_ptr< const fml::Mapping > data