459 qCDebug(qWasmMediaVideoOutput) << Q_FUNC_INFO;
463 auto timeUpdateCallback = [=](emscripten::val event) {
464 qCDebug(qWasmMediaVideoOutput) <<
"timeupdate";
467 emit progressChanged(event[
"target"][
"currentTime"].as<
double>() * 1000);
469 m_timeUpdateEvent.reset(
new QWasmEventHandler(m_video,
"timeupdate", timeUpdateCallback));
472 auto playCallback = [=](emscripten::val event) {
474 qCDebug(qWasmMediaVideoOutput) <<
"play" << m_video[
"src"].as<std::string>();
478 m_playEvent.reset(
new QWasmEventHandler(m_video,
"play", playCallback));
481 auto endedCallback = [=](emscripten::val event) {
483 qCDebug(qWasmMediaVideoOutput) <<
"ended";
484 m_currentMediaStatus = MediaStatus::EndOfMedia;
485 emit statusChanged(m_currentMediaStatus);
489 m_endedEvent.reset(
new QWasmEventHandler(m_video,
"ended", endedCallback));
492 auto durationChangeCallback = [=](emscripten::val event) {
493 qCDebug(qWasmMediaVideoOutput) <<
"durationChange";
496 qint64 dur = event[
"target"][
"duration"].as<
double>() * 1000;
497 emit durationChanged(dur);
499 m_durationChangeEvent.reset(
500 new QWasmEventHandler(m_video,
"durationchange", durationChangeCallback));
503 auto loadedDataCallback = [=](emscripten::val event) {
505 qCDebug(qWasmMediaVideoOutput) <<
"loaded data";
510 emit seekableChanged(m_isSeekable);
513 m_loadedDataEvent.reset(
new QWasmEventHandler(m_video,
"loadeddata", loadedDataCallback));
516 auto errorCallback = [=](emscripten::val event) {
517 qCDebug(qWasmMediaVideoOutput) <<
"error";
518 if (event.isUndefined() || event.isNull())
520 emit errorOccured(m_video[
"error"][
"code"].as<
int>(),
521 QString::fromStdString(m_video[
"error"][
"message"].as<std::string>()));
523 m_errorChangeEvent.reset(
new QWasmEventHandler(m_video,
"error", errorCallback));
526 auto resizeCallback = [=](emscripten::val event) {
528 qCDebug(qWasmMediaVideoOutput) <<
"resize";
530 updateVideoElementGeometry(
531 QRect(0, 0, m_video[
"videoWidth"].as<
int>(), m_video[
"videoHeight"].as<
int>()));
532 emit sizeChange(m_video[
"videoWidth"].as<
int>(), m_video[
"videoHeight"].as<
int>());
535 m_resizeChangeEvent.reset(
new QWasmEventHandler(m_video,
"resize", resizeCallback));
538 auto loadedMetadataCallback = [=](emscripten::val event) {
540 qCDebug(qWasmMediaVideoOutput) <<
"loaded meta data";
542 emit metaDataLoaded();
544 m_loadedMetadataChangeEvent.reset(
545 new QWasmEventHandler(m_video,
"loadedmetadata", loadedMetadataCallback));
548 auto loadStartCallback = [=](emscripten::val event) {
550 qCDebug(qWasmMediaVideoOutput) <<
"load started";
551 m_currentMediaStatus = MediaStatus::LoadingMedia;
552 emit statusChanged(m_currentMediaStatus);
553 m_shouldStop =
false;
555 m_loadStartChangeEvent.reset(
new QWasmEventHandler(m_video,
"loadstart", loadStartCallback));
559 auto canPlayCallback = [=](emscripten::val event) {
560 if (event.isUndefined() || event.isNull())
562 qCDebug(qWasmMediaVideoOutput) <<
"can play"
563 <<
"m_requestedPosition" << m_requestedPosition;
566 emit readyChanged(
true);
568 m_canPlayChangeEvent.reset(
new QWasmEventHandler(m_video,
"canplay", canPlayCallback));
571 auto canPlayThroughCallback = [=](emscripten::val event) {
573 qCDebug(qWasmMediaVideoOutput) <<
"can play through"
574 <<
"m_shouldStop" << m_shouldStop;
576 if (m_currentMediaStatus == MediaStatus::EndOfMedia)
580 emit seekableChanged(m_isSeekable);
582 if (!m_isSeeking && !m_shouldStop) {
583 emscripten::val timeRanges = m_video[
"buffered"];
584 if ((!timeRanges.isNull() || !timeRanges.isUndefined())
585 && timeRanges[
"length"].as<
int>() == 1) {
586 double buffered = m_video[
"buffered"].call<emscripten::val>(
"end", 0).as<
double>();
587 const double duration = m_video[
"duration"].as<
double>();
589 if (duration == buffered) {
590 m_currentBufferedValue = 100;
591 emit bufferingChanged(m_currentBufferedValue);
594 constexpr int hasCurrentData = 2;
595 if (m_video[
"readyState"].as<
int>() >= hasCurrentData) {
596 m_currentMediaStatus = MediaStatus::LoadedMedia;
597 emit statusChanged(m_currentMediaStatus);
601 m_shouldStop =
false;
604 m_canPlayThroughChangeEvent.reset(
605 new QWasmEventHandler(m_video,
"canplaythrough", canPlayThroughCallback));
608 auto seekingCallback = [=](emscripten::val event) {
610 qCDebug(qWasmMediaVideoOutput)
611 <<
"seeking started" << (m_video[
"currentTime"].as<
double>() * 1000);
614 m_seekingChangeEvent.reset(
new QWasmEventHandler(m_video,
"seeking", seekingCallback));
617 auto seekedCallback = [=](emscripten::val event) {
619 qCDebug(qWasmMediaVideoOutput) <<
"seeked" << (m_video[
"currentTime"].as<
double>() * 1000);
620 emit progressChanged(m_video[
"currentTime"].as<
double>() * 1000);
623 m_seekedChangeEvent.reset(
new QWasmEventHandler(m_video,
"seeked", seekedCallback));
626 auto emptiedCallback = [=](emscripten::val event) {
628 qCDebug(qWasmMediaVideoOutput) <<
"emptied";
629 emit readyChanged(
false);
630 m_currentMediaStatus = MediaStatus::EndOfMedia;
631 emit statusChanged(m_currentMediaStatus);
633 m_emptiedChangeEvent.reset(
new QWasmEventHandler(m_video,
"emptied", emptiedCallback));
636 auto stalledCallback = [=](emscripten::val event) {
638 qCDebug(qWasmMediaVideoOutput) <<
"stalled";
639 m_currentMediaStatus = MediaStatus::StalledMedia;
640 emit statusChanged(m_currentMediaStatus);
642 m_stalledChangeEvent.reset(
new QWasmEventHandler(m_video,
"stalled", stalledCallback));
645 auto waitingCallback = [=](emscripten::val event) {
648 qCDebug(qWasmMediaVideoOutput) <<
"waiting";
651 m_waitingChangeEvent.reset(
new QWasmEventHandler(m_video,
"waiting", waitingCallback));
656 auto playingCallback = [=](emscripten::val event) {
658 qCDebug(qWasmMediaVideoOutput) <<
"playing";
662 if (m_toBePaused || !m_shouldStop) {
663 m_toBePaused =
false;
664 QMetaObject::invokeMethod(
this, &QWasmVideoOutput::videoFrameTimerCallback, Qt::QueuedConnection);
667 m_playingChangeEvent.reset(
new QWasmEventHandler(m_video,
"playing", playingCallback));
670 auto progesssCallback = [=](emscripten::val event) {
671 if (event.isUndefined() || event.isNull())
674 const double duration = event[
"target"][
"duration"].as<
double>();
678 emscripten::val timeRanges = event[
"target"][
"buffered"];
680 if ((!timeRanges.isNull() || !timeRanges.isUndefined())
681 && timeRanges[
"length"].as<
int>() == 1) {
682 emscripten::val dVal = timeRanges.call<emscripten::val>(
"end", 0);
683 if (!dVal.isNull() || !dVal.isUndefined()) {
684 double bufferedEnd = dVal.as<
double>();
686 if (duration > 0 && bufferedEnd > 0) {
687 const double bufferedValue = (bufferedEnd / duration * 100);
688 qCDebug(qWasmMediaVideoOutput) <<
"progress buffered";
689 m_currentBufferedValue = bufferedValue;
690 emit bufferingChanged(m_currentBufferedValue);
691 if (bufferedEnd == duration)
692 m_currentMediaStatus = MediaStatus::BufferedMedia;
694 m_currentMediaStatus = MediaStatus::BufferingMedia;
695 emit statusChanged(m_currentMediaStatus);
700 m_progressChangeEvent.reset(
new QWasmEventHandler(m_video,
"progress", progesssCallback));
703 auto pauseCallback = [=](emscripten::val event) {
705 qCDebug(qWasmMediaVideoOutput) <<
"pause";
707 const double currentTime = m_video[
"currentTime"].as<
double>();
708 const double duration = m_video[
"duration"].as<
double>();
709 if ((currentTime > 0 && currentTime < duration) && (!m_shouldStop && m_toBePaused)) {
713 m_video.set(
"currentTime", emscripten::val(0));
717 m_pauseChangeEvent.reset(
new QWasmEventHandler(m_video,
"pause", pauseCallback));
722 emscripten::val window = emscripten::val::global(
"window");
724 auto beforeUnloadCallback = [=](emscripten::val event) {
728 m_video.call<
void>(
"removeAttribute", emscripten::val(
"src"));
729 m_video.call<
void>(
"load");
731 m_beforeUnloadEvent.reset(
new QWasmEventHandler(window,
"beforeunload", beforeUnloadCallback));
853 emscripten::val videoElement = videoOutput->currentVideoElement();
854 emscripten::val oneVideoFrame = val::global(
"VideoFrame").new_(videoElement);
856 if (oneVideoFrame.isNull() || oneVideoFrame.isUndefined()) {
857 qCDebug(qWasmMediaVideoOutput) << Q_FUNC_INFO
858 <<
"ERROR" <<
"failed to construct VideoFrame";
862 emscripten::val options = emscripten::val::object();
863 emscripten::val rectOptions = emscripten::val::object();
865 rectOptions.set(
"width",oneVideoFrame[
"displayWidth"].as<
int>());
866 rectOptions.set(
"height", oneVideoFrame[
"displayHeight"].as<
int>());
867 options.set(
"rect", rectOptions);
869 emscripten::val frameBytesAllocationSize = oneVideoFrame.call<emscripten::val>(
"allocationSize", options);
870 emscripten::val frameBuffer =
871 emscripten::val::global(
"Uint8Array").new_(frameBytesAllocationSize);
873 reinterpret_cast<QWasmVideoOutput*>(videoElement[
"data-qvideocontext"].as<quintptr>());
875 qstdweb::PromiseCallbacks copyToCallback;
876 copyToCallback.thenFunc = [wasmVideoOutput, oneVideoFrame, frameBuffer, videoElement]
877 (emscripten::val frameLayout)
879 if (frameLayout.isNull() || frameLayout.isUndefined()) {
880 qCDebug(qWasmMediaVideoOutput) <<
"theres no frameLayout";
885 const QSize frameSize(oneVideoFrame[
"displayWidth"].as<
int>(),
886 oneVideoFrame[
"displayHeight"].as<
int>());
888 QByteArray frameBytes = QByteArray::fromEcmaUint8Array(frameBuffer);
890 QVideoFrameFormat::PixelFormat pixelFormat = fromJsPixelFormat(oneVideoFrame[
"format"].as<std::string>());
891 if (pixelFormat == QVideoFrameFormat::Format_Invalid) {
892 qWarning() <<
"Invalid pixel format";
895 QVideoFrameFormat frameFormat = QVideoFrameFormat(frameSize, pixelFormat);
897 auto buffer = std::make_unique<QMemoryVideoBuffer>(
898 std::move(frameBytes),
899 oneVideoFrame[
"codedWidth"].as<
int>());
902 QVideoFramePrivate::createFrame(std::move(buffer), std::move(frameFormat));
904 if (!wasmVideoOutput) {
905 qCDebug(qWasmMediaVideoOutput) <<
"ERROR:"
906 <<
"data-qvideocontext not found";
909 if (!wasmVideoOutput->m_wasmSink) {
910 qWarning() <<
"ERROR ALERT!! video sink not set";
913 wasmVideoOutput->m_wasmSink->setVideoFrame(vFrame);
914 oneVideoFrame.call<emscripten::val>(
"close");
916 copyToCallback.catchFunc = [&, wasmVideoOutput, oneVideoFrame, videoElement](emscripten::val error)
918 qCDebug(qWasmMediaVideoOutput) <<
"Error"
919 << QString::fromStdString(error[
"name"].as<std::string>())
920 << QString::fromStdString(error[
"message"].as<std::string>()) ;
922 oneVideoFrame.call<emscripten::val>(
"close");
927 qstdweb::Promise::make(oneVideoFrame, u"copyTo"_s, std::move(copyToCallback), frameBuffer);