xref: /third_party/ffmpeg/libswscale/hscale.c (revision cabdff1a)
1/*
2 * Copyright (C) 2015 Pedro Arthur <bygrandao@gmail.com>
3 *
4 * This file is part of FFmpeg.
5 *
6 * FFmpeg is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * FFmpeg is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with FFmpeg; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19 */
20
21#include "swscale_internal.h"
22
23/// Scaler instance data
24typedef struct FilterContext
25{
26    uint16_t *filter;
27    int *filter_pos;
28    int filter_size;
29    int xInc;
30} FilterContext;
31
32/// Color conversion instance data
33typedef struct ColorContext
34{
35    uint32_t *pal;
36} ColorContext;
37
38static int lum_h_scale(SwsContext *c, SwsFilterDescriptor *desc, int sliceY, int sliceH)
39{
40    FilterContext *instance = desc->instance;
41    int srcW = desc->src->width;
42    int dstW = desc->dst->width;
43    int xInc = instance->xInc;
44
45    int i;
46    for (i = 0; i < sliceH; ++i) {
47        uint8_t ** src = desc->src->plane[0].line;
48        uint8_t ** dst = desc->dst->plane[0].line;
49        int src_pos = sliceY+i - desc->src->plane[0].sliceY;
50        int dst_pos = sliceY+i - desc->dst->plane[0].sliceY;
51
52
53        if (c->hyscale_fast) {
54            c->hyscale_fast(c, (int16_t*)dst[dst_pos], dstW, src[src_pos], srcW, xInc);
55        } else {
56            c->hyScale(c, (int16_t*)dst[dst_pos], dstW, (const uint8_t *)src[src_pos], instance->filter,
57                       instance->filter_pos, instance->filter_size);
58        }
59
60        if (c->lumConvertRange)
61            c->lumConvertRange((int16_t*)dst[dst_pos], dstW);
62
63        desc->dst->plane[0].sliceH += 1;
64
65        if (desc->alpha) {
66            src = desc->src->plane[3].line;
67            dst = desc->dst->plane[3].line;
68
69            src_pos = sliceY+i - desc->src->plane[3].sliceY;
70            dst_pos = sliceY+i - desc->dst->plane[3].sliceY;
71
72            desc->dst->plane[3].sliceH += 1;
73
74            if (c->hyscale_fast) {
75                c->hyscale_fast(c, (int16_t*)dst[dst_pos], dstW, src[src_pos], srcW, xInc);
76            } else {
77                c->hyScale(c, (int16_t*)dst[dst_pos], dstW, (const uint8_t *)src[src_pos], instance->filter,
78                            instance->filter_pos, instance->filter_size);
79            }
80        }
81    }
82
83    return sliceH;
84}
85
86static int lum_convert(SwsContext *c, SwsFilterDescriptor *desc, int sliceY, int sliceH)
87{
88    int srcW = desc->src->width;
89    ColorContext * instance = desc->instance;
90    uint32_t * pal = instance->pal;
91    int i;
92
93    desc->dst->plane[0].sliceY = sliceY;
94    desc->dst->plane[0].sliceH = sliceH;
95    desc->dst->plane[3].sliceY = sliceY;
96    desc->dst->plane[3].sliceH = sliceH;
97
98    for (i = 0; i < sliceH; ++i) {
99        int sp0 = sliceY+i - desc->src->plane[0].sliceY;
100        int sp1 = ((sliceY+i) >> desc->src->v_chr_sub_sample) - desc->src->plane[1].sliceY;
101        const uint8_t * src[4] = { desc->src->plane[0].line[sp0],
102                        desc->src->plane[1].line[sp1],
103                        desc->src->plane[2].line[sp1],
104                        desc->src->plane[3].line[sp0]};
105        uint8_t * dst = desc->dst->plane[0].line[i];
106
107        if (c->lumToYV12) {
108            c->lumToYV12(dst, src[0], src[1], src[2], srcW, pal);
109        } else if (c->readLumPlanar) {
110            c->readLumPlanar(dst, src, srcW, c->input_rgb2yuv_table);
111        }
112
113
114        if (desc->alpha) {
115            dst = desc->dst->plane[3].line[i];
116            if (c->alpToYV12) {
117                c->alpToYV12(dst, src[3], src[1], src[2], srcW, pal);
118            } else if (c->readAlpPlanar) {
119                c->readAlpPlanar(dst, src, srcW, NULL);
120            }
121        }
122    }
123
124    return sliceH;
125}
126
127int ff_init_desc_fmt_convert(SwsFilterDescriptor *desc, SwsSlice * src, SwsSlice *dst, uint32_t *pal)
128{
129    ColorContext * li = av_malloc(sizeof(ColorContext));
130    if (!li)
131        return AVERROR(ENOMEM);
132    li->pal = pal;
133    desc->instance = li;
134
135    desc->alpha = isALPHA(src->fmt) && isALPHA(dst->fmt);
136    desc->src =src;
137    desc->dst = dst;
138    desc->process = &lum_convert;
139
140    return 0;
141}
142
143
144int ff_init_desc_hscale(SwsFilterDescriptor *desc, SwsSlice *src, SwsSlice *dst, uint16_t *filter, int * filter_pos, int filter_size, int xInc)
145{
146    FilterContext *li = av_malloc(sizeof(FilterContext));
147    if (!li)
148        return AVERROR(ENOMEM);
149
150    li->filter = filter;
151    li->filter_pos = filter_pos;
152    li->filter_size = filter_size;
153    li->xInc = xInc;
154
155    desc->instance = li;
156
157    desc->alpha = isALPHA(src->fmt) && isALPHA(dst->fmt);
158    desc->src = src;
159    desc->dst = dst;
160
161    desc->process = &lum_h_scale;
162
163    return 0;
164}
165
166static int chr_h_scale(SwsContext *c, SwsFilterDescriptor *desc, int sliceY, int sliceH)
167{
168    FilterContext *instance = desc->instance;
169    int srcW = AV_CEIL_RSHIFT(desc->src->width, desc->src->h_chr_sub_sample);
170    int dstW = AV_CEIL_RSHIFT(desc->dst->width, desc->dst->h_chr_sub_sample);
171    int xInc = instance->xInc;
172
173    uint8_t ** src1 = desc->src->plane[1].line;
174    uint8_t ** dst1 = desc->dst->plane[1].line;
175    uint8_t ** src2 = desc->src->plane[2].line;
176    uint8_t ** dst2 = desc->dst->plane[2].line;
177
178    int src_pos1 = sliceY - desc->src->plane[1].sliceY;
179    int dst_pos1 = sliceY - desc->dst->plane[1].sliceY;
180
181    int src_pos2 = sliceY - desc->src->plane[2].sliceY;
182    int dst_pos2 = sliceY - desc->dst->plane[2].sliceY;
183
184    int i;
185    for (i = 0; i < sliceH; ++i) {
186        if (c->hcscale_fast) {
187            c->hcscale_fast(c, (uint16_t*)dst1[dst_pos1+i], (uint16_t*)dst2[dst_pos2+i], dstW, src1[src_pos1+i], src2[src_pos2+i], srcW, xInc);
188        } else {
189            c->hcScale(c, (uint16_t*)dst1[dst_pos1+i], dstW, src1[src_pos1+i], instance->filter, instance->filter_pos, instance->filter_size);
190            c->hcScale(c, (uint16_t*)dst2[dst_pos2+i], dstW, src2[src_pos2+i], instance->filter, instance->filter_pos, instance->filter_size);
191        }
192
193        if (c->chrConvertRange)
194            c->chrConvertRange((uint16_t*)dst1[dst_pos1+i], (uint16_t*)dst2[dst_pos2+i], dstW);
195
196        desc->dst->plane[1].sliceH += 1;
197        desc->dst->plane[2].sliceH += 1;
198    }
199    return sliceH;
200}
201
202static int chr_convert(SwsContext *c, SwsFilterDescriptor *desc, int sliceY, int sliceH)
203{
204    int srcW = AV_CEIL_RSHIFT(desc->src->width, desc->src->h_chr_sub_sample);
205    ColorContext * instance = desc->instance;
206    uint32_t * pal = instance->pal;
207
208    int sp0 = (sliceY - (desc->src->plane[0].sliceY >> desc->src->v_chr_sub_sample)) << desc->src->v_chr_sub_sample;
209    int sp1 = sliceY - desc->src->plane[1].sliceY;
210
211    int i;
212
213    desc->dst->plane[1].sliceY = sliceY;
214    desc->dst->plane[1].sliceH = sliceH;
215    desc->dst->plane[2].sliceY = sliceY;
216    desc->dst->plane[2].sliceH = sliceH;
217
218    for (i = 0; i < sliceH; ++i) {
219        const uint8_t * src[4] = { desc->src->plane[0].line[sp0+i],
220                        desc->src->plane[1].line[sp1+i],
221                        desc->src->plane[2].line[sp1+i],
222                        desc->src->plane[3].line[sp0+i]};
223
224        uint8_t * dst1 = desc->dst->plane[1].line[i];
225        uint8_t * dst2 = desc->dst->plane[2].line[i];
226        if (c->chrToYV12) {
227            c->chrToYV12(dst1, dst2, src[0], src[1], src[2], srcW, pal);
228        } else if (c->readChrPlanar) {
229            c->readChrPlanar(dst1, dst2, src, srcW, c->input_rgb2yuv_table);
230        }
231    }
232    return sliceH;
233}
234
235int ff_init_desc_cfmt_convert(SwsFilterDescriptor *desc, SwsSlice * src, SwsSlice *dst, uint32_t *pal)
236{
237    ColorContext * li = av_malloc(sizeof(ColorContext));
238    if (!li)
239        return AVERROR(ENOMEM);
240    li->pal = pal;
241    desc->instance = li;
242
243    desc->src =src;
244    desc->dst = dst;
245    desc->process = &chr_convert;
246
247    return 0;
248}
249
250int ff_init_desc_chscale(SwsFilterDescriptor *desc, SwsSlice *src, SwsSlice *dst, uint16_t *filter, int * filter_pos, int filter_size, int xInc)
251{
252    FilterContext *li = av_malloc(sizeof(FilterContext));
253    if (!li)
254        return AVERROR(ENOMEM);
255
256    li->filter = filter;
257    li->filter_pos = filter_pos;
258    li->filter_size = filter_size;
259    li->xInc = xInc;
260
261    desc->instance = li;
262
263    desc->alpha = isALPHA(src->fmt) && isALPHA(dst->fmt);
264    desc->src = src;
265    desc->dst = dst;
266
267    desc->process = &chr_h_scale;
268
269    return 0;
270}
271
272static int no_chr_scale(SwsContext *c, SwsFilterDescriptor *desc, int sliceY, int sliceH)
273{
274    desc->dst->plane[1].sliceY = sliceY + sliceH - desc->dst->plane[1].available_lines;
275    desc->dst->plane[1].sliceH = desc->dst->plane[1].available_lines;
276    desc->dst->plane[2].sliceY = sliceY + sliceH - desc->dst->plane[2].available_lines;
277    desc->dst->plane[2].sliceH = desc->dst->plane[2].available_lines;
278    return 0;
279}
280
281int ff_init_desc_no_chr(SwsFilterDescriptor *desc, SwsSlice * src, SwsSlice *dst)
282{
283    desc->src = src;
284    desc->dst = dst;
285    desc->alpha = 0;
286    desc->instance = NULL;
287    desc->process = &no_chr_scale;
288    return 0;
289}
290