diff --git a/.gitignore b/.gitignore index a0ebbd68..d06a2a8f 100644 --- a/.gitignore +++ b/.gitignore @@ -114,5 +114,7 @@ ui_*.h /ext/ffmpeg/libavutil/libavutil.a /ext/ffmpeg/libswresample/libswresample.a /ext/ffmpeg/libswscale/libswscale.a +/liboavideo/test_oaconvert +/liboavideo/test_oaconvert.txt /oacapture/oacapture /oalive/oalive diff --git a/include/openastro/video.h b/include/openastro/video.h index 73e39813..e6314743 100644 --- a/include/openastro/video.h +++ b/include/openastro/video.h @@ -27,6 +27,7 @@ #ifndef OPENASTRO_VIDEO_H #define OPENASTRO_VIDEO_H -extern int oaconvert ( void*, void*, int, int, int, int ); +extern int oaconvert ( const void*, void*, int, int, int, int ); +extern int oaconvert_greyscale ( const void*, void*, int, int, int, int ); #endif /* OPENASTRO_VIDEO_H */ diff --git a/liboavideo/Makefile.am b/liboavideo/Makefile.am index b81c812d..04dee9e4 100644 --- a/liboavideo/Makefile.am +++ b/liboavideo/Makefile.am @@ -27,7 +27,7 @@ AM_CPPFLAGS = -I$(top_srcdir)/include lib_LTLIBRARIES = liboavideo.la liboavideo_la_SOURCES = \ - oavideo.c yuv.c fits.c + oavideo.c yuv.c grey.c fits.c WARNINGS = -g -O -Wall -Werror -Wpointer-arith -Wuninitialized -Wsign-compare -Wformat-security -Wno-pointer-sign $(OSX_WARNINGS) @@ -38,3 +38,11 @@ warnings: verbose-warnings: $(MAKE) V=1 CFLAGS='$(WARNINGS)' CXXFLAGS='$(WARNINGS)' $(MAKE) V=1 CFLAGS='$(WARNINGS)' CXXFLAGS='$(WARNINGS)' $(check_PROGRAMS) + +test: + @gcc --std=c99 -g3 -O0 -I./ -I../include test_oaconvert.c yuv.c grey.c oavideo.c -o test_oaconvert + @./test_oaconvert 2>&1 | tee test_oaconvert.txt + @if grep -q "at line" test_oaconvert.txt; then \ + echo;\ + head -n `grep at\ line test_oaconvert.txt | sed -e 's/.* at line \(.*\) .*/\1/g'` test_oaconvert.c | tail -n 1; \ + fi diff --git a/liboavideo/grey.c b/liboavideo/grey.c new file mode 100644 index 00000000..f1309e8f --- /dev/null +++ b/liboavideo/grey.c @@ -0,0 +1,320 @@ +/***************************************************************************** + * + * grey.c -- convert any format to GREYxx + * + * Copyright 2014 James Fidell (james@openastroproject.org) + * + * License: + * + * This file is part of the Open Astro Project. + * + * The Open Astro Project is free software: you can redistribute it and/or + * modify it under the terms of the GNU General Public License as published + * by the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The Open Astro Project is distributed in the hope that it will be + * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with the Open Astro Project. If not, see + * . + * + *****************************************************************************/ + +#include +#include + +#include "grey.h" + +void +oaGreyscale_8to16LE( const uint8_t* source, uint8_t* target, int len ) +{ + int i; + uint8_t* t = target + (len-1)*2; + const uint8_t* s = source + (len-1); + + for ( i = len; i > 0; i--, s-=1, t-=2 ) { + *(t+1) = *s; + *t = 0x00; + } +} + +void +oaGreyscale_8to16BE( const uint8_t* source, uint8_t* target, int len ) +{ + int i; + uint8_t v; + uint8_t* t = target + (len-1)*2; + const uint8_t* s = source + (len-1); + + for ( i = len; i > 0; i--, s-=1, t-=2 ) { + *t = *s; + *(t+1) = 0x00; + } +} + +/* FIXME awaiting OA_PIX_FMT_XXXX10X +void +oaGreyscale_10to8( const uint8_t* s, uint8_t* t, int len, bool packed ) +{ + int i; + uint16_t p; + + if ( packed ) { + for ( i = 0; i < len; i += 5, s += 5 ) { + *t++ = *s; + *t++ = *(s+1); + *t++ = *(s+2); + *t++ = *(s+3); + // ignore 5th byte + } + } + else { + for ( i = 0; i < len; i += 2, s+=2 ) { + p = (*s << 6) + ((*(s+1)&0x03) << 14); + *t++ = (p & 0xff00) >> 8; + } + } +} + +void +oaGreyscale_10to16( const uint8_t* source, uint8_t* target, int len, bool packed, bool little_endian ) +{ + int i; + const uint8_t* s; + uint8_t* t; + uint16_t p1, p2, p3, p4; + + const int numPixels = len / ( packed ? 1.25 : 2 ); + + if ( packed ) { + t = target + (numPixels-4) * 2; + s = source + (numPixels-4) * 5/4; + + for ( i=0; i < len; i += 5, s -= 5, t -= 8) + { + uint8_t lsb = *(s+4); + + uint16_t p1 = (*(s) << 8) + ((lsb&0x03) << 6); + uint16_t p2 = (*(s+1) << 8) + ((lsb&0x0c) << 4); + uint16_t p3 = (*(s+2) << 8) + ((lsb&0x30) << 2); + uint16_t p4 = (*(s+3) << 8) + (lsb&0xc0); + + if (little_endian) { + *t = p1 & 0x00ff; + *(t+1) = (p1 & 0xff00) >> 8; + *(t+2) = p2 & 0x00ff; + *(t+3) = (p2 & 0xff00) >> 8; + *(t+4) = p3 & 0x00ff; + *(t+5) = (p3 & 0xff00) >> 8; + *(t+6) = p4 & 0x00ff; + *(t+7) = (p4 & 0xff00) >> 8; + } + else { + *t = (p1 & 0xff00) >> 8; + *(t+1) = p1 & 0x00ff; + *(t+2) = (p2 & 0xff00) >> 8; + *(t+3) = p2 & 0x00ff; + *(t+4) = (p3 & 0xff00) >> 8; + *(t+5) = p3 & 0x00ff; + *(t+6) = (p4 & 0xff00) >> 8; + *(t+7) = p4 & 0x00ff; + } + } + } + else { + t = target + (numPixels-1)*2; + s = source + (numPixels-1)*2; + + for ( i=0; i < len; i += 2, s-=2, t-=2) + { + p1 = (*s << 6) + ((*(s+1)&0x03) << 14); + if (little_endian) { + *t = p1 & 0x00ff; + *(t+1) = (p1 & 0xff00) >> 8; + } + else { + *t = (p1 & 0xff00) >> 8; + *(t+1) = p1 & 0x00ff; + } + } + } +} + +void +oaGreyscale_10to16LE( const uint8_t* s, uint8_t* t, int len, bool packed ) +{ + oaGreyscale_10to16( s, t, len, packed, true ); +} + +void +oaGreyscale_10to16BE( const uint8_t* s, uint8_t* t, int len, bool packed ) +{ + oaGreyscale_10to16( s, t, len, packed, false ); +} +*/ + +void +oaGreyscale_16LEto8( const uint8_t* s, uint8_t* t, int len ) +{ + int i; + for ( i = 0; i < len; i+=2, s+=2, t++ ) { + *t = *(s+1); + } +} + +void +oaGreyscale_16BEto8( const uint8_t* s, uint8_t* t, int len ) +{ + int i; + for ( i = 0; i < len; i+=2, s+=2, t++ ) { + *t = *s; + } +} + +void +oaGreyscale_16swap( const uint8_t* s, uint8_t* t, int len ) +{ + int i; + for ( i = 0; i < len; i+=2, s+=2, t+=2 ) { + uint8_t v = *s; + *t = *(s+1); + *(t+1) = v; + } +} + +void +oaGreyscale_RGB24to8( const uint8_t* s, uint8_t* t, int len, bool swapRB ) +{ + int i; + uint8_t R, G, B; + for ( i = 0; i < len; i += 3, s += 3, t += 1 ) { + R = swapRB ? *(s+2) : *s; G = *(s+1); B = swapRB ? *s : *(s+2); + *t = .2126 * R + .7152 * G + .0722 * B; + } +} + +void +oaGreyscale_RGB24to16LE( const uint8_t* s, uint8_t* t, int len, bool swapRB ) +{ + int i; + uint16_t R, G, B; + uint16_t Y; + for ( i = 0; i < len; i += 3, s += 3, t += 2 ) { + R = swapRB ? *(s+2) : *s; G = *(s+1); B = swapRB ? *s : *(s+2); + Y = .2126 * (R<<8) + .7152 * (G<<8) + .0722 * (B<<8); + *t = Y & 0x00ff; + *(t+1) = (Y & 0xff00) >> 8; + } +} + +void +oaGreyscale_RGB24to16BE( const uint8_t* s, uint8_t* t, int len, bool swapRB ) +{ + int i; + uint16_t R, G, B; + uint16_t Y; + for ( i = 0; i < len; i += 3, s += 3, t += 2 ) { + R = swapRB ? *(s+2) : *s; G = *(s+1); B = swapRB ? *s : *(s+2); + Y = .2126 * (R<<8) + .7152 * (G<<8) + .0722 * (B<<8); + *t = (Y & 0xff00) >> 8; + *(t+1) = Y & 0x00ff; + } +} + +void +oaGreyscale_RGB48LEto8( const uint8_t* s, uint8_t* t, int len, bool swapRB ) +{ + int i; + uint16_t R, G, B; + uint16_t Y; + for ( i = 0; i < len; i += 6, s += 6, t += 1 ) { + R = swapRB ? ((*(s+5)<<8) + *(s+4)) : (((*(s+1))<<8) + *s); + G = (*(s+3)<<8) + *(s+2); + B = swapRB ? ((*(s+1)<<8) + *s) : ((*(s+5)<<8) + *(s+4)); + Y = .2126 * R + .7152 * G + .0722 * B; + *t = (Y & 0xff00) >> 8; + } +} + +void +oaGreyscale_RGB48LEto16LE( const uint8_t* s, uint8_t* t, int len, bool swapRB ) +{ + int i; + uint16_t R, G, B; + uint16_t Y; + for ( i = 0; i < len; i += 6, s += 6, t += 2 ) { + R = swapRB ? ((*(s+5)<<8) + *(s+4)) : ((*(s+1)<<8) + *s); + G = (*(s+3)<<8) + *(s+2); + B = swapRB ? ((*(s+1)<<8) + *s) : ((*(s+5)<<8) + *(s+4)); + Y = .2126 * R + .7152 * G + .0722 * B; + *t = Y & 0x00ff; + *(t+1) = (Y & 0xff00) >> 8; + } +} + +void +oaGreyscale_RGB48LEto16BE( const uint8_t* s, uint8_t* t, int len, bool swapRB ) +{ + int i; + uint16_t R, G, B; + uint16_t Y; + for ( i = 0; i < len; i += 6, s += 6, t += 2 ) { + R = swapRB ? ((*(s+5)<<8) + *(s+4)) : ((*(s+1)<<8) + *s); + G = (*(s+3)<<8) + *(s+2); + B = swapRB ? ((*(s+1)<<8) + *s) : ((*(s+5)<<8) + *(s+4)); + Y = .2126 * R + .7152 * G + .0722 * B; + *t = (Y & 0xff00) >> 8; + *(t+1) = Y & 0x00ff; + } +} + +void +oaGreyscale_RGB48BEto8( const uint8_t* s, uint8_t* t, int len, bool swapRB ) +{ + int i; + uint16_t R, G, B; + uint16_t Y; + for ( i = 0; i < len; i += 6, s += 6, t += 1 ) { + R = swapRB ? ((*(s+4)<<8) + *(s+5)) : ((*s<<8) + *(s+1)); + G = (*(s+2)<<8) + *(s+3); + B = swapRB ? ((*s<<8) + *(s+1)) : ((*(s+4)<<8) + *(s+5)); + Y = .2126 * R + .7152 * G + .0722 * B; + *t = (Y & 0xff00) >> 8; + } +} + +void +oaGreyscale_RGB48BEto16LE( const uint8_t* s, uint8_t* t, int len, bool swapRB ) +{ + int i; + uint16_t R, G, B; + uint16_t Y; + for ( i = 0; i < len; i += 6, s += 6, t += 2 ) { + R = swapRB ? ((*(s+4)<<8) + *(s+5)) : ((*s<<8) + *(s+1)); + G = (*(s+2)<<8) + *(s+3); + B = swapRB ? ((*s<<8) + *(s+1)) : ((*(s+4)<<8) + *(s+5)); + Y = .2126 * R + .7152 * G + .0722 * B; + *t = Y & 0x00ff; + *(t+1) = (Y & 0xff00) >> 8; + } +} + +void +oaGreyscale_RGB48BEto16BE( const uint8_t* s, uint8_t* t, int len, bool swapRB ) +{ + int i; + uint16_t R, G, B; + uint16_t Y; + for ( i = 0; i < len; i += 6, s += 6, t += 2 ) { + R = swapRB ? ((*(s+4)<<8) + *(s+5)) : ((*s<<8) + *(s+1)); + G = (*(s+2)<<8) + *(s+3); + B = swapRB ? ((*s<<8) + *(s+1)) : ((*(s+4)<<8) + *(s+5)); + Y = .2126 * R + .7152 * G + .0722 * B; + *t = (Y & 0xff00) >> 8; + *(t+1) = Y & 0x00ff; + } +} diff --git a/liboavideo/grey.h b/liboavideo/grey.h new file mode 100644 index 00000000..f9542060 --- /dev/null +++ b/liboavideo/grey.h @@ -0,0 +1,58 @@ +/***************************************************************************** + * + * grey.h -- convert any format to GREYxx header + * + * Copyright 2017 ... + * + * License: + * + * This file is part of the Open Astro Project. + * + * The Open Astro Project is free software: you can redistribute it and/or + * modify it under the terms of the GNU General Public License as published + * by the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The Open Astro Project is distributed in the hope that it will be + * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with the Open Astro Project. If not, see + * . + * + *****************************************************************************/ + +#ifndef OPENASTRO_VIDEO_GREY_H +#define OPENASTRO_VIDEO_GREY_H + +#include +typedef enum { false, true } bool; + +extern void oaGreyscale_8to16LE( const uint8_t* s, uint8_t* t, int len ); +extern void oaGreyscale_8to16BE( const uint8_t* s, uint8_t* t, int len ); + +/* FIXME awaiting OA_PIX_FMT_XXXX10X +extern void oaGreyscale_10to8( const uint8_t* s, uint8_t* t, int len, bool packed ); +extern void oaGreyscale_10to16LE( const uint8_t* s, uint8_t* t, int len, bool packed ); +extern void oaGreyscale_10to16BE( const uint8_t* s, uint8_t* t, int len, bool packed ); +*/ + +extern void oaGreyscale_16LEto8( const uint8_t* s, uint8_t* t, int len ); +extern void oaGreyscale_16BEto8( const uint8_t* s, uint8_t* t, int len ); +extern void oaGreyscale_16swap( const uint8_t* s, uint8_t* t, int len ); + +extern void oaGreyscale_RGB24to8( const uint8_t* s, uint8_t* t, int len, bool swapRB ); +extern void oaGreyscale_RGB24to16LE( const uint8_t* s, uint8_t* t, int len, bool swapRB ); +extern void oaGreyscale_RGB24to16BE( const uint8_t* s, uint8_t* t, int len, bool swapRB ); + +extern void oaGreyscale_RGB48LEto8( const uint8_t* s, uint8_t* t, int len, bool swapRB ); +extern void oaGreyscale_RGB48LEto16LE( const uint8_t* s, uint8_t* t, int len, bool swapRB ); +extern void oaGreyscale_RGB48LEto16BE( const uint8_t* s, uint8_t* t, int len, bool swapRB ); + +extern void oaGreyscale_RGB48BEto8( const uint8_t* s, uint8_t* t, int len, bool swapRB ); +extern void oaGreyscale_RGB48BEto16LE( const uint8_t* s, uint8_t* t, int len, bool swapRB ); +extern void oaGreyscale_RGB48BEto16BE( const uint8_t* s, uint8_t* t, int len, bool swapRB ); + +#endif /* OPENASTRO_VIDEO_GREY_H */ diff --git a/liboavideo/oavideo.c b/liboavideo/oavideo.c index 1cd2f1e0..b37362fb 100644 --- a/liboavideo/oavideo.c +++ b/liboavideo/oavideo.c @@ -28,13 +28,20 @@ #include #include -#include "yuv.h" +#include +#include "yuv.h" +#include "grey.h" int -oaconvert ( void* source, void* target, int xSize, int ySize, int sourceFormat, +oaconvert ( const void* source, void* target, int xSize, int ySize, int sourceFormat, int targetFormat ) { + if ( OA_ISGREYSCALE( targetFormat ) ) { + oaconvert_greyscale( source, target, xSize, ySize, + sourceFormat, targetFormat ); + } + if ( targetFormat != OA_PIX_FMT_RGB24 ) { // FIX ME -- set errno return -1; @@ -66,3 +73,202 @@ oaconvert ( void* source, void* target, int xSize, int ySize, int sourceFormat, return 0; } + + + +int +oaconvert_greyscale ( const void* source, void* target, int xSize, int ySize, int sourceFormat, + int targetFormat ) +{ + int length; + bool swapRB; + + if ( !OA_ISGREYSCALE( targetFormat ) ) { + // FIX ME -- set errno + return -1; + } + + if ( !source || !target ) + { + // FIX ME -- set errno + return -1; + } + + switch ( sourceFormat ) { + case OA_PIX_FMT_GREY8: + case OA_PIX_FMT_BGGR8: + case OA_PIX_FMT_RGGB8: + case OA_PIX_FMT_GBRG8: + case OA_PIX_FMT_GRBG8: + length = xSize * ySize; + switch ( targetFormat ) { + case OA_PIX_FMT_GREY8: + if ( target != source ) memcpy( target, source, length ); + break; + case OA_PIX_FMT_GREY16LE: + oaGreyscale_8to16LE( source, target, length ); + break; + case OA_PIX_FMT_GREY16BE: + oaGreyscale_8to16BE( source, target, length ); + break; + default: + return -1; // FIX ME -- set errno + } + break; + +/* FIXME awaiting OA_PIX_FMTXXXX10X + //case OA_PIX_FMT_BGGR10P: + //case OA_PIX_FMT_RGGB10P: + //case OA_PIX_FMT_GBRG10P: + case OA_PIX_FMT_GRBG10P: + length = xSize * ySize * 1.25; + switch ( targetFormat ) { + case OA_PIX_FMT_GREY8: + oaGreyscale_10to8( source, target, length, true ); + break; + case OA_PIX_FMT_GREY16LE: + oaGreyscale_10to16LE( source, target, length, true ); + break; + case OA_PIX_FMT_GREY16BE: + oaGreyscale_10to16BE( source, target, length, true ); + break; + default: + return -1; // FIX ME -- set errno + } + break; + + //case OA_PIX_FMT_BGGR10: + //case OA_PIX_FMT_RGGB10: + //case OA_PIX_FMT_GBRG10: + case OA_PIX_FMT_GRBG10: + length = xSize * ySize * 2; + switch ( targetFormat ) { + case OA_PIX_FMT_GREY8: + oaGreyscale_10to8( source, target, length, false ); + break; + case OA_PIX_FMT_GREY16LE: + oaGreyscale_10to16LE( source, target, length, false ); + break; + case OA_PIX_FMT_GREY16BE: + oaGreyscale_10to16BE( source, target, length, false ); + break; + default: + return -1; // FIX ME -- set errno + } + break; +*/ + case OA_PIX_FMT_GREY16LE: + case OA_PIX_FMT_BGGR16LE: + case OA_PIX_FMT_RGGB16LE: + case OA_PIX_FMT_GBRG16LE: + case OA_PIX_FMT_GRBG16LE: + length = xSize * ySize * 2; + switch ( targetFormat ) { + case OA_PIX_FMT_GREY8: + oaGreyscale_16LEto8( source, target, length ); + break; + case OA_PIX_FMT_GREY16LE: + if ( target != source) memcpy( target, source, length ); + break; + case OA_PIX_FMT_GREY16BE: + oaGreyscale_16swap( source, target, length ); + break; + default: + return -1; // FIX ME -- set errno + } + break; + + case OA_PIX_FMT_GREY16BE: + case OA_PIX_FMT_BGGR16BE: + case OA_PIX_FMT_RGGB16BE: + case OA_PIX_FMT_GBRG16BE: + case OA_PIX_FMT_GRBG16BE: + length = xSize * ySize * 2; + switch ( targetFormat ) { + case OA_PIX_FMT_GREY8: + oaGreyscale_16BEto8( source, target, length ); + break; + case OA_PIX_FMT_GREY16LE: + oaGreyscale_16swap( source, target, length ); + break; + case OA_PIX_FMT_GREY16BE: + if ( target != source ) memcpy( target, source, length ); + break; + default: + return -1; // FIX ME -- set errno + } + break; + + case OA_PIX_FMT_RGB24: + case OA_PIX_FMT_BGR24: + length = xSize * ySize * 3; + swapRB = sourceFormat == OA_PIX_FMT_BGR24; + switch ( targetFormat ) { + case OA_PIX_FMT_GREY8: + oaGreyscale_RGB24to8( source, target, length, swapRB ); + break; + case OA_PIX_FMT_GREY16LE: + oaGreyscale_RGB24to16LE( source, target, length, swapRB ); + break; + case OA_PIX_FMT_GREY16BE: + oaGreyscale_RGB24to16BE( source, target, length, swapRB ); + break; + default: + return -1; // FIX ME -- set errno + } + break; + + case OA_PIX_FMT_RGB48LE: + case OA_PIX_FMT_BGR48LE: + length = xSize * ySize * 6; + swapRB = sourceFormat == OA_PIX_FMT_BGR48LE; + switch ( targetFormat ) { + case OA_PIX_FMT_GREY8: + oaGreyscale_RGB48LEto8( source, target, length, swapRB ); + break; + case OA_PIX_FMT_GREY16LE: + oaGreyscale_RGB48LEto16LE( source, target, length, swapRB ); + break; + case OA_PIX_FMT_GREY16BE: + oaGreyscale_RGB48LEto16BE( source, target, length, swapRB ); + break; + default: + return -1; // FIX ME -- set errno + } + break; + + case OA_PIX_FMT_RGB48BE: + case OA_PIX_FMT_BGR48BE: + length = xSize * ySize * 6; + swapRB = sourceFormat == OA_PIX_FMT_BGR48BE; + switch ( targetFormat ) { + case OA_PIX_FMT_GREY8: + oaGreyscale_RGB48BEto8( source, target, length, swapRB ); + break; + case OA_PIX_FMT_GREY16LE: + oaGreyscale_RGB48BEto16LE( source, target, length, swapRB ); + break; + case OA_PIX_FMT_GREY16BE: + oaGreyscale_RGB48BEto16BE( source, target, length, swapRB ); + break; + default: + return -1; // FIX ME -- set errno + } + break; + + //FIXME TODO + case OA_PIX_FMT_YUV444P: + case OA_PIX_FMT_YUV422P: + case OA_PIX_FMT_YUV420P: + case OA_PIX_FMT_YUV410P: + case OA_PIX_FMT_YUYV: + case OA_PIX_FMT_UYVY: + case OA_PIX_FMT_YUV420: + case OA_PIX_FMT_YUV411: + case OA_PIX_FMT_YUV410: + default: + return -1; // FIX ME -- set errno + } + return 0; +} + diff --git a/liboavideo/rgb_to_grey.ods b/liboavideo/rgb_to_grey.ods new file mode 100644 index 00000000..d4566b56 Binary files /dev/null and b/liboavideo/rgb_to_grey.ods differ diff --git a/liboavideo/test_oaconvert.c b/liboavideo/test_oaconvert.c new file mode 100644 index 00000000..734075da --- /dev/null +++ b/liboavideo/test_oaconvert.c @@ -0,0 +1,250 @@ +//gcc --std=c99 -g3 -O0 -I./ -I../include test_oaconvert.c yuv.c grey.c oavideo.c -o test_oaconvert +//or `head -n 1 test_oaconvert.c | cut -c 3-` +// ./test_oaconvert 2>&1 | tee test_oaconvert.txt; LINE=`grep at\ line test_oaconvert.txt | sed -e 's/.* at line //g'`; head -n $LINE test_oaconvert.c | tail -n 1 +#include +#include +#include + +#include +#include +#include "yuv.h" +#include "grey.h" + + +#define TARGET_LENGTH 24 + +uint8_t source[] = { 0x01, 0x23, 0x45, 0x67, + 0x89, 0xab, 0xcd, 0xef, + 0x01, 0x23, 0x45, 0x67, + 0x89, 0xab, 0xcd, 0xef, + 0x01, 0x23, 0x45, 0x67, + 0x89, 0xab, 0xcd, 0xef }; + +uint8_t empty[] = { 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00 }; + +void print_array(uint8_t* buf, int len, int sep) +{ + int i; + for ( i = 0; i < len; ++i ) + { + if (i == sep) + fprintf(stderr, " ... "); + fprintf(stderr, "%02x ", *(buf+i)); + } + fprintf(stderr, "\n"); +} + +void assert(int fmt, uint8_t expected[], uint8_t* target, int length, int check_nulls, int LINE) +{ + fprintf(stderr, "."); + if (0 != memcmp(target, expected, length)) { + fprintf(stderr, "F\n"); + fprintf(stderr, "Conversion does not match expected at line %d (fmt==%d)\n", LINE, fmt); + fprintf(stderr, "Expected: "); print_array(expected, length, -1); + fprintf(stderr, "Actual: "); print_array(target, length, -1); + exit(-1); + } + if (check_nulls && 0 != memcmp(empty, target+length, TARGET_LENGTH-length)) { + fprintf(stderr, "F\n"); + fprintf(stderr, "Conversion exceeds length of expected (%d) at line %d (fmt==%d)\n", length, LINE, fmt); + print_array(target, TARGET_LENGTH, length); + exit(-1); + } +} + +/** + * Test a conversion from pixel format S to pixel format T + * + * fmt - an index if running in a loop, to provide useful debug on failure + * S - source pixel format + * T - target pixel format + * e - pointer to array of expected result + * l - length of expected result + * L - line at which the function (macro) was invokved + */ +void test_convert(int fmt, int S, int T, uint8_t* e, int l, int L) +{ + uint8_t* t = (uint8_t*) malloc(TARGET_LENGTH); + + // Test conversion from one buffer to another + memset(t, 0, TARGET_LENGTH); + oaconvert(source, t, 2, 2, S, T); + assert(fmt, e, t, l, 1, L); + + // Test in-place conversion + memcpy(t, source, TARGET_LENGTH); + oaconvert(t, t, 2, 2, S, T); + assert(fmt, e, t, l, 0, L); + + free(t); +} + +#define EXPECTED(...) __VA_ARGS__ +#define TEST_CONVERT(fmt, S, T, expected) \ +do {\ + uint8_t e[] = expected;\ + test_convert(fmt, S, T, e, sizeof(e), __LINE__);\ +} while (0); + + + +/* FIXME - no routines and hence no tests exist for the following formats +#define OA_PIX_FMT_YUV444P 22 +#define OA_PIX_FMT_YUV422P 23 +#define OA_PIX_FMT_YUV420P 24 +#define OA_PIX_FMT_YUV410P 25 +#define OA_PIX_FMT_YUYV 27 +#define OA_PIX_FMT_UYVY 28 +#define OA_PIX_FMT_YUV420 29 +#define OA_PIX_FMT_YUV411 30 +#define OA_PIX_FMT_YUV410 31 +*/ + + +void test_8() +{ + int fmt; + uint8_t FORMATS_8[] = { OA_PIX_FMT_GREY8, + OA_PIX_FMT_BGGR8, + OA_PIX_FMT_RGGB8, + OA_PIX_FMT_GBRG8, + OA_PIX_FMT_GRBG8 }; + + fprintf(stderr, "Running tests in %s", __FUNCTION__); + + // 8bit + for ( fmt=0; fmt < sizeof(FORMATS_8); ++fmt ) { + TEST_CONVERT(fmt, FORMATS_8[fmt], OA_PIX_FMT_GREY8, EXPECTED({0x01, 0x23, 0x45, 0x67})); + TEST_CONVERT(fmt, FORMATS_8[fmt], OA_PIX_FMT_GREY16LE, EXPECTED({0x00, 0x01, 0x00, 0x23, 0x00, 0x45, 0x00, 0x67})); + TEST_CONVERT(fmt, FORMATS_8[fmt], OA_PIX_FMT_GREY16BE, EXPECTED({0x01, 0x00, 0x23, 0x00, 0x45, 0x00, 0x67, 0x00})); + } + + fprintf(stderr, "\n"); +} + +void test_10() +{ +/* FIXME awaiting OA_PIX_FMT_XXXX10X + + int fmt; + uint8_t FORMATS_10P[] = { //OA_PIX_FMT_BGGR10P, + //OA_PIX_FMT_RGGB10P, + //OA_PIX_FMT_GBRG10P, + OA_PIX_FMT_GRBG10P }; + + uint8_t FORMATS_10[] = { //OA_PIX_FMT_BGGR10, + //OA_PIX_FMT_RGGB10, + //OA_PIX_FMT_GBRG10, + OA_PIX_FMT_GRBG10 }; + + fprintf(stderr, "Running tests in %s", __FUNCTION__); + + // 10bit packed + for ( fmt=0; fmt < sizeof(FORMATS_10P); ++fmt ) { + TEST_CONVERT(fmt, FORMATS_10P[fmt], OA_PIX_FMT_GREY8, EXPECTED({0x01, 0x23, 0x45, 0x67})); + TEST_CONVERT(fmt, FORMATS_10P[fmt], OA_PIX_FMT_GREY16LE, EXPECTED({0x40, 0x01, 0x80, 0x23, 0x00, 0x45, 0x80, 0x67})); + TEST_CONVERT(fmt, FORMATS_10P[fmt], OA_PIX_FMT_GREY16BE, EXPECTED({0x01, 0x40, 0x23, 0x80, 0x45, 0x00, 0x67, 0x80})); + } + + // 10bit + for ( fmt=0; fmt < sizeof(FORMATS_10); ++fmt ) { + TEST_CONVERT(fmt, FORMATS_10[fmt], OA_PIX_FMT_GREY8, EXPECTED({0xc0, 0xd1, 0xe2, 0xf3})); + TEST_CONVERT(fmt, FORMATS_10[fmt], OA_PIX_FMT_GREY16LE, EXPECTED({0x40, 0xc0, 0x40, 0xd1, 0x40, 0xe2, 0x40, 0xf3})); + TEST_CONVERT(fmt, FORMATS_10[fmt], OA_PIX_FMT_GREY16BE, EXPECTED({0xc0, 0x40, 0xd1, 0x40, 0xe2, 0x40, 0xf3, 0x40})); + } + + fprintf(stderr, "\n"); +*/ +} + +void test_16 () +{ + int fmt; + uint8_t FORMATS_16LE[] = { OA_PIX_FMT_GREY16LE, + OA_PIX_FMT_BGGR16LE, + OA_PIX_FMT_RGGB16LE, + OA_PIX_FMT_GBRG16LE, + OA_PIX_FMT_GRBG16LE }; + + uint8_t FORMATS_16BE[] = { OA_PIX_FMT_GREY16BE, + OA_PIX_FMT_BGGR16BE, + OA_PIX_FMT_RGGB16BE, + OA_PIX_FMT_GBRG16BE, + OA_PIX_FMT_GRBG16BE }; + + fprintf(stderr, "Running tests in %s", __FUNCTION__); + + // 16bit LE + for ( fmt=0; fmt < sizeof(FORMATS_16LE); ++fmt ) { + TEST_CONVERT(fmt, FORMATS_16LE[fmt], OA_PIX_FMT_GREY8, EXPECTED({0x23, 0x67, 0xab, 0xef})); + TEST_CONVERT(fmt, FORMATS_16LE[fmt], OA_PIX_FMT_GREY16LE, EXPECTED({0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef})); + TEST_CONVERT(fmt, FORMATS_16LE[fmt], OA_PIX_FMT_GREY16BE, EXPECTED({0x23, 0x01, 0x67, 0x45, 0xab, 0x89, 0xef, 0xcd})); + } + + // 16bit BE + for ( fmt=0; fmt < sizeof(FORMATS_16BE); ++fmt ) { + TEST_CONVERT(fmt, FORMATS_16BE[fmt], OA_PIX_FMT_GREY8, EXPECTED({0x01, 0x45, 0x89, 0xcd})); + TEST_CONVERT(fmt, FORMATS_16BE[fmt], OA_PIX_FMT_GREY16LE, EXPECTED({0x23, 0x01, 0x67, 0x45, 0xab, 0x89, 0xef, 0xcd})); + TEST_CONVERT(fmt, FORMATS_16BE[fmt], OA_PIX_FMT_GREY16BE, EXPECTED({0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef})); + } + + fprintf(stderr, "\n"); +} + + +void test_rgb24() +{ + fprintf(stderr, "Running tests in %s", __FUNCTION__); + + // RGB24 + TEST_CONVERT(0, OA_PIX_FMT_RGB24, OA_PIX_FMT_GREY8, EXPECTED({0x1e, 0x84, 0xd6, 0x40})); + TEST_CONVERT(0, OA_PIX_FMT_RGB24, OA_PIX_FMT_GREY16LE, EXPECTED({0x39, 0x1e, 0x39, 0x84, 0x96, 0xd6, 0x39, 0x40})); + TEST_CONVERT(0, OA_PIX_FMT_RGB24, OA_PIX_FMT_GREY16BE, EXPECTED({0x1e, 0x39, 0x84, 0x39, 0xd6, 0x96, 0x40, 0x39})); + + // BGR24 + TEST_CONVERT(0, OA_PIX_FMT_BGR24, OA_PIX_FMT_GREY8, EXPECTED({0x27, 0x8d, 0xb9, 0x49})); + TEST_CONVERT(0, OA_PIX_FMT_BGR24, OA_PIX_FMT_GREY16LE, EXPECTED({0xc6, 0x27, 0xc6, 0x8d, 0xf2, 0xb9, 0xc6, 0x49})); + TEST_CONVERT(0, OA_PIX_FMT_BGR24, OA_PIX_FMT_GREY16BE, EXPECTED({0x27, 0xc6, 0x8d, 0xc6, 0xb9, 0xf2, 0x49, 0xc6})); + + fprintf(stderr, "\n"); +} + +void test_rgb48() +{ + fprintf(stderr, "Running tests in %s", __FUNCTION__); + + // RGB48 + TEST_CONVERT(0, OA_PIX_FMT_RGB48LE, OA_PIX_FMT_GREY8, EXPECTED({0x5d, 0x53, 0xd2, 0xa1})); + TEST_CONVERT(0, OA_PIX_FMT_RGB48LE, OA_PIX_FMT_GREY16LE, EXPECTED({0xaf, 0x5d, 0x78, 0x53, 0x80, 0xd2, 0xf3, 0xa1})); + TEST_CONVERT(0, OA_PIX_FMT_RGB48LE, OA_PIX_FMT_GREY16BE, EXPECTED({0x5d, 0xaf, 0x53, 0x78, 0xd2, 0x80, 0xa1, 0xf3})); + + TEST_CONVERT(0, OA_PIX_FMT_RGB48BE, OA_PIX_FMT_GREY8, EXPECTED({0x3b, 0x31, 0xb0, 0x80})); + TEST_CONVERT(0, OA_PIX_FMT_RGB48BE, OA_PIX_FMT_GREY16LE, EXPECTED({0xd1, 0x3b, 0x9a, 0x31, 0xa2, 0xb0, 0x15, 0x80})); + TEST_CONVERT(0, OA_PIX_FMT_RGB48BE, OA_PIX_FMT_GREY16BE, EXPECTED({0x3b, 0xd1, 0x31, 0x9a, 0xb0, 0xa2, 0x80, 0x15})); + + // BGR48 + TEST_CONVERT(0, OA_PIX_FMT_BGR48LE, OA_PIX_FMT_GREY8, EXPECTED({0x70, 0x40, 0xbf, 0xb5})); + TEST_CONVERT(0, OA_PIX_FMT_BGR48LE, OA_PIX_FMT_GREY16LE, EXPECTED({0xda, 0x70, 0x4d, 0x40, 0x55, 0xbf, 0x1e, 0xb5})); + TEST_CONVERT(0, OA_PIX_FMT_BGR48LE, OA_PIX_FMT_GREY16BE, EXPECTED({0x70, 0xda, 0x40, 0x4d, 0xbf, 0x55, 0xb5, 0x1e})); + + TEST_CONVERT(0, OA_PIX_FMT_BGR48BE, OA_PIX_FMT_GREY8, EXPECTED({0x4e, 0x1e, 0x9d, 0x93})); + TEST_CONVERT(0, OA_PIX_FMT_BGR48BE, OA_PIX_FMT_GREY16LE, EXPECTED({0xfc, 0x4e, 0x6f, 0x1e, 0x77, 0x9d, 0x40, 0x93})); + TEST_CONVERT(0, OA_PIX_FMT_BGR48BE, OA_PIX_FMT_GREY16BE, EXPECTED({0x4e, 0xfc, 0x1e, 0x6f, 0x9d, 0x77, 0x93, 0x40})); + + fprintf(stderr, "\n"); +} + +int main() +{ + test_8(); + test_10(); + test_16(); + test_rgb24(); + test_rgb48(); +} + diff --git a/liboavideo/yuv.c b/liboavideo/yuv.c index 8d2b3bb1..e49c0834 100644 --- a/liboavideo/yuv.c +++ b/liboavideo/yuv.c @@ -27,6 +27,8 @@ #include #include +#include + #include "yuv.h" #include "yuvlut.h" @@ -34,13 +36,13 @@ void -oaYUV444PtoRGB888 ( void* source, void* target, unsigned int xSize, +oaYUV444PtoRGB888 ( const void* source, void* target, unsigned int xSize, unsigned int ySize ) { unsigned int len = xSize * ySize; - uint8_t* ys = source; - uint8_t* us = ( uint8_t* ) source + len; - uint8_t* vs = ( uint8_t* ) source + 2 * len; + const uint8_t* ys = source; + const uint8_t* us = ( uint8_t* ) source + len; + const uint8_t* vs = ( uint8_t* ) source + 2 * len; uint8_t* t = ( uint8_t* ) target; int32_t r32, g32, b32; uint8_t r8, g8, b8, y, u, v; @@ -64,13 +66,13 @@ oaYUV444PtoRGB888 ( void* source, void* target, unsigned int xSize, void -oaYUV422PtoRGB888 ( void* source, void* target, unsigned int xSize, +oaYUV422PtoRGB888 ( const void* source, void* target, unsigned int xSize, unsigned int ySize ) { unsigned int len = xSize * ySize; - uint8_t* ys = ( uint8_t* ) source; - uint8_t* us = ( uint8_t* ) source + len; - uint8_t* vs = us + len / 2; + const uint8_t* ys = ( uint8_t* ) source; + const uint8_t* us = ( uint8_t* ) source + len; + const uint8_t* vs = us + len / 2; uint8_t* t = ( uint8_t* ) target; int32_t r32, g32, b32; uint8_t r8, g8, b8, y1, y2, u, v; @@ -113,7 +115,7 @@ oaYUV422PtoRGB888 ( void* source, void* target, unsigned int xSize, void -oaYUV420PtoRGB888 ( void* source, void* target, unsigned int xSize, +oaYUV420PtoRGB888 ( const void* source, void* target, unsigned int xSize, unsigned int ySize ) { unsigned int len = xSize * ySize; @@ -121,7 +123,7 @@ oaYUV420PtoRGB888 ( void* source, void* target, unsigned int xSize, unsigned int c, r; int32_t r32, g32, b32; uint8_t r8, g8, b8, y, u, v; - uint8_t* ys = ( uint8_t* ) source; + const uint8_t* ys = ( uint8_t* ) source; uint8_t* u_off; uint8_t* v_off; uint8_t* t = ( uint8_t* ) target; @@ -152,11 +154,11 @@ oaYUV420PtoRGB888 ( void* source, void* target, unsigned int xSize, void -oaYUYVtoRGB888 ( void* source, void* target, unsigned int xSize, +oaYUYVtoRGB888 ( const void* source, void* target, unsigned int xSize, unsigned int ySize ) { unsigned int len = xSize * ySize; - uint8_t* s = ( uint8_t* ) source; + const uint8_t* s = ( uint8_t* ) source; uint8_t* t = ( uint8_t* ) target; int32_t r32, g32, b32; uint8_t r8, g8, b8, y1, y2, u, v; @@ -199,11 +201,11 @@ oaYUYVtoRGB888 ( void* source, void* target, unsigned int xSize, void -oaUYVYtoRGB888 ( void* source, void* target, unsigned int xSize, +oaUYVYtoRGB888 ( const void* source, void* target, unsigned int xSize, unsigned int ySize ) { unsigned int len = xSize * ySize; - uint8_t* s = ( uint8_t* ) source; + const uint8_t* s = ( uint8_t* ) source; uint8_t* t = ( uint8_t* ) target; int32_t r32, g32, b32; uint8_t r8, g8, b8, y1, y2, u, v; @@ -246,11 +248,11 @@ oaUYVYtoRGB888 ( void* source, void* target, unsigned int xSize, void -oaYUV411toRGB888 ( void* source, void* target, unsigned int xSize, +oaYUV411toRGB888 ( const void* source, void* target, unsigned int xSize, unsigned int ySize ) { unsigned int len = xSize * ySize; - uint8_t* s = ( uint8_t* ) source; + const uint8_t* s = ( uint8_t* ) source; uint8_t* t = ( uint8_t* ) target; int32_t r32, g32, b32; uint8_t r8, g8, b8, y1, y2, y3, y4, u, v; diff --git a/liboavideo/yuv.h b/liboavideo/yuv.h index 64b5a8fc..a734797a 100644 --- a/liboavideo/yuv.h +++ b/liboavideo/yuv.h @@ -27,10 +27,10 @@ #ifndef OPENASTRO_VIDEO_YUV_H #define OPENASTRO_VIDEO_YUV_H -extern void oaYUV444PtoRGB888 ( void*, void*, unsigned int, unsigned int ); -extern void oaYUV422PtoRGB888 ( void*, void*, unsigned int, unsigned int ); -extern void oaYUV411toRGB888 ( void*, void*, unsigned int, unsigned int ); -extern void oaYUYVtoRGB888 ( void*, void*, unsigned int, unsigned int ); -extern void oaUYVYtoRGB888 ( void*, void*, unsigned int, unsigned int ); +extern void oaYUV444PtoRGB888 ( const void*, void*, unsigned int, unsigned int ); +extern void oaYUV422PtoRGB888 ( const void*, void*, unsigned int, unsigned int ); +extern void oaYUV411toRGB888 ( const void*, void*, unsigned int, unsigned int ); +extern void oaYUYVtoRGB888 ( const void*, void*, unsigned int, unsigned int ); +extern void oaUYVYtoRGB888 ( const void*, void*, unsigned int, unsigned int ); #endif /* OPENASTRO_VIDEO_YUV_H */