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