1cabdff1aSopenharmony_ci/*
2cabdff1aSopenharmony_ci * Directshow capture interface
3cabdff1aSopenharmony_ci * Copyright (c) 2010 Ramiro Polla
4cabdff1aSopenharmony_ci *
5cabdff1aSopenharmony_ci * This file is part of FFmpeg.
6cabdff1aSopenharmony_ci *
7cabdff1aSopenharmony_ci * FFmpeg is free software; you can redistribute it and/or
8cabdff1aSopenharmony_ci * modify it under the terms of the GNU Lesser General Public
9cabdff1aSopenharmony_ci * License as published by the Free Software Foundation; either
10cabdff1aSopenharmony_ci * version 2.1 of the License, or (at your option) any later version.
11cabdff1aSopenharmony_ci *
12cabdff1aSopenharmony_ci * FFmpeg is distributed in the hope that it will be useful,
13cabdff1aSopenharmony_ci * but WITHOUT ANY WARRANTY; without even the implied warranty of
14cabdff1aSopenharmony_ci * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15cabdff1aSopenharmony_ci * Lesser General Public License for more details.
16cabdff1aSopenharmony_ci *
17cabdff1aSopenharmony_ci * You should have received a copy of the GNU Lesser General Public
18cabdff1aSopenharmony_ci * License along with FFmpeg; if not, write to the Free Software
19cabdff1aSopenharmony_ci * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20cabdff1aSopenharmony_ci */
21cabdff1aSopenharmony_ci
22cabdff1aSopenharmony_ci#include "dshow_capture.h"
23cabdff1aSopenharmony_ci#include "libavutil/parseutils.h"
24cabdff1aSopenharmony_ci#include "libavutil/pixdesc.h"
25cabdff1aSopenharmony_ci#include "libavutil/opt.h"
26cabdff1aSopenharmony_ci#include "libavutil/mem.h"
27cabdff1aSopenharmony_ci#include "libavformat/internal.h"
28cabdff1aSopenharmony_ci#include "libavformat/riff.h"
29cabdff1aSopenharmony_ci#include "avdevice.h"
30cabdff1aSopenharmony_ci#include "libavcodec/raw.h"
31cabdff1aSopenharmony_ci#include "objidl.h"
32cabdff1aSopenharmony_ci#include "shlwapi.h"
33cabdff1aSopenharmony_ci// NB: technically, we should include dxva.h and use
34cabdff1aSopenharmony_ci// DXVA_ExtendedFormat, but that type is not defined in
35cabdff1aSopenharmony_ci// the MinGW headers. The DXVA2_ExtendedFormat and the
36cabdff1aSopenharmony_ci// contents of its fields is identical to
37cabdff1aSopenharmony_ci// DXVA_ExtendedFormat (see https://docs.microsoft.com/en-us/windows/win32/medfound/extended-color-information#color-space-in-media-types)
38cabdff1aSopenharmony_ci// and is provided by MinGW as well, so we use that
39cabdff1aSopenharmony_ci// instead. NB also that per the Microsoft docs, the
40cabdff1aSopenharmony_ci// lowest 8 bits of the structure, i.e. the SampleFormat
41cabdff1aSopenharmony_ci// field, contain AMCONTROL_xxx flags instead of sample
42cabdff1aSopenharmony_ci// format information, and should thus not be used.
43cabdff1aSopenharmony_ci// NB further that various values in the structure's
44cabdff1aSopenharmony_ci// fields (e.g. BT.2020 color space) are not provided
45cabdff1aSopenharmony_ci// for either of the DXVA structs, but are provided in
46cabdff1aSopenharmony_ci// the flags of the corresponding fields of Media Foundation.
47cabdff1aSopenharmony_ci// These may be provided by DirectShow devices (e.g. LAVFilters
48cabdff1aSopenharmony_ci// does so). So we use those values here too (the equivalence is
49cabdff1aSopenharmony_ci// indicated by Microsoft example code: https://docs.microsoft.com/en-us/windows/win32/api/dxva2api/ns-dxva2api-dxva2_videodesc)
50cabdff1aSopenharmony_ci#include "d3d9types.h"
51cabdff1aSopenharmony_ci#include "dxva2api.h"
52cabdff1aSopenharmony_ci
53cabdff1aSopenharmony_ci#ifndef AMCONTROL_COLORINFO_PRESENT
54cabdff1aSopenharmony_ci// not defined in some versions of MinGW's dvdmedia.h
55cabdff1aSopenharmony_ci#   define AMCONTROL_COLORINFO_PRESENT 0x00000080 // if set, indicates DXVA color info is present in the upper (24) bits of the dwControlFlags
56cabdff1aSopenharmony_ci#endif
57cabdff1aSopenharmony_ci
58cabdff1aSopenharmony_ci
59cabdff1aSopenharmony_cistatic enum AVPixelFormat dshow_pixfmt(DWORD biCompression, WORD biBitCount)
60cabdff1aSopenharmony_ci{
61cabdff1aSopenharmony_ci    switch(biCompression) {
62cabdff1aSopenharmony_ci    case BI_BITFIELDS:
63cabdff1aSopenharmony_ci    case BI_RGB:
64cabdff1aSopenharmony_ci        switch(biBitCount) { /* 1-8 are untested */
65cabdff1aSopenharmony_ci            case 1:
66cabdff1aSopenharmony_ci                return AV_PIX_FMT_MONOWHITE;
67cabdff1aSopenharmony_ci            case 4:
68cabdff1aSopenharmony_ci                return AV_PIX_FMT_RGB4;
69cabdff1aSopenharmony_ci            case 8:
70cabdff1aSopenharmony_ci                return AV_PIX_FMT_RGB8;
71cabdff1aSopenharmony_ci            case 16:
72cabdff1aSopenharmony_ci                return AV_PIX_FMT_RGB555;
73cabdff1aSopenharmony_ci            case 24:
74cabdff1aSopenharmony_ci                return AV_PIX_FMT_BGR24;
75cabdff1aSopenharmony_ci            case 32:
76cabdff1aSopenharmony_ci                return AV_PIX_FMT_0RGB32;
77cabdff1aSopenharmony_ci        }
78cabdff1aSopenharmony_ci    }
79cabdff1aSopenharmony_ci    return avpriv_pix_fmt_find(PIX_FMT_LIST_RAW, biCompression); // all others
80cabdff1aSopenharmony_ci}
81cabdff1aSopenharmony_ci
82cabdff1aSopenharmony_cistatic enum AVColorRange dshow_color_range(DXVA2_ExtendedFormat *fmt_info)
83cabdff1aSopenharmony_ci{
84cabdff1aSopenharmony_ci    switch (fmt_info->NominalRange)
85cabdff1aSopenharmony_ci    {
86cabdff1aSopenharmony_ci    case DXVA2_NominalRange_Unknown:
87cabdff1aSopenharmony_ci        return AVCOL_RANGE_UNSPECIFIED;
88cabdff1aSopenharmony_ci    case DXVA2_NominalRange_Normal: // equal to DXVA2_NominalRange_0_255
89cabdff1aSopenharmony_ci        return AVCOL_RANGE_JPEG;
90cabdff1aSopenharmony_ci    case DXVA2_NominalRange_Wide:   // equal to DXVA2_NominalRange_16_235
91cabdff1aSopenharmony_ci        return AVCOL_RANGE_MPEG;
92cabdff1aSopenharmony_ci    case DXVA2_NominalRange_48_208:
93cabdff1aSopenharmony_ci        // not an ffmpeg color range
94cabdff1aSopenharmony_ci        return AVCOL_RANGE_UNSPECIFIED;
95cabdff1aSopenharmony_ci
96cabdff1aSopenharmony_ci    // values from MediaFoundation SDK (mfobjects.h)
97cabdff1aSopenharmony_ci    case 4:     // MFNominalRange_64_127
98cabdff1aSopenharmony_ci        // not an ffmpeg color range
99cabdff1aSopenharmony_ci        return AVCOL_RANGE_UNSPECIFIED;
100cabdff1aSopenharmony_ci
101cabdff1aSopenharmony_ci    default:
102cabdff1aSopenharmony_ci        return AVCOL_RANGE_UNSPECIFIED;
103cabdff1aSopenharmony_ci    }
104cabdff1aSopenharmony_ci}
105cabdff1aSopenharmony_ci
106cabdff1aSopenharmony_cistatic enum AVColorSpace dshow_color_space(DXVA2_ExtendedFormat *fmt_info)
107cabdff1aSopenharmony_ci{
108cabdff1aSopenharmony_ci    switch (fmt_info->VideoTransferMatrix)
109cabdff1aSopenharmony_ci    {
110cabdff1aSopenharmony_ci    case DXVA2_VideoTransferMatrix_BT709:
111cabdff1aSopenharmony_ci        return AVCOL_SPC_BT709;
112cabdff1aSopenharmony_ci    case DXVA2_VideoTransferMatrix_BT601:
113cabdff1aSopenharmony_ci        return AVCOL_SPC_BT470BG;
114cabdff1aSopenharmony_ci    case DXVA2_VideoTransferMatrix_SMPTE240M:
115cabdff1aSopenharmony_ci        return AVCOL_SPC_SMPTE240M;
116cabdff1aSopenharmony_ci
117cabdff1aSopenharmony_ci    // values from MediaFoundation SDK (mfobjects.h)
118cabdff1aSopenharmony_ci    case 4:     // MFVideoTransferMatrix_BT2020_10
119cabdff1aSopenharmony_ci    case 5:     // MFVideoTransferMatrix_BT2020_12
120cabdff1aSopenharmony_ci        if (fmt_info->VideoTransferFunction == 12)  // MFVideoTransFunc_2020_const
121cabdff1aSopenharmony_ci            return AVCOL_SPC_BT2020_CL;
122cabdff1aSopenharmony_ci        else
123cabdff1aSopenharmony_ci            return AVCOL_SPC_BT2020_NCL;
124cabdff1aSopenharmony_ci
125cabdff1aSopenharmony_ci    default:
126cabdff1aSopenharmony_ci        return AVCOL_SPC_UNSPECIFIED;
127cabdff1aSopenharmony_ci    }
128cabdff1aSopenharmony_ci}
129cabdff1aSopenharmony_ci
130cabdff1aSopenharmony_cistatic enum AVColorPrimaries dshow_color_primaries(DXVA2_ExtendedFormat *fmt_info)
131cabdff1aSopenharmony_ci{
132cabdff1aSopenharmony_ci    switch (fmt_info->VideoPrimaries)
133cabdff1aSopenharmony_ci    {
134cabdff1aSopenharmony_ci    case DXVA2_VideoPrimaries_Unknown:
135cabdff1aSopenharmony_ci        return AVCOL_PRI_UNSPECIFIED;
136cabdff1aSopenharmony_ci    case DXVA2_VideoPrimaries_reserved:
137cabdff1aSopenharmony_ci        return AVCOL_PRI_RESERVED;
138cabdff1aSopenharmony_ci    case DXVA2_VideoPrimaries_BT709:
139cabdff1aSopenharmony_ci        return AVCOL_PRI_BT709;
140cabdff1aSopenharmony_ci    case DXVA2_VideoPrimaries_BT470_2_SysM:
141cabdff1aSopenharmony_ci        return AVCOL_PRI_BT470M;
142cabdff1aSopenharmony_ci    case DXVA2_VideoPrimaries_BT470_2_SysBG:
143cabdff1aSopenharmony_ci    case DXVA2_VideoPrimaries_EBU3213:   // this is PAL
144cabdff1aSopenharmony_ci        return AVCOL_PRI_BT470BG;
145cabdff1aSopenharmony_ci    case DXVA2_VideoPrimaries_SMPTE170M:
146cabdff1aSopenharmony_ci    case DXVA2_VideoPrimaries_SMPTE_C:
147cabdff1aSopenharmony_ci        return AVCOL_PRI_SMPTE170M;
148cabdff1aSopenharmony_ci    case DXVA2_VideoPrimaries_SMPTE240M:
149cabdff1aSopenharmony_ci        return AVCOL_PRI_SMPTE240M;
150cabdff1aSopenharmony_ci
151cabdff1aSopenharmony_ci    // values from MediaFoundation SDK (mfobjects.h)
152cabdff1aSopenharmony_ci    case 9:     // MFVideoPrimaries_BT2020
153cabdff1aSopenharmony_ci        return AVCOL_PRI_BT2020;
154cabdff1aSopenharmony_ci    case 10:    // MFVideoPrimaries_XYZ
155cabdff1aSopenharmony_ci        return AVCOL_PRI_SMPTE428;
156cabdff1aSopenharmony_ci    case 11:    // MFVideoPrimaries_DCI_P3
157cabdff1aSopenharmony_ci        return AVCOL_PRI_SMPTE431;
158cabdff1aSopenharmony_ci    case 12:    // MFVideoPrimaries_ACES (Academy Color Encoding System)
159cabdff1aSopenharmony_ci        // not an FFmpeg color primary
160cabdff1aSopenharmony_ci        return AVCOL_PRI_UNSPECIFIED;
161cabdff1aSopenharmony_ci
162cabdff1aSopenharmony_ci    default:
163cabdff1aSopenharmony_ci        return AVCOL_PRI_UNSPECIFIED;
164cabdff1aSopenharmony_ci    }
165cabdff1aSopenharmony_ci}
166cabdff1aSopenharmony_ci
167cabdff1aSopenharmony_cistatic enum AVColorTransferCharacteristic dshow_color_trc(DXVA2_ExtendedFormat *fmt_info)
168cabdff1aSopenharmony_ci{
169cabdff1aSopenharmony_ci    switch (fmt_info->VideoTransferFunction)
170cabdff1aSopenharmony_ci    {
171cabdff1aSopenharmony_ci    case DXVA2_VideoTransFunc_Unknown:
172cabdff1aSopenharmony_ci        return AVCOL_TRC_UNSPECIFIED;
173cabdff1aSopenharmony_ci    case DXVA2_VideoTransFunc_10:
174cabdff1aSopenharmony_ci        return AVCOL_TRC_LINEAR;
175cabdff1aSopenharmony_ci    case DXVA2_VideoTransFunc_18:
176cabdff1aSopenharmony_ci        // not an FFmpeg transfer characteristic
177cabdff1aSopenharmony_ci        return AVCOL_TRC_UNSPECIFIED;
178cabdff1aSopenharmony_ci    case DXVA2_VideoTransFunc_20:
179cabdff1aSopenharmony_ci        // not an FFmpeg transfer characteristic
180cabdff1aSopenharmony_ci        return AVCOL_TRC_UNSPECIFIED;
181cabdff1aSopenharmony_ci    case DXVA2_VideoTransFunc_22:
182cabdff1aSopenharmony_ci        return AVCOL_TRC_GAMMA22;
183cabdff1aSopenharmony_ci    case DXVA2_VideoTransFunc_709:
184cabdff1aSopenharmony_ci        return AVCOL_TRC_BT709;
185cabdff1aSopenharmony_ci    case DXVA2_VideoTransFunc_240M:
186cabdff1aSopenharmony_ci        return AVCOL_TRC_SMPTE240M;
187cabdff1aSopenharmony_ci    case DXVA2_VideoTransFunc_sRGB:
188cabdff1aSopenharmony_ci        return AVCOL_TRC_IEC61966_2_1;
189cabdff1aSopenharmony_ci    case DXVA2_VideoTransFunc_28:
190cabdff1aSopenharmony_ci        return AVCOL_TRC_GAMMA28;
191cabdff1aSopenharmony_ci
192cabdff1aSopenharmony_ci    // values from MediaFoundation SDK (mfobjects.h)
193cabdff1aSopenharmony_ci    case 9:     // MFVideoTransFunc_Log_100
194cabdff1aSopenharmony_ci        return AVCOL_TRC_LOG;
195cabdff1aSopenharmony_ci    case 10:    // MFVideoTransFunc_Log_316
196cabdff1aSopenharmony_ci        return AVCOL_TRC_LOG_SQRT;
197cabdff1aSopenharmony_ci    case 11:    // MFVideoTransFunc_709_sym
198cabdff1aSopenharmony_ci        // not an FFmpeg transfer characteristic
199cabdff1aSopenharmony_ci        return AVCOL_TRC_UNSPECIFIED;
200cabdff1aSopenharmony_ci    case 12:    // MFVideoTransFunc_2020_const
201cabdff1aSopenharmony_ci    case 13:    // MFVideoTransFunc_2020
202cabdff1aSopenharmony_ci        if (fmt_info->VideoTransferMatrix == 5) // MFVideoTransferMatrix_BT2020_12
203cabdff1aSopenharmony_ci            return AVCOL_TRC_BT2020_12;
204cabdff1aSopenharmony_ci        else
205cabdff1aSopenharmony_ci            return AVCOL_TRC_BT2020_10;
206cabdff1aSopenharmony_ci    case 14:    // MFVideoTransFunc_26
207cabdff1aSopenharmony_ci        // not an FFmpeg transfer characteristic
208cabdff1aSopenharmony_ci        return AVCOL_TRC_UNSPECIFIED;
209cabdff1aSopenharmony_ci    case 15:    // MFVideoTransFunc_2084
210cabdff1aSopenharmony_ci        return AVCOL_TRC_SMPTEST2084;
211cabdff1aSopenharmony_ci    case 16:    // MFVideoTransFunc_HLG
212cabdff1aSopenharmony_ci        return AVCOL_TRC_ARIB_STD_B67;
213cabdff1aSopenharmony_ci    case 17:    // MFVideoTransFunc_10_rel
214cabdff1aSopenharmony_ci        // not an FFmpeg transfer characteristic? Undocumented also by MS
215cabdff1aSopenharmony_ci        return AVCOL_TRC_UNSPECIFIED;
216cabdff1aSopenharmony_ci
217cabdff1aSopenharmony_ci    default:
218cabdff1aSopenharmony_ci        return AVCOL_TRC_UNSPECIFIED;
219cabdff1aSopenharmony_ci    }
220cabdff1aSopenharmony_ci}
221cabdff1aSopenharmony_ci
222cabdff1aSopenharmony_cistatic enum AVChromaLocation dshow_chroma_loc(DXVA2_ExtendedFormat *fmt_info)
223cabdff1aSopenharmony_ci{
224cabdff1aSopenharmony_ci    if (fmt_info->VideoChromaSubsampling == DXVA2_VideoChromaSubsampling_Cosited)       // that is: (DXVA2_VideoChromaSubsampling_Horizontally_Cosited | DXVA2_VideoChromaSubsampling_Vertically_Cosited | DXVA2_VideoChromaSubsampling_Vertically_AlignedChromaPlanes)
225cabdff1aSopenharmony_ci        return AVCHROMA_LOC_TOPLEFT;
226cabdff1aSopenharmony_ci    else if (fmt_info->VideoChromaSubsampling == DXVA2_VideoChromaSubsampling_MPEG1)    // that is: DXVA2_VideoChromaSubsampling_Vertically_AlignedChromaPlanes
227cabdff1aSopenharmony_ci        return AVCHROMA_LOC_CENTER;
228cabdff1aSopenharmony_ci    else if (fmt_info->VideoChromaSubsampling == DXVA2_VideoChromaSubsampling_MPEG2)    // that is: (DXVA2_VideoChromaSubsampling_Horizontally_Cosited | DXVA2_VideoChromaSubsampling_Vertically_AlignedChromaPlanes)
229cabdff1aSopenharmony_ci        return AVCHROMA_LOC_LEFT;
230cabdff1aSopenharmony_ci    else if (fmt_info->VideoChromaSubsampling == DXVA2_VideoChromaSubsampling_DV_PAL)   // that is: (DXVA2_VideoChromaSubsampling_Horizontally_Cosited | DXVA2_VideoChromaSubsampling_Vertically_Cosited)
231cabdff1aSopenharmony_ci        return AVCHROMA_LOC_TOPLEFT;
232cabdff1aSopenharmony_ci    else
233cabdff1aSopenharmony_ci        // unknown
234cabdff1aSopenharmony_ci        return AVCHROMA_LOC_UNSPECIFIED;
235cabdff1aSopenharmony_ci}
236cabdff1aSopenharmony_ci
237cabdff1aSopenharmony_cistatic int
238cabdff1aSopenharmony_cidshow_read_close(AVFormatContext *s)
239cabdff1aSopenharmony_ci{
240cabdff1aSopenharmony_ci    struct dshow_ctx *ctx = s->priv_data;
241cabdff1aSopenharmony_ci    PacketListEntry *pktl;
242cabdff1aSopenharmony_ci
243cabdff1aSopenharmony_ci    if (ctx->control) {
244cabdff1aSopenharmony_ci        IMediaControl_Stop(ctx->control);
245cabdff1aSopenharmony_ci        IMediaControl_Release(ctx->control);
246cabdff1aSopenharmony_ci    }
247cabdff1aSopenharmony_ci
248cabdff1aSopenharmony_ci    if (ctx->media_event)
249cabdff1aSopenharmony_ci        IMediaEvent_Release(ctx->media_event);
250cabdff1aSopenharmony_ci
251cabdff1aSopenharmony_ci    if (ctx->graph) {
252cabdff1aSopenharmony_ci        IEnumFilters *fenum;
253cabdff1aSopenharmony_ci        int r;
254cabdff1aSopenharmony_ci        r = IGraphBuilder_EnumFilters(ctx->graph, &fenum);
255cabdff1aSopenharmony_ci        if (r == S_OK) {
256cabdff1aSopenharmony_ci            IBaseFilter *f;
257cabdff1aSopenharmony_ci            IEnumFilters_Reset(fenum);
258cabdff1aSopenharmony_ci            while (IEnumFilters_Next(fenum, 1, &f, NULL) == S_OK) {
259cabdff1aSopenharmony_ci                if (IGraphBuilder_RemoveFilter(ctx->graph, f) == S_OK)
260cabdff1aSopenharmony_ci                    IEnumFilters_Reset(fenum); /* When a filter is removed,
261cabdff1aSopenharmony_ci                                                * the list must be reset. */
262cabdff1aSopenharmony_ci                IBaseFilter_Release(f);
263cabdff1aSopenharmony_ci            }
264cabdff1aSopenharmony_ci            IEnumFilters_Release(fenum);
265cabdff1aSopenharmony_ci        }
266cabdff1aSopenharmony_ci        IGraphBuilder_Release(ctx->graph);
267cabdff1aSopenharmony_ci    }
268cabdff1aSopenharmony_ci
269cabdff1aSopenharmony_ci    if (ctx->capture_pin[VideoDevice])
270cabdff1aSopenharmony_ci        ff_dshow_pin_Release(ctx->capture_pin[VideoDevice]);
271cabdff1aSopenharmony_ci    if (ctx->capture_pin[AudioDevice])
272cabdff1aSopenharmony_ci        ff_dshow_pin_Release(ctx->capture_pin[AudioDevice]);
273cabdff1aSopenharmony_ci    if (ctx->capture_filter[VideoDevice])
274cabdff1aSopenharmony_ci        ff_dshow_filter_Release(ctx->capture_filter[VideoDevice]);
275cabdff1aSopenharmony_ci    if (ctx->capture_filter[AudioDevice])
276cabdff1aSopenharmony_ci        ff_dshow_filter_Release(ctx->capture_filter[AudioDevice]);
277cabdff1aSopenharmony_ci
278cabdff1aSopenharmony_ci    if (ctx->device_pin[VideoDevice])
279cabdff1aSopenharmony_ci        IPin_Release(ctx->device_pin[VideoDevice]);
280cabdff1aSopenharmony_ci    if (ctx->device_pin[AudioDevice])
281cabdff1aSopenharmony_ci        IPin_Release(ctx->device_pin[AudioDevice]);
282cabdff1aSopenharmony_ci    if (ctx->device_filter[VideoDevice])
283cabdff1aSopenharmony_ci        IBaseFilter_Release(ctx->device_filter[VideoDevice]);
284cabdff1aSopenharmony_ci    if (ctx->device_filter[AudioDevice])
285cabdff1aSopenharmony_ci        IBaseFilter_Release(ctx->device_filter[AudioDevice]);
286cabdff1aSopenharmony_ci
287cabdff1aSopenharmony_ci    av_freep(&ctx->device_name[0]);
288cabdff1aSopenharmony_ci    av_freep(&ctx->device_name[1]);
289cabdff1aSopenharmony_ci    av_freep(&ctx->device_unique_name[0]);
290cabdff1aSopenharmony_ci    av_freep(&ctx->device_unique_name[1]);
291cabdff1aSopenharmony_ci
292cabdff1aSopenharmony_ci    if(ctx->mutex)
293cabdff1aSopenharmony_ci        CloseHandle(ctx->mutex);
294cabdff1aSopenharmony_ci    if(ctx->event[0])
295cabdff1aSopenharmony_ci        CloseHandle(ctx->event[0]);
296cabdff1aSopenharmony_ci    if(ctx->event[1])
297cabdff1aSopenharmony_ci        CloseHandle(ctx->event[1]);
298cabdff1aSopenharmony_ci
299cabdff1aSopenharmony_ci    pktl = ctx->pktl;
300cabdff1aSopenharmony_ci    while (pktl) {
301cabdff1aSopenharmony_ci        PacketListEntry *next = pktl->next;
302cabdff1aSopenharmony_ci        av_packet_unref(&pktl->pkt);
303cabdff1aSopenharmony_ci        av_free(pktl);
304cabdff1aSopenharmony_ci        pktl = next;
305cabdff1aSopenharmony_ci    }
306cabdff1aSopenharmony_ci
307cabdff1aSopenharmony_ci    CoUninitialize();
308cabdff1aSopenharmony_ci
309cabdff1aSopenharmony_ci    return 0;
310cabdff1aSopenharmony_ci}
311cabdff1aSopenharmony_ci
312cabdff1aSopenharmony_cistatic char *dup_wchar_to_utf8(wchar_t *w)
313cabdff1aSopenharmony_ci{
314cabdff1aSopenharmony_ci    char *s = NULL;
315cabdff1aSopenharmony_ci    int l = WideCharToMultiByte(CP_UTF8, 0, w, -1, 0, 0, 0, 0);
316cabdff1aSopenharmony_ci    s = av_malloc(l);
317cabdff1aSopenharmony_ci    if (s)
318cabdff1aSopenharmony_ci        WideCharToMultiByte(CP_UTF8, 0, w, -1, s, l, 0, 0);
319cabdff1aSopenharmony_ci    return s;
320cabdff1aSopenharmony_ci}
321cabdff1aSopenharmony_ci
322cabdff1aSopenharmony_cistatic int shall_we_drop(AVFormatContext *s, int index, enum dshowDeviceType devtype)
323cabdff1aSopenharmony_ci{
324cabdff1aSopenharmony_ci    struct dshow_ctx *ctx = s->priv_data;
325cabdff1aSopenharmony_ci    static const uint8_t dropscore[] = {62, 75, 87, 100};
326cabdff1aSopenharmony_ci    const int ndropscores = FF_ARRAY_ELEMS(dropscore);
327cabdff1aSopenharmony_ci    unsigned int buffer_fullness = (ctx->curbufsize[index]*100)/s->max_picture_buffer;
328cabdff1aSopenharmony_ci    const char *devtypename = (devtype == VideoDevice) ? "video" : "audio";
329cabdff1aSopenharmony_ci
330cabdff1aSopenharmony_ci    if(dropscore[++ctx->video_frame_num%ndropscores] <= buffer_fullness) {
331cabdff1aSopenharmony_ci        av_log(s, AV_LOG_ERROR,
332cabdff1aSopenharmony_ci              "real-time buffer [%s] [%s input] too full or near too full (%d%% of size: %d [rtbufsize parameter])! frame dropped!\n",
333cabdff1aSopenharmony_ci              ctx->device_name[devtype], devtypename, buffer_fullness, s->max_picture_buffer);
334cabdff1aSopenharmony_ci        return 1;
335cabdff1aSopenharmony_ci    }
336cabdff1aSopenharmony_ci
337cabdff1aSopenharmony_ci    return 0;
338cabdff1aSopenharmony_ci}
339cabdff1aSopenharmony_ci
340cabdff1aSopenharmony_cistatic void
341cabdff1aSopenharmony_cicallback(void *priv_data, int index, uint8_t *buf, int buf_size, int64_t time, enum dshowDeviceType devtype)
342cabdff1aSopenharmony_ci{
343cabdff1aSopenharmony_ci    AVFormatContext *s = priv_data;
344cabdff1aSopenharmony_ci    struct dshow_ctx *ctx = s->priv_data;
345cabdff1aSopenharmony_ci    PacketListEntry **ppktl, *pktl_next;
346cabdff1aSopenharmony_ci
347cabdff1aSopenharmony_ci//    dump_videohdr(s, vdhdr);
348cabdff1aSopenharmony_ci
349cabdff1aSopenharmony_ci    WaitForSingleObject(ctx->mutex, INFINITE);
350cabdff1aSopenharmony_ci
351cabdff1aSopenharmony_ci    if(shall_we_drop(s, index, devtype))
352cabdff1aSopenharmony_ci        goto fail;
353cabdff1aSopenharmony_ci
354cabdff1aSopenharmony_ci    pktl_next = av_mallocz(sizeof(*pktl_next));
355cabdff1aSopenharmony_ci    if(!pktl_next)
356cabdff1aSopenharmony_ci        goto fail;
357cabdff1aSopenharmony_ci
358cabdff1aSopenharmony_ci    if(av_new_packet(&pktl_next->pkt, buf_size) < 0) {
359cabdff1aSopenharmony_ci        av_free(pktl_next);
360cabdff1aSopenharmony_ci        goto fail;
361cabdff1aSopenharmony_ci    }
362cabdff1aSopenharmony_ci
363cabdff1aSopenharmony_ci    pktl_next->pkt.stream_index = index;
364cabdff1aSopenharmony_ci    pktl_next->pkt.pts = time;
365cabdff1aSopenharmony_ci    memcpy(pktl_next->pkt.data, buf, buf_size);
366cabdff1aSopenharmony_ci
367cabdff1aSopenharmony_ci    for(ppktl = &ctx->pktl ; *ppktl ; ppktl = &(*ppktl)->next);
368cabdff1aSopenharmony_ci    *ppktl = pktl_next;
369cabdff1aSopenharmony_ci    ctx->curbufsize[index] += buf_size;
370cabdff1aSopenharmony_ci
371cabdff1aSopenharmony_ci    SetEvent(ctx->event[1]);
372cabdff1aSopenharmony_ci    ReleaseMutex(ctx->mutex);
373cabdff1aSopenharmony_ci
374cabdff1aSopenharmony_ci    return;
375cabdff1aSopenharmony_cifail:
376cabdff1aSopenharmony_ci    ReleaseMutex(ctx->mutex);
377cabdff1aSopenharmony_ci    return;
378cabdff1aSopenharmony_ci}
379cabdff1aSopenharmony_ci
380cabdff1aSopenharmony_cistatic void
381cabdff1aSopenharmony_cidshow_get_device_media_types(AVFormatContext *avctx, enum dshowDeviceType devtype,
382cabdff1aSopenharmony_ci                                         enum dshowSourceFilterType sourcetype, IBaseFilter *device_filter,
383cabdff1aSopenharmony_ci                                         enum AVMediaType **media_types, int *nb_media_types)
384cabdff1aSopenharmony_ci{
385cabdff1aSopenharmony_ci    IEnumPins *pins = 0;
386cabdff1aSopenharmony_ci    IPin *pin;
387cabdff1aSopenharmony_ci    int has_audio = 0, has_video = 0;
388cabdff1aSopenharmony_ci
389cabdff1aSopenharmony_ci    if (IBaseFilter_EnumPins(device_filter, &pins) != S_OK)
390cabdff1aSopenharmony_ci        return;
391cabdff1aSopenharmony_ci
392cabdff1aSopenharmony_ci    while (IEnumPins_Next(pins, 1, &pin, NULL) == S_OK) {
393cabdff1aSopenharmony_ci        IKsPropertySet *p = NULL;
394cabdff1aSopenharmony_ci        PIN_INFO info = { 0 };
395cabdff1aSopenharmony_ci        GUID category;
396cabdff1aSopenharmony_ci        DWORD r2;
397cabdff1aSopenharmony_ci        IEnumMediaTypes *types = NULL;
398cabdff1aSopenharmony_ci        AM_MEDIA_TYPE *type;
399cabdff1aSopenharmony_ci
400cabdff1aSopenharmony_ci        if (IPin_QueryPinInfo(pin, &info) != S_OK)
401cabdff1aSopenharmony_ci            goto next;
402cabdff1aSopenharmony_ci        IBaseFilter_Release(info.pFilter);
403cabdff1aSopenharmony_ci
404cabdff1aSopenharmony_ci        if (info.dir != PINDIR_OUTPUT)
405cabdff1aSopenharmony_ci            goto next;
406cabdff1aSopenharmony_ci        if (IPin_QueryInterface(pin, &IID_IKsPropertySet, (void **) &p) != S_OK)
407cabdff1aSopenharmony_ci            goto next;
408cabdff1aSopenharmony_ci        if (IKsPropertySet_Get(p, &AMPROPSETID_Pin, AMPROPERTY_PIN_CATEGORY,
409cabdff1aSopenharmony_ci                               NULL, 0, &category, sizeof(GUID), &r2) != S_OK)
410cabdff1aSopenharmony_ci            goto next;
411cabdff1aSopenharmony_ci        if (!IsEqualGUID(&category, &PIN_CATEGORY_CAPTURE))
412cabdff1aSopenharmony_ci            goto next;
413cabdff1aSopenharmony_ci
414cabdff1aSopenharmony_ci        if (IPin_EnumMediaTypes(pin, &types) != S_OK)
415cabdff1aSopenharmony_ci            goto next;
416cabdff1aSopenharmony_ci
417cabdff1aSopenharmony_ci        // enumerate media types exposed by pin
418cabdff1aSopenharmony_ci        // NB: don't know if a pin can expose both audio and video, check 'm all to be safe
419cabdff1aSopenharmony_ci        IEnumMediaTypes_Reset(types);
420cabdff1aSopenharmony_ci        while (IEnumMediaTypes_Next(types, 1, &type, NULL) == S_OK) {
421cabdff1aSopenharmony_ci            if (IsEqualGUID(&type->majortype, &MEDIATYPE_Video)) {
422cabdff1aSopenharmony_ci                has_video = 1;
423cabdff1aSopenharmony_ci            } else if (IsEqualGUID(&type->majortype, &MEDIATYPE_Audio)) {
424cabdff1aSopenharmony_ci                has_audio = 1;
425cabdff1aSopenharmony_ci            }
426cabdff1aSopenharmony_ci            CoTaskMemFree(type);
427cabdff1aSopenharmony_ci        }
428cabdff1aSopenharmony_ci
429cabdff1aSopenharmony_ci    next:
430cabdff1aSopenharmony_ci        if (types)
431cabdff1aSopenharmony_ci            IEnumMediaTypes_Release(types);
432cabdff1aSopenharmony_ci        if (p)
433cabdff1aSopenharmony_ci            IKsPropertySet_Release(p);
434cabdff1aSopenharmony_ci        if (pin)
435cabdff1aSopenharmony_ci            IPin_Release(pin);
436cabdff1aSopenharmony_ci    }
437cabdff1aSopenharmony_ci
438cabdff1aSopenharmony_ci    IEnumPins_Release(pins);
439cabdff1aSopenharmony_ci
440cabdff1aSopenharmony_ci    if (has_audio || has_video) {
441cabdff1aSopenharmony_ci        int nb_types = has_audio + has_video;
442cabdff1aSopenharmony_ci        *media_types = av_malloc_array(nb_types, sizeof(enum AVMediaType));
443cabdff1aSopenharmony_ci        if (*media_types) {
444cabdff1aSopenharmony_ci            if (has_audio)
445cabdff1aSopenharmony_ci                (*media_types)[0] = AVMEDIA_TYPE_AUDIO;
446cabdff1aSopenharmony_ci            if (has_video)
447cabdff1aSopenharmony_ci                (*media_types)[0 + has_audio] = AVMEDIA_TYPE_VIDEO;
448cabdff1aSopenharmony_ci            *nb_media_types = nb_types;
449cabdff1aSopenharmony_ci        }
450cabdff1aSopenharmony_ci    }
451cabdff1aSopenharmony_ci}
452cabdff1aSopenharmony_ci
453cabdff1aSopenharmony_ci/**
454cabdff1aSopenharmony_ci * Cycle through available devices using the device enumerator devenum,
455cabdff1aSopenharmony_ci * retrieve the device with type specified by devtype and return the
456cabdff1aSopenharmony_ci * pointer to the object found in *pfilter.
457cabdff1aSopenharmony_ci * If pfilter is NULL, list all device names.
458cabdff1aSopenharmony_ci * If device_list is not NULL, populate it with found devices instead of
459cabdff1aSopenharmony_ci * outputting device names to log
460cabdff1aSopenharmony_ci */
461cabdff1aSopenharmony_cistatic int
462cabdff1aSopenharmony_cidshow_cycle_devices(AVFormatContext *avctx, ICreateDevEnum *devenum,
463cabdff1aSopenharmony_ci                    enum dshowDeviceType devtype, enum dshowSourceFilterType sourcetype,
464cabdff1aSopenharmony_ci                    IBaseFilter **pfilter, char **device_unique_name,
465cabdff1aSopenharmony_ci                    AVDeviceInfoList **device_list)
466cabdff1aSopenharmony_ci{
467cabdff1aSopenharmony_ci    struct dshow_ctx *ctx = avctx->priv_data;
468cabdff1aSopenharmony_ci    IBaseFilter *device_filter = NULL;
469cabdff1aSopenharmony_ci    IEnumMoniker *classenum = NULL;
470cabdff1aSopenharmony_ci    IMoniker *m = NULL;
471cabdff1aSopenharmony_ci    const char *device_name = ctx->device_name[devtype];
472cabdff1aSopenharmony_ci    int skip = (devtype == VideoDevice) ? ctx->video_device_number
473cabdff1aSopenharmony_ci                                        : ctx->audio_device_number;
474cabdff1aSopenharmony_ci    int r;
475cabdff1aSopenharmony_ci
476cabdff1aSopenharmony_ci    const GUID *device_guid[2] = { &CLSID_VideoInputDeviceCategory,
477cabdff1aSopenharmony_ci                                   &CLSID_AudioInputDeviceCategory };
478cabdff1aSopenharmony_ci    const char *devtypename = (devtype == VideoDevice) ? "video" : "audio only";
479cabdff1aSopenharmony_ci    const char *sourcetypename = (sourcetype == VideoSourceDevice) ? "video" : "audio";
480cabdff1aSopenharmony_ci
481cabdff1aSopenharmony_ci    r = ICreateDevEnum_CreateClassEnumerator(devenum, device_guid[sourcetype],
482cabdff1aSopenharmony_ci                                             (IEnumMoniker **) &classenum, 0);
483cabdff1aSopenharmony_ci    if (r != S_OK) {
484cabdff1aSopenharmony_ci        av_log(avctx, AV_LOG_ERROR, "Could not enumerate %s devices (or none found).\n",
485cabdff1aSopenharmony_ci               devtypename);
486cabdff1aSopenharmony_ci        return AVERROR(EIO);
487cabdff1aSopenharmony_ci    }
488cabdff1aSopenharmony_ci
489cabdff1aSopenharmony_ci    while (!device_filter && IEnumMoniker_Next(classenum, 1, &m, NULL) == S_OK) {
490cabdff1aSopenharmony_ci        IPropertyBag *bag = NULL;
491cabdff1aSopenharmony_ci        char *friendly_name = NULL;
492cabdff1aSopenharmony_ci        char *unique_name = NULL;
493cabdff1aSopenharmony_ci        VARIANT var;
494cabdff1aSopenharmony_ci        IBindCtx *bind_ctx = NULL;
495cabdff1aSopenharmony_ci        LPOLESTR olestr = NULL;
496cabdff1aSopenharmony_ci        LPMALLOC co_malloc = NULL;
497cabdff1aSopenharmony_ci        AVDeviceInfo *device = NULL;
498cabdff1aSopenharmony_ci        enum AVMediaType *media_types = NULL;
499cabdff1aSopenharmony_ci        int nb_media_types = 0;
500cabdff1aSopenharmony_ci        int i;
501cabdff1aSopenharmony_ci
502cabdff1aSopenharmony_ci        r = CoGetMalloc(1, &co_malloc);
503cabdff1aSopenharmony_ci        if (r != S_OK)
504cabdff1aSopenharmony_ci            goto fail;
505cabdff1aSopenharmony_ci        r = CreateBindCtx(0, &bind_ctx);
506cabdff1aSopenharmony_ci        if (r != S_OK)
507cabdff1aSopenharmony_ci            goto fail;
508cabdff1aSopenharmony_ci        /* GetDisplayname works for both video and audio, DevicePath doesn't */
509cabdff1aSopenharmony_ci        r = IMoniker_GetDisplayName(m, bind_ctx, NULL, &olestr);
510cabdff1aSopenharmony_ci        if (r != S_OK)
511cabdff1aSopenharmony_ci            goto fail;
512cabdff1aSopenharmony_ci        unique_name = dup_wchar_to_utf8(olestr);
513cabdff1aSopenharmony_ci        /* replace ':' with '_' since we use : to delineate between sources */
514cabdff1aSopenharmony_ci        for (i = 0; i < strlen(unique_name); i++) {
515cabdff1aSopenharmony_ci            if (unique_name[i] == ':')
516cabdff1aSopenharmony_ci                unique_name[i] = '_';
517cabdff1aSopenharmony_ci        }
518cabdff1aSopenharmony_ci
519cabdff1aSopenharmony_ci        r = IMoniker_BindToStorage(m, 0, 0, &IID_IPropertyBag, (void *) &bag);
520cabdff1aSopenharmony_ci        if (r != S_OK)
521cabdff1aSopenharmony_ci            goto fail;
522cabdff1aSopenharmony_ci
523cabdff1aSopenharmony_ci        var.vt = VT_BSTR;
524cabdff1aSopenharmony_ci        r = IPropertyBag_Read(bag, L"FriendlyName", &var, NULL);
525cabdff1aSopenharmony_ci        if (r != S_OK)
526cabdff1aSopenharmony_ci            goto fail;
527cabdff1aSopenharmony_ci        friendly_name = dup_wchar_to_utf8(var.bstrVal);
528cabdff1aSopenharmony_ci
529cabdff1aSopenharmony_ci        if (pfilter) {
530cabdff1aSopenharmony_ci            if (strcmp(device_name, friendly_name) && strcmp(device_name, unique_name))
531cabdff1aSopenharmony_ci                goto fail;
532cabdff1aSopenharmony_ci
533cabdff1aSopenharmony_ci            if (!skip--) {
534cabdff1aSopenharmony_ci                r = IMoniker_BindToObject(m, 0, 0, &IID_IBaseFilter, (void *) &device_filter);
535cabdff1aSopenharmony_ci                if (r != S_OK) {
536cabdff1aSopenharmony_ci                    av_log(avctx, AV_LOG_ERROR, "Unable to BindToObject for %s\n", device_name);
537cabdff1aSopenharmony_ci                    goto fail;
538cabdff1aSopenharmony_ci                }
539cabdff1aSopenharmony_ci                *device_unique_name = unique_name;
540cabdff1aSopenharmony_ci                unique_name = NULL;
541cabdff1aSopenharmony_ci                // success, loop will end now
542cabdff1aSopenharmony_ci            }
543cabdff1aSopenharmony_ci        } else {
544cabdff1aSopenharmony_ci            // get media types exposed by pins of device
545cabdff1aSopenharmony_ci            if (IMoniker_BindToObject(m, 0, 0, &IID_IBaseFilter, (void* ) &device_filter) == S_OK) {
546cabdff1aSopenharmony_ci                dshow_get_device_media_types(avctx, devtype, sourcetype, device_filter, &media_types, &nb_media_types);
547cabdff1aSopenharmony_ci                IBaseFilter_Release(device_filter);
548cabdff1aSopenharmony_ci                device_filter = NULL;
549cabdff1aSopenharmony_ci            }
550cabdff1aSopenharmony_ci            if (device_list) {
551cabdff1aSopenharmony_ci                device = av_mallocz(sizeof(AVDeviceInfo));
552cabdff1aSopenharmony_ci                if (!device)
553cabdff1aSopenharmony_ci                    goto fail;
554cabdff1aSopenharmony_ci
555cabdff1aSopenharmony_ci                device->device_name = av_strdup(unique_name);
556cabdff1aSopenharmony_ci                device->device_description = av_strdup(friendly_name);
557cabdff1aSopenharmony_ci                if (!device->device_name || !device->device_description)
558cabdff1aSopenharmony_ci                    goto fail;
559cabdff1aSopenharmony_ci
560cabdff1aSopenharmony_ci                // make space in device_list for this new device
561cabdff1aSopenharmony_ci                if (av_reallocp_array(&(*device_list)->devices,
562cabdff1aSopenharmony_ci                                     (*device_list)->nb_devices + 1,
563cabdff1aSopenharmony_ci                                     sizeof(*(*device_list)->devices)) < 0)
564cabdff1aSopenharmony_ci                    goto fail;
565cabdff1aSopenharmony_ci
566cabdff1aSopenharmony_ci                // attach media_types to device
567cabdff1aSopenharmony_ci                device->nb_media_types = nb_media_types;
568cabdff1aSopenharmony_ci                device->media_types = media_types;
569cabdff1aSopenharmony_ci                nb_media_types = 0;
570cabdff1aSopenharmony_ci                media_types = NULL;
571cabdff1aSopenharmony_ci
572cabdff1aSopenharmony_ci                // store device in list
573cabdff1aSopenharmony_ci                (*device_list)->devices[(*device_list)->nb_devices] = device;
574cabdff1aSopenharmony_ci                (*device_list)->nb_devices++;
575cabdff1aSopenharmony_ci                device = NULL;  // copied into array, make sure not freed below
576cabdff1aSopenharmony_ci            }
577cabdff1aSopenharmony_ci            else {
578cabdff1aSopenharmony_ci                av_log(avctx, AV_LOG_INFO, "\"%s\"", friendly_name);
579cabdff1aSopenharmony_ci                if (nb_media_types > 0) {
580cabdff1aSopenharmony_ci                    const char* media_type = av_get_media_type_string(media_types[0]);
581cabdff1aSopenharmony_ci                    av_log(avctx, AV_LOG_INFO, " (%s", media_type ? media_type : "unknown");
582cabdff1aSopenharmony_ci                    for (int i = 1; i < nb_media_types; ++i) {
583cabdff1aSopenharmony_ci                        media_type = av_get_media_type_string(media_types[i]);
584cabdff1aSopenharmony_ci                        av_log(avctx, AV_LOG_INFO, ", %s", media_type ? media_type : "unknown");
585cabdff1aSopenharmony_ci                    }
586cabdff1aSopenharmony_ci                    av_log(avctx, AV_LOG_INFO, ")");
587cabdff1aSopenharmony_ci                } else {
588cabdff1aSopenharmony_ci                    av_log(avctx, AV_LOG_INFO, " (none)");
589cabdff1aSopenharmony_ci                }
590cabdff1aSopenharmony_ci                av_log(avctx, AV_LOG_INFO, "\n");
591cabdff1aSopenharmony_ci                av_log(avctx, AV_LOG_INFO, "  Alternative name \"%s\"\n", unique_name);
592cabdff1aSopenharmony_ci            }
593cabdff1aSopenharmony_ci        }
594cabdff1aSopenharmony_ci
595cabdff1aSopenharmony_ci    fail:
596cabdff1aSopenharmony_ci        av_freep(&media_types);
597cabdff1aSopenharmony_ci        if (device) {
598cabdff1aSopenharmony_ci            av_freep(&device->device_name);
599cabdff1aSopenharmony_ci            av_freep(&device->device_description);
600cabdff1aSopenharmony_ci            // NB: no need to av_freep(&device->media_types), its only moved to device once nothing can fail anymore
601cabdff1aSopenharmony_ci            av_free(device);
602cabdff1aSopenharmony_ci        }
603cabdff1aSopenharmony_ci        if (olestr && co_malloc)
604cabdff1aSopenharmony_ci            IMalloc_Free(co_malloc, olestr);
605cabdff1aSopenharmony_ci        if (bind_ctx)
606cabdff1aSopenharmony_ci            IBindCtx_Release(bind_ctx);
607cabdff1aSopenharmony_ci        av_freep(&friendly_name);
608cabdff1aSopenharmony_ci        av_freep(&unique_name);
609cabdff1aSopenharmony_ci        if (bag)
610cabdff1aSopenharmony_ci            IPropertyBag_Release(bag);
611cabdff1aSopenharmony_ci        IMoniker_Release(m);
612cabdff1aSopenharmony_ci    }
613cabdff1aSopenharmony_ci
614cabdff1aSopenharmony_ci    IEnumMoniker_Release(classenum);
615cabdff1aSopenharmony_ci
616cabdff1aSopenharmony_ci    if (pfilter) {
617cabdff1aSopenharmony_ci        if (!device_filter) {
618cabdff1aSopenharmony_ci            av_log(avctx, AV_LOG_ERROR, "Could not find %s device with name [%s] among source devices of type %s.\n",
619cabdff1aSopenharmony_ci                   devtypename, device_name, sourcetypename);
620cabdff1aSopenharmony_ci            return AVERROR(EIO);
621cabdff1aSopenharmony_ci        }
622cabdff1aSopenharmony_ci        *pfilter = device_filter;
623cabdff1aSopenharmony_ci    }
624cabdff1aSopenharmony_ci
625cabdff1aSopenharmony_ci    return 0;
626cabdff1aSopenharmony_ci}
627cabdff1aSopenharmony_ci
628cabdff1aSopenharmony_cistatic int dshow_get_device_list(AVFormatContext *avctx, AVDeviceInfoList *device_list)
629cabdff1aSopenharmony_ci{
630cabdff1aSopenharmony_ci    ICreateDevEnum *devenum = NULL;
631cabdff1aSopenharmony_ci    int r;
632cabdff1aSopenharmony_ci    int ret = AVERROR(EIO);
633cabdff1aSopenharmony_ci
634cabdff1aSopenharmony_ci    if (!device_list)
635cabdff1aSopenharmony_ci        return AVERROR(EINVAL);
636cabdff1aSopenharmony_ci
637cabdff1aSopenharmony_ci    CoInitialize(0);
638cabdff1aSopenharmony_ci
639cabdff1aSopenharmony_ci    r = CoCreateInstance(&CLSID_SystemDeviceEnum, NULL, CLSCTX_INPROC_SERVER,
640cabdff1aSopenharmony_ci        &IID_ICreateDevEnum, (void**)&devenum);
641cabdff1aSopenharmony_ci    if (r != S_OK) {
642cabdff1aSopenharmony_ci        av_log(avctx, AV_LOG_ERROR, "Could not enumerate system devices.\n");
643cabdff1aSopenharmony_ci        goto error;
644cabdff1aSopenharmony_ci    }
645cabdff1aSopenharmony_ci
646cabdff1aSopenharmony_ci    ret = dshow_cycle_devices(avctx, devenum, VideoDevice, VideoSourceDevice, NULL, NULL, &device_list);
647cabdff1aSopenharmony_ci    if (ret < S_OK)
648cabdff1aSopenharmony_ci        goto error;
649cabdff1aSopenharmony_ci    ret = dshow_cycle_devices(avctx, devenum, AudioDevice, AudioSourceDevice, NULL, NULL, &device_list);
650cabdff1aSopenharmony_ci
651cabdff1aSopenharmony_cierror:
652cabdff1aSopenharmony_ci    if (devenum)
653cabdff1aSopenharmony_ci        ICreateDevEnum_Release(devenum);
654cabdff1aSopenharmony_ci
655cabdff1aSopenharmony_ci    CoUninitialize();
656cabdff1aSopenharmony_ci
657cabdff1aSopenharmony_ci    return ret;
658cabdff1aSopenharmony_ci}
659cabdff1aSopenharmony_ci
660cabdff1aSopenharmony_cistatic int dshow_should_set_format(AVFormatContext *avctx, enum dshowDeviceType devtype)
661cabdff1aSopenharmony_ci{
662cabdff1aSopenharmony_ci    struct dshow_ctx *ctx = avctx->priv_data;
663cabdff1aSopenharmony_ci
664cabdff1aSopenharmony_ci    return (devtype == VideoDevice && (ctx->framerate ||
665cabdff1aSopenharmony_ci                                      (ctx->requested_width && ctx->requested_height) ||
666cabdff1aSopenharmony_ci                                       ctx->pixel_format != AV_PIX_FMT_NONE ||
667cabdff1aSopenharmony_ci                                       ctx->video_codec_id != AV_CODEC_ID_RAWVIDEO))
668cabdff1aSopenharmony_ci        || (devtype == AudioDevice && (ctx->channels || ctx->sample_size || ctx->sample_rate));
669cabdff1aSopenharmony_ci}
670cabdff1aSopenharmony_ci
671cabdff1aSopenharmony_ci
672cabdff1aSopenharmony_cistruct dshow_format_info {
673cabdff1aSopenharmony_ci    enum dshowDeviceType devtype;
674cabdff1aSopenharmony_ci    // video
675cabdff1aSopenharmony_ci    int64_t framerate;
676cabdff1aSopenharmony_ci    enum AVPixelFormat pix_fmt;
677cabdff1aSopenharmony_ci    enum AVCodecID codec_id;
678cabdff1aSopenharmony_ci    enum AVColorRange col_range;
679cabdff1aSopenharmony_ci    enum AVColorSpace col_space;
680cabdff1aSopenharmony_ci    enum AVColorPrimaries col_prim;
681cabdff1aSopenharmony_ci    enum AVColorTransferCharacteristic col_trc;
682cabdff1aSopenharmony_ci    enum AVChromaLocation chroma_loc;
683cabdff1aSopenharmony_ci    int width;
684cabdff1aSopenharmony_ci    int height;
685cabdff1aSopenharmony_ci    // audio
686cabdff1aSopenharmony_ci    int sample_rate;
687cabdff1aSopenharmony_ci    int sample_size;
688cabdff1aSopenharmony_ci    int channels;
689cabdff1aSopenharmony_ci};
690cabdff1aSopenharmony_ci
691cabdff1aSopenharmony_ci// user must av_free the returned pointer
692cabdff1aSopenharmony_cistatic struct dshow_format_info *dshow_get_format_info(AM_MEDIA_TYPE *type)
693cabdff1aSopenharmony_ci{
694cabdff1aSopenharmony_ci    struct dshow_format_info *fmt_info = NULL;
695cabdff1aSopenharmony_ci    BITMAPINFOHEADER *bih;
696cabdff1aSopenharmony_ci    DXVA2_ExtendedFormat *extended_format_info = NULL;
697cabdff1aSopenharmony_ci    WAVEFORMATEX *fx;
698cabdff1aSopenharmony_ci    enum dshowDeviceType devtype;
699cabdff1aSopenharmony_ci    int64_t framerate;
700cabdff1aSopenharmony_ci
701cabdff1aSopenharmony_ci    if (!type)
702cabdff1aSopenharmony_ci        return NULL;
703cabdff1aSopenharmony_ci
704cabdff1aSopenharmony_ci    if (IsEqualGUID(&type->formattype, &FORMAT_VideoInfo)) {
705cabdff1aSopenharmony_ci        VIDEOINFOHEADER *v = (void *) type->pbFormat;
706cabdff1aSopenharmony_ci        framerate = v->AvgTimePerFrame;
707cabdff1aSopenharmony_ci        bih       = &v->bmiHeader;
708cabdff1aSopenharmony_ci        devtype   = VideoDevice;
709cabdff1aSopenharmony_ci    } else if (IsEqualGUID(&type->formattype, &FORMAT_VideoInfo2)) {
710cabdff1aSopenharmony_ci        VIDEOINFOHEADER2 *v = (void *) type->pbFormat;
711cabdff1aSopenharmony_ci        devtype   = VideoDevice;
712cabdff1aSopenharmony_ci        framerate = v->AvgTimePerFrame;
713cabdff1aSopenharmony_ci        bih       = &v->bmiHeader;
714cabdff1aSopenharmony_ci        if (v->dwControlFlags & AMCONTROL_COLORINFO_PRESENT)
715cabdff1aSopenharmony_ci            extended_format_info = (DXVA2_ExtendedFormat *) &v->dwControlFlags;
716cabdff1aSopenharmony_ci    } else if (IsEqualGUID(&type->formattype, &FORMAT_WaveFormatEx)) {
717cabdff1aSopenharmony_ci        fx = (void *) type->pbFormat;
718cabdff1aSopenharmony_ci        devtype = AudioDevice;
719cabdff1aSopenharmony_ci    } else {
720cabdff1aSopenharmony_ci        return NULL;
721cabdff1aSopenharmony_ci    }
722cabdff1aSopenharmony_ci
723cabdff1aSopenharmony_ci    fmt_info = av_mallocz(sizeof(struct dshow_format_info));
724cabdff1aSopenharmony_ci    if (!fmt_info)
725cabdff1aSopenharmony_ci        return NULL;
726cabdff1aSopenharmony_ci    // initialize fields where unset is not zero
727cabdff1aSopenharmony_ci    fmt_info->pix_fmt = AV_PIX_FMT_NONE;
728cabdff1aSopenharmony_ci    fmt_info->col_space = AVCOL_SPC_UNSPECIFIED;
729cabdff1aSopenharmony_ci    fmt_info->col_prim = AVCOL_PRI_UNSPECIFIED;
730cabdff1aSopenharmony_ci    fmt_info->col_trc = AVCOL_TRC_UNSPECIFIED;
731cabdff1aSopenharmony_ci    // now get info about format
732cabdff1aSopenharmony_ci    fmt_info->devtype = devtype;
733cabdff1aSopenharmony_ci    if (devtype == VideoDevice) {
734cabdff1aSopenharmony_ci        fmt_info->width = bih->biWidth;
735cabdff1aSopenharmony_ci        fmt_info->height = bih->biHeight;
736cabdff1aSopenharmony_ci        fmt_info->framerate = framerate;
737cabdff1aSopenharmony_ci        fmt_info->pix_fmt = dshow_pixfmt(bih->biCompression, bih->biBitCount);
738cabdff1aSopenharmony_ci        if (fmt_info->pix_fmt == AV_PIX_FMT_NONE) {
739cabdff1aSopenharmony_ci            const AVCodecTag *const tags[] = { avformat_get_riff_video_tags(), NULL };
740cabdff1aSopenharmony_ci            fmt_info->codec_id = av_codec_get_id(tags, bih->biCompression);
741cabdff1aSopenharmony_ci        }
742cabdff1aSopenharmony_ci        else
743cabdff1aSopenharmony_ci            fmt_info->codec_id = AV_CODEC_ID_RAWVIDEO;
744cabdff1aSopenharmony_ci
745cabdff1aSopenharmony_ci        if (extended_format_info) {
746cabdff1aSopenharmony_ci            fmt_info->col_range = dshow_color_range(extended_format_info);
747cabdff1aSopenharmony_ci            fmt_info->col_space = dshow_color_space(extended_format_info);
748cabdff1aSopenharmony_ci            fmt_info->col_prim = dshow_color_primaries(extended_format_info);
749cabdff1aSopenharmony_ci            fmt_info->col_trc = dshow_color_trc(extended_format_info);
750cabdff1aSopenharmony_ci            fmt_info->chroma_loc = dshow_chroma_loc(extended_format_info);
751cabdff1aSopenharmony_ci        }
752cabdff1aSopenharmony_ci    } else {
753cabdff1aSopenharmony_ci        fmt_info->sample_rate = fx->nSamplesPerSec;
754cabdff1aSopenharmony_ci        fmt_info->sample_size = fx->wBitsPerSample;
755cabdff1aSopenharmony_ci        fmt_info->channels = fx->nChannels;
756cabdff1aSopenharmony_ci    }
757cabdff1aSopenharmony_ci
758cabdff1aSopenharmony_ci    return fmt_info;
759cabdff1aSopenharmony_ci}
760cabdff1aSopenharmony_ci
761cabdff1aSopenharmony_cistatic void dshow_get_default_format(IPin *pin, IAMStreamConfig *config, enum dshowDeviceType devtype, AM_MEDIA_TYPE **type)
762cabdff1aSopenharmony_ci{
763cabdff1aSopenharmony_ci    HRESULT hr;
764cabdff1aSopenharmony_ci
765cabdff1aSopenharmony_ci    if ((hr = IAMStreamConfig_GetFormat(config, type)) != S_OK) {
766cabdff1aSopenharmony_ci        if (hr == E_NOTIMPL || !IsEqualGUID(&(*type)->majortype, devtype == VideoDevice ? &MEDIATYPE_Video : &MEDIATYPE_Audio)) {
767cabdff1aSopenharmony_ci            // default not available or of wrong type,
768cabdff1aSopenharmony_ci            // fall back to iterating exposed formats
769cabdff1aSopenharmony_ci            // until one of the right type is found
770cabdff1aSopenharmony_ci            IEnumMediaTypes* types = NULL;
771cabdff1aSopenharmony_ci            if (IPin_EnumMediaTypes(pin, &types) != S_OK)
772cabdff1aSopenharmony_ci                return;
773cabdff1aSopenharmony_ci            IEnumMediaTypes_Reset(types);
774cabdff1aSopenharmony_ci            while (IEnumMediaTypes_Next(types, 1, type, NULL) == S_OK) {
775cabdff1aSopenharmony_ci                if (IsEqualGUID(&(*type)->majortype, devtype == VideoDevice ? &MEDIATYPE_Video : &MEDIATYPE_Audio)) {
776cabdff1aSopenharmony_ci                    break;
777cabdff1aSopenharmony_ci                }
778cabdff1aSopenharmony_ci                CoTaskMemFree(*type);
779cabdff1aSopenharmony_ci                *type = NULL;
780cabdff1aSopenharmony_ci            }
781cabdff1aSopenharmony_ci            IEnumMediaTypes_Release(types);
782cabdff1aSopenharmony_ci        }
783cabdff1aSopenharmony_ci    }
784cabdff1aSopenharmony_ci}
785cabdff1aSopenharmony_ci
786cabdff1aSopenharmony_ci/**
787cabdff1aSopenharmony_ci * Cycle through available formats available from the specified pin,
788cabdff1aSopenharmony_ci * try to set parameters specified through AVOptions, or the pin's
789cabdff1aSopenharmony_ci * default format if no such parameters were set. If successful,
790cabdff1aSopenharmony_ci * return 1 in *pformat_set.
791cabdff1aSopenharmony_ci * If pformat_set is NULL, list all pin capabilities.
792cabdff1aSopenharmony_ci */
793cabdff1aSopenharmony_cistatic void
794cabdff1aSopenharmony_cidshow_cycle_formats(AVFormatContext *avctx, enum dshowDeviceType devtype,
795cabdff1aSopenharmony_ci                    IPin *pin, int *pformat_set)
796cabdff1aSopenharmony_ci{
797cabdff1aSopenharmony_ci    struct dshow_ctx *ctx = avctx->priv_data;
798cabdff1aSopenharmony_ci    IAMStreamConfig *config = NULL;
799cabdff1aSopenharmony_ci    AM_MEDIA_TYPE *type = NULL;
800cabdff1aSopenharmony_ci    AM_MEDIA_TYPE *previous_match_type = NULL;
801cabdff1aSopenharmony_ci    int format_set = 0;
802cabdff1aSopenharmony_ci    void *caps = NULL;
803cabdff1aSopenharmony_ci    int i, n, size, r;
804cabdff1aSopenharmony_ci    int wait_for_better = 0;
805cabdff1aSopenharmony_ci    int use_default;
806cabdff1aSopenharmony_ci
807cabdff1aSopenharmony_ci    // format parameters requested by user
808cabdff1aSopenharmony_ci    // if none are requested by user, the values will below be set to
809cabdff1aSopenharmony_ci    // those of the default format
810cabdff1aSopenharmony_ci    // video
811cabdff1aSopenharmony_ci    enum AVCodecID requested_video_codec_id   = ctx->video_codec_id;
812cabdff1aSopenharmony_ci    enum AVPixelFormat requested_pixel_format = ctx->pixel_format;
813cabdff1aSopenharmony_ci    int64_t requested_framerate               = ctx->framerate ? ((int64_t)ctx->requested_framerate.den * 10000000)
814cabdff1aSopenharmony_ci                                                                    / ctx->requested_framerate.num : 0;
815cabdff1aSopenharmony_ci    int requested_width                       = ctx->requested_width;
816cabdff1aSopenharmony_ci    int requested_height                      = ctx->requested_height;
817cabdff1aSopenharmony_ci    // audio
818cabdff1aSopenharmony_ci    int requested_sample_rate                 = ctx->sample_rate;
819cabdff1aSopenharmony_ci    int requested_sample_size                 = ctx->sample_size;
820cabdff1aSopenharmony_ci    int requested_channels                    = ctx->channels;
821cabdff1aSopenharmony_ci
822cabdff1aSopenharmony_ci    if (IPin_QueryInterface(pin, &IID_IAMStreamConfig, (void **) &config) != S_OK)
823cabdff1aSopenharmony_ci        return;
824cabdff1aSopenharmony_ci    if (IAMStreamConfig_GetNumberOfCapabilities(config, &n, &size) != S_OK)
825cabdff1aSopenharmony_ci        goto end;
826cabdff1aSopenharmony_ci
827cabdff1aSopenharmony_ci    caps = av_malloc(size);
828cabdff1aSopenharmony_ci    if (!caps)
829cabdff1aSopenharmony_ci        goto end;
830cabdff1aSopenharmony_ci
831cabdff1aSopenharmony_ci    /**
832cabdff1aSopenharmony_ci     * If we should open the device with the default format,
833cabdff1aSopenharmony_ci     * then:
834cabdff1aSopenharmony_ci     * 1. check what the format of the default device is, and
835cabdff1aSopenharmony_ci     * 2. below we iterate all formats till we find a matching
836cabdff1aSopenharmony_ci     *    one, with most info exposed (see comment below).
837cabdff1aSopenharmony_ci     */
838cabdff1aSopenharmony_ci    use_default = !dshow_should_set_format(avctx, devtype);
839cabdff1aSopenharmony_ci    if (use_default && pformat_set)
840cabdff1aSopenharmony_ci    {
841cabdff1aSopenharmony_ci        // get default
842cabdff1aSopenharmony_ci        dshow_get_default_format(pin, config, devtype, &type);
843cabdff1aSopenharmony_ci        if (!type)
844cabdff1aSopenharmony_ci            // this pin does not expose any formats of the expected type
845cabdff1aSopenharmony_ci            goto end;
846cabdff1aSopenharmony_ci
847cabdff1aSopenharmony_ci        if (type) {
848cabdff1aSopenharmony_ci            // interrogate default format, so we know what to search for below
849cabdff1aSopenharmony_ci            struct dshow_format_info *fmt_info = dshow_get_format_info(type);
850cabdff1aSopenharmony_ci            if (fmt_info) {
851cabdff1aSopenharmony_ci                if (fmt_info->devtype == VideoDevice) {
852cabdff1aSopenharmony_ci                    requested_video_codec_id = fmt_info->codec_id;
853cabdff1aSopenharmony_ci                    requested_pixel_format   = fmt_info->pix_fmt;
854cabdff1aSopenharmony_ci                    requested_framerate      = fmt_info->framerate;
855cabdff1aSopenharmony_ci                    requested_width          = fmt_info->width;
856cabdff1aSopenharmony_ci                    requested_height         = fmt_info->height;
857cabdff1aSopenharmony_ci                } else {
858cabdff1aSopenharmony_ci                    requested_sample_rate = fmt_info->sample_rate;
859cabdff1aSopenharmony_ci                    requested_sample_size = fmt_info->sample_size;
860cabdff1aSopenharmony_ci                    requested_channels    = fmt_info->channels;
861cabdff1aSopenharmony_ci                }
862cabdff1aSopenharmony_ci                av_free(fmt_info);  // free but don't set to NULL to enable below check
863cabdff1aSopenharmony_ci            }
864cabdff1aSopenharmony_ci
865cabdff1aSopenharmony_ci            if (type && type->pbFormat)
866cabdff1aSopenharmony_ci                CoTaskMemFree(type->pbFormat);
867cabdff1aSopenharmony_ci            CoTaskMemFree(type);
868cabdff1aSopenharmony_ci            type = NULL;
869cabdff1aSopenharmony_ci            if (!fmt_info)
870cabdff1aSopenharmony_ci                // default format somehow invalid, can't continue with this pin
871cabdff1aSopenharmony_ci                goto end;
872cabdff1aSopenharmony_ci            fmt_info = NULL;
873cabdff1aSopenharmony_ci        }
874cabdff1aSopenharmony_ci    }
875cabdff1aSopenharmony_ci
876cabdff1aSopenharmony_ci    // NB: some devices (e.g. Logitech C920) expose each video format twice:
877cabdff1aSopenharmony_ci    // both a format containing a VIDEOINFOHEADER and a format containing
878cabdff1aSopenharmony_ci    // a VIDEOINFOHEADER2. We want, if possible, to select a format with a
879cabdff1aSopenharmony_ci    // VIDEOINFOHEADER2, as this potentially provides more info about the
880cabdff1aSopenharmony_ci    // format. So, if in the iteration below we have found a matching format,
881cabdff1aSopenharmony_ci    // but it is a VIDEOINFOHEADER, keep looking for a matching format that
882cabdff1aSopenharmony_ci    // exposes contains a VIDEOINFOHEADER2. Fall back to the VIDEOINFOHEADER
883cabdff1aSopenharmony_ci    // format if no corresponding VIDEOINFOHEADER2 is found when we finish
884cabdff1aSopenharmony_ci    // iterating.
885cabdff1aSopenharmony_ci    for (i = 0; i < n && !format_set; i++) {
886cabdff1aSopenharmony_ci        struct dshow_format_info *fmt_info = NULL;
887cabdff1aSopenharmony_ci        r = IAMStreamConfig_GetStreamCaps(config, i, &type, (void *) caps);
888cabdff1aSopenharmony_ci        if (r != S_OK)
889cabdff1aSopenharmony_ci            goto next;
890cabdff1aSopenharmony_ci#if DSHOWDEBUG
891cabdff1aSopenharmony_ci        ff_print_AM_MEDIA_TYPE(type);
892cabdff1aSopenharmony_ci#endif
893cabdff1aSopenharmony_ci
894cabdff1aSopenharmony_ci        fmt_info = dshow_get_format_info(type);
895cabdff1aSopenharmony_ci        if (!fmt_info)
896cabdff1aSopenharmony_ci            goto next;
897cabdff1aSopenharmony_ci
898cabdff1aSopenharmony_ci        if (devtype == VideoDevice) {
899cabdff1aSopenharmony_ci            VIDEO_STREAM_CONFIG_CAPS *vcaps = caps;
900cabdff1aSopenharmony_ci            BITMAPINFOHEADER *bih;
901cabdff1aSopenharmony_ci            int64_t *fr;
902cabdff1aSopenharmony_ci#if DSHOWDEBUG
903cabdff1aSopenharmony_ci            ff_print_VIDEO_STREAM_CONFIG_CAPS(vcaps);
904cabdff1aSopenharmony_ci#endif
905cabdff1aSopenharmony_ci
906cabdff1aSopenharmony_ci            if (fmt_info->devtype != VideoDevice)
907cabdff1aSopenharmony_ci                goto next;
908cabdff1aSopenharmony_ci
909cabdff1aSopenharmony_ci            if (IsEqualGUID(&type->formattype, &FORMAT_VideoInfo)) {
910cabdff1aSopenharmony_ci                VIDEOINFOHEADER *v = (void *) type->pbFormat;
911cabdff1aSopenharmony_ci                fr  = &v->AvgTimePerFrame;
912cabdff1aSopenharmony_ci                bih = &v->bmiHeader;
913cabdff1aSopenharmony_ci                wait_for_better = 1;
914cabdff1aSopenharmony_ci            } else if (IsEqualGUID(&type->formattype, &FORMAT_VideoInfo2)) {
915cabdff1aSopenharmony_ci                VIDEOINFOHEADER2 *v = (void *) type->pbFormat;
916cabdff1aSopenharmony_ci                fr  = &v->AvgTimePerFrame;
917cabdff1aSopenharmony_ci                bih = &v->bmiHeader;
918cabdff1aSopenharmony_ci                wait_for_better = 0;
919cabdff1aSopenharmony_ci            }
920cabdff1aSopenharmony_ci
921cabdff1aSopenharmony_ci            if (!pformat_set) {
922cabdff1aSopenharmony_ci                const char *chroma = av_chroma_location_name(fmt_info->chroma_loc);
923cabdff1aSopenharmony_ci                if (fmt_info->pix_fmt == AV_PIX_FMT_NONE) {
924cabdff1aSopenharmony_ci                    const AVCodec *codec = avcodec_find_decoder(fmt_info->codec_id);
925cabdff1aSopenharmony_ci                    if (fmt_info->codec_id == AV_CODEC_ID_NONE || !codec) {
926cabdff1aSopenharmony_ci                        av_log(avctx, AV_LOG_INFO, "  unknown compression type 0x%X", (int) bih->biCompression);
927cabdff1aSopenharmony_ci                    } else {
928cabdff1aSopenharmony_ci                        av_log(avctx, AV_LOG_INFO, "  vcodec=%s", codec->name);
929cabdff1aSopenharmony_ci                    }
930cabdff1aSopenharmony_ci                } else {
931cabdff1aSopenharmony_ci                    av_log(avctx, AV_LOG_INFO, "  pixel_format=%s", av_get_pix_fmt_name(fmt_info->pix_fmt));
932cabdff1aSopenharmony_ci                }
933cabdff1aSopenharmony_ci                av_log(avctx, AV_LOG_INFO, "  min s=%ldx%ld fps=%g max s=%ldx%ld fps=%g",
934cabdff1aSopenharmony_ci                       vcaps->MinOutputSize.cx, vcaps->MinOutputSize.cy,
935cabdff1aSopenharmony_ci                       1e7 / vcaps->MaxFrameInterval,
936cabdff1aSopenharmony_ci                       vcaps->MaxOutputSize.cx, vcaps->MaxOutputSize.cy,
937cabdff1aSopenharmony_ci                       1e7 / vcaps->MinFrameInterval);
938cabdff1aSopenharmony_ci
939cabdff1aSopenharmony_ci                if (fmt_info->col_range != AVCOL_RANGE_UNSPECIFIED ||
940cabdff1aSopenharmony_ci                    fmt_info->col_space != AVCOL_SPC_UNSPECIFIED ||
941cabdff1aSopenharmony_ci                    fmt_info->col_prim != AVCOL_PRI_UNSPECIFIED ||
942cabdff1aSopenharmony_ci                    fmt_info->col_trc != AVCOL_TRC_UNSPECIFIED) {
943cabdff1aSopenharmony_ci                    const char *range = av_color_range_name(fmt_info->col_range);
944cabdff1aSopenharmony_ci                    const char *space = av_color_space_name(fmt_info->col_space);
945cabdff1aSopenharmony_ci                    const char *prim = av_color_primaries_name(fmt_info->col_prim);
946cabdff1aSopenharmony_ci                    const char *trc = av_color_transfer_name(fmt_info->col_trc);
947cabdff1aSopenharmony_ci                    av_log(avctx, AV_LOG_INFO, " (%s, %s/%s/%s",
948cabdff1aSopenharmony_ci                        range ? range : "unknown",
949cabdff1aSopenharmony_ci                        space ? space : "unknown",
950cabdff1aSopenharmony_ci                        prim  ? prim  : "unknown",
951cabdff1aSopenharmony_ci                        trc   ? trc   : "unknown");
952cabdff1aSopenharmony_ci                    if (fmt_info->chroma_loc != AVCHROMA_LOC_UNSPECIFIED)
953cabdff1aSopenharmony_ci                        av_log(avctx, AV_LOG_INFO, ", %s", chroma ? chroma : "unknown");
954cabdff1aSopenharmony_ci                    av_log(avctx, AV_LOG_INFO, ")");
955cabdff1aSopenharmony_ci                }
956cabdff1aSopenharmony_ci                else if (fmt_info->chroma_loc != AVCHROMA_LOC_UNSPECIFIED)
957cabdff1aSopenharmony_ci                    av_log(avctx, AV_LOG_INFO, "(%s)", chroma ? chroma : "unknown");
958cabdff1aSopenharmony_ci
959cabdff1aSopenharmony_ci                av_log(avctx, AV_LOG_INFO, "\n");
960cabdff1aSopenharmony_ci                goto next;
961cabdff1aSopenharmony_ci            }
962cabdff1aSopenharmony_ci            if (requested_video_codec_id != AV_CODEC_ID_RAWVIDEO) {
963cabdff1aSopenharmony_ci                if (requested_video_codec_id != fmt_info->codec_id)
964cabdff1aSopenharmony_ci                    goto next;
965cabdff1aSopenharmony_ci            }
966cabdff1aSopenharmony_ci            if (requested_pixel_format != AV_PIX_FMT_NONE &&
967cabdff1aSopenharmony_ci                requested_pixel_format != fmt_info->pix_fmt) {
968cabdff1aSopenharmony_ci                goto next;
969cabdff1aSopenharmony_ci            }
970cabdff1aSopenharmony_ci            if (requested_framerate) {
971cabdff1aSopenharmony_ci                if (requested_framerate > vcaps->MaxFrameInterval ||
972cabdff1aSopenharmony_ci                    requested_framerate < vcaps->MinFrameInterval)
973cabdff1aSopenharmony_ci                    goto next;
974cabdff1aSopenharmony_ci                *fr = requested_framerate;
975cabdff1aSopenharmony_ci            }
976cabdff1aSopenharmony_ci            if (requested_width && requested_height) {
977cabdff1aSopenharmony_ci                if (requested_width  > vcaps->MaxOutputSize.cx ||
978cabdff1aSopenharmony_ci                    requested_width  < vcaps->MinOutputSize.cx ||
979cabdff1aSopenharmony_ci                    requested_height > vcaps->MaxOutputSize.cy ||
980cabdff1aSopenharmony_ci                    requested_height < vcaps->MinOutputSize.cy)
981cabdff1aSopenharmony_ci                    goto next;
982cabdff1aSopenharmony_ci                bih->biWidth  = requested_width;
983cabdff1aSopenharmony_ci                bih->biHeight = requested_height;
984cabdff1aSopenharmony_ci            }
985cabdff1aSopenharmony_ci        } else {
986cabdff1aSopenharmony_ci            WAVEFORMATEX *fx;
987cabdff1aSopenharmony_ci            AUDIO_STREAM_CONFIG_CAPS *acaps = caps;
988cabdff1aSopenharmony_ci#if DSHOWDEBUG
989cabdff1aSopenharmony_ci            ff_print_AUDIO_STREAM_CONFIG_CAPS(acaps);
990cabdff1aSopenharmony_ci#endif
991cabdff1aSopenharmony_ci            if (IsEqualGUID(&type->formattype, &FORMAT_WaveFormatEx)) {
992cabdff1aSopenharmony_ci                fx = (void *) type->pbFormat;
993cabdff1aSopenharmony_ci            } else {
994cabdff1aSopenharmony_ci                goto next;
995cabdff1aSopenharmony_ci            }
996cabdff1aSopenharmony_ci            if (!pformat_set) {
997cabdff1aSopenharmony_ci                av_log(
998cabdff1aSopenharmony_ci                    avctx,
999cabdff1aSopenharmony_ci                    AV_LOG_INFO,
1000cabdff1aSopenharmony_ci                    "  ch=%2u, bits=%2u, rate=%6lu\n",
1001cabdff1aSopenharmony_ci                    fx->nChannels, fx->wBitsPerSample, fx->nSamplesPerSec
1002cabdff1aSopenharmony_ci                );
1003cabdff1aSopenharmony_ci                continue;
1004cabdff1aSopenharmony_ci            }
1005cabdff1aSopenharmony_ci            if (
1006cabdff1aSopenharmony_ci                (requested_sample_rate && requested_sample_rate != fx->nSamplesPerSec) ||
1007cabdff1aSopenharmony_ci                (requested_sample_size && requested_sample_size != fx->wBitsPerSample) ||
1008cabdff1aSopenharmony_ci                (requested_channels    && requested_channels    != fx->nChannels     )
1009cabdff1aSopenharmony_ci            ) {
1010cabdff1aSopenharmony_ci                goto next;
1011cabdff1aSopenharmony_ci            }
1012cabdff1aSopenharmony_ci        }
1013cabdff1aSopenharmony_ci
1014cabdff1aSopenharmony_ci        // found a matching format. Either apply or store
1015cabdff1aSopenharmony_ci        // for safekeeping if we might maybe find a better
1016cabdff1aSopenharmony_ci        // format with more info attached to it (see comment
1017cabdff1aSopenharmony_ci        // above loop)
1018cabdff1aSopenharmony_ci        if (!wait_for_better) {
1019cabdff1aSopenharmony_ci            if (IAMStreamConfig_SetFormat(config, type) != S_OK)
1020cabdff1aSopenharmony_ci                goto next;
1021cabdff1aSopenharmony_ci            format_set = 1;
1022cabdff1aSopenharmony_ci        }
1023cabdff1aSopenharmony_ci        else if (!previous_match_type) {
1024cabdff1aSopenharmony_ci            // store this matching format for possible later use.
1025cabdff1aSopenharmony_ci            // If we have already found a matching format, ignore it
1026cabdff1aSopenharmony_ci            previous_match_type = type;
1027cabdff1aSopenharmony_ci            type = NULL;
1028cabdff1aSopenharmony_ci        }
1029cabdff1aSopenharmony_cinext:
1030cabdff1aSopenharmony_ci        av_freep(&fmt_info);
1031cabdff1aSopenharmony_ci        if (type && type->pbFormat)
1032cabdff1aSopenharmony_ci            CoTaskMemFree(type->pbFormat);
1033cabdff1aSopenharmony_ci        CoTaskMemFree(type);
1034cabdff1aSopenharmony_ci        type = NULL;
1035cabdff1aSopenharmony_ci    }
1036cabdff1aSopenharmony_ci
1037cabdff1aSopenharmony_ci    // set the pin's format, if wanted
1038cabdff1aSopenharmony_ci    if (pformat_set && !format_set) {
1039cabdff1aSopenharmony_ci        if (previous_match_type) {
1040cabdff1aSopenharmony_ci            // previously found a matching VIDEOINFOHEADER format and stored
1041cabdff1aSopenharmony_ci            // it for safe keeping. Searching further for a matching
1042cabdff1aSopenharmony_ci            // VIDEOINFOHEADER2 format yielded nothing. So set the pin's
1043cabdff1aSopenharmony_ci            // format based on the VIDEOINFOHEADER format.
1044cabdff1aSopenharmony_ci            // NB: this never applies to an audio format because
1045cabdff1aSopenharmony_ci            // previous_match_type always NULL in that case
1046cabdff1aSopenharmony_ci            if (IAMStreamConfig_SetFormat(config, previous_match_type) == S_OK)
1047cabdff1aSopenharmony_ci                format_set = 1;
1048cabdff1aSopenharmony_ci        }
1049cabdff1aSopenharmony_ci        else if (use_default) {
1050cabdff1aSopenharmony_ci            // default format returned by device apparently was not contained
1051cabdff1aSopenharmony_ci            // in the capabilities of any of the formats returned by the device
1052cabdff1aSopenharmony_ci            // (sic?). Fall back to directly setting the default format
1053cabdff1aSopenharmony_ci            dshow_get_default_format(pin, config, devtype, &type);
1054cabdff1aSopenharmony_ci            if (IAMStreamConfig_SetFormat(config, type) == S_OK)
1055cabdff1aSopenharmony_ci                format_set = 1;
1056cabdff1aSopenharmony_ci            if (type && type->pbFormat)
1057cabdff1aSopenharmony_ci                CoTaskMemFree(type->pbFormat);
1058cabdff1aSopenharmony_ci            CoTaskMemFree(type);
1059cabdff1aSopenharmony_ci            type = NULL;
1060cabdff1aSopenharmony_ci        }
1061cabdff1aSopenharmony_ci    }
1062cabdff1aSopenharmony_ci
1063cabdff1aSopenharmony_ciend:
1064cabdff1aSopenharmony_ci    if (previous_match_type && previous_match_type->pbFormat)
1065cabdff1aSopenharmony_ci        CoTaskMemFree(previous_match_type->pbFormat);
1066cabdff1aSopenharmony_ci    CoTaskMemFree(previous_match_type);
1067cabdff1aSopenharmony_ci    IAMStreamConfig_Release(config);
1068cabdff1aSopenharmony_ci    av_free(caps);
1069cabdff1aSopenharmony_ci    if (pformat_set)
1070cabdff1aSopenharmony_ci        *pformat_set = format_set;
1071cabdff1aSopenharmony_ci}
1072cabdff1aSopenharmony_ci
1073cabdff1aSopenharmony_ci/**
1074cabdff1aSopenharmony_ci * Set audio device buffer size in milliseconds (which can directly impact
1075cabdff1aSopenharmony_ci * latency, depending on the device).
1076cabdff1aSopenharmony_ci */
1077cabdff1aSopenharmony_cistatic int
1078cabdff1aSopenharmony_cidshow_set_audio_buffer_size(AVFormatContext *avctx, IPin *pin)
1079cabdff1aSopenharmony_ci{
1080cabdff1aSopenharmony_ci    struct dshow_ctx *ctx = avctx->priv_data;
1081cabdff1aSopenharmony_ci    IAMBufferNegotiation *buffer_negotiation = NULL;
1082cabdff1aSopenharmony_ci    ALLOCATOR_PROPERTIES props = { -1, -1, -1, -1 };
1083cabdff1aSopenharmony_ci    IAMStreamConfig *config = NULL;
1084cabdff1aSopenharmony_ci    AM_MEDIA_TYPE *type = NULL;
1085cabdff1aSopenharmony_ci    int ret = AVERROR(EIO);
1086cabdff1aSopenharmony_ci
1087cabdff1aSopenharmony_ci    if (IPin_QueryInterface(pin, &IID_IAMStreamConfig, (void **) &config) != S_OK)
1088cabdff1aSopenharmony_ci        goto end;
1089cabdff1aSopenharmony_ci    if (IAMStreamConfig_GetFormat(config, &type) != S_OK)
1090cabdff1aSopenharmony_ci        goto end;
1091cabdff1aSopenharmony_ci    if (!IsEqualGUID(&type->formattype, &FORMAT_WaveFormatEx))
1092cabdff1aSopenharmony_ci        goto end;
1093cabdff1aSopenharmony_ci
1094cabdff1aSopenharmony_ci    props.cbBuffer = (((WAVEFORMATEX *) type->pbFormat)->nAvgBytesPerSec)
1095cabdff1aSopenharmony_ci                   * ctx->audio_buffer_size / 1000;
1096cabdff1aSopenharmony_ci
1097cabdff1aSopenharmony_ci    if (IPin_QueryInterface(pin, &IID_IAMBufferNegotiation, (void **) &buffer_negotiation) != S_OK)
1098cabdff1aSopenharmony_ci        goto end;
1099cabdff1aSopenharmony_ci    if (IAMBufferNegotiation_SuggestAllocatorProperties(buffer_negotiation, &props) != S_OK)
1100cabdff1aSopenharmony_ci        goto end;
1101cabdff1aSopenharmony_ci
1102cabdff1aSopenharmony_ci    ret = 0;
1103cabdff1aSopenharmony_ci
1104cabdff1aSopenharmony_ciend:
1105cabdff1aSopenharmony_ci    if (buffer_negotiation)
1106cabdff1aSopenharmony_ci        IAMBufferNegotiation_Release(buffer_negotiation);
1107cabdff1aSopenharmony_ci    if (type) {
1108cabdff1aSopenharmony_ci        if (type->pbFormat)
1109cabdff1aSopenharmony_ci            CoTaskMemFree(type->pbFormat);
1110cabdff1aSopenharmony_ci        CoTaskMemFree(type);
1111cabdff1aSopenharmony_ci    }
1112cabdff1aSopenharmony_ci    if (config)
1113cabdff1aSopenharmony_ci        IAMStreamConfig_Release(config);
1114cabdff1aSopenharmony_ci
1115cabdff1aSopenharmony_ci    return ret;
1116cabdff1aSopenharmony_ci}
1117cabdff1aSopenharmony_ci
1118cabdff1aSopenharmony_ci/**
1119cabdff1aSopenharmony_ci * Pops up a user dialog allowing them to adjust properties for the given filter, if possible.
1120cabdff1aSopenharmony_ci */
1121cabdff1aSopenharmony_civoid
1122cabdff1aSopenharmony_ciff_dshow_show_filter_properties(IBaseFilter *device_filter, AVFormatContext *avctx) {
1123cabdff1aSopenharmony_ci    ISpecifyPropertyPages *property_pages = NULL;
1124cabdff1aSopenharmony_ci    IUnknown *device_filter_iunknown = NULL;
1125cabdff1aSopenharmony_ci    HRESULT hr;
1126cabdff1aSopenharmony_ci    FILTER_INFO filter_info = {0}; /* a warning on this line is false positive GCC bug 53119 AFAICT */
1127cabdff1aSopenharmony_ci    CAUUID ca_guid = {0};
1128cabdff1aSopenharmony_ci
1129cabdff1aSopenharmony_ci    hr  = IBaseFilter_QueryInterface(device_filter, &IID_ISpecifyPropertyPages, (void **)&property_pages);
1130cabdff1aSopenharmony_ci    if (hr != S_OK) {
1131cabdff1aSopenharmony_ci        av_log(avctx, AV_LOG_WARNING, "requested filter does not have a property page to show");
1132cabdff1aSopenharmony_ci        goto end;
1133cabdff1aSopenharmony_ci    }
1134cabdff1aSopenharmony_ci    hr = IBaseFilter_QueryFilterInfo(device_filter, &filter_info);
1135cabdff1aSopenharmony_ci    if (hr != S_OK) {
1136cabdff1aSopenharmony_ci        goto fail;
1137cabdff1aSopenharmony_ci    }
1138cabdff1aSopenharmony_ci    hr = IBaseFilter_QueryInterface(device_filter, &IID_IUnknown, (void **)&device_filter_iunknown);
1139cabdff1aSopenharmony_ci    if (hr != S_OK) {
1140cabdff1aSopenharmony_ci        goto fail;
1141cabdff1aSopenharmony_ci    }
1142cabdff1aSopenharmony_ci    hr = ISpecifyPropertyPages_GetPages(property_pages, &ca_guid);
1143cabdff1aSopenharmony_ci    if (hr != S_OK) {
1144cabdff1aSopenharmony_ci        goto fail;
1145cabdff1aSopenharmony_ci    }
1146cabdff1aSopenharmony_ci    hr = OleCreatePropertyFrame(NULL, 0, 0, filter_info.achName, 1, &device_filter_iunknown, ca_guid.cElems,
1147cabdff1aSopenharmony_ci        ca_guid.pElems, 0, 0, NULL);
1148cabdff1aSopenharmony_ci    if (hr != S_OK) {
1149cabdff1aSopenharmony_ci        goto fail;
1150cabdff1aSopenharmony_ci    }
1151cabdff1aSopenharmony_ci    goto end;
1152cabdff1aSopenharmony_cifail:
1153cabdff1aSopenharmony_ci    av_log(avctx, AV_LOG_ERROR, "Failure showing property pages for filter");
1154cabdff1aSopenharmony_ciend:
1155cabdff1aSopenharmony_ci    if (property_pages)
1156cabdff1aSopenharmony_ci        ISpecifyPropertyPages_Release(property_pages);
1157cabdff1aSopenharmony_ci    if (device_filter_iunknown)
1158cabdff1aSopenharmony_ci        IUnknown_Release(device_filter_iunknown);
1159cabdff1aSopenharmony_ci    if (filter_info.pGraph)
1160cabdff1aSopenharmony_ci        IFilterGraph_Release(filter_info.pGraph);
1161cabdff1aSopenharmony_ci    if (ca_guid.pElems)
1162cabdff1aSopenharmony_ci        CoTaskMemFree(ca_guid.pElems);
1163cabdff1aSopenharmony_ci}
1164cabdff1aSopenharmony_ci
1165cabdff1aSopenharmony_ci/**
1166cabdff1aSopenharmony_ci * Cycle through available pins using the device_filter device, of type
1167cabdff1aSopenharmony_ci * devtype, retrieve the first output pin and return the pointer to the
1168cabdff1aSopenharmony_ci * object found in *ppin.
1169cabdff1aSopenharmony_ci * If ppin is NULL, cycle through all pins listing audio/video capabilities.
1170cabdff1aSopenharmony_ci */
1171cabdff1aSopenharmony_cistatic int
1172cabdff1aSopenharmony_cidshow_cycle_pins(AVFormatContext *avctx, enum dshowDeviceType devtype,
1173cabdff1aSopenharmony_ci                 enum dshowSourceFilterType sourcetype, IBaseFilter *device_filter, IPin **ppin)
1174cabdff1aSopenharmony_ci{
1175cabdff1aSopenharmony_ci    struct dshow_ctx *ctx = avctx->priv_data;
1176cabdff1aSopenharmony_ci    IEnumPins *pins = 0;
1177cabdff1aSopenharmony_ci    IPin *device_pin = NULL;
1178cabdff1aSopenharmony_ci    IPin *pin;
1179cabdff1aSopenharmony_ci    int r;
1180cabdff1aSopenharmony_ci
1181cabdff1aSopenharmony_ci    const char *devtypename = (devtype == VideoDevice) ? "video" : "audio only";
1182cabdff1aSopenharmony_ci    const char *sourcetypename = (sourcetype == VideoSourceDevice) ? "video" : "audio";
1183cabdff1aSopenharmony_ci
1184cabdff1aSopenharmony_ci    int set_format = dshow_should_set_format(avctx, devtype);
1185cabdff1aSopenharmony_ci    int format_set = 0;
1186cabdff1aSopenharmony_ci    int should_show_properties = (devtype == VideoDevice) ? ctx->show_video_device_dialog : ctx->show_audio_device_dialog;
1187cabdff1aSopenharmony_ci
1188cabdff1aSopenharmony_ci    if (should_show_properties)
1189cabdff1aSopenharmony_ci        ff_dshow_show_filter_properties(device_filter, avctx);
1190cabdff1aSopenharmony_ci
1191cabdff1aSopenharmony_ci    r = IBaseFilter_EnumPins(device_filter, &pins);
1192cabdff1aSopenharmony_ci    if (r != S_OK) {
1193cabdff1aSopenharmony_ci        av_log(avctx, AV_LOG_ERROR, "Could not enumerate pins.\n");
1194cabdff1aSopenharmony_ci        return AVERROR(EIO);
1195cabdff1aSopenharmony_ci    }
1196cabdff1aSopenharmony_ci
1197cabdff1aSopenharmony_ci    if (!ppin) {
1198cabdff1aSopenharmony_ci        av_log(avctx, AV_LOG_INFO, "DirectShow %s device options (from %s devices)\n",
1199cabdff1aSopenharmony_ci               devtypename, sourcetypename);
1200cabdff1aSopenharmony_ci    }
1201cabdff1aSopenharmony_ci
1202cabdff1aSopenharmony_ci    while (!device_pin && IEnumPins_Next(pins, 1, &pin, NULL) == S_OK) {
1203cabdff1aSopenharmony_ci        IKsPropertySet *p = NULL;
1204cabdff1aSopenharmony_ci        PIN_INFO info = {0};
1205cabdff1aSopenharmony_ci        GUID category;
1206cabdff1aSopenharmony_ci        DWORD r2;
1207cabdff1aSopenharmony_ci        char *name_buf = NULL;
1208cabdff1aSopenharmony_ci        wchar_t *pin_id = NULL;
1209cabdff1aSopenharmony_ci        char *pin_buf = NULL;
1210cabdff1aSopenharmony_ci        char *desired_pin_name = devtype == VideoDevice ? ctx->video_pin_name : ctx->audio_pin_name;
1211cabdff1aSopenharmony_ci
1212cabdff1aSopenharmony_ci        IPin_QueryPinInfo(pin, &info);
1213cabdff1aSopenharmony_ci        IBaseFilter_Release(info.pFilter);
1214cabdff1aSopenharmony_ci
1215cabdff1aSopenharmony_ci        if (info.dir != PINDIR_OUTPUT)
1216cabdff1aSopenharmony_ci            goto next;
1217cabdff1aSopenharmony_ci        if (IPin_QueryInterface(pin, &IID_IKsPropertySet, (void **) &p) != S_OK)
1218cabdff1aSopenharmony_ci            goto next;
1219cabdff1aSopenharmony_ci        if (IKsPropertySet_Get(p, &AMPROPSETID_Pin, AMPROPERTY_PIN_CATEGORY,
1220cabdff1aSopenharmony_ci                               NULL, 0, &category, sizeof(GUID), &r2) != S_OK)
1221cabdff1aSopenharmony_ci            goto next;
1222cabdff1aSopenharmony_ci        if (!IsEqualGUID(&category, &PIN_CATEGORY_CAPTURE))
1223cabdff1aSopenharmony_ci            goto next;
1224cabdff1aSopenharmony_ci        name_buf = dup_wchar_to_utf8(info.achName);
1225cabdff1aSopenharmony_ci
1226cabdff1aSopenharmony_ci        r = IPin_QueryId(pin, &pin_id);
1227cabdff1aSopenharmony_ci        if (r != S_OK) {
1228cabdff1aSopenharmony_ci            av_log(avctx, AV_LOG_ERROR, "Could not query pin id\n");
1229cabdff1aSopenharmony_ci            return AVERROR(EIO);
1230cabdff1aSopenharmony_ci        }
1231cabdff1aSopenharmony_ci        pin_buf = dup_wchar_to_utf8(pin_id);
1232cabdff1aSopenharmony_ci
1233cabdff1aSopenharmony_ci        if (!ppin) {
1234cabdff1aSopenharmony_ci            av_log(avctx, AV_LOG_INFO, " Pin \"%s\" (alternative pin name \"%s\")\n", name_buf, pin_buf);
1235cabdff1aSopenharmony_ci            dshow_cycle_formats(avctx, devtype, pin, NULL);
1236cabdff1aSopenharmony_ci            goto next;
1237cabdff1aSopenharmony_ci        }
1238cabdff1aSopenharmony_ci
1239cabdff1aSopenharmony_ci        if (desired_pin_name) {
1240cabdff1aSopenharmony_ci            if(strcmp(name_buf, desired_pin_name) && strcmp(pin_buf, desired_pin_name)) {
1241cabdff1aSopenharmony_ci                av_log(avctx, AV_LOG_DEBUG, "skipping pin \"%s\" (\"%s\") != requested \"%s\"\n",
1242cabdff1aSopenharmony_ci                    name_buf, pin_buf, desired_pin_name);
1243cabdff1aSopenharmony_ci                goto next;
1244cabdff1aSopenharmony_ci            }
1245cabdff1aSopenharmony_ci        }
1246cabdff1aSopenharmony_ci
1247cabdff1aSopenharmony_ci        // will either try to find format matching options supplied by user
1248cabdff1aSopenharmony_ci        // or try to open default format. Successful if returns with format_set==1
1249cabdff1aSopenharmony_ci        dshow_cycle_formats(avctx, devtype, pin, &format_set);
1250cabdff1aSopenharmony_ci        if (!format_set) {
1251cabdff1aSopenharmony_ci            goto next;
1252cabdff1aSopenharmony_ci        }
1253cabdff1aSopenharmony_ci
1254cabdff1aSopenharmony_ci        if (devtype == AudioDevice && ctx->audio_buffer_size) {
1255cabdff1aSopenharmony_ci            if (dshow_set_audio_buffer_size(avctx, pin) < 0) {
1256cabdff1aSopenharmony_ci                av_log(avctx, AV_LOG_ERROR, "unable to set audio buffer size %d to pin, using pin anyway...", ctx->audio_buffer_size);
1257cabdff1aSopenharmony_ci            }
1258cabdff1aSopenharmony_ci        }
1259cabdff1aSopenharmony_ci
1260cabdff1aSopenharmony_ci        if (format_set) {
1261cabdff1aSopenharmony_ci            device_pin = pin;
1262cabdff1aSopenharmony_ci            av_log(avctx, AV_LOG_DEBUG, "Selecting pin %s on %s\n", name_buf, devtypename);
1263cabdff1aSopenharmony_ci        }
1264cabdff1aSopenharmony_cinext:
1265cabdff1aSopenharmony_ci        if (p)
1266cabdff1aSopenharmony_ci            IKsPropertySet_Release(p);
1267cabdff1aSopenharmony_ci        if (device_pin != pin)
1268cabdff1aSopenharmony_ci            IPin_Release(pin);
1269cabdff1aSopenharmony_ci        av_free(name_buf);
1270cabdff1aSopenharmony_ci        av_free(pin_buf);
1271cabdff1aSopenharmony_ci        if (pin_id)
1272cabdff1aSopenharmony_ci            CoTaskMemFree(pin_id);
1273cabdff1aSopenharmony_ci    }
1274cabdff1aSopenharmony_ci
1275cabdff1aSopenharmony_ci    IEnumPins_Release(pins);
1276cabdff1aSopenharmony_ci
1277cabdff1aSopenharmony_ci    if (ppin) {
1278cabdff1aSopenharmony_ci        if (set_format && !format_set) {
1279cabdff1aSopenharmony_ci            av_log(avctx, AV_LOG_ERROR, "Could not set %s options\n", devtypename);
1280cabdff1aSopenharmony_ci            return AVERROR(EIO);
1281cabdff1aSopenharmony_ci        }
1282cabdff1aSopenharmony_ci        if (!device_pin) {
1283cabdff1aSopenharmony_ci            av_log(avctx, AV_LOG_ERROR,
1284cabdff1aSopenharmony_ci                "Could not find output pin from %s capture device.\n", devtypename);
1285cabdff1aSopenharmony_ci            return AVERROR(EIO);
1286cabdff1aSopenharmony_ci        }
1287cabdff1aSopenharmony_ci        *ppin = device_pin;
1288cabdff1aSopenharmony_ci    }
1289cabdff1aSopenharmony_ci
1290cabdff1aSopenharmony_ci    return 0;
1291cabdff1aSopenharmony_ci}
1292cabdff1aSopenharmony_ci
1293cabdff1aSopenharmony_ci/**
1294cabdff1aSopenharmony_ci * List options for device with type devtype, source filter type sourcetype
1295cabdff1aSopenharmony_ci *
1296cabdff1aSopenharmony_ci * @param devenum device enumerator used for accessing the device
1297cabdff1aSopenharmony_ci */
1298cabdff1aSopenharmony_cistatic int
1299cabdff1aSopenharmony_cidshow_list_device_options(AVFormatContext *avctx, ICreateDevEnum *devenum,
1300cabdff1aSopenharmony_ci                          enum dshowDeviceType devtype, enum dshowSourceFilterType sourcetype)
1301cabdff1aSopenharmony_ci{
1302cabdff1aSopenharmony_ci    struct dshow_ctx *ctx = avctx->priv_data;
1303cabdff1aSopenharmony_ci    IBaseFilter *device_filter = NULL;
1304cabdff1aSopenharmony_ci    char *device_unique_name = NULL;
1305cabdff1aSopenharmony_ci    int r;
1306cabdff1aSopenharmony_ci
1307cabdff1aSopenharmony_ci    if ((r = dshow_cycle_devices(avctx, devenum, devtype, sourcetype, &device_filter, &device_unique_name, NULL)) < 0)
1308cabdff1aSopenharmony_ci        return r;
1309cabdff1aSopenharmony_ci    ctx->device_filter[devtype] = device_filter;
1310cabdff1aSopenharmony_ci    ctx->device_unique_name[devtype] = device_unique_name;
1311cabdff1aSopenharmony_ci    if ((r = dshow_cycle_pins(avctx, devtype, sourcetype, device_filter, NULL)) < 0)
1312cabdff1aSopenharmony_ci        return r;
1313cabdff1aSopenharmony_ci    return 0;
1314cabdff1aSopenharmony_ci}
1315cabdff1aSopenharmony_ci
1316cabdff1aSopenharmony_cistatic int
1317cabdff1aSopenharmony_cidshow_open_device(AVFormatContext *avctx, ICreateDevEnum *devenum,
1318cabdff1aSopenharmony_ci                  enum dshowDeviceType devtype, enum dshowSourceFilterType sourcetype)
1319cabdff1aSopenharmony_ci{
1320cabdff1aSopenharmony_ci    struct dshow_ctx *ctx = avctx->priv_data;
1321cabdff1aSopenharmony_ci    IBaseFilter *device_filter = NULL;
1322cabdff1aSopenharmony_ci    char *device_filter_unique_name = NULL;
1323cabdff1aSopenharmony_ci    IGraphBuilder *graph = ctx->graph;
1324cabdff1aSopenharmony_ci    IPin *device_pin = NULL;
1325cabdff1aSopenharmony_ci    DShowPin *capture_pin = NULL;
1326cabdff1aSopenharmony_ci    DShowFilter *capture_filter = NULL;
1327cabdff1aSopenharmony_ci    ICaptureGraphBuilder2 *graph_builder2 = NULL;
1328cabdff1aSopenharmony_ci    int ret = AVERROR(EIO);
1329cabdff1aSopenharmony_ci    int r;
1330cabdff1aSopenharmony_ci    IStream *ifile_stream = NULL;
1331cabdff1aSopenharmony_ci    IStream *ofile_stream = NULL;
1332cabdff1aSopenharmony_ci    IPersistStream *pers_stream = NULL;
1333cabdff1aSopenharmony_ci    enum dshowDeviceType otherDevType = (devtype == VideoDevice) ? AudioDevice : VideoDevice;
1334cabdff1aSopenharmony_ci
1335cabdff1aSopenharmony_ci    const wchar_t *filter_name[2] = { L"Audio capture filter", L"Video capture filter" };
1336cabdff1aSopenharmony_ci
1337cabdff1aSopenharmony_ci
1338cabdff1aSopenharmony_ci    if ( ((ctx->audio_filter_load_file) && (strlen(ctx->audio_filter_load_file)>0) && (sourcetype == AudioSourceDevice)) ||
1339cabdff1aSopenharmony_ci            ((ctx->video_filter_load_file) && (strlen(ctx->video_filter_load_file)>0) && (sourcetype == VideoSourceDevice)) ) {
1340cabdff1aSopenharmony_ci        HRESULT hr;
1341cabdff1aSopenharmony_ci        char *filename = NULL;
1342cabdff1aSopenharmony_ci
1343cabdff1aSopenharmony_ci        if (sourcetype == AudioSourceDevice)
1344cabdff1aSopenharmony_ci            filename = ctx->audio_filter_load_file;
1345cabdff1aSopenharmony_ci        else
1346cabdff1aSopenharmony_ci            filename = ctx->video_filter_load_file;
1347cabdff1aSopenharmony_ci
1348cabdff1aSopenharmony_ci        hr = SHCreateStreamOnFile ((LPCSTR) filename, STGM_READ, &ifile_stream);
1349cabdff1aSopenharmony_ci        if (S_OK != hr) {
1350cabdff1aSopenharmony_ci            av_log(avctx, AV_LOG_ERROR, "Could not open capture filter description file.\n");
1351cabdff1aSopenharmony_ci            goto error;
1352cabdff1aSopenharmony_ci        }
1353cabdff1aSopenharmony_ci
1354cabdff1aSopenharmony_ci        hr = OleLoadFromStream(ifile_stream, &IID_IBaseFilter, (void **) &device_filter);
1355cabdff1aSopenharmony_ci        if (hr != S_OK) {
1356cabdff1aSopenharmony_ci            av_log(avctx, AV_LOG_ERROR, "Could not load capture filter from file.\n");
1357cabdff1aSopenharmony_ci            goto error;
1358cabdff1aSopenharmony_ci        }
1359cabdff1aSopenharmony_ci
1360cabdff1aSopenharmony_ci        if (sourcetype == AudioSourceDevice)
1361cabdff1aSopenharmony_ci            av_log(avctx, AV_LOG_INFO, "Audio-");
1362cabdff1aSopenharmony_ci        else
1363cabdff1aSopenharmony_ci            av_log(avctx, AV_LOG_INFO, "Video-");
1364cabdff1aSopenharmony_ci        av_log(avctx, AV_LOG_INFO, "Capture filter loaded successfully from file \"%s\".\n", filename);
1365cabdff1aSopenharmony_ci    } else {
1366cabdff1aSopenharmony_ci
1367cabdff1aSopenharmony_ci        if ((r = dshow_cycle_devices(avctx, devenum, devtype, sourcetype, &device_filter, &device_filter_unique_name, NULL)) < 0) {
1368cabdff1aSopenharmony_ci            ret = r;
1369cabdff1aSopenharmony_ci            goto error;
1370cabdff1aSopenharmony_ci        }
1371cabdff1aSopenharmony_ci    }
1372cabdff1aSopenharmony_ci        if (ctx->device_filter[otherDevType]) {
1373cabdff1aSopenharmony_ci        // avoid adding add two instances of the same device to the graph, one for video, one for audio
1374cabdff1aSopenharmony_ci        // a few devices don't support this (could also do this check earlier to avoid double crossbars, etc. but they seem OK)
1375cabdff1aSopenharmony_ci        if (strcmp(device_filter_unique_name, ctx->device_unique_name[otherDevType]) == 0) {
1376cabdff1aSopenharmony_ci          av_log(avctx, AV_LOG_DEBUG, "reusing previous graph capture filter... %s\n", device_filter_unique_name);
1377cabdff1aSopenharmony_ci          IBaseFilter_Release(device_filter);
1378cabdff1aSopenharmony_ci          device_filter = ctx->device_filter[otherDevType];
1379cabdff1aSopenharmony_ci          IBaseFilter_AddRef(ctx->device_filter[otherDevType]);
1380cabdff1aSopenharmony_ci        } else {
1381cabdff1aSopenharmony_ci            av_log(avctx, AV_LOG_DEBUG, "not reusing previous graph capture filter %s != %s\n", device_filter_unique_name, ctx->device_unique_name[otherDevType]);
1382cabdff1aSopenharmony_ci        }
1383cabdff1aSopenharmony_ci    }
1384cabdff1aSopenharmony_ci
1385cabdff1aSopenharmony_ci    ctx->device_filter [devtype] = device_filter;
1386cabdff1aSopenharmony_ci    ctx->device_unique_name [devtype] = device_filter_unique_name;
1387cabdff1aSopenharmony_ci
1388cabdff1aSopenharmony_ci    r = IGraphBuilder_AddFilter(graph, device_filter, NULL);
1389cabdff1aSopenharmony_ci    if (r != S_OK) {
1390cabdff1aSopenharmony_ci        av_log(avctx, AV_LOG_ERROR, "Could not add device filter to graph.\n");
1391cabdff1aSopenharmony_ci        goto error;
1392cabdff1aSopenharmony_ci    }
1393cabdff1aSopenharmony_ci
1394cabdff1aSopenharmony_ci    if ((r = dshow_cycle_pins(avctx, devtype, sourcetype, device_filter, &device_pin)) < 0) {
1395cabdff1aSopenharmony_ci        ret = r;
1396cabdff1aSopenharmony_ci        goto error;
1397cabdff1aSopenharmony_ci    }
1398cabdff1aSopenharmony_ci
1399cabdff1aSopenharmony_ci    ctx->device_pin[devtype] = device_pin;
1400cabdff1aSopenharmony_ci
1401cabdff1aSopenharmony_ci    capture_filter = ff_dshow_filter_Create(avctx, callback, devtype);
1402cabdff1aSopenharmony_ci    if (!capture_filter) {
1403cabdff1aSopenharmony_ci        av_log(avctx, AV_LOG_ERROR, "Could not create grabber filter.\n");
1404cabdff1aSopenharmony_ci        goto error;
1405cabdff1aSopenharmony_ci    }
1406cabdff1aSopenharmony_ci    ctx->capture_filter[devtype] = capture_filter;
1407cabdff1aSopenharmony_ci
1408cabdff1aSopenharmony_ci    if ( ((ctx->audio_filter_save_file) && (strlen(ctx->audio_filter_save_file)>0) && (sourcetype == AudioSourceDevice)) ||
1409cabdff1aSopenharmony_ci            ((ctx->video_filter_save_file) && (strlen(ctx->video_filter_save_file)>0) && (sourcetype == VideoSourceDevice)) ) {
1410cabdff1aSopenharmony_ci
1411cabdff1aSopenharmony_ci        HRESULT hr;
1412cabdff1aSopenharmony_ci        char *filename = NULL;
1413cabdff1aSopenharmony_ci
1414cabdff1aSopenharmony_ci        if (sourcetype == AudioSourceDevice)
1415cabdff1aSopenharmony_ci            filename = ctx->audio_filter_save_file;
1416cabdff1aSopenharmony_ci        else
1417cabdff1aSopenharmony_ci            filename = ctx->video_filter_save_file;
1418cabdff1aSopenharmony_ci
1419cabdff1aSopenharmony_ci        hr = SHCreateStreamOnFile ((LPCSTR) filename, STGM_CREATE | STGM_READWRITE, &ofile_stream);
1420cabdff1aSopenharmony_ci        if (S_OK != hr) {
1421cabdff1aSopenharmony_ci            av_log(avctx, AV_LOG_ERROR, "Could not create capture filter description file.\n");
1422cabdff1aSopenharmony_ci            goto error;
1423cabdff1aSopenharmony_ci        }
1424cabdff1aSopenharmony_ci
1425cabdff1aSopenharmony_ci        hr  = IBaseFilter_QueryInterface(device_filter, &IID_IPersistStream, (void **) &pers_stream);
1426cabdff1aSopenharmony_ci        if (hr != S_OK) {
1427cabdff1aSopenharmony_ci            av_log(avctx, AV_LOG_ERROR, "Query for IPersistStream failed.\n");
1428cabdff1aSopenharmony_ci            goto error;
1429cabdff1aSopenharmony_ci        }
1430cabdff1aSopenharmony_ci
1431cabdff1aSopenharmony_ci        hr = OleSaveToStream(pers_stream, ofile_stream);
1432cabdff1aSopenharmony_ci        if (hr != S_OK) {
1433cabdff1aSopenharmony_ci            av_log(avctx, AV_LOG_ERROR, "Could not save capture filter \n");
1434cabdff1aSopenharmony_ci            goto error;
1435cabdff1aSopenharmony_ci        }
1436cabdff1aSopenharmony_ci
1437cabdff1aSopenharmony_ci        hr = IStream_Commit(ofile_stream, STGC_DEFAULT);
1438cabdff1aSopenharmony_ci        if (S_OK != hr) {
1439cabdff1aSopenharmony_ci            av_log(avctx, AV_LOG_ERROR, "Could not commit capture filter data to file.\n");
1440cabdff1aSopenharmony_ci            goto error;
1441cabdff1aSopenharmony_ci        }
1442cabdff1aSopenharmony_ci
1443cabdff1aSopenharmony_ci        if (sourcetype == AudioSourceDevice)
1444cabdff1aSopenharmony_ci            av_log(avctx, AV_LOG_INFO, "Audio-");
1445cabdff1aSopenharmony_ci        else
1446cabdff1aSopenharmony_ci            av_log(avctx, AV_LOG_INFO, "Video-");
1447cabdff1aSopenharmony_ci        av_log(avctx, AV_LOG_INFO, "Capture filter saved successfully to file \"%s\".\n", filename);
1448cabdff1aSopenharmony_ci    }
1449cabdff1aSopenharmony_ci
1450cabdff1aSopenharmony_ci    r = IGraphBuilder_AddFilter(graph, (IBaseFilter *) capture_filter,
1451cabdff1aSopenharmony_ci                                filter_name[devtype]);
1452cabdff1aSopenharmony_ci    if (r != S_OK) {
1453cabdff1aSopenharmony_ci        av_log(avctx, AV_LOG_ERROR, "Could not add capture filter to graph\n");
1454cabdff1aSopenharmony_ci        goto error;
1455cabdff1aSopenharmony_ci    }
1456cabdff1aSopenharmony_ci
1457cabdff1aSopenharmony_ci    ff_dshow_pin_AddRef(capture_filter->pin);
1458cabdff1aSopenharmony_ci    capture_pin = capture_filter->pin;
1459cabdff1aSopenharmony_ci    ctx->capture_pin[devtype] = capture_pin;
1460cabdff1aSopenharmony_ci
1461cabdff1aSopenharmony_ci    r = CoCreateInstance(&CLSID_CaptureGraphBuilder2, NULL, CLSCTX_INPROC_SERVER,
1462cabdff1aSopenharmony_ci                         &IID_ICaptureGraphBuilder2, (void **) &graph_builder2);
1463cabdff1aSopenharmony_ci    if (r != S_OK) {
1464cabdff1aSopenharmony_ci        av_log(avctx, AV_LOG_ERROR, "Could not create CaptureGraphBuilder2\n");
1465cabdff1aSopenharmony_ci        goto error;
1466cabdff1aSopenharmony_ci    }
1467cabdff1aSopenharmony_ci    ICaptureGraphBuilder2_SetFiltergraph(graph_builder2, graph);
1468cabdff1aSopenharmony_ci    if (r != S_OK) {
1469cabdff1aSopenharmony_ci        av_log(avctx, AV_LOG_ERROR, "Could not set graph for CaptureGraphBuilder2\n");
1470cabdff1aSopenharmony_ci        goto error;
1471cabdff1aSopenharmony_ci    }
1472cabdff1aSopenharmony_ci
1473cabdff1aSopenharmony_ci    r = ICaptureGraphBuilder2_RenderStream(graph_builder2, NULL, NULL, (IUnknown *) device_pin, NULL /* no intermediate filter */,
1474cabdff1aSopenharmony_ci        (IBaseFilter *) capture_filter); /* connect pins, optionally insert intermediate filters like crossbar if necessary */
1475cabdff1aSopenharmony_ci
1476cabdff1aSopenharmony_ci    if (r != S_OK) {
1477cabdff1aSopenharmony_ci        av_log(avctx, AV_LOG_ERROR, "Could not RenderStream to connect pins\n");
1478cabdff1aSopenharmony_ci        goto error;
1479cabdff1aSopenharmony_ci    }
1480cabdff1aSopenharmony_ci
1481cabdff1aSopenharmony_ci    r = ff_dshow_try_setup_crossbar_options(graph_builder2, device_filter, devtype, avctx);
1482cabdff1aSopenharmony_ci
1483cabdff1aSopenharmony_ci    if (r != S_OK) {
1484cabdff1aSopenharmony_ci        av_log(avctx, AV_LOG_ERROR, "Could not setup CrossBar\n");
1485cabdff1aSopenharmony_ci        goto error;
1486cabdff1aSopenharmony_ci    }
1487cabdff1aSopenharmony_ci
1488cabdff1aSopenharmony_ci    ret = 0;
1489cabdff1aSopenharmony_ci
1490cabdff1aSopenharmony_cierror:
1491cabdff1aSopenharmony_ci    if (graph_builder2 != NULL)
1492cabdff1aSopenharmony_ci        ICaptureGraphBuilder2_Release(graph_builder2);
1493cabdff1aSopenharmony_ci
1494cabdff1aSopenharmony_ci    if (pers_stream)
1495cabdff1aSopenharmony_ci        IPersistStream_Release(pers_stream);
1496cabdff1aSopenharmony_ci
1497cabdff1aSopenharmony_ci    if (ifile_stream)
1498cabdff1aSopenharmony_ci        IStream_Release(ifile_stream);
1499cabdff1aSopenharmony_ci
1500cabdff1aSopenharmony_ci    if (ofile_stream)
1501cabdff1aSopenharmony_ci        IStream_Release(ofile_stream);
1502cabdff1aSopenharmony_ci
1503cabdff1aSopenharmony_ci    return ret;
1504cabdff1aSopenharmony_ci}
1505cabdff1aSopenharmony_ci
1506cabdff1aSopenharmony_cistatic enum AVCodecID waveform_codec_id(enum AVSampleFormat sample_fmt)
1507cabdff1aSopenharmony_ci{
1508cabdff1aSopenharmony_ci    switch (sample_fmt) {
1509cabdff1aSopenharmony_ci    case AV_SAMPLE_FMT_U8:  return AV_CODEC_ID_PCM_U8;
1510cabdff1aSopenharmony_ci    case AV_SAMPLE_FMT_S16: return AV_CODEC_ID_PCM_S16LE;
1511cabdff1aSopenharmony_ci    case AV_SAMPLE_FMT_S32: return AV_CODEC_ID_PCM_S32LE;
1512cabdff1aSopenharmony_ci    default:                return AV_CODEC_ID_NONE; /* Should never happen. */
1513cabdff1aSopenharmony_ci    }
1514cabdff1aSopenharmony_ci}
1515cabdff1aSopenharmony_ci
1516cabdff1aSopenharmony_cistatic enum AVSampleFormat sample_fmt_bits_per_sample(int bits)
1517cabdff1aSopenharmony_ci{
1518cabdff1aSopenharmony_ci    switch (bits) {
1519cabdff1aSopenharmony_ci    case 8:  return AV_SAMPLE_FMT_U8;
1520cabdff1aSopenharmony_ci    case 16: return AV_SAMPLE_FMT_S16;
1521cabdff1aSopenharmony_ci    case 32: return AV_SAMPLE_FMT_S32;
1522cabdff1aSopenharmony_ci    default: return AV_SAMPLE_FMT_NONE; /* Should never happen. */
1523cabdff1aSopenharmony_ci    }
1524cabdff1aSopenharmony_ci}
1525cabdff1aSopenharmony_ci
1526cabdff1aSopenharmony_cistatic int
1527cabdff1aSopenharmony_cidshow_add_device(AVFormatContext *avctx,
1528cabdff1aSopenharmony_ci                 enum dshowDeviceType devtype)
1529cabdff1aSopenharmony_ci{
1530cabdff1aSopenharmony_ci    struct dshow_ctx *ctx = avctx->priv_data;
1531cabdff1aSopenharmony_ci    AM_MEDIA_TYPE type;
1532cabdff1aSopenharmony_ci    AVCodecParameters *par;
1533cabdff1aSopenharmony_ci    AVStream *st;
1534cabdff1aSopenharmony_ci    struct dshow_format_info *fmt_info = NULL;
1535cabdff1aSopenharmony_ci    int ret = AVERROR(EIO);
1536cabdff1aSopenharmony_ci
1537cabdff1aSopenharmony_ci    type.pbFormat = NULL;
1538cabdff1aSopenharmony_ci
1539cabdff1aSopenharmony_ci    st = avformat_new_stream(avctx, NULL);
1540cabdff1aSopenharmony_ci    if (!st) {
1541cabdff1aSopenharmony_ci        ret = AVERROR(ENOMEM);
1542cabdff1aSopenharmony_ci        goto error;
1543cabdff1aSopenharmony_ci    }
1544cabdff1aSopenharmony_ci    st->id = devtype;
1545cabdff1aSopenharmony_ci
1546cabdff1aSopenharmony_ci    ctx->capture_filter[devtype]->stream_index = st->index;
1547cabdff1aSopenharmony_ci
1548cabdff1aSopenharmony_ci    ff_dshow_pin_ConnectionMediaType(ctx->capture_pin[devtype], &type);
1549cabdff1aSopenharmony_ci    fmt_info = dshow_get_format_info(&type);
1550cabdff1aSopenharmony_ci    if (!fmt_info) {
1551cabdff1aSopenharmony_ci        ret = AVERROR(EIO);
1552cabdff1aSopenharmony_ci        goto error;
1553cabdff1aSopenharmony_ci    }
1554cabdff1aSopenharmony_ci
1555cabdff1aSopenharmony_ci    par = st->codecpar;
1556cabdff1aSopenharmony_ci    if (devtype == VideoDevice) {
1557cabdff1aSopenharmony_ci        BITMAPINFOHEADER *bih = NULL;
1558cabdff1aSopenharmony_ci        AVRational time_base;
1559cabdff1aSopenharmony_ci
1560cabdff1aSopenharmony_ci        if (IsEqualGUID(&type.formattype, &FORMAT_VideoInfo)) {
1561cabdff1aSopenharmony_ci            VIDEOINFOHEADER *v = (void *) type.pbFormat;
1562cabdff1aSopenharmony_ci            time_base = (AVRational) { v->AvgTimePerFrame, 10000000 };
1563cabdff1aSopenharmony_ci            bih = &v->bmiHeader;
1564cabdff1aSopenharmony_ci        } else if (IsEqualGUID(&type.formattype, &FORMAT_VideoInfo2)) {
1565cabdff1aSopenharmony_ci            VIDEOINFOHEADER2 *v = (void *) type.pbFormat;
1566cabdff1aSopenharmony_ci            time_base = (AVRational) { v->AvgTimePerFrame, 10000000 };
1567cabdff1aSopenharmony_ci            bih = &v->bmiHeader;
1568cabdff1aSopenharmony_ci        }
1569cabdff1aSopenharmony_ci        if (!bih) {
1570cabdff1aSopenharmony_ci            av_log(avctx, AV_LOG_ERROR, "Could not get media type.\n");
1571cabdff1aSopenharmony_ci            goto error;
1572cabdff1aSopenharmony_ci        }
1573cabdff1aSopenharmony_ci
1574cabdff1aSopenharmony_ci        st->avg_frame_rate = av_inv_q(time_base);
1575cabdff1aSopenharmony_ci        st->r_frame_rate = av_inv_q(time_base);
1576cabdff1aSopenharmony_ci
1577cabdff1aSopenharmony_ci        par->codec_type = AVMEDIA_TYPE_VIDEO;
1578cabdff1aSopenharmony_ci        par->width      = fmt_info->width;
1579cabdff1aSopenharmony_ci        par->height     = fmt_info->height;
1580cabdff1aSopenharmony_ci        par->codec_tag  = bih->biCompression;
1581cabdff1aSopenharmony_ci        par->format     = fmt_info->pix_fmt;
1582cabdff1aSopenharmony_ci        if (bih->biCompression == MKTAG('H', 'D', 'Y', 'C')) {
1583cabdff1aSopenharmony_ci            av_log(avctx, AV_LOG_DEBUG, "attempt to use full range for HDYC...\n");
1584cabdff1aSopenharmony_ci            par->color_range = AVCOL_RANGE_MPEG; // just in case it needs this...
1585cabdff1aSopenharmony_ci        }
1586cabdff1aSopenharmony_ci        par->color_range = fmt_info->col_range;
1587cabdff1aSopenharmony_ci        par->color_space = fmt_info->col_space;
1588cabdff1aSopenharmony_ci        par->color_primaries = fmt_info->col_prim;
1589cabdff1aSopenharmony_ci        par->color_trc = fmt_info->col_trc;
1590cabdff1aSopenharmony_ci        par->chroma_location = fmt_info->chroma_loc;
1591cabdff1aSopenharmony_ci        par->codec_id = fmt_info->codec_id;
1592cabdff1aSopenharmony_ci        if (par->codec_id == AV_CODEC_ID_RAWVIDEO) {
1593cabdff1aSopenharmony_ci            if (bih->biCompression == BI_RGB || bih->biCompression == BI_BITFIELDS) {
1594cabdff1aSopenharmony_ci                par->bits_per_coded_sample = bih->biBitCount;
1595cabdff1aSopenharmony_ci                if (par->height < 0) {
1596cabdff1aSopenharmony_ci                    par->height *= -1;
1597cabdff1aSopenharmony_ci                } else {
1598cabdff1aSopenharmony_ci                    par->extradata = av_malloc(9 + AV_INPUT_BUFFER_PADDING_SIZE);
1599cabdff1aSopenharmony_ci                    if (par->extradata) {
1600cabdff1aSopenharmony_ci                        par->extradata_size = 9;
1601cabdff1aSopenharmony_ci                        memcpy(par->extradata, "BottomUp", 9);
1602cabdff1aSopenharmony_ci                    }
1603cabdff1aSopenharmony_ci                }
1604cabdff1aSopenharmony_ci            }
1605cabdff1aSopenharmony_ci        } else {
1606cabdff1aSopenharmony_ci            if (par->codec_id == AV_CODEC_ID_NONE) {
1607cabdff1aSopenharmony_ci                av_log(avctx, AV_LOG_ERROR, "Unknown compression type. "
1608cabdff1aSopenharmony_ci                                 "Please report type 0x%X.\n", (int) bih->biCompression);
1609cabdff1aSopenharmony_ci                ret = AVERROR_PATCHWELCOME;
1610cabdff1aSopenharmony_ci                goto error;
1611cabdff1aSopenharmony_ci            }
1612cabdff1aSopenharmony_ci            par->bits_per_coded_sample = bih->biBitCount;
1613cabdff1aSopenharmony_ci        }
1614cabdff1aSopenharmony_ci    } else {
1615cabdff1aSopenharmony_ci        if (!IsEqualGUID(&type.formattype, &FORMAT_WaveFormatEx)) {
1616cabdff1aSopenharmony_ci            av_log(avctx, AV_LOG_ERROR, "Could not get media type.\n");
1617cabdff1aSopenharmony_ci            goto error;
1618cabdff1aSopenharmony_ci        }
1619cabdff1aSopenharmony_ci
1620cabdff1aSopenharmony_ci        par->codec_type  = AVMEDIA_TYPE_AUDIO;
1621cabdff1aSopenharmony_ci        par->format      = sample_fmt_bits_per_sample(fmt_info->sample_size);
1622cabdff1aSopenharmony_ci        par->codec_id    = waveform_codec_id(par->format);
1623cabdff1aSopenharmony_ci        par->sample_rate = fmt_info->sample_rate;
1624cabdff1aSopenharmony_ci        par->ch_layout.nb_channels = fmt_info->channels;
1625cabdff1aSopenharmony_ci    }
1626cabdff1aSopenharmony_ci
1627cabdff1aSopenharmony_ci    avpriv_set_pts_info(st, 64, 1, 10000000);
1628cabdff1aSopenharmony_ci
1629cabdff1aSopenharmony_ci    ret = 0;
1630cabdff1aSopenharmony_ci
1631cabdff1aSopenharmony_cierror:
1632cabdff1aSopenharmony_ci    av_freep(&fmt_info);
1633cabdff1aSopenharmony_ci    if (type.pbFormat)
1634cabdff1aSopenharmony_ci        CoTaskMemFree(type.pbFormat);
1635cabdff1aSopenharmony_ci    return ret;
1636cabdff1aSopenharmony_ci}
1637cabdff1aSopenharmony_ci
1638cabdff1aSopenharmony_cistatic int parse_device_name(AVFormatContext *avctx)
1639cabdff1aSopenharmony_ci{
1640cabdff1aSopenharmony_ci    struct dshow_ctx *ctx = avctx->priv_data;
1641cabdff1aSopenharmony_ci    char **device_name = ctx->device_name;
1642cabdff1aSopenharmony_ci    char *name = av_strdup(avctx->url);
1643cabdff1aSopenharmony_ci    char *tmp = name;
1644cabdff1aSopenharmony_ci    int ret = 1;
1645cabdff1aSopenharmony_ci    char *type;
1646cabdff1aSopenharmony_ci
1647cabdff1aSopenharmony_ci    while ((type = strtok(tmp, "="))) {
1648cabdff1aSopenharmony_ci        char *token = strtok(NULL, ":");
1649cabdff1aSopenharmony_ci        tmp = NULL;
1650cabdff1aSopenharmony_ci
1651cabdff1aSopenharmony_ci        if        (!strcmp(type, "video")) {
1652cabdff1aSopenharmony_ci            device_name[0] = token;
1653cabdff1aSopenharmony_ci        } else if (!strcmp(type, "audio")) {
1654cabdff1aSopenharmony_ci            device_name[1] = token;
1655cabdff1aSopenharmony_ci        } else {
1656cabdff1aSopenharmony_ci            device_name[0] = NULL;
1657cabdff1aSopenharmony_ci            device_name[1] = NULL;
1658cabdff1aSopenharmony_ci            break;
1659cabdff1aSopenharmony_ci        }
1660cabdff1aSopenharmony_ci    }
1661cabdff1aSopenharmony_ci
1662cabdff1aSopenharmony_ci    if (!device_name[0] && !device_name[1]) {
1663cabdff1aSopenharmony_ci        ret = 0;
1664cabdff1aSopenharmony_ci    } else {
1665cabdff1aSopenharmony_ci        if (device_name[0])
1666cabdff1aSopenharmony_ci            device_name[0] = av_strdup(device_name[0]);
1667cabdff1aSopenharmony_ci        if (device_name[1])
1668cabdff1aSopenharmony_ci            device_name[1] = av_strdup(device_name[1]);
1669cabdff1aSopenharmony_ci    }
1670cabdff1aSopenharmony_ci
1671cabdff1aSopenharmony_ci    av_free(name);
1672cabdff1aSopenharmony_ci    return ret;
1673cabdff1aSopenharmony_ci}
1674cabdff1aSopenharmony_ci
1675cabdff1aSopenharmony_cistatic int dshow_read_header(AVFormatContext *avctx)
1676cabdff1aSopenharmony_ci{
1677cabdff1aSopenharmony_ci    struct dshow_ctx *ctx = avctx->priv_data;
1678cabdff1aSopenharmony_ci    IGraphBuilder *graph = NULL;
1679cabdff1aSopenharmony_ci    ICreateDevEnum *devenum = NULL;
1680cabdff1aSopenharmony_ci    IMediaControl *control = NULL;
1681cabdff1aSopenharmony_ci    IMediaEvent *media_event = NULL;
1682cabdff1aSopenharmony_ci    HANDLE media_event_handle;
1683cabdff1aSopenharmony_ci    HANDLE proc;
1684cabdff1aSopenharmony_ci    int ret = AVERROR(EIO);
1685cabdff1aSopenharmony_ci    int r;
1686cabdff1aSopenharmony_ci
1687cabdff1aSopenharmony_ci    CoInitialize(0);
1688cabdff1aSopenharmony_ci
1689cabdff1aSopenharmony_ci    if (!ctx->list_devices && !parse_device_name(avctx)) {
1690cabdff1aSopenharmony_ci        av_log(avctx, AV_LOG_ERROR, "Malformed dshow input string.\n");
1691cabdff1aSopenharmony_ci        goto error;
1692cabdff1aSopenharmony_ci    }
1693cabdff1aSopenharmony_ci
1694cabdff1aSopenharmony_ci    ctx->video_codec_id = avctx->video_codec_id ? avctx->video_codec_id
1695cabdff1aSopenharmony_ci                                                : AV_CODEC_ID_RAWVIDEO;
1696cabdff1aSopenharmony_ci    if (ctx->pixel_format != AV_PIX_FMT_NONE) {
1697cabdff1aSopenharmony_ci        if (ctx->video_codec_id != AV_CODEC_ID_RAWVIDEO) {
1698cabdff1aSopenharmony_ci            av_log(avctx, AV_LOG_ERROR, "Pixel format may only be set when "
1699cabdff1aSopenharmony_ci                              "video codec is not set or set to rawvideo\n");
1700cabdff1aSopenharmony_ci            ret = AVERROR(EINVAL);
1701cabdff1aSopenharmony_ci            goto error;
1702cabdff1aSopenharmony_ci        }
1703cabdff1aSopenharmony_ci    }
1704cabdff1aSopenharmony_ci    if (ctx->framerate) {
1705cabdff1aSopenharmony_ci        r = av_parse_video_rate(&ctx->requested_framerate, ctx->framerate);
1706cabdff1aSopenharmony_ci        if (r < 0) {
1707cabdff1aSopenharmony_ci            av_log(avctx, AV_LOG_ERROR, "Could not parse framerate '%s'.\n", ctx->framerate);
1708cabdff1aSopenharmony_ci            goto error;
1709cabdff1aSopenharmony_ci        }
1710cabdff1aSopenharmony_ci    }
1711cabdff1aSopenharmony_ci
1712cabdff1aSopenharmony_ci    r = CoCreateInstance(&CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER,
1713cabdff1aSopenharmony_ci                         &IID_IGraphBuilder, (void **) &graph);
1714cabdff1aSopenharmony_ci    if (r != S_OK) {
1715cabdff1aSopenharmony_ci        av_log(avctx, AV_LOG_ERROR, "Could not create capture graph.\n");
1716cabdff1aSopenharmony_ci        goto error;
1717cabdff1aSopenharmony_ci    }
1718cabdff1aSopenharmony_ci    ctx->graph = graph;
1719cabdff1aSopenharmony_ci
1720cabdff1aSopenharmony_ci    r = CoCreateInstance(&CLSID_SystemDeviceEnum, NULL, CLSCTX_INPROC_SERVER,
1721cabdff1aSopenharmony_ci                         &IID_ICreateDevEnum, (void **) &devenum);
1722cabdff1aSopenharmony_ci    if (r != S_OK) {
1723cabdff1aSopenharmony_ci        av_log(avctx, AV_LOG_ERROR, "Could not enumerate system devices.\n");
1724cabdff1aSopenharmony_ci        goto error;
1725cabdff1aSopenharmony_ci    }
1726cabdff1aSopenharmony_ci
1727cabdff1aSopenharmony_ci    if (ctx->list_devices) {
1728cabdff1aSopenharmony_ci        dshow_cycle_devices(avctx, devenum, VideoDevice, VideoSourceDevice, NULL, NULL, NULL);
1729cabdff1aSopenharmony_ci        dshow_cycle_devices(avctx, devenum, AudioDevice, AudioSourceDevice, NULL, NULL, NULL);
1730cabdff1aSopenharmony_ci        ret = AVERROR_EXIT;
1731cabdff1aSopenharmony_ci        goto error;
1732cabdff1aSopenharmony_ci    }
1733cabdff1aSopenharmony_ci    if (ctx->list_options) {
1734cabdff1aSopenharmony_ci        if (ctx->device_name[VideoDevice])
1735cabdff1aSopenharmony_ci            if ((r = dshow_list_device_options(avctx, devenum, VideoDevice, VideoSourceDevice))) {
1736cabdff1aSopenharmony_ci                ret = r;
1737cabdff1aSopenharmony_ci                goto error;
1738cabdff1aSopenharmony_ci            }
1739cabdff1aSopenharmony_ci        if (ctx->device_name[AudioDevice]) {
1740cabdff1aSopenharmony_ci            if (dshow_list_device_options(avctx, devenum, AudioDevice, AudioSourceDevice)) {
1741cabdff1aSopenharmony_ci                /* show audio options from combined video+audio sources as fallback */
1742cabdff1aSopenharmony_ci                if ((r = dshow_list_device_options(avctx, devenum, AudioDevice, VideoSourceDevice))) {
1743cabdff1aSopenharmony_ci                    ret = r;
1744cabdff1aSopenharmony_ci                    goto error;
1745cabdff1aSopenharmony_ci                }
1746cabdff1aSopenharmony_ci            }
1747cabdff1aSopenharmony_ci        }
1748cabdff1aSopenharmony_ci        // don't exit yet, allow it to list crossbar options in dshow_open_device
1749cabdff1aSopenharmony_ci    }
1750cabdff1aSopenharmony_ci    if (ctx->device_name[VideoDevice]) {
1751cabdff1aSopenharmony_ci        if ((r = dshow_open_device(avctx, devenum, VideoDevice, VideoSourceDevice)) < 0 ||
1752cabdff1aSopenharmony_ci            (r = dshow_add_device(avctx, VideoDevice)) < 0) {
1753cabdff1aSopenharmony_ci            ret = r;
1754cabdff1aSopenharmony_ci            goto error;
1755cabdff1aSopenharmony_ci        }
1756cabdff1aSopenharmony_ci    }
1757cabdff1aSopenharmony_ci    if (ctx->device_name[AudioDevice]) {
1758cabdff1aSopenharmony_ci        if ((r = dshow_open_device(avctx, devenum, AudioDevice, AudioSourceDevice)) < 0 ||
1759cabdff1aSopenharmony_ci            (r = dshow_add_device(avctx, AudioDevice)) < 0) {
1760cabdff1aSopenharmony_ci            av_log(avctx, AV_LOG_INFO, "Searching for audio device within video devices for %s\n", ctx->device_name[AudioDevice]);
1761cabdff1aSopenharmony_ci            /* see if there's a video source with an audio pin with the given audio name */
1762cabdff1aSopenharmony_ci            if ((r = dshow_open_device(avctx, devenum, AudioDevice, VideoSourceDevice)) < 0 ||
1763cabdff1aSopenharmony_ci                (r = dshow_add_device(avctx, AudioDevice)) < 0) {
1764cabdff1aSopenharmony_ci                ret = r;
1765cabdff1aSopenharmony_ci                goto error;
1766cabdff1aSopenharmony_ci            }
1767cabdff1aSopenharmony_ci        }
1768cabdff1aSopenharmony_ci    }
1769cabdff1aSopenharmony_ci    if (ctx->list_options) {
1770cabdff1aSopenharmony_ci        /* allow it to list crossbar options in dshow_open_device */
1771cabdff1aSopenharmony_ci        ret = AVERROR_EXIT;
1772cabdff1aSopenharmony_ci        goto error;
1773cabdff1aSopenharmony_ci    }
1774cabdff1aSopenharmony_ci    ctx->curbufsize[0] = 0;
1775cabdff1aSopenharmony_ci    ctx->curbufsize[1] = 0;
1776cabdff1aSopenharmony_ci    ctx->mutex = CreateMutex(NULL, 0, NULL);
1777cabdff1aSopenharmony_ci    if (!ctx->mutex) {
1778cabdff1aSopenharmony_ci        av_log(avctx, AV_LOG_ERROR, "Could not create Mutex\n");
1779cabdff1aSopenharmony_ci        goto error;
1780cabdff1aSopenharmony_ci    }
1781cabdff1aSopenharmony_ci    ctx->event[1] = CreateEvent(NULL, 1, 0, NULL);
1782cabdff1aSopenharmony_ci    if (!ctx->event[1]) {
1783cabdff1aSopenharmony_ci        av_log(avctx, AV_LOG_ERROR, "Could not create Event\n");
1784cabdff1aSopenharmony_ci        goto error;
1785cabdff1aSopenharmony_ci    }
1786cabdff1aSopenharmony_ci
1787cabdff1aSopenharmony_ci    r = IGraphBuilder_QueryInterface(graph, &IID_IMediaControl, (void **) &control);
1788cabdff1aSopenharmony_ci    if (r != S_OK) {
1789cabdff1aSopenharmony_ci        av_log(avctx, AV_LOG_ERROR, "Could not get media control.\n");
1790cabdff1aSopenharmony_ci        goto error;
1791cabdff1aSopenharmony_ci    }
1792cabdff1aSopenharmony_ci    ctx->control = control;
1793cabdff1aSopenharmony_ci
1794cabdff1aSopenharmony_ci    r = IGraphBuilder_QueryInterface(graph, &IID_IMediaEvent, (void **) &media_event);
1795cabdff1aSopenharmony_ci    if (r != S_OK) {
1796cabdff1aSopenharmony_ci        av_log(avctx, AV_LOG_ERROR, "Could not get media event.\n");
1797cabdff1aSopenharmony_ci        goto error;
1798cabdff1aSopenharmony_ci    }
1799cabdff1aSopenharmony_ci    ctx->media_event = media_event;
1800cabdff1aSopenharmony_ci
1801cabdff1aSopenharmony_ci    r = IMediaEvent_GetEventHandle(media_event, (void *) &media_event_handle);
1802cabdff1aSopenharmony_ci    if (r != S_OK) {
1803cabdff1aSopenharmony_ci        av_log(avctx, AV_LOG_ERROR, "Could not get media event handle.\n");
1804cabdff1aSopenharmony_ci        goto error;
1805cabdff1aSopenharmony_ci    }
1806cabdff1aSopenharmony_ci    proc = GetCurrentProcess();
1807cabdff1aSopenharmony_ci    r = DuplicateHandle(proc, media_event_handle, proc, &ctx->event[0],
1808cabdff1aSopenharmony_ci                        0, 0, DUPLICATE_SAME_ACCESS);
1809cabdff1aSopenharmony_ci    if (!r) {
1810cabdff1aSopenharmony_ci        av_log(avctx, AV_LOG_ERROR, "Could not duplicate media event handle.\n");
1811cabdff1aSopenharmony_ci        goto error;
1812cabdff1aSopenharmony_ci    }
1813cabdff1aSopenharmony_ci
1814cabdff1aSopenharmony_ci    r = IMediaControl_Run(control);
1815cabdff1aSopenharmony_ci    if (r == S_FALSE) {
1816cabdff1aSopenharmony_ci        OAFilterState pfs;
1817cabdff1aSopenharmony_ci        r = IMediaControl_GetState(control, 0, &pfs);
1818cabdff1aSopenharmony_ci    }
1819cabdff1aSopenharmony_ci    if (r != S_OK) {
1820cabdff1aSopenharmony_ci        av_log(avctx, AV_LOG_ERROR, "Could not run graph (sometimes caused by a device already in use by other application)\n");
1821cabdff1aSopenharmony_ci        goto error;
1822cabdff1aSopenharmony_ci    }
1823cabdff1aSopenharmony_ci
1824cabdff1aSopenharmony_ci    ret = 0;
1825cabdff1aSopenharmony_ci
1826cabdff1aSopenharmony_cierror:
1827cabdff1aSopenharmony_ci
1828cabdff1aSopenharmony_ci    if (devenum)
1829cabdff1aSopenharmony_ci        ICreateDevEnum_Release(devenum);
1830cabdff1aSopenharmony_ci
1831cabdff1aSopenharmony_ci    if (ret < 0)
1832cabdff1aSopenharmony_ci        dshow_read_close(avctx);
1833cabdff1aSopenharmony_ci
1834cabdff1aSopenharmony_ci    return ret;
1835cabdff1aSopenharmony_ci}
1836cabdff1aSopenharmony_ci
1837cabdff1aSopenharmony_ci/**
1838cabdff1aSopenharmony_ci * Checks media events from DirectShow and returns -1 on error or EOF. Also
1839cabdff1aSopenharmony_ci * purges all events that might be in the event queue to stop the trigger
1840cabdff1aSopenharmony_ci * of event notification.
1841cabdff1aSopenharmony_ci */
1842cabdff1aSopenharmony_cistatic int dshow_check_event_queue(IMediaEvent *media_event)
1843cabdff1aSopenharmony_ci{
1844cabdff1aSopenharmony_ci    LONG_PTR p1, p2;
1845cabdff1aSopenharmony_ci    long code;
1846cabdff1aSopenharmony_ci    int ret = 0;
1847cabdff1aSopenharmony_ci
1848cabdff1aSopenharmony_ci    while (IMediaEvent_GetEvent(media_event, &code, &p1, &p2, 0) != E_ABORT) {
1849cabdff1aSopenharmony_ci        if (code == EC_COMPLETE || code == EC_DEVICE_LOST || code == EC_ERRORABORT)
1850cabdff1aSopenharmony_ci            ret = -1;
1851cabdff1aSopenharmony_ci        IMediaEvent_FreeEventParams(media_event, code, p1, p2);
1852cabdff1aSopenharmony_ci    }
1853cabdff1aSopenharmony_ci
1854cabdff1aSopenharmony_ci    return ret;
1855cabdff1aSopenharmony_ci}
1856cabdff1aSopenharmony_ci
1857cabdff1aSopenharmony_cistatic int dshow_read_packet(AVFormatContext *s, AVPacket *pkt)
1858cabdff1aSopenharmony_ci{
1859cabdff1aSopenharmony_ci    struct dshow_ctx *ctx = s->priv_data;
1860cabdff1aSopenharmony_ci    PacketListEntry *pktl = NULL;
1861cabdff1aSopenharmony_ci
1862cabdff1aSopenharmony_ci    while (!ctx->eof && !pktl) {
1863cabdff1aSopenharmony_ci        WaitForSingleObject(ctx->mutex, INFINITE);
1864cabdff1aSopenharmony_ci        pktl = ctx->pktl;
1865cabdff1aSopenharmony_ci        if (pktl) {
1866cabdff1aSopenharmony_ci            *pkt = pktl->pkt;
1867cabdff1aSopenharmony_ci            ctx->pktl = ctx->pktl->next;
1868cabdff1aSopenharmony_ci            av_free(pktl);
1869cabdff1aSopenharmony_ci            ctx->curbufsize[pkt->stream_index] -= pkt->size;
1870cabdff1aSopenharmony_ci        }
1871cabdff1aSopenharmony_ci        ResetEvent(ctx->event[1]);
1872cabdff1aSopenharmony_ci        ReleaseMutex(ctx->mutex);
1873cabdff1aSopenharmony_ci        if (!pktl) {
1874cabdff1aSopenharmony_ci            if (dshow_check_event_queue(ctx->media_event) < 0) {
1875cabdff1aSopenharmony_ci                ctx->eof = 1;
1876cabdff1aSopenharmony_ci            } else if (s->flags & AVFMT_FLAG_NONBLOCK) {
1877cabdff1aSopenharmony_ci                return AVERROR(EAGAIN);
1878cabdff1aSopenharmony_ci            } else {
1879cabdff1aSopenharmony_ci                WaitForMultipleObjects(2, ctx->event, 0, INFINITE);
1880cabdff1aSopenharmony_ci            }
1881cabdff1aSopenharmony_ci        }
1882cabdff1aSopenharmony_ci    }
1883cabdff1aSopenharmony_ci
1884cabdff1aSopenharmony_ci    return ctx->eof ? AVERROR(EIO) : pkt->size;
1885cabdff1aSopenharmony_ci}
1886cabdff1aSopenharmony_ci
1887cabdff1aSopenharmony_ci#define OFFSET(x) offsetof(struct dshow_ctx, x)
1888cabdff1aSopenharmony_ci#define DEC AV_OPT_FLAG_DECODING_PARAM
1889cabdff1aSopenharmony_cistatic const AVOption options[] = {
1890cabdff1aSopenharmony_ci    { "video_size", "set video size given a string such as 640x480 or hd720.", OFFSET(requested_width), AV_OPT_TYPE_IMAGE_SIZE, {.str = NULL}, 0, 0, DEC },
1891cabdff1aSopenharmony_ci    { "pixel_format", "set video pixel format", OFFSET(pixel_format), AV_OPT_TYPE_PIXEL_FMT, {.i64 = AV_PIX_FMT_NONE}, -1, INT_MAX, DEC },
1892cabdff1aSopenharmony_ci    { "framerate", "set video frame rate", OFFSET(framerate), AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, DEC },
1893cabdff1aSopenharmony_ci    { "sample_rate", "set audio sample rate", OFFSET(sample_rate), AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT_MAX, DEC },
1894cabdff1aSopenharmony_ci    { "sample_size", "set audio sample size", OFFSET(sample_size), AV_OPT_TYPE_INT, {.i64 = 0}, 0, 16, DEC },
1895cabdff1aSopenharmony_ci    { "channels", "set number of audio channels, such as 1 or 2", OFFSET(channels), AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT_MAX, DEC },
1896cabdff1aSopenharmony_ci    { "audio_buffer_size", "set audio device buffer latency size in milliseconds (default is the device's default)", OFFSET(audio_buffer_size), AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT_MAX, DEC },
1897cabdff1aSopenharmony_ci    { "list_devices", "list available devices",                      OFFSET(list_devices), AV_OPT_TYPE_BOOL, {.i64=0}, 0, 1, DEC },
1898cabdff1aSopenharmony_ci    { "list_options", "list available options for specified device", OFFSET(list_options), AV_OPT_TYPE_BOOL, {.i64=0}, 0, 1, DEC },
1899cabdff1aSopenharmony_ci    { "video_device_number", "set video device number for devices with same name (starts at 0)", OFFSET(video_device_number), AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT_MAX, DEC },
1900cabdff1aSopenharmony_ci    { "audio_device_number", "set audio device number for devices with same name (starts at 0)", OFFSET(audio_device_number), AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT_MAX, DEC },
1901cabdff1aSopenharmony_ci    { "video_pin_name", "select video capture pin by name", OFFSET(video_pin_name),AV_OPT_TYPE_STRING, {.str = NULL},  0, 0, AV_OPT_FLAG_ENCODING_PARAM },
1902cabdff1aSopenharmony_ci    { "audio_pin_name", "select audio capture pin by name", OFFSET(audio_pin_name),AV_OPT_TYPE_STRING, {.str = NULL},  0, 0, AV_OPT_FLAG_ENCODING_PARAM },
1903cabdff1aSopenharmony_ci    { "crossbar_video_input_pin_number", "set video input pin number for crossbar device", OFFSET(crossbar_video_input_pin_number), AV_OPT_TYPE_INT, {.i64 = -1}, -1, INT_MAX, DEC },
1904cabdff1aSopenharmony_ci    { "crossbar_audio_input_pin_number", "set audio input pin number for crossbar device", OFFSET(crossbar_audio_input_pin_number), AV_OPT_TYPE_INT, {.i64 = -1}, -1, INT_MAX, DEC },
1905cabdff1aSopenharmony_ci    { "show_video_device_dialog",              "display property dialog for video capture device",                            OFFSET(show_video_device_dialog),              AV_OPT_TYPE_BOOL, {.i64 = 0}, 0, 1, DEC },
1906cabdff1aSopenharmony_ci    { "show_audio_device_dialog",              "display property dialog for audio capture device",                            OFFSET(show_audio_device_dialog),              AV_OPT_TYPE_BOOL, {.i64 = 0}, 0, 1, DEC },
1907cabdff1aSopenharmony_ci    { "show_video_crossbar_connection_dialog", "display property dialog for crossbar connecting pins filter on video device", OFFSET(show_video_crossbar_connection_dialog), AV_OPT_TYPE_BOOL, {.i64 = 0}, 0, 1, DEC },
1908cabdff1aSopenharmony_ci    { "show_audio_crossbar_connection_dialog", "display property dialog for crossbar connecting pins filter on audio device", OFFSET(show_audio_crossbar_connection_dialog), AV_OPT_TYPE_BOOL, {.i64 = 0}, 0, 1, DEC },
1909cabdff1aSopenharmony_ci    { "show_analog_tv_tuner_dialog",           "display property dialog for analog tuner filter",                             OFFSET(show_analog_tv_tuner_dialog),           AV_OPT_TYPE_BOOL, {.i64 = 0}, 0, 1, DEC },
1910cabdff1aSopenharmony_ci    { "show_analog_tv_tuner_audio_dialog",     "display property dialog for analog tuner audio filter",                       OFFSET(show_analog_tv_tuner_audio_dialog),     AV_OPT_TYPE_BOOL, {.i64 = 0}, 0, 1, DEC },
1911cabdff1aSopenharmony_ci    { "audio_device_load", "load audio capture filter device (and properties) from file", OFFSET(audio_filter_load_file), AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, DEC },
1912cabdff1aSopenharmony_ci    { "audio_device_save", "save audio capture filter device (and properties) to file", OFFSET(audio_filter_save_file), AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, DEC },
1913cabdff1aSopenharmony_ci    { "video_device_load", "load video capture filter device (and properties) from file", OFFSET(video_filter_load_file), AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, DEC },
1914cabdff1aSopenharmony_ci    { "video_device_save", "save video capture filter device (and properties) to file", OFFSET(video_filter_save_file), AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, DEC },
1915cabdff1aSopenharmony_ci    { "use_video_device_timestamps", "use device instead of wallclock timestamps for video frames", OFFSET(use_video_device_timestamps), AV_OPT_TYPE_BOOL, {.i64 = 1}, 0, 1, DEC },
1916cabdff1aSopenharmony_ci    { NULL },
1917cabdff1aSopenharmony_ci};
1918cabdff1aSopenharmony_ci
1919cabdff1aSopenharmony_cistatic const AVClass dshow_class = {
1920cabdff1aSopenharmony_ci    .class_name = "dshow indev",
1921cabdff1aSopenharmony_ci    .item_name  = av_default_item_name,
1922cabdff1aSopenharmony_ci    .option     = options,
1923cabdff1aSopenharmony_ci    .version    = LIBAVUTIL_VERSION_INT,
1924cabdff1aSopenharmony_ci    .category   = AV_CLASS_CATEGORY_DEVICE_VIDEO_INPUT,
1925cabdff1aSopenharmony_ci};
1926cabdff1aSopenharmony_ci
1927cabdff1aSopenharmony_ciconst AVInputFormat ff_dshow_demuxer = {
1928cabdff1aSopenharmony_ci    .name           = "dshow",
1929cabdff1aSopenharmony_ci    .long_name      = NULL_IF_CONFIG_SMALL("DirectShow capture"),
1930cabdff1aSopenharmony_ci    .priv_data_size = sizeof(struct dshow_ctx),
1931cabdff1aSopenharmony_ci    .read_header    = dshow_read_header,
1932cabdff1aSopenharmony_ci    .read_packet    = dshow_read_packet,
1933cabdff1aSopenharmony_ci    .read_close     = dshow_read_close,
1934cabdff1aSopenharmony_ci    .get_device_list= dshow_get_device_list,
1935cabdff1aSopenharmony_ci    .flags          = AVFMT_NOFILE | AVFMT_NOBINSEARCH | AVFMT_NOGENSEARCH | AVFMT_NO_BYTE_SEEK,
1936cabdff1aSopenharmony_ci    .priv_class     = &dshow_class,
1937cabdff1aSopenharmony_ci};
1938