- Main Page
- Namespaces
- Classes
- Files
- Directories

- File List
- File Members

# AviFile.cpp

    00001 #include "StdAfx.h"
    00002 #include "AviFile.h"
    00003
    00004 //
    00005 // CAviFile
    00006 //
    00007
    00008 CAviFile::CAviFile(IAsyncReader* pAsyncReader, HRESULT& hr)
    00009         : CBaseSplitterFile(pAsyncReader, hr)
    00010 {
    00011         if(FAILED(hr)) return;
    00012         hr = Init();
    00013 }
    00014
    00015 template<typename T>
    00016 HRESULT CAviFile::Read(T& var, int offset)
    00017 {
    00018         memset(&var, 0, sizeof(var));
    00019         HRESULT hr = Read((BYTE*)&var + offset, sizeof(var) - offset);
    00020         return hr;
    00021 }
    00022
    00023 HRESULT CAviFile::Init()
    00024 {
    00025         Seek(0);
    00026         DWORD dw[3];
    00027         if(S_OK != Read(dw) || dw[0] != FCC('RIFF') || (dw[2] != FCC('AVI ') && dw[2] != FCC('AVIX')))
    00028                 return E_FAIL;
    00029
    00030         Seek(0);
    00031         HRESULT hr = Parse(0, GetLength());
    00032         if(m_movis.GetCount() == 0) // FAILED(hr) is allowed as long as there was a movi chunk found
    00033                 return E_FAIL;
    00034
    00035         if(m_avih.dwStreams == 0 && m_strms.GetCount() > 0)
    00036                 m_avih.dwStreams = m_strms.GetCount();
    00037
    00038         if(m_avih.dwStreams != m_strms.GetCount())
    00039                 return E_FAIL;
    00040
    00041         for(int i = 0; i < (int)m_avih.dwStreams; i++)
    00042         {
    00043                 strm_t* s = m_strms[i];
    00044                 if(s->strh.fccType != FCC('auds')) continue;
    00045                 WAVEFORMATEX* wfe = (WAVEFORMATEX*)s->strf.GetData();
    00046                 if(wfe->wFormatTag == 0x55 && wfe->nBlockAlign == 1152
    00047                 && s->strh.dwScale == 1 && s->strh.dwRate != wfe->nSamplesPerSec)
    00048                 {
    00049                         // correcting encoder bugs...
    00050                         s->strh.dwScale = 1152;
    00051                         s->strh.dwRate = wfe->nSamplesPerSec;
    00052                 }
    00053         }
    00054
    00055         if(FAILED(BuildIndex()))
    00056                 EmptyIndex();
    00057
    00058         return S_OK;
    00059 }
    00060
    00061 HRESULT CAviFile::Parse(DWORD parentid, __int64 end)
    00062 {
    00063         HRESULT hr = S_OK;
    00064
    00065         CAutoPtr<strm_t> strm;
    00066
    00067         while(S_OK == hr && GetPos() < end)
    00068         {
    00069                 UINT64 pos = GetPos();
    00070
    00071                 DWORD id = 0, size;
    00072                 if(S_OK != Read(id) || id == 0)
    00073                         return E_FAIL;
    00074
    00075                 if(id == FCC('RIFF') || id == FCC('LIST'))
    00076                 {
    00077                         if(S_OK != Read(size) || S_OK != Read(id))
    00078                                 return E_FAIL;
    00079
    00080                         size += (size&1) + 8;
    00081
    00082                         TRACE(_T("CAviFile::Parse(..): LIST '%c%c%c%c'\n"),
    00083                                 TCHAR((id>>0)&0xff),
    00084                                 TCHAR((id>>8)&0xff),
    00085                                 TCHAR((id>>16)&0xff),
    00086                                 TCHAR((id>>24)&0xff));
    00087
    00088                         if(id == FCC('movi'))
    00089                         {
    00090                                 m_movis.AddTail(pos);
    00091                         }
    00092                         else
    00093                         {
    00094                                 hr = Parse(id, pos + size);
    00095                         }
    00096                 }
    00097                 else
    00098                 {
    00099                         if(S_OK != Read(size))
    00100                                 return E_FAIL;
    00101
    00102                         TRACE(_T("CAviFile::Parse(..): '%c%c%c%c'\n"),
    00103                                 TCHAR((id>>0)&0xff),
    00104                                 TCHAR((id>>8)&0xff),
    00105                                 TCHAR((id>>16)&0xff),
    00106                                 TCHAR((id>>24)&0xff));
    00107
    00108                         if(parentid == FCC('INFO') && size > 0)
    00109                         {
    00110                                 switch(id)
    00111                                 {
    00112                                 case FCC('IARL'): // Archival Location. Indicates where the subject of the file is archived.
    00113                                 case FCC('IART'): // Artist. Lists the artist of the original subject of the file; for example, “Michaelangelo.”
    00114                                 case FCC('ICMS'): // Commissioned. Lists the name of the person or organization that commissioned the subject of the file; for example, “Pope Julian II.”
    00115                                 case FCC('ICMT'): // Comments. Provides general comments about the file or the subject of the file. If the comment is several sentences long, end each sentence with a period. Do not include new-line characters.
    00116                                 case FCC('ICOP'): // Copyright. Records the copyright information for the file; for example, “Copyright Encyclopedia International 1991.” If there are multiple copyrights, separate them by a semicolon followed by a space.
    00117                                 case FCC('ICRD'): // Creation date. Specifies the date the subject of the file was created. List dates in year-month-day format, padding one-digit months and days with a zero on the left; for example, “1553-05-03” for May 3, 1553.
    00118                                 case FCC('ICRP'): // Cropped. Describes whether an image has been cropped and, if so, how it was cropped; for example, “lower-right corner.”
    00119                                 case FCC('IDIM'): // Dimensions. Specifies the size of the original subject of the file; for example, “8.5 in h, 11 in w.”
    00120                                 case FCC('IDPI'): // Dots Per Inch. Stores dots per inch setting of the digitizer used to produce the file, such as “300.”
    00121                                 case FCC('IENG'): // Engineer. Stores the name of the engineer who worked on the file. If there are multiple engineers, separate the names by a semicolon and a blank; for example, “Smith, John; Adams, Joe.”
    00122                                 case FCC('IGNR'): // Genre. Describes the original work, such as “landscape,” “portrait,” “still life,” etc.
    00123                                 case FCC('IKEY'): // Keywords. Provides a list of keywords that refer to the file or subject of the file. Separate multiple keywords with a semicolon and a blank; for example, “Seattle; aerial view; scenery.”
    00124                                 case FCC('ILGT'): // Lightness. Describes the changes in lightness settings on the digitizer required to produce the file. Note that the format of this information depends on hardware used.
    00125                                 case FCC('IMED'): // Medium. Describes the original subject of the file, such as “computer image,” “drawing,” “lithograph,” and so on.
    00126                                 case FCC('INAM'): // Name. Stores the title of the subject of the file, such as “Seattle From Above.”
    00127                                 case FCC('IPLT'): // Palette Setting. Specifies the number of colors requested when digitizing an image, such as “256.”
    00128                                 case FCC('IPRD'): // Product. Specifies the name of the title the file was originally intended for, such as “Encyclopedia of Pacific Northwest Geography.”
    00129                                 case FCC('ISBJ'): // Subject. Describes the contents of the file, such as “Aerial view of Seattle.”
    00130                                 case FCC('ISFT'): // Software. Identifies the name of the software package used to create the file, such as “Microsoft WaveEdit.”
    00131                                 case FCC('ISHP'): // Sharpness. Identifies the changes in sharpness for the digitizer required to produce the file (the format depends on the hardware used).
    00132                                 case FCC('ISRC'): // Source. Identifies the name of the person or organization who supplied the original subject of the file; for example, “Trey Research.”
    00133                                 case FCC('ISRF'): // Source Form. Identifies the original form of the material that was digitized, such as “slide,” “paper,” “map,” and so on. This is not necessarily the same as IMED.
    00134                                 case FCC('ITCH'): // Technician. Identifies the technician who digitized the subject file; for example, “Smith, John.”
    00135                                         {
    00136                                                 CStringA str;
    00137                                                 if(S_OK != Read((BYTE*)str.GetBufferSetLength(size), size)) return E_FAIL;
    00138                                                 m_info[id] = str;
    00139                                                 break;
    00140                                         }
    00141                                 }
    00142                         }
    00143
    00144                         switch(id)
    00145                         {
    00146                         case FCC('avih'):
    00147                                 m_avih.fcc = FCC('avih');
    00148                                 m_avih.cb = size;
    00149                                 if(S_OK != Read(m_avih, 8)) return E_FAIL;
    00150                                 break;
    00151                         case FCC('strh'):
    00152                                 if(!strm) strm.Attach(new strm_t());
    00153                                 strm->strh.fcc = FCC('strh');
    00154                                 strm->strh.cb = size;
    00155                                 if(S_OK != Read(strm->strh, 8)) return E_FAIL;
    00156                                 break;
    00157                         case FCC('strn'):
    00158                                 if(S_OK != Read((BYTE*)strm->strn.GetBufferSetLength(size), size)) return E_FAIL;
    00159                                 break;
    00160                         case FCC('strf'):
    00161                                 if(!strm) strm.Attach(new strm_t());
    00162                                 strm->strf.SetSize(size);
    00163                                 if(S_OK != Read(strm->strf.GetData(), size)) return E_FAIL;
    00164                                 break;
    00165                         case FCC('indx'):
    00166                                 if(!strm) strm.Attach(new strm_t());
    00167                                 ASSERT(strm->indx == NULL);
    00168                                 strm->indx.Attach((AVISUPERINDEX*)new BYTE[size + 8]);
    00169                                 strm->indx->fcc = FCC('indx');
    00170                                 strm->indx->cb = size;
    00171                                 if(S_OK != Read((BYTE*)(AVISUPERINDEX*)strm->indx + 8, size)) return E_FAIL;
    00172                                 ASSERT(strm->indx->wLongsPerEntry == 4 && strm->indx->bIndexType == AVI_INDEX_OF_INDEXES);
    00173                                 break;
    00174                         case FCC('dmlh'):
    00175                                 if(S_OK != Read(m_dmlh)) return E_FAIL;
    00176                                 break;
    00177                         case FCC('vprp'):
    00178 //                              if(S_OK != Read(m_vprp)) return E_FAIL;
    00179                                 break;
    00180                         case FCC('idx1'):
    00181                                 ASSERT(m_idx1 == NULL);
    00182                                 m_idx1.Attach((AVIOLDINDEX*)new BYTE[size + 8]);
    00183                                 m_idx1->fcc = FCC('idx1');
    00184                                 m_idx1->cb = size;
    00185                                 if(S_OK != Read((BYTE*)(AVIOLDINDEX*)m_idx1 + 8, size)) return E_FAIL;
    00186                                 break;
    00187                         }
    00188
    00189                         size += (size&1) + 8;
    00190                 }
    00191
    00192                 Seek(pos + size);
    00193         }
    00194
    00195         if(strm) m_strms.Add(strm);
    00196
    00197         return hr;
    00198 }
    00199
    00200 REFERENCE_TIME CAviFile::GetTotalTime()
    00201 {
    00202         REFERENCE_TIME t = 0/*10i64*m_avih.dwMicroSecPerFrame*m_avih.dwTotalFrames*/;
    00203
    00204         for(int i = 0; i < (int)m_avih.dwStreams; i++)
    00205         {
    00206                 strm_t* s = m_strms[i];
    00207                 REFERENCE_TIME t2 = s->GetRefTime(s->cs.GetCount(), s->totalsize);
    00208                 t = max(t, t2);
    00209         }
    00210
    00211         if(t == 0) t = 10i64*m_avih.dwMicroSecPerFrame*m_avih.dwTotalFrames;
    00212
    00213         return(t);
    00214 }
    00215
    00216 HRESULT CAviFile::BuildIndex()
    00217 {
    00218         EmptyIndex();
    00219
    00220         int nSuperIndexes = 0;
    00221
    00222         for(int i = 0; i < (int)m_avih.dwStreams; i++)
    00223         {
    00224                 strm_t* s = m_strms[i];
    00225                 if(s->indx && s->indx->nEntriesInUse > 0) nSuperIndexes++;
    00226         }
    00227
    00228         if(nSuperIndexes == m_avih.dwStreams)
    00229         {
    00230                 for(int i = 0; i < (int)m_avih.dwStreams; i++)
    00231                 {
    00232                         strm_t* s = m_strms[i];
    00233
    00234                         AVISUPERINDEX* idx = (AVISUPERINDEX*)s->indx;
    00235
    00236                         DWORD nEntriesInUse = 0;
    00237
    00238                         for(int j = 0; j < (int)idx->nEntriesInUse; j++)
    00239                         {
    00240                                 Seek(idx->aIndex[j].qwOffset);
    00241
    00242                                 AVISTDINDEX stdidx;
    00243                                 if(S_OK != Read((BYTE*)&stdidx, FIELD_OFFSET(AVISTDINDEX, aIndex)))
    00244                                 {
    00245                                         EmptyIndex();
    00246                                         return E_FAIL;
    00247                                 }
    00248
    00249                                 nEntriesInUse += stdidx.nEntriesInUse;
    00250                         }
    00251
    00252                         s->cs.SetSize(nEntriesInUse);
    00253
    00254                         DWORD frame = 0;
    00255                         UINT64 size = 0;
    00256
    00257                         for(int j = 0; j < (int)idx->nEntriesInUse; j++)
    00258                         {
    00259                                 Seek(idx->aIndex[j].qwOffset);
    00260
    00261                                 CAutoPtr<AVISTDINDEX> p((AVISTDINDEX*)new BYTE[idx->aIndex[j].dwSize]);
    00262                                 if(!p || S_OK != Read((BYTE*)(AVISTDINDEX*)p, idx->aIndex[j].dwSize))
    00263                                 {
    00264                                         EmptyIndex();
    00265                                         return E_FAIL;
    00266                                 }
    00267
    00268                                 for(int k = 0, l = 0; k < (int)p->nEntriesInUse; k++)
    00269                                 {
    00270                                         s->cs[frame].size = size;
    00271                                         s->cs[frame].filepos = p->qwBaseOffset + p->aIndex[k].dwOffset;
    00272                                         s->cs[frame].fKeyFrame = !(p->aIndex[k].dwSize&AVISTDINDEX_DELTAFRAME)
    00273                                                 || s->strh.fccType == FCC('auds');
    00274                                         s->cs[frame].fChunkHdr = false;
    00275                                         s->cs[frame].orgsize = p->aIndex[k].dwSize&AVISTDINDEX_SIZEMASK;
    00276
    00277                                         if(m_idx1)
    00278                                         {
    00279                                                 s->cs[frame].filepos -= 8;
    00280                                                 s->cs[frame].fChunkHdr = true;
    00281                                         }
    00282
    00283                                         frame++;
    00284                                         size += s->GetChunkSize(p->aIndex[k].dwSize&AVISTDINDEX_SIZEMASK);
    00285                                 }
    00286                         }
    00287
    00288                         s->totalsize = size;
    00289                 }
    00290         }
    00291         else if(AVIOLDINDEX* idx = m_idx1)
    00292         {
    00293                 int len = idx->cb/sizeof(idx->aIndex[0]);
    00294
    00295                 UINT64 offset = m_movis.GetHead() + 8;
    00296
    00297                 for(int i = 0; i < (int)m_avih.dwStreams; i++)
    00298                 {
    00299                         strm_t* s = m_strms[i];
    00300
    00301                         int nFrames = 0;
    00302
    00303                         for(int j = 0; j < len; j++)
    00304                         {
    00305                                 if(TRACKNUM(idx->aIndex[j].dwChunkId) == i)
    00306                                         nFrames++;
    00307                         }
    00308
    00309                         s->cs.SetSize(nFrames);
    00310
    00311                         DWORD frame = 0;
    00312                         UINT64 size = 0;
    00313
    00314                         for(int j = 0, k = 0; j < len; j++)
    00315                         {
    00316                                 DWORD TrackNumber = TRACKNUM(idx->aIndex[j].dwChunkId);
    00317
    00318                                 if(TrackNumber == i)
    00319                                 {
    00320                                         if(j == 0 && idx->aIndex[j].dwOffset > offset)
    00321                                         {
    00322                                                 DWORD id;
    00323                                                 Seek(offset + idx->aIndex[j].dwOffset);
    00324                                                 Read(id);
    00325                                                 if(id != idx->aIndex[j].dwChunkId)
    00326                                                 {
    00327                                                         TRACE(_T("WARNING: CAviFile::Init() detected absolute chunk addressing in \'idx1\'"));
    00328                                                         offset = 0;
    00329                                                 }
    00330                                         }
    00331
    00332                                         s->cs[frame].size = size;
    00333                                         s->cs[frame].filepos = offset + idx->aIndex[j].dwOffset;
    00334                                         s->cs[frame].fKeyFrame = !!(idx->aIndex[j].dwFlags&AVIIF_KEYFRAME)
    00335                                                 || s->strh.fccType == FCC('auds') // FIXME: some audio index is without any kf flag
    00336                                                 || frame == 0; // grrr
    00337                                         s->cs[frame].fChunkHdr = j == len-1 || idx->aIndex[j].dwOffset != idx->aIndex[j+1].dwOffset;
    00338                                         s->cs[frame].orgsize = idx->aIndex[j].dwSize;
    00339
    00340                                         frame++;
    00341                                         size += s->GetChunkSize(idx->aIndex[j].dwSize);
    00342                                 }
    00343                         }
    00344
    00345                         s->totalsize = size;
    00346                 }
    00347         }
    00348
    00349         m_idx1.Free();
    00350         for(int i = 0; i < (int)m_avih.dwStreams; i++)
    00351                 m_strms[i]->indx.Free();
    00352
    00353         return S_OK;
    00354 }
    00355
    00356 void CAviFile::EmptyIndex()
    00357 {
    00358         for(int i = 0; i < (int)m_avih.dwStreams; i++)
    00359         {
    00360                 strm_t* s = m_strms[i];
    00361                 s->cs.RemoveAll();
    00362                 s->totalsize = 0;
    00363         }
    00364 }
    00365
    00366 bool CAviFile::IsInterleaved(bool fKeepInfo)
    00367 {
    00368         if(m_strms.GetCount() < 2)
    00369                 return(true);
    00370 /*
    00371         if(m_avih.dwFlags&AVIF_ISINTERLEAVED) // not reliable, nandub can write f*cked up files and still sets it
    00372                 return(true);
    00373 */
    00374         for(int i = 0; i < (int)m_avih.dwStreams; i++)
    00375                 m_strms[i]->cs2.SetSize(m_strms[i]->cs.GetSize());
    00376
    00377         DWORD* curchunks = new DWORD[m_avih.dwStreams];
    00378         UINT64* cursizes = new UINT64[m_avih.dwStreams];
    00379
    00380         memset(curchunks, 0, sizeof(DWORD)*m_avih.dwStreams);
    00381         memset(cursizes, 0, sizeof(UINT64)*m_avih.dwStreams);
    00382
    00383         int end = 0;
    00384
    00385         while(1)
    00386         {
    00387                 UINT64 fpmin = _I64_MAX;
    00388
    00389                 DWORD n = -1;
    00390                 for(int i = 0; i < (int)m_avih.dwStreams; i++)
    00391                 {
    00392                         int curchunk = curchunks[i];
    00393                         CArray<strm_t::chunk>& cs = m_strms[i]->cs;
    00394                         if(curchunk >= cs.GetSize()) continue;
    00395             UINT64 fp = cs[curchunk].filepos;
    00396                         if(fp < fpmin) {fpmin = fp; n = i;}
    00397                 }
    00398                 if(n == -1) break;
    00399
    00400                 strm_t* s = m_strms[n];
    00401                 DWORD& curchunk = curchunks[n];
    00402                 UINT64& cursize = cursizes[n];
    00403
    00404                 if(!s->IsRawSubtitleStream())
    00405                 {
    00406                         strm_t::chunk2& cs2 = s->cs2[curchunk];
    00407                         cs2.t = (DWORD)(s->GetRefTime(curchunk, cursize)>>13); // for comparing later it is just as good as /10000 to get a near [ms] accuracy
    00408 //                      cs2.t = (DWORD)(s->GetRefTime(curchunk, cursize)/10000);
    00409                         cs2.n = end++;
    00410                 }
    00411
    00412                 cursize = s->cs[curchunk].size;
    00413                 curchunk++;
    00414         }
    00415
    00416         memset(curchunks, 0, sizeof(DWORD)*m_avih.dwStreams);
    00417
    00418         strm_t::chunk2 cs2last = {-1, 0};
    00419
    00420         bool fInterleaved = true;
    00421
    00422         while(fInterleaved)
    00423         {
    00424                 strm_t::chunk2 cs2min = {LONG_MAX, LONG_MAX};
    00425
    00426                 int n = -1;
    00427                 for(int i = 0; i < (int)m_avih.dwStreams; i++)
    00428                 {
    00429                         int curchunk = curchunks[i];
    00430                         if(curchunk >= m_strms[i]->cs2.GetSize()) continue;
    00431                         strm_t::chunk2& cs2 = m_strms[i]->cs2[curchunk];
    00432                         if(cs2.t < cs2min.t) {cs2min = cs2; n = i;}
    00433                 }
    00434                 if(n == -1) break;
    00435
    00436                 curchunks[n]++;
    00437
    00438                 if(cs2last.t >= 0 && abs(cs2min.n - cs2last.n) >= 1000)
    00439                         fInterleaved = false;
    00440
    00441                 cs2last = cs2min;
    00442         }
    00443
    00444         delete [] curchunks;
    00445         delete [] cursizes;
    00446
    00447         if(fInterleaved && !fKeepInfo)
    00448         {
    00449                 // this is not needed anymore, let's save a little memory then
    00450                 for(int i = 0; i < (int)m_avih.dwStreams; i++)
    00451                         m_strms[i]->cs2.SetSize(0);
    00452         }
    00453
    00454         return(fInterleaved);
    00455 }
    00456
    00457 REFERENCE_TIME CAviFile::strm_t::GetRefTime(DWORD frame, UINT64 size)
    00458 {
    00459         REFERENCE_TIME rt = -1;
    00460
    00461         if(strh.fccType == FCC('auds'))
    00462         {
    00463                 WAVEFORMATEX* wfe = (WAVEFORMATEX*)strf.GetData();
    00464
    00465                 rt = wfe->nBlockAlign && strh.dwRate
    00466                         ? ((10000000i64 * size + (wfe->nBlockAlign>>1)) / wfe->nBlockAlign * strh.dwScale + (strh.dwRate>>1)) / strh.dwRate
    00467                         : 0;
    00468         }
    00469         else
    00470         {
    00471                 rt = strh.dwRate
    00472                         ? 10000i64 * ((1000i64 * frame * strh.dwScale + (strh.dwRate>>1)) / strh.dwRate) // 10000 * (1000 * ... ) because it is less likely to overflow this way
    00473                         : 0;
    00474         }
    00475
    00476         return(rt);
    00477 }
    00478
    00479 int CAviFile::strm_t::GetFrame(REFERENCE_TIME rt)
    00480 {
    00481         int frame = -1;
    00482
    00483         rt /= 10000; // avoiding overflow later
    00484
    00485         if(strh.fccType == FCC('auds'))
    00486         {
    00487                 WAVEFORMATEX* wfe = (WAVEFORMATEX*)strf.GetData();
    00488
    00489                 INT64 size = strh.dwScale
    00490                         ? ((rt * strh.dwRate + strh.dwScale/2) / strh.dwScale * wfe->nBlockAlign + 1000/2) / 1000
    00491                         : 0;
    00492
    00493                 for(frame = 0; frame < cs.GetCount(); frame++)
    00494                 {
    00495                         if(cs[frame].size > size)
    00496                         {
    00497                                 frame--;
    00498                                 break;
    00499                         }
    00500                 }
    00501         }
    00502         else
    00503         {
    00504                 frame = strh.dwScale
    00505                         ? (int)(((rt * strh.dwRate + strh.dwScale/2) / strh.dwScale + 1000/2) / 1000)
    00506                         : 0;
    00507         }
    00508
    00509         if(frame >= cs.GetCount())
    00510                 frame = cs.GetCount()-1;
    00511
    00512         return(frame);
    00513 }
    00514
    00515 int CAviFile::strm_t::GetKeyFrame(REFERENCE_TIME rt)
    00516 {
    00517         int i = GetFrame(rt);
    00518         for(; i > 0; i--) {if(cs[i].fKeyFrame) break;}
    00519         return(i);
    00520 }
    00521
    00522 DWORD CAviFile::strm_t::GetChunkSize(DWORD size)
    00523 {
    00524         if(strh.fccType == FCC('auds'))
    00525         {
    00526                 WORD nBlockAlign = ((WAVEFORMATEX*)strf.GetData())->nBlockAlign;
    00527                 size = nBlockAlign
    00528                         ? (size + (nBlockAlign-1)) / nBlockAlign * nBlockAlign // round up for nando's vbr hack
    00529                         : 0;
    00530         }
    00531
    00532         return(size);
    00533 }
    00534
    00535 bool CAviFile::strm_t::IsRawSubtitleStream()
    00536 {
    00537         return strh.fccType == FCC('txts') && cs.GetCount() == 1;
    00538 }