TimeUnit MP3TrackDemuxer::ScanUntil(const TimeUnit& aTime) { MP3LOG("ScanUntil(%" PRId64 ") avgFrameLen=%f mNumParsedFrames=%" PRIu64 " mFrameIndex=%" PRId64 " mOffset=%" PRIu64, aTime.ToMicroseconds(), AverageFrameLength(), mNumParsedFrames, mFrameIndex, mOffset); if (!aTime.ToMicroseconds()) { return FastSeek(aTime); } if (Duration(mFrameIndex) > aTime) { FastSeek(aTime); } if (Duration(mFrameIndex + 1) > aTime) { return SeekPosition(); } MediaByteRange nextRange = FindNextFrame(); while (SkipNextFrame(nextRange) && Duration(mFrameIndex + 1) < aTime) { nextRange = FindNextFrame(); MP3LOGV("ScanUntil* avgFrameLen=%f mNumParsedFrames=%" PRIu64 " mFrameIndex=%" PRId64 " mOffset=%" PRIu64 " Duration=%" PRId64, AverageFrameLength(), mNumParsedFrames, mFrameIndex, mOffset, Duration(mFrameIndex + 1).ToMicroseconds()); } MP3LOG("ScanUntil End avgFrameLen=%f mNumParsedFrames=%" PRIu64 " mFrameIndex=%" PRId64 " mOffset=%" PRIu64, AverageFrameLength(), mNumParsedFrames, mFrameIndex, mOffset); return SeekPosition(); }
bool MediaSourceDecoder::CanPlayThrough() { MOZ_ASSERT(NS_IsMainThread()); if (NextFrameBufferedStatus() == MediaDecoderOwner::NEXT_FRAME_UNAVAILABLE) { return false; } if (IsNaN(mMediaSource->Duration())) { // Don't have any data yet. return false; } TimeUnit duration = TimeUnit::FromSeconds(mMediaSource->Duration()); TimeUnit currentPosition = TimeUnit::FromMicroseconds(CurrentPosition()); if (duration.IsInfinite()) { // We can't make an informed decision and just assume that it's a live stream return true; } else if (duration <= currentPosition) { return true; } // If we have data up to the mediasource's duration or 30s ahead, we can // assume that we can play without interruption. TimeUnit timeAhead = std::min(duration, currentPosition + TimeUnit::FromSeconds(30)); TimeInterval interval(currentPosition, timeAhead, MediaSourceDemuxer::EOS_FUZZ); return GetBuffered().Contains(ClampIntervalToEnd(interval)); }
// TODO: USE idx INSTEAD OF size_t size_t getElapsed() { /*! * Returns elapsed time as number of ticks of TimeUnits * Elapsed time can mean 2 different things: * * 1. If TickCounter is running, elapsed time is measured between starTime * and now. * 2. If TickCounter is not running (i.e. it is stopped), elapsed time * is measured between startTime and stopTime. */ // DIFFERENCE BETWEEN THE TWO "TIMEPOINTS" MUST BE CAST TO // A "DURATION" USING THE std::chrono::duration_cast TimeUnit duration; // CASE 1 - TickCounter IS RUNNING, USE CURRENT TIME if (isRunning) { duration = std::chrono::duration_cast <TimeUnit> ( std::chrono::high_resolution_clock::now() - startTime ); } // CASE 2 - NOT RUNNING, USE stopTime else { duration = std::chrono::duration_cast<TimeUnit> (stopTime - startTime); } // CAST TO TICK COUNT return static_cast <size_t> ( duration.count() ); }
TimeUnit MP3TrackDemuxer::FastSeek(TimeUnit aTime) { MP3DEMUXER_LOG("FastSeek(%" PRId64 ") avgFrameLen=%f mNumParsedFrames=%" PRIu64 " mFrameIndex=%" PRId64 " mOffset=%" PRIu64, aTime, AverageFrameLength(), mNumParsedFrames, mFrameIndex, mOffset); if (!aTime.ToMicroseconds()) { // Quick seek to the beginning of the stream. mOffset = mFirstFrameOffset; mFrameIndex = 0; mParser.EndFrameSession(); return TimeUnit(); } if (!mSamplesPerFrame || !mNumParsedFrames) { return TimeUnit::FromMicroseconds(-1); } const int64_t numFrames = aTime.ToSeconds() * mSamplesPerSecond / mSamplesPerFrame; mOffset = mFirstFrameOffset + numFrames * AverageFrameLength(); mFrameIndex = numFrames; MP3DEMUXER_LOG("FastSeek mSamplesPerSecond=%d mSamplesPerFrame=%d " "numFrames=%" PRId64, mSamplesPerSecond, mSamplesPerFrame, numFrames); mParser.EndFrameSession(); return Duration(mFrameIndex); }
TimeIntervals MP3TrackDemuxer::GetBuffered() { AutoPinned<MediaResource> stream(mSource.GetResource()); TimeIntervals buffered; if (Duration() > TimeUnit() && stream->IsDataCachedToEndOfResource(0)) { // Special case completely cached files. This also handles local files. buffered += TimeInterval(TimeUnit(), Duration()); MP3LOGV("buffered = [[%" PRId64 ", %" PRId64 "]]", TimeUnit().ToMicroseconds(), Duration().ToMicroseconds()); return buffered; } MediaByteRangeSet ranges; nsresult rv = stream->GetCachedRanges(ranges); NS_ENSURE_SUCCESS(rv, buffered); for (const auto& range: ranges) { if (range.IsEmpty()) { continue; } TimeUnit start = Duration(FrameIndexFromOffset(range.mStart)); TimeUnit end = Duration(FrameIndexFromOffset(range.mEnd)); MP3LOGV("buffered += [%" PRId64 ", %" PRId64 "]", start.ToMicroseconds(), end.ToMicroseconds()); buffered += TimeInterval(start, end); } return buffered; }
TEST(MP4Demuxer, GetNextKeyframe) { RefPtr<MP4DemuxerBinding> binding = new MP4DemuxerBinding("gizmo-frag.mp4"); binding->RunTestAndWait([binding]() { // Insert a [0,end] buffered range, to simulate Moof's being buffered // via MSE. auto len = binding->resource->GetLength(); binding->resource->MockAddBufferedRange(0, len); // gizmp-frag has two keyframes; one at dts=cts=0, and another at // dts=cts=1000000. Verify we get expected results. TimeUnit time; binding->mVideoTrack = binding->mDemuxer->GetTrackDemuxer(TrackInfo::kVideoTrack, 0); binding->mVideoTrack->Reset(); binding->mVideoTrack->GetNextRandomAccessPoint(&time); EXPECT_EQ(time.ToMicroseconds(), 0); binding->mVideoTrack->GetSamples()->Then( binding->mTaskQueue, __func__, [binding]() { TimeUnit time; binding->mVideoTrack->GetNextRandomAccessPoint(&time); EXPECT_EQ(time.ToMicroseconds(), 1000000); binding->mTaskQueue->BeginShutdown(); }, DO_FAIL); }); }
TimeUnit MP3TrackDemuxer::FastSeek(const TimeUnit& aTime) { MP3LOG("FastSeek(%" PRId64 ") avgFrameLen=%f mNumParsedFrames=%" PRIu64 " mFrameIndex=%" PRId64 " mOffset=%" PRIu64, aTime, AverageFrameLength(), mNumParsedFrames, mFrameIndex, mOffset); const auto& vbr = mParser.VBRInfo(); if (!aTime.ToMicroseconds()) { // Quick seek to the beginning of the stream. mFrameIndex = 0; } else if (vbr.IsTOCPresent()) { // Use TOC for more precise seeking. const float durationFrac = static_cast<float>(aTime.ToMicroseconds()) / Duration().ToMicroseconds(); mFrameIndex = FrameIndexFromOffset(vbr.Offset(durationFrac)); } else if (AverageFrameLength() > 0) { mFrameIndex = FrameIndexFromTime(aTime); } mOffset = OffsetFromFrameIndex(mFrameIndex); if (mOffset > mFirstFrameOffset && StreamLength() > 0) { mOffset = std::min(StreamLength() - 1, mOffset); } mParser.EndFrameSession(); MP3LOG("FastSeek End TOC=%d avgFrameLen=%f mNumParsedFrames=%" PRIu64 " mFrameIndex=%" PRId64 " mFirstFrameOffset=%llu mOffset=%" PRIu64 " SL=%llu NumBytes=%u", vbr.IsTOCPresent(), AverageFrameLength(), mNumParsedFrames, mFrameIndex, mFirstFrameOffset, mOffset, StreamLength(), vbr.NumBytes().valueOr(0)); return Duration(mFrameIndex); }
already_AddRefed<MediaByteBuffer> SourceBuffer::PrepareAppend(const uint8_t* aData, uint32_t aLength, ErrorResult& aRv) { typedef SourceBufferContentManager::EvictDataResult Result; if (!IsAttached() || mUpdating) { aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR); return nullptr; } if (mMediaSource->ReadyState() == MediaSourceReadyState::Ended) { mMediaSource->SetReadyState(MediaSourceReadyState::Open); } // Eviction uses a byte threshold. If the buffer is greater than the // number of bytes then data is evicted. The time range for this // eviction is reported back to the media source. It will then // evict data before that range across all SourceBuffers it knows // about. // TODO: Make the eviction threshold smaller for audio-only streams. // TODO: Drive evictions off memory pressure notifications. // TODO: Consider a global eviction threshold rather than per TrackBuffer. TimeUnit newBufferStartTime; // Attempt to evict the amount of data we are about to add by lowering the // threshold. uint32_t toEvict = (mEvictionThreshold > aLength) ? mEvictionThreshold - aLength : aLength; Result evicted = mContentManager->EvictData(TimeUnit::FromSeconds(mMediaSource->GetDecoder()->GetCurrentTime()), toEvict, &newBufferStartTime); if (evicted == Result::DATA_EVICTED) { MSE_DEBUG("AppendData Evict; current buffered start=%f", GetBufferedStart()); // We notify that we've evicted from the time range 0 through to // the current start point. mMediaSource->NotifyEvicted(0.0, newBufferStartTime.ToSeconds()); } // See if we have enough free space to append our new data. // As we can only evict once we have playable data, we must give a chance // to the DASH player to provide a complete media segment. if (aLength > mEvictionThreshold || evicted == Result::BUFFER_FULL || ((!mIsUsingFormatReader && mContentManager->GetSize() > mEvictionThreshold - aLength) && evicted != Result::CANT_EVICT)) { aRv.Throw(NS_ERROR_DOM_QUOTA_EXCEEDED_ERR); return nullptr; } nsRefPtr<MediaByteBuffer> data = new MediaByteBuffer(); if (!data->AppendElements(aData, aLength, fallible)) { aRv.Throw(NS_ERROR_DOM_QUOTA_EXCEEDED_ERR); return nullptr; } return data.forget(); }
TimeIntervals MP3TrackDemuxer::GetBuffered() { TimeUnit duration = Duration(); if (duration <= TimeUnit()) { return TimeIntervals(); } AutoPinned<MediaResource> stream(mSource.GetResource()); return GetEstimatedBufferedTimeRanges(stream, duration.ToMicroseconds()); }
nsCString DecodedStreamData::GetDebugInfo() { return nsPrintfCString( "DecodedStreamData=%p mPlaying=%d mAudioFramesWritten=%" PRId64 " mNextAudioTime=%" PRId64 " mNextVideoTime=%" PRId64 " mHaveSentFinish=%d " "mHaveSentFinishAudio=%d mHaveSentFinishVideo=%d", this, mPlaying, mAudioFramesWritten, mNextAudioTime.ToMicroseconds(), mNextVideoTime.ToMicroseconds(), mHaveSentFinish, mHaveSentFinishAudio, mHaveSentFinishVideo); }
TimeUnit AudioSink::GetEndTime() const { int64_t written; { MonitorAutoLock mon(mMonitor); written = mWritten; } TimeUnit played = FramesToTimeUnit(written, mOutputRate) + mStartTime; if (!played.IsValid()) { NS_WARNING("Int overflow calculating audio end time"); return TimeUnit::Zero(); } // As we may be resampling, rounding errors may occur. Ensure we never get // past the original end time. return std::min(mLastEndTime, played); }
TimeUnit AudioSink::GetEndTime() const { int64_t written; { MonitorAutoLock mon(mMonitor); written = mWritten; } TimeUnit played = FramesToTimeUnit(written, mOutputRate) + mStartTime; if (!played.IsValid()) { NS_WARNING("Int overflow calculating audio end time"); return TimeUnit::Zero(); } return played; }
nsresult PostOutput(BufferInfo::Param aInfo, MediaFormat::Param aFormat, const TimeUnit& aDuration) override { RefPtr<layers::Image> img = new SurfaceTextureImage(mSurfaceTexture.get(), mConfig.mDisplay, gl::OriginPos::BottomLeft); nsresult rv; int32_t flags; NS_ENSURE_SUCCESS(rv = aInfo->Flags(&flags), rv); bool isSync = !!(flags & MediaCodec::BUFFER_FLAG_SYNC_FRAME); int32_t offset; NS_ENSURE_SUCCESS(rv = aInfo->Offset(&offset), rv); int64_t presentationTimeUs; NS_ENSURE_SUCCESS(rv = aInfo->PresentationTimeUs(&presentationTimeUs), rv); RefPtr<VideoData> v = VideoData::CreateFromImage(mConfig, mImageContainer, offset, presentationTimeUs, aDuration.ToMicroseconds(), img, isSync, presentationTimeUs, gfx::IntRect(0, 0, mConfig.mDisplay.width, mConfig.mDisplay.height)); INVOKE_CALLBACK(Output, v); return NS_OK; }
static void WriteVideoToMediaStream(MediaStream* aStream, layers::Image* aImage, const TimeUnit& aEnd, const TimeUnit& aStart, const mozilla::gfx::IntSize& aIntrinsicSize, const TimeStamp& aTimeStamp, VideoSegment* aOutput, const PrincipalHandle& aPrincipalHandle) { RefPtr<layers::Image> image = aImage; auto end = aStream->MicrosecondsToStreamTimeRoundDown(aEnd.ToMicroseconds()); auto start = aStream->MicrosecondsToStreamTimeRoundDown(aStart.ToMicroseconds()); StreamTime duration = end - start; aOutput->AppendFrame(image.forget(), duration, aIntrinsicSize, aPrincipalHandle, false, aTimeStamp); }
STEPEntity * TimeUnit::Create(STEPWrapper *sw, SDAI_Application_instance *sse) { Factory::OBJECTS::iterator i; if ((i = Factory::FindObject(sse->STEPfile_id)) == Factory::objects.end()) { TimeUnit *object = new TimeUnit(sw,sse->STEPfile_id); Factory::AddObject(object); if (!object->Load(sw, sse)) { std::cerr << CLASSNAME << ":Error loading class in ::Create() method." << std::endl; delete object; return NULL; } return static_cast<STEPEntity *>(object); } else { return (*i).second; } }
inline TimeStamp(TimeUnit unit, double dec) : _unit(unit) { dec = std::max(0.0, dec); dec = std::min(double(std::numeric_limits<uint32_t>::max()), dec); double integral; const double fractional = modf(dec, &integral); _ticks = integral; _subticks = fractional * unit.ppt(); }
void MediaDecoder::DurationChanged(TimeUnit aNewDuration) { MOZ_ASSERT(NS_IsMainThread()); ReentrantMonitorAutoEnter mon(GetReentrantMonitor()); int64_t oldDuration = mDuration; mDuration = aNewDuration.ToMicroseconds(); // Duration has changed so we should recompute playback rate UpdatePlaybackRate(); SetInfinite(mDuration == -1); if (mOwner && oldDuration != mDuration && !IsInfinite()) { DECODER_LOG("Duration changed to %lld", mDuration); mOwner->DispatchAsyncEvent(NS_LITERAL_STRING("durationchange")); } if (CurrentPosition() > aNewDuration.ToMicroseconds()) { Seek(aNewDuration.ToSeconds(), SeekTarget::Accurate); } }
TimeUnit WAVTrackDemuxer::ScanUntil(const TimeUnit& aTime) { if (!aTime.ToMicroseconds()) { return FastSeek(aTime); } if (Duration(mChunkIndex) > aTime) { FastSeek(aTime); } return SeekPosition(); }
nsresult Output(BufferInfo::Param aInfo, void* aBuffer, MediaFormat::Param aFormat, const TimeUnit& aDuration) { // The output on Android is always 16-bit signed nsresult rv; int32_t numChannels; NS_ENSURE_SUCCESS(rv = aFormat->GetInteger(NS_LITERAL_STRING("channel-count"), &numChannels), rv); AudioConfig::ChannelLayout layout(numChannels); if (!layout.IsValid()) { return NS_ERROR_FAILURE; } int32_t sampleRate; NS_ENSURE_SUCCESS(rv = aFormat->GetInteger(NS_LITERAL_STRING("sample-rate"), &sampleRate), rv); int32_t size; NS_ENSURE_SUCCESS(rv = aInfo->Size(&size), rv); int32_t offset; NS_ENSURE_SUCCESS(rv = aInfo->Offset(&offset), rv); #ifdef MOZ_SAMPLE_TYPE_S16 const int32_t numSamples = size / 2; #else #error We only support 16-bit integer PCM #endif const int32_t numFrames = numSamples / numChannels; AlignedAudioBuffer audio(numSamples); if (!audio) { return NS_ERROR_OUT_OF_MEMORY; } const uint8_t* bufferStart = static_cast<uint8_t*>(aBuffer) + offset; PodCopy(audio.get(), reinterpret_cast<const AudioDataValue*>(bufferStart), numSamples); int64_t presentationTimeUs; NS_ENSURE_SUCCESS(rv = aInfo->PresentationTimeUs(&presentationTimeUs), rv); RefPtr<AudioData> data = new AudioData(0, presentationTimeUs, aDuration.ToMicroseconds(), numFrames, Move(audio), numChannels, sampleRate); INVOKE_CALLBACK(Output, data); return NS_OK; }
TimeUnit MP3TrackDemuxer::FastSeek(TimeUnit aTime) { if (!aTime.ToMicroseconds()) { // Quick seek to the beginning of the stream. mOffset = mFirstFrameOffset; mFrameIndex = 0; mParser.EndFrameSession(); return TimeUnit(); } if (!mSamplesPerFrame || !mNumParsedFrames) { return TimeUnit::FromMicroseconds(-1); } const int64_t numFrames = aTime.ToSeconds() * mSamplesPerSecond / mSamplesPerFrame; mOffset = mFirstFrameOffset + numFrames * AverageFrameLength(); mFrameIndex = numFrames; mParser.EndFrameSession(); return Duration(mFrameIndex); }
TimeUnit MP3TrackDemuxer::ScanUntil(TimeUnit aTime) { if (!aTime.ToMicroseconds()) { return FastSeek(aTime); } if (Duration(mFrameIndex) > aTime) { FastSeek(aTime); } MediaByteRange nextRange = FindNextFrame(); while (SkipNextFrame(nextRange) && Duration(mFrameIndex + 1) < aTime) { nextRange = FindNextFrame(); } return Duration(mFrameIndex); }
TimeUnit WAVTrackDemuxer::FastSeek(const TimeUnit& aTime) { if (aTime.ToMicroseconds()) { mChunkIndex = ChunkIndexFromTime(aTime); } else { mChunkIndex = 0; } mOffset = OffsetFromChunkIndex(mChunkIndex); if (mOffset > mFirstChunkOffset && StreamLength() > 0) { mOffset = std::min(StreamLength() - 1, mOffset); } return Duration(mChunkIndex); }
void TimeUnitTest::testAPI() { //================= TimeUnit ================= UErrorCode status = U_ZERO_ERROR; TimeUnit* tmunit = TimeUnit::createInstance(TimeUnit::UTIMEUNIT_YEAR, status); if (!assertSuccess("TimeUnit::createInstance", status)) return; TimeUnit* another = (TimeUnit*)tmunit->clone(); TimeUnit third(*tmunit); TimeUnit fourth = third; assertTrue("orig and clone are equal", (*tmunit == *another)); assertTrue("copied and assigned are equal", (third == fourth)); TimeUnit* tmunit_m = TimeUnit::createInstance(TimeUnit::UTIMEUNIT_MONTH, status); assertTrue("year != month", (*tmunit != *tmunit_m)); TimeUnit::UTimeUnitFields field = tmunit_m->getTimeUnitField(); assertTrue("field of month time unit is month", (field == TimeUnit::UTIMEUNIT_MONTH)); //===== Interoperability with MeasureUnit ====== MeasureUnit **ptrs = new MeasureUnit *[TimeUnit::UTIMEUNIT_FIELD_COUNT]; ptrs[TimeUnit::UTIMEUNIT_YEAR] = MeasureUnit::createYear(status); ptrs[TimeUnit::UTIMEUNIT_MONTH] = MeasureUnit::createMonth(status); ptrs[TimeUnit::UTIMEUNIT_DAY] = MeasureUnit::createDay(status); ptrs[TimeUnit::UTIMEUNIT_WEEK] = MeasureUnit::createWeek(status); ptrs[TimeUnit::UTIMEUNIT_HOUR] = MeasureUnit::createHour(status); ptrs[TimeUnit::UTIMEUNIT_MINUTE] = MeasureUnit::createMinute(status); ptrs[TimeUnit::UTIMEUNIT_SECOND] = MeasureUnit::createSecond(status); if (!assertSuccess("TimeUnit::createInstance", status)) return; for (TimeUnit::UTimeUnitFields j = TimeUnit::UTIMEUNIT_YEAR; j < TimeUnit::UTIMEUNIT_FIELD_COUNT; j = (TimeUnit::UTimeUnitFields)(j+1)) { MeasureUnit *ptr = TimeUnit::createInstance(j, status); if (!assertSuccess("TimeUnit::createInstance", status)) return; // We have to convert *ptr to a MeasureUnit or else == will fail over // differing types (TimeUnit vs. MeasureUnit). assertTrue( "Time unit should be equal to corresponding MeasureUnit", MeasureUnit(*ptr) == *ptrs[j]); delete ptr; } delete tmunit; delete another; delete tmunit_m; for (int i = 0; i < TimeUnit::UTIMEUNIT_FIELD_COUNT; ++i) { delete ptrs[i]; } delete [] ptrs; // //================= TimeUnitAmount ================= Formattable formattable((int32_t)2); TimeUnitAmount tma_long(formattable, TimeUnit::UTIMEUNIT_DAY, status); if (!assertSuccess("TimeUnitAmount(formattable...)", status)) return; formattable.setDouble(2); TimeUnitAmount tma_double(formattable, TimeUnit::UTIMEUNIT_DAY, status); if (!assertSuccess("TimeUnitAmount(formattable...)", status)) return; formattable.setDouble(3); TimeUnitAmount tma_double_3(formattable, TimeUnit::UTIMEUNIT_DAY, status); if (!assertSuccess("TimeUnitAmount(formattable...)", status)) return; TimeUnitAmount tma(2, TimeUnit::UTIMEUNIT_DAY, status); if (!assertSuccess("TimeUnitAmount(number...)", status)) return; TimeUnitAmount tma_h(2, TimeUnit::UTIMEUNIT_HOUR, status); if (!assertSuccess("TimeUnitAmount(number...)", status)) return; TimeUnitAmount second(tma); TimeUnitAmount third_tma = tma; TimeUnitAmount* fourth_tma = (TimeUnitAmount*)tma.clone(); assertTrue("orig and copy are equal", (second == tma)); assertTrue("clone and assigned are equal", (third_tma == *fourth_tma)); assertTrue("different if number diff", (tma_double != tma_double_3)); assertTrue("different if number type diff", (tma_double != tma_long)); assertTrue("different if time unit diff", (tma != tma_h)); assertTrue("same even different constructor", (tma_double == tma)); assertTrue("getTimeUnitField", (tma.getTimeUnitField() == TimeUnit::UTIMEUNIT_DAY)); delete fourth_tma; // //================= TimeUnitFormat ================= // TimeUnitFormat* tmf_en = new TimeUnitFormat(Locale("en"), status); if (!assertSuccess("TimeUnitFormat(en...)", status, TRUE)) return; TimeUnitFormat tmf_fr(Locale("fr"), status); if (!assertSuccess("TimeUnitFormat(fr...)", status)) return; assertTrue("TimeUnitFormat: en and fr diff", (*tmf_en != tmf_fr)); TimeUnitFormat tmf_assign = *tmf_en; assertTrue("TimeUnitFormat: orig and assign are equal", (*tmf_en == tmf_assign)); TimeUnitFormat tmf_copy(tmf_fr); assertTrue("TimeUnitFormat: orig and copy are equal", (tmf_fr == tmf_copy)); TimeUnitFormat* tmf_clone = (TimeUnitFormat*)tmf_en->clone(); assertTrue("TimeUnitFormat: orig and clone are equal", (*tmf_en == *tmf_clone)); delete tmf_clone; tmf_en->setLocale(Locale("fr"), status); if (!assertSuccess("setLocale(fr...)", status)) return; NumberFormat* numberFmt = NumberFormat::createInstance( Locale("fr"), status); if (!assertSuccess("NumberFormat::createInstance()", status)) return; tmf_en->setNumberFormat(*numberFmt, status); if (!assertSuccess("setNumberFormat(en...)", status)) return; assertTrue("TimeUnitFormat: setLocale", (*tmf_en == tmf_fr)); delete tmf_en; TimeUnitFormat* en_long = new TimeUnitFormat(Locale("en"), UTMUTFMT_FULL_STYLE, status); if (!assertSuccess("TimeUnitFormat(en...)", status)) return; delete en_long; TimeUnitFormat* en_short = new TimeUnitFormat(Locale("en"), UTMUTFMT_ABBREVIATED_STYLE, status); if (!assertSuccess("TimeUnitFormat(en...)", status)) return; delete en_short; TimeUnitFormat* format = new TimeUnitFormat(status); format->setLocale(Locale("zh"), status); format->setNumberFormat(*numberFmt, status); if (!assertSuccess("TimeUnitFormat(en...)", status)) return; delete numberFmt; delete format; }
// Format TimeUnit as number of frames at given rate. CheckedInt64 TimeUnitToFrames(const TimeUnit& aTime, uint32_t aRate) { return UsecsToFrames(aTime.ToMicroseconds(), aRate); }
// Format TimeUnit as number of frames at given rate. CheckedInt64 TimeUnitToFrames(const TimeUnit& aTime, uint32_t aRate) { return aTime.IsValid() ? UsecsToFrames(aTime.ToMicroseconds(), aRate) : CheckedInt64(INT64_MAX) + 1; }
void TimeUnitTest::testAPI() { //================= TimeUnit ================= UErrorCode status = U_ZERO_ERROR; TimeUnit* tmunit = TimeUnit::createInstance(TimeUnit::UTIMEUNIT_YEAR, status); if (!assertSuccess("TimeUnit::createInstance", status)) return; TimeUnit* another = (TimeUnit*)tmunit->clone(); TimeUnit third(*tmunit); TimeUnit fourth = third; assertTrue("orig and clone are equal", (*tmunit == *another)); assertTrue("copied and assigned are equal", (third == fourth)); TimeUnit* tmunit_m = TimeUnit::createInstance(TimeUnit::UTIMEUNIT_MONTH, status); assertTrue("year != month", (*tmunit != *tmunit_m)); TimeUnit::UTimeUnitFields field = tmunit_m->getTimeUnitField(); assertTrue("field of month time unit is month", (field == TimeUnit::UTIMEUNIT_MONTH)); delete tmunit; delete another; delete tmunit_m; // //================= TimeUnitAmount ================= Formattable formattable((int32_t)2); TimeUnitAmount tma_long(formattable, TimeUnit::UTIMEUNIT_DAY, status); if (!assertSuccess("TimeUnitAmount(formattable...)", status)) return; formattable.setDouble(2); TimeUnitAmount tma_double(formattable, TimeUnit::UTIMEUNIT_DAY, status); if (!assertSuccess("TimeUnitAmount(formattable...)", status)) return; formattable.setDouble(3); TimeUnitAmount tma_double_3(formattable, TimeUnit::UTIMEUNIT_DAY, status); if (!assertSuccess("TimeUnitAmount(formattable...)", status)) return; TimeUnitAmount tma(2, TimeUnit::UTIMEUNIT_DAY, status); if (!assertSuccess("TimeUnitAmount(number...)", status)) return; TimeUnitAmount tma_h(2, TimeUnit::UTIMEUNIT_HOUR, status); if (!assertSuccess("TimeUnitAmount(number...)", status)) return; TimeUnitAmount second(tma); TimeUnitAmount third_tma = tma; TimeUnitAmount* fourth_tma = (TimeUnitAmount*)tma.clone(); assertTrue("orig and copy are equal", (second == tma)); assertTrue("clone and assigned are equal", (third_tma == *fourth_tma)); assertTrue("different if number diff", (tma_double != tma_double_3)); assertTrue("different if number type diff", (tma_double != tma_long)); assertTrue("different if time unit diff", (tma != tma_h)); assertTrue("same even different constructor", (tma_double == tma)); assertTrue("getTimeUnitField", (tma.getTimeUnitField() == TimeUnit::UTIMEUNIT_DAY)); delete fourth_tma; // //================= TimeUnitFormat ================= // TimeUnitFormat* tmf_en = new TimeUnitFormat(Locale("en"), status); if (!assertSuccess("TimeUnitFormat(en...)", status, TRUE)) return; TimeUnitFormat tmf_fr(Locale("fr"), status); if (!assertSuccess("TimeUnitFormat(fr...)", status)) return; assertTrue("TimeUnitFormat: en and fr diff", (*tmf_en != tmf_fr)); TimeUnitFormat tmf_assign = *tmf_en; assertTrue("TimeUnitFormat: orig and assign are equal", (*tmf_en == tmf_assign)); TimeUnitFormat tmf_copy(tmf_fr); assertTrue("TimeUnitFormat: orig and copy are equal", (tmf_fr == tmf_copy)); TimeUnitFormat* tmf_clone = (TimeUnitFormat*)tmf_en->clone(); assertTrue("TimeUnitFormat: orig and clone are equal", (*tmf_en == *tmf_clone)); delete tmf_clone; tmf_en->setLocale(Locale("fr"), status); if (!assertSuccess("setLocale(fr...)", status)) return; NumberFormat* numberFmt = NumberFormat::createInstance( Locale("fr"), status); if (!assertSuccess("NumberFormat::createInstance()", status)) return; tmf_en->setNumberFormat(*numberFmt, status); if (!assertSuccess("setNumberFormat(en...)", status)) return; assertTrue("TimeUnitFormat: setLocale", (*tmf_en == tmf_fr)); delete tmf_en; TimeUnitFormat* en_long = new TimeUnitFormat(Locale("en"), UTMUTFMT_FULL_STYLE, status); if (!assertSuccess("TimeUnitFormat(en...)", status)) return; delete en_long; TimeUnitFormat* en_short = new TimeUnitFormat(Locale("en"), UTMUTFMT_ABBREVIATED_STYLE, status); if (!assertSuccess("TimeUnitFormat(en...)", status)) return; delete en_short; TimeUnitFormat* format = new TimeUnitFormat(status); format->setLocale(Locale("zh"), status); format->setNumberFormat(*numberFmt, status); if (!assertSuccess("TimeUnitFormat(en...)", status)) return; delete numberFmt; delete format; }