imgconvert.c 78.4 KB
Newer Older
glantau's avatar
glantau committed
1
/*
diego's avatar
diego committed
2
 * Misc image conversion routines
3
 * Copyright (c) 2001, 2002, 2003 Fabrice Bellard
glantau's avatar
glantau committed
4
 *
5 6 7
 * This file is part of FFmpeg.
 *
 * FFmpeg is free software; you can redistribute it and/or
glantau's avatar
glantau committed
8 9
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
10
 * version 2.1 of the License, or (at your option) any later version.
glantau's avatar
glantau committed
11
 *
12
 * FFmpeg is distributed in the hope that it will be useful,
glantau's avatar
glantau committed
13
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
glantau's avatar
glantau committed
14 15
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
glantau's avatar
glantau committed
16
 *
glantau's avatar
glantau committed
17
 * You should have received a copy of the GNU Lesser General Public
18
 * License along with FFmpeg; if not, write to the Free Software
19
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
glantau's avatar
glantau committed
20
 */
michaelni's avatar
michaelni committed
21 22

/**
23
 * @file libavcodec/imgconvert.c
diego's avatar
diego committed
24
 * misc image conversion routines
michaelni's avatar
michaelni committed
25 26
 */

27 28 29 30 31
/* TODO:
 * - write 'ffimg' program to test all the image related stuff
 * - move all api to slice based system
 * - integrate deinterlacing, postprocessing and scaling in the conversion process
 */
michaelni's avatar
michaelni committed
32

glantau's avatar
glantau committed
33
#include "avcodec.h"
34
#include "dsputil.h"
35
#include "colorspace.h"
glantau's avatar
glantau committed
36

37
#if HAVE_MMX
38 39
#include "x86/mmx.h"
#include "x86/dsputil_mmx.h"
michaelni's avatar
michaelni committed
40
#endif
41

42 43 44
#define xglue(x, y) x ## y
#define glue(x, y) xglue(x, y)

45 46 47 48
#define FF_COLOR_RGB      0 /**< RGB color space */
#define FF_COLOR_GRAY     1 /**< gray color space */
#define FF_COLOR_YUV      2 /**< YUV color space. 16 <= Y <= 235, 16 <= U, V <= 240 */
#define FF_COLOR_YUV_JPEG 3 /**< YUV color space. 0 <= Y <= 255, 0 <= U, V <= 255 */
49

50 51 52
#define FF_PIXEL_PLANAR   0 /**< each channel has one component in AVPicture */
#define FF_PIXEL_PACKED   1 /**< only one components containing all the channels */
#define FF_PIXEL_PALETTE  2  /**< one components containing indexes for a palette */
53

54 55
typedef struct PixFmtInfo {
    const char *name;
56 57 58 59 60 61 62
    uint8_t nb_channels;     /**< number of channels (including alpha) */
    uint8_t color_type;      /**< color type (see FF_COLOR_xxx constants) */
    uint8_t pixel_type;      /**< pixel storage type (see FF_PIXEL_xxx constants) */
    uint8_t is_alpha : 1;    /**< true if alpha can be specified */
    uint8_t x_chroma_shift;  /**< X chroma subsampling factor is 2 ^ shift */
    uint8_t y_chroma_shift;  /**< Y chroma subsampling factor is 2 ^ shift */
    uint8_t depth;           /**< bit depth of the color components */
63 64 65
} PixFmtInfo;

/* this table gives more information about formats */
66
static const PixFmtInfo pix_fmt_info[PIX_FMT_NB] = {
67 68
    /* YUV formats */
    [PIX_FMT_YUV420P] = {
69
        .name = "yuv420p",
70
        .nb_channels = 3,
71
        .color_type = FF_COLOR_YUV,
72
        .pixel_type = FF_PIXEL_PLANAR,
73
        .depth = 8,
74
        .x_chroma_shift = 1, .y_chroma_shift = 1,
75 76
    },
    [PIX_FMT_YUV422P] = {
77
        .name = "yuv422p",
78
        .nb_channels = 3,
79
        .color_type = FF_COLOR_YUV,
80
        .pixel_type = FF_PIXEL_PLANAR,
81
        .depth = 8,
82
        .x_chroma_shift = 1, .y_chroma_shift = 0,
83 84
    },
    [PIX_FMT_YUV444P] = {
85
        .name = "yuv444p",
86
        .nb_channels = 3,
87
        .color_type = FF_COLOR_YUV,
88
        .pixel_type = FF_PIXEL_PLANAR,
89
        .depth = 8,
90
        .x_chroma_shift = 0, .y_chroma_shift = 0,
91
    },
92 93
    [PIX_FMT_YUYV422] = {
        .name = "yuyv422",
94
        .nb_channels = 1,
95
        .color_type = FF_COLOR_YUV,
96
        .pixel_type = FF_PIXEL_PACKED,
97
        .depth = 8,
98
        .x_chroma_shift = 1, .y_chroma_shift = 0,
99
    },
100 101 102 103 104 105 106 107
    [PIX_FMT_UYVY422] = {
        .name = "uyvy422",
        .nb_channels = 1,
        .color_type = FF_COLOR_YUV,
        .pixel_type = FF_PIXEL_PACKED,
        .depth = 8,
        .x_chroma_shift = 1, .y_chroma_shift = 0,
    },
108
    [PIX_FMT_YUV410P] = {
109
        .name = "yuv410p",
110
        .nb_channels = 3,
111
        .color_type = FF_COLOR_YUV,
112
        .pixel_type = FF_PIXEL_PLANAR,
113
        .depth = 8,
114
        .x_chroma_shift = 2, .y_chroma_shift = 2,
115 116
    },
    [PIX_FMT_YUV411P] = {
117
        .name = "yuv411p",
118
        .nb_channels = 3,
119
        .color_type = FF_COLOR_YUV,
120
        .pixel_type = FF_PIXEL_PLANAR,
121
        .depth = 8,
122
        .x_chroma_shift = 2, .y_chroma_shift = 0,
123
    },
benoit's avatar
benoit committed
124 125 126 127 128 129 130 131
    [PIX_FMT_YUV440P] = {
        .name = "yuv440p",
        .nb_channels = 3,
        .color_type = FF_COLOR_YUV,
        .pixel_type = FF_PIXEL_PLANAR,
        .depth = 8,
        .x_chroma_shift = 0, .y_chroma_shift = 1,
    },
132

133 134 135 136 137 138 139 140 141 142
    /* YUV formats with alpha plane */
    [PIX_FMT_YUVA420P] = {
        .name = "yuva420p",
        .nb_channels = 4,
        .color_type = FF_COLOR_YUV,
        .pixel_type = FF_PIXEL_PLANAR,
        .depth = 8,
        .x_chroma_shift = 1, .y_chroma_shift = 1,
    },

143 144 145
    /* JPEG YUV */
    [PIX_FMT_YUVJ420P] = {
        .name = "yuvj420p",
146
        .nb_channels = 3,
147
        .color_type = FF_COLOR_YUV_JPEG,
148
        .pixel_type = FF_PIXEL_PLANAR,
149
        .depth = 8,
150
        .x_chroma_shift = 1, .y_chroma_shift = 1,
151 152 153
    },
    [PIX_FMT_YUVJ422P] = {
        .name = "yuvj422p",
154
        .nb_channels = 3,
155
        .color_type = FF_COLOR_YUV_JPEG,
156
        .pixel_type = FF_PIXEL_PLANAR,
157
        .depth = 8,
158
        .x_chroma_shift = 1, .y_chroma_shift = 0,
159 160 161
    },
    [PIX_FMT_YUVJ444P] = {
        .name = "yuvj444p",
162
        .nb_channels = 3,
163
        .color_type = FF_COLOR_YUV_JPEG,
164
        .pixel_type = FF_PIXEL_PLANAR,
165
        .depth = 8,
166
        .x_chroma_shift = 0, .y_chroma_shift = 0,
167
    },
benoit's avatar
benoit committed
168 169 170 171 172 173 174 175
    [PIX_FMT_YUVJ440P] = {
        .name = "yuvj440p",
        .nb_channels = 3,
        .color_type = FF_COLOR_YUV_JPEG,
        .pixel_type = FF_PIXEL_PLANAR,
        .depth = 8,
        .x_chroma_shift = 0, .y_chroma_shift = 1,
    },
176

177 178
    /* RGB formats */
    [PIX_FMT_RGB24] = {
179
        .name = "rgb24",
180
        .nb_channels = 3,
181
        .color_type = FF_COLOR_RGB,
182
        .pixel_type = FF_PIXEL_PACKED,
183
        .depth = 8,
michael's avatar
michael committed
184
        .x_chroma_shift = 0, .y_chroma_shift = 0,
185 186
    },
    [PIX_FMT_BGR24] = {
187
        .name = "bgr24",
188
        .nb_channels = 3,
189
        .color_type = FF_COLOR_RGB,
190
        .pixel_type = FF_PIXEL_PACKED,
191
        .depth = 8,
michael's avatar
michael committed
192
        .x_chroma_shift = 0, .y_chroma_shift = 0,
193
    },
194 195
    [PIX_FMT_RGB32] = {
        .name = "rgb32",
196
        .nb_channels = 4, .is_alpha = 1,
197
        .color_type = FF_COLOR_RGB,
198
        .pixel_type = FF_PIXEL_PACKED,
199
        .depth = 8,
michael's avatar
michael committed
200
        .x_chroma_shift = 0, .y_chroma_shift = 0,
201 202
    },
    [PIX_FMT_RGB565] = {
203
        .name = "rgb565",
204
        .nb_channels = 3,
205
        .color_type = FF_COLOR_RGB,
206
        .pixel_type = FF_PIXEL_PACKED,
207
        .depth = 5,
michael's avatar
michael committed
208
        .x_chroma_shift = 0, .y_chroma_shift = 0,
209 210
    },
    [PIX_FMT_RGB555] = {
211
        .name = "rgb555",
alex's avatar
alex committed
212
        .nb_channels = 3,
213
        .color_type = FF_COLOR_RGB,
214
        .pixel_type = FF_PIXEL_PACKED,
215
        .depth = 5,
michael's avatar
michael committed
216
        .x_chroma_shift = 0, .y_chroma_shift = 0,
217 218 219
    },

    /* gray / mono formats */
kostya's avatar
kostya committed
220 221 222 223 224 225 226 227 228 229 230 231 232 233
    [PIX_FMT_GRAY16BE] = {
        .name = "gray16be",
        .nb_channels = 1,
        .color_type = FF_COLOR_GRAY,
        .pixel_type = FF_PIXEL_PLANAR,
        .depth = 16,
    },
    [PIX_FMT_GRAY16LE] = {
        .name = "gray16le",
        .nb_channels = 1,
        .color_type = FF_COLOR_GRAY,
        .pixel_type = FF_PIXEL_PLANAR,
        .depth = 16,
    },
234
    [PIX_FMT_GRAY8] = {
235
        .name = "gray",
236
        .nb_channels = 1,
237
        .color_type = FF_COLOR_GRAY,
238
        .pixel_type = FF_PIXEL_PLANAR,
239
        .depth = 8,
240 241
    },
    [PIX_FMT_MONOWHITE] = {
242
        .name = "monow",
243
        .nb_channels = 1,
244
        .color_type = FF_COLOR_GRAY,
245
        .pixel_type = FF_PIXEL_PLANAR,
246
        .depth = 1,
247 248
    },
    [PIX_FMT_MONOBLACK] = {
249
        .name = "monob",
250
        .nb_channels = 1,
251
        .color_type = FF_COLOR_GRAY,
252
        .pixel_type = FF_PIXEL_PLANAR,
253
        .depth = 1,
254
    },
255 256 257 258

    /* paletted formats */
    [PIX_FMT_PAL8] = {
        .name = "pal8",
259
        .nb_channels = 4, .is_alpha = 1,
260
        .color_type = FF_COLOR_RGB,
261
        .pixel_type = FF_PIXEL_PALETTE,
262
        .depth = 8,
263
    },
264 265 266 267 268 269
    [PIX_FMT_XVMC_MPEG2_MC] = {
        .name = "xvmcmc",
    },
    [PIX_FMT_XVMC_MPEG2_IDCT] = {
        .name = "xvmcidct",
    },
270 271 272 273 274 275
    [PIX_FMT_VDPAU_MPEG1] = {
        .name = "vdpau_mpeg1",
    },
    [PIX_FMT_VDPAU_MPEG2] = {
        .name = "vdpau_mpeg2",
    },
276 277 278
    [PIX_FMT_VDPAU_H264] = {
        .name = "vdpau_h264",
    },
279 280 281 282 283 284
    [PIX_FMT_VDPAU_WMV3] = {
        .name = "vdpau_wmv3",
    },
    [PIX_FMT_VDPAU_VC1] = {
        .name = "vdpau_vc1",
    },
285 286
    [PIX_FMT_UYYVYY411] = {
        .name = "uyyvyy411",
romansh's avatar
 
romansh committed
287 288 289 290 291 292
        .nb_channels = 1,
        .color_type = FF_COLOR_YUV,
        .pixel_type = FF_PIXEL_PACKED,
        .depth = 8,
        .x_chroma_shift = 2, .y_chroma_shift = 0,
    },
293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310
    [PIX_FMT_BGR32] = {
        .name = "bgr32",
        .nb_channels = 4, .is_alpha = 1,
        .color_type = FF_COLOR_RGB,
        .pixel_type = FF_PIXEL_PACKED,
        .depth = 8,
        .x_chroma_shift = 0, .y_chroma_shift = 0,
    },
    [PIX_FMT_BGR565] = {
        .name = "bgr565",
        .nb_channels = 3,
        .color_type = FF_COLOR_RGB,
        .pixel_type = FF_PIXEL_PACKED,
        .depth = 5,
        .x_chroma_shift = 0, .y_chroma_shift = 0,
    },
    [PIX_FMT_BGR555] = {
        .name = "bgr555",
311
        .nb_channels = 3,
312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 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
        .color_type = FF_COLOR_RGB,
        .pixel_type = FF_PIXEL_PACKED,
        .depth = 5,
        .x_chroma_shift = 0, .y_chroma_shift = 0,
    },
    [PIX_FMT_RGB8] = {
        .name = "rgb8",
        .nb_channels = 1,
        .color_type = FF_COLOR_RGB,
        .pixel_type = FF_PIXEL_PACKED,
        .depth = 8,
        .x_chroma_shift = 0, .y_chroma_shift = 0,
    },
    [PIX_FMT_RGB4] = {
        .name = "rgb4",
        .nb_channels = 1,
        .color_type = FF_COLOR_RGB,
        .pixel_type = FF_PIXEL_PACKED,
        .depth = 4,
        .x_chroma_shift = 0, .y_chroma_shift = 0,
    },
    [PIX_FMT_RGB4_BYTE] = {
        .name = "rgb4_byte",
        .nb_channels = 1,
        .color_type = FF_COLOR_RGB,
        .pixel_type = FF_PIXEL_PACKED,
        .depth = 8,
        .x_chroma_shift = 0, .y_chroma_shift = 0,
    },
    [PIX_FMT_BGR8] = {
        .name = "bgr8",
        .nb_channels = 1,
        .color_type = FF_COLOR_RGB,
        .pixel_type = FF_PIXEL_PACKED,
        .depth = 8,
        .x_chroma_shift = 0, .y_chroma_shift = 0,
    },
    [PIX_FMT_BGR4] = {
        .name = "bgr4",
        .nb_channels = 1,
        .color_type = FF_COLOR_RGB,
        .pixel_type = FF_PIXEL_PACKED,
        .depth = 4,
        .x_chroma_shift = 0, .y_chroma_shift = 0,
    },
    [PIX_FMT_BGR4_BYTE] = {
        .name = "bgr4_byte",
        .nb_channels = 1,
        .color_type = FF_COLOR_RGB,
        .pixel_type = FF_PIXEL_PACKED,
        .depth = 8,
        .x_chroma_shift = 0, .y_chroma_shift = 0,
    },
    [PIX_FMT_NV12] = {
        .name = "nv12",
        .nb_channels = 2,
        .color_type = FF_COLOR_YUV,
        .pixel_type = FF_PIXEL_PLANAR,
        .depth = 8,
        .x_chroma_shift = 1, .y_chroma_shift = 1,
    },
    [PIX_FMT_NV21] = {
        .name = "nv12",
        .nb_channels = 2,
        .color_type = FF_COLOR_YUV,
        .pixel_type = FF_PIXEL_PLANAR,
        .depth = 8,
        .x_chroma_shift = 1, .y_chroma_shift = 1,
    },

    [PIX_FMT_BGR32_1] = {
        .name = "bgr32_1",
        .nb_channels = 4, .is_alpha = 1,
        .color_type = FF_COLOR_RGB,
        .pixel_type = FF_PIXEL_PACKED,
        .depth = 8,
        .x_chroma_shift = 0, .y_chroma_shift = 0,
    },
    [PIX_FMT_RGB32_1] = {
        .name = "rgb32_1",
        .nb_channels = 4, .is_alpha = 1,
        .color_type = FF_COLOR_RGB,
        .pixel_type = FF_PIXEL_PACKED,
        .depth = 8,
        .x_chroma_shift = 0, .y_chroma_shift = 0,
    },
398 399 400 401
};

