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