Home | History | Annotate | Download | only in data
      1 /*
      2  * Copyright (C) 2015 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package com.android.tv.tuner.data;
     18 
     19 import android.support.annotation.NonNull;
     20 import android.text.TextUtils;
     21 import android.text.format.DateUtils;
     22 
     23 import com.android.tv.tuner.data.nano.Track.AtscAudioTrack;
     24 import com.android.tv.tuner.data.nano.Track.AtscCaptionTrack;
     25 import com.android.tv.tuner.ts.SectionParser;
     26 import com.android.tv.tuner.util.ConvertUtils;
     27 import com.android.tv.tuner.util.StringUtils;
     28 
     29 import java.util.ArrayList;
     30 import java.util.List;
     31 import java.util.Locale;
     32 
     33 /**
     34  * Collection of ATSC PSIP table items.
     35  */
     36 public class PsipData {
     37 
     38     private PsipData() {
     39     }
     40 
     41     public static class PsipSection {
     42         private final int mTableId;
     43         private final int mTableIdExtension;
     44         private final int mSectionNumber;
     45         private final boolean mCurrentNextIndicator;
     46 
     47         public static PsipSection create(byte[] data) {
     48             if (data.length < 9) {
     49                 return null;
     50             }
     51             int tableId = data[0] & 0xff;
     52             int tableIdExtension = (data[3] & 0xff) << 8 | (data[4] & 0xff);
     53             int sectionNumber = data[6] & 0xff;
     54             boolean currentNextIndicator = (data[5] & 0x01) != 0;
     55             return new PsipSection(tableId, tableIdExtension, sectionNumber, currentNextIndicator);
     56         }
     57 
     58         private PsipSection(int tableId, int tableIdExtension, int sectionNumber,
     59                 boolean currentNextIndicator) {
     60             mTableId = tableId;
     61             mTableIdExtension = tableIdExtension;
     62             mSectionNumber = sectionNumber;
     63             mCurrentNextIndicator = currentNextIndicator;
     64         }
     65 
     66         public int getTableId() {
     67             return mTableId;
     68         }
     69 
     70         public int getTableIdExtension() {
     71             return mTableIdExtension;
     72         }
     73 
     74         public int getSectionNumber() {
     75             return mSectionNumber;
     76         }
     77 
     78         // This is for indicating that the section sent is applicable.
     79         // We only consider a situation where currentNextIndicator is expected to have a true value.
     80         // So, we are not going to compare this variable in hashCode() and equals() methods.
     81         public boolean getCurrentNextIndicator() {
     82             return mCurrentNextIndicator;
     83         }
     84 
     85         @Override
     86         public int hashCode() {
     87             int result = 17;
     88             result = 31 * result + mTableId;
     89             result = 31 * result + mTableIdExtension;
     90             result = 31 * result + mSectionNumber;
     91             return result;
     92         }
     93 
     94         @Override
     95         public boolean equals(Object obj) {
     96             if (obj instanceof PsipSection) {
     97                 PsipSection another = (PsipSection) obj;
     98                 return mTableId == another.getTableId()
     99                         && mTableIdExtension == another.getTableIdExtension()
    100                         && mSectionNumber == another.getSectionNumber();
    101             }
    102             return false;
    103         }
    104     }
    105 
    106     /**
    107      * {@link TvTracksInterface} for serving the audio and caption tracks.
    108      */
    109     public interface TvTracksInterface {
    110         /**
    111          * Set the flag that tells the caption tracks have been found in this section container.
    112          */
    113         void setHasCaptionTrack();
    114 
    115         /**
    116          * Returns whether or not the caption tracks have been found in this section container.
    117          * If true, zero caption track will be interpreted as a clearance of the caption tracks.
    118          */
    119         boolean hasCaptionTrack();
    120 
    121         /**
    122          * Returns the audio tracks received.
    123          */
    124         List<AtscAudioTrack> getAudioTracks();
    125 
    126         /**
    127          * Returns the caption tracks received.
    128          */
    129         List<AtscCaptionTrack> getCaptionTracks();
    130     }
    131 
    132     public static class MgtItem {
    133         public static final int TABLE_TYPE_EIT_RANGE_START = 0x0100;
    134         public static final int TABLE_TYPE_EIT_RANGE_END = 0x017f;
    135         public static final int TABLE_TYPE_CHANNEL_ETT = 0x0004;
    136         public static final int TABLE_TYPE_ETT_RANGE_START = 0x0200;
    137         public static final int TABLE_TYPE_ETT_RANGE_END = 0x027f;
    138 
    139         private final int mTableType;
    140         private final int mTableTypePid;
    141 
    142         public MgtItem(int tableType, int tableTypePid) {
    143             mTableType = tableType;
    144             mTableTypePid = tableTypePid;
    145         }
    146 
    147         public int getTableType() {
    148             return mTableType;
    149         }
    150 
    151         public int getTableTypePid() {
    152             return mTableTypePid;
    153         }
    154     }
    155 
    156     public static class VctItem {
    157         private final String mShortName;
    158         private final String mLongName;
    159         private final int mServiceType;
    160         private final int mChannelTsid;
    161         private final int mProgramNumber;
    162         private final int mMajorChannelNumber;
    163         private final int mMinorChannelNumber;
    164         private final int mSourceId;
    165         private String mDescription;
    166 
    167         public VctItem(String shortName, String longName, int serviceType, int channelTsid,
    168                 int programNumber, int majorChannelNumber, int minorChannelNumber, int sourceId) {
    169             mShortName = shortName;
    170             mLongName = longName;
    171             mServiceType = serviceType;
    172             mChannelTsid = channelTsid;
    173             mProgramNumber = programNumber;
    174             mMajorChannelNumber = majorChannelNumber;
    175             mMinorChannelNumber = minorChannelNumber;
    176             mSourceId = sourceId;
    177         }
    178 
    179         public String getShortName() {
    180             return mShortName;
    181         }
    182 
    183         public String getLongName() {
    184             return mLongName;
    185         }
    186 
    187         public int getServiceType() {
    188             return mServiceType;
    189         }
    190 
    191         public int getChannelTsid() {
    192             return mChannelTsid;
    193         }
    194 
    195         public int getProgramNumber() {
    196             return mProgramNumber;
    197         }
    198 
    199         public int getMajorChannelNumber() {
    200             return mMajorChannelNumber;
    201         }
    202 
    203         public int getMinorChannelNumber() {
    204             return mMinorChannelNumber;
    205         }
    206 
    207         public int getSourceId() {
    208             return mSourceId;
    209         }
    210 
    211         @Override
    212         public String toString() {
    213             return String
    214                     .format(Locale.US, "ShortName: %s LongName: %s ServiceType: %d ChannelTsid: %x "
    215                             + "ProgramNumber:%d %d-%d SourceId: %x",
    216                     mShortName, mLongName, mServiceType, mChannelTsid,
    217                     mProgramNumber, mMajorChannelNumber, mMinorChannelNumber, mSourceId);
    218         }
    219 
    220         public void setDescription(String description) {
    221             mDescription = description;
    222         }
    223 
    224         public String getDescription() {
    225             return mDescription;
    226         }
    227     }
    228 
    229     /**
    230      * A base class for descriptors of Ts packets.
    231      */
    232     public abstract static class TsDescriptor {
    233         public abstract int getTag();
    234     }
    235 
    236     public static class ContentAdvisoryDescriptor extends TsDescriptor {
    237         private final List<RatingRegion> mRatingRegions;
    238 
    239         public ContentAdvisoryDescriptor(List<RatingRegion> ratingRegions) {
    240             mRatingRegions = ratingRegions;
    241         }
    242 
    243         @Override
    244         public int getTag() {
    245             return SectionParser.DESCRIPTOR_TAG_CONTENT_ADVISORY;
    246         }
    247 
    248         public List<RatingRegion> getRatingRegions() {
    249             return mRatingRegions;
    250         }
    251     }
    252 
    253     public static class CaptionServiceDescriptor extends TsDescriptor {
    254         private final List<AtscCaptionTrack> mCaptionTracks;
    255 
    256         public CaptionServiceDescriptor(List<AtscCaptionTrack> captionTracks) {
    257             mCaptionTracks = captionTracks;
    258         }
    259 
    260         @Override
    261         public int getTag() {
    262             return SectionParser.DESCRIPTOR_TAG_CAPTION_SERVICE;
    263         }
    264 
    265         public List<AtscCaptionTrack> getCaptionTracks() {
    266             return mCaptionTracks;
    267         }
    268     }
    269 
    270     public static class ExtendedChannelNameDescriptor extends TsDescriptor {
    271         private final String mLongChannelName;
    272 
    273         public ExtendedChannelNameDescriptor(String longChannelName) {
    274             mLongChannelName = longChannelName;
    275         }
    276 
    277         @Override
    278         public int getTag() {
    279             return SectionParser.DESCRIPTOR_TAG_EXTENDED_CHANNEL_NAME;
    280         }
    281 
    282         public String getLongChannelName() {
    283             return mLongChannelName;
    284         }
    285     }
    286 
    287     public static class GenreDescriptor extends TsDescriptor {
    288         private final String[] mBroadcastGenres;
    289         private final String[] mCanonicalGenres;
    290 
    291         public GenreDescriptor(String[] broadcastGenres, String[] canonicalGenres) {
    292             mBroadcastGenres = broadcastGenres;
    293             mCanonicalGenres = canonicalGenres;
    294         }
    295 
    296         @Override
    297         public int getTag() {
    298             return SectionParser.DESCRIPTOR_TAG_GENRE;
    299         }
    300 
    301         public String[] getBroadcastGenres() {
    302             return mBroadcastGenres;
    303         }
    304 
    305         public String[] getCanonicalGenres() {
    306             return mCanonicalGenres;
    307         }
    308     }
    309 
    310     public static class Ac3AudioDescriptor extends TsDescriptor {
    311         // See A/52 Annex A. Table A4.2
    312         private static final byte SAMPLE_RATE_CODE_48000HZ = 0;
    313         private static final byte SAMPLE_RATE_CODE_44100HZ = 1;
    314         private static final byte SAMPLE_RATE_CODE_32000HZ = 2;
    315 
    316         private final byte mSampleRateCode;
    317         private final byte mBsid;
    318         private final byte mBitRateCode;
    319         private final byte mSurroundMode;
    320         private final byte mBsmod;
    321         private final int mNumChannels;
    322         private final boolean mFullSvc;
    323         private final byte mLangCod;
    324         private final byte mLangCod2;
    325         private final byte mMainId;
    326         private final byte mPriority;
    327         private final byte mAsvcflags;
    328         private final String mText;
    329         private final String mLanguage;
    330         private final String mLanguage2;
    331 
    332         public Ac3AudioDescriptor(byte sampleRateCode, byte bsid, byte bitRateCode,
    333                 byte surroundMode, byte bsmod, int numChannels, boolean fullSvc, byte langCod,
    334                 byte langCod2, byte mainId, byte priority, byte asvcflags, String text,
    335                 String language, String language2) {
    336             mSampleRateCode = sampleRateCode;
    337             mBsid = bsid;
    338             mBitRateCode = bitRateCode;
    339             mSurroundMode = surroundMode;
    340             mBsmod = bsmod;
    341             mNumChannels = numChannels;
    342             mFullSvc = fullSvc;
    343             mLangCod = langCod;
    344             mLangCod2 = langCod2;
    345             mMainId = mainId;
    346             mPriority = priority;
    347             mAsvcflags = asvcflags;
    348             mText = text;
    349             mLanguage = language;
    350             mLanguage2 = language2;
    351         }
    352 
    353         @Override
    354         public int getTag() {
    355             return SectionParser.DESCRIPTOR_TAG_AC3_AUDIO_STREAM;
    356         }
    357 
    358         public byte getSampleRateCode() {
    359             return mSampleRateCode;
    360         }
    361 
    362         public int getSampleRate() {
    363             switch (mSampleRateCode) {
    364                 case SAMPLE_RATE_CODE_48000HZ:
    365                     return 48000;
    366                 case SAMPLE_RATE_CODE_44100HZ:
    367                     return 44100;
    368                 case SAMPLE_RATE_CODE_32000HZ:
    369                     return 32000;
    370                 default:
    371                     return 0;
    372             }
    373         }
    374 
    375         public byte getBsid() {
    376             return mBsid;
    377         }
    378 
    379         public byte getBitRateCode() {
    380             return mBitRateCode;
    381         }
    382 
    383         public byte getSurroundMode() {
    384             return mSurroundMode;
    385         }
    386 
    387         public byte getBsmod() {
    388             return mBsmod;
    389         }
    390 
    391         public int getNumChannels() {
    392             return mNumChannels;
    393         }
    394 
    395         public boolean isFullSvc() {
    396             return mFullSvc;
    397         }
    398 
    399         public byte getLangCod() {
    400             return mLangCod;
    401         }
    402 
    403         public byte getLangCod2() {
    404             return mLangCod2;
    405         }
    406 
    407         public byte getMainId() {
    408             return mMainId;
    409         }
    410 
    411         public byte getPriority() {
    412             return mPriority;
    413         }
    414 
    415         public byte getAsvcflags() {
    416             return mAsvcflags;
    417         }
    418 
    419         public String getText() {
    420             return mText;
    421         }
    422 
    423         public String getLanguage() {
    424             return mLanguage;
    425         }
    426 
    427         public String getLanguage2() {
    428             return mLanguage2;
    429         }
    430 
    431         @Override
    432         public String toString() {
    433             return String.format(Locale.US,
    434                     "AC3 audio stream sampleRateCode: %d, bsid: %d, bitRateCode: %d, "
    435                     + "surroundMode: %d, bsmod: %d, numChannels: %d, fullSvc: %s, langCod: %d, "
    436                     + "langCod2: %d, mainId: %d, priority: %d, avcflags: %d, text: %s, language: %s"
    437                     + ", language2: %s", mSampleRateCode, mBsid, mBitRateCode, mSurroundMode,
    438                     mBsmod, mNumChannels, mFullSvc, mLangCod, mLangCod2, mMainId, mPriority,
    439                     mAsvcflags, mText, mLanguage, mLanguage2);
    440         }
    441     }
    442 
    443     public static class Iso639LanguageDescriptor extends TsDescriptor {
    444         private final List<AtscAudioTrack> mAudioTracks;
    445 
    446         public Iso639LanguageDescriptor(List<AtscAudioTrack> audioTracks) {
    447             mAudioTracks = audioTracks;
    448         }
    449 
    450         @Override
    451         public int getTag() {
    452             return SectionParser.DESCRIPTOR_TAG_ISO639LANGUAGE;
    453         }
    454 
    455         public List<AtscAudioTrack> getAudioTracks() {
    456             return mAudioTracks;
    457         }
    458 
    459         @Override
    460         public String toString() {
    461             return String.format("%s %s", getClass().getName(), mAudioTracks);
    462         }
    463     }
    464 
    465     public static class RatingRegion {
    466         private final int mName;
    467         private final String mDescription;
    468         private final List<RegionalRating> mRegionalRatings;
    469 
    470         public RatingRegion(int name, String description, List<RegionalRating> regionalRatings) {
    471             mName = name;
    472             mDescription = description;
    473             mRegionalRatings = regionalRatings;
    474         }
    475 
    476         public int getName() {
    477             return mName;
    478         }
    479 
    480         public String getDescription() {
    481             return mDescription;
    482         }
    483 
    484         public List<RegionalRating> getRegionalRatings() {
    485             return mRegionalRatings;
    486         }
    487     }
    488 
    489     public static class RegionalRating {
    490         private final int mDimension;
    491         private final int mRating;
    492 
    493         public RegionalRating(int dimension, int rating) {
    494             mDimension = dimension;
    495             mRating = rating;
    496         }
    497 
    498         public int getDimension() {
    499             return mDimension;
    500         }
    501 
    502         public int getRating() {
    503             return mRating;
    504         }
    505     }
    506 
    507     public static class EitItem implements Comparable<EitItem>, TvTracksInterface {
    508         public static final long INVALID_PROGRAM_ID = -1;
    509 
    510         // A program id is a primary key of TvContract.Programs table. So it must be positive.
    511         private final long mProgramId;
    512         private final int mEventId;
    513         private final String mTitleText;
    514         private String mDescription;
    515         private final long mStartTime;
    516         private final int mLengthInSecond;
    517         private final String mContentRating;
    518         private final List<AtscAudioTrack> mAudioTracks;
    519         private final List<AtscCaptionTrack> mCaptionTracks;
    520         private boolean mHasCaptionTrack;
    521         private final String mBroadcastGenre;
    522         private final String mCanonicalGenre;
    523 
    524         public EitItem(long programId, int eventId, String titleText, long startTime,
    525                 int lengthInSecond, String contentRating, List<AtscAudioTrack> audioTracks,
    526                 List<AtscCaptionTrack> captionTracks, String broadcastGenre, String canonicalGenre,
    527                 String description) {
    528             mProgramId = programId;
    529             mEventId = eventId;
    530             mTitleText = titleText;
    531             mStartTime = startTime;
    532             mLengthInSecond = lengthInSecond;
    533             mContentRating = contentRating;
    534             mAudioTracks = audioTracks;
    535             mCaptionTracks = captionTracks;
    536             mBroadcastGenre = broadcastGenre;
    537             mCanonicalGenre = canonicalGenre;
    538             mDescription = description;
    539         }
    540 
    541         public long getProgramId() {
    542             return mProgramId;
    543         }
    544 
    545         public int getEventId() {
    546             return mEventId;
    547         }
    548 
    549         public String getTitleText() {
    550             return mTitleText;
    551         }
    552 
    553         public void setDescription(String description) {
    554             mDescription = description;
    555         }
    556 
    557         public String getDescription() {
    558             return mDescription;
    559         }
    560 
    561         public long getStartTime() {
    562             return mStartTime;
    563         }
    564 
    565         public int getLengthInSecond() {
    566             return mLengthInSecond;
    567         }
    568 
    569         public long getStartTimeUtcMillis() {
    570             return ConvertUtils.convertGPSTimeToUnixEpoch(mStartTime) * DateUtils.SECOND_IN_MILLIS;
    571         }
    572 
    573         public long getEndTimeUtcMillis() {
    574             return ConvertUtils.convertGPSTimeToUnixEpoch(
    575                     mStartTime + mLengthInSecond) * DateUtils.SECOND_IN_MILLIS;
    576         }
    577 
    578         public String getContentRating() {
    579             return mContentRating;
    580         }
    581 
    582         @Override
    583         public List<AtscAudioTrack> getAudioTracks() {
    584             return mAudioTracks;
    585         }
    586 
    587         @Override
    588         public List<AtscCaptionTrack> getCaptionTracks() {
    589             return mCaptionTracks;
    590         }
    591 
    592         public String getBroadcastGenre() {
    593             return mBroadcastGenre;
    594         }
    595 
    596         public String getCanonicalGenre() {
    597             return mCanonicalGenre;
    598         }
    599 
    600         @Override
    601         public void setHasCaptionTrack() {
    602             mHasCaptionTrack = true;
    603         }
    604 
    605         @Override
    606         public boolean hasCaptionTrack() {
    607             return mHasCaptionTrack;
    608         }
    609 
    610         @Override
    611         public int compareTo(@NonNull EitItem item) {
    612             // The list of caption tracks and the program ids are not compared in here because the
    613             // channels in TIF have the concept of the caption and audio tracks while the programs
    614             // do not and the programs in TIF only have a program id since they are the rows of
    615             // Content Provider.
    616             int ret = mEventId - item.getEventId();
    617             if (ret != 0) {
    618                 return ret;
    619             }
    620             ret = StringUtils.compare(mTitleText, item.getTitleText());
    621             if (ret != 0) {
    622                 return ret;
    623             }
    624             if (mStartTime > item.getStartTime()) {
    625                 return 1;
    626             } else if (mStartTime < item.getStartTime()) {
    627                 return -1;
    628             }
    629             if (mLengthInSecond > item.getLengthInSecond()) {
    630                 return 1;
    631             } else if (mLengthInSecond < item.getLengthInSecond()) {
    632                 return -1;
    633             }
    634 
    635             // Compares content ratings
    636             ret = StringUtils.compare(mContentRating, item.getContentRating());
    637             if (ret != 0) {
    638                 return ret;
    639             }
    640 
    641             // Compares broadcast genres
    642             ret = StringUtils.compare(mBroadcastGenre, item.getBroadcastGenre());
    643             if (ret != 0) {
    644                 return ret;
    645             }
    646             // Compares canonical genres
    647             ret = StringUtils.compare(mCanonicalGenre, item.getCanonicalGenre());
    648             if (ret != 0) {
    649                 return ret;
    650             }
    651 
    652             // Compares descriptions
    653             return StringUtils.compare(mDescription, item.getDescription());
    654         }
    655 
    656         public String getAudioLanguage() {
    657             if (mAudioTracks == null) {
    658                 return "";
    659             }
    660             ArrayList<String> languages = new ArrayList<>();
    661             for (AtscAudioTrack audioTrack : mAudioTracks) {
    662                 languages.add(audioTrack.language);
    663             }
    664             return TextUtils.join(",", languages);
    665         }
    666 
    667         @Override
    668         public String toString() {
    669             return String.format(Locale.US,
    670                     "EitItem programId: %d, eventId: %d, title: %s, startTime: %10d, "
    671                             + "length: %6d, rating: %s, audio tracks: %d, caption tracks: %d, "
    672                             + "genres (broadcast: %s, canonical: %s), description: %s",
    673                     mProgramId, mEventId, mTitleText, mStartTime, mLengthInSecond, mContentRating,
    674                     mAudioTracks != null ? mAudioTracks.size() : 0,
    675                     mCaptionTracks != null ? mCaptionTracks.size() : 0,
    676                     mBroadcastGenre, mCanonicalGenre, mDescription);
    677         }
    678     }
    679 
    680     public static class EttItem {
    681         public final int eventId;
    682         public final String text;
    683 
    684         public EttItem(int eventId, String text) {
    685             this.eventId = eventId;
    686             this.text = text;
    687         }
    688     }
    689 }
    690