APacketSource.cpp revision 85f12e9b9062402d6110df3f7099707912040edb
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 "avc_utils.h"
22
23#include <ctype.h>
24
25#include <media/stagefright/foundation/ABuffer.h>
26#include <media/stagefright/foundation/ADebug.h>
27#include <media/stagefright/foundation/AMessage.h>
28#include <media/stagefright/foundation/AString.h>
29#include <media/stagefright/foundation/base64.h>
30#include <media/stagefright/foundation/hexdump.h>
31#include <media/stagefright/MediaBuffer.h>
32#include <media/stagefright/MediaDefs.h>
33#include <media/stagefright/MetaData.h>
34#include <utils/Vector.h>
35
36namespace android {
37
38static bool GetAttribute(const char *s, const char *key, AString *value) {
39    value->clear();
40
41    size_t keyLen = strlen(key);
42
43    for (;;) {
44        while (isspace(*s)) {
45            ++s;
46        }
47
48        const char *colonPos = strchr(s, ';');
49
50        size_t len =
51            (colonPos == NULL) ? strlen(s) : colonPos - s;
52
53        if (len >= keyLen + 1 && s[keyLen] == '=' && !strncmp(s, key, keyLen)) {
54            value->setTo(&s[keyLen + 1], len - keyLen - 1);
55            return true;
56        }
57
58        if (colonPos == NULL) {
59            return false;
60        }
61
62        s = colonPos + 1;
63    }
64}
65
66static sp<ABuffer> decodeHex(const AString &s) {
67    if ((s.size() % 2) != 0) {
68        return NULL;
69    }
70
71    size_t outLen = s.size() / 2;
72    sp<ABuffer> buffer = new ABuffer(outLen);
73    uint8_t *out = buffer->data();
74
75    uint8_t accum = 0;
76    for (size_t i = 0; i < s.size(); ++i) {
77        char c = s.c_str()[i];
78        unsigned value;
79        if (c >= '0' && c <= '9') {
80            value = c - '0';
81        } else if (c >= 'a' && c <= 'f') {
82            value = c - 'a' + 10;
83        } else if (c >= 'A' && c <= 'F') {
84            value = c - 'A' + 10;
85        } else {
86            return NULL;
87        }
88
89        accum = (accum << 4) | value;
90
91        if (i & 1) {
92            *out++ = accum;
93
94            accum = 0;
95        }
96    }
97
98    return buffer;
99}
100
101static sp<ABuffer> MakeAVCCodecSpecificData(
102        const char *params, int32_t *width, int32_t *height) {
103    *width = 0;
104    *height = 0;
105
106    AString val;
107    if (!GetAttribute(params, "profile-level-id", &val)) {
108        return NULL;
109    }
110
111    sp<ABuffer> profileLevelID = decodeHex(val);
112    CHECK(profileLevelID != NULL);
113    CHECK_EQ(profileLevelID->size(), 3u);
114
115    Vector<sp<ABuffer> > paramSets;
116
117    size_t numSeqParameterSets = 0;
118    size_t totalSeqParameterSetSize = 0;
119    size_t numPicParameterSets = 0;
120    size_t totalPicParameterSetSize = 0;
121
122    if (!GetAttribute(params, "sprop-parameter-sets", &val)) {
123        return NULL;
124    }
125
126    size_t start = 0;
127    for (;;) {
128        ssize_t commaPos = val.find(",", start);
129        size_t end = (commaPos < 0) ? val.size() : commaPos;
130
131        AString nalString(val, start, end - start);
132        sp<ABuffer> nal = decodeBase64(nalString);
133        CHECK(nal != NULL);
134        CHECK_GT(nal->size(), 0u);
135        CHECK_LE(nal->size(), 65535u);
136
137        uint8_t nalType = nal->data()[0] & 0x1f;
138        if (numSeqParameterSets == 0) {
139            CHECK_EQ((unsigned)nalType, 7u);
140        } else if (numPicParameterSets > 0) {
141            CHECK_EQ((unsigned)nalType, 8u);
142        }
143        if (nalType == 7) {
144            ++numSeqParameterSets;
145            totalSeqParameterSetSize += nal->size();
146        } else  {
147            CHECK_EQ((unsigned)nalType, 8u);
148            ++numPicParameterSets;
149            totalPicParameterSetSize += nal->size();
150        }
151
152        paramSets.push(nal);
153
154        if (commaPos < 0) {
155            break;
156        }
157
158        start = commaPos + 1;
159    }
160
161    CHECK_LT(numSeqParameterSets, 32u);
162    CHECK_LE(numPicParameterSets, 255u);
163
164    size_t csdSize =
165        1 + 3 + 1 + 1
166        + 2 * numSeqParameterSets + totalSeqParameterSetSize
167        + 1 + 2 * numPicParameterSets + totalPicParameterSetSize;
168
169    sp<ABuffer> csd = new ABuffer(csdSize);
170    uint8_t *out = csd->data();
171
172    *out++ = 0x01;  // configurationVersion
173    memcpy(out, profileLevelID->data(), 3);
174    out += 3;
175    *out++ = (0x3f << 2) | 1;  // lengthSize == 2 bytes
176    *out++ = 0xe0 | numSeqParameterSets;
177
178    for (size_t i = 0; i < numSeqParameterSets; ++i) {
179        sp<ABuffer> nal = paramSets.editItemAt(i);
180
181        *out++ = nal->size() >> 8;
182        *out++ = nal->size() & 0xff;
183
184        memcpy(out, nal->data(), nal->size());
185
186        out += nal->size();
187
188        if (i == 0) {
189            FindAVCDimensions(nal, width, height);
190            LOG(INFO) << "dimensions " << *width << "x" << *height;
191        }
192    }
193
194    *out++ = numPicParameterSets;
195
196    for (size_t i = 0; i < numPicParameterSets; ++i) {
197        sp<ABuffer> nal = paramSets.editItemAt(i + numSeqParameterSets);
198
199        *out++ = nal->size() >> 8;
200        *out++ = nal->size() & 0xff;
201
202        memcpy(out, nal->data(), nal->size());
203
204        out += nal->size();
205    }
206
207    // hexdump(csd->data(), csd->size());
208
209    return csd;
210}
211
212sp<ABuffer> MakeAACCodecSpecificData(const char *params) {
213    AString val;
214    CHECK(GetAttribute(params, "config", &val));
215
216    sp<ABuffer> config = decodeHex(val);
217    CHECK(config != NULL);
218    CHECK_GE(config->size(), 4u);
219
220    const uint8_t *data = config->data();
221    uint32_t x = data[0] << 24 | data[1] << 16 | data[2] << 8 | data[3];
222    x = (x >> 1) & 0xffff;
223
224    static const uint8_t kStaticESDS[] = {
225        0x03, 22,
226        0x00, 0x00,     // ES_ID
227        0x00,           // streamDependenceFlag, URL_Flag, OCRstreamFlag
228
229        0x04, 17,
230        0x40,                       // Audio ISO/IEC 14496-3
231        0x00, 0x00, 0x00, 0x00,
232        0x00, 0x00, 0x00, 0x00,
233        0x00, 0x00, 0x00, 0x00,
234
235        0x05, 2,
236        // AudioSpecificInfo follows
237    };
238
239    sp<ABuffer> csd = new ABuffer(sizeof(kStaticESDS) + 2);
240    memcpy(csd->data(), kStaticESDS, sizeof(kStaticESDS));
241    csd->data()[sizeof(kStaticESDS)] = (x >> 8) & 0xff;
242    csd->data()[sizeof(kStaticESDS) + 1] = x & 0xff;
243
244    // hexdump(csd->data(), csd->size());
245
246    return csd;
247}
248
249APacketSource::APacketSource(
250        const sp<ASessionDescription> &sessionDesc, size_t index)
251    : mInitCheck(NO_INIT),
252      mFormat(new MetaData),
253      mEOSResult(OK),
254      mFirstAccessUnit(true),
255      mFirstAccessUnitNTP(0) {
256    unsigned long PT;
257    AString desc;
258    AString params;
259    sessionDesc->getFormatType(index, &PT, &desc, &params);
260
261    int64_t durationUs;
262    if (sessionDesc->getDurationUs(&durationUs)) {
263        mFormat->setInt64(kKeyDuration, durationUs);
264    } else {
265        mFormat->setInt64(kKeyDuration, 60 * 60 * 1000000ll);
266    }
267
268    mInitCheck = OK;
269    if (!strncmp(desc.c_str(), "H264/", 5)) {
270        mFormat->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_AVC);
271
272        int32_t width, height;
273        if (!sessionDesc->getDimensions(index, PT, &width, &height)) {
274            width = -1;
275            height = -1;
276        }
277
278        int32_t encWidth, encHeight;
279        sp<ABuffer> codecSpecificData =
280            MakeAVCCodecSpecificData(params.c_str(), &encWidth, &encHeight);
281
282        if (codecSpecificData != NULL) {
283            if (width < 0) {
284                // If no explicit width/height given in the sdp, use the dimensions
285                // extracted from the first sequence parameter set.
286                width = encWidth;
287                height = encHeight;
288            }
289
290            mFormat->setData(
291                    kKeyAVCC, 0,
292                    codecSpecificData->data(), codecSpecificData->size());
293        } else if (width < 0) {
294            mInitCheck = ERROR_UNSUPPORTED;
295            return;
296        }
297
298        mFormat->setInt32(kKeyWidth, width);
299        mFormat->setInt32(kKeyHeight, height);
300    } else if (!strncmp(desc.c_str(), "H263-2000/", 10)
301            || !strncmp(desc.c_str(), "H263-1998/", 10)) {
302        mFormat->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_H263);
303
304        int32_t width, height;
305        if (!sessionDesc->getDimensions(index, PT, &width, &height)) {
306            mInitCheck = ERROR_UNSUPPORTED;
307            return;
308        }
309
310        mFormat->setInt32(kKeyWidth, width);
311        mFormat->setInt32(kKeyHeight, height);
312    } else if (!strncmp(desc.c_str(), "MP4A-LATM/", 10)) {
313        mFormat->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_AAC);
314
315        int32_t sampleRate, numChannels;
316        ASessionDescription::ParseFormatDesc(
317                desc.c_str(), &sampleRate, &numChannels);
318
319        mFormat->setInt32(kKeySampleRate, sampleRate);
320        mFormat->setInt32(kKeyChannelCount, numChannels);
321
322        sp<ABuffer> codecSpecificData =
323            MakeAACCodecSpecificData(params.c_str());
324
325        mFormat->setData(
326                kKeyESDS, 0,
327                codecSpecificData->data(), codecSpecificData->size());
328    } else if (!strncmp(desc.c_str(), "AMR/", 4)) {
329        mFormat->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_AMR_NB);
330
331        int32_t sampleRate, numChannels;
332        ASessionDescription::ParseFormatDesc(
333                desc.c_str(), &sampleRate, &numChannels);
334
335        mFormat->setInt32(kKeySampleRate, sampleRate);
336        mFormat->setInt32(kKeyChannelCount, numChannels);
337
338        if (sampleRate != 8000 || numChannels != 1) {
339            mInitCheck = ERROR_UNSUPPORTED;
340        }
341    } else if (!strncmp(desc.c_str(), "AMR-WB/", 7)) {
342        mFormat->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_AMR_WB);
343
344        int32_t sampleRate, numChannels;
345        ASessionDescription::ParseFormatDesc(
346                desc.c_str(), &sampleRate, &numChannels);
347
348        mFormat->setInt32(kKeySampleRate, sampleRate);
349        mFormat->setInt32(kKeyChannelCount, numChannels);
350
351        if (sampleRate != 16000 || numChannels != 1) {
352            mInitCheck = ERROR_UNSUPPORTED;
353        }
354    } else {
355        mInitCheck = ERROR_UNSUPPORTED;
356    }
357}
358
359APacketSource::~APacketSource() {
360}
361
362status_t APacketSource::initCheck() const {
363    return mInitCheck;
364}
365
366status_t APacketSource::start(MetaData *params) {
367    mFirstAccessUnit = true;
368    mFirstAccessUnitNTP = 0;
369
370    return OK;
371}
372
373status_t APacketSource::stop() {
374    return OK;
375}
376
377sp<MetaData> APacketSource::getFormat() {
378    return mFormat;
379}
380
381status_t APacketSource::read(
382        MediaBuffer **out, const ReadOptions *) {
383    *out = NULL;
384
385    Mutex::Autolock autoLock(mLock);
386    while (mEOSResult == OK && mBuffers.empty()) {
387        mCondition.wait(mLock);
388    }
389
390    if (!mBuffers.empty()) {
391        const sp<ABuffer> buffer = *mBuffers.begin();
392
393        MediaBuffer *mediaBuffer = new MediaBuffer(buffer->size());
394
395        int64_t timeUs;
396        CHECK(buffer->meta()->findInt64("timeUs", &timeUs));
397
398        mediaBuffer->meta_data()->setInt64(kKeyTime, timeUs);
399
400        memcpy(mediaBuffer->data(), buffer->data(), buffer->size());
401        *out = mediaBuffer;
402
403        mBuffers.erase(mBuffers.begin());
404        return OK;
405    }
406
407    return mEOSResult;
408}
409
410void APacketSource::queueAccessUnit(const sp<ABuffer> &buffer) {
411    int32_t damaged;
412    if (buffer->meta()->findInt32("damaged", &damaged) && damaged) {
413        LOG(VERBOSE) << "discarding damaged AU";
414        return;
415    }
416
417    uint64_t ntpTime;
418    CHECK(buffer->meta()->findInt64(
419                "ntp-time", (int64_t *)&ntpTime));
420
421    if (mFirstAccessUnit) {
422        mFirstAccessUnit = false;
423        mFirstAccessUnitNTP = ntpTime;
424    }
425
426    if (ntpTime > mFirstAccessUnitNTP) {
427        ntpTime -= mFirstAccessUnitNTP;
428    } else {
429        ntpTime = 0;
430    }
431
432    int64_t timeUs = (int64_t)(ntpTime * 1E6 / (1ll << 32));
433
434    buffer->meta()->setInt64("timeUs", timeUs);
435
436    Mutex::Autolock autoLock(mLock);
437    mBuffers.push_back(buffer);
438    mCondition.signal();
439}
440
441void APacketSource::signalEOS(status_t result) {
442    CHECK(result != OK);
443
444    Mutex::Autolock autoLock(mLock);
445    mEOSResult = result;
446    mCondition.signal();
447}
448
449int64_t APacketSource::getQueuedDuration(bool *eos) {
450    Mutex::Autolock autoLock(mLock);
451
452    *eos = (mEOSResult != OK);
453
454    if (mBuffers.empty()) {
455        return 0;
456    }
457
458    sp<ABuffer> buffer = *mBuffers.begin();
459
460    uint64_t ntpTime;
461    CHECK(buffer->meta()->findInt64(
462                "ntp-time", (int64_t *)&ntpTime));
463
464    int64_t firstTimeUs = (int64_t)(ntpTime * 1E6 / (1ll << 32));
465
466    buffer = *--mBuffers.end();
467
468    CHECK(buffer->meta()->findInt64(
469                "ntp-time", (int64_t *)&ntpTime));
470
471    int64_t lastTimeUs = (int64_t)(ntpTime * 1E6 / (1ll << 32));
472
473    return lastTimeUs - firstTimeUs;
474}
475
476}  // namespace android
477