swscale_unscaled.c 49.4 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
/*
 * Copyright (C) 2001-2003 Michael Niedermayer <michaelni@gmx.at>
 *
 * This file is part of Libav.
 *
 * Libav is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * Libav is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with Libav; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 */

#include <inttypes.h>
#include <string.h>
#include <math.h>
#include <stdio.h>
#include "config.h"
#include <assert.h>
#include "swscale.h"
#include "swscale_internal.h"
#include "rgb2rgb.h"
#include "libavutil/intreadwrite.h"
#include "libavutil/cpu.h"
#include "libavutil/avutil.h"
#include "libavutil/mathematics.h"
#include "libavutil/bswap.h"
#include "libavutil/pixdesc.h"

37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78
DECLARE_ALIGNED(8, const uint8_t, dither_8x8_1)[8][8] = {
    {   0,  1,  0,  1,  0,  1,  0,  1,},
    {   1,  0,  1,  0,  1,  0,  1,  0,},
    {   0,  1,  0,  1,  0,  1,  0,  1,},
    {   1,  0,  1,  0,  1,  0,  1,  0,},
    {   0,  1,  0,  1,  0,  1,  0,  1,},
    {   1,  0,  1,  0,  1,  0,  1,  0,},
    {   0,  1,  0,  1,  0,  1,  0,  1,},
    {   1,  0,  1,  0,  1,  0,  1,  0,},
};
DECLARE_ALIGNED(8, const uint8_t, dither_8x8_3)[8][8] = {
    {   1,  2,  1,  2,  1,  2,  1,  2,},
    {   3,  0,  3,  0,  3,  0,  3,  0,},
    {   1,  2,  1,  2,  1,  2,  1,  2,},
    {   3,  0,  3,  0,  3,  0,  3,  0,},
    {   1,  2,  1,  2,  1,  2,  1,  2,},
    {   3,  0,  3,  0,  3,  0,  3,  0,},
    {   1,  2,  1,  2,  1,  2,  1,  2,},
    {   3,  0,  3,  0,  3,  0,  3,  0,},
};
DECLARE_ALIGNED(8, const uint8_t, dither_8x8_64)[8][8] = {
    {  18, 34, 30, 46, 17, 33, 29, 45,},
    {  50,  2, 62, 14, 49,  1, 61, 13,},
    {  26, 42, 22, 38, 25, 41, 21, 37,},
    {  58, 10, 54,  6, 57,  9, 53,  5,},
    {  16, 32, 28, 44, 19, 35, 31, 47,},
    {  48,  0, 60, 12, 51,  3, 63, 15,},
    {  24, 40, 20, 36, 27, 43, 23, 39,},
    {  56,  8, 52,  4, 59, 11, 55,  7,},
};
extern const uint8_t dither_8x8_128[8][8];
DECLARE_ALIGNED(8, const uint8_t, dither_8x8_256)[8][8] = {
    {  72, 136, 120, 184,  68, 132, 116, 180,},
    { 200,   8, 248,  56, 196,   4, 244,  52,},
    { 104, 168,  88, 152, 100, 164,  84, 148,},
    { 232,  40, 216,  24, 228,  36, 212,  20,},
    {  64, 128, 102, 176,  76, 140, 124, 188,},
    { 192,   0, 240,  48, 204,  12, 252,  60,},
    {  96, 160,  80, 144, 108, 172,  92, 156,},
    { 224,  32, 208,  16, 236,  44, 220,  28,},
};

79
#define RGB2YUV_SHIFT 15
80 81 82 83 84 85 86 87 88 89 90 91
#define BY ( (int) (0.114 * 219 / 255 * (1 << RGB2YUV_SHIFT) + 0.5))
#define BV (-(int) (0.081 * 224 / 255 * (1 << RGB2YUV_SHIFT) + 0.5))
#define BU ( (int) (0.500 * 224 / 255 * (1 << RGB2YUV_SHIFT) + 0.5))
#define GY ( (int) (0.587 * 219 / 255 * (1 << RGB2YUV_SHIFT) + 0.5))
#define GV (-(int) (0.419 * 224 / 255 * (1 << RGB2YUV_SHIFT) + 0.5))
#define GU (-(int) (0.331 * 224 / 255 * (1 << RGB2YUV_SHIFT) + 0.5))
#define RY ( (int) (0.299 * 219 / 255 * (1 << RGB2YUV_SHIFT) + 0.5))
#define RV ( (int) (0.500 * 224 / 255 * (1 << RGB2YUV_SHIFT) + 0.5))
#define RU (-(int) (0.169 * 224 / 255 * (1 << RGB2YUV_SHIFT) + 0.5))

static void fillPlane(uint8_t *plane, int stride, int width, int height, int y,
                      uint8_t val)
92 93
{
    int i;
94 95
    uint8_t *ptr = plane + stride * y;
    for (i = 0; i < height; i++) {
96 97 98 99 100
        memset(ptr, val, width);
        ptr += stride;
    }
}

101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121
static void fill_plane9or10(uint8_t *plane, int stride, int width,
                            int height, int y, uint8_t val,
                            const int dst_depth, const int big_endian)
{
    int i, j;
    uint16_t *dst = (uint16_t *) (plane + stride * y);
#define FILL8TO9_OR_10(wfunc) \
    for (i = 0; i < height; i++) { \
        for (j = 0; j < width; j++) { \
            wfunc(&dst[j], (val << (dst_depth - 8)) |  \
                               (val >> (16 - dst_depth))); \
        } \
        dst += stride / 2; \
    }
    if (big_endian) {
        FILL8TO9_OR_10(AV_WB16);
    } else {
        FILL8TO9_OR_10(AV_WL16);
    }
}

122 123 124 125 126 127 128 129 130
static void copyPlane(const uint8_t *src, int srcStride,
                      int srcSliceY, int srcSliceH, int width,
                      uint8_t *dst, int dstStride)
{
    dst += dstStride * srcSliceY;
    if (dstStride == srcStride && srcStride > 0) {
        memcpy(dst, src, srcSliceH * dstStride);
    } else {
        int i;
131
        for (i = 0; i < srcSliceH; i++) {
132 133 134 135 136 137 138
            memcpy(dst, src, width);
            src += srcStride;
            dst += dstStride;
        }
    }
}

