Skip to content
This repository has been archived by the owner on Nov 22, 2022. It is now read-only.

Commit

Permalink
Add support for CHANNELS attribute in EXT-X-MEDIA tag. (#54)
Browse files Browse the repository at this point in the history
* Added support for CHANNELS attribute in EXT-X-MEDIA tag.

It can be a list seperated by /, but it is only defined for TYPE: AUDIO,
and then only the first parameter is used.

Also updated the test so it contains the CHANNELS attribute.

From the specification:
CHANNELS

      The value is a quoted-string that specifies an ordered,
      "/"-separated list of parameters.  If the TYPE attribute is AUDIO
      then the first parameter is a count of audio channels expressed as
      a decimal-integer, indicating the maximum number of independent,
      simultaneous audio channels present in any Media Segment in the
      Rendition.  For example, an AC-3 5.1 rendition would have a
      CHANNELS="6" attribute.  No other CHANNELS parameters are
      currently defined.

      All audio EXT-X-MEDIA tags SHOULD have a CHANNELS attribute.  If a
      Master Playlist contains two renditions encoded with the same
      codec but a different number of channels, then the CHANNELS
      attribute is REQUIRED; otherwise it is OPTIONAL.

Signed-off-by: Even Thomassen <even.thomassen@noriginmedia.com>

* MediaData.channels is now primitive int, instead of Integer.

Also included channels in hashcode.

Signed-off-by: Even Thomassen <even.thomassen@noriginmedia.com>
  • Loading branch information
eventh authored and sunglee413 committed Oct 20, 2017
1 parent d8a14bc commit 00a886c
Show file tree
Hide file tree
Showing 5 changed files with 54 additions and 16 deletions.
1 change: 1 addition & 0 deletions src/main/java/com/iheartradio/m3u8/Constants.java
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ final class Constants {
public static final String FORCED = "FORCED";
public static final String IN_STREAM_ID = "INSTREAM-ID";
public static final String CHARACTERISTICS = "CHARACTERISTICS";
public static final String CHANNELS = "CHANNELS";

public static final String EXT_X_STREAM_INF_TAG = "EXT-X-STREAM-INF";
public static final String EXT_X_I_FRAME_STREAM_INF_TAG = "EXT-X-I-FRAME-STREAM-INF";
Expand Down
22 changes: 16 additions & 6 deletions src/main/java/com/iheartradio/m3u8/MasterPlaylistLineParser.java
Original file line number Diff line number Diff line change
@@ -1,15 +1,11 @@
package com.iheartradio.m3u8;

import com.iheartradio.m3u8.data.*;

import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;

import com.iheartradio.m3u8.data.IFrameStreamInfo;
import com.iheartradio.m3u8.data.MediaData;
import com.iheartradio.m3u8.data.MediaType;
import com.iheartradio.m3u8.data.StreamInfo;
import com.iheartradio.m3u8.data.StreamInfoBuilder;

class MasterPlaylistLineParser implements LineParser {
private final IExtTagParser mTagParser;
private final LineParser mLineParser;
Expand Down Expand Up @@ -164,6 +160,20 @@ public void parse(Attribute attribute, MediaData.Builder builder, ParseState sta
}
}
});

HANDLERS.put(Constants.CHANNELS, new AttributeParser<MediaData.Builder>() {
@Override
public void parse(Attribute attribute, MediaData.Builder builder, ParseState state) throws ParseException {
final String[] channelsStrings = ParseUtil.parseQuotedString(attribute.value, getTag()).split(Constants.LIST_SEPARATOR);

if (channelsStrings.length == 0 || channelsStrings[0].isEmpty()) {
throw ParseException.create(ParseExceptionType.EMPTY_MEDIA_CHANNELS, getTag(), attribute.toString());
} else {
final int channelsCount = ParseUtil.parseInt(channelsStrings[0], getTag());
builder.withChannels(channelsCount);
}
}
});
}

