www.pudn.com > VOBSUB.rar > SubtitleSource.cpp


#include "stdafx.h" 
 
#include  
#include "DirectVobSubUIDs.h" 
#include "IDirectVobSub.h" 
#include "SubtitleSource.h" 
 
///////////////////////////////////////////////////////////////////////////////////// 
 
CUnknown* WINAPI CSubtitleSource::CreateInstance(LPUNKNOWN lpunk, HRESULT* phr) 
{ 
    CUnknown* punk = new CSubtitleSource(lpunk, phr); 
    if(punk == NULL) *phr = E_OUTOFMEMORY; 
	return punk; 
} 
 
CSubtitleSource::CSubtitleSource(LPUNKNOWN lpunk, HRESULT* phr) :  
	CSource(NAME("Subtitle Source"), lpunk, CLSID_SubtitleSource), 
    CPersistStream(lpunk, phr) 
{ 
    CAutoLock cAutoLock(&m_cStateLock); 
 
	m_paStreams = (CSourceStream**) new CSubtitleStream*[1]; 
	if(m_paStreams == NULL) 
	{ 
		*phr = E_OUTOFMEMORY; 
		return; 
	} 
	 
	m_paStreams[0] = new CSubtitleStream("Subtitle Source", phr, this, L"Output"); 
	if(m_paStreams[0] == NULL) 
	{ 
		*phr = E_OUTOFMEMORY; 
		return; 
	} 
} 
 
STDMETHODIMP CSubtitleSource::NonDelegatingQueryInterface(REFIID riid, void** ppv) 
{ 
    CheckPointer(ppv, E_POINTER); 
 
	return (riid == IID_IPersistStream) ? GetInterface((IPersistStream *)this, ppv) 
		: (riid == IID_IFileSourceFilter) ? GetInterface((IFileSourceFilter *)this, ppv) 
		: CSource::NonDelegatingQueryInterface(riid, ppv); 
} 
 
DWORD CSubtitleSource::GetSoftwareVersion() 
{ 
	return(0x0223); 
} 
 
HRESULT CSubtitleSource::WriteToStream(IStream* pStream) 
{ 
    CAutoLock cAutolock(&m_propsLock); 
 
	int len = m_fn.GetLength(); 
	HRESULT hr = pStream->Write(&len, sizeof(len), NULL); 
	if(FAILED(hr)) return hr; 
 
	return NOERROR; 
} 
 
HRESULT CSubtitleSource::ReadFromStream(IStream* pStream) 
{ 
    CAutoLock cAutolock(&m_propsLock); 
 
	int len; 
 
    HRESULT hr = pStream->Read(&len, sizeof(len), NULL); 
	if(FAILED(hr) || len <= 0) return hr; 
 
	char* buff = new char[len+1]; 
 
    hr = pStream->Read(buff, len+1, NULL); 
	if(FAILED(hr)) {delete [] buff; return hr;} 
 
	m_fn = buff; 
 
	delete [] buff; 
 
	if(m_paStreams[0]) ((CSubtitleStream*)m_paStreams[0])->Open(m_fn); 
 
    return NOERROR; 
} 
 
STDMETHODIMP CSubtitleSource::GetClassID(CLSID* pClsid) 
{ 
    if(pClsid == NULL) return E_POINTER; 
 
	*pClsid = CLSID_SubtitleSource; 
 
    return NOERROR; 
} 
 
STDMETHODIMP CSubtitleSource::GetCurFile(LPOLESTR* ppszFileName, AM_MEDIA_TYPE* pmt) 
{ 
	ASSERT(ppszFileName); 
	 
	if(m_fn.IsEmpty()) return(E_FAIL); 
 
	*ppszFileName = (unsigned short*)CoTaskMemAlloc((m_fn.GetLength()+1)*sizeof(unsigned short)); 
	if(*ppszFileName == NULL) return S_FALSE; 
 
#ifdef UNICODE 
	wcscpy(*ppszFileName, m_fn); 
#else 
	mbstowcs(*ppszFileName, m_fn, MAX_PATH); 
#endif 
 
	CMediaType mt; 
	((CSubtitleStream*)m_paStreams[0])->GetMediaType(0, &mt); 
	*pmt = mt; 
 
	return(S_OK); 
} 
 
