1
    2
    3
    4
    5
    6
    7
    8
    9
   10
   11
   12
   13
   14
   15
   16
   17
   18
   19
   20
   21
   22
   23
   24
   25
   26
   27
   28
   29
   30
   31
   32
   33
   34
   35
   36
   37
   38
   39
   40
   41
   42
   43
   44
   45
   46
   47
   48
   49
   50
   51
   52
   53
   54
   55
   56
   57
   58
   59
   60
   61
   62
   63
   64
   65
   66
   67
   68
   69
   70
   71
   72
   73
   74
   75
   76
   77
   78
   79
   80
   81
   82
   83
   84
   85
   86
   87
   88
   89
   90
   91
   92
   93
   94
   95
   96
   97
   98
   99
  100
  101
  102
  103
  104
  105
  106
  107
  108
  109
  110
  111
  112
  113
  114
  115
  116
  117
  118
  119
  120
  121
  122
  123
  124
  125
  126
  127
  128
  129
  130
  131
  132
  133
  134
  135
  136
  137
  138
  139
  140
  141
  142
  143
  144
  145
  146
  147
  148
  149
  150
  151
  152
  153
  154
  155
  156
  157
  158
  159
  160
  161
  162
  163
  164
  165
  166
  167
  168
  169
  170
  171
  172
  173
  174
  175
  176
  177
  178
  179
  180
  181
  182
  183
  184
  185
  186
  187
  188
  189
  190
  191
  192
  193
  194
  195
  196
  197
  198
  199
  200
  201
  202
  203
  204
  205
  206
  207
  208
  209
  210
  211
  212
  213
  214
  215
  216
  217
  218
  219
  220
  221
  222
  223
  224
  225
  226
  227
  228
  229
  230
  231

media / base / win / mf_helpers.h [blame]

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

#ifndef MEDIA_BASE_WIN_MF_HELPERS_H_
#define MEDIA_BASE_WIN_MF_HELPERS_H_

#include <mfapi.h>
#include <mfidl.h>
#include <stdint.h>
#include <wrl/client.h>

#include "base/functional/callback.h"
#include "base/logging.h"
#include "base/time/time.h"
#include "media/base/audio_decoder_config.h"
#include "media/base/channel_layout.h"
#include "media/base/decoder_buffer.h"
#include "media/base/media_export.h"
#include "media/base/subsample_entry.h"
#include "media/base/video_codecs.h"
#include "media/base/video_color_space.h"
#include "media/base/video_frame.h"
#include "media/base/video_types.h"
#include "media/base/win/dxgi_device_manager.h"
#include "media/media_buildflags.h"

struct ID3D11DeviceChild;
struct ID3D11Device;
class IMFMediaType;

namespace media {

// Helper function to print HRESULT to std::string.
const auto PrintHr = logging::SystemErrorCodeToString;

// Helper macro for DVLOG with function name and this pointer.
#define DVLOG_FUNC(level) DVLOG(level) << __func__ << ": (" << this << ") "

// Macros that contain return statements can make code harder to read. Only use
// these when necessary, e.g. in places where we deal with a lot of Windows API
// calls, for each of which we have to check the returned HRESULT.
// See discussion thread at:
// https://groups.google.com/a/chromium.org/d/msg/cxx/zw5Xmcs--S4/r7Fwb-TsCAAJ

#define RETURN_IF_FAILED(expr)                                          \
  do {                                                                  \
    HRESULT hresult = (expr);                                           \
    if (FAILED(hresult)) {                                              \
      LOG(ERROR) << __func__ << ": failed with \"" << PrintHr(hresult) \
                  << "\"";                                              \
      return hresult;                                                   \
    }                                                                   \
  } while (0)

#define RETURN_ON_FAILURE(success, log, ret) \
  do {                                       \
    if (!(success)) {                        \
      LOG(ERROR) << log;                    \
      return ret;                            \
    }                                        \
  } while (0)

#define RETURN_ON_HR_FAILURE(hresult, log, ret) \
  RETURN_ON_FAILURE(SUCCEEDED(hresult), log << ", " << PrintHr(hresult), ret);

// Creates a Media Foundation sample with one buffer of length |buffer_length|
// on a |align|-byte boundary. Alignment must be a perfect power of 2 or 0.
MEDIA_EXPORT Microsoft::WRL::ComPtr<IMFSample> CreateEmptySampleWithBuffer(
    uint32_t buffer_length,
    int align);

// Provides scoped access to the underlying buffer in an IMFMediaBuffer
// instance.
class MEDIA_EXPORT MediaBufferScopedPointer {
 public:
  explicit MediaBufferScopedPointer(IMFMediaBuffer* media_buffer);

