Bumping manifests a=b2g-bump
[gecko.git] / media / gmp-clearkey / 0.1 / WMFH264Decoder.cpp
blob019f7b274bfa0f85f7822affeecaa74deeb30d0f
1 /*
2 * Copyright 2013, Mozilla Foundation and contributors
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
17 #include "WMFH264Decoder.h"
18 #include <algorithm>
20 namespace wmf {
22 WMFH264Decoder::WMFH264Decoder()
23 : mDecoder(nullptr)
25 memset(&mInputStreamInfo, 0, sizeof(MFT_INPUT_STREAM_INFO));
26 memset(&mOutputStreamInfo, 0, sizeof(MFT_OUTPUT_STREAM_INFO));
29 WMFH264Decoder::~WMFH264Decoder()
33 HRESULT
34 WMFH264Decoder::Init()
36 HRESULT hr;
38 hr = CreateMFT(__uuidof(CMSH264DecoderMFT),
39 "msmpeg2vdec.dll",
40 mDecoder);
41 ENSURE(SUCCEEDED(hr), hr);
43 hr = SetDecoderInputType();
44 ENSURE(SUCCEEDED(hr), hr);
46 hr = SetDecoderOutputType();
47 ENSURE(SUCCEEDED(hr), hr);
49 hr = SendMFTMessage(MFT_MESSAGE_NOTIFY_BEGIN_STREAMING, 0);
50 ENSURE(SUCCEEDED(hr), hr);
52 hr = SendMFTMessage(MFT_MESSAGE_NOTIFY_START_OF_STREAM, 0);
53 ENSURE(SUCCEEDED(hr), hr);
55 hr = mDecoder->GetInputStreamInfo(0, &mInputStreamInfo);
56 ENSURE(SUCCEEDED(hr), hr);
58 hr = mDecoder->GetOutputStreamInfo(0, &mOutputStreamInfo);
59 ENSURE(SUCCEEDED(hr), hr);
61 return S_OK;
64 HRESULT
65 WMFH264Decoder::ConfigureVideoFrameGeometry(IMFMediaType* aMediaType)
67 ENSURE(aMediaType != nullptr, E_POINTER);
68 HRESULT hr;
70 IntRect pictureRegion;
71 hr = wmf::GetPictureRegion(aMediaType, pictureRegion);
72 ENSURE(SUCCEEDED(hr), hr);
74 UINT32 width = 0, height = 0;
75 hr = MFGetAttributeSize(aMediaType, MF_MT_FRAME_SIZE, &width, &height);
76 ENSURE(SUCCEEDED(hr), hr);
78 // Success! Save state.
79 GetDefaultStride(aMediaType, (UINT32*)&mStride);
80 mVideoWidth = width;
81 mVideoHeight = height;
82 mPictureRegion = pictureRegion;
84 LOG("WMFH264Decoder frame geometry frame=(%u,%u) stride=%u picture=(%d, %d, %d, %d)\n",
85 width, height,
86 mStride,
87 mPictureRegion.x, mPictureRegion.y, mPictureRegion.width, mPictureRegion.height);
89 return S_OK;
92 int32_t
93 WMFH264Decoder::GetFrameWidth() const
95 return mVideoWidth;
98 int32_t
99 WMFH264Decoder::GetFrameHeight() const
101 return mVideoHeight;
104 const IntRect&
105 WMFH264Decoder::GetPictureRegion() const
107 return mPictureRegion;
110 int32_t
111 WMFH264Decoder::GetStride() const
113 return mStride;
116 HRESULT
117 WMFH264Decoder::SetDecoderInputType()
119 HRESULT hr;
121 CComPtr<IMFMediaType> type;
122 hr = MFCreateMediaType(&type);
123 ENSURE(SUCCEEDED(hr), hr);
125 hr = type->SetGUID(MF_MT_MAJOR_TYPE, MFMediaType_Video);
126 ENSURE(SUCCEEDED(hr), hr);
128 hr = type->SetGUID(MF_MT_SUBTYPE, MFVideoFormat_H264);
129 ENSURE(SUCCEEDED(hr), hr);
131 hr = type->SetUINT32(MF_MT_INTERLACE_MODE, MFVideoInterlace_MixedInterlaceOrProgressive);
132 ENSURE(SUCCEEDED(hr), hr);
134 hr = mDecoder->SetInputType(0, type, 0);
135 ENSURE(SUCCEEDED(hr), hr);
137 return S_OK;
140 HRESULT
141 WMFH264Decoder::SetDecoderOutputType()
143 HRESULT hr;
145 CComPtr<IMFMediaType> type;
147 UINT32 typeIndex = 0;
148 while (type = nullptr, SUCCEEDED(mDecoder->GetOutputAvailableType(0, typeIndex++, &type))) {
149 GUID subtype;
150 hr = type->GetGUID(MF_MT_SUBTYPE, &subtype);
151 if (FAILED(hr)) {
152 continue;
154 if (subtype == MFVideoFormat_I420) {
155 hr = mDecoder->SetOutputType(0, type, 0);
156 ENSURE(SUCCEEDED(hr), hr);
158 hr = ConfigureVideoFrameGeometry(type);
159 ENSURE(SUCCEEDED(hr), hr);
161 return S_OK;
165 return E_FAIL;
168 HRESULT
169 WMFH264Decoder::SendMFTMessage(MFT_MESSAGE_TYPE aMsg, UINT32 aData)
171 ENSURE(mDecoder != nullptr, E_POINTER);
172 HRESULT hr = mDecoder->ProcessMessage(aMsg, aData);
173 ENSURE(SUCCEEDED(hr), hr);
174 return S_OK;
177 HRESULT
178 WMFH264Decoder::CreateInputSample(const uint8_t* aData,
179 uint32_t aDataSize,
180 Microseconds aTimestamp,
181 Microseconds aDuration,
182 IMFSample** aOutSample)
184 HRESULT hr;
185 CComPtr<IMFSample> sample;
186 hr = MFCreateSample(&sample);
187 ENSURE(SUCCEEDED(hr), hr);
189 CComPtr<IMFMediaBuffer> buffer;
190 int32_t bufferSize = std::max<uint32_t>(uint32_t(mInputStreamInfo.cbSize), aDataSize);
191 UINT32 alignment = (mInputStreamInfo.cbAlignment > 1) ? mInputStreamInfo.cbAlignment - 1 : 0;
192 hr = MFCreateAlignedMemoryBuffer(bufferSize, alignment, &buffer);
193 ENSURE(SUCCEEDED(hr), hr);
195 DWORD maxLength = 0;
196 DWORD currentLength = 0;
197 BYTE* dst = nullptr;
198 hr = buffer->Lock(&dst, &maxLength, &currentLength);
199 ENSURE(SUCCEEDED(hr), hr);
201 // Copy data into sample's buffer.
202 memcpy(dst, aData, aDataSize);
204 hr = buffer->Unlock();
205 ENSURE(SUCCEEDED(hr), hr);
207 hr = buffer->SetCurrentLength(aDataSize);
208 ENSURE(SUCCEEDED(hr), hr);
210 hr = sample->AddBuffer(buffer);
211 ENSURE(SUCCEEDED(hr), hr);
213 hr = sample->SetSampleTime(UsecsToHNs(aTimestamp));
214 ENSURE(SUCCEEDED(hr), hr);
216 sample->SetSampleDuration(UsecsToHNs(aDuration));
218 *aOutSample = sample.Detach();
220 return S_OK;
223 HRESULT
224 WMFH264Decoder::CreateOutputSample(IMFSample** aOutSample)
226 HRESULT hr;
227 CComPtr<IMFSample> sample;
228 hr = MFCreateSample(&sample);
229 ENSURE(SUCCEEDED(hr), hr);
231 CComPtr<IMFMediaBuffer> buffer;
232 int32_t bufferSize = mOutputStreamInfo.cbSize;
233 UINT32 alignment = (mOutputStreamInfo.cbAlignment > 1) ? mOutputStreamInfo.cbAlignment - 1 : 0;
234 hr = MFCreateAlignedMemoryBuffer(bufferSize, alignment, &buffer);
235 ENSURE(SUCCEEDED(hr), hr);
237 hr = sample->AddBuffer(buffer);
238 ENSURE(SUCCEEDED(hr), hr);
240 *aOutSample = sample.Detach();
242 return S_OK;
246 HRESULT
247 WMFH264Decoder::GetOutputSample(IMFSample** aOutSample)
249 HRESULT hr;
250 // We allocate samples for MFT output.
251 MFT_OUTPUT_DATA_BUFFER output = {0};
253 CComPtr<IMFSample> sample;
254 hr = CreateOutputSample(&sample);
255 ENSURE(SUCCEEDED(hr), hr);
257 output.pSample = sample;
259 DWORD status = 0;
260 hr = mDecoder->ProcessOutput(0, 1, &output, &status);
261 //LOG(L"WMFH264Decoder::GetOutputSample() ProcessOutput returned 0x%x\n", hr);
262 CComPtr<IMFCollection> events = output.pEvents; // Ensure this is released.
264 if (hr == MF_E_TRANSFORM_STREAM_CHANGE) {
265 // Type change. Probably geometric apperature change.
266 hr = SetDecoderOutputType();
267 ENSURE(SUCCEEDED(hr), hr);
269 return GetOutputSample(aOutSample);
270 } else if (hr == MF_E_TRANSFORM_NEED_MORE_INPUT) {
271 return MF_E_TRANSFORM_NEED_MORE_INPUT;
273 // Treat other errors as fatal.
274 ENSURE(SUCCEEDED(hr), hr);
276 assert(sample);
278 // output.pSample
279 *aOutSample = sample.Detach(); // AddRefs
280 return S_OK;
283 HRESULT
284 WMFH264Decoder::Input(const uint8_t* aData,
285 uint32_t aDataSize,
286 Microseconds aTimestamp,
287 Microseconds aDuration)
289 HRESULT hr;
290 CComPtr<IMFSample> input = nullptr;
291 hr = CreateInputSample(aData, aDataSize, aTimestamp, aDuration, &input);
292 ENSURE(SUCCEEDED(hr) && input!=nullptr, hr);
294 hr = mDecoder->ProcessInput(0, input, 0);
295 if (hr == MF_E_NOTACCEPTING) {
296 // MFT *already* has enough data to produce a sample. Retrieve it.
297 LOG("ProcessInput returned MF_E_NOTACCEPTING\n");
298 return MF_E_NOTACCEPTING;
300 ENSURE(SUCCEEDED(hr), hr);
302 return S_OK;
305 HRESULT
306 WMFH264Decoder::Output(IMFSample** aOutput)
308 HRESULT hr;
309 CComPtr<IMFSample> outputSample;
310 hr = GetOutputSample(&outputSample);
311 if (hr == MF_E_TRANSFORM_NEED_MORE_INPUT) {
312 return MF_E_TRANSFORM_NEED_MORE_INPUT;
314 // Treat other errors as fatal.
315 ENSURE(SUCCEEDED(hr) && outputSample, hr);
317 *aOutput = outputSample.Detach();
319 return S_OK;
322 HRESULT
323 WMFH264Decoder::Reset()
325 HRESULT hr = SendMFTMessage(MFT_MESSAGE_COMMAND_FLUSH, 0);
326 ENSURE(SUCCEEDED(hr), hr);
328 return S_OK;
331 HRESULT
332 WMFH264Decoder::Drain()
334 HRESULT hr = SendMFTMessage(MFT_MESSAGE_COMMAND_DRAIN, 0);
335 ENSURE(SUCCEEDED(hr), hr);
337 return S_OK;
340 } // namespace wmf