• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2019 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 "FrameReassembler"
19 
20 #include <log/log.h>
21 
22 #include <media/stagefright/foundation/AMessage.h>
23 
24 #include "FrameReassembler.h"
25 
26 namespace android {
27 
28 static constexpr uint64_t kToleranceUs = 1000;  // 1ms
29 
FrameReassembler()30 FrameReassembler::FrameReassembler()
31     : mUsage{0, 0},
32       mSampleRate(0u),
33       mChannelCount(0u),
34       mEncoding(C2Config::PCM_16),
35       mCurrentOrdinal({0, 0, 0}) {
36 }
37 
init(const std::shared_ptr<C2BlockPool> & pool,C2MemoryUsage usage,uint32_t frameSize,uint32_t sampleRate,uint32_t channelCount,C2Config::pcm_encoding_t encoding)38 void FrameReassembler::init(
39         const std::shared_ptr<C2BlockPool> &pool,
40         C2MemoryUsage usage,
41         uint32_t frameSize,
42         uint32_t sampleRate,
43         uint32_t channelCount,
44         C2Config::pcm_encoding_t encoding) {
45     mBlockPool = pool;
46     mUsage = usage;
47     mFrameSize = frameSize;
48     mSampleRate = sampleRate;
49     mChannelCount = channelCount;
50     mEncoding = encoding;
51 }
52 
updateFrameSize(uint32_t frameSize)53 void FrameReassembler::updateFrameSize(uint32_t frameSize) {
54     finishCurrentBlock(&mPendingWork);
55     mFrameSize = frameSize;
56 }
57 
updateSampleRate(uint32_t sampleRate)58 void FrameReassembler::updateSampleRate(uint32_t sampleRate) {
59     finishCurrentBlock(&mPendingWork);
60     mSampleRate = sampleRate;
61 }
62 
updateChannelCount(uint32_t channelCount)63 void FrameReassembler::updateChannelCount(uint32_t channelCount) {
64     finishCurrentBlock(&mPendingWork);
65     mChannelCount = channelCount;
66 }
67 
updatePcmEncoding(C2Config::pcm_encoding_t encoding)68 void FrameReassembler::updatePcmEncoding(C2Config::pcm_encoding_t encoding) {
69     finishCurrentBlock(&mPendingWork);
70     mEncoding = encoding;
71 }
72 
reset()73 void FrameReassembler::reset() {
74     flush();
75     mCurrentOrdinal = {0, 0, 0};
76     mBlockPool.reset();
77     mFrameSize.reset();
78     mSampleRate = 0u;
79     mChannelCount = 0u;
80     mEncoding = C2Config::PCM_16;
81 }
82 
operator bool() const83 FrameReassembler::operator bool() const {
84     return mFrameSize.has_value();
85 }
86 
process(const sp<MediaCodecBuffer> & buffer,std::list<std::unique_ptr<C2Work>> * items)87 c2_status_t FrameReassembler::process(
88         const sp<MediaCodecBuffer> &buffer,
89         std::list<std::unique_ptr<C2Work>> *items) {
90     int64_t timeUs;
91     if (buffer->size() == 0u
92             || !buffer->meta()->findInt64("timeUs", &timeUs)) {
93         return C2_BAD_VALUE;
94     }
95 
96     items->splice(items->end(), mPendingWork);
97 
98     // Fill mCurrentBlock
99     if (mCurrentBlock) {
100         // First check the timestamp
101         c2_cntr64_t endTimestampUs = mCurrentOrdinal.timestamp;
102         endTimestampUs += bytesToSamples(mWriteView->size()) * 1000000 / mSampleRate;
103         if (timeUs < endTimestampUs.peek()) {
104             uint64_t diffUs = (endTimestampUs - timeUs).peeku();
105             if (diffUs > kToleranceUs) {
106                 // The timestamp is going back in time in large amount.
107                 // TODO: b/145702136
108                 ALOGW("timestamp going back in time! from %lld to %lld",
109                         endTimestampUs.peekll(), (long long)timeUs);
110             }
111         } else {  // timeUs >= endTimestampUs.peek()
112             uint64_t diffUs = (timeUs - endTimestampUs).peeku();
113             if (diffUs > kToleranceUs) {
114                 // The timestamp is going forward; add silence as necessary.
115                 size_t gapSamples = usToSamples(diffUs);
116                 size_t remainingSamples =
117                     (mWriteView->capacity() - mWriteView->size())
118                     / mChannelCount / bytesPerSample();
119                 if (gapSamples < remainingSamples) {
120                     size_t gapBytes = gapSamples * mChannelCount * bytesPerSample();
121                     memset(mWriteView->base() + mWriteView->size(), 0u, gapBytes);
122                     mWriteView->setSize(mWriteView->size() + gapBytes);
123                 } else {
124                     finishCurrentBlock(items);
125                 }
126             }
127         }
128     }
129 
130     if (mCurrentBlock) {
131         // Append the data at the end of the current block
132         size_t copySize = std::min(
133                 buffer->size(),
134                 size_t(mWriteView->capacity() - mWriteView->size()));
135         memcpy(mWriteView->base() + mWriteView->size(), buffer->data(), copySize);
136         buffer->setRange(buffer->offset() + copySize, buffer->size() - copySize);
137         mWriteView->setSize(mWriteView->size() + copySize);
138         if (mWriteView->size() == mWriteView->capacity()) {
139             finishCurrentBlock(items);
140         }
141         timeUs += bytesToSamples(copySize) * 1000000 / mSampleRate;
142     }
143 
144     if (buffer->size() > 0) {
145         mCurrentOrdinal.timestamp = timeUs;
146         mCurrentOrdinal.customOrdinal = timeUs;
147     }
148 
149     size_t frameSizeBytes = mFrameSize.value() * mChannelCount * bytesPerSample();
150     while (buffer->size() > 0) {
151         LOG_ALWAYS_FATAL_IF(
152                 mCurrentBlock,
153                 "There's remaining data but the pending block is not filled & finished");
154         std::unique_ptr<C2Work> work(new C2Work);
155         c2_status_t err = mBlockPool->fetchLinearBlock(frameSizeBytes, mUsage, &mCurrentBlock);
156         if (err != C2_OK) {
157             return err;
158         }
159         size_t copySize = std::min(buffer->size(), frameSizeBytes);
160         mWriteView = mCurrentBlock->map().get();
161         if (mWriteView->error() != C2_OK) {
162             return mWriteView->error();
163         }
164         ALOGV("buffer={offset=%zu size=%zu} copySize=%zu",
165                 buffer->offset(), buffer->size(), copySize);
166         memcpy(mWriteView->base(), buffer->data(), copySize);
167         mWriteView->setOffset(0u);
168         mWriteView->setSize(copySize);
169         buffer->setRange(buffer->offset() + copySize, buffer->size() - copySize);
170         if (copySize == frameSizeBytes) {
171             finishCurrentBlock(items);
172         }
173     }
174 
175     int32_t eos = 0;
176     if (buffer->meta()->findInt32("eos", &eos) && eos) {
177         finishCurrentBlock(items);
178     }
179 
180     return C2_OK;
181 }
182 
flush()183 void FrameReassembler::flush() {
184     mPendingWork.clear();
185     mWriteView.reset();
186     mCurrentBlock.reset();
187 }
188 
bytesToSamples(size_t numBytes) const189 uint64_t FrameReassembler::bytesToSamples(size_t numBytes) const {
190     return numBytes / mChannelCount / bytesPerSample();
191 }
192 
usToSamples(uint64_t us) const193 size_t FrameReassembler::usToSamples(uint64_t us) const {
194     return (us * mChannelCount * mSampleRate / 1000000);
195 }
196 
bytesPerSample() const197 uint32_t FrameReassembler::bytesPerSample() const {
198     return (mEncoding == C2Config::PCM_8) ? 1
199          : (mEncoding == C2Config::PCM_16) ? 2
200          : (mEncoding == C2Config::PCM_FLOAT) ? 4 : 0;
201 }
202 
finishCurrentBlock(std::list<std::unique_ptr<C2Work>> * items)203 void FrameReassembler::finishCurrentBlock(std::list<std::unique_ptr<C2Work>> *items) {
204     if (!mCurrentBlock) {
205         // No-op
206         return;
207     }
208     if (mWriteView->size() < mWriteView->capacity()) {
209         memset(mWriteView->base() + mWriteView->size(), 0u,
210                 mWriteView->capacity() - mWriteView->size());
211         mWriteView->setSize(mWriteView->capacity());
212     }
213     std::unique_ptr<C2Work> work{std::make_unique<C2Work>()};
214     work->input.ordinal = mCurrentOrdinal;
215     work->input.buffers.push_back(C2Buffer::CreateLinearBuffer(
216             mCurrentBlock->share(0, mCurrentBlock->capacity(), C2Fence())));
217     work->worklets.clear();
218     work->worklets.emplace_back(new C2Worklet);
219     items->push_back(std::move(work));
220 
221     ++mCurrentOrdinal.frameIndex;
222     mCurrentOrdinal.timestamp += mFrameSize.value() * 1000000 / mSampleRate;
223     mCurrentOrdinal.customOrdinal = mCurrentOrdinal.timestamp;
224     mCurrentBlock.reset();
225     mWriteView.reset();
226 }
227 
228 }  // namespace android
229