  MediaBufferScopedPointer(const MediaBufferScopedPointer&) = delete;
  MediaBufferScopedPointer& operator=(const MediaBufferScopedPointer&) = delete;

  ~MediaBufferScopedPointer();

  raw_ptr<uint8_t, AllowPtrArithmetic> get() { return buffer_; }
  DWORD current_length() const { return current_length_; }
  DWORD max_length() const { return max_length_; }

 private:
  Microsoft::WRL::ComPtr<IMFMediaBuffer> media_buffer_;
  raw_ptr<uint8_t, AllowPtrArithmetic> buffer_;
  DWORD max_length_;
  DWORD current_length_;
};

// Copies |in_string| to |out_string| that is allocated with CoTaskMemAlloc().
MEDIA_EXPORT HRESULT CopyCoTaskMemWideString(LPCWSTR in_string,
                                             LPWSTR* out_string);

// Set the debug name of a D3D11 resource for use with ETW debugging tools.
// D3D11 retains the string passed to this function.
MEDIA_EXPORT HRESULT SetDebugName(ID3D11DeviceChild* d3d11_device_child,
                                  const char* debug_string);
MEDIA_EXPORT HRESULT SetDebugName(ID3D11Device* d3d11_device,
                                  const char* debug_string);

// Represents audio channel configuration constants as understood by Windows.
// E.g. KSAUDIO_SPEAKER_MONO.  For a list of possible values see:
// http://msdn.microsoft.com/en-us/library/windows/hardware/ff537083(v=vs.85).aspx
using ChannelConfig = uint32_t;

// Converts Microsoft's channel configuration to ChannelLayout.
// This mapping is not perfect but the best we can do given the current
// ChannelLayout enumerator and the Windows-specific speaker configurations
// defined in ksmedia.h.
MEDIA_EXPORT ChannelLayout ChannelConfigToChannelLayout(ChannelConfig config);

// Converts a GUID (little endian) to a bytes array (big endian).
MEDIA_EXPORT std::vector<uint8_t> ByteArrayFromGUID(REFGUID guid);

// Returns a GUID from a binary serialization of a GUID string in network byte
// order format.
MEDIA_EXPORT GUID GetGUIDFromString(const std::string& guid_string);

// Returns a binary serialization of a GUID string in network byte order format.
MEDIA_EXPORT std::string GetStringFromGUID(REFGUID guid);

// Given an AudioDecoderConfig, get its corresponding IMFMediaType format.
// Note:
// IMFMediaType is derived from IMFAttributes and hence all the of information
// in a media type is store as attributes.
// https://docs.microsoft.com/en-us/windows/win32/medfound/media-type-attributes
// has a list of media type attributes.
MEDIA_EXPORT HRESULT
GetDefaultAudioType(const AudioDecoderConfig decoder_config,
                    IMFMediaType** media_type_out);

#if BUILDFLAG(USE_PROPRIETARY_CODECS)
// Given an AudioDecoderConfig which represents AAC audio, get its
// corresponding IMFMediaType format (by calling GetDefaultAudioType)
// and populate the aac_extra_data in the decoder_config into the
// returned IMFMediaType.
MEDIA_EXPORT HRESULT GetAacAudioType(const AudioDecoderConfig& decoder_config,
                                     IMFMediaType** media_type_out);
#endif  // BUILDFLAG(USE_PROPRIETARY_CODECS)

#if BUILDFLAG(ENABLE_PLATFORM_AC4_AUDIO)
// Given an AudioDecoderConfig which represents AC4 audio, get its
// corresponding IMFMediaType format (by calling GetDefaultAudioType)
// and populate the AC4 extra_data in the decoder_config into the
// returned IMFMediaType.
MEDIA_EXPORT HRESULT GetAC4AudioType(const AudioDecoderConfig& decoder_config,
                                     IMFMediaType** media_type_out);
#endif  // BUILDFLAG(ENABLE_PLATFORM_AC4_AUDIO)

// A wrapper of SubsampleEntry for MediaFoundation. The data blob associated
// with MFSampleExtension_Encryption_SubSample_Mapping attribute should contain
// an array of byte ranges as DWORDs where every two DWORDs make a set.
// SubsampleEntry has a set of uint32_t that needs to be converted to DWORDs.
struct MediaFoundationSubsampleEntry {
  explicit MediaFoundationSubsampleEntry(SubsampleEntry entry)
      : clear_bytes(entry.clear_bytes), cipher_bytes(entry.cypher_bytes) {}
  MediaFoundationSubsampleEntry() = default;
  DWORD clear_bytes = 0;
  DWORD cipher_bytes = 0;
};

// Converts between MFTIME and TimeDelta. MFTIME defines units of 100
// nanoseconds. See
// https://learn.microsoft.com/en-us/windows/win32/medfound/mftime
MEDIA_EXPORT MFTIME TimeDeltaToMfTime(base::TimeDelta time);
MEDIA_EXPORT base::TimeDelta MfTimeToTimeDelta(MFTIME mf_time);

// Converts `codec` into a MediaFoundation subtype. `profile` must be provided
// when converting VideoCodec::kDolbyVision.
MEDIA_EXPORT GUID
VideoCodecToMFSubtype(VideoCodec codec,
                      VideoCodecProfile profile = VIDEO_CODEC_PROFILE_UNKNOWN);

// Converts `video_pixel_format` into a MediaFoundation subtype.
MEDIA_EXPORT GUID
VideoPixelFormatToMFSubtype(VideoPixelFormat video_pixel_format);

// Converts `primaries` into an MFVideoPrimaries value
MEDIA_EXPORT MFVideoPrimaries
VideoPrimariesToMFVideoPrimaries(gfx::ColorSpace::PrimaryID primaries);

// Callback to transform a Media Foundation sample when converting from the
// DecoderBuffer if needed.
using TransformSampleCB =
    base::OnceCallback<HRESULT(Microsoft::WRL::ComPtr<IMFSample>& sample)>;

// Converts the DecoderBuffer back to a Media Foundation sample.
// `TransformSampleCB` is to allow derived classes to transform the Media
// Foundation sample if needed.
MEDIA_EXPORT HRESULT
GenerateSampleFromDecoderBuffer(const scoped_refptr<DecoderBuffer>& buffer,
                                IMFSample** sample_out,
                                GUID* last_key_id,
                                TransformSampleCB transform_sample_cb);

// Creates a DecryptConfig from a Media Foundation sample.
MEDIA_EXPORT HRESULT
CreateDecryptConfigFromSample(IMFSample* mf_sample,
                              const GUID& key_id,
                              std::unique_ptr<DecryptConfig>* decrypt_config);

// Converts `frame` into an IMFSample, using an underlying D3D texture,
// reading back from the GPU, or copying the frame contents as necessary.
MEDIA_EXPORT HRESULT GenerateSampleFromVideoFrame(
    const media::VideoFrame* frame,
    DXGIDeviceManager* dxgi_device_manager,
    bool use_dxgi_buffer,
    Microsoft::WRL::ComPtr<ID3D11Texture2D>* staging_texture,
    DWORD buffer_alignment,
    IMFSample** sample_out);

class CommandBufferHelper;
typedef base::OnceCallback<void(scoped_refptr<VideoFrame> frame,
                                Microsoft::WRL::ComPtr<IMFSample>,
                                HRESULT)>
    SampleAvailableCB;

MEDIA_EXPORT void GenerateSampleFromSharedImageVideoFrame(
    scoped_refptr<VideoFrame> frame,
    Microsoft::WRL::ComPtr<ID3D11Device> d3d_device,
    scoped_refptr<CommandBufferHelper> command_buffer_helper,
    SampleAvailableCB sample_available_cb);

}  // namespace media

#endif  // MEDIA_BASE_WIN_MF_HELPERS_H_