Add API to get the format from the file extension

This will allow to use the file extension in DefaultExtractorsFactory.

PiperOrigin-RevId: 314296640
This commit is contained in:
kimvde 2020-06-02 10:58:37 +01:00 committed by Oliver Woodman
parent a5067e6314
commit 1f80cf1558
3 changed files with 256 additions and 44 deletions

View File

@ -0,0 +1,172 @@
/*
* Copyright 2020 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.android.exoplayer2.util;
import androidx.annotation.IntDef;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
/** Filename related utility methods. */
public final class FilenameUtil {
/**
* File formats. One of {@link #FILE_FORMAT_UNKNOWN}, {@link #FILE_FORMAT_AC3}, {@link
* #FILE_FORMAT_AC4}, {@link #FILE_FORMAT_ADTS}, {@link #FILE_FORMAT_AMR}, {@link
* #FILE_FORMAT_FLAC}, {@link #FILE_FORMAT_FLV}, {@link #FILE_FORMAT_MATROSKA}, {@link
* #FILE_FORMAT_MP3}, {@link #FILE_FORMAT_MP4}, {@link #FILE_FORMAT_OGG}, {@link #FILE_FORMAT_PS},
* {@link #FILE_FORMAT_TS}, {@link #FILE_FORMAT_WAV} and {@link #FILE_FORMAT_WEBVTT}.
*/
@Documented
@Retention(RetentionPolicy.SOURCE)
@IntDef({
FILE_FORMAT_UNKNOWN,
FILE_FORMAT_AC3,
FILE_FORMAT_AC4,
FILE_FORMAT_ADTS,
FILE_FORMAT_AMR,
FILE_FORMAT_FLAC,
FILE_FORMAT_FLV,
FILE_FORMAT_MATROSKA,
FILE_FORMAT_MP3,
FILE_FORMAT_MP4,
FILE_FORMAT_OGG,
FILE_FORMAT_PS,
FILE_FORMAT_TS,
FILE_FORMAT_WAV,
FILE_FORMAT_WEBVTT
})
public @interface FileFormat {}
/** Unknown file format. */
public static final int FILE_FORMAT_UNKNOWN = -1;
/** File format for AC-3 and E-AC-3. */
public static final int FILE_FORMAT_AC3 = 0;
/** File format for AC-4. */
public static final int FILE_FORMAT_AC4 = 1;
/** File format for ADTS. */
public static final int FILE_FORMAT_ADTS = 2;
/** File format for AMR. */
public static final int FILE_FORMAT_AMR = 3;
/** File format for FLAC. */
public static final int FILE_FORMAT_FLAC = 4;
/** File format for FLV. */
public static final int FILE_FORMAT_FLV = 5;
/** File format for Matroska and WebM. */
public static final int FILE_FORMAT_MATROSKA = 6;
/** File format for MP3. */
public static final int FILE_FORMAT_MP3 = 7;
/** File format for MP4. */
public static final int FILE_FORMAT_MP4 = 8;
/** File format for Ogg. */
public static final int FILE_FORMAT_OGG = 9;
/** File format for MPEG-PS. */
public static final int FILE_FORMAT_PS = 10;
/** File format for MPEG-TS. */
public static final int FILE_FORMAT_TS = 11;
/** File format for WAV. */
public static final int FILE_FORMAT_WAV = 12;
/** File format for WebVTT. */
public static final int FILE_FORMAT_WEBVTT = 13;
private static final String FILE_EXTENSION_AC3 = ".ac3";
private static final String FILE_EXTENSION_EC3 = ".ec3";
private static final String FILE_EXTENSION_AC4 = ".ac4";
private static final String FILE_EXTENSION_ADTS = ".adts";
private static final String FILE_EXTENSION_AAC = ".aac";
private static final String FILE_EXTENSION_AMR = ".amr";
private static final String FILE_EXTENSION_FLAC = ".flac";
private static final String FILE_EXTENSION_FLV = ".flv";
private static final String FILE_EXTENSION_PREFIX_MK = ".mk";
private static final String FILE_EXTENSION_WEBM = ".webm";
private static final String FILE_EXTENSION_PREFIX_OG = ".og";
private static final String FILE_EXTENSION_OPUS = ".opus";
private static final String FILE_EXTENSION_MP3 = ".mp3";
private static final String FILE_EXTENSION_MP4 = ".mp4";
private static final String FILE_EXTENSION_PREFIX_M4 = ".m4";
private static final String FILE_EXTENSION_PREFIX_MP4 = ".mp4";
private static final String FILE_EXTENSION_PREFIX_CMF = ".cmf";
private static final String FILE_EXTENSION_PS = ".ps";
private static final String FILE_EXTENSION_MPEG = ".mpeg";
private static final String FILE_EXTENSION_MPG = ".mpg";
private static final String FILE_EXTENSION_M2P = ".m2p";
private static final String FILE_EXTENSION_TS = ".ts";
private static final String FILE_EXTENSION_PREFIX_TS = ".ts";
private static final String FILE_EXTENSION_WAV = ".wav";
private static final String FILE_EXTENSION_WAVE = ".wave";
private static final String FILE_EXTENSION_VTT = ".vtt";
private static final String FILE_EXTENSION_WEBVTT = ".webvtt";
private FilenameUtil() {}
/**
* Returns the {@link FileFormat} corresponding to the extension of the provided {@code filename}.
*/
@FileFormat
public static int getFormatFromExtension(String filename) {
if (filename.endsWith(FILE_EXTENSION_AC3) || filename.endsWith(FILE_EXTENSION_EC3)) {
return FILE_FORMAT_AC3;
} else if (filename.endsWith(FILE_EXTENSION_AC4)) {
return FILE_FORMAT_AC4;
} else if (filename.endsWith(FILE_EXTENSION_ADTS) || filename.endsWith(FILE_EXTENSION_AAC)) {
return FILE_FORMAT_ADTS;
} else if (filename.endsWith(FILE_EXTENSION_AMR)) {
return FILE_FORMAT_AMR;
} else if (filename.endsWith(FILE_EXTENSION_FLAC)) {
return FILE_FORMAT_FLAC;
} else if (filename.endsWith(FILE_EXTENSION_FLV)) {
return FILE_FORMAT_FLV;
} else if (filename.startsWith(
FILE_EXTENSION_PREFIX_MK,
/* toffset= */ filename.length() - (FILE_EXTENSION_PREFIX_MK.length() + 1))
|| filename.endsWith(FILE_EXTENSION_WEBM)) {
return FILE_FORMAT_MATROSKA;
} else if (filename.endsWith(FILE_EXTENSION_MP3)) {
return FILE_FORMAT_MP3;
} else if (filename.endsWith(FILE_EXTENSION_MP4)
|| filename.startsWith(
FILE_EXTENSION_PREFIX_M4,
/* toffset= */ filename.length() - (FILE_EXTENSION_PREFIX_M4.length() + 1))
|| filename.startsWith(
FILE_EXTENSION_PREFIX_MP4,
/* toffset= */ filename.length() - (FILE_EXTENSION_PREFIX_MP4.length() + 1))
|| filename.startsWith(
FILE_EXTENSION_PREFIX_CMF,
/* toffset= */ filename.length() - (FILE_EXTENSION_PREFIX_CMF.length() + 1))) {
return FILE_FORMAT_MP4;
} else if (filename.startsWith(
FILE_EXTENSION_PREFIX_OG,
/* toffset= */ filename.length() - (FILE_EXTENSION_PREFIX_OG.length() + 1))
|| filename.endsWith(FILE_EXTENSION_OPUS)) {
return FILE_FORMAT_OGG;
} else if (filename.endsWith(FILE_EXTENSION_PS)
|| filename.endsWith(FILE_EXTENSION_MPEG)
|| filename.endsWith(FILE_EXTENSION_MPG)
|| filename.endsWith(FILE_EXTENSION_M2P)) {
return FILE_FORMAT_PS;
} else if (filename.endsWith(FILE_EXTENSION_TS)
|| filename.startsWith(
FILE_EXTENSION_PREFIX_TS,
/* toffset= */ filename.length() - (FILE_EXTENSION_PREFIX_TS.length() + 1))) {
return FILE_FORMAT_TS;
} else if (filename.endsWith(FILE_EXTENSION_WAV) || filename.endsWith(FILE_EXTENSION_WAVE)) {
return FILE_FORMAT_WAV;
} else if (filename.endsWith(FILE_EXTENSION_VTT) || filename.endsWith(FILE_EXTENSION_WEBVTT)) {
return FILE_FORMAT_WEBVTT;
} else {
return FILE_FORMAT_UNKNOWN;
}
}
}

