You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

486 lines
15KB

  1. /*
  2. * Misc image conversion routines
  3. * Copyright (c) 2001, 2002, 2003 Fabrice Bellard
  4. *
  5. * This file is part of FFmpeg.
  6. *
  7. * FFmpeg is free software; you can redistribute it and/or
  8. * modify it under the terms of the GNU Lesser General Public
  9. * License as published by the Free Software Foundation; either
  10. * version 2.1 of the License, or (at your option) any later version.
  11. *
  12. * FFmpeg is distributed in the hope that it will be useful,
  13. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  15. * Lesser General Public License for more details.
  16. *
  17. * You should have received a copy of the GNU Lesser General Public
  18. * License along with FFmpeg; if not, write to the Free Software
  19. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  20. */
  21. /**
  22. * @file
  23. * misc image conversion routines
  24. */
  25. /* TODO:
  26. * - write 'ffimg' program to test all the image related stuff
  27. * - move all api to slice based system
  28. * - integrate deinterlacing, postprocessing and scaling in the conversion process
  29. */
  30. #include "avcodec.h"
  31. #include "imgconvert.h"
  32. #include "internal.h"
  33. #include "mathops.h"
  34. #include "libavutil/avassert.h"
  35. #include "libavutil/colorspace.h"
  36. #include "libavutil/common.h"
  37. #include "libavutil/pixdesc.h"
  38. #include "libavutil/imgutils.h"
  39. void avcodec_get_chroma_sub_sample(enum AVPixelFormat pix_fmt, int *h_shift, int *v_shift)
  40. {
  41. const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(pix_fmt);
  42. av_assert0(desc);
  43. *h_shift = desc->log2_chroma_w;
  44. *v_shift = desc->log2_chroma_h;
  45. }
  46. int avcodec_get_pix_fmt_loss(enum AVPixelFormat dst_pix_fmt,
  47. enum AVPixelFormat src_pix_fmt,
  48. int has_alpha)
  49. {
  50. return av_get_pix_fmt_loss(dst_pix_fmt, src_pix_fmt, has_alpha);
  51. }
  52. enum AVPixelFormat avcodec_find_best_pix_fmt_of_2(enum AVPixelFormat dst_pix_fmt1, enum AVPixelFormat dst_pix_fmt2,
  53. enum AVPixelFormat src_pix_fmt, int has_alpha, int *loss_ptr)
  54. {
  55. return av_find_best_pix_fmt_of_2(dst_pix_fmt1, dst_pix_fmt2, src_pix_fmt, has_alpha, loss_ptr);
  56. }
  57. #if AV_HAVE_INCOMPATIBLE_LIBAV_ABI
  58. enum AVPixelFormat avcodec_find_best_pix_fmt2(const enum AVPixelFormat *pix_fmt_list,
  59. enum AVPixelFormat src_pix_fmt,
  60. int has_alpha, int *loss_ptr){
  61. return avcodec_find_best_pix_fmt_of_list(pix_fmt_list, src_pix_fmt, has_alpha, loss_ptr);
  62. }
  63. #else
  64. enum AVPixelFormat avcodec_find_best_pix_fmt2(enum AVPixelFormat dst_pix_fmt1, enum AVPixelFormat dst_pix_fmt2,
  65. enum AVPixelFormat src_pix_fmt, int has_alpha, int *loss_ptr)
  66. {
  67. return avcodec_find_best_pix_fmt_of_2(dst_pix_fmt1, dst_pix_fmt2, src_pix_fmt, has_alpha, loss_ptr);
  68. }
  69. #endif
  70. enum AVPixelFormat avcodec_find_best_pix_fmt_of_list(const enum AVPixelFormat *pix_fmt_list,
  71. enum AVPixelFormat src_pix_fmt,
  72. int has_alpha, int *loss_ptr){
  73. int i;
  74. enum AVPixelFormat best = AV_PIX_FMT_NONE;
  75. for(i=0; pix_fmt_list[i] != AV_PIX_FMT_NONE; i++)
  76. best = avcodec_find_best_pix_fmt_of_2(best, pix_fmt_list[i], src_pix_fmt, has_alpha, loss_ptr);
  77. return best;
  78. }
  79. /* 2x2 -> 1x1 */
  80. void ff_shrink22(uint8_t *dst, int dst_wrap,
  81. const uint8_t *src, int src_wrap,
  82. int width, int height)
  83. {
  84. int w;
  85. const uint8_t *s1, *s2;
  86. uint8_t *d;
  87. for(;height > 0; height--) {
  88. s1 = src;
  89. s2 = s1 + src_wrap;
  90. d = dst;
  91. for(w = width;w >= 4; w-=4) {
  92. d[0] = (s1[0] + s1[1] + s2[0] + s2[1] + 2) >> 2;
  93. d[1] = (s1[2] + s1[3] + s2[2] + s2[3] + 2) >> 2;
  94. d[2] = (s1[4] + s1[5] + s2[4] + s2[5] + 2) >> 2;
  95. d[3] = (s1[6] + s1[7] + s2[6] + s2[7] + 2) >> 2;
  96. s1 += 8;
  97. s2 += 8;
  98. d += 4;
  99. }
  100. for(;w > 0; w--) {
  101. d[0] = (s1[0] + s1[1] + s2[0] + s2[1] + 2) >> 2;
  102. s1 += 2;
  103. s2 += 2;
  104. d++;
  105. }
  106. src += 2 * src_wrap;
  107. dst += dst_wrap;
  108. }
  109. }
  110. /* 4x4 -> 1x1 */
  111. void ff_shrink44(uint8_t *dst, int dst_wrap,
  112. const uint8_t *src, int src_wrap,
  113. int width, int height)
  114. {
  115. int w;
  116. const uint8_t *s1, *s2, *s3, *s4;
  117. uint8_t *d;
  118. for(;height > 0; height--) {
  119. s1 = src;
  120. s2 = s1 + src_wrap;
  121. s3 = s2 + src_wrap;
  122. s4 = s3 + src_wrap;
  123. d = dst;
  124. for(w = width;w > 0; w--) {
  125. d[0] = (s1[0] + s1[1] + s1[2] + s1[3] +
  126. s2[0] + s2[1] + s2[2] + s2[3] +
  127. s3[0] + s3[1] + s3[2] + s3[3] +
  128. s4[0] + s4[1] + s4[2] + s4[3] + 8) >> 4;
  129. s1 += 4;
  130. s2 += 4;
  131. s3 += 4;
  132. s4 += 4;
  133. d++;
  134. }
  135. src += 4 * src_wrap;
  136. dst += dst_wrap;
  137. }
  138. }
  139. /* 8x8 -> 1x1 */
  140. void ff_shrink88(uint8_t *dst, int dst_wrap,
  141. const uint8_t *src, int src_wrap,
  142. int width, int height)
  143. {
  144. int w, i;
  145. for(;height > 0; height--) {
  146. for(w = width;w > 0; w--) {
  147. int tmp=0;
  148. for(i=0; i<8; i++){
  149. tmp += src[0] + src[1] + src[2] + src[3] + src[4] + src[5] + src[6] + src[7];
  150. src += src_wrap;
  151. }
  152. *(dst++) = (tmp + 32)>>6;
  153. src += 8 - 8*src_wrap;
  154. }
  155. src += 8*src_wrap - 8*width;
  156. dst += dst_wrap - width;
  157. }
  158. }
  159. /* return true if yuv planar */
  160. static inline int is_yuv_planar(const AVPixFmtDescriptor *desc)
  161. {
  162. int i;
  163. int planes[4] = { 0 };
  164. if ( desc->flags & AV_PIX_FMT_FLAG_RGB
  165. || !(desc->flags & AV_PIX_FMT_FLAG_PLANAR))
  166. return 0;
  167. /* set the used planes */
  168. for (i = 0; i < desc->nb_components; i++)
  169. planes[desc->comp[i].plane] = 1;
  170. /* if there is an unused plane, the format is not planar */
  171. for (i = 0; i < desc->nb_components; i++)
  172. if (!planes[i])
  173. return 0;
  174. return 1;
  175. }
  176. int av_picture_crop(AVPicture *dst, const AVPicture *src,
  177. enum AVPixelFormat pix_fmt, int top_band, int left_band)
  178. {
  179. const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(pix_fmt);
  180. int y_shift;
  181. int x_shift;
  182. if (pix_fmt < 0 || pix_fmt >= AV_PIX_FMT_NB)
  183. return -1;
  184. y_shift = desc->log2_chroma_h;
  185. x_shift = desc->log2_chroma_w;
  186. if (is_yuv_planar(desc)) {
  187. dst->data[0] = src->data[0] + (top_band * src->linesize[0]) + left_band;
  188. dst->data[1] = src->data[1] + ((top_band >> y_shift) * src->linesize[1]) + (left_band >> x_shift);
  189. dst->data[2] = src->data[2] + ((top_band >> y_shift) * src->linesize[2]) + (left_band >> x_shift);
  190. } else{
  191. if(top_band % (1<<y_shift) || left_band % (1<<x_shift))
  192. return -1;
  193. if(left_band) //FIXME add support for this too
  194. return -1;
  195. dst->data[0] = src->data[0] + (top_band * src->linesize[0]) + left_band;
  196. }
  197. dst->linesize[0] = src->linesize[0];
  198. dst->linesize[1] = src->linesize[1];
  199. dst->linesize[2] = src->linesize[2];
  200. return 0;
  201. }
  202. int av_picture_pad(AVPicture *dst, const AVPicture *src, int height, int width,
  203. enum AVPixelFormat pix_fmt, int padtop, int padbottom, int padleft, int padright,
  204. int *color)
  205. {
  206. const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(pix_fmt);
  207. uint8_t *optr;
  208. int y_shift;
  209. int x_shift;
  210. int yheight;
  211. int i, y;
  212. if (pix_fmt < 0 || pix_fmt >= AV_PIX_FMT_NB ||
  213. !is_yuv_planar(desc)) return -1;
  214. for (i = 0; i < 3; i++) {
  215. x_shift = i ? desc->log2_chroma_w : 0;
  216. y_shift = i ? desc->log2_chroma_h : 0;
  217. if (padtop || padleft) {
  218. memset(dst->data[i], color[i],
  219. dst->linesize[i] * (padtop >> y_shift) + (padleft >> x_shift));
  220. }
  221. if (padleft || padright) {
  222. optr = dst->data[i] + dst->linesize[i] * (padtop >> y_shift) +
  223. (dst->linesize[i] - (padright >> x_shift));
  224. yheight = (height - 1 - (padtop + padbottom)) >> y_shift;
  225. for (y = 0; y < yheight; y++) {
  226. memset(optr, color[i], (padleft + padright) >> x_shift);
  227. optr += dst->linesize[i];
  228. }
  229. }
  230. if (src) { /* first line */
  231. uint8_t *iptr = src->data[i];
  232. optr = dst->data[i] + dst->linesize[i] * (padtop >> y_shift) +
  233. (padleft >> x_shift);
  234. memcpy(optr, iptr, (width - padleft - padright) >> x_shift);
  235. iptr += src->linesize[i];
  236. optr = dst->data[i] + dst->linesize[i] * (padtop >> y_shift) +
  237. (dst->linesize[i] - (padright >> x_shift));
  238. yheight = (height - 1 - (padtop + padbottom)) >> y_shift;
  239. for (y = 0; y < yheight; y++) {
  240. memset(optr, color[i], (padleft + padright) >> x_shift);
  241. memcpy(optr + ((padleft + padright) >> x_shift), iptr,
  242. (width - padleft - padright) >> x_shift);
  243. iptr += src->linesize[i];
  244. optr += dst->linesize[i];
  245. }
  246. }
  247. if (padbottom || padright) {
  248. optr = dst->data[i] + dst->linesize[i] *
  249. ((height - padbottom) >> y_shift) - (padright >> x_shift);
  250. memset(optr, color[i],dst->linesize[i] *
  251. (padbottom >> y_shift) + (padright >> x_shift));
  252. }
  253. }
  254. return 0;
  255. }
  256. #if FF_API_DEINTERLACE
  257. #if HAVE_MMX_EXTERNAL
  258. #define deinterlace_line_inplace ff_deinterlace_line_inplace_mmx
  259. #define deinterlace_line ff_deinterlace_line_mmx
  260. #else
  261. #define deinterlace_line_inplace deinterlace_line_inplace_c
  262. #define deinterlace_line deinterlace_line_c
  263. /* filter parameters: [-1 4 2 4 -1] // 8 */
  264. static void deinterlace_line_c(uint8_t *dst,
  265. const uint8_t *lum_m4, const uint8_t *lum_m3,
  266. const uint8_t *lum_m2, const uint8_t *lum_m1,
  267. const uint8_t *lum,
  268. int size)
  269. {
  270. const uint8_t *cm = ff_crop_tab + MAX_NEG_CROP;
  271. int sum;
  272. for(;size > 0;size--) {
  273. sum = -lum_m4[0];
  274. sum += lum_m3[0] << 2;
  275. sum += lum_m2[0] << 1;
  276. sum += lum_m1[0] << 2;
  277. sum += -lum[0];
  278. dst[0] = cm[(sum + 4) >> 3];
  279. lum_m4++;
  280. lum_m3++;
  281. lum_m2++;
  282. lum_m1++;
  283. lum++;
  284. dst++;
  285. }
  286. }
  287. static void deinterlace_line_inplace_c(uint8_t *lum_m4, uint8_t *lum_m3,
  288. uint8_t *lum_m2, uint8_t *lum_m1,
  289. uint8_t *lum, int size)
  290. {
  291. const uint8_t *cm = ff_crop_tab + MAX_NEG_CROP;
  292. int sum;
  293. for(;size > 0;size--) {
  294. sum = -lum_m4[0];
  295. sum += lum_m3[0] << 2;
  296. sum += lum_m2[0] << 1;
  297. lum_m4[0]=lum_m2[0];
  298. sum += lum_m1[0] << 2;
  299. sum += -lum[0];
  300. lum_m2[0] = cm[(sum + 4) >> 3];
  301. lum_m4++;
  302. lum_m3++;
  303. lum_m2++;
  304. lum_m1++;
  305. lum++;
  306. }
  307. }
  308. #endif /* !HAVE_MMX_EXTERNAL */
  309. /* deinterlacing : 2 temporal taps, 3 spatial taps linear filter. The
  310. top field is copied as is, but the bottom field is deinterlaced
  311. against the top field. */
  312. static void deinterlace_bottom_field(uint8_t *dst, int dst_wrap,
  313. const uint8_t *src1, int src_wrap,
  314. int width, int height)
  315. {
  316. const uint8_t *src_m2, *src_m1, *src_0, *src_p1, *src_p2;
  317. int y;
  318. src_m2 = src1;
  319. src_m1 = src1;
  320. src_0=&src_m1[src_wrap];
  321. src_p1=&src_0[src_wrap];
  322. src_p2=&src_p1[src_wrap];
  323. for(y=0;y<(height-2);y+=2) {
  324. memcpy(dst,src_m1,width);
  325. dst += dst_wrap;
  326. deinterlace_line(dst,src_m2,src_m1,src_0,src_p1,src_p2,width);
  327. src_m2 = src_0;
  328. src_m1 = src_p1;
  329. src_0 = src_p2;
  330. src_p1 += 2*src_wrap;
  331. src_p2 += 2*src_wrap;
  332. dst += dst_wrap;
  333. }
  334. memcpy(dst,src_m1,width);
  335. dst += dst_wrap;
  336. /* do last line */
  337. deinterlace_line(dst,src_m2,src_m1,src_0,src_0,src_0,width);
  338. }
  339. static void deinterlace_bottom_field_inplace(uint8_t *src1, int src_wrap,
  340. int width, int height)
  341. {
  342. uint8_t *src_m1, *src_0, *src_p1, *src_p2;
  343. int y;
  344. uint8_t *buf;
  345. buf = av_malloc(width);
  346. src_m1 = src1;
  347. memcpy(buf,src_m1,width);
  348. src_0=&src_m1[src_wrap];
  349. src_p1=&src_0[src_wrap];
  350. src_p2=&src_p1[src_wrap];
  351. for(y=0;y<(height-2);y+=2) {
  352. deinterlace_line_inplace(buf,src_m1,src_0,src_p1,src_p2,width);
  353. src_m1 = src_p1;
  354. src_0 = src_p2;
  355. src_p1 += 2*src_wrap;
  356. src_p2 += 2*src_wrap;
  357. }
  358. /* do last line */
  359. deinterlace_line_inplace(buf,src_m1,src_0,src_0,src_0,width);
  360. av_free(buf);
  361. }
  362. int avpicture_deinterlace(AVPicture *dst, const AVPicture *src,
  363. enum AVPixelFormat pix_fmt, int width, int height)
  364. {
  365. int i;
  366. if (pix_fmt != AV_PIX_FMT_YUV420P &&
  367. pix_fmt != AV_PIX_FMT_YUVJ420P &&
  368. pix_fmt != AV_PIX_FMT_YUV422P &&
  369. pix_fmt != AV_PIX_FMT_YUVJ422P &&
  370. pix_fmt != AV_PIX_FMT_YUV444P &&
  371. pix_fmt != AV_PIX_FMT_YUV411P &&
  372. pix_fmt != AV_PIX_FMT_GRAY8)
  373. return -1;
  374. if ((width & 3) != 0 || (height & 3) != 0)
  375. return -1;
  376. for(i=0;i<3;i++) {
  377. if (i == 1) {
  378. switch(pix_fmt) {
  379. case AV_PIX_FMT_YUVJ420P:
  380. case AV_PIX_FMT_YUV420P:
  381. width >>= 1;
  382. height >>= 1;
  383. break;
  384. case AV_PIX_FMT_YUV422P:
  385. case AV_PIX_FMT_YUVJ422P:
  386. width >>= 1;
  387. break;
  388. case AV_PIX_FMT_YUV411P:
  389. width >>= 2;
  390. break;
  391. default:
  392. break;
  393. }
  394. if (pix_fmt == AV_PIX_FMT_GRAY8) {
  395. break;
  396. }
  397. }
  398. if (src == dst) {
  399. deinterlace_bottom_field_inplace(dst->data[i], dst->linesize[i],
  400. width, height);
  401. } else {
  402. deinterlace_bottom_field(dst->data[i],dst->linesize[i],
  403. src->data[i], src->linesize[i],
  404. width, height);
  405. }
  406. }
  407. emms_c();
  408. return 0;
  409. }
  410. #endif /* FF_API_DEINTERLACE */
  411. #ifdef TEST
  412. int main(void){
  413. int i;
  414. int err=0;
  415. int skip = 0;
  416. for (i=0; i<AV_PIX_FMT_NB*2; i++) {
  417. const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(i);
  418. if(!desc || !desc->name) {
  419. skip ++;
  420. continue;
  421. }
  422. if (skip) {
  423. av_log(NULL, AV_LOG_INFO, "%3d unused pixel format values\n", skip);
  424. skip = 0;
  425. }
  426. av_log(NULL, AV_LOG_INFO, "pix fmt %s yuv_plan:%d avg_bpp:%d\n", desc->name, is_yuv_planar(desc), av_get_padded_bits_per_pixel(desc));
  427. if ((!(desc->flags & AV_PIX_FMT_FLAG_ALPHA)) != (desc->nb_components != 2 && desc->nb_components != 4)) {
  428. av_log(NULL, AV_LOG_ERROR, "Alpha flag mismatch\n");
  429. err = 1;
  430. }
  431. }
  432. return err;
  433. }
  434. #endif