chromium/media/filters/stream_parser_factory.cc

// Copyright 2013 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifdef UNSAFE_BUFFERS_BUILD
// TODO(crbug.com/40285824): Remove this and convert code to safer constructs.
#pragma allow_unsafe_buffers
#endif

#include "media/filters/stream_parser_factory.h"

#include <stddef.h>

#include <algorithm>

#include "base/command_line.h"
#include "base/containers/span.h"
#include "base/memory/ptr_util.h"
#include "base/memory/raw_ptr_exclusion.h"
#include "base/metrics/histogram_macros.h"
#include "base/strings/pattern.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_split.h"
#include "base/strings/string_util.h"
#include "build/build_config.h"
#include "media/base/audio_decoder_config.h"
#include "media/base/media.h"
#include "media/base/media_switches.h"
#include "media/base/media_util.h"
#include "media/base/video_codecs.h"
#include "media/base/video_decoder_config.h"
#include "media/formats/mp4/mp4_stream_parser.h"
#include "media/formats/mpeg/adts_stream_parser.h"
#include "media/formats/mpeg/mpeg1_audio_stream_parser.h"
#include "media/formats/webcodecs/webcodecs_encoded_chunk_stream_parser.h"
#include "media/formats/webm/webm_stream_parser.h"
#include "media/media_buildflags.h"

#if BUILDFLAG(IS_ANDROID)
#include "media/base/android/media_codec_util.h"
#endif

#if BUILDFLAG(USE_PROPRIETARY_CODECS)
#include "media/formats/mp4/es_descriptor.h"
#if BUILDFLAG(ENABLE_MSE_MPEG2TS_STREAM_PARSER)
#include "media/formats/mp2t/mp2t_stream_parser.h"
#endif
#endif

