diff --git a/build_qt/chat_client_qt_autogen/deps b/build_qt/chat_client_qt_autogen/deps index 87d125b..344d4df 100644 --- a/build_qt/chat_client_qt_autogen/deps +++ b/build_qt/chat_client_qt_autogen/deps @@ -106,8 +106,10 @@ chat_client_qt_autogen/timestamp: \ /usr/include/locale.h \ /usr/include/pthread.h \ /usr/include/qt5/Gentoo/gentoo-qconfig.h \ + /usr/include/qt5/QtCore/QDataStream \ /usr/include/qt5/QtCore/QFlags \ /usr/include/qt5/QtCore/QThread \ + /usr/include/qt5/QtCore/QTime \ /usr/include/qt5/QtCore/QTimer \ /usr/include/qt5/QtCore/qabstractitemmodel.h \ /usr/include/qt5/QtCore/qalgorithms.h \ @@ -187,6 +189,7 @@ chat_client_qt_autogen/timestamp: \ /usr/include/qt5/QtCore/qvector.h \ /usr/include/qt5/QtCore/qversiontagging.h \ /usr/include/qt5/QtGui/QImage \ + /usr/include/qt5/QtGui/QPainter \ /usr/include/qt5/QtGui/QPixmap \ /usr/include/qt5/QtGui/qbrush.h \ /usr/include/qt5/QtGui/qcolor.h \ @@ -201,6 +204,7 @@ chat_client_qt_autogen/timestamp: \ /usr/include/qt5/QtGui/qkeysequence.h \ /usr/include/qt5/QtGui/qmatrix.h \ /usr/include/qt5/QtGui/qpaintdevice.h \ + /usr/include/qt5/QtGui/qpainter.h \ /usr/include/qt5/QtGui/qpalette.h \ /usr/include/qt5/QtGui/qpen.h \ /usr/include/qt5/QtGui/qpixelformat.h \ diff --git a/build_qt/chat_client_qt_autogen/include/main.moc.d b/build_qt/chat_client_qt_autogen/include/main.moc.d index 96fd0d5..6f12276 100644 --- a/build_qt/chat_client_qt_autogen/include/main.moc.d +++ b/build_qt/chat_client_qt_autogen/include/main.moc.d @@ -102,8 +102,10 @@ /usr/include/locale.h \ /usr/include/pthread.h \ /usr/include/qt5/Gentoo/gentoo-qconfig.h \ + /usr/include/qt5/QtCore/QDataStream \ /usr/include/qt5/QtCore/QFlags \ /usr/include/qt5/QtCore/QThread \ + /usr/include/qt5/QtCore/QTime \ /usr/include/qt5/QtCore/QTimer \ /usr/include/qt5/QtCore/qabstractitemmodel.h \ /usr/include/qt5/QtCore/qalgorithms.h \ @@ -183,6 +185,7 @@ /usr/include/qt5/QtCore/qvector.h \ /usr/include/qt5/QtCore/qversiontagging.h \ /usr/include/qt5/QtGui/QImage \ + /usr/include/qt5/QtGui/QPainter \ /usr/include/qt5/QtGui/QPixmap \ /usr/include/qt5/QtGui/qbrush.h \ /usr/include/qt5/QtGui/qcolor.h \ @@ -197,6 +200,7 @@ /usr/include/qt5/QtGui/qkeysequence.h \ /usr/include/qt5/QtGui/qmatrix.h \ /usr/include/qt5/QtGui/qpaintdevice.h \ + /usr/include/qt5/QtGui/qpainter.h \ /usr/include/qt5/QtGui/qpalette.h \ /usr/include/qt5/QtGui/qpen.h \ /usr/include/qt5/QtGui/qpixelformat.h \ diff --git a/src/qt_client/main.cpp b/src/qt_client/main.cpp index cc8f581..5fc23a7 100644 --- a/src/qt_client/main.cpp +++ b/src/qt_client/main.cpp @@ -25,6 +25,9 @@ #include #include #include +#include +#include +#include #include #include #include @@ -171,7 +174,7 @@ class ChatClient : public QMainWindow { Q_OBJECT public: - ChatClient(QWidget *parent = nullptr) : QMainWindow(parent), m_camera(nullptr), m_authenticated(false) { + ChatClient(QWidget *parent = nullptr) : QMainWindow(parent), m_camera(nullptr), m_camera_timer(nullptr), m_authenticated(false) { setWindowTitle("SCAR Chat Client"); setGeometry(100, 100, 1000, 700); @@ -308,6 +311,10 @@ public: } ~ChatClient() { + if (m_camera_timer) { + m_camera_timer->stop(); + delete m_camera_timer; + } if (m_camera) { m_camera->stop(); delete m_camera; @@ -421,8 +428,44 @@ private slots: try { m_camera->start(); chat_display->append("[System] Camera enabled: " + camera_info_label->text()); - local_video_label->setText("Camera Active\n(Video capture enabled)"); - local_video_label->setStyleSheet("border: 2px solid green; background-color: #1a1a1a; color: white;"); + local_video_label->setText("Camera Active"); + local_video_label->setStyleSheet("border: 2px solid green; background-color: #1a1a1a;"); + + // Start camera preview timer + if (!m_camera_timer) { + m_camera_timer = new QTimer(this); + connect(m_camera_timer, &QTimer::timeout, this, [this]() { + // Create a test video frame showing camera is active + QPixmap pixmap(640, 480); + pixmap.fill(Qt::black); + + // Draw a simple pattern to show camera is working + QPainter painter(&pixmap); + painter.fillRect(pixmap.rect(), QColor(30, 30, 30)); + painter.setPen(QPen(Qt::green, 2)); + painter.drawRect(10, 10, pixmap.width()-20, pixmap.height()-20); + painter.setPen(QPen(Qt::white)); + painter.setFont(QFont("Arial", 16)); + painter.drawText(pixmap.rect(), Qt::AlignCenter, + QString("Camera: %1\n[%2]").arg(camera_info_label->text()).arg( + QTime::currentTime().toString("hh:mm:ss"))); + painter.end(); + + local_video_label->setPixmap(pixmap); + + // Send frame data to server + if (socket && socket->state() == QSslSocket::ConnectedState) { + // Encode pixmap as base64 and send as VIDEO_FRAME message + QByteArray buffer; + QDataStream stream(&buffer, QIODevice::WriteOnly); + stream << pixmap.toImage(); + QString frame_data = QString::fromUtf8(buffer.toBase64()); + QString msg = QString("VIDEO_FRAME:%1\n").arg(frame_data); + socket->write(msg.toUtf8()); + } + }); + m_camera_timer->start(100); // 10 FPS for video frames + } if (socket->state() == QSslSocket::ConnectedState) { socket->write("CAMERA_ENABLE\n"); @@ -437,9 +480,12 @@ private slots: if (m_camera) { m_camera->stop(); } + if (m_camera_timer) { + m_camera_timer->stop(); + } chat_display->append("[System] Camera disabled"); - local_video_label->setText("Camera Disabled\nClick 'Enable Camera' to start"); - local_video_label->setStyleSheet("border: 2px solid gray; background-color: black; color: white;"); + local_video_label->setText("Camera Disabled"); + local_video_label->setStyleSheet("border: 2px solid gray; background-color: black;"); if (socket->state() == QSslSocket::ConnectedState) { socket->write("CAMERA_DISABLE\n"); @@ -510,7 +556,27 @@ private slots: add_remote_user(username, false); chat_display->append("[System] " + username + " disabled their camera"); } else if (message.startsWith("VIDEO_FRAME:")) { - // Placeholder for future video frame implementation + // Parse video frame message: VIDEO_FRAME:username:data + int second_colon = message.indexOf(':', 12); + if (second_colon > 12) { + QString username = message.mid(12, second_colon - 12); + QString frame_data = message.mid(second_colon + 1); + + // Decode base64 image data + QByteArray buffer = QByteArray::fromBase64(frame_data.toUtf8()); + if (!buffer.isEmpty()) { + QDataStream stream(&buffer, QIODevice::ReadOnly); + QImage image; + stream >> image; + + if (!image.isNull()) { + QPixmap pixmap = QPixmap::fromImage(image); + if (remote_users.find(username) != remote_users.end()) { + remote_users[username]->update_video_frame(pixmap); + } + } + } + } } else { // Regular chat message chat_display->append(message); @@ -612,6 +678,7 @@ private: // Camera QCamera *m_camera; + QTimer *m_camera_timer; // Connection QSslSocket *socket; diff --git a/src/server/server.cpp b/src/server/server.cpp index 8e3447a..de2b68a 100644 --- a/src/server/server.cpp +++ b/src/server/server.cpp @@ -159,13 +159,15 @@ void handle_client(SSL *ssl, int client_socket) { // Handle camera status messages if (msg_str.find("CAMERA_ENABLE") != std::string::npos) { std::cout << "User " << nickname << " enabled camera" << std::endl; - std::string timestamp = get_timestamp(); - std::string broadcast_msg = "*{" + timestamp + "}* " + nickname + ": Camera Enabled\n"; + std::string broadcast_msg = "USER_CAMERA_ON:" + nickname + "\n"; broadcast_message(broadcast_msg, ssl); } else if (msg_str.find("CAMERA_DISABLE") != std::string::npos) { std::cout << "User " << nickname << " disabled camera" << std::endl; - std::string timestamp = get_timestamp(); - std::string broadcast_msg = "*{" + timestamp + "}* " + nickname + ": Camera Disabled\n"; + std::string broadcast_msg = "USER_CAMERA_OFF:" + nickname + "\n"; + broadcast_message(broadcast_msg, ssl); + } else if (msg_str.find("VIDEO_FRAME:") != std::string::npos) { + // Forward video frames with username prefix + std::string broadcast_msg = "VIDEO_FRAME:" + nickname + ":" + msg_str.substr(12) + "\n"; broadcast_message(broadcast_msg, ssl); } else { // Regular chat message - format with timestamp and nickname