Loading media/libstagefright/MPEG4Extractor.cpp +3 −2 Original line number Diff line number Diff line Loading @@ -1566,8 +1566,9 @@ status_t MPEG4Extractor::parseChunk(off64_t *offset, int depth) { const char *mime; CHECK(mLastTrack->meta->findCString(kKeyMIMEType, &mime)); if (!strcmp(mime, MEDIA_MIMETYPE_VIDEO_AVC)) { // AVC requires compression ratio of at least 2, and uses if (!strcmp(mime, MEDIA_MIMETYPE_VIDEO_AVC) || !strcmp(mime, MEDIA_MIMETYPE_VIDEO_HEVC)) { // AVC & HEVC requires compression ratio of at least 2, and uses // macroblocks max_size = ((width + 15) / 16) * ((height + 15) / 16) * 192; } else { Loading media/libstagefright/MPEG4Writer.cpp +1 −0 Original line number Diff line number Diff line Loading @@ -1957,6 +1957,7 @@ const uint8_t *MPEG4Writer::Track::parseParamSet( if (mProfileIdc != data[1] || mProfileCompatible != data[2] || mLevelIdc != data[3]) { // COULD DO: set profile/level to the lowest required to support all SPSs ALOGE("Inconsistent profile/level found in seq parameter sets"); return NULL; } Loading media/libstagefright/Utils.cpp +437 −5 Original line number Diff line number Diff line Loading @@ -21,15 +21,20 @@ #include <stdio.h> #include <sys/stat.h> #include <utility> #include "include/ESDS.h" #include "include/HevcUtils.h" #include <arpa/inet.h> #include <cutils/properties.h> #include <media/openmax/OMX_Audio.h> #include <media/openmax/OMX_Video.h> #include <media/openmax/OMX_VideoExt.h> #include <media/stagefright/CodecBase.h> #include <media/stagefright/foundation/ABuffer.h> #include <media/stagefright/foundation/ADebug.h> #include <media/stagefright/foundation/ALookup.h> #include <media/stagefright/foundation/AMessage.h> #include <media/stagefright/MetaData.h> #include <media/stagefright/MediaDefs.h> Loading Loading @@ -134,6 +139,418 @@ static void convertMetaDataToMessageColorAspects(const sp<MetaData> &meta, sp<AM } } static void parseAacProfileFromCsd(const sp<ABuffer> &csd, sp<AMessage> &format) { if (csd->size() < 2) { return; } uint16_t audioObjectType = U16_AT((uint8_t*)csd->data()); if ((audioObjectType & 0xF800) == 0xF800) { audioObjectType = 32 + ((audioObjectType >> 5) & 0x3F); } else { audioObjectType >>= 11; } const static ALookup<uint16_t, OMX_AUDIO_AACPROFILETYPE> profiles { { 1, OMX_AUDIO_AACObjectMain }, { 2, OMX_AUDIO_AACObjectLC }, { 3, OMX_AUDIO_AACObjectSSR }, { 4, OMX_AUDIO_AACObjectLTP }, { 5, OMX_AUDIO_AACObjectHE }, { 6, OMX_AUDIO_AACObjectScalable }, { 17, OMX_AUDIO_AACObjectERLC }, { 23, OMX_AUDIO_AACObjectLD }, { 29, OMX_AUDIO_AACObjectHE_PS }, { 39, OMX_AUDIO_AACObjectELD }, }; OMX_AUDIO_AACPROFILETYPE profile; if (profiles.map(audioObjectType, &profile)) { format->setInt32("profile", profile); } } static void parseAvcProfileLevelFromAvcc(const uint8_t *ptr, size_t size, sp<AMessage> &format) { if (size < 4 || ptr[0] != 1) { // configurationVersion == 1 return; } const uint8_t profile = ptr[1]; const uint8_t constraints = ptr[2]; const uint8_t level = ptr[3]; const static ALookup<uint8_t, OMX_VIDEO_AVCLEVELTYPE> levels { { 9, OMX_VIDEO_AVCLevel1b }, // technically, 9 is only used for High+ profiles { 10, OMX_VIDEO_AVCLevel1 }, { 11, OMX_VIDEO_AVCLevel11 }, // prefer level 1.1 for the value 11 { 11, OMX_VIDEO_AVCLevel1b }, { 12, OMX_VIDEO_AVCLevel12 }, { 13, OMX_VIDEO_AVCLevel13 }, { 20, OMX_VIDEO_AVCLevel2 }, { 21, OMX_VIDEO_AVCLevel21 }, { 22, OMX_VIDEO_AVCLevel22 }, { 30, OMX_VIDEO_AVCLevel3 }, { 31, OMX_VIDEO_AVCLevel31 }, { 32, OMX_VIDEO_AVCLevel32 }, { 40, OMX_VIDEO_AVCLevel4 }, { 41, OMX_VIDEO_AVCLevel41 }, { 42, OMX_VIDEO_AVCLevel42 }, { 50, OMX_VIDEO_AVCLevel5 }, { 51, OMX_VIDEO_AVCLevel51 }, { 52, OMX_VIDEO_AVCLevel52 }, }; const static ALookup<uint8_t, OMX_VIDEO_AVCPROFILETYPE> profiles { { 66, OMX_VIDEO_AVCProfileBaseline }, { 77, OMX_VIDEO_AVCProfileMain }, { 88, OMX_VIDEO_AVCProfileExtended }, { 100, OMX_VIDEO_AVCProfileHigh }, { 110, OMX_VIDEO_AVCProfileHigh10 }, { 122, OMX_VIDEO_AVCProfileHigh422 }, { 244, OMX_VIDEO_AVCProfileHigh444 }, }; // set profile & level if they are recognized OMX_VIDEO_AVCPROFILETYPE codecProfile; OMX_VIDEO_AVCLEVELTYPE codecLevel; if (profiles.map(profile, &codecProfile)) { format->setInt32("profile", codecProfile); if (levels.map(level, &codecLevel)) { // for 9 && 11 decide level based on profile and constraint_set3 flag if (level == 11 && (profile == 66 || profile == 77 || profile == 88)) { codecLevel = (constraints & 0x10) ? OMX_VIDEO_AVCLevel1b : OMX_VIDEO_AVCLevel11; } format->setInt32("level", codecLevel); } } } static void parseH263ProfileLevelFromD263(const uint8_t *ptr, size_t size, sp<AMessage> &format) { if (size < 7) { return; } const uint8_t profile = ptr[6]; const uint8_t level = ptr[5]; const static ALookup<uint8_t, OMX_VIDEO_H263PROFILETYPE> profiles { { 0, OMX_VIDEO_H263ProfileBaseline }, { 1, OMX_VIDEO_H263ProfileH320Coding }, { 2, OMX_VIDEO_H263ProfileBackwardCompatible }, { 3, OMX_VIDEO_H263ProfileISWV2 }, { 4, OMX_VIDEO_H263ProfileISWV3 }, { 5, OMX_VIDEO_H263ProfileHighCompression }, { 6, OMX_VIDEO_H263ProfileInternet }, { 7, OMX_VIDEO_H263ProfileInterlace }, { 8, OMX_VIDEO_H263ProfileHighLatency }, }; const static ALookup<uint8_t, OMX_VIDEO_H263LEVELTYPE> levels { { 10, OMX_VIDEO_H263Level10 }, { 20, OMX_VIDEO_H263Level20 }, { 30, OMX_VIDEO_H263Level30 }, { 40, OMX_VIDEO_H263Level40 }, { 45, OMX_VIDEO_H263Level45 }, { 50, OMX_VIDEO_H263Level50 }, { 60, OMX_VIDEO_H263Level60 }, { 70, OMX_VIDEO_H263Level70 }, }; // set profile & level if they are recognized OMX_VIDEO_H263PROFILETYPE codecProfile; OMX_VIDEO_H263LEVELTYPE codecLevel; if (profiles.map(profile, &codecProfile)) { format->setInt32("profile", codecProfile); if (levels.map(level, &codecLevel)) { format->setInt32("level", codecLevel); } } } static void parseHevcProfileLevelFromHvcc(const uint8_t *ptr, size_t size, sp<AMessage> &format) { if (size < 13 || ptr[0] != 1) { // configurationVersion == 1 return; } const uint8_t profile = ptr[1] & 0x1F; const uint8_t tier = (ptr[1] & 0x20) >> 5; const uint8_t level = ptr[12]; const static ALookup<std::pair<uint8_t, uint8_t>, OMX_VIDEO_HEVCLEVELTYPE> levels { { { 0, 30 }, OMX_VIDEO_HEVCMainTierLevel1 }, { { 0, 60 }, OMX_VIDEO_HEVCMainTierLevel2 }, { { 0, 63 }, OMX_VIDEO_HEVCMainTierLevel21 }, { { 0, 90 }, OMX_VIDEO_HEVCMainTierLevel3 }, { { 0, 93 }, OMX_VIDEO_HEVCMainTierLevel31 }, { { 0, 120 }, OMX_VIDEO_HEVCMainTierLevel4 }, { { 0, 123 }, OMX_VIDEO_HEVCMainTierLevel41 }, { { 0, 150 }, OMX_VIDEO_HEVCMainTierLevel5 }, { { 0, 153 }, OMX_VIDEO_HEVCMainTierLevel51 }, { { 0, 156 }, OMX_VIDEO_HEVCMainTierLevel52 }, { { 0, 180 }, OMX_VIDEO_HEVCMainTierLevel6 }, { { 0, 183 }, OMX_VIDEO_HEVCMainTierLevel61 }, { { 0, 186 }, OMX_VIDEO_HEVCMainTierLevel62 }, { { 1, 30 }, OMX_VIDEO_HEVCHighTierLevel1 }, { { 1, 60 }, OMX_VIDEO_HEVCHighTierLevel2 }, { { 1, 63 }, OMX_VIDEO_HEVCHighTierLevel21 }, { { 1, 90 }, OMX_VIDEO_HEVCHighTierLevel3 }, { { 1, 93 }, OMX_VIDEO_HEVCHighTierLevel31 }, { { 1, 120 }, OMX_VIDEO_HEVCHighTierLevel4 }, { { 1, 123 }, OMX_VIDEO_HEVCHighTierLevel41 }, { { 1, 150 }, OMX_VIDEO_HEVCHighTierLevel5 }, { { 1, 153 }, OMX_VIDEO_HEVCHighTierLevel51 }, { { 1, 156 }, OMX_VIDEO_HEVCHighTierLevel52 }, { { 1, 180 }, OMX_VIDEO_HEVCHighTierLevel6 }, { { 1, 183 }, OMX_VIDEO_HEVCHighTierLevel61 }, { { 1, 186 }, OMX_VIDEO_HEVCHighTierLevel62 }, }; const static ALookup<uint8_t, OMX_VIDEO_HEVCPROFILETYPE> profiles { { 1, OMX_VIDEO_HEVCProfileMain }, { 2, OMX_VIDEO_HEVCProfileMain10 }, }; // set profile & level if they are recognized OMX_VIDEO_HEVCPROFILETYPE codecProfile; OMX_VIDEO_HEVCLEVELTYPE codecLevel; if (!profiles.map(profile, &codecProfile)) { if (ptr[2] & 0x40 /* general compatibility flag 1 */) { codecProfile = OMX_VIDEO_HEVCProfileMain; } else if (ptr[2] & 0x20 /* general compatibility flag 2 */) { codecProfile = OMX_VIDEO_HEVCProfileMain10; } else { return; } } format->setInt32("profile", codecProfile); if (levels.map(std::make_pair(tier, level), &codecLevel)) { format->setInt32("level", codecLevel); } } static void parseMpeg2ProfileLevelFromHeader( const uint8_t *data, size_t size, sp<AMessage> &format) { // find sequence extension const uint8_t *seq = (const uint8_t*)memmem(data, size, "\x00\x00\x01\xB5", 4); if (seq != NULL && seq + 5 < data + size) { const uint8_t start_code = seq[4] >> 4; if (start_code != 1 /* sequence extension ID */) { return; } const uint8_t indication = ((seq[4] & 0xF) << 4) | ((seq[5] & 0xF0) >> 4); const static ALookup<uint8_t, OMX_VIDEO_MPEG2PROFILETYPE> profiles { { 0x50, OMX_VIDEO_MPEG2ProfileSimple }, { 0x40, OMX_VIDEO_MPEG2ProfileMain }, { 0x30, OMX_VIDEO_MPEG2ProfileSNR }, { 0x20, OMX_VIDEO_MPEG2ProfileSpatial }, { 0x10, OMX_VIDEO_MPEG2ProfileHigh }, }; const static ALookup<uint8_t, OMX_VIDEO_MPEG2LEVELTYPE> levels { { 0x0A, OMX_VIDEO_MPEG2LevelLL }, { 0x08, OMX_VIDEO_MPEG2LevelML }, { 0x06, OMX_VIDEO_MPEG2LevelH14 }, { 0x04, OMX_VIDEO_MPEG2LevelHL }, { 0x02, OMX_VIDEO_MPEG2LevelHP }, }; const static ALookup<uint8_t, std::pair<OMX_VIDEO_MPEG2PROFILETYPE, OMX_VIDEO_MPEG2LEVELTYPE>> escapes { /* unsupported { 0x8E, { XXX_MPEG2ProfileMultiView, OMX_VIDEO_MPEG2LevelLL } }, { 0x8D, { XXX_MPEG2ProfileMultiView, OMX_VIDEO_MPEG2LevelML } }, { 0x8B, { XXX_MPEG2ProfileMultiView, OMX_VIDEO_MPEG2LevelH14 } }, { 0x8A, { XXX_MPEG2ProfileMultiView, OMX_VIDEO_MPEG2LevelHL } }, */ { 0x85, { OMX_VIDEO_MPEG2Profile422, OMX_VIDEO_MPEG2LevelML } }, { 0x82, { OMX_VIDEO_MPEG2Profile422, OMX_VIDEO_MPEG2LevelHL } }, }; OMX_VIDEO_MPEG2PROFILETYPE profile; OMX_VIDEO_MPEG2LEVELTYPE level; std::pair<OMX_VIDEO_MPEG2PROFILETYPE, OMX_VIDEO_MPEG2LEVELTYPE> profileLevel; if (escapes.map(indication, &profileLevel)) { format->setInt32("profile", profileLevel.first); format->setInt32("level", profileLevel.second); } else if (profiles.map(indication & 0x70, &profile)) { format->setInt32("profile", profile); if (levels.map(indication & 0xF, &level)) { format->setInt32("level", level); } } } } static void parseMpeg2ProfileLevelFromEsds(ESDS &esds, sp<AMessage> &format) { // esds seems to only contain the profile for MPEG-2 uint8_t objType; if (esds.getObjectTypeIndication(&objType) == OK) { const static ALookup<uint8_t, OMX_VIDEO_MPEG2PROFILETYPE> profiles{ { 0x60, OMX_VIDEO_MPEG2ProfileSimple }, { 0x61, OMX_VIDEO_MPEG2ProfileMain }, { 0x62, OMX_VIDEO_MPEG2ProfileSNR }, { 0x63, OMX_VIDEO_MPEG2ProfileSpatial }, { 0x64, OMX_VIDEO_MPEG2ProfileHigh }, { 0x65, OMX_VIDEO_MPEG2Profile422 }, }; OMX_VIDEO_MPEG2PROFILETYPE profile; if (profiles.map(objType, &profile)) { format->setInt32("profile", profile); } } } static void parseMpeg4ProfileLevelFromCsd(const sp<ABuffer> &csd, sp<AMessage> &format) { const uint8_t *data = csd->data(); // find visual object sequence const uint8_t *seq = (const uint8_t*)memmem(data, csd->size(), "\x00\x00\x01\xB0", 4); if (seq != NULL && seq + 4 < data + csd->size()) { const uint8_t indication = seq[4]; const static ALookup<uint8_t, std::pair<OMX_VIDEO_MPEG4PROFILETYPE, OMX_VIDEO_MPEG4LEVELTYPE>> table { { 0b00000001, { OMX_VIDEO_MPEG4ProfileSimple, OMX_VIDEO_MPEG4Level1 } }, { 0b00000010, { OMX_VIDEO_MPEG4ProfileSimple, OMX_VIDEO_MPEG4Level2 } }, { 0b00000011, { OMX_VIDEO_MPEG4ProfileSimple, OMX_VIDEO_MPEG4Level3 } }, { 0b00000100, { OMX_VIDEO_MPEG4ProfileSimple, OMX_VIDEO_MPEG4Level4a } }, { 0b00000101, { OMX_VIDEO_MPEG4ProfileSimple, OMX_VIDEO_MPEG4Level5 } }, { 0b00000110, { OMX_VIDEO_MPEG4ProfileSimple, OMX_VIDEO_MPEG4Level6 } }, { 0b00001000, { OMX_VIDEO_MPEG4ProfileSimple, OMX_VIDEO_MPEG4Level0 } }, { 0b00001001, { OMX_VIDEO_MPEG4ProfileSimple, OMX_VIDEO_MPEG4Level0b } }, { 0b00010000, { OMX_VIDEO_MPEG4ProfileSimpleScalable, OMX_VIDEO_MPEG4Level0 } }, { 0b00010001, { OMX_VIDEO_MPEG4ProfileSimpleScalable, OMX_VIDEO_MPEG4Level1 } }, { 0b00010010, { OMX_VIDEO_MPEG4ProfileSimpleScalable, OMX_VIDEO_MPEG4Level2 } }, /* unsupported { 0b00011101, { XXX_MPEG4ProfileSimpleScalableER, OMX_VIDEO_MPEG4Level0 } }, { 0b00011110, { XXX_MPEG4ProfileSimpleScalableER, OMX_VIDEO_MPEG4Level1 } }, { 0b00011111, { XXX_MPEG4ProfileSimpleScalableER, OMX_VIDEO_MPEG4Level2 } }, */ { 0b00100001, { OMX_VIDEO_MPEG4ProfileCore, OMX_VIDEO_MPEG4Level1 } }, { 0b00100010, { OMX_VIDEO_MPEG4ProfileCore, OMX_VIDEO_MPEG4Level2 } }, { 0b00110010, { OMX_VIDEO_MPEG4ProfileMain, OMX_VIDEO_MPEG4Level2 } }, { 0b00110011, { OMX_VIDEO_MPEG4ProfileMain, OMX_VIDEO_MPEG4Level3 } }, { 0b00110100, { OMX_VIDEO_MPEG4ProfileMain, OMX_VIDEO_MPEG4Level4 } }, /* deprecated { 0b01000010, { OMX_VIDEO_MPEG4ProfileNbit, OMX_VIDEO_MPEG4Level2 } }, */ { 0b01010001, { OMX_VIDEO_MPEG4ProfileScalableTexture, OMX_VIDEO_MPEG4Level1 } }, { 0b01100001, { OMX_VIDEO_MPEG4ProfileSimpleFace, OMX_VIDEO_MPEG4Level1 } }, { 0b01100010, { OMX_VIDEO_MPEG4ProfileSimpleFace, OMX_VIDEO_MPEG4Level2 } }, { 0b01100011, { OMX_VIDEO_MPEG4ProfileSimpleFBA, OMX_VIDEO_MPEG4Level1 } }, { 0b01100100, { OMX_VIDEO_MPEG4ProfileSimpleFBA, OMX_VIDEO_MPEG4Level2 } }, { 0b01110001, { OMX_VIDEO_MPEG4ProfileBasicAnimated, OMX_VIDEO_MPEG4Level1 } }, { 0b01110010, { OMX_VIDEO_MPEG4ProfileBasicAnimated, OMX_VIDEO_MPEG4Level2 } }, { 0b10000001, { OMX_VIDEO_MPEG4ProfileHybrid, OMX_VIDEO_MPEG4Level1 } }, { 0b10000010, { OMX_VIDEO_MPEG4ProfileHybrid, OMX_VIDEO_MPEG4Level2 } }, { 0b10010001, { OMX_VIDEO_MPEG4ProfileAdvancedRealTime, OMX_VIDEO_MPEG4Level1 } }, { 0b10010010, { OMX_VIDEO_MPEG4ProfileAdvancedRealTime, OMX_VIDEO_MPEG4Level2 } }, { 0b10010011, { OMX_VIDEO_MPEG4ProfileAdvancedRealTime, OMX_VIDEO_MPEG4Level3 } }, { 0b10010100, { OMX_VIDEO_MPEG4ProfileAdvancedRealTime, OMX_VIDEO_MPEG4Level4 } }, { 0b10100001, { OMX_VIDEO_MPEG4ProfileCoreScalable, OMX_VIDEO_MPEG4Level1 } }, { 0b10100010, { OMX_VIDEO_MPEG4ProfileCoreScalable, OMX_VIDEO_MPEG4Level2 } }, { 0b10100011, { OMX_VIDEO_MPEG4ProfileCoreScalable, OMX_VIDEO_MPEG4Level3 } }, { 0b10110001, { OMX_VIDEO_MPEG4ProfileAdvancedCoding, OMX_VIDEO_MPEG4Level1 } }, { 0b10110010, { OMX_VIDEO_MPEG4ProfileAdvancedCoding, OMX_VIDEO_MPEG4Level2 } }, { 0b10110011, { OMX_VIDEO_MPEG4ProfileAdvancedCoding, OMX_VIDEO_MPEG4Level3 } }, { 0b10110100, { OMX_VIDEO_MPEG4ProfileAdvancedCoding, OMX_VIDEO_MPEG4Level4 } }, { 0b11000001, { OMX_VIDEO_MPEG4ProfileAdvancedCore, OMX_VIDEO_MPEG4Level1 } }, { 0b11000010, { OMX_VIDEO_MPEG4ProfileAdvancedCore, OMX_VIDEO_MPEG4Level2 } }, { 0b11010001, { OMX_VIDEO_MPEG4ProfileAdvancedScalable, OMX_VIDEO_MPEG4Level1 } }, { 0b11010010, { OMX_VIDEO_MPEG4ProfileAdvancedScalable, OMX_VIDEO_MPEG4Level2 } }, { 0b11010011, { OMX_VIDEO_MPEG4ProfileAdvancedScalable, OMX_VIDEO_MPEG4Level3 } }, /* unsupported { 0b11100001, { XXX_MPEG4ProfileSimpleStudio, OMX_VIDEO_MPEG4Level1 } }, { 0b11100010, { XXX_MPEG4ProfileSimpleStudio, OMX_VIDEO_MPEG4Level2 } }, { 0b11100011, { XXX_MPEG4ProfileSimpleStudio, OMX_VIDEO_MPEG4Level3 } }, { 0b11100100, { XXX_MPEG4ProfileSimpleStudio, OMX_VIDEO_MPEG4Level4 } }, { 0b11100101, { XXX_MPEG4ProfileCoreStudio, OMX_VIDEO_MPEG4Level1 } }, { 0b11100110, { XXX_MPEG4ProfileCoreStudio, OMX_VIDEO_MPEG4Level2 } }, { 0b11100111, { XXX_MPEG4ProfileCoreStudio, OMX_VIDEO_MPEG4Level3 } }, { 0b11101000, { XXX_MPEG4ProfileCoreStudio, OMX_VIDEO_MPEG4Level4 } }, { 0b11101011, { XXX_MPEG4ProfileSimpleStudio, OMX_VIDEO_MPEG4Level5 } }, { 0b11101100, { XXX_MPEG4ProfileSimpleStudio, OMX_VIDEO_MPEG4Level6 } }, */ { 0b11110000, { OMX_VIDEO_MPEG4ProfileAdvancedSimple, OMX_VIDEO_MPEG4Level0 } }, { 0b11110001, { OMX_VIDEO_MPEG4ProfileAdvancedSimple, OMX_VIDEO_MPEG4Level1 } }, { 0b11110010, { OMX_VIDEO_MPEG4ProfileAdvancedSimple, OMX_VIDEO_MPEG4Level2 } }, { 0b11110011, { OMX_VIDEO_MPEG4ProfileAdvancedSimple, OMX_VIDEO_MPEG4Level3 } }, { 0b11110100, { OMX_VIDEO_MPEG4ProfileAdvancedSimple, OMX_VIDEO_MPEG4Level4 } }, { 0b11110101, { OMX_VIDEO_MPEG4ProfileAdvancedSimple, OMX_VIDEO_MPEG4Level5 } }, { 0b11110111, { OMX_VIDEO_MPEG4ProfileAdvancedSimple, OMX_VIDEO_MPEG4Level3b } }, /* deprecated { 0b11111000, { XXX_MPEG4ProfileFineGranularityScalable, OMX_VIDEO_MPEG4Level0 } }, { 0b11111001, { XXX_MPEG4ProfileFineGranularityScalable, OMX_VIDEO_MPEG4Level1 } }, { 0b11111010, { XXX_MPEG4ProfileFineGranularityScalable, OMX_VIDEO_MPEG4Level2 } }, { 0b11111011, { XXX_MPEG4ProfileFineGranularityScalable, OMX_VIDEO_MPEG4Level3 } }, { 0b11111100, { XXX_MPEG4ProfileFineGranularityScalable, OMX_VIDEO_MPEG4Level4 } }, { 0b11111101, { XXX_MPEG4ProfileFineGranularityScalable, OMX_VIDEO_MPEG4Level5 } }, */ }; std::pair<OMX_VIDEO_MPEG4PROFILETYPE, OMX_VIDEO_MPEG4LEVELTYPE> profileLevel; if (table.map(indication, &profileLevel)) { format->setInt32("profile", profileLevel.first); format->setInt32("level", profileLevel.second); } } } static void parseVp9ProfileLevelFromCsd(const sp<ABuffer> &csd, sp<AMessage> &format) { const uint8_t *data = csd->data(); size_t remaining = csd->size(); while (remaining >= 2) { const uint8_t id = data[0]; const uint8_t length = data[1]; remaining -= 2; data += 2; if (length > remaining) { break; } switch (id) { case 1 /* profileId */: if (length >= 1) { const static ALookup<uint8_t, OMX_VIDEO_VP9PROFILETYPE> profiles { { 0, OMX_VIDEO_VP9Profile0 }, { 1, OMX_VIDEO_VP9Profile1 }, { 2, OMX_VIDEO_VP9Profile2 }, { 3, OMX_VIDEO_VP9Profile3 }, }; OMX_VIDEO_VP9PROFILETYPE profile; if (profiles.map(data[0], &profile)) { format->setInt32("profile", profile); } } break; case 2 /* levelId */: if (length >= 1) { const static ALookup<uint8_t, OMX_VIDEO_VP9LEVELTYPE> levels { { 10, OMX_VIDEO_VP9Level1 }, { 11, OMX_VIDEO_VP9Level11 }, { 20, OMX_VIDEO_VP9Level2 }, { 21, OMX_VIDEO_VP9Level21 }, { 30, OMX_VIDEO_VP9Level3 }, { 31, OMX_VIDEO_VP9Level31 }, { 40, OMX_VIDEO_VP9Level4 }, { 41, OMX_VIDEO_VP9Level41 }, { 50, OMX_VIDEO_VP9Level5 }, { 51, OMX_VIDEO_VP9Level51 }, { 52, OMX_VIDEO_VP9Level52 }, { 60, OMX_VIDEO_VP9Level6 }, { 61, OMX_VIDEO_VP9Level61 }, { 62, OMX_VIDEO_VP9Level62 }, }; OMX_VIDEO_VP9LEVELTYPE level; if (levels.map(data[0], &level)) { format->setInt32("level", level); } } break; default: break; } remaining -= length; data += length; } } status_t convertMetaDataToMessage( const sp<MetaData> &meta, sp<AMessage> *format) { Loading Loading @@ -294,8 +711,8 @@ status_t convertMetaDataToMessage( ALOGE("b/23680780"); return BAD_VALUE; } uint8_t profile __unused = ptr[1]; uint8_t level __unused = ptr[3]; parseAvcProfileLevelFromAvcc(ptr, size, msg); // There is decodable content out there that fails the following // assertion, let's be lenient for now... Loading Loading @@ -391,12 +808,11 @@ status_t convertMetaDataToMessage( ALOGE("b/23680780"); return BAD_VALUE; } uint8_t profile __unused = ptr[1] & 31; uint8_t level __unused = ptr[12]; parseHevcProfileLevelFromHvcc(ptr, size, msg); ptr += 22; size -= 22; size_t numofArrays = (char)ptr[0]; ptr += 1; size -= 1; Loading Loading @@ -471,6 +887,17 @@ status_t convertMetaDataToMessage( buffer->meta()->setInt64("timeUs", 0); msg->setBuffer("csd-0", buffer); if (!strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_MPEG4)) { parseMpeg4ProfileLevelFromCsd(buffer, msg); } else if (!strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_MPEG2)) { parseMpeg2ProfileLevelFromEsds(esds, msg); if (meta->findData(kKeyStreamHeader, &type, &data, &size)) { parseMpeg2ProfileLevelFromHeader((uint8_t*)data, size, msg); } } else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AAC)) { parseAacProfileFromCsd(buffer, msg); } uint32_t maxBitrate, avgBitrate; if (esds.getBitRate(&maxBitrate, &avgBitrate) == OK) { if (!meta->hasData(kKeyMaxBitRate) Loading @@ -482,6 +909,9 @@ status_t convertMetaDataToMessage( msg->setInt32("bitrate", (int32_t)avgBitrate); } } } else if (meta->findData(kTypeD263, &type, &data, &size)) { const uint8_t *ptr = (const uint8_t *)data; parseH263ProfileLevelFromD263(ptr, size, msg); } else if (meta->findData(kKeyVorbisInfo, &type, &data, &size)) { sp<ABuffer> buffer = new (std::nothrow) ABuffer(size); if (buffer.get() == NULL || buffer->base() == NULL) { Loading Loading @@ -554,6 +984,8 @@ status_t convertMetaDataToMessage( buffer->meta()->setInt32("csd", true); buffer->meta()->setInt64("timeUs", 0); msg->setBuffer("csd-0", buffer); parseVp9ProfileLevelFromCsd(buffer, msg); } // TODO expose "crypto-key"/kKeyCryptoKey through public api Loading Loading
media/libstagefright/MPEG4Extractor.cpp +3 −2 Original line number Diff line number Diff line Loading @@ -1566,8 +1566,9 @@ status_t MPEG4Extractor::parseChunk(off64_t *offset, int depth) { const char *mime; CHECK(mLastTrack->meta->findCString(kKeyMIMEType, &mime)); if (!strcmp(mime, MEDIA_MIMETYPE_VIDEO_AVC)) { // AVC requires compression ratio of at least 2, and uses if (!strcmp(mime, MEDIA_MIMETYPE_VIDEO_AVC) || !strcmp(mime, MEDIA_MIMETYPE_VIDEO_HEVC)) { // AVC & HEVC requires compression ratio of at least 2, and uses // macroblocks max_size = ((width + 15) / 16) * ((height + 15) / 16) * 192; } else { Loading
media/libstagefright/MPEG4Writer.cpp +1 −0 Original line number Diff line number Diff line Loading @@ -1957,6 +1957,7 @@ const uint8_t *MPEG4Writer::Track::parseParamSet( if (mProfileIdc != data[1] || mProfileCompatible != data[2] || mLevelIdc != data[3]) { // COULD DO: set profile/level to the lowest required to support all SPSs ALOGE("Inconsistent profile/level found in seq parameter sets"); return NULL; } Loading
media/libstagefright/Utils.cpp +437 −5 Original line number Diff line number Diff line Loading @@ -21,15 +21,20 @@ #include <stdio.h> #include <sys/stat.h> #include <utility> #include "include/ESDS.h" #include "include/HevcUtils.h" #include <arpa/inet.h> #include <cutils/properties.h> #include <media/openmax/OMX_Audio.h> #include <media/openmax/OMX_Video.h> #include <media/openmax/OMX_VideoExt.h> #include <media/stagefright/CodecBase.h> #include <media/stagefright/foundation/ABuffer.h> #include <media/stagefright/foundation/ADebug.h> #include <media/stagefright/foundation/ALookup.h> #include <media/stagefright/foundation/AMessage.h> #include <media/stagefright/MetaData.h> #include <media/stagefright/MediaDefs.h> Loading Loading @@ -134,6 +139,418 @@ static void convertMetaDataToMessageColorAspects(const sp<MetaData> &meta, sp<AM } } static void parseAacProfileFromCsd(const sp<ABuffer> &csd, sp<AMessage> &format) { if (csd->size() < 2) { return; } uint16_t audioObjectType = U16_AT((uint8_t*)csd->data()); if ((audioObjectType & 0xF800) == 0xF800) { audioObjectType = 32 + ((audioObjectType >> 5) & 0x3F); } else { audioObjectType >>= 11; } const static ALookup<uint16_t, OMX_AUDIO_AACPROFILETYPE> profiles { { 1, OMX_AUDIO_AACObjectMain }, { 2, OMX_AUDIO_AACObjectLC }, { 3, OMX_AUDIO_AACObjectSSR }, { 4, OMX_AUDIO_AACObjectLTP }, { 5, OMX_AUDIO_AACObjectHE }, { 6, OMX_AUDIO_AACObjectScalable }, { 17, OMX_AUDIO_AACObjectERLC }, { 23, OMX_AUDIO_AACObjectLD }, { 29, OMX_AUDIO_AACObjectHE_PS }, { 39, OMX_AUDIO_AACObjectELD }, }; OMX_AUDIO_AACPROFILETYPE profile; if (profiles.map(audioObjectType, &profile)) { format->setInt32("profile", profile); } } static void parseAvcProfileLevelFromAvcc(const uint8_t *ptr, size_t size, sp<AMessage> &format) { if (size < 4 || ptr[0] != 1) { // configurationVersion == 1 return; } const uint8_t profile = ptr[1]; const uint8_t constraints = ptr[2]; const uint8_t level = ptr[3]; const static ALookup<uint8_t, OMX_VIDEO_AVCLEVELTYPE> levels { { 9, OMX_VIDEO_AVCLevel1b }, // technically, 9 is only used for High+ profiles { 10, OMX_VIDEO_AVCLevel1 }, { 11, OMX_VIDEO_AVCLevel11 }, // prefer level 1.1 for the value 11 { 11, OMX_VIDEO_AVCLevel1b }, { 12, OMX_VIDEO_AVCLevel12 }, { 13, OMX_VIDEO_AVCLevel13 }, { 20, OMX_VIDEO_AVCLevel2 }, { 21, OMX_VIDEO_AVCLevel21 }, { 22, OMX_VIDEO_AVCLevel22 }, { 30, OMX_VIDEO_AVCLevel3 }, { 31, OMX_VIDEO_AVCLevel31 }, { 32, OMX_VIDEO_AVCLevel32 }, { 40, OMX_VIDEO_AVCLevel4 }, { 41, OMX_VIDEO_AVCLevel41 }, { 42, OMX_VIDEO_AVCLevel42 }, { 50, OMX_VIDEO_AVCLevel5 }, { 51, OMX_VIDEO_AVCLevel51 }, { 52, OMX_VIDEO_AVCLevel52 }, }; const static ALookup<uint8_t, OMX_VIDEO_AVCPROFILETYPE> profiles { { 66, OMX_VIDEO_AVCProfileBaseline }, { 77, OMX_VIDEO_AVCProfileMain }, { 88, OMX_VIDEO_AVCProfileExtended }, { 100, OMX_VIDEO_AVCProfileHigh }, { 110, OMX_VIDEO_AVCProfileHigh10 }, { 122, OMX_VIDEO_AVCProfileHigh422 }, { 244, OMX_VIDEO_AVCProfileHigh444 }, }; // set profile & level if they are recognized OMX_VIDEO_AVCPROFILETYPE codecProfile; OMX_VIDEO_AVCLEVELTYPE codecLevel; if (profiles.map(profile, &codecProfile)) { format->setInt32("profile", codecProfile); if (levels.map(level, &codecLevel)) { // for 9 && 11 decide level based on profile and constraint_set3 flag if (level == 11 && (profile == 66 || profile == 77 || profile == 88)) { codecLevel = (constraints & 0x10) ? OMX_VIDEO_AVCLevel1b : OMX_VIDEO_AVCLevel11; } format->setInt32("level", codecLevel); } } } static void parseH263ProfileLevelFromD263(const uint8_t *ptr, size_t size, sp<AMessage> &format) { if (size < 7) { return; } const uint8_t profile = ptr[6]; const uint8_t level = ptr[5]; const static ALookup<uint8_t, OMX_VIDEO_H263PROFILETYPE> profiles { { 0, OMX_VIDEO_H263ProfileBaseline }, { 1, OMX_VIDEO_H263ProfileH320Coding }, { 2, OMX_VIDEO_H263ProfileBackwardCompatible }, { 3, OMX_VIDEO_H263ProfileISWV2 }, { 4, OMX_VIDEO_H263ProfileISWV3 }, { 5, OMX_VIDEO_H263ProfileHighCompression }, { 6, OMX_VIDEO_H263ProfileInternet }, { 7, OMX_VIDEO_H263ProfileInterlace }, { 8, OMX_VIDEO_H263ProfileHighLatency }, }; const static ALookup<uint8_t, OMX_VIDEO_H263LEVELTYPE> levels { { 10, OMX_VIDEO_H263Level10 }, { 20, OMX_VIDEO_H263Level20 }, { 30, OMX_VIDEO_H263Level30 }, { 40, OMX_VIDEO_H263Level40 }, { 45, OMX_VIDEO_H263Level45 }, { 50, OMX_VIDEO_H263Level50 }, { 60, OMX_VIDEO_H263Level60 }, { 70, OMX_VIDEO_H263Level70 }, }; // set profile & level if they are recognized OMX_VIDEO_H263PROFILETYPE codecProfile; OMX_VIDEO_H263LEVELTYPE codecLevel; if (profiles.map(profile, &codecProfile)) { format->setInt32("profile", codecProfile); if (levels.map(level, &codecLevel)) { format->setInt32("level", codecLevel); } } } static void parseHevcProfileLevelFromHvcc(const uint8_t *ptr, size_t size, sp<AMessage> &format) { if (size < 13 || ptr[0] != 1) { // configurationVersion == 1 return; } const uint8_t profile = ptr[1] & 0x1F; const uint8_t tier = (ptr[1] & 0x20) >> 5; const uint8_t level = ptr[12]; const static ALookup<std::pair<uint8_t, uint8_t>, OMX_VIDEO_HEVCLEVELTYPE> levels { { { 0, 30 }, OMX_VIDEO_HEVCMainTierLevel1 }, { { 0, 60 }, OMX_VIDEO_HEVCMainTierLevel2 }, { { 0, 63 }, OMX_VIDEO_HEVCMainTierLevel21 }, { { 0, 90 }, OMX_VIDEO_HEVCMainTierLevel3 }, { { 0, 93 }, OMX_VIDEO_HEVCMainTierLevel31 }, { { 0, 120 }, OMX_VIDEO_HEVCMainTierLevel4 }, { { 0, 123 }, OMX_VIDEO_HEVCMainTierLevel41 }, { { 0, 150 }, OMX_VIDEO_HEVCMainTierLevel5 }, { { 0, 153 }, OMX_VIDEO_HEVCMainTierLevel51 }, { { 0, 156 }, OMX_VIDEO_HEVCMainTierLevel52 }, { { 0, 180 }, OMX_VIDEO_HEVCMainTierLevel6 }, { { 0, 183 }, OMX_VIDEO_HEVCMainTierLevel61 }, { { 0, 186 }, OMX_VIDEO_HEVCMainTierLevel62 }, { { 1, 30 }, OMX_VIDEO_HEVCHighTierLevel1 }, { { 1, 60 }, OMX_VIDEO_HEVCHighTierLevel2 }, { { 1, 63 }, OMX_VIDEO_HEVCHighTierLevel21 }, { { 1, 90 }, OMX_VIDEO_HEVCHighTierLevel3 }, { { 1, 93 }, OMX_VIDEO_HEVCHighTierLevel31 }, { { 1, 120 }, OMX_VIDEO_HEVCHighTierLevel4 }, { { 1, 123 }, OMX_VIDEO_HEVCHighTierLevel41 }, { { 1, 150 }, OMX_VIDEO_HEVCHighTierLevel5 }, { { 1, 153 }, OMX_VIDEO_HEVCHighTierLevel51 }, { { 1, 156 }, OMX_VIDEO_HEVCHighTierLevel52 }, { { 1, 180 }, OMX_VIDEO_HEVCHighTierLevel6 }, { { 1, 183 }, OMX_VIDEO_HEVCHighTierLevel61 }, { { 1, 186 }, OMX_VIDEO_HEVCHighTierLevel62 }, }; const static ALookup<uint8_t, OMX_VIDEO_HEVCPROFILETYPE> profiles { { 1, OMX_VIDEO_HEVCProfileMain }, { 2, OMX_VIDEO_HEVCProfileMain10 }, }; // set profile & level if they are recognized OMX_VIDEO_HEVCPROFILETYPE codecProfile; OMX_VIDEO_HEVCLEVELTYPE codecLevel; if (!profiles.map(profile, &codecProfile)) { if (ptr[2] & 0x40 /* general compatibility flag 1 */) { codecProfile = OMX_VIDEO_HEVCProfileMain; } else if (ptr[2] & 0x20 /* general compatibility flag 2 */) { codecProfile = OMX_VIDEO_HEVCProfileMain10; } else { return; } } format->setInt32("profile", codecProfile); if (levels.map(std::make_pair(tier, level), &codecLevel)) { format->setInt32("level", codecLevel); } } static void parseMpeg2ProfileLevelFromHeader( const uint8_t *data, size_t size, sp<AMessage> &format) { // find sequence extension const uint8_t *seq = (const uint8_t*)memmem(data, size, "\x00\x00\x01\xB5", 4); if (seq != NULL && seq + 5 < data + size) { const uint8_t start_code = seq[4] >> 4; if (start_code != 1 /* sequence extension ID */) { return; } const uint8_t indication = ((seq[4] & 0xF) << 4) | ((seq[5] & 0xF0) >> 4); const static ALookup<uint8_t, OMX_VIDEO_MPEG2PROFILETYPE> profiles { { 0x50, OMX_VIDEO_MPEG2ProfileSimple }, { 0x40, OMX_VIDEO_MPEG2ProfileMain }, { 0x30, OMX_VIDEO_MPEG2ProfileSNR }, { 0x20, OMX_VIDEO_MPEG2ProfileSpatial }, { 0x10, OMX_VIDEO_MPEG2ProfileHigh }, }; const static ALookup<uint8_t, OMX_VIDEO_MPEG2LEVELTYPE> levels { { 0x0A, OMX_VIDEO_MPEG2LevelLL }, { 0x08, OMX_VIDEO_MPEG2LevelML }, { 0x06, OMX_VIDEO_MPEG2LevelH14 }, { 0x04, OMX_VIDEO_MPEG2LevelHL }, { 0x02, OMX_VIDEO_MPEG2LevelHP }, }; const static ALookup<uint8_t, std::pair<OMX_VIDEO_MPEG2PROFILETYPE, OMX_VIDEO_MPEG2LEVELTYPE>> escapes { /* unsupported { 0x8E, { XXX_MPEG2ProfileMultiView, OMX_VIDEO_MPEG2LevelLL } }, { 0x8D, { XXX_MPEG2ProfileMultiView, OMX_VIDEO_MPEG2LevelML } }, { 0x8B, { XXX_MPEG2ProfileMultiView, OMX_VIDEO_MPEG2LevelH14 } }, { 0x8A, { XXX_MPEG2ProfileMultiView, OMX_VIDEO_MPEG2LevelHL } }, */ { 0x85, { OMX_VIDEO_MPEG2Profile422, OMX_VIDEO_MPEG2LevelML } }, { 0x82, { OMX_VIDEO_MPEG2Profile422, OMX_VIDEO_MPEG2LevelHL } }, }; OMX_VIDEO_MPEG2PROFILETYPE profile; OMX_VIDEO_MPEG2LEVELTYPE level; std::pair<OMX_VIDEO_MPEG2PROFILETYPE, OMX_VIDEO_MPEG2LEVELTYPE> profileLevel; if (escapes.map(indication, &profileLevel)) { format->setInt32("profile", profileLevel.first); format->setInt32("level", profileLevel.second); } else if (profiles.map(indication & 0x70, &profile)) { format->setInt32("profile", profile); if (levels.map(indication & 0xF, &level)) { format->setInt32("level", level); } } } } static void parseMpeg2ProfileLevelFromEsds(ESDS &esds, sp<AMessage> &format) { // esds seems to only contain the profile for MPEG-2 uint8_t objType; if (esds.getObjectTypeIndication(&objType) == OK) { const static ALookup<uint8_t, OMX_VIDEO_MPEG2PROFILETYPE> profiles{ { 0x60, OMX_VIDEO_MPEG2ProfileSimple }, { 0x61, OMX_VIDEO_MPEG2ProfileMain }, { 0x62, OMX_VIDEO_MPEG2ProfileSNR }, { 0x63, OMX_VIDEO_MPEG2ProfileSpatial }, { 0x64, OMX_VIDEO_MPEG2ProfileHigh }, { 0x65, OMX_VIDEO_MPEG2Profile422 }, }; OMX_VIDEO_MPEG2PROFILETYPE profile; if (profiles.map(objType, &profile)) { format->setInt32("profile", profile); } } } static void parseMpeg4ProfileLevelFromCsd(const sp<ABuffer> &csd, sp<AMessage> &format) { const uint8_t *data = csd->data(); // find visual object sequence const uint8_t *seq = (const uint8_t*)memmem(data, csd->size(), "\x00\x00\x01\xB0", 4); if (seq != NULL && seq + 4 < data + csd->size()) { const uint8_t indication = seq[4]; const static ALookup<uint8_t, std::pair<OMX_VIDEO_MPEG4PROFILETYPE, OMX_VIDEO_MPEG4LEVELTYPE>> table { { 0b00000001, { OMX_VIDEO_MPEG4ProfileSimple, OMX_VIDEO_MPEG4Level1 } }, { 0b00000010, { OMX_VIDEO_MPEG4ProfileSimple, OMX_VIDEO_MPEG4Level2 } }, { 0b00000011, { OMX_VIDEO_MPEG4ProfileSimple, OMX_VIDEO_MPEG4Level3 } }, { 0b00000100, { OMX_VIDEO_MPEG4ProfileSimple, OMX_VIDEO_MPEG4Level4a } }, { 0b00000101, { OMX_VIDEO_MPEG4ProfileSimple, OMX_VIDEO_MPEG4Level5 } }, { 0b00000110, { OMX_VIDEO_MPEG4ProfileSimple, OMX_VIDEO_MPEG4Level6 } }, { 0b00001000, { OMX_VIDEO_MPEG4ProfileSimple, OMX_VIDEO_MPEG4Level0 } }, { 0b00001001, { OMX_VIDEO_MPEG4ProfileSimple, OMX_VIDEO_MPEG4Level0b } }, { 0b00010000, { OMX_VIDEO_MPEG4ProfileSimpleScalable, OMX_VIDEO_MPEG4Level0 } }, { 0b00010001, { OMX_VIDEO_MPEG4ProfileSimpleScalable, OMX_VIDEO_MPEG4Level1 } }, { 0b00010010, { OMX_VIDEO_MPEG4ProfileSimpleScalable, OMX_VIDEO_MPEG4Level2 } }, /* unsupported { 0b00011101, { XXX_MPEG4ProfileSimpleScalableER, OMX_VIDEO_MPEG4Level0 } }, { 0b00011110, { XXX_MPEG4ProfileSimpleScalableER, OMX_VIDEO_MPEG4Level1 } }, { 0b00011111, { XXX_MPEG4ProfileSimpleScalableER, OMX_VIDEO_MPEG4Level2 } }, */ { 0b00100001, { OMX_VIDEO_MPEG4ProfileCore, OMX_VIDEO_MPEG4Level1 } }, { 0b00100010, { OMX_VIDEO_MPEG4ProfileCore, OMX_VIDEO_MPEG4Level2 } }, { 0b00110010, { OMX_VIDEO_MPEG4ProfileMain, OMX_VIDEO_MPEG4Level2 } }, { 0b00110011, { OMX_VIDEO_MPEG4ProfileMain, OMX_VIDEO_MPEG4Level3 } }, { 0b00110100, { OMX_VIDEO_MPEG4ProfileMain, OMX_VIDEO_MPEG4Level4 } }, /* deprecated { 0b01000010, { OMX_VIDEO_MPEG4ProfileNbit, OMX_VIDEO_MPEG4Level2 } }, */ { 0b01010001, { OMX_VIDEO_MPEG4ProfileScalableTexture, OMX_VIDEO_MPEG4Level1 } }, { 0b01100001, { OMX_VIDEO_MPEG4ProfileSimpleFace, OMX_VIDEO_MPEG4Level1 } }, { 0b01100010, { OMX_VIDEO_MPEG4ProfileSimpleFace, OMX_VIDEO_MPEG4Level2 } }, { 0b01100011, { OMX_VIDEO_MPEG4ProfileSimpleFBA, OMX_VIDEO_MPEG4Level1 } }, { 0b01100100, { OMX_VIDEO_MPEG4ProfileSimpleFBA, OMX_VIDEO_MPEG4Level2 } }, { 0b01110001, { OMX_VIDEO_MPEG4ProfileBasicAnimated, OMX_VIDEO_MPEG4Level1 } }, { 0b01110010, { OMX_VIDEO_MPEG4ProfileBasicAnimated, OMX_VIDEO_MPEG4Level2 } }, { 0b10000001, { OMX_VIDEO_MPEG4ProfileHybrid, OMX_VIDEO_MPEG4Level1 } }, { 0b10000010, { OMX_VIDEO_MPEG4ProfileHybrid, OMX_VIDEO_MPEG4Level2 } }, { 0b10010001, { OMX_VIDEO_MPEG4ProfileAdvancedRealTime, OMX_VIDEO_MPEG4Level1 } }, { 0b10010010, { OMX_VIDEO_MPEG4ProfileAdvancedRealTime, OMX_VIDEO_MPEG4Level2 } }, { 0b10010011, { OMX_VIDEO_MPEG4ProfileAdvancedRealTime, OMX_VIDEO_MPEG4Level3 } }, { 0b10010100, { OMX_VIDEO_MPEG4ProfileAdvancedRealTime, OMX_VIDEO_MPEG4Level4 } }, { 0b10100001, { OMX_VIDEO_MPEG4ProfileCoreScalable, OMX_VIDEO_MPEG4Level1 } }, { 0b10100010, { OMX_VIDEO_MPEG4ProfileCoreScalable, OMX_VIDEO_MPEG4Level2 } }, { 0b10100011, { OMX_VIDEO_MPEG4ProfileCoreScalable, OMX_VIDEO_MPEG4Level3 } }, { 0b10110001, { OMX_VIDEO_MPEG4ProfileAdvancedCoding, OMX_VIDEO_MPEG4Level1 } }, { 0b10110010, { OMX_VIDEO_MPEG4ProfileAdvancedCoding, OMX_VIDEO_MPEG4Level2 } }, { 0b10110011, { OMX_VIDEO_MPEG4ProfileAdvancedCoding, OMX_VIDEO_MPEG4Level3 } }, { 0b10110100, { OMX_VIDEO_MPEG4ProfileAdvancedCoding, OMX_VIDEO_MPEG4Level4 } }, { 0b11000001, { OMX_VIDEO_MPEG4ProfileAdvancedCore, OMX_VIDEO_MPEG4Level1 } }, { 0b11000010, { OMX_VIDEO_MPEG4ProfileAdvancedCore, OMX_VIDEO_MPEG4Level2 } }, { 0b11010001, { OMX_VIDEO_MPEG4ProfileAdvancedScalable, OMX_VIDEO_MPEG4Level1 } }, { 0b11010010, { OMX_VIDEO_MPEG4ProfileAdvancedScalable, OMX_VIDEO_MPEG4Level2 } }, { 0b11010011, { OMX_VIDEO_MPEG4ProfileAdvancedScalable, OMX_VIDEO_MPEG4Level3 } }, /* unsupported { 0b11100001, { XXX_MPEG4ProfileSimpleStudio, OMX_VIDEO_MPEG4Level1 } }, { 0b11100010, { XXX_MPEG4ProfileSimpleStudio, OMX_VIDEO_MPEG4Level2 } }, { 0b11100011, { XXX_MPEG4ProfileSimpleStudio, OMX_VIDEO_MPEG4Level3 } }, { 0b11100100, { XXX_MPEG4ProfileSimpleStudio, OMX_VIDEO_MPEG4Level4 } }, { 0b11100101, { XXX_MPEG4ProfileCoreStudio, OMX_VIDEO_MPEG4Level1 } }, { 0b11100110, { XXX_MPEG4ProfileCoreStudio, OMX_VIDEO_MPEG4Level2 } }, { 0b11100111, { XXX_MPEG4ProfileCoreStudio, OMX_VIDEO_MPEG4Level3 } }, { 0b11101000, { XXX_MPEG4ProfileCoreStudio, OMX_VIDEO_MPEG4Level4 } }, { 0b11101011, { XXX_MPEG4ProfileSimpleStudio, OMX_VIDEO_MPEG4Level5 } }, { 0b11101100, { XXX_MPEG4ProfileSimpleStudio, OMX_VIDEO_MPEG4Level6 } }, */ { 0b11110000, { OMX_VIDEO_MPEG4ProfileAdvancedSimple, OMX_VIDEO_MPEG4Level0 } }, { 0b11110001, { OMX_VIDEO_MPEG4ProfileAdvancedSimple, OMX_VIDEO_MPEG4Level1 } }, { 0b11110010, { OMX_VIDEO_MPEG4ProfileAdvancedSimple, OMX_VIDEO_MPEG4Level2 } }, { 0b11110011, { OMX_VIDEO_MPEG4ProfileAdvancedSimple, OMX_VIDEO_MPEG4Level3 } }, { 0b11110100, { OMX_VIDEO_MPEG4ProfileAdvancedSimple, OMX_VIDEO_MPEG4Level4 } }, { 0b11110101, { OMX_VIDEO_MPEG4ProfileAdvancedSimple, OMX_VIDEO_MPEG4Level5 } }, { 0b11110111, { OMX_VIDEO_MPEG4ProfileAdvancedSimple, OMX_VIDEO_MPEG4Level3b } }, /* deprecated { 0b11111000, { XXX_MPEG4ProfileFineGranularityScalable, OMX_VIDEO_MPEG4Level0 } }, { 0b11111001, { XXX_MPEG4ProfileFineGranularityScalable, OMX_VIDEO_MPEG4Level1 } }, { 0b11111010, { XXX_MPEG4ProfileFineGranularityScalable, OMX_VIDEO_MPEG4Level2 } }, { 0b11111011, { XXX_MPEG4ProfileFineGranularityScalable, OMX_VIDEO_MPEG4Level3 } }, { 0b11111100, { XXX_MPEG4ProfileFineGranularityScalable, OMX_VIDEO_MPEG4Level4 } }, { 0b11111101, { XXX_MPEG4ProfileFineGranularityScalable, OMX_VIDEO_MPEG4Level5 } }, */ }; std::pair<OMX_VIDEO_MPEG4PROFILETYPE, OMX_VIDEO_MPEG4LEVELTYPE> profileLevel; if (table.map(indication, &profileLevel)) { format->setInt32("profile", profileLevel.first); format->setInt32("level", profileLevel.second); } } } static void parseVp9ProfileLevelFromCsd(const sp<ABuffer> &csd, sp<AMessage> &format) { const uint8_t *data = csd->data(); size_t remaining = csd->size(); while (remaining >= 2) { const uint8_t id = data[0]; const uint8_t length = data[1]; remaining -= 2; data += 2; if (length > remaining) { break; } switch (id) { case 1 /* profileId */: if (length >= 1) { const static ALookup<uint8_t, OMX_VIDEO_VP9PROFILETYPE> profiles { { 0, OMX_VIDEO_VP9Profile0 }, { 1, OMX_VIDEO_VP9Profile1 }, { 2, OMX_VIDEO_VP9Profile2 }, { 3, OMX_VIDEO_VP9Profile3 }, }; OMX_VIDEO_VP9PROFILETYPE profile; if (profiles.map(data[0], &profile)) { format->setInt32("profile", profile); } } break; case 2 /* levelId */: if (length >= 1) { const static ALookup<uint8_t, OMX_VIDEO_VP9LEVELTYPE> levels { { 10, OMX_VIDEO_VP9Level1 }, { 11, OMX_VIDEO_VP9Level11 }, { 20, OMX_VIDEO_VP9Level2 }, { 21, OMX_VIDEO_VP9Level21 }, { 30, OMX_VIDEO_VP9Level3 }, { 31, OMX_VIDEO_VP9Level31 }, { 40, OMX_VIDEO_VP9Level4 }, { 41, OMX_VIDEO_VP9Level41 }, { 50, OMX_VIDEO_VP9Level5 }, { 51, OMX_VIDEO_VP9Level51 }, { 52, OMX_VIDEO_VP9Level52 }, { 60, OMX_VIDEO_VP9Level6 }, { 61, OMX_VIDEO_VP9Level61 }, { 62, OMX_VIDEO_VP9Level62 }, }; OMX_VIDEO_VP9LEVELTYPE level; if (levels.map(data[0], &level)) { format->setInt32("level", level); } } break; default: break; } remaining -= length; data += length; } } status_t convertMetaDataToMessage( const sp<MetaData> &meta, sp<AMessage> *format) { Loading Loading @@ -294,8 +711,8 @@ status_t convertMetaDataToMessage( ALOGE("b/23680780"); return BAD_VALUE; } uint8_t profile __unused = ptr[1]; uint8_t level __unused = ptr[3]; parseAvcProfileLevelFromAvcc(ptr, size, msg); // There is decodable content out there that fails the following // assertion, let's be lenient for now... Loading Loading @@ -391,12 +808,11 @@ status_t convertMetaDataToMessage( ALOGE("b/23680780"); return BAD_VALUE; } uint8_t profile __unused = ptr[1] & 31; uint8_t level __unused = ptr[12]; parseHevcProfileLevelFromHvcc(ptr, size, msg); ptr += 22; size -= 22; size_t numofArrays = (char)ptr[0]; ptr += 1; size -= 1; Loading Loading @@ -471,6 +887,17 @@ status_t convertMetaDataToMessage( buffer->meta()->setInt64("timeUs", 0); msg->setBuffer("csd-0", buffer); if (!strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_MPEG4)) { parseMpeg4ProfileLevelFromCsd(buffer, msg); } else if (!strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_MPEG2)) { parseMpeg2ProfileLevelFromEsds(esds, msg); if (meta->findData(kKeyStreamHeader, &type, &data, &size)) { parseMpeg2ProfileLevelFromHeader((uint8_t*)data, size, msg); } } else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AAC)) { parseAacProfileFromCsd(buffer, msg); } uint32_t maxBitrate, avgBitrate; if (esds.getBitRate(&maxBitrate, &avgBitrate) == OK) { if (!meta->hasData(kKeyMaxBitRate) Loading @@ -482,6 +909,9 @@ status_t convertMetaDataToMessage( msg->setInt32("bitrate", (int32_t)avgBitrate); } } } else if (meta->findData(kTypeD263, &type, &data, &size)) { const uint8_t *ptr = (const uint8_t *)data; parseH263ProfileLevelFromD263(ptr, size, msg); } else if (meta->findData(kKeyVorbisInfo, &type, &data, &size)) { sp<ABuffer> buffer = new (std::nothrow) ABuffer(size); if (buffer.get() == NULL || buffer->base() == NULL) { Loading Loading @@ -554,6 +984,8 @@ status_t convertMetaDataToMessage( buffer->meta()->setInt32("csd", true); buffer->meta()->setInt64("timeUs", 0); msg->setBuffer("csd-0", buffer); parseVp9ProfileLevelFromCsd(buffer, msg); } // TODO expose "crypto-key"/kKeyCryptoKey through public api Loading