/
AsfContentInfoBuilder.cpp
141 lines (103 loc) · 4.46 KB
/
AsfContentInfoBuilder.cpp
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
#include "stdafx.h"
#include <windows.h>
#include <propvarutil.h>
#include <stdexcept>
#include "AsfContentInfoBuilder.h"
AsfContentInfoBuilder::AsfContentInfoBuilder()
{
IPropertyStore* fileLevelEncodingConfiguration = nullptr;
HRESULT hr;
_mfAsfContentInfo = nullptr;
_mfAsfProfile = nullptr;
_mfMetadataProvider = nullptr;
_mfMetadata = nullptr;
do
{
if (!SUCCEEDED(hr = MFCreateASFContentInfo(&_mfAsfContentInfo)))
break;
if (!SUCCEEDED(hr = MFCreateASFProfile(&_mfAsfProfile)))
break;
if (!SUCCEEDED(hr = _mfAsfContentInfo->QueryInterface(IID_IMFMetadataProvider, (void**)&_mfMetadataProvider)))
break;
if (!SUCCEEDED(hr = _mfMetadataProvider->GetMFMetadata(NULL, 0, 0, &_mfMetadata)))
break;
// Set MFPKEY_ASFMEDIASINK_AUTOADJUST_BITRATE to true on the file-level encoding configuration
// property store. Does this actually do anything? Is it needed?
if (!SUCCEEDED(hr = _mfAsfContentInfo->GetEncodingConfigurationPropertyStore(0, &fileLevelEncodingConfiguration)))
break;
PROPVARIANT pv;
InitPropVariantFromBoolean(TRUE, &pv);
if (!SUCCEEDED(hr = fileLevelEncodingConfiguration->SetValue(MFPKEY_ASFMEDIASINK_AUTOADJUST_BITRATE, pv)))
break;
PropVariantClear(&pv);
} while (0);
if (fileLevelEncodingConfiguration) fileLevelEncodingConfiguration->Release();
if (FAILED(hr))
{
if (_mfMetadata) _mfMetadata->Release();
if (_mfMetadataProvider) _mfMetadataProvider->Release();
if (_mfAsfProfile) _mfAsfProfile->Release();
if (_mfAsfContentInfo) _mfAsfContentInfo->Release();
throw std::exception("Unable to create MediaSinkContentInfo object");
}
}
AsfContentInfoBuilder::~AsfContentInfoBuilder()
{
_mfMetadata->Release();
_mfMetadataProvider->Release();
_mfAsfProfile->Release();
_mfAsfContentInfo->Release();
}
void AsfContentInfoBuilder::AddStreamSink(WORD streamNumber, AudioEncoderParameters* encoderParameters)
{
HRESULT hr;
// First off, get the appropriate Media Foundation MediaType from the encoder, based on the compressor parameters
// we've specified
IMFMediaType* mfMediaType = AudioEncoder::GetEncoderMediaType(encoderParameters);
IMFASFStreamConfig* mfAsfStreamConfig = nullptr;
do
{
if (!SUCCEEDED(hr = _mfAsfProfile->CreateStream(mfMediaType, &mfAsfStreamConfig)))
break;
if (!SUCCEEDED(hr = mfAsfStreamConfig->SetStreamNumber(streamNumber)))
break;
if (!SUCCEEDED(hr = _mfAsfProfile->SetStream(mfAsfStreamConfig)))
break;
// Here's the critical piece needed to make Quality-based VBR encoding work:
// The audio encoder is instantiated indirectly based on the stream sink,
// but the stream sink's MediaType alone is not enough to get the audio encoder
// into a state where it will perform quality-based VBR compression. That's
// because some specific properties need to be set on the Media Foundation's
// transform before we make the call to enumerate the available compression
// options. So, the AsfStreamConfig object has an additional property store
// tacked on to it where we can set these property values that need to be set
// on the encoder. Somewhat oddly they're not attached to the AsfStreamConfig,
// nor are they attached to the AsfProfile object that's used to add stream
// sinks. Rather, this property store is tied to the AsfContentInfo object and
// the association between the stream sinks and the encoder parameter property
// store is maintained by the stream number
if (encoderParameters->IsQualityBasedVbr())
{
IPropertyStore *streamPropertyStore; // TODO when should this be released?
if (!SUCCEEDED(hr = _mfAsfContentInfo->GetEncodingConfigurationPropertyStore(streamNumber, &streamPropertyStore)))
break;
AudioEncoder::SetEncoderPropertiesForQualityBasedVbr(streamPropertyStore, encoderParameters->GetQualityLevel());
}
} while (0);
if (mfAsfStreamConfig) mfAsfStreamConfig->Release();
if (FAILED(hr))
throw std::exception("Unable to add stream to the MediaSink");
}
void AsfContentInfoBuilder::SetMetadataAsString(PCWSTR field, PCWSTR value)
{
PROPVARIANT pv;
InitPropVariantFromString(value, &pv);
HRESULT hr = _mfMetadata->SetProperty(field, &pv);
PropVariantClear(&pv);
}
IMFASFContentInfo* AsfContentInfoBuilder::ConstructMfAsfContentInfo()
{
SetMetadataAsString(L"WM/EncodedBy", L"MfEncoder");
_mfAsfContentInfo->SetProfile(_mfAsfProfile);
return _mfAsfContentInfo;
}