Skip to content

Commit

Permalink
Fix: now mp4 file on internet url can be played by dvdplayer by doubl…
Browse files Browse the repository at this point in the history
…e session support of cache.
  • Loading branch information
ulion committed Apr 19, 2013
1 parent a4654c5 commit b0609b3
Show file tree
Hide file tree
Showing 11 changed files with 285 additions and 26 deletions.
7 changes: 6 additions & 1 deletion xbmc/cores/dvdplayer/DVDInputStreams/DVDInputStreamFile.cpp
Expand Up @@ -51,8 +51,13 @@ bool CDVDInputStreamFile::Open(const char* strFile, const std::string& content)
if (!m_pFile)
return false;

unsigned int flags = READ_TRUNCATED | READ_BITRATE | READ_CHUNKED;

if (content == "video/mp4")
flags |= READ_MULTI_STREAM;

// open file in binary mode
if (!m_pFile->Open(strFile, READ_TRUNCATED | READ_BITRATE | READ_CHUNKED))
if (!m_pFile->Open(strFile, flags))
{
delete m_pFile;
m_pFile = NULL;
Expand Down
147 changes: 146 additions & 1 deletion xbmc/filesystem/CacheStrategy.cpp
Expand Up @@ -229,9 +229,16 @@ int64_t CSimpleFileCache::Seek(int64_t iFilePosition)
return iFilePosition;
}

void CSimpleFileCache::Reset(int64_t iSourcePosition)
void CSimpleFileCache::Reset(int64_t iSourcePosition, bool clearAnyway)
{
LARGE_INTEGER pos;
if (!clearAnyway && IsCachedPosition(iSourcePosition))
{
pos.QuadPart = m_nReadPosition = iSourcePosition - m_nStartPosition;
SetFilePointerEx(m_hCacheFileRead, pos, NULL, FILE_BEGIN);
return;
}

pos.QuadPart = 0;

SetFilePointerEx(m_hCacheFileWrite, pos, NULL, FILE_BEGIN);
Expand All @@ -247,3 +254,141 @@ void CSimpleFileCache::EndOfInput()
m_hDataAvailEvent->Set();
}

int64_t CSimpleFileCache::CachedDataEndPosIfSeekTo(int64_t iFilePosition)
{
if (iFilePosition >= m_nStartPosition && iFilePosition <= m_nStartPosition + m_nWritePosition)
return m_nStartPosition + m_nWritePosition;
return iFilePosition;
}

int64_t CSimpleFileCache::CachedDataEndPos()
{
return m_nStartPosition + m_nWritePosition;
}

bool CSimpleFileCache::IsCachedPosition(int64_t iFilePosition)
{
return iFilePosition >= m_nStartPosition && iFilePosition <= m_nStartPosition + m_nWritePosition;
}

CCacheStrategy *CSimpleFileCache::CreateNew()
{
return new CSimpleFileCache();
}


CSimpleDoubleCache::CSimpleDoubleCache(CCacheStrategy *impl)
{
assert(NULL != impl);
m_pCache = impl;
m_pCacheOld = NULL;
}

CSimpleDoubleCache::~CSimpleDoubleCache()
{
delete m_pCache;
delete m_pCacheOld;
}

int CSimpleDoubleCache::Open()
{
return m_pCache->Open();
}

void CSimpleDoubleCache::Close()
{
m_pCache->Close();
if (m_pCacheOld)
{
delete m_pCacheOld;
m_pCacheOld = NULL;
}
}

int CSimpleDoubleCache::WriteToCache(const char *pBuffer, size_t iSize)
{
return m_pCache->WriteToCache(pBuffer, iSize);
}

int CSimpleDoubleCache::ReadFromCache(char *pBuffer, size_t iMaxSize)
{
return m_pCache->ReadFromCache(pBuffer, iMaxSize);
}

int64_t CSimpleDoubleCache::WaitForData(unsigned int iMinAvail, unsigned int iMillis)
{
return m_pCache->WaitForData(iMinAvail, iMillis);
}

int64_t CSimpleDoubleCache::Seek(int64_t iFilePosition)
{
return m_pCache->Seek(iFilePosition);
}

void CSimpleDoubleCache::Reset(int64_t iSourcePosition, bool clearAnyway)
{
if (!clearAnyway && m_pCache->IsCachedPosition(iSourcePosition)
&& (!m_pCacheOld || !m_pCacheOld->IsCachedPosition(iSourcePosition)
|| m_pCache->CachedDataEndPos() >= m_pCacheOld->CachedDataEndPos()))
{
m_pCache->Reset(iSourcePosition, clearAnyway);
return;
}
if (!m_pCacheOld)
{
CSimpleFileCache *pCacheNew = new CSimpleFileCache();
if (pCacheNew->Open() != CACHE_RC_OK)
{
delete pCacheNew;
m_pCache->Reset(iSourcePosition, clearAnyway);
return;
}
pCacheNew->Reset(iSourcePosition, clearAnyway);
m_pCacheOld = m_pCache;
m_pCache = pCacheNew;
return;
}
m_pCacheOld->Reset(iSourcePosition, clearAnyway);
CCacheStrategy *tmp = m_pCacheOld;
m_pCacheOld = m_pCache;
m_pCache = tmp;
}