STDMETHODIMP CSubtitleSource::Load(LPCOLESTR pszFileName, const AM_MEDIA_TYPE* pmt) 
{ 
	if(m_paStreams[0])  
	{ 
		if(!((CSubtitleStream*)m_paStreams[0])->Open(CString(pszFileName))) 
		{ 
			return(E_INVALIDARG); 
		} 
	} 
	else 
	{ 
		return(E_FAIL); 
	} 
 
	return(S_OK); 
} 
 
///////////////////////////////////////////////////////////////////////////////////////////////////////// 
 
CSubtitleStream::CSubtitleStream(char* fn, HRESULT* phr, CSubtitleSource* pParent, LPCWSTR pPinName) :  
	CSourceStream(NAME("Subtitle Stream"), phr, pParent, pPinName) 
{ 
	m_duration = 0; 
	m_filesize = 0; 
	m_data = NULL; 
} 
 
CSubtitleStream::~CSubtitleStream() 
{ 
	if(m_data) {delete [] m_data; m_data = NULL;} 
} 
 
bool CSubtitleStream::Open(CString fn) 
{ 
	if(m_data) {delete [] m_data; m_data = NULL;} 
 
	if(!m_sts.Open(fn, DEFAULT_CHARSET) || m_sts.GetSize() <= 0) return(false); 
 
	m_duration = m_sts.TranslateEnd(m_sts.GetSize()-1, 23.976); // 23.976 will give us the worst case if we have a FRAME based sub (well, for ordenary dvd rips) 
 
	m_name = m_sts.m_name; 
 
	CFileStatus status; 
	if(!CFile::GetStatus(fn, status)) return(false); 
 
	m_filesize = status.m_size; 
 
	CFile f; 
	if(!f.Open(fn, CFile::modeRead|CFile::typeBinary)) return(false); 
 
	m_data = new BYTE[m_filesize]; 
	if(!m_data) return(false); 
 
	if(f.Read(m_data, m_filesize) != m_filesize) 
	{ 
		delete [] m_data; m_data = NULL; 
		return(false); 
	}; 
 
	return(true); 
} 
 
