Сводка
Я извлекаю данные text / 3gpp-tt из файлов mp4.Как я могу получить «конечное» время синхронизированного текстового элемента (то есть, начиная с TimeOfItem + durationOfTheItem)?
Я знаю, что это возможно с FFmpeg (я действительно делал это раньше), но есть ли более простой способвокруг?
Фон
Я делаю андроид-активность, чтобы показать что-то вроде сценария фильма.Это почти сделано.
Единственная функция, которую я не реализовал, - это просто добавление дополнительной новой строки между двумя строками, интервал которых превышает определенное количество времени (например, одну секунду).
Интервал - это не "initialTimeOfTheCurrentItem - initialTimeOfThePreviousItem", а "initialTimeOfTheCurrentItem - ENDingTimeOfThePreviousItem".
Android MediaExtractor имеет метод для получения времени начала, но, похоже, у него нет метода для определения продолжительности или окончаниявремя.
Код
Пока у меня есть этот код.Мне не нравится переменная "pseudoDuration".
private void uriToTextView(Uri uri, TextView textView) {
FileDescriptor fileDescriptor = uriToFileDescriptor(uri);
if (fileDescriptor == null) {
textView.append("ERROR: cannot open the uri\n");
return;
}
MediaExtractor mediaExtractor = fileDescriptorToMediaExtractor(fileDescriptor);
if (mediaExtractor == null) {
textView.append("ERROR: cannot open media extractor\n");
return;
}
int timedTextTrack = mediaExtractorToTimedTextTrack(mediaExtractor);
if (timedTextTrack < 0) {
textView.append("No timed text found\n");
return;
}
mediaExtractor.selectTrack(timedTextTrack);
ByteBuffer inputBuffer = ByteBuffer.allocate(2048);
long lastTime = 0;
int readSize;
while ((readSize = mediaExtractor.readSampleData(inputBuffer, 0)) >= 0) {
long startTime = mediaExtractor.getSampleTime();
short textLength = inputBuffer.getShort();
if (textLength != readSize - 2) {
textView.append("ERROR: length mismatch\n");
}
// I suppose I can get the duration like
// "long duration = mediaExtractor.XXXXX"
//
long pseudoDuration = textLength * 70000;
byte[] oneLineByteArray = Arrays.copyOfRange(inputBuffer.array(), 2, readSize);
String oneLine = new String(oneLineByteArray, StandardCharsets.UTF_8);
if (oneLine.length() > 0) {
if (!oneLine.endsWith("\n"))
oneLine += "\n";
if (startTime - lastTime > 1000000)
textView.append("\n");
textView.append(oneLine);
lastTime = startTime + pseudoDuration;
}
mediaExtractor.advance();
}
mediaExtractor.release();
}
private FileDescriptor uriToFileDescriptor(Uri uri) {
ParcelFileDescriptor parcelFileDescriptor;
try {
parcelFileDescriptor = this.getContentResolver().openFileDescriptor(uri, "r");
} catch (java.io.IOException e) {
return null;
}
if (parcelFileDescriptor == null)
return null;
return parcelFileDescriptor.getFileDescriptor();
}
private MediaExtractor fileDescriptorToMediaExtractor(FileDescriptor fileDescriptor) {
MediaExtractor mediaExtractor = new MediaExtractor();
try {
mediaExtractor.setDataSource(fileDescriptor);
} catch (java.io.IOException e) {
return null;
}
return mediaExtractor;
}
private int mediaExtractorToTimedTextTrack(MediaExtractor mediaExtractor) {
int numTracks = mediaExtractor.getTrackCount();
for (int i = 0; i < numTracks; i++) {
MediaFormat mediaFormat = mediaExtractor.getTrackFormat(i);
String mime = mediaFormat.getString(MediaFormat.KEY_MIME);
if (mime != null && mime.equalsIgnoreCase("text/3gpp-tt"))
return i;
}
return -1;
}
Results
Я ожидаю получить продолжительность вместе с длиной текста и самим текстом.(См. https://tools.ietf.org/html/rfc4396#section-4.7, чтобы найти SDUR непосредственно перед TLEN и текстовой строкой.)
Но метод MediaExtractor # readSampleData заполняет данный буфер только TLEN и текстовой строкой.
И этокажется, что нет способа получить длительность через MediaExtractor.