Exemple #1
0
DWORD CService::WatcherThreadMemberProc()
{
   DWORD dwWait = 0;
   bool bControlWait = true;

   // Wait for any events to signal
   while(bControlWait)
   {
      dwWait = WaitForMultipleObjects(NUMEVENTS, m_hEvents, FALSE, INFINITE);

      switch(dwWait - WAIT_OBJECT_0)
      {
      case STOP:
         OnStop();
         bControlWait = false;
         break;

      case PAUSE:
         OnPause();
         ResetEvent(m_hEvents[PAUSE]);
         break;

      case CONTINUE:
         OnContinue();
         ResetEvent(m_hEvents[CONTINUE]);
         break;

      case SHUTDOWN:
         OnShutdown();
         bControlWait = false;
         break;
      }
   }
   return 0;
}
//
//   FUNCTION: CServiceBase::Continue()
//
//   PURPOSE: The function resumes normal functioning after being paused if
//   the service supports pause and continue. It calls the OnContinue virtual 
//   function in which you can specify the actions to take when the service 
//   continues. If an error occurs, the error will be logged in the 
//   Application event log, and the service will still be paused.
//
void CServiceBase::Continue()
{
    try
    {
        // Tell SCM that the service is resuming.
        SetServiceStatus(SERVICE_CONTINUE_PENDING);

        // Perform service-specific continue operations.
        OnContinue();

        // Tell SCM that the service is running.
        SetServiceStatus(SERVICE_RUNNING);
    }
    catch (DWORD dwError)
    {
        // Log the error.
        WriteErrorLogEntry(L"Service failed to resume.", dwError);

        // Tell SCM that the service is still paused.
        SetServiceStatus(SERVICE_PAUSED);
    }
    catch (...)
    {
        // Log the error.
        WriteEventLogEntry(L"Service failed to resume.", TRACE_LEVEL_ERROR);

        // Tell SCM that the service is still paused.
        SetServiceStatus(SERVICE_PAUSED);
    }
}
Exemple #3
0
void Service::Run()
{
    // We use a message loop here because this is arguably the easiest
    // way to deal with the potential race conditions that exist between
    // the service thread and the handler thread.  The SCM will make no
    // provisions for synchronizing status activity, the best bet is to
    // ensure that all calls are handled through the service main thread.
    MSG msg;
    while (GetMessage(&msg, NULL, WM_USER, WM_USER) > 0) {
        WPARAM opcode = msg.wParam;
        if (opcode == SERVICE_CONTROL_STOP) {
            SetStatus(SERVICE_STOP_PENDING);
            OnStop();
            break;
        }
        else if (opcode == SERVICE_CONTROL_PAUSE) {
            OnPause();
        }
        else if (opcode == SERVICE_CONTROL_CONTINUE) {
            OnContinue();
        }
        else if (opcode == SERVICE_CONTROL_INTERROGATE) {
            OnInterrogate();
        }
        else if (opcode == SERVICE_CONTROL_SHUTDOWN) {
            OnShutdown();
        }
        ::SetServiceStatus(m_pThis->m_hServiceStatus, &m_pThis->m_Status);
    }
}
Exemple #4
0
void QTE::Continue () {
	if (!mIsStarted || !mIsPaused)
		return;

	mIsPaused = false;

	OnContinue ();
}
Exemple #5
0
DWORD Service::_HandlerEx(DWORD dwOpcode,DWORD dwEventType,LPVOID lpEventData,LPVOID lpContext)
{
	m_dbgMsg(L"Service::Handler(%lu)", dwOpcode);
    switch (dwOpcode) {
    case SERVICE_CONTROL_STOP: // 1
        SetStatus(SERVICE_STOP_PENDING);
        OnStop();
        m_bIsRunning = FALSE;
		EVLOG_INFO(EVMSG_STOPPED);
        break;

    case SERVICE_CONTROL_PAUSE: // 2
        OnPause();
        break;

    case SERVICE_CONTROL_CONTINUE: // 3
        OnContinue();
        break;

    case SERVICE_CONTROL_INTERROGATE: // 4
        OnInterrogate();
        break;

    case SERVICE_CONTROL_SHUTDOWN: // 5
        OnShutdown();
        break;

    case SERVICE_CONTROL_DEVICEEVENT:
        OnDeviceEvent(dwEventType,lpEventData);
        break;

    default:
        if (dwOpcode >= SERVICE_CONTROL_USER) {
            if (!OnUserControl(dwOpcode)) {
				EVLOG_ERROR(EVMSG_BADREQUEST);
            }
        } else {
            EVLOG_ERROR(EVMSG_BADREQUEST);
        }
        break;
    }

    // Report current status
	m_dbgMsg(L"Updating status (%lu, %lu)", m_hServiceStatus, m_Status.dwCurrentState);

    ::SetServiceStatus(m_hServiceStatus, &m_Status);

#ifdef HANDLEREX
    return NO_ERROR;
#endif HANDLEREX
}
Exemple #6
0
bool ServiceBase::OnCommand(DWORD dwControl, DWORD dwEventType, void *lpEventData) {
	TRC(2, ServiceName << ": " << ServiceControlToString(dwControl));

	switch (dwControl) {
	case SERVICE_CONTROL_STOP:
		Stop();
		break;
	case SERVICE_CONTROL_SHUTDOWN:
		Status = SERVICE_STOP_PENDING;
		OnShutdown();
		break;
	case SERVICE_CONTROL_PAUSE:
		Status = SERVICE_PAUSE_PENDING;
		OnPause();
		break;
	case SERVICE_CONTROL_CONTINUE:
		Status = SERVICE_CONTINUE_PENDING;
		OnContinue();
		break;
	case SERVICE_CONTROL_INTERROGATE:
		Status = m_status;
		break;
	case SERVICE_CONTROL_POWEREVENT:
		OnPowerEvent((PowerBroadcastStatus)dwEventType);
		break;
	case SERVICE_CONTROL_SESSIONCHANGE:
		{
			SessionChangeDescription scd = { (SessionChangeReason)dwEventType, (int)((WTSSESSION_NOTIFICATION*)lpEventData)->dwSessionId };
			TRC(2, ReasonToString(scd.Reason));
			OnSessionChange(scd);
		}
		break;
	case SERVICE_CONTROL_PARAMCHANGE:
		OnParamChange();
		break;
	case SERVICE_CONTROL_TIMECHANGE:
		OnTimeChange();
		break;
	case SERVICE_CONTROL_HARDWAREPROFILECHANGE:
		OnHardwareProfileChange();
		break;
	default:
		if (dwControl >= 128 && dwControl <= 255)
			OnCustomCommand(dwControl);
		else
			return false;
	}
	return true;
}
/*++

Routine Description:

    The function resumes normal functioning after being paused if
    the service supports pause and continue. It calls the OnContinue virtual
    function in which you can specify the actions to take when the service
    continues. If an error occurs, the error will be logged in the
    Application event log, and the service will still be paused.

Arguments:

    VOID

Return Value:

    VOID

--*/
VOID
CServiceBase::Continue()
{
    try
    {
        //
        // Tell SCM that the service is resuming.
        //
        SetServiceStatus(SERVICE_CONTINUE_PENDING);

        //
        // Perform service-specific continue operations.
        //
        OnContinue();

        //
        // Tell SCM that the service is running.
        //
        SetServiceStatus(SERVICE_RUNNING);
    }
    catch (DWORD Error)
    {
        //
        // Log the error.
        //
        WriteToErrorLog(L"Service Continue", Error);

        //
        // Tell SCM that the service is still paused.
        //
        SetServiceStatus(SERVICE_PAUSED);
    }
    catch (...)
    {
        //
        // Log the error.
        //
        WriteToEventLog(L"Service failed to resume.", EVENTLOG_ERROR_TYPE);

        //
        // Tell SCM that the service is still paused.
        //
        SetServiceStatus(SERVICE_PAUSED);
    }
}
// The function resumes normal functioning after being paused by calling
// OnContinue virtual function.
void GServiceBase::Continue() {
  try {
    // Tell SCM that the service is resuming.
    SetServiceStatus(SERVICE_CONTINUE_PENDING);

    // Perform service-specific continue operations.
    OnContinue();

    // Tell SCM that the service is running.
    SetServiceStatus(SERVICE_RUNNING);
  } catch (DWORD error) {
    WriteErrorLogEntry(L"Service Continue", error);

    // Tell SCM that the service is still paused.
    SetServiceStatus(SERVICE_PAUSED);
  } catch (...) {
    LogOperationalMessage(L"Service failed to resume.");

    // Tell SCM that the service is still paused.
    SetServiceStatus(SERVICE_PAUSED);
  }
}
Exemple #9
0
GDisAsmView::GDisAsmView(QWidget* parent, EmuThread& emu_thread) : QDockWidget(parent), base_addr(0), emu_thread(emu_thread)
{
    disasm_ui.setupUi(this);

    model = new QStandardItemModel(this);
    model->setColumnCount(3);
    disasm_ui.treeView->setModel(model);

    RegisterHotkey("Disassembler", "Step", QKeySequence(Qt::Key_F10), Qt::ApplicationShortcut);
//    RegisterHotkey("Disassembler", "Step into", QKeySequence(Qt::Key_F11), Qt::ApplicationShortcut);
//    RegisterHotkey("Disassembler", "Pause", QKeySequence(Qt::Key_F5), Qt::ApplicationShortcut);
    RegisterHotkey("Disassembler", "Continue", QKeySequence(Qt::Key_F5), Qt::ApplicationShortcut);
    RegisterHotkey("Disassembler", "Set Breakpoint", QKeySequence(Qt::Key_F9), Qt::ApplicationShortcut);

    connect(disasm_ui.button_breakpoint, SIGNAL(clicked()), this, SLOT(OnSetBreakpoint()));
    connect(disasm_ui.button_step, SIGNAL(clicked()), this, SLOT(OnStep()));
    connect(disasm_ui.button_pause, SIGNAL(clicked()), this, SLOT(OnPause()));
    connect(disasm_ui.button_continue, SIGNAL(clicked()), this, SLOT(OnContinue()));
    connect(GetHotkey("Disassembler", "Step", this), SIGNAL(activated()), this, SLOT(OnStep()));
//    connect(GetHotkey("Disassembler", "Step into", this), SIGNAL(activated()), this, SLOT(OnStepInto()));
//    connect(GetHotkey("Disassembler", "Pause", this), SIGNAL(activated()), this, SLOT(OnPause()));
    connect(GetHotkey("Disassembler", "Continue", this), SIGNAL(activated()), this, SLOT(OnContinue()));
    connect(GetHotkey("Disassembler", "Set Breakpoint", this), SIGNAL(activated()), this, SLOT(OnSetBreakpoint()));
}
Exemple #10
0
PageInput::PageInput(MainWindow* main_window)
	: QWidget(main_window->centralWidget()) {

	m_main_window = main_window;

	m_grabbing = false;
	m_selecting_window = false;

	m_glinject_command = "";
	m_glinject_max_megapixels = 0;

	QGroupBox *group_video = new QGroupBox("Video input", this);
	{
		m_buttongroup_video_area = new QButtonGroup(group_video);
		QRadioButton *radio_area_screen = new QRadioButton("Record the entire screen", group_video);
		QRadioButton *radio_area_fixed = new QRadioButton("Record a fixed rectangle", group_video);
		QRadioButton *radio_area_cursor = new QRadioButton("Follow the cursor", group_video);
		QRadioButton *radio_area_glinject = new QRadioButton("Record OpenGL (experimental)", group_video);
		m_buttongroup_video_area->addButton(radio_area_screen, VIDEO_AREA_SCREEN);
		m_buttongroup_video_area->addButton(radio_area_fixed, VIDEO_AREA_FIXED);
		m_buttongroup_video_area->addButton(radio_area_cursor, VIDEO_AREA_CURSOR);
		m_buttongroup_video_area->addButton(radio_area_glinject, VIDEO_AREA_GLINJECT);
		m_combobox_screens = new QComboBoxWithSignal(group_video);
		m_combobox_screens->setToolTip("Select what monitor should be recorded in a multi-monitor configuration.");
		m_pushbutton_video_select_rectangle = new QPushButton("Select rectangle...", group_video);
		m_pushbutton_video_select_rectangle->setToolTip("Use the mouse to select the recorded rectangle.");
		m_pushbutton_video_select_window = new QPushButton("Select window...", group_video);
		m_pushbutton_video_select_window->setToolTip("Use the mouse to select a window to record.\n"
													 "Hint: If you click the border of a window, the entire window will be recorded (including the borders). Otherwise only\n"
													 "the client area of the window will be recorded.");
		m_pushbutton_video_opengl_settings = new QPushButton("OpenGL settings...", group_video);
		m_pushbutton_video_opengl_settings->setToolTip("Change the settings for OpenGL recording.");
		m_label_video_x = new QLabel("Left:", group_video);
		m_spinbox_video_x = new QSpinBoxWithSignal(group_video);
		m_spinbox_video_x->setRange(0, 10000);
		m_spinbox_video_x->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
		m_spinbox_video_x->setToolTip("The x coordinate of the upper-left corner of the recorded rectangle.\n"
									  "Hint: You can also change this value with the scroll wheel or the up/down arrows.");
		m_label_video_y = new QLabel("Top:", group_video);
		m_spinbox_video_y = new QSpinBoxWithSignal(group_video);
		m_spinbox_video_y->setRange(0, 10000);
		m_spinbox_video_y->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
		m_spinbox_video_y->setToolTip("The y coordinate of the upper-left corner of the recorded rectangle.\n"
									  "Hint: You can also change this value with the scroll wheel or the up/down arrows.");
		m_label_video_w = new QLabel("Width:", group_video);
		m_spinbox_video_w = new QSpinBoxWithSignal(group_video);
		m_spinbox_video_w->setRange(0, 10000);
		m_spinbox_video_w->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
		m_spinbox_video_w->setToolTip("The width of the recorded rectangle.\n"
									  "Hint: You can also change this value with the scroll wheel or the up/down arrows.");
		m_label_video_h = new QLabel("Height:", group_video);
		m_spinbox_video_h = new QSpinBoxWithSignal(group_video);
		m_spinbox_video_h->setRange(0, 10000);
		m_spinbox_video_h->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
		m_spinbox_video_h->setToolTip("The height of the recorded rectangle.\n"
									  "Hint: You can also change this value with the scroll wheel or the up/down arrows.");
		QLabel *label_frame_rate = new QLabel("Frame rate:", group_video);
		m_spinbox_video_frame_rate = new QSpinBox(group_video);
		m_spinbox_video_frame_rate->setRange(1, 1000);
		m_spinbox_video_frame_rate->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
		m_spinbox_video_frame_rate->setToolTip("The number of frames per second in the final video. Higher frame rates use more CPU time.");
		m_checkbox_scale = new QCheckBox("Scale video", group_video);
		m_checkbox_scale->setToolTip("Enable or disable scaling. Scaling uses more CPU time, but if the scaled video is smaller, it could make the encoding faster.");
		m_label_video_scaled_w = new QLabel("Scaled width:", group_video);
		m_spinbox_video_scaled_w = new QSpinBox(group_video);
		m_spinbox_video_scaled_w->setRange(0, 10000);
		m_spinbox_video_scaled_w->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
		m_label_video_scaled_h = new QLabel("Scaled height:", group_video);
		m_spinbox_video_scaled_h = new QSpinBox(group_video);
		m_spinbox_video_scaled_h->setRange(0, 10000);
		m_spinbox_video_scaled_h->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
		m_checkbox_record_cursor = new QCheckBox("Record cursor", group_video);

		connect(m_buttongroup_video_area, SIGNAL(buttonClicked(int)), this, SLOT(OnUpdateVideoAreaFields()));
		connect(m_combobox_screens, SIGNAL(activated(int)), this, SLOT(OnUpdateVideoAreaFields()));
		connect(m_combobox_screens, SIGNAL(popupShown()), this, SLOT(OnIdentifyScreens()));
		connect(m_combobox_screens, SIGNAL(popupHidden()), this, SLOT(OnStopIdentifyScreens()));
		connect(m_spinbox_video_x, SIGNAL(focusIn()), this, SLOT(OnUpdateRecordingFrame()));
		connect(m_spinbox_video_x, SIGNAL(focusOut()), this, SLOT(OnUpdateRecordingFrame()));
		connect(m_spinbox_video_x, SIGNAL(valueChanged(int)), this, SLOT(OnUpdateRecordingFrame()));
		connect(m_spinbox_video_y, SIGNAL(focusIn()), this, SLOT(OnUpdateRecordingFrame()));
		connect(m_spinbox_video_y, SIGNAL(focusOut()), this, SLOT(OnUpdateRecordingFrame()));
		connect(m_spinbox_video_y, SIGNAL(valueChanged(int)), this, SLOT(OnUpdateRecordingFrame()));
		connect(m_spinbox_video_w, SIGNAL(focusIn()), this, SLOT(OnUpdateRecordingFrame()));
		connect(m_spinbox_video_w, SIGNAL(focusOut()), this, SLOT(OnUpdateRecordingFrame()));
		connect(m_spinbox_video_w, SIGNAL(valueChanged(int)), this, SLOT(OnUpdateRecordingFrame()));
		connect(m_spinbox_video_h, SIGNAL(focusIn()), this, SLOT(OnUpdateRecordingFrame()));
		connect(m_spinbox_video_h, SIGNAL(focusOut()), this, SLOT(OnUpdateRecordingFrame()));
		connect(m_spinbox_video_h, SIGNAL(valueChanged(int)), this, SLOT(OnUpdateRecordingFrame()));
		connect(m_pushbutton_video_select_rectangle, SIGNAL(clicked()), this, SLOT(OnStartSelectRectangle()));
		connect(m_pushbutton_video_select_window, SIGNAL(clicked()), this, SLOT(OnStartSelectWindow()));
		connect(m_pushbutton_video_opengl_settings, SIGNAL(clicked()), this, SLOT(OnGLInjectDialog()));
		connect(m_checkbox_scale, SIGNAL(clicked()), this, SLOT(OnUpdateVideoScaleFields()));

		QVBoxLayout *layout = new QVBoxLayout(group_video);
		{
			QHBoxLayout *layout2 = new QHBoxLayout();
			layout->addLayout(layout2);
			layout2->addWidget(radio_area_screen);
			layout2->addWidget(m_combobox_screens);
		}
		layout->addWidget(radio_area_fixed);
		layout->addWidget(radio_area_cursor);
		layout->addWidget(radio_area_glinject);
		{
			QHBoxLayout *layout2 = new QHBoxLayout();
			layout->addLayout(layout2);
			layout2->addWidget(m_pushbutton_video_select_rectangle);
			layout2->addWidget(m_pushbutton_video_select_window);
			layout2->addWidget(m_pushbutton_video_opengl_settings);
			layout2->addStretch();
		}
		{
			QGridLayout *layout2 = new QGridLayout();
			layout->addLayout(layout2);
			layout2->addWidget(m_label_video_x, 0, 0);
			layout2->addWidget(m_spinbox_video_x, 0, 1);
			layout2->addWidget(m_label_video_y, 0, 2);
			layout2->addWidget(m_spinbox_video_y, 0, 3);
			layout2->addWidget(m_label_video_w, 1, 0);
			layout2->addWidget(m_spinbox_video_w, 1, 1);
			layout2->addWidget(m_label_video_h, 1, 2);
			layout2->addWidget(m_spinbox_video_h, 1, 3);
		}
		{
			QGridLayout *layout2 = new QGridLayout();
			layout->addLayout(layout2);
			layout2->addWidget(label_frame_rate, 0, 0);
			layout2->addWidget(m_spinbox_video_frame_rate, 0, 1);
		}
		layout->addWidget(m_checkbox_scale);
		{
			QGridLayout *layout2 = new QGridLayout();
			layout->addLayout(layout2);
			layout2->addWidget(m_label_video_scaled_w, 0, 0);
			layout2->addWidget(m_spinbox_video_scaled_w, 0, 1);
			layout2->addWidget(m_label_video_scaled_h, 0, 2);
			layout2->addWidget(m_spinbox_video_scaled_h, 0, 3);
		}
		layout->addWidget(m_checkbox_record_cursor);
	}
	QGroupBox *group_audio = new QGroupBox("Audio input", this);
	{
		m_checkbox_audio_enable = new QCheckBox("Record microphone", group_audio);
		m_label_audio_backend = new QLabel("Backend:", group_audio);
		m_combobox_audio_backend = new QComboBox(group_audio);
		m_combobox_audio_backend->addItem("ALSA");
		m_combobox_audio_backend->addItem("PulseAudio");
		m_combobox_audio_backend->setToolTip("The audio backend that will be used for recording.\n"
											 "The ALSA backend will also work on systems that use PulseAudio, but it is better to use the PulseAudio backend directly.");
		m_label_alsa_device = new QLabel("Device:", group_audio);
		m_lineedit_alsa_device = new QLineEdit(group_audio);
		m_lineedit_alsa_device->setToolTip("The ALSA device that will be used for recording. Normally this should be 'default'.\n"
										   "You can change this to something like plughw:0,0 (which means sound card 0 input 0 with plugins enabled).");
		m_label_pulseaudio_source = new QLabel("Source:", group_audio);
		m_combobox_pulseaudio_source = new QComboBox(group_audio);
		m_combobox_pulseaudio_source->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
		m_combobox_pulseaudio_source->setToolTip("The PulseAudio source that will be used for recording.\n"
												 "A 'monitor' is a source that records the audio played by other applications.");
		m_pushbutton_pulseaudio_refresh = new QPushButton("Refresh", group_audio);
		m_pushbutton_pulseaudio_refresh->setToolTip("Refreshes the list of PulseAudio sources.");

		connect(m_checkbox_audio_enable, SIGNAL(clicked()), this, SLOT(OnUpdateAudioFields()));
		connect(m_combobox_audio_backend, SIGNAL(activated(int)), this, SLOT(OnUpdateAudioFields()));
		connect(m_pushbutton_pulseaudio_refresh, SIGNAL(clicked()), this, SLOT(OnUpdatePulseAudioSources()));

		QVBoxLayout *layout = new QVBoxLayout(group_audio);
		layout->addWidget(m_checkbox_audio_enable);
		{
			QGridLayout *layout2 = new QGridLayout();
			layout->addLayout(layout2);
			layout2->addWidget(m_label_audio_backend, 0, 0);
			layout2->addWidget(m_combobox_audio_backend, 0, 1, 1, 2);
			layout2->addWidget(m_label_alsa_device, 1, 0);
			layout2->addWidget(m_lineedit_alsa_device, 1, 1, 1, 2);
			layout2->addWidget(m_label_pulseaudio_source, 2, 0);
			layout2->addWidget(m_combobox_pulseaudio_source, 2, 1);
			layout2->addWidget(m_pushbutton_pulseaudio_refresh, 2, 2);
		}
	}
	QPushButton *button_back = new QPushButton(QIcon::fromTheme("go-previous"), "Back", this);
	QPushButton *button_continue = new QPushButton(QIcon::fromTheme("go-next"), "Continue", this);

	connect(button_back, SIGNAL(clicked()), m_main_window, SLOT(GoPageWelcome()));
	connect(button_continue, SIGNAL(clicked()), this, SLOT(OnContinue()));

	QVBoxLayout *layout = new QVBoxLayout(this);
	layout->addWidget(group_video);
	layout->addWidget(group_audio);
	layout->addStretch();
	{
		QHBoxLayout *layout2 = new QHBoxLayout();
		layout->addLayout(layout2);
		layout2->addWidget(button_back);
		layout2->addWidget(button_continue);
	}

	connect(QApplication::desktop(), SIGNAL(screenCountChanged(int)), this, SLOT(OnUpdateScreenConfiguration()));
	connect(QApplication::desktop(), SIGNAL(resized(int)), this, SLOT(OnUpdateScreenConfiguration()));
	LoadScreenConfigurations();
	LoadPulseAudioSources();

	OnUpdateVideoAreaFields();
	OnUpdateVideoScaleFields();
	OnUpdateAudioFields();

}
Exemple #11
0
void GFXDebuggerPanel::CreateGUIControls()
{
	static PauseEventMap map[] = {
		{NEXT_FRAME,                _("Frame")},
		{NEXT_FLUSH,                _("Flush")},

		{NEXT_PIXEL_SHADER_CHANGE,  _("Pixel Shader")},
		{NEXT_VERTEX_SHADER_CHANGE, _("Vertex Shader")},
		{NEXT_TEXTURE_CHANGE,       _("Texture")},
		{NEXT_NEW_TEXTURE,          _("New Texture")},

		{NEXT_XFB_CMD,              _("XFB Cmd")},
		{NEXT_EFB_CMD,              _("EFB Cmd")},

		{NEXT_MATRIX_CMD,           _("Matrix Cmd")},
		{NEXT_VERTEX_CMD,           _("Vertex Cmd")},
		{NEXT_TEXTURE_CMD,          _("Texture Cmd")},
		{NEXT_LIGHT_CMD,            _("Light Cmd")},
		{NEXT_FOG_CMD,              _("Fog Cmd")},

		{NEXT_SET_TLUT,             _("TLUT Cmd")},

		{NEXT_ERROR,                _("Error")}
	};
	pauseEventMap = map;
	const int numPauseEventMap = sizeof(map)/sizeof(PauseEventMap);

	// Basic settings
	CenterOnParent();

	m_pButtonPause = new wxButton(this, ID_PAUSE, _("Pause"), wxDefaultPosition, wxDefaultSize, 0, wxDefaultValidator, _("Pause"));
	m_pButtonPauseAtNext = new wxButton(this, ID_PAUSE_AT_NEXT, _("Pause After"), wxDefaultPosition, wxDefaultSize, 0, wxDefaultValidator, _("Pause At Next"));
	m_pButtonPauseAtNextFrame = new wxButton(this, ID_PAUSE_AT_NEXT_FRAME, _("Go to Next Frame"), wxDefaultPosition, wxDefaultSize, 0, wxDefaultValidator, _("Next Frame"));
	m_pButtonCont = new wxButton(this, ID_CONT, _("Continue"), wxDefaultPosition, wxDefaultSize, 0, wxDefaultValidator, _("Continue"));

	m_pCount = new wxTextCtrl(this, ID_COUNT, "1", wxDefaultPosition, wxSize(50,25), wxTE_RIGHT, wxDefaultValidator, _("Count"));

	m_pPauseAtList = new wxChoice(this, ID_PAUSE_AT_LIST, wxDefaultPosition, wxSize(100,25), 0, nullptr,0,wxDefaultValidator, _("PauseAtList"));
	for (int i=0; i<numPauseEventMap; i++)
	{
		m_pPauseAtList->Append(pauseEventMap[i].ListStr);
	}
	m_pPauseAtList->SetSelection(0);

	m_pButtonDump = new wxButton(this, ID_DUMP, _("Dump"), wxDefaultPosition, wxDefaultSize, 0, wxDefaultValidator, _("Dump"));
	m_pButtonUpdateScreen = new wxButton(this, ID_UPDATE_SCREEN, _("Update Screen"), wxDefaultPosition, wxDefaultSize, 0, wxDefaultValidator, _("Update Screen"));
	m_pButtonClearScreen = new wxButton(this, ID_CLEAR_SCREEN, _("Clear Screen"), wxDefaultPosition, wxDefaultSize, 0, wxDefaultValidator, _("Clear Screen"));
	m_pButtonClearTextureCache = new wxButton(this, ID_CLEAR_TEXTURE_CACHE, _("Clear Textures"), wxDefaultPosition, wxDefaultSize, 0, wxDefaultValidator, _("Clear Textures"));
	m_pButtonClearVertexShaderCache = new wxButton(this, ID_CLEAR_VERTEX_SHADER_CACHE, _("Clear V Shaders"), wxDefaultPosition, wxDefaultSize, 0, wxDefaultValidator, _("Clear V Shaders"));
	m_pButtonClearPixelShaderCache = new wxButton(this, ID_CLEAR_PIXEL_SHADER_CACHE, _("Clear P Shaders"), wxDefaultPosition, wxDefaultSize, 0, wxDefaultValidator, _("Clear P Shaders"));

	m_pDumpList = new wxChoice(this, ID_DUMP_LIST, wxDefaultPosition, wxSize(120,25), 0, nullptr, 0 ,wxDefaultValidator, _("DumpList"));
	m_pDumpList->Insert(_("Pixel Shader"),0);
	m_pDumpList->Append(_("Vertex Shader"));
	m_pDumpList->Append(_("Pixel Shader Constants"));
	m_pDumpList->Append(_("Vertex Shader Constants"));
	m_pDumpList->Append(_("Textures"));
	m_pDumpList->Append(_("Frame Buffer"));
	m_pDumpList->Append(_("Geometry data"));
	m_pDumpList->Append(_("Vertex Description"));
	m_pDumpList->Append(_("Vertex Matrices"));
	m_pDumpList->Append(_("Statistics"));
	m_pDumpList->SetSelection(0);

	// Layout everything on m_MainPanel
	wxBoxSizer *sMain = new wxBoxSizer(wxVERTICAL);

	wxStaticBoxSizer* const pFlowCtrlBox = new wxStaticBoxSizer(wxVERTICAL, this, _("Flow Control"));
	wxBoxSizer* const pPauseAtNextSzr = new wxBoxSizer(wxHORIZONTAL);
	pFlowCtrlBox->Add(m_pButtonPause);
	pPauseAtNextSzr->Add(m_pButtonPauseAtNext);
	pPauseAtNextSzr->Add(m_pCount);
	pPauseAtNextSzr->Add(m_pPauseAtList);
	pFlowCtrlBox->Add(pPauseAtNextSzr);
	pFlowCtrlBox->Add(m_pButtonPauseAtNextFrame);
	pFlowCtrlBox->Add(m_pButtonCont);

	wxStaticBoxSizer* const pDebugBox = new wxStaticBoxSizer(wxVERTICAL, this, _("Debugging"));
	wxBoxSizer* const pDumpSzr = new wxBoxSizer(wxHORIZONTAL);
	pDumpSzr->Add(m_pButtonDump);
	pDumpSzr->Add(m_pDumpList);
	pDebugBox->Add(pDumpSzr);
	wxGridSizer* const pDbgGrid = new wxGridSizer(2, 5, 5);
	pDbgGrid->Add(m_pButtonUpdateScreen);
	pDbgGrid->Add(m_pButtonClearScreen);
	pDbgGrid->Add(m_pButtonClearTextureCache);
	pDbgGrid->Add(m_pButtonClearVertexShaderCache);
	pDbgGrid->Add(m_pButtonClearPixelShaderCache);
	pDebugBox->Add(pDbgGrid);

	sMain->Add(pFlowCtrlBox, 0, 0, 5);
	sMain->Add(pDebugBox, 0, 0, 5);
	SetSizerAndFit(sMain);

	OnContinue();
}
Exemple #12
0
PageInput::PageInput(MainWindow* main_window)
	: QWidget(main_window->centralWidget()) {

	m_main_window = main_window;

	m_grabbing = false;
	m_selecting_window = false;

	m_profile_box = new ProfileBox(this, "input-profiles", &LoadProfileSettingsCallback, &SaveProfileSettingsCallback, this);

	QGroupBox *groupbox_video = new QGroupBox(tr("Video input"), this);
	{
		m_buttongroup_video_area = new QButtonGroup(groupbox_video);
		QRadioButton *radio_area_screen = new QRadioButton(tr("Record the entire screen"), groupbox_video);
		QRadioButton *radio_area_fixed = new QRadioButton(tr("Record a fixed rectangle"), groupbox_video);
		QRadioButton *radio_area_cursor = new QRadioButton(tr("Follow the cursor"), groupbox_video);
		QRadioButton *radio_area_glinject = new QRadioButton(tr("Record OpenGL (experimental)"), groupbox_video);
		m_buttongroup_video_area->addButton(radio_area_screen, VIDEO_AREA_SCREEN);
		m_buttongroup_video_area->addButton(radio_area_fixed, VIDEO_AREA_FIXED);
		m_buttongroup_video_area->addButton(radio_area_cursor, VIDEO_AREA_CURSOR);
		m_buttongroup_video_area->addButton(radio_area_glinject, VIDEO_AREA_GLINJECT);
		m_combobox_screens = new QComboBoxWithSignal(groupbox_video);
		m_combobox_screens->setToolTip(tr("Select what monitor should be recorded in a multi-monitor configuration."));
		m_pushbutton_video_select_rectangle = new QPushButton(tr("Select rectangle..."), groupbox_video);
		m_pushbutton_video_select_rectangle->setToolTip(tr("Use the mouse to select the recorded rectangle."));
		m_pushbutton_video_select_window = new QPushButton(tr("Select window..."), groupbox_video);
		m_pushbutton_video_select_window->setToolTip(tr("Use the mouse to select a window to record.\n"
														"Hint: If you click the border of a window, the entire window will be recorded (including the borders). Otherwise only\n"
														"the client area of the window will be recorded."));
		m_pushbutton_video_opengl_settings = new QPushButton(tr("OpenGL settings..."), groupbox_video);
		m_pushbutton_video_opengl_settings->setToolTip(tr("Change the settings for OpenGL recording."));
		m_label_video_x = new QLabel(tr("Left:"), groupbox_video);
		m_spinbox_video_x = new QSpinBoxWithSignal(groupbox_video);
		m_spinbox_video_x->setRange(0, 10000);
		m_spinbox_video_x->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
		m_spinbox_video_x->setToolTip(tr("The x coordinate of the upper-left corner of the recorded rectangle.\n"
										 "Hint: You can also change this value with the scroll wheel or the up/down arrows."));
		m_label_video_y = new QLabel(tr("Top:"), groupbox_video);
		m_spinbox_video_y = new QSpinBoxWithSignal(groupbox_video);
		m_spinbox_video_y->setRange(0, 10000);
		m_spinbox_video_y->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
		m_spinbox_video_y->setToolTip(tr("The y coordinate of the upper-left corner of the recorded rectangle.\n"
										 "Hint: You can also change this value with the scroll wheel or the up/down arrows."));
		m_label_video_w = new QLabel(tr("Width:"), groupbox_video);
		m_spinbox_video_w = new QSpinBoxWithSignal(groupbox_video);
		m_spinbox_video_w->setRange(0, 10000);
		m_spinbox_video_w->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
		m_spinbox_video_w->setToolTip(tr("The width of the recorded rectangle.\n"
										 "Hint: You can also change this value with the scroll wheel or the up/down arrows."));
		m_label_video_h = new QLabel(tr("Height:"), groupbox_video);
		m_spinbox_video_h = new QSpinBoxWithSignal(groupbox_video);
		m_spinbox_video_h->setRange(0, 10000);
		m_spinbox_video_h->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
		m_spinbox_video_h->setToolTip(tr("The height of the recorded rectangle.\n"
										 "Hint: You can also change this value with the scroll wheel or the up/down arrows."));
		QLabel *label_frame_rate = new QLabel(tr("Frame rate:"), groupbox_video);
		m_spinbox_video_frame_rate = new QSpinBox(groupbox_video);
		m_spinbox_video_frame_rate->setRange(1, 1000);
		m_spinbox_video_frame_rate->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
		m_spinbox_video_frame_rate->setToolTip(tr("The number of frames per second in the final video. Higher frame rates use more CPU time."));
		m_checkbox_scale = new QCheckBox(tr("Scale video"), groupbox_video);
		m_checkbox_scale->setToolTip(tr("Enable or disable scaling. Scaling uses more CPU time, but if the scaled video is smaller, it could make the encoding faster."));
		m_label_video_scaled_w = new QLabel(tr("Scaled width:"), groupbox_video);
		m_spinbox_video_scaled_w = new QSpinBox(groupbox_video);
		m_spinbox_video_scaled_w->setRange(0, 10000);
		m_spinbox_video_scaled_w->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
		m_label_video_scaled_h = new QLabel(tr("Scaled height:"), groupbox_video);
		m_spinbox_video_scaled_h = new QSpinBox(groupbox_video);
		m_spinbox_video_scaled_h->setRange(0, 10000);
		m_spinbox_video_scaled_h->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
		m_checkbox_record_cursor = new QCheckBox(tr("Record cursor"), groupbox_video);

		connect(m_buttongroup_video_area, SIGNAL(buttonClicked(int)), this, SLOT(OnUpdateVideoAreaFields()));
		connect(m_combobox_screens, SIGNAL(activated(int)), this, SLOT(OnUpdateVideoAreaFields()));
		connect(m_combobox_screens, SIGNAL(popupShown()), this, SLOT(OnIdentifyScreens()));
		connect(m_combobox_screens, SIGNAL(popupHidden()), this, SLOT(OnStopIdentifyScreens()));
		connect(m_spinbox_video_x, SIGNAL(focusIn()), this, SLOT(OnUpdateRecordingFrame()));
		connect(m_spinbox_video_x, SIGNAL(focusOut()), this, SLOT(OnUpdateRecordingFrame()));
		connect(m_spinbox_video_x, SIGNAL(valueChanged(int)), this, SLOT(OnUpdateRecordingFrame()));
		connect(m_spinbox_video_y, SIGNAL(focusIn()), this, SLOT(OnUpdateRecordingFrame()));
		connect(m_spinbox_video_y, SIGNAL(focusOut()), this, SLOT(OnUpdateRecordingFrame()));
		connect(m_spinbox_video_y, SIGNAL(valueChanged(int)), this, SLOT(OnUpdateRecordingFrame()));
		connect(m_spinbox_video_w, SIGNAL(focusIn()), this, SLOT(OnUpdateRecordingFrame()));
		connect(m_spinbox_video_w, SIGNAL(focusOut()), this, SLOT(OnUpdateRecordingFrame()));
		connect(m_spinbox_video_w, SIGNAL(valueChanged(int)), this, SLOT(OnUpdateRecordingFrame()));
		connect(m_spinbox_video_h, SIGNAL(focusIn()), this, SLOT(OnUpdateRecordingFrame()));
		connect(m_spinbox_video_h, SIGNAL(focusOut()), this, SLOT(OnUpdateRecordingFrame()));
		connect(m_spinbox_video_h, SIGNAL(valueChanged(int)), this, SLOT(OnUpdateRecordingFrame()));
		connect(m_pushbutton_video_select_rectangle, SIGNAL(clicked()), this, SLOT(OnStartSelectRectangle()));
		connect(m_pushbutton_video_select_window, SIGNAL(clicked()), this, SLOT(OnStartSelectWindow()));
		connect(m_pushbutton_video_opengl_settings, SIGNAL(clicked()), this, SLOT(OnGLInjectDialog()));
		connect(m_checkbox_scale, SIGNAL(clicked()), this, SLOT(OnUpdateVideoScaleFields()));

		QVBoxLayout *layout = new QVBoxLayout(groupbox_video);
		{
			QHBoxLayout *layout2 = new QHBoxLayout();
			layout->addLayout(layout2);
			layout2->addWidget(radio_area_screen);
			layout2->addWidget(m_combobox_screens);
		}
		layout->addWidget(radio_area_fixed);
		layout->addWidget(radio_area_cursor);
		layout->addWidget(radio_area_glinject);
		{
			QHBoxLayout *layout2 = new QHBoxLayout();
			layout->addLayout(layout2);
			layout2->addWidget(m_pushbutton_video_select_rectangle);
			layout2->addWidget(m_pushbutton_video_select_window);
			layout2->addWidget(m_pushbutton_video_opengl_settings);
			layout2->addStretch();
		}
		{
			QGridLayout *layout2 = new QGridLayout();
			layout->addLayout(layout2);
			layout2->addWidget(m_label_video_x, 0, 0);
			layout2->addWidget(m_spinbox_video_x, 0, 1);
			layout2->addWidget(m_label_video_y, 0, 2);
			layout2->addWidget(m_spinbox_video_y, 0, 3);
			layout2->addWidget(m_label_video_w, 1, 0);
			layout2->addWidget(m_spinbox_video_w, 1, 1);
			layout2->addWidget(m_label_video_h, 1, 2);
			layout2->addWidget(m_spinbox_video_h, 1, 3);
		}
		{
			QGridLayout *layout2 = new QGridLayout();
			layout->addLayout(layout2);
			layout2->addWidget(label_frame_rate, 0, 0);
			layout2->addWidget(m_spinbox_video_frame_rate, 0, 1);
		}
		layout->addWidget(m_checkbox_scale);
		{
			QGridLayout *layout2 = new QGridLayout();
			layout->addLayout(layout2);
			layout2->addWidget(m_label_video_scaled_w, 0, 0);
			layout2->addWidget(m_spinbox_video_scaled_w, 0, 1);
			layout2->addWidget(m_label_video_scaled_h, 0, 2);
			layout2->addWidget(m_spinbox_video_scaled_h, 0, 3);
		}
		layout->addWidget(m_checkbox_record_cursor);
	}
	QGroupBox *groupbox_audio = new QGroupBox(tr("Audio input"), this);
	{
		m_checkbox_audio_enable = new QCheckBox(tr("Record audio"), groupbox_audio);
		m_label_audio_backend = new QLabel(tr("Backend:"), groupbox_audio);
		m_combobox_audio_backend = new QComboBox(groupbox_audio);
		m_combobox_audio_backend->addItem("ALSA");
#if SSR_USE_PULSEAUDIO
		m_combobox_audio_backend->addItem("PulseAudio");
#endif
#if SSR_USE_JACK
		m_combobox_audio_backend->addItem("JACK");
#endif
		m_combobox_audio_backend->setToolTip(tr("The audio backend that will be used for recording.\n"
												"The ALSA backend will also work on systems that use PulseAudio, but it is better to use the PulseAudio backend directly."));
		m_label_alsa_source = new QLabel(tr("Source:"), groupbox_audio);
		m_combobox_alsa_source = new QComboBox(groupbox_audio);
		m_combobox_alsa_source->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
		m_combobox_alsa_source->setToolTip(tr("The ALSA source that will be used for recording.\n"
											  "The default is usually fine. The 'shared' sources allow multiple programs to record at the same time, but they may be less reliable."));
		m_pushbutton_alsa_refresh = new QPushButton(tr("Refresh"), groupbox_audio);
		m_pushbutton_alsa_refresh->setToolTip(tr("Refreshes the list of ALSA sources."));
#if SSR_USE_PULSEAUDIO
		m_label_pulseaudio_source = new QLabel(tr("Source:"), groupbox_audio);
		m_combobox_pulseaudio_source = new QComboBox(groupbox_audio);
		m_combobox_pulseaudio_source->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
		m_combobox_pulseaudio_source->setToolTip(tr("The PulseAudio source that will be used for recording.\n"
													"A 'monitor' is a source that records the audio played by other applications.", "Don't translate 'monitor' unless PulseAudio does this as well"));
		m_pushbutton_pulseaudio_refresh = new QPushButton(tr("Refresh"), groupbox_audio);
		m_pushbutton_pulseaudio_refresh->setToolTip(tr("Refreshes the list of PulseAudio sources."));
#endif
#if SSR_USE_JACK
		m_checkbox_jack_connect_system_capture = new QCheckBox(tr("Record system microphone"));
		m_checkbox_jack_connect_system_capture->setToolTip(tr("If checked, the ports will be automatically connected to the system capture ports."));
		m_checkbox_jack_connect_system_playback = new QCheckBox(tr("Record system speakers"));
		m_checkbox_jack_connect_system_playback->setToolTip(tr("If checked, the ports will be automatically connected to anything that connects to the system playback ports."));
#endif

		connect(m_checkbox_audio_enable, SIGNAL(clicked()), this, SLOT(OnUpdateAudioFields()));
		connect(m_combobox_audio_backend, SIGNAL(activated(int)), this, SLOT(OnUpdateAudioFields()));
		connect(m_pushbutton_alsa_refresh, SIGNAL(clicked()), this, SLOT(OnUpdateALSASources()));
#if SSR_USE_PULSEAUDIO
		connect(m_pushbutton_pulseaudio_refresh, SIGNAL(clicked()), this, SLOT(OnUpdatePulseAudioSources()));
#endif

		QVBoxLayout *layout = new QVBoxLayout(groupbox_audio);
		layout->addWidget(m_checkbox_audio_enable);
		{
			QGridLayout *layout2 = new QGridLayout();
			layout->addLayout(layout2);
			layout2->addWidget(m_label_audio_backend, 0, 0);
			layout2->addWidget(m_combobox_audio_backend, 0, 1, 1, 2);
			layout2->addWidget(m_label_alsa_source, 2, 0);
			layout2->addWidget(m_combobox_alsa_source, 2, 1);
			layout2->addWidget(m_pushbutton_alsa_refresh, 2, 2);
#if SSR_USE_PULSEAUDIO
			layout2->addWidget(m_label_pulseaudio_source, 2, 0);
			layout2->addWidget(m_combobox_pulseaudio_source, 2, 1);
			layout2->addWidget(m_pushbutton_pulseaudio_refresh, 2, 2);
#endif
		}
#if SSR_USE_JACK
		{
			QHBoxLayout *layout2 = new QHBoxLayout();
			layout->addLayout(layout2);
			layout2->addWidget(m_checkbox_jack_connect_system_capture);
			layout2->addWidget(m_checkbox_jack_connect_system_playback);
		}
#endif
	}
	QPushButton *button_back = new QPushButton(QIcon::fromTheme("go-previous"), tr("Back"), this);
	QPushButton *button_continue = new QPushButton(QIcon::fromTheme("go-next"), tr("Continue"), this);

	connect(button_back, SIGNAL(clicked()), m_main_window, SLOT(GoPageWelcome()));
	connect(button_continue, SIGNAL(clicked()), this, SLOT(OnContinue()));

	QVBoxLayout *layout = new QVBoxLayout(this);
	layout->addWidget(m_profile_box);
	layout->addWidget(groupbox_video);
	layout->addWidget(groupbox_audio);
	layout->addStretch();
	{
		QHBoxLayout *layout2 = new QHBoxLayout();
		layout->addLayout(layout2);
		layout2->addWidget(button_back);
		layout2->addWidget(button_continue);
	}

	connect(QApplication::desktop(), SIGNAL(screenCountChanged(int)), this, SLOT(OnUpdateScreenConfiguration()));
	connect(QApplication::desktop(), SIGNAL(resized(int)), this, SLOT(OnUpdateScreenConfiguration()));

	LoadScreenConfigurations();
	LoadALSASources();
#if SSR_USE_PULSEAUDIO
	LoadPulseAudioSources();
#endif

	OnUpdateVideoAreaFields();
	OnUpdateVideoScaleFields();
	OnUpdateAudioFields();

}
Exemple #13
0
PageOutput::PageOutput(MainWindow* main_window)
	: QWidget(main_window->centralWidget()) {

	m_main_window = main_window;

	m_old_container = (enum_container) 0;
	m_old_container_av = 0;

	// main codecs
	// (initializer lists should use explicit types for Clang)
	m_containers = {
		ContainerData({"Matroska (MKV)", "matroska", QStringList({"mkv"}), tr("%1 files", "This appears in the file dialog, e.g. 'MP4 files'").arg("Matroska") + " (*.mkv)",
			{VIDEO_CODEC_H264, VIDEO_CODEC_VP8, VIDEO_CODEC_THEORA},
			{AUDIO_CODEC_VORBIS, AUDIO_CODEC_MP3, AUDIO_CODEC_AAC, AUDIO_CODEC_UNCOMPRESSED}}),
		ContainerData({"MP4", "mp4", QStringList({"mp4"}), tr("%1 files", "This appears in the file dialog, e.g. 'MP4 files'").arg("MP4") + " (*.mp4)",
			{VIDEO_CODEC_H264},
			{AUDIO_CODEC_VORBIS, AUDIO_CODEC_MP3, AUDIO_CODEC_AAC}}),
		ContainerData({"WebM", "webm", QStringList({"webm"}), tr("%1 files", "This appears in the file dialog, e.g. 'MP4 files'").arg("WebM") + " (*.webm)",
			{VIDEO_CODEC_VP8},
			{AUDIO_CODEC_VORBIS}}),
		ContainerData({"OGG", "ogg", QStringList({"ogg"}), tr("%1 files", "This appears in the file dialog, e.g. 'MP4 files'").arg("OGG") + " (*.ogg)",
			{VIDEO_CODEC_THEORA},
			{AUDIO_CODEC_VORBIS}}),
		ContainerData({tr("Other..."), "other", QStringList(), "", std::set<enum_video_codec>({}), std::set<enum_audio_codec>({})}),
	};
	m_video_codecs = {
		{"H.264"       , "libx264"  },
		{"VP8"         , "libvpx"   },
		{"Theora"      , "libtheora"},
		{tr("Other..."), "other"    },
	};
	m_audio_codecs = {
		{"Vorbis"          , "libvorbis"   },
		{"MP3"             , "libmp3lame"  },
		{"AAC"             , "libvo_aacenc"},
		{tr("Uncompressed"), "pcm_s16le"   },
		{tr("Other...")    , "other"       },
	};

	// alternative aac codec
	if(!AVCodecIsInstalled(m_audio_codecs[AUDIO_CODEC_AAC].avname)) {
		m_audio_codecs[AUDIO_CODEC_AAC].avname = "aac";
	}

	// load AV container list
	m_containers_av.clear();
	for(AVOutputFormat *format = av_oformat_next(NULL); format != NULL; format = av_oformat_next(format)) {
		if(format->video_codec == AV_CODEC_ID_NONE)
			continue;
		ContainerData c;
		c.name = format->long_name;
		c.avname = format->name;
		c.suffixes = QString(format->extensions).split(',', QString::SkipEmptyParts);
		if(c.suffixes.isEmpty()) {
			c.filter = "";
		} else {
			c.filter = tr("%1 files", "This appears in the file dialog, e.g. 'MP4 files'").arg(c.avname) + " (*." + c.suffixes[0];
			for(int i = 1; i < c.suffixes.size(); ++i) {
				c.suffixes[i] = c.suffixes[i].trimmed(); // needed because libav/ffmpeg isn't very consistent when they say 'comma-separated'
				c.filter += " *." + c.suffixes[i];
			}
			c.filter += ")";
		}
		m_containers_av.push_back(c);
	}
	std::sort(m_containers_av.begin(), m_containers_av.end());

	// load AV codec list
	m_video_codecs_av.clear();
	m_audio_codecs_av.clear();
	for(AVCodec *codec = av_codec_next(NULL); codec != NULL; codec = av_codec_next(codec)) {
		if(!av_codec_is_encoder(codec))
			continue;
		if(codec->type == AVMEDIA_TYPE_VIDEO && VideoEncoder::AVCodecIsSupported(codec->name)) {
			VideoCodecData c;
			c.name = codec->long_name;
			c.avname = codec->name;
			m_video_codecs_av.push_back(c);
		}
		if(codec->type == AVMEDIA_TYPE_AUDIO && AudioEncoder::AVCodecIsSupported(codec->name)) {
			AudioCodecData c;
			c.name = codec->long_name;
			c.avname = codec->name;
			m_audio_codecs_av.push_back(c);
		}
	}
	std::sort(m_video_codecs_av.begin(), m_video_codecs_av.end());
	std::sort(m_audio_codecs_av.begin(), m_audio_codecs_av.end());

	if(m_containers_av.empty()) {
		Logger::LogError("[PageOutput::PageOutput] " + tr("Error: Could not find any suitable container in libavformat!"));
		throw LibavException();
	}
	if(m_video_codecs_av.empty()) {
		Logger::LogError("[PageOutput::PageOutput] " + tr("Error: Could not find any suitable video codec in libavcodec!"));
		throw LibavException();
	}
	if(m_audio_codecs_av.empty()) {
		Logger::LogError("[PageOutput::PageOutput] " + tr("Error: Could not find any suitable audio codec in libavcodec!"));
		throw LibavException();
	}

	m_profile_box = new ProfileBox(this, "output-profiles", &LoadProfileSettingsCallback, &SaveProfileSettingsCallback, this);

	QGroupBox *groupbox_file = new QGroupBox(tr("File"), this);
	{
		QLabel *label_file = new QLabel(tr("Save as:"), groupbox_file);
		m_lineedit_file = new QLineEdit(groupbox_file);
		m_lineedit_file->setToolTip(tr("The recording will be saved to this location."));
		QPushButton *button_browse = new QPushButton(tr("Browse..."), groupbox_file);
		m_checkbox_separate_files = new QCheckBox(tr("Separate file per segment"), groupbox_file);
		m_checkbox_separate_files->setToolTip(tr("If checked, a separate video file will be created every time you pause and resume the recording.\n"
												 "If the original file name is 'test.mkv', the segments will be saved as 'test-YYYY-MM-DD_HH.MM.SS.mkv'."));
		QLabel *label_container = new QLabel(tr("Container:"), groupbox_file);
		m_combobox_container = new QComboBox(groupbox_file);
		for(unsigned int i = 0; i < CONTAINER_COUNT; ++i) {
			QString name = "\u200e" + m_containers[i].name + "\u200e";
			if(i != CONTAINER_OTHER && !AVFormatIsInstalled(m_containers[i].avname))
				name += " \u200e" + tr("(not installed)") + "\u200e";
			m_combobox_container->addItem(name);
		}
		m_combobox_container->setToolTip(tr("The container (file format) that will be used to save the recording.\n"
											"Note that not all codecs are supported by all containers, and that not all media players can read all file formats.\n"
											"- Matroska (MKV) supports all the codecs, but is less well-known.\n"
											"- MP4 is the most well-known format and will play on almost any modern media player, but supports only H.264 video\n"
											"   (and many media players only support AAC audio).\n"
											"- WebM is intended for embedding video into websites (with the HTML5 <video> tag). The format was created by Google.\n"
											"   WebM is supported by default in Firefox, Chrome and Opera, and plugins are available for Internet Explorer and Safari.\n"
											"   It supports only VP8 and Vorbis.\n"
											"- OGG supports only Theora and Vorbis."));
		m_label_container_av = new QLabel(tr("Container name:"), groupbox_file);
		m_combobox_container_av = new QComboBox(groupbox_file);
		for(unsigned int i = 0; i < m_containers_av.size(); ++i) {
			ContainerData &c = m_containers_av[i];
			m_combobox_container_av->addItem(c.avname);
		}
		m_combobox_container_av->setToolTip(tr("For advanced users. You can use any libav/ffmpeg format, but many of them are not useful or may not work."));

		connect(m_combobox_container, SIGNAL(activated(int)), this, SLOT(OnUpdateSuffixAndContainerFields()));
		connect(m_combobox_container_av, SIGNAL(activated(int)), this, SLOT(OnUpdateSuffixAndContainerFields()));
		connect(button_browse, SIGNAL(clicked()), this, SLOT(OnBrowse()));

		QGridLayout *layout = new QGridLayout(groupbox_file);
		layout->addWidget(label_file, 0, 0);
		layout->addWidget(m_lineedit_file, 0, 1);
		layout->addWidget(button_browse, 0, 2);
		layout->addWidget(m_checkbox_separate_files, 1, 0, 1, 3);
		layout->addWidget(label_container, 2, 0);
		layout->addWidget(m_combobox_container, 2, 1, 1, 2);
		layout->addWidget(m_label_container_av, 3, 0);
		layout->addWidget(m_combobox_container_av, 3, 1, 1, 2);
	}
	QGroupBox *groupbox_video = new QGroupBox(tr("Video"), this);
	{
		QLabel *label_video_codec = new QLabel(tr("Codec:"), groupbox_video);
		m_combobox_video_codec = new QComboBox(groupbox_video);
		for(unsigned int i = 0; i < VIDEO_CODEC_COUNT; ++i) {
			m_combobox_video_codec->addItem(m_video_codecs[i].name);
		}
		m_combobox_video_codec->setToolTip(tr("The codec that will be used to compress the video stream.\n"
											  "- H.264 (libx264) is by far the best codec - high quality and very fast.\n"
											  "- VP8 (libvpx) is quite good but also quite slow.\n"
											  "- Theora (libtheora) isn't really recommended because the quality isn't very good."));
		m_label_video_codec_av = new QLabel(tr("Codec name:"), groupbox_video);
		m_combobox_video_codec_av = new QComboBox(groupbox_video);
		for(unsigned int i = 0; i < m_video_codecs_av.size(); ++i) {
			VideoCodecData &c = m_video_codecs_av[i];
			m_combobox_video_codec_av->addItem(c.avname);
		}
		m_combobox_video_codec_av->setToolTip(tr("For advanced users. You can use any libav/ffmpeg video codec, but many of them are not useful or may not work."));
		m_label_video_kbit_rate = new QLabel(tr("Bit rate (in kbps):"), groupbox_video);
		m_lineedit_video_kbit_rate = new QLineEdit(groupbox_video);
		m_lineedit_video_kbit_rate->setToolTip(tr("The video bit rate (in kilobit per second). A higher value means a higher quality."
												  "\nIf you have no idea where to start, try 5000 and change it if needed."));
		m_label_h264_crf = new QLabel(tr("Constant rate factor:", "libx264 setting: don't translate this unless you can come up with something sensible"), groupbox_video);
		m_slider_h264_crf = new QSlider(Qt::Horizontal, groupbox_video);
		m_slider_h264_crf->setRange(0, 51);
		m_slider_h264_crf->setSingleStep(1);
		m_slider_h264_crf->setPageStep(5);
		m_slider_h264_crf->setToolTip(tr("This setting changes the video quality. A lower value means a higher quality.\n"
										 "The allowed range is 0-51 (0 means lossless, the default is 23)."));
		m_label_h264_crf_value = new QLabel(groupbox_video);
		m_label_h264_crf_value->setNum(m_slider_h264_crf->value());
		m_label_h264_crf_value->setAlignment(Qt::AlignRight | Qt::AlignVCenter);
		m_label_h264_crf_value->setMinimumWidth(QFontMetrics(m_label_h264_crf_value->font()).width("99") + 2);
		m_label_h264_preset = new QLabel(tr("Preset:", "libx264 setting: don't translate this unless you can come up with something sensible"), groupbox_video);
		m_combobox_h264_preset = new QComboBox(groupbox_video);
		for(unsigned int i = 0; i < H264_PRESET_COUNT; ++i) {
			m_combobox_h264_preset->addItem(EnumToString((enum_h264_preset) i));
		}
		m_combobox_h264_preset->setToolTip(tr("The encoding speed. A higher speed uses less CPU (making higher recording frame rates possible),\n"
											  "but results in larger files. The quality shouldn't be affected too much."));
		m_label_vp8_cpu_used = new QLabel(tr("CPU used:", "libvpx setting: don't translate this unless you can come up with something sensible"), groupbox_video);
		m_combobox_vp8_cpu_used = new QComboBox(groupbox_video);
		m_combobox_vp8_cpu_used->addItem("5 (" + tr("fastest") + ")");
		m_combobox_vp8_cpu_used->addItem("4");
		m_combobox_vp8_cpu_used->addItem("3");
		m_combobox_vp8_cpu_used->addItem("2");
		m_combobox_vp8_cpu_used->addItem("1");
		m_combobox_vp8_cpu_used->addItem("0 (" + tr("slowest") + ")");
		m_combobox_vp8_cpu_used->setToolTip(tr("The encoding speed. A higher value uses *less* CPU time. (I didn't choose the name, this is the name\n"
											   "used by the VP8 encoder). Higher values result in lower quality video, unless you increase the bit rate too."));
		m_label_video_options = new QLabel(tr("Custom options:"), groupbox_video);
		m_lineedit_video_options = new QLineEdit(groupbox_video);
		m_lineedit_video_options->setToolTip(tr("Custom codec options separated by commas (e.g. option1=value1,option2=value2,option3=value3)"));
		m_checkbox_video_allow_frame_skipping = new QCheckBox(tr("Allow frame skipping"), groupbox_video);
		m_checkbox_video_allow_frame_skipping->setToolTip(tr("If checked, the video encoder will be allowed to skip frames if the input frame rate is\n"
															 "lower than the output frame rate. If not checked, input frames will be duplicated to fill the holes.\n"
															 "This increases the file size and CPU usage, but reduces the latency for live streams in some cases.\n"
															 "It shouldn't affect the appearance of the video."));

		connect(m_combobox_video_codec, SIGNAL(activated(int)), this, SLOT(OnUpdateVideoCodecFields()));
		connect(m_slider_h264_crf, SIGNAL(valueChanged(int)), m_label_h264_crf_value, SLOT(setNum(int)));

		QGridLayout *layout = new QGridLayout(groupbox_video);
		layout->addWidget(label_video_codec, 0, 0);
		layout->addWidget(m_combobox_video_codec, 0, 1, 1, 2);
		layout->addWidget(m_label_video_codec_av, 1, 0);
		layout->addWidget(m_combobox_video_codec_av, 1, 1, 1, 2);
		layout->addWidget(m_label_video_kbit_rate, 2, 0);
		layout->addWidget(m_lineedit_video_kbit_rate, 2, 1, 1, 2);
		layout->addWidget(m_label_h264_crf, 3, 0);
		layout->addWidget(m_slider_h264_crf, 3, 1);
		layout->addWidget(m_label_h264_crf_value, 3, 2);
		layout->addWidget(m_label_h264_preset, 4, 0);
		layout->addWidget(m_combobox_h264_preset, 4, 1, 1, 2);
		layout->addWidget(m_label_vp8_cpu_used, 5, 0);
		layout->addWidget(m_combobox_vp8_cpu_used, 5, 1, 1, 2);
		layout->addWidget(m_label_video_options, 6, 0);
		layout->addWidget(m_lineedit_video_options, 6, 1, 1, 2);
		layout->addWidget(m_checkbox_video_allow_frame_skipping, 7, 0, 1, 3);
	}
	m_groupbox_audio = new QGroupBox(tr("Audio"));
	{
		QLabel *label_audio_codec = new QLabel(tr("Codec:"), m_groupbox_audio);
		m_combobox_audio_codec = new QComboBox(m_groupbox_audio);
		for(unsigned int i = 0; i < AUDIO_CODEC_COUNT; ++i) {
			m_combobox_audio_codec->addItem(m_audio_codecs[i].name);
		}
		m_combobox_audio_codec->setToolTip(tr("The codec that will be used to compress the audio stream. You shouldn't worry too much about\n"
											  "this, because the size of the audio data is usually negligible compared to the size of the video data.\n"
											  "And if you're only recording your own voice (i.e. no music), the quality won't matter that much anyway.\n"
											  "- Vorbis (libvorbis) is great, this is the recommended codec.\n"
											  "- MP3 (libmp3lame) is reasonably good.\n"
											  "- AAC is a good codec, but the implementations used here (libvo_aacenc or the experimental ffmpeg aac encoder)\n"
											  "   are pretty bad. Only use it if you have no other choice.\n"
											  "- Uncompressed will simply store the sound data without compressing it. The file will be quite large, but it's very fast."));
		m_label_audio_codec_av = new QLabel(tr("Codec name:"), m_groupbox_audio);
		m_combobox_audio_codec_av = new QComboBox(m_groupbox_audio);
		for(unsigned int i = 0; i < m_audio_codecs_av.size(); ++i) {
			AudioCodecData &c = m_audio_codecs_av[i];
			m_combobox_audio_codec_av->addItem(c.avname);
		}
		m_combobox_audio_codec_av->setToolTip(tr("For advanced users. You can use any libav/ffmpeg audio codec, but many of them are not useful or may not work."));
		m_label_audio_kbit_rate = new QLabel(tr("Bit rate (in kbps):"), m_groupbox_audio);
		m_lineedit_audio_kbit_rate = new QLineEdit(m_groupbox_audio);
		m_lineedit_audio_kbit_rate->setToolTip(tr("The audio bit rate (in kilobit per second). A higher value means a higher quality. The typical value is 128."));
		m_label_audio_options = new QLabel(tr("Custom options:"), m_groupbox_audio);
		m_lineedit_audio_options = new QLineEdit(m_groupbox_audio);
		m_lineedit_audio_options->setToolTip(tr("Custom codec options separated by commas (e.g. option1=value1,option2=value2,option3=value3)"));

		connect(m_combobox_audio_codec, SIGNAL(activated(int)), this, SLOT(OnUpdateAudioCodecFields()));

		QGridLayout *layout = new QGridLayout(m_groupbox_audio);
		layout->addWidget(label_audio_codec, 0, 0);
		layout->addWidget(m_combobox_audio_codec, 0, 1);
		layout->addWidget(m_label_audio_codec_av, 1, 0);
		layout->addWidget(m_combobox_audio_codec_av, 1, 1);
		layout->addWidget(m_label_audio_kbit_rate, 2, 0);
		layout->addWidget(m_lineedit_audio_kbit_rate, 2, 1);
		layout->addWidget(m_label_audio_options, 3, 0);
		layout->addWidget(m_lineedit_audio_options, 3, 1);
	}
	QPushButton *button_back = new QPushButton(g_icon_go_previous, tr("Back"), this);
	QPushButton *button_continue = new QPushButton(g_icon_go_next, tr("Continue"), this);

	connect(button_back, SIGNAL(clicked()), m_main_window, SLOT(GoPageInput()));
	connect(button_continue, SIGNAL(clicked()), this, SLOT(OnContinue()));

	QVBoxLayout *layout = new QVBoxLayout(this);
	layout->addWidget(m_profile_box);
	layout->addWidget(groupbox_file);
	layout->addWidget(groupbox_video);
	layout->addWidget(m_groupbox_audio);
	layout->addStretch();
	{
		QHBoxLayout *layout2 = new QHBoxLayout();
		layout->addLayout(layout2);
		layout2->addWidget(button_back);
		layout2->addWidget(button_continue);
	}

	OnUpdateContainerFields();
	OnUpdateVideoCodecFields();
	OnUpdateAudioCodecFields();

}