14#include "libswscale/swscale.h"
24 size_t pos()
const {
return fPos; }
26 size_t size()
const {
return fStorage.size(); }
28 void write(
const void* src,
size_t bytes) {
29 size_t len = fStorage.size();
32 size_t overwrite = std::min(len - fPos, bytes);
34 SkDebugf(
"overwrite %zu bytes at %zu offset with %zu remaining\n", overwrite, fPos, bytes - overwrite);
35 memcpy(&fStorage[fPos], src, overwrite);
37 src = (
const char*)src + overwrite;
42 fStorage.append(bytes, (
const char*)src);
62static bool check_err(
int err,
const int silentList[] =
nullptr) {
68 for (; *silentList; ++silentList) {
69 if (*silentList == err) {
76 const char *errbuf_ptr = errbuf;
78 if (av_strerror(err, errbuf,
sizeof(errbuf)) < 0) {
79 errbuf_ptr = strerror(AVUNERROR(err));
87 stream->write(
buffer, size);
97 pos = (int64_t)stream->pos() +
pos;
100 pos = (int64_t)stream->size() +
pos;
105 if (pos < 0 || pos > (int64_t)stream->size()) {
120 sws_freeContext(fSWScaleCtx);
124void SkVideoEncoder::reset() {
126 av_frame_free(&fFrame);
130 avcodec_free_context(&fEncoderCtx);
131 fEncoderCtx =
nullptr;
134 avformat_free_context(fFormatCtx);
135 fFormatCtx =
nullptr;
138 av_packet_free(&fPacket);
145bool SkVideoEncoder::init(
int fps) {
147 AVPixelFormat pix_fmt = AV_PIX_FMT_YUV420P;
153 int bufferSize = 4 * 1024;
154 uint8_t*
buffer = (uint8_t*)av_malloc(bufferSize);
158 fStreamCtx = avio_alloc_context(
buffer, bufferSize, AVIO_FLAG_WRITE, fWStream.get(),
162 avformat_alloc_output_context2(&fFormatCtx,
nullptr,
"mp4",
nullptr);
164 fFormatCtx->pb = fStreamCtx;
166 const auto* output_format = fFormatCtx->oformat;
168 if (output_format->video_codec == AV_CODEC_ID_NONE) {
171 const auto* codec = avcodec_find_encoder(output_format->video_codec);
174 fStream = avformat_new_stream(fFormatCtx, codec);
176 fStream->id = fFormatCtx->nb_streams-1;
177 fStream->time_base = (AVRational){ 1, fps };
179 fEncoderCtx = avcodec_alloc_context3(codec);
182 fEncoderCtx->codec_id = output_format->video_codec;
183 fEncoderCtx->width = fInfo.
width();
184 fEncoderCtx->height = fInfo.
height();
185 fEncoderCtx->time_base = fStream->time_base;
186 fEncoderCtx->pix_fmt = pix_fmt;
189 if (output_format->flags & AVFMT_GLOBALHEADER) {
190 fEncoderCtx->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;
193 if (
check_err(avcodec_open2(fEncoderCtx, codec,
nullptr))) {
196 fFrame = av_frame_alloc();
198 fFrame->format = pix_fmt;
199 fFrame->width = fEncoderCtx->width;
200 fFrame->height = fEncoderCtx->height;
201 if (
check_err(av_frame_get_buffer(fFrame, 32))) {
205 if (
check_err(avcodec_parameters_from_context(fStream->codecpar, fEncoderCtx))) {
208 if (
check_err(avformat_write_header(fFormatCtx,
nullptr))) {
211 fPacket = av_packet_alloc();
236 if (!this->init(fps)) {
245 SkASSERT(sws_isSupportedOutput(AV_PIX_FMT_YUV420P) > 0);
250 fSWScaleCtx = sws_getCachedContext(fSWScaleCtx,
253 SWS_FAST_BILINEAR,
nullptr,
nullptr,
nullptr);
254 return fSWScaleCtx !=
nullptr;
265 if (
check_err(av_frame_make_writable(fFrame))) {
269 fFrame->pts = fCurrentPTS;
270 fCurrentPTS += fDeltaPTS;
272 const uint8_t* src[] = { (
const uint8_t*)pm.
addr() };
274 sws_scale(fSWScaleCtx, src, strides, 0, fInfo.
height(), fFrame->data, fFrame->linesize);
276 return this->sendFrame(fFrame);
279bool SkVideoEncoder::sendFrame(AVFrame*
frame) {
286 ret = avcodec_receive_packet(fEncoderCtx, fPacket);
287 if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) {
294 av_packet_rescale_ts(fPacket, fEncoderCtx->time_base, fStream->time_base);
295 SkASSERT(fPacket->stream_index == fStream->index);
297 if (
check_err(av_interleaved_write_frame(fFormatCtx, fPacket))) {
330 this->sendFrame(
nullptr);
331 av_write_trailer(fFormatCtx);
@ kOpaque_SkAlphaType
pixel is opaque
@ kRGBA_8888_SkColorType
pixel with 8 bits for red, green, blue, alpha; in 32-bit word
void SK_SPI SkDebugf(const char format[],...) SK_PRINTF_LIKE(1
constexpr size_t SkToSizeT(S x)
constexpr int SkToInt(S x)
static bool check_err(int err, const int silentList[]=nullptr)
static int sk_write_packet(void *ctx, uint8_t *buffer, int size)
static int64_t sk_seek_packet(void *ctx, int64_t pos, int whence)
static bool check_err(int err, const int silentList[]=nullptr)
static bool is_valid(SkISize dim)
void clear(SkColor color)
void restoreToCount(int saveCount)
static sk_sp< SkData > MakeWithCopy(const void *data, size_t length)
const SkImageInfo & info() const
const void * addr() const
SkISize dimensions() const
void write(const void *src, size_t bytes)
sk_sp< SkData > detachAsData()
bool peekPixels(SkPixmap *pixmap)
bool beginRecording(SkISize, int fps)
sk_sp< SkData > endRecording()
bool addFrame(const SkPixmap &)
void reset(T *ptr=nullptr)
static const uint8_t buffer[]
SK_API sk_sp< SkSurface > Raster(const SkImageInfo &imageInfo, size_t rowBytes, const SkSurfaceProps *surfaceProps)
static SkString fmt(SkColor4f c)
constexpr int32_t width() const
constexpr int32_t height() const
static SkImageInfo MakeUnknown()
static SkImageInfo MakeN32(int width, int height, SkAlphaType at)
SkColorType colorType() const