Fri, 16 Jan 2015 04:50:19 +0100
Replace accessor implementation with direct member state manipulation, by
request https://trac.torproject.org/projects/tor/ticket/9701#comment:32
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim:set ts=2 sw=2 sts=2 et cindent: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #include "WMF.h"
9 #include <unknwn.h>
10 #include <ole2.h>
12 #include "WMFByteStream.h"
13 #include "WMFSourceReaderCallback.h"
14 #include "WMFUtils.h"
15 #include "MediaResource.h"
16 #include "nsISeekableStream.h"
17 #include "mozilla/RefPtr.h"
18 #include "nsIThreadPool.h"
19 #include "nsXPCOMCIDInternal.h"
20 #include "nsComponentManagerUtils.h"
21 #include "mozilla/DebugOnly.h"
22 #include "SharedThreadPool.h"
23 #include <algorithm>
24 #include <cassert>
26 namespace mozilla {
28 #ifdef PR_LOGGING
29 PRLogModuleInfo* gWMFByteStreamLog = nullptr;
30 #define WMF_BS_LOG(...) PR_LOG(gWMFByteStreamLog, PR_LOG_DEBUG, (__VA_ARGS__))
31 #else
32 #define WMF_BS_LOG(...)
33 #endif
35 WMFByteStream::WMFByteStream(MediaResource* aResource,
36 WMFSourceReaderCallback* aSourceReaderCallback)
37 : mSourceReaderCallback(aSourceReaderCallback),
38 mResource(aResource),
39 mReentrantMonitor("WMFByteStream.Data"),
40 mOffset(0),
41 mIsShutdown(false)
42 {
43 NS_ASSERTION(NS_IsMainThread(), "Must be on main thread.");
44 NS_ASSERTION(mSourceReaderCallback, "Must have a source reader callback.");
46 #ifdef PR_LOGGING
47 if (!gWMFByteStreamLog) {
48 gWMFByteStreamLog = PR_NewLogModule("WMFByteStream");
49 }
50 #endif
51 WMF_BS_LOG("[%p] WMFByteStream CTOR", this);
52 MOZ_COUNT_CTOR(WMFByteStream);
53 }
55 WMFByteStream::~WMFByteStream()
56 {
57 MOZ_COUNT_DTOR(WMFByteStream);
58 WMF_BS_LOG("[%p] WMFByteStream DTOR", this);
59 }
61 nsresult
62 WMFByteStream::Init()
63 {
64 NS_ASSERTION(NS_IsMainThread(), "Must be on main thread.");
66 mThreadPool = SharedThreadPool::Get(NS_LITERAL_CSTRING("WMFByteStream IO"), 4);
67 NS_ENSURE_TRUE(mThreadPool, NS_ERROR_FAILURE);
69 NS_ConvertUTF8toUTF16 contentTypeUTF16(mResource->GetContentType());
70 if (!contentTypeUTF16.IsEmpty()) {
71 HRESULT hr = wmf::MFCreateAttributes(byRef(mAttributes), 1);
72 NS_ENSURE_TRUE(SUCCEEDED(hr), NS_ERROR_FAILURE);
74 hr = mAttributes->SetString(MF_BYTESTREAM_CONTENT_TYPE,
75 contentTypeUTF16.get());
76 NS_ENSURE_TRUE(SUCCEEDED(hr), NS_ERROR_FAILURE);
78 WMF_BS_LOG("[%p] WMFByteStream has Content-Type=%s", this, mResource->GetContentType().get());
79 }
80 return NS_OK;
81 }
83 nsresult
84 WMFByteStream::Shutdown()
85 {
86 {
87 ReentrantMonitorAutoEnter mon(mReentrantMonitor);
88 mIsShutdown = true;
89 }
90 mSourceReaderCallback->Cancel();
91 return NS_OK;
92 }
94 // IUnknown Methods
95 STDMETHODIMP
96 WMFByteStream::QueryInterface(REFIID aIId, void **aInterface)
97 {
98 WMF_BS_LOG("[%p] WMFByteStream::QueryInterface %s", this, GetGUIDName(aIId).get());
100 if (aIId == IID_IMFByteStream) {
101 return DoGetInterface(static_cast<IMFByteStream*>(this), aInterface);
102 }
103 if (aIId == IID_IUnknown) {
104 return DoGetInterface(static_cast<IMFByteStream*>(this), aInterface);
105 }
106 if (aIId == IID_IMFAttributes) {
107 return DoGetInterface(static_cast<IMFAttributes*>(this), aInterface);
108 }
110 *aInterface = nullptr;
111 return E_NOINTERFACE;
112 }
114 NS_IMPL_ADDREF(WMFByteStream)
115 NS_IMPL_RELEASE(WMFByteStream)
118 // Stores data regarding an async read opreation.
119 class ReadRequest MOZ_FINAL : public IUnknown {
120 public:
121 ReadRequest(int64_t aOffset, BYTE* aBuffer, ULONG aLength)
122 : mOffset(aOffset),
123 mBuffer(aBuffer),
124 mBufferLength(aLength),
125 mBytesRead(0)
126 {}
128 // IUnknown Methods
129 STDMETHODIMP QueryInterface(REFIID aRIID, LPVOID *aOutObject);
130 STDMETHODIMP_(ULONG) AddRef();
131 STDMETHODIMP_(ULONG) Release();
133 int64_t mOffset;
134 BYTE* mBuffer;
135 ULONG mBufferLength;
136 ULONG mBytesRead;
138 // IUnknown ref counting.
139 ThreadSafeAutoRefCnt mRefCnt;
140 NS_DECL_OWNINGTHREAD
141 };
143 NS_IMPL_ADDREF(ReadRequest)
144 NS_IMPL_RELEASE(ReadRequest)
146 // IUnknown Methods
147 STDMETHODIMP
148 ReadRequest::QueryInterface(REFIID aIId, void **aInterface)
149 {
150 WMF_BS_LOG("ReadRequest::QueryInterface %s", GetGUIDName(aIId).get());
152 if (aIId == IID_IUnknown) {
153 return DoGetInterface(static_cast<IUnknown*>(this), aInterface);
154 }
156 *aInterface = nullptr;
157 return E_NOINTERFACE;
158 }
160 class ProcessReadRequestEvent MOZ_FINAL : public nsRunnable {
161 public:
162 ProcessReadRequestEvent(WMFByteStream* aStream,
163 IMFAsyncResult* aResult,
164 ReadRequest* aRequestState)
165 : mStream(aStream),
166 mResult(aResult),
167 mRequestState(aRequestState) {}
169 NS_IMETHOD Run() {
170 mStream->ProcessReadRequest(mResult, mRequestState);
171 return NS_OK;
172 }
173 private:
174 RefPtr<WMFByteStream> mStream;
175 RefPtr<IMFAsyncResult> mResult;
176 RefPtr<ReadRequest> mRequestState;
177 };
179 // IMFByteStream Methods
180 STDMETHODIMP
181 WMFByteStream::BeginRead(BYTE *aBuffer,
182 ULONG aLength,
183 IMFAsyncCallback *aCallback,
184 IUnknown *aCallerState)
185 {
186 NS_ENSURE_TRUE(aBuffer, E_POINTER);
187 NS_ENSURE_TRUE(aCallback, E_POINTER);
189 ReentrantMonitorAutoEnter mon(mReentrantMonitor);
190 WMF_BS_LOG("[%p] WMFByteStream::BeginRead() mOffset=%lld tell=%lld length=%lu mIsShutdown=%d",
191 this, mOffset, mResource->Tell(), aLength, mIsShutdown);
193 if (mIsShutdown || mOffset < 0) {
194 return E_INVALIDARG;
195 }
197 // Create an object to store our state.
198 RefPtr<ReadRequest> requestState = new ReadRequest(mOffset, aBuffer, aLength);
200 // Create an IMFAsyncResult, this is passed back to the caller as a token to
201 // retrieve the number of bytes read.
202 RefPtr<IMFAsyncResult> callersResult;
203 HRESULT hr = wmf::MFCreateAsyncResult(requestState,
204 aCallback,
205 aCallerState,
206 byRef(callersResult));
207 NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
209 // Dispatch an event to perform the read in the thread pool.
210 nsCOMPtr<nsIRunnable> r = new ProcessReadRequestEvent(this,
211 callersResult,
212 requestState);
213 nsresult rv = mThreadPool->Dispatch(r, NS_DISPATCH_NORMAL);
215 if (mResource->GetLength() > -1) {
216 mOffset = std::min<int64_t>(mOffset + aLength, mResource->GetLength());
217 } else {
218 mOffset += aLength;
219 }
221 return NS_SUCCEEDED(rv) ? S_OK : E_FAIL;
222 }
224 nsresult
225 WMFByteStream::Read(ReadRequest* aRequestState)
226 {
227 // Read in a loop to ensure we fill the buffer, when possible.
228 ULONG totalBytesRead = 0;
229 nsresult rv = NS_OK;
230 while (totalBytesRead < aRequestState->mBufferLength) {
231 BYTE* buffer = aRequestState->mBuffer + totalBytesRead;
232 ULONG bytesRead = 0;
233 ULONG length = aRequestState->mBufferLength - totalBytesRead;
234 rv = mResource->ReadAt(aRequestState->mOffset + totalBytesRead,
235 reinterpret_cast<char*>(buffer),
236 length,
237 reinterpret_cast<uint32_t*>(&bytesRead));
238 NS_ENSURE_SUCCESS(rv, rv);
239 totalBytesRead += bytesRead;
240 if (bytesRead == 0) {
241 break;
242 }
243 }
244 aRequestState->mBytesRead = totalBytesRead;
245 return NS_OK;
246 }
248 // Note: This is called on one of the thread pool's threads.
249 void
250 WMFByteStream::ProcessReadRequest(IMFAsyncResult* aResult,
251 ReadRequest* aRequestState)
252 {
253 if (mResource->GetLength() > -1 &&
254 aRequestState->mOffset > mResource->GetLength()) {
255 aResult->SetStatus(S_OK);
256 wmf::MFInvokeCallback(aResult);
257 WMF_BS_LOG("[%p] WMFByteStream::ProcessReadRequest() read offset greater than length, soft-failing read", this);
258 return;
259 }
261 nsresult rv = Read(aRequestState);
262 if (NS_FAILED(rv)) {
263 Shutdown();
264 aResult->SetStatus(E_ABORT);
265 } else {
266 aResult->SetStatus(S_OK);
267 }
269 WMF_BS_LOG("[%p] WMFByteStream::ProcessReadRequest() read %d at %lld finished rv=%x",
270 this, aRequestState->mBytesRead, aRequestState->mOffset, rv);
272 // Let caller know read is complete.
273 DebugOnly<HRESULT> hr = wmf::MFInvokeCallback(aResult);
274 NS_ASSERTION(SUCCEEDED(hr), "Failed to invoke callback!");
275 }
277 STDMETHODIMP
278 WMFByteStream::BeginWrite(const BYTE *, ULONG ,
279 IMFAsyncCallback *,
280 IUnknown *)
281 {
282 WMF_BS_LOG("[%p] WMFByteStream::BeginWrite()", this);
283 return E_NOTIMPL;
284 }
286 STDMETHODIMP
287 WMFByteStream::Close()
288 {
289 WMF_BS_LOG("[%p] WMFByteStream::Close()", this);
290 return S_OK;
291 }
293 STDMETHODIMP
294 WMFByteStream::EndRead(IMFAsyncResult* aResult, ULONG *aBytesRead)
295 {
296 NS_ENSURE_TRUE(aResult, E_POINTER);
297 NS_ENSURE_TRUE(aBytesRead, E_POINTER);
299 ReentrantMonitorAutoEnter mon(mReentrantMonitor);
301 // Extract our state object.
302 RefPtr<IUnknown> unknown;
303 HRESULT hr = aResult->GetObject(byRef(unknown));
304 if (FAILED(hr) || !unknown) {
305 return E_INVALIDARG;
306 }
307 ReadRequest* requestState =
308 static_cast<ReadRequest*>(unknown.get());
310 // Report result.
311 *aBytesRead = requestState->mBytesRead;
313 WMF_BS_LOG("[%p] WMFByteStream::EndRead() offset=%lld *aBytesRead=%u mOffset=%lld status=0x%x hr=0x%x eof=%d",
314 this, requestState->mOffset, *aBytesRead, mOffset, aResult->GetStatus(), hr, IsEOS());
316 return aResult->GetStatus();
317 }
319 STDMETHODIMP
320 WMFByteStream::EndWrite(IMFAsyncResult *, ULONG *)
321 {
322 WMF_BS_LOG("[%p] WMFByteStream::EndWrite()", this);
323 return E_NOTIMPL;
324 }
326 STDMETHODIMP
327 WMFByteStream::Flush()
328 {
329 WMF_BS_LOG("[%p] WMFByteStream::Flush()", this);
330 return S_OK;
331 }
333 STDMETHODIMP
334 WMFByteStream::GetCapabilities(DWORD *aCapabilities)
335 {
336 WMF_BS_LOG("[%p] WMFByteStream::GetCapabilities()", this);
337 NS_ENSURE_TRUE(aCapabilities, E_POINTER);
338 ReentrantMonitorAutoEnter mon(mReentrantMonitor);
339 bool seekable = mResource->IsTransportSeekable();
340 bool cached = mResource->IsDataCachedToEndOfResource(0);
341 *aCapabilities = MFBYTESTREAM_IS_READABLE |
342 MFBYTESTREAM_IS_SEEKABLE |
343 (!cached ? MFBYTESTREAM_IS_PARTIALLY_DOWNLOADED : 0) |
344 (!seekable ? MFBYTESTREAM_HAS_SLOW_SEEK : 0);
345 return S_OK;
346 }
348 STDMETHODIMP
349 WMFByteStream::GetCurrentPosition(QWORD *aPosition)
350 {
351 NS_ENSURE_TRUE(aPosition, E_POINTER);
352 ReentrantMonitorAutoEnter mon(mReentrantMonitor);
353 // Note: Returning the length of stream as position when read
354 // cursor is < 0 seems to be the behaviour expected by WMF, but
355 // also note it doesn't seem to expect that the position is an
356 // unsigned value since if you seek to > length and read WMF
357 // expects the read to succeed after reading 0 bytes, but if you
358 // seek to < 0 and read, the read is expected to fails... So
359 // go figure...
360 *aPosition = mOffset < 0 ? mResource->GetLength() : mOffset;
361 WMF_BS_LOG("[%p] WMFByteStream::GetCurrentPosition() %lld", this, mOffset);
362 return S_OK;
363 }
365 STDMETHODIMP
366 WMFByteStream::GetLength(QWORD *aLength)
367 {
368 NS_ENSURE_TRUE(aLength, E_POINTER);
369 ReentrantMonitorAutoEnter mon(mReentrantMonitor);
370 *aLength = mResource->GetLength();
371 WMF_BS_LOG("[%p] WMFByteStream::GetLength() %lld", this, *aLength);
372 return S_OK;
373 }
375 bool
376 WMFByteStream::IsEOS()
377 {
378 ReentrantMonitorAutoEnter mon(mReentrantMonitor);
379 return mResource->GetLength() > -1 &&
380 (mOffset < 0 ||
381 mOffset >= mResource->GetLength());
382 }
384 STDMETHODIMP
385 WMFByteStream::IsEndOfStream(BOOL *aEndOfStream)
386 {
387 NS_ENSURE_TRUE(aEndOfStream, E_POINTER);
388 *aEndOfStream = IsEOS();
389 WMF_BS_LOG("[%p] WMFByteStream::IsEndOfStream() %d", this, *aEndOfStream);
390 return S_OK;
391 }
393 STDMETHODIMP
394 WMFByteStream::Read(BYTE* aBuffer, ULONG aBufferLength, ULONG* aOutBytesRead)
395 {
396 ReentrantMonitorAutoEnter mon(mReentrantMonitor);
397 ReadRequest request(mOffset, aBuffer, aBufferLength);
398 if (NS_FAILED(Read(&request))) {
399 WMF_BS_LOG("[%p] WMFByteStream::Read() offset=%lld failed!", this, mOffset);
400 return E_FAIL;
401 }
402 if (aOutBytesRead) {
403 *aOutBytesRead = request.mBytesRead;
404 }
405 WMF_BS_LOG("[%p] WMFByteStream::Read() offset=%lld length=%u bytesRead=%u",
406 this, mOffset, aBufferLength, request.mBytesRead);
407 mOffset += request.mBytesRead;
408 return S_OK;
409 }
411 STDMETHODIMP
412 WMFByteStream::Seek(MFBYTESTREAM_SEEK_ORIGIN aSeekOrigin,
413 LONGLONG aSeekOffset,
414 DWORD aSeekFlags,
415 QWORD *aCurrentPosition)
416 {
417 WMF_BS_LOG("[%p] WMFByteStream::Seek(%d, %lld)", this, aSeekOrigin, aSeekOffset);
419 ReentrantMonitorAutoEnter mon(mReentrantMonitor);
421 int64_t offset = mOffset;
422 if (aSeekOrigin == msoBegin) {
423 offset = aSeekOffset;
424 } else {
425 offset += aSeekOffset;
426 }
427 int64_t length = mResource->GetLength();
428 if (length > -1) {
429 mOffset = std::min<int64_t>(offset, length);
430 } else {
431 mOffset = offset;
432 }
433 if (aCurrentPosition) {
434 *aCurrentPosition = mOffset;
435 }
437 return S_OK;
438 }
440 STDMETHODIMP
441 WMFByteStream::SetCurrentPosition(QWORD aPosition)
442 {
443 ReentrantMonitorAutoEnter mon(mReentrantMonitor);
444 WMF_BS_LOG("[%p] WMFByteStream::SetCurrentPosition(%lld)",
445 this, aPosition);
447 int64_t length = mResource->GetLength();
448 if (length > -1) {
449 mOffset = std::min<int64_t>(aPosition, length);
450 } else {
451 mOffset = aPosition;
452 }
454 return S_OK;
455 }
457 STDMETHODIMP
458 WMFByteStream::SetLength(QWORD)
459 {
460 WMF_BS_LOG("[%p] WMFByteStream::SetLength()", this);
461 return E_NOTIMPL;
462 }
464 STDMETHODIMP
465 WMFByteStream::Write(const BYTE *, ULONG, ULONG *)
466 {
467 WMF_BS_LOG("[%p] WMFByteStream::Write()", this);
468 return E_NOTIMPL;
469 }
471 // IMFAttributes methods
472 STDMETHODIMP
473 WMFByteStream::GetItem(REFGUID guidKey, PROPVARIANT* pValue)
474 {
475 MOZ_ASSERT(mAttributes);
476 return mAttributes->GetItem(guidKey, pValue);
477 }
479 STDMETHODIMP
480 WMFByteStream::GetItemType(REFGUID guidKey, MF_ATTRIBUTE_TYPE* pType)
481 {
482 assert(mAttributes);
483 return mAttributes->GetItemType(guidKey, pType);
484 }
486 STDMETHODIMP
487 WMFByteStream::CompareItem(REFGUID guidKey, REFPROPVARIANT Value, BOOL* pbResult)
488 {
489 assert(mAttributes);
490 return mAttributes->CompareItem(guidKey, Value, pbResult);
491 }
493 STDMETHODIMP
494 WMFByteStream::Compare(IMFAttributes* pTheirs,
495 MF_ATTRIBUTES_MATCH_TYPE MatchType,
496 BOOL* pbResult)
497 {
498 assert(mAttributes);
499 return mAttributes->Compare(pTheirs, MatchType, pbResult);
500 }
502 STDMETHODIMP
503 WMFByteStream::GetUINT32(REFGUID guidKey, UINT32* punValue)
504 {
505 assert(mAttributes);
506 return mAttributes->GetUINT32(guidKey, punValue);
507 }
509 STDMETHODIMP
510 WMFByteStream::GetUINT64(REFGUID guidKey, UINT64* punValue)
511 {
512 assert(mAttributes);
513 return mAttributes->GetUINT64(guidKey, punValue);
514 }
516 STDMETHODIMP
517 WMFByteStream::GetDouble(REFGUID guidKey, double* pfValue)
518 {
519 assert(mAttributes);
520 return mAttributes->GetDouble(guidKey, pfValue);
521 }
523 STDMETHODIMP
524 WMFByteStream::GetGUID(REFGUID guidKey, GUID* pguidValue)
525 {
526 assert(mAttributes);
527 return mAttributes->GetGUID(guidKey, pguidValue);
528 }
530 STDMETHODIMP
531 WMFByteStream::GetStringLength(REFGUID guidKey, UINT32* pcchLength)
532 {
533 assert(mAttributes);
534 return mAttributes->GetStringLength(guidKey, pcchLength);
535 }
537 STDMETHODIMP
538 WMFByteStream::GetString(REFGUID guidKey, LPWSTR pwszValue, UINT32 cchBufSize, UINT32* pcchLength)
539 {
540 assert(mAttributes);
541 return mAttributes->GetString(guidKey, pwszValue, cchBufSize, pcchLength);
542 }
544 STDMETHODIMP
545 WMFByteStream::GetAllocatedString(REFGUID guidKey, LPWSTR* ppwszValue, UINT32* pcchLength)
546 {
547 assert(mAttributes);
548 return mAttributes->GetAllocatedString(guidKey, ppwszValue, pcchLength);
549 }
551 STDMETHODIMP
552 WMFByteStream::GetBlobSize(REFGUID guidKey, UINT32* pcbBlobSize)
553 {
554 assert(mAttributes);
555 return mAttributes->GetBlobSize(guidKey, pcbBlobSize);
556 }
558 STDMETHODIMP
559 WMFByteStream::GetBlob(REFGUID guidKey, UINT8* pBuf, UINT32 cbBufSize, UINT32* pcbBlobSize)
560 {
561 assert(mAttributes);
562 return mAttributes->GetBlob(guidKey, pBuf, cbBufSize, pcbBlobSize);
563 }
565 STDMETHODIMP
566 WMFByteStream::GetAllocatedBlob(REFGUID guidKey, UINT8** ppBuf, UINT32* pcbSize)
567 {
568 assert(mAttributes);
569 return mAttributes->GetAllocatedBlob(guidKey, ppBuf, pcbSize);
570 }
572 STDMETHODIMP
573 WMFByteStream::GetUnknown(REFGUID guidKey, REFIID riid, LPVOID* ppv)
574 {
575 assert(mAttributes);
576 return mAttributes->GetUnknown(guidKey, riid, ppv);
577 }
579 STDMETHODIMP
580 WMFByteStream::SetItem(REFGUID guidKey, REFPROPVARIANT Value)
581 {
582 assert(mAttributes);
583 return mAttributes->SetItem(guidKey, Value);
584 }
586 STDMETHODIMP
587 WMFByteStream::DeleteItem(REFGUID guidKey)
588 {
589 assert(mAttributes);
590 return mAttributes->DeleteItem(guidKey);
591 }
593 STDMETHODIMP
594 WMFByteStream::DeleteAllItems()
595 {
596 assert(mAttributes);
597 return mAttributes->DeleteAllItems();
598 }
600 STDMETHODIMP
601 WMFByteStream::SetUINT32(REFGUID guidKey, UINT32 unValue)
602 {
603 assert(mAttributes);
604 return mAttributes->SetUINT32(guidKey, unValue);
605 }
607 STDMETHODIMP
608 WMFByteStream::SetUINT64(REFGUID guidKey,UINT64 unValue)
609 {
610 assert(mAttributes);
611 return mAttributes->SetUINT64(guidKey, unValue);
612 }
614 STDMETHODIMP
615 WMFByteStream::SetDouble(REFGUID guidKey, double fValue)
616 {
617 assert(mAttributes);
618 return mAttributes->SetDouble(guidKey, fValue);
619 }
621 STDMETHODIMP
622 WMFByteStream::SetGUID(REFGUID guidKey, REFGUID guidValue)
623 {
624 assert(mAttributes);
625 return mAttributes->SetGUID(guidKey, guidValue);
626 }
628 STDMETHODIMP
629 WMFByteStream::SetString(REFGUID guidKey, LPCWSTR wszValue)
630 {
631 assert(mAttributes);
632 return mAttributes->SetString(guidKey, wszValue);
633 }
635 STDMETHODIMP
636 WMFByteStream::SetBlob(REFGUID guidKey, const UINT8* pBuf, UINT32 cbBufSize)
637 {
638 assert(mAttributes);
639 return mAttributes->SetBlob(guidKey, pBuf, cbBufSize);
640 }
642 STDMETHODIMP
643 WMFByteStream::SetUnknown(REFGUID guidKey, IUnknown* pUnknown)
644 {
645 assert(mAttributes);
646 return mAttributes->SetUnknown(guidKey, pUnknown);
647 }
649 STDMETHODIMP
650 WMFByteStream::LockStore()
651 {
652 assert(mAttributes);
653 return mAttributes->LockStore();
654 }
656 STDMETHODIMP
657 WMFByteStream::UnlockStore()
658 {
659 assert(mAttributes);
660 return mAttributes->UnlockStore();
661 }
663 STDMETHODIMP
664 WMFByteStream::GetCount(UINT32* pcItems)
665 {
666 assert(mAttributes);
667 return mAttributes->GetCount(pcItems);
668 }
670 STDMETHODIMP
671 WMFByteStream::GetItemByIndex(UINT32 unIndex, GUID* pguidKey, PROPVARIANT* pValue)
672 {
673 assert(mAttributes);
674 return mAttributes->GetItemByIndex(unIndex, pguidKey, pValue);
675 }
677 STDMETHODIMP
678 WMFByteStream::CopyAllItems(IMFAttributes* pDest)
679 {
680 assert(mAttributes);
681 return mAttributes->CopyAllItems(pDest);
682 }
684 } // namespace mozilla