blob: bf4c77e785b13612609eb6801ca470db0b0c3cec [file] [log] [blame]
Amy Zhangbb94eeb2020-07-09 22:48:04 -07001/*
2 * Copyright 2020 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_TAG "android.hardware.tv.tuner@1.1-Dvr"
18
19#include "Dvr.h"
20#include <utils/Log.h>
21
22namespace android {
23namespace hardware {
24namespace tv {
25namespace tuner {
26namespace V1_0 {
27namespace implementation {
28
29#define WAIT_TIMEOUT 3000000000
30
31Dvr::Dvr() {}
32
33Dvr::Dvr(DvrType type, uint32_t bufferSize, const sp<IDvrCallback>& cb, sp<Demux> demux) {
34 mType = type;
35 mBufferSize = bufferSize;
36 mCallback = cb;
37 mDemux = demux;
38}
39
40Dvr::~Dvr() {}
41
42Return<void> Dvr::getQueueDesc(getQueueDesc_cb _hidl_cb) {
43 ALOGV("%s", __FUNCTION__);
44
45 _hidl_cb(Result::SUCCESS, *mDvrMQ->getDesc());
46 return Void();
47}
48
49Return<Result> Dvr::configure(const DvrSettings& settings) {
50 ALOGV("%s", __FUNCTION__);
51
52 mDvrSettings = settings;
53 mDvrConfigured = true;
54
55 return Result::SUCCESS;
56}
57
58Return<Result> Dvr::attachFilter(const sp<V1_0::IFilter>& filter) {
59 ALOGV("%s", __FUNCTION__);
60
61 uint64_t filterId;
62 Result status;
63
64 sp<V1_1::IFilter> filter_v1_1 = V1_1::IFilter::castFrom(filter);
65 if (filter_v1_1 != NULL) {
66 filter_v1_1->getId64Bit([&](Result result, uint64_t id) {
67 filterId = id;
68 status = result;
69 });
70 } else {
71 filter->getId([&](Result result, uint32_t id) {
72 filterId = id;
73 status = result;
74 });
75 }
76
77 if (status != Result::SUCCESS) {
78 return status;
79 }
80
81 // TODO check if the attached filter is a record filter
82 if (!mDemux->attachRecordFilter(filterId)) {
83 return Result::INVALID_ARGUMENT;
84 }
85
86 return Result::SUCCESS;
87}
88
89Return<Result> Dvr::detachFilter(const sp<V1_0::IFilter>& filter) {
90 ALOGV("%s", __FUNCTION__);
91
92 uint64_t filterId;
93 Result status;
94
95 sp<V1_1::IFilter> filter_v1_1 = V1_1::IFilter::castFrom(filter);
96 if (filter_v1_1 != NULL) {
97 filter_v1_1->getId64Bit([&](Result result, uint64_t id) {
98 filterId = id;
99 status = result;
100 });
101 } else {
102 filter->getId([&](Result result, uint32_t id) {
103 filterId = id;
104 status = result;
105 });
106 }
107
108 if (status != Result::SUCCESS) {
109 return status;
110 }
111
112 if (!mDemux->detachRecordFilter(filterId)) {
113 return Result::INVALID_ARGUMENT;
114 }
115
116 return Result::SUCCESS;
117}
118
119Return<Result> Dvr::start() {
120 ALOGV("%s", __FUNCTION__);
121
122 if (!mCallback) {
123 return Result::NOT_INITIALIZED;
124 }
125
126 if (!mDvrConfigured) {
127 return Result::INVALID_STATE;
128 }
129
130 if (mType == DvrType::PLAYBACK) {
131 pthread_create(&mDvrThread, NULL, __threadLoopPlayback, this);
132 pthread_setname_np(mDvrThread, "playback_waiting_loop");
133 } else if (mType == DvrType::RECORD) {
134 mRecordStatus = RecordStatus::DATA_READY;
135 mDemux->setIsRecording(mType == DvrType::RECORD);
136 }
137
138 // TODO start another thread to send filter status callback to the framework
139
140 return Result::SUCCESS;
141}
142
143Return<Result> Dvr::stop() {
144 ALOGV("%s", __FUNCTION__);
145
146 mDvrThreadRunning = false;
147
148 lock_guard<mutex> lock(mDvrThreadLock);
149
150 mIsRecordStarted = false;
151 mDemux->setIsRecording(false);
152
153 return Result::SUCCESS;
154}
155
156Return<Result> Dvr::flush() {
157 ALOGV("%s", __FUNCTION__);
158
159 mRecordStatus = RecordStatus::DATA_READY;
160
161 return Result::SUCCESS;
162}
163
164Return<Result> Dvr::close() {
165 ALOGV("%s", __FUNCTION__);
166
167 return Result::SUCCESS;
168}
169
170bool Dvr::createDvrMQ() {
171 ALOGV("%s", __FUNCTION__);
172
173 // Create a synchronized FMQ that supports blocking read/write
174 unique_ptr<DvrMQ> tmpDvrMQ = unique_ptr<DvrMQ>(new (nothrow) DvrMQ(mBufferSize, true));
175 if (!tmpDvrMQ->isValid()) {
176 ALOGW("[Dvr] Failed to create FMQ of DVR");
177 return false;
178 }
179
180 mDvrMQ = move(tmpDvrMQ);
181
182 if (EventFlag::createEventFlag(mDvrMQ->getEventFlagWord(), &mDvrEventFlag) != OK) {
183 return false;
184 }
185
186 return true;
187}
188
189EventFlag* Dvr::getDvrEventFlag() {
190 return mDvrEventFlag;
191}
192
193void* Dvr::__threadLoopPlayback(void* user) {
194 Dvr* const self = static_cast<Dvr*>(user);
195 self->playbackThreadLoop();
196 return 0;
197}
198
199void Dvr::playbackThreadLoop() {
200 ALOGD("[Dvr] playback threadLoop start.");
201 lock_guard<mutex> lock(mDvrThreadLock);
202 mDvrThreadRunning = true;
203
204 while (mDvrThreadRunning) {
205 uint32_t efState = 0;
206 status_t status =
207 mDvrEventFlag->wait(static_cast<uint32_t>(DemuxQueueNotifyBits::DATA_READY),
208 &efState, WAIT_TIMEOUT, true /* retry on spurious wake */);
209 if (status != OK) {
210 ALOGD("[Dvr] wait for data ready on the playback FMQ");
211 continue;
212 }
213
214 if (mDvrSettings.playback().dataFormat == DataFormat::ES) {
215 if (!processEsDataOnPlayback(false /*isVirtualFrontend*/, false /*isRecording*/)) {
216 ALOGE("[Dvr] playback es data failed to be filtered. Ending thread");
217 break;
218 }
219 maySendPlaybackStatusCallback();
Amy Zhang68afca62020-07-20 18:28:58 -0700220 continue;
Amy Zhangbb94eeb2020-07-09 22:48:04 -0700221 }
222 // Our current implementation filter the data and write it into the filter FMQ immediately
223 // after the DATA_READY from the VTS/framework
Amy Zhang68afca62020-07-20 18:28:58 -0700224 // This is for the non-ES data source, real playback use case handling.
Amy Zhangbb94eeb2020-07-09 22:48:04 -0700225 if (!readPlaybackFMQ(false /*isVirtualFrontend*/, false /*isRecording*/) ||
226 !startFilterDispatcher(false /*isVirtualFrontend*/, false /*isRecording*/)) {
227 ALOGE("[Dvr] playback data failed to be filtered. Ending thread");
228 break;
229 }
230
231 maySendPlaybackStatusCallback();
232 }
233
234 mDvrThreadRunning = false;
235 ALOGD("[Dvr] playback thread ended.");
236}
237
238void Dvr::maySendPlaybackStatusCallback() {
239 lock_guard<mutex> lock(mPlaybackStatusLock);
240 int availableToRead = mDvrMQ->availableToRead();
241 int availableToWrite = mDvrMQ->availableToWrite();
242
243 PlaybackStatus newStatus = checkPlaybackStatusChange(availableToWrite, availableToRead,
244 mDvrSettings.playback().highThreshold,
245 mDvrSettings.playback().lowThreshold);
246 if (mPlaybackStatus != newStatus) {
247 mCallback->onPlaybackStatus(newStatus);
248 mPlaybackStatus = newStatus;
249 }
250}
251
252PlaybackStatus Dvr::checkPlaybackStatusChange(uint32_t availableToWrite, uint32_t availableToRead,
253 uint32_t highThreshold, uint32_t lowThreshold) {
254 if (availableToWrite == 0) {
255 return PlaybackStatus::SPACE_FULL;
256 } else if (availableToRead > highThreshold) {
257 return PlaybackStatus::SPACE_ALMOST_FULL;
258 } else if (availableToRead < lowThreshold) {
259 return PlaybackStatus::SPACE_ALMOST_EMPTY;
260 } else if (availableToRead == 0) {
261 return PlaybackStatus::SPACE_EMPTY;
262 }
263 return mPlaybackStatus;
264}
265
266bool Dvr::readPlaybackFMQ(bool isVirtualFrontend, bool isRecording) {
267 // Read playback data from the input FMQ
268 int size = mDvrMQ->availableToRead();
269 int playbackPacketSize = mDvrSettings.playback().packetSize;
270 vector<uint8_t> dataOutputBuffer;
271 dataOutputBuffer.resize(playbackPacketSize);
272 // Dispatch the packet to the PID matching filter output buffer
273 for (int i = 0; i < size / playbackPacketSize; i++) {
274 if (!mDvrMQ->read(dataOutputBuffer.data(), playbackPacketSize)) {
275 return false;
276 }
277 if (isVirtualFrontend) {
278 if (isRecording) {
279 mDemux->sendFrontendInputToRecord(dataOutputBuffer);
280 } else {
281 mDemux->startBroadcastTsFilter(dataOutputBuffer);
282 }
283 } else {
284 startTpidFilter(dataOutputBuffer);
285 }
286 }
287
288 return true;
289}
290
291bool Dvr::processEsDataOnPlayback(bool isVirtualFrontend, bool isRecording) {
292 // Read ES from the DVR FMQ
293 // Note that currently we only provides ES with metaData in a specific format to be parsed.
294 // The ES size should be smaller than the Playback FMQ size to avoid reading truncated data.
295 int size = mDvrMQ->availableToRead();
296 vector<uint8_t> dataOutputBuffer;
297 dataOutputBuffer.resize(size);
298 if (!mDvrMQ->read(dataOutputBuffer.data(), size)) {
299 return false;
300 }
301
302 int metaDataSize = size;
303 int totalFrames = 0;
304 int videoEsDataSize = 0;
305 int audioEsDataSize = 0;
306 int audioPid = 0;
307 int videoPid = 0;
308
309 vector<MediaEsMetaData> esMeta;
310 int videoReadPointer = 0;
311 int audioReadPointer = 0;
312 int frameCount = 0;
313 // Get meta data from the es
314 for (int i = 0; i < metaDataSize; i++) {
315 switch (dataOutputBuffer[i]) {
316 case 'm':
317 metaDataSize = 0;
318 getMetaDataValue(i, dataOutputBuffer.data(), metaDataSize);
319 videoReadPointer = metaDataSize;
320 continue;
321 case 'l':
322 getMetaDataValue(i, dataOutputBuffer.data(), totalFrames);
323 esMeta.resize(totalFrames);
324 continue;
325 case 'V':
326 getMetaDataValue(i, dataOutputBuffer.data(), videoEsDataSize);
327 audioReadPointer = metaDataSize + videoEsDataSize;
328 continue;
329 case 'A':
330 getMetaDataValue(i, dataOutputBuffer.data(), audioEsDataSize);
331 continue;
332 case 'p':
333 if (dataOutputBuffer[++i] == 'a') {
334 getMetaDataValue(i, dataOutputBuffer.data(), audioPid);
335 } else if (dataOutputBuffer[i] == 'v') {
336 getMetaDataValue(i, dataOutputBuffer.data(), videoPid);
337 }
338 continue;
339 case 'v':
340 case 'a':
341 if (dataOutputBuffer[i + 1] != ',') {
342 ALOGE("[Dvr] Invalid format meta data.");
343 return false;
344 }
345 esMeta[frameCount] = {
346 .isAudio = dataOutputBuffer[i] == 'a' ? true : false,
347 };
348 i += 5; // Move to Len
349 getMetaDataValue(i, dataOutputBuffer.data(), esMeta[frameCount].len);
350 if (esMeta[frameCount].isAudio) {
351 esMeta[frameCount].startIndex = audioReadPointer;
352 audioReadPointer += esMeta[frameCount].len;
353 } else {
354 esMeta[frameCount].startIndex = videoReadPointer;
355 videoReadPointer += esMeta[frameCount].len;
356 }
357 i += 4; // move to PTS
358 getMetaDataValue(i, dataOutputBuffer.data(), esMeta[frameCount].pts);
359 frameCount++;
360 continue;
361 default:
362 continue;
363 }
364 }
365
366 if (frameCount != totalFrames) {
367 ALOGE("[Dvr] Invalid meta data, frameCount=%d, totalFrames reported=%d", frameCount,
368 totalFrames);
369 return false;
370 }
371
372 if (metaDataSize + audioEsDataSize + videoEsDataSize != size) {
373 ALOGE("[Dvr] Invalid meta data, metaSize=%d, videoSize=%d, audioSize=%d, totolSize=%d",
374 metaDataSize, videoEsDataSize, audioEsDataSize, size);
375 return false;
376 }
377
378 // Read es raw data from the FMQ per meta data built previously
379 vector<uint8_t> frameData;
380 map<uint64_t, sp<IFilter>>::iterator it;
381 int pid = 0;
382 for (int i = 0; i < totalFrames; i++) {
383 frameData.resize(esMeta[i].len);
384 pid = esMeta[i].isAudio ? audioPid : videoPid;
Amy Zhang68afca62020-07-20 18:28:58 -0700385 memcpy(frameData.data(), dataOutputBuffer.data() + esMeta[i].startIndex, esMeta[i].len);
386 // Send to the media filters or record filters
387 if (!isRecording) {
Amy Zhangbb94eeb2020-07-09 22:48:04 -0700388 for (it = mFilters.begin(); it != mFilters.end(); it++) {
389 if (pid == mDemux->getFilterTpid(it->first)) {
390 mDemux->updateMediaFilterOutput(it->first, frameData,
391 static_cast<uint64_t>(esMeta[i].pts));
Amy Zhangbb94eeb2020-07-09 22:48:04 -0700392 }
393 }
Amy Zhang68afca62020-07-20 18:28:58 -0700394 } else {
395 mDemux->sendFrontendInputToRecord(frameData, pid, static_cast<uint64_t>(esMeta[i].pts));
Amy Zhangbb94eeb2020-07-09 22:48:04 -0700396 }
Amy Zhang68afca62020-07-20 18:28:58 -0700397 startFilterDispatcher(isVirtualFrontend, isRecording);
Amy Zhangbb94eeb2020-07-09 22:48:04 -0700398 }
399
400 return true;
401}
402
403void Dvr::getMetaDataValue(int& index, uint8_t* dataOutputBuffer, int& value) {
404 index += 2; // Move the pointer across the ":" to the value
405 while (dataOutputBuffer[index] != ',' && dataOutputBuffer[index] != '\n') {
406 value = ((dataOutputBuffer[index++] - 48) + value * 10);
407 }
408}
409
410void Dvr::startTpidFilter(vector<uint8_t> data) {
411 map<uint64_t, sp<IFilter>>::iterator it;
412 for (it = mFilters.begin(); it != mFilters.end(); it++) {
413 uint16_t pid = ((data[1] & 0x1f) << 8) | ((data[2] & 0xff));
414 if (DEBUG_DVR) {
415 ALOGW("[Dvr] start ts filter pid: %d", pid);
416 }
417 if (pid == mDemux->getFilterTpid(it->first)) {
418 mDemux->updateFilterOutput(it->first, data);
419 }
420 }
421}
422
423bool Dvr::startFilterDispatcher(bool isVirtualFrontend, bool isRecording) {
424 if (isVirtualFrontend) {
425 if (isRecording) {
426 return mDemux->startRecordFilterDispatcher();
427 } else {
428 return mDemux->startBroadcastFilterDispatcher();
429 }
430 }
431
432 map<uint64_t, sp<IFilter>>::iterator it;
433 // Handle the output data per filter type
434 for (it = mFilters.begin(); it != mFilters.end(); it++) {
435 if (mDemux->startFilterHandler(it->first) != Result::SUCCESS) {
436 return false;
437 }
438 }
439
440 return true;
441}
442
443bool Dvr::writeRecordFMQ(const vector<uint8_t>& data) {
444 lock_guard<mutex> lock(mWriteLock);
445 if (mRecordStatus == RecordStatus::OVERFLOW) {
446 ALOGW("[Dvr] stops writing and wait for the client side flushing.");
447 return true;
448 }
449 if (mDvrMQ->write(data.data(), data.size())) {
450 mDvrEventFlag->wake(static_cast<uint32_t>(DemuxQueueNotifyBits::DATA_READY));
451 maySendRecordStatusCallback();
452 return true;
453 }
454
455 maySendRecordStatusCallback();
456 return false;
457}
458
459void Dvr::maySendRecordStatusCallback() {
460 lock_guard<mutex> lock(mRecordStatusLock);
461 int availableToRead = mDvrMQ->availableToRead();
462 int availableToWrite = mDvrMQ->availableToWrite();
463
464 RecordStatus newStatus = checkRecordStatusChange(availableToWrite, availableToRead,
465 mDvrSettings.record().highThreshold,
466 mDvrSettings.record().lowThreshold);
467 if (mRecordStatus != newStatus) {
468 mCallback->onRecordStatus(newStatus);
469 mRecordStatus = newStatus;
470 }
471}
472
473RecordStatus Dvr::checkRecordStatusChange(uint32_t availableToWrite, uint32_t availableToRead,
474 uint32_t highThreshold, uint32_t lowThreshold) {
475 if (availableToWrite == 0) {
476 return DemuxFilterStatus::OVERFLOW;
477 } else if (availableToRead > highThreshold) {
478 return DemuxFilterStatus::HIGH_WATER;
479 } else if (availableToRead < lowThreshold) {
480 return DemuxFilterStatus::LOW_WATER;
481 }
482 return mRecordStatus;
483}
484
485bool Dvr::addPlaybackFilter(uint64_t filterId, sp<IFilter> filter) {
486 mFilters[filterId] = filter;
487 return true;
488}
489
490bool Dvr::removePlaybackFilter(uint64_t filterId) {
491 mFilters.erase(filterId);
492 return true;
493}
494} // namespace implementation
495} // namespace V1_0
496} // namespace tuner
497} // namespace tv
498} // namespace hardware
499} // namespace android