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.usbtuner.data;
     18 
     19 import android.support.annotation.NonNull;
     20 import android.text.TextUtils;
     21 import android.text.format.DateUtils;
     22 
     23 import com.android.usbtuner.data.Track.AtscAudioTrack;
     24 import com.android.usbtuner.data.Track.AtscCaptionTrack;
     25 import com.android.usbtuner.ts.SectionParser;
     26 import com.android.usbtuner.util.ConvertUtils;
     27 import com.android.usbtuner.util.IsoUtils;
     28 import com.android.usbtuner.util.StringUtils;
     29 
     30 import java.util.ArrayList;
     31 import java.util.List;
     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.format("ShortName: %s LongName: %s ServiceType: %d ChannelTsid: %x "
    214                             + "ProgramNumber:%d %d-%d SourceId: %x",
    215                     mShortName, mLongName, mServiceType, mChannelTsid,
    216                     mProgramNumber, mMajorChannelNumber, mMinorChannelNumber, mSourceId);
    217         }
    218 
    219         public void setDescription(String description) {
    220             mDescription = description;
    221         }
    222 
    223         public String getDescription() {
    224             return mDescription;
    225         }
    226     }
    227 
    228     /**
    229      * A base class for descriptors of Ts packets.
    230      */
    231     public abstract static class TsDescriptor {
    232         public abstract int getTag();
    233     }
    234 
    235     public static class ContentAdvisoryDescriptor extends TsDescriptor {
    236         private final List<RatingRegion> mRatingRegions;
    237 
    238         public ContentAdvisoryDescriptor(List<RatingRegion> ratingRegions) {
    239             mRatingRegions = ratingRegions;
    240         }
    241 
    242         @Override
    243         public int getTag() {
    244             return SectionParser.DESCRIPTOR_TAG_CONTENT_ADVISORY;
    245         }
    246 
    247         public List<RatingRegion> getRatingRegions() {
    248             return mRatingRegions;
    249         }
    250     }
    251 
    252     public static class CaptionServiceDescriptor extends TsDescriptor {
    253         private final List<AtscCaptionTrack> mCaptionTracks;
    254 
    255         public CaptionServiceDescriptor(List<AtscCaptionTrack> captionTracks) {
    256             mCaptionTracks = captionTracks;
    257         }
    258 
    259         @Override
    260         public int getTag() {
    261             return SectionParser.DESCRIPTOR_TAG_CAPTION_SERVICE;
    262         }
    263 
    264         public List<AtscCaptionTrack> getCaptionTracks() {
    265             return mCaptionTracks;
    266         }
    267     }
    268 
    269     public static class ExtendedChannelNameDescriptor extends TsDescriptor {
    270         private final String mLongChannelName;
    271 
    272         public ExtendedChannelNameDescriptor(String longChannelName) {
    273             mLongChannelName = longChannelName;
    274         }
    275 
    276         @Override
    277         public int getTag() {
    278             return SectionParser.DESCRIPTOR_TAG_EXTENDED_CHANNEL_NAME;
    279         }
    280 
    281         public String getLongChannelName() {
    282             return mLongChannelName;
    283         }
    284     }
    285 
    286     public static class GenreDescriptor extends TsDescriptor {
    287         private final String[] mBroadcastGenres;
    288         private final String[] mCanonicalGenres;
    289 
    290         public GenreDescriptor(String[] broadcastGenres, String[] canonicalGenres) {
    291             mBroadcastGenres = broadcastGenres;
    292             mCanonicalGenres = canonicalGenres;
    293         }
    294 
    295         @Override
    296         public int getTag() {
    297             return SectionParser.DESCRIPTOR_TAG_GENRE;
    298         }
    299 
    300         public String[] getBroadcastGenres() {
    301             return mBroadcastGenres;
    302         }
    303 
    304         public String[] getCanonicalGenres() {
    305             return mCanonicalGenres;
    306         }
    307     }
    308 
    309     public static class Ac3AudioDescriptor extends TsDescriptor {
    310         // See A/52 Annex A. Table A4.2
    311         private static final byte SAMPLE_RATE_CODE_48000HZ = 0;
    312         private static final byte SAMPLE_RATE_CODE_44100HZ = 1;
    313         private static final byte SAMPLE_RATE_CODE_32000HZ = 2;
    314 
    315         private final byte mSampleRateCode;
    316         private final byte mBsid;
    317         private final byte mBitRateCode;
    318         private final byte mSurroundMode;
    319         private final byte mBsmod;
    320         private final int mNumChannels;
    321         private final boolean mFullSvc;
    322         private final byte mLangCod;
    323         private final byte mLangCod2;
    324         private final byte mMainId;
    325         private final byte mPriority;
    326         private final byte mAsvcflags;
    327         private final String mText;
    328         private final String mLanguage;
    329         private final String mLanguage2;
    330 
    331         public Ac3AudioDescriptor(byte sampleRateCode, byte bsid, byte bitRateCode,
    332                 byte surroundMode, byte bsmod, int numChannels, boolean fullSvc, byte langCod,
    333                 byte langCod2, byte mainId, byte priority, byte asvcflags, String text,
    334                 String language, String language2) {
    335             mSampleRateCode = sampleRateCode;
    336             mBsid = bsid;
    337             mBitRateCode = bitRateCode;
    338             mSurroundMode = surroundMode;
    339             mBsmod = bsmod;
    340             mNumChannels = numChannels;
    341             mFullSvc = fullSvc;
    342             mLangCod = langCod;
    343             mLangCod2 = langCod2;
    344             mMainId = mainId;
    345             mPriority = priority;
    346             mAsvcflags = asvcflags;
    347             mText = text;
    348             mLanguage = language;
    349             mLanguage2 = language2;
    350         }
    351 
    352         @Override
    353         public int getTag() {
    354             return SectionParser.DESCRIPTOR_TAG_AC3_AUDIO_STREAM;
    355         }
    356 
    357         public byte getSampleRateCode() {
    358             return mSampleRateCode;
    359         }
    360 
    361         public int getSampleRate() {
    362             switch (mSampleRateCode) {
    363                 case SAMPLE_RATE_CODE_48000HZ:
    364                     return 48000;
    365                 case SAMPLE_RATE_CODE_44100HZ:
    366                     return 44100;
    367                 case SAMPLE_RATE_CODE_32000HZ:
    368                     return 32000;
    369                 default:
    370                     return 0;
    371             }
    372         }
    373 
    374         public byte getBsid() {
    375             return mBsid;
    376         }
    377 
    378         public byte getBitRateCode() {
    379             return mBitRateCode;
    380         }
    381 
    382         public byte getSurroundMode() {
    383             return mSurroundMode;
    384         }
    385 
    386         public byte getBsmod() {
    387             return mBsmod;
    388         }
    389 
    390         public int getNumChannels() {
    391             return mNumChannels;
    392         }
    393 
    394         public boolean isFullSvc() {
    395             return mFullSvc;
    396         }
    397 
    398         public byte getLangCod() {
    399             return mLangCod;
    400         }
    401 
    402         public byte getLangCod2() {
    403             return mLangCod2;
    404         }
    405 
    406         public byte getMainId() {
    407             return mMainId;
    408         }
    409 
    410         public byte getPriority() {
    411             return mPriority;
    412         }
    413 
    414         public byte getAsvcflags() {
    415             return mAsvcflags;
    416         }
    417 
    418         public String getText() {
    419             return mText;
    420         }
    421 
    422         public String getLanguage() {
    423             return mLanguage;
    424         }
    425 
    426         public String getLanguage2() {
    427             return mLanguage2;
    428         }
    429 
    430         @Override
    431         public String toString() {
    432             return String.format("AC3 audio stream sampleRateCode: %d, bsid: %d, bitRateCode: %d, "
    433                     + "surroundMode: %d, bsmod: %d, numChannels: %d, fullSvc: %s, langCod: %d, "
    434                     + "langCod2: %d, mainId: %d, priority: %d, avcflags: %d, text: %s, language: %s"
    435                     + ", language2: %s", mSampleRateCode, mBsid, mBitRateCode, mSurroundMode,
    436                     mBsmod, mNumChannels, mFullSvc, mLangCod, mLangCod2, mMainId, mPriority,
    437                     mAsvcflags, mText, mLanguage, mLanguage2);
    438         }
    439     }
    440 
    441     public static class Iso639LanguageDescriptor extends TsDescriptor {
    442         private final List<AtscAudioTrack> mAudioTracks;
    443 
    444         public Iso639LanguageDescriptor(List<AtscAudioTrack> audioTracks) {
    445             mAudioTracks = audioTracks;
    446         }
    447 
    448         @Override
    449         public int getTag() {
    450             return SectionParser.DESCRIPTOR_TAG_ISO639LANGUAGE;
    451         }
    452 
    453         public List<AtscAudioTrack> getAudioTracks() {
    454             return mAudioTracks;
    455         }
    456 
    457         @Override
    458         public String toString() {
    459             return String.format("%s %s", getClass().getName(), mAudioTracks);
    460         }
    461     }
    462 
    463     public static class RatingRegion {
    464         private final int mName;
    465         private final String mDescription;
    466         private final List<RegionalRating> mRegionalRatings;
    467 
    468         public RatingRegion(int name, String description, List<RegionalRating> regionalRatings) {
    469             mName = name;
    470             mDescription = description;
    471             mRegionalRatings = regionalRatings;
    472         }
    473 
    474         public int getName() {
    475             return mName;
    476         }
    477 
    478         public String getDescription() {
    479             return mDescription;
    480         }
    481 
    482         public List<RegionalRating> getRegionalRatings() {
    483             return mRegionalRatings;
    484         }
    485     }
    486 
    487     public static class RegionalRating {
    488         private int mDimension;
    489         private int mRating;
    490 
    491         public RegionalRating(int dimension, int rating) {
    492             mDimension = dimension;
    493             mRating = rating;
    494         }
    495 
    496         public int getDimension() {
    497             return mDimension;
    498         }
    499 
    500         public int getRating() {
    501             return mRating;
    502         }
    503     }
    504 
    505     public static class EitItem implements Comparable<EitItem>, TvTracksInterface {
    506         public static long INVALID_PROGRAM_ID = -1;
    507 
    508         // A program id is a primary key of TvContract.Programs table. So it must be positive.
    509         private final long mProgramId;
    510         private final int mEventId;
    511         private final String mTitleText;
    512         private String mDescription;
    513         private final long mStartTime;
    514         private final int mLengthInSecond;
    515         private final String mContentRating;
    516         private final List<AtscAudioTrack> mAudioTracks;
    517         private final List<AtscCaptionTrack> mCaptionTracks;
    518         private boolean mHasCaptionTrack;
    519         private final String mBroadcastGenre;
    520         private final String mCanonicalGenre;
    521 
    522         public EitItem(long programId, int eventId, String titleText, long startTime,
    523                 int lengthInSecond, String contentRating, List<AtscAudioTrack> audioTracks,
    524                 List<AtscCaptionTrack> captionTracks, String broadcastGenre, String canonicalGenre,
    525                 String description) {
    526             mProgramId = programId;
    527             mEventId = eventId;
    528             mTitleText = titleText;
    529             mStartTime = startTime;
    530             mLengthInSecond = lengthInSecond;
    531             mContentRating = contentRating;
    532             mAudioTracks = audioTracks;
    533             mCaptionTracks = captionTracks;
    534             mBroadcastGenre = broadcastGenre;
    535             mCanonicalGenre = canonicalGenre;
    536             mDescription = description;
    537         }
    538 
    539         public long getProgramId() {
    540             return mProgramId;
    541         }
    542 
    543         public int getEventId() {
    544             return mEventId;
    545         }
    546 
    547         public String getTitleText() {
    548             return mTitleText;
    549         }
    550 
    551         public void setDescription(String description) {
    552             mDescription = description;
    553         }
    554 
    555         public String getDescription() {
    556             return mDescription;
    557         }
    558 
    559         public long getStartTime() {
    560             return mStartTime;
    561         }
    562 
    563         public int getLengthInSecond() {
    564             return mLengthInSecond;
    565         }
    566 
    567         public long getStartTimeUtcMillis() {
    568             return ConvertUtils.convertGPSTimeToUnixEpoch(mStartTime) * DateUtils.SECOND_IN_MILLIS;
    569         }
    570 
    571         public long getEndTimeUtcMillis() {
    572             return ConvertUtils.convertGPSTimeToUnixEpoch(
    573                     mStartTime + mLengthInSecond) * DateUtils.SECOND_IN_MILLIS;
    574         }
    575 
    576         public String getContentRating() {
    577             return mContentRating;
    578         }
    579 
    580         @Override
    581         public List<AtscAudioTrack> getAudioTracks() {
    582             return mAudioTracks;
    583         }
    584 
    585         @Override
    586         public List<AtscCaptionTrack> getCaptionTracks() {
    587             return mCaptionTracks;
    588         }
    589 
    590         public String getBroadcastGenre() {
    591             return mBroadcastGenre;
    592         }
    593 
    594         public String getCanonicalGenre() {
    595             return mCanonicalGenre;
    596         }
    597 
    598         @Override
    599         public void setHasCaptionTrack() {
    600             mHasCaptionTrack = true;
    601         }
    602 
    603         @Override
    604         public boolean hasCaptionTrack() {
    605             return mHasCaptionTrack;
    606         }
    607 
    608         @Override
    609         public int compareTo(@NonNull EitItem item) {
    610             // The list of caption tracks and the program ids are not compared in here because the
    611             // channels in TIF have the concept of the caption and audio tracks while the programs
    612             // do not and the programs in TIF only have a program id since they are the rows of
    613             // Content Provider.
    614             int ret = mEventId - item.getEventId();
    615             if (ret != 0) {
    616                 return ret;
    617             }
    618             ret = StringUtils.compare(mTitleText, item.getTitleText());
    619             if (ret != 0) {
    620                 return ret;
    621             }
    622             if (mStartTime > item.getStartTime()) {
    623                 return 1;
    624             } else if (mStartTime < item.getStartTime()) {
    625                 return -1;
    626             }
    627             if (mLengthInSecond > item.getLengthInSecond()) {
    628                 return 1;
    629             } else if (mLengthInSecond < item.getLengthInSecond()) {
    630                 return -1;
    631             }
    632 
    633             // Compares content ratings
    634             ret = StringUtils.compare(mContentRating, item.getContentRating());
    635             if (ret != 0) {
    636                 return ret;
    637             }
    638 
    639             // Compares broadcast genres
    640             ret = StringUtils.compare(mBroadcastGenre, item.getBroadcastGenre());
    641             if (ret != 0) {
    642                 return ret;
    643             }
    644             // Compares canonical genres
    645             ret = StringUtils.compare(mCanonicalGenre, item.getCanonicalGenre());
    646             if (ret != 0) {
    647                 return ret;
    648             }
    649 
    650             // Compares descriptions
    651             return StringUtils.compare(mDescription, item.getDescription());
    652         }
    653 
    654         public String getAudioLanguage() {
    655             if (mAudioTracks == null) {
    656                 return "";
    657             }
    658             ArrayList<String> languages = new ArrayList<>();
    659             for (AtscAudioTrack audioTrack : mAudioTracks) {
    660                 if (IsoUtils.isValidIso3Language(audioTrack.language)) {
    661                     languages.add(audioTrack.language);
    662                 }
    663             }
    664             return TextUtils.join(",", languages);
    665         }
    666 
    667         @Override
    668         public String toString() {
    669             return String.format("EitItem programId: %d, eventId: %d, title: %s, startTime: %10d"
    670                             + "length: %6d, rating: %s, audio tracks: %d, caption tracks: %d, "
    671                             + "genres (broadcast: %s, canonical: %s), description: %s",
    672                     mProgramId, mEventId, mTitleText, mStartTime, mLengthInSecond, mContentRating,
    673                     mAudioTracks != null ? mAudioTracks.size() : 0,
    674                     mCaptionTracks != null ? mCaptionTracks.size() : 0,
    675                     mBroadcastGenre, mCanonicalGenre, mDescription);
    676         }
    677     }
    678 
    679     public static class EttItem {
    680         public final int eventId;
    681         public final String text;
    682 
    683         public EttItem(int eventId, String text) {
    684             this.eventId = eventId;
    685             this.text = text;
    686         }
    687     }
    688 }
    689