HRESULT CSubtitleStream::FillBuffer(IMediaSample* pms) 
{ 
    BYTE* pData; 
    long lDataLen; 
 
    pms->GetPointer(&pData); 
    lDataLen = pms->GetSize(); 
 
	if(m_fRAWOutput) 
	{ 
        CAutoLock cAutoLockShared(&m_cSharedState); 
 
		if(!pData || !m_data || !m_filesize || m_fOutputDone) return(S_FALSE); 
 
		BYTE* ptr = pData; 
 
		{ 
			// Format ID 
			strcpy((char*)ptr, __GAB2__);  
			ptr += strlen(__GAB2__)+1; 
		} 
 
		{ 
			int len = (m_name.GetLength()+1)*sizeof(WCHAR); 
			*((ushort*)ptr) = __GAB1_LANGUAGE_UNICODE__; ptr += 2; 
			*((uint*)ptr) = len; ptr += 4; 
#ifdef UNICODE 
			wcscpy((WCHAR*)ptr, m_name); ptr += len; 
#else 
			mbstowcs((WCHAR*)ptr, m_name, m_name.GetLength()+1); ptr += len; 
#endif 
		} 
 
		{ 
			int len = m_filesize; 
			*((ushort*)ptr) = __GAB1_RAWTEXTSUBTITLE__; ptr += 2; 
			*((uint*)ptr) = len; ptr += 4; 
			memcpy(ptr, m_data, len); ptr += len; 
		} 
 
		REFERENCE_TIME start = __int64(0)*10000, stop = __int64(m_duration)*10000; 
        pms->SetTime(&start, &stop); 
 
		pms->SetActualDataLength(ptr - pData); 
 
		m_fOutputDone = true; 
	} 
	else 
    { 
        CAutoLock cAutoLockShared(&m_cSharedState); 
 
		REFERENCE_TIME start, stop; 
		start = m_sts.TranslateSegmentStart(m_currentidx, 23.976),  
		stop = m_sts.TranslateSegmentEnd(m_currentidx, 23.976); 
		if(start == -1 && stop == -1) return S_FALSE; 
		const STSSegment* stss = m_sts.SearchSubs((int)start, 23.976); 
 
		start = __int64(start)*10000; 
		stop = __int64(stop)*10000; 
        pms->SetTime(&start, &stop); 
 
		BYTE* ptr = pData; 
 
		*ptr = 0; 
 
		for(int i = 0; stss && i < stss->subs.GetSize(); i++, ptr++) 
		{ 
			if(ptr != pData) ptr[-1] = '\n'; 
			m_sts.GetMBCSStr(stss->subs[i], (char*)ptr, 10240); 
			ptr += strlen((char*)ptr); 
		} 
 
		pms->SetActualDataLength(ptr - pData); 
 
		m_currentidx++; 
	} 
 
	pms->SetSyncPoint(TRUE); 
/* 
 
		int len = m_sts.GetSize(); 
		if(len < 0 || m_currentidx >= len)  
			return S_FALSE; 
 
		REFERENCE_TIME  
			start = __int64(m_start)*10000,  
			stop = start + __int64(SUBALIGN)*10000; 
 
        pms->SetTime(&start, &stop); 
 
		m_start += SUBALIGN; 
 
		BYTE* ptr = pData; 
 
		// Format ID 
		strcpy((char*)ptr, __GAB1__);  
		ptr += strlen(__GAB1__)+1; 
 
//		if(m_start == SUBALIGN) 
		{ 
			if(m_sts.IsEntryUnicode(0)) // m_fUnicode) 
			{ 
				int size = (m_sts.m_name.GetLength()+1)*sizeof(WCHAR); 
			 
				*((ushort*)ptr) = __GAB1_LANGUAGE_UNICODE__; ptr += 2; 
				*((ushort*)ptr) = size;	ptr += 2; 
			 
#ifdef UNICODE 
				wcscpy((WCHAR*)ptr, m_sts.m_name); ptr += size; 
#else 
				mbstowcs((WCHAR*)ptr, m_sts.m_name, m_sts.m_name.GetLength()+1); ptr += size; // TODO: Use user specified charset 
#endif 
			} 
			else 
			{ 
				int size = (m_sts.m_name.GetLength()+1)*sizeof(char); 
 
				*((ushort*)ptr) = __GAB1_LANGUAGE__; ptr += 2; 
				*((ushort*)ptr) = size;	ptr += 2; 
 
#ifdef UNICODE 
				wcstombs((char*)ptr, m_sts.m_name, m_sts.m_name.GetLength()+1); ptr += size; 
#else 
				strcpy((char*)ptr, m_sts.m_name); ptr += size; 
#endif 
			} 
		} 
		 
		for(int i = m_currentidx; i < len && m_sts[i].start < m_start; i++) 
		{ 
			STSEntry& stse = m_sts[i]; 
 
			int start = m_sts.TranslateStart(i, 25); 
			int end = m_sts.TranslateEnd(i, 25); 
 
			bool fUnicode = m_sts.IsEntryUnicode(i); 
 
			CString str =  
#ifdef UNICODE 
				fUnicode ? m_sts.GetUnicodeStr(i) :  
#endif 
				m_sts.GetMBCSStr(i); 
 
			int len = str.GetLength()+1; 
 
#ifdef UNICODE 
			if(fUnicode) 
			{ 
				int size = 4+4+len*sizeof(WCHAR); 
 
				*((ushort*)ptr) = __GAB1_ENTRY_UNICODE__; ptr += 2; 
				*((ushort*)ptr) = size;	ptr += 2; 
				memcpy(ptr, &start, 4); ptr += 4; 
				memcpy(ptr, &end, 4); ptr += 4; 
 
				wcscpy((WCHAR*)ptr, str); ptr += len*sizeof(WCHAR); 
			} 
			else 
#endif 
			{ 
				int size = 4+4+len*sizeof(char); 
			 
				*((ushort*)ptr) = __GAB1_ENTRY__; ptr += 2; 
				*((ushort*)ptr) = size;	ptr += 2; 
				memcpy(ptr, &start, 4); ptr += 4; 
				memcpy(ptr, &end, 4); ptr += 4; 
 
#ifdef UNICODE 
				wcstombs((char*)ptr, str, len+1); ptr += len*sizeof(char); 
#else 
				strcpy((char*)ptr, str); ptr += len*sizeof(char); 
#endif 
 
			} 
		} 
 
		m_currentidx = i; 
 
		pms->SetActualDataLength(ptr - pData); 
 
    } 
*/ 
//    pms->SetSyncPoint(TRUE); 
 
    return NOERROR; 
} 
 