void CSimpleDoubleCache::EndOfInput()
{
m_pCache->EndOfInput();
}

bool CSimpleDoubleCache::IsEndOfInput()
{
return m_pCache->IsEndOfInput();
}

void CSimpleDoubleCache::ClearEndOfInput()
{
m_pCache->ClearEndOfInput();
}

int64_t CSimpleDoubleCache::CachedDataEndPos()
{
return m_pCache->CachedDataEndPos();
}

int64_t CSimpleDoubleCache::CachedDataEndPosIfSeekTo(int64_t iFilePosition)
{
int64_t ret = m_pCache->CachedDataEndPosIfSeekTo(iFilePosition);
if (m_pCacheOld)
return std::max(ret, m_pCacheOld->CachedDataEndPosIfSeekTo(iFilePosition));
return ret;
}

bool CSimpleDoubleCache::IsCachedPosition(int64_t iFilePosition)
{
return m_pCache->IsCachedPosition(iFilePosition) || (m_pCacheOld && m_pCacheOld->IsCachedPosition(iFilePosition));
}

CCacheStrategy *CSimpleDoubleCache::CreateNew()
{
return new CSimpleDoubleCache(m_pCache->CreateNew());
}

45 changes: 43 additions & 2 deletions xbmc/filesystem/CacheStrategy.h
Expand Up @@ -51,12 +51,18 @@ class CCacheStrategy{
virtual int64_t WaitForData(unsigned int iMinAvail, unsigned int iMillis) = 0;

virtual int64_t Seek(int64_t iFilePosition) = 0;
virtual void Reset(int64_t iSourcePosition) = 0;
virtual void Reset(int64_t iSourcePosition, bool clearAnyway=true) = 0;

virtual void EndOfInput(); // mark the end of the input stream so that Read will know when to return EOF
virtual bool IsEndOfInput();
virtual void ClearEndOfInput();

virtual int64_t CachedDataEndPosIfSeekTo(int64_t iFilePosition) = 0;
virtual int64_t CachedDataEndPos() = 0;
virtual bool IsCachedPosition(int64_t iFilePosition) = 0;

virtual CCacheStrategy *CreateNew() = 0;

CEvent m_space;
protected:
bool m_bEndOfInput;
Expand All @@ -77,9 +83,15 @@ class CSimpleFileCache : public CCacheStrategy {
virtual int64_t WaitForData(unsigned int iMinAvail, unsigned int iMillis) ;

virtual int64_t Seek(int64_t iFilePosition);
virtual void Reset(int64_t iSourcePosition);
virtual void Reset(int64_t iSourcePosition, bool clearAnyway=true);
virtual void EndOfInput();

virtual int64_t CachedDataEndPosIfSeekTo(int64_t iFilePosition);
virtual int64_t CachedDataEndPos();
virtual bool IsCachedPosition(int64_t iFilePosition);

virtual CCacheStrategy *CreateNew();

int64_t GetAvailableRead();

protected:
Expand All @@ -91,6 +103,35 @@ class CSimpleFileCache : public CCacheStrategy {
volatile int64_t m_nReadPosition;
};

class CSimpleDoubleCache : public CCacheStrategy{
public:
CSimpleDoubleCache(CCacheStrategy *impl);
virtual ~CSimpleDoubleCache();

virtual int Open() ;
virtual void Close() ;

virtual int WriteToCache(const char *pBuffer, size_t iSize) ;
virtual int ReadFromCache(char *pBuffer, size_t iMaxSize) ;
virtual int64_t WaitForData(unsigned int iMinAvail, unsigned int iMillis) ;

virtual int64_t Seek(int64_t iFilePosition);
virtual void Reset(int64_t iSourcePosition, bool clearAnyway=true);
virtual void EndOfInput();
virtual bool IsEndOfInput();
virtual void ClearEndOfInput();

virtual int64_t CachedDataEndPosIfSeekTo(int64_t iFilePosition);
virtual int64_t CachedDataEndPos();
virtual bool IsCachedPosition(int64_t iFilePosition);

virtual CCacheStrategy *CreateNew();

protected:
CCacheStrategy *m_pCache;
CCacheStrategy *m_pCacheOld;
};

}

#endif
29 changes: 28 additions & 1 deletion xbmc/filesystem/CircularCache.cpp
Expand Up @@ -211,11 +211,38 @@ int64_t CCircularCache::Seek(int64_t pos)
return CACHE_RC_ERROR;
}

