1 /*
2 * Copyright (C) 2010 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 "NuPlayerStreamListener"
19 #include <utils/Log.h>
20
21 #include "NuPlayerStreamListener.h"
22
23 #include <binder/MemoryDealer.h>
24 #include <media/stagefright/foundation/ADebug.h>
25 #include <media/stagefright/foundation/AMessage.h>
26 #include <media/stagefright/MediaErrors.h>
27
28 namespace android {
29
NuPlayerStreamListener(const sp<IStreamSource> & source,const sp<AHandler> & targetHandler)30 NuPlayer::NuPlayerStreamListener::NuPlayerStreamListener(
31 const sp<IStreamSource> &source,
32 const sp<AHandler> &targetHandler)
33 : mSource(source),
34 mTargetHandler(targetHandler),
35 mEOS(false),
36 mSendDataNotification(true) {
37 mMemoryDealer = new MemoryDealer(kNumBuffers * kBufferSize);
38 for (size_t i = 0; i < kNumBuffers; ++i) {
39 sp<IMemory> mem = mMemoryDealer->allocate(kBufferSize);
40 CHECK(mem != NULL);
41
42 mBuffers.push(mem);
43 }
44 mSource->setBuffers(mBuffers);
45 }
46
start()47 void NuPlayer::NuPlayerStreamListener::start() {
48 for (size_t i = 0; i < kNumBuffers; ++i) {
49 mSource->onBufferAvailable(i);
50 }
51 }
52
queueBuffer(size_t index,size_t size)53 void NuPlayer::NuPlayerStreamListener::queueBuffer(size_t index, size_t size) {
54 QueueEntry entry;
55 entry.mIsCommand = false;
56 entry.mIndex = index;
57 entry.mSize = size;
58 entry.mOffset = 0;
59
60 Mutex::Autolock autoLock(mLock);
61 mQueue.push_back(entry);
62
63 if (mSendDataNotification) {
64 mSendDataNotification = false;
65
66 if (mTargetHandler != NULL) {
67 (new AMessage(kWhatMoreDataQueued, mTargetHandler))->post();
68 }
69 }
70 }
71
issueCommand(Command cmd,bool synchronous,const sp<AMessage> & extra)72 void NuPlayer::NuPlayerStreamListener::issueCommand(
73 Command cmd, bool synchronous, const sp<AMessage> &extra) {
74 CHECK(!synchronous);
75
76 QueueEntry entry;
77 entry.mIsCommand = true;
78 entry.mCommand = cmd;
79 entry.mExtra = extra;
80
81 Mutex::Autolock autoLock(mLock);
82 mQueue.push_back(entry);
83
84 if (mSendDataNotification) {
85 mSendDataNotification = false;
86
87 if (mTargetHandler != NULL) {
88 (new AMessage(kWhatMoreDataQueued, mTargetHandler))->post();
89 }
90 }
91 }
92
read(void * data,size_t size,sp<AMessage> * extra)93 ssize_t NuPlayer::NuPlayerStreamListener::read(
94 void *data, size_t size, sp<AMessage> *extra) {
95 CHECK_GT(size, 0u);
96
97 extra->clear();
98
99 Mutex::Autolock autoLock(mLock);
100
101 if (mEOS) {
102 return 0;
103 }
104
105 if (mQueue.empty()) {
106 mSendDataNotification = true;
107
108 return -EWOULDBLOCK;
109 }
110
111 QueueEntry *entry = &*mQueue.begin();
112
113 if (entry->mIsCommand) {
114 switch (entry->mCommand) {
115 case EOS:
116 {
117 mQueue.erase(mQueue.begin());
118 entry = NULL;
119
120 mEOS = true;
121 return 0;
122 }
123
124 case DISCONTINUITY:
125 {
126 *extra = entry->mExtra;
127
128 mQueue.erase(mQueue.begin());
129 entry = NULL;
130
131 return INFO_DISCONTINUITY;
132 }
133
134 default:
135 TRESPASS();
136 break;
137 }
138 }
139
140 size_t copy = entry->mSize;
141 if (copy > size) {
142 copy = size;
143 }
144
145 if (entry->mIndex >= mBuffers.size()) {
146 return ERROR_MALFORMED;
147 }
148
149 sp<IMemory> mem = mBuffers.editItemAt(entry->mIndex);
150 if (mem == NULL || mem->size() < copy || mem->size() - copy < entry->mOffset) {
151 return ERROR_MALFORMED;
152 }
153
154 memcpy(data,
155 (const uint8_t *)mem->unsecurePointer()
156 + entry->mOffset,
157 copy);
158
159 entry->mOffset += copy;
160 entry->mSize -= copy;
161
162 if (entry->mSize == 0) {
163 mSource->onBufferAvailable(entry->mIndex);
164 mQueue.erase(mQueue.begin());
165 entry = NULL;
166 }
167
168 return copy;
169 }
170
171 } // namespace android
172