@@ -1284,14 +1284,48 @@ object HlsPlaylistParser {
12841284 val subtitleGroupId : String? ,
12851285 val captionGroupId : String? ,
12861286 ) {
1287- fun isPlayableStandalone (): Boolean = containsAudio() && ! isTrickPlay()
1287+ /* * This is unfortunately impossible to do 100%, given that audio detection is hard without TS inspection,
1288+ * however this is a generous safety abstraction */
1289+ fun isPlayableStandalone (playlist : HlsMultivariantPlaylist ): Boolean =
1290+ mustContainAudio(playlist) && ! isTrickPlay()
12881291
1289- // Trick play is "visual feedback while they are rewinding or fast-forwarding a stream",
1290- // This more or less means thumbnails
1292+ /* *
1293+ * https://datatracker.ietf.org/doc/html/rfc8216#section-4.3.3.6
1294+ * > The EXT-X-I-FRAMES-ONLY tag indicates that each Media Segment in the
1295+ * > Playlist describes a single I-frame. I-frames are encoded video
1296+ * > frames whose encoding does not depend on any other frame. I-frame
1297+ * > Playlists can be used for trick play, such as fast forward, rapid
1298+ * > reverse, and scrubbing.
1299+ */
12911300 fun isTrickPlay (): Boolean = (format.roleFlags and C .ROLE_FLAG_TRICK_PLAY != 0 )
12921301
1293- fun containsAudio (): Boolean = (audioGroupId == null || format.codecs?.split(" ," )
1294- ?.any { MimeTypes .isAudio(MimeTypes .getMediaMimeType(it)) } == true )
1302+ /* *
1303+ https://datatracker.ietf.org/doc/html/rfc6381:
1304+ > When the 'codecs' parameter is used, it MUST contain all codecs
1305+ > indicated by the content present in the body part. The 'codecs'
1306+ > parameter MUST NOT include any codecs that are not indicated by any
1307+ > media elements in the body part.
1308+
1309+ This means that codecs cant be used
1310+ "|| format.codecs?.split(",")?.any { MimeTypes.isAudio(MimeTypes.getMediaMimeType(it)) } == true"
1311+ They may be used for harsher restriction on "audioGroupId == null", but codecs is optional
1312+
1313+ https://datatracker.ietf.org/doc/html/rfc8216
1314+ > Since the EXT-X-STREAM-INF tag has no AUDIO attribute, all video
1315+ > Renditions would be required to contain the audio.
1316+
1317+ However it may still contain audio with the AUDIO attribute, therefore we also check the audio with that groupId:
1318+
1319+ > If the media type is VIDEO or AUDIO, a missing URI attribute
1320+ > indicates that the media data for this Rendition is included in the
1321+ > Media Playlist of any EXT-X-STREAM-INF tag referencing this EXT-
1322+ > X-MEDIA tag.
1323+
1324+ But this is not foolproof, because TS segments needs to be investigated to be sure as I do not see any
1325+ way to detect this from the m3u8 playlist
1326+ */
1327+ fun mustContainAudio (playlist : HlsMultivariantPlaylist ): Boolean =
1328+ audioGroupId == null || (playlist.audios.firstOrNull { it.groupId == audioGroupId }?.url == null )
12951329 }
12961330
12971331 data class Rendition (
0 commit comments