void avcodec_get_chroma_sub_sample(int pix_fmt, int *h_shift, int *v_shift)
{
402 403
    *h_shift = pix_fmt_info[pix_fmt].x_chroma_shift;
    *v_shift = pix_fmt_info[pix_fmt].y_chroma_shift;
404 405 406 407 408
}

const char *avcodec_get_pix_fmt_name(int pix_fmt)
{
    if (pix_fmt < 0 || pix_fmt >= PIX_FMT_NB)
409
        return NULL;
410 411 412 413
    else
        return pix_fmt_info[pix_fmt].name;
}

romansh's avatar
 
romansh committed
414 415
enum PixelFormat avcodec_get_pix_fmt(const char* name)
{
416 417
    int i;

romansh's avatar
 
romansh committed
418 419
    for (i=0; i < PIX_FMT_NB; i++)
         if (!strcmp(pix_fmt_info[i].name, name))
420 421
             return i;
    return PIX_FMT_NONE;
romansh's avatar
 
romansh committed
422 423
}

benoit's avatar
 
benoit committed
424 425 426 427 428 429 430
void avcodec_pix_fmt_string (char *buf, int buf_size, int pix_fmt)
{
    /* print header */
    if (pix_fmt < 0)
        snprintf (buf, buf_size,
                  "name      " " nb_channels" " depth" " is_alpha"
            );
431 432 433 434 435
    else{
        PixFmtInfo info= pix_fmt_info[pix_fmt];

        char is_alpha_char= info.is_alpha ? 'y' : 'n';

benoit's avatar
 
benoit committed
436 437 438 439 440 441 442
        snprintf (buf, buf_size,
                  "%-10s" "      %1d     " "   %2d " "     %c   ",
                  info.name,
                  info.nb_channels,
                  info.depth,
                  is_alpha_char
            );
443
    }
benoit's avatar
 
benoit committed
444 445
}

446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482
int ff_set_systematic_pal(uint32_t pal[256], enum PixelFormat pix_fmt){
    int i;

    for(i=0; i<256; i++){
        int r,g,b;

        switch(pix_fmt) {
        case PIX_FMT_RGB8:
            r= (i>>5    )*36;
            g= ((i>>2)&7)*36;
            b= (i&3     )*85;
            break;
        case PIX_FMT_BGR8:
            b= (i>>6    )*85;
            g= ((i>>3)&7)*36;
            r= (i&7     )*36;
            break;
        case PIX_FMT_RGB4_BYTE:
            r= (i>>3    )*255;
            g= ((i>>1)&3)*85;
            b= (i&1     )*255;
            break;
        case PIX_FMT_BGR4_BYTE:
            b= (i>>3    )*255;
            g= ((i>>1)&3)*85;
            r= (i&1     )*255;
            break;
        case PIX_FMT_GRAY8:
            r=b=g= i;
            break;
        }
        pal[i] =  b + (g<<8) + (r<<16);
    }

    return 0;
}

483
int ff_fill_linesize(AVPicture *picture, int pix_fmt, int width)
484
{
485
    int w2;
486
    const PixFmtInfo *pinfo;
487

488
    memset(picture->linesize, 0, sizeof(picture->linesize));
489

490
    pinfo = &pix_fmt_info[pix_fmt];
491 492
    switch(pix_fmt) {
    case PIX_FMT_YUV420P:
493 494 495 496
    case PIX_FMT_YUV422P:
    case PIX_FMT_YUV444P:
    case PIX_FMT_YUV410P:
    case PIX_FMT_YUV411P:
benoit's avatar
benoit committed
497
    case PIX_FMT_YUV440P:
498 499 500
    case PIX_FMT_YUVJ420P:
    case PIX_FMT_YUVJ422P:
    case PIX_FMT_YUVJ444P:
benoit's avatar
benoit committed
501
    case PIX_FMT_YUVJ440P:
502
        w2 = (width + (1 << pinfo->x_chroma_shift) - 1) >> pinfo->x_chroma_shift;
503
        picture->linesize[0] = width;
504 505
        picture->linesize[1] = w2;
        picture->linesize[2] = w2;
506
        break;
507 508 509 510 511 512
    case PIX_FMT_YUVA420P:
        w2 = (width + (1 << pinfo->x_chroma_shift) - 1) >> pinfo->x_chroma_shift;
        picture->linesize[0] = width;
        picture->linesize[1] = w2;
        picture->linesize[2] = w2;
        picture->linesize[3] = width;
513
        break;
514 515 516 517 518
    case PIX_FMT_NV12:
    case PIX_FMT_NV21:
        w2 = (width + (1 << pinfo->x_chroma_shift) - 1) >> pinfo->x_chroma_shift;
        picture->linesize[0] = width;
        picture->linesize[1] = w2;
519
        break;
520 521 522
    case PIX_FMT_RGB24:
    case PIX_FMT_BGR24:
        picture->linesize[0] = width * 3;
523
        break;
524
    case PIX_FMT_RGB32:
525 526 527
    case PIX_FMT_BGR32:
    case PIX_FMT_RGB32_1:
    case PIX_FMT_BGR32_1:
528
        picture->linesize[0] = width * 4;
529
        break;
kostya's avatar
kostya committed
530 531
    case PIX_FMT_GRAY16BE:
    case PIX_FMT_GRAY16LE:
532 533
    case PIX_FMT_BGR555:
    case PIX_FMT_BGR565:
534 535
    case PIX_FMT_RGB555:
    case PIX_FMT_RGB565:
536
    case PIX_FMT_YUYV422:
537
        picture->linesize[0] = width * 2;
538
        break;
539 540
    case PIX_FMT_UYVY422:
        picture->linesize[0] = width * 2;
541
        break;
542
    case PIX_FMT_UYYVYY411:
romansh's avatar
 
romansh committed
543
        picture->linesize[0] = width + width/2;
544
        break;
545 546
    case PIX_FMT_RGB4:
    case PIX_FMT_BGR4:
547 548 549 550 551 552 553
        picture->linesize[0] = width / 2;
        break;
    case PIX_FMT_MONOWHITE:
    case PIX_FMT_MONOBLACK:
        picture->linesize[0] = (width + 7) >> 3;
        break;
    case PIX_FMT_PAL8:
554 555 556 557 558
    case PIX_FMT_RGB8:
    case PIX_FMT_BGR8:
    case PIX_FMT_RGB4_BYTE:
    case PIX_FMT_BGR4_BYTE:
    case PIX_FMT_GRAY8:
559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588
        picture->linesize[0] = width;
        picture->linesize[1] = 4;
        break;
    default:
        return -1;
    }
    return 0;
}

int ff_fill_pointer(AVPicture *picture, uint8_t *ptr, int pix_fmt,
                    int height)
{
    int size, h2, size2;
    const PixFmtInfo *pinfo;

    pinfo = &pix_fmt_info[pix_fmt];
    size = picture->linesize[0] * height;
    switch(pix_fmt) {
    case PIX_FMT_YUV420P:
    case PIX_FMT_YUV422P:
    case PIX_FMT_YUV444P:
    case PIX_FMT_YUV410P:
    case PIX_FMT_YUV411P:
    case PIX_FMT_YUV440P:
    case PIX_FMT_YUVJ420P:
    case PIX_FMT_YUVJ422P:
    case PIX_FMT_YUVJ444P:
    case PIX_FMT_YUVJ440P:
        h2 = (height + (1 << pinfo->y_chroma_shift) - 1) >> pinfo->y_chroma_shift;
        size2 = picture->linesize[1] * h2;
589
        picture->data[0] = ptr;
590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607
        picture->data[1] = picture->data[0] + size;
        picture->data[2] = picture->data[1] + size2;
        picture->data[3] = NULL;
        return size + 2 * size2;
    case PIX_FMT_YUVA420P:
        h2 = (height + (1 << pinfo->y_chroma_shift) - 1) >> pinfo->y_chroma_shift;
        size2 = picture->linesize[1] * h2;
        picture->data[0] = ptr;
        picture->data[1] = picture->data[0] + size;
        picture->data[2] = picture->data[1] + size2;
        picture->data[3] = picture->data[1] + size2 + size2;
        return 2 * size + 2 * size2;
    case PIX_FMT_NV12:
    case PIX_FMT_NV21:
        h2 = (height + (1 << pinfo->y_chroma_shift) - 1) >> pinfo->y_chroma_shift;
        size2 = picture->linesize[1] * h2 * 2;
        picture->data[0] = ptr;
        picture->data[1] = picture->data[0] + size;
608
        picture->data[2] = NULL;
609
        picture->data[3] = NULL;
610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627
        return size + 2 * size2;
    case PIX_FMT_RGB24:
    case PIX_FMT_BGR24:
    case PIX_FMT_RGB32:
    case PIX_FMT_BGR32:
    case PIX_FMT_RGB32_1:
    case PIX_FMT_BGR32_1:
    case PIX_FMT_GRAY16BE:
    case PIX_FMT_GRAY16LE:
    case PIX_FMT_BGR555:
    case PIX_FMT_BGR565:
    case PIX_FMT_RGB555:
    case PIX_FMT_RGB565:
    case PIX_FMT_YUYV422:
    case PIX_FMT_UYVY422:
    case PIX_FMT_UYYVYY411:
    case PIX_FMT_RGB4:
    case PIX_FMT_BGR4:
628 629 630 631 632
    case PIX_FMT_MONOWHITE:
    case PIX_FMT_MONOBLACK:
        picture->data[0] = ptr;
        picture->data[1] = NULL;
        picture->data[2] = NULL;
633
        picture->data[3] = NULL;
634
        return size;
635
    case PIX_FMT_PAL8:
636 637 638 639 640
    case PIX_FMT_RGB8:
    case PIX_FMT_BGR8:
    case PIX_FMT_RGB4_BYTE:
    case PIX_FMT_BGR4_BYTE:
    case PIX_FMT_GRAY8:
641 642 643 644
        size2 = (size + 3) & ~3;
        picture->data[0] = ptr;
        picture->data[1] = ptr + size2; /* palette is stored here as 256 32 bit words */
        picture->data[2] = NULL;
645
        picture->data[3] = NULL;
646
        return size2 + 256 * 4;
647 648 649 650
    default:
        picture->data[0] = NULL;
        picture->data[1] = NULL;
        picture->data[2] = NULL;
651
        picture->data[3] = NULL;
652 653 654 655
        return -1;
    }
}

656 657 658 659 660 661 662
int avpicture_fill(AVPicture *picture, uint8_t *ptr,
                   int pix_fmt, int width, int height)
{

    if(avcodec_check_dimensions(NULL, width, height))
        return -1;

663
    if (ff_fill_linesize(picture, pix_fmt, width))
664 665
        return -1;

666
    return ff_fill_pointer(picture, ptr, pix_fmt, height);
667 668
}

669
int avpicture_layout(const AVPicture* src, int pix_fmt, int width, int height,
romansh's avatar
 
romansh committed
670 671
                     unsigned char *dest, int dest_size)
{
672
    const PixFmtInfo* pf = &pix_fmt_info[pix_fmt];
romansh's avatar
 
romansh committed
673
    int i, j, w, h, data_planes;
674
    const unsigned char* s;
romansh's avatar
 
romansh committed
675 676
    int size = avpicture_get_size(pix_fmt, width, height);

677
    if (size > dest_size || size < 0)
romansh's avatar
 
romansh committed
678 679
        return -1;

romansh's avatar
 
romansh committed
680
    if (pf->pixel_type == FF_PIXEL_PACKED || pf->pixel_type == FF_PIXEL_PALETTE) {
681
        if (pix_fmt == PIX_FMT_YUYV422 ||
682
            pix_fmt == PIX_FMT_UYVY422 ||
683
            pix_fmt == PIX_FMT_BGR565 ||
684
            pix_fmt == PIX_FMT_BGR555 ||
685 686 687
            pix_fmt == PIX_FMT_RGB565 ||
            pix_fmt == PIX_FMT_RGB555)
            w = width * 2;
688
        else if (pix_fmt == PIX_FMT_UYYVYY411)
689 690 691 692 693 694 695 696
          w = width + width/2;
        else if (pix_fmt == PIX_FMT_PAL8)
          w = width;
        else
          w = width * (pf->depth * pf->nb_channels / 8);

        data_planes = 1;
        h = height;
romansh's avatar
 
romansh committed
697 698
    } else {
        data_planes = pf->nb_channels;
699 700
        w = (width*pf->depth + 7)/8;
        h = height;
romansh's avatar
 
romansh committed
701
    }
702

romansh's avatar
 
romansh committed
703 704
    for (i=0; i<data_planes; i++) {
         if (i == 1) {
705 706 707
             w = width >> pf->x_chroma_shift;
             h = height >> pf->y_chroma_shift;
         }
romansh's avatar
 
romansh committed
708
         s = src->data[i];
709 710 711 712 713
         for(j=0; j<h; j++) {
             memcpy(dest, s, w);
             dest += w;
             s += src->linesize[i];
         }
romansh's avatar
 
romansh committed
714
    }
715

romansh's avatar
 
romansh committed
716
    if (pf->pixel_type == FF_PIXEL_PALETTE)
717
        memcpy((unsigned char *)(((size_t)dest + 3) & ~3), src->data[1], 256 * 4);
718

romansh's avatar
 
romansh committed
719 720 721
    return size;
}

