AMPEG4ElementaryAssembler.cpp revision f6d0c1fd6d9e697bb3a891fae14c7e9d4b685de6
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 "AMPEG4ElementaryAssembler"
19#include <utils/Log.h>
20
21#include "AMPEG4ElementaryAssembler.h"
22
23#include "ARTPSource.h"
24#include "ASessionDescription.h"
25
26#include <media/stagefright/foundation/ABitReader.h>
27#include <media/stagefright/foundation/ABuffer.h>
28#include <media/stagefright/foundation/ADebug.h>
29#include <media/stagefright/foundation/AMessage.h>
30#include <media/stagefright/foundation/hexdump.h>
31#include <media/stagefright/Utils.h>
32
33#include <ctype.h>
34#include <stdint.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] == '='
54                && !strncasecmp(s, key, keyLen)) {
55            value->setTo(&s[keyLen + 1], len - keyLen - 1);
56            return true;
57        }
58
59        if (colonPos == NULL) {
60            return false;
61        }
62
63        s = colonPos + 1;
64    }
65}
66
67static bool GetIntegerAttribute(
68        const char *s, const char *key, unsigned *x) {
69    *x = 0;
70
71    AString val;
72    if (!GetAttribute(s, key, &val)) {
73        return false;
74    }
75
76    s = val.c_str();
77    char *end;
78    unsigned y = strtoul(s, &end, 10);
79
80    if (end == s || *end != '\0') {
81        return false;
82    }
83
84    *x = y;
85
86    return true;
87}
88
89static bool GetSampleRateIndex(int32_t sampleRate, size_t *tableIndex) {
90    static const int32_t kSampleRateTable[] = {
91        96000, 88200, 64000, 48000, 44100, 32000,
92        24000, 22050, 16000, 12000, 11025, 8000
93    };
94    const size_t kNumSampleRates =
95        sizeof(kSampleRateTable) / sizeof(kSampleRateTable[0]);
96
97    *tableIndex = 0;
98    for (size_t index = 0; index < kNumSampleRates; ++index) {
99        if (sampleRate == kSampleRateTable[index]) {
100            *tableIndex = index;
101            return true;
102        }
103    }
104
105    return false;
106}
107
108// static
109AMPEG4ElementaryAssembler::AMPEG4ElementaryAssembler(
110        const sp<AMessage> &notify, const AString &desc, const AString &params)
111    : mNotifyMsg(notify),
112      mIsGeneric(false),
113      mParams(params),
114      mSizeLength(0),
115      mIndexLength(0),
116      mIndexDeltaLength(0),
117      mCTSDeltaLength(0),
118      mDTSDeltaLength(0),
119      mRandomAccessIndication(false),
120      mStreamStateIndication(0),
121      mAuxiliaryDataSizeLength(0),
122      mHasAUHeader(false),
123      mChannelConfig(0),
124      mSampleRateIndex(0),
125      mAccessUnitRTPTime(0),
126      mNextExpectedSeqNoValid(false),
127      mNextExpectedSeqNo(0),
128      mAccessUnitDamaged(false) {
129    mIsGeneric = !strncasecmp(desc.c_str(),"mpeg4-generic/", 14);
130
131    if (mIsGeneric) {
132        AString value;
133        CHECK(GetAttribute(params.c_str(), "mode", &value));
134
135        if (!GetIntegerAttribute(params.c_str(), "sizeLength", &mSizeLength)) {
136            mSizeLength = 0;
137        }
138
139        if (!GetIntegerAttribute(
140                    params.c_str(), "indexLength", &mIndexLength)) {
141            mIndexLength = 0;
142        }
143
144        if (!GetIntegerAttribute(
145                    params.c_str(), "indexDeltaLength", &mIndexDeltaLength)) {
146            mIndexDeltaLength = 0;
147        }
148
149        if (!GetIntegerAttribute(
150                    params.c_str(), "CTSDeltaLength", &mCTSDeltaLength)) {
151            mCTSDeltaLength = 0;
152        }
153
154        if (!GetIntegerAttribute(
155                    params.c_str(), "DTSDeltaLength", &mDTSDeltaLength)) {
156            mDTSDeltaLength = 0;
157        }
158
159        unsigned x;
160        if (!GetIntegerAttribute(
161                    params.c_str(), "randomAccessIndication", &x)) {
162            mRandomAccessIndication = false;
163        } else {
164            CHECK(x == 0 || x == 1);
165            mRandomAccessIndication = (x != 0);
166        }
167
168        if (!GetIntegerAttribute(
169                    params.c_str(), "streamStateIndication",
170                    &mStreamStateIndication)) {
171            mStreamStateIndication = 0;
172        }
173
174        if (!GetIntegerAttribute(
175                    params.c_str(), "auxiliaryDataSizeLength",
176                    &mAuxiliaryDataSizeLength)) {
177            mAuxiliaryDataSizeLength = 0;
178        }
179
180        mHasAUHeader =
181            mSizeLength > 0
182            || mIndexLength > 0
183            || mIndexDeltaLength > 0
184            || mCTSDeltaLength > 0
185            || mDTSDeltaLength > 0
186            || mRandomAccessIndication
187            || mStreamStateIndication > 0;
188
189        int32_t sampleRate, numChannels;
190        ASessionDescription::ParseFormatDesc(
191                desc.c_str(), &sampleRate, &numChannels);
192
193        mChannelConfig = numChannels;
194        CHECK(GetSampleRateIndex(sampleRate, &mSampleRateIndex));
195    }
196}
197
198AMPEG4ElementaryAssembler::~AMPEG4ElementaryAssembler() {
199}
200
201struct AUHeader {
202    unsigned mSize;
203    unsigned mSerial;
204};
205
206ARTPAssembler::AssemblyStatus AMPEG4ElementaryAssembler::addPacket(
207        const sp<ARTPSource> &source) {
208    List<sp<ABuffer> > *queue = source->queue();
209
210    if (queue->empty()) {
211        return NOT_ENOUGH_DATA;
212    }
213
214    if (mNextExpectedSeqNoValid) {
215        List<sp<ABuffer> >::iterator it = queue->begin();
216        while (it != queue->end()) {
217            if ((uint32_t)(*it)->int32Data() >= mNextExpectedSeqNo) {
218                break;
219            }
220
221            it = queue->erase(it);
222        }
223
224        if (queue->empty()) {
225            return NOT_ENOUGH_DATA;
226        }
227    }
228
229    sp<ABuffer> buffer = *queue->begin();
230
231    if (!mNextExpectedSeqNoValid) {
232        mNextExpectedSeqNoValid = true;
233        mNextExpectedSeqNo = (uint32_t)buffer->int32Data();
234    } else if ((uint32_t)buffer->int32Data() != mNextExpectedSeqNo) {
235        ALOGV("Not the sequence number I expected");
236
237        return WRONG_SEQUENCE_NUMBER;
238    }
239
240    uint32_t rtpTime;
241    CHECK(buffer->meta()->findInt32("rtp-time", (int32_t *)&rtpTime));
242
243    if (mPackets.size() > 0 && rtpTime != mAccessUnitRTPTime) {
244        submitAccessUnit();
245    }
246    mAccessUnitRTPTime = rtpTime;
247
248    if (!mIsGeneric) {
249        mPackets.push_back(buffer);
250    } else {
251        // hexdump(buffer->data(), buffer->size());
252
253        CHECK_GE(buffer->size(), 2u);
254        unsigned AU_headers_length = U16_AT(buffer->data());  // in bits
255
256        CHECK_GE(buffer->size(), 2 + (AU_headers_length + 7) / 8);
257
258        List<AUHeader> headers;
259
260        ABitReader bits(buffer->data() + 2, buffer->size() - 2);
261        unsigned numBitsLeft = AU_headers_length;
262
263        unsigned AU_serial = 0;
264        for (;;) {
265            if (numBitsLeft < mSizeLength) { break; }
266
267            unsigned AU_size = bits.getBits(mSizeLength);
268            numBitsLeft -= mSizeLength;
269
270            size_t n = headers.empty() ? mIndexLength : mIndexDeltaLength;
271            if (numBitsLeft < n) { break; }
272
273            unsigned AU_index = bits.getBits(n);
274            numBitsLeft -= n;
275
276            if (headers.empty()) {
277                AU_serial = AU_index;
278            } else {
279                AU_serial += 1 + AU_index;
280            }
281
282            if (mCTSDeltaLength > 0) {
283                if (numBitsLeft < 1) {
284                    break;
285                }
286                --numBitsLeft;
287                if (bits.getBits(1)) {
288                    if (numBitsLeft < mCTSDeltaLength) {
289                        break;
290                    }
291                    bits.skipBits(mCTSDeltaLength);
292                    numBitsLeft -= mCTSDeltaLength;
293                }
294            }
295
296            if (mDTSDeltaLength > 0) {
297                if (numBitsLeft < 1) {
298                    break;
299                }
300                --numBitsLeft;
301                if (bits.getBits(1)) {
302                    if (numBitsLeft < mDTSDeltaLength) {
303                        break;
304                    }
305                    bits.skipBits(mDTSDeltaLength);
306                    numBitsLeft -= mDTSDeltaLength;
307                }
308            }
309
310            if (mRandomAccessIndication) {
311                if (numBitsLeft < 1) {
312                    break;
313                }
314                bits.skipBits(1);
315                --numBitsLeft;
316            }
317
318            if (mStreamStateIndication > 0) {
319                if (numBitsLeft < mStreamStateIndication) {
320                    break;
321                }
322                bits.skipBits(mStreamStateIndication);
323            }
324
325            AUHeader header;
326            header.mSize = AU_size;
327            header.mSerial = AU_serial;
328            headers.push_back(header);
329        }
330
331        size_t offset = 2 + (AU_headers_length + 7) / 8;
332
333        if (mAuxiliaryDataSizeLength > 0) {
334            ABitReader bits(buffer->data() + offset, buffer->size() - offset);
335
336            unsigned auxSize = bits.getBits(mAuxiliaryDataSizeLength);
337
338            offset += (mAuxiliaryDataSizeLength + auxSize + 7) / 8;
339        }
340
341        for (List<AUHeader>::iterator it = headers.begin();
342             it != headers.end(); ++it) {
343            const AUHeader &header = *it;
344
345            CHECK_LE(offset + header.mSize, buffer->size());
346
347            sp<ABuffer> accessUnit = new ABuffer(header.mSize);
348            memcpy(accessUnit->data(), buffer->data() + offset, header.mSize);
349
350            offset += header.mSize;
351
352            CopyTimes(accessUnit, buffer);
353            mPackets.push_back(accessUnit);
354        }
355
356        CHECK_EQ(offset, buffer->size());
357    }
358
359    queue->erase(queue->begin());
360    ++mNextExpectedSeqNo;
361
362    return OK;
363}
364
365void AMPEG4ElementaryAssembler::submitAccessUnit() {
366    CHECK(!mPackets.empty());
367
368    ALOGV("Access unit complete (%zu nal units)", mPackets.size());
369
370    sp<ABuffer> accessUnit;
371
372    if (mIsGeneric) {
373        accessUnit = MakeADTSCompoundFromAACFrames(
374                OMX_AUDIO_AACObjectLC - 1,
375                mSampleRateIndex,
376                mChannelConfig,
377                mPackets);
378    } else {
379        accessUnit = MakeCompoundFromPackets(mPackets);
380    }
381
382#if 0
383    printf(mAccessUnitDamaged ? "X" : ".");
384    fflush(stdout);
385#endif
386
387    if (mAccessUnitDamaged) {
388        accessUnit->meta()->setInt32("damaged", true);
389    }
390
391    mPackets.clear();
392    mAccessUnitDamaged = false;
393
394    sp<AMessage> msg = mNotifyMsg->dup();
395    msg->setBuffer("access-unit", accessUnit);
396    msg->post();
397}
398
399ARTPAssembler::AssemblyStatus AMPEG4ElementaryAssembler::assembleMore(
400        const sp<ARTPSource> &source) {
401    AssemblyStatus status = addPacket(source);
402    if (status == MALFORMED_PACKET) {
403        mAccessUnitDamaged = true;
404    }
405    return status;
406}
407
408void AMPEG4ElementaryAssembler::packetLost() {
409    CHECK(mNextExpectedSeqNoValid);
410    ALOGV("packetLost (expected %d)", mNextExpectedSeqNo);
411
412    ++mNextExpectedSeqNo;
413
414    mAccessUnitDamaged = true;
415}
416
417void AMPEG4ElementaryAssembler::onByeReceived() {
418    sp<AMessage> msg = mNotifyMsg->dup();
419    msg->setInt32("eos", true);
420    msg->post();
421}
422
423}  // namespace android
424