View File

@ -0,0 +1,46 @@
/*
* Copyright 2020 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.android.exoplayer2.util;
import static com.google.android.exoplayer2.util.FilenameUtil.FILE_FORMAT_MATROSKA;
import static com.google.android.exoplayer2.util.FilenameUtil.FILE_FORMAT_MP3;
import static com.google.android.exoplayer2.util.FilenameUtil.FILE_FORMAT_UNKNOWN;
import static com.google.android.exoplayer2.util.FilenameUtil.getFormatFromExtension;
import static com.google.common.truth.Truth.assertThat;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import org.junit.Test;
import org.junit.runner.RunWith;
/** Tests for {@link FilenameUtilTest}. */
@RunWith(AndroidJUnit4.class)
public class FilenameUtilTest {
@Test
public void getFormatFromExtension_withExtension_returnsExpectedFormat() {
assertThat(getFormatFromExtension("filename.mp3")).isEqualTo(FILE_FORMAT_MP3);
}
@Test
public void getFormatFromExtension_withExtensionPrefix_returnsExpectedFormat() {
assertThat(getFormatFromExtension("filename.mka")).isEqualTo(FILE_FORMAT_MATROSKA);
}
@Test
public void getFormatFromExtension_unknownExtension_returnsUnknownFormat() {
assertThat(getFormatFromExtension("filename.unknown")).isEqualTo(FILE_FORMAT_UNKNOWN);
}
}