void CCircularCache::Reset(int64_t pos)
void CCircularCache::Reset(int64_t pos, bool clearAnyway)
{
CSingleLock lock(m_sync);
if (!clearAnyway && IsCachedPosition(pos))
{
m_cur = pos;
return;
}
m_end = pos;
m_beg = pos;
m_cur = pos;
}

int64_t CCircularCache::CachedDataEndPosIfSeekTo(int64_t iFilePosition)
{
if (IsCachedPosition(iFilePosition))
return m_end;
return iFilePosition;
}

int64_t CCircularCache::CachedDataEndPos()
{
return m_end;
}

bool CCircularCache::IsCachedPosition(int64_t iFilePosition)
{
return iFilePosition >= m_beg && iFilePosition <= m_end;
}

CCacheStrategy *CCircularCache::CreateNew()
{
return new CCircularCache(m_size - m_size_back, m_size_back);
}

7 changes: 6 additions & 1 deletion xbmc/filesystem/CircularCache.h
Expand Up @@ -41,8 +41,13 @@ class CCircularCache : public CCacheStrategy
virtual int64_t WaitForData(unsigned int minimum, unsigned int iMillis) ;

virtual int64_t Seek(int64_t pos) ;
virtual void Reset(int64_t pos) ;
virtual void Reset(int64_t pos, bool clearAnyway=true) ;

virtual int64_t CachedDataEndPosIfSeekTo(int64_t iFilePosition);
virtual int64_t CachedDataEndPos();
virtual bool IsCachedPosition(int64_t iFilePosition);

virtual CCacheStrategy *CreateNew();
protected:
int64_t m_beg; /**< index in file (not buffer) of beginning of valid data */
int64_t m_end; /**< index in file (not buffer) of end of valid data */
Expand Down
24 changes: 19 additions & 5 deletions xbmc/filesystem/CurlFile.cpp
Expand Up @@ -378,6 +378,7 @@ CCurlFile::~CCurlFile()
{
Close();
delete m_state;
delete m_oldState;
g_curlInterface.Unload();
}

Expand All @@ -404,6 +405,7 @@ CCurlFile::CCurlFile()
m_httpauth = "";
m_proxytype = PROXY_HTTP;
m_state = new CReadState();
m_oldState = NULL;
m_skipshout = false;
m_httpresponse = -1;
}
Expand All @@ -420,6 +422,8 @@ void CCurlFile::Close()
Write(NULL, 0);

m_state->Disconnect();
delete m_oldState;
m_oldState = NULL;

m_url.Empty();
m_referer.Empty();
Expand Down Expand Up @@ -1143,17 +1147,28 @@ int64_t CCurlFile::Seek(int64_t iFilePosition, int iWhence)
if(m_state->Seek(nextPos))
return nextPos;

if (m_oldState && m_oldState->Seek(nextPos))
{
CReadState *tmp = m_state;
m_state = m_oldState;
m_oldState = tmp;
return nextPos;
}

if(!m_seekable)
return -1;

CReadState* oldstate = NULL;
if(m_multisession)
{
CURL url(m_url);
oldstate = m_state;
oldstate = m_oldState;
m_oldState = m_state;
m_state = new CReadState();

g_curlInterface.easy_aquire(url.GetProtocol(), url.GetHostName(), &m_state->m_easyHandle, &m_state->m_multiHandle );

m_state->m_fileSize = m_oldState->m_fileSize;
}
else
m_state->Disconnect();
Expand All @@ -1165,17 +1180,16 @@ int64_t CCurlFile::Seek(int64_t iFilePosition, int iWhence)
SetRequestHeaders(m_state);

m_state->m_filePos = nextPos;
if (oldstate)
m_state->m_fileSize = oldstate->m_fileSize;

long response = m_state->Connect(m_bufferSize);
if(response < 0 && (m_state->m_fileSize == 0 || m_state->m_fileSize != m_state->m_filePos))
{
m_seekable = false;
if(oldstate)
if(m_multisession && m_oldState)
{
delete m_state;
m_state = oldstate;
m_state = m_oldState;
m_oldState = oldstate;
}
return -1;
}
Expand Down
1 change: 1 addition & 0 deletions xbmc/filesystem/CurlFile.h
Expand Up @@ -148,6 +148,7 @@ namespace XFILE

protected:
CReadState* m_state;
CReadState* m_oldState;
unsigned int m_bufferSize;
int64_t m_writeOffset;

Expand Down

1 comment on commit b0609b3

@wsnipex
Copy link

@wsnipex wsnipex commented on b0609b3 Apr 7, 2014

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@ulion this has been reported to break http streaming with less then 3 concurrent connections allowed.
Please check: http://forum.xbmc.org/showthread.php?tid=189963&pid=1675410#pid1675410

Please sign in to comment.