From 718044dc198710f9d6e70d94affd5f8a1a52430f Mon Sep 17 00:00:00 2001 From: Michael Niedermayer Date: Thu, 25 Oct 2018 23:08:20 +0200 Subject: [PATCH] avutil/pixdesc: Add av_write_image_line2(), av_read_image_line2() This is needed because of 32bit float formats (which are difficult to store in 16bits) This also fixes undefined behavior found by fate Signed-off-by: Michael Niedermayer --- doc/APIchanges | 3 ++ libavutil/pixdesc.c | 72 +++++++++++++++++++------ libavutil/pixdesc.h | 11 ++++ libavutil/version.h | 2 +- tests/ref/fate/filter-pixdesc-grayf32be | 2 +- tests/ref/fate/filter-pixdesc-grayf32le | 2 +- 6 files changed, 73 insertions(+), 19 deletions(-) diff --git a/doc/APIchanges b/doc/APIchanges index ca4f93b8b20..346a5f02299 100644 --- a/doc/APIchanges +++ b/doc/APIchanges @@ -15,6 +15,9 @@ libavutil: 2017-10-21 API changes, most recent first: +2018-XX-XX - xxxxxxxxxx - lavu 56.21.100 - pixdesc.h + Add av_read_image_line2(), av_write_image_line2() + 2018-10-24 - xxxxxxxxxx - lavu 56.20.100 - frame.h Add AV_FRAME_DATA_S12M_TIMECODE diff --git a/libavutil/pixdesc.c b/libavutil/pixdesc.c index 970a83214c5..1c365772895 100644 --- a/libavutil/pixdesc.c +++ b/libavutil/pixdesc.c @@ -31,19 +31,22 @@ #include "intreadwrite.h" #include "version.h" -void av_read_image_line(uint16_t *dst, +void av_read_image_line2(void *dst, const uint8_t *data[4], const int linesize[4], const AVPixFmtDescriptor *desc, int x, int y, int c, int w, - int read_pal_component) + int read_pal_component, + int dst_element_size) { AVComponentDescriptor comp = desc->comp[c]; int plane = comp.plane; int depth = comp.depth; - int mask = (1 << depth) - 1; + unsigned mask = (1ULL << depth) - 1; int shift = comp.shift; int step = comp.step; int flags = desc->flags; + uint16_t *dst16 = dst; + uint32_t *dst32 = dst; if (flags & AV_PIX_FMT_FLAG_BITSTREAM) { int skip = x * step + comp.offset; @@ -57,38 +60,56 @@ void av_read_image_line(uint16_t *dst, shift -= step; p -= shift >> 3; shift &= 7; - *dst++ = val; + if (dst_element_size == 4) *dst32++ = val; + else *dst16++ = val; } } else { const uint8_t *p = data[plane] + y * linesize[plane] + x * step + comp.offset; int is_8bit = shift + depth <= 8; + int is_16bit= shift + depth <=16; if (is_8bit) p += !!(flags & AV_PIX_FMT_FLAG_BE); while (w--) { - int val = is_8bit ? *p : - flags & AV_PIX_FMT_FLAG_BE ? AV_RB16(p) : AV_RL16(p); + unsigned val; + if (is_8bit) val = *p; + else if(is_16bit) val = flags & AV_PIX_FMT_FLAG_BE ? AV_RB16(p) : AV_RL16(p); + else val = flags & AV_PIX_FMT_FLAG_BE ? AV_RB32(p) : AV_RL32(p); val = (val >> shift) & mask; if (read_pal_component) val = data[1][4 * val + c]; p += step; - *dst++ = val; + if (dst_element_size == 4) *dst32++ = val; + else *dst16++ = val; } } } -void av_write_image_line(const uint16_t *src, +void av_read_image_line(uint16_t *dst, + const uint8_t *data[4], const int linesize[4], + const AVPixFmtDescriptor *desc, + int x, int y, int c, int w, + int read_pal_component) +{ + av_read_image_line2(dst, data, linesize, desc,x, y, c, w, + read_pal_component, + 2); +} + +void av_write_image_line2(const void *src, uint8_t *data[4], const int linesize[4], const AVPixFmtDescriptor *desc, - int x, int y, int c, int w) + int x, int y, int c, int w, int src_element_size) { AVComponentDescriptor comp = desc->comp[c]; int plane = comp.plane; int depth = comp.depth; int step = comp.step; int flags = desc->flags; + const uint32_t *src32 = src; + const uint16_t *src16 = src; if (flags & AV_PIX_FMT_FLAG_BITSTREAM) { int skip = x * step + comp.offset; @@ -96,7 +117,7 @@ void av_write_image_line(const uint16_t *src, int shift = 8 - depth - (skip & 7); while (w--) { - *p |= *src++ << shift; + *p |= (src_element_size == 4 ? *src32++ : *src16++) << shift; shift -= step; p -= shift >> 3; shift &= 7; @@ -109,17 +130,28 @@ void av_write_image_line(const uint16_t *src, if (shift + depth <= 8) { p += !!(flags & AV_PIX_FMT_FLAG_BE); while (w--) { - *p |= (*src++ << shift); + *p |= ((src_element_size == 4 ? *src32++ : *src16++) << shift); p += step; } } else { while (w--) { - if (flags & AV_PIX_FMT_FLAG_BE) { - uint16_t val = AV_RB16(p) | (*src++ << shift); - AV_WB16(p, val); + unsigned s = (src_element_size == 4 ? *src32++ : *src16++); + if (shift + depth <= 16) { + if (flags & AV_PIX_FMT_FLAG_BE) { + uint16_t val = AV_RB16(p) | (s << shift); + AV_WB16(p, val); + } else { + uint16_t val = AV_RL16(p) | (s << shift); + AV_WL16(p, val); + } } else { - uint16_t val = AV_RL16(p) | (*src++ << shift); - AV_WL16(p, val); + if (flags & AV_PIX_FMT_FLAG_BE) { + uint32_t val = AV_RB32(p) | (s << shift); + AV_WB32(p, val); + } else { + uint32_t val = AV_RL32(p) | (s << shift); + AV_WL32(p, val); + } } p += step; } @@ -127,6 +159,14 @@ void av_write_image_line(const uint16_t *src, } } +void av_write_image_line(const uint16_t *src, + uint8_t *data[4], const int linesize[4], + const AVPixFmtDescriptor *desc, + int x, int y, int c, int w) +{ + av_write_image_line2(src, data, linesize, desc, x, y, c, w, 2); +} + #if FF_API_PLUS1_MINUS1 FF_DISABLE_DEPRECATION_WARNINGS #endif diff --git a/libavutil/pixdesc.h b/libavutil/pixdesc.h index 4f9c5a271fd..c055810ae87 100644 --- a/libavutil/pixdesc.h +++ b/libavutil/pixdesc.h @@ -343,7 +343,13 @@ char *av_get_pix_fmt_string(char *buf, int buf_size, * format writes the values corresponding to the palette * component c in data[1] to dst, rather than the palette indexes in * data[0]. The behavior is undefined if the format is not paletted. + * @param dst_element_size size of elements in dst array (2 or 4 byte) */ +void av_read_image_line2(void *dst, const uint8_t *data[4], + const int linesize[4], const AVPixFmtDescriptor *desc, + int x, int y, int c, int w, int read_pal_component, + int dst_element_size); + void av_read_image_line(uint16_t *dst, const uint8_t *data[4], const int linesize[4], const AVPixFmtDescriptor *desc, int x, int y, int c, int w, int read_pal_component); @@ -361,7 +367,12 @@ void av_read_image_line(uint16_t *dst, const uint8_t *data[4], * @param y the vertical coordinate of the first pixel to write * @param w the width of the line to write, that is the number of * values to write to the image line + * @param src_element_size size of elements in src array (2 or 4 byte) */ +void av_write_image_line2(const void *src, uint8_t *data[4], + const int linesize[4], const AVPixFmtDescriptor *desc, + int x, int y, int c, int w, int src_element_size); + void av_write_image_line(const uint16_t *src, uint8_t *data[4], const int linesize[4], const AVPixFmtDescriptor *desc, int x, int y, int c, int w); diff --git a/libavutil/version.h b/libavutil/version.h index 377714a91e9..8e27e6bbc69 100644 --- a/libavutil/version.h +++ b/libavutil/version.h @@ -79,7 +79,7 @@ */ #define LIBAVUTIL_VERSION_MAJOR 56 -#define LIBAVUTIL_VERSION_MINOR 20 +#define LIBAVUTIL_VERSION_MINOR 21 #define LIBAVUTIL_VERSION_MICRO 100 #define LIBAVUTIL_VERSION_INT AV_VERSION_INT(LIBAVUTIL_VERSION_MAJOR, \ diff --git a/tests/ref/fate/filter-pixdesc-grayf32be b/tests/ref/fate/filter-pixdesc-grayf32be index 423bbfbebc7..787ca0ca7e7 100644 --- a/tests/ref/fate/filter-pixdesc-grayf32be +++ b/tests/ref/fate/filter-pixdesc-grayf32be @@ -1 +1 @@ -pixdesc-grayf32be 381c8d0f19d286809b91cd6e6c0048ab +pixdesc-grayf32be 047d17c62f2e712c6547e4227b427303 diff --git a/tests/ref/fate/filter-pixdesc-grayf32le b/tests/ref/fate/filter-pixdesc-grayf32le index a76e0a995e2..8de4d4c88d9 100644 --- a/tests/ref/fate/filter-pixdesc-grayf32le +++ b/tests/ref/fate/filter-pixdesc-grayf32le @@ -1 +1 @@ -pixdesc-grayf32le 381c8d0f19d286809b91cd6e6c0048ab +pixdesc-grayf32le cdedfdbaa4e192b9f2c84092f955fb4b -- 2.39.2