139 140 141 142
static int planarToNv12Wrapper(SwsContext *c, const uint8_t *src[],
                               int srcStride[], int srcSliceY,
                               int srcSliceH, uint8_t *dstParam[],
                               int dstStride[])
143
{
144
    uint8_t *dst = dstParam[1] + dstStride[1] * srcSliceY / 2;
145 146 147 148

    copyPlane(src[0], srcStride[0], srcSliceY, srcSliceH, c->srcW,
              dstParam[0], dstStride[0]);

149
    if (c->dstFormat == AV_PIX_FMT_NV12)
150 151
        interleaveBytes(src[1], src[2], dst, c->srcW / 2, srcSliceH / 2,
                        srcStride[1], srcStride[2], dstStride[0]);
152
    else
153 154
        interleaveBytes(src[2], src[1], dst, c->srcW / 2, srcSliceH / 2,
                        srcStride[2], srcStride[1], dstStride[0]);
155 156 157 158

    return srcSliceH;
}

159 160 161
static int planarToYuy2Wrapper(SwsContext *c, const uint8_t *src[],
                               int srcStride[], int srcSliceY, int srcSliceH,
                               uint8_t *dstParam[], int dstStride[])
162
{
163
    uint8_t *dst = dstParam[0] + dstStride[0] * srcSliceY;
164

165 166
    yv12toyuy2(src[0], src[1], src[2], dst, c->srcW, srcSliceH, srcStride[0],
               srcStride[1], dstStride[0]);
167 168 169 170

    return srcSliceH;
}

171 172 173
static int planarToUyvyWrapper(SwsContext *c, const uint8_t *src[],
                               int srcStride[], int srcSliceY, int srcSliceH,
                               uint8_t *dstParam[], int dstStride[])
174
{
175
    uint8_t *dst = dstParam[0] + dstStride[0] * srcSliceY;
176

177 178
    yv12touyvy(src[0], src[1], src[2], dst, c->srcW, srcSliceH, srcStride[0],
               srcStride[1], dstStride[0]);
179 180 181 182

    return srcSliceH;
}

183 184 185
static int yuv422pToYuy2Wrapper(SwsContext *c, const uint8_t *src[],
                                int srcStride[], int srcSliceY, int srcSliceH,
                                uint8_t *dstParam[], int dstStride[])
186
{
187
    uint8_t *dst = dstParam[0] + dstStride[0] * srcSliceY;
188

189 190
    yuv422ptoyuy2(src[0], src[1], src[2], dst, c->srcW, srcSliceH, srcStride[0],
                  srcStride[1], dstStride[0]);
191 192 193 194

    return srcSliceH;
}

195 196 197
static int yuv422pToUyvyWrapper(SwsContext *c, const uint8_t *src[],
                                int srcStride[], int srcSliceY, int srcSliceH,
                                uint8_t *dstParam[], int dstStride[])
198
{
199
    uint8_t *dst = dstParam[0] + dstStride[0] * srcSliceY;
200

201 202
    yuv422ptouyvy(src[0], src[1], src[2], dst, c->srcW, srcSliceH, srcStride[0],
                  srcStride[1], dstStride[0]);
203 204 205 206

    return srcSliceH;
}

207 208 209
static int yuyvToYuv420Wrapper(SwsContext *c, const uint8_t *src[],
                               int srcStride[], int srcSliceY, int srcSliceH,
                               uint8_t *dstParam[], int dstStride[])
210
{
211 212 213
    uint8_t *ydst = dstParam[0] + dstStride[0] * srcSliceY;
    uint8_t *udst = dstParam[1] + dstStride[1] * srcSliceY / 2;
    uint8_t *vdst = dstParam[2] + dstStride[2] * srcSliceY / 2;
214

215 216
    yuyvtoyuv420(ydst, udst, vdst, src[0], c->srcW, srcSliceH, dstStride[0],
                 dstStride[1], srcStride[0]);
217 218 219 220 221 222 223

    if (dstParam[3])
        fillPlane(dstParam[3], dstStride[3], c->srcW, srcSliceH, srcSliceY, 255);

    return srcSliceH;
}

224 225 226
static int yuyvToYuv422Wrapper(SwsContext *c, const uint8_t *src[],
                               int srcStride[], int srcSliceY, int srcSliceH,
                               uint8_t *dstParam[], int dstStride[])
227
{
228 229 230
    uint8_t *ydst = dstParam[0] + dstStride[0] * srcSliceY;
    uint8_t *udst = dstParam[1] + dstStride[1] * srcSliceY;
    uint8_t *vdst = dstParam[2] + dstStride[2] * srcSliceY;
231

232 233
    yuyvtoyuv422(ydst, udst, vdst, src[0], c->srcW, srcSliceH, dstStride[0],
                 dstStride[1], srcStride[0]);
234 235 236 237

    return srcSliceH;
}

238 239 240
static int uyvyToYuv420Wrapper(SwsContext *c, const uint8_t *src[],
                               int srcStride[], int srcSliceY, int srcSliceH,
                               uint8_t *dstParam[], int dstStride[])
241
{
242 243 244
    uint8_t *ydst = dstParam[0] + dstStride[0] * srcSliceY;
    uint8_t *udst = dstParam[1] + dstStride[1] * srcSliceY / 2;
    uint8_t *vdst = dstParam[2] + dstStride[2] * srcSliceY / 2;
245

246 247
    uyvytoyuv420(ydst, udst, vdst, src[0], c->srcW, srcSliceH, dstStride[0],
                 dstStride[1], srcStride[0]);
248 249 250 251 252 253 254

    if (dstParam[3])
        fillPlane(dstParam[3], dstStride[3], c->srcW, srcSliceH, srcSliceY, 255);

    return srcSliceH;
}

255 256 257
static int uyvyToYuv422Wrapper(SwsContext *c, const uint8_t *src[],
                               int srcStride[], int srcSliceY, int srcSliceH,
                               uint8_t *dstParam[], int dstStride[])
