20template <
typename StreamInfo>
21struct GstDiscovererStreamInfoList : QGstUtils::GListRangeAdaptor<StreamInfo *>
23 using BaseType = QGstUtils::GListRangeAdaptor<StreamInfo *>;
24 using BaseType::BaseType;
26 ~GstDiscovererStreamInfoList() { gst_discoverer_stream_info_list_free(BaseType::head); }
29QGstTagListHandle duplicateTagList(
const GstTagList *tagList)
33 return QGstTagListHandle{
34 gst_tag_list_copy(tagList),
35 QGstTagListHandle::HasRef,
43 result.streamID = QString::fromUtf8(gst_discoverer_stream_info_get_stream_id(info));
44 result.tags = duplicateTagList(gst_discoverer_stream_info_get_tags(info));
46 result
.streamNumber = gst_discoverer_stream_info_get_stream_number(info);
48 result.caps = QGstCaps{
49 gst_discoverer_stream_info_get_caps(info),
57constexpr bool isStreamInfo = std::is_same_v<std::decay_t<T>, GstDiscovererVideoInfo>
58 || std::is_same_v<std::decay_t<T>, GstDiscovererAudioInfo>
59 || std::is_same_v<std::decay_t<T>, GstDiscovererSubtitleInfo>
60 || std::is_same_v<std::decay_t<T>, GstDiscovererContainerInfo>;
65 static_assert(isStreamInfo<T>);
66 return parseGstDiscovererStreamInfo(GST_DISCOVERER_STREAM_INFO(info));
72 static_cast<QGstDiscovererStreamInfo &>(result) = parseGstDiscovererStreamInfo(info);
75 int(gst_discoverer_video_info_get_width(info)),
76 int(gst_discoverer_video_info_get_height(info)),
79 result
.bitDepth = gst_discoverer_video_info_get_depth(info);
80 result.framerate = Fraction{
81 int(gst_discoverer_video_info_get_framerate_num(info)),
82 int(gst_discoverer_video_info_get_framerate_denom(info)),
85 result.pixelAspectRatio = Fraction{
86 int(gst_discoverer_video_info_get_par_num(info)),
87 int(gst_discoverer_video_info_get_par_denom(info)),
90 result
.isInterlaced = gst_discoverer_video_info_is_interlaced(info);
91 result
.bitrate =
int(gst_discoverer_video_info_get_bitrate(info));
92 result
.maxBitrate =
int(gst_discoverer_video_info_get_max_bitrate(info));
93 result
.isImage =
int(gst_discoverer_video_info_is_image(info));
101 static_cast<QGstDiscovererStreamInfo &>(result) = parseGstDiscovererStreamInfo(info);
103 result
.channels =
int(gst_discoverer_audio_info_get_channels(info));
104 result.channelMask = gst_discoverer_audio_info_get_channel_mask(info);
105 result
.sampleRate = gst_discoverer_audio_info_get_sample_rate(info);
108 result
.bitrate =
int(gst_discoverer_audio_info_get_bitrate(info));
109 result
.maxBitrate =
int(gst_discoverer_audio_info_get_max_bitrate(info));
110 result.language = QGstUtils::codeToLanguage(gst_discoverer_audio_info_get_language(info));
118 static_cast<QGstDiscovererStreamInfo &>(result) = parseGstDiscovererStreamInfo(info);
119 result.language = QGstUtils::codeToLanguage(gst_discoverer_subtitle_info_get_language(info));
126 static_cast<QGstDiscovererStreamInfo &>(result) = parseGstDiscovererStreamInfo(info);
128 result.tags = duplicateTagList(gst_discoverer_container_info_get_tags(info));
138 result
.isLive = gst_discoverer_info_get_live(info);
139 result
.isSeekable = gst_discoverer_info_get_seekable(info);
141 GstClockTime duration = gst_discoverer_info_get_duration(info);
142 if (duration != GST_CLOCK_TIME_NONE)
143 result.duration =
std::chrono::nanoseconds{ duration };
145 QGstDiscovererStreamInfoHandle streamInfo{
146 gst_discoverer_info_get_stream_info(info),
147 QGstDiscovererStreamInfoHandle::HasRef,
149 if (streamInfo && GST_IS_DISCOVERER_CONTAINER_INFO(streamInfo.get()))
150 result.containerInfo =
151 parseGstDiscovererContainerInfo(GST_DISCOVERER_CONTAINER_INFO(streamInfo.get()));
152 result.tags = duplicateTagList(gst_discoverer_info_get_tags(info));
154 GstDiscovererStreamInfoList<GstDiscovererVideoInfo> videoStreams{
155 gst_discoverer_info_get_video_streams(info),
157 for (GstDiscovererVideoInfo *videoInfo : videoStreams) {
158 QGstDiscovererVideoInfo item = parseGstDiscovererVideoInfo(videoInfo);
159 if (!item.streamID.isNull())
160 result.videoStreams.emplace_back(std::move(item));
162 GstDiscovererStreamInfoList<GstDiscovererAudioInfo> audioStreams{
163 gst_discoverer_info_get_audio_streams(info),
165 for (GstDiscovererAudioInfo *audioInfo : audioStreams) {
166 QGstDiscovererAudioInfo item = parseGstDiscovererAudioInfo(audioInfo);
167 if (!item.streamID.isNull())
168 result.audioStreams.emplace_back(std::move(item));
170 GstDiscovererStreamInfoList<GstDiscovererSubtitleInfo> subtitleStreams{
171 gst_discoverer_info_get_subtitle_streams(info),
173 for (GstDiscovererSubtitleInfo *subtitleInfo : subtitleStreams) {
174 QGstDiscovererSubtitleInfo item = parseGstDiscovererSubtitleInfo(subtitleInfo);
175 if (!item.streamID.isNull())
176 result.subtitleStreams.emplace_back(std::move(item));
179 GstDiscovererStreamInfoList<GstDiscovererContainerInfo> containerStreams{
180 gst_discoverer_info_get_container_streams(info),
182 for (GstDiscovererContainerInfo *containerInfo : containerStreams)
183 result.containerStreams.emplace_back(parseGstDiscovererContainerInfo(containerInfo));
204 return discover(uri.toUtf8().constData());
207q23::expected<QGstDiscovererInfo, QUniqueGErrorHandle>
QGstDiscoverer::discover(
const QUrl &url)
209 return discover(url.toEncoded().constData());
212q23::expected<QGstDiscovererInfo, QUniqueGErrorHandle>
QGstDiscoverer::discover(QIODevice *device)
214 return discover(qGstRegisterQIODevice(device));
217q23::expected<QGstDiscovererInfo, QUniqueGErrorHandle>
QGstDiscoverer::discover(
const char *uri)
219 QUniqueGErrorHandle error;
220 QGstDiscovererInfoHandle info{
221 gst_discoverer_discover_uri(m_instance.get(), uri, &error),
222 QGstDiscovererInfoHandle::HasRef,
226 return q23::unexpected{
238 QMediaMetaData metadata;
239 using Key = QMediaMetaData::Key;
240 using namespace std::chrono;
242 if (info.containerInfo)
243 extendMetaDataFromTagList(metadata, info.containerInfo->tags);
245 extendMetaDataFromTagList(metadata, info.tags);
247 auto updateMetadata = [&](Key key,
auto value) {
248 QVariant currentValue = metadata.value(key);
249 if (!currentValue.isValid() || currentValue != value)
250 metadata.insert(key, value);
254 updateMetadata(Key::Duration,
255 QVariant::fromValue(round<milliseconds>(*info.duration).count()));
262 QMediaMetaData tagMetaData = taglistToMetaData(tagList);
263 for (
auto element : tagMetaData.asKeyValueRange()) {
264 if (metadata.keys().contains(element.first))
267 metadata.insert(element.first, element.second);
271template <
typename ValueType>
272static void updateMetadata(QMediaMetaData &metadata, QMediaMetaData::Key key, ValueType value)
274 QVariant currentValue = metadata.value(key);
275 if (!currentValue.isValid() || currentValue != value)
276 metadata.insert(key, value);
281 QMediaMetaData metadata;
282 using Key = QMediaMetaData::Key;
284 updateMetadata(metadata, Key::VideoBitRate, info.bitrate);
286 extendMetaDataFromCaps(metadata, info
.caps);
287 addMissingKeysFromTaglist(metadata, info.tags);
294 QMediaMetaData metadata;
295 using Key = QMediaMetaData::Key;
297 updateMetadata(metadata, Key::AudioBitRate, info.bitrate);
298 updateMetadata(metadata, Key::Language, info.language);
300 extendMetaDataFromCaps(metadata, info
.caps);
301 addMissingKeysFromTaglist(metadata, info.tags);
308 QMediaMetaData metadata;
309 using Key = QMediaMetaData::Key;
311 updateMetadata(metadata, Key::Language, info.language);
313 extendMetaDataFromCaps(metadata, info
.caps);
314 addMissingKeysFromTaglist(metadata, info.tags);