tiny-nv12-scale.c 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200
  1. #include <string.h>
  2. #include "tiny-nv12-scale.h"
  3. /* TODO: optimize this stuff later, or replace with something better. it's
  4. * kind of garbage. although normally it shouldn't be called that often. plus
  5. * it's nearest neighbor so not really a huge deal. at the very least it
  6. * should be sse2 at some point. */
  7. void nv12_scale_init(nv12_scale_t *s, enum target_format format, int dst_cx, int dst_cy, int src_cx, int src_cy)
  8. {
  9. s->format = format;
  10. s->src_cx = src_cx;
  11. s->src_cy = src_cy;
  12. s->dst_cx = dst_cx;
  13. s->dst_cy = dst_cy;
  14. }
  15. static void nv12_scale_nearest(nv12_scale_t *s, uint8_t *dst_start, const uint8_t *src)
  16. {
  17. register uint8_t *dst = dst_start;
  18. const int src_cx = s->src_cx;
  19. const int src_cy = s->src_cy;
  20. const int dst_cx = s->dst_cx;
  21. const int dst_cy = s->dst_cy;
  22. /* lum */
  23. for (int y = 0; y < dst_cy; y++) {
  24. const int src_line = y * src_cy / dst_cy * s->src_cx;
  25. for (int x = 0; x < dst_cx; x++) {
  26. const int src_x = x * src_cx / dst_cx;
  27. *(dst++) = src[src_line + src_x];
  28. }
  29. }
  30. src += src_cx * src_cy;
  31. /* uv */
  32. const int dst_cx_d2 = dst_cx / 2;
  33. const int dst_cy_d2 = dst_cy / 2;
  34. for (int y = 0; y < dst_cy_d2; y++) {
  35. const int src_line = y * src_cy / dst_cy * src_cx;
  36. for (int x = 0; x < dst_cx_d2; x++) {
  37. const int src_x = x * src_cx / dst_cx * 2;
  38. const int pos = src_line + src_x;
  39. *(dst++) = src[pos];
  40. *(dst++) = src[pos + 1];
  41. }
  42. }
  43. }
  44. static void nv12_scale_nearest_to_i420(nv12_scale_t *s, uint8_t *dst_start, const uint8_t *src)
  45. {
  46. register uint8_t *dst = dst_start;
  47. const int src_cx = s->src_cx;
  48. const int src_cy = s->src_cy;
  49. const int dst_cx = s->dst_cx;
  50. const int dst_cy = s->dst_cy;
  51. const int size = src_cx * src_cy;
  52. /* lum */
  53. for (int y = 0; y < dst_cy; y++) {
  54. const int src_line = y * src_cy / dst_cy * s->src_cx;
  55. for (int x = 0; x < dst_cx; x++) {
  56. const int src_x = x * src_cx / dst_cx;
  57. *(dst++) = src[src_line + src_x];
  58. }
  59. }
  60. src += size;
  61. /* uv */
  62. const int dst_cx_d2 = dst_cx / 2;
  63. const int dst_cy_d2 = dst_cy / 2;
  64. register uint8_t *dst2 = dst + dst_cx * dst_cy / 4;
  65. for (int y = 0; y < dst_cy_d2; y++) {
  66. const int src_line = y * src_cy / dst_cy * src_cx;
  67. for (int x = 0; x < dst_cx_d2; x++) {
  68. const int src_x = x * src_cx / dst_cx * 2;
  69. const int pos = src_line + src_x;
  70. *(dst++) = src[pos];
  71. *(dst2++) = src[pos + 1];
  72. }
  73. }
  74. }
  75. static void nv12_convert_to_i420(nv12_scale_t *s, uint8_t *dst_start, const uint8_t *src_start)
  76. {
  77. const int size = s->src_cx * s->src_cy;
  78. const int size_d4 = size / 4;
  79. memcpy(dst_start, src_start, size);
  80. register uint8_t *dst1 = dst_start + size;
  81. register uint8_t *dst2 = dst1 + size_d4;
  82. register uint8_t *dst_end = dst2 + size_d4;
  83. register const uint8_t *src = src_start + size;
  84. while (dst2 < dst_end) {
  85. *(dst1++) = *(src++);
  86. *(dst2++) = *(src++);
  87. }
  88. }
  89. static void nv12_scale_nearest_to_yuy2(nv12_scale_t *s, uint8_t *dst_start, const uint8_t *src)
  90. {
  91. register uint8_t *dst = dst_start;
  92. const int src_cx = s->src_cx;
  93. const int src_cy = s->src_cy;
  94. const int dst_cx = s->dst_cx;
  95. const int dst_cy = s->dst_cy;
  96. const int src_cx_d2 = src_cx / 2;
  97. const int src_cy_d2 = src_cy / 2;
  98. const int dst_cx_d2 = dst_cx / 2;
  99. const int dst_cy_d2 = dst_cy / 2;
  100. const int size = src_cx * src_cy;
  101. const uint8_t *src_uv = src + size;
  102. register int uv_flip = 0;
  103. for (int y = 0; y < dst_cy; y++) {
  104. const int src_line = y * src_cy / dst_cy * s->src_cx;
  105. const int src_line_d2 = y / 2 * src_cy_d2 / dst_cy_d2 * s->src_cx;
  106. for (int x = 0; x < dst_cx; x++) {
  107. const int src_x = x * src_cx / dst_cx;
  108. const int src_x_d2 = x / 2 * src_cx_d2 / dst_cx_d2;
  109. const int pos = src_line + src_x;
  110. const int pos_uv = src_line_d2 + src_x_d2 * 2 + uv_flip;
  111. *(dst++) = src[pos];
  112. *(dst++) = src_uv[pos_uv];
  113. uv_flip ^= 1;
  114. }
  115. }
  116. }
  117. static void nv12_convert_to_yuy2(nv12_scale_t *s, uint8_t *dst_start, const uint8_t *src_start)
  118. {
  119. const int size = s->src_cx * s->src_cy;
  120. const int size_dst_line = s->src_cx * 2;
  121. register const uint8_t *src_y = src_start;
  122. register const uint8_t *src_uv = src_y + size;
  123. register uint8_t *dst = dst_start;
  124. register uint8_t *dst_end = dst + size * 2;
  125. while (dst < dst_end) {
  126. register uint8_t *dst_line_end = dst + size_dst_line;
  127. const uint8_t *src_uv_start = src_uv;
  128. while (dst < dst_line_end) {
  129. *(dst++) = *(src_y++);
  130. *(dst++) = *(src_uv++);
  131. *(dst++) = *(src_y++);
  132. *(dst++) = *(src_uv++);
  133. }
  134. dst_line_end = dst + size_dst_line;
  135. src_uv = src_uv_start;
  136. while (dst < dst_line_end) {
  137. *(dst++) = *(src_y++);
  138. *(dst++) = *(src_uv++);
  139. *(dst++) = *(src_y++);
  140. *(dst++) = *(src_uv++);
  141. }
  142. }
  143. }
  144. void nv12_do_scale(nv12_scale_t *s, uint8_t *dst, const uint8_t *src)
  145. {
  146. if (s->src_cx == s->dst_cx && s->src_cy == s->dst_cy) {
  147. if (s->format == TARGET_FORMAT_I420)
  148. nv12_convert_to_i420(s, dst, src);
  149. else if (s->format == TARGET_FORMAT_YUY2)
  150. nv12_convert_to_yuy2(s, dst, src);
  151. else
  152. memcpy(dst, src, s->src_cx * s->src_cy * 3 / 2);
  153. } else {
  154. if (s->format == TARGET_FORMAT_I420)
  155. nv12_scale_nearest_to_i420(s, dst, src);
  156. else if (s->format == TARGET_FORMAT_YUY2)
  157. nv12_scale_nearest_to_yuy2(s, dst, src);
  158. else
  159. nv12_scale_nearest(s, dst, src);
  160. }
  161. }