258
{
259 260 261
    uint8_t *ydst = dstParam[0] + dstStride[0] * srcSliceY;
    uint8_t *udst = dstParam[1] + dstStride[1] * srcSliceY;
    uint8_t *vdst = dstParam[2] + dstStride[2] * srcSliceY;
262

263 264
    uyvytoyuv422(ydst, udst, vdst, src[0], c->srcW, srcSliceH, dstStride[0],
                 dstStride[1], srcStride[0]);
265 266 267 268

    return srcSliceH;
}

269 270
static void gray8aToPacked32(const uint8_t *src, uint8_t *dst, int num_pixels,
                             const uint8_t *palette)
271 272
{
    int i;
273 274
    for (i = 0; i < num_pixels; i++)
        ((uint32_t *) dst)[i] = ((const uint32_t *) palette)[src[i << 1]] | (src[(i << 1) + 1] << 24);
275 276
}

277 278
static void gray8aToPacked32_1(const uint8_t *src, uint8_t *dst, int num_pixels,
                               const uint8_t *palette)
279 280 281
{
    int i;

282 283
    for (i = 0; i < num_pixels; i++)
        ((uint32_t *) dst)[i] = ((const uint32_t *) palette)[src[i << 1]] | src[(i << 1) + 1];
284 285
}

286 287
static void gray8aToPacked24(const uint8_t *src, uint8_t *dst, int num_pixels,
                             const uint8_t *palette)
288 289 290
{
    int i;

291
    for (i = 0; i < num_pixels; i++) {
292
        //FIXME slow?
293 294 295 296
        dst[0] = palette[src[i << 1] * 4 + 0];
        dst[1] = palette[src[i << 1] * 4 + 1];
        dst[2] = palette[src[i << 1] * 4 + 2];
        dst += 3;
297 298 299
    }
}

300
static int packed_16bpc_bswap(SwsContext *c, const uint8_t *src[],
301
                              int srcStride[], int srcSliceY, int srcSliceH,
302
                              uint8_t *dst[], int dstStride[])
303 304 305 306
{
    int i, j;
    int srcstr = srcStride[0] >> 1;
    int dststr = dstStride[0] >> 1;
307 308
    uint16_t       *dstPtr =       (uint16_t *) dst[0];
    const uint16_t *srcPtr = (const uint16_t *) src[0];
309
    int min_stride         = FFMIN(srcstr, dststr);
310 311

    for (i = 0; i < srcSliceH; i++) {
312
        for (j = 0; j < min_stride; j++) {
313 314 315 316 317 318 319 320 321
            dstPtr[j] = av_bswap16(srcPtr[j]);
        }
        srcPtr += srcstr;
        dstPtr += dststr;
    }

    return srcSliceH;
}

322 323 324
static int palToRgbWrapper(SwsContext *c, const uint8_t *src[], int srcStride[],
                           int srcSliceY, int srcSliceH, uint8_t *dst[],
                           int dstStride[])
325
{
326 327
    const enum AVPixelFormat srcFormat = c->srcFormat;
    const enum AVPixelFormat dstFormat = c->dstFormat;
328
    void (*conv)(const uint8_t *src, uint8_t *dst, int num_pixels,
329
                 const uint8_t *palette) = NULL;
330
    int i;
331 332
    uint8_t *dstPtr = dst[0] + dstStride[0] * srcSliceY;
    const uint8_t *srcPtr = src[0];
333

334
    if (srcFormat == AV_PIX_FMT_Y400A) {
335
        switch (dstFormat) {
336 337 338 339 340 341
        case AV_PIX_FMT_RGB32  : conv = gray8aToPacked32; break;
        case AV_PIX_FMT_BGR32  : conv = gray8aToPacked32; break;
        case AV_PIX_FMT_BGR32_1: conv = gray8aToPacked32_1; break;
        case AV_PIX_FMT_RGB32_1: conv = gray8aToPacked32_1; break;
        case AV_PIX_FMT_RGB24  : conv = gray8aToPacked24; break;
        case AV_PIX_FMT_BGR24  : conv = gray8aToPacked24; break;
342 343 344
        }
    } else if (usePal(srcFormat)) {
        switch (dstFormat) {
345 346 347 348 349 350
        case AV_PIX_FMT_RGB32  : conv = sws_convertPalette8ToPacked32; break;
        case AV_PIX_FMT_BGR32  : conv = sws_convertPalette8ToPacked32; break;
        case AV_PIX_FMT_BGR32_1: conv = sws_convertPalette8ToPacked32; break;
        case AV_PIX_FMT_RGB32_1: conv = sws_convertPalette8ToPacked32; break;
        case AV_PIX_FMT_RGB24  : conv = sws_convertPalette8ToPacked24; break;
        case AV_PIX_FMT_BGR24  : conv = sws_convertPalette8ToPacked24; break;
351 352 353 354 355 356 357
        }
    }

    if (!conv)
        av_log(c, AV_LOG_ERROR, "internal error %s -> %s converter\n",
               sws_format_name(srcFormat), sws_format_name(dstFormat));
    else {
358
        for (i = 0; i < srcSliceH; i++) {
359
            conv(srcPtr, dstPtr, c->srcW, (uint8_t *) c->pal_rgb);
360 361
            srcPtr += srcStride[0];
            dstPtr += dstStride[0];
362 363 364 365 366 367
        }
    }

    return srcSliceH;
}

368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419
static void gbr24ptopacked24(const uint8_t *src[], int srcStride[],
                             uint8_t *dst, int dstStride, int srcSliceH,
                             int width)
{
    int x, h, i;
    for (h = 0; h < srcSliceH; h++) {
        uint8_t *dest = dst + dstStride * h;
        for (x = 0; x < width; x++) {
            *dest++ = src[0][x];
            *dest++ = src[1][x];
            *dest++ = src[2][x];
        }

        for (i = 0; i < 3; i++)
            src[i] += srcStride[i];
    }
}

static void gbr24ptopacked32(const uint8_t *src[], int srcStride[],
                             uint8_t *dst, int dstStride, int srcSliceH,
                             int alpha_first, int width)
{
    int x, h, i;
    for (h = 0; h < srcSliceH; h++) {
        uint8_t *dest = dst + dstStride * h;

        if (alpha_first) {
            for (x = 0; x < width; x++) {
                *dest++ = 0xff;
                *dest++ = src[0][x];
                *dest++ = src[1][x];
                *dest++ = src[2][x];
            }
        } else {
            for (x = 0; x < width; x++) {
                *dest++ = src[0][x];
                *dest++ = src[1][x];
                *dest++ = src[2][x];
                *dest++ = 0xff;
            }
        }

        for (i = 0; i < 3; i++)
            src[i] += srcStride[i];
    }
}

static int planarRgbToRgbWrapper(SwsContext *c, const uint8_t *src[],
                                 int srcStride[], int srcSliceY, int srcSliceH,
                                 uint8_t *dst[], int dstStride[])
{
    int alpha_first = 0;
420 421 422 423 424
    const uint8_t *src102[] = { src[1], src[0], src[2] };
    const uint8_t *src201[] = { src[2], src[0], src[1] };
    int stride102[] = { srcStride[1], srcStride[0], srcStride[2] };
    int stride201[] = { srcStride[2], srcStride[0], srcStride[1] };

425
    if (c->srcFormat != AV_PIX_FMT_GBRP) {
426 427 428 429 430 431 432
        av_log(c, AV_LOG_ERROR, "unsupported planar RGB conversion %s -> %s\n",
               av_get_pix_fmt_name(c->srcFormat),
               av_get_pix_fmt_name(c->dstFormat));
        return srcSliceH;
    }

    switch (c->dstFormat) {
433
    case AV_PIX_FMT_BGR24:
434
        gbr24ptopacked24(src102, stride102,
435 436 437 438
                         dst[0] + srcSliceY * dstStride[0], dstStride[0],
                         srcSliceH, c->srcW);
        break;

439
    case AV_PIX_FMT_RGB24:
440
        gbr24ptopacked24(src201, stride201,
441 442 443 444
                         dst[0] + srcSliceY * dstStride[0], dstStride[0],
                         srcSliceH, c->srcW);
        break;

445
    case AV_PIX_FMT_ARGB:
446
        alpha_first = 1;
447
    case AV_PIX_FMT_RGBA:
448
        gbr24ptopacked32(src201, stride201,
449 450 451 452
                         dst[0] + srcSliceY * dstStride[0], dstStride[0],
                         srcSliceH, alpha_first, c->srcW);
        break;

453
    case AV_PIX_FMT_ABGR:
454
        alpha_first = 1;
455
    case AV_PIX_FMT_BGRA:
456
        gbr24ptopacked32(src102, stride102,
457 458 459 460 461 462 463 464 465 466 467 468 469 470
                         dst[0] + srcSliceY * dstStride[0], dstStride[0],
                         srcSliceH, alpha_first, c->srcW);
        break;

    default:
        av_log(c, AV_LOG_ERROR,
               "unsupported planar RGB conversion %s -> %s\n",
               av_get_pix_fmt_name(c->srcFormat),
               av_get_pix_fmt_name(c->dstFormat));
    }

    return srcSliceH;
}

471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544
static void packedtogbr24p(const uint8_t *src, int srcStride,
                           uint8_t *dst[], int dstStride[], int srcSliceH,
                           int alpha_first, int inc_size, int width)
{
    uint8_t *dest[3];
    int x, h;

    dest[0] = dst[0];
    dest[1] = dst[1];
    dest[2] = dst[2];

    if (alpha_first)
        src++;

    for (h = 0; h < srcSliceH; h++) {
        for (x = 0; x < width; x++) {
            dest[0][x] = src[0];
            dest[1][x] = src[1];
            dest[2][x] = src[2];

            src += inc_size;
        }
        src     += srcStride - width * inc_size;
        dest[0] += dstStride[0];
        dest[1] += dstStride[1];
        dest[2] += dstStride[2];
    }
}

static int rgbToPlanarRgbWrapper(SwsContext *c, const uint8_t *src[],
                                 int srcStride[], int srcSliceY, int srcSliceH,
                                 uint8_t *dst[], int dstStride[])
{
    int alpha_first = 0;
    int stride102[] = { dstStride[1], dstStride[0], dstStride[2] };
    int stride201[] = { dstStride[2], dstStride[0], dstStride[1] };
    uint8_t *dst102[] = { dst[1] + srcSliceY * dstStride[1],
                          dst[0] + srcSliceY * dstStride[0],
                          dst[2] + srcSliceY * dstStride[2] };
    uint8_t *dst201[] = { dst[2] + srcSliceY * dstStride[2],
                          dst[0] + srcSliceY * dstStride[0],
                          dst[1] + srcSliceY * dstStride[1] };

    switch (c->srcFormat) {
    case PIX_FMT_RGB24:
        packedtogbr24p((const uint8_t *) src[0], srcStride[0], dst201,
                       stride201, srcSliceH, alpha_first, 3, c->srcW);
        break;
    case PIX_FMT_BGR24:
        packedtogbr24p((const uint8_t *) src[0], srcStride[0], dst102,
                       stride102, srcSliceH, alpha_first, 3, c->srcW);
        break;
    case PIX_FMT_ARGB:
        alpha_first = 1;
    case PIX_FMT_RGBA:
        packedtogbr24p((const uint8_t *) src[0], srcStride[0], dst201,
                       stride201, srcSliceH, alpha_first, 4, c->srcW);
        break;
    case PIX_FMT_ABGR:
        alpha_first = 1;
    case PIX_FMT_BGRA:
        packedtogbr24p((const uint8_t *) src[0], srcStride[0], dst102,
                       stride102, srcSliceH, alpha_first, 4, c->srcW);
        break;
    default:
        av_log(c, AV_LOG_ERROR,
               "unsupported planar RGB conversion %s -> %s\n",
               av_get_pix_fmt_name(c->srcFormat),
               av_get_pix_fmt_name(c->dstFormat));
    }

    return srcSliceH;
}

545
#define isRGBA32(x) (            \
546 547 548 549
           (x) == AV_PIX_FMT_ARGB   \
        || (x) == AV_PIX_FMT_RGBA   \
        || (x) == AV_PIX_FMT_BGRA   \
        || (x) == AV_PIX_FMT_ABGR   \
550 551 552
        )

