Skip to content

Commit 198a6d4

Browse files
feat(MediaCap): Guess the codecs of multiplexd stream for MediaCap
If we have a multiplexd stream with audio and video, the video codecs are a combined string containing both audio and video codecs. Before sending the request to decodingInfo(), we should check which codec is audio and which one is video. This is a follow-up of commit 966a756. Issue #1391 Change-Id: Ic9b1c5972a99f63a715c74ae068b85f43efac447
1 parent 863e345 commit 198a6d4

File tree

3 files changed

+134
-125
lines changed

3 files changed

+134
-125
lines changed

lib/hls/hls_parser.js

+11-119
Original file line numberDiff line numberDiff line change
@@ -596,17 +596,20 @@ shaka.hls.HlsParser = class {
596596
const allCodecs = this.getCodecsForVariantTag_(variantTag);
597597

598598
if (subGroupId) {
599-
const textCodecs = this.guessCodecsSafe_(ContentType.TEXT, allCodecs);
599+
const textCodecs = shaka.util.ManifestParserUtils.guessCodecsSafe(
600+
ContentType.TEXT, allCodecs);
600601
goog.asserts.assert(textCodecs != null, 'Text codecs should be valid.');
601602
this.groupIdToCodecsMap_.set(subGroupId, textCodecs);
602603
shaka.util.ArrayUtils.remove(allCodecs, textCodecs);
603604
}
604605
if (audioGroupId) {
605-
const codecs = this.guessCodecs_(ContentType.AUDIO, allCodecs);
606+
const codecs = shaka.util.ManifestParserUtils.guessCodecs(
607+
ContentType.AUDIO, allCodecs);
606608
this.groupIdToCodecsMap_.set(audioGroupId, codecs);
607609
}
608610
if (videoGroupId) {
609-
const codecs = this.guessCodecs_(ContentType.VIDEO, allCodecs);
611+
const codecs = shaka.util.ManifestParserUtils.guessCodecs(
612+
ContentType.VIDEO, allCodecs);
610613
this.groupIdToCodecsMap_.set(videoGroupId, codecs);
611614
}
612615
}
@@ -774,8 +777,10 @@ shaka.hls.HlsParser = class {
774777
return audio && audio.verbatimMediaPlaylistUri == streamURI;
775778
});
776779

777-
const videoCodecs = this.guessCodecsSafe_(ContentType.VIDEO, allCodecs);
778-
const audioCodecs = this.guessCodecsSafe_(ContentType.AUDIO, allCodecs);
780+
const videoCodecs = shaka.util.ManifestParserUtils.guessCodecsSafe(
781+
ContentType.VIDEO, allCodecs);
782+
const audioCodecs = shaka.util.ManifestParserUtils.guessCodecsSafe(
783+
ContentType.AUDIO, allCodecs);
779784

