diff options
Diffstat (limited to 'tuner/src/com/android/tv/tuner/data/PsipData.java')
-rw-r--r-- | tuner/src/com/android/tv/tuner/data/PsipData.java | 871 |
1 files changed, 871 insertions, 0 deletions
diff --git a/tuner/src/com/android/tv/tuner/data/PsipData.java b/tuner/src/com/android/tv/tuner/data/PsipData.java new file mode 100644 index 00000000..239009dc --- /dev/null +++ b/tuner/src/com/android/tv/tuner/data/PsipData.java @@ -0,0 +1,871 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.tv.tuner.data; + +import android.support.annotation.NonNull; +import android.text.TextUtils; +import android.text.format.DateUtils; +import com.android.tv.common.util.StringUtils; +import com.android.tv.tuner.data.nano.Track.AtscAudioTrack; +import com.android.tv.tuner.data.nano.Track.AtscCaptionTrack; +import com.android.tv.tuner.ts.SectionParser; +import com.android.tv.tuner.util.ConvertUtils; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Locale; + +/** Collection of ATSC PSIP table items. */ +public class PsipData { + + private PsipData() {} + + public static class PsipSection { + private final int mTableId; + private final int mTableIdExtension; + private final int mSectionNumber; + private final boolean mCurrentNextIndicator; + + public static PsipSection create(byte[] data) { + if (data.length < 9) { + return null; + } + int tableId = data[0] & 0xff; + int tableIdExtension = (data[3] & 0xff) << 8 | (data[4] & 0xff); + int sectionNumber = data[6] & 0xff; + boolean currentNextIndicator = (data[5] & 0x01) != 0; + return new PsipSection(tableId, tableIdExtension, sectionNumber, currentNextIndicator); + } + + private PsipSection( + int tableId, + int tableIdExtension, + int sectionNumber, + boolean currentNextIndicator) { + mTableId = tableId; + mTableIdExtension = tableIdExtension; + mSectionNumber = sectionNumber; + mCurrentNextIndicator = currentNextIndicator; + } + + public int getTableId() { + return mTableId; + } + + public int getTableIdExtension() { + return mTableIdExtension; + } + + public int getSectionNumber() { + return mSectionNumber; + } + + // This is for indicating that the section sent is applicable. + // We only consider a situation where currentNextIndicator is expected to have a true value. + // So, we are not going to compare this variable in hashCode() and equals() methods. + public boolean getCurrentNextIndicator() { + return mCurrentNextIndicator; + } + + @Override + public int hashCode() { + int result = 17; + result = 31 * result + mTableId; + result = 31 * result + mTableIdExtension; + result = 31 * result + mSectionNumber; + return result; + } + + @Override + public boolean equals(Object obj) { + if (obj instanceof PsipSection) { + PsipSection another = (PsipSection) obj; + return mTableId == another.getTableId() + && mTableIdExtension == another.getTableIdExtension() + && mSectionNumber == another.getSectionNumber(); + } + return false; + } + } + + /** {@link TvTracksInterface} for serving the audio and caption tracks. */ + public interface TvTracksInterface { + /** Set the flag that tells the caption tracks have been found in this section container. */ + void setHasCaptionTrack(); + + /** + * Returns whether or not the caption tracks have been found in this section container. If + * true, zero caption track will be interpreted as a clearance of the caption tracks. + */ + boolean hasCaptionTrack(); + + /** Returns the audio tracks received. */ + List<AtscAudioTrack> getAudioTracks(); + + /** Returns the caption tracks received. */ + List<AtscCaptionTrack> getCaptionTracks(); + } + + public static class MgtItem { + public static final int TABLE_TYPE_EIT_RANGE_START = 0x0100; + public static final int TABLE_TYPE_EIT_RANGE_END = 0x017f; + public static final int TABLE_TYPE_CHANNEL_ETT = 0x0004; + public static final int TABLE_TYPE_ETT_RANGE_START = 0x0200; + public static final int TABLE_TYPE_ETT_RANGE_END = 0x027f; + + private final int mTableType; + private final int mTableTypePid; + + public MgtItem(int tableType, int tableTypePid) { + mTableType = tableType; + mTableTypePid = tableTypePid; + } + + public int getTableType() { + return mTableType; + } + + public int getTableTypePid() { + return mTableTypePid; + } + } + + public static class VctItem { + private final String mShortName; + private final String mLongName; + private final int mServiceType; + private final int mChannelTsid; + private final int mProgramNumber; + private final int mMajorChannelNumber; + private final int mMinorChannelNumber; + private final int mSourceId; + private String mDescription; + + public VctItem( + String shortName, + String longName, + int serviceType, + int channelTsid, + int programNumber, + int majorChannelNumber, + int minorChannelNumber, + int sourceId) { + mShortName = shortName; + mLongName = longName; + mServiceType = serviceType; + mChannelTsid = channelTsid; + mProgramNumber = programNumber; + mMajorChannelNumber = majorChannelNumber; + mMinorChannelNumber = minorChannelNumber; + mSourceId = sourceId; + } + + public String getShortName() { + return mShortName; + } + + public String getLongName() { + return mLongName; + } + + public int getServiceType() { + return mServiceType; + } + + public int getChannelTsid() { + return mChannelTsid; + } + + public int getProgramNumber() { + return mProgramNumber; + } + + public int getMajorChannelNumber() { + return mMajorChannelNumber; + } + + public int getMinorChannelNumber() { + return mMinorChannelNumber; + } + + public int getSourceId() { + return mSourceId; + } + + @Override + public String toString() { + return String.format( + Locale.US, + "ShortName: %s LongName: %s ServiceType: %d ChannelTsid: %x " + + "ProgramNumber:%d %d-%d SourceId: %x", + mShortName, + mLongName, + mServiceType, + mChannelTsid, + mProgramNumber, + mMajorChannelNumber, + mMinorChannelNumber, + mSourceId); + } + + public void setDescription(String description) { + mDescription = description; + } + + public String getDescription() { + return mDescription; + } + } + + public static class SdtItem { + private final String mServiceName; + private final String mServiceProviderName; + private final int mServiceType; + private final int mServiceId; + private final int mOriginalNetWorkId; + + public SdtItem( + String serviceName, + String serviceProviderName, + int serviceType, + int serviceId, + int originalNetWorkId) { + mServiceName = serviceName; + mServiceProviderName = serviceProviderName; + mServiceType = serviceType; + mServiceId = serviceId; + mOriginalNetWorkId = originalNetWorkId; + } + + public String getServiceName() { + return mServiceName; + } + + public String getServiceProviderName() { + return mServiceProviderName; + } + + public int getServiceType() { + return mServiceType; + } + + public int getServiceId() { + return mServiceId; + } + + public int getOriginalNetworkId() { + return mOriginalNetWorkId; + } + + @Override + public String toString() { + return String.format( + "ServiceName: %s ServiceProviderName:%s ServiceType:%d " + + "OriginalNetworkId:%d", + mServiceName, mServiceProviderName, mServiceType, mOriginalNetWorkId); + } + } + + /** A base class for descriptors of Ts packets. */ + public abstract static class TsDescriptor { + public abstract int getTag(); + } + + public static class ContentAdvisoryDescriptor extends TsDescriptor { + private final List<RatingRegion> mRatingRegions; + + public ContentAdvisoryDescriptor(List<RatingRegion> ratingRegions) { + mRatingRegions = ratingRegions; + } + + @Override + public int getTag() { + return SectionParser.DESCRIPTOR_TAG_CONTENT_ADVISORY; + } + + public List<RatingRegion> getRatingRegions() { + return mRatingRegions; + } + } + + public static class CaptionServiceDescriptor extends TsDescriptor { + private final List<AtscCaptionTrack> mCaptionTracks; + + public CaptionServiceDescriptor(List<AtscCaptionTrack> captionTracks) { + mCaptionTracks = captionTracks; + } + + @Override + public int getTag() { + return SectionParser.DESCRIPTOR_TAG_CAPTION_SERVICE; + } + + public List<AtscCaptionTrack> getCaptionTracks() { + return mCaptionTracks; + } + } + + public static class ExtendedChannelNameDescriptor extends TsDescriptor { + private final String mLongChannelName; + + public ExtendedChannelNameDescriptor(String longChannelName) { + mLongChannelName = longChannelName; + } + + @Override + public int getTag() { + return SectionParser.DESCRIPTOR_TAG_EXTENDED_CHANNEL_NAME; + } + + public String getLongChannelName() { + return mLongChannelName; + } + } + + public static class GenreDescriptor extends TsDescriptor { + private final String[] mBroadcastGenres; + private final String[] mCanonicalGenres; + + public GenreDescriptor(String[] broadcastGenres, String[] canonicalGenres) { + mBroadcastGenres = broadcastGenres; + mCanonicalGenres = canonicalGenres; + } + + @Override + public int getTag() { + return SectionParser.DESCRIPTOR_TAG_GENRE; + } + + public String[] getBroadcastGenres() { + return mBroadcastGenres; + } + + public String[] getCanonicalGenres() { + return mCanonicalGenres; + } + } + + public static class Ac3AudioDescriptor extends TsDescriptor { + // See A/52 Annex A. Table A4.2 + private static final byte SAMPLE_RATE_CODE_48000HZ = 0; + private static final byte SAMPLE_RATE_CODE_44100HZ = 1; + private static final byte SAMPLE_RATE_CODE_32000HZ = 2; + + private final byte mSampleRateCode; + private final byte mBsid; + private final byte mBitRateCode; + private final byte mSurroundMode; + private final byte mBsmod; + private final int mNumChannels; + private final boolean mFullSvc; + private final byte mLangCod; + private final byte mLangCod2; + private final byte mMainId; + private final byte mPriority; + private final byte mAsvcflags; + private final String mText; + private final String mLanguage; + private final String mLanguage2; + + public Ac3AudioDescriptor( + byte sampleRateCode, + byte bsid, + byte bitRateCode, + byte surroundMode, + byte bsmod, + int numChannels, + boolean fullSvc, + byte langCod, + byte langCod2, + byte mainId, + byte priority, + byte asvcflags, + String text, + String language, + String language2) { + mSampleRateCode = sampleRateCode; + mBsid = bsid; + mBitRateCode = bitRateCode; + mSurroundMode = surroundMode; + mBsmod = bsmod; + mNumChannels = numChannels; + mFullSvc = fullSvc; + mLangCod = langCod; + mLangCod2 = langCod2; + mMainId = mainId; + mPriority = priority; + mAsvcflags = asvcflags; + mText = text; + mLanguage = language; + mLanguage2 = language2; + } + + @Override + public int getTag() { + return SectionParser.DESCRIPTOR_TAG_AC3_AUDIO_STREAM; + } + + public byte getSampleRateCode() { + return mSampleRateCode; + } + + public int getSampleRate() { + switch (mSampleRateCode) { + case SAMPLE_RATE_CODE_48000HZ: + return 48000; + case SAMPLE_RATE_CODE_44100HZ: + return 44100; + case SAMPLE_RATE_CODE_32000HZ: + return 32000; + default: + return 0; + } + } + + public byte getBsid() { + return mBsid; + } + + public byte getBitRateCode() { + return mBitRateCode; + } + + public byte getSurroundMode() { + return mSurroundMode; + } + + public byte getBsmod() { + return mBsmod; + } + + public int getNumChannels() { + return mNumChannels; + } + + public boolean isFullSvc() { + return mFullSvc; + } + + public byte getLangCod() { + return mLangCod; + } + + public byte getLangCod2() { + return mLangCod2; + } + + public byte getMainId() { + return mMainId; + } + + public byte getPriority() { + return mPriority; + } + + public byte getAsvcflags() { + return mAsvcflags; + } + + public String getText() { + return mText; + } + + public String getLanguage() { + return mLanguage; + } + + public String getLanguage2() { + return mLanguage2; + } + + @Override + public String toString() { + return String.format( + Locale.US, + "AC3 audio stream sampleRateCode: %d, bsid: %d, bitRateCode: %d, " + + "surroundMode: %d, bsmod: %d, numChannels: %d, fullSvc: %s, langCod: %d, " + + "langCod2: %d, mainId: %d, priority: %d, avcflags: %d, text: %s, language: %s" + + ", language2: %s", + mSampleRateCode, + mBsid, + mBitRateCode, + mSurroundMode, + mBsmod, + mNumChannels, + mFullSvc, + mLangCod, + mLangCod2, + mMainId, + mPriority, + mAsvcflags, + mText, + mLanguage, + mLanguage2); + } + } + + public static class Iso639LanguageDescriptor extends TsDescriptor { + private final List<AtscAudioTrack> mAudioTracks; + + public Iso639LanguageDescriptor(List<AtscAudioTrack> audioTracks) { + mAudioTracks = audioTracks; + } + + @Override + public int getTag() { + return SectionParser.DESCRIPTOR_TAG_ISO639LANGUAGE; + } + + public List<AtscAudioTrack> getAudioTracks() { + return mAudioTracks; + } + + @Override + public String toString() { + return String.format("%s %s", getClass().getName(), mAudioTracks); + } + } + + public static class ServiceDescriptor extends TsDescriptor { + private final int mServiceType; + private final String mServiceProviderName; + private final String mServiceName; + + public ServiceDescriptor(int serviceType, String serviceProviderName, String serviceName) { + mServiceType = serviceType; + mServiceProviderName = serviceProviderName; + mServiceName = serviceName; + } + + @Override + public int getTag() { + return SectionParser.DVB_DESCRIPTOR_TAG_SERVICE; + } + + public int getServiceType() { + return mServiceType; + } + + public String getServiceProviderName() { + return mServiceProviderName; + } + + public String getServiceName() { + return mServiceName; + } + + @Override + public String toString() { + return String.format( + "Service descriptor, service type: %d, " + + "service provider name: %s, " + + "service name: %s", + mServiceType, mServiceProviderName, mServiceName); + } + } + + public static class ShortEventDescriptor extends TsDescriptor { + private final String mLanguage; + private final String mEventName; + private final String mText; + + public ShortEventDescriptor(String language, String eventName, String text) { + mLanguage = language; + mEventName = eventName; + mText = text; + } + + public String getEventName() { + return mEventName; + } + + @Override + public int getTag() { + return SectionParser.DVB_DESCRIPTOR_TAG_SHORT_EVENT; + } + + @Override + public String toString() { + return String.format( + "ShortEvent Descriptor, language:%s, event name: %s, " + "text:%s", + mLanguage, mEventName, mText); + } + } + + public static class ParentalRatingDescriptor extends TsDescriptor { + private final HashMap<String, Integer> mRatings; + + public ParentalRatingDescriptor(HashMap<String, Integer> ratings) { + mRatings = ratings; + } + + @Override + public int getTag() { + return SectionParser.DVB_DESCRIPTOR_TAG_PARENTAL_RATING; + } + + public HashMap<String, Integer> getRatings() { + return mRatings; + } + + @Override + public String toString() { + return String.format("Parental rating descriptor, ratings:" + mRatings); + } + } + + public static class RatingRegion { + private final int mName; + private final String mDescription; + private final List<RegionalRating> mRegionalRatings; + + public RatingRegion(int name, String description, List<RegionalRating> regionalRatings) { + mName = name; + mDescription = description; + mRegionalRatings = regionalRatings; + } + + public int getName() { + return mName; + } + + public String getDescription() { + return mDescription; + } + + public List<RegionalRating> getRegionalRatings() { + return mRegionalRatings; + } + } + + public static class RegionalRating { + private final int mDimension; + private final int mRating; + + public RegionalRating(int dimension, int rating) { + mDimension = dimension; + mRating = rating; + } + + public int getDimension() { + return mDimension; + } + + public int getRating() { + return mRating; + } + } + + public static class EitItem implements Comparable<EitItem>, TvTracksInterface { + public static final long INVALID_PROGRAM_ID = -1; + + // A program id is a primary key of TvContract.Programs table. So it must be positive. + private final long mProgramId; + private final int mEventId; + private final String mTitleText; + private String mDescription; + private final long mStartTime; + private final int mLengthInSecond; + private final String mContentRating; + private final List<AtscAudioTrack> mAudioTracks; + private final List<AtscCaptionTrack> mCaptionTracks; + private boolean mHasCaptionTrack; + private final String mBroadcastGenre; + private final String mCanonicalGenre; + + public EitItem( + long programId, + int eventId, + String titleText, + long startTime, + int lengthInSecond, + String contentRating, + List<AtscAudioTrack> audioTracks, + List<AtscCaptionTrack> captionTracks, + String broadcastGenre, + String canonicalGenre, + String description) { + mProgramId = programId; + mEventId = eventId; + mTitleText = titleText; + mStartTime = startTime; + mLengthInSecond = lengthInSecond; + mContentRating = contentRating; + mAudioTracks = audioTracks; + mCaptionTracks = captionTracks; + mBroadcastGenre = broadcastGenre; + mCanonicalGenre = canonicalGenre; + mDescription = description; + } + + public long getProgramId() { + return mProgramId; + } + + public int getEventId() { + return mEventId; + } + + public String getTitleText() { + return mTitleText; + } + + public void setDescription(String description) { + mDescription = description; + } + + public String getDescription() { + return mDescription; + } + + public long getStartTime() { + return mStartTime; + } + + public int getLengthInSecond() { + return mLengthInSecond; + } + + public long getStartTimeUtcMillis() { + return ConvertUtils.convertGPSTimeToUnixEpoch(mStartTime) * DateUtils.SECOND_IN_MILLIS; + } + + public long getEndTimeUtcMillis() { + return ConvertUtils.convertGPSTimeToUnixEpoch(mStartTime + mLengthInSecond) + * DateUtils.SECOND_IN_MILLIS; + } + + public String getContentRating() { + return mContentRating; + } + + @Override + public List<AtscAudioTrack> getAudioTracks() { + return mAudioTracks; + } + + @Override + public List<AtscCaptionTrack> getCaptionTracks() { + return mCaptionTracks; + } + + public String getBroadcastGenre() { + return mBroadcastGenre; + } + + public String getCanonicalGenre() { + return mCanonicalGenre; + } + + @Override + public void setHasCaptionTrack() { + mHasCaptionTrack = true; + } + + @Override + public boolean hasCaptionTrack() { + return mHasCaptionTrack; + } + + @Override + public int compareTo(@NonNull EitItem item) { + // The list of caption tracks and the program ids are not compared in here because the + // channels in TIF have the concept of the caption and audio tracks while the programs + // do not and the programs in TIF only have a program id since they are the rows of + // Content Provider. + int ret = mEventId - item.getEventId(); + if (ret != 0) { + return ret; + } + ret = StringUtils.compare(mTitleText, item.getTitleText()); + if (ret != 0) { + return ret; + } + if (mStartTime > item.getStartTime()) { + return 1; + } else if (mStartTime < item.getStartTime()) { + return -1; + } + if (mLengthInSecond > item.getLengthInSecond()) { + return 1; + } else if (mLengthInSecond < item.getLengthInSecond()) { + return -1; + } + + // Compares content ratings + ret = StringUtils.compare(mContentRating, item.getContentRating()); + if (ret != 0) { + return ret; + } + + // Compares broadcast genres + ret = StringUtils.compare(mBroadcastGenre, item.getBroadcastGenre()); + if (ret != 0) { + return ret; + } + // Compares canonical genres + ret = StringUtils.compare(mCanonicalGenre, item.getCanonicalGenre()); + if (ret != 0) { + return ret; + } + + // Compares descriptions + return StringUtils.compare(mDescription, item.getDescription()); + } + + public String getAudioLanguage() { + if (mAudioTracks == null) { + return ""; + } + ArrayList<String> languages = new ArrayList<>(); + for (AtscAudioTrack audioTrack : mAudioTracks) { + languages.add(audioTrack.language); + } + return TextUtils.join(",", languages); + } + + @Override + public String toString() { + return String.format( + Locale.US, + "EitItem programId: %d, eventId: %d, title: %s, startTime: %10d, " + + "length: %6d, rating: %s, audio tracks: %d, caption tracks: %d, " + + "genres (broadcast: %s, canonical: %s), description: %s", + mProgramId, + mEventId, + mTitleText, + mStartTime, + mLengthInSecond, + mContentRating, + mAudioTracks != null ? mAudioTracks.size() : 0, + mCaptionTracks != null ? mCaptionTracks.size() : 0, + mBroadcastGenre, + mCanonicalGenre, + mDescription); + } + } + + public static class EttItem { + public final int eventId; + public final String text; + + public EttItem(int eventId, String text) { + this.eventId = eventId; + this.text = text; + } + } +} |