66import androidx .annotation .NonNull ;
77
88import com .google .android .exoplayer2 .C ;
9+ import com .google .android .exoplayer2 .Format ;
910import com .google .android .exoplayer2 .extractor .ExtractorInput ;
1011import com .google .android .exoplayer2 .source .sabr .parser .exceptions .SabrStreamError ;
12+ import com .google .android .exoplayer2 .source .sabr .parser .misc .EnabledTrackTypes ;
1113import com .google .android .exoplayer2 .source .sabr .parser .models .AudioSelector ;
1214import com .google .android .exoplayer2 .source .sabr .parser .models .CaptionSelector ;
1315import com .google .android .exoplayer2 .source .sabr .parser .models .ConsumedRange ;
@@ -87,6 +89,7 @@ public class SabrProcessor {
8789 private List <FormatId > selectedAudioFormatIds ;
8890 private List <FormatId > selectedVideoFormatIds ;
8991 private List <FormatId > selectedCaptionFormatIds ;
92+ private final Map <Integer , MediaHeader > initializedFormats ;
9093
9194 public SabrProcessor (
9295 @ NonNull String videoPlaybackUstreamerConfig ,
@@ -131,6 +134,7 @@ public SabrProcessor(
131134 totalDurationMs = NO_VALUE ;
132135 sabrContextsToSend = new HashSet <>();
133136 sabrContextUpdates = new HashMap <>();
137+ initializedFormats = new HashMap <>();
134138 initializeClientAbrState ();
135139 }
136140
@@ -244,6 +248,7 @@ public ProcessMediaHeaderResult processMediaHeader(MediaHeader mediaHeader) {
244248 }
245249
246250 Segment segment = new Segment (
251+ mediaHeader ,
247252 mediaHeader .getFormatId (),
248253 isInitSegment ,
249254 durationMs ,
@@ -329,6 +334,8 @@ public ProcessMediaEndResult processMediaEnd(long headerId) {
329334 throw new SabrStreamError (String .format ("Header ID %s not found in partial segments" , headerId ));
330335 }
331336
337+ initializedFormats .put (segment .mediaHeader .getItag (), segment .mediaHeader );
338+
332339 Log .d (TAG , "MediaEnd for %s (sequence %s, data length = %s)" ,
333340 segment .formatId , segment .sequenceNumber , segment .receivedDataLength );
334341
@@ -478,12 +485,12 @@ public ProcessFormatInitializationMetadataResult processFormatInitializationMeta
478485 }
479486 }
480487
481- int durationMs = Utils .ticksToMs (
482- formatInitMetadata .hasDurationTicks () ? formatInitMetadata .getDurationTicks () : -1 ,
488+ long durationMs = Utils .ticksToMs (
489+ formatInitMetadata .hasDurationUnits () ? formatInitMetadata .getDurationUnits () : -1 ,
483490 formatInitMetadata .hasDurationTimescale () ? formatInitMetadata .getDurationTimescale () : -1
484491 );
485492
486- int totalSegments = formatInitMetadata .hasTotalSegments () ? formatInitMetadata .getTotalSegments () : -1 ;
493+ long totalSegments = formatInitMetadata .hasEndSegmentNumber () ? formatInitMetadata .getEndSegmentNumber () : -1 ;
487494
488495 if (totalSegments == -1 && liveMetadata != null && liveMetadata .hasHeadSequenceNumber ()) {
489496 totalSegments = liveMetadata .getHeadSequenceNumber ();
@@ -558,7 +565,7 @@ public ProcessLiveMetadataResult processLiveMetadata(LiveMetadata liveMetadata)
558565 // If the current player time is less than the min dvr time, simulate a server seek to the min dvr time.
559566 // The server SHOULD send us a SABR_SEEK part in this case, but it does not always happen (e.g. ANDROID_VR)
560567 // The server SHOULD NOT send us segments before the min dvr time, so we should assume that the player time is correct.
561- int minSeekableTimeMs = Utils .ticksToMs (liveMetadata .hasMinSeekableTimeTicks () ? liveMetadata .getMinSeekableTimeTicks () : -1 ,
568+ long minSeekableTimeMs = Utils .ticksToMs (liveMetadata .hasMinSeekableTimeTicks () ? liveMetadata .getMinSeekableTimeTicks () : -1 ,
562569 liveMetadata .hasMinSeekableTimescale () ? liveMetadata .getMinSeekableTimescale () : -1 );
563570 if (minSeekableTimeMs != -1 && clientAbrState .hasPlayerTimeMs () && clientAbrState .getPlayerTimeMs () < minSeekableTimeMs ) {
564571 Log .d (TAG , "Player time %s is less than min seekable time %s, simulating server seek" ,
@@ -693,19 +700,34 @@ public int getLiveSegmentTargetDurationSec() {
693700 //}
694701
695702 public VideoPlaybackAbrRequest buildVideoPlaybackAbrRequest (int trackType , boolean isInit ) {
696- int resolution = trackType == C .TRACK_TYPE_VIDEO && videoFormatSelector != null ? Utils .parseHeight (videoFormatSelector .displayName ) : 0 ;
697- int bandwidthEstimate = 1350000 ; // ???
698-
699- ClientAbrState clientAbrStateTest = ClientAbrState .newBuilder ()
700- .setLastManualSelectedResolution (resolution )
701- .setStickyResolution (resolution )
703+ Format selectedVideoFormat = getSelectedFormat (videoFormatSelector );
704+ Format selectedAudioFormat = getSelectedFormat (audioFormatSelector );
705+ int height = trackType == C .TRACK_TYPE_VIDEO && selectedVideoFormat != null
706+ ? selectedVideoFormat .height : -1 ;
707+ int bandwidthEstimate = trackType == C .TRACK_TYPE_VIDEO && selectedVideoFormat != null
708+ ? selectedVideoFormat .bitrate : selectedAudioFormat != null ? selectedAudioFormat .bitrate : -1 ;
709+
710+ ClientAbrState .Builder clientAbrStateBuilder = getClientAbrState ().toBuilder ()
711+ .setSabrForceMaxNetworkInterruptionDurationMs (0 )
712+ .setPlaybackRate (1 ) // TODO: ???
713+ .setPlayerTimeMs (0 ) // TODO: ???
714+ .setClientViewportIsFlexible (false )
702715 .setBandwidthEstimate (bandwidthEstimate )
703- .setEnabledTrackTypesBitfield (getAllSelectedTracksBitfield (trackType ))
704716 .setDrcEnabled (false )
705- .setSabrForceMaxNetworkInterruptionDurationMs (0 )
706- .build ();
717+ .setEnabledTrackTypesBitfield (height != -1 ? EnabledTrackTypes .VIDEO_ONLY : EnabledTrackTypes .AUDIO_ONLY );
718+
719+ if (height != -1 ) {
720+ clientAbrStateBuilder
721+ .setStickyResolution (height )
722+ .setLastManualSelectedResolution (height );
723+ } else {
724+ //clientAbrStateBuilder
725+ // .setAudioTrackId("0");
726+ }
727+
728+ ClientAbrState clientAbrStateMod = clientAbrStateBuilder .build ();
707729
708- Pair <List <BufferedRange >, FormatId > bufferRanges = createBufferedRangesAndDiscardFormat (trackType );
730+ Pair <List <BufferedRange >, FormatId > bufferRanges = addBufferingInfoToAbrRequest (trackType );
709731
710732 List <FormatId > selectedFormats = getSelectedFormatIds (trackType );
711733
@@ -718,7 +740,7 @@ public VideoPlaybackAbrRequest buildVideoPlaybackAbrRequest(int trackType, boole
718740 }
719741
720742 return VideoPlaybackAbrRequest .newBuilder ()
721- .setClientAbrState (clientAbrStateTest )
743+ .setClientAbrState (clientAbrStateMod )
722744 .addAllPreferredVideoFormatIds (videoFormatSelector .formatIds )
723745 .addAllPreferredAudioFormatIds (audioFormatSelector .formatIds )
724746 .addAllPreferredSubtitleFormatIds (captionFormatSelector .formatIds )
@@ -733,6 +755,10 @@ public VideoPlaybackAbrRequest buildVideoPlaybackAbrRequest(int trackType, boole
733755 .build ();
734756 }
735757
758+ private static Format getSelectedFormat (FormatSelector formatSelector ) {
759+ return formatSelector != null && !formatSelector .selectedFormats .isEmpty () ? formatSelector .selectedFormats .get (0 ) : null ;
760+ }
761+
736762 private List <FormatId > getSelectedFormatIds () {
737763 List <FormatId > result = new ArrayList <>();
738764
@@ -743,18 +769,6 @@ private List<FormatId> getSelectedFormatIds() {
743769 return result ;
744770 }
745771
746- private int getAllSelectedTracksBitfield (int trackType ) {
747- if (!videoFormatSelector .formatIds .isEmpty () && trackType == C .TRACK_TYPE_VIDEO ) {
748- return 1 ;
749- } else if (!audioFormatSelector .formatIds .isEmpty () && trackType == C .TRACK_TYPE_AUDIO ) {
750- return 2 ;
751- } else if (!captionFormatSelector .formatIds .isEmpty () && trackType == C .TRACK_TYPE_TEXT ) {
752- return 3 ;
753- }
754-
755- return 0 ;
756- }
757-
758772 private List <FormatId > getSelectedFormatIds (int trackType ) {
759773 List <FormatId > result = new ArrayList <>();
760774
@@ -885,23 +899,24 @@ public void setCaptionFormatSelector(CaptionSelector captionFormatSelector) {
885899 *
886900 * @return The format to discard (if any) - typically formats that are active but not currently requested.
887901 */
888- private Pair <List <BufferedRange >, FormatId > createBufferedRangesAndDiscardFormat (int trackType ) {
902+ private Pair <List <BufferedRange >, FormatId > addBufferingInfoToAbrRequest (int trackType ) {
889903 FormatId audioFormat = audioFormatSelector .formatIds .isEmpty () ? null : audioFormatSelector .formatIds .get (0 );
890904 FormatId videoFormat = videoFormatSelector .formatIds .isEmpty () ? null : videoFormatSelector .formatIds .get (0 );
891905
892906 FormatId formatToDiscard = null ;
893907 List <BufferedRange > bufferedRanges = new ArrayList <>();
894908
895909 FormatId currentFormat = trackType == C .TRACK_TYPE_VIDEO ? videoFormat : audioFormat ;
896- int currentFormatITag = currentFormat != null ? currentFormat .getItag () : -1 ;
910+ int currentFormatKey = currentFormat != null ? currentFormat .getItag () : -1 ;
897911
898912 for (FormatId activeFormat : new FormatId []{videoFormat , audioFormat }) {
899913 if (activeFormat == null ) {
900914 continue ;
901915 }
902916
903- boolean shouldDiscard = currentFormatITag != activeFormat .getItag ();
904- SelectedFormat initializedFormat = null ; // TODO: not implemented
917+ int activeFormatKey = activeFormat .getItag ();
918+ boolean shouldDiscard = currentFormatKey != activeFormatKey ;
919+ MediaHeader initializedFormat = initializedFormats .get (activeFormatKey );
905920
906921 BufferedRange bufferedRange = shouldDiscard ? createFullBufferRange (activeFormat ) : createPartialBufferRange (initializedFormat );
907922
@@ -943,11 +958,30 @@ private BufferedRange createFullBufferRange(@NonNull FormatId format) {
943958 * @param initializedFormat - The format with initialization data.
944959 * @return A BufferedRange object with segment information, or null if no metadata is available.
945960 */
946- private BufferedRange createPartialBufferRange (SelectedFormat initializedFormat ) {
961+ private BufferedRange createPartialBufferRange (MediaHeader initializedFormat ) {
947962 if (initializedFormat == null ) {
948963 return null ;
949964 }
950965
951- return null ;
966+ int sequenceNumber = initializedFormat .hasSequenceNumber () ? initializedFormat .getSequenceNumber () : 1 ;
967+ TimeRange timeRange = initializedFormat .hasTimeRange () ? initializedFormat .getTimeRange () : null ;
968+ int timeScale = timeRange != null && timeRange .hasTimescale () ? timeRange .getTimescale () : 1_000 ;
969+ long durationMs = initializedFormat .hasDurationMs () ? initializedFormat .getDurationMs () : 0 ;
970+ return BufferedRange .newBuilder ()
971+ .setFormatId (initializedFormat .getFormatId ())
972+ .setStartSegmentIndex (sequenceNumber )
973+ .setDurationMs (durationMs )
974+ .setStartTimeMs (0 )
975+ .setEndSegmentIndex (sequenceNumber )
976+ .setTimeRange (TimeRange .newBuilder ()
977+ .setTimescale (timeScale )
978+ .setStartTicks (0 )
979+ .setDurationTicks (durationMs )
980+ .build ())
981+ .build ();
982+ }
983+
984+ public void handleResponse () {
985+
952986 }
953987}
0 commit comments