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