Result HDevice::Start() { HRESULT hr; if (!EnsureInitialized(L"Start") || !EnsureInactive(L"Start")) return Result::Error; if (!!rocketEncoder) Sleep(ROCKET_WAIT_TIME_MS); hr = control->Run(); if (FAILED(hr)) { if (hr == (HRESULT)0x8007001F) { WarningHR(L"Run failed, device already in use", hr); return Result::InUse; } else { WarningHR(L"Run failed", hr); return Result::Error; } } active = true; return Result::Success; }
static inline bool MapPacketIDs(IBaseFilter *demuxer, ULONG video, ULONG audio) { CComPtr<IPin> videoPin, audioPin; HRESULT hr; if (!GetPinByName(demuxer, PINDIR_OUTPUT, DEMUX_VIDEO_PIN, &videoPin)) { Warning(L"Encoded Device: Could not get video pin from " L"demuxer"); return false; } if (!GetPinByName(demuxer, PINDIR_OUTPUT, DEMUX_AUDIO_PIN, &audioPin)) { Warning(L"Encoded Device: Could not get audio pin from " L"demuxer"); return false; } hr = MapPinToPacketID(videoPin, video); if (FAILED(hr)) { WarningHR(L"Encoded Device: Failed to map demuxer video pin " L"packet ID", hr); return false; } hr = MapPinToPacketID(audioPin, audio); if (FAILED(hr)) { WarningHR(L"Encoded Device: Failed to map demuxer audio pin " L"packet ID", hr); return false; } return true; }
bool EnumDevices(const GUID &type, EnumDeviceCallback callback, void *param) { CComPtr<ICreateDevEnum> deviceEnum; CComPtr<IEnumMoniker> enumMoniker; CComPtr<IMoniker> deviceInfo; HRESULT hr; DWORD count = 0; hr = CoCreateInstance(CLSID_SystemDeviceEnum, NULL, CLSCTX_INPROC_SERVER, IID_ICreateDevEnum, (void**)&deviceEnum); if (FAILED(hr)) { WarningHR(L"EnumAudioDevices: Could not create " L"ICreateDeviceEnum", hr); return false; } hr = deviceEnum->CreateClassEnumerator(type, &enumMoniker, 0); if (FAILED(hr)) { WarningHR(L"EnumAudioDevices: CreateClassEnumerator failed", hr); return false; } if (hr == S_FALSE) return true; while (enumMoniker->Next(1, &deviceInfo, &count) == S_OK) { if (!EnumDevice(deviceInfo, callback, param)) return true; deviceInfo.Release(); } return true; }
bool HVideoEncoder::ConnectFilters() { ComPtr<IPin> deviceIn; ComPtr<IPin> deviceOut; ComPtr<IPin> encoderIn; ComPtr<IPin> encoderOut; bool success; HRESULT hr; success = GetPinByName(device, PINDIR_INPUT, L"YUV In", &deviceIn); if (!success) { Warning(L"Failed to get YUV In pin"); return false; } success = GetPinByName(device, PINDIR_OUTPUT, L"Virtual Video Out", &deviceOut); if (!success) { Warning(L"Failed to get Virtual Video Out pin"); return false; } success = GetPinByName(encoder, PINDIR_INPUT, L"Virtual Video In", &encoderIn); if (!success) { Warning(L"Failed to get encoder input pin"); return false; } success = GetPinByName(encoder, PINDIR_OUTPUT, nullptr, &encoderOut); if (!success) { Warning(L"Failed to get encoder output pin"); return false; } hr = graph->ConnectDirect(output->GetPin(), deviceIn, nullptr); if (FAILED(hr)) { WarningHR(L"Failed to connect output to device", hr); return false; } hr = graph->ConnectDirect(deviceOut, encoderIn, nullptr); if (FAILED(hr)) { WarningHR(L"Failed to connect device to encoder", hr); return false; } hr = graph->ConnectDirect(encoderOut, capture->GetPin(), nullptr); if (FAILED(hr)) { WarningHR(L"Failed to connect encoder to capture", hr); return false; } return true; }
bool SetAvermediaEncoderConfig(IBaseFilter *encoder, VideoEncoderConfig &config) { HRESULT hr; ComQIPtr<IKsPropertySet> propertySet(encoder); if (!propertySet) { Warning(L"Could not get IKsPropertySet for encoder"); return false; } double fps = double(config.fpsNumerator) / double(config.fpsDenominator); hr = SetAVMEncoderSetting(propertySet, AVER_PARAMETER_ENCODE_FRAME_RATE, ULONG(fps), 0); if (FAILED(hr)) { WarningHR(L"Failed to set Avermedia encoder FPS", hr); return false; } hr = SetAVMEncoderSetting(propertySet, AVER_PARAMETER_ENCODE_BIT_RATE, ULONG(config.bitrate), 0); if (FAILED(hr)) { WarningHR(L"Failed to set Avermedia encoder bitrate", hr); return false; } hr = SetAVMEncoderSetting(propertySet, AVER_PARAMETER_CURRENT_RESOLUTION, ULONG(config.cx), ULONG(config.cy)); if (FAILED(hr)) { WarningHR(L"Failed to set Avermedia encoder current res", hr); return false; } hr = SetAVMEncoderSetting(propertySet, AVER_PARAMETER_ENCODE_RESOLUTION, ULONG(config.cx), ULONG(config.cy)); if (FAILED(hr)) { WarningHR(L"Failed to set Avermedia encoder res", hr); return false; } hr = SetAVMEncoderSetting(propertySet, AVER_PARAMETER_ENCODE_GOP, ULONG(config.keyframeInterval), 0); if (FAILED(hr)) { WarningHR(L"Failed to set Avermedia encoder GOP", hr); return false; } return true; }
void Device::OpenDialog(void *hwnd, DialogType type) const { ComPtr<IUnknown> ptr; HRESULT hr; if (type == DialogType::ConfigVideo) { ptr = context->videoFilter; } else if (type == DialogType::ConfigCrossbar || type == DialogType::ConfigCrossbar2) { hr = context->builder->FindInterface(NULL, NULL, context->videoFilter, IID_IAMCrossbar, (void**)&ptr); if (FAILED(hr)) { WarningHR(L"Failed to find crossbar", hr); return; } if (ptr != NULL && type == DialogType::ConfigCrossbar2) { ComQIPtr<IAMCrossbar> xbar(ptr); ComQIPtr<IBaseFilter> filter(xbar); hr = context->builder->FindInterface( &LOOK_UPSTREAM_ONLY, NULL, filter, IID_IAMCrossbar, (void**)&ptr); if (FAILED(hr)) { WarningHR(L"Failed to find crossbar2", hr); return; } } } else if (type == DialogType::ConfigAudio) { ptr = context->audioFilter; } if (!ptr) { Warning(L"Could not find filter to open dialog type: %d with", (int)type); return; } OpenPropertyPages((HWND)hwnd, ptr); }
bool HVideoEncoder::SetConfig(VideoEncoderConfig &config) { ComPtr<IBaseFilter> filter; ComPtr<IBaseFilter> crossbar; if (config.name.empty() && config.path.empty()) { Warning(L"No video encoder name or path specified"); return false; } bool success = GetDeviceFilter(KSCATEGORY_ENCODER, config.name.c_str(), config.path.c_str(), &filter); if (!success) { Warning(L"Video encoder '%s': %s not found", config.name.c_str(), config.path.c_str()); return false; } if (!filter) { Warning(L"Could not get encoder filter"); return false; } this->config = config; if (!SetupEncoder(filter)) { Warning(L"Failed to set up encoder"); return false; } if (!SetupCrossbar()) { Warning(L"Failed to set up crossbar"); return false; } if (!SetAvermediaEncoderConfig(device, config)) { Warning(L"Failed to set Avermedia encoder settings"); return false; } if (!ConnectFilters()) { Warning(L"Failed to connect encoder filters"); return false; } LogFilters(graph); HRESULT hr = control->Run(); if (FAILED(hr)) { WarningHR(L"Run failed", hr); return false; } active = true; return true; }
bool HDevice::RenderFilters(const GUID &category, const GUID &type, IBaseFilter *filter, IBaseFilter *capture) { HRESULT hr; if (!EnsureInitialized(L"HDevice::RenderFilters") || !EnsureInactive(L"HDevice::RenderFilters")) return false; hr = builder->RenderStream(&category, &type, filter, NULL, capture); if (FAILED(hr)) { WarningHR(L"HDevice::ConnectFilters: RenderStream failed", hr); return false; } return true; }
static inline bool CreateFilters(IBaseFilter *filter, IBaseFilter **crossbar, IBaseFilter **encoder, IBaseFilter **demuxer) { CComPtr<IPin> inputPin; CComPtr<IPin> outputPin; REGPINMEDIUM inMedium; REGPINMEDIUM outMedium; bool hasOutMedium; HRESULT hr; if (!GetPinByName(filter, PINDIR_INPUT, nullptr, &inputPin)) { Warning(L"Encoded Device: Failed to get input pin"); return false; } if (!GetPinByName(filter, PINDIR_OUTPUT, nullptr, &outputPin)) { Warning(L"Encoded Device: Failed to get output pin"); return false; } if (!GetPinMedium(inputPin, inMedium)) { Warning(L"Encoded Device: Failed to get input pin medium"); return false; } hasOutMedium = GetPinMedium(outputPin, outMedium); if (!GetFilterByMedium(AM_KSCATEGORY_CROSSBAR, inMedium, crossbar)) { Warning(L"Encoded Device: Failed to get crossbar filter"); return false; } /* perfectly okay if there's no encoder filter, some don't have them */ if (hasOutMedium) GetFilterByMedium(KSCATEGORY_ENCODER, outMedium, encoder); hr = CoCreateInstance(CLSID_MPEG2Demultiplexer, nullptr, CLSCTX_INPROC_SERVER, IID_IBaseFilter, (void**)demuxer); if (FAILED(hr)) { WarningHR(L"Encoded Device: Failed to create demuxer", hr); return false; } return true; }
bool CreateDemuxVideoPin(IBaseFilter *demuxFilter, MediaType &mt, long width, long height, long long frameTime, VideoFormat format) { CComQIPtr<IMpeg2Demultiplexer> demuxer(demuxFilter); if (!demuxer) { Warning(L"CreateDemuxVideoPin: Failed to get " L"IMpeg2Demultiplexer from filter"); return false; } CComPtr<IPin> pin; HRESULT hr; VIDEOINFOHEADER *vih = mt.AllocFormat<VIDEOINFOHEADER>(); vih->bmiHeader.biSize = sizeof(vih->bmiHeader); vih->bmiHeader.biWidth = width; vih->bmiHeader.biHeight = height; vih->bmiHeader.biCompression = VideoFormatToFourCC(format); vih->rcSource.right = height; vih->rcSource.bottom = width; vih->AvgTimePerFrame = frameTime; if (!vih->bmiHeader.biCompression) { Warning(L"CreateDemuxVideoPin: Invalid video format"); return false; } mt->majortype = MEDIATYPE_Video; mt->subtype = VideoFormatToSubType(format); mt->formattype = FORMAT_VideoInfo; mt->bTemporalCompression = true; hr = demuxer->CreateOutputPin(mt, DEMUX_VIDEO_PIN, &pin); if (FAILED(hr)) { WarningHR(L"CreateDemuxVideoPin: Failed to create video pin " L"on demuxer", hr); return false; } return true; }
bool HDevice::ConnectPins(const GUID &category, const GUID &type, IBaseFilter *filter, IBaseFilter *capture) { HRESULT hr; ComPtr<IBaseFilter> crossbar; ComPtr<IPin> filterPin; ComPtr<IPin> capturePin; bool connectCrossbar = !encodedDevice && type == MEDIATYPE_Video; if (!EnsureInitialized(L"HDevice::ConnectPins") || !EnsureInactive(L"HDevice::ConnectPins")) return false; if (connectCrossbar && FindCrossbar(filter, &crossbar)) { if (!DirectConnectFilters(graph, crossbar, filter)) { Warning(L"HDevice::ConnectPins: Failed to connect " L"crossbar"); return false; } } if (!GetFilterPin(filter, type, category, PINDIR_OUTPUT, &filterPin)) { Error(L"HDevice::ConnectPins: Failed to find pin"); return false; } if (!GetPinByName(capture, PINDIR_INPUT, nullptr, &capturePin)) { Error(L"HDevice::ConnectPins: Failed to find capture pin"); return false; } hr = graph->ConnectDirect(filterPin, capturePin, nullptr); if (FAILED(hr)) { WarningHR(L"HDevice::ConnectPins: failed to connect pins", hr); return false; } return true; }
bool CreateDemuxAudioPin(IBaseFilter *demuxFilter, MediaType &mt, DWORD samplesPerSec, WORD bitsPerSample, WORD channels, AudioFormat format) { CComQIPtr<IMpeg2Demultiplexer> demuxer(demuxFilter); if (!demuxer) { Warning(L"CreateDemuxAudioPin: Failed to get " L"IMpeg2Demultiplexer from filter"); return false; } CComPtr<IPin> pin; HRESULT hr; WAVEFORMATEX *wfex = mt.AllocFormat<WAVEFORMATEX>(); wfex->wFormatTag = AudioFormatToFormatTag(format); wfex->nChannels = channels; wfex->nSamplesPerSec = samplesPerSec; wfex->wBitsPerSample = bitsPerSample; if (!wfex->wFormatTag) { Warning(L"CreateDemuxAudioPin: Invalid audio format"); return false; } mt->majortype = MEDIATYPE_Audio; mt->subtype = AudioFormatToSubType(format); mt->formattype = FORMAT_WaveFormatEx; mt->bTemporalCompression = true; hr = demuxer->CreateOutputPin(mt, DEMUX_AUDIO_PIN, &pin); if (FAILED(hr)) { WarningHR(L"CreateDemuxAudioPin: Failed to create audio pin " L"on demuxer", hr); return false; } return true; }
void HDevice::SetAudioBuffering(int bufferingMs) { ComPtr<IPin> pin; bool success = GetFilterPin(audioFilter, MEDIATYPE_Audio, PIN_CATEGORY_CAPTURE, PINDIR_OUTPUT, &pin); if (!success) return; ComQIPtr<IAMStreamConfig> config(pin); if (!config) return; ComQIPtr<IAMBufferNegotiation> neg(pin); if (!neg) return; MediaTypePtr mt; if (FAILED(config->GetFormat(&mt))) return; if (mt->formattype != FORMAT_WaveFormatEx) return; if (mt->cbFormat != sizeof(WAVEFORMATEX)) return; WAVEFORMATEX *wfex = (WAVEFORMATEX*)mt->pbFormat; ALLOCATOR_PROPERTIES props; props.cBuffers = -1; props.cbBuffer = wfex->nAvgBytesPerSec * bufferingMs / 1000; props.cbAlign = -1; props.cbPrefix = -1; HRESULT hr = neg->SuggestAllocatorProperties(&props); if (FAILED(hr)) WarningHR(L"Could not set allocator properties on audio " L"capture pin", hr); }
bool HDevice::SetupExceptionAudioCapture(IPin *pin) { ComPtr<IEnumMediaTypes> enumMediaTypes; ULONG count = 0; HRESULT hr; MediaTypePtr mt; hr = pin->EnumMediaTypes(&enumMediaTypes); if (FAILED(hr)) { WarningHR(L"SetupExceptionAudioCapture: pin->EnumMediaTypes " L"failed", hr); return false; } enumMediaTypes->Reset(); if (enumMediaTypes->Next(1, &mt, &count) == S_OK && mt->formattype == FORMAT_WaveFormatEx) { audioMediaType = mt; return true; } return false; }