2 * Copyright 2020 Nikolay Sivov for CodeWeavers
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
23 #include "mf_private.h"
25 #include "wine/debug.h"
26 #include "wine/heap.h"
28 WINE_DEFAULT_DEBUG_CHANNEL(mfplat
);
30 enum sample_copier_flags
32 SAMPLE_COPIER_INPUT_TYPE_SET
= 0x1,
33 SAMPLE_COPIER_OUTPUT_TYPE_SET
= 0x2
38 IMFTransform IMFTransform_iface
;
41 IMFAttributes
*attributes
;
42 IMFMediaType
*buffer_type
;
49 static struct sample_copier
*impl_from_IMFTransform(IMFTransform
*iface
)
51 return CONTAINING_RECORD(iface
, struct sample_copier
, IMFTransform_iface
);
54 static HRESULT WINAPI
sample_copier_transform_QueryInterface(IMFTransform
*iface
, REFIID riid
, void **obj
)
56 TRACE("%p, %s, %p.\n", iface
, debugstr_guid(riid
), obj
);
58 if (IsEqualIID(riid
, &IID_IMFTransform
) ||
59 IsEqualIID(riid
, &IID_IUnknown
))
62 IMFTransform_AddRef(iface
);
66 WARN("Unsupported interface %s.\n", debugstr_guid(riid
));
71 static ULONG WINAPI
sample_copier_transform_AddRef(IMFTransform
*iface
)
73 struct sample_copier
*transform
= impl_from_IMFTransform(iface
);
74 ULONG refcount
= InterlockedIncrement(&transform
->refcount
);
76 TRACE("%p, refcount %u.\n", iface
, refcount
);
81 static ULONG WINAPI
sample_copier_transform_Release(IMFTransform
*iface
)
83 struct sample_copier
*transform
= impl_from_IMFTransform(iface
);
84 ULONG refcount
= InterlockedDecrement(&transform
->refcount
);
86 TRACE("%p, refcount %u.\n", iface
, refcount
);
90 if (transform
->attributes
)
91 IMFAttributes_Release(transform
->attributes
);
92 if (transform
->buffer_type
)
93 IMFMediaType_Release(transform
->buffer_type
);
94 DeleteCriticalSection(&transform
->cs
);
101 static HRESULT WINAPI
sample_copier_transform_GetStreamLimits(IMFTransform
*iface
, DWORD
*input_minimum
,
102 DWORD
*input_maximum
, DWORD
*output_minimum
, DWORD
*output_maximum
)
104 TRACE("%p, %p, %p, %p, %p.\n", iface
, input_minimum
, input_maximum
, output_minimum
, output_maximum
);
106 *input_minimum
= *input_maximum
= *output_minimum
= *output_maximum
= 1;
111 static HRESULT WINAPI
sample_copier_transform_GetStreamCount(IMFTransform
*iface
, DWORD
*inputs
, DWORD
*outputs
)
113 TRACE("%p, %p, %p.\n", iface
, inputs
, outputs
);
121 static HRESULT WINAPI
sample_copier_transform_GetStreamIDs(IMFTransform
*iface
, DWORD input_size
, DWORD
*inputs
,
122 DWORD output_size
, DWORD
*outputs
)
124 TRACE("%p, %u, %p, %u, %p.\n", iface
, input_size
, inputs
, output_size
, outputs
);
129 static HRESULT WINAPI
sample_copier_transform_GetInputStreamInfo(IMFTransform
*iface
, DWORD id
, MFT_INPUT_STREAM_INFO
*info
)
131 struct sample_copier
*transform
= impl_from_IMFTransform(iface
);
133 TRACE("%p, %u, %p.\n", iface
, id
, info
);
135 memset(info
, 0, sizeof(*info
));
137 EnterCriticalSection(&transform
->cs
);
138 info
->cbSize
= transform
->buffer_size
;
139 LeaveCriticalSection(&transform
->cs
);
144 static HRESULT WINAPI
sample_copier_transform_GetOutputStreamInfo(IMFTransform
*iface
, DWORD id
,
145 MFT_OUTPUT_STREAM_INFO
*info
)
147 struct sample_copier
*transform
= impl_from_IMFTransform(iface
);
149 TRACE("%p, %u, %p.\n", iface
, id
, info
);
151 memset(info
, 0, sizeof(*info
));
153 EnterCriticalSection(&transform
->cs
);
154 info
->cbSize
= transform
->buffer_size
;
155 LeaveCriticalSection(&transform
->cs
);
160 static HRESULT WINAPI
sample_copier_transform_GetAttributes(IMFTransform
*iface
, IMFAttributes
**attributes
)
162 struct sample_copier
*transform
= impl_from_IMFTransform(iface
);
164 TRACE("%p, %p.\n", iface
, attributes
);
166 *attributes
= transform
->attributes
;
167 IMFAttributes_AddRef(*attributes
);
172 static HRESULT WINAPI
sample_copier_transform_GetInputStreamAttributes(IMFTransform
*iface
, DWORD id
,
173 IMFAttributes
**attributes
)
175 TRACE("%p, %u, %p.\n", iface
, id
, attributes
);
180 static HRESULT WINAPI
sample_copier_transform_GetOutputStreamAttributes(IMFTransform
*iface
, DWORD id
,
181 IMFAttributes
**attributes
)
183 TRACE("%p, %u, %p.\n", iface
, id
, attributes
);
188 static HRESULT WINAPI
sample_copier_transform_DeleteInputStream(IMFTransform
*iface
, DWORD id
)
190 TRACE("%p, %u.\n", iface
, id
);
195 static HRESULT WINAPI
sample_copier_transform_AddInputStreams(IMFTransform
*iface
, DWORD streams
, DWORD
*ids
)
197 TRACE("%p, %u, %p.\n", iface
, streams
, ids
);
202 static HRESULT WINAPI
sample_copier_transform_GetInputAvailableType(IMFTransform
*iface
, DWORD id
, DWORD index
,
205 static const GUID
*types
[] = { &MFMediaType_Video
, &MFMediaType_Audio
};
208 TRACE("%p, %u, %u, %p.\n", iface
, id
, index
, type
);
211 return MF_E_INVALIDSTREAMNUMBER
;
213 if (index
> ARRAY_SIZE(types
) - 1)
214 return MF_E_NO_MORE_TYPES
;
216 if (SUCCEEDED(hr
= MFCreateMediaType(type
)))
217 hr
= IMFMediaType_SetGUID(*type
, &MF_MT_MAJOR_TYPE
, types
[index
]);
222 static HRESULT WINAPI
sample_copier_transform_GetOutputAvailableType(IMFTransform
*iface
, DWORD id
, DWORD index
,
225 struct sample_copier
*transform
= impl_from_IMFTransform(iface
);
226 IMFMediaType
*cloned_type
= NULL
;
229 TRACE("%p, %u, %u, %p.\n", iface
, id
, index
, type
);
231 EnterCriticalSection(&transform
->cs
);
232 if (transform
->buffer_type
)
234 if (SUCCEEDED(hr
= MFCreateMediaType(&cloned_type
)))
235 hr
= IMFMediaType_CopyAllItems(transform
->buffer_type
, (IMFAttributes
*)cloned_type
);
238 hr
= MF_E_INVALIDSTREAMNUMBER
;
240 hr
= MF_E_NO_MORE_TYPES
;
241 LeaveCriticalSection(&transform
->cs
);
245 else if (cloned_type
)
246 IMFMediaType_Release(cloned_type
);
251 static HRESULT
sample_copier_get_buffer_size(IMFMediaType
*type
, DWORD
*size
)
259 if (FAILED(hr
= IMFMediaType_GetMajorType(type
, &major
)))
262 if (IsEqualGUID(&major
, &MFMediaType_Video
))
264 if (SUCCEEDED(hr
= IMFMediaType_GetGUID(type
, &MF_MT_SUBTYPE
, &subtype
)))
266 if (SUCCEEDED(hr
= IMFMediaType_GetUINT64(type
, &MF_MT_FRAME_SIZE
, &frame_size
)))
268 if (FAILED(hr
= MFCalculateImageSize(&subtype
, (UINT32
)(frame_size
>> 32), (UINT32
)frame_size
, size
)))
269 WARN("Failed to get image size for video format %s.\n", debugstr_guid(&subtype
));
273 else if (IsEqualGUID(&major
, &MFMediaType_Audio
))
275 FIXME("Audio formats are not handled.\n");
282 static HRESULT
sample_copier_set_media_type(struct sample_copier
*transform
, BOOL input
, DWORD id
, IMFMediaType
*type
,
289 return MF_E_INVALIDSTREAMNUMBER
;
291 EnterCriticalSection(&transform
->cs
);
294 hr
= sample_copier_get_buffer_size(type
, &buffer_size
);
295 if (!(flags
& MFT_SET_TYPE_TEST_ONLY
) && SUCCEEDED(hr
))
297 if (!transform
->buffer_type
)
298 hr
= MFCreateMediaType(&transform
->buffer_type
);
300 hr
= IMFMediaType_CopyAllItems(type
, (IMFAttributes
*)transform
->buffer_type
);
302 transform
->buffer_size
= buffer_size
;
308 transform
->flags
|= SAMPLE_COPIER_INPUT_TYPE_SET
;
309 transform
->flags
&= ~SAMPLE_COPIER_OUTPUT_TYPE_SET
;
312 transform
->flags
|= SAMPLE_COPIER_OUTPUT_TYPE_SET
;
316 else if (transform
->buffer_type
)
318 IMFMediaType_Release(transform
->buffer_type
);
319 transform
->buffer_type
= NULL
;
321 LeaveCriticalSection(&transform
->cs
);
326 static HRESULT WINAPI
sample_copier_transform_SetInputType(IMFTransform
*iface
, DWORD id
, IMFMediaType
*type
, DWORD flags
)
328 struct sample_copier
*transform
= impl_from_IMFTransform(iface
);
330 TRACE("%p, %u, %p, %#x.\n", iface
, id
, type
, flags
);
332 return sample_copier_set_media_type(transform
, TRUE
, id
, type
, flags
);
335 static HRESULT WINAPI
sample_copier_transform_SetOutputType(IMFTransform
*iface
, DWORD id
, IMFMediaType
*type
, DWORD flags
)
337 struct sample_copier
*transform
= impl_from_IMFTransform(iface
);
339 TRACE("%p, %u, %p, %#x.\n", iface
, id
, type
, flags
);
341 return sample_copier_set_media_type(transform
, FALSE
, id
, type
, flags
);
344 static HRESULT
sample_copier_get_current_type(struct sample_copier
*transform
, DWORD id
, DWORD flags
,
347 IMFMediaType
*cloned_type
= NULL
;
351 return MF_E_INVALIDSTREAMNUMBER
;
353 EnterCriticalSection(&transform
->cs
);
354 if (transform
->flags
& flags
)
356 if (SUCCEEDED(hr
= MFCreateMediaType(&cloned_type
)))
357 hr
= IMFMediaType_CopyAllItems(transform
->buffer_type
, (IMFAttributes
*)cloned_type
);
360 hr
= MF_E_TRANSFORM_TYPE_NOT_SET
;
361 LeaveCriticalSection(&transform
->cs
);
365 else if (cloned_type
)
366 IMFMediaType_Release(cloned_type
);
371 static HRESULT WINAPI
sample_copier_transform_GetInputCurrentType(IMFTransform
*iface
, DWORD id
, IMFMediaType
**type
)
373 struct sample_copier
*transform
= impl_from_IMFTransform(iface
);
375 TRACE("%p, %u, %p.\n", iface
, id
, type
);
377 return sample_copier_get_current_type(transform
, id
, SAMPLE_COPIER_INPUT_TYPE_SET
, type
);
380 static HRESULT WINAPI
sample_copier_transform_GetOutputCurrentType(IMFTransform
*iface
, DWORD id
, IMFMediaType
**type
)
382 struct sample_copier
*transform
= impl_from_IMFTransform(iface
);
384 TRACE("%p, %u, %p.\n", iface
, id
, type
);
386 return sample_copier_get_current_type(transform
, id
, SAMPLE_COPIER_OUTPUT_TYPE_SET
, type
);
389 static HRESULT WINAPI
sample_copier_transform_GetInputStatus(IMFTransform
*iface
, DWORD id
, DWORD
*flags
)
391 struct sample_copier
*transform
= impl_from_IMFTransform(iface
);
394 TRACE("%p, %u, %p.\n", iface
, id
, flags
);
397 return MF_E_INVALIDSTREAMNUMBER
;
399 EnterCriticalSection(&transform
->cs
);
400 if (!(transform
->flags
& SAMPLE_COPIER_INPUT_TYPE_SET
))
401 hr
= MF_E_TRANSFORM_TYPE_NOT_SET
;
403 *flags
= transform
->sample
? 0 : MFT_INPUT_STATUS_ACCEPT_DATA
;
404 LeaveCriticalSection(&transform
->cs
);
409 static HRESULT WINAPI
sample_copier_transform_GetOutputStatus(IMFTransform
*iface
, DWORD
*flags
)
411 struct sample_copier
*transform
= impl_from_IMFTransform(iface
);
414 TRACE("%p, %p.\n", iface
, flags
);
416 EnterCriticalSection(&transform
->cs
);
417 if (!(transform
->flags
& SAMPLE_COPIER_OUTPUT_TYPE_SET
))
418 hr
= MF_E_TRANSFORM_TYPE_NOT_SET
;
420 *flags
= transform
->sample
? MFT_OUTPUT_STATUS_SAMPLE_READY
: 0;
421 LeaveCriticalSection(&transform
->cs
);
426 static HRESULT WINAPI
sample_copier_transform_SetOutputBounds(IMFTransform
*iface
, LONGLONG lower
, LONGLONG upper
)
428 TRACE("%p, %s, %s.\n", iface
, debugstr_time(lower
), debugstr_time(upper
));
433 static HRESULT WINAPI
sample_copier_transform_ProcessEvent(IMFTransform
*iface
, DWORD id
, IMFMediaEvent
*event
)
435 FIXME("%p, %u, %p.\n", iface
, id
, event
);
440 static HRESULT WINAPI
sample_copier_transform_ProcessMessage(IMFTransform
*iface
, MFT_MESSAGE_TYPE message
, ULONG_PTR param
)
442 struct sample_copier
*transform
= impl_from_IMFTransform(iface
);
444 TRACE("%p, %#x, %p.\n", iface
, message
, (void *)param
);
446 EnterCriticalSection(&transform
->cs
);
448 if (message
== MFT_MESSAGE_COMMAND_FLUSH
)
450 if (transform
->sample
)
452 IMFSample_Release(transform
->sample
);
453 transform
->sample
= NULL
;
457 LeaveCriticalSection(&transform
->cs
);
462 static HRESULT WINAPI
sample_copier_transform_ProcessInput(IMFTransform
*iface
, DWORD id
, IMFSample
*sample
, DWORD flags
)
464 struct sample_copier
*transform
= impl_from_IMFTransform(iface
);
467 TRACE("%p, %u, %p, %#x.\n", iface
, id
, sample
, flags
);
470 return MF_E_INVALIDSTREAMNUMBER
;
472 EnterCriticalSection(&transform
->cs
);
473 if (!transform
->buffer_type
)
474 hr
= MF_E_TRANSFORM_TYPE_NOT_SET
;
475 else if (transform
->sample
)
476 hr
= MF_E_NOTACCEPTING
;
479 transform
->sample
= sample
;
480 IMFSample_AddRef(transform
->sample
);
482 LeaveCriticalSection(&transform
->cs
);
487 static HRESULT WINAPI
sample_copier_transform_ProcessOutput(IMFTransform
*iface
, DWORD flags
, DWORD count
,
488 MFT_OUTPUT_DATA_BUFFER
*buffers
, DWORD
*status
)
490 struct sample_copier
*transform
= impl_from_IMFTransform(iface
);
491 IMFMediaBuffer
*buffer
;
496 TRACE("%p, %#x, %u, %p, %p.\n", iface
, flags
, count
, buffers
, status
);
498 EnterCriticalSection(&transform
->cs
);
499 if (!(transform
->flags
& SAMPLE_COPIER_OUTPUT_TYPE_SET
))
500 hr
= MF_E_TRANSFORM_TYPE_NOT_SET
;
501 else if (!transform
->sample
)
502 hr
= MF_E_TRANSFORM_NEED_MORE_INPUT
;
505 IMFSample_CopyAllItems(transform
->sample
, (IMFAttributes
*)buffers
->pSample
);
507 if (SUCCEEDED(IMFSample_GetSampleDuration(transform
->sample
, &time
)))
508 IMFSample_SetSampleDuration(buffers
->pSample
, time
);
510 if (SUCCEEDED(IMFSample_GetSampleTime(transform
->sample
, &time
)))
511 IMFSample_SetSampleTime(buffers
->pSample
, time
);
513 if (SUCCEEDED(IMFSample_GetSampleFlags(transform
->sample
, &sample_flags
)))
514 IMFSample_SetSampleFlags(buffers
->pSample
, sample_flags
);
516 if (SUCCEEDED(IMFSample_ConvertToContiguousBuffer(transform
->sample
, NULL
)))
518 if (SUCCEEDED(IMFSample_GetBufferByIndex(buffers
->pSample
, 0, &buffer
)))
520 if (FAILED(IMFSample_CopyToBuffer(transform
->sample
, buffer
)))
521 hr
= MF_E_UNEXPECTED
;
522 IMFMediaBuffer_Release(buffer
);
526 IMFSample_Release(transform
->sample
);
527 transform
->sample
= NULL
;
529 LeaveCriticalSection(&transform
->cs
);
534 static const IMFTransformVtbl sample_copier_transform_vtbl
=
536 sample_copier_transform_QueryInterface
,
537 sample_copier_transform_AddRef
,
538 sample_copier_transform_Release
,
539 sample_copier_transform_GetStreamLimits
,
540 sample_copier_transform_GetStreamCount
,
541 sample_copier_transform_GetStreamIDs
,
542 sample_copier_transform_GetInputStreamInfo
,
543 sample_copier_transform_GetOutputStreamInfo
,
544 sample_copier_transform_GetAttributes
,
545 sample_copier_transform_GetInputStreamAttributes
,
546 sample_copier_transform_GetOutputStreamAttributes
,
547 sample_copier_transform_DeleteInputStream
,
548 sample_copier_transform_AddInputStreams
,
549 sample_copier_transform_GetInputAvailableType
,
550 sample_copier_transform_GetOutputAvailableType
,
551 sample_copier_transform_SetInputType
,
552 sample_copier_transform_SetOutputType
,
553 sample_copier_transform_GetInputCurrentType
,
554 sample_copier_transform_GetOutputCurrentType
,
555 sample_copier_transform_GetInputStatus
,
556 sample_copier_transform_GetOutputStatus
,
557 sample_copier_transform_SetOutputBounds
,
558 sample_copier_transform_ProcessEvent
,
559 sample_copier_transform_ProcessMessage
,
560 sample_copier_transform_ProcessInput
,
561 sample_copier_transform_ProcessOutput
,
564 BOOL
mf_is_sample_copier_transform(IMFTransform
*transform
)
566 return transform
->lpVtbl
== &sample_copier_transform_vtbl
;
569 /***********************************************************************
570 * MFCreateSampleCopierMFT (mf.@)
572 HRESULT WINAPI
MFCreateSampleCopierMFT(IMFTransform
**transform
)
574 struct sample_copier
*object
;
577 TRACE("%p.\n", transform
);
579 object
= heap_alloc_zero(sizeof(*object
));
581 return E_OUTOFMEMORY
;
583 object
->IMFTransform_iface
.lpVtbl
= &sample_copier_transform_vtbl
;
584 object
->refcount
= 1;
585 InitializeCriticalSection(&object
->cs
);
587 if (FAILED(hr
= MFCreateAttributes(&object
->attributes
, 0)))
590 IMFAttributes_SetUINT32(object
->attributes
, &MFT_SUPPORT_DYNAMIC_FORMAT_CHANGE
, 1);
592 *transform
= &object
->IMFTransform_iface
;
598 IMFTransform_Release(&object
->IMFTransform_iface
);