blob: 3c50a6c074ec965a9ae8ca2f27a0764c15765b87 [file] [log] [blame]
wm4050b72a2017-04-04 05:45:411/*
2 * This file is part of FFmpeg.
3 *
4 * FFmpeg 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.
8 *
9 * FFmpeg 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.
13 *
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with FFmpeg; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17 */
18
19#define COBJMACROS
20#if !defined(_WIN32_WINNT) || _WIN32_WINNT < 0x0602
21#undef _WIN32_WINNT
22#define _WIN32_WINNT 0x0602
23#endif
24
James Almer827d6fe2020-06-09 21:31:3225#include "encode.h"
wm4050b72a2017-04-04 05:45:4126#include "mf_utils.h"
27#include "libavutil/imgutils.h"
28#include "libavutil/opt.h"
29#include "libavutil/time.h"
Andreas Rheinhardta688f3c2022-03-16 17:18:2830#include "codec_internal.h"
Martin Storsjö869f6552020-05-25 10:18:0331#include "internal.h"
Martin Storsjö9fba0b82022-05-25 21:31:0532#include "compat/w32dlfcn.h"
wm4050b72a2017-04-04 05:45:4133
34typedef struct MFContext {
35 AVClass *av_class;
Trystan Mata1cb601a2022-05-25 10:54:0136 HMODULE library;
37 MFFunctions functions;
James Almer827d6fe2020-06-09 21:31:3238 AVFrame *frame;
wm4050b72a2017-04-04 05:45:4139 int is_video, is_audio;
40 GUID main_subtype;
41 IMFTransform *mft;
42 IMFMediaEventGenerator *async_events;
43 DWORD in_stream_id, out_stream_id;
44 MFT_INPUT_STREAM_INFO in_info;
45 MFT_OUTPUT_STREAM_INFO out_info;
46 int out_stream_provides_samples;
47 int draining, draining_done;
48 int sample_sent;
49 int async_need_input, async_have_output, async_marker;
50 int64_t reorder_delay;
51 ICodecAPI *codec_api;
52 // set by AVOption
53 int opt_enc_rc;
54 int opt_enc_quality;
55 int opt_enc_scenario;
56 int opt_enc_hw;
57} MFContext;
58
59static int mf_choose_output_type(AVCodecContext *avctx);
60static int mf_setup_context(AVCodecContext *avctx);
61
62#define MF_TIMEBASE (AVRational){1, 10000000}
63// Sentinel value only used by us.
64#define MF_INVALID_TIME AV_NOPTS_VALUE
65
66static int mf_wait_events(AVCodecContext *avctx)
67{
68 MFContext *c = avctx->priv_data;
69
70 if (!c->async_events)
71 return 0;
72
73 while (!(c->async_need_input || c->async_have_output || c->draining_done || c->async_marker)) {
74 IMFMediaEvent *ev = NULL;
75 MediaEventType ev_id = 0;
76 HRESULT hr = IMFMediaEventGenerator_GetEvent(c->async_events, 0, &ev);
77 if (FAILED(hr)) {
78 av_log(avctx, AV_LOG_ERROR, "IMFMediaEventGenerator_GetEvent() failed: %s\n",
79 ff_hr_str(hr));
80 return AVERROR_EXTERNAL;
81 }
82 IMFMediaEvent_GetType(ev, &ev_id);
83 switch (ev_id) {
84 case ff_METransformNeedInput:
85 if (!c->draining)
86 c->async_need_input = 1;
87 break;
88 case ff_METransformHaveOutput:
89 c->async_have_output = 1;
90 break;
91 case ff_METransformDrainComplete:
92 c->draining_done = 1;
93 break;
94 case ff_METransformMarker:
95 c->async_marker = 1;
96 break;
97 default: ;
98 }
99 IMFMediaEvent_Release(ev);
100 }
101
102 return 0;
103}
104
105static AVRational mf_get_tb(AVCodecContext *avctx)
106{
wm4050b72a2017-04-04 05:45:41107 if (avctx->time_base.num > 0 && avctx->time_base.den > 0)
108 return avctx->time_base;
109 return MF_TIMEBASE;
110}
111
112static LONGLONG mf_to_mf_time(AVCodecContext *avctx, int64_t av_pts)
113{
114 if (av_pts == AV_NOPTS_VALUE)
115 return MF_INVALID_TIME;
116 return av_rescale_q(av_pts, mf_get_tb(avctx), MF_TIMEBASE);
117}
118
119static void mf_sample_set_pts(AVCodecContext *avctx, IMFSample *sample, int64_t av_pts)
120{
121 LONGLONG stime = mf_to_mf_time(avctx, av_pts);
122 if (stime != MF_INVALID_TIME)
123 IMFSample_SetSampleTime(sample, stime);
124}
125
126static int64_t mf_from_mf_time(AVCodecContext *avctx, LONGLONG stime)
127{
128 return av_rescale_q(stime, MF_TIMEBASE, mf_get_tb(avctx));
129}
130
131static int64_t mf_sample_get_pts(AVCodecContext *avctx, IMFSample *sample)
132{
133 LONGLONG pts;
134 HRESULT hr = IMFSample_GetSampleTime(sample, &pts);
135 if (FAILED(hr))
136 return AV_NOPTS_VALUE;
137 return mf_from_mf_time(avctx, pts);
138}
139
140static int mf_enca_output_type_get(AVCodecContext *avctx, IMFMediaType *type)
141{
142 MFContext *c = avctx->priv_data;
143 HRESULT hr;
144 UINT32 sz;
145
146 if (avctx->codec_id != AV_CODEC_ID_MP3 && avctx->codec_id != AV_CODEC_ID_AC3) {
147 hr = IMFAttributes_GetBlobSize(type, &MF_MT_USER_DATA, &sz);
148 if (!FAILED(hr) && sz > 0) {
149 avctx->extradata = av_mallocz(sz + AV_INPUT_BUFFER_PADDING_SIZE);
150 if (!avctx->extradata)
151 return AVERROR(ENOMEM);
152 avctx->extradata_size = sz;
153 hr = IMFAttributes_GetBlob(type, &MF_MT_USER_DATA, avctx->extradata, sz, NULL);
154 if (FAILED(hr))
155 return AVERROR_EXTERNAL;
156
157 if (avctx->codec_id == AV_CODEC_ID_AAC && avctx->extradata_size >= 12) {
158 // Get rid of HEAACWAVEINFO (after wfx field, 12 bytes).
159 avctx->extradata_size = avctx->extradata_size - 12;
160 memmove(avctx->extradata, avctx->extradata + 12, avctx->extradata_size);
161 }
162 }
163 }
164
165 // I don't know where it's documented that we need this. It happens with the
166 // MS mp3 encoder MFT. The idea for the workaround is taken from NAudio.
167 // (Certainly any lossy codec will have frames much smaller than 1 second.)
168 if (!c->out_info.cbSize && !c->out_stream_provides_samples) {
169 hr = IMFAttributes_GetUINT32(type, &MF_MT_AUDIO_AVG_BYTES_PER_SECOND, &sz);
170 if (!FAILED(hr)) {
171 av_log(avctx, AV_LOG_VERBOSE, "MFT_OUTPUT_STREAM_INFO.cbSize set to 0, "
172 "assuming %d bytes instead.\n", (int)sz);
173 c->out_info.cbSize = sz;
174 }
175 }
176
177 return 0;
178}
179
180static int mf_encv_output_type_get(AVCodecContext *avctx, IMFMediaType *type)
181{
182 HRESULT hr;
183 UINT32 sz;
184
185 hr = IMFAttributes_GetBlobSize(type, &MF_MT_MPEG_SEQUENCE_HEADER, &sz);
186 if (!FAILED(hr) && sz > 0) {
187 uint8_t *extradata = av_mallocz(sz + AV_INPUT_BUFFER_PADDING_SIZE);
188 if (!extradata)
189 return AVERROR(ENOMEM);
190 hr = IMFAttributes_GetBlob(type, &MF_MT_MPEG_SEQUENCE_HEADER, extradata, sz, NULL);
191 if (FAILED(hr)) {
192 av_free(extradata);
193 return AVERROR_EXTERNAL;
194 }
195 av_freep(&avctx->extradata);
196 avctx->extradata = extradata;
197 avctx->extradata_size = sz;
198 }
199
200 return 0;
201}
202
203static int mf_output_type_get(AVCodecContext *avctx)
204{
205 MFContext *c = avctx->priv_data;
206 HRESULT hr;
207 IMFMediaType *type;
208 int ret;
209
210 hr = IMFTransform_GetOutputCurrentType(c->mft, c->out_stream_id, &type);
211 if (FAILED(hr)) {
212 av_log(avctx, AV_LOG_ERROR, "could not get output type\n");
213 return AVERROR_EXTERNAL;
214 }
215
216 av_log(avctx, AV_LOG_VERBOSE, "final output type:\n");
217 ff_media_type_dump(avctx, type);
218
219 ret = 0;
220 if (c->is_video) {
221 ret = mf_encv_output_type_get(avctx, type);
222 } else if (c->is_audio) {
223 ret = mf_enca_output_type_get(avctx, type);
224 }
225
226 if (ret < 0)
227 av_log(avctx, AV_LOG_ERROR, "output type not supported\n");
228
229 IMFMediaType_Release(type);
230 return ret;
231}
232
233static int mf_sample_to_avpacket(AVCodecContext *avctx, IMFSample *sample, AVPacket *avpkt)
234{
235 MFContext *c = avctx->priv_data;
236 HRESULT hr;
237 int ret;
238 DWORD len;
239 IMFMediaBuffer *buffer;
240 BYTE *data;
241 UINT64 t;
242 UINT32 t32;
243
244 hr = IMFSample_GetTotalLength(sample, &len);
245 if (FAILED(hr))
246 return AVERROR_EXTERNAL;
247
James Almerb86af932021-03-13 00:07:42248 if ((ret = ff_get_encode_buffer(avctx, avpkt, len, 0)) < 0)
wm4050b72a2017-04-04 05:45:41249 return ret;
250
251 IMFSample_ConvertToContiguousBuffer(sample, &buffer);
252 if (FAILED(hr))
253 return AVERROR_EXTERNAL;
254
255 hr = IMFMediaBuffer_Lock(buffer, &data, NULL, NULL);
256 if (FAILED(hr)) {
257 IMFMediaBuffer_Release(buffer);
258 return AVERROR_EXTERNAL;
259 }
260
261 memcpy(avpkt->data, data, len);
262
263 IMFMediaBuffer_Unlock(buffer);
264 IMFMediaBuffer_Release(buffer);
265
266 avpkt->pts = avpkt->dts = mf_sample_get_pts(avctx, sample);
267
268 hr = IMFAttributes_GetUINT32(sample, &MFSampleExtension_CleanPoint, &t32);
269 if (c->is_audio || (!FAILED(hr) && t32 != 0))
270 avpkt->flags |= AV_PKT_FLAG_KEY;
271
272 hr = IMFAttributes_GetUINT64(sample, &MFSampleExtension_DecodeTimestamp, &t);
273 if (!FAILED(hr)) {
274 avpkt->dts = mf_from_mf_time(avctx, t);
275 // At least on Qualcomm's HEVC encoder on SD 835, the output dts
276 // starts from the input pts of the first frame, while the output pts
277 // is shifted forward. Therefore, shift the output values back so that
278 // the output pts matches the input.
279 if (c->reorder_delay == AV_NOPTS_VALUE)
280 c->reorder_delay = avpkt->pts - avpkt->dts;
281 avpkt->dts -= c->reorder_delay;
282 avpkt->pts -= c->reorder_delay;
283 }
284
285 return 0;
286}
287
288static IMFSample *mf_a_avframe_to_sample(AVCodecContext *avctx, const AVFrame *frame)
289{
290 MFContext *c = avctx->priv_data;
291 size_t len;
292 size_t bps;
293 IMFSample *sample;
294
James Almer6d8b2582021-08-25 13:37:54295 bps = av_get_bytes_per_sample(avctx->sample_fmt) * avctx->ch_layout.nb_channels;
wm4050b72a2017-04-04 05:45:41296 len = frame->nb_samples * bps;
297
Trystan Mata1cb601a2022-05-25 10:54:01298 sample = ff_create_memory_sample(&c->functions, frame->data[0], len,
299 c->in_info.cbAlignment);
wm4050b72a2017-04-04 05:45:41300 if (sample)
301 IMFSample_SetSampleDuration(sample, mf_to_mf_time(avctx, frame->nb_samples));
302 return sample;
303}
304
305static IMFSample *mf_v_avframe_to_sample(AVCodecContext *avctx, const AVFrame *frame)
306{
307 MFContext *c = avctx->priv_data;
308 IMFSample *sample;
309 IMFMediaBuffer *buffer;
310 BYTE *data;
311 HRESULT hr;
312 int ret;
313 int size;
314
315 size = av_image_get_buffer_size(avctx->pix_fmt, avctx->width, avctx->height, 1);
316 if (size < 0)
317 return NULL;
318
Trystan Mata1cb601a2022-05-25 10:54:01319 sample = ff_create_memory_sample(&c->functions, NULL, size,
320 c->in_info.cbAlignment);
wm4050b72a2017-04-04 05:45:41321 if (!sample)
322 return NULL;
323
324 hr = IMFSample_GetBufferByIndex(sample, 0, &buffer);
325 if (FAILED(hr)) {
326 IMFSample_Release(sample);
327 return NULL;
328 }
329
330 hr = IMFMediaBuffer_Lock(buffer, &data, NULL, NULL);
331 if (FAILED(hr)) {
332 IMFMediaBuffer_Release(buffer);
333 IMFSample_Release(sample);
334 return NULL;
335 }
336
337 ret = av_image_copy_to_buffer((uint8_t *)data, size, (void *)frame->data, frame->linesize,
338 avctx->pix_fmt, avctx->width, avctx->height, 1);
339 IMFMediaBuffer_SetCurrentLength(buffer, size);
340 IMFMediaBuffer_Unlock(buffer);
341 IMFMediaBuffer_Release(buffer);
342 if (ret < 0) {
343 IMFSample_Release(sample);
344 return NULL;
345 }
346
Anton Khirnovac2cda42022-07-11 08:20:12347 IMFSample_SetSampleDuration(sample, mf_to_mf_time(avctx, frame->duration));
wm4050b72a2017-04-04 05:45:41348
349 return sample;
350}
351
352static IMFSample *mf_avframe_to_sample(AVCodecContext *avctx, const AVFrame *frame)
353{
354 MFContext *c = avctx->priv_data;
355 IMFSample *sample;
356
357 if (c->is_audio) {
358 sample = mf_a_avframe_to_sample(avctx, frame);
359 } else {
360 sample = mf_v_avframe_to_sample(avctx, frame);
361 }
362
363 if (sample)
364 mf_sample_set_pts(avctx, sample, frame->pts);
365
366 return sample;
367}
368
369static int mf_send_sample(AVCodecContext *avctx, IMFSample *sample)
370{
371 MFContext *c = avctx->priv_data;
372 HRESULT hr;
373 int ret;
374
375 if (sample) {
376 if (c->async_events) {
377 if ((ret = mf_wait_events(avctx)) < 0)
378 return ret;
379 if (!c->async_need_input)
380 return AVERROR(EAGAIN);
381 }
382 if (!c->sample_sent)
383 IMFSample_SetUINT32(sample, &MFSampleExtension_Discontinuity, TRUE);
384 c->sample_sent = 1;
385 hr = IMFTransform_ProcessInput(c->mft, c->in_stream_id, sample, 0);
386 if (hr == MF_E_NOTACCEPTING) {
387 return AVERROR(EAGAIN);
388 } else if (FAILED(hr)) {
389 av_log(avctx, AV_LOG_ERROR, "failed processing input: %s\n", ff_hr_str(hr));
390 return AVERROR_EXTERNAL;
391 }
392 c->async_need_input = 0;
393 } else if (!c->draining) {
394 hr = IMFTransform_ProcessMessage(c->mft, MFT_MESSAGE_COMMAND_DRAIN, 0);
395 if (FAILED(hr))
396 av_log(avctx, AV_LOG_ERROR, "failed draining: %s\n", ff_hr_str(hr));
397 // Some MFTs (AC3) will send a frame after each drain command (???), so
398 // this is required to make draining actually terminate.
399 c->draining = 1;
400 c->async_need_input = 0;
401 } else {
402 return AVERROR_EOF;
403 }
404 return 0;
405}
406
wm4050b72a2017-04-04 05:45:41407static int mf_receive_sample(AVCodecContext *avctx, IMFSample **out_sample)
408{
409 MFContext *c = avctx->priv_data;
410 HRESULT hr;
411 DWORD st;
412 MFT_OUTPUT_DATA_BUFFER out_buffers;
413 IMFSample *sample;
414 int ret = 0;
415
416 while (1) {
417 *out_sample = NULL;
418 sample = NULL;
419
420 if (c->async_events) {
421 if ((ret = mf_wait_events(avctx)) < 0)
422 return ret;
423 if (!c->async_have_output || c->draining_done) {
424 ret = 0;
425 break;
426 }
427 }
428
429 if (!c->out_stream_provides_samples) {
Trystan Mata1cb601a2022-05-25 10:54:01430 sample = ff_create_memory_sample(&c->functions, NULL,
431 c->out_info.cbSize,
432 c->out_info.cbAlignment);
wm4050b72a2017-04-04 05:45:41433 if (!sample)
434 return AVERROR(ENOMEM);
435 }
436
437 out_buffers = (MFT_OUTPUT_DATA_BUFFER) {
438 .dwStreamID = c->out_stream_id,
439 .pSample = sample,
440 };
441
442 st = 0;
443 hr = IMFTransform_ProcessOutput(c->mft, 0, 1, &out_buffers, &st);
444
445 if (out_buffers.pEvents)
446 IMFCollection_Release(out_buffers.pEvents);
447
448 if (!FAILED(hr)) {
449 *out_sample = out_buffers.pSample;
450 ret = 0;
451 break;
452 }
453
454 if (out_buffers.pSample)
455 IMFSample_Release(out_buffers.pSample);
456
457 if (hr == MF_E_TRANSFORM_NEED_MORE_INPUT) {
458 if (c->draining)
459 c->draining_done = 1;
460 ret = 0;
461 } else if (hr == MF_E_TRANSFORM_STREAM_CHANGE) {
462 av_log(avctx, AV_LOG_WARNING, "stream format change\n");
463 ret = mf_choose_output_type(avctx);
464 if (ret == 0) // we don't expect renegotiating the input type
465 ret = AVERROR_EXTERNAL;
466 if (ret > 0) {
467 ret = mf_setup_context(avctx);
468 if (ret >= 0) {
469 c->async_have_output = 0;
470 continue;
471 }
472 }
473 } else {
474 av_log(avctx, AV_LOG_ERROR, "failed processing output: %s\n", ff_hr_str(hr));
475 ret = AVERROR_EXTERNAL;
476 }
477
478 break;
479 }
480
481 c->async_have_output = 0;
482
483 if (ret >= 0 && !*out_sample)
484 ret = c->draining_done ? AVERROR_EOF : AVERROR(EAGAIN);
485
486 return ret;
487}
488
489static int mf_receive_packet(AVCodecContext *avctx, AVPacket *avpkt)
490{
James Almer827d6fe2020-06-09 21:31:32491 MFContext *c = avctx->priv_data;
492 IMFSample *sample = NULL;
wm4050b72a2017-04-04 05:45:41493 int ret;
494
James Almer827d6fe2020-06-09 21:31:32495 if (!c->frame->buf[0]) {
496 ret = ff_encode_get_frame(avctx, c->frame);
497 if (ret < 0 && ret != AVERROR_EOF)
498 return ret;
499 }
500
501 if (c->frame->buf[0]) {
502 sample = mf_avframe_to_sample(avctx, c->frame);
503 if (!sample) {
504 av_frame_unref(c->frame);
505 return AVERROR(ENOMEM);
506 }
507 if (c->is_video && c->codec_api) {
508 if (c->frame->pict_type == AV_PICTURE_TYPE_I || !c->sample_sent)
509 ICodecAPI_SetValue(c->codec_api, &ff_CODECAPI_AVEncVideoForceKeyFrame, FF_VAL_VT_UI4(1));
510 }
511 }
512
513 ret = mf_send_sample(avctx, sample);
514 if (sample)
515 IMFSample_Release(sample);
516 if (ret != AVERROR(EAGAIN))
517 av_frame_unref(c->frame);
518 if (ret < 0 && ret != AVERROR(EAGAIN) && ret != AVERROR_EOF)
519 return ret;
520
wm4050b72a2017-04-04 05:45:41521 ret = mf_receive_sample(avctx, &sample);
522 if (ret < 0)
523 return ret;
524
525 ret = mf_sample_to_avpacket(avctx, sample, avpkt);
526 IMFSample_Release(sample);
527
528 return ret;
529}
530
531// Most encoders seem to enumerate supported audio formats on the output types,
532// at least as far as channel configuration and sample rate is concerned. Pick
533// the one which seems to match best.
534static int64_t mf_enca_output_score(AVCodecContext *avctx, IMFMediaType *type)
535{
536 MFContext *c = avctx->priv_data;
537 HRESULT hr;
538 UINT32 t;
539 GUID tg;
540 int64_t score = 0;
541
542 hr = IMFAttributes_GetUINT32(type, &MF_MT_AUDIO_SAMPLES_PER_SECOND, &t);
543 if (!FAILED(hr) && t == avctx->sample_rate)
544 score |= 1LL << 32;
545
546 hr = IMFAttributes_GetUINT32(type, &MF_MT_AUDIO_NUM_CHANNELS, &t);
James Almer6d8b2582021-08-25 13:37:54547 if (!FAILED(hr) && t == avctx->ch_layout.nb_channels)
wm4050b72a2017-04-04 05:45:41548 score |= 2LL << 32;
549
550 hr = IMFAttributes_GetGUID(type, &MF_MT_SUBTYPE, &tg);
551 if (!FAILED(hr)) {
552 if (IsEqualGUID(&c->main_subtype, &tg))
553 score |= 4LL << 32;
554 }
555
556 // Select the bitrate (lowest priority).
557 hr = IMFAttributes_GetUINT32(type, &MF_MT_AUDIO_AVG_BYTES_PER_SECOND, &t);
558 if (!FAILED(hr)) {
559 int diff = (int)t - avctx->bit_rate / 8;
560 if (diff >= 0) {
561 score |= (1LL << 31) - diff; // prefer lower bitrate
562 } else {
563 score |= (1LL << 30) + diff; // prefer higher bitrate
564 }
565 }
566
567 hr = IMFAttributes_GetUINT32(type, &MF_MT_AAC_PAYLOAD_TYPE, &t);
568 if (!FAILED(hr) && t != 0)
569 return -1;
570
571 return score;
572}
573
574static int mf_enca_output_adjust(AVCodecContext *avctx, IMFMediaType *type)
575{
576 // (some decoders allow adjusting this freely, but it can also cause failure
577 // to set the output type - so it's commented for being too fragile)
578 //IMFAttributes_SetUINT32(type, &MF_MT_AUDIO_AVG_BYTES_PER_SECOND, avctx->bit_rate / 8);
579 //IMFAttributes_SetUINT32(type, &MF_MT_AVG_BITRATE, avctx->bit_rate);
580
581 return 0;
582}
583
584static int64_t mf_enca_input_score(AVCodecContext *avctx, IMFMediaType *type)
585{
586 HRESULT hr;
587 UINT32 t;
588 int64_t score = 0;
589
590 enum AVSampleFormat sformat = ff_media_type_to_sample_fmt((IMFAttributes *)type);
591 if (sformat == AV_SAMPLE_FMT_NONE)
592 return -1; // can not use
593
594 if (sformat == avctx->sample_fmt)
595 score |= 1;
596
597 hr = IMFAttributes_GetUINT32(type, &MF_MT_AUDIO_SAMPLES_PER_SECOND, &t);
598 if (!FAILED(hr) && t == avctx->sample_rate)
599 score |= 2;
600
601 hr = IMFAttributes_GetUINT32(type, &MF_MT_AUDIO_NUM_CHANNELS, &t);
James Almer6d8b2582021-08-25 13:37:54602 if (!FAILED(hr) && t == avctx->ch_layout.nb_channels)
wm4050b72a2017-04-04 05:45:41603 score |= 4;
604
605 return score;
606}
607
608static int mf_enca_input_adjust(AVCodecContext *avctx, IMFMediaType *type)
609{
610 HRESULT hr;
611 UINT32 t;
612
613 enum AVSampleFormat sformat = ff_media_type_to_sample_fmt((IMFAttributes *)type);
614 if (sformat != avctx->sample_fmt) {
615 av_log(avctx, AV_LOG_ERROR, "unsupported input sample format set\n");
616 return AVERROR(EINVAL);
617 }
618
619 hr = IMFAttributes_GetUINT32(type, &MF_MT_AUDIO_SAMPLES_PER_SECOND, &t);
620 if (FAILED(hr) || t != avctx->sample_rate) {
621 av_log(avctx, AV_LOG_ERROR, "unsupported input sample rate set\n");
622 return AVERROR(EINVAL);
623 }
624
625 hr = IMFAttributes_GetUINT32(type, &MF_MT_AUDIO_NUM_CHANNELS, &t);
James Almer6d8b2582021-08-25 13:37:54626 if (FAILED(hr) || t != avctx->ch_layout.nb_channels) {
wm4050b72a2017-04-04 05:45:41627 av_log(avctx, AV_LOG_ERROR, "unsupported input channel number set\n");
628 return AVERROR(EINVAL);
629 }
630
631 return 0;
632}
633
634static int64_t mf_encv_output_score(AVCodecContext *avctx, IMFMediaType *type)
635{
636 MFContext *c = avctx->priv_data;
637 GUID tg;
638 HRESULT hr;
639 int score = -1;
640
641 hr = IMFAttributes_GetGUID(type, &MF_MT_SUBTYPE, &tg);
642 if (!FAILED(hr)) {
643 if (IsEqualGUID(&c->main_subtype, &tg))
644 score = 1;
645 }
646
647 return score;
648}
649
650static int mf_encv_output_adjust(AVCodecContext *avctx, IMFMediaType *type)
651{
652 MFContext *c = avctx->priv_data;
Martin Storsjöc116c122020-05-20 20:08:17653 AVRational framerate;
wm4050b72a2017-04-04 05:45:41654
655 ff_MFSetAttributeSize((IMFAttributes *)type, &MF_MT_FRAME_SIZE, avctx->width, avctx->height);
656 IMFAttributes_SetUINT32(type, &MF_MT_INTERLACE_MODE, MFVideoInterlace_Progressive);
657
Martin Storsjöc116c122020-05-20 20:08:17658 if (avctx->framerate.num > 0 && avctx->framerate.den > 0) {
659 framerate = avctx->framerate;
660 } else {
661 framerate = av_inv_q(avctx->time_base);
Anton Khirnov7d1d61c2023-05-04 09:50:48662#if FF_API_TICKS_PER_FRAME
663FF_DISABLE_DEPRECATION_WARNINGS
Martin Storsjöc116c122020-05-20 20:08:17664 framerate.den *= avctx->ticks_per_frame;
Anton Khirnov7d1d61c2023-05-04 09:50:48665FF_ENABLE_DEPRECATION_WARNINGS
666#endif
Martin Storsjöc116c122020-05-20 20:08:17667 }
668
669 ff_MFSetAttributeRatio((IMFAttributes *)type, &MF_MT_FRAME_RATE, framerate.num, framerate.den);
wm4050b72a2017-04-04 05:45:41670
671 // (MS HEVC supports eAVEncH265VProfile_Main_420_8 only.)
672 if (avctx->codec_id == AV_CODEC_ID_H264) {
Martin Storsjö6c33a232020-05-25 10:26:04673 UINT32 profile = ff_eAVEncH264VProfile_Base;
wm4050b72a2017-04-04 05:45:41674 switch (avctx->profile) {
Andreas Rheinhardt8238bc02023-09-02 12:57:41675 case AV_PROFILE_H264_MAIN:
Martin Storsjö6c33a232020-05-25 10:26:04676 profile = ff_eAVEncH264VProfile_Main;
wm4050b72a2017-04-04 05:45:41677 break;
Andreas Rheinhardt8238bc02023-09-02 12:57:41678 case AV_PROFILE_H264_HIGH:
Martin Storsjö6c33a232020-05-25 10:26:04679 profile = ff_eAVEncH264VProfile_High;
wm4050b72a2017-04-04 05:45:41680 break;
681 }
682 IMFAttributes_SetUINT32(type, &MF_MT_MPEG2_PROFILE, profile);
683 }
684
685 IMFAttributes_SetUINT32(type, &MF_MT_AVG_BITRATE, avctx->bit_rate);
686
687 // Note that some of the ICodecAPI options must be set before SetOutputType.
688 if (c->codec_api) {
689 if (avctx->bit_rate)
690 ICodecAPI_SetValue(c->codec_api, &ff_CODECAPI_AVEncCommonMeanBitRate, FF_VAL_VT_UI4(avctx->bit_rate));
691
692 if (c->opt_enc_rc >= 0)
693 ICodecAPI_SetValue(c->codec_api, &ff_CODECAPI_AVEncCommonRateControlMode, FF_VAL_VT_UI4(c->opt_enc_rc));
694
695 if (c->opt_enc_quality >= 0)
696 ICodecAPI_SetValue(c->codec_api, &ff_CODECAPI_AVEncCommonQuality, FF_VAL_VT_UI4(c->opt_enc_quality));
697
698 // Always set the number of b-frames. Qualcomm's HEVC encoder on SD835
699 // defaults this to 1, and that setting is buggy with many of the
700 // rate control modes. (0 or 2 b-frames works fine with most rate
701 // control modes, but 2 seems buggy with the u_vbr mode.) Setting
702 // "scenario" to "camera_record" sets it in CFR mode (where the default
703 // is VFR), which makes the encoder avoid dropping frames.
704 ICodecAPI_SetValue(c->codec_api, &ff_CODECAPI_AVEncMPVDefaultBPictureCount, FF_VAL_VT_UI4(avctx->max_b_frames));
Martin Storsjöfea5f5b2020-05-20 21:11:47705 avctx->has_b_frames = avctx->max_b_frames > 0;
wm4050b72a2017-04-04 05:45:41706
707 ICodecAPI_SetValue(c->codec_api, &ff_CODECAPI_AVEncH264CABACEnable, FF_VAL_VT_BOOL(1));
708
709 if (c->opt_enc_scenario >= 0)
710 ICodecAPI_SetValue(c->codec_api, &ff_CODECAPI_AVScenarioInfo, FF_VAL_VT_UI4(c->opt_enc_scenario));
711 }
712
713 return 0;
714}
715
716static int64_t mf_encv_input_score(AVCodecContext *avctx, IMFMediaType *type)
717{
718 enum AVPixelFormat pix_fmt = ff_media_type_to_pix_fmt((IMFAttributes *)type);
719 if (pix_fmt != avctx->pix_fmt)
720 return -1; // can not use
721
722 return 0;
723}
724
725static int mf_encv_input_adjust(AVCodecContext *avctx, IMFMediaType *type)
726{
727 enum AVPixelFormat pix_fmt = ff_media_type_to_pix_fmt((IMFAttributes *)type);
728 if (pix_fmt != avctx->pix_fmt) {
729 av_log(avctx, AV_LOG_ERROR, "unsupported input pixel format set\n");
730 return AVERROR(EINVAL);
731 }
732
733 //ff_MFSetAttributeSize((IMFAttributes *)type, &MF_MT_FRAME_SIZE, avctx->width, avctx->height);
734
735 return 0;
736}
737
738static int mf_choose_output_type(AVCodecContext *avctx)
739{
740 MFContext *c = avctx->priv_data;
741 HRESULT hr;
742 int ret;
743 IMFMediaType *out_type = NULL;
744 int64_t out_type_score = -1;
745 int out_type_index = -1;
746 int n;
747
748 av_log(avctx, AV_LOG_VERBOSE, "output types:\n");
749 for (n = 0; ; n++) {
750 IMFMediaType *type;
751 int64_t score = -1;
752
753 hr = IMFTransform_GetOutputAvailableType(c->mft, c->out_stream_id, n, &type);
754 if (hr == MF_E_NO_MORE_TYPES || hr == E_NOTIMPL)
755 break;
756 if (hr == MF_E_TRANSFORM_TYPE_NOT_SET) {
757 av_log(avctx, AV_LOG_VERBOSE, "(need to set input type)\n");
758 ret = 0;
759 goto done;
760 }
761 if (FAILED(hr)) {
762 av_log(avctx, AV_LOG_ERROR, "error getting output type: %s\n", ff_hr_str(hr));
763 ret = AVERROR_EXTERNAL;
764 goto done;
765 }
766
767 av_log(avctx, AV_LOG_VERBOSE, "output type %d:\n", n);
768 ff_media_type_dump(avctx, type);
769
770 if (c->is_video) {
771 score = mf_encv_output_score(avctx, type);
772 } else if (c->is_audio) {
773 score = mf_enca_output_score(avctx, type);
774 }
775
776 if (score > out_type_score) {
777 if (out_type)
778 IMFMediaType_Release(out_type);
779 out_type = type;
780 out_type_score = score;
781 out_type_index = n;
782 IMFMediaType_AddRef(out_type);
783 }
784
785 IMFMediaType_Release(type);
786 }
787
788 if (out_type) {
789 av_log(avctx, AV_LOG_VERBOSE, "picking output type %d.\n", out_type_index);
790 } else {
Trystan Mata1cb601a2022-05-25 10:54:01791 hr = c->functions.MFCreateMediaType(&out_type);
wm4050b72a2017-04-04 05:45:41792 if (FAILED(hr)) {
793 ret = AVERROR(ENOMEM);
794 goto done;
795 }
796 }
797
798 ret = 0;
799 if (c->is_video) {
800 ret = mf_encv_output_adjust(avctx, out_type);
801 } else if (c->is_audio) {
802 ret = mf_enca_output_adjust(avctx, out_type);
803 }
804
805 if (ret >= 0) {
806 av_log(avctx, AV_LOG_VERBOSE, "setting output type:\n");
807 ff_media_type_dump(avctx, out_type);
808
809 hr = IMFTransform_SetOutputType(c->mft, c->out_stream_id, out_type, 0);
810 if (!FAILED(hr)) {
811 ret = 1;
812 } else if (hr == MF_E_TRANSFORM_TYPE_NOT_SET) {
813 av_log(avctx, AV_LOG_VERBOSE, "rejected - need to set input type\n");
814 ret = 0;
815 } else {
816 av_log(avctx, AV_LOG_ERROR, "could not set output type (%s)\n", ff_hr_str(hr));
817 ret = AVERROR_EXTERNAL;
818 }
819 }
820
821done:
822 if (out_type)
823 IMFMediaType_Release(out_type);
824 return ret;
825}
826
827static int mf_choose_input_type(AVCodecContext *avctx)
828{
829 MFContext *c = avctx->priv_data;
830 HRESULT hr;
831 int ret;
832 IMFMediaType *in_type = NULL;
833 int64_t in_type_score = -1;
834 int in_type_index = -1;
835 int n;
836
837 av_log(avctx, AV_LOG_VERBOSE, "input types:\n");
838 for (n = 0; ; n++) {
839 IMFMediaType *type = NULL;
840 int64_t score = -1;
841
842 hr = IMFTransform_GetInputAvailableType(c->mft, c->in_stream_id, n, &type);
843 if (hr == MF_E_NO_MORE_TYPES || hr == E_NOTIMPL)
844 break;
845 if (hr == MF_E_TRANSFORM_TYPE_NOT_SET) {
846 av_log(avctx, AV_LOG_VERBOSE, "(need to set output type 1)\n");
847 ret = 0;
848 goto done;
849 }
850 if (FAILED(hr)) {
851 av_log(avctx, AV_LOG_ERROR, "error getting input type: %s\n", ff_hr_str(hr));
852 ret = AVERROR_EXTERNAL;
853 goto done;
854 }
855
856 av_log(avctx, AV_LOG_VERBOSE, "input type %d:\n", n);
857 ff_media_type_dump(avctx, type);
858
859 if (c->is_video) {
860 score = mf_encv_input_score(avctx, type);
861 } else if (c->is_audio) {
862 score = mf_enca_input_score(avctx, type);
863 }
864
865 if (score > in_type_score) {
866 if (in_type)
867 IMFMediaType_Release(in_type);
868 in_type = type;
869 in_type_score = score;
870 in_type_index = n;
871 IMFMediaType_AddRef(in_type);
872 }
873
874 IMFMediaType_Release(type);
875 }
876
877 if (in_type) {
878 av_log(avctx, AV_LOG_VERBOSE, "picking input type %d.\n", in_type_index);
879 } else {
880 // Some buggy MFTs (WMA encoder) fail to return MF_E_TRANSFORM_TYPE_NOT_SET.
881 av_log(avctx, AV_LOG_VERBOSE, "(need to set output type 2)\n");
882 ret = 0;
883 goto done;
884 }
885
886 ret = 0;
887 if (c->is_video) {
888 ret = mf_encv_input_adjust(avctx, in_type);
889 } else if (c->is_audio) {
890 ret = mf_enca_input_adjust(avctx, in_type);
891 }
892
893 if (ret >= 0) {
894 av_log(avctx, AV_LOG_VERBOSE, "setting input type:\n");
895 ff_media_type_dump(avctx, in_type);
896
897 hr = IMFTransform_SetInputType(c->mft, c->in_stream_id, in_type, 0);
898 if (!FAILED(hr)) {
899 ret = 1;
900 } else if (hr == MF_E_TRANSFORM_TYPE_NOT_SET) {
901 av_log(avctx, AV_LOG_VERBOSE, "rejected - need to set output type\n");
902 ret = 0;
903 } else {
904 av_log(avctx, AV_LOG_ERROR, "could not set input type (%s)\n", ff_hr_str(hr));
905 ret = AVERROR_EXTERNAL;
906 }
907 }
908
909done:
910 if (in_type)
911 IMFMediaType_Release(in_type);
912 return ret;
913}
914
915static int mf_negotiate_types(AVCodecContext *avctx)
916{
917 // This follows steps 1-5 on:
918 // https://msdn.microsoft.com/en-us/library/windows/desktop/aa965264(v=vs.85).aspx
919 // If every MFT implementer does this correctly, this loop should at worst
920 // be repeated once.
921 int need_input = 1, need_output = 1;
922 int n;
923 for (n = 0; n < 2 && (need_input || need_output); n++) {
924 int ret;
925 ret = mf_choose_input_type(avctx);
926 if (ret < 0)
927 return ret;
928 need_input = ret < 1;
929 ret = mf_choose_output_type(avctx);
930 if (ret < 0)
931 return ret;
932 need_output = ret < 1;
933 }
934 if (need_input || need_output) {
935 av_log(avctx, AV_LOG_ERROR, "format negotiation failed (%d/%d)\n",
936 need_input, need_output);
937 return AVERROR_EXTERNAL;
938 }
939 return 0;
940}
941
942static int mf_setup_context(AVCodecContext *avctx)
943{
944 MFContext *c = avctx->priv_data;
945 HRESULT hr;
946 int ret;
947
948 hr = IMFTransform_GetInputStreamInfo(c->mft, c->in_stream_id, &c->in_info);
949 if (FAILED(hr))
950 return AVERROR_EXTERNAL;
951 av_log(avctx, AV_LOG_VERBOSE, "in_info: size=%d, align=%d\n",
952 (int)c->in_info.cbSize, (int)c->in_info.cbAlignment);
953
954 hr = IMFTransform_GetOutputStreamInfo(c->mft, c->out_stream_id, &c->out_info);
955 if (FAILED(hr))
956 return AVERROR_EXTERNAL;
957 c->out_stream_provides_samples =
958 (c->out_info.dwFlags & MFT_OUTPUT_STREAM_PROVIDES_SAMPLES) ||
959 (c->out_info.dwFlags & MFT_OUTPUT_STREAM_CAN_PROVIDE_SAMPLES);
960 av_log(avctx, AV_LOG_VERBOSE, "out_info: size=%d, align=%d%s\n",
961 (int)c->out_info.cbSize, (int)c->out_info.cbAlignment,
962 c->out_stream_provides_samples ? " (provides samples)" : "");
963
964 if ((ret = mf_output_type_get(avctx)) < 0)
965 return ret;
966
967 return 0;
968}
969
970static int mf_unlock_async(AVCodecContext *avctx)
971{
972 MFContext *c = avctx->priv_data;
973 HRESULT hr;
974 IMFAttributes *attrs;
975 UINT32 v;
976 int res = AVERROR_EXTERNAL;
977
978 // For hw encoding we unfortunately need to use async mode, otherwise
979 // play it safe and avoid it.
980 if (!(c->is_video && c->opt_enc_hw))
981 return 0;
982
983 hr = IMFTransform_GetAttributes(c->mft, &attrs);
984 if (FAILED(hr)) {
985 av_log(avctx, AV_LOG_ERROR, "error retrieving MFT attributes: %s\n", ff_hr_str(hr));
986 goto err;
987 }
988
989 hr = IMFAttributes_GetUINT32(attrs, &MF_TRANSFORM_ASYNC, &v);
990 if (FAILED(hr)) {
991 av_log(avctx, AV_LOG_ERROR, "error querying async: %s\n", ff_hr_str(hr));
992 goto err;
993 }
994
995 if (!v) {
996 av_log(avctx, AV_LOG_ERROR, "hardware MFT is not async\n");
997 goto err;
998 }
999
1000 hr = IMFAttributes_SetUINT32(attrs, &MF_TRANSFORM_ASYNC_UNLOCK, TRUE);
1001 if (FAILED(hr)) {
1002 av_log(avctx, AV_LOG_ERROR, "could not set async unlock: %s\n", ff_hr_str(hr));
1003 goto err;
1004 }
1005
1006 hr = IMFTransform_QueryInterface(c->mft, &IID_IMFMediaEventGenerator, (void **)&c->async_events);
1007 if (FAILED(hr)) {
1008 av_log(avctx, AV_LOG_ERROR, "could not get async interface\n");
1009 goto err;
1010 }
1011
1012 res = 0;
1013
1014err:
1015 IMFAttributes_Release(attrs);
1016 return res;
1017}
1018
Trystan Mata1cb601a2022-05-25 10:54:011019static int mf_create(void *log, MFFunctions *f, IMFTransform **mft,
1020 const AVCodec *codec, int use_hw)
wm4050b72a2017-04-04 05:45:411021{
1022 int is_audio = codec->type == AVMEDIA_TYPE_AUDIO;
1023 const CLSID *subtype = ff_codec_to_mf_subtype(codec->id);
1024 MFT_REGISTER_TYPE_INFO reg = {0};
1025 GUID category;
1026 int ret;
1027
1028 *mft = NULL;
1029
1030 if (!subtype)
1031 return AVERROR(ENOSYS);
1032
1033 reg.guidSubtype = *subtype;
1034
1035 if (is_audio) {
1036 reg.guidMajorType = MFMediaType_Audio;
1037 category = MFT_CATEGORY_AUDIO_ENCODER;
1038 } else {
1039 reg.guidMajorType = MFMediaType_Video;
1040 category = MFT_CATEGORY_VIDEO_ENCODER;
1041 }
1042
Trystan Mata1cb601a2022-05-25 10:54:011043 if ((ret = ff_instantiate_mf(log, f, category, NULL, &reg, use_hw, mft)) < 0)
wm4050b72a2017-04-04 05:45:411044 return ret;
1045
1046 return 0;
1047}
1048
Trystan Mata1cb601a2022-05-25 10:54:011049static int mf_init_encoder(AVCodecContext *avctx)
wm4050b72a2017-04-04 05:45:411050{
1051 MFContext *c = avctx->priv_data;
1052 HRESULT hr;
1053 int ret;
1054 const CLSID *subtype = ff_codec_to_mf_subtype(avctx->codec_id);
1055 int use_hw = 0;
1056
James Almer827d6fe2020-06-09 21:31:321057 c->frame = av_frame_alloc();
1058 if (!c->frame)
1059 return AVERROR(ENOMEM);
1060
wm4050b72a2017-04-04 05:45:411061 c->is_audio = avctx->codec_type == AVMEDIA_TYPE_AUDIO;
1062 c->is_video = !c->is_audio;
1063 c->reorder_delay = AV_NOPTS_VALUE;
1064
1065 if (c->is_video && c->opt_enc_hw)
1066 use_hw = 1;
1067
1068 if (!subtype)
1069 return AVERROR(ENOSYS);
1070
1071 c->main_subtype = *subtype;
1072
Trystan Mata1cb601a2022-05-25 10:54:011073 if ((ret = mf_create(avctx, &c->functions, &c->mft, avctx->codec, use_hw)) < 0)
wm4050b72a2017-04-04 05:45:411074 return ret;
1075
1076 if ((ret = mf_unlock_async(avctx)) < 0)
1077 return ret;
1078
1079 hr = IMFTransform_QueryInterface(c->mft, &IID_ICodecAPI, (void **)&c->codec_api);
1080 if (!FAILED(hr))
1081 av_log(avctx, AV_LOG_VERBOSE, "MFT supports ICodecAPI.\n");
1082
1083
1084 hr = IMFTransform_GetStreamIDs(c->mft, 1, &c->in_stream_id, 1, &c->out_stream_id);
1085 if (hr == E_NOTIMPL) {
1086 c->in_stream_id = c->out_stream_id = 0;
1087 } else if (FAILED(hr)) {
1088 av_log(avctx, AV_LOG_ERROR, "could not get stream IDs (%s)\n", ff_hr_str(hr));
1089 return AVERROR_EXTERNAL;
1090 }
1091
1092 if ((ret = mf_negotiate_types(avctx)) < 0)
1093 return ret;
1094
1095 if ((ret = mf_setup_context(avctx)) < 0)
1096 return ret;
1097
1098 hr = IMFTransform_ProcessMessage(c->mft, MFT_MESSAGE_NOTIFY_BEGIN_STREAMING, 0);
1099 if (FAILED(hr)) {
1100 av_log(avctx, AV_LOG_ERROR, "could not start streaming (%s)\n", ff_hr_str(hr));
1101 return AVERROR_EXTERNAL;
1102 }
1103
1104 hr = IMFTransform_ProcessMessage(c->mft, MFT_MESSAGE_NOTIFY_START_OF_STREAM, 0);
1105 if (FAILED(hr)) {
1106 av_log(avctx, AV_LOG_ERROR, "could not start stream (%s)\n", ff_hr_str(hr));
1107 return AVERROR_EXTERNAL;
1108 }
1109
1110 if (avctx->flags & AV_CODEC_FLAG_GLOBAL_HEADER && c->async_events &&
1111 c->is_video && !avctx->extradata) {
1112 int sleep = 10000, total = 0;
1113 av_log(avctx, AV_LOG_VERBOSE, "Awaiting extradata\n");
1114 while (total < 70*1000) {
1115 // The Qualcomm H264 encoder on SD835 doesn't provide extradata
1116 // immediately, but it becomes available soon after init (without
1117 // any waitable event). In practice, it's available after less
1118 // than 10 ms, but wait for up to 70 ms before giving up.
1119 // Some encoders (Qualcomm's HEVC encoder on SD835, some versions
1120 // of the QSV H264 encoder at least) don't provide extradata this
1121 // way at all, not even after encoding a frame - it's only
1122 // available prepended to frames.
1123 av_usleep(sleep);
1124 total += sleep;
1125 mf_output_type_get(avctx);
1126 if (avctx->extradata)
1127 break;
1128 sleep *= 2;
1129 }
1130 av_log(avctx, AV_LOG_VERBOSE, "%s extradata in %d ms\n",
1131 avctx->extradata ? "Got" : "Didn't get", total / 1000);
1132 }
1133
1134 return 0;
1135}
1136
Trystan Mata1cb601a2022-05-25 10:54:011137#if !HAVE_UWP
1138#define LOAD_MF_FUNCTION(context, func_name) \
Martin Storsjö9fba0b82022-05-25 21:31:051139 context->functions.func_name = (void *)dlsym(context->library, #func_name); \
Trystan Mata1cb601a2022-05-25 10:54:011140 if (!context->functions.func_name) { \
1141 av_log(context, AV_LOG_ERROR, "DLL mfplat.dll failed to find function "\
1142 #func_name "\n"); \
1143 return AVERROR_UNKNOWN; \
1144 }
1145#else
1146// In UWP (which lacks LoadLibrary), just link directly against
1147// the functions - this requires building with new/complete enough
1148// import libraries.
1149#define LOAD_MF_FUNCTION(context, func_name) \
1150 context->functions.func_name = func_name; \
1151 if (!context->functions.func_name) { \
1152 av_log(context, AV_LOG_ERROR, "Failed to find function " #func_name \
1153 "\n"); \
1154 return AVERROR_UNKNOWN; \
1155 }
1156#endif
1157
1158// Windows N editions does not provide MediaFoundation by default.
1159// So to avoid DLL loading error, MediaFoundation is dynamically loaded except
1160// on UWP build since LoadLibrary is not available on it.
1161static int mf_load_library(AVCodecContext *avctx)
1162{
1163 MFContext *c = avctx->priv_data;
1164
1165#if !HAVE_UWP
Martin Storsjö9fba0b82022-05-25 21:31:051166 c->library = dlopen("mfplat.dll", 0);
Trystan Mata1cb601a2022-05-25 10:54:011167
1168 if (!c->library) {
1169 av_log(c, AV_LOG_ERROR, "DLL mfplat.dll failed to open\n");
1170 return AVERROR_UNKNOWN;
1171 }
1172#endif
1173
1174 LOAD_MF_FUNCTION(c, MFStartup);
1175 LOAD_MF_FUNCTION(c, MFShutdown);
1176 LOAD_MF_FUNCTION(c, MFCreateAlignedMemoryBuffer);
1177 LOAD_MF_FUNCTION(c, MFCreateSample);
1178 LOAD_MF_FUNCTION(c, MFCreateMediaType);
1179 // MFTEnumEx is missing in Windows Vista's mfplat.dll.
1180 LOAD_MF_FUNCTION(c, MFTEnumEx);
1181
1182 return 0;
1183}
1184
wm4050b72a2017-04-04 05:45:411185static int mf_close(AVCodecContext *avctx)
1186{
1187 MFContext *c = avctx->priv_data;
1188
1189 if (c->codec_api)
1190 ICodecAPI_Release(c->codec_api);
1191
1192 if (c->async_events)
1193 IMFMediaEventGenerator_Release(c->async_events);
1194
Trystan Mata1cb601a2022-05-25 10:54:011195#if !HAVE_UWP
1196 if (c->library)
1197 ff_free_mf(&c->functions, &c->mft);
1198
Martin Storsjö9fba0b82022-05-25 21:31:051199 dlclose(c->library);
Trystan Mata1cb601a2022-05-25 10:54:011200 c->library = NULL;
1201#else
1202 ff_free_mf(&c->functions, &c->mft);
1203#endif
wm4050b72a2017-04-04 05:45:411204
James Almer827d6fe2020-06-09 21:31:321205 av_frame_free(&c->frame);
1206
wm4050b72a2017-04-04 05:45:411207 av_freep(&avctx->extradata);
1208 avctx->extradata_size = 0;
1209
1210 return 0;
1211}
1212
Trystan Mata1cb601a2022-05-25 10:54:011213static int mf_init(AVCodecContext *avctx)
1214{
1215 int ret;
1216 if ((ret = mf_load_library(avctx)) == 0) {
1217 if ((ret = mf_init_encoder(avctx)) == 0) {
1218 return 0;
1219 }
1220 }
Trystan Mata1cb601a2022-05-25 10:54:011221 return ret;
1222}
1223
wm4050b72a2017-04-04 05:45:411224#define OFFSET(x) offsetof(MFContext, x)
1225
Gyan Doshi56419422022-06-17 05:42:051226#define MF_ENCODER(MEDIATYPE, NAME, ID, OPTS, FMTS, CAPS) \
wm4050b72a2017-04-04 05:45:411227 static const AVClass ff_ ## NAME ## _mf_encoder_class = { \
1228 .class_name = #NAME "_mf", \
1229 .item_name = av_default_item_name, \
1230 .option = OPTS, \
1231 .version = LIBAVUTIL_VERSION_INT, \
1232 }; \
Andreas Rheinhardt20f97272022-03-16 20:09:541233 const FFCodec ff_ ## NAME ## _mf_encoder = { \
1234 .p.priv_class = &ff_ ## NAME ## _mf_encoder_class, \
1235 .p.name = #NAME "_mf", \
Andreas Rheinhardt48286d42022-08-29 11:38:021236 CODEC_LONG_NAME(#ID " via MediaFoundation"), \
Andreas Rheinhardt20f97272022-03-16 20:09:541237 .p.type = AVMEDIA_TYPE_ ## MEDIATYPE, \
1238 .p.id = AV_CODEC_ID_ ## ID, \
wm4050b72a2017-04-04 05:45:411239 .priv_data_size = sizeof(MFContext), \
1240 .init = mf_init, \
1241 .close = mf_close, \
Andreas Rheinhardt4243da42022-03-30 21:28:241242 FF_CODEC_RECEIVE_PACKET_CB(mf_receive_packet), \
Gyan Doshi56419422022-06-17 05:42:051243 FMTS \
1244 CAPS \
Andreas Rheinhardt21b23ce2022-07-09 22:05:451245 .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, \
wm4050b72a2017-04-04 05:45:411246 };
1247
1248#define AFMTS \
Andreas Rheinhardt20f97272022-03-16 20:09:541249 .p.sample_fmts = (const enum AVSampleFormat[]){ AV_SAMPLE_FMT_S16, \
wm4050b72a2017-04-04 05:45:411250 AV_SAMPLE_FMT_NONE },
Gyan Doshi56419422022-06-17 05:42:051251#define ACAPS \
1252 .p.capabilities = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_HYBRID | \
1253 AV_CODEC_CAP_DR1 | AV_CODEC_CAP_VARIABLE_FRAME_SIZE,
wm4050b72a2017-04-04 05:45:411254
Gyan Doshi56419422022-06-17 05:42:051255MF_ENCODER(AUDIO, aac, AAC, NULL, AFMTS, ACAPS);
1256MF_ENCODER(AUDIO, ac3, AC3, NULL, AFMTS, ACAPS);
1257MF_ENCODER(AUDIO, mp3, MP3, NULL, AFMTS, ACAPS);
wm4050b72a2017-04-04 05:45:411258
1259#define VE AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_ENCODING_PARAM
1260static const AVOption venc_opts[] = {
1261 {"rate_control", "Select rate control mode", OFFSET(opt_enc_rc), AV_OPT_TYPE_INT, {.i64 = -1}, -1, INT_MAX, VE, "rate_control"},
1262 { "default", "Default mode", 0, AV_OPT_TYPE_CONST, {.i64 = -1}, 0, 0, VE, "rate_control"},
1263 { "cbr", "CBR mode", 0, AV_OPT_TYPE_CONST, {.i64 = ff_eAVEncCommonRateControlMode_CBR}, 0, 0, VE, "rate_control"},
1264 { "pc_vbr", "Peak constrained VBR mode", 0, AV_OPT_TYPE_CONST, {.i64 = ff_eAVEncCommonRateControlMode_PeakConstrainedVBR}, 0, 0, VE, "rate_control"},
1265 { "u_vbr", "Unconstrained VBR mode", 0, AV_OPT_TYPE_CONST, {.i64 = ff_eAVEncCommonRateControlMode_UnconstrainedVBR}, 0, 0, VE, "rate_control"},
1266 { "quality", "Quality mode", 0, AV_OPT_TYPE_CONST, {.i64 = ff_eAVEncCommonRateControlMode_Quality}, 0, 0, VE, "rate_control" },
1267 // The following rate_control modes require Windows 8.
1268 { "ld_vbr", "Low delay VBR mode", 0, AV_OPT_TYPE_CONST, {.i64 = ff_eAVEncCommonRateControlMode_LowDelayVBR}, 0, 0, VE, "rate_control"},
1269 { "g_vbr", "Global VBR mode", 0, AV_OPT_TYPE_CONST, {.i64 = ff_eAVEncCommonRateControlMode_GlobalVBR}, 0, 0, VE, "rate_control" },
1270 { "gld_vbr", "Global low delay VBR mode", 0, AV_OPT_TYPE_CONST, {.i64 = ff_eAVEncCommonRateControlMode_GlobalLowDelayVBR}, 0, 0, VE, "rate_control"},
1271
1272 {"scenario", "Select usage scenario", OFFSET(opt_enc_scenario), AV_OPT_TYPE_INT, {.i64 = -1}, -1, INT_MAX, VE, "scenario"},
1273 { "default", "Default scenario", 0, AV_OPT_TYPE_CONST, {.i64 = -1}, 0, 0, VE, "scenario"},
1274 { "display_remoting", "Display remoting", 0, AV_OPT_TYPE_CONST, {.i64 = ff_eAVScenarioInfo_DisplayRemoting}, 0, 0, VE, "scenario"},
1275 { "video_conference", "Video conference", 0, AV_OPT_TYPE_CONST, {.i64 = ff_eAVScenarioInfo_VideoConference}, 0, 0, VE, "scenario"},
1276 { "archive", "Archive", 0, AV_OPT_TYPE_CONST, {.i64 = ff_eAVScenarioInfo_Archive}, 0, 0, VE, "scenario"},
1277 { "live_streaming", "Live streaming", 0, AV_OPT_TYPE_CONST, {.i64 = ff_eAVScenarioInfo_LiveStreaming}, 0, 0, VE, "scenario"},
1278 { "camera_record", "Camera record", 0, AV_OPT_TYPE_CONST, {.i64 = ff_eAVScenarioInfo_CameraRecord}, 0, 0, VE, "scenario"},
1279 { "display_remoting_with_feature_map", "Display remoting with feature map", 0, AV_OPT_TYPE_CONST, {.i64 = ff_eAVScenarioInfo_DisplayRemotingWithFeatureMap}, 0, 0, VE, "scenario"},
1280
1281 {"quality", "Quality", OFFSET(opt_enc_quality), AV_OPT_TYPE_INT, {.i64 = -1}, -1, 100, VE},
1282 {"hw_encoding", "Force hardware encoding", OFFSET(opt_enc_hw), AV_OPT_TYPE_BOOL, {.i64 = 0}, 0, 1, VE},
1283 {NULL}
1284};
1285
1286#define VFMTS \
Andreas Rheinhardt20f97272022-03-16 20:09:541287 .p.pix_fmts = (const enum AVPixelFormat[]){ AV_PIX_FMT_NV12, \
wm4050b72a2017-04-04 05:45:411288 AV_PIX_FMT_YUV420P, \
1289 AV_PIX_FMT_NONE },
Gyan Doshi56419422022-06-17 05:42:051290#define VCAPS \
1291 .p.capabilities = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_HYBRID | \
1292 AV_CODEC_CAP_DR1,
wm4050b72a2017-04-04 05:45:411293
Gyan Doshi56419422022-06-17 05:42:051294MF_ENCODER(VIDEO, h264, H264, venc_opts, VFMTS, VCAPS);
1295MF_ENCODER(VIDEO, hevc, HEVC, venc_opts, VFMTS, VCAPS);