static int ipc_remove(struct platform_device *pdev) { ipc_stop(); kfree(ipc); return 0; }
int ipc_init(u32 src_width, u32 src_height, enum ipc_2d ipc2d) { if(src_width > IN_SC_MAX_WIDTH || src_height > IN_SC_MAX_HEIGHT) { ipc_err("IPC input size error\n"); ipc_stop(); return -EINVAL; } ipc->src.imghsz = src_width; ipc->src.imgvsz = src_height; ipc->src.srchsz = src_width; ipc->src.srcvsz = src_height; ipc->dst.scanmode = PROGRESSIVE; if(ipc2d == IPC_2D) { ipc->dst.dsthsz = src_width; ipc->dst.dstvsz = src_height * 2; } else { ipc->dst.dsthsz = src_width * 2; ipc->dst.dstvsz = src_height; } ipc->control_var.modeval = ipc2d; clk_enable(ipc->clk); ipc_reset(); ipc_enable(OFF); ipc_enable_postprocessing(OFF); ipc_set_mode(ipc->control_var); ipc_set_imgsize(ipc->src, ipc->dst); ipc_set_enhance_param(); ipc_set_contrast(ipc->enhance_var.contrast); ipc_set_brightness(ipc->enhance_var.brightness); ipc_set_bright_offset(ipc->enhance_var.brightoffset); ipc_set_saturation(ipc->enhance_var.saturation); ipc_set_sharpness(ipc->enhance_var.sharpness, ipc->enhance_var.thhnoise); ipc_set_filter(); ipc_set_pixel_rate(); return 0; }
QSVEncoder(int fps_, int width, int height, int quality, CTSTR preset, bool bUse444, ColorDescription &colorDesc, int maxBitrate, int bufferSize, bool bUseCFR_) : bFirstFrameProcessed(false), width(width), height(height), max_bitrate(maxBitrate) { fps = fps_; bUseCBR = AppConfig->GetInt(TEXT("Video Encoding"), TEXT("UseCBR")) != 0; bUseCFR = bUseCFR_; UINT keyframeInterval = AppConfig->GetInt(TEXT("Video Encoding"), TEXT("KeyframeInterval"), 6); int keyint = fps*keyframeInterval; int bframes = 7; bool bHaveCustomImpl = false; impl_parameters custom = { 0 }; BOOL bUseCustomParams = AppConfig->GetInt(TEXT("Video Encoding"), TEXT("UseCustomSettings")) && AppConfig->GetInt(TEXT("Video Encoding"), TEXT("QSVUseVideoEncoderSettings")); if(bUseCustomParams) { StringList paramList; String strCustomParams = AppConfig->GetString(TEXT("Video Encoding"), TEXT("CustomSettings")); strCustomParams.KillSpaces(); if(strCustomParams.IsValid()) { Log(TEXT("Using custom encoder settings: \"%s\""), strCustomParams.Array()); strCustomParams.GetTokenList(paramList, ' ', FALSE); for(UINT i=0; i<paramList.Num(); i++) { String &strParam = paramList[i]; if(!schr(strParam, '=')) continue; String strParamName = strParam.GetToken(0, '='); String strParamVal = strParam.GetTokenOffset(1, '='); if(strParamName == "keyint") { int keyint_ = strParamVal.ToInt(); if(keyint_ < 0) continue; keyint = keyint_; } else if(strParamName == "bframes") { int bframes_ = strParamVal.ToInt(); if(bframes_ < 0) continue; bframes = bframes_; } else if(strParamName == "qsvimpl") { StringList bits; strParamVal.GetTokenList(bits, ',', true); if(bits.Num() < 3) continue; StringList version; bits[2].GetTokenList(version, '.', false); if(version.Num() != 2) continue; custom.type = bits[0].ToInt(); if(custom.type == 0) custom.type = MFX_IMPL_HARDWARE_ANY; auto &intf = bits[1].MakeLower(); custom.intf = intf == "d3d11" ? MFX_IMPL_VIA_D3D11 : (intf == "d3d9" ? MFX_IMPL_VIA_D3D9 : MFX_IMPL_VIA_ANY); custom.version.Major = version[0].ToInt(); custom.version.Minor = version[1].ToInt(); bHaveCustomImpl = true; } } } } if(!spawn_helper(event_prefix, qsvhelper_process, qsvhelper_thread, process_waiter)) CrashError(TEXT("Couldn't launch QSVHelper: %u"), GetLastError()); ipc_init_request request((event_prefix + INIT_REQUEST).Array()); request->mode = request->MODE_ENCODE; request->obs_process_id = GetCurrentProcessId(); request->fps = fps_; request->keyint = keyint; request->bframes = bframes; request->width = width; request->height = height; request->max_bitrate = maxBitrate; request->buffer_size = bufferSize; request->use_cbr = bUseCBR; request->full_range = colorDesc.fullRange; request->matrix = colorDesc.matrix; request->primaries = colorDesc.primaries; request->transfer = colorDesc.transfer; request->use_custom_impl = bHaveCustomImpl; request->custom_impl = custom.type; request->custom_intf = custom.intf; request->custom_version = custom.version; request.signal(); ipc_init_response response((event_prefix + INIT_RESPONSE).Array()); IPCWaiter response_waiter = process_waiter; response_waiter.push_back(response.signal_); if(response_waiter.wait_for_two(0, 1, INFINITE)) { DWORD code = 0; if(!GetExitCodeProcess(qsvhelper_process.h, &code)) CrashError(TEXT("Failed to initialize QSV session.")); switch(code) { case EXIT_INCOMPATIBLE_CONFIGURATION: CrashError(TEXT("QSVHelper.exe has exited because of an incompatible qsvimpl custom parameter (before response)")); case EXIT_NO_VALID_CONFIGURATION: if(OSGetVersion() < 8) CrashError(TEXT("QSVHelper.exe could not find a valid configuration. Make sure you have a (virtual) display connected to your iGPU")); CrashError(TEXT("QSVHelper.exe could not find a valid configuration")); default: CrashError(TEXT("QSVHelper.exe has exited with code %i (before response)"), code); } } Log(TEXT("------------------------------------------")); if(bHaveCustomImpl && !response->using_custom_impl) AppWarning(TEXT("Could not initialize QSV session using custom settings")); ver = response->version; auto intf_str = qsv_intf_str(response->requested_impl), actual_intf_str = qsv_intf_str(response->actual_impl); auto length = std::distance(std::begin(implStr), std::end(implStr)); auto impl = response->requested_impl & (MFX_IMPL_VIA_ANY - 1); if(impl > length) impl = static_cast<mfxIMPL>(length-1); Log(TEXT("QSV version %u.%u using %s%s (actual: %s%s)"), ver.Major, ver.Minor, implStr[impl], intf_str, implStr[response->actual_impl & (MFX_IMPL_VIA_ANY - 1)], actual_intf_str); target_usage = response->target_usage; encode_tasks.SetSize(response->bitstream_num); bs_buff = ipc_bitstream_buff((event_prefix + BITSTREAM_BUFF).Array(), response->bitstream_size*response->bitstream_num); if(!bs_buff) CrashError(TEXT("Failed to initialize QSV bitstream buffer (%u)"), GetLastError()); mfxU8 *bs_start = (mfxU8*)(((size_t)&bs_buff + 31)/32*32); for(unsigned i = 0; i < encode_tasks.Num(); i++) { zero(encode_tasks[i].surf); mfxBitstream &bs = encode_tasks[i].bs; zero(bs); bs.Data = bs_start + i*response->bitstream_size; bs.MaxLength = response->bitstream_size; idle_tasks << i; } frames.SetSize(response->frame_num); frame_buff = ipc_frame_buff((event_prefix + FRAME_BUFF).Array(), response->frame_size*response->frame_num); if(!frame_buff) CrashError(TEXT("Failed to initialize QSV frame buffer (%u)"), GetLastError()); mfxU8 *frame_start = (mfxU8*)(((size_t)&frame_buff + 15)/16*16); for(unsigned i = 0; i < frames.Num(); i++) { mfxFrameData& frame = frames[i]; zero(frame); frame.Y = frame_start + i * response->frame_size; frame.UV = frame_start + i * response->frame_size + response->UV_offset; frame.V = frame_start + i * response->frame_size + response->V_offset; frame.Pitch = response->frame_pitch; } Log(TEXT("Using %u bitstreams and %u frame buffers"), encode_tasks.Num(), frames.Num()); Log(TEXT("------------------------------------------")); Log(GetInfoString()); Log(TEXT("------------------------------------------")); DataPacket packet; GetHeaders(packet); frame_queue = ipc_frame_queue((event_prefix + FRAME_QUEUE).Array(), frames.Num()); if(!frame_queue) CrashError(TEXT("Failed to initialize frame queue (%u)"), GetLastError()); frame_buff_status = ipc_frame_buff_status((event_prefix + FRAME_BUFF_STATUS).Array(), frames.Num()); if(!frame_buff_status) CrashError(TEXT("Failed to initialize QSV frame buffer status (%u)"), GetLastError()); bs_info = ipc_bitstream_info((event_prefix + BITSTREAM_INFO).Array(), response->bitstream_num); if(!bs_info) CrashError(TEXT("Failed to initialize QSV bitstream info (%u)"), GetLastError()); filled_bitstream = ipc_filled_bitstream((event_prefix + FILLED_BITSTREAM).Array()); if(!filled_bitstream) CrashError(TEXT("Failed to initialize bitstream signal (%u)"), GetLastError()); stop = ipc_stop((event_prefix + STOP_REQUEST).Array()); if(!stop) CrashError(TEXT("Failed to initialize QSV stop signal (%u)"), GetLastError()); filled_bitstream_waiter = process_waiter; filled_bitstream_waiter.push_back(filled_bitstream.signal_); }