722 723 724 725 726 727
int avpicture_get_size(int pix_fmt, int width, int height)
{
    AVPicture dummy_pict;
    return avpicture_fill(&dummy_pict, NULL, pix_fmt, width, height);
}

728 729 730 731 732 733 734 735 736 737 738 739
int avcodec_get_pix_fmt_loss(int dst_pix_fmt, int src_pix_fmt,
                             int has_alpha)
{
    const PixFmtInfo *pf, *ps;
    int loss;

    ps = &pix_fmt_info[src_pix_fmt];
    pf = &pix_fmt_info[dst_pix_fmt];

    /* compute loss */
    loss = 0;
    pf = &pix_fmt_info[dst_pix_fmt];
740 741
    if (pf->depth < ps->depth ||
        (dst_pix_fmt == PIX_FMT_RGB555 && src_pix_fmt == PIX_FMT_RGB565))
742
        loss |= FF_LOSS_DEPTH;
743 744
    if (pf->x_chroma_shift > ps->x_chroma_shift ||
        pf->y_chroma_shift > ps->y_chroma_shift)
745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761
        loss |= FF_LOSS_RESOLUTION;
    switch(pf->color_type) {
    case FF_COLOR_RGB:
        if (ps->color_type != FF_COLOR_RGB &&
            ps->color_type != FF_COLOR_GRAY)
            loss |= FF_LOSS_COLORSPACE;
        break;
    case FF_COLOR_GRAY:
        if (ps->color_type != FF_COLOR_GRAY)
            loss |= FF_LOSS_COLORSPACE;
        break;
    case FF_COLOR_YUV:
        if (ps->color_type != FF_COLOR_YUV)
            loss |= FF_LOSS_COLORSPACE;
        break;
    case FF_COLOR_YUV_JPEG:
        if (ps->color_type != FF_COLOR_YUV_JPEG &&
762
            ps->color_type != FF_COLOR_YUV &&
763
            ps->color_type != FF_COLOR_GRAY)
764 765 766 767 768 769 770 771 772 773 774 775 776
            loss |= FF_LOSS_COLORSPACE;
        break;
    default:
        /* fail safe test */
        if (ps->color_type != pf->color_type)
            loss |= FF_LOSS_COLORSPACE;
        break;
    }
    if (pf->color_type == FF_COLOR_GRAY &&
        ps->color_type != FF_COLOR_GRAY)
        loss |= FF_LOSS_CHROMA;
    if (!pf->is_alpha && (ps->is_alpha && has_alpha))
        loss |= FF_LOSS_ALPHA;
777
    if (pf->pixel_type == FF_PIXEL_PALETTE &&
778
        (ps->pixel_type != FF_PIXEL_PALETTE && ps->color_type != FF_COLOR_GRAY))
779 780 781 782 783 784 785 786 787 788
        loss |= FF_LOSS_COLORQUANT;
    return loss;
}

static int avg_bits_per_pixel(int pix_fmt)
{
    int bits;
    const PixFmtInfo *pf;

    pf = &pix_fmt_info[pix_fmt];
789 790
    switch(pf->pixel_type) {
    case FF_PIXEL_PACKED:
791
        switch(pix_fmt) {
792
        case PIX_FMT_YUYV422:
793
        case PIX_FMT_UYVY422:
794 795
        case PIX_FMT_RGB565:
        case PIX_FMT_RGB555:
796 797
        case PIX_FMT_BGR565:
        case PIX_FMT_BGR555:
798 799
            bits = 16;
            break;
800
        case PIX_FMT_UYYVYY411:
801 802
            bits = 12;
            break;
803
        default:
804
            bits = pf->depth * pf->nb_channels;
805 806
            break;
        }
807 808 809 810 811
        break;
    case FF_PIXEL_PLANAR:
        if (pf->x_chroma_shift == 0 && pf->y_chroma_shift == 0) {
            bits = pf->depth * pf->nb_channels;
        } else {
812
            bits = pf->depth + ((2 * pf->depth) >>
813 814 815 816 817 818 819 820 821
                                (pf->x_chroma_shift + pf->y_chroma_shift));
        }
        break;
    case FF_PIXEL_PALETTE:
        bits = 8;
        break;
    default:
        bits = -1;
        break;
822 823 824 825
    }
    return bits;
}

826
static int avcodec_find_best_pix_fmt1(int64_t pix_fmt_mask,
827 828 829 830 831 832 833 834 835 836
                                      int src_pix_fmt,
                                      int has_alpha,
                                      int loss_mask)
{
    int dist, i, loss, min_dist, dst_pix_fmt;

    /* find exact color match with smallest size */
    dst_pix_fmt = -1;
    min_dist = 0x7fffffff;
    for(i = 0;i < PIX_FMT_NB; i++) {
837
        if (pix_fmt_mask & (1ULL << i)) {
838 839 840 841 842 843 844 845 846 847 848 849 850
            loss = avcodec_get_pix_fmt_loss(i, src_pix_fmt, has_alpha) & loss_mask;
            if (loss == 0) {
                dist = avg_bits_per_pixel(i);
                if (dist < min_dist) {
                    min_dist = dist;
                    dst_pix_fmt = i;
                }
            }
        }
    }
    return dst_pix_fmt;
}

851
int avcodec_find_best_pix_fmt(int64_t pix_fmt_mask, int src_pix_fmt,
852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868
                              int has_alpha, int *loss_ptr)
{
    int dst_pix_fmt, loss_mask, i;
    static const int loss_mask_order[] = {
        ~0, /* no loss first */
        ~FF_LOSS_ALPHA,
        ~FF_LOSS_RESOLUTION,
        ~(FF_LOSS_COLORSPACE | FF_LOSS_RESOLUTION),
        ~FF_LOSS_COLORQUANT,
        ~FF_LOSS_DEPTH,
        0,
    };

    /* try with successive loss */
    i = 0;
    for(;;) {
        loss_mask = loss_mask_order[i++];
869
        dst_pix_fmt = avcodec_find_best_pix_fmt1(pix_fmt_mask, src_pix_fmt,
870 871 872 873 874 875 876 877 878 879 880 881 882
                                                 has_alpha, loss_mask);
        if (dst_pix_fmt >= 0)
            goto found;
        if (loss_mask == 0)
            break;
    }
    return -1;
 found:
    if (loss_ptr)
        *loss_ptr = avcodec_get_pix_fmt_loss(dst_pix_fmt, src_pix_fmt, has_alpha);
    return dst_pix_fmt;
}

883
void ff_img_copy_plane(uint8_t *dst, int dst_wrap,
bellard's avatar
bellard committed
884 885
                           const uint8_t *src, int src_wrap,
                           int width, int height)
886
{
887
    if((!dst) || (!src))
michael's avatar
michael committed
888
        return;
889 890 891 892 893 894 895
    for(;height > 0; height--) {
        memcpy(dst, src, width);
        dst += dst_wrap;
        src += src_wrap;
    }
}

896
int ff_get_plane_bytewidth(enum PixelFormat pix_fmt, int width, int plane)
897
{
898
    int bits;
899
    const PixFmtInfo *pf = &pix_fmt_info[pix_fmt];
900

901 902 903 904
    pf = &pix_fmt_info[pix_fmt];
    switch(pf->pixel_type) {
    case FF_PIXEL_PACKED:
        switch(pix_fmt) {
905
        case PIX_FMT_YUYV422:
906
        case PIX_FMT_UYVY422:
907 908
        case PIX_FMT_RGB565:
        case PIX_FMT_RGB555:
909 910
        case PIX_FMT_BGR565:
        case PIX_FMT_BGR555:
911 912
            bits = 16;
            break;
913
        case PIX_FMT_UYYVYY411:
914 915
            bits = 12;
            break;
916 917 918 919
        default:
            bits = pf->depth * pf->nb_channels;
            break;
        }
920 921 922 923
        return (width * bits + 7) >> 3;
        break;
    case FF_PIXEL_PLANAR:
            if (plane == 1 || plane == 2)
924
                width= -((-width)>>pf->x_chroma_shift);
925 926 927 928 929 930

            return (width * pf->depth + 7) >> 3;
        break;
    case FF_PIXEL_PALETTE:
        if (plane == 0)
            return width;
931
        break;
932 933 934 935 936 937 938 939 940 941 942 943 944 945
    }

    return -1;
}

void av_picture_copy(AVPicture *dst, const AVPicture *src,
              int pix_fmt, int width, int height)
{
    int i;
    const PixFmtInfo *pf = &pix_fmt_info[pix_fmt];

    pf = &pix_fmt_info[pix_fmt];
    switch(pf->pixel_type) {
    case FF_PIXEL_PACKED:
946 947
    case FF_PIXEL_PLANAR:
        for(i = 0; i < pf->nb_channels; i++) {
948
            int h;
949
            int bwidth = ff_get_plane_bytewidth(pix_fmt, width, i);
950 951
            h = height;
            if (i == 1 || i == 2) {
952
                h= -((-height)>>pf->y_chroma_shift);
953
            }
954
            ff_img_copy_plane(dst->data[i], dst->linesize[i],
955 956 957 958 959
                           src->data[i], src->linesize[i],
                           bwidth, h);
        }
        break;
    case FF_PIXEL_PALETTE:
960
        ff_img_copy_plane(dst->data[0], dst->linesize[0],
961 962 963
                       src->data[0], src->linesize[0],
                       width, height);
        /* copy the palette */
964
        ff_img_copy_plane(dst->data[1], dst->linesize[1],
965 966 967 968 969
                       src->data[1], src->linesize[1],
                       4, 256);
        break;
    }
}
970

glantau's avatar
glantau committed
971 972
/* XXX: totally non optimized */

973
static void yuyv422_to_yuv420p(AVPicture *dst, const AVPicture *src,
974
                              int width, int height)
glantau's avatar
glantau committed
975
{
976 977
    const uint8_t *p, *p1;
    uint8_t *lum, *cr, *cb, *lum1, *cr1, *cb1;
978
    int w;
979

980 981
    p1 = src->data[0];
    lum1 = dst->data[0];
bellard's avatar
bellard committed
982 983
    cb1 = dst->data[1];
    cr1 = dst->data[2];
984

985
    for(;height >= 1; height -= 2) {
986 987 988 989
        p = p1;
        lum = lum1;
        cb = cb1;
        cr = cr1;
990
        for(w = width; w >= 2; w -= 2) {
991 992 993 994
            lum[0] = p[0];
            cb[0] = p[1];
            lum[1] = p[2];
            cr[0] = p[3];
glantau's avatar
glantau committed
995 996 997 998 999
            p += 4;
            lum += 2;
            cb++;
            cr++;
        }
1000
        if (w) {
1001
            lum[0] = p[0];
1002 1003 1004 1005
            cb[0] = p[1];
            cr[0] = p[3];
            cb++;
            cr++;
glantau's avatar
glantau committed
1006
        }
1007 1008
        p1 += src->linesize[0];
        lum1 += dst->linesize[0];
1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023
        if (height>1) {
            p = p1;
            lum = lum1;
            for(w = width; w >= 2; w -= 2) {
                lum[0] = p[0];
                lum[1] = p[2];
                p += 4;
                lum += 2;
            }
            if (w) {
                lum[0] = p[0];
            }
            p1 += src->linesize[0];
            lum1 += dst->linesize[0];
        }
1024 1025 1026 1027 1028
        cb1 += dst->linesize[1];
        cr1 += dst->linesize[2];
    }
}

1029 1030 1031 1032 1033 1034
static void uyvy422_to_yuv420p(AVPicture *dst, const AVPicture *src,
                              int width, int height)
{
    const uint8_t *p, *p1;
    uint8_t *lum, *cr, *cb, *lum1, *cr1, *cb1;
    int w;
1035

1036
    p1 = src->data[0];
1037

1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120
    lum1 = dst->data[0];
    cb1 = dst->data[1];
    cr1 = dst->data[2];

    for(;height >= 1; height -= 2) {
        p = p1;
        lum = lum1;
        cb = cb1;
        cr = cr1;
        for(w = width; w >= 2; w -= 2) {
            lum[0] = p[1];
            cb[0] = p[0];
            lum[1] = p[3];
            cr[0] = p[2];
            p += 4;
            lum += 2;
            cb++;
            cr++;
        }
        if (w) {
            lum[0] = p[1];
            cb[0] = p[0];
            cr[0] = p[2];
            cb++;
            cr++;
        }
        p1 += src->linesize[0];
        lum1 += dst->linesize[0];
        if (height>1) {
            p = p1;
            lum = lum1;
            for(w = width; w >= 2; w -= 2) {
                lum[0] = p[1];
                lum[1] = p[3];
                p += 4;
                lum += 2;
            }
            if (w) {
                lum[0] = p[1];
            }
            p1 += src->linesize[0];
            lum1 += dst->linesize[0];
        }
        cb1 += dst->linesize[1];
        cr1 += dst->linesize[2];
    }
}


static void uyvy422_to_yuv422p(AVPicture *dst, const AVPicture *src,
                              int width, int height)
{
    const uint8_t *p, *p1;
    uint8_t *lum, *cr, *cb, *lum1, *cr1, *cb1;
    int w;

    p1 = src->data[0];
    lum1 = dst->data[0];
    cb1 = dst->data[1];
    cr1 = dst->data[2];
    for(;height > 0; height--) {
        p = p1;
        lum = lum1;
        cb = cb1;
        cr = cr1;
        for(w = width; w >= 2; w -= 2) {
            lum[0] = p[1];
            cb[0] = p[0];
            lum[1] = p[3];
            cr[0] = p[2];
            p += 4;
            lum += 2;
            cb++;
            cr++;
        }
        p1 += src->linesize[0];
        lum1 += dst->linesize[0];
        cb1 += dst->linesize[1];
        cr1 += dst->linesize[2];
    }
}


