Skip to content

Commit aca569a

Browse files
committed
swscale/input: add rgbaf16 input support
This is by no means perfect, since at least ddagrab will return scRGB data with values outside of 0.0f to 1.0f for HDR values. Its primary purpose is to be able to work with the format at all.
1 parent f2de911 commit aca569a

File tree

7 files changed

+171
-2
lines changed

7 files changed

+171
-2
lines changed

libswscale/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ OBJS = alphablend.o \
99
hscale.o \
1010
hscale_fast_bilinear.o \
1111
gamma.o \
12+
half2float.o \
1213
input.o \
1314
options.o \
1415
output.o \

libswscale/half2float.c

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
/*
2+
* This file is part of FFmpeg.
3+
*
4+
* FFmpeg is free software; you can redistribute it and/or
5+
* modify it under the terms of the GNU Lesser General Public
6+
* License as published by the Free Software Foundation; either
7+
* version 2.1 of the License, or (at your option) any later version.
8+
*
9+
* FFmpeg is distributed in the hope that it will be useful,
10+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
11+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12+
* Lesser General Public License for more details.
13+
*
14+
* You should have received a copy of the GNU Lesser General Public
15+
* License along with FFmpeg; if not, write to the Free Software
16+
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17+
*/
18+
19+
#include "libavutil/half2float.c"

libswscale/input.c

Lines changed: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1124,6 +1124,112 @@ static void grayf32##endian_name##ToY16_c(uint8_t *dst, const uint8_t *src,
11241124
rgbf32_planar_funcs_endian(le, 0)
11251125
rgbf32_planar_funcs_endian(be, 1)
11261126

