686 { |
688 { |
687 MetaDataReady(KErrCompletion); |
689 MetaDataReady(KErrCompletion); |
688 } |
690 } |
689 } |
691 } |
690 |
692 |
|
693 /* Determines whether a frame contains sufficient data to be considered an useful frame. |
|
694 * The logic scans a set of pixels to confirm: |
|
695 * too bright or too dark pixels are not taken into account. Only mid brightness pixels will be considered |
|
696 * if less than minSamples valid samples the frame is rejected. |
|
697 * if the mode is more frequent than maxModePrct% the frame is rejected. This is useful to reject the MPAA rating or other simple logos |
|
698 * if the contrast is too low (max - min) frame is rejected |
|
699 * if the standard deviation is too low frame is rejected. |
|
700 */ |
|
701 |
691 TBool CTneSession::IsGoodFrame(TUint8* aYUVDataPtr) |
702 TBool CTneSession::IsGoodFrame(TUint8* aYUVDataPtr) |
692 { |
703 { |
693 |
|
694 TInt i; |
704 TInt i; |
|
705 TInt ySize = iWidth*iHeight; |
|
706 TUint8 * resetYUVPtr = aYUVDataPtr; |
|
707 |
|
708 // only these luminances are taken into account |
|
709 TInt minSamples = 5; |
|
710 TInt tooDark = 30; |
|
711 TInt tooBright = 240; |
|
712 |
|
713 // Defines how much data we analyze from the image to analyze its validity |
|
714 TInt pixelSkips = iHeight; // scans about 1 to 3 pixels per line depending on aspect ratio |
|
715 |
|
716 // average luminance profiling |
|
717 TInt runningSum = 0; |
|
718 TInt numberOfSamples = 0; |
|
719 TInt averageValue = 0; |
|
720 |
|
721 // contrast profiling |
695 TInt minValue = 255; |
722 TInt minValue = 255; |
696 TInt maxValue = 0; |
723 TInt maxValue = 0; |
|
724 TInt minMaxDeltaThreshold = 20; |
|
725 |
|
726 // mode profiling |
|
727 int mode = 0; |
|
728 int modeSamples = 0; |
|
729 int histogram[255] = {0}; |
|
730 int maxModePrct = 69; |
|
731 |
|
732 // standard deviation profiling |
|
733 TInt minStdDeviation = 5; |
|
734 TUint32 residualsum = 0; |
|
735 TReal stdDeviation = 0; |
|
736 |
|
737 // Exit value |
697 TBool goodFrame = ETrue; |
738 TBool goodFrame = ETrue; |
698 TInt runningSum=0; |
739 |
699 TInt averageValue=0; |
740 for(i=0, numberOfSamples=0; i<ySize; i+=pixelSkips, aYUVDataPtr+=pixelSkips) |
700 TInt pixelSkips = 4; |
741 { |
701 TInt numberOfSamples=0; |
742 if ( (*aYUVDataPtr>tooDark) && (*aYUVDataPtr<tooBright) ) |
702 TInt minMaxDeltaThreshold = 20; |
743 { |
703 TInt extremeRegionThreshold = 20; |
744 runningSum += *aYUVDataPtr; |
704 TInt ySize = iWidth*iHeight; |
745 if(*aYUVDataPtr > maxValue) |
705 |
746 maxValue = *aYUVDataPtr; |
706 // gather image statistics |
747 if(*aYUVDataPtr < minValue) |
707 for(i=0, numberOfSamples=0; i<ySize; i+=pixelSkips, aYUVDataPtr+=pixelSkips, numberOfSamples++) |
748 minValue = *aYUVDataPtr; |
708 { |
749 histogram[*aYUVDataPtr]++; |
709 |
750 numberOfSamples++; |
710 |
751 } |
711 runningSum += *aYUVDataPtr; |
752 } |
712 if(*aYUVDataPtr > maxValue) |
753 |
713 maxValue = *aYUVDataPtr; |
754 if (numberOfSamples < minSamples) |
714 if(*aYUVDataPtr < minValue) |
755 { |
715 minValue = *aYUVDataPtr; |
756 //FLOG(_L("CTneSession::IsGoodFrame too few good samples")); |
716 } |
|
717 //VDASSERT(numberOfSamples,10); |
|
718 if (numberOfSamples == 0) |
|
719 { |
|
720 FLOG(_L("CTneSession::IsGoodFrame numberOfSamples is zero")); |
|
721 } |
|
722 else |
|
723 { |
|
724 averageValue = runningSum/numberOfSamples; |
|
725 } |
|
726 |
|
727 // make decision based statistics |
|
728 if((maxValue - minValue) < minMaxDeltaThreshold) |
|
729 goodFrame = EFalse; |
757 goodFrame = EFalse; |
730 else |
758 } |
731 { |
759 else |
732 if(averageValue < (minValue + extremeRegionThreshold) || |
760 { |
733 averageValue > (maxValue - extremeRegionThreshold)) |
761 // Find the mode |
734 goodFrame = EFalse; |
762 for (i=0; i<255; i++) |
735 } |
763 { |
|
764 if (histogram[i] > modeSamples) |
|
765 { |
|
766 modeSamples = histogram[i]; |
|
767 mode = i; |
|
768 } |
|
769 } |
|
770 // Add the mode and most immediate values, as compression may add artifacts that disperse its value |
|
771 for (i = mode-2, modeSamples = 0; i < mode+3; i++) |
|
772 { |
|
773 modeSamples += histogram[i]; |
|
774 } |
|
775 |
|
776 if (modeSamples * 100 / numberOfSamples > maxModePrct) |
|
777 { |
|
778 //FLOG(_L("Mode (%d) in over %d%% of the image\n", mode, modeSamples * 100 / numberOfSamples); |
|
779 goodFrame = false; |
|
780 } |
|
781 else |
|
782 { |
|
783 averageValue = runningSum / numberOfSamples; |
|
784 // Rescan the frame now that we the average value is known |
|
785 aYUVDataPtr = resetYUVPtr; |
|
786 |
|
787 |
|
788 // Calculate the sum of residuals: (pixel - avgpixel)^2 |
|
789 for(i=0; i<ySize; i+=pixelSkips, aYUVDataPtr+=pixelSkips) |
|
790 { |
|
791 if ( (*aYUVDataPtr>tooDark) && (*aYUVDataPtr<tooBright) ) |
|
792 { |
|
793 residualsum += (*aYUVDataPtr - averageValue) * (*aYUVDataPtr - averageValue); |
|
794 } |
|
795 } |
|
796 |
|
797 // Get the standard deviation |
|
798 Math::Sqrt(stdDeviation , residualsum / numberOfSamples); |
|
799 |
|
800 if (stdDeviation < minStdDeviation) |
|
801 { |
|
802 //FLOG(_L("CTneSession::IsGoodFrame too low StdDeviation: %f"), stdDeviation); |
|
803 goodFrame = EFalse; |
|
804 } |
|
805 else if((maxValue - minValue) < minMaxDeltaThreshold) |
|
806 { |
|
807 //FLOG(_L("CTneSession::IsGoodFrame too little difference between brightest and darkest pixel")); |
|
808 goodFrame = EFalse; |
|
809 } |
|
810 } |
|
811 } |
|
812 |
736 return goodFrame; |
813 return goodFrame; |
737 } |
814 } |
738 |
815 |
739 TInt CTneSession::GetStartingTime(TUint &uStartingTime) |
816 TInt CTneSession::GetStartingTime(TUint &uStartingTime) |
740 { |
817 { |