780785
if (audioCodecs && !videoCodecs) {
781786
// There are no associated media tags, and there's only audio codec,
@@ -1196,7 +1201,7 @@ shaka.hls.HlsParser = class {
11961201
}
11971202

11981203
const closedCaptions = this.getClosedCaptions_(tag, type);
1199-
const codecs = this.guessCodecs_(type, allCodecs);
1204+
const codecs = shaka.util.ManifestParserUtils.guessCodecs(type, allCodecs);
12001205
const streamInfo = await this.createStreamInfo_(verbatimMediaPlaylistUri,
12011206
codecs, type, /* language= */ 'und', /* primary= */ false,
12021207
/* name= */ null, /* channelcount= */ null, closedCaptions,
@@ -2291,65 +2296,6 @@ shaka.hls.HlsParser = class {
22912296
}
22922297
}
22932298

2294-
/**
2295-
* Attempts to guess which codecs from the codecs list belong to a given
2296-
* content type.
2297-
* Assumes that at least one codec is correct, and throws if none are.
2298-
*
2299-
* @param {string} contentType
2300-
* @param {!Array.<string>} codecs
2301-
* @return {string}
2302-
* @private
2303-
*/
2304-
guessCodecs_(contentType, codecs) {
2305-
if (codecs.length == 1) {
2306-
return codecs[0];
2307-
}
2308-
2309-
const match = this.guessCodecsSafe_(contentType, codecs);
2310-
// A failure is specifically denoted by null; an empty string represents a
2311-
// valid match of no codec.
2312-
if (match != null) {
2313-
return match;
2314-
}
2315-
2316-
// Unable to guess codecs.
2317-
throw new shaka.util.Error(
2318-
shaka.util.Error.Severity.CRITICAL,
2319-
shaka.util.Error.Category.MANIFEST,
2320-
shaka.util.Error.Code.HLS_COULD_NOT_GUESS_CODECS,
2321-
codecs);
2322-
}
2323-
2324-
/**
2325-
* Attempts to guess which codecs from the codecs list belong to a given
2326-
* content type. Does not assume a single codec is anything special, and does
2327-
* not throw if it fails to match.
2328-
*
2329-
* @param {string} contentType
2330-
* @param {!Array.<string>} codecs
2331-
* @return {?string} or null if no match is found
2332-
* @private
2333-
*/
2334-
guessCodecsSafe_(contentType, codecs) {
2335-
const formats =
2336-
shaka.hls.HlsParser.CODEC_REGEXPS_BY_CONTENT_TYPE_[contentType];
2337-
for (const format of formats) {
2338-
for (const codec of codecs) {
2339-
if (format.test(codec.trim())) {
2340-
return codec.trim();
2341-
}
2342-
}
2343-
}
2344-
2345-
// Text does not require a codec string.
2346-
if (contentType == shaka.util.ManifestParserUtils.ContentType.TEXT) {
2347-
return '';
2348-
}
2349-
2350-
return null;
2351-
}
2352-
23532299
/**
23542300
* Replaces the variables of a given URI.
23552301
*
@@ -2719,60 +2665,6 @@ shaka.hls.HlsParser.StreamInfo;
27192665
shaka.hls.HlsParser.StreamInfos;
27202666

27212667

2722-
/**
2723-
* A list of regexps to detect well-known video codecs.
2724-
*
2725-
* @const {!Array.<!RegExp>}
2726-
* @private
2727-
*/
2728-
shaka.hls.HlsParser.VIDEO_CODEC_REGEXPS_ = [
2729-
/^avc/,
2730-
/^hev/,
2731-
/^hvc/,
2732-
/^vp0?[89]/,
2733-
/^av1$/,
2734-
];
2735-
2736-
2737-
/**
2738-
* A list of regexps to detect well-known audio codecs.
2739-
*
2740-
* @const {!Array.<!RegExp>}
2741-
* @private
2742-
*/
2743-
shaka.hls.HlsParser.AUDIO_CODEC_REGEXPS_ = [
2744-
/^vorbis$/,
2745-
/^opus$/,
2746-
/^flac$/,
2747-
/^mp4a/,
2748-
/^[ae]c-3$/,
2749-
];
2750-
2751-
2752-
/**
2753-
* A list of regexps to detect well-known text codecs.
2754-
*
2755-
* @const {!Array.<!RegExp>}
2756-
* @private
2757-
*/
2758-
shaka.hls.HlsParser.TEXT_CODEC_REGEXPS_ = [
2759-
/^vtt$/,
2760-
/^wvtt/,
2761-
/^stpp/,
2762-
];
2763-
2764-
2765-
/**
2766-
* @const {!Object.<string, !Array.<!RegExp>>}
2767-
* @private
2768-
*/
2769-
shaka.hls.HlsParser.CODEC_REGEXPS_BY_CONTENT_TYPE_ = {
2770-
'audio': shaka.hls.HlsParser.AUDIO_CODEC_REGEXPS_,
2771-
'video': shaka.hls.HlsParser.VIDEO_CODEC_REGEXPS_,
2772-
'text': shaka.hls.HlsParser.TEXT_CODEC_REGEXPS_,
2773-
};
2774-
2775-
27762668
/**
27772669
* @const {!Object.<string, string>}
27782670
* @private

lib/util/manifest_parser_utils.js

+114
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
goog.provide('shaka.util.ManifestParserUtils');
88

99
goog.require('goog.Uri');
10+
goog.require('shaka.util.Error');
1011
goog.require('shaka.util.Functional');
1112

1213

@@ -58,6 +59,66 @@ shaka.util.ManifestParserUtils = class {
5859
keyIds: new Set(),
5960
};
6061
}
62+
63+
64+
/**
65+
* Attempts to guess which codecs from the codecs list belong to a given
66+
* content type.
67+
* Assumes that at least one codec is correct, and throws if none are.
68+
*
69+
* @param {string} contentType
70+
* @param {!Array.<string>} codecs
71+
* @return {string}
72+
*/
73+
static guessCodecs(contentType, codecs) {
74+
if (codecs.length == 1) {
75+
return codecs[0];
76+
}
77+
78+
const match = shaka.util.ManifestParserUtils.guessCodecsSafe(
79+
contentType, codecs);
80+
// A failure is specifically denoted by null; an empty string represents a
81+
// valid match of no codec.
82+
if (match != null) {
83+
return match;
84+
}
85+
86+
// Unable to guess codecs.
87+
throw new shaka.util.Error(
88+
shaka.util.Error.Severity.CRITICAL,
89+
shaka.util.Error.Category.MANIFEST,
90+
shaka.util.Error.Code.HLS_COULD_NOT_GUESS_CODECS,
91+
codecs);
92+
}
93+
94+
95+
/**
96+
* Attempts to guess which codecs from the codecs list belong to a given
97+
* content type. Does not assume a single codec is anything special, and does
98+
* not throw if it fails to match.
99+
*
100+
* @param {string} contentType
101+
* @param {!Array.<string>} codecs
102+
* @return {?string} or null if no match is found
103+
*/
104+
static guessCodecsSafe(contentType, codecs) {
105+
const formats = shaka.util.ManifestParserUtils
106+
.CODEC_REGEXPS_BY_CONTENT_TYPE_[contentType];
107+
for (const format of formats) {
108+
for (const codec of codecs) {
109+
if (format.test(codec.trim())) {
110+
return codec.trim();
111+
}
112+
}
113+
}
114+
115+
// Text does not require a codec string.
116+
if (contentType == shaka.util.ManifestParserUtils.ContentType.TEXT) {
117+
return '';
118+
}
119+
120+
return null;
121+
}
61122
};
62123

