invtelec.cpp
Upload User: zhongxx05
Upload Date: 2007-06-06
Package Size: 33641k
Code Size: 46k
Category:

Symbian

Development Platform:

C/C++

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