#ifdef UNSAFE_BUFFERS_BUILD
#pragma allow_unsafe_buffers
#endif
#include "media/renderers/win/media_foundation_audio_stream.h"
#include <mferror.h>
#include <mmreg.h>
#include <wrl.h>
#include "base/win/scoped_co_mem.h"
#include "media/base/audio_codecs.h"
#include "media/base/audio_decoder_config.h"
#include "media/base/win/mf_helpers.h"
namespace media {
using Microsoft::WRL::ComPtr;
using Microsoft::WRL::MakeAndInitialize;
HRESULT MediaFoundationAudioStream::Create(
int stream_id,
IMFMediaSource* parent_source,
DemuxerStream* demuxer_stream,
std::unique_ptr<MediaLog> media_log,
MediaFoundationStreamWrapper** stream_out) {
DVLOG(1) << __func__ << ": stream_id=" << stream_id;
ComPtr<IMFMediaStream> audio_stream;
AudioCodec codec = demuxer_stream->audio_decoder_config().codec();
switch (codec) {
#if BUILDFLAG(USE_PROPRIETARY_CODECS)
case AudioCodec::kAAC:
RETURN_IF_FAILED(MakeAndInitialize<MediaFoundationAACAudioStream>(
&audio_stream, stream_id, parent_source, demuxer_stream,
std::move(media_log)));
break;
#endif
#if BUILDFLAG(ENABLE_PLATFORM_AC4_AUDIO)
case AudioCodec::kAC4:
RETURN_IF_FAILED(MakeAndInitialize<MediaFoundationAC4AudioStream>(
&audio_stream, stream_id, parent_source, demuxer_stream,
std::move(media_log)));
break;
#endif
default:
RETURN_IF_FAILED(MakeAndInitialize<MediaFoundationAudioStream>(
&audio_stream, stream_id, parent_source, demuxer_stream,
std::move(media_log)));
break;
}
*stream_out =
static_cast<MediaFoundationStreamWrapper*>(audio_stream.Detach());
return S_OK;
}
bool MediaFoundationAudioStream::IsEncrypted() const {
AudioDecoderConfig audio_config = demuxer_stream_->audio_decoder_config();
return audio_config.is_encrypted();
}
HRESULT MediaFoundationAudioStream::GetMediaType(
IMFMediaType** media_type_out) {
AudioDecoderConfig decoder_config = demuxer_stream_->audio_decoder_config();
return GetDefaultAudioType(decoder_config, media_type_out);
}
#if BUILDFLAG(USE_PROPRIETARY_CODECS)
HRESULT MediaFoundationAACAudioStream::GetMediaType(
IMFMediaType** media_type_out) {
AudioDecoderConfig decoder_config = demuxer_stream_->audio_decoder_config();
enable_adts_header_removal_ = !decoder_config.should_discard_decoder_delay();
return GetAacAudioType(decoder_config, media_type_out);
}
HRESULT MediaFoundationAACAudioStream::TransformSample(
Microsoft::WRL::ComPtr<IMFSample>& sample) {
DVLOG_FUNC(3);
if (!enable_adts_header_removal_)
return S_OK;
ComPtr<IMFMediaBuffer> mf_buffer;
ComPtr<IMFMediaBuffer> new_mf_buffer;
DWORD buffer_count = 0;
RETURN_IF_FAILED(sample->GetBufferCount(&buffer_count));
if (buffer_count != 1) {
DLOG(ERROR) << __func__ << ": buffer_count=" << buffer_count;
return MF_E_UNEXPECTED;
}
RETURN_IF_FAILED(sample->GetBufferByIndex(0, &mf_buffer));
BYTE* mf_buffer_data = nullptr;
DWORD max_length = 0;
DWORD current_length = 0;
const int kADTSHeaderSize = 7;
bool might_contain_adts_header = false;
RETURN_IF_FAILED(
mf_buffer->Lock(&mf_buffer_data, &max_length, ¤t_length));
if (current_length >= kADTSHeaderSize && mf_buffer_data[0] == 0xff &&
mf_buffer_data[1] == 0xf1 && mf_buffer_data[6] == 0xfc) {
might_contain_adts_header = true;
}
RETURN_IF_FAILED(mf_buffer->Unlock());
if (!might_contain_adts_header)
return S_OK;
bool contains_clear_adts_header = true;
base::win::ScopedCoMem<MediaFoundationSubsampleEntry> subsample_mappings;
uint32_t subsample_mappings_size = 0;
if (SUCCEEDED(sample->GetAllocatedBlob(
MFSampleExtension_Encryption_SubSample_Mapping,
reinterpret_cast<uint8_t**>(&subsample_mappings),
&subsample_mappings_size)) &&
subsample_mappings_size >= sizeof(MediaFoundationSubsampleEntry)) {
uint32_t subsample_count =
subsample_mappings_size / sizeof(MediaFoundationSubsampleEntry);
if (subsample_count == 1 &&
subsample_mappings.get()[0].clear_bytes == kADTSHeaderSize) {
RETURN_IF_FAILED(
sample->DeleteItem(MFSampleExtension_Encryption_SubSample_Mapping));
} else if (subsample_mappings.get()[0].clear_bytes >= kADTSHeaderSize) {
subsample_mappings.get()[0].clear_bytes -= kADTSHeaderSize;
RETURN_IF_FAILED(sample->SetBlob(
MFSampleExtension_Encryption_SubSample_Mapping,
reinterpret_cast<const uint8_t*>(subsample_mappings.get()),
subsample_mappings_size));
} else {
contains_clear_adts_header = false;
}
}
if (contains_clear_adts_header) {
RETURN_IF_FAILED(MFCreateMediaBufferWrapper(
mf_buffer.Get(), kADTSHeaderSize, current_length - kADTSHeaderSize,
&new_mf_buffer));
RETURN_IF_FAILED(sample->RemoveAllBuffers());
RETURN_IF_FAILED(sample->AddBuffer(new_mf_buffer.Get()));
}
return S_OK;
}
#endif
#if BUILDFLAG(ENABLE_PLATFORM_AC4_AUDIO)
HRESULT MediaFoundationAC4AudioStream::GetMediaType(
IMFMediaType** media_type_out) {
AudioDecoderConfig decoder_config = demuxer_stream_->audio_decoder_config();
return GetAC4AudioType(decoder_config, media_type_out);
}
#endif
}