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;
668 m_playingChangeEvent.reset(
new QWasmEventHandler(m_video,
"playing", playingCallback));
671 auto progesssCallback = [=](emscripten::val event) {
672 if (event.isUndefined() || event.isNull())
675 const double duration = event[
"target"][
"duration"].as<
double>();
679 emscripten::val timeRanges = event[
"target"][
"buffered"];
681 if ((!timeRanges.isNull() || !timeRanges.isUndefined())
682 && timeRanges[
"length"].as<
int>() == 1) {
683 emscripten::val dVal = timeRanges.call<emscripten::val>(
"end", 0);
684 if (!dVal.isNull() || !dVal.isUndefined()) {
685 double bufferedEnd = dVal.as<
double>();
687 if (duration > 0 && bufferedEnd > 0) {
688 const double bufferedValue = (bufferedEnd / duration * 100);
689 qCDebug(qWasmMediaVideoOutput) <<
"progress buffered";
690 m_currentBufferedValue = bufferedValue;
691 emit bufferingChanged(m_currentBufferedValue);
692 if (bufferedEnd == duration)
693 m_currentMediaStatus = MediaStatus::BufferedMedia;
695 m_currentMediaStatus = MediaStatus::BufferingMedia;
696 emit statusChanged(m_currentMediaStatus);
701 m_progressChangeEvent.reset(
new QWasmEventHandler(m_video,
"progress", progesssCallback));
704 auto pauseCallback = [=](emscripten::val event) {
706 qCDebug(qWasmMediaVideoOutput) <<
"pause";
708 const double currentTime = m_video[
"currentTime"].as<
double>();
709 const double duration = m_video[
"duration"].as<
double>();
710 if ((currentTime > 0 && currentTime < duration) && (!m_shouldStop && m_toBePaused)) {
714 m_video.set(
"currentTime", emscripten::val(0));
718 m_pauseChangeEvent.reset(
new QWasmEventHandler(m_video,
"pause", pauseCallback));
723 emscripten::val window = emscripten::val::global(
"window");
725 auto beforeUnloadCallback = [=](emscripten::val event) {
729 m_video.call<
void>(
"removeAttribute", emscripten::val(
"src"));
730 m_video.call<
void>(
"load");
732 m_beforeUnloadEvent.reset(
new QWasmEventHandler(window,
"beforeunload", beforeUnloadCallback));
854 emscripten::val videoElement = videoOutput->currentVideoElement();
855 emscripten::val oneVideoFrame = val::global(
"VideoFrame").new_(videoElement);
857 if (oneVideoFrame.isNull() || oneVideoFrame.isUndefined()) {
858 qCDebug(qWasmMediaVideoOutput) << Q_FUNC_INFO
859 <<
"ERROR" <<
"failed to construct VideoFrame";
863 emscripten::val options = emscripten::val::object();
864 emscripten::val rectOptions = emscripten::val::object();
866 rectOptions.set(
"width",oneVideoFrame[
"displayWidth"].as<
int>());
867 rectOptions.set(
"height", oneVideoFrame[
"displayHeight"].as<
int>());
868 options.set(
"rect", rectOptions);
870 emscripten::val frameBytesAllocationSize = oneVideoFrame.call<emscripten::val>(
"allocationSize", options);
871 emscripten::val frameBuffer =
872 emscripten::val::global(
"Uint8Array").new_(frameBytesAllocationSize);
874 reinterpret_cast<QWasmVideoOutput*>(videoElement[
"data-qvideocontext"].as<quintptr>());
876 qstdweb::PromiseCallbacks copyToCallback;
877 copyToCallback.thenFunc = [wasmVideoOutput, oneVideoFrame, frameBuffer, videoElement]
878 (emscripten::val frameLayout)
880 if (frameLayout.isNull() || frameLayout.isUndefined()) {
881 qCDebug(qWasmMediaVideoOutput) <<
"theres no frameLayout";
886 const QSize frameSize(oneVideoFrame[
"displayWidth"].as<
int>(),
887 oneVideoFrame[
"displayHeight"].as<
int>());
889 QByteArray frameBytes = QByteArray::fromEcmaUint8Array(frameBuffer);
891 QVideoFrameFormat::PixelFormat pixelFormat = fromJsPixelFormat(oneVideoFrame[
"format"].as<std::string>());
892 if (pixelFormat == QVideoFrameFormat::Format_Invalid) {
893 qWarning() <<
"Invalid pixel format";
896 QVideoFrameFormat frameFormat = QVideoFrameFormat(frameSize, pixelFormat);
898 auto buffer = std::make_unique<QMemoryVideoBuffer>(
899 std::move(frameBytes),
900 oneVideoFrame[
"codedWidth"].as<
int>());
903 QVideoFramePrivate::createFrame(std::move(buffer), std::move(frameFormat));
905 if (!wasmVideoOutput) {
906 qCDebug(qWasmMediaVideoOutput) <<
"ERROR:"
907 <<
"data-qvideocontext not found";
910 if (!wasmVideoOutput->m_wasmSink) {
911 qWarning() <<
"ERROR ALERT!! video sink not set";
914 wasmVideoOutput->m_wasmSink->setVideoFrame(vFrame);
915 oneVideoFrame.call<emscripten::val>(
"close");
917 copyToCallback.catchFunc = [&, wasmVideoOutput, oneVideoFrame, videoElement](emscripten::val error)
919 qCDebug(qWasmMediaVideoOutput) <<
"Error"
920 << QString::fromStdString(error[
"name"].as<std::string>())
921 << QString::fromStdString(error[
"message"].as<std::string>()) ;
923 oneVideoFrame.call<emscripten::val>(
"close");
928 qstdweb::Promise::make(oneVideoFrame, u"copyTo"_s, std::move(copyToCallback), frameBuffer);