qt: playlist: use item title if available
[vlc.git] / modules / codec / mft.c
blob46e03bdcab0b4d2fbcc53275e17dc41c513fac6a
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 }
203 * We cannot use the FOURCC code for audio either since the
204 * WAVE_FORMAT value is used to create the GUID.
206 static const pair_format_guid audio_format_table[] =
208 { VLC_CODEC_MPGA, &MFAudioFormat_MPEG },
209 { VLC_CODEC_MP3, &MFAudioFormat_MP3 },
210 { VLC_CODEC_DTS, &MFAudioFormat_DTS },
211 { VLC_CODEC_MP4A, &MFAudioFormat_AAC },
212 { VLC_CODEC_WMA2, &MFAudioFormat_WMAudioV8 },
213 { VLC_CODEC_A52, &MFAudioFormat_Dolby_AC3 },
214 { 0, NULL }
217 static const GUID *FormatToGUID(const pair_format_guid table[], vlc_fourcc_t fourcc)
219 for (int i = 0; table[i].fourcc; ++i)
220 if (table[i].fourcc == fourcc)
221 return table[i].guid;
223 return NULL;
226 static vlc_fourcc_t GUIDToFormat(const pair_format_guid table[], const GUID* guid)
228 for (int i = 0; table[i].fourcc; ++i)
229 if (IsEqualGUID(table[i].guid, guid))
230 return table[i].fourcc;
232 return 0;
236 * Low latency mode for Windows 8. Without this option, the H264
237 * decoder will fill *all* its internal buffers before returning a
238 * frame. Because of this behavior, the decoder might return no frame
239 * for more than 500 ms, making it unusable for playback.
241 DEFINE_GUID(CODECAPI_AVLowLatencyMode, 0x9c27891a, 0xed7a, 0x40e1, 0x88, 0xe8, 0xb2, 0x27, 0x27, 0xa0, 0x24, 0xee);
243 static int SetInputType(decoder_t *p_dec, DWORD stream_id, IMFMediaType **result)
245 decoder_sys_t *p_sys = p_dec->p_sys;
246 HRESULT hr;
248 *result = NULL;
250 IMFMediaType *input_media_type = NULL;
252 /* Search a suitable input type for the MFT. */
253 int input_type_index = 0;
254 bool found = false;
255 for (int i = 0; !found; ++i)
257 hr = IMFTransform_GetInputAvailableType(p_sys->mft, stream_id, i, &input_media_type);
258 if (hr == MF_E_NO_MORE_TYPES)
259 break;
260 else if (hr == MF_E_TRANSFORM_TYPE_NOT_SET)
262 /* The output type must be set before setting the input type for this MFT. */
263 return VLC_SUCCESS;
265 else if (FAILED(hr))
266 goto error;
268 GUID subtype;
269 hr = IMFMediaType_GetGUID(input_media_type, &MF_MT_SUBTYPE, &subtype);
270 if (FAILED(hr))
271 goto error;
273 if (IsEqualGUID(&subtype, p_sys->subtype))
274 found = true;
276 if (found)
277 input_type_index = i;
279 IMFMediaType_Release(input_media_type);
280 input_media_type = NULL;
282 if (!found)
283 goto error;
285 hr = IMFTransform_GetInputAvailableType(p_sys->mft, stream_id, input_type_index, &input_media_type);
286 if (FAILED(hr))
287 goto error;
289 if (p_dec->fmt_in.i_cat == VIDEO_ES)
291 UINT64 width = p_dec->fmt_in.video.i_width;
292 UINT64 height = p_dec->fmt_in.video.i_height;
293 UINT64 frame_size = (width << 32) | height;
294 hr = IMFMediaType_SetUINT64(input_media_type, &MF_MT_FRAME_SIZE, frame_size);
295 if (FAILED(hr))
296 goto error;
298 /* Some transforms like to know the frame rate and may reject the input type otherwise. */
299 UINT64 frame_ratio_num = p_dec->fmt_in.video.i_frame_rate;
300 UINT64 frame_ratio_dem = p_dec->fmt_in.video.i_frame_rate_base;
301 if(frame_ratio_num && frame_ratio_dem) {
302 UINT64 frame_rate = (frame_ratio_num << 32) | frame_ratio_dem;
303 hr = IMFMediaType_SetUINT64(input_media_type, &MF_MT_FRAME_RATE, frame_rate);
304 if(FAILED(hr))
305 goto error;
308 else
310 hr = IMFMediaType_SetUINT32(input_media_type, &MF_MT_ORIGINAL_WAVE_FORMAT_TAG, p_sys->subtype->Data1);
311 if (FAILED(hr))
312 goto error;
313 if (p_dec->fmt_in.audio.i_rate)
315 hr = IMFMediaType_SetUINT32(input_media_type, &MF_MT_AUDIO_SAMPLES_PER_SECOND, p_dec->fmt_in.audio.i_rate);
316 if (FAILED(hr))
317 goto error;
319 if (p_dec->fmt_in.audio.i_channels)
321 hr = IMFMediaType_SetUINT32(input_media_type, &MF_MT_AUDIO_NUM_CHANNELS, p_dec->fmt_in.audio.i_channels);
322 if (FAILED(hr))
323 goto error;
325 if (p_dec->fmt_in.audio.i_bitspersample)
327 hr = IMFMediaType_SetUINT32(input_media_type, &MF_MT_AUDIO_BITS_PER_SAMPLE, p_dec->fmt_in.audio.i_bitspersample);
328 if (FAILED(hr))
329 goto error;
331 if (p_dec->fmt_in.audio.i_blockalign)
333 hr = IMFMediaType_SetUINT32(input_media_type, &MF_MT_AUDIO_BLOCK_ALIGNMENT, p_dec->fmt_in.audio.i_blockalign);
334 if (FAILED(hr))
335 goto error;
337 if (p_dec->fmt_in.i_bitrate)
339 hr = IMFMediaType_SetUINT32(input_media_type, &MF_MT_AUDIO_AVG_BYTES_PER_SECOND, p_dec->fmt_in.i_bitrate / 8);
340 if (FAILED(hr))
341 goto error;
345 if (p_dec->fmt_in.i_extra > 0)
347 UINT32 blob_size = 0;
348 hr = IMFMediaType_GetBlobSize(input_media_type, &MF_MT_USER_DATA, &blob_size);
350 * Do not overwrite existing user data in the input type, this
351 * can cause the MFT to reject the type.
353 if (hr == MF_E_ATTRIBUTENOTFOUND)
355 hr = IMFMediaType_SetBlob(input_media_type, &MF_MT_USER_DATA,
356 (const UINT8*)p_dec->fmt_in.p_extra, p_dec->fmt_in.i_extra);
357 if (FAILED(hr))
358 goto error;
362 hr = IMFTransform_SetInputType(p_sys->mft, stream_id, input_media_type, 0);
363 if (FAILED(hr))
364 goto error;
366 *result = input_media_type;
368 return VLC_SUCCESS;
370 error:
371 msg_Err(p_dec, "Error in SetInputType()");
372 if (input_media_type)
373 IMFMediaType_Release(input_media_type);
374 return VLC_EGENERIC;
377 static int SetOutputType(decoder_t *p_dec, DWORD stream_id, IMFMediaType **result)
379 decoder_sys_t *p_sys = p_dec->p_sys;
380 HRESULT hr;
382 *result = NULL;
384 IMFMediaType *output_media_type = NULL;
387 * Enumerate available output types. The list is ordered by
388 * preference thus we will use the first one unless YV12/I420 is
389 * available for video or float32 for audio.
391 int output_type_index = -1;
392 bool found = false;
393 for (int i = 0; !found; ++i)
395 hr = IMFTransform_GetOutputAvailableType(p_sys->mft, stream_id, i, &output_media_type);
396 if (hr == MF_E_NO_MORE_TYPES)
397 break;
398 else if (hr == MF_E_TRANSFORM_TYPE_NOT_SET)
400 /* The input type must be set before setting the output type for this MFT. */
401 return VLC_SUCCESS;
403 else if (FAILED(hr))
404 goto error;
406 GUID subtype;
407 hr = IMFMediaType_GetGUID(output_media_type, &MF_MT_SUBTYPE, &subtype);
408 if (FAILED(hr))
409 goto error;
411 if (p_dec->fmt_in.i_cat == VIDEO_ES)
413 if (IsEqualGUID(&subtype, &MFVideoFormat_YV12) || IsEqualGUID(&subtype, &MFVideoFormat_I420))
414 found = true;
415 /* Transform might offer output in a D3DFMT propietary FCC. If we can
416 * use it, fall back to it in case we do not find YV12 or I420 */
417 else if(output_type_index < 0 && GUIDToFormat(d3d_format_table, &subtype) > 0)
418 output_type_index = i;
420 else
422 UINT32 bits_per_sample;
423 hr = IMFMediaType_GetUINT32(output_media_type, &MF_MT_AUDIO_BITS_PER_SAMPLE, &bits_per_sample);
424 if (FAILED(hr))
425 continue;
426 if (bits_per_sample == 32 && IsEqualGUID(&subtype, &MFAudioFormat_Float))
427 found = true;
430 if (found)
431 output_type_index = i;
433 IMFMediaType_Release(output_media_type);
434 output_media_type = NULL;
437 * It's not an error if we don't find the output type we were
438 * looking for, in this case we use the first available type.
440 if(output_type_index < 0)
441 /* No output format found we prefer, just pick the first one preferred
442 * by the MFT */
443 output_type_index = 0;
445 hr = IMFTransform_GetOutputAvailableType(p_sys->mft, stream_id, output_type_index, &output_media_type);
446 if (FAILED(hr))
447 goto error;
449 hr = IMFTransform_SetOutputType(p_sys->mft, stream_id, output_media_type, 0);
450 if (FAILED(hr))
451 goto error;
453 GUID subtype;
454 hr = IMFMediaType_GetGUID(output_media_type, &MF_MT_SUBTYPE, &subtype);
455 if (FAILED(hr))
456 goto error;
458 if (p_dec->fmt_in.i_cat == VIDEO_ES)
460 video_format_Copy( &p_dec->fmt_out.video, &p_dec->fmt_in.video );
462 /* Transform might offer output in a D3DFMT propietary FCC */
463 vlc_fourcc_t fcc = GUIDToFormat(d3d_format_table, &subtype);
464 if(fcc) {
465 /* D3D formats are upside down */
466 p_dec->fmt_out.video.orientation = ORIENT_BOTTOM_LEFT;
467 } else {
468 fcc = vlc_fourcc_GetCodec(p_dec->fmt_in.i_cat, subtype.Data1);
471 p_dec->fmt_out.i_codec = fcc;
473 else
475 p_dec->fmt_out.audio = p_dec->fmt_in.audio;
477 UINT32 bitspersample = 0;
478 hr = IMFMediaType_GetUINT32(output_media_type, &MF_MT_AUDIO_BITS_PER_SAMPLE, &bitspersample);
479 if (SUCCEEDED(hr) && bitspersample)
480 p_dec->fmt_out.audio.i_bitspersample = bitspersample;
482 UINT32 channels = 0;
483 hr = IMFMediaType_GetUINT32(output_media_type, &MF_MT_AUDIO_NUM_CHANNELS, &channels);
484 if (SUCCEEDED(hr) && channels)
485 p_dec->fmt_out.audio.i_channels = channels;
487 UINT32 rate = 0;
488 hr = IMFMediaType_GetUINT32(output_media_type, &MF_MT_AUDIO_SAMPLES_PER_SECOND, &rate);
489 if (SUCCEEDED(hr) && rate)
490 p_dec->fmt_out.audio.i_rate = rate;
492 vlc_fourcc_t fourcc;
493 wf_tag_to_fourcc(subtype.Data1, &fourcc, NULL);
494 p_dec->fmt_out.i_codec = vlc_fourcc_GetCodecAudio(fourcc, p_dec->fmt_out.audio.i_bitspersample);
496 p_dec->fmt_out.audio.i_physical_channels = pi_channels_maps[p_dec->fmt_out.audio.i_channels];
499 *result = output_media_type;
501 return VLC_SUCCESS;
503 error:
504 msg_Err(p_dec, "Error in SetOutputType()");
505 if (output_media_type)
506 IMFMediaType_Release(output_media_type);
507 return VLC_EGENERIC;
510 static int AllocateInputSample(decoder_t *p_dec, DWORD stream_id, IMFSample** result, DWORD size)
512 decoder_sys_t *p_sys = p_dec->p_sys;
513 MFHandle *mf = &p_sys->mf_handle;
514 HRESULT hr;
516 *result = NULL;
518 IMFSample *input_sample = NULL;
520 MFT_INPUT_STREAM_INFO input_info;
521 hr = IMFTransform_GetInputStreamInfo(p_sys->mft, stream_id, &input_info);
522 if (FAILED(hr))
523 goto error;
525 hr = mf->fptr_MFCreateSample(&input_sample);
526 if (FAILED(hr))
527 goto error;
529 IMFMediaBuffer *input_media_buffer = NULL;
530 DWORD allocation_size = __MAX(input_info.cbSize, size);
531 hr = mf->fptr_MFCreateMemoryBuffer(allocation_size, &input_media_buffer);
532 if (FAILED(hr))
533 goto error;
535 hr = IMFSample_AddBuffer(input_sample, input_media_buffer);
536 IMFMediaBuffer_Release(input_media_buffer);
537 if (FAILED(hr))
538 goto error;
540 *result = input_sample;
542 return VLC_SUCCESS;
544 error:
545 msg_Err(p_dec, "Error in AllocateInputSample()");
546 if (input_sample)
547 IMFSample_Release(input_sample);
548 if (input_media_buffer)
549 IMFMediaBuffer_Release(input_media_buffer);
550 return VLC_EGENERIC;
553 static int AllocateOutputSample(decoder_t *p_dec, DWORD stream_id, IMFSample **result)
555 decoder_sys_t *p_sys = p_dec->p_sys;
556 MFHandle *mf = &p_sys->mf_handle;
557 HRESULT hr;
559 *result = NULL;
561 IMFSample *output_sample = NULL;
563 MFT_OUTPUT_STREAM_INFO output_info;
564 hr = IMFTransform_GetOutputStreamInfo(p_sys->mft, stream_id, &output_info);
565 if (FAILED(hr))
566 goto error;
568 if (output_info.dwFlags & (MFT_OUTPUT_STREAM_PROVIDES_SAMPLES | MFT_OUTPUT_STREAM_CAN_PROVIDE_SAMPLES))
570 /* The MFT will provide an allocated sample. */
571 return VLC_SUCCESS;
574 DWORD expected_flags = 0;
575 if (p_dec->fmt_in.i_cat == VIDEO_ES)
576 expected_flags |= MFT_OUTPUT_STREAM_WHOLE_SAMPLES
577 | MFT_OUTPUT_STREAM_SINGLE_SAMPLE_PER_BUFFER
578 | MFT_OUTPUT_STREAM_FIXED_SAMPLE_SIZE;
579 if ((output_info.dwFlags & expected_flags) != expected_flags)
580 goto error;
582 hr = mf->fptr_MFCreateSample(&output_sample);
583 if (FAILED(hr))
584 goto error;
586 IMFMediaBuffer *output_media_buffer = NULL;
587 DWORD allocation_size = output_info.cbSize;
588 DWORD alignment = output_info.cbAlignment;
589 if (alignment > 0)
590 hr = mf->fptr_MFCreateAlignedMemoryBuffer(allocation_size, alignment - 1, &output_media_buffer);
591 else
592 hr = mf->fptr_MFCreateMemoryBuffer(allocation_size, &output_media_buffer);
593 if (FAILED(hr))
594 goto error;
596 hr = IMFSample_AddBuffer(output_sample, output_media_buffer);
597 if (FAILED(hr))
598 goto error;
600 *result = output_sample;
602 return VLC_SUCCESS;
604 error:
605 msg_Err(p_dec, "Error in AllocateOutputSample()");
606 if (output_sample)
607 IMFSample_Release(output_sample);
608 return VLC_EGENERIC;
611 static int ProcessInputStream(decoder_t *p_dec, DWORD stream_id, block_t *p_block)
613 decoder_sys_t *p_sys = p_dec->p_sys;
614 HRESULT hr;
615 IMFSample *input_sample = NULL;
617 if (AllocateInputSample(p_dec, stream_id, &input_sample, p_block->i_buffer))
618 goto error;
620 IMFMediaBuffer *input_media_buffer = NULL;
621 hr = IMFSample_GetBufferByIndex(input_sample, 0, &input_media_buffer);
622 if (FAILED(hr))
623 goto error;
625 BYTE *buffer_start;
626 hr = IMFMediaBuffer_Lock(input_media_buffer, &buffer_start, NULL, NULL);
627 if (FAILED(hr))
628 goto error;
630 memcpy(buffer_start, p_block->p_buffer, p_block->i_buffer);
632 if (p_dec->fmt_in.i_codec == VLC_CODEC_H264)
634 /* in-place NAL to annex B conversion. */
635 h264_AVC_to_AnnexB(buffer_start, p_block->i_buffer, p_sys->nal_length_size);
638 hr = IMFMediaBuffer_Unlock(input_media_buffer);
639 if (FAILED(hr))
640 goto error;
642 hr = IMFMediaBuffer_SetCurrentLength(input_media_buffer, p_block->i_buffer);
643 if (FAILED(hr))
644 goto error;
646 vlc_tick_t ts = p_block->i_pts == VLC_TICK_INVALID ? p_block->i_dts : p_block->i_pts;
648 /* Convert from microseconds to 100 nanoseconds unit. */
649 hr = IMFSample_SetSampleTime(input_sample, MSFTIME_FROM_VLC_TICK(ts));
650 if (FAILED(hr))
651 goto error;
653 hr = IMFTransform_ProcessInput(p_sys->mft, stream_id, input_sample, 0);
654 if (FAILED(hr))
655 goto error;
657 IMFMediaBuffer_Release(input_media_buffer);
658 IMFSample_Release(input_sample);
660 return VLC_SUCCESS;
662 error:
663 msg_Err(p_dec, "Error in ProcessInputStream()");
664 if (input_sample)
665 IMFSample_Release(input_sample);
666 return VLC_EGENERIC;
669 /* Copy a packed buffer (no padding) to a picture_t */
670 static void CopyPackedBufferToPicture(picture_t *p_pic, const uint8_t *p_src)
672 for (int i = 0; i < p_pic->i_planes; ++i)
674 uint8_t *p_dst = p_pic->p[i].p_pixels;
676 if (p_pic->p[i].i_visible_pitch == p_pic->p[i].i_pitch)
678 /* Plane is packed, only one memcpy is needed. */
679 uint32_t plane_size = p_pic->p[i].i_pitch * p_pic->p[i].i_visible_lines;
680 memcpy(p_dst, p_src, plane_size);
681 p_src += plane_size;
682 continue;
685 for (int i_line = 0; i_line < p_pic->p[i].i_visible_lines; i_line++)
687 memcpy(p_dst, p_src, p_pic->p[i].i_visible_pitch);
688 p_src += p_pic->p[i].i_visible_pitch;
689 p_dst += p_pic->p[i].i_pitch;
694 static int ProcessOutputStream(decoder_t *p_dec, DWORD stream_id)
696 decoder_sys_t *p_sys = p_dec->p_sys;
697 HRESULT hr;
698 picture_t *picture = NULL;
699 block_t *aout_buffer = NULL;
701 DWORD output_status = 0;
702 MFT_OUTPUT_DATA_BUFFER output_buffer = { stream_id, p_sys->output_sample, 0, NULL };
703 hr = IMFTransform_ProcessOutput(p_sys->mft, 0, 1, &output_buffer, &output_status);
704 if (output_buffer.pEvents)
705 IMFCollection_Release(output_buffer.pEvents);
706 /* Use the returned sample since it can be provided by the MFT. */
707 IMFSample *output_sample = output_buffer.pSample;
709 if (hr == S_OK)
711 if (!output_sample)
712 return VLC_SUCCESS;
714 LONGLONG sample_time;
715 hr = IMFSample_GetSampleTime(output_sample, &sample_time);
716 if (FAILED(hr))
717 goto error;
718 /* Convert from 100 nanoseconds unit to microseconds. */
719 vlc_tick_t samp_time = VLC_TICK_FROM_MSFTIME(sample_time);
721 DWORD total_length = 0;
722 hr = IMFSample_GetTotalLength(output_sample, &total_length);
723 if (FAILED(hr))
724 goto error;
726 if (p_dec->fmt_in.i_cat == VIDEO_ES)
728 if (decoder_UpdateVideoFormat(p_dec))
729 return VLC_SUCCESS;
730 picture = decoder_NewPicture(p_dec);
731 if (!picture)
732 return VLC_SUCCESS;
734 UINT32 interlaced = false;
735 hr = IMFSample_GetUINT32(output_sample, &MFSampleExtension_Interlaced, &interlaced);
736 picture->b_progressive = !interlaced;
738 picture->date = samp_time;
740 else
742 if (decoder_UpdateAudioFormat(p_dec))
743 goto error;
744 if (p_dec->fmt_out.audio.i_bitspersample == 0 || p_dec->fmt_out.audio.i_channels == 0)
745 goto error;
746 int samples = total_length / (p_dec->fmt_out.audio.i_bitspersample * p_dec->fmt_out.audio.i_channels / 8);
747 aout_buffer = decoder_NewAudioBuffer(p_dec, samples);
748 if (!aout_buffer)
749 return VLC_SUCCESS;
750 if (aout_buffer->i_buffer < total_length)
751 goto error;
753 aout_buffer->i_pts = samp_time;
756 IMFMediaBuffer *output_media_buffer = NULL;
757 hr = IMFSample_GetBufferByIndex(output_sample, 0, &output_media_buffer);
759 BYTE *buffer_start;
760 hr = IMFMediaBuffer_Lock(output_media_buffer, &buffer_start, NULL, NULL);
761 if (FAILED(hr))
762 goto error;
764 if (p_dec->fmt_in.i_cat == VIDEO_ES)
765 CopyPackedBufferToPicture(picture, buffer_start);
766 else
767 memcpy(aout_buffer->p_buffer, buffer_start, total_length);
769 hr = IMFMediaBuffer_Unlock(output_media_buffer);
770 IMFSample_Release(output_media_buffer);
771 if (FAILED(hr))
772 goto error;
774 if (p_sys->output_sample)
776 /* Sample is not provided by the MFT: clear its content. */
777 hr = IMFMediaBuffer_SetCurrentLength(output_media_buffer, 0);
778 if (FAILED(hr))
779 goto error;
781 else
783 /* Sample is provided by the MFT: decrease refcount. */
784 IMFSample_Release(output_sample);
787 else if (hr == MF_E_TRANSFORM_STREAM_CHANGE || hr == MF_E_TRANSFORM_TYPE_NOT_SET)
789 if (p_sys->output_type)
790 IMFMediaType_Release(p_sys->output_type);
791 if (SetOutputType(p_dec, p_sys->output_stream_id, &p_sys->output_type))
792 goto error;
794 /* Reallocate output sample. */
795 if (p_sys->output_sample)
796 IMFSample_Release(p_sys->output_sample);
797 p_sys->output_sample = NULL;
798 if (AllocateOutputSample(p_dec, 0, &p_sys->output_sample))
799 goto error;
800 return VLC_SUCCESS;
802 else if (hr == MF_E_TRANSFORM_NEED_MORE_INPUT)
804 return VLC_SUCCESS;
806 else /* An error not listed above occurred */
808 msg_Err(p_dec, "Unexpected error in IMFTransform::ProcessOutput: %#lx",
809 hr);
810 goto error;
813 if (p_dec->fmt_in.i_cat == VIDEO_ES)
814 decoder_QueueVideo(p_dec, picture);
815 else
816 decoder_QueueAudio(p_dec, aout_buffer);
818 return VLC_SUCCESS;
820 error:
821 msg_Err(p_dec, "Error in ProcessOutputStream()");
822 if (picture)
823 picture_Release(picture);
824 if (aout_buffer)
825 block_Release(aout_buffer);
826 return VLC_EGENERIC;
829 static int DecodeSync(decoder_t *p_dec, block_t *p_block)
831 decoder_sys_t *p_sys = p_dec->p_sys;
833 if (!p_block) /* No Drain */
834 return VLCDEC_SUCCESS;
836 if (p_block->i_flags & (BLOCK_FLAG_CORRUPTED))
838 block_Release(p_block);
839 return VLCDEC_SUCCESS;
842 /* Drain the output stream before sending the input packet. */
843 if (ProcessOutputStream(p_dec, p_sys->output_stream_id))
844 goto error;
845 if (ProcessInputStream(p_dec, p_sys->input_stream_id, p_block))
846 goto error;
847 block_Release(p_block);
849 return VLCDEC_SUCCESS;
851 error:
852 msg_Err(p_dec, "Error in DecodeSync()");
853 block_Release(p_block);
854 return VLCDEC_SUCCESS;
857 static HRESULT DequeueMediaEvent(decoder_t *p_dec)
859 decoder_sys_t *p_sys = p_dec->p_sys;
860 HRESULT hr;
862 IMFMediaEvent *event = NULL;
863 hr = IMFMediaEventGenerator_GetEvent(p_sys->event_generator, MF_EVENT_FLAG_NO_WAIT, &event);
864 if (FAILED(hr))
865 return hr;
866 MediaEventType event_type;
867 hr = IMFMediaEvent_GetType(event, &event_type);
868 IMFMediaEvent_Release(event);
869 if (FAILED(hr))
870 return hr;
872 if (event_type == VLC_METransformNeedInput)
873 p_sys->pending_input_events += 1;
874 else if (event_type == VLC_METransformHaveOutput)
875 p_sys->pending_output_events += 1;
876 else
877 msg_Err(p_dec, "Unsupported asynchronous event.");
879 return S_OK;
882 static int DecodeAsync(decoder_t *p_dec, block_t *p_block)
884 decoder_sys_t *p_sys = p_dec->p_sys;
885 HRESULT hr;
887 if (!p_block) /* No Drain */
888 return VLCDEC_SUCCESS;
890 if (p_block->i_flags & (BLOCK_FLAG_CORRUPTED))
892 block_Release(p_block);
893 return VLCDEC_SUCCESS;
896 /* Dequeue all pending media events. */
897 while ((hr = DequeueMediaEvent(p_dec)) == S_OK)
898 continue;
899 if (hr != MF_E_NO_EVENTS_AVAILABLE && FAILED(hr))
900 goto error;
902 /* Drain the output stream of the MFT before sending the input packet. */
903 if (p_sys->pending_output_events > 0)
905 p_sys->pending_output_events -= 1;
906 if (ProcessOutputStream(p_dec, p_sys->output_stream_id))
907 goto error;
910 /* Poll the MFT and return decoded frames until the input stream is ready. */
911 while (p_sys->pending_input_events == 0)
913 hr = DequeueMediaEvent(p_dec);
914 if (hr == MF_E_NO_EVENTS_AVAILABLE)
916 /* Sleep for 1 ms to avoid excessive polling. */
917 Sleep(1);
918 continue;
920 if (FAILED(hr))
921 goto error;
923 if (p_sys->pending_output_events > 0)
925 p_sys->pending_output_events -= 1;
926 if (ProcessOutputStream(p_dec, p_sys->output_stream_id))
927 goto error;
928 break;
932 p_sys->pending_input_events -= 1;
933 if (ProcessInputStream(p_dec, p_sys->input_stream_id, p_block))
934 goto error;
936 block_Release(p_block);
938 return VLCDEC_SUCCESS;
940 error:
941 msg_Err(p_dec, "Error in DecodeAsync()");
942 block_Release(p_block);
943 return VLCDEC_SUCCESS;
946 static void DestroyMFT(decoder_t *p_dec);
948 static int InitializeMFT(decoder_t *p_dec)
950 decoder_sys_t *p_sys = p_dec->p_sys;
951 HRESULT hr;
953 IMFAttributes *attributes = NULL;
954 hr = IMFTransform_GetAttributes(p_sys->mft, &attributes);
955 if (hr != E_NOTIMPL && FAILED(hr))
956 goto error;
957 if (SUCCEEDED(hr))
959 UINT32 is_async = false;
960 hr = IMFAttributes_GetUINT32(attributes, &MF_TRANSFORM_ASYNC, &is_async);
961 if (hr != MF_E_ATTRIBUTENOTFOUND && FAILED(hr))
962 goto error;
963 p_sys->is_async = is_async;
964 if (p_sys->is_async)
966 hr = IMFAttributes_SetUINT32(attributes, &MF_TRANSFORM_ASYNC_UNLOCK, true);
967 if (FAILED(hr))
968 goto error;
969 hr = IMFTransform_QueryInterface(p_sys->mft, &IID_IMFMediaEventGenerator, (void**)&p_sys->event_generator);
970 if (FAILED(hr))
971 goto error;
975 DWORD input_streams_count;
976 DWORD output_streams_count;
977 hr = IMFTransform_GetStreamCount(p_sys->mft, &input_streams_count, &output_streams_count);
978 if (FAILED(hr))
979 goto error;
980 if (input_streams_count != 1 || output_streams_count != 1)
982 msg_Err(p_dec, "MFT decoder should have 1 input stream and 1 output stream.");
983 goto error;
986 hr = IMFTransform_GetStreamIDs(p_sys->mft, 1, &p_sys->input_stream_id, 1, &p_sys->output_stream_id);
987 if (hr == E_NOTIMPL)
990 * This is not an error, it happens if:
991 * - there is a fixed number of streams.
992 * AND
993 * - streams are numbered consecutively from 0 to N-1.
995 p_sys->input_stream_id = 0;
996 p_sys->output_stream_id = 0;
998 else if (FAILED(hr))
999 goto error;
1001 if (SetInputType(p_dec, p_sys->input_stream_id, &p_sys->input_type))
1002 goto error;
1004 if (SetOutputType(p_dec, p_sys->output_stream_id, &p_sys->output_type))
1005 goto error;
1008 * The input type was not set by the previous call to
1009 * SetInputType, try again after setting the output type.
1011 if (!p_sys->input_type)
1012 if (SetInputType(p_dec, p_sys->input_stream_id, &p_sys->input_type) || !p_sys->input_type)
1013 goto error;
1015 /* This call can be a no-op for some MFT decoders, but it can potentially reduce starting time. */
1016 hr = IMFTransform_ProcessMessage(p_sys->mft, MFT_MESSAGE_NOTIFY_BEGIN_STREAMING, (ULONG_PTR)0);
1017 if (FAILED(hr))
1018 goto error;
1020 /* This event is required for asynchronous MFTs, optional otherwise. */
1021 hr = IMFTransform_ProcessMessage(p_sys->mft, MFT_MESSAGE_NOTIFY_START_OF_STREAM, (ULONG_PTR)0);
1022 if (FAILED(hr))
1023 goto error;
1025 if (p_dec->fmt_in.i_codec == VLC_CODEC_H264)
1027 /* It's not an error if the following call fails. */
1028 IMFAttributes_SetUINT32(attributes, &CODECAPI_AVLowLatencyMode, true);
1030 if (p_dec->fmt_in.i_extra)
1032 if (h264_isavcC((uint8_t*)p_dec->fmt_in.p_extra, p_dec->fmt_in.i_extra))
1034 size_t i_buf;
1035 uint8_t *buf = h264_avcC_to_AnnexB_NAL(p_dec->fmt_in.p_extra,
1036 p_dec->fmt_in.i_extra,
1037 &i_buf, &p_sys->nal_length_size);
1038 if(buf)
1040 free(p_dec->fmt_in.p_extra);
1041 p_dec->fmt_in.p_extra = buf;
1042 p_dec->fmt_in.i_extra = i_buf;
1047 return VLC_SUCCESS;
1049 error:
1050 msg_Err(p_dec, "Error in InitializeMFT()");
1051 DestroyMFT(p_dec);
1052 return VLC_EGENERIC;
1055 static void DestroyMFT(decoder_t *p_dec)
1057 decoder_sys_t *p_sys = p_dec->p_sys;
1059 if (p_sys->event_generator)
1060 IMFMediaEventGenerator_Release(p_sys->event_generator);
1061 if (p_sys->input_type)
1062 IMFMediaType_Release(p_sys->input_type);
1063 if (p_sys->output_sample)
1065 IMFMediaBuffer *output_media_buffer = NULL;
1066 HRESULT hr = IMFSample_GetBufferByIndex(p_sys->output_sample, 0, &output_media_buffer);
1067 if (SUCCEEDED(hr))
1068 IMFSample_Release(output_media_buffer);
1069 IMFSample_Release(p_sys->output_sample);
1071 if (p_sys->output_type)
1072 IMFMediaType_Release(p_sys->output_type);
1073 if (p_sys->mft)
1074 IMFTransform_Release(p_sys->mft);
1076 p_sys->event_generator = NULL;
1077 p_sys->input_type = NULL;
1078 p_sys->output_sample = NULL;
1079 p_sys->output_type = NULL;
1080 p_sys->mft = NULL;
1083 static int FindMFT(decoder_t *p_dec)
1085 decoder_sys_t *p_sys = p_dec->p_sys;
1086 MFHandle *mf = &p_sys->mf_handle;
1087 HRESULT hr;
1089 /* Try to create a MFT using MFTEnumEx. */
1090 GUID category;
1091 if (p_dec->fmt_in.i_cat == VIDEO_ES)
1093 category = MFT_CATEGORY_VIDEO_DECODER;
1094 p_sys->major_type = &MFMediaType_Video;
1095 p_sys->subtype = FormatToGUID(video_format_table, p_dec->fmt_in.i_codec);
1096 if(!p_sys->subtype) {
1097 /* Codec is not well known. Construct a MF transform subtype from the fourcc */
1098 p_sys->custom_subtype = MFVideoFormat_Base;
1099 p_sys->custom_subtype.Data1 = p_dec->fmt_in.i_codec;
1100 p_sys->subtype = &p_sys->custom_subtype;
1103 else
1105 category = MFT_CATEGORY_AUDIO_DECODER;
1106 p_sys->major_type = &MFMediaType_Audio;
1107 p_sys->subtype = FormatToGUID(audio_format_table, p_dec->fmt_in.i_codec);
1109 if (!p_sys->subtype)
1110 return VLC_EGENERIC;
1112 UINT32 flags = MFT_ENUM_FLAG_SORTANDFILTER | MFT_ENUM_FLAG_LOCALMFT
1113 | MFT_ENUM_FLAG_SYNCMFT | MFT_ENUM_FLAG_ASYNCMFT
1114 | MFT_ENUM_FLAG_HARDWARE | MFT_ENUM_FLAG_TRANSCODE_ONLY;
1115 MFT_REGISTER_TYPE_INFO input_type = { *p_sys->major_type, *p_sys->subtype };
1116 IMFActivate **activate_objects = NULL;
1117 UINT32 activate_objects_count = 0;
1118 hr = mf->fptr_MFTEnumEx(category, flags, &input_type, NULL, &activate_objects, &activate_objects_count);
1119 if (FAILED(hr))
1120 return VLC_EGENERIC;
1122 msg_Dbg(p_dec, "Found %d available MFT module(s)", activate_objects_count);
1123 if (activate_objects_count == 0)
1124 return VLC_EGENERIC;
1126 for (UINT32 i = 0; i < activate_objects_count; ++i)
1128 hr = IMFActivate_ActivateObject(activate_objects[i], &IID_IMFTransform, (void**)&p_sys->mft);
1129 IMFActivate_Release(activate_objects[i]);
1130 if (FAILED(hr))
1131 continue;
1133 if (InitializeMFT(p_dec) == VLC_SUCCESS)
1135 CoTaskMemFree(activate_objects);
1136 return VLC_SUCCESS;
1139 CoTaskMemFree(activate_objects);
1141 return VLC_EGENERIC;
1144 static int LoadMFTLibrary(MFHandle *mf)
1146 #if _WIN32_WINNT < _WIN32_WINNT_WIN7 || VLC_WINSTORE_APP || __MINGW64_VERSION_MAJOR < 6
1147 mf->mfplat_dll = LoadLibrary(TEXT("mfplat.dll"));
1148 if (!mf->mfplat_dll)
1149 return VLC_EGENERIC;
1151 mf->fptr_MFTEnumEx = (void*)GetProcAddress(mf->mfplat_dll, "MFTEnumEx");
1152 mf->fptr_MFCreateSample = (void*)GetProcAddress(mf->mfplat_dll, "MFCreateSample");
1153 mf->fptr_MFCreateMemoryBuffer = (void*)GetProcAddress(mf->mfplat_dll, "MFCreateMemoryBuffer");
1154 mf->fptr_MFCreateAlignedMemoryBuffer = (void*)GetProcAddress(mf->mfplat_dll, "MFCreateAlignedMemoryBuffer");
1155 if (!mf->fptr_MFTEnumEx || !mf->fptr_MFCreateSample || !mf->fptr_MFCreateMemoryBuffer || !mf->fptr_MFCreateAlignedMemoryBuffer)
1156 return VLC_EGENERIC;
1157 #else
1158 mf->fptr_MFTEnumEx = &MFTEnumEx;
1159 mf->fptr_MFCreateSample = &MFCreateSample;
1160 mf->fptr_MFCreateMemoryBuffer = &MFCreateMemoryBuffer;
1161 mf->fptr_MFCreateAlignedMemoryBuffer = &MFCreateAlignedMemoryBuffer;
1162 #endif
1164 return VLC_SUCCESS;
1167 static int Open(vlc_object_t *p_this)
1169 decoder_t *p_dec = (decoder_t *)p_this;
1170 decoder_sys_t *p_sys;
1172 p_sys = p_dec->p_sys = calloc(1, sizeof(*p_sys));
1173 if (!p_sys)
1174 return VLC_ENOMEM;
1176 if( FAILED(CoInitializeEx(NULL, COINIT_MULTITHREADED)) )
1178 free(p_sys);
1179 return VLC_EGENERIC;
1182 if (LoadMFTLibrary(&p_sys->mf_handle))
1184 msg_Err(p_dec, "Failed to load MFT library.");
1185 goto error;
1188 if (FindMFT(p_dec))
1190 msg_Err(p_dec, "Could not find suitable MFT decoder");
1191 goto error;
1194 /* Only one output sample is needed, we can allocate one and reuse it. */
1195 if (AllocateOutputSample(p_dec, 0, &p_sys->output_sample))
1196 goto error;
1198 p_dec->pf_decode = p_sys->is_async ? DecodeAsync : DecodeSync;
1200 return VLC_SUCCESS;
1202 error:
1203 Close(p_this);
1204 return VLC_EGENERIC;
1207 static void Close(vlc_object_t *p_this)
1209 decoder_t *p_dec = (decoder_t *)p_this;
1210 decoder_sys_t *p_sys = p_dec->p_sys;
1211 MFHandle *mf = &p_sys->mf_handle;
1213 DestroyMFT(p_dec);
1215 if (mf->mfplat_dll)
1216 FreeLibrary(mf->mfplat_dll);
1218 free(p_sys);
1220 CoUninitialize();