1121
static void yuyv422_to_yuv422p(AVPicture *dst, const AVPicture *src,
1122 1123 1124 1125 1126 1127 1128 1129
                              int width, int height)
{
    const uint8_t *p, *p1;
    uint8_t *lum, *cr, *cb, *lum1, *cr1, *cb1;
    int w;

    p1 = src->data[0];
    lum1 = dst->data[0];
bellard's avatar
bellard committed
1130 1131 1132
    cb1 = dst->data[1];
    cr1 = dst->data[2];
    for(;height > 0; height--) {
1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150
        p = p1;
        lum = lum1;
        cb = cb1;
        cr = cr1;
        for(w = width; w >= 2; w -= 2) {
            lum[0] = p[0];
            cb[0] = p[1];
            lum[1] = p[2];
            cr[0] = p[3];
            p += 4;
            lum += 2;
            cb++;
            cr++;
        }
        p1 += src->linesize[0];
        lum1 += dst->linesize[0];
        cb1 += dst->linesize[1];
        cr1 += dst->linesize[2];
glantau's avatar
glantau committed
1151 1152 1153
    }
}

1154
static void yuv422p_to_yuyv422(AVPicture *dst, const AVPicture *src,
1155 1156 1157 1158 1159 1160 1161 1162
                              int width, int height)
{
    uint8_t *p, *p1;
    const uint8_t *lum, *cr, *cb, *lum1, *cr1, *cb1;
    int w;

    p1 = dst->data[0];
    lum1 = src->data[0];
bellard's avatar
bellard committed
1163 1164 1165
    cb1 = src->data[1];
    cr1 = src->data[2];
    for(;height > 0; height--) {
1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179
        p = p1;
        lum = lum1;
        cb = cb1;
        cr = cr1;
        for(w = width; w >= 2; w -= 2) {
            p[0] = lum[0];
            p[1] = cb[0];
            p[2] = lum[1];
            p[3] = cr[0];
            p += 4;
            lum += 2;
            cb++;
            cr++;
        }
bellard's avatar
bellard committed
1180 1181 1182 1183
        p1 += dst->linesize[0];
        lum1 += src->linesize[0];
        cb1 += src->linesize[1];
        cr1 += src->linesize[2];
1184 1185 1186
    }
}

1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219
static void yuv422p_to_uyvy422(AVPicture *dst, const AVPicture *src,
                              int width, int height)
{
    uint8_t *p, *p1;
    const uint8_t *lum, *cr, *cb, *lum1, *cr1, *cb1;
    int w;

    p1 = dst->data[0];
    lum1 = src->data[0];
    cb1 = src->data[1];
    cr1 = src->data[2];
    for(;height > 0; height--) {
        p = p1;
        lum = lum1;
        cb = cb1;
        cr = cr1;
        for(w = width; w >= 2; w -= 2) {
            p[1] = lum[0];
            p[0] = cb[0];
            p[3] = lum[1];
            p[2] = cr[0];
            p += 4;
            lum += 2;
            cb++;
            cr++;
        }
        p1 += dst->linesize[0];
        lum1 += src->linesize[0];
        cb1 += src->linesize[1];
        cr1 += src->linesize[2];
    }
}

1220
static void uyyvyy411_to_yuv411p(AVPicture *dst, const AVPicture *src,
romansh's avatar
 
romansh committed
1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237
                              int width, int height)
{
    const uint8_t *p, *p1;
    uint8_t *lum, *cr, *cb, *lum1, *cr1, *cb1;
    int w;

    p1 = src->data[0];
    lum1 = dst->data[0];
    cb1 = dst->data[1];
    cr1 = dst->data[2];
    for(;height > 0; height--) {
        p = p1;
        lum = lum1;
        cb = cb1;
        cr = cr1;
        for(w = width; w >= 4; w -= 4) {
            cb[0] = p[0];
1238
            lum[0] = p[1];
romansh's avatar
 
romansh committed
1239 1240
            lum[1] = p[2];
            cr[0] = p[3];
1241 1242
            lum[2] = p[4];
            lum[3] = p[5];
romansh's avatar
 
romansh committed
1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253
            p += 6;
            lum += 4;
            cb++;
            cr++;
        }
        p1 += src->linesize[0];
        lum1 += dst->linesize[0];
        cb1 += dst->linesize[1];
        cr1 += dst->linesize[2];
    }
}
1254 1255


1256
static void yuv420p_to_yuyv422(AVPicture *dst, const AVPicture *src,
1257 1258 1259 1260 1261 1262 1263
                              int width, int height)
{
    int w, h;
    uint8_t *line1, *line2, *linesrc = dst->data[0];
    uint8_t *lum1, *lum2, *lumsrc = src->data[0];
    uint8_t *cb1, *cb2 = src->data[1];
    uint8_t *cr1, *cr2 = src->data[2];
1264

1265 1266 1267
    for(h = height / 2; h--;) {
        line1 = linesrc;
        line2 = linesrc + dst->linesize[0];
1268

1269 1270
        lum1 = lumsrc;
        lum2 = lumsrc + src->linesize[0];
1271

1272 1273
        cb1 = cb2;
        cr1 = cr2;
1274

1275
        for(w = width / 2; w--;) {
1276 1277 1278
                *line1++ = *lum1++; *line2++ = *lum2++;
                *line1++ =          *line2++ = *cb1++;
                *line1++ = *lum1++; *line2++ = *lum2++;
1279 1280
                *line1++ =          *line2++ = *cr1++;
        }
1281

1282 1283 1284 1285 1286 1287 1288
        linesrc += dst->linesize[0] * 2;
        lumsrc += src->linesize[0] * 2;
        cb2 += src->linesize[1];
        cr2 += src->linesize[2];
    }
}

1289 1290 1291 1292 1293 1294 1295 1296
static void yuv420p_to_uyvy422(AVPicture *dst, const AVPicture *src,
                              int width, int height)
{
    int w, h;
    uint8_t *line1, *line2, *linesrc = dst->data[0];
    uint8_t *lum1, *lum2, *lumsrc = src->data[0];
    uint8_t *cb1, *cb2 = src->data[1];
    uint8_t *cr1, *cr2 = src->data[2];
1297

1298 1299 1300
    for(h = height / 2; h--;) {
        line1 = linesrc;
        line2 = linesrc + dst->linesize[0];
1301

1302 1303
        lum1 = lumsrc;
        lum2 = lumsrc + src->linesize[0];
1304

1305 1306
        cb1 = cb2;
        cr1 = cr2;
1307

1308
        for(w = width / 2; w--;) {
1309 1310
                *line1++ =          *line2++ = *cb1++;
                *line1++ = *lum1++; *line2++ = *lum2++;
1311
                *line1++ =          *line2++ = *cr1++;
1312
                *line1++ = *lum1++; *line2++ = *lum2++;
1313
        }
1314

1315 1316 1317 1318 1319 1320 1321
        linesrc += dst->linesize[0] * 2;
        lumsrc += src->linesize[0] * 2;
        cb2 += src->linesize[1];
        cr2 += src->linesize[2];
    }
}

1322
/* 2x2 -> 1x1 */
1323
void ff_shrink22(uint8_t *dst, int dst_wrap,
bellard's avatar
bellard committed
1324
                     const uint8_t *src, int src_wrap,
1325 1326 1327
                     int width, int height)
{
    int w;
bellard's avatar
bellard committed
1328 1329
    const uint8_t *s1, *s2;
    uint8_t *d;
1330 1331 1332 1333 1334 1335

    for(;height > 0; height--) {
        s1 = src;
        s2 = s1 + src_wrap;
        d = dst;
        for(w = width;w >= 4; w-=4) {
1336 1337 1338 1339
            d[0] = (s1[0] + s1[1] + s2[0] + s2[1] + 2) >> 2;
            d[1] = (s1[2] + s1[3] + s2[2] + s2[3] + 2) >> 2;
            d[2] = (s1[4] + s1[5] + s2[4] + s2[5] + 2) >> 2;
            d[3] = (s1[6] + s1[7] + s2[6] + s2[7] + 2) >> 2;
1340 1341 1342 1343 1344
            s1 += 8;
            s2 += 8;
            d += 4;
        }
        for(;w > 0; w--) {
1345
            d[0] = (s1[0] + s1[1] + s2[0] + s2[1] + 2) >> 2;
1346 1347 1348 1349 1350 1351 1352 1353 1354
            s1 += 2;
            s2 += 2;
            d++;
        }
        src += 2 * src_wrap;
        dst += dst_wrap;
    }
}

bellard's avatar
bellard committed
1355
/* 4x4 -> 1x1 */
1356
void ff_shrink44(uint8_t *dst, int dst_wrap,
bellard's avatar
bellard committed
1357
                     const uint8_t *src, int src_wrap,
1358 1359 1360
                     int width, int height)
{
    int w;
bellard's avatar
bellard committed
1361 1362
    const uint8_t *s1, *s2, *s3, *s4;
    uint8_t *d;
1363 1364 1365

    for(;height > 0; height--) {
        s1 = src;
bellard's avatar
bellard committed
1366 1367 1368
        s2 = s1 + src_wrap;
        s3 = s2 + src_wrap;
        s4 = s3 + src_wrap;
1369
        d = dst;
bellard's avatar
bellard committed
1370 1371 1372 1373 1374 1375 1376 1377 1378
        for(w = width;w > 0; w--) {
            d[0] = (s1[0] + s1[1] + s1[2] + s1[3] +
                    s2[0] + s2[1] + s2[2] + s2[3] +
                    s3[0] + s3[1] + s3[2] + s3[3] +
                    s4[0] + s4[1] + s4[2] + s4[3] + 8) >> 4;
            s1 += 4;
            s2 += 4;
            s3 += 4;
            s4 += 4;
1379 1380
            d++;
        }
bellard's avatar
bellard committed
1381 1382 1383 1384 1385
        src += 4 * src_wrap;
        dst += dst_wrap;
    }
}

1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407
/* 8x8 -> 1x1 */
void ff_shrink88(uint8_t *dst, int dst_wrap,
                     const uint8_t *src, int src_wrap,
                     int width, int height)
{
    int w, i;

    for(;height > 0; height--) {
        for(w = width;w > 0; w--) {
            int tmp=0;
            for(i=0; i<8; i++){
                tmp += src[0] + src[1] + src[2] + src[3] + src[4] + src[5] + src[6] + src[7];
                src += src_wrap;
            }
            *(dst++) = (tmp + 32)>>6;
            src += 8 - 8*src_wrap;
        }
        src += 8*src_wrap - 8*width;
        dst += dst_wrap - width;
    }
}

1408
/* XXX: add jpeg quantize code */
bellard's avatar
bellard committed
1409

1410
#define TRANSP_INDEX (6*6*6)
bellard's avatar
bellard committed
1411

1412 1413
/* this is maybe slow, but allows for extensions */
static inline unsigned char gif_clut_index(uint8_t r, uint8_t g, uint8_t b)
bellard's avatar
bellard committed
1414
{
1415
    return (((r) / 47) % 6) * 6 * 6 + (((g) / 47) % 6) * 6 + (((b) / 47) % 6);
bellard's avatar
bellard committed
1416 1417
}

1418
static void build_rgb_palette(uint8_t *palette, int has_alpha)
bellard's avatar
bellard committed
1419
{
1420 1421 1422
    uint32_t *pal;
    static const uint8_t pal_value[6] = { 0x00, 0x33, 0x66, 0x99, 0xcc, 0xff };
    int i, r, g, b;
bellard's avatar
bellard committed
1423

1424 1425 1426 1427 1428 1429 1430 1431 1432
    pal = (uint32_t *)palette;
    i = 0;
    for(r = 0; r < 6; r++) {
        for(g = 0; g < 6; g++) {
            for(b = 0; b < 6; b++) {
                pal[i++] = (0xff << 24) | (pal_value[r] << 16) |
                    (pal_value[g] << 8) | pal_value[b];
            }
        }
benoit's avatar
benoit committed
1433
    }
1434 1435 1436 1437
    if (has_alpha)
        pal[i++] = 0;
    while (i < 256)
        pal[i++] = 0xff000000;
benoit's avatar
benoit committed
1438 1439
}

1440 1441
/* copy bit n to bits 0 ... n - 1 */
static inline unsigned int bitcopy_n(unsigned int a, int n)
bellard's avatar
bellard committed
1442
{
1443 1444 1445
    int mask;
    mask = (1 << n) - 1;
    return (a & (0xff & ~mask)) | ((-((a >> n) & 1)) & mask);
1446 1447
}

1448 1449 1450 1451 1452 1453 1454 1455 1456 1457
/* rgb555 handling */

#define RGB_NAME rgb555

#define RGB_IN(r, g, b, s)\
{\
    unsigned int v = ((const uint16_t *)(s))[0];\
    r = bitcopy_n(v >> (10 - 3), 3);\
    g = bitcopy_n(v >> (5 - 3), 3);\
    b = bitcopy_n(v << 3, 3);\
1458 1459
}

1460

alex's avatar
alex committed
1461
#define RGB_OUT(d, r, g, b)\
1462
{\
alex's avatar
alex committed
1463
    ((uint16_t *)(d))[0] = ((r >> 3) << 10) | ((g >> 3) << 5) | (b >> 3);\
1464 1465 1466 1467
}

#define BPP 2

1468
#include "imgconvert_template.c"
1469 1470 1471

/* rgb565 handling */

1472 1473
#define RGB_NAME rgb565

1474 1475
#define RGB_IN(r, g, b, s)\
{\
kabi's avatar
kabi committed
1476
    unsigned int v = ((const uint16_t *)(s))[0];\
1477 1478 1479 1480 1481 1482 1483
    r = bitcopy_n(v >> (11 - 3), 3);\
    g = bitcopy_n(v >> (5 - 2), 2);\
    b = bitcopy_n(v << 3, 3);\
}

#define RGB_OUT(d, r, g, b)\
{\
kabi's avatar
kabi committed
1484
    ((uint16_t *)(d))[0] = ((r >> 3) << 11) | ((g >> 2) << 5) | (b >> 3);\
1485 1486 1487 1488
}

#define BPP 2

1489
#include "imgconvert_template.c"
1490 1491 1492

/* bgr24 handling */

1493 1494
#define RGB_NAME bgr24

1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510
#define RGB_IN(r, g, b, s)\
{\
    b = (s)[0];\
    g = (s)[1];\
    r = (s)[2];\
}

