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"
22 WMFH264Decoder::WMFH264Decoder()
25 memset(&mInputStreamInfo
, 0, sizeof(MFT_INPUT_STREAM_INFO
));
26 memset(&mOutputStreamInfo
, 0, sizeof(MFT_OUTPUT_STREAM_INFO
));
29 WMFH264Decoder::~WMFH264Decoder()
34 WMFH264Decoder::Init()
38 hr
= CreateMFT(__uuidof(CMSH264DecoderMFT
),
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
);
65 WMFH264Decoder::ConfigureVideoFrameGeometry(IMFMediaType
* aMediaType
)
67 ENSURE(aMediaType
!= nullptr, E_POINTER
);
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
);
81 mVideoHeight
= height
;
82 mPictureRegion
= pictureRegion
;
84 LOG("WMFH264Decoder frame geometry frame=(%u,%u) stride=%u picture=(%d, %d, %d, %d)\n",
87 mPictureRegion
.x
, mPictureRegion
.y
, mPictureRegion
.width
, mPictureRegion
.height
);
93 WMFH264Decoder::GetFrameWidth() const
99 WMFH264Decoder::GetFrameHeight() const
105 WMFH264Decoder::GetPictureRegion() const
107 return mPictureRegion
;
111 WMFH264Decoder::GetStride() const
117 WMFH264Decoder::SetDecoderInputType()
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
);
141 WMFH264Decoder::SetDecoderOutputType()
145 CComPtr
<IMFMediaType
> type
;
147 UINT32 typeIndex
= 0;
148 while (type
= nullptr, SUCCEEDED(mDecoder
->GetOutputAvailableType(0, typeIndex
++, &type
))) {
150 hr
= type
->GetGUID(MF_MT_SUBTYPE
, &subtype
);
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
);
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
);
178 WMFH264Decoder::CreateInputSample(const uint8_t* aData
,
180 Microseconds aTimestamp
,
181 Microseconds aDuration
,
182 IMFSample
** aOutSample
)
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
);
196 DWORD currentLength
= 0;
198 hr
= buffer
->Lock(&dst
, &maxLength
, ¤tLength
);
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();
224 WMFH264Decoder::CreateOutputSample(IMFSample
** aOutSample
)
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();
247 WMFH264Decoder::GetOutputSample(IMFSample
** aOutSample
)
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
;
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
);
279 *aOutSample
= sample
.Detach(); // AddRefs
284 WMFH264Decoder::Input(const uint8_t* aData
,
286 Microseconds aTimestamp
,
287 Microseconds aDuration
)
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
);
306 WMFH264Decoder::Output(IMFSample
** aOutput
)
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();
323 WMFH264Decoder::Reset()
325 HRESULT hr
= SendMFTMessage(MFT_MESSAGE_COMMAND_FLUSH
, 0);
326 ENSURE(SUCCEEDED(hr
), hr
);
332 WMFH264Decoder::Drain()
334 HRESULT hr
= SendMFTMessage(MFT_MESSAGE_COMMAND_DRAIN
, 0);
335 ENSURE(SUCCEEDED(hr
), hr
);