653{
654 QJsonObject ffmpegInfo =
m_ui.cmbFFMpegLocation->currentData().toJsonObject();
655 QJsonObject ffprobeInfo =
m_ui.cmbFFProbeLocation->currentData().toJsonObject();
657
659 QJsonObject ffprobeJsonObj;
660
661 std::function<
void(
void)> warnFFmpegFormatSupport = [
this](){
662 QMessageBox::warning(this, i18nc("@title:window", "Krita"), i18n("Your FFMpeg version does not support this format"));
663 };
664
665 if (ffprobeInfo["enabled"].toBool()) {
666 ffprobeJsonObj = ffprobe->ffprobe(inputFile, ffprobeInfo[
"path"].
toString());
667 }
668
669
672
674
675 dbgFile <<
"ffmpeg probe1" << ffprobeJsonObj;
676
677 QJsonObject ffprobeProgress = ffprobeJsonObj["progress"].toObject();
678
679 videoInfoData.frames = ffprobeProgress["frame"].toString().toInt();
680 }
681
683
684 warnFFmpegFormatSupport();
685 return {};
687
688 QJsonObject ffprobeFormat = ffprobeJsonObj["format"].toObject();
689 QJsonArray ffprobeStreams = ffprobeJsonObj["streams"].toArray();
690
691 videoInfoData.file = inputFile;
692 for (const QJsonValueRef &streamItemRef : ffprobeStreams) {
693 QJsonObject streamItemObj = streamItemRef.toObject();
694
695 if ( streamItemObj[
"codec_type"].
toString() ==
"video" ) {
696 videoInfoData.stream = streamItemObj["index"].toInt();
697 break;
698 }
699 }
700
701 if ( videoInfoData.stream == -1 ) {
702 QMessageBox::warning(this, i18nc("@title:window", "Krita"), i18n("No video stream could be found!"));
703 return {};
704 }
705
706 const QJsonObject ffprobeSelectedStream = ffprobeStreams[videoInfoData.stream].toObject();
707
708 const QJsonObject decoders = ffmpegInfo.value("codecs").toObject();
709
710 const QString codecName = ffprobeSelectedStream["codec_name"].toString();
711
712 const auto decoder = decoders.constFind(codecName);
713
714 if (decoder == decoders.constEnd() ) {
715 dbgFile <<
"Codec missing or unsupported:" << codecName;
716 warnFFmpegFormatSupport();
717 return {};
718 } else if (!decoder->toObject().value("decoding").toBool()) {
719 dbgFile <<
"Codec not supported for decoding:" << codecName;
720 warnFFmpegFormatSupport();
721 return {};
722 }
723
724 videoInfoData.width = ffprobeSelectedStream["width"].toInt();
725 videoInfoData.height = ffprobeSelectedStream["height"].toInt();
726 videoInfoData.encoding = ffprobeSelectedStream["codec_name"].toString();
729
730
731 if (ffprobeSelectedStream.value("bits_per_raw_sample").toInt() > 8) {
733 } else {
735 }
736
737
738
739 QStringList rawFrameRate = ffprobeSelectedStream[
"r_frame_rate"].toString().split(
'/');
740
741 if (!rawFrameRate.isEmpty())
742 videoInfoData.fps = qCeil(rawFrameRate[0].toFloat() / rawFrameRate[1].toFloat());
743
744 if ( !ffprobeSelectedStream["nb_frames"].isNull() ) {
745 videoInfoData.frames = ffprobeSelectedStream["nb_frames"].toString().toInt();
746 }
747
748
749 if ( !ffprobeSelectedStream["duration"].isNull() ) {
750 videoInfoData.duration = ffprobeSelectedStream["duration"].toString().toFloat();
751 } else if ( !ffprobeFormat["duration"].isNull() ) {
752 videoInfoData.duration = ffprobeFormat["duration"].toString().toFloat();
753 } else if ( videoInfoData.frames ) {
754 videoInfoData.duration = videoInfoData.frames / videoInfoData.fps;
755 }
756
757 dbgFile <<
"Initial video info from probe: "
758 << "stream:" << videoInfoData.stream
759 << "frames:" << videoInfoData.frames
760 << "duration:" << videoInfoData.duration
761 << "fps:" << videoInfoData.fps
762 << "encoding:" << videoInfoData.encoding;
763
764 if ( !videoInfoData.frames && !videoInfoData.duration ) {
766
767 QJsonObject ffmpegJsonObj = ffmpeg->
ffmpegProbe(inputFile, ffmpegInfo[
"path"].
toString(),
false);
768
769 dbgFile <<
"ffmpeg probe2" << ffmpegJsonObj;
770
772 QMessageBox::warning(this, i18nc("@title:window", "Krita"), i18n("Failed to load video information"));
773 return {};
774 }
775
776 QJsonObject ffmpegProgressJsonObj = ffmpegJsonObj["progress"].toObject();
777 float ffmpegFPS = ffmpegProgressJsonObj["ffmpeg_fps"].toString().toFloat();
778
779 videoInfoData.frames = ffmpegProgressJsonObj["frame"].toString().toInt();
780
781 if (ffmpegFPS > 0 && videoInfoData.frames) {
782 videoInfoData.duration = videoInfoData.frames / ffmpegFPS;
783 videoInfoData.fps = ffmpegFPS;
784 } else {
785 videoInfoData.duration = ffmpegProgressJsonObj["out_time_ms"].toString().toFloat() / 1000000;
786 if (videoInfoData.frames) videoInfoData.fps = videoInfoData.frames / videoInfoData.duration;
787 }
788
789 }
790 }
791
792
793 if ( videoInfoData.fps && videoInfoData.duration && !videoInfoData.frames ) {
794 videoInfoData.frames = qCeil( videoInfoData.fps * videoInfoData.duration );
795 }
796
797 dbgFile <<
"Final video info from probe: "
798 << "stream:" << videoInfoData.stream
799 << "frames:" << videoInfoData.frames
800 << "duration:" << videoInfoData.duration
801 << "fps:" << videoInfoData.fps
802 << "encoding:" << videoInfoData.encoding;
803
804 const float calculatedFrameRateByDuration = videoInfoData.frames / videoInfoData.duration;
805 const int frameRateDifference = qAbs(videoInfoData.fps - calculatedFrameRateByDuration);
806
807 if (frameRateDifference > 1) {
808
809
810 videoInfoData.hasOverriddenFPS = true;
811 videoInfoData.fps = calculatedFrameRateByDuration;
812 } else {
813 videoInfoData.hasOverriddenFPS = false;
814 }
815
816 return videoInfoData;
817}
const KoID Integer8BitsColorDepthID("U8", ki18n("8-bit integer/channel"))
const KoID Integer16BitsColorDepthID("U16", ki18n("16-bit integer/channel"))
static TransferCharacteristics transferCharacteristicsFromName(QString name)
QJsonObject ffmpegProbe(const QString &inputFile, const QString &ffmpegPath, bool batchMode)
static ColorPrimaries colorPrimariesFromName(QString name)
typedef void(QOPENGLF_APIENTRYP PFNGLINVALIDATEBUFFERDATAPROC)(GLuint buffer)
int toInt(const QString &str, bool *ok=nullptr)