#define RGB_OUT(d, r, g, b)\
{\
    (d)[0] = b;\
    (d)[1] = g;\
    (d)[2] = r;\
}

#define BPP 3

1511
#include "imgconvert_template.c"
1512 1513 1514 1515 1516 1517 1518

#undef RGB_IN
#undef RGB_OUT
#undef BPP

/* rgb24 handling */

1519 1520 1521
#define RGB_NAME rgb24
#define FMT_RGB24

1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537
#define RGB_IN(r, g, b, s)\
{\
    r = (s)[0];\
    g = (s)[1];\
    b = (s)[2];\
}

#define RGB_OUT(d, r, g, b)\
{\
    (d)[0] = r;\
    (d)[1] = g;\
    (d)[2] = b;\
}

#define BPP 3

1538
#include "imgconvert_template.c"
1539

1540
/* rgb32 handling */
1541

1542 1543
#define RGB_NAME rgb32
#define FMT_RGB32
1544

1545 1546
#define RGB_IN(r, g, b, s)\
{\
kabi's avatar
kabi committed
1547
    unsigned int v = ((const uint32_t *)(s))[0];\
1548 1549 1550 1551 1552
    r = (v >> 16) & 0xff;\
    g = (v >> 8) & 0xff;\
    b = v & 0xff;\
}

1553
#define RGBA_IN(r, g, b, a, s)\
1554
{\
1555 1556 1557 1558 1559
    unsigned int v = ((const uint32_t *)(s))[0];\
    a = (v >> 24) & 0xff;\
    r = (v >> 16) & 0xff;\
    g = (v >> 8) & 0xff;\
    b = v & 0xff;\
1560 1561
}

1562 1563 1564
#define RGBA_OUT(d, r, g, b, a)\
{\
    ((uint32_t *)(d))[0] = (a << 24) | (r << 16) | (g << 8) | b;\
1565 1566
}

1567
#define BPP 4
1568

1569
#include "imgconvert_template.c"
1570

1571
static void mono_to_gray(AVPicture *dst, const AVPicture *src,
1572
                         int width, int height, int xor_mask)
1573 1574 1575 1576 1577 1578 1579 1580 1581 1582
{
    const unsigned char *p;
    unsigned char *q;
    int v, dst_wrap, src_wrap;
    int y, w;

    p = src->data[0];
    src_wrap = src->linesize[0] - ((width + 7) >> 3);

    q = dst->data[0];
1583
    dst_wrap = dst->linesize[0] - width;
1584
    for(y=0;y<height;y++) {
1585
        w = width;
1586
        while (w >= 8) {
1587 1588 1589 1590 1591 1592 1593 1594 1595
            v = *p++ ^ xor_mask;
            q[0] = -(v >> 7);
            q[1] = -((v >> 6) & 1);
            q[2] = -((v >> 5) & 1);
            q[3] = -((v >> 4) & 1);
            q[4] = -((v >> 3) & 1);
            q[5] = -((v >> 2) & 1);
            q[6] = -((v >> 1) & 1);
            q[7] = -((v >> 0) & 1);
1596
            w -= 8;
1597
            q += 8;
1598 1599
        }
        if (w > 0) {
1600
            v = *p++ ^ xor_mask;
1601
            do {
1602 1603
                q[0] = -((v >> 7) & 1);
                q++;
1604 1605
                v <<= 1;
            } while (--w);
1606
        }
1607 1608
        p += src_wrap;
        q += dst_wrap;
1609 1610 1611
    }
}

1612
static void monowhite_to_gray(AVPicture *dst, const AVPicture *src,
1613 1614
                               int width, int height)
{
1615 1616
    mono_to_gray(dst, src, width, height, 0xff);
}
1617

1618
static void monoblack_to_gray(AVPicture *dst, const AVPicture *src,
1619 1620 1621 1622
                               int width, int height)
{
    mono_to_gray(dst, src, width, height, 0x00);
}
1623

1624
static void gray_to_mono(AVPicture *dst, const AVPicture *src,
1625 1626 1627
                         int width, int height, int xor_mask)
{
    int n;
kabi's avatar
kabi committed
1628 1629
    const uint8_t *s;
    uint8_t *d;
1630 1631 1632 1633 1634 1635 1636
    int j, b, v, n1, src_wrap, dst_wrap, y;

    s = src->data[0];
    src_wrap = src->linesize[0] - width;

    d = dst->data[0];
    dst_wrap = dst->linesize[0] - ((width + 7) >> 3);
1637 1638

    for(y=0;y<height;y++) {
1639 1640 1641 1642 1643 1644 1645 1646 1647 1648 1649
        n = width;
        while (n >= 8) {
            v = 0;
            for(j=0;j<8;j++) {
                b = s[0];
                s++;
                v = (v << 1) | (b >> 7);
            }
            d[0] = v ^ xor_mask;
            d++;
            n -= 8;
1650
        }
1651 1652 1653 1654 1655 1656 1657 1658 1659 1660 1661
        if (n > 0) {
            n1 = n;
            v = 0;
            while (n > 0) {
                b = s[0];
                s++;
                v = (v << 1) | (b >> 7);
                n--;
            }
            d[0] = (v << (8 - (n1 & 7))) ^ xor_mask;
            d++;
1662
        }
1663 1664
        s += src_wrap;
        d += dst_wrap;
1665 1666 1667
    }
}

1668
static void gray_to_monowhite(AVPicture *dst, const AVPicture *src,
1669 1670 1671 1672 1673
                              int width, int height)
{
    gray_to_mono(dst, src, width, height, 0xff);
}

1674
static void gray_to_monoblack(AVPicture *dst, const AVPicture *src,
1675 1676 1677 1678 1679
                              int width, int height)
{
    gray_to_mono(dst, src, width, height, 0x00);
}

kostya's avatar
kostya committed
1680 1681 1682 1683 1684 1685 1686 1687 1688 1689 1690 1691 1692 1693 1694 1695 1696 1697 1698 1699 1700 1701 1702 1703 1704 1705 1706 1707 1708 1709 1710 1711 1712 1713 1714 1715 1716 1717 1718 1719 1720 1721 1722 1723 1724 1725 1726
static void gray_to_gray16(AVPicture *dst, const AVPicture *src,
                              int width, int height)
{
    int x, y, src_wrap, dst_wrap;
    uint8_t *s, *d;
    s = src->data[0];
    src_wrap = src->linesize[0] - width;
    d = dst->data[0];
    dst_wrap = dst->linesize[0] - width * 2;
    for(y=0; y<height; y++){
        for(x=0; x<width; x++){
            *d++ = *s;
            *d++ = *s++;
        }
        s += src_wrap;
        d += dst_wrap;
    }
}

static void gray16_to_gray(AVPicture *dst, const AVPicture *src,
                              int width, int height)
{
    int x, y, src_wrap, dst_wrap;
    uint8_t *s, *d;
    s = src->data[0];
    src_wrap = src->linesize[0] - width * 2;
    d = dst->data[0];
    dst_wrap = dst->linesize[0] - width;
    for(y=0; y<height; y++){
        for(x=0; x<width; x++){
            *d++ = *s;
            s += 2;
        }
        s += src_wrap;
        d += dst_wrap;
    }
}

static void gray16be_to_gray(AVPicture *dst, const AVPicture *src,
                              int width, int height)
{
    gray16_to_gray(dst, src, width, height);
}

static void gray16le_to_gray(AVPicture *dst, const AVPicture *src,
                              int width, int height)
{
1727 1728 1729
    AVPicture tmpsrc = *src;
    tmpsrc.data[0]++;
    gray16_to_gray(dst, &tmpsrc, width, height);
kostya's avatar
kostya committed
1730 1731 1732 1733 1734 1735 1736
}

static void gray16_to_gray16(AVPicture *dst, const AVPicture *src,
                              int width, int height)
{
    int x, y, src_wrap, dst_wrap;
    uint16_t *s, *d;
1737
    s = (uint16_t*)src->data[0];
kostya's avatar
kostya committed
1738
    src_wrap = (src->linesize[0] - width * 2)/2;
1739
    d = (uint16_t*)dst->data[0];
kostya's avatar
kostya committed
1740 1741 1742 1743 1744 1745 1746 1747 1748 1749 1750
    dst_wrap = (dst->linesize[0] - width * 2)/2;
    for(y=0; y<height; y++){
        for(x=0; x<width; x++){
            *d++ = bswap_16(*s++);
        }
        s += src_wrap;
        d += dst_wrap;
    }
}


1751
typedef struct ConvertEntry {
1752
    void (*convert)(AVPicture *dst,
1753
                    const AVPicture *src, int width, int height);
1754 1755
} ConvertEntry;

diego's avatar
diego committed
1756
/* Add each new conversion function in this table. In order to be able
1757 1758 1759
   to convert from any format to any format, the following constraints
   must be satisfied:

1760
   - all FF_COLOR_RGB formats must convert to and from PIX_FMT_RGB24
1761 1762 1763

   - all FF_COLOR_GRAY formats must convert to and from PIX_FMT_GRAY8

1764
   - all FF_COLOR_RGB formats with alpha must convert to and from PIX_FMT_RGB32
1765

bellard's avatar
bellard committed
1766
   - PIX_FMT_YUV444P and PIX_FMT_YUVJ444P must convert to and from
1767 1768 1769
     PIX_FMT_RGB24.

   - PIX_FMT_422 must convert to and from PIX_FMT_422P.
bellard's avatar
bellard committed
1770

vitor's avatar
vitor committed
1771
   The other conversion functions are just optimizations for common cases.
1772
*/
1773
static const ConvertEntry convert_table[PIX_FMT_NB][PIX_FMT_NB] = {
1774
    [PIX_FMT_YUV420P] = {
1775
        [PIX_FMT_YUYV422] = {
1776
            .convert = yuv420p_to_yuyv422,
1777
        },
1778
        [PIX_FMT_RGB555] = {
1779
            .convert = yuv420p_to_rgb555
1780
        },
1781
        [PIX_FMT_RGB565] = {
1782
            .convert = yuv420p_to_rgb565
1783
        },
1784
        [PIX_FMT_BGR24] = {
1785
            .convert = yuv420p_to_bgr24
1786
        },
1787
        [PIX_FMT_RGB24] = {
1788
            .convert = yuv420p_to_rgb24
1789
        },
1790
        [PIX_FMT_RGB32] = {
1791
            .convert = yuv420p_to_rgb32
1792
        },
1793
        [PIX_FMT_UYVY422] = {
1794 1795
            .convert = yuv420p_to_uyvy422,
        },
1796
    },
1797
    [PIX_FMT_YUV422P] = {
1798
        [PIX_FMT_YUYV422] = {
1799
            .convert = yuv422p_to_yuyv422,
1800
        },
1801
        [PIX_FMT_UYVY422] = {
1802 1803
            .convert = yuv422p_to_uyvy422,
        },
1804
    },
1805 1806
    [PIX_FMT_YUV444P] = {
        [PIX_FMT_RGB24] = {
1807 1808 1809 1810
            .convert = yuv444p_to_rgb24
        },
    },
    [PIX_FMT_YUVJ420P] = {
1811
        [PIX_FMT_RGB555] = {
1812
            .convert = yuvj420p_to_rgb555
1813
        },
1814
        [PIX_FMT_RGB565] = {
1815
            .convert = yuvj420p_to_rgb565
1816
        },
1817
        [PIX_FMT_BGR24] = {
1818
            .convert = yuvj420p_to_bgr24
1819
        },
1820
        [PIX_FMT_RGB24] = {
1821
            .convert = yuvj420p_to_rgb24
1822
        },
1823
        [PIX_FMT_RGB32] = {
1824
            .convert = yuvj420p_to_rgb32
1825 1826
        },
    },
1827 1828
    [PIX_FMT_YUVJ444P] = {
        [PIX_FMT_RGB24] = {
1829
            .convert = yuvj444p_to_rgb24
1830 1831
        },
    },
1832
    [PIX_FMT_YUYV422] = {
1833
        [PIX_FMT_YUV420P] = {
1834
            .convert = yuyv422_to_yuv420p,
1835
        },
1836
        [PIX_FMT_YUV422P] = {
1837
            .convert = yuyv422_to_yuv422p,
1838
        },
1839
    },
1840 1841
    [PIX_FMT_UYVY422] = {
        [PIX_FMT_YUV420P] = {
1842 1843
            .convert = uyvy422_to_yuv420p,
        },
1844
        [PIX_FMT_YUV422P] = {
1845 1846 1847
            .convert = uyvy422_to_yuv422p,
        },
    },
1848
    [PIX_FMT_RGB24] = {
1849
        [PIX_FMT_YUV420P] = {
1850
            .convert = rgb24_to_yuv420p
1851
        },
1852
        [PIX_FMT_RGB565] = {
1853
            .convert = rgb24_to_rgb565
1854
        },
1855
        [PIX_FMT_RGB555] = {
1856
            .convert = rgb24_to_rgb555
1857
        },
1858
        [PIX_FMT_RGB32] = {
1859
            .convert = rgb24_to_rgb32
1860
        },
1861
        [PIX_FMT_BGR24] = {
1862 1863
            .convert = rgb24_to_bgr24
        },
1864
        [PIX_FMT_GRAY8] = {
1865
            .convert = rgb24_to_gray
1866
        },
1867
        [PIX_FMT_PAL8] = {
1868 1869
            .convert = rgb24_to_pal8
        },
1870
        [PIX_FMT_YUV444P] = {
1871 1872
            .convert = rgb24_to_yuv444p
        },
1873
        [PIX_FMT_YUVJ420P] = {
1874 1875
            .convert = rgb24_to_yuvj420p
        },
1876
        [PIX_FMT_YUVJ444P] = {
1877 1878
            .convert = rgb24_to_yuvj444p
        },
1879
    },
1880
    [PIX_FMT_RGB32] = {
1881
        [PIX_FMT_RGB24] = {
1882
            .convert = rgb32_to_rgb24
1883
        },
1884
        [PIX_FMT_BGR24] = {
1885
            .convert = rgb32_to_bgr24
1886 1887
        },
        [PIX_FMT_RGB565] = {
1888
            .convert = rgb32_to_rgb565
1889
        },
1890
        [PIX_FMT_RGB555] = {
1891
            .convert = rgb32_to_rgb555
1892
        },
1893
        [PIX_FMT_PAL8] = {
1894
            .convert = rgb32_to_pal8
1895
        },
1896
        [PIX_FMT_YUV420P] = {
1897
            .convert = rgb32_to_yuv420p
1898
        },
1899
        [PIX_FMT_GRAY8] = {
1900
            .convert = rgb32_to_gray
1901
        },
1902 1903
    },
    [PIX_FMT_BGR24] = {
1904
        [PIX_FMT_RGB32] = {
1905
            .convert = bgr24_to_rgb32
1906
        },
1907
        [PIX_FMT_RGB24] = {
1908 1909
            .convert = bgr24_to_rgb24
        },
1910
        [PIX_FMT_YUV420P] = {
1911
            .convert = bgr24_to_yuv420p
1912
        },
1913
        [PIX_FMT_GRAY8] = {
1914 1915
            .convert = bgr24_to_gray
        },
1916 1917
    },
    [PIX_FMT_RGB555] = {
1918
        [PIX_FMT_RGB24] = {
1919 1920
            .convert = rgb555_to_rgb24
        },
1921
        [PIX_FMT_RGB32] = {
1922
            .convert = rgb555_to_rgb32
1923
        },
1924
        [PIX_FMT_YUV420P] = {
1925
            .convert = rgb555_to_yuv420p
1926
        },
1927
        [PIX_FMT_GRAY8] = {
1928 1929
            .convert = rgb555_to_gray
        },
1930 1931
    },
    [PIX_FMT_RGB565] = {
1932
        [PIX_FMT_RGB32] = {
1933
            .convert = rgb565_to_rgb32
1934
        },
1935
        [PIX_FMT_RGB24] = {
1936 1937
            .convert = rgb565_to_rgb24
        },
1938
        [PIX_FMT_YUV420P] = {
1939
            .convert = rgb565_to_yuv420p
1940
        },
1941
        [PIX_FMT_GRAY8] = {
1942 1943
            .convert = rgb565_to_gray
        },
1944
    },
kostya's avatar
kostya committed
1945 1946 1947 1948 1949 1950 1951 1952 1953 1954 1955 1956 1957 1958 1959 1960
    [PIX_FMT_GRAY16BE] = {
        [PIX_FMT_GRAY8] = {
            .convert = gray16be_to_gray
        },
        [PIX_FMT_GRAY16LE] = {
            .convert = gray16_to_gray16
        },
    },
    [PIX_FMT_GRAY16LE] = {
        [PIX_FMT_GRAY8] = {
            .convert = gray16le_to_gray
        },
        [PIX_FMT_GRAY16BE] = {
            .convert = gray16_to_gray16
        },
    },
1961
    [PIX_FMT_GRAY8] = {
1962
        [PIX_FMT_RGB555] = {
1963 1964
            .convert = gray_to_rgb555
        },
1965
        [PIX_FMT_RGB565] = {
1966 1967
            .convert = gray_to_rgb565
        },
1968
        [PIX_FMT_RGB24] = {
1969
            .convert = gray_to_rgb24
1970
        },
1971
        [PIX_FMT_BGR24] = {
1972 1973
            .convert = gray_to_bgr24
        },
1974
        [PIX_FMT_RGB32] = {
1975
            .convert = gray_to_rgb32
1976
        },
1977
        [PIX_FMT_MONOWHITE] = {
1978
            .convert = gray_to_monowhite
1979
        },
1980
        [PIX_FMT_MONOBLACK] = {
1981
            .convert = gray_to_monoblack
1982
        },
kostya's avatar
kostya committed
1983 1984 1985 1986 1987 1988
        [PIX_FMT_GRAY16LE] = {
            .convert = gray_to_gray16
        },
        [PIX_FMT_GRAY16BE] = {
            .convert = gray_to_gray16
        },
1989 1990
    },
    [PIX_FMT_MONOWHITE] = {
1991
        [PIX_FMT_GRAY8] = {
1992
            .convert = monowhite_to_gray
1993 1994 1995
        },
    },
    [PIX_FMT_MONOBLACK] = {
1996
        [PIX_FMT_GRAY8] = {
1997
            .convert = monoblack_to_gray
1998 1999
        },
    },
2000
    [PIX_FMT_PAL8] = {
2001
        [PIX_FMT_RGB555] = {
2002 2003
            .convert = pal8_to_rgb555
        },
2004
        [PIX_FMT_RGB565] = {
2005 2006
            .convert = pal8_to_rgb565
        },
2007
        [PIX_FMT_BGR24] = {
2008 2009
            .convert = pal8_to_bgr24
        },
2010
        [PIX_FMT_RGB24] = {
2011 2012
            .convert = pal8_to_rgb24
        },
2013
        [PIX_FMT_RGB32] = {
2014
            .convert = pal8_to_rgb32
2015 2016
        },
    },
2017
    [PIX_FMT_UYYVYY411] = {
2018
        [PIX_FMT_YUV411P] = {
2019
            .convert = uyyvyy411_to_yuv411p,
romansh's avatar
 
romansh committed
2020 2021 2022
        },
    },

2023 2024
};

