1 /*
2  * Copyright (C) 2015 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 //#define LOG_NDEBUG 0
18 #define LOG_TAG "MediaClock"
19 #include <utils/Log.h>
20 
21 #include <media/stagefright/MediaClock.h>
22 
23 #include <media/stagefright/foundation/ADebug.h>
24 #include <media/stagefright/foundation/ALooper.h>
25 
26 namespace android {
27 
MediaClock()28 MediaClock::MediaClock()
29     : mAnchorTimeMediaUs(-1),
30       mAnchorTimeRealUs(-1),
31       mMaxTimeMediaUs(INT64_MAX),
32       mStartingTimeMediaUs(-1),
33       mPlaybackRate(1.0) {
34 }
35 
~MediaClock()36 MediaClock::~MediaClock() {
37 }
38 
setStartingTimeMedia(int64_t startingTimeMediaUs)39 void MediaClock::setStartingTimeMedia(int64_t startingTimeMediaUs) {
40     Mutex::Autolock autoLock(mLock);
41     mStartingTimeMediaUs = startingTimeMediaUs;
42 }
43 
clearAnchor()44 void MediaClock::clearAnchor() {
45     Mutex::Autolock autoLock(mLock);
46     mAnchorTimeMediaUs = -1;
47     mAnchorTimeRealUs = -1;
48 }
49 
updateAnchor(int64_t anchorTimeMediaUs,int64_t anchorTimeRealUs,int64_t maxTimeMediaUs)50 void MediaClock::updateAnchor(
51         int64_t anchorTimeMediaUs,
52         int64_t anchorTimeRealUs,
53         int64_t maxTimeMediaUs) {
54     if (anchorTimeMediaUs < 0 || anchorTimeRealUs < 0) {
55         ALOGW("reject anchor time since it is negative.");
56         return;
57     }
58 
59     Mutex::Autolock autoLock(mLock);
60     int64_t nowUs = ALooper::GetNowUs();
61     int64_t nowMediaUs =
62         anchorTimeMediaUs + (nowUs - anchorTimeRealUs) * (double)mPlaybackRate;
63     if (nowMediaUs < 0) {
64         ALOGW("reject anchor time since it leads to negative media time.");
65         return;
66     }
67     mAnchorTimeRealUs = nowUs;
68     mAnchorTimeMediaUs = nowMediaUs;
69     mMaxTimeMediaUs = maxTimeMediaUs;
70 }
71 
updateMaxTimeMedia(int64_t maxTimeMediaUs)72 void MediaClock::updateMaxTimeMedia(int64_t maxTimeMediaUs) {
73     Mutex::Autolock autoLock(mLock);
74     mMaxTimeMediaUs = maxTimeMediaUs;
75 }
76 
setPlaybackRate(float rate)77 void MediaClock::setPlaybackRate(float rate) {
78     CHECK_GE(rate, 0.0);
79     Mutex::Autolock autoLock(mLock);
80     if (mAnchorTimeRealUs == -1) {
81         mPlaybackRate = rate;
82         return;
83     }
84 
85     int64_t nowUs = ALooper::GetNowUs();
86     mAnchorTimeMediaUs += (nowUs - mAnchorTimeRealUs) * (double)mPlaybackRate;
87     if (mAnchorTimeMediaUs < 0) {
88         ALOGW("setRate: anchor time should not be negative, set to 0.");
89         mAnchorTimeMediaUs = 0;
90     }
91     mAnchorTimeRealUs = nowUs;
92     mPlaybackRate = rate;
93 }
94 
getPlaybackRate() const95 float MediaClock::getPlaybackRate() const {
96     Mutex::Autolock autoLock(mLock);
97     return mPlaybackRate;
98 }
99 
getMediaTime(int64_t realUs,int64_t * outMediaUs,bool allowPastMaxTime) const100 status_t MediaClock::getMediaTime(
101         int64_t realUs, int64_t *outMediaUs, bool allowPastMaxTime) const {
102     if (outMediaUs == NULL) {
103         return BAD_VALUE;
104     }
105 
106     Mutex::Autolock autoLock(mLock);
107     return getMediaTime_l(realUs, outMediaUs, allowPastMaxTime);
108 }
109 
getMediaTime_l(int64_t realUs,int64_t * outMediaUs,bool allowPastMaxTime) const110 status_t MediaClock::getMediaTime_l(
111         int64_t realUs, int64_t *outMediaUs, bool allowPastMaxTime) const {
112     if (mAnchorTimeRealUs == -1) {
113         return NO_INIT;
114     }
115 
116     int64_t mediaUs = mAnchorTimeMediaUs
117             + (realUs - mAnchorTimeRealUs) * (double)mPlaybackRate;
118     if (mediaUs > mMaxTimeMediaUs && !allowPastMaxTime) {
119         mediaUs = mMaxTimeMediaUs;
120     }
121     if (mediaUs < mStartingTimeMediaUs) {
122         mediaUs = mStartingTimeMediaUs;
123     }
124     if (mediaUs < 0) {
125         mediaUs = 0;
126     }
127     *outMediaUs = mediaUs;
128     return OK;
129 }
130 
getRealTimeFor(int64_t targetMediaUs,int64_t * outRealUs) const131 status_t MediaClock::getRealTimeFor(
132         int64_t targetMediaUs, int64_t *outRealUs) const {
133     if (outRealUs == NULL) {
134         return BAD_VALUE;
135     }
136 
137     Mutex::Autolock autoLock(mLock);
138     if (mPlaybackRate == 0.0) {
139         return NO_INIT;
140     }
141 
142     int64_t nowUs = ALooper::GetNowUs();
143     int64_t nowMediaUs;
144     status_t status =
145             getMediaTime_l(nowUs, &nowMediaUs, true /* allowPastMaxTime */);
146     if (status != OK) {
147         return status;
148     }
149     *outRealUs = (targetMediaUs - nowMediaUs) / (double)mPlaybackRate + nowUs;
150     return OK;
151 }
152 
153 }  // namespace android
154