/* {RGB,BGR}{15,16,24,32,32_1} -> {RGB,BGR}{15,16,24,32} */
553 554
typedef void (* rgbConvFn) (const uint8_t *, uint8_t *, int);
static rgbConvFn findRgbConvFn(SwsContext *c)
555
{
556 557
    const enum AVPixelFormat srcFormat = c->srcFormat;
    const enum AVPixelFormat dstFormat = c->dstFormat;
558 559
    const int srcId = c->srcFormatBpp;
    const int dstId = c->dstFormatBpp;
560
    rgbConvFn conv = NULL;
561 562
    const AVPixFmtDescriptor *desc_src = av_pix_fmt_desc_get(srcFormat);
    const AVPixFmtDescriptor *desc_dst = av_pix_fmt_desc_get(dstFormat);
563

564
#define IS_NOT_NE(bpp, desc) \
565
    (((bpp + 7) >> 3) == 2 && \
566
     (!(desc->flags & PIX_FMT_BE) != !HAVE_BIGENDIAN))
567 568

    /* if this is non-native rgb444/555/565, don't handle it here. */
569
    if (IS_NOT_NE(srcId, desc_src) || IS_NOT_NE(dstId, desc_dst))
570
        return NULL;
571

572
#define CONV_IS(src, dst) (srcFormat == AV_PIX_FMT_##src && dstFormat == AV_PIX_FMT_##dst)
573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588

    if (isRGBA32(srcFormat) && isRGBA32(dstFormat)) {
        if (     CONV_IS(ABGR, RGBA)
              || CONV_IS(ARGB, BGRA)
              || CONV_IS(BGRA, ARGB)
              || CONV_IS(RGBA, ABGR)) conv = shuffle_bytes_3210;
        else if (CONV_IS(ABGR, ARGB)
              || CONV_IS(ARGB, ABGR)) conv = shuffle_bytes_0321;
        else if (CONV_IS(ABGR, BGRA)
              || CONV_IS(ARGB, RGBA)) conv = shuffle_bytes_1230;
        else if (CONV_IS(BGRA, RGBA)
              || CONV_IS(RGBA, BGRA)) conv = shuffle_bytes_2103;
        else if (CONV_IS(BGRA, ABGR)
              || CONV_IS(RGBA, ARGB)) conv = shuffle_bytes_3012;
    } else
    /* BGR -> BGR */
589 590
    if ((isBGRinInt(srcFormat) && isBGRinInt(dstFormat)) ||
        (isRGBinInt(srcFormat) && isRGBinInt(dstFormat))) {
591
        switch (srcId | (dstId << 16)) {
Paul B Mahol's avatar
Paul B Mahol committed
592
        case 0x000F000C: conv = rgb12to15; break;
593 594 595 596 597 598 599 600 601 602 603 604
        case 0x000F0010: conv = rgb16to15; break;
        case 0x000F0018: conv = rgb24to15; break;
        case 0x000F0020: conv = rgb32to15; break;
        case 0x0010000F: conv = rgb15to16; break;
        case 0x00100018: conv = rgb24to16; break;
        case 0x00100020: conv = rgb32to16; break;
        case 0x0018000F: conv = rgb15to24; break;
        case 0x00180010: conv = rgb16to24; break;
        case 0x00180020: conv = rgb32to24; break;
        case 0x0020000F: conv = rgb15to32; break;
        case 0x00200010: conv = rgb16to32; break;
        case 0x00200018: conv = rgb24to32; break;
605
        }
606 607
    } else if ((isBGRinInt(srcFormat) && isRGBinInt(dstFormat)) ||
               (isRGBinInt(srcFormat) && isBGRinInt(dstFormat))) {
608
        switch (srcId | (dstId << 16)) {
Paul B Mahol's avatar
Paul B Mahol committed
609
        case 0x000C000C: conv = rgb12tobgr12; break;
610 611 612 613 614 615 616 617 618 619 620 621 622 623 624
        case 0x000F000F: conv = rgb15tobgr15; break;
        case 0x000F0010: conv = rgb16tobgr15; break;
        case 0x000F0018: conv = rgb24tobgr15; break;
        case 0x000F0020: conv = rgb32tobgr15; break;
        case 0x0010000F: conv = rgb15tobgr16; break;
        case 0x00100010: conv = rgb16tobgr16; break;
        case 0x00100018: conv = rgb24tobgr16; break;
        case 0x00100020: conv = rgb32tobgr16; break;
        case 0x0018000F: conv = rgb15tobgr24; break;
        case 0x00180010: conv = rgb16tobgr24; break;
        case 0x00180018: conv = rgb24tobgr24; break;
        case 0x00180020: conv = rgb32tobgr24; break;
        case 0x0020000F: conv = rgb15tobgr32; break;
        case 0x00200010: conv = rgb16tobgr32; break;
        case 0x00200018: conv = rgb24tobgr32; break;
625 626 627
        }
    }

628 629 630 631 632 633 634 635 636
    return conv;
}

/* {RGB,BGR}{15,16,24,32,32_1} -> {RGB,BGR}{15,16,24,32} */
static int rgbToRgbWrapper(SwsContext *c, const uint8_t *src[], int srcStride[],
                           int srcSliceY, int srcSliceH, uint8_t *dst[],
                           int dstStride[])

{
637 638
    const enum AVPixelFormat srcFormat = c->srcFormat;
    const enum AVPixelFormat dstFormat = c->dstFormat;
639 640 641 642
    const int srcBpp = (c->srcFormatBpp + 7) >> 3;
    const int dstBpp = (c->dstFormatBpp + 7) >> 3;
    rgbConvFn conv = findRgbConvFn(c);

643 644 645 646
    if (!conv) {
        av_log(c, AV_LOG_ERROR, "internal error %s -> %s converter\n",
               sws_format_name(srcFormat), sws_format_name(dstFormat));
    } else {
647 648
        const uint8_t *srcPtr = src[0];
              uint8_t *dstPtr = dst[0];
649
        if ((srcFormat == AV_PIX_FMT_RGB32_1 || srcFormat == AV_PIX_FMT_BGR32_1) &&
650
            !isRGBA32(dstFormat))
651 652
            srcPtr += ALT32_CORR;

653
        if ((dstFormat == AV_PIX_FMT_RGB32_1 || dstFormat == AV_PIX_FMT_BGR32_1) &&
654
            !isRGBA32(srcFormat))
655 656
            dstPtr += ALT32_CORR;

657 658 659 660
        if (dstStride[0] * srcBpp == srcStride[0] * dstBpp && srcStride[0] > 0 &&
            !(srcStride[0] % srcBpp))
            conv(srcPtr, dstPtr + dstStride[0] * srcSliceY,
                 srcSliceH * srcStride[0]);
661 662
        else {
            int i;
663
            dstPtr += dstStride[0] * srcSliceY;
664

665 666 667 668
            for (i = 0; i < srcSliceH; i++) {
                conv(srcPtr, dstPtr, c->srcW * srcBpp);
                srcPtr += srcStride[0];
                dstPtr += dstStride[0];
669 670 671 672 673 674
            }
        }
    }
    return srcSliceH;
}

