mmplugins/mmfwplugins/src/Plugin/Controller/Video/AviPlayController/srtdecoder/srtdecoder.cpp
changeset 0 b8ed18f6c07b
child 2 5c1df44f2eed
equal deleted inserted replaced
-1:000000000000 0:b8ed18f6c07b
       
     1 // Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies).
       
     2 // All rights reserved.
       
     3 // This component and the accompanying materials are made available
       
     4 // under the terms of "Eclipse Public License v1.0"
       
     5 // which accompanies this distribution, and is available
       
     6 // at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     7 //
       
     8 // Initial Contributors:
       
     9 // Nokia Corporation - initial contribution.
       
    10 //
       
    11 // Contributors:
       
    12 //
       
    13 // Description:
       
    14 //
       
    15 
       
    16 #include <bitdev.h> 
       
    17 #include <fbs.h> 
       
    18 #include <gdi.h> 
       
    19 #include <utf.h> 
       
    20 
       
    21 #include "subtitlesource.h"
       
    22 #include "srtdecoder.h"
       
    23 #include "srtframe.h"
       
    24 
       
    25 // Define the separators for each subtitle frame in SRT file
       
    26 _LIT8(KSrtFrameSeparator1, "\r\n\r\n" );
       
    27 _LIT8(KSrtFrameSeparator2, "\n\n" );
       
    28 
       
    29 // The length of the separators
       
    30 const TInt KSrtFrameSeparator1Len = 4;
       
    31 const TInt KSrtFrameSeparator2Len = 2;
       
    32 
       
    33 // The margin size
       
    34 const TInt KSrtBmpMarginWidth = 6;
       
    35 const TInt KSrtBmpMarginHeight = 6;
       
    36 
       
    37 // The width of subtitle region is the same as the width of the video region, while the height is 33 
       
    38 // percent of the height of the video region. 
       
    39 const TInt KSrtSubtitleRegionYFactor = 33;
       
    40 
       
    41 // Define panic category
       
    42 _LIT(KSrtSubtitleDecoderPanicCategory, "SrtSubDec");
       
    43 
       
    44 // TSrtSubtitleDecoderPanics is an enumeration with the following entries:
       
    45 // EBadCall indicates a bad call
       
    46 enum TSrtSubtitleDecoderPanics
       
    47     {
       
    48     ESrtBadCall = 1,
       
    49     ESrtUnexpected,
       
    50     ESrtNotStarted,
       
    51     ESrtAlreadyStarted
       
    52     };
       
    53 
       
    54 
       
    55 /** Constructor with a reference to the subtitle source 
       
    56     
       
    57 @param aSubtitleSource a reference to the subtitle source
       
    58 */ 
       
    59 CSrtSubtitleDecoder::CSrtSubtitleDecoder(MSubtitleSource& aSubtitleSource) : 
       
    60     iSource(aSubtitleSource)
       
    61     {
       
    62     }
       
    63 
       
    64 EXPORT_C CSrtSubtitleDecoder::~CSrtSubtitleDecoder()
       
    65     {
       
    66     delete iFrameParser;
       
    67     iDecodeBuffer.Close();
       
    68     }
       
    69 
       
    70 /** Allocates and constructs a srt subtitle decoder 
       
    71     
       
    72 @param aSubtitleSource a reference to the subtitle source
       
    73 @return A pointer to the new object. 
       
    74 @leave If an error occurs, the method will leave with a system-wide error code. 
       
    75 */    
       
    76 EXPORT_C CSrtSubtitleDecoder* CSrtSubtitleDecoder::NewL(MSubtitleSource& aSubtitleSource)
       
    77     {
       
    78     CSrtSubtitleDecoder* self = new(ELeave) CSrtSubtitleDecoder(aSubtitleSource);
       
    79     CleanupStack::PushL(self);
       
    80     self->ConstructL();
       
    81     CleanupStack::Pop(self);
       
    82     return self;
       
    83     }
       
    84 
       
    85 /** Initialises the decoder
       
    86     
       
    87 @leave If an error occurs, the method will leave with a system-wide error code.
       
    88 */
       
    89 void CSrtSubtitleDecoder::ConstructL()
       
    90     {
       
    91     iFrameParser = CSrtFrame::NewL();
       
    92     iDecodeBuffer.Create(KSubtitleDecoderBufferLength);
       
    93     }
       
    94     
       
    95 EXPORT_C TInt CSrtSubtitleDecoder::CalculateSubtitleRegion(const TRect& aScreenSize, TRect& aSubtitleRegion)
       
    96     {
       
    97     // TRect::IsEmpty is not used because the following test tests the minus values.
       
    98     if ((aScreenSize.iBr.iX < 0) || (aScreenSize.iBr.iY < 0) || 
       
    99         (aScreenSize.iTl.iX < 0) || (aScreenSize.iTl.iY < 0))
       
   100         {
       
   101         return KErrArgument;  
       
   102         }
       
   103     
       
   104     if ((aScreenSize.iBr.iX <= aScreenSize.iTl.iX) || (aScreenSize.iBr.iY <= aScreenSize.iTl.iY))
       
   105         {
       
   106         return KErrArgument; 
       
   107         }
       
   108     
       
   109     TPoint topleft;
       
   110     
       
   111     topleft.iX = aScreenSize.iTl.iX;
       
   112     topleft.iY = aScreenSize.iTl.iY + aScreenSize.Height() * (100 - KSrtSubtitleRegionYFactor) / 100; 
       
   113     
       
   114     aSubtitleRegion.SetRect(topleft, aScreenSize.iBr);
       
   115     
       
   116     return KErrNone;
       
   117     }
       
   118 
       
   119 /** Calculate the number of the characters in the first line. The full words are supposed to be displayed 
       
   120 unless the length of a word is bigger than one line space. 
       
   121 
       
   122 @param aFont The font in current use.
       
   123 @param aText The descriptor
       
   124 @param aWidthInPixels The available width for character display.
       
   125 @param aNumOfCharsToSkip The number of characters to skip, it can be 0, 1 (\n) or 2 (\r\n) 
       
   126 @return The number of characters which will be able to be displayed without exceeding the specified width. 
       
   127 The count starts from the beginning of the descriptor. 
       
   128 */   
       
   129 TInt CSrtSubtitleDecoder::CalculateCharsInNextLine(const CFont &aFont, const TDesC &aText, TInt aWidthInPixels, TInt& aNumOfCharsToSkip)
       
   130     {
       
   131     const TChar KMMFSubtitleCharSpace(' ');
       
   132     const TChar KMMFSubtitleCharCR('\r');
       
   133     const TChar KMMFSubtitleCharLF('\n');
       
   134     TInt charsInLine = aFont.TextCount(aText, aWidthInPixels);
       
   135     aNumOfCharsToSkip = 0;
       
   136         
       
   137     if (charsInLine < aText.Length())
       
   138         {
       
   139         // For finding the last space of a descriptor which is not very big, using a simple loop 
       
   140         // shall be more efficient than using TLex
       
   141         for (TInt i = charsInLine; i > 0; i--)
       
   142             {
       
   143             if (KMMFSubtitleCharSpace == aText[i - 1])
       
   144                 {
       
   145                 charsInLine = i;
       
   146                 break;
       
   147                 }
       
   148             }
       
   149         }
       
   150     
       
   151     // Check \r\n or \n, the following loop is more efficient than TDesC::Find() in most cases 
       
   152     // because both \r\n and \n are handled in one loop. 
       
   153     for (TInt j = 0; j < charsInLine; j++)
       
   154         {
       
   155         if (KMMFSubtitleCharLF == aText[j])
       
   156             {
       
   157             if (j > 0)
       
   158                 {
       
   159                 // ignore \r if there is a \n
       
   160                 if (KMMFSubtitleCharCR == aText[j - 1])
       
   161                     {
       
   162                     charsInLine = j;
       
   163                     aNumOfCharsToSkip = 2;
       
   164                     }
       
   165                 else
       
   166                     {
       
   167                     charsInLine = j + 1;
       
   168                     aNumOfCharsToSkip = 1;
       
   169                     }
       
   170                 }
       
   171             else
       
   172                 {
       
   173                 charsInLine = j + 1;
       
   174                 aNumOfCharsToSkip = 1;
       
   175                 }
       
   176             break;
       
   177             }
       
   178         }
       
   179 
       
   180     return charsInLine;
       
   181     }
       
   182 
       
   183 /** Based on a descriptor containing a SRT subtitle frame, the function generates a single frame of 
       
   184 subtitle animation for the current time and outputs the region of the subtitle frame that has been 
       
   185 updated.
       
   186 
       
   187 @param aContent The subtitle frame as a descriptor
       
   188 @param aSubtitleFrame Reference to the current subtitle frame
       
   189 @param aDirtyRegion The decoder outputs the region of the subtitle frame that has been updated. 
       
   190     i.e. the region that now contains new subtitle content.
       
   191 @leave If an error occurs, the method will leave with a system-wide error code. 
       
   192 */
       
   193 void CSrtSubtitleDecoder::DecodeSubtitleContentL(const TDesC8& aContent, CFbsBitmap& aSubtitleFrame, TRect& aDirtyRegion)
       
   194     {
       
   195     TSize bmpSize = aSubtitleFrame.SizeInPixels(); 
       
   196     TSize modifiedBmpSize;
       
   197     
       
   198     // the following value of "2" means two side of margin. 
       
   199     modifiedBmpSize.iHeight = bmpSize.iHeight - KSrtBmpMarginHeight * 2;
       
   200     modifiedBmpSize.iWidth = bmpSize.iWidth - KSrtBmpMarginWidth * 2;
       
   201     
       
   202     // test if the size of the bitmap is valid after taking margin into account   
       
   203     if ((modifiedBmpSize.iHeight > 0) && (modifiedBmpSize.iWidth > 0))
       
   204         {
       
   205         // prepare and populate the bitmap
       
   206         CFbsBitmapDevice* bmpDevice = CFbsBitmapDevice::NewL(&aSubtitleFrame);
       
   207         CleanupStack::PushL(bmpDevice);
       
   208         
       
   209         CFbsBitGc* bitmapContext = CFbsBitGc::NewL(); //Create a GC to draw to the bitmap
       
   210         bitmapContext->Activate(bmpDevice);
       
   211         
       
   212         CleanupStack::PushL(bitmapContext);
       
   213         
       
   214         bitmapContext->SetDrawMode(CGraphicsContext::EDrawModeWriteAlpha);
       
   215         
       
   216         // Use a white color (R=255, G=255, B=255) with alpha value of 0. 
       
   217         TRgb transparentWhite(255, 255, 255, 0);
       
   218         bitmapContext->SetBrushColor(transparentWhite);
       
   219         
       
   220         bitmapContext->Clear(); 
       
   221         
       
   222         bitmapContext->SetDrawMode(CGraphicsContext::EDrawModePEN);
       
   223         
       
   224         bitmapContext->SetPenStyle(CGraphicsContext::ESolidPen);
       
   225         bitmapContext->SetPenColor(KRgbBlack);
       
   226         
       
   227         HBufC* content = CnvUtfConverter::ConvertToUnicodeFromUtf8L(aContent);
       
   228         CleanupStack::PushL(content);
       
   229         
       
   230         // try to set up font
       
   231         CFont *font = NULL;
       
   232         TFontSpec fontSpec(KSrtTargetTypefaceName, KSrtTargetTypefaceHeightInTwips);
       
   233         User::LeaveIfError(bmpDevice->GetNearestFontToDesignHeightInTwips(font, fontSpec));
       
   234             
       
   235         bitmapContext->UseFont(font);
       
   236 
       
   237         TInt maxCharWidthInPixels = font->MaxCharWidthInPixels();
       
   238         TInt heightInPixels = font->HeightInPixels();
       
   239         TInt maxLines = modifiedBmpSize.iHeight / heightInPixels;    
       
   240         TInt maxCharsPerLine = modifiedBmpSize.iWidth / maxCharWidthInPixels; 
       
   241         TInt charsInLine = 0;
       
   242         TInt currentRow = 0;
       
   243         TPoint drawPosition;
       
   244         drawPosition.iX = KSrtBmpMarginWidth;
       
   245         drawPosition.iY = KSrtBmpMarginHeight + heightInPixels;
       
   246         TInt unvisitedChars = content->Length();
       
   247         TInt lineStartPos = 0;
       
   248         TInt numOfCharsToSkip = 0;
       
   249         
       
   250         if ((maxLines > 0) && (maxCharsPerLine > 0))
       
   251             {
       
   252             do
       
   253                 {
       
   254                 TPtrC ptrUnvisitedDesc = content->Right(unvisitedChars);                
       
   255                 
       
   256                 charsInLine = CalculateCharsInNextLine(*font, ptrUnvisitedDesc, modifiedBmpSize.iWidth, numOfCharsToSkip); 
       
   257                 if (charsInLine > 0)
       
   258                     {
       
   259                     if (charsInLine > numOfCharsToSkip)
       
   260                         {
       
   261                         TPtrC ptrLine = content->Mid(lineStartPos, charsInLine - numOfCharsToSkip);
       
   262                         // try to draw text line by line
       
   263                         // Note that aPosition in DrawText indicates the bottom left of the first character. 
       
   264                         bitmapContext->DrawText(ptrLine, drawPosition);
       
   265                     
       
   266                         drawPosition.iY += heightInPixels; 
       
   267                         currentRow++;
       
   268                         }
       
   269                         
       
   270                     lineStartPos += charsInLine;
       
   271                     unvisitedChars -= charsInLine;
       
   272                     }
       
   273                 }
       
   274             while(charsInLine > 0 && currentRow < maxLines);
       
   275             
       
   276             // update the dirty region
       
   277             aDirtyRegion.iTl.SetXY(KSrtBmpMarginWidth, KSrtBmpMarginHeight);
       
   278 
       
   279             TInt actualMaxCharsPerLine = 0;
       
   280             actualMaxCharsPerLine = Min(content->Length(), maxCharsPerLine);
       
   281 
       
   282             aDirtyRegion.iBr.SetXY(
       
   283                 KSrtBmpMarginWidth + actualMaxCharsPerLine * maxCharWidthInPixels,
       
   284                 KSrtBmpMarginHeight + currentRow * heightInPixels + font->FontMaxDescent());
       
   285             }
       
   286         else
       
   287             {
       
   288             // bitmap too small for the font
       
   289             User::Leave(KErrArgument);
       
   290             }
       
   291 
       
   292         bmpDevice->ReleaseFont(font);
       
   293         bitmapContext->DiscardFont();
       
   294         
       
   295         CleanupStack::PopAndDestroy(3, bmpDevice); // content, bitmapContext, bmpDevice
       
   296         }
       
   297     else
       
   298         {
       
   299         // bitmap too small or the length of content is 0
       
   300         User::Leave(KErrArgument);
       
   301         }
       
   302     }
       
   303     
       
   304 /** Try to get the next valid frame 
       
   305 
       
   306 @param aSearchByVideoPosition Indicate if search for the next valid frame matching aVideoPosition
       
   307 @param aVideoPosition The video position in microsecond
       
   308 @leave If an error occurs, the method will leave with a system-wide error code. 
       
   309 */
       
   310 void CSrtSubtitleDecoder::GetNextValidFrameL(TBool aSearchByVideoPosition, TInt64 aVideoPosition)
       
   311     {
       
   312     TInt decoderBufferMaxLen = iDecodeBuffer.MaxLength();
       
   313     TInt errorFrame = KErrNone;
       
   314     TInt error = KErrNone;
       
   315     TInt sepLen = 0;
       
   316     TInt i = 0;
       
   317     TChar currentChar = 0;
       
   318     TBool frameFound = EFalse;
       
   319     
       
   320     if (iLastFrame)
       
   321     	{
       
   322     	User::Leave(KErrEof);
       
   323     	}
       
   324     
       
   325     while (!frameFound)
       
   326         {
       
   327         // if a frame is not available in iDecodeBuffer, fill iBuffer until CRLFCRLF is available in iBuffer
       
   328         TPtrC8 restOfData = iDecodeBuffer.Right(iDecodeBuffer.Length() - iDecodeBufferPosition);
       
   329         TInt sepPosition = 0;
       
   330         
       
   331         // try to extract a frame from iDecodeBuffer
       
   332         errorFrame = GetFrameSeparatorInfo(restOfData, sepLen, sepPosition);
       
   333         if (KErrNotFound != errorFrame)
       
   334             {
       
   335             User::LeaveIfError(errorFrame);
       
   336             }
       
   337             
       
   338         // if no frame can be extracted, read source until a frame is available or get an EOF error.
       
   339         while (KErrNotFound == errorFrame)
       
   340             {
       
   341             // move the unvisited data in decode buffer to the head before read from the source
       
   342             if (iDecodeBufferPosition != 0)
       
   343                 {
       
   344                 // move the unvisited data in decode buffer to the head
       
   345                 if (iDecodeBufferPosition <= iDecodeBuffer.Length() - 1)
       
   346                     {
       
   347                     TPtrC8 newSubtitleFrame = iDecodeBuffer.Right(iDecodeBuffer.Length() - (iDecodeBufferPosition));
       
   348                     
       
   349                     // use iBuffer to hold the preserved data when rotating data in iDecodeBuffer
       
   350                     if (iBuffer.MaxLength() < newSubtitleFrame.Length())
       
   351                         {
       
   352                         // Some data in iBuffer make iDecodeBuffer hold at least one frame, and so
       
   353                         // iBuffer should always be larger than the preserved data in iDecodeBuffer
       
   354                         User::Panic(KSrtSubtitleDecoderPanicCategory, ESrtUnexpected);
       
   355                         }
       
   356                         
       
   357                     iBuffer.Copy(newSubtitleFrame);
       
   358                     iDecodeBuffer.Copy(iBuffer);
       
   359                     }
       
   360 
       
   361                 iDecodeBufferPosition = 0;
       
   362                 }
       
   363                 
       
   364             error = iSource.GetBuffer(iBuffer);
       
   365             if ((KErrNone != error) && (KErrEof != error))
       
   366                 {
       
   367                 User::Leave(error);
       
   368                 }
       
   369             
       
   370             if (iBuffer.Length() > 0)
       
   371                 {
       
   372                 TInt bufLen = iDecodeBuffer.Length();
       
   373                 TInt newBufLen = iBuffer.Length();
       
   374                 
       
   375                 if (decoderBufferMaxLen < newBufLen + bufLen)
       
   376                     {
       
   377                     iDecodeBuffer.ReAllocL(newBufLen + bufLen);
       
   378                     decoderBufferMaxLen = iDecodeBuffer.MaxLength();
       
   379                     }
       
   380                 iDecodeBuffer.Append(iBuffer);
       
   381                 }
       
   382                 
       
   383             if (KErrEof == error)
       
   384                 {
       
   385                 // reach the end of the subtitle source but cannot find new line separators.  Frame 
       
   386                 // ends at EOF marker then.  No more frames can be read after this one.
       
   387                 sepLen = 0;
       
   388                 sepPosition = iDecodeBuffer.Length();
       
   389                 errorFrame = KErrNone;
       
   390                 if (iLastFrame)
       
   391                 	{
       
   392                 	User::Leave(KErrEof);
       
   393                 	}
       
   394                 iLastFrame = ETrue;
       
   395                 }
       
   396             else
       
   397             	{
       
   398             	errorFrame = GetFrameSeparatorInfo(iDecodeBuffer, sepLen, sepPosition);
       
   399             	}
       
   400             
       
   401             if (KErrNotFound != errorFrame)
       
   402                 {
       
   403                 User::LeaveIfError(errorFrame);
       
   404                 }
       
   405             }
       
   406         
       
   407         // extract a possible frame
       
   408         TPtrC8 subtitleFrameDescriptor = iDecodeBuffer.Mid(iDecodeBufferPosition, sepPosition);
       
   409         
       
   410         // Find the start of the next frame, and update the current position of the decode buffer by 
       
   411         // the following method: from the start of iDecodeBuffer, find the position of the first digit 
       
   412         // character after the first frame separator. 
       
   413         // Not the current position of the decode buffer is updated before parsing the frame, so the 
       
   414         // potential invalid frame will be skipped.  
       
   415         iDecodeBufferPosition += sepPosition + sepLen;
       
   416         TInt firstDigitPosFromCurrentPos = KErrNotFound;
       
   417         for (i = iDecodeBufferPosition; i < iDecodeBuffer.Length(); i++)
       
   418             {
       
   419             currentChar = iDecodeBuffer[i];
       
   420             if (currentChar.IsDigit())
       
   421                 {
       
   422                 firstDigitPosFromCurrentPos = i;
       
   423                 break;
       
   424                 }
       
   425             }
       
   426         if (KErrNotFound == firstDigitPosFromCurrentPos) 
       
   427             {
       
   428             iDecodeBufferPosition = iDecodeBuffer.Length() - 1;
       
   429             }
       
   430         else
       
   431             {
       
   432             iDecodeBufferPosition = firstDigitPosFromCurrentPos;
       
   433             }
       
   434         
       
   435         // parse the frame 
       
   436         TRAPD(parseError, iFrameParser->ParseL(subtitleFrameDescriptor, aSearchByVideoPosition, aVideoPosition));
       
   437         if (KErrNone == parseError)
       
   438             {
       
   439             frameFound = ETrue;
       
   440             if (!aSearchByVideoPosition)
       
   441                 {
       
   442                 // skip the past frames, such as 
       
   443                 // 2\r\n00:00:02,000 --> 00:00:04,000\r\nhome\r\n\r\n
       
   444                 // 1\r\n00:00:00,000 --> 00:00:02,000\r\nwelcome\r\n\r\n
       
   445                 // 3\r\n00:00:04,000 --> 00:00:06,000\r\nagain
       
   446                 if (iFrameParser->EndTime() < iEndTimeOfLastValidFrame)
       
   447                     {
       
   448                     frameFound = EFalse;
       
   449                     }  
       
   450                 else
       
   451                     {
       
   452                     iEndTimeOfLastValidFrame = iFrameParser->EndTime();
       
   453                     }  
       
   454                 }      
       
   455             else
       
   456                 {
       
   457                 iEndTimeOfLastValidFrame = iFrameParser->EndTime();
       
   458                 }    
       
   459             }
       
   460         else
       
   461             {
       
   462             if (KErrArgument != parseError)
       
   463                 {
       
   464                 User::Leave(parseError);
       
   465                 }
       
   466             }
       
   467         }
       
   468     }
       
   469 
       
   470 /** The decoder generates a single frame of subtitle animation for the current time.   
       
   471 The decoder maintains track of the video position. The video position can be updated 
       
   472 via a call to MSubtitleDecoder::SetVideoPosition(). 
       
   473 
       
   474 @param aSubtitleFrame Reference to the current subtitle frame
       
   475 @param aDirtyRegion The decoder outputs the region of the subtitle frame that has been updated. 
       
   476     i.e. the region that now contains new subtitle content.
       
   477 @param aDisplayTime The time in microseconds from the current stream position that the subtitle is due. 
       
   478     DevSubtitle will draw aSubtitleFrame after aDisplayTime has elapsed.
       
   479 @param aDisplayDuration The time in microseconds that this frame should be displayed for. The CRP will clear 
       
   480     this frame after aDisplayFor microseconds
       
   481 @leave If an error occurs, the method will leave with a system-wide error code.
       
   482 */   
       
   483 EXPORT_C void CSrtSubtitleDecoder::GetNextFrameL(CFbsBitmap& aSubtitleFrame, TRect& aDirtyRegion, TTimeIntervalMicroSeconds& aDisplayTime, TTimeIntervalMicroSeconds& aDisplayDuration)
       
   484     {
       
   485     if (!iStarted)
       
   486         {
       
   487         User::Panic(KSrtSubtitleDecoderPanicCategory, ESrtNotStarted);
       
   488         }
       
   489         
       
   490     TTime currentTime;
       
   491     currentTime.UniversalTime();
       
   492     TTimeIntervalMicroSeconds elapsedTime = currentTime.MicroSecondsFrom(iStartSystemTime);
       
   493     TInt64 currentVideoPositionValue = elapsedTime.Int64() + iStartVideoPosition;
       
   494     
       
   495     if (iFirstSearch)
       
   496         {
       
   497         // skip the past frame
       
   498         GetNextValidFrameL(ETrue, currentVideoPositionValue);
       
   499             
       
   500         iFirstSearch = EFalse;
       
   501         }
       
   502     else
       
   503         {
       
   504         // get the next frame
       
   505         GetNextValidFrameL(EFalse, 0);
       
   506         }
       
   507     
       
   508     TInt64 elapsedDuration = 0;
       
   509     // if start time <= current video time, this frame needs to be started immediately.    
       
   510     if (iFrameParser->StartTime() <= currentVideoPositionValue)
       
   511         {
       
   512         aDisplayTime = 0;
       
   513         elapsedDuration = currentVideoPositionValue - iFrameParser->StartTime();
       
   514         }
       
   515     else
       
   516         {
       
   517         aDisplayTime = iFrameParser->StartTime() - currentVideoPositionValue;
       
   518         }
       
   519     
       
   520     // if end time < current video time, this duration becomes 0.
       
   521     if (iFrameParser->EndTime() <= currentVideoPositionValue)
       
   522         {
       
   523         aDisplayDuration = 0;
       
   524         }
       
   525     else
       
   526         {
       
   527         aDisplayDuration = iFrameParser->Duration() - elapsedDuration;
       
   528         }
       
   529             
       
   530     // decode the content into bitmap and get dirty region
       
   531     TPtrC8 ptrContent = iFrameParser->Content();
       
   532     DecodeSubtitleContentL(ptrContent, aSubtitleFrame, aDirtyRegion);
       
   533     }
       
   534     
       
   535 EXPORT_C TLanguage CSrtSubtitleDecoder::SubtitleLanguageL()
       
   536     {
       
   537     return iSource.SubtitleLanguageL();
       
   538     }
       
   539     
       
   540 EXPORT_C void CSrtSubtitleDecoder::GetSupportedSubtitleLanguagesL(RArray<TLanguage>& aLanguages)
       
   541     {
       
   542     iSource.GetSupportedSubtitleLanguagesL(aLanguages);
       
   543     }
       
   544     
       
   545 EXPORT_C void CSrtSubtitleDecoder::SetSubtitleLanguageL(TLanguage aLanguage)
       
   546     {
       
   547     iSource.SetSubtitleLanguageL(aLanguage);
       
   548     }
       
   549     
       
   550 EXPORT_C void CSrtSubtitleDecoder::SetVideoPosition(const TTimeIntervalMicroSeconds& aPosition)
       
   551     {
       
   552     if (aPosition < 0)
       
   553         {
       
   554         User::Panic(KSrtSubtitleDecoderPanicCategory, ESrtBadCall);
       
   555         }
       
   556         
       
   557     iStartVideoPosition = aPosition.Int64();
       
   558     iLastFrame = EFalse;
       
   559     }
       
   560     
       
   561 EXPORT_C void CSrtSubtitleDecoder::Start()
       
   562     {
       
   563     if (iStarted)
       
   564         {
       
   565         User::Panic(KSrtSubtitleDecoderPanicCategory, ESrtAlreadyStarted);
       
   566         }
       
   567     iSource.SetPosition(0);
       
   568     iStartSystemTime.UniversalTime();
       
   569     iStarted = ETrue;
       
   570     iDecodeBufferPosition = 0;
       
   571     iFirstSearch = ETrue;
       
   572     iEndTimeOfLastValidFrame = 0;
       
   573     iLastFrame = EFalse;
       
   574     }
       
   575     
       
   576 EXPORT_C void CSrtSubtitleDecoder::Stop()
       
   577     {
       
   578     iSource.SetPosition(0);
       
   579     iDecodeBuffer.SetLength(0);
       
   580     iBuffer.SetLength(0);
       
   581     iStartVideoPosition = 0; 
       
   582     iStartSystemTime = 0;
       
   583     iStarted = EFalse;
       
   584     iDecodeBufferPosition = 0;
       
   585     iLastFrame = EFalse;
       
   586     }
       
   587     
       
   588 /** Searches for the first occurrence of the SRT frame separator (\r\n\r\n or \n\n) within this 
       
   589     descriptor and return the length and the position of the separator.
       
   590         
       
   591 @param aDes The buffer being searched
       
   592 @param aSeparatorLength Output the length of the SRT frame separator
       
   593 @param aPosition The offset of the SRT frame separator from the beginning of this descriptor's data.
       
   594 @return A system-wide error code, KErrNotFound if the SRT frame separator cannot be found. 
       
   595 */
       
   596 TInt CSrtSubtitleDecoder::GetFrameSeparatorInfo(const TDesC8& aDes, TInt& aSeparatorLength, TInt& aPosition)
       
   597     {
       
   598     TInt errCode = KErrNone;
       
   599     
       
   600     aPosition = aDes.Find(KSrtFrameSeparator1);
       
   601     if (KErrNotFound == aPosition)
       
   602         {
       
   603         aPosition = aDes.Find(KSrtFrameSeparator2);
       
   604         if (KErrNotFound == aPosition)
       
   605             {
       
   606             errCode = KErrNotFound;
       
   607             }
       
   608         else
       
   609             {
       
   610             aSeparatorLength = KSrtFrameSeparator2Len;
       
   611             }
       
   612         }
       
   613     else
       
   614         {
       
   615         aSeparatorLength = KSrtFrameSeparator1Len;
       
   616         }   
       
   617     
       
   618     return errCode;
       
   619     }
       
   620 
       
   621 
       
   622 
       
   623