NuPlayerDecoder.cpp revision 1173118eace0e9e347cb007f0da817cee87579ed
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 "NuPlayerDecoder"
19#include <utils/Log.h>
20
21#include "NuPlayerDecoder.h"
22
23#include "DecoderWrapper.h"
24#include "ESDS.h"
25
26#include <media/stagefright/foundation/ABuffer.h>
27#include <media/stagefright/foundation/ADebug.h>
28#include <media/stagefright/foundation/AMessage.h>
29#include <media/stagefright/ACodec.h>
30#include <media/stagefright/MediaDefs.h>
31#include <media/stagefright/MetaData.h>
32#include <media/stagefright/Utils.h>
33#include <surfaceflinger/Surface.h>
34#include <gui/ISurfaceTexture.h>
35
36namespace android {
37
38NuPlayer::Decoder::Decoder(
39        const sp<AMessage> &notify,
40        const sp<NativeWindowWrapper> &nativeWindow)
41    : mNotify(notify),
42      mNativeWindow(nativeWindow) {
43}
44
45NuPlayer::Decoder::~Decoder() {
46}
47
48void NuPlayer::Decoder::configure(const sp<MetaData> &meta) {
49    CHECK(mCodec == NULL);
50    CHECK(mWrapper == NULL);
51
52    const char *mime;
53    CHECK(meta->findCString(kKeyMIMEType, &mime));
54
55    sp<AMessage> notifyMsg =
56        new AMessage(kWhatCodecNotify, id());
57
58    sp<AMessage> format = makeFormat(meta);
59
60    if (mNativeWindow != NULL) {
61        format->setObject("native-window", mNativeWindow);
62    }
63
64    if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AAC)) {
65        mWrapper = new DecoderWrapper;
66        looper()->registerHandler(mWrapper);
67
68        mWrapper->setNotificationMessage(notifyMsg);
69        mWrapper->initiateSetup(format);
70    } else {
71        mCodec = new ACodec;
72        looper()->registerHandler(mCodec);
73
74        mCodec->setNotificationMessage(notifyMsg);
75        mCodec->initiateSetup(format);
76    }
77}
78
79void NuPlayer::Decoder::onMessageReceived(const sp<AMessage> &msg) {
80    switch (msg->what()) {
81        case kWhatCodecNotify:
82        {
83            int32_t what;
84            CHECK(msg->findInt32("what", &what));
85
86            if (what == ACodec::kWhatFillThisBuffer) {
87                onFillThisBuffer(msg);
88            } else {
89                sp<AMessage> notify = mNotify->dup();
90                notify->setMessage("codec-request", msg);
91                notify->post();
92            }
93            break;
94        }
95
96        default:
97            TRESPASS();
98            break;
99    }
100}
101
102sp<AMessage> NuPlayer::Decoder::makeFormat(const sp<MetaData> &meta) {
103    CHECK(mCSD.isEmpty());
104
105    const char *mime;
106    CHECK(meta->findCString(kKeyMIMEType, &mime));
107
108    sp<AMessage> msg = new AMessage;
109    msg->setString("mime", mime);
110
111    if (!strncasecmp("video/", mime, 6)) {
112        int32_t width, height;
113        CHECK(meta->findInt32(kKeyWidth, &width));
114        CHECK(meta->findInt32(kKeyHeight, &height));
115
116        msg->setInt32("width", width);
117        msg->setInt32("height", height);
118    } else {
119        CHECK(!strncasecmp("audio/", mime, 6));
120
121        int32_t numChannels, sampleRate;
122        CHECK(meta->findInt32(kKeyChannelCount, &numChannels));
123        CHECK(meta->findInt32(kKeySampleRate, &sampleRate));
124
125        msg->setInt32("channel-count", numChannels);
126        msg->setInt32("sample-rate", sampleRate);
127    }
128
129    int32_t maxInputSize;
130    if (meta->findInt32(kKeyMaxInputSize, &maxInputSize)) {
131        msg->setInt32("max-input-size", maxInputSize);
132    }
133
134    mCSDIndex = 0;
135
136    uint32_t type;
137    const void *data;
138    size_t size;
139    if (meta->findData(kKeyAVCC, &type, &data, &size)) {
140        // Parse the AVCDecoderConfigurationRecord
141
142        const uint8_t *ptr = (const uint8_t *)data;
143
144        CHECK(size >= 7);
145        CHECK_EQ((unsigned)ptr[0], 1u);  // configurationVersion == 1
146        uint8_t profile = ptr[1];
147        uint8_t level = ptr[3];
148
149        // There is decodable content out there that fails the following
150        // assertion, let's be lenient for now...
151        // CHECK((ptr[4] >> 2) == 0x3f);  // reserved
152
153        size_t lengthSize = 1 + (ptr[4] & 3);
154
155        // commented out check below as H264_QVGA_500_NO_AUDIO.3gp
156        // violates it...
157        // CHECK((ptr[5] >> 5) == 7);  // reserved
158
159        size_t numSeqParameterSets = ptr[5] & 31;
160
161        ptr += 6;
162        size -= 6;
163
164        sp<ABuffer> buffer = new ABuffer(1024);
165        buffer->setRange(0, 0);
166
167        for (size_t i = 0; i < numSeqParameterSets; ++i) {
168            CHECK(size >= 2);
169            size_t length = U16_AT(ptr);
170
171            ptr += 2;
172            size -= 2;
173
174            CHECK(size >= length);
175
176            memcpy(buffer->data() + buffer->size(), "\x00\x00\x00\x01", 4);
177            memcpy(buffer->data() + buffer->size() + 4, ptr, length);
178            buffer->setRange(0, buffer->size() + 4 + length);
179
180            ptr += length;
181            size -= length;
182        }
183
184        buffer->meta()->setInt32("csd", true);
185        mCSD.push(buffer);
186
187        buffer = new ABuffer(1024);
188        buffer->setRange(0, 0);
189
190        CHECK(size >= 1);
191        size_t numPictureParameterSets = *ptr;
192        ++ptr;
193        --size;
194
195        for (size_t i = 0; i < numPictureParameterSets; ++i) {
196            CHECK(size >= 2);
197            size_t length = U16_AT(ptr);
198
199            ptr += 2;
200            size -= 2;
201
202            CHECK(size >= length);
203
204            memcpy(buffer->data() + buffer->size(), "\x00\x00\x00\x01", 4);
205            memcpy(buffer->data() + buffer->size() + 4, ptr, length);
206            buffer->setRange(0, buffer->size() + 4 + length);
207
208            ptr += length;
209            size -= length;
210        }
211
212        buffer->meta()->setInt32("csd", true);
213        mCSD.push(buffer);
214
215        msg->setObject("csd", buffer);
216    } else if (meta->findData(kKeyESDS, &type, &data, &size)) {
217#if 0
218        ESDS esds((const char *)data, size);
219        CHECK_EQ(esds.InitCheck(), (status_t)OK);
220
221        const void *codec_specific_data;
222        size_t codec_specific_data_size;
223        esds.getCodecSpecificInfo(
224                &codec_specific_data, &codec_specific_data_size);
225
226        sp<ABuffer> buffer = new ABuffer(codec_specific_data_size);
227
228        memcpy(buffer->data(), codec_specific_data,
229               codec_specific_data_size);
230
231        buffer->meta()->setInt32("csd", true);
232        mCSD.push(buffer);
233#else
234        sp<ABuffer> buffer = new ABuffer(size);
235        memcpy(buffer->data(), data, size);
236
237        msg->setObject("esds", buffer);
238#endif
239    }
240
241    return msg;
242}
243
244void NuPlayer::Decoder::onFillThisBuffer(const sp<AMessage> &msg) {
245    sp<AMessage> reply;
246    CHECK(msg->findMessage("reply", &reply));
247
248#if 0
249    sp<RefBase> obj;
250    CHECK(msg->findObject("buffer", &obj));
251    sp<ABuffer> outBuffer = static_cast<ABuffer *>(obj.get());
252#else
253    sp<ABuffer> outBuffer;
254#endif
255
256    if (mCSDIndex < mCSD.size()) {
257        outBuffer = mCSD.editItemAt(mCSDIndex++);
258        outBuffer->meta()->setInt64("timeUs", 0);
259
260        reply->setObject("buffer", outBuffer);
261        reply->post();
262        return;
263    }
264
265    sp<AMessage> notify = mNotify->dup();
266    notify->setMessage("codec-request", msg);
267    notify->post();
268}
269
270void NuPlayer::Decoder::signalFlush() {
271    if (mCodec != NULL) {
272        mCodec->signalFlush();
273    } else {
274        CHECK(mWrapper != NULL);
275        mWrapper->signalFlush();
276    }
277}
278
279void NuPlayer::Decoder::signalResume() {
280    if (mCodec != NULL) {
281        mCodec->signalResume();
282    } else {
283        CHECK(mWrapper != NULL);
284        mWrapper->signalResume();
285    }
286}
287
288void NuPlayer::Decoder::initiateShutdown() {
289    if (mCodec != NULL) {
290        mCodec->initiateShutdown();
291    } else {
292        CHECK(mWrapper != NULL);
293        mWrapper->initiateShutdown();
294    }
295}
296
297}  // namespace android
298
299