[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>
This commit is contained in:
Florin Malita 2019-10-09 16:03:35 -04:00 committed by Skia Commit-Bot
parent 232e3301c7
commit 10e5257ec9
4 changed files with 26 additions and 22 deletions

View File

@ -231,10 +231,9 @@ bool SkVideoEncoder::beginRecording(SkISize dim, int fps) {
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 @@ bool SkVideoEncoder::beginRecording(SkISize dim, int fps) {
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 @@ bool SkVideoEncoder::addFrame(const SkPixmap& pm) {
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;

View File

@ -28,21 +28,15 @@ public:
~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&);

View File

@ -173,7 +173,7 @@ private:
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 @@ struct MP4Sink final : public Sink {
}
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 @@ int main(int argc, char** argv) {
#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();

View File

@ -100,11 +100,14 @@ int main(int argc, char** argv) {
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) {