675 676 677
static int bgr24ToYv12Wrapper(SwsContext *c, const uint8_t *src[],
                              int srcStride[], int srcSliceY, int srcSliceH,
                              uint8_t *dst[], int dstStride[])
678 679 680
{
    rgb24toyv12(
        src[0],
681 682 683
        dst[0] +  srcSliceY       * dstStride[0],
        dst[1] + (srcSliceY >> 1) * dstStride[1],
        dst[2] + (srcSliceY >> 1) * dstStride[2],
684 685 686 687 688 689 690
        c->srcW, srcSliceH,
        dstStride[0], dstStride[1], srcStride[0]);
    if (dst[3])
        fillPlane(dst[3], dstStride[3], c->srcW, srcSliceH, srcSliceY, 255);
    return srcSliceH;
}

691 692 693
static int yvu9ToYv12Wrapper(SwsContext *c, const uint8_t *src[],
                             int srcStride[], int srcSliceY, int srcSliceH,
                             uint8_t *dst[], int dstStride[])
694 695 696 697
{
    copyPlane(src[0], srcStride[0], srcSliceY, srcSliceH, c->srcW,
              dst[0], dstStride[0]);

698
    planar2x(src[1], dst[1] + dstStride[1] * (srcSliceY >> 1), c->chrSrcW,
699
             srcSliceH >> 2, srcStride[1], dstStride[1]);
700
    planar2x(src[2], dst[2] + dstStride[2] * (srcSliceY >> 1), c->chrSrcW,
701 702 703 704 705 706 707
             srcSliceH >> 2, srcStride[2], dstStride[2]);
    if (dst[3])
        fillPlane(dst[3], dstStride[3], c->srcW, srcSliceH, srcSliceY, 255);
    return srcSliceH;
}

/* unscaled copy like stuff (assumes nearly identical formats) */
708 709 710
static int packedCopyWrapper(SwsContext *c, const uint8_t *src[],
                             int srcStride[], int srcSliceY, int srcSliceH,
                             uint8_t *dst[], int dstStride[])
711
{
712 713
    if (dstStride[0] == srcStride[0] && srcStride[0] > 0)
        memcpy(dst[0] + dstStride[0] * srcSliceY, src[0], srcSliceH * dstStride[0]);
714 715
    else {
        int i;
716 717 718
        const uint8_t *srcPtr = src[0];
        uint8_t *dstPtr = dst[0] + dstStride[0] * srcSliceY;
        int length = 0;
719 720

        /* universal length finder */
721 722 723 724
        while (length + c->srcW <= FFABS(dstStride[0]) &&
               length + c->srcW <= FFABS(srcStride[0]))
            length += c->srcW;
        assert(length != 0);
725

726
        for (i = 0; i < srcSliceH; i++) {
727
            memcpy(dstPtr, srcPtr, length);
728 729
            srcPtr += srcStride[0];
            dstPtr += dstStride[0];
730 731 732 733 734
        }
    }
    return srcSliceH;
}

735 736 737
#define clip9(x)  av_clip_uintp2(x,  9)
#define clip10(x) av_clip_uintp2(x, 10)
#define DITHER_COPY(dst, dstStride, wfunc, src, srcStride, rfunc, dithers, shift, clip) \
738 739 740
    for (i = 0; i < height; i++) { \
        const uint8_t *dither = dithers[i & 7]; \
        for (j = 0; j < length - 7; j += 8) { \
741 742 743 744 745 746 747 748
            wfunc(&dst[j + 0], clip((rfunc(&src[j + 0]) + dither[0]) >> shift)); \
            wfunc(&dst[j + 1], clip((rfunc(&src[j + 1]) + dither[1]) >> shift)); \
            wfunc(&dst[j + 2], clip((rfunc(&src[j + 2]) + dither[2]) >> shift)); \
            wfunc(&dst[j + 3], clip((rfunc(&src[j + 3]) + dither[3]) >> shift)); \
            wfunc(&dst[j + 4], clip((rfunc(&src[j + 4]) + dither[4]) >> shift)); \
            wfunc(&dst[j + 5], clip((rfunc(&src[j + 5]) + dither[5]) >> shift)); \
            wfunc(&dst[j + 6], clip((rfunc(&src[j + 6]) + dither[6]) >> shift)); \
            wfunc(&dst[j + 7], clip((rfunc(&src[j + 7]) + dither[7]) >> shift)); \
749 750 751 752 753 754 755
        } \
        for (; j < length; j++) \
            wfunc(&dst[j],     (rfunc(&src[j]) + dither[j & 7]) >> shift); \
        dst += dstStride; \
        src += srcStride; \
    }

756 757 758
static int planarCopyWrapper(SwsContext *c, const uint8_t *src[],
                             int srcStride[], int srcSliceY, int srcSliceH,
                             uint8_t *dst[], int dstStride[])
