invtelec.cpp
上传用户:dangjiwu
上传日期:2013-07-19
资源大小:42019k
文件大小:47k
源码类别:

Symbian

开发平台:

Visual C++

  1. /* ***** BEGIN LICENSE BLOCK *****
  2.  * Source last modified: $Id: invtelec.cpp,v 1.7.32.1 2004/07/09 01:55:14 hubbe Exp $
  3.  * 
  4.  * Portions Copyright (c) 1995-2004 RealNetworks, Inc. All Rights Reserved.
  5.  * 
  6.  * The contents of this file, and the files included with this file,
  7.  * are subject to the current version of the RealNetworks Public
  8.  * Source License (the "RPSL") available at
  9.  * http://www.helixcommunity.org/content/rpsl unless you have licensed
  10.  * the file under the current version of the RealNetworks Community
  11.  * Source License (the "RCSL") available at
  12.  * http://www.helixcommunity.org/content/rcsl, in which case the RCSL
  13.  * will apply. You may also obtain the license terms directly from
  14.  * RealNetworks.  You may not use this file except in compliance with
  15.  * the RPSL or, if you have a valid RCSL with RealNetworks applicable
  16.  * to this file, the RCSL.  Please see the applicable RPSL or RCSL for
  17.  * the rights, obligations and limitations governing use of the
  18.  * contents of the file.
  19.  * 
  20.  * Alternatively, the contents of this file may be used under the
  21.  * terms of the GNU General Public License Version 2 or later (the
  22.  * "GPL") in which case the provisions of the GPL are applicable
  23.  * instead of those above. If you wish to allow use of your version of
  24.  * this file only under the terms of the GPL, and not to allow others
  25.  * to use your version of this file under the terms of either the RPSL
  26.  * or RCSL, indicate your decision by deleting the provisions above
  27.  * and replace them with the notice and other provisions required by
  28.  * the GPL. If you do not delete the provisions above, a recipient may
  29.  * use your version of this file under the terms of any one of the
  30.  * RPSL, the RCSL or the GPL.
  31.  * 
  32.  * This file is part of the Helix DNA Technology. RealNetworks is the
  33.  * developer of the Original Code and owns the copyrights in the
  34.  * portions it created.
  35.  * 
  36.  * This file, and the files included with this file, is distributed
  37.  * and made available on an 'AS IS' basis, WITHOUT WARRANTY OF ANY
  38.  * KIND, EITHER EXPRESS OR IMPLIED, AND REALNETWORKS HEREBY DISCLAIMS
  39.  * ALL SUCH WARRANTIES, INCLUDING WITHOUT LIMITATION, ANY WARRANTIES
  40.  * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, QUIET
  41.  * ENJOYMENT OR NON-INFRINGEMENT.
  42.  * 
  43.  * Technology Compatibility Kit Test Suite(s) Location:
  44.  *    http://www.helixcommunity.org/content/tck
  45.  * 
  46.  * Contributor(s):
  47.  * 
  48.  * ***** END LICENSE BLOCK ***** */
  49. ////////////////////////////////////////////////////////
  50. // include files
  51. ////////////////////////////////////////////////////////
  52. #include "invtelec.h"
  53. #include "hxtick.h"
  54. #include "mmx_util.h"
  55. #include "hlxclib/stdlib.h"
  56. #include "hlxclib/string.h"
  57. #include "hlxclib/math.h"
  58. ////////////////////////////////////////////////////////
  59. // internal prototypes
  60. ////////////////////////////////////////////////////////
  61. static T_INVTELE_RESULT 
  62. InvTelecineDetect(
  63. UCHAR *data, UCHAR *prevData, 
  64. double frameRate, 
  65. ULONG32 timestamp, 
  66. ULONG32 pels, ULONG32 lines,
  67. BOOL bDeInterlaced,
  68. T_INVTELE_STATE *state);
  69. //#define CODEC_DEBUG_32PULLDOWN
  70. #ifdef CODEC_DEBUG_32PULLDOWN
  71. #include <stdio.h>
  72. static FILE *fp_log = NULL;
  73. #endif
  74. const T_INVTELE_FLOAT inThresh[PULLDOWN_HIST_LEN+1] = {3,3,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,4,4,4};
  75. const T_INVTELE_FLOAT outThresh[PULLDOWN_HIST_LEN+1] = {1,1,1,1,1,1,1,1,1,1,2,2,2,2,2,2,2,2,2,2,2};
  76. #ifdef ALLOW_MMX_INVTELE
  77. void
  78. SumSqaredFrameDiff_MMX(
  79. unsigned char *frame, 
  80. unsigned char *prev_frame,
  81. int pels,
  82. int lines,
  83. int pitch,
  84. float *ssd_odd,
  85. float *ssd_even);
  86. void
  87. RestitchCheck_MMX(
  88. unsigned char *frame, 
  89. unsigned char *prev_frame,
  90. int pels,
  91. int lines,
  92. int pitch,
  93. float *ssd_new,
  94. float *ssd_old);
  95. #endif
  96. ////////////////////////////////////////////////////////
  97. //
  98. // InitInvTelecine
  99. //
  100. // Allocates and initializes memory for state information
  101. //
  102. // Parameters:
  103. // state: Pointer to the allocated state pointer
  104. //
  105. ////////////////////////////////////////////////////////
  106. INT32
  107. InitInvTelecine(T_INVTELE_STATE **state)
  108. {
  109. T_INVTELE_STATE *new_state = 0;
  110. if (*state != 0)
  111. return 1;
  112. new_state = (T_INVTELE_STATE *)malloc(sizeof(T_INVTELE_STATE));
  113. if (new_state == 0)
  114. {
  115. return 1;
  116. }
  117. new_state->impl_id = INVTELE_IMPL_ID_C;
  118. new_state->firstFrame = TRUE;
  119. new_state->ulPulldownActiveTimerIntl = 0;
  120. new_state->ulPulldownActiveTimerProg = 0;
  121. new_state->lastRemovedTimestamp = 0;
  122. new_state->frameCountMod = 4;
  123. new_state->frameRemovalPattern = 4;
  124. new_state->NTSCTrackingFrameCounter = 500;
  125. new_state->interleaveEvenFlag = FALSE;
  126. new_state->interleaveOddFlag = FALSE;
  127. new_state->checkNextFrameForInterlace = FALSE;
  128. new_state->checkNextFrameForProgressive = FALSE;
  129. new_state->bProgressiveTelecineSeen = FALSE;
  130. new_state->bInterlacedTelecineSeen = FALSE;
  131. new_state->pulldownTimeBuffer = 0;
  132. for (int i = 0; i < PULLDOWN_HIST_LEN; i++)
  133. {
  134. new_state->pulldownSadHistEven[i] = UN_INIT_SAD;
  135. new_state->pulldownSadHistOdd[i] = UN_INIT_SAD;
  136. new_state->pulldownSadHistAll[i] = UN_INIT_SAD;
  137. new_state->pulldownTimeHist[i] = 0;
  138. }
  139. #ifdef ALLOW_MMX_INVTELE
  140. // Check for MMx availability
  141.     if (checkMmxAvailablity() & CPU_HAS_MMX)
  142. new_state->impl_id = INVTELE_IMPL_ID_MMX;
  143. #endif
  144. *state = new_state;
  145. return 0;
  146. }
  147. ////////////////////////////////////////////////////////
  148. //
  149. // FreeInvTelecine
  150. //
  151. // Frees memory for state information
  152. //
  153. // Parameters:
  154. // state: Pointer to the allocated state pointer
  155. //
  156. ////////////////////////////////////////////////////////
  157. void
  158. FreeInvTelecine(T_INVTELE_STATE **state)
  159. {
  160. if (*state != 0)
  161. free(*state);
  162. *state = 0;
  163. }
  164. ////////////////////////////////////////////////////////
  165. //
  166. // IsContentProgressiveTelecine
  167. //
  168. // Returns TRUE if the telecine detector has seen 
  169. //   interlaced telecine content
  170. //
  171. // Parameters:
  172. // state: State pointer
  173. //
  174. ////////////////////////////////////////////////////////
  175. BOOL
  176. IsContentProgressiveTelecine(T_INVTELE_STATE *state)
  177. {
  178. if (state != 0)
  179. return (state->bProgressiveTelecineSeen)?(TRUE):(FALSE);
  180. return FALSE;
  181. }
  182. ////////////////////////////////////////////////////////
  183. //
  184. // IsContentInterlacedTelecine
  185. //
  186. // Returns TRUE if the telecine detector has seen 
  187. //   progressive telecine content
  188. //
  189. // Parameters:
  190. // state: State pointer
  191. //
  192. ////////////////////////////////////////////////////////
  193. BOOL
  194. IsContentInterlacedTelecine(T_INVTELE_STATE *state)
  195. {
  196. if (state != 0)
  197. return (state->bInterlacedTelecineSeen)?(TRUE):(FALSE);
  198. return FALSE;
  199. }
  200. ////////////////////////////////////////////////////////
  201. //
  202. // GetTelecinePattern
  203. //
  204. // Returns the frame modulo for the removal pattern
  205. //
  206. // Parameters:
  207. // state: State pointer
  208. //
  209. ////////////////////////////////////////////////////////
  210. UCHAR
  211. GetTelecinePattern(T_INVTELE_STATE *state)
  212. {
  213. INT32 pattern;
  214. if (state != 0)
  215. pattern = (state->frameRemovalPattern - state->frameCountMod) % 5;
  216. else
  217. pattern = 0;
  218. if (pattern < 0)
  219. pattern +=5;
  220. return (UCHAR)pattern;
  221. }
  222. ////////////////////////////////////////////////////////
  223. //
  224. // SetTelecinePattern
  225. //
  226. // Sets the frame modulo for the removal pattern
  227. //
  228. // Parameters:
  229. // state: State pointer
  230. //
  231. ////////////////////////////////////////////////////////
  232. void
  233. SetTelecinePattern(T_INVTELE_STATE *state, UCHAR telecine_pattern)
  234. {
  235. if (state != 0)
  236. state->frameRemovalPattern = ((telecine_pattern + state->frameCountMod) % 5);
  237. }
  238. ////////////////////////////////////////////////////////
  239. //
  240. // DoInvTelecine
  241. //
  242. // Performs inverse Telecine
  243. //
  244. // Parameters:
  245. // data: Pointer to the current planar frame.
  246. // prevData: Pointer to the previous source frame.
  247. // frameRate: The input frame rate.
  248. // timestamp: The timestamp of the current frame.
  249. // This value will be adjusted to account
  250. // for the change to 24 fps
  251. // pels, lines: Frame dimensions.
  252. // bDeInterlaced: Should be set to TRUE if frame is known
  253. // to be progressive.
  254. // state: State pointer
  255. //
  256. ////////////////////////////////////////////////////////
  257. T_INVTELE_RESULT
  258. DoInvTelecine(
  259. UCHAR *data, 
  260. UCHAR *prevData, 
  261. double frameRate, 
  262. ULONG32 &timestamp, 
  263. ULONG32 pels, ULONG32 lines, 
  264. BOOL bDeInterlaced, 
  265. T_INVTELE_STATE *state)
  266. {
  267. T_INVTELE_RESULT ret;
  268. if (frameRate < 25.5)
  269. return (INVTELE_RESULT_LOW_FRAMERATE);
  270. #ifdef CODEC_DEBUG_32PULLDOWN
  271.   if(fp_log == NULL)
  272.   fp_log = fopen("c:\pulldown.log","w");
  273. #endif
  274. ret = InvTelecineDetect(data, prevData, frameRate, timestamp, pels, lines, bDeInterlaced, state);
  275. // hack -- don't drop more than 1 out of every 5 progressive frames
  276. if ((state->pulldownTimeBuffer > 1) && 
  277. (bDeInterlaced || lines < 242) &&
  278. (ret == INVTELE_RESULT_DROP_FRAME))
  279. {
  280. ret = INVTELE_RESULT_FRAME_OK;
  281. }
  282. if (ret == INVTELE_RESULT_DROP_FRAME)
  283. {
  284. state->pulldownTimeBuffer = 33;
  285. }
  286. else
  287. {
  288. // adjust timestamp 
  289. // -- allowed offsets will be -33, -25, -17, -9, -1, 0
  290. timestamp -= state->pulldownTimeBuffer;
  291. if (state->pulldownTimeBuffer > 8)
  292. {
  293. state->pulldownTimeBuffer -= 8;
  294. }
  295. else
  296. {
  297. state->pulldownTimeBuffer = 0;
  298. }
  299. }
  300. return (ret);
  301. }
  302. ////////////////////////////////////////////////////////
  303. //
  304. // InvTelecineDetect
  305. //
  306. // Performs detection of the inverse telecine pattern
  307. //
  308. // Parameters:
  309. // data: Pointer to the current planar frame.
  310. // prevData: Pointer to the previous source frame.
  311. // frameRate: The input frame rate.
  312. // timestamp: The timestamp of the current frame.
  313. // pels, lines: Frame dimensions.
  314. // bDeInterlaced: Should be set to TRUE if frame is known
  315. // to be progressive.
  316. // state: State pointer
  317. //
  318. ////////////////////////////////////////////////////////
  319. T_INVTELE_RESULT
  320. InvTelecineDetect
  321. (
  322.  UCHAR *data, 
  323.  UCHAR *prevData, 
  324.  double frameRate, 
  325.  ULONG32 timestamp, 
  326.  ULONG32 pels, ULONG32 lines,
  327.  BOOL bDeInterlaced,
  328.  T_INVTELE_STATE *state
  329. )
  330. {
  331. unsigned int i, j, k, ll;
  332. ULONG32 patternStart, histLength;
  333. LONG32 *pNew, *pOld;
  334. float temp;
  335. float sumEven = 0.0f, sumOdd = 0.0f;
  336. float sumOld = 0.0f, sumNew = 0.0f;
  337. float sumAll = 0.0f;
  338. float inGroupMeanEven[5],outGroupMeanEven[5];
  339. float inGroupStdEven[5],outGroupStdEven[5];
  340. ULONG32 inGroupCountEven,outGroupCountEven;
  341. float outMinEven[5],outMaxEven[5];
  342. float inMaxEven[5],inMinEven[5];
  343. BOOL groupValidFlagEven[5];
  344. float inGroupMeanOdd[5],outGroupMeanOdd[5];
  345. float inGroupStdOdd[5],outGroupStdOdd[5];
  346. ULONG32 inGroupCountOdd,outGroupCountOdd;
  347. float outMinOdd[5],outMaxOdd[5];
  348. float inMaxOdd[5],inMinOdd[5];
  349. BOOL groupValidFlagOdd[5];
  350. float inGroupMean[5], outGroupMean[5];
  351. float inGroupStd[5], outGroupStd[5];
  352. ULONG32 inGroupCount,outGroupCount;
  353. float outMin[5],outMax[5],inMax[5];
  354. BOOL groupValidFlag[5];
  355. ULONG32 timeSinceLastFrame;
  356. BOOL obviousPatternFlag = FALSE;
  357. BOOL sceneChangeFlag = FALSE;
  358. if (state->firstFrame == TRUE)
  359. {
  360. // Initialize history timestamps with this first timestamp
  361. for (i = 0; i < PULLDOWN_HIST_LEN; i++)
  362. {
  363. state->pulldownTimeHist[i] = timestamp;
  364. }
  365. state->lastRemovedTimestamp = timestamp;
  366. state->firstFrame = FALSE;
  367. goto TOO_EARLY;
  368. }
  369. // Calculate Sum of Differences for even and odd lines...
  370. // If we know that the frame is de-interlaced, then the stats
  371. // for the "odd" lines are invalid.  So just measure "even"
  372. // lines then copy into "odd" SAD (so the rest of the algorithm
  373. // will work).
  374. ll = (pels >> 2);
  375. if (bDeInterlaced)
  376. {
  377. pNew = (LONG32 *)data;
  378. pOld = (LONG32 *)prevData;
  379. ll = (pels >> 2);
  380. for (i = 0; i < lines; i += 2)  //  only do the luma.
  381. {
  382. for (j = 0; j < ll; j++)
  383. {
  384. temp = (float)((pNew[j]&0xff00) - (pOld[j]&0xFF00));
  385. sumEven += ((float)(1./(256.*256.)))*(temp*temp);
  386. }
  387. pOld += 2*ll;
  388. pNew += 2*ll;
  389. }
  390. sumOdd = sumEven;
  391. }
  392. else
  393. {
  394. switch (state->impl_id)
  395. {
  396. #ifdef ALLOW_MMX_INVTELE
  397. case INVTELE_IMPL_ID_MMX:
  398. {
  399. SumSqaredFrameDiff_MMX(
  400. data, prevData,
  401. pels, lines, pels,
  402. &sumEven, &sumOdd);
  403. sumAll = 0.5f * (sumEven + sumOdd);
  404. }
  405. break;
  406. #endif
  407. case INVTELE_IMPL_ID_C:
  408. default:
  409. {
  410. pNew = (LONG32 *)data;
  411. pOld = (LONG32 *)prevData;
  412. for (i = 0; i < lines; i += 2)  //  only do the luma.
  413. {
  414. for (j = 0; j < ll; j++)
  415. {
  416. temp = (float)((pNew[j]&0xff00) - (pOld[j]&0xFF00));
  417. sumEven += ((float)(1./(256.*256.)))*(temp*temp);
  418. temp = (float)((pNew[j+ll]&0xFF00) - (pOld[j+ll]&0xFF00));
  419. sumOdd += ((float)(1./(256.*256.)))*(temp*temp);
  420. }
  421. pOld += 2*ll;
  422. pNew += 2*ll;
  423. }
  424. sumAll = sumEven + sumOdd;
  425. sumEven /= (ll * (lines>>1));
  426. sumOdd /= (ll * (lines>>1));
  427. sumAll /= (ll * lines);
  428. }
  429. break;
  430. }
  431. }
  432. sceneChangeFlag = (sumAll > 7500)?(TRUE):(FALSE);
  433. if (sumEven > 100) sumEven=100;
  434. if (sumOdd > 100) sumOdd=100;
  435. if (sumAll > 100) sumAll=100;
  436. #ifdef CODEC_DEBUG_32PULLDOWN
  437. fprintf(fp_log,"ssd are %f %f at time %dn",sumEven,sumOdd,timestamp);
  438. #endif
  439. // Compensate for 30 vs 29.97fps captures.
  440. if ((sumEven == 0) && (sumOdd == 0) && 
  441. (state->NTSCTrackingFrameCounter > 500) && (frameRate > 29.98))
  442. {
  443. state->pulldownTimeHist[PULLDOWN_HIST_LEN-1] = timestamp;
  444. state->NTSCTrackingFrameCounter = 0;
  445.   goto REMOVE_FRAME;
  446. }
  447. state->NTSCTrackingFrameCounter++;
  448. // In case we dropped a frame
  449. timeSinceLastFrame = CALCULATE_ELAPSED_TICKS(state->pulldownTimeHist[PULLDOWN_HIST_LEN-1], timestamp);
  450. while(timeSinceLastFrame > 50)
  451. {
  452. for(i=0;i<PULLDOWN_HIST_LEN-1;i++)
  453. {
  454. state->pulldownSadHistEven[i] = state->pulldownSadHistEven[i+1];
  455. state->pulldownSadHistOdd[i] = state->pulldownSadHistOdd[i+1];
  456. state->pulldownSadHistAll[i] = state->pulldownSadHistAll[i+1];
  457. state->pulldownTimeHist[i] = state->pulldownTimeHist[i+1];
  458. }
  459. state->pulldownSadHistEven[i] = MISSING_SAD;
  460. state->pulldownSadHistOdd[i] = MISSING_SAD;
  461. state->pulldownSadHistAll[i] = MISSING_SAD;
  462. state->pulldownTimeHist[i] = timestamp;
  463. timeSinceLastFrame -= 33;
  464. state->frameRemovalPattern--;
  465. if (state->frameRemovalPattern < 0)
  466. state->frameRemovalPattern = 4;
  467. state->frameCountMod--;
  468. if (state->frameCountMod < 0)
  469. state->frameCountMod = 4;
  470. }
  471. //  Update the history 
  472. for(i = 0; i < PULLDOWN_HIST_LEN - 1; i++)
  473. {
  474. state->pulldownSadHistEven[i] = state->pulldownSadHistEven[i+1];
  475. state->pulldownSadHistOdd[i] = state->pulldownSadHistOdd[i+1];
  476. state->pulldownSadHistAll[i] = state->pulldownSadHistAll[i+1];
  477. state->pulldownTimeHist[i] = state->pulldownTimeHist[i+1];
  478. }
  479. state->frameRemovalPattern--;
  480. if (state->frameRemovalPattern < 0)
  481. state->frameRemovalPattern = 4;
  482. state->frameCountMod--;
  483. if (state->frameCountMod < 0)
  484. state->frameCountMod = 4;
  485. state->pulldownSadHistEven[i] = sumEven;
  486. state->pulldownSadHistOdd[i] = sumOdd;
  487. state->pulldownSadHistAll[i] = sumAll;
  488. state->pulldownTimeHist[i] = timestamp;
  489. // If removal on, and we have no pattern established, wait a while.
  490. if ((state->pulldownSadHistEven[PULLDOWN_HIST_LEN - 5] == UN_INIT_SAD) || 
  491. (state->pulldownSadHistOdd[PULLDOWN_HIST_LEN - 5] == UN_INIT_SAD) || 
  492. (state->pulldownSadHistAll[PULLDOWN_HIST_LEN - 5] == UN_INIT_SAD))
  493. {
  494. #ifdef CODEC_DEBUG_32PULLDOWN
  495. fprintf(fp_log,"gotoing - too earlyn");
  496. #endif
  497. goto TOO_EARLY;
  498. }
  499. histLength = 0;
  500. while (state->pulldownSadHistAll[histLength] == UN_INIT_SAD)
  501. {
  502. histLength += 5;
  503. if (histLength > PULLDOWN_HIST_LEN - 10)
  504. goto TOO_EARLY;
  505. }
  506. if ((bDeInterlaced) || (state->ulPulldownActiveTimerProg > 90 && state->ulPulldownActiveTimerIntl < 10))
  507. {
  508. // Skip interlaced telecine tests
  509. goto PROGRESSIVE_TESTS;
  510. }
  511. // Gather statistics from SAD history
  512. // Run through tests looking at the last 20, then 15, then 10, then 5 frames
  513. for (patternStart = histLength; patternStart < PULLDOWN_HIST_LEN; patternStart += 5)
  514. {
  515. for (i = 0; i < 5;i++)
  516. {
  517. // Stats for "even" lines
  518. inGroupMeanEven[i]  = 0;
  519. outGroupMeanEven[i] = 0;
  520. inGroupStdEven[i]   = 0;
  521. outGroupStdEven[i]  = 0;
  522. inGroupCountEven    = 0;
  523. outGroupCountEven   = 0;
  524. outMinEven[i] = 255*255;
  525. inMinEven[i]  = 255*255;
  526. outMaxEven[i] = 0;
  527. inMaxEven[i]  = 0;
  528. for (j = patternStart + i; j < PULLDOWN_HIST_LEN; j++)
  529. {
  530. if (state->pulldownSadHistEven[j] == MISSING_SAD ||
  531. state->pulldownSadHistEven[j] == UN_INIT_SAD)
  532. continue;
  533. if (((j - i) % 5) == 0)
  534. {
  535. inGroupMeanEven[i] += state->pulldownSadHistEven[j];
  536. inGroupStdEven[i] += state->pulldownSadHistEven[j]*state->pulldownSadHistEven[j];
  537. if (inMaxEven[i] < state->pulldownSadHistEven[j])
  538. inMaxEven[i] = state->pulldownSadHistEven[j];
  539. if (inMinEven[i] > state->pulldownSadHistOdd[j])
  540. inMinEven[i] = state->pulldownSadHistOdd[j];
  541. inGroupCountEven++;
  542. }
  543. else
  544. {
  545. outGroupMeanEven[i]+= state->pulldownSadHistEven[j];
  546. outGroupStdEven[i]+= state->pulldownSadHistEven[j]*state->pulldownSadHistEven[j];
  547. if (outMinEven[i] > state->pulldownSadHistEven[j])
  548. outMinEven[i] = state->pulldownSadHistEven[j];
  549. if (outMaxEven[i] < state->pulldownSadHistEven[j])
  550. outMaxEven[i] = state->pulldownSadHistEven[j];
  551. outGroupCountEven++;
  552. }
  553. }
  554. // Is there enough valid data to analyze?
  555. if ((inGroupCountEven > 1) && (outGroupCountEven > 3))
  556. {
  557. inGroupMeanEven[i] = inGroupMeanEven[i]/inGroupCountEven;
  558. if ((inGroupStdEven[i]/inGroupCountEven)-(inGroupMeanEven[i]*inGroupMeanEven[i]) > 0.0f)
  559. inGroupStdEven[i] = (float)sqrt((inGroupStdEven[i]/inGroupCountEven)-(inGroupMeanEven[i]*inGroupMeanEven[i]));
  560. else
  561. inGroupStdEven[i] = 0.0f;
  562. outGroupMeanEven[i] = outGroupMeanEven[i]/outGroupCountEven;
  563. if ((outGroupStdEven[i]/outGroupCountEven)-(outGroupMeanEven[i]*outGroupMeanEven[i]) > 0.0f)
  564. outGroupStdEven[i] = (float)sqrt((outGroupStdEven[i]/outGroupCountEven)-(outGroupMeanEven[i]*outGroupMeanEven[i]));
  565. else
  566. outGroupStdEven[i] = 0.0f;
  567. groupValidFlagEven[i] = TRUE;
  568. }
  569. else
  570. {
  571. inGroupMeanEven[i] = 0;
  572. outGroupMeanEven[i] = 0;
  573. inGroupStdEven[i] = 1;
  574. outGroupStdEven[i] = 1;
  575. groupValidFlagEven[i] = FALSE;
  576. }
  577. // Stats for "odd" lines
  578. inGroupMeanOdd[i]  = 0;
  579. outGroupMeanOdd[i] = 0;
  580. inGroupStdOdd[i]   = 0;
  581. outGroupStdOdd[i]  = 0;
  582. inGroupCountOdd    = 0;
  583. outGroupCountOdd   = 0;
  584. outMinOdd[i] = 255*255;
  585. inMinOdd[i]  = 255*255;
  586. outMaxOdd[i] = 0;
  587. inMaxOdd[i]  = 0;
  588. for (j = patternStart + i; j < PULLDOWN_HIST_LEN; j++)
  589. {
  590. if (state->pulldownSadHistOdd[j] == MISSING_SAD ||
  591. state->pulldownSadHistOdd[j] == UN_INIT_SAD)
  592. continue;
  593. if (((j - i) % 5) == 0)
  594. {
  595. inGroupMeanOdd[i] += state->pulldownSadHistOdd[j];
  596. inGroupStdOdd[i] += state->pulldownSadHistOdd[j]*state->pulldownSadHistOdd[j];
  597. if (inMaxOdd[i] < state->pulldownSadHistOdd[j])
  598. inMaxOdd[i] = state->pulldownSadHistOdd[j];
  599. if (inMinOdd[i] > state->pulldownSadHistOdd[j])
  600. inMinOdd[i] = state->pulldownSadHistOdd[j];
  601. inGroupCountOdd++;
  602. }
  603. else
  604. {
  605. outGroupMeanOdd[i] += state->pulldownSadHistOdd[j];
  606. outGroupStdOdd[i] += state->pulldownSadHistOdd[j]*state->pulldownSadHistOdd[j];
  607. if (outMinOdd[i] > state->pulldownSadHistOdd[j])
  608. outMinOdd[i] = state->pulldownSadHistOdd[j];
  609. if (outMaxOdd[i] < state->pulldownSadHistOdd[j])
  610. outMaxOdd[i] = state->pulldownSadHistOdd[j];
  611. outGroupCountOdd++;
  612. }
  613. }
  614. // Is there enough valid data to analyze?
  615. if ((inGroupCountOdd > 1) && (outGroupCountOdd > 3))
  616. {
  617. inGroupMeanOdd[i] = inGroupMeanOdd[i]/inGroupCountOdd;
  618. if ((inGroupStdOdd[i]/inGroupCountOdd)-(inGroupMeanOdd[i]*inGroupMeanOdd[i]) > 0.0f)
  619. inGroupStdOdd[i] = (float)sqrt((inGroupStdOdd[i]/inGroupCountOdd)-(inGroupMeanOdd[i]*inGroupMeanOdd[i]));
  620. else
  621. inGroupStdOdd[i] = 0.0f;
  622. outGroupMeanOdd[i] = outGroupMeanOdd[i]/outGroupCountOdd;
  623. if ((outGroupStdOdd[i]/outGroupCountOdd)-(outGroupMeanOdd[i]*outGroupMeanOdd[i]) > 0.0f)
  624. outGroupStdOdd[i] = (float)sqrt((outGroupStdOdd[i]/outGroupCountOdd)-(outGroupMeanOdd[i]*outGroupMeanOdd[i]));
  625. else
  626. outGroupStdOdd[i] = 0.0f;
  627. groupValidFlagOdd[i] = TRUE;
  628. }
  629. else
  630. {
  631. inGroupMeanOdd[i] = 0;
  632. outGroupMeanOdd[i] = 0;
  633. inGroupStdOdd[i] = 1;
  634. outGroupStdOdd[i] = 1;
  635. groupValidFlagOdd[i] = FALSE;
  636. }
  637. }
  638. // Do we have a clear pattern? Always trust this test.
  639. for (i = 0; i < 5; i++)
  640. {
  641. if (groupValidFlagEven[i] == FALSE)
  642. continue;
  643. if (groupValidFlagOdd[i] == FALSE)
  644. continue;
  645. if (groupValidFlagEven[(i+2)%5] == FALSE)
  646. continue;
  647. if (groupValidFlagOdd[(i+2)%5] == FALSE)
  648. continue;
  649. if ((inGroupMeanEven[i]+inThresh[patternStart]*inGroupStdEven[i] < outGroupMeanEven[i] - outThresh[patternStart]*outGroupStdEven[i]) &&
  650. (inGroupMeanOdd[(i+2)%5]+inThresh[patternStart]*inGroupStdOdd[(i+2)%5] < outGroupMeanOdd[(i+2)%5] - outThresh[patternStart]*outGroupStdOdd[(i+2)%5]) &&
  651. (inGroupMeanEven[i]+inGroupStdEven[i] < inGroupMeanOdd[i]) &&
  652. (inGroupMeanOdd[(i+2)%5]+inGroupStdOdd[(i+2)%5] < inGroupMeanEven[(i+2)%5]))
  653. {
  654. #ifdef CODEC_DEBUG_32PULLDOWN
  655. fprintf(fp_log,"clear pattern, i is %d, pulldown timer is %d, patternStart is %dn",i,state->ulPulldownActiveTimerIntl,patternStart);
  656. #endif
  657. // Set the removal pattern phase
  658. state->frameRemovalPattern = i;
  659. // If this is the right frame remove it!
  660. if (i == (PULLDOWN_HIST_LEN - 1) % 5)
  661. {
  662. // Set a counter that goes up if we have a consistent pattern 80+% of the time, down otherwise
  663. if ((timestamp - state->lastRemovedTimestamp > 145) &&
  664. (timestamp - state->lastRemovedTimestamp < 175))
  665. {
  666. if (state->ulPulldownActiveTimerIntl < 95)
  667. state->ulPulldownActiveTimerIntl += 5;
  668. else
  669. {
  670. state->ulPulldownActiveTimerIntl = 100;
  671. state->bInterlacedTelecineSeen = TRUE;
  672. }
  673. if (state->ulPulldownActiveTimerProg > 5)
  674. state->ulPulldownActiveTimerProg -= 5;
  675. else
  676. state->ulPulldownActiveTimerProg = 0;
  677. }
  678. else if (timestamp - state->lastRemovedTimestamp < 300)
  679. {
  680. if (state->ulPulldownActiveTimerIntl > 5)
  681. state->ulPulldownActiveTimerIntl -= 5;
  682. else
  683. state->ulPulldownActiveTimerIntl = 0;
  684. }
  685. state->lastRemovedTimestamp = timestamp;
  686. goto REMOVE_FRAME;
  687. }
  688. else if (i == ((PULLDOWN_HIST_LEN - 2) % 5))
  689. {
  690. obviousPatternFlag = TRUE;
  691. goto INTERLEAVE_ODD;
  692. }
  693. else 
  694. goto DO_NOTHING;
  695. }
  696. if ((inGroupMeanOdd[i]+inThresh[patternStart]*inGroupStdOdd[i] < outGroupMeanOdd[i] - outThresh[patternStart]*outGroupStdOdd[i]) &&
  697. (inGroupMeanEven[(i+2)%5]+inThresh[patternStart]*inGroupStdEven[(i+2)%5] < outGroupMeanEven[(i+2)%5] - outThresh[patternStart]*outGroupStdEven[(i+2)%5]) &&
  698. (inGroupMeanOdd[i]+inGroupStdOdd[i] < inGroupMeanEven[i]) &&
  699. (inGroupMeanEven[(i+2)%5]+inGroupStdEven[(i+2)%5] < inGroupMeanOdd[(i+2)%5]))
  700. {
  701. #ifdef CODEC_DEBUG_32PULLDOWN
  702. fprintf(fp_log,"clear pattern, i is %d, pulldown timer is %d, patternStart is %dn",i,state->ulPulldownActiveTimerIntl,patternStart);
  703. #endif
  704. // Set the removal pattern phase
  705. state->frameRemovalPattern=i;
  706. // If this is the right frame remove it!
  707. if (i == (PULLDOWN_HIST_LEN - 1) % 5)
  708. {
  709. // Set a counter that goes up if we have a consistent pattern 80+% of the time, down otherwise
  710. if ((timestamp - state->lastRemovedTimestamp > 145) &&
  711. (timestamp - state->lastRemovedTimestamp < 175))
  712. {
  713. if (state->ulPulldownActiveTimerIntl < 95)
  714. state->ulPulldownActiveTimerIntl += 5;
  715. else
  716. {
  717. state->ulPulldownActiveTimerIntl = 100;
  718. state->bInterlacedTelecineSeen = TRUE;
  719. }
  720. if (state->ulPulldownActiveTimerProg > 5)
  721. state->ulPulldownActiveTimerProg -= 5;
  722. else
  723. state->ulPulldownActiveTimerProg = 0;
  724. }
  725. else if (timestamp - state->lastRemovedTimestamp < 300)
  726. {
  727. if (state->ulPulldownActiveTimerIntl > 5)
  728. state->ulPulldownActiveTimerIntl -= 5;
  729. else
  730. state->ulPulldownActiveTimerIntl = 0;
  731. }
  732. state->lastRemovedTimestamp = timestamp;
  733. goto REMOVE_FRAME;
  734. }
  735. else if (i == ((PULLDOWN_HIST_LEN - 2) % 5))
  736. {
  737. obviousPatternFlag = TRUE;
  738. goto INTERLEAVE_EVEN;
  739. }
  740. else 
  741. goto DO_NOTHING;
  742. }
  743. }
  744. // Do we have a pretty clear pattern? Only trust this test 
  745. // if we have succeeded with the strongest test a couple of times
  746. for (i = 0; i < 5; i++)
  747. {
  748. if (groupValidFlagEven[i] == FALSE)
  749. continue;
  750. if (groupValidFlagOdd[i] == FALSE)
  751. continue;
  752. if (groupValidFlagEven[(i+2)%5] == FALSE)
  753. continue;
  754. if (groupValidFlagOdd[(i+2)%5] == FALSE)
  755. continue;
  756. if ((state->ulPulldownActiveTimerIntl > 10) &&
  757. (inGroupMeanEven[i]      + inThresh[patternStart]*inGroupStdEven[i]      < outMinEven[i]     ) &&
  758. (inGroupMeanOdd[(i+2)%5] + inThresh[patternStart]*inGroupStdOdd[(i+2)%5] < outMinOdd[(i+2)%5]) &&
  759. (inGroupMeanEven[i]      + inGroupStdEven[i]      < inGroupMeanOdd[i]       ) &&
  760. (inGroupMeanOdd[(i+2)%5] + inGroupStdOdd[(i+2)%5] < inGroupMeanEven[(i+2)%5]))
  761. {
  762. #ifdef CODEC_DEBUG_32PULLDOWN
  763. fprintf(fp_log,"pretty clear pattern, i is %d, pulldown timer is %d, patternStart is %dn",i,state->ulPulldownActiveTimerIntl,patternStart);
  764. #endif
  765. // Set the removal pattern phase
  766. state->frameRemovalPattern=i;
  767. // If this is the right frame remove it!
  768. if(i == (PULLDOWN_HIST_LEN - 1) % 5)
  769. {
  770. // Set a counter that goes up if we have a consistent pattern 80+% of the time, down otherwise
  771. if ((timestamp - state->lastRemovedTimestamp > 145) &&
  772. (timestamp - state->lastRemovedTimestamp < 175))
  773. {
  774. if (state->ulPulldownActiveTimerIntl < 95)
  775. state->ulPulldownActiveTimerIntl += 5;
  776. else
  777. {
  778. state->ulPulldownActiveTimerIntl = 100;
  779. state->bInterlacedTelecineSeen = TRUE;
  780. }
  781. if (state->ulPulldownActiveTimerProg > 5)
  782. state->ulPulldownActiveTimerProg -= 5;
  783. else
  784. state->ulPulldownActiveTimerProg = 0;
  785. }
  786. else if (timestamp - state->lastRemovedTimestamp < 300)
  787. {
  788. if (state->ulPulldownActiveTimerIntl > 5)
  789. state->ulPulldownActiveTimerIntl -= 5;
  790. else
  791. state->ulPulldownActiveTimerIntl = 0;
  792. }
  793. state->lastRemovedTimestamp = timestamp;
  794. goto REMOVE_FRAME;
  795. }
  796. else if (i == ((PULLDOWN_HIST_LEN - 2) % 5))
  797. {
  798. obviousPatternFlag = TRUE;
  799. goto INTERLEAVE_ODD;
  800. }
  801. else 
  802. goto DO_NOTHING;
  803. }
  804. if ((state->ulPulldownActiveTimerIntl > 10) &&
  805. (inGroupMeanOdd[i]        + inThresh[patternStart]*inGroupStdOdd[i]        < outMinOdd[i]       ) &&
  806. (inGroupMeanEven[(i+2)%5] + inThresh[patternStart]*inGroupStdEven[(i+2)%5] < outMinEven[(i+2)%5]) &&
  807. (inGroupMeanOdd[i]        + inGroupStdOdd[i]        < inGroupMeanEven[i]     ) &&
  808. (inGroupMeanEven[(i+2)%5] + inGroupStdEven[(i+2)%5] < inGroupMeanOdd[(i+2)%5]))
  809. {
  810. #ifdef CODEC_DEBUG_32PULLDOWN
  811. fprintf(fp_log,"pretty clear pattern, i is %d, pulldown timer is %d, patternStart is %dn",i,state->ulPulldownActiveTimerIntl,patternStart);
  812. #endif
  813. // Set the removal pattern phase
  814. state->frameRemovalPattern=i;
  815. // If this is the right frame remove it!
  816. if(i == (PULLDOWN_HIST_LEN - 1) % 5)
  817. {
  818. // Set a counter that goes up if we have a consistent pattern 80+% of the time, down otherwise
  819. if ((timestamp - state->lastRemovedTimestamp > 145) && 
  820. (timestamp - state->lastRemovedTimestamp < 175))
  821. {
  822. if (state->ulPulldownActiveTimerIntl < 95)
  823. state->ulPulldownActiveTimerIntl += 5;
  824. else
  825. {
  826. state->ulPulldownActiveTimerIntl = 100;
  827. state->bInterlacedTelecineSeen = TRUE;
  828. }
  829. if (state->ulPulldownActiveTimerProg > 5)
  830. state->ulPulldownActiveTimerProg -= 5;
  831. else
  832. state->ulPulldownActiveTimerProg = 0;
  833. }
  834. else if (timestamp - state->lastRemovedTimestamp < 300)
  835. {
  836. if (state->ulPulldownActiveTimerIntl > 5)
  837. state->ulPulldownActiveTimerIntl -= 5;
  838. else
  839. state->ulPulldownActiveTimerIntl = 0;
  840. }
  841. state->lastRemovedTimestamp = timestamp;
  842. goto REMOVE_FRAME;
  843. }
  844. else if (i == ((PULLDOWN_HIST_LEN - 2) % 5))
  845. {
  846. obviousPatternFlag = TRUE;
  847. goto INTERLEAVE_EVEN;
  848. }
  849. else 
  850. goto DO_NOTHING;
  851. }
  852. }
  853. }
  854. // Rule that maintains the pattern
  855. // No pattern, but things are VERY quiet, and we have been seeing a 3:2 pattern 
  856. if ((state->frameRemovalPattern == ((PULLDOWN_HIST_LEN-1)%5)) &&
  857. (state->ulPulldownActiveTimerIntl > 50) &&
  858. (inMaxEven [(PULLDOWN_HIST_LEN-1)%5] < 13) && 
  859. (inMaxOdd  [(PULLDOWN_HIST_LEN-1)%5] < 13) && 
  860. (outMaxOdd [(PULLDOWN_HIST_LEN-1)%5] < 13) &&
  861. (outMaxEven[(PULLDOWN_HIST_LEN-1)%5] < 13) && 
  862. (groupValidFlagEven[(PULLDOWN_HIST_LEN-1)%5] == TRUE) &&
  863. (groupValidFlagOdd[(PULLDOWN_HIST_LEN-1)%5] == TRUE))
  864. {
  865. #ifdef CODEC_DEBUG_32PULLDOWN
  866. fprintf(fp_log,"maintain pattern 1 - things are very quiet, pulldown timer is %d, patternStart is %dn",state->ulPulldownActiveTimerIntl,patternStart);
  867. #endif
  868. state->lastRemovedTimestamp = timestamp;
  869. state->checkNextFrameForInterlace = TRUE;
  870. goto REMOVE_FRAME;
  871. }
  872. // Rule that maintains the pattern
  873. // If we have been seeing consistent pulldown, 
  874. // and the last frame looks a bit interlaced, but it is in the right place.
  875. // This is a weak test.
  876. if ((state->frameRemovalPattern == ((PULLDOWN_HIST_LEN-1)%5)) &&
  877. (state->ulPulldownActiveTimerIntl > 50) &&
  878. (!state->checkNextFrameForInterlace) &&
  879. (state->pulldownSadHistEven[(PULLDOWN_HIST_LEN-1)] < (.6*state->pulldownSadHistOdd[(PULLDOWN_HIST_LEN-1)]) ||
  880.  state->pulldownSadHistOdd[(PULLDOWN_HIST_LEN-1)] < (.6*state->pulldownSadHistEven[(PULLDOWN_HIST_LEN-1)])))
  881. {
  882. #ifdef CODEC_DEBUG_32PULLDOWN
  883. fprintf(fp_log,"maintain pattern 2, pulldown timer is %d, patternStart is %dn",state->ulPulldownActiveTimerIntl,patternStart);
  884. #endif
  885. state->lastRemovedTimestamp = timestamp;
  886. state->checkNextFrameForInterlace = TRUE;
  887. goto REMOVE_FRAME;
  888. }
  889. // If we have been seeing consistent pulldown, and the last frame looks very interlaced.
  890. // This is a weak test
  891. if ((state->ulPulldownActiveTimerIntl > 50) &&
  892. (!state->checkNextFrameForInterlace) &&
  893. (
  894.  (state->pulldownSadHistEven[(PULLDOWN_HIST_LEN-1)] < (state->pulldownSadHistOdd[(PULLDOWN_HIST_LEN-1)]*.3)) &&
  895.  (state->pulldownSadHistOdd[(PULLDOWN_HIST_LEN-1)] > 9)
  896. ) || (
  897.  (state->pulldownSadHistOdd[(PULLDOWN_HIST_LEN-1)] < (state->pulldownSadHistEven[(PULLDOWN_HIST_LEN-1)]*.3)) &&
  898.  (state->pulldownSadHistEven[(PULLDOWN_HIST_LEN-1)] > 9)
  899. )
  900.    )
  901. {
  902. #ifdef CODEC_DEBUG_32PULLDOWN
  903. fprintf(fp_log,"things look interlaced, pulldown timer is %d, patternStart is %dn",state->ulPulldownActiveTimerIntl,patternStart);
  904. #endif
  905. state->lastRemovedTimestamp = timestamp;
  906. state->checkNextFrameForInterlace = TRUE;
  907. goto REMOVE_FRAME;
  908. }
  909. if(state->checkNextFrameForInterlace)
  910. {
  911. #ifdef CODEC_DEBUG_32PULLDOWN
  912. fprintf(fp_log,"checking frame for interlacen",i,state->ulPulldownActiveTimerIntl,patternStart);
  913. #endif
  914. state->checkNextFrameForInterlace = FALSE;
  915. if(state->interleaveEvenFlag)
  916. goto INTERLEAVE_EVEN;
  917. if(state->interleaveOddFlag)
  918. goto INTERLEAVE_ODD;
  919. }
  920. // Otherwise no pulldown!
  921. #ifdef CODEC_DEBUG_32PULLDOWN
  922. fprintf(fp_log,"no pattern, pulldown timer is %d, patternStart is %dn",state->ulPulldownActiveTimerIntl,patternStart);
  923. #endif
  924. if ((inMaxEven[(PULLDOWN_HIST_LEN-1)%5] > 30) || 
  925. (outMaxEven[(PULLDOWN_HIST_LEN-1)%5] > 30))
  926. {
  927. if (state->ulPulldownActiveTimerIntl > 0)
  928. state->ulPulldownActiveTimerIntl--;
  929. }
  930. // should we attempt progressive patterns?
  931. if ((lines > 242) || 
  932. (state->ulPulldownActiveTimerIntl > 90 && state->ulPulldownActiveTimerProg < 10))
  933. {
  934. goto NO_PATTERN;
  935. }
  936. PROGRESSIVE_TESTS:
  937. // Now test to see if there is an entire repeated frame
  938. for (patternStart = histLength; patternStart < PULLDOWN_HIST_LEN; patternStart += 5)
  939. {
  940. for (i = 0; i < 5; i++)
  941. {
  942. inGroupMean[i]  = 0;
  943. outGroupMean[i] = 0;
  944. inGroupStd[i]   = 0;
  945. outGroupStd[i]  = 0;
  946. inGroupCount    = 0;
  947. outGroupCount   = 0;
  948. outMin[i] = 255*255;
  949. outMax[i] = 0;
  950. inMax[i]  = 0;
  951. for (j = patternStart + i; j < PULLDOWN_HIST_LEN; j++)
  952. {
  953. if (state->pulldownSadHistAll[j] == MISSING_SAD ||
  954. state->pulldownSadHistAll[j] == UN_INIT_SAD)
  955. continue;
  956. if (((j - i) % 5) == 0)
  957. {
  958. inGroupMean[i] += state->pulldownSadHistAll[j];
  959. inGroupStd[i] += state->pulldownSadHistAll[j] * state->pulldownSadHistAll[j];
  960. if (inMax[i] < state->pulldownSadHistAll[j])
  961. inMax[i] = state->pulldownSadHistAll[j];
  962. inGroupCount++;
  963. }
  964. else
  965. {
  966. outGroupMean[i] += state->pulldownSadHistAll[j];
  967. outGroupStd[i] += state->pulldownSadHistAll[j] * state->pulldownSadHistAll[j];
  968. if (outMin[i] > state->pulldownSadHistAll[j])
  969. outMin[i] = state->pulldownSadHistAll[j];
  970. if (outMax[i] < state->pulldownSadHistAll[j])
  971. outMax[i] = state->pulldownSadHistAll[j];
  972. outGroupCount++;
  973. }
  974. }
  975. if ((inGroupCount > 1) && (outGroupCount > 3))
  976. {
  977. groupValidFlag[i] = TRUE;
  978. inGroupMean[i] = inGroupMean[i]/inGroupCount;
  979. if ((inGroupStd[i]/inGroupCount)-(inGroupMean[i]*inGroupMean[i]) > 0.0f)
  980. inGroupStd[i] = (float)sqrt((inGroupStd[i]/inGroupCount)-(inGroupMean[i]*inGroupMean[i]));
  981. else
  982. inGroupStd[i] = 0.0f;
  983. outGroupMean[i] = outGroupMean[i]/outGroupCount;
  984. if ((outGroupStd[i]/outGroupCount)-(outGroupMean[i]*outGroupMean[i]) > 0.0f)
  985. outGroupStd[i] = (float)sqrt((outGroupStd[i]/outGroupCount)-(outGroupMean[i]*outGroupMean[i]));
  986. else
  987. outGroupStd[i] = 0.0f;
  988. }
  989. else
  990. {
  991. groupValidFlag[i] = FALSE;
  992. inGroupMean[i] = 0;
  993. outGroupMean[i] = 0;
  994. inGroupStd[i] = 1;
  995. outGroupStd[i] = 1;
  996. }
  997. }
  998. // Do we have a clear pattern? Always trust this test.
  999. for (i = 0;i < 5; i++)
  1000. {
  1001. if ((inGroupMean[i]+inThresh[patternStart]*inGroupStd[i] < outGroupMean[i] - outThresh[patternStart]*outGroupStd[i]) &&
  1002. (groupValidFlag[i] == TRUE))
  1003. {
  1004. #ifdef CODEC_DEBUG_32PULLDOWN
  1005. fprintf(fp_log,"clear pattern, i is %d, pulldown timer is %d, patternStart is %dn",i,state->ulPulldownActiveTimerProg,patternStart);
  1006. #endif
  1007. // If this is the right frame remove it!
  1008. state->frameRemovalPattern=i;
  1009. if(i==(PULLDOWN_HIST_LEN-1)%5)
  1010. {
  1011. // Set a counter that goes up if we have a consistent pattern 80+% of the time, down otherwise
  1012. if ((timestamp - state->lastRemovedTimestamp > 145) &&
  1013. (timestamp - state->lastRemovedTimestamp < 175))
  1014. {
  1015. if (state->ulPulldownActiveTimerProg < 95)
  1016. state->ulPulldownActiveTimerProg += 5;
  1017. else
  1018. {
  1019. state->ulPulldownActiveTimerProg = 100;
  1020. state->bProgressiveTelecineSeen = TRUE;
  1021. }
  1022. if (state->ulPulldownActiveTimerIntl > 5)
  1023. state->ulPulldownActiveTimerIntl -= 5;
  1024. else
  1025. state->ulPulldownActiveTimerIntl = 0;
  1026. }
  1027. else if (timestamp - state->lastRemovedTimestamp < 300)
  1028. {
  1029. if (state->ulPulldownActiveTimerProg > 5)
  1030. state->ulPulldownActiveTimerProg -= 5;
  1031. else
  1032. state->ulPulldownActiveTimerProg = 0;
  1033. }
  1034. state->lastRemovedTimestamp = timestamp;
  1035. goto REMOVE_FRAME;
  1036. }
  1037. else 
  1038. goto DO_NOTHING;
  1039. }
  1040. }
  1041. // Do we have a pretty clear pattern? Only trust this test if we have succeeded with the strongest test a couple of times
  1042. for(i = 0; i < 5; i++)
  1043. {
  1044. if ((inGroupMean[i]+inThresh[patternStart]*inGroupStd[i] < outMin[i]) &&
  1045. (state->ulPulldownActiveTimerProg > 10) &&
  1046. (groupValidFlag[i] == TRUE))
  1047. {
  1048. #ifdef CODEC_DEBUG_32PULLDOWN
  1049. fprintf(fp_log,"pretty clear pattern, i is %d, pulldown timer is %d, patternStart is %dn",i,state->ulPulldownActiveTimerProg,patternStart);
  1050. #endif
  1051. // If this is the right frame remove it!
  1052. state->frameRemovalPattern = i;
  1053. if (i == (PULLDOWN_HIST_LEN-1)%5)
  1054. {
  1055. // Set a counter that goes up if we have a consistent pattern 80+% of the time, down otherwise
  1056. if ((timestamp - state->lastRemovedTimestamp > 145) && 
  1057. (timestamp - state->lastRemovedTimestamp < 175))
  1058. {
  1059. if (state->ulPulldownActiveTimerProg < 95)
  1060. state->ulPulldownActiveTimerProg += 5;
  1061. else
  1062. {
  1063. state->ulPulldownActiveTimerProg = 100;
  1064. state->bProgressiveTelecineSeen = TRUE;
  1065. }
  1066. if (state->ulPulldownActiveTimerIntl > 5)
  1067. state->ulPulldownActiveTimerIntl -= 5;
  1068. else
  1069. state->ulPulldownActiveTimerIntl = 0;
  1070. }
  1071. else if (timestamp - state->lastRemovedTimestamp < 300)
  1072. {
  1073. if (state->ulPulldownActiveTimerProg > 5)
  1074. state->ulPulldownActiveTimerProg -= 5;
  1075. else
  1076. state->ulPulldownActiveTimerProg = 0;
  1077. }
  1078. state->lastRemovedTimestamp = timestamp;
  1079. goto REMOVE_FRAME;
  1080. }
  1081. else 
  1082. goto DO_NOTHING;
  1083. }
  1084. }
  1085. // No pattern, but things are VERY quiet, and we have been seeing a 3:2 pattern 
  1086. if ((inMax[(PULLDOWN_HIST_LEN-1)%5] < 9) && (state->ulPulldownActiveTimerProg > 50) &&
  1087. (outMax[(PULLDOWN_HIST_LEN-1)%5] < 9) && (groupValidFlag[(PULLDOWN_HIST_LEN-1)%5] == TRUE) &&
  1088. (state->frameRemovalPattern==((PULLDOWN_HIST_LEN-1)%5))
  1089.    )
  1090. {
  1091. #ifdef CODEC_DEBUG_32PULLDOWN
  1092. fprintf(fp_log,"things are quiet, pulldown timer is %d, patternStart is %dn",state->ulPulldownActiveTimerProg,patternStart);
  1093. #endif
  1094. state->lastRemovedTimestamp = timestamp;
  1095. goto REMOVE_FRAME;
  1096. }
  1097. }
  1098. // If we have been seeing consistent pulldown, and the last two frames have been quiet frames.
  1099. // This is our weakest test
  1100. if (((state->pulldownSadHistAll[(PULLDOWN_HIST_LEN-1)] < 9) ||
  1101. (state->pulldownSadHistAll[(PULLDOWN_HIST_LEN-1)] < state->pulldownSadHistAll[(PULLDOWN_HIST_LEN-2)])) &&
  1102. (state->ulPulldownActiveTimerProg > 50) &&
  1103. (groupValidFlag[(PULLDOWN_HIST_LEN-1)%5] == TRUE)&&(state->frameRemovalPattern==((PULLDOWN_HIST_LEN-1)%5))
  1104.    )
  1105. {
  1106. #ifdef CODEC_DEBUG_32PULLDOWN
  1107. fprintf(fp_log,"things are quiet, pulldown timer is %d, patternStart is %dn",state->ulPulldownActiveTimerProg,patternStart);
  1108. #endif
  1109. state->lastRemovedTimestamp = timestamp;
  1110. goto REMOVE_FRAME;
  1111. }
  1112. // If we have been seeing consistent pulldown, and the last frame looks very interlaced.
  1113. // This is a weak test
  1114. if ((state->pulldownSadHistAll[(PULLDOWN_HIST_LEN-1)] < state->pulldownSadHistAll[(PULLDOWN_HIST_LEN-2)] * 0.5) &&
  1115. (state->ulPulldownActiveTimerProg > 50) &&
  1116. (groupValidFlag[(PULLDOWN_HIST_LEN-1)%5] == TRUE))
  1117. {
  1118. state->frameRemovalPattern = (PULLDOWN_HIST_LEN-1)%5;
  1119. #ifdef CODEC_DEBUG_32PULLDOWN
  1120. fprintf(fp_log,"things look interlaced, pulldown timer is %d, patternStart is %dn",state->ulPulldownActiveTimerProg,patternStart);
  1121. #endif
  1122. state->lastRemovedTimestamp = timestamp;
  1123. goto REMOVE_FRAME;
  1124. }
  1125. // Otherwise no pulldown!
  1126. #ifdef CODEC_DEBUG_32PULLDOWN
  1127. fprintf(fp_log,"no pattern, pulldown timer is %d, patternStart is %dn",state->ulPulldownActiveTimerProg,patternStart);
  1128. #endif
  1129. if((inMax[(PULLDOWN_HIST_LEN-1)%5] > 30) || (outMax[(PULLDOWN_HIST_LEN-1)%5] >30))
  1130. if (state->ulPulldownActiveTimerProg > 0)
  1131. state->ulPulldownActiveTimerProg--;
  1132. NO_PATTERN:
  1133. // If there was no clear pattern, do nothing
  1134. state->checkNextFrameForProgressive = FALSE;
  1135. return INVTELE_RESULT_NO_PATTERN;
  1136. INTERLEAVE_ODD:
  1137. state->checkNextFrameForProgressive = FALSE;
  1138. // Test if data should be re-interleaved.
  1139. // Look at cross difference of old vs. re-stitched. Only replace if better
  1140. if (obviousPatternFlag == FALSE || sceneChangeFlag == TRUE)
  1141. {
  1142. switch (state->impl_id)
  1143. {
  1144. #ifdef ALLOW_MMX_INVTELE
  1145. case INVTELE_IMPL_ID_MMX:
  1146. {
  1147. RestitchCheck_MMX(data, prevData, 
  1148. pels, lines, pels, &sumOld, &sumNew);
  1149. }
  1150. break;
  1151. #endif
  1152. case INVTELE_IMPL_ID_C:
  1153. default:
  1154. {
  1155. pNew = (LONG32 *)(data);
  1156. pOld = (LONG32 *)(prevData);
  1157. for (i = 0; i < lines; i += 2)  //  only do the luma.
  1158. {
  1159. for(j = 0; j < ll; j++)
  1160. {
  1161. temp = (float)((pNew[j]&0xff00) - (pNew[j+ll]&0xff00));
  1162. sumOld += (temp*temp);
  1163. temp = (float)((pNew[j]&0xff00) - (pOld[j+ll]&0xff00));
  1164. sumNew += (temp*temp);
  1165. }
  1166. pOld += 2*ll;
  1167. pNew += 2*ll;
  1168. }
  1169. }
  1170. break;
  1171. }
  1172. if (sumNew > sumOld)
  1173. {
  1174. return INVTELE_RESULT_FRAME_OK;
  1175. }
  1176. }
  1177. state->interleaveOddFlag = TRUE;
  1178. #ifdef CODEC_DEBUG_32PULLDOWN
  1179. fprintf(fp_log,"interleaving oddn");
  1180. #endif
  1181. // Re-interleave
  1182. pNew = ((LONG32 *)data)+ll;
  1183. pOld = ((LONG32 *)prevData)+ll;
  1184. for (k = 1; k < lines; k += 2)  //  only do the luma.
  1185. {
  1186. memcpy(pNew,pOld,sizeof(ULONG32)*ll); /* Flawfinder: ignore */
  1187. pOld+=2*ll;
  1188. pNew+=2*ll;
  1189. }
  1190. return INVTELE_RESULT_FRAME_OK;
  1191. INTERLEAVE_EVEN:
  1192. state->checkNextFrameForProgressive = FALSE;
  1193. // Test if data should be re-interleaved.
  1194. // Look at cross difference of old vs. re-stitched. Only replace if better
  1195. if (obviousPatternFlag == FALSE || sceneChangeFlag == TRUE)
  1196. {
  1197. switch (state->impl_id)
  1198. {
  1199. #ifdef ALLOW_MMX_INVTELE
  1200. case INVTELE_IMPL_ID_MMX:
  1201. {
  1202. RestitchCheck_MMX(data + pels, prevData + pels, 
  1203. pels, lines - 2, pels, &sumOld, &sumNew);
  1204. }
  1205. break;
  1206. #endif
  1207. case INVTELE_IMPL_ID_C:
  1208. default:
  1209. {
  1210. pNew = (LONG32 *)(data);
  1211. pOld = (LONG32 *)(prevData);
  1212. for (i = 0; i < lines; i += 2)  //  only do the luma.
  1213. {
  1214. for(j = 0; j < ll; j++)
  1215. {
  1216. temp = (float)((pNew[j]&0xff00) - (pNew[j+ll]&0xff00));
  1217. sumOld += (temp*temp);
  1218. temp = (float)((pNew[j+ll]&0xff00) - (pOld[j]&0xff00));
  1219. sumNew += (temp*temp);
  1220. }
  1221. pOld+=2*ll;
  1222. pNew+=2*ll;
  1223. }
  1224. }
  1225. break;
  1226. }
  1227. if (sumNew > sumOld)
  1228. {
  1229. return INVTELE_RESULT_FRAME_OK;
  1230. }
  1231. }
  1232. state->interleaveEvenFlag = TRUE;
  1233. #ifdef CODEC_DEBUG_32PULLDOWN
  1234. fprintf(fp_log,"interleaving evenn");
  1235. #endif
  1236. // Re-interleave
  1237. pNew = ((LONG32 *)data);
  1238. pOld = ((LONG32 *)prevData);
  1239. for (k = 0; k < lines; k += 2)  //  only do the luma.
  1240. {
  1241. memcpy(pNew,pOld,sizeof(ULONG32)*ll); /* Flawfinder: ignore */
  1242. pOld+=2*ll;
  1243. pNew+=2*ll;
  1244. }
  1245. return INVTELE_RESULT_FRAME_OK;
  1246. DO_NOTHING:
  1247. // One final check in this case
  1248. // If we are here, we think the frame is progressive.
  1249. // If we think the previous frame was also progressive, then
  1250. // the odd and even SADs should be somewhat similar.  If not,
  1251. // we're in trouble.
  1252. if (state->checkNextFrameForProgressive)
  1253. {
  1254. if (state->ulPulldownActiveTimerProg < 10 &&
  1255. state->ulPulldownActiveTimerIntl > 90 &&
  1256. (sumEven > 8 * sumOdd || sumOdd > 8 * sumEven))
  1257. {
  1258. goto NO_PATTERN;
  1259. }
  1260. if (sceneChangeFlag == TRUE)
  1261. {
  1262. // Just return here because we want to be sure
  1263. // state->checkNextFrameForProgressive is TRUE
  1264. return INVTELE_RESULT_NO_PATTERN;
  1265. }
  1266. }
  1267. state->checkNextFrameForProgressive = TRUE;
  1268. return INVTELE_RESULT_FRAME_OK;
  1269. REMOVE_FRAME:
  1270. #ifdef CODEC_DEBUG_32PULLDOWN
  1271. fprintf(fp_log,"removing framen");
  1272. #endif
  1273. state->checkNextFrameForProgressive = FALSE;
  1274. return INVTELE_RESULT_DROP_FRAME;
  1275. TOO_EARLY:
  1276. state->checkNextFrameForProgressive = FALSE;
  1277. return INVTELE_RESULT_TOO_EARLY;
  1278. }
  1279. // Platform specific SSD functions
  1280. #ifdef ALLOW_MMX_INVTELE
  1281. void
  1282. SumSqaredFrameDiff_MMX(
  1283. unsigned char *frame, 
  1284. unsigned char *prev_frame,
  1285. int pels,
  1286. int lines,
  1287. int pitch,
  1288. float *ssd_odd,
  1289. float *ssd_even)
  1290. {
  1291. unsigned int res_odd[2];
  1292. unsigned int res_even[2];
  1293. float pel_avg;
  1294. const unsigned int mask[2] = {0x00FF00FF, 0x00FF00FF};
  1295. int line_shift;
  1296. int pels_div8;
  1297. pels_div8 = (pels >> 3); // round down
  1298. line_shift = ((pitch) - (pels & ~7));
  1299. __asm {
  1300. mov ecx, lines // ecx -> lines
  1301. shr ecx, 1 // ecx -> lines/2
  1302. mov esi, frame // esi -> current frame
  1303. mov edi, prev_frame // edi -> previous frame
  1304. movq mm5, [mask]
  1305. pxor mm6, mm6 // mm6 -> odd ssd
  1306. pxor mm7, mm7 // mm7 -> even ssd
  1307. ALIGN 16
  1308. line_loop:
  1309. mov ebx, pels_div8 // ebx -> pels/8 (rounded down)
  1310. ALIGN 16
  1311. pel_loop_even:
  1312. movq mm0,[esi]
  1313. movq mm1,[edi]
  1314. pand mm0, mm5
  1315. pand mm1, mm5
  1316. psubw mm0, mm1
  1317. pmaddwd mm0, mm0
  1318. paddd mm6, mm0
  1319. lea esi,[esi+8]
  1320. lea edi,[edi+8]
  1321. dec ebx
  1322. jnz pel_loop_even
  1323. add esi, line_shift; // move esi to the next line
  1324. add edi, line_shift; // move edi to the next line
  1325. mov ebx, pels_div8 // ebx -> pels/8 (rounded down)
  1326. ALIGN 16
  1327. pel_loop_odd:
  1328. movq mm0,[esi]
  1329. movq mm1,[edi]
  1330. pand mm0, mm5
  1331. pand mm1, mm5
  1332. psubw mm0, mm1
  1333. pmaddwd mm0, mm0
  1334. paddd mm7, mm0
  1335. lea esi,[esi+8]
  1336. lea edi,[edi+8]
  1337. dec ebx
  1338. jnz pel_loop_odd
  1339. add esi, line_shift; // move esi to the next line
  1340. add edi, line_shift; // move edi to the next line
  1341. dec ecx
  1342. jnz line_loop
  1343. movq res_odd, mm6
  1344. movq res_even, mm7
  1345. emms
  1346. }
  1347. // fill "even" result
  1348. pel_avg = (float)(res_even[0] + res_even[1]);
  1349. pel_avg /= (float)((pels*lines)>>2);
  1350. *ssd_even = pel_avg;
  1351. // fill "odd" result
  1352. pel_avg = (float)(res_odd[0] + res_odd[1]);
  1353. pel_avg /= (float)((pels*lines)>>2);
  1354. *ssd_odd = pel_avg;
  1355. }
  1356. void
  1357. RestitchCheck_MMX(
  1358. unsigned char *frame, 
  1359. unsigned char *prev_frame,
  1360. int pels,
  1361. int lines,
  1362. int pitch,
  1363. float *ssd_new,
  1364. float *ssd_old)
  1365. {
  1366. unsigned int res_new[2];
  1367. unsigned int res_old[2];
  1368. const unsigned int mask[2] = {0x00FF00FF, 0x00FF00FF};
  1369. int line_shift;
  1370. int pels_div8;
  1371. pels_div8 = (pels >> 3); // round down
  1372. line_shift = ((pitch << 1) - (pels & ~7));
  1373. __asm {
  1374. mov ecx, lines // ecx -> lines
  1375. shr ecx, 1 // ecx -> lines/2
  1376. mov esi, frame // esi -> current frame
  1377. mov edi, prev_frame // edi -> previous frame
  1378. mov edx, pitch // pitch
  1379. lea edi, [edi+edx] // edi -> previous frame + pitch
  1380. movq mm5, [mask]
  1381. pxor mm6, mm6 // mm6 -> odd ssd
  1382. pxor mm7, mm7 // mm7 -> even ssd
  1383. ALIGN 16
  1384. line_loop:
  1385. mov ebx, pels_div8 // ebx -> pels/8 (rounded down)
  1386. ALIGN 16
  1387. pel_loop:
  1388. movq mm0,[esi]
  1389. movq mm1,[esi + edx]
  1390. movq mm2,[edi]
  1391. pand mm0, mm5
  1392. pand mm1, mm5
  1393. pand mm2, mm5
  1394. psubw mm1, mm0
  1395. pmaddwd mm1, mm1
  1396. paddd mm6, mm1
  1397. psubw mm2, mm0
  1398. pmaddwd mm2, mm2
  1399. paddd mm7, mm2
  1400. lea esi, [esi+8]
  1401. lea edi, [edi+8]
  1402. dec ebx
  1403. jnz pel_loop
  1404. add esi, line_shift // move esi down 2 lines
  1405. add edi, line_shift // move edi down 2 lines
  1406. dec ecx
  1407. jnz line_loop
  1408. movq res_new, mm6
  1409. movq res_old, mm7
  1410. emms
  1411. }
  1412. // fill "new" result
  1413. *ssd_new = (float)(res_new[0] + res_new[1]);
  1414. // fill "old" result
  1415. *ssd_old = (float)(res_old[0] + res_old[1]);
  1416. }
  1417. #endif