├── .gitignore ├── LICENSE ├── Makefile ├── README.md ├── build ├── rgb2yuv.pro └── rgb2yuv.sln ├── include ├── detail │ ├── basic_concept.hxx │ ├── buffer_creator.hxx │ ├── pixel_convertor.hxx │ ├── pixel_iterator.hxx │ ├── pixel_walker.hxx │ ├── predefine.hxx │ ├── scope_block.hxx │ ├── undefine.hxx │ └── yuv_helper.hxx └── rgb2yuv.hpp └── test ├── detect_plat.hpp ├── stopwatch.hpp ├── test.cpp ├── test.vcxproj ├── test.vcxproj.filters └── test.vcxproj.user /.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled Object files 2 | *.slo 3 | *.lo 4 | *.o 5 | *.obj 6 | 7 | # Precompiled Headers 8 | *.gch 9 | *.pch 10 | 11 | # Compiled Dynamic libraries 12 | *.so 13 | *.dylib 14 | *.dll 15 | 16 | # Fortran module files 17 | *.mod 18 | 19 | # Compiled Static libraries 20 | *.lai 21 | *.la 22 | *.a 23 | *.lib 24 | 25 | # Executables 26 | *.exe 27 | *.out 28 | *.app 29 | /.vs 30 | /build/.vs 31 | /build/bin 32 | /build/tmp 33 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | rgb2yuv - A Lightweight Tool for Transforming RGB to YUV/YCbCr (https://github.com/mutouyun/rgb2yuv) 2 | Copyright (c) 2015, mutouyun (http://orzz.org). All rights reserved. 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy 5 | of this software and associated documentation files (the "Software"), to deal 6 | in the Software without restriction, including without limitation the rights 7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the Software is 9 | furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in 12 | all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | THE SOFTWARE. -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | .PHONY: clean all install 2 | 3 | EXE_NAME = $(notdir $(CURDIR)).out 4 | COMPILE_PREFIX ?= 5 | 6 | CFLAGS = -I. 7 | CFLAGS += -g 8 | 9 | LDFLAGS = 10 | 11 | SRC_DIRS = test 12 | 13 | OBJS_C = $(addsuffix .o, $(wildcard $(addsuffix /*.c, $(SRC_DIRS)))) 14 | OBJS_CPP = $(addsuffix .o, $(wildcard $(addsuffix /*.cpp, $(SRC_DIRS)))) 15 | 16 | all: $(EXE_NAME) 17 | 18 | $(EXE_NAME): $(OBJS_C) $(OBJS_CPP) 19 | @$(COMPILE_PREFIX)g++ $^ $(LDFLAGS) -o $(EXE_NAME) 20 | @echo [LD] $@ 21 | 22 | $(OBJS_C): %.c.o: %.c 23 | @$(COMPILE_PREFIX)gcc -c $(CFLAGS) $< -o $@ 24 | @echo [CC] $< 25 | 26 | $(OBJS_CPP): %.cpp.o: %.cpp 27 | @$(COMPILE_PREFIX)g++ -c $(CFLAGS) $< -o $@ 28 | @echo [CXX] $< 29 | 30 | clean: 31 | rm -f $(EXE_NAME) 32 | rm -f $(OBJS_C) $(OBJS_CPP) 33 | rm -f *.yuv *.txt -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # rgb2yuv 2 | 3 | 一个轻量级的转换工具, 用于把RGB像素块转换为YUV. 4 | 使用时仅需include rgb2yuv.hpp, 库本身不需要编译. 5 | 6 | ## 支持的RGB格式 7 | 8 | RGB 888 - 24位 9 | RGB 565 - 16位 10 | RGB 555 - 16位 11 | RGB 444 - 12位(无padding, 3字节2像素) 12 | RGB 888X - 32位 13 | 14 | ## 支持的YUV格式 15 | 16 | NV24 - YUV 4:4:4, Planar, Combined CbCr planes 17 | NV42 - YUV 4:4:4, Planar, Combined CbCr planes 18 | YUY2 - YUV 4:2:2, Packed 19 | YUYV - YUV 4:2:2, Packed, Same as YUY2 20 | YVYU - YUV 4:2:2, Packed 21 | UYVY - YUV 4:2:2, Packed 22 | VYUY - YUV 4:2:2, Packed 23 | 422P - YUV 4:2:2, Planar 24 | YV12 - YUV 4:2:0, Planar 25 | YU12 - YUV 4:2:0, Planar 26 | I420 - YUV 4:2:0, Planar, Same as YU12 27 | NV12 - YUV 4:2:0, Planar, Combined CbCr planes 28 | NV21 - YUV 4:2:0, Planar, Combined CbCr planes 29 | Y41P - YUV 4:1:1, Packed 30 | Y411 - YUV 4:1:1, Packed, Same as Y41P 31 | 411P - YUV 4:1:1, Planar 32 | YVU9 - YUV 4:1:0, Planar 33 | YUV9 - YUV 4:1:0, Planar -------------------------------------------------------------------------------- /build/rgb2yuv.pro: -------------------------------------------------------------------------------- 1 | TEMPLATE = app 2 | CONFIG += console 3 | CONFIG -= app_bundle 4 | CONFIG -= qt 5 | 6 | CONFIG(debug, debug|release) { 7 | DESTDIR = $$PWD/bin/Debug 8 | } 9 | CONFIG(release, debug|release) { 10 | DEFINES += NDEBUG 11 | DESTDIR = $$PWD/bin/Release 12 | } 13 | 14 | INCLUDEPATH += \ 15 | ./ \ 16 | ../test 17 | 18 | SOURCES += \ 19 | ../test/test.cpp 20 | 21 | HEADERS += \ 22 | ../include/detail/predefine.hxx \ 23 | ../include/detail/undefine.hxx \ 24 | ../include/detail/basic_concept.hxx \ 25 | ../include/detail/scope_block.hxx \ 26 | ../include/detail/buffer_creator.hxx \ 27 | ../include/detail/pixel_convertor.hxx \ 28 | ../include/detail/pixel_walker.hxx \ 29 | ../include/detail/pixel_iterator.hxx \ 30 | ../include/rgb2yuv_old.hpp \ 31 | ../include/rgb2yuv.hpp 32 | -------------------------------------------------------------------------------- /build/rgb2yuv.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 14 4 | VisualStudioVersion = 14.0.22609.0 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "test", "..\test\test.vcxproj", "{734F949E-443C-454C-8217-AD4D6BB88C48}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|x86 = Debug|x86 11 | Release|x86 = Release|x86 12 | EndGlobalSection 13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 14 | {734F949E-443C-454C-8217-AD4D6BB88C48}.Debug|x86.ActiveCfg = Debug|Win32 15 | {734F949E-443C-454C-8217-AD4D6BB88C48}.Debug|x86.Build.0 = Debug|Win32 16 | {734F949E-443C-454C-8217-AD4D6BB88C48}.Release|x86.ActiveCfg = Release|Win32 17 | {734F949E-443C-454C-8217-AD4D6BB88C48}.Release|x86.Build.0 = Release|Win32 18 | EndGlobalSection 19 | GlobalSection(SolutionProperties) = preSolution 20 | HideSolutionNode = FALSE 21 | EndGlobalSection 22 | EndGlobal 23 | -------------------------------------------------------------------------------- /include/detail/basic_concept.hxx: -------------------------------------------------------------------------------- 1 | /* 2 | rgb2yuv - Code covered by the MIT License 3 | Author: mutouyun (http://orzz.org) 4 | */ 5 | 6 | //////////////////////////////////////////////////////////////// 7 | /// Provide basic universal types and constants 8 | //////////////////////////////////////////////////////////////// 9 | 10 | typedef GLB_ uint8_t byte_t; 11 | typedef struct { GLB_ uint8_t b_, g_, r_; } rgb_t; 12 | typedef struct { GLB_ uint8_t v_, u_, y_; } yuv_t; 13 | 14 | enum supported 15 | { 16 | rgb_MIN, 17 | rgb_888, 18 | rgb_565, 19 | rgb_555, 20 | rgb_444, 21 | rgb_888X, 22 | rgb_MAX, 23 | 24 | /* 25 | * YUV Formats Chapter 2. Image Formats 26 | * See: http://www.retiisi.org.uk/v4l2/tmp/media_api/yuv-formats.html 27 | * http://www.fourcc.org/yuv.php 28 | */ 29 | yuv_MIN, 30 | yuv_NV24, // 444 SP 31 | yuv_NV42, 32 | yuv_YUY2, // 422 33 | yuv_YUYV = yuv_YUY2, 34 | yuv_YVYU, 35 | yuv_UYVY, 36 | yuv_VYUY, 37 | yuv_422P, // 422 P 38 | yuv_YV12, // 420 P 39 | yuv_YU12, 40 | yuv_I420 = yuv_YU12, 41 | yuv_NV12, // 420 SP 42 | yuv_NV21, 43 | yuv_Y41P, // 411 44 | yuv_Y411, // 411, see: http://www.fourcc.org/pixel-format/yuv-y411/ 45 | yuv_IYU1 = yuv_Y411, 46 | yuv_411P, // 411 P 47 | yuv_YVU9, // 410 P 48 | yuv_YUV9, 49 | yuv_MAX 50 | }; 51 | 52 | enum plane_type 53 | { 54 | plane_Y = 0, 55 | plane_U, 56 | plane_V, 57 | 58 | plane_R, 59 | plane_G, 60 | plane_B, 61 | 62 | plane_MAX 63 | }; 64 | 65 | //////////////////////////////////////////////////////////////// 66 | /// Useful tools for SFINAE 67 | //////////////////////////////////////////////////////////////// 68 | 69 | template struct is_rgb 70 | { 71 | enum { value = ((S > rgb_MIN) && (S < rgb_MAX)) ? 1 : 0 }; 72 | }; 73 | 74 | template struct is_yuv 75 | { 76 | enum { value = ((S > yuv_MIN) && (S < yuv_MAX)) ? 1 : 0 }; 77 | }; 78 | 79 | template struct is_rgb_plane { enum { value = 0 }; }; 80 | template <> struct is_rgb_plane { enum { value = 1 }; }; 81 | template <> struct is_rgb_plane { enum { value = 1 }; }; 82 | template <> struct is_rgb_plane { enum { value = 1 }; }; 83 | 84 | template struct is_yuv_plane { enum { value = 0 }; }; 85 | template <> struct is_yuv_plane { enum { value = 1 }; }; 86 | template <> struct is_yuv_plane { enum { value = 1 }; }; 87 | template <> struct is_yuv_plane { enum { value = 1 }; }; 88 | -------------------------------------------------------------------------------- /include/detail/buffer_creator.hxx: -------------------------------------------------------------------------------- 1 | /* 2 | rgb2yuv - Code covered by the MIT License 3 | Author: mutouyun (http://orzz.org) 4 | */ 5 | 6 | //////////////////////////////////////////////////////////////// 7 | /// Create a buffer for transforming the image pixels 8 | //////////////////////////////////////////////////////////////// 9 | 10 | /* Calculate RGB size */ 11 | 12 | template 13 | typename STD_ enable_if<(S == R2Y_ rgb_888), 14 | GLB_ size_t>::type calculate_size(GLB_ size_t in_w, GLB_ size_t in_h) 15 | { 16 | return (in_w * in_h) * sizeof(R2Y_ rgb_t); 17 | } 18 | 19 | template 20 | typename STD_ enable_if<(S == R2Y_ rgb_565 || S == R2Y_ rgb_555), 21 | GLB_ size_t>::type calculate_size(GLB_ size_t in_w, GLB_ size_t in_h) 22 | { 23 | return (in_w * in_h) * sizeof(GLB_ uint16_t); 24 | } 25 | 26 | template 27 | typename STD_ enable_if<(S == R2Y_ rgb_444), 28 | GLB_ size_t>::type calculate_size(GLB_ size_t in_w, GLB_ size_t in_h) 29 | { 30 | return ( (in_w * in_h * 3 + 1) >> 1 ); 31 | } 32 | 33 | template 34 | typename STD_ enable_if<(S == R2Y_ rgb_888X), 35 | GLB_ size_t>::type calculate_size(GLB_ size_t in_w, GLB_ size_t in_h) 36 | { 37 | return (in_w * in_h) * sizeof(GLB_ uint32_t); 38 | } 39 | 40 | /* Calculate YUV size */ 41 | 42 | template 43 | typename STD_ enable_if<(S == R2Y_ yuv_NV24 || S == R2Y_ yuv_NV42), 44 | GLB_ size_t>::type calculate_size(GLB_ size_t in_w, GLB_ size_t in_h) 45 | { 46 | return (in_w * in_h) * sizeof(R2Y_ yuv_t); 47 | } 48 | 49 | template 50 | typename STD_ enable_if<(S == R2Y_ yuv_YVYU || S == R2Y_ yuv_UYVY || S == R2Y_ yuv_VYUY || 51 | S == R2Y_ yuv_YUY2 || S == R2Y_ yuv_422P), 52 | GLB_ size_t>::type calculate_size(GLB_ size_t in_w, GLB_ size_t in_h) 53 | { 54 | GLB_ size_t s = in_w * in_h; 55 | assert((s & 1) == 0); // s % 2 == 0 56 | return (s << 1); 57 | } 58 | 59 | template 60 | typename STD_ enable_if<(S == R2Y_ yuv_Y41P), 61 | GLB_ size_t>::type calculate_size(GLB_ size_t in_w, GLB_ size_t in_h) 62 | { 63 | GLB_ size_t s = in_w * in_h; 64 | assert((s & 7) == 0); // s % 8 == 0 65 | return ( s + (s >> 1) ); 66 | } 67 | 68 | template 69 | typename STD_ enable_if<(S == R2Y_ yuv_Y411 || S == R2Y_ yuv_411P || 70 | S == R2Y_ yuv_YV12 || S == R2Y_ yuv_YU12 || 71 | S == R2Y_ yuv_NV12 || S == R2Y_ yuv_NV21), 72 | GLB_ size_t>::type calculate_size(GLB_ size_t in_w, GLB_ size_t in_h) 73 | { 74 | GLB_ size_t s = in_w * in_h; 75 | assert((s & 3) == 0); // s % 4 == 0 76 | return ( s + (s >> 1) ); 77 | } 78 | 79 | template 80 | typename STD_ enable_if<(S == R2Y_ yuv_YVU9 || S == R2Y_ yuv_YUV9), 81 | GLB_ size_t>::type calculate_size(GLB_ size_t in_w, GLB_ size_t in_h) 82 | { 83 | GLB_ size_t s = in_w * in_h; 84 | assert((s & 15) == 0); // s % 16 == 0 85 | return ( s + (s >> 3) ); 86 | } 87 | 88 | /* Create a buffer with given w & h */ 89 | 90 | template 91 | R2Y_ scope_block create_buffer(GLB_ size_t in_w, GLB_ size_t in_h) 92 | { 93 | return R2Y_ scope_block{ calculate_size(in_w, in_h) }; 94 | } -------------------------------------------------------------------------------- /include/detail/pixel_convertor.hxx: -------------------------------------------------------------------------------- 1 | /* 2 | rgb2yuv - Code covered by the MIT License 3 | Author: mutouyun (http://orzz.org) 4 | */ 5 | 6 | //////////////////////////////////////////////////////////////// 7 | /// Converting between RGB & YUV/YCbCr planes 8 | //////////////////////////////////////////////////////////////// 9 | 10 | struct pixel_t 11 | { 12 | GLB_ uint8_t c_, b_, a_; 13 | 14 | template static pixel_t const & cast(P const & p) 15 | { 16 | return reinterpret_cast(p); 17 | } 18 | }; 19 | 20 | struct convertor 21 | { 22 | enum : GLB_ int32_t { MAX = static_cast(~0) }; 23 | 24 | R2Y_FORCE_INLINE_ static GLB_ uint8_t clip(GLB_ int32_t value) 25 | { 26 | return static_cast( (value < 0) ? 0 : 27 | (value > convertor::MAX) ? convertor::MAX : value ); 28 | } 29 | 30 | convertor(GLB_ int32_t const (& matrix)[4]) 31 | { 32 | for (GLB_ int32_t i = 0; i <= convertor::MAX; ++i) 33 | for (GLB_ size_t n = 0; n < (sizeof(tb_) / sizeof(tb_[0])); ++n) 34 | tb_[n][i] = matrix[n] * i; 35 | for (GLB_ int32_t i = 0; i <= convertor::MAX; ++i) 36 | tb_[2][i] += matrix[3]; 37 | } 38 | 39 | R2Y_FORCE_INLINE_ GLB_ int32_t convert(R2Y_ pixel_t const & in_p) const 40 | { 41 | return (tb_[0][in_p.a_] + tb_[1][in_p.b_] + tb_[2][in_p.c_]) >> 8; 42 | } 43 | 44 | template 45 | R2Y_FORCE_INLINE_ auto convert(R2Y_ pixel_t const & in_p) const 46 | -> STD_ enable_if_t 47 | { 48 | return clip(this->convert(in_p)); 49 | } 50 | 51 | template 52 | R2Y_FORCE_INLINE_ auto convert(R2Y_ pixel_t const & in_p) const 53 | -> STD_ enable_if_t 54 | { 55 | return this->convert(in_p); 56 | } 57 | 58 | private: 59 | GLB_ int32_t tb_[3][convertor::MAX + 1]; 60 | }; 61 | 62 | R2Y_FORCE_INLINE_ convertor const * factor_matrix(void) 63 | { 64 | /* 65 | * The factors for converting between YUV and RGB 66 | * See: https://msdn.microsoft.com/en-us/library/ms893078.aspx 67 | */ 68 | static GLB_ int32_t const matrix[R2Y_ plane_MAX][4] = 69 | { 70 | { 66 , 129, 25 , 4224 }, // RGB -> Y 71 | { -38 , -74 , 112, 32896 }, // RGB -> U/Cb 72 | { 112, -94 , -18 , 32896 }, // RGB -> V/Cr 73 | 74 | { 298, 0 , 409, -56992 }, // YUV -> R 75 | { 298, -100, -208, 34784 }, // YUV -> G 76 | { 298, 516, 0 , -70688 } // YUV -> B 77 | }; 78 | // Create and initialize the convertors 79 | static R2Y_ convertor const conv[R2Y_ plane_MAX] = 80 | { 81 | matrix[0], matrix[1], matrix[2], 82 | matrix[3], matrix[4], matrix[5] 83 | }; 84 | // Return the convertors 85 | return conv; 86 | } 87 | 88 | template 89 | R2Y_FORCE_INLINE_ GLB_ uint8_t pixel_convert(R2Y_ pixel_t const & in_p) 90 | { 91 | return factor_matrix()[P].convert::value>(in_p); 92 | } 93 | 94 | template 95 | R2Y_FORCE_INLINE_ auto pixel_convert(T const & in_p) 96 | -> STD_ enable_if_t<(R2Y_ is_yuv_plane

