/* Empty the write buffer to disk. Return -1 on error, 0 on success. */ int RageFileObj::EmptyWriteBuf() { if( m_pWriteBuffer == NULL ) return 0; if( m_iWriteBufferUsed ) { /* The write buffer might not align with the actual file, if we've seeked. Only * seek if needed. */ bool bSeeked = (m_iWriteBufferPos+m_iWriteBufferUsed != m_iFilePos); if( bSeeked ) SeekInternal( m_iWriteBufferPos ); int iRet = WriteInternal( m_pWriteBuffer, m_iWriteBufferUsed ); if( bSeeked ) SeekInternal( m_iFilePos ); if( iRet == -1 ) return iRet; } m_iWriteBufferPos = m_iFilePos; m_iWriteBufferUsed = 0; return 0; }
nsresult SourceBufferResource::Seek(int32_t aWhence, int64_t aOffset) { SBR_DEBUG("Seek(aWhence=%d, aOffset=%lld)", aWhence, aOffset); ReentrantMonitorAutoEnter mon(mMonitor); int64_t newOffset = mOffset; switch (aWhence) { case nsISeekableStream::NS_SEEK_END: newOffset = GetLength() - aOffset; break; case nsISeekableStream::NS_SEEK_CUR: newOffset += aOffset; break; case nsISeekableStream::NS_SEEK_SET: newOffset = aOffset; break; } SBR_DEBUGV("newOffset=%lld GetOffset()=%llu GetLength()=%llu)", newOffset, mInputBuffer.GetOffset(), GetLength()); nsresult rv = SeekInternal(newOffset); mon.NotifyAll(); return rv; }
bool File::Open(PackageFile* package, const String& fileName) { if (!package) return false; const PackageEntry* entry = package->GetEntry(fileName); if (!entry) return false; bool success = OpenInternal(package->GetName(), FILE_READ, true); if (!success) { ATOMIC_LOGERROR("Could not open package file " + fileName); return false; } fileName_ = fileName; offset_ = entry->offset_; checksum_ = entry->checksum_; size_ = entry->size_; compressed_ = package->IsCompressed(); // Seek to beginning of package entry's file data SeekInternal(offset_); return true; }
nsRefPtr<MediaDecoderReader::SeekPromise> WMFReader::Seek(int64_t aTargetUs, int64_t aEndTime) { nsresult res = SeekInternal(aTargetUs); if (NS_FAILED(res)) { return SeekPromise::CreateAndReject(res, __func__); } else { return SeekPromise::CreateAndResolve(aTargetUs, __func__); } }
RefPtr<ReaderProxy::SeekPromise> ReaderProxy::Seek(const SeekTarget& aTarget) { MOZ_ASSERT(mOwnerThread->IsCurrentThreadIn()); mSeamlessLoopingBlocked = true; // Reset the members for seamless looping if the seek is triggered outside. mLoopingOffset = media::TimeUnit::Zero(); mLastAudioEndTime = media::TimeUnit::Zero(); mAudioDuration = media::TimeUnit::Invalid(); return SeekInternal(aTarget); }
unsigned File::Seek(unsigned position) { if (!IsOpen()) { // If file not open, do not log the error further here to prevent spamming the stderr stream return 0; } // Allow sparse seeks if writing if (mode_ == FILE_READ && position > size_) position = size_; if (compressed_) { // Start over from the beginning if (position == 0) { position_ = 0; readBufferOffset_ = 0; readBufferSize_ = 0; SeekInternal(offset_); } // Skip bytes else if (position >= position_) { unsigned char skipBuffer[SKIP_BUFFER_SIZE]; while (position > position_) Read(skipBuffer, Min(position - position_, SKIP_BUFFER_SIZE)); } else ATOMIC_LOGERROR("Seeking backward in a compressed file is not supported"); return position_; } SeekInternal(position + offset_); position_ = position; readSyncNeeded_ = false; writeSyncNeeded_ = false; return position_; }
nsresult SourceBufferResource::ReadAtInternal(int64_t aOffset, char* aBuffer, uint32_t aCount, uint32_t* aBytes, bool aMayBlock) { mMonitor.AssertCurrentThreadIn(); nsresult rv = SeekInternal(aOffset); if (NS_FAILED(rv)) { return rv; } return ReadInternal(aBuffer, aCount, aBytes, aMayBlock); }
RefPtr<ReaderProxy::AudioDataPromise> ReaderProxy::OnAudioDataRequestFailed(const MediaResult& aError) { MOZ_ASSERT(mOwnerThread->IsCurrentThreadIn()); if (mSeamlessLoopingBlocked || !mSeamlessLoopingEnabled || aError.Code() != NS_ERROR_DOM_MEDIA_END_OF_STREAM) { return AudioDataPromise::CreateAndReject(aError, __func__); } // The data time in the audio queue is assumed to be increased linearly, // so we need to add the last ending time as the offset to correct the // audio data time in the next round when seamless looping is enabled. mLoopingOffset = mLastAudioEndTime; // Save the duration of the audio track if it hasn't been set. if (!mAudioDuration.IsValid()) { mAudioDuration = mLastAudioEndTime; } // For seamless looping, the demuxer is sought to the beginning and then // keep requesting decoded data in advance, upon receiving EOS. // The MDSM will not be aware of the EOS and keep receiving decoded data // as usual while looping is on. RefPtr<ReaderProxy> self = this; RefPtr<MediaFormatReader> reader = mReader; ResetDecode(TrackInfo::kAudioTrack); return SeekInternal(SeekTarget(media::TimeUnit::Zero(), SeekTarget::Accurate)) ->Then(mReader->OwnerThread(), __func__, [reader]() { return reader->RequestAudioData(); }, [](const SeekRejectValue& aReject) { return AudioDataPromise::CreateAndReject(aReject.mError, __func__); }) ->Then(mOwnerThread, __func__, [self](RefPtr<AudioData> aAudio) { return self->OnAudioDataRequestCompleted(aAudio.forget()); }, [](const MediaResult& aError) { return AudioDataPromise::CreateAndReject(aError, __func__); }); }
int RageFileObj::Seek( int iOffset ) { /* If we're already at the requested position, short circuit and don't flush * our buffer. */ if( iOffset == m_iFilePos ) return m_iFilePos; m_bEOF = false; /* If we're calculating a CRC32, disable it. */ m_bCRC32Enabled = false; ResetReadBuf(); int iPos = SeekInternal( iOffset ); if( iPos != -1 ) m_iFilePos = iPos; return iPos; }
unsigned File::Read(void* dest, unsigned size) { if (!IsOpen()) { // If file not open, do not log the error further here to prevent spamming the stderr stream return 0; } if (mode_ == FILE_WRITE) { ATOMIC_LOGERROR("File not opened for reading"); return 0; } if (size + position_ > size_) size = size_ - position_; if (!size) return 0; #ifdef __ANDROID__ if (assetHandle_ && !compressed_) { // If not using a compressed package file, buffer file reads on Android for better performance if (!readBuffer_) { readBuffer_ = new unsigned char[READ_BUFFER_SIZE]; readBufferOffset_ = 0; readBufferSize_ = 0; } unsigned sizeLeft = size; unsigned char* destPtr = (unsigned char*)dest; while (sizeLeft) { if (readBufferOffset_ >= readBufferSize_) { readBufferSize_ = Min(size_ - position_, READ_BUFFER_SIZE); readBufferOffset_ = 0; ReadInternal(readBuffer_.Get(), readBufferSize_); } unsigned copySize = Min((readBufferSize_ - readBufferOffset_), sizeLeft); memcpy(destPtr, readBuffer_.Get() + readBufferOffset_, copySize); destPtr += copySize; sizeLeft -= copySize; readBufferOffset_ += copySize; position_ += copySize; } return size; } #endif if (compressed_) { unsigned sizeLeft = size; unsigned char* destPtr = (unsigned char*)dest; while (sizeLeft) { if (!readBuffer_ || readBufferOffset_ >= readBufferSize_) { unsigned char blockHeaderBytes[4]; ReadInternal(blockHeaderBytes, sizeof blockHeaderBytes); MemoryBuffer blockHeader(&blockHeaderBytes[0], sizeof blockHeaderBytes); unsigned unpackedSize = blockHeader.ReadUShort(); unsigned packedSize = blockHeader.ReadUShort(); if (!readBuffer_) { readBuffer_ = new unsigned char[unpackedSize]; inputBuffer_ = new unsigned char[LZ4_compressBound(unpackedSize)]; } /// \todo Handle errors ReadInternal(inputBuffer_.Get(), packedSize); LZ4_decompress_fast((const char*)inputBuffer_.Get(), (char*)readBuffer_.Get(), unpackedSize); readBufferSize_ = unpackedSize; readBufferOffset_ = 0; } unsigned copySize = Min((readBufferSize_ - readBufferOffset_), sizeLeft); memcpy(destPtr, readBuffer_.Get() + readBufferOffset_, copySize); destPtr += copySize; sizeLeft -= copySize; readBufferOffset_ += copySize; position_ += copySize; } return size; } // Need to reassign the position due to internal buffering when transitioning from writing to reading if (readSyncNeeded_) { SeekInternal(position_ + offset_); readSyncNeeded_ = false; } if (!ReadInternal(dest, size)) { // Return to the position where the read began SeekInternal(position_ + offset_); ATOMIC_LOGERROR("Error while reading from file " + GetName()); return 0; } writeSyncNeeded_ = true; position_ += size; return size; }
long long BDRingBuffer::SeekInternal(long long pos, int whence) { long long ret = -1; poslock.lockForWrite(); // Optimize no-op seeks if (readaheadrunning && ((whence == SEEK_SET && pos == readpos) || (whence == SEEK_CUR && pos == 0))) { ret = readpos; poslock.unlock(); return ret; } // only valid for SEEK_SET & SEEK_CUR long long new_pos = (SEEK_SET==whence) ? pos : readpos + pos; // Here we perform a normal seek. When successful we // need to call ResetReadAhead(). A reset means we will // need to refill the buffer, which takes some time. if ((SEEK_END == whence) || ((SEEK_CUR == whence) && new_pos != 0)) { errno = EINVAL; ret = -1; } else { SeekInternal(new_pos); m_currentTime = bd_tell_time(bdnav); ret = new_pos; } if (ret >= 0) { readpos = ret; ignorereadpos = -1; if (readaheadrunning) ResetReadAhead(readpos); readAdjust = 0; } else { QString cmd = QString("Seek(%1, %2)").arg(pos) .arg((whence == SEEK_SET) ? "SEEK_SET" : ((whence == SEEK_CUR) ?"SEEK_CUR" : "SEEK_END")); LOG(VB_GENERAL, LOG_ERR, LOC + cmd + " Failed" + ENO); } poslock.unlock(); generalWait.wakeAll(); return ret; }