| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681 |
- #include "recorderwidget.h"
- #include <QApplication>
- #include <QDateTime>
- #include <QDebug>
- #include <QMessageBox>
- #include <QFileDialog>
- #include <QStandardPaths>
- #include <QOpenGLFunctions>
- #include <QPainter>
- #include "../config/networkconfig.h"
- // 静态实例指针
- RecorderWidget* RecorderWidget::s_instance = nullptr;
- RecorderWidget::RecorderWidget(QWidget *parent)
- : QWidget(parent)
- , m_mainLayout(nullptr)
- , m_previewWidget(nullptr)
- , m_encoderComboBox(nullptr)
- , m_micComboBox(nullptr)
- , m_speakerComboBox(nullptr)
- , m_statusBar(nullptr)
- , m_statusLabel(nullptr)
- , m_timeLabel(nullptr)
- , m_encoderLabel(nullptr)
- , m_previewTimer(nullptr)
- , m_statusTimer(nullptr)
- , m_micDevices(nullptr)
- , m_speakerDevices(nullptr)
- , m_encoders(nullptr)
- , m_micCount(0)
- , m_speakerCount(0)
- , m_encoderCount(0)
- , m_isRecording(false)
- , m_isStreaming(false)
- , m_isInitialized(false)
- , m_previewWidth(0)
- , m_previewHeight(0)
- {
- // 设置静态实例指针
- s_instance = this;
- // rtmp://106.55.186.74:1935/stream/V1/0198da41-cdb6-78e3-879d-2ea32d58f73f
- // 设置初始大小,与AVPlayerWidget保持一致
- setMinimumSize(640, 480);
- resize(800, 600);
- setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
- // 初始化默认设置
- m_settings.liveUrl = NetworkConfig::instance().getStreamUrl();
- m_settings.liveName = "0198da41-cdb6-78e3-879d-2ea32d58f73f";
- m_settings.outputDir = QStandardPaths::writableLocation(QStandardPaths::MoviesLocation).toStdString();
- m_settings.videoBitRate = 10000000; // 提高到10Mbps,为高分辨率提供更好的画质
- m_settings.videoFrameRate = 30;
- m_settings.videoQuality = 100;
- m_settings.audioBitRate = 128000;
-
- initUI();
- initRecorder();
-
- // 创建定时器(预览已移除,不再创建预览定时器)
- // m_previewTimer = new QTimer(this);
- // connect(m_previewTimer, &QTimer::timeout, this, &RecorderWidget::updatePreview);
-
- m_statusTimer = new QTimer(this);
- connect(m_statusTimer, &QTimer::timeout, this, &RecorderWidget::updateStatus);
- m_statusTimer->start(1000); // 每秒更新一次状态
- }
- RecorderWidget::~RecorderWidget()
- {
- releaseRecorder();
- s_instance = nullptr;
- }
- void RecorderWidget::initUI()
- {
- m_mainLayout = new QVBoxLayout(this);
- m_mainLayout->setContentsMargins(0, 0, 0, 0);
- m_mainLayout->setSpacing(0);
-
- // 上部分:空白区域,占据主要空间
- QWidget* blankWidget = new QWidget(this);
- blankWidget->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
- // blankWidget->setStyleSheet("background-color: #2b2b2b; border: 1px solid #555;");
- //blankWidget->setVisible(false); // 隐藏但仍占据布局空间
-
- // 可以在空白区域添加一些提示信息
- QVBoxLayout* blankLayout = new QVBoxLayout(blankWidget);
- QLabel* hintLabel = new QLabel("录制预览区域", this);
- hintLabel->setAlignment(Qt::AlignCenter);
- hintLabel->setText("");
- // hintLabel->setStyleSheet("color: #888; font-size: 14px; border: none;");
- blankLayout->addWidget(hintLabel);
-
- // 状态栏
- initStatusBar();
-
- // 添加到主布局:上部分空白区域占据主要空间,下部分状态栏
- m_mainLayout->addWidget(blankWidget, 1); // 拉伸因子为1,占据主要空间
- m_mainLayout->addWidget(m_statusBar, 0); // 拉伸因子为0,固定高度
- }
- void RecorderWidget::initStatusBar()
- {
- m_statusBar = new QStatusBar(this);
-
- m_statusLabel = new QLabel("状态: 就绪", this);
- m_timeLabel = new QLabel("00:00:00", this);
- m_encoderLabel = new QLabel("编码器: 未选择", this);
- m_vrbLabel = new QLabel("V丢0/积0", this);
- m_arbLabel = new QLabel("A丢0/积0", this);
-
- m_statusBar->addWidget(m_statusLabel);
- m_statusBar->addPermanentWidget(m_encoderLabel);
- m_statusBar->addPermanentWidget(m_vrbLabel);
- m_statusBar->addPermanentWidget(m_arbLabel);
- m_statusBar->addPermanentWidget(m_timeLabel);
- }
- void RecorderWidget::initRecorder()
- {
- // 设置回调函数
- setupCallbacks();
-
- // 设置录制器日志路径
- QString logPath = QStandardPaths::writableLocation(QStandardPaths::TempLocation) + "/recorder.log";
- recorder_set_logpath(logPath.toUtf8().constData());
-
- // 延迟刷新编码器列表,避免在构造函数中调用可能导致异常的API
- QTimer::singleShot(100, this, [this]() {
- refreshVideoEncoders();
- });
- }
- void RecorderWidget::releaseRecorder()
- {
- if (m_isRecording || m_isStreaming) {
- recorder_stop();
- }
-
- if (m_isInitialized) {
- recorder_release();
- m_isInitialized = false;
- }
-
- // 释放设备数组
- if (m_micDevices) {
- recorder_free_array(m_micDevices);
- m_micDevices = nullptr;
- }
- if (m_speakerDevices) {
- recorder_free_array(m_speakerDevices);
- m_speakerDevices = nullptr;
- }
- if (m_encoders) {
- recorder_free_array(m_encoders);
- m_encoders = nullptr;
- }
- }
- void RecorderWidget::setupCallbacks()
- {
- m_callbacks.func_duration = onDurationCallback;
- m_callbacks.func_error = onErrorCallback;
- m_callbacks.func_device_change = onDeviceChangeCallback;
- // 预览已移除,不再设置视频/音频预览回调
- m_callbacks.func_preview_yuv = nullptr;
- m_callbacks.func_preview_audio = nullptr;
- }
- void RecorderWidget::refreshAudioDevices()
- {
- // 不再维护内部设备选择 UI,此处仅确保释放旧的查询结果
- if (m_micDevices) { recorder_free_array(m_micDevices); m_micDevices = nullptr; }
- if (m_speakerDevices) { recorder_free_array(m_speakerDevices); m_speakerDevices = nullptr; }
- m_micCount = 0;
- m_speakerCount = 0;
- }
- void RecorderWidget::refreshVideoEncoders()
- {
- // 释放之前的编码器数组
- if (m_encoders) {
- recorder_free_array(m_encoders);
- m_encoders = nullptr;
- }
-
- // 获取视频编码器
- try {
- m_encoderCount = recorder_get_vencoders(&m_encoders);
- if (m_encoderComboBox) m_encoderComboBox->clear();
- for (int i = 0; i < m_encoderCount; ++i) {
- QString encoderName = QString::fromUtf8(m_encoders[i].name);
- if (m_encoderComboBox) m_encoderComboBox->addItem(encoderName);
- }
-
- // 同步默认或外部选择
- if (m_encoderCount > 0) {
- if (m_selectedEncoderId >= 0) {
- // 若已由外部选择,则优先匹配该ID
- int matchIndex = -1;
- for (int i = 0; i < m_encoderCount; ++i) {
- if (m_encoders[i].id == m_selectedEncoderId) { matchIndex = i; break; }
- }
- if (matchIndex >= 0 && m_encoderComboBox) {
- m_encoderComboBox->setCurrentIndex(matchIndex);
- }
- if (m_encoderLabel) {
- const char* nm = (matchIndex >= 0) ? m_encoders[matchIndex].name : nullptr;
- m_encoderLabel->setText(QString("编码器: %1").arg(nm ? nm : "已选择"));
- }
- } else {
- // 否则选择第一个并更新状态
- if (m_encoderComboBox) m_encoderComboBox->setCurrentIndex(0);
- if (m_encoderLabel) m_encoderLabel->setText(QString("编码器: %1").arg(m_encoders[0].name));
- }
- }
- } catch (...) {
- m_encoderCount = 0;
- qWarning() << "Failed to get video encoders";
- if (m_encoderLabel) m_encoderLabel->setText("编码器: 获取失败");
- }
- }
- void RecorderWidget::setSettings(const Settings& settings)
- {
- m_settings = settings;
- }
- void RecorderWidget::setMicDevice(const AMRECORDER_DEVICE& device)
- {
- m_selectedMicDevice = device;
- qDebug() << "[RecorderWidget] 设置麦克风设备:" << device.name;
- }
- void RecorderWidget::setSpeakerDevice(const AMRECORDER_DEVICE& device)
- {
- m_selectedSpeakerDevice = device;
- qDebug() << "[RecorderWidget] 设置扬声器设备:" << device.name;
- }
- // 新增:外部设置视频编码器ID
- void RecorderWidget::setVideoEncoderId(int encId)
- {
- m_selectedEncoderId = encId;
- // 同步状态栏显示与内部下拉框(若存在)
- const char* encName = nullptr;
- if (m_encoders) {
- for (int i = 0; i < m_encoderCount; ++i) {
- if (m_encoders[i].id == encId) {
- encName = m_encoders[i].name;
- if (m_encoderComboBox) {
- m_encoderComboBox->blockSignals(true);
- m_encoderComboBox->setCurrentIndex(i);
- m_encoderComboBox->blockSignals(false);
- }
- break;
- }
- }
- }
- if (m_encoderLabel) {
- if (encName) m_encoderLabel->setText(QString("编码器: %1").arg(encName));
- else m_encoderLabel->setText(QString("编码器: %1").arg(encId));
- }
- }
- static void copyDevice(AMRECORDER_DEVICE &dst, const AMRECORDER_DEVICE &src)
- {
- strcpy_s(dst.id, src.id);
- strcpy_s(dst.name, src.name);
- dst.is_default = src.is_default;
- }
- static void chooseDefaultIfEmpty(AMRECORDER_DEVICE &dstMic, AMRECORDER_DEVICE &dstSpeaker)
- {
- // 若未设置,尝试从系统枚举中选择默认设备
- if (dstMic.id[0] == '\0') {
- AMRECORDER_DEVICE *mics = nullptr;
- int micCount = 0;
- try { micCount = recorder_get_mics(&mics); } catch(...) { micCount = 0; }
- if (micCount > 0 && mics) {
- int idx = 0;
- for (int i = 0; i < micCount; ++i) { if (mics[i].is_default) { idx = i; break; } }
- copyDevice(dstMic, mics[idx]);
- }
- if (mics) recorder_free_array(mics);
- }
- if (dstSpeaker.id[0] == '\0') {
- AMRECORDER_DEVICE *speakers = nullptr;
- int spkCount = 0;
- try { spkCount = recorder_get_speakers(&speakers); } catch(...) { spkCount = 0; }
- if (spkCount > 0 && speakers) {
- int idx = 0;
- for (int i = 0; i < spkCount; ++i) { if (speakers[i].is_default) { idx = i; break; } }
- copyDevice(dstSpeaker, speakers[idx]);
- }
- if (speakers) recorder_free_array(speakers);
- }
- }
- bool RecorderWidget::startRecording()
- {
- if (m_isRecording) {
- return true;
- }
-
- // 准备录制设置
- memset(&m_recorderSetting, 0, sizeof(m_recorderSetting));
-
- // 视频设置
- m_recorderSetting.v_left = 0;
- m_recorderSetting.v_top = 0;
- m_recorderSetting.v_width = GetSystemMetrics(SM_CXSCREEN);
- m_recorderSetting.v_height = GetSystemMetrics(SM_CYSCREEN);
- m_recorderSetting.v_qb = m_settings.videoQuality;
- m_recorderSetting.v_bit_rate = m_settings.videoBitRate;
- m_recorderSetting.v_frame_rate = m_settings.videoFrameRate;
-
- // 选择编码器
- int encoderIndex = m_encoderComboBox ? m_encoderComboBox->currentIndex() : -1;
- if (m_selectedEncoderId >= 0) {
- m_recorderSetting.v_enc_id = m_selectedEncoderId;
- } else if (encoderIndex >= 0 && encoderIndex < m_encoderCount && m_encoders) {
- m_recorderSetting.v_enc_id = m_encoders[encoderIndex].id;
- }
-
- // 输出文件
- QString fileName = QString::fromStdString(m_settings.outputDir);
- if (!fileName.endsWith("/") && !fileName.endsWith("\\")) {
- fileName += "/";
- }
- fileName += QDateTime::currentDateTime().toString("yyyy-MM-dd-hh-mm-ss") + ".mp4";
- strcpy_s(m_recorderSetting.output, fileName.toUtf8().constData());
-
- // 音频设备设置:优先使用外部指定,否则选默认
- AMRECORDER_DEVICE mic = m_selectedMicDevice;
- AMRECORDER_DEVICE spk = m_selectedSpeakerDevice;
- chooseDefaultIfEmpty(mic, spk);
- if (mic.id[0] != '\0') copyDevice(m_recorderSetting.a_mic, mic);
- if (spk.id[0] != '\0') copyDevice(m_recorderSetting.a_speaker, spk);
-
- // 异步初始化和启动录制器,避免主线程阻塞
- QFuture<void> future = QtConcurrent::run([this]() {
- // 初始化录制器
- int result = recorder_init(m_recorderSetting, m_callbacks);
- if (result != 0) {
- QString error = QString("初始化录制器失败: %1").arg(recorder_err2str(result));
- QMetaObject::invokeMethod(this, [this, error]() {
- emit errorOccurred(error);
- if (m_statusLabel) {
- m_statusLabel->setText("状态: 就绪");
- }
- }, Qt::QueuedConnection);
- return;
- }
-
- m_isInitialized = true;
-
- // 关闭预览
- recorder_set_preview_enabled(0);
- // 重置环形缓冲区丢帧计数
- recorder_reset_video_rb_dropped();
- recorder_reset_audio_rb_dropped();
- // 平衡低延迟设置:视频2帧、音频2帧,确保稳定性
- recorder_set_video_rb_max(2);
- recorder_set_audio_rb_max(2);
-
- // 开始录制
- result = recorder_start();
- if (result != 0) {
- QString error = QString("开始录制失败: %1").arg(recorder_err2str(result));
- QMetaObject::invokeMethod(this, [this, error]() {
- emit errorOccurred(error);
- recorder_release();
- m_isInitialized = false;
- if (m_statusLabel) {
- m_statusLabel->setText("状态: 就绪");
- }
- }, Qt::QueuedConnection);
- return;
- }
-
- // 成功启动录制
- QMetaObject::invokeMethod(this, [this]() {
- m_isRecording = true;
- m_recordStartTime = QTime::currentTime();
-
- // 预览已移除,不再启动预览定时器
- // if (m_previewTimer) m_previewTimer->start(33);
-
- emit recordingStarted();
- }, Qt::QueuedConnection);
- });
-
- // 立即更新UI状态,显示正在初始化
- m_statusLabel->setText("状态: 初始化中...");
-
- return true;
- }
- void RecorderWidget::stopRecording()
- {
- if (!m_isRecording) {
- return;
- }
-
- recorder_stop();
-
- if (m_isInitialized) {
- recorder_release();
- m_isInitialized = false;
- }
-
- m_isRecording = false;
-
- // 预览已移除,不再停止预览定时器
- // if (m_previewTimer) m_previewTimer->stop();
-
- emit recordingStopped();
- }
- bool RecorderWidget::startStreaming()
- {
- if (m_isStreaming) {
- return true;
- }
-
- // 准备推流设置
- memset(&m_recorderSetting, 0, sizeof(m_recorderSetting));
-
- // 视频设置
- m_recorderSetting.v_left = 0;
- m_recorderSetting.v_top = 0;
- m_recorderSetting.v_width = GetSystemMetrics(SM_CXSCREEN);
- m_recorderSetting.v_height = GetSystemMetrics(SM_CYSCREEN);
- m_recorderSetting.v_qb = m_settings.videoQuality;
- m_recorderSetting.v_bit_rate = m_settings.videoBitRate;
- m_recorderSetting.v_frame_rate = m_settings.videoFrameRate;
-
- // 选择编码器
- int encoderIndex = m_encoderComboBox ? m_encoderComboBox->currentIndex() : -1;
- if (m_selectedEncoderId >= 0) {
- m_recorderSetting.v_enc_id = m_selectedEncoderId;
- } else if (encoderIndex >= 0 && encoderIndex < m_encoderCount && m_encoders) {
- m_recorderSetting.v_enc_id = m_encoders[encoderIndex].id;
- }
-
- // 推流地址
- QString streamUrl = m_settings.liveUrl + "/" + QString::fromStdString(m_settings.liveName);
- strcpy_s(m_recorderSetting.output, streamUrl.toUtf8().constData());
-
- // 音频设备设置:优先使用外部指定,否则选默认
- AMRECORDER_DEVICE mic = m_selectedMicDevice;
- AMRECORDER_DEVICE spk = m_selectedSpeakerDevice;
- chooseDefaultIfEmpty(mic, spk);
- if (mic.id[0] != '\0') copyDevice(m_recorderSetting.a_mic, mic);
- if (spk.id[0] != '\0') copyDevice(m_recorderSetting.a_speaker, spk);
- qDebug() << m_recorderSetting.output;
- // 异步初始化和启动推流,避免主线程阻塞
- QFuture<void> future = QtConcurrent::run([this]() {
- // 初始化录制器
- int result = recorder_init(m_recorderSetting, m_callbacks);
- if (result != 0) {
- QString error = QString("初始化推流失败: %1").arg(recorder_err2str(result));
- QMetaObject::invokeMethod(this, [this, error]() {
- emit errorOccurred(error);
- if (m_statusLabel) {
- m_statusLabel->setText("状态: 就绪");
- }
- }, Qt::QueuedConnection);
- return;
- }
-
- m_isInitialized = true;
-
- // 关闭预览
- recorder_set_preview_enabled(0);
- // 重置环形缓冲区丢帧计数
- recorder_reset_video_rb_dropped();
- recorder_reset_audio_rb_dropped();
- // 平衡低延迟设置:视频2帧、音频2帧,确保稳定性
- recorder_set_video_rb_max(2);
- recorder_set_audio_rb_max(2);
-
- // 开始推流
- result = recorder_start();
- if (result != 0) {
- QString error = QString("开始推流失败: %1").arg(recorder_err2str(result));
- QMetaObject::invokeMethod(this, [this, error]() {
- emit errorOccurred(error);
- recorder_release();
- m_isInitialized = false;
- if (m_statusLabel) {
- m_statusLabel->setText("状态: 就绪");
- }
- }, Qt::QueuedConnection);
- return;
- }
-
- // 成功启动推流
- QMetaObject::invokeMethod(this, [this]() {
- m_isStreaming = true;
- m_recordStartTime = QTime::currentTime();
-
- // 预览已移除,不再启动预览定时器
- // if (m_previewTimer) m_previewTimer->start(33);
-
- emit streamingStarted();
- }, Qt::QueuedConnection);
- });
-
- // 立即更新UI状态,显示正在初始化
- m_statusLabel->setText("状态: 连接中...");
-
- return true;
- }
- void RecorderWidget::stopStreaming()
- {
- if (!m_isStreaming && !m_isInitialized) {
- return;
- }
- if (m_statusLabel) {
- m_statusLabel->setText("状态: 正在停止...");
- }
- QtConcurrent::run([this]() {
- // 停止推流并释放资源(与 startStreaming 对称)
- recorder_stop();
- if (m_isInitialized) {
- recorder_release();
- }
- QMetaObject::invokeMethod(this, [this]() {
- m_isStreaming = false;
- m_isInitialized = false;
- if (m_statusLabel)
- m_statusLabel->setText("状态: 就绪");
- emit streamingStopped();
- }, Qt::QueuedConnection);
- });
- }
- void RecorderWidget::setLiveName(const QString& name)
- {
- m_settings.liveName = name.toStdString();
- }
- // 新增:供MainPanel调用的按钮功能
- void RecorderWidget::onRecordButtonClicked()
- {
- if (m_isRecording) {
- stopRecording();
- } else {
- startRecording();
- }
- }
- void RecorderWidget::onStreamButtonClicked()
- {
- if (!m_isStreaming) {
- if (startStreaming()) {
- if (m_statusLabel) {
- m_statusLabel->setText("状态: 推流中");
- }
- }
- } else {
- stopStreaming();
- if (m_statusLabel) {
- m_statusLabel->setText("状态: 就绪");
- }
- }
- }
- void RecorderWidget::onSettingsButtonClicked()
- {
- // 打开设置对话框
- QMessageBox::information(this, "设置", "设置功能待实现");
- }
- void RecorderWidget::updatePreview()
- {
- if (m_previewWidget && m_previewWidth > 0 && m_previewHeight > 0) {
- m_previewWidget->update();
- }
- }
- // 预览显示控制方法实现
- void RecorderWidget::showPreview()
- {
- if (m_previewWidget) {
- m_previewWidget->show();
- }
- }
- void RecorderWidget::hidePreview()
- {
- if (m_previewWidget) {
- m_previewWidget->hide();
- }
- }
- bool RecorderWidget::isPreviewVisible() const
- {
- return m_previewWidget ? m_previewWidget->isVisible() : false;
- }
- void RecorderWidget::updateStatus()
- {
- if (m_isRecording || m_isStreaming) {
- QTime currentTime = QTime::currentTime();
- int elapsed = m_recordStartTime.secsTo(currentTime);
- int hours = elapsed / 3600;
- int minutes = (elapsed % 3600) / 60;
- int seconds = elapsed % 60;
-
- QString timeStr = QString("%1:%2:%3")
- .arg(hours, 2, 10, QChar('0'))
- .arg(minutes, 2, 10, QChar('0'))
- .arg(seconds, 2, 10, QChar('0'));
- m_timeLabel->setText(timeStr);
- } else {
- m_timeLabel->setText("00:00:00");
- }
- // 更新环形缓冲区统计(仅在初始化后)
- if (m_isInitialized) {
- uint64_t vdrop = recorder_get_video_rb_dropped();
- int vpend = recorder_get_video_rb_pending();
- uint64_t adrop = recorder_get_audio_rb_dropped();
- int apend = recorder_get_audio_rb_pending();
- if (m_vrbLabel) m_vrbLabel->setText(QString("V丢%1/积%2").arg(vdrop).arg(vpend));
- if (m_arbLabel) m_arbLabel->setText(QString("A丢%1/积%2").arg(adrop).arg(apend));
- } else {
- if (m_vrbLabel) m_vrbLabel->setText("V丢0/积0");
- if (m_arbLabel) m_arbLabel->setText("A丢0/积0");
- }
- }
- // 静态回调函数实现
- void RecorderWidget::onDurationCallback(uint64_t duration)
- {
- if (s_instance) {
- // 可以在这里处理持续时间更新
- qDebug() << "Recording duration:" << duration << "ms";
- }
- }
- void RecorderWidget::onErrorCallback(int error)
- {
- if (s_instance) {
- QString errorStr = QString("录制错误: %1").arg(recorder_err2str(error));
- QMetaObject::invokeMethod(s_instance, "errorOccurred", Qt::QueuedConnection, Q_ARG(QString, errorStr));
- }
- }
- void RecorderWidget::onDeviceChangeCallback(int type)
- {
- Q_UNUSED(type);
- // 不再自动刷新内部设备列表,由主界面设备选择器负责
- }
- void RecorderWidget::onPreviewYUVCallback(const unsigned char *data, unsigned int size, int width, int height, int type)
- {
- if (s_instance && data && size > 0) {
- QMutexLocker locker(&s_instance->m_previewMutex);
- s_instance->m_previewData = QByteArray(reinterpret_cast<const char*>(data), size);
- s_instance->m_previewWidth = width;
- s_instance->m_previewHeight = height;
- }
- }
- void RecorderWidget::onPreviewAudioCallback()
- {
- // 音频预览回调,暂时不处理
- }
|