View File

@ -15,6 +15,15 @@
*/ */
package com.google.android.exoplayer2.source.hls; package com.google.android.exoplayer2.source.hls;
import static com.google.android.exoplayer2.util.FilenameUtil.FILE_FORMAT_AC3;
import static com.google.android.exoplayer2.util.FilenameUtil.FILE_FORMAT_AC4;
import static com.google.android.exoplayer2.util.FilenameUtil.FILE_FORMAT_ADTS;
import static com.google.android.exoplayer2.util.FilenameUtil.FILE_FORMAT_MP3;
import static com.google.android.exoplayer2.util.FilenameUtil.FILE_FORMAT_MP4;
import static com.google.android.exoplayer2.util.FilenameUtil.FILE_FORMAT_TS;
import static com.google.android.exoplayer2.util.FilenameUtil.FILE_FORMAT_WEBVTT;
import static com.google.android.exoplayer2.util.FilenameUtil.getFormatFromExtension;
import android.net.Uri; import android.net.Uri;
import android.text.TextUtils; import android.text.TextUtils;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
@ -30,6 +39,7 @@ import com.google.android.exoplayer2.extractor.ts.DefaultTsPayloadReaderFactory;
import com.google.android.exoplayer2.extractor.ts.TsExtractor; import com.google.android.exoplayer2.extractor.ts.TsExtractor;
import com.google.android.exoplayer2.metadata.Metadata; import com.google.android.exoplayer2.metadata.Metadata;
import com.google.android.exoplayer2.util.Assertions; import com.google.android.exoplayer2.util.Assertions;
import com.google.android.exoplayer2.util.FilenameUtil;
import com.google.android.exoplayer2.util.MimeTypes; import com.google.android.exoplayer2.util.MimeTypes;
import com.google.android.exoplayer2.util.TimestampAdjuster; import com.google.android.exoplayer2.util.TimestampAdjuster;
import java.io.EOFException; import java.io.EOFException;
@ -43,20 +53,6 @@ import java.util.Map;
*/ */
public final class DefaultHlsExtractorFactory implements HlsExtractorFactory { public final class DefaultHlsExtractorFactory implements HlsExtractorFactory {
public static final String AAC_FILE_EXTENSION = ".aac";
public static final String AC3_FILE_EXTENSION = ".ac3";
public static final String EC3_FILE_EXTENSION = ".ec3";
public static final String AC4_FILE_EXTENSION = ".ac4";
public static final String MP3_FILE_EXTENSION = ".mp3";
public static final String MP4_FILE_EXTENSION = ".mp4";
public static final String M4_FILE_EXTENSION_PREFIX = ".m4";
public static final String MP4_FILE_EXTENSION_PREFIX = ".mp4";
public static final String CMF_FILE_EXTENSION_PREFIX = ".cmf";
public static final String TS_FILE_EXTENSION = ".ts";
public static final String TS_FILE_EXTENSION_PREFIX = ".ts";
public static final String VTT_FILE_EXTENSION = ".vtt";
public static final String WEBVTT_FILE_EXTENSION = ".webvtt";
@DefaultTsPayloadReaderFactory.Flags private final int payloadReaderFactoryFlags; @DefaultTsPayloadReaderFactory.Flags private final int payloadReaderFactoryFlags;
private final boolean exposeCea608WhenMissingDeclarations; private final boolean exposeCea608WhenMissingDeclarations;
@ -196,39 +192,37 @@ public final class DefaultHlsExtractorFactory implements HlsExtractorFactory {
Format format, Format format,
@Nullable List<Format> muxedCaptionFormats, @Nullable List<Format> muxedCaptionFormats,
TimestampAdjuster timestampAdjuster) { TimestampAdjuster timestampAdjuster) {
String lastPathSegment = uri.getLastPathSegment(); if (MimeTypes.TEXT_VTT.equals(format.sampleMimeType)) {
if (lastPathSegment == null) {
lastPathSegment = "";
}
if (MimeTypes.TEXT_VTT.equals(format.sampleMimeType)
|| lastPathSegment.endsWith(WEBVTT_FILE_EXTENSION)
|| lastPathSegment.endsWith(VTT_FILE_EXTENSION)) {
return new WebvttExtractor(format.language, timestampAdjuster); return new WebvttExtractor(format.language, timestampAdjuster);
} else if (lastPathSegment.endsWith(AAC_FILE_EXTENSION)) { }
return new AdtsExtractor(); String filename = uri.getLastPathSegment();
} else if (lastPathSegment.endsWith(AC3_FILE_EXTENSION) if (filename == null) {
|| lastPathSegment.endsWith(EC3_FILE_EXTENSION)) {
return new Ac3Extractor();
} else if (lastPathSegment.endsWith(AC4_FILE_EXTENSION)) {
return new Ac4Extractor();
} else if (lastPathSegment.endsWith(MP3_FILE_EXTENSION)) {
return new Mp3Extractor(/* flags= */ 0, /* forcedFirstSampleTimestampUs= */ 0);
} else if (lastPathSegment.endsWith(MP4_FILE_EXTENSION)
|| lastPathSegment.startsWith(M4_FILE_EXTENSION_PREFIX, lastPathSegment.length() - 4)
|| lastPathSegment.startsWith(MP4_FILE_EXTENSION_PREFIX, lastPathSegment.length() - 5)
|| lastPathSegment.startsWith(CMF_FILE_EXTENSION_PREFIX, lastPathSegment.length() - 5)) {
return createFragmentedMp4Extractor(timestampAdjuster, format, muxedCaptionFormats);
} else if (lastPathSegment.endsWith(TS_FILE_EXTENSION)
|| lastPathSegment.startsWith(TS_FILE_EXTENSION_PREFIX, lastPathSegment.length() - 4)) {
return createTsExtractor(
payloadReaderFactoryFlags,
exposeCea608WhenMissingDeclarations,
format,
muxedCaptionFormats,
timestampAdjuster);
} else {
return null; return null;
} }
@FilenameUtil.FileFormat int fileFormat = getFormatFromExtension(filename);
switch (fileFormat) {
case FILE_FORMAT_WEBVTT:
return new WebvttExtractor(format.language, timestampAdjuster);
case FILE_FORMAT_ADTS:
return new AdtsExtractor();
case FILE_FORMAT_AC3:
return new Ac3Extractor();
case FILE_FORMAT_AC4:
return new Ac4Extractor();
case FILE_FORMAT_MP3:
return new Mp3Extractor(/* flags= */ 0, /* forcedFirstSampleTimestampUs= */ 0);
case FILE_FORMAT_MP4:
return createFragmentedMp4Extractor(timestampAdjuster, format, muxedCaptionFormats);
case FILE_FORMAT_TS:
return createTsExtractor(
payloadReaderFactoryFlags,
exposeCea608WhenMissingDeclarations,
format,
muxedCaptionFormats,
timestampAdjuster);
default:
return null;
}
} }
private static TsExtractor createTsExtractor( private static TsExtractor createTsExtractor(