Commit d9c9f37a authored by fbarchard@google.com's avatar fbarchard@google.com

Conversions use malloc for row buffers.

BUG=296
TESTED=libyuv convert_test
R=tpsiaki@google.com

Review URL: https://webrtc-codereview.appspot.com/6399004

git-svn-id: http://libyuv.googlecode.com/svn/trunk@928 16f28f9a-4ce2-e073-06de-1de4eb20be90
parent b2a51d04
Name: libyuv Name: libyuv
URL: http://code.google.com/p/libyuv/ URL: http://code.google.com/p/libyuv/
Version: 927 Version: 928
License: BSD License: BSD
License File: LICENSE License File: LICENSE
......
...@@ -20,12 +20,6 @@ namespace libyuv { ...@@ -20,12 +20,6 @@ namespace libyuv {
extern "C" { extern "C" {
#endif #endif
// TODO(fbarchard): Remove kMaxStride.
#ifdef __arm__
#define kMaxStride (1920 * 4)
#else
#define kMaxStride (4096 * 4)
#endif
#define IS_ALIGNED(p, a) (!((uintptr_t)(p) & ((a) - 1))) #define IS_ALIGNED(p, a) (!((uintptr_t)(p) & ((a) - 1)))
// TODO (fbarchard): Port to C. // TODO (fbarchard): Port to C.
...@@ -448,14 +442,6 @@ typedef uint8 uvec8[16]; ...@@ -448,14 +442,6 @@ typedef uint8 uvec8[16];
#opcode " " #offset "(%" #base ",%" #index "," #scale "),%" #arg "\n" #opcode " " #offset "(%" #base ",%" #index "," #scale "),%" #arg "\n"
#endif #endif
// For functions that use rowbuffer and have runtime checks for overflow,
// use SAFEBUFFERS to avoid additional check.
#if defined(_MSC_VER) && (_MSC_FULL_VER >= 160040219)
#define SAFEBUFFERS __declspec(safebuffers)
#else
#define SAFEBUFFERS
#endif
void I444ToARGBRow_NEON(const uint8* src_y, void I444ToARGBRow_NEON(const uint8* src_y,
const uint8* src_u, const uint8* src_u,
const uint8* src_v, const uint8* src_v,
......
...@@ -11,6 +11,6 @@ ...@@ -11,6 +11,6 @@
#ifndef INCLUDE_LIBYUV_VERSION_H_ // NOLINT #ifndef INCLUDE_LIBYUV_VERSION_H_ // NOLINT
#define INCLUDE_LIBYUV_VERSION_H_ #define INCLUDE_LIBYUV_VERSION_H_
#define LIBYUV_VERSION 927 #define LIBYUV_VERSION 928
#endif // INCLUDE_LIBYUV_VERSION_H_ NOLINT #endif // INCLUDE_LIBYUV_VERSION_H_ NOLINT
...@@ -937,15 +937,14 @@ int RGBAToI420(const uint8* src_rgba, int src_stride_rgba, ...@@ -937,15 +937,14 @@ int RGBAToI420(const uint8* src_rgba, int src_stride_rgba,
} }
// Convert RGB24 to I420. // Convert RGB24 to I420.
LIBYUV_API SAFEBUFFERS LIBYUV_API
int RGB24ToI420(const uint8* src_rgb24, int src_stride_rgb24, int RGB24ToI420(const uint8* src_rgb24, int src_stride_rgb24,
uint8* dst_y, int dst_stride_y, uint8* dst_y, int dst_stride_y,
uint8* dst_u, int dst_stride_u, uint8* dst_u, int dst_stride_u,
uint8* dst_v, int dst_stride_v, uint8* dst_v, int dst_stride_v,
int width, int height) { int width, int height) {
if (!src_rgb24 || !dst_y || !dst_u || !dst_v || if (!src_rgb24 || !dst_y || !dst_u || !dst_v ||
width <= 0 || height == 0 || width <= 0 || height == 0) {
width * 4 > kMaxStride) {
return -1; return -1;
} }
// Negative height means invert the image. // Negative height means invert the image.
...@@ -973,7 +972,11 @@ int RGB24ToI420(const uint8* src_rgb24, int src_stride_rgb24, ...@@ -973,7 +972,11 @@ int RGB24ToI420(const uint8* src_rgb24, int src_stride_rgb24,
} }
} }
#else // HAS_RGB24TOYROW_NEON #else // HAS_RGB24TOYROW_NEON
SIMD_ALIGNED(uint8 row[kMaxStride * 2]);
// Allocate 2 rows of ARGB.
const int kRowSize = (width * 4 + 15) & ~15;
align_buffer_64(row, kRowSize * 2);
void (*RGB24ToARGBRow)(const uint8* src_rgb, uint8* dst_argb, int pix) = void (*RGB24ToARGBRow)(const uint8* src_rgb, uint8* dst_argb, int pix) =
RGB24ToARGBRow_C; RGB24ToARGBRow_C;
#if defined(HAS_RGB24TOARGBROW_SSSE3) #if defined(HAS_RGB24TOARGBROW_SSSE3)
...@@ -1016,10 +1019,10 @@ int RGB24ToI420(const uint8* src_rgb24, int src_stride_rgb24, ...@@ -1016,10 +1019,10 @@ int RGB24ToI420(const uint8* src_rgb24, int src_stride_rgb24,
RGB24ToYRow(src_rgb24 + src_stride_rgb24, dst_y + dst_stride_y, width); RGB24ToYRow(src_rgb24 + src_stride_rgb24, dst_y + dst_stride_y, width);
#else #else
RGB24ToARGBRow(src_rgb24, row, width); RGB24ToARGBRow(src_rgb24, row, width);
RGB24ToARGBRow(src_rgb24 + src_stride_rgb24, row + kMaxStride, width); RGB24ToARGBRow(src_rgb24 + src_stride_rgb24, row + kRowSize, width);
ARGBToUVRow(row, kMaxStride, dst_u, dst_v, width); ARGBToUVRow(row, kRowSize, dst_u, dst_v, width);
ARGBToYRow(row, dst_y, width); ARGBToYRow(row, dst_y, width);
ARGBToYRow(row + kMaxStride, dst_y + dst_stride_y, width); ARGBToYRow(row + kRowSize, dst_y + dst_stride_y, width);
#endif #endif
src_rgb24 += src_stride_rgb24 * 2; src_rgb24 += src_stride_rgb24 * 2;
dst_y += dst_stride_y * 2; dst_y += dst_stride_y * 2;
...@@ -1036,19 +1039,21 @@ int RGB24ToI420(const uint8* src_rgb24, int src_stride_rgb24, ...@@ -1036,19 +1039,21 @@ int RGB24ToI420(const uint8* src_rgb24, int src_stride_rgb24,
ARGBToYRow(row, dst_y, width); ARGBToYRow(row, dst_y, width);
#endif #endif
} }
#if !defined(HAS_RGB24TOYROW_NEON)
free_aligned_buffer_64(row);
#endif
return 0; return 0;
} }
// Convert RAW to I420. // Convert RAW to I420.
LIBYUV_API SAFEBUFFERS LIBYUV_API
int RAWToI420(const uint8* src_raw, int src_stride_raw, int RAWToI420(const uint8* src_raw, int src_stride_raw,
uint8* dst_y, int dst_stride_y, uint8* dst_y, int dst_stride_y,
uint8* dst_u, int dst_stride_u, uint8* dst_u, int dst_stride_u,
uint8* dst_v, int dst_stride_v, uint8* dst_v, int dst_stride_v,
int width, int height) { int width, int height) {
if (!src_raw || !dst_y || !dst_u || !dst_v || if (!src_raw || !dst_y || !dst_u || !dst_v ||
width <= 0 || height == 0 || width <= 0 || height == 0) {
width * 4 > kMaxStride) {
return -1; return -1;
} }
// Negative height means invert the image. // Negative height means invert the image.
...@@ -1076,7 +1081,11 @@ int RAWToI420(const uint8* src_raw, int src_stride_raw, ...@@ -1076,7 +1081,11 @@ int RAWToI420(const uint8* src_raw, int src_stride_raw,
} }
} }
#else // HAS_RAWTOYROW_NEON #else // HAS_RAWTOYROW_NEON
SIMD_ALIGNED(uint8 row[kMaxStride * 2]);
// Allocate 2 rows of ARGB.
const int kRowSize = (width * 4 + 15) & ~15;
align_buffer_64(row, kRowSize * 2);
void (*RAWToARGBRow)(const uint8* src_rgb, uint8* dst_argb, int pix) = void (*RAWToARGBRow)(const uint8* src_rgb, uint8* dst_argb, int pix) =
RAWToARGBRow_C; RAWToARGBRow_C;
#if defined(HAS_RAWTOARGBROW_SSSE3) #if defined(HAS_RAWTOARGBROW_SSSE3)
...@@ -1119,10 +1128,10 @@ int RAWToI420(const uint8* src_raw, int src_stride_raw, ...@@ -1119,10 +1128,10 @@ int RAWToI420(const uint8* src_raw, int src_stride_raw,
RAWToYRow(src_raw + src_stride_raw, dst_y + dst_stride_y, width); RAWToYRow(src_raw + src_stride_raw, dst_y + dst_stride_y, width);
#else #else
RAWToARGBRow(src_raw, row, width); RAWToARGBRow(src_raw, row, width);
RAWToARGBRow(src_raw + src_stride_raw, row + kMaxStride, width); RAWToARGBRow(src_raw + src_stride_raw, row + kRowSize, width);
ARGBToUVRow(row, kMaxStride, dst_u, dst_v, width); ARGBToUVRow(row, kRowSize, dst_u, dst_v, width);
ARGBToYRow(row, dst_y, width); ARGBToYRow(row, dst_y, width);
ARGBToYRow(row + kMaxStride, dst_y + dst_stride_y, width); ARGBToYRow(row + kRowSize, dst_y + dst_stride_y, width);
#endif #endif
src_raw += src_stride_raw * 2; src_raw += src_stride_raw * 2;
dst_y += dst_stride_y * 2; dst_y += dst_stride_y * 2;
...@@ -1139,19 +1148,21 @@ int RAWToI420(const uint8* src_raw, int src_stride_raw, ...@@ -1139,19 +1148,21 @@ int RAWToI420(const uint8* src_raw, int src_stride_raw,
ARGBToYRow(row, dst_y, width); ARGBToYRow(row, dst_y, width);
#endif #endif
} }
#if !defined(HAS_RAWTOYROW_NEON)
free_aligned_buffer_64(row);
#endif
return 0; return 0;
} }
// Convert RGB565 to I420. // Convert RGB565 to I420.
LIBYUV_API SAFEBUFFERS LIBYUV_API
int RGB565ToI420(const uint8* src_rgb565, int src_stride_rgb565, int RGB565ToI420(const uint8* src_rgb565, int src_stride_rgb565,
uint8* dst_y, int dst_stride_y, uint8* dst_y, int dst_stride_y,
uint8* dst_u, int dst_stride_u, uint8* dst_u, int dst_stride_u,
uint8* dst_v, int dst_stride_v, uint8* dst_v, int dst_stride_v,
int width, int height) { int width, int height) {
if (!src_rgb565 || !dst_y || !dst_u || !dst_v || if (!src_rgb565 || !dst_y || !dst_u || !dst_v ||
width <= 0 || height == 0 || width <= 0 || height == 0) {
width * 4 > kMaxStride) {
return -1; return -1;
} }
// Negative height means invert the image. // Negative height means invert the image.
...@@ -1179,7 +1190,11 @@ int RGB565ToI420(const uint8* src_rgb565, int src_stride_rgb565, ...@@ -1179,7 +1190,11 @@ int RGB565ToI420(const uint8* src_rgb565, int src_stride_rgb565,
} }
} }
#else // HAS_RGB565TOYROW_NEON #else // HAS_RGB565TOYROW_NEON
SIMD_ALIGNED(uint8 row[kMaxStride * 2]);
// Allocate 2 rows of ARGB.
const int kRowSize = (width * 4 + 15) & ~15;
align_buffer_64(row, kRowSize * 2);
void (*RGB565ToARGBRow)(const uint8* src_rgb, uint8* dst_argb, int pix) = void (*RGB565ToARGBRow)(const uint8* src_rgb, uint8* dst_argb, int pix) =
RGB565ToARGBRow_C; RGB565ToARGBRow_C;
#if defined(HAS_RGB565TOARGBROW_SSE2) #if defined(HAS_RGB565TOARGBROW_SSE2)
...@@ -1222,10 +1237,10 @@ int RGB565ToI420(const uint8* src_rgb565, int src_stride_rgb565, ...@@ -1222,10 +1237,10 @@ int RGB565ToI420(const uint8* src_rgb565, int src_stride_rgb565,
RGB565ToYRow(src_rgb565 + src_stride_rgb565, dst_y + dst_stride_y, width); RGB565ToYRow(src_rgb565 + src_stride_rgb565, dst_y + dst_stride_y, width);
#else #else
RGB565ToARGBRow(src_rgb565, row, width); RGB565ToARGBRow(src_rgb565, row, width);
RGB565ToARGBRow(src_rgb565 + src_stride_rgb565, row + kMaxStride, width); RGB565ToARGBRow(src_rgb565 + src_stride_rgb565, row + kRowSize, width);
ARGBToUVRow(row, kMaxStride, dst_u, dst_v, width); ARGBToUVRow(row, kRowSize, dst_u, dst_v, width);
ARGBToYRow(row, dst_y, width); ARGBToYRow(row, dst_y, width);
ARGBToYRow(row + kMaxStride, dst_y + dst_stride_y, width); ARGBToYRow(row + kRowSize, dst_y + dst_stride_y, width);
#endif #endif
src_rgb565 += src_stride_rgb565 * 2; src_rgb565 += src_stride_rgb565 * 2;
dst_y += dst_stride_y * 2; dst_y += dst_stride_y * 2;
...@@ -1242,19 +1257,21 @@ int RGB565ToI420(const uint8* src_rgb565, int src_stride_rgb565, ...@@ -1242,19 +1257,21 @@ int RGB565ToI420(const uint8* src_rgb565, int src_stride_rgb565,
ARGBToYRow(row, dst_y, width); ARGBToYRow(row, dst_y, width);
#endif #endif
} }
#if !defined(HAS_RGB565TOYROW_NEON)
free_aligned_buffer_64(row);
#endif
return 0; return 0;
} }
// Convert ARGB1555 to I420. // Convert ARGB1555 to I420.
LIBYUV_API SAFEBUFFERS LIBYUV_API
int ARGB1555ToI420(const uint8* src_argb1555, int src_stride_argb1555, int ARGB1555ToI420(const uint8* src_argb1555, int src_stride_argb1555,
uint8* dst_y, int dst_stride_y, uint8* dst_y, int dst_stride_y,
uint8* dst_u, int dst_stride_u, uint8* dst_u, int dst_stride_u,
uint8* dst_v, int dst_stride_v, uint8* dst_v, int dst_stride_v,
int width, int height) { int width, int height) {
if (!src_argb1555 || !dst_y || !dst_u || !dst_v || if (!src_argb1555 || !dst_y || !dst_u || !dst_v ||
width <= 0 || height == 0 || width <= 0 || height == 0) {
width * 4 > kMaxStride) {
return -1; return -1;
} }
// Negative height means invert the image. // Negative height means invert the image.
...@@ -1282,7 +1299,11 @@ int ARGB1555ToI420(const uint8* src_argb1555, int src_stride_argb1555, ...@@ -1282,7 +1299,11 @@ int ARGB1555ToI420(const uint8* src_argb1555, int src_stride_argb1555,
} }
} }
#else // HAS_ARGB1555TOYROW_NEON #else // HAS_ARGB1555TOYROW_NEON
SIMD_ALIGNED(uint8 row[kMaxStride * 2]);
// Allocate 2 rows of ARGB.
const int kRowSize = (width * 4 + 15) & ~15;
align_buffer_64(row, kRowSize * 2);
void (*ARGB1555ToARGBRow)(const uint8* src_rgb, uint8* dst_argb, int pix) = void (*ARGB1555ToARGBRow)(const uint8* src_rgb, uint8* dst_argb, int pix) =
ARGB1555ToARGBRow_C; ARGB1555ToARGBRow_C;
#if defined(HAS_ARGB1555TOARGBROW_SSE2) #if defined(HAS_ARGB1555TOARGBROW_SSE2)
...@@ -1326,11 +1347,11 @@ int ARGB1555ToI420(const uint8* src_argb1555, int src_stride_argb1555, ...@@ -1326,11 +1347,11 @@ int ARGB1555ToI420(const uint8* src_argb1555, int src_stride_argb1555,
width); width);
#else #else
ARGB1555ToARGBRow(src_argb1555, row, width); ARGB1555ToARGBRow(src_argb1555, row, width);
ARGB1555ToARGBRow(src_argb1555 + src_stride_argb1555, row + kMaxStride, ARGB1555ToARGBRow(src_argb1555 + src_stride_argb1555, row + kRowSize,
width); width);
ARGBToUVRow(row, kMaxStride, dst_u, dst_v, width); ARGBToUVRow(row, kRowSize, dst_u, dst_v, width);
ARGBToYRow(row, dst_y, width); ARGBToYRow(row, dst_y, width);
ARGBToYRow(row + kMaxStride, dst_y + dst_stride_y, width); ARGBToYRow(row + kRowSize, dst_y + dst_stride_y, width);
#endif #endif
src_argb1555 += src_stride_argb1555 * 2; src_argb1555 += src_stride_argb1555 * 2;
dst_y += dst_stride_y * 2; dst_y += dst_stride_y * 2;
...@@ -1347,19 +1368,21 @@ int ARGB1555ToI420(const uint8* src_argb1555, int src_stride_argb1555, ...@@ -1347,19 +1368,21 @@ int ARGB1555ToI420(const uint8* src_argb1555, int src_stride_argb1555,
ARGBToYRow(row, dst_y, width); ARGBToYRow(row, dst_y, width);
#endif #endif
} }
#if !defined(HAS_ARGB1555TOYROW_NEON)
free_aligned_buffer_64(row);
#endif
return 0; return 0;
} }
// Convert ARGB4444 to I420. // Convert ARGB4444 to I420.
LIBYUV_API SAFEBUFFERS LIBYUV_API
int ARGB4444ToI420(const uint8* src_argb4444, int src_stride_argb4444, int ARGB4444ToI420(const uint8* src_argb4444, int src_stride_argb4444,
uint8* dst_y, int dst_stride_y, uint8* dst_y, int dst_stride_y,
uint8* dst_u, int dst_stride_u, uint8* dst_u, int dst_stride_u,
uint8* dst_v, int dst_stride_v, uint8* dst_v, int dst_stride_v,
int width, int height) { int width, int height) {
if (!src_argb4444 || !dst_y || !dst_u || !dst_v || if (!src_argb4444 || !dst_y || !dst_u || !dst_v ||
width <= 0 || height == 0 || width <= 0 || height == 0) {
width * 4 > kMaxStride) {
return -1; return -1;
} }
// Negative height means invert the image. // Negative height means invert the image.
...@@ -1387,7 +1410,11 @@ int ARGB4444ToI420(const uint8* src_argb4444, int src_stride_argb4444, ...@@ -1387,7 +1410,11 @@ int ARGB4444ToI420(const uint8* src_argb4444, int src_stride_argb4444,
} }
} }
#else // HAS_ARGB4444TOYROW_NEON #else // HAS_ARGB4444TOYROW_NEON
SIMD_ALIGNED(uint8 row[kMaxStride * 2]);
// Allocate 2 rows of ARGB.
const int kRowSize = (width * 4 + 15) & ~15;
align_buffer_64(row, kRowSize * 2);
void (*ARGB4444ToARGBRow)(const uint8* src_rgb, uint8* dst_argb, int pix) = void (*ARGB4444ToARGBRow)(const uint8* src_rgb, uint8* dst_argb, int pix) =
ARGB4444ToARGBRow_C; ARGB4444ToARGBRow_C;
#if defined(HAS_ARGB4444TOARGBROW_SSE2) #if defined(HAS_ARGB4444TOARGBROW_SSE2)
...@@ -1431,11 +1458,11 @@ int ARGB4444ToI420(const uint8* src_argb4444, int src_stride_argb4444, ...@@ -1431,11 +1458,11 @@ int ARGB4444ToI420(const uint8* src_argb4444, int src_stride_argb4444,
width); width);
#else #else
ARGB4444ToARGBRow(src_argb4444, row, width); ARGB4444ToARGBRow(src_argb4444, row, width);
ARGB4444ToARGBRow(src_argb4444 + src_stride_argb4444, row + kMaxStride, ARGB4444ToARGBRow(src_argb4444 + src_stride_argb4444, row + kRowSize,
width); width);
ARGBToUVRow(row, kMaxStride, dst_u, dst_v, width); ARGBToUVRow(row, kRowSize, dst_u, dst_v, width);
ARGBToYRow(row, dst_y, width); ARGBToYRow(row, dst_y, width);
ARGBToYRow(row + kMaxStride, dst_y + dst_stride_y, width); ARGBToYRow(row + kRowSize, dst_y + dst_stride_y, width);
#endif #endif
src_argb4444 += src_stride_argb4444 * 2; src_argb4444 += src_stride_argb4444 * 2;
dst_y += dst_stride_y * 2; dst_y += dst_stride_y * 2;
...@@ -1452,6 +1479,9 @@ int ARGB4444ToI420(const uint8* src_argb4444, int src_stride_argb4444, ...@@ -1452,6 +1479,9 @@ int ARGB4444ToI420(const uint8* src_argb4444, int src_stride_argb4444,
ARGBToYRow(row, dst_y, width); ARGBToYRow(row, dst_y, width);
#endif #endif
} }
#if !defined(HAS_ARGB4444TOYROW_NEON)
free_aligned_buffer_64(row);
#endif
return 0; return 0;
} }
......
...@@ -807,8 +807,7 @@ int YUY2ToARGB(const uint8* src_yuy2, int src_stride_yuy2, ...@@ -807,8 +807,7 @@ int YUY2ToARGB(const uint8* src_yuy2, int src_stride_yuy2,
src_stride_yuy2 = -src_stride_yuy2; src_stride_yuy2 = -src_stride_yuy2;
} }
// Coalesce rows. // Coalesce rows.
if (width * height <= kMaxStride && if (src_stride_yuy2 == width * 2 &&
src_stride_yuy2 == width * 2 &&
dst_stride_argb == width * 4) { dst_stride_argb == width * 4) {
width *= height; width *= height;
height = 1; height = 1;
...@@ -818,7 +817,7 @@ int YUY2ToARGB(const uint8* src_yuy2, int src_stride_yuy2, ...@@ -818,7 +817,7 @@ int YUY2ToARGB(const uint8* src_yuy2, int src_stride_yuy2,
YUY2ToARGBRow_C; YUY2ToARGBRow_C;
#if defined(HAS_YUY2TOARGBROW_SSSE3) #if defined(HAS_YUY2TOARGBROW_SSSE3)
// Posix is 16, Windows is 8. // Posix is 16, Windows is 8.
if (TestCpuFlag(kCpuHasSSSE3) && width >= 16 && width <= kMaxStride) { if (TestCpuFlag(kCpuHasSSSE3) && width >= 16) {
YUY2ToARGBRow = YUY2ToARGBRow_Any_SSSE3; YUY2ToARGBRow = YUY2ToARGBRow_Any_SSSE3;
if (IS_ALIGNED(width, 16)) { if (IS_ALIGNED(width, 16)) {
YUY2ToARGBRow = YUY2ToARGBRow_Unaligned_SSSE3; YUY2ToARGBRow = YUY2ToARGBRow_Unaligned_SSSE3;
...@@ -860,8 +859,7 @@ int UYVYToARGB(const uint8* src_uyvy, int src_stride_uyvy, ...@@ -860,8 +859,7 @@ int UYVYToARGB(const uint8* src_uyvy, int src_stride_uyvy,
src_stride_uyvy = -src_stride_uyvy; src_stride_uyvy = -src_stride_uyvy;
} }
// Coalesce rows. // Coalesce rows.
if (width * height <= kMaxStride && if (src_stride_uyvy == width * 2 &&
src_stride_uyvy == width * 2 &&
dst_stride_argb == width * 4) { dst_stride_argb == width * 4) {
width *= height; width *= height;
height = 1; height = 1;
...@@ -871,7 +869,7 @@ int UYVYToARGB(const uint8* src_uyvy, int src_stride_uyvy, ...@@ -871,7 +869,7 @@ int UYVYToARGB(const uint8* src_uyvy, int src_stride_uyvy,
UYVYToARGBRow_C; UYVYToARGBRow_C;
#if defined(HAS_UYVYTOARGBROW_SSSE3) #if defined(HAS_UYVYTOARGBROW_SSSE3)
// Posix is 16, Windows is 8. // Posix is 16, Windows is 8.
if (TestCpuFlag(kCpuHasSSSE3) && width >= 16 && width <= kMaxStride) { if (TestCpuFlag(kCpuHasSSSE3) && width >= 16) {
UYVYToARGBRow = UYVYToARGBRow_Any_SSSE3; UYVYToARGBRow = UYVYToARGBRow_Any_SSSE3;
if (IS_ALIGNED(width, 16)) { if (IS_ALIGNED(width, 16)) {
UYVYToARGBRow = UYVYToARGBRow_Unaligned_SSSE3; UYVYToARGBRow = UYVYToARGBRow_Unaligned_SSSE3;
......
...@@ -808,7 +808,7 @@ int I420ToARGB1555(const uint8* src_y, int src_stride_y, ...@@ -808,7 +808,7 @@ int I420ToARGB1555(const uint8* src_y, int src_stride_y,
uint8* rgb_buf, uint8* rgb_buf,
int width) = I422ToARGB1555Row_C; int width) = I422ToARGB1555Row_C;
#if defined(HAS_I422TOARGB1555ROW_SSSE3) #if defined(HAS_I422TOARGB1555ROW_SSSE3)
if (TestCpuFlag(kCpuHasSSSE3) && width >= 8 && width * 4 <= kMaxStride) { if (TestCpuFlag(kCpuHasSSSE3) && width >= 8) {
I422ToARGB1555Row = I422ToARGB1555Row_Any_SSSE3; I422ToARGB1555Row = I422ToARGB1555Row_Any_SSSE3;
if (IS_ALIGNED(width, 8)) { if (IS_ALIGNED(width, 8)) {
I422ToARGB1555Row = I422ToARGB1555Row_SSSE3; I422ToARGB1555Row = I422ToARGB1555Row_SSSE3;
...@@ -859,7 +859,7 @@ int I420ToARGB4444(const uint8* src_y, int src_stride_y, ...@@ -859,7 +859,7 @@ int I420ToARGB4444(const uint8* src_y, int src_stride_y,
uint8* rgb_buf, uint8* rgb_buf,
int width) = I422ToARGB4444Row_C; int width) = I422ToARGB4444Row_C;
#if defined(HAS_I422TOARGB4444ROW_SSSE3) #if defined(HAS_I422TOARGB4444ROW_SSSE3)
if (TestCpuFlag(kCpuHasSSSE3) && width >= 8 && width * 4 <= kMaxStride) { if (TestCpuFlag(kCpuHasSSSE3) && width >= 8) {
I422ToARGB4444Row = I422ToARGB4444Row_Any_SSSE3; I422ToARGB4444Row = I422ToARGB4444Row_Any_SSSE3;
if (IS_ALIGNED(width, 8)) { if (IS_ALIGNED(width, 8)) {
I422ToARGB4444Row = I422ToARGB4444Row_SSSE3; I422ToARGB4444Row = I422ToARGB4444Row_SSSE3;
...@@ -909,11 +909,7 @@ int I420ToRGB565(const uint8* src_y, int src_stride_y, ...@@ -909,11 +909,7 @@ int I420ToRGB565(const uint8* src_y, int src_stride_y,
uint8* rgb_buf, uint8* rgb_buf,
int width) = I422ToRGB565Row_C; int width) = I422ToRGB565Row_C;
#if defined(HAS_I422TORGB565ROW_SSSE3) #if defined(HAS_I422TORGB565ROW_SSSE3)
if (TestCpuFlag(kCpuHasSSSE3) && width >= 8 if (TestCpuFlag(kCpuHasSSSE3) && width >= 8) {
#if defined(__x86_64__) || defined(__i386__)
&& width * 4 <= kMaxStride
#endif
) {
I422ToRGB565Row = I422ToRGB565Row_Any_SSSE3; I422ToRGB565Row = I422ToRGB565Row_Any_SSSE3;
if (IS_ALIGNED(width, 8)) { if (IS_ALIGNED(width, 8)) {
I422ToRGB565Row = I422ToRGB565Row_SSSE3; I422ToRGB565Row = I422ToRGB565Row_SSSE3;
......
...@@ -245,15 +245,14 @@ int ARGBToI411(const uint8* src_argb, int src_stride_argb, ...@@ -245,15 +245,14 @@ int ARGBToI411(const uint8* src_argb, int src_stride_argb,
return 0; return 0;
} }
LIBYUV_API SAFEBUFFERS LIBYUV_API
int ARGBToNV12(const uint8* src_argb, int src_stride_argb, int ARGBToNV12(const uint8* src_argb, int src_stride_argb,
uint8* dst_y, int dst_stride_y, uint8* dst_y, int dst_stride_y,
uint8* dst_uv, int dst_stride_uv, uint8* dst_uv, int dst_stride_uv,
int width, int height) { int width, int height) {
if (!src_argb || if (!src_argb ||
!dst_y || !dst_uv || !dst_y || !dst_uv ||
width <= 0 || height == 0 || width <= 0 || height == 0) {
width > kMaxStride) {
return -1; return -1;
} }
// Negative height means invert the image. // Negative height means invert the image.
...@@ -326,8 +325,9 @@ int ARGBToNV12(const uint8* src_argb, int src_stride_argb, ...@@ -326,8 +325,9 @@ int ARGBToNV12(const uint8* src_argb, int src_stride_argb,
} }
#endif #endif
SIMD_ALIGNED(uint8 row_u[kMaxStride / 2]); // Allocate a row of uv.
SIMD_ALIGNED(uint8 row_v[kMaxStride / 2]); align_buffer_64(row_u, halfwidth);
align_buffer_64(row_v, halfwidth);
for (int y = 0; y < height - 1; y += 2) { for (int y = 0; y < height - 1; y += 2) {
ARGBToUVRow(src_argb, src_stride_argb, row_u, row_v, width); ARGBToUVRow(src_argb, src_stride_argb, row_u, row_v, width);
...@@ -343,19 +343,20 @@ int ARGBToNV12(const uint8* src_argb, int src_stride_argb, ...@@ -343,19 +343,20 @@ int ARGBToNV12(const uint8* src_argb, int src_stride_argb,
MergeUVRow_(row_u, row_v, dst_uv, halfwidth); MergeUVRow_(row_u, row_v, dst_uv, halfwidth);
ARGBToYRow(src_argb, dst_y, width); ARGBToYRow(src_argb, dst_y, width);
} }
free_aligned_buffer_64(row_u);
free_aligned_buffer_64(row_v);
return 0; return 0;
} }
// Same as NV12 but U and V swapped. // Same as NV12 but U and V swapped.
LIBYUV_API SAFEBUFFERS LIBYUV_API
int ARGBToNV21(const uint8* src_argb, int src_stride_argb, int ARGBToNV21(const uint8* src_argb, int src_stride_argb,
uint8* dst_y, int dst_stride_y, uint8* dst_y, int dst_stride_y,
uint8* dst_uv, int dst_stride_uv, uint8* dst_uv, int dst_stride_uv,
int width, int height) { int width, int height) {
if (!src_argb || if (!src_argb ||
!dst_y || !dst_uv || !dst_y || !dst_uv ||
width <= 0 || height == 0 || width <= 0 || height == 0) {
width > kMaxStride) {
return -1; return -1;
} }
// Negative height means invert the image. // Negative height means invert the image.
...@@ -428,8 +429,9 @@ int ARGBToNV21(const uint8* src_argb, int src_stride_argb, ...@@ -428,8 +429,9 @@ int ARGBToNV21(const uint8* src_argb, int src_stride_argb,
} }
#endif #endif
SIMD_ALIGNED(uint8 row_u[kMaxStride / 2]); // Allocate a row of uv.
SIMD_ALIGNED(uint8 row_v[kMaxStride / 2]); align_buffer_64(row_u, halfwidth);
align_buffer_64(row_v, halfwidth);
for (int y = 0; y < height - 1; y += 2) { for (int y = 0; y < height - 1; y += 2) {
ARGBToUVRow(src_argb, src_stride_argb, row_u, row_v, width); ARGBToUVRow(src_argb, src_stride_argb, row_u, row_v, width);
...@@ -445,17 +447,18 @@ int ARGBToNV21(const uint8* src_argb, int src_stride_argb, ...@@ -445,17 +447,18 @@ int ARGBToNV21(const uint8* src_argb, int src_stride_argb,
MergeUVRow_(row_v, row_u, dst_uv, halfwidth); MergeUVRow_(row_v, row_u, dst_uv, halfwidth);
ARGBToYRow(src_argb, dst_y, width); ARGBToYRow(src_argb, dst_y, width);
} }
free_aligned_buffer_64(row_u);
free_aligned_buffer_64(row_v);
return 0; return 0;
} }
// Convert ARGB to YUY2. // Convert ARGB to YUY2.
LIBYUV_API SAFEBUFFERS LIBYUV_API
int ARGBToYUY2(const uint8* src_argb, int src_stride_argb, int ARGBToYUY2(const uint8* src_argb, int src_stride_argb,
uint8* dst_yuy2, int dst_stride_yuy2, uint8* dst_yuy2, int dst_stride_yuy2,
int width, int height) { int width, int height) {
if (!src_argb || !dst_yuy2 || if (!src_argb || !dst_yuy2 ||
width <= 0 || height == 0 || width <= 0 || height == 0) {
width > kMaxStride) {
return -1; return -1;
} }
// Negative height means invert the image. // Negative height means invert the image.
...@@ -465,8 +468,7 @@ int ARGBToYUY2(const uint8* src_argb, int src_stride_argb, ...@@ -465,8 +468,7 @@ int ARGBToYUY2(const uint8* src_argb, int src_stride_argb,
dst_stride_yuy2 = -dst_stride_yuy2; dst_stride_yuy2 = -dst_stride_yuy2;
} }
// Coalesce rows. // Coalesce rows.
if (width * height <= kMaxStride && if (src_stride_argb == width * 4 &&
src_stride_argb == width * 4 &&
dst_stride_yuy2 == width * 2) { dst_stride_yuy2 == width * 2) {
width *= height; width *= height;
height = 1; height = 1;
...@@ -530,9 +532,11 @@ int ARGBToYUY2(const uint8* src_argb, int src_stride_argb, ...@@ -530,9 +532,11 @@ int ARGBToYUY2(const uint8* src_argb, int src_stride_argb,
} }
} }
#endif #endif
SIMD_ALIGNED(uint8 row_y[kMaxStride]);
SIMD_ALIGNED(uint8 row_u[kMaxStride / 2]); // Allocate a row of yuv.
SIMD_ALIGNED(uint8 row_v[kMaxStride / 2]); align_buffer_64(row_y, width);
align_buffer_64(row_u, (width + 1) / 2);
align_buffer_64(row_v, (width + 1) / 2);
for (int y = 0; y < height; ++y) { for (int y = 0; y < height; ++y) {
ARGBToUV422Row(src_argb, row_u, row_v, width); ARGBToUV422Row(src_argb, row_u, row_v, width);
...@@ -541,17 +545,20 @@ int ARGBToYUY2(const uint8* src_argb, int src_stride_argb, ...@@ -541,17 +545,20 @@ int ARGBToYUY2(const uint8* src_argb, int src_stride_argb,
src_argb += src_stride_argb; src_argb += src_stride_argb;
dst_yuy2 += dst_stride_yuy2; dst_yuy2 += dst_stride_yuy2;
} }
free_aligned_buffer_64(row_y);
free_aligned_buffer_64(row_u);
free_aligned_buffer_64(row_v);
return 0; return 0;
} }
// Convert ARGB to UYVY. // Convert ARGB to UYVY.
LIBYUV_API SAFEBUFFERS LIBYUV_API
int ARGBToUYVY(const uint8* src_argb, int src_stride_argb, int ARGBToUYVY(const uint8* src_argb, int src_stride_argb,
uint8* dst_uyvy, int dst_stride_uyvy, uint8* dst_uyvy, int dst_stride_uyvy,
int width, int height) { int width, int height) {
if (!src_argb || !dst_uyvy || if (!src_argb || !dst_uyvy ||
width <= 0 || height == 0 || width <= 0 || height == 0) {
width > kMaxStride) {
return -1; return -1;
} }
// Negative height means invert the image. // Negative height means invert the image.
...@@ -561,8 +568,7 @@ int ARGBToUYVY(const uint8* src_argb, int src_stride_argb, ...@@ -561,8 +568,7 @@ int ARGBToUYVY(const uint8* src_argb, int src_stride_argb,
dst_stride_uyvy = -dst_stride_uyvy; dst_stride_uyvy = -dst_stride_uyvy;
} }
// Coalesce rows. // Coalesce rows.
if (width * height <= kMaxStride && if (src_stride_argb == width * 4 &&
src_stride_argb == width * 4 &&
dst_stride_uyvy == width * 2) { dst_stride_uyvy == width * 2) {
width *= height; width *= height;
height = 1; height = 1;
...@@ -626,9 +632,10 @@ int ARGBToUYVY(const uint8* src_argb, int src_stride_argb, ...@@ -626,9 +632,10 @@ int ARGBToUYVY(const uint8* src_argb, int src_stride_argb,
} }
} }
#endif #endif
SIMD_ALIGNED(uint8 row_y[kMaxStride]); // Allocate a row of yuv.
SIMD_ALIGNED(uint8 row_u[kMaxStride / 2]); align_buffer_64(row_y, width);
SIMD_ALIGNED(uint8 row_v[kMaxStride / 2]); align_buffer_64(row_u, (width + 1) / 2);
align_buffer_64(row_v, (width + 1) / 2);
for (int y = 0; y < height; ++y) { for (int y = 0; y < height; ++y) {
ARGBToUV422Row(src_argb, row_u, row_v, width); ARGBToUV422Row(src_argb, row_u, row_v, width);
...@@ -637,6 +644,10 @@ int ARGBToUYVY(const uint8* src_argb, int src_stride_argb, ...@@ -637,6 +644,10 @@ int ARGBToUYVY(const uint8* src_argb, int src_stride_argb,
src_argb += src_stride_argb; src_argb += src_stride_argb;
dst_uyvy += dst_stride_uyvy; dst_uyvy += dst_stride_uyvy;
} }
free_aligned_buffer_64(row_y);
free_aligned_buffer_64(row_u);
free_aligned_buffer_64(row_v);
return 0; return 0;
} }
......
...@@ -33,7 +33,7 @@ namespace libyuv { ...@@ -33,7 +33,7 @@ namespace libyuv {
extern "C" { extern "C" {
#endif #endif
// For functions that use rowbuffer and have runtime checks for overflow, // For functions that use the stack and have runtime checks for overflow,
// use SAFEBUFFERS to avoid additional check. // use SAFEBUFFERS to avoid additional check.
#if defined(_MSC_VER) && (_MSC_FULL_VER >= 160040219) #if defined(_MSC_VER) && (_MSC_FULL_VER >= 160040219)
#define SAFEBUFFERS __declspec(safebuffers) #define SAFEBUFFERS __declspec(safebuffers)
......
...@@ -280,7 +280,7 @@ int BayerToARGB(const uint8* src_bayer, int src_stride_bayer, ...@@ -280,7 +280,7 @@ int BayerToARGB(const uint8* src_bayer, int src_stride_bayer,
} }
// Converts any Bayer RGB format to ARGB. // Converts any Bayer RGB format to ARGB.
LIBYUV_API SAFEBUFFERS LIBYUV_API
int BayerToI420(const uint8* src_bayer, int src_stride_bayer, int BayerToI420(const uint8* src_bayer, int src_stride_bayer,
uint8* dst_y, int dst_stride_y, uint8* dst_y, int dst_stride_y,
uint8* dst_u, int dst_stride_u, uint8* dst_u, int dst_stride_u,
...@@ -380,7 +380,7 @@ int BayerToI420(const uint8* src_bayer, int src_stride_bayer, ...@@ -380,7 +380,7 @@ int BayerToI420(const uint8* src_bayer, int src_stride_bayer,
} }
// Convert I420 to Bayer. // Convert I420 to Bayer.
LIBYUV_API SAFEBUFFERS LIBYUV_API
int I420ToBayer(const uint8* src_y, int src_stride_y, int I420ToBayer(const uint8* src_y, int src_stride_y,
const uint8* src_u, int src_stride_u, const uint8* src_u, int src_stride_u,
const uint8* src_v, int src_stride_v, const uint8* src_v, int src_stride_v,
......
...@@ -1372,7 +1372,7 @@ int ARGBColorMatrix(const uint8* src_argb, int src_stride_argb, ...@@ -1372,7 +1372,7 @@ int ARGBColorMatrix(const uint8* src_argb, int src_stride_argb,
// Apply a 4x3 matrix to each ARGB pixel. // Apply a 4x3 matrix to each ARGB pixel.
// Deprecated. // Deprecated.
LIBYUV_API SAFEBUFFERS LIBYUV_API
int RGBColorMatrix(uint8* dst_argb, int dst_stride_argb, int RGBColorMatrix(uint8* dst_argb, int dst_stride_argb,
const int8* matrix_rgb, const int8* matrix_rgb,
int dst_x, int dst_y, int width, int height) { int dst_x, int dst_y, int width, int height) {
...@@ -1837,13 +1837,12 @@ int ARGBShuffle(const uint8* src_bgra, int src_stride_bgra, ...@@ -1837,13 +1837,12 @@ int ARGBShuffle(const uint8* src_bgra, int src_stride_bgra,
} }
// Sobel ARGB effect. // Sobel ARGB effect.
static SAFEBUFFERS static int ARGBSobelize(const uint8* src_argb, int src_stride_argb,
int ARGBSobelize(const uint8* src_argb, int src_stride_argb, uint8* dst_argb, int dst_stride_argb,
uint8* dst_argb, int dst_stride_argb, int width, int height,
int width, int height, void (*SobelRow)(const uint8* src_sobelx,
void (*SobelRow)(const uint8* src_sobelx, const uint8* src_sobely,
const uint8* src_sobely, uint8* dst, int width)) {
uint8* dst, int width)) {
const int kEdge = 16; // Extra pixels at start of row for extrude/align. const int kEdge = 16; // Extra pixels at start of row for extrude/align.
if (!src_argb || !dst_argb || width <= 0 || height == 0) { if (!src_argb || !dst_argb || width <= 0 || height == 0) {
return -1; return -1;
......
...@@ -867,7 +867,7 @@ void RotatePlane270(const uint8* src, int src_stride, ...@@ -867,7 +867,7 @@ void RotatePlane270(const uint8* src, int src_stride,
TransposePlane(src, src_stride, dst, dst_stride, width, height); TransposePlane(src, src_stride, dst, dst_stride, width, height);
} }
LIBYUV_API SAFEBUFFERS LIBYUV_API
void RotatePlane180(const uint8* src, int src_stride, void RotatePlane180(const uint8* src, int src_stride,
uint8* dst, int dst_stride, uint8* dst, int dst_stride,
int width, int height) { int width, int height) {
......
...@@ -1943,18 +1943,9 @@ void I422ToUYVYRow_C(const uint8* src_y, ...@@ -1943,18 +1943,9 @@ void I422ToUYVYRow_C(const uint8* src_y,
} }
} }
// TODO(fbarchard): Ensure these are stack safe.
#ifdef DEBUG
#define MAYBE_SAFEBUFFERS
#else
#define MAYBE_SAFEBUFFERS SAFEBUFFERS
#endif
#if !defined(LIBYUV_DISABLE_X86) && defined(HAS_I422TOARGBROW_SSSE3) #if !defined(LIBYUV_DISABLE_X86) && defined(HAS_I422TOARGBROW_SSSE3)
// row_win.cc has asm version, but GCC uses 2 step wrapper. // row_win.cc has asm version, but GCC uses 2 step wrapper.
#if defined(__x86_64__) || defined(__i386__) #if defined(__x86_64__) || defined(__i386__)
MAYBE_SAFEBUFFERS
void I422ToRGB565Row_SSSE3(const uint8* src_y, void I422ToRGB565Row_SSSE3(const uint8* src_y,
const uint8* src_u, const uint8* src_u,
const uint8* src_v, const uint8* src_v,
...@@ -1969,7 +1960,6 @@ void I422ToRGB565Row_SSSE3(const uint8* src_y, ...@@ -1969,7 +1960,6 @@ void I422ToRGB565Row_SSSE3(const uint8* src_y,
#endif // defined(__x86_64__) || defined(__i386__) #endif // defined(__x86_64__) || defined(__i386__)
#if defined(_M_IX86) || defined(__x86_64__) || defined(__i386__) #if defined(_M_IX86) || defined(__x86_64__) || defined(__i386__)
MAYBE_SAFEBUFFERS
void I422ToARGB1555Row_SSSE3(const uint8* src_y, void I422ToARGB1555Row_SSSE3(const uint8* src_y,
const uint8* src_u, const uint8* src_u,
const uint8* src_v, const uint8* src_v,
...@@ -1982,7 +1972,6 @@ void I422ToARGB1555Row_SSSE3(const uint8* src_y, ...@@ -1982,7 +1972,6 @@ void I422ToARGB1555Row_SSSE3(const uint8* src_y,
free_aligned_buffer_64(row); free_aligned_buffer_64(row);
} }
MAYBE_SAFEBUFFERS
void I422ToARGB4444Row_SSSE3(const uint8* src_y, void I422ToARGB4444Row_SSSE3(const uint8* src_y,
const uint8* src_u, const uint8* src_u,
const uint8* src_v, const uint8* src_v,
...@@ -1995,7 +1984,6 @@ void I422ToARGB4444Row_SSSE3(const uint8* src_y, ...@@ -1995,7 +1984,6 @@ void I422ToARGB4444Row_SSSE3(const uint8* src_y,
free_aligned_buffer_64(row); free_aligned_buffer_64(row);
} }
MAYBE_SAFEBUFFERS
void NV12ToRGB565Row_SSSE3(const uint8* src_y, void NV12ToRGB565Row_SSSE3(const uint8* src_y,
const uint8* src_uv, const uint8* src_uv,
uint8* dst_rgb565, uint8* dst_rgb565,
...@@ -2007,7 +1995,6 @@ void NV12ToRGB565Row_SSSE3(const uint8* src_y, ...@@ -2007,7 +1995,6 @@ void NV12ToRGB565Row_SSSE3(const uint8* src_y,
free_aligned_buffer_64(row); free_aligned_buffer_64(row);
} }
MAYBE_SAFEBUFFERS
void NV21ToRGB565Row_SSSE3(const uint8* src_y, void NV21ToRGB565Row_SSSE3(const uint8* src_y,
const uint8* src_vu, const uint8* src_vu,
uint8* dst_rgb565, uint8* dst_rgb565,
...@@ -2019,7 +2006,6 @@ void NV21ToRGB565Row_SSSE3(const uint8* src_y, ...@@ -2019,7 +2006,6 @@ void NV21ToRGB565Row_SSSE3(const uint8* src_y,
free_aligned_buffer_64(row); free_aligned_buffer_64(row);
} }
MAYBE_SAFEBUFFERS
void YUY2ToARGBRow_SSSE3(const uint8* src_yuy2, void YUY2ToARGBRow_SSSE3(const uint8* src_yuy2,
uint8* dst_argb, uint8* dst_argb,
int width) { int width) {
...@@ -2035,7 +2021,6 @@ void YUY2ToARGBRow_SSSE3(const uint8* src_yuy2, ...@@ -2035,7 +2021,6 @@ void YUY2ToARGBRow_SSSE3(const uint8* src_yuy2,
free_aligned_buffer_64(row_v); free_aligned_buffer_64(row_v);
} }
MAYBE_SAFEBUFFERS
void YUY2ToARGBRow_Unaligned_SSSE3(const uint8* src_yuy2, void YUY2ToARGBRow_Unaligned_SSSE3(const uint8* src_yuy2,
uint8* dst_argb, uint8* dst_argb,
int width) { int width) {
...@@ -2051,7 +2036,6 @@ void YUY2ToARGBRow_Unaligned_SSSE3(const uint8* src_yuy2, ...@@ -2051,7 +2036,6 @@ void YUY2ToARGBRow_Unaligned_SSSE3(const uint8* src_yuy2,
free_aligned_buffer_64(row_v); free_aligned_buffer_64(row_v);
} }
MAYBE_SAFEBUFFERS
void UYVYToARGBRow_SSSE3(const uint8* src_uyvy, void UYVYToARGBRow_SSSE3(const uint8* src_uyvy,
uint8* dst_argb, uint8* dst_argb,
int width) { int width) {
...@@ -2067,7 +2051,6 @@ void UYVYToARGBRow_SSSE3(const uint8* src_uyvy, ...@@ -2067,7 +2051,6 @@ void UYVYToARGBRow_SSSE3(const uint8* src_uyvy,
free_aligned_buffer_64(row_v); free_aligned_buffer_64(row_v);
} }
MAYBE_SAFEBUFFERS
void UYVYToARGBRow_Unaligned_SSSE3(const uint8* src_uyvy, void UYVYToARGBRow_Unaligned_SSSE3(const uint8* src_uyvy,
uint8* dst_argb, uint8* dst_argb,
int width) { int width) {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment