Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

is There a Loop Mode ? #490

Closed
hateum opened this issue May 24, 2015 · 12 comments
Closed

is There a Loop Mode ? #490

hateum opened this issue May 24, 2015 · 12 comments

Comments

@hateum
Copy link

hateum commented May 24, 2015

How can I add a loop mode ?

@alim-n
Copy link

alim-n commented May 24, 2015

You can play track again when it ends.

@hateum
Copy link
Author

hateum commented May 24, 2015

How can I do it, can you help me.
on the state == end I make seekTo(0) and it doesn't work :(

@crushonme
Copy link

For Dash and Smoothstreaming, you can implements LoopEvaluator from FormatEvaluator in ExoPlayer/library/src/main/java/com/google/android/exoplayer/chunk/FormatEvaluator.java

@hateum
Copy link
Author

hateum commented May 26, 2015

I use the default one to stream an mp4 video

@crushonme
Copy link

/**

  • Selects circularly between the available formats.
    */
    public static class LoopEvaluator implements FormatEvaluator {
static int loop = 0;

@Override
public void enable() {
  // Do nothing.
}

@Override
public void disable() {
  // Do nothing.
}

@Override
public void evaluate(List<? extends MediaChunk> queue, long playbackPositionUs,
                     Format[] formats, Evaluation evaluation) {
    evaluation.format = formats[(formats.length - loop%formats.length -1)];
    loop = (++loop )%formats.length;
}

}

@crushonme
Copy link

Maybe I misunderstand your means.

@ojw28 ojw28 added the question label May 26, 2015
@CaptnBlubber
Copy link

@crushonme

Where do you apply that looping format evaluator to?
From my understanding this should be in the Renderer?

My Problem: I need Adaptive Streaming AND a endless Video Loop.
Therefore I Changed the AdaptiveStreaming Format Evaluator, since the ChunkSources can only Get One FormatEvaluator:

public class AdaptiveLoopingEvaluator implements FormatEvaluator {

public static final int DEFAULT_MAX_INITIAL_BITRATE = 800000;
public static final int DEFAULT_MIN_DURATION_FOR_QUALITY_INCREASE_MS = 10000;
public static final int DEFAULT_MAX_DURATION_FOR_QUALITY_DECREASE_MS = 25000;
public static final int DEFAULT_MIN_DURATION_TO_RETAIN_AFTER_DISCARD_MS = 25000;
public static final float DEFAULT_BANDWIDTH_FRACTION = 0.75F;
private final BandwidthMeter bandwidthMeter;
private final int maxInitialBitrate;
private final long minDurationForQualityIncreaseUs;
private final long maxDurationForQualityDecreaseUs;
private final long minDurationToRetainAfterDiscardUs;
private final float bandwidthFraction;
private int loop = 0;

public AdaptiveLoopingEvaluator(BandwidthMeter bandwidthMeter) {
    this(bandwidthMeter, 800000, 10000, 25000, 25000, 0.75F);
}

public AdaptiveLoopingEvaluator(BandwidthMeter bandwidthMeter, int maxInitialBitrate, int minDurationForQualityIncreaseMs, int maxDurationForQualityDecreaseMs, int minDurationToRetainAfterDiscardMs, float bandwidthFraction) {
    this.bandwidthMeter = bandwidthMeter;
    this.maxInitialBitrate = maxInitialBitrate;
    this.minDurationForQualityIncreaseUs = (long) minDurationForQualityIncreaseMs * 1000L;
    this.maxDurationForQualityDecreaseUs = (long) maxDurationForQualityDecreaseMs * 1000L;
    this.minDurationToRetainAfterDiscardUs = (long) minDurationToRetainAfterDiscardMs * 1000L;
    this.bandwidthFraction = bandwidthFraction;
}

public void enable() {
}

public void disable() {
}

public void evaluate(List<? extends MediaChunk> queue, long playbackPositionUs, Format[] formats, FormatEvaluator.Evaluation evaluation) {
    long bufferedDurationUs = queue.isEmpty() ? 0L : ((MediaChunk) queue.get(queue.size() - 1)).endTimeUs - playbackPositionUs;
    Format current = evaluation.format;
    Format ideal = this.determineIdealFormat(formats, this.bandwidthMeter.getBitrateEstimate());
    boolean isHigher = ideal != null && current != null && ideal.bitrate > current.bitrate;
    boolean isLower = ideal != null && current != null && ideal.bitrate < current.bitrate;
    if (isHigher) {
        if (bufferedDurationUs < this.minDurationForQualityIncreaseUs) {
            ideal = current;
        } else if (bufferedDurationUs >= this.minDurationToRetainAfterDiscardUs) {
            for (int i = 1; i < queue.size(); ++i) {
                MediaChunk thisChunk = (MediaChunk) queue.get(i);
                long durationBeforeThisSegmentUs = thisChunk.startTimeUs - playbackPositionUs;
                if (durationBeforeThisSegmentUs >= this.minDurationToRetainAfterDiscardUs && thisChunk.format.bitrate < ideal.bitrate && thisChunk.format.height < ideal.height && thisChunk.format.height < 720 && thisChunk.format.width < 1280) {
                    evaluation.queueSize = i;
                    break;
                }
            }
        }
    } else if (isLower && current != null && bufferedDurationUs >= this.maxDurationForQualityDecreaseUs) {
        ideal = current;
    }

    if (current != null && ideal != current) {
        evaluation.trigger = 3;
    }

    evaluation.format = ideal;
    loop = (++loop) % formats.length;
}

private Format determineIdealFormat(Format[] formats, long bitrateEstimate) {
    long effectiveBitrate = bitrateEstimate == -1L ? (long) this.maxInitialBitrate : (long) ((float) bitrateEstimate * this.bandwidthFraction);

    for (int i = 0; i < formats.length; ++i) {
        Format format = formats[i];
        if ((long) format.bitrate <= effectiveBitrate) {
            return format;
        }
    }

    return formats[(formats.length - loop % formats.length - 1)];
}
}

I am using the DashRenderBuilder from the sample code (https://github.com/google/ExoPlayer/blob/master/demo/src/main/java/com/google/android/exoplayer/demo/player/DashRendererBuilder.java), the only difference is that I apply my Class to the videoChunkSource and not the Adaptive one from the samples.

It also Seems that the player gets Released once Media Playback is done, since i cannot switch to another Video when one has finished playing and called STATE_ENDED (wich during playback works....)

@vvincirey
Copy link

Can someone explain the solution above?. It is a bit confusing.

@mjsibbald
Copy link

Same here, I dont understand what the LoopEvaluator is doing and if its working for looping video. Doesn't feel like it the aswer to the question "is There a Loop Mode ?"

@Cher80
Copy link

Cher80 commented Apr 21, 2016

`

 playerExo.addListener(new ExoPlayer.Listener() {

            @Override
            public void onPlayerStateChanged(boolean playWhenReady, int playbackState) {

                switch(playbackState) {
                    case ExoPlayer.STATE_BUFFERING:
                        break;
                    case ExoPlayer.STATE_ENDED:
                        playerExo.seekTo(0);
                        break;
                    case ExoPlayer.STATE_IDLE:
                        break;
                    case ExoPlayer.STATE_PREPARING:
                        break;
                    case ExoPlayer.STATE_READY:
                        break;
                    default:
                        break;
                }
            }

            @Override
            public void onPlayWhenReadyCommitted() {

            }

            @Override
            public void onPlayerError(ExoPlaybackException error) {

            }
        });
        playerExo.seekTo(0);
        playerExo.setPlayWhenReady(true);

@ojw28 ojw28 mentioned this issue Aug 23, 2016
ojw28 added a commit that referenced this issue Sep 2, 2016
Now you can do cool things (if you really want to!) like
play a video twice, then play a second video, then loop
the whole thing, all seamlessly.

new LoopingMediaSource(
  new LoopingMediaSource(firstVideoSource, 2),
  secondVideoSource));

You can also just loop, which is probably more useful :).

Issue: #490

-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=132049599
@ojw28
Copy link
Contributor

ojw28 commented Sep 2, 2016

Seamless looping is supported in dev-v2. See the change description above for information about how to do this.

We'll also be publishing a blog post next week about MediaSource composition, which will include a small section on looping media. I'd suggest subscribing to the blog so you're notified when this happens!

@ojw28 ojw28 closed this as completed Sep 2, 2016
@dmota-systango
Copy link

You can use LoopingMediaSource as source instead.

MediaSource source = new ExtractorMediaSource(videoUri, ...);
// Loops the video indefinitely.
LoopingMediaSource loopingSource = new LoopingMediaSource(source);

Ref: https://google.github.io/ExoPlayer/guide.html#seamlessly-looping-a-video

@google google locked and limited conversation to collaborators Jun 28, 2017
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

9 participants