APacketSource.cpp revision c9e894872c298b25fe9d74e68aa1e7287a541ac3
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/ABitReader.h>
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/foundation/AString.h>
30#include <media/stagefright/foundation/base64.h>
31#include <media/stagefright/foundation/hexdump.h>
32#include <media/stagefright/MediaBuffer.h>
33#include <media/stagefright/MediaDefs.h>
34#include <media/stagefright/MetaData.h>
35#include <utils/Vector.h>
36
37namespace android {
38
39static bool GetAttribute(const char *s, const char *key, AString *value) {
40    value->clear();
41
42    size_t keyLen = strlen(key);
43
44    for (;;) {
45        while (isspace(*s)) {
46            ++s;
47        }
48
49        const char *colonPos = strchr(s, ';');
50
51        size_t len =
52            (colonPos == NULL) ? strlen(s) : colonPos - s;
53
54        if (len >= keyLen + 1 && s[keyLen] == '=' && !strncmp(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 sp<ABuffer> decodeHex(const AString &s) {
68    if ((s.size() % 2) != 0) {
69        return NULL;
70    }
71
72    size_t outLen = s.size() / 2;
73    sp<ABuffer> buffer = new ABuffer(outLen);
74    uint8_t *out = buffer->data();
75
76    uint8_t accum = 0;
77    for (size_t i = 0; i < s.size(); ++i) {
78        char c = s.c_str()[i];
79        unsigned value;
80        if (c >= '0' && c <= '9') {
81            value = c - '0';
82        } else if (c >= 'a' && c <= 'f') {
83            value = c - 'a' + 10;
84        } else if (c >= 'A' && c <= 'F') {
85            value = c - 'A' + 10;
86        } else {
87            return NULL;
88        }
89
90        accum = (accum << 4) | value;
91
92        if (i & 1) {
93            *out++ = accum;
94
95            accum = 0;
96        }
97    }
98
99    return buffer;
100}
101
102static sp<ABuffer> MakeAVCCodecSpecificData(
103        const char *params, int32_t *width, int32_t *height) {
104    *width = 0;
105    *height = 0;
106
107    AString val;
108    if (!GetAttribute(params, "profile-level-id", &val)) {
109        return NULL;
110    }
111
112    sp<ABuffer> profileLevelID = decodeHex(val);
113    CHECK(profileLevelID != NULL);
114    CHECK_EQ(profileLevelID->size(), 3u);
115
116    Vector<sp<ABuffer> > paramSets;
117
118    size_t numSeqParameterSets = 0;
119    size_t totalSeqParameterSetSize = 0;
120    size_t numPicParameterSets = 0;
121    size_t totalPicParameterSetSize = 0;
122
123    if (!GetAttribute(params, "sprop-parameter-sets", &val)) {
124        return NULL;
125    }
126
127    size_t start = 0;
128    for (;;) {
129        ssize_t commaPos = val.find(",", start);
130        size_t end = (commaPos < 0) ? val.size() : commaPos;
131
132        AString nalString(val, start, end - start);
133        sp<ABuffer> nal = decodeBase64(nalString);
134        CHECK(nal != NULL);
135        CHECK_GT(nal->size(), 0u);
136        CHECK_LE(nal->size(), 65535u);
137
138        uint8_t nalType = nal->data()[0] & 0x1f;
139        if (numSeqParameterSets == 0) {
140            CHECK_EQ((unsigned)nalType, 7u);
141        } else if (numPicParameterSets > 0) {
142            CHECK_EQ((unsigned)nalType, 8u);
143        }
144        if (nalType == 7) {
145            ++numSeqParameterSets;
146            totalSeqParameterSetSize += nal->size();
147        } else  {
148            CHECK_EQ((unsigned)nalType, 8u);
149            ++numPicParameterSets;
150            totalPicParameterSetSize += nal->size();
151        }
152
153        paramSets.push(nal);
154
155        if (commaPos < 0) {
156            break;
157        }
158
159        start = commaPos + 1;
160    }
161
162    CHECK_LT(numSeqParameterSets, 32u);
163    CHECK_LE(numPicParameterSets, 255u);
164
165    size_t csdSize =
166        1 + 3 + 1 + 1
167        + 2 * numSeqParameterSets + totalSeqParameterSetSize
168        + 1 + 2 * numPicParameterSets + totalPicParameterSetSize;
169
170    sp<ABuffer> csd = new ABuffer(csdSize);
171    uint8_t *out = csd->data();
172
173    *out++ = 0x01;  // configurationVersion
174    memcpy(out, profileLevelID->data(), 3);
175    out += 3;
176    *out++ = (0x3f << 2) | 1;  // lengthSize == 2 bytes
177    *out++ = 0xe0 | numSeqParameterSets;
178
179    for (size_t i = 0; i < numSeqParameterSets; ++i) {
180        sp<ABuffer> nal = paramSets.editItemAt(i);
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        if (i == 0) {
190            FindAVCDimensions(nal, width, height);
191            LOG(INFO) << "dimensions " << *width << "x" << *height;
192        }
193    }
194
195    *out++ = numPicParameterSets;
196
197    for (size_t i = 0; i < numPicParameterSets; ++i) {
198        sp<ABuffer> nal = paramSets.editItemAt(i + numSeqParameterSets);
199
200        *out++ = nal->size() >> 8;
201        *out++ = nal->size() & 0xff;
202
203        memcpy(out, nal->data(), nal->size());
204
205        out += nal->size();
206    }
207
208    // hexdump(csd->data(), csd->size());
209
210    return csd;
211}
212
213sp<ABuffer> MakeAACCodecSpecificData(const char *params) {
214    AString val;
215    CHECK(GetAttribute(params, "config", &val));
216
217    sp<ABuffer> config = decodeHex(val);
218    CHECK(config != NULL);
219    CHECK_GE(config->size(), 4u);
220
221    const uint8_t *data = config->data();
222    uint32_t x = data[0] << 24 | data[1] << 16 | data[2] << 8 | data[3];
223    x = (x >> 1) & 0xffff;
224
225    static const uint8_t kStaticESDS[] = {
226        0x03, 22,
227        0x00, 0x00,     // ES_ID
228        0x00,           // streamDependenceFlag, URL_Flag, OCRstreamFlag
229
230        0x04, 17,
231        0x40,                       // Audio ISO/IEC 14496-3
232        0x00, 0x00, 0x00, 0x00,
233        0x00, 0x00, 0x00, 0x00,
234        0x00, 0x00, 0x00, 0x00,
235
236        0x05, 2,
237        // AudioSpecificInfo follows
238    };
239
240    sp<ABuffer> csd = new ABuffer(sizeof(kStaticESDS) + 2);
241    memcpy(csd->data(), kStaticESDS, sizeof(kStaticESDS));
242    csd->data()[sizeof(kStaticESDS)] = (x >> 8) & 0xff;
243    csd->data()[sizeof(kStaticESDS) + 1] = x & 0xff;
244
245    // hexdump(csd->data(), csd->size());
246
247    return csd;
248}
249
250// From mpeg4-generic configuration data.
251sp<ABuffer> MakeAACCodecSpecificData2(const char *params) {
252    AString val;
253    unsigned long objectType;
254    if (GetAttribute(params, "objectType", &val)) {
255        const char *s = val.c_str();
256        char *end;
257        objectType = strtoul(s, &end, 10);
258        CHECK(end > s && *end == '\0');
259    } else {
260        objectType = 0x40;  // Audio ISO/IEC 14496-3
261    }
262
263    CHECK(GetAttribute(params, "config", &val));
264
265    sp<ABuffer> config = decodeHex(val);
266    CHECK(config != NULL);
267
268    // Make sure size fits into a single byte and doesn't have to
269    // be encoded.
270    CHECK_LT(20 + config->size(), 128u);
271
272    const uint8_t *data = config->data();
273
274    static const uint8_t kStaticESDS[] = {
275        0x03, 22,
276        0x00, 0x00,     // ES_ID
277        0x00,           // streamDependenceFlag, URL_Flag, OCRstreamFlag
278
279        0x04, 17,
280        0x40,                       // Audio ISO/IEC 14496-3
281        0x00, 0x00, 0x00, 0x00,
282        0x00, 0x00, 0x00, 0x00,
283        0x00, 0x00, 0x00, 0x00,
284
285        0x05, 2,
286        // AudioSpecificInfo follows
287    };
288
289    sp<ABuffer> csd = new ABuffer(sizeof(kStaticESDS) + config->size());
290    uint8_t *dst = csd->data();
291    *dst++ = 0x03;
292    *dst++ = 20 + config->size();
293    *dst++ = 0x00;  // ES_ID
294    *dst++ = 0x00;
295    *dst++ = 0x00;  // streamDependenceFlag, URL_Flag, OCRstreamFlag
296    *dst++ = 0x04;
297    *dst++ = 15 + config->size();
298    *dst++ = objectType;
299    for (int i = 0; i < 12; ++i) { *dst++ = 0x00; }
300    *dst++ = 0x05;
301    *dst++ = config->size();
302    memcpy(dst, config->data(), config->size());
303
304    // hexdump(csd->data(), csd->size());
305
306    return csd;
307}
308
309static size_t GetSizeWidth(size_t x) {
310    size_t n = 1;
311    while (x > 127) {
312        ++n;
313        x >>= 7;
314    }
315    return n;
316}
317
318static uint8_t *EncodeSize(uint8_t *dst, size_t x) {
319    while (x > 127) {
320        *dst++ = (x & 0x7f) | 0x80;
321        x >>= 7;
322    }
323    *dst++ = x;
324    return dst;
325}
326
327static bool ExtractDimensionsFromVOLHeader(
328        const sp<ABuffer> &config, int32_t *width, int32_t *height) {
329    *width = 0;
330    *height = 0;
331
332    const uint8_t *ptr = config->data();
333    size_t offset = 0;
334    bool foundVOL = false;
335    while (offset + 3 < config->size()) {
336        if (memcmp("\x00\x00\x01", &ptr[offset], 3)
337                || (ptr[offset + 3] & 0xf0) != 0x20) {
338            ++offset;
339            continue;
340        }
341
342        foundVOL = true;
343        break;
344    }
345
346    if (!foundVOL) {
347        return false;
348    }
349
350    ABitReader br(&ptr[offset + 4], config->size() - offset - 4);
351    br.skipBits(1);  // random_accessible_vol
352    unsigned video_object_type_indication = br.getBits(8);
353
354    CHECK_NE(video_object_type_indication,
355             0x21u /* Fine Granularity Scalable */);
356
357    unsigned video_object_layer_verid;
358    unsigned video_object_layer_priority;
359    if (br.getBits(1)) {
360        video_object_layer_verid = br.getBits(4);
361        video_object_layer_priority = br.getBits(3);
362    }
363    unsigned aspect_ratio_info = br.getBits(4);
364    if (aspect_ratio_info == 0x0f /* extended PAR */) {
365        br.skipBits(8);  // par_width
366        br.skipBits(8);  // par_height
367    }
368    if (br.getBits(1)) {  // vol_control_parameters
369        br.skipBits(2);  // chroma_format
370        br.skipBits(1);  // low_delay
371        if (br.getBits(1)) {  // vbv_parameters
372            TRESPASS();
373        }
374    }
375    unsigned video_object_layer_shape = br.getBits(2);
376    CHECK_EQ(video_object_layer_shape, 0x00u /* rectangular */);
377
378    CHECK(br.getBits(1));  // marker_bit
379    unsigned vop_time_increment_resolution = br.getBits(16);
380    CHECK(br.getBits(1));  // marker_bit
381
382    if (br.getBits(1)) {  // fixed_vop_rate
383        // range [0..vop_time_increment_resolution)
384
385        // vop_time_increment_resolution
386        // 2 => 0..1, 1 bit
387        // 3 => 0..2, 2 bits
388        // 4 => 0..3, 2 bits
389        // 5 => 0..4, 3 bits
390        // ...
391
392        CHECK_GT(vop_time_increment_resolution, 0u);
393        --vop_time_increment_resolution;
394
395        unsigned numBits = 0;
396        while (vop_time_increment_resolution > 0) {
397            ++numBits;
398            vop_time_increment_resolution >>= 1;
399        }
400
401        br.skipBits(numBits);  // fixed_vop_time_increment
402    }
403
404    CHECK(br.getBits(1));  // marker_bit
405    unsigned video_object_layer_width = br.getBits(13);
406    CHECK(br.getBits(1));  // marker_bit
407    unsigned video_object_layer_height = br.getBits(13);
408    CHECK(br.getBits(1));  // marker_bit
409
410    unsigned interlaced = br.getBits(1);
411
412    *width = video_object_layer_width;
413    *height = video_object_layer_height;
414
415    LOG(INFO) << "VOL dimensions = " << *width << "x" << *height;
416
417    return true;
418}
419
420sp<ABuffer> MakeMPEG4VideoCodecSpecificData(
421        const char *params, int32_t *width, int32_t *height) {
422    *width = 0;
423    *height = 0;
424
425    AString val;
426    CHECK(GetAttribute(params, "config", &val));
427
428    sp<ABuffer> config = decodeHex(val);
429    CHECK(config != NULL);
430
431    if (!ExtractDimensionsFromVOLHeader(config, width, height)) {
432        return NULL;
433    }
434
435    size_t len1 = config->size() + GetSizeWidth(config->size()) + 1;
436    size_t len2 = len1 + GetSizeWidth(len1) + 1 + 13;
437    size_t len3 = len2 + GetSizeWidth(len2) + 1 + 3;
438
439    sp<ABuffer> csd = new ABuffer(len3);
440    uint8_t *dst = csd->data();
441    *dst++ = 0x03;
442    dst = EncodeSize(dst, len2 + 3);
443    *dst++ = 0x00;  // ES_ID
444    *dst++ = 0x00;
445    *dst++ = 0x00;  // streamDependenceFlag, URL_Flag, OCRstreamFlag
446
447    *dst++ = 0x04;
448    dst = EncodeSize(dst, len1 + 13);
449    *dst++ = 0x01;  // Video ISO/IEC 14496-2 Simple Profile
450    for (size_t i = 0; i < 12; ++i) {
451        *dst++ = 0x00;
452    }
453
454    *dst++ = 0x05;
455    dst = EncodeSize(dst, config->size());
456    memcpy(dst, config->data(), config->size());
457    dst += config->size();
458
459    // hexdump(csd->data(), csd->size());
460
461    return csd;
462}
463
464static bool GetClockRate(const AString &desc, uint32_t *clockRate) {
465    ssize_t slashPos = desc.find("/");
466    if (slashPos < 0) {
467        return false;
468    }
469
470    const char *s = desc.c_str() + slashPos + 1;
471
472    char *end;
473    unsigned long x = strtoul(s, &end, 10);
474
475    if (end == s || (*end != '\0' && *end != '/')) {
476        return false;
477    }
478
479    *clockRate = x;
480
481    return true;
482}
483
484APacketSource::APacketSource(
485        const sp<ASessionDescription> &sessionDesc, size_t index)
486    : mInitCheck(NO_INIT),
487      mFormat(new MetaData),
488      mEOSResult(OK),
489      mRTPTimeBase(0),
490      mNormalPlayTimeBaseUs(0),
491      mLastNormalPlayTimeUs(0) {
492    unsigned long PT;
493    AString desc;
494    AString params;
495    sessionDesc->getFormatType(index, &PT, &desc, &params);
496
497    CHECK(GetClockRate(desc, &mClockRate));
498
499    int64_t durationUs;
500    if (sessionDesc->getDurationUs(&durationUs)) {
501        mFormat->setInt64(kKeyDuration, durationUs);
502    } else {
503        mFormat->setInt64(kKeyDuration, 60 * 60 * 1000000ll);
504    }
505
506    mInitCheck = OK;
507    if (!strncmp(desc.c_str(), "H264/", 5)) {
508        mFormat->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_AVC);
509
510        int32_t width, height;
511        if (!sessionDesc->getDimensions(index, PT, &width, &height)) {
512            width = -1;
513            height = -1;
514        }
515
516        int32_t encWidth, encHeight;
517        sp<ABuffer> codecSpecificData =
518            MakeAVCCodecSpecificData(params.c_str(), &encWidth, &encHeight);
519
520        if (codecSpecificData != NULL) {
521            if (width < 0) {
522                // If no explicit width/height given in the sdp, use the dimensions
523                // extracted from the first sequence parameter set.
524                width = encWidth;
525                height = encHeight;
526            }
527
528            mFormat->setData(
529                    kKeyAVCC, 0,
530                    codecSpecificData->data(), codecSpecificData->size());
531        } else if (width < 0) {
532            mInitCheck = ERROR_UNSUPPORTED;
533            return;
534        }
535
536        mFormat->setInt32(kKeyWidth, width);
537        mFormat->setInt32(kKeyHeight, height);
538    } else if (!strncmp(desc.c_str(), "H263-2000/", 10)
539            || !strncmp(desc.c_str(), "H263-1998/", 10)) {
540        mFormat->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_H263);
541
542        int32_t width, height;
543        if (!sessionDesc->getDimensions(index, PT, &width, &height)) {
544            mInitCheck = ERROR_UNSUPPORTED;
545            return;
546        }
547
548        mFormat->setInt32(kKeyWidth, width);
549        mFormat->setInt32(kKeyHeight, height);
550    } else if (!strncmp(desc.c_str(), "MP4A-LATM/", 10)) {
551        mFormat->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_AAC);
552
553        int32_t sampleRate, numChannels;
554        ASessionDescription::ParseFormatDesc(
555                desc.c_str(), &sampleRate, &numChannels);
556
557        mFormat->setInt32(kKeySampleRate, sampleRate);
558        mFormat->setInt32(kKeyChannelCount, numChannels);
559
560        sp<ABuffer> codecSpecificData =
561            MakeAACCodecSpecificData(params.c_str());
562
563        mFormat->setData(
564                kKeyESDS, 0,
565                codecSpecificData->data(), codecSpecificData->size());
566    } else if (!strncmp(desc.c_str(), "AMR/", 4)) {
567        mFormat->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_AMR_NB);
568
569        int32_t sampleRate, numChannels;
570        ASessionDescription::ParseFormatDesc(
571                desc.c_str(), &sampleRate, &numChannels);
572
573        mFormat->setInt32(kKeySampleRate, sampleRate);
574        mFormat->setInt32(kKeyChannelCount, numChannels);
575
576        if (sampleRate != 8000 || numChannels != 1) {
577            mInitCheck = ERROR_UNSUPPORTED;
578        }
579    } else if (!strncmp(desc.c_str(), "AMR-WB/", 7)) {
580        mFormat->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_AMR_WB);
581
582        int32_t sampleRate, numChannels;
583        ASessionDescription::ParseFormatDesc(
584                desc.c_str(), &sampleRate, &numChannels);
585
586        mFormat->setInt32(kKeySampleRate, sampleRate);
587        mFormat->setInt32(kKeyChannelCount, numChannels);
588
589        if (sampleRate != 16000 || numChannels != 1) {
590            mInitCheck = ERROR_UNSUPPORTED;
591        }
592    } else if (!strncmp(desc.c_str(), "MP4V-ES/", 8)) {
593        mFormat->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_MPEG4);
594
595        int32_t width, height;
596        if (!sessionDesc->getDimensions(index, PT, &width, &height)) {
597            width = -1;
598            height = -1;
599        }
600
601        int32_t encWidth, encHeight;
602        sp<ABuffer> codecSpecificData =
603            MakeMPEG4VideoCodecSpecificData(
604                    params.c_str(), &encWidth, &encHeight);
605
606        if (codecSpecificData != NULL) {
607            mFormat->setData(
608                    kKeyESDS, 0,
609                    codecSpecificData->data(), codecSpecificData->size());
610
611            if (width < 0) {
612                width = encWidth;
613                height = encHeight;
614            }
615        } else if (width < 0) {
616            mInitCheck = ERROR_UNSUPPORTED;
617            return;
618        }
619
620        mFormat->setInt32(kKeyWidth, width);
621        mFormat->setInt32(kKeyHeight, height);
622    } else if (!strncmp(desc.c_str(), "mpeg4-generic/", 14)) {
623        AString val;
624        if (!GetAttribute(params.c_str(), "mode", &val)
625                || (strcasecmp(val.c_str(), "AAC-lbr")
626                    && strcasecmp(val.c_str(), "AAC-hbr"))) {
627            mInitCheck = ERROR_UNSUPPORTED;
628            return;
629        }
630
631        mFormat->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_AAC);
632
633        int32_t sampleRate, numChannels;
634        ASessionDescription::ParseFormatDesc(
635                desc.c_str(), &sampleRate, &numChannels);
636
637        mFormat->setInt32(kKeySampleRate, sampleRate);
638        mFormat->setInt32(kKeyChannelCount, numChannels);
639
640        sp<ABuffer> codecSpecificData =
641            MakeAACCodecSpecificData2(params.c_str());
642
643        mFormat->setData(
644                kKeyESDS, 0,
645                codecSpecificData->data(), codecSpecificData->size());
646    } else {
647        mInitCheck = ERROR_UNSUPPORTED;
648    }
649}
650
651APacketSource::~APacketSource() {
652}
653
654status_t APacketSource::initCheck() const {
655    return mInitCheck;
656}
657
658status_t APacketSource::start(MetaData *params) {
659    return OK;
660}
661
662status_t APacketSource::stop() {
663    return OK;
664}
665
666sp<MetaData> APacketSource::getFormat() {
667    return mFormat;
668}
669
670status_t APacketSource::read(
671        MediaBuffer **out, const ReadOptions *) {
672    *out = NULL;
673
674    Mutex::Autolock autoLock(mLock);
675    while (mEOSResult == OK && mBuffers.empty()) {
676        mCondition.wait(mLock);
677    }
678
679    if (!mBuffers.empty()) {
680        const sp<ABuffer> buffer = *mBuffers.begin();
681
682        updateNormalPlayTime_l(buffer);
683
684        MediaBuffer *mediaBuffer = new MediaBuffer(buffer->size());
685
686        int64_t timeUs;
687        CHECK(buffer->meta()->findInt64("timeUs", &timeUs));
688
689        mediaBuffer->meta_data()->setInt64(kKeyTime, timeUs);
690
691        memcpy(mediaBuffer->data(), buffer->data(), buffer->size());
692        *out = mediaBuffer;
693
694        mBuffers.erase(mBuffers.begin());
695        return OK;
696    }
697
698    return mEOSResult;
699}
700
701void APacketSource::updateNormalPlayTime_l(const sp<ABuffer> &buffer) {
702    uint32_t rtpTime;
703    CHECK(buffer->meta()->findInt32("rtp-time", (int32_t *)&rtpTime));
704
705    mLastNormalPlayTimeUs =
706        (((double)rtpTime - (double)mRTPTimeBase) / mClockRate)
707            * 1000000ll
708            + mNormalPlayTimeBaseUs;
709}
710
711void APacketSource::queueAccessUnit(const sp<ABuffer> &buffer) {
712    int32_t damaged;
713    if (buffer->meta()->findInt32("damaged", &damaged) && damaged) {
714        LOG(VERBOSE) << "discarding damaged AU";
715        return;
716    }
717
718    Mutex::Autolock autoLock(mLock);
719    mBuffers.push_back(buffer);
720    mCondition.signal();
721}
722
723void APacketSource::signalEOS(status_t result) {
724    CHECK(result != OK);
725
726    Mutex::Autolock autoLock(mLock);
727    mEOSResult = result;
728    mCondition.signal();
729}
730
731void APacketSource::flushQueue() {
732    Mutex::Autolock autoLock(mLock);
733    mBuffers.clear();
734}
735
736int64_t APacketSource::getNormalPlayTimeUs() {
737    Mutex::Autolock autoLock(mLock);
738    return mLastNormalPlayTimeUs;
739}
740
741void APacketSource::setNormalPlayTimeMapping(
742        uint32_t rtpTime, int64_t normalPlayTimeUs) {
743    Mutex::Autolock autoLock(mLock);
744
745    mRTPTimeBase = rtpTime;
746    mNormalPlayTimeBaseUs = normalPlayTimeUs;
747}
748
749int64_t APacketSource::getQueueDurationUs(bool *eos) {
750    Mutex::Autolock autoLock(mLock);
751
752    *eos = (mEOSResult != OK);
753
754    if (mBuffers.size() < 2) {
755        return 0;
756    }
757
758    const sp<ABuffer> first = *mBuffers.begin();
759    const sp<ABuffer> last = *--mBuffers.end();
760
761    int64_t firstTimeUs;
762    CHECK(first->meta()->findInt64("timeUs", &firstTimeUs));
763
764    int64_t lastTimeUs;
765    CHECK(last->meta()->findInt64("timeUs", &lastTimeUs));
766
767    CHECK_GE(lastTimeUs, firstTimeUs);
768
769    return lastTimeUs - firstTimeUs;
770}
771
772}  // namespace android
773