demux: heif: send extradata with avif
[vlc.git] / modules / codec / mft.c
blob175fd6b63fc43fdb4749e2c91e05755c65e73a24
1 /*****************************************************************************
2 * mft.c : Media Foundation Transform audio/video decoder
3 *****************************************************************************
4 * Copyright (C) 2014 VLC authors and VideoLAN
6 * Author: Felix Abecassis <felix.abecassis@gmail.com>
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms of the GNU Lesser General Public License as published by
10 * the Free Software Foundation; either version 2.1 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public License
19 * along with this program; if not, write to the Free Software Foundation,
20 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
21 *****************************************************************************/
23 #ifdef HAVE_CONFIG_H
24 # include "config.h"
25 #endif
27 #undef WINVER
28 #define WINVER 0x0601
30 /* Needed for many mingw macros. */
31 #define COBJMACROS
33 /* Avoid having GUIDs being defined as "extern". */
34 #define INITGUID
36 #ifndef STDCALL
37 # define STDCALL __stdcall
38 #endif
40 #include <winapifamily.h>
41 #undef WINAPI_FAMILY
42 #define WINAPI_FAMILY WINAPI_FAMILY_DESKTOP_APP
44 #include <assert.h>
46 #include <vlc_common.h>
47 #include <vlc_plugin.h>
48 #include <vlc_codec.h>
49 #include "../packetizer/h264_nal.h"
50 #define _VIDEOINFOHEADER_
51 #include <vlc_codecs.h>
53 #include <mfapi.h>
54 #include <mftransform.h>
55 #include <mferror.h>
56 #include <mfobjects.h>
58 static int Open(vlc_object_t *);
59 static void Close(vlc_object_t *);
61 vlc_module_begin()
62 set_description(N_("Media Foundation Transform decoder"))
63 add_shortcut("mft")
64 set_capability("video decoder", 1)
65 set_callbacks(Open, Close)
66 set_category(CAT_INPUT)
67 set_subcategory(SUBCAT_INPUT_VCODEC)
69 add_submodule()
70 add_shortcut("mft")
71 set_capability("audio decoder", 1)
72 set_callbacks(Open, Close)
73 vlc_module_end()
75 typedef struct
77 HINSTANCE mfplat_dll;
78 HRESULT (STDCALL *fptr_MFTEnumEx)(GUID guidCategory, UINT32 Flags,
79 const MFT_REGISTER_TYPE_INFO *pInputType,
80 const MFT_REGISTER_TYPE_INFO *pOutputType,
81 IMFActivate ***pppMFTActivate, UINT32 *pcMFTActivate);
82 HRESULT (STDCALL *fptr_MFCreateSample)(IMFSample **ppIMFSample);
83 HRESULT (STDCALL *fptr_MFCreateMemoryBuffer)(DWORD cbMaxLength, IMFMediaBuffer **ppBuffer);
84 HRESULT (STDCALL *fptr_MFCreateAlignedMemoryBuffer)(DWORD cbMaxLength, DWORD fAlignmentFlags, IMFMediaBuffer **ppBuffer);
85 } MFHandle;
87 typedef struct
89 MFHandle mf_handle;
91 IMFTransform *mft;
93 const GUID* major_type;
94 const GUID* subtype;
95 /* Container for a dynamically constructed subtype */
96 GUID custom_subtype;
98 /* For asynchronous MFT */
99 bool is_async;
100 IMFMediaEventGenerator *event_generator;
101 int pending_input_events;
102 int pending_output_events;
104 /* Input stream */
105 DWORD input_stream_id;
106 IMFMediaType *input_type;
108 /* Output stream */
109 DWORD output_stream_id;
110 IMFSample *output_sample;
111 IMFMediaType *output_type;
113 /* H264 only. */
114 uint8_t nal_length_size;
115 } decoder_sys_t;
117 static const int pi_channels_maps[9] =
120 AOUT_CHAN_CENTER,
121 AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT,
122 AOUT_CHAN_CENTER | AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT,
123 AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT | AOUT_CHAN_REARLEFT
124 | AOUT_CHAN_REARRIGHT,
125 AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT | AOUT_CHAN_CENTER
126 | AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT,
127 AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT | AOUT_CHAN_CENTER
128 | AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT | AOUT_CHAN_LFE,
129 AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT | AOUT_CHAN_CENTER
130 | AOUT_CHAN_REARCENTER | AOUT_CHAN_MIDDLELEFT
131 | AOUT_CHAN_MIDDLERIGHT | AOUT_CHAN_LFE,
132 AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT | AOUT_CHAN_CENTER | AOUT_CHAN_REARLEFT
133 | AOUT_CHAN_REARRIGHT | AOUT_CHAN_MIDDLELEFT | AOUT_CHAN_MIDDLERIGHT
134 | AOUT_CHAN_LFE,
137 /* Possibly missing from mingw headers */
138 #ifndef MF_E_TRANSFORM_NEED_MORE_INPUT
139 # define MF_E_TRANSFORM_NEED_MORE_INPUT _HRESULT_TYPEDEF_(0xc00d6d72)
140 #endif
142 #ifndef MF_E_TRANSFORM_STREAM_CHANGE
143 # define MF_E_TRANSFORM_STREAM_CHANGE _HRESULT_TYPEDEF_(0xc00d6d61)
144 #endif
146 #ifndef MF_E_NO_EVENTS_AVAILABLE
147 # define MF_E_NO_EVENTS_AVAILABLE _HRESULT_TYPEDEF_(0xC00D3E80L)
148 #endif
150 #ifndef MF_EVENT_FLAG_NO_WAIT
151 # define MF_EVENT_FLAG_NO_WAIT 0x00000001
152 #endif
155 * The MFTransformXXX values might not be defined in mingw headers,
156 * thus we use our own enum with the VLC prefix.
158 enum
160 VLC_METransformUnknown = 600,
161 VLC_METransformNeedInput,
162 VLC_METransformHaveOutput,
163 VLC_METransformDrainComplete,
164 VLC_METransformMarker,
167 typedef struct
169 vlc_fourcc_t fourcc;
170 const GUID *guid;
171 } pair_format_guid;
174 * We need this table since the FOURCC used for GUID is not the same
175 * as the FOURCC used by VLC, for instance h264 vs H264.
177 static const pair_format_guid video_format_table[] =
179 { VLC_CODEC_H264, &MFVideoFormat_H264 },
180 { VLC_CODEC_MJPG, &MFVideoFormat_MJPG },
181 { VLC_CODEC_WMV1, &MFVideoFormat_WMV1 },
182 { VLC_CODEC_WMV2, &MFVideoFormat_WMV2 },
183 { VLC_CODEC_WMV3, &MFVideoFormat_WMV3 },
184 { VLC_CODEC_VC1, &MFVideoFormat_WVC1 },
185 { 0, NULL }
188 // 8-bit luminance only
189 DEFINE_MEDIATYPE_GUID (MFVideoFormat_L8, 50);
192 * Table to map MF Transform raw 3D3 output formats to native VLC FourCC
194 static const pair_format_guid d3d_format_table[] = {
195 { VLC_CODEC_RGB32, &MFVideoFormat_RGB32 },
196 { VLC_CODEC_RGB24, &MFVideoFormat_RGB24 },
197 { VLC_CODEC_RGBA, &MFVideoFormat_ARGB32 },
198 { VLC_CODEC_GREY, &MFVideoFormat_L8 },
199 { 0, NULL }
202 #if defined(__MINGW64_VERSION_MAJOR) && __MINGW64_VERSION_MAJOR < 4
203 DEFINE_GUID(MFAudioFormat_Dolby_AC3, 0xe06d802c, 0xdb46, 0x11cf, 0xb4, 0xd1, 0x00, 0x80, 0x5f, 0x6c, 0xbb, 0xea);
204 #endif
206 * We cannot use the FOURCC code for audio either since the
207 * WAVE_FORMAT value is used to create the GUID.
209 static const pair_format_guid audio_format_table[] =
211 { VLC_CODEC_MPGA, &MFAudioFormat_MPEG },
212 { VLC_CODEC_MP3, &MFAudioFormat_MP3 },
213 { VLC_CODEC_DTS, &MFAudioFormat_DTS },
214 { VLC_CODEC_MP4A, &MFAudioFormat_AAC },
215 { VLC_CODEC_WMA2, &MFAudioFormat_WMAudioV8 },
216 { VLC_CODEC_A52, &MFAudioFormat_Dolby_AC3 },
217 { 0, NULL }
220 static const GUID *FormatToGUID(const pair_format_guid table[], vlc_fourcc_t fourcc)
222 for (int i = 0; table[i].fourcc; ++i)
223 if (table[i].fourcc == fourcc)
224 return table[i].guid;
226 return NULL;
229 static vlc_fourcc_t GUIDToFormat(const pair_format_guid table[], const GUID* guid)
231 for (int i = 0; table[i].fourcc; ++i)
232 if (IsEqualGUID(table[i].guid, guid))
233 return table[i].fourcc;
235 return 0;
239 * Low latency mode for Windows 8. Without this option, the H264
240 * decoder will fill *all* its internal buffers before returning a
241 * frame. Because of this behavior, the decoder might return no frame
242 * for more than 500 ms, making it unusable for playback.
244 DEFINE_GUID(CODECAPI_AVLowLatencyMode, 0x9c27891a, 0xed7a, 0x40e1, 0x88, 0xe8, 0xb2, 0x27, 0x27, 0xa0, 0x24, 0xee);
246 static int SetInputType(decoder_t *p_dec, DWORD stream_id, IMFMediaType **result)
248 decoder_sys_t *p_sys = p_dec->p_sys;
249 HRESULT hr;
251 *result = NULL;
253 IMFMediaType *input_media_type = NULL;
255 /* Search a suitable input type for the MFT. */
256 int input_type_index = 0;
257 bool found = false;
258 for (int i = 0; !found; ++i)
260 hr = IMFTransform_GetInputAvailableType(p_sys->mft, stream_id, i, &input_media_type);
261 if (hr == MF_E_NO_MORE_TYPES)
262 break;
263 else if (hr == MF_E_TRANSFORM_TYPE_NOT_SET)
265 /* The output type must be set before setting the input type for this MFT. */
266 return VLC_SUCCESS;
268 else if (FAILED(hr))
269 goto error;
271 GUID subtype;
272 hr = IMFMediaType_GetGUID(input_media_type, &MF_MT_SUBTYPE, &subtype);
273 if (FAILED(hr))
274 goto error;
276 if (IsEqualGUID(&subtype, p_sys->subtype))
277 found = true;
279 if (found)
280 input_type_index = i;
282 IMFMediaType_Release(input_media_type);
283 input_media_type = NULL;
285 if (!found)
286 goto error;
288 hr = IMFTransform_GetInputAvailableType(p_sys->mft, stream_id, input_type_index, &input_media_type);
289 if (FAILED(hr))
290 goto error;
292 if (p_dec->fmt_in.i_cat == VIDEO_ES)
294 UINT64 width = p_dec->fmt_in.video.i_width;
295 UINT64 height = p_dec->fmt_in.video.i_height;
296 UINT64 frame_size = (width << 32) | height;
297 hr = IMFMediaType_SetUINT64(input_media_type, &MF_MT_FRAME_SIZE, frame_size);
298 if (FAILED(hr))
299 goto error;
301 /* Some transforms like to know the frame rate and may reject the input type otherwise. */
302 UINT64 frame_ratio_num = p_dec->fmt_in.video.i_frame_rate;
303 UINT64 frame_ratio_dem = p_dec->fmt_in.video.i_frame_rate_base;
304 if(frame_ratio_num && frame_ratio_dem) {
305 UINT64 frame_rate = (frame_ratio_num << 32) | frame_ratio_dem;
306 hr = IMFMediaType_SetUINT64(input_media_type, &MF_MT_FRAME_RATE, frame_rate);
307 if(FAILED(hr))
308 goto error;
311 else
313 hr = IMFMediaType_SetUINT32(input_media_type, &MF_MT_ORIGINAL_WAVE_FORMAT_TAG, p_sys->subtype->Data1);
314 if (FAILED(hr))
315 goto error;
316 if (p_dec->fmt_in.audio.i_rate)
318 hr = IMFMediaType_SetUINT32(input_media_type, &MF_MT_AUDIO_SAMPLES_PER_SECOND, p_dec->fmt_in.audio.i_rate);
319 if (FAILED(hr))
320 goto error;
322 if (p_dec->fmt_in.audio.i_channels)
324 hr = IMFMediaType_SetUINT32(input_media_type, &MF_MT_AUDIO_NUM_CHANNELS, p_dec->fmt_in.audio.i_channels);
325 if (FAILED(hr))
326 goto error;
328 if (p_dec->fmt_in.audio.i_bitspersample)
330 hr = IMFMediaType_SetUINT32(input_media_type, &MF_MT_AUDIO_BITS_PER_SAMPLE, p_dec->fmt_in.audio.i_bitspersample);
331 if (FAILED(hr))
332 goto error;
334 if (p_dec->fmt_in.audio.i_blockalign)
336 hr = IMFMediaType_SetUINT32(input_media_type, &MF_MT_AUDIO_BLOCK_ALIGNMENT, p_dec->fmt_in.audio.i_blockalign);
337 if (FAILED(hr))
338 goto error;
340 if (p_dec->fmt_in.i_bitrate)
342 hr = IMFMediaType_SetUINT32(input_media_type, &MF_MT_AUDIO_AVG_BYTES_PER_SECOND, p_dec->fmt_in.i_bitrate / 8);
343 if (FAILED(hr))
344 goto error;
348 if (p_dec->fmt_in.i_extra > 0)
350 UINT32 blob_size = 0;
351 hr = IMFMediaType_GetBlobSize(input_media_type, &MF_MT_USER_DATA, &blob_size);
353 * Do not overwrite existing user data in the input type, this
354 * can cause the MFT to reject the type.
356 if (hr == MF_E_ATTRIBUTENOTFOUND)
358 hr = IMFMediaType_SetBlob(input_media_type, &MF_MT_USER_DATA,
359 (const UINT8*)p_dec->fmt_in.p_extra, p_dec->fmt_in.i_extra);
360 if (FAILED(hr))
361 goto error;
365 hr = IMFTransform_SetInputType(p_sys->mft, stream_id, input_media_type, 0);
366 if (FAILED(hr))
367 goto error;
369 *result = input_media_type;
371 return VLC_SUCCESS;
373 error:
374 msg_Err(p_dec, "Error in SetInputType()");
375 if (input_media_type)
376 IMFMediaType_Release(input_media_type);
377 return VLC_EGENERIC;
380 static int SetOutputType(decoder_t *p_dec, DWORD stream_id, IMFMediaType **result)
382 decoder_sys_t *p_sys = p_dec->p_sys;
383 HRESULT hr;
385 *result = NULL;
387 IMFMediaType *output_media_type = NULL;
390 * Enumerate available output types. The list is ordered by
391 * preference thus we will use the first one unless YV12/I420 is
392 * available for video or float32 for audio.
394 int output_type_index = -1;
395 bool found = false;
396 for (int i = 0; !found; ++i)
398 hr = IMFTransform_GetOutputAvailableType(p_sys->mft, stream_id, i, &output_media_type);
399 if (hr == MF_E_NO_MORE_TYPES)
400 break;
401 else if (hr == MF_E_TRANSFORM_TYPE_NOT_SET)
403 /* The input type must be set before setting the output type for this MFT. */
404 return VLC_SUCCESS;
406 else if (FAILED(hr))
407 goto error;
409 GUID subtype;
410 hr = IMFMediaType_GetGUID(output_media_type, &MF_MT_SUBTYPE, &subtype);
411 if (FAILED(hr))
412 goto error;
414 if (p_dec->fmt_in.i_cat == VIDEO_ES)
416 if (IsEqualGUID(&subtype, &MFVideoFormat_YV12) || IsEqualGUID(&subtype, &MFVideoFormat_I420))
417 found = true;
418 /* Transform might offer output in a D3DFMT propietary FCC. If we can
419 * use it, fall back to it in case we do not find YV12 or I420 */
420 else if(output_type_index < 0 && GUIDToFormat(d3d_format_table, &subtype) > 0)
421 output_type_index = i;
423 else
425 UINT32 bits_per_sample;
426 hr = IMFMediaType_GetUINT32(output_media_type, &MF_MT_AUDIO_BITS_PER_SAMPLE, &bits_per_sample);
427 if (FAILED(hr))
428 continue;
429 if (bits_per_sample == 32 && IsEqualGUID(&subtype, &MFAudioFormat_Float))
430 found = true;
433 if (found)
434 output_type_index = i;
436 IMFMediaType_Release(output_media_type);
437 output_media_type = NULL;
440 * It's not an error if we don't find the output type we were
441 * looking for, in this case we use the first available type.
443 if(output_type_index < 0)
444 /* No output format found we prefer, just pick the first one preferred
445 * by the MFT */
446 output_type_index = 0;
448 hr = IMFTransform_GetOutputAvailableType(p_sys->mft, stream_id, output_type_index, &output_media_type);
449 if (FAILED(hr))
450 goto error;
452 hr = IMFTransform_SetOutputType(p_sys->mft, stream_id, output_media_type, 0);
453 if (FAILED(hr))
454 goto error;
456 GUID subtype;
457 hr = IMFMediaType_GetGUID(output_media_type, &MF_MT_SUBTYPE, &subtype);
458 if (FAILED(hr))
459 goto error;
461 if (p_dec->fmt_in.i_cat == VIDEO_ES)
463 video_format_Copy( &p_dec->fmt_out.video, &p_dec->fmt_in.video );
465 /* Transform might offer output in a D3DFMT propietary FCC */
466 vlc_fourcc_t fcc = GUIDToFormat(d3d_format_table, &subtype);
467 if(fcc) {
468 /* D3D formats are upside down */
469 p_dec->fmt_out.video.orientation = ORIENT_BOTTOM_LEFT;
470 } else {
471 fcc = vlc_fourcc_GetCodec(p_dec->fmt_in.i_cat, subtype.Data1);
474 p_dec->fmt_out.i_codec = fcc;
476 else
478 p_dec->fmt_out.audio = p_dec->fmt_in.audio;
480 UINT32 bitspersample = 0;
481 hr = IMFMediaType_GetUINT32(output_media_type, &MF_MT_AUDIO_BITS_PER_SAMPLE, &bitspersample);
482 if (SUCCEEDED(hr) && bitspersample)
483 p_dec->fmt_out.audio.i_bitspersample = bitspersample;
485 UINT32 channels = 0;
486 hr = IMFMediaType_GetUINT32(output_media_type, &MF_MT_AUDIO_NUM_CHANNELS, &channels);
487 if (SUCCEEDED(hr) && channels)
488 p_dec->fmt_out.audio.i_channels = channels;
490 UINT32 rate = 0;
491 hr = IMFMediaType_GetUINT32(output_media_type, &MF_MT_AUDIO_SAMPLES_PER_SECOND, &rate);
492 if (SUCCEEDED(hr) && rate)
493 p_dec->fmt_out.audio.i_rate = rate;
495 vlc_fourcc_t fourcc;
496 wf_tag_to_fourcc(subtype.Data1, &fourcc, NULL);
497 p_dec->fmt_out.i_codec = vlc_fourcc_GetCodecAudio(fourcc, p_dec->fmt_out.audio.i_bitspersample);
499 p_dec->fmt_out.audio.i_physical_channels = pi_channels_maps[p_dec->fmt_out.audio.i_channels];
502 *result = output_media_type;
504 return VLC_SUCCESS;
506 error:
507 msg_Err(p_dec, "Error in SetOutputType()");
508 if (output_media_type)
509 IMFMediaType_Release(output_media_type);
510 return VLC_EGENERIC;
513 static int AllocateInputSample(decoder_t *p_dec, DWORD stream_id, IMFSample** result, DWORD size)
515 decoder_sys_t *p_sys = p_dec->p_sys;
516 MFHandle *mf = &p_sys->mf_handle;
517 HRESULT hr;
519 *result = NULL;
521 IMFSample *input_sample = NULL;
523 MFT_INPUT_STREAM_INFO input_info;
524 hr = IMFTransform_GetInputStreamInfo(p_sys->mft, stream_id, &input_info);
525 if (FAILED(hr))
526 goto error;
528 hr = mf->fptr_MFCreateSample(&input_sample);
529 if (FAILED(hr))
530 goto error;
532 IMFMediaBuffer *input_media_buffer = NULL;
533 DWORD allocation_size = __MAX(input_info.cbSize, size);
534 hr = mf->fptr_MFCreateMemoryBuffer(allocation_size, &input_media_buffer);
535 if (FAILED(hr))
536 goto error;
538 hr = IMFSample_AddBuffer(input_sample, input_media_buffer);
539 IMFMediaBuffer_Release(input_media_buffer);
540 if (FAILED(hr))
541 goto error;
543 *result = input_sample;
545 return VLC_SUCCESS;
547 error:
548 msg_Err(p_dec, "Error in AllocateInputSample()");
549 if (input_sample)
550 IMFSample_Release(input_sample);
551 if (input_media_buffer)
552 IMFMediaBuffer_Release(input_media_buffer);
553 return VLC_EGENERIC;
556 static int AllocateOutputSample(decoder_t *p_dec, DWORD stream_id, IMFSample **result)
558 decoder_sys_t *p_sys = p_dec->p_sys;
559 MFHandle *mf = &p_sys->mf_handle;
560 HRESULT hr;
562 *result = NULL;
564 IMFSample *output_sample = NULL;
566 MFT_OUTPUT_STREAM_INFO output_info;
567 hr = IMFTransform_GetOutputStreamInfo(p_sys->mft, stream_id, &output_info);
568 if (FAILED(hr))
569 goto error;
571 if (output_info.dwFlags & (MFT_OUTPUT_STREAM_PROVIDES_SAMPLES | MFT_OUTPUT_STREAM_CAN_PROVIDE_SAMPLES))
573 /* The MFT will provide an allocated sample. */
574 return VLC_SUCCESS;
577 DWORD expected_flags = 0;
578 if (p_dec->fmt_in.i_cat == VIDEO_ES)
579 expected_flags |= MFT_OUTPUT_STREAM_WHOLE_SAMPLES
580 | MFT_OUTPUT_STREAM_SINGLE_SAMPLE_PER_BUFFER
581 | MFT_OUTPUT_STREAM_FIXED_SAMPLE_SIZE;
582 if ((output_info.dwFlags & expected_flags) != expected_flags)
583 goto error;
585 hr = mf->fptr_MFCreateSample(&output_sample);
586 if (FAILED(hr))
587 goto error;
589 IMFMediaBuffer *output_media_buffer = NULL;
590 DWORD allocation_size = output_info.cbSize;
591 DWORD alignment = output_info.cbAlignment;
592 if (alignment > 0)
593 hr = mf->fptr_MFCreateAlignedMemoryBuffer(allocation_size, alignment - 1, &output_media_buffer);
594 else
595 hr = mf->fptr_MFCreateMemoryBuffer(allocation_size, &output_media_buffer);
596 if (FAILED(hr))
597 goto error;
599 hr = IMFSample_AddBuffer(output_sample, output_media_buffer);
600 if (FAILED(hr))
601 goto error;
603 *result = output_sample;
605 return VLC_SUCCESS;
607 error:
608 msg_Err(p_dec, "Error in AllocateOutputSample()");
609 if (output_sample)
610 IMFSample_Release(output_sample);
611 return VLC_EGENERIC;
614 static int ProcessInputStream(decoder_t *p_dec, DWORD stream_id, block_t *p_block)
616 decoder_sys_t *p_sys = p_dec->p_sys;
617 HRESULT hr;
618 IMFSample *input_sample = NULL;
620 if (AllocateInputSample(p_dec, stream_id, &input_sample, p_block->i_buffer))
621 goto error;
623 IMFMediaBuffer *input_media_buffer = NULL;
624 hr = IMFSample_GetBufferByIndex(input_sample, 0, &input_media_buffer);
625 if (FAILED(hr))
626 goto error;
628 BYTE *buffer_start;
629 hr = IMFMediaBuffer_Lock(input_media_buffer, &buffer_start, NULL, NULL);
630 if (FAILED(hr))
631 goto error;
633 memcpy(buffer_start, p_block->p_buffer, p_block->i_buffer);
635 if (p_dec->fmt_in.i_codec == VLC_CODEC_H264)
637 /* in-place NAL to annex B conversion. */
638 h264_AVC_to_AnnexB(buffer_start, p_block->i_buffer, p_sys->nal_length_size);
641 hr = IMFMediaBuffer_Unlock(input_media_buffer);
642 if (FAILED(hr))
643 goto error;
645 hr = IMFMediaBuffer_SetCurrentLength(input_media_buffer, p_block->i_buffer);
646 if (FAILED(hr))
647 goto error;
649 vlc_tick_t ts = p_block->i_pts == VLC_TICK_INVALID ? p_block->i_dts : p_block->i_pts;
651 /* Convert from microseconds to 100 nanoseconds unit. */
652 hr = IMFSample_SetSampleTime(input_sample, MSFTIME_FROM_VLC_TICK(ts));
653 if (FAILED(hr))
654 goto error;
656 hr = IMFTransform_ProcessInput(p_sys->mft, stream_id, input_sample, 0);
657 if (FAILED(hr))
658 goto error;
660 IMFMediaBuffer_Release(input_media_buffer);
661 IMFSample_Release(input_sample);
663 return VLC_SUCCESS;
665 error:
666 msg_Err(p_dec, "Error in ProcessInputStream()");
667 if (input_sample)
668 IMFSample_Release(input_sample);
669 return VLC_EGENERIC;
672 /* Copy a packed buffer (no padding) to a picture_t */
673 static void CopyPackedBufferToPicture(picture_t *p_pic, const uint8_t *p_src)
675 for (int i = 0; i < p_pic->i_planes; ++i)
677 uint8_t *p_dst = p_pic->p[i].p_pixels;
679 if (p_pic->p[i].i_visible_pitch == p_pic->p[i].i_pitch)
681 /* Plane is packed, only one memcpy is needed. */
682 uint32_t plane_size = p_pic->p[i].i_pitch * p_pic->p[i].i_visible_lines;
683 memcpy(p_dst, p_src, plane_size);
684 p_src += plane_size;
685 continue;
688 for (int i_line = 0; i_line < p_pic->p[i].i_visible_lines; i_line++)
690 memcpy(p_dst, p_src, p_pic->p[i].i_visible_pitch);
691 p_src += p_pic->p[i].i_visible_pitch;
692 p_dst += p_pic->p[i].i_pitch;
697 static int ProcessOutputStream(decoder_t *p_dec, DWORD stream_id)
699 decoder_sys_t *p_sys = p_dec->p_sys;
700 HRESULT hr;
701 picture_t *picture = NULL;
702 block_t *aout_buffer = NULL;
704 DWORD output_status = 0;
705 MFT_OUTPUT_DATA_BUFFER output_buffer = { stream_id, p_sys->output_sample, 0, NULL };
706 hr = IMFTransform_ProcessOutput(p_sys->mft, 0, 1, &output_buffer, &output_status);
707 if (output_buffer.pEvents)
708 IMFCollection_Release(output_buffer.pEvents);
709 /* Use the returned sample since it can be provided by the MFT. */
710 IMFSample *output_sample = output_buffer.pSample;
712 if (hr == S_OK)
714 if (!output_sample)
715 return VLC_SUCCESS;
717 LONGLONG sample_time;
718 hr = IMFSample_GetSampleTime(output_sample, &sample_time);
719 if (FAILED(hr))
720 goto error;
721 /* Convert from 100 nanoseconds unit to microseconds. */
722 vlc_tick_t samp_time = VLC_TICK_FROM_MSFTIME(sample_time);
724 DWORD total_length = 0;
725 hr = IMFSample_GetTotalLength(output_sample, &total_length);
726 if (FAILED(hr))
727 goto error;
729 if (p_dec->fmt_in.i_cat == VIDEO_ES)
731 if (decoder_UpdateVideoFormat(p_dec))
732 return VLC_SUCCESS;
733 picture = decoder_NewPicture(p_dec);
734 if (!picture)
735 return VLC_SUCCESS;
737 UINT32 interlaced = false;
738 hr = IMFSample_GetUINT32(output_sample, &MFSampleExtension_Interlaced, &interlaced);
739 picture->b_progressive = !interlaced;
741 picture->date = samp_time;
743 else
745 if (decoder_UpdateAudioFormat(p_dec))
746 goto error;
747 if (p_dec->fmt_out.audio.i_bitspersample == 0 || p_dec->fmt_out.audio.i_channels == 0)
748 goto error;
749 int samples = total_length / (p_dec->fmt_out.audio.i_bitspersample * p_dec->fmt_out.audio.i_channels / 8);
750 aout_buffer = decoder_NewAudioBuffer(p_dec, samples);
751 if (!aout_buffer)
752 return VLC_SUCCESS;
753 if (aout_buffer->i_buffer < total_length)
754 goto error;
756 aout_buffer->i_pts = samp_time;
759 IMFMediaBuffer *output_media_buffer = NULL;
760 hr = IMFSample_GetBufferByIndex(output_sample, 0, &output_media_buffer);
762 BYTE *buffer_start;
763 hr = IMFMediaBuffer_Lock(output_media_buffer, &buffer_start, NULL, NULL);
764 if (FAILED(hr))
765 goto error;
767 if (p_dec->fmt_in.i_cat == VIDEO_ES)
768 CopyPackedBufferToPicture(picture, buffer_start);
769 else
770 memcpy(aout_buffer->p_buffer, buffer_start, total_length);
772 hr = IMFMediaBuffer_Unlock(output_media_buffer);
773 IMFSample_Release(output_media_buffer);
774 if (FAILED(hr))
775 goto error;
777 if (p_sys->output_sample)
779 /* Sample is not provided by the MFT: clear its content. */
780 hr = IMFMediaBuffer_SetCurrentLength(output_media_buffer, 0);
781 if (FAILED(hr))
782 goto error;
784 else
786 /* Sample is provided by the MFT: decrease refcount. */
787 IMFSample_Release(output_sample);
790 else if (hr == MF_E_TRANSFORM_STREAM_CHANGE || hr == MF_E_TRANSFORM_TYPE_NOT_SET)
792 if (p_sys->output_type)
793 IMFMediaType_Release(p_sys->output_type);
794 if (SetOutputType(p_dec, p_sys->output_stream_id, &p_sys->output_type))
795 goto error;
797 /* Reallocate output sample. */
798 if (p_sys->output_sample)
799 IMFSample_Release(p_sys->output_sample);
800 p_sys->output_sample = NULL;
801 if (AllocateOutputSample(p_dec, 0, &p_sys->output_sample))
802 goto error;
803 return VLC_SUCCESS;
805 else if (hr == MF_E_TRANSFORM_NEED_MORE_INPUT)
807 return VLC_SUCCESS;
809 else /* An error not listed above occurred */
811 msg_Err(p_dec, "Unexpected error in IMFTransform::ProcessOutput: %#lx",
812 hr);
813 goto error;
816 if (p_dec->fmt_in.i_cat == VIDEO_ES)
817 decoder_QueueVideo(p_dec, picture);
818 else
819 decoder_QueueAudio(p_dec, aout_buffer);
821 return VLC_SUCCESS;
823 error:
824 msg_Err(p_dec, "Error in ProcessOutputStream()");
825 if (picture)
826 picture_Release(picture);
827 if (aout_buffer)
828 block_Release(aout_buffer);
829 return VLC_EGENERIC;
832 static int DecodeSync(decoder_t *p_dec, block_t *p_block)
834 decoder_sys_t *p_sys = p_dec->p_sys;
836 if (!p_block) /* No Drain */
837 return VLCDEC_SUCCESS;
839 if (p_block->i_flags & (BLOCK_FLAG_CORRUPTED))
841 block_Release(p_block);
842 return VLCDEC_SUCCESS;
845 /* Drain the output stream before sending the input packet. */
846 if (ProcessOutputStream(p_dec, p_sys->output_stream_id))
847 goto error;
848 if (ProcessInputStream(p_dec, p_sys->input_stream_id, p_block))
849 goto error;
850 block_Release(p_block);
852 return VLCDEC_SUCCESS;
854 error:
855 msg_Err(p_dec, "Error in DecodeSync()");
856 block_Release(p_block);
857 return VLCDEC_SUCCESS;
860 static HRESULT DequeueMediaEvent(decoder_t *p_dec)
862 decoder_sys_t *p_sys = p_dec->p_sys;
863 HRESULT hr;
865 IMFMediaEvent *event = NULL;
866 hr = IMFMediaEventGenerator_GetEvent(p_sys->event_generator, MF_EVENT_FLAG_NO_WAIT, &event);
867 if (FAILED(hr))
868 return hr;
869 MediaEventType event_type;
870 hr = IMFMediaEvent_GetType(event, &event_type);
871 IMFMediaEvent_Release(event);
872 if (FAILED(hr))
873 return hr;
875 if (event_type == VLC_METransformNeedInput)
876 p_sys->pending_input_events += 1;
877 else if (event_type == VLC_METransformHaveOutput)
878 p_sys->pending_output_events += 1;
879 else
880 msg_Err(p_dec, "Unsupported asynchronous event.");
882 return S_OK;
885 static int DecodeAsync(decoder_t *p_dec, block_t *p_block)
887 decoder_sys_t *p_sys = p_dec->p_sys;
888 HRESULT hr;
890 if (!p_block) /* No Drain */
891 return VLCDEC_SUCCESS;
893 if (p_block->i_flags & (BLOCK_FLAG_CORRUPTED))
895 block_Release(p_block);
896 return VLCDEC_SUCCESS;
899 /* Dequeue all pending media events. */
900 while ((hr = DequeueMediaEvent(p_dec)) == S_OK)
901 continue;
902 if (hr != MF_E_NO_EVENTS_AVAILABLE && FAILED(hr))
903 goto error;
905 /* Drain the output stream of the MFT before sending the input packet. */
906 if (p_sys->pending_output_events > 0)
908 p_sys->pending_output_events -= 1;
909 if (ProcessOutputStream(p_dec, p_sys->output_stream_id))
910 goto error;
913 /* Poll the MFT and return decoded frames until the input stream is ready. */
914 while (p_sys->pending_input_events == 0)
916 hr = DequeueMediaEvent(p_dec);
917 if (hr == MF_E_NO_EVENTS_AVAILABLE)
919 /* Sleep for 1 ms to avoid excessive polling. */
920 Sleep(1);
921 continue;
923 if (FAILED(hr))
924 goto error;
926 if (p_sys->pending_output_events > 0)
928 p_sys->pending_output_events -= 1;
929 if (ProcessOutputStream(p_dec, p_sys->output_stream_id))
930 goto error;
931 break;
935 p_sys->pending_input_events -= 1;
936 if (ProcessInputStream(p_dec, p_sys->input_stream_id, p_block))
937 goto error;
939 block_Release(p_block);
941 return VLCDEC_SUCCESS;
943 error:
944 msg_Err(p_dec, "Error in DecodeAsync()");
945 block_Release(p_block);
946 return VLCDEC_SUCCESS;
949 static void DestroyMFT(decoder_t *p_dec);
951 static int InitializeMFT(decoder_t *p_dec)
953 decoder_sys_t *p_sys = p_dec->p_sys;
954 HRESULT hr;
956 IMFAttributes *attributes = NULL;
957 hr = IMFTransform_GetAttributes(p_sys->mft, &attributes);
958 if (hr != E_NOTIMPL && FAILED(hr))
959 goto error;
960 if (SUCCEEDED(hr))
962 UINT32 is_async = false;
963 hr = IMFAttributes_GetUINT32(attributes, &MF_TRANSFORM_ASYNC, &is_async);
964 if (hr != MF_E_ATTRIBUTENOTFOUND && FAILED(hr))
965 goto error;
966 p_sys->is_async = is_async;
967 if (p_sys->is_async)
969 hr = IMFAttributes_SetUINT32(attributes, &MF_TRANSFORM_ASYNC_UNLOCK, true);
970 if (FAILED(hr))
971 goto error;
972 hr = IMFTransform_QueryInterface(p_sys->mft, &IID_IMFMediaEventGenerator, (void**)&p_sys->event_generator);
973 if (FAILED(hr))
974 goto error;
978 DWORD input_streams_count;
979 DWORD output_streams_count;
980 hr = IMFTransform_GetStreamCount(p_sys->mft, &input_streams_count, &output_streams_count);
981 if (FAILED(hr))
982 goto error;
983 if (input_streams_count != 1 || output_streams_count != 1)
985 msg_Err(p_dec, "MFT decoder should have 1 input stream and 1 output stream.");
986 goto error;
989 hr = IMFTransform_GetStreamIDs(p_sys->mft, 1, &p_sys->input_stream_id, 1, &p_sys->output_stream_id);
990 if (hr == E_NOTIMPL)
993 * This is not an error, it happens if:
994 * - there is a fixed number of streams.
995 * AND
996 * - streams are numbered consecutively from 0 to N-1.
998 p_sys->input_stream_id = 0;
999 p_sys->output_stream_id = 0;
1001 else if (FAILED(hr))
1002 goto error;
1004 if (SetInputType(p_dec, p_sys->input_stream_id, &p_sys->input_type))
1005 goto error;
1007 if (SetOutputType(p_dec, p_sys->output_stream_id, &p_sys->output_type))
1008 goto error;
1011 * The input type was not set by the previous call to
1012 * SetInputType, try again after setting the output type.
1014 if (!p_sys->input_type)
1015 if (SetInputType(p_dec, p_sys->input_stream_id, &p_sys->input_type) || !p_sys->input_type)
1016 goto error;
1018 /* This call can be a no-op for some MFT decoders, but it can potentially reduce starting time. */
1019 hr = IMFTransform_ProcessMessage(p_sys->mft, MFT_MESSAGE_NOTIFY_BEGIN_STREAMING, (ULONG_PTR)0);
1020 if (FAILED(hr))
1021 goto error;
1023 /* This event is required for asynchronous MFTs, optional otherwise. */
1024 hr = IMFTransform_ProcessMessage(p_sys->mft, MFT_MESSAGE_NOTIFY_START_OF_STREAM, (ULONG_PTR)0);
1025 if (FAILED(hr))
1026 goto error;
1028 if (p_dec->fmt_in.i_codec == VLC_CODEC_H264)
1030 /* It's not an error if the following call fails. */
1031 IMFAttributes_SetUINT32(attributes, &CODECAPI_AVLowLatencyMode, true);
1033 if (p_dec->fmt_in.i_extra)
1035 if (h264_isavcC((uint8_t*)p_dec->fmt_in.p_extra, p_dec->fmt_in.i_extra))
1037 size_t i_buf;
1038 uint8_t *buf = h264_avcC_to_AnnexB_NAL(p_dec->fmt_in.p_extra,
1039 p_dec->fmt_in.i_extra,
1040 &i_buf, &p_sys->nal_length_size);
1041 if(buf)
1043 free(p_dec->fmt_in.p_extra);
1044 p_dec->fmt_in.p_extra = buf;
1045 p_dec->fmt_in.i_extra = i_buf;
1050 return VLC_SUCCESS;
1052 error:
1053 msg_Err(p_dec, "Error in InitializeMFT()");
1054 DestroyMFT(p_dec);
1055 return VLC_EGENERIC;
1058 static void DestroyMFT(decoder_t *p_dec)
1060 decoder_sys_t *p_sys = p_dec->p_sys;
1062 if (p_sys->event_generator)
1063 IMFMediaEventGenerator_Release(p_sys->event_generator);
1064 if (p_sys->input_type)
1065 IMFMediaType_Release(p_sys->input_type);
1066 if (p_sys->output_sample)
1068 IMFMediaBuffer *output_media_buffer = NULL;
1069 HRESULT hr = IMFSample_GetBufferByIndex(p_sys->output_sample, 0, &output_media_buffer);
1070 if (SUCCEEDED(hr))
1071 IMFSample_Release(output_media_buffer);
1072 IMFSample_Release(p_sys->output_sample);
1074 if (p_sys->output_type)
1075 IMFMediaType_Release(p_sys->output_type);
1076 if (p_sys->mft)
1077 IMFTransform_Release(p_sys->mft);
1079 p_sys->event_generator = NULL;
1080 p_sys->input_type = NULL;
1081 p_sys->output_sample = NULL;
1082 p_sys->output_type = NULL;
1083 p_sys->mft = NULL;
1086 static int FindMFT(decoder_t *p_dec)
1088 decoder_sys_t *p_sys = p_dec->p_sys;
1089 MFHandle *mf = &p_sys->mf_handle;
1090 HRESULT hr;
1092 /* Try to create a MFT using MFTEnumEx. */
1093 GUID category;
1094 if (p_dec->fmt_in.i_cat == VIDEO_ES)
1096 category = MFT_CATEGORY_VIDEO_DECODER;
1097 p_sys->major_type = &MFMediaType_Video;
1098 p_sys->subtype = FormatToGUID(video_format_table, p_dec->fmt_in.i_codec);
1099 if(!p_sys->subtype) {
1100 /* Codec is not well known. Construct a MF transform subtype from the fourcc */
1101 p_sys->custom_subtype = MFVideoFormat_Base;
1102 p_sys->custom_subtype.Data1 = p_dec->fmt_in.i_codec;
1103 p_sys->subtype = &p_sys->custom_subtype;
1106 else
1108 category = MFT_CATEGORY_AUDIO_DECODER;
1109 p_sys->major_type = &MFMediaType_Audio;
1110 p_sys->subtype = FormatToGUID(audio_format_table, p_dec->fmt_in.i_codec);
1112 if (!p_sys->subtype)
1113 return VLC_EGENERIC;
1115 UINT32 flags = MFT_ENUM_FLAG_SORTANDFILTER | MFT_ENUM_FLAG_LOCALMFT
1116 | MFT_ENUM_FLAG_SYNCMFT | MFT_ENUM_FLAG_ASYNCMFT
1117 | MFT_ENUM_FLAG_HARDWARE | MFT_ENUM_FLAG_TRANSCODE_ONLY;
1118 MFT_REGISTER_TYPE_INFO input_type = { *p_sys->major_type, *p_sys->subtype };
1119 IMFActivate **activate_objects = NULL;
1120 UINT32 activate_objects_count = 0;
1121 hr = mf->fptr_MFTEnumEx(category, flags, &input_type, NULL, &activate_objects, &activate_objects_count);
1122 if (FAILED(hr))
1123 return VLC_EGENERIC;
1125 msg_Dbg(p_dec, "Found %d available MFT module(s)", activate_objects_count);
1126 if (activate_objects_count == 0)
1127 return VLC_EGENERIC;
1129 for (UINT32 i = 0; i < activate_objects_count; ++i)
1131 hr = IMFActivate_ActivateObject(activate_objects[i], &IID_IMFTransform, (void**)&p_sys->mft);
1132 IMFActivate_Release(activate_objects[i]);
1133 if (FAILED(hr))
1134 continue;
1136 if (InitializeMFT(p_dec) == VLC_SUCCESS)
1138 CoTaskMemFree(activate_objects);
1139 return VLC_SUCCESS;
1142 CoTaskMemFree(activate_objects);
1144 return VLC_EGENERIC;
1147 static int LoadMFTLibrary(MFHandle *mf)
1149 #if _WIN32_WINNT < _WIN32_WINNT_WIN7 || VLC_WINSTORE_APP || __MINGW64_VERSION_MAJOR < 6
1150 mf->mfplat_dll = LoadLibrary(TEXT("mfplat.dll"));
1151 if (!mf->mfplat_dll)
1152 return VLC_EGENERIC;
1154 mf->fptr_MFTEnumEx = (void*)GetProcAddress(mf->mfplat_dll, "MFTEnumEx");
1155 mf->fptr_MFCreateSample = (void*)GetProcAddress(mf->mfplat_dll, "MFCreateSample");
1156 mf->fptr_MFCreateMemoryBuffer = (void*)GetProcAddress(mf->mfplat_dll, "MFCreateMemoryBuffer");
1157 mf->fptr_MFCreateAlignedMemoryBuffer = (void*)GetProcAddress(mf->mfplat_dll, "MFCreateAlignedMemoryBuffer");
1158 if (!mf->fptr_MFTEnumEx || !mf->fptr_MFCreateSample || !mf->fptr_MFCreateMemoryBuffer || !mf->fptr_MFCreateAlignedMemoryBuffer)
1159 return VLC_EGENERIC;
1160 #else
1161 mf->fptr_MFTEnumEx = &MFTEnumEx;
1162 mf->fptr_MFCreateSample = &MFCreateSample;
1163 mf->fptr_MFCreateMemoryBuffer = &MFCreateMemoryBuffer;
1164 mf->fptr_MFCreateAlignedMemoryBuffer = &MFCreateAlignedMemoryBuffer;
1165 #endif
1167 return VLC_SUCCESS;
1170 static int Open(vlc_object_t *p_this)
1172 decoder_t *p_dec = (decoder_t *)p_this;
1173 decoder_sys_t *p_sys;
1175 p_sys = p_dec->p_sys = calloc(1, sizeof(*p_sys));
1176 if (!p_sys)
1177 return VLC_ENOMEM;
1179 if( FAILED(CoInitializeEx(NULL, COINIT_MULTITHREADED)) )
1181 free(p_sys);
1182 return VLC_EGENERIC;
1185 if (LoadMFTLibrary(&p_sys->mf_handle))
1187 msg_Err(p_dec, "Failed to load MFT library.");
1188 goto error;
1191 if (FindMFT(p_dec))
1193 msg_Err(p_dec, "Could not find suitable MFT decoder");
1194 goto error;
1197 /* Only one output sample is needed, we can allocate one and reuse it. */
1198 if (AllocateOutputSample(p_dec, 0, &p_sys->output_sample))
1199 goto error;
1201 p_dec->pf_decode = p_sys->is_async ? DecodeAsync : DecodeSync;
1203 return VLC_SUCCESS;
1205 error:
1206 Close(p_this);
1207 return VLC_EGENERIC;
1210 static void Close(vlc_object_t *p_this)
1212 decoder_t *p_dec = (decoder_t *)p_this;
1213 decoder_sys_t *p_sys = p_dec->p_sys;
1214 MFHandle *mf = &p_sys->mf_handle;
1216 DestroyMFT(p_dec);
1218 if (mf->mfplat_dll)
1219 FreeLibrary(mf->mfplat_dll);
1221 free(p_sys);
1223 CoUninitialize();