nsresult WebMReader::Seek(int64_t aTarget, int64_t aStartTime, int64_t aEndTime, int64_t aCurrentTime) { NS_ASSERTION(mDecoder->OnDecodeThread(), "Should be on decode thread."); LOG(PR_LOG_DEBUG, ("Reader [%p] for Decoder [%p]: About to seek to %fs", this, mDecoder, aTarget/1000000.0)); if (NS_FAILED(ResetDecode())) { return NS_ERROR_FAILURE; } uint32_t trackToSeek = mHasVideo ? mVideoTrack : mAudioTrack; int r = nestegg_track_seek(mContext, trackToSeek, aTarget * NS_PER_USEC); if (r != 0) { return NS_ERROR_FAILURE; } #ifdef MOZ_DASH // Find next cluster index; MediaResource* resource = mDecoder->GetResource(); int64_t newOffset = resource->Tell(); for (uint32_t i = 1; i < mClusterByteRanges.Length(); i++) { if (newOffset < mClusterByteRanges[i].mStart) { mNextCluster = i; LOG(PR_LOG_DEBUG, ("WebMReader [%p] for decoder [%p] updating mNextCluster to [%d] " "after seek to offset [%lld]", this, mDecoder, mNextCluster, resource->Tell())); break; } } #endif return DecodeToTarget(aTarget); }
gboolean GStreamerReader::SeekData(GstAppSrc* aSrc, guint64 aOffset) { aOffset += mDataOffset; ReentrantMonitorAutoEnter mon(mGstThreadsMonitor); MediaResource* resource = mDecoder->GetResource(); int64_t resourceLength = resource->GetLength(); if (gst_app_src_get_size(mSource) == -1) { /* It's possible that we didn't know the length when we initialized mSource * but maybe we do now */ gst_app_src_set_size(mSource, GetDataLength()); } nsresult rv = NS_ERROR_FAILURE; if (aOffset < static_cast<guint64>(resourceLength)) { rv = resource->Seek(SEEK_SET, aOffset); } if (NS_FAILED(rv)) { LOG(PR_LOG_ERROR, "seek at %lu failed", aOffset); } else { MOZ_ASSERT(aOffset == static_cast<guint64>(resource->Tell())); } return NS_SUCCEEDED(rv); }
static int64_t webm_tell(void *aUserData) { NS_ASSERTION(aUserData, "aUserData must point to a valid AbstractMediaDecoder"); AbstractMediaDecoder* decoder = reinterpret_cast<AbstractMediaDecoder*>(aUserData); MediaResource* resource = decoder->GetResource(); NS_ASSERTION(resource, "Decoder has no media resource"); return resource->Tell(); }
static bool Read(Decoder *aDecoder, char *aBuffer, int64_t aOffset, uint32_t aCount, uint32_t* aBytes) { MediaResource *resource = GetResource(aDecoder); if (aOffset != resource->Tell()) { nsresult rv = resource->Seek(nsISeekableStream::NS_SEEK_SET, aOffset); if (NS_FAILED(rv)) { return false; } } nsresult rv = resource->Read(aBuffer, aCount, aBytes); if (NS_FAILED(rv)) { return false; } return true; }
/* * If we're not at end of stream, read |aNumBytes| from the media resource, * put it in |aData|, and return true. * Otherwise, put as much data as is left into |aData|, set |aNumBytes| to the * amount of data we have left, and return false. * * This function also passes the read data on to the MP3 frame parser for * stream duration estimation. */ nsresult AppleMP3Reader::ReadAndNotify(uint32_t *aNumBytes, char *aData) { MediaResource *resource = mDecoder->GetResource(); uint64_t offset = resource->Tell(); // Loop until we have all the data asked for, or we've reached EOS uint32_t totalBytes = 0; uint32_t numBytes; do { uint32_t bytesWanted = *aNumBytes - totalBytes; nsresult rv = resource->Read(aData + totalBytes, bytesWanted, &numBytes); totalBytes += numBytes; if (NS_FAILED(rv)) { *aNumBytes = 0; return NS_ERROR_FAILURE; } } while(totalBytes < *aNumBytes && numBytes); // Pass the buffer to the MP3 frame parser to improve our duration estimate. if (mMP3FrameParser.IsMP3()) { mMP3FrameParser.Parse(aData, totalBytes, offset); uint64_t duration = mMP3FrameParser.GetDuration(); if (duration != mDuration) { LOGD("Updating media duration to %lluus\n", duration); mDuration = duration; ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor()); mDecoder->UpdateEstimatedMediaDuration(duration); } } *aNumBytes = totalBytes; // We will have read some data in the last iteration iff we filled the buffer. // XXX Maybe return a better value than NS_ERROR_FAILURE? return numBytes ? NS_OK : NS_ERROR_FAILURE; }
void GStreamerReader::ReadAndPushData(guint aLength) { MediaResource* resource = mDecoder->GetResource(); NS_ASSERTION(resource, "Decoder has no media resource"); int64_t offset1 = resource->Tell(); unused << offset1; nsresult rv = NS_OK; GstBuffer* buffer = gst_buffer_new_and_alloc(aLength); #if GST_VERSION_MAJOR >= 1 GstMapInfo info; gst_buffer_map(buffer, &info, GST_MAP_WRITE); guint8 *data = info.data; #else guint8* data = GST_BUFFER_DATA(buffer); #endif uint32_t size = 0, bytesRead = 0; while(bytesRead < aLength) { rv = resource->Read(reinterpret_cast<char*>(data + bytesRead), aLength - bytesRead, &size); if (NS_FAILED(rv) || size == 0) break; bytesRead += size; } int64_t offset2 = resource->Tell(); unused << offset2; #if GST_VERSION_MAJOR >= 1 gst_buffer_unmap(buffer, &info); gst_buffer_set_size(buffer, bytesRead); #else GST_BUFFER_SIZE(buffer) = bytesRead; #endif GstFlowReturn ret = gst_app_src_push_buffer(mSource, gst_buffer_ref(buffer)); if (ret != GST_FLOW_OK) { LOG(PR_LOG_ERROR, "ReadAndPushData push ret %s(%d)", gst_flow_get_name(ret), ret); } if (NS_FAILED(rv)) { /* Terminate the stream if there is an error in reading */ LOG(PR_LOG_ERROR, "ReadAndPushData read error, rv=%x", rv); gst_app_src_end_of_stream(mSource); } else if (bytesRead < aLength) { /* If we read less than what we wanted, we reached the end */ LOG(PR_LOG_WARNING, "ReadAndPushData read underflow, " "bytesRead=%u, aLength=%u, offset(%lld,%lld)", bytesRead, aLength, offset1, offset2); gst_app_src_end_of_stream(mSource); } gst_buffer_unref(buffer); /* Ensure offset change is consistent in this function. * If there are other stream operations on another thread at the same time, * it will disturb the GStreamer state machine. */ MOZ_ASSERT(offset1 + bytesRead == offset2); }