/[tivodecode]/tivocom/trunk/CTivoFile.cpp
ViewVC logotype

Contents of /tivocom/trunk/CTivoFile.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 254 - (show annotations) (download)
Sun Sep 9 23:26:20 2007 UTC (14 years, 9 months ago) by jeremyd2019
File size: 5827 byte(s)
rework interfaces (bumped typelib version to 1.1).  Add support for decoding the MPEG stream.  Added support to read and write from streams (implementing IStream) and make the versions which take filenames use a stream implementation that wraps file access.  Make OpenTivoFile take the MAK as a parameter.  It has a default value of "" (empty string), which means try to get the MAK from the registry, so either omit that param (for those languages which permit that) or specify it as empty string to use the MAK from the registry.  Added progress reporting of MPEG stream decoding via a connection point.  Progress is updated every 100 frames, and percent complete is provided if the tivo file stream supports Seek and Stat functions

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 }

cvs@jdrake.com
ViewVC Help
Powered by ViewVC 1.1.13