package io.cine.android.streaming; import android.util.Log; import android.view.Surface; import io.cine.ffmpegbridge.FFmpegBridge; /** * Created by thomas on 7/1/14. */ public class EncodingConfig { private String camera; private String forcedOrientation; public void forceOrientation(String forcedOrientation) { this.forcedOrientation = forcedOrientation; } public boolean hasForcedOrientation() { return this.forcedOrientation != null; } public interface EncodingCallback { public void muxerStatusUpdate(MUXER_STATE muxerState); } private static final String TAG = "EncodingConfig"; private int customWidth; private static final int LANDSCAPE_CAMERA_WIDTH = 1280; private int customHeight; private static final int LANDSCAPE_CAMERA_HEIGHT = 720; private static int DEFAULT_BIT_RATE = 1500000; private static int DEFAULT_HUMAN_FPS = 15; private EncodingCallback mEncodingCallback; private MUXER_STATE mMuxerState; public static enum MUXER_STATE {PREPARING, READY, CONNECTING, STREAMING, SHUTDOWN} private Muxer.FORMAT mFormat; private String mOutputString; private AudioEncoderConfig mAudioEncoderConfig; private int mOrientation; private int mMachineVideoFps; public EncodingConfig(EncodingCallback encodingCallback) { mEncodingCallback = encodingCallback; mOrientation = Surface.ROTATION_0; mMachineVideoFps = DEFAULT_HUMAN_FPS * 1000; setDefaultValues(); } public EncodingConfig(){ setDefaultValues(); } private void setDefaultValues(){ this.customHeight = -1; this.customWidth = -1; } public void setWidth(int width){ this.customWidth = width; } public void setHeight(int height){ this.customHeight = height; } public int getWidth() { if (isLandscape()) { return getOrientationAgnosticWidth(); } else { return getOrientationAgnosticHeight(); } } public int getHeight() { if (isLandscape()) { return getOrientationAgnosticHeight(); } else { return getOrientationAgnosticWidth(); } } public int getLandscapeWidth() { return getOrientationAgnosticWidth(); } public int getLandscapeHeight() { return getOrientationAgnosticHeight(); } private int getOrientationAgnosticWidth(){ return this.customWidth == -1 ? LANDSCAPE_CAMERA_WIDTH : this.customWidth; } private int getOrientationAgnosticHeight(){ return this.customHeight == -1 ? LANDSCAPE_CAMERA_HEIGHT : this.customHeight; } public int getBitrate() { return DEFAULT_BIT_RATE; } public boolean forcedLandscape(){ return forcedOrientation.equals("landscape"); } public boolean isLandscape() { if (forcedOrientation != null){ return forcedLandscape(); } boolean isLandscape = false; switch (mOrientation) { case Surface.ROTATION_0: case Surface.ROTATION_180: isLandscape = false; break; case Surface.ROTATION_90: case Surface.ROTATION_270: isLandscape = true; break; } Log.d(TAG, "IS LANDSCAPE: " + isLandscape); return isLandscape; } public void setOutput(String outputString) { mOutputString = outputString; mFormat = EncodingConfig.calculateFormat(outputString); } private static Muxer.FORMAT calculateFormat(String outputString) { if (outputString.startsWith("rtmp://")) { return Muxer.FORMAT.RTMP; } else if (outputString.endsWith(".mp4")) { return Muxer.FORMAT.MPEG4; } else if (outputString.endsWith(".m3u8")) { return Muxer.FORMAT.HLS; } else { return null; } } public String getOutputPath() { return mOutputString; } public Muxer.FORMAT getFormat() { return mFormat; } public AudioEncoderConfig getAudioEncoderConfig() { return mAudioEncoderConfig; } public void setAudioEncoderConfig(AudioEncoderConfig audioEncoderConfig) { mAudioEncoderConfig = audioEncoderConfig; } public FFmpegBridge.AVOptions getAVOptions() { FFmpegBridge.AVOptions opts = new FFmpegBridge.AVOptions(); switch (mFormat) { case MPEG4: opts.outputFormatName = "mp4"; break; case HLS: opts.outputFormatName = "hls"; break; case RTMP: opts.outputFormatName = "flv"; break; default: throw new IllegalArgumentException("Unrecognized format!"); } opts.outputUrl = getOutputPath(); opts.videoHeight = getHeight(); opts.videoWidth = getWidth(); opts.videoFps = getHumanFPS(); opts.videoBitRate = getBitrate(); opts.audioSampleRate = mAudioEncoderConfig.getSampleRate(); opts.audioNumChannels = mAudioEncoderConfig.getNumChannels(); opts.audioBitRate = mAudioEncoderConfig.getBitrate(); return opts; } public int getHumanFPS() { return getMachineVideoFps() / 1000; } // this works because getWidth and getHeight change depending on if it is landscape mode. public double getAspectRatio() { return (double) getWidth() / getHeight(); } public int getOrientation() { return mOrientation; } public void setOrientation(int mOrientation) { this.mOrientation = mOrientation; } public int getMachineVideoFps() { return mMachineVideoFps; } public void setMachineVideoFps(int machineVideoFps) { this.mMachineVideoFps = machineVideoFps; } public void setMuxerState(MUXER_STATE muxerState) { if (mMuxerState == muxerState){ return; } mMuxerState = muxerState; mEncodingCallback.muxerStatusUpdate(muxerState); } }