SimplePlayerWindow.cpp 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483
  1. #include "SimplePlayerWindow.h"
  2. #include <QFileDialog>
  3. #include <QMessageBox>
  4. #include <QDebug>
  5. #include <QFileInfo>
  6. SimplePlayerWindow::SimplePlayerWindow(QWidget *parent)
  7. : QMainWindow(parent)
  8. , m_videoRenderer(nullptr)
  9. , m_openGLVideoRenderer(nullptr)
  10. {
  11. qDebug() << "Initializing SimplePlayerWindow...";
  12. try {
  13. // 创建播放器适配器
  14. m_playerAdapter = PlayerAdapterFactory::create(this);
  15. if (!m_playerAdapter) {
  16. throw std::runtime_error("Failed to create PlayerAdapter");
  17. }
  18. qDebug() << "PlayerAdapter created successfully";
  19. setupUI();
  20. connectSignals();
  21. updateUI();
  22. // 优先设置OpenGL渲染器
  23. if (m_openGLVideoRenderer && m_playerAdapter) {
  24. qDebug() << "Setting OpenGL video renderer...";
  25. m_playerAdapter->setOpenGLVideoRenderer(m_openGLVideoRenderer);
  26. } else if (m_videoRenderer && m_playerAdapter) {
  27. qDebug() << "Setting traditional video renderer...";
  28. m_playerAdapter->setVideoRenderer(m_videoRenderer);
  29. } else {
  30. qWarning() << "No video renderer available";
  31. }
  32. setWindowTitle("Simple Media Player (OpenGL)");
  33. resize(800, 600);
  34. qDebug() << "SimplePlayerWindow initialized successfully";
  35. } catch (const std::exception& e) {
  36. qCritical() << "Exception during SimplePlayerWindow initialization:" << e.what();
  37. QMessageBox::critical(this, "Initialization Error",
  38. QString("Failed to initialize player window: %1").arg(e.what()));
  39. throw;
  40. } catch (...) {
  41. qCritical() << "Unknown exception during SimplePlayerWindow initialization";
  42. QMessageBox::critical(this, "Initialization Error",
  43. "Unknown error during player window initialization");
  44. throw;
  45. }
  46. }
  47. SimplePlayerWindow::~SimplePlayerWindow()
  48. {
  49. if (m_playerAdapter) {
  50. m_playerAdapter->stop();
  51. }
  52. }
  53. void SimplePlayerWindow::openFile()
  54. {
  55. qDebug() << "Opening file dialog...";
  56. QString filename = QFileDialog::getOpenFileName(
  57. this,
  58. "Open Media File",
  59. "",
  60. "Media Files (*.mp4 *.avi *.mkv *.mov *.wmv *.flv *.webm *.mp3 *.wav *.aac *.flac *.ogg);;All Files (*.*)"
  61. );
  62. if (!filename.isEmpty()) {
  63. qDebug() << "Selected file:" << filename;
  64. // 检查文件是否存在
  65. QFileInfo fileInfo(filename);
  66. if (!fileInfo.exists()) {
  67. QMessageBox::critical(this, "Error", "File does not exist: " + filename);
  68. return;
  69. }
  70. if (!fileInfo.isReadable()) {
  71. QMessageBox::critical(this, "Error", "File is not readable: " + filename);
  72. return;
  73. }
  74. // 显示加载状态
  75. m_stateLabel->setText("State: Loading...");
  76. m_fileLabel->setText("Loading: " + fileInfo.fileName());
  77. // 尝试打开文件
  78. av::ErrorCode result = m_playerAdapter->openFile(filename);
  79. if (result != av::ErrorCode::SUCCESS) {
  80. QString errorMsg = "Failed to open file: " + filename;
  81. // 根据错误代码提供更具体的错误信息
  82. switch (result) {
  83. case av::ErrorCode::FILE_OPEN_FAILED:
  84. errorMsg = "Could not open file. Please check if the file is corrupted or in an unsupported format.";
  85. break;
  86. case av::ErrorCode::CODEC_OPEN_FAILED:
  87. errorMsg = "Could not initialize codecs. The file format may not be supported.";
  88. break;
  89. case av::ErrorCode::NOT_INITIALIZED:
  90. errorMsg = "Player not properly initialized. Please restart the application.";
  91. break;
  92. case av::ErrorCode::INVALID_STATE:
  93. errorMsg = "Player is in an invalid state. Please try again.";
  94. break;
  95. default:
  96. errorMsg = "Unknown error occurred while opening the file.";
  97. break;
  98. }
  99. QMessageBox::critical(this, "Error", errorMsg);
  100. qCritical() << "Failed to open file:" << filename << "Error code:" << static_cast<int>(result);
  101. // 重置状态
  102. m_stateLabel->setText("State: Idle");
  103. m_fileLabel->setText("No file loaded");
  104. } else {
  105. m_fileLabel->setText("File: " + fileInfo.fileName());
  106. qDebug() << "File opened successfully:" << filename;
  107. }
  108. } else {
  109. qDebug() << "No file selected";
  110. }
  111. }
  112. void SimplePlayerWindow::playPause()
  113. {
  114. if (!m_playerAdapter) {
  115. qWarning() << "PlayerAdapter is null";
  116. return;
  117. }
  118. PlayerState state = m_playerAdapter->getState();
  119. qDebug() << "Current player state:" << static_cast<int>(state);
  120. if (state == PlayerState::Playing) {
  121. qDebug() << "Pausing playback...";
  122. av::ErrorCode result = m_playerAdapter->pause();
  123. if (result != av::ErrorCode::SUCCESS) {
  124. qWarning() << "Failed to pause playback, error code:" << static_cast<int>(result);
  125. }
  126. } else if (state == PlayerState::Paused || state == PlayerState::Stopped) {
  127. qDebug() << "Starting playback...";
  128. av::ErrorCode result = m_playerAdapter->play();
  129. if (result != av::ErrorCode::SUCCESS) {
  130. qWarning() << "Failed to start playback, error code:" << static_cast<int>(result);
  131. QMessageBox::warning(this, "Playback Error",
  132. "Failed to start playback. Please check if a file is loaded.");
  133. }
  134. } else if (state == PlayerState::Idle) {
  135. QMessageBox::information(this, "Information",
  136. "Please open a media file first.");
  137. } else {
  138. qDebug() << "Player is in state:" << static_cast<int>(state) << "- cannot play/pause";
  139. }
  140. }
  141. void SimplePlayerWindow::stop()
  142. {
  143. m_playerAdapter->stop();
  144. }
  145. void SimplePlayerWindow::seek()
  146. {
  147. if (m_seeking) {
  148. qint64 duration = m_playerAdapter->getDuration();
  149. qint64 position = (duration * m_positionSlider->value()) / 1000;
  150. m_playerAdapter->seek(position);
  151. }
  152. }
  153. void SimplePlayerWindow::setVolume()
  154. {
  155. double volume = m_volumeSlider->value() / 100.0;
  156. m_playerAdapter->setVolume(volume);
  157. m_volumeLabel->setText(QString("Volume: %1%").arg(m_volumeSlider->value()));
  158. }
  159. void SimplePlayerWindow::toggleMute()
  160. {
  161. bool muted = m_playerAdapter->isMuted();
  162. m_playerAdapter->setMuted(!muted);
  163. }
  164. void SimplePlayerWindow::setPlaybackSpeed()
  165. {
  166. double speed = m_speedSlider->value() / 100.0;
  167. m_playerAdapter->setPlaybackSpeed(speed);
  168. m_speedLabel->setText(QString("Speed: %1x").arg(speed, 0, 'f', 2));
  169. }
  170. void SimplePlayerWindow::onStateChanged(PlayerState state)
  171. {
  172. QString stateText;
  173. switch (state) {
  174. case PlayerState::Idle:
  175. stateText = "Idle";
  176. break;
  177. // case PlayerState::Loading:
  178. // stateText = "Loading";
  179. // break;
  180. case PlayerState::Playing:
  181. stateText = "Playing";
  182. break;
  183. case PlayerState::Paused:
  184. stateText = "Paused";
  185. break;
  186. case PlayerState::Stopped:
  187. stateText = "Stopped";
  188. break;
  189. case PlayerState::Error:
  190. stateText = "Error";
  191. break;
  192. }
  193. m_stateLabel->setText("State: " + stateText);
  194. updateUI();
  195. }
  196. void SimplePlayerWindow::onMediaInfoChanged(const MediaInfo& info)
  197. {
  198. QString infoText = QString("Duration: %1 | Video: %2x%3 | Audio: %4 Hz")
  199. .arg(formatTime(info.duration))
  200. .arg(info.width)
  201. .arg(info.height)
  202. .arg(info.audioSampleRate);
  203. m_infoLabel->setText(infoText);
  204. }
  205. void SimplePlayerWindow::onPositionChanged(qint64 position)
  206. {
  207. if (!m_seeking) {
  208. qint64 duration = m_playerAdapter->getDuration();
  209. if (duration > 0) {
  210. int sliderValue = (position * 1000) / duration;
  211. m_positionSlider->setValue(sliderValue);
  212. }
  213. QString timeText = QString("%1 / %2")
  214. .arg(formatTime(position))
  215. .arg(formatTime(duration));
  216. m_timeLabel->setText(timeText);
  217. }
  218. }
  219. void SimplePlayerWindow::onVolumeChanged(double volume)
  220. {
  221. int volumePercent = static_cast<int>(volume * 100);
  222. m_volumeSlider->setValue(volumePercent);
  223. m_volumeLabel->setText(QString("Volume: %1%").arg(volumePercent));
  224. }
  225. void SimplePlayerWindow::onMutedChanged(bool muted)
  226. {
  227. m_muteButton->setText(muted ? "Unmute" : "Mute");
  228. }
  229. void SimplePlayerWindow::onPlaybackSpeedChanged(double speed)
  230. {
  231. int speedPercent = static_cast<int>(speed * 100);
  232. m_speedSlider->setValue(speedPercent);
  233. m_speedLabel->setText(QString("Speed: %1x").arg(speed, 0, 'f', 2));
  234. }
  235. void SimplePlayerWindow::onErrorOccurred(const QString& error)
  236. {
  237. QMessageBox::critical(this, "Player Error", error);
  238. qDebug() << "Player error:" << error;
  239. }
  240. void SimplePlayerWindow::onStatsUpdated(const PlaybackStats& stats)
  241. {
  242. QString statsText = QString("Packets: %1 | Video Frames: %2 | Audio Frames: %3")
  243. .arg(stats.queuedPackets)
  244. .arg(stats.queuedVideoFrames)
  245. .arg(stats.queuedAudioFrames);
  246. m_statsLabel->setText(statsText);
  247. }
  248. void SimplePlayerWindow::setupUI()
  249. {
  250. auto* centralWidget = new QWidget(this);
  251. setCentralWidget(centralWidget);
  252. auto* mainLayout = new QVBoxLayout(centralWidget);
  253. // 文件信息
  254. m_fileLabel = new QLabel("No file loaded");
  255. m_stateLabel = new QLabel("State: Idle");
  256. m_infoLabel = new QLabel("Media info will appear here");
  257. mainLayout->addWidget(m_fileLabel);
  258. mainLayout->addWidget(m_stateLabel);
  259. mainLayout->addWidget(m_infoLabel);
  260. // 视频渲染器 - 优先使用OpenGL渲染器
  261. m_openGLVideoRenderer = new OpenGLVideoRenderer(this);
  262. m_openGLVideoRenderer->setMinimumSize(640, 480);
  263. m_openGLVideoRenderer->setStyleSheet("border: 1px solid gray;");
  264. mainLayout->addWidget(m_openGLVideoRenderer);
  265. // 备用传统渲染器(隐藏)
  266. m_videoRenderer = new VideoRenderer(this);
  267. m_videoRenderer->setMinimumSize(640, 480);
  268. m_videoRenderer->setStyleSheet("border: 1px solid gray;");
  269. m_videoRenderer->hide();
  270. mainLayout->addWidget(m_videoRenderer);
  271. // 控制按钮
  272. auto* buttonLayout = new QHBoxLayout();
  273. m_openButton = new QPushButton("Open File");
  274. m_playPauseButton = new QPushButton("Play");
  275. m_stopButton = new QPushButton("Stop");
  276. buttonLayout->addWidget(m_openButton);
  277. buttonLayout->addWidget(m_playPauseButton);
  278. buttonLayout->addWidget(m_stopButton);
  279. buttonLayout->addStretch();
  280. mainLayout->addLayout(buttonLayout);
  281. // 进度控制
  282. auto* progressLayout = new QHBoxLayout();
  283. m_timeLabel = new QLabel("00:00 / 00:00");
  284. m_positionSlider = new QSlider(Qt::Horizontal);
  285. m_positionSlider->setRange(0, 1000);
  286. progressLayout->addWidget(m_timeLabel);
  287. progressLayout->addWidget(m_positionSlider);
  288. mainLayout->addLayout(progressLayout);
  289. // 音量控制
  290. auto* volumeLayout = new QHBoxLayout();
  291. m_volumeLabel = new QLabel("Volume: 100%");
  292. m_volumeSlider = new QSlider(Qt::Horizontal);
  293. m_volumeSlider->setRange(0, 100);
  294. m_volumeSlider->setValue(100);
  295. m_muteButton = new QPushButton("Mute");
  296. volumeLayout->addWidget(m_volumeLabel);
  297. volumeLayout->addWidget(m_volumeSlider);
  298. volumeLayout->addWidget(m_muteButton);
  299. mainLayout->addLayout(volumeLayout);
  300. // 播放速度控制
  301. auto* speedLayout = new QHBoxLayout();
  302. m_speedLabel = new QLabel("Speed: 1.00x");
  303. m_speedSlider = new QSlider(Qt::Horizontal);
  304. m_speedSlider->setRange(25, 400); // 0.25x to 4.0x
  305. m_speedSlider->setValue(100);
  306. speedLayout->addWidget(m_speedLabel);
  307. speedLayout->addWidget(m_speedSlider);
  308. mainLayout->addLayout(speedLayout);
  309. // 统计信息
  310. m_statsLabel = new QLabel("Statistics will appear here");
  311. mainLayout->addWidget(m_statsLabel);
  312. mainLayout->addStretch();
  313. }
  314. void SimplePlayerWindow::connectSignals()
  315. {
  316. // UI信号
  317. connect(m_openButton, &QPushButton::clicked, this, &SimplePlayerWindow::openFile);
  318. connect(m_playPauseButton, &QPushButton::clicked, this, &SimplePlayerWindow::playPause);
  319. connect(m_stopButton, &QPushButton::clicked, this, &SimplePlayerWindow::stop);
  320. connect(m_positionSlider, &QSlider::sliderPressed, [this]() { m_seeking = true; });
  321. connect(m_positionSlider, &QSlider::sliderReleased, [this]() {
  322. seek();
  323. m_seeking = false;
  324. });
  325. connect(m_volumeSlider, &QSlider::valueChanged, this, &SimplePlayerWindow::setVolume);
  326. connect(m_muteButton, &QPushButton::clicked, this, &SimplePlayerWindow::toggleMute);
  327. connect(m_speedSlider, &QSlider::valueChanged, this, &SimplePlayerWindow::setPlaybackSpeed);
  328. // 播放器信号
  329. connect(m_playerAdapter.get(),
  330. &PlayerAdapter::stateChanged,
  331. this,
  332. &SimplePlayerWindow::onStateChanged);
  333. connect(m_playerAdapter.get(),
  334. &PlayerAdapter::mediaInfoChanged,
  335. this,
  336. &SimplePlayerWindow::onMediaInfoChanged);
  337. connect(m_playerAdapter.get(),
  338. &PlayerAdapter::positionChanged,
  339. this,
  340. &SimplePlayerWindow::onPositionChanged);
  341. connect(m_playerAdapter.get(),
  342. &PlayerAdapter::volumeChanged,
  343. this,
  344. &SimplePlayerWindow::onVolumeChanged);
  345. connect(m_playerAdapter.get(),
  346. &PlayerAdapter::mutedChanged,
  347. this,
  348. &SimplePlayerWindow::onMutedChanged);
  349. connect(m_playerAdapter.get(),
  350. &PlayerAdapter::playbackSpeedChanged,
  351. this,
  352. &SimplePlayerWindow::onPlaybackSpeedChanged);
  353. connect(m_playerAdapter.get(),
  354. &PlayerAdapter::errorOccurred,
  355. this,
  356. &SimplePlayerWindow::onErrorOccurred);
  357. connect(m_playerAdapter.get(),
  358. &PlayerAdapter::statsUpdated,
  359. this,
  360. &SimplePlayerWindow::onStatsUpdated);
  361. // 渲染器相关信号
  362. connect(m_playerAdapter.get(),
  363. &PlayerAdapter::rendererTypeChanged,
  364. this,
  365. &SimplePlayerWindow::onRendererTypeChanged);
  366. connect(m_playerAdapter.get(),
  367. &PlayerAdapter::openGLRendererInitialized,
  368. this,
  369. &SimplePlayerWindow::onOpenGLRendererInitialized);
  370. }
  371. void SimplePlayerWindow::updateUI()
  372. {
  373. PlayerState state = m_playerAdapter->getState();
  374. // 更新播放/暂停按钮
  375. if (state == PlayerState::Playing) {
  376. m_playPauseButton->setText("Pause");
  377. } else {
  378. m_playPauseButton->setText("Play");
  379. }
  380. // 更新按钮可用状态
  381. bool hasMedia = (state != PlayerState::Idle);
  382. m_playPauseButton->setEnabled(hasMedia);
  383. m_stopButton->setEnabled(hasMedia);
  384. m_positionSlider->setEnabled(hasMedia);
  385. }
  386. void SimplePlayerWindow::onRendererTypeChanged(const QString& type)
  387. {
  388. qDebug() << "Renderer type changed to:" << type;
  389. // 更新窗口标题显示当前渲染器类型
  390. QString title = QString("Simple Media Player (%1)").arg(type);
  391. setWindowTitle(title);
  392. }
  393. void SimplePlayerWindow::onOpenGLRendererInitialized()
  394. {
  395. qDebug() << "OpenGL renderer initialized successfully";
  396. // 可以在这里添加OpenGL渲染器初始化完成后的逻辑
  397. // 比如显示一些OpenGL特定的信息
  398. }
  399. QString SimplePlayerWindow::formatTime(qint64 microseconds)
  400. {
  401. qint64 seconds = microseconds / 1000000;
  402. qint64 minutes = seconds / 60;
  403. seconds %= 60;
  404. return QString("%1:%2").arg(minutes, 2, 10, QChar('0')).arg(seconds, 2, 10, QChar('0'));
  405. }