63124

@@ -91,3 +152,56 @@ shaka.util.ManifestParserUtils.TextStreamKind = {
91152
* @const {number}
92153
*/
93154
shaka.util.ManifestParserUtils.GAP_OVERLAP_TOLERANCE_SECONDS = 1 / 15;
155+
156+
157+
/**
158+
* A list of regexps to detect well-known video codecs.
159+
*
160+
* @const {!Array.<!RegExp>}
161+
* @private
162+
*/
163+
shaka.util.ManifestParserUtils.VIDEO_CODEC_REGEXPS_ = [
164+
/^avc/,
165+
/^hev/,
166+
/^hvc/,
167+
/^vp0?[89]/,
168+
/^av1$/,
169+
];
170+
171+
172+
/**
173+
* A list of regexps to detect well-known audio codecs.
174+
*
175+
* @const {!Array.<!RegExp>}
176+
* @private
177+
*/
178+
shaka.util.ManifestParserUtils.AUDIO_CODEC_REGEXPS_ = [
179+
/^vorbis$/,
180+
/^opus$/,
181+
/^flac$/,
182+
/^mp4a/,
183+
/^[ae]c-3$/,
184+
];
185+
186+
187+
/**
188+
* A list of regexps to detect well-known text codecs.
189+
*
190+
* @const {!Array.<!RegExp>}
191+
* @private
192+
*/
193+
shaka.util.ManifestParserUtils.TEXT_CODEC_REGEXPS_ = [
194+
/^vtt$/,
195+
/^wvtt/,
196+
/^stpp/,
197+
];
198+
199+
200+
/**
201+
* @const {!Object.<string, !Array.<!RegExp>>}
202+
*/
203+
shaka.util.ManifestParserUtils.CODEC_REGEXPS_BY_CONTENT_TYPE_ = {
204+
'audio': shaka.util.ManifestParserUtils.AUDIO_CODEC_REGEXPS_,
205+
'video': shaka.util.ManifestParserUtils.VIDEO_CODEC_REGEXPS_,
206+
'text': shaka.util.ManifestParserUtils.TEXT_CODEC_REGEXPS_,
207+
};

lib/util/stream_utils.js

+9-6
Original file line numberDiff line numberDiff line change
@@ -433,15 +433,18 @@ shaka.util.StreamUtils = class {
433433
};
434434

435435
if (video) {
436-
let audioCodec;
437-
let videoCodec = video.codecs;
438-
436+
let videoCodecs = video.codecs;
439437
// For multiplexed streams with audio+video codecs, the config should have
440438
// AudioConfiguration and VideoConfiguration.
441439
if (video.codecs.includes(',')) {
442-
[videoCodec, audioCodec] = video.codecs.split(',');
440+
const allCodecs = video.codecs.split(',');
441+
videoCodecs = shaka.util.ManifestParserUtils.guessCodecs(
442+
ContentType.VIDEO, allCodecs);
443+
const audioCodecs = shaka.util.ManifestParserUtils.guessCodecs(
444+
ContentType.AUDIO, allCodecs);
445+
443446
const audioFullType = shaka.util.MimeUtils.getFullOrConvertedType(
444-
video.mimeType, audioCodec, ContentType.AUDIO);
447+
video.mimeType, audioCodecs, ContentType.AUDIO);
445448
mediaDecodingConfig.audio = {
446449
contentType: audioFullType,
447450
channels: 2,
@@ -451,7 +454,7 @@ shaka.util.StreamUtils = class {
451454
};
452455
}
453456
const fullType = shaka.util.MimeUtils.getFullOrConvertedType(
454-
video.mimeType, videoCodec, ContentType.VIDEO);
457+
video.mimeType, videoCodecs, ContentType.VIDEO);
455458
// VideoConfiguration
456459
mediaDecodingConfig.video = {
457460
contentType: fullType,

0 commit comments

Comments
 (0)