759
{
760 761
    const AVPixFmtDescriptor *desc_src = av_pix_fmt_desc_get(c->srcFormat);
    const AVPixFmtDescriptor *desc_dst = av_pix_fmt_desc_get(c->dstFormat);
762
    int plane, i, j;
763 764 765 766 767 768 769 770 771
    for (plane = 0; plane < 4; plane++) {
        int length = (plane == 0 || plane == 3) ? c->srcW  : -((-c->srcW  ) >> c->chrDstHSubSample);
        int y =      (plane == 0 || plane == 3) ? srcSliceY: -((-srcSliceY) >> c->chrDstVSubSample);
        int height = (plane == 0 || plane == 3) ? srcSliceH: -((-srcSliceH) >> c->chrDstVSubSample);
        const uint8_t *srcPtr = src[plane];
        uint8_t *dstPtr = dst[plane] + dstStride[plane] * y;

        if (!dst[plane])
            continue;
772 773 774
        // ignore palette for GRAY8
        if (plane == 1 && !dst[2]) continue;
        if (!src[plane] || (plane == 1 && !src[2])) {
775
            int val = (plane == 3) ? 255 : 128;
776 777
            if (is16BPS(c->dstFormat))
                length *= 2;
778 779 780 781 782 783 784 785
            if (is9_OR_10BPS(c->dstFormat)) {
                fill_plane9or10(dst[plane], dstStride[plane],
                                length, height, y, val,
                                desc_dst->comp[plane].depth_minus1 + 1,
                                isBE(c->dstFormat));
            } else
                fillPlane(dst[plane], dstStride[plane], length, height, y,
                          val);
786
        } else {
787
            if (is9_OR_10BPS(c->srcFormat)) {
788 789
                const int src_depth = desc_src->comp[plane].depth_minus1 + 1;
                const int dst_depth = desc_dst->comp[plane].depth_minus1 + 1;
790
                const uint16_t *srcPtr2 = (const uint16_t *) srcPtr;
791 792

                if (is16BPS(c->dstFormat)) {
793
                    uint16_t *dstPtr2 = (uint16_t *) dstPtr;
794 795 796 797
#define COPY9_OR_10TO16(rfunc, wfunc) \
                    for (i = 0; i < height; i++) { \
                        for (j = 0; j < length; j++) { \
                            int srcpx = rfunc(&srcPtr2[j]); \
798
                            wfunc(&dstPtr2[j], (srcpx << (16 - src_depth)) | (srcpx >> (2 * src_depth - 16))); \
799
                        } \
800 801
                        dstPtr2 += dstStride[plane] / 2; \
                        srcPtr2 += srcStride[plane] / 2; \
802 803 804 805 806 807 808 809 810 811 812 813 814 815 816
                    }
                    if (isBE(c->dstFormat)) {
                        if (isBE(c->srcFormat)) {
                            COPY9_OR_10TO16(AV_RB16, AV_WB16);
                        } else {
                            COPY9_OR_10TO16(AV_RL16, AV_WB16);
                        }
                    } else {
                        if (isBE(c->srcFormat)) {
                            COPY9_OR_10TO16(AV_RB16, AV_WL16);
                        } else {
                            COPY9_OR_10TO16(AV_RL16, AV_WL16);
                        }
                    }
                } else if (is9_OR_10BPS(c->dstFormat)) {
817
                    uint16_t *dstPtr2 = (uint16_t *) dstPtr;
818 819 820 821 822
#define COPY9_OR_10TO9_OR_10(loop) \
                    for (i = 0; i < height; i++) { \
                        for (j = 0; j < length; j++) { \
                            loop; \
                        } \
823 824
                        dstPtr2 += dstStride[plane] / 2; \
                        srcPtr2 += srcStride[plane] / 2; \
825 826 827 828 829 830
                    }
#define COPY9_OR_10TO9_OR_10_2(rfunc, wfunc) \
                    if (dst_depth > src_depth) { \
                        COPY9_OR_10TO9_OR_10(int srcpx = rfunc(&srcPtr2[j]); \
                            wfunc(&dstPtr2[j], (srcpx << 1) | (srcpx >> 9))); \
                    } else if (dst_depth < src_depth) { \
831 832
                        DITHER_COPY(dstPtr2, dstStride[plane] / 2, wfunc, \
                                    srcPtr2, srcStride[plane] / 2, rfunc, \
833
                                    dither_8x8_1, 1, clip9); \
834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850
                    } else { \
                        COPY9_OR_10TO9_OR_10(wfunc(&dstPtr2[j], rfunc(&srcPtr2[j]))); \
                    }
                    if (isBE(c->dstFormat)) {
                        if (isBE(c->srcFormat)) {
                            COPY9_OR_10TO9_OR_10_2(AV_RB16, AV_WB16);
                        } else {
                            COPY9_OR_10TO9_OR_10_2(AV_RL16, AV_WB16);
                        }
                    } else {
                        if (isBE(c->srcFormat)) {
                            COPY9_OR_10TO9_OR_10_2(AV_RB16, AV_WL16);
                        } else {
                            COPY9_OR_10TO9_OR_10_2(AV_RL16, AV_WL16);
                        }
                    }
                } else {
851
#define W8(a, b) { *(a) = (b); }
852
#define COPY9_OR_10TO8(rfunc) \
853 854
                    if (src_depth == 9) { \
                        DITHER_COPY(dstPtr,  dstStride[plane],   W8, \
855
                                    srcPtr2, srcStride[plane] / 2, rfunc, \
856
                                    dither_8x8_1, 1, av_clip_uint8); \
857 858
                    } else { \
                        DITHER_COPY(dstPtr,  dstStride[plane],   W8, \
859
                                    srcPtr2, srcStride[plane] / 2, rfunc, \
860
                                    dither_8x8_3, 2, av_clip_uint8); \
861 862 863 864 865 866 867
                    }
                    if (isBE(c->srcFormat)) {
                        COPY9_OR_10TO8(AV_RB16);
                    } else {
                        COPY9_OR_10TO8(AV_RL16);
                    }
                }
868
            } else if (is9_OR_10BPS(c->dstFormat)) {
869
                const int dst_depth = desc_dst->comp[plane].depth_minus1 + 1;
870
                uint16_t *dstPtr2 = (uint16_t *) dstPtr;
871 872

                if (is16BPS(c->srcFormat)) {
873
                    const uint16_t *srcPtr2 = (const uint16_t *) srcPtr;
874
#define COPY16TO9_OR_10(rfunc, wfunc) \
875
                    if (dst_depth == 9) { \
876 877
                        DITHER_COPY(dstPtr2, dstStride[plane] / 2, wfunc, \
                                    srcPtr2, srcStride[plane] / 2, rfunc, \
878
                                    dither_8x8_128, 7, clip9); \
879
                    } else { \
880 881
                        DITHER_COPY(dstPtr2, dstStride[plane] / 2, wfunc, \
                                    srcPtr2, srcStride[plane] / 2, rfunc, \
882
                                    dither_8x8_64, 6, clip10); \
883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901
                    }
                    if (isBE(c->dstFormat)) {
                        if (isBE(c->srcFormat)) {
                            COPY16TO9_OR_10(AV_RB16, AV_WB16);
                        } else {
                            COPY16TO9_OR_10(AV_RL16, AV_WB16);
                        }
                    } else {
                        if (isBE(c->srcFormat)) {
                            COPY16TO9_OR_10(AV_RB16, AV_WL16);
                        } else {
                            COPY16TO9_OR_10(AV_RL16, AV_WL16);
                        }
                    }
                } else /* 8bit */ {
#define COPY8TO9_OR_10(wfunc) \
                    for (i = 0; i < height; i++) { \
                        for (j = 0; j < length; j++) { \
                            const int srcpx = srcPtr[j]; \
902
                            wfunc(&dstPtr2[j], (srcpx << (dst_depth - 8)) | (srcpx >> (16 - dst_depth))); \
903
                        } \
904
                        dstPtr2 += dstStride[plane] / 2; \
905 906 907 908 909 910 911 912
                        srcPtr  += srcStride[plane]; \
                    }
                    if (isBE(c->dstFormat)) {
                        COPY8TO9_OR_10(AV_WB16);
                    } else {
                        COPY8TO9_OR_10(AV_WL16);
                    }
                }
913 914
            } else if (is16BPS(c->srcFormat) && !is16BPS(c->dstFormat)) {
                const uint16_t *srcPtr2 = (const uint16_t *) srcPtr;
915 916
#define COPY16TO8(rfunc) \
                    DITHER_COPY(dstPtr,  dstStride[plane],   W8, \
917
                                srcPtr2, srcStride[plane] / 2, rfunc, \
918
                                dither_8x8_256, 8, av_clip_uint8);
919 920 921 922
                if (isBE(c->srcFormat)) {
                    COPY16TO8(AV_RB16);
                } else {
                    COPY16TO8(AV_RL16);
923
                }
924 925 926 927 928
            } else if (!is16BPS(c->srcFormat) && is16BPS(c->dstFormat)) {
                for (i = 0; i < height; i++) {
                    for (j = 0; j < length; j++) {
                        dstPtr[ j << 1     ] = srcPtr[j];
                        dstPtr[(j << 1) + 1] = srcPtr[j];
929
                    }
930 931
                    srcPtr += srcStride[plane];
                    dstPtr += dstStride[plane];
932
                }
933 934 935 936 937 938 939 940
            } else if (is16BPS(c->srcFormat) && is16BPS(c->dstFormat) &&
                      isBE(c->srcFormat) != isBE(c->dstFormat)) {

                for (i = 0; i < height; i++) {
                    for (j = 0; j < length; j++)
                        ((uint16_t *) dstPtr)[j] = av_bswap16(((const uint16_t *) srcPtr)[j]);
                    srcPtr += srcStride[plane];
                    dstPtr += dstStride[plane];
941 942 943
                }
            } else if (dstStride[plane] == srcStride[plane] &&
                       srcStride[plane] > 0 && srcStride[plane] == length) {
944 945
                memcpy(dst[plane] + dstStride[plane] * y, src[plane],
                       height * dstStride[plane]);
946
            } else {
947 948
                if (is16BPS(c->srcFormat) && is16BPS(c->dstFormat))
                    length *= 2;
949
                else if (!desc_src->comp[0].depth_minus1)
950
                    length >>= 3; // monowhite/black
951
                for (i = 0; i < height; i++) {
952
                    memcpy(dstPtr, srcPtr, length);
953 954
                    srcPtr += srcStride[plane];
                    dstPtr += dstStride[plane];
955 956 957 958 959 960 961
                }
            }
        }
    }
    return srcSliceH;
}