1127+
#define rdpx(src) av_int2float(half2float(is_be ? AV_RB16(&src) : AV_RL16(&src), h2f_tbl))
1128+
1129+
static av_always_inline void rgbaf16ToUV_half_endian(uint16_t *dstU, uint16_t *dstV, int is_be,
1130+
const uint16_t *src, int width,
1131+
int32_t *rgb2yuv, Half2FloatTables *h2f_tbl)
1132+
{
1133+
int32_t ru = rgb2yuv[RU_IDX], gu = rgb2yuv[GU_IDX], bu = rgb2yuv[BU_IDX];
1134+
int32_t rv = rgb2yuv[RV_IDX], gv = rgb2yuv[GV_IDX], bv = rgb2yuv[BV_IDX];
1135+
int i;
1136+
for (i = 0; i < width; i++) {
1137+
int r = (lrintf(av_clipf(65535.0f * rdpx(src[i*8+0]), 0.0f, 65535.0f)) +
1138+
lrintf(av_clipf(65535.0f * rdpx(src[i*8+4]), 0.0f, 65535.0f))) >> 1;
1139+
int g = (lrintf(av_clipf(65535.0f * rdpx(src[i*8+1]), 0.0f, 65535.0f)) +
1140+
lrintf(av_clipf(65535.0f * rdpx(src[i*8+5]), 0.0f, 65535.0f))) >> 1;
1141+
int b = (lrintf(av_clipf(65535.0f * rdpx(src[i*8+2]), 0.0f, 65535.0f)) +
1142+
lrintf(av_clipf(65535.0f * rdpx(src[i*8+6]), 0.0f, 65535.0f))) >> 1;
1143+
1144+
dstU[i] = (ru*r + gu*g + bu*b + (0x10001<<(RGB2YUV_SHIFT-1))) >> RGB2YUV_SHIFT;
1145+
dstV[i] = (rv*r + gv*g + bv*b + (0x10001<<(RGB2YUV_SHIFT-1))) >> RGB2YUV_SHIFT;
1146+
}
1147+
}
1148+
1149+
static av_always_inline void rgbaf16ToUV_endian(uint16_t *dstU, uint16_t *dstV, int is_be,
1150+
const uint16_t *src, int width,
1151+
int32_t *rgb2yuv, Half2FloatTables *h2f_tbl)
1152+
{
1153+
int32_t ru = rgb2yuv[RU_IDX], gu = rgb2yuv[GU_IDX], bu = rgb2yuv[BU_IDX];
1154+
int32_t rv = rgb2yuv[RV_IDX], gv = rgb2yuv[GV_IDX], bv = rgb2yuv[BV_IDX];
1155+
int i;
1156+
for (i = 0; i < width; i++) {
1157+
int r = lrintf(av_clipf(65535.0f * rdpx(src[i*4+0]), 0.0f, 65535.0f));
1158+
int g = lrintf(av_clipf(65535.0f * rdpx(src[i*4+1]), 0.0f, 65535.0f));
1159+
int b = lrintf(av_clipf(65535.0f * rdpx(src[i*4+2]), 0.0f, 65535.0f));
1160+
1161+
dstU[i] = (ru*r + gu*g + bu*b + (0x10001<<(RGB2YUV_SHIFT-1))) >> RGB2YUV_SHIFT;
1162+
dstV[i] = (rv*r + gv*g + bv*b + (0x10001<<(RGB2YUV_SHIFT-1))) >> RGB2YUV_SHIFT;
1163+
}
1164+
}
1165+
1166+
static av_always_inline void rgbaf16ToY_endian(uint16_t *dst, const uint16_t *src, int is_be,
1167+
int width, int32_t *rgb2yuv, Half2FloatTables *h2f_tbl)
1168+
{
1169+
int32_t ry = rgb2yuv[RY_IDX], gy = rgb2yuv[GY_IDX], by = rgb2yuv[BY_IDX];
1170+
int i;
1171+
for (i = 0; i < width; i++) {
1172+
int r = lrintf(av_clipf(65535.0f * rdpx(src[i*4+0]), 0.0f, 65535.0f));
1173+
int g = lrintf(av_clipf(65535.0f * rdpx(src[i*4+1]), 0.0f, 65535.0f));
1174+
int b = lrintf(av_clipf(65535.0f * rdpx(src[i*4+2]), 0.0f, 65535.0f));
1175+
1176+
dst[i] = (ry*r + gy*g + by*b + (0x2001<<(RGB2YUV_SHIFT-1))) >> RGB2YUV_SHIFT;
1177+
}
1178+
}
1179+
1180+
static av_always_inline void rgbaf16ToA_endian(uint16_t *dst, const uint16_t *src, int is_be,
1181+
int width, Half2FloatTables *h2f_tbl)
1182+
{
1183+
int i;
1184+
for (i=0; i<width; i++) {
1185+
dst[i] = lrintf(av_clipf(65535.0f * rdpx(src[i*4+3]), 0.0f, 65535.0f));
1186+
}
1187+
}
1188+
1189+
#undef rdpx
1190+
1191+
#define rgbaf16_funcs_endian(endian_name, endian) \
1192+
static void rgbaf16##endian_name##ToUV_half_c(uint8_t *_dstU, uint8_t *_dstV, const uint8_t *unused, \
1193+
const uint8_t *src1, const uint8_t *src2, \
1194+
int width, uint32_t *_rgb2yuv, void *opq) \
1195+
{ \
1196+
const uint16_t *src = (const uint16_t*)src1; \
1197+
uint16_t *dstU = (uint16_t*)_dstU; \
1198+
uint16_t *dstV = (uint16_t*)_dstV; \
1199+
int32_t *rgb2yuv = (int32_t*)_rgb2yuv; \
1200+
av_assert1(src1==src2); \
1201+
rgbaf16ToUV_half_endian(dstU, dstV, endian, src, width, rgb2yuv, opq); \
1202+
} \
1203+
static void rgbaf16##endian_name##ToUV_c(uint8_t *_dstU, uint8_t *_dstV, const uint8_t *unused, \
1204+
const uint8_t *src1, const uint8_t *src2, \
1205+
int width, uint32_t *_rgb2yuv, void *opq) \
1206+
{ \
1207+
const uint16_t *src = (const uint16_t*)src1; \
1208+
uint16_t *dstU = (uint16_t*)_dstU; \
1209+
uint16_t *dstV = (uint16_t*)_dstV; \
1210+
int32_t *rgb2yuv = (int32_t*)_rgb2yuv; \
1211+
av_assert1(src1==src2); \
1212+
rgbaf16ToUV_endian(dstU, dstV, endian, src, width, rgb2yuv, opq); \
1213+
} \
1214+
static void rgbaf16##endian_name##ToY_c(uint8_t *_dst, const uint8_t *_src, const uint8_t *unused0, \
1215+
const uint8_t *unused1, int width, uint32_t *_rgb2yuv, void *opq) \
1216+
{ \
1217+
const uint16_t *src = (const uint16_t*)_src; \
1218+
uint16_t *dst = (uint16_t*)_dst; \
1219+
int32_t *rgb2yuv = (int32_t*)_rgb2yuv; \
1220+
rgbaf16ToY_endian(dst, src, endian, width, rgb2yuv, opq); \
1221+
} \
1222+
static void rgbaf16##endian_name##ToA_c(uint8_t *_dst, const uint8_t *_src, const uint8_t *unused0, \
1223+
const uint8_t *unused1, int width, uint32_t *unused2, void *opq) \
1224+
{ \
1225+
const uint16_t *src = (const uint16_t*)_src; \
1226+
uint16_t *dst = (uint16_t*)_dst; \
1227+
rgbaf16ToA_endian(dst, src, endian, width, opq); \
1228+
}
1229+
1230+
rgbaf16_funcs_endian(le, 0)
1231+
rgbaf16_funcs_endian(be, 1)
1232+
11271233
av_cold void ff_sws_init_input_funcs(SwsContext *c)
11281234
{
11291235
enum AVPixelFormat srcFormat = c->srcFormat;
@@ -1388,6 +1494,12 @@ av_cold void ff_sws_init_input_funcs(SwsContext *c)
13881494
case AV_PIX_FMT_X2BGR10LE:
13891495
c->chrToYV12 = bgr30leToUV_half_c;
13901496
break;
1497+
case AV_PIX_FMT_RGBAF16BE:
1498+
c->chrToYV12 = rgbaf16beToUV_half_c;
1499+
break;
1500+
case AV_PIX_FMT_RGBAF16LE:
1501+
c->chrToYV12 = rgbaf16leToUV_half_c;
1502+
break;
13911503
}
13921504
} else {
13931505
switch (srcFormat) {
@@ -1475,6 +1587,12 @@ av_cold void ff_sws_init_input_funcs(SwsContext *c)
14751587
case AV_PIX_FMT_X2BGR10LE:
14761588
c->chrToYV12 = bgr30leToUV_c;
14771589
break;
1590+
case AV_PIX_FMT_RGBAF16BE:
1591+
c->chrToYV12 = rgbaf16beToUV_c;
1592+
break;
1593+
case AV_PIX_FMT_RGBAF16LE:
1594+
c->chrToYV12 = rgbaf16leToUV_c;
1595+
break;
14781596
}
14791597
}
14801598

