APacketSource.cpp revision cf7b9c7aae758ac0b99833915053c63c2ac46e09
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#include "APacketSource.h"
18
19#include "ASessionDescription.h"
20
21#include <media/stagefright/foundation/ABuffer.h>
22#include <media/stagefright/foundation/ADebug.h>
23#include <media/stagefright/foundation/AMessage.h>
24#include <media/stagefright/foundation/AString.h>
25#include <media/stagefright/foundation/base64.h>
26#include <media/stagefright/foundation/hexdump.h>
27#include <media/stagefright/MediaBuffer.h>
28#include <media/stagefright/MediaDefs.h>
29#include <media/stagefright/MetaData.h>
30#include <utils/Vector.h>
31
32namespace android {
33
34static bool GetAttribute(const char *s, const char *key, AString *value) {
35    value->clear();
36
37    size_t keyLen = strlen(key);
38
39    for (;;) {
40        const char *colonPos = strchr(s, ';');
41
42        size_t len =
43            (colonPos == NULL) ? strlen(s) : colonPos - s;
44
45        if (len >= keyLen + 1 && s[keyLen] == '=' && !strncmp(s, key, keyLen)) {
46            value->setTo(&s[keyLen + 1], len - keyLen - 1);
47            return true;
48        }
49
50        if (colonPos == NULL) {
51            return false;
52        }
53
54        s = colonPos + 1;
55    }
56}
57
58static sp<ABuffer> decodeHex(const AString &s) {
59    if ((s.size() % 2) != 0) {
60        return NULL;
61    }
62
63    size_t outLen = s.size() / 2;
64    sp<ABuffer> buffer = new ABuffer(outLen);
65    uint8_t *out = buffer->data();
66
67    uint8_t accum = 0;
68    for (size_t i = 0; i < s.size(); ++i) {
69        char c = s.c_str()[i];
70        unsigned value;
71        if (c >= '0' && c <= '9') {
72            value = c - '0';
73        } else if (c >= 'a' && c <= 'f') {
74            value = c - 'a' + 10;
75        } else if (c >= 'A' && c <= 'F') {
76            value = c - 'A' + 10;
77        } else {
78            return NULL;
79        }
80
81        accum = (accum << 4) | value;
82
83        if (i & 1) {
84            *out++ = accum;
85
86            accum = 0;
87        }
88    }
89
90    return buffer;
91}
92
93static sp<ABuffer> MakeAVCCodecSpecificData(const char *params) {
94    AString val;
95    CHECK(GetAttribute(params, "profile-level-id", &val));
96
97    sp<ABuffer> profileLevelID = decodeHex(val);
98    CHECK(profileLevelID != NULL);
99    CHECK_EQ(profileLevelID->size(), 3u);
100
101    Vector<sp<ABuffer> > paramSets;
102
103    size_t numSeqParameterSets = 0;
104    size_t totalSeqParameterSetSize = 0;
105    size_t numPicParameterSets = 0;
106    size_t totalPicParameterSetSize = 0;
107
108    CHECK(GetAttribute(params, "sprop-parameter-sets", &val));
109    size_t start = 0;
110    for (;;) {
111        ssize_t commaPos = val.find(",", start);
112        size_t end = (commaPos < 0) ? val.size() : commaPos;
113
114        AString nalString(val, start, end - start);
115        sp<ABuffer> nal = decodeBase64(nalString);
116        CHECK(nal != NULL);
117        CHECK_GT(nal->size(), 0u);
118        CHECK_LE(nal->size(), 65535u);
119
120        uint8_t nalType = nal->data()[0] & 0x1f;
121        if (numSeqParameterSets == 0) {
122            CHECK_EQ((unsigned)nalType, 7u);
123        } else if (numPicParameterSets > 0) {
124            CHECK_EQ((unsigned)nalType, 8u);
125        }
126        if (nalType == 7) {
127            ++numSeqParameterSets;
128            totalSeqParameterSetSize += nal->size();
129        } else  {
130            CHECK_EQ((unsigned)nalType, 8u);
131            ++numPicParameterSets;
132            totalPicParameterSetSize += nal->size();
133        }
134
135        paramSets.push(nal);
136
137        if (commaPos < 0) {
138            break;
139        }
140
141        start = commaPos + 1;
142    }
143
144    CHECK_LT(numSeqParameterSets, 32u);
145    CHECK_LE(numPicParameterSets, 255u);
146
147    size_t csdSize =
148        1 + 3 + 1 + 1
149        + 2 * numSeqParameterSets + totalSeqParameterSetSize
150        + 1 + 2 * numPicParameterSets + totalPicParameterSetSize;
151
152    sp<ABuffer> csd = new ABuffer(csdSize);
153    uint8_t *out = csd->data();
154
155    *out++ = 0x01;  // configurationVersion
156    memcpy(out, profileLevelID->data(), 3);
157    out += 3;
158    *out++ = (0x3f << 2) | 1;  // lengthSize == 2 bytes
159    *out++ = 0xe0 | numSeqParameterSets;
160
161    for (size_t i = 0; i < numSeqParameterSets; ++i) {
162        sp<ABuffer> nal = paramSets.editItemAt(i);
163
164        *out++ = nal->size() >> 8;
165        *out++ = nal->size() & 0xff;
166
167        memcpy(out, nal->data(), nal->size());
168
169        out += nal->size();
170    }
171
172    *out++ = numPicParameterSets;
173
174    for (size_t i = 0; i < numPicParameterSets; ++i) {
175        sp<ABuffer> nal = paramSets.editItemAt(i + numSeqParameterSets);
176
177        *out++ = nal->size() >> 8;
178        *out++ = nal->size() & 0xff;
179
180        memcpy(out, nal->data(), nal->size());
181
182        out += nal->size();
183    }
184
185    hexdump(csd->data(), csd->size());
186
187    return csd;
188}
189
190sp<ABuffer> MakeAACCodecSpecificData(const char *params) {
191    AString val;
192    CHECK(GetAttribute(params, "config", &val));
193
194    sp<ABuffer> config = decodeHex(val);
195    CHECK(config != NULL);
196    CHECK_GE(config->size(), 4u);
197
198    const uint8_t *data = config->data();
199    uint32_t x = data[0] << 24 | data[1] << 16 | data[2] << 8 | data[3];
200    x = (x >> 1) & 0xffff;
201
202    static const uint8_t kStaticESDS[] = {
203        0x03, 22,
204        0x00, 0x00,     // ES_ID
205        0x00,           // streamDependenceFlag, URL_Flag, OCRstreamFlag
206
207        0x04, 17,
208        0x40,                       // Audio ISO/IEC 14496-3
209        0x00, 0x00, 0x00, 0x00,
210        0x00, 0x00, 0x00, 0x00,
211        0x00, 0x00, 0x00, 0x00,
212
213        0x05, 2,
214        // AudioSpecificInfo follows
215    };
216
217    sp<ABuffer> csd = new ABuffer(sizeof(kStaticESDS) + 2);
218    memcpy(csd->data(), kStaticESDS, sizeof(kStaticESDS));
219    csd->data()[sizeof(kStaticESDS)] = (x >> 8) & 0xff;
220    csd->data()[sizeof(kStaticESDS) + 1] = x & 0xff;
221
222    hexdump(csd->data(), csd->size());
223
224    return csd;
225}
226
227APacketSource::APacketSource(
228        const sp<ASessionDescription> &sessionDesc, size_t index)
229    : mFormat(new MetaData),
230      mEOSResult(OK) {
231    unsigned long PT;
232    AString desc;
233    AString params;
234    sessionDesc->getFormatType(index, &PT, &desc, &params);
235
236    int64_t durationUs;
237    if (sessionDesc->getDurationUs(&durationUs)) {
238        mFormat->setInt64(kKeyDuration, durationUs);
239    } else {
240        mFormat->setInt64(kKeyDuration, 60 * 60 * 1000000ll);
241    }
242
243    if (!strncmp(desc.c_str(), "H264/", 5)) {
244        mFormat->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_AVC);
245
246        int32_t width, height;
247        sessionDesc->getDimensions(index, PT, &width, &height);
248
249        mFormat->setInt32(kKeyWidth, width);
250        mFormat->setInt32(kKeyHeight, height);
251
252        sp<ABuffer> codecSpecificData =
253            MakeAVCCodecSpecificData(params.c_str());
254
255        mFormat->setData(
256                kKeyAVCC, 0,
257                codecSpecificData->data(), codecSpecificData->size());
258
259    } else if (!strncmp(desc.c_str(), "MP4A-LATM", 9)) {
260        mFormat->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_AAC);
261
262        int32_t sampleRate, numChannels;
263        ASessionDescription::ParseFormatDesc(
264                desc.c_str(), &sampleRate, &numChannels);
265
266        mFormat->setInt32(kKeySampleRate, sampleRate);
267        mFormat->setInt32(kKeyChannelCount, numChannels);
268
269        sp<ABuffer> codecSpecificData =
270            MakeAACCodecSpecificData(params.c_str());
271
272        mFormat->setData(
273                kKeyESDS, 0,
274                codecSpecificData->data(), codecSpecificData->size());
275    } else {
276        TRESPASS();
277    }
278}
279
280APacketSource::~APacketSource() {
281}
282
283status_t APacketSource::start(MetaData *params) {
284    return OK;
285}
286
287status_t APacketSource::stop() {
288    return OK;
289}
290
291sp<MetaData> APacketSource::getFormat() {
292    return mFormat;
293}
294
295status_t APacketSource::read(
296        MediaBuffer **out, const ReadOptions *) {
297    *out = NULL;
298
299    Mutex::Autolock autoLock(mLock);
300    while (mEOSResult == OK && mBuffers.empty()) {
301        mCondition.wait(mLock);
302    }
303
304    if (!mBuffers.empty()) {
305        const sp<ABuffer> buffer = *mBuffers.begin();
306
307        uint64_t ntpTime;
308        CHECK(buffer->meta()->findInt64(
309                    "ntp-time", (int64_t *)&ntpTime));
310
311        int64_t timeUs = (int64_t)(ntpTime * 1E6 / (1ll << 32));
312
313        MediaBuffer *mediaBuffer = new MediaBuffer(buffer->size());
314        mediaBuffer->meta_data()->setInt64(kKeyTime, timeUs);
315        memcpy(mediaBuffer->data(), buffer->data(), buffer->size());
316        *out = mediaBuffer;
317
318        mBuffers.erase(mBuffers.begin());
319        return OK;
320    }
321
322    return mEOSResult;
323}
324
325void APacketSource::queueAccessUnit(const sp<ABuffer> &buffer) {
326    int32_t damaged;
327    if (buffer->meta()->findInt32("damaged", &damaged) && damaged) {
328        // LOG(VERBOSE) << "discarding damaged AU";
329        return;
330    }
331
332    Mutex::Autolock autoLock(mLock);
333    mBuffers.push_back(buffer);
334    mCondition.signal();
335}
336
337void APacketSource::signalEOS(status_t result) {
338    CHECK(result != OK);
339
340    Mutex::Autolock autoLock(mLock);
341    mEOSResult = result;
342    mCondition.signal();
343}
344
345}  // namespace android
346