com.att.aro.core.videoanalysis.impl.BufferInSecondsCalculatorImpl.java Source code

Java tutorial

Introduction

Here is the source code for com.att.aro.core.videoanalysis.impl.BufferInSecondsCalculatorImpl.java

Source

/*
 *  Copyright 2017 AT&T
 *
 * 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.att.aro.core.videoanalysis.impl;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.HashMap;
import java.util.Map;
import java.util.TreeMap;

import org.apache.commons.math3.util.MathUtils;
import org.springframework.beans.factory.annotation.Autowired;
import com.att.aro.core.bestpractice.pojo.VideoUsage;
import com.att.aro.core.packetanalysis.pojo.BufferTimeBPResult;
import com.att.aro.core.packetanalysis.pojo.VideoStall;
import com.att.aro.core.videoanalysis.AbstractBufferOccupancyCalculator;
import com.att.aro.core.videoanalysis.IVideoUsagePrefsManager;
import com.att.aro.core.videoanalysis.pojo.AROManifest;
import com.att.aro.core.videoanalysis.pojo.VideoEvent;

public class BufferInSecondsCalculatorImpl extends AbstractBufferOccupancyCalculator {

    private List<VideoEvent> filteredChunk;
    private List<VideoEvent> chunkDownload;
    private Map<VideoEvent, AROManifest> veManifestList;

    private List<VideoEvent> veDone;

    double beginBuffer, endBuffer;

    Map<Integer, String> seriesDataSets = new TreeMap<Integer, String>();
    int key;

    private BufferTimeBPResult bufferTimeResult;

    @Autowired
    private VideoChunkPlotterImpl videoChunkPlotterImpl;

    private List<VideoEvent> veWithIn;
    private List<VideoEvent> completedDownloads = new ArrayList<>();
    // private int stallCount;
    private List<VideoStall> videoStallResult;
    private boolean stallStarted;
    double possibleStartPlayTime;

    @Autowired
    private IVideoUsagePrefsManager videoPrefManager;

    private double stallTriggerTime;
    private double stallPausePoint;
    private double stallRecovery;

    public List<VideoStall> getVideoStallResult() {
        return videoStallResult;
    }

    public double getStallTriggerTime() {
        return stallTriggerTime;
    }

    private void setStallTriggerTime(double stallTriggerTime) {
        this.stallTriggerTime = stallTriggerTime;
    }

    public double getStallPausePoint() {
        return stallPausePoint;
    }

    public void setStallPausePoint(double stallPausePoint) {
        this.stallPausePoint = stallPausePoint;
    }

    public double getStallRecovery() {
        return stallRecovery;
    }

    public void setStallRecovery(double stallRecovery) {
        this.stallRecovery = stallRecovery;
    }

    public Map<Integer, String> populate(VideoUsage videoUsage, Map<VideoEvent, Double> chunkPlayTimeList) {
        if (videoPrefManager.getVideoUsagePreference() != null) {
            setStallTriggerTime(videoPrefManager.getVideoUsagePreference().getStallTriggerTime());
            setStallPausePoint(videoPrefManager.getVideoUsagePreference().getStallPausePoint());
            setStallRecovery(videoPrefManager.getVideoUsagePreference().getStallRecovery());
        }
        // this.chunkPlayTimeList = chunkPlayTimeList;
        seriesDataSets.clear();
        key = 0;
        // stallCount=0;
        videoStallResult = new ArrayList<>();
        if (videoUsage != null) {
            filteredChunk = new ArrayList<>();
            chunkDownload = new ArrayList<>();
            veDone = new ArrayList<>();
            veWithIn = new ArrayList<>();
            completedDownloads.clear();
            beginBuffer = 0;
            endBuffer = 0;
            stallStarted = false;

            initialize(videoUsage);

            double bufferInSeconds = 0;
            possibleStartPlayTime = 0;
            for (int index = 0; index < videoUsage.getChunksBySegmentNumber().size(); index++) {// filteredChunk
                bufferInSeconds = 0;

                updateUnfinishedDoneVideoEvent();

                bufferInSeconds = drawVeDone(veDone, beginBuffer);
                veDone.clear();

                bufferInSeconds = drawVeWithIn(veWithIn, bufferInSeconds);
                veWithIn.clear();

                endBuffer = bufferInSeconds;

                if (bufferInSeconds < 0) { // using -ve as stall indicator
                    // if indicated push the chunk play start time
                    double tempPrevTime = 0;
                    if (possibleStartPlayTime != 0) {
                        tempPrevTime = possibleStartPlayTime;
                    }
                    possibleStartPlayTime = updatePlayStartTime(chunkPlaying);

                    if (possibleStartPlayTime == -1 || possibleStartPlayTime == tempPrevTime) {
                        possibleStartPlayTime = updatePlayStartTimeAfterStall(chunkPlaying, stallPausePoint,
                                stallRecovery);
                        if (possibleStartPlayTime <= tempPrevTime) {
                            seriesDataSets.clear();
                            break;
                        }
                        if (!videoStallResult.isEmpty()) {
                            videoStallResult.get(videoStallResult.size() - 1).setSegmentTryingToPlay(chunkPlaying);
                            videoStallResult.get(videoStallResult.size() - 1)
                                    .setStallEndTimeStamp(possibleStartPlayTime);
                        }
                        addToChunkPlayTimeList(chunkPlaying, possibleStartPlayTime);
                    }
                    index--;
                    continue;
                }

                beginBuffer = endBuffer;
                if (index + 1 <= videoUsage.getChunksBySegmentNumber().size() - 1) {
                    setNextPlayingChunk(index + 1, videoUsage.getChunksBySegmentNumber());
                }
            }
        }

        return seriesDataSets;

    }

    @Override
    public double drawVeDone(List<VideoEvent> veDone, double beginBuffer) {
        double buffer = beginBuffer;
        Collections.sort(veDone, new VideoEventComparator(SortSelection.END_TS));

        for (VideoEvent chunk : veDone) {

            seriesDataSets.put(key, chunk.getEndTS() + "," + buffer);
            key++;

            buffer = buffer + getChunkPlayTimeDuration(chunk);

            seriesDataSets.put(key, chunk.getEndTS() + "," + buffer);
            key++;

            completedDownloads.add(chunk);
            chunkDownload.remove(chunk);

        }

        return buffer;
    }

    public double drawVeWithIn(List<VideoEvent> veWithIn, double beginBuffer) {
        double buffer = beginBuffer;

        if (veWithIn.size() == 0 && completedDownloads.contains(chunkPlaying)) {
            buffer = bufferDrain(buffer);
        } else if (completedDownloads.contains(chunkPlaying)) {
            Collections.sort(veWithIn, new VideoEventComparator(SortSelection.END_TS));

            boolean drained = false;
            VideoEvent chunk;
            double timeRange;
            double durationLeft = chunkPlayTimeDuration;

            seriesDataSets.put(key, chunkPlayStartTime + "," + buffer);
            key++;

            if (stallStarted) {
                updateStallInformation(chunkPlayStartTime);
                stallStarted = false;
            }

            for (int index = 0; index < veWithIn.size(); index++) {
                chunk = veWithIn.get(index);
                if (MathUtils.equals(chunk.getEndTS(), chunkPlayEndTime)) {
                    // finish draining
                    buffer = buffer - durationLeft;
                    if (buffer <= 0) {
                        buffer = 0;
                        updateStallInformation(chunk.getEndTS());
                    }
                    seriesDataSets.put(key, chunkPlayEndTime + "," + buffer);
                    key++;
                    drained = true;

                    buffer = buffer + getChunkPlayTimeDuration(chunk);

                    seriesDataSets.put(key, chunk.getEndTS() + "," + buffer);
                    key++;

                    completedDownloads.add(chunk);
                    chunkDownload.remove(chunk);
                } else {
                    if (index == 0) {
                        timeRange = chunk.getEndTS() - chunkPlayStartTime;
                    } else {
                        timeRange = chunk.getEndTS() - veWithIn.get(index - 1).getEndTS();
                    }

                    buffer = buffer - timeRange;
                    if (buffer <= 0) {
                        buffer = 0;
                        stallStarted = true;
                        updateStallInformation(chunk.getEndTS());
                    }
                    durationLeft = durationLeft - timeRange;

                    seriesDataSets.put(key, chunk.getEndTS() + "," + buffer);
                    key++;

                    buffer = buffer + getChunkPlayTimeDuration(chunk);

                    seriesDataSets.put(key, chunk.getEndTS() + "," + buffer);
                    key++;

                    completedDownloads.add(chunk);
                    chunkDownload.remove(chunk);
                }
            }

            if (drained == false) {
                buffer = buffer - durationLeft;
                if (buffer <= 0) {
                    buffer = 0;
                    stallStarted = true;
                    updateStallInformation(chunkPlayEndTime);
                }
                seriesDataSets.put(key, chunkPlayEndTime + "," + buffer);
                key++;

            }

        } else {
            boolean skipStallStart = false;
            for (VideoStall stall : videoStallResult) {
                if (BigDecimal.valueOf(stall.getStallStartTimeStamp()) == BigDecimal.valueOf(chunkPlayStartTime)) {
                    skipStallStart = true;
                    break;
                }
            }
            if (skipStallStart == false) {
                stallStarted = true;
                VideoStall stall = new VideoStall(chunkPlayStartTime);
                videoStallResult.add(stall);
            }
            return -1;
        }

        return buffer;

    }

    private void initialize(VideoUsage videoUsage) {
        this.videoUsage = videoUsage;
        filteredChunk = videoUsage.getFilteredSegments(); // filterVideoSegment(videoUsage);
        chunkDownload = new ArrayList<>();
        for (VideoEvent vEvent : filteredChunk) {
            chunkDownload.add(vEvent);
        }
        veManifestList = videoUsage.getVideoEventManifestMap();

        runInit(videoUsage, veManifestList, videoUsage.getChunksBySegmentNumber());
    }

    public double getChunkPlayStartTime(VideoEvent chunkPlaying) {
        for (VideoEvent veEvent : chunkPlayTimeList.keySet()) {
            if (veEvent.equals(chunkPlaying)) {
                return chunkPlayTimeList.get(veEvent); // return play start time
            }
        }
        return -1;
    }

    public void updateUnfinishedDoneVideoEvent() {
        for (VideoEvent ve : chunkDownload) {
            if (ve.getDLTimeStamp() < chunkPlayStartTime && ve.getEndTS() <= chunkPlayStartTime) {
                veDone.add(ve);
            } else if (ve.getEndTS() > chunkPlayStartTime && ve.getEndTS() <= chunkPlayEndTime) {
                veWithIn.add(ve);
            }
        }
    }

    public void updateStallInformation(double stallTime) {
        if (stallStarted && (videoStallResult != null && videoStallResult.size() != 0)) {
            VideoStall veStall = videoStallResult.get(videoStallResult.size() - 1);
            if (veStall.getStallStartTimeStamp() != stallTime) {
                veStall.setStallEndTimeStamp(stallTime);
            }
        } else {
            stallStarted = true;
            VideoStall stall = new VideoStall(stallTime);
            videoStallResult.add(stall);
        }
    }

    @Override
    public double bufferDrain(double buffer) {
        if (buffer > 0 && completedDownloads.contains(chunkPlaying)) {
            seriesDataSets.put(key, chunkPlayStartTime + "," + buffer);
            key++;

            buffer = buffer - chunkPlayTimeDuration;
            if (buffer <= 0) {
                buffer = 0;
                stallStarted = true;
                VideoStall stall = new VideoStall(chunkPlayEndTime);
                videoStallResult.add(stall);
            } else {
                if (stallStarted) {
                    updateStallInformation(chunkPlayStartTime);
                    stallStarted = false;
                }
            }

            seriesDataSets.put(key, chunkPlayEndTime + "," + buffer);
            key++;

        } else {
            // stall
            if (buffer <= 0) { // want to see if buffer >0 & stall happening
                buffer = 0;
                stallStarted = true;
                updateStallInformation(chunkPlayStartTime);
            }
            seriesDataSets.put(key, chunkPlayStartTime + "," + buffer);
            key++;
            return -1;
        }

        return buffer;
    }

    public Map<Long, Double> getSegmentStartTimeMap() {
        return videoChunkPlotterImpl.getSegmentStartTimeList();
    }

    public Map<Double, Long> getSegmentEndTimeMap() {
        Map<Long, Double> segmentStartTimeMap = getSegmentStartTimeMap();
        Map<Double, Long> segmentEndTimeMap = new HashMap<Double, Long>();
        if (segmentStartTimeMap != null) {
            for (VideoEvent ve : videoUsage.getFilteredSegments()) {
                if (ve == null) {
                    continue;
                }
                Double startTime = segmentStartTimeMap.get(new Double(ve.getSegment()).longValue());
                double segmentPlayEndTime = (startTime != null ? startTime : 0.0) + getChunkPlayTimeDuration(ve);
                segmentEndTimeMap.put(segmentPlayEndTime, new Double(ve.getSegment()).longValue());
            }
        }
        return segmentEndTimeMap;
    }

    public BufferTimeBPResult updateBufferTimeResult(List<Double> bufferTimeBPResult) {
        bufferTimeResult = new BufferTimeBPResult(bufferTimeBPResult);
        return bufferTimeResult;
    }
}