BaseSplitterFile.cpp

00001 /* 
00002  *      Copyright (C) 2003-2005 Gabest
00003  *      http://www.gabest.org
00004  *
00005  *  This Program is free software; you can redistribute it and/or modify
00006  *  it under the terms of the GNU General Public License as published by
00007  *  the Free Software Foundation; either version 2, or (at your option)
00008  *  any later version.
00009  *   
00010  *  This Program is distributed in the hope that it will be useful,
00011  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00012  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
00013  *  GNU General Public License for more details.
00014  *   
00015  *  You should have received a copy of the GNU General Public License
00016  *  along with GNU Make; see the file COPYING.  If not, write to
00017  *  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. 
00018  *  http://www.gnu.org/copyleft/gpl.html
00019  *
00020  */
00021 
00022 #include "StdAfx.h"
00023 #include "BaseSplitterFile.h"
00024 
00025 //
00026 // CBaseSplitterFile
00027 //
00028 
00029 CBaseSplitterFile::CBaseSplitterFile(IAsyncReader* pAsyncReader, HRESULT& hr, int cachelen)
00030         : m_pAsyncReader(pAsyncReader)
00031         , m_fStreaming(false)
00032         , m_pos(0), m_len(0)
00033         , m_bitbuff(0), m_bitlen(0)
00034         , m_cachepos(0), m_cachelen(0)
00035 {
00036         if(!m_pAsyncReader) {hr = E_UNEXPECTED; return;}
00037 
00038         LONGLONG total = 0, available;
00039         hr = m_pAsyncReader->Length(&total, &available);
00040 
00041         m_fStreaming = total == 0 && available > 0;
00042         m_len = available;
00043 
00044         if(FAILED(hr) || !m_fStreaming && total != available || total < 0)
00045         {
00046                 hr = E_FAIL;
00047                 return;
00048         }
00049 
00050         if(!SetCacheSize(cachelen))
00051         {
00052                 hr = E_OUTOFMEMORY; 
00053                 return;
00054         }
00055 
00056         hr = S_OK;
00057 }
00058 
00059 bool CBaseSplitterFile::SetCacheSize(int cachelen)
00060 {
00061         m_pCache.Free();
00062         m_cachetotal = 0;
00063         m_pCache.Allocate((size_t)cachelen);
00064         if(!m_pCache) return false;
00065         m_cachetotal = cachelen;
00066         m_cachelen = 0;
00067         return true;
00068 }
00069 
00070 __int64 CBaseSplitterFile::GetPos()
00071 {
00072         return m_pos - (m_bitlen>>3);
00073 }
00074 
00075 __int64 CBaseSplitterFile::GetLength()
00076 {
00077         if(m_fStreaming)
00078         {
00079                 LONGLONG total, available = 0;
00080                 if(SUCCEEDED(m_pAsyncReader->Length(&total, &available))) m_len = available;
00081         }
00082 
00083         return m_len;
00084 }
00085 
00086 void CBaseSplitterFile::Seek(__int64 pos)
00087 {
00088         __int64 len = GetLength();
00089         m_pos = min(max(pos, 0), len);
00090         BitFlush();
00091 }
00092 
00093 HRESULT CBaseSplitterFile::Read(BYTE* pData, __int64 len)
00094 {
00095         CheckPointer(m_pAsyncReader, E_NOINTERFACE);
00096 
00097         HRESULT hr = S_OK;
00098 
00099         if(m_cachetotal == 0 || !m_pCache)
00100         {
00101                 hr = m_pAsyncReader->SyncRead(m_pos, (long)len, pData);
00102                 m_pos += len;
00103                 return hr;
00104         }
00105 
00106         BYTE* pCache = m_pCache;
00107 
00108         if(m_cachepos <= m_pos && m_pos < m_cachepos + m_cachelen)
00109         {
00110                 __int64 minlen = min(len, m_cachelen - (m_pos - m_cachepos));
00111 
00112                 memcpy(pData, &pCache[m_pos - m_cachepos], (size_t)minlen);
00113 
00114                 len -= minlen;
00115                 m_pos += minlen;
00116                 pData += minlen;
00117         }
00118 
00119         while(len > m_cachetotal)
00120         {
00121                 hr = m_pAsyncReader->SyncRead(m_pos, (long)m_cachetotal, pData);
00122                 if(S_OK != hr) return hr;
00123 
00124                 len -= m_cachetotal;
00125                 m_pos += m_cachetotal;
00126                 pData += m_cachetotal;
00127         }
00128 
00129         while(len > 0)
00130         {
00131                 __int64 tmplen = GetLength();
00132                 __int64 maxlen = min(tmplen - m_pos, m_cachetotal);
00133                 __int64 minlen = min(len, maxlen);
00134                 if(minlen <= 0) return S_FALSE;
00135 
00136                 hr = m_pAsyncReader->SyncRead(m_pos, (long)maxlen, pCache);
00137                 if(S_OK != hr) return hr;
00138 
00139                 m_cachepos = m_pos;
00140                 m_cachelen = maxlen;
00141 
00142                 memcpy(pData, pCache, (size_t)minlen);
00143 
00144                 len -= minlen;
00145                 m_pos += minlen;
00146                 pData += minlen;
00147         }
00148 
00149         return hr;
00150 }
00151 
00152 UINT64 CBaseSplitterFile::BitRead(int nBits, bool fPeek)
00153 {
00154         ASSERT(nBits >= 0 && nBits <= 64);
00155 
00156         while(m_bitlen < nBits)
00157         {
00158                 m_bitbuff <<= 8;
00159                 if(S_OK != Read((BYTE*)&m_bitbuff, 1)) {return 0;} // EOF? // ASSERT(0);
00160                 m_bitlen += 8;
00161         }
00162 
00163         int bitlen = m_bitlen - nBits;
00164 
00165         UINT64 ret = (m_bitbuff >> bitlen) & ((1ui64 << nBits) - 1);
00166 
00167         if(!fPeek)
00168         {
00169                 m_bitbuff &= ((1ui64 << bitlen) - 1);
00170                 m_bitlen = bitlen;
00171         }
00172 
00173         return ret;
00174 }
00175 
00176 void CBaseSplitterFile::BitByteAlign()
00177 {
00178         m_bitlen &= ~7;
00179 }
00180 
00181 void CBaseSplitterFile::BitFlush()
00182 {
00183         m_bitlen = 0;
00184 }
00185 
00186 HRESULT CBaseSplitterFile::ByteRead(BYTE* pData, __int64 len)
00187 {
00188     Seek(GetPos());
00189         return Read(pData, len);
00190 }
00191 
00192 UINT64 CBaseSplitterFile::UExpGolombRead()
00193 {
00194         int n = -1;
00195         for(BYTE b = 0; !b; n++) b = BitRead(1);
00196         return (1ui64 << n) - 1 + BitRead(n);
00197 }
00198 
00199 INT64 CBaseSplitterFile::SExpGolombRead()
00200 {
00201         UINT64 k = UExpGolombRead();
00202         return ((k&1) ? 1 : -1) * ((k + 1) >> 1);
00203 }
00204 
00205 HRESULT CBaseSplitterFile::HasMoreData(__int64 len, DWORD ms)
00206 {
00207         __int64 available = GetLength() - GetPos();
00208 
00209         if(!m_fStreaming)
00210         {
00211                 return available < 1 ? E_FAIL : S_OK;
00212         }
00213 
00214         if(available < len)
00215         {
00216                 if(ms > 0) Sleep(ms);
00217                 return S_FALSE;
00218         }
00219 
00220         return S_OK;
00221 }
00222 

Generated on Tue Dec 13 14:47:11 2005 for guliverkli by  doxygen 1.4.5