frameworks/av
修訂 | 834fa293bf296c85169338c498cdc0bbf9891e2b (tree) |
---|---|
時間 | 2019-10-24 13:07:30 |
作者 | Chih-Wei Huang <cwhuang@linu...> |
Commiter | Chih-Wei Huang |
Merge tag 'android-8.1.0_r69' into oreo-x86
Android 8.1.0 Release 69 (5794017)
@@ -314,6 +314,11 @@ bool NuPlayer::CCDecoder::extractFromMPEGUserData(const sp<ABuffer> &accessUnit) | ||
314 | 314 | const size_t *userData = (size_t *)mpegUserData->data(); |
315 | 315 | |
316 | 316 | for (size_t i = 0; i < mpegUserData->size() / sizeof(size_t); ++i) { |
317 | + if (accessUnit->size() < userData[i]) { | |
318 | + ALOGW("b/129068792, skip invalid offset for user data"); | |
319 | + android_errorWriteLog(0x534e4554, "129068792"); | |
320 | + continue; | |
321 | + } | |
317 | 322 | trackAdded |= parseMPEGUserDataUnit( |
318 | 323 | timeUs, accessUnit->data() + userData[i], accessUnit->size() - userData[i]); |
319 | 324 | } |
@@ -323,6 +328,12 @@ bool NuPlayer::CCDecoder::extractFromMPEGUserData(const sp<ABuffer> &accessUnit) | ||
323 | 328 | |
324 | 329 | // returns true if a new CC track is found |
325 | 330 | bool NuPlayer::CCDecoder::parseMPEGUserDataUnit(int64_t timeUs, const uint8_t *data, size_t size) { |
331 | + if (size < 9) { | |
332 | + ALOGW("b/129068792, MPEG user data size too small %zu", size); | |
333 | + android_errorWriteLog(0x534e4554, "129068792"); | |
334 | + return false; | |
335 | + } | |
336 | + | |
326 | 337 | ABitReader br(data + 4, 5); |
327 | 338 | |
328 | 339 | uint32_t user_identifier = br.getBits(32); |
@@ -375,8 +386,14 @@ bool NuPlayer::CCDecoder::parseMPEGCCData(int64_t timeUs, const uint8_t *data, s | ||
375 | 386 | mDTVCCPacket->setRange(0, mDTVCCPacket->size() + 2); |
376 | 387 | br.skipBits(16); |
377 | 388 | } else if (mDTVCCPacket->size() > 0 && cc_type == 2) { |
378 | - memcpy(mDTVCCPacket->data() + mDTVCCPacket->size(), br.data(), 2); | |
379 | - mDTVCCPacket->setRange(0, mDTVCCPacket->size() + 2); | |
389 | + if (mDTVCCPacket->capacity() - mDTVCCPacket->size() >= 2) { | |
390 | + memcpy(mDTVCCPacket->data() + mDTVCCPacket->size(), br.data(), 2); | |
391 | + mDTVCCPacket->setRange(0, mDTVCCPacket->size() + 2); | |
392 | + } else { | |
393 | + ALOGW("b/129068792, skip CC due to too much data(%zu, %zu)", | |
394 | + mDTVCCPacket->capacity(), mDTVCCPacket->size()); | |
395 | + android_errorWriteLog(0x534e4554, "129068792"); | |
396 | + } | |
380 | 397 | br.skipBits(16); |
381 | 398 | } else if (cc_type == 0 || cc_type == 1) { |
382 | 399 | uint8_t cc_data_1 = br.getBits(8) & 0x7f; |
@@ -463,6 +480,11 @@ bool NuPlayer::CCDecoder::parseDTVCCPacket(int64_t timeUs, const uint8_t *data, | ||
463 | 480 | size_t trackIndex = getTrackIndex(kTrackTypeCEA708, service_number, &trackAdded); |
464 | 481 | if (mSelectedTrack == (ssize_t)trackIndex) { |
465 | 482 | sp<ABuffer> ccPacket = new ABuffer(block_size); |
483 | + if (ccPacket->capacity() == 0) { | |
484 | + ALOGW("b/129068792, no memory available, %zu", block_size); | |
485 | + android_errorWriteLog(0x534e4554, "129068792"); | |
486 | + return false; | |
487 | + } | |
466 | 488 | memcpy(ccPacket->data(), br.data(), block_size); |
467 | 489 | mCCMap.add(timeUs, ccPacket); |
468 | 490 | } |
@@ -1,1307 +0,0 @@ | ||
1 | -/* | |
2 | - * Copyright (C) 2011 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 "AVIExtractor" | |
19 | -#include <utils/Log.h> | |
20 | - | |
21 | -#include "include/avc_utils.h" | |
22 | -#include "include/AVIExtractor.h" | |
23 | - | |
24 | -#include <binder/ProcessState.h> | |
25 | -#include <media/stagefright/foundation/hexdump.h> | |
26 | -#include <media/stagefright/foundation/ABuffer.h> | |
27 | -#include <media/stagefright/foundation/ADebug.h> | |
28 | -#include <media/stagefright/DataSource.h> | |
29 | -#include <media/stagefright/MediaBuffer.h> | |
30 | -#include <media/stagefright/MediaBufferGroup.h> | |
31 | -#include <media/stagefright/MediaDefs.h> | |
32 | -#include <media/stagefright/MediaErrors.h> | |
33 | -#include <media/stagefright/MetaData.h> | |
34 | -#include <media/stagefright/Utils.h> | |
35 | - | |
36 | -namespace android { | |
37 | - | |
38 | -struct AVIExtractor::AVISource : public MediaSource { | |
39 | - AVISource(const sp<AVIExtractor> &extractor, size_t trackIndex); | |
40 | - | |
41 | - virtual status_t start(MetaData *params); | |
42 | - virtual status_t stop(); | |
43 | - | |
44 | - virtual sp<MetaData> getFormat(); | |
45 | - | |
46 | - virtual status_t read( | |
47 | - MediaBuffer **buffer, const ReadOptions *options); | |
48 | - | |
49 | -protected: | |
50 | - virtual ~AVISource(); | |
51 | - | |
52 | -private: | |
53 | - sp<AVIExtractor> mExtractor; | |
54 | - size_t mTrackIndex; | |
55 | - const AVIExtractor::Track &mTrack; | |
56 | - MediaBufferGroup *mBufferGroup; | |
57 | - size_t mSampleIndex; | |
58 | - | |
59 | - sp<MP3Splitter> mSplitter; | |
60 | - | |
61 | - DISALLOW_EVIL_CONSTRUCTORS(AVISource); | |
62 | -}; | |
63 | - | |
64 | -//////////////////////////////////////////////////////////////////////////////// | |
65 | - | |
66 | -struct AVIExtractor::MP3Splitter : public RefBase { | |
67 | - MP3Splitter(); | |
68 | - | |
69 | - void clear(); | |
70 | - void append(MediaBuffer *buffer); | |
71 | - status_t read(MediaBuffer **buffer); | |
72 | - | |
73 | -protected: | |
74 | - virtual ~MP3Splitter(); | |
75 | - | |
76 | -private: | |
77 | - bool mFindSync; | |
78 | - int64_t mBaseTimeUs; | |
79 | - int64_t mNumSamplesRead; | |
80 | - sp<ABuffer> mBuffer; | |
81 | - | |
82 | - bool resync(); | |
83 | - | |
84 | - DISALLOW_EVIL_CONSTRUCTORS(MP3Splitter); | |
85 | -}; | |
86 | - | |
87 | -//////////////////////////////////////////////////////////////////////////////// | |
88 | - | |
89 | -AVIExtractor::AVISource::AVISource( | |
90 | - const sp<AVIExtractor> &extractor, size_t trackIndex) | |
91 | - : mExtractor(extractor), | |
92 | - mTrackIndex(trackIndex), | |
93 | - mTrack(mExtractor->mTracks.itemAt(trackIndex)), | |
94 | - mBufferGroup(NULL) { | |
95 | -} | |
96 | - | |
97 | -AVIExtractor::AVISource::~AVISource() { | |
98 | - if (mBufferGroup) { | |
99 | - stop(); | |
100 | - } | |
101 | -} | |
102 | - | |
103 | -status_t AVIExtractor::AVISource::start(MetaData *params) { | |
104 | - CHECK(!mBufferGroup); | |
105 | - | |
106 | - mBufferGroup = new MediaBufferGroup; | |
107 | - | |
108 | - mBufferGroup->add_buffer(new MediaBuffer(mTrack.mMaxSampleSize)); | |
109 | - mBufferGroup->add_buffer(new MediaBuffer(mTrack.mMaxSampleSize)); | |
110 | - mSampleIndex = 0; | |
111 | - | |
112 | - const char *mime; | |
113 | - CHECK(mTrack.mMeta->findCString(kKeyMIMEType, &mime)); | |
114 | - | |
115 | - if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_MPEG)) { | |
116 | - mSplitter = new MP3Splitter; | |
117 | - } else { | |
118 | - mSplitter.clear(); | |
119 | - } | |
120 | - | |
121 | - return OK; | |
122 | -} | |
123 | - | |
124 | -status_t AVIExtractor::AVISource::stop() { | |
125 | - CHECK(mBufferGroup); | |
126 | - | |
127 | - delete mBufferGroup; | |
128 | - mBufferGroup = NULL; | |
129 | - | |
130 | - mSplitter.clear(); | |
131 | - | |
132 | - return OK; | |
133 | -} | |
134 | - | |
135 | -sp<MetaData> AVIExtractor::AVISource::getFormat() { | |
136 | - return mTrack.mMeta; | |
137 | -} | |
138 | - | |
139 | -status_t AVIExtractor::AVISource::read( | |
140 | - MediaBuffer **buffer, const ReadOptions *options) { | |
141 | - CHECK(mBufferGroup); | |
142 | - | |
143 | - *buffer = NULL; | |
144 | - | |
145 | - int64_t seekTimeUs; | |
146 | - ReadOptions::SeekMode seekMode; | |
147 | - if (options && options->getSeekTo(&seekTimeUs, &seekMode)) { | |
148 | - status_t err = | |
149 | - mExtractor->getSampleIndexAtTime( | |
150 | - mTrackIndex, seekTimeUs, seekMode, &mSampleIndex); | |
151 | - | |
152 | - if (err != OK) { | |
153 | - return ERROR_END_OF_STREAM; | |
154 | - } | |
155 | - | |
156 | - if (mSplitter != NULL) { | |
157 | - mSplitter->clear(); | |
158 | - } | |
159 | - } | |
160 | - | |
161 | - for (;;) { | |
162 | - if (mSplitter != NULL) { | |
163 | - status_t err = mSplitter->read(buffer); | |
164 | - | |
165 | - if (err == OK) { | |
166 | - break; | |
167 | - } else if (err != -EAGAIN) { | |
168 | - return err; | |
169 | - } | |
170 | - } | |
171 | - | |
172 | - off64_t offset; | |
173 | - size_t size; | |
174 | - bool isKey; | |
175 | - int64_t timeUs; | |
176 | - status_t err = mExtractor->getSampleInfo( | |
177 | - mTrackIndex, mSampleIndex, &offset, &size, &isKey, &timeUs); | |
178 | - | |
179 | - ++mSampleIndex; | |
180 | - | |
181 | - if (err != OK) { | |
182 | - return ERROR_END_OF_STREAM; | |
183 | - } | |
184 | - | |
185 | - MediaBuffer *out; | |
186 | - CHECK_EQ(mBufferGroup->acquire_buffer(&out), (status_t)OK); | |
187 | - | |
188 | - ssize_t n = mExtractor->mDataSource->readAt(offset, out->data(), size); | |
189 | - | |
190 | - if (n < (ssize_t)size) { | |
191 | - return n < 0 ? (status_t)n : (status_t)ERROR_MALFORMED; | |
192 | - } | |
193 | - | |
194 | - out->set_range(0, size); | |
195 | - | |
196 | - out->meta_data()->setInt64(kKeyTime, timeUs); | |
197 | - | |
198 | - if (isKey) { | |
199 | - out->meta_data()->setInt32(kKeyIsSyncFrame, 1); | |
200 | - } | |
201 | - | |
202 | - if (mSplitter == NULL) { | |
203 | - *buffer = out; | |
204 | - break; | |
205 | - } | |
206 | - | |
207 | - mSplitter->append(out); | |
208 | - out->release(); | |
209 | - out = NULL; | |
210 | - } | |
211 | - | |
212 | - return OK; | |
213 | -} | |
214 | - | |
215 | -//////////////////////////////////////////////////////////////////////////////// | |
216 | - | |
217 | -AVIExtractor::MP3Splitter::MP3Splitter() | |
218 | - : mFindSync(true), | |
219 | - mBaseTimeUs(-1ll), | |
220 | - mNumSamplesRead(0) { | |
221 | -} | |
222 | - | |
223 | -AVIExtractor::MP3Splitter::~MP3Splitter() { | |
224 | -} | |
225 | - | |
226 | -void AVIExtractor::MP3Splitter::clear() { | |
227 | - mFindSync = true; | |
228 | - mBaseTimeUs = -1ll; | |
229 | - mNumSamplesRead = 0; | |
230 | - | |
231 | - if (mBuffer != NULL) { | |
232 | - mBuffer->setRange(0, 0); | |
233 | - } | |
234 | -} | |
235 | - | |
236 | -void AVIExtractor::MP3Splitter::append(MediaBuffer *buffer) { | |
237 | - size_t prevCapacity = (mBuffer != NULL) ? mBuffer->capacity() : 0; | |
238 | - | |
239 | - if (mBaseTimeUs < 0) { | |
240 | - CHECK(mBuffer == NULL || mBuffer->size() == 0); | |
241 | - CHECK(buffer->meta_data()->findInt64(kKeyTime, &mBaseTimeUs)); | |
242 | - mNumSamplesRead = 0; | |
243 | - } | |
244 | - | |
245 | - if (mBuffer != NULL && mBuffer->offset() > 0) { | |
246 | - memmove(mBuffer->base(), mBuffer->data(), mBuffer->size()); | |
247 | - mBuffer->setRange(0, mBuffer->size()); | |
248 | - } | |
249 | - | |
250 | - if (mBuffer == NULL | |
251 | - || mBuffer->size() + buffer->range_length() > prevCapacity) { | |
252 | - size_t newCapacity = | |
253 | - (prevCapacity + buffer->range_length() + 1023) & ~1023; | |
254 | - | |
255 | - sp<ABuffer> newBuffer = new ABuffer(newCapacity); | |
256 | - if (mBuffer != NULL) { | |
257 | - memcpy(newBuffer->data(), mBuffer->data(), mBuffer->size()); | |
258 | - newBuffer->setRange(0, mBuffer->size()); | |
259 | - } else { | |
260 | - newBuffer->setRange(0, 0); | |
261 | - } | |
262 | - mBuffer = newBuffer; | |
263 | - } | |
264 | - | |
265 | - memcpy(mBuffer->data() + mBuffer->size(), | |
266 | - (const uint8_t *)buffer->data() + buffer->range_offset(), | |
267 | - buffer->range_length()); | |
268 | - | |
269 | - mBuffer->setRange(0, mBuffer->size() + buffer->range_length()); | |
270 | -} | |
271 | - | |
272 | -bool AVIExtractor::MP3Splitter::resync() { | |
273 | - if (mBuffer == NULL) { | |
274 | - return false; | |
275 | - } | |
276 | - | |
277 | - bool foundSync = false; | |
278 | - for (size_t offset = 0; offset + 3 < mBuffer->size(); ++offset) { | |
279 | - uint32_t firstHeader = U32_AT(mBuffer->data() + offset); | |
280 | - | |
281 | - size_t frameSize; | |
282 | - if (!GetMPEGAudioFrameSize(firstHeader, &frameSize)) { | |
283 | - continue; | |
284 | - } | |
285 | - | |
286 | - size_t subsequentOffset = offset + frameSize; | |
287 | - size_t i = 3; | |
288 | - while (i > 0) { | |
289 | - if (subsequentOffset + 3 >= mBuffer->size()) { | |
290 | - break; | |
291 | - } | |
292 | - | |
293 | - static const uint32_t kMask = 0xfffe0c00; | |
294 | - | |
295 | - uint32_t header = U32_AT(mBuffer->data() + subsequentOffset); | |
296 | - if ((header & kMask) != (firstHeader & kMask)) { | |
297 | - break; | |
298 | - } | |
299 | - | |
300 | - if (!GetMPEGAudioFrameSize(header, &frameSize)) { | |
301 | - break; | |
302 | - } | |
303 | - | |
304 | - subsequentOffset += frameSize; | |
305 | - --i; | |
306 | - } | |
307 | - | |
308 | - if (i == 0) { | |
309 | - foundSync = true; | |
310 | - memmove(mBuffer->data(), | |
311 | - mBuffer->data() + offset, | |
312 | - mBuffer->size() - offset); | |
313 | - | |
314 | - mBuffer->setRange(0, mBuffer->size() - offset); | |
315 | - break; | |
316 | - } | |
317 | - } | |
318 | - | |
319 | - return foundSync; | |
320 | -} | |
321 | - | |
322 | -status_t AVIExtractor::MP3Splitter::read(MediaBuffer **out) { | |
323 | - *out = NULL; | |
324 | - | |
325 | - if (mFindSync) { | |
326 | - if (!resync()) { | |
327 | - return -EAGAIN; | |
328 | - } | |
329 | - | |
330 | - mFindSync = false; | |
331 | - } | |
332 | - | |
333 | - if (mBuffer->size() < 4) { | |
334 | - return -EAGAIN; | |
335 | - } | |
336 | - | |
337 | - uint32_t header = U32_AT(mBuffer->data()); | |
338 | - size_t frameSize; | |
339 | - int sampleRate; | |
340 | - int numSamples; | |
341 | - if (!GetMPEGAudioFrameSize( | |
342 | - header, &frameSize, &sampleRate, NULL, NULL, &numSamples)) { | |
343 | - return ERROR_MALFORMED; | |
344 | - } | |
345 | - | |
346 | - if (mBuffer->size() < frameSize) { | |
347 | - return -EAGAIN; | |
348 | - } | |
349 | - | |
350 | - MediaBuffer *mbuf = new MediaBuffer(frameSize); | |
351 | - memcpy(mbuf->data(), mBuffer->data(), frameSize); | |
352 | - | |
353 | - int64_t timeUs = mBaseTimeUs + (mNumSamplesRead * 1000000ll) / sampleRate; | |
354 | - mNumSamplesRead += numSamples; | |
355 | - | |
356 | - mbuf->meta_data()->setInt64(kKeyTime, timeUs); | |
357 | - | |
358 | - mBuffer->setRange( | |
359 | - mBuffer->offset() + frameSize, mBuffer->size() - frameSize); | |
360 | - | |
361 | - *out = mbuf; | |
362 | - | |
363 | - return OK; | |
364 | -} | |
365 | - | |
366 | -//////////////////////////////////////////////////////////////////////////////// | |
367 | - | |
368 | -AVIExtractor::AVIExtractor(const sp<DataSource> &dataSource) | |
369 | - : mDataSource(dataSource) { | |
370 | - mInitCheck = parseHeaders(); | |
371 | - | |
372 | - if (mInitCheck != OK) { | |
373 | - mTracks.clear(); | |
374 | - } | |
375 | -} | |
376 | - | |
377 | -AVIExtractor::~AVIExtractor() { | |
378 | -} | |
379 | - | |
380 | -size_t AVIExtractor::countTracks() { | |
381 | - return mTracks.size(); | |
382 | -} | |
383 | - | |
384 | -sp<MediaSource> AVIExtractor::getTrack(size_t index) { | |
385 | - return index < mTracks.size() ? new AVISource(this, index) : NULL; | |
386 | -} | |
387 | - | |
388 | -sp<MetaData> AVIExtractor::getTrackMetaData( | |
389 | - size_t index, uint32_t flags) { | |
390 | - return index < mTracks.size() ? mTracks.editItemAt(index).mMeta : NULL; | |
391 | -} | |
392 | - | |
393 | -sp<MetaData> AVIExtractor::getMetaData() { | |
394 | - sp<MetaData> meta = new MetaData; | |
395 | - | |
396 | - if (mInitCheck == OK) { | |
397 | - meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_CONTAINER_AVI); | |
398 | - } | |
399 | - | |
400 | - return meta; | |
401 | -} | |
402 | - | |
403 | -status_t AVIExtractor::parseHeaders() { | |
404 | - mTracks.clear(); | |
405 | - mMovieOffset = 0; | |
406 | - mFoundIndex = false; | |
407 | - mOffsetsAreAbsolute = false; | |
408 | - | |
409 | - ssize_t res = parseChunk(0ll, -1ll); | |
410 | - | |
411 | - if (res < 0) { | |
412 | - return (status_t)res; | |
413 | - } | |
414 | - | |
415 | - if (mMovieOffset == 0ll || !mFoundIndex) { | |
416 | - return ERROR_MALFORMED; | |
417 | - } | |
418 | - | |
419 | - return OK; | |
420 | -} | |
421 | - | |
422 | -ssize_t AVIExtractor::parseChunk(off64_t offset, off64_t size, int depth) { | |
423 | - if (size >= 0 && size < 8) { | |
424 | - return ERROR_MALFORMED; | |
425 | - } | |
426 | - | |
427 | - uint8_t tmp[12]; | |
428 | - ssize_t n = mDataSource->readAt(offset, tmp, 8); | |
429 | - | |
430 | - if (n < 8) { | |
431 | - return (n < 0) ? n : (ssize_t)ERROR_MALFORMED; | |
432 | - } | |
433 | - | |
434 | - uint32_t fourcc = U32_AT(tmp); | |
435 | - uint32_t chunkSize = U32LE_AT(&tmp[4]); | |
436 | - | |
437 | - if (size >= 0 && chunkSize + 8 > size) { | |
438 | - return ERROR_MALFORMED; | |
439 | - } | |
440 | - | |
441 | - static const char kPrefix[] = " "; | |
442 | - const char *prefix = &kPrefix[strlen(kPrefix) - 2 * depth]; | |
443 | - | |
444 | - if (fourcc == FOURCC('L', 'I', 'S', 'T') | |
445 | - || fourcc == FOURCC('R', 'I', 'F', 'F')) { | |
446 | - // It's a list of chunks | |
447 | - | |
448 | - if (size >= 0 && size < 12) { | |
449 | - return ERROR_MALFORMED; | |
450 | - } | |
451 | - | |
452 | - n = mDataSource->readAt(offset + 8, &tmp[8], 4); | |
453 | - | |
454 | - if (n < 4) { | |
455 | - return (n < 0) ? n : (ssize_t)ERROR_MALFORMED; | |
456 | - } | |
457 | - | |
458 | - uint32_t subFourcc = U32_AT(&tmp[8]); | |
459 | - | |
460 | - ALOGV("%s offset 0x%08llx LIST of '%c%c%c%c', size %d", | |
461 | - prefix, | |
462 | - offset, | |
463 | - (char)(subFourcc >> 24), | |
464 | - (char)((subFourcc >> 16) & 0xff), | |
465 | - (char)((subFourcc >> 8) & 0xff), | |
466 | - (char)(subFourcc & 0xff), | |
467 | - chunkSize - 4); | |
468 | - | |
469 | - if (subFourcc == FOURCC('m', 'o', 'v', 'i')) { | |
470 | - // We're not going to parse this, but will take note of the | |
471 | - // offset. | |
472 | - | |
473 | - mMovieOffset = offset; | |
474 | - } else { | |
475 | - off64_t subOffset = offset + 12; | |
476 | - off64_t subOffsetLimit = subOffset + chunkSize - 4; | |
477 | - while (subOffset < subOffsetLimit) { | |
478 | - ssize_t res = | |
479 | - parseChunk(subOffset, subOffsetLimit - subOffset, depth + 1); | |
480 | - | |
481 | - if (res < 0) { | |
482 | - return res; | |
483 | - } | |
484 | - | |
485 | - subOffset += res; | |
486 | - } | |
487 | - } | |
488 | - } else { | |
489 | - ALOGV("%s offset 0x%08llx CHUNK '%c%c%c%c'", | |
490 | - prefix, | |
491 | - offset, | |
492 | - (char)(fourcc >> 24), | |
493 | - (char)((fourcc >> 16) & 0xff), | |
494 | - (char)((fourcc >> 8) & 0xff), | |
495 | - (char)(fourcc & 0xff)); | |
496 | - | |
497 | - status_t err = OK; | |
498 | - | |
499 | - switch (fourcc) { | |
500 | - case FOURCC('s', 't', 'r', 'h'): | |
501 | - { | |
502 | - err = parseStreamHeader(offset + 8, chunkSize); | |
503 | - break; | |
504 | - } | |
505 | - | |
506 | - case FOURCC('s', 't', 'r', 'f'): | |
507 | - { | |
508 | - err = parseStreamFormat(offset + 8, chunkSize); | |
509 | - break; | |
510 | - } | |
511 | - | |
512 | - case FOURCC('i', 'd', 'x', '1'): | |
513 | - { | |
514 | - err = parseIndex(offset + 8, chunkSize); | |
515 | - break; | |
516 | - } | |
517 | - | |
518 | - default: | |
519 | - break; | |
520 | - } | |
521 | - | |
522 | - if (err != OK) { | |
523 | - return err; | |
524 | - } | |
525 | - } | |
526 | - | |
527 | - if (chunkSize & 1) { | |
528 | - ++chunkSize; | |
529 | - } | |
530 | - | |
531 | - return chunkSize + 8; | |
532 | -} | |
533 | - | |
534 | -static const char *GetMIMETypeForHandler(uint32_t handler) { | |
535 | - switch (handler) { | |
536 | - // Wow... shamelessly copied from | |
537 | - // http://wiki.multimedia.cx/index.php?title=ISO_MPEG-4 | |
538 | - | |
539 | - case FOURCC('3', 'I', 'V', '2'): | |
540 | - case FOURCC('3', 'i', 'v', '2'): | |
541 | - case FOURCC('B', 'L', 'Z', '0'): | |
542 | - case FOURCC('D', 'I', 'G', 'I'): | |
543 | - case FOURCC('D', 'I', 'V', '1'): | |
544 | - case FOURCC('d', 'i', 'v', '1'): | |
545 | - case FOURCC('D', 'I', 'V', 'X'): | |
546 | - case FOURCC('d', 'i', 'v', 'x'): | |
547 | - case FOURCC('D', 'X', '5', '0'): | |
548 | - case FOURCC('d', 'x', '5', '0'): | |
549 | - case FOURCC('D', 'X', 'G', 'M'): | |
550 | - case FOURCC('E', 'M', '4', 'A'): | |
551 | - case FOURCC('E', 'P', 'H', 'V'): | |
552 | - case FOURCC('F', 'M', 'P', '4'): | |
553 | - case FOURCC('f', 'm', 'p', '4'): | |
554 | - case FOURCC('F', 'V', 'F', 'W'): | |
555 | - case FOURCC('H', 'D', 'X', '4'): | |
556 | - case FOURCC('h', 'd', 'x', '4'): | |
557 | - case FOURCC('M', '4', 'C', 'C'): | |
558 | - case FOURCC('M', '4', 'S', '2'): | |
559 | - case FOURCC('m', '4', 's', '2'): | |
560 | - case FOURCC('M', 'P', '4', 'S'): | |
561 | - case FOURCC('m', 'p', '4', 's'): | |
562 | - case FOURCC('M', 'P', '4', 'V'): | |
563 | - case FOURCC('m', 'p', '4', 'v'): | |
564 | - case FOURCC('M', 'V', 'X', 'M'): | |
565 | - case FOURCC('R', 'M', 'P', '4'): | |
566 | - case FOURCC('S', 'E', 'D', 'G'): | |
567 | - case FOURCC('S', 'M', 'P', '4'): | |
568 | - case FOURCC('U', 'M', 'P', '4'): | |
569 | - case FOURCC('W', 'V', '1', 'F'): | |
570 | - case FOURCC('X', 'V', 'I', 'D'): | |
571 | - case FOURCC('X', 'v', 'i', 'D'): | |
572 | - case FOURCC('x', 'v', 'i', 'd'): | |
573 | - case FOURCC('X', 'V', 'I', 'X'): | |
574 | - return MEDIA_MIMETYPE_VIDEO_MPEG4; | |
575 | - | |
576 | - // from http://wiki.multimedia.cx/index.php?title=H264 | |
577 | - case FOURCC('a', 'v', 'c', '1'): | |
578 | - case FOURCC('d', 'a', 'v', 'c'): | |
579 | - case FOURCC('x', '2', '6', '4'): | |
580 | - case FOURCC('H', '2', '6', '4'): | |
581 | - case FOURCC('v', 's', 's', 'h'): | |
582 | - return MEDIA_MIMETYPE_VIDEO_AVC; | |
583 | - | |
584 | - default: | |
585 | - return NULL; | |
586 | - } | |
587 | -} | |
588 | - | |
589 | -status_t AVIExtractor::parseStreamHeader(off64_t offset, size_t size) { | |
590 | - if (size != 56) { | |
591 | - return ERROR_MALFORMED; | |
592 | - } | |
593 | - | |
594 | - if (mTracks.size() > 99) { | |
595 | - return -ERANGE; | |
596 | - } | |
597 | - | |
598 | - sp<ABuffer> buffer = new ABuffer(size); | |
599 | - ssize_t n = mDataSource->readAt(offset, buffer->data(), buffer->size()); | |
600 | - | |
601 | - if (n < (ssize_t)size) { | |
602 | - return n < 0 ? (status_t)n : ERROR_MALFORMED; | |
603 | - } | |
604 | - | |
605 | - const uint8_t *data = buffer->data(); | |
606 | - | |
607 | - uint32_t type = U32_AT(data); | |
608 | - uint32_t handler = U32_AT(&data[4]); | |
609 | - uint32_t flags = U32LE_AT(&data[8]); | |
610 | - | |
611 | - sp<MetaData> meta = new MetaData; | |
612 | - | |
613 | - uint32_t rate = U32LE_AT(&data[20]); | |
614 | - uint32_t scale = U32LE_AT(&data[24]); | |
615 | - | |
616 | - uint32_t sampleSize = U32LE_AT(&data[44]); | |
617 | - | |
618 | - const char *mime = NULL; | |
619 | - Track::Kind kind = Track::OTHER; | |
620 | - | |
621 | - if (type == FOURCC('v', 'i', 'd', 's')) { | |
622 | - mime = GetMIMETypeForHandler(handler); | |
623 | - | |
624 | - if (mime && strncasecmp(mime, "video/", 6)) { | |
625 | - return ERROR_MALFORMED; | |
626 | - } | |
627 | - | |
628 | - if (mime == NULL) { | |
629 | - ALOGW("Unsupported video format '%c%c%c%c'", | |
630 | - (char)(handler >> 24), | |
631 | - (char)((handler >> 16) & 0xff), | |
632 | - (char)((handler >> 8) & 0xff), | |
633 | - (char)(handler & 0xff)); | |
634 | - } | |
635 | - | |
636 | - kind = Track::VIDEO; | |
637 | - } else if (type == FOURCC('a', 'u', 'd', 's')) { | |
638 | - if (mime && strncasecmp(mime, "audio/", 6)) { | |
639 | - return ERROR_MALFORMED; | |
640 | - } | |
641 | - | |
642 | - kind = Track::AUDIO; | |
643 | - } | |
644 | - | |
645 | - if (!mime) { | |
646 | - mime = "application/octet-stream"; | |
647 | - } | |
648 | - | |
649 | - meta->setCString(kKeyMIMEType, mime); | |
650 | - | |
651 | - mTracks.push(); | |
652 | - Track *track = &mTracks.editItemAt(mTracks.size() - 1); | |
653 | - | |
654 | - track->mMeta = meta; | |
655 | - track->mRate = rate; | |
656 | - track->mScale = scale; | |
657 | - track->mBytesPerSample = sampleSize; | |
658 | - track->mKind = kind; | |
659 | - track->mNumSyncSamples = 0; | |
660 | - track->mThumbnailSampleSize = 0; | |
661 | - track->mThumbnailSampleIndex = -1; | |
662 | - track->mMaxSampleSize = 0; | |
663 | - track->mAvgChunkSize = 1.0; | |
664 | - track->mFirstChunkSize = 0; | |
665 | - | |
666 | - return OK; | |
667 | -} | |
668 | - | |
669 | -status_t AVIExtractor::parseStreamFormat(off64_t offset, size_t size) { | |
670 | - if (mTracks.isEmpty()) { | |
671 | - return ERROR_MALFORMED; | |
672 | - } | |
673 | - | |
674 | - Track *track = &mTracks.editItemAt(mTracks.size() - 1); | |
675 | - | |
676 | - if (track->mKind == Track::OTHER) { | |
677 | - // We don't support this content, but that's not a parsing error. | |
678 | - return OK; | |
679 | - } | |
680 | - | |
681 | - bool isVideo = (track->mKind == Track::VIDEO); | |
682 | - | |
683 | - if ((isVideo && size < 40) || (!isVideo && size < 16)) { | |
684 | - // Expected a BITMAPINFO or WAVEFORMAT(EX) structure, respectively. | |
685 | - return ERROR_MALFORMED; | |
686 | - } | |
687 | - | |
688 | - sp<ABuffer> buffer = new ABuffer(size); | |
689 | - ssize_t n = mDataSource->readAt(offset, buffer->data(), buffer->size()); | |
690 | - | |
691 | - if (n < (ssize_t)size) { | |
692 | - return n < 0 ? (status_t)n : ERROR_MALFORMED; | |
693 | - } | |
694 | - | |
695 | - const uint8_t *data = buffer->data(); | |
696 | - | |
697 | - if (isVideo) { | |
698 | - uint32_t width = U32LE_AT(&data[4]); | |
699 | - uint32_t height = U32LE_AT(&data[8]); | |
700 | - | |
701 | - track->mMeta->setInt32(kKeyWidth, width); | |
702 | - track->mMeta->setInt32(kKeyHeight, height); | |
703 | - } else { | |
704 | - uint32_t format = U16LE_AT(data); | |
705 | - | |
706 | - if (format == 0x55) { | |
707 | - track->mMeta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_MPEG); | |
708 | - } else { | |
709 | - ALOGW("Unsupported audio format = 0x%04x", format); | |
710 | - } | |
711 | - | |
712 | - uint32_t numChannels = U16LE_AT(&data[2]); | |
713 | - uint32_t sampleRate = U32LE_AT(&data[4]); | |
714 | - | |
715 | - track->mMeta->setInt32(kKeyChannelCount, numChannels); | |
716 | - track->mMeta->setInt32(kKeySampleRate, sampleRate); | |
717 | - } | |
718 | - | |
719 | - return OK; | |
720 | -} | |
721 | - | |
722 | -// static | |
723 | -bool AVIExtractor::IsCorrectChunkType( | |
724 | - ssize_t trackIndex, Track::Kind kind, uint32_t chunkType) { | |
725 | - uint32_t chunkBase = chunkType & 0xffff; | |
726 | - | |
727 | - switch (kind) { | |
728 | - case Track::VIDEO: | |
729 | - { | |
730 | - if (chunkBase != FOURCC(0, 0, 'd', 'c') | |
731 | - && chunkBase != FOURCC(0, 0, 'd', 'b')) { | |
732 | - return false; | |
733 | - } | |
734 | - break; | |
735 | - } | |
736 | - | |
737 | - case Track::AUDIO: | |
738 | - { | |
739 | - if (chunkBase != FOURCC(0, 0, 'w', 'b')) { | |
740 | - return false; | |
741 | - } | |
742 | - break; | |
743 | - } | |
744 | - | |
745 | - default: | |
746 | - break; | |
747 | - } | |
748 | - | |
749 | - if (trackIndex < 0) { | |
750 | - return true; | |
751 | - } | |
752 | - | |
753 | - uint8_t hi = chunkType >> 24; | |
754 | - uint8_t lo = (chunkType >> 16) & 0xff; | |
755 | - | |
756 | - if (hi < '0' || hi > '9' || lo < '0' || lo > '9') { | |
757 | - return false; | |
758 | - } | |
759 | - | |
760 | - if (trackIndex != (10 * (hi - '0') + (lo - '0'))) { | |
761 | - return false; | |
762 | - } | |
763 | - | |
764 | - return true; | |
765 | -} | |
766 | - | |
767 | -status_t AVIExtractor::parseIndex(off64_t offset, size_t size) { | |
768 | - if ((size % 16) != 0) { | |
769 | - return ERROR_MALFORMED; | |
770 | - } | |
771 | - | |
772 | - sp<ABuffer> buffer = new ABuffer(size); | |
773 | - ssize_t n = mDataSource->readAt(offset, buffer->data(), buffer->size()); | |
774 | - | |
775 | - if (n < (ssize_t)size) { | |
776 | - return n < 0 ? (status_t)n : ERROR_MALFORMED; | |
777 | - } | |
778 | - | |
779 | - const uint8_t *data = buffer->data(); | |
780 | - | |
781 | - while (size > 0) { | |
782 | - uint32_t chunkType = U32_AT(data); | |
783 | - | |
784 | - uint8_t hi = chunkType >> 24; | |
785 | - uint8_t lo = (chunkType >> 16) & 0xff; | |
786 | - | |
787 | - if (hi < '0' || hi > '9' || lo < '0' || lo > '9') { | |
788 | - return ERROR_MALFORMED; | |
789 | - } | |
790 | - | |
791 | - size_t trackIndex = 10 * (hi - '0') + (lo - '0'); | |
792 | - | |
793 | - if (trackIndex >= mTracks.size()) { | |
794 | - return ERROR_MALFORMED; | |
795 | - } | |
796 | - | |
797 | - Track *track = &mTracks.editItemAt(trackIndex); | |
798 | - | |
799 | - if (!IsCorrectChunkType(-1, track->mKind, chunkType)) { | |
800 | - return ERROR_MALFORMED; | |
801 | - } | |
802 | - | |
803 | - if (track->mKind == Track::OTHER) { | |
804 | - data += 16; | |
805 | - size -= 16; | |
806 | - continue; | |
807 | - } | |
808 | - | |
809 | - uint32_t flags = U32LE_AT(&data[4]); | |
810 | - uint32_t offset = U32LE_AT(&data[8]); | |
811 | - uint32_t chunkSize = U32LE_AT(&data[12]); | |
812 | - | |
813 | - if (chunkSize > track->mMaxSampleSize) { | |
814 | - track->mMaxSampleSize = chunkSize; | |
815 | - } | |
816 | - | |
817 | - track->mSamples.push(); | |
818 | - | |
819 | - SampleInfo *info = | |
820 | - &track->mSamples.editItemAt(track->mSamples.size() - 1); | |
821 | - | |
822 | - info->mOffset = offset; | |
823 | - info->mIsKey = (flags & 0x10) != 0; | |
824 | - | |
825 | - if (info->mIsKey) { | |
826 | - static const size_t kMaxNumSyncSamplesToScan = 20; | |
827 | - | |
828 | - if (track->mNumSyncSamples < kMaxNumSyncSamplesToScan) { | |
829 | - if (chunkSize > track->mThumbnailSampleSize) { | |
830 | - track->mThumbnailSampleSize = chunkSize; | |
831 | - | |
832 | - track->mThumbnailSampleIndex = | |
833 | - track->mSamples.size() - 1; | |
834 | - } | |
835 | - } | |
836 | - | |
837 | - ++track->mNumSyncSamples; | |
838 | - } | |
839 | - | |
840 | - data += 16; | |
841 | - size -= 16; | |
842 | - } | |
843 | - | |
844 | - if (!mTracks.isEmpty()) { | |
845 | - off64_t offset; | |
846 | - size_t size; | |
847 | - bool isKey; | |
848 | - int64_t timeUs; | |
849 | - status_t err = getSampleInfo(0, 0, &offset, &size, &isKey, &timeUs); | |
850 | - | |
851 | - if (err != OK) { | |
852 | - mOffsetsAreAbsolute = !mOffsetsAreAbsolute; | |
853 | - err = getSampleInfo(0, 0, &offset, &size, &isKey, &timeUs); | |
854 | - | |
855 | - if (err != OK) { | |
856 | - return err; | |
857 | - } | |
858 | - } | |
859 | - | |
860 | - ALOGV("Chunk offsets are %s", | |
861 | - mOffsetsAreAbsolute ? "absolute" : "movie-chunk relative"); | |
862 | - } | |
863 | - | |
864 | - for (size_t i = 0; i < mTracks.size(); ++i) { | |
865 | - Track *track = &mTracks.editItemAt(i); | |
866 | - | |
867 | - if (track->mBytesPerSample > 0) { | |
868 | - // Assume all chunks are roughly the same size for now. | |
869 | - | |
870 | - // Compute the avg. size of the first 128 chunks (if there are | |
871 | - // that many), but exclude the size of the first one, since | |
872 | - // it may be an outlier. | |
873 | - size_t numSamplesToAverage = track->mSamples.size(); | |
874 | - if (numSamplesToAverage > 256) { | |
875 | - numSamplesToAverage = 256; | |
876 | - } | |
877 | - | |
878 | - double avgChunkSize = 0; | |
879 | - size_t j; | |
880 | - for (j = 0; j <= numSamplesToAverage; ++j) { | |
881 | - off64_t offset; | |
882 | - size_t size; | |
883 | - bool isKey; | |
884 | - int64_t dummy; | |
885 | - | |
886 | - status_t err = | |
887 | - getSampleInfo( | |
888 | - i, j, | |
889 | - &offset, &size, &isKey, &dummy); | |
890 | - | |
891 | - if (err != OK) { | |
892 | - return err; | |
893 | - } | |
894 | - | |
895 | - if (j == 0) { | |
896 | - track->mFirstChunkSize = size; | |
897 | - continue; | |
898 | - } | |
899 | - | |
900 | - avgChunkSize += size; | |
901 | - } | |
902 | - | |
903 | - avgChunkSize /= numSamplesToAverage; | |
904 | - | |
905 | - track->mAvgChunkSize = avgChunkSize; | |
906 | - } | |
907 | - | |
908 | - int64_t durationUs; | |
909 | - CHECK_EQ((status_t)OK, | |
910 | - getSampleTime(i, track->mSamples.size() - 1, &durationUs)); | |
911 | - | |
912 | - ALOGV("track %d duration = %.2f secs", i, durationUs / 1E6); | |
913 | - | |
914 | - track->mMeta->setInt64(kKeyDuration, durationUs); | |
915 | - track->mMeta->setInt32(kKeyMaxInputSize, track->mMaxSampleSize); | |
916 | - | |
917 | - const char *tmp; | |
918 | - CHECK(track->mMeta->findCString(kKeyMIMEType, &tmp)); | |
919 | - | |
920 | - AString mime = tmp; | |
921 | - | |
922 | - if (!strncasecmp("video/", mime.c_str(), 6)) { | |
923 | - if (track->mThumbnailSampleIndex >= 0) { | |
924 | - int64_t thumbnailTimeUs; | |
925 | - CHECK_EQ((status_t)OK, | |
926 | - getSampleTime(i, track->mThumbnailSampleIndex, | |
927 | - &thumbnailTimeUs)); | |
928 | - | |
929 | - track->mMeta->setInt64(kKeyThumbnailTime, thumbnailTimeUs); | |
930 | - } | |
931 | - | |
932 | - status_t err = OK; | |
933 | - | |
934 | - if (!strcasecmp(mime.c_str(), MEDIA_MIMETYPE_VIDEO_MPEG4)) { | |
935 | - err = addMPEG4CodecSpecificData(i); | |
936 | - } else if (!strcasecmp(mime.c_str(), MEDIA_MIMETYPE_VIDEO_AVC)) { | |
937 | - err = addH264CodecSpecificData(i); | |
938 | - } | |
939 | - | |
940 | - if (err != OK) { | |
941 | - return err; | |
942 | - } | |
943 | - } | |
944 | - } | |
945 | - | |
946 | - mFoundIndex = true; | |
947 | - | |
948 | - return OK; | |
949 | -} | |
950 | - | |
951 | -static size_t GetSizeWidth(size_t x) { | |
952 | - size_t n = 1; | |
953 | - while (x > 127) { | |
954 | - ++n; | |
955 | - x >>= 7; | |
956 | - } | |
957 | - return n; | |
958 | -} | |
959 | - | |
960 | -static uint8_t *EncodeSize(uint8_t *dst, size_t x) { | |
961 | - while (x > 127) { | |
962 | - *dst++ = (x & 0x7f) | 0x80; | |
963 | - x >>= 7; | |
964 | - } | |
965 | - *dst++ = x; | |
966 | - return dst; | |
967 | -} | |
968 | - | |
969 | -sp<ABuffer> MakeMPEG4VideoCodecSpecificData(const sp<ABuffer> &config) { | |
970 | - size_t len1 = config->size() + GetSizeWidth(config->size()) + 1; | |
971 | - size_t len2 = len1 + GetSizeWidth(len1) + 1 + 13; | |
972 | - size_t len3 = len2 + GetSizeWidth(len2) + 1 + 3; | |
973 | - | |
974 | - sp<ABuffer> csd = new ABuffer(len3); | |
975 | - uint8_t *dst = csd->data(); | |
976 | - *dst++ = 0x03; | |
977 | - dst = EncodeSize(dst, len2 + 3); | |
978 | - *dst++ = 0x00; // ES_ID | |
979 | - *dst++ = 0x00; | |
980 | - *dst++ = 0x00; // streamDependenceFlag, URL_Flag, OCRstreamFlag | |
981 | - | |
982 | - *dst++ = 0x04; | |
983 | - dst = EncodeSize(dst, len1 + 13); | |
984 | - *dst++ = 0x01; // Video ISO/IEC 14496-2 Simple Profile | |
985 | - for (size_t i = 0; i < 12; ++i) { | |
986 | - *dst++ = 0x00; | |
987 | - } | |
988 | - | |
989 | - *dst++ = 0x05; | |
990 | - dst = EncodeSize(dst, config->size()); | |
991 | - memcpy(dst, config->data(), config->size()); | |
992 | - dst += config->size(); | |
993 | - | |
994 | - // hexdump(csd->data(), csd->size()); | |
995 | - | |
996 | - return csd; | |
997 | -} | |
998 | - | |
999 | -status_t AVIExtractor::addMPEG4CodecSpecificData(size_t trackIndex) { | |
1000 | - Track *track = &mTracks.editItemAt(trackIndex); | |
1001 | - | |
1002 | - off64_t offset; | |
1003 | - size_t size; | |
1004 | - bool isKey; | |
1005 | - int64_t timeUs; | |
1006 | - status_t err = | |
1007 | - getSampleInfo(trackIndex, 0, &offset, &size, &isKey, &timeUs); | |
1008 | - | |
1009 | - if (err != OK) { | |
1010 | - return err; | |
1011 | - } | |
1012 | - | |
1013 | - sp<ABuffer> buffer = new ABuffer(size); | |
1014 | - ssize_t n = mDataSource->readAt(offset, buffer->data(), buffer->size()); | |
1015 | - | |
1016 | - if (n < (ssize_t)size) { | |
1017 | - return n < 0 ? (status_t)n : ERROR_MALFORMED; | |
1018 | - } | |
1019 | - | |
1020 | - // Extract everything up to the first VOP start code from the first | |
1021 | - // frame's encoded data and use it to construct an ESDS with the | |
1022 | - // codec specific data. | |
1023 | - | |
1024 | - size_t i = 0; | |
1025 | - bool found = false; | |
1026 | - while (i + 3 < buffer->size()) { | |
1027 | - if (!memcmp("\x00\x00\x01\xb6", &buffer->data()[i], 4)) { | |
1028 | - found = true; | |
1029 | - break; | |
1030 | - } | |
1031 | - | |
1032 | - ++i; | |
1033 | - } | |
1034 | - | |
1035 | - if (!found) { | |
1036 | - return ERROR_MALFORMED; | |
1037 | - } | |
1038 | - | |
1039 | - buffer->setRange(0, i); | |
1040 | - | |
1041 | - sp<ABuffer> csd = MakeMPEG4VideoCodecSpecificData(buffer); | |
1042 | - track->mMeta->setData(kKeyESDS, kTypeESDS, csd->data(), csd->size()); | |
1043 | - | |
1044 | - return OK; | |
1045 | -} | |
1046 | - | |
1047 | -status_t AVIExtractor::addH264CodecSpecificData(size_t trackIndex) { | |
1048 | - Track *track = &mTracks.editItemAt(trackIndex); | |
1049 | - | |
1050 | - off64_t offset; | |
1051 | - size_t size; | |
1052 | - bool isKey; | |
1053 | - int64_t timeUs; | |
1054 | - | |
1055 | - // Extract codec specific data from the first non-empty sample. | |
1056 | - | |
1057 | - size_t sampleIndex = 0; | |
1058 | - for (;;) { | |
1059 | - status_t err = | |
1060 | - getSampleInfo( | |
1061 | - trackIndex, sampleIndex, &offset, &size, &isKey, &timeUs); | |
1062 | - | |
1063 | - if (err != OK) { | |
1064 | - return err; | |
1065 | - } | |
1066 | - | |
1067 | - if (size > 0) { | |
1068 | - break; | |
1069 | - } | |
1070 | - | |
1071 | - ++sampleIndex; | |
1072 | - } | |
1073 | - | |
1074 | - sp<ABuffer> buffer = new ABuffer(size); | |
1075 | - ssize_t n = mDataSource->readAt(offset, buffer->data(), buffer->size()); | |
1076 | - | |
1077 | - if (n < (ssize_t)size) { | |
1078 | - return n < 0 ? (status_t)n : ERROR_MALFORMED; | |
1079 | - } | |
1080 | - | |
1081 | - sp<MetaData> meta = MakeAVCCodecSpecificData(buffer); | |
1082 | - | |
1083 | - if (meta == NULL) { | |
1084 | - ALOGE("Unable to extract AVC codec specific data"); | |
1085 | - return ERROR_MALFORMED; | |
1086 | - } | |
1087 | - | |
1088 | - int32_t width, height; | |
1089 | - CHECK(meta->findInt32(kKeyWidth, &width)); | |
1090 | - CHECK(meta->findInt32(kKeyHeight, &height)); | |
1091 | - | |
1092 | - uint32_t type; | |
1093 | - const void *csd; | |
1094 | - size_t csdSize; | |
1095 | - CHECK(meta->findData(kKeyAVCC, &type, &csd, &csdSize)); | |
1096 | - | |
1097 | - track->mMeta->setInt32(kKeyWidth, width); | |
1098 | - track->mMeta->setInt32(kKeyHeight, height); | |
1099 | - track->mMeta->setData(kKeyAVCC, type, csd, csdSize); | |
1100 | - | |
1101 | - return OK; | |
1102 | -} | |
1103 | - | |
1104 | -status_t AVIExtractor::getSampleInfo( | |
1105 | - size_t trackIndex, size_t sampleIndex, | |
1106 | - off64_t *offset, size_t *size, bool *isKey, | |
1107 | - int64_t *sampleTimeUs) { | |
1108 | - if (trackIndex >= mTracks.size()) { | |
1109 | - return -ERANGE; | |
1110 | - } | |
1111 | - | |
1112 | - const Track &track = mTracks.itemAt(trackIndex); | |
1113 | - | |
1114 | - if (sampleIndex >= track.mSamples.size()) { | |
1115 | - return -ERANGE; | |
1116 | - } | |
1117 | - | |
1118 | - const SampleInfo &info = track.mSamples.itemAt(sampleIndex); | |
1119 | - | |
1120 | - if (!mOffsetsAreAbsolute) { | |
1121 | - *offset = info.mOffset + mMovieOffset + 8; | |
1122 | - } else { | |
1123 | - *offset = info.mOffset; | |
1124 | - } | |
1125 | - | |
1126 | - *size = 0; | |
1127 | - | |
1128 | - uint8_t tmp[8]; | |
1129 | - ssize_t n = mDataSource->readAt(*offset, tmp, 8); | |
1130 | - | |
1131 | - if (n < 8) { | |
1132 | - return n < 0 ? (status_t)n : (status_t)ERROR_MALFORMED; | |
1133 | - } | |
1134 | - | |
1135 | - uint32_t chunkType = U32_AT(tmp); | |
1136 | - | |
1137 | - if (!IsCorrectChunkType(trackIndex, track.mKind, chunkType)) { | |
1138 | - return ERROR_MALFORMED; | |
1139 | - } | |
1140 | - | |
1141 | - *offset += 8; | |
1142 | - *size = U32LE_AT(&tmp[4]); | |
1143 | - | |
1144 | - *isKey = info.mIsKey; | |
1145 | - | |
1146 | - if (track.mBytesPerSample > 0) { | |
1147 | - size_t sampleStartInBytes; | |
1148 | - if (sampleIndex == 0) { | |
1149 | - sampleStartInBytes = 0; | |
1150 | - } else { | |
1151 | - sampleStartInBytes = | |
1152 | - track.mFirstChunkSize + track.mAvgChunkSize * (sampleIndex - 1); | |
1153 | - } | |
1154 | - | |
1155 | - sampleIndex = sampleStartInBytes / track.mBytesPerSample; | |
1156 | - } | |
1157 | - | |
1158 | - *sampleTimeUs = (sampleIndex * 1000000ll * track.mRate) / track.mScale; | |
1159 | - | |
1160 | - return OK; | |
1161 | -} | |
1162 | - | |
1163 | -status_t AVIExtractor::getSampleTime( | |
1164 | - size_t trackIndex, size_t sampleIndex, int64_t *sampleTimeUs) { | |
1165 | - off64_t offset; | |
1166 | - size_t size; | |
1167 | - bool isKey; | |
1168 | - return getSampleInfo( | |
1169 | - trackIndex, sampleIndex, &offset, &size, &isKey, sampleTimeUs); | |
1170 | -} | |
1171 | - | |
1172 | -status_t AVIExtractor::getSampleIndexAtTime( | |
1173 | - size_t trackIndex, | |
1174 | - int64_t timeUs, MediaSource::ReadOptions::SeekMode mode, | |
1175 | - size_t *sampleIndex) const { | |
1176 | - if (trackIndex >= mTracks.size()) { | |
1177 | - return -ERANGE; | |
1178 | - } | |
1179 | - | |
1180 | - const Track &track = mTracks.itemAt(trackIndex); | |
1181 | - | |
1182 | - ssize_t closestSampleIndex; | |
1183 | - | |
1184 | - if (track.mBytesPerSample > 0) { | |
1185 | - size_t closestByteOffset = | |
1186 | - (timeUs * track.mBytesPerSample) | |
1187 | - / track.mRate * track.mScale / 1000000ll; | |
1188 | - | |
1189 | - if (closestByteOffset <= track.mFirstChunkSize) { | |
1190 | - closestSampleIndex = 0; | |
1191 | - } else { | |
1192 | - closestSampleIndex = | |
1193 | - (closestByteOffset - track.mFirstChunkSize) | |
1194 | - / track.mAvgChunkSize; | |
1195 | - } | |
1196 | - } else { | |
1197 | - // Each chunk contains a single sample. | |
1198 | - closestSampleIndex = timeUs / track.mRate * track.mScale / 1000000ll; | |
1199 | - } | |
1200 | - | |
1201 | - ssize_t numSamples = track.mSamples.size(); | |
1202 | - | |
1203 | - if (closestSampleIndex < 0) { | |
1204 | - closestSampleIndex = 0; | |
1205 | - } else if (closestSampleIndex >= numSamples) { | |
1206 | - closestSampleIndex = numSamples - 1; | |
1207 | - } | |
1208 | - | |
1209 | - if (mode == MediaSource::ReadOptions::SEEK_CLOSEST) { | |
1210 | - *sampleIndex = closestSampleIndex; | |
1211 | - | |
1212 | - return OK; | |
1213 | - } | |
1214 | - | |
1215 | - ssize_t prevSyncSampleIndex = closestSampleIndex; | |
1216 | - while (prevSyncSampleIndex >= 0) { | |
1217 | - const SampleInfo &info = | |
1218 | - track.mSamples.itemAt(prevSyncSampleIndex); | |
1219 | - | |
1220 | - if (info.mIsKey) { | |
1221 | - break; | |
1222 | - } | |
1223 | - | |
1224 | - --prevSyncSampleIndex; | |
1225 | - } | |
1226 | - | |
1227 | - ssize_t nextSyncSampleIndex = closestSampleIndex; | |
1228 | - while (nextSyncSampleIndex < numSamples) { | |
1229 | - const SampleInfo &info = | |
1230 | - track.mSamples.itemAt(nextSyncSampleIndex); | |
1231 | - | |
1232 | - if (info.mIsKey) { | |
1233 | - break; | |
1234 | - } | |
1235 | - | |
1236 | - ++nextSyncSampleIndex; | |
1237 | - } | |
1238 | - | |
1239 | - switch (mode) { | |
1240 | - case MediaSource::ReadOptions::SEEK_PREVIOUS_SYNC: | |
1241 | - { | |
1242 | - *sampleIndex = prevSyncSampleIndex; | |
1243 | - | |
1244 | - return prevSyncSampleIndex >= 0 ? OK : UNKNOWN_ERROR; | |
1245 | - } | |
1246 | - | |
1247 | - case MediaSource::ReadOptions::SEEK_NEXT_SYNC: | |
1248 | - { | |
1249 | - *sampleIndex = nextSyncSampleIndex; | |
1250 | - | |
1251 | - return nextSyncSampleIndex < numSamples ? OK : UNKNOWN_ERROR; | |
1252 | - } | |
1253 | - | |
1254 | - case MediaSource::ReadOptions::SEEK_CLOSEST_SYNC: | |
1255 | - { | |
1256 | - if (prevSyncSampleIndex < 0 && nextSyncSampleIndex >= numSamples) { | |
1257 | - return UNKNOWN_ERROR; | |
1258 | - } | |
1259 | - | |
1260 | - if (prevSyncSampleIndex < 0) { | |
1261 | - *sampleIndex = nextSyncSampleIndex; | |
1262 | - return OK; | |
1263 | - } | |
1264 | - | |
1265 | - if (nextSyncSampleIndex >= numSamples) { | |
1266 | - *sampleIndex = prevSyncSampleIndex; | |
1267 | - return OK; | |
1268 | - } | |
1269 | - | |
1270 | - size_t dist1 = closestSampleIndex - prevSyncSampleIndex; | |
1271 | - size_t dist2 = nextSyncSampleIndex - closestSampleIndex; | |
1272 | - | |
1273 | - *sampleIndex = | |
1274 | - (dist1 < dist2) ? prevSyncSampleIndex : nextSyncSampleIndex; | |
1275 | - | |
1276 | - return OK; | |
1277 | - } | |
1278 | - | |
1279 | - default: | |
1280 | - TRESPASS(); | |
1281 | - break; | |
1282 | - } | |
1283 | -} | |
1284 | - | |
1285 | -bool SniffAVI( | |
1286 | - const sp<DataSource> &source, String8 *mimeType, float *confidence, | |
1287 | - sp<AMessage> *) { | |
1288 | - char tmp[12]; | |
1289 | - if (source->readAt(0, tmp, 12) < 12) { | |
1290 | - return false; | |
1291 | - } | |
1292 | - | |
1293 | - if (!memcmp(tmp, "RIFF", 4) && !memcmp(&tmp[8], "AVI ", 4)) { | |
1294 | - mimeType->setTo(MEDIA_MIMETYPE_CONTAINER_AVI); | |
1295 | - | |
1296 | - // Just a tad over the mp3 extractor's confidence, since | |
1297 | - // these .avi files may contain .mp3 content that otherwise would | |
1298 | - // mistakenly lead to us identifying the entire file as a .mp3 file. | |
1299 | - *confidence = 0.21; | |
1300 | - | |
1301 | - return true; | |
1302 | - } | |
1303 | - | |
1304 | - return false; | |
1305 | -} | |
1306 | - | |
1307 | -} // namespace android |
@@ -129,6 +129,7 @@ cc_library_static { | ||
129 | 129 | |
130 | 130 | shared_libs: [ |
131 | 131 | "libstagefright_enc_common", |
132 | + "liblog", | |
132 | 133 | ], |
133 | 134 | |
134 | 135 | cflags: ["-Werror"], |
@@ -12,6 +12,7 @@ cc_test { | ||
12 | 12 | |
13 | 13 | shared_libs: [ |
14 | 14 | "libdl", |
15 | + "liblog", | |
15 | 16 | ], |
16 | 17 | |
17 | 18 | static_libs: [ |
@@ -47,6 +47,10 @@ | ||
47 | 47 | |
48 | 48 | #include "q_pulse.h" |
49 | 49 | |
50 | +#undef LOG_TAG | |
51 | +#define LOG_TAG "amrwbenc" | |
52 | +#include "log/log.h" | |
53 | + | |
50 | 54 | static Word16 tipos[36] = { |
51 | 55 | 0, 1, 2, 3, /* starting point &ipos[0], 1st iter */ |
52 | 56 | 1, 2, 3, 0, /* starting point &ipos[4], 2nd iter */ |
@@ -745,11 +749,16 @@ void ACELP_4t64_fx( | ||
745 | 749 | |
746 | 750 | i = (Word16)((vo_L_mult(track, NPMAXPT) >> 1)); |
747 | 751 | |
748 | - while (ind[i] >= 0) | |
752 | + while (i < NPMAXPT * NB_TRACK && ind[i] >= 0) | |
749 | 753 | { |
750 | 754 | i += 1; |
751 | 755 | } |
752 | - ind[i] = index; | |
756 | + if (i < NPMAXPT * NB_TRACK) { | |
757 | + ind[i] = index; | |
758 | + } else { | |
759 | + ALOGE("b/132647222, OOB access in ind array track=%d i=%d", track, i); | |
760 | + android_errorWriteLog(0x534e4554, "132647222"); | |
761 | + } | |
753 | 762 | } |
754 | 763 | |
755 | 764 | k = 0; |
@@ -52,7 +52,11 @@ PV_STATUS PV_ReadVideoPacketHeader(VideoDecData *video, int *next_MB) | ||
52 | 52 | PV_BitstreamByteAlign(stream); |
53 | 53 | BitstreamReadBits32(stream, resync_marker_length); |
54 | 54 | |
55 | - *next_MB = (int) BitstreamReadBits16(stream, nbits); | |
55 | + int mbnum = (int) BitstreamReadBits16(stream, nbits); | |
56 | + if (mbnum < 0) { | |
57 | + return PV_FAIL; | |
58 | + } | |
59 | + *next_MB = mbnum; | |
56 | 60 | // if (*next_MB <= video->mbnum) /* needs more investigation */ |
57 | 61 | // *next_MB = video->mbnum+1; |
58 | 62 |
@@ -1355,6 +1355,14 @@ PV_STATUS DecodeShortHeader(VideoDecData *video, Vop *currVop) | ||
1355 | 1355 | int tmpHeight = (tmpDisplayHeight + 15) & -16; |
1356 | 1356 | int tmpWidth = (tmpDisplayWidth + 15) & -16; |
1357 | 1357 | |
1358 | + if (tmpWidth > video->width) | |
1359 | + { | |
1360 | + // while allowed by the spec, this decoder does not actually | |
1361 | + // support an increase in size. | |
1362 | + ALOGE("width increase not supported"); | |
1363 | + status = PV_FAIL; | |
1364 | + goto return_point; | |
1365 | + } | |
1358 | 1366 | if (tmpHeight * tmpWidth > video->size) |
1359 | 1367 | { |
1360 | 1368 | // This is just possibly "b/37079296". |
@@ -157,6 +157,12 @@ ssize_t HTTPDownloader::fetchBlock( | ||
157 | 157 | buffer->size() + bufferRemaining); |
158 | 158 | |
159 | 159 | sp<ABuffer> copy = new ABuffer(buffer->size() + bufferRemaining); |
160 | + if (copy->data() == NULL) { | |
161 | + android_errorWriteLog(0x534e4554, "68399439"); | |
162 | + ALOGE("not enough memory to download: requesting %zu + %zu", | |
163 | + buffer->size(), bufferRemaining); | |
164 | + return NO_MEMORY; | |
165 | + } | |
160 | 166 | memcpy(copy->data(), buffer->data(), buffer->size()); |
161 | 167 | copy->setRange(0, buffer->size()); |
162 | 168 |
@@ -40,7 +40,7 @@ Return<void> TWGraphicBufferProducer::requestBuffer( | ||
40 | 40 | int32_t slot, requestBuffer_cb _hidl_cb) { |
41 | 41 | sp<GraphicBuffer> buf; |
42 | 42 | status_t status = mBase->requestBuffer(slot, &buf); |
43 | - AnwBuffer anwBuffer; | |
43 | + AnwBuffer anwBuffer{}; | |
44 | 44 | if (buf != nullptr) { |
45 | 45 | wrapAs(&anwBuffer, *buf); |
46 | 46 | } |
@@ -62,15 +62,15 @@ Return<void> TWGraphicBufferProducer::dequeueBuffer( | ||
62 | 62 | uint32_t width, uint32_t height, |
63 | 63 | PixelFormat format, uint32_t usage, |
64 | 64 | bool getFrameTimestamps, dequeueBuffer_cb _hidl_cb) { |
65 | - int slot; | |
65 | + int slot{}; | |
66 | 66 | sp<Fence> fence; |
67 | 67 | ::android::FrameEventHistoryDelta outTimestamps; |
68 | 68 | status_t status = mBase->dequeueBuffer( |
69 | 69 | &slot, &fence, width, height, |
70 | 70 | static_cast<::android::PixelFormat>(format), usage, nullptr, |
71 | 71 | getFrameTimestamps ? &outTimestamps : nullptr); |
72 | - hidl_handle tFence; | |
73 | - FrameEventHistoryDelta tOutTimestamps; | |
72 | + hidl_handle tFence{}; | |
73 | + FrameEventHistoryDelta tOutTimestamps{}; | |
74 | 74 | |
75 | 75 | native_handle_t* nh = nullptr; |
76 | 76 | if ((fence == nullptr) || !wrapAs(&tFence, &nh, *fence)) { |
@@ -118,8 +118,8 @@ Return<void> TWGraphicBufferProducer::detachNextBuffer( | ||
118 | 118 | sp<GraphicBuffer> outBuffer; |
119 | 119 | sp<Fence> outFence; |
120 | 120 | status_t status = mBase->detachNextBuffer(&outBuffer, &outFence); |
121 | - AnwBuffer tBuffer; | |
122 | - hidl_handle tFence; | |
121 | + AnwBuffer tBuffer{}; | |
122 | + hidl_handle tFence{}; | |
123 | 123 | |
124 | 124 | if (outBuffer == nullptr) { |
125 | 125 | LOG(ERROR) << "TWGraphicBufferProducer::detachNextBuffer - " |
@@ -161,7 +161,7 @@ Return<void> TWGraphicBufferProducer::attachBuffer( | ||
161 | 161 | Return<void> TWGraphicBufferProducer::queueBuffer( |
162 | 162 | int32_t slot, const QueueBufferInput& input, |
163 | 163 | queueBuffer_cb _hidl_cb) { |
164 | - QueueBufferOutput tOutput; | |
164 | + QueueBufferOutput tOutput{}; | |
165 | 165 | BGraphicBufferProducer::QueueBufferInput lInput( |
166 | 166 | 0, false, HAL_DATASPACE_UNKNOWN, |
167 | 167 | ::android::Rect(0, 0, 1, 1), |
@@ -223,7 +223,7 @@ Return<void> TWGraphicBufferProducer::connect( | ||
223 | 223 | producerControlledByApp, |
224 | 224 | &lOutput); |
225 | 225 | |
226 | - QueueBufferOutput tOutput; | |
226 | + QueueBufferOutput tOutput{}; | |
227 | 227 | std::vector<std::vector<native_handle_t*> > nhAA; |
228 | 228 | if (!wrapAs(&tOutput, &nhAA, lOutput)) { |
229 | 229 | LOG(ERROR) << "TWGraphicBufferProducer::connect - " |
@@ -295,11 +295,11 @@ Return<void> TWGraphicBufferProducer::getLastQueuedBuffer( | ||
295 | 295 | status_t status = mBase->getLastQueuedBuffer( |
296 | 296 | &lOutBuffer, &lOutFence, lOutTransformMatrix); |
297 | 297 | |
298 | - AnwBuffer tOutBuffer; | |
298 | + AnwBuffer tOutBuffer{}; | |
299 | 299 | if (lOutBuffer != nullptr) { |
300 | 300 | wrapAs(&tOutBuffer, *lOutBuffer); |
301 | 301 | } |
302 | - hidl_handle tOutFence; | |
302 | + hidl_handle tOutFence{}; | |
303 | 303 | native_handle_t* nh = nullptr; |
304 | 304 | if ((lOutFence == nullptr) || !wrapAs(&tOutFence, &nh, *lOutFence)) { |
305 | 305 | LOG(ERROR) << "TWGraphicBufferProducer::getLastQueuedBuffer - " |
@@ -322,7 +322,7 @@ Return<void> TWGraphicBufferProducer::getFrameTimestamps( | ||
322 | 322 | ::android::FrameEventHistoryDelta lDelta; |
323 | 323 | mBase->getFrameTimestamps(&lDelta); |
324 | 324 | |
325 | - FrameEventHistoryDelta tDelta; | |
325 | + FrameEventHistoryDelta tDelta{}; | |
326 | 326 | std::vector<std::vector<native_handle_t*> > nhAA; |
327 | 327 | if (!wrapAs(&tDelta, &nhAA, lDelta)) { |
328 | 328 | LOG(ERROR) << "TWGraphicBufferProducer::getFrameTimestamps - " |
@@ -341,7 +341,7 @@ Return<void> TWGraphicBufferProducer::getFrameTimestamps( | ||
341 | 341 | } |
342 | 342 | |
343 | 343 | Return<void> TWGraphicBufferProducer::getUniqueId(getUniqueId_cb _hidl_cb) { |
344 | - uint64_t outId; | |
344 | + uint64_t outId{}; | |
345 | 345 | status_t status = mBase->getUniqueId(&outId); |
346 | 346 | _hidl_cb(static_cast<int32_t>(status), outId); |
347 | 347 | return Void(); |
@@ -383,7 +383,7 @@ status_t TextDescriptions::extract3GPPGlobalDescriptions( | ||
383 | 383 | tmpData += 8; |
384 | 384 | size_t remaining = size - 8; |
385 | 385 | |
386 | - if (size < chunkSize) { | |
386 | + if (chunkSize <= 8 || size < chunkSize) { | |
387 | 387 | return OK; |
388 | 388 | } |
389 | 389 | switch(chunkType) { |
@@ -2987,9 +2987,13 @@ sp<IEffect> AudioFlinger::createEffect( | ||
2987 | 2987 | } |
2988 | 2988 | // look for the thread where the specified audio session is present |
2989 | 2989 | for (size_t i = 0; i < mPlaybackThreads.size(); i++) { |
2990 | - if (mPlaybackThreads.valueAt(i)->hasAudioSession(sessionId) != 0) { | |
2990 | + uint32_t sessionType = mPlaybackThreads.valueAt(i)->hasAudioSession(sessionId); | |
2991 | + if (sessionType != 0) { | |
2991 | 2992 | io = mPlaybackThreads.keyAt(i); |
2992 | - break; | |
2993 | + // thread with same effect session is preferable | |
2994 | + if ((sessionType & ThreadBase::EFFECT_SESSION) != 0) { | |
2995 | + break; | |
2996 | + } | |
2993 | 2997 | } |
2994 | 2998 | } |
2995 | 2999 | if (io == AUDIO_IO_HANDLE_NONE) { |
@@ -3015,6 +3019,21 @@ sp<IEffect> AudioFlinger::createEffect( | ||
3015 | 3019 | io = mPlaybackThreads.keyAt(0); |
3016 | 3020 | } |
3017 | 3021 | ALOGV("createEffect() got io %d for effect %s", io, desc.name); |
3022 | + } else if (checkPlaybackThread_l(io) != nullptr) { | |
3023 | + // allow only one effect chain per sessionId on mPlaybackThreads. | |
3024 | + for (size_t i = 0; i < mPlaybackThreads.size(); i++) { | |
3025 | + const audio_io_handle_t checkIo = mPlaybackThreads.keyAt(i); | |
3026 | + if (io == checkIo) continue; | |
3027 | + const uint32_t sessionType = | |
3028 | + mPlaybackThreads.valueAt(i)->hasAudioSession(sessionId); | |
3029 | + if ((sessionType & ThreadBase::EFFECT_SESSION) != 0) { | |
3030 | + ALOGE("%s: effect %s io %d denied because session %d effect exists on io %d", | |
3031 | + __func__, desc.name, (int)io, (int)sessionId, (int)checkIo); | |
3032 | + android_errorWriteLog(0x534e4554, "123237974"); | |
3033 | + lStatus = BAD_VALUE; | |
3034 | + goto Exit; | |
3035 | + } | |
3036 | + } | |
3018 | 3037 | } |
3019 | 3038 | ThreadBase *thread = checkRecordThread_l(io); |
3020 | 3039 | if (thread == NULL) { |
@@ -27,7 +27,7 @@ | ||
27 | 27 | namespace android { |
28 | 28 | |
29 | 29 | class IOProfile; |
30 | -class AudioMix; | |
30 | +class AudioPolicyMix; | |
31 | 31 | |
32 | 32 | // descriptor for audio inputs. Used to maintain current configuration of each opened audio input |
33 | 33 | // and keep track of the usage of this input. |
@@ -44,7 +44,7 @@ public: | ||
44 | 44 | |
45 | 45 | audio_io_handle_t mIoHandle; // input handle |
46 | 46 | audio_devices_t mDevice; // current device this input is routed to |
47 | - AudioMix *mPolicyMix; // non NULL when used by a dynamic policy | |
47 | + wp<AudioPolicyMix> mPolicyMix; // non NULL when used by a dynamic policy | |
48 | 48 | const sp<IOProfile> mProfile; // I/O profile this output derives from |
49 | 49 | |
50 | 50 | virtual void toAudioPortConfig(struct audio_port_config *dstConfig, |
@@ -29,7 +29,7 @@ | ||
29 | 29 | namespace android { |
30 | 30 | |
31 | 31 | class IOProfile; |
32 | -class AudioMix; | |
32 | +class AudioPolicyMix; | |
33 | 33 | class AudioPolicyClientInterface; |
34 | 34 | class DeviceDescriptor; |
35 | 35 |
@@ -126,7 +126,7 @@ public: | ||
126 | 126 | audio_io_handle_t mIoHandle; // output handle |
127 | 127 | uint32_t mLatency; // |
128 | 128 | audio_output_flags_t mFlags; // |
129 | - AudioMix *mPolicyMix; // non NULL when used by a dynamic policy | |
129 | + wp<AudioPolicyMix> mPolicyMix; // non NULL when used by a dynamic policy | |
130 | 130 | sp<SwAudioOutputDescriptor> mOutput1; // used by duplicated outputs: first output |
131 | 131 | sp<SwAudioOutputDescriptor> mOutput2; // used by duplicated outputs: second output |
132 | 132 | uint32_t mDirectOpenCount; // number of clients using this output (direct outputs only) |
@@ -29,9 +29,11 @@ class SwAudioOutputDescriptor; | ||
29 | 29 | /** |
30 | 30 | * custom mix entry in mPolicyMixes |
31 | 31 | */ |
32 | -class AudioPolicyMix : public RefBase { | |
32 | +class AudioPolicyMix : public AudioMix, public RefBase { | |
33 | 33 | public: |
34 | - AudioPolicyMix() {} | |
34 | + AudioPolicyMix(const AudioMix &mix); | |
35 | + AudioPolicyMix(const AudioPolicyMix&) = delete; | |
36 | + AudioPolicyMix& operator=(const AudioPolicyMix&) = delete; | |
35 | 37 | |
36 | 38 | const sp<SwAudioOutputDescriptor> &getOutput() const; |
37 | 39 |
@@ -39,14 +41,9 @@ public: | ||
39 | 41 | |
40 | 42 | void clearOutput(); |
41 | 43 | |
42 | - android::AudioMix *getMix(); | |
43 | - | |
44 | - void setMix(AudioMix &mix); | |
45 | - | |
46 | 44 | status_t dump(int fd, int spaces, int index) const; |
47 | 45 | |
48 | 46 | private: |
49 | - AudioMix mMix; // Audio policy mix descriptor | |
50 | 47 | sp<SwAudioOutputDescriptor> mOutput; // Corresponding output stream |
51 | 48 | }; |
52 | 49 |
@@ -76,9 +73,9 @@ public: | ||
76 | 73 | |
77 | 74 | audio_devices_t getDeviceAndMixForInputSource(audio_source_t inputSource, |
78 | 75 | audio_devices_t availableDeviceTypes, |
79 | - AudioMix **policyMix); | |
76 | + sp<AudioPolicyMix> *policyMix); | |
80 | 77 | |
81 | - status_t getInputMixForAttr(audio_attributes_t attr, AudioMix **policyMix); | |
78 | + status_t getInputMixForAttr(audio_attributes_t attr, sp<AudioPolicyMix> *policyMix); | |
82 | 79 | |
83 | 80 | status_t dump(int fd) const; |
84 | 81 | }; |
@@ -28,6 +28,7 @@ | ||
28 | 28 | namespace android { |
29 | 29 | |
30 | 30 | class AudioPolicyClientInterface; |
31 | +class AudioPolicyMix; | |
31 | 32 | |
32 | 33 | class AudioSession : public RefBase, public AudioSessionInfoUpdateListener |
33 | 34 | { |
@@ -40,7 +41,7 @@ public: | ||
40 | 41 | audio_input_flags_t flags, |
41 | 42 | uid_t uid, |
42 | 43 | bool isSoundTrigger, |
43 | - AudioMix* policyMix, | |
44 | + const sp<AudioPolicyMix> &policyMix, | |
44 | 45 | AudioPolicyClientInterface *clientInterface); |
45 | 46 | |
46 | 47 | status_t dump(int fd, int spaces, int index) const; |
@@ -72,7 +73,7 @@ private: | ||
72 | 73 | bool mIsSoundTrigger; |
73 | 74 | uint32_t mOpenCount; |
74 | 75 | uint32_t mActiveCount; |
75 | - AudioMix* mPolicyMix; // non NULL when used by a dynamic policy | |
76 | + wp<AudioPolicyMix> mPolicyMix; // non NULL when used by a dynamic policy | |
76 | 77 | AudioPolicyClientInterface* mClientInterface; |
77 | 78 | const AudioSessionInfoProvider* mInfoProvider; |
78 | 79 | }; |
@@ -20,6 +20,7 @@ | ||
20 | 20 | #include "AudioInputDescriptor.h" |
21 | 21 | #include "IOProfile.h" |
22 | 22 | #include "AudioGain.h" |
23 | +#include "AudioPolicyMix.h" | |
23 | 24 | #include "HwModule.h" |
24 | 25 | #include <media/AudioPolicy.h> |
25 | 26 | #include <policy.h> |
@@ -19,6 +19,7 @@ | ||
19 | 19 | |
20 | 20 | #include <AudioPolicyInterface.h> |
21 | 21 | #include "AudioOutputDescriptor.h" |
22 | +#include "AudioPolicyMix.h" | |
22 | 23 | #include "IOProfile.h" |
23 | 24 | #include "AudioGain.h" |
24 | 25 | #include "Volume.h" |
@@ -313,17 +314,18 @@ void SwAudioOutputDescriptor::changeRefCount(audio_stream_type_t stream, | ||
313 | 314 | } else { |
314 | 315 | mGlobalRefCount += delta; |
315 | 316 | } |
317 | + sp<AudioPolicyMix> policyMix = mPolicyMix.promote(); | |
316 | 318 | if ((oldGlobalRefCount == 0) && (mGlobalRefCount > 0)) { |
317 | - if ((mPolicyMix != NULL) && ((mPolicyMix->mCbFlags & AudioMix::kCbFlagNotifyActivity) != 0)) | |
319 | + if ((policyMix != NULL) && ((policyMix->mCbFlags & AudioMix::kCbFlagNotifyActivity) != 0)) | |
318 | 320 | { |
319 | - mClientInterface->onDynamicPolicyMixStateUpdate(mPolicyMix->mDeviceAddress, | |
321 | + mClientInterface->onDynamicPolicyMixStateUpdate(policyMix->mDeviceAddress, | |
320 | 322 | MIX_STATE_MIXING); |
321 | 323 | } |
322 | 324 | |
323 | 325 | } else if ((oldGlobalRefCount > 0) && (mGlobalRefCount == 0)) { |
324 | - if ((mPolicyMix != NULL) && ((mPolicyMix->mCbFlags & AudioMix::kCbFlagNotifyActivity) != 0)) | |
326 | + if ((policyMix != NULL) && ((policyMix->mCbFlags & AudioMix::kCbFlagNotifyActivity) != 0)) | |
325 | 327 | { |
326 | - mClientInterface->onDynamicPolicyMixStateUpdate(mPolicyMix->mDeviceAddress, | |
328 | + mClientInterface->onDynamicPolicyMixStateUpdate(policyMix->mDeviceAddress, | |
327 | 329 | MIX_STATE_IDLE); |
328 | 330 | } |
329 | 331 | } |
@@ -27,6 +27,10 @@ | ||
27 | 27 | |
28 | 28 | namespace android { |
29 | 29 | |
30 | +AudioPolicyMix::AudioPolicyMix(const AudioMix &mix) : AudioMix(mix) | |
31 | +{ | |
32 | +} | |
33 | + | |
30 | 34 | void AudioPolicyMix::setOutput(sp<SwAudioOutputDescriptor> &output) |
31 | 35 | { |
32 | 36 | mOutput = output; |
@@ -42,16 +46,6 @@ void AudioPolicyMix::clearOutput() | ||
42 | 46 | mOutput.clear(); |
43 | 47 | } |
44 | 48 | |
45 | -void AudioPolicyMix::setMix(AudioMix &mix) | |
46 | -{ | |
47 | - mMix = mix; | |
48 | -} | |
49 | - | |
50 | -android::AudioMix *AudioPolicyMix::getMix() | |
51 | -{ | |
52 | - return &mMix; | |
53 | -} | |
54 | - | |
55 | 49 | status_t AudioPolicyMix::dump(int fd, int spaces, int index) const |
56 | 50 | { |
57 | 51 | const size_t SIZE = 256; |
@@ -61,25 +55,25 @@ status_t AudioPolicyMix::dump(int fd, int spaces, int index) const | ||
61 | 55 | snprintf(buffer, SIZE, "%*sAudio Policy Mix %d:\n", spaces, "", index+1); |
62 | 56 | result.append(buffer); |
63 | 57 | std::string mixTypeLiteral; |
64 | - if (!MixTypeConverter::toString(mMix.mMixType, mixTypeLiteral)) { | |
65 | - ALOGE("%s: failed to convert mix type %d", __FUNCTION__, mMix.mMixType); | |
58 | + if (!MixTypeConverter::toString(mMixType, mixTypeLiteral)) { | |
59 | + ALOGE("%s: failed to convert mix type %d", __FUNCTION__, mMixType); | |
66 | 60 | return BAD_VALUE; |
67 | 61 | } |
68 | 62 | snprintf(buffer, SIZE, "%*s- mix type: %s\n", spaces, "", mixTypeLiteral.c_str()); |
69 | 63 | result.append(buffer); |
70 | 64 | std::string routeFlagLiteral; |
71 | - RouteFlagTypeConverter::maskToString(mMix.mRouteFlags, routeFlagLiteral); | |
65 | + RouteFlagTypeConverter::maskToString(mRouteFlags, routeFlagLiteral); | |
72 | 66 | snprintf(buffer, SIZE, "%*s- Route Flags: %s\n", spaces, "", routeFlagLiteral.c_str()); |
73 | 67 | result.append(buffer); |
74 | 68 | std::string deviceLiteral; |
75 | - deviceToString(mMix.mDeviceType, deviceLiteral); | |
69 | + deviceToString(mDeviceType, deviceLiteral); | |
76 | 70 | snprintf(buffer, SIZE, "%*s- device type: %s\n", spaces, "", deviceLiteral.c_str()); |
77 | 71 | result.append(buffer); |
78 | - snprintf(buffer, SIZE, "%*s- device address: %s\n", spaces, "", mMix.mDeviceAddress.string()); | |
72 | + snprintf(buffer, SIZE, "%*s- device address: %s\n", spaces, "", mDeviceAddress.string()); | |
79 | 73 | result.append(buffer); |
80 | 74 | |
81 | 75 | int indexCriterion = 0; |
82 | - for (const auto &criterion : mMix.mCriteria) { | |
76 | + for (const auto &criterion : mCriteria) { | |
83 | 77 | snprintf(buffer, SIZE, "%*s- Criterion %d:\n", spaces + 2, "", indexCriterion++); |
84 | 78 | result.append(buffer); |
85 | 79 | std::string usageLiteral; |
@@ -89,7 +83,7 @@ status_t AudioPolicyMix::dump(int fd, int spaces, int index) const | ||
89 | 83 | } |
90 | 84 | snprintf(buffer, SIZE, "%*s- Usage:%s\n", spaces + 4, "", usageLiteral.c_str()); |
91 | 85 | result.append(buffer); |
92 | - if (mMix.mMixType == MIX_TYPE_RECORDERS) { | |
86 | + if (mMixType == MIX_TYPE_RECORDERS) { | |
93 | 87 | std::string sourceLiteral; |
94 | 88 | if (!SourceTypeConverter::toString(criterion.mValue.mSource, sourceLiteral)) { |
95 | 89 | ALOGE("%s: failed to convert source %d", __FUNCTION__, criterion.mValue.mSource); |
@@ -120,12 +114,11 @@ status_t AudioPolicyMixCollection::registerMix(const String8& address, AudioMix | ||
120 | 114 | ALOGE("registerPolicyMixes(): mix for address %s already registered", address.string()); |
121 | 115 | return BAD_VALUE; |
122 | 116 | } |
123 | - sp<AudioPolicyMix> policyMix = new AudioPolicyMix(); | |
124 | - policyMix->setMix(mix); | |
117 | + sp<AudioPolicyMix> policyMix = new AudioPolicyMix(mix); | |
125 | 118 | add(address, policyMix); |
126 | 119 | |
127 | 120 | if (desc != 0) { |
128 | - desc->mPolicyMix = policyMix->getMix(); | |
121 | + desc->mPolicyMix = policyMix; | |
129 | 122 | policyMix->setOutput(desc); |
130 | 123 | } |
131 | 124 | return NO_ERROR; |
@@ -171,8 +164,7 @@ status_t AudioPolicyMixCollection::getOutputForAttr(audio_attributes_t attribute | ||
171 | 164 | ALOGV("getOutputForAttr() querying %zu mixes:", size()); |
172 | 165 | desc = 0; |
173 | 166 | for (size_t i = 0; i < size(); i++) { |
174 | - sp<AudioPolicyMix> policyMix = valueAt(i); | |
175 | - AudioMix *mix = policyMix->getMix(); | |
167 | + sp<AudioPolicyMix> mix = valueAt(i); | |
176 | 168 | |
177 | 169 | if (mix->mMixType == MIX_TYPE_PLAYERS) { |
178 | 170 | // TODO if adding more player rules (currently only 2), make rule handling "generic" |
@@ -269,7 +261,7 @@ status_t AudioPolicyMixCollection::getOutputForAttr(audio_attributes_t attribute | ||
269 | 261 | (hasUidExcludeRules && uidExclusionFound) || |
270 | 262 | (hasUidMatchRules && !uidMatchFound))) { |
271 | 263 | ALOGV("\tgetOutputForAttr will use mix %zu", i); |
272 | - desc = policyMix->getOutput(); | |
264 | + desc = mix->getOutput(); | |
273 | 265 | } |
274 | 266 | |
275 | 267 | } else if (mix->mMixType == MIX_TYPE_RECORDERS) { |
@@ -278,7 +270,7 @@ status_t AudioPolicyMixCollection::getOutputForAttr(audio_attributes_t attribute | ||
278 | 270 | strncmp(attributes.tags + strlen("addr="), |
279 | 271 | mix->mDeviceAddress.string(), |
280 | 272 | AUDIO_ATTRIBUTES_TAGS_MAX_SIZE - strlen("addr=") - 1) == 0) { |
281 | - desc = policyMix->getOutput(); | |
273 | + desc = mix->getOutput(); | |
282 | 274 | } |
283 | 275 | } |
284 | 276 | if (desc != 0) { |
@@ -289,12 +281,13 @@ status_t AudioPolicyMixCollection::getOutputForAttr(audio_attributes_t attribute | ||
289 | 281 | return BAD_VALUE; |
290 | 282 | } |
291 | 283 | |
292 | -audio_devices_t AudioPolicyMixCollection::getDeviceAndMixForInputSource(audio_source_t inputSource, | |
293 | - audio_devices_t availDevices, | |
294 | - AudioMix **policyMix) | |
284 | +audio_devices_t AudioPolicyMixCollection::getDeviceAndMixForInputSource( | |
285 | + audio_source_t inputSource, | |
286 | + audio_devices_t availDevices, | |
287 | + sp<AudioPolicyMix> *policyMix) | |
295 | 288 | { |
296 | 289 | for (size_t i = 0; i < size(); i++) { |
297 | - AudioMix *mix = valueAt(i)->getMix(); | |
290 | + AudioPolicyMix *mix = valueAt(i).get(); | |
298 | 291 | |
299 | 292 | if (mix->mMixType != MIX_TYPE_RECORDERS) { |
300 | 293 | continue; |
@@ -317,7 +310,8 @@ audio_devices_t AudioPolicyMixCollection::getDeviceAndMixForInputSource(audio_so | ||
317 | 310 | return AUDIO_DEVICE_NONE; |
318 | 311 | } |
319 | 312 | |
320 | -status_t AudioPolicyMixCollection::getInputMixForAttr(audio_attributes_t attr, AudioMix **policyMix) | |
313 | +status_t AudioPolicyMixCollection::getInputMixForAttr( | |
314 | + audio_attributes_t attr, sp<AudioPolicyMix> *policyMix) | |
321 | 315 | { |
322 | 316 | if (strncmp(attr.tags, "addr=", strlen("addr=")) != 0) { |
323 | 317 | return BAD_VALUE; |
@@ -327,8 +321,7 @@ status_t AudioPolicyMixCollection::getInputMixForAttr(audio_attributes_t attr, A | ||
327 | 321 | #ifdef LOG_NDEBUG |
328 | 322 | ALOGV("getInputMixForAttr looking for address %s\n mixes available:", address.string()); |
329 | 323 | for (size_t i = 0; i < size(); i++) { |
330 | - sp<AudioPolicyMix> policyMix = valueAt(i); | |
331 | - AudioMix *mix = policyMix->getMix(); | |
324 | + sp<AudioPolicyMix> mix = valueAt(i); | |
332 | 325 | ALOGV("\tmix %zu address=%s", i, mix->mDeviceAddress.string()); |
333 | 326 | } |
334 | 327 | #endif |
@@ -339,13 +332,14 @@ status_t AudioPolicyMixCollection::getInputMixForAttr(audio_attributes_t attr, A | ||
339 | 332 | return BAD_VALUE; |
340 | 333 | } |
341 | 334 | sp<AudioPolicyMix> audioPolicyMix = valueAt(index); |
342 | - AudioMix *mix = audioPolicyMix->getMix(); | |
343 | 335 | |
344 | - if (mix->mMixType != MIX_TYPE_PLAYERS) { | |
336 | + if (audioPolicyMix->mMixType != MIX_TYPE_PLAYERS) { | |
345 | 337 | ALOGW("getInputMixForAttr() bad policy mix type for address %s", address.string()); |
346 | 338 | return BAD_VALUE; |
347 | 339 | } |
348 | - *policyMix = mix; | |
340 | + if (policyMix != nullptr) { | |
341 | + *policyMix = audioPolicyMix; | |
342 | + } | |
349 | 343 | return NO_ERROR; |
350 | 344 | } |
351 | 345 |
@@ -19,6 +19,7 @@ | ||
19 | 19 | |
20 | 20 | #include <AudioPolicyInterface.h> |
21 | 21 | #include "policy.h" |
22 | +#include "AudioPolicyMix.h" | |
22 | 23 | #include "AudioSession.h" |
23 | 24 | #include "AudioGain.h" |
24 | 25 | #include "TypeConverter.h" |
@@ -36,7 +37,7 @@ AudioSession::AudioSession(audio_session_t session, | ||
36 | 37 | audio_input_flags_t flags, |
37 | 38 | uid_t uid, |
38 | 39 | bool isSoundTrigger, |
39 | - AudioMix* policyMix, | |
40 | + const sp<AudioPolicyMix> &policyMix, | |
40 | 41 | AudioPolicyClientInterface *clientInterface) : |
41 | 42 | mRecordClientInfo({ .uid = uid, .session = session, .source = inputSource}), |
42 | 43 | mConfig({ .format = format, .sample_rate = sampleRate, .channel_mask = channelMask}), |
@@ -79,9 +80,10 @@ uint32_t AudioSession::changeActiveCount(int delta) | ||
79 | 80 | if (event != RECORD_CONFIG_EVENT_NONE) { |
80 | 81 | // Dynamic policy callback: |
81 | 82 | // if input maps to a dynamic policy with an activity listener, notify of state change |
82 | - if ((mPolicyMix != NULL) && ((mPolicyMix->mCbFlags & AudioMix::kCbFlagNotifyActivity) != 0)) | |
83 | + sp<AudioPolicyMix> policyMix = mPolicyMix.promote(); | |
84 | + if ((policyMix != NULL) && ((policyMix->mCbFlags & AudioMix::kCbFlagNotifyActivity) != 0)) | |
83 | 85 | { |
84 | - mClientInterface->onDynamicPolicyMixStateUpdate(mPolicyMix->mDeviceAddress, | |
86 | + mClientInterface->onDynamicPolicyMixStateUpdate(policyMix->mDeviceAddress, | |
85 | 87 | (event == RECORD_CONFIG_EVENT_START) ? MIX_STATE_MIXING : MIX_STATE_IDLE); |
86 | 88 | } |
87 | 89 |
@@ -1197,10 +1197,9 @@ status_t AudioPolicyManager::startOutput(audio_io_handle_t output, | ||
1197 | 1197 | mOutputRoutes.incRouteActivity(session); |
1198 | 1198 | |
1199 | 1199 | audio_devices_t newDevice; |
1200 | - AudioMix *policyMix = NULL; | |
1200 | + sp<AudioPolicyMix> policyMix = outputDesc->mPolicyMix.promote(); | |
1201 | 1201 | const char *address = NULL; |
1202 | - if (outputDesc->mPolicyMix != NULL) { | |
1203 | - policyMix = outputDesc->mPolicyMix; | |
1202 | + if (policyMix != NULL) { | |
1204 | 1203 | address = policyMix->mDeviceAddress.string(); |
1205 | 1204 | if ((policyMix->mRouteFlags & MIX_ROUTE_FLAG_RENDER) == MIX_ROUTE_FLAG_RENDER) { |
1206 | 1205 | newDevice = policyMix->mDeviceType; |
@@ -1358,12 +1357,13 @@ status_t AudioPolicyManager::stopOutput(audio_io_handle_t output, | ||
1358 | 1357 | if (outputDesc->mRefCount[stream] == 1) { |
1359 | 1358 | // Automatically disable the remote submix input when output is stopped on a |
1360 | 1359 | // re routing mix of type MIX_TYPE_RECORDERS |
1360 | + sp<AudioPolicyMix> policyMix = outputDesc->mPolicyMix.promote(); | |
1361 | 1361 | if (audio_is_remote_submix_device(outputDesc->mDevice) && |
1362 | - outputDesc->mPolicyMix != NULL && | |
1363 | - outputDesc->mPolicyMix->mMixType == MIX_TYPE_RECORDERS) { | |
1362 | + policyMix != NULL && | |
1363 | + policyMix->mMixType == MIX_TYPE_RECORDERS) { | |
1364 | 1364 | setDeviceConnectionStateInt(AUDIO_DEVICE_IN_REMOTE_SUBMIX, |
1365 | 1365 | AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE, |
1366 | - outputDesc->mPolicyMix->mDeviceAddress, | |
1366 | + policyMix->mDeviceAddress, | |
1367 | 1367 | "remote-submix"); |
1368 | 1368 | } |
1369 | 1369 | } |
@@ -1504,7 +1504,7 @@ status_t AudioPolicyManager::getInputForAttr(const audio_attributes_t *attr, | ||
1504 | 1504 | String8 address = String8(""); |
1505 | 1505 | audio_source_t halInputSource; |
1506 | 1506 | audio_source_t inputSource = attr->source; |
1507 | - AudioMix *policyMix = NULL; | |
1507 | + sp<AudioPolicyMix> policyMix; | |
1508 | 1508 | DeviceVector inputDevices; |
1509 | 1509 | |
1510 | 1510 | // Explicit routing? |
@@ -1646,7 +1646,7 @@ audio_io_handle_t AudioPolicyManager::getInputForDevice(audio_devices_t device, | ||
1646 | 1646 | audio_format_t format, |
1647 | 1647 | audio_channel_mask_t channelMask, |
1648 | 1648 | audio_input_flags_t flags, |
1649 | - AudioMix *policyMix) | |
1649 | + const sp<AudioPolicyMix> &policyMix) | |
1650 | 1650 | { |
1651 | 1651 | audio_io_handle_t input = AUDIO_IO_HANDLE_NONE; |
1652 | 1652 | audio_source_t halInputSource = inputSource; |
@@ -2028,10 +2028,11 @@ status_t AudioPolicyManager::startInput(audio_io_handle_t input, | ||
2028 | 2028 | setInputDevice(input, device, true /* force */); |
2029 | 2029 | |
2030 | 2030 | if (inputDesc->getAudioSessionCount(true/*activeOnly*/) == 1) { |
2031 | + sp<AudioPolicyMix> policyMix = inputDesc->mPolicyMix.promote(); | |
2031 | 2032 | // if input maps to a dynamic policy with an activity listener, notify of state change |
2032 | - if ((inputDesc->mPolicyMix != NULL) | |
2033 | - && ((inputDesc->mPolicyMix->mCbFlags & AudioMix::kCbFlagNotifyActivity) != 0)) { | |
2034 | - mpClientInterface->onDynamicPolicyMixStateUpdate(inputDesc->mPolicyMix->mDeviceAddress, | |
2033 | + if ((policyMix != NULL) | |
2034 | + && ((policyMix->mCbFlags & AudioMix::kCbFlagNotifyActivity) != 0)) { | |
2035 | + mpClientInterface->onDynamicPolicyMixStateUpdate(policyMix->mDeviceAddress, | |
2035 | 2036 | MIX_STATE_MIXING); |
2036 | 2037 | } |
2037 | 2038 |
@@ -2046,10 +2047,10 @@ status_t AudioPolicyManager::startInput(audio_io_handle_t input, | ||
2046 | 2047 | // For remote submix (a virtual device), we open only one input per capture request. |
2047 | 2048 | if (audio_is_remote_submix_device(inputDesc->mDevice)) { |
2048 | 2049 | String8 address = String8(""); |
2049 | - if (inputDesc->mPolicyMix == NULL) { | |
2050 | + if (policyMix == NULL) { | |
2050 | 2051 | address = String8("0"); |
2051 | - } else if (inputDesc->mPolicyMix->mMixType == MIX_TYPE_PLAYERS) { | |
2052 | - address = inputDesc->mPolicyMix->mDeviceAddress; | |
2052 | + } else if (policyMix->mMixType == MIX_TYPE_PLAYERS) { | |
2053 | + address = policyMix->mDeviceAddress; | |
2053 | 2054 | } |
2054 | 2055 | if (address != "") { |
2055 | 2056 | setDeviceConnectionStateInt(AUDIO_DEVICE_OUT_REMOTE_SUBMIX, |
@@ -2097,10 +2098,11 @@ status_t AudioPolicyManager::stopInput(audio_io_handle_t input, | ||
2097 | 2098 | if (inputDesc->isActive()) { |
2098 | 2099 | setInputDevice(input, getNewInputDevice(inputDesc), false /* force */); |
2099 | 2100 | } else { |
2101 | + sp<AudioPolicyMix> policyMix = inputDesc->mPolicyMix.promote(); | |
2100 | 2102 | // if input maps to a dynamic policy with an activity listener, notify of state change |
2101 | - if ((inputDesc->mPolicyMix != NULL) | |
2102 | - && ((inputDesc->mPolicyMix->mCbFlags & AudioMix::kCbFlagNotifyActivity) != 0)) { | |
2103 | - mpClientInterface->onDynamicPolicyMixStateUpdate(inputDesc->mPolicyMix->mDeviceAddress, | |
2103 | + if ((policyMix != NULL) | |
2104 | + && ((policyMix->mCbFlags & AudioMix::kCbFlagNotifyActivity) != 0)) { | |
2105 | + mpClientInterface->onDynamicPolicyMixStateUpdate(policyMix->mDeviceAddress, | |
2104 | 2106 | MIX_STATE_IDLE); |
2105 | 2107 | } |
2106 | 2108 |
@@ -2108,10 +2110,10 @@ status_t AudioPolicyManager::stopInput(audio_io_handle_t input, | ||
2108 | 2110 | // used by a policy mix of type MIX_TYPE_RECORDERS |
2109 | 2111 | if (audio_is_remote_submix_device(inputDesc->mDevice)) { |
2110 | 2112 | String8 address = String8(""); |
2111 | - if (inputDesc->mPolicyMix == NULL) { | |
2113 | + if (policyMix == NULL) { | |
2112 | 2114 | address = String8("0"); |
2113 | - } else if (inputDesc->mPolicyMix->mMixType == MIX_TYPE_PLAYERS) { | |
2114 | - address = inputDesc->mPolicyMix->mDeviceAddress; | |
2115 | + } else if (policyMix->mMixType == MIX_TYPE_PLAYERS) { | |
2116 | + address = policyMix->mDeviceAddress; | |
2115 | 2117 | } |
2116 | 2118 | if (address != "") { |
2117 | 2119 | setDeviceConnectionStateInt(AUDIO_DEVICE_OUT_REMOTE_SUBMIX, |
@@ -4211,7 +4213,7 @@ status_t AudioPolicyManager::checkOutputsForDevice(const sp<DeviceDescriptor>& d | ||
4211 | 4213 | address.string()); |
4212 | 4214 | } |
4213 | 4215 | policyMix->setOutput(desc); |
4214 | - desc->mPolicyMix = policyMix->getMix(); | |
4216 | + desc->mPolicyMix = policyMix; | |
4215 | 4217 | |
4216 | 4218 | } else if (((desc->mFlags & AUDIO_OUTPUT_FLAG_DIRECT) == 0) && |
4217 | 4219 | hasPrimaryOutput()) { |
@@ -5325,7 +5327,7 @@ sp<IOProfile> AudioPolicyManager::getInputProfile(audio_devices_t device, | ||
5325 | 5327 | |
5326 | 5328 | |
5327 | 5329 | audio_devices_t AudioPolicyManager::getDeviceAndMixForInputSource(audio_source_t inputSource, |
5328 | - AudioMix **policyMix) | |
5330 | + sp<AudioPolicyMix> *policyMix) | |
5329 | 5331 | { |
5330 | 5332 | audio_devices_t availableDeviceTypes = mAvailableInputDevices.types() & ~AUDIO_DEVICE_BIT_IN; |
5331 | 5333 | audio_devices_t selectedDeviceFromMix = |
@@ -645,7 +645,7 @@ private: | ||
645 | 645 | audio_format_t format, |
646 | 646 | audio_channel_mask_t channelMask, |
647 | 647 | audio_input_flags_t flags, |
648 | - AudioMix *policyMix); | |
648 | + const sp<AudioPolicyMix> &policyMix); | |
649 | 649 | |
650 | 650 | // internal function to derive a stream type value from audio attributes |
651 | 651 | audio_stream_type_t streamTypefromAttributesInt(const audio_attributes_t *attr); |
@@ -659,7 +659,7 @@ private: | ||
659 | 659 | // select input device corresponding to requested audio source and return associated policy |
660 | 660 | // mix if any. Calls getDeviceForInputSource(). |
661 | 661 | audio_devices_t getDeviceAndMixForInputSource(audio_source_t inputSource, |
662 | - AudioMix **policyMix = NULL); | |
662 | + sp<AudioPolicyMix> *policyMix = NULL); | |
663 | 663 | |
664 | 664 | // Called by setDeviceConnectionState(). |
665 | 665 | status_t setDeviceConnectionStateInt(audio_devices_t device, |