org.red5.service.httpstream.SegmenterService.java Source code

Java tutorial

Introduction

Here is the source code for org.red5.service.httpstream.SegmenterService.java

Source

/*
 * RED5 HLS plugin - https://github.com/mondain/red5-hls-plugin
 * 
 * Copyright 2006-2013 by respective authors (see below). All rights reserved.
 * 
 * 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 org.red5.service.httpstream;

import java.util.Map.Entry;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.Future;

import org.red5.logging.Red5LoggerFactory;
import org.red5.server.api.scope.IScope;
import org.red5.server.api.stream.IBroadcastStream;
import org.red5.service.httpstream.model.Segment;
import org.red5.stream.util.AudioMux;
import org.slf4j.Logger;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;

//import com.xuggle.mediatool.ToolFactory;
import io.humble.video.Global;

/**
 * Creates, updates, locates, and manages media segments.
 * 
 * @author Paul Gregoire (mondain@gmail.com)
 */
public class SegmenterService implements InitializingBean, DisposableBean {

    private static Logger log = Red5LoggerFactory.getLogger(SegmenterService.class);

    // map of currently available segment facades, keyed by stream name
    private static ConcurrentMap<String, SegmentFacade> segmentMap = new ConcurrentHashMap<String, SegmentFacade>();

    // mux service
    private MuxService muxService;

    // execution handling
    private ThreadPoolTaskScheduler segmentExecutor;

    // length of a segment in milliseconds
    private long segmentTimeLimit = 4000;

    // where to write segment files
    private String segmentDirectory;

    // whether to use files or memory for segments
    private boolean memoryMapped;

    // maximum number of segments to keep available per stream
    private int maxSegmentsPerFacade = 4;

    private String outputAudioCodec = "libvo_aacenc";

    private String outputVideoCodec = "libx264";

    /**
     * Creates and starts a facade and adds an audio mux for the given scope.
     * 
     * @param scope
     * @param stream
     * @param useRTMPReader
     */
    public void start(IScope scope, IBroadcastStream stream, boolean useRTMPReader) {
        log.debug("start - scope: {} stream: {} rtmp reader: {}", scope.getName(), stream.getPublishedName(),
                useRTMPReader);
        String streamName = stream.getPublishedName();
        start(streamName, useRTMPReader);
        // add the mux associated with the given scope
        AudioMux mux = muxService.getAudioMux(scope.getName());
        if (mux != null) {
            // get the facade for this stream
            segmentMap.get(streamName).setAudioMux(mux);
            // add the streams audio track to the muxer
            mux.addTrack(2, streamName); // TODO create a better way to know what our output channels are (defaulting to 2 / stereo)
        } else {
            log.warn("Audio mux service was not found");
        }
    }

    /**
     * Creates and starts a facade.
     * 
     * @param name
     * @param useRTMPReader
     */
    public SegmentFacade start(String name, boolean useRTMPReader) {
        log.debug("start - name: {} rtmp reader: {}", name, useRTMPReader);
        // lookup the associated segment
        SegmentFacade facade = segmentMap.get(name);
        if (facade == null) {
            log.debug("Creating segment facade for {}", name);
            // create a facade
            facade = new SegmentFacade(this, name);
            // add to the map
            addFacade(name, facade);
            // configure
            facade.setSegmentTimeLimit(segmentTimeLimit);
            facade.setSegmentDirectory(segmentDirectory);
            facade.setMaxSegmentsPerFacade(maxSegmentsPerFacade);
            facade.setMemoryMapped(memoryMapped);
            facade.setOutputAudioCodec(outputAudioCodec);
            facade.setOutputVideoCodec(outputVideoCodec);
            // initialization
            if (useRTMPReader) {
                // initialize RTMP reader
                facade.initReader();
            }
            // initialize HLS writer
            facade.initWriter();
        }
        return facade;
    }

    public void afterPropertiesSet() throws Exception {
        // put xuggle into turbo mode
        //TODO: Determine if setTurboCharged exists for H-IO
        //ToolFactory.setTurboCharged(true);
        if (log.isDebugEnabled()) {
            Global.setFFmpegLoggingLevel(99);
        }
        log.debug("Executor - prefers short tasks: {} daemon: {}", segmentExecutor.prefersShortLivedTasks(),
                segmentExecutor.isDaemon());
    }

    public void destroy() throws Exception {
        // walk the map and close them down
        for (Entry<String, SegmentFacade> entry : segmentMap.entrySet()) {
            SegmentFacade value = entry.getValue();
            Segment segment = value.getSegment();
            if (segment != null) {
                segment.setLast(true);
                segment.close();
            }
            segmentMap.remove(entry.getKey(), value);
        }
        segmentMap.clear();
    }

    public Future<?> submitJob(Runnable task) {
        log.debug("submitJob: {}", task.getClass().getName());
        return segmentExecutor.submit(task);
    }

    public Future<?> submitJob(Runnable task, long period) {
        log.debug("submitJob: {} period: {}", task.getClass().getName(), period);
        return segmentExecutor.scheduleAtFixedRate(task, period);
    }

    /**
     * @param muxService the muxService to set
     */
    public void setMuxService(MuxService muxService) {
        this.muxService = muxService;
    }

    /**
     * @param segmentExecutor the segmentExecutor to set
     */
    public void setSegmentExecutor(ThreadPoolTaskScheduler segmentExecutor) {
        this.segmentExecutor = segmentExecutor;
    }

    /**
     * @param outputAudioCodec the outputAudioCodec to set
     */
    public void setOutputAudioCodec(String outputAudioCodec) {
        this.outputAudioCodec = outputAudioCodec;
    }

    /**
     * @param outputVideoCodec the outputVideoCodec to set
     */
    public void setOutputVideoCodec(String outputVideoCodec) {
        this.outputVideoCodec = outputVideoCodec;
    }

    public long getSegmentTimeLimit() {
        return segmentTimeLimit;
    }

    public void setSegmentTimeLimit(long segmentTimeLimit) {
        this.segmentTimeLimit = segmentTimeLimit;
    }

    public String getSegmentDirectory() {
        return segmentDirectory;
    }

    public void setSegmentDirectory(String segmentDirectory) {
        this.segmentDirectory = segmentDirectory;
    }

    public boolean isMemoryMapped() {
        return memoryMapped;
    }

    public void setMemoryMapped(boolean memoryMapped) {
        this.memoryMapped = memoryMapped;
    }

    public int getMaxSegmentsPerFacade() {
        return maxSegmentsPerFacade;
    }

    public void setMaxSegmentsPerFacade(int maxSegmentsPerFacade) {
        this.maxSegmentsPerFacade = maxSegmentsPerFacade;
    }

    public int getSegmentCount(String streamName) {
        SegmentFacade facade = segmentMap.get(streamName);
        return facade.getSegmentCount();
    }

    public Segment getSegment(String streamName) {
        SegmentFacade facade = segmentMap.get(streamName);
        return facade.getSegment();
    }

    public Segment getSegment(String streamName, int index) {
        SegmentFacade facade = segmentMap.get(streamName);
        return facade.getSegment(index);
    }

    public Segment[] getSegments(String streamName) {
        SegmentFacade facade = segmentMap.get(streamName);
        return facade.getSegments();
    }

    public boolean isAvailable(String streamName) {
        return segmentMap.containsKey(streamName);
    }

    protected void addFacade(String streamName, SegmentFacade facade) {
        segmentMap.put(streamName, facade);
    }

}