@Override
Expand Down
1 change: 1 addition & 0 deletions src/main/java/com/iheartradio/m3u8/ParseExceptionType.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
public enum ParseExceptionType {
AUTO_SELECT_DISABLED_FOR_DEFAULT("default media data must be auto selected"),
BAD_EXT_TAG_FORMAT("bad format found for an EXT tag"),
EMPTY_MEDIA_CHANNELS("CHANNELS is empty"),
EMPTY_MEDIA_CHARACTERISTICS("CHARACTERISTICS is empty"),
EMPTY_MEDIA_GROUP_ID("GROUP-ID is empty"),
EMPTY_MEDIA_NAME("NAME is empty"),
Expand Down
40 changes: 33 additions & 7 deletions src/main/java/com/iheartradio/m3u8/data/MediaData.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
import java.util.Objects;

public class MediaData {
public static final int NO_CHANNELS = -1;

private final MediaType mType;
private final String mUri;
private final String mGroupId;
Expand All @@ -15,6 +17,7 @@ public class MediaData {
private final boolean mForced;
private final String mInStreamId;
private final List<String> mCharacteristics;
private final int mChannels;

private MediaData(
MediaType type,
Expand All @@ -27,7 +30,8 @@ private MediaData(
boolean isAutoSelect,
boolean isForced,
String inStreamId,
List<String> characteristics) {
List<String> characteristics,
int channels) {
mType = type;
mUri = uri;
mGroupId = groupId;
Expand All @@ -39,6 +43,7 @@ private MediaData(
mForced = isForced;
mInStreamId = inStreamId;
mCharacteristics = DataUtil.emptyOrUnmodifiable(characteristics);
mChannels = channels;
}

public MediaType getType() {
Expand Down Expand Up @@ -105,6 +110,14 @@ public List<String> getCharacteristics() {
return mCharacteristics;
}

public boolean hasChannels() {
return mChannels != NO_CHANNELS;
}

public Integer getChannels() {
return mChannels;
}

public Builder buildUpon() {
return new Builder(
mType,
Expand All @@ -117,7 +130,8 @@ public Builder buildUpon() {
mAutoSelect,
mForced,
mInStreamId,
mCharacteristics);
mCharacteristics,
mChannels);
}

@Override
Expand All @@ -133,7 +147,8 @@ public int hashCode() {
mLanguage,
mName,
mType,
mUri);
mUri,
mChannels);
}

@Override
Expand All @@ -154,7 +169,8 @@ public boolean equals(Object o) {
mAutoSelect == other.mAutoSelect &&
mForced == other.mForced &&
Objects.equals(mInStreamId, other.mInStreamId) &&
Objects.equals(mCharacteristics, other.mCharacteristics);
Objects.equals(mCharacteristics, other.mCharacteristics) &&
mChannels == other.mChannels;
}

public static class Builder {
Expand All @@ -169,6 +185,7 @@ public static class Builder {
private boolean mForced;
private String mInStreamId;
private List<String> mCharacteristics;
private int mChannels = NO_CHANNELS;

public Builder() {
}
Expand All @@ -184,7 +201,8 @@ private Builder(
boolean autoSelect,
boolean forced,
String inStreamId,
List<String> characteristics) {
List<String> characteristics,
int channels) {
mType = type;
mUri = uri;
mGroupId = groupId;
Expand All @@ -196,6 +214,7 @@ private Builder(
mForced = forced;
mInStreamId = inStreamId;
mCharacteristics = characteristics;
mChannels = channels;
}

public Builder withType(MediaType type) {
Expand Down Expand Up @@ -253,6 +272,11 @@ public Builder withCharacteristics(List<String> characteristics) {
return this;
}

public Builder withChannels(int channels) {
mChannels = channels;
return this;
}

public MediaData build() {
return new MediaData(
mType,
Expand All @@ -265,7 +289,8 @@ public MediaData build() {
mAutoSelect,
mForced,
mInStreamId,
mCharacteristics);
mCharacteristics,
mChannels);
}
}

Expand All @@ -276,6 +301,7 @@ public String toString() {
+ ", mAssociatedLanguage=" + mAssociatedLanguage + ", mName="
+ mName + ", mDefault=" + mDefault + ", mAutoSelect="
+ mAutoSelect + ", mForced=" + mForced + ", mInStreamId="
+ mInStreamId + ", mCharacteristics=" + mCharacteristics + "]";
+ mInStreamId + ", mCharacteristics=" + mCharacteristics
+ ", mChannels=" + mChannels + "]";
}
}
6 changes: 3 additions & 3 deletions src/test/resources/masterPlaylistWithAlternativeAudio.m3u8
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#EXTM3U
#EXT-X-MEDIA:TYPE=AUDIO,GROUP-ID="aac",NAME="English",DEFAULT=YES,AUTOSELECT=YES,LANGUAGE="en",URI="main/english-audio.m3u8"
#EXT-X-MEDIA:TYPE=AUDIO,GROUP-ID="aac",NAME="Deutsch",DEFAULT=NO,AUTOSELECT=YES,LANGUAGE="de",URI="main/german-audio.m3u8"
#EXT-X-MEDIA:TYPE=AUDIO,GROUP-ID="aac",NAME="Commentary",DEFAULT=NO,AUTOSELECT=NO,LANGUAGE="en",URI="commentary/audio-only.m3u8"
#EXT-X-MEDIA:TYPE=AUDIO,GROUP-ID="aac",NAME="English",DEFAULT=YES,AUTOSELECT=YES,LANGUAGE="en",CHANNELS="2",URI="main/english-audio.m3u8"
#EXT-X-MEDIA:TYPE=AUDIO,GROUP-ID="aac",NAME="Deutsch",DEFAULT=NO,AUTOSELECT=YES,LANGUAGE="de",CHANNELS="2",URI="main/german-audio.m3u8"
#EXT-X-MEDIA:TYPE=AUDIO,GROUP-ID="aac",NAME="Commentary",DEFAULT=NO,AUTOSELECT=NO,LANGUAGE="en",CHANNELS="2",URI="commentary/audio-only.m3u8"
#EXT-X-STREAM-INF:BANDWIDTH=1280000,CODECS="...",AUDIO="aac"
low/video-only.m3u8
#EXT-X-STREAM-INF:BANDWIDTH=2560000,CODECS="...",AUDIO="aac"
Expand Down

0 comments on commit 00a886c

Please sign in to comment.