HRESULT CSubtitleStream::GetMediaType(int iPosition, CMediaType *pmt) 
{ 
    CAutoLock cAutoLock(m_pFilter->pStateLock()); 
 
    if(iPosition < 0) return E_INVALIDARG; 
    if(iPosition > 0) return VFW_S_NO_MORE_ITEMS; 
 
    pmt->SetType(&MEDIATYPE_Text); 
    pmt->SetSubtype(&MEDIASUBTYPE_None); 
    pmt->SetFormatType(&FORMAT_None); 
    pmt->SetTemporalCompression(FALSE); 
	pmt->SetVariableSize(); 
 
    return NOERROR; 
 
} 
 
HRESULT CSubtitleStream::CheckConnect(IPin* pPin) 
{ 
	bool fAccept = true; 
 
	PIN_INFO pi; 
	pPin->QueryPinInfo(&pi); 
	if(pi.pFilter) 
	{ 
		FILTER_INFO fi; 
		pi.pFilter->QueryFilterInfo(&fi); 
 
		if(fi.pGraph) 
		{ 
			fAccept = (wcsstr(fi.achName, L"Internal Script Command Renderer") == NULL); // sorry, but no! 
			m_fRAWOutput = (CComQIPtr(pi.pFilter) || CComQIPtr(pi.pFilter)); 
 
			fi.pGraph->Release(); 
		} 
 
		pi.pFilter->Release(); 
 
		return(fAccept ? CBaseOutputPin::CheckConnect(pPin) : E_FAIL); 
	} 
	 
	return E_FAIL; 
} 
 
HRESULT CSubtitleStream::CheckMediaType(const CMediaType* pMediaType) 
{ 
    CAutoLock cAutoLock(m_pFilter->pStateLock()); 
 
	return IsEqualGUID(*pMediaType->Type(), MEDIATYPE_Text) ? S_OK : E_INVALIDARG; 
} 
 
HRESULT CSubtitleStream::DecideBufferSize(IMemAllocator* pAlloc, ALLOCATOR_PROPERTIES* pProperties) 
{ 
    CAutoLock cAutoLock(m_pFilter->pStateLock()); 
    ASSERT(pAlloc); 
    ASSERT(pProperties); 
    HRESULT hr = NOERROR; 
 
    pProperties->cBuffers = 1; 
	pProperties->cbBuffer = 100 + m_filesize; 
 
    ASSERT(pProperties->cbBuffer); 
 
    ALLOCATOR_PROPERTIES Actual; 
    hr = pAlloc->SetProperties(pProperties, &Actual); 
    if(FAILED(hr)) return hr; 
 
    if(Actual.cbBuffer < pProperties->cbBuffer) return E_FAIL; 
 
    ASSERT(Actual.cBuffers == 1); 
    return NOERROR; 
} 
 
HRESULT CSubtitleStream::OnThreadCreate() 
{ 
    CAutoLock cAutoLockShared(&m_cSharedState); 
 
	m_fOutputDone = false; 
 
	m_currentidx = 0; 
 
    return NOERROR; 
}