/// /// Marshal an exception to the Dispatcher thread /// private static void MarshalException( QueueEntry entry, Exception e ) { lock (_syncLock) { // Fire download completion event for each decoder foreach (WeakReference decoderReference in entry.decoders) { LateBoundBitmapDecoder decoder = decoderReference.Target as LateBoundBitmapDecoder; if (decoder != null) { MarshalEvents( decoder, new DispatcherOperationCallback(decoder.ExceptionCallback), e ); } } if (entry.inputUri != null) { lock (_syncLock) { _uriTable[entry.inputUri] = null; } } } }
/// Called when download fails private void OnDownloadFailed(object sender, ExceptionEventArgs e) { // // The sender should be the LateBoundDecoder that we hooked when it was _decoder. // LateBoundBitmapDecoder decoder = (LateBoundBitmapDecoder)sender; // // Unhook the decoders download events // decoder.DownloadCompleted -= OnDownloadCompleted; decoder.DownloadProgress -= OnDownloadProgress; decoder.DownloadFailed -= OnDownloadFailed; _failedEvent.InvokeEvents(this, e); }
/// /// Marshals a call to the Dispatcher thread /// private static void MarshalEvents( LateBoundBitmapDecoder decoder, DispatcherOperationCallback doc, object arg ) { Dispatcher dispatcher = decoder.Dispatcher; if (dispatcher != null) { dispatcher.BeginInvoke(DispatcherPriority.Normal, doc, arg); } else { // Decoder seems to be thread free. This is probably bad Debug.Assert(false); } }
internal BitmapFrameDecode( int frameNumber, BitmapCreateOptions createOptions, BitmapCacheOption cacheOption, LateBoundBitmapDecoder decoder ) : base(true) { _bitmapInit.BeginInit(); _frameNumber = frameNumber; byte[] pixels = new byte[4]; BitmapSource source = BitmapSource.Create( 1, 1, 96, 96, PixelFormats.Pbgra32, null, pixels, 4 ); WicSourceHandle = source.WicSourceHandle; Debug.Assert(decoder != null); _decoder = decoder; _createOptions = createOptions; _cacheOption = cacheOption; // // Hook the decoders download events // _decoder.DownloadCompleted += OnDownloadCompleted; _decoder.DownloadProgress += OnDownloadProgress; _decoder.DownloadFailed += OnDownloadFailed; _bitmapInit.EndInit(); }
/// /// Read callback /// private static void ReadCallback(IAsyncResult result) { QueueEntry entry = (QueueEntry)result.AsyncState; int bytesRead = 0; #pragma warning disable 6500 try { bytesRead = entry.inputStream.EndRead(result); } catch (Exception e) { MarshalException(entry, e); } #pragma warning restore 6500 if (bytesRead == 0) { // // We're done reading from the input stream. // entry.inputStream.Close(); entry.inputStream = null; // // We're done writing to the output stream. Make sure everything // is written to disk. // entry.outputStream.Flush(); entry.outputStream.Seek(0, SeekOrigin.Begin); lock (_syncLock) { // Fire download progress & completion event for each decoder foreach (WeakReference decoderReference in entry.decoders) { LateBoundBitmapDecoder decoder = decoderReference.Target as LateBoundBitmapDecoder; if (decoder != null) { // // Marshal events to UI thread // MarshalEvents( decoder, new DispatcherOperationCallback(decoder.ProgressCallback), 100 ); MarshalEvents( decoder, new DispatcherOperationCallback(decoder.DownloadCallback), entry.outputStream ); } } } // Delete entry from uri table if (entry.inputUri != null) { lock (_syncLock) { _uriTable[entry.inputUri] = null; } } } else { entry.outputStream.Write(entry.readBuffer, 0, bytesRead); if (entry.contentLength > 0) { int percentComplete = (int)Math.Floor(100.0 * (double)entry.outputStream.Length / (double)entry.contentLength); // Only raise if percentage went up by ~1% (ie value changed). if (percentComplete != entry.lastPercent) { // Update last value entry.lastPercent = percentComplete; lock (_syncLock) { // Fire download progress event for each decoder foreach (WeakReference decoderReference in entry.decoders) { LateBoundBitmapDecoder decoder = decoderReference.Target as LateBoundBitmapDecoder; if (decoder != null) { // // Marshal events to UI thread // MarshalEvents( decoder, new DispatcherOperationCallback(decoder.ProgressCallback), percentComplete ); } } } } } _workQueue.Enqueue(entry); _waitEvent.Set(); } }