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