962 963 964 965 966 967

#define IS_DIFFERENT_ENDIANESS(src_fmt, dst_fmt, pix_fmt)          \
    ((src_fmt == pix_fmt ## BE && dst_fmt == pix_fmt ## LE) ||     \
     (src_fmt == pix_fmt ## LE && dst_fmt == pix_fmt ## BE))


968 969
void ff_get_unscaled_swscale(SwsContext *c)
{
970 971
    const enum AVPixelFormat srcFormat = c->srcFormat;
    const enum AVPixelFormat dstFormat = c->dstFormat;
972 973 974 975
    const int flags = c->flags;
    const int dstH = c->dstH;
    int needsDither;

976 977 978
    needsDither = isAnyRGB(dstFormat) &&
            c->dstFormatBpp < 24 &&
           (c->dstFormatBpp < c->srcFormatBpp || (!isAnyRGB(srcFormat)));
979 980

    /* yv12_to_nv12 */
981 982
    if ((srcFormat == AV_PIX_FMT_YUV420P || srcFormat == AV_PIX_FMT_YUVA420P) &&
        (dstFormat == AV_PIX_FMT_NV12 || dstFormat == AV_PIX_FMT_NV21)) {
983
        c->swScale = planarToNv12Wrapper;
984 985
    }
    /* yuv2bgr */
986 987
    if ((srcFormat == AV_PIX_FMT_YUV420P || srcFormat == AV_PIX_FMT_YUV422P ||
         srcFormat == AV_PIX_FMT_YUVA420P) && isAnyRGB(dstFormat) &&
988 989
        !(flags & SWS_ACCURATE_RND) && !(dstH & 1)) {
        c->swScale = ff_yuv2rgb_get_func_ptr(c);
990 991
    }

992 993
    if (srcFormat == AV_PIX_FMT_YUV410P &&
        (dstFormat == AV_PIX_FMT_YUV420P || dstFormat == AV_PIX_FMT_YUVA420P) &&
994 995
        !(flags & SWS_BITEXACT)) {
        c->swScale = yvu9ToYv12Wrapper;
Ronald S. Bultje's avatar