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.

525 lines
16KB

  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. int max_step[4];
  183. if (pix_fmt < 0 || pix_fmt >= AV_PIX_FMT_NB)
  184. return -1;
  185. y_shift = desc->log2_chroma_h;
  186. x_shift = desc->log2_chroma_w;
  187. av_image_fill_max_pixsteps(max_step, NULL, desc);
  188. if (is_yuv_planar(desc)) {
  189. dst->data[0] = src->data[0] + (top_band * src->linesize[0]) + left_band;
  190. dst->data[1] = src->data[1] + ((top_band >> y_shift) * src->linesize[1]) + (left_band >> x_shift);
  191. dst->data[2] = src->data[2] + ((top_band >> y_shift) * src->linesize[2]) + (left_band >> x_shift);
  192. } else{
  193. if(top_band % (1<<y_shift) || left_band % (1<<x_shift))
  194. return -1;
  195. dst->data[0] = src->data[0] + (top_band * src->linesize[0]) + (left_band * max_step[0]);
  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. int max_step[4];
  213. if (pix_fmt < 0 || pix_fmt >= AV_PIX_FMT_NB)
  214. return -1;
  215. if (!is_yuv_planar(desc)) {
  216. if (src)
  217. return -1; //TODO: Not yet implemented
  218. av_image_fill_max_pixsteps(max_step, NULL, desc);
  219. if (padtop || padleft) {
  220. memset(dst->data[0], color[0],
  221. dst->linesize[0] * padtop + (padleft * max_step[0]));
  222. }
  223. if (padleft || padright) {
  224. optr = dst->data[0] + dst->linesize[0] * padtop +
  225. (dst->linesize[0] - (padright * max_step[0]));
  226. yheight = height - 1 - (padtop + padbottom);
  227. for (y = 0; y < yheight; y++) {
  228. memset(optr, color[0], (padleft + padright) * max_step[0]);
  229. optr += dst->linesize[0];
  230. }
  231. }
  232. if (padbottom || padright) {
  233. optr = dst->data[0] + dst->linesize[0] * (height - padbottom) -
  234. (padright * max_step[0]);
  235. memset(optr, color[0], dst->linesize[0] * padbottom +
  236. (padright * max_step[0]));
  237. }
  238. return 0;
  239. }
  240. for (i = 0; i < 3; i++) {
  241. x_shift = i ? desc->log2_chroma_w : 0;
  242. y_shift = i ? desc->log2_chroma_h : 0;
  243. if (padtop || padleft) {
  244. memset(dst->data[i], color[i],
  245. dst->linesize[i] * (padtop >> y_shift) + (padleft >> x_shift));
  246. }
  247. if (padleft || padright) {
  248. optr = dst->data[i] + dst->linesize[i] * (padtop >> y_shift) +
  249. (dst->linesize[i] - (padright >> x_shift));
  250. yheight = (height - 1 - (padtop + padbottom)) >> y_shift;
  251. for (y = 0; y < yheight; y++) {
  252. memset(optr, color[i], (padleft + padright) >> x_shift);
  253. optr += dst->linesize[i];
  254. }
  255. }
  256. if (src) { /* first line */
  257. uint8_t *iptr = src->data[i];
  258. optr = dst->data[i] + dst->linesize[i] * (padtop >> y_shift) +
  259. (padleft >> x_shift);
  260. memcpy(optr, iptr, (width - padleft - padright) >> x_shift);
  261. iptr += src->linesize[i];
  262. optr = dst->data[i] + dst->linesize[i] * (padtop >> y_shift) +
  263. (dst->linesize[i] - (padright >> x_shift));
  264. yheight = (height - 1 - (padtop + padbottom)) >> y_shift;
  265. for (y = 0; y < yheight; y++) {
  266. memset(optr, color[i], (padleft + padright) >> x_shift);
  267. memcpy(optr + ((padleft + padright) >> x_shift), iptr,
  268. (width - padleft - padright) >> x_shift);
  269. iptr += src->linesize[i];
  270. optr += dst->linesize[i];
  271. }
  272. }
  273. if (padbottom || padright) {
  274. optr = dst->data[i] + dst->linesize[i] *
  275. ((height - padbottom) >> y_shift) - (padright >> x_shift);
  276. memset(optr, color[i],dst->linesize[i] *
  277. (padbottom >> y_shift) + (padright >> x_shift));
  278. }
  279. }
  280. return 0;
  281. }
  282. #if FF_API_DEINTERLACE
  283. #if HAVE_MMX_EXTERNAL
  284. #define deinterlace_line_inplace ff_deinterlace_line_inplace_mmx
  285. #define deinterlace_line ff_deinterlace_line_mmx
  286. #else
  287. #define deinterlace_line_inplace deinterlace_line_inplace_c
  288. #define deinterlace_line deinterlace_line_c
  289. /* filter parameters: [-1 4 2 4 -1] // 8 */
  290. static void deinterlace_line_c(uint8_t *dst,
  291. const uint8_t *lum_m4, const uint8_t *lum_m3,
  292. const uint8_t *lum_m2, const uint8_t *lum_m1,
  293. const uint8_t *lum,
  294. int size)
  295. {
  296. const uint8_t *cm = ff_crop_tab + MAX_NEG_CROP;
  297. int sum;
  298. for(;size > 0;size--) {
  299. sum = -lum_m4[0];
  300. sum += lum_m3[0] << 2;
  301. sum += lum_m2[0] << 1;
  302. sum += lum_m1[0] << 2;
  303. sum += -lum[0];
  304. dst[0] = cm[(sum + 4) >> 3];
  305. lum_m4++;
  306. lum_m3++;
  307. lum_m2++;
  308. lum_m1++;
  309. lum++;
  310. dst++;
  311. }
  312. }
  313. static void deinterlace_line_inplace_c(uint8_t *lum_m4, uint8_t *lum_m3,
  314. uint8_t *lum_m2, uint8_t *lum_m1,
  315. uint8_t *lum, int size)
  316. {
  317. const uint8_t *cm = ff_crop_tab + MAX_NEG_CROP;
  318. int sum;
  319. for(;size > 0;size--) {
  320. sum = -lum_m4[0];
  321. sum += lum_m3[0] << 2;
  322. sum += lum_m2[0] << 1;
  323. lum_m4[0]=lum_m2[0];
  324. sum += lum_m1[0] << 2;
  325. sum += -lum[0];
  326. lum_m2[0] = cm[(sum + 4) >> 3];
  327. lum_m4++;
  328. lum_m3++;
  329. lum_m2++;
  330. lum_m1++;
  331. lum++;
  332. }
  333. }
  334. #endif /* !HAVE_MMX_EXTERNAL */
  335. /* deinterlacing : 2 temporal taps, 3 spatial taps linear filter. The
  336. top field is copied as is, but the bottom field is deinterlaced
  337. against the top field. */
  338. static void deinterlace_bottom_field(uint8_t *dst, int dst_wrap,
  339. const uint8_t *src1, int src_wrap,
  340. int width, int height)
  341. {
  342. const uint8_t *src_m2, *src_m1, *src_0, *src_p1, *src_p2;
  343. int y;
  344. src_m2 = src1;
  345. src_m1 = src1;
  346. src_0=&src_m1[src_wrap];
  347. src_p1=&src_0[src_wrap];
  348. src_p2=&src_p1[src_wrap];
  349. for(y=0;y<(height-2);y+=2) {
  350. memcpy(dst,src_m1,width);
  351. dst += dst_wrap;
  352. deinterlace_line(dst,src_m2,src_m1,src_0,src_p1,src_p2,width);
  353. src_m2 = src_0;
  354. src_m1 = src_p1;
  355. src_0 = src_p2;
  356. src_p1 += 2*src_wrap;
  357. src_p2 += 2*src_wrap;
  358. dst += dst_wrap;
  359. }
  360. memcpy(dst,src_m1,width);
  361. dst += dst_wrap;
  362. /* do last line */
  363. deinterlace_line(dst,src_m2,src_m1,src_0,src_0,src_0,width);
  364. }
  365. static int deinterlace_bottom_field_inplace(uint8_t *src1, int src_wrap,
  366. int width, int height)
  367. {
  368. uint8_t *src_m1, *src_0, *src_p1, *src_p2;
  369. int y;
  370. uint8_t *buf;
  371. buf = av_malloc(width);
  372. if (!buf)
  373. return AVERROR(ENOMEM);
  374. src_m1 = src1;
  375. memcpy(buf,src_m1,width);
  376. src_0=&src_m1[src_wrap];
  377. src_p1=&src_0[src_wrap];
  378. src_p2=&src_p1[src_wrap];
  379. for(y=0;y<(height-2);y+=2) {
  380. deinterlace_line_inplace(buf,src_m1,src_0,src_p1,src_p2,width);
  381. src_m1 = src_p1;
  382. src_0 = src_p2;
  383. src_p1 += 2*src_wrap;
  384. src_p2 += 2*src_wrap;
  385. }
  386. /* do last line */
  387. deinterlace_line_inplace(buf,src_m1,src_0,src_0,src_0,width);
  388. av_free(buf);
  389. return 0;
  390. }
  391. int avpicture_deinterlace(AVPicture *dst, const AVPicture *src,
  392. enum AVPixelFormat pix_fmt, int width, int height)
  393. {
  394. int i, ret;
  395. if (pix_fmt != AV_PIX_FMT_YUV420P &&
  396. pix_fmt != AV_PIX_FMT_YUVJ420P &&
  397. pix_fmt != AV_PIX_FMT_YUV422P &&
  398. pix_fmt != AV_PIX_FMT_YUVJ422P &&
  399. pix_fmt != AV_PIX_FMT_YUV444P &&
  400. pix_fmt != AV_PIX_FMT_YUV411P &&
  401. pix_fmt != AV_PIX_FMT_GRAY8)
  402. return -1;
  403. if ((width & 3) != 0 || (height & 3) != 0)
  404. return -1;
  405. for(i=0;i<3;i++) {
  406. if (i == 1) {
  407. switch(pix_fmt) {
  408. case AV_PIX_FMT_YUVJ420P:
  409. case AV_PIX_FMT_YUV420P:
  410. width >>= 1;
  411. height >>= 1;
  412. break;
  413. case AV_PIX_FMT_YUV422P:
  414. case AV_PIX_FMT_YUVJ422P:
  415. width >>= 1;
  416. break;
  417. case AV_PIX_FMT_YUV411P:
  418. width >>= 2;
  419. break;
  420. default:
  421. break;
  422. }
  423. if (pix_fmt == AV_PIX_FMT_GRAY8) {
  424. break;
  425. }
  426. }
  427. if (src == dst) {
  428. ret = deinterlace_bottom_field_inplace(dst->data[i],
  429. dst->linesize[i],
  430. width, height);
  431. if (ret < 0)
  432. return ret;
  433. } else {
  434. deinterlace_bottom_field(dst->data[i],dst->linesize[i],
  435. src->data[i], src->linesize[i],
  436. width, height);
  437. }
  438. }
  439. emms_c();
  440. return 0;
  441. }
  442. #endif /* FF_API_DEINTERLACE */
  443. #ifdef TEST
  444. int main(void){
  445. int i;
  446. int err=0;
  447. int skip = 0;
  448. for (i=0; i<AV_PIX_FMT_NB*2; i++) {
  449. const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(i);
  450. if(!desc || !desc->name) {
  451. skip ++;
  452. continue;
  453. }
  454. if (skip) {
  455. av_log(NULL, AV_LOG_INFO, "%3d unused pixel format values\n", skip);
  456. skip = 0;
  457. }
  458. 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));
  459. if ((!(desc->flags & AV_PIX_FMT_FLAG_ALPHA)) != (desc->nb_components != 2 && desc->nb_components != 4)) {
  460. av_log(NULL, AV_LOG_ERROR, "Alpha flag mismatch\n");
  461. err = 1;
  462. }
  463. }
  464. return err;
  465. }
  466. #endif