@@ -1763,6 +1881,12 @@ av_cold void ff_sws_init_input_funcs(SwsContext *c)
17631881
case AV_PIX_FMT_X2BGR10LE:
17641882
c->lumToYV12 = bgr30leToY_c;
17651883
break;
1884+
case AV_PIX_FMT_RGBAF16BE:
1885+
c->lumToYV12 = rgbaf16beToY_c;
1886+
break;
1887+
case AV_PIX_FMT_RGBAF16LE:
1888+
c->lumToYV12 = rgbaf16leToY_c;
1889+
break;
17661890
}
17671891
if (c->needAlpha) {
17681892
if (is16BPS(srcFormat) || isNBPS(srcFormat)) {
@@ -1782,6 +1906,12 @@ av_cold void ff_sws_init_input_funcs(SwsContext *c)
17821906
case AV_PIX_FMT_ARGB:
17831907
c->alpToYV12 = abgrToA_c;
17841908
break;
1909+
case AV_PIX_FMT_RGBAF16BE:
1910+
c->alpToYV12 = rgbaf16beToA_c;
1911+
break;
1912+
case AV_PIX_FMT_RGBAF16LE:
1913+
c->alpToYV12 = rgbaf16leToA_c;
1914+
break;
17851915
case AV_PIX_FMT_YA8:
17861916
c->alpToYV12 = uyvyToY_c;
17871917
break;

libswscale/slice.c

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -282,7 +282,13 @@ int ff_init_filters(SwsContext * c)
282282
c->descIndex[0] = num_ydesc + (need_gamma ? 1 : 0);
283283
c->descIndex[1] = num_ydesc + num_cdesc + (need_gamma ? 1 : 0);
284284

285-
285+
if (isFloat16(c->srcFormat)) {
286+
c->h2f_tables = av_malloc(sizeof(*c->h2f_tables));
287+
if (!c->h2f_tables)
288+
return AVERROR(ENOMEM);
289+
ff_init_half2float_tables(c->h2f_tables);
290+
c->input_opaque = c->h2f_tables;
291+
}
286292

287293
c->desc = av_calloc(c->numDesc, sizeof(*c->desc));
288294
if (!c->desc)
@@ -393,5 +399,6 @@ int ff_free_filters(SwsContext *c)
393399
free_slice(&c->slice[i]);
394400
av_freep(&c->slice);
395401
}
402+
av_freep(&c->h2f_tables);
396403
return 0;
397404
}

