diff options
author | James Cheng <jacheng@mozilla.com> | 2022-05-02 14:06:50 -0500 |
---|---|---|
committer | Matt A. Tobin <email@mattatobin.com> | 2022-05-02 14:07:05 -0500 |
commit | b405e6878e4e303f7fbe51035e251f51a2eb5887 (patch) | |
tree | 2870557f837688b1eb31329e09d3bcaaa294a65d | |
parent | b17c689b521e44fcf6cbc0ffaa5b635466c95671 (diff) | |
download | aura-central-b405e6878e4e303f7fbe51035e251f51a2eb5887.tar.gz |
Issue #28 - Support new RFC-6381 VPx codec strings
* Add an extraction function to parse the RFC-6381 VP9 codec string.
* Add VP9-in-MP4 support to the decoder
* Use Codec detail extractor helper to tell if it's a new style VP8/VP9 codec string.
* Add a gtest for testing the extraction function.
* Add mBitDepth field to VideoInfo.
* Extract bit depth information from codec parameter string into VideoInfo::mBitDepth.
* Check bit depth in WebMDecoder to determine if we support HDR.
* Add an extraction function to parse the RFC-6381 VP9 codec string.
Based on Bug 1407919
-rw-r--r-- | dom/media/MediaInfo.h | 4 | ||||
-rw-r--r-- | dom/media/VideoUtils.cpp | 189 | ||||
-rw-r--r-- | dom/media/VideoUtils.h | 28 | ||||
-rw-r--r-- | dom/media/fmp4/MP4Decoder.cpp | 13 | ||||
-rw-r--r-- | dom/media/mediasource/gtest/TestExtractVPXCodecDetails.cpp | 111 | ||||
-rw-r--r-- | dom/media/mediasource/gtest/moz.build | 1 | ||||
-rw-r--r-- | dom/media/platforms/PlatformDecoderModule.h | 17 | ||||
-rw-r--r-- | dom/media/platforms/ffmpeg/FFmpegDecoderModule.h | 15 | ||||
-rw-r--r-- | dom/media/platforms/wmf/WMFDecoderModule.cpp | 10 | ||||
-rw-r--r-- | dom/media/webm/WebMDecoder.cpp | 30 | ||||
-rw-r--r-- | libs/libstagefright/frameworks/av/media/libstagefright/MPEG4Extractor.cpp | 3 | ||||
-rw-r--r-- | libs/libstagefright/frameworks/av/media/libstagefright/MediaDefs.cpp | 2 |
12 files changed, 410 insertions, 13 deletions
diff --git a/dom/media/MediaInfo.h b/dom/media/MediaInfo.h index 29dcf2cc9..4d37dd674 100644 --- a/dom/media/MediaInfo.h +++ b/dom/media/MediaInfo.h @@ -210,6 +210,7 @@ public: , mCodecSpecificConfig(aOther.mCodecSpecificConfig) , mExtraData(aOther.mExtraData) , mRotation(aOther.mRotation) + , mBitDepth(aOther.mBitDepth) , mImageRect(aOther.mImageRect) { } @@ -300,6 +301,9 @@ public: // Describing how many degrees video frames should be rotated in clock-wise to // get correct view. Rotation mRotation; + + // Bits per channel -- Should be 8, 10 or 12. Default value is 8. + uint8_t mBitDepth = 8; private: // mImage may be cropped; currently only used with the WebM container. diff --git a/dom/media/VideoUtils.cpp b/dom/media/VideoUtils.cpp index 56033c2fa..cc8d56146 100644 --- a/dom/media/VideoUtils.cpp +++ b/dom/media/VideoUtils.cpp @@ -223,12 +223,185 @@ already_AddRefed<SharedThreadPool> GetMediaThreadPool(MediaThreadType aType) } bool +ExtractVPXCodecDetails(const nsAString& aCodec, + uint8_t& aProfile, + uint8_t& aLevel, + uint8_t& aBitDepth) +{ + uint8_t dummyChromaSubsampling = 1; + VideoColorSpace dummyColorspace; + return ExtractVPXCodecDetails(aCodec, + aProfile, + aLevel, + aBitDepth, + dummyChromaSubsampling, + dummyColorspace); +} + +bool ExtractVPXCodecDetails(const nsAString& aCodec, + uint8_t& aProfile, + uint8_t& aLevel, + uint8_t& aBitDepth, + uint8_t& aChromaSubsampling, + VideoColorSpace& aColorSpace) +{ + nsTArray<nsString> fieldsArr; + + // Assign default value. + aChromaSubsampling = 1; + + nsCharSeparatedTokenizer tokenizer(aCodec, '.'); + while (tokenizer.hasMoreTokens()) { + const nsSubstring& token = tokenizer.nextToken(); + fieldsArr.AppendElement(token); + } + auto fourCC = fieldsArr[0]; + + if (!fourCC.EqualsLiteral("vp09") && !fourCC.EqualsLiteral("vp08")) { + // Invalid 4CC + return false; + } + uint8_t *fields[] = { &aProfile, &aLevel, &aBitDepth, &aChromaSubsampling, + &aColorSpace.mPrimaryId, &aColorSpace.mTransferId, + &aColorSpace.mMatrixId, &aColorSpace.mRangeId }; + int fieldsCount = 0; + nsresult rv; + for (int fieldsItr = 1; fieldsItr < fieldsArr.Length(); ++fieldsItr, ++fieldsCount) { + if (fieldsCount > 7) { + // No more than 8 fields are expected. + return false; + } + *(fields[fieldsCount]) = + static_cast<uint8_t>(fieldsArr[fieldsItr].ToInteger(&rv)); + // We got invalid field value, parsing error. + NS_ENSURE_SUCCESS(rv, false); + } + // Mandatory Fields + // <sample entry 4CC>.<profile>.<level>.<bitDepth>. + // Optional Fields + // <chromaSubsampling>.<colourPrimaries>.<transferCharacteristics>. + // <matrixCoefficients>.<videoFullRangeFlag> + // First three fields are mandatory(we have parsed 4CC). + if (fieldsCount < 3) { + // Invalid number of fields. + return false; + } + // Start to validate the parsing value. + + // profile should be 0,1,2 or 3. + // See https://www.webmproject.org/vp9/profiles/ + // We don't support more than profile 2 + if (aProfile > 2) { + // Invalid profile. + return false; + } + + // level, See https://www.webmproject.org/vp9/mp4/#semantics_1 + switch (aLevel) { + case 10: + case 11: + case 20: + case 21: + case 30: + case 31: + case 40: + case 41: + case 50: + case 51: + case 52: + case 60: + case 61: + case 62: + break; + default: + // Invalid level. + return false; + } + + if (aBitDepth != 8 && aBitDepth != 10 && aBitDepth != 12) { + // Invalid bitDepth: + return false; + } + + if (fieldsCount == 3) { + // No more options. + return true; + } + + // chromaSubsampling should be 0,1,2,3...4~7 are reserved. + if (aChromaSubsampling > 3) { + return false; + } + + if (fieldsCount == 4) { + // No more options. + return true; + } + + // It is an integer that is defined by the "Colour primaries" + // section of ISO/IEC 23001-8:2016 Table 2. + // We treat reserved value as false case. + const auto& primaryId = aColorSpace.mPrimaryId; + if (primaryId == 0 || primaryId == 3 || primaryId > 22) { + // reserved value. + return false; + } + if (primaryId > 12 && primaryId < 22) { + // 13~21 are reserved values. + return false; + } + + if (fieldsCount == 5) { + // No more options. + return true; + } + + // It is an integer that is defined by the + // "Transfer characteristics" section of ISO/IEC 23001-8:2016 Table 3. + // We treat reserved value as false case. + const auto& transferId = aColorSpace.mTransferId; + if (transferId == 0 || transferId == 3 || transferId > 18) { + // reserved value. + return false; + } + + if (fieldsCount == 6) { + // No more options. + return true; + } + + // It is an integer that is defined by the + // "Matrix coefficients" section of ISO/IEC 23001-8:2016 Table 4. + // We treat reserved value as false case. + const auto& matrixId = aColorSpace.mMatrixId; + if (matrixId == 3 || matrixId > 11) { + return false; + } + + // If matrixCoefficients is 0 (RGB), then chroma subsampling MUST be 3 (4:4:4). + if (matrixId == 0 && aChromaSubsampling != 3) { + return false; + } + + if (fieldsCount == 7) { + // No more options. + return true; + } + + // videoFullRangeFlag indicates the black level and range of the luma and + // chroma signals. 0 = legal range (e.g. 16-235 for 8 bit sample depth); + // 1 = full range (e.g. 0-255 for 8-bit sample depth). + const auto& rangeId = aColorSpace.mRangeId; + return rangeId <= 1; +} + +bool ExtractH264CodecDetails(const nsAString& aCodec, int16_t& aProfile, int16_t& aLevel) { // H.264 codecs parameters have a type defined as avcN.PPCCLL, where - // N = avc type. avc3 is avcc with SPS & PPS implicit (within stream) + // N = avc type. avc3 is avcc with SPS & PPS implicit (within stream) // PP = profile_idc, CC = constraint_set flags, LL = level_idc. // We ignore the constraint_set flags, as it's not clear from any // documentation what constraints the platform decoders support. @@ -468,15 +641,25 @@ IsAACCodecString(const nsAString& aCodec) bool IsVP8CodecString(const nsAString& aCodec) { + uint8_t profile = 0; + uint8_t level = 0; + uint8_t bitDepth = 0; return aCodec.EqualsLiteral("vp8") || - aCodec.EqualsLiteral("vp8.0"); + aCodec.EqualsLiteral("vp8.0") || + (StartsWith(NS_ConvertUTF16toUTF8(aCodec), "vp08") && + ExtractVPXCodecDetails(aCodec, profile, level, bitDepth)); } bool IsVP9CodecString(const nsAString& aCodec) { + uint8_t profile = 0; + uint8_t level = 0; + uint8_t bitDepth = 0; return aCodec.EqualsLiteral("vp9") || - aCodec.EqualsLiteral("vp9.0"); + aCodec.EqualsLiteral("vp9.0") || + (StartsWith(NS_ConvertUTF16toUTF8(aCodec), "vp09") && + ExtractVPXCodecDetails(aCodec, profile, level, bitDepth)); } #ifdef MOZ_AV1 diff --git a/dom/media/VideoUtils.h b/dom/media/VideoUtils.h index eee6561fd..421e6bb51 100644 --- a/dom/media/VideoUtils.h +++ b/dom/media/VideoUtils.h @@ -257,6 +257,34 @@ ExtractH264CodecDetails(const nsAString& aCodecs, int16_t& aProfile, int16_t& aLevel); +struct VideoColorSpace +{ + // TODO: Define the value type as strong type enum + // to better know the exact meaning corresponding to ISO/IEC 23001-8:2016. + // Default value is listed https://www.webmproject.org/vp9/mp4/#optional-fields + uint8_t mPrimaryId = 1; // Table 2 + uint8_t mTransferId = 1; // Table 3 + uint8_t mMatrixId = 1; // Table 4 + uint8_t mRangeId = 0; +}; + +// Extracts the VPX codecs parameter string. +// See https://www.webmproject.org/vp9/mp4/#codecs-parameter-string +// for more details. +// Returns false on failure. +bool +ExtractVPXCodecDetails(const nsAString& aCodec, + uint8_t& aProfile, + uint8_t& aLevel, + uint8_t& aBitDepth); +bool +ExtractVPXCodecDetails(const nsAString& aCodec, + uint8_t& aProfile, + uint8_t& aLevel, + uint8_t& aBitDepth, + uint8_t& aChromaSubsampling, + VideoColorSpace& aColorSpace); + // Use a cryptographic quality PRNG to generate raw random bytes // and convert that to a base64 string. nsresult diff --git a/dom/media/fmp4/MP4Decoder.cpp b/dom/media/fmp4/MP4Decoder.cpp index 8cddfc4f4..9b0886e74 100644 --- a/dom/media/fmp4/MP4Decoder.cpp +++ b/dom/media/fmp4/MP4Decoder.cpp @@ -131,6 +131,19 @@ MP4Decoder::CanHandleMediaType(const MediaContentType& aType, NS_LITERAL_CSTRING("audio/flac"), aType)); continue; } + if (IsVP9CodecString(codec)) { + auto trackInfo = + CreateTrackInfoWithMIMETypeAndContentTypeExtraParameters( + NS_LITERAL_CSTRING("video/vp9"), aType); + uint8_t profile = 0; + uint8_t level = 0; + uint8_t bitDepth = 0; + if (ExtractVPXCodecDetails(codec, profile, level, bitDepth)) { + trackInfo->GetAsVideoInfo()->mBitDepth = bitDepth; + } + trackInfos.AppendElement(Move(trackInfo)); + continue; + } #ifdef MOZ_AV1 if (IsAV1CodecString(codec)) { trackInfos.AppendElement( diff --git a/dom/media/mediasource/gtest/TestExtractVPXCodecDetails.cpp b/dom/media/mediasource/gtest/TestExtractVPXCodecDetails.cpp new file mode 100644 index 000000000..be8a120f6 --- /dev/null +++ b/dom/media/mediasource/gtest/TestExtractVPXCodecDetails.cpp @@ -0,0 +1,111 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include <gtest/gtest.h> +#include <stdint.h> + +#include "VideoUtils.h" + +using namespace mozilla; + +struct TestData +{ + const char16_t* const mCodecParameterString; + const bool mExpectedValue; +}; + +TEST(ExtractVPXCodecDetails, TestDataLength) { + TestData tests[] = + { + {u"vp09.00.11.08", true }, // valid case + {u"vp09.00.11.08.00", true }, // valid case, have extra optional field + {u"vp09.02.10.10.01.09.16.09.01", true}, // maximum length valid case + {u"vp09", false }, // lack of mandatory fields + {u"vp09.00", false }, // lack of mandatory fields + {u"vp09.00.11", false }, // lack of mandatory fields + {u"vp09.02.10.10.01.09.16.09.01.00", false} // more than 9 fields, invalid case. + }; + + for (const auto& data : tests) { + uint8_t profile = 0; + uint8_t level = 0; + uint8_t bitDepth = 0; + bool result = ExtractVPXCodecDetails(nsString(data.mCodecParameterString), profile, level, bitDepth); + EXPECT_EQ(result, data.mExpectedValue) << NS_ConvertUTF16toUTF8(data.mCodecParameterString).get(); + } +} + +TEST(ExtractVPXCodecDetails, TestInputData) { + TestData tests[] = + { + {u"vp09.02..08", false}, // malformed + {u"vp9.02.10.08", false}, // invalid 4CC + {u"vp09.03.11.08", false }, // profile should < 3 + {u"vp09.00.63.08.00", false }, // invalid level + {u"vp09.02.10.13", false}, // invalid bitDepth + {u"vp09.02.10.10.04", false}, // invalid chromasubsampling, should < 4 + {u"vp09.02.10.10.01.00", false}, // invalid Colour primaries, should not be 0,3 or < 23. + {u"vp09.02.10.10.01.03", false}, // invalid Colour primaries. + {u"vp09.02.10.10.01.23", false}, // invalid Colour primaries. + {u"vp09.02.10.10.01.09.00", false}, // invalid Transfer characteristics, should not be 0,3 or < 19. + {u"vp09.02.10.10.01.09.03", false}, // invalid Transfer characteristics. + {u"vp09.02.10.10.01.09.19", false}, // invalid Transfer characteristics. + {u"vp09.02.10.10.01.09.16.12", false}, // invalid Matrix coefficients, should not be 3 or < 12. + {u"vp09.02.10.10.01.09.16.03", false}, // invalid matrix. + {u"vp09.02.10.10.01.09.16.09.02", false}, // invalid range, should < 2. + // Test if matrixCoefficients is 0 (RGB), then chroma subsampling MUST be 3 (4:4:4). + {u"vp09.02.10.08.03.09.16.00.00", true} // invalid combination. + }; + + for (const auto& data : tests) { + uint8_t profile = 0; + uint8_t level = 0; + uint8_t bitDepth = 0; + bool result = ExtractVPXCodecDetails(nsString(data.mCodecParameterString), profile, level, bitDepth); + EXPECT_EQ(result, data.mExpectedValue) << NS_ConvertUTF16toUTF8(data.mCodecParameterString).get(); + } +} + +TEST(ExtractVPXCodecDetails, TestParsingOutput) { + uint8_t profile = 0; + uint8_t level = 0; + uint8_t bitDepth = 0; + uint8_t chromaSubsampling = 0; + VideoColorSpace colorSpace; + auto data = u"vp09.01.11.08"; + bool result = ExtractVPXCodecDetails(nsString(data), + profile, + level, + bitDepth, + chromaSubsampling, + colorSpace); + EXPECT_EQ(result, true); + EXPECT_EQ(profile, 1); + EXPECT_EQ(level, 11); + EXPECT_EQ(bitDepth, 8); + // Should keep spec defined default value. + EXPECT_EQ(chromaSubsampling, 1); + EXPECT_EQ(colorSpace.mPrimaryId, 1); + EXPECT_EQ(colorSpace.mTransferId, 1); + EXPECT_EQ(colorSpace.mMatrixId, 1); + EXPECT_EQ(colorSpace.mRangeId, 0); + + data = u"vp09.02.10.10.01.09.16.09.01"; + result = ExtractVPXCodecDetails(nsString(data), + profile, + level, + bitDepth, + chromaSubsampling, + colorSpace); + EXPECT_EQ(result, true); + EXPECT_EQ(profile, 2); + EXPECT_EQ(level, 10); + EXPECT_EQ(bitDepth, 10); + EXPECT_EQ(chromaSubsampling, 1); + EXPECT_EQ(colorSpace.mPrimaryId, 9); + EXPECT_EQ(colorSpace.mTransferId, 16); + EXPECT_EQ(colorSpace.mMatrixId, 9); + EXPECT_EQ(colorSpace.mRangeId, 1); +} diff --git a/dom/media/mediasource/gtest/moz.build b/dom/media/mediasource/gtest/moz.build index 2cccc80a2..2a59a8343 100644 --- a/dom/media/mediasource/gtest/moz.build +++ b/dom/media/mediasource/gtest/moz.build @@ -5,6 +5,7 @@ UNIFIED_SOURCES += [ 'TestContainerParser.cpp', + 'TestExtractVPXCodecDetails.cpp', ] LOCAL_INCLUDES += [ diff --git a/dom/media/platforms/PlatformDecoderModule.h b/dom/media/platforms/PlatformDecoderModule.h index 54feb13c7..1507b4492 100644 --- a/dom/media/platforms/PlatformDecoderModule.h +++ b/dom/media/platforms/PlatformDecoderModule.h @@ -125,9 +125,11 @@ public: virtual bool Supports(const TrackInfo& aTrackInfo, DecoderDoctorDiagnostics* aDiagnostics) const { - // By default, fall back to SupportsMimeType with just the MIME string. - // (So PDMs do not need to override this method -- yet.) - return SupportsMimeType(aTrackInfo.mMimeType, aDiagnostics); + if (!SupportsMimeType(aTrackInfo.mMimeType, aDiagnostics)) { + return false; + } + const auto videoInfo = aTrackInfo.GetAsVideoInfo(); + return !videoInfo || SupportsBitDepth(videoInfo->mBitDepth, aDiagnostics); } enum class ConversionRequired : uint8_t { @@ -149,6 +151,15 @@ protected: friend class PDMFactory; friend class dom::RemoteDecoderModule; + // Indicates if the PlatformDecoderModule supports decoding of aBitDepth. + // Should override this method when the platform can support bitDepth != 8. + virtual bool SupportsBitDepth(const uint8_t aBitDepth, + DecoderDoctorDiagnostics* aDiagnostics) const + { + return aBitDepth == 8; + } + + // Creates a Video decoder. The layers backend is passed in so that // decoders can determine whether hardware accelerated decoding can be used. // Asynchronous decoding of video should be done in runnables dispatched diff --git a/dom/media/platforms/ffmpeg/FFmpegDecoderModule.h b/dom/media/platforms/ffmpeg/FFmpegDecoderModule.h index 969ac7e0b..d220fcf91 100644 --- a/dom/media/platforms/ffmpeg/FFmpegDecoderModule.h +++ b/dom/media/platforms/ffmpeg/FFmpegDecoderModule.h @@ -77,6 +77,21 @@ public: } } +protected: + bool SupportsBitDepth(const uint8_t aBitDepth, + DecoderDoctorDiagnostics* aDiagnostics) const override + { + // We don't support bitDepth > 8 when compositor backend is D3D11. + // But we don't have KnowsCompositor or any object + // that we can ask for the layersbackend type. + // We should remove this restriction until + // we solve the D3D11 compositor backend issue. +#if defined(XP_LINUX) || defined(XP_MACOSX) + return true; +#endif + return aBitDepth == 8; + } + private: FFmpegLibWrapper* mLib; }; diff --git a/dom/media/platforms/wmf/WMFDecoderModule.cpp b/dom/media/platforms/wmf/WMFDecoderModule.cpp index 6268135ec..26c01aba5 100644 --- a/dom/media/platforms/wmf/WMFDecoderModule.cpp +++ b/dom/media/platforms/wmf/WMFDecoderModule.cpp @@ -213,6 +213,14 @@ bool WMFDecoderModule::Supports(const TrackInfo& aTrackInfo, DecoderDoctorDiagnostics* aDiagnostics) const { + // Check bit depth of video. + // XXXMC: This is here in case we want to start accepting HDR video. Do we? + // This currently defaults to a fail if video bitdepth != 8 + const auto videoInfo = aTrackInfo.GetAsVideoInfo(); + if (videoInfo && !SupportsBitDepth(videoInfo->mBitDepth, aDiagnostics)) { + return false; + } + if ((aTrackInfo.mMimeType.EqualsLiteral("audio/mp4a-latm") || aTrackInfo.mMimeType.EqualsLiteral("audio/mp4")) && WMFDecoderModule::HasAAC()) { @@ -229,7 +237,7 @@ WMFDecoderModule::Supports(const TrackInfo& aTrackInfo, return false; } } else { - // Windows <=7 supports at most 1920x1088. + // Windows 7 supports at most 1920x1088. if (videoInfo->mImage.width > 1920 || videoInfo->mImage.height > 1088) { return false; } diff --git a/dom/media/webm/WebMDecoder.cpp b/dom/media/webm/WebMDecoder.cpp index cbe9ffdb7..b4cc794e7 100644 --- a/dom/media/webm/WebMDecoder.cpp +++ b/dom/media/webm/WebMDecoder.cpp @@ -12,6 +12,7 @@ #include "MediaDecoderStateMachine.h" #include "WebMDemuxer.h" #include "WebMDecoder.h" +#include "PDMFactory.h" #include "VideoUtils.h" #include "nsContentTypeParser.h" @@ -66,11 +67,30 @@ WebMDecoder::CanHandleMediaType(const nsACString& aMIMETypeExcludingCodecs, } // Note: Only accept VP8/VP9 in a video content type, not in an audio // content type. - if ((isWebMVideo || isMatroskaVideo) && - (codec.EqualsLiteral("vp8") || codec.EqualsLiteral("vp8.0") || - codec.EqualsLiteral("vp9") || codec.EqualsLiteral("vp9.0"))) { - - continue; + if (isWebMVideo || isMatroskaVideo) { + UniquePtr<TrackInfo> trackInfo; + if (IsVP9CodecString(codec)) { + trackInfo = CreateTrackInfoWithMIMEType( + NS_LITERAL_CSTRING("video/vp9")); + } else if (IsVP8CodecString(codec)) { + trackInfo = CreateTrackInfoWithMIMEType( + NS_LITERAL_CSTRING("video/vp8")); + } + // If it is vp8 or vp9, check the bit depth. + if (trackInfo) { + uint8_t profile = 0; + uint8_t level = 0; + uint8_t bitDepth = 0; + if (ExtractVPXCodecDetails(codec, profile, level, bitDepth)) { + trackInfo->GetAsVideoInfo()->mBitDepth = bitDepth; + } + // Verify that we have a PDM that supports this bit depth. + RefPtr<PDMFactory> platform = new PDMFactory(); + if (!platform->Supports(*trackInfo, nullptr)) { + return false; + } + continue; + } } #ifdef MOZ_AV1 if (MediaPrefs::AV1Enabled() && IsAV1CodecString(codec)) { diff --git a/libs/libstagefright/frameworks/av/media/libstagefright/MPEG4Extractor.cpp b/libs/libstagefright/frameworks/av/media/libstagefright/MPEG4Extractor.cpp index 786e80487..bbc067ab1 100644 --- a/libs/libstagefright/frameworks/av/media/libstagefright/MPEG4Extractor.cpp +++ b/libs/libstagefright/frameworks/av/media/libstagefright/MPEG4Extractor.cpp @@ -269,6 +269,9 @@ static const char *FourCC2MIME(uint32_t fourcc) { case FOURCC('V', 'P', '6', 'F'): return MEDIA_MIMETYPE_VIDEO_VP6; + case FOURCC('v', 'p', '0', '9'): + return MEDIA_MIMETYPE_VIDEO_VP9; + case FOURCC('a', 'v', '0', '1'): case FOURCC('.', 'a', 'v', '1'): return MEDIA_MIMETYPE_VIDEO_AV1; diff --git a/libs/libstagefright/frameworks/av/media/libstagefright/MediaDefs.cpp b/libs/libstagefright/frameworks/av/media/libstagefright/MediaDefs.cpp index a7c6e75fc..bc81dceb3 100644 --- a/libs/libstagefright/frameworks/av/media/libstagefright/MediaDefs.cpp +++ b/libs/libstagefright/frameworks/av/media/libstagefright/MediaDefs.cpp @@ -22,7 +22,7 @@ const char *MEDIA_MIMETYPE_IMAGE_JPEG = "image/jpeg"; const char *MEDIA_MIMETYPE_VIDEO_VP6 = "video/x-vnd.on2.vp6"; const char *MEDIA_MIMETYPE_VIDEO_VP8 = "video/x-vnd.on2.vp8"; -const char *MEDIA_MIMETYPE_VIDEO_VP9 = "video/x-vnd.on2.vp9"; +const char *MEDIA_MIMETYPE_VIDEO_VP9 = "video/vp9"; const char *MEDIA_MIMETYPE_VIDEO_AV1 = "video/av1"; const char *MEDIA_MIMETYPE_VIDEO_AVC = "video/avc"; const char *MEDIA_MIMETYPE_VIDEO_MPEG4 = "video/mp4v-es"; |