Utils.cpp revision 46f80165c595d81dda68f8f3fea27f4fb04937dd
1/*
2 * Copyright (C) 2009 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 "Utils"
19#include <utils/Log.h>
20#include <ctype.h>
21#include <stdio.h>
22#include <sys/stat.h>
23
24#include "include/ESDS.h"
25#include "include/HevcUtils.h"
26
27#include <arpa/inet.h>
28#include <cutils/properties.h>
29#include <media/openmax/OMX_Audio.h>
30#include <media/stagefright/CodecBase.h>
31#include <media/stagefright/foundation/ABuffer.h>
32#include <media/stagefright/foundation/ADebug.h>
33#include <media/stagefright/foundation/AMessage.h>
34#include <media/stagefright/MetaData.h>
35#include <media/stagefright/MediaDefs.h>
36#include <media/AudioSystem.h>
37#include <media/MediaPlayerInterface.h>
38#include <hardware/audio.h>
39#include <media/stagefright/Utils.h>
40#include <media/AudioParameter.h>
41
42namespace android {
43
44uint16_t U16_AT(const uint8_t *ptr) {
45    return ptr[0] << 8 | ptr[1];
46}
47
48uint32_t U32_AT(const uint8_t *ptr) {
49    return ptr[0] << 24 | ptr[1] << 16 | ptr[2] << 8 | ptr[3];
50}
51
52uint64_t U64_AT(const uint8_t *ptr) {
53    return ((uint64_t)U32_AT(ptr)) << 32 | U32_AT(ptr + 4);
54}
55
56uint16_t U16LE_AT(const uint8_t *ptr) {
57    return ptr[0] | (ptr[1] << 8);
58}
59
60uint32_t U32LE_AT(const uint8_t *ptr) {
61    return ptr[3] << 24 | ptr[2] << 16 | ptr[1] << 8 | ptr[0];
62}
63
64uint64_t U64LE_AT(const uint8_t *ptr) {
65    return ((uint64_t)U32LE_AT(ptr + 4)) << 32 | U32LE_AT(ptr);
66}
67
68// XXX warning: these won't work on big-endian host.
69uint64_t ntoh64(uint64_t x) {
70    return ((uint64_t)ntohl(x & 0xffffffff) << 32) | ntohl(x >> 32);
71}
72
73uint64_t hton64(uint64_t x) {
74    return ((uint64_t)htonl(x & 0xffffffff) << 32) | htonl(x >> 32);
75}
76
77static status_t copyNALUToABuffer(sp<ABuffer> *buffer, const uint8_t *ptr, size_t length) {
78    if (((*buffer)->size() + 4 + length) > ((*buffer)->capacity() - (*buffer)->offset())) {
79        sp<ABuffer> tmpBuffer = new (std::nothrow) ABuffer((*buffer)->size() + 4 + length + 1024);
80        if (tmpBuffer.get() == NULL || tmpBuffer->base() == NULL) {
81            return NO_MEMORY;
82        }
83        memcpy(tmpBuffer->data(), (*buffer)->data(), (*buffer)->size());
84        tmpBuffer->setRange(0, (*buffer)->size());
85        (*buffer) = tmpBuffer;
86    }
87
88    memcpy((*buffer)->data() + (*buffer)->size(), "\x00\x00\x00\x01", 4);
89    memcpy((*buffer)->data() + (*buffer)->size() + 4, ptr, length);
90    (*buffer)->setRange((*buffer)->offset(), (*buffer)->size() + 4 + length);
91    return OK;
92}
93
94static void convertMetaDataToMessageInt32(
95        const sp<MetaData> &meta, sp<AMessage> &msg, uint32_t key, const char *name) {
96    int32_t value;
97    if (meta->findInt32(key, &value)) {
98        msg->setInt32(name, value);
99    }
100}
101
102static void convertMetaDataToMessageColorAspects(const sp<MetaData> &meta, sp<AMessage> &msg) {
103    // 0 values are unspecified
104    int32_t range = 0;
105    int32_t primaries = 0;
106    int32_t transferFunction = 0;
107    int32_t colorMatrix = 0;
108    meta->findInt32(kKeyColorRange, &range);
109    meta->findInt32(kKeyColorPrimaries, &primaries);
110    meta->findInt32(kKeyTransferFunction, &transferFunction);
111    meta->findInt32(kKeyColorMatrix, &colorMatrix);
112    ColorAspects colorAspects;
113    memset(&colorAspects, 0, sizeof(colorAspects));
114    colorAspects.mRange = (ColorAspects::Range)range;
115    colorAspects.mPrimaries = (ColorAspects::Primaries)primaries;
116    colorAspects.mTransfer = (ColorAspects::Transfer)transferFunction;
117    colorAspects.mMatrixCoeffs = (ColorAspects::MatrixCoeffs)colorMatrix;
118
119    int32_t rangeMsg, standardMsg, transferMsg;
120    if (CodecBase::convertCodecColorAspectsToPlatformAspects(
121            colorAspects, &rangeMsg, &standardMsg, &transferMsg) != OK) {
122        return;
123    }
124
125    // save specified values to msg
126    if (rangeMsg != 0) {
127        msg->setInt32("color-range", rangeMsg);
128    }
129    if (standardMsg != 0) {
130        msg->setInt32("color-standard", standardMsg);
131    }
132    if (transferMsg != 0) {
133        msg->setInt32("color-transfer", transferMsg);
134    }
135}
136
137status_t convertMetaDataToMessage(
138        const sp<MetaData> &meta, sp<AMessage> *format) {
139
140    format->clear();
141
142    if (meta == NULL) {
143        ALOGE("convertMetaDataToMessage: NULL input");
144        return BAD_VALUE;
145    }
146
147    const char *mime;
148    if (!meta->findCString(kKeyMIMEType, &mime)) {
149        return BAD_VALUE;
150    }
151
152    sp<AMessage> msg = new AMessage;
153    msg->setString("mime", mime);
154
155    int64_t durationUs;
156    if (meta->findInt64(kKeyDuration, &durationUs)) {
157        msg->setInt64("durationUs", durationUs);
158    }
159
160    int32_t avgBitRate;
161    if (meta->findInt32(kKeyBitRate, &avgBitRate)) {
162        msg->setInt32("bitrate", avgBitRate);
163    }
164
165    int32_t maxBitRate;
166    if (meta->findInt32(kKeyMaxBitRate, &maxBitRate)) {
167        msg->setInt32("max-bitrate", maxBitRate);
168    }
169
170    int32_t isSync;
171    if (meta->findInt32(kKeyIsSyncFrame, &isSync) && isSync != 0) {
172        msg->setInt32("is-sync-frame", 1);
173    }
174
175    // this only needs to be translated from meta to message as it is an extractor key
176    int32_t trackID;
177    if (meta->findInt32(kKeyTrackID, &trackID)) {
178        msg->setInt32("track-id", trackID);
179    }
180
181    if (!strncasecmp("video/", mime, 6)) {
182        int32_t width, height;
183        if (!meta->findInt32(kKeyWidth, &width)
184                || !meta->findInt32(kKeyHeight, &height)) {
185            return BAD_VALUE;
186        }
187
188        msg->setInt32("width", width);
189        msg->setInt32("height", height);
190
191        int32_t sarWidth, sarHeight;
192        if (meta->findInt32(kKeySARWidth, &sarWidth)
193                && meta->findInt32(kKeySARHeight, &sarHeight)) {
194            msg->setInt32("sar-width", sarWidth);
195            msg->setInt32("sar-height", sarHeight);
196        }
197
198        int32_t colorFormat;
199        if (meta->findInt32(kKeyColorFormat, &colorFormat)) {
200            msg->setInt32("color-format", colorFormat);
201        }
202
203        int32_t cropLeft, cropTop, cropRight, cropBottom;
204        if (meta->findRect(kKeyCropRect,
205                           &cropLeft,
206                           &cropTop,
207                           &cropRight,
208                           &cropBottom)) {
209            msg->setRect("crop", cropLeft, cropTop, cropRight, cropBottom);
210        }
211
212        int32_t rotationDegrees;
213        if (meta->findInt32(kKeyRotation, &rotationDegrees)) {
214            msg->setInt32("rotation-degrees", rotationDegrees);
215        }
216
217        convertMetaDataToMessageInt32(meta, msg, kKeyMinLuminance, "min-luminance");
218        convertMetaDataToMessageInt32(meta, msg, kKeyMaxLuminance, "max-luminance");
219        convertMetaDataToMessageColorAspects(meta, msg);
220    } else if (!strncasecmp("audio/", mime, 6)) {
221        int32_t numChannels, sampleRate;
222        if (!meta->findInt32(kKeyChannelCount, &numChannels)
223                || !meta->findInt32(kKeySampleRate, &sampleRate)) {
224            return BAD_VALUE;
225        }
226
227        msg->setInt32("channel-count", numChannels);
228        msg->setInt32("sample-rate", sampleRate);
229
230        int32_t channelMask;
231        if (meta->findInt32(kKeyChannelMask, &channelMask)) {
232            msg->setInt32("channel-mask", channelMask);
233        }
234
235        int32_t delay = 0;
236        if (meta->findInt32(kKeyEncoderDelay, &delay)) {
237            msg->setInt32("encoder-delay", delay);
238        }
239        int32_t padding = 0;
240        if (meta->findInt32(kKeyEncoderPadding, &padding)) {
241            msg->setInt32("encoder-padding", padding);
242        }
243
244        int32_t isADTS;
245        if (meta->findInt32(kKeyIsADTS, &isADTS)) {
246            msg->setInt32("is-adts", isADTS);
247        }
248
249        int32_t aacProfile = -1;
250        if (meta->findInt32(kKeyAACAOT, &aacProfile)) {
251            msg->setInt32("aac-profile", aacProfile);
252        }
253
254        int32_t pcmEncoding;
255        if (meta->findInt32(kKeyPcmEncoding, &pcmEncoding)) {
256            msg->setInt32("pcm-encoding", pcmEncoding);
257        }
258    }
259
260    int32_t maxInputSize;
261    if (meta->findInt32(kKeyMaxInputSize, &maxInputSize)) {
262        msg->setInt32("max-input-size", maxInputSize);
263    }
264
265    int32_t maxWidth;
266    if (meta->findInt32(kKeyMaxWidth, &maxWidth)) {
267        msg->setInt32("max-width", maxWidth);
268    }
269
270    int32_t maxHeight;
271    if (meta->findInt32(kKeyMaxHeight, &maxHeight)) {
272        msg->setInt32("max-height", maxHeight);
273    }
274
275    int32_t rotationDegrees;
276    if (meta->findInt32(kKeyRotation, &rotationDegrees)) {
277        msg->setInt32("rotation-degrees", rotationDegrees);
278    }
279
280    int32_t fps;
281    if (meta->findInt32(kKeyFrameRate, &fps) && fps > 0) {
282        msg->setInt32("frame-rate", fps);
283    }
284
285    uint32_t type;
286    const void *data;
287    size_t size;
288    if (meta->findData(kKeyAVCC, &type, &data, &size)) {
289        // Parse the AVCDecoderConfigurationRecord
290
291        const uint8_t *ptr = (const uint8_t *)data;
292
293        if (size < 7 || ptr[0] != 1) {  // configurationVersion == 1
294            ALOGE("b/23680780");
295            return BAD_VALUE;
296        }
297        uint8_t profile __unused = ptr[1];
298        uint8_t level __unused = ptr[3];
299
300        // There is decodable content out there that fails the following
301        // assertion, let's be lenient for now...
302        // CHECK((ptr[4] >> 2) == 0x3f);  // reserved
303
304        size_t lengthSize __unused = 1 + (ptr[4] & 3);
305
306        // commented out check below as H264_QVGA_500_NO_AUDIO.3gp
307        // violates it...
308        // CHECK((ptr[5] >> 5) == 7);  // reserved
309
310        size_t numSeqParameterSets = ptr[5] & 31;
311
312        ptr += 6;
313        size -= 6;
314
315        sp<ABuffer> buffer = new (std::nothrow) ABuffer(1024);
316        if (buffer.get() == NULL || buffer->base() == NULL) {
317            return NO_MEMORY;
318        }
319        buffer->setRange(0, 0);
320
321        for (size_t i = 0; i < numSeqParameterSets; ++i) {
322            if (size < 2) {
323                ALOGE("b/23680780");
324                return BAD_VALUE;
325            }
326            size_t length = U16_AT(ptr);
327
328            ptr += 2;
329            size -= 2;
330
331            if (size < length) {
332                return BAD_VALUE;
333            }
334            status_t err = copyNALUToABuffer(&buffer, ptr, length);
335            if (err != OK) {
336                return err;
337            }
338
339            ptr += length;
340            size -= length;
341        }
342
343        buffer->meta()->setInt32("csd", true);
344        buffer->meta()->setInt64("timeUs", 0);
345
346        msg->setBuffer("csd-0", buffer);
347
348        buffer = new (std::nothrow) ABuffer(1024);
349        if (buffer.get() == NULL || buffer->base() == NULL) {
350            return NO_MEMORY;
351        }
352        buffer->setRange(0, 0);
353
354        if (size < 1) {
355            ALOGE("b/23680780");
356            return BAD_VALUE;
357        }
358        size_t numPictureParameterSets = *ptr;
359        ++ptr;
360        --size;
361
362        for (size_t i = 0; i < numPictureParameterSets; ++i) {
363            if (size < 2) {
364                ALOGE("b/23680780");
365                return BAD_VALUE;
366            }
367            size_t length = U16_AT(ptr);
368
369            ptr += 2;
370            size -= 2;
371
372            if (size < length) {
373                return BAD_VALUE;
374            }
375            status_t err = copyNALUToABuffer(&buffer, ptr, length);
376            if (err != OK) {
377                return err;
378            }
379
380            ptr += length;
381            size -= length;
382        }
383
384        buffer->meta()->setInt32("csd", true);
385        buffer->meta()->setInt64("timeUs", 0);
386        msg->setBuffer("csd-1", buffer);
387    } else if (meta->findData(kKeyHVCC, &type, &data, &size)) {
388        const uint8_t *ptr = (const uint8_t *)data;
389
390        if (size < 23 || ptr[0] != 1) {  // configurationVersion == 1
391            ALOGE("b/23680780");
392            return BAD_VALUE;
393        }
394        uint8_t profile __unused = ptr[1] & 31;
395        uint8_t level __unused = ptr[12];
396        ptr += 22;
397        size -= 22;
398
399
400        size_t numofArrays = (char)ptr[0];
401        ptr += 1;
402        size -= 1;
403        size_t j = 0, i = 0;
404
405        sp<ABuffer> buffer = new (std::nothrow) ABuffer(1024);
406        if (buffer.get() == NULL || buffer->base() == NULL) {
407            return NO_MEMORY;
408        }
409        buffer->setRange(0, 0);
410
411        for (i = 0; i < numofArrays; i++) {
412            if (size < 3) {
413                ALOGE("b/23680780");
414                return BAD_VALUE;
415            }
416            ptr += 1;
417            size -= 1;
418
419            //Num of nals
420            size_t numofNals = U16_AT(ptr);
421
422            ptr += 2;
423            size -= 2;
424
425            for (j = 0; j < numofNals; j++) {
426                if (size < 2) {
427                    ALOGE("b/23680780");
428                    return BAD_VALUE;
429                }
430                size_t length = U16_AT(ptr);
431
432                ptr += 2;
433                size -= 2;
434
435                if (size < length) {
436                    return BAD_VALUE;
437                }
438                status_t err = copyNALUToABuffer(&buffer, ptr, length);
439                if (err != OK) {
440                    return err;
441                }
442
443                ptr += length;
444                size -= length;
445            }
446        }
447        buffer->meta()->setInt32("csd", true);
448        buffer->meta()->setInt64("timeUs", 0);
449        msg->setBuffer("csd-0", buffer);
450
451    } else if (meta->findData(kKeyESDS, &type, &data, &size)) {
452        ESDS esds((const char *)data, size);
453        if (esds.InitCheck() != (status_t)OK) {
454            return BAD_VALUE;
455        }
456
457        const void *codec_specific_data;
458        size_t codec_specific_data_size;
459        esds.getCodecSpecificInfo(
460                &codec_specific_data, &codec_specific_data_size);
461
462        sp<ABuffer> buffer = new (std::nothrow) ABuffer(codec_specific_data_size);
463        if (buffer.get() == NULL || buffer->base() == NULL) {
464            return NO_MEMORY;
465        }
466
467        memcpy(buffer->data(), codec_specific_data,
468               codec_specific_data_size);
469
470        buffer->meta()->setInt32("csd", true);
471        buffer->meta()->setInt64("timeUs", 0);
472        msg->setBuffer("csd-0", buffer);
473
474        uint32_t maxBitrate, avgBitrate;
475        if (esds.getBitRate(&maxBitrate, &avgBitrate) == OK) {
476            if (!meta->hasData(kKeyMaxBitRate)
477                    && maxBitrate > 0 && maxBitrate <= INT32_MAX) {
478                msg->setInt32("max-bitrate", (int32_t)maxBitrate);
479            }
480            if (!meta->hasData(kKeyBitRate)
481                    && avgBitrate > 0 && avgBitrate <= INT32_MAX) {
482                msg->setInt32("bitrate", (int32_t)avgBitrate);
483            }
484        }
485    } else if (meta->findData(kKeyVorbisInfo, &type, &data, &size)) {
486        sp<ABuffer> buffer = new (std::nothrow) ABuffer(size);
487        if (buffer.get() == NULL || buffer->base() == NULL) {
488            return NO_MEMORY;
489        }
490        memcpy(buffer->data(), data, size);
491
492        buffer->meta()->setInt32("csd", true);
493        buffer->meta()->setInt64("timeUs", 0);
494        msg->setBuffer("csd-0", buffer);
495
496        if (!meta->findData(kKeyVorbisBooks, &type, &data, &size)) {
497            return -EINVAL;
498        }
499
500        buffer = new (std::nothrow) ABuffer(size);
501        if (buffer.get() == NULL || buffer->base() == NULL) {
502            return NO_MEMORY;
503        }
504        memcpy(buffer->data(), data, size);
505
506        buffer->meta()->setInt32("csd", true);
507        buffer->meta()->setInt64("timeUs", 0);
508        msg->setBuffer("csd-1", buffer);
509    } else if (meta->findData(kKeyOpusHeader, &type, &data, &size)) {
510        sp<ABuffer> buffer = new (std::nothrow) ABuffer(size);
511        if (buffer.get() == NULL || buffer->base() == NULL) {
512            return NO_MEMORY;
513        }
514        memcpy(buffer->data(), data, size);
515
516        buffer->meta()->setInt32("csd", true);
517        buffer->meta()->setInt64("timeUs", 0);
518        msg->setBuffer("csd-0", buffer);
519
520        if (!meta->findData(kKeyOpusCodecDelay, &type, &data, &size)) {
521            return -EINVAL;
522        }
523
524        buffer = new (std::nothrow) ABuffer(size);
525        if (buffer.get() == NULL || buffer->base() == NULL) {
526            return NO_MEMORY;
527        }
528        memcpy(buffer->data(), data, size);
529
530        buffer->meta()->setInt32("csd", true);
531        buffer->meta()->setInt64("timeUs", 0);
532        msg->setBuffer("csd-1", buffer);
533
534        if (!meta->findData(kKeyOpusSeekPreRoll, &type, &data, &size)) {
535            return -EINVAL;
536        }
537
538        buffer = new (std::nothrow) ABuffer(size);
539        if (buffer.get() == NULL || buffer->base() == NULL) {
540            return NO_MEMORY;
541        }
542        memcpy(buffer->data(), data, size);
543
544        buffer->meta()->setInt32("csd", true);
545        buffer->meta()->setInt64("timeUs", 0);
546        msg->setBuffer("csd-2", buffer);
547    } else if (meta->findData(kKeyVp9CodecPrivate, &type, &data, &size)) {
548        sp<ABuffer> buffer = new (std::nothrow) ABuffer(size);
549        if (buffer.get() == NULL || buffer->base() == NULL) {
550            return NO_MEMORY;
551        }
552        memcpy(buffer->data(), data, size);
553
554        buffer->meta()->setInt32("csd", true);
555        buffer->meta()->setInt64("timeUs", 0);
556        msg->setBuffer("csd-0", buffer);
557    }
558
559    // TODO expose "crypto-key"/kKeyCryptoKey through public api
560    if (meta->findData(kKeyCryptoKey, &type, &data, &size)) {
561        sp<ABuffer> buffer = new (std::nothrow) ABuffer(size);
562        msg->setBuffer("crypto-key", buffer);
563        memcpy(buffer->data(), data, size);
564    }
565
566    *format = msg;
567
568    return OK;
569}
570
571static size_t reassembleAVCC(const sp<ABuffer> &csd0, const sp<ABuffer> csd1, char *avcc) {
572    avcc[0] = 1;        // version
573    avcc[1] = 0x64;     // profile (default to high)
574    avcc[2] = 0;        // constraints (default to none)
575    avcc[3] = 0xd;      // level (default to 1.3)
576    avcc[4] = 0xff;     // reserved+size
577
578    size_t i = 0;
579    int numparams = 0;
580    int lastparamoffset = 0;
581    int avccidx = 6;
582    do {
583        if (i >= csd0->size() - 4 ||
584                memcmp(csd0->data() + i, "\x00\x00\x00\x01", 4) == 0) {
585            if (i >= csd0->size() - 4) {
586                // there can't be another param here, so use all the rest
587                i = csd0->size();
588            }
589            ALOGV("block at %zu, last was %d", i, lastparamoffset);
590            if (lastparamoffset > 0) {
591                int size = i - lastparamoffset;
592                avcc[avccidx++] = size >> 8;
593                avcc[avccidx++] = size & 0xff;
594                memcpy(avcc+avccidx, csd0->data() + lastparamoffset, size);
595                avccidx += size;
596                numparams++;
597            }
598            i += 4;
599            lastparamoffset = i;
600        } else {
601            i++;
602        }
603    } while(i < csd0->size());
604    ALOGV("csd0 contains %d params", numparams);
605
606    avcc[5] = 0xe0 | numparams;
607    //and now csd-1
608    i = 0;
609    numparams = 0;
610    lastparamoffset = 0;
611    int numpicparamsoffset = avccidx;
612    avccidx++;
613    do {
614        if (i >= csd1->size() - 4 ||
615                memcmp(csd1->data() + i, "\x00\x00\x00\x01", 4) == 0) {
616            if (i >= csd1->size() - 4) {
617                // there can't be another param here, so use all the rest
618                i = csd1->size();
619            }
620            ALOGV("block at %zu, last was %d", i, lastparamoffset);
621            if (lastparamoffset > 0) {
622                int size = i - lastparamoffset;
623                avcc[avccidx++] = size >> 8;
624                avcc[avccidx++] = size & 0xff;
625                memcpy(avcc+avccidx, csd1->data() + lastparamoffset, size);
626                avccidx += size;
627                numparams++;
628            }
629            i += 4;
630            lastparamoffset = i;
631        } else {
632            i++;
633        }
634    } while(i < csd1->size());
635    avcc[numpicparamsoffset] = numparams;
636    return avccidx;
637}
638
639static void reassembleESDS(const sp<ABuffer> &csd0, char *esds) {
640    int csd0size = csd0->size();
641    esds[0] = 3; // kTag_ESDescriptor;
642    int esdescriptorsize = 26 + csd0size;
643    CHECK(esdescriptorsize < 268435456); // 7 bits per byte, so max is 2^28-1
644    esds[1] = 0x80 | (esdescriptorsize >> 21);
645    esds[2] = 0x80 | ((esdescriptorsize >> 14) & 0x7f);
646    esds[3] = 0x80 | ((esdescriptorsize >> 7) & 0x7f);
647    esds[4] = (esdescriptorsize & 0x7f);
648    esds[5] = esds[6] = 0; // es id
649    esds[7] = 0; // flags
650    esds[8] = 4; // kTag_DecoderConfigDescriptor
651    int configdescriptorsize = 18 + csd0size;
652    esds[9] = 0x80 | (configdescriptorsize >> 21);
653    esds[10] = 0x80 | ((configdescriptorsize >> 14) & 0x7f);
654    esds[11] = 0x80 | ((configdescriptorsize >> 7) & 0x7f);
655    esds[12] = (configdescriptorsize & 0x7f);
656    esds[13] = 0x40; // objectTypeIndication
657    // bytes 14-25 are examples from a real file. they are unused/overwritten by muxers.
658    esds[14] = 0x15; // streamType(5), upStream(0),
659    esds[15] = 0x00; // 15-17: bufferSizeDB (6KB)
660    esds[16] = 0x18;
661    esds[17] = 0x00;
662    esds[18] = 0x00; // 18-21: maxBitrate (64kbps)
663    esds[19] = 0x00;
664    esds[20] = 0xfa;
665    esds[21] = 0x00;
666    esds[22] = 0x00; // 22-25: avgBitrate (64kbps)
667    esds[23] = 0x00;
668    esds[24] = 0xfa;
669    esds[25] = 0x00;
670    esds[26] = 5; // kTag_DecoderSpecificInfo;
671    esds[27] = 0x80 | (csd0size >> 21);
672    esds[28] = 0x80 | ((csd0size >> 14) & 0x7f);
673    esds[29] = 0x80 | ((csd0size >> 7) & 0x7f);
674    esds[30] = (csd0size & 0x7f);
675    memcpy((void*)&esds[31], csd0->data(), csd0size);
676    // data following this is ignored, so don't bother appending it
677}
678
679static size_t reassembleHVCC(const sp<ABuffer> &csd0, uint8_t *hvcc, size_t hvccSize, size_t nalSizeLength) {
680    HevcParameterSets paramSets;
681    uint8_t* data = csd0->data();
682    if (csd0->size() < 4) {
683        ALOGE("csd0 too small");
684        return 0;
685    }
686    if (memcmp(data, "\x00\x00\x00\x01", 4) != 0) {
687        ALOGE("csd0 doesn't start with a start code");
688        return 0;
689    }
690    size_t prevNalOffset = 4;
691    status_t err = OK;
692    for (size_t i = 1; i < csd0->size() - 4; ++i) {
693        if (memcmp(&data[i], "\x00\x00\x00\x01", 4) != 0) {
694            continue;
695        }
696        err = paramSets.addNalUnit(&data[prevNalOffset], i - prevNalOffset);
697        if (err != OK) {
698            return 0;
699        }
700        prevNalOffset = i + 4;
701    }
702    err = paramSets.addNalUnit(&data[prevNalOffset], csd0->size() - prevNalOffset);
703    if (err != OK) {
704        return 0;
705    }
706    size_t size = hvccSize;
707    err = paramSets.makeHvcc(hvcc, &size, nalSizeLength);
708    if (err != OK) {
709        return 0;
710    }
711    return size;
712}
713
714static void convertMessageToMetaDataInt32(
715        const sp<AMessage> &msg, sp<MetaData> &meta, uint32_t key, const char *name) {
716    int32_t value;
717    if (msg->findInt32(name, &value)) {
718        meta->setInt32(key, value);
719    }
720}
721
722static void convertMessageToMetaDataColorAspects(const sp<AMessage> &msg, sp<MetaData> &meta) {
723    // 0 values are unspecified
724    int32_t range = 0, standard = 0, transfer = 0;
725    (void)msg->findInt32("color-range", &range);
726    (void)msg->findInt32("color-standard", &standard);
727    (void)msg->findInt32("color-transfer", &transfer);
728
729    ColorAspects colorAspects;
730    memset(&colorAspects, 0, sizeof(colorAspects));
731    if (CodecBase::convertPlatformColorAspectsToCodecAspects(
732            range, standard, transfer, colorAspects) != OK) {
733        return;
734    }
735
736    // save specified values to meta
737    if (colorAspects.mRange != 0) {
738        meta->setInt32(kKeyColorRange, colorAspects.mRange);
739    }
740    if (colorAspects.mPrimaries != 0) {
741        meta->setInt32(kKeyColorPrimaries, colorAspects.mPrimaries);
742    }
743    if (colorAspects.mTransfer != 0) {
744        meta->setInt32(kKeyTransferFunction, colorAspects.mTransfer);
745    }
746    if (colorAspects.mMatrixCoeffs != 0) {
747        meta->setInt32(kKeyColorMatrix, colorAspects.mMatrixCoeffs);
748    }
749}
750
751void convertMessageToMetaData(const sp<AMessage> &msg, sp<MetaData> &meta) {
752    AString mime;
753    if (msg->findString("mime", &mime)) {
754        meta->setCString(kKeyMIMEType, mime.c_str());
755    } else {
756        ALOGW("did not find mime type");
757    }
758
759    int64_t durationUs;
760    if (msg->findInt64("durationUs", &durationUs)) {
761        meta->setInt64(kKeyDuration, durationUs);
762    }
763
764    int32_t isSync;
765    if (msg->findInt32("is-sync-frame", &isSync) && isSync != 0) {
766        meta->setInt32(kKeyIsSyncFrame, 1);
767    }
768
769    if (mime.startsWith("video/")) {
770        int32_t width;
771        int32_t height;
772        if (msg->findInt32("width", &width) && msg->findInt32("height", &height)) {
773            meta->setInt32(kKeyWidth, width);
774            meta->setInt32(kKeyHeight, height);
775        } else {
776            ALOGW("did not find width and/or height");
777        }
778
779        int32_t sarWidth, sarHeight;
780        if (msg->findInt32("sar-width", &sarWidth)
781                && msg->findInt32("sar-height", &sarHeight)) {
782            meta->setInt32(kKeySARWidth, sarWidth);
783            meta->setInt32(kKeySARHeight, sarHeight);
784        }
785
786        int32_t colorFormat;
787        if (msg->findInt32("color-format", &colorFormat)) {
788            meta->setInt32(kKeyColorFormat, colorFormat);
789        }
790
791        int32_t cropLeft, cropTop, cropRight, cropBottom;
792        if (msg->findRect("crop",
793                          &cropLeft,
794                          &cropTop,
795                          &cropRight,
796                          &cropBottom)) {
797            meta->setRect(kKeyCropRect, cropLeft, cropTop, cropRight, cropBottom);
798        }
799
800        int32_t rotationDegrees;
801        if (msg->findInt32("rotation-degrees", &rotationDegrees)) {
802            meta->setInt32(kKeyRotation, rotationDegrees);
803        }
804
805        convertMessageToMetaDataInt32(msg, meta, kKeyMinLuminance, "min-luminance");
806        convertMessageToMetaDataInt32(msg, meta, kKeyMaxLuminance, "max-luminance");
807        convertMessageToMetaDataColorAspects(msg, meta);
808    } else if (mime.startsWith("audio/")) {
809        int32_t numChannels;
810        if (msg->findInt32("channel-count", &numChannels)) {
811            meta->setInt32(kKeyChannelCount, numChannels);
812        }
813        int32_t sampleRate;
814        if (msg->findInt32("sample-rate", &sampleRate)) {
815            meta->setInt32(kKeySampleRate, sampleRate);
816        }
817        int32_t channelMask;
818        if (msg->findInt32("channel-mask", &channelMask)) {
819            meta->setInt32(kKeyChannelMask, channelMask);
820        }
821        int32_t delay = 0;
822        if (msg->findInt32("encoder-delay", &delay)) {
823            meta->setInt32(kKeyEncoderDelay, delay);
824        }
825        int32_t padding = 0;
826        if (msg->findInt32("encoder-padding", &padding)) {
827            meta->setInt32(kKeyEncoderPadding, padding);
828        }
829
830        int32_t isADTS;
831        if (msg->findInt32("is-adts", &isADTS)) {
832            meta->setInt32(kKeyIsADTS, isADTS);
833        }
834
835        int32_t pcmEncoding;
836        if (msg->findInt32("pcm-encoding", &pcmEncoding)) {
837            meta->setInt32(kKeyPcmEncoding, pcmEncoding);
838        }
839    }
840
841    int32_t maxInputSize;
842    if (msg->findInt32("max-input-size", &maxInputSize)) {
843        meta->setInt32(kKeyMaxInputSize, maxInputSize);
844    }
845
846    int32_t maxWidth;
847    if (msg->findInt32("max-width", &maxWidth)) {
848        meta->setInt32(kKeyMaxWidth, maxWidth);
849    }
850
851    int32_t maxHeight;
852    if (msg->findInt32("max-height", &maxHeight)) {
853        meta->setInt32(kKeyMaxHeight, maxHeight);
854    }
855
856    int32_t fps;
857    float fpsFloat;
858    if (msg->findInt32("frame-rate", &fps) && fps > 0) {
859        meta->setInt32(kKeyFrameRate, fps);
860    } else if (msg->findFloat("frame-rate", &fpsFloat)
861            && fpsFloat >= 1 && fpsFloat <= INT32_MAX) {
862        // truncate values to distinguish between e.g. 24 vs 23.976 fps
863        meta->setInt32(kKeyFrameRate, (int32_t)fpsFloat);
864    }
865
866    // reassemble the csd data into its original form
867    sp<ABuffer> csd0;
868    if (msg->findBuffer("csd-0", &csd0)) {
869        if (mime == MEDIA_MIMETYPE_VIDEO_AVC) {
870            sp<ABuffer> csd1;
871            if (msg->findBuffer("csd-1", &csd1)) {
872                char avcc[1024]; // that oughta be enough, right?
873                size_t outsize = reassembleAVCC(csd0, csd1, avcc);
874                meta->setData(kKeyAVCC, kKeyAVCC, avcc, outsize);
875            }
876        } else if (mime == MEDIA_MIMETYPE_AUDIO_AAC || mime == MEDIA_MIMETYPE_VIDEO_MPEG4) {
877            int csd0size = csd0->size();
878            char esds[csd0size + 31];
879            // The written ESDS is actually for an audio stream, but it's enough
880            // for transporting the CSD to muxers.
881            reassembleESDS(csd0, esds);
882            meta->setData(kKeyESDS, kKeyESDS, esds, sizeof(esds));
883        } else if (mime == MEDIA_MIMETYPE_VIDEO_HEVC) {
884            uint8_t hvcc[1024]; // that oughta be enough, right?
885            size_t outsize = reassembleHVCC(csd0, hvcc, 1024, 4);
886            meta->setData(kKeyHVCC, kKeyHVCC, hvcc, outsize);
887        }
888    }
889
890    int32_t timeScale;
891    if (msg->findInt32("time-scale", &timeScale)) {
892        meta->setInt32(kKeyTimeScale, timeScale);
893    }
894
895    // XXX TODO add whatever other keys there are
896
897#if 0
898    ALOGI("converted %s to:", msg->debugString(0).c_str());
899    meta->dumpToLog();
900#endif
901}
902
903AString MakeUserAgent() {
904    AString ua;
905    ua.append("stagefright/1.2 (Linux;Android ");
906
907#if (PROPERTY_VALUE_MAX < 8)
908#error "PROPERTY_VALUE_MAX must be at least 8"
909#endif
910
911    char value[PROPERTY_VALUE_MAX];
912    property_get("ro.build.version.release", value, "Unknown");
913    ua.append(value);
914    ua.append(")");
915
916    return ua;
917}
918
919status_t sendMetaDataToHal(sp<MediaPlayerBase::AudioSink>& sink,
920                           const sp<MetaData>& meta)
921{
922    int32_t sampleRate = 0;
923    int32_t bitRate = 0;
924    int32_t channelMask = 0;
925    int32_t delaySamples = 0;
926    int32_t paddingSamples = 0;
927
928    AudioParameter param = AudioParameter();
929
930    if (meta->findInt32(kKeySampleRate, &sampleRate)) {
931        param.addInt(String8(AUDIO_OFFLOAD_CODEC_SAMPLE_RATE), sampleRate);
932    }
933    if (meta->findInt32(kKeyChannelMask, &channelMask)) {
934        param.addInt(String8(AUDIO_OFFLOAD_CODEC_NUM_CHANNEL), channelMask);
935    }
936    if (meta->findInt32(kKeyBitRate, &bitRate)) {
937        param.addInt(String8(AUDIO_OFFLOAD_CODEC_AVG_BIT_RATE), bitRate);
938    }
939    if (meta->findInt32(kKeyEncoderDelay, &delaySamples)) {
940        param.addInt(String8(AUDIO_OFFLOAD_CODEC_DELAY_SAMPLES), delaySamples);
941    }
942    if (meta->findInt32(kKeyEncoderPadding, &paddingSamples)) {
943        param.addInt(String8(AUDIO_OFFLOAD_CODEC_PADDING_SAMPLES), paddingSamples);
944    }
945
946    ALOGV("sendMetaDataToHal: bitRate %d, sampleRate %d, chanMask %d,"
947          "delaySample %d, paddingSample %d", bitRate, sampleRate,
948          channelMask, delaySamples, paddingSamples);
949
950    sink->setParameters(param.toString());
951    return OK;
952}
953
954struct mime_conv_t {
955    const char* mime;
956    audio_format_t format;
957};
958
959static const struct mime_conv_t mimeLookup[] = {
960    { MEDIA_MIMETYPE_AUDIO_MPEG,        AUDIO_FORMAT_MP3 },
961    { MEDIA_MIMETYPE_AUDIO_RAW,         AUDIO_FORMAT_PCM_16_BIT },
962    { MEDIA_MIMETYPE_AUDIO_AMR_NB,      AUDIO_FORMAT_AMR_NB },
963    { MEDIA_MIMETYPE_AUDIO_AMR_WB,      AUDIO_FORMAT_AMR_WB },
964    { MEDIA_MIMETYPE_AUDIO_AAC,         AUDIO_FORMAT_AAC },
965    { MEDIA_MIMETYPE_AUDIO_VORBIS,      AUDIO_FORMAT_VORBIS },
966    { MEDIA_MIMETYPE_AUDIO_OPUS,        AUDIO_FORMAT_OPUS},
967    { 0, AUDIO_FORMAT_INVALID }
968};
969
970status_t mapMimeToAudioFormat( audio_format_t& format, const char* mime )
971{
972const struct mime_conv_t* p = &mimeLookup[0];
973    while (p->mime != NULL) {
974        if (0 == strcasecmp(mime, p->mime)) {
975            format = p->format;
976            return OK;
977        }
978        ++p;
979    }
980
981    return BAD_VALUE;
982}
983
984struct aac_format_conv_t {
985    OMX_AUDIO_AACPROFILETYPE eAacProfileType;
986    audio_format_t format;
987};
988
989static const struct aac_format_conv_t profileLookup[] = {
990    { OMX_AUDIO_AACObjectMain,        AUDIO_FORMAT_AAC_MAIN},
991    { OMX_AUDIO_AACObjectLC,          AUDIO_FORMAT_AAC_LC},
992    { OMX_AUDIO_AACObjectSSR,         AUDIO_FORMAT_AAC_SSR},
993    { OMX_AUDIO_AACObjectLTP,         AUDIO_FORMAT_AAC_LTP},
994    { OMX_AUDIO_AACObjectHE,          AUDIO_FORMAT_AAC_HE_V1},
995    { OMX_AUDIO_AACObjectScalable,    AUDIO_FORMAT_AAC_SCALABLE},
996    { OMX_AUDIO_AACObjectERLC,        AUDIO_FORMAT_AAC_ERLC},
997    { OMX_AUDIO_AACObjectLD,          AUDIO_FORMAT_AAC_LD},
998    { OMX_AUDIO_AACObjectHE_PS,       AUDIO_FORMAT_AAC_HE_V2},
999    { OMX_AUDIO_AACObjectELD,         AUDIO_FORMAT_AAC_ELD},
1000    { OMX_AUDIO_AACObjectNull,        AUDIO_FORMAT_AAC},
1001};
1002
1003void mapAACProfileToAudioFormat( audio_format_t& format, uint64_t eAacProfile)
1004{
1005const struct aac_format_conv_t* p = &profileLookup[0];
1006    while (p->eAacProfileType != OMX_AUDIO_AACObjectNull) {
1007        if (eAacProfile == p->eAacProfileType) {
1008            format = p->format;
1009            return;
1010        }
1011        ++p;
1012    }
1013    format = AUDIO_FORMAT_AAC;
1014    return;
1015}
1016
1017bool canOffloadStream(const sp<MetaData>& meta, bool hasVideo,
1018                      bool isStreaming, audio_stream_type_t streamType)
1019{
1020    const char *mime;
1021    if (meta == NULL) {
1022        return false;
1023    }
1024    CHECK(meta->findCString(kKeyMIMEType, &mime));
1025
1026    audio_offload_info_t info = AUDIO_INFO_INITIALIZER;
1027
1028    info.format = AUDIO_FORMAT_INVALID;
1029    if (mapMimeToAudioFormat(info.format, mime) != OK) {
1030        ALOGE(" Couldn't map mime type \"%s\" to a valid AudioSystem::audio_format !", mime);
1031        return false;
1032    } else {
1033        ALOGV("Mime type \"%s\" mapped to audio_format %d", mime, info.format);
1034    }
1035
1036    if (AUDIO_FORMAT_INVALID == info.format) {
1037        // can't offload if we don't know what the source format is
1038        ALOGE("mime type \"%s\" not a known audio format", mime);
1039        return false;
1040    }
1041
1042    // Redefine aac format according to its profile
1043    // Offloading depends on audio DSP capabilities.
1044    int32_t aacaot = -1;
1045    if (meta->findInt32(kKeyAACAOT, &aacaot)) {
1046        mapAACProfileToAudioFormat(info.format,(OMX_AUDIO_AACPROFILETYPE) aacaot);
1047    }
1048
1049    int32_t srate = -1;
1050    if (!meta->findInt32(kKeySampleRate, &srate)) {
1051        ALOGV("track of type '%s' does not publish sample rate", mime);
1052    }
1053    info.sample_rate = srate;
1054
1055    int32_t cmask = 0;
1056    if (!meta->findInt32(kKeyChannelMask, &cmask)) {
1057        ALOGV("track of type '%s' does not publish channel mask", mime);
1058
1059        // Try a channel count instead
1060        int32_t channelCount;
1061        if (!meta->findInt32(kKeyChannelCount, &channelCount)) {
1062            ALOGV("track of type '%s' does not publish channel count", mime);
1063        } else {
1064            cmask = audio_channel_out_mask_from_count(channelCount);
1065        }
1066    }
1067    info.channel_mask = cmask;
1068
1069    int64_t duration = 0;
1070    if (!meta->findInt64(kKeyDuration, &duration)) {
1071        ALOGV("track of type '%s' does not publish duration", mime);
1072    }
1073    info.duration_us = duration;
1074
1075    int32_t brate = -1;
1076    if (!meta->findInt32(kKeyBitRate, &brate)) {
1077        ALOGV("track of type '%s' does not publish bitrate", mime);
1078    }
1079    info.bit_rate = brate;
1080
1081
1082    info.stream_type = streamType;
1083    info.has_video = hasVideo;
1084    info.is_streaming = isStreaming;
1085
1086    // Check if offload is possible for given format, stream type, sample rate,
1087    // bit rate, duration, video and streaming
1088    return AudioSystem::isOffloadSupported(info);
1089}
1090
1091AString uriDebugString(const AString &uri, bool incognito) {
1092    if (incognito) {
1093        return AString("<URI suppressed>");
1094    }
1095
1096    char prop[PROPERTY_VALUE_MAX];
1097    if (property_get("media.stagefright.log-uri", prop, "false") &&
1098        (!strcmp(prop, "1") || !strcmp(prop, "true"))) {
1099        return uri;
1100    }
1101
1102    // find scheme
1103    AString scheme;
1104    const char *chars = uri.c_str();
1105    for (size_t i = 0; i < uri.size(); i++) {
1106        const char c = chars[i];
1107        if (!isascii(c)) {
1108            break;
1109        } else if (isalpha(c)) {
1110            continue;
1111        } else if (i == 0) {
1112            // first character must be a letter
1113            break;
1114        } else if (isdigit(c) || c == '+' || c == '.' || c =='-') {
1115            continue;
1116        } else if (c != ':') {
1117            break;
1118        }
1119        scheme = AString(uri, 0, i);
1120        scheme.append("://<suppressed>");
1121        return scheme;
1122    }
1123    return AString("<no-scheme URI suppressed>");
1124}
1125
1126HLSTime::HLSTime(const sp<AMessage>& meta) :
1127    mSeq(-1),
1128    mTimeUs(-1ll),
1129    mMeta(meta) {
1130    if (meta != NULL) {
1131        CHECK(meta->findInt32("discontinuitySeq", &mSeq));
1132        CHECK(meta->findInt64("timeUs", &mTimeUs));
1133    }
1134}
1135
1136int64_t HLSTime::getSegmentTimeUs() const {
1137    int64_t segmentStartTimeUs = -1ll;
1138    if (mMeta != NULL) {
1139        CHECK(mMeta->findInt64("segmentStartTimeUs", &segmentStartTimeUs));
1140
1141        int64_t segmentFirstTimeUs;
1142        if (mMeta->findInt64("segmentFirstTimeUs", &segmentFirstTimeUs)) {
1143            segmentStartTimeUs += mTimeUs - segmentFirstTimeUs;
1144        }
1145
1146        // adjust segment time by playlist age (for live streaming)
1147        int64_t playlistTimeUs;
1148        if (mMeta->findInt64("playlistTimeUs", &playlistTimeUs)) {
1149            int64_t playlistAgeUs = ALooper::GetNowUs() - playlistTimeUs;
1150
1151            int64_t durationUs;
1152            CHECK(mMeta->findInt64("segmentDurationUs", &durationUs));
1153
1154            // round to nearest whole segment
1155            playlistAgeUs = (playlistAgeUs + durationUs / 2)
1156                    / durationUs * durationUs;
1157
1158            segmentStartTimeUs -= playlistAgeUs;
1159            if (segmentStartTimeUs < 0) {
1160                segmentStartTimeUs = 0;
1161            }
1162        }
1163    }
1164    return segmentStartTimeUs;
1165}
1166
1167bool operator <(const HLSTime &t0, const HLSTime &t1) {
1168    // we can only compare discontinuity sequence and timestamp.
1169    // (mSegmentTimeUs is not reliable in live streaming case, it's the
1170    // time starting from beginning of playlist but playlist could change.)
1171    return t0.mSeq < t1.mSeq
1172            || (t0.mSeq == t1.mSeq && t0.mTimeUs < t1.mTimeUs);
1173}
1174
1175void writeToAMessage(sp<AMessage> msg, const AudioPlaybackRate &rate) {
1176    msg->setFloat("speed", rate.mSpeed);
1177    msg->setFloat("pitch", rate.mPitch);
1178    msg->setInt32("audio-fallback-mode", rate.mFallbackMode);
1179    msg->setInt32("audio-stretch-mode", rate.mStretchMode);
1180}
1181
1182void readFromAMessage(const sp<AMessage> &msg, AudioPlaybackRate *rate /* nonnull */) {
1183    *rate = AUDIO_PLAYBACK_RATE_DEFAULT;
1184    CHECK(msg->findFloat("speed", &rate->mSpeed));
1185    CHECK(msg->findFloat("pitch", &rate->mPitch));
1186    CHECK(msg->findInt32("audio-fallback-mode", (int32_t *)&rate->mFallbackMode));
1187    CHECK(msg->findInt32("audio-stretch-mode", (int32_t *)&rate->mStretchMode));
1188}
1189
1190void writeToAMessage(sp<AMessage> msg, const AVSyncSettings &sync, float videoFpsHint) {
1191    msg->setInt32("sync-source", sync.mSource);
1192    msg->setInt32("audio-adjust-mode", sync.mAudioAdjustMode);
1193    msg->setFloat("tolerance", sync.mTolerance);
1194    msg->setFloat("video-fps", videoFpsHint);
1195}
1196
1197void readFromAMessage(
1198        const sp<AMessage> &msg,
1199        AVSyncSettings *sync /* nonnull */,
1200        float *videoFps /* nonnull */) {
1201    AVSyncSettings settings;
1202    CHECK(msg->findInt32("sync-source", (int32_t *)&settings.mSource));
1203    CHECK(msg->findInt32("audio-adjust-mode", (int32_t *)&settings.mAudioAdjustMode));
1204    CHECK(msg->findFloat("tolerance", &settings.mTolerance));
1205    CHECK(msg->findFloat("video-fps", videoFps));
1206    *sync = settings;
1207}
1208
1209AString nameForFd(int fd) {
1210    const size_t SIZE = 256;
1211    char buffer[SIZE];
1212    AString result;
1213    snprintf(buffer, SIZE, "/proc/%d/fd/%d", getpid(), fd);
1214    struct stat s;
1215    if (lstat(buffer, &s) == 0) {
1216        if ((s.st_mode & S_IFMT) == S_IFLNK) {
1217            char linkto[256];
1218            int len = readlink(buffer, linkto, sizeof(linkto));
1219            if(len > 0) {
1220                if(len > 255) {
1221                    linkto[252] = '.';
1222                    linkto[253] = '.';
1223                    linkto[254] = '.';
1224                    linkto[255] = 0;
1225                } else {
1226                    linkto[len] = 0;
1227                }
1228                result.append(linkto);
1229            }
1230        } else {
1231            result.append("unexpected type for ");
1232            result.append(buffer);
1233        }
1234    } else {
1235        result.append("couldn't open ");
1236        result.append(buffer);
1237    }
1238    return result;
1239}
1240
1241}  // namespace android
1242
1243