blob: f8e6937ee610a5757a5edc9f803c38e4cae0ead9 [file] [log] [blame]
Wonsik Kime1104ca2020-11-24 15:01:33 -08001/*
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
26namespace android {
27
28static constexpr uint64_t kToleranceUs = 1000; // 1ms
29
30FrameReassembler::FrameReassembler()
31 : mUsage{0, 0},
32 mSampleRate(0u),
33 mChannelCount(0u),
34 mEncoding(C2Config::PCM_16),
35 mCurrentOrdinal({0, 0, 0}) {
36}
37
38void 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
53void FrameReassembler::updateFrameSize(uint32_t frameSize) {
54 finishCurrentBlock(&mPendingWork);
55 mFrameSize = frameSize;
56}
57
58void FrameReassembler::updateSampleRate(uint32_t sampleRate) {
59 finishCurrentBlock(&mPendingWork);
60 mSampleRate = sampleRate;
61}
62
63void FrameReassembler::updateChannelCount(uint32_t channelCount) {
64 finishCurrentBlock(&mPendingWork);
65 mChannelCount = channelCount;
66}
67
68void FrameReassembler::updatePcmEncoding(C2Config::pcm_encoding_t encoding) {
69 finishCurrentBlock(&mPendingWork);
70 mEncoding = encoding;
71}
72
73void 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
83FrameReassembler::operator bool() const {
84 return mFrameSize.has_value();
85}
86
87c2_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 }
147
148 size_t frameSizeBytes = mFrameSize.value() * mChannelCount * bytesPerSample();
149 while (buffer->size() > 0) {
150 LOG_ALWAYS_FATAL_IF(
151 mCurrentBlock,
152 "There's remaining data but the pending block is not filled & finished");
153 std::unique_ptr<C2Work> work(new C2Work);
154 c2_status_t err = mBlockPool->fetchLinearBlock(frameSizeBytes, mUsage, &mCurrentBlock);
155 if (err != C2_OK) {
156 return err;
157 }
158 size_t copySize = std::min(buffer->size(), frameSizeBytes);
159 mWriteView = mCurrentBlock->map().get();
160 if (mWriteView->error() != C2_OK) {
161 return mWriteView->error();
162 }
163 ALOGV("buffer={offset=%zu size=%zu) copySize=%zu",
164 buffer->offset(), buffer->size(), copySize);
165 memcpy(mWriteView->base(), buffer->data(), copySize);
166 mWriteView->setOffset(0u);
167 mWriteView->setSize(copySize);
168 buffer->setRange(buffer->offset() + copySize, buffer->size() - copySize);
169 if (copySize == frameSizeBytes) {
170 finishCurrentBlock(items);
171 }
172 }
173
174 int32_t eos = 0;
175 if (buffer->meta()->findInt32("eos", &eos) && eos) {
176 finishCurrentBlock(items);
177 }
178
179 return C2_OK;
180}
181
182void FrameReassembler::flush() {
183 mPendingWork.clear();
184 mWriteView.reset();
185 mCurrentBlock.reset();
186}
187
188uint64_t FrameReassembler::bytesToSamples(size_t numBytes) const {
189 return numBytes / mChannelCount / bytesPerSample();
190}
191
192size_t FrameReassembler::usToSamples(uint64_t us) const {
193 return (us * mChannelCount * mSampleRate / 1000000);
194}
195
196uint32_t FrameReassembler::bytesPerSample() const {
197 return (mEncoding == C2Config::PCM_8) ? 1
198 : (mEncoding == C2Config::PCM_16) ? 2
199 : (mEncoding == C2Config::PCM_FLOAT) ? 4 : 0;
200}
201
202void FrameReassembler::finishCurrentBlock(std::list<std::unique_ptr<C2Work>> *items) {
203 if (!mCurrentBlock) {
204 // No-op
205 return;
206 }
207 if (mWriteView->size() < mWriteView->capacity()) {
208 memset(mWriteView->base() + mWriteView->size(), 0u,
209 mWriteView->capacity() - mWriteView->size());
210 mWriteView->setSize(mWriteView->capacity());
211 }
212 std::unique_ptr<C2Work> work{std::make_unique<C2Work>()};
213 work->input.ordinal = mCurrentOrdinal;
214 work->input.buffers.push_back(C2Buffer::CreateLinearBuffer(
215 mCurrentBlock->share(0, mCurrentBlock->capacity(), C2Fence())));
216 work->worklets.clear();
217 work->worklets.emplace_back(new C2Worklet);
218 items->push_back(std::move(work));
219
220 ++mCurrentOrdinal.frameIndex;
221 mCurrentOrdinal.timestamp += mFrameSize.value() * 1000000 / mSampleRate;
222 mCurrentBlock.reset();
223 mWriteView.reset();
224}
225
226} // namespace android