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"
27 WINE_DEFAULT_DEBUG_CHANNEL(mfplat
);
29 enum sample_copier_flags
31 SAMPLE_COPIER_INPUT_TYPE_SET
= 0x1,
32 SAMPLE_COPIER_OUTPUT_TYPE_SET
= 0x2
37 IMFTransform IMFTransform_iface
;
40 IMFAttributes
*attributes
;
41 IMFMediaType
*buffer_type
;
48 static struct sample_copier
*impl_from_IMFTransform(IMFTransform
*iface
)
50 return CONTAINING_RECORD(iface
, struct sample_copier
, IMFTransform_iface
);
53 static HRESULT WINAPI
sample_copier_transform_QueryInterface(IMFTransform
*iface
, REFIID riid
, void **obj
)
55 TRACE("%p, %s, %p.\n", iface
, debugstr_guid(riid
), obj
);
57 if (IsEqualIID(riid
, &IID_IMFTransform
) ||
58 IsEqualIID(riid
, &IID_IUnknown
))
61 IMFTransform_AddRef(iface
);
65 WARN("Unsupported interface %s.\n", debugstr_guid(riid
));
70 static ULONG WINAPI
sample_copier_transform_AddRef(IMFTransform
*iface
)
72 struct sample_copier
*transform
= impl_from_IMFTransform(iface
);
73 ULONG refcount
= InterlockedIncrement(&transform
->refcount
);
75 TRACE("%p, refcount %lu.\n", iface
, refcount
);
80 static ULONG WINAPI
sample_copier_transform_Release(IMFTransform
*iface
)
82 struct sample_copier
*transform
= impl_from_IMFTransform(iface
);
83 ULONG refcount
= InterlockedDecrement(&transform
->refcount
);
85 TRACE("%p, refcount %lu.\n", iface
, refcount
);
89 if (transform
->attributes
)
90 IMFAttributes_Release(transform
->attributes
);
91 if (transform
->buffer_type
)
92 IMFMediaType_Release(transform
->buffer_type
);
93 DeleteCriticalSection(&transform
->cs
);
100 static HRESULT WINAPI
sample_copier_transform_GetStreamLimits(IMFTransform
*iface
, DWORD
*input_minimum
,
101 DWORD
*input_maximum
, DWORD
*output_minimum
, DWORD
*output_maximum
)
103 TRACE("%p, %p, %p, %p, %p.\n", iface
, input_minimum
, input_maximum
, output_minimum
, output_maximum
);
105 *input_minimum
= *input_maximum
= *output_minimum
= *output_maximum
= 1;
110 static HRESULT WINAPI
sample_copier_transform_GetStreamCount(IMFTransform
*iface
, DWORD
*inputs
, DWORD
*outputs
)
112 TRACE("%p, %p, %p.\n", iface
, inputs
, outputs
);
120 static HRESULT WINAPI
sample_copier_transform_GetStreamIDs(IMFTransform
*iface
, DWORD input_size
, DWORD
*inputs
,
121 DWORD output_size
, DWORD
*outputs
)
123 TRACE("%p, %lu, %p, %lu, %p.\n", iface
, input_size
, inputs
, output_size
, outputs
);
128 static HRESULT WINAPI
sample_copier_transform_GetInputStreamInfo(IMFTransform
*iface
, DWORD id
, MFT_INPUT_STREAM_INFO
*info
)
130 struct sample_copier
*transform
= impl_from_IMFTransform(iface
);
132 TRACE("%p, %lu, %p.\n", iface
, id
, info
);
134 memset(info
, 0, sizeof(*info
));
136 EnterCriticalSection(&transform
->cs
);
137 info
->cbSize
= transform
->buffer_size
;
138 LeaveCriticalSection(&transform
->cs
);
143 static HRESULT WINAPI
sample_copier_transform_GetOutputStreamInfo(IMFTransform
*iface
, DWORD id
,
144 MFT_OUTPUT_STREAM_INFO
*info
)
146 struct sample_copier
*transform
= impl_from_IMFTransform(iface
);
148 TRACE("%p, %lu, %p.\n", iface
, id
, info
);
150 memset(info
, 0, sizeof(*info
));
152 EnterCriticalSection(&transform
->cs
);
153 info
->cbSize
= transform
->buffer_size
;
154 LeaveCriticalSection(&transform
->cs
);
159 static HRESULT WINAPI
sample_copier_transform_GetAttributes(IMFTransform
*iface
, IMFAttributes
**attributes
)
161 struct sample_copier
*transform
= impl_from_IMFTransform(iface
);
163 TRACE("%p, %p.\n", iface
, attributes
);
165 *attributes
= transform
->attributes
;
166 IMFAttributes_AddRef(*attributes
);
171 static HRESULT WINAPI
sample_copier_transform_GetInputStreamAttributes(IMFTransform
*iface
, DWORD id
,
172 IMFAttributes
**attributes
)
174 TRACE("%p, %lu, %p.\n", iface
, id
, attributes
);
179 static HRESULT WINAPI
sample_copier_transform_GetOutputStreamAttributes(IMFTransform
*iface
, DWORD id
,
180 IMFAttributes
**attributes
)
182 TRACE("%p, %lu, %p.\n", iface
, id
, attributes
);
187 static HRESULT WINAPI
sample_copier_transform_DeleteInputStream(IMFTransform
*iface
, DWORD id
)
189 TRACE("%p, %lu.\n", iface
, id
);
194 static HRESULT WINAPI
sample_copier_transform_AddInputStreams(IMFTransform
*iface
, DWORD streams
, DWORD
*ids
)
196 TRACE("%p, %lu, %p.\n", iface
, streams
, ids
);
201 static HRESULT WINAPI
sample_copier_transform_GetInputAvailableType(IMFTransform
*iface
, DWORD id
, DWORD index
,
204 static const GUID
*types
[] = { &MFMediaType_Video
, &MFMediaType_Audio
};
207 TRACE("%p, %lu, %lu, %p.\n", iface
, id
, index
, type
);
210 return MF_E_INVALIDSTREAMNUMBER
;
212 if (index
> ARRAY_SIZE(types
) - 1)
213 return MF_E_NO_MORE_TYPES
;
215 if (SUCCEEDED(hr
= MFCreateMediaType(type
)))
216 hr
= IMFMediaType_SetGUID(*type
, &MF_MT_MAJOR_TYPE
, types
[index
]);
221 static HRESULT WINAPI
sample_copier_transform_GetOutputAvailableType(IMFTransform
*iface
, DWORD id
, DWORD index
,
224 struct sample_copier
*transform
= impl_from_IMFTransform(iface
);
225 IMFMediaType
*cloned_type
= NULL
;
228 TRACE("%p, %lu, %lu, %p.\n", iface
, id
, index
, type
);
230 EnterCriticalSection(&transform
->cs
);
231 if (transform
->buffer_type
)
233 if (SUCCEEDED(hr
= MFCreateMediaType(&cloned_type
)))
234 hr
= IMFMediaType_CopyAllItems(transform
->buffer_type
, (IMFAttributes
*)cloned_type
);
237 hr
= MF_E_INVALIDSTREAMNUMBER
;
239 hr
= MF_E_NO_MORE_TYPES
;
240 LeaveCriticalSection(&transform
->cs
);
244 else if (cloned_type
)
245 IMFMediaType_Release(cloned_type
);
250 static HRESULT
sample_copier_get_buffer_size(IMFMediaType
*type
, UINT32
*size
)
258 if (FAILED(hr
= IMFMediaType_GetMajorType(type
, &major
)))
261 if (IsEqualGUID(&major
, &MFMediaType_Video
))
263 if (SUCCEEDED(hr
= IMFMediaType_GetGUID(type
, &MF_MT_SUBTYPE
, &subtype
)))
265 if (SUCCEEDED(hr
= IMFMediaType_GetUINT64(type
, &MF_MT_FRAME_SIZE
, &frame_size
)))
267 if (FAILED(hr
= MFCalculateImageSize(&subtype
, (UINT32
)(frame_size
>> 32), (UINT32
)frame_size
, size
)))
268 WARN("Failed to get image size for video format %s.\n", debugstr_guid(&subtype
));
272 else if (IsEqualGUID(&major
, &MFMediaType_Audio
))
274 FIXME("Audio formats are not handled.\n");
281 static HRESULT
sample_copier_set_media_type(struct sample_copier
*transform
, BOOL input
, DWORD id
, IMFMediaType
*type
,
288 return MF_E_INVALIDSTREAMNUMBER
;
290 EnterCriticalSection(&transform
->cs
);
293 hr
= sample_copier_get_buffer_size(type
, &buffer_size
);
294 if (!(flags
& MFT_SET_TYPE_TEST_ONLY
) && SUCCEEDED(hr
))
296 if (!transform
->buffer_type
)
297 hr
= MFCreateMediaType(&transform
->buffer_type
);
299 hr
= IMFMediaType_CopyAllItems(type
, (IMFAttributes
*)transform
->buffer_type
);
301 transform
->buffer_size
= buffer_size
;
307 transform
->flags
|= SAMPLE_COPIER_INPUT_TYPE_SET
;
308 transform
->flags
&= ~SAMPLE_COPIER_OUTPUT_TYPE_SET
;
311 transform
->flags
|= SAMPLE_COPIER_OUTPUT_TYPE_SET
;
315 else if (transform
->buffer_type
)
317 IMFMediaType_Release(transform
->buffer_type
);
318 transform
->buffer_type
= NULL
;
320 LeaveCriticalSection(&transform
->cs
);
325 static HRESULT WINAPI
sample_copier_transform_SetInputType(IMFTransform
*iface
, DWORD id
, IMFMediaType
*type
, DWORD flags
)
327 struct sample_copier
*transform
= impl_from_IMFTransform(iface
);
329 TRACE("%p, %lu, %p, %#lx.\n", iface
, id
, type
, flags
);
331 return sample_copier_set_media_type(transform
, TRUE
, id
, type
, flags
);
334 static HRESULT WINAPI
sample_copier_transform_SetOutputType(IMFTransform
*iface
, DWORD id
, IMFMediaType
*type
, DWORD flags
)
336 struct sample_copier
*transform
= impl_from_IMFTransform(iface
);
338 TRACE("%p, %lu, %p, %#lx.\n", iface
, id
, type
, flags
);
340 return sample_copier_set_media_type(transform
, FALSE
, id
, type
, flags
);
343 static HRESULT
sample_copier_get_current_type(struct sample_copier
*transform
, DWORD id
, DWORD flags
,
346 IMFMediaType
*cloned_type
= NULL
;
350 return MF_E_INVALIDSTREAMNUMBER
;
352 EnterCriticalSection(&transform
->cs
);
353 if (transform
->flags
& flags
)
355 if (SUCCEEDED(hr
= MFCreateMediaType(&cloned_type
)))
356 hr
= IMFMediaType_CopyAllItems(transform
->buffer_type
, (IMFAttributes
*)cloned_type
);
359 hr
= MF_E_TRANSFORM_TYPE_NOT_SET
;
360 LeaveCriticalSection(&transform
->cs
);
364 else if (cloned_type
)
365 IMFMediaType_Release(cloned_type
);
370 static HRESULT WINAPI
sample_copier_transform_GetInputCurrentType(IMFTransform
*iface
, DWORD id
, IMFMediaType
**type
)
372 struct sample_copier
*transform
= impl_from_IMFTransform(iface
);
374 TRACE("%p, %lu, %p.\n", iface
, id
, type
);
376 return sample_copier_get_current_type(transform
, id
, SAMPLE_COPIER_INPUT_TYPE_SET
, type
);
379 static HRESULT WINAPI
sample_copier_transform_GetOutputCurrentType(IMFTransform
*iface
, DWORD id
, IMFMediaType
**type
)
381 struct sample_copier
*transform
= impl_from_IMFTransform(iface
);
383 TRACE("%p, %lu, %p.\n", iface
, id
, type
);
385 return sample_copier_get_current_type(transform
, id
, SAMPLE_COPIER_OUTPUT_TYPE_SET
, type
);
388 static HRESULT WINAPI
sample_copier_transform_GetInputStatus(IMFTransform
*iface
, DWORD id
, DWORD
*flags
)
390 struct sample_copier
*transform
= impl_from_IMFTransform(iface
);
393 TRACE("%p, %lu, %p.\n", iface
, id
, flags
);
396 return MF_E_INVALIDSTREAMNUMBER
;
398 EnterCriticalSection(&transform
->cs
);
399 if (!(transform
->flags
& SAMPLE_COPIER_INPUT_TYPE_SET
))
400 hr
= MF_E_TRANSFORM_TYPE_NOT_SET
;
402 *flags
= transform
->sample
? 0 : MFT_INPUT_STATUS_ACCEPT_DATA
;
403 LeaveCriticalSection(&transform
->cs
);
408 static HRESULT WINAPI
sample_copier_transform_GetOutputStatus(IMFTransform
*iface
, DWORD
*flags
)
410 struct sample_copier
*transform
= impl_from_IMFTransform(iface
);
413 TRACE("%p, %p.\n", iface
, flags
);
415 EnterCriticalSection(&transform
->cs
);
416 if (!(transform
->flags
& SAMPLE_COPIER_OUTPUT_TYPE_SET
))
417 hr
= MF_E_TRANSFORM_TYPE_NOT_SET
;
419 *flags
= transform
->sample
? MFT_OUTPUT_STATUS_SAMPLE_READY
: 0;
420 LeaveCriticalSection(&transform
->cs
);
425 static HRESULT WINAPI
sample_copier_transform_SetOutputBounds(IMFTransform
*iface
, LONGLONG lower
, LONGLONG upper
)
427 TRACE("%p, %s, %s.\n", iface
, debugstr_time(lower
), debugstr_time(upper
));
432 static HRESULT WINAPI
sample_copier_transform_ProcessEvent(IMFTransform
*iface
, DWORD id
, IMFMediaEvent
*event
)
434 FIXME("%p, %lu, %p.\n", iface
, id
, event
);
439 static HRESULT WINAPI
sample_copier_transform_ProcessMessage(IMFTransform
*iface
, MFT_MESSAGE_TYPE message
, ULONG_PTR param
)
441 struct sample_copier
*transform
= impl_from_IMFTransform(iface
);
443 TRACE("%p, %#x, %p.\n", iface
, message
, (void *)param
);
445 EnterCriticalSection(&transform
->cs
);
447 if (message
== MFT_MESSAGE_COMMAND_FLUSH
)
449 if (transform
->sample
)
451 IMFSample_Release(transform
->sample
);
452 transform
->sample
= NULL
;
456 LeaveCriticalSection(&transform
->cs
);
461 static HRESULT WINAPI
sample_copier_transform_ProcessInput(IMFTransform
*iface
, DWORD id
, IMFSample
*sample
, DWORD flags
)
463 struct sample_copier
*transform
= impl_from_IMFTransform(iface
);
466 TRACE("%p, %lu, %p, %#lx.\n", iface
, id
, sample
, flags
);
469 return MF_E_INVALIDSTREAMNUMBER
;
471 EnterCriticalSection(&transform
->cs
);
472 if (!transform
->buffer_type
)
473 hr
= MF_E_TRANSFORM_TYPE_NOT_SET
;
474 else if (transform
->sample
)
475 hr
= MF_E_NOTACCEPTING
;
478 transform
->sample
= sample
;
479 IMFSample_AddRef(transform
->sample
);
481 LeaveCriticalSection(&transform
->cs
);
486 static HRESULT WINAPI
sample_copier_transform_ProcessOutput(IMFTransform
*iface
, DWORD flags
, DWORD count
,
487 MFT_OUTPUT_DATA_BUFFER
*buffers
, DWORD
*status
)
489 struct sample_copier
*transform
= impl_from_IMFTransform(iface
);
490 IMFMediaBuffer
*buffer
;
495 TRACE("%p, %#lx, %lu, %p, %p.\n", iface
, flags
, count
, buffers
, status
);
497 EnterCriticalSection(&transform
->cs
);
498 if (!(transform
->flags
& SAMPLE_COPIER_OUTPUT_TYPE_SET
))
499 hr
= MF_E_TRANSFORM_TYPE_NOT_SET
;
500 else if (!transform
->sample
)
501 hr
= MF_E_TRANSFORM_NEED_MORE_INPUT
;
504 IMFSample_CopyAllItems(transform
->sample
, (IMFAttributes
*)buffers
->pSample
);
506 if (SUCCEEDED(IMFSample_GetSampleDuration(transform
->sample
, &time
)))
507 IMFSample_SetSampleDuration(buffers
->pSample
, time
);
509 if (SUCCEEDED(IMFSample_GetSampleTime(transform
->sample
, &time
)))
510 IMFSample_SetSampleTime(buffers
->pSample
, time
);
512 if (SUCCEEDED(IMFSample_GetSampleFlags(transform
->sample
, &sample_flags
)))
513 IMFSample_SetSampleFlags(buffers
->pSample
, sample_flags
);
515 if (SUCCEEDED(IMFSample_ConvertToContiguousBuffer(transform
->sample
, NULL
)))
517 if (SUCCEEDED(IMFSample_GetBufferByIndex(buffers
->pSample
, 0, &buffer
)))
519 if (FAILED(IMFSample_CopyToBuffer(transform
->sample
, buffer
)))
520 hr
= MF_E_UNEXPECTED
;
521 IMFMediaBuffer_Release(buffer
);
525 IMFSample_Release(transform
->sample
);
526 transform
->sample
= NULL
;
528 LeaveCriticalSection(&transform
->cs
);
533 static const IMFTransformVtbl sample_copier_transform_vtbl
=
535 sample_copier_transform_QueryInterface
,
536 sample_copier_transform_AddRef
,
537 sample_copier_transform_Release
,
538 sample_copier_transform_GetStreamLimits
,
539 sample_copier_transform_GetStreamCount
,
540 sample_copier_transform_GetStreamIDs
,
541 sample_copier_transform_GetInputStreamInfo
,
542 sample_copier_transform_GetOutputStreamInfo
,
543 sample_copier_transform_GetAttributes
,
544 sample_copier_transform_GetInputStreamAttributes
,
545 sample_copier_transform_GetOutputStreamAttributes
,
546 sample_copier_transform_DeleteInputStream
,
547 sample_copier_transform_AddInputStreams
,
548 sample_copier_transform_GetInputAvailableType
,
549 sample_copier_transform_GetOutputAvailableType
,
550 sample_copier_transform_SetInputType
,
551 sample_copier_transform_SetOutputType
,
552 sample_copier_transform_GetInputCurrentType
,
553 sample_copier_transform_GetOutputCurrentType
,
554 sample_copier_transform_GetInputStatus
,
555 sample_copier_transform_GetOutputStatus
,
556 sample_copier_transform_SetOutputBounds
,
557 sample_copier_transform_ProcessEvent
,
558 sample_copier_transform_ProcessMessage
,
559 sample_copier_transform_ProcessInput
,
560 sample_copier_transform_ProcessOutput
,
563 BOOL
mf_is_sample_copier_transform(IMFTransform
*transform
)
565 return transform
->lpVtbl
== &sample_copier_transform_vtbl
;
568 /***********************************************************************
569 * MFCreateSampleCopierMFT (mf.@)
571 HRESULT WINAPI
MFCreateSampleCopierMFT(IMFTransform
**transform
)
573 struct sample_copier
*object
;
576 TRACE("%p.\n", transform
);
578 if (!(object
= calloc(1, sizeof(*object
))))
579 return E_OUTOFMEMORY
;
581 object
->IMFTransform_iface
.lpVtbl
= &sample_copier_transform_vtbl
;
582 object
->refcount
= 1;
583 InitializeCriticalSection(&object
->cs
);
585 if (FAILED(hr
= MFCreateAttributes(&object
->attributes
, 0)))
588 IMFAttributes_SetUINT32(object
->attributes
, &MFT_SUPPORT_DYNAMIC_FORMAT_CHANGE
, 1);
590 *transform
= &object
->IMFTransform_iface
;
596 IMFTransform_Release(&object
->IMFTransform_iface
);