libswscale/swscale_internal.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
#include "libavutil/pixdesc.h"
3636
#include "libavutil/slicethread.h"
3737
#include "libavutil/ppc/util_altivec.h"
38+
#include "libavutil/half2float.h"
3839

3940
#define STR(s) AV_TOSTRING(s) // AV_STRINGIFY is too long
4041

@@ -679,6 +680,8 @@ typedef struct SwsContext {
679680
unsigned int dst_slice_align;
680681
atomic_int stride_unaligned_warned;
681682
atomic_int data_unaligned_warned;
683+
684+
Half2FloatTables *h2f_tables;
682685
} SwsContext;
683686
//FIXME check init (where 0)
684687

@@ -840,6 +843,13 @@ static av_always_inline int isFloat(enum AVPixelFormat pix_fmt)
840843
return desc->flags & AV_PIX_FMT_FLAG_FLOAT;
841844
}
842845

846+
static av_always_inline int isFloat16(enum AVPixelFormat pix_fmt)
847+
{
848+
const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(pix_fmt);
849+
av_assert0(desc);
850+
return (desc->flags & AV_PIX_FMT_FLAG_FLOAT) && desc->comp[0].depth == 16;
851+
}
852+
843853
static av_always_inline int isALPHA(enum AVPixelFormat pix_fmt)
844854
{
845855
const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(pix_fmt);

libswscale/utils.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -259,6 +259,8 @@ static const FormatEntry format_entries[] = {
259259
[AV_PIX_FMT_P416LE] = { 1, 1 },
260260
[AV_PIX_FMT_NV16] = { 1, 1 },
261261
[AV_PIX_FMT_VUYA] = { 1, 1 },
262+
[AV_PIX_FMT_RGBAF16BE] = { 1, 0 },
263+
[AV_PIX_FMT_RGBAF16LE] = { 1, 0 },
262264
};
263265

264266
int ff_shuffle_filter_coefficients(SwsContext *c, int *filterPos,

libswscale/version.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@
2929
#include "version_major.h"
3030

3131
#define LIBSWSCALE_VERSION_MINOR 8
32-
#define LIBSWSCALE_VERSION_MICRO 102
32+
#define LIBSWSCALE_VERSION_MICRO 103
3333

3434
#define LIBSWSCALE_VERSION_INT AV_VERSION_INT(LIBSWSCALE_VERSION_MAJOR, \
3535
LIBSWSCALE_VERSION_MINOR, \

0 commit comments

Comments
 (0)