vf_noise.c 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474
  1. /*
  2. * Copyright (C) 2002 Michael Niedermayer <michaelni@gmx.at>
  3. *
  4. * This file is part of MPlayer.
  5. *
  6. * MPlayer is free software; you can redistribute it and/or modify
  7. * it under the terms of the GNU General Public License as published by
  8. * the Free Software Foundation; either version 2 of the License, or
  9. * (at your option) any later version.
  10. *
  11. * MPlayer is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU General Public License along
  17. * with MPlayer; if not, write to the Free Software Foundation, Inc.,
  18. * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  19. */
  20. #include <stdio.h>
  21. #include <stdlib.h>
  22. #include <string.h>
  23. #include <inttypes.h>
  24. #include <math.h>
  25. #include "config.h"
  26. #include "mp_msg.h"
  27. #include "cpudetect.h"
  28. #if HAVE_MALLOC_H
  29. #include <malloc.h>
  30. #endif
  31. #include "img_format.h"
  32. #include "mp_image.h"
  33. #include "vf.h"
  34. #include "libvo/fastmemcpy.h"
  35. #include "libavutil/mem.h"
  36. #define MAX_NOISE 4096
  37. #define MAX_SHIFT 1024
  38. #define MAX_RES (MAX_NOISE-MAX_SHIFT)
  39. //===========================================================================//
  40. static inline void lineNoise_C(uint8_t *dst, uint8_t *src, int8_t *noise, int len, int shift);
  41. static inline void lineNoiseAvg_C(uint8_t *dst, uint8_t *src, int len, int8_t **shift);
  42. static void (*lineNoise)(uint8_t *dst, uint8_t *src, int8_t *noise, int len, int shift)= lineNoise_C;
  43. static void (*lineNoiseAvg)(uint8_t *dst, uint8_t *src, int len, int8_t **shift)= lineNoiseAvg_C;
  44. typedef struct FilterParam{
  45. int strength;
  46. int uniform;
  47. int temporal;
  48. int quality;
  49. int averaged;
  50. int pattern;
  51. int shiftptr;
  52. int8_t *noise;
  53. int8_t *prev_shift[MAX_RES][3];
  54. }FilterParam;
  55. struct vf_priv_s {
  56. FilterParam lumaParam;
  57. FilterParam chromaParam;
  58. unsigned int outfmt;
  59. };
  60. static int nonTempRandShift_init;
  61. static int nonTempRandShift[MAX_RES];
  62. static int patt[4] = {
  63. -1,0,1,0
  64. };
  65. #define RAND_N(range) ((int) ((double)range*rand()/(RAND_MAX+1.0)))
  66. static int8_t *initNoise(FilterParam *fp){
  67. int strength= fp->strength;
  68. int uniform= fp->uniform;
  69. int averaged= fp->averaged;
  70. int pattern= fp->pattern;
  71. int8_t *noise= av_malloc(MAX_NOISE*sizeof(int8_t));
  72. int i, j;
  73. srand(123457);
  74. for(i=0,j=0; i<MAX_NOISE; i++,j++)
  75. {
  76. if(uniform) {
  77. if (averaged) {
  78. if (pattern) {
  79. noise[i]= (RAND_N(strength) - strength/2)/6
  80. +patt[j%4]*strength*0.25/3;
  81. } else {
  82. noise[i]= (RAND_N(strength) - strength/2)/3;
  83. }
  84. } else {
  85. if (pattern) {
  86. noise[i]= (RAND_N(strength) - strength/2)/2
  87. + patt[j%4]*strength*0.25;
  88. } else {
  89. noise[i]= RAND_N(strength) - strength/2;
  90. }
  91. }
  92. } else {
  93. double x1, x2, w, y1;
  94. do {
  95. x1 = 2.0 * rand()/(float)RAND_MAX - 1.0;
  96. x2 = 2.0 * rand()/(float)RAND_MAX - 1.0;
  97. w = x1 * x1 + x2 * x2;
  98. } while ( w >= 1.0 );
  99. w = sqrt( (-2.0 * log( w ) ) / w );
  100. y1= x1 * w;
  101. y1*= strength / sqrt(3.0);
  102. if (pattern) {
  103. y1 /= 2;
  104. y1 += patt[j%4]*strength*0.35;
  105. }
  106. if (y1<-128) y1=-128;
  107. else if(y1> 127) y1= 127;
  108. if (averaged) y1 /= 3.0;
  109. noise[i]= (int)y1;
  110. }
  111. if (RAND_N(6) == 0) j--;
  112. }
  113. for (i = 0; i < MAX_RES; i++)
  114. for (j = 0; j < 3; j++)
  115. fp->prev_shift[i][j] = noise + (rand()&(MAX_SHIFT-1));
  116. if(!nonTempRandShift_init){
  117. for(i=0; i<MAX_RES; i++){
  118. nonTempRandShift[i]= rand()&(MAX_SHIFT-1);
  119. }
  120. nonTempRandShift_init = 1;
  121. }
  122. fp->noise= noise;
  123. fp->shiftptr= 0;
  124. return noise;
  125. }
  126. /***************************************************************************/
  127. #if HAVE_MMX
  128. static inline void lineNoise_MMX(uint8_t *dst, uint8_t *src, int8_t *noise, int len, int shift){
  129. x86_reg mmx_len= len&(~7);
  130. noise+=shift;
  131. __asm__ volatile(
  132. "mov %3, %%"REG_a" \n\t"
  133. "pcmpeqb %%mm7, %%mm7 \n\t"
  134. "psllw $15, %%mm7 \n\t"
  135. "packsswb %%mm7, %%mm7 \n\t"
  136. ASMALIGN(4)
  137. "1: \n\t"
  138. "movq (%0, %%"REG_a"), %%mm0 \n\t"
  139. "movq (%1, %%"REG_a"), %%mm1 \n\t"
  140. "pxor %%mm7, %%mm0 \n\t"
  141. "paddsb %%mm1, %%mm0 \n\t"
  142. "pxor %%mm7, %%mm0 \n\t"
  143. "movq %%mm0, (%2, %%"REG_a") \n\t"
  144. "add $8, %%"REG_a" \n\t"
  145. " js 1b \n\t"
  146. :: "r" (src+mmx_len), "r" (noise+mmx_len), "r" (dst+mmx_len), "g" (-mmx_len)
  147. : "%"REG_a
  148. );
  149. if(mmx_len!=len)
  150. lineNoise_C(dst+mmx_len, src+mmx_len, noise+mmx_len, len-mmx_len, 0);
  151. }
  152. #endif
  153. //duplicate of previous except movntq
  154. #if HAVE_MMX2
  155. static inline void lineNoise_MMX2(uint8_t *dst, uint8_t *src, int8_t *noise, int len, int shift){
  156. x86_reg mmx_len= len&(~7);
  157. noise+=shift;
  158. __asm__ volatile(
  159. "mov %3, %%"REG_a" \n\t"
  160. "pcmpeqb %%mm7, %%mm7 \n\t"
  161. "psllw $15, %%mm7 \n\t"
  162. "packsswb %%mm7, %%mm7 \n\t"
  163. ASMALIGN(4)
  164. "1: \n\t"
  165. "movq (%0, %%"REG_a"), %%mm0 \n\t"
  166. "movq (%1, %%"REG_a"), %%mm1 \n\t"
  167. "pxor %%mm7, %%mm0 \n\t"
  168. "paddsb %%mm1, %%mm0 \n\t"
  169. "pxor %%mm7, %%mm0 \n\t"
  170. "movntq %%mm0, (%2, %%"REG_a") \n\t"
  171. "add $8, %%"REG_a" \n\t"
  172. " js 1b \n\t"
  173. :: "r" (src+mmx_len), "r" (noise+mmx_len), "r" (dst+mmx_len), "g" (-mmx_len)
  174. : "%"REG_a
  175. );
  176. if(mmx_len!=len)
  177. lineNoise_C(dst+mmx_len, src+mmx_len, noise+mmx_len, len-mmx_len, 0);
  178. }
  179. #endif
  180. static inline void lineNoise_C(uint8_t *dst, uint8_t *src, int8_t *noise, int len, int shift){
  181. int i;
  182. noise+= shift;
  183. for(i=0; i<len; i++)
  184. {
  185. int v= src[i]+ noise[i];
  186. if(v>255) dst[i]=255; //FIXME optimize
  187. else if(v<0) dst[i]=0;
  188. else dst[i]=v;
  189. }
  190. }
  191. /***************************************************************************/
  192. #if HAVE_MMX
  193. static inline void lineNoiseAvg_MMX(uint8_t *dst, uint8_t *src, int len, int8_t **shift){
  194. x86_reg mmx_len= len&(~7);
  195. __asm__ volatile(
  196. "mov %5, %%"REG_a" \n\t"
  197. ASMALIGN(4)
  198. "1: \n\t"
  199. "movq (%1, %%"REG_a"), %%mm1 \n\t"
  200. "movq (%0, %%"REG_a"), %%mm0 \n\t"
  201. "paddb (%2, %%"REG_a"), %%mm1 \n\t"
  202. "paddb (%3, %%"REG_a"), %%mm1 \n\t"
  203. "movq %%mm0, %%mm2 \n\t"
  204. "movq %%mm1, %%mm3 \n\t"
  205. "punpcklbw %%mm0, %%mm0 \n\t"
  206. "punpckhbw %%mm2, %%mm2 \n\t"
  207. "punpcklbw %%mm1, %%mm1 \n\t"
  208. "punpckhbw %%mm3, %%mm3 \n\t"
  209. "pmulhw %%mm0, %%mm1 \n\t"
  210. "pmulhw %%mm2, %%mm3 \n\t"
  211. "paddw %%mm1, %%mm1 \n\t"
  212. "paddw %%mm3, %%mm3 \n\t"
  213. "paddw %%mm0, %%mm1 \n\t"
  214. "paddw %%mm2, %%mm3 \n\t"
  215. "psrlw $8, %%mm1 \n\t"
  216. "psrlw $8, %%mm3 \n\t"
  217. "packuswb %%mm3, %%mm1 \n\t"
  218. "movq %%mm1, (%4, %%"REG_a") \n\t"
  219. "add $8, %%"REG_a" \n\t"
  220. " js 1b \n\t"
  221. :: "r" (src+mmx_len), "r" (shift[0]+mmx_len), "r" (shift[1]+mmx_len), "r" (shift[2]+mmx_len),
  222. "r" (dst+mmx_len), "g" (-mmx_len)
  223. : "%"REG_a
  224. );
  225. if(mmx_len!=len){
  226. int8_t *shift2[3]={shift[0]+mmx_len, shift[1]+mmx_len, shift[2]+mmx_len};
  227. lineNoiseAvg_C(dst+mmx_len, src+mmx_len, len-mmx_len, shift2);
  228. }
  229. }
  230. #endif
  231. static inline void lineNoiseAvg_C(uint8_t *dst, uint8_t *src, int len, int8_t **shift){
  232. int i;
  233. int8_t *src2= (int8_t*)src;
  234. for(i=0; i<len; i++)
  235. {
  236. const int n= shift[0][i] + shift[1][i] + shift[2][i];
  237. dst[i]= src2[i]+((n*src2[i])>>7);
  238. }
  239. }
  240. /***************************************************************************/
  241. static void noise(uint8_t *dst, uint8_t *src, int dstStride, int srcStride, int width, int height, FilterParam *fp){
  242. int8_t *noise= fp->noise;
  243. int y;
  244. int shift=0;
  245. if(!noise)
  246. {
  247. if(src==dst) return;
  248. if(dstStride==srcStride) fast_memcpy(dst, src, srcStride*height);
  249. else
  250. {
  251. for(y=0; y<height; y++)
  252. {
  253. fast_memcpy(dst, src, width);
  254. dst+= dstStride;
  255. src+= srcStride;
  256. }
  257. }
  258. return;
  259. }
  260. for(y=0; y<height; y++)
  261. {
  262. if(fp->temporal) shift= rand()&(MAX_SHIFT -1);
  263. else shift= nonTempRandShift[y];
  264. if(fp->quality==0) shift&= ~7;
  265. if (fp->averaged) {
  266. lineNoiseAvg(dst, src, width, fp->prev_shift[y]);
  267. fp->prev_shift[y][fp->shiftptr] = noise + shift;
  268. } else {
  269. lineNoise(dst, src, noise, width, shift);
  270. }
  271. dst+= dstStride;
  272. src+= srcStride;
  273. }
  274. fp->shiftptr++;
  275. if (fp->shiftptr == 3) fp->shiftptr = 0;
  276. }
  277. static int config(struct vf_instance *vf,
  278. int width, int height, int d_width, int d_height,
  279. unsigned int flags, unsigned int outfmt){
  280. return vf_next_config(vf,width,height,d_width,d_height,flags,outfmt);
  281. }
  282. static void get_image(struct vf_instance *vf, mp_image_t *mpi){
  283. if(mpi->flags&MP_IMGFLAG_PRESERVE) return; // don't change
  284. if(mpi->imgfmt!=vf->priv->outfmt) return; // colorspace differ
  285. // ok, we can do pp in-place (or pp disabled):
  286. vf->dmpi=vf_get_image(vf->next,mpi->imgfmt,
  287. mpi->type, mpi->flags, mpi->w, mpi->h);
  288. mpi->planes[0]=vf->dmpi->planes[0];
  289. mpi->stride[0]=vf->dmpi->stride[0];
  290. mpi->width=vf->dmpi->width;
  291. if(mpi->flags&MP_IMGFLAG_PLANAR){
  292. mpi->planes[1]=vf->dmpi->planes[1];
  293. mpi->planes[2]=vf->dmpi->planes[2];
  294. mpi->stride[1]=vf->dmpi->stride[1];
  295. mpi->stride[2]=vf->dmpi->stride[2];
  296. }
  297. mpi->flags|=MP_IMGFLAG_DIRECT;
  298. }
  299. static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts){
  300. mp_image_t *dmpi;
  301. if(!(mpi->flags&MP_IMGFLAG_DIRECT)){
  302. // no DR, so get a new image! hope we'll get DR buffer:
  303. vf->dmpi=vf_get_image(vf->next,vf->priv->outfmt,
  304. MP_IMGTYPE_TEMP, MP_IMGFLAG_ACCEPT_STRIDE,
  305. mpi->w,mpi->h);
  306. //printf("nodr\n");
  307. }
  308. //else printf("dr\n");
  309. dmpi= vf->dmpi;
  310. noise(dmpi->planes[0], mpi->planes[0], dmpi->stride[0], mpi->stride[0], mpi->w, mpi->h, &vf->priv->lumaParam);
  311. noise(dmpi->planes[1], mpi->planes[1], dmpi->stride[1], mpi->stride[1], mpi->w/2, mpi->h/2, &vf->priv->chromaParam);
  312. noise(dmpi->planes[2], mpi->planes[2], dmpi->stride[2], mpi->stride[2], mpi->w/2, mpi->h/2, &vf->priv->chromaParam);
  313. vf_clone_mpi_attributes(dmpi, mpi);
  314. #if HAVE_MMX
  315. if(gCpuCaps.hasMMX) __asm__ volatile ("emms\n\t");
  316. #endif
  317. #if HAVE_MMX2
  318. if(gCpuCaps.hasMMX2) __asm__ volatile ("sfence\n\t");
  319. #endif
  320. return vf_next_put_image(vf,dmpi, pts);
  321. }
  322. static void uninit(struct vf_instance *vf){
  323. if(!vf->priv) return;
  324. av_free(vf->priv->chromaParam.noise);
  325. vf->priv->chromaParam.noise= NULL;
  326. av_free(vf->priv->lumaParam.noise);
  327. vf->priv->lumaParam.noise= NULL;
  328. free(vf->priv);
  329. vf->priv=NULL;
  330. }
  331. //===========================================================================//
  332. static int query_format(struct vf_instance *vf, unsigned int fmt){
  333. switch(fmt)
  334. {
  335. case IMGFMT_YV12:
  336. case IMGFMT_I420:
  337. case IMGFMT_IYUV:
  338. return vf_next_query_format(vf,vf->priv->outfmt);
  339. }
  340. return 0;
  341. }
  342. static void parse(FilterParam *fp, char* args){
  343. char *pos;
  344. char *max= strchr(args, ':');
  345. if(!max) max= args + strlen(args);
  346. fp->strength= atoi(args);
  347. pos= strchr(args, 'u');
  348. if(pos && pos<max) fp->uniform=1;
  349. pos= strchr(args, 't');
  350. if(pos && pos<max) fp->temporal=1;
  351. pos= strchr(args, 'h');
  352. if(pos && pos<max) fp->quality=1;
  353. pos= strchr(args, 'p');
  354. if(pos && pos<max) fp->pattern=1;
  355. pos= strchr(args, 'a');
  356. if(pos && pos<max) {
  357. fp->temporal=1;
  358. fp->averaged=1;
  359. }
  360. if(fp->strength) initNoise(fp);
  361. }
  362. static const unsigned int fmt_list[]={
  363. IMGFMT_YV12,
  364. IMGFMT_I420,
  365. IMGFMT_IYUV,
  366. 0
  367. };
  368. static int vf_open(vf_instance_t *vf, char *args){
  369. vf->config=config;
  370. vf->put_image=put_image;
  371. vf->get_image=get_image;
  372. vf->query_format=query_format;
  373. vf->uninit=uninit;
  374. vf->priv=malloc(sizeof(struct vf_priv_s));
  375. memset(vf->priv, 0, sizeof(struct vf_priv_s));
  376. if(args)
  377. {
  378. char *arg2= strchr(args,':');
  379. if(arg2) parse(&vf->priv->chromaParam, arg2+1);
  380. parse(&vf->priv->lumaParam, args);
  381. }
  382. // check csp:
  383. vf->priv->outfmt=vf_match_csp(&vf->next,fmt_list,IMGFMT_YV12);
  384. if(!vf->priv->outfmt)
  385. {
  386. uninit(vf);
  387. return 0; // no csp match :(
  388. }
  389. #if HAVE_MMX
  390. if(gCpuCaps.hasMMX){
  391. lineNoise= lineNoise_MMX;
  392. lineNoiseAvg= lineNoiseAvg_MMX;
  393. }
  394. #endif
  395. #if HAVE_MMX2
  396. if(gCpuCaps.hasMMX2) lineNoise= lineNoise_MMX2;
  397. // if(gCpuCaps.hasMMX) lineNoiseAvg= lineNoiseAvg_MMX2;
  398. #endif
  399. return 1;
  400. }
  401. const vf_info_t vf_info_noise = {
  402. "noise generator",
  403. "noise",
  404. "Michael Niedermayer",
  405. "",
  406. vf_open,
  407. NULL
  408. };
  409. //===========================================================================//