michael's avatar
michael committed
2025
int avpicture_alloc(AVPicture *picture,
2026 2027
                           int pix_fmt, int width, int height)
{
2028
    int size;
2029 2030 2031
    void *ptr;

    size = avpicture_get_size(pix_fmt, width, height);
2032 2033
    if(size<0)
        goto fail;
2034 2035 2036 2037
    ptr = av_malloc(size);
    if (!ptr)
        goto fail;
    avpicture_fill(picture, ptr, pix_fmt, width, height);
2038 2039 2040
    if(picture->data[1] && !picture->data[2])
        ff_set_systematic_pal((uint32_t*)picture->data[1], pix_fmt);

2041 2042 2043 2044 2045 2046
    return 0;
 fail:
    memset(picture, 0, sizeof(AVPicture));
    return -1;
}

michael's avatar
michael committed
2047
void avpicture_free(AVPicture *picture)
2048
{
2049
    av_free(picture->data[0]);
2050 2051
}

2052
/* return true if yuv planar */
2053
static inline int is_yuv_planar(const PixFmtInfo *ps)
2054 2055
{
    return (ps->color_type == FF_COLOR_YUV ||
2056
            ps->color_type == FF_COLOR_YUV_JPEG) &&
2057
        ps->pixel_type == FF_PIXEL_PLANAR;
2058 2059
}

2060
int av_picture_crop(AVPicture *dst, const AVPicture *src,
2061 2062 2063 2064 2065 2066 2067 2068 2069 2070 2071 2072 2073 2074 2075 2076 2077 2078 2079 2080 2081
              int pix_fmt, int top_band, int left_band)
{
    int y_shift;
    int x_shift;

    if (pix_fmt < 0 || pix_fmt >= PIX_FMT_NB || !is_yuv_planar(&pix_fmt_info[pix_fmt]))
        return -1;

    y_shift = pix_fmt_info[pix_fmt].y_chroma_shift;
    x_shift = pix_fmt_info[pix_fmt].x_chroma_shift;

    dst->data[0] = src->data[0] + (top_band * src->linesize[0]) + left_band;
    dst->data[1] = src->data[1] + ((top_band >> y_shift) * src->linesize[1]) + (left_band >> x_shift);
    dst->data[2] = src->data[2] + ((top_band >> y_shift) * src->linesize[2]) + (left_band >> x_shift);

    dst->linesize[0] = src->linesize[0];
    dst->linesize[1] = src->linesize[1];
    dst->linesize[2] = src->linesize[2];
    return 0;
}

2082
int av_picture_pad(AVPicture *dst, const AVPicture *src, int height, int width,
lu_zero's avatar
lu_zero committed
2083 2084
            int pix_fmt, int padtop, int padbottom, int padleft, int padright,
            int *color)
2085
{
2086
    uint8_t *optr;
2087 2088 2089 2090 2091
    int y_shift;
    int x_shift;
    int yheight;
    int i, y;

lu_zero's avatar
lu_zero committed
2092 2093
    if (pix_fmt < 0 || pix_fmt >= PIX_FMT_NB ||
        !is_yuv_planar(&pix_fmt_info[pix_fmt])) return -1;
2094 2095 2096 2097 2098 2099

    for (i = 0; i < 3; i++) {
        x_shift = i ? pix_fmt_info[pix_fmt].x_chroma_shift : 0;
        y_shift = i ? pix_fmt_info[pix_fmt].y_chroma_shift : 0;

        if (padtop || padleft) {
lu_zero's avatar
lu_zero committed
2100 2101
            memset(dst->data[i], color[i],
                dst->linesize[i] * (padtop >> y_shift) + (padleft >> x_shift));
2102 2103
        }

2104 2105 2106 2107 2108 2109 2110
        if (padleft || padright) {
            optr = dst->data[i] + dst->linesize[i] * (padtop >> y_shift) +
                (dst->linesize[i] - (padright >> x_shift));
            yheight = (height - 1 - (padtop + padbottom)) >> y_shift;
            for (y = 0; y < yheight; y++) {
                memset(optr, color[i], (padleft + padright) >> x_shift);
                optr += dst->linesize[i];
2111
            }
2112 2113 2114 2115 2116 2117
        }

        if (src) { /* first line */
            uint8_t *iptr = src->data[i];
            optr = dst->data[i] + dst->linesize[i] * (padtop >> y_shift) +
                    (padleft >> x_shift);
2118
            memcpy(optr, iptr, (width - padleft - padright) >> x_shift);
2119
            iptr += src->linesize[i];
lu_zero's avatar
lu_zero committed
2120 2121
            optr = dst->data[i] + dst->linesize[i] * (padtop >> y_shift) +
                (dst->linesize[i] - (padright >> x_shift));
2122 2123 2124
            yheight = (height - 1 - (padtop + padbottom)) >> y_shift;
            for (y = 0; y < yheight; y++) {
                memset(optr, color[i], (padleft + padright) >> x_shift);
2125
                memcpy(optr + ((padleft + padright) >> x_shift), iptr,
2126
                       (width - padleft - padright) >> x_shift);
2127
                iptr += src->linesize[i];
2128 2129 2130 2131 2132
                optr += dst->linesize[i];
            }
        }

        if (padbottom || padright) {
lu_zero's avatar
lu_zero committed
2133 2134 2135 2136
            optr = dst->data[i] + dst->linesize[i] *
                ((height - padbottom) >> y_shift) - (padright >> x_shift);
            memset(optr, color[i],dst->linesize[i] *
                (padbottom >> y_shift) + (padright >> x_shift));
2137 2138 2139 2140 2141
        }
    }
    return 0;
}

2142
#if !CONFIG_SWSCALE
2143 2144 2145 2146 2147 2148 2149 2150 2151 2152 2153 2154 2155 2156 2157 2158 2159 2160 2161 2162 2163 2164 2165 2166 2167 2168 2169 2170 2171 2172 2173 2174 2175 2176 2177 2178 2179 2180 2181 2182 2183 2184 2185 2186 2187 2188 2189 2190 2191 2192 2193 2194 2195 2196 2197 2198 2199 2200 2201 2202 2203 2204 2205 2206 2207 2208 2209 2210 2211 2212 2213 2214 2215 2216 2217 2218 2219 2220 2221 2222 2223 2224 2225 2226 2227 2228 2229 2230 2231 2232 2233 2234 2235 2236 2237 2238 2239 2240 2241 2242 2243 2244 2245 2246 2247 2248 2249 2250 2251 2252 2253 2254 2255 2256 2257 2258 2259 2260 2261 2262 2263 2264 2265 2266 2267 2268 2269 2270 2271 2272 2273 2274 2275 2276 2277 2278 2279 2280 2281 2282 2283 2284 2285 2286 2287 2288 2289 2290 2291 2292 2293 2294 2295 2296 2297 2298 2299 2300 2301 2302 2303 2304 2305 2306 2307 2308 2309 2310 2311 2312 2313 2314 2315 2316 2317 2318 2319 2320 2321 2322 2323 2324 2325 2326 2327 2328 2329 2330 2331 2332 2333 2334 2335 2336 2337 2338 2339 2340 2341 2342 2343 2344 2345 2346 2347 2348 2349 2350 2351 2352 2353 2354 2355 2356 2357 2358 2359 2360 2361 2362 2363 2364 2365 2366 2367 2368 2369 2370 2371 2372 2373 2374 2375 2376 2377 2378 2379 2380 2381 2382 2383 2384 2385 2386 2387 2388 2389 2390 2391 2392 2393 2394 2395 2396 2397 2398 2399 2400 2401 2402 2403 2404 2405 2406 2407 2408 2409 2410 2411 2412 2413 2414 2415
static uint8_t y_ccir_to_jpeg[256];
static uint8_t y_jpeg_to_ccir[256];
static uint8_t c_ccir_to_jpeg[256];
static uint8_t c_jpeg_to_ccir[256];

/* init various conversion tables */
static void img_convert_init(void)
{
    int i;
    uint8_t *cm = ff_cropTbl + MAX_NEG_CROP;

    for(i = 0;i < 256; i++) {
        y_ccir_to_jpeg[i] = Y_CCIR_TO_JPEG(i);
        y_jpeg_to_ccir[i] = Y_JPEG_TO_CCIR(i);
        c_ccir_to_jpeg[i] = C_CCIR_TO_JPEG(i);
        c_jpeg_to_ccir[i] = C_JPEG_TO_CCIR(i);
    }
}

/* apply to each pixel the given table */
static void img_apply_table(uint8_t *dst, int dst_wrap,
                            const uint8_t *src, int src_wrap,
                            int width, int height, const uint8_t *table1)
{
    int n;
    const uint8_t *s;
    uint8_t *d;
    const uint8_t *table;

    table = table1;
    for(;height > 0; height--) {
        s = src;
        d = dst;
        n = width;
        while (n >= 4) {
            d[0] = table[s[0]];
            d[1] = table[s[1]];
            d[2] = table[s[2]];
            d[3] = table[s[3]];
            d += 4;
            s += 4;
            n -= 4;
        }
        while (n > 0) {
            d[0] = table[s[0]];
            d++;
            s++;
            n--;
        }
        dst += dst_wrap;
        src += src_wrap;
    }
}

/* XXX: use generic filter ? */
/* XXX: in most cases, the sampling position is incorrect */

/* 4x1 -> 1x1 */
static void shrink41(uint8_t *dst, int dst_wrap,
                     const uint8_t *src, int src_wrap,
                     int width, int height)
{
    int w;
    const uint8_t *s;
    uint8_t *d;

    for(;height > 0; height--) {
        s = src;
        d = dst;
        for(w = width;w > 0; w--) {
            d[0] = (s[0] + s[1] + s[2] + s[3] + 2) >> 2;
            s += 4;
            d++;
        }
        src += src_wrap;
        dst += dst_wrap;
    }
}

/* 2x1 -> 1x1 */
static void shrink21(uint8_t *dst, int dst_wrap,
                     const uint8_t *src, int src_wrap,
                     int width, int height)
{
    int w;
    const uint8_t *s;
    uint8_t *d;

    for(;height > 0; height--) {
        s = src;
        d = dst;
        for(w = width;w > 0; w--) {
            d[0] = (s[0] + s[1]) >> 1;
            s += 2;
            d++;
        }
        src += src_wrap;
        dst += dst_wrap;
    }
}

