Add pts adjustment in SpliceInfoDecoder
This allows the user to interpret PTSs in the playback timebase. ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=145280921
This commit is contained in:
parent
5debf5a14a
commit
18d7cdf39f
@ -0,0 +1,173 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2016 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.metadata.scte35;
|
||||||
|
|
||||||
|
import com.google.android.exoplayer2.C;
|
||||||
|
import com.google.android.exoplayer2.extractor.TimestampAdjuster;
|
||||||
|
import com.google.android.exoplayer2.metadata.Metadata;
|
||||||
|
import com.google.android.exoplayer2.metadata.MetadataDecoderException;
|
||||||
|
import com.google.android.exoplayer2.metadata.MetadataInputBuffer;
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
import java.util.List;
|
||||||
|
import junit.framework.TestCase;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test for {@link SpliceInfoDecoder}.
|
||||||
|
*/
|
||||||
|
public final class SpliceInfoDecoderTest extends TestCase {
|
||||||
|
|
||||||
|
private SpliceInfoDecoder decoder;
|
||||||
|
private MetadataInputBuffer inputBuffer;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setUp() {
|
||||||
|
decoder = new SpliceInfoDecoder();
|
||||||
|
inputBuffer = new MetadataInputBuffer();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testWrappedAroundTimeSignalCommand() throws MetadataDecoderException {
|
||||||
|
byte[] rawTimeSignalSection = new byte[] {
|
||||||
|
0, // table_id.
|
||||||
|
(byte) 0x80, // section_syntax_indicator, private_indicator, reserved, section_length(4).
|
||||||
|
0x14, // section_length(8).
|
||||||
|
0x00, // protocol_version.
|
||||||
|
0x00, // encrypted_packet, encryption_algorithm, pts_adjustment(1).
|
||||||
|
0x00, 0x00, 0x00, 0x00, // pts_adjustment(32).
|
||||||
|
0x00, // cw_index.
|
||||||
|
0x00, // tier(8).
|
||||||
|
0x00, // tier(4), splice_command_length(4).
|
||||||
|
0x05, // splice_command_length(8).
|
||||||
|
0x06, // splice_command_type = time_signal.
|
||||||
|
// Start of splice_time().
|
||||||
|
(byte) 0x80, // time_specified_flag, reserved, pts_time(1).
|
||||||
|
0x52, 0x03, 0x02, (byte) 0x8f, // pts_time(32). PTS for a second after playback position.
|
||||||
|
0x00, 0x00, 0x00, 0x00}; // CRC_32 (ignored, check happens at extraction).
|
||||||
|
|
||||||
|
// The playback position is 57:15:58.43 approximately.
|
||||||
|
// With this offset, the playback position pts before wrapping is 0x451ebf851.
|
||||||
|
Metadata metadata = feedInputBuffer(rawTimeSignalSection, 0x3000000000L, -0x50000L);
|
||||||
|
assertEquals(1, metadata.length());
|
||||||
|
assertEquals(removePtsConversionPrecisionError(0x3001000000L, inputBuffer.subsampleOffsetUs),
|
||||||
|
((TimeSignalCommand) metadata.get(0)).playbackPositionUs);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void test2SpliceInsertCommands() throws MetadataDecoderException {
|
||||||
|
byte[] rawSpliceInsertCommand1 = new byte[] {
|
||||||
|
0, // table_id.
|
||||||
|
(byte) 0x80, // section_syntax_indicator, private_indicator, reserved, section_length(4).
|
||||||
|
0x19, // section_length(8).
|
||||||
|
0x00, // protocol_version.
|
||||||
|
0x00, // encrypted_packet, encryption_algorithm, pts_adjustment(1).
|
||||||
|
0x00, 0x00, 0x00, 0x00, // pts_adjustment(32).
|
||||||
|
0x00, // cw_index.
|
||||||
|
0x00, // tier(8).
|
||||||
|
0x00, // tier(4), splice_command_length(4).
|
||||||
|
0x0e, // splice_command_length(8).
|
||||||
|
0x05, // splice_command_type = splice_insert.
|
||||||
|
// Start of splice_insert().
|
||||||
|
0x00, 0x00, 0x00, 0x42, // splice_event_id.
|
||||||
|
0x00, // splice_event_cancel_indicator, reserved.
|
||||||
|
0x40, // out_of_network_indicator, program_splice_flag, duration_flag,
|
||||||
|
// splice_immediate_flag, reserved.
|
||||||
|
// start of splice_time().
|
||||||
|
(byte) 0x80, // time_specified_flag, reserved, pts_time(1).
|
||||||
|
0x00, 0x00, 0x00, 0x00, // PTS for playback position 3s.
|
||||||
|
0x00, 0x10, // unique_program_id.
|
||||||
|
0x01, // avail_num.
|
||||||
|
0x02, // avails_expected.
|
||||||
|
0x00, 0x00, 0x00, 0x00}; // CRC_32 (ignored, check happens at extraction).
|
||||||
|
|
||||||
|
Metadata metadata = feedInputBuffer(rawSpliceInsertCommand1, 2000000, 3000000);
|
||||||
|
assertEquals(1, metadata.length());
|
||||||
|
SpliceInsertCommand command = (SpliceInsertCommand) metadata.get(0);
|
||||||
|
assertEquals(66, command.spliceEventId);
|
||||||
|
assertFalse(command.spliceEventCancelIndicator);
|
||||||
|
assertFalse(command.outOfNetworkIndicator);
|
||||||
|
assertTrue(command.programSpliceFlag);
|
||||||
|
assertFalse(command.spliceImmediateFlag);
|
||||||
|
assertEquals(3000000, command.programSplicePlaybackPositionUs);
|
||||||
|
assertEquals(C.TIME_UNSET, command.breakDuration);
|
||||||
|
assertEquals(16, command.uniqueProgramId);
|
||||||
|
assertEquals(1, command.availNum);
|
||||||
|
assertEquals(2, command.availsExpected);
|
||||||
|
|
||||||
|
byte[] rawSpliceInsertCommand2 = new byte[] {
|
||||||
|
0, // table_id.
|
||||||
|
(byte) 0x80, // section_syntax_indicator, private_indicator, reserved, section_length(4).
|
||||||
|
0x22, // section_length(8).
|
||||||
|
0x00, // protocol_version.
|
||||||
|
0x00, // encrypted_packet, encryption_algorithm, pts_adjustment(1).
|
||||||
|
0x00, 0x00, 0x00, 0x00, // pts_adjustment(32).
|
||||||
|
0x00, // cw_index.
|
||||||
|
0x00, // tier(8).
|
||||||
|
0x00, // tier(4), splice_command_length(4).
|
||||||
|
0x13, // splice_command_length(8).
|
||||||
|
0x05, // splice_command_type = splice_insert.
|
||||||
|
// Start of splice_insert().
|
||||||
|
(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, // splice_event_id.
|
||||||
|
0x00, // splice_event_cancel_indicator, reserved.
|
||||||
|
0x00, // out_of_network_indicator, program_splice_flag, duration_flag,
|
||||||
|
// splice_immediate_flag, reserved.
|
||||||
|
0x02, // component_count.
|
||||||
|
0x10, // component_tag.
|
||||||
|
// start of splice_time().
|
||||||
|
(byte) 0x81, // time_specified_flag, reserved, pts_time(1).
|
||||||
|
(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, // PTS for playback position 10s.
|
||||||
|
// start of splice_time().
|
||||||
|
0x11, // component_tag.
|
||||||
|
0x00, // time_specified_flag, reserved.
|
||||||
|
0x00, 0x20, // unique_program_id.
|
||||||
|
0x01, // avail_num.
|
||||||
|
0x02, // avails_expected.
|
||||||
|
0x00, 0x00, 0x00, 0x00}; // CRC_32 (ignored, check happens at extraction).
|
||||||
|
|
||||||
|
// By changing the subsample offset we force adjuster reconstruction.
|
||||||
|
long subsampleOffset = 1000011;
|
||||||
|
metadata = feedInputBuffer(rawSpliceInsertCommand2, 1000000, subsampleOffset);
|
||||||
|
assertEquals(1, metadata.length());
|
||||||
|
command = (SpliceInsertCommand) metadata.get(0);
|
||||||
|
assertEquals(0xffffffffL, command.spliceEventId);
|
||||||
|
assertFalse(command.spliceEventCancelIndicator);
|
||||||
|
assertFalse(command.outOfNetworkIndicator);
|
||||||
|
assertFalse(command.programSpliceFlag);
|
||||||
|
assertFalse(command.spliceImmediateFlag);
|
||||||
|
assertEquals(C.TIME_UNSET, command.programSplicePlaybackPositionUs);
|
||||||
|
assertEquals(C.TIME_UNSET, command.breakDuration);
|
||||||
|
List<SpliceInsertCommand.ComponentSplice> componentSplices = command.componentSpliceList;
|
||||||
|
assertEquals(2, componentSplices.size());
|
||||||
|
assertEquals(16, componentSplices.get(0).componentTag);
|
||||||
|
assertEquals(1000000, componentSplices.get(0).componentSplicePlaybackPositionUs);
|
||||||
|
assertEquals(17, componentSplices.get(1).componentTag);
|
||||||
|
assertEquals(C.TIME_UNSET, componentSplices.get(1).componentSplicePts);
|
||||||
|
assertEquals(32, command.uniqueProgramId);
|
||||||
|
assertEquals(1, command.availNum);
|
||||||
|
assertEquals(2, command.availsExpected);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Metadata feedInputBuffer(byte[] data, long timeUs, long subsampleOffset)
|
||||||
|
throws MetadataDecoderException{
|
||||||
|
inputBuffer.clear();
|
||||||
|
inputBuffer.data = ByteBuffer.allocate(data.length).put(data);
|
||||||
|
inputBuffer.timeUs = timeUs;
|
||||||
|
inputBuffer.subsampleOffsetUs = subsampleOffset;
|
||||||
|
return decoder.decode(inputBuffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static long removePtsConversionPrecisionError(long timeUs, long offsetUs) {
|
||||||
|
return TimestampAdjuster.ptsToUs(TimestampAdjuster.usToPts(timeUs - offsetUs)) + offsetUs;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -93,6 +93,9 @@ public final class TimestampAdjuster {
|
|||||||
* @return The adjusted timestamp in microseconds.
|
* @return The adjusted timestamp in microseconds.
|
||||||
*/
|
*/
|
||||||
public long adjustTsTimestamp(long pts) {
|
public long adjustTsTimestamp(long pts) {
|
||||||
|
if (pts == C.TIME_UNSET) {
|
||||||
|
return C.TIME_UNSET;
|
||||||
|
}
|
||||||
if (lastSampleTimestamp != C.TIME_UNSET) {
|
if (lastSampleTimestamp != C.TIME_UNSET) {
|
||||||
// The wrap count for the current PTS may be closestWrapCount or (closestWrapCount - 1),
|
// The wrap count for the current PTS may be closestWrapCount or (closestWrapCount - 1),
|
||||||
// and we need to snap to the one closest to lastSampleTimestamp.
|
// and we need to snap to the one closest to lastSampleTimestamp.
|
||||||
@ -113,6 +116,9 @@ public final class TimestampAdjuster {
|
|||||||
* @return The adjusted timestamp in microseconds.
|
* @return The adjusted timestamp in microseconds.
|
||||||
*/
|
*/
|
||||||
public long adjustSampleTimestamp(long timeUs) {
|
public long adjustSampleTimestamp(long timeUs) {
|
||||||
|
if (timeUs == C.TIME_UNSET) {
|
||||||
|
return C.TIME_UNSET;
|
||||||
|
}
|
||||||
// Record the adjusted PTS to adjust for wraparound next time.
|
// Record the adjusted PTS to adjust for wraparound next time.
|
||||||
if (lastSampleTimestamp != C.TIME_UNSET) {
|
if (lastSampleTimestamp != C.TIME_UNSET) {
|
||||||
lastSampleTimestamp = timeUs;
|
lastSampleTimestamp = timeUs;
|
||||||
|
@ -26,7 +26,6 @@ public final class PrivateCommand extends SpliceCommand {
|
|||||||
|
|
||||||
public final long ptsAdjustment;
|
public final long ptsAdjustment;
|
||||||
public final long identifier;
|
public final long identifier;
|
||||||
|
|
||||||
public final byte[] commandBytes;
|
public final byte[] commandBytes;
|
||||||
|
|
||||||
private PrivateCommand(long identifier, byte[] commandBytes, long ptsAdjustment) {
|
private PrivateCommand(long identifier, byte[] commandBytes, long ptsAdjustment) {
|
||||||
|
@ -15,6 +15,7 @@
|
|||||||
*/
|
*/
|
||||||
package com.google.android.exoplayer2.metadata.scte35;
|
package com.google.android.exoplayer2.metadata.scte35;
|
||||||
|
|
||||||
|
import com.google.android.exoplayer2.extractor.TimestampAdjuster;
|
||||||
import com.google.android.exoplayer2.metadata.Metadata;
|
import com.google.android.exoplayer2.metadata.Metadata;
|
||||||
import com.google.android.exoplayer2.metadata.MetadataDecoder;
|
import com.google.android.exoplayer2.metadata.MetadataDecoder;
|
||||||
import com.google.android.exoplayer2.metadata.MetadataDecoderException;
|
import com.google.android.exoplayer2.metadata.MetadataDecoderException;
|
||||||
@ -37,6 +38,8 @@ public final class SpliceInfoDecoder implements MetadataDecoder {
|
|||||||
private final ParsableByteArray sectionData;
|
private final ParsableByteArray sectionData;
|
||||||
private final ParsableBitArray sectionHeader;
|
private final ParsableBitArray sectionHeader;
|
||||||
|
|
||||||
|
private TimestampAdjuster timestampAdjuster;
|
||||||
|
|
||||||
public SpliceInfoDecoder() {
|
public SpliceInfoDecoder() {
|
||||||
sectionData = new ParsableByteArray();
|
sectionData = new ParsableByteArray();
|
||||||
sectionHeader = new ParsableBitArray();
|
sectionHeader = new ParsableBitArray();
|
||||||
@ -44,6 +47,13 @@ public final class SpliceInfoDecoder implements MetadataDecoder {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Metadata decode(MetadataInputBuffer inputBuffer) throws MetadataDecoderException {
|
public Metadata decode(MetadataInputBuffer inputBuffer) throws MetadataDecoderException {
|
||||||
|
// Internal timestamps adjustment.
|
||||||
|
if (timestampAdjuster == null
|
||||||
|
|| inputBuffer.subsampleOffsetUs != timestampAdjuster.getTimestampOffsetUs()) {
|
||||||
|
timestampAdjuster = new TimestampAdjuster(inputBuffer.timeUs);
|
||||||
|
timestampAdjuster.adjustSampleTimestamp(inputBuffer.timeUs - inputBuffer.subsampleOffsetUs);
|
||||||
|
}
|
||||||
|
|
||||||
ByteBuffer buffer = inputBuffer.data;
|
ByteBuffer buffer = inputBuffer.data;
|
||||||
byte[] data = buffer.array();
|
byte[] data = buffer.array();
|
||||||
int size = buffer.limit();
|
int size = buffer.limit();
|
||||||
@ -69,10 +79,11 @@ public final class SpliceInfoDecoder implements MetadataDecoder {
|
|||||||
command = SpliceScheduleCommand.parseFromSection(sectionData);
|
command = SpliceScheduleCommand.parseFromSection(sectionData);
|
||||||
break;
|
break;
|
||||||
case TYPE_SPLICE_INSERT:
|
case TYPE_SPLICE_INSERT:
|
||||||
command = SpliceInsertCommand.parseFromSection(sectionData, ptsAdjustment);
|
command = SpliceInsertCommand.parseFromSection(sectionData, ptsAdjustment,
|
||||||
|
timestampAdjuster);
|
||||||
break;
|
break;
|
||||||
case TYPE_TIME_SIGNAL:
|
case TYPE_TIME_SIGNAL:
|
||||||
command = TimeSignalCommand.parseFromSection(sectionData, ptsAdjustment);
|
command = TimeSignalCommand.parseFromSection(sectionData, ptsAdjustment, timestampAdjuster);
|
||||||
break;
|
break;
|
||||||
case TYPE_PRIVATE_COMMAND:
|
case TYPE_PRIVATE_COMMAND:
|
||||||
command = PrivateCommand.parseFromSection(sectionData, spliceCommandLength, ptsAdjustment);
|
command = PrivateCommand.parseFromSection(sectionData, spliceCommandLength, ptsAdjustment);
|
||||||
|
@ -18,6 +18,7 @@ package com.google.android.exoplayer2.metadata.scte35;
|
|||||||
import android.os.Parcel;
|
import android.os.Parcel;
|
||||||
import android.os.Parcelable;
|
import android.os.Parcelable;
|
||||||
import com.google.android.exoplayer2.C;
|
import com.google.android.exoplayer2.C;
|
||||||
|
import com.google.android.exoplayer2.extractor.TimestampAdjuster;
|
||||||
import com.google.android.exoplayer2.util.ParsableByteArray;
|
import com.google.android.exoplayer2.util.ParsableByteArray;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
@ -34,6 +35,7 @@ public final class SpliceInsertCommand extends SpliceCommand {
|
|||||||
public final boolean programSpliceFlag;
|
public final boolean programSpliceFlag;
|
||||||
public final boolean spliceImmediateFlag;
|
public final boolean spliceImmediateFlag;
|
||||||
public final long programSplicePts;
|
public final long programSplicePts;
|
||||||
|
public final long programSplicePlaybackPositionUs;
|
||||||
public final List<ComponentSplice> componentSpliceList;
|
public final List<ComponentSplice> componentSpliceList;
|
||||||
public final boolean autoReturn;
|
public final boolean autoReturn;
|
||||||
public final long breakDuration;
|
public final long breakDuration;
|
||||||
@ -43,14 +45,16 @@ public final class SpliceInsertCommand extends SpliceCommand {
|
|||||||
|
|
||||||
private SpliceInsertCommand(long spliceEventId, boolean spliceEventCancelIndicator,
|
private SpliceInsertCommand(long spliceEventId, boolean spliceEventCancelIndicator,
|
||||||
boolean outOfNetworkIndicator, boolean programSpliceFlag, boolean spliceImmediateFlag,
|
boolean outOfNetworkIndicator, boolean programSpliceFlag, boolean spliceImmediateFlag,
|
||||||
long programSplicePts, List<ComponentSplice> componentSpliceList, boolean autoReturn,
|
long programSplicePts, long programSplicePlaybackPositionUs,
|
||||||
long breakDuration, int uniqueProgramId, int availNum, int availsExpected) {
|
List<ComponentSplice> componentSpliceList, boolean autoReturn, long breakDuration,
|
||||||
|
int uniqueProgramId, int availNum, int availsExpected) {
|
||||||
this.spliceEventId = spliceEventId;
|
this.spliceEventId = spliceEventId;
|
||||||
this.spliceEventCancelIndicator = spliceEventCancelIndicator;
|
this.spliceEventCancelIndicator = spliceEventCancelIndicator;
|
||||||
this.outOfNetworkIndicator = outOfNetworkIndicator;
|
this.outOfNetworkIndicator = outOfNetworkIndicator;
|
||||||
this.programSpliceFlag = programSpliceFlag;
|
this.programSpliceFlag = programSpliceFlag;
|
||||||
this.spliceImmediateFlag = spliceImmediateFlag;
|
this.spliceImmediateFlag = spliceImmediateFlag;
|
||||||
this.programSplicePts = programSplicePts;
|
this.programSplicePts = programSplicePts;
|
||||||
|
this.programSplicePlaybackPositionUs = programSplicePlaybackPositionUs;
|
||||||
this.componentSpliceList = Collections.unmodifiableList(componentSpliceList);
|
this.componentSpliceList = Collections.unmodifiableList(componentSpliceList);
|
||||||
this.autoReturn = autoReturn;
|
this.autoReturn = autoReturn;
|
||||||
this.breakDuration = breakDuration;
|
this.breakDuration = breakDuration;
|
||||||
@ -66,6 +70,7 @@ public final class SpliceInsertCommand extends SpliceCommand {
|
|||||||
programSpliceFlag = in.readByte() == 1;
|
programSpliceFlag = in.readByte() == 1;
|
||||||
spliceImmediateFlag = in.readByte() == 1;
|
spliceImmediateFlag = in.readByte() == 1;
|
||||||
programSplicePts = in.readLong();
|
programSplicePts = in.readLong();
|
||||||
|
programSplicePlaybackPositionUs = in.readLong();
|
||||||
int componentSpliceListSize = in.readInt();
|
int componentSpliceListSize = in.readInt();
|
||||||
List<ComponentSplice> componentSpliceList = new ArrayList<>(componentSpliceListSize);
|
List<ComponentSplice> componentSpliceList = new ArrayList<>(componentSpliceListSize);
|
||||||
for (int i = 0; i < componentSpliceListSize; i++) {
|
for (int i = 0; i < componentSpliceListSize; i++) {
|
||||||
@ -80,7 +85,7 @@ public final class SpliceInsertCommand extends SpliceCommand {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* package */ static SpliceInsertCommand parseFromSection(ParsableByteArray sectionData,
|
/* package */ static SpliceInsertCommand parseFromSection(ParsableByteArray sectionData,
|
||||||
long ptsAdjustment) {
|
long ptsAdjustment, TimestampAdjuster timestampAdjuster) {
|
||||||
long spliceEventId = sectionData.readUnsignedInt();
|
long spliceEventId = sectionData.readUnsignedInt();
|
||||||
// splice_event_cancel_indicator(1), reserved(7).
|
// splice_event_cancel_indicator(1), reserved(7).
|
||||||
boolean spliceEventCancelIndicator = (sectionData.readUnsignedByte() & 0x80) != 0;
|
boolean spliceEventCancelIndicator = (sectionData.readUnsignedByte() & 0x80) != 0;
|
||||||
@ -88,7 +93,7 @@ public final class SpliceInsertCommand extends SpliceCommand {
|
|||||||
boolean programSpliceFlag = false;
|
boolean programSpliceFlag = false;
|
||||||
boolean spliceImmediateFlag = false;
|
boolean spliceImmediateFlag = false;
|
||||||
long programSplicePts = C.TIME_UNSET;
|
long programSplicePts = C.TIME_UNSET;
|
||||||
ArrayList<ComponentSplice> componentSplices = new ArrayList<>();
|
List<ComponentSplice> componentSplices = Collections.emptyList();
|
||||||
int uniqueProgramId = 0;
|
int uniqueProgramId = 0;
|
||||||
int availNum = 0;
|
int availNum = 0;
|
||||||
int availsExpected = 0;
|
int availsExpected = 0;
|
||||||
@ -112,7 +117,8 @@ public final class SpliceInsertCommand extends SpliceCommand {
|
|||||||
if (!spliceImmediateFlag) {
|
if (!spliceImmediateFlag) {
|
||||||
componentSplicePts = TimeSignalCommand.parseSpliceTime(sectionData, ptsAdjustment);
|
componentSplicePts = TimeSignalCommand.parseSpliceTime(sectionData, ptsAdjustment);
|
||||||
}
|
}
|
||||||
componentSplices.add(new ComponentSplice(componentTag, componentSplicePts));
|
componentSplices.add(new ComponentSplice(componentTag, componentSplicePts,
|
||||||
|
timestampAdjuster.adjustTsTimestamp(componentSplicePts)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (durationFlag) {
|
if (durationFlag) {
|
||||||
@ -125,7 +131,8 @@ public final class SpliceInsertCommand extends SpliceCommand {
|
|||||||
availsExpected = sectionData.readUnsignedByte();
|
availsExpected = sectionData.readUnsignedByte();
|
||||||
}
|
}
|
||||||
return new SpliceInsertCommand(spliceEventId, spliceEventCancelIndicator, outOfNetworkIndicator,
|
return new SpliceInsertCommand(spliceEventId, spliceEventCancelIndicator, outOfNetworkIndicator,
|
||||||
programSpliceFlag, spliceImmediateFlag, programSplicePts, componentSplices, autoReturn,
|
programSpliceFlag, spliceImmediateFlag, programSplicePts,
|
||||||
|
timestampAdjuster.adjustTsTimestamp(programSplicePts), componentSplices, autoReturn,
|
||||||
duration, uniqueProgramId, availNum, availsExpected);
|
duration, uniqueProgramId, availNum, availsExpected);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -136,19 +143,23 @@ public final class SpliceInsertCommand extends SpliceCommand {
|
|||||||
|
|
||||||
public final int componentTag;
|
public final int componentTag;
|
||||||
public final long componentSplicePts;
|
public final long componentSplicePts;
|
||||||
|
public final long componentSplicePlaybackPositionUs;
|
||||||
|
|
||||||
private ComponentSplice(int componentTag, long componentSplicePts) {
|
private ComponentSplice(int componentTag, long componentSplicePts,
|
||||||
|
long componentSplicePlaybackPositionUs) {
|
||||||
this.componentTag = componentTag;
|
this.componentTag = componentTag;
|
||||||
this.componentSplicePts = componentSplicePts;
|
this.componentSplicePts = componentSplicePts;
|
||||||
|
this.componentSplicePlaybackPositionUs = componentSplicePlaybackPositionUs;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void writeToParcel(Parcel dest) {
|
public void writeToParcel(Parcel dest) {
|
||||||
dest.writeInt(componentTag);
|
dest.writeInt(componentTag);
|
||||||
dest.writeLong(componentSplicePts);
|
dest.writeLong(componentSplicePts);
|
||||||
|
dest.writeLong(componentSplicePlaybackPositionUs);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static ComponentSplice createFromParcel(Parcel in) {
|
public static ComponentSplice createFromParcel(Parcel in) {
|
||||||
return new ComponentSplice(in.readInt(), in.readLong());
|
return new ComponentSplice(in.readInt(), in.readLong(), in.readLong());
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -163,6 +174,7 @@ public final class SpliceInsertCommand extends SpliceCommand {
|
|||||||
dest.writeByte((byte) (programSpliceFlag ? 1 : 0));
|
dest.writeByte((byte) (programSpliceFlag ? 1 : 0));
|
||||||
dest.writeByte((byte) (spliceImmediateFlag ? 1 : 0));
|
dest.writeByte((byte) (spliceImmediateFlag ? 1 : 0));
|
||||||
dest.writeLong(programSplicePts);
|
dest.writeLong(programSplicePts);
|
||||||
|
dest.writeLong(programSplicePlaybackPositionUs);
|
||||||
int componentSpliceListSize = componentSpliceList.size();
|
int componentSpliceListSize = componentSpliceList.size();
|
||||||
dest.writeInt(componentSpliceListSize);
|
dest.writeInt(componentSpliceListSize);
|
||||||
for (int i = 0; i < componentSpliceListSize; i++) {
|
for (int i = 0; i < componentSpliceListSize; i++) {
|
||||||
|
@ -17,6 +17,7 @@ package com.google.android.exoplayer2.metadata.scte35;
|
|||||||
|
|
||||||
import android.os.Parcel;
|
import android.os.Parcel;
|
||||||
import com.google.android.exoplayer2.C;
|
import com.google.android.exoplayer2.C;
|
||||||
|
import com.google.android.exoplayer2.extractor.TimestampAdjuster;
|
||||||
import com.google.android.exoplayer2.util.ParsableByteArray;
|
import com.google.android.exoplayer2.util.ParsableByteArray;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -25,14 +26,18 @@ import com.google.android.exoplayer2.util.ParsableByteArray;
|
|||||||
public final class TimeSignalCommand extends SpliceCommand {
|
public final class TimeSignalCommand extends SpliceCommand {
|
||||||
|
|
||||||
public final long ptsTime;
|
public final long ptsTime;
|
||||||
|
public final long playbackPositionUs;
|
||||||
|
|
||||||
private TimeSignalCommand(long ptsTime) {
|
private TimeSignalCommand(long ptsTime, long playbackPositionUs) {
|
||||||
this.ptsTime = ptsTime;
|
this.ptsTime = ptsTime;
|
||||||
|
this.playbackPositionUs = playbackPositionUs;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* package */ static TimeSignalCommand parseFromSection(ParsableByteArray sectionData,
|
/* package */ static TimeSignalCommand parseFromSection(ParsableByteArray sectionData,
|
||||||
long ptsAdjustment) {
|
long ptsAdjustment, TimestampAdjuster timestampAdjuster) {
|
||||||
return new TimeSignalCommand(parseSpliceTime(sectionData, ptsAdjustment));
|
long ptsTime = parseSpliceTime(sectionData, ptsAdjustment);
|
||||||
|
long playbackPositionUs = timestampAdjuster.adjustTsTimestamp(ptsTime);
|
||||||
|
return new TimeSignalCommand(ptsTime, playbackPositionUs);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -61,6 +66,7 @@ public final class TimeSignalCommand extends SpliceCommand {
|
|||||||
@Override
|
@Override
|
||||||
public void writeToParcel(Parcel dest, int flags) {
|
public void writeToParcel(Parcel dest, int flags) {
|
||||||
dest.writeLong(ptsTime);
|
dest.writeLong(ptsTime);
|
||||||
|
dest.writeLong(playbackPositionUs);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static final Creator<TimeSignalCommand> CREATOR =
|
public static final Creator<TimeSignalCommand> CREATOR =
|
||||||
@ -68,7 +74,7 @@ public final class TimeSignalCommand extends SpliceCommand {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public TimeSignalCommand createFromParcel(Parcel in) {
|
public TimeSignalCommand createFromParcel(Parcel in) {
|
||||||
return new TimeSignalCommand(in.readLong());
|
return new TimeSignalCommand(in.readLong(), in.readLong());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
Loading…
x
Reference in New Issue
Block a user