File indexing completed on 2025-02-23 04:35:13

0001 // SPDX-FileCopyrightText: 2021 Linus Jahn <lnj@kaidan.im>
0002 // SPDX-License-Identifier: GPL-3.0-or-later
0003 
0004 #include "mediaformat.h"
0005 
0006 #include <QJsonObject>
0007 
0008 using namespace QInvidious;
0009 
0010 MediaFormatBase::Container containerFromString(QStringView container)
0011 {
0012     if (container == u"webm") {
0013         return MediaFormatBase::WebM;
0014     }
0015     if (container == u"mp4") {
0016         return MediaFormatBase::Mp4;
0017     }
0018     if (container == u"m4a") {
0019         return MediaFormatBase::M4a;
0020     }
0021     return MediaFormatBase::InvalidContainer;
0022 }
0023 
0024 MediaFormatBase::Codec codecFromString(QStringView codec)
0025 {
0026     if (codec == u"opus") {
0027         return MediaFormatBase::Opus;
0028     }
0029     if (codec == u"aac" || codec.startsWith(u"mp4a")) {
0030         return MediaFormatBase::AAC;
0031     }
0032     if (codec == u"vp9") {
0033         return MediaFormatBase::VP9;
0034     }
0035     if (codec == u"h264" || codec.startsWith(u"avc1")) {
0036         return MediaFormatBase::H264;
0037     }
0038     if (codec.startsWith(u"av01")) {
0039         return MediaFormatBase::AV1;
0040     }
0041     return MediaFormatBase::InvalidCodec;
0042 }
0043 
0044 MediaFormatBase MediaFormatBase::fromJson(const QJsonObject &obj, MediaFormatBase &format)
0045 {
0046     format.m_url = QUrl(obj.value(u"url").toString());
0047     format.m_formatId = obj.value(u"itag").toInt();
0048     format.m_fps = obj.value(u"fps").toInt();
0049     // remove 'p' from "2160p", resolution doesn't contain something like "720p60"
0050     if (const auto resolution = obj.value(u"resolution").toString(); resolution.size() > 1) {
0051         format.m_resolution = resolution.chopped(1).toUInt();
0052     }
0053     format.m_container = containerFromString(obj.value(u"container").toString());
0054     return format;
0055 }
0056 
0057 QUrl MediaFormatBase::url() const
0058 {
0059     return m_url;
0060 }
0061 
0062 uint16_t MediaFormatBase::formatId() const
0063 {
0064     return m_formatId;
0065 }
0066 
0067 uint8_t MediaFormatBase::fps() const
0068 {
0069     return m_fps;
0070 }
0071 
0072 uint16_t MediaFormatBase::resolution() const
0073 {
0074     return m_resolution;
0075 }
0076 
0077 auto MediaFormatBase::container() const -> Container
0078 {
0079     return m_container;
0080 }
0081 
0082 MediaFormat MediaFormat::fromJson(const QJsonObject &obj, MediaFormat &format)
0083 {
0084     MediaFormatBase::fromJson(obj, format);
0085     format.m_bitrate = obj.value(u"bitrate").toInt();
0086     format.m_size = obj.value(u"clen").toInt();
0087     format.m_codec = codecFromString(obj.value(u"encoding").toString());
0088     // the value is provided as a string and in nanoseconds
0089     format.m_createdTimestamp = QDateTime::fromMSecsSinceEpoch(QStringView(obj.value(u"lmt").toString()).toULongLong() / 1000);
0090     return format;
0091 }
0092 
0093 MediaFormat::MediaType MediaFormat::mediaType() const
0094 {
0095     switch (m_codec) {
0096     case Opus:
0097     case AAC:
0098         return Audio;
0099     case VP9:
0100     case H264:
0101     case AV1:
0102         return Video;
0103     case InvalidCodec:
0104         break;
0105     }
0106     return Unknown;
0107 }
0108 
0109 uint32_t MediaFormat::bitrate() const
0110 {
0111     return m_bitrate;
0112 }
0113 
0114 void MediaFormat::setBitrate(uint32_t bitrate)
0115 {
0116     m_bitrate = bitrate;
0117 }
0118 
0119 uint64_t MediaFormat::size() const
0120 {
0121     return m_size;
0122 }
0123 
0124 void MediaFormat::setSize(uint64_t size)
0125 {
0126     m_size = size;
0127 }
0128 
0129 auto MediaFormat::codec() const -> Codec
0130 {
0131     return m_codec;
0132 }
0133 
0134 void MediaFormat::setCodec(Codec codec)
0135 {
0136     m_codec = codec;
0137 }
0138 
0139 QDateTime MediaFormat::createdTimestamp() const
0140 {
0141     return m_createdTimestamp;
0142 }
0143 
0144 void MediaFormat::setCreatedTimestamp(const QDateTime &createdTimestamp)
0145 {
0146     m_createdTimestamp = createdTimestamp;
0147 }
0148 
0149 MediaFormatCombined MediaFormatCombined::fromJson(const QJsonObject &obj, MediaFormatCombined &format)
0150 {
0151     MediaFormatBase::fromJson(obj, format);
0152     // something like: "video/mp4; codecs=\"avc1.42001E, mp4a.40.2\""
0153     const auto codecsStr = obj.value(u"format").toString();
0154     const QStringView codecs = codecsStr;
0155     const auto codecsStart = codecs.indexOf(u'"');
0156     const auto codecsLength = codecsStart - codecs.indexOf(u'"', codecsStart);
0157     const auto codecList = codecs.mid(codecsStart, codecsLength).split(u", ");
0158     if (codecList.size() >= 1) {
0159         format.m_videoCodec = codecFromString(codecList[0]);
0160         if (codecList.size() >= 2) {
0161             format.m_audioCodec = codecFromString(codecList[1]);
0162         }
0163     }
0164     return format;
0165 }
0166 
0167 auto MediaFormatCombined::audioCodec() const -> Codec
0168 {
0169     return m_audioCodec;
0170 }
0171 
0172 void MediaFormatCombined::setAudioCodec(Codec audioCodec)
0173 {
0174     m_audioCodec = audioCodec;
0175 }
0176 
0177 auto MediaFormatCombined::videoCodec() const -> Codec
0178 {
0179     return m_videoCodec;
0180 }
0181 
0182 void MediaFormatCombined::setVideoCodec(Codec videoCodec)
0183 {
0184     m_videoCodec = videoCodec;
0185 }