/* 1x2 -> 1x1 */
static void shrink12(uint8_t *dst, int dst_wrap,
                     const uint8_t *src, int src_wrap,
                     int width, int height)
{
    int w;
    uint8_t *d;
    const uint8_t *s1, *s2;

    for(;height > 0; height--) {
        s1 = src;
        s2 = s1 + src_wrap;
        d = dst;
        for(w = width;w >= 4; w-=4) {
            d[0] = (s1[0] + s2[0]) >> 1;
            d[1] = (s1[1] + s2[1]) >> 1;
            d[2] = (s1[2] + s2[2]) >> 1;
            d[3] = (s1[3] + s2[3]) >> 1;
            s1 += 4;
            s2 += 4;
            d += 4;
        }
        for(;w > 0; w--) {
            d[0] = (s1[0] + s2[0]) >> 1;
            s1++;
            s2++;
            d++;
        }
        src += 2 * src_wrap;
        dst += dst_wrap;
    }
}

static void grow21_line(uint8_t *dst, const uint8_t *src,
                        int width)
{
    int w;
    const uint8_t *s1;
    uint8_t *d;

    s1 = src;
    d = dst;
    for(w = width;w >= 4; w-=4) {
        d[1] = d[0] = s1[0];
        d[3] = d[2] = s1[1];
        s1 += 2;
        d += 4;
    }
    for(;w >= 2; w -= 2) {
        d[1] = d[0] = s1[0];
        s1 ++;
        d += 2;
    }
    /* only needed if width is not a multiple of two */
    /* XXX: veryfy that */
    if (w) {
        d[0] = s1[0];
    }
}

static void grow41_line(uint8_t *dst, const uint8_t *src,
                        int width)
{
    int w, v;
    const uint8_t *s1;
    uint8_t *d;

    s1 = src;
    d = dst;
    for(w = width;w >= 4; w-=4) {
        v = s1[0];
        d[0] = v;
        d[1] = v;
        d[2] = v;
        d[3] = v;
        s1 ++;
        d += 4;
    }
}

/* 1x1 -> 2x1 */
static void grow21(uint8_t *dst, int dst_wrap,
                   const uint8_t *src, int src_wrap,
                   int width, int height)
{
    for(;height > 0; height--) {
        grow21_line(dst, src, width);
        src += src_wrap;
        dst += dst_wrap;
    }
}

/* 1x1 -> 1x2 */
static void grow12(uint8_t *dst, int dst_wrap,
                   const uint8_t *src, int src_wrap,
                   int width, int height)
{
    for(;height > 0; height-=2) {
        memcpy(dst, src, width);
        dst += dst_wrap;
        memcpy(dst, src, width);
        dst += dst_wrap;
        src += src_wrap;
    }
}

/* 1x1 -> 2x2 */
static void grow22(uint8_t *dst, int dst_wrap,
                   const uint8_t *src, int src_wrap,
                   int width, int height)
{
    for(;height > 0; height--) {
        grow21_line(dst, src, width);
        if (height%2)
            src += src_wrap;
        dst += dst_wrap;
    }
}

/* 1x1 -> 4x1 */
static void grow41(uint8_t *dst, int dst_wrap,
                   const uint8_t *src, int src_wrap,
                   int width, int height)
{
    for(;height > 0; height--) {
        grow41_line(dst, src, width);
        src += src_wrap;
        dst += dst_wrap;
    }
}

/* 1x1 -> 4x4 */
static void grow44(uint8_t *dst, int dst_wrap,
                   const uint8_t *src, int src_wrap,
                   int width, int height)
{
    for(;height > 0; height--) {
        grow41_line(dst, src, width);
        if ((height & 3) == 1)
            src += src_wrap;
        dst += dst_wrap;
    }
}

/* 1x2 -> 2x1 */
static void conv411(uint8_t *dst, int dst_wrap,
                    const uint8_t *src, int src_wrap,
                    int width, int height)
{
    int w, c;
    const uint8_t *s1, *s2;
    uint8_t *d;

    width>>=1;

    for(;height > 0; height--) {
        s1 = src;
        s2 = src + src_wrap;
        d = dst;
        for(w = width;w > 0; w--) {
            c = (s1[0] + s2[0]) >> 1;
            d[0] = c;
            d[1] = c;
            s1++;
            s2++;
            d += 2;
        }
        src += src_wrap * 2;
        dst += dst_wrap;
    }
}

2416 2417
/* XXX: always use linesize. Return -1 if not supported */
int img_convert(AVPicture *dst, int dst_pix_fmt,
2418
                const AVPicture *src, int src_pix_fmt,
2419
                int src_width, int src_height)
2420
{
diego's avatar
diego committed
2421
    static int initialized;
2422
    int i, ret, dst_width, dst_height, int_pix_fmt;
2423 2424
    const PixFmtInfo *src_pix, *dst_pix;
    const ConvertEntry *ce;
2425 2426 2427 2428 2429 2430 2431
    AVPicture tmp1, *tmp = &tmp1;

    if (src_pix_fmt < 0 || src_pix_fmt >= PIX_FMT_NB ||
        dst_pix_fmt < 0 || dst_pix_fmt >= PIX_FMT_NB)
        return -1;
    if (src_width <= 0 || src_height <= 0)
        return 0;
2432

diego's avatar
diego committed
2433 2434
    if (!initialized) {
        initialized = 1;
2435 2436 2437
        img_convert_init();
    }

2438 2439
    dst_width = src_width;
    dst_height = src_height;
2440

2441 2442 2443
    dst_pix = &pix_fmt_info[dst_pix_fmt];
    src_pix = &pix_fmt_info[src_pix_fmt];
    if (src_pix_fmt == dst_pix_fmt) {
2444
        /* no conversion needed: just copy */
2445
        av_picture_copy(dst, src, dst_pix_fmt, dst_width, dst_height);
2446 2447 2448 2449 2450
        return 0;
    }

    ce = &convert_table[src_pix_fmt][dst_pix_fmt];
    if (ce->convert) {
2451
        /* specific conversion routine */
2452 2453 2454 2455 2456
        ce->convert(dst, src, dst_width, dst_height);
        return 0;
    }

    /* gray to YUV */
2457
    if (is_yuv_planar(dst_pix) &&
2458
        src_pix_fmt == PIX_FMT_GRAY8) {
2459 2460 2461
        int w, h, y;
        uint8_t *d;

2462
        if (dst_pix->color_type == FF_COLOR_YUV_JPEG) {
2463
            ff_img_copy_plane(dst->data[0], dst->linesize[0],
2464 2465 2466
                     src->data[0], src->linesize[0],
                     dst_width, dst_height);
        } else {
2467 2468 2469 2470
            img_apply_table(dst->data[0], dst->linesize[0],
                            src->data[0], src->linesize[0],
                            dst_width, dst_height,
                            y_jpeg_to_ccir);
2471
        }
2472 2473 2474 2475 2476 2477 2478
        /* fill U and V with 128 */
        w = dst_width;
        h = dst_height;
        w >>= dst_pix->x_chroma_shift;
        h >>= dst_pix->y_chroma_shift;
        for(i = 1; i <= 2; i++) {
            d = dst->data[i];
2479 2480
            for(y = 0; y< h; y++) {
                memset(d, 128, w);
2481 2482
                d += dst->linesize[i];
            }
2483
        }
2484 2485 2486 2487
        return 0;
    }

    /* YUV to gray */
2488
    if (is_yuv_planar(src_pix) &&
2489 2490
        dst_pix_fmt == PIX_FMT_GRAY8) {
        if (src_pix->color_type == FF_COLOR_YUV_JPEG) {
2491
            ff_img_copy_plane(dst->data[0], dst->linesize[0],
2492 2493 2494
                     src->data[0], src->linesize[0],
                     dst_width, dst_height);
        } else {
2495 2496 2497 2498
            img_apply_table(dst->data[0], dst->linesize[0],
                            src->data[0], src->linesize[0],
                            dst_width, dst_height,
                            y_ccir_to_jpeg);
2499
        }
2500 2501 2502
        return 0;
    }

2503 2504
    /* YUV to YUV planar */
    if (is_yuv_planar(dst_pix) && is_yuv_planar(src_pix)) {
bellard's avatar
bellard committed
2505
        int x_shift, y_shift, w, h, xy_shift;
2506
        void (*resize_func)(uint8_t *dst, int dst_wrap,
bellard's avatar
bellard committed
2507
                            const uint8_t *src, int src_wrap,
2508 2509 2510 2511 2512 2513 2514 2515 2516 2517 2518 2519 2520 2521 2522 2523
                            int width, int height);

        /* compute chroma size of the smallest dimensions */
        w = dst_width;
        h = dst_height;
        if (dst_pix->x_chroma_shift >= src_pix->x_chroma_shift)
            w >>= dst_pix->x_chroma_shift;
        else
            w >>= src_pix->x_chroma_shift;
        if (dst_pix->y_chroma_shift >= src_pix->y_chroma_shift)
            h >>= dst_pix->y_chroma_shift;
        else
            h >>= src_pix->y_chroma_shift;

        x_shift = (dst_pix->x_chroma_shift - src_pix->x_chroma_shift);
        y_shift = (dst_pix->y_chroma_shift - src_pix->y_chroma_shift);
bellard's avatar
bellard committed
2524 2525 2526 2527 2528
        xy_shift = ((x_shift & 0xf) << 4) | (y_shift & 0xf);
        /* there must be filters for conversion at least from and to
           YUV444 format */
        switch(xy_shift) {
        case 0x00:
2529
            resize_func = ff_img_copy_plane;
bellard's avatar
bellard committed
2530 2531 2532 2533 2534 2535 2536 2537 2538 2539 2540
            break;
        case 0x10:
            resize_func = shrink21;
            break;
        case 0x20:
            resize_func = shrink41;
            break;
        case 0x01:
            resize_func = shrink12;
            break;
        case 0x11:
2541
            resize_func = ff_shrink22;
bellard's avatar
bellard committed
2542 2543
            break;
        case 0x22:
2544
            resize_func = ff_shrink44;
bellard's avatar
bellard committed
2545 2546 2547 2548
            break;
        case 0xf0:
            resize_func = grow21;
            break;
benoit's avatar
benoit committed
2549 2550 2551
        case 0x0f:
            resize_func = grow12;
            break;
bellard's avatar
bellard committed
2552 2553 2554 2555
        case 0xe0:
            resize_func = grow41;
            break;
        case 0xff:
2556
            resize_func = grow22;
bellard's avatar
bellard committed
2557 2558 2559 2560 2561
            break;
        case 0xee:
            resize_func = grow44;
            break;
        case 0xf1:
2562
            resize_func = conv411;
bellard's avatar
bellard committed
2563 2564
            break;
        default:
2565
            /* currently not handled */
bellard's avatar
bellard committed
2566
            goto no_chroma_filter;
2567
        }
2568

2569
        ff_img_copy_plane(dst->data[0], dst->linesize[0],
2570 2571
                       src->data[0], src->linesize[0],
                       dst_width, dst_height);
2572

2573
        for(i = 1;i <= 2; i++)
2574 2575
            resize_func(dst->data[i], dst->linesize[i],
                        src->data[i], src->linesize[i],
michaelni's avatar
michaelni committed
2576
                        dst_width>>dst_pix->x_chroma_shift, dst_height>>dst_pix->y_chroma_shift);
2577 2578 2579 2580 2581 2582 2583 2584 2585 2586 2587 2588 2589 2590 2591 2592 2593 2594 2595
        /* if yuv color space conversion is needed, we do it here on
           the destination image */
        if (dst_pix->color_type != src_pix->color_type) {
            const uint8_t *y_table, *c_table;
            if (dst_pix->color_type == FF_COLOR_YUV) {
                y_table = y_jpeg_to_ccir;
                c_table = c_jpeg_to_ccir;
            } else {
                y_table = y_ccir_to_jpeg;
                c_table = c_ccir_to_jpeg;
            }
            img_apply_table(dst->data[0], dst->linesize[0],
                            dst->data[0], dst->linesize[0],
                            dst_width, dst_height,
                            y_table);

            for(i = 1;i <= 2; i++)
                img_apply_table(dst->data[i], dst->linesize[i],
                                dst->data[i], dst->linesize[i],
2596
                                dst_width>>dst_pix->x_chroma_shift,
2597 2598 2599 2600
                                dst_height>>dst_pix->y_chroma_shift,
                                c_table);
        }
        return 0;
2601
    }
bellard's avatar
bellard committed
2602
 no_chroma_filter:
2603

2604
    /* try to use an intermediate format */
2605 2606
    if (src_pix_fmt == PIX_FMT_YUYV422 ||
        dst_pix_fmt == PIX_FMT_YUYV422) {
2607 2608
        /* specific case: convert to YUV422P first */
        int_pix_fmt = PIX_FMT_YUV422P;
2609 2610 2611 2612
    } else if (src_pix_fmt == PIX_FMT_UYVY422 ||
        dst_pix_fmt == PIX_FMT_UYVY422) {
        /* specific case: convert to YUV422P first */
        int_pix_fmt = PIX_FMT_YUV422P;
2613 2614
    } else if (src_pix_fmt == PIX_FMT_UYYVYY411 ||
        dst_pix_fmt == PIX_FMT_UYYVYY411) {
romansh's avatar
 
romansh committed
2615 2616
        /* specific case: convert to YUV411P first */
        int_pix_fmt = PIX_FMT_YUV411P;
2617
    } else if ((src_pix->color_type == FF_COLOR_GRAY &&
2618
                src_pix_fmt != PIX_FMT_GRAY8) ||
2619 2620 2621
               (dst_pix->color_type == FF_COLOR_GRAY &&
                dst_pix_fmt != PIX_FMT_GRAY8)) {
        /* gray8 is the normalized format */
2622
        int_pix_fmt = PIX_FMT_GRAY8;
2623
    } else if ((is_yuv_planar(src_pix) &&
2624 2625 2626 2627 2628 2629 2630
                src_pix_fmt != PIX_FMT_YUV444P &&
                src_pix_fmt != PIX_FMT_YUVJ444P)) {
        /* yuv444 is the normalized format */
        if (src_pix->color_type == FF_COLOR_YUV_JPEG)
            int_pix_fmt = PIX_FMT_YUVJ444P;
        else
            int_pix_fmt = PIX_FMT_YUV444P;
2631
    } else if ((is_yuv_planar(dst_pix) &&
2632 2633 2634 2635 2636 2637 2638
                dst_pix_fmt != PIX_FMT_YUV444P &&
                dst_pix_fmt != PIX_FMT_YUVJ444P)) {
        /* yuv444 is the normalized format */
        if (dst_pix->color_type == FF_COLOR_YUV_JPEG)
            int_pix_fmt = PIX_FMT_YUVJ444P;
        else
            int_pix_fmt = PIX_FMT_YUV444P;
2639
    } else {
2640 2641
        /* the two formats are rgb or gray8 or yuv[j]444p */
        if (src_pix->is_alpha && dst_pix->is_alpha)
2642
            int_pix_fmt = PIX_FMT_RGB32;
2643 2644
        else
            int_pix_fmt = PIX_FMT_RGB24;
2645
    }
2646 2647
    if (src_pix_fmt == int_pix_fmt)
        return -1;
2648 2649 2650 2651 2652 2653 2654 2655 2656 2657 2658 2659 2660
    if (avpicture_alloc(tmp, int_pix_fmt, dst_width, dst_height) < 0)
        return -1;
    ret = -1;
    if (img_convert(tmp, int_pix_fmt,
                    src, src_pix_fmt, src_width, src_height) < 0)
        goto fail1;
    if (img_convert(dst, dst_pix_fmt,
                    tmp, int_pix_fmt, dst_width, dst_height) < 0)
        goto fail1;
    ret = 0;
 fail1:
    avpicture_free(tmp);
    return ret;
2661
}
lucabe's avatar
lucabe committed
2662
#endif
2663

