APacketSource.cpp revision f8ca90452ff3e252f20de38f1c3eee524c808c3e
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    if (!GetAttribute(params, "profile-level-id", &val)) {
96        return NULL;
97    }
98
99    sp<ABuffer> profileLevelID = decodeHex(val);
100    CHECK(profileLevelID != NULL);
101    CHECK_EQ(profileLevelID->size(), 3u);
102
103    Vector<sp<ABuffer> > paramSets;
104
105    size_t numSeqParameterSets = 0;
106    size_t totalSeqParameterSetSize = 0;
107    size_t numPicParameterSets = 0;
108    size_t totalPicParameterSetSize = 0;
109
110    if (!GetAttribute(params, "sprop-parameter-sets", &val)) {
111        return NULL;
112    }
113
114    size_t start = 0;
115    for (;;) {
116        ssize_t commaPos = val.find(",", start);
117        size_t end = (commaPos < 0) ? val.size() : commaPos;
118
119        AString nalString(val, start, end - start);
120        sp<ABuffer> nal = decodeBase64(nalString);
121        CHECK(nal != NULL);
122        CHECK_GT(nal->size(), 0u);
123        CHECK_LE(nal->size(), 65535u);
124
125        uint8_t nalType = nal->data()[0] & 0x1f;
126        if (numSeqParameterSets == 0) {
127            CHECK_EQ((unsigned)nalType, 7u);
128        } else if (numPicParameterSets > 0) {
129            CHECK_EQ((unsigned)nalType, 8u);
130        }
131        if (nalType == 7) {
132            ++numSeqParameterSets;
133            totalSeqParameterSetSize += nal->size();
134        } else  {
135            CHECK_EQ((unsigned)nalType, 8u);
136            ++numPicParameterSets;
137            totalPicParameterSetSize += nal->size();
138        }
139
140        paramSets.push(nal);
141
142        if (commaPos < 0) {
143            break;
144        }
145
146        start = commaPos + 1;
147    }
148
149    CHECK_LT(numSeqParameterSets, 32u);
150    CHECK_LE(numPicParameterSets, 255u);
151
152    size_t csdSize =
153        1 + 3 + 1 + 1
154        + 2 * numSeqParameterSets + totalSeqParameterSetSize
155        + 1 + 2 * numPicParameterSets + totalPicParameterSetSize;
156
157    sp<ABuffer> csd = new ABuffer(csdSize);
158    uint8_t *out = csd->data();
159
160    *out++ = 0x01;  // configurationVersion
161    memcpy(out, profileLevelID->data(), 3);
162    out += 3;
163    *out++ = (0x3f << 2) | 1;  // lengthSize == 2 bytes
164    *out++ = 0xe0 | numSeqParameterSets;
165
166    for (size_t i = 0; i < numSeqParameterSets; ++i) {
167        sp<ABuffer> nal = paramSets.editItemAt(i);
168
169        *out++ = nal->size() >> 8;
170        *out++ = nal->size() & 0xff;
171
172        memcpy(out, nal->data(), nal->size());
173
174        out += nal->size();
175    }
176
177    *out++ = numPicParameterSets;
178
179    for (size_t i = 0; i < numPicParameterSets; ++i) {
180        sp<ABuffer> nal = paramSets.editItemAt(i + numSeqParameterSets);
181
182        *out++ = nal->size() >> 8;
183        *out++ = nal->size() & 0xff;
184
185        memcpy(out, nal->data(), nal->size());
186
187        out += nal->size();
188    }
189
190    hexdump(csd->data(), csd->size());
191
192    return csd;
193}
194
195sp<ABuffer> MakeAACCodecSpecificData(const char *params) {
196    AString val;
197    CHECK(GetAttribute(params, "config", &val));
198
199    sp<ABuffer> config = decodeHex(val);
200    CHECK(config != NULL);
201    CHECK_GE(config->size(), 4u);
202
203    const uint8_t *data = config->data();
204    uint32_t x = data[0] << 24 | data[1] << 16 | data[2] << 8 | data[3];
205    x = (x >> 1) & 0xffff;
206
207    static const uint8_t kStaticESDS[] = {
208        0x03, 22,
209        0x00, 0x00,     // ES_ID
210        0x00,           // streamDependenceFlag, URL_Flag, OCRstreamFlag
211
212        0x04, 17,
213        0x40,                       // Audio ISO/IEC 14496-3
214        0x00, 0x00, 0x00, 0x00,
215        0x00, 0x00, 0x00, 0x00,
216        0x00, 0x00, 0x00, 0x00,
217
218        0x05, 2,
219        // AudioSpecificInfo follows
220    };
221
222    sp<ABuffer> csd = new ABuffer(sizeof(kStaticESDS) + 2);
223    memcpy(csd->data(), kStaticESDS, sizeof(kStaticESDS));
224    csd->data()[sizeof(kStaticESDS)] = (x >> 8) & 0xff;
225    csd->data()[sizeof(kStaticESDS) + 1] = x & 0xff;
226
227    hexdump(csd->data(), csd->size());
228
229    return csd;
230}
231
232APacketSource::APacketSource(
233        const sp<ASessionDescription> &sessionDesc, size_t index)
234    : mInitCheck(NO_INIT),
235      mFormat(new MetaData),
236      mEOSResult(OK),
237      mFirstAccessUnit(true),
238      mFirstAccessUnitNTP(0) {
239    unsigned long PT;
240    AString desc;
241    AString params;
242    sessionDesc->getFormatType(index, &PT, &desc, &params);
243
244    int64_t durationUs;
245    if (sessionDesc->getDurationUs(&durationUs)) {
246        mFormat->setInt64(kKeyDuration, durationUs);
247    } else {
248        mFormat->setInt64(kKeyDuration, 60 * 60 * 1000000ll);
249    }
250
251    mInitCheck = OK;
252    if (!strncmp(desc.c_str(), "H264/", 5)) {
253        mFormat->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_AVC);
254
255        int32_t width, height;
256        sessionDesc->getDimensions(index, PT, &width, &height);
257
258        mFormat->setInt32(kKeyWidth, width);
259        mFormat->setInt32(kKeyHeight, height);
260
261        sp<ABuffer> codecSpecificData =
262            MakeAVCCodecSpecificData(params.c_str());
263
264        if (codecSpecificData != NULL) {
265            mFormat->setData(
266                    kKeyAVCC, 0,
267                    codecSpecificData->data(), codecSpecificData->size());
268        }
269    } else if (!strncmp(desc.c_str(), "H263-2000/", 10)
270            || !strncmp(desc.c_str(), "H263-1998/", 10)) {
271        mFormat->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_H263);
272
273        int32_t width, height;
274        sessionDesc->getDimensions(index, PT, &width, &height);
275
276        mFormat->setInt32(kKeyWidth, width);
277        mFormat->setInt32(kKeyHeight, height);
278    } else if (!strncmp(desc.c_str(), "MP4A-LATM/", 10)) {
279        mFormat->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_AAC);
280
281        int32_t sampleRate, numChannels;
282        ASessionDescription::ParseFormatDesc(
283                desc.c_str(), &sampleRate, &numChannels);
284
285        mFormat->setInt32(kKeySampleRate, sampleRate);
286        mFormat->setInt32(kKeyChannelCount, numChannels);
287
288        sp<ABuffer> codecSpecificData =
289            MakeAACCodecSpecificData(params.c_str());
290
291        mFormat->setData(
292                kKeyESDS, 0,
293                codecSpecificData->data(), codecSpecificData->size());
294    } else if (!strncmp(desc.c_str(), "AMR/", 4)) {
295        mFormat->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_AMR_NB);
296
297        int32_t sampleRate, numChannels;
298        ASessionDescription::ParseFormatDesc(
299                desc.c_str(), &sampleRate, &numChannels);
300
301        mFormat->setInt32(kKeySampleRate, sampleRate);
302        mFormat->setInt32(kKeyChannelCount, numChannels);
303
304        if (sampleRate != 8000 || numChannels != 1) {
305            mInitCheck = ERROR_UNSUPPORTED;
306        }
307    } else if (!strncmp(desc.c_str(), "AMR-WB/", 7)) {
308        mFormat->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_AMR_WB);
309
310        int32_t sampleRate, numChannels;
311        ASessionDescription::ParseFormatDesc(
312                desc.c_str(), &sampleRate, &numChannels);
313
314        mFormat->setInt32(kKeySampleRate, sampleRate);
315        mFormat->setInt32(kKeyChannelCount, numChannels);
316
317        if (sampleRate != 16000 || numChannels != 1) {
318            mInitCheck = ERROR_UNSUPPORTED;
319        }
320    } else {
321        mInitCheck = ERROR_UNSUPPORTED;
322    }
323}
324
325APacketSource::~APacketSource() {
326}
327
328status_t APacketSource::initCheck() const {
329    return mInitCheck;
330}
331
332status_t APacketSource::start(MetaData *params) {
333    mFirstAccessUnit = true;
334    mFirstAccessUnitNTP = 0;
335
336    return OK;
337}
338
339status_t APacketSource::stop() {
340    return OK;
341}
342
343sp<MetaData> APacketSource::getFormat() {
344    return mFormat;
345}
346
347status_t APacketSource::read(
348        MediaBuffer **out, const ReadOptions *) {
349    *out = NULL;
350
351    Mutex::Autolock autoLock(mLock);
352    while (mEOSResult == OK && mBuffers.empty()) {
353        mCondition.wait(mLock);
354    }
355
356    if (!mBuffers.empty()) {
357        const sp<ABuffer> buffer = *mBuffers.begin();
358
359        MediaBuffer *mediaBuffer = new MediaBuffer(buffer->size());
360
361        int64_t timeUs;
362        CHECK(buffer->meta()->findInt64("timeUs", &timeUs));
363
364        mediaBuffer->meta_data()->setInt64(kKeyTime, timeUs);
365
366        memcpy(mediaBuffer->data(), buffer->data(), buffer->size());
367        *out = mediaBuffer;
368
369        mBuffers.erase(mBuffers.begin());
370        return OK;
371    }
372
373    return mEOSResult;
374}
375
376void APacketSource::queueAccessUnit(const sp<ABuffer> &buffer) {
377    int32_t damaged;
378    if (buffer->meta()->findInt32("damaged", &damaged) && damaged) {
379        LOG(INFO) << "discarding damaged AU";
380        return;
381    }
382
383    uint64_t ntpTime;
384    CHECK(buffer->meta()->findInt64(
385                "ntp-time", (int64_t *)&ntpTime));
386
387    if (mFirstAccessUnit) {
388        mFirstAccessUnit = false;
389        mFirstAccessUnitNTP = ntpTime;
390    }
391
392    if (ntpTime > mFirstAccessUnitNTP) {
393        ntpTime -= mFirstAccessUnitNTP;
394    } else {
395        ntpTime = 0;
396    }
397
398    int64_t timeUs = (int64_t)(ntpTime * 1E6 / (1ll << 32));
399
400    buffer->meta()->setInt64("timeUs", timeUs);
401
402    Mutex::Autolock autoLock(mLock);
403    mBuffers.push_back(buffer);
404    mCondition.signal();
405}
406
407void APacketSource::signalEOS(status_t result) {
408    CHECK(result != OK);
409
410    Mutex::Autolock autoLock(mLock);
411    mEOSResult = result;
412    mCondition.signal();
413}
414
415int64_t APacketSource::getQueuedDuration(bool *eos) {
416    Mutex::Autolock autoLock(mLock);
417
418    *eos = (mEOSResult != OK);
419
420    if (mBuffers.empty()) {
421        return 0;
422    }
423
424    sp<ABuffer> buffer = *mBuffers.begin();
425
426    uint64_t ntpTime;
427    CHECK(buffer->meta()->findInt64(
428                "ntp-time", (int64_t *)&ntpTime));
429
430    int64_t firstTimeUs = (int64_t)(ntpTime * 1E6 / (1ll << 32));
431
432    buffer = *--mBuffers.end();
433
434    CHECK(buffer->meta()->findInt64(
435                "ntp-time", (int64_t *)&ntpTime));
436
437    int64_t lastTimeUs = (int64_t)(ntpTime * 1E6 / (1ll << 32));
438
439    return lastTimeUs - firstTimeUs;
440}
441
442}  // namespace android
443