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, &ROPSETID_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, &ROPSETID_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