bellard's avatar
bellard committed
2664
/* NOTE: we scan all the pixels to have an exact information */
2665
static int get_alpha_info_pal8(const AVPicture *src, int width, int height)
bellard's avatar
bellard committed
2666 2667 2668 2669 2670
{
    const unsigned char *p;
    int src_wrap, ret, x, y;
    unsigned int a;
    uint32_t *palette = (uint32_t *)src->data[1];
2671

bellard's avatar
bellard committed
2672 2673 2674 2675 2676 2677 2678 2679 2680 2681 2682 2683 2684 2685 2686 2687 2688 2689
    p = src->data[0];
    src_wrap = src->linesize[0] - width;
    ret = 0;
    for(y=0;y<height;y++) {
        for(x=0;x<width;x++) {
            a = palette[p[0]] >> 24;
            if (a == 0x00) {
                ret |= FF_ALPHA_TRANSP;
            } else if (a != 0xff) {
                ret |= FF_ALPHA_SEMI_TRANSP;
            }
            p++;
        }
        p += src_wrap;
    }
    return ret;
}

2690
int img_get_alpha_info(const AVPicture *src,
2691
                       int pix_fmt, int width, int height)
bellard's avatar
bellard committed
2692
{
2693
    const PixFmtInfo *pf = &pix_fmt_info[pix_fmt];
bellard's avatar
bellard committed
2694 2695 2696 2697 2698 2699 2700
    int ret;

    pf = &pix_fmt_info[pix_fmt];
    /* no alpha can be represented in format */
    if (!pf->is_alpha)
        return 0;
    switch(pix_fmt) {
2701
    case PIX_FMT_RGB32:
2702
        ret = get_alpha_info_rgb32(src, width, height);
bellard's avatar
bellard committed
2703 2704 2705 2706 2707 2708 2709 2710 2711 2712 2713
        break;
    case PIX_FMT_PAL8:
        ret = get_alpha_info_pal8(src, width, height);
        break;
    default:
        /* we do not know, so everything is indicated */
        ret = FF_ALPHA_TRANSP | FF_ALPHA_SEMI_TRANSP;
        break;
    }
    return ret;
}
michaelni's avatar
michaelni committed
2714

2715
#if HAVE_MMX
michaelni's avatar
michaelni committed
2716 2717 2718 2719 2720 2721 2722 2723 2724 2725 2726 2727 2728 2729 2730 2731 2732 2733 2734 2735 2736 2737 2738 2739 2740 2741 2742 2743 2744 2745 2746 2747 2748 2749 2750 2751 2752 2753 2754 2755 2756 2757 2758 2759 2760 2761
#define DEINT_INPLACE_LINE_LUM \
                    movd_m2r(lum_m4[0],mm0);\
                    movd_m2r(lum_m3[0],mm1);\
                    movd_m2r(lum_m2[0],mm2);\
                    movd_m2r(lum_m1[0],mm3);\
                    movd_m2r(lum[0],mm4);\
                    punpcklbw_r2r(mm7,mm0);\
                    movd_r2m(mm2,lum_m4[0]);\
                    punpcklbw_r2r(mm7,mm1);\
                    punpcklbw_r2r(mm7,mm2);\
                    punpcklbw_r2r(mm7,mm3);\
                    punpcklbw_r2r(mm7,mm4);\
                    paddw_r2r(mm3,mm1);\
                    psllw_i2r(1,mm2);\
                    paddw_r2r(mm4,mm0);\
                    psllw_i2r(2,mm1);\
                    paddw_r2r(mm6,mm2);\
                    paddw_r2r(mm2,mm1);\
                    psubusw_r2r(mm0,mm1);\
                    psrlw_i2r(3,mm1);\
                    packuswb_r2r(mm7,mm1);\
                    movd_r2m(mm1,lum_m2[0]);

#define DEINT_LINE_LUM \
                    movd_m2r(lum_m4[0],mm0);\
                    movd_m2r(lum_m3[0],mm1);\
                    movd_m2r(lum_m2[0],mm2);\
                    movd_m2r(lum_m1[0],mm3);\
                    movd_m2r(lum[0],mm4);\
                    punpcklbw_r2r(mm7,mm0);\
                    punpcklbw_r2r(mm7,mm1);\
                    punpcklbw_r2r(mm7,mm2);\
                    punpcklbw_r2r(mm7,mm3);\
                    punpcklbw_r2r(mm7,mm4);\
                    paddw_r2r(mm3,mm1);\
                    psllw_i2r(1,mm2);\
                    paddw_r2r(mm4,mm0);\
                    psllw_i2r(2,mm1);\
                    paddw_r2r(mm6,mm2);\
                    paddw_r2r(mm2,mm1);\
                    psubusw_r2r(mm0,mm1);\
                    psrlw_i2r(3,mm1);\
                    packuswb_r2r(mm7,mm1);\
                    movd_r2m(mm1,dst[0]);
#endif

2762
/* filter parameters: [-1 4 2 4 -1] // 8 */
2763
static void deinterlace_line(uint8_t *dst,
2764 2765 2766 2767
                             const uint8_t *lum_m4, const uint8_t *lum_m3,
                             const uint8_t *lum_m2, const uint8_t *lum_m1,
                             const uint8_t *lum,
                             int size)
2768
{
2769
#if !HAVE_MMX
mru's avatar
mru committed
2770
    uint8_t *cm = ff_cropTbl + MAX_NEG_CROP;
2771 2772 2773
    int sum;

    for(;size > 0;size--) {
michaelni's avatar
michaelni committed
2774 2775 2776 2777 2778
        sum = -lum_m4[0];
        sum += lum_m3[0] << 2;
        sum += lum_m2[0] << 1;
        sum += lum_m1[0] << 2;
        sum += -lum[0];
2779
        dst[0] = cm[(sum + 4) >> 3];
michaelni's avatar
michaelni committed
2780 2781 2782 2783 2784
        lum_m4++;
        lum_m3++;
        lum_m2++;
        lum_m1++;
        lum++;
2785 2786
        dst++;
    }
michaelni's avatar
michaelni committed
2787 2788
#else

michaelni's avatar
michaelni committed
2789 2790
    {
        pxor_r2r(mm7,mm7);
aurel's avatar
aurel committed
2791
        movq_m2r(ff_pw_4,mm6);
michaelni's avatar
michaelni committed
2792
    }
michaelni's avatar
michaelni committed
2793 2794 2795 2796 2797 2798 2799 2800 2801 2802 2803
    for (;size > 3; size-=4) {
        DEINT_LINE_LUM
        lum_m4+=4;
        lum_m3+=4;
        lum_m2+=4;
        lum_m1+=4;
        lum+=4;
        dst+=4;
    }
#endif
}
kabi's avatar
kabi committed
2804
static void deinterlace_line_inplace(uint8_t *lum_m4, uint8_t *lum_m3, uint8_t *lum_m2, uint8_t *lum_m1, uint8_t *lum,
michaelni's avatar
michaelni committed
2805 2806
                             int size)
{
2807
#if !HAVE_MMX
mru's avatar
mru committed
2808
    uint8_t *cm = ff_cropTbl + MAX_NEG_CROP;
michaelni's avatar
michaelni committed
2809 2810 2811 2812 2813 2814 2815 2816 2817 2818 2819 2820 2821 2822 2823 2824 2825 2826
    int sum;

    for(;size > 0;size--) {
        sum = -lum_m4[0];
        sum += lum_m3[0] << 2;
        sum += lum_m2[0] << 1;
        lum_m4[0]=lum_m2[0];
        sum += lum_m1[0] << 2;
        sum += -lum[0];
        lum_m2[0] = cm[(sum + 4) >> 3];
        lum_m4++;
        lum_m3++;
        lum_m2++;
        lum_m1++;
        lum++;
    }
#else

michaelni's avatar
michaelni committed
2827 2828
    {
        pxor_r2r(mm7,mm7);
aurel's avatar
aurel committed
2829
        movq_m2r(ff_pw_4,mm6);
michaelni's avatar
michaelni committed
2830
    }
michaelni's avatar
michaelni committed
2831 2832 2833 2834 2835 2836 2837 2838 2839
    for (;size > 3; size-=4) {
        DEINT_INPLACE_LINE_LUM
        lum_m4+=4;
        lum_m3+=4;
        lum_m2+=4;
        lum_m1+=4;
        lum+=4;
    }
#endif
2840 2841 2842 2843 2844
}

/* deinterlacing : 2 temporal taps, 3 spatial taps linear filter. The
   top field is copied as is, but the bottom field is deinterlaced
   against the top field. */
kabi's avatar
kabi committed
2845
static void deinterlace_bottom_field(uint8_t *dst, int dst_wrap,
2846
                                    const uint8_t *src1, int src_wrap,
michaelni's avatar
michaelni committed
2847
                                    int width, int height)
2848
{
2849
    const uint8_t *src_m2, *src_m1, *src_0, *src_p1, *src_p2;
michaelni's avatar
michaelni committed
2850 2851 2852 2853 2854 2855 2856 2857 2858
    int y;

    src_m2 = src1;
    src_m1 = src1;
    src_0=&src_m1[src_wrap];
    src_p1=&src_0[src_wrap];
    src_p2=&src_p1[src_wrap];
    for(y=0;y<(height-2);y+=2) {
        memcpy(dst,src_m1,width);
2859
        dst += dst_wrap;
michaelni's avatar
michaelni committed
2860 2861 2862 2863 2864 2865
        deinterlace_line(dst,src_m2,src_m1,src_0,src_p1,src_p2,width);
        src_m2 = src_0;
        src_m1 = src_p1;
        src_0 = src_p2;
        src_p1 += 2*src_wrap;
        src_p2 += 2*src_wrap;
2866 2867
        dst += dst_wrap;
    }
michaelni's avatar
michaelni committed
2868 2869 2870 2871 2872 2873
    memcpy(dst,src_m1,width);
    dst += dst_wrap;
    /* do last line */
    deinterlace_line(dst,src_m2,src_m1,src_0,src_0,src_0,width);
}

kabi's avatar
kabi committed
2874
static void deinterlace_bottom_field_inplace(uint8_t *src1, int src_wrap,
2875
                                             int width, int height)
michaelni's avatar
michaelni committed
2876
{
kabi's avatar
kabi committed
2877
    uint8_t *src_m1, *src_0, *src_p1, *src_p2;
michaelni's avatar
michaelni committed
2878
    int y;
kabi's avatar
kabi committed
2879 2880
    uint8_t *buf;
    buf = (uint8_t*)av_malloc(width);
michaelni's avatar
michaelni committed
2881 2882 2883 2884 2885 2886 2887 2888 2889 2890 2891 2892 2893 2894 2895

    src_m1 = src1;
    memcpy(buf,src_m1,width);
    src_0=&src_m1[src_wrap];
    src_p1=&src_0[src_wrap];
    src_p2=&src_p1[src_wrap];
    for(y=0;y<(height-2);y+=2) {
        deinterlace_line_inplace(buf,src_m1,src_0,src_p1,src_p2,width);
        src_m1 = src_p1;
        src_0 = src_p2;
        src_p1 += 2*src_wrap;
        src_p2 += 2*src_wrap;
    }
    /* do last line */
    deinterlace_line_inplace(buf,src_m1,src_0,src_0,src_0,width);
2896
    av_free(buf);
2897 2898
}

2899
int avpicture_deinterlace(AVPicture *dst, const AVPicture *src,
glantau's avatar
glantau committed
2900 2901
                          int pix_fmt, int width, int height)
{
2902 2903 2904 2905
    int i;

    if (pix_fmt != PIX_FMT_YUV420P &&
        pix_fmt != PIX_FMT_YUV422P &&
romansh's avatar
 
romansh committed
2906
        pix_fmt != PIX_FMT_YUV444P &&
2907 2908
        pix_fmt != PIX_FMT_YUV411P &&
        pix_fmt != PIX_FMT_GRAY8)
2909
        return -1;
michaelni's avatar
michaelni committed
2910
    if ((width & 3) != 0 || (height & 3) != 0)
2911
        return -1;
michaelni's avatar
michaelni committed
2912

2913 2914 2915 2916 2917 2918 2919 2920 2921 2922
    for(i=0;i<3;i++) {
        if (i == 1) {
            switch(pix_fmt) {
            case PIX_FMT_YUV420P:
                width >>= 1;
                height >>= 1;
                break;
            case PIX_FMT_YUV422P:
                width >>= 1;
                break;
romansh's avatar
 
romansh committed
2923 2924 2925
            case PIX_FMT_YUV411P:
                width >>= 2;
                break;
2926 2927 2928
            default:
                break;
            }
2929 2930 2931
            if (pix_fmt == PIX_FMT_GRAY8) {
                break;
            }
2932
        }
michaelni's avatar
michaelni committed
2933
        if (src == dst) {
2934
            deinterlace_bottom_field_inplace(dst->data[i], dst->linesize[i],
2935
                                 width, height);
michaelni's avatar
michaelni committed
2936 2937 2938 2939 2940
        } else {
            deinterlace_bottom_field(dst->data[i],dst->linesize[i],
                                        src->data[i], src->linesize[i],
                                        width, height);
        }
glantau's avatar
glantau committed
2941
    }
andoma's avatar
andoma committed
2942
    emms_c();
2943
    return 0;
glantau's avatar
glantau committed
2944
}
2945