root/branches/perian-1.1/DataHandlerCallback.cpp

Revision 395, 6.5 kB (checked in by dconrad, 2 years ago)

Use simple buffered read for Matroska. 20-30% faster import.

Line 
1 /*
2  *  DataHandlerCallback.cpp
3  *
4  *    DataHandlerCallback.cpp - file I/O for libebml.
5  *
6  *
7  *  Copyright (c) 2006  David Conrad
8  *
9  *  This program is free software; you can redistribute it and/or
10  *  modify it under the terms of the GNU Lesser General Public
11  *  License as published by the Free Software Foundation;
12  *  version 2.1 of the License.
13  *
14  *  This program is distributed in the hope that it will be useful,
15  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
16  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17  *  Lesser General Public License for more details.
18  *
19  *  You should have received a copy of the GNU Lesser General Public
20  *  License along with this program; if not, write to the Free Software
21  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
22  *
23  */
24
25 #include "DataHandlerCallback.h"
26 #include <QuickTime/QuickTime.h>
27
28 #include "ebml/Debug.h"
29 #include "ebml/EbmlConfig.h"
30
31 using namespace std;
32
33 CRTError::CRTError(int nError, const std::string & Description)
34         :std::runtime_error(Description+": "+strerror(nError))
35         ,Error(Error)
36 {
37 }
38
39 CRTError::CRTError(const std::string & Description,int nError)
40         :std::runtime_error(Description+": "+strerror(nError))
41         ,Error(Error)
42 {
43 }
44
45
46 DataHBuffer::DataHBuffer(size_t bufferSize)
47 {
48         buffer = new uint8_t[bufferSize];
49         allocatedSize = bufferSize;
50         fileOffset = -1;
51         dataSize = 0;
52 }
53
54 DataHBuffer::~DataHBuffer()
55 {
56         if (buffer)
57                 delete[] buffer;
58 }
59
60 void DataHBuffer::Realloc(size_t bufferSize)
61 {
62         if (buffer)
63                 delete[] buffer;
64        
65         buffer = new uint8_t[bufferSize];
66         allocatedSize = bufferSize;
67         fileOffset = -1;
68         dataSize = 0;
69 }
70
71 bool DataHBuffer::ContainsOffset(uint64_t offset)
72 {
73         return offset >= fileOffset && offset < fileOffset + dataSize;
74 }
75
76 uint8_t * DataHBuffer::GetBuffer(uint64_t offset, size_t size)
77 {
78         if (size > allocatedSize)
79                 Realloc(size);
80        
81         fileOffset = offset;
82         dataSize = size;
83         return buffer;
84 }
85
86 size_t DataHBuffer::Read(uint64_t offset, size_t size, uint8_t *store)
87 {
88         if (!ContainsOffset(offset))
89                 return 0;
90        
91         uint8_t *dataStart = buffer + (offset - fileOffset);
92         size_t amountToRead = MIN(fileOffset + dataSize - offset, size);
93         memcpy(store, dataStart, amountToRead);
94         return amountToRead;
95 }
96
97
98 DataHandlerCallback::DataHandlerCallback(ComponentInstance dataHandler, const open_mode aMode)
99 {       
100         Initialize(aMode);
101        
102         switch (aMode)
103         {
104                 case MODE_READ:
105                 case MODE_WRITE:
106                         this->dataHandler = dataHandler;
107                         break;
108                        
109                 default:
110                         throw 0;
111                         break;
112         }
113        
114         // figure out if we support wide offesets
115         getFileSize();
116 }
117
118 DataHandlerCallback::DataHandlerCallback(Handle dataRef, OSType dataRefType, const open_mode aMode)
119 {
120     ComponentResult err = noErr;
121         Component dataHComponent = NULL;
122        
123         Initialize(aMode);
124        
125         if (aMode == MODE_READ)
126                 dataHComponent = GetDataHandler(dataRef, dataRefType, kDataHCanRead);
127         else if (aMode == MODE_WRITE)
128                 dataHComponent = GetDataHandler(dataRef, dataRefType, kDataHCanWrite);
129         else
130                 throw 0;
131        
132         err = OpenAComponent(dataHComponent, &dataHandler);
133         if (err) {
134                 throw CRTError("Error opening data handler component", err);
135         }
136        
137         err = DataHSetDataRef(dataHandler, dataRef);
138         if (err) {
139                 throw CRTError("Error setting data handler ref", err);
140         }
141        
142         if (aMode == MODE_READ) {
143                 err = DataHOpenForRead(dataHandler);
144         if (err) {
145             throw CRTError("Error opening data handler for read", err);
146         }
147         } else if (aMode == MODE_WRITE) {
148                 err = DataHOpenForWrite(dataHandler);
149         if (err) {
150             throw CRTError("Error opening data handler for write", err);
151         }
152         } else {
153                 throw 0;
154         }
155        
156         closeHandler = true;
157        
158         // figure out if we support wide offesets
159         getFileSize();
160 }
161
162 void DataHandlerCallback::Initialize(const open_mode aMode)
163 {
164         closeHandler = false;
165         supportsWideOffsets = true;
166         this->dataHandler = NULL;
167         mCurrentPosition = 0;
168         filesize = 0;
169         this->aMode = aMode;
170 }
171
172 DataHandlerCallback::~DataHandlerCallback() throw()
173 {
174         close();
175 }
176
177 uint32 DataHandlerCallback::read(void *buffer, size_t size)
178 {
179         ComponentResult err = noErr;
180         size_t amountRead = 0;
181         uint64_t oldPos = mCurrentPosition;
182         uint8_t *internalBuffer, *myBuffer = (uint8_t *)buffer;
183        
184     if (size < 1 || mCurrentPosition > filesize)
185         return 0;
186        
187         if (mCurrentPosition + size > filesize)
188                 size = filesize - mCurrentPosition;
189        
190         while (size > 0) {
191                 if (dataBuffer.ContainsOffset(mCurrentPosition)) {
192                         amountRead = dataBuffer.Read(mCurrentPosition, size, myBuffer);
193                         myBuffer += amountRead;
194                         mCurrentPosition += amountRead;
195                         size -= amountRead;
196                 }
197                
198                 if (size <= 0)
199                         break;
200                
201                 internalBuffer = dataBuffer.GetBuffer(mCurrentPosition, READ_SIZE);
202                
203                 if (supportsWideOffsets) {
204                         wide wideOffset = SInt64ToWide(mCurrentPosition);
205                        
206                         err = DataHScheduleData64(dataHandler, (Ptr)internalBuffer, &wideOffset,
207                                                                           READ_SIZE, 0, NULL, NULL);
208                 } else {
209                         err = DataHScheduleData(dataHandler, (Ptr)internalBuffer, mCurrentPosition,
210                                                                         READ_SIZE, 0, NULL, NULL);
211                 }
212        
213                 if (err) {
214                         throw CRTError("Error reading data", err);
215                 }
216         }
217        
218         return mCurrentPosition - oldPos;
219 }
220
221 void DataHandlerCallback::setFilePointer(int64 Offset, seek_mode Mode)
222 {
223         switch ( Mode )
224         {
225                 case SEEK_CUR:
226                         mCurrentPosition += Offset;
227                         break;
228                 case SEEK_END:
229                         // I think this is what seeking this way does (was ftell(File))
230                         mCurrentPosition = getFileSize() + Offset;
231                         break;
232                 case SEEK_SET:
233                         mCurrentPosition = Offset;
234                         break;
235         }
236 }
237
238 size_t DataHandlerCallback::write(const void *Buffer, size_t Size)
239 {
240         ComponentResult err = noErr;
241        
242         if (supportsWideOffsets) {
243                 wide wideOffset = SInt64ToWide(mCurrentPosition);
244                
245                 err = DataHWrite64(dataHandler, (Ptr)Buffer, &wideOffset, Size, NULL, 0);
246         } else {
247                 err = DataHWrite(dataHandler, (Ptr)Buffer, mCurrentPosition, Size, NULL, 0);
248         }
249        
250         if (err) {
251                 throw CRTError("Error writing data", err);
252         }
253         mCurrentPosition += Size;
254        
255         // does QT tell us how much it writes?
256         return Size;
257 }
258
259 uint64 DataHandlerCallback::getFilePointer()
260 {
261         return mCurrentPosition;
262 }
263
264 void DataHandlerCallback::close()
265 {
266         if (closeHandler) {
267                 if (aMode == MODE_READ)
268                         DataHCloseForRead(dataHandler);
269                 else if (aMode == MODE_WRITE)
270                         DataHCloseForWrite(dataHandler);
271                 dataHandler = NULL;
272         }
273 }
274
275 SInt64 DataHandlerCallback::getFileSize()
276 {
277         ComponentResult err = noErr;
278         wide wideFilesize;
279        
280         if (filesize > 0)
281                 return filesize;
282        
283         err = DataHGetFileSize64(dataHandler, &wideFilesize);
284         if (err == noErr) {
285                 supportsWideOffsets = true;
286                 filesize = WideToSInt64(wideFilesize);
287         } else {
288                 long size32;
289                 supportsWideOffsets = false;
290                 DataHGetFileSize(dataHandler, &size32);
291                 filesize = size32;
292         }
293        
294         return filesize;
295 }
Note: See TracBrowser for help on using the browser.