add -f mp4 to skottie_tool
This runs way faster than skottie2movie, even with Mike's patch.
We could probably ditch skottie2movie with this CL and one adding --gpu?
Change-Id: I41376c2cd636eb75a3a6d2aaa75bef48211a1021
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/247377
Reviewed-by: Florin Malita <fmalita@chromium.org>
Commit-Queue: Mike Klein <mtklein@google.com>
diff --git a/modules/skottie/BUILD.gn b/modules/skottie/BUILD.gn
index c9703cb..93893ee 100644
--- a/modules/skottie/BUILD.gn
+++ b/modules/skottie/BUILD.gn
@@ -110,6 +110,10 @@
"../..:flags",
"../..:skia",
]
+ if (skia_use_ffmpeg) {
+ defines = [ "HAVE_VIDEO_ENCODER" ]
+ deps += [ "../..:video_decoder" ]
+ }
public_deps = [
":skottie",
diff --git a/modules/skottie/src/SkottieTool.cpp b/modules/skottie/src/SkottieTool.cpp
index 268ac92..4f516a7 100644
--- a/modules/skottie/src/SkottieTool.cpp
+++ b/modules/skottie/src/SkottieTool.cpp
@@ -25,9 +25,16 @@
#include <numeric>
#include <vector>
+#if defined(HAVE_VIDEO_ENCODER)
+ #include "experimental/ffmpeg/SkVideoEncoder.h"
+ const char* formats_help = "Output format (png, skp, mp4, or null)";
+#else
+ const char* formats_help = "Output format (png, skp, or null)";
+#endif
+
static DEFINE_string2(input , i, nullptr, "Input .json file.");
static DEFINE_string2(writePath, w, nullptr, "Output directory. Frames are names [0-9]{6}.png.");
-static DEFINE_string2(format , f, "png" , "Output format (png, skp or null)");
+static DEFINE_string2(format , f, "png" , formats_help);
static DEFINE_double(t0, 0, "Timeline start [0..1].");
static DEFINE_double(t1, 1, "Timeline stop [0..1].");
@@ -166,6 +173,29 @@
const sk_sp<SkSurface> fSurface;
};
+static std::vector<SkBitmap> gMP4Frames;
+
+struct MP4Sink final : public Sink {
+ explicit MP4Sink(const SkMatrix& scale_matrix)
+ : fSurface(SkSurface::MakeRasterN32Premul(FLAGS_width, FLAGS_height)) {
+ fSurface->getCanvas()->concat(scale_matrix);
+ }
+
+ SkCanvas* beginFrame(size_t) override {
+ SkCanvas* canvas = fSurface->getCanvas();
+ canvas->clear(SK_ColorTRANSPARENT);
+ return canvas;
+ }
+
+ bool endFrame(size_t i) override {
+ // SkVideoEncoder wants RGBA 8888 frames. (N32 may be RGBA 8888 or BGRA 8888.)
+ gMP4Frames[i].allocPixels(fSurface->imageInfo().makeColorType(kRGBA_8888_SkColorType));
+ return fSurface->readPixels(gMP4Frames[i].pixmap(), 0,0);
+ }
+
+ const sk_sp<SkSurface> fSurface;
+};
+
class Logger final : public skottie::Logger {
public:
struct LogEntry {
@@ -203,6 +233,7 @@
if (0 == strcmp(fmt, "png")) return PNGSink::Make(scale_matrix);
if (0 == strcmp(fmt, "skp")) return SKPSink::Make(scale_matrix);
if (0 == strcmp(fmt, "null")) return NullSink::Make(scale_matrix);
+ if (0 == strcmp(fmt, "mp4")) return skstd::make_unique<MP4Sink>(scale_matrix);
SkDebugf("Unknown format: %s\n", FLAGS_format[0]);
return nullptr;
@@ -227,7 +258,7 @@
return 1;
}
- if (!sk_mkdir(FLAGS_writePath[0])) {
+ if (!FLAGS_format.contains("mp4") && !sk_mkdir(FLAGS_writePath[0])) {
return 1;
}
@@ -266,6 +297,10 @@
const auto frame_count = static_cast<int>((t1 - t0) / dt);
+ if (FLAGS_format.contains("mp4")) {
+ gMP4Frames.resize(frame_count);
+ }
+
SkSpinlock lock;
std::vector<double> frames_ms;
frames_ms.reserve(frame_count);
@@ -305,5 +340,19 @@
double sum = std::accumulate(frames_ms.begin(), frames_ms.end(), 0);
SkDebugf("frame time min %gms, med %gms, avg %gms, max %gms, sum %gms\n",
frames_ms[0], frames_ms[frame_count/2], sum/frame_count, frames_ms.back(), sum);
+
+#if defined(HAVE_VIDEO_ENCODER)
+ if (FLAGS_format.contains("mp4")) {
+ SkVideoEncoder enc;
+ enc.beginRecording({FLAGS_width, FLAGS_height}, FLAGS_fps);
+ for (const SkBitmap& frame : gMP4Frames) {
+ enc.addFrame(frame.pixmap());
+ }
+ sk_sp<SkData> mp4 = enc.endRecording();
+
+ SkFILEWStream{FLAGS_writePath[0]}
+ .write(mp4->data(), mp4->size());
+ }
+#endif
return 0;
}