QML 비디오 레코더
Qt Quick 을 사용하여 오디오 및 동영상 녹화하기.
QML 레코더는 마이크, 카메라 또는 화면 캡처를 사용하여 오디오와 비디오를 개별적으로 또는 함께 녹화할 수 있는 간단한 애플리케이션을 보여줍니다.
예제 실행하기
에서 예제를 실행하려면 Qt Creator에서 Welcome 모드를 열고 Examples 에서 예제를 선택합니다. 자세한 내용은 예제 만들기 및 실행하기를 참조하세요.
개요
이 예제의 핵심은 QML 애플리케이션입니다( Qt Quick 으로 프로그래밍 시작하기 참조). 이 문서는 이 예제에서 어떻게 Qt Multimedia QML Types.
이 예에서는 CaptureSession 에 연결된 QML Camera 및 AudioInput 유형을 사용하고 MediaRecorder 객체를 사용하여 캡처된 오디오 및 비디오를 녹화합니다.
QtMultimedia, Qt Quick 의 윈도우, 컨트롤 및 레이아웃 기능을 사용하여 그래픽 사용자 인터페이스와 기능을 구현합니다. 재생은 여기서는 다루지 않으므로 QML 미디어 플레이어 예제를 참조하세요.
이 예제에서는 다음을 보여줍니다:
- 입력 장치를 선택할 수 있습니다.
- 입력 유형이 꺼져 있습니다.
- 화질, 코덱 선택, 파일 형식, 메타데이터 할당 등 캡처를 위한 설정.
- 캡처한 파일이 저장되고 재생할 수 있습니다.
녹화
애플리케이션이 녹화를 구현합니다.
captureSession
main.qml
에서 captureSession
은 다음과 같이 선언됩니다:
CaptureSession { id: captureSession recorder: recorder audioInput: controls.audioInput camera: controls.camera screenCapture: controls.screenCapture windowCapture: controls.windowCapture videoOutput: videoOutput }
recorder
main.qml
에서 MediaRecorder recorder
는 레코딩 미디어를 처리하고 파일의 썸네일을 캡처하여 ListModel, mediaList
에 추가합니다.
MediaRecorder { id: recorder onRecorderStateChanged: (state) => { if (state === MediaRecorder.StoppedState) { root.contentOrientation = Qt.PrimaryOrientation mediaList.append() } else if (state === MediaRecorder.RecordingState && captureSession.camera) { // lock orientation while recording and create a preview image root.contentOrientation = root.screen.orientation; videoOutput.grabToImage(function(res) { mediaList.mediaThumbnail = res.url }) } } onActualLocationChanged: (url) => { mediaList.mediaUrl = url } onErrorOccurred: { recorderErrorText.text = recorder.errorString; recorderError.open(); } }
mediaList
는 Frame mediaListFrame
Frame { id: mediaListFrame height: 150 width: parent.width anchors.bottom: controlsFrame.top x: controls.capturesVisible ? 0 : parent.width background: Rectangle { anchors.fill: parent color: palette.base opacity: 0.8 } Behavior on x { NumberAnimation { duration: 200 } } MediaList { id: mediaList anchors.fill: parent playback: playback
컨트롤
이들은 Controls.qml
에 정의되어 있고 main.qml 에 선언되어 있습니다.
루트는 Columns inputControls
, recordButton
, optionButtons
, 각각 자체 .qml 파일에 정의된 것을 포함하는 Row 입니다.
비디오 소스 선택
VideoSourceSelect.qml
에 정의된 VideoSourceSlect
은 Switch 과 ComboBox 로 구성되어 있으며 사용자가 사용 가능한 카메라 중에서 선택할 수 있습니다.
Row { id: root height: Style.height property Camera selectedCamera: cameraAvailable ? camera : null property ScreenCapture selectedScreenCapture: screenAvailable ? screenCapture : null property WindowCapture selectedWindowCapture: windowAvailable ? windowCapture : null property bool sourceAvailable: typeof comboBox.currentValue !== 'undefined' && comboBox.currentValue.type !== 'toggler' && videoSourceSwitch.checked property bool cameraAvailable: sourceAvailable && comboBox.currentValue.type === 'camera' property bool screenAvailable: sourceAvailable && comboBox.currentValue.type === 'screen' property bool windowAvailable: sourceAvailable && comboBox.currentValue.type === 'window' Component.onCompleted: { videoSourceModel.populate() for (var i = 0; i < videoSourceModel.count; i++) { if (videoSourceModel.get(i).value.type !== 'toggler') { comboBox.currentIndex = i break } } } Camera { id: camera active: cameraAvailable } ScreenCapture { id: screenCapture active: screenAvailable } WindowCapture { id: windowCapture active: windowAvailable } MediaDevices { id: mediaDevices onVideoInputsChanged: { videoSourceModel.populate() for (var i = 0; i < videoSourceModel.count; i++) { if (videoSourceModel.get(i).value.type !== 'toggler') { comboBox.currentIndex = i break } } } } Switch { id: videoSourceSwitch anchors.verticalCenter: parent.verticalCenter checked: true } ListModel { id: videoSourceModel property var enabledSources: { 'camera': true, 'screen': true, 'window': false } function toggleEnabledSource(type) { enabledSources[type] = !enabledSources[type] populate() } function appendItem(text, value) { append({ text: text, value: value}) } function appendToggler(name, sourceType) { appendItem((enabledSources[sourceType] ? "- Hide " : "+ Show ") + name, { type: 'toggler', 'sourceType': sourceType }) } function populate() { clear() appendToggler('Cameras', 'camera') if (enabledSources['camera']) for (var camera of mediaDevices.videoInputs) appendItem(camera.description, { type: 'camera', camera: camera }) appendToggler('Screens', 'screen') if (enabledSources['screen']) for (var screen of Application.screens) appendItem(screen.name, { type: 'screen', screen: screen }) appendToggler('Windows', 'window') if (enabledSources['window']) for (var window of windowCapture.capturableWindows()) appendItem(window.description, { type: 'window', window: window }) } }
comboBox
위의 스니펫에서 선언된 는 현재 비디오 소스를 할당합니다.
ComboBox { id: comboBox width: Style.widthLong height: Style.height background: StyleRectangle { anchors.fill: parent } model: videoSourceModel displayText: typeof currentValue === 'undefined' || currentValue.type === 'toggler' ? "Unavailable" : currentText font.pointSize: Style.fontSize textRole: "text" valueRole: "value" onCurrentValueChanged: { if (typeof currentValue === 'undefined') return if (currentValue.type === 'screen') screenCapture.screen = currentValue.screen else if (currentValue.type === 'camera') camera.cameraDevice = currentValue.camera
오디오 입력 선택
비디오 소스 선택과 동일한 방식으로 구현되며 AudioInputSelect.qml
에 다음과 같이 정의됩니다:
Row { id: root height: Style.height property AudioInput selected: available ? audioInput : null property bool available: (typeof comboBox.currentValue !== 'undefined') && audioSwitch.checked Component.onCompleted: { audioInputModel.populate() comboBox.currentIndex = 0 } MediaDevices { id: mediaDevices } AudioInput { id: audioInput; muted: !audioSwitch.checked } Switch { id: audioSwitch; height: Style.height; checked: true } ListModel { id: audioInputModel property var audioInputs: mediaDevices.audioInputs function populate() { audioInputModel.clear() for (var audioDevice of audioInputs) audioInputModel.append({ text: audioDevice.description, value: { type: 'audioDevice', audioDevice: audioDevice } }) } } ComboBox { id: comboBox width: Style.widthLong height: Style.height background: StyleRectangle { anchors.fill: parent } model: audioInputModel textRole: "text" font.pointSize: Style.fontSize displayText: typeof currentValue === 'undefined' ? "unavailable" : currentText valueRole: "value"
© 2025 The Qt Company Ltd. Documentation contributions included herein are the copyrights of their respective owners. The documentation provided herein is licensed under the terms of the GNU Free Documentation License version 1.3 as published by the Free Software Foundation. Qt and respective logos are trademarks of The Qt Company Ltd. in Finland and/or other countries worldwide. All other trademarks are property of their respective owners.