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