1 /*
2 * Copyright 2019 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8 #include "experimental/ffmpeg/SkVideoDecoder.h"
9 #include "include/core/SkBitmap.h"
10 #include "include/core/SkColorSpace.h"
11 #include "include/core/SkImage.h"
12 #include "include/core/SkStream.h"
13 #include "include/core/SkYUVAPixmaps.h"
14
get_yuvspace(AVColorSpace space)15 static SkYUVColorSpace get_yuvspace(AVColorSpace space) {
16 // this is pretty incomplete -- TODO: look to convert more AVColorSpaces
17 switch (space) {
18 case AVCOL_SPC_RGB: return kIdentity_SkYUVColorSpace;
19 case AVCOL_SPC_BT709: return kRec709_SkYUVColorSpace;
20 case AVCOL_SPC_SMPTE170M:
21 case AVCOL_SPC_SMPTE240M:
22 case AVCOL_SPC_BT470BG: return kRec601_SkYUVColorSpace;
23 default: break;
24 }
25 return kRec709_SkYUVColorSpace;
26 }
27
28 struct av_transfer_characteristics {
29 // if x < beta delta * x
30 // else alpha * (x^gama)
31 float alpha, beta, gamma, delta;
32 };
33
34 // Tables extracted from vf_colorspace.c
35
36 const av_transfer_characteristics gTransfer[AVCOL_TRC_NB] = {
37 [AVCOL_TRC_BT709] = { 1.099, 0.018, 0.45, 4.5 },
38 [AVCOL_TRC_GAMMA22] = { 1.0, 0.0, 1.0 / 2.2, 0.0 },
39 [AVCOL_TRC_GAMMA28] = { 1.0, 0.0, 1.0 / 2.8, 0.0 },
40 [AVCOL_TRC_SMPTE170M] = { 1.099, 0.018, 0.45, 4.5 },
41 [AVCOL_TRC_SMPTE240M] = { 1.1115, 0.0228, 0.45, 4.0 },
42 [AVCOL_TRC_IEC61966_2_1] = { 1.055, 0.0031308, 1.0 / 2.4, 12.92 },
43 [AVCOL_TRC_IEC61966_2_4] = { 1.099, 0.018, 0.45, 4.5 },
44 [AVCOL_TRC_BT2020_10] = { 1.099, 0.018, 0.45, 4.5 },
45 [AVCOL_TRC_BT2020_12] = { 1.0993, 0.0181, 0.45, 4.5 },
46 };
47
compute_transfer(AVColorTransferCharacteristic t)48 static skcms_TransferFunction compute_transfer(AVColorTransferCharacteristic t) {
49 const av_transfer_characteristics* av = &gTransfer[AVCOL_TRC_BT709];
50 if ((unsigned)t < AVCOL_TRC_NB) {
51 av = &gTransfer[t];
52 }
53 if (av->alpha == 0) {
54 av = &gTransfer[AVCOL_TRC_BT709];
55 }
56
57 skcms_TransferFunction linear_to_encoded = {
58 av->gamma, sk_float_pow(av->alpha, 1/av->gamma), 0, av->delta, av->beta, 1 - av->alpha, 0,
59 };
60 skcms_TransferFunction encoded_to_linear;
61 bool success = skcms_TransferFunction_invert(&linear_to_encoded, &encoded_to_linear);
62 SkASSERT(success);
63
64 return encoded_to_linear;
65 }
66
67 enum Whitepoint {
68 WP_D65,
69 WP_C,
70 WP_DCI,
71 WP_E,
72 WP_NB,
73 };
74
75 const SkPoint gWP[WP_NB] = {
76 [WP_D65] = { 0.3127f, 0.3290f },
77 [WP_C] = { 0.3100f, 0.3160f },
78 [WP_DCI] = { 0.3140f, 0.3510f },
79 [WP_E] = { 1/3.0f, 1/3.0f },
80 };
81
82 #define ExpandWP(index) gWP[index].fX, gWP[index].fY
83
84 const SkColorSpacePrimaries gPrimaries[AVCOL_PRI_NB] = {
85 [AVCOL_PRI_BT709] = { 0.640f, 0.330f, 0.300f, 0.600f, 0.150f, 0.060f, ExpandWP(WP_D65) },
86 [AVCOL_PRI_BT470M] = { 0.670f, 0.330f, 0.210f, 0.710f, 0.140f, 0.080f, ExpandWP(WP_C) },
87 [AVCOL_PRI_BT470BG] = { 0.640f, 0.330f, 0.290f, 0.600f, 0.150f, 0.060f, ExpandWP(WP_D65) },
88 [AVCOL_PRI_SMPTE170M] = { 0.630f, 0.340f, 0.310f, 0.595f, 0.155f, 0.070f, ExpandWP(WP_D65) },
89 [AVCOL_PRI_SMPTE240M] = { 0.630f, 0.340f, 0.310f, 0.595f, 0.155f, 0.070f, ExpandWP(WP_D65) },
90 [AVCOL_PRI_SMPTE428] = { 0.735f, 0.265f, 0.274f, 0.718f, 0.167f, 0.009f, ExpandWP(WP_E) },
91 [AVCOL_PRI_SMPTE431] = { 0.680f, 0.320f, 0.265f, 0.690f, 0.150f, 0.060f, ExpandWP(WP_DCI) },
92 [AVCOL_PRI_SMPTE432] = { 0.680f, 0.320f, 0.265f, 0.690f, 0.150f, 0.060f, ExpandWP(WP_D65) },
93 [AVCOL_PRI_FILM] = { 0.681f, 0.319f, 0.243f, 0.692f, 0.145f, 0.049f, ExpandWP(WP_C) },
94 [AVCOL_PRI_BT2020] = { 0.708f, 0.292f, 0.170f, 0.797f, 0.131f, 0.046f, ExpandWP(WP_D65) },
95 [AVCOL_PRI_JEDEC_P22] = { 0.630f, 0.340f, 0.295f, 0.605f, 0.155f, 0.077f, ExpandWP(WP_D65) },
96 };
97
make_colorspace(AVColorPrimaries primaries,AVColorTransferCharacteristic transfer)98 sk_sp<SkColorSpace> make_colorspace(AVColorPrimaries primaries,
99 AVColorTransferCharacteristic transfer) {
100 if (primaries == AVCOL_PRI_BT709 && transfer == AVCOL_TRC_BT709) {
101 return SkColorSpace::MakeSRGB();
102 }
103
104 const SkColorSpacePrimaries* p = &gPrimaries[0];
105 if ((unsigned)primaries < (unsigned)AVCOL_PRI_NB) {
106 p = &gPrimaries[primaries];
107 }
108
109 skcms_Matrix3x3 matrix;
110 p->toXYZD50(&matrix);
111 return SkColorSpace::MakeRGB(compute_transfer(transfer), matrix);
112 }
113
114 // returns true on error (and may dump the particular error message)
check_err(int err,const int silentList[]=nullptr)115 static bool check_err(int err, const int silentList[] = nullptr) {
116 if (err >= 0) {
117 return false;
118 }
119
120 if (silentList) {
121 for (; *silentList; ++silentList) {
122 if (*silentList == err) {
123 return true; // we still report the error, but we don't printf
124 }
125 }
126 }
127
128 char errbuf[128];
129 const char *errbuf_ptr = errbuf;
130
131 if (av_strerror(err, errbuf, sizeof(errbuf)) < 0) {
132 errbuf_ptr = strerror(AVUNERROR(err));
133 }
134 SkDebugf("%s\n", errbuf_ptr);
135 return true;
136 }
137
skstream_read_packet(void * ctx,uint8_t * dstBuffer,int dstSize)138 static int skstream_read_packet(void* ctx, uint8_t* dstBuffer, int dstSize) {
139 SkStream* stream = (SkStream*)ctx;
140 int result = (int)stream->read(dstBuffer, dstSize);
141 if (result == 0) {
142 result = AVERROR_EOF;
143 }
144 return result;
145 }
146
skstream_seek_packet(void * ctx,int64_t pos,int whence)147 static int64_t skstream_seek_packet(void* ctx, int64_t pos, int whence) {
148 SkStream* stream = (SkStream*)ctx;
149 switch (whence) {
150 case SEEK_SET:
151 break;
152 case SEEK_CUR:
153 pos = (int64_t)stream->getPosition() + pos;
154 break;
155 case SEEK_END:
156 pos = (int64_t)stream->getLength() + pos;
157 break;
158 default:
159 return -1;
160 }
161 return stream->seek(SkToSizeT(pos)) ? pos : -1;
162 }
163
make_yuv_420(GrRecordingContext * rContext,int w,int h,uint8_t * const data[],int const strides[],SkYUVColorSpace yuvSpace,sk_sp<SkColorSpace> cs)164 static sk_sp<SkImage> make_yuv_420(GrRecordingContext* rContext,
165 int w, int h,
166 uint8_t* const data[],
167 int const strides[],
168 SkYUVColorSpace yuvSpace,
169 sk_sp<SkColorSpace> cs) {
170 SkYUVAInfo yuvaInfo({w, h},
171 SkYUVAInfo::PlaneConfig::kY_U_V,
172 SkYUVAInfo::Subsampling::k420,
173 yuvSpace);
174 SkPixmap pixmaps[3];
175 pixmaps[0].reset(SkImageInfo::MakeA8(w, h), data[0], strides[0]);
176 w = (w + 1)/2;
177 h = (h + 1)/2;
178 pixmaps[1].reset(SkImageInfo::MakeA8(w, h), data[1], strides[1]);
179 pixmaps[2].reset(SkImageInfo::MakeA8(w, h), data[2], strides[2]);
180 auto yuvaPixmaps = SkYUVAPixmaps::FromExternalPixmaps(yuvaInfo, pixmaps);
181
182 return SkImage::MakeFromYUVAPixmaps(
183 rContext, yuvaPixmaps, GrMipmapped::kNo, false, std::move(cs));
184 }
185
186 // Init with illegal values, so our first compare will fail, forcing us to compute
187 // the skcolorspace.
ConvertedColorSpace()188 SkVideoDecoder::ConvertedColorSpace::ConvertedColorSpace()
189 : fPrimaries(AVCOL_PRI_NB), fTransfer(AVCOL_TRC_NB)
190 {}
191
update(AVColorPrimaries primaries,AVColorTransferCharacteristic transfer)192 void SkVideoDecoder::ConvertedColorSpace::update(AVColorPrimaries primaries,
193 AVColorTransferCharacteristic transfer) {
194 if (fPrimaries != primaries || fTransfer != transfer) {
195 fPrimaries = primaries;
196 fTransfer = transfer;
197 fCS = make_colorspace(primaries, transfer);
198 }
199 }
200
computeTimeStamp(const AVFrame * frame) const201 double SkVideoDecoder::computeTimeStamp(const AVFrame* frame) const {
202 AVRational base = fFormatCtx->streams[fStreamIndex]->time_base;
203 return 1.0 * frame->pts * base.num / base.den;
204 }
205
convertFrame(const AVFrame * frame)206 sk_sp<SkImage> SkVideoDecoder::convertFrame(const AVFrame* frame) {
207 auto yuv_space = get_yuvspace(frame->colorspace);
208
209 // we have a 1-entry cache for converting colorspaces
210 fCSCache.update(frame->color_primaries, frame->color_trc);
211
212 // Are these always true? If so, we don't need to check our "cache" on each frame...
213 SkASSERT(fDecoderCtx->colorspace == frame->colorspace);
214 SkASSERT(fDecoderCtx->color_primaries == frame->color_primaries);
215 SkASSERT(fDecoderCtx->color_trc == frame->color_trc);
216
217 // Is this always true? If so, we might take advantage of it, knowing up-front if we support
218 // the format for the whole stream, in which case we might have to ask ffmpeg to convert it
219 // to something more reasonable (for us)...
220 SkASSERT(fDecoderCtx->pix_fmt == frame->format);
221
222 switch (frame->format) {
223 case AV_PIX_FMT_YUV420P:
224 if (auto image = make_yuv_420(fRecordingContext, frame->width, frame->height,
225 frame->data, frame->linesize, yuv_space, fCSCache.fCS)) {
226 return image;
227 }
228 break;
229 default:
230 break;
231 }
232
233 // General N32 fallback.
234 const auto info = SkImageInfo::MakeN32(frame->width, frame->height,
235 SkAlphaType::kOpaque_SkAlphaType);
236
237 SkBitmap bm;
238 bm.allocPixels(info, info.minRowBytes());
239
240 constexpr auto fmt = SK_PMCOLOR_BYTE_ORDER(R,G,B,A) ? AV_PIX_FMT_RGBA : AV_PIX_FMT_BGRA;
241
242 // TODO: should we cache these?
243 auto* ctx = sws_getContext(frame->width, frame->height, (AVPixelFormat)frame->format,
244 info.width(), info.height(), fmt,
245 SWS_BILINEAR, nullptr, nullptr, nullptr);
246
247 uint8_t* dst[] = { (uint8_t*)bm.pixmap().writable_addr() };
248 int dst_stride[] = { SkToInt(bm.pixmap().rowBytes()) };
249
250 sws_scale(ctx, frame->data, frame->linesize, 0, frame->height, dst, dst_stride);
251
252 sws_freeContext(ctx);
253
254 bm.setImmutable();
255
256 return SkImage::MakeFromBitmap(bm);
257 }
258
nextImage(double * timeStamp)259 sk_sp<SkImage> SkVideoDecoder::nextImage(double* timeStamp) {
260 double defaultTimeStampStorage = 0;
261 if (!timeStamp) {
262 timeStamp = &defaultTimeStampStorage;
263 }
264
265 if (fFormatCtx == nullptr) {
266 return nullptr;
267 }
268
269 if (fMode == kProcessing_Mode) {
270 // We sit in a loop, waiting for the codec to have received enough data (packets)
271 // to have at least one frame available.
272 // Treat non-zero return as EOF (or error, which we will decide is also EOF)
273 while (!av_read_frame(fFormatCtx, &fPacket)) {
274 if (fPacket.stream_index != fStreamIndex) {
275 // got a packet for a stream other than our (video) stream, so continue
276 continue;
277 }
278
279 int ret = avcodec_send_packet(fDecoderCtx, &fPacket);
280 if (ret == AVERROR(EAGAIN)) {
281 // may signal that we have plenty already, encouraging us to call receive_frame
282 // so we don't treat this as an error.
283 ret = 0;
284 }
285 (void)check_err(ret); // we try to continue if there was an error
286
287 int silentList[] = {
288 -35, // Resource temporarily unavailable (need more packets)
289 0,
290 };
291 if (check_err(avcodec_receive_frame(fDecoderCtx, fFrame), silentList)) {
292 // this may be just "needs more input", so we try to continue
293 } else {
294 *timeStamp = this->computeTimeStamp(fFrame);
295 return this->convertFrame(fFrame);
296 }
297 }
298
299 fMode = kDraining_Mode;
300 (void)avcodec_send_packet(fDecoderCtx, nullptr); // signal to start draining
301 }
302 if (fMode == kDraining_Mode) {
303 if (avcodec_receive_frame(fDecoderCtx, fFrame) >= 0) {
304 *timeStamp = this->computeTimeStamp(fFrame);
305 return this->convertFrame(fFrame);
306 }
307 // else we decide we're done
308 fMode = kDone_Mode;
309 }
310 return nullptr;
311 }
312
SkVideoDecoder(GrRecordingContext * rContext)313 SkVideoDecoder::SkVideoDecoder(GrRecordingContext* rContext) : fRecordingContext(rContext) {}
314
~SkVideoDecoder()315 SkVideoDecoder::~SkVideoDecoder() {
316 this->reset();
317 }
318
reset()319 void SkVideoDecoder::reset() {
320 if (fFrame) {
321 av_frame_free(&fFrame);
322 fFrame = nullptr;
323 }
324 if (fDecoderCtx) {
325 avcodec_free_context(&fDecoderCtx);
326 fDecoderCtx = nullptr;
327 }
328 if (fFormatCtx) {
329 avformat_close_input(&fFormatCtx);
330 fFormatCtx = nullptr;
331 }
332 if (fStreamCtx) {
333 av_freep(&fStreamCtx->buffer);
334 avio_context_free(&fStreamCtx);
335 fStreamCtx = nullptr;
336 }
337
338 fStream.reset(nullptr);
339 fStreamIndex = -1;
340 fMode = kDone_Mode;
341 }
342
loadStream(std::unique_ptr<SkStream> stream)343 bool SkVideoDecoder::loadStream(std::unique_ptr<SkStream> stream) {
344 this->reset();
345 if (!stream) {
346 return false;
347 }
348
349 int bufferSize = 4 * 1024;
350 uint8_t* buffer = (uint8_t*)av_malloc(bufferSize);
351 if (!buffer) {
352 return false;
353 }
354
355 fStream = std::move(stream);
356 fStreamCtx = avio_alloc_context(buffer, bufferSize, 0, fStream.get(),
357 skstream_read_packet, nullptr, skstream_seek_packet);
358 if (!fStreamCtx) {
359 av_freep(buffer);
360 this->reset();
361 return false;
362 }
363
364 fFormatCtx = avformat_alloc_context();
365 if (!fFormatCtx) {
366 this->reset();
367 return false;
368 }
369 fFormatCtx->pb = fStreamCtx;
370
371 int err = avformat_open_input(&fFormatCtx, nullptr, nullptr, nullptr);
372 if (err < 0) {
373 SkDebugf("avformat_open_input failed %d\n", err);
374 return false;
375 }
376
377 const AVCodec* codec;
378 fStreamIndex = av_find_best_stream(fFormatCtx, AVMEDIA_TYPE_VIDEO, -1, -1, &codec, 0);
379 if (fStreamIndex < 0) {
380 SkDebugf("av_find_best_stream failed %d\n", fStreamIndex);
381 this->reset();
382 return false;
383 }
384
385 SkASSERT(codec);
386 fDecoderCtx = avcodec_alloc_context3(codec);
387
388 AVStream* strm = fFormatCtx->streams[fStreamIndex];
389 if ((err = avcodec_parameters_to_context(fDecoderCtx, strm->codecpar)) < 0) {
390 SkDebugf("avcodec_parameters_to_context failed %d\n", err);
391 this->reset();
392 return false;
393 }
394
395 if ((err = avcodec_open2(fDecoderCtx, codec, nullptr)) < 0) {
396 SkDebugf("avcodec_open2 failed %d\n", err);
397 this->reset();
398 return false;
399 }
400
401 fFrame = av_frame_alloc();
402 SkASSERT(fFrame);
403
404 av_init_packet(&fPacket); // is there a "free" call?
405
406 fMode = kProcessing_Mode;
407
408 return true;
409 }
410
dimensions() const411 SkISize SkVideoDecoder::dimensions() const {
412 if (!fFormatCtx) {
413 return {0, 0};
414 }
415
416 AVStream* strm = fFormatCtx->streams[fStreamIndex];
417 return {strm->codecpar->width, strm->codecpar->height};
418 }
419
duration() const420 double SkVideoDecoder::duration() const {
421 if (!fFormatCtx) {
422 return 0;
423 }
424
425 AVStream* strm = fFormatCtx->streams[fStreamIndex];
426 AVRational base = strm->time_base;
427 return 1.0 * strm->duration * base.num / base.den;
428 }
429
rewind()430 bool SkVideoDecoder::rewind() {
431 auto stream = std::move(fStream);
432 this->reset();
433 if (stream) {
434 stream->rewind();
435 }
436 return this->loadStream(std::move(stream));
437 }
438