File indexing completed on 2024-04-28 04:51:59
0001 /* 0002 SPDX-FileCopyrightText: 2012 Simon A. Eugster (Granjow) <simon.eu@gmail.com> 0003 SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL 0004 */ 0005 0006 #include "audioStreamInfo.h" 0007 #include "kdenlivesettings.h" 0008 0009 #include "kdenlive_debug.h" 0010 #include <KLocalizedString> 0011 #include <cstdlib> 0012 0013 AudioStreamInfo::AudioStreamInfo(const std::shared_ptr<Mlt::Producer> &producer, int audioStreamIndex, bool playlist) 0014 : m_audioStreamIndex(audioStreamIndex) 0015 , m_ffmpegAudioIndex(0) 0016 , m_samplingRate(48000) 0017 , m_channels(2) 0018 , m_bitRate(0) 0019 { 0020 // Fetch audio streams 0021 int streams = producer->get_int("meta.media.nb_streams"); 0022 if (playlist && streams == 0) { 0023 // Playlist clips do not provide stream info 0024 m_audioStreams.insert(0, i18n("Audio")); 0025 // TODO: compute playlist channels 0026 m_audioChannels.insert(0, 2); 0027 } 0028 int streamIndex = 1; 0029 for (int ix = 0; ix < streams; ix++) { 0030 char property[200]; 0031 snprintf(property, sizeof(property), "meta.media.%d.stream.type", ix); 0032 QString type = producer->get(property); 0033 if (type == QLatin1String("audio")) { 0034 memset(property, 0, 200); 0035 snprintf(property, sizeof(property), "meta.media.%d.codec.channels", ix); 0036 int chan = producer->get_int(property); 0037 memset(property, 0, 200); 0038 snprintf(property, sizeof(property), "kdenlive:streamname.%d", ix); 0039 QString channelDescription = producer->get(property); 0040 if (channelDescription.isEmpty()) { 0041 channelDescription = QString("%1|").arg(streamIndex++); 0042 switch (chan) { 0043 case 1: 0044 channelDescription.append(i18n("Mono ")); 0045 break; 0046 case 2: 0047 channelDescription.append(i18n("Stereo ")); 0048 break; 0049 default: 0050 channelDescription.append(i18n("%1 channels ", chan)); 0051 break; 0052 } 0053 // Frequency 0054 memset(property, 0, 200); 0055 snprintf(property, sizeof(property), "meta.media.%d.codec.sample_rate", ix); 0056 QString frequency(producer->get(property)); 0057 if (frequency.endsWith(QLatin1String("000"))) { 0058 frequency.chop(3); 0059 frequency.append(i18n("kHz ")); 0060 } else { 0061 frequency.append(i18n("Hz ")); 0062 } 0063 channelDescription.append(frequency); 0064 memset(property, 0, 200); 0065 snprintf(property, sizeof(property), "meta.media.%d.codec.name", ix); 0066 channelDescription.append(producer->get(property)); 0067 } else { 0068 streamIndex++; 0069 } 0070 m_audioStreams.insert(ix, channelDescription); 0071 m_audioChannels.insert(ix, chan); 0072 } 0073 } 0074 QString active = producer->get("kdenlive:active_streams"); 0075 updateActiveStreams(active); 0076 if (m_audioStreams.count() > 1 && active.isEmpty()) { 0077 // initialize enabled streams 0078 QStringList streamString; 0079 for (int streamIx : qAsConst(m_activeStreams)) { 0080 streamString << QString::number(streamIx); 0081 } 0082 producer->set("kdenlive:active_streams", streamString.join(QLatin1Char(';')).toUtf8().constData()); 0083 } 0084 0085 if (audioStreamIndex > -1) { 0086 QByteArray key; 0087 key = QStringLiteral("meta.media.%1.codec.sample_fmt").arg(audioStreamIndex).toLocal8Bit(); 0088 m_samplingFormat = QString::fromLatin1(producer->get(key.data())); 0089 0090 key = QStringLiteral("meta.media.%1.codec.sample_rate").arg(audioStreamIndex).toLocal8Bit(); 0091 m_samplingRate = producer->get_int(key.data()); 0092 0093 key = QStringLiteral("meta.media.%1.codec.bit_rate").arg(audioStreamIndex).toLocal8Bit(); 0094 m_bitRate = producer->get_int(key.data()); 0095 0096 key = QStringLiteral("meta.media.%1.codec.channels").arg(audioStreamIndex).toLocal8Bit(); 0097 m_channels = producer->get_int(key.data()); 0098 setAudioIndex(producer, m_audioStreamIndex); 0099 } 0100 } 0101 0102 AudioStreamInfo::~AudioStreamInfo() = default; 0103 0104 int AudioStreamInfo::samplingRate() const 0105 { 0106 return m_samplingRate; 0107 } 0108 0109 int AudioStreamInfo::channels() const 0110 { 0111 return m_channels; 0112 } 0113 0114 QMap<int, QString> AudioStreamInfo::streams() const 0115 { 0116 return m_audioStreams; 0117 } 0118 0119 QMap<int, int> AudioStreamInfo::streamChannels() const 0120 { 0121 return m_audioChannels; 0122 } 0123 0124 int AudioStreamInfo::channelsForStream(int stream) const 0125 { 0126 if (m_audioChannels.contains(stream)) { 0127 return m_audioChannels.value(stream); 0128 } 0129 return m_channels; 0130 } 0131 0132 QList<int> AudioStreamInfo::activeStreamChannels() const 0133 { 0134 if (m_activeStreams.size() == 1 && m_activeStreams.contains(INT_MAX)) { 0135 return m_audioChannels.values(); 0136 } 0137 QList<int> activeChannels; 0138 QMapIterator<int, QString> i(m_audioStreams); 0139 while (i.hasNext()) { 0140 i.next(); 0141 if (m_activeStreams.contains(i.key())) { 0142 activeChannels << m_audioChannels.value(i.key()); 0143 } 0144 } 0145 return activeChannels; 0146 } 0147 0148 QMap<int, QString> AudioStreamInfo::activeStreams() const 0149 { 0150 QMap<int, QString> active; 0151 QMapIterator<int, QString> i(m_audioStreams); 0152 if (m_activeStreams.size() == 1 && m_activeStreams.contains(INT_MAX)) { 0153 active.insert(INT_MAX, i18n("Merged streams")); 0154 } else { 0155 while (i.hasNext()) { 0156 i.next(); 0157 if (m_activeStreams.contains(i.key())) { 0158 active.insert(i.key(), i.value()); 0159 } 0160 } 0161 } 0162 return active; 0163 } 0164 0165 int AudioStreamInfo::bitrate() const 0166 { 0167 return m_bitRate; 0168 } 0169 0170 int AudioStreamInfo::audio_index() const 0171 { 0172 return m_audioStreamIndex; 0173 } 0174 0175 int AudioStreamInfo::ffmpeg_audio_index() const 0176 { 0177 return m_ffmpegAudioIndex; 0178 } 0179 0180 void AudioStreamInfo::dumpInfo() const 0181 { 0182 qCDebug(KDENLIVE_LOG) << "Info for audio stream " << m_audioStreamIndex << "\n\tChannels: " << m_channels << "\n\tSampling rate: " << m_samplingRate 0183 << "\n\tBit rate: " << m_bitRate; 0184 } 0185 0186 void AudioStreamInfo::setAudioIndex(const std::shared_ptr<Mlt::Producer> &producer, int ix) 0187 { 0188 m_audioStreamIndex = ix; 0189 if (ix > -1) { 0190 int streams = producer->get_int("meta.media.nb_streams"); 0191 QList<int> audioStreams; 0192 for (int i = 0; i < streams; ++i) { 0193 QByteArray propertyName = QStringLiteral("meta.media.%1.stream.type").arg(i).toLocal8Bit(); 0194 QString type = producer->get(propertyName.data()); 0195 if (type == QLatin1String("audio")) { 0196 audioStreams << i; 0197 } 0198 } 0199 if (audioStreams.count() > 1 && m_audioStreamIndex < audioStreams.count()) { 0200 m_ffmpegAudioIndex = audioStreams.indexOf(m_audioStreamIndex); 0201 } 0202 } 0203 } 0204 0205 void AudioStreamInfo::updateActiveStreams(const QString &activeStreams) 0206 { 0207 // -1 = disable all audio 0208 // empty = enable all audio or first depending on config 0209 m_activeStreams.clear(); 0210 if (activeStreams.isEmpty()) { 0211 switch (KdenliveSettings::multistream()) { 0212 case 1: 0213 // Enable first stream only 0214 m_activeStreams << m_audioStreams.firstKey(); 0215 break; 0216 case 2: 0217 // Enable the first two streams only 0218 { 0219 QList<int> str = m_audioStreams.keys(); 0220 while (!str.isEmpty()) { 0221 m_activeStreams << str.takeFirst(); 0222 if (m_activeStreams.size() == 2) { 0223 break; 0224 } 0225 } 0226 break; 0227 } 0228 default: 0229 // Enable all streams 0230 m_activeStreams = m_audioStreams.keys(); 0231 break; 0232 } 0233 return; 0234 } 0235 QStringList st = activeStreams.split(QLatin1Char(';')); 0236 for (const QString &s : qAsConst(st)) { 0237 m_activeStreams << s.toInt(); 0238 } 0239 } 0240 0241 void AudioStreamInfo::renameStream(int ix, const QString &streamName) 0242 { 0243 if (m_audioStreams.contains(ix)) { 0244 m_audioStreams.insert(ix, streamName); 0245 } 0246 }