1 /* 2 * Copyright (C) 2022 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.samples.sampletunertvinput; 18 19 import android.content.Context; 20 import android.media.tv.tuner.Tuner; 21 import android.media.tv.tuner.dvr.DvrPlayback; 22 import android.media.tv.tuner.dvr.DvrSettings; 23 import android.media.tv.tuner.filter.AvSettings; 24 import android.media.tv.tuner.filter.Filter; 25 import android.media.tv.tuner.filter.FilterCallback; 26 import android.media.tv.tuner.filter.FilterEvent; 27 import android.media.tv.tuner.filter.SectionSettingsWithSectionBits; 28 import android.media.tv.tuner.filter.TsFilterConfiguration; 29 import android.media.tv.tuner.frontend.DvbtFrontendSettings; 30 import android.os.Handler; 31 import android.os.HandlerExecutor; 32 import android.os.ParcelFileDescriptor; 33 import android.util.Log; 34 35 import java.io.File; 36 import java.io.FileNotFoundException; 37 38 public class SampleTunerTvInputUtils { 39 private static final String TAG = "SampleTunerTvInput"; 40 private static final boolean DEBUG = true; 41 42 private static final int AUDIO_TPID = 257; 43 private static final int VIDEO_TPID = 256; 44 private static final int SECTION_TPID = 255; 45 private static final int FILTER_BUFFER_SIZE = 16000000; 46 47 private static final int STATUS_MASK = 0xf; 48 private static final int LOW_THRESHOLD = 0x1000; 49 private static final int HIGH_THRESHOLD = 0x07fff; 50 private static final int DVR_BUFFER_SIZE = 4000000; 51 private static final int PACKET_SIZE = 188; 52 private static final long FREQUENCY = 578000; 53 private static final int INPUT_FILE_MAX_SIZE = 1000000; 54 configureDvrPlayback(Tuner tuner, Handler handler, int dataFormat)55 public static DvrPlayback configureDvrPlayback(Tuner tuner, Handler handler, int dataFormat) { 56 DvrPlayback dvr = tuner.openDvrPlayback(DVR_BUFFER_SIZE, new HandlerExecutor(handler), 57 status -> { 58 if (DEBUG) { 59 Log.d(TAG, "onPlaybackStatusChanged status=" + status); 60 } 61 }); 62 int res = dvr.configure( 63 DvrSettings.builder() 64 .setStatusMask(STATUS_MASK) 65 .setLowThreshold(LOW_THRESHOLD) 66 .setHighThreshold(HIGH_THRESHOLD) 67 .setDataFormat(dataFormat) 68 .setPacketSize(PACKET_SIZE) 69 .build()); 70 if (DEBUG) { 71 Log.d(TAG, "config res=" + res); 72 } 73 return dvr; 74 } 75 readFilePlaybackInput(Context context, DvrPlayback dvr, String fileName)76 public static void readFilePlaybackInput(Context context, DvrPlayback dvr, String fileName) { 77 String testFile = context.getFilesDir().getAbsolutePath() + "/" + fileName; 78 File file = new File(testFile); 79 if (file.exists()) { 80 try { 81 dvr.setFileDescriptor( 82 ParcelFileDescriptor.open(file, ParcelFileDescriptor.MODE_READ_WRITE)); 83 } catch (FileNotFoundException e) { 84 Log.e(TAG, "Failed to create FD"); 85 } 86 } else { 87 Log.w(TAG, "File not existing"); 88 } 89 90 long read = dvr.read(INPUT_FILE_MAX_SIZE); 91 if (DEBUG) { 92 Log.d(TAG, "read=" + read); 93 } 94 } 95 tune(Tuner tuner, Handler handler)96 public static void tune(Tuner tuner, Handler handler) { 97 DvbtFrontendSettings feSettings = DvbtFrontendSettings.builder() 98 .setFrequencyLong(FREQUENCY) 99 .setTransmissionMode(DvbtFrontendSettings.TRANSMISSION_MODE_AUTO) 100 .setBandwidth(DvbtFrontendSettings.BANDWIDTH_8MHZ) 101 .setConstellation(DvbtFrontendSettings.CONSTELLATION_AUTO) 102 .setHierarchy(DvbtFrontendSettings.HIERARCHY_AUTO) 103 .setHighPriorityCodeRate(DvbtFrontendSettings.CODERATE_AUTO) 104 .setLowPriorityCodeRate(DvbtFrontendSettings.CODERATE_AUTO) 105 .setGuardInterval(DvbtFrontendSettings.GUARD_INTERVAL_AUTO) 106 .setHighPriority(true) 107 .setStandard(DvbtFrontendSettings.STANDARD_T) 108 .build(); 109 110 tuner.setOnTuneEventListener(new HandlerExecutor(handler), tuneEvent -> { 111 if (DEBUG) { 112 Log.d(TAG, "onTuneEvent " + tuneEvent); 113 } 114 }); 115 116 tuner.tune(feSettings); 117 } 118 createSectionFilter(Tuner tuner, Handler handler, FilterCallback callback)119 public static Filter createSectionFilter(Tuner tuner, Handler handler, 120 FilterCallback callback) { 121 Filter sectionFilter = tuner.openFilter(Filter.TYPE_TS, Filter.SUBTYPE_SECTION, 122 FILTER_BUFFER_SIZE, new HandlerExecutor(handler), callback); 123 124 SectionSettingsWithSectionBits settings = SectionSettingsWithSectionBits 125 .builder(Filter.TYPE_TS).build(); 126 127 sectionFilter.configure( 128 TsFilterConfiguration.builder().setTpid(SECTION_TPID) 129 .setSettings(settings).build()); 130 131 return sectionFilter; 132 } 133 createAvFilter(Tuner tuner, Handler handler, FilterCallback callback, boolean isAudio)134 public static Filter createAvFilter(Tuner tuner, Handler handler, 135 FilterCallback callback, boolean isAudio) { 136 Filter avFilter = tuner.openFilter(Filter.TYPE_TS, 137 isAudio ? Filter.SUBTYPE_AUDIO : Filter.SUBTYPE_VIDEO, 138 FILTER_BUFFER_SIZE, 139 new HandlerExecutor(handler), 140 callback); 141 142 AvSettings settings = 143 AvSettings.builder(Filter.TYPE_TS, isAudio).setPassthrough(false).build(); 144 avFilter.configure( 145 TsFilterConfiguration.builder(). 146 setTpid(isAudio ? AUDIO_TPID : VIDEO_TPID) 147 .setSettings(settings).build()); 148 return avFilter; 149 } 150 createDefaultLoggingFilterCallback(String filterType)151 public static FilterCallback createDefaultLoggingFilterCallback(String filterType) { 152 return new FilterCallback() { 153 @Override 154 public void onFilterEvent(Filter filter, FilterEvent[] events) { 155 if (DEBUG) { 156 Log.d(TAG, "onFilterEvent " + filterType + ", size=" + events.length); 157 } 158 for (int i = 0; i < events.length; i++) { 159 if (DEBUG) { 160 Log.d(TAG, "events[" + i + "] is " 161 + events[i].getClass().getSimpleName()); 162 } 163 } 164 } 165 166 @Override 167 public void onFilterStatusChanged(Filter filter, int status) { 168 if (DEBUG) { 169 Log.d(TAG, "onFilterStatusChanged " + filterType + ", status=" + status); 170 } 171 } 172 }; 173 } 174 } 175