::value && STD_ is_same::value) || 97 | (R2Y_ is_rgb_plane

::value && STD_ is_same::value), GLB_ uint8_t> 98 | { 99 | return pixel_convert

(R2Y_ pixel_t::cast(in_p)); 100 | } 101 | 102 | R2Y_FORCE_INLINE_ R2Y_ yuv_t pixel_convert(R2Y_ rgb_t const & in_p) 103 | { 104 | return 105 | { 106 | pixel_convert(in_p), 107 | pixel_convert(in_p), 108 | pixel_convert(in_p) 109 | }; 110 | } 111 | 112 | R2Y_FORCE_INLINE_ R2Y_ rgb_t pixel_convert(R2Y_ yuv_t const & in_p) 113 | { 114 | return 115 | { 116 | pixel_convert(in_p), 117 | pixel_convert(in_p), 118 | pixel_convert(in_p) 119 | }; 120 | } 121 | -------------------------------------------------------------------------------- /include/detail/pixel_iterator.hxx: -------------------------------------------------------------------------------- 1 | /* 2 | rgb2yuv - Code covered by the MIT License 3 | Author: mutouyun (http://orzz.org) 4 | */ 5 | 6 | //////////////////////////////////////////////////////////////// 7 | /// The pixel iterator for an image 8 | //////////////////////////////////////////////////////////////// 9 | 10 | namespace detail_iterator_ { 11 | 12 | #pragma push_macro("R2Y_DETAIL_") 13 | #undef R2Y_DETAIL_ 14 | #define R2Y_DETAIL_ R2Y_ detail_iterator_:: 15 | 16 | #pragma push_macro("R2Y_HELPER_") 17 | #undef R2Y_HELPER_ 18 | #define R2Y_HELPER_ R2Y_ detail_helper_:: 19 | 20 | #pragma push_macro("R2Y_DETAIL_INHERIT_") 21 | #undef R2Y_DETAIL_INHERIT_ 22 | #define R2Y_DETAIL_INHERIT_(SP, P) \ 23 | template \ 24 | class impl_ : public impl_ \ 25 | { \ 26 | public: \ 27 | using impl_::impl_; \ 28 | }; 29 | 30 | template 31 | class impl_; 32 | 33 | /* RGB 888 */ 34 | 35 | template class impl_ 36 | { 37 | R2Y_ rgb_t * rgb_; 38 | 39 | public: 40 | enum { iterator_size = 1, is_block = 0 }; 41 | 42 | impl_(R2Y_ byte_t * in_data, GLB_ size_t /*in_w*/, GLB_ size_t /*in_h*/) 43 | : rgb_(reinterpret_cast(in_data)) 44 | {} 45 | 46 | void set_and_next(R2Y_ rgb_t const & rhs) 47 | { 48 | (*rgb_) = rhs; 49 | ++rgb_; 50 | } 51 | 52 | template 53 | void set_and_next(R2Y_ rgb_t const (&rhs)[N]) 54 | { 55 | memcpy(rgb_, rhs, sizeof(rhs)); 56 | rgb_ += N; 57 | } 58 | }; 59 | 60 | /* RGB 888X */ 61 | 62 | template class impl_ 63 | { 64 | GLB_ uint32_t * rgb_; 65 | 66 | public: 67 | enum { iterator_size = 1, is_block = 0 }; 68 | 69 | impl_(R2Y_ byte_t * in_data, GLB_ size_t /*in_w*/, GLB_ size_t /*in_h*/) 70 | : rgb_(reinterpret_cast(in_data)) 71 | {} 72 | 73 | void set_and_next(R2Y_ rgb_t const & rhs) 74 | { 75 | (*reinterpret_cast(rgb_)) = rhs; 76 | ++rgb_; 77 | } 78 | 79 | template 80 | void set_and_next(R2Y_ rgb_t const (&rhs)[N]) 81 | { 82 | for (GLB_ size_t i = 0; i < N; ++i) 83 | { 84 | set_and_next(rhs[i]); 85 | } 86 | } 87 | }; 88 | 89 | /* YUV Packed */ 90 | 91 | #pragma push_macro("R2Y_SET_AND_NEXT_") 92 | #undef R2Y_SET_AND_NEXT_ 93 | #define R2Y_SET_AND_NEXT_(I, OP, ...) do \ 94 | { \ 95 | R2Y_ yuv_t const & pix = rhs[I]; \ 96 | yuv_->y##I##_ = pix.y_; \ 97 | u_k OP pix.u_; \ 98 | v_k OP pix.v_; \ 99 | __VA_ARGS__ \ 100 | } while(0) 101 | 102 | /* 4:2:2 */ 103 | 104 | template class impl_ 105 | { 106 | typedef R2Y_HELPER_ packed_yuv_t p_t; 107 | 108 | p_t * yuv_; 109 | 110 | public: 111 | enum { iterator_size = 2, is_block = 0 }; 112 | 113 | impl_(R2Y_ byte_t * in_data, GLB_ size_t /*in_w*/, GLB_ size_t /*in_h*/) 114 | : yuv_(reinterpret_cast(in_data)) 115 | {} 116 | 117 | void set_and_next(R2Y_ yuv_t const (& rhs)[iterator_size]) 118 | { 119 | GLB_ uint16_t u_k, v_k; 120 | R2Y_SET_AND_NEXT_(0, = ); 121 | R2Y_SET_AND_NEXT_(1, +=, yuv_->cb_ = u_k >> 1; yuv_->cr_ = v_k >> 1;); 122 | ++yuv_; 123 | } 124 | }; 125 | 126 | R2Y_DETAIL_INHERIT_(yuv_YVYU, yuv_YUY2) 127 | R2Y_DETAIL_INHERIT_(yuv_UYVY, yuv_YUY2) 128 | R2Y_DETAIL_INHERIT_(yuv_VYUY, yuv_YUY2) 129 | 130 | /* 4:1:1 */ 131 | 132 | template class impl_ 133 | { 134 | typedef R2Y_HELPER_ packed_yuv_t p_t; 135 | 136 | p_t * yuv_; 137 | 138 | public: 139 | enum { iterator_size = 8, is_block = 0 }; 140 | 141 | impl_(R2Y_ byte_t * in_data, GLB_ size_t /*in_w*/, GLB_ size_t /*in_h*/) 142 | : yuv_(reinterpret_cast(in_data)) 143 | {} 144 | 145 | void set_and_next(R2Y_ yuv_t const (& rhs)[iterator_size]) 146 | { 147 | GLB_ uint16_t u_k, v_k; 148 | R2Y_SET_AND_NEXT_(0, = ); 149 | R2Y_SET_AND_NEXT_(1, +=); 150 | R2Y_SET_AND_NEXT_(2, +=); 151 | R2Y_SET_AND_NEXT_(3, +=, yuv_->u0_ = u_k >> 2; yuv_->v0_ = v_k >> 2;); 152 | R2Y_SET_AND_NEXT_(4, = ); 153 | R2Y_SET_AND_NEXT_(5, +=); 154 | R2Y_SET_AND_NEXT_(6, +=); 155 | R2Y_SET_AND_NEXT_(7, +=, yuv_->u1_ = u_k >> 2; yuv_->v1_ = v_k >> 2;); 156 | ++yuv_; 157 | } 158 | }; 159 | 160 | template class impl_ 161 | { 162 | typedef R2Y_HELPER_ packed_yuv_t p_t; 163 | 164 | p_t * yuv_; 165 | 166 | public: 167 | enum { iterator_size = 4, is_block = 0 }; 168 | 169 | impl_(R2Y_ byte_t * in_data, GLB_ size_t /*in_w*/, GLB_ size_t /*in_h*/) 170 | : yuv_(reinterpret_cast(in_data)) 171 | {} 172 | 173 | void set_and_next(R2Y_ yuv_t const (& rhs)[iterator_size]) 174 | { 175 | GLB_ uint16_t u_k, v_k; 176 | R2Y_SET_AND_NEXT_(0, = ); 177 | R2Y_SET_AND_NEXT_(1, +=); 178 | R2Y_SET_AND_NEXT_(2, +=); 179 | R2Y_SET_AND_NEXT_(3, +=, yuv_->cb_ = u_k >> 2; yuv_->cr_ = v_k >> 2;); 180 | ++yuv_; 181 | } 182 | }; 183 | 184 | #pragma pop_macro("R2Y_SET_AND_NEXT_") 185 | 186 | /* YUV Planar */ 187 | 188 | /* 4:4:4 */ 189 | 190 | template class impl_ : R2Y_HELPER_ yuv_planar 191 | { 192 | typedef R2Y_HELPER_ planar_uv_t uv_t; 193 | 194 | R2Y_ byte_t * y_; 195 | uv_t uv_; 196 | 197 | public: 198 | enum { iterator_size = 1, is_block = 0 }; 199 | 200 | impl_(R2Y_ byte_t * in_data, GLB_ size_t in_w, GLB_ size_t in_h) 201 | : R2Y_HELPER_ yuv_planar(y_, uv_, in_data, in_w, in_h) 202 | {} 203 | 204 | void set_and_next(R2Y_ yuv_t const & rhs) 205 | { 206 | (*y_) = rhs.y_; ++y_; 207 | R2Y_HELPER_ set_planar_uv(rhs.u_, rhs.v_, uv_); 208 | R2Y_HELPER_ next_planar_uv(uv_); 209 | } 210 | }; 211 | 212 | R2Y_DETAIL_INHERIT_(yuv_NV42, yuv_NV24) 213 | 214 | /* 4:2:2 */ 215 | 216 | template class impl_ : R2Y_HELPER_ yuv_planar 217 | { 218 | typedef R2Y_HELPER_ planar_uv_t uv_t; 219 | 220 | R2Y_ byte_t * y_; 221 | uv_t uv_; 222 | 223 | public: 224 | enum { iterator_size = 2, is_block = 0 }; 225 | 226 | impl_(R2Y_ byte_t * in_data, GLB_ size_t in_w, GLB_ size_t in_h) 227 | : R2Y_HELPER_ yuv_planar(y_, uv_, in_data, in_w, in_h) 228 | {} 229 | 230 | void set_and_next(R2Y_ yuv_t const (& rhs)[iterator_size]) 231 | { 232 | GLB_ uint16_t u_k, v_k; 233 | { 234 | R2Y_ yuv_t const & pix = rhs[0]; 235 | (*y_) = pix.y_; ++y_; 236 | u_k = pix.u_; 237 | v_k = pix.v_; 238 | } 239 | { 240 | R2Y_ yuv_t const & pix = rhs[1]; 241 | (*y_) = pix.y_; ++y_; 242 | R2Y_HELPER_ set_planar_uv((u_k + pix.u_) >> 1, 243 | (v_k + pix.v_) >> 1, uv_); 244 | R2Y_HELPER_ next_planar_uv(uv_); 245 | } 246 | } 247 | }; 248 | 249 | /* 4:2:0 */ 250 | 251 | template class impl_ : R2Y_HELPER_ yuv_planar 252 | { 253 | typedef R2Y_HELPER_ planar_uv_t uv_t; 254 | 255 | R2Y_ byte_t * y_, * y1_, * ye_; 256 | uv_t uv_; 257 | GLB_ size_t w_; 258 | 259 | public: 260 | enum { iterator_size = 2, is_block = 1 }; 261 | 262 | impl_(R2Y_ byte_t * in_data, GLB_ size_t in_w, GLB_ size_t in_h) 263 | : R2Y_HELPER_ yuv_planar(y_, uv_, in_data, in_w, in_h) 264 | , y1_(y_ + in_w), ye_(y1_) 265 | , w_(in_w) 266 | {} 267 | 268 | void set_and_next(R2Y_ yuv_t const (& rhs)[iterator_size * iterator_size]) 269 | { 270 | (*y_) = rhs[0].y_; ++y_; 271 | (*y_) = rhs[1].y_; ++y_; 272 | (*y1_) = rhs[2].y_; ++y1_; 273 | (*y1_) = rhs[3].y_; ++y1_; 274 | if (y_ == ye_) 275 | { 276 | y_ = y1_; 277 | y1_ += w_; 278 | ye_ = y1_; 279 | } 280 | R2Y_HELPER_ set_planar_uv((rhs[0].u_ + rhs[1].u_ + rhs[2].u_ + rhs[3].u_) >> 2, 281 | (rhs[0].v_ + rhs[1].v_ + rhs[2].v_ + rhs[3].v_) >> 2, uv_); 282 | R2Y_HELPER_ next_planar_uv(uv_); 283 | } 284 | }; 285 | 286 | R2Y_DETAIL_INHERIT_(yuv_YU12, yuv_YV12) 287 | R2Y_DETAIL_INHERIT_(yuv_NV12, yuv_YV12) 288 | R2Y_DETAIL_INHERIT_(yuv_NV21, yuv_YV12) 289 | 290 | /* 4:1:1 */ 291 | 292 | template class impl_ : R2Y_HELPER_ yuv_planar 293 | { 294 | typedef R2Y_HELPER_ planar_uv_t uv_t; 295 | 296 | R2Y_ byte_t * y_; 297 | uv_t uv_; 298 | 299 | public: 300 | enum { iterator_size = 4, is_block = 0 }; 301 | 302 | impl_(R2Y_ byte_t * in_data, GLB_ size_t in_w, GLB_ size_t in_h) 303 | : R2Y_HELPER_ yuv_planar(y_, uv_, in_data, in_w, in_h) 304 | {} 305 | 306 | void set_and_next(R2Y_ yuv_t const (& rhs)[iterator_size]) 307 | { 308 | GLB_ uint16_t u_k, v_k; 309 | 310 | # pragma push_macro("R2Y_SET_AND_NEXT_") 311 | # undef R2Y_SET_AND_NEXT_ 312 | # define R2Y_SET_AND_NEXT_(I, OP, ...) do \ 313 | { \ 314 | R2Y_ yuv_t const & pix = rhs[I]; \ 315 | (*y_) = pix.y_; ++y_; \ 316 | u_k OP pix.u_; \ 317 | v_k OP pix.v_; \ 318 | __VA_ARGS__ \ 319 | } while(0) 320 | 321 | R2Y_SET_AND_NEXT_(0, = ); 322 | R2Y_SET_AND_NEXT_(1, +=); 323 | R2Y_SET_AND_NEXT_(2, +=); 324 | R2Y_SET_AND_NEXT_(3, +=, R2Y_HELPER_ set_planar_uv(u_k >> 2, v_k >> 2, uv_); 325 | R2Y_HELPER_ next_planar_uv(uv_);); 326 | 327 | # pragma pop_macro("R2Y_SET_AND_NEXT_") 328 | } 329 | }; 330 | 331 | /* 4:1:0 */ 332 | 333 | template class impl_ : R2Y_HELPER_ yuv_planar 334 | { 335 | typedef R2Y_HELPER_ planar_uv_t uv_t; 336 | 337 | R2Y_ byte_t * y_, * y1_, * y2_, * y3_, * ye_; 338 | uv_t uv_; 339 | GLB_ size_t w_; 340 | 341 | public: 342 | enum { iterator_size = 4, is_block = 1 }; 343 | 344 | impl_(R2Y_ byte_t * in_data, GLB_ size_t in_w, GLB_ size_t in_h) 345 | : R2Y_HELPER_ yuv_planar(y_, uv_, in_data, in_w, in_h) 346 | , y1_(y_ + in_w), y2_(y1_ + in_w), y3_(y2_ + in_w), ye_(y1_) 347 | , w_(in_w) 348 | {} 349 | 350 | void set_and_next(R2Y_ yuv_t const (& rhs)[iterator_size * iterator_size]) 351 | { 352 | int i = 0; 353 | for (; i < 4 ; ++i, ++y_ ) (*y_) = rhs[i].y_; 354 | for (; i < 8 ; ++i, ++y1_) (*y1_) = rhs[i].y_; 355 | for (; i < 12; ++i, ++y2_) (*y2_) = rhs[i].y_; 356 | for (; i < 16; ++i, ++y3_) (*y3_) = rhs[i].y_; 357 | if (y_ == ye_) 358 | { 359 | y_ = y3_; 360 | y1_ = y_ + w_; 361 | y2_ = y1_ + w_; 362 | y3_ = y2_ + w_; 363 | ye_ = y1_; 364 | } 365 | R2Y_HELPER_ set_planar_uv((rhs[0 ].u_ + rhs[1 ].u_ + rhs[2 ].u_ + rhs[3 ].u_ + 366 | rhs[4 ].u_ + rhs[5 ].u_ + rhs[6 ].u_ + rhs[7 ].u_ + 367 | rhs[8 ].u_ + rhs[9 ].u_ + rhs[10].u_ + rhs[11].u_ + 368 | rhs[12].u_ + rhs[13].u_ + rhs[14].u_ + rhs[15].u_) >> 4, 369 | (rhs[0 ].v_ + rhs[1 ].v_ + rhs[2 ].v_ + rhs[3 ].v_ + 370 | rhs[4 ].v_ + rhs[5 ].v_ + rhs[6 ].v_ + rhs[7 ].v_ + 371 | rhs[8 ].v_ + rhs[9 ].v_ + rhs[10].v_ + rhs[11].v_ + 372 | rhs[12].v_ + rhs[13].v_ + rhs[14].v_ + rhs[15].v_) >> 4, uv_); 373 | R2Y_HELPER_ next_planar_uv(uv_); 374 | } 375 | }; 376 | 377 | R2Y_DETAIL_INHERIT_(yuv_YVU9, yuv_YUV9) 378 | 379 | #pragma pop_macro("R2Y_DETAIL_INHERIT_") 380 | #pragma pop_macro("R2Y_HELPER_") 381 | #pragma pop_macro("R2Y_DETAIL_") 382 | 383 | } // namespace detail_iterator_ 384 | 385 | template 386 | class iterator : public R2Y_ detail_iterator_::impl_ 387 | { 388 | typedef R2Y_ detail_iterator_::impl_ base_t; 389 | 390 | public: 391 | using base_t::base_t; 392 | }; 393 | -------------------------------------------------------------------------------- /include/detail/pixel_walker.hxx: -------------------------------------------------------------------------------- 1 | /* 2 | rgb2yuv - Code covered by the MIT License 3 | Author: mutouyun (http://orzz.org) 4 | */ 5 | 6 | //////////////////////////////////////////////////////////////// 7 | /// It's a pixel walker to walk each pixel and execute a closure with it. 8 | //////////////////////////////////////////////////////////////// 9 | 10 | /* 888 */ 11 | 12 | template > 13 | auto pixel_foreach(R2Y_ byte_t * in_data, GLB_ size_t in_w, GLB_ size_t in_h, T && do_sth) 14 | -> STD_ enable_if_t<(S == R2Y_ rgb_888 && F::iterator_size == 1 && F::is_block == 0)> 15 | { 16 | GLB_ size_t size = calculate_size(in_w, in_h); 17 | assert((size % sizeof(R2Y_ rgb_t)) == 0); // 3 input bytes convert to 1 pixel 18 | R2Y_ rgb_t * cur_pixel = reinterpret_cast(in_data); 19 | for (GLB_ size_t i = 0; i < size; i += 3, ++cur_pixel) 20 | { 21 | STD_ forward(do_sth)(*cur_pixel); 22 | } 23 | } 24 | 25 | template > 26 | auto pixel_foreach(R2Y_ byte_t * in_data, GLB_ size_t in_w, GLB_ size_t in_h, T && do_sth) 27 | -> STD_ enable_if_t<(S == R2Y_ rgb_888 && F::iterator_size > 1 && F::is_block == 0)> 28 | { 29 | GLB_ size_t size = calculate_size(in_w, in_h); 30 | assert((size % sizeof(R2Y_ rgb_t)) == 0); // 3 input bytes convert to 1 pixel 31 | R2Y_ rgb_t * cur_pixel = reinterpret_cast(in_data); 32 | for (GLB_ size_t i = 0; i < size; i += (3 * F::iterator_size), cur_pixel += F::iterator_size) 33 | { 34 | STD_ forward(do_sth)(*reinterpret_cast(& cur_pixel)); 35 | } 36 | } 37 | 38 | template > 39 | auto pixel_foreach(R2Y_ byte_t * in_data, GLB_ size_t in_w, GLB_ size_t in_h, T && do_sth) 40 | -> STD_ enable_if_t<(S == R2Y_ rgb_888 && F::iterator_size > 1 && F::is_block == 1)> 41 | { 42 | assert((in_w % F::iterator_size) == 0); 43 | assert((in_h % F::iterator_size) == 0); 44 | R2Y_ rgb_t tmp[F::iterator_size * F::iterator_size]; 45 | GLB_ size_t row_offset = in_w - F::iterator_size; 46 | R2Y_ rgb_t * cur_pixel = reinterpret_cast(in_data); 47 | for (GLB_ size_t i = 0; i < in_h; i += F::iterator_size, cur_pixel += (in_w * (F::iterator_size - 1))) 48 | { 49 | for (GLB_ size_t j = 0; j < in_w; j += F::iterator_size, cur_pixel += F::iterator_size) 50 | { 51 | R2Y_ rgb_t * block_iter = cur_pixel; 52 | for (int n = 0, index = 0; n < F::iterator_size; ++n, block_iter += row_offset) 53 | { 54 | for (int m = 0; m < F::iterator_size; ++m, ++index, ++block_iter) 55 | { 56 | tmp[index] = *block_iter; 57 | } 58 | } 59 | STD_ forward(do_sth)(tmp); 60 | } 61 | } 62 | } 63 | 64 | /* 565 */ 65 | 66 | template > 67 | auto pixel_foreach(R2Y_ byte_t * in_data, GLB_ size_t in_w, GLB_ size_t in_h, T && do_sth) 68 | -> STD_ enable_if_t<(S == R2Y_ rgb_565 && F::iterator_size == 1 && F::is_block == 0)> 69 | { 70 | GLB_ size_t size = calculate_size(in_w, in_h); 71 | assert((size & 1) == 0); // in_size must be an even number 72 | R2Y_ rgb_t tmp; 73 | GLB_ uint16_t * cur_pixel = reinterpret_cast(in_data); 74 | for (GLB_ size_t i = 0; i < size; i += 2, ++cur_pixel) 75 | { 76 | tmp.r_ = static_cast( ((*cur_pixel) & 0xF800) >> 8 ); 77 | tmp.g_ = static_cast( ((*cur_pixel) & 0x07E0) >> 3 ); 78 | tmp.b_ = static_cast( ((*cur_pixel) & 0x001F) << 3 ); 79 | STD_ forward(do_sth)(tmp); 80 | } 81 | } 82 | 83 | template > 84 | auto pixel_foreach(R2Y_ byte_t * in_data, GLB_ size_t in_w, GLB_ size_t in_h, T && do_sth) 85 | -> STD_ enable_if_t<(S == R2Y_ rgb_565 && F::iterator_size > 1 && F::is_block == 0)> 86 | { 87 | GLB_ size_t size = calculate_size(in_w, in_h); 88 | assert((size & 1) == 0); // in_size must be an even number 89 | R2Y_ rgb_t tmp[F::iterator_size]; 90 | GLB_ uint16_t * cur_pixel = reinterpret_cast(in_data); 91 | for (GLB_ size_t i = 0; i < size; i += (2 * F::iterator_size)) 92 | { 93 | for (int n = 0; n < F::iterator_size; ++n, ++cur_pixel) 94 | { 95 | R2Y_ rgb_t & ref = tmp[n]; 96 | ref.r_ = static_cast( ((*cur_pixel) & 0xF800) >> 8 ); 97 | ref.g_ = static_cast( ((*cur_pixel) & 0x07E0) >> 3 ); 98 | ref.b_ = static_cast( ((*cur_pixel) & 0x001F) << 3 ); 99 | } 100 | STD_ forward(do_sth)(tmp); 101 | } 102 | } 103 | 104 | template > 105 | auto pixel_foreach(R2Y_ byte_t * in_data, GLB_ size_t in_w, GLB_ size_t in_h, T && do_sth) 106 | -> STD_ enable_if_t<(S == R2Y_ rgb_565 && F::iterator_size > 1 && F::is_block == 1)> 107 | { 108 | assert((in_w % F::iterator_size) == 0); 109 | assert((in_h % F::iterator_size) == 0); 110 | R2Y_ rgb_t tmp[F::iterator_size * F::iterator_size]; 111 | GLB_ size_t row_offset = in_w - F::iterator_size; 112 | GLB_ uint16_t * cur_pixel = reinterpret_cast(in_data); 113 | for (GLB_ size_t i = 0; i < in_h; i += F::iterator_size, cur_pixel += (in_w * (F::iterator_size - 1))) 114 | { 115 | for (GLB_ size_t j = 0; j < in_w; j += F::iterator_size, cur_pixel += F::iterator_size) 116 | { 117 | GLB_ uint16_t * block_iter = cur_pixel; 118 | for (int n = 0, index = 0; n < F::iterator_size; ++n, block_iter += row_offset) 119 | { 120 | for (int m = 0; m < F::iterator_size; ++m, ++index, ++block_iter) 121 | { 122 | R2Y_ rgb_t & ref = tmp[index]; 123 | ref.r_ = static_cast( ((*block_iter) & 0xF800) >> 8 ); 124 | ref.g_ = static_cast( ((*block_iter) & 0x07E0) >> 3 ); 125 | ref.b_ = static_cast( ((*block_iter) & 0x001F) << 3 ); 126 | } 127 | } 128 | STD_ forward(do_sth)(tmp); 129 | } 130 | } 131 | } 132 | 133 | /* 555 */ 134 | 135 | template > 136 | auto pixel_foreach(R2Y_ byte_t * in_data, GLB_ size_t in_w, GLB_ size_t in_h, T && do_sth) 137 | -> STD_ enable_if_t<(S == R2Y_ rgb_555 && F::iterator_size == 1 && F::is_block == 0)> 138 | { 139 | GLB_ size_t size = calculate_size(in_w, in_h); 140 | assert((size & 1) == 0); // in_size must be an even number 141 | R2Y_ rgb_t tmp; 142 | GLB_ uint16_t * cur_pixel = reinterpret_cast(in_data); 143 | for (GLB_ size_t i = 0; i < size; i += 2, ++cur_pixel) 144 | { 145 | tmp.r_ = static_cast( ((*cur_pixel) & 0x7C00) >> 7 ); 146 | tmp.g_ = static_cast( ((*cur_pixel) & 0x03E0) >> 2 ); 147 | tmp.b_ = static_cast( ((*cur_pixel) & 0x001F) << 3 ); 148 | STD_ forward(do_sth)(tmp); 149 | } 150 | } 151 | 152 | template > 153 | auto pixel_foreach(R2Y_ byte_t * in_data, GLB_ size_t in_w, GLB_ size_t in_h, T && do_sth) 154 | -> STD_ enable_if_t<(S == R2Y_ rgb_555 && F::iterator_size > 1 && F::is_block == 0)> 155 | { 156 | GLB_ size_t size = calculate_size(in_w, in_h); 157 | assert((size & 1) == 0); // in_size must be an even number 158 | R2Y_ rgb_t tmp[F::iterator_size]; 159 | GLB_ uint16_t * cur_pixel = reinterpret_cast(in_data); 160 | for (GLB_ size_t i = 0; i < size; i += (2 * F::iterator_size)) 161 | { 162 | for (int n = 0; n < F::iterator_size; ++n, ++cur_pixel) 163 | { 164 | R2Y_ rgb_t & ref = tmp[n]; 165 | ref.r_ = static_cast( ((*cur_pixel) & 0x7C00) >> 7 ); 166 | ref.g_ = static_cast( ((*cur_pixel) & 0x03E0) >> 2 ); 167 | ref.b_ = static_cast( ((*cur_pixel) & 0x001F) << 3 ); 168 | } 169 | STD_ forward(do_sth)(tmp); 170 | } 171 | } 172 | 173 | template > 174 | auto pixel_foreach(R2Y_ byte_t * in_data, GLB_ size_t in_w, GLB_ size_t in_h, T && do_sth) 175 | -> STD_ enable_if_t<(S == R2Y_ rgb_555 && F::iterator_size > 1 && F::is_block == 1)> 176 | { 177 | assert((in_w % F::iterator_size) == 0); 178 | assert((in_h % F::iterator_size) == 0); 179 | R2Y_ rgb_t tmp[F::iterator_size * F::iterator_size]; 180 | GLB_ size_t row_offset = in_w - F::iterator_size; 181 | GLB_ uint16_t * cur_pixel = reinterpret_cast(in_data); 182 | for (GLB_ size_t i = 0; i < in_h; i += F::iterator_size, cur_pixel += (in_w * (F::iterator_size - 1))) 183 | { 184 | for (GLB_ size_t j = 0; j < in_w; j += F::iterator_size, cur_pixel += F::iterator_size) 185 | { 186 | GLB_ uint16_t * block_iter = cur_pixel; 187 | for (int n = 0, index = 0; n < F::iterator_size; ++n, block_iter += row_offset) 188 | { 189 | for (int m = 0; m < F::iterator_size; ++m, ++index, ++block_iter) 190 | { 191 | R2Y_ rgb_t & ref = tmp[index]; 192 | ref.r_ = static_cast( ((*block_iter) & 0x7C00) >> 7 ); 193 | ref.g_ = static_cast( ((*block_iter) & 0x03E0) >> 2 ); 194 | ref.b_ = static_cast( ((*block_iter) & 0x001F) << 3 ); 195 | } 196 | } 197 | STD_ forward(do_sth)(tmp); 198 | } 199 | } 200 | } 201 | 202 | /* 444 */ 203 | 204 | template > 205 | auto pixel_foreach(R2Y_ byte_t * in_data, GLB_ size_t in_w, GLB_ size_t in_h, T && do_sth) 206 | -> STD_ enable_if_t<(S == R2Y_ rgb_444 && F::iterator_size == 1 && F::is_block == 0)> 207 | { 208 | GLB_ size_t size = calculate_size(in_w, in_h); 209 | assert((size % 3) == 0); // 3 input bytes convert to 2 pixels (6 bytes) 210 | R2Y_ rgb_t tmp; 211 | for (GLB_ size_t i = 0; i < size; i += 3) 212 | { 213 | tmp.b_ = static_cast( ((*in_data) & 0x0F) << 4 ); 214 | tmp.g_ = static_cast ((*in_data) & 0xF0); ++in_data; 215 | tmp.r_ = static_cast( ((*in_data) & 0x0F) << 4 ); 216 | STD_ forward(do_sth)(tmp); 217 | tmp.b_ = static_cast ((*in_data) & 0xF0); ++in_data; 218 | tmp.g_ = static_cast( ((*in_data) & 0x0F) << 4 ); 219 | tmp.r_ = static_cast ((*in_data) & 0xF0); ++in_data; 220 | STD_ forward(do_sth)(tmp); 221 | } 222 | } 223 | 224 | template > 225 | auto pixel_foreach(R2Y_ byte_t * in_data, GLB_ size_t in_w, GLB_ size_t in_h, T && do_sth) 226 | -> STD_ enable_if_t<(S == R2Y_ rgb_444 && F::iterator_size > 1 && (F::iterator_size & 1) == 0 && F::is_block == 0)> 227 | { 228 | GLB_ size_t size = calculate_size(in_w, in_h); 229 | assert((size % 3) == 0); // 3 input bytes convert to 2 pixels (6 bytes) 230 | R2Y_ rgb_t tmp[F::iterator_size]; 231 | for (GLB_ size_t i = 0; i < size; i += (3 * (F::iterator_size >> 1))) 232 | { 233 | for (int n = 0; n < F::iterator_size;) 234 | { 235 | { 236 | R2Y_ rgb_t & ref = tmp[n]; ++n; 237 | ref.b_ = static_cast( ((*in_data) & 0x0F) << 4 ); 238 | ref.g_ = static_cast ((*in_data) & 0xF0); ++in_data; 239 | ref.r_ = static_cast( ((*in_data) & 0x0F) << 4 ); 240 | } 241 | { 242 | R2Y_ rgb_t & ref = tmp[n]; ++n; 243 | ref.b_ = static_cast ((*in_data) & 0xF0); ++in_data; 244 | ref.g_ = static_cast( ((*in_data) & 0x0F) << 4 ); 245 | ref.r_ = static_cast ((*in_data) & 0xF0); ++in_data; 246 | } 247 | } 248 | STD_ forward(do_sth)(tmp); 249 | } 250 | } 251 | 252 | template > 253 | auto pixel_foreach(R2Y_ byte_t * in_data, GLB_ size_t in_w, GLB_ size_t in_h, T && do_sth) 254 | -> STD_ enable_if_t<(S == R2Y_ rgb_444 && F::iterator_size > 1 && (F::iterator_size & 1) == 0 && F::is_block == 1)> 255 | { 256 | assert((in_w % F::iterator_size) == 0); 257 | assert((in_h % F::iterator_size) == 0); 258 | R2Y_ rgb_t tmp[F::iterator_size * F::iterator_size]; 259 | GLB_ size_t row_offset = ((in_w - F::iterator_size) >> 1) * 3; 260 | for (GLB_ size_t i = 0; i < in_h; i += F::iterator_size, in_data += (in_w * (((F::iterator_size - 1) * 3) >> 1))) 261 | { 262 | for (GLB_ size_t j = 0; j < in_w; j += F::iterator_size, in_data += (3 * (F::iterator_size >> 1))) 263 | { 264 | R2Y_ byte_t * block_iter = in_data; 265 | for (int n = 0, index = 0; n < F::iterator_size; ++n, block_iter += row_offset) 266 | { 267 | for (int m = 0; m < F::iterator_size; m += 2) 268 | { 269 | { 270 | R2Y_ rgb_t & ref = tmp[index]; ++index; 271 | ref.b_ = static_cast( ((*block_iter) & 0x0F) << 4 ); 272 | ref.g_ = static_cast ((*block_iter) & 0xF0); ++block_iter; 273 | ref.r_ = static_cast( ((*block_iter) & 0x0F) << 4 ); 274 | } 275 | { 276 | R2Y_ rgb_t & ref = tmp[index]; ++index; 277 | ref.b_ = static_cast ((*block_iter) & 0xF0); ++block_iter; 278 | ref.g_ = static_cast( ((*block_iter) & 0x0F) << 4 ); 279 | ref.r_ = static_cast ((*block_iter) & 0xF0); ++block_iter; 280 | } 281 | } 282 | } 283 | STD_ forward(do_sth)(tmp); 284 | } 285 | } 286 | } 287 | 288 | /* 888X */ 289 | 290 | template > 291 | auto pixel_foreach(R2Y_ byte_t * in_data, GLB_ size_t in_w, GLB_ size_t in_h, T && do_sth) 292 | -> STD_ enable_if_t<(S == R2Y_ rgb_888X && F::iterator_size == 1 && F::is_block == 0)> 293 | { 294 | GLB_ size_t size = calculate_size(in_w, in_h); 295 | assert((size % 4) == 0); // 4 input bytes convert to 1 pixel (3 bytes) 296 | GLB_ uint32_t * cur_pixel = reinterpret_cast(in_data); 297 | for (GLB_ size_t i = 0; i < size; i += 4, ++cur_pixel) 298 | { 299 | STD_ forward(do_sth)(*reinterpret_cast(cur_pixel)); 300 | } 301 | } 302 | 303 | template > 304 | auto pixel_foreach(R2Y_ byte_t * in_data, GLB_ size_t in_w, GLB_ size_t in_h, T && do_sth) 305 | -> STD_ enable_if_t<(S == R2Y_ rgb_888X && F::iterator_size > 1 && F::is_block == 0)> 306 | { 307 | GLB_ size_t size = calculate_size(in_w, in_h); 308 | assert((size % 4) == 0); // 4 input bytes convert to 1 pixel (3 bytes) 309 | R2Y_ rgb_t tmp[F::iterator_size]; 310 | GLB_ uint32_t * cur_pixel = reinterpret_cast(in_data); 311 | for (GLB_ size_t i = 0; i < size; i += (4 * F::iterator_size)) 312 | { 313 | for (int n = 0; n < F::iterator_size; ++n, ++cur_pixel) 314 | { 315 | tmp[n] = *reinterpret_cast(cur_pixel); 316 | } 317 | STD_ forward(do_sth)(tmp); 318 | } 319 | } 320 | 321 | template > 322 | auto pixel_foreach(R2Y_ byte_t * in_data, GLB_ size_t in_w, GLB_ size_t in_h, T && do_sth) 323 | -> STD_ enable_if_t<(S == R2Y_ rgb_888X && F::iterator_size > 1 && F::is_block == 1)> 324 | { 325 | assert((in_w % F::iterator_size) == 0); 326 | assert((in_h % F::iterator_size) == 0); 327 | R2Y_ rgb_t tmp[F::iterator_size * F::iterator_size]; 328 | GLB_ size_t row_offset = in_w - F::iterator_size; 329 | GLB_ uint32_t * cur_pixel = reinterpret_cast(in_data); 330 | for (GLB_ size_t i = 0; i < in_h; i += F::iterator_size, cur_pixel += (in_w * (F::iterator_size - 1))) 331 | { 332 | for (GLB_ size_t j = 0; j < in_w; j += F::iterator_size, cur_pixel += F::iterator_size) 333 | { 334 | GLB_ uint32_t * block_iter = cur_pixel; 335 | for (int n = 0, index = 0; n < F::iterator_size; ++n, block_iter += row_offset) 336 | { 337 | for (int m = 0; m < F::iterator_size; ++m, ++index, ++block_iter) 338 | { 339 | tmp[index] = *reinterpret_cast(block_iter); 340 | } 341 | } 342 | STD_ forward(do_sth)(tmp); 343 | } 344 | } 345 | } 346 | 347 | #pragma push_macro("R2Y_HELPER_") 348 | #undef R2Y_HELPER_ 349 | #define R2Y_HELPER_ R2Y_ detail_helper_:: 350 | 351 | /* YUYV/YVYU/UYVY/VYUY */ 352 | 353 | template > 354 | auto pixel_foreach(R2Y_ byte_t * in_data, GLB_ size_t in_w, GLB_ size_t in_h, T && do_sth) 355 | -> STD_ enable_if_t<((S == R2Y_ yuv_YUYV || S == R2Y_ yuv_YVYU || 356 | S == R2Y_ yuv_UYVY || S == R2Y_ yuv_VYUY) && F::iterator_size == 1 && F::is_block == 0)> 357 | { 358 | auto yuv = reinterpret_cast*>(in_data); 359 | for (GLB_ size_t i = 0; i < (in_w * in_h); i += R2Y_ iterator::iterator_size, ++yuv) 360 | { 361 | R2Y_ yuv_t tmp[R2Y_ iterator::iterator_size] = 362 | { 363 | { yuv->cr_, yuv->cb_, yuv->y0_ }, 364 | { yuv->cr_, yuv->cb_, yuv->y1_ } 365 | }; 366 | STD_ forward(do_sth)(tmp); 367 | } 368 | } 369 | 370 | /* Y41P */ 371 | 372 | template > 373 | auto pixel_foreach(R2Y_ byte_t * in_data, GLB_ size_t in_w, GLB_ size_t in_h, T && do_sth) 374 | -> STD_ enable_if_t<(S == R2Y_ yuv_Y41P && F::iterator_size == 1 && F::is_block == 0)> 375 | { 376 | auto yuv = reinterpret_cast*>(in_data); 377 | for (GLB_ size_t i = 0; i < (in_w * in_h); i += R2Y_ iterator::iterator_size, ++yuv) 378 | { 379 | R2Y_ yuv_t tmp[R2Y_ iterator::iterator_size] = 380 | { 381 | { yuv->v0_, yuv->u0_, yuv->y0_ }, 382 | { yuv->v0_, yuv->u0_, yuv->y1_ }, 383 | { yuv->v0_, yuv->u0_, yuv->y2_ }, 384 | { yuv->v0_, yuv->u0_, yuv->y3_ }, 385 | { yuv->v1_, yuv->u1_, yuv->y4_ }, 386 | { yuv->v1_, yuv->u1_, yuv->y5_ }, 387 | { yuv->v1_, yuv->u1_, yuv->y6_ }, 388 | { yuv->v1_, yuv->u1_, yuv->y7_ } 389 | }; 390 | STD_ forward(do_sth)(tmp); 391 | } 392 | } 393 | 394 | /* Y411 */ 395 | 396 | template > 397 | auto pixel_foreach(R2Y_ byte_t * in_data, GLB_ size_t in_w, GLB_ size_t in_h, T && do_sth) 398 | -> STD_ enable_if_t<(S == R2Y_ yuv_Y411 && F::iterator_size == 1 && F::is_block == 0)> 399 | { 400 | auto yuv = reinterpret_cast*>(in_data); 401 | for (GLB_ size_t i = 0; i < (in_w * in_h); i += R2Y_ iterator::iterator_size, ++yuv) 402 | { 403 | R2Y_ yuv_t tmp[R2Y_ iterator::iterator_size] = 404 | { 405 | { yuv->cr_, yuv->cb_, yuv->y0_ }, 406 | { yuv->cr_, yuv->cb_, yuv->y1_ }, 407 | { yuv->cr_, yuv->cb_, yuv->y2_ }, 408 | { yuv->cr_, yuv->cb_, yuv->y3_ } 409 | }; 410 | STD_ forward(do_sth)(tmp); 411 | } 412 | } 413 | 414 | /* NV24/NV42 */ 415 | 416 | template > 417 | auto pixel_foreach(R2Y_ byte_t * in_data, GLB_ size_t in_w, GLB_ size_t in_h, T && do_sth) 418 | -> STD_ enable_if_t<((S == R2Y_ yuv_NV24 || S == R2Y_ yuv_NV42) && F::iterator_size == 1 && F::is_block == 0)> 419 | { 420 | R2Y_ byte_t * y = nullptr; 421 | R2Y_HELPER_ planar_uv_t uv; 422 | R2Y_HELPER_ yuv_planar (y, uv, in_data, in_w, in_h); 423 | for (GLB_ size_t i = 0; i < (in_w * in_h); ++i, ++y, ++(uv.uv_)) 424 | { 425 | STD_ forward(do_sth)(R2Y_ yuv_t { uv.uv_->cr_, uv.uv_->cb_, *y }); 426 | } 427 | } 428 | 429 | /* YV12/YU12/NV12/NV21 */ 430 | 431 | template > 432 | auto pixel_foreach(R2Y_ byte_t * in_data, GLB_ size_t in_w, GLB_ size_t in_h, T && do_sth) 433 | -> STD_ enable_if_t<((S == R2Y_ yuv_YV12 || S == R2Y_ yuv_YU12 || 434 | S == R2Y_ yuv_NV12 || S == R2Y_ yuv_NV21) && F::iterator_size == 1 && F::is_block == 0)> 435 | { 436 | R2Y_ byte_t * y = nullptr; 437 | R2Y_HELPER_ planar_uv_t uv; 438 | R2Y_HELPER_ yuv_planar (y, uv, in_data, in_w, in_h); 439 | R2Y_HELPER_ planar_uv_t uv1 = uv; 440 | for (GLB_ size_t i = 0; i < in_h; i += 2) 441 | { 442 | for (GLB_ size_t j = 0; j < in_w; j += 2) 443 | { 444 | R2Y_ yuv_t tmp[2]; 445 | tmp[0].y_ = *y; ++y; 446 | tmp[1].y_ = *y; ++y; 447 | R2Y_HELPER_ get_planar_uv(tmp[0].u_, tmp[0].v_, uv); 448 | R2Y_HELPER_ get_planar_uv(tmp[1].u_, tmp[1].v_, uv); 449 | R2Y_HELPER_ next_planar_uv(uv); 450 | STD_ forward(do_sth)(tmp); 451 | } 452 | for (GLB_ size_t j = 0; j < in_w; j += 2) 453 | { 454 | R2Y_ yuv_t tmp[2]; 455 | tmp[0].y_ = *y; ++y; 456 | tmp[1].y_ = *y; ++y; 457 | R2Y_HELPER_ get_planar_uv(tmp[0].u_, tmp[0].v_, uv1); 458 | R2Y_HELPER_ get_planar_uv(tmp[1].u_, tmp[1].v_, uv1); 459 | R2Y_HELPER_ next_planar_uv(uv1); 460 | STD_ forward(do_sth)(tmp); 461 | } 462 | } 463 | } 464 | 465 | #pragma pop_macro("R2Y_HELPER_") 466 | -------------------------------------------------------------------------------- /include/detail/predefine.hxx: -------------------------------------------------------------------------------- 1 | /* 2 | rgb2yuv - Code covered by the MIT License 3 | Author: mutouyun (http://orzz.org) 4 | */ 5 | 6 | //////////////////////////////////////////////////////////////// 7 | /// Predefine functional macros 8 | //////////////////////////////////////////////////////////////// 9 | 10 | #pragma push_macro("GLB_") 11 | #undef GLB_ 12 | #define GLB_ :: 13 | 14 | #pragma push_macro("STD_") 15 | #undef STD_ 16 | #define STD_ GLB_ std:: 17 | 18 | #pragma push_macro("R2Y_NAMESPACE_") 19 | #undef R2Y_NAMESPACE_ 20 | #define R2Y_NAMESPACE_ r2y 21 | 22 | #pragma push_macro("R2Y_") 23 | #undef R2Y_ 24 | #define R2Y_ GLB_ R2Y_NAMESPACE_ :: 25 | 26 | #pragma push_macro("R2Y_ALLOC_") 27 | #ifndef R2Y_ALLOC_ 28 | #define R2Y_ALLOC_ R2Y_ allocator 29 | #endif // R2Y_ALLOC_ 30 | 31 | #pragma push_macro("R2Y_UNUSED_") 32 | #undef R2Y_UNUSED_ 33 | #if defined(_MSC_VER) 34 | # define R2Y_UNUSED_ __pragma(warning(suppress:4100)) 35 | #elif defined(__GNUC__) 36 | # define R2Y_UNUSED_ __attribute__((__unused__)) 37 | #else 38 | # define R2Y_UNUSED_ 39 | #endif 40 | 41 | #pragma push_macro("R2Y_FORCE_INLINE_") 42 | #if defined(_MSC_VER) 43 | # define R2Y_FORCE_INLINE_ __forceinline 44 | #elif defined(__GNUC__) 45 | # define R2Y_FORCE_INLINE_ __inline__ __attribute__((always_inline)) 46 | #else 47 | # define R2Y_FORCE_INLINE_ inline 48 | #endif 49 | -------------------------------------------------------------------------------- /include/detail/scope_block.hxx: -------------------------------------------------------------------------------- 1 | /* 2 | rgb2yuv - Code covered by the MIT License 3 | Author: mutouyun (http://orzz.org) 4 | */ 5 | 6 | //////////////////////////////////////////////////////////////// 7 | /// Define default memory allocator 8 | //////////////////////////////////////////////////////////////// 9 | 10 | struct allocator 11 | { 12 | static void * alloc(GLB_ size_t size) 13 | { 14 | return ( (size == 0) ? NULL : GLB_ operator new(size, STD_ nothrow) ); 15 | } 16 | 17 | static void free(void * ptr) 18 | { 19 | GLB_ operator delete(ptr, STD_ nothrow); 20 | } 21 | }; 22 | 23 | //////////////////////////////////////////////////////////////// 24 | /// The limited garbage collection facility for memory block 25 | //////////////////////////////////////////////////////////////// 26 | 27 | template 28 | class scope_block 29 | { 30 | template 31 | friend class scope_block; 32 | 33 | T * block_; 34 | GLB_ size_t size_; 35 | bool trust_; 36 | 37 | public: 38 | scope_block(void) 39 | : block_(NULL), size_(0), trust_(false) 40 | {} 41 | 42 | explicit scope_block(GLB_ size_t count) : scope_block() 43 | { 44 | reset(count); 45 | } 46 | 47 | scope_block(T * block, GLB_ size_t count) : scope_block() 48 | { 49 | reset(block, count); 50 | } 51 | 52 | scope_block(scope_block const &) = delete; 53 | 54 | template 55 | scope_block(scope_block && rhs) : scope_block() 56 | { 57 | this->swap(rhs); 58 | } 59 | 60 | template 61 | scope_block & operator=(scope_block && rhs) 62 | { 63 | this->swap(rhs); 64 | return (*this); 65 | } 66 | 67 | ~scope_block(void) 68 | { 69 | if (trust_) AllocT::free(block_); 70 | } 71 | 72 | void reset(GLB_ size_t count) 73 | { 74 | this->~scope_block(); 75 | size_ = count * sizeof(T); 76 | block_ = static_cast( AllocT::alloc(this->size()) ); 77 | trust_ = true; 78 | } 79 | 80 | void reset(T * block, GLB_ size_t count) 81 | { 82 | this->~scope_block(); 83 | size_ = count * sizeof(T); 84 | block_ = block; 85 | trust_ = false; 86 | } 87 | 88 | void trust(void) { trust_ = true; } 89 | 90 | void swap(scope_block & rhs) 91 | { 92 | STD_ swap(this->block_, rhs.block_); 93 | STD_ swap(this->size_ , rhs.size_ ); 94 | STD_ swap(this->trust_, rhs.trust_); 95 | } 96 | 97 | template 98 | void swap(scope_block & rhs) 99 | { 100 | void * tmp_ptr = this->block_; 101 | this->block_ = reinterpret_cast(rhs.block_); 102 | rhs .block_ = reinterpret_cast(tmp_ptr); 103 | STD_ swap(this->size_ , rhs.size_ ); 104 | STD_ swap(this->trust_, rhs.trust_); 105 | } 106 | 107 | /* 108 | * You need to handle the datas from this scope_block object 109 | * by yourself before you calling this function. 110 | */ 111 | T * dismiss(void) 112 | { 113 | T * data_ret = this->data(); 114 | block_ = NULL; 115 | size_ = 0; 116 | trust_ = false; 117 | return data_ret; 118 | } 119 | 120 | T * data (void) const { return block_; } 121 | GLB_ size_t size (void) const { return size_ ; } 122 | GLB_ size_t count(void) const { return size_ / sizeof(T); } 123 | bool is_trusted(void) const { return trust_; } 124 | 125 | T & operator[](GLB_ size_t pos) { return block_[pos]; } 126 | T const & operator[](GLB_ size_t pos) const { return block_[pos]; } 127 | }; 128 | 129 | template 130 | void swap(R2Y_ scope_block & a, R2Y_ scope_block & b) 131 | { 132 | a.swap(b); 133 | } -------------------------------------------------------------------------------- /include/detail/undefine.hxx: -------------------------------------------------------------------------------- 1 | /* 2 | rgb2yuv - Code covered by the MIT License 3 | Author: mutouyun (http://orzz.org) 4 | */ 5 | 6 | //////////////////////////////////////////////////////////////// 7 | /// Pop previous definition of used macros 8 | //////////////////////////////////////////////////////////////// 9 | 10 | #pragma pop_macro("R2Y_FORCE_INLINE_") 11 | #pragma pop_macro("R2Y_UNUSED_") 12 | #pragma pop_macro("R2Y_ALLOC_") 13 | #pragma pop_macro("R2Y_") 14 | #pragma pop_macro("R2Y_NAMESPACE_") 15 | #pragma pop_macro("STD_") 16 | #pragma pop_macro("GLB_") 17 | -------------------------------------------------------------------------------- /include/detail/yuv_helper.hxx: -------------------------------------------------------------------------------- 1 | /* 2 | rgb2yuv - Code covered by the MIT License 3 | Author: mutouyun (http://orzz.org) 4 | */ 5 | 6 | namespace detail_helper_ { 7 | 8 | /* YUV Packed */ 9 | 10 | template struct packed_yuv_t; 11 | 12 | template <> struct packed_yuv_t { GLB_ uint8_t y0_, cr_, y1_, cb_; }; 13 | template <> struct packed_yuv_t { GLB_ uint8_t y0_, cb_, y1_, cr_; }; 14 | template <> struct packed_yuv_t { GLB_ uint8_t cr_, y0_, cb_, y1_; }; 15 | template <> struct packed_yuv_t { GLB_ uint8_t cb_, y0_, cr_, y1_; }; 16 | template <> struct packed_yuv_t { GLB_ uint8_t u0_, y0_, v0_, y1_; 17 | GLB_ uint8_t u1_, y2_, v1_, y3_; 18 | GLB_ uint8_t y4_, y5_, y6_, y7_; }; 19 | template <> struct packed_yuv_t { GLB_ uint8_t cb_, y0_, y1_, cr_, y2_, y3_; }; 20 | 21 | /* YUV Planar */ 22 | 23 | template struct planar_uv_t { GLB_ uint8_t * cb_, *cr_; }; 24 | 25 | template <> struct planar_uv_t { struct { GLB_ uint8_t cr_, cb_; } * uv_; }; 26 | template <> struct planar_uv_t { struct { GLB_ uint8_t cb_, cr_; } * uv_; }; 27 | template <> struct planar_uv_t { struct { GLB_ uint8_t cr_, cb_; } * uv_; }; 28 | template <> struct planar_uv_t { struct { GLB_ uint8_t cb_, cr_; } * uv_; }; 29 | 30 | template 31 | R2Y_FORCE_INLINE_ auto set_planar_uv(GLB_ uint8_t in_u, GLB_ uint8_t in_v, planar_uv_t & ot_uv) 32 | -> STD_ enable_if_t<(S == R2Y_ yuv_NV24 || S == R2Y_ yuv_NV42 || S == R2Y_ yuv_NV12 || S == R2Y_ yuv_NV21)> 33 | { 34 | ot_uv.uv_->cb_ = in_u; 35 | ot_uv.uv_->cr_ = in_v; 36 | } 37 | 38 | template 39 | R2Y_FORCE_INLINE_ auto set_planar_uv(GLB_ uint8_t in_u, GLB_ uint8_t in_v, planar_uv_t & ot_uv) 40 | -> STD_ enable_if_t 41 | { 42 | (*(ot_uv.cb_)) = in_u; 43 | (*(ot_uv.cr_)) = in_v; 44 | } 45 | 46 | template 47 | R2Y_FORCE_INLINE_ auto get_planar_uv(GLB_ uint8_t & ot_u, GLB_ uint8_t & ot_v, const planar_uv_t & in_uv) 48 | -> STD_ enable_if_t<(S == R2Y_ yuv_NV24 || S == R2Y_ yuv_NV42 || S == R2Y_ yuv_NV12 || S == R2Y_ yuv_NV21)> 49 | { 50 | ot_u = in_uv.uv_->cb_; 51 | ot_v = in_uv.uv_->cr_; 52 | } 53 | 54 | template 55 | R2Y_FORCE_INLINE_ auto get_planar_uv(GLB_ uint8_t & ot_u, GLB_ uint8_t & ot_v, const planar_uv_t & in_uv) 56 | -> STD_ enable_if_t 57 | { 58 | ot_u = (*(in_uv.cb_)); 59 | ot_v = (*(in_uv.cr_)); 60 | } 61 | 62 | template 63 | R2Y_FORCE_INLINE_ auto next_planar_uv(planar_uv_t & ot_uv) 64 | -> STD_ enable_if_t<(S == R2Y_ yuv_NV24 || S == R2Y_ yuv_NV42 || S == R2Y_ yuv_NV12 || S == R2Y_ yuv_NV21)> 65 | { 66 | ++(ot_uv.uv_); 67 | } 68 | 69 | template 70 | R2Y_FORCE_INLINE_ auto next_planar_uv(planar_uv_t & ot_uv) 71 | -> STD_ enable_if_t 72 | { 73 | ++(ot_uv.cb_); 74 | ++(ot_uv.cr_); 75 | } 76 | 77 | template 78 | R2Y_FORCE_INLINE_ auto split(R2Y_ byte_t * in_data, GLB_ size_t /*in_size*/) 79 | -> STD_ enable_if_t<(P == R2Y_ plane_Y), R2Y_ byte_t *> 80 | { 81 | return in_data; 82 | } 83 | 84 | template 85 | R2Y_FORCE_INLINE_ auto split(R2Y_ byte_t * in_data, GLB_ size_t in_size) 86 | -> STD_ enable_if_t<((P == R2Y_ plane_U) && (S == R2Y_ yuv_YU12 || S == R2Y_ yuv_411P || 87 | S == R2Y_ yuv_422P || S == R2Y_ yuv_YUV9)) || 88 | ((P == R2Y_ plane_V) && (S == R2Y_ yuv_YV12 || S == R2Y_ yuv_YVU9)), R2Y_ byte_t *> 89 | { 90 | return in_data + in_size; 91 | } 92 | 93 | template 94 | R2Y_FORCE_INLINE_ auto split(R2Y_ byte_t * in_data, GLB_ size_t in_size) 95 | -> STD_ enable_if_t<((P == R2Y_ plane_V) && (S == R2Y_ yuv_422P)), R2Y_ byte_t *> 96 | { 97 | return in_data + in_size + (in_size >> 1); 98 | } 99 | 100 | template 101 | R2Y_FORCE_INLINE_ auto split(R2Y_ byte_t * in_data, GLB_ size_t in_size) 102 | -> STD_ enable_if_t<((P == R2Y_ plane_V) && (S == R2Y_ yuv_YU12 || S == R2Y_ yuv_411P)) || 103 | ((P == R2Y_ plane_U) && (S == R2Y_ yuv_YV12)), R2Y_ byte_t *> 104 | { 105 | return in_data + in_size + (in_size >> 2); 106 | } 107 | 108 | template 109 | R2Y_FORCE_INLINE_ auto split(R2Y_ byte_t * in_data, GLB_ size_t in_size) 110 | -> STD_ enable_if_t<((P == R2Y_ plane_V) && (S == R2Y_ yuv_YUV9)) || 111 | ((P == R2Y_ plane_U) && (S == R2Y_ yuv_YVU9)), R2Y_ byte_t *> 112 | 113 | { 114 | return in_data + in_size + (in_size >> 4); 115 | } 116 | 117 | template 118 | R2Y_FORCE_INLINE_ auto fill(R2Y_ byte_t * in_data, GLB_ size_t in_size) 119 | -> STD_ enable_if_t<(S == R2Y_ yuv_YV12 || S == R2Y_ yuv_YU12 || 120 | S == R2Y_ yuv_411P || S == R2Y_ yuv_422P || 121 | S == R2Y_ yuv_YUV9 || S == R2Y_ yuv_YVU9), planar_uv_t> 122 | 123 | { 124 | return 125 | { 126 | split(in_data, in_size), 127 | split(in_data, in_size) 128 | }; 129 | } 130 | 131 | template 132 | R2Y_FORCE_INLINE_ auto fill(R2Y_ byte_t * in_data, GLB_ size_t in_size) 133 | -> STD_ enable_if_t<(S == R2Y_ yuv_NV24 || S == R2Y_ yuv_NV42 || 134 | S == R2Y_ yuv_NV12 || S == R2Y_ yuv_NV21), planar_uv_t> 135 | { 136 | return 137 | { 138 | reinterpret_cast>().uv_)>( 139 | split(in_data, in_size)) 140 | }; 141 | } 142 | 143 | template 144 | struct yuv_planar 145 | { 146 | template 147 | R2Y_FORCE_INLINE_ yuv_planar(Y & y, UV & uv, R2Y_ byte_t * in_data, GLB_ size_t in_w, GLB_ size_t in_h) 148 | { 149 | GLB_ size_t size = in_w * in_h; 150 | y = split(in_data, size); 151 | uv = fill(in_data, size); 152 | } 153 | }; 154 | 155 | } // namespace detail_helper_ 156 | -------------------------------------------------------------------------------- /include/rgb2yuv.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | rgb2yuv - Code covered by the MIT License 3 | Author: mutouyun (http://orzz.org) 4 | */ 5 | 6 | #ifndef RGB2YUV_HPP__ 7 | #define RGB2YUV_HPP__ 8 | 9 | #include // size_t, ... 10 | #include // uint8_t, ... 11 | #include // assert 12 | #include // placement new, std::nothrow 13 | #include // std::swap, std::forward, std::move 14 | #include // std::enable_if 15 | 16 | #include "detail/predefine.hxx" 17 | 18 | namespace R2Y_NAMESPACE_ { 19 | 20 | #include "detail/basic_concept.hxx" 21 | #include "detail/scope_block.hxx" 22 | #include "detail/buffer_creator.hxx" 23 | #include "detail/yuv_helper.hxx" 24 | #include "detail/pixel_iterator.hxx" 25 | #include "detail/pixel_walker.hxx" 26 | #include "detail/pixel_convertor.hxx" 27 | 28 | //////////////////////////////////////////////////////////////// 29 | /// Transforming between RGB & YUV/YCbCr blocks 30 | //////////////////////////////////////////////////////////////// 31 | 32 | template 33 | struct do_convert_t 34 | { 35 | enum 36 | { 37 | iterator_size = R2Y_ iterator::iterator_size, 38 | is_block = R2Y_ iterator::is_block 39 | }; 40 | 41 | do_convert_t(R2Y_ scope_block & ot_data, GLB_ size_t in_w, GLB_ size_t in_h) 42 | : iter_(ot_data.data(), in_w, in_h) 43 | {} 44 | 45 | template struct convert_pixel_t; 46 | template struct convert_pixel_t { typedef R2Y_ yuv_t type; }; 47 | template struct convert_pixel_t { typedef R2Y_ rgb_t type; }; 48 | 49 | template 50 | void operator()(T const & pix) 51 | { 52 | iter_.set_and_next(pixel_convert(pix)); 53 | } 54 | 55 | template 56 | void operator()(T const (& pix)[N]) 57 | { 58 | typename convert_pixel_t::type c_pix[N]; 59 | for (GLB_ size_t i = 0; i < N; ++i) 60 | { 61 | c_pix[i] = pixel_convert(pix[i]); 62 | } 63 | iter_.set_and_next(c_pix); 64 | } 65 | 66 | private: 67 | R2Y_ iterator iter_; 68 | }; 69 | 70 | template 71 | STD_ enable_if_t<(In != Ot), R2Y_ scope_block> 72 | transform(R2Y_ byte_t * in_data, GLB_ size_t in_w, GLB_ size_t in_h) 73 | { 74 | assert(in_data != NULL); 75 | assert(in_w > 0 && in_h > 0); 76 | 77 | R2Y_ scope_block ot_data{ create_buffer(in_w, in_h) }; 78 | R2Y_ pixel_foreach(in_data, in_w, in_h, R2Y_ do_convert_t{ ot_data, in_w, in_h }); 79 | return ot_data; 80 | } 81 | 82 | } // namespace R2Y_NAMESPACE_ 83 | 84 | #include "detail/undefine.hxx" 85 | 86 | #endif // RGB2YUV_HPP__ 87 | -------------------------------------------------------------------------------- /test/detect_plat.hpp: -------------------------------------------------------------------------------- 1 | #ifndef DETECT_PLAT_HPP 2 | #define DETECT_PLAT_HPP 3 | 4 | #if defined(WINCE) || defined(_WIN32_WCE) 5 | # define SIMPLE_WINCE__ 6 | #elif defined(WIN64) || defined(_WIN64) || defined(__WIN64__) 7 | # define SIMPLE_WIN64__ 8 | #elif defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || defined(__NT__) 9 | # define SIMPLE_WIN32__ 10 | #elif defined(__linux__) || defined(__linux) 11 | # define SIMPLE_LINUX__ 12 | #else 13 | # error "This OS is unsupported." 14 | #endif 15 | 16 | #if defined(SIMPLE_WIN32__) || defined(SIMPLE_WIN64__) || defined(SIMPLE_WINCE__) 17 | # define SIMPLE_WINDOWS__ 18 | #endif 19 | 20 | #if defined(SIMPLE_WINDOWS__) 21 | 22 | # ifndef _WIN32_WINNT 23 | # define _WIN32_WINNT 0x0501 24 | # endif 25 | # ifndef WINVER 26 | # define WINVER _WIN32_WINNT 27 | # endif 28 | # ifndef _WIN32_WINDOWS 29 | # define _WIN32_WINDOWS 0x0410 30 | # endif 31 | # ifndef _WIN32_IE 32 | # define _WIN32_IE 0x0600 33 | # endif 34 | 35 | #endif 36 | 37 | #endif // DETECT_PLAT_HPP 38 | -------------------------------------------------------------------------------- /test/stopwatch.hpp: -------------------------------------------------------------------------------- 1 | #ifndef STOPWATCH_HPP 2 | #define STOPWATCH_HPP 3 | 4 | #include "detect_plat.hpp" 5 | 6 | #if defined(SIMPLE_WINDOWS__) 7 | #include 8 | #elif defined(SIMPLE_LINUX__) 9 | #include 10 | #endif 11 | 12 | namespace simple { 13 | 14 | //////////////////////////////////////////////////////////////// 15 | 16 | inline unsigned long tickcount(void) 17 | { 18 | #if defined(SIMPLE_WINDOWS__) 19 | return static_cast(::GetTickCount()); 20 | #elif defined(SIMPLE_LINUX__) 21 | /* need -lrt */ 22 | struct timespec tv; 23 | clock_gettime(CLOCK_MONOTONIC, &tv); 24 | return (tv.tv_sec * 1000) + (tv.tv_nsec / 1000000); 25 | #else 26 | return 0; 27 | #endif 28 | } 29 | 30 | namespace use 31 | { 32 | struct clock_default // Default clock policy 33 | { 34 | typedef unsigned long clock_t; 35 | clock_t clock(void) { return simple::tickcount(); } 36 | static double second(clock_t cl) { return double(cl) / double(1000); } 37 | }; 38 | } 39 | 40 | template 41 | class stopwatch : public ModelT 42 | { 43 | public: 44 | typedef typename ModelT::clock_t clock_t; 45 | 46 | protected: 47 | clock_t start_time_; 48 | clock_t pause_elap_; 49 | bool is_stopped_; 50 | 51 | public: 52 | stopwatch(bool start_watch = false) 53 | : ModelT() 54 | , start_time_(0) 55 | , pause_elap_(0) 56 | , is_stopped_(true) 57 | { 58 | if (start_watch) start(); 59 | } 60 | 61 | public: 62 | bool check(void) 63 | { 64 | return (start_time_ <= ModelT::clock()); 65 | } 66 | 67 | double value(void) 68 | { 69 | return ModelT::second(elapsed()); 70 | } 71 | 72 | clock_t elapsed(void) 73 | { 74 | if (is_stopped()) return 0; 75 | else 76 | if (is_paused()) return pause_elap_; 77 | else 78 | { 79 | clock_t now = ModelT::clock(); 80 | if (start_time_ > now) 81 | { 82 | stop(); 83 | return 0; 84 | } 85 | return now - start_time_; 86 | } 87 | } 88 | 89 | void start(void) 90 | { 91 | elapsed(); // if (start_time_ > now), stopwatch will restart 92 | start_time_ = ModelT::clock(); 93 | start_time_ -= pause_elap_; 94 | pause_elap_ = 0; 95 | is_stopped_ = false; 96 | } 97 | 98 | void pause(void) 99 | { 100 | pause_elap_ = elapsed(); 101 | } 102 | 103 | void stop(void) 104 | { 105 | start_time_ = 0; 106 | pause_elap_ = 0; 107 | is_stopped_ = true; 108 | } 109 | 110 | bool is_stopped(void) 111 | { 112 | return is_stopped_; 113 | } 114 | 115 | bool is_paused(void) 116 | { 117 | return (pause_elap_ != 0); 118 | } 119 | }; 120 | 121 | //////////////////////////////////////////////////////////////// 122 | 123 | } // namespace simple 124 | 125 | #endif // STOPWATCH_HPP 126 | -------------------------------------------------------------------------------- /test/test.cpp: -------------------------------------------------------------------------------- 1 | // test.cpp : Defines the entry point for the console application. 2 | // 3 | 4 | #include 5 | #include 6 | 7 | #include "../include/rgb2yuv.hpp" 8 | 9 | #include "stopwatch.hpp" 10 | 11 | int main(int /*argc*/, char* /*argv*/[]) 12 | { 13 | using namespace r2y; 14 | 15 | uint32_t xx = 2179683; // 00000000 00100001 01000010 01100011 (33, 66, 99) 16 | rgb_t yy; 17 | memcpy(&yy, &xx, sizeof(yy)); 18 | //yy.r_ = 76; yy.g_ = 255; yy.b_ = 29; 19 | printf("%03d %03d %03d\n", yy.r_, yy.g_, yy.b_); 20 | 21 | yuv_t zz; 22 | zz.y_ = pixel_convert(yy); 23 | zz.u_ = pixel_convert(yy); 24 | zz.v_ = pixel_convert(yy); 25 | printf("%03d %03d %03d\n", zz.y_, zz.u_, zz.v_); 26 | 27 | //zz.y_ = 255; zz.u_ = zz.v_ = 0; 28 | yy.r_ = pixel_convert(zz); 29 | yy.g_ = pixel_convert(zz); 30 | yy.b_ = pixel_convert(zz); 31 | printf("%03d %03d %03d\n", yy.r_, yy.g_, yy.b_); 32 | 33 | uint32_t data[] = 34 | { 35 | 6504993, 2179683, 2179683, 2179683, 36 | 2179683, 8421504, 2179683, 2179683, 37 | 2179683, 2179683, 2179683, 2179683, 38 | 2179683, 2179683, 2179683, 8421504 39 | }; 40 | scope_block yuv; 41 | 42 | printf("RGB-888X: "); 43 | uint8_t* rgb = (uint8_t*)data; 44 | for (size_t i = 0; i < sizeof(data); ++i) 45 | printf("%02X ", rgb[i]); 46 | printf("\n"); 47 | 48 | #define TEST_(TO) \ 49 | yuv = transform((uint8_t*)data, 4, 4); \ 50 | printf("-> %s: ", #TO); \ 51 | for (size_t i = 0; i < yuv.count(); ++i) printf("%02X ", yuv[i]); \ 52 | printf("\n") 53 | 54 | TEST_(YV12); 55 | { 56 | auto rgb = transform(yuv.data(), 4, 4); 57 | printf("## YV12 -> 888: "); 58 | for (size_t i = 0; i < rgb.count(); ++i) printf("%02X ", rgb[i]); 59 | printf("\n"); 60 | } 61 | TEST_(YU12); 62 | TEST_(NV12); 63 | { 64 | auto rgb = transform(yuv.data(), 4, 4); 65 | printf("## NV12 -> 888: "); 66 | for (size_t i = 0; i < rgb.count(); ++i) printf("%02X ", rgb[i]); 67 | printf("\n"); 68 | } 69 | TEST_(NV21); 70 | TEST_(YUY2); 71 | { 72 | auto rgb = transform(yuv.data(), 4, 4); 73 | printf("## YUY2 -> 888: "); 74 | for (size_t i = 0; i < rgb.count(); ++i) printf("%02X ", rgb[i]); 75 | printf("\n"); 76 | } 77 | TEST_(VYUY); 78 | TEST_(Y41P); 79 | { 80 | auto rgb = transform(yuv.data(), 4, 4); 81 | printf("## Y41P -> 888: "); 82 | for (size_t i = 0; i < rgb.count(); ++i) printf("%02X ", rgb[i]); 83 | printf("\n"); 84 | } 85 | TEST_(Y411); 86 | { 87 | auto rgb = transform(yuv.data(), 4, 4); 88 | printf("## Y411 -> 888: "); 89 | for (size_t i = 0; i < rgb.count(); ++i) printf("%02X ", rgb[i]); 90 | printf("\n"); 91 | } 92 | TEST_(411P); 93 | TEST_(422P); 94 | TEST_(NV24); 95 | { 96 | auto rgb = transform(yuv.data(), 4, 4); 97 | printf("## NV24 -> 888: "); 98 | for (size_t i = 0; i < rgb.count(); ++i) printf("%02X ", rgb[i]); 99 | printf("\n"); 100 | } 101 | TEST_(NV42); 102 | TEST_(YUV9); 103 | TEST_(YVU9); 104 | 105 | simple::stopwatch<> sw(false); 106 | printf("\n"); 107 | #define TEST_SPEED_(TO, ...) \ 108 | sw.start(); \ 109 | for (int i = 0; i < 2000000; ++i) \ 110 | { \ 111 | yuv = transform##__VA_ARGS__((uint8_t*)data, 4, 4); \ 112 | } \ 113 | printf("%s: %ld ms. %s\n", #TO, static_cast(sw.value() * 1000), ""#__VA_ARGS__) 114 | 115 | TEST_SPEED_(YUV9); 116 | TEST_SPEED_(NV12); 117 | TEST_SPEED_(NV24); 118 | TEST_SPEED_(YUY2); 119 | TEST_SPEED_(411P); 120 | TEST_SPEED_(Y41P); 121 | 122 | return 0; 123 | } 124 | -------------------------------------------------------------------------------- /test/test.vcxproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | 14 | {734F949E-443C-454C-8217-AD4D6BB88C48} 15 | Win32Proj 16 | test 17 | 10.0.17134.0 18 | 19 | 20 | 21 | Application 22 | true 23 | v141 24 | Unicode 25 | 26 | 27 | Application 28 | false 29 | v141 30 | true 31 | Unicode 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | true 47 | $(SolutionDir)bin\$(Configuration)\ 48 | $(SolutionDir)tmp\$(Configuration)\$(ProjectName)\ 49 | 50 | 51 | false 52 | $(SolutionDir)bin\$(Configuration)\ 53 | $(SolutionDir)tmp\$(Configuration)\$(ProjectName)\ 54 | 55 | 56 | 57 | NotUsing 58 | Level3 59 | Disabled 60 | WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) 61 | true 62 | 63 | 64 | Console 65 | true 66 | 67 | 68 | 69 | 70 | Level3 71 | NotUsing 72 | MaxSpeed 73 | true 74 | true 75 | WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 76 | true 77 | 78 | 79 | Console 80 | true 81 | true 82 | true 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | -------------------------------------------------------------------------------- /test/test.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hh;hpp;hxx;hm;inl;inc;xsd 11 | 12 | 13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} 14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms 15 | 16 | 17 | {985a4af9-c8e9-40c4-b1ea-d3a4656ae1a8} 18 | 19 | 20 | 21 | 22 | Header Files 23 | 24 | 25 | Header Files\detail 26 | 27 | 28 | Header Files\detail 29 | 30 | 31 | Header Files\detail 32 | 33 | 34 | Header Files\detail 35 | 36 | 37 | Header Files\detail 38 | 39 | 40 | Header Files\detail 41 | 42 | 43 | Header Files\detail 44 | 45 | 46 | Header Files\detail 47 | 48 | 49 | Header Files\detail 50 | 51 | 52 | 53 | 54 | Source Files 55 | 56 | 57 | -------------------------------------------------------------------------------- /test/test.vcxproj.user: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | --------------------------------------------------------------------------------