Skip to content

Commit 7531650

Browse files
committed
[YouTube] Extract the audioChannels and the approxDurationMs values
The first is only returned for audio streams, the second only for progressive streams. These values are stored in the ItagItem class. Some default constants have been also added.
1 parent f3bcde1 commit 7531650

3 files changed

Lines changed: 109 additions & 15 deletions

File tree

extractor/src/main/java/org/schabi/newpipe/extractor/services/youtube/ItagItem.java

Lines changed: 70 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,8 @@ public static ItagItem getItag(final int itagId) throws ParsingException {
111111
public static final int SAMPLE_RATE_UNKNOWN = -1;
112112
public static final int FPS_UNKNOWN = -1;
113113
public static final int TARGET_DURATION_SEC_UNKNOWN = -1;
114+
public static final int APPROX_DURATION_MS_UNKNOWN = -1;
115+
public static final int AUDIO_CHANNELS_NOT_APPLICABLE_OR_UNKNOWN = -1;
114116

115117
/*//////////////////////////////////////////////////////////////////////////
116118
// Constructors and misc
@@ -174,6 +176,7 @@ public MediaFormat getMediaFormat() {
174176
// Audio fields
175177
public int avgBitrate = AVERAGE_BITRATE_UNKNOWN;
176178
private int sampleRate = SAMPLE_RATE_UNKNOWN;
179+
private int audioChannels = AUDIO_CHANNELS_NOT_APPLICABLE_OR_UNKNOWN;
177180

178181
// Video fields
179182
public String resolutionString;
@@ -190,6 +193,7 @@ public MediaFormat getMediaFormat() {
190193
private String quality;
191194
private String codec;
192195
private int targetDurationSec = TARGET_DURATION_SEC_UNKNOWN;
196+
private int approxDurationMs = APPROX_DURATION_MS_UNKNOWN;
193197

194198
public int getBitrate() {
195199
return bitrate;
@@ -263,6 +267,59 @@ public void setCodec(final String codec) {
263267
this.codec = codec;
264268
}
265269

270+
/**
271+
* Get the sample rate.
272+
* <p>
273+
* It is only known for audio streams, so {@link #SAMPLE_RATE_UNKNOWN} is returned for video
274+
* streams or if the sample rate is unknown.
275+
* </p>
276+
*
277+
* @return the sample rate or {@link #SAMPLE_RATE_UNKNOWN}
278+
*/
279+
public int getSampleRate() {
280+
return sampleRate;
281+
}
282+
283+
/**
284+
* Set the sample rate.
285+
* <p>
286+
* It is only known for audio streams, so {@link #SAMPLE_RATE_UNKNOWN} is set for video
287+
* streams or if the sample rate value is less than or equal to 0.
288+
* </p>
289+
*/
290+
public void setSampleRate(final int sampleRate) {
291+
if (sampleRate > 0) {
292+
this.sampleRate = sampleRate;
293+
}
294+
}
295+
296+
/**
297+
* Get the number of audio channels.
298+
* <p>
299+
* It is only known for audio streams, so {@link #AUDIO_CHANNELS_NOT_APPLICABLE_OR_UNKNOWN} is
300+
* returned for video streams or if it is unknown.
301+
* </p>
302+
*
303+
* @return the number of audio channels or {@link #AUDIO_CHANNELS_NOT_APPLICABLE_OR_UNKNOWN}
304+
*/
305+
public int getAudioChannels() {
306+
return audioChannels;
307+
}
308+
309+
/**
310+
* Set the number of audio channels.
311+
* <p>
312+
* It is only known for audio streams, so {@link #AUDIO_CHANNELS_NOT_APPLICABLE_OR_UNKNOWN} is
313+
* set for video streams or if the {@code audioChannels} value is less than or equal to 0.
314+
* </p>
315+
* @param audioChannels the number of audio channels
316+
*/
317+
public void setAudioChannels(final int audioChannels) {
318+
if (audioChannels > 0) {
319+
this.audioChannels = audioChannels;
320+
}
321+
}
322+
266323
/**
267324
* Get the {@code targetDurationSec} value.
268325
* <p>
@@ -271,7 +328,7 @@ public void setCodec(final String codec) {
271328
* videos, so {@link #TARGET_DURATION_SEC_UNKNOWN} is returned for video streams.
272329
* </p>
273330
*
274-
* @return the targetDurationSec value or {@link #TARGET_DURATION_SEC_UNKNOWN}
331+
* @return the {@code targetDurationSec} value or {@link #TARGET_DURATION_SEC_UNKNOWN}
275332
*/
276333
public int getTargetDurationSec() {
277334
return targetDurationSec;
@@ -285,7 +342,6 @@ public int getTargetDurationSec() {
285342
* videos, so {@link #TARGET_DURATION_SEC_UNKNOWN} will be set for video streams or if this
286343
* value is less than or equal to 0.
287344
* </p>
288-
*
289345
*/
290346
public void setTargetDurationSec(final int targetDurationSec) {
291347
if (targetDurationSec > 0) {
@@ -294,28 +350,28 @@ public void setTargetDurationSec(final int targetDurationSec) {
294350
}
295351

296352
/**
297-
* Get the sample rate.
353+
* Get the {@code approxDurationMs} value.
298354
* <p>
299-
* It is only known for audio streams, so {@link #SAMPLE_RATE_UNKNOWN} is returned for video
300-
* streams or if the sample rate is unknown.
355+
* It is only known for DASH progressive streams, so {@link #APPROX_DURATION_MS_UNKNOWN} is
356+
* returned for other stream types or if this value is less than or equal to 0.
301357
* </p>
302358
*
303-
* @return the sample rate or {@link #SAMPLE_RATE_UNKNOWN}
359+
* @return the {@code approxDurationMs} value or {@link #APPROX_DURATION_MS_UNKNOWN}
304360
*/
305-
public int getSampleRate() {
306-
return sampleRate;
361+
public int getApproxDurationMs() {
362+
return approxDurationMs;
307363
}
308364

309365
/**
310-
* Set the sample rate.
366+
* Set the {@code approxDurationMs} value.
311367
* <p>
312-
* It is only known for audio streams, so {@link #SAMPLE_RATE_UNKNOWN} is set for video
313-
* streams or if the sample rate value is less than or equal to 0.
368+
* It is only known for DASH progressive streams, so {@link #APPROX_DURATION_MS_UNKNOWN} is set
369+
* for other stream types or if this value is less than or equal to 0.
314370
* </p>
315371
*/
316-
public void setSampleRate(final int sampleRate) {
317-
if (sampleRate > 0) {
318-
this.sampleRate = sampleRate;
372+
public void setApproxDurationMs(final int approxDurationMs) {
373+
if (approxDurationMs > 0) {
374+
this.approxDurationMs = approxDurationMs;
319375
}
320376
}
321377
}

extractor/src/main/java/org/schabi/newpipe/extractor/services/youtube/YoutubeDashManifestCreator.java

Lines changed: 38 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,9 @@ public static String createDashManifestFromOtfStreamingUrl(
9595
generateAdaptationSetElement(document, itagItem.getMediaFormat().mimeType);
9696
generateRoleElement(document);
9797
generateRepresentationElement(document, itagItem);
98+
if (itagItem.itagType == ItagItem.ItagType.AUDIO) {
99+
generateAudioChannelConfigurationElement(document, itagItem);
100+
}
98101
generateSegmentTemplateElement(document, otfBaseStreamingUrl, false);
99102
generateSegmentTimelineElement(document);
100103
collectSegmentsData(segmentDuration);
@@ -165,11 +168,15 @@ public static String createDashManifestFromPostLiveStreamDvrStreamingUrl(
165168
"Unable to generate the DASH manifest: could not get the number of segments");
166169
}
167170

168-
final Document document = generateDocumentAndMpdElement(new String[] {streamDuration}, true);
171+
final Document document = generateDocumentAndMpdElement(new String[] {streamDuration},
172+
true);
169173
generatePeriodElement(document);
170174
generateAdaptationSetElement(document, itagItem.getMediaFormat().mimeType);
171175
generateRoleElement(document);
172176
generateRepresentationElement(document, itagItem);
177+
if (itagItem.itagType == ItagItem.ItagType.AUDIO) {
178+
generateAudioChannelConfigurationElement(document, itagItem);
179+
}
173180
generateSegmentTemplateElement(document, postLiveStreamDvrStreamingUrl, true);
174181
generateSegmentTimelineElement(document);
175182
generateSegmentElementsForPostLiveDvrStreams(document, targetDurationSec, segmentCount);
@@ -491,6 +498,36 @@ private static void generateRepresentationElement(@Nonnull final Document docume
491498
}
492499
}
493500

501+
private static void generateAudioChannelConfigurationElement(
502+
@Nonnull final Document document,
503+
@Nonnull final ItagItem itagItem) throws YoutubeDashManifestCreationException {
504+
try {
505+
final Element representationElement = (Element) document.getElementsByTagName(
506+
"Representation").item(0);
507+
final Element audioChannelConfigurationElement = document.createElement(
508+
"AudioChannelConfiguration");
509+
510+
final Attr schemeIdUriAttribute = document.createAttribute("schemeIdUri");
511+
schemeIdUriAttribute.setValue(
512+
"urn:mpeg:dash:23003:3:audio_channel_configuration:2011");
513+
audioChannelConfigurationElement.setAttributeNode(schemeIdUriAttribute);
514+
515+
final Attr valueAttribute = document.createAttribute("value");
516+
final int audioChannels = itagItem.getAudioChannels();
517+
if (audioChannels <= 0) {
518+
throw new YoutubeDashManifestCreationException(
519+
"Could not generate the DASH manifest: the audioChannels value is less than or equal to 0 (" + audioChannels + ")");
520+
}
521+
valueAttribute.setValue(String.valueOf(itagItem.getAudioChannels()));
522+
audioChannelConfigurationElement.setAttributeNode(valueAttribute);
523+
524+
representationElement.appendChild(audioChannelConfigurationElement);
525+
} catch (final DOMException e) {
526+
throw new YoutubeDashManifestCreationException(
527+
"Could not generate or append to the document the AudioChannelConfiguration element of the DASH manifest", e);
528+
}
529+
}
530+
494531
private static void generateSegmentTemplateElement(@Nonnull final Document document,
495532
@Nonnull final String baseUrl,
496533
final boolean isPostLiveDvr)

extractor/src/main/java/org/schabi/newpipe/extractor/services/youtube/extractors/YoutubeStreamExtractor.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1257,6 +1257,7 @@ private List<ItagInfo> getStreamsFromStreamingDataKey(
12571257
if (itagType == ItagItem.ItagType.AUDIO) {
12581258
itagItem.setSampleRate(Integer.parseInt(formatData.getString(
12591259
"audioSampleRate")));
1260+
itagItem.setAudioChannels(formatData.getInt("audioChannels"));
12601261
}
12611262
final ItagInfo itagInfo = new ItagInfo(streamUrl, itagItem);
12621263

0 commit comments

Comments
 (0)