Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit f7e34cfc authored by Robert Shih's avatar Robert Shih Committed by Lajos Molnar
Browse files

stagefright: use CODECS field in EXT-X_STREAM-INF as fallback

Use the CODECS field in EXT-X-STREAM-INF as a viable fallback for identifying
available streams in a variant playlist.

Bug: 11854054
Change-Id: I5011809dc7c56220b023eb1a16f2d6a392ddd6f1
parent b2be2f2e
Loading
Loading
Loading
Loading
+153 −7
Original line number Diff line number Diff line
@@ -24,6 +24,7 @@
#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/foundation/AMessage.h>
#include <media/stagefright/MediaErrors.h>
#include <media/stagefright/Utils.h>
#include <media/mediaplayer.h>

namespace android {
@@ -352,9 +353,27 @@ bool M3UParser::getTypeURI(size_t index, const char *key, AString *uri) const {
    if (!meta->findString(key, &groupID)) {
        *uri = mItems.itemAt(index).mURI;

        AString codecs;
        if (!meta->findString("codecs", &codecs)) {
            // Assume media without any more specific attribute contains
            // audio and video, but no subtitles.
            return !strcmp("audio", key) || !strcmp("video", key);
        } else {
            // Split the comma separated list of codecs.
            size_t offset = 0;
            ssize_t commaPos = -1;
            codecs.append(',');
            while ((commaPos = codecs.find(",", offset)) >= 0) {
                AString codec(codecs, offset, commaPos - offset);
                // return true only if a codec of type `key` ("audio"/"video")
                // is found.
                if (codecIsType(codec, key)) {
                    return true;
                }
                offset = commaPos + 1;
            }
            return false;
        }
    }

    sp<MediaGroup> group = mMediaGroups.valueFor(groupID);
@@ -684,12 +703,22 @@ status_t M3UParser::parseStreamInf(
                *meta = new AMessage;
            }
            (*meta)->setInt32("bandwidth", x);
        } else if (!strcasecmp("codecs", key.c_str())) {
            if (!isQuotedString(val)) {
                ALOGE("Expected quoted string for %s attribute, "
                      "got '%s' instead.",
                      key.c_str(), val.c_str());;

                return ERROR_MALFORMED;
            }

            key.tolower();
            const AString &codecs = unquoteString(val);
            (*meta)->setString(key.c_str(), codecs.c_str());
        } else if (!strcasecmp("audio", key.c_str())
                || !strcasecmp("video", key.c_str())
                || !strcasecmp("subtitles", key.c_str())) {
            if (val.size() < 2
                    || val.c_str()[0] != '"'
                    || val.c_str()[val.size() - 1] != '"') {
            if (!isQuotedString(val)) {
                ALOGE("Expected quoted string for %s attribute, "
                      "got '%s' instead.",
                      key.c_str(), val.c_str());
@@ -697,7 +726,7 @@ status_t M3UParser::parseStreamInf(
                return ERROR_MALFORMED;
            }

            AString groupID(val, 1, val.size() - 2);
            const AString &groupID = unquoteString(val);
            ssize_t groupIndex = mMediaGroups.indexOfKey(groupID);

            if (groupIndex < 0) {
@@ -1086,4 +1115,121 @@ status_t M3UParser::ParseDouble(const char *s, double *x) {
    return OK;
}

// static
bool M3UParser::isQuotedString(const AString &str) {
    if (str.size() < 2
            || str.c_str()[0] != '"'
            || str.c_str()[str.size() - 1] != '"') {
        return false;
    }
    return true;
}

// static
AString M3UParser::unquoteString(const AString &str) {
     if (!isQuotedString(str)) {
         return str;
     }
     return AString(str, 1, str.size() - 2);
}

// static
bool M3UParser::codecIsType(const AString &codec, const char *type) {
    if (codec.size() < 4) {
        return false;
    }
    const char *c = codec.c_str();
    switch (FOURCC(c[0], c[1], c[2], c[3])) {
        // List extracted from http://www.mp4ra.org/codecs.html
        case 'ac-3':
        case 'alac':
        case 'dra1':
        case 'dtsc':
        case 'dtse':
        case 'dtsh':
        case 'dtsl':
        case 'ec-3':
        case 'enca':
        case 'g719':
        case 'g726':
        case 'm4ae':
        case 'mlpa':
        case 'mp4a':
        case 'raw ':
        case 'samr':
        case 'sawb':
        case 'sawp':
        case 'sevc':
        case 'sqcp':
        case 'ssmv':
        case 'twos':
        case 'agsm':
        case 'alaw':
        case 'dvi ':
        case 'fl32':
        case 'fl64':
        case 'ima4':
        case 'in24':
        case 'in32':
        case 'lpcm':
        case 'Qclp':
        case 'QDM2':
        case 'QDMC':
        case 'ulaw':
        case 'vdva':
            return !strcmp("audio", type);

        case 'avc1':
        case 'avc2':
        case 'avcp':
        case 'drac':
        case 'encv':
        case 'mjp2':
        case 'mp4v':
        case 'mvc1':
        case 'mvc2':
        case 'resv':
        case 's263':
        case 'svc1':
        case 'vc-1':
        case 'CFHD':
        case 'civd':
        case 'DV10':
        case 'dvh5':
        case 'dvh6':
        case 'dvhp':
        case 'DVOO':
        case 'DVOR':
        case 'DVTV':
        case 'DVVT':
        case 'flic':
        case 'gif ':
        case 'h261':
        case 'h263':
        case 'HD10':
        case 'jpeg':
        case 'M105':
        case 'mjpa':
        case 'mjpb':
        case 'png ':
        case 'PNTG':
        case 'rle ':
        case 'rpza':
        case 'Shr0':
        case 'Shr1':
        case 'Shr2':
        case 'Shr3':
        case 'Shr4':
        case 'SVQ1':
        case 'SVQ3':
        case 'tga ':
        case 'tiff':
        case 'WRLE':
            return !strcmp("video", type);

        default:
            return false;
    }
}

}  // namespace android
+4 −0
Original line number Diff line number Diff line
@@ -100,6 +100,10 @@ private:
    static status_t ParseInt32(const char *s, int32_t *x);
    static status_t ParseDouble(const char *s, double *x);

    static bool isQuotedString(const AString &str);
    static AString unquoteString(const AString &str);
    static bool codecIsType(const AString &codec, const char *type);

    DISALLOW_EVIL_CONSTRUCTORS(M3UParser);
};