namespace media {

CodecIDValidatorFunction;

struct CodecInfo {};

ParserFactoryFunction;

struct SupportedTypeInfo {};

static const CodecInfo kVP8CodecInfo =;
static const CodecInfo kLegacyVP9CodecInfo =;
static const CodecInfo kVP9CodecInfo =;
static const CodecInfo kVorbisCodecInfo =;
static const CodecInfo kOpusCodecInfo =;
static const CodecInfo kOpusCodecInfo2 =;

#if BUILDFLAG(ENABLE_AV1_DECODER)
// Note: Validation of the codec string is handled by the caller.
static const CodecInfo kAV1CodecInfo =;
#endif

static const CodecInfo* const kVideoWebMCodecs[] =;

static const CodecInfo* const kAudioWebMCodecs[] =;

static StreamParser* BuildWebMParser(base::span<const std::string> codecs,
                                     MediaLog* media_log) {}

#if BUILDFLAG(USE_PROPRIETARY_CODECS)
static int GetMP4AudioObjectType(std::string_view codec_id,
                                 MediaLog* media_log) {
  // From RFC 6381 section 3.3 (ISO Base Media File Format Name Space):
  // When the first element of a ['codecs' parameter value] is 'mp4a' ...,
  // the second element is a hexadecimal representation of the MP4 Registration
  // Authority ObjectTypeIndication (OTI). Note that MP4RA uses a leading "0x"
  // with these values, which is omitted here and hence implied.
  std::vector<std::string_view> tokens = base::SplitStringPiece(
      codec_id, ".", base::KEEP_WHITESPACE, base::SPLIT_WANT_NONEMPTY);
  if (tokens.size() == 3 && tokens[0] == "mp4a" && tokens[1] == "40") {
    // From RFC 6381 section 3.3:
    // One of the OTI values for 'mp4a' is 40 (identifying MPEG-4 audio). For
    // this value, the third element identifies the audio ObjectTypeIndication
    // (OTI) ... expressed as a decimal number.
    int audio_object_type;
    if (base::StringToInt(tokens[2], &audio_object_type))
      return audio_object_type;
  }

  MEDIA_LOG(DEBUG, media_log)
      << "Malformed mimetype codec '" << codec_id << "'";
  return -1;
}

// AAC Object Type IDs that Chrome supports.
constexpr int kAACLCObjectType = 2;
constexpr int kAACSBRObjectType = 5;
constexpr int kAACPSObjectType = 29;
constexpr int kAACXHEObjectType = 42;

bool ValidateMP4ACodecID(std::string_view codec_id, MediaLog* media_log) {
  int audio_object_type = GetMP4AudioObjectType(codec_id, media_log);
  if (audio_object_type == kAACLCObjectType ||
      audio_object_type == kAACSBRObjectType ||
      audio_object_type == kAACPSObjectType ||
      audio_object_type == kAACXHEObjectType) {
    return true;
  }

  MEDIA_LOG(DEBUG, media_log)
      << "Unsupported audio object type " << audio_object_type << " in codec '"
      << codec_id << "'";
  return false;
}

static const CodecInfo kH264AVC1CodecInfo = {
    "avc1.*", CodecInfo::VIDEO, nullptr, CodecInfo::HISTOGRAM_H264};
static const CodecInfo kH264AVC3CodecInfo = {
    "avc3.*", CodecInfo::VIDEO, nullptr, CodecInfo::HISTOGRAM_H264};

#if BUILDFLAG(ENABLE_PLATFORM_HEVC)
static const CodecInfo kHEVCHEV1CodecInfo = {
    "hev1.*", CodecInfo::VIDEO, nullptr, CodecInfo::HISTOGRAM_HEVC};
static const CodecInfo kHEVCHVC1CodecInfo = {
    "hvc1.*", CodecInfo::VIDEO, nullptr, CodecInfo::HISTOGRAM_HEVC};
#endif  // BUILDFLAG(ENABLE_PLATFORM_HEVC)
#if BUILDFLAG(ENABLE_PLATFORM_DOLBY_VISION)
static const CodecInfo kDolbyVisionAVCCodecInfo1 = {
    "dva1.*", CodecInfo::VIDEO, nullptr, CodecInfo::HISTOGRAM_DOLBYVISION};
static const CodecInfo kDolbyVisionAVCCodecInfo2 = {
    "dvav.*", CodecInfo::VIDEO, nullptr, CodecInfo::HISTOGRAM_DOLBYVISION};
#if BUILDFLAG(ENABLE_PLATFORM_HEVC)
static const CodecInfo kDolbyVisionHEVCCodecInfo1 = {
    "dvh1.*", CodecInfo::VIDEO, nullptr, CodecInfo::HISTOGRAM_DOLBYVISION};
static const CodecInfo kDolbyVisionHEVCCodecInfo2 = {
    "dvhe.*", CodecInfo::VIDEO, nullptr, CodecInfo::HISTOGRAM_DOLBYVISION};
#endif  // BUILDFLAG(ENABLE_PLATFORM_HEVC)
#endif  // BUILDFLAG(ENABLE_PLATFORM_DOLBY_VISION)
static const CodecInfo kMPEG4AACCodecInfo = {"mp4a.40.*", CodecInfo::AUDIO,
                                             &ValidateMP4ACodecID,
                                             CodecInfo::HISTOGRAM_MPEG4AAC};
static const CodecInfo kMPEG2AACLCCodecInfo = {
    "mp4a.67", CodecInfo::AUDIO, nullptr, CodecInfo::HISTOGRAM_MPEG2AAC};

#if BUILDFLAG(ENABLE_PLATFORM_AC3_EAC3_AUDIO)
// The 'ac-3' and 'ec-3' are mime codec ids for AC3 and EAC3 according to
// http://www.mp4ra.org/codecs.html
// The object types for AC3 and EAC3 in MP4 container are 0xa5 and 0xa6, so
// according to RFC 6381 this corresponds to codec ids 'mp4a.A5' and 'mp4a.A6'.
// Codec ids with lower case oti (mp4a.a5 and mp4a.a6) are supported for
// backward compatibility.
static const CodecInfo kAC3CodecInfo1 = {"ac-3", CodecInfo::AUDIO, nullptr,
                                         CodecInfo::HISTOGRAM_AC3};
static const CodecInfo kAC3CodecInfo2 = {"mp4a.a5", CodecInfo::AUDIO, nullptr,
                                         CodecInfo::HISTOGRAM_AC3};
static const CodecInfo kAC3CodecInfo3 = {"mp4a.A5", CodecInfo::AUDIO, nullptr,
                                         CodecInfo::HISTOGRAM_AC3};
static const CodecInfo kEAC3CodecInfo1 = {"ec-3", CodecInfo::AUDIO, nullptr,
                                          CodecInfo::HISTOGRAM_EAC3};
static const CodecInfo kEAC3CodecInfo2 = {"mp4a.a6", CodecInfo::AUDIO, nullptr,
                                          CodecInfo::HISTOGRAM_EAC3};
static const CodecInfo kEAC3CodecInfo3 = {"mp4a.A6", CodecInfo::AUDIO, nullptr,
                                          CodecInfo::HISTOGRAM_EAC3};
#endif  // BUILDFLAG(ENABLE_PLATFORM_AC3_EAC3_AUDIO)

#if BUILDFLAG(ENABLE_PLATFORM_AC4_AUDIO)
// The 'ac-4' is mime codec id for AC4 according to
// http://www.mp4ra.org/codecs.html
// The object types for AC4 in MP4 container is 0xae, so according to RFC 6381
// this corresponds to codec ids 'mp4a.AE'.
// Codec id with lower case oti (mp4a.ae) is supported for backward
// compatibility.
static const CodecInfo kAC4CodecInfo1 = {"ac-4.*", CodecInfo::AUDIO, nullptr,
                                         CodecInfo::HISTOGRAM_AC4};
static const CodecInfo kAC4CodecInfo2 = {"mp4a.ae.*", CodecInfo::AUDIO, nullptr,
                                         CodecInfo::HISTOGRAM_AC4};
static const CodecInfo kAC4CodecInfo3 = {"mp4a.AE.*", CodecInfo::AUDIO, nullptr,
                                         CodecInfo::HISTOGRAM_AC4};
static const CodecInfo kAC4CodecInfo4 = {"ac-4", CodecInfo::AUDIO, nullptr,
                                         CodecInfo::HISTOGRAM_AC4};
static const CodecInfo kAC4CodecInfo5 = {"mp4a.ae", CodecInfo::AUDIO, nullptr,
                                         CodecInfo::HISTOGRAM_AC4};
static const CodecInfo kAC4CodecInfo6 = {"mp4a.AE", CodecInfo::AUDIO, nullptr,
                                         CodecInfo::HISTOGRAM_AC4};
#endif  // BUILDFLAG(ENABLE_PLATFORM_AC4_AUDIO)

#if BUILDFLAG(ENABLE_PLATFORM_DTS_AUDIO)
// The 'dtsc' and 'dtsx' are mime codec ids for DTS and DTSX according to
// http://mp4ra.org/#/codecs
// The object types for DTS and DTSX in MP4 container are 0xa9 and 0xb2, so
// according to RFC 6381 this corresponds to codec ids 'mp4a.A9' and 'mp4a.B2'.
// Codec ids with lower case oti (mp4a.a9 and mp4a.b2) are supported for
// backward compatibility.
static const CodecInfo kDTSCodecInfo1 = {"dtsc", CodecInfo::AUDIO, nullptr,
                                         CodecInfo::HISTOGRAM_DTS};
static const CodecInfo kDTSCodecInfo2 = {"mp4a.a9", CodecInfo::AUDIO, nullptr,
                                         CodecInfo::HISTOGRAM_DTS};
static const CodecInfo kDTSCodecInfo3 = {"mp4a.A9", CodecInfo::AUDIO, nullptr,
                                         CodecInfo::HISTOGRAM_DTS};
static const CodecInfo kDTSXCodecInfo1 = {"dtsx", CodecInfo::AUDIO, nullptr,
                                          CodecInfo::HISTOGRAM_DTSXP2};
static const CodecInfo kDTSXCodecInfo2 = {"mp4a.b2", CodecInfo::AUDIO, nullptr,
                                          CodecInfo::HISTOGRAM_DTSXP2};
static const CodecInfo kDTSXCodecInfo3 = {"mp4a.B2", CodecInfo::AUDIO, nullptr,
                                          CodecInfo::HISTOGRAM_DTSXP2};
static const CodecInfo kDTSECodecInfo1 = {"dtse", CodecInfo::AUDIO, nullptr,
                                          CodecInfo::HISTOGRAM_DTSE};
static const CodecInfo kDTSECodecInfo2 = {"mp4a.ac", CodecInfo::AUDIO, nullptr,
                                          CodecInfo::HISTOGRAM_DTSE};
static const CodecInfo kDTSECodecInfo3 = {"mp4a.AC", CodecInfo::AUDIO, nullptr,
                                          CodecInfo::HISTOGRAM_DTSE};
#endif  // BUILDFLAG(ENABLE_PLATFORM_DTS_AUDIO)

#if BUILDFLAG(ENABLE_PLATFORM_MPEG_H_AUDIO)
static const CodecInfo kMpegHAudioCodecInfo1 = {
    "mhm1.*", CodecInfo::AUDIO, nullptr, CodecInfo::HISTOGRAM_MPEG_H_AUDIO};
static const CodecInfo kMpegHAudioCodecInfo2 = {
    "mha1.*", CodecInfo::AUDIO, nullptr, CodecInfo::HISTOGRAM_MPEG_H_AUDIO};
#endif

#endif  // BUILDFLAG(USE_PROPRIETARY_CODECS)

static const CodecInfo kMP3CodecInfo =;
static const CodecInfo* const kAudioMP3Codecs[] =;

static StreamParser* BuildMP3Parser(base::span<const std::string> codecs,
                                    MediaLog* media_log) {}

static const CodecInfo kMPEG4VP09CodecInfo =;
static const CodecInfo kMPEG4FLACCodecInfo =;
static const CodecInfo kMPEG4FLACCodecInfo2 =;
#if BUILDFLAG(ENABLE_PLATFORM_IAMF_AUDIO)
static const CodecInfo kIAMFCodecInfo1 = {"iamf", CodecInfo::AUDIO, nullptr,
                                          CodecInfo::HISTOGRAM_IAMF};
static const CodecInfo kIAMFCodecInfo2 = {"iamf.*", CodecInfo::AUDIO, nullptr,
                                          CodecInfo::HISTOGRAM_IAMF};
#endif  // BUILDFLAG(ENABLE_PLATFORM_IAMF_AUDIO)

static const CodecInfo* const kVideoMP4Codecs[] =;

static const CodecInfo* const kAudioMP4Codecs[] =;

static StreamParser* BuildMP4Parser(base::span<const std::string> codecs,
                                    MediaLog* media_log) {}
#if BUILDFLAG(USE_PROPRIETARY_CODECS)
static const CodecInfo kADTSCodecInfo = {nullptr, CodecInfo::AUDIO, nullptr,
                                         CodecInfo::HISTOGRAM_MPEG4AAC};
static const CodecInfo* const kAudioADTSCodecs[] = {&kADTSCodecInfo, nullptr};

static StreamParser* BuildADTSParser(base::span<const std::string> codecs,
                                     MediaLog* media_log) {
  return new ADTSStreamParser();
}

#if BUILDFLAG(ENABLE_MSE_MPEG2TS_STREAM_PARSER)
// These codec ids correspond to object types registered with MP4RA and are the
// same as MP3 audio codec ids in media/base/mime_util_internal.cc.
// From http://www.mp4ra.org/object.html:
// 69   Audio ISO/IEC 13818-3
// 6B   Audio ISO/IEC 11172-3
static const CodecInfo kMPEG2TS_MP3CodecInfo1 = {
    "mp4a.69", CodecInfo::AUDIO, nullptr, CodecInfo::HISTOGRAM_MP3};
static const CodecInfo kMPEG2TS_MP3CodecInfo2 = {
    "mp4a.6B", CodecInfo::AUDIO, nullptr, CodecInfo::HISTOGRAM_MP3};

static const CodecInfo* const kVideoMP2TCodecs[] = {&kH264AVC1CodecInfo,
                                                    &kH264AVC3CodecInfo,
                                                    &kMPEG2TS_MP3CodecInfo1,
                                                    &kMPEG2TS_MP3CodecInfo2,
                                                    &kMPEG4AACCodecInfo,
                                                    &kMPEG2AACLCCodecInfo,
                                                    nullptr};

static StreamParser* BuildMP2TParser(base::span<const std::string> codecs,
                                     MediaLog* media_log) {
  bool has_sbr = false;
  for (const auto& codec_id : codecs) {
    if (base::MatchPattern(codec_id, kMPEG4AACCodecInfo.pattern)) {
      int audio_object_type = GetMP4AudioObjectType(codec_id, media_log);
      if (audio_object_type == kAACSBRObjectType ||
          audio_object_type == kAACPSObjectType) {
        has_sbr = true;
      }
    }
  }

  return new media::mp2t::Mp2tStreamParser(codecs, has_sbr);
}
#endif  // ENABLE_MSE_MPEG2TS_STREAM_PARSER
#endif  // BUILDFLAG(USE_PROPRIETARY_CODECS)

static const SupportedTypeInfo kSupportedTypeInfo[] =;

#if BUILDFLAG(ENABLE_HLS_DEMUXER)
std::unique_ptr<StreamParser> StreamParserFactory::CreateRelaxedParser(
    RelaxedParserSupportedType mime) {
  const bool enable_mp4 = base::FeatureList::IsEnabled(kBuiltInHlsMP4);
  switch (mime) {
    case RelaxedParserSupportedType::kMP2T: {
      // TODO(issue/40253609): Figure out how to determine SBR presence.
      return std::make_unique<mp2t::Mp2tStreamParser>(std::nullopt, false);
    }
    case RelaxedParserSupportedType::kAAC: {
      return std::make_unique<ADTSStreamParser>();
    }
    case RelaxedParserSupportedType::kMP4: {
      // TODO(issue/40253609): Figure out how to determine presence of SBR,
      // FLAC, IAMF, DolbyVision.
      return enable_mp4 ? std::make_unique<mp4::MP4StreamParser>(
                              std::nullopt, false, true, false, false)
                        : nullptr;
    }
  }
}
#endif

// Verify that |codec_info| is supported on this platform.
//
// Returns true if |codec_info| is a valid audio/video codec and is allowed.
// |audio_codecs| has |codec_info|.tag added to its list if |codec_info| is an
// audio codec. |audio_codecs| may be nullptr, in which case it is not updated.
// |video_codecs| has |codec_info|.tag added to its list if |codec_info| is a
// video codec. |video_codecs| may be nullptr, in which case it is not updated.
//
// Returns false otherwise, and |audio_codecs| and |video_codecs| not touched.
static bool VerifyCodec(const CodecInfo* codec_info,
                        std::vector<CodecInfo::HistogramTag>* audio_codecs,
                        std::vector<CodecInfo::HistogramTag>* video_codecs) {}

// Checks to see if the specified |type| and |codecs| list are supported.
// Returns kNotSupported if |type| and |codecs| are definitively not supported.
// The values of |factory_function|, |audio_codecs|, and |video_codecs| are
// undefined in this case.
// Returns kSupported if |type| and all codecs listed in |codecs| are
// supported, any non-empty codecs requirement is met for |type|, and all of
// |codecs| are supported for |type|.
// Returns kMaybeSupported if |type| is supported, but requires a codecs
// parameter that is missing.
// For both kSupported and kMaybeSupported results, |factory_function| is
// updated to be a function that can build a StreamParser for this type,
// |audio_codecs| is updated with the appropriate HistogramTags for matching
// audio codecs specified in |codecs|, and |video_codecs| is updated with the
// appropriate HistogramTags for matching video codecs specified in |codecs|.
// The value of each of |factory_function|, |audio_codecs| and |video_codecs| is
// not updated if it was nullptr initially.
static SupportsType CheckTypeAndCodecs(
    std::string_view type,
    base::span<const std::string> codecs,
    MediaLog* media_log,
    ParserFactoryFunction* factory_function,
    std::vector<CodecInfo::HistogramTag>* audio_codecs,
    std::vector<CodecInfo::HistogramTag>* video_codecs) {}

// static
SupportsType StreamParserFactory::IsTypeSupported(
    std::string_view type,
    base::span<const std::string> codecs) {}

// static
std::unique_ptr<StreamParser> StreamParserFactory::Create(
    std::string_view type,
    base::span<const std::string> codecs,
    MediaLog* media_log) {}

// static
std::unique_ptr<StreamParser> StreamParserFactory::Create(
    std::unique_ptr<AudioDecoderConfig> audio_config) {}

// static
std::unique_ptr<StreamParser> StreamParserFactory::Create(
    std::unique_ptr<VideoDecoderConfig> video_config) {}

}  // namespace media