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