Loading media/libstagefright/httplive/M3UParser.cpp +153 −7 Original line number Diff line number Diff line Loading @@ -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 { Loading Loading @@ -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); Loading Loading @@ -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()); Loading @@ -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) { Loading Loading @@ -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 media/libstagefright/httplive/M3UParser.h +4 −0 Original line number Diff line number Diff line Loading @@ -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); }; Loading Loading
media/libstagefright/httplive/M3UParser.cpp +153 −7 Original line number Diff line number Diff line Loading @@ -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 { Loading Loading @@ -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); Loading Loading @@ -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()); Loading @@ -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) { Loading Loading @@ -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
media/libstagefright/httplive/M3UParser.h +4 −0 Original line number Diff line number Diff line Loading @@ -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); }; Loading