diff --git a/src/multimedia/camera/qcameraviewfindersettings.cpp b/src/multimedia/camera/qcameraviewfindersettings.cpp
index 90b61bcf7..fd9c86c7e 100644
--- a/src/multimedia/camera/qcameraviewfindersettings.cpp
+++ b/src/multimedia/camera/qcameraviewfindersettings.cpp
@@ -54,6 +54,9 @@ class QCameraViewfinderSettingsPrivate  : public QSharedData
 public:
     QCameraViewfinderSettingsPrivate() :
         isNull(true),
+#ifdef Q_OS_OPENHARMONY
+        isMirrored(false),
+#endif
         minimumFrameRate(0.0),
         maximumFrameRate(0.0),
         pixelFormat(QVideoFrame::Format_Invalid)
@@ -63,6 +66,9 @@ public:
     QCameraViewfinderSettingsPrivate(const QCameraViewfinderSettingsPrivate &other):
         QSharedData(other),
         isNull(other.isNull),
+#ifdef Q_OS_OPENHARMONY
+        isMirrored(other.isMirrored),
+#endif
         resolution(other.resolution),
         minimumFrameRate(other.minimumFrameRate),
         maximumFrameRate(other.maximumFrameRate),
@@ -72,6 +78,9 @@ public:
     }
 
     bool isNull;
+#ifdef Q_OS_OPENHARMONY
+    bool isMirrored;
+#endif
     QSize resolution;
     qreal minimumFrameRate;
     qreal maximumFrameRate;
@@ -165,6 +174,9 @@ bool operator==(const QCameraViewfinderSettings &lhs, const QCameraViewfinderSet
 {
     return (lhs.d == rhs.d) ||
            (lhs.d->isNull == rhs.d->isNull &&
+#ifdef Q_OS_OPENHARMONY
+            lhs.d->isMirrored == rhs.d->isMirrored &&
+#endif
             lhs.d->resolution == rhs.d->resolution &&
             lhs.d->minimumFrameRate == rhs.d->minimumFrameRate &&
             lhs.d->maximumFrameRate == rhs.d->maximumFrameRate &&
@@ -254,6 +266,18 @@ void QCameraViewfinderSettings::setMinimumFrameRate(qreal rate)
     d->minimumFrameRate = rate;
 }
 
+#ifdef Q_OS_OPENHARMONY
+bool QCameraViewfinderSettings::mirrored()
+{
+    return d->isMirrored;
+}
+
+void QCameraViewfinderSettings::setMirrored(bool mirrored)
+{
+    d->isMirrored = mirrored;
+}
+#endif
+
 /*!
     Returns the viewfinder maximum frame rate in frames per second.
 
diff --git a/src/multimedia/camera/qcameraviewfindersettings.h b/src/multimedia/camera/qcameraviewfindersettings.h
index 432bdcf1f..415de54e1 100644
--- a/src/multimedia/camera/qcameraviewfindersettings.h
+++ b/src/multimedia/camera/qcameraviewfindersettings.h
@@ -77,6 +77,11 @@ public:
     qreal minimumFrameRate() const;
     void setMinimumFrameRate(qreal rate);
 
+#ifdef Q_OS_OPENHARMONY
+    bool mirrored();
+    void setMirrored(bool mirrored);
+#endif
+
     qreal maximumFrameRate() const;
     void setMaximumFrameRate(qreal rate);
 
diff --git a/src/multimedia/playback/qmediaplayer.cpp b/src/multimedia/playback/qmediaplayer.cpp
index 382d8b30b..51ecdcdec 100644
--- a/src/multimedia/playback/qmediaplayer.cpp
+++ b/src/multimedia/playback/qmediaplayer.cpp
@@ -354,10 +354,16 @@ void QMediaPlayerPrivate::setMedia(const QMediaContent &media, QIODevice *stream
     // Backends can't play qrc files directly.
     // If the backend supports StreamPlayback, we pass a QFile for that resource.
     // If it doesn't, we copy the data to a temporary file and pass its path.
-    if (!media.isNull() && !stream && media.request().url().scheme() == QLatin1String("qrc")) {
+    QString scheme = media.request().url().scheme();
+    if (!media.isNull() && !stream && (scheme == QLatin1String("qrc")
+                                       || scheme == QLatin1String("rawfile"))) {
         qrcMedia = media;
 
-        file.reset(new QFile(QLatin1Char(':') + media.request().url().path()));
+        if (scheme == QLatin1String("qrc")) {
+            file.reset(new QFile(QLatin1Char(':') + media.request().url().path()));
+        } else if (scheme == QLatin1String("rawfile")) {
+            file.reset(new QFile(media.request().url().toString()));
+        }
         if (!file->open(QFile::ReadOnly)) {
             QMetaObject::invokeMethod(q, "_q_error", Qt::QueuedConnection,
                                       Q_ARG(int, QMediaPlayer::ResourceError),
diff --git a/src/multimediawidgets/qpaintervideosurface.cpp b/src/multimediawidgets/qpaintervideosurface.cpp
index 5fe76d869..444a32d49 100644
--- a/src/multimediawidgets/qpaintervideosurface.cpp
+++ b/src/multimediawidgets/qpaintervideosurface.cpp
@@ -142,6 +142,7 @@ bool QVideoSurfaceGenericPainter::isFormatSupported(const QVideoSurfaceFormat &f
 QAbstractVideoSurface::Error QVideoSurfaceGenericPainter::start(const QVideoSurfaceFormat &format)
 {
     m_frame = QVideoFrame();
+
     m_imageFormat = QVideoFrame::imageFormatFromPixelFormat(format.pixelFormat());
     // Do not render into ARGB32 images using QPainter.
     // Using QImage::Format_ARGB32_Premultiplied is significantly faster.
@@ -196,7 +197,6 @@ QAbstractVideoSurface::Error QVideoSurfaceGenericPainter::paint(
                 m_imageSize.height(),
                 m_frame.bytesPerLine(),
                 m_imageFormat);
-
         const QTransform oldTransform = painter->transform();
         QTransform transform = oldTransform;
         QRectF targetRect = target;
@@ -216,8 +216,6 @@ QAbstractVideoSurface::Error QVideoSurfaceGenericPainter::paint(
         painter->setTransform(oldTransform);
 
         m_frame.unmap();
-    } else if (m_frame.isValid()) {
-        return QAbstractVideoSurface::IncorrectFormatError;
     } else {
         painter->fillRect(target, Qt::black);
     }
diff --git a/src/multimediawidgets/qvideowidget.cpp b/src/multimediawidgets/qvideowidget.cpp
index 5158b2f35..865fbdba7 100644
--- a/src/multimediawidgets/qvideowidget.cpp
+++ b/src/multimediawidgets/qvideowidget.cpp
@@ -630,9 +630,11 @@ QVideoWidget::QVideoWidget(QVideoWidgetPrivate &dd, QWidget *parent)
 {
     d_ptr->q_ptr = this;
 
+#ifndef Q_OS_OPENHARMONY
     QPalette palette = QWidget::palette();
     palette.setColor(QPalette::Window, Qt::black);
     setPalette(palette);
+#endif
 }
 
 /*!
diff --git a/src/openharmony/native/QtMultiMedia/JsAudioManager.ts b/src/openharmony/native/QtMultiMedia/JsAudioManager.ts
new file mode 100644
index 000000000..a80c8a8c6
--- /dev/null
+++ b/src/openharmony/native/QtMultiMedia/JsAudioManager.ts
@@ -0,0 +1,101 @@
+import audio from '@ohos.multimedia.audio';
+import JsLogger from '../QtCore/JsLogger';
+
+
+export class JsAudioManager {
+    private audioManager: audio.AudioManager = audio.getAudioManager();
+    private routingManager: audio.AudioRoutingManager = this.audioManager.getRoutingManager();
+    private deviceDescript = new Map([
+        [0, "INVALID"], [1, "EARPIECE"], [2, "SPEAKER"], [3, "WIRED_HEADSET"], [4, "WIRED_HEADPHONES"],
+        [7, "BLUETOOTH_SCO"], [8, "BLUETOOTH_A2DP"], [15, "MIC"], [22, "USB_HEADSET"], [1000, "DEFAULT"]
+    ]);
+
+    public constructor() {
+    }
+
+    /* 获取可用的输入设备描述 */
+    private async availableInputDevicesDes() {
+        let devicesDes = await this.routingManager.getDevices(audio.DeviceFlag.INPUT_DEVICES_FLAG);
+        return devicesDes;
+    }
+
+    /* 获取可用的输出设备描述 */
+    private async availableOutputDevicesDes() {
+        let devices = await this.routingManager.getDevices(audio.DeviceFlag.OUTPUT_DEVICES_FLAG);
+        return devices;
+    }
+
+    /* 获取可用的输入设备id值 */
+    async availableInputDevices() {
+        let devices: string = '';//Array<string>作为返回值C++只能获取空值
+        let devDes = await this.availableInputDevicesDes();
+        for (let des of devDes) {
+            if (audio.DeviceType.INVALID != des.deviceType) {
+                devices += des.displayName + '|';
+            }
+        }
+
+        if(devices.length > 0)
+            return devices.slice(0, -1);
+        return devices;
+    }
+    /* 获取可用的输出设备id值 */
+    async availableOutputDevices() {
+        let devices: string = '';//Array<string>作为返回值C++只能获取空值
+        let devDes = await this.availableOutputDevicesDes();
+        for (let des of devDes) {
+            if (audio.DeviceType.INVALID != des.deviceType) {
+                devices += des.displayName + '|';
+            }
+        }
+
+        if(devices.length > 0)
+            return devices.slice(0, -1);
+        return devices;
+    }
+
+    /* 获取指定输入设备支持的通道数 param id---设备id */
+    async inputChannelCounts(name: string) {
+        let devices = await this.availableInputDevicesDes();
+        for (let dev of devices) {
+            if (name === dev.displayName) {
+                return dev.channelCounts.join(',');
+            }
+        }
+        return '';
+    }
+
+    /* 获取指定输出设备支持的通道数 param id---设备id */
+    async outputChannelCounts(name: string) {
+        let devices = await this.availableOutputDevicesDes();
+        for (let dev of devices) {
+            if (name === dev.displayName) {
+                return dev.channelCounts.join(',');
+            }
+        }
+        return '';
+    }
+
+    /* 返回指定输入设备支持的采样率列表 param id---设备id */
+    async inputSupportedSampleRates(name: string) {
+        JsLogger.info("call into inputSupportedSampleRates: %{public}s", name);
+        let devices = await this.availableInputDevicesDes();
+        for (let dev of devices) {
+            if (name === dev.displayName) {
+                JsLogger.info("return: %{public}s", dev.sampleRates.join(','));
+                return dev.sampleRates.join(',');
+            }
+        }
+        return '';
+    }
+    /* 返回输出设备支持的采样率列表 param id---设备id */
+    async outputSupportedSampleRates(name: string) {
+        let devices = await this.availableOutputDevicesDes();
+        for (let dev of devices) {
+            if (name === dev.displayName) {
+                return dev.sampleRates.join(',');
+            }
+        }
+        return '';
+    }
+}
diff --git a/src/openharmony/native/QtMultiMedia/JsCameraManager.ts b/src/openharmony/native/QtMultiMedia/JsCameraManager.ts
new file mode 100644
index 000000000..19f28fc0d
--- /dev/null
+++ b/src/openharmony/native/QtMultiMedia/JsCameraManager.ts
@@ -0,0 +1,56 @@
+import camera from '@ohos.multimedia.camera';
+import JsDataStore from '../QtCore/JsDataStore';
+
+export class JsCameraManager {
+    private cameraDevs = new Map();
+
+    constructor() {
+    }
+
+    private interfaceToObject(data:camera.CameraDevice):any {
+        var cameraInfo = {
+            "cameraId" : data.cameraId,
+            "cameraType" : data.cameraType,
+            "cameraPosition" : data.cameraPosition,
+            "connectionType" : data.connectionType,
+        }
+        return cameraInfo;
+    }
+
+    /* 获取相机设备列表 Array<CameraDevice> */
+    private async cameraDevices() {
+        let cameraManager = await camera.getCameraManager(JsDataStore.getValidContext());
+        let cameras = await cameraManager.getSupportedCameras();
+        for (let dev of cameras) {
+            this.cameraDevs.set(dev.cameraId, dev);
+        }
+        return cameras;
+    }
+
+    /* 获取指定id的相机设备信息 */
+    cameraInfo(id: string): string {
+        if (this.cameraDevs.has(id)) {
+            let info = this.cameraDevs.get(id);
+            var cameraInfo = this.interfaceToObject(info);
+            return JSON.stringify(cameraInfo);
+        }
+        return null;
+    }
+
+    /* 获取相机设备数量 */
+    async idOfCameras() {
+        await this.cameraDevices();
+        return [...this.cameraDevs.keys()];
+    }
+
+    /* 获取相机设备信息的以JSON字符串格式表示 */
+    async jsonOfCameras() {
+        let cameras = await this.cameraDevices();
+        let devices = new Array();
+        for (let dev of cameras) {
+            var cameraInfo = this.interfaceToObject(dev);
+            devices.push(cameraInfo);
+        }
+        return JSON.stringify(devices);
+    }
+}
diff --git a/src/openharmony/native/QtMultiMedia/JsMediaRecorder.ts b/src/openharmony/native/QtMultiMedia/JsMediaRecorder.ts
new file mode 100644
index 000000000..7a3fc0e63
--- /dev/null
+++ b/src/openharmony/native/QtMultiMedia/JsMediaRecorder.ts
@@ -0,0 +1,90 @@
+import media from '@ohos.multimedia.media';
+import { to } from './JsMultimediaUtils';
+
+export class JsMediaRecorder {
+    private mRecorder: media.AVRecorder = null;
+
+    constructor() {
+    }
+
+    private async hasRecorder() {
+        if (null != this.mRecorder) {
+            return true;
+        }
+
+        let [error, record] = await to(media.createAVRecorder());
+        if (null != error) {
+            console.error(`createAVRecorder catchCallback, error:${error}`);
+            return false;
+        }
+        this.mRecorder = record;
+        return true;
+    }
+
+    async release() {
+        if (this.hasRecorder()) {
+            let [error, placeholder] = await to(this.mRecorder.release());
+            if (null != error) {
+                console.error('release AVRecorder failed and catch error is ' + error.message);
+            }
+        }
+    }
+
+    /* NOTE 配置项数据,C++端调用时传入json字符串 */
+    async prepare(configs:string) {
+        if (this.hasRecorder()) {
+            //TODO
+            var obj = JSON.parse(configs);
+            let AVRecorderProfile = {
+                audioBitrate : 48000,
+                audioChannels : 2,
+                audioCodec : media.CodecMimeType.AUDIO_AAC,
+                audioSampleRate : 48000,
+                fileFormat : media.ContainerFormatType.CFT_MPEG_4,
+                videoBitrate : 48000,
+                videoCodec : media.CodecMimeType.VIDEO_MPEG4,
+                videoFrameWidth : 640,
+                videoFrameHeight : 480,
+                videoFrameRate : 30
+            }
+            let AVRecorderConfig = {
+                audioSourceType : media.AudioSourceType.AUDIO_SOURCE_TYPE_MIC,
+                videoSourceType : media.VideoSourceType.VIDEO_SOURCE_TYPE_SURFACE_YUV,
+                profile : AVRecorderProfile,
+                url : 'fd://', // 文件需先由调用者创建,赋予读写权限,将文件fd传给此参数,eg.fd://45
+                rotation : 0, // 合理值0、90、180、270,非合理值prepare接口将报错
+                location : { latitude : 30, longitude : 130 }
+            }
+
+            this.mRecorder.prepare(AVRecorderConfig);
+        }
+    }
+
+    async reset() {
+        if (this.hasRecorder()) {
+            let [error, placeholder] = await to(this.mRecorder.reset());
+            if (null != error) {
+                console.error('reset AVRecorder failed and catch error is ' + error.message);
+            }
+        }
+    }
+
+    async start() {
+        if (this.hasRecorder()) {
+            let [error, placeholder] = await to(this.mRecorder.start());
+            if (null != error) {
+                console.info('start AVRecorder failed and catch error is ' + error.message);
+            }
+        }
+    }
+
+    async stop() {
+        if (this.hasRecorder()) {
+            let [error, placeholder] = await to(this.mRecorder.stop());
+            if (null != error) {
+                console.info('stop AVRecorder failed and error is ' + error.message);
+            }
+        }
+    }
+}
+
diff --git a/src/openharmony/native/QtMultiMedia/JsMultiMediaModule.ets b/src/openharmony/native/QtMultiMedia/JsMultiMediaModule.ets
new file mode 100644
index 000000000..25936f513
--- /dev/null
+++ b/src/openharmony/native/QtMultiMedia/JsMultiMediaModule.ets
@@ -0,0 +1,34 @@
+import { JsQtModule, ObjectBuilder } from '../QtCore/JsQtModule';
+import JsDataStore from '../QtCore/JsDataStore';
+import { JsAudioManager } from './JsAudioManager'
+import { JsMediaRecorder } from './JsMediaRecorder'
+import { JsMultimediaUtils } from './JsMultimediaUtils'
+import { abilityAccessCtrl } from '@kit.AbilityKit';
+import { JsCameraManager } from './JsCameraManager'
+
+class JsMultiMediaModule extends JsQtModule {
+
+  public constructor() {
+    super()
+    this.moduleJsObjects.set("JsAudioManager", new ObjectBuilder<[]>(() =>{
+      return new JsAudioManager();
+    }));
+    this.moduleJsObjects.set("JsMediaRecorder", new ObjectBuilder<[]>(() =>{
+      return new JsMediaRecorder();
+    }));
+    this.moduleJsObjects.set("JsMultimediaUtils", new ObjectBuilder<[]>(() =>{
+      return new JsMultimediaUtils();
+    }));
+    this.moduleJsObjects.set("JsCameraManager", new ObjectBuilder<[]>(() =>{
+      return new JsCameraManager();
+    }));
+  }
+
+  async loadQtModule(): Promise<void> {
+    let atManager: abilityAccessCtrl.AtManager = abilityAccessCtrl.createAtManager();
+    atManager.requestPermissionsFromUser(JsDataStore.getValidContext(), ['ohos.permission.CAMERA',
+      'ohos.permission.MICROPHONE']);
+  }
+}
+
+export default new JsMultiMediaModule;
\ No newline at end of file
diff --git a/src/openharmony/native/QtMultiMedia/JsMultimediaUtils.ts b/src/openharmony/native/QtMultiMedia/JsMultimediaUtils.ts
new file mode 100644
index 000000000..9988d04c6
--- /dev/null
+++ b/src/openharmony/native/QtMultiMedia/JsMultimediaUtils.ts
@@ -0,0 +1,21 @@
+import media from '@ohos.multimedia.media';
+// import mediaLibrary from '@ohos.multimedia.mediaLibrary';
+import JsDataStore from '../QtCore/JsDataStore';
+
+export class JsMultimediaUtils {
+    // private media = mediaLibrary.getMediaLibrary(JsDataStore.getValidContext());
+
+    constructor(){}
+
+    async getMediaDirectory(type:number){
+        // const dictResult = await this.media.getPublicDirectory(type);
+        // return dictResult;
+        return undefined;
+    }
+}
+
+export function to(promise) {
+    return promise.then(data => {
+        return [null, data];
+    }).catch(err => [err]);
+}
diff --git a/src/openharmony/openharmony.pro b/src/openharmony/openharmony.pro
new file mode 100644
index 000000000..597a116d0
--- /dev/null
+++ b/src/openharmony/openharmony.pro
@@ -0,0 +1,10 @@
+TEMPLATE = aux
+
+CONFIG -= qt
+
+templates.files += $$files($$PWD/native/QtMultiMedia/*.ts, true)
+templates.files += $$files($$PWD/native/QtMultiMedia/*.ets, true)
+templates.path = $$[QT_INSTALL_PREFIX]/openharmony/qtmultimedia
+templates.base = $$PWD
+
+INSTALLS += templates
diff --git a/src/plugins/ohaudiodevice/ohaudiodevice.json b/src/plugins/ohaudiodevice/ohaudiodevice.json
new file mode 100644
index 000000000..a31d52107
--- /dev/null
+++ b/src/plugins/ohaudiodevice/ohaudiodevice.json
@@ -0,0 +1,3 @@
+{
+    "Keys": ["default"]
+}
diff --git a/src/plugins/ohaudiodevice/ohaudiodevice.pro b/src/plugins/ohaudiodevice/ohaudiodevice.pro
new file mode 100644
index 000000000..44c297725
--- /dev/null
+++ b/src/plugins/ohaudiodevice/ohaudiodevice.pro
@@ -0,0 +1,27 @@
+TARGET = qtaudio_ohaudiodevice
+QT += multimedia-private core-private
+
+LIBS += -lohaudio -lnative_media_codecbase
+
+HEADERS += \
+    qohaudiodeviceplugin.h \
+    qopenharmonyaudioinput.h \
+    qopenharmonyaudiomanager.h \
+    qopenharmonyaudiooutput.h \
+    qopenharmonydeviceinfo.h \
+    qopenharmonyengine.h
+
+SOURCES += \
+    qohaudiodeviceplugin.cpp \
+    qopenharmonyaudioinput.cpp \
+    qopenharmonyaudiomanager.cpp \
+    qopenharmonyaudiooutput.cpp \
+    qopenharmonydeviceinfo.cpp \
+    qopenharmonyengine.cpp
+
+OTHER_FILES += \
+    ohaudiodevice.json
+
+PLUGIN_TYPE = audio
+PLUGIN_CLASS_NAME = QOHAudioDevicePlugin
+load(qt_plugin)
diff --git a/src/plugins/ohaudiodevice/qohaudiodeviceplugin.cpp b/src/plugins/ohaudiodevice/qohaudiodeviceplugin.cpp
new file mode 100644
index 000000000..10a2535c7
--- /dev/null
+++ b/src/plugins/ohaudiodevice/qohaudiodeviceplugin.cpp
@@ -0,0 +1,82 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qohaudiodeviceplugin.h"
+
+#include "qopenharmonyengine.h"
+#include "qopenharmonydeviceinfo.h"
+#include "qopenharmonyaudioinput.h"
+#include "qopenharmonyaudiooutput.h"
+
+QT_BEGIN_NAMESPACE
+
+QOHAudioDevicePlugin::QOHAudioDevicePlugin(QObject *parent)
+    : QAudioSystemPlugin(parent)
+    , m_engine(QOpenharmonyEngine::instance())
+{
+}
+
+QByteArray QOHAudioDevicePlugin::defaultDevice(QAudio::Mode mode) const
+{
+    return m_engine->defaultDevice(mode);
+}
+
+QList<QByteArray> QOHAudioDevicePlugin::availableDevices(QAudio::Mode mode) const
+{
+    return m_engine->availableDevices(mode);
+}
+
+QAbstractAudioInput *QOHAudioDevicePlugin::createInput(const QByteArray &device)
+{
+    return new QOpenharmonyAudioInput(device);
+}
+
+QAbstractAudioOutput *QOHAudioDevicePlugin::createOutput(const QByteArray &device)
+{
+    return new QOpenharmonyAudioOutput(device);
+
+}
+
+QAbstractAudioDeviceInfo *QOHAudioDevicePlugin::createDeviceInfo(const QByteArray &device, QAudio::Mode mode)
+{
+    return new QOpenharmonyDeviceInfo(device, mode);
+}
+
+QT_END_NAMESPACE
+
diff --git a/src/plugins/ohaudiodevice/qohaudiodeviceplugin.h b/src/plugins/ohaudiodevice/qohaudiodeviceplugin.h
new file mode 100644
index 000000000..0007af767
--- /dev/null
+++ b/src/plugins/ohaudiodevice/qohaudiodeviceplugin.h
@@ -0,0 +1,73 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QOPENSLESPLUGIN_H
+#define QOPENSLESPLUGIN_H
+
+#include <QtMultimedia/qaudiosystemplugin.h>
+#include <QtMultimedia/private/qaudiosystempluginext_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QOpenharmonyEngine;
+
+class QOHAudioDevicePlugin : public QAudioSystemPlugin, public QAudioSystemPluginExtension
+{
+    Q_OBJECT
+
+    Q_PLUGIN_METADATA(IID "org.qt-project.qt.audiosystemfactory/5.0" FILE "ohaudiodevice.json")
+    Q_INTERFACES(QAudioSystemPluginExtension)
+
+public:
+    QOHAudioDevicePlugin(QObject *parent = 0);
+    ~QOHAudioDevicePlugin() {}
+
+    QByteArray defaultDevice(QAudio::Mode mode) const;
+    QList<QByteArray> availableDevices(QAudio::Mode mode) const;
+    QAbstractAudioInput *createInput(const QByteArray &device);
+    QAbstractAudioOutput *createOutput(const QByteArray &device);
+    QAbstractAudioDeviceInfo *createDeviceInfo(const QByteArray &device, QAudio::Mode mode);
+
+private:
+    QOpenharmonyEngine *m_engine;
+};
+
+QT_END_NAMESPACE
+
+#endif // QOPENSLESPLUGIN_H
diff --git a/src/plugins/ohaudiodevice/qopenharmonyaudioinput.cpp b/src/plugins/ohaudiodevice/qopenharmonyaudioinput.cpp
new file mode 100644
index 000000000..106649d5b
--- /dev/null
+++ b/src/plugins/ohaudiodevice/qopenharmonyaudioinput.cpp
@@ -0,0 +1,384 @@
+#include "qopenharmonyaudioinput.h"
+
+#include <qbuffer.h>
+#include <private/qaudiohelpers_p.h>
+#include <qdebug.h>
+#include "qopenharmony.h"
+
+QT_BEGIN_NAMESPACE
+
+#define DEFAULT_PERIOD_TIME_MS 50
+#define MINIMUM_PERIOD_TIME_MS 5
+// 自定义写入数据函数
+static int32_t MyOnReadData(OH_AudioCapturer* capturer, void* userData, void* buffer, int32_t length)
+{
+    Q_UNUSED(capturer)
+    // Process buffer in main thread
+    QByteArray dataArray((char *)buffer, length);
+
+    QMetaObject::invokeMethod(reinterpret_cast<QOpenharmonyAudioInput*>(userData), "processBuffer",\
+                              Q_ARG(QByteArray, dataArray));
+    return 0;
+}
+// 自定义异常回调函数
+static int32_t MyOnError(OH_AudioCapturer* capturer, void* userData, OH_AudioStream_Result error)
+{
+    Q_UNUSED(capturer)
+    Q_UNUSED(userData)
+    qWarning() << "Audio get some error :" << error;
+    // 根据error表示的音频异常信息,做出相应的处理
+    return 0;
+}
+
+QOpenharmonyAudioInput::QOpenharmonyAudioInput(const QByteArray &device)
+    : m_device(device)
+    , m_pullMode(true)
+    , m_processedBytes(0)
+    , m_audioSource(0)
+    , m_bufferIODevice(0)
+    , m_errorState(QAudio::NoError)
+    , m_deviceState(QAudio::StoppedState)
+    , m_lastNotifyTime(0)
+    , m_volume(1.0)
+    , m_intervalTime(1000)
+    ,m_builder(nullptr)
+    ,m_capturer(nullptr)
+{
+
+}
+
+QOpenharmonyAudioInput::~QOpenharmonyAudioInput()
+{
+}
+
+void QOpenharmonyAudioInput::start(QIODevice *device)
+{
+    if (m_deviceState != QAudio::StoppedState)
+        stopRecording();
+
+    if (!m_pullMode && m_bufferIODevice) {
+        m_bufferIODevice->close();
+        delete m_bufferIODevice;
+        m_bufferIODevice = 0;
+    }
+
+    m_pullMode = true;
+    m_audioSource = device;
+
+    if (startRecording()) {
+        m_deviceState = QAudio::ActiveState;
+    } else {
+        m_deviceState = QAudio::StoppedState;
+        Q_EMIT errorChanged(m_errorState);
+    }
+
+    Q_EMIT stateChanged(m_deviceState);
+}
+
+QIODevice *QOpenharmonyAudioInput::start()
+{
+    if (m_deviceState != QAudio::StoppedState)
+        stopRecording();
+
+    m_audioSource = 0;
+
+    if (!m_pullMode && m_bufferIODevice) {
+        m_bufferIODevice->close();
+        delete m_bufferIODevice;
+    }
+
+    m_pullMode = false;
+    m_pushBuffer.clear();
+    m_bufferIODevice = new QBuffer(&m_pushBuffer);
+    m_bufferIODevice->open(QIODevice::ReadOnly);
+
+    if (startRecording()) {
+        m_deviceState = QAudio::IdleState;
+    } else {
+        m_deviceState = QAudio::StoppedState;
+        Q_EMIT errorChanged(m_errorState);
+    }
+
+    Q_EMIT stateChanged(m_deviceState);
+    return m_bufferIODevice;
+}
+
+void QOpenharmonyAudioInput::stop()
+{
+    if (m_deviceState == QAudio::StoppedState)
+        return;
+
+    m_deviceState = QAudio::StoppedState;
+
+    stopRecording();
+
+    m_errorState = QAudio::NoError;
+    Q_EMIT stateChanged(m_deviceState);
+}
+
+void QOpenharmonyAudioInput::reset()
+{
+    stop();
+}
+
+void QOpenharmonyAudioInput::suspend()
+{
+    if (m_deviceState != QAudio::ActiveState) {
+        return;
+    }
+    m_deviceState = QAudio::SuspendedState;
+    emit stateChanged(m_deviceState);
+
+    OH_AudioCapturer_Pause(m_capturer);//暂停录制
+}
+
+void QOpenharmonyAudioInput::resume()
+{
+    if (m_deviceState == QAudio::SuspendedState || m_deviceState == QAudio::IdleState) {
+        OH_AudioCapturer_Start(m_capturer);//开始录制
+
+        m_deviceState = QAudio::ActiveState;
+        emit stateChanged(m_deviceState);
+    }
+}
+
+int QOpenharmonyAudioInput::bytesReady() const
+{
+    if (m_deviceState == QAudio::ActiveState || m_deviceState == QAudio::SuspendedState)
+        return m_bufferIODevice ? m_bufferIODevice->bytesAvailable() : 0;
+
+    return 0;
+}
+
+int QOpenharmonyAudioInput::periodSize() const
+{
+    return 0;
+}
+
+void QOpenharmonyAudioInput::setBufferSize(int value)
+{
+    Q_UNUSED(value)
+}
+
+int QOpenharmonyAudioInput::bufferSize() const
+{
+    return 0;
+}
+
+void QOpenharmonyAudioInput::setNotifyInterval(int milliSeconds)
+{
+    m_intervalTime = qMax(0, milliSeconds);
+}
+
+int QOpenharmonyAudioInput::notifyInterval() const
+{
+    return m_intervalTime;
+}
+
+qint64 QOpenharmonyAudioInput::processedUSecs() const
+{
+    return m_format.durationForBytes(m_processedBytes);
+}
+
+qint64 QOpenharmonyAudioInput::elapsedUSecs() const
+{
+    if (m_deviceState == QAudio::StoppedState)
+        return 0;
+
+    return m_clockStamp.elapsed() * qint64(1000);
+}
+
+QAudio::Error QOpenharmonyAudioInput::error() const
+{
+    return m_errorState;
+}
+
+QAudio::State QOpenharmonyAudioInput::state() const
+{
+    return m_deviceState;
+}
+
+void QOpenharmonyAudioInput::setFormat(const QAudioFormat &format)
+{
+    if (m_deviceState == QAudio::StoppedState)
+        m_format = format;
+}
+
+QAudioFormat QOpenharmonyAudioInput::format() const
+{
+    return m_format;
+}
+
+void QOpenharmonyAudioInput::setVolume(qreal volume)
+{
+    m_volume = volume;
+}
+
+qreal QOpenharmonyAudioInput::volume() const
+{
+    return m_volume;
+}
+
+void QOpenharmonyAudioInput::processBuffer(const QByteArray& audioData)
+{
+    if (m_deviceState == QAudio::StoppedState || m_deviceState == QAudio::SuspendedState)
+        return;
+
+    if (m_deviceState != QAudio::ActiveState) {
+        m_errorState = QAudio::NoError;
+        m_deviceState = QAudio::ActiveState;
+        emit stateChanged(m_deviceState);
+    }
+
+    //write Data To Device
+    int size = audioData.size();
+    m_processedBytes += size;
+
+    QByteArray outData;
+
+    if (m_volume < 1.0f) {// Apply volume
+        outData.resize(size);
+        QAudioHelperInternal::qMultiplySamples(m_volume, m_format, audioData.data(), outData.data(), size);
+    } else {
+        outData.append(audioData);
+    }
+
+    if (m_pullMode) {
+        // write buffer to the QIODevice
+        if (m_audioSource->write(outData) < 0) {
+            stop();
+            m_errorState = QAudio::IOError;
+            Q_EMIT errorChanged(m_errorState);
+        }
+    } else {
+        // emits readyRead() so user will call read() on QIODevice to get some audio data
+        if (m_bufferIODevice != 0) {
+            m_pushBuffer.append(outData);
+            Q_EMIT m_bufferIODevice->readyRead();
+        }
+    }
+
+    // Send notify signal if needed
+    qint64 processedMsecs = processedUSecs() / 1000;
+    if (m_intervalTime && (processedMsecs - m_lastNotifyTime) >= m_intervalTime) {
+        Q_EMIT notify();
+        m_lastNotifyTime = processedMsecs;
+    }
+}
+
+bool QOpenharmonyAudioInput::startRecording()
+{
+    m_processedBytes = 0;
+    m_clockStamp.restart();
+    m_lastNotifyTime = 0;
+
+    if(m_builder || m_capturer)
+    {
+        qWarning() << "Please stop Recording first!";
+        stopRecording();
+    }
+
+    OH_AudioStream_Type streamType = AUDIOSTREAM_TYPE_CAPTURER;
+    OH_AudioStream_Result ret = OH_AudioStreamBuilder_Create(&m_builder, streamType);
+    if(ret != AUDIOSTREAM_SUCCESS || !m_builder)
+    {
+        qWarning() << "Create Audio Stream Builder failed!";
+        m_errorState = QAudio::FatalError;
+        return false;
+    }
+
+    //设置低时延模式
+    OH_AudioStream_LatencyMode latencyMode = AUDIOSTREAM_LATENCY_MODE_FAST;
+    OH_AudioStreamBuilder_SetLatencyMode(m_builder, latencyMode);
+
+    // 设置音频采样率
+    OH_AudioStreamBuilder_SetSamplingRate(m_builder, m_format.sampleRate());
+    // 设置音频声道
+    OH_AudioStreamBuilder_SetChannelCount(m_builder, m_format.channelCount());
+    // 设置音频采样格式
+    OH_AudioStreamBuilder_SetSampleFormat(m_builder, sampleSizeToFormatEnum(m_format.sampleSize(), m_format.sampleType()));
+    // 设置音频流的编码类型
+    OH_AudioStreamBuilder_SetEncodingType(m_builder, AUDIOSTREAM_ENCODING_TYPE_RAW);
+    // 设置输入音频流的工作场景
+    OH_AudioStreamBuilder_SetCapturerInfo(m_builder, AUDIOSTREAM_SOURCE_TYPE_MIC);
+
+    OH_AudioCapturer_Callbacks callbacks;
+    // 配置回调函数
+    callbacks.OH_AudioCapturer_OnReadData = MyOnReadData;
+    callbacks.OH_AudioCapturer_OnStreamEvent = nullptr;
+    callbacks.OH_AudioCapturer_OnInterruptEvent = nullptr;
+    callbacks.OH_AudioCapturer_OnError = MyOnError;
+    // 设置音频输入流的回调
+    ret = OH_AudioStreamBuilder_SetCapturerCallback(m_builder, callbacks, this);
+    if(ret != AUDIOSTREAM_SUCCESS)
+    {
+        stopRecording();
+        qWarning() << "Set Capturer Callback failed!";
+        m_errorState = QAudio::FatalError;
+        return false;
+    }
+
+    ret = OH_AudioStreamBuilder_GenerateCapturer(m_builder, &m_capturer);
+    if(ret != AUDIOSTREAM_SUCCESS || !m_capturer)
+    {
+        stopRecording();
+        qWarning() << "Get Generate Capturer failed!";
+        m_errorState = QAudio::FatalError;
+        return false;
+    }
+
+    ret = OH_AudioCapturer_Start(m_capturer);//开始录制
+    if(ret != AUDIOSTREAM_SUCCESS)
+    {
+        stopRecording();
+        qWarning() << "Start Capturer Audio failed!";
+        m_errorState = QAudio::FatalError;
+        return false;
+    }
+
+    return true;
+}
+
+void QOpenharmonyAudioInput::stopRecording()
+{
+    if(m_builder)
+    {
+        OH_AudioStreamBuilder_Destroy(m_builder);
+        m_builder = nullptr;
+    }
+
+    if(m_capturer)
+    {
+        OH_AudioCapturer_Stop(m_capturer);
+        OH_AudioCapturer_Flush(m_capturer);//释放缓存数据
+        OH_AudioCapturer_Release(m_capturer);//释放录制实例
+    }
+
+    if (!m_pullMode && m_bufferIODevice) {
+        m_bufferIODevice->close();
+        delete m_bufferIODevice;
+        m_bufferIODevice = 0;
+        m_pushBuffer.clear();
+    }
+}
+
+OH_AudioStream_SampleFormat QOpenharmonyAudioInput::sampleSizeToFormatEnum(int sampleSize, QAudioFormat::SampleType sampleType)
+{
+#if OHOS_SDK_VERSION >= 17
+    if (QtOh::apiVersion() >= 17 && QAudioFormat::Float == sampleType)
+        return AUDIOSTREAM_SAMPLE_F32LE;
+#endif
+
+    switch (sampleSize)
+    {
+    case 8: return AUDIOSTREAM_SAMPLE_U8;
+    case 16: return AUDIOSTREAM_SAMPLE_S16LE;
+    case 24: return AUDIOSTREAM_SAMPLE_S24LE;
+    case 32: return AUDIOSTREAM_SAMPLE_S32LE;
+    default :break;
+    }
+
+    return AUDIOSTREAM_SAMPLE_S16LE;
+}
+
+QT_END_NAMESPACE
diff --git a/src/plugins/ohaudiodevice/qopenharmonyaudioinput.h b/src/plugins/ohaudiodevice/qopenharmonyaudioinput.h
new file mode 100644
index 000000000..a48f9aba3
--- /dev/null
+++ b/src/plugins/ohaudiodevice/qopenharmonyaudioinput.h
@@ -0,0 +1,74 @@
+#ifndef QOPENHARMONYAUDIOINPUT_H
+#define QOPENHARMONYAUDIOINPUT_H
+
+#include <qaudiosystem.h>
+#include <QElapsedTimer>
+#include <ohaudio/native_audiocapturer.h>
+#include <ohaudio/native_audiostreambuilder.h>
+
+QT_BEGIN_NAMESPACE
+
+class QOpenharmonyEngine;
+class QIODevice;
+class QBuffer;
+
+class QOpenharmonyAudioInput : public QAbstractAudioInput
+{
+    Q_OBJECT
+public:
+    QOpenharmonyAudioInput(const QByteArray &device);
+    ~QOpenharmonyAudioInput();
+
+    void start(QIODevice *device);
+    QIODevice *start();
+    void stop();
+    void reset();
+    void suspend();
+    void resume();
+    int bytesReady() const;
+    int periodSize() const;
+    void setBufferSize(int value);
+    int bufferSize() const;
+    void setNotifyInterval(int milliSeconds);
+    int notifyInterval() const;
+    qint64 processedUSecs() const;
+    qint64 elapsedUSecs() const;
+    QAudio::Error error() const;
+    QAudio::State state() const;
+    void setFormat(const QAudioFormat &format);
+    QAudioFormat format() const;
+
+    void setVolume(qreal volume);
+    qreal volume() const;
+
+public Q_SLOTS:
+    void processBuffer(const QByteArray& audioData);
+
+private:
+    bool startRecording();
+    void stopRecording();
+    void writeDataToDevice(const char *data, int size);
+    void flushBuffers();
+    OH_AudioStream_SampleFormat sampleSizeToFormatEnum(int sampleSize, QAudioFormat::SampleType sampleType);
+
+    QByteArray m_device;
+
+    bool m_pullMode;
+    qint64 m_processedBytes;
+    QIODevice *m_audioSource;
+    QBuffer *m_bufferIODevice;
+    QByteArray m_pushBuffer;
+    QAudio::Error m_errorState;
+    QAudio::State m_deviceState;
+    QElapsedTimer m_clockStamp;
+    qint64 m_lastNotifyTime;
+    qreal m_volume;
+    int m_intervalTime;
+    QAudioFormat m_format;
+
+    OH_AudioStreamBuilder *m_builder;
+    OH_AudioCapturer *m_capturer;
+};
+
+QT_END_NAMESPACE
+#endif // QOPENHARMONYAUDIOINPUT_H
diff --git a/src/plugins/ohaudiodevice/qopenharmonyaudiomanager.cpp b/src/plugins/ohaudiodevice/qopenharmonyaudiomanager.cpp
new file mode 100644
index 000000000..b141e156f
--- /dev/null
+++ b/src/plugins/ohaudiodevice/qopenharmonyaudiomanager.cpp
@@ -0,0 +1,142 @@
+#include <QDebug>
+#include <QJsModule>
+
+#include "qopenharmonyaudiomanager.h"
+#include <private/qopenharmony_p.h>
+
+auto createRouting = []{
+    return QtOh::runOnJsUIThreadWithResult([]{
+        Napi::Object object = Napi::Object();
+        QJsModule module("@ohos.multimedia.audio");
+        Napi::Object obj = module.call("getAudioManager").As<Napi::Object>();
+        if (!obj.IsNull()) {
+            Napi::Value value = QJsObject(obj).call("getRoutingManager");
+            if (!value.IsNull()) {
+                object = value.As<Napi::Object>();
+                return object;
+            }
+        }
+
+        qWarning() << "get audio routing manager failed.";
+        return Napi::Object();
+    });
+};
+
+Q_GLOBAL_STATIC_WITH_ARGS(QJsObject, audioMgr, (createRouting()));
+
+
+enum class DeviceFlag {
+    ALL_DEVICES_FLAG = 3,
+    INPUT_DEVICES_FLAG = 2,
+    OUTPUT_DEVICES_FLAG = 1,
+};
+
+auto availableDevices = [](DeviceFlag flag)->Napi::Array {
+    return QtOh::runOnJsUIThreadWithResult([=]{
+        if (audioMgr->object().IsNull())
+            return Napi::Array();
+
+        Napi::Value devs;
+        devs = audioMgr->call("getDevicesSync", { Napi::Number::New(audioMgr->env(), int(flag)) });
+        return devs.As<Napi::Array>();
+    });
+};
+
+auto channelCounts(const QString &devName, DeviceFlag flag)->QList<int> {
+    return QtOh::runOnJsUIThreadWithResult([&](){
+        Napi::Array devices = availableDevices(flag);
+        QList<int> result;
+
+        for (uint32_t i = 0; i < devices.Length(); ++i){
+            Napi::Object obj = Napi::Value(devices[i]).ToObject();
+            if (obj.IsNull())
+                continue;
+
+            QJsObject dev(obj);
+            QString curName = QString::fromStdString(dev.get("displayName").ToString());
+            if(curName == devName){
+                Napi::Array channels = dev.get("channelCounts").As<Napi::Array>();
+                for (uint32_t j = 0; j < channels.Length(); ++j){
+                    result.append(Napi::Value(channels[j]).ToNumber());
+                }
+            }
+        }
+        return result;
+    });
+}
+
+auto supportedSampleRates(const QString &devName, DeviceFlag flag)->QList<int> {
+    return QtOh::runOnJsUIThreadWithResult([&](){
+        Napi::Array devices = availableDevices(flag);
+        QList<int> result;
+        for (uint32_t i = 0; i < devices.Length(); ++i){
+            Napi::Object obj = Napi::Value(devices[i]).ToObject();
+            if (obj.IsNull())
+                continue;
+
+            QJsObject dev(obj);
+            QString curName = QString::fromStdString(dev.get("displayName").ToString());
+            if(curName == devName){
+                Napi::Array sampleRates = dev.get("sampleRates").As<Napi::Array>();
+                for (uint32_t j = 0; j < sampleRates.Length(); ++j){
+                    result.append(Napi::Value(sampleRates[j]).ToNumber());
+                }
+            }
+        }
+        return result;
+    });
+};
+auto availableDeviceNames = [](DeviceFlag flag)->QList<QByteArray> {
+    return QtOh::runOnJsUIThreadWithResult([&](){
+        Napi::Array devices = availableDevices(flag);
+        QList<QByteArray> result;
+        for (uint32_t i = 0; i < devices.Length(); ++i) {
+            Napi::Object obj = Napi::Value(devices[i]).ToObject();
+            if (obj.IsNull())
+                continue;
+
+            QJsObject dev(obj);
+            int deviceType = dev.get("deviceType").ToNumber();
+            if(deviceType == 0){
+                continue;
+            }
+
+            QString devName = QString::fromStdString(dev.get("displayName").ToString());
+            if(!devName.isEmpty())
+            {
+                result.append(devName.toUtf8());
+            }
+        }
+        return result;
+    });
+};
+
+QList<QByteArray> QOpenharmonyAudioManager::availableInputDevices()
+{
+    return availableDeviceNames(DeviceFlag::INPUT_DEVICES_FLAG);
+}
+
+QList<QByteArray> QOpenharmonyAudioManager::availableOutputDevices()
+{
+    return availableDeviceNames(DeviceFlag::OUTPUT_DEVICES_FLAG);
+}
+
+QList<int> QOpenharmonyAudioManager::inputChannelCounts(const QString &devName)
+{
+    return channelCounts(devName, DeviceFlag::INPUT_DEVICES_FLAG);
+}
+
+QList<int> QOpenharmonyAudioManager::outputChannelCounts(const QString &devName)
+{
+    return channelCounts(devName, DeviceFlag::OUTPUT_DEVICES_FLAG);
+}
+
+QList<int> QOpenharmonyAudioManager::inputSupportedSampleRates(const QString &devName)
+{
+    return supportedSampleRates(devName, DeviceFlag::INPUT_DEVICES_FLAG);
+}
+
+QList<int> QOpenharmonyAudioManager::outputSupportedSampleRates(const QString &devName)
+{
+    return supportedSampleRates(devName, DeviceFlag::OUTPUT_DEVICES_FLAG);
+}
diff --git a/src/plugins/ohaudiodevice/qopenharmonyaudiomanager.h b/src/plugins/ohaudiodevice/qopenharmonyaudiomanager.h
new file mode 100644
index 000000000..7f6bbc598
--- /dev/null
+++ b/src/plugins/ohaudiodevice/qopenharmonyaudiomanager.h
@@ -0,0 +1,18 @@
+#ifndef QOPENHARMONYAUDIOMANAGER_H
+#define QOPENHARMONYAUDIOMANAGER_H
+
+#include <QList>
+#include <QString>
+
+class QOpenharmonyAudioManager
+{
+public:
+    static QList<QByteArray> availableInputDevices();
+    static QList<QByteArray> availableOutputDevices();
+    static QList<int> inputChannelCounts(const QString &devName);
+    static QList<int> outputChannelCounts(const QString &devName);
+    static QList<int> inputSupportedSampleRates(const QString &devName);
+    static QList<int> outputSupportedSampleRates(const QString &devName);
+};
+
+#endif // QOPENHARMONYAUDIOMANAGER_H
diff --git a/src/plugins/ohaudiodevice/qopenharmonyaudiooutput.cpp b/src/plugins/ohaudiodevice/qopenharmonyaudiooutput.cpp
new file mode 100644
index 000000000..104e9f94a
--- /dev/null
+++ b/src/plugins/ohaudiodevice/qopenharmonyaudiooutput.cpp
@@ -0,0 +1,420 @@
+#include "qopenharmonyaudiooutput.h"
+#include "qopenharmonydeviceinfo.h"
+#include "qopenharmony.h"
+
+#include <QtEndian>
+#include <QtCore/QDataStream>
+#include <QtCore/qtimer.h>
+#include <private/qaudiohelpers_p.h>
+
+static int32_t AudioRendererOnWriteData(OH_AudioRenderer *renderer, void *userData, void *buffer, int32_t bufferLen)
+{
+    Q_UNUSED(renderer)
+
+    auto    pSelf = reinterpret_cast<QOpenharmonyAudioOutput*>(userData);
+    if(pSelf)
+    {
+        pSelf->writeBuffer(buffer, bufferLen);
+    }
+
+    return 0;
+}
+
+// 自定义异常回调函数
+static int32_t AudioRendererOnError(OH_AudioRenderer *renderer, void* userData, OH_AudioStream_Result error)
+{
+    Q_UNUSED(renderer)
+    Q_UNUSED(userData)
+    qWarning() << "Audio output error code:" << error;
+    return 0;
+}
+
+QOpenharmonyAudioOutput::QOpenharmonyAudioOutput(const QByteArray &device)
+      : m_device(device)
+      , buffer_size(2500)
+      , period_size(0)
+      , totalBytes(0)
+      , pullMode(true)
+      , intervalTime(1000)
+      , lastNotifyTime(0)
+      , volumeCache(qreal(1.0))
+      , pRenderer(nullptr)
+      , pBuilder(nullptr)
+      , errorState(QAudio::NoError)
+      , audioSource(nullptr)
+      , deviceState(QAudio::StoppedState)
+{
+
+}
+
+QOpenharmonyAudioOutput::~QOpenharmonyAudioOutput()
+{
+    close();
+}
+
+void QOpenharmonyAudioOutput::writeBuffer(void *buffer, int length)
+{
+    period_size = length;
+    buffer_size = length;
+    int readLen = 0;
+    memset(buffer, 0, length);
+    if(pullMode)
+    {
+        readLen = audioSource->read((char *)buffer, length);
+        if(audioSource->atEnd() && (QAudio::ActiveState == deviceState))
+        {
+            deviceState = QAudio::IdleState;
+            emit stateChanged(deviceState);
+        }
+    }
+    else
+    {
+        mutex.lock();
+        if(length < selfBytes.size())
+        {
+            memcpy(buffer, selfBytes.data(), length);
+            readLen = length;
+            int len = selfBytes.size() - length;
+            selfBytes = selfBytes.right(len);
+        }
+        else
+        {
+            memcpy((char *)buffer, selfBytes.data(), selfBytes.size());
+            readLen = selfBytes.size();
+            selfBytes.clear();
+        }
+
+        if(0 == readLen && (QAudio::ActiveState == deviceState))
+        {
+            deviceState = QAudio::IdleState;
+            emit stateChanged(deviceState);
+        }
+
+        mutex.unlock();
+    }
+
+    totalBytes += readLen;
+
+    qint64 processedMsecs = processedUSecs() / 1000;
+    if (intervalTime && (processedMsecs - lastNotifyTime) >= intervalTime) {
+        emit notify();
+        lastNotifyTime = processedMsecs;
+    }
+}
+
+OH_AudioStream_SampleFormat QOpenharmonyAudioOutput::sampleSizeToFormatEnum(int sampleSize, QAudioFormat::SampleType sampleType)
+{
+#if OHOS_SDK_VERSION >= 17
+    if(QtOh::apiVersion() >= 17 && QAudioFormat::Float == sampleType)
+        return AUDIOSTREAM_SAMPLE_F32LE;
+#endif
+
+    switch(sampleSize)
+    {
+    case 8: return AUDIOSTREAM_SAMPLE_U8;
+    case 16: return AUDIOSTREAM_SAMPLE_S16LE;
+    case 24: return AUDIOSTREAM_SAMPLE_S24LE;
+    case 32: return AUDIOSTREAM_SAMPLE_S32LE;
+    default :break;
+    }
+
+    return AUDIOSTREAM_SAMPLE_S16LE;
+}
+
+
+bool QOpenharmonyAudioOutput::open()
+{
+    //创建
+    OH_AudioStream_Type type = AUDIOSTREAM_TYPE_RENDERER;
+    OH_AudioStream_Result result = OH_AudioStreamBuilder_Create(&pBuilder, AUDIOSTREAM_TYPE_RENDERER);
+    if(AUDIOSTREAM_SUCCESS != result)
+    {
+        qWarning() << "OH_Audio create builder error code : " << result;
+        close();
+        return false;
+    }
+
+    //设置参数
+    // 设置音频采样率
+    OH_AudioStreamBuilder_SetSamplingRate(pBuilder, settings.sampleRate());
+    // 设置音频声道
+    OH_AudioStreamBuilder_SetChannelCount(pBuilder, settings.channelCount());
+    // 设置音频采样格式
+    OH_AudioStreamBuilder_SetSampleFormat(pBuilder, sampleSizeToFormatEnum(settings.sampleSize(), settings.sampleType()));
+    //设置低延时
+    OH_AudioStreamBuilder_SetLatencyMode(pBuilder, AUDIOSTREAM_LATENCY_MODE_NORMAL);
+    
+    OH_AudioStreamBuilder_SetFrameSizeInCallback(pBuilder, buffer_size);
+
+    //设置回调函数
+    OH_AudioRenderer_Callbacks rendererCallbacks;
+    memset(&rendererCallbacks, 0, sizeof(OH_AudioRenderer_Callbacks));
+    rendererCallbacks.OH_AudioRenderer_OnWriteData = AudioRendererOnWriteData;
+    rendererCallbacks.OH_AudioRenderer_OnStreamEvent = nullptr;
+    rendererCallbacks.OH_AudioRenderer_OnInterruptEvent = nullptr;
+    rendererCallbacks.OH_AudioRenderer_OnError = AudioRendererOnError;
+
+    result = OH_AudioStreamBuilder_SetRendererCallback(pBuilder, rendererCallbacks, this);
+    if(AUDIOSTREAM_SUCCESS != result)
+    {
+        qWarning() << "OH_Audio set callBack error code : " << result;
+        close();
+        return false;
+    }
+
+    // create OH_AudioRenderer
+    result = OH_AudioStreamBuilder_GenerateRenderer(pBuilder, &pRenderer);
+    if(AUDIOSTREAM_SUCCESS != result)
+    {
+        qWarning() << "OH_Audio Generate Renderer error code : " << result;
+        close();
+        return false;
+    }
+
+    // start
+    result = OH_AudioRenderer_Start(pRenderer);
+    if(AUDIOSTREAM_SUCCESS != result)
+    {
+        qWarning() << "OH_Audio Start error code : " << result;
+        close();
+        return false;
+    }
+
+    timeStampOpened.restart();
+    lastNotifyTime = 0;
+    totalBytes = 0;
+    return true;
+}
+
+void QOpenharmonyAudioOutput::close()
+{
+    if(!pullMode && audioSource)
+    {
+        delete audioSource;
+        audioSource = nullptr;
+        pullMode = true;
+    }
+
+    if(deviceState != QAudio::StoppedState)
+    {
+        OH_AudioRenderer_Stop(pRenderer);
+    }
+
+    if(pRenderer)
+    {
+        OH_AudioRenderer_Release(pRenderer);
+        pRenderer = nullptr;
+    }
+
+    if(pBuilder)
+    {
+        OH_AudioStreamBuilder_Destroy(pBuilder);
+        pBuilder = nullptr;
+    }
+}
+
+
+QIODevice* QOpenharmonyAudioOutput::start()
+{
+    if(deviceState != QAudio::StoppedState)
+        close();
+
+    if(!pullMode && audioSource)
+        delete audioSource;
+
+    pullMode = false;
+    selfBytes.clear();
+    audioSource = new OutputPrivate(this);
+    if(!audioSource->open(QIODevice::WriteOnly|QIODevice::Unbuffered))
+    {
+        qWarning() << "open selfSource falid.";
+        errorState = QAudio::OpenError;
+        return nullptr;
+    }
+
+    if(!open())
+    {
+        errorState = QAudio::OpenError;
+        return nullptr;
+    }
+
+    deviceState = QAudio::IdleState;
+    emit stateChanged(deviceState);
+
+    return audioSource;
+}
+
+void QOpenharmonyAudioOutput::start(QIODevice* device)
+{
+    if(deviceState != QAudio::StoppedState)
+        close();
+
+    if(!pullMode && audioSource)
+        delete audioSource;
+
+    pullMode = true;
+    audioSource = device;
+
+    if(!open())
+        return;
+
+    deviceState = QAudio::ActiveState;
+    emit stateChanged(deviceState);
+}
+
+void QOpenharmonyAudioOutput::stop()
+{
+    if(deviceState == QAudio::StoppedState)
+        return;
+
+    close();
+
+    deviceState = QAudio::StoppedState;
+
+    emit stateChanged(deviceState);
+}
+
+void QOpenharmonyAudioOutput::reset()
+{
+    if(deviceState == QAudio::ActiveState) {
+        OH_AudioRenderer_Flush(pRenderer);
+    }
+    //stop();
+}
+
+void QOpenharmonyAudioOutput::suspend()
+{
+    if(deviceState == QAudio::ActiveState || deviceState == QAudio::IdleState) {
+        OH_AudioRenderer_Pause(pRenderer);
+        deviceState = QAudio::SuspendedState;
+        errorState = QAudio::NoError;
+        emit stateChanged(deviceState);
+    }
+}
+
+void QOpenharmonyAudioOutput::resume()
+{
+    if (QAudio::SuspendedState == deviceState|| (QAudio::IdleState == deviceState)) {
+        OH_AudioRenderer_Start(pRenderer);//开始播放
+
+        deviceState = pullMode ? QAudio::ActiveState : QAudio::IdleState;
+        emit stateChanged(deviceState);
+    }
+}
+
+int QOpenharmonyAudioOutput::bytesFree() const
+{
+    return buffer_size;
+}
+
+int QOpenharmonyAudioOutput::periodSize() const
+{
+     return period_size;
+}
+
+void QOpenharmonyAudioOutput::setBufferSize(int value)
+{
+    if(deviceState == QAudio::StoppedState)
+        buffer_size = value;
+}
+
+int QOpenharmonyAudioOutput::bufferSize() const
+{
+    return buffer_size;
+}
+
+void QOpenharmonyAudioOutput::setNotifyInterval(int milliSeconds)
+{
+    intervalTime = qMax(0, milliSeconds);
+}
+
+int QOpenharmonyAudioOutput::notifyInterval() const
+{
+    return intervalTime;
+}
+
+qint64 QOpenharmonyAudioOutput::processedUSecs() const
+{
+    if (deviceState == QAudio::StoppedState)
+        return 0;
+    return settings.durationForBytes(totalBytes);
+}
+
+qint64 QOpenharmonyAudioOutput::elapsedUSecs() const
+{
+    if (deviceState == QAudio::StoppedState)
+        return 0;
+
+    return timeStampOpened.elapsed() * qint64(1000);
+}
+
+QAudio::Error QOpenharmonyAudioOutput::error() const
+{
+    return errorState;
+}
+
+QAudio::State QOpenharmonyAudioOutput::state() const
+{
+    return deviceState;
+}
+
+void QOpenharmonyAudioOutput::setVolume(qreal volume)
+{
+    if (qFuzzyCompare(volumeCache, volume))
+        return;
+
+    volumeCache = qBound(qreal(0), volume, qreal(1));
+}
+
+qreal QOpenharmonyAudioOutput::volume() const
+{
+    return volumeCache;
+}
+
+void QOpenharmonyAudioOutput::setFormat(const QAudioFormat& fmt)
+{
+    if (deviceState == QAudio::StoppedState)
+        settings = fmt;
+}
+
+QAudioFormat QOpenharmonyAudioOutput::format() const
+{
+    return settings;
+}
+
+qint64 QOpenharmonyAudioOutput::getAudioBuff(const char* data, qint64 len)
+{
+    mutex.lock();
+    selfBytes.append(data, len);
+    mutex.unlock();
+    return len;
+}
+
+
+OutputPrivate::OutputPrivate(QOpenharmonyAudioOutput* audio)
+{
+    audioDevice = qobject_cast<QOpenharmonyAudioOutput*>(audio);
+}
+
+OutputPrivate::~OutputPrivate() {}
+
+qint64 OutputPrivate::readData( char* data, qint64 len)
+{
+    Q_UNUSED(data)
+    Q_UNUSED(len)
+
+    return 0;
+}
+
+qint64 OutputPrivate::writeData(const char* data, qint64 len)
+{
+    qint64 written = 0;
+
+    if((audioDevice->deviceState == QAudio::ActiveState)
+        ||(audioDevice->deviceState == QAudio::IdleState))
+    {
+        written = audioDevice->getAudioBuff(data, len);
+        audioDevice->deviceState = QAudio::ActiveState;
+    }
+    return written;
+}
diff --git a/src/plugins/ohaudiodevice/qopenharmonyaudiooutput.h b/src/plugins/ohaudiodevice/qopenharmonyaudiooutput.h
new file mode 100644
index 000000000..78bf1e470
--- /dev/null
+++ b/src/plugins/ohaudiodevice/qopenharmonyaudiooutput.h
@@ -0,0 +1,97 @@
+#ifndef QOPENHARMONYAUDIOOUTPUT_H
+#define QOPENHARMONYAUDIOOUTPUT_H
+
+#include <QAbstractAudioOutput>
+#include <QtCore/qdebug.h>
+#include <QtCore/qelapsedtimer.h>
+#include <QtCore/qstring.h>
+#include <QtCore/qstringlist.h>
+#include <QtCore/qdatetime.h>
+#include <QtCore/qmutex.h>
+#include <QBuffer>
+#include <QByteArray>
+
+#include <QtMultimedia/qaudio.h>
+#include <QtMultimedia/qaudiodeviceinfo.h>
+#include <QtMultimedia/qaudiosystem.h>
+
+#include <napi/native_api.h>
+#include <ohaudio/native_audiorenderer.h>
+#include <ohaudio/native_audiostreambuilder.h>
+
+class QOpenharmonyAudioOutput : public QAbstractAudioOutput
+{
+    Q_OBJECT
+public:
+    QOpenharmonyAudioOutput(const QByteArray &device);
+    ~QOpenharmonyAudioOutput();
+private:
+    OH_AudioStream_SampleFormat sampleSizeToFormatEnum(int sampleSize, QAudioFormat::SampleType sampleType);
+    //打开
+    bool open();
+    //关闭
+    void close();
+public:
+    QIODevice* start();
+    void start(QIODevice* device);
+    void stop();
+    void reset();
+    void suspend();
+    void resume();
+    int bytesFree() const;
+    int periodSize() const;
+    void setBufferSize(int value);
+    int bufferSize() const;
+    void setNotifyInterval(int milliSeconds);
+    int notifyInterval() const;
+    qint64 processedUSecs() const;
+    qint64 elapsedUSecs() const;
+    QAudio::Error error() const;
+    QAudio::State state() const;
+    void setVolume(qreal volume);
+    qreal volume() const;
+    void setFormat(const QAudioFormat& fmt);
+    QAudioFormat format() const;
+
+    qint64 getAudioBuff(const char* data, qint64 len);
+
+    void writeBuffer(void *buffer, int length);
+
+    QAudio::Error errorState;
+    QAudio::State deviceState;
+private:
+    QByteArray m_device;
+    QElapsedTimer timeStampOpened;
+    qint32 buffer_size;
+    qint32 period_size;
+    qint64 totalBytes;
+    bool pullMode;
+    qint64 intervalTime;
+    qint64 lastNotifyTime;
+    qreal volumeCache;
+
+    QMutex mutex;
+
+    OH_AudioRenderer * pRenderer;
+    OH_AudioStreamBuilder * pBuilder;
+
+    QByteArray selfBytes;
+    QIODevice* audioSource;
+    QAudioFormat settings;
+};
+
+class OutputPrivate : public QIODevice
+{
+    Q_OBJECT
+public:
+    OutputPrivate(QOpenharmonyAudioOutput* audio);
+    ~OutputPrivate();
+
+    qint64 readData( char* data, qint64 len);
+    qint64 writeData(const char* data, qint64 len);
+
+private:
+    QOpenharmonyAudioOutput *audioDevice;
+};
+
+#endif // QOPENHARMONYAUDIOOUTPUT_H
diff --git a/src/plugins/ohaudiodevice/qopenharmonydeviceinfo.cpp b/src/plugins/ohaudiodevice/qopenharmonydeviceinfo.cpp
new file mode 100644
index 000000000..d9dbbe16a
--- /dev/null
+++ b/src/plugins/ohaudiodevice/qopenharmonydeviceinfo.cpp
@@ -0,0 +1,82 @@
+#include "qopenharmonydeviceinfo.h"
+#include "qopenharmonyaudiomanager.h"
+
+#include <QList>
+
+QT_BEGIN_NAMESPACE
+
+QOpenharmonyDeviceInfo::QOpenharmonyDeviceInfo(const QByteArray &device, QAudio::Mode mode)
+    :m_device(device)
+    , m_mode(mode)
+{
+}
+
+QAudioFormat QOpenharmonyDeviceInfo::preferredFormat() const
+{
+    QAudioFormat format;
+    format.setCodec(QStringLiteral("audio/pcm"));
+    format.setSampleSize(16);
+    format.setSampleType(QAudioFormat::SignedInt);
+    format.setSampleRate(48000);
+    format.setChannelCount(2);
+
+    return format;
+}
+
+bool QOpenharmonyDeviceInfo::isFormatSupported(const QAudioFormat &format) const
+{
+    QOpenharmonyDeviceInfo *that = const_cast<QOpenharmonyDeviceInfo*>(this);
+    return that->supportedCodecs().contains(format.codec())
+            && that->supportedSampleRates().contains(format.sampleRate())
+            && that->supportedChannelCounts().contains(format.channelCount())
+            && that->supportedSampleSizes().contains(format.sampleSize())
+            && that->supportedByteOrders().contains(format.byteOrder())
+            && that->supportedSampleTypes().contains(format.sampleType());
+}
+
+QString QOpenharmonyDeviceInfo::deviceName() const
+{
+    return m_device;
+}
+
+QStringList QOpenharmonyDeviceInfo::supportedCodecs()
+{
+    return QStringList() << QStringLiteral("audio/pcm");
+}
+
+QList<int> QOpenharmonyDeviceInfo::supportedSampleRates()
+{
+    if (QAudio::AudioInput == m_mode) {
+        return QOpenharmonyAudioManager::inputSupportedSampleRates(QString::fromUtf8(m_device));
+    } else {
+        return QOpenharmonyAudioManager::outputSupportedSampleRates(QString::fromUtf8(m_device));
+    }
+}
+
+QList<int> QOpenharmonyDeviceInfo::supportedChannelCounts()
+{
+    if (QAudio::AudioInput == m_mode) {
+        return QOpenharmonyAudioManager::inputChannelCounts(QString::fromUtf8(m_device));
+    } else {
+        return QOpenharmonyAudioManager::outputChannelCounts(QString::fromUtf8(m_device));
+    }
+}
+
+QList<int> QOpenharmonyDeviceInfo::supportedSampleSizes()
+{
+    return QList<int>() << 8 << 16 << 24 << 32;
+}
+
+QList<QAudioFormat::Endian> QOpenharmonyDeviceInfo::supportedByteOrders()
+{
+    return QList<QAudioFormat::Endian>() << QAudioFormat::LittleEndian;
+}
+
+QList<QAudioFormat::SampleType> QOpenharmonyDeviceInfo::supportedSampleTypes()
+{
+    return QList<QAudioFormat::SampleType>() << QAudioFormat::Float
+                                             << QAudioFormat::SignedInt
+                                             << QAudioFormat::UnSignedInt;
+}
+
+QT_END_NAMESPACE
diff --git a/src/plugins/ohaudiodevice/qopenharmonydeviceinfo.h b/src/plugins/ohaudiodevice/qopenharmonydeviceinfo.h
new file mode 100644
index 000000000..80252779f
--- /dev/null
+++ b/src/plugins/ohaudiodevice/qopenharmonydeviceinfo.h
@@ -0,0 +1,35 @@
+#ifndef QOPENHARMONYDEVICEINFO_H
+#define QOPENHARMONYDEVICEINFO_H
+
+#include <qaudiosystem.h>
+#include <QSharedPointer>
+
+QT_BEGIN_NAMESPACE
+
+class QOpenHarmonyJsObject;
+
+class QOpenharmonyDeviceInfo : public QAbstractAudioDeviceInfo
+{
+    Q_OBJECT
+public:
+    QOpenharmonyDeviceInfo(const QByteArray &device, QAudio::Mode mode);
+    ~QOpenharmonyDeviceInfo() {};
+
+    QAudioFormat preferredFormat() const;
+    bool isFormatSupported(const QAudioFormat &format) const;
+    QString deviceName() const;
+    QStringList supportedCodecs();
+    QList<int> supportedSampleRates();
+    QList<int> supportedChannelCounts();
+    QList<int> supportedSampleSizes();
+    QList<QAudioFormat::Endian> supportedByteOrders();
+    QList<QAudioFormat::SampleType> supportedSampleTypes();
+
+private:
+    QByteArray m_device;
+    QAudio::Mode m_mode;
+    QSharedPointer<QOpenHarmonyJsObject> m_jsAudioMgr;
+};
+
+QT_END_NAMESPACE
+#endif // QOPENHARMONYDEVICEINFO_H
diff --git a/src/plugins/ohaudiodevice/qopenharmonyengine.cpp b/src/plugins/ohaudiodevice/qopenharmonyengine.cpp
new file mode 100644
index 000000000..a9bf607de
--- /dev/null
+++ b/src/plugins/ohaudiodevice/qopenharmonyengine.cpp
@@ -0,0 +1,42 @@
+#include "qopenharmonyengine.h"
+#include "qopenharmonyaudiomanager.h"
+
+#include <qdebug.h>
+
+QT_BEGIN_NAMESPACE
+
+Q_GLOBAL_STATIC(QOpenharmonyEngine, openharmonyEngine);
+
+QOpenharmonyEngine::QOpenharmonyEngine()
+{
+}
+
+QOpenharmonyEngine::~QOpenharmonyEngine()
+{
+
+}
+
+QOpenharmonyEngine *QOpenharmonyEngine::instance()
+{
+    return openharmonyEngine();
+}
+
+QByteArray QOpenharmonyEngine::defaultDevice(QAudio::Mode mode) const
+{
+    const auto &devices = availableDevices(mode);
+    return !devices.isEmpty() ? devices.first() : QByteArray();
+}
+
+QList<QByteArray> QOpenharmonyEngine::availableDevices(QAudio::Mode mode) const
+{
+    QList<QByteArray> devices;
+    if (mode == QAudio::AudioInput) {
+        return QOpenharmonyAudioManager::availableInputDevices();
+    } else {
+        return QOpenharmonyAudioManager::availableOutputDevices();
+    }
+
+    return devices;
+}
+
+QT_END_NAMESPACE
diff --git a/src/plugins/ohaudiodevice/qopenharmonyengine.h b/src/plugins/ohaudiodevice/qopenharmonyengine.h
new file mode 100644
index 000000000..4b284bca7
--- /dev/null
+++ b/src/plugins/ohaudiodevice/qopenharmonyengine.h
@@ -0,0 +1,26 @@
+#ifndef QOPENHARMONYENGINE_H
+#define QOPENHARMONYENGINE_H
+
+#include <qaudio.h>
+#include <qlist.h>
+
+QT_BEGIN_NAMESPACE
+
+class QOpenHarmonyJsObject;
+
+class QOpenharmonyEngine
+{
+public:
+    enum OutputValue { FramesPerBuffer, SampleRate };
+
+    QOpenharmonyEngine();
+    ~QOpenharmonyEngine();
+
+    static QOpenharmonyEngine *instance();
+
+    QByteArray defaultDevice(QAudio::Mode mode) const;
+    QList<QByteArray> availableDevices(QAudio::Mode mode) const;
+};
+
+QT_END_NAMESPACE
+#endif // QOPENHARMONYENGINE_H
diff --git a/src/plugins/openharmony/openharmony.pro b/src/plugins/openharmony/openharmony.pro
new file mode 100644
index 000000000..a3841d703
--- /dev/null
+++ b/src/plugins/openharmony/openharmony.pro
@@ -0,0 +1,7 @@
+TEMPLATE = subdirs
+
+SUBDIRS += src
+
+qtHaveModule(quick) {
+    SUBDIRS += videonode
+}
diff --git a/src/plugins/openharmony/src/mediacapture/mediacapture.pri b/src/plugins/openharmony/src/mediacapture/mediacapture.pri
new file mode 100644
index 000000000..df5060e88
--- /dev/null
+++ b/src/plugins/openharmony/src/mediacapture/mediacapture.pri
@@ -0,0 +1,32 @@
+INCLUDEPATH += $$PWD
+
+HEADERS += \
+    $$PWD/qohaudioencodercontrol.h \
+    $$PWD/qohcameracontrol.h \
+    $$PWD/qohcameraimagecapturecontrol.h \
+    $$PWD/qohcamerainfocontrol.h \
+    $$PWD/qohcamerarendercontrol.h \
+    $$PWD/qohcamerasession.h \
+    $$PWD/qohcaptureservice.h \
+    $$PWD/qohcapturesession.h \
+    $$PWD/qohcontainercontrol.h \
+    $$PWD/qohdevicecontrol.h \
+    $$PWD/qohrecordercontrol.h \
+    $$PWD/qohvideoencodercontrol.h \
+    $$PWD/qohviewfindersettingscontrol2.h
+
+SOURCES += \
+    $$PWD/qohaudioencodercontrol.cpp \
+    $$PWD/qohcameracontrol.cpp \
+    $$PWD/qohcameraimagecapturecontrol.cpp \
+    $$PWD/qohcamerainfocontrol.cpp \
+    $$PWD/qohcamerarendercontrol.cpp \
+    $$PWD/qohcamerasession.cpp \
+    $$PWD/qohcaptureservice.cpp \
+    $$PWD/qohcapturesession.cpp \
+    $$PWD/qohcontainercontrol.cpp \
+    $$PWD/qohdevicecontrol.cpp \
+    $$PWD/qohrecordercontrol.cpp \
+    $$PWD/qohvideoencodercontrol.cpp \
+    $$PWD/qohviewfindersettingscontrol2.cpp
+
diff --git a/src/plugins/openharmony/src/mediacapture/qohaudioencodercontrol.cpp b/src/plugins/openharmony/src/mediacapture/qohaudioencodercontrol.cpp
new file mode 100644
index 000000000..040f2a616
--- /dev/null
+++ b/src/plugins/openharmony/src/mediacapture/qohaudioencodercontrol.cpp
@@ -0,0 +1,119 @@
+#include "qohaudioencodercontrol.h"
+#include "qohcapturesession.h"
+#include <qaudiodeviceinfo.h>
+
+static int getnearsetValue(const QList<int> &supported, int value){
+    int offset = INT_MAX;
+    int ret;
+    for(int curValue : supported){
+        if(qAbs(value - curValue) <= offset)
+        {
+            offset = qAbs(value - curValue);
+            ret = value;
+        }
+    }
+
+    return ret;
+}
+
+QOhAudioEncoderControl::QOhAudioEncoderControl(QObject *parent)
+    :QAudioEncoderSettingsControl(parent)
+{
+    m_session = qobject_cast<QOhCaptureSession*>(parent);
+    update();
+}
+
+QStringList QOhAudioEncoderControl::supportedAudioCodecs() const
+{
+    return QStringList() << QLatin1String("audio/mp4a-latm") << QLatin1String("audio/g711mu");
+}
+
+QString QOhAudioEncoderControl::codecDescription(const QString &codecName) const
+{
+    if (QString::compare(codecName, QLatin1String("audio/mp4a-latm")) == 0)
+        return tr("AAC Low Complexity (AAC-LC) audio codec");
+
+    if (QString::compare(codecName, QLatin1String("audio/g711mu")) == 0)
+        return tr("G.711 μ-law audio codec");
+
+    return QString();
+}
+
+QList<int> QOhAudioEncoderControl::supportedSampleRates(const QAudioEncoderSettings &settings, bool *continuous) const
+{
+    Q_UNUSED(settings)
+    if (continuous)
+        *continuous = false;
+
+    return m_sampleRates;
+}
+
+QAudioEncoderSettings QOhAudioEncoderControl::audioSettings() const
+{
+    return m_session->audioSettings();
+}
+
+void QOhAudioEncoderControl::setAudioSettings(const QAudioEncoderSettings &settings)
+{
+    QAudioEncoderSettings tsettings(settings);
+    if(tsettings.channelCount() == 0)
+        tsettings.setChannelCount(2);
+
+    if (tsettings.encodingMode() == QMultimedia::ConstantQualityEncoding) {
+        tsettings.setCodec("audio/mp4a-latm");
+        switch (tsettings.quality()) {
+        case QMultimedia::VeryLowQuality:
+            tsettings.setSampleRate(8000);
+            break;
+        case QMultimedia::LowQuality:
+            tsettings.setSampleRate(22050);
+            break;
+        case QMultimedia::HighQuality:
+            tsettings.setSampleRate(48000);
+            break;
+        case QMultimedia::VeryHighQuality:
+            tsettings.setSampleRate(96000);
+            break;
+        case QMultimedia::NormalQuality:
+        default:
+            tsettings.setSampleRate(44100);
+            break;
+        }
+    }
+
+    if(!supportedAudioCodecs().contains(tsettings.codec()))
+    {
+        tsettings.setCodec("audio/mp4a-latm");
+    }
+
+    if (QString::compare(tsettings.codec(), QLatin1String("audio/mp4a-latm")) == 0){
+        tsettings.setBitRate( qBound(32000, settings.bitRate(), 500000) );
+        tsettings.setChannelCount( qBound(1, settings.channelCount(), 8) );
+        QList<int> supportSampleRate({8000, 11025, 12000, 16000, 22050, 24000, 32000,\
+                                       44100, 48000, 64000, 88200, 96000});
+        tsettings.setSampleRate( getnearsetValue(supportSampleRate, tsettings.sampleRate()) );
+    }
+
+    if (QString::compare(tsettings.codec(), QLatin1String("audio/g711mu")) == 0){
+        tsettings.setBitRate( 64000 );
+        tsettings.setChannelCount( 1 );
+        tsettings.setSampleRate(8000);
+    }
+
+    m_session->setAudioSettings(tsettings);
+}
+
+void QOhAudioEncoderControl::update()
+{
+    m_sampleRates.clear();
+    QList<QAudioDeviceInfo> devices = QAudioDeviceInfo::availableDevices(QAudio::AudioInput);
+    for (int i = 0; i < devices.size(); ++i) {
+        QList<int> rates = devices.at(i).supportedSampleRates();
+        for (int j = 0; j < rates.size(); ++j) {
+            int rate = rates.at(j);
+            if (!m_sampleRates.contains(rate))
+                m_sampleRates.append(rate);
+        }
+    }
+    std::sort(m_sampleRates.begin(), m_sampleRates.end());
+}
diff --git a/src/plugins/openharmony/src/mediacapture/qohaudioencodercontrol.h b/src/plugins/openharmony/src/mediacapture/qohaudioencodercontrol.h
new file mode 100644
index 000000000..d26d45254
--- /dev/null
+++ b/src/plugins/openharmony/src/mediacapture/qohaudioencodercontrol.h
@@ -0,0 +1,34 @@
+#ifndef QOHAUDIOENCODERCONTROL_H
+#define QOHAUDIOENCODERCONTROL_H
+
+#include "qaudioencodersettingscontrol.h"
+#include <qaudioformat.h>
+
+QT_BEGIN_NAMESPACE
+
+class QOhCaptureSession;
+
+class QOhAudioEncoderControl : public QAudioEncoderSettingsControl
+{
+    Q_OBJECT
+public:
+    QOhAudioEncoderControl(QObject *parent);
+    // virtual ~QOhAudioEncoderControl();
+
+    QStringList supportedAudioCodecs() const;
+    QString codecDescription(const QString &codecName) const;
+    QList<int> supportedSampleRates(const QAudioEncoderSettings &, bool *continuous = 0) const;
+
+    QAudioEncoderSettings audioSettings() const;
+    void setAudioSettings(const QAudioEncoderSettings&);
+
+private:
+    void update();
+
+    QOhCaptureSession* m_session;
+    QList<int> m_sampleRates;
+};
+
+QT_END_NAMESPACE
+
+#endif // QOHAUDIOENCODERCONTROL_H
diff --git a/src/plugins/openharmony/src/mediacapture/qohcameracontrol.cpp b/src/plugins/openharmony/src/mediacapture/qohcameracontrol.cpp
new file mode 100644
index 000000000..25d71718d
--- /dev/null
+++ b/src/plugins/openharmony/src/mediacapture/qohcameracontrol.cpp
@@ -0,0 +1,72 @@
+#include "qohcamerasession.h"
+#include "qohcameracontrol.h"
+
+QT_BEGIN_NAMESPACE
+
+QOhCameraControl::QOhCameraControl(QOhCameraSession *session)
+    : QCameraControl(Q_NULLPTR)
+      , m_cameraSession(session)
+{
+    connect(m_cameraSession, SIGNAL(statusChanged(QCamera::Status)),
+            this, SIGNAL(statusChanged(QCamera::Status)));
+
+    connect(m_cameraSession, SIGNAL(stateChanged(QCamera::State)),
+            this, SIGNAL(stateChanged(QCamera::State)));
+
+    connect(m_cameraSession, SIGNAL(error(int,QString)), this, SIGNAL(error(int,QString)));
+
+    connect(m_cameraSession, SIGNAL(captureModeChanged(QCamera::CaptureModes)),
+            this, SIGNAL(captureModeChanged(QCamera::CaptureModes)));
+}
+
+QOhCameraControl::~QOhCameraControl()
+{
+
+}
+
+QCamera::CaptureModes QOhCameraControl::captureMode() const
+{
+    return m_cameraSession->captureMode();
+}
+
+void QOhCameraControl::setCaptureMode(QCamera::CaptureModes mode)
+{
+    m_cameraSession->setCaptureMode(mode);
+}
+
+bool QOhCameraControl::isCaptureModeSupported(QCamera::CaptureModes mode) const
+{
+    return m_cameraSession->isCaptureModeSupported(mode);
+}
+
+void QOhCameraControl::setState(QCamera::State state)
+{
+    m_cameraSession->setState(state);
+}
+
+QCamera::State QOhCameraControl::state() const
+{
+    return m_cameraSession->state();
+}
+
+QCamera::Status QOhCameraControl::status() const
+{
+    return m_cameraSession->status();
+}
+
+bool QOhCameraControl::canChangeProperty(PropertyChangeType changeType, QCamera::Status status) const
+{
+    Q_UNUSED(status);
+
+    switch (changeType) {
+    case QCameraControl::CaptureMode:
+    case QCameraControl::ImageEncodingSettings:
+    case QCameraControl::VideoEncodingSettings:
+    case QCameraControl::Viewfinder:
+        return true;
+    default:
+        return false;
+    }
+}
+
+QT_END_NAMESPACE
diff --git a/src/plugins/openharmony/src/mediacapture/qohcameracontrol.h b/src/plugins/openharmony/src/mediacapture/qohcameracontrol.h
new file mode 100644
index 000000000..7fe92cce3
--- /dev/null
+++ b/src/plugins/openharmony/src/mediacapture/qohcameracontrol.h
@@ -0,0 +1,35 @@
+#ifndef QOHCAMERACONTROL_H
+#define QOHCAMERACONTROL_H
+
+#include <qcameracontrol.h>
+
+QT_BEGIN_NAMESPACE
+
+class QOhCameraSession;
+
+class QOhCameraControl : public QCameraControl
+{
+    Q_OBJECT
+
+public:
+    explicit QOhCameraControl(QOhCameraSession *session);
+    virtual ~QOhCameraControl();
+
+    QCamera::State state() const;
+    void setState(QCamera::State state);
+
+    QCamera::Status status() const;
+
+    QCamera::CaptureModes captureMode() const;
+    void setCaptureMode(QCamera::CaptureModes mode);
+    bool isCaptureModeSupported(QCamera::CaptureModes mode) const;
+
+    bool canChangeProperty(PropertyChangeType changeType, QCamera::Status status) const;
+
+private:
+    QOhCameraSession *m_cameraSession;
+};
+
+QT_END_NAMESPACE
+
+#endif // QOHCAMERACONTROL_H
diff --git a/src/plugins/openharmony/src/mediacapture/qohcameraimagecapturecontrol.cpp b/src/plugins/openharmony/src/mediacapture/qohcameraimagecapturecontrol.cpp
new file mode 100644
index 000000000..b3830a0ba
--- /dev/null
+++ b/src/plugins/openharmony/src/mediacapture/qohcameraimagecapturecontrol.cpp
@@ -0,0 +1,40 @@
+#include "qohcamerasession.h"
+#include "qohcameraimagecapturecontrol.h"
+
+QOhCameraImageCaptureControl::QOhCameraImageCaptureControl(QOhCameraSession *session)
+    :QCameraImageCaptureControl()
+      , m_session(session)
+{
+    connect(m_session, SIGNAL(readyForCaptureChanged(bool)), this, SIGNAL(readyForCaptureChanged(bool)));
+    connect(m_session, SIGNAL(imageExposed(int)), this, SIGNAL(imageExposed(int)));
+    connect(m_session, SIGNAL(imageCaptured(int,QImage)), this, SIGNAL(imageCaptured(int,QImage)));
+    connect(m_session, SIGNAL(imageMetadataAvailable(int,QString,QVariant)), this, SIGNAL(imageMetadataAvailable(int,QString,QVariant)));
+    connect(m_session, SIGNAL(imageAvailable(int,QVideoFrame)), this, SIGNAL(imageAvailable(int,QVideoFrame)));
+    connect(m_session, SIGNAL(imageSaved(int,QString)), this, SIGNAL(imageSaved(int,QString)));
+    connect(m_session, SIGNAL(imageCaptureError(int,int,QString)), this, SIGNAL(error(int,int,QString)));
+}
+
+bool QOhCameraImageCaptureControl::isReadyForCapture() const
+{
+    return m_session->isReadyForCapture();
+}
+
+QCameraImageCapture::DriveMode QOhCameraImageCaptureControl::driveMode() const
+{
+    return m_session->driveMode();
+}
+
+void QOhCameraImageCaptureControl::setDriveMode(QCameraImageCapture::DriveMode mode)
+{
+    m_session->setDriveMode(mode);
+}
+
+int QOhCameraImageCaptureControl::capture(const QString &fileName)
+{
+    return m_session->capture(fileName);
+}
+
+void QOhCameraImageCaptureControl::cancelCapture()
+{
+    m_session->cancelCapture();
+}
diff --git a/src/plugins/openharmony/src/mediacapture/qohcameraimagecapturecontrol.h b/src/plugins/openharmony/src/mediacapture/qohcameraimagecapturecontrol.h
new file mode 100644
index 000000000..32efa8815
--- /dev/null
+++ b/src/plugins/openharmony/src/mediacapture/qohcameraimagecapturecontrol.h
@@ -0,0 +1,29 @@
+#ifndef QOHCAMERAIMAGECAPTURECONTROL_H
+#define QOHCAMERAIMAGECAPTURECONTROL_H
+
+#include <QCameraImageCaptureControl>
+
+QT_BEGIN_NAMESPACE
+
+class QOhCameraSession;
+
+class QOhCameraImageCaptureControl : public QCameraImageCaptureControl
+{
+    Q_OBJECT
+public:
+    explicit QOhCameraImageCaptureControl(QOhCameraSession *session);
+
+    bool isReadyForCapture() const override;
+
+    QCameraImageCapture::DriveMode driveMode() const override;
+    void setDriveMode(QCameraImageCapture::DriveMode mode) override;
+
+    int capture(const QString &fileName) override;
+    void cancelCapture() override;
+
+private:
+    QOhCameraSession *m_session;
+};
+
+QT_END_NAMESPACE
+#endif // QOHCAMERAIMAGECAPTURECONTROL_H
diff --git a/src/plugins/openharmony/src/mediacapture/qohcamerainfocontrol.cpp b/src/plugins/openharmony/src/mediacapture/qohcamerainfocontrol.cpp
new file mode 100644
index 000000000..784b39663
--- /dev/null
+++ b/src/plugins/openharmony/src/mediacapture/qohcamerainfocontrol.cpp
@@ -0,0 +1,40 @@
+#include "qohcamerasession.h"
+#include "qohcamerainfocontrol.h"
+
+QT_BEGIN_NAMESPACE
+
+QCamera::Position QOhCameraInfoControl::cameraPosition(const QString &deviceName) const
+{
+    return position(deviceName);
+}
+
+int QOhCameraInfoControl::cameraOrientation(const QString &deviceName) const
+{
+    return orientation(deviceName);
+}
+
+QCamera::Position QOhCameraInfoControl::position(const QString &deviceName)
+{
+    const QList<OhCameraInfo> &cameras = QOhCameraSession::availableCameras();
+    for (int i = 0; i < cameras.count(); ++i) {
+        const OhCameraInfo &info = cameras.at(i);
+        if (QString::fromLatin1(info.name) == deviceName)
+            return info.position;
+    }
+
+    return QCamera::UnspecifiedPosition;
+}
+
+int QOhCameraInfoControl::orientation(const QString &deviceName)
+{
+    const QList<OhCameraInfo> &cameras = QOhCameraSession::availableCameras();
+    for (int i = 0; i < cameras.count(); ++i) {
+        const OhCameraInfo &info = cameras.at(i);
+        if (QString::fromLatin1(info.name) == deviceName)
+            return info.orientation;
+    }
+
+    return 0;
+}
+
+QT_END_NAMESPACE
diff --git a/src/plugins/openharmony/src/mediacapture/qohcamerainfocontrol.h b/src/plugins/openharmony/src/mediacapture/qohcamerainfocontrol.h
new file mode 100644
index 000000000..76a793dbd
--- /dev/null
+++ b/src/plugins/openharmony/src/mediacapture/qohcamerainfocontrol.h
@@ -0,0 +1,22 @@
+#ifndef QOHCAMERAINFOCONTROL_H
+#define QOHCAMERAINFOCONTROL_H
+
+#include <qcamerainfocontrol.h>
+
+QT_BEGIN_NAMESPACE
+
+class QOhCameraInfoControl : public QCameraInfoControl
+{
+    Q_OBJECT
+
+public:
+    QCamera::Position cameraPosition(const QString &deviceName) const;
+    int cameraOrientation(const QString &deviceName) const;
+
+    static QCamera::Position position(const QString &deviceName);
+    static int orientation(const QString &deviceName);
+};
+
+QT_END_NAMESPACE
+
+#endif // QOHCAMERAINFOCONTROL_H
diff --git a/src/plugins/openharmony/src/mediacapture/qohcamerarendercontrol.cpp b/src/plugins/openharmony/src/mediacapture/qohcamerarendercontrol.cpp
new file mode 100644
index 000000000..3068fb3f5
--- /dev/null
+++ b/src/plugins/openharmony/src/mediacapture/qohcamerarendercontrol.cpp
@@ -0,0 +1,44 @@
+#include <arkui/native_node.h>
+#include <arkui/native_type.h>
+#include <arkui/native_interface.h>
+
+#include "qohcamerasession.h"
+#include "qohcamerarendercontrol.h"
+
+QT_BEGIN_NAMESPACE
+
+QOhCameraRenderControl::QOhCameraRenderControl(QOhCameraSession* session, QObject *parent)
+    : QVideoRendererControl(parent)
+    , m_surface(nullptr)
+    , m_session(session)
+{
+}
+
+QOhCameraRenderControl::~QOhCameraRenderControl()
+{
+
+};
+
+QAbstractVideoSurface *QOhCameraRenderControl::surface() const
+{
+    return m_surface;
+}
+
+void QOhCameraRenderControl::setSurface(QAbstractVideoSurface *surface)
+{
+    m_surface = surface;
+    if(m_session)
+    {
+        m_session->setSurface(surface);
+    }
+}
+
+void QOhCameraRenderControl::setSession(QOhCameraSession *session)
+{
+    m_session = session;
+    if(session && m_surface)
+    {
+        m_session->setSurface(m_surface);
+    }
+}
+QT_BEGIN_NAMESPACE
diff --git a/src/plugins/openharmony/src/mediacapture/qohcamerarendercontrol.h b/src/plugins/openharmony/src/mediacapture/qohcamerarendercontrol.h
new file mode 100644
index 000000000..1b4b1470f
--- /dev/null
+++ b/src/plugins/openharmony/src/mediacapture/qohcamerarendercontrol.h
@@ -0,0 +1,28 @@
+#ifndef QOHCAMERARENDERCONTROL_H
+#define QOHCAMERARENDERCONTROL_H
+
+#include <qvideorenderercontrol.h>
+
+QT_BEGIN_NAMESPACE
+
+class QOhCameraSession;
+
+class QOhCameraRenderControl : public QVideoRendererControl
+{
+    Q_OBJECT
+public:
+    QOhCameraRenderControl(QOhCameraSession* session, QObject *parent = nullptr);
+    ~QOhCameraRenderControl() override;
+
+    QAbstractVideoSurface *surface() const override;
+    void setSurface(QAbstractVideoSurface *surface) override;
+
+    void setSession(QOhCameraSession* session);
+
+private:
+    QAbstractVideoSurface *m_surface;
+    QOhCameraSession *m_session;
+};
+
+QT_END_NAMESPACE
+#endif // QOHCAMERARENDERCONTROL_H
diff --git a/src/plugins/openharmony/src/mediacapture/qohcamerasession.cpp b/src/plugins/openharmony/src/mediacapture/qohcamerasession.cpp
new file mode 100644
index 000000000..55628bd7b
--- /dev/null
+++ b/src/plugins/openharmony/src/mediacapture/qohcamerasession.cpp
@@ -0,0 +1,1112 @@
+#include "qohcamerasession.h"
+#include "ohmultimediautils.h"
+#include "../player/qohnativevideobuffer.h"
+#include <qelapsedtimer.h>
+#include <qfile.h>
+
+#include <QAbstractVideoSurface>
+#include <QtMultimedia/qvideosurfaceformat.h>
+#include <QtConcurrent/qtconcurrentrun.h>
+
+#include "ohcamera/camera.h"
+#include "ohcamera/camera_input.h"
+#include "ohcamera/capture_session.h"
+#include "ohcamera/photo_output.h"
+#include "ohcamera/preview_output.h"
+#include "ohcamera/video_output.h"
+#include "ohcamera/camera_manager.h"
+#include <qguiapplication.h>
+
+#include <multimedia/image_framework/image/image_native.h>
+#include <multimedia/image_framework/image/image_receiver_native.h>
+
+QT_BEGIN_NAMESPACE
+
+Q_GLOBAL_STATIC(QList<OhCameraInfo>, deviceList)
+
+Camera_Manager *QOhCameraSession::g_cameraManager = nullptr;
+Camera_Device *QOhCameraSession::g_cameras = nullptr;
+uint32_t QOhCameraSession::g_camerasCount = 0;
+
+QOhCameraSession *p_cameraSession = nullptr;
+void OnCallback(OH_ImageReceiverNative *receiver){
+    if(p_cameraSession)
+        p_cameraSession->onReceiverCallback(receiver);
+}
+
+QVideoFrame imageNativeToVideoFrame(OH_ImageNative *image, Camera_Format fromat) {
+    Image_Size imgSize;
+    Image_ErrorCode errCode = OH_ImageNative_GetImageSize(image, &imgSize);
+    if (errCode != IMAGE_SUCCESS) {
+        qWarning() << "Failed to get image size, error code:" << errCode;
+        return QVideoFrame();
+    }
+
+    size_t componentTypeSize = 0;
+    OH_ImageNative_GetComponentTypes(image, nullptr, &componentTypeSize);
+    if (componentTypeSize == 0) {
+        qWarning() << "Failed to get image component type size";
+        return QVideoFrame();
+    }
+    uint32_t* components = new uint32_t[componentTypeSize];
+    errCode = OH_ImageNative_GetComponentTypes(image, &components, &componentTypeSize);
+    if (errCode != IMAGE_SUCCESS) {
+        qWarning() << "Failed to get image component types, error code:" << errCode;
+        delete[] components;
+        return QVideoFrame();
+    }
+
+    OH_NativeBuffer* nativeBuffer = nullptr;
+    errCode = OH_ImageNative_GetByteBuffer(image, components[0], &nativeBuffer);
+    if (errCode != IMAGE_SUCCESS) {
+        qWarning() << "Failed to get image byte buffer, error code:" << errCode;
+        delete[] components;
+        return QVideoFrame();
+    }
+
+    size_t nativeBufferSize = 0;
+    errCode = OH_ImageNative_GetBufferSize(image, components[0], &nativeBufferSize);
+    if (errCode != IMAGE_SUCCESS) {
+        qWarning() << "Failed to get buffer size, error code:" << errCode;
+        delete[] components;
+        return QVideoFrame();
+    }
+
+    int32_t rowStride = 0;
+    errCode = OH_ImageNative_GetRowStride(image, components[0], &rowStride);
+    if (errCode != IMAGE_SUCCESS) {
+        qWarning() << "Failed to get row stride, error code:" << errCode;
+        delete[] components;
+        return QVideoFrame();
+    }
+    delete[] components;
+
+    void* srcVir = nullptr;
+    OH_NativeBuffer_Map(nativeBuffer, &srcVir);
+    uint8_t* srcBuffer = static_cast<uint8_t*>(srcVir);
+
+    QVideoFrame result;
+    switch (fromat) {
+    case CAMERA_FORMAT_YUV_420_SP: {
+        OH_NativeBuffer_Config config{};
+        OH_NativeBuffer_GetConfig(nativeBuffer, &config);
+        const int dataSize = config.stride * config.height * 3 / 2;
+        uchar *dataCopy = new uchar[dataSize];
+        memcpy(dataCopy, srcBuffer, dataSize);
+        OH_NativeBuffer_Unmap(nativeBuffer);
+        auto *videoBuffer = new QOhNativeVideoBuffer(dataCopy, dataSize, config, config.stride);
+        QVideoFrame nv21Frame(videoBuffer, QSize(imgSize.width, imgSize.height), QVideoFrame::Format_NV21);
+        QImage argb = nv21Frame.image();
+        if (!argb.isNull())
+            result = QVideoFrame(argb);
+        return result;
+    }
+    case CAMERA_FORMAT_JPEG: {
+        uchar *dataCopy = new uchar[nativeBufferSize];
+        memcpy(dataCopy, srcBuffer, nativeBufferSize);
+        OH_NativeBuffer_Unmap(nativeBuffer);
+        QImage img;
+        img.loadFromData(dataCopy, static_cast<int>(nativeBufferSize), "JPEG");
+        delete[] dataCopy;
+        if (!img.isNull())
+            result = QVideoFrame(img);
+        return result;
+    }
+    case CAMERA_FORMAT_RGBA_8888:
+        result = QVideoFrame(nativeBufferSize, QSize(imgSize.width, imgSize.height),
+                             rowStride, QVideoFrame::Format_RGB32);
+        if (result.map(QAbstractVideoBuffer::WriteOnly)) {
+            memcpy(result.bits(), srcBuffer, result.mappedBytes());
+            result.unmap();
+        }
+        break;
+    default:
+        break;
+    }
+    OH_NativeBuffer_Unmap(nativeBuffer);
+    return result;
+}
+
+QOhCameraSession::QOhCameraSession(QObject *parent) : QObject{ parent }
+    , m_state(QCamera::UnloadedState)
+    , m_savedState(-1)
+    , m_status(QCamera::UnloadedStatus)
+    , m_captureMode(QCamera::CaptureStillImage)
+    , m_captureCanceled(false)
+    , m_lastImageCaptureId(0)
+    , m_captureDestination(QCameraImageCapture::CaptureToFile)
+    , m_captureImageDriveMode(QCameraImageCapture::SingleImageCapture)
+    , m_readyForCapture(false)
+    , m_currentImageCaptureId(-1)
+{
+    p_cameraSession = this;
+
+    m_mediaStorageLocation.addStorageLocation(
+            QMediaStorageLocation::Pictures,
+            OhMultimediaUtils::getDefaultMediaDirectory(OhMultimediaUtils::Image));
+
+    if (qApp) {
+        connect(qApp, SIGNAL(applicationStateChanged(Qt::ApplicationState)),
+                this, SLOT(onApplicationStateChanged(Qt::ApplicationState)));
+    }
+    initCameraSession();
+    m_surfaceID[0] = '\0';
+}
+
+QOhCameraSession::~QOhCameraSession()
+{
+    if(m_state != QCamera::UnloadedState)
+    {
+        unload();
+    }
+
+    if(g_cameraManager && cameraOutputCapability_)
+    {
+        OH_CameraManager_DeleteSupportedCameraOutputCapability(g_cameraManager, cameraOutputCapability_);
+        cameraOutputCapability_ = nullptr;
+    }
+
+    if(g_cameras)
+    {
+        OH_CameraManager_DeleteSupportedCameras(g_cameraManager, g_cameras, g_camerasCount);
+        g_cameras = nullptr;
+        g_camerasCount = 0;
+        deviceList->clear();
+    }
+
+    if(captureSession_)
+    {
+        OH_CaptureSession_Release(captureSession_);
+        captureSession_ = nullptr;
+    }
+
+    if(g_cameraManager)
+    {
+        OH_Camera_DeleteCameraManager(g_cameraManager);
+        g_cameraManager = nullptr;
+    }
+
+    p_cameraSession = nullptr;
+}
+
+const QList<OhCameraInfo> &QOhCameraSession::availableCameras()
+{    
+    if (deviceList->isEmpty())
+        updateAvailableCameras();
+
+    return *deviceList;
+}
+
+void QOhCameraSession::setState(QCamera::State state)
+{
+    if (m_state == state)
+        return;
+
+           // If the application is inactive, the camera shouldn't be started. Save the desired state
+           // instead and it will be set when the application becomes active.
+    ////TODO applicationStateChanged信号无法触发,暂时不做判断
+    // if (qApp->applicationState() == Qt::ApplicationActive)
+    //     setStateHelper(state);
+    // else
+    //     m_savedState = state;
+
+    setStateHelper(state);
+}
+
+void QOhCameraSession::setDevice(const QString &device)
+{
+    m_sourceDeviceName = device;
+    if(!g_cameraManager) return;
+
+    if(cameraOutputCapability_)
+    {
+        OH_CameraManager_DeleteSupportedCameraOutputCapability(g_cameraManager, cameraOutputCapability_);
+        cameraOutputCapability_ = nullptr;
+        unload();
+    }
+
+    if(!g_cameras)
+    {
+        updateAvailableCameras();
+    }
+
+    m_deviceIndex = (m_sourceDeviceName == QLatin1String("default") ? 0 : -1);
+    for(uint32_t i = 0; i < g_camerasCount; ++i)
+    {
+        if(QString(g_cameras[i].cameraId) == m_sourceDeviceName)
+        {
+            m_deviceIndex = i;
+        }
+    }
+
+    if(m_deviceIndex < 0)
+    {
+        qWarning() << QString("camera %1 not exsists!").arg(m_sourceDeviceName);
+        return;
+    }
+
+    Camera_ErrorCode ret;
+    ret = OH_CameraManager_GetSupportedCameraOutputCapability(g_cameraManager, &g_cameras[m_deviceIndex],
+                                                               &cameraOutputCapability_);
+
+    if (!cameraOutputCapability_ || ret != CAMERA_OK \
+        || cameraOutputCapability_->previewProfilesSize == 0) {
+        qWarning() << "OH_CameraManager_GetSupportedCameraOutputCapability falied!";
+        return;
+    }
+
+    Q_EMIT loaded();
+}
+
+void QOhCameraSession::setStateHelper(QCamera::State state)
+{
+    bool succeeded = false;
+    switch (state) {
+    case QCamera::UnloadedState:
+        succeeded = unload();
+        break;
+    case QCamera::LoadedState:
+    case QCamera::ActiveState:
+        if (m_state == QCamera::UnloadedState && !load())
+            return;
+
+        if (state == QCamera::ActiveState)
+            succeeded = startPreview();
+        else if (state == QCamera::LoadedState)
+            succeeded = stopPreview();
+        break;
+    }
+
+    if (succeeded) {
+        m_state = state;
+        emit stateChanged(m_state);
+
+        QCamera::Status newStatus;
+        switch (state) {
+        case QCamera::ActiveState:
+            newStatus = QCamera::ActiveStatus;
+            break;
+        case QCamera::LoadedState:
+            newStatus = QCamera::LoadedStatus;
+            break;
+        case QCamera::UnloadedState:
+        default:
+            newStatus = QCamera::UnloadedStatus;
+            break;
+        }
+        if (m_status != newStatus) {
+            m_status = newStatus;
+            emit statusChanged(m_status);
+        }
+    }
+}
+
+void QOhCameraSession::initCameraSession()
+{
+    Camera_ErrorCode ret;
+
+    if(!g_cameraManager){
+        ret = OH_Camera_GetCameraManager(&g_cameraManager);
+        if (!g_cameraManager || ret != CAMERA_OK)
+        {
+            qWarning() << "OH_Camera_GetCameraManager failed!";
+            return;
+        }
+    }
+
+    ret = OH_CameraManager_CreateCaptureSession(g_cameraManager, &captureSession_);
+    if (captureSession_ == nullptr || ret != CAMERA_OK)
+    {
+        qWarning() << "OH_CameraManager_CreateCaptureSession failed!";
+        return;
+    }
+}
+
+bool QOhCameraSession::initReceiver(uint32_t width, uint32_t height)
+{
+    // 创建 OH_ImageReceiverOptions 实例
+    m_recOptions = nullptr;
+    Image_ErrorCode errCode = OH_ImageReceiverOptions_Create(&m_recOptions);
+    if (errCode != IMAGE_SUCCESS) {
+        qWarning() << "ImageReceiverNativeCTest create image receiver options failed, errCode: "<<errCode;
+        return false;
+    }
+
+    Image_Size imgSize;
+    imgSize.width = width;
+    imgSize.height = height;
+
+    // 设置 OH_ImageReceiverOptions 的 size 属性
+    errCode = OH_ImageReceiverOptions_SetSize(m_recOptions, imgSize);
+    if (errCode != IMAGE_SUCCESS) {
+        qWarning() << "ImageReceiverNativeCTest set image receiver options size failed, errCode: "<< errCode;
+        stopReceiver();
+        return false;
+    }
+
+    // 设置 OH_ImageReceiverOptions 的 capacity 属性
+    int32_t image_capcity = 8;
+    errCode = OH_ImageReceiverOptions_SetCapacity(m_recOptions, image_capcity);
+    if (errCode != IMAGE_SUCCESS) {
+        qWarning() << "ImageReceiverNativeCTest set image receiver options capacity failed, errCode: "<< errCode;
+        stopReceiver();
+        return false;
+    }
+
+    // 创建 OH_ImageReceiverNative 实例
+    m_receiver = nullptr;
+    errCode = OH_ImageReceiverNative_Create(m_recOptions, &m_receiver);
+    if (errCode != IMAGE_SUCCESS) {
+        qWarning() << "ImageReceiverNativeCTest create image receiver failed, errCode: "<< errCode;
+        stopReceiver();
+        return false;
+    }
+
+    // 注册一个回调事件,每当接收到新的图片,该回调事件就会响应。
+    errCode = OH_ImageReceiverNative_On(m_receiver, OnCallback);
+    if (errCode != IMAGE_SUCCESS) {
+        qWarning() << "ImageReceiverNativeCTest image receiver on failed, errCode: "<< errCode;
+        stopReceiver();
+        return false;
+    }
+
+    // 读取 OH_ImageReceiverNative 的 surfaceID 属性
+    uint64_t surfaceID = 0;
+    errCode = OH_ImageReceiverNative_GetReceivingSurfaceId(m_receiver, &surfaceID);
+    if (errCode != IMAGE_SUCCESS) {
+        qWarning() << "ImageReceiverNativeCTest get image receiver surfaceID failed, errCode: "<< errCode;
+        stopReceiver();
+        return false;
+    }
+
+    sprintf(m_surfaceID, "%ld", surfaceID);
+    return true;
+}
+
+void QOhCameraSession::stopReceiver()
+{
+    if(m_recOptions)
+    {
+        OH_ImageReceiverOptions_Release(m_recOptions);
+        m_recOptions = nullptr;
+    }
+    if(m_receiver)
+    {
+        OH_ImageReceiverNative_Release(m_receiver);
+        m_receiver = nullptr;
+    }
+
+    m_surfaceID[0] = '\0';
+}
+
+void QOhCameraSession::processCapturedImage(int id, const QVideoFrame &data,\
+                                                QCameraImageCapture::CaptureDestinations dest, const QString &fileName)
+{
+    if (dest & QCameraImageCapture::CaptureToFile) {
+
+
+        const QString actualFileName = m_mediaStorageLocation.generateFileName(fileName,
+                                                                               QMediaStorageLocation::Pictures,
+                                                                               QLatin1String("IMG_"),
+                                                                               QLatin1String("jpg"));
+        QImage image = data.image();
+        QFile file(actualFileName);
+        if (!file.open(QIODevice::WriteOnly)) {
+            const QString errorMessage = tr("Could not open destination file: %1").arg(actualFileName);
+            emit imageCaptureError(id, QCameraImageCapture::ResourceError, errorMessage);
+            return;
+        }
+
+        if (!image.save(&file, "JPG")) {
+            emit imageCaptureError(id, QCameraImageCapture::OutOfSpaceError, file.errorString());
+            file.close();
+            return;
+        }
+
+        file.close();
+        emit imageSaved(id, actualFileName);
+    }
+
+    if (dest & QCameraImageCapture::CaptureToBuffer) {
+        emit imageAvailable(id, data);
+    }
+}
+
+QCameraViewfinderSettings QOhCameraSession::profileToSetting(Camera_Profile *profile)
+{
+    QCameraViewfinderSettings s(m_viewfinderSettings);
+
+    s.setResolution(QSize(profile->size.width, profile->size.height));
+    s.setPixelAspectRatio(QSize(1, 1));
+    QVideoFrame::PixelFormat sformat;
+
+    switch(profile->format){
+    case CAMERA_FORMAT_RGBA_8888: sformat = QVideoFrame::Format_RGB32;break;
+    case CAMERA_FORMAT_YUV_420_SP: sformat = QVideoFrame::Format_NV21;break;
+    case CAMERA_FORMAT_JPEG: sformat = QVideoFrame::Format_Jpeg;break;
+    case CAMERA_FORMAT_YCBCR_P010:
+    case CAMERA_FORMAT_YCRCB_P010:
+        sformat = QVideoFrame::Format_User;
+        break;
+    default:
+        sformat = QVideoFrame::Format_Invalid;
+    }
+    s.setPixelFormat(sformat);
+    s.setMinimumFrameRate(30);
+    s.setMaximumFrameRate(30);
+
+    return s;
+}
+
+
+void QOhCameraSession::setCaptureMode(QCamera::CaptureModes mode)
+{
+    m_captureMode = mode;
+}
+
+bool QOhCameraSession::isCaptureModeSupported(QCamera::CaptureModes mode) const
+{
+    return true;
+}
+
+bool QOhCameraSession::isReadyForCapture()
+{
+    return m_status == QCamera::ActiveStatus;
+}
+
+int QOhCameraSession::capture(const QString &fileName)
+{
+    ++m_lastImageCaptureId;
+
+    if (m_captureImageDriveMode == QCameraImageCapture::SingleImageCapture) {
+
+        if (!photoOutput_) {
+            emit imageCaptureError(m_lastImageCaptureId, QCameraImageCapture::NotReadyError,
+                                   tr("Photo output not ready"));
+            return m_lastImageCaptureId;
+        }
+
+        m_currentImageCaptureId = m_lastImageCaptureId;
+        m_currentImageCaptureFileName = fileName;
+
+        emit imageExposed(m_currentImageCaptureId);
+
+        Camera_ErrorCode ret = OH_PhotoOutput_Capture(photoOutput_);
+        if (ret != CAMERA_OK) {
+            qWarning() << "OH_PhotoOutput_Capture failed." << ret;
+            emit imageCaptureError(m_currentImageCaptureId, QCameraImageCapture::ResourceError,
+                                   tr("Capture request failed"));
+        }
+    } else {
+        //: Drive mode is the camera's shutter mode, for example single shot, continuos exposure, etc.
+        emit imageCaptureError(m_lastImageCaptureId, QCameraImageCapture::NotSupportedFeatureError,
+                               tr("Drive mode not supported"));
+    }
+
+    return m_lastImageCaptureId;
+}
+
+void QOhCameraSession::cancelCapture()
+{
+    m_captureCanceled = true;
+}
+
+QCameraImageCapture::DriveMode QOhCameraSession::driveMode() const
+{
+    return m_captureImageDriveMode;
+}
+
+void QOhCameraSession::setDriveMode(QCameraImageCapture::DriveMode mode)
+{
+    m_captureImageDriveMode = mode;
+}
+
+void QOhCameraSession::setReadyForCapture(bool ready)
+{
+    if (m_readyForCapture == ready)
+        return;
+
+    m_readyForCapture = ready;
+    emit readyForCaptureChanged(ready);
+}
+
+QCameraImageCapture::CaptureDestinations QOhCameraSession::captureDestination() const
+{
+    return m_captureDestination;
+}
+
+void QOhCameraSession::setCaptureDestination(QCameraImageCapture::CaptureDestinations destination)
+{
+    if (m_captureDestination != destination) {
+        m_captureDestination = destination;
+        emit captureDestinationChanged(m_captureDestination);
+    }
+}
+
+QCameraViewfinderSettings QOhCameraSession::viewfinderSettings() const
+{
+    return m_status == QCamera::ActiveStatus ? m_actualViewfinderSettings : m_viewfinderSettings;
+}
+
+void QOhCameraSession::setViewfinderSettings(const QCameraViewfinderSettings &settings)
+{
+    if (m_viewfinderSettings == settings)
+        return;
+
+    m_viewfinderSettings = m_actualViewfinderSettings = settings;
+}
+
+void QOhCameraSession::setSurface(QAbstractVideoSurface *surface)
+{
+    if(m_surface == surface)
+        return;
+
+    m_surface = surface;
+}
+
+void QOhCameraSession::onReceiverCallback(OH_ImageReceiverNative *receiver)
+{
+    if(!m_surface) return;
+
+    // 读取 OH_ImageReceiverNative 的下一个图片对象
+    OH_ImageNative* image = nullptr;
+    Image_ErrorCode errCode = OH_ImageReceiverNative_ReadNextImage(receiver, &image);
+    if (errCode != IMAGE_SUCCESS) {
+        qWarning() << "OnCallback ImageReceiverNativeCTest get image receiver next image failed, errCode: "<< errCode;
+        return;
+    }
+
+    if (profile_) {
+        QVideoFrame frame = imageNativeToVideoFrame(image, profile_->format);
+
+        m_presentMutex.lock();
+        m_currentFrame = frame;
+        m_presentMutex.unlock();
+
+        QMetaObject::invokeMethod(this, "presentFrame", Qt::QueuedConnection);
+    }
+
+    // 释放 OH_ImageNative 实例
+    errCode = OH_ImageNative_Release(image);
+}
+
+void QOhCameraSession::onPhotoCallback(Camera_PhotoOutput *photoOutput, OH_PhotoNative *photo)
+{
+    Q_UNUSED(photoOutput)
+    if (!m_captureCanceled) {
+        if (!photoProfile_) {
+            qWarning() << "onPhotoCallback: photoProfile_ is null";
+            return;
+        }
+
+        OH_ImageNative* imageNative;
+        Camera_ErrorCode errCode = OH_PhotoNative_GetMainImage(photo, &imageNative);
+        if (errCode != CAMERA_OK) {
+            qWarning() << "OH_PhotoNative_GetMainImage get image failed, errCode: "<< errCode;
+            return;
+        }
+        QVideoFrame frame = imageNativeToVideoFrame(imageNative, photoProfile_->format);
+
+        if (frame.isValid()) {
+            emit imageCaptured(m_currentImageCaptureId, frame.image());
+        }
+
+        QtConcurrent::run(this, &QOhCameraSession::processCapturedImage,
+                          m_currentImageCaptureId,
+                          frame,
+                          m_captureDestination,
+                          m_currentImageCaptureFileName);
+    }
+
+    m_captureCanceled = false;
+}
+
+bool QOhCameraSession::addVideoOutput(const QString &surfaceID, const QSize &reslotion)
+{
+    Camera_VideoOutput *videoOutput = nullptr;
+    if(!g_cameraManager) return false;
+
+    qDebug() << "record video surfaceID:" << surfaceID;
+    if(m_sessionStarted)
+    {
+        OH_CaptureSession_Stop(captureSession_);
+    }
+
+    Camera_VideoProfile *videoProfile = nullptr;
+    int offset = INT_MAX;
+    int usrPix = reslotion.width() * reslotion.height();
+    for(int i = 0; i < cameraOutputCapability_->videoProfilesSize; ++i)
+    {
+        Camera_VideoProfile *curPro = cameraOutputCapability_->videoProfiles[i];
+        if(curPro->size.width > 4096 || curPro->size.height > 4096) continue;
+
+        int curPix = curPro->size.width * curPro->size.height;
+        if(qAbs(curPix - usrPix) < offset)
+        {
+            offset = qAbs(curPix - usrPix);
+            videoProfile = curPro;
+        }
+    }
+    if (!videoProfile) {
+        qWarning() << "Get previewProfiles failed.";
+        return false;
+    }
+    //videoProfile = cameraOutputCapability->videoProfiles[0];
+
+    Camera_ErrorCode ret;
+    ret = OH_CaptureSession_BeginConfig(captureSession_);
+    if (ret != CAMERA_OK) {
+        qWarning() << "OH_CaptureSession_BeginConfig failed.";
+        return false;
+    }
+
+    if(!cameraInput_){
+        ret = OH_CameraManager_CreateCameraInput(g_cameraManager, &g_cameras[m_deviceIndex], &cameraInput_);
+        if (!cameraInput_ || ret != CAMERA_OK) {
+            qWarning() << "CreateCameraInput failed.";
+            return false;
+        }
+
+        ret = OH_CameraInput_Open(cameraInput_);
+        if (ret != CAMERA_OK) {
+            qWarning() << "CameraInput_Open failed.";
+            return false;
+        }
+
+        ret = OH_CaptureSession_AddInput(captureSession_, cameraInput_);
+        if (ret != CAMERA_OK) {
+            qWarning() << "OH_CaptureSession_AddInput failed.";
+            return false;
+        }
+    }
+
+    ret = OH_CameraManager_CreateVideoOutput(g_cameraManager, videoProfile,\
+                                            surfaceID.toLatin1().data(), &videoOutput);
+    if (videoProfile == nullptr || videoOutput == nullptr || ret != CAMERA_OK) {
+        qWarning() << "OH_CameraManager_CreateVideoOutput failed.";
+    }
+
+    ret = OH_CaptureSession_AddVideoOutput(captureSession_, videoOutput);
+    if (ret != CAMERA_OK) {
+        qWarning() << "OH_CaptureSession_AddVideoOutput failed.";
+        return false;
+    }
+
+    ret = OH_CaptureSession_CommitConfig(captureSession_);
+    if (ret != CAMERA_OK) {
+        qWarning() << "OH_CaptureSession_CommitConfig failed.";
+        return false;
+    }
+
+    ret = OH_CaptureSession_Start(captureSession_);
+    if (ret != CAMERA_OK) {
+        qWarning() << "OH_VideoOutput_Start failed.";
+        return false;
+    }
+
+    ret = OH_VideoOutput_Start(videoOutput);
+    m_sessionStarted = true;
+
+    videoOutput_ = videoOutput;
+    return true;
+}
+
+bool QOhCameraSession::removeVideoOutput()
+{
+    OH_CaptureSession_Stop(captureSession_);
+
+    if(captureSession_ && videoOutput_){
+        OH_CaptureSession_BeginConfig(captureSession_);
+        OH_CaptureSession_RemoveVideoOutput(captureSession_, videoOutput_);
+        OH_CaptureSession_CommitConfig(captureSession_);
+    }
+
+    if (videoOutput_) {
+        OH_VideoOutput_Stop(videoOutput_);
+        OH_VideoOutput_Release(videoOutput_);
+        videoOutput_ = nullptr;
+    }
+
+    if(m_state == QCamera::ActiveState)
+    {
+        OH_CaptureSession_Start(captureSession_);
+        m_sessionStarted = true;
+    }
+    
+    return true;
+}
+
+bool QOhCameraSession::createPreviewOutput()
+{
+    int offset = INT_MAX;
+    int usrPix = m_viewfinderSettings.resolution().width() * m_viewfinderSettings.resolution().height();
+
+    Camera_Format defaultFormat;
+    switch(m_viewfinderSettings.pixelFormat()){
+    case QVideoFrame::Format_RGB32: defaultFormat = CAMERA_FORMAT_RGBA_8888;break;
+    case QVideoFrame::Format_NV21: defaultFormat = CAMERA_FORMAT_YUV_420_SP;break;
+    case QVideoFrame::Format_Jpeg: defaultFormat = CAMERA_FORMAT_JPEG;break;
+    default:
+        defaultFormat = CAMERA_FORMAT_YUV_420_SP;
+    }
+
+    for(int i = 0; i < cameraOutputCapability_->previewProfilesSize; ++i)
+    {
+        Camera_Profile *curPro = cameraOutputCapability_->previewProfiles[i];
+        int curPix = curPro->size.width * curPro->size.height;
+
+        if (!profile_) {
+            offset = qAbs(curPix - usrPix);
+            profile_ = curPro;
+            continue;
+        }
+
+        if (curPro->format == defaultFormat) {
+            if(profile_->format != defaultFormat){
+                offset = qAbs(curPix - usrPix);
+                profile_ = curPro;
+                continue;
+            }
+        } else if (profile_->format == defaultFormat) {
+            continue;
+        }
+
+        if (qAbs(curPix - usrPix) < offset) {
+            offset = qAbs(curPix - usrPix);
+            profile_ = curPro;
+        }
+    }
+    if (!profile_) {
+        qWarning() << "Get previewProfiles failed.";
+        return false;
+    }
+
+    m_actualViewfinderSettings = profileToSetting(profile_);
+
+    initReceiver(profile_->size.width, profile_->size.height);
+    if (m_surface) {
+        if (m_surfaceID[0] != '\0') {
+            Camera_ErrorCode ret;
+            ret = OH_CameraManager_CreatePreviewOutput(g_cameraManager, profile_, m_surfaceID, &previewOutput_);
+            if (m_surfaceID[0] == '\0' || !previewOutput_ || ret != CAMERA_OK) {
+                qWarning() << "CreatePreviewOutput failed or surfaceID not valid.";
+                return false;
+            }
+        }
+        else {
+            qWarning() << "surface not ready.";
+            return false;
+        }
+    } else {
+        qWarning() << "surface not set.";
+        return false;
+    }
+
+    return true;
+}
+
+bool QOhCameraSession::createPhotoOutput()
+{
+    int maxPix = 0;
+
+    for (int i = 0; i < cameraOutputCapability_->photoProfilesSize; ++i)
+    {
+        Camera_Profile *curPro = cameraOutputCapability_->photoProfiles[i];
+        int curPix = curPro->size.width * curPro->size.height;
+        if (curPix > maxPix) {
+            maxPix = curPix;
+            photoProfile_ = curPro;
+        }
+    }
+
+    if (!photoProfile_) {
+        qWarning() << "get photoProfile failed.";
+        return false;
+    }
+
+    Camera_ErrorCode ret;
+    ret = OH_CameraManager_CreatePhotoOutputWithoutSurface(g_cameraManager, photoProfile_, &photoOutput_);
+    if (!photoOutput_ || ret != CAMERA_OK) {
+        qWarning() << "CreatePhotoOutput failed.";
+        return false;
+    }
+
+    ret = OH_PhotoOutput_RegisterPhotoAvailableCallback(photoOutput_, \
+                                                        [](Camera_PhotoOutput* photoOutput, OH_PhotoNative* photo) {
+                                                            if(p_cameraSession)
+                                                                p_cameraSession->onPhotoCallback(photoOutput, photo);
+                                                        });
+
+    return true;
+}
+
+Camera_OutputCapability *QOhCameraSession::cameraAbility()
+{
+    return cameraOutputCapability_;
+}
+
+void QOhCameraSession::presentFrame()
+{
+    m_presentMutex.lock();
+
+    if (m_currentFrame.isValid() && m_surface) {
+        m_surface->present(m_currentFrame);
+        m_currentFrame = QVideoFrame();
+    }
+
+    m_presentMutex.unlock();
+}
+
+void QOhCameraSession::onApplicationStateChanged(Qt::ApplicationState state)
+{
+#if 0
+    switch (state) {
+    case Qt::ApplicationInactive:
+        if (m_state != QCamera::UnloadedState) {
+            m_savedState = m_state;
+            //close(); TODO
+            m_state = QCamera::UnloadedState;
+            emit stateChanged(m_state);
+        }
+        break;
+    case Qt::ApplicationActive:
+        if (m_savedState != -1) {
+            setStateHelper(QCamera::State(m_savedState));
+            m_savedState = -1;
+        }
+        break;
+    default:
+        break;
+    }
+#endif
+}
+
+void QOhCameraSession::updateAvailableCameras()
+{
+    static QElapsedTimer timer;
+    if (timer.isValid() && timer.elapsed() < 500) // ms
+        return;
+
+    deviceList->clear();
+
+    if(!g_cameraManager && OH_Camera_GetCameraManager(&g_cameraManager) != CAMERA_OK)
+    {
+        qWarning() << "OH_Camera_GetCameraManager failed!";
+        return;
+    }
+
+    if(g_cameras)
+    {
+        OH_CameraManager_DeleteSupportedCameras(g_cameraManager, g_cameras, g_camerasCount);
+        g_cameras = nullptr;
+    }
+
+    Camera_ErrorCode ret;
+    ret = OH_CameraManager_GetSupportedCameras(g_cameraManager, &g_cameras, &g_camerasCount);
+    if (g_cameras == nullptr || g_camerasCount == 0 || ret != CAMERA_OK)
+    {
+        qWarning() << "OH_CameraManager_GetSupportedCameras failed or no decices!";
+        return;
+    }
+
+    for(uint32_t i = 0; i < g_camerasCount; ++i)
+    {
+        OhCameraInfo info;
+        info.name = g_cameras[i].cameraId;
+
+        switch(g_cameras[i].connectionType)
+        {
+        case CAMERA_CONNECTION_BUILT_IN: info.description += "Built-in";break;
+        case CAMERA_CONNECTION_USB_PLUGIN: info.description += "using USB";break;
+        case CAMERA_CONNECTION_REMOTE: info.description += "Remote camera";break;
+        default:break;
+        }
+
+        info.description += "-";
+
+        switch(g_cameras[i].cameraType)
+        {
+        case CAMERA_TYPE_DEFAULT: info.description += "Default camera";break;
+        case CAMERA_TYPE_WIDE_ANGLE: info.description += "Wide camera";break;
+        case CAMERA_TYPE_ULTRA_WIDE: info.description += "Ultra wide camera";break;
+        case CAMERA_TYPE_TELEPHOTO: info.description += "Telephoto camera";break;
+        case CAMERA_TYPE_TRUE_DEPTH: info.description += "True depth camera";break;
+        default:break;
+        }
+
+        switch(g_cameras[i].cameraPosition)
+        {
+        case CAMERA_POSITION_UNSPECIFIED: info.position = QCamera::UnspecifiedPosition;break;
+        case CAMERA_POSITION_BACK: info.position = QCamera::BackFace;break;
+        case CAMERA_POSITION_FRONT: info.position = QCamera::FrontFace;break;
+        default:break;
+        }
+
+        info.orientation = 0;
+        deviceList->append(info);
+    }
+
+    timer.restart();
+}
+
+bool QOhCameraSession::load()
+{
+    if (!createPreviewOutput())
+        return false;
+
+    if (m_captureMode.testFlag(QCamera::CaptureStillImage)) {
+        if (!createPhotoOutput())
+            return false;
+    }
+
+    Camera_ErrorCode ret;
+    ret = OH_CaptureSession_BeginConfig(captureSession_);
+    if (ret != CAMERA_OK) {
+        qWarning() << "OH_CaptureSession_BeginConfig failed.";
+        return false;
+    }
+
+    if (!cameraInput_) {
+        ret = OH_CameraManager_CreateCameraInput(g_cameraManager, &g_cameras[m_deviceIndex], &cameraInput_);
+        if (!cameraInput_ || ret != CAMERA_OK) {
+            qWarning() << "CreateCameraInput failed.";
+            return false;
+        }
+
+        ret = OH_CameraInput_Open(cameraInput_);
+        if (ret != CAMERA_OK) {
+            qWarning() << "CameraInput_Open failed.";
+            return false;
+        }
+
+        ret = OH_CaptureSession_AddInput(captureSession_, cameraInput_);
+        if (ret != CAMERA_OK) {
+            qWarning() << "OH_CaptureSession_AddInput failed.";
+            return false;
+        }
+    }
+
+    if (previewOutput_) {
+        ret = OH_CaptureSession_AddPreviewOutput(captureSession_, previewOutput_);
+        if (ret != CAMERA_OK) {
+            qWarning() << "OH_CaptureSession_AddPreviewOutput failed.";
+            return false;
+        }
+    }
+
+    if (photoOutput_) {
+        ret = OH_CaptureSession_AddPhotoOutput(captureSession_, photoOutput_);
+        if (ret != CAMERA_OK) {
+            qWarning() << "OH_CaptureSession_AddPhotoOutput failed.";
+            return false;
+        }
+    }
+
+    ret = OH_CaptureSession_CommitConfig(captureSession_);
+    if (ret != CAMERA_OK) {
+        qWarning() << "OH_CaptureSession_CommitConfig failed.";
+        unload();
+        return false;
+    }
+
+    m_state = QCamera::LoadedState;
+    emit loaded();
+    return true;
+}
+
+bool QOhCameraSession::unload()
+{
+    if(captureSession_ && (previewOutput_ || cameraInput_ || photoOutput_)){
+        OH_CaptureSession_BeginConfig(captureSession_);
+        if(previewOutput_)
+            OH_CaptureSession_RemovePreviewOutput(captureSession_, previewOutput_);
+        if(photoOutput_)
+            OH_CaptureSession_RemovePhotoOutput(captureSession_, photoOutput_);
+        if(cameraInput_)
+            OH_CaptureSession_RemoveInput(captureSession_, cameraInput_);
+        OH_CaptureSession_CommitConfig(captureSession_);
+    }
+
+    profile_ = nullptr;
+    if (previewOutput_) {
+        OH_PreviewOutput_Stop(previewOutput_);
+        OH_PreviewOutput_Release(previewOutput_);
+        previewOutput_ = nullptr;
+    }
+
+    photoProfile_ = nullptr;
+    if (photoOutput_) {
+        OH_PhotoOutput_Release(photoOutput_);
+        photoOutput_ = nullptr;
+    }
+
+    if (cameraInput_) {
+        OH_CameraInput_Close(cameraInput_);
+        OH_CameraInput_Release(cameraInput_);
+        cameraInput_ = nullptr;
+    }
+
+    stopReceiver();
+
+    m_readyForCapture = false;
+    m_currentImageCaptureId = -1;
+    m_currentImageCaptureFileName.clear();
+    m_state = QCamera::UnloadedState;
+    return true;
+}
+
+bool QOhCameraSession::startPreview()
+{
+    if(!captureSession_)
+    {
+        qWarning() << "captureSession is empty!";
+        return false;
+    }
+
+    Camera_ErrorCode ret;
+
+    ret = OH_CaptureSession_Start(captureSession_);
+    if (ret != CAMERA_OK) {
+        qWarning() << "OH_CaptureSession_Start failed.";
+        return false;
+    }
+    m_sessionStarted = true;
+
+    // ret = OH_PreviewOutput_Start(previewOutput_);
+    // if (ret != CAMERA_OK) {
+    //     qWarning() << "OH_PreviewOutput_Start failed.";
+    //     return false;
+    // }
+
+    QVideoSurfaceFormat fomat(QSize(profile_->size.width,profile_->size.height),
+                              QVideoFrame::Format_ARGB32,
+                              QAbstractVideoBuffer::NoHandle);
+    const bool isFront = (m_deviceIndex >= 0
+                          && (uint32_t)m_deviceIndex < g_camerasCount
+                          && g_cameras[m_deviceIndex].cameraPosition == CAMERA_POSITION_FRONT);
+    fomat.setProperty("mirrored", isFront);
+
+    if (m_surface)
+        m_surface->start(fomat);
+
+    setReadyForCapture(true);
+
+    return true;
+}
+
+bool QOhCameraSession::stopPreview()
+{
+    setReadyForCapture(false);
+
+    if(captureSession_)
+    {
+        // OH_PreviewOutput_Stop(previewOutput_);
+        OH_CaptureSession_Stop(captureSession_);
+        m_sessionStarted = false;
+        return true;
+    }
+
+    return false;
+}
+
+QT_END_NAMESPACE
diff --git a/src/plugins/openharmony/src/mediacapture/qohcamerasession.h b/src/plugins/openharmony/src/mediacapture/qohcamerasession.h
new file mode 100644
index 000000000..240263987
--- /dev/null
+++ b/src/plugins/openharmony/src/mediacapture/qohcamerasession.h
@@ -0,0 +1,154 @@
+#ifndef QOHCAMERASESSION_H
+#define QOHCAMERASESSION_H
+
+#include <QObject>
+#include <QMutex>
+#include <QTimer>
+#include <qcamera.h>
+
+#include "ohcamera.h"
+#include <QCameraImageCapture>
+#include <private/qmediastoragelocation_p.h>
+
+QT_BEGIN_NAMESPACE
+
+struct Camera_PreviewOutput;
+struct Camera_VideoOutput;
+struct Camera_Input;
+struct Camera_Manager;
+struct Camera_CaptureSession;
+struct Camera_Device;
+struct Camera_OutputCapability;
+struct Camera_Profile;
+struct Camera_VideoProfile;
+struct OH_ImageReceiverNative;
+struct OH_ImageReceiverOptions;
+struct OH_ImageReceiverNative;
+struct Camera_PhotoOutput;
+struct OH_PhotoNative;
+
+class QOhCameraSession : public QObject
+{
+    Q_OBJECT
+public:
+    explicit QOhCameraSession(QObject *parent = nullptr);
+    ~QOhCameraSession();
+    static const QList<OhCameraInfo> &availableCameras();
+
+    QCamera::State state() const { return m_state; }
+    void setState(QCamera::State state);
+
+    QCamera::Status status() const { return m_status; }
+
+    void setDevice(const QString &device);
+
+    QCamera::CaptureModes captureMode() const { return m_captureMode; }
+    void setCaptureMode(QCamera::CaptureModes mode);
+    bool isCaptureModeSupported(QCamera::CaptureModes mode) const;
+
+    bool isReadyForCapture();
+    int capture(const QString &fileName);
+    void cancelCapture();
+    QCameraImageCapture::DriveMode driveMode() const;
+    void setDriveMode(QCameraImageCapture::DriveMode mode);
+    void setReadyForCapture(bool ready);
+
+    QCameraImageCapture::CaptureDestinations captureDestination() const;
+    void setCaptureDestination(QCameraImageCapture::CaptureDestinations destination);
+
+    QCameraViewfinderSettings viewfinderSettings() const;
+    void setViewfinderSettings(const QCameraViewfinderSettings &settings);
+
+    void setSurface(QAbstractVideoSurface* surface);
+    void onReceiverCallback(OH_ImageReceiverNative *receiver);
+    void onPhotoCallback(Camera_PhotoOutput* photoOutput, OH_PhotoNative* photo);
+
+    bool addVideoOutput(const QString &surfaceID, const QSize &reslotion);
+    bool removeVideoOutput();
+
+    Camera_OutputCapability *cameraAbility();
+    QCameraViewfinderSettings profileToSetting(Camera_Profile *profile);
+Q_SIGNALS:
+    void statusChanged(QCamera::Status status);
+    void stateChanged(QCamera::State);
+    void error(int error, const QString &errorString);
+    void captureModeChanged(QCamera::CaptureModes);
+    void loaded();
+
+    void captureDestinationChanged(QCameraImageCapture::CaptureDestinations destination);
+
+    void readyForCaptureChanged(bool);
+    void imageExposed(int id);
+    void imageCaptured(int id, const QImage &preview);
+    void imageMetadataAvailable(int id, const QString &key, const QVariant &value);
+    void imageAvailable(int id, const QVideoFrame &buffer);
+    void imageSaved(int id, const QString &fileName);
+    void imageCaptureError(int id, int error, const QString &errorString);
+
+private Q_SLOTS:
+    void presentFrame();
+    void onApplicationStateChanged(Qt::ApplicationState state);
+
+private:
+    static void updateAvailableCameras();
+    bool load();
+    bool unload();
+    bool startPreview();
+    bool stopPreview();
+
+    void setStateHelper(QCamera::State state);
+
+    void initCameraSession();
+    bool createPreviewOutput();
+    bool createPhotoOutput();
+
+    bool initReceiver(uint32_t width, uint32_t height);
+    void stopReceiver();
+
+    void processCapturedImage(int id,
+                              const QVideoFrame &data,
+                              QCameraImageCapture::CaptureDestinations dest,
+                              const QString &fileName);
+
+    QString m_sourceDeviceName = QLatin1String("default");
+    char m_surfaceID[21];
+    QAbstractVideoSurface *m_surface = nullptr;
+    QCamera::State m_state;
+    int m_savedState;
+    QCamera::Status m_status;
+    QCamera::CaptureModes m_captureMode;
+    bool m_captureCanceled;
+    int m_lastImageCaptureId;
+    QCameraImageCapture::CaptureDestinations m_captureDestination;
+    QCameraImageCapture::DriveMode m_captureImageDriveMode;
+    bool m_readyForCapture;
+    int m_currentImageCaptureId;
+    QString m_currentImageCaptureFileName;
+
+    QMediaStorageLocation m_mediaStorageLocation;
+
+    QMutex m_presentMutex;
+    QVideoFrame m_currentFrame;
+
+    QCameraViewfinderSettings m_viewfinderSettings;
+    QCameraViewfinderSettings m_actualViewfinderSettings;
+
+    Camera_PreviewOutput *previewOutput_ = nullptr;
+    Camera_PhotoOutput* photoOutput_ = nullptr;
+    Camera_VideoOutput *videoOutput_ = nullptr;
+    static Camera_Manager *g_cameraManager;
+    static Camera_Device *g_cameras;
+    static uint32_t g_camerasCount;
+    Camera_Input *cameraInput_ = nullptr;
+    int m_deviceIndex = 0;
+    Camera_CaptureSession *captureSession_ = nullptr;
+    bool m_sessionStarted = false;
+    Camera_OutputCapability *cameraOutputCapability_ = nullptr;
+    Camera_Profile *profile_ = nullptr;
+    Camera_Profile *photoProfile_ = nullptr;
+    OH_ImageReceiverOptions *m_recOptions = nullptr;
+    OH_ImageReceiverNative *m_receiver = nullptr;
+};
+
+QT_END_NAMESPACE
+#endif // QOHCAMERASESSION_H
diff --git a/src/plugins/openharmony/src/mediacapture/qohcaptureservice.cpp b/src/plugins/openharmony/src/mediacapture/qohcaptureservice.cpp
new file mode 100644
index 000000000..53d020f18
--- /dev/null
+++ b/src/plugins/openharmony/src/mediacapture/qohcaptureservice.cpp
@@ -0,0 +1,97 @@
+#include "qohcamerasession.h"
+#include "qohcapturesession.h"
+#include "qohcameracontrol.h"
+#include "qohcaptureservice.h"
+#include "qmediaserviceproviderplugin.h"
+#include "qohcamerainfocontrol.h"
+#include "qohcamerarendercontrol.h"
+#include "qohcameraimagecapturecontrol.h"
+#include "qohdevicecontrol.h"
+#include "qohrecordercontrol.h"
+#include "qohaudioencodercontrol.h"
+#include "qohcontainercontrol.h"
+#include "qohvideoencodercontrol.h"
+#include "qohviewfindersettingscontrol2.h"
+
+QOhCaptureService::QOhCaptureService(QObject *parent)
+    : QMediaService{ parent }
+{
+    m_cameraSession = new QOhCameraSession();
+    m_cameraControl = new QOhCameraControl(m_cameraSession);
+    m_cameraInfoControl = new QOhCameraInfoControl();
+    m_videoDevice = new QOhDeviceControl(m_cameraSession);
+    m_viewfinderSettings = new QOhViewfinderSettingsControl2(m_cameraSession);
+
+    m_captureSession = new QOhCaptureSession(m_cameraSession);
+    m_recorderControl = new QOhRecorderControl(m_captureSession);
+    m_audioEncoderSettingsControl = new QOhAudioEncoderControl(m_captureSession);
+    m_mediaContainerControl = new QOhContainerControl(m_captureSession);
+    m_imageCaptureControl = new QOhCameraImageCaptureControl(m_cameraSession);
+    m_videoEncoderSettingsControl = new QOhVideoEncoderControl(m_captureSession);
+}
+
+QOhCaptureService::~QOhCaptureService()
+{
+    delete m_videoEncoderSettingsControl;
+    delete m_imageCaptureControl;
+    delete m_mediaContainerControl;
+    delete m_audioEncoderSettingsControl;
+    delete m_recorderControl;
+    delete m_captureSession;
+
+    delete m_viewfinderSettings;
+    delete m_videoDevice;
+    delete m_cameraInfoControl;
+    delete m_cameraControl;
+    delete m_cameraSession;
+}
+
+QMediaControl *QOhCaptureService::requestControl(const char *name)
+{
+    if (qstrcmp(name, QMediaRecorderControl_iid) == 0)
+        return m_recorderControl;
+
+    if (qstrcmp(name, QMediaContainerControl_iid) == 0)
+        return m_mediaContainerControl;
+
+    if (qstrcmp(name, QCameraImageCaptureControl_iid) == 0)
+        return m_imageCaptureControl;
+
+    if (qstrcmp(name, QAudioEncoderSettingsControl_iid) == 0)
+        return m_audioEncoderSettingsControl;
+
+    if (qstrcmp(name, QVideoEncoderSettingsControl_iid) == 0)
+        return m_videoEncoderSettingsControl;
+
+    if(qstrcmp(name,QCameraControl_iid) == 0)
+        return m_cameraControl;
+
+    if (qstrcmp(name, QCameraInfoControl_iid) == 0)
+        return m_cameraInfoControl;
+
+    if (qstrcmp(name,QVideoRendererControl_iid) == 0) {
+        if (!m_videoRenderer) {
+            m_videoRenderer = new QOhCameraRenderControl(m_cameraSession, this);
+            return m_videoRenderer;
+        }
+    }
+
+    if (qstrcmp(name, QVideoDeviceSelectorControl_iid) == 0)
+        return m_videoDevice;
+
+    if (qstrcmp(name, QCameraViewfinderSettingsControl2_iid) == 0)
+        return m_viewfinderSettings;
+    return nullptr;
+}
+
+void QOhCaptureService::releaseControl(QMediaControl *control)
+{
+    if(control){
+        if(control == m_videoRenderer)
+        {
+            delete m_videoRenderer;
+            m_videoRenderer = 0;
+            return;
+        }
+    }
+}
diff --git a/src/plugins/openharmony/src/mediacapture/qohcaptureservice.h b/src/plugins/openharmony/src/mediacapture/qohcaptureservice.h
new file mode 100644
index 000000000..2745b0879
--- /dev/null
+++ b/src/plugins/openharmony/src/mediacapture/qohcaptureservice.h
@@ -0,0 +1,52 @@
+#ifndef QOHCAPTURESERVICE_H
+#define QOHCAPTURESERVICE_H
+
+#include <qmediaservice.h>
+#include <qmediacontrol.h>
+
+QT_BEGIN_NAMESPACE
+
+class QOhCameraControl;
+class QOhCameraSession;
+class QOhCameraInfoControl;
+class QOhCameraRenderControl;
+class QOhCameraImageCaptureControl;
+class QOhDeviceControl;
+class QOhCaptureSession;
+class QOhRecorderControl;
+class QOhAudioEncoderControl;
+class QOhContainerControl;
+class QOhVideoEncoderControl;
+class QOhViewfinderSettingsControl2;
+
+class QOhCaptureService : public QMediaService
+{
+    Q_OBJECT
+
+public:
+    explicit QOhCaptureService(QObject *parent = nullptr);
+    virtual ~QOhCaptureService();
+
+    QMediaControl *requestControl(const char *name);
+    void releaseControl(QMediaControl *);
+
+private:
+    QString m_service;
+
+    QOhCameraSession *m_cameraSession = nullptr;
+    QOhCameraControl *m_cameraControl = nullptr;
+    QOhCameraInfoControl *m_cameraInfoControl = nullptr;
+    QOhCameraRenderControl *m_videoRenderer = nullptr;
+    QOhCameraImageCaptureControl *m_imageCaptureControl = nullptr;
+    QOhDeviceControl *m_videoDevice = nullptr;
+    QOhCaptureSession *m_captureSession = nullptr;
+    QOhRecorderControl *m_recorderControl = nullptr;
+    QOhAudioEncoderControl *m_audioEncoderSettingsControl = nullptr;
+    QOhContainerControl *m_mediaContainerControl = nullptr;
+    QOhVideoEncoderControl *m_videoEncoderSettingsControl = nullptr;
+    QOhViewfinderSettingsControl2 *m_viewfinderSettings = nullptr;
+};
+
+QT_END_NAMESPACE
+
+#endif // QOHCAPTURESERVICE_H
diff --git a/src/plugins/openharmony/src/mediacapture/qohcapturesession.cpp b/src/plugins/openharmony/src/mediacapture/qohcapturesession.cpp
new file mode 100644
index 000000000..7c3ca2b81
--- /dev/null
+++ b/src/plugins/openharmony/src/mediacapture/qohcapturesession.cpp
@@ -0,0 +1,449 @@
+#include "qohcapturesession.h"
+#include "qohcamerasession.h"
+#include "ohmultimediautils.h"
+
+#include "ohcamera/camera.h"
+QT_BEGIN_NAMESPACE
+
+QOhCaptureSession::QOhCaptureSession(QOhCameraSession *cameraSession)
+    : QObject()
+      , m_mediaRecorder(0)
+      , m_cameraSession(cameraSession)
+      , m_duration(0)
+      , m_state(QMediaRecorder::StoppedState)
+      , m_status(QMediaRecorder::UnloadedStatus)
+      , m_containerFormat()
+      , m_containerFormatDirty(true)
+      , m_videoSettingsDirty(true)
+      , m_audioSettingsDirty(true)
+{
+    m_mediaStorageLocation.addStorageLocation(
+            QMediaStorageLocation::Movies,
+            OhMultimediaUtils::getDefaultMediaDirectory(OhMultimediaUtils::Video));
+
+    if(cameraSession) {
+        // onCameraLoaded();
+        connect(cameraSession, SIGNAL(loaded()), this, SLOT(onCameraLoaded()));
+        connect(cameraSession, &QOhCameraSession::statusChanged, this,
+                [this](QCamera::Status status) {
+                    if (status == QCamera::UnavailableStatus) {
+                        setState(QMediaRecorder::StoppedState);
+                        setStatus(QMediaRecorder::UnavailableStatus);
+                        return;
+                    }
+
+                           // Stop recording when stopping the camera.
+                    if (status == QCamera::StoppingStatus) {
+                        setState(QMediaRecorder::StoppedState);
+                        setStatus(QMediaRecorder::UnloadedStatus);
+                        return;
+                    }
+
+                    if (status == QCamera::LoadingStatus)
+                        setStatus(QMediaRecorder::LoadingStatus);
+                });
+        connect(cameraSession, &QOhCameraSession::captureModeChanged, this,
+                [this](QCamera::CaptureModes mode) {
+                    if (!mode.testFlag(QCamera::CaptureVideo)) {
+                        setState(QMediaRecorder::StoppedState);
+                        setStatus(QMediaRecorder::UnloadedStatus);
+                    }
+                });
+        setStatus(QMediaRecorder::LoadedStatus);
+        // connect(cameraSession, &QOhCameraSession::readyForCaptureChanged, this,
+        //         [this](bool ready) {
+        //             if (ready)
+        //                 setStatus(QMediaRecorder::LoadedStatus);
+        //         });
+    }
+    else{
+        // Audio-only recording.
+        setStatus(QMediaRecorder::LoadedStatus);
+    }
+
+    m_notifyTimer.setInterval(1000);
+    connect(&m_notifyTimer, SIGNAL(timeout()), this, SLOT(updateDuration()));
+}
+
+QOhCaptureSession::~QOhCaptureSession()
+{
+    stop();
+    if(m_mediaRecorder)
+    {
+        delete m_mediaRecorder;
+    }
+}
+
+QUrl QOhCaptureSession::outputLocation() const
+{
+    if(m_actualOutputLocation.isEmpty())
+    {
+        return m_requestedOutputLocation;
+    }
+    return m_actualOutputLocation;
+}
+
+bool QOhCaptureSession::setOutputLocation(const QUrl &location)
+{
+    if (m_requestedOutputLocation == location)
+        return false;
+
+    m_actualOutputLocation = QUrl();
+    m_requestedOutputLocation = location;
+
+    if (m_requestedOutputLocation.isEmpty())
+        return true;
+
+    if (m_requestedOutputLocation.isValid()
+        && (m_requestedOutputLocation.isLocalFile() || m_requestedOutputLocation.isRelative())) {
+        return true;
+    }
+
+    m_requestedOutputLocation = QUrl();
+    return false;
+}
+
+qint64 QOhCaptureSession::duration() const
+{
+    return m_duration;
+}
+
+QMediaRecorder::State QOhCaptureSession::state() const
+{
+    return m_state;
+}
+
+QMediaRecorder::Status QOhCaptureSession::status() const
+{
+    return m_status;
+}
+
+void QOhCaptureSession::setState(QMediaRecorder::State state)
+{
+    if (m_state == state)
+        return;
+
+    switch (state) {
+    case QMediaRecorder::StoppedState:
+        stop();
+        break;
+    case QMediaRecorder::RecordingState:
+        start();
+        break;
+    case QMediaRecorder::PausedState:
+        paused();
+        break;
+    }
+}
+
+void QOhCaptureSession::setContainerFormat(const QString &format)
+{
+    if (m_containerFormat == format)
+        return;
+
+    m_containerFormat = format;
+    m_containerFormatDirty = true;
+}
+
+void QOhCaptureSession::setAudioSettings(const QAudioEncoderSettings &settings)
+{
+    if (m_audioSettings == settings)
+        return;
+
+    m_audioSettings = settings;
+    m_audioSettingsDirty = true;
+}
+
+void QOhCaptureSession::setVideoSettings(const QVideoEncoderSettings &settings)
+{
+    if (!m_cameraSession || m_videoSettings == settings)
+        return;
+
+    m_videoSettings = settings;
+    m_videoSettingsDirty = true;
+}
+
+void QOhCaptureSession::applySettings()
+{
+    // container settings
+    if (m_containerFormatDirty) {
+        //only support mp4
+        m_containerFormat = QStringLiteral("mp4");
+        m_containerFormatDirty = false;
+    }
+
+    // audio settings
+    if (m_audioSettingsDirty) {
+        if (m_audioSettings.channelCount() <= 0)
+            m_audioSettings.setChannelCount(1);
+        if (m_audioSettings.bitRate() <= 0)
+            m_audioSettings.setBitRate(48000);
+        if (m_audioSettings.sampleRate() <= 0)
+            m_audioSettings.setSampleRate(48000);
+
+        if (m_audioSettings.codec().isEmpty())
+            m_audioEncoder = OhMediaRecorder::AAC;
+        else if (m_audioSettings.codec() == QLatin1String("audio/mp4a-latm"))
+            m_audioEncoder = OhMediaRecorder::AAC;
+        else if (m_audioSettings.codec() == QLatin1String("audio/g711mu"))
+            m_audioEncoder = OhMediaRecorder::G711MU;
+        else
+            m_audioEncoder = OhMediaRecorder::AAC;
+
+        m_audioSettingsDirty = false;
+    }
+
+           // video settings
+    if (m_cameraSession && m_videoSettingsDirty) {
+        if (m_videoSettings.resolution().isEmpty()) {
+            m_videoSettings.setResolution(m_supportedResolutions.back());
+        } else if (!m_supportedResolutions.contains(m_videoSettings.resolution())) {
+            // if the requested resolution is not supported, find the closest one
+            QSize reqSize = m_videoSettings.resolution();
+            int reqPixelCount = reqSize.width() * reqSize.height();
+            QList<int> supportedPixelCounts;
+            for (int i = 0; i < m_supportedResolutions.size(); ++i) {
+                const QSize &s = m_supportedResolutions.at(i);
+                supportedPixelCounts.append(s.width() * s.height());
+            }
+            int closestIndex = qt_findClosestValue(supportedPixelCounts, reqPixelCount);
+            m_videoSettings.setResolution(m_supportedResolutions.at(closestIndex));
+        }
+
+        if (m_supportedFramerates.isEmpty() && \
+            (m_videoSettings.frameRate() <= 0 || m_videoSettings.frameRate() >= m_supportedFramerates.back()) )
+            m_videoSettings.setFrameRate(m_supportedFramerates.back());
+
+        if (m_videoSettings.bitRate() <= 0)
+            m_videoSettings.setBitRate(200000);
+
+        m_videoEncoder = OhMediaRecorder::AVC;
+
+        m_videoSettingsDirty = false;
+    }
+}
+
+void QOhCaptureSession::updateDuration()
+{
+    if (m_elapsedTime.isValid())
+        m_duration = m_elapsedTime.elapsed();
+
+    emit durationChanged(m_duration);
+}
+
+void QOhCaptureSession::onCameraLoaded()
+{
+    Camera_OutputCapability *ability = m_cameraSession->cameraAbility();
+    if(!ability)
+    {
+        return;
+    }
+
+    m_supportedResolutions.clear();
+    m_supportedFramerates.clear();
+
+    QList<int> defaultRates({5, 10, 15, 30, 45, 60});
+
+    for(int i = 0; i < ability->videoProfilesSize; ++i)
+    {
+        Camera_VideoProfile *profile = ability->videoProfiles[i];
+        if(profile->size.width <= 4096 && profile->size.width >= 176 &&\
+           profile->size.height <= 4096 && profile->size.height >= 144){
+            m_supportedResolutions.append(QSize(profile->size.width, profile->size.height));
+        }
+
+        for(int &rate : defaultRates)
+        {
+            if(rate && rate >= profile->range.min && rate <= profile->range.max)
+            {
+                m_supportedFramerates.append(rate);
+                rate = 0;
+            }
+        }
+    }
+
+    m_supportedResolutions = QSet<QSize>(m_supportedResolutions.begin(), m_supportedResolutions.end()).values();
+    std::sort(m_supportedResolutions.begin(), m_supportedResolutions.end(), qt_sizeLessThan);
+    std::sort(m_supportedFramerates.begin(), m_supportedFramerates.end());
+
+    applySettings();
+}
+
+void QOhCaptureSession::onError(int what, int extra)
+{
+    Q_UNUSED(what)
+    Q_UNUSED(extra)
+    stop(true);
+    emit error(QMediaRecorder::ResourceError, QLatin1String("Unknown error."));
+}
+
+void QOhCaptureSession::onInfo(int what, int extra)
+{
+    Q_UNUSED(extra)
+    if (what == 800) {
+        // MEDIA_RECORDER_INFO_MAX_DURATION_REACHED
+        setState(QMediaRecorder::StoppedState);
+        emit error(QMediaRecorder::OutOfSpaceError, QLatin1String("Maximum duration reached."));
+    } else if (what == 801) {
+        // MEDIA_RECORDER_INFO_MAX_FILESIZE_REACHED
+        setState(QMediaRecorder::StoppedState);
+        emit error(QMediaRecorder::OutOfSpaceError, QLatin1String("Maximum file size reached."));
+    }
+}
+
+void QOhCaptureSession::start()
+{
+    if (m_state == QMediaRecorder::PausedState && m_mediaRecorder)
+    {
+        m_mediaRecorder->resume();
+        setStatus(QMediaRecorder::RecordingStatus);
+        m_state = QMediaRecorder::RecordingState;
+        return;
+    }
+
+    if (m_state == QMediaRecorder::RecordingState || m_status != QMediaRecorder::LoadedStatus)
+        return;
+
+    setStatus(QMediaRecorder::StartingStatus);
+
+    if (m_mediaRecorder) {
+        m_mediaRecorder->release();
+        delete m_mediaRecorder;
+    }
+
+    const bool granted = OhMultimediaUtils::qt_openharmonyRequestPermission();
+    if (!granted) {
+        setStatus(QMediaRecorder::UnavailableStatus);
+        Q_EMIT error(QMediaRecorder::ResourceError, QLatin1String("Permission denied."));
+        return;
+    }
+
+    m_mediaRecorder = new OhMediaRecorder;
+    connect(m_mediaRecorder, SIGNAL(error(int,int)), this, SLOT(onError(int,int)));
+    connect(m_mediaRecorder, SIGNAL(info(int,int)), this, SLOT(onInfo(int,int)));
+
+    // Set audio encoder settings
+    m_mediaRecorder->setAudioChannels(m_audioSettings.channelCount());
+    m_mediaRecorder->setAudioEncodingBitRate(m_audioSettings.bitRate());
+    m_mediaRecorder->setAudioSamplingRate(m_audioSettings.sampleRate());
+    m_mediaRecorder->setAudioEncoder(m_audioEncoder);
+
+    // Set video encoder settings
+    if (m_cameraSession) {
+        m_mediaRecorder->setvideoFramSize(m_videoSettings.resolution());
+        m_mediaRecorder->setvideoFrameRate(qRound(m_videoSettings.frameRate()));
+        m_mediaRecorder->setVideoBitrate(m_videoSettings.bitRate());
+        m_mediaRecorder->setVideoEncoder(m_videoEncoder);
+
+        // m_mediaRecorder->setOrientationHint(m_cameraSession->currentCameraRotation());
+    }
+
+    // Set output file
+    QString filePath = m_mediaStorageLocation.generateFileName(
+            m_requestedOutputLocation.isLocalFile() ? m_requestedOutputLocation.toLocalFile()
+                                                    : m_requestedOutputLocation.toString(),
+            QMediaStorageLocation::Movies,
+            QLatin1String("VID_"),
+            m_containerFormat);
+
+    m_usedOutputLocation = QUrl::fromLocalFile(filePath);
+    m_mediaRecorder->setOutputFile(filePath);
+
+    m_mediaRecorder->reset();
+
+    QString videoSurface = m_mediaRecorder->prepare();
+    if (videoSurface.isEmpty()) {
+        emit error(QMediaRecorder::FormatError, QLatin1String("Unable to prepare the media recorder and get surface."));
+        return;
+    }
+
+    if(!m_cameraSession || !m_cameraSession->addVideoOutput(videoSurface, m_videoSettings.resolution()))
+    {
+        emit error(QMediaRecorder::FormatError, QLatin1String("Unable to create videoOutput."));
+        return;
+    }
+
+    if (!m_mediaRecorder->start()) {
+        emit error(QMediaRecorder::FormatError, QLatin1String("Unable to start the media recorder."));
+        return;
+    }
+
+    m_elapsedTime.start();
+    m_notifyTimer.start();
+    updateDuration();
+
+    if(m_state != QMediaRecorder::RecordingState)
+    {
+        m_state = QMediaRecorder::RecordingState;
+        emit stateChanged(m_state);
+    }
+    if(m_status != QMediaRecorder::RecordingStatus)
+    {
+        m_status = QMediaRecorder::RecordingStatus;
+        emit stateChanged(m_state);
+    }
+
+    m_actualOutputLocation = m_usedOutputLocation;
+    emit actualLocationChanged(m_actualOutputLocation);
+}
+
+void QOhCaptureSession::stop(bool error)
+{
+    if (m_state == QMediaRecorder::StoppedState || m_mediaRecorder == 0)
+        return;
+
+    setStatus(QMediaRecorder::FinalizingStatus);
+
+    m_mediaRecorder->stop();
+    m_notifyTimer.stop();
+    updateDuration();
+    m_elapsedTime.invalidate();
+    m_mediaRecorder->release();
+    delete m_mediaRecorder;
+    m_mediaRecorder = 0;
+
+    if(m_cameraSession)
+        m_cameraSession->removeVideoOutput();
+
+    if (!error) {
+        m_actualOutputLocation = m_usedOutputLocation;
+        emit actualLocationChanged(m_actualOutputLocation);
+    }
+
+    m_state = QMediaRecorder::StoppedState;
+    emit stateChanged(m_state);
+    if (!m_cameraSession)
+        setStatus(QMediaRecorder::LoadedStatus);
+}
+
+void QOhCaptureSession::paused()
+{
+    if (m_state != QMediaRecorder::RecordingState || m_mediaRecorder == 0)
+        return;
+
+    m_mediaRecorder->pause();
+
+    m_state = QMediaRecorder::PausedState;
+    setStatus(QMediaRecorder::PausedStatus);
+}
+
+void QOhCaptureSession::setStatus(QMediaRecorder::Status status)
+{
+    if (m_status == status)
+        return;
+
+    m_status = status;
+    emit statusChanged(m_status);
+}
+
+void QOhCaptureSession::updateViewfinder()
+{
+
+}
+
+void QOhCaptureSession::restartViewfinder()
+{
+
+}
+
+QT_END_NAMESPACE
diff --git a/src/plugins/openharmony/src/mediacapture/qohcapturesession.h b/src/plugins/openharmony/src/mediacapture/qohcapturesession.h
new file mode 100644
index 000000000..a9f367fec
--- /dev/null
+++ b/src/plugins/openharmony/src/mediacapture/qohcapturesession.h
@@ -0,0 +1,102 @@
+#ifndef QOHCAPTURESESSION_H
+#define QOHCAPTURESESSION_H
+
+#include <qurl.h>
+#include <qtimer.h>
+#include <qobject.h>
+#include <qelapsedtimer.h>
+#include <qmediarecorder.h>
+#include "ohmediarecorder.h"
+#include <private/qmediastoragelocation_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QOhCameraSession;
+struct Camera_OutputCapability;
+
+class QOhCaptureSession : public QObject
+{
+    Q_OBJECT
+
+public:
+    QOhCaptureSession(QOhCameraSession *cameraSession = Q_NULLPTR);
+    ~QOhCaptureSession();
+
+    QList<QSize> supportedResolutions() const { return m_supportedResolutions; }
+    QList<qreal> supportedFrameRates() const { return m_supportedFramerates; }
+
+    QUrl outputLocation() const;
+    bool setOutputLocation(const QUrl &location);
+
+    qint64 duration() const;
+    QMediaRecorder::State state() const;
+    QMediaRecorder::Status status() const;
+    void setState(QMediaRecorder::State state);
+
+    QString containerFormat() const { return m_containerFormat; }
+    void setContainerFormat(const QString &format);
+
+    QAudioEncoderSettings audioSettings() const { return m_audioSettings; }
+    void setAudioSettings(const QAudioEncoderSettings &settings);
+
+    QVideoEncoderSettings videoSettings() const { return m_videoSettings; }
+    void setVideoSettings(const QVideoEncoderSettings &settings);
+
+    void applySettings();
+Q_SIGNALS:
+    void durationChanged(qint64 position);
+    void audioInputChanged(const QString& name);
+    void stateChanged(QMediaRecorder::State state);
+    void actualLocationChanged(const QUrl &location);
+    void statusChanged(QMediaRecorder::Status status);
+    void error(int error, const QString &errorString);
+
+private Q_SLOTS:
+    void updateDuration();
+    void onCameraLoaded();
+
+    void onError(int what, int extra);
+    void onInfo(int what, int extra);
+
+private:
+    void start();
+    void stop(bool error = false);
+    void paused();
+
+    void setStatus(QMediaRecorder::Status status);
+
+    void updateViewfinder();
+    void restartViewfinder();
+
+    OhMediaRecorder *m_mediaRecorder;
+    QOhCameraSession *m_cameraSession;
+
+    QMediaStorageLocation m_mediaStorageLocation;
+
+    QElapsedTimer m_elapsedTime;
+    QTimer m_notifyTimer;
+    qint64 m_duration;
+
+    QMediaRecorder::State m_state;
+    QMediaRecorder::Status m_status;
+    QUrl m_requestedOutputLocation;
+    QUrl m_usedOutputLocation;
+    QUrl m_actualOutputLocation;
+
+    QString m_containerFormat;
+    QAudioEncoderSettings m_audioSettings;
+    QVideoEncoderSettings m_videoSettings;
+    bool m_containerFormatDirty;
+    bool m_videoSettingsDirty;
+    bool m_audioSettingsDirty;
+    OhMediaRecorder::AudioEncoder m_audioEncoder;
+    OhMediaRecorder::VideoEncoder m_videoEncoder;
+
+    QList<QSize> m_supportedResolutions;
+    QList<qreal> m_supportedFramerates;
+
+};
+
+
+QT_END_NAMESPACE
+#endif // QOHCAPTURESESSION_H
diff --git a/src/plugins/openharmony/src/mediacapture/qohcontainercontrol.cpp b/src/plugins/openharmony/src/mediacapture/qohcontainercontrol.cpp
new file mode 100644
index 000000000..c02d4908f
--- /dev/null
+++ b/src/plugins/openharmony/src/mediacapture/qohcontainercontrol.cpp
@@ -0,0 +1,43 @@
+#include "qohcapturesession.h"
+#include "qohcontainercontrol.h"
+#include <QDebug>
+
+QT_BEGIN_NAMESPACE
+
+QOhContainerControl::QOhContainerControl(QOhCaptureSession *session)
+    : QMediaContainerControl()
+    , m_session(session)
+{
+
+}
+
+QString QOhContainerControl::containerFormat() const
+{
+    return m_session->containerFormat();
+}
+
+QStringList QOhContainerControl::supportedContainers() const
+{
+    return QStringList() << QLatin1String("mp4");
+}
+
+void QOhContainerControl::setContainerFormat(const QString &format)
+{
+    if(format != QLatin1String("mp4"))
+    {
+        qWarning() << "Only supported mp4 format!";
+        return;
+    }
+
+    m_session->setContainerFormat(format);
+}
+
+QString QOhContainerControl::containerDescription(const QString &formatMimeType) const
+{
+    if (formatMimeType == QLatin1String("mp4"))
+        return tr("MPEG4 media file format");
+
+    return QString();
+}
+
+QT_END_NAMESPACE
diff --git a/src/plugins/openharmony/src/mediacapture/qohcontainercontrol.h b/src/plugins/openharmony/src/mediacapture/qohcontainercontrol.h
new file mode 100644
index 000000000..7f6a41b90
--- /dev/null
+++ b/src/plugins/openharmony/src/mediacapture/qohcontainercontrol.h
@@ -0,0 +1,27 @@
+#ifndef QOHCONTAINERCONTROL_H
+#define QOHCONTAINERCONTROL_H
+
+#include <qmediacontainercontrol.h>
+
+QT_BEGIN_NAMESPACE
+class QOhCaptureSession;
+
+class QOhContainerControl : public QMediaContainerControl
+{
+    Q_OBJECT
+
+public:
+    QOhContainerControl(QOhCaptureSession *session);
+
+    QString containerFormat() const override;
+    QStringList supportedContainers() const override;
+    void setContainerFormat(const QString &format) override;
+    QString containerDescription(const QString &formatMimeType) const override;
+
+private:
+    QOhCaptureSession *m_session;
+};
+
+QT_END_NAMESPACE
+
+#endif // QOHCONTAINERCONTROL_H
diff --git a/src/plugins/openharmony/src/mediacapture/qohdevicecontrol.cpp b/src/plugins/openharmony/src/mediacapture/qohdevicecontrol.cpp
new file mode 100644
index 000000000..b15abe209
--- /dev/null
+++ b/src/plugins/openharmony/src/mediacapture/qohdevicecontrol.cpp
@@ -0,0 +1,70 @@
+#include <QDebug>
+#include <qelapsedtimer.h>
+
+#include "qohdevicecontrol.h"
+#include "qohcamerasession.h"
+
+QT_BEGIN_NAMESPACE
+
+QOhDeviceControl::QOhDeviceControl(QObject *parent)
+    : QVideoDeviceSelectorControl(parent)
+{
+    m_session = qobject_cast<QOhCameraSession*>(parent);
+    selected = 0;
+}
+
+QOhDeviceControl::~QOhDeviceControl()
+{
+
+}
+
+int QOhDeviceControl::deviceCount() const
+{
+    const QList<OhCameraInfo> &deviceList = QOhCameraSession::availableCameras();
+    return deviceList.count();
+}
+
+QString QOhDeviceControl::deviceName(int index) const
+{
+    const QList<OhCameraInfo> &deviceList = QOhCameraSession::availableCameras();
+
+    if (index >= 0 && index <= deviceList.count())
+        return QString::fromUtf8(deviceList.at(index).name.constData());
+
+    return QString();
+}
+
+QString QOhDeviceControl::deviceDescription(int index) const
+{
+    const QList<OhCameraInfo> &deviceList = QOhCameraSession::availableCameras();
+
+    if (index >= 0 && index <= deviceList.count())
+        return deviceList.at(index).description;
+
+    return QString();
+}
+
+int QOhDeviceControl::defaultDevice() const
+{
+    return 0;
+}
+
+int QOhDeviceControl::selectedDevice() const
+{
+    return selected;
+}
+
+void QOhDeviceControl::setSelectedDevice(int index)
+{
+    const QList<OhCameraInfo> &deviceList = QOhCameraSession::availableCameras();
+
+    if (index >= 0 && index < deviceList.count()) {
+        if (m_session) {
+            QString device = deviceList.at(index).name;
+            m_session->setDevice(device);
+        }
+        selected = index;
+    }
+}
+
+QT_END_NAMESPACE
diff --git a/src/plugins/openharmony/src/mediacapture/qohdevicecontrol.h b/src/plugins/openharmony/src/mediacapture/qohdevicecontrol.h
new file mode 100644
index 000000000..844f775b0
--- /dev/null
+++ b/src/plugins/openharmony/src/mediacapture/qohdevicecontrol.h
@@ -0,0 +1,32 @@
+#ifndef QOHDEVICECONTROL_H
+#define QOHDEVICECONTROL_H
+
+#include <qvideodeviceselectorcontrol.h>
+
+QT_BEGIN_NAMESPACE
+
+class QOhCameraSession;
+
+class QOhDeviceControl: public QVideoDeviceSelectorControl
+{
+    Q_OBJECT
+public:
+    QOhDeviceControl(QObject *parent = nullptr);
+    ~QOhDeviceControl();
+
+    int deviceCount() const override;
+    QString deviceName(int index) const override;
+    QString deviceDescription(int index) const override;
+    int defaultDevice() const override;
+    int selectedDevice() const override;
+
+public Q_SLOTS:
+    void setSelectedDevice(int index) override;
+
+private:
+    QOhCameraSession* m_session;
+    int selected;
+};
+
+QT_END_NAMESPACE
+#endif // QOHDEVICECONTROL_H
diff --git a/src/plugins/openharmony/src/mediacapture/qohrecordercontrol.cpp b/src/plugins/openharmony/src/mediacapture/qohrecordercontrol.cpp
new file mode 100644
index 000000000..e7fc9d533
--- /dev/null
+++ b/src/plugins/openharmony/src/mediacapture/qohrecordercontrol.cpp
@@ -0,0 +1,70 @@
+#include "qohcapturesession.h"
+#include "qohrecordercontrol.h"
+
+QOhRecorderControl::QOhRecorderControl(QOhCaptureSession *session)
+    :QMediaRecorderControl()
+    , m_session(session)
+{
+    connect(m_session, SIGNAL(stateChanged(QMediaRecorder::State)), this, SIGNAL(stateChanged(QMediaRecorder::State)));
+    connect(m_session, SIGNAL(statusChanged(QMediaRecorder::Status)), this, SIGNAL(statusChanged(QMediaRecorder::Status)));
+    connect(m_session, SIGNAL(durationChanged(qint64)), this, SIGNAL(durationChanged(qint64)));
+    connect(m_session, SIGNAL(actualLocationChanged(QUrl)), this, SIGNAL(actualLocationChanged(QUrl)));
+    connect(m_session, SIGNAL(error(int,QString)), this, SIGNAL(error(int,QString)));
+}
+
+QUrl QOhRecorderControl::outputLocation() const
+{
+    return m_session->outputLocation();
+}
+
+bool QOhRecorderControl::setOutputLocation(const QUrl &location)
+{
+    return m_session->setOutputLocation(location);
+}
+
+QMediaRecorder::State QOhRecorderControl::state() const
+{
+    return m_session->state();
+}
+
+QMediaRecorder::Status QOhRecorderControl::status() const
+{
+    return m_session->status();
+}
+
+qint64 QOhRecorderControl::duration() const
+{
+    return m_session->duration();
+}
+
+bool QOhRecorderControl::isMuted() const
+{
+    return false;
+}
+
+qreal QOhRecorderControl::volume() const
+{
+    return 1.0f;
+}
+
+void QOhRecorderControl::applySettings()
+{
+    m_session->applySettings();
+}
+
+void QOhRecorderControl::setState(QMediaRecorder::State state)
+{
+    m_session->setState(state);
+}
+
+void QOhRecorderControl::setMuted(bool muted)
+{
+    Q_UNUSED(muted)
+    qWarning("QMediaRecorder::setMuted() is not supported on Openharmony.");
+}
+
+void QOhRecorderControl::setVolume(qreal volume)
+{
+    Q_UNUSED(volume)
+    qWarning("QMediaRecorder::setVolume() is not supported on Openharmony.");
+}
diff --git a/src/plugins/openharmony/src/mediacapture/qohrecordercontrol.h b/src/plugins/openharmony/src/mediacapture/qohrecordercontrol.h
new file mode 100644
index 000000000..4d1a4a2df
--- /dev/null
+++ b/src/plugins/openharmony/src/mediacapture/qohrecordercontrol.h
@@ -0,0 +1,36 @@
+#ifndef QOHRECORDERCONTROL_H
+#define QOHRECORDERCONTROL_H
+
+#include <qmediarecordercontrol.h>
+
+QT_BEGIN_NAMESPACE
+
+class QOhCaptureSession;
+
+class QOhRecorderControl : public QMediaRecorderControl
+{
+    Q_OBJECT
+public:
+    explicit QOhRecorderControl(QOhCaptureSession *session);
+
+    QUrl outputLocation() const override;
+    bool setOutputLocation(const QUrl &location) override;
+    QMediaRecorder::State state() const override;
+    QMediaRecorder::Status status() const override;
+    qint64 duration() const override;
+    bool isMuted() const override;
+    qreal volume() const override;
+    void applySettings() override;
+
+public Q_SLOTS:
+    void setState(QMediaRecorder::State state) override;
+    void setMuted(bool muted) override;
+    void setVolume(qreal volume) override;
+
+private:
+    QOhCaptureSession *m_session;
+};
+
+QT_END_NAMESPACE
+
+#endif // QOHRECORDERCONTROL_H
diff --git a/src/plugins/openharmony/src/mediacapture/qohvideoencodercontrol.cpp b/src/plugins/openharmony/src/mediacapture/qohvideoencodercontrol.cpp
new file mode 100644
index 000000000..0c1f67d2c
--- /dev/null
+++ b/src/plugins/openharmony/src/mediacapture/qohvideoencodercontrol.cpp
@@ -0,0 +1,73 @@
+#include "qohcapturesession.h"
+#include "qohvideoencodercontrol.h"
+
+QOhVideoEncoderControl::QOhVideoEncoderControl(QOhCaptureSession *session)
+    : QVideoEncoderSettingsControl()
+      , m_session(session) { }
+
+QList<QSize> QOhVideoEncoderControl::supportedResolutions(const QVideoEncoderSettings &settings, bool *continuous) const
+{
+    if (continuous)
+        *continuous = false;
+
+    return m_session->supportedResolutions();
+}
+
+QList<qreal> QOhVideoEncoderControl::supportedFrameRates(const QVideoEncoderSettings &settings, bool *continuous) const
+{
+    if (continuous)
+        *continuous = false;
+
+    return m_session->supportedFrameRates();
+}
+
+QStringList QOhVideoEncoderControl::supportedVideoCodecs() const
+{
+    return QStringList() << QLatin1String("video/avc");
+}
+
+QString QOhVideoEncoderControl::videoCodecDescription(const QString &codecName) const
+{
+    if (codecName == QLatin1String("video/avc"))
+        return tr("Advanced Video Coding (H.264)");
+
+    // if (codecName == QLatin1String("video/h263"))
+    //     return tr("H.263 compression");
+
+    // if (codecName == QLatin1String("video/mpeg2"))
+    //     return tr("MPEG-2 video codec");
+
+    // if (codecName == QLatin1String("video/mp4v-es"))
+    //     return tr("MPEG-4 Visual (MPEG-4 Part 2)");
+
+    // if (codecName == QLatin1String("video/x-vnd.on2.vp8"))
+    //     return tr("VP8 video codec");
+
+    return QString();
+}
+
+QVideoEncoderSettings QOhVideoEncoderControl::videoSettings() const
+{
+    return m_session->videoSettings();
+}
+
+void QOhVideoEncoderControl::setVideoSettings(const QVideoEncoderSettings &settings)
+{
+    QVideoEncoderSettings tsettings(settings);
+    if(tsettings.bitRate() == 0)
+        tsettings.setBitRate(200000);
+    else
+        tsettings.setBitRate( qBound(10000, tsettings.bitRate(), 100000000) );
+
+    if(tsettings.frameRate() == 0)
+        tsettings.setFrameRate(30);
+    else
+        tsettings.setFrameRate( qBound(1.0, tsettings.frameRate(), 60.0) );
+
+    QSize newResolution = tsettings.resolution();
+    newResolution.setWidth( qBound(640, newResolution.width(), 4096));
+    newResolution.setHeight( qBound(480, newResolution.height(), 4096));
+    tsettings.setResolution(newResolution);
+
+    m_session->setVideoSettings(tsettings);
+}
diff --git a/src/plugins/openharmony/src/mediacapture/qohvideoencodercontrol.h b/src/plugins/openharmony/src/mediacapture/qohvideoencodercontrol.h
new file mode 100644
index 000000000..47b6a901c
--- /dev/null
+++ b/src/plugins/openharmony/src/mediacapture/qohvideoencodercontrol.h
@@ -0,0 +1,28 @@
+#ifndef QOHVIDEOENCODERCONTROL_H
+#define QOHVIDEOENCODERCONTROL_H
+
+#include <qvideoencodersettingscontrol.h>
+
+QT_BEGIN_NAMESPACE
+
+class QOhCaptureSession;
+
+class QOhVideoEncoderControl : public QVideoEncoderSettingsControl
+{
+    Q_OBJECT
+public:
+    QOhVideoEncoderControl(QOhCaptureSession *session);
+
+    QList<QSize> supportedResolutions(const QVideoEncoderSettings &settings, bool *continuous = 0) const override;
+    QList<qreal> supportedFrameRates(const QVideoEncoderSettings &settings, bool *continuous = 0) const override;
+    QStringList supportedVideoCodecs() const override;
+    QString videoCodecDescription(const QString &codecName) const override;
+    QVideoEncoderSettings videoSettings() const override;
+    void setVideoSettings(const QVideoEncoderSettings &settings) override;
+private:
+    QOhCaptureSession *m_session;
+};
+
+QT_END_NAMESPACE
+
+#endif // QOHVIDEOENCODERCONTROL_H
diff --git a/src/plugins/openharmony/src/mediacapture/qohviewfindersettingscontrol2.cpp b/src/plugins/openharmony/src/mediacapture/qohviewfindersettingscontrol2.cpp
new file mode 100644
index 000000000..d1a4d8127
--- /dev/null
+++ b/src/plugins/openharmony/src/mediacapture/qohviewfindersettingscontrol2.cpp
@@ -0,0 +1,36 @@
+#include "qohcamerasession.h"
+#include "ohcamera/camera.h"
+#include "qohviewfindersettingscontrol2.h"
+
+QOhViewfinderSettingsControl2::QOhViewfinderSettingsControl2(QOhCameraSession *session)
+    : m_cameraSession(session)
+{
+}
+
+QList<QCameraViewfinderSettings> QOhViewfinderSettingsControl2::supportedViewfinderSettings() const
+{
+    Camera_OutputCapability *ability = m_cameraSession->cameraAbility();
+    if(!ability)
+    {
+        return {};
+    }
+
+    QList<QCameraViewfinderSettings> viewfinderSettings;
+
+    for(int i = 0; i < ability->previewProfilesSize; ++i)
+    {
+        viewfinderSettings << m_cameraSession->profileToSetting(ability->previewProfiles[i]);
+    }
+
+    return viewfinderSettings;
+}
+
+QCameraViewfinderSettings QOhViewfinderSettingsControl2::viewfinderSettings() const
+{
+    return m_cameraSession->viewfinderSettings();
+}
+
+void QOhViewfinderSettingsControl2::setViewfinderSettings(const QCameraViewfinderSettings &settings)
+{
+    m_cameraSession->setViewfinderSettings(settings);
+}
diff --git a/src/plugins/openharmony/src/mediacapture/qohviewfindersettingscontrol2.h b/src/plugins/openharmony/src/mediacapture/qohviewfindersettingscontrol2.h
new file mode 100644
index 000000000..4f3513ff1
--- /dev/null
+++ b/src/plugins/openharmony/src/mediacapture/qohviewfindersettingscontrol2.h
@@ -0,0 +1,25 @@
+#ifndef QOHVIEWFINDERSETTINGSCONTROL2_H
+#define QOHVIEWFINDERSETTINGSCONTROL2_H
+
+#include <QtMultimedia/qcameraviewfindersettingscontrol.h>
+#include <QtMultimedia/qcameraviewfindersettings.h>
+
+QT_BEGIN_NAMESPACE
+class QOhCameraSession;
+
+class QOhViewfinderSettingsControl2 : public QCameraViewfinderSettingsControl2
+{
+    Q_OBJECT
+public:
+    explicit QOhViewfinderSettingsControl2(QOhCameraSession *session);
+
+    QList<QCameraViewfinderSettings> supportedViewfinderSettings() const override;
+    QCameraViewfinderSettings viewfinderSettings() const override;
+    void setViewfinderSettings(const QCameraViewfinderSettings &settings) override;
+private:
+    QOhCameraSession *m_cameraSession;
+};
+
+QT_END_NAMESPACE
+
+#endif // QOHVIEWFINDERSETTINGSCONTROL2_H
diff --git a/src/plugins/openharmony/src/oh_mediaservice.json b/src/plugins/openharmony/src/oh_mediaservice.json
new file mode 100644
index 000000000..5c0f28152
--- /dev/null
+++ b/src/plugins/openharmony/src/oh_mediaservice.json
@@ -0,0 +1,4 @@
+{
+    "Keys": ["openharmonymultimedia"],
+    "Services": ["org.qt-project.qt.camera", "org.qt-project.qt.mediaplayer"]
+}
diff --git a/src/plugins/openharmony/src/player/player.pri b/src/plugins/openharmony/src/player/player.pri
new file mode 100644
index 000000000..217b474c5
--- /dev/null
+++ b/src/plugins/openharmony/src/player/player.pri
@@ -0,0 +1,33 @@
+INCLUDEPATH += $$PWD
+
+qtHaveModule(widgets): QT += widgets
+
+HEADERS += \
+    $$PWD/private/qohcodekit_p.h \
+    $$PWD/qohcodekit.h \
+    $$PWD/qohdecoder.h \
+    $$PWD/qohdemuxer.h \
+    $$PWD/qohplayer.h \
+    $$PWD/qohplayercontrol.h \
+    $$PWD/qohplayerservice.h \
+    $$PWD/qohvideorenderercontrol.h \
+    $$PWD/qohnativevideobuffer.h \
+    $$PWD/qohaudiorolecontrol.h \
+    $$PWD/qohcustomaudiorolecontrol.h \
+    $$PWD/qohwindowcontrol.h
+
+SOURCES += \
+    $$PWD/qohcodekit.cpp \
+    $$PWD/qohdecoder.cpp \
+    $$PWD/qohdemuxer.cpp \
+    $$PWD/qohplayer.cpp \
+    $$PWD/qohplayercontrol.cpp \
+    $$PWD/qohplayerservice.cpp \
+    $$PWD/qohvideorenderercontrol.cpp \
+    $$PWD/qohnativevideobuffer.cpp \
+    $$PWD/qohaudiorolecontrol.cpp \
+    $$PWD/qohcustomaudiorolecontrol.cpp \
+    $$PWD/qohwindowcontrol.cpp
+
+LIBS += -lnative_image -lnative_buffer -lnative_window
+
diff --git a/src/plugins/openharmony/src/player/private/qohcodekit_p.h b/src/plugins/openharmony/src/player/private/qohcodekit_p.h
new file mode 100644
index 000000000..e4c5377bc
--- /dev/null
+++ b/src/plugins/openharmony/src/player/private/qohcodekit_p.h
@@ -0,0 +1,23 @@
+#ifndef QOHCODEKIT_P_H
+#define QOHCODEKIT_P_H
+
+#include <qglobal.h>
+
+QT_BEGIN_NAMESPACE
+class QOhCodeKit;
+class QOhCodeKitPrivate
+{
+    Q_DECLARE_PUBLIC(QOhCodeKit)
+    Q_DISABLE_COPY_MOVE(QOhCodeKitPrivate)
+
+public:
+    explicit QOhCodeKitPrivate(QOhCodeKit *const qq);
+    virtual ~QOhCodeKitPrivate();
+
+protected:
+    QOhCodeKit *const q_ptr;
+};
+
+QT_END_NAMESPACE
+
+#endif // QOHCODEKIT_P_H
diff --git a/src/plugins/openharmony/src/player/qohaudiorolecontrol.cpp b/src/plugins/openharmony/src/player/qohaudiorolecontrol.cpp
new file mode 100644
index 000000000..2b699805c
--- /dev/null
+++ b/src/plugins/openharmony/src/player/qohaudiorolecontrol.cpp
@@ -0,0 +1,39 @@
+#include "qohaudiorolecontrol.h"
+
+QT_BEGIN_NAMESPACE
+
+QOhAudioRoleControl::QOhAudioRoleControl(QObject *parent)
+    : QAudioRoleControl(parent)
+{
+}
+
+QAudio::Role QOhAudioRoleControl::audioRole() const
+{
+    return m_role;
+}
+
+void QOhAudioRoleControl::setAudioRole(QAudio::Role role)
+{
+    if (m_role == role)
+        return;
+
+    m_role = role;
+    emit audioRoleChanged(m_role);
+}
+
+QList<QAudio::Role> QOhAudioRoleControl::supportedAudioRoles() const
+{
+    return QList<QAudio::Role>()
+            << QAudio::UnknownRole
+            << QAudio::MusicRole
+            << QAudio::VideoRole
+            << QAudio::VoiceCommunicationRole
+            << QAudio::AlarmRole
+            << QAudio::NotificationRole
+            << QAudio::RingtoneRole
+            << QAudio::AccessibilityRole
+            << QAudio::GameRole
+            << QAudio::CustomRole;
+}
+
+QT_END_NAMESPACE
diff --git a/src/plugins/openharmony/src/player/qohaudiorolecontrol.h b/src/plugins/openharmony/src/player/qohaudiorolecontrol.h
new file mode 100644
index 000000000..c7fa0350f
--- /dev/null
+++ b/src/plugins/openharmony/src/player/qohaudiorolecontrol.h
@@ -0,0 +1,24 @@
+#ifndef QOHAUDIOROLECONTROL_H
+#define QOHAUDIOROLECONTROL_H
+
+#include <qaudiorolecontrol.h>
+
+QT_BEGIN_NAMESPACE
+
+class QOhAudioRoleControl : public QAudioRoleControl
+{
+    Q_OBJECT
+public:
+    explicit QOhAudioRoleControl(QObject *parent = nullptr);
+
+    QAudio::Role audioRole() const override;
+    void setAudioRole(QAudio::Role role) override;
+    QList<QAudio::Role> supportedAudioRoles() const override;
+
+private:
+    QAudio::Role m_role = QAudio::UnknownRole;
+};
+
+QT_END_NAMESPACE
+
+#endif // QOHAUDIOROLECONTROL_H
diff --git a/src/plugins/openharmony/src/player/qohcodekit.cpp b/src/plugins/openharmony/src/player/qohcodekit.cpp
new file mode 100644
index 000000000..14f234d0f
--- /dev/null
+++ b/src/plugins/openharmony/src/player/qohcodekit.cpp
@@ -0,0 +1,38 @@
+#include <QLoggingCategory>
+
+#include "qohcodekit.h"
+#include "private/qohcodekit_p.h"
+
+QT_BEGIN_NAMESPACE
+Q_LOGGING_CATEGORY(AvCoder, "qt.oh.avcoder")
+
+QOhCodeKitPrivate::QOhCodeKitPrivate(QOhCodeKit * const qq)
+    : q_ptr(qq)
+{
+
+}
+
+QOhCodeKitPrivate::~QOhCodeKitPrivate()
+{
+
+}
+
+QOhCodeKit::QOhCodeKit(QObject *parent) : QObject { parent }
+    , d_ptr(new QOhCodeKitPrivate(this))
+{
+}
+
+QOhCodeKit::~QOhCodeKit()
+{
+
+}
+
+QOhCodeKit::QOhCodeKit(QOhCodeKitPrivate &dd, QObject *parent)
+    : QObject { parent }
+    , d_ptr(&dd)
+{
+
+}
+
+QT_END_NAMESPACE
+
diff --git a/src/plugins/openharmony/src/player/qohcodekit.h b/src/plugins/openharmony/src/player/qohcodekit.h
new file mode 100644
index 000000000..850e5c90f
--- /dev/null
+++ b/src/plugins/openharmony/src/player/qohcodekit.h
@@ -0,0 +1,46 @@
+#ifndef QOHCODEKIT_H
+#define QOHCODEKIT_H
+
+#include <QObject>
+#include <QScopedPointer>
+
+QT_BEGIN_NAMESPACE
+class QOhCodeKitPrivate;
+class QOhCodeKit : public QObject
+{
+    Q_OBJECT
+    Q_DECLARE_PRIVATE(QOhCodeKit)
+    Q_DISABLE_COPY_MOVE(QOhCodeKit)
+
+public:
+    struct Video {
+        int32_t width;          /* 视频宽度 */
+        int32_t height;         /* 视频高度 */
+        int64_t bitRate;        /* 比特率 */
+        double frameRate;       /* 视频帧率 */
+        int32_t rotation;       /* 旋转角度 */
+        int32_t videoTrack;     /* 视频轨道索引 */
+        int32_t pixelForamt;    /* 视频像素格式 */
+        std::string codeMime;   /* 编解码器MIME类型 */
+    };
+
+    struct Audio {
+        int32_t sampleRate;     /* 音频采样率 */
+        int32_t audioTrack;     /* 音频轨道索引 */
+        int32_t audioFormat;    /* 音频原始格式 */
+        int32_t channelCount;   /* 音频通道计数 */
+        std::string codeMime;   /* 编解码器MIME类型 */
+        int64_t channelLayout;  /* 所需编码通道布局-仅适用于编码器 */
+    };
+
+    explicit QOhCodeKit(QObject *parent = nullptr);
+    virtual ~QOhCodeKit();
+
+protected:
+    explicit QOhCodeKit(QOhCodeKitPrivate &dd, QObject *parent = nullptr);
+    QScopedPointer<QOhCodeKitPrivate> d_ptr;
+};
+
+QT_END_NAMESPACE
+
+#endif // QOHCODEKIT_H
diff --git a/src/plugins/openharmony/src/player/qohcustomaudiorolecontrol.cpp b/src/plugins/openharmony/src/player/qohcustomaudiorolecontrol.cpp
new file mode 100644
index 000000000..352f5b3aa
--- /dev/null
+++ b/src/plugins/openharmony/src/player/qohcustomaudiorolecontrol.cpp
@@ -0,0 +1,34 @@
+#include "qohcustomaudiorolecontrol.h"
+
+QT_BEGIN_NAMESPACE
+
+QOhCustomAudioRoleControl::QOhCustomAudioRoleControl(QObject *parent)
+    : QCustomAudioRoleControl(parent)
+{
+}
+
+QString QOhCustomAudioRoleControl::customAudioRole() const
+{
+    return m_role;
+}
+
+void QOhCustomAudioRoleControl::setCustomAudioRole(const QString &role)
+{
+    if (m_role == role)
+        return;
+
+    m_role = role;
+    emit customAudioRoleChanged(m_role);
+}
+
+QStringList QOhCustomAudioRoleControl::supportedCustomAudioRoles() const
+{
+    return QStringList()
+            << "AUDIOSTREAM_USAGE_VOICE_ASSISTANT"
+            << "AUDIOSTREAM_USAGE_VOICE_MESSAGE"
+            << "AUDIOSTREAM_USAGE_AUDIOBOOK"
+            << "AUDIOSTREAM_USAGE_NAVIGATION"
+            << "AUDIOSTREAM_USAGE_VIDEO_COMMUNICATION";
+}
+
+QT_END_NAMESPACE
diff --git a/src/plugins/openharmony/src/player/qohcustomaudiorolecontrol.h b/src/plugins/openharmony/src/player/qohcustomaudiorolecontrol.h
new file mode 100644
index 000000000..87c9d90c5
--- /dev/null
+++ b/src/plugins/openharmony/src/player/qohcustomaudiorolecontrol.h
@@ -0,0 +1,24 @@
+#ifndef QOHCUSTOMAUDIOROLECONTROL_H
+#define QOHCUSTOMAUDIOROLECONTROL_H
+
+#include <qcustomaudiorolecontrol.h>
+
+QT_BEGIN_NAMESPACE
+
+class QOhCustomAudioRoleControl : public QCustomAudioRoleControl
+{
+    Q_OBJECT
+public:
+    explicit QOhCustomAudioRoleControl(QObject *parent = nullptr);
+
+    QString customAudioRole() const override;
+    void setCustomAudioRole(const QString &role) override;
+    QStringList supportedCustomAudioRoles() const override;
+
+private:
+    QString m_role;
+};
+
+QT_END_NAMESPACE
+
+#endif // QOHCUSTOMAUDIOROLECONTROL_H
diff --git a/src/plugins/openharmony/src/player/qohdecoder.cpp b/src/plugins/openharmony/src/player/qohdecoder.cpp
new file mode 100644
index 000000000..4d700fce8
--- /dev/null
+++ b/src/plugins/openharmony/src/player/qohdecoder.cpp
@@ -0,0 +1,407 @@
+/*******************************************************************
+ *  Copyright(c) 2022-2025 ISS
+ *  All right reserved. See LGPL for detailed Information
+ *
+ *  文件名称: qohdecoder.cpp
+ *  简要描述: 封装鸿蒙提供的解码器接口
+ *  创建日期: 2024/12/13
+ *  作者: WangHao
+ *  说明:
+ *
+ *  修改日期:
+ *  作者:
+ *  说明:
+ ******************************************************************/
+#include <QImage>
+#include <QDebug>
+#include <QVideoFrame>
+#include <QLoggingCategory>
+#include <QVideoSurfaceFormat>
+#include <qopenharmonydefines.h>
+#include <native_buffer/native_buffer.h>
+#include <multimedia/player_framework/native_avformat.h>
+#include <multimedia/player_framework/native_avbuffer.h>
+#include <multimedia/player_framework/native_avcodec_base.h>
+#include <multimedia/player_framework/native_avcodec_videodecoder.h>
+
+#include "qohdemuxer.h"
+#include "qohdecoder.h"
+#include "private/qohcodekit_p.h"
+
+QT_BEGIN_NAMESPACE
+Q_DECLARE_LOGGING_CATEGORY(AvCoder)
+
+class QOhVideoDecoderPrivate : public QOhCodeKitPrivate
+{
+    Q_DECLARE_PUBLIC(QOhVideoDecoder)
+    Q_DISABLE_COPY_MOVE(QOhVideoDecoderPrivate)
+
+public:
+    struct Frame {
+        int32_t width;          /* 视频宽度 */
+        int32_t height;         /* 视频高度 */
+        int32_t stride;         /* 视频帧宽跨距 */
+        int32_t cropTop;        /* 裁剪矩形顶部坐标(y)值 */
+        int32_t cropLeft;       /* 裁剪矩形左坐标(x)值 */
+        int32_t cropRight;      /* 裁剪矩形右坐标(x)值 */
+        int32_t cropBottom;     /* 裁剪矩形底部坐标(y)值 */
+        int32_t sliceStride;    /* 视频帧高跨距 */
+        int32_t pixelFormat;    /* 视频像素格式 */
+    };
+    explicit QOhVideoDecoderPrivate(QOhDemuxer *const demuxer,
+                                    QOhVideoDecoder *const qq);
+    ~QOhVideoDecoderPrivate();
+
+protected:
+    void updateFrame(OH_AVFormat *format);
+    QVideoFrame fromRawData(uint8_t * const data, int32_t size, Frame frame);
+
+private:
+    static void OnCodecError(OH_AVCodec *codec, int32_t errorCode, void *userData);
+    static void OnStreamChanged(OH_AVCodec *codec, OH_AVFormat *format, void *userData);
+    static void OnNeedInputBuffer(OH_AVCodec *codec, uint32_t index, OH_AVBuffer *buffer, void *userData);
+    static void OnNewOutputBuffer(OH_AVCodec *codec, uint32_t index, OH_AVBuffer *buffer, void *userData);
+
+private:
+    QOhDemuxer *const m_demuxer;
+    QSharedPointer<Frame> m_frame;
+    QSharedPointer<OH_AVCodec> m_decoder;
+};
+
+QOhVideoDecoderPrivate::QOhVideoDecoderPrivate(QOhDemuxer * const demuxer, QOhVideoDecoder * const qq)
+    : QOhCodeKitPrivate(qq)
+    , m_demuxer(demuxer)
+    , m_frame(nullptr)
+    , m_decoder(nullptr)
+{
+
+}
+
+QOhVideoDecoderPrivate::~QOhVideoDecoderPrivate()
+{
+
+}
+
+void QOhVideoDecoderPrivate::updateFrame(OH_AVFormat *format)
+{
+    if (m_frame.isNull())
+        m_frame.reset(new Frame());
+
+    OH_AVFormat_GetIntValue(format, OH_MD_KEY_VIDEO_STRIDE, &m_frame->stride);
+    OH_AVFormat_GetIntValue(format, OH_MD_KEY_VIDEO_PIC_WIDTH, &m_frame->width);
+    OH_AVFormat_GetIntValue(format, OH_MD_KEY_VIDEO_PIC_HEIGHT, &m_frame->height);
+    OH_AVFormat_GetIntValue(format, OH_MD_KEY_PIXEL_FORMAT, &m_frame->pixelFormat);
+    OH_AVFormat_GetIntValue(format, OH_MD_KEY_VIDEO_SLICE_HEIGHT, &m_frame->sliceStride);
+    /* 获取裁剪矩形信息 */
+    OH_AVFormat_GetIntValue(format, OH_MD_KEY_VIDEO_CROP_TOP, &m_frame->cropTop);
+    OH_AVFormat_GetIntValue(format, OH_MD_KEY_VIDEO_CROP_LEFT, &m_frame->cropLeft);
+    OH_AVFormat_GetIntValue(format, OH_MD_KEY_VIDEO_CROP_RIGHT, &m_frame->cropRight);
+    OH_AVFormat_GetIntValue(format, OH_MD_KEY_VIDEO_CROP_BOTTOM, &m_frame->cropBottom);
+}
+
+QVideoFrame QOhVideoDecoderPrivate::fromRawData(uint8_t * const data, int32_t size, Frame frame)
+{
+    switch (frame.pixelFormat) {
+    case AV_PIXEL_FORMAT_RGBA:
+    {
+        QVideoFrame videoFrame(size, QSize(frame.width, frame.height), frame.stride, QVideoFrame::Format_RGB32);
+        if (videoFrame.map(QAbstractVideoBuffer::WriteOnly)) {
+            memcpy(videoFrame.bits(), data, videoFrame.mappedBytes());
+        }
+        videoFrame.unmap();
+        return videoFrame;
+    }
+    case AV_PIXEL_FORMAT_YUVI420:
+    {
+        QVideoFrame videoFrame(size, QSize(frame.width, frame.height), frame.stride, QVideoFrame::Format_YUV420P);
+        if (videoFrame.map(QAbstractVideoBuffer::WriteOnly)) {
+            memcpy(videoFrame.bits(), data, videoFrame.mappedBytes());
+        }
+        videoFrame.unmap();
+        return videoFrame;
+    }
+    case AV_PIXEL_FORMAT_NV21:
+    {
+        QVideoFrame videoFrame(size, QSize(frame.width, frame.height), frame.stride, QVideoFrame::Format_NV21);
+        if (videoFrame.map(QAbstractVideoBuffer::WriteOnly)) {
+            memcpy(videoFrame.bits(), data, videoFrame.mappedBytes());
+        }
+        videoFrame.unmap();
+        return videoFrame;
+    }
+    case AV_PIXEL_FORMAT_NV12:
+    {
+        QVideoFrame videoFrame(size, QSize(frame.width, frame.height), frame.stride, QVideoFrame::Format_NV12);
+        if (videoFrame.map(QAbstractVideoBuffer::WriteOnly)) {
+            memcpy(videoFrame.bits(), data, videoFrame.mappedBytes());
+        }
+        videoFrame.unmap();
+        return videoFrame;
+    }
+    default:
+        break;
+    }
+    return QVideoFrame();
+}
+/*!
+ * \brief 解码异常回调OH_AVCodecOnError实现
+ * \param codec
+ * \param errorCode
+ * \param userData
+ */
+void QOhVideoDecoderPrivate::OnCodecError(OH_AVCodec *codec, int32_t errorCode, void *userData)
+{
+    Q_UNUSED(codec);
+    Q_UNUSED(userData);
+    LOGE("on codec error, error code: %{public}d", errorCode);
+}
+/*!
+ * \brief 解码数据流变化回调OH_AVCodecOnStreamChanged实现
+ * \param codec
+ * \param format
+ * \param userData
+ */
+void QOhVideoDecoderPrivate::OnStreamChanged(OH_AVCodec *codec, OH_AVFormat *format, void *userData)
+{
+    Q_UNUSED(codec);
+    Q_UNUSED(format);
+    Q_UNUSED(userData);
+
+    QOhVideoDecoder *decoder = reinterpret_cast<QOhVideoDecoder*>(userData);
+    if (!decoder)
+        return;
+
+    decoder->d_func()->updateFrame(format);
+
+    LOGI("on video codec format change");
+}
+/*!
+ * \brief 解码输入回调OH_AVCodecOnNeedInputBuffer实现
+ * \param codec
+ * \param index
+ * \param buffer
+ * \param userData
+ */
+void QOhVideoDecoderPrivate::OnNeedInputBuffer(OH_AVCodec *codec, uint32_t index, OH_AVBuffer *buffer, void *userData)
+{
+    //LOGI("on video input buffer, codec: [%{public}p] index: [%{public}d]", codec, index);
+    qCInfo(AvCoder) << "on video input buffer, codec: [" << codec << "] index: [" << index << ']';
+
+    Q_UNUSED(codec);
+    if (nullptr == userData)
+        return;
+
+    QOhVideoDecoder *decoder = reinterpret_cast<QOhVideoDecoder*>(userData);
+    if (!decoder)
+        return;
+
+    QOhDemuxer *demuxer = decoder->d_func()->m_demuxer;
+    if (!demuxer)
+        return;
+
+    if (!demuxer->readSample(demuxer->videoInfo()->videoTrack, buffer)) {
+        LOGW("read video sample buffer failed.");
+        return;
+    }
+
+    OH_VideoDecoder_PushInputBuffer(codec, index);
+}
+/*!
+ * \brief 解码输出回调OH_AVCodecOnNewOutputBuffer实现
+ * \param codec
+ * \param index
+ * \param buffer
+ * \param userData
+ */
+void QOhVideoDecoderPrivate::OnNewOutputBuffer(OH_AVCodec *codec, uint32_t index, OH_AVBuffer *buffer, void *userData)
+{
+    //LOGI("on video output buffer, codec: [%{public}p] index: [%{public}d]", codec, index);
+    qCInfo(AvCoder) << "on video output buffer, codec: [" << codec << "] index: [" << index << ']';
+    if (nullptr == userData) {
+        return;
+    }
+
+    QOhVideoDecoder *decoder = reinterpret_cast<QOhVideoDecoder*>(userData);
+    if (!decoder)
+        return;
+
+    QOhDemuxer *demuxer = decoder->d_func()->m_demuxer;
+    if (!demuxer)
+        return;
+
+    static bool firstFrame = true;
+    if (firstFrame) {
+        OH_AVFormat *format = OH_VideoDecoder_GetOutputDescription(codec);
+        decoder->d_func()->updateFrame(format);
+
+        firstFrame = false;
+        OH_AVFormat_Destroy(format);
+    }
+
+    /* AVCODEC_BUFFER_FLAGS_NONE                默认
+     * AVCODEC_BUFFER_FLAGS_EOS                 结尾sample,数据为空
+     * AVCODEC_BUFFER_FLAGS_SYNC_FRAME          IDR帧或I帧
+     * AVCODEC_BUFFER_FLAGS_INCOMPLETE_FRAME	非完整的sample,一般由于buffer过小,无法拷贝完整的sample
+     * AVCODEC_BUFFER_FLAGS_CODEC_DATA          含参数集信息的帧
+     * AVCODEC_BUFFER_FLAGS_DISCARD             可丢弃的帧
+     */
+    OH_AVCodecBufferAttr attr = {  0, 0, 0, AVCODEC_BUFFER_FLAGS_NONE };
+    int ret = OH_AVBuffer_GetBufferAttr(buffer, &attr);
+    if (AV_ERR_OK == ret && (AVCODEC_BUFFER_FLAGS_EOS & attr.flags)) {
+        OH_VideoDecoder_FreeOutputBuffer(codec, index);
+        Q_EMIT decoder->finished(QOhVideoDecoder::QPrivateSignal());
+        return;
+    }
+
+    /* TODO 是否必要线程处理 */
+    uint8_t *data = OH_AVBuffer_GetAddr(buffer);
+    Frame *frameInfo = decoder->d_func()->m_frame.get();
+    const QVideoFrame &frame = decoder->d_func()->fromRawData(data, attr.size, *frameInfo);
+    Q_EMIT decoder->videoFrameChange(frame, QOhVideoDecoder::QPrivateSignal());
+
+    OH_VideoDecoder_FreeOutputBuffer(codec, index);
+}
+
+QOhVideoDecoder::QOhVideoDecoder(QOhDemuxer *const demuxer, QObject *parent)
+    : QOhCodeKit(*(new QOhVideoDecoderPrivate(demuxer, this)), parent)
+{
+}
+
+QOhVideoDecoder::~QOhVideoDecoder()
+{
+
+}
+
+bool QOhVideoDecoder::stop()
+{
+    Q_D(QOhVideoDecoder);
+    if (d->m_decoder.isNull()) {
+        qCCritical(AvCoder) << "video decoder is null, call configure function first.";
+        return false;
+    }
+
+    OH_VideoDecoder_Flush(d->m_decoder.get());
+    int ret = OH_VideoDecoder_Stop(d->m_decoder.get());
+    if (AV_ERR_OK != ret) {
+        qCCritical(AvCoder) << "stop video decoder failed. ret: " << ret;
+        return false;
+    }
+    return true;
+}
+
+bool QOhVideoDecoder::start()
+{
+    Q_D(QOhVideoDecoder);
+    if (d->m_decoder.isNull()) {
+        qCCritical(AvCoder) << "video decoder is null, call configure function first.";
+        return false;
+    }
+
+    OH_VideoDecoder_Flush(d->m_decoder.get());
+    int ret = OH_VideoDecoder_Start(d->m_decoder.get());
+    if (AV_ERR_OK != ret) {
+        qCCritical(AvCoder) << "start video decoder failed. ret: " << ret;
+        return false;
+    }
+    return true;
+}
+
+bool QOhVideoDecoder::reset()
+{
+    Q_D(QOhVideoDecoder);
+    if (d->m_decoder.isNull()) {
+        qCCritical(AvCoder) << "video decoder is null, call configure function first.";
+        return false;
+    }
+
+    OH_VideoDecoder_Flush(d->m_decoder.get());
+    int ret = OH_VideoDecoder_Reset(d->m_decoder.get());
+    if (AV_ERR_OK != ret) {
+        qCCritical(AvCoder) << "reset video decoder failed, ret: " << ret;
+        return false;
+    }
+    return true;
+}
+
+bool QOhVideoDecoder::prepare()
+{
+    Q_D(QOhVideoDecoder);
+    int ret = OH_VideoDecoder_Prepare(d->m_decoder.get());
+    if (AV_ERR_OK != ret) {
+        qCCritical(AvCoder) << "video decoder prepare failed. ret: " << ret;
+        return false;
+    }
+    return true;
+}
+
+bool QOhVideoDecoder::configure(QSharedPointer<Video> info)
+{
+    OH_AVCodec *code = OH_VideoDecoder_CreateByMime(info->codeMime.c_str());
+    if (nullptr == code) {
+        qCCritical(AvCoder) << "create video decoder failed.";
+        return false;
+    }
+
+    auto format = QSharedPointer<OH_AVFormat>(OH_AVFormat_Create(), OH_AVFormat_Destroy);
+    if (!format) {
+        qCCritical(AvCoder) << "create video decoder format failed.";
+        return false;
+    }
+
+    bool result = false;
+
+    result = OH_AVFormat_SetIntValue(format.get(), OH_MD_KEY_WIDTH, info->width);
+    qInfo() << tr("set video format width: %1 value: %2").arg(result).arg(info->width);
+
+    result = OH_AVFormat_SetIntValue(format.get(), OH_MD_KEY_HEIGHT, info->height);
+    qInfo() << tr("set video format height: %1 value: %2").arg(result).arg(info->height);
+
+#if 0
+    /* 配置低时延解码 */
+    result = OH_AVFormat_SetIntValue(format.get(), OH_MD_KEY_VIDEO_ENABLE_LOW_LATENCY, 1);
+    qInfo() << tr("set video format LOW_LATENCY: %1").arg(result);
+#endif
+
+    result = OH_AVFormat_SetDoubleValue(format.get(), OH_MD_KEY_FRAME_RATE, info->frameRate);
+    qInfo() << tr("set video format frameRate: %1 value: %2").arg(result).arg(info->frameRate);
+
+#if 0
+    /* FIXME 不能持预设图片格式 */
+    result = OH_AVFormat_SetIntValue(format.get(), OH_MD_KEY_PIXEL_FORMAT, info->pixelForamt);
+    qInfo() << tr("set video format pixelForamt: %1 value: %2").arg(result).arg(info->pixelForamt);
+#endif
+
+#if 0
+    /* 只在视频解码Surface模式下使用 */
+    if (info->height > info->width)
+        OH_AVFormat_SetIntValue(format, OH_MD_KEY_ROTATION, info->rotation + 90);
+#endif
+
+    int ret = OH_VideoDecoder_Configure(code, format.get());
+    if (AV_ERR_OK != ret) {
+        qCCritical(AvCoder) << "configure video decoder failed, ret: " << ret;
+        return false;
+    }
+
+    OH_AVCodecCallback cb = { &QOhVideoDecoderPrivate::OnCodecError,
+                              &QOhVideoDecoderPrivate::OnStreamChanged,
+                              &QOhVideoDecoderPrivate::OnNeedInputBuffer,
+                              &QOhVideoDecoderPrivate::OnNewOutputBuffer };
+
+    ret = OH_VideoDecoder_RegisterCallback(code, cb, reinterpret_cast<void*>(this));
+    if (AV_ERR_OK != ret) {
+        qCCritical(AvCoder) << "register video decoder callback failed. ret: " << ret;
+        return false;
+    }
+
+
+    Q_D(QOhVideoDecoder);
+    d->m_decoder = QSharedPointer<OH_AVCodec>(code, OH_VideoDecoder_Destroy);
+
+    return true;
+}
+
+QT_END_NAMESPACE
+
+
+
diff --git a/src/plugins/openharmony/src/player/qohdecoder.h b/src/plugins/openharmony/src/player/qohdecoder.h
new file mode 100644
index 000000000..1e44bdab2
--- /dev/null
+++ b/src/plugins/openharmony/src/player/qohdecoder.h
@@ -0,0 +1,54 @@
+/*******************************************************************
+ *  Copyright(c) 2022-2025 ISS
+ *  All right reserved. See LGPL for detailed Information
+ *
+ *  文件名称: qohdecoder.h
+ *  简要描述: 封装鸿蒙提供的解码器接口
+ *  创建日期: 2024/12/13
+ *  作者: WangHao
+ *  说明:
+ *
+ *  修改日期:
+ *  作者:
+ *  说明:
+ ******************************************************************/
+#ifndef QOHDECODER_H
+#define QOHDECODER_H
+
+#include <QObject>
+#include <QScopedPointer>
+
+#include "qohcodekit.h"
+
+QT_BEGIN_NAMESPACE
+class QOhDemuxer;
+class QVideoFrame;
+class QOhVideoDecoderPrivate;
+
+/*!
+ * \brief 视频解码
+ */
+class QOhVideoDecoder : public QOhCodeKit
+{
+    Q_OBJECT
+    Q_DECLARE_PRIVATE(QOhVideoDecoder)
+    Q_DISABLE_COPY_MOVE(QOhVideoDecoder)
+
+public:
+    explicit QOhVideoDecoder(QOhDemuxer *const demuxer, QObject *parent = nullptr);
+    ~QOhVideoDecoder();
+
+    bool stop();
+    bool start();
+    bool reset();
+    bool prepare();
+    bool configure(QSharedPointer<QOhCodeKit::Video> info);
+
+Q_SIGNALS:
+    void finished(QPrivateSignal);
+    void videoFrameChange(const QVideoFrame&, QPrivateSignal);
+};
+
+QT_END_NAMESPACE
+
+#endif // QOHDECODER_H
diff --git a/src/plugins/openharmony/src/player/qohdemuxer.cpp b/src/plugins/openharmony/src/player/qohdemuxer.cpp
new file mode 100644
index 000000000..2c6a06be5
--- /dev/null
+++ b/src/plugins/openharmony/src/player/qohdemuxer.cpp
@@ -0,0 +1,336 @@
+/*******************************************************************
+ *  Copyright(c) 2022-2025 ISS
+ *  All right reserved. See LGPL for detailed Information
+ *
+ *  文件名称: qohdemuxer.cpp
+ *  简要描述: 封装鸿蒙接口,提供从媒体文件码流中提取sample的接口
+ *  创建日期: 2024/12/13
+ *  作者: WangHao
+ *  说明:
+ *
+ *  修改日期:
+ *  作者:
+ *  说明:
+ ******************************************************************/
+#include <QUrl>
+#include <QFile>
+#include <QDebug>
+#include <QSharedPointer>
+#include <QLoggingCategory>
+#include <qopenharmonydefines.h>
+#include <multimedia/player_framework/native_avsource.h>
+#include <multimedia/player_framework/native_avformat.h>
+#include <multimedia/player_framework/native_avbuffer.h>
+#include <multimedia/player_framework/native_avdemuxer.h>
+#include <multimedia/player_framework/native_avcodec_base.h>
+
+#include "qohdemuxer.h"
+#include "private/qohcodekit_p.h"
+
+QT_BEGIN_NAMESPACE
+Q_DECLARE_LOGGING_CATEGORY(AvCoder)
+class QOhDemuxerPrivate : public QOhCodeKitPrivate
+{
+    Q_DECLARE_PUBLIC(QOhDemuxer)
+    Q_DISABLE_COPY_MOVE(QOhDemuxerPrivate)
+
+public:
+    explicit QOhDemuxerPrivate(QOhDemuxer *const qq);
+    ~QOhDemuxerPrivate();
+
+    /* 创建媒体源 */
+    QSharedPointer<OH_AVSource> createSource(const QUrl &url);
+
+    /* 创建分流器 */
+    QSharedPointer<OH_AVDemuxer> createDemuxer(const QSharedPointer<OH_AVSource> source);
+
+    /* 媒体轨道选择 */
+    bool selectTrackType(const QSharedPointer<OH_AVSource> source,
+                         const QSharedPointer<OH_AVDemuxer> demuxer);
+
+private:
+    QOhDemuxer::Type m_type;
+
+    /* 媒体源 */
+    QSharedPointer<OH_AVSource> m_source;
+    /* 解封装器 */
+    QSharedPointer<OH_AVDemuxer> m_demuxer;    
+    /* 视频信息 */
+    QSharedPointer<QOhCodeKit::Video> m_videoInfo;
+    QSharedPointer<QOhCodeKit::Audio> m_audioInfo;
+};
+
+QOhDemuxerPrivate::QOhDemuxerPrivate(QOhDemuxer * const qq)
+    : QOhCodeKitPrivate(qq)
+    , m_type(QOhDemuxer::Type::E_NONE)
+    , m_source(nullptr)
+    , m_demuxer(nullptr)
+    , m_videoInfo(nullptr)
+    , m_audioInfo(nullptr)
+{
+
+}
+
+QOhDemuxerPrivate::~QOhDemuxerPrivate()
+{
+}
+
+QSharedPointer<OH_AVSource> QOhDemuxerPrivate::createSource(const QUrl &url)
+{
+    if (url.isEmpty())
+        return nullptr;
+
+    QSharedPointer<OH_AVSource> avSource(nullptr);
+    if (0 == QString::compare(url.scheme(), "file")) {
+        const QString &path = url.path();
+        QFile *file = new QFile(path);
+        if (!file->open(QIODevice::ReadOnly)) {
+            file->close();
+            qCCritical(AvCoder) << QObject::tr("open file: %1 failed, cause: %2.").arg(path, file->errorString());
+            file->deleteLater();
+            return nullptr;
+        }
+
+        OH_AVSource *source = OH_AVSource_CreateWithFD(file->handle(), 0, file->size());
+        if (nullptr == source) {
+            file->close();
+            qCCritical(AvCoder) << Q_FUNC_INFO << QObject::tr("call OH_AVSource_CreateWithFD failed.");
+            file->deleteLater();
+            return nullptr;
+        }
+
+        /* 为 fd 资源文件创建 source 资源对象
+         * 传入 offset 不为文件起始位置 或 size 不为文件大小时
+         * 可能会因不能获取完整数据导致 source 创建失败,或后续解封装失败等问题.
+         */
+        avSource = QSharedPointer<OH_AVSource>(source, [file](OH_AVSource *source){
+            OH_AVSource_Destroy(source);
+            file->close();
+            file->deleteLater();
+        });
+    } else {
+        /* 为 uri 资源文件创建 source 资源对象 */
+        const QString &path = url.path();
+        OH_AVSource *source = OH_AVSource_CreateWithURI(path.toLocal8Bit().data());
+        if (nullptr == source) {
+            qCCritical(AvCoder) << Q_FUNC_INFO << QObject::tr("call OH_AVSource_CreateWithURI failed.");
+            return nullptr;
+        }
+
+        avSource = QSharedPointer<OH_AVSource>(source, OH_AVSource_Destroy);
+    }
+
+    return avSource;
+}
+
+QSharedPointer<OH_AVDemuxer> QOhDemuxerPrivate::createDemuxer(const QSharedPointer<OH_AVSource> source)
+{
+    OH_AVDemuxer *demuxer = OH_AVDemuxer_CreateWithSource(source.get());
+    if (nullptr == demuxer) {
+        qCCritical(AvCoder) << "call OH_AVDemuxer_CreateWithSource failed.";
+        return nullptr;
+    }
+
+    return QSharedPointer<OH_AVDemuxer>(demuxer, OH_AVDemuxer_Destroy);
+}
+
+bool QOhDemuxerPrivate::selectTrackType(const QSharedPointer<OH_AVSource> source,
+                                        const QSharedPointer<OH_AVDemuxer> demuxer)
+{
+    OH_AVFormat *sfm = OH_AVSource_GetSourceFormat(source.get());
+    if (nullptr == sfm) {
+        qWarning() << "get source format failed.";
+        return false;
+    }
+
+    QSharedPointer<OH_AVFormat> format(sfm, OH_AVFormat_Destroy);
+    int32_t trackCount = 0;
+    if (!OH_AVFormat_GetIntValue(format.get(), OH_MD_KEY_TRACK_COUNT, &trackCount)) {
+        qWarning() << "get track count from source format failed.";
+        return false;
+    }
+
+
+    for (int32_t index = 0; index < trackCount; ++index) {
+        OH_AVFormat* tfm = OH_AVSource_GetTrackFormat(source.get(), index);
+        if (nullptr == tfm)
+            continue;
+
+        int trackType = -1;
+        auto trackFormat = QSharedPointer<OH_AVFormat>(tfm, OH_AVFormat_Destroy);
+        OH_AVFormat_GetIntValue(trackFormat.get(), OH_MD_KEY_TRACK_TYPE, &trackType);
+
+        /* 视频轨 */
+        if ((QOhDemuxer::E_VIDEO == (QOhDemuxer::E_VIDEO & m_type)) &&
+          MEDIA_TYPE_VID == trackType)
+        {
+            m_videoInfo.reset(new QOhCodeKit::Video());
+
+            char *codeMime;
+            bool result = false;
+            m_videoInfo->videoTrack = index;
+            OH_AVDemuxer_SelectTrackByID(demuxer.get(), index);
+
+            result = OH_AVFormat_GetIntValue(trackFormat.get(), OH_MD_KEY_WIDTH, &m_videoInfo->width);
+            qInfo() << QObject::tr("get video format width: %1 value: %2").arg(result).arg(m_videoInfo->width);
+
+            result = OH_AVFormat_GetIntValue(trackFormat.get(), OH_MD_KEY_HEIGHT, &m_videoInfo->height);
+            qInfo() << QObject::tr("get video format height: %1 value: %2").arg(result).arg(m_videoInfo->height);
+
+            result = OH_AVFormat_GetLongValue(trackFormat.get(), OH_MD_KEY_BITRATE, &m_videoInfo->bitRate);
+            qInfo() << QObject::tr("get video format bitRate: %1 value: %2").arg(result).arg(m_videoInfo->bitRate);
+
+            result = OH_AVFormat_GetIntValue(trackFormat.get(), OH_MD_KEY_ROTATION, &m_videoInfo->rotation);
+            qInfo() << QObject::tr("get video format rotation: %1 value: %2").arg(result).arg(m_videoInfo->rotation);
+
+            result = OH_AVFormat_GetDoubleValue(trackFormat.get(), OH_MD_KEY_FRAME_RATE, &m_videoInfo->frameRate);
+            qInfo() << QObject::tr("get video format frameRate: %1 value: %2").arg(result).arg(m_videoInfo->frameRate);
+
+            result = OH_AVFormat_GetIntValue(trackFormat.get(), OH_MD_KEY_PIXEL_FORMAT, &m_videoInfo->pixelForamt);
+            qInfo() << QObject::tr("get video format pixelForamt: %1 value: %2").arg(result).arg(m_videoInfo->pixelForamt);
+
+            result = OH_AVFormat_GetStringValue(trackFormat.get(), OH_MD_KEY_CODEC_MIME, const_cast<char const **>(&codeMime));
+            qInfo() << QObject::tr("get video format codeMime: %1 value: %2").arg(result).arg(codeMime);
+
+            m_videoInfo->codeMime = std::string(codeMime);
+
+            LOGI("====== QOhDemuxer Video config ======");
+            LOGI("%{public}d*%{public}d, %{public}.1ffps, %{public}d kbps", m_videoInfo->width,
+                 m_videoInfo->height, m_videoInfo->frameRate, m_videoInfo->bitRate / 1024);
+            LOGI("====== QOhDemuxer Video config ======");
+        }
+
+        /* 音频轨 */
+        if ((QOhDemuxer::E_AUDIO == (QOhDemuxer::E_AUDIO & m_type)) &&
+            MEDIA_TYPE_AUD == trackType)
+        {
+            m_audioInfo.reset(new QOhCodeKit::Audio());
+
+            char *codeMime;
+            bool result = false;
+            m_audioInfo->audioTrack = index;
+            OH_AVDemuxer_SelectTrackByID(demuxer.get(), index);
+
+            result = OH_AVFormat_GetIntValue(trackFormat.get(), OH_MD_KEY_AUD_SAMPLE_RATE, &m_audioInfo->sampleRate);
+            qInfo() << QObject::tr("get audio format sampleRate: %1 value: %2").arg(result).arg(m_audioInfo->sampleRate);
+
+            result = OH_AVFormat_GetIntValue(trackFormat.get(), OH_MD_KEY_AUDIO_SAMPLE_FORMAT, &m_audioInfo->audioFormat);
+            qInfo() << QObject::tr("get audio format audioFormat: %1 value: %2").arg(result).arg(m_audioInfo->audioFormat);
+
+            result = OH_AVFormat_GetIntValue(trackFormat.get(), OH_MD_KEY_AUD_CHANNEL_COUNT, &m_audioInfo->channelCount);
+            qInfo() << QObject::tr("get audio format channelCount: %1 value: %2").arg(result).arg(m_audioInfo->channelCount);
+
+            result = OH_AVFormat_GetLongValue(trackFormat.get(), OH_MD_KEY_CHANNEL_LAYOUT, &m_audioInfo->channelLayout);
+            qInfo() << QObject::tr("get audio format channelLayout: %1 value: %2").arg(result).arg(m_audioInfo->channelLayout);
+
+            result = OH_AVFormat_GetStringValue(trackFormat.get(), OH_MD_KEY_CODEC_MIME, const_cast<char const **>(&codeMime));
+            qInfo() << QObject::tr("get audio format codeMime: %1 value: %2").arg(result).arg(codeMime);
+
+            m_audioInfo->codeMime = std::string(codeMime);
+
+            LOGI("====== QOhDemuxer Audio config ======");
+            LOGI("Mime: %{public}s", codeMime);
+            LOGI("audioMime:%{public}s sampleForamt:%{public}d "
+                 "sampleRate:%{public}d channelCount:%{public}d channelLayout:%{public}d",
+                 m_audioInfo->codeMime.c_str(),
+                 m_audioInfo->audioFormat,
+                 m_audioInfo->sampleRate,
+                 m_audioInfo->channelCount,
+                 (int)m_audioInfo->channelLayout);
+            LOGI("====== QOhDemuxer Audio config ======");
+        }
+    }
+
+    return true;
+}
+
+QOhDemuxer::QOhDemuxer(Type type)
+    : QOhCodeKit(*(new QOhDemuxerPrivate(this)))
+{
+    d_func()->m_type = type;
+}
+
+QOhDemuxer::~QOhDemuxer()
+{
+
+}
+
+bool QOhDemuxer::isValid() const
+{
+    Q_D(const QOhDemuxer);
+    return (!d->m_source.isNull() && !d->m_demuxer.isNull());
+}
+
+bool QOhDemuxer::configure(const QUrl &url)
+{
+    Q_D(QOhDemuxer);
+    /* FIXME 以下调用顺序不可修改 */
+
+    /* 创建媒体源 */
+    d->m_source = d->createSource(url);
+    if (!d->m_source) {
+        qCCritical(AvCoder) << "create multimedia source failed.";
+        return false;
+    }
+
+    /* 创建分流器 */
+    d->m_demuxer = d->createDemuxer(d->m_source);
+    if (!d->m_demuxer) {
+        qCCritical(AvCoder) << "create demuxer failed.";
+        return false;
+    }
+
+    /* 选取媒体轨道-获取格式信息 */
+    if (!d->selectTrackType(d->m_source, d->m_demuxer)) {
+        qCCritical(AvCoder) << "select track failed.";
+        return false;
+    }
+
+    return true;
+}
+
+bool QOhDemuxer::seekTime(qint64 millisecond)
+{
+    Q_D(QOhDemuxer);
+    if (d->m_demuxer.isNull())
+        return false;
+
+    int ret = OH_AVDemuxer_SeekToTime(d->m_demuxer.get(), millisecond,
+                                      SEEK_MODE_CLOSEST_SYNC);
+
+    if (AV_ERR_OK != ret) {
+        return false;
+        qCCritical(AvCoder) << "seekTime failed, ret: " << ret;
+    }
+    return true;
+}
+
+QSharedPointer<QOhCodeKit::Audio> QOhDemuxer::audioInfo() const
+{
+    Q_D(const QOhDemuxer);
+    return d->m_audioInfo;
+}
+
+QSharedPointer<QOhCodeKit::Video> QOhDemuxer::videoInfo() const
+{
+    Q_D(const QOhDemuxer);
+    return d->m_videoInfo;
+}
+
+bool QOhDemuxer::readSample(int32_t trackId, OH_AVBuffer *buffer)
+{
+    Q_D(QOhDemuxer);
+    if (d->m_demuxer.isNull() || !buffer)
+        return false;
+
+    int ret = OH_AVDemuxer_ReadSampleBuffer(d->m_demuxer.get(), trackId, buffer);
+    if (AV_ERR_OK != ret) {
+        LOGE("read demuxer sample failed, ret: %{public}d", ret);
+        return false;
+    }
+
+    return true;
+}
+
+QT_END_NAMESPACE
+
diff --git a/src/plugins/openharmony/src/player/qohdemuxer.h b/src/plugins/openharmony/src/player/qohdemuxer.h
new file mode 100644
index 000000000..86ec12b30
--- /dev/null
+++ b/src/plugins/openharmony/src/player/qohdemuxer.h
@@ -0,0 +1,51 @@
+/*******************************************************************
+ *  Copyright(c) 2022-2025 ISS
+ *  All right reserved. See LGPL for detailed Information
+ *
+ *  文件名称: qohdemuxer.h
+ *  简要描述: 封装鸿蒙接口,提供从媒体文件码流中提取sample的接口
+ *  创建日期: 2024/12/13
+ *  作者: WangHao
+ *  说明:
+ *
+ *  修改日期:
+ *  作者:
+ *  说明:
+ ******************************************************************/
+#ifndef QOHDEMUXER_H
+#define QOHDEMUXER_H
+
+#include "qohcodekit.h"
+
+struct OH_AVBuffer;
+QT_BEGIN_NAMESPACE
+class QUrl;
+class QOhDemuxerPrivate;
+
+class QOhDemuxer : public QOhCodeKit
+{
+    Q_DECLARE_PRIVATE(QOhDemuxer)
+    Q_DISABLE_COPY_MOVE(QOhDemuxer)
+
+public:
+    enum Type {
+        E_NONE  = 0x00,
+        E_AUDIO = 0x01,
+        E_VIDEO = 0x02,
+    };
+
+    Q_DECLARE_FLAGS(Types, Type)
+    explicit QOhDemuxer(Type type);
+    ~QOhDemuxer();
+
+    bool isValid() const;
+    bool configure(const QUrl &url);
+    bool seekTime(qint64 millisecond);
+    QSharedPointer<QOhCodeKit::Audio> audioInfo() const;
+    QSharedPointer<QOhCodeKit::Video> videoInfo() const;
+    bool readSample(int32_t trackId, OH_AVBuffer *buffer);
+};
+Q_DECLARE_OPERATORS_FOR_FLAGS(QOhDemuxer::Types)
+QT_END_NAMESPACE
+
+#endif // QOHDEMUXER_H
diff --git a/src/plugins/openharmony/src/player/qohnativevideobuffer.cpp b/src/plugins/openharmony/src/player/qohnativevideobuffer.cpp
new file mode 100644
index 000000000..45311366c
--- /dev/null
+++ b/src/plugins/openharmony/src/player/qohnativevideobuffer.cpp
@@ -0,0 +1,68 @@
+#include <QDebug>
+#include <unistd.h>
+#include <native_buffer/buffer_common.h>
+
+#include "qohnativevideobuffer.h"
+
+QT_BEGIN_NAMESPACE
+
+QOhNativeVideoBuffer::QOhNativeVideoBuffer(uchar *dataCopy,
+                                           int dataSize,
+                                           const OH_NativeBuffer_Config &config,
+                                           int strideBytes)
+    : QAbstractVideoBuffer(QAbstractVideoBuffer::NoHandle)
+    , m_dataCopy(dataCopy)
+    , m_dataSize(dataSize)
+    , m_strideBytes(strideBytes > 0 ? strideBytes : config.stride)
+    , m_config(config)
+    , m_mapMode(NotMapped)
+{
+    
+}
+
+QOhNativeVideoBuffer::~QOhNativeVideoBuffer()
+{
+    /* 确保已经 unmap */
+    if (m_mapMode != NotMapped)
+        unmap();
+
+    /* 释放拷贝的数据 */
+    delete[] m_dataCopy;
+    m_dataCopy = nullptr;
+}
+
+QAbstractVideoBuffer::MapMode QOhNativeVideoBuffer::mapMode() const
+{
+    return m_mapMode;
+}
+
+uchar *QOhNativeVideoBuffer::map(MapMode mode, int *numBytes, int *bytesPerLine)
+{
+    if (m_mapMode != NotMapped || !m_dataCopy) {
+        qWarning() << "QOhNativeVideoBuffer::map: buffer already mapped or dataCopy is null";
+        return nullptr;
+    }
+
+    if (mode == NotMapped)
+        return nullptr;
+
+    m_mapMode = mode;
+
+    if (bytesPerLine)
+        *bytesPerLine = m_strideBytes;
+
+    if (numBytes)
+        *numBytes = m_dataSize;
+
+    return m_dataCopy;
+}
+
+void QOhNativeVideoBuffer::unmap()
+{
+    if (m_mapMode == NotMapped)
+        return;
+
+    m_mapMode = NotMapped;
+}
+
+QT_END_NAMESPACE
diff --git a/src/plugins/openharmony/src/player/qohnativevideobuffer.h b/src/plugins/openharmony/src/player/qohnativevideobuffer.h
new file mode 100644
index 000000000..864bc73cd
--- /dev/null
+++ b/src/plugins/openharmony/src/player/qohnativevideobuffer.h
@@ -0,0 +1,35 @@
+#ifndef QOHNATIVEVIDEOBUFFER_H
+#define QOHNATIVEVIDEOBUFFER_H
+
+#include <QAbstractVideoBuffer>
+#include <native_image/native_image.h>
+#include <native_buffer/native_buffer.h>
+#include <native_window/external_window.h>
+
+QT_BEGIN_NAMESPACE
+
+class QOhNativeVideoBuffer : public QAbstractVideoBuffer
+{
+    Q_DISABLE_COPY_MOVE(QOhNativeVideoBuffer)
+public:
+    QOhNativeVideoBuffer(uchar *dataCopy,
+                         int dataSize,
+                         const OH_NativeBuffer_Config &config,
+                         int strideBytes = 0); /* strideBytes=0 时自动根据 config.stride 计算 */
+    ~QOhNativeVideoBuffer() override;
+
+    MapMode mapMode() const override;
+    uchar *map(MapMode mode, int *numBytes, int *bytesPerLine) override;
+    void unmap() override;
+
+private:
+    uchar                 *m_dataCopy;      /* 已拷贝的像素数据 */
+    int                    m_dataSize;      /* 数据总字节数 */
+    int                    m_strideBytes;   /* 行跳(字节/行)*/
+    OH_NativeBuffer_Config m_config;
+    MapMode                m_mapMode;
+};
+
+QT_END_NAMESPACE
+
+#endif // QOHNATIVEVIDEOBUFFER_H
diff --git a/src/plugins/openharmony/src/player/qohplayer.cpp b/src/plugins/openharmony/src/player/qohplayer.cpp
new file mode 100644
index 000000000..808179267
--- /dev/null
+++ b/src/plugins/openharmony/src/player/qohplayer.cpp
@@ -0,0 +1,439 @@
+#include <QUrl>
+#include <QFile>
+#include <QHash>
+#include <QDebug>
+#include <QString>
+#include <QReadWriteLock>
+#include <QNetworkRequest>
+#include <rawfile/raw_file_manager.h>
+#include <multimedia/player_framework/avplayer_base.h>
+
+#include "qohplayer.h"
+
+typedef QHash<OH_AVPlayer *, QOhPlayer *> MediaPlayers;
+Q_GLOBAL_STATIC(MediaPlayers, mediaPlayers)
+Q_GLOBAL_STATIC(QReadWriteLock, rwLock)
+
+QT_BEGIN_NAMESPACE
+
+QOhPlayer::QOhPlayer()
+    : QObject()
+    , m_state(AV_IDLE)
+{
+    QWriteLocker locker(rwLock);
+    m_player = OH_AVPlayer_Create();
+    if (m_player != nullptr) {
+        OH_AVPlayer_SetOnInfoCallback(m_player, &QOhPlayer::onPlayerInfo, Q_NULLPTR);
+        OH_AVPlayer_SetOnErrorCallback(m_player, &QOhPlayer::onPlayerError, Q_NULLPTR);
+        mediaPlayers->insert(m_player, this);
+    }
+}
+
+QOhPlayer::~QOhPlayer()
+{
+    if (m_player != nullptr) {
+        QWriteLocker locker(rwLock);
+        mediaPlayers->remove(m_player);
+        OH_AVPlayer_Release(m_player);
+    }
+}
+
+void QOhPlayer::release()
+{
+    OH_AVPlayer_Release(m_player);
+}
+
+void QOhPlayer::reset()
+{
+    OH_AVPlayer_Reset(m_player);
+}
+
+int QOhPlayer::getCurrentPosition()
+{
+    if ((m_state == AV_PLAYING)
+        || (m_state == AV_PAUSED)
+        || (m_state == AV_COMPLETED)) {
+        int time = 0;
+        OH_AVPlayer_GetCurrentTime(m_player, &time);
+        return time;
+    }
+    return 0;
+}
+
+int QOhPlayer::getDuration()
+{
+    if (m_state < AV_PREPARED)
+        return 0;
+    int duration = 0;
+    OH_AVPlayer_GetDuration(m_player, &duration);
+    return duration;
+}
+
+bool QOhPlayer::isPlaying()
+{
+    return m_state == AV_PLAYING;
+}
+
+int QOhPlayer::volume()
+{
+    return m_volume * 100;
+}
+
+bool QOhPlayer::isMuted()
+{
+    return qFuzzyCompare(m_volume, 0.0);
+}
+
+qreal QOhPlayer::playbackRate()
+{
+    qreal rate(1.0);
+
+    AVPlaybackSpeed speed;
+    OH_AVPlayer_GetPlaybackSpeed(m_player, &speed);
+    switch (speed) {
+    case AV_SPEED_FORWARD_0_75_X:
+        rate = 0.75;
+        break;
+    case AV_SPEED_FORWARD_1_00_X:
+        rate = 1.0;
+        break;
+    case AV_SPEED_FORWARD_1_25_X:
+        rate = 1.25;
+        break;
+    case AV_SPEED_FORWARD_1_75_X:
+        rate = 1.75;
+        break;
+    case AV_SPEED_FORWARD_2_00_X:
+        rate = 2.0;
+        break;
+    }
+    return rate;
+}
+
+void QOhPlayer::play()
+{
+    if (m_state == AV_PLAYING)
+        return;
+
+    if ((m_state == AV_PREPARED)
+        || (m_state == AV_PAUSED)
+        || (m_state == AV_COMPLETED)) {
+        prepare();
+        OH_AVPlayer_Play(m_player);
+    } else if (m_state == AV_STOPPED) {
+        m_isPendingPlaying = true;
+        prepare();
+    }
+    else {
+        m_isPendingPlaying = true;
+    }
+}
+
+void QOhPlayer::pause()
+{
+    if (m_state == AV_PLAYING)
+        OH_AVPlayer_Pause(m_player);
+}
+
+void QOhPlayer::stop()
+{
+    if ((m_state == AV_PLAYING) ||
+        (m_state == AV_COMPLETED) ||
+        (m_state == AV_PREPARED) ||
+        (m_state == AV_PAUSED)) {
+        OH_AVPlayer_Stop(m_player);
+        OH_AVPlayer_Reset(m_player);
+    }
+}
+
+void QOhPlayer::seekTo(qint32 msec)
+{
+    if ((m_state == AV_PLAYING) ||
+        (m_state == AV_PAUSED) ||
+        (m_state == AV_COMPLETED)) {
+        OH_AVPlayer_Seek(m_player, msec, AV_SEEK_NEXT_SYNC);
+    }
+}
+
+void QOhPlayer::setMuted(bool mute)
+{
+    if (mute) {
+        m_volumeBeforeMute = m_volume;
+        setVolume(0);
+    } else {
+        setVolume(m_volumeBeforeMute);
+    }
+}
+
+void QOhPlayer::setDataSource(const QNetworkRequest &request)
+{
+    if (AV_IDLE != m_state)
+        reset();
+
+    QUrl url = request.url();
+    if (url.isEmpty())
+        return;
+
+    QString scheme = url.scheme();
+    if (scheme == "file") {
+        QFile file(url.path());
+        if (file.open(QFile::ReadOnly)) {
+            int length = file.size();
+            int fd = file.handle();
+            OH_AVErrCode code = OH_AVPlayer_SetFDSource(m_player, fd, 0, length);
+            if (AV_ERR_OK != code) {
+                setErrorString(code, tr("player with a null pointer or url with an empty value"));
+            }
+            file.close();
+        } else {
+            qWarning() << "Could not open media:" << file.errorString();
+            emit mediaStatusChanged(QMediaPlayer::InvalidMedia);
+        }
+    } else {
+        QString urlString = url.toString();
+        QByteArray dataArray = urlString.toLatin1();
+        OH_AVErrCode code = OH_AVPlayer_SetURLSource(m_player, dataArray);
+        if (AV_ERR_OK != code) {
+            setErrorString(code, tr("player with a null pointer or url with an empty value"));
+        }
+    }
+}
+
+void QOhPlayer::prepare()
+{
+    OH_AVPlayer_Prepare(m_player);
+}
+
+void QOhPlayer::setVolume(int volume)
+{
+    m_volume = volume;
+    OH_AVPlayer_SetVolume(m_player, m_volume / 100.0, m_volume / 100.0);
+}
+
+bool QOhPlayer::setPlaybackRate(qreal rate)
+{
+    AVPlaybackSpeed speed;
+    if (rate < 0.75)
+        speed = AV_SPEED_FORWARD_0_75_X;
+    else if (rate < 1.0)
+        speed = AV_SPEED_FORWARD_1_00_X;
+    else if (rate < 1.25)
+        speed = AV_SPEED_FORWARD_1_25_X;
+    else if (rate < 1.75)
+        speed = AV_SPEED_FORWARD_1_75_X;
+    else
+        speed = AV_SPEED_FORWARD_2_00_X;
+    return OH_AVPlayer_SetPlaybackSpeed(m_player, speed) == AV_ERR_OK;
+}
+
+#include <native_window/external_window.h>
+void QOhPlayer::setDisplay(OHNativeWindow *window)
+{
+    if (window == nullptr)
+        return;
+    m_window = window;
+
+    if (m_state == AV_INITIALIZED) {
+        OH_AVErrCode result = OH_AVPlayer_SetVideoSurface(m_player, m_window);
+        qWarning() << "Set Video Surface Result" << result;
+        m_surfaceSetted = true;
+        OH_AVPlayer_Prepare(m_player);
+    }
+}
+
+OHNativeWindow *QOhPlayer::display() const
+{
+    return m_window;
+}
+
+void QOhPlayer::setErrorString(int code, const QString &errorString)
+{
+    emit error(code, errorString);
+}
+
+void QOhPlayer::setPlayerInfo(AVPlayerOnInfoType type, OH_AVFormat *infoBody)
+{
+    switch(type) {
+    case AV_INFO_TYPE_STATE_CHANGE: {
+        int32_t state(AV_IDLE);
+        OH_AVFormat_GetIntValue(infoBody, OH_PLAYER_STATE, &state);
+        setState(state);
+    }
+        break;
+    case AV_INFO_TYPE_RESOLUTION_CHANGE:
+        obtainVideoSize();
+        emit videoAvailableChanged(true);
+        break;
+    case AV_INFO_TYPE_DURATION_UPDATE: {
+        int64_t duration(0);
+        OH_AVFormat_GetLongValue(infoBody, OH_PLAYER_DURATION, &duration);
+        emit durationChanged(duration);
+    }
+        break;
+    case AV_INFO_TYPE_POSITION_UPDATE: {
+        int32_t position(0);
+        OH_AVFormat_GetIntValue(infoBody, OH_PLAYER_CURRENT_POSITION, &position);
+        emit progressChanged(position);
+    }
+        break;
+    case AV_INFO_TYPE_BUFFERING_UPDATE: {
+        int32_t type(0);
+        int32_t value(0);
+        OH_AVFormat_GetIntValue(infoBody, OH_PLAYER_BUFFERING_TYPE, &type);
+        if (type == AVPLAYER_BUFFERING_START) {
+            emit bufferingChanged(0);
+        } else if (type == AVPLAYER_BUFFERING_END) {
+            emit bufferingChanged(100);
+        } else if (type == AVPLAYER_BUFFERING_PERCENT) {
+            OH_AVFormat_GetIntValue(infoBody, OH_PLAYER_BUFFERING_VALUE, &value);
+            emit bufferingChanged(value);
+        }
+    }
+        break;
+    default:
+        break;
+    }
+}
+
+void QOhPlayer::setState(int32_t state)
+{
+    m_state = AVPlayerState(state);
+    switch(state) {
+    case AV_IDLE:
+        //release(); /* NOTE 重置资源时不需要释放,否则引起崩溃 */
+        break;
+    case AV_INITIALIZED: // avplayer 设置播放源后触发该状态上报
+        if (!m_surfaceSetted && m_window != nullptr) {
+            OH_AVErrCode result = OH_AVPlayer_SetVideoSurface(m_player, m_window);
+            qWarning() << "Set Video Surface Result" << result;
+            m_surfaceSetted = true;
+        }
+        prepare();
+        break;
+    case AV_PREPARED: // prepare调用成功后上报该状态机
+        obtainVideoSize();
+        mediaStatusChanged(QMediaPlayer::LoadedMedia);
+        if (m_isPendingPlaying) {
+            OH_AVPlayer_Play(m_player);
+        }
+        emit audioAvailableChanged(true);
+        emit seekableChanged(true);
+        break;
+    case AV_STOPPED:
+        emit seekableChanged(false);
+        break;
+    case AV_COMPLETED:
+        emit mediaStatusChanged(QMediaPlayer::EndOfMedia);
+        break;
+    case AV_RELEASED:
+        emit durationChanged(0);
+        emit progressChanged(0);
+
+        emit audioAvailableChanged(false);
+        emit videoAvailableChanged(false);
+        emit seekableChanged(true);
+        break;
+    default:
+        break;
+    }
+    stateChanged(state);
+}
+
+void QOhPlayer::setAudioRole(QAudio::Role role)
+{
+    OH_AudioStream_Usage ohAudioRole = AUDIOSTREAM_USAGE_UNKNOWN;
+
+    switch(role){
+    case QAudio::UnknownRole:
+        ohAudioRole = AUDIOSTREAM_USAGE_UNKNOWN;
+        break;
+    case QAudio::MusicRole:
+        ohAudioRole = AUDIOSTREAM_USAGE_MUSIC;
+        break;
+    case QAudio::VideoRole:
+        ohAudioRole = AUDIOSTREAM_USAGE_MOVIE;
+        break;
+    case QAudio::VoiceCommunicationRole:
+        ohAudioRole = AUDIOSTREAM_USAGE_VOICE_COMMUNICATION;
+        break;
+    case QAudio::AlarmRole:
+        ohAudioRole = AUDIOSTREAM_USAGE_ALARM;
+        break;
+    case QAudio::NotificationRole:
+        ohAudioRole = AUDIOSTREAM_USAGE_NOTIFICATION;
+        break;
+    case QAudio::RingtoneRole:
+        ohAudioRole = AUDIOSTREAM_USAGE_RINGTONE;
+        break;
+    case QAudio::AccessibilityRole:
+        ohAudioRole = AUDIOSTREAM_USAGE_ACCESSIBILITY;
+        break;
+    case QAudio::GameRole:
+        ohAudioRole = AUDIOSTREAM_USAGE_GAME;
+        break;
+    default:
+        break;
+    }
+
+    OH_AVPlayer_SetAudioRendererInfo(m_player, ohAudioRole);
+}
+
+void QOhPlayer::setCustomAudioRole(const QString &role)
+{
+    OH_AudioStream_Usage ohAudioRole = AUDIOSTREAM_USAGE_UNKNOWN;
+
+    if(role == QLatin1String("AUDIOSTREAM_USAGE_VOICE_ASSISTANT"))
+        ohAudioRole = AUDIOSTREAM_USAGE_VOICE_ASSISTANT;
+    else if(role == QLatin1String("AUDIOSTREAM_USAGE_VOICE_MESSAGE"))
+        ohAudioRole = AUDIOSTREAM_USAGE_VOICE_MESSAGE;
+    else if(role == QLatin1String("AUDIOSTREAM_USAGE_AUDIOBOOK"))
+        ohAudioRole = AUDIOSTREAM_USAGE_AUDIOBOOK;
+    else if(role == QLatin1String("AUDIOSTREAM_USAGE_NAVIGATION"))
+        ohAudioRole = AUDIOSTREAM_USAGE_NAVIGATION;
+    else if(role == QLatin1String("AUDIOSTREAM_USAGE_VIDEO_COMMUNICATION"))
+        ohAudioRole = AUDIOSTREAM_USAGE_VIDEO_COMMUNICATION;
+    else{
+        ohAudioRole = AUDIOSTREAM_USAGE_UNKNOWN;
+    }
+
+    OH_AVPlayer_SetAudioRendererInfo(m_player, ohAudioRole);
+}
+
+void QOhPlayer::obtainVideoSize()
+{
+    int32_t w, h = 0;
+    OH_AVErrCode result = OH_AVPlayer_GetVideoWidth(m_player, &w);
+    if (result != AV_ERR_OK)
+        return;
+    result = OH_AVPlayer_GetVideoHeight(m_player, &h);
+    if (result != AV_ERR_OK)
+        return;
+    emit videoSizeChanged(w, h);    
+}
+
+void QOhPlayer::onPlayerInfo(OH_AVPlayer *player, AVPlayerOnInfoType type,
+                                      OH_AVFormat *infoBody, void *userData)
+{
+    Q_UNUSED(userData);
+    QOhPlayer *p = mediaPlayers->value(player);
+    if (p == nullptr)
+        return;
+    p->setPlayerInfo(type, infoBody);
+}
+
+void QOhPlayer::onPlayerError(OH_AVPlayer *player, int32_t errorCode,
+                                       const char *errorMsg, void *userData)
+{
+    Q_UNUSED(userData);
+    QOhPlayer *p = mediaPlayers->value(player);
+    if (p == nullptr)
+        return;
+    p->setErrorString(errorCode, QString::fromLatin1(errorMsg));
+}
+
+AVPlayerState QOhPlayer::state() const
+{
+    return m_state;
+}
+
+QT_END_NAMESPACE
diff --git a/src/plugins/openharmony/src/player/qohplayer.h b/src/plugins/openharmony/src/player/qohplayer.h
new file mode 100644
index 000000000..c2ead3ffa
--- /dev/null
+++ b/src/plugins/openharmony/src/player/qohplayer.h
@@ -0,0 +1,82 @@
+#ifndef QOHPLAYER_H
+#define QOHPLAYER_H
+
+#include <cstdint>
+#include <QObject>
+#include <napi/native_api.h>
+#include <QtMultimedia/qmediaplayer.h>
+#include <multimedia/player_framework/avplayer.h>
+#include <multimedia/player_framework/native_avformat.h>
+#include <ohaudio/native_audiostream_base.h>
+
+class QNetworkRequest;
+struct NativeResourceManager;
+
+class QOhPlayer : public QObject
+{
+    Q_OBJECT
+public:
+    QOhPlayer();
+    ~QOhPlayer();
+
+    void release();
+    void reset();
+
+    int getCurrentPosition();
+    int getDuration();
+    bool isPlaying();
+    int volume();
+    bool isMuted();
+    qreal playbackRate();
+
+    void play();
+    void pause();
+    void stop();
+    void seekTo(qint32 msec);
+    void setMuted(bool mute);
+    void setDataSource(const QNetworkRequest &request);
+    void prepare();
+    void setVolume(int volume);
+    bool setPlaybackRate(qreal rate);
+    void setDisplay(OHNativeWindow *window);
+    OHNativeWindow *display() const;
+
+
+    void setErrorString(int code, const QString &errorString);
+    void setPlayerInfo(AVPlayerOnInfoType type, OH_AVFormat *infoBody);
+
+    AVPlayerState state() const;
+    void setState(int32_t state);
+
+    void setAudioRole(QAudio::Role role);
+    void setCustomAudioRole(const QString &role);
+
+Q_SIGNALS:
+    void error(int code, const QString &errorString);
+    void bufferingChanged(qint32 percent);
+    void durationChanged(qint64 duration);
+    void progressChanged(qint64 progress);
+    void stateChanged(qint32 state);
+    void videoSizeChanged(qint32 width, qint32 height);
+    void audioAvailableChanged(bool available);
+    void videoAvailableChanged(bool available);
+    void seekableChanged(bool seekable);
+    void mediaStatusChanged(QMediaPlayer::MediaStatus status);
+private:
+    void obtainVideoSize();
+    void setPlayerData();
+private:
+    static void onPlayerInfo(OH_AVPlayer *player, AVPlayerOnInfoType type, OH_AVFormat *infoBody, void *userData);
+    static void onPlayerError(OH_AVPlayer *player, int32_t errorCode, const char *errorMsg, void *userData);
+private:
+    OH_AVPlayer *m_player = nullptr;
+    int m_volume = 0;
+    int m_volumeBeforeMute = 0;
+    OHNativeWindow *m_window = nullptr;
+    bool m_surfaceSetted = false;
+    AVPlayerState m_state;
+    bool m_isPendingPlaying = false;
+    QUrl m_url;
+};
+
+#endif // QOHPLAYER_H
diff --git a/src/plugins/openharmony/src/player/qohplayercontrol.cpp b/src/plugins/openharmony/src/player/qohplayercontrol.cpp
new file mode 100644
index 000000000..72d2366e7
--- /dev/null
+++ b/src/plugins/openharmony/src/player/qohplayercontrol.cpp
@@ -0,0 +1,381 @@
+#include <qaudio.h>
+#include <QtCore/qmath.h>
+#include <QtCore/qcoreapplication.h>
+#include <multimedia/player_framework/avplayer.h>
+
+#include "qohplayer.h"
+#include "qohvideorenderercontrol.h"
+#include "qohplayercontrol.h"
+#include "qohplayerservice.h"
+#include "qohwindowcontrol.h"
+
+QOhPlayerControl::QOhPlayerControl(QObject *parent)
+    : QMediaPlayerControl(parent)
+{
+    m_player = new QOhPlayer();
+    connect(m_player,SIGNAL(bufferingChanged(qint32)),
+            this,SLOT(onBufferingChanged(qint32)));
+    connect(m_player,SIGNAL(error(int,QString)),
+            this,SLOT(onError(int,QString)));
+    connect(m_player,SIGNAL(stateChanged(qint32)),
+            this,SLOT(onStateChanged(qint32)));
+    connect(m_player,SIGNAL(videoSizeChanged(qint32,qint32)),
+            this,SLOT(onVideoSizeChanged(qint32,qint32)));
+    connect(m_player,SIGNAL(progressChanged(qint64)),
+            this,SIGNAL(positionChanged(qint64)));
+    connect(m_player,SIGNAL(durationChanged(qint64)),
+            this,SIGNAL(durationChanged(qint64)));
+    connect(m_player,SIGNAL(audioAvailableChanged(bool)),
+            this,SLOT(setAudioAvailable(bool)));
+    connect(m_player,SIGNAL(videoAvailableChanged(bool)),
+            this,SLOT(setVideoAvailable(bool)));
+    connect(m_player,SIGNAL(seekableChanged(bool)),
+            this,SLOT(setSeekable(bool)));
+    connect(m_player,SIGNAL(mediaStatusChanged(QMediaPlayer::MediaStatus)),
+            this,SLOT(setMediaStatus(QMediaPlayer::MediaStatus)));
+}
+
+QOhPlayerControl::~QOhPlayerControl()
+{
+    m_player->release();
+    delete m_player;
+}
+
+void QOhPlayerControl::setVideoRenderOutput(QOhVideoRendererControl *control)
+{
+    m_videoRenderControl = control;
+}
+
+void QOhPlayerControl::setVideoWindowOutput(QOhWindowControl *control)
+{
+    m_videoWindowcControl = control;
+
+    if (nullptr != m_videoWindowcControl)
+        connect(m_videoWindowcControl, &QOhWindowControl::windowCreated, this, &QOhPlayerControl::onWindowCreated);
+}
+
+QMediaPlayer::State QOhPlayerControl::state() const
+{
+     AVPlayerState state = m_player->state();
+     if (state == AV_PLAYING)
+         return QMediaPlayer::PlayingState;
+     else if (state == AV_PAUSED)
+         return QMediaPlayer::PausedState;
+     else
+         return QMediaPlayer::StoppedState;
+}
+
+QMediaPlayer::MediaStatus QOhPlayerControl::mediaStatus() const
+{
+    return m_status;
+}
+
+qint64 QOhPlayerControl::duration() const
+{
+    return m_player->getDuration();
+}
+
+qint64 QOhPlayerControl::position() const
+{
+    if (m_status == QMediaPlayer::EndOfMedia)
+        return duration();
+    return m_player->getCurrentPosition();
+}
+
+void QOhPlayerControl::setPosition(qint64 position)
+{
+    if (m_status == QMediaPlayer::EndOfMedia) {
+        m_status = QMediaPlayer::LoadedMedia;
+        emit mediaStatusChanged(m_status);
+    }
+    const int seekPosition = (position > INT_MAX) ? INT_MAX : position;
+
+    if (seekPosition == this->position())
+        return;
+
+    m_player->seekTo(seekPosition);
+    /* NativeImage 方案下 seek 由 AVPlayer 统一处理,无需单独通知 videoRenderControl */
+
+    Q_EMIT positionChanged(seekPosition);
+}
+
+int QOhPlayerControl::volume() const
+{
+    return m_volume;
+}
+
+void QOhPlayerControl::setVolume(int volume)
+{
+    if (m_volume == volume)
+        return;
+    m_player->setVolume(volume);
+
+    Q_EMIT volumeChanged(volume);
+}
+
+bool QOhPlayerControl::isMuted() const
+{
+    return m_muted;
+}
+
+void QOhPlayerControl::setMuted(bool muted)
+{
+    if (m_muted == muted)
+        return;
+
+    m_player->setMuted(muted);
+
+    Q_EMIT mutedChanged(muted);
+}
+
+int QOhPlayerControl::bufferStatus() const
+{
+    return m_bufferFilled ? 100 : 0;
+}
+
+bool QOhPlayerControl::isAudioAvailable() const
+{
+    return m_audioAvailable;
+}
+
+bool QOhPlayerControl::isVideoAvailable() const
+{
+    return m_videoAvailable;
+}
+
+bool QOhPlayerControl::isSeekable() const
+{
+    return m_seekable;
+}
+
+QMediaTimeRange QOhPlayerControl::availablePlaybackRanges() const
+{
+    return m_availablePlaybackRange;
+}
+
+void QOhPlayerControl::updateAvailablePlaybackRanges()
+{
+    if (m_buffering) {
+        const qint64 pos = position();
+        const qint64 end = (duration() / 100) * m_bufferPercent;
+        m_availablePlaybackRange.addInterval(pos, end);
+    } else if (m_seekable) {
+        m_availablePlaybackRange = QMediaTimeRange(0, duration());
+    } else {
+        m_availablePlaybackRange = QMediaTimeRange();
+    }
+
+    Q_EMIT availablePlaybackRangesChanged(m_availablePlaybackRange);
+}
+
+qreal QOhPlayerControl::playbackRate() const
+{
+    return m_player->playbackRate();
+}
+
+void QOhPlayerControl::setPlaybackRate(qreal rate)
+{
+    if (m_player->setPlaybackRate(rate)) {
+        emit playbackRateChanged(rate);
+    }
+}
+
+QMediaContent QOhPlayerControl::media() const
+{
+    return m_media;
+}
+
+const QIODevice *QOhPlayerControl::mediaStream() const
+{
+    return m_stream;
+}
+
+void QOhPlayerControl::setMedia(const QMediaContent &media, QIODevice *stream)
+{
+    if (m_media == media && m_stream == stream)
+        return;
+
+    m_media = media;
+    m_stream = stream;
+    if (media.isNull()) {
+        m_status = QMediaPlayer::NoMedia;
+    } else {
+        m_status = QMediaPlayer::LoadingMedia;
+
+        /* 确保 Surface 已设置到 AVPlayer(如果 setVideoRenderOutput 在 setMedia 之后才调用) */
+        if (m_videoRenderControl && m_videoRenderControl->producerWindow())
+            m_player->setDisplay(m_videoRenderControl->producerWindow());
+
+        m_player->setDataSource(media.request());
+        /* 注意:不再调用 m_videoRenderControl->setDataSource()
+         * NativeImage 方案由 AVPlayer Surface 模式直接输出到 ConsumerSurface */
+
+        m_status = QMediaPlayer::LoadedMedia;
+    }
+
+    Q_EMIT mediaChanged(media);
+}
+
+void QOhPlayerControl::play()
+{
+    playOrPause(QMediaPlayer::PlayingState);
+}
+
+void QOhPlayerControl::pause()
+{
+    playOrPause(QMediaPlayer::PausedState);
+}
+
+void QOhPlayerControl::playOrPause(QMediaPlayer::State state)
+{
+    if (m_status == QMediaPlayer::NoMedia || state == QMediaPlayer::StoppedState)
+        return;
+
+    if (m_status == QMediaPlayer::InvalidMedia) {
+        setMedia(m_media, m_stream);
+        if (m_error != QMediaPlayer::NoError)
+            return;
+    }
+
+    if (state == QMediaPlayer::PausedState) {
+        m_player->pause();
+        if (m_videoRenderControl)
+            m_videoRenderControl->pause();
+    } else {
+        if (m_videoRenderControl)
+            m_videoRenderControl->play();
+        m_player->play();
+    }
+    emit stateChanged(state);
+}
+
+void QOhPlayerControl::stop()
+{
+    if (m_videoRenderControl)
+        m_videoRenderControl->stop();
+
+    m_player->stop();
+    emit stateChanged(QMediaPlayer::StoppedState);
+}
+
+QSize QOhPlayerControl::videoSize() const
+{
+    return m_videoSize;
+}
+
+void QOhPlayerControl::setAudioRole(QAudio::Role role)
+{
+    m_player->setAudioRole(role);
+}
+
+void QOhPlayerControl::setCustomAudioRole(const QString &role)
+{
+    m_player->setCustomAudioRole(role);
+}
+
+void QOhPlayerControl::setSeekable(bool seekable)
+{
+    if (m_seekable == seekable)
+        return;
+
+    m_seekable = seekable;
+    Q_EMIT seekableChanged(m_seekable);
+}
+
+void QOhPlayerControl::setAudioAvailable(bool available)
+{
+    if (m_audioAvailable == available)
+        return;
+
+    m_audioAvailable = available;
+    Q_EMIT videoAvailableChanged(m_audioAvailable);
+}
+
+void QOhPlayerControl::setVideoAvailable(bool available)
+{
+    if (m_videoAvailable == available)
+        return;
+
+    m_videoAvailable = available;
+    Q_EMIT videoAvailableChanged(m_videoAvailable);
+}
+
+void QOhPlayerControl::onWindowCreated()
+{
+    m_player->setDisplay(m_videoWindowcControl->nativeWindow());
+}
+
+void QOhPlayerControl::onStateChanged(qint32)
+{
+    emit stateChanged(state());
+}
+
+void QOhPlayerControl::onVideoSizeChanged(qint32 width, qint32 height)
+{
+    QSize newSize(width, height);
+
+    if (width == 0 || height == 0 || newSize == m_videoSize)
+        return;
+
+    m_videoSize = newSize;
+}
+
+void QOhPlayerControl::setMediaStatus(QMediaPlayer::MediaStatus status)
+{
+    if (m_status == status)
+        return;
+
+    m_status = status;
+
+    Q_EMIT mediaStatusChanged(m_status);
+
+    if (status == QMediaPlayer::NoMedia || status == QMediaPlayer::InvalidMedia)
+        Q_EMIT durationChanged(0);
+
+    if (status == QMediaPlayer::EndOfMedia)
+        Q_EMIT positionChanged(position());
+
+    updateBufferStatus();
+}
+
+void QOhPlayerControl::updateBufferStatus()
+{
+    bool bufferFilled = (m_status == QMediaPlayer::BufferedMedia
+                         || m_status == QMediaPlayer::BufferingMedia);
+
+    if (m_bufferFilled != bufferFilled) {
+        m_bufferFilled = bufferFilled;
+        Q_EMIT bufferStatusChanged(bufferStatus());
+    }
+}
+
+void QOhPlayerControl::onBufferingChanged(qint32 percent)
+{
+    m_buffering = percent != 100;
+    m_bufferPercent = percent;
+
+    updateAvailablePlaybackRanges();
+
+    if (state() != QMediaPlayer::StoppedState)
+        setMediaStatus(m_buffering ? QMediaPlayer::BufferingMedia : QMediaPlayer::BufferedMedia);
+}
+
+void QOhPlayerControl::onError(int code, const QString &errorString)
+{
+    qWarning() <<"open harmony player error: " << code << errorString;
+    // Todo 鸿蒙errorCode和QMediaPlayer::Error对应
+    QMediaPlayer::Error mError = QMediaPlayer::ResourceError;
+    switch(code) {
+    case AV_ERR_SERVICE_DIED:
+        mError = QMediaPlayer::ServiceMissingError;
+        break;
+    case AV_ERR_INVALID_VAL:
+        mError = QMediaPlayer::ResourceError;
+        break;
+    default:
+        mError = QMediaPlayer::ResourceError;
+        break;
+    }
+
+    emit error(mError, errorString);
+}
diff --git a/src/plugins/openharmony/src/player/qohplayercontrol.h b/src/plugins/openharmony/src/player/qohplayercontrol.h
new file mode 100644
index 000000000..15f709954
--- /dev/null
+++ b/src/plugins/openharmony/src/player/qohplayercontrol.h
@@ -0,0 +1,101 @@
+#ifndef QOHPLAYERCONTROL_H
+#define QOHPLAYERCONTROL_H
+
+#include "qmediacontent.h"
+#include "qmediaplayercontrol.h"
+
+#include <QSize>
+#include <QtCore/qcoreevent.h>
+
+QT_BEGIN_NAMESPACE
+class QOhPlayer;
+class QOhVideoRendererControl;
+class QOhWindowControl;
+
+class QOhPlayerControl : public QMediaPlayerControl
+{
+    Q_OBJECT
+public:
+    QOhPlayerControl(QObject *parent = nullptr);
+    ~QOhPlayerControl() override;
+
+    void setVideoRenderOutput(QOhVideoRendererControl *control);
+    void setVideoWindowOutput(QOhWindowControl *control);
+
+    QMediaPlayer::State state() const override;
+
+    QMediaPlayer::MediaStatus mediaStatus() const override;
+
+    qint64 duration() const override;
+
+    qint64 position() const override;
+    void setPosition(qint64 position) override;
+
+    int volume() const override;
+    void setVolume(int volume) override;
+
+    bool isMuted() const override;
+    void setMuted(bool muted) override;
+
+    int bufferStatus() const override;
+
+    bool isAudioAvailable() const override;
+    bool isVideoAvailable() const override;
+
+    bool isSeekable() const override;
+
+    QMediaTimeRange availablePlaybackRanges() const override;
+
+    qreal playbackRate() const override;
+    void setPlaybackRate(qreal rate) override;
+
+    QMediaContent media() const override;
+    const QIODevice *mediaStream() const override;
+    void setMedia(const QMediaContent &media, QIODevice *stream) override;
+
+    void play() override;
+    void pause() override;
+    void stop() override;
+    QSize videoSize() const;
+
+public slots:
+    void setAudioRole(QAudio::Role role);
+    void setCustomAudioRole(const QString &role);
+
+private slots:
+    void setSeekable(bool seekable);
+    void setAudioAvailable(bool available);
+    void setVideoAvailable(bool available);
+    void onWindowCreated();
+    void onStateChanged(qint32);
+    void onVideoSizeChanged(qint32, qint32 height);
+    void setMediaStatus(QMediaPlayer::MediaStatus status);
+    void onBufferingChanged(qint32 percent);
+    void onError(int code, const QString &errorString);
+private:
+    void updateAvailablePlaybackRanges();
+    void updateBufferStatus();
+    void playOrPause(QMediaPlayer::State state);
+    QOhVideoRendererControl *m_videoRenderControl = nullptr;
+    QOhWindowControl *m_videoWindowcControl = nullptr;
+    QOhPlayer *m_player = nullptr;
+    QMediaPlayer::MediaStatus m_status = QMediaPlayer::NoMedia;
+    QMediaPlayer::Error m_error = QMediaPlayer::NoError;
+    QMediaTimeRange m_availablePlaybackRange;
+    QIODevice *m_stream = nullptr;
+    int m_volume = 100;
+    bool m_muted = false;
+    QMediaContent m_media;
+    QString m_errorString;
+    QSize m_videoSize;
+    bool m_seekable = true;
+    bool m_audioAvailable = false;
+    bool m_videoAvailable = false;
+    bool m_buffering = false;
+    bool m_bufferPercent = 0;
+    bool m_bufferFilled = false;
+};
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/plugins/openharmony/src/player/qohplayerservice.cpp b/src/plugins/openharmony/src/player/qohplayerservice.cpp
new file mode 100644
index 000000000..6bbeee3be
--- /dev/null
+++ b/src/plugins/openharmony/src/player/qohplayerservice.cpp
@@ -0,0 +1,87 @@
+#include "qvideorenderercontrol.h"
+#include "qohvideorenderercontrol.h"
+#include "qohplayerservice.h"
+#include "qohplayercontrol.h"
+#include "qohwindowcontrol.h"
+#include "qohaudiorolecontrol.h"
+#include "qohcustomaudiorolecontrol.h"
+
+QT_BEGIN_NAMESPACE
+
+QOhPlayerService::QOhPlayerService(QObject *parent)
+    : QMediaService(parent)
+{
+    m_playerControl = new QOhPlayerControl(this);
+
+    m_audioRoleControl = new QOhAudioRoleControl;
+    m_customAudioRoleControl = new QOhCustomAudioRoleControl;
+    connect(m_audioRoleControl, &QOhAudioRoleControl::audioRoleChanged,
+            m_playerControl, &QOhPlayerControl::setAudioRole);
+    connect(m_customAudioRoleControl, &QOhCustomAudioRoleControl::customAudioRoleChanged,
+            m_playerControl, &QOhPlayerControl::setCustomAudioRole);
+}
+
+QOhPlayerService::~QOhPlayerService()
+{
+    if (m_playerControl) {
+        delete m_playerControl;
+        m_playerControl = nullptr;
+    }
+
+    if (m_videoWindowControl) {
+        delete m_videoWindowControl;
+        m_videoWindowControl = nullptr;
+    }
+
+    if (m_videoRenderControl) {
+        delete m_videoRenderControl;
+        m_videoRenderControl = nullptr;
+    }
+}
+
+QMediaControl *QOhPlayerService::requestControl(const char *name)
+{
+    if (0 == qstrcmp(QMediaPlayerControl_iid, name))
+        return m_playerControl;
+
+    if (0 == qstrcmp(QVideoWindowControl_iid, name)) {
+        m_videoWindowControl = new QOhWindowControl();
+        m_videoWindowControl->setPlayerControl(m_playerControl);
+        m_playerControl->setVideoWindowOutput(m_videoWindowControl);
+        return m_videoWindowControl;
+    }
+
+    if (0 == qstrcmp(QVideoRendererControl_iid, name)) {
+        m_videoRenderControl = new QOhVideoRendererControl();
+        m_playerControl->setVideoRenderOutput(m_videoRenderControl);
+        return m_videoRenderControl;
+    }
+
+    if (0 == qstrcmp(QAudioRoleControl_iid, name)){
+        return m_audioRoleControl;
+    }
+
+    if (0 == qstrcmp(QCustomAudioRoleControl_iid, name)){
+        return m_customAudioRoleControl;
+    }
+
+    return nullptr;
+}
+
+void QOhPlayerService::releaseControl(QMediaControl *control)
+{
+    if (m_videoWindowControl == control) {
+        delete m_videoWindowControl;
+        m_videoWindowControl = nullptr;
+        m_playerControl->setVideoWindowOutput(nullptr);
+    }
+
+    if (m_videoRenderControl == control) {
+        m_videoRenderControl->stop();
+        delete m_videoRenderControl;
+        m_videoRenderControl = nullptr;
+        m_playerControl->setVideoRenderOutput(nullptr);
+    }
+}
+
+QT_END_NAMESPACE
diff --git a/src/plugins/openharmony/src/player/qohplayerservice.h b/src/plugins/openharmony/src/player/qohplayerservice.h
new file mode 100644
index 000000000..ec3961879
--- /dev/null
+++ b/src/plugins/openharmony/src/player/qohplayerservice.h
@@ -0,0 +1,34 @@
+#ifndef QOHPLAYERSERVICE_H
+#define QOHPLAYERSERVICE_H
+
+#include "qmediaservice.h"
+
+QT_BEGIN_NAMESPACE
+
+class QOhVideoRendererControl;
+class QOhPlayerControl;
+class QOhWindowControl;
+class QOhAudioRoleControl;
+class QOhCustomAudioRoleControl;
+
+class QOhPlayerService : public QMediaService
+{
+    Q_OBJECT
+public:
+    QOhPlayerService(QObject *parent = nullptr);
+    ~QOhPlayerService() override;
+
+    QMediaControl *requestControl(const char *name) override;
+    void releaseControl(QMediaControl *control) override;
+
+private:
+    QOhPlayerControl *m_playerControl = nullptr;
+    QOhVideoRendererControl *m_videoRenderControl  = nullptr;
+    QOhWindowControl *m_videoWindowControl = nullptr;
+    QOhAudioRoleControl *m_audioRoleControl = nullptr;
+    QOhCustomAudioRoleControl *m_customAudioRoleControl = nullptr;
+};
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/plugins/openharmony/src/player/qohvideorenderercontrol.cpp b/src/plugins/openharmony/src/player/qohvideorenderercontrol.cpp
new file mode 100644
index 000000000..04fe94e6d
--- /dev/null
+++ b/src/plugins/openharmony/src/player/qohvideorenderercontrol.cpp
@@ -0,0 +1,342 @@
+#include <QImage>
+#include <QDebug>
+#include <QVideoSurfaceFormat>
+#include <QAbstractVideoSurface>
+#include <QVideoFrame>
+#include <unistd.h>
+#include <poll.h>
+#include <cerrno>
+#include <native_buffer/native_buffer.h>
+#include <native_buffer/buffer_common.h>
+#include <native_window/external_window.h>
+
+#include "qohnativevideobuffer.h"
+#include "qohvideorenderercontrol.h"
+
+QT_BEGIN_NAMESPACE
+
+QOhVideoRendererControl::QOhVideoRendererControl(QObject *parent)
+    : QVideoRendererControl(parent)
+{
+    m_nativeImage = OH_ConsumerSurface_Create();
+    if (!m_nativeImage) {
+        qCritical() << "QOhVideoRendererControl: OH_ConsumerSurface_Create failed";
+        return;
+    }
+
+    /* 必须设置 CPU_READ usage,否则 OH_NativeBuffer_Map 返回的是图形内存句柄而非像素数据 */
+    int32_t usageRet = OH_ConsumerSurface_SetDefaultUsage(
+            m_nativeImage,
+            NATIVEBUFFER_USAGE_CPU_READ | NATIVEBUFFER_USAGE_CPU_WRITE | NATIVEBUFFER_USAGE_MEM_DMA);
+    if (usageRet != 0)
+        qWarning() << "QOhVideoRendererControl: SetDefaultUsage failed, ret=" << usageRet;
+
+    m_producerWindow = OH_NativeImage_AcquireNativeWindow(m_nativeImage);
+    if (!m_producerWindow) {
+        qCritical() << "QOhVideoRendererControl: OH_NativeImage_AcquireNativeWindow failed";
+        return;
+    }
+
+    OH_OnFrameAvailableListener listener;
+    listener.context = this;
+    listener.onFrameAvailable = &QOhVideoRendererControl::onFrameAvailable;
+    int ret = OH_NativeImage_SetOnFrameAvailableListener(m_nativeImage, listener);
+    if (ret != 0)
+        qWarning() << "QOhVideoRendererControl: SetOnFrameAvailableListener failed, ret=" << ret;
+}
+
+QOhVideoRendererControl::~QOhVideoRendererControl()
+{
+    stop();
+
+    if (m_nativeImage) {
+        OH_NativeImage_Destroy(&m_nativeImage);
+        m_nativeImage = nullptr;
+        m_producerWindow = nullptr;
+    }
+}
+
+OHNativeWindow *QOhVideoRendererControl::producerWindow() const
+{
+    return m_producerWindow;
+}
+
+void QOhVideoRendererControl::play()
+{
+    m_active = true;
+}
+
+void QOhVideoRendererControl::stop()
+{
+    m_active = false;
+
+    if (m_surface && m_surface->isActive())
+        m_surface->stop();
+
+    m_pixelFormat        = QVideoFrame::Format_Invalid;
+    m_frameSize = QSize();
+}
+
+void QOhVideoRendererControl::pause()
+{
+    m_active = false;
+}
+
+QAbstractVideoSurface *QOhVideoRendererControl::surface() const
+{
+    return m_surface;
+}
+
+void QOhVideoRendererControl::setSurface(QAbstractVideoSurface *surface)
+{
+    if (m_surface == surface)
+        return;
+
+    if (m_surface && m_surface->isActive())
+        m_surface->stop();
+
+    m_surface = surface;
+    m_pixelFormat        = QVideoFrame::Format_Invalid;
+    m_frameSize = QSize();
+}
+
+void QOhVideoRendererControl::onFrameAvailable(void *context)
+{
+    QOhVideoRendererControl *ctrl = static_cast<QOhVideoRendererControl *>(context);
+    if (!ctrl)
+        return;
+    
+    QMetaObject::invokeMethod(ctrl, "consumeFrame", Qt::QueuedConnection);
+}
+
+void QOhVideoRendererControl::consumeFrame()
+{
+    if (!m_active || !m_surface || !m_nativeImage)
+        return;
+
+    OHNativeWindowBuffer *windowBuffer = nullptr;
+    int fenceFd = -1;
+    int ret = OH_NativeImage_AcquireNativeWindowBuffer(m_nativeImage, &windowBuffer, &fenceFd);
+    if (ret != 0 || !windowBuffer) {
+        qWarning() << "QOhVideoRendererControl: AcquireNativeWindowBuffer failed, ret=" << ret;
+        return;
+    }
+
+    OH_NativeBuffer *nativeBuffer = nullptr;
+    OH_NativeBuffer_FromNativeWindowBuffer(windowBuffer, &nativeBuffer);
+    if (!nativeBuffer) {
+        qWarning() << "QOhVideoRendererControl: OH_NativeBuffer_FromNativeWindowBuffer failed";
+        OH_NativeImage_ReleaseNativeWindowBuffer(m_nativeImage, windowBuffer, fenceFd);
+        return;
+    }
+
+    if (fenceFd >= 0) {
+        struct pollfd pollfds = {};
+        pollfds.fd = fenceFd;
+        pollfds.events = POLLIN;
+        
+        int retCode = -1;
+        constexpr int MAX_RETRY = 3;
+        int retryCount = 0;
+        
+        do {
+            retCode = poll(&pollfds, 1, 3000); // 3 秒超时
+            retryCount++;
+            
+            if (retryCount >= MAX_RETRY) {
+                qWarning() << "QOhVideoRendererControl: poll fence reached max retry, ret=" << retCode 
+                          << "errno=" << errno;
+                break;
+            }
+        } while (retCode == -1 && (errno == EINTR || errno == EAGAIN));
+        
+        close(fenceFd);
+        fenceFd = -1;
+        
+        if (retCode <= 0) {
+            qWarning() << "QOhVideoRendererControl: poll fence failed, ret=" << retCode;
+            OH_NativeImage_ReleaseNativeWindowBuffer(m_nativeImage, windowBuffer, -1);
+            return;
+        }
+    }
+    
+    void *ptr = nullptr;
+    OH_NativeBuffer_Planes planes{};
+    int ret2 = OH_NativeBuffer_MapPlanes(nativeBuffer, &ptr, &planes);
+    if (ret2 != 0 || !ptr) {
+        qWarning() << "QOhVideoRendererControl: OH_NativeBuffer_MapPlanes failed, ret=" << ret2;
+        OH_NativeImage_ReleaseNativeWindowBuffer(m_nativeImage, windowBuffer, -1);
+        return;
+    }
+
+    OH_NativeBuffer_Config config{};
+    OH_NativeBuffer_GetConfig(nativeBuffer, &config);
+
+    if (config.width <= 0 || config.height <= 0) {
+        qWarning() << "QOhVideoRendererControl: invalid buffer config w=" << config.width
+                   << " h=" << config.height;
+        OH_NativeBuffer_Unmap(nativeBuffer);
+        OH_NativeImage_ReleaseNativeWindowBuffer(m_nativeImage, windowBuffer, -1);
+        return;
+    }
+
+    const OH_NativeBuffer_Format cfgFmt = static_cast<OH_NativeBuffer_Format>(config.format);
+    const uchar *base = static_cast<const uchar *>(ptr);
+
+    /* 对 NV12/NV21 直接从 planes 取各平面的真实 offset 和 stride */
+    uint64_t yOffset   = 0;
+    uint64_t uvOffset  = 0;
+    uint32_t yStride   = static_cast<uint32_t>(config.stride);
+    uint32_t uvStride  = static_cast<uint32_t>(config.stride);
+    bool hasPlaneInfo  = false;
+
+    if ((cfgFmt == NATIVEBUFFER_PIXEL_FMT_YCBCR_420_SP ||
+         cfgFmt == NATIVEBUFFER_PIXEL_FMT_YCRCB_420_SP) && planes.planeCount >= 2
+            && planes.planes[1].offset >= (uint64_t)(config.stride) * config.height) {
+        /* MapPlanes 返回的 offset 对消费者 Surface 的 buffer 是可靠的,
+         * rowStride 字段对该类型 buffer 无效,始终用 config.stride */
+        yOffset      = planes.planes[0].offset;
+        uvOffset     = planes.planes[1].offset;
+        yStride      = static_cast<uint32_t>(config.stride);
+        uvStride     = static_cast<uint32_t>(config.stride);
+        hasPlaneInfo = true;
+    }
+
+    int dataSize;
+    if (hasPlaneInfo) {
+        /* 总拷贝大小:包含 Y+UV 平面的最大范围 */
+        dataSize = static_cast<int>(uvOffset) + static_cast<int>(uvStride) * (config.height / 2);
+    } else {
+        switch (cfgFmt) {
+        case NATIVEBUFFER_PIXEL_FMT_YCBCR_420_SP:
+        case NATIVEBUFFER_PIXEL_FMT_YCRCB_420_SP:
+        case NATIVEBUFFER_PIXEL_FMT_YCBCR_420_P:
+        case NATIVEBUFFER_PIXEL_FMT_YCRCB_420_P:
+            dataSize = config.stride * config.height * 3 / 2;
+            break;
+        default:
+            dataSize = config.stride * config.height;
+            break;
+        }
+    }
+
+    uchar *dataCopy = new uchar[dataSize];
+    memcpy(dataCopy, base, dataSize);
+
+    OH_NativeBuffer_Unmap(nativeBuffer);
+    OH_NativeImage_ReleaseNativeWindowBuffer(m_nativeImage, windowBuffer, -1);
+    QVideoFrame::PixelFormat qtFmt = nativeFormatToQtFormat(cfgFmt);
+
+    const QSize frameSize(config.width, config.height);
+    QVideoFrame presentFrame;
+
+    if (qtFmt == QVideoFrame::Format_NV12 || qtFmt == QVideoFrame::Format_NV21) {
+        QImage argb(config.width, config.height, QImage::Format_ARGB32);
+        const uchar *yPlane  = dataCopy + yOffset;
+        const uchar *uvPlane = dataCopy + uvOffset;
+        const bool isNV12    = (qtFmt == QVideoFrame::Format_NV12);
+        convertNV12NV21ToARGB32(yPlane, static_cast<int>(yStride),
+                                uvPlane, static_cast<int>(uvStride),
+                                argb.bits(), config.width, config.height, isNV12);
+        delete[] dataCopy;
+        presentFrame = QVideoFrame(argb);
+    } else {
+        auto *videoBuffer = new QOhNativeVideoBuffer(dataCopy, dataSize, config,
+                                                     static_cast<int>(yStride));
+        presentFrame = QVideoFrame(videoBuffer, frameSize, qtFmt);
+    }
+
+    if (!m_surface->isActive()
+            || m_frameSize != frameSize
+            || m_pixelFormat != presentFrame.pixelFormat()) {
+        startSurface(presentFrame);
+    }
+
+    if (!m_surface->isActive())
+        return;
+
+    m_surface->present(presentFrame);
+}
+
+void QOhVideoRendererControl::startSurface(const QVideoFrame &frame)
+{
+    if (!m_surface)
+        return;
+
+    if (m_surface->isActive())
+        m_surface->stop();
+
+    QVideoSurfaceFormat format(frame.size(), frame.pixelFormat());
+    if (!m_surface->isFormatSupported(format)) {
+        format = QVideoSurfaceFormat(frame.size(), QVideoFrame::Format_ARGB32);
+    }
+
+    if (!m_surface->start(format)) {
+        qWarning() << "QOhVideoRendererControl: failed to start surface with format" << format;
+        return;
+    }
+
+    m_frameSize          = frame.size();
+    m_pixelFormat        = frame.pixelFormat();
+}
+
+QVideoFrame::PixelFormat QOhVideoRendererControl::nativeFormatToQtFormat(OH_NativeBuffer_Format fmt)
+{
+    switch (fmt) {
+    case NATIVEBUFFER_PIXEL_FMT_YCBCR_420_SP: return QVideoFrame::Format_NV12;
+    case NATIVEBUFFER_PIXEL_FMT_YCRCB_420_SP: return QVideoFrame::Format_NV21;
+    case NATIVEBUFFER_PIXEL_FMT_RGBA_8888:    return QVideoFrame::Format_ARGB32;  /* RGBA 内存[R,G,B,A], Qt ARGB32小端 = [B,G,R,A],小端 ARM 下指向同一内存内容 */
+    case NATIVEBUFFER_PIXEL_FMT_RGBX_8888:    return QVideoFrame::Format_RGB32;
+    case NATIVEBUFFER_PIXEL_FMT_BGRA_8888:    return QVideoFrame::Format_ARGB32; /* BGRA 内存小端 = Qt ARGB32 */
+    case NATIVEBUFFER_PIXEL_FMT_YCBCR_420_P:  return QVideoFrame::Format_YUV420P;
+    case NATIVEBUFFER_PIXEL_FMT_YCRCB_420_P:  return QVideoFrame::Format_YUV420P;
+    default:
+        qWarning() << "QOhVideoRendererControl: unknown native format" << static_cast<int>(fmt)
+                   << ", fallback to ARGB32";
+        return QVideoFrame::Format_ARGB32;
+    }
+}
+
+void QOhVideoRendererControl::convertNV12NV21ToARGB32(
+        const uchar *yPlane, int yStride,
+        const uchar *uvPlane, int uvStride,
+        uchar *output, int width, int height, bool isNV12)
+{
+    quint32 *dst = reinterpret_cast<quint32 *>(output);
+
+    for (int j = 0; j < height; j += 2) {
+        const uchar *y0row = yPlane + j * yStride;
+        const uchar *y1row = yPlane + (j + 1) * yStride;
+        const uchar *uvrow = uvPlane + (j / 2) * uvStride;
+        quint32 *out0 = dst + j * width;
+        quint32 *out1 = dst + (j + 1) * width;
+
+        for (int i = 0; i < width; i += 2) {
+            const uchar *uv = uvrow + i;
+            const int u = static_cast<int>(isNV12 ? uv[0] : uv[1]) - 128;
+            const int v = static_cast<int>(isNV12 ? uv[1] : uv[0]) - 128;
+
+            const int rv  = 409 * v + 128;
+            const int guv = 100 * u + 208 * v + 128;
+            const int bu  = 516 * u + 128;
+
+            auto clamp = [](int x) -> int { return x < 0 ? 0 : (x > 255 ? 255 : x); };
+            auto yuv2rgb = [&](int y) -> quint32 {
+                int yy = (y - 16) * 298;
+                return (0xffu << 24)
+                       | (clamp((yy + rv)  >> 8) << 16)
+                       | (clamp((yy - guv) >> 8) << 8)
+                       |  clamp((yy + bu)  >> 8);
+            };
+
+            out0[i]     = yuv2rgb(y0row[i]);
+            out0[i + 1] = yuv2rgb(y0row[i + 1]);
+            if (j + 1 < height) {
+                out1[i]     = yuv2rgb(y1row[i]);
+                out1[i + 1] = yuv2rgb(y1row[i + 1]);
+            }
+        }
+    }
+}
+
+QT_END_NAMESPACE
diff --git a/src/plugins/openharmony/src/player/qohvideorenderercontrol.h b/src/plugins/openharmony/src/player/qohvideorenderercontrol.h
new file mode 100644
index 000000000..06ce00f08
--- /dev/null
+++ b/src/plugins/openharmony/src/player/qohvideorenderercontrol.h
@@ -0,0 +1,55 @@
+#ifndef QOHVIDEORENDERERCONTROL_H
+#define QOHVIDEORENDERERCONTROL_H
+
+#include <QList>
+#include <QSize>
+#include <QVideoFrame>
+#include <QVideoRendererControl>
+#include <native_image/native_image.h>
+#include <native_window/external_window.h>
+#include <native_buffer/native_buffer.h>
+#include <native_buffer/buffer_common.h>
+#include <atomic>
+
+QT_BEGIN_NAMESPACE
+
+class QOhVideoRendererControl : public QVideoRendererControl
+{
+    Q_OBJECT
+    Q_DISABLE_COPY_MOVE(QOhVideoRendererControl)
+
+public:
+    explicit QOhVideoRendererControl(QObject *parent = nullptr);
+    ~QOhVideoRendererControl();
+
+    OHNativeWindow *producerWindow() const;
+
+    void play();
+    void stop();
+    void pause();
+
+    QAbstractVideoSurface *surface() const override;
+    void setSurface(QAbstractVideoSurface *surface) override;
+
+private slots:
+    void consumeFrame();
+
+private:
+    static void onFrameAvailable(void *context);
+    void startSurface(const QVideoFrame &frame);
+    static QVideoFrame::PixelFormat nativeFormatToQtFormat(OH_NativeBuffer_Format fmt);
+    static void convertNV12NV21ToARGB32(const uchar *yPlane, int yStride,
+                                        const uchar *uvPlane, int uvStride,
+                                        uchar *output, int width, int height, bool isNV12);
+
+    QAbstractVideoSurface    *m_surface             = nullptr;
+    OH_NativeImage           *m_nativeImage         = nullptr;
+    OHNativeWindow           *m_producerWindow      = nullptr;
+    bool                      m_active              = false;
+    QVideoFrame::PixelFormat  m_pixelFormat         = QVideoFrame::Format_Invalid; /* 上一帧格式,用于检测格式变化 */
+    QSize                     m_frameSize;
+};
+
+QT_END_NAMESPACE
+
+#endif // QOHVIDEORENDERERCONTROL_H
diff --git a/src/plugins/openharmony/src/player/qohwindowcontrol.cpp b/src/plugins/openharmony/src/player/qohwindowcontrol.cpp
new file mode 100644
index 000000000..2c4926407
--- /dev/null
+++ b/src/plugins/openharmony/src/player/qohwindowcontrol.cpp
@@ -0,0 +1,210 @@
+#include "qohwindowcontrol.h"
+#include <qopenharmonydefines.h>
+#include <QHash>
+#include "qohplayercontrol.h"
+#include <arkui/native_node.h>
+#include <arkui/native_type.h>
+#include <arkui/native_interface.h>
+#include <native_window/external_window.h>
+#include <QTimer>
+#include <QWidget>
+#include <uv.h>
+
+#include <QtPlatformHeaders/qohwindowfunctions.h>
+
+struct Node {
+    ArkUI_NodeType nodeType; // Type of the node. The value can be ARKUI_NODE_XCOMPONENT or other types supported in later versions.
+    ArkUI_NodeHandle node; // ARKUI_NODE_XCOMPONENT type or other.
+    ArkUI_NodeHandle container; // Must be of type ARKUI_NODE_STACK.
+    char nodeOwner[8]; // Describes the body of the Node structure to be created, such as "QT," "CEF," "SDL2," "FLUT".
+    void* nodePrivate; // Structure used for the definition of the nodeOwner body record itself.
+};
+
+struct WindowNode : Node
+{
+    void *window;
+};
+
+class VideoOutWidget : public QWidget
+{
+    // 阻止Qt绘制,创建surface
+public:
+    VideoOutWidget(QWidget *parent) : QWidget(parent)
+    {
+        setUpdatesEnabled(false);
+        setObjectName("_q_oh_videowidget");
+        //setAttribute(Qt::WA_UpdatesDisabled);
+        //setAttribute(Qt::WA_StyledBackground);
+    }
+};
+
+
+QOhWindowControl::QOhWindowControl(QObject *parent)
+    : QVideoWindowControl(parent)
+    , m_timer(nullptr)
+    , m_widget(nullptr)
+{
+
+}
+
+QOhWindowControl::~QOhWindowControl()
+{
+
+}
+
+WId QOhWindowControl::winId() const
+{
+    return m_windowId;
+}
+
+void QOhWindowControl::setWinId(WId id)
+{
+    if (m_windowId == id)
+        return;
+    m_windowId = id;
+
+    QWidget *widget = QWidget::find(m_windowId);
+    if (widget == nullptr) {
+        qWarning() << "set player output widget failed";
+        return;
+    }
+
+    m_widget = new VideoOutWidget(widget);
+    WId videoId = m_widget->winId();
+    m_widget->show();
+    QOhWindowFunctions::setNativeNodeRenderFit(m_widget->windowHandle(), QOhWindowFunctions::NativeNodeRenderFit::FIT_RESIZE_FILL);
+    WindowNode *node = reinterpret_cast<WindowNode*>(videoId);
+    if (node == nullptr) {
+        qWarning() << "set player output widget failed";
+        return;
+    }
+
+    if (node->window != nullptr) {
+        setNativeWindow(reinterpret_cast<OHNativeWindow *>(node->window));
+    } else {
+        if (m_timer == nullptr) {
+            m_timer = new QTimer(this);
+            connect(m_timer, &QTimer::timeout, this, [node, this]{
+                if (node->window != nullptr) {                    
+                    setNativeWindow(reinterpret_cast<OHNativeWindow *>(node->window));
+                    m_timer->stop();
+                }
+            });
+        }
+        if (!m_timer->isActive()) {
+            m_timer->start(500);
+        }
+    }
+}
+
+QRect QOhWindowControl::displayRect() const
+{
+    return m_displayRect;
+}
+
+void QOhWindowControl::setDisplayRect(const QRect &rect)
+{
+    m_displayRect = rect;
+    if (m_widget != nullptr)
+        m_widget->setGeometry(0, 0, rect.width(), rect.height());
+}
+
+bool QOhWindowControl::isFullScreen() const
+{
+    return m_fullScreen;
+}
+
+void QOhWindowControl::setFullScreen(bool fullScreen)
+{
+    emit fullScreenChanged(m_fullScreen = fullScreen);
+}
+
+void QOhWindowControl::repaint()
+{
+
+}
+
+QSize QOhWindowControl::nativeSize() const
+{
+    return m_playerControl == nullptr ? QSize() : m_playerControl->videoSize();
+}
+
+Qt::AspectRatioMode QOhWindowControl::aspectRatioMode() const
+{
+    return m_aspectRatioMode;
+}
+
+void QOhWindowControl::setAspectRatioMode(Qt::AspectRatioMode mode)
+{
+    m_aspectRatioMode = mode;
+#if 0
+    QOhWindowFunctions::setNativeNodeRenderFit(m_widget->windowHandle(), Qt::IgnoreAspectRatio == mode ? QOhWindowFunctions::NativeNodeRenderFit::FIT_RESIZE_FILL
+    : Qt::KeepAspectRatio == mode ? QOhWindowFunctions::NativeNodeRenderFit::FIT_RESIZE_CONTAIN_TOP_LEFT : QOhWindowFunctions::NativeNodeRenderFit::FIT_RESIZE_COVER);
+#endif
+}
+
+int QOhWindowControl::brightness() const
+{
+    return m_brightness;
+}
+
+void QOhWindowControl::setBrightness(int brightness)
+{
+    m_brightness = brightness;
+
+    emit brightnessChanged(brightness);
+}
+
+int QOhWindowControl::contrast() const
+{
+    return m_contrast;
+}
+
+void QOhWindowControl::setContrast(int contrast)
+{
+    m_contrast = contrast;
+
+    emit contrastChanged(contrast);
+}
+
+int QOhWindowControl::hue() const
+{
+    return m_hue;
+}
+
+void QOhWindowControl::setHue(int hue)
+{
+    m_hue = hue;
+
+    emit hueChanged(hue);
+}
+
+int QOhWindowControl::saturation() const
+{
+    return m_saturation;
+}
+
+void QOhWindowControl::setSaturation(int saturation)
+{
+    m_saturation = saturation;
+
+    emit saturationChanged(saturation);
+}
+
+void QOhWindowControl::setNativeWindow(OHNativeWindow *nativeWindow)
+{
+    m_nativeWindow = nativeWindow;
+    QMetaObject::invokeMethod(this, "windowCreated");
+}
+
+OHNativeWindow *QOhWindowControl::nativeWindow() const
+{
+    return m_nativeWindow;
+}
+
+void QOhWindowControl::setPlayerControl(QOhPlayerControl *control)
+{
+    if (control == nullptr)
+        return;
+    m_playerControl = control;
+}
diff --git a/src/plugins/openharmony/src/player/qohwindowcontrol.h b/src/plugins/openharmony/src/player/qohwindowcontrol.h
new file mode 100644
index 000000000..4b29959db
--- /dev/null
+++ b/src/plugins/openharmony/src/player/qohwindowcontrol.h
@@ -0,0 +1,70 @@
+#ifndef QOHWINDOWCONTROL_H
+#define QOHWINDOWCONTROL_H
+
+#include "qvideowindowcontrol.h"
+#include <multimedia/player_framework/avplayer.h>
+
+QT_BEGIN_NAMESPACE
+class VideoOutWidget;
+class QOhPlayerControl;
+class QOhWindowControl : public QVideoWindowControl
+{
+    Q_OBJECT
+public:
+    QOhWindowControl(QObject *parent = nullptr);
+    ~QOhWindowControl() override;
+
+    WId winId() const override;
+    void setWinId(WId id) override;
+
+    QRect displayRect() const override;
+    void setDisplayRect(const QRect &rect) override;
+
+    bool isFullScreen() const override;
+    void setFullScreen(bool fullScreen) override;
+
+    void repaint() override;
+
+    QSize nativeSize() const override;
+
+    Qt::AspectRatioMode aspectRatioMode() const override;
+    void setAspectRatioMode(Qt::AspectRatioMode mode) override;
+
+    int brightness() const override;
+    void setBrightness(int brightness) override;
+
+    int contrast() const override;
+    void setContrast(int contrast) override;
+
+    int hue() const override;
+    void setHue(int hue) override;
+
+    int saturation() const override;
+    void setSaturation(int saturation) override;
+
+    void setNativeWindow(OHNativeWindow *nativeWindow);
+    OHNativeWindow *nativeWindow() const;
+
+    void setPlayerControl(QOhPlayerControl *control);
+
+Q_SIGNALS:
+    void windowCreated();
+
+private:
+    WId m_windowId = 0;
+    OHNativeWindow *m_nativeWindow = nullptr;
+    Qt::AspectRatioMode m_aspectRatioMode = Qt::IgnoreAspectRatio;
+    QRect m_displayRect;
+    int m_brightness = 0;
+    int m_contrast = 0;
+    int m_hue = 0;
+    int m_saturation = 0;
+    bool m_fullScreen = false;
+    QOhPlayerControl *m_playerControl;
+    QTimer *m_timer;
+    VideoOutWidget *m_widget;
+};
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/plugins/openharmony/src/qohmediaserviceplugin.cpp b/src/plugins/openharmony/src/qohmediaserviceplugin.cpp
new file mode 100644
index 000000000..7518aca32
--- /dev/null
+++ b/src/plugins/openharmony/src/qohmediaserviceplugin.cpp
@@ -0,0 +1,100 @@
+#include <QLoggingCategory>
+
+#include "qcamera.h"
+#include "qmediaserviceproviderplugin.h"
+#include "qohmediaserviceplugin.h"
+#include "mediacapture/qohcamerasession.h"
+#include "mediacapture/qohcaptureservice.h"
+#include "mediacapture/qohcamerainfocontrol.h"
+#include "qohplayerservice.h"
+// #include "qopenharmonyaudioservice.h"
+
+QT_BEGIN_NAMESPACE
+
+Q_LOGGING_CATEGORY(qtOPenHaronyMediaPlugin, "qt.multimedia.plugins.openharmony")
+
+QOhMediaServicePlugin::QOhMediaServicePlugin()
+{
+}
+
+QOhMediaServicePlugin::~QOhMediaServicePlugin()
+{
+}
+
+QMediaService *QOhMediaServicePlugin::create(const QString &key)
+{
+    if (key == QLatin1String(Q_MEDIASERVICE_MEDIAPLAYER))
+        return new QOhPlayerService();
+
+    if (key == QLatin1String(Q_MEDIASERVICE_CAMERA)) {
+        return new QOhCaptureService();
+    }
+
+    qCWarning(qtOPenHaronyMediaPlugin) << "OPenHarony service plugin: unsupported key:" << key;
+    return 0;
+}
+
+void QOhMediaServicePlugin::release(QMediaService *service)
+{
+    delete service;
+}
+
+QMediaServiceProviderHint::Features QOhMediaServicePlugin::supportedFeatures(const QByteArray &service) const
+{
+    if (service == Q_MEDIASERVICE_MEDIAPLAYER)
+        return QMediaServiceProviderHint::VideoSurface;
+
+    if (service == Q_MEDIASERVICE_CAMERA)
+        return QMediaServiceProviderHint::VideoSurface | QMediaServiceProviderHint::RecordingSupport;
+
+
+    return QMediaServiceProviderHint::Features();
+}
+
+QByteArray QOhMediaServicePlugin::defaultDevice(const QByteArray &service) const
+{
+    if (service == Q_MEDIASERVICE_CAMERA && !QOhCameraSession::availableCameras().isEmpty())
+        return QOhCameraSession::availableCameras().first().name;
+
+    return QByteArray();
+}
+
+QList<QByteArray> QOhMediaServicePlugin::devices(const QByteArray &service) const
+{
+    Q_UNUSED(service);
+    if (service == Q_MEDIASERVICE_CAMERA) {
+        QList<QByteArray> devices;
+        const QList<OhCameraInfo> &cameras = QOhCameraSession::availableCameras();
+        for (int i = 0; i < cameras.count(); ++i)
+            devices.append(cameras.at(i).name);
+        return devices;
+    }
+
+    return QList<QByteArray>();
+}
+
+QString QOhMediaServicePlugin::deviceDescription(const QByteArray &service, const QByteArray &device)
+{
+    if (service == Q_MEDIASERVICE_CAMERA) {
+        const QList<OhCameraInfo> &cameras = QOhCameraSession::availableCameras();
+        for (int i = 0; i < cameras.count(); ++i) {
+            const OhCameraInfo &info = cameras.at(i);
+            if (info.name == device)
+                return info.description;
+        }
+    }
+
+    return QString();
+}
+
+QCamera::Position QOhMediaServicePlugin::cameraPosition(const QByteArray &device) const
+{
+    return QOhCameraInfoControl::position(device);
+}
+
+int QOhMediaServicePlugin::cameraOrientation(const QByteArray &device) const
+{
+    return QOhCameraInfoControl::orientation(device);
+}
+
+QT_END_NAMESPACE
diff --git a/src/plugins/openharmony/src/qohmediaserviceplugin.h b/src/plugins/openharmony/src/qohmediaserviceplugin.h
new file mode 100644
index 000000000..6b85e4769
--- /dev/null
+++ b/src/plugins/openharmony/src/qohmediaserviceplugin.h
@@ -0,0 +1,42 @@
+#ifndef QOHMEDIASERVICEPLUGIN_H
+#define QOHMEDIASERVICEPLUGIN_H
+
+#include <QMediaServiceProviderPlugin>
+
+QT_BEGIN_NAMESPACE
+
+class QOhMediaServicePlugin
+        : public QMediaServiceProviderPlugin
+        , public QMediaServiceSupportedDevicesInterface
+        , public QMediaServiceDefaultDeviceInterface
+        , public QMediaServiceCameraInfoInterface
+        , public QMediaServiceFeaturesInterface
+{
+    Q_OBJECT
+    Q_INTERFACES(QMediaServiceSupportedDevicesInterface)
+    Q_INTERFACES(QMediaServiceDefaultDeviceInterface)
+    Q_INTERFACES(QMediaServiceCameraInfoInterface)
+    Q_INTERFACES(QMediaServiceFeaturesInterface)
+    Q_PLUGIN_METADATA(IID "org.qt-project.qt.mediaserviceproviderfactory/5.0"
+                      FILE "oh_mediaservice.json")
+
+public:
+    QOhMediaServicePlugin();
+    ~QOhMediaServicePlugin();
+
+    QMediaService* create(QString const& key) override;
+    void release(QMediaService *service) override;
+
+    QMediaServiceProviderHint::Features supportedFeatures(const QByteArray &service) const override;
+
+    QByteArray defaultDevice(const QByteArray &service) const override;
+    QList<QByteArray> devices(const QByteArray &service) const override;
+    QString deviceDescription(const QByteArray &service, const QByteArray &device) override;
+
+    QCamera::Position cameraPosition(const QByteArray &device) const override;
+    int cameraOrientation(const QByteArray &device) const override;
+};
+
+QT_END_NAMESPACE
+
+#endif // QOHMEDIASERVICEPLUGIN_H
diff --git a/src/plugins/openharmony/src/src.pro b/src/plugins/openharmony/src/src.pro
new file mode 100644
index 000000000..79ec4b6a9
--- /dev/null
+++ b/src/plugins/openharmony/src/src.pro
@@ -0,0 +1,26 @@
+include (wrappers/napi/napi.pri)
+include (mediacapture/mediacapture.pri)
+include (player/player.pri)
+
+TARGET = qtmedia_openharmony
+
+LIBS += -lace_ndk.z -lavplayer -lrawfile.z -lnative_media_core
+LIBS += -lohcamera -lohimage -limage_receiver -lnative_image -lnative_buffer
+LIBS += -lnative_media_codecbase -lnative_media_core -lnative_media_vdec \
+        -lnative_media_avsource -lnative_media_avdemuxer -lohaudio -lnative_window
+
+QT += multimedia-private core-private network
+
+HEADERS += \
+    qohmediaserviceplugin.h
+
+SOURCES += \
+    qohmediaserviceplugin.cpp
+
+
+OTHER_FILES += \
+    oh_mediaservice.json
+
+PLUGIN_TYPE = mediaservice
+PLUGIN_CLASS_NAME = QOPenHarmonyMediaServicePlugin
+load(qt_plugin)
diff --git a/src/plugins/openharmony/src/wrappers/napi/napi.pri b/src/plugins/openharmony/src/wrappers/napi/napi.pri
new file mode 100644
index 000000000..6f279c810
--- /dev/null
+++ b/src/plugins/openharmony/src/wrappers/napi/napi.pri
@@ -0,0 +1,11 @@
+INCLUDEPATH += $$PWD
+
+HEADERS += \
+    # $$PWD/ohcamera.h \
+    $$PWD/ohmediarecorder.h \
+    $$PWD/ohmultimediautils.h
+
+SOURCES += \
+    # $$PWD/ohcamera.cpp \
+    $$PWD/ohmediarecorder.cpp \
+    $$PWD/ohmultimediautils.cpp
diff --git a/src/plugins/openharmony/src/wrappers/napi/ohcamera.cpp b/src/plugins/openharmony/src/wrappers/napi/ohcamera.cpp
new file mode 100644
index 000000000..f6981d481
--- /dev/null
+++ b/src/plugins/openharmony/src/wrappers/napi/ohcamera.cpp
@@ -0,0 +1,167 @@
+#include <QDebug>
+#include <QThread>
+#include <QWriteLocker>
+#include <QReadWriteLock>
+#include <QSharedPointer>
+#include <QtCore/QJsonValue>
+#include <QtCore/QJsonArray>
+#include <QtCore/QJsonObject>
+#include <QtCore/QJsonDocument>
+#include <QtCore/QJsonParseError>
+#include <QtCore/QLoggingCategory>
+
+#include "QtCore/QOpenHarmonyJsObject"
+#include "QtCore/QOpenHarmonyJsEnvironment"
+#include "QtCore/QOpenHarmonyJsObjectLoader"
+
+QT_BEGIN_NAMESPACE
+
+Q_LOGGING_CATEGORY(qtCameraInfo, "qt.multimedia.plugins.openharmony.camerainfo")
+
+using CameraMap = QHash<QString, OhCamera *>;
+
+Q_GLOBAL_STATIC(CameraMap, cameras)
+Q_GLOBAL_STATIC(QReadWriteLock, rwLock)
+
+class OhCameraPrivate : public QObject
+{
+    Q_OBJECT
+
+public:
+    OhCameraPrivate();
+    ~OhCameraPrivate();
+
+    Q_INVOKABLE bool init(const QString &cameraId);
+
+    static QStringList getIdOfCameras();
+    static void getCameraInfo(const QString &id, OhCameraInfo *info);
+public:
+    QString m_cameraId;
+    static QSharedPointer<QOpenHarmonyJsObject> m_jsCamera;
+};
+QSharedPointer<QOpenHarmonyJsObject> OhCameraPrivate::m_jsCamera(Q_NULLPTR);
+
+OhCameraPrivate::OhCameraPrivate()
+    : QObject()
+{
+    m_jsCamera = qJsObjectLoader->create("JsCameraManager");
+}
+
+OhCameraPrivate::~OhCameraPrivate()
+{
+
+}
+
+bool OhCameraPrivate::init(const QString &cameraId)
+{
+    Q_UNUSED(cameraId);
+    return false;
+}
+
+QStringList OhCameraPrivate::getIdOfCameras()
+{
+    if (m_jsCamera.isNull()){
+        m_jsCamera = qJsObjectLoader->create("JsCameraManager");
+    }
+    QStringList ids = m_jsCamera->call<QStringList>("idOfCameras");
+    return ids;
+}
+
+void OhCameraPrivate::getCameraInfo(const QString &id, OhCameraInfo *info)
+{
+    Q_ASSERT(info);
+    if (m_jsCamera.isNull()){
+        m_jsCamera = qJsObjectLoader->create("JsCameraManager");
+    }
+
+    QString json = m_jsCamera->call<QString>("cameraInfo", id);
+    if (json.isEmpty())
+        return;
+
+    QJsonParseError error;
+    QJsonDocument doc = QJsonDocument::fromJson(json.toLocal8Bit(), &error);
+    if (QJsonParseError::NoError != error.error) {
+        qCWarning(qtCameraInfo) << "parase camera info from openharmony: " << error.errorString();
+        return;
+    }
+
+    QJsonObject obj = doc.object();
+    QString cameraId = obj.value(QStringLiteral("cameraId")).toString();
+    info->name = cameraId.toLocal8Bit();
+    int pos = obj.value(QStringLiteral("cameraPosition")).toInt();
+    info->position = QCamera::Position(pos);
+
+    static QHash<int, QString> sCameraTypeDes{
+        { 3, QStringLiteral("Telephoto camera") },
+        { 1, QStringLiteral("Wide Angle Len Camera") },
+        { 2, QStringLiteral("Ultra wide Angle camera") },
+        { 0, QStringLiteral("The camera type was not specified") },
+        { 4, QStringLiteral("Camera with depth of field information") }
+    };
+
+            static QHash<int, QString> sConnectionTypeDes{
+                                                            { 0, QStringLiteral(" Built-in Camera") },
+                                                            { 1, QStringLiteral(" Usb-connected camera") },
+                                                            { 2, QStringLiteral(" Remotely connected camera") },
+                                                            };
+
+    int cameraType = obj.value("cameraType").toInt();
+    int connectType = obj.value("connectionType").toInt();
+    info->description = sCameraTypeDes.value(cameraType) + sConnectionTypeDes.value(connectType);
+    info->orientation = 0; //TODO Returns the physical orientation of the camera sensor.
+}
+
+OhCamera::~OhCamera()
+{
+
+}
+
+QString OhCamera::cameraId() const
+{
+    Q_D(const OhCamera);
+    return d->m_cameraId;
+}
+
+QStringList OhCamera::getIdOfCameras()
+{
+    return std::move(OhCameraPrivate::getIdOfCameras());
+}
+
+OhCamera *OhCamera::open(const QString &cameraId)
+{
+    OhCameraPrivate *d = new OhCameraPrivate();
+    QThread *worker = new QThread;
+    worker->start();
+    d->moveToThread(worker);
+    connect(worker, &QThread::finished, d, &OhCameraPrivate::deleteLater);
+    bool ok = true;
+    QMetaObject::invokeMethod(d, "init", Qt::BlockingQueuedConnection, Q_RETURN_ARG(bool, ok), Q_ARG(const QString&, cameraId));
+    if (!ok) {
+        worker->quit();
+        worker->wait(5000);
+        delete worker;
+        return 0;
+    }
+
+    OhCamera *q = new OhCamera(d, worker);
+    QWriteLocker locker(rwLock);
+    cameras->insert(cameraId, q);
+
+    return q;
+}
+
+void OhCamera::getCameraInfo(const QString &id, OhCameraInfo *info)
+{
+    OhCameraPrivate::getCameraInfo(id, info);
+}
+
+OhCamera::OhCamera(OhCameraPrivate *d, QThread *worker) : QObject()
+      , d_ptr(d)
+      , m_worker(worker)
+{
+
+}
+
+QT_END_NAMESPACE
+
+#include "OhCamera.moc"
diff --git a/src/plugins/openharmony/src/wrappers/napi/ohcamera.h b/src/plugins/openharmony/src/wrappers/napi/ohcamera.h
new file mode 100644
index 000000000..5da3f8ac5
--- /dev/null
+++ b/src/plugins/openharmony/src/wrappers/napi/ohcamera.h
@@ -0,0 +1,43 @@
+#ifndef OHCAMERA_H
+#define OHCAMERA_H
+
+#include <QObject>
+#include <QtMultimedia/qcamera.h>
+
+QT_BEGIN_NAMESPACE
+
+class QThread;
+class OhCameraPrivate;
+
+struct OhCameraInfo
+{
+    QByteArray name;
+    QString description;
+    QCamera::Position position;
+    int orientation;
+};
+Q_DECLARE_TYPEINFO(OhCameraInfo, Q_MOVABLE_TYPE);
+
+class OhCamera : public QObject
+{
+    Q_OBJECT    
+
+public:    
+    ~OhCamera();
+
+    QString cameraId() const;
+    static QStringList getIdOfCameras();
+    static OhCamera *open(const QString &cameraId);
+    static void getCameraInfo(const QString &id, OhCameraInfo *info);
+
+Q_SIGNALS:
+
+private:
+    OhCameraPrivate *d_ptr;
+    QScopedPointer<QThread> m_worker;
+    Q_DECLARE_PRIVATE(OhCamera)
+    OhCamera(OhCameraPrivate *d, QThread *worker);
+};
+
+QT_END_NAMESPACE
+#endif // OHCAMERA_H
diff --git a/src/plugins/openharmony/src/wrappers/napi/ohmediarecorder.cpp b/src/plugins/openharmony/src/wrappers/napi/ohmediarecorder.cpp
new file mode 100644
index 000000000..156ff970a
--- /dev/null
+++ b/src/plugins/openharmony/src/wrappers/napi/ohmediarecorder.cpp
@@ -0,0 +1,232 @@
+#include "ohmediarecorder.h"
+#include "qopenharmony.h"
+
+#include <QDebug>
+#include <QJsObject>
+#include <private/qopenharmony_p.h>
+#include <private/qjspromise_p.h>
+#include "private/qjspromise_p.h"
+
+OhMediaRecorder::OhMediaRecorder()
+    :QJsModule("@ohos.multimedia.media"),
+      m_audioBitrate(48000),
+      m_audioChannel(2),
+      m_audioCodeC(AAC),
+      m_audioSampleRate(48000),
+      m_videoBitrate(200000),
+      m_videoCodec(AVC),
+      m_videoFrameSize(640, 480),
+      m_videoFrameRate(30)
+{
+    m_mediaRecorder = QtOh::runOnJsUIThreadWithPromise<QJsObject *>([this](auto p){
+        QJsPromise promise(call("createAVRecorder").As<Napi::Promise>());
+        promise.onThen([p](const Napi::CallbackInfo &info){
+            if (info.Length() < 1) {
+                p->set_value(nullptr);
+                return ;
+            }
+
+            Napi::Object recorder = info[0].As<Napi::Object>();
+            p->set_value(new QJsObject(recorder));
+        });
+    });
+}
+
+OhMediaRecorder::~OhMediaRecorder()
+{
+    if(m_mediaRecorder){
+        delete m_mediaRecorder;
+        m_mediaRecorder = nullptr;
+    }
+}
+
+void OhMediaRecorder::release()
+{
+    QtOh::runOnJsUIThreadAndWait([this]{
+        if(m_mediaRecorder)
+            m_mediaRecorder->call("release");
+    });
+}
+
+QString OhMediaRecorder::prepare()
+{
+    if(!m_mediaRecorder)
+        return QString();
+
+    return QtOh::runOnJsUIThreadWithPromise<QString>([this] (auto p){
+        Napi::Object AVRecorderProfile = Napi::Object::New(m_mediaRecorder->env());
+        AVRecorderProfile.Set("audioBitrate", m_audioBitrate);
+        AVRecorderProfile.Set("audioChannels", m_audioChannel);
+
+        QJsModule fileInfo("@ohos.file.fs");
+        QJsObject jsFile = QJsObject(fileInfo.call("openSync", { Napi::String::New(fileInfo.env(), m_outputFile.toStdString()),\
+                                                                  Napi::Number::New(fileInfo.env(), 02 | 0100)}).As<Napi::Object>());
+        if (jsFile.object().IsNull() || jsFile.object().IsEmpty()){
+            qDebug() << "openSync fialed:" << jsFile.lastError();
+            p->set_value(QString());
+        }
+
+        int fd = jsFile.get("fd").ToNumber();
+        QString fdStr = QString("fd://%1").arg(fd);
+
+        //TODO 无法构造ts枚举对象,暂时直接使用枚举值
+        switch(m_audioCodeC) {
+        case AAC:
+            AVRecorderProfile.Set("audioCodec", "audio/mp4a-latm");
+        case VORBIS:
+            AVRecorderProfile.Set("audioCodec", "audio/vorbis");
+        case FLAC:
+            AVRecorderProfile.Set("audioCodec", "audio/flac");
+        case MP3:
+            AVRecorderProfile.Set("audioCodec", "audio/mpeg");
+        default:
+            AVRecorderProfile.Set("audioCodec", "audio/mp4a-latm");
+        }
+        AVRecorderProfile.Set("audioSampleRate", m_audioSampleRate);
+
+        AVRecorderProfile.Set("fileFormat", "mp4");
+
+        AVRecorderProfile.Set("videoBitrate", m_videoBitrate);
+        switch(m_videoCodec) {
+        case H263:
+            AVRecorderProfile.Set("videoCodec", "video/h263");
+        case AVC:
+            AVRecorderProfile.Set("videoCodec", "video/avc");
+        case MPEG_2:
+            AVRecorderProfile.Set("videoCodec", "video/mpeg2");
+        case MPEG_4:
+            AVRecorderProfile.Set("videoCodec", "video/mp4v-es");
+        case VP8:
+            AVRecorderProfile.Set("videoCodec", "video/x-vnd.on2.vp8");
+        default:
+            AVRecorderProfile.Set("videoCodec", "video/avc");
+        }
+        AVRecorderProfile.Set("videoFrameWidth", m_videoFrameSize.width());
+        AVRecorderProfile.Set("videoFrameHeight", m_videoFrameSize.height());
+        AVRecorderProfile.Set("videoFrameRate", m_videoFrameRate);
+
+        Napi::Object avRecorderConfig = Napi::Object::New(m_mediaRecorder->env());
+        avRecorderConfig.Set("audioSourceType", 1);
+        avRecorderConfig.Set("videoSourceType", 0);
+        avRecorderConfig.Set("profile", AVRecorderProfile);
+        avRecorderConfig.Set("url", fdStr.toStdString());
+        avRecorderConfig.Set("rotation", 0);
+
+        Napi::Object location = Napi::Object::New(m_mediaRecorder->env());
+        location.Set("latitude", 30);
+        location.Set("longitude", 130);
+        avRecorderConfig.Set("location", location);
+
+        m_mediaRecorder->call("prepare", { avRecorderConfig });
+        if(m_mediaRecorder->hasError()){
+            qDebug() << "prepare falied:" << m_mediaRecorder->lastError();
+            p->set_value(QString());
+        }
+
+        QString ret;
+        Napi::Value value = m_mediaRecorder->call("getInputSurface");
+
+        if (value.IsPromise()) {
+            QJsPromise promise(value.As<Napi::Promise>());
+            promise.onThen([&](const Napi::CallbackInfo &info){
+                if (info.Length() < 1)
+                {
+                    p->set_value(QString());
+                    return;
+                }
+
+                ret = QString::fromStdString(info[0].As<Napi::String>());
+                p->set_value(ret);
+            });
+        }
+        else
+            p->set_value(QString());
+    });
+}
+
+void OhMediaRecorder::reset()
+{
+    QtOh::runOnJsUIThreadAndWait([this] {
+        if(m_mediaRecorder)
+            m_mediaRecorder->call("reset");
+    });
+}
+
+void OhMediaRecorder::pause()
+{
+    QtOh::runOnJsUIThreadAndWait([this] {
+        if(m_mediaRecorder)
+            m_mediaRecorder->call("pause");
+    });
+}
+
+void OhMediaRecorder::resume()
+{
+    QtOh::runOnJsUIThreadAndWait([this] {
+        if(m_mediaRecorder)
+            m_mediaRecorder->call("resume");
+    });
+}
+
+bool OhMediaRecorder::start()
+{
+    return QtOh::runOnJsUIThreadWithResult([this] () -> bool{
+        if(m_mediaRecorder)
+            return m_mediaRecorder->call("start").ToBoolean();
+
+        return false;
+    });
+}
+
+void OhMediaRecorder::stop()
+{
+    QtOh::runOnJsUIThreadAndWait([this] {
+        if(m_mediaRecorder)
+            m_mediaRecorder->call("stop");
+    });
+}
+
+void OhMediaRecorder::setAudioChannels(int numChannels)
+{
+    m_audioChannel = qBound(1, numChannels, 8);
+}
+
+void OhMediaRecorder::setAudioEncoder(AudioEncoder encoder)
+{
+    m_audioCodeC = encoder;
+}
+
+void OhMediaRecorder::setAudioEncodingBitRate(int bitRate)
+{
+    m_audioBitrate = bitRate;
+}
+
+void OhMediaRecorder::setAudioSamplingRate(int samplingRate)
+{
+    m_audioSampleRate = samplingRate;
+}
+
+void OhMediaRecorder::setVideoBitrate(int bitrate)
+{
+    m_videoBitrate = bitrate;
+}
+
+void OhMediaRecorder::setVideoEncoder(VideoEncoder encoder)
+{
+    m_videoCodec = encoder;
+}
+
+void OhMediaRecorder::setvideoFramSize(const QSize &size)
+{
+    m_videoFrameSize = size;
+}
+
+void OhMediaRecorder::setvideoFrameRate(int frameRate)
+{
+    m_videoFrameRate = frameRate;
+}
+
+void OhMediaRecorder::setOutputFile(const QString &path)
+{
+    m_outputFile = path;
+}
diff --git a/src/plugins/openharmony/src/wrappers/napi/ohmediarecorder.h b/src/plugins/openharmony/src/wrappers/napi/ohmediarecorder.h
new file mode 100644
index 000000000..8cdf0679e
--- /dev/null
+++ b/src/plugins/openharmony/src/wrappers/napi/ohmediarecorder.h
@@ -0,0 +1,88 @@
+#ifndef OHMEDIARECORDER_H
+#define OHMEDIARECORDER_H
+
+#include "qobject.h"
+#include <QSize>
+#include <QJsModule>
+
+QT_BEGIN_NAMESPACE
+
+class OhMediaRecorder :public QObject, public QJsModule
+{
+    Q_OBJECT
+public:
+    enum AudioEncoder {
+        AAC = 0,
+        VORBIS = 1,
+        FLAC = 2,
+        MP3 = 3,
+        G711MU = 4
+    };
+
+    enum VideoEncoder {        
+        H263 = 0,
+        AVC = 1,
+        MPEG_2 = 2,
+        MPEG_4 = 3,
+        VP8 = 4
+    };
+
+    enum VideoSource {
+        YUV = 0,
+        ES = 1
+    };
+
+    enum OutputFormat {
+        CFT_MPEG_4 = 0,
+        CFT_MPEG_4A = 1,
+    };
+
+    OhMediaRecorder();
+    ~OhMediaRecorder();
+
+    void release();
+    QString prepare();
+    void reset();
+    void pause();
+    void resume();
+
+    bool start();
+    void stop();
+
+    void setAudioChannels(int numChannels);
+    void setAudioEncoder(AudioEncoder encoder);
+    void setAudioEncodingBitRate(int bitRate);
+    void setAudioSamplingRate(int samplingRate);
+
+    void setVideoBitrate(int bitrate);
+    void setVideoEncoder(VideoEncoder encoder);
+    void setvideoFramSize(const QSize &size);
+    void setvideoFrameRate(int frameRate);
+
+    void setOutputFile(const QString &path);
+
+Q_SIGNALS:
+    void error(int what, int extra);
+    void info(int what, int extra);
+
+private:
+    qptrdiff m_id;
+    QJsObject *m_mediaRecorder = nullptr;
+
+    //audio
+    int m_audioBitrate;
+    int m_audioChannel;
+    AudioEncoder m_audioCodeC;
+    int m_audioSampleRate;
+
+    //video
+    int m_videoBitrate;
+    VideoEncoder m_videoCodec;
+    QSize m_videoFrameSize;
+    int m_videoFrameRate;
+
+    QString m_outputFile;
+};
+
+QT_END_NAMESPACE
+#endif // OHMEDIARECORDER_H
diff --git a/src/plugins/openharmony/src/wrappers/napi/ohmultimediautils.cpp b/src/plugins/openharmony/src/wrappers/napi/ohmultimediautils.cpp
new file mode 100644
index 000000000..1747c2cc9
--- /dev/null
+++ b/src/plugins/openharmony/src/wrappers/napi/ohmultimediautils.cpp
@@ -0,0 +1,96 @@
+#include <qstring.h>
+#include "ohmultimediautils.h"
+
+QT_BEGIN_NAMESPACE
+
+int qt_findClosestValue(const QList<int> &list, int value)
+{
+    if (list.size() < 2)
+        return 0;
+
+    int begin = 0;
+    int end = list.size() - 1;
+    int pivot = begin + (end - begin) / 2;
+    int v = list.at(pivot);
+
+    while (end - begin > 1) {
+        if (value == v)
+            return pivot;
+
+        if (value > v)
+            begin = pivot;
+        else
+            end = pivot;
+
+        pivot = begin + (end - begin) / 2;
+        v = list.at(pivot);
+    }
+
+    return value - v >= list.at(pivot + 1) - value ? pivot + 1 : pivot;
+}
+
+bool qt_sizeLessThan(const QSize &s1, const QSize &s2)
+{
+    return s1.width() * s1.height() < s2.width() * s2.height();
+}
+
+class QtMultimediaUtils
+{
+    // QSharedPointer<QOpenHarmonyJsObject> m_jsUtils;
+
+public:
+    QtMultimediaUtils();
+    QString getDefaultMediaDirectory(OhMultimediaUtils::MediaType type);
+
+    bool requestPermission();
+};
+
+QtMultimediaUtils::QtMultimediaUtils()
+{
+    // m_jsUtils = qJsObjectLoader->create("JsMultimediaUtils");
+}
+
+QString QtMultimediaUtils::getDefaultMediaDirectory(OhMultimediaUtils::MediaType type)
+{
+    return QString();
+//    QString dir = m_jsUtils->call<QString>("getMediaDirectory", type);
+//    return std::move(dir);
+}
+
+bool QtMultimediaUtils::requestPermission()
+{
+    return true;
+    // return m_jsUtils->call<bool>("requestPermission", (int)OhMultimediaUtils::PerCamera);
+}
+
+Q_GLOBAL_STATIC(QtMultimediaUtils, gsUtils)
+int OhMultimediaUtils::getDeviceOrientation()
+{
+    //TODO
+    return 0;
+}
+
+void OhMultimediaUtils::enableOrientationListener(bool enable)
+{
+    //TODO
+    Q_UNUSED(enable);
+}
+
+void OhMultimediaUtils::registerMediaFile(const QString &file)
+{
+    //TODO
+    Q_UNUSED(file);
+}
+
+QString OhMultimediaUtils::getDefaultMediaDirectory(MediaType type)
+{
+    const QString &dir = gsUtils->getDefaultMediaDirectory(type);
+    return std::move(dir);
+}
+
+bool OhMultimediaUtils::qt_openharmonyRequestPermission()
+{
+    return gsUtils->requestPermission();
+}
+
+QT_END_NAMESPACE
diff --git a/src/plugins/openharmony/src/wrappers/napi/ohmultimediautils.h b/src/plugins/openharmony/src/wrappers/napi/ohmultimediautils.h
new file mode 100644
index 000000000..201ce7bf0
--- /dev/null
+++ b/src/plugins/openharmony/src/wrappers/napi/ohmultimediautils.h
@@ -0,0 +1,43 @@
+#ifndef OHMULTIMEDIAUTILS_H
+#define OHMULTIMEDIAUTILS_H
+
+#include <qobject.h>
+#include <qsize.h>
+
+QT_BEGIN_NAMESPACE
+
+int qt_findClosestValue(const QList<int> &list, int value);
+
+bool qt_sizeLessThan(const QSize &s1, const QSize &s2);
+
+inline uint qHash(const QSize& size, uint seed = 0) {
+    return qHash(size.width(), seed) ^ qHash(size.height(), seed << 1);
+}
+
+class OhMultimediaUtils
+{
+public:
+    enum MediaType {
+        Camera = 0,
+        Video = 1,
+        Image = 2,
+        Audio = 3,
+        Documents = 4,
+        Download = 5
+    };
+
+    enum Permissions{
+        PerCameraAndMicroPhone = 0,
+        PerCamera = 1,
+        PerMicroPhone = 2
+    };
+
+    static int getDeviceOrientation();
+    static void enableOrientationListener(bool enable);
+    static void registerMediaFile(const QString &file);
+    static QString getDefaultMediaDirectory(MediaType type);
+    static bool qt_openharmonyRequestPermission();
+};
+
+QT_END_NAMESPACE
+#endif // OHMULTIMEDIAUTILS_H
diff --git a/src/plugins/openharmony/videonode/openharmony_videonode.json b/src/plugins/openharmony/videonode/openharmony_videonode.json
new file mode 100644
index 000000000..c82757cb0
--- /dev/null
+++ b/src/plugins/openharmony/videonode/openharmony_videonode.json
@@ -0,0 +1,3 @@
+{
+    "Keys": ["openharmony"]
+}
diff --git a/src/plugins/openharmony/videonode/qopenharmonysgvideonode.cpp b/src/plugins/openharmony/videonode/qopenharmonysgvideonode.cpp
new file mode 100644
index 000000000..e329ae8ee
--- /dev/null
+++ b/src/plugins/openharmony/videonode/qopenharmonysgvideonode.cpp
@@ -0,0 +1,212 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qopenharmonysgvideonode.h"
+
+#include <qsgmaterial.h>
+#include <qmutex.h>
+
+QT_BEGIN_NAMESPACE
+
+class QOPenHarmonySGVideoNodeMaterialShader : public QSGMaterialShader
+{
+public:
+    void updateState(const RenderState &state, QSGMaterial *newMaterial, QSGMaterial *oldMaterial);
+
+    char const *const *attributeNames() const {
+        static const char *names[] = {
+            "qt_VertexPosition",
+            "qt_VertexTexCoord",
+            0
+        };
+        return names;
+    }
+
+protected:
+
+    const char *vertexShader() const {
+        const char *shader =
+        "uniform highp mat4 qt_Matrix;                      \n"
+        "attribute highp vec4 qt_VertexPosition;            \n"
+        "attribute highp vec2 qt_VertexTexCoord;            \n"
+        "varying highp vec2 qt_TexCoord;                    \n"
+        "void main() {                                      \n"
+        "    qt_TexCoord = qt_VertexTexCoord;               \n"
+        "    gl_Position = qt_Matrix * qt_VertexPosition;   \n"
+        "}";
+        return shader;
+    }
+
+    const char *fragmentShader() const {
+        static const char *shader =
+        "uniform sampler2D rgbTexture;"
+        "uniform lowp float opacity;"
+        ""
+        "varying highp vec2 qt_TexCoord;"
+        ""
+        "void main()"
+        "{"
+        "    gl_FragColor = texture2D(rgbTexture, qt_TexCoord) * opacity;"
+        "}";
+        return shader;
+    }
+
+    void initialize() {
+        m_id_matrix = program()->uniformLocation("qt_Matrix");
+        m_id_Texture = program()->uniformLocation("rgbTexture");
+        m_id_opacity = program()->uniformLocation("opacity");
+    }
+
+    int m_id_matrix;
+    int m_id_Texture;
+    int m_id_opacity;
+};
+
+class QOPenHarmonySGVideoNodeMaterial : public QSGMaterial
+{
+public:
+    QOPenHarmonySGVideoNodeMaterial()
+        : m_textureId(0)
+        , m_textureUpdated(false)
+        , m_opacity(1.0)
+    {
+        setFlag(Blending, false);
+    }
+
+    QSGMaterialType *type() const {
+        static QSGMaterialType theType;
+        return &theType;
+    }
+
+    QSGMaterialShader *createShader() const {
+        return new QOPenHarmonySGVideoNodeMaterialShader;
+    }
+
+    int compare(const QSGMaterial *other) const {
+        const QOPenHarmonySGVideoNodeMaterial *m = static_cast<const QOPenHarmonySGVideoNodeMaterial *>(other);
+        int diff = m_textureId - m->m_textureId;
+        if (diff)
+            return diff;
+
+        return (m_opacity > m->m_opacity) ? 1 : -1;
+    }
+
+    void updateBlending() {
+        setFlag(Blending, qFuzzyCompare(m_opacity, qreal(1.0)) ? false : true);
+    }
+
+    void updateTexture(GLuint id, const QSize &size) {
+        if (m_textureId != id || m_textureSize != size) {
+            m_textureId = id;
+            m_textureSize = size;
+            m_textureUpdated = true;
+        }
+    }
+
+    void bind()
+    {
+        glBindTexture(GL_TEXTURE_2D, m_textureId);
+        if (m_textureUpdated) {
+            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+            m_textureUpdated = false;
+        }
+    }
+
+    QSize m_textureSize;
+    GLuint m_textureId;
+    bool m_textureUpdated;
+    qreal m_opacity;
+};
+
+
+QOPenHarmonySGVideoNode::QOPenHarmonySGVideoNode(const QVideoSurfaceFormat &format)
+    : m_format(format)
+{
+    setFlags(OwnsMaterial | UsePreprocess);
+    m_material = new QOPenHarmonySGVideoNodeMaterial;
+    setMaterial(m_material);
+}
+
+QOPenHarmonySGVideoNode::~QOPenHarmonySGVideoNode()
+{
+    m_frame = QVideoFrame();
+}
+
+void QOPenHarmonySGVideoNode::setCurrentFrame(const QVideoFrame &frame, FrameFlags)
+{
+    QMutexLocker lock(&m_frameMutex);
+    m_frame = frame;
+    markDirty(DirtyMaterial);
+}
+
+void QOPenHarmonySGVideoNodeMaterialShader::updateState(const RenderState &state,
+                                                    QSGMaterial *newMaterial,
+                                                    QSGMaterial *oldMaterial)
+{
+    Q_UNUSED(oldMaterial);
+    QOPenHarmonySGVideoNodeMaterial *mat = static_cast<QOPenHarmonySGVideoNodeMaterial *>(newMaterial);
+    program()->setUniformValue(m_id_Texture, 0);
+
+    mat->bind();
+
+    if (state.isOpacityDirty()) {
+        mat->m_opacity = state.opacity();
+        mat->updateBlending();
+        program()->setUniformValue(m_id_opacity, GLfloat(mat->m_opacity));
+    }
+
+    if (state.isMatrixDirty())
+        program()->setUniformValue(m_id_matrix, state.combinedMatrix());
+}
+
+void QOPenHarmonySGVideoNode::preprocess()
+{
+    QMutexLocker lock(&m_frameMutex);
+
+    GLuint texId = 0;
+    if (m_frame.isValid())
+        texId = m_frame.handle().toUInt();
+
+    m_material->updateTexture(texId, m_frame.size());
+}
+
+QT_END_NAMESPACE
diff --git a/src/plugins/openharmony/videonode/qopenharmonysgvideonode.h b/src/plugins/openharmony/videonode/qopenharmonysgvideonode.h
new file mode 100644
index 000000000..fa731c5af
--- /dev/null
+++ b/src/plugins/openharmony/videonode/qopenharmonysgvideonode.h
@@ -0,0 +1,71 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QOPENHARMONYSGVIDEONODE_H
+#define QOPENHARMONYSGVIDEONODE_H
+
+#include <private/qsgvideonode_p.h>
+#include <qmutex.h>
+
+QT_BEGIN_NAMESPACE
+
+class QOPenHarmonySGVideoNodeMaterial;
+
+class QOPenHarmonySGVideoNode : public QSGVideoNode
+{
+public:
+    QOPenHarmonySGVideoNode(const QVideoSurfaceFormat &format);
+    ~QOPenHarmonySGVideoNode();
+
+    void setCurrentFrame(const QVideoFrame &frame, FrameFlags flags);
+    QVideoFrame::PixelFormat pixelFormat() const { return m_format.pixelFormat(); }
+    QAbstractVideoBuffer::HandleType handleType() const { return QAbstractVideoBuffer::GLTextureHandle; }
+
+    void preprocess();
+
+private:
+    QOPenHarmonySGVideoNodeMaterial *m_material;
+    QMutex m_frameMutex;
+    QVideoFrame m_frame;
+    QVideoSurfaceFormat m_format;
+};
+
+QT_END_NAMESPACE
+
+#endif // QOPENHARMONYSGVIDEONODE_H
diff --git a/src/plugins/openharmony/videonode/qopenharmonysgvideonodeplugin.cpp b/src/plugins/openharmony/videonode/qopenharmonysgvideonodeplugin.cpp
new file mode 100644
index 000000000..ae79b8627
--- /dev/null
+++ b/src/plugins/openharmony/videonode/qopenharmonysgvideonodeplugin.cpp
@@ -0,0 +1,65 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qopenharmonysgvideonodeplugin.h"
+#include "qopenharmonysgvideonode.h"
+
+QT_BEGIN_NAMESPACE
+
+QList<QVideoFrame::PixelFormat> QOPenHarmonySGVideoNodeFactoryPlugin::supportedPixelFormats(
+        QAbstractVideoBuffer::HandleType handleType) const
+{
+    QList<QVideoFrame::PixelFormat> pixelFormats;
+
+    if (handleType == QAbstractVideoBuffer::GLTextureHandle)
+        pixelFormats.append(QVideoFrame::Format_BGR32);
+
+    return pixelFormats;
+}
+
+QSGVideoNode *QOPenHarmonySGVideoNodeFactoryPlugin::createNode(const QVideoSurfaceFormat &format)
+{
+    if (supportedPixelFormats(format.handleType()).contains(format.pixelFormat()))
+        return new QOPenHarmonySGVideoNode(format);
+
+    return 0;
+}
+
+
+QT_END_NAMESPACE
diff --git a/src/plugins/openharmony/videonode/qopenharmonysgvideonodeplugin.h b/src/plugins/openharmony/videonode/qopenharmonysgvideonodeplugin.h
new file mode 100644
index 000000000..d2cc4359f
--- /dev/null
+++ b/src/plugins/openharmony/videonode/qopenharmonysgvideonodeplugin.h
@@ -0,0 +1,60 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QOPENHARMONYSGVIDEONODEPLUGIN_H
+#define QOPENHARMONYSGVIDEONODEPLUGIN_H
+
+#include <private/qsgvideonode_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QOPenHarmonySGVideoNodeFactoryPlugin : public QSGVideoNodeFactoryPlugin
+{
+    Q_OBJECT
+    Q_PLUGIN_METADATA(IID QSGVideoNodeFactoryInterface_iid
+                      FILE "openharmony_videonode.json")
+
+public:
+    QList<QVideoFrame::PixelFormat> supportedPixelFormats(QAbstractVideoBuffer::HandleType handleType) const;
+    QSGVideoNode *createNode(const QVideoSurfaceFormat &format);
+};
+
+QT_END_NAMESPACE
+
+#endif // QOPENHARMONYSGVIDEONODEPLUGIN_H
diff --git a/src/plugins/openharmony/videonode/videonode.pro b/src/plugins/openharmony/videonode/videonode.pro
new file mode 100644
index 000000000..e4aa287f2
--- /dev/null
+++ b/src/plugins/openharmony/videonode/videonode.pro
@@ -0,0 +1,18 @@
+TARGET = qtsgvideonode_openharmony
+
+QT += quick multimedia-private qtmultimediaquicktools-private
+
+HEADERS += \
+    qopenharmonysgvideonode.h \
+    qopenharmonysgvideonodeplugin.h
+
+SOURCES += \
+    qopenharmonysgvideonode.cpp \
+    qopenharmonysgvideonodeplugin.cpp
+
+OTHER_FILES += openharmony_videonode.json
+
+PLUGIN_TYPE = video/videonode
+PLUGIN_EXTENDS = quick
+PLUGIN_CLASS_NAME = QOPenharmonySGVideoNodeFactoryPlugin
+load(qt_plugin)
diff --git a/src/plugins/opensles/opensles.pro b/src/plugins/opensles/opensles.pro
index 2bb0f3cf5..de0d39ea6 100644
--- a/src/plugins/opensles/opensles.pro
+++ b/src/plugins/opensles/opensles.pro
@@ -1,13 +1,11 @@
 TARGET = qtaudio_opensles
 QT += multimedia-private core-private
 
-LIBS += -lOpenSLES
-
 HEADERS += \
     qopenslesplugin.h \
     qopenslesengine.h \
     qopenslesdeviceinfo.h \
-    qopenslesaudioinput.h \
+    qopenslesaudioinput.h\
     qopenslesaudiooutput.h
 
 SOURCES += \
@@ -17,6 +15,8 @@ SOURCES += \
     qopenslesaudioinput.cpp \
     qopenslesaudiooutput.cpp
 
+LIBS += -lOpenSLES
+
 OTHER_FILES += \
     opensles.json
 
diff --git a/src/plugins/opensles/qopenslesaudioinput.cpp b/src/plugins/opensles/qopenslesaudioinput.cpp
index 54ed18ac1..0c4efb714 100644
--- a/src/plugins/opensles/qopenslesaudioinput.cpp
+++ b/src/plugins/opensles/qopenslesaudioinput.cpp
@@ -84,13 +84,17 @@ static bool hasRecordingPermission()
 }
 
 static void bufferQueueCallback(SLAndroidSimpleBufferQueueItf, void *context)
+{
+    // Process buffer in main thread
+    QMetaObject::invokeMethod(reinterpret_cast<QOpenSLESAudioInput*>(context), "processBuffer");
+}
 #else
 static void bufferQueueCallback(SLBufferQueueItf, void *context)
-#endif
 {
     // Process buffer in main thread
     QMetaObject::invokeMethod(reinterpret_cast<QOpenSLESAudioInput*>(context), "processBuffer");
 }
+#endif
 
 QOpenSLESAudioInput::QOpenSLESAudioInput(const QByteArray &device)
     : m_device(device)
@@ -209,8 +213,10 @@ QIODevice *QOpenSLESAudioInput::start()
 
 bool QOpenSLESAudioInput::startRecording()
 {
+#ifdef ANDROID
     if (!hasRecordingPermission())
         return false;
+#endif
 
     m_processedBytes = 0;
     m_clockStamp.restart();
diff --git a/src/plugins/opensles/qopenslesaudiooutput.cpp b/src/plugins/opensles/qopenslesaudiooutput.cpp
index 381ce0ec2..93716e1c9 100644
--- a/src/plugins/opensles/qopenslesaudiooutput.cpp
+++ b/src/plugins/opensles/qopenslesaudiooutput.cpp
@@ -360,8 +360,11 @@ void QOpenSLESAudioOutput::onEOSEvent()
 {
     if (m_state != QAudio::ActiveState)
         return;
-
+#if defined(Q_OS_OPENHARMONY)
+    SLOHBufferQueueState state;
+#else
     SLBufferQueueState state;
+#endif
     if (SL_RESULT_SUCCESS != (*m_bufferQueueItf)->GetState(m_bufferQueueItf, &state))
         return;
 
@@ -426,7 +429,15 @@ void QOpenSLESAudioOutput::playCallback(SLPlayItf player, void *ctx, SLuint32 ev
         Q_EMIT audioOutput->notify();
 
 }
-
+#if defined(Q_OS_OPENHARMONY)
+void QOpenSLESAudioOutput::bufferQueueCallback (SLOHBufferQueueItf bufferQueue, void *ctx, SLuint32 size)
+{
+    SLOHBufferQueueState state;
+    (*bufferQueue)->GetState(bufferQueue, &state);
+    QOpenSLESAudioOutput *audioOutput = reinterpret_cast<QOpenSLESAudioOutput *>(ctx);
+    audioOutput->bufferAvailable(state.count, state.index);
+}
+#else
 void QOpenSLESAudioOutput::bufferQueueCallback(SLBufferQueueItf bufferQueue, void *ctx)
 {
     SLBufferQueueState state;
@@ -434,7 +445,7 @@ void QOpenSLESAudioOutput::bufferQueueCallback(SLBufferQueueItf bufferQueue, voi
     QOpenSLESAudioOutput *audioOutput = reinterpret_cast<QOpenSLESAudioOutput *>(ctx);
     audioOutput->bufferAvailable(state.count, state.playIndex);
 }
-
+#endif
 bool QOpenSLESAudioOutput::preparePlayer()
 {
     if (m_startRequiresInit)
@@ -476,7 +487,11 @@ bool QOpenSLESAudioOutput::preparePlayer()
 
 #ifndef ANDROID
     const int iids = 2;
+#if defined(Q_OS_OPENHARMONY)
+    const SLInterfaceID ids[iids] = { SL_IID_OH_BUFFERQUEUE, SL_IID_VOLUME };
+#else
     const SLInterfaceID ids[iids] = { SL_IID_BUFFERQUEUE, SL_IID_VOLUME };
+#endif
     const SLboolean req[iids] = { SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE };
 #else
     const int iids = 3;
@@ -490,10 +505,18 @@ bool QOpenSLESAudioOutput::preparePlayer()
     if (SL_RESULT_SUCCESS != (*engine)->CreateAudioPlayer(engine,
                                                           &m_playerObject,
                                                           &audioSrc,
+#if defined(Q_OS_OPENHARMONY)
+                                                          nullptr,
+                                                          0,
+                                                          nullptr,
+                                                          nullptr
+#else
                                                           &audioSink,
                                                           iids,
                                                           ids,
-                                                          req)) {
+                                                          req
+#endif
+                                                          )) {
         qWarning() << "Unable to create AudioPlayer";
         setError(QAudio::OpenError);
         return false;
@@ -520,7 +543,11 @@ bool QOpenSLESAudioOutput::preparePlayer()
 
     // Buffer interface
     if (SL_RESULT_SUCCESS != (*m_playerObject)->GetInterface(m_playerObject,
+#if defined(Q_OS_OPENHARMONY)
+                                                             SL_IID_OH_BUFFERQUEUE,
+#else
                                                              SL_IID_BUFFERQUEUE,
+#endif
                                                              &m_bufferQueueItf)) {
         setError(QAudio::FatalError);
         return false;
@@ -540,7 +567,8 @@ bool QOpenSLESAudioOutput::preparePlayer()
         setError(QAudio::FatalError);
         return false;
     }
-
+#ifndef Q_OS_OPENHARMONY
+    /* TODO for openharmony*/
     if (SL_RESULT_SUCCESS != (*m_playItf)->RegisterCallback(m_playItf, playCallback, this)) {
         setError(QAudio::FatalError);
         return false;
@@ -555,7 +583,7 @@ bool QOpenSLESAudioOutput::preparePlayer()
         setError(QAudio::FatalError);
         return false;
     }
-
+#endif
     // Volume interface
     if (SL_RESULT_SUCCESS != (*m_playerObject)->GetInterface(m_playerObject,
                                                              SL_IID_VOLUME,
diff --git a/src/plugins/opensles/qopenslesaudiooutput.h b/src/plugins/opensles/qopenslesaudiooutput.h
index b480f00e6..342423d40 100644
--- a/src/plugins/opensles/qopenslesaudiooutput.h
+++ b/src/plugins/opensles/qopenslesaudiooutput.h
@@ -47,6 +47,11 @@
 #include <QTime>
 #include <QIODevice>
 
+#if defined(Q_OS_OPENHARMONY)
+#include <SLES/OpenSLES_OpenHarmony.h>
+#include <SLES/OpenSLES_Platform.h>
+#endif
+
 QT_BEGIN_NAMESPACE
 
 class QOpenSLESAudioOutput : public QAbstractAudioOutput
@@ -90,8 +95,11 @@ private:
     void bufferAvailable(quint32 count, quint32 playIndex);
 
     static void playCallback(SLPlayItf playItf, void *ctx, SLuint32 event);
+#if defined(Q_OS_OPENHARMONY)
+    static void bufferQueueCallback(SLOHBufferQueueItf bufferQueue, void *ctx, SLuint32 size);
+#else
     static void bufferQueueCallback(SLBufferQueueItf bufferQueue, void *ctx);
-
+#endif
     bool preparePlayer();
     void destroyPlayer();
     void stopPlayer();
@@ -110,7 +118,11 @@ private:
     SLObjectItf m_playerObject;
     SLPlayItf m_playItf;
     SLVolumeItf m_volumeItf;
+#if defined(Q_OS_OPENHARMONY)
+    SLOHBufferQueueItf m_bufferQueueItf;
+#else
     SLBufferQueueItf m_bufferQueueItf;
+#endif
     QIODevice *m_audioSource;
     char *m_buffers;
     qreal m_volume;
diff --git a/src/plugins/opensles/qopenslesengine.cpp b/src/plugins/opensles/qopenslesengine.cpp
index 36025dcfd..40269e583 100644
--- a/src/plugins/opensles/qopenslesengine.cpp
+++ b/src/plugins/opensles/qopenslesengine.cpp
@@ -38,7 +38,6 @@
 ****************************************************************************/
 
 #include "qopenslesengine.h"
-
 #include "qopenslesaudioinput.h"
 #include <qdebug.h>
 
@@ -122,6 +121,7 @@ QList<QByteArray> QOpenSLESEngine::availableDevices(QAudio::Mode mode) const
     } else {
         devices << "default";
     }
+
     return devices;
 }
 
diff --git a/src/plugins/opensles/qopenslesplugin.cpp b/src/plugins/opensles/qopenslesplugin.cpp
index 9a2fbbf79..5bd58b324 100644
--- a/src/plugins/opensles/qopenslesplugin.cpp
+++ b/src/plugins/opensles/qopenslesplugin.cpp
@@ -1,4 +1,4 @@
-/****************************************************************************
+/****************************************************************************
 **
 ** Copyright (C) 2016 The Qt Company Ltd.
 ** Contact: https://www.qt.io/licensing/
@@ -42,6 +42,7 @@
 #include "qopenslesengine.h"
 #include "qopenslesdeviceinfo.h"
 #include "qopenslesaudioinput.h"
+
 #include "qopenslesaudiooutput.h"
 
 QT_BEGIN_NAMESPACE
diff --git a/src/plugins/plugins.pro b/src/plugins/plugins.pro
index 95c004125..08c0b9ab4 100644
--- a/src/plugins/plugins.pro
+++ b/src/plugins/plugins.pro
@@ -17,6 +17,10 @@ android {
    SUBDIRS += android opensles
 }
 
+openharmony {
+    SUBDIRS += openharmony ohaudiodevice
+}
+
 qnx {
     qtConfig(mmrenderer): SUBDIRS += qnx
     SUBDIRS += audiocapture
diff --git a/src/plugins/videonode/egl/qsgvideonode_egl.cpp b/src/plugins/videonode/egl/qsgvideonode_egl.cpp
index c3694f533..d87cbe837 100644
--- a/src/plugins/videonode/egl/qsgvideonode_egl.cpp
+++ b/src/plugins/videonode/egl/qsgvideonode_egl.cpp
@@ -41,7 +41,11 @@
 
 #include <QtMultimedia/qvideosurfaceformat.h>
 
+#ifdef Q_OS_OPENHARMONY
+#include <EGL/eglext.h>
+#else
 #include <GLES2/gl2ext.h>
+#endif
 
 QT_BEGIN_NAMESPACE
 
diff --git a/src/src.pro b/src/src.pro
index 1dc1015c6..686dd74d8 100644
--- a/src/src.pro
+++ b/src/src.pro
@@ -1,6 +1,7 @@
 TEMPLATE = subdirs
 
 SUBDIRS += multimedia
+#SUBDIRS += openharmony
 
 include($$OUT_PWD/multimedia/qtmultimedia-config.pri)
 QT_FOR_CONFIG += multimedia-private