mirror of
https://github.com/samsonjs/media.git
synced 2026-03-27 09:45:47 +00:00
parent
c960636d28
commit
da97e30e33
3 changed files with 61 additions and 30 deletions
|
|
@ -48,6 +48,7 @@ public final class Mp3Extractor implements Extractor {
|
|||
private static final int INFO_HEADER = Util.getIntegerCodeForString("Info");
|
||||
private static final int VBRI_HEADER = Util.getIntegerCodeForString("VBRI");
|
||||
|
||||
private final long forcedFirstSampleTimestampUs;
|
||||
private final BufferingInput inputBuffer;
|
||||
private final ParsableByteArray scratch;
|
||||
private final MpegAudioHeader synchronizedHeader;
|
||||
|
|
@ -63,11 +64,25 @@ public final class Mp3Extractor implements Extractor {
|
|||
private int samplesRead;
|
||||
private int sampleBytesRemaining;
|
||||
|
||||
/** Constructs a new {@link Mp3Extractor}. */
|
||||
/**
|
||||
* Constructs a new {@link Mp3Extractor}.
|
||||
*/
|
||||
public Mp3Extractor() {
|
||||
this(-1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new {@link Mp3Extractor}.
|
||||
*
|
||||
* @param forcedFirstSampleTimestampUs A timestamp to force for the first sample, or -1 if forcing
|
||||
* is not required.
|
||||
*/
|
||||
public Mp3Extractor(long forcedFirstSampleTimestampUs) {
|
||||
this.forcedFirstSampleTimestampUs = forcedFirstSampleTimestampUs;
|
||||
inputBuffer = new BufferingInput(MpegAudioHeader.MAX_FRAME_SIZE_BYTES * 3);
|
||||
scratch = new ParsableByteArray(4);
|
||||
synchronizedHeader = new MpegAudioHeader();
|
||||
basisTimeUs = -1;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -164,6 +179,10 @@ public final class Mp3Extractor implements Extractor {
|
|||
}
|
||||
if (basisTimeUs == -1) {
|
||||
basisTimeUs = seeker.getTimeUs(getPosition(extractorInput, inputBuffer));
|
||||
if (forcedFirstSampleTimestampUs != -1) {
|
||||
long embeddedFirstSampleTimestampUs = seeker.getTimeUs(0);
|
||||
basisTimeUs += forcedFirstSampleTimestampUs - embeddedFirstSampleTimestampUs;
|
||||
}
|
||||
}
|
||||
sampleBytesRemaining = synchronizedHeader.frameSize;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@ import com.google.android.exoplayer.chunk.ChunkOperationHolder;
|
|||
import com.google.android.exoplayer.chunk.DataChunk;
|
||||
import com.google.android.exoplayer.chunk.Format;
|
||||
import com.google.android.exoplayer.extractor.Extractor;
|
||||
import com.google.android.exoplayer.extractor.mp3.Mp3Extractor;
|
||||
import com.google.android.exoplayer.extractor.ts.AdtsExtractor;
|
||||
import com.google.android.exoplayer.extractor.ts.PtsTimestampAdjuster;
|
||||
import com.google.android.exoplayer.extractor.ts.TsExtractor;
|
||||
|
|
@ -114,6 +115,7 @@ public class HlsChunkSource {
|
|||
|
||||
private static final String TAG = "HlsChunkSource";
|
||||
private static final String AAC_FILE_EXTENSION = ".aac";
|
||||
private static final String MP3_FILE_EXTENSION = ".mp3";
|
||||
private static final float BANDWIDTH_FRACTION = 0.8f;
|
||||
|
||||
private final DataSource dataSource;
|
||||
|
|
@ -354,24 +356,28 @@ public class HlsChunkSource {
|
|||
|
||||
// Configure the extractor that will read the chunk.
|
||||
HlsExtractorWrapper extractorWrapper;
|
||||
|
||||
if (previousTsChunk == null || segment.discontinuity || liveDiscontinuity
|
||||
if (chunkUri.getLastPathSegment().endsWith(AAC_FILE_EXTENSION)) {
|
||||
Extractor extractor = new AdtsExtractor(startTimeUs);
|
||||
extractorWrapper = new HlsExtractorWrapper(trigger, format, startTimeUs, extractor,
|
||||
switchingVariantSpliced, adaptiveMaxWidth, adaptiveMaxHeight);
|
||||
} else if (chunkUri.getLastPathSegment().endsWith(MP3_FILE_EXTENSION)) {
|
||||
Extractor extractor = new Mp3Extractor(startTimeUs);
|
||||
extractorWrapper = new HlsExtractorWrapper(trigger, format, startTimeUs, extractor,
|
||||
switchingVariantSpliced, adaptiveMaxWidth, adaptiveMaxHeight);
|
||||
} else if (previousTsChunk == null || segment.discontinuity || liveDiscontinuity
|
||||
|| !format.equals(previousTsChunk.format)) {
|
||||
Extractor extractor;
|
||||
if (chunkUri.getLastPathSegment().endsWith(AAC_FILE_EXTENSION)) {
|
||||
extractor = new AdtsExtractor(startTimeUs);
|
||||
} else {
|
||||
if (previousTsChunk == null || segment.discontinuity || liveDiscontinuity
|
||||
|| ptsTimestampAdjuster == null) {
|
||||
// TODO: Use this for AAC as well, along with the ID3 PRIV priv tag values with owner
|
||||
// identifier com.apple.streaming.transportStreamTimestamp.
|
||||
ptsTimestampAdjuster = new PtsTimestampAdjuster(startTimeUs);
|
||||
}
|
||||
extractor = new TsExtractor(ptsTimestampAdjuster);
|
||||
// MPEG-2 TS segments, but we need a new extractor.
|
||||
if (previousTsChunk == null || segment.discontinuity || liveDiscontinuity
|
||||
|| ptsTimestampAdjuster == null) {
|
||||
// TODO: Use this for AAC as well, along with the ID3 PRIV priv tag values with owner
|
||||
// identifier com.apple.streaming.transportStreamTimestamp.
|
||||
ptsTimestampAdjuster = new PtsTimestampAdjuster(startTimeUs);
|
||||
}
|
||||
Extractor extractor = new TsExtractor(ptsTimestampAdjuster);
|
||||
extractorWrapper = new HlsExtractorWrapper(trigger, format, startTimeUs, extractor,
|
||||
switchingVariantSpliced, adaptiveMaxWidth, adaptiveMaxHeight);
|
||||
} else {
|
||||
// MPEG-2 TS segments, and we need to continue using the same extractor.
|
||||
extractorWrapper = previousTsChunk.extractorWrapper;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -131,24 +131,30 @@ public final class HlsSampleSource implements SampleSource, SampleSourceReader,
|
|||
return true;
|
||||
}
|
||||
if (!extractors.isEmpty()) {
|
||||
// We're not prepared, but we might have loaded what we need.
|
||||
HlsExtractorWrapper extractor = getCurrentExtractor();
|
||||
if (extractor.isPrepared()) {
|
||||
trackCount = extractor.getTrackCount();
|
||||
trackEnabledStates = new boolean[trackCount];
|
||||
pendingDiscontinuities = new boolean[trackCount];
|
||||
downstreamMediaFormats = new MediaFormat[trackCount];
|
||||
trackFormat = new MediaFormat[trackCount];
|
||||
long durationUs = chunkSource.getDurationUs();
|
||||
for (int i = 0; i < trackCount; i++) {
|
||||
MediaFormat format = extractor.getMediaFormat(i).copyWithDurationUs(durationUs);
|
||||
if (MimeTypes.isVideo(format.mimeType)) {
|
||||
format = format.copyAsAdaptive();
|
||||
while (true) {
|
||||
// We're not prepared, but we might have loaded what we need.
|
||||
HlsExtractorWrapper extractor = extractors.getFirst();
|
||||
if (extractor.isPrepared()) {
|
||||
trackCount = extractor.getTrackCount();
|
||||
trackEnabledStates = new boolean[trackCount];
|
||||
pendingDiscontinuities = new boolean[trackCount];
|
||||
downstreamMediaFormats = new MediaFormat[trackCount];
|
||||
trackFormat = new MediaFormat[trackCount];
|
||||
long durationUs = chunkSource.getDurationUs();
|
||||
for (int i = 0; i < trackCount; i++) {
|
||||
MediaFormat format = extractor.getMediaFormat(i).copyWithDurationUs(durationUs);
|
||||
if (MimeTypes.isVideo(format.mimeType)) {
|
||||
format = format.copyAsAdaptive();
|
||||
}
|
||||
trackFormat[i] = format;
|
||||
}
|
||||
trackFormat[i] = format;
|
||||
prepared = true;
|
||||
return true;
|
||||
} else if (extractors.size() > 1) {
|
||||
extractors.removeFirst().clear();
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
prepared = true;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
// We're not prepared and we haven't loaded what we need.
|
||||
|
|
|
|||
Loading…
Reference in a new issue