[SkVideoEncoder] Allow clients to control the color type
Change-Id: If57514c9e7e8d0a417eb9388873bbb348fc49076
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/247384
Commit-Queue: Mike Klein <mtklein@google.com>
Reviewed-by: Mike Klein <mtklein@google.com>
diff --git a/experimental/ffmpeg/SkVideoEncoder.cpp b/experimental/ffmpeg/SkVideoEncoder.cpp
index 96daeb6..358f5a5 100644
--- a/experimental/ffmpeg/SkVideoEncoder.cpp
+++ b/experimental/ffmpeg/SkVideoEncoder.cpp
@@ -231,10 +231,9 @@
return false;
}
- // need opaque and bgra to efficiently use libyuv / convert-to-yuv-420
SkAlphaType alphaType = kOpaque_SkAlphaType;
sk_sp<SkColorSpace> cs = nullptr; // should we use this?
- fInfo = SkImageInfo::Make(dim, kRGBA_8888_SkColorType, alphaType, cs);
+ fInfo = SkImageInfo::MakeN32(dim.width(), dim.height(), alphaType, cs);
if (!this->init(fps)) {
return false;
}
@@ -242,14 +241,15 @@
fCurrentPTS = 0;
fDeltaPTS = 1;
- SkASSERT(sws_isSupportedInput(AV_PIX_FMT_RGBA) > 0);
+ const auto fmt = kN32_SkColorType == kRGBA_8888_SkColorType ? AV_PIX_FMT_RGBA : AV_PIX_FMT_BGRA;
+ SkASSERT(sws_isSupportedInput(fmt) > 0);
SkASSERT(sws_isSupportedOutput(AV_PIX_FMT_YUV420P) > 0);
// sws_getCachedContext takes in either null or a previous ctx. It returns either a new ctx,
// or the same as the input if it is compatible with the inputs. Thus we never have to
// explicitly release our ctx until the destructor, since sws_getCachedContext takes care
// of freeing the old as needed if/when it returns a new one.
fSWScaleCtx = sws_getCachedContext(fSWScaleCtx,
- dim.width(), dim.height(), AV_PIX_FMT_RGBA,
+ dim.width(), dim.height(), fmt,
dim.width(), dim.height(), AV_PIX_FMT_YUV420P,
SWS_FAST_BILINEAR, nullptr, nullptr, nullptr);
return fSWScaleCtx != nullptr;
@@ -259,6 +259,9 @@
if (!is_valid(pm.dimensions())) {
return false;
}
+ if (pm.info().colorType() != fInfo.colorType()) {
+ return false;
+ }
/* make sure the frame data is writable */
if (check_err(av_frame_make_writable(fFrame))) {
return false;
diff --git a/experimental/ffmpeg/SkVideoEncoder.h b/experimental/ffmpeg/SkVideoEncoder.h
index 6a35061..62450e4 100644
--- a/experimental/ffmpeg/SkVideoEncoder.h
+++ b/experimental/ffmpeg/SkVideoEncoder.h
@@ -28,21 +28,15 @@
~SkVideoEncoder();
/**
- * Begina a new recording. Balance this (after adding all of your frames) with a call
+ * Begins a new recording. Balance this (after adding all of your frames) with a call
* to endRecording().
*/
bool beginRecording(SkISize, int fps);
/**
- * Returns the preferred ImageInfo for this recording. Only valid if beginRecording() has
- * been called, and endRecording has not been called (yet).
- */
- SkImageInfo preferredInfo() const { return fInfo; }
-
- /**
* If you have your own pixmap, call addFrame(). Note this may fail if it uses an unsupported
- * ColorType or AlphaType, or the dimensions don't match those set in beginRecording.
- * For best results, use the SkImageInfo returned by preferredInfo().
+ * ColorType (requires kN32_SkColorType) or AlphaType, or the dimensions don't match those set
+ * in beginRecording.
*/
bool addFrame(const SkPixmap&);
diff --git a/modules/skottie/src/SkottieTool.cpp b/modules/skottie/src/SkottieTool.cpp
index 4f516a7..483bcfe 100644
--- a/modules/skottie/src/SkottieTool.cpp
+++ b/modules/skottie/src/SkottieTool.cpp
@@ -173,7 +173,7 @@
const sk_sp<SkSurface> fSurface;
};
-static std::vector<SkBitmap> gMP4Frames;
+static std::vector<sk_sp<SkImage>> gMP4Frames;
struct MP4Sink final : public Sink {
explicit MP4Sink(const SkMatrix& scale_matrix)
@@ -188,9 +188,8 @@
}
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);
+ gMP4Frames[i] = fSurface->makeImageSnapshot();
+ return SkToBool(gMP4Frames[i]);
}
const sk_sp<SkSurface> fSurface;
@@ -344,9 +343,14 @@
#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());
+ if (!enc.beginRecording({FLAGS_width, FLAGS_height}, FLAGS_fps)) {
+ SkDEBUGF("Invalid video stream configuration.\n");
+ return -1;
+ }
+ for (const auto& frame : gMP4Frames) {
+ SkPixmap pm;
+ SkAssertResult(frame->peekPixels(&pm));
+ enc.addFrame(pm);
}
sk_sp<SkData> mp4 = enc.endRecording();
diff --git a/tools/skottie2movie.cpp b/tools/skottie2movie.cpp
index 48d5dee..e12ad3c 100644
--- a/tools/skottie2movie.cpp
+++ b/tools/skottie2movie.cpp
@@ -100,11 +100,14 @@
sk_sp<SkSurface> surf;
sk_sp<SkData> data;
+ const auto info = SkImageInfo::MakeN32Premul(dim);
do {
double loop_start = SkTime::GetSecs();
- encoder.beginRecording(dim, fps);
- auto info = encoder.preferredInfo();
+ if (!encoder.beginRecording(dim, fps)) {
+ SkDEBUGF("Invalid video stream configuration.\n");
+ return -1;
+ }
// lazily allocate the surfaces
if (!surf) {