11abddd9f6225298066094e20a6c29061b6af4590Nick Chalko/* 21abddd9f6225298066094e20a6c29061b6af4590Nick Chalko * Copyright (C) 2015 The Android Open Source Project 31abddd9f6225298066094e20a6c29061b6af4590Nick Chalko * 41abddd9f6225298066094e20a6c29061b6af4590Nick Chalko * Licensed under the Apache License, Version 2.0 (the "License"); 51abddd9f6225298066094e20a6c29061b6af4590Nick Chalko * you may not use this file except in compliance with the License. 61abddd9f6225298066094e20a6c29061b6af4590Nick Chalko * You may obtain a copy of the License at 71abddd9f6225298066094e20a6c29061b6af4590Nick Chalko * 81abddd9f6225298066094e20a6c29061b6af4590Nick Chalko * http://www.apache.org/licenses/LICENSE-2.0 91abddd9f6225298066094e20a6c29061b6af4590Nick Chalko * 101abddd9f6225298066094e20a6c29061b6af4590Nick Chalko * Unless required by applicable law or agreed to in writing, software 111abddd9f6225298066094e20a6c29061b6af4590Nick Chalko * distributed under the License is distributed on an "AS IS" BASIS, 121abddd9f6225298066094e20a6c29061b6af4590Nick Chalko * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 131abddd9f6225298066094e20a6c29061b6af4590Nick Chalko * See the License for the specific language governing permissions and 141abddd9f6225298066094e20a6c29061b6af4590Nick Chalko * limitations under the License. 151abddd9f6225298066094e20a6c29061b6af4590Nick Chalko */ 161abddd9f6225298066094e20a6c29061b6af4590Nick Chalko 1765fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalkopackage com.android.tv.tuner.exoplayer.buffer; 181abddd9f6225298066094e20a6c29061b6af4590Nick Chalko 191abddd9f6225298066094e20a6c29061b6af4590Nick Chalkoimport android.media.MediaFormat; 206ebde20b03db4c0d57f67acaac11832b610b966bNick Chalkoimport android.util.Log; 211abddd9f6225298066094e20a6c29061b6af4590Nick Chalkoimport android.util.Pair; 221abddd9f6225298066094e20a6c29061b6af4590Nick Chalko 236ebde20b03db4c0d57f67acaac11832b610b966bNick Chalkoimport com.android.tv.tuner.data.nano.Track.AtscCaptionTrack; 246ebde20b03db4c0d57f67acaac11832b610b966bNick Chalkoimport com.google.protobuf.nano.MessageNano; 256ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko 261abddd9f6225298066094e20a6c29061b6af4590Nick Chalkoimport java.io.DataInputStream; 271abddd9f6225298066094e20a6c29061b6af4590Nick Chalkoimport java.io.DataOutputStream; 281abddd9f6225298066094e20a6c29061b6af4590Nick Chalkoimport java.io.File; 291abddd9f6225298066094e20a6c29061b6af4590Nick Chalkoimport java.io.FileInputStream; 301abddd9f6225298066094e20a6c29061b6af4590Nick Chalkoimport java.io.FileOutputStream; 311abddd9f6225298066094e20a6c29061b6af4590Nick Chalkoimport java.io.IOException; 321abddd9f6225298066094e20a6c29061b6af4590Nick Chalkoimport java.nio.ByteBuffer; 331abddd9f6225298066094e20a6c29061b6af4590Nick Chalkoimport java.nio.charset.StandardCharsets; 341abddd9f6225298066094e20a6c29061b6af4590Nick Chalkoimport java.util.ArrayList; 356ebde20b03db4c0d57f67acaac11832b610b966bNick Chalkoimport java.util.List; 366ebde20b03db4c0d57f67acaac11832b610b966bNick Chalkoimport java.util.Map; 371abddd9f6225298066094e20a6c29061b6af4590Nick Chalkoimport java.util.SortedMap; 381abddd9f6225298066094e20a6c29061b6af4590Nick Chalko 391abddd9f6225298066094e20a6c29061b6af4590Nick Chalko/** 401abddd9f6225298066094e20a6c29061b6af4590Nick Chalko * Manages DVR storage. 411abddd9f6225298066094e20a6c29061b6af4590Nick Chalko */ 4265fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalkopublic class DvrStorageManager implements BufferManager.StorageManager { 436ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko private static final String TAG = "DvrStorageManager"; 441abddd9f6225298066094e20a6c29061b6af4590Nick Chalko 451abddd9f6225298066094e20a6c29061b6af4590Nick Chalko // TODO: make serializable classes and use protobuf after internal data structure is finalized. 461abddd9f6225298066094e20a6c29061b6af4590Nick Chalko private static final String KEY_PIXEL_WIDTH_HEIGHT_RATIO = 471abddd9f6225298066094e20a6c29061b6af4590Nick Chalko "com.google.android.videos.pixelWidthHeightRatio"; 486ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko private static final String META_FILE_TYPE_AUDIO = "audio"; 496ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko private static final String META_FILE_TYPE_VIDEO = "video"; 506ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko private static final String META_FILE_TYPE_CAPTION = "caption"; 511abddd9f6225298066094e20a6c29061b6af4590Nick Chalko private static final String META_FILE_SUFFIX = ".meta"; 521abddd9f6225298066094e20a6c29061b6af4590Nick Chalko private static final String IDX_FILE_SUFFIX = ".idx"; 536ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko private static final String IDX_FILE_SUFFIX_V2 = IDX_FILE_SUFFIX + "2"; 541abddd9f6225298066094e20a6c29061b6af4590Nick Chalko 551abddd9f6225298066094e20a6c29061b6af4590Nick Chalko // Size of minimum reserved storage buffer which will be used to save meta files 561abddd9f6225298066094e20a6c29061b6af4590Nick Chalko // and index files after actual recording finished. 57ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko private static final long MIN_BUFFER_BYTES = 256L * 1024 * 1024; 581abddd9f6225298066094e20a6c29061b6af4590Nick Chalko private static final int NO_VALUE = -1; 591abddd9f6225298066094e20a6c29061b6af4590Nick Chalko private static final long NO_VALUE_LONG = -1L; 601abddd9f6225298066094e20a6c29061b6af4590Nick Chalko 6165fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko private final File mBufferDir; 621abddd9f6225298066094e20a6c29061b6af4590Nick Chalko 631abddd9f6225298066094e20a6c29061b6af4590Nick Chalko // {@code true} when this is for recording, {@code false} when this is for replaying. 641abddd9f6225298066094e20a6c29061b6af4590Nick Chalko private final boolean mIsRecording; 651abddd9f6225298066094e20a6c29061b6af4590Nick Chalko 661abddd9f6225298066094e20a6c29061b6af4590Nick Chalko public DvrStorageManager(File file, boolean isRecording) { 6765fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko mBufferDir = file; 6865fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko mBufferDir.mkdirs(); 691abddd9f6225298066094e20a6c29061b6af4590Nick Chalko mIsRecording = isRecording; 701abddd9f6225298066094e20a6c29061b6af4590Nick Chalko } 711abddd9f6225298066094e20a6c29061b6af4590Nick Chalko 721abddd9f6225298066094e20a6c29061b6af4590Nick Chalko @Override 7365fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko public File getBufferDir() { 7465fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko return mBufferDir; 751abddd9f6225298066094e20a6c29061b6af4590Nick Chalko } 761abddd9f6225298066094e20a6c29061b6af4590Nick Chalko 771abddd9f6225298066094e20a6c29061b6af4590Nick Chalko @Override 781abddd9f6225298066094e20a6c29061b6af4590Nick Chalko public boolean isPersistent() { 791abddd9f6225298066094e20a6c29061b6af4590Nick Chalko return true; 801abddd9f6225298066094e20a6c29061b6af4590Nick Chalko } 811abddd9f6225298066094e20a6c29061b6af4590Nick Chalko 821abddd9f6225298066094e20a6c29061b6af4590Nick Chalko @Override 8365fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko public boolean reachedStorageMax(long bufferSize, long pendingDelete) { 841abddd9f6225298066094e20a6c29061b6af4590Nick Chalko return false; 851abddd9f6225298066094e20a6c29061b6af4590Nick Chalko } 861abddd9f6225298066094e20a6c29061b6af4590Nick Chalko 871abddd9f6225298066094e20a6c29061b6af4590Nick Chalko @Override 881abddd9f6225298066094e20a6c29061b6af4590Nick Chalko public boolean hasEnoughBuffer(long pendingDelete) { 8965fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko return !mIsRecording || mBufferDir.getUsableSpace() >= MIN_BUFFER_BYTES; 901abddd9f6225298066094e20a6c29061b6af4590Nick Chalko } 911abddd9f6225298066094e20a6c29061b6af4590Nick Chalko 921abddd9f6225298066094e20a6c29061b6af4590Nick Chalko private void readFormatInt(DataInputStream in, MediaFormat format, String key) 931abddd9f6225298066094e20a6c29061b6af4590Nick Chalko throws IOException { 941abddd9f6225298066094e20a6c29061b6af4590Nick Chalko int val = in.readInt(); 951abddd9f6225298066094e20a6c29061b6af4590Nick Chalko if (val != NO_VALUE) { 961abddd9f6225298066094e20a6c29061b6af4590Nick Chalko format.setInteger(key, val); 971abddd9f6225298066094e20a6c29061b6af4590Nick Chalko } 981abddd9f6225298066094e20a6c29061b6af4590Nick Chalko } 991abddd9f6225298066094e20a6c29061b6af4590Nick Chalko 1001abddd9f6225298066094e20a6c29061b6af4590Nick Chalko private void readFormatLong(DataInputStream in, MediaFormat format, String key) 1011abddd9f6225298066094e20a6c29061b6af4590Nick Chalko throws IOException { 1021abddd9f6225298066094e20a6c29061b6af4590Nick Chalko long val = in.readLong(); 1031abddd9f6225298066094e20a6c29061b6af4590Nick Chalko if (val != NO_VALUE_LONG) { 1041abddd9f6225298066094e20a6c29061b6af4590Nick Chalko format.setLong(key, val); 1051abddd9f6225298066094e20a6c29061b6af4590Nick Chalko } 1061abddd9f6225298066094e20a6c29061b6af4590Nick Chalko } 1071abddd9f6225298066094e20a6c29061b6af4590Nick Chalko 1081abddd9f6225298066094e20a6c29061b6af4590Nick Chalko private void readFormatFloat(DataInputStream in, MediaFormat format, String key) 1091abddd9f6225298066094e20a6c29061b6af4590Nick Chalko throws IOException { 1101abddd9f6225298066094e20a6c29061b6af4590Nick Chalko float val = in.readFloat(); 1111abddd9f6225298066094e20a6c29061b6af4590Nick Chalko if (val != NO_VALUE) { 1121abddd9f6225298066094e20a6c29061b6af4590Nick Chalko format.setFloat(key, val); 1131abddd9f6225298066094e20a6c29061b6af4590Nick Chalko } 1141abddd9f6225298066094e20a6c29061b6af4590Nick Chalko } 1151abddd9f6225298066094e20a6c29061b6af4590Nick Chalko 1161abddd9f6225298066094e20a6c29061b6af4590Nick Chalko private String readString(DataInputStream in) throws IOException { 1171abddd9f6225298066094e20a6c29061b6af4590Nick Chalko int len = in.readInt(); 1181abddd9f6225298066094e20a6c29061b6af4590Nick Chalko if (len <= 0) { 1191abddd9f6225298066094e20a6c29061b6af4590Nick Chalko return null; 1201abddd9f6225298066094e20a6c29061b6af4590Nick Chalko } 1211abddd9f6225298066094e20a6c29061b6af4590Nick Chalko byte [] strBytes = new byte[len]; 1221abddd9f6225298066094e20a6c29061b6af4590Nick Chalko in.readFully(strBytes); 1231abddd9f6225298066094e20a6c29061b6af4590Nick Chalko return new String(strBytes, StandardCharsets.UTF_8); 1241abddd9f6225298066094e20a6c29061b6af4590Nick Chalko } 1251abddd9f6225298066094e20a6c29061b6af4590Nick Chalko 1261abddd9f6225298066094e20a6c29061b6af4590Nick Chalko private void readFormatString(DataInputStream in, MediaFormat format, String key) 1271abddd9f6225298066094e20a6c29061b6af4590Nick Chalko throws IOException { 1281abddd9f6225298066094e20a6c29061b6af4590Nick Chalko String str = readString(in); 1291abddd9f6225298066094e20a6c29061b6af4590Nick Chalko if (str != null) { 1301abddd9f6225298066094e20a6c29061b6af4590Nick Chalko format.setString(key, str); 1311abddd9f6225298066094e20a6c29061b6af4590Nick Chalko } 1321abddd9f6225298066094e20a6c29061b6af4590Nick Chalko } 1331abddd9f6225298066094e20a6c29061b6af4590Nick Chalko 1346ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko private void readFormatStringOptional(DataInputStream in, MediaFormat format, String key) { 1356ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko try { 1366ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko String str = readString(in); 1376ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko if (str != null) { 1386ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko format.setString(key, str); 1396ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko } 1406ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko } catch (IOException e) { 1416ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko // Since we are reading optional field, ignore the exception. 1426ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko } 1436ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko } 1446ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko 1451abddd9f6225298066094e20a6c29061b6af4590Nick Chalko private ByteBuffer readByteBuffer(DataInputStream in) throws IOException { 1461abddd9f6225298066094e20a6c29061b6af4590Nick Chalko int len = in.readInt(); 1471abddd9f6225298066094e20a6c29061b6af4590Nick Chalko if (len <= 0) { 1481abddd9f6225298066094e20a6c29061b6af4590Nick Chalko return null; 1491abddd9f6225298066094e20a6c29061b6af4590Nick Chalko } 1501abddd9f6225298066094e20a6c29061b6af4590Nick Chalko byte [] bytes = new byte[len]; 1511abddd9f6225298066094e20a6c29061b6af4590Nick Chalko in.readFully(bytes); 1521abddd9f6225298066094e20a6c29061b6af4590Nick Chalko ByteBuffer buffer = ByteBuffer.allocate(len); 1531abddd9f6225298066094e20a6c29061b6af4590Nick Chalko buffer.put(bytes); 1541abddd9f6225298066094e20a6c29061b6af4590Nick Chalko buffer.flip(); 1551abddd9f6225298066094e20a6c29061b6af4590Nick Chalko 1561abddd9f6225298066094e20a6c29061b6af4590Nick Chalko return buffer; 1571abddd9f6225298066094e20a6c29061b6af4590Nick Chalko } 1581abddd9f6225298066094e20a6c29061b6af4590Nick Chalko 1591abddd9f6225298066094e20a6c29061b6af4590Nick Chalko private void readFormatByteBuffer(DataInputStream in, MediaFormat format, String key) 1601abddd9f6225298066094e20a6c29061b6af4590Nick Chalko throws IOException { 1611abddd9f6225298066094e20a6c29061b6af4590Nick Chalko ByteBuffer buffer = readByteBuffer(in); 1621abddd9f6225298066094e20a6c29061b6af4590Nick Chalko if (buffer != null) { 1631abddd9f6225298066094e20a6c29061b6af4590Nick Chalko format.setByteBuffer(key, buffer); 1641abddd9f6225298066094e20a6c29061b6af4590Nick Chalko } 1651abddd9f6225298066094e20a6c29061b6af4590Nick Chalko } 1661abddd9f6225298066094e20a6c29061b6af4590Nick Chalko 1671abddd9f6225298066094e20a6c29061b6af4590Nick Chalko @Override 1686ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko public List<BufferManager.TrackFormat> readTrackInfoFiles(boolean isAudio) { 1696ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko List<BufferManager.TrackFormat> trackFormatList = new ArrayList<>(); 1706ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko int index = 0; 1716ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko boolean trackNotFound = false; 1726ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko do { 1736ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko String fileName = (isAudio ? META_FILE_TYPE_AUDIO : META_FILE_TYPE_VIDEO) 1746ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko + ((index == 0) ? META_FILE_SUFFIX : (index + META_FILE_SUFFIX)); 1756ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko File file = new File(getBufferDir(), fileName); 1766ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko try (DataInputStream in = new DataInputStream(new FileInputStream(file))) { 1776ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko String name = readString(in); 1786ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko MediaFormat format = new MediaFormat(); 1796ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko readFormatString(in, format, MediaFormat.KEY_MIME); 1806ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko readFormatInt(in, format, MediaFormat.KEY_MAX_INPUT_SIZE); 1816ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko readFormatInt(in, format, MediaFormat.KEY_WIDTH); 1826ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko readFormatInt(in, format, MediaFormat.KEY_HEIGHT); 1836ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko readFormatInt(in, format, MediaFormat.KEY_CHANNEL_COUNT); 1846ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko readFormatInt(in, format, MediaFormat.KEY_SAMPLE_RATE); 1856ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko readFormatFloat(in, format, KEY_PIXEL_WIDTH_HEIGHT_RATIO); 1866ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko for (int i = 0; i < 3; ++i) { 1876ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko readFormatByteBuffer(in, format, "csd-" + i); 1886ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko } 1896ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko readFormatLong(in, format, MediaFormat.KEY_DURATION); 1906ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko 1916ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko // This is optional since language field is added later. 1926ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko readFormatStringOptional(in, format, MediaFormat.KEY_LANGUAGE); 1936ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko trackFormatList.add(new BufferManager.TrackFormat(name, format)); 1946ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko } catch (IOException e) { 1956ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko trackNotFound = true; 1961abddd9f6225298066094e20a6c29061b6af4590Nick Chalko } 1976ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko index++; 1986ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko } while(!trackNotFound); 1996ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko return trackFormatList; 2006ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko } 2016ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko 2026ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko /** 2036ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko * Reads caption information from files. 2046ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko * 2056ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko * @return a list of {@link AtscCaptionTrack} objects which store caption information. 2066ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko */ 2076ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko public List<AtscCaptionTrack> readCaptionInfoFiles() { 2086ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko List<AtscCaptionTrack> tracks = new ArrayList<>(); 2096ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko int index = 0; 2106ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko boolean trackNotFound = false; 2116ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko do { 2126ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko String fileName = META_FILE_TYPE_CAPTION + 2136ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko ((index == 0) ? META_FILE_SUFFIX : (index + META_FILE_SUFFIX)); 2146ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko File file = new File(getBufferDir(), fileName); 2156ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko try (DataInputStream in = new DataInputStream(new FileInputStream(file))) { 2166ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko byte[] data = new byte[(int) file.length()]; 2176ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko in.read(data); 2186ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko tracks.add(AtscCaptionTrack.parseFrom(data)); 2196ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko } catch (IOException e) { 2206ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko trackNotFound = true; 2216ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko } 2226ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko index++; 2236ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko } while(!trackNotFound); 2246ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko return tracks; 2256ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko } 2266ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko 2276ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko private ArrayList<BufferManager.PositionHolder> readOldIndexFile(File indexFile) 2286ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko throws IOException { 2296ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko ArrayList<BufferManager.PositionHolder> indices = new ArrayList<>(); 2306ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko try (DataInputStream in = new DataInputStream(new FileInputStream(indexFile))) { 2316ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko long count = in.readLong(); 2326ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko for (long i = 0; i < count; ++i) { 2336ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko long positionUs = in.readLong(); 2346ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko indices.add(new BufferManager.PositionHolder(positionUs, positionUs, 0)); 2356ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko } 2366ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko return indices; 2371abddd9f6225298066094e20a6c29061b6af4590Nick Chalko } 2381abddd9f6225298066094e20a6c29061b6af4590Nick Chalko } 2391abddd9f6225298066094e20a6c29061b6af4590Nick Chalko 2406ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko private ArrayList<BufferManager.PositionHolder> readNewIndexFile(File indexFile) 2416ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko throws IOException { 2426ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko ArrayList<BufferManager.PositionHolder> indices = new ArrayList<>(); 2436ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko try (DataInputStream in = new DataInputStream(new FileInputStream(indexFile))) { 2441abddd9f6225298066094e20a6c29061b6af4590Nick Chalko long count = in.readLong(); 2451abddd9f6225298066094e20a6c29061b6af4590Nick Chalko for (long i = 0; i < count; ++i) { 2466ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko long positionUs = in.readLong(); 2476ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko long basePositionUs = in.readLong(); 2486ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko int offset = in.readInt(); 2496ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko indices.add(new BufferManager.PositionHolder(positionUs, basePositionUs, offset)); 2501abddd9f6225298066094e20a6c29061b6af4590Nick Chalko } 2511abddd9f6225298066094e20a6c29061b6af4590Nick Chalko return indices; 2521abddd9f6225298066094e20a6c29061b6af4590Nick Chalko } 2531abddd9f6225298066094e20a6c29061b6af4590Nick Chalko } 2541abddd9f6225298066094e20a6c29061b6af4590Nick Chalko 2556ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko @Override 2566ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko public ArrayList<BufferManager.PositionHolder> readIndexFile(String trackId) 2576ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko throws IOException { 2586ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko File file = new File(getBufferDir(), trackId + IDX_FILE_SUFFIX_V2); 2596ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko if (file.exists()) { 2606ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko return readNewIndexFile(file); 2616ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko } else { 2626ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko return readOldIndexFile(new File(getBufferDir(),trackId + IDX_FILE_SUFFIX)); 2636ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko } 2646ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko } 2656ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko 2661abddd9f6225298066094e20a6c29061b6af4590Nick Chalko private void writeFormatInt(DataOutputStream out, MediaFormat format, String key) 2671abddd9f6225298066094e20a6c29061b6af4590Nick Chalko throws IOException { 2681abddd9f6225298066094e20a6c29061b6af4590Nick Chalko if (format.containsKey(key)) { 2691abddd9f6225298066094e20a6c29061b6af4590Nick Chalko out.writeInt(format.getInteger(key)); 2701abddd9f6225298066094e20a6c29061b6af4590Nick Chalko } else { 2711abddd9f6225298066094e20a6c29061b6af4590Nick Chalko out.writeInt(NO_VALUE); 2721abddd9f6225298066094e20a6c29061b6af4590Nick Chalko } 2731abddd9f6225298066094e20a6c29061b6af4590Nick Chalko } 2741abddd9f6225298066094e20a6c29061b6af4590Nick Chalko 2751abddd9f6225298066094e20a6c29061b6af4590Nick Chalko private void writeFormatLong(DataOutputStream out, MediaFormat format, String key) 2761abddd9f6225298066094e20a6c29061b6af4590Nick Chalko throws IOException { 2771abddd9f6225298066094e20a6c29061b6af4590Nick Chalko if (format.containsKey(key)) { 2781abddd9f6225298066094e20a6c29061b6af4590Nick Chalko out.writeLong(format.getLong(key)); 2791abddd9f6225298066094e20a6c29061b6af4590Nick Chalko } else { 2801abddd9f6225298066094e20a6c29061b6af4590Nick Chalko out.writeLong(NO_VALUE_LONG); 2811abddd9f6225298066094e20a6c29061b6af4590Nick Chalko } 2821abddd9f6225298066094e20a6c29061b6af4590Nick Chalko } 2831abddd9f6225298066094e20a6c29061b6af4590Nick Chalko 2841abddd9f6225298066094e20a6c29061b6af4590Nick Chalko private void writeFormatFloat(DataOutputStream out, MediaFormat format, String key) 2851abddd9f6225298066094e20a6c29061b6af4590Nick Chalko throws IOException { 2861abddd9f6225298066094e20a6c29061b6af4590Nick Chalko if (format.containsKey(key)) { 2871abddd9f6225298066094e20a6c29061b6af4590Nick Chalko out.writeFloat(format.getFloat(key)); 2881abddd9f6225298066094e20a6c29061b6af4590Nick Chalko } else { 2891abddd9f6225298066094e20a6c29061b6af4590Nick Chalko out.writeFloat(NO_VALUE); 2901abddd9f6225298066094e20a6c29061b6af4590Nick Chalko } 2911abddd9f6225298066094e20a6c29061b6af4590Nick Chalko } 2921abddd9f6225298066094e20a6c29061b6af4590Nick Chalko 2931abddd9f6225298066094e20a6c29061b6af4590Nick Chalko private void writeString(DataOutputStream out, String str) throws IOException { 2941abddd9f6225298066094e20a6c29061b6af4590Nick Chalko byte [] data = str.getBytes(StandardCharsets.UTF_8); 2951abddd9f6225298066094e20a6c29061b6af4590Nick Chalko out.writeInt(data.length); 2961abddd9f6225298066094e20a6c29061b6af4590Nick Chalko if (data.length > 0) { 2971abddd9f6225298066094e20a6c29061b6af4590Nick Chalko out.write(data); 2981abddd9f6225298066094e20a6c29061b6af4590Nick Chalko } 2991abddd9f6225298066094e20a6c29061b6af4590Nick Chalko } 3001abddd9f6225298066094e20a6c29061b6af4590Nick Chalko 3011abddd9f6225298066094e20a6c29061b6af4590Nick Chalko private void writeFormatString(DataOutputStream out, MediaFormat format, String key) 3021abddd9f6225298066094e20a6c29061b6af4590Nick Chalko throws IOException { 3031abddd9f6225298066094e20a6c29061b6af4590Nick Chalko if (format.containsKey(key)) { 3041abddd9f6225298066094e20a6c29061b6af4590Nick Chalko writeString(out, format.getString(key)); 3051abddd9f6225298066094e20a6c29061b6af4590Nick Chalko } else { 3061abddd9f6225298066094e20a6c29061b6af4590Nick Chalko out.writeInt(0); 3071abddd9f6225298066094e20a6c29061b6af4590Nick Chalko } 3081abddd9f6225298066094e20a6c29061b6af4590Nick Chalko } 3091abddd9f6225298066094e20a6c29061b6af4590Nick Chalko 3101abddd9f6225298066094e20a6c29061b6af4590Nick Chalko private void writeByteBuffer(DataOutputStream out, ByteBuffer buffer) throws IOException { 3111abddd9f6225298066094e20a6c29061b6af4590Nick Chalko byte [] data = new byte[buffer.limit()]; 3121abddd9f6225298066094e20a6c29061b6af4590Nick Chalko buffer.get(data); 3131abddd9f6225298066094e20a6c29061b6af4590Nick Chalko buffer.flip(); 3141abddd9f6225298066094e20a6c29061b6af4590Nick Chalko out.writeInt(data.length); 3151abddd9f6225298066094e20a6c29061b6af4590Nick Chalko if (data.length > 0) { 3161abddd9f6225298066094e20a6c29061b6af4590Nick Chalko out.write(data); 3171abddd9f6225298066094e20a6c29061b6af4590Nick Chalko } else { 3181abddd9f6225298066094e20a6c29061b6af4590Nick Chalko out.writeInt(0); 3191abddd9f6225298066094e20a6c29061b6af4590Nick Chalko } 3201abddd9f6225298066094e20a6c29061b6af4590Nick Chalko } 3211abddd9f6225298066094e20a6c29061b6af4590Nick Chalko 3221abddd9f6225298066094e20a6c29061b6af4590Nick Chalko private void writeFormatByteBuffer(DataOutputStream out, MediaFormat format, String key) 3231abddd9f6225298066094e20a6c29061b6af4590Nick Chalko throws IOException { 3241abddd9f6225298066094e20a6c29061b6af4590Nick Chalko if (format.containsKey(key)) { 3251abddd9f6225298066094e20a6c29061b6af4590Nick Chalko writeByteBuffer(out, format.getByteBuffer(key)); 3261abddd9f6225298066094e20a6c29061b6af4590Nick Chalko } else { 3271abddd9f6225298066094e20a6c29061b6af4590Nick Chalko out.writeInt(0); 3281abddd9f6225298066094e20a6c29061b6af4590Nick Chalko } 3291abddd9f6225298066094e20a6c29061b6af4590Nick Chalko } 3301abddd9f6225298066094e20a6c29061b6af4590Nick Chalko 3311abddd9f6225298066094e20a6c29061b6af4590Nick Chalko @Override 3326ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko public void writeTrackInfoFiles(List<BufferManager.TrackFormat> formatList, boolean isAudio) 3331abddd9f6225298066094e20a6c29061b6af4590Nick Chalko throws IOException { 3346ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko for (int i = 0; i < formatList.size() ; ++i) { 3356ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko BufferManager.TrackFormat trackFormat = formatList.get(i); 3366ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko String fileName = (isAudio ? META_FILE_TYPE_AUDIO : META_FILE_TYPE_VIDEO) 3376ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko + ((i == 0) ? META_FILE_SUFFIX : (i + META_FILE_SUFFIX)); 3386ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko File file = new File(getBufferDir(), fileName); 3396ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko try (DataOutputStream out = new DataOutputStream(new FileOutputStream(file))) { 3406ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko writeString(out, trackFormat.trackId); 3416ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko writeFormatString(out, trackFormat.format, MediaFormat.KEY_MIME); 3426ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko writeFormatInt(out, trackFormat.format, MediaFormat.KEY_MAX_INPUT_SIZE); 3436ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko writeFormatInt(out, trackFormat.format, MediaFormat.KEY_WIDTH); 3446ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko writeFormatInt(out, trackFormat.format, MediaFormat.KEY_HEIGHT); 3456ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko writeFormatInt(out, trackFormat.format, MediaFormat.KEY_CHANNEL_COUNT); 3466ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko writeFormatInt(out, trackFormat.format, MediaFormat.KEY_SAMPLE_RATE); 3476ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko writeFormatFloat(out, trackFormat.format, KEY_PIXEL_WIDTH_HEIGHT_RATIO); 3486ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko for (int j = 0; j < 3; ++j) { 3496ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko writeFormatByteBuffer(out, trackFormat.format, "csd-" + j); 3506ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko } 3516ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko writeFormatLong(out, trackFormat.format, MediaFormat.KEY_DURATION); 3526ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko writeFormatString(out, trackFormat.format, MediaFormat.KEY_LANGUAGE); 3536ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko } 3546ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko } 3556ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko } 3566ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko 3576ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko /** 3586ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko * Writes caption information to files. 3596ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko * 3606ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko * @param tracks a list of {@link AtscCaptionTrack} objects which store caption information. 3616ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko */ 3626ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko public void writeCaptionInfoFiles(List<AtscCaptionTrack> tracks) { 3636ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko if (tracks == null || tracks.isEmpty()) { 3646ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko return; 3656ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko } 3666ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko for (int i = 0; i < tracks.size(); i++) { 3676ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko AtscCaptionTrack track = tracks.get(i); 3686ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko String fileName = META_FILE_TYPE_CAPTION + 3696ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko ((i == 0) ? META_FILE_SUFFIX : (i + META_FILE_SUFFIX)); 3706ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko File file = new File(getBufferDir(), fileName); 3716ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko try (DataOutputStream out = new DataOutputStream(new FileOutputStream(file))) { 3726ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko out.write(MessageNano.toByteArray(track)); 3736ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko } catch (Exception e) { 3746ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko Log.e(TAG, "Fail to write caption info to files", e); 3751abddd9f6225298066094e20a6c29061b6af4590Nick Chalko } 3761abddd9f6225298066094e20a6c29061b6af4590Nick Chalko } 3771abddd9f6225298066094e20a6c29061b6af4590Nick Chalko } 3781abddd9f6225298066094e20a6c29061b6af4590Nick Chalko 3791abddd9f6225298066094e20a6c29061b6af4590Nick Chalko @Override 3806ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko public void writeIndexFile(String trackName, SortedMap<Long, Pair<SampleChunk, Integer>> index) 3811abddd9f6225298066094e20a6c29061b6af4590Nick Chalko throws IOException { 3826ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko File indexFile = new File(getBufferDir(), trackName + IDX_FILE_SUFFIX_V2); 3831abddd9f6225298066094e20a6c29061b6af4590Nick Chalko try (DataOutputStream out = new DataOutputStream(new FileOutputStream(indexFile))) { 3841abddd9f6225298066094e20a6c29061b6af4590Nick Chalko out.writeLong(index.size()); 3856ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko for (Map.Entry<Long, Pair<SampleChunk, Integer>> entry : index.entrySet()) { 3866ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko out.writeLong(entry.getKey()); 3876ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko out.writeLong(entry.getValue().first.getStartPositionUs()); 3886ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko out.writeInt(entry.getValue().second); 3891abddd9f6225298066094e20a6c29061b6af4590Nick Chalko } 3901abddd9f6225298066094e20a6c29061b6af4590Nick Chalko } 3911abddd9f6225298066094e20a6c29061b6af4590Nick Chalko } 3921abddd9f6225298066094e20a6c29061b6af4590Nick Chalko} 393