private bool ReadTag() {
			uint tagType, dataSize, timeStamp, streamID, mediaInfo;
			byte[] data;

			if ((_fileLength - _fileOffset) < 11) {
				return false;
			}

			// Read tag header
			tagType = ReadUInt8();
			dataSize = ReadUInt24();
			timeStamp = ReadUInt24();
			timeStamp |= ReadUInt8() << 24;
			streamID = ReadUInt24();

			// Read tag data
			if (dataSize == 0) {
				return true;
			}
			if ((_fileLength - _fileOffset) < dataSize) {
				return false;
			}
			mediaInfo = ReadUInt8();
			dataSize -= 1;
			data = ReadBytes((int)dataSize);

			if (tagType == 0x8) {  // Audio
				if (_audioWriter == null) {
					_audioWriter = _extractAudio ? GetAudioWriter(mediaInfo) : new DummyAudioWriter();
					_extractedAudio = !(_audioWriter is DummyAudioWriter);
				}
				_audioWriter.WriteChunk(data, timeStamp);
			}
			else if ((tagType == 0x9) && ((mediaInfo >> 4) != 5)) { // Video
				if (_videoWriter == null) {
					_videoWriter = _extractVideo ? GetVideoWriter(mediaInfo) : new DummyVideoWriter();
					_extractedVideo = !(_videoWriter is DummyVideoWriter);
				}
				if (_timeCodeWriter == null) {
					string path = _outputPathBase + ".txt";
					_timeCodeWriter = new TimeCodeWriter((_extractTimeCodes && CanWriteTo(path)) ? path : null);
					_extractedTimeCodes = _extractTimeCodes;
				}
				_videoTimeStamps.Add(timeStamp);
				_videoWriter.WriteChunk(data, timeStamp, (int)((mediaInfo & 0xF0) >> 4));
				_timeCodeWriter.Write(timeStamp);
			}

			return true;
		}
		private void CloseOutput(FractionUInt32? averageFrameRate, bool disposing) {
			if (_videoWriter != null) {
				_videoWriter.Finish(averageFrameRate ?? new FractionUInt32(25, 1));
				if (disposing && (_videoWriter.Path != null)) {
					try { File.Delete(_videoWriter.Path); }
					catch { }
				}
				_videoWriter = null;
			}
			if (_audioWriter != null) {
				_audioWriter.Finish();
				if (disposing && (_audioWriter.Path != null)) {
					try { File.Delete(_audioWriter.Path); }
					catch { }
				}
				_audioWriter = null;
			}
			if (_timeCodeWriter != null) {
				_timeCodeWriter.Finish();
				if (disposing && (_timeCodeWriter.Path != null)) {
					try { File.Delete(_timeCodeWriter.Path); }
					catch { }
				}
				_timeCodeWriter = null;
			}
		}