1 |
// CTivoFile.cpp : Implementation of CTivoFile
|
2 |
|
3 |
#include "stdafx.h"
|
4 |
#include "CTivoFile.h"
|
5 |
#include "CChunkCollection.h"
|
6 |
#include "FileStream.h"
|
7 |
#include "CTivoChunk.h"
|
8 |
|
9 |
/* I want to use std::min */
|
10 |
#ifdef min
|
11 |
#undef min
|
12 |
#endif
|
13 |
|
14 |
extern "C" {
|
15 |
int o_verbose = 0;
|
16 |
int o_no_verify = 0;
|
17 |
|
18 |
int stream_read_wrapper(void* mem, int size, void* fh)
|
19 |
{
|
20 |
IStream* pStm = reinterpret_cast<IStream*>(fh);
|
21 |
ULONG retval = 0;
|
22 |
HRESULT hr = pStm->Read(mem, size, &retval);
|
23 |
return (int)retval;
|
24 |
}
|
25 |
|
26 |
int stream_write_wrapper(void* mem, int size, void* fh)
|
27 |
{
|
28 |
IStream* pStm = reinterpret_cast<IStream*>(fh);
|
29 |
ULONG retval = 0;
|
30 |
HRESULT hr = pStm->Write(mem, size, &retval);
|
31 |
return (int)retval;
|
32 |
}
|
33 |
}
|
34 |
|
35 |
|
36 |
// CTivoFile
|
37 |
|
38 |
void CTivoFile::FinalRelease()
|
39 |
{
|
40 |
if (m_mpeg_turing_inited)
|
41 |
destruct_turing (&m_mpeg_turing);
|
42 |
}
|
43 |
|
44 |
|
45 |
STDMETHODIMP CTivoFile::Init(BSTR mak, IStream* stream)
|
46 |
{
|
47 |
try
|
48 |
{
|
49 |
USES_CONVERSION;
|
50 |
|
51 |
m_pStm = stream;
|
52 |
m_mak = OLE2CA(mak);
|
53 |
|
54 |
if (read_tivo_header(m_pStm, &m_fileheader, &stream_read_wrapper) < 0)
|
55 |
_com_raise_error(E_FAIL);
|
56 |
|
57 |
m_endoffileheader.QuadPart = SIZEOF_STREAM_HEADER;
|
58 |
|
59 |
CComObject<CChunkCollection>* chunkColl = new CComObject<CChunkCollection> ();
|
60 |
m_chunkcoll = chunkColl;
|
61 |
_com_util::CheckError(chunkColl->Init(m_mak, m_fileheader.chunks, &m_endoffileheader, m_pStm));
|
62 |
/* need to get to the start of the MPG stream, but cannot rely on Seek being
|
63 |
* implemented (to support streaming)
|
64 |
*/
|
65 |
ULONG bytesToMPEG = m_fileheader.mpeg_offset - m_endoffileheader.QuadPart;
|
66 |
while(bytesToMPEG > 0)
|
67 |
{
|
68 |
BYTE tmp[1024];
|
69 |
ULONG bytesRead;
|
70 |
_com_util::CheckError(m_pStm->Read (tmp, std::min(bytesToMPEG, (ULONG)1024), &bytesRead));
|
71 |
bytesToMPEG -= bytesRead;
|
72 |
}
|
73 |
|
74 |
CComPtr<ITivoChunk> pChunk0;
|
75 |
_com_util::CheckError(m_chunkcoll->get_Item(1, &pChunk0));
|
76 |
CTivoChunk* pCChunk = dynamic_cast<CTivoChunk*>(pChunk0.p);
|
77 |
setup_turing_key(&m_mpeg_turing, pCChunk->m_chunk, const_cast<char*>(m_mak.c_str()));
|
78 |
m_mpeg_turing_inited = true;
|
79 |
}
|
80 |
catch (const _com_error & ex)
|
81 |
{
|
82 |
return ex.Error();
|
83 |
}
|
84 |
|
85 |
return S_OK;
|
86 |
}
|
87 |
|
88 |
|
89 |
STDMETHODIMP CTivoFile::get_filename(BSTR* pVal)
|
90 |
{
|
91 |
return E_NOTIMPL;
|
92 |
}
|
93 |
|
94 |
STDMETHODIMP CTivoFile::get_filetype(BSTR* pVal)
|
95 |
{
|
96 |
CComBSTR retval (4, m_fileheader.filetype);
|
97 |
return retval.CopyTo(pVal);
|
98 |
}
|
99 |
|
100 |
STDMETHODIMP CTivoFile::get_dummy_4(USHORT* pVal)
|
101 |
{
|
102 |
if (!pVal)
|
103 |
return E_POINTER;
|
104 |
|
105 |
*pVal = m_fileheader.dummy_0004;
|
106 |
|
107 |
return S_OK;
|
108 |
}
|
109 |
|
110 |
STDMETHODIMP CTivoFile::get_dummy_6(USHORT* pVal)
|
111 |
{
|
112 |
if (!pVal)
|
113 |
return E_POINTER;
|
114 |
|
115 |
*pVal = m_fileheader.dummy_0006;
|
116 |
|
117 |
return S_OK;
|
118 |
}
|
119 |
|
120 |
STDMETHODIMP CTivoFile::get_dummy_8(USHORT* pVal)
|
121 |
{
|
122 |
if (!pVal)
|
123 |
return E_POINTER;
|
124 |
|
125 |
*pVal = m_fileheader.dummy_0008;
|
126 |
|
127 |
return S_OK;
|
128 |
}
|
129 |
|
130 |
STDMETHODIMP CTivoFile::get_mpeg_offset(UINT* pVal)
|
131 |
{
|
132 |
if (!pVal)
|
133 |
return E_POINTER;
|
134 |
|
135 |
*pVal = m_fileheader.mpeg_offset;
|
136 |
|
137 |
return S_OK;
|
138 |
}
|
139 |
|
140 |
STDMETHODIMP CTivoFile::get_chunk_count(USHORT* pVal)
|
141 |
{
|
142 |
if (!pVal)
|
143 |
return E_POINTER;
|
144 |
|
145 |
*pVal = m_fileheader.chunks;
|
146 |
|
147 |
return S_OK;
|
148 |
}
|
149 |
|
150 |
STDMETHODIMP CTivoFile::get_chunks(IChunkCollection** pVal)
|
151 |
{
|
152 |
try
|
153 |
{
|
154 |
_com_util::CheckError(m_chunkcoll.CopyTo(pVal));
|
155 |
}
|
156 |
catch (const _com_error & ex)
|
157 |
{
|
158 |
return ex.Error();
|
159 |
}
|
160 |
return S_OK;
|
161 |
}
|
162 |
|
163 |
STDMETHODIMP CTivoFile::get_mak(BSTR* pVal)
|
164 |
{
|
165 |
CComBSTR mak (static_cast<int>(m_mak.size()), m_mak.data());
|
166 |
return mak.CopyTo(pVal);
|
167 |
}
|
168 |
|
169 |
STDMETHODIMP CTivoFile::put_mak(BSTR newVal)
|
170 |
{
|
171 |
USES_CONVERSION;
|
172 |
m_mak = OLE2CA(newVal);
|
173 |
|
174 |
return S_OK;
|
175 |
}
|
176 |
|
177 |
STDMETHODIMP CTivoFile::DecryptMPEGToFile(BSTR bstrFileName)
|
178 |
{
|
179 |
try
|
180 |
{
|
181 |
IStream * pFileStm;
|
182 |
CComPtr<IStream> pStm;
|
183 |
_com_util::CheckError(FileStream::OpenFile(OLE2CW(bstrFileName), &pFileStm, TRUE));
|
184 |
pStm.Attach(pFileStm);
|
185 |
_com_util::CheckError(this->DecryptMPEGToStream(pStm));
|
186 |
}
|
187 |
catch (const _com_error & ex)
|
188 |
{
|
189 |
return ex.Error();
|
190 |
}
|
191 |
|
192 |
return S_OK;
|
193 |
}
|
194 |
|
195 |
STDMETHODIMP CTivoFile::DecryptMPEGToStream(IStream* pStm)
|
196 |
{
|
197 |
//ATLTRACENOTIMPL("DecryptMPEGToStream");
|
198 |
ULARGE_INTEGER filesize, filepos;
|
199 |
LARGE_INTEGER zero = {0};
|
200 |
bool percentage_determinable = false;
|
201 |
|
202 |
try
|
203 |
{
|
204 |
STATSTG stats;
|
205 |
_com_util::CheckError(m_pStm->Stat(&stats, STATFLAG_NONAME));
|
206 |
filesize = stats.cbSize;
|
207 |
_com_util::CheckError(m_pStm->Seek(zero, STREAM_SEEK_CUR, &filepos));
|
208 |
percentage_determinable = true;
|
209 |
}
|
210 |
catch (const _com_error & ex)
|
211 |
{
|
212 |
/* non-determinable */
|
213 |
UNREFERENCED_PARAMETER(ex);
|
214 |
percentage_determinable = false;
|
215 |
}
|
216 |
|
217 |
try
|
218 |
{
|
219 |
ULONG t;
|
220 |
UINT32 marker = 0xFFFFFFFF;
|
221 |
DWORD dwFrames = 0, dwLastNotifiedFrames = 0;
|
222 |
UINT8 byte;
|
223 |
bool first=true, running=true;
|
224 |
|
225 |
while (running)
|
226 |
{
|
227 |
if ((marker & 0xFFFFFF00) == 0x100)
|
228 |
{
|
229 |
int ret = process_frame(byte, &m_mpeg_turing, 0, m_pStm.p, &stream_read_wrapper, pStm, &stream_write_wrapper);
|
230 |
if (ret == 1)
|
231 |
{
|
232 |
marker = 0xFFFFFFFF;
|
233 |
if ((++dwFrames) >= (dwLastNotifiedFrames + 100))
|
234 |
{
|
235 |
double percent = -1.0;
|
236 |
if (percentage_determinable)
|
237 |
{
|
238 |
_com_util::CheckError(m_pStm->Seek(zero, STREAM_SEEK_CUR, &filepos));
|
239 |
percent = (double)filepos.QuadPart / (double)filesize.QuadPart;
|
240 |
}
|
241 |
|
242 |
if (Fire_OnProgressChange(dwFrames, percent) == S_FALSE)
|
243 |
{
|
244 |
return S_FALSE;
|
245 |
}
|
246 |
|
247 |
dwLastNotifiedFrames = dwFrames;
|
248 |
}
|
249 |
}
|
250 |
else if (ret == 0)
|
251 |
{
|
252 |
_com_util::CheckError(pStm->Write(&byte, 1, &t));
|
253 |
ATLASSERT (t == 1);
|
254 |
}
|
255 |
else if (ret < 0)
|
256 |
{
|
257 |
ATLTRACE("Error processing frame!\n");
|
258 |
return Error(OLESTR("Error processing frame"), GUID_NULL, AtlHresultFromLastError());
|
259 |
}
|
260 |
}
|
261 |
else if (!first)
|
262 |
{
|
263 |
_com_util::CheckError(pStm->Write(&byte, 1, &t));
|
264 |
ATLASSERT (t == 1);
|
265 |
}
|
266 |
marker <<= 8;
|
267 |
_com_util::CheckError(m_pStm->Read(&byte, 1, &t));
|
268 |
if (t == 0)
|
269 |
{
|
270 |
running = false;
|
271 |
}
|
272 |
else
|
273 |
marker |= byte;
|
274 |
first = false;
|
275 |
}
|
276 |
}
|
277 |
catch (const _com_error & ex)
|
278 |
{
|
279 |
ATLTRACE("Got error 0x%08x: %s\n", ex.Error(), ex.ErrorMessage());
|
280 |
return ex.Error();
|
281 |
}
|
282 |
|
283 |
return S_OK;
|
284 |
}
|