+ * The EGLContext must only be attached to one thread at a time. This class is not thread-safe.
+ */
+
+public final class EglCore {
+
+ private final static String TAG = EglCore.class.getSimpleName();
+
+ public final static int FLAG_RECORDABLE = 0x01;
+
+ public final static int FLAG_TRY_GLES3 = 0x02;
+
+ private final static int EGL_RECORDABLE_ANDROID = 0x3142;
+
+ private int mGlVersion = -1;
+ private EGLConfig mEGLConfig = null;
+ private EGLDisplay mEGLDisplay = EGL14.EGL_NO_DISPLAY;
+ private EGLContext mEGLContext = EGL14.EGL_NO_CONTEXT;
+
+ public EglCore() {
+ this(null, 0);
+ }
+
+ public EglCore(EGLContext sharedContext, int flag) {
+ mEGLDisplay = EGL14.eglGetDisplay(EGL14.EGL_DEFAULT_DISPLAY);
+ int[] version = new int[2];
+ if (!EGL14.eglInitialize(mEGLDisplay, version, 0, version, 1)) {
+ throw new RuntimeException("unable to init EGL14");
+ }
+
+ if ((flag & FLAG_TRY_GLES3) != 0) {
+ initEGLContext(sharedContext, flag, 3);
+ }
+ if (mEGLContext == EGL14.EGL_NO_CONTEXT) {
+ initEGLContext(sharedContext, flag, 2);
+ }
+
+ int[] value = new int[1];
+ EGL14.eglQueryContext(mEGLDisplay, mEGLContext, EGL14.EGL_CONTEXT_CLIENT_VERSION, value, 0);
+ Log.i(TAG, "EGLContext client version=" + value[0]);
+ }
+
+ private void initEGLContext(EGLContext sharedContext, int flag, int version) {
+ EGLConfig config = getConfig(flag, version);
+ if (config == null) {
+ throw new RuntimeException("unable to find suitable EGLConfig");
+ }
+ int[] attributeList = {EGL14.EGL_CONTEXT_CLIENT_VERSION, version, EGL14.EGL_NONE};
+ EGLContext context = EGL14.eglCreateContext(mEGLDisplay, config, sharedContext, attributeList, 0);
+ if (EGL14.eglGetError() == EGL14.EGL_SUCCESS) {
+ mEGLConfig = config;
+ mEGLContext = context;
+ mGlVersion = version;
+ }
+ }
+
+ private EGLConfig getConfig(int flag, int version) {
+ int renderType = EGL14.EGL_OPENGL_ES2_BIT;
+ if (version >= 3) {
+ renderType |= EGLExt.EGL_OPENGL_ES3_BIT_KHR;
+ }
+
+ int[] attributeList = {
+ EGL14.EGL_RED_SIZE, 8,
+ EGL14.EGL_GREEN_SIZE, 8,
+ EGL14.EGL_BLUE_SIZE, 8,
+ EGL14.EGL_ALPHA_SIZE, 8,
+ //EGL14.EGL_DEPTH_SIZE, 16,
+ //EGL14.EGL_STENCIL_SIZE, 8,
+ EGL14.EGL_RENDERABLE_TYPE, renderType,
+ EGL14.EGL_NONE, 0,
+ EGL14.EGL_NONE
+ };
+
+ if ((flag & FLAG_RECORDABLE) != 0) {
+ attributeList[attributeList.length - 3] = EGL_RECORDABLE_ANDROID;
+ attributeList[attributeList.length - 2] = 1;
+ }
+ int[] numConfigs = new int[1];
+ EGLConfig[] configs = new EGLConfig[1];
+ if (!EGL14.eglChooseConfig(mEGLDisplay, attributeList, 0, configs,
+ 0, configs.length, numConfigs, 0)) {
+ Log.e(TAG, "unable to find RGB8888 / " + version + " EGLConfig");
+ return null;
+ }
+ return configs[0];
+ }
+
+ public void release() {
+ if (mEGLDisplay != EGL14.EGL_NO_DISPLAY) {
+ EGL14.eglMakeCurrent(mEGLDisplay, EGL14.EGL_NO_SURFACE, EGL14.EGL_NO_SURFACE, EGL14.EGL_NO_CONTEXT);
+ EGL14.eglDestroyContext(mEGLDisplay, mEGLContext);
+ EGL14.eglReleaseThread();
+ EGL14.eglTerminate(mEGLDisplay);
+ }
+ mEGLConfig = null;
+ mEGLDisplay = EGL14.EGL_NO_DISPLAY;
+ mEGLContext = EGL14.EGL_NO_CONTEXT;
+ }
+
+ @Override
+ protected void finalize() throws Throwable {
+ try {
+ if (mEGLDisplay != EGL14.EGL_NO_DISPLAY) {
+ release();
+ }
+ } finally {
+ super.finalize();
+ }
+ }
+
+ public void releaseSurface(EGLSurface eglSurface) {
+ if (mEGLDisplay != EGL14.EGL_NO_DISPLAY) {
+ EGL14.eglDestroySurface(mEGLDisplay, eglSurface);
+ }
+ }
+
+ public EGLSurface createWindowSurface(Object surface) {
+ if (!(surface instanceof Surface) && !(surface instanceof SurfaceTexture)) {
+ throw new RuntimeException("invalid surface:" + surface);
+ }
+
+ int[] surfaceAttr = {EGL14.EGL_NONE};
+ EGLSurface eglSurface = EGL14.eglCreateWindowSurface(mEGLDisplay, mEGLConfig, surface, surfaceAttr, 0);
+ if (eglSurface == null) {
+ throw new RuntimeException("window surface is null");
+ }
+ return eglSurface;
+ }
+
+ public EGLSurface createOffsetScreenSurface(int width, int height) {
+ int[] surfaceAttr = {EGL14.EGL_WIDTH, width,
+ EGL14.EGL_HEIGHT, height,
+ EGL14.EGL_NONE};
+ EGLSurface eglSurface = EGL14.eglCreatePbufferSurface(mEGLDisplay, mEGLConfig, surfaceAttr, 0);
+ if (eglSurface == null) {
+ throw new RuntimeException("offset-screen surface is null");
+ }
+ return eglSurface;
+ }
+
+ public void makeCurrent(EGLSurface eglSurface) {
+ if (!EGL14.eglMakeCurrent(mEGLDisplay, eglSurface, eglSurface, mEGLContext)) {
+ throw new RuntimeException("eglMakeCurrent failed!");
+ }
+ }
+
+ public void makeCurrent(EGLSurface drawSurface, EGLSurface readSurface) {
+ if (!EGL14.eglMakeCurrent(mEGLDisplay, drawSurface, readSurface, mEGLContext)) {
+ throw new RuntimeException("eglMakeCurrent failed!");
+ }
+ }
+
+ public boolean swapBuffers(EGLSurface eglSurface) {
+ return EGL14.eglSwapBuffers(mEGLDisplay, eglSurface);
+ }
+
+ public void setPresentationTime(EGLSurface eglSurface, long nsec) {
+ EGLExt.eglPresentationTimeANDROID(mEGLDisplay, eglSurface, nsec);
+ }
+
+ public boolean isCurrent(EGLSurface eglSurface) {
+ return mEGLContext.equals(EGL14.eglGetCurrentContext())
+ && eglSurface.equals(EGL14.eglGetCurrentSurface(EGL14.EGL_DRAW));
+ }
+
+ public int querySurface(EGLSurface eglSurface, int what) {
+ int[] value = new int[1];
+ EGL14.eglQuerySurface(mEGLDisplay, eglSurface, what, value, 0);
+ return value[0];
+ }
+
+ public String queryString(int what) {
+ return EGL14.eglQueryString(mEGLDisplay, what);
+ }
+
+ public int getVersion() {
+ return mGlVersion;
+ }
+
+}
diff --git a/CameraFilter/src/main/java/com/frank/camerafilter/recorder/egl/EglSurfaceBase.java b/CameraFilter/src/main/java/com/frank/camerafilter/recorder/egl/EglSurfaceBase.java
new file mode 100644
index 00000000..a408c60e
--- /dev/null
+++ b/CameraFilter/src/main/java/com/frank/camerafilter/recorder/egl/EglSurfaceBase.java
@@ -0,0 +1,106 @@
+package com.frank.camerafilter.recorder.egl;
+
+import android.graphics.Bitmap;
+import android.opengl.EGL14;
+import android.opengl.EGLSurface;
+import android.opengl.GLES20;
+
+import java.io.BufferedOutputStream;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.nio.IntBuffer;
+
+/**
+ * @author xufulong
+ * @date 2022/6/23 8:51 上午
+ * @desc
+ */
+public class EglSurfaceBase {
+
+ protected EglCore mEglCore;
+ protected int mWidth = -1;
+ protected int mHeight = -1;
+
+ private EGLSurface mEGLSurface = EGL14.EGL_NO_SURFACE;
+
+ protected EglSurfaceBase(EglCore eglCore) {
+ mEglCore = eglCore;
+ }
+
+ public void createWindowSurface(Object surface) {
+ if (mEGLSurface != EGL14.EGL_NO_SURFACE) {
+ throw new IllegalStateException("egl surface has already created");
+ }
+ mEGLSurface = mEglCore.createWindowSurface(surface);
+ }
+
+ public void createOffsetScreenSurface(int width, int height) {
+ if (mEGLSurface != EGL14.EGL_NO_SURFACE) {
+ throw new IllegalStateException("egl surface has already created");
+ }
+ mWidth = width;
+ mHeight = height;
+ mEGLSurface = mEglCore.createOffsetScreenSurface(width, height);
+ }
+
+ public int getWidth() {
+ if (mWidth <= 0) {
+ mWidth = mEglCore.querySurface(mEGLSurface, EGL14.EGL_WIDTH);
+ }
+ return mWidth;
+ }
+
+ public int getHeight() {
+ if (mHeight <= 0) {
+ mHeight = mEglCore.querySurface(mEGLSurface, EGL14.EGL_HEIGHT);
+ }
+ return mHeight;
+ }
+
+ public void releaseEglSurface() {
+ mEglCore.releaseSurface(mEGLSurface);
+ mEGLSurface = EGL14.EGL_NO_SURFACE;
+ mWidth = -1;
+ mHeight = -1;
+ }
+
+ public void makeCurrent() {
+ mEglCore.makeCurrent(mEGLSurface);
+ }
+
+ public void makeCurrentReadFrom(EglSurfaceBase readSurface) {
+ mEglCore.makeCurrent(mEGLSurface, readSurface.mEGLSurface);
+ }
+
+ public boolean swapBuffers() {
+ return mEglCore.swapBuffers(mEGLSurface);
+ }
+
+ public void setPresentationTime(long nsec) {
+ mEglCore.setPresentationTime(mEGLSurface, nsec);
+ }
+
+ public void saveFrame(File file) throws IOException {
+ if (!mEglCore.isCurrent(mEGLSurface)) {
+ throw new RuntimeException("isn't current surface/context");
+ }
+ String fileName = file.toString();
+ int width = getWidth();
+ int height = getHeight();
+ IntBuffer buffer = IntBuffer.allocate(width * height);
+ GLES20.glReadPixels(0, 0, width, height, GLES20.GL_RGBA, GLES20.GL_UNSIGNED_BYTE, buffer);
+ BufferedOutputStream outputStream = null;
+ try {
+ outputStream = new BufferedOutputStream(new FileOutputStream(fileName));
+ Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
+ bitmap.copyPixelsFromBuffer(buffer);
+ bitmap.compress(Bitmap.CompressFormat.JPEG, 100, outputStream);
+ bitmap.recycle();
+ } finally {
+ if (outputStream != null)
+ outputStream.close();
+ }
+ }
+
+}
diff --git a/CameraFilter/src/main/java/com/frank/camerafilter/recorder/video/CameraVideoRecorder.java b/CameraFilter/src/main/java/com/frank/camerafilter/recorder/video/CameraVideoRecorder.java
new file mode 100644
index 00000000..5267d4eb
--- /dev/null
+++ b/CameraFilter/src/main/java/com/frank/camerafilter/recorder/video/CameraVideoRecorder.java
@@ -0,0 +1,329 @@
+package com.frank.camerafilter.recorder.video;
+
+import android.content.Context;
+import android.graphics.SurfaceTexture;
+import android.opengl.EGLContext;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
+
+import androidx.annotation.NonNull;
+
+import com.frank.camerafilter.filter.BeautyCameraFilter;
+import com.frank.camerafilter.filter.BaseFilter;
+import com.frank.camerafilter.factory.BeautyFilterFactory;
+import com.frank.camerafilter.factory.BeautyFilterType;
+import com.frank.camerafilter.recorder.egl.EglCore;
+
+import java.io.File;
+import java.io.IOException;
+import java.lang.ref.WeakReference;
+import java.nio.FloatBuffer;
+
+/**
+ * Encode a movie from frames rendered from an external texture image.
+ *
+ * The object wraps an encoder running on a dedicated thread. The various control messages
+ * may be sent from arbitrary threads (typically the app UI thread). The encoder thread
+ * manages both sides of the encoder (feeding and draining); the only external input is
+ * the GL texture.
+ *
+ * The design is complicated slightly by the need to create an EGL context that shares state
+ * with a view that gets restarted if (say) the device orientation changes. When the view
+ * in question is a GLSurfaceView, we don't have full control over the EGL context creation
+ * on that side, so we have to bend a bit backwards here.
+ *
mWeakRecorder;
+
+ public RecorderHandler(CameraVideoRecorder recorder) {
+ mWeakRecorder = new WeakReference<>(recorder);
+ }
+
+ @Override
+ public void handleMessage(@NonNull Message msg) {
+ Object obj = msg.obj;
+ CameraVideoRecorder recorder = mWeakRecorder.get();
+ if (recorder == null) {
+ return;
+ }
+
+ switch (msg.what) {
+ case MSG_START_RECORDING:
+ recorder.handlerStartRecording((RecorderConfig)obj);
+ break;
+ case MSG_STOP_RECORDING:
+ recorder.handlerStopRecording();
+ break;
+ case MSG_FRAME_AVAILABLE:
+ long timestamp = (((long) msg.arg1) << 32) |
+ (((long) msg.arg2) & 0xffffffffL);
+ recorder.handleFrameAvailable((float[]) obj, timestamp);
+ break;
+ case MSG_SET_TEXTURE_ID:
+ recorder.handleSetTexture(msg.arg1);
+ break;
+ case MSG_UPDATE_SHARED_CONTEXT:
+ recorder.handleUpdateSharedContext((EGLContext)obj);
+ break;
+ case MSG_QUIT_RECORDING:
+ Looper.myLooper().quit();
+ break;
+ default:
+ break;
+ }
+ }
+ }
+
+ private void handlerStartRecording(RecorderConfig config) {
+ prepareRecorder(
+ config.mEglContext,
+ config.mWidth,
+ config.mHeight,
+ config.mBitrate,
+ config.mOutputFile);
+ }
+
+ private void handlerStopRecording() {
+ mVideoRecorder.drainEncoder(true);
+ releaseRecorder();
+ }
+
+ private void handleFrameAvailable(float[] transform, long timestamp) {
+ mVideoRecorder.drainEncoder(false);
+ mCameraFilter.setTextureTransformMatrix(transform);
+ if (mAddFilter == null) {
+ mCameraFilter.onDrawFrame(mTextureId, glVertexBuffer, glTextureBuffer);
+ } else {
+ mAddFilter.onDrawFrame(mTextureId, glVertexBuffer, glTextureBuffer);
+ }
+ mWindowSurface.setPresentationTime(timestamp);
+ mWindowSurface.swapBuffers();
+ }
+
+ private void handleSetTexture(int id) {
+ mTextureId = id;
+ }
+
+ private void handleUpdateSharedContext(EGLContext eglContext) {
+ mWindowSurface.releaseEglSurface();
+ mCameraFilter.destroy();
+ mEglCore.release();
+
+ mEglCore = new EglCore(eglContext, EglCore.FLAG_RECORDABLE);
+ mWindowSurface.recreate(mEglCore);
+ mWindowSurface.makeCurrent();
+
+ mCameraFilter = new BeautyCameraFilter(mContext);
+ mCameraFilter.init();
+ mAddFilter = BeautyFilterFactory.getFilter(type, mContext);
+ if (mAddFilter != null) {
+ mAddFilter.init();
+ mAddFilter.onOutputSizeChanged(mVideoWidth, mVideoHeight);
+ mAddFilter.onInputSizeChanged(mPreviewWidth, mPreviewHeight);
+ }
+ }
+
+ private void prepareRecorder(EGLContext eglContext, int width, int height, int bitrate, File file) {
+ try {
+ mVideoRecorder = new VideoRecorderCore(width, height, bitrate, file);
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ mVideoWidth = width;
+ mVideoHeight = height;
+ mEglCore = new EglCore(eglContext, EglCore.FLAG_RECORDABLE);
+ mWindowSurface = new WindowEglSurface(mEglCore, mVideoRecorder.getInputSurface(), true);
+ mWindowSurface.makeCurrent();
+
+ mCameraFilter = new BeautyCameraFilter(mContext);
+ mCameraFilter.init();
+ mAddFilter = BeautyFilterFactory.getFilter(type, mContext);
+ if (mAddFilter != null) {
+ mAddFilter.init();
+ mAddFilter.onOutputSizeChanged(mVideoWidth, mVideoHeight);
+ mAddFilter.onInputSizeChanged(mPreviewWidth, mPreviewHeight);
+ }
+ }
+
+ private void releaseRecorder() {
+ mVideoRecorder.release();
+ if (mWindowSurface != null) {
+ mWindowSurface.release();
+ mWindowSurface = null;
+ }
+ if (mCameraFilter != null) {
+ mCameraFilter.destroy();
+ mCameraFilter = null;
+ }
+ if (mAddFilter != null) {
+ mAddFilter.destroy();
+ mAddFilter = null;
+ type = BeautyFilterType.NONE;
+ }
+ if (mEglCore != null) {
+ mEglCore.release();
+ mEglCore = null;
+ }
+ }
+
+ public void startRecording(RecorderConfig config) {
+ synchronized (mReadyFence) {
+ if (mRunning) {
+ return;
+ }
+ mRunning = true;
+ new Thread(this, TAG).start();
+ while (!mReady) {
+ try {
+ mReadyFence.wait();
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+ }
+ }
+ mHandler.sendMessage(mHandler.obtainMessage(MSG_START_RECORDING, config));
+ }
+
+ public void stopRecording() {
+ mHandler.sendMessage(mHandler.obtainMessage(MSG_STOP_RECORDING));
+ mHandler.sendMessage(mHandler.obtainMessage(MSG_QUIT_RECORDING));
+ }
+
+ public boolean isRecording() {
+ synchronized (mReadyFence) {
+ return mRunning;
+ }
+ }
+
+ public void updateSharedContext(EGLContext eglContext) {
+ mHandler.sendMessage(mHandler.obtainMessage(MSG_UPDATE_SHARED_CONTEXT, eglContext));
+ }
+
+ public void frameAvailable(SurfaceTexture surfaceTexture) {
+ synchronized (mReadyFence) {
+ if (!mReady)
+ return;
+ }
+ if (mTransformMatrix == null) {
+ mTransformMatrix = new float[16];
+ }
+ surfaceTexture.getTransformMatrix(mTransformMatrix);
+ long timestamp = surfaceTexture.getTimestamp();
+ if (timestamp == 0) {
+ return;
+ }
+ mHandler.sendMessage(mHandler.obtainMessage(MSG_FRAME_AVAILABLE, (int) (timestamp >> 32), (int) timestamp, mTransformMatrix));
+ }
+
+ public void setTextureId(int id) {
+ synchronized (mReadyFence) {
+ if (!mReady)
+ return;
+ }
+ mHandler.sendMessage(mHandler.obtainMessage(MSG_SET_TEXTURE_ID, id, 0, null));
+ }
+
+ @Override
+ public void run() {
+ Looper.prepare();
+ synchronized (mReadyFence) {
+ mHandler = new RecorderHandler(this);
+ mReady = true;
+ mReadyFence.notify();
+ }
+ Looper.loop();
+ synchronized (mReadyFence) {
+ mReady = false;
+ mRunning = false;
+ mHandler = null;
+ }
+ }
+
+ public void setFilter(BeautyFilterType type) {
+ this.type = type;
+ }
+
+ public void setPreviewSize(int width, int height){
+ mPreviewWidth = width;
+ mPreviewHeight = height;
+ }
+
+ public void setTextureBuffer(FloatBuffer glTextureBuffer) {
+ this.glTextureBuffer = glTextureBuffer;
+ }
+
+ public void setVertexBuffer(FloatBuffer gLVertexBuffer) {
+ this.glVertexBuffer = gLVertexBuffer;
+ }
+
+}
diff --git a/CameraFilter/src/main/java/com/frank/camerafilter/recorder/video/VideoRecorderCore.java b/CameraFilter/src/main/java/com/frank/camerafilter/recorder/video/VideoRecorderCore.java
new file mode 100644
index 00000000..80ff1543
--- /dev/null
+++ b/CameraFilter/src/main/java/com/frank/camerafilter/recorder/video/VideoRecorderCore.java
@@ -0,0 +1,121 @@
+package com.frank.camerafilter.recorder.video;
+
+import android.media.MediaCodec;
+import android.media.MediaCodecInfo;
+import android.media.MediaFormat;
+import android.media.MediaMuxer;
+import android.util.Log;
+import android.view.Surface;
+
+import java.io.File;
+import java.io.IOException;
+import java.nio.ByteBuffer;
+
+/**
+ * This class wraps up the core components used for surface-input video encoding.
+ *
+ * Once created, frames are fed to the input surface. Remember to provide the presentation
+ * time stamp, and always call drainEncoder() before swapBuffers() to ensure that the
+ * producer side doesn't get backed up.
+ *
+ * This class is not thread-safe, with one exception: it is valid to use the input surface
+ * on one thread, and drain the output on a different thread.
+ */
+public class VideoRecorderCore {
+
+ private final static String TAG = VideoRecorderCore.class.getSimpleName();
+
+ private final static int FRAME_RATE = 30;
+ private final static int IFRAME_INTERVAL = 30;
+ private final static String MIME_TYPE = "video/avc";
+ private final static int TIMEOUT_USEC = 20000;
+
+ private int mTrackIndex;
+ private boolean mMuxerStarted;
+ private final Surface mInputSurface;
+ private MediaMuxer mMediaMuxer;
+ private MediaCodec mVideoEncoder;
+ private final MediaCodec.BufferInfo mBufferInfo;
+
+ public VideoRecorderCore(int width, int height, int bitrate, File outputFile) throws IOException {
+ mBufferInfo = new MediaCodec.BufferInfo();
+ MediaFormat mediaFormat = MediaFormat.createVideoFormat(MIME_TYPE, width, height);
+ mediaFormat.setInteger(MediaFormat.KEY_COLOR_FORMAT, MediaCodecInfo.CodecCapabilities.COLOR_FormatSurface);
+ mediaFormat.setInteger(MediaFormat.KEY_BIT_RATE, bitrate);
+ mediaFormat.setInteger(MediaFormat.KEY_FRAME_RATE, FRAME_RATE);
+ mediaFormat.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, IFRAME_INTERVAL);
+
+ mVideoEncoder = MediaCodec.createEncoderByType(MIME_TYPE);
+ mVideoEncoder.configure(mediaFormat, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE);
+ mInputSurface = mVideoEncoder.createInputSurface();
+ mVideoEncoder.start();
+
+ mMediaMuxer = new MediaMuxer(outputFile.toString(), MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4);
+ mTrackIndex = -1;
+ mMuxerStarted = false;
+ }
+
+ public Surface getInputSurface() {
+ return mInputSurface;
+ }
+
+ public void drainEncoder(boolean endOfStream) {
+ if (endOfStream) {
+ mVideoEncoder.signalEndOfInputStream();
+ }
+
+ ByteBuffer[] outputBuffers = mVideoEncoder.getOutputBuffers();
+ while (true) {
+ int encodeStatus = mVideoEncoder.dequeueOutputBuffer(mBufferInfo, TIMEOUT_USEC);
+ if (encodeStatus == MediaCodec.INFO_TRY_AGAIN_LATER) {
+ if (!endOfStream) {
+ break;
+ }
+ } else if (encodeStatus == MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED) {
+ outputBuffers = mVideoEncoder.getOutputBuffers();
+ } else if (encodeStatus == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) {
+ if (mMuxerStarted) {
+ throw new RuntimeException("format has changed!");
+ }
+ MediaFormat newFormat = mVideoEncoder.getOutputFormat();
+ mTrackIndex = mMediaMuxer.addTrack(newFormat);
+ mMediaMuxer.start();
+ mMuxerStarted = true;
+ } else if (encodeStatus < 0) {
+ Log.e(TAG, "error encodeStatus=" + encodeStatus);
+ } else {
+ ByteBuffer data = outputBuffers[encodeStatus];
+ if ((mBufferInfo.flags & MediaCodec.BUFFER_FLAG_CODEC_CONFIG) != 0) {
+ mBufferInfo.size = 0;
+ }
+ if (mBufferInfo.size != 0) {
+ if (!mMuxerStarted) {
+ throw new RuntimeException("muxer hasn't started");
+ }
+ data.position(mBufferInfo.offset);
+ data.limit(mBufferInfo.offset + mBufferInfo.size);
+ mMediaMuxer.writeSampleData(mTrackIndex, data, mBufferInfo);
+ }
+ mVideoEncoder.releaseOutputBuffer(encodeStatus, false);
+ // end of stream
+ if ((mBufferInfo.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0) {
+ break;
+ }
+ }
+ }
+ }
+
+ public void release() {
+ if (mVideoEncoder != null) {
+ mVideoEncoder.stop();
+ mVideoEncoder.release();
+ mVideoEncoder = null;
+ }
+ if (mMediaMuxer != null) {
+ mMediaMuxer.stop();
+ mMediaMuxer.release();
+ mMediaMuxer = null;
+ }
+ }
+
+}
diff --git a/CameraFilter/src/main/java/com/frank/camerafilter/recorder/video/WindowEglSurface.java b/CameraFilter/src/main/java/com/frank/camerafilter/recorder/video/WindowEglSurface.java
new file mode 100644
index 00000000..4478f9af
--- /dev/null
+++ b/CameraFilter/src/main/java/com/frank/camerafilter/recorder/video/WindowEglSurface.java
@@ -0,0 +1,45 @@
+package com.frank.camerafilter.recorder.video;
+
+import android.view.Surface;
+
+import com.frank.camerafilter.recorder.egl.EglCore;
+import com.frank.camerafilter.recorder.egl.EglSurfaceBase;
+
+/**
+ * @author xufulong
+ * @date 2022/6/23 9:15 上午
+ * @desc
+ */
+public class WindowEglSurface extends EglSurfaceBase {
+
+ private Surface mSurface;
+ private boolean mReleaseSurface;
+
+ public WindowEglSurface(EglCore eglCore, Surface surface) {
+ this(eglCore, surface, false);
+ }
+
+ public WindowEglSurface(EglCore eglCore, Surface surface, boolean releaseSurface) {
+ super(eglCore);
+ createWindowSurface(surface);
+ mSurface = surface;
+ mReleaseSurface = releaseSurface;
+ }
+
+ public void release() {
+ releaseEglSurface();
+ if (mSurface != null && mReleaseSurface) {
+ mSurface.release();
+ }
+ mSurface = null;
+ }
+
+ public void recreate(EglCore newEglCore) {
+ if (mSurface == null) {
+ throw new RuntimeException("Surface is null");
+ }
+ mEglCore = newEglCore;
+ createWindowSurface(mSurface);
+ }
+
+}
diff --git a/CameraFilter/src/main/java/com/frank/camerafilter/util/OpenGLUtil.java b/CameraFilter/src/main/java/com/frank/camerafilter/util/OpenGLUtil.java
new file mode 100644
index 00000000..5eecd866
--- /dev/null
+++ b/CameraFilter/src/main/java/com/frank/camerafilter/util/OpenGLUtil.java
@@ -0,0 +1,128 @@
+package com.frank.camerafilter.util;
+
+import android.content.Context;
+import android.content.res.AssetManager;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.opengl.GLES11Ext;
+import android.opengl.GLES30;
+import android.opengl.GLUtils;
+import android.util.Log;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+
+import javax.microedition.khronos.opengles.GL10;
+
+public class OpenGLUtil {
+
+ public final static int ON_DRAWN = 1;
+ public static final int NOT_INIT = -1;
+ public static final int NO_SHADER = 0;
+ public static final int NO_TEXTURE = -1;
+
+ private static Bitmap getBitmapFromAssetFile(Context context, String name) {
+ try {
+ AssetManager assetManager = context.getResources().getAssets();
+ InputStream stream = assetManager.open(name);
+ Bitmap bitmap = BitmapFactory.decodeStream(stream);
+ stream.close();
+ return bitmap;
+ } catch (IOException e) {
+ return null;
+ }
+ }
+
+ public static int loadTexture(final Context context, final String name) {
+ if (context == null || name == null)
+ return NO_TEXTURE;
+ final int[] textures = new int[1];
+ GLES30.glGenTextures(1, textures, 0);
+ if (textures[0] == 0)
+ return NO_TEXTURE;
+ Bitmap bitmap = getBitmapFromAssetFile(context, name);
+ if (bitmap == null)
+ return NO_TEXTURE;
+ GLES30.glBindTexture(GLES30.GL_TEXTURE_2D, textures[0]);
+ GLES30.glTexParameteri(GLES30.GL_TEXTURE_2D, GLES30.GL_TEXTURE_MIN_FILTER, GLES30.GL_LINEAR);
+ GLES30.glTexParameteri(GLES30.GL_TEXTURE_2D, GLES30.GL_TEXTURE_MAG_FILTER, GLES30.GL_LINEAR);
+ GLES30.glTexParameteri(GLES30.GL_TEXTURE_2D, GLES30.GL_TEXTURE_WRAP_S, GLES30.GL_CLAMP_TO_EDGE);
+ GLES30.glTexParameteri(GLES30.GL_TEXTURE_2D, GLES30.GL_TEXTURE_WRAP_T, GLES30.GL_CLAMP_TO_EDGE);
+ GLUtils.texImage2D(GLES30.GL_TEXTURE_2D, 0, bitmap, 0);
+ bitmap.recycle();
+ return textures[0];
+ }
+
+ private static int loadShader(final String source, final int type) {
+ int shader = GLES30.glCreateShader(type);
+ GLES30.glShaderSource(shader, source);
+ GLES30.glCompileShader(shader);
+ int[] compile = new int[1];
+ GLES30.glGetShaderiv(shader, GLES30.GL_COMPILE_STATUS, compile, 0);
+ if (compile[0] <= 0) {
+ Log.e("OpenGlUtil", "Shader compile error=" + GLES30.glGetShaderInfoLog(shader));
+ return NO_SHADER;
+ }
+ return shader;
+ }
+
+ public static int loadProgram(final String vertexSource, final String fragmentSource) {
+ int vertexShader = loadShader(vertexSource, GLES30.GL_VERTEX_SHADER);
+ int fragmentShader = loadShader(fragmentSource, GLES30.GL_FRAGMENT_SHADER);
+ if (vertexShader == NO_SHADER || fragmentShader == NO_SHADER) {
+ return 0;
+ }
+ int programId = GLES30.glCreateProgram();
+ GLES30.glAttachShader(programId, vertexShader);
+ GLES30.glAttachShader(programId, fragmentShader);
+ GLES30.glLinkProgram(programId);
+ int[] linked = new int[1];
+ GLES30.glGetProgramiv(programId, GLES30.GL_LINK_STATUS, linked, 0);
+ if (linked[0] <= 0) {
+ programId = 0;
+ Log.e("OpenGlUtil", "program link error=" + GLES30.glGetProgramInfoLog(programId));
+ }
+ GLES30.glDeleteShader(vertexShader);
+ GLES30.glDeleteShader(fragmentShader);
+ return programId;
+ }
+
+ public static int getExternalOESTextureId() {
+ int[] textures = new int[1];
+ GLES30.glGenTextures(1, textures, 0);
+ GLES30.glBindTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, textures[0]);
+ GLES30.glTexParameterf(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, GL10.GL_TEXTURE_MIN_FILTER, GL10.GL_LINEAR);
+ GLES30.glTexParameterf(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, GL10.GL_TEXTURE_MAG_FILTER, GL10.GL_LINEAR);
+ GLES30.glTexParameteri(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, GL10.GL_TEXTURE_WRAP_S, GL10.GL_CLAMP_TO_EDGE);
+ GLES30.glTexParameteri(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, GL10.GL_TEXTURE_WRAP_T, GL10.GL_CLAMP_TO_EDGE);
+ return textures[0];
+ }
+
+ public static String readShaderFromSource(Context context, final int resourceId) {
+ String line;
+ StringBuilder builder = new StringBuilder();
+ InputStream inputStream = context.getResources().openRawResource(resourceId);
+ InputStreamReader reader = new InputStreamReader(inputStream);
+ BufferedReader bufferedReader = new BufferedReader(reader);
+ try {
+ while ((line = bufferedReader.readLine()) != null) {
+ builder.append(line).append("\n");
+ }
+ } catch (IOException e) {
+ return null;
+ } finally {
+ try {
+ inputStream.close();
+ reader.close();
+ bufferedReader.close();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+
+ }
+ return builder.toString();
+ }
+
+}
diff --git a/CameraFilter/src/main/java/com/frank/camerafilter/util/Rotation.java b/CameraFilter/src/main/java/com/frank/camerafilter/util/Rotation.java
new file mode 100644
index 00000000..56bec976
--- /dev/null
+++ b/CameraFilter/src/main/java/com/frank/camerafilter/util/Rotation.java
@@ -0,0 +1,36 @@
+package com.frank.camerafilter.util;
+
+public enum Rotation {
+
+ NORMAL, ROTATION_90, ROTATION_180, ROTATION_270;
+
+ public int toInt() {
+ switch (this) {
+ case NORMAL:
+ return 0;
+ case ROTATION_90:
+ return 90;
+ case ROTATION_180:
+ return 180;
+ case ROTATION_270:
+ return 270;
+ default:
+ throw new IllegalStateException("unknown rotation value...");
+ }
+ }
+
+ public static Rotation fromInt(int rotation) {
+ switch (rotation) {
+ case 0:
+ return NORMAL;
+ case 90:
+ return ROTATION_90;
+ case 180:
+ return ROTATION_180;
+ case 270:
+ return ROTATION_270;
+ default:
+ throw new IllegalStateException("unknown rotation=" +rotation);
+ }
+ }
+}
diff --git a/CameraFilter/src/main/java/com/frank/camerafilter/util/TextureRotateUtil.java b/CameraFilter/src/main/java/com/frank/camerafilter/util/TextureRotateUtil.java
new file mode 100644
index 00000000..0657433e
--- /dev/null
+++ b/CameraFilter/src/main/java/com/frank/camerafilter/util/TextureRotateUtil.java
@@ -0,0 +1,82 @@
+package com.frank.camerafilter.util;
+
+public class TextureRotateUtil {
+
+ public final static float[] TEXTURE_ROTATE_0 = {
+ 0.0f, 1.0f,
+ 1.0f, 1.0f,
+ 0.0f, 0.0f,
+ 1.0f, 0.0f
+ };
+
+ public final static float[] TEXTURE_ROTATE_90 = {
+ 1.0f, 1.0f,
+ 1.0f, 0.0f,
+ 0.0f, 1.0f,
+ 0.0f, 0.0f
+ };
+
+ public final static float[] TEXTURE_ROTATE_180 = {
+ 1.0f, 0.0f,
+ 0.0f, 0.0f,
+ 1.0f, 1.0f,
+ 0.0f, 1.0f
+ };
+
+ public final static float[] TEXTURE_ROTATE_270 = {
+ 0.0f, 0.0f,
+ 0.0f, 1.0f,
+ 1.0f, 0.0f,
+ 1.0f, 1.0f
+ };
+
+ public final static float[] VERTEX = {
+ -1.0f, -1.0f,
+ 1.0f, -1.0f,
+ -1.0f, 1.0f,
+ 1.0f, 1.0f
+ };
+
+ private TextureRotateUtil() {}
+
+ private static float flip(float value) {
+ return value == 1.0f ? 0.0f : 1.0f;
+ }
+
+ public static float[] getRotateTexture(Rotation rotation, boolean horizontalFlip, boolean verticalFlip) {
+ float[] rotateTexture;
+ switch (rotation) {
+ case ROTATION_90:
+ rotateTexture = TEXTURE_ROTATE_90;
+ break;
+ case ROTATION_180:
+ rotateTexture = TEXTURE_ROTATE_180;
+ break;
+ case ROTATION_270:
+ rotateTexture = TEXTURE_ROTATE_270;
+ break;
+ case NORMAL:
+ default:
+ rotateTexture = TEXTURE_ROTATE_0;
+ break;
+ }
+ if (horizontalFlip) {
+ rotateTexture = new float[] {
+ flip(rotateTexture[0]), rotateTexture[1],
+ flip(rotateTexture[2]), rotateTexture[3],
+ flip(rotateTexture[4]), rotateTexture[5],
+ flip(rotateTexture[6]), rotateTexture[7]
+ };
+ }
+ if (verticalFlip) {
+ rotateTexture = new float[] {
+ rotateTexture[0], flip(rotateTexture[1]),
+ rotateTexture[2], flip(rotateTexture[3]),
+ rotateTexture[4], flip(rotateTexture[5]),
+ rotateTexture[6], flip(rotateTexture[7])
+ };
+ }
+ return rotateTexture;
+ }
+
+}
diff --git a/CameraFilter/src/main/java/com/frank/camerafilter/widget/BeautyCameraView.java b/CameraFilter/src/main/java/com/frank/camerafilter/widget/BeautyCameraView.java
new file mode 100644
index 00000000..a3a4adda
--- /dev/null
+++ b/CameraFilter/src/main/java/com/frank/camerafilter/widget/BeautyCameraView.java
@@ -0,0 +1,60 @@
+package com.frank.camerafilter.widget;
+
+import android.content.Context;
+import android.opengl.GLSurfaceView;
+import android.util.AttributeSet;
+import android.view.SurfaceHolder;
+
+import com.frank.camerafilter.factory.BeautyFilterType;
+
+public class BeautyCameraView extends GLSurfaceView {
+
+ private final CameraRender mCameraRender;
+
+ public BeautyCameraView(Context context) {
+ this(context, null);
+ }
+
+ public BeautyCameraView(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ getHolder().addCallback(this);
+
+ mCameraRender = new CameraRender(this);
+ setEGLContextClientVersion(3);
+ setRenderer(mCameraRender);
+ setRenderMode(GLSurfaceView.RENDERMODE_WHEN_DIRTY);
+ }
+
+ @Override
+ public void surfaceDestroyed(SurfaceHolder holder) {
+ super.surfaceDestroyed(holder);
+ if (mCameraRender != null) {
+ mCameraRender.releaseCamera();
+ }
+ }
+
+ public void switchCamera() {
+ if (mCameraRender != null) {
+ mCameraRender.switchCamera();
+ }
+ }
+
+ public void setFilter(BeautyFilterType type) {
+ if (mCameraRender == null)
+ return;
+ mCameraRender.setFilter(type);
+ }
+
+ public void setRecording(boolean isRecording) {
+ if (mCameraRender == null)
+ return;
+ mCameraRender.setRecording(isRecording);
+ }
+
+ public boolean isRecording() {
+ if (mCameraRender == null)
+ return false;
+ return mCameraRender.isRecording();
+ }
+
+}
diff --git a/CameraFilter/src/main/java/com/frank/camerafilter/widget/CameraRender.java b/CameraFilter/src/main/java/com/frank/camerafilter/widget/CameraRender.java
new file mode 100644
index 00000000..55b110ed
--- /dev/null
+++ b/CameraFilter/src/main/java/com/frank/camerafilter/widget/CameraRender.java
@@ -0,0 +1,251 @@
+package com.frank.camerafilter.widget;
+
+import android.graphics.SurfaceTexture;
+import android.hardware.Camera;
+import android.opengl.EGL14;
+import android.opengl.GLES30;
+import android.opengl.GLSurfaceView;
+import android.os.Environment;
+
+import com.frank.camerafilter.camera.CameraManager;
+import com.frank.camerafilter.factory.BeautyFilterFactory;
+import com.frank.camerafilter.factory.BeautyFilterType;
+import com.frank.camerafilter.filter.BeautyCameraFilter;
+import com.frank.camerafilter.filter.BaseFilter;
+import com.frank.camerafilter.recorder.video.CameraVideoRecorder;
+import com.frank.camerafilter.util.OpenGLUtil;
+import com.frank.camerafilter.util.Rotation;
+import com.frank.camerafilter.util.TextureRotateUtil;
+
+import java.io.File;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.nio.FloatBuffer;
+
+import javax.microedition.khronos.egl.EGLConfig;
+import javax.microedition.khronos.opengles.GL10;
+
+public class CameraRender implements GLSurfaceView.Renderer, SurfaceTexture.OnFrameAvailableListener {
+
+ protected BaseFilter mFilter;
+
+ private SurfaceTexture surfaceTexture;
+ private BeautyCameraFilter cameraFilter;
+
+ private final CameraManager cameraManager;
+
+ protected int mTextureId = OpenGLUtil.NO_TEXTURE;
+
+ protected FloatBuffer mVertexBuffer;
+
+ protected FloatBuffer mTextureBuffer;
+
+ protected int mImageWidth, mImageHeight;
+
+ protected int mSurfaceWidth, mSurfaceHeight;
+ private final float[] mMatrix = new float[16];
+
+ private final BeautyCameraView mCameraView;
+
+ private final File outputFile;
+ private int recordStatus;
+ protected boolean recordEnable;
+ private final CameraVideoRecorder videoRecorder;
+
+ private final static int RECORDING_OFF = 0;
+ private final static int RECORDING_ON = 1;
+ private final static int RECORDING_RESUME = 2;
+
+ private static final int videoBitrate = 6 * 1024 * 1024;
+ private static final String videoName = "camera_record.mp4";
+ private static final String videoPath = Environment.getExternalStorageDirectory().getPath();
+
+ public CameraRender(BeautyCameraView cameraView) {
+ mCameraView = cameraView;
+
+ cameraManager = new CameraManager();
+ mVertexBuffer = ByteBuffer.allocateDirect(TextureRotateUtil.VERTEX.length * 4)
+ .order(ByteOrder.nativeOrder())
+ .asFloatBuffer();
+ mVertexBuffer.put(TextureRotateUtil.VERTEX).position(0);
+ mTextureBuffer = ByteBuffer.allocateDirect(TextureRotateUtil.TEXTURE_ROTATE_0.length * 4)
+ .order(ByteOrder.nativeOrder())
+ .asFloatBuffer();
+ mTextureBuffer.put(TextureRotateUtil.TEXTURE_ROTATE_0).position(0);
+
+ recordEnable = false;
+ recordStatus = RECORDING_OFF;
+ videoRecorder = new CameraVideoRecorder(mCameraView.getContext());
+ outputFile = new File(videoPath, videoName);
+ }
+
+ private void openCamera() {
+ if (cameraManager.getCamera() == null)
+ cameraManager.openCamera();
+ Camera.Size size = cameraManager.getPreviewSize();
+ // rotation=90 or rotation=270, we need to exchange width and height
+ if (cameraManager.getOrientation() == 90 || cameraManager.getOrientation() == 270) {
+ mImageWidth = size.height;
+ mImageHeight = size.width;
+ } else {
+ mImageWidth = size.width;
+ mImageHeight = size.height;
+ }
+ cameraFilter.onInputSizeChanged(mImageWidth, mImageHeight);
+ adjustSize(cameraManager.getOrientation(), cameraManager.isFront(), true);
+ }
+
+ @Override
+ public void onSurfaceCreated(GL10 gl10, EGLConfig eglConfig) {
+ GLES30.glDisable(GL10.GL_DITHER);
+ GLES30.glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
+ GLES30.glEnable(GL10.GL_CULL_FACE);
+ GLES30.glEnable(GL10.GL_DEPTH_TEST);
+
+ cameraFilter = new BeautyCameraFilter(mCameraView.getContext());
+ cameraFilter.init();
+ mTextureId = OpenGLUtil.getExternalOESTextureId();
+ if (mTextureId != OpenGLUtil.NO_TEXTURE) {
+ surfaceTexture = new SurfaceTexture(mTextureId);
+ surfaceTexture.setOnFrameAvailableListener(this);
+ }
+
+ openCamera();
+ }
+
+ @Override
+ public void onSurfaceChanged(GL10 gl10, int width, int height) {
+ GLES30.glViewport(0, 0, width, height);
+ mSurfaceWidth = width;
+ mSurfaceHeight = height;
+ cameraManager.startPreview(surfaceTexture);
+ onFilterChanged();
+ }
+
+ @Override
+ public void onDrawFrame(GL10 gl10) {
+ GLES30.glClear(GLES30.GL_COLOR_BUFFER_BIT | GLES30.GL_DEPTH_BUFFER_BIT);
+ GLES30.glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
+
+ surfaceTexture.updateTexImage();
+
+ surfaceTexture.getTransformMatrix(mMatrix);
+ cameraFilter.setTextureTransformMatrix(mMatrix);
+ int id = mTextureId;
+ if (mFilter == null) {
+ cameraFilter.onDrawFrame(mTextureId, mVertexBuffer, mTextureBuffer);
+ } else {
+ id = cameraFilter.onDrawToTexture(mTextureId);
+ mFilter.onDrawFrame(id, mVertexBuffer, mTextureBuffer);
+ }
+
+ onRecordVideo(id);
+ }
+
+ @Override
+ public void onFrameAvailable(SurfaceTexture surfaceTexture) {
+ mCameraView.requestRender();
+ }
+
+ public void adjustSize(int rotation, boolean horizontalFlip, boolean verticalFlip) {
+ float[] vertexData = TextureRotateUtil.VERTEX;
+ float[] textureData = TextureRotateUtil.getRotateTexture(Rotation.fromInt(rotation),
+ horizontalFlip, verticalFlip);
+
+ mVertexBuffer.clear();
+ mVertexBuffer.put(vertexData).position(0);
+ mTextureBuffer.clear();
+ mTextureBuffer.put(textureData).position(0);
+
+ }
+
+ public void switchCamera() {
+ if (cameraManager != null) {
+ cameraManager.switchCamera();
+ }
+ }
+
+ public void releaseCamera() {
+ if (cameraManager != null) {
+ cameraManager.releaseCamera();
+ }
+ }
+
+ private void onRecordVideo(int textureId) {
+ if (recordEnable) {
+ switch (recordStatus) {
+ case RECORDING_OFF:
+ videoRecorder.setPreviewSize(mImageWidth, mImageHeight);
+ videoRecorder.setTextureBuffer(mTextureBuffer);
+ videoRecorder.setVertexBuffer(mVertexBuffer);
+ videoRecorder.startRecording(new CameraVideoRecorder.RecorderConfig(
+ mImageWidth,
+ mImageHeight,
+ videoBitrate,
+ outputFile,
+ EGL14.eglGetCurrentContext()));
+ recordStatus = RECORDING_ON;
+ break;
+ case RECORDING_RESUME:
+ videoRecorder.updateSharedContext(EGL14.eglGetCurrentContext());
+ recordStatus = RECORDING_ON;
+ break;
+ case RECORDING_ON:
+ break;
+ default:
+ throw new RuntimeException("unknown status " + recordStatus);
+ }
+ } else {
+ switch (recordStatus) {
+ case RECORDING_ON:
+ case RECORDING_RESUME:
+ videoRecorder.stopRecording();
+ recordStatus = RECORDING_OFF;
+ break;
+ case RECORDING_OFF:
+ break;
+ default:
+ throw new RuntimeException("unknown status " + recordStatus);
+ }
+ }
+ videoRecorder.setTextureId(textureId);
+ videoRecorder.frameAvailable(surfaceTexture);
+ }
+
+ public void setRecording(boolean isRecording) {
+ recordEnable = isRecording;
+ }
+
+ public boolean isRecording() {
+ return recordEnable;
+ }
+
+ public void setFilter(final BeautyFilterType type) {
+ mCameraView.queueEvent(new Runnable() {
+ @Override
+ public void run() {
+ if (mFilter != null)
+ mFilter.destroy();
+ mFilter = null;
+ mFilter = BeautyFilterFactory.getFilter(type, mCameraView.getContext());
+ if (mFilter != null)
+ mFilter.init();
+ onFilterChanged();
+ }
+ });
+ mCameraView.requestRender();
+ }
+
+ public void onFilterChanged() {
+ if (mFilter != null) {
+ mFilter.onInputSizeChanged(mImageWidth, mImageHeight);
+ mFilter.onOutputSizeChanged(mSurfaceWidth, mSurfaceHeight);
+ }
+ cameraFilter.onOutputSizeChanged(mSurfaceWidth, mSurfaceHeight);
+ if (mFilter != null)
+ cameraFilter.initFrameBuffer(mImageWidth, mImageHeight);
+ else
+ cameraFilter.destroyFrameBuffer();
+ }
+
+}
diff --git a/CameraFilter/src/main/res/raw/breath_circle.glsl b/CameraFilter/src/main/res/raw/breath_circle.glsl
new file mode 100644
index 00000000..0c0ac664
--- /dev/null
+++ b/CameraFilter/src/main/res/raw/breath_circle.glsl
@@ -0,0 +1,17 @@
+precision mediump float;
+
+varying highp vec2 textureCoordinate;
+
+uniform sampler2D inputImageTexture;
+uniform vec2 uCenter;
+uniform float uInnerRadius;
+uniform float uOuterRadius;
+
+void main() {
+ vec3 textureColor = texture2D(inputImageTexture, textureCoordinate).rgb;
+
+ float dist = distance(textureCoordinate, uCenter);
+ float scale = clamp(1.0 - (dist - uInnerRadius) / (uOuterRadius - uInnerRadius), 0.0, 1.0);
+
+ gl_FragColor = vec4(textureColor.r * scale, textureColor.g * scale, textureColor.b * scale, 1.0);
+}
\ No newline at end of file
diff --git a/CameraFilter/src/main/res/raw/brightness.glsl b/CameraFilter/src/main/res/raw/brightness.glsl
new file mode 100644
index 00000000..9d98d772
--- /dev/null
+++ b/CameraFilter/src/main/res/raw/brightness.glsl
@@ -0,0 +1,12 @@
+precision mediump float;
+
+varying vec2 textureCoordinate;
+
+uniform sampler2D inputImageTexture;
+uniform float brightness;
+
+void main() {
+ vec3 textureColor = texture2D(inputImageTexture, textureCoordinate).rgb;
+
+ gl_FragColor = vec4(textureColor.rgb + vec3(brightness), 1.0);
+}
\ No newline at end of file
diff --git a/CameraFilter/src/main/res/raw/contrast.glsl b/CameraFilter/src/main/res/raw/contrast.glsl
new file mode 100644
index 00000000..dbebb5d9
--- /dev/null
+++ b/CameraFilter/src/main/res/raw/contrast.glsl
@@ -0,0 +1,14 @@
+precision mediump float;
+
+varying vec2 textureCoordinate;
+
+uniform sampler2D inputImageTexture;
+uniform float contrast;
+
+const vec3 halfColor = vec3(0.5);
+
+void main() {
+ vec3 textureColor = texture2D(inputImageTexture, textureCoordinate).rgb;
+ vec3 outputColor = (textureColor - halfColor) * contrast + halfColor;
+ gl_FragColor = vec4(outputColor, 1.0);
+}
\ No newline at end of file
diff --git a/CameraFilter/src/main/res/raw/default_fragment.glsl b/CameraFilter/src/main/res/raw/default_fragment.glsl
new file mode 100644
index 00000000..e280bd82
--- /dev/null
+++ b/CameraFilter/src/main/res/raw/default_fragment.glsl
@@ -0,0 +1,43 @@
+#extension GL_OES_EGL_image_external : require
+
+precision mediump float;
+
+varying mediump vec2 textureCoordinate;
+
+uniform samplerExternalOES inputImageTexture;
+
+void main(){
+ vec2 xy = textureCoordinate.xy;
+ // two screen(0.25~0.75)
+// if (xy.x <= 0.5) {
+// xy.x += 0.25;
+// } else {
+// xy.x -= 0.25;
+// }
+ // four screen
+// if (xy.x <= 0.5) {
+// xy.x = xy.x * 2.0;
+// } else {
+// xy.x = (xy.x - 0.5) * 2.0;
+// }
+// if (xy.y <= 0.5) {
+// xy.y = xy.y * 2.0;
+// } else {
+// xy.y = (xy.y - 0.5) * 2.0;
+// }
+ // white black
+// const vec3 weight = vec3(0.3, 0.59, 0.11);
+// float gray = dot(textureColor.rgb, weight);
+ // invert
+// 1.0 - textureColor.rgb
+ // mirror
+// if (xy.x <= 0.5) {
+// xy.x += 0.25;
+// } else {
+// xy.x -= 0.25;
+// xy.x = 1.0 - xy.x;
+// }
+
+ vec3 textureColor = texture2D(inputImageTexture, xy).rgb;
+ gl_FragColor = vec4(textureColor.rgb,1.0);
+}
\ No newline at end of file
diff --git a/Live/src/main/res/raw/vertex.glsl b/CameraFilter/src/main/res/raw/default_vertex.glsl
similarity index 53%
rename from Live/src/main/res/raw/vertex.glsl
rename to CameraFilter/src/main/res/raw/default_vertex.glsl
index da856356..6349d0fa 100644
--- a/Live/src/main/res/raw/vertex.glsl
+++ b/CameraFilter/src/main/res/raw/default_vertex.glsl
@@ -1,11 +1,11 @@
attribute vec4 position;
attribute vec4 inputTextureCoordinate;
-varying vec2 textureCoordinate;
-
uniform mat4 textureTransform;
+varying vec2 textureCoordinate;
-void main() {
- textureCoordinate = (textureTransform * inputTextureCoordinate).xy;
- gl_Position = position;
+void main()
+{
+ textureCoordinate = (textureTransform * inputTextureCoordinate).xy;
+ gl_Position = position;
}
diff --git a/CameraFilter/src/main/res/raw/frag_gaussian_blur.glsl b/CameraFilter/src/main/res/raw/frag_gaussian_blur.glsl
new file mode 100644
index 00000000..36ddeeb6
--- /dev/null
+++ b/CameraFilter/src/main/res/raw/frag_gaussian_blur.glsl
@@ -0,0 +1,34 @@
+precision mediump float;
+
+const int GAUSSIAN_SAMPLES = 9;
+
+varying vec2 textureCoordinate;
+varying vec2 blurCoordinates[GAUSSIAN_SAMPLES];
+
+uniform vec2 blurCenter;
+uniform float blurRadius;
+uniform float aspectRatio;
+uniform sampler2D inputImageTexture;
+
+void main() {
+ vec2 textureCoordinateToUse = vec2(textureCoordinate.x, (textureCoordinate.y * aspectRatio + 0.5 - 0.5 * aspectRatio));
+ float dist = distance(blurCenter, textureCoordinateToUse);
+
+ if (dist < blurRadius) {
+ vec4 sum = vec4(0.0);
+
+ sum += texture2D(inputImageTexture, blurCoordinates[0]) * 0.05;
+ sum += texture2D(inputImageTexture, blurCoordinates[1]) * 0.09;
+ sum += texture2D(inputImageTexture, blurCoordinates[2]) * 0.12;
+ sum += texture2D(inputImageTexture, blurCoordinates[3]) * 0.15;
+ sum += texture2D(inputImageTexture, blurCoordinates[4]) * 0.18;
+ sum += texture2D(inputImageTexture, blurCoordinates[5]) * 0.15;
+ sum += texture2D(inputImageTexture, blurCoordinates[6]) * 0.12;
+ sum += texture2D(inputImageTexture, blurCoordinates[7]) * 0.09;
+ sum += texture2D(inputImageTexture, blurCoordinates[8]) * 0.05;
+
+ gl_FragColor = sum;
+ } else {
+ gl_FragColor = texture2D(inputImageTexture, textureCoordinate);
+ }
+}
\ No newline at end of file
diff --git a/CameraFilter/src/main/res/raw/hue.glsl b/CameraFilter/src/main/res/raw/hue.glsl
new file mode 100644
index 00000000..de084c29
--- /dev/null
+++ b/CameraFilter/src/main/res/raw/hue.glsl
@@ -0,0 +1,43 @@
+precision highp float;
+varying highp vec2 textureCoordinate;
+
+uniform sampler2D inputImageTexture;
+uniform mediump float hueAdjust;
+const highp vec4 kRGBToYPrime = vec4 (0.299, 0.587, 0.114, 0.0);
+const highp vec4 kRGBToI = vec4 (0.595716, -0.274453, -0.321263, 0.0);
+const highp vec4 kRGBToQ = vec4 (0.211456, -0.522591, 0.31135, 0.0);
+
+const highp vec4 kYIQToR = vec4 (1.0, 0.9563, 0.6210, 0.0);
+const highp vec4 kYIQToG = vec4 (1.0, -0.2721, -0.6474, 0.0);
+const highp vec4 kYIQToB = vec4 (1.0, -1.1070, 1.7046, 0.0);
+
+void main ()
+{
+ // Sample the input pixel
+ highp vec4 color = texture2D(inputImageTexture, textureCoordinate);
+
+ // Convert to YIQ
+ highp float YPrime = dot (color, kRGBToYPrime);
+ highp float I = dot (color, kRGBToI);
+ highp float Q = dot (color, kRGBToQ);
+
+ // Calculate the hue and chroma
+ highp float hue = atan (Q, I);
+ highp float chroma = sqrt (I * I + Q * Q);
+
+ // Make the user's adjustments
+ hue += (-hueAdjust); //why negative rotation?
+
+ // Convert back to YIQ
+ Q = chroma * sin (hue);
+ I = chroma * cos (hue);
+
+ // Convert back to RGB
+ highp vec4 yIQ = vec4 (YPrime, I, Q, 0.0);
+ color.r = dot (yIQ, kYIQToR);
+ color.g = dot (yIQ, kYIQToG);
+ color.b = dot (yIQ, kYIQToB);
+
+ // Save the result
+ gl_FragColor = color;
+}
\ No newline at end of file
diff --git a/CameraFilter/src/main/res/raw/overlay.glsl b/CameraFilter/src/main/res/raw/overlay.glsl
new file mode 100644
index 00000000..5e14ebd4
--- /dev/null
+++ b/CameraFilter/src/main/res/raw/overlay.glsl
@@ -0,0 +1,14 @@
+precision mediump float;
+
+varying highp vec2 textureCoordinate;
+
+uniform sampler2D inputImageTexture;
+uniform sampler2D overlayTexture;
+
+void main()
+{
+ vec4 textureColor = texture2D(inputImageTexture, textureCoordinate);
+ vec4 overlayColor = texture2D(overlayTexture, textureCoordinate);
+
+ gl_FragColor = mix(textureColor, overlayColor, overlayColor.a);
+}
\ No newline at end of file
diff --git a/CameraFilter/src/main/res/raw/saturation.glsl b/CameraFilter/src/main/res/raw/saturation.glsl
new file mode 100644
index 00000000..446dbc75
--- /dev/null
+++ b/CameraFilter/src/main/res/raw/saturation.glsl
@@ -0,0 +1,16 @@
+precision mediump float;
+
+varying vec2 textureCoordinate;
+
+uniform sampler2D inputImageTexture;
+uniform float saturation;
+
+const vec3 lumaWeight = vec3(0.2125, 0.7154, 0.0721);
+
+void main() {
+ vec3 textureColor = texture2D(inputImageTexture, textureCoordinate).rgb;
+ float luma = dot(textureColor, lumaWeight);
+ vec3 lumaColor = vec3(luma);
+ vec3 outputColor = mix(lumaColor, textureColor, saturation);
+ gl_FragColor = vec4(outputColor, 1.0);
+}
\ No newline at end of file
diff --git a/CameraFilter/src/main/res/raw/sharpen_fragment.glsl b/CameraFilter/src/main/res/raw/sharpen_fragment.glsl
new file mode 100644
index 00000000..b84a001e
--- /dev/null
+++ b/CameraFilter/src/main/res/raw/sharpen_fragment.glsl
@@ -0,0 +1,23 @@
+precision mediump float;
+
+varying vec2 textureCoordinate;
+varying vec2 leftTextureCoordinate;
+varying vec2 rightTextureCoordinate;
+varying vec2 topTextureCoordinate;
+varying vec2 bottomTextureCoordinate;
+varying float centerMultiplier;
+varying float edgeMultiplier;
+
+uniform sampler2D inputImageTexture;
+
+void main() {
+ vec3 textureColor = texture2D(inputImageTexture, textureCoordinate).rgb;
+ vec3 leftTextureColor = texture2D(inputImageTexture, leftTextureCoordinate).rgb;
+ vec3 rightTextureColor = texture2D(inputImageTexture, rightTextureCoordinate).rgb;
+ vec3 topTextureColor = texture2D(inputImageTexture, topTextureCoordinate).rgb;
+ vec3 bottomTextureColor = texture2D(inputImageTexture, bottomTextureCoordinate).rgb;
+
+ gl_FragColor = vec4((textureColor * centerMultiplier -
+ ((leftTextureColor+rightTextureColor+topTextureColor+bottomTextureColor)* edgeMultiplier)),
+ texture2D(inputImageTexture, bottomTextureCoordinate).w);
+}
\ No newline at end of file
diff --git a/Live/src/main/res/raw/vertex_sharpen.glsl b/CameraFilter/src/main/res/raw/sharpen_vertex.glsl
similarity index 57%
rename from Live/src/main/res/raw/vertex_sharpen.glsl
rename to CameraFilter/src/main/res/raw/sharpen_vertex.glsl
index faec16eb..b8e4a9ef 100644
--- a/Live/src/main/res/raw/vertex_sharpen.glsl
+++ b/CameraFilter/src/main/res/raw/sharpen_vertex.glsl
@@ -1,10 +1,8 @@
+precision mediump float;
+
attribute vec4 position;
attribute vec4 inputTextureCoordinate;
-uniform float imageWidthFactor;
-uniform float imageHeightFactor;
-uniform float sharpness;
-
varying vec2 textureCoordinate;
varying vec2 leftTextureCoordinate;
varying vec2 rightTextureCoordinate;
@@ -13,19 +11,21 @@ varying vec2 bottomTextureCoordinate;
varying float centerMultiplier;
varying float edgeMultiplier;
+uniform float imageWidthFactor;
+uniform float imageHeightFactor;
+uniform float sharpness;
void main() {
gl_Position = position;
+ vec2 width = vec2(imageWidthFactor, 0.0);
+ vec2 height = vec2(0.0, imageHeightFactor);
- mediump vec2 widthStep = vec2(imageWidthFactor, 0.0);
- mediump vec2 heightStep = vec2(0.0, imageHeightFactor);
-
- textureCoordinate = inputTextureCoordinate.xy;
- leftTextureCoordinate = inputTextureCoordinate.xy - widthStep;
- rightTextureCoordinate = inputTextureCoordinate.xy + widthStep;
- topTextureCoordinate = inputTextureCoordinate.xy + heightStep;
- bottomTextureCoordinate = inputTextureCoordinate.xy - heightStep;
+ textureCoordinate = inputTextureCoordinate.xy;
+ leftTextureCoordinate = inputTextureCoordinate.xy - width;
+ rightTextureCoordinate = inputTextureCoordinate.xy + width;
+ topTextureCoordinate = inputTextureCoordinate.xy + height;
+ bottomTextureCoordinate = inputTextureCoordinate.xy - height;
centerMultiplier = 1.0 + 4.0 * sharpness;
- edgeMultiplier = sharpness;
+ edgeMultiplier = sharpness;
}
\ No newline at end of file
diff --git a/CameraFilter/src/main/res/raw/sketch.glsl b/CameraFilter/src/main/res/raw/sketch.glsl
new file mode 100644
index 00000000..5239dfee
--- /dev/null
+++ b/CameraFilter/src/main/res/raw/sketch.glsl
@@ -0,0 +1,43 @@
+varying highp vec2 textureCoordinate;
+precision mediump float;
+
+uniform sampler2D inputImageTexture;
+uniform vec2 singleStepOffset;
+uniform float strength;
+
+const highp vec3 W = vec3(0.299, 0.587, 0.114);
+
+
+void main()
+{
+ float threshold = 0.0;
+ //pic1
+ vec4 oralColor = texture2D(inputImageTexture, textureCoordinate);
+ //pic2
+ vec3 maxValue = vec3(0., 0., 0.);
+
+ for (int i = -2; i<=2; i++)
+ {
+ for (int j = -2; j<=2; j++)
+ {
+ vec4 tempColor = texture2D(inputImageTexture, textureCoordinate+singleStepOffset*vec2(i, j));
+ maxValue.r = max(maxValue.r, tempColor.r);
+ maxValue.g = max(maxValue.g, tempColor.g);
+ maxValue.b = max(maxValue.b, tempColor.b);
+ threshold += dot(tempColor.rgb, W);
+ }
+ }
+ //pic3
+ float gray1 = dot(oralColor.rgb, W);
+ //pic4
+ float gray2 = dot(maxValue, W);
+ //pic5
+ float contour = gray1 / gray2;
+
+ threshold = threshold / 25.;
+ float alpha = max(1.0, gray1>threshold?1.0:(gray1/threshold));
+
+ float result = contour * alpha + (1.0-alpha)*gray1;
+
+ gl_FragColor = vec4(vec3(result, result, result), oralColor.w);
+}
\ No newline at end of file
diff --git a/CameraFilter/src/main/res/raw/vert_gaussian_blur.glsl b/CameraFilter/src/main/res/raw/vert_gaussian_blur.glsl
new file mode 100644
index 00000000..cbe1d607
--- /dev/null
+++ b/CameraFilter/src/main/res/raw/vert_gaussian_blur.glsl
@@ -0,0 +1,27 @@
+attribute vec4 position;
+attribute vec4 inputTextureCoordinate;
+
+const int GAUSSIAN_SAMPLES = 9;
+
+varying vec2 textureCoordinate;
+varying vec2 blurCoordinates[GAUSSIAN_SAMPLES];
+
+uniform float textureWidthOffset;
+uniform float textureHeightOffset;
+
+void main() {
+ gl_Position = position;
+ textureCoordinate = inputTextureCoordinate.xy;
+
+ // Calculate the position of blur
+ vec2 blurStep;
+ int multiplier = 0;
+ vec2 singleStepOffset = vec2(textureWidthOffset, textureHeightOffset);
+
+ for (int i = 0; i < GAUSSIAN_SAMPLES; i++) {
+ multiplier = (i - ((GAUSSIAN_SAMPLES - 1) / 2));
+ // Blur in x (horizontal)
+ blurStep = float(multiplier) * singleStepOffset;
+ blurCoordinates[i] = inputTextureCoordinate.xy + blurStep;
+ }
+}
\ No newline at end of file
diff --git a/CameraFilter/src/main/res/raw/whitebalance.glsl b/CameraFilter/src/main/res/raw/whitebalance.glsl
new file mode 100644
index 00000000..5a6557cb
--- /dev/null
+++ b/CameraFilter/src/main/res/raw/whitebalance.glsl
@@ -0,0 +1,26 @@
+uniform sampler2D inputImageTexture;
+varying highp vec2 textureCoordinate;
+
+uniform lowp float temperature;
+uniform lowp float tint;
+
+const lowp vec3 warmFilter = vec3(0.93, 0.54, 0.0);
+
+const mediump mat3 RGBtoYIQ = mat3(0.299, 0.587, 0.114, 0.596, -0.274, -0.322, 0.212, -0.523, 0.311);
+const mediump mat3 YIQtoRGB = mat3(1.0, 0.956, 0.621, 1.0, -0.272, -0.647, 1.0, -1.105, 1.702);
+
+void main()
+{
+ lowp vec4 source = texture2D(inputImageTexture, textureCoordinate);
+
+ mediump vec3 yiq = RGBtoYIQ * source.rgb; //adjusting tint
+ yiq.b = clamp(yiq.b + tint*0.5226*0.1, -0.5226, 0.5226);
+ lowp vec3 rgb = YIQtoRGB * yiq;
+
+ lowp vec3 processed = vec3(
+ (rgb.r < 0.5 ? (2.0 * rgb.r * warmFilter.r) : (1.0 - 2.0 * (1.0 - rgb.r) * (1.0 - warmFilter.r))), //adjusting temperature
+ (rgb.g < 0.5 ? (2.0 * rgb.g * warmFilter.g) : (1.0 - 2.0 * (1.0 - rgb.g) * (1.0 - warmFilter.g))),
+ (rgb.b < 0.5 ? (2.0 * rgb.b * warmFilter.b) : (1.0 - 2.0 * (1.0 - rgb.b) * (1.0 - warmFilter.b))));
+
+ gl_FragColor = vec4(mix(rgb, processed, temperature), source.a);
+}
\ No newline at end of file
diff --git a/Live/CMakeLists.txt b/Live/CMakeLists.txt
index d34f9d06..2f08e06d 100644
--- a/Live/CMakeLists.txt
+++ b/Live/CMakeLists.txt
@@ -3,7 +3,10 @@
# Sets the minimum version of CMake required to build the native library.
-cmake_minimum_required(VERSION 3.4.1)
+cmake_minimum_required(VERSION 3.10.2)
+
+project(live)
+
set(distribution_DIR ${CMAKE_SOURCE_DIR}/../../../../libs)
add_library(faac
@@ -11,30 +14,32 @@ add_library(faac
IMPORTED)
set_target_properties(faac
PROPERTIES IMPORTED_LOCATION
- ../../../../libs/armeabi-v7a/libfaac.a)
+ ../../../../libs/${CMAKE_ANDROID_ARCH_ABI}/libfaac.a)
-add_library(rtmp
- STATIC
- IMPORTED)
-set_target_properties(rtmp
- PROPERTIES IMPORTED_LOCATION
- ../../../../libs/armeabi-v7a/librtmp.a)
+add_subdirectory(src/main/cpp/rtmp)
+#add_library(rtmp
+# STATIC
+# IMPORTED)
+#set_target_properties(rtmp
+# PROPERTIES IMPORTED_LOCATION
+# ../../../../libs/${CMAKE_ANDROID_ARCH_ABI}/librtmp.a)
add_library(x264
STATIC
IMPORTED)
set_target_properties(x264
PROPERTIES IMPORTED_LOCATION
- ../../../../libs/armeabi-v7a/libx264.a)
+ ../../../../libs/${CMAKE_ANDROID_ARCH_ABI}/libx264.a)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=gnu++11")
-include_directories(main/cpp/include)
+include_directories(src/main/cpp/include)
add_library(live
- SHARED
- src/main/cpp/live.c
- src/main/cpp/queue.c)
+ SHARED
+ src/main/cpp/AudioStream.cpp
+ src/main/cpp/VideoStream.cpp
+ src/main/cpp/RtmpPusher.cpp)
find_library( log-lib
log )
diff --git a/Live/build.gradle b/Live/build.gradle
index e6d994b3..821326e3 100644
--- a/Live/build.gradle
+++ b/Live/build.gradle
@@ -1,22 +1,22 @@
apply plugin: 'com.android.library'
android {
- compileSdkVersion 25
- buildToolsVersion "25.0.2"
+ compileSdkVersion rootProject.ext.compileSdkVersion
+ buildToolsVersion rootProject.ext.buildToolsVersion
+ namespace "com.frank.live"
+
defaultConfig {
-// applicationId "com.frank.live"
- minSdkVersion 15
- targetSdkVersion 25
- versionCode 1
- versionName "1.0"
- testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
+ minSdkVersion rootProject.ext.minSdkVersion
+ targetSdkVersion rootProject.ext.targetSdkVersion
+ versionCode rootProject.ext.versionCode
+ versionName rootProject.ext.versionName
externalNativeBuild {
cmake {
cppFlags ""
}
}
ndk{
- abiFilters "armeabi-v7a"
+ abiFilters /*"armeabi-v7a",*/ "arm64-v8a"
}
}
buildTypes {
@@ -33,11 +33,6 @@ android {
}
dependencies {
- compile fileTree(dir: 'libs', include: ['*.jar'])
- androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
- exclude group: 'com.android.support', module: 'support-annotations'
- })
- compile 'com.android.support:appcompat-v7:25.3.1'
- compile 'com.android.support.constraint:constraint-layout:1.0.2'
- testCompile 'junit:junit:4.12'
+ implementation fileTree(dir: 'libs', include: ['*.jar'])
+ implementation "androidx.appcompat:appcompat:$rootProject.appcompatVersion"
}
diff --git a/Live/libs/arm64-v8a/libfaac.a b/Live/libs/arm64-v8a/libfaac.a
new file mode 100644
index 00000000..c56ae005
Binary files /dev/null and b/Live/libs/arm64-v8a/libfaac.a differ
diff --git a/Live/libs/arm64-v8a/libx264.a b/Live/libs/arm64-v8a/libx264.a
new file mode 100644
index 00000000..2b5d4466
Binary files /dev/null and b/Live/libs/arm64-v8a/libx264.a differ
diff --git a/Live/libs/armeabi-v7a/libfaac.a b/Live/libs/armeabi-v7a/libfaac.a
index f6d4452c..0a9aeba1 100644
Binary files a/Live/libs/armeabi-v7a/libfaac.a and b/Live/libs/armeabi-v7a/libfaac.a differ
diff --git a/Live/libs/armeabi-v7a/librtmp.a b/Live/libs/armeabi-v7a/librtmp.a
deleted file mode 100644
index c9222af0..00000000
Binary files a/Live/libs/armeabi-v7a/librtmp.a and /dev/null differ
diff --git a/Live/libs/armeabi-v7a/libx264.a b/Live/libs/armeabi-v7a/libx264.a
index b7c90f06..795f0d50 100644
Binary files a/Live/libs/armeabi-v7a/libx264.a and b/Live/libs/armeabi-v7a/libx264.a differ
diff --git a/Live/proguard-rules.pro b/Live/proguard-rules.pro
index 316ea847..b88bca25 100644
--- a/Live/proguard-rules.pro
+++ b/Live/proguard-rules.pro
@@ -23,3 +23,9 @@
# If you keep the line number information, uncomment this to
# hide the original source file name.
#-renamesourcefileattribute SourceFile
+-keepclasseswithmembernames class * {
+ native ;
+}
+
+-keep public class com.frank.live.LivePusherNew {
+}
\ No newline at end of file
diff --git a/Live/src/androidTest/java/com/frank/live/ExampleInstrumentedTest.java b/Live/src/androidTest/java/com/frank/live/ExampleInstrumentedTest.java
deleted file mode 100644
index 68f66e28..00000000
--- a/Live/src/androidTest/java/com/frank/live/ExampleInstrumentedTest.java
+++ /dev/null
@@ -1,26 +0,0 @@
-package com.frank.live;
-
-import android.content.Context;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.runner.AndroidJUnit4;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import static org.junit.Assert.*;
-
-/**
- * Instrumentation test, which will execute on an Android device.
- *
- * @see Testing documentation
- */
-@RunWith(AndroidJUnit4.class)
-public class ExampleInstrumentedTest {
- @Test
- public void useAppContext() throws Exception {
- // Context of the app under test.
- Context appContext = InstrumentationRegistry.getTargetContext();
-
- assertEquals("com.frank.pusher", appContext.getPackageName());
- }
-}
diff --git a/Live/src/main/AndroidManifest.xml b/Live/src/main/AndroidManifest.xml
index fb5db84f..d87ecd14 100644
--- a/Live/src/main/AndroidManifest.xml
+++ b/Live/src/main/AndroidManifest.xml
@@ -7,21 +7,4 @@
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/Live/src/main/cpp/AudioStream.cpp b/Live/src/main/cpp/AudioStream.cpp
new file mode 100644
index 00000000..f4a58a0b
--- /dev/null
+++ b/Live/src/main/cpp/AudioStream.cpp
@@ -0,0 +1,96 @@
+
+#include
+#include "AudioStream.h"
+#include "PushInterface.h"
+
+AudioStream::AudioStream() {
+
+}
+
+void AudioStream::setAudioCallback(AudioCallback callback) {
+ audioCallback = callback;
+}
+
+int AudioStream::setAudioEncInfo(int samplesInHZ, int channels) {
+ m_channels = channels;
+ //open faac encoder
+ m_audioCodec = faacEncOpen(static_cast(samplesInHZ),
+ static_cast(channels),
+ &m_inputSamples,
+ &m_maxOutputBytes);
+ m_buffer = new u_char[m_maxOutputBytes];
+
+ //set encoder params
+ faacEncConfigurationPtr config = faacEncGetCurrentConfiguration(m_audioCodec);
+ config->mpegVersion = MPEG4;
+ config->aacObjectType = LOW;
+ config->inputFormat = FAAC_INPUT_16BIT;
+ config->outputFormat = 0;
+ return faacEncSetConfiguration(m_audioCodec, config);
+}
+
+int AudioStream::getInputSamples() const {
+ return static_cast(m_inputSamples);
+}
+
+RTMPPacket *AudioStream::getAudioTag() {
+ u_char *buf;
+ u_long len;
+ faacEncGetDecoderSpecificInfo(m_audioCodec, &buf, &len);
+ int bodySize = static_cast(2 + len);
+ auto *packet = new RTMPPacket();
+ RTMPPacket_Alloc(packet, bodySize);
+ //channel layout: stereo
+ packet->m_body[0] = 0xAF;
+ if (m_channels == 1) {
+ packet->m_body[0] = 0xAE;
+ }
+ packet->m_body[1] = 0x00;
+
+ memcpy(&packet->m_body[2], buf, len);
+
+ packet->m_hasAbsTimestamp = 0;
+ packet->m_nBodySize = bodySize;
+ packet->m_packetType = RTMP_PACKET_TYPE_AUDIO;
+ packet->m_nChannel = 0x11;
+ packet->m_headerType = RTMP_PACKET_SIZE_LARGE;
+ return packet;
+}
+
+void AudioStream::encodeData(int8_t *data) {
+ //encode a frame, and return encoded len
+ int byteLen = faacEncEncode(m_audioCodec, reinterpret_cast(data),
+ static_cast(m_inputSamples),
+ m_buffer,
+ static_cast(m_maxOutputBytes));
+ if (byteLen > 0) {
+ int bodySize = 2 + byteLen;
+ auto *packet = new RTMPPacket();
+ RTMPPacket_Alloc(packet, bodySize);
+ //stereo
+ packet->m_body[0] = 0xAF;
+ if (m_channels == 1) {
+ packet->m_body[0] = 0xAE;
+ }
+
+ packet->m_body[1] = 0x01;
+ memcpy(&packet->m_body[2], m_buffer, static_cast(byteLen));
+
+ packet->m_hasAbsTimestamp = 0;
+ packet->m_nBodySize = bodySize;
+ packet->m_packetType = RTMP_PACKET_TYPE_AUDIO;
+ packet->m_nChannel = 0x11;
+ packet->m_headerType = RTMP_PACKET_SIZE_LARGE;
+ audioCallback(packet);
+ }
+}
+
+AudioStream::~AudioStream() {
+ delete m_buffer;
+ m_buffer = nullptr;
+ if (m_audioCodec) {
+ faacEncClose(m_audioCodec);
+ m_audioCodec = nullptr;
+ }
+}
+
diff --git a/Live/src/main/cpp/AudioStream.h b/Live/src/main/cpp/AudioStream.h
new file mode 100644
index 00000000..38b24384
--- /dev/null
+++ b/Live/src/main/cpp/AudioStream.h
@@ -0,0 +1,38 @@
+
+#ifndef AUDIOSTREAM_H
+#define AUDIOSTREAM_H
+
+#include "rtmp/rtmp.h"
+#include "faac/faac.h"
+#include
+
+class AudioStream {
+ typedef void (*AudioCallback)(RTMPPacket *packet);
+
+private:
+ AudioCallback audioCallback;
+ int m_channels;
+ faacEncHandle m_audioCodec = 0;
+ u_long m_inputSamples;
+ u_long m_maxOutputBytes;
+ u_char *m_buffer = 0;
+
+public:
+ AudioStream();
+
+ ~AudioStream();
+
+ int setAudioEncInfo(int samplesInHZ, int channels);
+
+ void setAudioCallback(AudioCallback audioCallback);
+
+ int getInputSamples() const;
+
+ void encodeData(int8_t *data);
+
+ RTMPPacket *getAudioTag();
+
+};
+
+
+#endif
diff --git a/Live/src/main/cpp/PacketQueue.h b/Live/src/main/cpp/PacketQueue.h
new file mode 100644
index 00000000..f43a81fa
--- /dev/null
+++ b/Live/src/main/cpp/PacketQueue.h
@@ -0,0 +1,75 @@
+
+#ifndef PACKET_QUEUE_H
+#define PACKET_QUEUE_H
+
+#include
+#include
+
+template
+class PacketQueue {
+ typedef void (*ReleaseCallback)(T &);
+
+private:
+ std::mutex m_mutex;
+ std::condition_variable m_cond;
+ std::queue m_queue;
+ bool m_running;
+
+ ReleaseCallback releaseCallback;
+
+public:
+
+ void push(T new_value) {
+ std::lock_guard lock(m_mutex);
+ if (m_running) {
+ m_queue.push(new_value);
+ m_cond.notify_one();
+ }
+ }
+
+ int pop(T &value) {
+ int ret = 0;
+ std::unique_lock lock(m_mutex);
+ if (!m_running) {
+ return ret;
+ }
+ if (!m_queue.empty()) {
+ value = m_queue.front();
+ m_queue.pop();
+ ret = 1;
+ }
+ return ret;
+ }
+
+ void clear() {
+ std::lock_guard lock(m_mutex);
+ int size = m_queue.size();
+ for (int i = 0; i < size; ++i) {
+ T value = m_queue.front();
+ releaseCallback(value);
+ m_queue.pop();
+ }
+ }
+
+ void setRunning(bool run) {
+ std::lock_guard lock(m_mutex);
+ m_running = run;
+ }
+
+ bool empty() {
+ std::lock_guard lock(m_mutex);
+ return m_queue.empty();
+ }
+
+ int size() {
+ std::lock_guard lock(m_mutex);
+ return static_cast(m_queue.size());
+ }
+
+ void setReleaseCallback(ReleaseCallback callback) {
+ releaseCallback = callback;
+ }
+
+};
+
+#endif // PACKET_QUEUE_H
diff --git a/Live/src/main/cpp/PushInterface.h b/Live/src/main/cpp/PushInterface.h
new file mode 100644
index 00000000..43b6ab50
--- /dev/null
+++ b/Live/src/main/cpp/PushInterface.h
@@ -0,0 +1,28 @@
+
+#ifndef PUSHINTERFACE_H
+#define PUSHINTERFACE_H
+
+#include
+
+#define LOGI(...) __android_log_print(ANDROID_LOG_INFO,"FrankLive",__VA_ARGS__)
+#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR,"FrankLive",__VA_ARGS__)
+
+/***************relative to Java**************/
+//error code for opening video encoder
+const int ERROR_VIDEO_ENCODER_OPEN = 0x01;
+//error code for video encoding
+const int ERROR_VIDEO_ENCODE = 0x02;
+//error code for opening audio encoder
+const int ERROR_AUDIO_ENCODER_OPEN = 0x03;
+//error code for audio encoding
+const int ERROR_AUDIO_ENCODE = 0x04;
+//error code for RTMP connecting
+const int ERROR_RTMP_CONNECT = 0x05;
+//error code for connecting stream
+const int ERROR_RTMP_CONNECT_STREAM = 0x06;
+//error code for sending packet
+const int ERROR_RTMP_SEND_PACKET = 0x07;
+
+/***************relative to Java**************/
+
+#endif
diff --git a/Live/src/main/cpp/RtmpPusher.cpp b/Live/src/main/cpp/RtmpPusher.cpp
new file mode 100644
index 00000000..5609cfbd
--- /dev/null
+++ b/Live/src/main/cpp/RtmpPusher.cpp
@@ -0,0 +1,205 @@
+#include
+#include
+#include "PacketQueue.h"
+#include "PushInterface.h"
+#include "VideoStream.h"
+#include "AudioStream.h"
+
+#define RTMP_PUSHER_FUNC(RETURN_TYPE, FUNC_NAME, ...) \
+ extern "C" \
+ JNIEXPORT RETURN_TYPE JNICALL Java_com_frank_live_LivePusherNew_ ## FUNC_NAME \
+ (JNIEnv *env, jobject instance, ##__VA_ARGS__)\
+
+PacketQueue packets;
+VideoStream *videoStream = nullptr;
+AudioStream *audioStream = nullptr;
+
+std::atomic isPushing;
+uint32_t start_time;
+
+//use to get thread's JNIEnv
+JavaVM *javaVM;
+//callback object
+jobject jobject_error;
+
+//when calling System.loadLibrary, will callback it
+jint JNICALL JNI_OnLoad(JavaVM *vm, void *reserved) {
+ javaVM = vm;
+ return JNI_VERSION_1_6;
+}
+
+//callback error to java
+void throwErrToJava(int error_code) {
+ JNIEnv *env;
+ javaVM->AttachCurrentThread(&env, nullptr);
+ jclass classErr = env->GetObjectClass(jobject_error);
+ jmethodID methodErr = env->GetMethodID(classErr, "errorFromNative", "(I)V");
+ env->CallVoidMethod(jobject_error, methodErr, error_code);
+ javaVM->DetachCurrentThread();
+}
+
+void callback(RTMPPacket *packet) {
+ if (packet) {
+ packet->m_nTimeStamp = RTMP_GetTime() - start_time;
+ packets.push(packet);
+ }
+}
+
+void releasePackets(RTMPPacket *&packet) {
+ if (packet) {
+ RTMPPacket_Free(packet);
+ delete packet;
+ packet = nullptr;
+ }
+}
+
+void *start(void *args) {
+ char *url = static_cast(args);
+ RTMP *rtmp;
+ do {
+ rtmp = RTMP_Alloc();
+ if (!rtmp) {
+ LOGE("RTMP_Alloc fail");
+ break;
+ }
+ RTMP_Init(rtmp);
+ int ret = RTMP_SetupURL(rtmp, url);
+ if (!ret) {
+ LOGE("RTMP_SetupURL:%s", url);
+ break;
+ }
+ //timeout
+ rtmp->Link.timeout = 5;
+ RTMP_EnableWrite(rtmp);
+ ret = RTMP_Connect(rtmp, nullptr);
+ if (!ret) {
+ LOGE("RTMP_Connect:%s", url);
+ throwErrToJava(ERROR_RTMP_CONNECT);
+ break;
+ }
+ ret = RTMP_ConnectStream(rtmp, 0);
+ if (!ret) {
+ LOGE("RTMP_ConnectStream:%s", url);
+ throwErrToJava(ERROR_RTMP_CONNECT_STREAM);
+ break;
+ }
+ //start time
+ start_time = RTMP_GetTime();
+ //start pushing
+ isPushing = true;
+ packets.setRunning(true);
+ callback(audioStream->getAudioTag());
+ RTMPPacket *packet = nullptr;
+ while (isPushing) {
+ packets.pop(packet);
+ if (!isPushing) {
+ break;
+ }
+ if (!packet) {
+ continue;
+ }
+
+ packet->m_nInfoField2 = rtmp->m_stream_id;
+ ret = RTMP_SendPacket(rtmp, packet, 1);
+ releasePackets(packet);
+ if (!ret) {
+ LOGE("RTMP_SendPacket fail...");
+ throwErrToJava(ERROR_RTMP_SEND_PACKET);
+ break;
+ }
+ }
+ releasePackets(packet);
+ } while (0);
+ isPushing = false;
+ packets.setRunning(false);
+ packets.clear();
+ if (rtmp) {
+ RTMP_Close(rtmp);
+ RTMP_Free(rtmp);
+ }
+ delete (url);
+ return nullptr;
+}
+
+RTMP_PUSHER_FUNC(void, native_1init) {
+ LOGI("native init...");
+ videoStream = new VideoStream();
+ videoStream->setVideoCallback(callback);
+ audioStream = new AudioStream();
+ audioStream->setAudioCallback(callback);
+ packets.setReleaseCallback(releasePackets);
+ jobject_error = env->NewGlobalRef(instance);
+}
+
+RTMP_PUSHER_FUNC(void, native_1setVideoCodecInfo,
+ jint width, jint height, jint fps, jint bitrate) {
+ if (videoStream) {
+ int ret = videoStream->setVideoEncInfo(width, height, fps, bitrate);
+ if (ret < 0) {
+ throwErrToJava(ERROR_VIDEO_ENCODER_OPEN);
+ }
+ }
+}
+
+RTMP_PUSHER_FUNC(void, native_1start, jstring path_) {
+ LOGI("native start...");
+ if (isPushing) {
+ return;
+ }
+ const char *path = env->GetStringUTFChars(path_, nullptr);
+ char *url = new char[strlen(path) + 1];
+ strcpy(url, path);
+
+ std::thread pushThread(start, url);
+ pushThread.detach();
+ env->ReleaseStringUTFChars(path_, path);
+}
+
+RTMP_PUSHER_FUNC(void, native_1pushVideo, jbyteArray yuv, jint camera_type) {
+ if (!videoStream || !isPushing) {
+ return;
+ }
+ jbyte *yuv_plane = env->GetByteArrayElements(yuv, JNI_FALSE);
+ videoStream->encodeVideo(yuv_plane, camera_type);
+ env->ReleaseByteArrayElements(yuv, yuv_plane, 0);
+}
+
+RTMP_PUSHER_FUNC(void, native_1setAudioCodecInfo, jint sampleRateInHz, jint channels) {
+ if (audioStream) {
+ int ret = audioStream->setAudioEncInfo(sampleRateInHz, channels);
+ if (ret < 0) {
+ throwErrToJava(ERROR_AUDIO_ENCODER_OPEN);
+ }
+ }
+}
+
+RTMP_PUSHER_FUNC(jint, native_1getInputSamples) {
+ if (audioStream) {
+ return audioStream->getInputSamples();
+ }
+ return -1;
+}
+
+RTMP_PUSHER_FUNC(void, native_1pushAudio, jbyteArray data_) {
+ if (!audioStream || !isPushing) {
+ return;
+ }
+ jbyte *data = env->GetByteArrayElements(data_, nullptr);
+ audioStream->encodeData(data);
+ env->ReleaseByteArrayElements(data_, data, 0);
+}
+
+RTMP_PUSHER_FUNC(void, native_1stop) {
+ LOGI("native stop...");
+ isPushing = false;
+ packets.setRunning(false);
+}
+
+RTMP_PUSHER_FUNC(void, native_1release) {
+ LOGI("native release...");
+ env->DeleteGlobalRef(jobject_error);
+ delete videoStream;
+ videoStream = nullptr;
+ delete audioStream;
+ audioStream = nullptr;
+}
\ No newline at end of file
diff --git a/Live/src/main/cpp/VideoStream.cpp b/Live/src/main/cpp/VideoStream.cpp
new file mode 100644
index 00000000..3cb107eb
--- /dev/null
+++ b/Live/src/main/cpp/VideoStream.cpp
@@ -0,0 +1,221 @@
+
+#include
+#include "VideoStream.h"
+#include "PushInterface.h"
+
+VideoStream::VideoStream():m_frameLen(0),
+ videoCodec(nullptr),
+ pic_in(nullptr),
+ videoCallback(nullptr) {
+
+}
+
+int VideoStream::setVideoEncInfo(int width, int height, int fps, int bitrate) {
+ std::lock_guard l(m_mutex);
+ m_frameLen = width * height;
+ if (videoCodec) {
+ x264_encoder_close(videoCodec);
+ videoCodec = nullptr;
+ }
+ if (pic_in) {
+ x264_picture_clean(pic_in);
+ delete pic_in;
+ pic_in = nullptr;
+ }
+
+ //setting x264 params
+ x264_param_t param;
+ int ret = x264_param_default_preset(¶m, "ultrafast", "zerolatency");
+ if (ret < 0) {
+ return ret;
+ }
+ param.i_level_idc = 32;
+ //input format
+ param.i_csp = X264_CSP_I420;
+ param.i_width = width;
+ param.i_height = height;
+ //no B frame
+ param.i_bframe = 0;
+ //i_rc_method:bitrate control, CQP(constant quality), CRF(constant bitrate), ABR(average bitrate)
+ param.rc.i_rc_method = X264_RC_ABR;
+ //bitrate(Kbps)
+ param.rc.i_bitrate = bitrate / 1024;
+ //max bitrate
+ param.rc.i_vbv_max_bitrate = bitrate / 1024 * 1.2;
+ //unit:kbps
+ param.rc.i_vbv_buffer_size = bitrate / 1024;
+
+ //frame rate
+ param.i_fps_num = fps;
+ param.i_fps_den = 1;
+ param.i_timebase_den = param.i_fps_num;
+ param.i_timebase_num = param.i_fps_den;
+ //using fps
+ param.b_vfr_input = 0;
+ //key frame interval(GOP)
+ param.i_keyint_max = fps * 2;
+ //each key frame attaches sps/pps
+ param.b_repeat_headers = 1;
+ //thread number
+ param.i_threads = 1;
+
+ ret = x264_param_apply_profile(¶m, "baseline");
+ if (ret < 0) {
+ return ret;
+ }
+ //open encoder
+ videoCodec = x264_encoder_open(¶m);
+ if (!videoCodec) {
+ return -1;
+ }
+ pic_in = new x264_picture_t();
+ x264_picture_alloc(pic_in, X264_CSP_I420, width, height);
+ return ret;
+}
+
+void VideoStream::setVideoCallback(VideoCallback callback) {
+ this->videoCallback = callback;
+}
+
+void VideoStream::sendSpsPps(uint8_t *sps, uint8_t *pps, int sps_len, int pps_len) {
+ int bodySize = 13 + sps_len + 3 + pps_len;
+ auto *packet = new RTMPPacket();
+ RTMPPacket_Alloc(packet, bodySize);
+ int i = 0;
+ // type
+ packet->m_body[i++] = 0x17;
+ packet->m_body[i++] = 0x00;
+ // timestamp
+ packet->m_body[i++] = 0x00;
+ packet->m_body[i++] = 0x00;
+ packet->m_body[i++] = 0x00;
+
+ //version
+ packet->m_body[i++] = 0x01;
+ // profile
+ packet->m_body[i++] = sps[1];
+ packet->m_body[i++] = sps[2];
+ packet->m_body[i++] = sps[3];
+ packet->m_body[i++] = 0xFF;
+
+ //sps
+ packet->m_body[i++] = 0xE1;
+ //sps len
+ packet->m_body[i++] = (sps_len >> 8) & 0xFF;
+ packet->m_body[i++] = sps_len & 0xFF;
+ memcpy(&packet->m_body[i], sps, sps_len);
+ i += sps_len;
+
+ //pps
+ packet->m_body[i++] = 0x01;
+ packet->m_body[i++] = (pps_len >> 8) & 0xFF;
+ packet->m_body[i++] = (pps_len) & 0xFF;
+ memcpy(&packet->m_body[i], pps, pps_len);
+
+ //video
+ packet->m_packetType = RTMP_PACKET_TYPE_VIDEO;
+ packet->m_nBodySize = bodySize;
+ packet->m_nChannel = 0x10;
+ //sps and pps no timestamp
+ packet->m_nTimeStamp = 0;
+ packet->m_hasAbsTimestamp = 0;
+ packet->m_headerType = RTMP_PACKET_SIZE_MEDIUM;
+
+ videoCallback(packet);
+}
+
+void VideoStream::sendFrame(int type, uint8_t *payload, int i_payload) {
+ if (payload[2] == 0x00) {
+ i_payload -= 4;
+ payload += 4;
+ } else {
+ i_payload -= 3;
+ payload += 3;
+ }
+ int i = 0;
+ int bodySize = 9 + i_payload;
+ auto *packet = new RTMPPacket();
+ RTMPPacket_Alloc(packet, bodySize);
+
+ if (type == NAL_SLICE_IDR) {
+ packet->m_body[i++] = 0x17; // 1:Key frame 7:AVC
+ } else {
+ packet->m_body[i++] = 0x27; // 2:None key frame 7:AVC
+ }
+ //AVC NALU
+ packet->m_body[i++] = 0x01;
+ //timestamp
+ packet->m_body[i++] = 0x00;
+ packet->m_body[i++] = 0x00;
+ packet->m_body[i++] = 0x00;
+ //packet len
+ packet->m_body[i++] = (i_payload >> 24) & 0xFF;
+ packet->m_body[i++] = (i_payload >> 16) & 0xFF;
+ packet->m_body[i++] = (i_payload >> 8) & 0xFF;
+ packet->m_body[i++] = (i_payload) & 0xFF;
+
+ memcpy(&packet->m_body[i], payload, static_cast(i_payload));
+
+ packet->m_hasAbsTimestamp = 0;
+ packet->m_nBodySize = bodySize;
+ packet->m_packetType = RTMP_PACKET_TYPE_VIDEO;
+ packet->m_nChannel = 0x10;
+ packet->m_headerType = RTMP_PACKET_SIZE_LARGE;
+ videoCallback(packet);
+}
+
+void VideoStream::encodeVideo(int8_t *data, int camera_type) {
+ std::lock_guard l(m_mutex);
+ if (!pic_in)
+ return;
+
+ if (camera_type == 1) {
+ memcpy(pic_in->img.plane[0], data, m_frameLen); // y
+ for (int i = 0; i < m_frameLen/4; ++i) {
+ *(pic_in->img.plane[1] + i) = *(data + m_frameLen + i * 2 + 1); // u
+ *(pic_in->img.plane[2] + i) = *(data + m_frameLen + i * 2); // v
+ }
+ } else if (camera_type == 2) {
+ int offset = 0;
+ memcpy(pic_in->img.plane[0], data, (size_t) m_frameLen); // y
+ offset += m_frameLen;
+ memcpy(pic_in->img.plane[1], data + offset, (size_t) m_frameLen / 4); // u
+ offset += m_frameLen / 4;
+ memcpy(pic_in->img.plane[2], data + offset, (size_t) m_frameLen / 4); // v
+ } else {
+ return;
+ }
+
+ x264_nal_t *pp_nal;
+ int pi_nal;
+ x264_picture_t pic_out;
+ x264_encoder_encode(videoCodec, &pp_nal, &pi_nal, pic_in, &pic_out);
+ int pps_len, sps_len = 0;
+ uint8_t sps[100];
+ uint8_t pps[100];
+ for (int i = 0; i < pi_nal; ++i) {
+ x264_nal_t nal = pp_nal[i];
+ if (nal.i_type == NAL_SPS) {
+ sps_len = nal.i_payload - 4;
+ memcpy(sps, nal.p_payload + 4, static_cast(sps_len));
+ } else if (nal.i_type == NAL_PPS) {
+ pps_len = nal.i_payload - 4;
+ memcpy(pps, nal.p_payload + 4, static_cast(pps_len));
+ sendSpsPps(sps, pps, sps_len, pps_len);
+ } else {
+ sendFrame(nal.i_type, nal.p_payload, nal.i_payload);
+ }
+ }
+}
+
+VideoStream::~VideoStream() {
+ if (videoCodec) {
+ x264_encoder_close(videoCodec);
+ videoCodec = nullptr;
+ }
+ if (pic_in) {
+ x264_picture_clean(pic_in);
+ delete pic_in;
+ pic_in = nullptr;
+ }
+}
diff --git a/Live/src/main/cpp/VideoStream.h b/Live/src/main/cpp/VideoStream.h
new file mode 100644
index 00000000..fdad427b
--- /dev/null
+++ b/Live/src/main/cpp/VideoStream.h
@@ -0,0 +1,39 @@
+
+#ifndef VIDEOSTREAM_H
+#define VIDEOSTREAM_H
+
+#include
+#include
+#include "rtmp/rtmp.h"
+#include "x264/x264.h"
+
+class VideoStream {
+ typedef void (*VideoCallback)(RTMPPacket *packet);
+
+private:
+ std::mutex m_mutex;
+
+ int m_frameLen;
+ x264_t *videoCodec = 0;
+ x264_picture_t *pic_in = 0;
+
+ VideoCallback videoCallback;
+
+ void sendSpsPps(uint8_t *sps, uint8_t *pps, int sps_len, int pps_len);
+
+ void sendFrame(int type, uint8_t *payload, int i_payload);
+
+public:
+ VideoStream();
+
+ ~VideoStream();
+
+ int setVideoEncInfo(int width, int height, int fps, int bitrate);
+
+ void encodeVideo(int8_t *data, int camera_type);
+
+ void setVideoCallback(VideoCallback videoCallback);
+
+};
+
+#endif
diff --git a/Live/src/main/cpp/include/x264/x264.h b/Live/src/main/cpp/include/x264/x264.h
index 38048203..b9a5334b 100644
--- a/Live/src/main/cpp/include/x264/x264.h
+++ b/Live/src/main/cpp/include/x264/x264.h
@@ -1,11 +1,11 @@
/*****************************************************************************
- * include.x264.h: include.x264 public header
+ * x264.h: x264 public header
*****************************************************************************
- * Copyright (C) 2003-2016 include.x264 project
+ * Copyright (C) 2003-2019 x264 project
*
* Authors: Laurent Aimar
* Loren Merritt
- * Fiona Glaser
+ * Fiona Glaser
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -22,7 +22,7 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111, USA.
*
* This program is also available under a commercial proprietary license.
- * For more information, contact us at licensing@include.x264.com.
+ * For more information, contact us at licensing@x264.com.
*****************************************************************************/
#ifndef X264_X264_H
@@ -35,7 +35,7 @@ extern "C" {
#if !defined(_STDINT_H) && !defined(_STDINT_H_) && !defined(_STDINT_H_INCLUDED) && !defined(_STDINT) &&\
!defined(_SYS_STDINT_H_) && !defined(_INTTYPES_H) && !defined(_INTTYPES_H_) && !defined(_INTTYPES)
# ifdef _MSC_VER
-# pragma message("You must include stdint.h or inttypes.h before include.x264.h")
+# pragma message("You must include stdint.h or inttypes.h before x264.h")
# else
# warning You must include stdint.h or inttypes.h before x264.h
# endif
@@ -46,7 +46,20 @@ extern "C" {
#include "x264_config.h"
-#define X264_BUILD 148
+#define X264_BUILD 159
+
+#ifdef _WIN32
+# define X264_DLL_IMPORT __declspec(dllimport)
+# define X264_DLL_EXPORT __declspec(dllexport)
+#else
+# if defined(__GNUC__) && (__GNUC__ >= 4)
+# define X264_DLL_IMPORT
+# define X264_DLL_EXPORT __attribute__((visibility("default")))
+# else
+# define X264_DLL_IMPORT
+# define X264_DLL_EXPORT
+# endif
+#endif
/* Application developers planning to link against a shared library version of
* libx264 from a Microsoft Visual Studio or similar development environment
@@ -54,9 +67,13 @@ extern "C" {
* This clause does not apply to MinGW, similar development environments, or non
* Windows platforms. */
#ifdef X264_API_IMPORTS
-#define X264_API __declspec(dllimport)
+# define X264_API X264_DLL_IMPORT
#else
-#define X264_API
+# ifdef X264_API_EXPORTS
+# define X264_API X264_DLL_EXPORT
+# else
+# define X264_API
+# endif
#endif
/* x264_t:
@@ -120,39 +137,38 @@ typedef struct x264_nal_t
/* CPU flags */
/* x86 */
-#define X264_CPU_CMOV 0x0000001
-#define X264_CPU_MMX 0x0000002
-#define X264_CPU_MMX2 0x0000004 /* MMX2 aka MMXEXT aka ISSE */
-#define X264_CPU_MMXEXT X264_CPU_MMX2
-#define X264_CPU_SSE 0x0000008
-#define X264_CPU_SSE2 0x0000010
-#define X264_CPU_SSE3 0x0000020
-#define X264_CPU_SSSE3 0x0000040
-#define X264_CPU_SSE4 0x0000080 /* SSE4.1 */
-#define X264_CPU_SSE42 0x0000100 /* SSE4.2 */
-#define X264_CPU_LZCNT 0x0000200 /* Phenom support for "leading zero count" instruction. */
-#define X264_CPU_AVX 0x0000400 /* AVX support: requires OS support even if YMM registers aren't used. */
-#define X264_CPU_XOP 0x0000800 /* AMD XOP */
-#define X264_CPU_FMA4 0x0001000 /* AMD FMA4 */
-#define X264_CPU_FMA3 0x0002000 /* FMA3 */
-#define X264_CPU_AVX2 0x0004000 /* AVX2 */
-#define X264_CPU_BMI1 0x0008000 /* BMI1 */
-#define X264_CPU_BMI2 0x0010000 /* BMI2 */
+#define X264_CPU_MMX (1<<0)
+#define X264_CPU_MMX2 (1<<1) /* MMX2 aka MMXEXT aka ISSE */
+#define X264_CPU_MMXEXT X264_CPU_MMX2
+#define X264_CPU_SSE (1<<2)
+#define X264_CPU_SSE2 (1<<3)
+#define X264_CPU_LZCNT (1<<4)
+#define X264_CPU_SSE3 (1<<5)
+#define X264_CPU_SSSE3 (1<<6)
+#define X264_CPU_SSE4 (1<<7) /* SSE4.1 */
+#define X264_CPU_SSE42 (1<<8) /* SSE4.2 */
+#define X264_CPU_AVX (1<<9) /* Requires OS support even if YMM registers aren't used */
+#define X264_CPU_XOP (1<<10) /* AMD XOP */
+#define X264_CPU_FMA4 (1<<11) /* AMD FMA4 */
+#define X264_CPU_FMA3 (1<<12)
+#define X264_CPU_BMI1 (1<<13)
+#define X264_CPU_BMI2 (1<<14)
+#define X264_CPU_AVX2 (1<<15)
+#define X264_CPU_AVX512 (1<<16) /* AVX-512 {F, CD, BW, DQ, VL}, requires OS support */
/* x86 modifiers */
-#define X264_CPU_CACHELINE_32 0x0020000 /* avoid memory loads that span the border between two cachelines */
-#define X264_CPU_CACHELINE_64 0x0040000 /* 32/64 is the size of a cacheline in bytes */
-#define X264_CPU_SSE2_IS_SLOW 0x0080000 /* avoid most SSE2 functions on Athlon64 */
-#define X264_CPU_SSE2_IS_FAST 0x0100000 /* a few functions are only faster on Core2 and Phenom */
-#define X264_CPU_SLOW_SHUFFLE 0x0200000 /* The Conroe has a slow shuffle unit (relative to overall SSE performance) */
-#define X264_CPU_STACK_MOD4 0x0400000 /* if stack is only mod4 and not mod16 */
-#define X264_CPU_SLOW_CTZ 0x0800000 /* BSR/BSF x86 instructions are really slow on some CPUs */
-#define X264_CPU_SLOW_ATOM 0x1000000 /* The Atom is terrible: slow SSE unaligned loads, slow
+#define X264_CPU_CACHELINE_32 (1<<17) /* avoid memory loads that span the border between two cachelines */
+#define X264_CPU_CACHELINE_64 (1<<18) /* 32/64 is the size of a cacheline in bytes */
+#define X264_CPU_SSE2_IS_SLOW (1<<19) /* avoid most SSE2 functions on Athlon64 */
+#define X264_CPU_SSE2_IS_FAST (1<<20) /* a few functions are only faster on Core2 and Phenom */
+#define X264_CPU_SLOW_SHUFFLE (1<<21) /* The Conroe has a slow shuffle unit (relative to overall SSE performance) */
+#define X264_CPU_STACK_MOD4 (1<<22) /* if stack is only mod4 and not mod16 */
+#define X264_CPU_SLOW_ATOM (1<<23) /* The Atom is terrible: slow SSE unaligned loads, slow
* SIMD multiplies, slow SIMD variable shifts, slow pshufb,
* cacheline split penalties -- gather everything here that
* isn't shared by other CPUs to avoid making half a dozen
* new SLOW flags. */
-#define X264_CPU_SLOW_PSHUFB 0x2000000 /* such as on the Intel Atom */
-#define X264_CPU_SLOW_PALIGNR 0x4000000 /* such as on the AMD Bobcat */
+#define X264_CPU_SLOW_PSHUFB (1<<24) /* such as on the Intel Atom */
+#define X264_CPU_SLOW_PALIGNR (1<<25) /* such as on the AMD Bobcat */
/* PowerPC */
#define X264_CPU_ALTIVEC 0x0000001
@@ -172,6 +188,7 @@ typedef struct x264_nal_t
#define X264_ANALYSE_PSUB16x16 0x0010 /* Analyse p16x8, p8x16 and p8x8 */
#define X264_ANALYSE_PSUB8x8 0x0020 /* Analyse p8x4, p4x8, p4x4 */
#define X264_ANALYSE_BSUB16x16 0x0100 /* Analyse b16x8, b8x16 and b8x8 */
+
#define X264_DIRECT_PRED_NONE 0
#define X264_DIRECT_PRED_SPATIAL 1
#define X264_DIRECT_PRED_TEMPORAL 2
@@ -204,6 +221,10 @@ typedef struct x264_nal_t
#define X264_KEYINT_MIN_AUTO 0
#define X264_KEYINT_MAX_INFINITE (1<<30)
+/* AVC-Intra flavors */
+#define X264_AVCINTRA_FLAVOR_PANASONIC 0
+#define X264_AVCINTRA_FLAVOR_SONY 1
+
static const char * const x264_direct_pred_names[] = { "none", "spatial", "temporal", "auto", 0 };
static const char * const x264_motion_est_names[] = { "dia", "hex", "umh", "esa", "tesa", 0 };
static const char * const x264_b_pyramid_names[] = { "none", "strict", "normal", 0 };
@@ -213,33 +234,37 @@ static const char * const x264_fullrange_names[] = { "off", "on", 0 };
static const char * const x264_colorprim_names[] = { "", "bt709", "undef", "", "bt470m", "bt470bg", "smpte170m", "smpte240m", "film", "bt2020", "smpte428",
"smpte431", "smpte432", 0 };
static const char * const x264_transfer_names[] = { "", "bt709", "undef", "", "bt470m", "bt470bg", "smpte170m", "smpte240m", "linear", "log100", "log316",
- "iec61966-2-4", "bt1361e", "iec61966-2-1", "bt2020-10", "bt2020-12", "smpte2084", "smpte428", 0 };
+ "iec61966-2-4", "bt1361e", "iec61966-2-1", "bt2020-10", "bt2020-12", "smpte2084", "smpte428", "arib-std-b67", 0 };
static const char * const x264_colmatrix_names[] = { "GBR", "bt709", "undef", "", "fcc", "bt470bg", "smpte170m", "smpte240m", "YCgCo", "bt2020nc", "bt2020c",
- "smpte2085", 0 };
+ "smpte2085", "chroma-derived-nc", "chroma-derived-c", "ICtCp", 0 };
static const char * const x264_nal_hrd_names[] = { "none", "vbr", "cbr", 0 };
+static const char * const x264_avcintra_flavor_names[] = { "panasonic", "sony", 0 };
/* Colorspace type */
#define X264_CSP_MASK 0x00ff /* */
#define X264_CSP_NONE 0x0000 /* Invalid mode */
-#define X264_CSP_I420 0x0001 /* yuv 4:2:0 planar */
-#define X264_CSP_YV12 0x0002 /* yvu 4:2:0 planar */
-#define X264_CSP_NV12 0x0003 /* yuv 4:2:0, with one y plane and one packed u+v */
-#define X264_CSP_NV21 0x0004 /* yuv 4:2:0, with one y plane and one packed v+u */
-#define X264_CSP_I422 0x0005 /* yuv 4:2:2 planar */
-#define X264_CSP_YV16 0x0006 /* yvu 4:2:2 planar */
-#define X264_CSP_NV16 0x0007 /* yuv 4:2:2, with one y plane and one packed u+v */
-#define X264_CSP_V210 0x0008 /* 10-bit yuv 4:2:2 packed in 32 */
-#define X264_CSP_I444 0x0009 /* yuv 4:4:4 planar */
-#define X264_CSP_YV24 0x000a /* yvu 4:4:4 planar */
-#define X264_CSP_BGR 0x000b /* packed bgr 24bits */
-#define X264_CSP_BGRA 0x000c /* packed bgr 32bits */
-#define X264_CSP_RGB 0x000d /* packed rgb 24bits */
-#define X264_CSP_MAX 0x000e /* end of list */
+#define X264_CSP_I400 0x0001 /* monochrome 4:0:0 */
+#define X264_CSP_I420 0x0002 /* yuv 4:2:0 planar */
+#define X264_CSP_YV12 0x0003 /* yvu 4:2:0 planar */
+#define X264_CSP_NV12 0x0004 /* yuv 4:2:0, with one y plane and one packed u+v */
+#define X264_CSP_NV21 0x0005 /* yuv 4:2:0, with one y plane and one packed v+u */
+#define X264_CSP_I422 0x0006 /* yuv 4:2:2 planar */
+#define X264_CSP_YV16 0x0007 /* yvu 4:2:2 planar */
+#define X264_CSP_NV16 0x0008 /* yuv 4:2:2, with one y plane and one packed u+v */
+#define X264_CSP_YUYV 0x0009 /* yuyv 4:2:2 packed */
+#define X264_CSP_UYVY 0x000a /* uyvy 4:2:2 packed */
+#define X264_CSP_V210 0x000b /* 10-bit yuv 4:2:2 packed in 32 */
+#define X264_CSP_I444 0x000c /* yuv 4:4:4 planar */
+#define X264_CSP_YV24 0x000d /* yvu 4:4:4 planar */
+#define X264_CSP_BGR 0x000e /* packed bgr 24bits */
+#define X264_CSP_BGRA 0x000f /* packed bgr 32bits */
+#define X264_CSP_RGB 0x0010 /* packed rgb 24bits */
+#define X264_CSP_MAX 0x0011 /* end of list */
#define X264_CSP_VFLIP 0x1000 /* the csp is vertically flipped */
#define X264_CSP_HIGH_DEPTH 0x2000 /* the csp has a depth of 16 bits per pixel component */
/* Slice type */
-#define X264_TYPE_AUTO 0x0000 /* Let include.x264 choose the right type */
+#define X264_TYPE_AUTO 0x0000 /* Let x264 choose the right type */
#define X264_TYPE_IDR 0x0001
#define X264_TYPE_I 0x0002
#define X264_TYPE_P 0x0003
@@ -292,6 +317,7 @@ typedef struct x264_param_t
int i_width;
int i_height;
int i_csp; /* CSP of encoded bitstream */
+ int i_bitdepth;
int i_level_idc;
int i_frame_total; /* number of frames to encode if known, else 0 */
@@ -336,6 +362,7 @@ typedef struct x264_param_t
int b_open_gop;
int b_bluray_compat;
int i_avcintra_class;
+ int i_avcintra_flavor;
int b_deblocking_filter;
int i_deblocking_filter_alphac0; /* [-6, 6] -6 light filter, 6 strong */
@@ -407,7 +434,7 @@ typedef struct x264_param_t
{
int i_rc_method; /* X264_RC_* */
- int i_qp_constant; /* 0 to (51 + 6*(x264_bit_depth-8)). 0=lossless */
+ int i_qp_constant; /* 0=lossless */
int i_qp_min; /* min allowed QP value */
int i_qp_max; /* max allowed QP value */
int i_qp_step; /* max QP step between frames */
@@ -459,6 +486,9 @@ typedef struct x264_param_t
/* frame packing arrangement flag */
int i_frame_packing;
+ /* alternative transfer SEI */
+ int i_alternative_transfer;
+
/* Muxing parameters */
int b_aud; /* generate access unit delimiters */
int b_repeat_headers; /* put SPS/PPS before each keyframe */
@@ -553,10 +583,10 @@ typedef struct x264_param_t
* NAL unit. This helps distinguish between nalu_process calls from different sources,
* e.g. if doing multiple encodes in one process.
*/
- void (*nalu_process) ( x264_t *h, x264_nal_t *nal, void *opaque );
+ void (*nalu_process)( x264_t *h, x264_nal_t *nal, void *opaque );
} x264_param_t;
-void x264_nal_encode( x264_t *h, uint8_t *dst, x264_nal_t *nal );
+X264_API void x264_nal_encode( x264_t *h, uint8_t *dst, x264_nal_t *nal );
/****************************************************************************
* H.264 level restriction information
@@ -564,19 +594,19 @@ void x264_nal_encode( x264_t *h, uint8_t *dst, x264_nal_t *nal );
typedef struct x264_level_t
{
- int level_idc;
- int mbps; /* max macroblock processing rate (macroblocks/sec) */
- int frame_size; /* max frame size (macroblocks) */
- int dpb; /* max decoded picture buffer (mbs) */
- int bitrate; /* max bitrate (kbit/sec) */
- int cpb; /* max vbv buffer (kbit) */
- int mv_range; /* max vertical mv component range (pixels) */
- int mvs_per_2mb; /* max mvs per 2 consecutive mbs. */
- int slice_rate; /* ?? */
- int mincr; /* min compression ratio */
- int bipred8x8; /* limit bipred to >=8x8 */
- int direct8x8; /* limit b_direct to >=8x8 */
- int frame_only; /* forbid interlacing */
+ uint8_t level_idc;
+ uint32_t mbps; /* max macroblock processing rate (macroblocks/sec) */
+ uint32_t frame_size; /* max frame size (macroblocks) */
+ uint32_t dpb; /* max decoded picture buffer (mbs) */
+ uint32_t bitrate; /* max bitrate (kbit/sec) */
+ uint32_t cpb; /* max vbv buffer (kbit) */
+ uint16_t mv_range; /* max vertical mv component range (pixels) */
+ uint8_t mvs_per_2mb; /* max mvs per 2 consecutive mbs. */
+ uint8_t slice_rate; /* ?? */
+ uint8_t mincr; /* min compression ratio */
+ uint8_t bipred8x8; /* limit bipred to >=8x8 */
+ uint8_t direct8x8; /* limit b_direct to >=8x8 */
+ uint8_t frame_only; /* forbid interlacing */
} x264_level_t;
/* all of the levels defined in the standard, terminated by .level_idc=0 */
@@ -588,7 +618,7 @@ X264_API extern const x264_level_t x264_levels[];
/* x264_param_default:
* fill x264_param_t with default values and do CPU detection */
-void x264_param_default( x264_param_t * );
+X264_API void x264_param_default( x264_param_t * );
/* x264_param_parse:
* set one parameter by name.
@@ -599,13 +629,13 @@ void x264_param_default( x264_param_t * );
* value=NULL means "true" for boolean options, but is a BAD_VALUE for non-booleans. */
#define X264_PARAM_BAD_NAME (-1)
#define X264_PARAM_BAD_VALUE (-2)
-int x264_param_parse( x264_param_t *, const char *name, const char *value );
+X264_API int x264_param_parse( x264_param_t *, const char *name, const char *value );
/****************************************************************************
* Advanced parameter handling functions
****************************************************************************/
-/* These functions expose the full power of include.x264's preset-tune-profile system for
+/* These functions expose the full power of x264's preset-tune-profile system for
* easy adjustment of large numbers of internal parameters.
*
* In order to replicate x264CLI's option handling, these functions MUST be called
@@ -643,13 +673,13 @@ static const char * const x264_tune_names[] = { "film", "animation", "grain", "s
* film, animation, grain, stillimage, psnr, and ssim are psy tunings.
*
* returns 0 on success, negative on failure (e.g. invalid preset/tune name). */
-int x264_param_default_preset( x264_param_t *, const char *preset, const char *tune );
+X264_API int x264_param_default_preset( x264_param_t *, const char *preset, const char *tune );
/* x264_param_apply_fastfirstpass:
* If first-pass mode is set (rc.b_stat_read == 0, rc.b_stat_write == 1),
* modify the encoder settings to disable options generally not useful on
* the first pass. */
-void x264_param_apply_fastfirstpass( x264_param_t * );
+X264_API void x264_param_apply_fastfirstpass( x264_param_t * );
/* x264_param_apply_profile:
* Applies the restrictions of the given profile.
@@ -664,25 +694,16 @@ static const char * const x264_profile_names[] = { "baseline", "main", "high", "
* decrease them.
*
* returns 0 on success, negative on failure (e.g. invalid profile name). */
-int x264_param_apply_profile( x264_param_t *, const char *profile );
+X264_API int x264_param_apply_profile( x264_param_t *, const char *profile );
/****************************************************************************
* Picture structures and functions
****************************************************************************/
-/* x264_bit_depth:
- * Specifies the number of bits per pixel that include.x264 uses. This is also the
- * bit depth that include.x264 encodes in. If this value is > 8, include.x264 will read
- * two bytes of input data for each pixel sample, and expect the upper
- * (16-x264_bit_depth) bits to be zero.
- * Note: The flag X264_CSP_HIGH_DEPTH must be used to specify the
- * colorspace depth as well. */
-X264_API extern const int x264_bit_depth;
-
/* x264_chroma_format:
- * Specifies the chroma formats that include.x264 supports encoding. When this
+ * Specifies the chroma formats that x264 supports encoding. When this
* value is non-zero, then it represents a X264_CSP_* that is the only
- * chroma format that include.x264 supports encoding. If the value is 0 then
+ * chroma format that x264 supports encoding. If the value is 0 then
* there are no restrictions. */
X264_API extern const int x264_chroma_format;
@@ -690,7 +711,7 @@ enum pic_struct_e
{
PIC_STRUCT_AUTO = 0, // automatically decide (default)
PIC_STRUCT_PROGRESSIVE = 1, // progressive frame
- // "TOP" and "BOTTOM" are not supported in include.x264 (PAFF only)
+ // "TOP" and "BOTTOM" are not supported in x264 (PAFF only)
PIC_STRUCT_TOP_BOTTOM = 4, // top field followed by bottom
PIC_STRUCT_BOTTOM_TOP = 5, // bottom field followed by top
PIC_STRUCT_TOP_BOTTOM_TOP = 6, // top field, bottom field, top field repeated
@@ -750,7 +771,7 @@ typedef struct x264_image_properties_t
* the nearest 16. If in interlaced mode, height is rounded up to the nearest 32 instead. */
/* In: an array of quantizer offsets to be applied to this image during encoding.
- * These are added on top of the decisions made by include.x264.
+ * These are added on top of the decisions made by x264.
* Offsets can be fractional; they are added before QPs are rounded to integer.
* Adaptive quantization must be enabled to use this feature. Behavior if quant
* offsets differ between encoding passes is undefined. */
@@ -762,10 +783,10 @@ typedef struct x264_image_properties_t
/* In: optional array of flags for each macroblock.
* Allows specifying additional information for the encoder such as which macroblocks
* remain unchanged. Usable flags are listed below.
- * x264_param_t.analyse.b_mb_info must be set to use this, since include.x264 needs to track
+ * x264_param_t.analyse.b_mb_info must be set to use this, since x264 needs to track
* extra data internally to make full use of this information.
*
- * Out: if b_mb_info_update is set, include.x264 will update this array as a result of encoding.
+ * Out: if b_mb_info_update is set, x264 will update this array as a result of encoding.
*
* For "MBINFO_CONSTANT", it will remove this flag on any macroblock whose decoded
* pixels have changed. This can be useful for e.g. noting which areas of the
@@ -799,8 +820,8 @@ typedef struct x264_image_properties_t
typedef struct x264_picture_t
{
/* In: force picture type (if not auto)
- * If include.x264 encoding parameters are violated in the forcing of picture types,
- * include.x264 will correct the input picture type and log a warning.
+ * If x264 encoding parameters are violated in the forcing of picture types,
+ * x264 will correct the input picture type and log a warning.
* Out: type of the picture encoded */
int i_type;
/* In: force quantizer for != X264_QP_AUTO */
@@ -825,7 +846,7 @@ typedef struct x264_picture_t
if it needs the changed parameter to apply immediately. */
x264_param_t *param;
/* In: raw image data */
- /* Out: reconstructed image data. include.x264 may skip part of the reconstruction process,
+ /* Out: reconstructed image data. x264 may skip part of the reconstruction process,
e.g. deblocking, in frames where it isn't necessary. To force complete
reconstruction, at a small speed cost, set b_full_recon. */
x264_image_t img;
@@ -843,17 +864,17 @@ typedef struct x264_picture_t
/* x264_picture_init:
* initialize an x264_picture_t. Needs to be done if the calling application
* allocates its own x264_picture_t as opposed to using x264_picture_alloc. */
-void x264_picture_init( x264_picture_t *pic );
+X264_API void x264_picture_init( x264_picture_t *pic );
/* x264_picture_alloc:
* alloc data for a picture. You must call x264_picture_clean on it.
* returns 0 on success, or -1 on malloc failure or invalid colorspace. */
-int x264_picture_alloc( x264_picture_t *pic, int i_csp, int i_width, int i_height );
+X264_API int x264_picture_alloc( x264_picture_t *pic, int i_csp, int i_width, int i_height );
/* x264_picture_clean:
* free associated resource for a x264_picture_t allocated with
* x264_picture_alloc ONLY */
-void x264_picture_clean( x264_picture_t *pic );
+X264_API void x264_picture_clean( x264_picture_t *pic );
/****************************************************************************
* Encoder functions
@@ -868,7 +889,7 @@ void x264_picture_clean( x264_picture_t *pic );
/* x264_encoder_open:
* create a new encoder handler, all parameters from x264_param_t are copied */
-x264_t *x264_encoder_open( x264_param_t * );
+X264_API x264_t *x264_encoder_open( x264_param_t * );
/* x264_encoder_reconfig:
* various parameters from x264_param_t are copied.
@@ -883,7 +904,7 @@ x264_t *x264_encoder_open( x264_param_t * );
* more so than for other presets, many of the speed shortcuts used in ultrafast cannot be
* switched out of; using reconfig to switch between ultrafast and other presets is not
* recommended without a more fine-grained breakdown of parameters to take this into account. */
-int x264_encoder_reconfig( x264_t *, x264_param_t * );
+X264_API int x264_encoder_reconfig( x264_t *, x264_param_t * );
/* x264_encoder_parameters:
* copies the current internal set of parameters to the pointer provided
* by the caller. useful when the calling application needs to know
@@ -891,32 +912,32 @@ int x264_encoder_reconfig( x264_t *, x264_param_t * );
* of the encoder after multiple x264_encoder_reconfig calls.
* note that the data accessible through pointers in the returned param struct
* (e.g. filenames) should not be modified by the calling application. */
-void x264_encoder_parameters( x264_t *, x264_param_t * );
+X264_API void x264_encoder_parameters( x264_t *, x264_param_t * );
/* x264_encoder_headers:
* return the SPS and PPS that will be used for the whole stream.
* *pi_nal is the number of NAL units outputted in pp_nal.
* returns the number of bytes in the returned NALs.
* returns negative on error.
* the payloads of all output NALs are guaranteed to be sequential in memory. */
-int x264_encoder_headers( x264_t *, x264_nal_t **pp_nal, int *pi_nal );
+X264_API int x264_encoder_headers( x264_t *, x264_nal_t **pp_nal, int *pi_nal );
/* x264_encoder_encode:
* encode one picture.
* *pi_nal is the number of NAL units outputted in pp_nal.
* returns the number of bytes in the returned NALs.
* returns negative on error and zero if no NAL units returned.
* the payloads of all output NALs are guaranteed to be sequential in memory. */
-int x264_encoder_encode( x264_t *, x264_nal_t **pp_nal, int *pi_nal, x264_picture_t *pic_in, x264_picture_t *pic_out );
+X264_API int x264_encoder_encode( x264_t *, x264_nal_t **pp_nal, int *pi_nal, x264_picture_t *pic_in, x264_picture_t *pic_out );
/* x264_encoder_close:
* close an encoder handler */
-void x264_encoder_close ( x264_t * );
+X264_API void x264_encoder_close( x264_t * );
/* x264_encoder_delayed_frames:
* return the number of currently delayed (buffered) frames
* this should be used at the end of the stream, to know when you have all the encoded frames. */
-int x264_encoder_delayed_frames( x264_t * );
-/* x264_encoder_maximum_delayed_frames( x264_t *h ):
+X264_API int x264_encoder_delayed_frames( x264_t * );
+/* x264_encoder_maximum_delayed_frames( x264_t * ):
* return the maximum number of delayed (buffered) frames that can occur with the current
* parameters. */
-int x264_encoder_maximum_delayed_frames( x264_t *h );
+X264_API int x264_encoder_maximum_delayed_frames( x264_t * );
/* x264_encoder_intra_refresh:
* If an intra refresh is not in progress, begin one with the next P-frame.
* If an intra refresh is in progress, begin one as soon as the current one finishes.
@@ -930,7 +951,7 @@ int x264_encoder_maximum_delayed_frames( x264_t *h );
* behavior is undefined.
*
* Should not be called during an x264_encoder_encode. */
-void x264_encoder_intra_refresh( x264_t * );
+X264_API void x264_encoder_intra_refresh( x264_t * );
/* x264_encoder_invalidate_reference:
* An interactive error resilience tool, designed for use in a low-latency one-encoder-few-clients
* system. When the client has packet loss or otherwise incorrectly decodes a frame, the encoder
@@ -953,7 +974,7 @@ void x264_encoder_intra_refresh( x264_t * );
* Should not be called during an x264_encoder_encode, but multiple calls can be made simultaneously.
*
* Returns 0 on success, negative on failure. */
-int x264_encoder_invalidate_reference( x264_t *, int64_t pts );
+X264_API int x264_encoder_invalidate_reference( x264_t *, int64_t pts );
#ifdef __cplusplus
}
diff --git a/Live/src/main/cpp/include/x264/x264_config.h b/Live/src/main/cpp/include/x264/x264_config.h
index 1e0d3776..b18ce033 100644
--- a/Live/src/main/cpp/include/x264/x264_config.h
+++ b/Live/src/main/cpp/include/x264/x264_config.h
@@ -1,6 +1,6 @@
-#define X264_BIT_DEPTH 8
#define X264_GPL 1
#define X264_INTERLACED 1
+#define X264_BIT_DEPTH 0
#define X264_CHROMA_FORMAT 0
#define X264_VERSION ""
-#define X264_POINTVER "0.148.x"
+#define X264_POINTVER "0.159.x"
diff --git a/Live/src/main/cpp/live.c b/Live/src/main/cpp/live.c
deleted file mode 100644
index b2ecfa6d..00000000
--- a/Live/src/main/cpp/live.c
+++ /dev/null
@@ -1,480 +0,0 @@
-#include
-#include
-#include "include/x264/x264.h"
-#include
-#include "include/rtmp/rtmp.h"
-#include "include/faac/faac.h"
-#include
-#include "queue.h"
-#include
-
-#define TAG "FrankLive"
-#define LOGI(format, ...) __android_log_print(ANDROID_LOG_INFO, TAG, format, ##__VA_ARGS__)
-#define LOGE(format, ...) __android_log_print(ANDROID_LOG_ERROR, TAG, format, ##__VA_ARGS__)
-
-x264_picture_t picture_in;
-x264_picture_t picture_out;
-int y_len, uv_len;
-x264_t *video_encode_handle;
-faacEncHandle *audio_encode_handle;
-uint32_t start_time;
-pthread_cond_t cond;
-pthread_mutex_t mutex;
-char *url_path;
-int is_pushing = FALSE;
-unsigned long inputSamples;
-unsigned long maxOutputBytes;
-//子线程回调给Java需要用到JavaVM
-JavaVM* javaVM;
-//调用类
-jobject jobject_error;
-
-/***************与Java层对应**************/
-//视频编码器打开失败
-const int ERROR_VIDEO_ENCODER_OPEN = 0x01;
-//视频帧编码失败
-const int ERROR_VIDEO_ENCODE = 0x02;
-//音频编码器打开失败
-const int ERROR_AUDIO_ENCODER_OPEN = 0x03;
-//音频帧编码失败
-const int ERROR_AUDIO_ENCODE = 0x04;
-//RTMP连接失败
-const int ERROR_RTMP_CONNECT = 0x05;
-//RTMP连接流失败
-const int ERROR_RTMP_CONNECT_STREAM = 0x06;
-//RTMP发送数据包失败
-const int ERROR_RTMP_SEND_PACKAT = 0x07;
-/***************与Java层对应**************/
-
-void add_rtmp_packet(RTMPPacket *pPacket);
-void add_x264_body(uint8_t *buf, int len);
-void add_x264_key_header(unsigned char sps[100], unsigned char pps[100], int len, int pps_len);
-void add_aac_body(unsigned char *buf, int len);
-void add_aac_header();
-
-//当调用System.loadLibrary时,会回调这个方法
-jint JNICALL JNI_OnLoad(JavaVM* vm, void* reserved){
- javaVM = vm;
- return JNI_VERSION_1_6;
-}
-
-//回调异常给java
-void throw_error_to_java(int error_code){
- JNIEnv* env;
- (*javaVM)->AttachCurrentThread(javaVM, &env, NULL);
- jclass jclazz = (*env)->GetObjectClass(env, jobject_error);
- jmethodID jmethod = (*env)->GetMethodID(env, jclazz, "errorFromNative", "(I)V");
- (*env)->CallVoidMethod(env, jobject_error, jmethod, error_code);
- (*javaVM)->DetachCurrentThread(javaVM);
-}
-
-//推流线程
-void *push_thread(void * args){
- //建立RTMP连接
- RTMP* rtmp = RTMP_Alloc();
- if(!rtmp){
- LOGE("RTMP_Alloc fail...");
- goto end;
- }
- RTMP_Init(rtmp);
- RTMP_SetupURL(rtmp, url_path);
- LOGI("url_path=%s", url_path);
- RTMP_EnableWrite(rtmp);
- rtmp->Link.timeout = 10;
- if(!RTMP_Connect(rtmp, NULL)){
- LOGE("RTMP_Connect fail...");
- throw_error_to_java(ERROR_RTMP_CONNECT);
- goto end;
- }
- LOGI("RTMP_Connect success...");
- if(!RTMP_ConnectStream(rtmp, 0)){
- LOGE("RTMP_ConnectStream fail...");
- throw_error_to_java(ERROR_RTMP_CONNECT_STREAM);
- goto end;
- }
- LOGI("RTMP_ConnectStream success...");
-
- //开始计时
- start_time = RTMP_GetTime();
- is_pushing = TRUE;
- //发送一个ACC HEADER
- add_aac_header();
- //循环推流
- while(is_pushing) {
- pthread_mutex_lock(&mutex);
- pthread_cond_wait(&cond, &mutex);
- //从队头去一个RTMP包出来
- RTMPPacket *packet = queue_get_first();
- if(packet){
- queue_delete_first();
- //发送rtmp包,true代表rtmp内部有缓存
- int ret = RTMP_SendPacket(rtmp, packet, TRUE);
- if(!ret){
- LOGE("RTMP_SendPacket fail...");
- RTMPPacket_Free(packet);
- pthread_mutex_unlock(&mutex);
- throw_error_to_java(ERROR_RTMP_SEND_PACKAT);
- goto end;
- }
- RTMPPacket_Free(packet);
- }
- pthread_mutex_unlock(&mutex);
- }
- end:
- LOGI("free all the thing about rtmp...");
- RTMP_Close(rtmp);
- free(rtmp);
- free(url_path);
- return 0;
-}
-
-JNIEXPORT jint JNICALL
-Java_com_frank_live_LiveUtil_native_1start(JNIEnv *env, jobject instance, jstring url_) {
- const char *url = (*env)->GetStringUTFChars(env, url_, 0);
- url_path = malloc(strlen(url) + 1);
- memset(url_path, 0, strlen(url) + 1);
- memcpy(url_path, url, strlen(url));
- //创建队列
- create_queue();
- //初始化互斥锁和条件变量
- pthread_mutex_init(&mutex, NULL);
- pthread_cond_init(&cond, NULL);
- pthread_t push_thread_id;
- //创建消费线程推流
- pthread_create(&push_thread_id, NULL, push_thread, NULL);
- (*env)->ReleaseStringUTFChars(env, url_, url);
-
- jobject_error= (*env)->NewGlobalRef(env, instance);
- return 0;
-}
-
-//视频编码器x264参数配置
-JNIEXPORT void JNICALL
-Java_com_frank_live_LiveUtil_setVideoParam(JNIEnv *env, jobject instance, jint width, jint height,
- jint bitRate, jint frameRate) {
- y_len = width * height;
- uv_len = y_len/4;
-
- x264_param_t param;
- //默认设置
- x264_param_default_preset(¶m, "ultrafast", "zerolatency");
- param.i_csp = X264_CSP_I420;//YUV420SP
- param.i_width = width;
- param.i_height = height;
- param.b_vfr_input = 0;//码率控制不通过timebase和timestamp,通过fps控制
- param.b_repeat_headers = 1;//每帧传入sps和pps,提高视频纠错能力
- param.i_level_idc = 51;//最大level:resolution@frameRate
- param.rc.i_rc_method = X264_RC_CRF;//控制恒定码率 CRF:恒定码率;CQP:恒定质量;ABR:平均码率
- param.rc.i_bitrate = bitRate;//码率
- param.rc.i_vbv_max_bitrate = (int) (bitRate * 1.2);//瞬间最大码率
- param.i_fps_num = (uint32_t) frameRate;//帧率分子
- param.i_fps_den = 1;//帧率分母
- param.i_timebase_num = param.i_fps_den;//时间基分子
- param.i_timebase_den = param.i_fps_num;//时间基分母
- param.i_threads = 1;//编码线程数
- //设置profile档次,"baseline"代表没有B帧
- x264_param_apply_profile(¶m, "baseline");
- //初始化图像
- x264_picture_alloc(&picture_in, param.i_csp, param.i_width, param.i_height);
- //打开编码器
- video_encode_handle = x264_encoder_open(¶m);
- if(video_encode_handle){
- LOGI("x264_encoder_open success...");
- } else{
- LOGE("x264_encoder_open fail...");
- throw_error_to_java(ERROR_VIDEO_ENCODER_OPEN);
- }
-}
-
-//音频编码器FAAC参数配置
-JNIEXPORT void JNICALL
-Java_com_frank_live_LiveUtil_setAudioParam(JNIEnv *env, jobject instance, jint sampleRate, jint numChannels) {
- inputSamples;
- maxOutputBytes;
- audio_encode_handle = faacEncOpen((unsigned long) sampleRate,
- (unsigned int) numChannels, &inputSamples, &maxOutputBytes);
- if(!audio_encode_handle){
- LOGE("faacEncOpen fail...");
- throw_error_to_java(ERROR_AUDIO_ENCODER_OPEN);
- return;
- }
- LOGI("faacEncOpen success...");
- faacEncConfigurationPtr configPtr = faacEncGetCurrentConfiguration(audio_encode_handle);
- configPtr->bandWidth = 0;
- configPtr->mpegVersion = MPEG4;//MPEG版本
- configPtr->outputFormat = 0;//包含ADTS头
- configPtr->useTns = 1;//时域噪音控制
- configPtr->useLfe = 0;
- configPtr->allowMidside = 1;
- configPtr->aacObjectType = LOW;
- configPtr->quantqual = 100;//量化
- configPtr->shortctl = SHORTCTL_NORMAL;
- int result = faacEncSetConfiguration(audio_encode_handle, configPtr);
- if(result){
- LOGI("faacEncSetConfiguration success...");
- } else{
- LOGE("faacEncSetConfiguration fail...");
- throw_error_to_java(ERROR_AUDIO_ENCODER_OPEN);
- }
-}
-
-//添加RTMPPacket包到队列中
-void add_rtmp_packet(RTMPPacket *pPacket) {
- pthread_mutex_lock(&mutex);
- if(is_pushing){
- queue_append_last(pPacket);
- }
- pthread_cond_signal(&cond);
- pthread_mutex_unlock(&mutex);
-}
-
-//添加SPS和PPS header
-void add_x264_key_header(unsigned char sps[100], unsigned char pps[100], int sps_len, int pps_len) {
- int body_size = 16 + sps_len + pps_len;
- RTMPPacket *packet = malloc(sizeof(RTMPPacket));
- RTMPPacket_Alloc(packet, body_size);
- RTMPPacket_Reset(packet);
- unsigned char* body = (unsigned char *) packet->m_body;
- int i = 0;
- body[i++] = 0x17;//VideoHeadType 0-3:FrameType(KeyFrame=1);4-7:CodecId(AVC=7)
- body[i++] = 0x00;//AVC PacketType
-
- body[i++] = 0x00;//composition type 24bit
- body[i++] = 0x00;
- body[i++] = 0x00;
-
- body[i++] = 0x01;//AVC decoder configuration record
- body[i++] = sps[1];
- body[i++] = sps[2];
- body[i++] = sps[3];
-
- body[i++] = 0xFF;
-
- body[i++] = 0xE1;//sps
- body[i++] = (unsigned char) ((sps_len >> 8) & 0xFF);
- body[i++] = (unsigned char) (sps_len & 0xFF);
- memcpy(&body[i], sps, (size_t) sps_len);
- i += sps_len;
-
- body[i++] = 0x01;//pps
- body[i++] = (unsigned char) ((pps_len >> 8) & 0xFF);
- body[i++] = (unsigned char) (pps_len & 0xFF);
- memcpy(&body[i], pps, (size_t) pps_len);
- i += pps_len;
-
- packet->m_packetType = RTMP_PACKET_TYPE_VIDEO;
- packet->m_nBodySize = (uint32_t) body_size;
- packet->m_nTimeStamp = 0;
- packet->m_hasAbsTimestamp = 0;
- packet->m_nChannel = 0x04;
- packet->m_headerType = RTMP_PACKET_SIZE_MEDIUM;
-
- add_rtmp_packet(packet);
-}
-
-//添加x264的body
-void add_x264_body(uint8_t *buf, int len) {
- if(buf[2] == 0x01){//00 00 01
- buf += 3;
- len -= 3;
- } else if (buf[3] == 0x01){//00 00 00 01
- buf += 4;
- len -= 4;
- }
- int body_size = len + 9;//
- RTMPPacket *packet = malloc(sizeof(RTMPPacket));
- RTMPPacket_Alloc(packet, body_size);
- RTMPPacket_Reset(packet);
- unsigned char *body = (unsigned char *) packet->m_body;
- int type = buf[0] & 0x1F;
- if(type == NAL_SLICE_IDR){//关键帧
- body[0] = 0x17;
- } else{
- body[0] = 0x27;
- }
- body[1] = 0x01;
- body[2] = 0x00;
- body[3] = 0x00;
- body[4] = 0x00;
-
- body[5] = (unsigned char) ((len >> 24) & 0xFF);
- body[6] = (unsigned char) ((len >> 16) & 0xFF);
- body[7] = (unsigned char) ((len >> 8) & 0xFF);
- body[8] = (unsigned char) (len & 0xFF);
-
- memcpy(&body[9], buf, (size_t) len);
- packet->m_headerType = RTMP_PACKET_SIZE_LARGE;
- packet->m_hasAbsTimestamp = 0;
- packet->m_nBodySize = (uint32_t) body_size;
- packet->m_nChannel = 0x04;
- packet->m_packetType = RTMP_PACKET_TYPE_VIDEO;
- packet->m_nTimeStamp = RTMP_GetTime() - start_time;
-
- add_rtmp_packet(packet);
-}
-
-//推送视频流
-JNIEXPORT void JNICALL
-Java_com_frank_live_LiveUtil_pushVideo(JNIEnv *env, jobject instance, jbyteArray data_) {
- //NV21转成YUV420P
- jbyte *nv21_buffer = (*env)->GetByteArrayElements(env, data_, NULL);
- //Y相同,直接拷贝
- memcpy(picture_in.img.plane[0], nv21_buffer, (size_t) y_len);
- jbyte *v_buffer = (jbyte *) picture_in.img.plane[2];
- jbyte *u_buffer = (jbyte *) picture_in.img.plane[1];
- int i;
- //U和V交换
- for(i=0; iReleaseByteArrayElements(env, data_, nv21_buffer, 0);
-}
-
-//添加AAC header
-void add_aac_header() {
- unsigned char *ppBuffer;
- unsigned long pSize;
- faacEncGetDecoderSpecificInfo(audio_encode_handle, &ppBuffer, &pSize);
- int body_size = (int) (2 + pSize);
- RTMPPacket* packet = malloc(sizeof(RTMPPacket));
- RTMPPacket_Alloc(packet, body_size);
- RTMPPacket_Reset(packet);
- unsigned char* body = (unsigned char *) packet->m_body;
- //两字节头
- //soundFormat(4bits):10->aac;soundRate(2bits):3->44kHz;soundSize(1bit):1->pcm_16bit;soundType(1bit):1->stereo
- body[0] = 0xAF;
- //AACPacketType:0表示AAC sequence header
- body[1] = 0x00;
-
- memcpy(&body[2], ppBuffer, (size_t) pSize);
- packet->m_packetType = RTMP_PACKET_TYPE_AUDIO;
- packet->m_nBodySize = (uint32_t) body_size;
- packet->m_nChannel = 4;
- packet->m_nTimeStamp = 0;
- packet->m_hasAbsTimestamp = 0;
- packet->m_headerType = RTMP_PACKET_SIZE_MEDIUM;
- add_rtmp_packet(packet);
- free(ppBuffer);
-}
-
-//添加AAC body
-void add_aac_body(unsigned char *buf, int len) {
- int body_size = 2 + len;
- RTMPPacket* packet = malloc(sizeof(RTMPPacket));
- RTMPPacket_Alloc(packet, body_size);
- RTMPPacket_Reset(packet);
- unsigned char* body = (unsigned char *) packet->m_body;
- //两字节头
- //soundFormat(4bits):10->aac;soundRate(2bits):3->44kHz;soundSize(1bit):1->pcm_16bit;soundType(1bit):1->stereo
- body[0] = 0xAF;
- //PackageType(StreamType):0->AAC带ADTS头;1->AAC RAW
- body[1] = 0x01;
-
- memcpy(&body[2], buf, (size_t) len);
- packet->m_packetType = RTMP_PACKET_TYPE_AUDIO;
- packet->m_nBodySize = (uint32_t) body_size;
- packet->m_nChannel = 4;
- packet->m_nTimeStamp = RTMP_GetTime() - start_time;
- packet->m_hasAbsTimestamp = 0;
- packet->m_headerType = RTMP_PACKET_SIZE_LARGE;
- add_rtmp_packet(packet);
- free(buf);
-}
-
-//推送音频流
-JNIEXPORT void JNICALL
-Java_com_frank_live_LiveUtil_pushAudio(JNIEnv *env, jobject instance, jbyteArray data_, jint length) {
- jbyte *data = (*env)->GetByteArrayElements(env, data_, NULL);
- int* pcm_buf;
- unsigned char* aac_buf;
- pcm_buf = malloc(inputSamples * sizeof(int));
- aac_buf = malloc(maxOutputBytes * sizeof(unsigned char));
- int count = 0;
- unsigned int buffer_size = (unsigned int) (length / 2);
- unsigned short* buf = (unsigned short*) data;
- while (count < buffer_size){
- int audio_length = (int) inputSamples;
- if((count + audio_length) >= buffer_size){
- audio_length = buffer_size - count;
- }
- int i;
- for(i=0; iReleaseByteArrayElements(env, data_, data, 0);
- if(pcm_buf != NULL){
- free(pcm_buf);
- }
-}
-
-//停止推流
-JNIEXPORT void JNICALL
-Java_com_frank_live_LiveUtil_native_1stop(JNIEnv *env, jobject instance) {
- is_pushing = FALSE;
- LOGI("native_1stop");
-}
-
-//释放所有资源
-JNIEXPORT void JNICALL
-Java_com_frank_live_LiveUtil_native_1release(JNIEnv *env, jobject instance) {
- //清除x264的picture缓存
- x264_picture_clean(&picture_in);
- x264_picture_clean(&picture_out);
- //关闭音视频编码器
- x264_encoder_close(video_encode_handle);
- faacEncClose(audio_encode_handle);
- //删除全局引用
- (*env)->DeleteGlobalRef(env, jobject_error);
- (*javaVM)->DestroyJavaVM(javaVM);
- //销毁互斥锁和条件变量
- pthread_cond_destroy(&cond);
- pthread_mutex_destroy(&mutex);
- //退出线程
- pthread_exit(0);
-}
\ No newline at end of file
diff --git a/Live/src/main/cpp/queue.c b/Live/src/main/cpp/queue.c
deleted file mode 100644
index 6942c44f..00000000
--- a/Live/src/main/cpp/queue.c
+++ /dev/null
@@ -1,218 +0,0 @@
-#include
-#include
-
-typedef struct queue_node {
- struct queue_node* prev;
- struct queue_node* next;
- void *p;//节点的值
-} node;
-
-// 表头
-static node *phead = NULL;
-static int count = 0;
-
-static node* create_node(void *pval) {
- node *pnode = NULL;
- pnode = (node *) malloc(sizeof(node));
- if (pnode) {
- // 默认的,pnode的前一节点和后一节点都指向它自身
- pnode->prev = pnode->next = pnode;
- // 节点的值为pval
- pnode->p = pval;
- }
- return pnode;
-}
-
-/**
- * 创建双向链表
- * @return 成功,返回0;否则,返回-1。
- */
-int create_queue() {
- phead = create_node(NULL);
- if (!phead) {
- return -1;
- }
- count = 0;
- return 0;
-}
-
-/**
- * 判断双向链表是否为空
- * @return 0为空
- */
-int queue_is_empty() {
- return count == 0;
-}
-
-/**
- * 获取双向链表的大小
- * @return size
- */
-int queue_size() {
- return count;
-}
-
-/**
- * 获取链表中指定位置的节点
- */
-
-static node* get_node(int index) {
- if (index < 0 || index >= count) {
- return NULL;
- }
- if (index <= (count / 2)) {
- int i = 0;
- node *pnode = phead->next;
- while ((i++) < index)
- pnode = pnode->next;
- return pnode;
- }
- int j = 0;
- int rindex = count - index - 1;
- node *rnode = phead->prev;
- while ((j++) < rindex)
- rnode = rnode->prev;
- return rnode;
-}
-
-/**
- * 获取链表中指定位置的元素
- * @param index index
- * @return 指定位置的元素
- */
-void* queue_get(int index) {
- node *pindex = get_node(index);
- if (!pindex) {
- return NULL;
- }
- return pindex->p;
-}
-
-/**
- * 获取链表中第1个元素的值
- * @return 第1个元素的值
- */
-void* queue_get_first() {
- return queue_get(0);
-}
-
-/**
- * 获取链表中最后1个元素的值
- * @return 最后1个元素的值
- */
-void* queue_get_last() {
- return queue_get(count - 1);
-}
-
-/**
- * 插入到index位置
- * @param index index
- * @param pval pval
- * @return 是否插入成功
- */
-int queue_insert(int index, void* pval) {
- // 插入表头
- if (index == 0)
- return queue_insert_first(pval);
- // 获取要插入的位置对应的节点
- node *pindex = get_node(index);
- if (!pindex)
- return -1;
-// 创建“节点”
- node *pnode = create_node(pval);
- if (!pnode)
- return -1;
- pnode->prev = pindex->prev;
- pnode->next = pindex;
- pindex->prev->next = pnode;
- pindex->prev = pnode;
- // 节点个数+1
- count++;
- return 0;
-}
-
-/**
- * 插入到链表头
- * @param pval
- * @return 是否插入成功
- */
-int queue_insert_first(void *pval) {
- node *pnode = create_node(pval);
- if (!pnode)
- return -1;
- pnode->prev = phead;
- pnode->next = phead->next;
- phead->next->prev = pnode;
- phead->next = pnode;
- count++;
- return 0;
-}
-
-/**
- * 插入链表尾
- * @param pval
- * @return 是否插入成功
- */
-int queue_append_last(void *pval) {
- node *pnode = create_node(pval);
- if (!pnode)
- return -1;
- pnode->next = phead;
- pnode->prev = phead->prev;
- phead->prev->next = pnode;
- phead->prev = pnode;
- count++;
- return 0;
-}
-
-/**
- * 删除双向链表中index位置的节点
- * @param index index
- * @return 成功,返回0;否则,返回-1
- */
-int queue_delete(int index) {
- node *pindex = get_node(index);
- if (!pindex) {
- return -1;
- }
- pindex->next->prev = pindex->prev;
- pindex->prev->next = pindex->next;
- free(pindex);
- count--;
- return 0;
-}
-
-/**
- * 删除第一个节点
- */
-int queue_delete_first() {
- return queue_delete(0);
-}
-
-/*
- * 删除最后一个节点
- */
-int queue_delete_last() {
- return queue_delete(count - 1);
-}
-
-/**
- * 释放双向链表
- * @return 成功,返回0;否则,返回-1。
- */
-int destroy_queue() {
- if (!phead) {
- return -1;
- }
- node *pnode = phead->next;
- node *ptmp = NULL;
- while (pnode != phead) {
- ptmp = pnode;
- pnode = pnode->next;
- free(ptmp);
- }
- free(phead);
- phead = NULL;
- count = 0;
- return 0;
-}
diff --git a/Live/src/main/cpp/queue.h b/Live/src/main/cpp/queue.h
deleted file mode 100644
index 1dbdd297..00000000
--- a/Live/src/main/cpp/queue.h
+++ /dev/null
@@ -1,29 +0,0 @@
-#ifndef _QUQEUE_H
-#define _QUQEUE_H
-// 新建“双向链表”。成功,返回表头;否则,返回NULL
-extern int create_queue();
-// 撤销“双向链表”。成功,返回0;否则,返回-1
-extern int destroy_queue();
-// “双向链表是否为空”。为空的话返回1;否则,返回0。
-extern int queue_is_empty();
-// 返回“双向链表的大小”
-extern int queue_size();
-// 获取“双向链表中第index位置的元素”。成功,返回节点指针;否则,返回NULL。
-extern void* queue_get(int index);
-// 获取“双向链表中第1个元素”。成功,返回节点指针;否则,返回NULL。
-extern void* queue_get_first();
-// 获取“双向链表中最后1个元素”。成功,返回节点指针;否则,返回NULL。
-extern void* queue_get_last();
-// 将“value”插入到index位置。成功,返回0;否则,返回-1。
-extern int queue_insert(int index, void *pval);
-// 将“value”插入到表头位置。成功,返回0;否则,返回-1。
-extern int queue_insert_first(void *pval);
-// 将“value”插入到末尾位置。成功,返回0;否则,返回-1。
-extern int queue_append_last(void *pval);
-// 删除“双向链表中index位置的节点”。成功,返回0;否则,返回-1
-extern int queue_delete(int index);
-// 删除第一个节点。成功,返回0;否则,返回-1
-extern int queue_delete_first();
-// 删除组后一个节点。成功,返回0;否则,返回-1
-extern int queue_delete_last();
-#endif//_QUQEUE_H
diff --git a/Live/src/main/cpp/rtmp/CMakeLists.txt b/Live/src/main/cpp/rtmp/CMakeLists.txt
new file mode 100644
index 00000000..e077fe97
--- /dev/null
+++ b/Live/src/main/cpp/rtmp/CMakeLists.txt
@@ -0,0 +1,16 @@
+cmake_minimum_required(VERSION 3.10.2)
+
+project(rtmp)
+
+
+set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DNO_CRYPTO")
+
+add_library(rtmp
+
+ STATIC
+
+ amf.c
+ hashswf.c
+ log.c
+ parseurl.c
+ rtmp.c)
\ No newline at end of file
diff --git a/Live/src/main/cpp/rtmp/amf.c b/Live/src/main/cpp/rtmp/amf.c
new file mode 100644
index 00000000..7fa289e3
--- /dev/null
+++ b/Live/src/main/cpp/rtmp/amf.c
@@ -0,0 +1,1186 @@
+/*
+ * Copyright (C) 2005-2008 Team XBMC
+ * http://www.xbmc.org
+ * Copyright (C) 2008-2009 Andrej Stepanchuk
+ * Copyright (C) 2009-2010 Howard Chu
+ *
+ * This file is part of librtmp.
+ *
+ * librtmp is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1,
+ * or (at your option) any later version.
+ *
+ * librtmp is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with librtmp see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/lgpl.html
+ */
+
+#include
+#include
+#include
+
+#include "rtmp_sys.h"
+#include "amf.h"
+#include "log.h"
+#include "bytes.h"
+
+static const AMFObjectProperty AMFProp_Invalid = { {0, 0}, AMF_INVALID };
+static const AVal AV_empty = { 0, 0 };
+
+/* Data is Big-Endian */
+unsigned short
+AMF_DecodeInt16(const char *data)
+{
+ unsigned char *c = (unsigned char *) data;
+ unsigned short val;
+ val = (c[0] << 8) | c[1];
+ return val;
+}
+
+unsigned int
+AMF_DecodeInt24(const char *data)
+{
+ unsigned char *c = (unsigned char *) data;
+ unsigned int val;
+ val = (c[0] << 16) | (c[1] << 8) | c[2];
+ return val;
+}
+
+unsigned int
+AMF_DecodeInt32(const char *data)
+{
+ unsigned char *c = (unsigned char *)data;
+ unsigned int val;
+ val = (c[0] << 24) | (c[1] << 16) | (c[2] << 8) | c[3];
+ return val;
+}
+
+void
+AMF_DecodeString(const char *data, AVal *bv)
+{
+ bv->av_len = AMF_DecodeInt16(data);
+ bv->av_val = (bv->av_len > 0) ? (char *)data + 2 : NULL;
+}
+
+void
+AMF_DecodeLongString(const char *data, AVal *bv)
+{
+ bv->av_len = AMF_DecodeInt32(data);
+ bv->av_val = (bv->av_len > 0) ? (char *)data + 4 : NULL;
+}
+
+double
+AMF_DecodeNumber(const char *data)
+{
+ double dVal;
+#if __FLOAT_WORD_ORDER == __BYTE_ORDER
+#if __BYTE_ORDER == __BIG_ENDIAN
+ memcpy(&dVal, data, 8);
+#elif __BYTE_ORDER == __LITTLE_ENDIAN
+ unsigned char *ci, *co;
+ ci = (unsigned char *)data;
+ co = (unsigned char *)&dVal;
+ co[0] = ci[7];
+ co[1] = ci[6];
+ co[2] = ci[5];
+ co[3] = ci[4];
+ co[4] = ci[3];
+ co[5] = ci[2];
+ co[6] = ci[1];
+ co[7] = ci[0];
+#endif
+#else
+#if __BYTE_ORDER == __LITTLE_ENDIAN /* __FLOAT_WORD_ORER == __BIG_ENDIAN */
+ unsigned char *ci, *co;
+ ci = (unsigned char *)data;
+ co = (unsigned char *)&dVal;
+ co[0] = ci[3];
+ co[1] = ci[2];
+ co[2] = ci[1];
+ co[3] = ci[0];
+ co[4] = ci[7];
+ co[5] = ci[6];
+ co[6] = ci[5];
+ co[7] = ci[4];
+#else /* __BYTE_ORDER == __BIG_ENDIAN && __FLOAT_WORD_ORER == __LITTLE_ENDIAN */
+ unsigned char *ci, *co;
+ ci = (unsigned char *)data;
+ co = (unsigned char *)&dVal;
+ co[0] = ci[4];
+ co[1] = ci[5];
+ co[2] = ci[6];
+ co[3] = ci[7];
+ co[4] = ci[0];
+ co[5] = ci[1];
+ co[6] = ci[2];
+ co[7] = ci[3];
+#endif
+#endif
+ return dVal;
+}
+
+int
+AMF_DecodeBoolean(const char *data)
+{
+ return *data != 0;
+}
+
+char *
+AMF_EncodeInt16(char *output, char *outend, short nVal)
+{
+ if (output+2 > outend)
+ return NULL;
+
+ output[1] = nVal & 0xff;
+ output[0] = nVal >> 8;
+ return output+2;
+}
+
+char *
+AMF_EncodeInt24(char *output, char *outend, int nVal)
+{
+ if (output+3 > outend)
+ return NULL;
+
+ output[2] = nVal & 0xff;
+ output[1] = nVal >> 8;
+ output[0] = nVal >> 16;
+ return output+3;
+}
+
+char *
+AMF_EncodeInt32(char *output, char *outend, int nVal)
+{
+ if (output+4 > outend)
+ return NULL;
+
+ output[3] = nVal & 0xff;
+ output[2] = nVal >> 8;
+ output[1] = nVal >> 16;
+ output[0] = nVal >> 24;
+ return output+4;
+}
+
+char *
+AMF_EncodeString(char *output, char *outend, const AVal *bv)
+{
+ if ((bv->av_len < 65536 && output + 1 + 2 + bv->av_len > outend) ||
+ output + 1 + 4 + bv->av_len > outend)
+ return NULL;
+
+ if (bv->av_len < 65536)
+ {
+ *output++ = AMF_STRING;
+
+ output = AMF_EncodeInt16(output, outend, bv->av_len);
+ }
+ else
+ {
+ *output++ = AMF_LONG_STRING;
+
+ output = AMF_EncodeInt32(output, outend, bv->av_len);
+ }
+ memcpy(output, bv->av_val, bv->av_len);
+ output += bv->av_len;
+
+ return output;
+}
+
+char *
+AMF_EncodeNumber(char *output, char *outend, double dVal)
+{
+ if (output+1+8 > outend)
+ return NULL;
+
+ *output++ = AMF_NUMBER; /* type: Number */
+
+#if __FLOAT_WORD_ORDER == __BYTE_ORDER
+#if __BYTE_ORDER == __BIG_ENDIAN
+ memcpy(output, &dVal, 8);
+#elif __BYTE_ORDER == __LITTLE_ENDIAN
+ {
+ unsigned char *ci, *co;
+ ci = (unsigned char *)&dVal;
+ co = (unsigned char *)output;
+ co[0] = ci[7];
+ co[1] = ci[6];
+ co[2] = ci[5];
+ co[3] = ci[4];
+ co[4] = ci[3];
+ co[5] = ci[2];
+ co[6] = ci[1];
+ co[7] = ci[0];
+ }
+#endif
+#else
+#if __BYTE_ORDER == __LITTLE_ENDIAN /* __FLOAT_WORD_ORER == __BIG_ENDIAN */
+ {
+ unsigned char *ci, *co;
+ ci = (unsigned char *)&dVal;
+ co = (unsigned char *)output;
+ co[0] = ci[3];
+ co[1] = ci[2];
+ co[2] = ci[1];
+ co[3] = ci[0];
+ co[4] = ci[7];
+ co[5] = ci[6];
+ co[6] = ci[5];
+ co[7] = ci[4];
+ }
+#else /* __BYTE_ORDER == __BIG_ENDIAN && __FLOAT_WORD_ORER == __LITTLE_ENDIAN */
+ {
+ unsigned char *ci, *co;
+ ci = (unsigned char *)&dVal;
+ co = (unsigned char *)output;
+ co[0] = ci[4];
+ co[1] = ci[5];
+ co[2] = ci[6];
+ co[3] = ci[7];
+ co[4] = ci[0];
+ co[5] = ci[1];
+ co[6] = ci[2];
+ co[7] = ci[3];
+ }
+#endif
+#endif
+
+ return output+8;
+}
+
+char *
+AMF_EncodeBoolean(char *output, char *outend, int bVal)
+{
+ if (output+2 > outend)
+ return NULL;
+
+ *output++ = AMF_BOOLEAN;
+
+ *output++ = bVal ? 0x01 : 0x00;
+
+ return output;
+}
+
+char *
+AMF_EncodeNamedString(char *output, char *outend, const AVal *strName, const AVal *strValue)
+{
+ if (output+2+strName->av_len > outend)
+ return NULL;
+ output = AMF_EncodeInt16(output, outend, strName->av_len);
+
+ memcpy(output, strName->av_val, strName->av_len);
+ output += strName->av_len;
+
+ return AMF_EncodeString(output, outend, strValue);
+}
+
+char *
+AMF_EncodeNamedNumber(char *output, char *outend, const AVal *strName, double dVal)
+{
+ if (output+2+strName->av_len > outend)
+ return NULL;
+ output = AMF_EncodeInt16(output, outend, strName->av_len);
+
+ memcpy(output, strName->av_val, strName->av_len);
+ output += strName->av_len;
+
+ return AMF_EncodeNumber(output, outend, dVal);
+}
+
+char *
+AMF_EncodeNamedBoolean(char *output, char *outend, const AVal *strName, int bVal)
+{
+ if (output+2+strName->av_len > outend)
+ return NULL;
+ output = AMF_EncodeInt16(output, outend, strName->av_len);
+
+ memcpy(output, strName->av_val, strName->av_len);
+ output += strName->av_len;
+
+ return AMF_EncodeBoolean(output, outend, bVal);
+}
+
+void
+AMFProp_GetName(AMFObjectProperty *prop, AVal *name)
+{
+ *name = prop->p_name;
+}
+
+void
+AMFProp_SetName(AMFObjectProperty *prop, AVal *name)
+{
+ prop->p_name = *name;
+}
+
+AMFDataType
+AMFProp_GetType(AMFObjectProperty *prop)
+{
+ return prop->p_type;
+}
+
+double
+AMFProp_GetNumber(AMFObjectProperty *prop)
+{
+ return prop->p_vu.p_number;
+}
+
+int
+AMFProp_GetBoolean(AMFObjectProperty *prop)
+{
+ return prop->p_vu.p_number != 0;
+}
+
+void
+AMFProp_GetString(AMFObjectProperty *prop, AVal *str)
+{
+ *str = prop->p_vu.p_aval;
+}
+
+void
+AMFProp_GetObject(AMFObjectProperty *prop, AMFObject *obj)
+{
+ *obj = prop->p_vu.p_object;
+}
+
+int
+AMFProp_IsValid(AMFObjectProperty *prop)
+{
+ return prop->p_type != AMF_INVALID;
+}
+
+char *
+AMFProp_Encode(AMFObjectProperty *prop, char *pBuffer, char *pBufEnd)
+{
+ if (prop->p_type == AMF_INVALID)
+ return NULL;
+
+ if (prop->p_type != AMF_NULL && pBuffer + prop->p_name.av_len + 2 + 1 >= pBufEnd)
+ return NULL;
+
+ if (prop->p_type != AMF_NULL && prop->p_name.av_len)
+ {
+ *pBuffer++ = prop->p_name.av_len >> 8;
+ *pBuffer++ = prop->p_name.av_len & 0xff;
+ memcpy(pBuffer, prop->p_name.av_val, prop->p_name.av_len);
+ pBuffer += prop->p_name.av_len;
+ }
+
+ switch (prop->p_type)
+ {
+ case AMF_NUMBER:
+ pBuffer = AMF_EncodeNumber(pBuffer, pBufEnd, prop->p_vu.p_number);
+ break;
+
+ case AMF_BOOLEAN:
+ pBuffer = AMF_EncodeBoolean(pBuffer, pBufEnd, prop->p_vu.p_number != 0);
+ break;
+
+ case AMF_STRING:
+ pBuffer = AMF_EncodeString(pBuffer, pBufEnd, &prop->p_vu.p_aval);
+ break;
+
+ case AMF_NULL:
+ if (pBuffer+1 >= pBufEnd)
+ return NULL;
+ *pBuffer++ = AMF_NULL;
+ break;
+
+ case AMF_OBJECT:
+ pBuffer = AMF_Encode(&prop->p_vu.p_object, pBuffer, pBufEnd);
+ break;
+
+ default:
+ RTMP_Log(RTMP_LOGERROR, "%s, invalid type. %d", __FUNCTION__, prop->p_type);
+ pBuffer = NULL;
+ };
+
+ return pBuffer;
+}
+
+#define AMF3_INTEGER_MAX 268435455
+#define AMF3_INTEGER_MIN -268435456
+
+int
+AMF3ReadInteger(const char *data, int32_t *valp)
+{
+ int i = 0;
+ int32_t val = 0;
+
+ while (i <= 2)
+ { /* handle first 3 bytes */
+ if (data[i] & 0x80)
+ { /* byte used */
+ val <<= 7; /* shift up */
+ val |= (data[i] & 0x7f); /* add bits */
+ i++;
+ }
+ else
+ {
+ break;
+ }
+ }
+
+ if (i > 2)
+ { /* use 4th byte, all 8bits */
+ val <<= 8;
+ val |= data[3];
+
+ /* range check */
+ if (val > AMF3_INTEGER_MAX)
+ val -= (1 << 29);
+ }
+ else
+ { /* use 7bits of last unparsed byte (0xxxxxxx) */
+ val <<= 7;
+ val |= data[i];
+ }
+
+ *valp = val;
+
+ return i > 2 ? 4 : i + 1;
+}
+
+int
+AMF3ReadString(const char *data, AVal *str)
+{
+ int32_t ref = 0;
+ int len;
+ assert(str != 0);
+
+ len = AMF3ReadInteger(data, &ref);
+ data += len;
+
+ if ((ref & 0x1) == 0)
+ { /* reference: 0xxx */
+ uint32_t refIndex = (ref >> 1);
+ RTMP_Log(RTMP_LOGDEBUG,
+ "%s, string reference, index: %d, not supported, ignoring!",
+ __FUNCTION__, refIndex);
+ return len;
+ }
+ else
+ {
+ uint32_t nSize = (ref >> 1);
+
+ str->av_val = (char *)data;
+ str->av_len = nSize;
+
+ return len + nSize;
+ }
+ return len;
+}
+
+int
+AMF3Prop_Decode(AMFObjectProperty *prop, const char *pBuffer, int nSize,
+ int bDecodeName)
+{
+ int nOriginalSize = nSize;
+ AMF3DataType type;
+
+ prop->p_name.av_len = 0;
+ prop->p_name.av_val = NULL;
+
+ if (nSize == 0 || !pBuffer)
+ {
+ RTMP_Log(RTMP_LOGDEBUG, "empty buffer/no buffer pointer!");
+ return -1;
+ }
+
+ /* decode name */
+ if (bDecodeName)
+ {
+ AVal name;
+ int nRes = AMF3ReadString(pBuffer, &name);
+
+ if (name.av_len <= 0)
+ return nRes;
+
+ prop->p_name = name;
+ pBuffer += nRes;
+ nSize -= nRes;
+ }
+
+ /* decode */
+ type = *pBuffer++;
+ nSize--;
+
+ switch (type)
+ {
+ case AMF3_UNDEFINED:
+ case AMF3_NULL:
+ prop->p_type = AMF_NULL;
+ break;
+ case AMF3_FALSE:
+ prop->p_type = AMF_BOOLEAN;
+ prop->p_vu.p_number = 0.0;
+ break;
+ case AMF3_TRUE:
+ prop->p_type = AMF_BOOLEAN;
+ prop->p_vu.p_number = 1.0;
+ break;
+ case AMF3_INTEGER:
+ {
+ int32_t res = 0;
+ int len = AMF3ReadInteger(pBuffer, &res);
+ prop->p_vu.p_number = (double)res;
+ prop->p_type = AMF_NUMBER;
+ nSize -= len;
+ break;
+ }
+ case AMF3_DOUBLE:
+ if (nSize < 8)
+ return -1;
+ prop->p_vu.p_number = AMF_DecodeNumber(pBuffer);
+ prop->p_type = AMF_NUMBER;
+ nSize -= 8;
+ break;
+ case AMF3_STRING:
+ case AMF3_XML_DOC:
+ case AMF3_XML:
+ {
+ int len = AMF3ReadString(pBuffer, &prop->p_vu.p_aval);
+ prop->p_type = AMF_STRING;
+ nSize -= len;
+ break;
+ }
+ case AMF3_DATE:
+ {
+ int32_t res = 0;
+ int len = AMF3ReadInteger(pBuffer, &res);
+
+ nSize -= len;
+ pBuffer += len;
+
+ if ((res & 0x1) == 0)
+ { /* reference */
+ uint32_t nIndex = (res >> 1);
+ RTMP_Log(RTMP_LOGDEBUG, "AMF3_DATE reference: %d, not supported!", nIndex);
+ }
+ else
+ {
+ if (nSize < 8)
+ return -1;
+
+ prop->p_vu.p_number = AMF_DecodeNumber(pBuffer);
+ nSize -= 8;
+ prop->p_type = AMF_NUMBER;
+ }
+ break;
+ }
+ case AMF3_OBJECT:
+ {
+ int nRes = AMF3_Decode(&prop->p_vu.p_object, pBuffer, nSize, TRUE);
+ if (nRes == -1)
+ return -1;
+ nSize -= nRes;
+ prop->p_type = AMF_OBJECT;
+ break;
+ }
+ case AMF3_ARRAY:
+ case AMF3_BYTE_ARRAY:
+ default:
+ RTMP_Log(RTMP_LOGDEBUG, "%s - AMF3 unknown/unsupported datatype 0x%02x, @0x%08X",
+ __FUNCTION__, (unsigned char)(*pBuffer), pBuffer);
+ return -1;
+ }
+
+ return nOriginalSize - nSize;
+}
+
+int
+AMFProp_Decode(AMFObjectProperty *prop, const char *pBuffer, int nSize,
+ int bDecodeName)
+{
+ int nOriginalSize = nSize;
+ int nRes;
+
+ prop->p_name.av_len = 0;
+ prop->p_name.av_val = NULL;
+
+ if (nSize == 0 || !pBuffer)
+ {
+ RTMP_Log(RTMP_LOGDEBUG, "%s: Empty buffer/no buffer pointer!", __FUNCTION__);
+ return -1;
+ }
+
+ if (bDecodeName && nSize < 4)
+ { /* at least name (length + at least 1 byte) and 1 byte of data */
+ RTMP_Log(RTMP_LOGDEBUG,
+ "%s: Not enough data for decoding with name, less than 4 bytes!",
+ __FUNCTION__);
+ return -1;
+ }
+
+ if (bDecodeName)
+ {
+ unsigned short nNameSize = AMF_DecodeInt16(pBuffer);
+ if (nNameSize > nSize - 2)
+ {
+ RTMP_Log(RTMP_LOGDEBUG,
+ "%s: Name size out of range: namesize (%d) > len (%d) - 2",
+ __FUNCTION__, nNameSize, nSize);
+ return -1;
+ }
+
+ AMF_DecodeString(pBuffer, &prop->p_name);
+ nSize -= 2 + nNameSize;
+ pBuffer += 2 + nNameSize;
+ }
+
+ if (nSize == 0)
+ {
+ return -1;
+ }
+
+ nSize--;
+
+ prop->p_type = *pBuffer++;
+ switch (prop->p_type)
+ {
+ case AMF_NUMBER:
+ if (nSize < 8)
+ return -1;
+ prop->p_vu.p_number = AMF_DecodeNumber(pBuffer);
+ nSize -= 8;
+ break;
+ case AMF_BOOLEAN:
+ if (nSize < 1)
+ return -1;
+ prop->p_vu.p_number = (double)AMF_DecodeBoolean(pBuffer);
+ nSize--;
+ break;
+ case AMF_STRING:
+ {
+ unsigned short nStringSize = AMF_DecodeInt16(pBuffer);
+
+ if (nSize < (long)nStringSize + 2)
+ return -1;
+ AMF_DecodeString(pBuffer, &prop->p_vu.p_aval);
+ nSize -= (2 + nStringSize);
+ break;
+ }
+ case AMF_OBJECT:
+ {
+ int nRes = AMF_Decode(&prop->p_vu.p_object, pBuffer, nSize, TRUE);
+ if (nRes == -1)
+ return -1;
+ nSize -= nRes;
+ break;
+ }
+ case AMF_MOVIECLIP:
+ {
+ RTMP_Log(RTMP_LOGERROR, "AMF_MOVIECLIP reserved!");
+ return -1;
+ break;
+ }
+ case AMF_NULL:
+ case AMF_UNDEFINED:
+ case AMF_UNSUPPORTED:
+ prop->p_type = AMF_NULL;
+ break;
+ case AMF_REFERENCE:
+ {
+ RTMP_Log(RTMP_LOGERROR, "AMF_REFERENCE not supported!");
+ return -1;
+ break;
+ }
+ case AMF_ECMA_ARRAY:
+ {
+ nSize -= 4;
+
+ /* next comes the rest, mixed array has a final 0x000009 mark and names, so its an object */
+ nRes = AMF_Decode(&prop->p_vu.p_object, pBuffer + 4, nSize, TRUE);
+ if (nRes == -1)
+ return -1;
+ nSize -= nRes;
+ prop->p_type = AMF_OBJECT;
+ break;
+ }
+ case AMF_OBJECT_END:
+ {
+ return -1;
+ break;
+ }
+ case AMF_STRICT_ARRAY:
+ {
+ unsigned int nArrayLen = AMF_DecodeInt32(pBuffer);
+ nSize -= 4;
+
+ nRes = AMF_DecodeArray(&prop->p_vu.p_object, pBuffer + 4, nSize,
+ nArrayLen, FALSE);
+ if (nRes == -1)
+ return -1;
+ nSize -= nRes;
+ prop->p_type = AMF_OBJECT;
+ break;
+ }
+ case AMF_DATE:
+ {
+ RTMP_Log(RTMP_LOGDEBUG, "AMF_DATE");
+
+ if (nSize < 10)
+ return -1;
+
+ prop->p_vu.p_number = AMF_DecodeNumber(pBuffer);
+ prop->p_UTCoffset = AMF_DecodeInt16(pBuffer + 8);
+
+ nSize -= 10;
+ break;
+ }
+ case AMF_LONG_STRING:
+ {
+ unsigned int nStringSize = AMF_DecodeInt32(pBuffer);
+ if (nSize < (long)nStringSize + 4)
+ return -1;
+ AMF_DecodeLongString(pBuffer, &prop->p_vu.p_aval);
+ nSize -= (4 + nStringSize);
+ prop->p_type = AMF_STRING;
+ break;
+ }
+ case AMF_RECORDSET:
+ {
+ RTMP_Log(RTMP_LOGERROR, "AMF_RECORDSET reserved!");
+ return -1;
+ break;
+ }
+ case AMF_XML_DOC:
+ {
+ RTMP_Log(RTMP_LOGERROR, "AMF_XML_DOC not supported!");
+ return -1;
+ break;
+ }
+ case AMF_TYPED_OBJECT:
+ {
+ RTMP_Log(RTMP_LOGERROR, "AMF_TYPED_OBJECT not supported!");
+ return -1;
+ break;
+ }
+ case AMF_AVMPLUS:
+ {
+ int nRes = AMF3_Decode(&prop->p_vu.p_object, pBuffer, nSize, TRUE);
+ if (nRes == -1)
+ return -1;
+ nSize -= nRes;
+ prop->p_type = AMF_OBJECT;
+ break;
+ }
+ default:
+ RTMP_Log(RTMP_LOGDEBUG, "%s - unknown datatype 0x%02x, @0x%08X", __FUNCTION__,
+ prop->p_type, pBuffer - 1);
+ return -1;
+ }
+
+ return nOriginalSize - nSize;
+}
+
+void
+AMFProp_Dump(AMFObjectProperty *prop)
+{
+ char strRes[256];
+ char str[256];
+ AVal name;
+
+ if (prop->p_type == AMF_INVALID)
+ {
+ RTMP_Log(RTMP_LOGDEBUG, "Property: INVALID");
+ return;
+ }
+
+ if (prop->p_type == AMF_NULL)
+ {
+ RTMP_Log(RTMP_LOGDEBUG, "Property: NULL");
+ return;
+ }
+
+ if (prop->p_name.av_len)
+ {
+ name = prop->p_name;
+ }
+ else
+ {
+ name.av_val = "no-name.";
+ name.av_len = sizeof("no-name.") - 1;
+ }
+ if (name.av_len > 18)
+ name.av_len = 18;
+
+ snprintf(strRes, 255, "Name: %18.*s, ", name.av_len, name.av_val);
+
+ if (prop->p_type == AMF_OBJECT)
+ {
+ RTMP_Log(RTMP_LOGDEBUG, "Property: <%sOBJECT>", strRes);
+ AMF_Dump(&prop->p_vu.p_object);
+ return;
+ }
+
+ switch (prop->p_type)
+ {
+ case AMF_NUMBER:
+ snprintf(str, 255, "NUMBER:\t%.2f", prop->p_vu.p_number);
+ break;
+ case AMF_BOOLEAN:
+ snprintf(str, 255, "BOOLEAN:\t%s",
+ prop->p_vu.p_number != 0.0 ? "TRUE" : "FALSE");
+ break;
+ case AMF_STRING:
+ snprintf(str, 255, "STRING:\t%.*s", prop->p_vu.p_aval.av_len,
+ prop->p_vu.p_aval.av_val);
+ break;
+ case AMF_DATE:
+ snprintf(str, 255, "DATE:\ttimestamp: %.2f, UTC offset: %d",
+ prop->p_vu.p_number, prop->p_UTCoffset);
+ break;
+ default:
+ snprintf(str, 255, "INVALID TYPE 0x%02x", (unsigned char)prop->p_type);
+ }
+
+ RTMP_Log(RTMP_LOGDEBUG, "Property: <%s%s>", strRes, str);
+}
+
+void
+AMFProp_Reset(AMFObjectProperty *prop)
+{
+ if (prop->p_type == AMF_OBJECT)
+ AMF_Reset(&prop->p_vu.p_object);
+ else
+ {
+ prop->p_vu.p_aval.av_len = 0;
+ prop->p_vu.p_aval.av_val = NULL;
+ }
+ prop->p_type = AMF_INVALID;
+}
+
+/* AMFObject */
+
+char *
+AMF_Encode(AMFObject *obj, char *pBuffer, char *pBufEnd)
+{
+ int i;
+
+ if (pBuffer+4 >= pBufEnd)
+ return NULL;
+
+ *pBuffer++ = AMF_OBJECT;
+
+ for (i = 0; i < obj->o_num; i++)
+ {
+ char *res = AMFProp_Encode(&obj->o_props[i], pBuffer, pBufEnd);
+ if (res == NULL)
+ {
+ RTMP_Log(RTMP_LOGERROR, "AMF_Encode - failed to encode property in index %d",
+ i);
+ break;
+ }
+ else
+ {
+ pBuffer = res;
+ }
+ }
+
+ if (pBuffer + 3 >= pBufEnd)
+ return NULL; /* no room for the end marker */
+
+ pBuffer = AMF_EncodeInt24(pBuffer, pBufEnd, AMF_OBJECT_END);
+
+ return pBuffer;
+}
+
+int
+AMF_DecodeArray(AMFObject *obj, const char *pBuffer, int nSize,
+ int nArrayLen, int bDecodeName)
+{
+ int nOriginalSize = nSize;
+ int bError = FALSE;
+
+ obj->o_num = 0;
+ obj->o_props = NULL;
+ while (nArrayLen > 0)
+ {
+ AMFObjectProperty prop;
+ int nRes;
+ nArrayLen--;
+
+ nRes = AMFProp_Decode(&prop, pBuffer, nSize, bDecodeName);
+ if (nRes == -1)
+ bError = TRUE;
+ else
+ {
+ nSize -= nRes;
+ pBuffer += nRes;
+ AMF_AddProp(obj, &prop);
+ }
+ }
+ if (bError)
+ return -1;
+
+ return nOriginalSize - nSize;
+}
+
+int
+AMF3_Decode(AMFObject *obj, const char *pBuffer, int nSize, int bAMFData)
+{
+ int nOriginalSize = nSize;
+ int32_t ref;
+ int len;
+
+ obj->o_num = 0;
+ obj->o_props = NULL;
+ if (bAMFData)
+ {
+ if (*pBuffer != AMF3_OBJECT)
+ RTMP_Log(RTMP_LOGERROR,
+ "AMF3 Object encapsulated in AMF stream does not start with AMF3_OBJECT!");
+ pBuffer++;
+ nSize--;
+ }
+
+ ref = 0;
+ len = AMF3ReadInteger(pBuffer, &ref);
+ pBuffer += len;
+ nSize -= len;
+
+ if ((ref & 1) == 0)
+ { /* object reference, 0xxx */
+ uint32_t objectIndex = (ref >> 1);
+
+ RTMP_Log(RTMP_LOGDEBUG, "Object reference, index: %d", objectIndex);
+ }
+ else /* object instance */
+ {
+ int32_t classRef = (ref >> 1);
+
+ AMF3ClassDef cd = { {0, 0}
+ };
+ AMFObjectProperty prop;
+
+ if ((classRef & 0x1) == 0)
+ { /* class reference */
+ uint32_t classIndex = (classRef >> 1);
+ RTMP_Log(RTMP_LOGDEBUG, "Class reference: %d", classIndex);
+ }
+ else
+ {
+ int32_t classExtRef = (classRef >> 1);
+ int i;
+
+ cd.cd_externalizable = (classExtRef & 0x1) == 1;
+ cd.cd_dynamic = ((classExtRef >> 1) & 0x1) == 1;
+
+ cd.cd_num = classExtRef >> 2;
+
+ /* class name */
+
+ len = AMF3ReadString(pBuffer, &cd.cd_name);
+ nSize -= len;
+ pBuffer += len;
+
+ /*std::string str = className; */
+
+ RTMP_Log(RTMP_LOGDEBUG,
+ "Class name: %s, externalizable: %d, dynamic: %d, classMembers: %d",
+ cd.cd_name.av_val, cd.cd_externalizable, cd.cd_dynamic,
+ cd.cd_num);
+
+ for (i = 0; i < cd.cd_num; i++)
+ {
+ AVal memberName;
+ len = AMF3ReadString(pBuffer, &memberName);
+ RTMP_Log(RTMP_LOGDEBUG, "Member: %s", memberName.av_val);
+ AMF3CD_AddProp(&cd, &memberName);
+ nSize -= len;
+ pBuffer += len;
+ }
+ }
+
+ /* add as referencable object */
+
+ if (cd.cd_externalizable)
+ {
+ int nRes;
+ AVal name = AVC("DEFAULT_ATTRIBUTE");
+
+ RTMP_Log(RTMP_LOGDEBUG, "Externalizable, TODO check");
+
+ nRes = AMF3Prop_Decode(&prop, pBuffer, nSize, FALSE);
+ if (nRes == -1)
+ RTMP_Log(RTMP_LOGDEBUG, "%s, failed to decode AMF3 property!",
+ __FUNCTION__);
+ else
+ {
+ nSize -= nRes;
+ pBuffer += nRes;
+ }
+
+ AMFProp_SetName(&prop, &name);
+ AMF_AddProp(obj, &prop);
+ }
+ else
+ {
+ int nRes, i;
+ for (i = 0; i < cd.cd_num; i++) /* non-dynamic */
+ {
+ nRes = AMF3Prop_Decode(&prop, pBuffer, nSize, FALSE);
+ if (nRes == -1)
+ RTMP_Log(RTMP_LOGDEBUG, "%s, failed to decode AMF3 property!",
+ __FUNCTION__);
+
+ AMFProp_SetName(&prop, AMF3CD_GetProp(&cd, i));
+ AMF_AddProp(obj, &prop);
+
+ pBuffer += nRes;
+ nSize -= nRes;
+ }
+ if (cd.cd_dynamic)
+ {
+ int len = 0;
+
+ do
+ {
+ nRes = AMF3Prop_Decode(&prop, pBuffer, nSize, TRUE);
+ AMF_AddProp(obj, &prop);
+
+ pBuffer += nRes;
+ nSize -= nRes;
+
+ len = prop.p_name.av_len;
+ }
+ while (len > 0);
+ }
+ }
+ RTMP_Log(RTMP_LOGDEBUG, "class object!");
+ }
+ return nOriginalSize - nSize;
+}
+
+int
+AMF_Decode(AMFObject *obj, const char *pBuffer, int nSize, int bDecodeName)
+{
+ int nOriginalSize = nSize;
+ int bError = FALSE; /* if there is an error while decoding - try to at least find the end mark AMF_OBJECT_END */
+
+ obj->o_num = 0;
+ obj->o_props = NULL;
+ while (nSize > 0)
+ {
+ AMFObjectProperty prop;
+ int nRes;
+
+ if (nSize >=3 && AMF_DecodeInt24(pBuffer) == AMF_OBJECT_END)
+ {
+ nSize -= 3;
+ bError = FALSE;
+ break;
+ }
+
+ if (bError)
+ {
+ RTMP_Log(RTMP_LOGERROR,
+ "DECODING ERROR, IGNORING BYTES UNTIL NEXT KNOWN PATTERN!");
+ nSize--;
+ pBuffer++;
+ continue;
+ }
+
+ nRes = AMFProp_Decode(&prop, pBuffer, nSize, bDecodeName);
+ if (nRes == -1)
+ bError = TRUE;
+ else
+ {
+ nSize -= nRes;
+ pBuffer += nRes;
+ AMF_AddProp(obj, &prop);
+ }
+ }
+
+ if (bError)
+ return -1;
+
+ return nOriginalSize - nSize;
+}
+
+void
+AMF_AddProp(AMFObject *obj, const AMFObjectProperty *prop)
+{
+ if (!(obj->o_num & 0x0f))
+ obj->o_props =
+ realloc(obj->o_props, (obj->o_num + 16) * sizeof(AMFObjectProperty));
+ obj->o_props[obj->o_num++] = *prop;
+}
+
+int
+AMF_CountProp(AMFObject *obj)
+{
+ return obj->o_num;
+}
+
+AMFObjectProperty *
+AMF_GetProp(AMFObject *obj, const AVal *name, int nIndex)
+{
+ if (nIndex >= 0)
+ {
+ if (nIndex <= obj->o_num)
+ return &obj->o_props[nIndex];
+ }
+ else
+ {
+ int n;
+ for (n = 0; n < obj->o_num; n++)
+ {
+ if (AVMATCH(&obj->o_props[n].p_name, name))
+ return &obj->o_props[n];
+ }
+ }
+
+ return (AMFObjectProperty *)&AMFProp_Invalid;
+}
+
+void
+AMF_Dump(AMFObject *obj)
+{
+ int n;
+ RTMP_Log(RTMP_LOGDEBUG, "(object begin)");
+ for (n = 0; n < obj->o_num; n++)
+ {
+ AMFProp_Dump(&obj->o_props[n]);
+ }
+ RTMP_Log(RTMP_LOGDEBUG, "(object end)");
+}
+
+void
+AMF_Reset(AMFObject *obj)
+{
+ int n;
+ for (n = 0; n < obj->o_num; n++)
+ {
+ AMFProp_Reset(&obj->o_props[n]);
+ }
+ free(obj->o_props);
+ obj->o_props = NULL;
+ obj->o_num = 0;
+}
+
+
+/* AMF3ClassDefinition */
+
+void
+AMF3CD_AddProp(AMF3ClassDef *cd, AVal *prop)
+{
+ if (!(cd->cd_num & 0x0f))
+ cd->cd_props = realloc(cd->cd_props, (cd->cd_num + 16) * sizeof(AVal));
+ cd->cd_props[cd->cd_num++] = *prop;
+}
+
+AVal *
+AMF3CD_GetProp(AMF3ClassDef *cd, int nIndex)
+{
+ if (nIndex >= cd->cd_num)
+ return (AVal *)&AV_empty;
+ return &cd->cd_props[nIndex];
+}
diff --git a/Live/src/main/cpp/include/rtmp/amf.h b/Live/src/main/cpp/rtmp/amf.h
similarity index 100%
rename from Live/src/main/cpp/include/rtmp/amf.h
rename to Live/src/main/cpp/rtmp/amf.h
diff --git a/Live/src/main/cpp/rtmp/bytes.h b/Live/src/main/cpp/rtmp/bytes.h
new file mode 100644
index 00000000..8c6e80d0
--- /dev/null
+++ b/Live/src/main/cpp/rtmp/bytes.h
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2005-2008 Team XBMC
+ * http://www.xbmc.org
+ * Copyright (C) 2008-2009 Andrej Stepanchuk
+ * Copyright (C) 2009-2010 Howard Chu
+ *
+ * This file is part of librtmp.
+ *
+ * librtmp is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1,
+ * or (at your option) any later version.
+ *
+ * librtmp is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with librtmp see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/lgpl.html
+ */
+
+#ifndef __BYTES_H__
+#define __BYTES_H__
+
+#include
+
+#ifdef _WIN32
+/* Windows is little endian only */
+#define __LITTLE_ENDIAN 1234
+#define __BIG_ENDIAN 4321
+#define __BYTE_ORDER __LITTLE_ENDIAN
+#define __FLOAT_WORD_ORDER __BYTE_ORDER
+
+typedef unsigned char uint8_t;
+
+#else /* !_WIN32 */
+
+#include
+
+#if defined(BYTE_ORDER) && !defined(__BYTE_ORDER)
+#define __BYTE_ORDER BYTE_ORDER
+#endif
+
+#if defined(BIG_ENDIAN) && !defined(__BIG_ENDIAN)
+#define __BIG_ENDIAN BIG_ENDIAN
+#endif
+
+#if defined(LITTLE_ENDIAN) && !defined(__LITTLE_ENDIAN)
+#define __LITTLE_ENDIAN LITTLE_ENDIAN
+#endif
+
+#endif /* !_WIN32 */
+
+/* define default endianness */
+#ifndef __LITTLE_ENDIAN
+#define __LITTLE_ENDIAN 1234
+#endif
+
+#ifndef __BIG_ENDIAN
+#define __BIG_ENDIAN 4321
+#endif
+
+#ifndef __BYTE_ORDER
+#warning "Byte order not defined on your system, assuming little endian!"
+#define __BYTE_ORDER __LITTLE_ENDIAN
+#endif
+
+/* ok, we assume to have the same float word order and byte order if float word order is not defined */
+#ifndef __FLOAT_WORD_ORDER
+#warning "Float word order not defined, assuming the same as byte order!"
+#define __FLOAT_WORD_ORDER __BYTE_ORDER
+#endif
+
+#if !defined(__BYTE_ORDER) || !defined(__FLOAT_WORD_ORDER)
+#error "Undefined byte or float word order!"
+#endif
+
+#if __FLOAT_WORD_ORDER != __BIG_ENDIAN && __FLOAT_WORD_ORDER != __LITTLE_ENDIAN
+#error "Unknown/unsupported float word order!"
+#endif
+
+#if __BYTE_ORDER != __BIG_ENDIAN && __BYTE_ORDER != __LITTLE_ENDIAN
+#error "Unknown/unsupported byte order!"
+#endif
+
+#endif
+
diff --git a/Live/src/main/cpp/rtmp/dh.h b/Live/src/main/cpp/rtmp/dh.h
new file mode 100644
index 00000000..8e285a60
--- /dev/null
+++ b/Live/src/main/cpp/rtmp/dh.h
@@ -0,0 +1,334 @@
+/* RTMPDump - Diffie-Hellmann Key Exchange
+ * Copyright (C) 2009 Andrej Stepanchuk
+ * Copyright (C) 2009-2010 Howard Chu
+ *
+ * This file is part of librtmp.
+ *
+ * librtmp is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1,
+ * or (at your option) any later version.
+ *
+ * librtmp is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with librtmp see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/lgpl.html
+ */
+
+#include
+#include
+#include
+#include
+#include
+
+#ifdef USE_POLARSSL
+#include
+typedef mpi * MP_t;
+#define MP_new(m) m = malloc(sizeof(mpi)); mpi_init(m, NULL)
+#define MP_set_w(mpi, w) mpi_lset(mpi, w)
+#define MP_cmp(u, v) mpi_cmp_mpi(u, v)
+#define MP_set(u, v) mpi_copy(u, v)
+#define MP_sub_w(mpi, w) mpi_sub_int(mpi, mpi, w)
+#define MP_cmp_1(mpi) mpi_cmp_int(mpi, 1)
+#define MP_modexp(r, y, q, p) mpi_exp_mod(r, y, q, p, NULL)
+#define MP_free(mpi) mpi_free(mpi, NULL); free(mpi)
+#define MP_gethex(u, hex, res) MP_new(u); res = mpi_read_string(u, 16, hex) == 0
+#define MP_bytes(u) mpi_size(u)
+#define MP_setbin(u,buf,len) mpi_write_binary(u,buf,len)
+#define MP_getbin(u,buf,len) MP_new(u); mpi_read_binary(u,buf,len)
+
+typedef struct MDH {
+ MP_t p;
+ MP_t g;
+ MP_t pub_key;
+ MP_t priv_key;
+ long length;
+ dhm_context ctx;
+} MDH;
+
+#define MDH_new() calloc(1,sizeof(MDH))
+#define MDH_free(vp) {MDH *dh = vp; dhm_free(&dh->ctx); MP_free(dh->p); MP_free(dh->g); MP_free(dh->pub_key); MP_free(dh->priv_key); free(dh);}
+
+static int MDH_generate_key(MDH *dh)
+{
+ unsigned char out[2];
+ MP_set(&dh->ctx.P, dh->p);
+ MP_set(&dh->ctx.G, dh->g);
+ dh->ctx.len = 128;
+ dhm_make_public(&dh->ctx, 1024, out, 1, havege_rand, &RTMP_TLS_ctx->hs);
+ MP_new(dh->pub_key);
+ MP_new(dh->priv_key);
+ MP_set(dh->pub_key, &dh->ctx.GX);
+ MP_set(dh->priv_key, &dh->ctx.X);
+ return 1;
+}
+
+static int MDH_compute_key(uint8_t *secret, size_t len, MP_t pub, MDH *dh)
+{
+ int n = len;
+ MP_set(&dh->ctx.GY, pub);
+ dhm_calc_secret(&dh->ctx, secret, &n);
+ return 0;
+}
+
+#elif defined(USE_GNUTLS)
+#include
+typedef gcry_mpi_t MP_t;
+#define MP_new(m) m = gcry_mpi_new(1)
+#define MP_set_w(mpi, w) gcry_mpi_set_ui(mpi, w)
+#define MP_cmp(u, v) gcry_mpi_cmp(u, v)
+#define MP_set(u, v) gcry_mpi_set(u, v)
+#define MP_sub_w(mpi, w) gcry_mpi_sub_ui(mpi, mpi, w)
+#define MP_cmp_1(mpi) gcry_mpi_cmp_ui(mpi, 1)
+#define MP_modexp(r, y, q, p) gcry_mpi_powm(r, y, q, p)
+#define MP_free(mpi) gcry_mpi_release(mpi)
+#define MP_gethex(u, hex, res) res = (gcry_mpi_scan(&u, GCRYMPI_FMT_HEX, hex, 0, 0) == 0)
+#define MP_bytes(u) (gcry_mpi_get_nbits(u) + 7) / 8
+#define MP_setbin(u,buf,len) gcry_mpi_print(GCRYMPI_FMT_USG,buf,len,NULL,u)
+#define MP_getbin(u,buf,len) gcry_mpi_scan(&u,GCRYMPI_FMT_USG,buf,len,NULL)
+
+typedef struct MDH {
+ MP_t p;
+ MP_t g;
+ MP_t pub_key;
+ MP_t priv_key;
+ long length;
+} MDH;
+
+#define MDH_new() calloc(1,sizeof(MDH))
+#define MDH_free(dh) do {MP_free(((MDH*)(dh))->p); MP_free(((MDH*)(dh))->g); MP_free(((MDH*)(dh))->pub_key); MP_free(((MDH*)(dh))->priv_key); free(dh);} while(0)
+
+extern MP_t gnutls_calc_dh_secret(MP_t *priv, MP_t g, MP_t p);
+extern MP_t gnutls_calc_dh_key(MP_t y, MP_t x, MP_t p);
+
+#define MDH_generate_key(dh) (dh->pub_key = gnutls_calc_dh_secret(&dh->priv_key, dh->g, dh->p))
+static int MDH_compute_key(uint8_t *secret, size_t len, MP_t pub, MDH *dh)
+{
+ MP_t sec = gnutls_calc_dh_key(pub, dh->priv_key, dh->p);
+ if (sec)
+ {
+ MP_setbin(sec, secret, len);
+ MP_free(sec);
+ return 0;
+ }
+ else
+ return -1;
+}
+
+#else /* USE_OPENSSL */
+#include
+#include
+
+typedef BIGNUM * MP_t;
+#define MP_new(m) m = BN_new()
+#define MP_set_w(mpi, w) BN_set_word(mpi, w)
+#define MP_cmp(u, v) BN_cmp(u, v)
+#define MP_set(u, v) BN_copy(u, v)
+#define MP_sub_w(mpi, w) BN_sub_word(mpi, w)
+#define MP_cmp_1(mpi) BN_cmp(mpi, BN_value_one())
+#define MP_modexp(r, y, q, p) do {BN_CTX *ctx = BN_CTX_new(); BN_mod_exp(r, y, q, p, ctx); BN_CTX_free(ctx);} while(0)
+#define MP_free(mpi) BN_free(mpi)
+#define MP_gethex(u, hex, res) res = BN_hex2bn(&u, hex)
+#define MP_bytes(u) BN_num_bytes(u)
+#define MP_setbin(u,buf,len) BN_bn2bin(u,buf)
+#define MP_getbin(u,buf,len) u = BN_bin2bn(buf,len,0)
+
+#define MDH DH
+#define MDH_new() DH_new()
+#define MDH_free(dh) DH_free(dh)
+#define MDH_generate_key(dh) DH_generate_key(dh)
+#define MDH_compute_key(secret, seclen, pub, dh) DH_compute_key(secret, pub, dh)
+
+#endif
+
+#include "log.h"
+#include "dhgroups.h"
+
+/* RFC 2631, Section 2.1.5, http://www.ietf.org/rfc/rfc2631.txt */
+static int
+isValidPublicKey(MP_t y, MP_t p, MP_t q)
+{
+ int ret = TRUE;
+ MP_t bn;
+ assert(y);
+
+ MP_new(bn);
+ assert(bn);
+
+ /* y must lie in [2,p-1] */
+ MP_set_w(bn, 1);
+ if (MP_cmp(y, bn) < 0)
+ {
+ RTMP_Log(RTMP_LOGERROR, "DH public key must be at least 2");
+ ret = FALSE;
+ goto failed;
+ }
+
+ /* bn = p-2 */
+ MP_set(bn, p);
+ MP_sub_w(bn, 1);
+ if (MP_cmp(y, bn) > 0)
+ {
+ RTMP_Log(RTMP_LOGERROR, "DH public key must be at most p-2");
+ ret = FALSE;
+ goto failed;
+ }
+
+ /* Verify with Sophie-Germain prime
+ *
+ * This is a nice test to make sure the public key position is calculated
+ * correctly. This test will fail in about 50% of the cases if applied to
+ * random data.
+ */
+ if (q)
+ {
+ /* y must fulfill y^q mod p = 1 */
+ MP_modexp(bn, y, q, p);
+
+ if (MP_cmp_1(bn) != 0)
+ {
+ RTMP_Log(RTMP_LOGWARNING, "DH public key does not fulfill y^q mod p = 1");
+ }
+ }
+
+failed:
+ MP_free(bn);
+ return ret;
+}
+
+static MDH *
+DHInit(int nKeyBits)
+{
+ size_t res;
+ MDH *dh = MDH_new();
+
+ if (!dh)
+ goto failed;
+
+ MP_new(dh->g);
+
+ if (!dh->g)
+ goto failed;
+
+ MP_gethex(dh->p, P1024, res); /* prime P1024, see dhgroups.h */
+ if (!res)
+ {
+ goto failed;
+ }
+
+ MP_set_w(dh->g, 2); /* base 2 */
+
+ dh->length = nKeyBits;
+ return dh;
+
+failed:
+ if (dh)
+ MDH_free(dh);
+
+ return 0;
+}
+
+static int
+DHGenerateKey(MDH *dh)
+{
+ size_t res = 0;
+ if (!dh)
+ return 0;
+
+ while (!res)
+ {
+ MP_t q1 = NULL;
+
+ if (!MDH_generate_key(dh))
+ return 0;
+
+ MP_gethex(q1, Q1024, res);
+ assert(res);
+
+ res = isValidPublicKey(dh->pub_key, dh->p, q1);
+ if (!res)
+ {
+ MP_free(dh->pub_key);
+ MP_free(dh->priv_key);
+ dh->pub_key = dh->priv_key = 0;
+ }
+
+ MP_free(q1);
+ }
+ return 1;
+}
+
+/* fill pubkey with the public key in BIG ENDIAN order
+ * 00 00 00 00 00 x1 x2 x3 .....
+ */
+
+static int
+DHGetPublicKey(MDH *dh, uint8_t *pubkey, size_t nPubkeyLen)
+{
+ int len;
+ if (!dh || !dh->pub_key)
+ return 0;
+
+ len = MP_bytes(dh->pub_key);
+ if (len <= 0 || len > (int) nPubkeyLen)
+ return 0;
+
+ memset(pubkey, 0, nPubkeyLen);
+ MP_setbin(dh->pub_key, pubkey + (nPubkeyLen - len), len);
+ return 1;
+}
+
+#if 0 /* unused */
+static int
+DHGetPrivateKey(MDH *dh, uint8_t *privkey, size_t nPrivkeyLen)
+{
+ if (!dh || !dh->priv_key)
+ return 0;
+
+ int len = MP_bytes(dh->priv_key);
+ if (len <= 0 || len > (int) nPrivkeyLen)
+ return 0;
+
+ memset(privkey, 0, nPrivkeyLen);
+ MP_setbin(dh->priv_key, privkey + (nPrivkeyLen - len), len);
+ return 1;
+}
+#endif
+
+/* computes the shared secret key from the private MDH value and the
+ * other party's public key (pubkey)
+ */
+static int
+DHComputeSharedSecretKey(MDH *dh, uint8_t *pubkey, size_t nPubkeyLen,
+ uint8_t *secret)
+{
+ MP_t q1 = NULL, pubkeyBn = NULL;
+ size_t len;
+ int res;
+
+ if (!dh || !secret || nPubkeyLen >= INT_MAX)
+ return -1;
+
+ MP_getbin(pubkeyBn, pubkey, nPubkeyLen);
+ if (!pubkeyBn)
+ return -1;
+
+ MP_gethex(q1, Q1024, len);
+ assert(len);
+
+ if (isValidPublicKey(pubkeyBn, dh->p, q1))
+ res = MDH_compute_key(secret, nPubkeyLen, pubkeyBn, dh);
+ else
+ res = -1;
+
+ MP_free(q1);
+ MP_free(pubkeyBn);
+
+ return res;
+}
diff --git a/Live/src/main/cpp/rtmp/dhgroups.h b/Live/src/main/cpp/rtmp/dhgroups.h
new file mode 100644
index 00000000..2db3989c
--- /dev/null
+++ b/Live/src/main/cpp/rtmp/dhgroups.h
@@ -0,0 +1,199 @@
+/* librtmp - Diffie-Hellmann Key Exchange
+ * Copyright (C) 2009 Andrej Stepanchuk
+ *
+ * This file is part of librtmp.
+ *
+ * librtmp is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1,
+ * or (at your option) any later version.
+ *
+ * librtmp is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with librtmp see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/lgpl.html
+ */
+
+/* from RFC 3526, see http://www.ietf.org/rfc/rfc3526.txt */
+
+/* 2^768 - 2 ^704 - 1 + 2^64 * { [2^638 pi] + 149686 } */
+#define P768 \
+ "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1" \
+ "29024E088A67CC74020BBEA63B139B22514A08798E3404DD" \
+ "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245" \
+ "E485B576625E7EC6F44C42E9A63A3620FFFFFFFFFFFFFFFF"
+
+/* 2^1024 - 2^960 - 1 + 2^64 * { [2^894 pi] + 129093 } */
+#define P1024 \
+ "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1" \
+ "29024E088A67CC74020BBEA63B139B22514A08798E3404DD" \
+ "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245" \
+ "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED" \
+ "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE65381" \
+ "FFFFFFFFFFFFFFFF"
+
+/* Group morder largest prime factor: */
+#define Q1024 \
+ "7FFFFFFFFFFFFFFFE487ED5110B4611A62633145C06E0E68" \
+ "948127044533E63A0105DF531D89CD9128A5043CC71A026E" \
+ "F7CA8CD9E69D218D98158536F92F8A1BA7F09AB6B6A8E122" \
+ "F242DABB312F3F637A262174D31BF6B585FFAE5B7A035BF6" \
+ "F71C35FDAD44CFD2D74F9208BE258FF324943328F67329C0" \
+ "FFFFFFFFFFFFFFFF"
+
+/* 2^1536 - 2^1472 - 1 + 2^64 * { [2^1406 pi] + 741804 } */
+#define P1536 \
+ "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1" \
+ "29024E088A67CC74020BBEA63B139B22514A08798E3404DD" \
+ "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245" \
+ "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED" \
+ "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D" \
+ "C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F" \
+ "83655D23DCA3AD961C62F356208552BB9ED529077096966D" \
+ "670C354E4ABC9804F1746C08CA237327FFFFFFFFFFFFFFFF"
+
+/* 2^2048 - 2^1984 - 1 + 2^64 * { [2^1918 pi] + 124476 } */
+#define P2048 \
+ "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1" \
+ "29024E088A67CC74020BBEA63B139B22514A08798E3404DD" \
+ "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245" \
+ "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED" \
+ "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D" \
+ "C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F" \
+ "83655D23DCA3AD961C62F356208552BB9ED529077096966D" \
+ "670C354E4ABC9804F1746C08CA18217C32905E462E36CE3B" \
+ "E39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9" \
+ "DE2BCBF6955817183995497CEA956AE515D2261898FA0510" \
+ "15728E5A8AACAA68FFFFFFFFFFFFFFFF"
+
+/* 2^3072 - 2^3008 - 1 + 2^64 * { [2^2942 pi] + 1690314 } */
+#define P3072 \
+ "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1" \
+ "29024E088A67CC74020BBEA63B139B22514A08798E3404DD" \
+ "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245" \
+ "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED" \
+ "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D" \
+ "C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F" \
+ "83655D23DCA3AD961C62F356208552BB9ED529077096966D" \
+ "670C354E4ABC9804F1746C08CA18217C32905E462E36CE3B" \
+ "E39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9" \
+ "DE2BCBF6955817183995497CEA956AE515D2261898FA0510" \
+ "15728E5A8AAAC42DAD33170D04507A33A85521ABDF1CBA64" \
+ "ECFB850458DBEF0A8AEA71575D060C7DB3970F85A6E1E4C7" \
+ "ABF5AE8CDB0933D71E8C94E04A25619DCEE3D2261AD2EE6B" \
+ "F12FFA06D98A0864D87602733EC86A64521F2B18177B200C" \
+ "BBE117577A615D6C770988C0BAD946E208E24FA074E5AB31" \
+ "43DB5BFCE0FD108E4B82D120A93AD2CAFFFFFFFFFFFFFFFF"
+
+/* 2^4096 - 2^4032 - 1 + 2^64 * { [2^3966 pi] + 240904 } */
+#define P4096 \
+ "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1" \
+ "29024E088A67CC74020BBEA63B139B22514A08798E3404DD" \
+ "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245" \
+ "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED" \
+ "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D" \
+ "C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F" \
+ "83655D23DCA3AD961C62F356208552BB9ED529077096966D" \
+ "670C354E4ABC9804F1746C08CA18217C32905E462E36CE3B" \
+ "E39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9" \
+ "DE2BCBF6955817183995497CEA956AE515D2261898FA0510" \
+ "15728E5A8AAAC42DAD33170D04507A33A85521ABDF1CBA64" \
+ "ECFB850458DBEF0A8AEA71575D060C7DB3970F85A6E1E4C7" \
+ "ABF5AE8CDB0933D71E8C94E04A25619DCEE3D2261AD2EE6B" \
+ "F12FFA06D98A0864D87602733EC86A64521F2B18177B200C" \
+ "BBE117577A615D6C770988C0BAD946E208E24FA074E5AB31" \
+ "43DB5BFCE0FD108E4B82D120A92108011A723C12A787E6D7" \
+ "88719A10BDBA5B2699C327186AF4E23C1A946834B6150BDA" \
+ "2583E9CA2AD44CE8DBBBC2DB04DE8EF92E8EFC141FBECAA6" \
+ "287C59474E6BC05D99B2964FA090C3A2233BA186515BE7ED" \
+ "1F612970CEE2D7AFB81BDD762170481CD0069127D5B05AA9" \
+ "93B4EA988D8FDDC186FFB7DC90A6C08F4DF435C934063199" \
+ "FFFFFFFFFFFFFFFF"
+
+/* 2^6144 - 2^6080 - 1 + 2^64 * { [2^6014 pi] + 929484 } */
+#define P6144 \
+ "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1" \
+ "29024E088A67CC74020BBEA63B139B22514A08798E3404DD" \
+ "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245" \
+ "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED" \
+ "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D" \
+ "C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F" \
+ "83655D23DCA3AD961C62F356208552BB9ED529077096966D" \
+ "670C354E4ABC9804F1746C08CA18217C32905E462E36CE3B" \
+ "E39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9" \
+ "DE2BCBF6955817183995497CEA956AE515D2261898FA0510" \
+ "15728E5A8AAAC42DAD33170D04507A33A85521ABDF1CBA64" \
+ "ECFB850458DBEF0A8AEA71575D060C7DB3970F85A6E1E4C7" \
+ "ABF5AE8CDB0933D71E8C94E04A25619DCEE3D2261AD2EE6B" \
+ "F12FFA06D98A0864D87602733EC86A64521F2B18177B200C" \
+ "BBE117577A615D6C770988C0BAD946E208E24FA074E5AB31" \
+ "43DB5BFCE0FD108E4B82D120A92108011A723C12A787E6D7" \
+ "88719A10BDBA5B2699C327186AF4E23C1A946834B6150BDA" \
+ "2583E9CA2AD44CE8DBBBC2DB04DE8EF92E8EFC141FBECAA6" \
+ "287C59474E6BC05D99B2964FA090C3A2233BA186515BE7ED" \
+ "1F612970CEE2D7AFB81BDD762170481CD0069127D5B05AA9" \
+ "93B4EA988D8FDDC186FFB7DC90A6C08F4DF435C934028492" \
+ "36C3FAB4D27C7026C1D4DCB2602646DEC9751E763DBA37BD" \
+ "F8FF9406AD9E530EE5DB382F413001AEB06A53ED9027D831" \
+ "179727B0865A8918DA3EDBEBCF9B14ED44CE6CBACED4BB1B" \
+ "DB7F1447E6CC254B332051512BD7AF426FB8F401378CD2BF" \
+ "5983CA01C64B92ECF032EA15D1721D03F482D7CE6E74FEF6" \
+ "D55E702F46980C82B5A84031900B1C9E59E7C97FBEC7E8F3" \
+ "23A97A7E36CC88BE0F1D45B7FF585AC54BD407B22B4154AA" \
+ "CC8F6D7EBF48E1D814CC5ED20F8037E0A79715EEF29BE328" \
+ "06A1D58BB7C5DA76F550AA3D8A1FBFF0EB19CCB1A313D55C" \
+ "DA56C9EC2EF29632387FE8D76E3C0468043E8F663F4860EE" \
+ "12BF2D5B0B7474D6E694F91E6DCC4024FFFFFFFFFFFFFFFF"
+
+/* 2^8192 - 2^8128 - 1 + 2^64 * { [2^8062 pi] + 4743158 } */
+#define P8192 \
+ "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1" \
+ "29024E088A67CC74020BBEA63B139B22514A08798E3404DD" \
+ "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245" \
+ "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED" \
+ "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D" \
+ "C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F" \
+ "83655D23DCA3AD961C62F356208552BB9ED529077096966D" \
+ "670C354E4ABC9804F1746C08CA18217C32905E462E36CE3B" \
+ "E39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9" \
+ "DE2BCBF6955817183995497CEA956AE515D2261898FA0510" \
+ "15728E5A8AAAC42DAD33170D04507A33A85521ABDF1CBA64" \
+ "ECFB850458DBEF0A8AEA71575D060C7DB3970F85A6E1E4C7" \
+ "ABF5AE8CDB0933D71E8C94E04A25619DCEE3D2261AD2EE6B" \
+ "F12FFA06D98A0864D87602733EC86A64521F2B18177B200C" \
+ "BBE117577A615D6C770988C0BAD946E208E24FA074E5AB31" \
+ "43DB5BFCE0FD108E4B82D120A92108011A723C12A787E6D7" \
+ "88719A10BDBA5B2699C327186AF4E23C1A946834B6150BDA" \
+ "2583E9CA2AD44CE8DBBBC2DB04DE8EF92E8EFC141FBECAA6" \
+ "287C59474E6BC05D99B2964FA090C3A2233BA186515BE7ED" \
+ "1F612970CEE2D7AFB81BDD762170481CD0069127D5B05AA9" \
+ "93B4EA988D8FDDC186FFB7DC90A6C08F4DF435C934028492" \
+ "36C3FAB4D27C7026C1D4DCB2602646DEC9751E763DBA37BD" \
+ "F8FF9406AD9E530EE5DB382F413001AEB06A53ED9027D831" \
+ "179727B0865A8918DA3EDBEBCF9B14ED44CE6CBACED4BB1B" \
+ "DB7F1447E6CC254B332051512BD7AF426FB8F401378CD2BF" \
+ "5983CA01C64B92ECF032EA15D1721D03F482D7CE6E74FEF6" \
+ "D55E702F46980C82B5A84031900B1C9E59E7C97FBEC7E8F3" \
+ "23A97A7E36CC88BE0F1D45B7FF585AC54BD407B22B4154AA" \
+ "CC8F6D7EBF48E1D814CC5ED20F8037E0A79715EEF29BE328" \
+ "06A1D58BB7C5DA76F550AA3D8A1FBFF0EB19CCB1A313D55C" \
+ "DA56C9EC2EF29632387FE8D76E3C0468043E8F663F4860EE" \
+ "12BF2D5B0B7474D6E694F91E6DBE115974A3926F12FEE5E4" \
+ "38777CB6A932DF8CD8BEC4D073B931BA3BC832B68D9DD300" \
+ "741FA7BF8AFC47ED2576F6936BA424663AAB639C5AE4F568" \
+ "3423B4742BF1C978238F16CBE39D652DE3FDB8BEFC848AD9" \
+ "22222E04A4037C0713EB57A81A23F0C73473FC646CEA306B" \
+ "4BCBC8862F8385DDFA9D4B7FA2C087E879683303ED5BDD3A" \
+ "062B3CF5B3A278A66D2A13F83F44F82DDF310EE074AB6A36" \
+ "4597E899A0255DC164F31CC50846851DF9AB48195DED7EA1" \
+ "B1D510BD7EE74D73FAF36BC31ECFA268359046F4EB879F92" \
+ "4009438B481C6CD7889A002ED5EE382BC9190DA6FC026E47" \
+ "9558E4475677E9AA9E3050E2765694DFC81F56E880B96E71" \
+ "60C980DD98EDD3DFFFFFFFFFFFFFFFFF"
+
diff --git a/Live/src/main/cpp/rtmp/handshake.h b/Live/src/main/cpp/rtmp/handshake.h
new file mode 100644
index 00000000..958579a8
--- /dev/null
+++ b/Live/src/main/cpp/rtmp/handshake.h
@@ -0,0 +1,1093 @@
+/*
+ * Copyright (C) 2008-2009 Andrej Stepanchuk
+ * Copyright (C) 2009-2010 Howard Chu
+ * Copyright (C) 2010 2a665470ced7adb7156fcef47f8199a6371c117b8a79e399a2771e0b36384090
+ *
+ * This file is part of librtmp.
+ *
+ * librtmp is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1,
+ * or (at your option) any later version.
+ *
+ * librtmp is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with librtmp see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/lgpl.html
+ */
+
+/* This file is #included in rtmp.c, it is not meant to be compiled alone */
+
+#ifdef USE_POLARSSL
+#include
+#include
+#ifndef SHA256_DIGEST_LENGTH
+#define SHA256_DIGEST_LENGTH 32
+#endif
+#define HMAC_CTX sha2_context
+#define HMAC_setup(ctx, key, len) sha2_hmac_starts(&ctx, (unsigned char *)key, len, 0)
+#define HMAC_crunch(ctx, buf, len) sha2_hmac_update(&ctx, buf, len)
+#define HMAC_finish(ctx, dig, dlen) dlen = SHA256_DIGEST_LENGTH; sha2_hmac_finish(&ctx, dig)
+
+typedef arc4_context * RC4_handle;
+#define RC4_alloc(h) *h = malloc(sizeof(arc4_context))
+#define RC4_setkey(h,l,k) arc4_setup(h,k,l)
+#define RC4_encrypt(h,l,d) arc4_crypt(h,l,(unsigned char *)d,(unsigned char *)d)
+#define RC4_encrypt2(h,l,s,d) arc4_crypt(h,l,(unsigned char *)s,(unsigned char *)d)
+#define RC4_free(h) free(h)
+
+#elif defined(USE_GNUTLS)
+#include
+#ifndef SHA256_DIGEST_LENGTH
+#define SHA256_DIGEST_LENGTH 32
+#endif
+#define HMAC_CTX gcry_md_hd_t
+#define HMAC_setup(ctx, key, len) gcry_md_open(&ctx, GCRY_MD_SHA256, GCRY_MD_FLAG_HMAC); gcry_md_setkey(ctx, key, len)
+#define HMAC_crunch(ctx, buf, len) gcry_md_write(ctx, buf, len)
+#define HMAC_finish(ctx, dig, dlen) dlen = SHA256_DIGEST_LENGTH; memcpy(dig, gcry_md_read(ctx, 0), dlen); gcry_md_close(ctx)
+
+typedef gcry_cipher_hd_t RC4_handle;
+#define RC4_alloc(h) gcry_cipher_open(h, GCRY_CIPHER_ARCFOUR, GCRY_CIPHER_MODE_STREAM, 0)
+#define RC4_setkey(h,l,k) gcry_cipher_setkey(h,k,l)
+#define RC4_encrypt(h,l,d) gcry_cipher_encrypt(h,(void *)d,l,NULL,0)
+#define RC4_encrypt2(h,l,s,d) gcry_cipher_encrypt(h,(void *)d,l,(void *)s,l)
+#define RC4_free(h) gcry_cipher_close(h)
+
+#else /* USE_OPENSSL */
+#include
+#include
+#include
+#if OPENSSL_VERSION_NUMBER < 0x0090800 || !defined(SHA256_DIGEST_LENGTH)
+#error Your OpenSSL is too old, need 0.9.8 or newer with SHA256
+#endif
+#define HMAC_setup(ctx, key, len) HMAC_CTX_init(&ctx); HMAC_Init_ex(&ctx, key, len, EVP_sha256(), 0)
+#define HMAC_crunch(ctx, buf, len) HMAC_Update(&ctx, buf, len)
+#define HMAC_finish(ctx, dig, dlen) HMAC_Final(&ctx, dig, &dlen); HMAC_CTX_cleanup(&ctx)
+
+typedef RC4_KEY * RC4_handle;
+#define RC4_alloc(h) *h = malloc(sizeof(RC4_KEY))
+#define RC4_setkey(h,l,k) RC4_set_key(h,l,k)
+#define RC4_encrypt(h,l,d) RC4(h,l,(uint8_t *)d,(uint8_t *)d)
+#define RC4_encrypt2(h,l,s,d) RC4(h,l,(uint8_t *)s,(uint8_t *)d)
+#define RC4_free(h) free(h)
+#endif
+
+#define FP10
+
+#include "dh.h"
+
+static const uint8_t GenuineFMSKey[] = {
+ 0x47, 0x65, 0x6e, 0x75, 0x69, 0x6e, 0x65, 0x20, 0x41, 0x64, 0x6f, 0x62,
+ 0x65, 0x20, 0x46, 0x6c,
+ 0x61, 0x73, 0x68, 0x20, 0x4d, 0x65, 0x64, 0x69, 0x61, 0x20, 0x53, 0x65,
+ 0x72, 0x76, 0x65, 0x72,
+ 0x20, 0x30, 0x30, 0x31, /* Genuine Adobe Flash Media Server 001 */
+
+ 0xf0, 0xee, 0xc2, 0x4a, 0x80, 0x68, 0xbe, 0xe8, 0x2e, 0x00, 0xd0, 0xd1,
+ 0x02, 0x9e, 0x7e, 0x57, 0x6e, 0xec, 0x5d, 0x2d, 0x29, 0x80, 0x6f, 0xab,
+ 0x93, 0xb8, 0xe6, 0x36,
+ 0xcf, 0xeb, 0x31, 0xae
+}; /* 68 */
+
+static const uint8_t GenuineFPKey[] = {
+ 0x47, 0x65, 0x6E, 0x75, 0x69, 0x6E, 0x65, 0x20, 0x41, 0x64, 0x6F, 0x62,
+ 0x65, 0x20, 0x46, 0x6C,
+ 0x61, 0x73, 0x68, 0x20, 0x50, 0x6C, 0x61, 0x79, 0x65, 0x72, 0x20, 0x30,
+ 0x30, 0x31, /* Genuine Adobe Flash Player 001 */
+ 0xF0, 0xEE,
+ 0xC2, 0x4A, 0x80, 0x68, 0xBE, 0xE8, 0x2E, 0x00, 0xD0, 0xD1, 0x02, 0x9E,
+ 0x7E, 0x57, 0x6E, 0xEC,
+ 0x5D, 0x2D, 0x29, 0x80, 0x6F, 0xAB, 0x93, 0xB8, 0xE6, 0x36, 0xCF, 0xEB,
+ 0x31, 0xAE
+}; /* 62 */
+
+static void InitRC4Encryption
+ (uint8_t * secretKey,
+ uint8_t * pubKeyIn,
+ uint8_t * pubKeyOut, RC4_handle *rc4keyIn, RC4_handle *rc4keyOut)
+{
+ uint8_t digest[SHA256_DIGEST_LENGTH];
+ unsigned int digestLen = 0;
+ HMAC_CTX ctx;
+
+ RC4_alloc(rc4keyIn);
+ RC4_alloc(rc4keyOut);
+
+ HMAC_setup(ctx, secretKey, 128);
+ HMAC_crunch(ctx, pubKeyIn, 128);
+ HMAC_finish(ctx, digest, digestLen);
+
+ RTMP_Log(RTMP_LOGDEBUG, "RC4 Out Key: ");
+ RTMP_LogHex(RTMP_LOGDEBUG, digest, 16);
+
+ RC4_setkey(*rc4keyOut, 16, digest);
+
+ HMAC_setup(ctx, secretKey, 128);
+ HMAC_crunch(ctx, pubKeyOut, 128);
+ HMAC_finish(ctx, digest, digestLen);
+
+ RTMP_Log(RTMP_LOGDEBUG, "RC4 In Key: ");
+ RTMP_LogHex(RTMP_LOGDEBUG, digest, 16);
+
+ RC4_setkey(*rc4keyIn, 16, digest);
+}
+
+typedef unsigned int (getoff)(uint8_t *buf, unsigned int len);
+
+static unsigned int
+GetDHOffset2(uint8_t *handshake, unsigned int len)
+{
+ unsigned int offset = 0;
+ uint8_t *ptr = handshake + 768;
+ unsigned int res;
+
+ assert(RTMP_SIG_SIZE <= len);
+
+ offset += (*ptr);
+ ptr++;
+ offset += (*ptr);
+ ptr++;
+ offset += (*ptr);
+ ptr++;
+ offset += (*ptr);
+
+ res = (offset % 632) + 8;
+
+ if (res + 128 > 767)
+ {
+ RTMP_Log(RTMP_LOGERROR,
+ "%s: Couldn't calculate correct DH offset (got %d), exiting!",
+ __FUNCTION__, res);
+ exit(1);
+ }
+ return res;
+}
+
+static unsigned int
+GetDigestOffset2(uint8_t *handshake, unsigned int len)
+{
+ unsigned int offset = 0;
+ uint8_t *ptr = handshake + 772;
+ unsigned int res;
+
+ offset += (*ptr);
+ ptr++;
+ offset += (*ptr);
+ ptr++;
+ offset += (*ptr);
+ ptr++;
+ offset += (*ptr);
+
+ res = (offset % 728) + 776;
+
+ if (res + 32 > 1535)
+ {
+ RTMP_Log(RTMP_LOGERROR,
+ "%s: Couldn't calculate correct digest offset (got %d), exiting",
+ __FUNCTION__, res);
+ exit(1);
+ }
+ return res;
+}
+
+static unsigned int
+GetDHOffset1(uint8_t *handshake, unsigned int len)
+{
+ unsigned int offset = 0;
+ uint8_t *ptr = handshake + 1532;
+ unsigned int res;
+
+ assert(RTMP_SIG_SIZE <= len);
+
+ offset += (*ptr);
+ ptr++;
+ offset += (*ptr);
+ ptr++;
+ offset += (*ptr);
+ ptr++;
+ offset += (*ptr);
+
+ res = (offset % 632) + 772;
+
+ if (res + 128 > 1531)
+ {
+ RTMP_Log(RTMP_LOGERROR, "%s: Couldn't calculate DH offset (got %d), exiting!",
+ __FUNCTION__, res);
+ exit(1);
+ }
+
+ return res;
+}
+
+static unsigned int
+GetDigestOffset1(uint8_t *handshake, unsigned int len)
+{
+ unsigned int offset = 0;
+ uint8_t *ptr = handshake + 8;
+ unsigned int res;
+
+ assert(12 <= len);
+
+ offset += (*ptr);
+ ptr++;
+ offset += (*ptr);
+ ptr++;
+ offset += (*ptr);
+ ptr++;
+ offset += (*ptr);
+
+ res = (offset % 728) + 12;
+
+ if (res + 32 > 771)
+ {
+ RTMP_Log(RTMP_LOGERROR,
+ "%s: Couldn't calculate digest offset (got %d), exiting!",
+ __FUNCTION__, res);
+ exit(1);
+ }
+
+ return res;
+}
+
+static getoff *digoff[] = {GetDigestOffset1, GetDigestOffset2};
+static getoff *dhoff[] = {GetDHOffset1, GetDHOffset2};
+
+static void
+HMACsha256(const uint8_t *message, size_t messageLen, const uint8_t *key,
+ size_t keylen, uint8_t *digest)
+{
+ unsigned int digestLen;
+ HMAC_CTX ctx;
+
+ HMAC_setup(ctx, key, keylen);
+ HMAC_crunch(ctx, message, messageLen);
+ HMAC_finish(ctx, digest, digestLen);
+
+ assert(digestLen == 32);
+}
+
+static void
+CalculateDigest(unsigned int digestPos, uint8_t *handshakeMessage,
+ const uint8_t *key, size_t keyLen, uint8_t *digest)
+{
+ const int messageLen = RTMP_SIG_SIZE - SHA256_DIGEST_LENGTH;
+ uint8_t message[RTMP_SIG_SIZE - SHA256_DIGEST_LENGTH];
+
+ memcpy(message, handshakeMessage, digestPos);
+ memcpy(message + digestPos,
+ &handshakeMessage[digestPos + SHA256_DIGEST_LENGTH],
+ messageLen - digestPos);
+
+ HMACsha256(message, messageLen, key, keyLen, digest);
+}
+
+static int
+VerifyDigest(unsigned int digestPos, uint8_t *handshakeMessage, const uint8_t *key,
+ size_t keyLen)
+{
+ uint8_t calcDigest[SHA256_DIGEST_LENGTH];
+
+ CalculateDigest(digestPos, handshakeMessage, key, keyLen, calcDigest);
+
+ return memcmp(&handshakeMessage[digestPos], calcDigest,
+ SHA256_DIGEST_LENGTH) == 0;
+}
+
+/* handshake
+ *
+ * Type = [1 bytes] plain: 0x03, encrypted: 0x06, 0x08, 0x09
+ * -------------------------------------------------------------------- [1536 bytes]
+ * Uptime = [4 bytes] big endian unsigned number, uptime
+ * Version = [4 bytes] each byte represents a version number, e.g. 9.0.124.0
+ * ...
+ *
+ */
+
+static const uint32_t rtmpe8_keys[16][4] = {
+ {0xbff034b2, 0x11d9081f, 0xccdfb795, 0x748de732},
+ {0x086a5eb6, 0x1743090e, 0x6ef05ab8, 0xfe5a39e2},
+ {0x7b10956f, 0x76ce0521, 0x2388a73a, 0x440149a1},
+ {0xa943f317, 0xebf11bb2, 0xa691a5ee, 0x17f36339},
+ {0x7a30e00a, 0xb529e22c, 0xa087aea5, 0xc0cb79ac},
+ {0xbdce0c23, 0x2febdeff, 0x1cfaae16, 0x1123239d},
+ {0x55dd3f7b, 0x77e7e62e, 0x9bb8c499, 0xc9481ee4},
+ {0x407bb6b4, 0x71e89136, 0xa7aebf55, 0xca33b839},
+ {0xfcf6bdc3, 0xb63c3697, 0x7ce4f825, 0x04d959b2},
+ {0x28e091fd, 0x41954c4c, 0x7fb7db00, 0xe3a066f8},
+ {0x57845b76, 0x4f251b03, 0x46d45bcd, 0xa2c30d29},
+ {0x0acceef8, 0xda55b546, 0x03473452, 0x5863713b},
+ {0xb82075dc, 0xa75f1fee, 0xd84268e8, 0xa72a44cc},
+ {0x07cf6e9e, 0xa16d7b25, 0x9fa7ae6c, 0xd92f5629},
+ {0xfeb1eae4, 0x8c8c3ce1, 0x4e0064a7, 0x6a387c2a},
+ {0x893a9427, 0xcc3013a2, 0xf106385b, 0xa829f927}
+};
+
+/* RTMPE type 8 uses XTEA on the regular signature
+ * http://en.wikipedia.org/wiki/XTEA
+ */
+static void rtmpe8_sig(uint8_t *in, uint8_t *out, int keyid)
+{
+ unsigned int i, num_rounds = 32;
+ uint32_t v0, v1, sum=0, delta=0x9E3779B9;
+ uint32_t const *k;
+
+ v0 = in[0] | (in[1] << 8) | (in[2] << 16) | (in[3] << 24);
+ v1 = in[4] | (in[5] << 8) | (in[6] << 16) | (in[7] << 24);
+ k = rtmpe8_keys[keyid];
+
+ for (i=0; i < num_rounds; i++) {
+ v0 += (((v1 << 4) ^ (v1 >> 5)) + v1) ^ (sum + k[sum & 3]);
+ sum += delta;
+ v1 += (((v0 << 4) ^ (v0 >> 5)) + v0) ^ (sum + k[(sum>>11) & 3]);
+ }
+
+ out[0] = v0; v0 >>= 8;
+ out[1] = v0; v0 >>= 8;
+ out[2] = v0; v0 >>= 8;
+ out[3] = v0;
+
+ out[4] = v1; v1 >>= 8;
+ out[5] = v1; v1 >>= 8;
+ out[6] = v1; v1 >>= 8;
+ out[7] = v1;
+}
+
+static int
+HandShake(RTMP * r, int FP9HandShake)
+{
+ int i, offalg = 0;
+ int dhposClient = 0;
+ int digestPosClient = 0;
+ int encrypted = r->Link.protocol & RTMP_FEATURE_ENC;
+
+ RC4_handle keyIn = 0;
+ RC4_handle keyOut = 0;
+
+ int32_t *ip;
+ uint32_t uptime;
+
+ uint8_t clientbuf[RTMP_SIG_SIZE + 4], *clientsig=clientbuf+4;
+ uint8_t serversig[RTMP_SIG_SIZE], client2[RTMP_SIG_SIZE], *reply;
+ uint8_t type;
+ getoff *getdh = NULL, *getdig = NULL;
+
+ if (encrypted || r->Link.SWFSize)
+ FP9HandShake = TRUE;
+ else
+ FP9HandShake = FALSE;
+
+ r->Link.rc4keyIn = r->Link.rc4keyOut = 0;
+
+ if (encrypted)
+ {
+ clientsig[-1] = 0x06; /* 0x08 is RTMPE as well */
+ offalg = 1;
+ }
+ else
+ clientsig[-1] = 0x03;
+
+ uptime = htonl(RTMP_GetTime());
+ memcpy(clientsig, &uptime, 4);
+
+ if (FP9HandShake)
+ {
+ /* set version to at least 9.0.115.0 */
+ if (encrypted)
+ {
+ clientsig[4] = 128;
+ clientsig[6] = 3;
+ }
+ else
+ {
+ clientsig[4] = 10;
+ clientsig[6] = 45;
+ }
+ clientsig[5] = 0;
+ clientsig[7] = 2;
+
+ RTMP_Log(RTMP_LOGDEBUG, "%s: Client type: %02X", __FUNCTION__, clientsig[-1]);
+ getdig = digoff[offalg];
+ getdh = dhoff[offalg];
+ }
+ else
+ {
+ memset(&clientsig[4], 0, 4);
+ }
+
+ /* generate random data */
+#ifdef _DEBUG
+ memset(clientsig+8, 0, RTMP_SIG_SIZE-8);
+#else
+ ip = (int32_t *)(clientsig+8);
+ for (i = 2; i < RTMP_SIG_SIZE/4; i++)
+ *ip++ = rand();
+#endif
+
+ /* set handshake digest */
+ if (FP9HandShake)
+ {
+ if (encrypted)
+ {
+ /* generate Diffie-Hellmann parameters */
+ r->Link.dh = DHInit(1024);
+ if (!r->Link.dh)
+ {
+ RTMP_Log(RTMP_LOGERROR, "%s: Couldn't initialize Diffie-Hellmann!",
+ __FUNCTION__);
+ return FALSE;
+ }
+
+ dhposClient = getdh(clientsig, RTMP_SIG_SIZE);
+ RTMP_Log(RTMP_LOGDEBUG, "%s: DH pubkey position: %d", __FUNCTION__, dhposClient);
+
+ if (!DHGenerateKey(r->Link.dh))
+ {
+ RTMP_Log(RTMP_LOGERROR, "%s: Couldn't generate Diffie-Hellmann public key!",
+ __FUNCTION__);
+ return FALSE;
+ }
+
+ if (!DHGetPublicKey(r->Link.dh, &clientsig[dhposClient], 128))
+ {
+ RTMP_Log(RTMP_LOGERROR, "%s: Couldn't write public key!", __FUNCTION__);
+ return FALSE;
+ }
+ }
+
+ digestPosClient = getdig(clientsig, RTMP_SIG_SIZE); /* reuse this value in verification */
+ RTMP_Log(RTMP_LOGDEBUG, "%s: Client digest offset: %d", __FUNCTION__,
+ digestPosClient);
+
+ CalculateDigest(digestPosClient, clientsig, GenuineFPKey, 30,
+ &clientsig[digestPosClient]);
+
+ RTMP_Log(RTMP_LOGDEBUG, "%s: Initial client digest: ", __FUNCTION__);
+ RTMP_LogHex(RTMP_LOGDEBUG, clientsig + digestPosClient,
+ SHA256_DIGEST_LENGTH);
+ }
+
+#ifdef _DEBUG
+ RTMP_Log(RTMP_LOGDEBUG, "Clientsig: ");
+ RTMP_LogHex(RTMP_LOGDEBUG, clientsig, RTMP_SIG_SIZE);
+#endif
+
+ if (!WriteN(r, (char *)clientsig-1, RTMP_SIG_SIZE + 1))
+ return FALSE;
+
+ if (ReadN(r, (char *)&type, 1) != 1) /* 0x03 or 0x06 */
+ return FALSE;
+
+ RTMP_Log(RTMP_LOGDEBUG, "%s: Type Answer : %02X", __FUNCTION__, type);
+
+ if (type != clientsig[-1])
+ RTMP_Log(RTMP_LOGWARNING, "%s: Type mismatch: client sent %d, server answered %d",
+ __FUNCTION__, clientsig[-1], type);
+
+ if (ReadN(r, (char *)serversig, RTMP_SIG_SIZE) != RTMP_SIG_SIZE)
+ return FALSE;
+
+ /* decode server response */
+ memcpy(&uptime, serversig, 4);
+ uptime = ntohl(uptime);
+
+ RTMP_Log(RTMP_LOGDEBUG, "%s: Server Uptime : %d", __FUNCTION__, uptime);
+ RTMP_Log(RTMP_LOGDEBUG, "%s: FMS Version : %d.%d.%d.%d", __FUNCTION__, serversig[4],
+ serversig[5], serversig[6], serversig[7]);
+
+ if (FP9HandShake && type == 3 && !serversig[4])
+ FP9HandShake = FALSE;
+
+#ifdef _DEBUG
+ RTMP_Log(RTMP_LOGDEBUG, "Server signature:");
+ RTMP_LogHex(RTMP_LOGDEBUG, serversig, RTMP_SIG_SIZE);
+#endif
+
+ if (FP9HandShake)
+ {
+ uint8_t digestResp[SHA256_DIGEST_LENGTH];
+ uint8_t *signatureResp = NULL;
+
+ /* we have to use this signature now to find the correct algorithms for getting the digest and DH positions */
+ int digestPosServer = getdig(serversig, RTMP_SIG_SIZE);
+
+ if (!VerifyDigest(digestPosServer, serversig, GenuineFMSKey, 36))
+ {
+ RTMP_Log(RTMP_LOGWARNING, "Trying different position for server digest!");
+ offalg ^= 1;
+ getdig = digoff[offalg];
+ getdh = dhoff[offalg];
+ digestPosServer = getdig(serversig, RTMP_SIG_SIZE);
+
+ if (!VerifyDigest(digestPosServer, serversig, GenuineFMSKey, 36))
+ {
+ RTMP_Log(RTMP_LOGERROR, "Couldn't verify the server digest"); /* continuing anyway will probably fail */
+ return FALSE;
+ }
+ }
+
+ /* generate SWFVerification token (SHA256 HMAC hash of decompressed SWF, key are the last 32 bytes of the server handshake) */
+ if (r->Link.SWFSize)
+ {
+ const char swfVerify[] = { 0x01, 0x01 };
+ char *vend = r->Link.SWFVerificationResponse+sizeof(r->Link.SWFVerificationResponse);
+
+ memcpy(r->Link.SWFVerificationResponse, swfVerify, 2);
+ AMF_EncodeInt32(&r->Link.SWFVerificationResponse[2], vend, r->Link.SWFSize);
+ AMF_EncodeInt32(&r->Link.SWFVerificationResponse[6], vend, r->Link.SWFSize);
+ HMACsha256(r->Link.SWFHash, SHA256_DIGEST_LENGTH,
+ &serversig[RTMP_SIG_SIZE - SHA256_DIGEST_LENGTH],
+ SHA256_DIGEST_LENGTH,
+ (uint8_t *)&r->Link.SWFVerificationResponse[10]);
+ }
+
+ /* do Diffie-Hellmann Key exchange for encrypted RTMP */
+ if (encrypted)
+ {
+ /* compute secret key */
+ uint8_t secretKey[128] = { 0 };
+ int len, dhposServer;
+
+ dhposServer = getdh(serversig, RTMP_SIG_SIZE);
+ RTMP_Log(RTMP_LOGDEBUG, "%s: Server DH public key offset: %d", __FUNCTION__,
+ dhposServer);
+ len = DHComputeSharedSecretKey(r->Link.dh, &serversig[dhposServer],
+ 128, secretKey);
+ if (len < 0)
+ {
+ RTMP_Log(RTMP_LOGDEBUG, "%s: Wrong secret key position!", __FUNCTION__);
+ return FALSE;
+ }
+
+ RTMP_Log(RTMP_LOGDEBUG, "%s: Secret key: ", __FUNCTION__);
+ RTMP_LogHex(RTMP_LOGDEBUG, secretKey, 128);
+
+ InitRC4Encryption(secretKey,
+ (uint8_t *) & serversig[dhposServer],
+ (uint8_t *) & clientsig[dhposClient],
+ &keyIn, &keyOut);
+ }
+
+
+ reply = client2;
+#ifdef _DEBUG
+ memset(reply, 0xff, RTMP_SIG_SIZE);
+#else
+ ip = (int32_t *)reply;
+ for (i = 0; i < RTMP_SIG_SIZE/4; i++)
+ *ip++ = rand();
+#endif
+ /* calculate response now */
+ signatureResp = reply+RTMP_SIG_SIZE-SHA256_DIGEST_LENGTH;
+
+ HMACsha256(&serversig[digestPosServer], SHA256_DIGEST_LENGTH,
+ GenuineFPKey, sizeof(GenuineFPKey), digestResp);
+ HMACsha256(reply, RTMP_SIG_SIZE - SHA256_DIGEST_LENGTH, digestResp,
+ SHA256_DIGEST_LENGTH, signatureResp);
+
+ /* some info output */
+ RTMP_Log(RTMP_LOGDEBUG,
+ "%s: Calculated digest key from secure key and server digest: ",
+ __FUNCTION__);
+ RTMP_LogHex(RTMP_LOGDEBUG, digestResp, SHA256_DIGEST_LENGTH);
+
+#ifdef FP10
+ if (type == 8 )
+ {
+ uint8_t *dptr = digestResp;
+ uint8_t *sig = signatureResp;
+ /* encrypt signatureResp */
+ for (i=0; iLink.rc4keyIn = keyIn;
+ r->Link.rc4keyOut = keyOut;
+
+
+ /* update the keystreams */
+ if (r->Link.rc4keyIn)
+ {
+ RC4_encrypt(r->Link.rc4keyIn, RTMP_SIG_SIZE, (uint8_t *) buff);
+ }
+
+ if (r->Link.rc4keyOut)
+ {
+ RC4_encrypt(r->Link.rc4keyOut, RTMP_SIG_SIZE, (uint8_t *) buff);
+ }
+ }
+ }
+ else
+ {
+ if (memcmp(serversig, clientsig, RTMP_SIG_SIZE) != 0)
+ {
+ RTMP_Log(RTMP_LOGWARNING, "%s: client signature does not match!",
+ __FUNCTION__);
+ }
+ }
+
+ RTMP_Log(RTMP_LOGDEBUG, "%s: Handshaking finished....", __FUNCTION__);
+ return TRUE;
+}
+
+static int
+SHandShake(RTMP * r)
+{
+ int i, offalg = 0;
+ int dhposServer = 0;
+ int digestPosServer = 0;
+ RC4_handle keyIn = 0;
+ RC4_handle keyOut = 0;
+ int FP9HandShake = FALSE;
+ int encrypted;
+ int32_t *ip;
+
+ uint8_t clientsig[RTMP_SIG_SIZE];
+ uint8_t serverbuf[RTMP_SIG_SIZE + 4], *serversig = serverbuf+4;
+ uint8_t type;
+ uint32_t uptime;
+ getoff *getdh = NULL, *getdig = NULL;
+
+ if (ReadN(r, (char *)&type, 1) != 1) /* 0x03 or 0x06 */
+ return FALSE;
+
+ if (ReadN(r, (char *)clientsig, RTMP_SIG_SIZE) != RTMP_SIG_SIZE)
+ return FALSE;
+
+ RTMP_Log(RTMP_LOGDEBUG, "%s: Type Requested : %02X", __FUNCTION__, type);
+ RTMP_LogHex(RTMP_LOGDEBUG2, clientsig, RTMP_SIG_SIZE);
+
+ if (type == 3)
+ {
+ encrypted = FALSE;
+ }
+ else if (type == 6 || type == 8)
+ {
+ offalg = 1;
+ encrypted = TRUE;
+ FP9HandShake = TRUE;
+ r->Link.protocol |= RTMP_FEATURE_ENC;
+ /* use FP10 if client is capable */
+ if (clientsig[4] == 128)
+ type = 8;
+ }
+ else
+ {
+ RTMP_Log(RTMP_LOGERROR, "%s: Unknown version %02x",
+ __FUNCTION__, type);
+ return FALSE;
+ }
+
+ if (!FP9HandShake && clientsig[4])
+ FP9HandShake = TRUE;
+
+ serversig[-1] = type;
+
+ r->Link.rc4keyIn = r->Link.rc4keyOut = 0;
+
+ uptime = htonl(RTMP_GetTime());
+ memcpy(serversig, &uptime, 4);
+
+ if (FP9HandShake)
+ {
+ /* Server version */
+ serversig[4] = 3;
+ serversig[5] = 5;
+ serversig[6] = 1;
+ serversig[7] = 1;
+
+ getdig = digoff[offalg];
+ getdh = dhoff[offalg];
+ }
+ else
+ {
+ memset(&serversig[4], 0, 4);
+ }
+
+ /* generate random data */
+#ifdef _DEBUG
+ memset(serversig+8, 0, RTMP_SIG_SIZE-8);
+#else
+ ip = (int32_t *)(serversig+8);
+ for (i = 2; i < RTMP_SIG_SIZE/4; i++)
+ *ip++ = rand();
+#endif
+
+ /* set handshake digest */
+ if (FP9HandShake)
+ {
+ if (encrypted)
+ {
+ /* generate Diffie-Hellmann parameters */
+ r->Link.dh = DHInit(1024);
+ if (!r->Link.dh)
+ {
+ RTMP_Log(RTMP_LOGERROR, "%s: Couldn't initialize Diffie-Hellmann!",
+ __FUNCTION__);
+ return FALSE;
+ }
+
+ dhposServer = getdh(serversig, RTMP_SIG_SIZE);
+ RTMP_Log(RTMP_LOGDEBUG, "%s: DH pubkey position: %d", __FUNCTION__, dhposServer);
+
+ if (!DHGenerateKey(r->Link.dh))
+ {
+ RTMP_Log(RTMP_LOGERROR, "%s: Couldn't generate Diffie-Hellmann public key!",
+ __FUNCTION__);
+ return FALSE;
+ }
+
+ if (!DHGetPublicKey
+ (r->Link.dh, (uint8_t *) &serversig[dhposServer], 128))
+ {
+ RTMP_Log(RTMP_LOGERROR, "%s: Couldn't write public key!", __FUNCTION__);
+ return FALSE;
+ }
+ }
+
+ digestPosServer = getdig(serversig, RTMP_SIG_SIZE); /* reuse this value in verification */
+ RTMP_Log(RTMP_LOGDEBUG, "%s: Server digest offset: %d", __FUNCTION__,
+ digestPosServer);
+
+ CalculateDigest(digestPosServer, serversig, GenuineFMSKey, 36,
+ &serversig[digestPosServer]);
+
+ RTMP_Log(RTMP_LOGDEBUG, "%s: Initial server digest: ", __FUNCTION__);
+ RTMP_LogHex(RTMP_LOGDEBUG, serversig + digestPosServer,
+ SHA256_DIGEST_LENGTH);
+ }
+
+ RTMP_Log(RTMP_LOGDEBUG2, "Serversig: ");
+ RTMP_LogHex(RTMP_LOGDEBUG2, serversig, RTMP_SIG_SIZE);
+
+ if (!WriteN(r, (char *)serversig-1, RTMP_SIG_SIZE + 1))
+ return FALSE;
+
+ /* decode client response */
+ memcpy(&uptime, clientsig, 4);
+ uptime = ntohl(uptime);
+
+ RTMP_Log(RTMP_LOGDEBUG, "%s: Client Uptime : %d", __FUNCTION__, uptime);
+ RTMP_Log(RTMP_LOGDEBUG, "%s: Player Version: %d.%d.%d.%d", __FUNCTION__, clientsig[4],
+ clientsig[5], clientsig[6], clientsig[7]);
+
+ if (FP9HandShake)
+ {
+ uint8_t digestResp[SHA256_DIGEST_LENGTH];
+ uint8_t *signatureResp = NULL;
+
+ /* we have to use this signature now to find the correct algorithms for getting the digest and DH positions */
+ int digestPosClient = getdig(clientsig, RTMP_SIG_SIZE);
+
+ if (!VerifyDigest(digestPosClient, clientsig, GenuineFPKey, 30))
+ {
+ RTMP_Log(RTMP_LOGWARNING, "Trying different position for client digest!");
+ offalg ^= 1;
+ getdig = digoff[offalg];
+ getdh = dhoff[offalg];
+
+ digestPosClient = getdig(clientsig, RTMP_SIG_SIZE);
+
+ if (!VerifyDigest(digestPosClient, clientsig, GenuineFPKey, 30))
+ {
+ RTMP_Log(RTMP_LOGERROR, "Couldn't verify the client digest"); /* continuing anyway will probably fail */
+ return FALSE;
+ }
+ }
+
+ /* generate SWFVerification token (SHA256 HMAC hash of decompressed SWF, key are the last 32 bytes of the server handshake) */
+ if (r->Link.SWFSize)
+ {
+ const char swfVerify[] = { 0x01, 0x01 };
+ char *vend = r->Link.SWFVerificationResponse+sizeof(r->Link.SWFVerificationResponse);
+
+ memcpy(r->Link.SWFVerificationResponse, swfVerify, 2);
+ AMF_EncodeInt32(&r->Link.SWFVerificationResponse[2], vend, r->Link.SWFSize);
+ AMF_EncodeInt32(&r->Link.SWFVerificationResponse[6], vend, r->Link.SWFSize);
+ HMACsha256(r->Link.SWFHash, SHA256_DIGEST_LENGTH,
+ &serversig[RTMP_SIG_SIZE - SHA256_DIGEST_LENGTH],
+ SHA256_DIGEST_LENGTH,
+ (uint8_t *)&r->Link.SWFVerificationResponse[10]);
+ }
+
+ /* do Diffie-Hellmann Key exchange for encrypted RTMP */
+ if (encrypted)
+ {
+ int dhposClient, len;
+ /* compute secret key */
+ uint8_t secretKey[128] = { 0 };
+
+ dhposClient = getdh(clientsig, RTMP_SIG_SIZE);
+ RTMP_Log(RTMP_LOGDEBUG, "%s: Client DH public key offset: %d", __FUNCTION__,
+ dhposClient);
+ len =
+ DHComputeSharedSecretKey(r->Link.dh,
+ (uint8_t *) &clientsig[dhposClient], 128,
+ secretKey);
+ if (len < 0)
+ {
+ RTMP_Log(RTMP_LOGDEBUG, "%s: Wrong secret key position!", __FUNCTION__);
+ return FALSE;
+ }
+
+ RTMP_Log(RTMP_LOGDEBUG, "%s: Secret key: ", __FUNCTION__);
+ RTMP_LogHex(RTMP_LOGDEBUG, secretKey, 128);
+
+ InitRC4Encryption(secretKey,
+ (uint8_t *) &clientsig[dhposClient],
+ (uint8_t *) &serversig[dhposServer],
+ &keyIn, &keyOut);
+ }
+
+
+ /* calculate response now */
+ signatureResp = clientsig+RTMP_SIG_SIZE-SHA256_DIGEST_LENGTH;
+
+ HMACsha256(&clientsig[digestPosClient], SHA256_DIGEST_LENGTH,
+ GenuineFMSKey, sizeof(GenuineFMSKey), digestResp);
+ HMACsha256(clientsig, RTMP_SIG_SIZE - SHA256_DIGEST_LENGTH, digestResp,
+ SHA256_DIGEST_LENGTH, signatureResp);
+#ifdef FP10
+ if (type == 8 )
+ {
+ uint8_t *dptr = digestResp;
+ uint8_t *sig = signatureResp;
+ /* encrypt signatureResp */
+ for (i=0; iLink.rc4keyIn = keyIn;
+ r->Link.rc4keyOut = keyOut;
+
+ /* update the keystreams */
+ if (r->Link.rc4keyIn)
+ {
+ RC4_encrypt(r->Link.rc4keyIn, RTMP_SIG_SIZE, (uint8_t *) buff);
+ }
+
+ if (r->Link.rc4keyOut)
+ {
+ RC4_encrypt(r->Link.rc4keyOut, RTMP_SIG_SIZE, (uint8_t *) buff);
+ }
+ }
+ }
+ else
+ {
+ if (memcmp(serversig, clientsig, RTMP_SIG_SIZE) != 0)
+ {
+ RTMP_Log(RTMP_LOGWARNING, "%s: client signature does not match!",
+ __FUNCTION__);
+ }
+ }
+
+ RTMP_Log(RTMP_LOGDEBUG, "%s: Handshaking finished....", __FUNCTION__);
+ return TRUE;
+}
diff --git a/Live/src/main/cpp/rtmp/hashswf.c b/Live/src/main/cpp/rtmp/hashswf.c
new file mode 100644
index 00000000..06d2bbb0
--- /dev/null
+++ b/Live/src/main/cpp/rtmp/hashswf.c
@@ -0,0 +1,665 @@
+/*
+ * Copyright (C) 2009-2010 Howard Chu
+ *
+ * This file is part of librtmp.
+ *
+ * librtmp is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1,
+ * or (at your option) any later version.
+ *
+ * librtmp is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with librtmp see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/lgpl.html
+ */
+
+#include
+#include
+#include
+#include
+#include
+
+#include "rtmp_sys.h"
+#include "log.h"
+#include "http.h"
+
+#ifdef CRYPTO
+#ifdef USE_POLARSSL
+#include
+#ifndef SHA256_DIGEST_LENGTH
+#define SHA256_DIGEST_LENGTH 32
+#endif
+#define HMAC_CTX sha2_context
+#define HMAC_setup(ctx, key, len) sha2_hmac_starts(&ctx, (unsigned char *)key, len, 0)
+#define HMAC_crunch(ctx, buf, len) sha2_hmac_update(&ctx, buf, len)
+#define HMAC_finish(ctx, dig, dlen) dlen = SHA256_DIGEST_LENGTH; sha2_hmac_finish(&ctx, dig)
+#define HMAC_close(ctx)
+#elif defined(USE_GNUTLS)
+#include
+#include
+#ifndef SHA256_DIGEST_LENGTH
+#define SHA256_DIGEST_LENGTH 32
+#endif
+#define HMAC_CTX gcry_md_hd_t
+#define HMAC_setup(ctx, key, len) gcry_md_open(&ctx, GCRY_MD_SHA256, GCRY_MD_FLAG_HMAC); gcry_md_setkey(ctx, key, len)
+#define HMAC_crunch(ctx, buf, len) gcry_md_write(ctx, buf, len)
+#define HMAC_finish(ctx, dig, dlen) dlen = SHA256_DIGEST_LENGTH; memcpy(dig, gcry_md_read(ctx, 0), dlen)
+#define HMAC_close(ctx) gcry_md_close(ctx)
+#else /* USE_OPENSSL */
+#include
+#include
+#include
+#include
+#define HMAC_setup(ctx, key, len) HMAC_CTX_init(&ctx); HMAC_Init_ex(&ctx, (unsigned char *)key, len, EVP_sha256(), 0)
+#define HMAC_crunch(ctx, buf, len) HMAC_Update(&ctx, (unsigned char *)buf, len)
+#define HMAC_finish(ctx, dig, dlen) HMAC_Final(&ctx, (unsigned char *)dig, &dlen);
+#define HMAC_close(ctx) HMAC_CTX_cleanup(&ctx)
+#endif
+
+extern void RTMP_TLS_Init();
+extern TLS_CTX RTMP_TLS_ctx;
+
+#endif /* CRYPTO */
+
+#include
+
+#define AGENT "Mozilla/5.0"
+
+HTTPResult
+HTTP_get(struct HTTP_ctx *http, const char *url, HTTP_read_callback *cb)
+{
+ char *host, *path;
+ char *p1, *p2;
+ char hbuf[256];
+ int port = 80;
+#ifdef CRYPTO
+ int ssl = 0;
+#endif
+ int hlen, flen = 0;
+ int rc, i;
+ int len_known;
+ HTTPResult ret = HTTPRES_OK;
+ struct sockaddr_in sa;
+ RTMPSockBuf sb = {0};
+
+ http->status = -1;
+
+ memset(&sa, 0, sizeof(struct sockaddr_in));
+ sa.sin_family = AF_INET;
+
+ /* we only handle http here */
+ if (strncasecmp(url, "http", 4))
+ return HTTPRES_BAD_REQUEST;
+
+ if (url[4] == 's')
+ {
+#ifdef CRYPTO
+ ssl = 1;
+ port = 443;
+ if (!RTMP_TLS_ctx)
+ RTMP_TLS_Init();
+#else
+ return HTTPRES_BAD_REQUEST;
+#endif
+ }
+
+ p1 = strchr(url + 4, ':');
+ if (!p1 || strncmp(p1, "://", 3))
+ return HTTPRES_BAD_REQUEST;
+
+ host = p1 + 3;
+ path = strchr(host, '/');
+ hlen = path - host;
+ strncpy(hbuf, host, hlen);
+ hbuf[hlen] = '\0';
+ host = hbuf;
+ p1 = strrchr(host, ':');
+ if (p1)
+ {
+ *p1++ = '\0';
+ port = atoi(p1);
+ }
+
+ sa.sin_addr.s_addr = inet_addr(host);
+ if (sa.sin_addr.s_addr == INADDR_NONE)
+ {
+ struct hostent *hp = gethostbyname(host);
+ if (!hp || !hp->h_addr)
+ return HTTPRES_LOST_CONNECTION;
+ sa.sin_addr = *(struct in_addr *)hp->h_addr;
+ }
+ sa.sin_port = htons(port);
+ sb.sb_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+ if (sb.sb_socket == -1)
+ return HTTPRES_LOST_CONNECTION;
+ i =
+ sprintf(sb.sb_buf,
+ "GET %s HTTP/1.0\r\nUser-Agent: %s\r\nHost: %s\r\nReferrer: %.*s\r\n",
+ path, AGENT, host, (int)(path - url + 1), url);
+ if (http->date[0])
+ i += sprintf(sb.sb_buf + i, "If-Modified-Since: %s\r\n", http->date);
+ i += sprintf(sb.sb_buf + i, "\r\n");
+
+ if (connect
+ (sb.sb_socket, (struct sockaddr *)&sa, sizeof(struct sockaddr)) < 0)
+ {
+ ret = HTTPRES_LOST_CONNECTION;
+ goto leave;
+ }
+#ifdef CRYPTO
+ if (ssl)
+ {
+#ifdef NO_SSL
+ RTMP_Log(RTMP_LOGERROR, "%s, No SSL/TLS support", __FUNCTION__);
+ ret = HTTPRES_BAD_REQUEST;
+ goto leave;
+#else
+ TLS_client(RTMP_TLS_ctx, sb.sb_ssl);
+ TLS_setfd(sb.sb_ssl, sb.sb_socket);
+ if ((i = TLS_connect(sb.sb_ssl)) < 0)
+ {
+ RTMP_Log(RTMP_LOGERROR, "%s, TLS_Connect failed", __FUNCTION__);
+ ret = HTTPRES_LOST_CONNECTION;
+ goto leave;
+ }
+#endif
+ }
+#endif
+ RTMPSockBuf_Send(&sb, sb.sb_buf, i);
+
+ /* set timeout */
+#define HTTP_TIMEOUT 5
+ {
+ SET_RCVTIMEO(tv, HTTP_TIMEOUT);
+ if (setsockopt
+ (sb.sb_socket, SOL_SOCKET, SO_RCVTIMEO, (char *)&tv, sizeof(tv)))
+ {
+ RTMP_Log(RTMP_LOGERROR, "%s, Setting socket timeout to %ds failed!",
+ __FUNCTION__, HTTP_TIMEOUT);
+ }
+ }
+
+ sb.sb_size = 0;
+ sb.sb_timedout = FALSE;
+ if (RTMPSockBuf_Fill(&sb) < 1)
+ {
+ ret = HTTPRES_LOST_CONNECTION;
+ goto leave;
+ }
+ if (strncmp(sb.sb_buf, "HTTP/1", 6))
+ {
+ ret = HTTPRES_BAD_REQUEST;
+ goto leave;
+ }
+
+ p1 = strchr(sb.sb_buf, ' ');
+ rc = atoi(p1 + 1);
+ http->status = rc;
+
+ if (rc >= 300)
+ {
+ if (rc == 304)
+ {
+ ret = HTTPRES_OK_NOT_MODIFIED;
+ goto leave;
+ }
+ else if (rc == 404)
+ ret = HTTPRES_NOT_FOUND;
+ else if (rc >= 500)
+ ret = HTTPRES_SERVER_ERROR;
+ else if (rc >= 400)
+ ret = HTTPRES_BAD_REQUEST;
+ else
+ ret = HTTPRES_REDIRECTED;
+ }
+
+ p1 = memchr(sb.sb_buf, '\n', sb.sb_size);
+ if (!p1)
+ {
+ ret = HTTPRES_BAD_REQUEST;
+ goto leave;
+ }
+ sb.sb_start = p1 + 1;
+ sb.sb_size -= sb.sb_start - sb.sb_buf;
+
+ while ((p2 = memchr(sb.sb_start, '\r', sb.sb_size)))
+ {
+ if (*sb.sb_start == '\r')
+ {
+ sb.sb_start += 2;
+ sb.sb_size -= 2;
+ break;
+ }
+ else
+ if (!strncasecmp
+ (sb.sb_start, "Content-Length: ", sizeof("Content-Length: ") - 1))
+ {
+ flen = atoi(sb.sb_start + sizeof("Content-Length: ") - 1);
+ }
+ else
+ if (!strncasecmp
+ (sb.sb_start, "Last-Modified: ", sizeof("Last-Modified: ") - 1))
+ {
+ *p2 = '\0';
+ strcpy(http->date, sb.sb_start + sizeof("Last-Modified: ") - 1);
+ }
+ p2 += 2;
+ sb.sb_size -= p2 - sb.sb_start;
+ sb.sb_start = p2;
+ if (sb.sb_size < 1)
+ {
+ if (RTMPSockBuf_Fill(&sb) < 1)
+ {
+ ret = HTTPRES_LOST_CONNECTION;
+ goto leave;
+ }
+ }
+ }
+
+ len_known = flen > 0;
+ while ((!len_known || flen > 0) &&
+ (sb.sb_size > 0 || RTMPSockBuf_Fill(&sb) > 0))
+ {
+ cb(sb.sb_start, 1, sb.sb_size, http->data);
+ if (len_known)
+ flen -= sb.sb_size;
+ http->size += sb.sb_size;
+ sb.sb_size = 0;
+ }
+
+ if (flen > 0)
+ ret = HTTPRES_LOST_CONNECTION;
+
+leave:
+ RTMPSockBuf_Close(&sb);
+ return ret;
+}
+
+#ifdef CRYPTO
+
+#define CHUNK 16384
+
+struct info
+{
+ z_stream *zs;
+ HMAC_CTX ctx;
+ int first;
+ int zlib;
+ int size;
+};
+
+static size_t
+swfcrunch(void *ptr, size_t size, size_t nmemb, void *stream)
+{
+ struct info *i = stream;
+ char *p = ptr;
+ size_t len = size * nmemb;
+
+ if (i->first)
+ {
+ i->first = 0;
+ /* compressed? */
+ if (!strncmp(p, "CWS", 3))
+ {
+ *p = 'F';
+ i->zlib = 1;
+ }
+ HMAC_crunch(i->ctx, (unsigned char *)p, 8);
+ p += 8;
+ len -= 8;
+ i->size = 8;
+ }
+
+ if (i->zlib)
+ {
+ unsigned char out[CHUNK];
+ i->zs->next_in = (unsigned char *)p;
+ i->zs->avail_in = len;
+ do
+ {
+ i->zs->avail_out = CHUNK;
+ i->zs->next_out = out;
+ inflate(i->zs, Z_NO_FLUSH);
+ len = CHUNK - i->zs->avail_out;
+ i->size += len;
+ HMAC_crunch(i->ctx, out, len);
+ }
+ while (i->zs->avail_out == 0);
+ }
+ else
+ {
+ i->size += len;
+ HMAC_crunch(i->ctx, (unsigned char *)p, len);
+ }
+ return size * nmemb;
+}
+
+static int tzoff;
+static int tzchecked;
+
+#define JAN02_1980 318340800
+
+static const char *monthtab[12] = { "Jan", "Feb", "Mar",
+ "Apr", "May", "Jun",
+ "Jul", "Aug", "Sep",
+ "Oct", "Nov", "Dec"
+};
+static const char *days[] =
+ { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" };
+
+/* Parse an HTTP datestamp into Unix time */
+static time_t
+make_unix_time(char *s)
+{
+ struct tm time;
+ int i, ysub = 1900, fmt = 0;
+ char *month;
+ char *n;
+ time_t res;
+
+ if (s[3] != ' ')
+ {
+ fmt = 1;
+ if (s[3] != ',')
+ ysub = 0;
+ }
+ for (n = s; *n; ++n)
+ if (*n == '-' || *n == ':')
+ *n = ' ';
+
+ time.tm_mon = 0;
+ n = strchr(s, ' ');
+ if (fmt)
+ {
+ /* Day, DD-MMM-YYYY HH:MM:SS GMT */
+ time.tm_mday = strtol(n + 1, &n, 0);
+ month = n + 1;
+ n = strchr(month, ' ');
+ time.tm_year = strtol(n + 1, &n, 0);
+ time.tm_hour = strtol(n + 1, &n, 0);
+ time.tm_min = strtol(n + 1, &n, 0);
+ time.tm_sec = strtol(n + 1, NULL, 0);
+ }
+ else
+ {
+ /* Unix ctime() format. Does not conform to HTTP spec. */
+ /* Day MMM DD HH:MM:SS YYYY */
+ month = n + 1;
+ n = strchr(month, ' ');
+ while (isspace(*n))
+ n++;
+ time.tm_mday = strtol(n, &n, 0);
+ time.tm_hour = strtol(n + 1, &n, 0);
+ time.tm_min = strtol(n + 1, &n, 0);
+ time.tm_sec = strtol(n + 1, &n, 0);
+ time.tm_year = strtol(n + 1, NULL, 0);
+ }
+ if (time.tm_year > 100)
+ time.tm_year -= ysub;
+
+ for (i = 0; i < 12; i++)
+ if (!strncasecmp(month, monthtab[i], 3))
+ {
+ time.tm_mon = i;
+ break;
+ }
+ time.tm_isdst = 0; /* daylight saving is never in effect in GMT */
+
+ /* this is normally the value of extern int timezone, but some
+ * braindead C libraries don't provide it.
+ */
+ if (!tzchecked)
+ {
+ struct tm *tc;
+ time_t then = JAN02_1980;
+ tc = localtime(&then);
+ tzoff = (12 - tc->tm_hour) * 3600 + tc->tm_min * 60 + tc->tm_sec;
+ tzchecked = 1;
+ }
+ res = mktime(&time);
+ /* Unfortunately, mktime() assumes the input is in local time,
+ * not GMT, so we have to correct it here.
+ */
+ if (res != -1)
+ res += tzoff;
+ return res;
+}
+
+/* Convert a Unix time to a network time string
+ * Weekday, DD-MMM-YYYY HH:MM:SS GMT
+ */
+void
+strtime(time_t * t, char *s)
+{
+ struct tm *tm;
+
+ tm = gmtime((time_t *) t);
+ sprintf(s, "%s, %02d %s %d %02d:%02d:%02d GMT",
+ days[tm->tm_wday], tm->tm_mday, monthtab[tm->tm_mon],
+ tm->tm_year + 1900, tm->tm_hour, tm->tm_min, tm->tm_sec);
+}
+
+#define HEX2BIN(a) (((a)&0x40)?((a)&0xf)+9:((a)&0xf))
+
+int
+RTMP_HashSWF(const char *url, unsigned int *size, unsigned char *hash,
+ int age)
+{
+ FILE *f = NULL;
+ char *path, date[64], cctim[64];
+ long pos = 0;
+ time_t ctim = -1, cnow;
+ int i, got = 0, ret = 0;
+ unsigned int hlen;
+ struct info in = { 0 };
+ struct HTTP_ctx http = { 0 };
+ HTTPResult httpres;
+ z_stream zs = { 0 };
+ AVal home, hpre;
+
+ date[0] = '\0';
+#ifdef _WIN32
+#ifdef _XBOX
+ hpre.av_val = "Q:";
+ hpre.av_len = 2;
+ home.av_val = "\\UserData";
+#else
+ hpre.av_val = getenv("HOMEDRIVE");
+ hpre.av_len = strlen(hpre.av_val);
+ home.av_val = getenv("HOMEPATH");
+#endif
+#define DIRSEP "\\"
+
+#else /* !_WIN32 */
+ hpre.av_val = "";
+ hpre.av_len = 0;
+ home.av_val = getenv("HOME");
+#define DIRSEP "/"
+#endif
+ if (!home.av_val)
+ home.av_val = ".";
+ home.av_len = strlen(home.av_val);
+
+ /* SWF hash info is cached in a fixed-format file.
+ * url:
+ * ctim: HTTP datestamp of when we last checked it.
+ * date: HTTP datestamp of the SWF's last modification.
+ * size: SWF size in hex
+ * hash: SWF hash in hex
+ *
+ * These fields must be present in this order. All fields
+ * besides URL are fixed size.
+ */
+ path = malloc(hpre.av_len + home.av_len + sizeof(DIRSEP ".swfinfo"));
+ sprintf(path, "%s%s" DIRSEP ".swfinfo", hpre.av_val, home.av_val);
+
+ f = fopen(path, "r+");
+ while (f)
+ {
+ char buf[4096], *file, *p;
+
+ file = strchr(url, '/');
+ if (!file)
+ break;
+ file += 2;
+ file = strchr(file, '/');
+ if (!file)
+ break;
+ file++;
+ hlen = file - url;
+ p = strrchr(file, '/');
+ if (p)
+ file = p;
+ else
+ file--;
+
+ while (fgets(buf, sizeof(buf), f))
+ {
+ char *r1;
+
+ got = 0;
+
+ if (strncmp(buf, "url: ", 5))
+ continue;
+ if (strncmp(buf + 5, url, hlen))
+ continue;
+ r1 = strrchr(buf, '/');
+ i = strlen(r1);
+ r1[--i] = '\0';
+ if (strncmp(r1, file, i))
+ continue;
+ pos = ftell(f);
+ while (got < 4 && fgets(buf, sizeof(buf), f))
+ {
+ if (!strncmp(buf, "size: ", 6))
+ {
+ *size = strtol(buf + 6, NULL, 16);
+ got++;
+ }
+ else if (!strncmp(buf, "hash: ", 6))
+ {
+ unsigned char *ptr = hash, *in = (unsigned char *)buf + 6;
+ int l = strlen((char *)in) - 1;
+ for (i = 0; i < l; i += 2)
+ *ptr++ = (HEX2BIN(in[i]) << 4) | HEX2BIN(in[i + 1]);
+ got++;
+ }
+ else if (!strncmp(buf, "date: ", 6))
+ {
+ buf[strlen(buf) - 1] = '\0';
+ strncpy(date, buf + 6, sizeof(date));
+ got++;
+ }
+ else if (!strncmp(buf, "ctim: ", 6))
+ {
+ buf[strlen(buf) - 1] = '\0';
+ ctim = make_unix_time(buf + 6);
+ got++;
+ }
+ else if (!strncmp(buf, "url: ", 5))
+ break;
+ }
+ break;
+ }
+ break;
+ }
+
+ cnow = time(NULL);
+ /* If we got a cache time, see if it's young enough to use directly */
+ if (age && ctim > 0)
+ {
+ ctim = cnow - ctim;
+ ctim /= 3600 * 24; /* seconds to days */
+ if (ctim < age) /* ok, it's new enough */
+ goto out;
+ }
+
+ in.first = 1;
+ HMAC_setup(in.ctx, "Genuine Adobe Flash Player 001", 30);
+ inflateInit(&zs);
+ in.zs = &zs;
+
+ http.date = date;
+ http.data = ∈
+
+ httpres = HTTP_get(&http, url, swfcrunch);
+
+ inflateEnd(&zs);
+
+ if (httpres != HTTPRES_OK && httpres != HTTPRES_OK_NOT_MODIFIED)
+ {
+ ret = -1;
+ if (httpres == HTTPRES_LOST_CONNECTION)
+ RTMP_Log(RTMP_LOGERROR, "%s: connection lost while downloading swfurl %s",
+ __FUNCTION__, url);
+ else if (httpres == HTTPRES_NOT_FOUND)
+ RTMP_Log(RTMP_LOGERROR, "%s: swfurl %s not found", __FUNCTION__, url);
+ else
+ RTMP_Log(RTMP_LOGERROR, "%s: couldn't contact swfurl %s (HTTP error %d)",
+ __FUNCTION__, url, http.status);
+ }
+ else
+ {
+ if (got && pos)
+ fseek(f, pos, SEEK_SET);
+ else
+ {
+ char *q;
+ if (!f)
+ f = fopen(path, "w");
+ if (!f)
+ {
+ int err = errno;
+ RTMP_Log(RTMP_LOGERROR,
+ "%s: couldn't open %s for writing, errno %d (%s)",
+ __FUNCTION__, path, err, strerror(err));
+ ret = -1;
+ goto out;
+ }
+ fseek(f, 0, SEEK_END);
+ q = strchr(url, '?');
+ if (q)
+ i = q - url;
+ else
+ i = strlen(url);
+
+ fprintf(f, "url: %.*s\n", i, url);
+ }
+ strtime(&cnow, cctim);
+ fprintf(f, "ctim: %s\n", cctim);
+
+ if (!in.first)
+ {
+ HMAC_finish(in.ctx, hash, hlen);
+ *size = in.size;
+
+ fprintf(f, "date: %s\n", date);
+ fprintf(f, "size: %08x\n", in.size);
+ fprintf(f, "hash: ");
+ for (i = 0; i < SHA256_DIGEST_LENGTH; i++)
+ fprintf(f, "%02x", hash[i]);
+ fprintf(f, "\n");
+ }
+ }
+ HMAC_close(in.ctx);
+out:
+ free(path);
+ if (f)
+ fclose(f);
+ return ret;
+}
+#else
+int
+RTMP_HashSWF(const char *url, unsigned int *size, unsigned char *hash,
+ int age)
+{
+ return -1;
+}
+#endif
diff --git a/Live/src/main/cpp/include/rtmp/http.h b/Live/src/main/cpp/rtmp/http.h
similarity index 100%
rename from Live/src/main/cpp/include/rtmp/http.h
rename to Live/src/main/cpp/rtmp/http.h
diff --git a/Live/src/main/cpp/rtmp/log.c b/Live/src/main/cpp/rtmp/log.c
new file mode 100644
index 00000000..0012985c
--- /dev/null
+++ b/Live/src/main/cpp/rtmp/log.c
@@ -0,0 +1,220 @@
+/*
+ * Copyright (C) 2008-2009 Andrej Stepanchuk
+ * Copyright (C) 2009-2010 Howard Chu
+ *
+ * This file is part of librtmp.
+ *
+ * librtmp is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1,
+ * or (at your option) any later version.
+ *
+ * librtmp is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with librtmp see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/lgpl.html
+ */
+
+#include
+#include
+#include
+#include
+#include
+
+#include "rtmp_sys.h"
+#include "log.h"
+
+#define MAX_PRINT_LEN 2048
+
+RTMP_LogLevel RTMP_debuglevel = RTMP_LOGERROR;
+
+static int neednl;
+
+static FILE *fmsg;
+
+static RTMP_LogCallback rtmp_log_default, *cb = rtmp_log_default;
+
+static const char *levels[] = {
+ "CRIT", "ERROR", "WARNING", "INFO",
+ "DEBUG", "DEBUG2"
+};
+
+static void rtmp_log_default(int level, const char *format, va_list vl)
+{
+ char str[MAX_PRINT_LEN]="";
+
+ vsnprintf(str, MAX_PRINT_LEN-1, format, vl);
+
+ /* Filter out 'no-name' */
+ if ( RTMP_debuglevel RTMP_debuglevel )
+ return;
+
+ ptr = line;
+
+ for(i=0; i> 4)];
+ *ptr++ = hexdig[0x0f & data[i]];
+ if ((i & 0x0f) == 0x0f) {
+ *ptr = '\0';
+ ptr = line;
+ RTMP_Log(level, "%s", line);
+ } else {
+ *ptr++ = ' ';
+ }
+ }
+ if (i & 0x0f) {
+ *ptr = '\0';
+ RTMP_Log(level, "%s", line);
+ }
+}
+
+void RTMP_LogHexString(int level, const uint8_t *data, unsigned long len)
+{
+#define BP_OFFSET 9
+#define BP_GRAPH 60
+#define BP_LEN 80
+ char line[BP_LEN];
+ unsigned long i;
+
+ if ( !data || level > RTMP_debuglevel )
+ return;
+
+ /* in case len is zero */
+ line[0] = '\0';
+
+ for ( i = 0 ; i < len ; i++ ) {
+ int n = i % 16;
+ unsigned off;
+
+ if( !n ) {
+ if( i ) RTMP_Log( level, "%s", line );
+ memset( line, ' ', sizeof(line)-2 );
+ line[sizeof(line)-2] = '\0';
+
+ off = i % 0x0ffffU;
+
+ line[2] = hexdig[0x0f & (off >> 12)];
+ line[3] = hexdig[0x0f & (off >> 8)];
+ line[4] = hexdig[0x0f & (off >> 4)];
+ line[5] = hexdig[0x0f & off];
+ line[6] = ':';
+ }
+
+ off = BP_OFFSET + n*3 + ((n >= 8)?1:0);
+ line[off] = hexdig[0x0f & ( data[i] >> 4 )];
+ line[off+1] = hexdig[0x0f & data[i]];
+
+ off = BP_GRAPH + n + ((n >= 8)?1:0);
+
+ if ( isprint( data[i] )) {
+ line[BP_GRAPH + n] = data[i];
+ } else {
+ line[BP_GRAPH + n] = '.';
+ }
+ }
+
+ RTMP_Log( level, "%s", line );
+}
+
+/* These should only be used by apps, never by the library itself */
+void RTMP_LogPrintf(const char *format, ...)
+{
+ char str[MAX_PRINT_LEN]="";
+ int len;
+ va_list args;
+ va_start(args, format);
+ len = vsnprintf(str, MAX_PRINT_LEN-1, format, args);
+ va_end(args);
+
+ if ( RTMP_debuglevel==RTMP_LOGCRIT )
+ return;
+
+ if ( !fmsg ) fmsg = stderr;
+
+ if (neednl) {
+ putc('\n', fmsg);
+ neednl = 0;
+ }
+
+ if (len > MAX_PRINT_LEN-1)
+ len = MAX_PRINT_LEN-1;
+ fprintf(fmsg, "%s", str);
+ if (str[len-1] == '\n')
+ fflush(fmsg);
+}
+
+void RTMP_LogStatus(const char *format, ...)
+{
+ char str[MAX_PRINT_LEN]="";
+ va_list args;
+ va_start(args, format);
+ vsnprintf(str, MAX_PRINT_LEN-1, format, args);
+ va_end(args);
+
+ if ( RTMP_debuglevel==RTMP_LOGCRIT )
+ return;
+
+ if ( !fmsg ) fmsg = stderr;
+
+ fprintf(fmsg, "%s", str);
+ fflush(fmsg);
+ neednl = 1;
+}
diff --git a/Live/src/main/cpp/include/rtmp/log.h b/Live/src/main/cpp/rtmp/log.h
similarity index 100%
rename from Live/src/main/cpp/include/rtmp/log.h
rename to Live/src/main/cpp/rtmp/log.h
diff --git a/Live/src/main/cpp/rtmp/parseurl.c b/Live/src/main/cpp/rtmp/parseurl.c
new file mode 100644
index 00000000..0183958c
--- /dev/null
+++ b/Live/src/main/cpp/rtmp/parseurl.c
@@ -0,0 +1,285 @@
+/*
+ * Copyright (C) 2009 Andrej Stepanchuk
+ * Copyright (C) 2009-2010 Howard Chu
+ *
+ * This file is part of librtmp.
+ *
+ * librtmp is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1,
+ * or (at your option) any later version.
+ *
+ * librtmp is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with librtmp see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/lgpl.html
+ */
+
+#include
+#include
+
+#include
+#include
+
+#include "rtmp_sys.h"
+#include "log.h"
+
+int RTMP_ParseURL(const char *url, int *protocol, AVal *host, unsigned int *port,
+ AVal *playpath, AVal *app)
+{
+ char *p, *end, *col, *ques, *slash;
+
+ RTMP_Log(RTMP_LOGDEBUG, "Parsing...");
+
+ *protocol = RTMP_PROTOCOL_RTMP;
+ *port = 0;
+ playpath->av_len = 0;
+ playpath->av_val = NULL;
+ app->av_len = 0;
+ app->av_val = NULL;
+
+ /* Old School Parsing */
+
+ /* look for usual :// pattern */
+ p = strstr(url, "://");
+ if(!p) {
+ RTMP_Log(RTMP_LOGERROR, "RTMP URL: No :// in url!");
+ return FALSE;
+ }
+ {
+ int len = (int)(p-url);
+
+ if(len == 4 && strncasecmp(url, "rtmp", 4)==0)
+ *protocol = RTMP_PROTOCOL_RTMP;
+ else if(len == 5 && strncasecmp(url, "rtmpt", 5)==0)
+ *protocol = RTMP_PROTOCOL_RTMPT;
+ else if(len == 5 && strncasecmp(url, "rtmps", 5)==0)
+ *protocol = RTMP_PROTOCOL_RTMPS;
+ else if(len == 5 && strncasecmp(url, "rtmpe", 5)==0)
+ *protocol = RTMP_PROTOCOL_RTMPE;
+ else if(len == 5 && strncasecmp(url, "rtmfp", 5)==0)
+ *protocol = RTMP_PROTOCOL_RTMFP;
+ else if(len == 6 && strncasecmp(url, "rtmpte", 6)==0)
+ *protocol = RTMP_PROTOCOL_RTMPTE;
+ else if(len == 6 && strncasecmp(url, "rtmpts", 6)==0)
+ *protocol = RTMP_PROTOCOL_RTMPTS;
+ else {
+ RTMP_Log(RTMP_LOGWARNING, "Unknown protocol!\n");
+ goto parsehost;
+ }
+ }
+
+ RTMP_Log(RTMP_LOGDEBUG, "Parsed protocol: %d", *protocol);
+
+parsehost:
+ /* let's get the hostname */
+ p+=3;
+
+ /* check for sudden death */
+ if(*p==0) {
+ RTMP_Log(RTMP_LOGWARNING, "No hostname in URL!");
+ return FALSE;
+ }
+
+ end = p + strlen(p);
+ col = strchr(p, ':');
+ ques = strchr(p, '?');
+ slash = strchr(p, '/');
+
+ {
+ int hostlen;
+ if(slash)
+ hostlen = slash - p;
+ else
+ hostlen = end - p;
+ if(col && col -p < hostlen)
+ hostlen = col - p;
+
+ if(hostlen < 256) {
+ host->av_val = p;
+ host->av_len = hostlen;
+ RTMP_Log(RTMP_LOGDEBUG, "Parsed host : %.*s", hostlen, host->av_val);
+ } else {
+ RTMP_Log(RTMP_LOGWARNING, "Hostname exceeds 255 characters!");
+ }
+
+ p+=hostlen;
+ }
+
+ /* get the port number if available */
+ if(*p == ':') {
+ unsigned int p2;
+ p++;
+ p2 = atoi(p);
+ if(p2 > 65535) {
+ RTMP_Log(RTMP_LOGWARNING, "Invalid port number!");
+ } else {
+ *port = p2;
+ }
+ }
+
+ if(!slash) {
+ RTMP_Log(RTMP_LOGWARNING, "No application or playpath in URL!");
+ return TRUE;
+ }
+ p = slash+1;
+
+ {
+ /* parse application
+ *
+ * rtmp://host[:port]/app[/appinstance][/...]
+ * application = app[/appinstance]
+ */
+
+ char *slash2, *slash3 = NULL;
+ int applen, appnamelen;
+
+ slash2 = strchr(p, '/');
+ if(slash2)
+ slash3 = strchr(slash2+1, '/');
+
+ applen = end-p; /* ondemand, pass all parameters as app */
+ appnamelen = applen; /* ondemand length */
+
+ if(ques && strstr(p, "slist=")) { /* whatever it is, the '?' and slist= means we need to use everything as app and parse plapath from slist= */
+ appnamelen = ques-p;
+ }
+ else if(strncmp(p, "ondemand/", 9)==0) {
+ /* app = ondemand/foobar, only pass app=ondemand */
+ applen = 8;
+ appnamelen = 8;
+ }
+ else { /* app!=ondemand, so app is app[/appinstance] */
+ if(slash3)
+ appnamelen = slash3-p;
+ else if(slash2)
+ appnamelen = slash2-p;
+
+ applen = appnamelen;
+ }
+
+ app->av_val = p;
+ app->av_len = applen;
+ RTMP_Log(RTMP_LOGDEBUG, "Parsed app : %.*s", applen, p);
+
+ p += appnamelen;
+ }
+
+ if (*p == '/')
+ p++;
+
+ if (end-p) {
+ AVal av = {p, end-p};
+ RTMP_ParsePlaypath(&av, playpath);
+ }
+
+ return TRUE;
+}
+
+/*
+ * Extracts playpath from RTMP URL. playpath is the file part of the
+ * URL, i.e. the part that comes after rtmp://host:port/app/
+ *
+ * Returns the stream name in a format understood by FMS. The name is
+ * the playpath part of the URL with formatting depending on the stream
+ * type:
+ *
+ * mp4 streams: prepend "mp4:", remove extension
+ * mp3 streams: prepend "mp3:", remove extension
+ * flv streams: remove extension
+ */
+void RTMP_ParsePlaypath(AVal *in, AVal *out) {
+ int addMP4 = 0;
+ int addMP3 = 0;
+ int subExt = 0;
+ const char *playpath = in->av_val;
+ const char *temp, *q, *ext = NULL;
+ const char *ppstart = playpath;
+ char *streamname, *destptr, *p;
+
+ int pplen = in->av_len;
+
+ out->av_val = NULL;
+ out->av_len = 0;
+
+ if ((*ppstart == '?') &&
+ (temp=strstr(ppstart, "slist=")) != 0) {
+ ppstart = temp+6;
+ pplen = strlen(ppstart);
+
+ temp = strchr(ppstart, '&');
+ if (temp) {
+ pplen = temp-ppstart;
+ }
+ }
+
+ q = strchr(ppstart, '?');
+ if (pplen >= 4) {
+ if (q)
+ ext = q-4;
+ else
+ ext = &ppstart[pplen-4];
+ if ((strncmp(ext, ".f4v", 4) == 0) ||
+ (strncmp(ext, ".mp4", 4) == 0)) {
+ addMP4 = 1;
+ subExt = 1;
+ /* Only remove .flv from rtmp URL, not slist params */
+ } else if ((ppstart == playpath) &&
+ (strncmp(ext, ".flv", 4) == 0)) {
+ subExt = 1;
+ } else if (strncmp(ext, ".mp3", 4) == 0) {
+ addMP3 = 1;
+ subExt = 1;
+ }
+ }
+
+ streamname = (char *)malloc((pplen+4+1)*sizeof(char));
+ if (!streamname)
+ return;
+
+ destptr = streamname;
+ if (addMP4) {
+ if (strncmp(ppstart, "mp4:", 4)) {
+ strcpy(destptr, "mp4:");
+ destptr += 4;
+ } else {
+ subExt = 0;
+ }
+ } else if (addMP3) {
+ if (strncmp(ppstart, "mp3:", 4)) {
+ strcpy(destptr, "mp3:");
+ destptr += 4;
+ } else {
+ subExt = 0;
+ }
+ }
+
+ for (p=(char *)ppstart; pplen >0;) {
+ /* skip extension */
+ if (subExt && p == ext) {
+ p += 4;
+ pplen -= 4;
+ continue;
+ }
+ if (*p == '%') {
+ unsigned int c;
+ sscanf(p+1, "%02x", &c);
+ *destptr++ = c;
+ pplen -= 3;
+ p += 3;
+ } else {
+ *destptr++ = *p++;
+ pplen--;
+ }
+ }
+ *destptr = '\0';
+
+ out->av_val = streamname;
+ out->av_len = destptr - streamname;
+}
diff --git a/Live/src/main/cpp/rtmp/rtmp.c b/Live/src/main/cpp/rtmp/rtmp.c
new file mode 100644
index 00000000..39466c1c
--- /dev/null
+++ b/Live/src/main/cpp/rtmp/rtmp.c
@@ -0,0 +1,4388 @@
+/*
+ * Copyright (C) 2005-2008 Team XBMC
+ * http://www.xbmc.org
+ * Copyright (C) 2008-2009 Andrej Stepanchuk
+ * Copyright (C) 2009-2010 Howard Chu
+ *
+ * This file is part of librtmp.
+ *
+ * librtmp is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1,
+ * or (at your option) any later version.
+ *
+ * librtmp is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with librtmp see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/lgpl.html
+ */
+
+#include
+#include
+#include
+#include
+
+#include "rtmp_sys.h"
+#include "log.h"
+
+#ifdef CRYPTO
+#ifdef USE_POLARSSL
+#include
+#elif defined(USE_GNUTLS)
+#include
+#else /* USE_OPENSSL */
+#include
+#include
+#endif
+TLS_CTX RTMP_TLS_ctx;
+#endif
+
+#define RTMP_SIG_SIZE 1536
+#define RTMP_LARGE_HEADER_SIZE 12
+
+static const int packetSize[] = { 12, 8, 4, 1 };
+
+int RTMP_ctrlC;
+
+const char RTMPProtocolStrings[][7] = {
+ "RTMP",
+ "RTMPT",
+ "RTMPE",
+ "RTMPTE",
+ "RTMPS",
+ "RTMPTS",
+ "",
+ "",
+ "RTMFP"
+};
+
+const char RTMPProtocolStringsLower[][7] = {
+ "rtmp",
+ "rtmpt",
+ "rtmpe",
+ "rtmpte",
+ "rtmps",
+ "rtmpts",
+ "",
+ "",
+ "rtmfp"
+};
+
+static const char *RTMPT_cmds[] = {
+ "open",
+ "send",
+ "idle",
+ "close"
+};
+
+typedef enum {
+ RTMPT_OPEN=0, RTMPT_SEND, RTMPT_IDLE, RTMPT_CLOSE
+} RTMPTCmd;
+
+static int DumpMetaData(AMFObject *obj);
+static int HandShake(RTMP *r, int FP9HandShake);
+static int SocksNegotiate(RTMP *r);
+
+static int SendConnectPacket(RTMP *r, RTMPPacket *cp);
+static int SendCheckBW(RTMP *r);
+static int SendCheckBWResult(RTMP *r, double txn);
+static int SendDeleteStream(RTMP *r, double dStreamId);
+static int SendFCSubscribe(RTMP *r, AVal *subscribepath);
+static int SendPlay(RTMP *r);
+static int SendBytesReceived(RTMP *r);
+
+#if 0 /* unused */
+static int SendBGHasStream(RTMP *r, double dId, AVal *playpath);
+#endif
+
+static int HandleInvoke(RTMP *r, const char *body, unsigned int nBodySize);
+static int HandleMetadata(RTMP *r, char *body, unsigned int len);
+static void HandleChangeChunkSize(RTMP *r, const RTMPPacket *packet);
+static void HandleAudio(RTMP *r, const RTMPPacket *packet);
+static void HandleVideo(RTMP *r, const RTMPPacket *packet);
+static void HandleCtrl(RTMP *r, const RTMPPacket *packet);
+static void HandleServerBW(RTMP *r, const RTMPPacket *packet);
+static void HandleClientBW(RTMP *r, const RTMPPacket *packet);
+
+static int ReadN(RTMP *r, char *buffer, int n);
+static int WriteN(RTMP *r, const char *buffer, int n);
+
+static void DecodeTEA(AVal *key, AVal *text);
+
+static int HTTP_Post(RTMP *r, RTMPTCmd cmd, const char *buf, int len);
+static int HTTP_read(RTMP *r, int fill);
+
+#ifndef _WIN32
+static int clk_tck;
+#endif
+
+#ifdef CRYPTO
+#include "handshake.h"
+#endif
+
+uint32_t
+RTMP_GetTime()
+{
+#ifdef _DEBUG
+ return 0;
+#elif defined(_WIN32)
+ return timeGetTime();
+#else
+ struct tms t;
+ if (!clk_tck) clk_tck = sysconf(_SC_CLK_TCK);
+ return times(&t) * 1000 / clk_tck;
+#endif
+}
+
+void
+RTMP_UserInterrupt()
+{
+ RTMP_ctrlC = TRUE;
+}
+
+void
+RTMPPacket_Reset(RTMPPacket *p)
+{
+ p->m_headerType = 0;
+ p->m_packetType = 0;
+ p->m_nChannel = 0;
+ p->m_nTimeStamp = 0;
+ p->m_nInfoField2 = 0;
+ p->m_hasAbsTimestamp = FALSE;
+ p->m_nBodySize = 0;
+ p->m_nBytesRead = 0;
+}
+
+int
+RTMPPacket_Alloc(RTMPPacket *p, int nSize)
+{
+ char *ptr = calloc(1, nSize + RTMP_MAX_HEADER_SIZE);
+ if (!ptr)
+ return FALSE;
+ p->m_body = ptr + RTMP_MAX_HEADER_SIZE;
+ p->m_nBytesRead = 0;
+ return TRUE;
+}
+
+void
+RTMPPacket_Free(RTMPPacket *p)
+{
+ if (p->m_body)
+ {
+ free(p->m_body - RTMP_MAX_HEADER_SIZE);
+ p->m_body = NULL;
+ }
+}
+
+void
+RTMPPacket_Dump(RTMPPacket *p)
+{
+ RTMP_Log(RTMP_LOGDEBUG,
+ "RTMP PACKET: packet type: 0x%02x. channel: 0x%02x. info 1: %d info 2: %d. Body size: %lu. body: 0x%02x",
+ p->m_packetType, p->m_nChannel, p->m_nTimeStamp, p->m_nInfoField2,
+ p->m_nBodySize, p->m_body ? (unsigned char)p->m_body[0] : 0);
+}
+
+int
+RTMP_LibVersion()
+{
+ return RTMP_LIB_VERSION;
+}
+
+void
+RTMP_TLS_Init()
+{
+#ifdef CRYPTO
+#ifdef USE_POLARSSL
+ /* Do this regardless of NO_SSL, we use havege for rtmpe too */
+ RTMP_TLS_ctx = calloc(1,sizeof(struct tls_ctx));
+ havege_init(&RTMP_TLS_ctx->hs);
+#elif defined(USE_GNUTLS) && !defined(NO_SSL)
+ /* Technically we need to initialize libgcrypt ourselves if
+ * we're not going to call gnutls_global_init(). Ignoring this
+ * for now.
+ */
+ gnutls_global_init();
+ RTMP_TLS_ctx = malloc(sizeof(struct tls_ctx));
+ gnutls_certificate_allocate_credentials(&RTMP_TLS_ctx->cred);
+ gnutls_priority_init(&RTMP_TLS_ctx->prios, "NORMAL", NULL);
+ gnutls_certificate_set_x509_trust_file(RTMP_TLS_ctx->cred,
+ "ca.pem", GNUTLS_X509_FMT_PEM);
+#elif !defined(NO_SSL) /* USE_OPENSSL */
+ /* libcrypto doesn't need anything special */
+ SSL_load_error_strings();
+ SSL_library_init();
+ OpenSSL_add_all_digests();
+ RTMP_TLS_ctx = SSL_CTX_new(SSLv23_method());
+ SSL_CTX_set_options(RTMP_TLS_ctx, SSL_OP_ALL);
+ SSL_CTX_set_default_verify_paths(RTMP_TLS_ctx);
+#endif
+#endif
+}
+
+RTMP *
+RTMP_Alloc()
+{
+ return calloc(1, sizeof(RTMP));
+}
+
+void
+RTMP_Free(RTMP *r)
+{
+ free(r);
+}
+
+void
+RTMP_Init(RTMP *r)
+{
+#ifdef CRYPTO
+ if (!RTMP_TLS_ctx)
+ RTMP_TLS_Init();
+#endif
+
+ memset(r, 0, sizeof(RTMP));
+ r->m_sb.sb_socket = -1;
+ r->m_inChunkSize = RTMP_DEFAULT_CHUNKSIZE;
+ r->m_outChunkSize = RTMP_DEFAULT_CHUNKSIZE;
+ r->m_nBufferMS = 30000;
+ r->m_nClientBW = 2500000;
+ r->m_nClientBW2 = 2;
+ r->m_nServerBW = 2500000;
+ r->m_fAudioCodecs = 3191.0;
+ r->m_fVideoCodecs = 252.0;
+ r->Link.timeout = 30;
+ r->Link.swfAge = 30;
+}
+
+void
+RTMP_EnableWrite(RTMP *r)
+{
+ r->Link.protocol |= RTMP_FEATURE_WRITE;
+}
+
+double
+RTMP_GetDuration(RTMP *r)
+{
+ return r->m_fDuration;
+}
+
+int
+RTMP_IsConnected(RTMP *r)
+{
+ return r->m_sb.sb_socket != -1;
+}
+
+int
+RTMP_Socket(RTMP *r)
+{
+ return r->m_sb.sb_socket;
+}
+
+int
+RTMP_IsTimedout(RTMP *r)
+{
+ return r->m_sb.sb_timedout;
+}
+
+void
+RTMP_SetBufferMS(RTMP *r, int size)
+{
+ r->m_nBufferMS = size;
+}
+
+void
+RTMP_UpdateBufferMS(RTMP *r)
+{
+ RTMP_SendCtrl(r, 3, r->m_stream_id, r->m_nBufferMS);
+}
+
+#undef OSS
+#ifdef _WIN32
+#define OSS "WIN"
+#elif defined(__sun__)
+#define OSS "SOL"
+#elif defined(__APPLE__)
+#define OSS "MAC"
+#elif defined(__linux__)
+#define OSS "LNX"
+#else
+#define OSS "GNU"
+#endif
+#define DEF_VERSTR OSS " 10,0,32,18"
+static const char DEFAULT_FLASH_VER[] = DEF_VERSTR;
+const AVal RTMP_DefaultFlashVer =
+ { (char *)DEFAULT_FLASH_VER, sizeof(DEFAULT_FLASH_VER) - 1 };
+
+void
+RTMP_SetupStream(RTMP *r,
+ int protocol,
+ AVal *host,
+ unsigned int port,
+ AVal *sockshost,
+ AVal *playpath,
+ AVal *tcUrl,
+ AVal *swfUrl,
+ AVal *pageUrl,
+ AVal *app,
+ AVal *auth,
+ AVal *swfSHA256Hash,
+ uint32_t swfSize,
+ AVal *flashVer,
+ AVal *subscribepath,
+ int dStart,
+ int dStop, int bLiveStream, long int timeout)
+{
+ RTMP_Log(RTMP_LOGDEBUG, "Protocol : %s", RTMPProtocolStrings[protocol&7]);
+ RTMP_Log(RTMP_LOGDEBUG, "Hostname : %.*s", host->av_len, host->av_val);
+ RTMP_Log(RTMP_LOGDEBUG, "Port : %d", port);
+ RTMP_Log(RTMP_LOGDEBUG, "Playpath : %s", playpath->av_val);
+
+ if (tcUrl && tcUrl->av_val)
+ RTMP_Log(RTMP_LOGDEBUG, "tcUrl : %s", tcUrl->av_val);
+ if (swfUrl && swfUrl->av_val)
+ RTMP_Log(RTMP_LOGDEBUG, "swfUrl : %s", swfUrl->av_val);
+ if (pageUrl && pageUrl->av_val)
+ RTMP_Log(RTMP_LOGDEBUG, "pageUrl : %s", pageUrl->av_val);
+ if (app && app->av_val)
+ RTMP_Log(RTMP_LOGDEBUG, "app : %.*s", app->av_len, app->av_val);
+ if (auth && auth->av_val)
+ RTMP_Log(RTMP_LOGDEBUG, "auth : %s", auth->av_val);
+ if (subscribepath && subscribepath->av_val)
+ RTMP_Log(RTMP_LOGDEBUG, "subscribepath : %s", subscribepath->av_val);
+ if (flashVer && flashVer->av_val)
+ RTMP_Log(RTMP_LOGDEBUG, "flashVer : %s", flashVer->av_val);
+ if (dStart > 0)
+ RTMP_Log(RTMP_LOGDEBUG, "StartTime : %d msec", dStart);
+ if (dStop > 0)
+ RTMP_Log(RTMP_LOGDEBUG, "StopTime : %d msec", dStop);
+
+ RTMP_Log(RTMP_LOGDEBUG, "live : %s", bLiveStream ? "yes" : "no");
+ RTMP_Log(RTMP_LOGDEBUG, "timeout : %d sec", timeout);
+
+#ifdef CRYPTO
+ if (swfSHA256Hash != NULL && swfSize > 0)
+ {
+ memcpy(r->Link.SWFHash, swfSHA256Hash->av_val, sizeof(r->Link.SWFHash));
+ r->Link.SWFSize = swfSize;
+ RTMP_Log(RTMP_LOGDEBUG, "SWFSHA256:");
+ RTMP_LogHex(RTMP_LOGDEBUG, r->Link.SWFHash, sizeof(r->Link.SWFHash));
+ RTMP_Log(RTMP_LOGDEBUG, "SWFSize : %lu", r->Link.SWFSize);
+ }
+ else
+ {
+ r->Link.SWFSize = 0;
+ }
+#endif
+
+ if (sockshost->av_len)
+ {
+ const char *socksport = strchr(sockshost->av_val, ':');
+ char *hostname = strdup(sockshost->av_val);
+
+ if (socksport)
+ hostname[socksport - sockshost->av_val] = '\0';
+ r->Link.sockshost.av_val = hostname;
+ r->Link.sockshost.av_len = strlen(hostname);
+
+ r->Link.socksport = socksport ? atoi(socksport + 1) : 1080;
+ RTMP_Log(RTMP_LOGDEBUG, "Connecting via SOCKS proxy: %s:%d", r->Link.sockshost.av_val,
+ r->Link.socksport);
+ }
+ else
+ {
+ r->Link.sockshost.av_val = NULL;
+ r->Link.sockshost.av_len = 0;
+ r->Link.socksport = 0;
+ }
+
+ if (tcUrl && tcUrl->av_len)
+ r->Link.tcUrl = *tcUrl;
+ if (swfUrl && swfUrl->av_len)
+ r->Link.swfUrl = *swfUrl;
+ if (pageUrl && pageUrl->av_len)
+ r->Link.pageUrl = *pageUrl;
+ if (app && app->av_len)
+ r->Link.app = *app;
+ if (auth && auth->av_len)
+ {
+ r->Link.auth = *auth;
+ r->Link.lFlags |= RTMP_LF_AUTH;
+ }
+ if (flashVer && flashVer->av_len)
+ r->Link.flashVer = *flashVer;
+ else
+ r->Link.flashVer = RTMP_DefaultFlashVer;
+ if (subscribepath && subscribepath->av_len)
+ r->Link.subscribepath = *subscribepath;
+ r->Link.seekTime = dStart;
+ r->Link.stopTime = dStop;
+ if (bLiveStream)
+ r->Link.lFlags |= RTMP_LF_LIVE;
+ r->Link.timeout = timeout;
+
+ r->Link.protocol = protocol;
+ r->Link.hostname = *host;
+ r->Link.port = port;
+ r->Link.playpath = *playpath;
+
+ if (r->Link.port == 0)
+ {
+ if (protocol & RTMP_FEATURE_SSL)
+ r->Link.port = 443;
+ else if (protocol & RTMP_FEATURE_HTTP)
+ r->Link.port = 80;
+ else
+ r->Link.port = 1935;
+ }
+}
+
+enum { OPT_STR=0, OPT_INT, OPT_BOOL, OPT_CONN };
+static const char *optinfo[] = {
+ "string", "integer", "boolean", "AMF" };
+
+#define OFF(x) offsetof(struct RTMP,x)
+
+static struct urlopt {
+ AVal name;
+ off_t off;
+ int otype;
+ int omisc;
+ char *use;
+} options[] = {
+ { AVC("socks"), OFF(Link.sockshost), OPT_STR, 0,
+ "Use the specified SOCKS proxy" },
+ { AVC("app"), OFF(Link.app), OPT_STR, 0,
+ "Name of target app on server" },
+ { AVC("tcUrl"), OFF(Link.tcUrl), OPT_STR, 0,
+ "URL to played stream" },
+ { AVC("pageUrl"), OFF(Link.pageUrl), OPT_STR, 0,
+ "URL of played media's web page" },
+ { AVC("swfUrl"), OFF(Link.swfUrl), OPT_STR, 0,
+ "URL to player SWF file" },
+ { AVC("flashver"), OFF(Link.flashVer), OPT_STR, 0,
+ "Flash version string (default " DEF_VERSTR ")" },
+ { AVC("conn"), OFF(Link.extras), OPT_CONN, 0,
+ "Append arbitrary AMF data to Connect message" },
+ { AVC("playpath"), OFF(Link.playpath), OPT_STR, 0,
+ "Path to target media on server" },
+ { AVC("playlist"), OFF(Link.lFlags), OPT_BOOL, RTMP_LF_PLST,
+ "Set playlist before play command" },
+ { AVC("live"), OFF(Link.lFlags), OPT_BOOL, RTMP_LF_LIVE,
+ "Stream is live, no seeking possible" },
+ { AVC("subscribe"), OFF(Link.subscribepath), OPT_STR, 0,
+ "Stream to subscribe to" },
+ { AVC("token"), OFF(Link.token), OPT_STR, 0,
+ "Key for SecureToken response" },
+ { AVC("swfVfy"), OFF(Link.lFlags), OPT_BOOL, RTMP_LF_SWFV,
+ "Perform SWF Verification" },
+ { AVC("swfAge"), OFF(Link.swfAge), OPT_INT, 0,
+ "Number of days to use cached SWF hash" },
+ { AVC("start"), OFF(Link.seekTime), OPT_INT, 0,
+ "Stream start position in milliseconds" },
+ { AVC("stop"), OFF(Link.stopTime), OPT_INT, 0,
+ "Stream stop position in milliseconds" },
+ { AVC("buffer"), OFF(m_nBufferMS), OPT_INT, 0,
+ "Buffer time in milliseconds" },
+ { AVC("timeout"), OFF(Link.timeout), OPT_INT, 0,
+ "Session timeout in seconds" },
+ { {NULL,0}, 0, 0}
+};
+
+static const AVal truth[] = {
+ AVC("1"),
+ AVC("on"),
+ AVC("yes"),
+ AVC("true"),
+ {0,0}
+};
+
+static void RTMP_OptUsage()
+{
+ int i;
+
+ RTMP_Log(RTMP_LOGERROR, "Valid RTMP options are:\n");
+ for (i=0; options[i].name.av_len; i++) {
+ RTMP_Log(RTMP_LOGERROR, "%10s %-7s %s\n", options[i].name.av_val,
+ optinfo[options[i].otype], options[i].use);
+ }
+}
+
+static int
+parseAMF(AMFObject *obj, AVal *av, int *depth)
+{
+ AMFObjectProperty prop = {{0,0}};
+ int i;
+ char *p, *arg = av->av_val;
+
+ if (arg[1] == ':')
+ {
+ p = (char *)arg+2;
+ switch(arg[0])
+ {
+ case 'B':
+ prop.p_type = AMF_BOOLEAN;
+ prop.p_vu.p_number = atoi(p);
+ break;
+ case 'S':
+ prop.p_type = AMF_STRING;
+ prop.p_vu.p_aval.av_val = p;
+ prop.p_vu.p_aval.av_len = av->av_len - (p-arg);
+ break;
+ case 'N':
+ prop.p_type = AMF_NUMBER;
+ prop.p_vu.p_number = strtod(p, NULL);
+ break;
+ case 'Z':
+ prop.p_type = AMF_NULL;
+ break;
+ case 'O':
+ i = atoi(p);
+ if (i)
+ {
+ prop.p_type = AMF_OBJECT;
+ }
+ else
+ {
+ (*depth)--;
+ return 0;
+ }
+ break;
+ default:
+ return -1;
+ }
+ }
+ else if (arg[2] == ':' && arg[0] == 'N')
+ {
+ p = strchr(arg+3, ':');
+ if (!p || !*depth)
+ return -1;
+ prop.p_name.av_val = (char *)arg+3;
+ prop.p_name.av_len = p - (arg+3);
+
+ p++;
+ switch(arg[1])
+ {
+ case 'B':
+ prop.p_type = AMF_BOOLEAN;
+ prop.p_vu.p_number = atoi(p);
+ break;
+ case 'S':
+ prop.p_type = AMF_STRING;
+ prop.p_vu.p_aval.av_val = p;
+ prop.p_vu.p_aval.av_len = av->av_len - (p-arg);
+ break;
+ case 'N':
+ prop.p_type = AMF_NUMBER;
+ prop.p_vu.p_number = strtod(p, NULL);
+ break;
+ case 'O':
+ prop.p_type = AMF_OBJECT;
+ break;
+ default:
+ return -1;
+ }
+ }
+ else
+ return -1;
+
+ if (*depth)
+ {
+ AMFObject *o2;
+ for (i=0; i<*depth; i++)
+ {
+ o2 = &obj->o_props[obj->o_num-1].p_vu.p_object;
+ obj = o2;
+ }
+ }
+ AMF_AddProp(obj, &prop);
+ if (prop.p_type == AMF_OBJECT)
+ (*depth)++;
+ return 0;
+}
+
+int RTMP_SetOpt(RTMP *r, const AVal *opt, AVal *arg)
+{
+ int i;
+ void *v;
+
+ for (i=0; options[i].name.av_len; i++) {
+ if (opt->av_len != options[i].name.av_len) continue;
+ if (strcasecmp(opt->av_val, options[i].name.av_val)) continue;
+ v = (char *)r + options[i].off;
+ switch(options[i].otype) {
+ case OPT_STR: {
+ AVal *aptr = v;
+ *aptr = *arg; }
+ break;
+ case OPT_INT: {
+ long l = strtol(arg->av_val, NULL, 0);
+ *(int *)v = l; }
+ break;
+ case OPT_BOOL: {
+ int j, fl;
+ fl = *(int *)v;
+ for (j=0; truth[j].av_len; j++) {
+ if (arg->av_len != truth[j].av_len) continue;
+ if (strcasecmp(arg->av_val, truth[j].av_val)) continue;
+ fl |= options[i].omisc; break; }
+ *(int *)v = fl;
+ }
+ break;
+ case OPT_CONN:
+ if (parseAMF(&r->Link.extras, arg, &r->Link.edepth))
+ return FALSE;
+ break;
+ }
+ break;
+ }
+ if (!options[i].name.av_len) {
+ RTMP_Log(RTMP_LOGERROR, "Unknown option %s", opt->av_val);
+ RTMP_OptUsage();
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+int RTMP_SetupURL(RTMP *r, char *url)
+{
+ AVal opt, arg;
+ char *p1, *p2, *ptr = strchr(url, ' ');
+ int ret, len;
+ unsigned int port = 0;
+
+ if (ptr)
+ *ptr = '\0';
+
+ len = strlen(url);
+ ret = RTMP_ParseURL(url, &r->Link.protocol, &r->Link.hostname,
+ &port, &r->Link.playpath0, &r->Link.app);
+ if (!ret)
+ return ret;
+ r->Link.port = port;
+ r->Link.playpath = r->Link.playpath0;
+
+ while (ptr) {
+ *ptr++ = '\0';
+ p1 = ptr;
+ p2 = strchr(p1, '=');
+ if (!p2)
+ break;
+ opt.av_val = p1;
+ opt.av_len = p2 - p1;
+ *p2++ = '\0';
+ arg.av_val = p2;
+ ptr = strchr(p2, ' ');
+ if (ptr) {
+ *ptr = '\0';
+ arg.av_len = ptr - p2;
+ /* skip repeated spaces */
+ while(ptr[1] == ' ')
+ *ptr++ = '\0';
+ } else {
+ arg.av_len = strlen(p2);
+ }
+
+ /* unescape */
+ port = arg.av_len;
+ for (p1=p2; port >0;) {
+ if (*p1 == '\\') {
+ unsigned int c;
+ if (port < 3)
+ return FALSE;
+ sscanf(p1+1, "%02x", &c);
+ *p2++ = c;
+ port -= 3;
+ p1 += 3;
+ } else {
+ *p2++ = *p1++;
+ port--;
+ }
+ }
+ arg.av_len = p2 - arg.av_val;
+
+ ret = RTMP_SetOpt(r, &opt, &arg);
+ if (!ret)
+ return ret;
+ }
+
+ if (!r->Link.tcUrl.av_len)
+ {
+ r->Link.tcUrl.av_val = url;
+ if (r->Link.app.av_len)
+ {
+ if (r->Link.app.av_val < url + len)
+ {
+ /* if app is part of original url, just use it */
+ r->Link.tcUrl.av_len = r->Link.app.av_len + (r->Link.app.av_val - url);
+ }
+ else
+ {
+ len = r->Link.hostname.av_len + r->Link.app.av_len +
+ sizeof("rtmpte://:65535/");
+ r->Link.tcUrl.av_val = malloc(len);
+ r->Link.tcUrl.av_len = snprintf(r->Link.tcUrl.av_val, len,
+ "%s://%.*s:%d/%.*s",
+ RTMPProtocolStringsLower[r->Link.protocol],
+ r->Link.hostname.av_len, r->Link.hostname.av_val,
+ r->Link.port,
+ r->Link.app.av_len, r->Link.app.av_val);
+ r->Link.lFlags |= RTMP_LF_FTCU;
+ }
+ }
+ else
+ {
+ r->Link.tcUrl.av_len = strlen(url);
+ }
+ }
+
+#ifdef CRYPTO
+ if ((r->Link.lFlags & RTMP_LF_SWFV) && r->Link.swfUrl.av_len)
+ RTMP_HashSWF(r->Link.swfUrl.av_val, &r->Link.SWFSize,
+ (unsigned char *)r->Link.SWFHash, r->Link.swfAge);
+#endif
+
+ if (r->Link.port == 0)
+ {
+ if (r->Link.protocol & RTMP_FEATURE_SSL)
+ r->Link.port = 443;
+ else if (r->Link.protocol & RTMP_FEATURE_HTTP)
+ r->Link.port = 80;
+ else
+ r->Link.port = 1935;
+ }
+ return TRUE;
+}
+
+static int
+add_addr_info(struct sockaddr_in *service, AVal *host, int port)
+{
+ char *hostname;
+ int ret = TRUE;
+ if (host->av_val[host->av_len])
+ {
+ hostname = malloc(host->av_len+1);
+ memcpy(hostname, host->av_val, host->av_len);
+ hostname[host->av_len] = '\0';
+ }
+ else
+ {
+ hostname = host->av_val;
+ }
+
+ service->sin_addr.s_addr = inet_addr(hostname);
+ if (service->sin_addr.s_addr == INADDR_NONE)
+ {
+ struct hostent *host = gethostbyname(hostname);
+ if (host == NULL || host->h_addr == NULL)
+ {
+ RTMP_Log(RTMP_LOGERROR, "Problem accessing the DNS. (addr: %s)", hostname);
+ ret = FALSE;
+ goto finish;
+ }
+ service->sin_addr = *(struct in_addr *)host->h_addr;
+ }
+
+ service->sin_port = htons(port);
+finish:
+ if (hostname != host->av_val)
+ free(hostname);
+ return ret;
+}
+
+int
+RTMP_Connect0(RTMP *r, struct sockaddr * service)
+{
+ int on = 1;
+ r->m_sb.sb_timedout = FALSE;
+ r->m_pausing = 0;
+ r->m_fDuration = 0.0;
+
+ r->m_sb.sb_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+ if (r->m_sb.sb_socket != -1)
+ {
+ SET_RCVTIMEO(tv, r->Link.timeout);
+ if (setsockopt
+ (r->m_sb.sb_socket, SOL_SOCKET, SO_SNDTIMEO, (char *)&tv, sizeof(tv)))
+ {
+ RTMP_Log(RTMP_LOGERROR, "%s, Setting socket timeout to %ds failed!",
+ __FUNCTION__, r->Link.timeout);
+ }
+
+ if (connect(r->m_sb.sb_socket, service, sizeof(struct sockaddr)) < 0)
+ {
+ int err = GetSockError();
+ RTMP_Log(RTMP_LOGERROR, "%s, failed to connect socket. %d (%s)",
+ __FUNCTION__, err, strerror(err));
+ RTMP_Close(r);
+ return FALSE;
+ }
+
+ if (r->Link.socksport)
+ {
+ RTMP_Log(RTMP_LOGDEBUG, "%s ... SOCKS negotiation", __FUNCTION__);
+ if (!SocksNegotiate(r))
+ {
+ RTMP_Log(RTMP_LOGERROR, "%s, SOCKS negotiation failed.", __FUNCTION__);
+ RTMP_Close(r);
+ return FALSE;
+ }
+ }
+ }
+ else
+ {
+ RTMP_Log(RTMP_LOGERROR, "%s, failed to create socket. Error: %d", __FUNCTION__,
+ GetSockError());
+ return FALSE;
+ }
+
+ /* set timeout */
+ {
+ SET_RCVTIMEO(tv, r->Link.timeout);
+ if (setsockopt
+ (r->m_sb.sb_socket, SOL_SOCKET, SO_RCVTIMEO, (char *)&tv, sizeof(tv)))
+ {
+ RTMP_Log(RTMP_LOGERROR, "%s, Setting socket timeout to %ds failed!",
+ __FUNCTION__, r->Link.timeout);
+ }
+ }
+
+ setsockopt(r->m_sb.sb_socket, IPPROTO_TCP, TCP_NODELAY, (char *) &on, sizeof(on));
+
+ return TRUE;
+}
+
+int
+RTMP_Connect1(RTMP *r, RTMPPacket *cp)
+{
+ if (r->Link.protocol & RTMP_FEATURE_SSL)
+ {
+#if defined(CRYPTO) && !defined(NO_SSL)
+ TLS_client(RTMP_TLS_ctx, r->m_sb.sb_ssl);
+ TLS_setfd(r->m_sb.sb_ssl, r->m_sb.sb_socket);
+ if (TLS_connect(r->m_sb.sb_ssl) < 0)
+ {
+ RTMP_Log(RTMP_LOGERROR, "%s, TLS_Connect failed", __FUNCTION__);
+ RTMP_Close(r);
+ return FALSE;
+ }
+#else
+ RTMP_Log(RTMP_LOGERROR, "%s, no SSL/TLS support", __FUNCTION__);
+ RTMP_Close(r);
+ return FALSE;
+
+#endif
+ }
+ if (r->Link.protocol & RTMP_FEATURE_HTTP)
+ {
+ r->m_msgCounter = 1;
+ r->m_clientID.av_val = NULL;
+ r->m_clientID.av_len = 0;
+ HTTP_Post(r, RTMPT_OPEN, "", 1);
+ HTTP_read(r, 1);
+ r->m_msgCounter = 0;
+ }
+ RTMP_Log(RTMP_LOGDEBUG, "%s, ... connected, handshaking", __FUNCTION__);
+ if (!HandShake(r, TRUE))
+ {
+ RTMP_Log(RTMP_LOGERROR, "%s, handshake failed.", __FUNCTION__);
+ RTMP_Close(r);
+ return FALSE;
+ }
+ RTMP_Log(RTMP_LOGDEBUG, "%s, handshaked", __FUNCTION__);
+
+ if (!SendConnectPacket(r, cp))
+ {
+ RTMP_Log(RTMP_LOGERROR, "%s, RTMP connect failed.", __FUNCTION__);
+ RTMP_Close(r);
+ return FALSE;
+ }
+ return TRUE;
+}
+
+int
+RTMP_Connect(RTMP *r, RTMPPacket *cp)
+{
+ struct sockaddr_in service;
+ if (!r->Link.hostname.av_len)
+ return FALSE;
+
+ memset(&service, 0, sizeof(struct sockaddr_in));
+ service.sin_family = AF_INET;
+
+ if (r->Link.socksport)
+ {
+ /* Connect via SOCKS */
+ if (!add_addr_info(&service, &r->Link.sockshost, r->Link.socksport))
+ return FALSE;
+ }
+ else
+ {
+ /* Connect directly */
+ if (!add_addr_info(&service, &r->Link.hostname, r->Link.port))
+ return FALSE;
+ }
+
+ if (!RTMP_Connect0(r, (struct sockaddr *)&service))
+ return FALSE;
+
+ r->m_bSendCounter = TRUE;
+
+ return RTMP_Connect1(r, cp);
+}
+
+static int
+SocksNegotiate(RTMP *r)
+{
+ unsigned long addr;
+ struct sockaddr_in service;
+ memset(&service, 0, sizeof(struct sockaddr_in));
+
+ add_addr_info(&service, &r->Link.hostname, r->Link.port);
+ addr = htonl(service.sin_addr.s_addr);
+
+ {
+ char packet[] = {
+ 4, 1, /* SOCKS 4, connect */
+ (r->Link.port >> 8) & 0xFF,
+ (r->Link.port) & 0xFF,
+ (char)(addr >> 24) & 0xFF, (char)(addr >> 16) & 0xFF,
+ (char)(addr >> 8) & 0xFF, (char)addr & 0xFF,
+ 0
+ }; /* NULL terminate */
+
+ WriteN(r, packet, sizeof packet);
+
+ if (ReadN(r, packet, 8) != 8)
+ return FALSE;
+
+ if (packet[0] == 0 && packet[1] == 90)
+ {
+ return TRUE;
+ }
+ else
+ {
+ RTMP_Log(RTMP_LOGERROR, "%s, SOCKS returned error code %d", packet[1]);
+ return FALSE;
+ }
+ }
+}
+
+int
+RTMP_ConnectStream(RTMP *r, int seekTime)
+{
+ RTMPPacket packet = { 0 };
+
+ /* seekTime was already set by SetupStream / SetupURL.
+ * This is only needed by ReconnectStream.
+ */
+ if (seekTime > 0)
+ r->Link.seekTime = seekTime;
+
+ r->m_mediaChannel = 0;
+
+ while (!r->m_bPlaying && RTMP_IsConnected(r) && RTMP_ReadPacket(r, &packet))
+ {
+ if (RTMPPacket_IsReady(&packet))
+ {
+ if (!packet.m_nBodySize)
+ continue;
+ if ((packet.m_packetType == RTMP_PACKET_TYPE_AUDIO) ||
+ (packet.m_packetType == RTMP_PACKET_TYPE_VIDEO) ||
+ (packet.m_packetType == RTMP_PACKET_TYPE_INFO))
+ {
+ RTMP_Log(RTMP_LOGWARNING, "Received FLV packet before play()! Ignoring.");
+ RTMPPacket_Free(&packet);
+ continue;
+ }
+
+ RTMP_ClientPacket(r, &packet);
+ RTMPPacket_Free(&packet);
+ }
+ }
+
+ return r->m_bPlaying;
+}
+
+int
+RTMP_ReconnectStream(RTMP *r, int seekTime)
+{
+ RTMP_DeleteStream(r);
+
+ RTMP_SendCreateStream(r);
+
+ return RTMP_ConnectStream(r, seekTime);
+}
+
+int
+RTMP_ToggleStream(RTMP *r)
+{
+ int res;
+
+ if (!r->m_pausing)
+ {
+ res = RTMP_SendPause(r, TRUE, r->m_pauseStamp);
+ if (!res)
+ return res;
+
+ r->m_pausing = 1;
+ sleep(1);
+ }
+ res = RTMP_SendPause(r, FALSE, r->m_pauseStamp);
+ r->m_pausing = 3;
+ return res;
+}
+
+void
+RTMP_DeleteStream(RTMP *r)
+{
+ if (r->m_stream_id < 0)
+ return;
+
+ r->m_bPlaying = FALSE;
+
+ SendDeleteStream(r, r->m_stream_id);
+ r->m_stream_id = -1;
+}
+
+int
+RTMP_GetNextMediaPacket(RTMP *r, RTMPPacket *packet)
+{
+ int bHasMediaPacket = 0;
+
+ while (!bHasMediaPacket && RTMP_IsConnected(r)
+ && RTMP_ReadPacket(r, packet))
+ {
+ if (!RTMPPacket_IsReady(packet))
+ {
+ continue;
+ }
+
+ bHasMediaPacket = RTMP_ClientPacket(r, packet);
+
+ if (!bHasMediaPacket)
+ {
+ RTMPPacket_Free(packet);
+ }
+ else if (r->m_pausing == 3)
+ {
+ if (packet->m_nTimeStamp <= r->m_mediaStamp)
+ {
+ bHasMediaPacket = 0;
+#ifdef _DEBUG
+ RTMP_Log(RTMP_LOGDEBUG,
+ "Skipped type: %02X, size: %d, TS: %d ms, abs TS: %d, pause: %d ms",
+ packet->m_packetType, packet->m_nBodySize,
+ packet->m_nTimeStamp, packet->m_hasAbsTimestamp,
+ r->m_mediaStamp);
+#endif
+ continue;
+ }
+ r->m_pausing = 0;
+ }
+ }
+
+ if (bHasMediaPacket)
+ r->m_bPlaying = TRUE;
+ else if (r->m_sb.sb_timedout && !r->m_pausing)
+ r->m_pauseStamp = r->m_channelTimestamp[r->m_mediaChannel];
+
+ return bHasMediaPacket;
+}
+
+int
+RTMP_ClientPacket(RTMP *r, RTMPPacket *packet)
+{
+ int bHasMediaPacket = 0;
+ switch (packet->m_packetType)
+ {
+ case 0x01:
+ /* chunk size */
+ HandleChangeChunkSize(r, packet);
+ break;
+
+ case 0x03:
+ /* bytes read report */
+ RTMP_Log(RTMP_LOGDEBUG, "%s, received: bytes read report", __FUNCTION__);
+ break;
+
+ case 0x04:
+ /* ctrl */
+ HandleCtrl(r, packet);
+ break;
+
+ case 0x05:
+ /* server bw */
+ HandleServerBW(r, packet);
+ break;
+
+ case 0x06:
+ /* client bw */
+ HandleClientBW(r, packet);
+ break;
+
+ case 0x08:
+ /* audio data */
+ /*RTMP_Log(RTMP_LOGDEBUG, "%s, received: audio %lu bytes", __FUNCTION__, packet.m_nBodySize); */
+ HandleAudio(r, packet);
+ bHasMediaPacket = 1;
+ if (!r->m_mediaChannel)
+ r->m_mediaChannel = packet->m_nChannel;
+ if (!r->m_pausing)
+ r->m_mediaStamp = packet->m_nTimeStamp;
+ break;
+
+ case 0x09:
+ /* video data */
+ /*RTMP_Log(RTMP_LOGDEBUG, "%s, received: video %lu bytes", __FUNCTION__, packet.m_nBodySize); */
+ HandleVideo(r, packet);
+ bHasMediaPacket = 1;
+ if (!r->m_mediaChannel)
+ r->m_mediaChannel = packet->m_nChannel;
+ if (!r->m_pausing)
+ r->m_mediaStamp = packet->m_nTimeStamp;
+ break;
+
+ case 0x0F: /* flex stream send */
+ RTMP_Log(RTMP_LOGDEBUG,
+ "%s, flex stream send, size %lu bytes, not supported, ignoring",
+ __FUNCTION__, packet->m_nBodySize);
+ break;
+
+ case 0x10: /* flex shared object */
+ RTMP_Log(RTMP_LOGDEBUG,
+ "%s, flex shared object, size %lu bytes, not supported, ignoring",
+ __FUNCTION__, packet->m_nBodySize);
+ break;
+
+ case 0x11: /* flex message */
+ {
+ RTMP_Log(RTMP_LOGDEBUG,
+ "%s, flex message, size %lu bytes, not fully supported",
+ __FUNCTION__, packet->m_nBodySize);
+ /*RTMP_LogHex(packet.m_body, packet.m_nBodySize); */
+
+ /* some DEBUG code */
+#if 0
+ RTMP_LIB_AMFObject obj;
+ int nRes = obj.Decode(packet.m_body+1, packet.m_nBodySize-1);
+ if(nRes < 0) {
+ RTMP_Log(RTMP_LOGERROR, "%s, error decoding AMF3 packet", __FUNCTION__);
+ /*return; */
+ }
+
+ obj.Dump();
+#endif
+
+ if (HandleInvoke(r, packet->m_body + 1, packet->m_nBodySize - 1) == 1)
+ bHasMediaPacket = 2;
+ break;
+ }
+ case 0x12:
+ /* metadata (notify) */
+ RTMP_Log(RTMP_LOGDEBUG, "%s, received: notify %lu bytes", __FUNCTION__,
+ packet->m_nBodySize);
+ if (HandleMetadata(r, packet->m_body, packet->m_nBodySize))
+ bHasMediaPacket = 1;
+ break;
+
+ case 0x13:
+ RTMP_Log(RTMP_LOGDEBUG, "%s, shared object, not supported, ignoring",
+ __FUNCTION__);
+ break;
+
+ case 0x14:
+ /* invoke */
+ RTMP_Log(RTMP_LOGDEBUG, "%s, received: invoke %lu bytes", __FUNCTION__,
+ packet->m_nBodySize);
+ /*RTMP_LogHex(packet.m_body, packet.m_nBodySize); */
+
+ if (HandleInvoke(r, packet->m_body, packet->m_nBodySize) == 1)
+ bHasMediaPacket = 2;
+ break;
+
+ case 0x16:
+ {
+ /* go through FLV packets and handle metadata packets */
+ unsigned int pos = 0;
+ uint32_t nTimeStamp = packet->m_nTimeStamp;
+
+ while (pos + 11 < packet->m_nBodySize)
+ {
+ uint32_t dataSize = AMF_DecodeInt24(packet->m_body + pos + 1); /* size without header (11) and prevTagSize (4) */
+
+ if (pos + 11 + dataSize + 4 > packet->m_nBodySize)
+ {
+ RTMP_Log(RTMP_LOGWARNING, "Stream corrupt?!");
+ break;
+ }
+ if (packet->m_body[pos] == 0x12)
+ {
+ HandleMetadata(r, packet->m_body + pos + 11, dataSize);
+ }
+ else if (packet->m_body[pos] == 8 || packet->m_body[pos] == 9)
+ {
+ nTimeStamp = AMF_DecodeInt24(packet->m_body + pos + 4);
+ nTimeStamp |= (packet->m_body[pos + 7] << 24);
+ }
+ pos += (11 + dataSize + 4);
+ }
+ if (!r->m_pausing)
+ r->m_mediaStamp = nTimeStamp;
+
+ /* FLV tag(s) */
+ /*RTMP_Log(RTMP_LOGDEBUG, "%s, received: FLV tag(s) %lu bytes", __FUNCTION__, packet.m_nBodySize); */
+ bHasMediaPacket = 1;
+ break;
+ }
+ default:
+ RTMP_Log(RTMP_LOGDEBUG, "%s, unknown packet type received: 0x%02x", __FUNCTION__,
+ packet->m_packetType);
+#ifdef _DEBUG
+ RTMP_LogHex(RTMP_LOGDEBUG, packet->m_body, packet->m_nBodySize);
+#endif
+ }
+
+ return bHasMediaPacket;
+}
+
+#ifdef _DEBUG
+extern FILE *netstackdump;
+extern FILE *netstackdump_read;
+#endif
+
+static int
+ReadN(RTMP *r, char *buffer, int n)
+{
+ int nOriginalSize = n;
+ int avail;
+ char *ptr;
+
+ r->m_sb.sb_timedout = FALSE;
+
+#ifdef _DEBUG
+ memset(buffer, 0, n);
+#endif
+
+ ptr = buffer;
+ while (n > 0)
+ {
+ int nBytes = 0, nRead;
+ if (r->Link.protocol & RTMP_FEATURE_HTTP)
+ {
+ while (!r->m_resplen)
+ {
+ if (r->m_sb.sb_size < 144)
+ {
+ if (!r->m_unackd)
+ HTTP_Post(r, RTMPT_IDLE, "", 1);
+ if (RTMPSockBuf_Fill(&r->m_sb) < 1)
+ {
+ if (!r->m_sb.sb_timedout)
+ RTMP_Close(r);
+ return 0;
+ }
+ }
+ HTTP_read(r, 0);
+ }
+ if (r->m_resplen && !r->m_sb.sb_size)
+ RTMPSockBuf_Fill(&r->m_sb);
+ avail = r->m_sb.sb_size;
+ if (avail > r->m_resplen)
+ avail = r->m_resplen;
+ }
+ else
+ {
+ avail = r->m_sb.sb_size;
+ if (avail == 0)
+ {
+ if (RTMPSockBuf_Fill(&r->m_sb) < 1)
+ {
+ if (!r->m_sb.sb_timedout)
+ RTMP_Close(r);
+ return 0;
+ }
+ avail = r->m_sb.sb_size;
+ }
+ }
+ nRead = ((n < avail) ? n : avail);
+ if (nRead > 0)
+ {
+ memcpy(ptr, r->m_sb.sb_start, nRead);
+ r->m_sb.sb_start += nRead;
+ r->m_sb.sb_size -= nRead;
+ nBytes = nRead;
+ r->m_nBytesIn += nRead;
+ if (r->m_bSendCounter
+ && r->m_nBytesIn > r->m_nBytesInSent + r->m_nClientBW / 2)
+ SendBytesReceived(r);
+ }
+ /*RTMP_Log(RTMP_LOGDEBUG, "%s: %d bytes\n", __FUNCTION__, nBytes); */
+#ifdef _DEBUG
+ fwrite(ptr, 1, nBytes, netstackdump_read);
+#endif
+
+ if (nBytes == 0)
+ {
+ RTMP_Log(RTMP_LOGDEBUG, "%s, RTMP socket closed by peer", __FUNCTION__);
+ /*goto again; */
+ RTMP_Close(r);
+ break;
+ }
+
+ if (r->Link.protocol & RTMP_FEATURE_HTTP)
+ r->m_resplen -= nBytes;
+
+#ifdef CRYPTO
+ if (r->Link.rc4keyIn)
+ {
+ RC4_encrypt(r->Link.rc4keyIn, nBytes, ptr);
+ }
+#endif
+
+ n -= nBytes;
+ ptr += nBytes;
+ }
+
+ return nOriginalSize - n;
+}
+
+static int
+WriteN(RTMP *r, const char *buffer, int n)
+{
+ const char *ptr = buffer;
+#ifdef CRYPTO
+ char *encrypted = 0;
+ char buf[RTMP_BUFFER_CACHE_SIZE];
+
+ if (r->Link.rc4keyOut)
+ {
+ if (n > sizeof(buf))
+ encrypted = (char *)malloc(n);
+ else
+ encrypted = (char *)buf;
+ ptr = encrypted;
+ RC4_encrypt2(r->Link.rc4keyOut, n, buffer, ptr);
+ }
+#endif
+
+ while (n > 0)
+ {
+ int nBytes;
+
+ if (r->Link.protocol & RTMP_FEATURE_HTTP)
+ nBytes = HTTP_Post(r, RTMPT_SEND, ptr, n);
+ else
+ nBytes = RTMPSockBuf_Send(&r->m_sb, ptr, n);
+ /*RTMP_Log(RTMP_LOGDEBUG, "%s: %d\n", __FUNCTION__, nBytes); */
+
+ if (nBytes < 0)
+ {
+ int sockerr = GetSockError();
+ RTMP_Log(RTMP_LOGERROR, "%s, RTMP send error %d (%d bytes)", __FUNCTION__,
+ sockerr, n);
+
+ if (sockerr == EINTR && !RTMP_ctrlC)
+ continue;
+ /**
+ * TODO 意外断网 阻止递归调用
+ */
+ //RTMP_Close(r);
+ n = 1;
+ break;
+ }
+
+ if (nBytes == 0)
+ break;
+
+ n -= nBytes;
+ ptr += nBytes;
+ }
+
+#ifdef CRYPTO
+ if (encrypted && encrypted != buf)
+ free(encrypted);
+#endif
+
+ return n == 0;
+}
+
+#define SAVC(x) static const AVal av_##x = AVC(#x)
+
+SAVC(app);
+SAVC(connect);
+SAVC(flashVer);
+SAVC(swfUrl);
+SAVC(pageUrl);
+SAVC(tcUrl);
+SAVC(fpad);
+SAVC(capabilities);
+SAVC(audioCodecs);
+SAVC(videoCodecs);
+SAVC(videoFunction);
+SAVC(objectEncoding);
+SAVC(secureToken);
+SAVC(secureTokenResponse);
+SAVC(type);
+SAVC(nonprivate);
+
+static int
+SendConnectPacket(RTMP *r, RTMPPacket *cp)
+{
+ RTMPPacket packet;
+ char pbuf[4096], *pend = pbuf + sizeof(pbuf);
+ char *enc;
+
+ if (cp)
+ return RTMP_SendPacket(r, cp, TRUE);
+
+ packet.m_nChannel = 0x03; /* control channel (invoke) */
+ packet.m_headerType = RTMP_PACKET_SIZE_LARGE;
+ packet.m_packetType = 0x14; /* INVOKE */
+ packet.m_nTimeStamp = 0;
+ packet.m_nInfoField2 = 0;
+ packet.m_hasAbsTimestamp = 0;
+ packet.m_body = pbuf + RTMP_MAX_HEADER_SIZE;
+
+ enc = packet.m_body;
+ enc = AMF_EncodeString(enc, pend, &av_connect);
+ enc = AMF_EncodeNumber(enc, pend, ++r->m_numInvokes);
+ *enc++ = AMF_OBJECT;
+
+ enc = AMF_EncodeNamedString(enc, pend, &av_app, &r->Link.app);
+ if (!enc)
+ return FALSE;
+ if (r->Link.protocol & RTMP_FEATURE_WRITE)
+ {
+ enc = AMF_EncodeNamedString(enc, pend, &av_type, &av_nonprivate);
+ if (!enc)
+ return FALSE;
+ }
+ if (r->Link.flashVer.av_len)
+ {
+ enc = AMF_EncodeNamedString(enc, pend, &av_flashVer, &r->Link.flashVer);
+ if (!enc)
+ return FALSE;
+ }
+ if (r->Link.swfUrl.av_len)
+ {
+ enc = AMF_EncodeNamedString(enc, pend, &av_swfUrl, &r->Link.swfUrl);
+ if (!enc)
+ return FALSE;
+ }
+ if (r->Link.tcUrl.av_len)
+ {
+ enc = AMF_EncodeNamedString(enc, pend, &av_tcUrl, &r->Link.tcUrl);
+ if (!enc)
+ return FALSE;
+ }
+ if (!(r->Link.protocol & RTMP_FEATURE_WRITE))
+ {
+ enc = AMF_EncodeNamedBoolean(enc, pend, &av_fpad, FALSE);
+ if (!enc)
+ return FALSE;
+ enc = AMF_EncodeNamedNumber(enc, pend, &av_capabilities, 15.0);
+ if (!enc)
+ return FALSE;
+ enc = AMF_EncodeNamedNumber(enc, pend, &av_audioCodecs, r->m_fAudioCodecs);
+ if (!enc)
+ return FALSE;
+ enc = AMF_EncodeNamedNumber(enc, pend, &av_videoCodecs, r->m_fVideoCodecs);
+ if (!enc)
+ return FALSE;
+ enc = AMF_EncodeNamedNumber(enc, pend, &av_videoFunction, 1.0);
+ if (!enc)
+ return FALSE;
+ if (r->Link.pageUrl.av_len)
+ {
+ enc = AMF_EncodeNamedString(enc, pend, &av_pageUrl, &r->Link.pageUrl);
+ if (!enc)
+ return FALSE;
+ }
+ }
+ if (r->m_fEncoding != 0.0 || r->m_bSendEncoding)
+ { /* AMF0, AMF3 not fully supported yet */
+ enc = AMF_EncodeNamedNumber(enc, pend, &av_objectEncoding, r->m_fEncoding);
+ if (!enc)
+ return FALSE;
+ }
+ if (enc + 3 >= pend)
+ return FALSE;
+ *enc++ = 0;
+ *enc++ = 0; /* end of object - 0x00 0x00 0x09 */
+ *enc++ = AMF_OBJECT_END;
+
+ /* add auth string */
+ if (r->Link.auth.av_len)
+ {
+ enc = AMF_EncodeBoolean(enc, pend, r->Link.lFlags & RTMP_LF_AUTH);
+ if (!enc)
+ return FALSE;
+ enc = AMF_EncodeString(enc, pend, &r->Link.auth);
+ if (!enc)
+ return FALSE;
+ }
+ if (r->Link.extras.o_num)
+ {
+ int i;
+ for (i = 0; i < r->Link.extras.o_num; i++)
+ {
+ enc = AMFProp_Encode(&r->Link.extras.o_props[i], enc, pend);
+ if (!enc)
+ return FALSE;
+ }
+ }
+ packet.m_nBodySize = enc - packet.m_body;
+
+ return RTMP_SendPacket(r, &packet, TRUE);
+}
+
+#if 0 /* unused */
+SAVC(bgHasStream);
+
+static int
+SendBGHasStream(RTMP *r, double dId, AVal *playpath)
+{
+ RTMPPacket packet;
+ char pbuf[1024], *pend = pbuf + sizeof(pbuf);
+ char *enc;
+
+ packet.m_nChannel = 0x03; /* control channel (invoke) */
+ packet.m_headerType = RTMP_PACKET_SIZE_MEDIUM;
+ packet.m_packetType = 0x14; /* INVOKE */
+ packet.m_nTimeStamp = 0;
+ packet.m_nInfoField2 = 0;
+ packet.m_hasAbsTimestamp = 0;
+ packet.m_body = pbuf + RTMP_MAX_HEADER_SIZE;
+
+ enc = packet.m_body;
+ enc = AMF_EncodeString(enc, pend, &av_bgHasStream);
+ enc = AMF_EncodeNumber(enc, pend, dId);
+ *enc++ = AMF_NULL;
+
+ enc = AMF_EncodeString(enc, pend, playpath);
+ if (enc == NULL)
+ return FALSE;
+
+ packet.m_nBodySize = enc - packet.m_body;
+
+ return RTMP_SendPacket(r, &packet, TRUE);
+}
+#endif
+
+SAVC(createStream);
+
+int
+RTMP_SendCreateStream(RTMP *r)
+{
+ RTMPPacket packet;
+ char pbuf[256], *pend = pbuf + sizeof(pbuf);
+ char *enc;
+
+ packet.m_nChannel = 0x03; /* control channel (invoke) */
+ packet.m_headerType = RTMP_PACKET_SIZE_MEDIUM;
+ packet.m_packetType = 0x14; /* INVOKE */
+ packet.m_nTimeStamp = 0;
+ packet.m_nInfoField2 = 0;
+ packet.m_hasAbsTimestamp = 0;
+ packet.m_body = pbuf + RTMP_MAX_HEADER_SIZE;
+
+ enc = packet.m_body;
+ enc = AMF_EncodeString(enc, pend, &av_createStream);
+ enc = AMF_EncodeNumber(enc, pend, ++r->m_numInvokes);
+ *enc++ = AMF_NULL; /* NULL */
+
+ packet.m_nBodySize = enc - packet.m_body;
+
+ return RTMP_SendPacket(r, &packet, TRUE);
+}
+
+SAVC(FCSubscribe);
+
+static int
+SendFCSubscribe(RTMP *r, AVal *subscribepath)
+{
+ RTMPPacket packet;
+ char pbuf[512], *pend = pbuf + sizeof(pbuf);
+ char *enc;
+ packet.m_nChannel = 0x03; /* control channel (invoke) */
+ packet.m_headerType = RTMP_PACKET_SIZE_MEDIUM;
+ packet.m_packetType = 0x14; /* INVOKE */
+ packet.m_nTimeStamp = 0;
+ packet.m_nInfoField2 = 0;
+ packet.m_hasAbsTimestamp = 0;
+ packet.m_body = pbuf + RTMP_MAX_HEADER_SIZE;
+
+ RTMP_Log(RTMP_LOGDEBUG, "FCSubscribe: %s", subscribepath->av_val);
+ enc = packet.m_body;
+ enc = AMF_EncodeString(enc, pend, &av_FCSubscribe);
+ enc = AMF_EncodeNumber(enc, pend, ++r->m_numInvokes);
+ *enc++ = AMF_NULL;
+ enc = AMF_EncodeString(enc, pend, subscribepath);
+
+ if (!enc)
+ return FALSE;
+
+ packet.m_nBodySize = enc - packet.m_body;
+
+ return RTMP_SendPacket(r, &packet, TRUE);
+}
+
+SAVC(releaseStream);
+
+static int
+SendReleaseStream(RTMP *r)
+{
+ RTMPPacket packet;
+ char pbuf[1024], *pend = pbuf + sizeof(pbuf);
+ char *enc;
+
+ packet.m_nChannel = 0x03; /* control channel (invoke) */
+ packet.m_headerType = RTMP_PACKET_SIZE_MEDIUM;
+ packet.m_packetType = 0x14; /* INVOKE */
+ packet.m_nTimeStamp = 0;
+ packet.m_nInfoField2 = 0;
+ packet.m_hasAbsTimestamp = 0;
+ packet.m_body = pbuf + RTMP_MAX_HEADER_SIZE;
+
+ enc = packet.m_body;
+ enc = AMF_EncodeString(enc, pend, &av_releaseStream);
+ enc = AMF_EncodeNumber(enc, pend, ++r->m_numInvokes);
+ *enc++ = AMF_NULL;
+ enc = AMF_EncodeString(enc, pend, &r->Link.playpath);
+ if (!enc)
+ return FALSE;
+
+ packet.m_nBodySize = enc - packet.m_body;
+
+ return RTMP_SendPacket(r, &packet, FALSE);
+}
+
+SAVC(FCPublish);
+
+static int
+SendFCPublish(RTMP *r)
+{
+ RTMPPacket packet;
+ char pbuf[1024], *pend = pbuf + sizeof(pbuf);
+ char *enc;
+
+ packet.m_nChannel = 0x03; /* control channel (invoke) */
+ packet.m_headerType = RTMP_PACKET_SIZE_MEDIUM;
+ packet.m_packetType = 0x14; /* INVOKE */
+ packet.m_nTimeStamp = 0;
+ packet.m_nInfoField2 = 0;
+ packet.m_hasAbsTimestamp = 0;
+ packet.m_body = pbuf + RTMP_MAX_HEADER_SIZE;
+
+ enc = packet.m_body;
+ enc = AMF_EncodeString(enc, pend, &av_FCPublish);
+ enc = AMF_EncodeNumber(enc, pend, ++r->m_numInvokes);
+ *enc++ = AMF_NULL;
+ enc = AMF_EncodeString(enc, pend, &r->Link.playpath);
+ if (!enc)
+ return FALSE;
+
+ packet.m_nBodySize = enc - packet.m_body;
+
+ return RTMP_SendPacket(r, &packet, FALSE);
+}
+
+SAVC(FCUnpublish);
+
+static int
+SendFCUnpublish(RTMP *r)
+{
+ RTMPPacket packet;
+ char pbuf[1024], *pend = pbuf + sizeof(pbuf);
+ char *enc;
+
+ packet.m_nChannel = 0x03; /* control channel (invoke) */
+ packet.m_headerType = RTMP_PACKET_SIZE_MEDIUM;
+ packet.m_packetType = 0x14; /* INVOKE */
+ packet.m_nTimeStamp = 0;
+ packet.m_nInfoField2 = 0;
+ packet.m_hasAbsTimestamp = 0;
+ packet.m_body = pbuf + RTMP_MAX_HEADER_SIZE;
+
+ enc = packet.m_body;
+ enc = AMF_EncodeString(enc, pend, &av_FCUnpublish);
+ enc = AMF_EncodeNumber(enc, pend, ++r->m_numInvokes);
+ *enc++ = AMF_NULL;
+ enc = AMF_EncodeString(enc, pend, &r->Link.playpath);
+ if (!enc)
+ return FALSE;
+
+ packet.m_nBodySize = enc - packet.m_body;
+
+ return RTMP_SendPacket(r, &packet, FALSE);
+}
+
+SAVC(publish);
+SAVC(live);
+SAVC(record);
+
+static int
+SendPublish(RTMP *r)
+{
+ RTMPPacket packet;
+ char pbuf[1024], *pend = pbuf + sizeof(pbuf);
+ char *enc;
+
+ packet.m_nChannel = 0x04; /* source channel (invoke) */
+ packet.m_headerType = RTMP_PACKET_SIZE_LARGE;
+ packet.m_packetType = 0x14; /* INVOKE */
+ packet.m_nTimeStamp = 0;
+ packet.m_nInfoField2 = r->m_stream_id;
+ packet.m_hasAbsTimestamp = 0;
+ packet.m_body = pbuf + RTMP_MAX_HEADER_SIZE;
+
+ enc = packet.m_body;
+ enc = AMF_EncodeString(enc, pend, &av_publish);
+ enc = AMF_EncodeNumber(enc, pend, ++r->m_numInvokes);
+ *enc++ = AMF_NULL;
+ enc = AMF_EncodeString(enc, pend, &r->Link.playpath);
+ if (!enc)
+ return FALSE;
+
+ /* FIXME: should we choose live based on Link.lFlags & RTMP_LF_LIVE? */
+ enc = AMF_EncodeString(enc, pend, &av_live);
+ if (!enc)
+ return FALSE;
+
+ packet.m_nBodySize = enc - packet.m_body;
+
+ return RTMP_SendPacket(r, &packet, TRUE);
+}
+
+SAVC(deleteStream);
+
+static int
+SendDeleteStream(RTMP *r, double dStreamId)
+{
+ RTMPPacket packet;
+ char pbuf[256], *pend = pbuf + sizeof(pbuf);
+ char *enc;
+
+ packet.m_nChannel = 0x03; /* control channel (invoke) */
+ packet.m_headerType = RTMP_PACKET_SIZE_MEDIUM;
+ packet.m_packetType = 0x14; /* INVOKE */
+ packet.m_nTimeStamp = 0;
+ packet.m_nInfoField2 = 0;
+ packet.m_hasAbsTimestamp = 0;
+ packet.m_body = pbuf + RTMP_MAX_HEADER_SIZE;
+
+ enc = packet.m_body;
+ enc = AMF_EncodeString(enc, pend, &av_deleteStream);
+ enc = AMF_EncodeNumber(enc, pend, ++r->m_numInvokes);
+ *enc++ = AMF_NULL;
+ enc = AMF_EncodeNumber(enc, pend, dStreamId);
+
+ packet.m_nBodySize = enc - packet.m_body;
+
+ /* no response expected */
+ return RTMP_SendPacket(r, &packet, FALSE);
+}
+
+SAVC(pause);
+
+int
+RTMP_SendPause(RTMP *r, int DoPause, int iTime)
+{
+ RTMPPacket packet;
+ char pbuf[256], *pend = pbuf + sizeof(pbuf);
+ char *enc;
+
+ packet.m_nChannel = 0x08; /* video channel */
+ packet.m_headerType = RTMP_PACKET_SIZE_MEDIUM;
+ packet.m_packetType = 0x14; /* invoke */
+ packet.m_nTimeStamp = 0;
+ packet.m_nInfoField2 = 0;
+ packet.m_hasAbsTimestamp = 0;
+ packet.m_body = pbuf + RTMP_MAX_HEADER_SIZE;
+
+ enc = packet.m_body;
+ enc = AMF_EncodeString(enc, pend, &av_pause);
+ enc = AMF_EncodeNumber(enc, pend, ++r->m_numInvokes);
+ *enc++ = AMF_NULL;
+ enc = AMF_EncodeBoolean(enc, pend, DoPause);
+ enc = AMF_EncodeNumber(enc, pend, (double)iTime);
+
+ packet.m_nBodySize = enc - packet.m_body;
+
+ RTMP_Log(RTMP_LOGDEBUG, "%s, %d, pauseTime=%d", __FUNCTION__, DoPause, iTime);
+ return RTMP_SendPacket(r, &packet, TRUE);
+}
+
+int RTMP_Pause(RTMP *r, int DoPause)
+{
+ if (DoPause)
+ r->m_pauseStamp = r->m_channelTimestamp[r->m_mediaChannel];
+ return RTMP_SendPause(r, DoPause, r->m_pauseStamp);
+}
+
+SAVC(seek);
+
+int
+RTMP_SendSeek(RTMP *r, int iTime)
+{
+ RTMPPacket packet;
+ char pbuf[256], *pend = pbuf + sizeof(pbuf);
+ char *enc;
+
+ packet.m_nChannel = 0x08; /* video channel */
+ packet.m_headerType = RTMP_PACKET_SIZE_MEDIUM;
+ packet.m_packetType = 0x14; /* invoke */
+ packet.m_nTimeStamp = 0;
+ packet.m_nInfoField2 = 0;
+ packet.m_hasAbsTimestamp = 0;
+ packet.m_body = pbuf + RTMP_MAX_HEADER_SIZE;
+
+ enc = packet.m_body;
+ enc = AMF_EncodeString(enc, pend, &av_seek);
+ enc = AMF_EncodeNumber(enc, pend, ++r->m_numInvokes);
+ *enc++ = AMF_NULL;
+ enc = AMF_EncodeNumber(enc, pend, (double)iTime);
+
+ packet.m_nBodySize = enc - packet.m_body;
+
+ r->m_read.flags |= RTMP_READ_SEEKING;
+ r->m_read.nResumeTS = 0;
+
+ return RTMP_SendPacket(r, &packet, TRUE);
+}
+
+int
+RTMP_SendServerBW(RTMP *r)
+{
+ RTMPPacket packet;
+ char pbuf[256], *pend = pbuf + sizeof(pbuf);
+
+ packet.m_nChannel = 0x02; /* control channel (invoke) */
+ packet.m_headerType = RTMP_PACKET_SIZE_LARGE;
+ packet.m_packetType = 0x05; /* Server BW */
+ packet.m_nTimeStamp = 0;
+ packet.m_nInfoField2 = 0;
+ packet.m_hasAbsTimestamp = 0;
+ packet.m_body = pbuf + RTMP_MAX_HEADER_SIZE;
+
+ packet.m_nBodySize = 4;
+
+ AMF_EncodeInt32(packet.m_body, pend, r->m_nServerBW);
+ return RTMP_SendPacket(r, &packet, FALSE);
+}
+
+int
+RTMP_SendClientBW(RTMP *r)
+{
+ RTMPPacket packet;
+ char pbuf[256], *pend = pbuf + sizeof(pbuf);
+
+ packet.m_nChannel = 0x02; /* control channel (invoke) */
+ packet.m_headerType = RTMP_PACKET_SIZE_LARGE;
+ packet.m_packetType = 0x06; /* Client BW */
+ packet.m_nTimeStamp = 0;
+ packet.m_nInfoField2 = 0;
+ packet.m_hasAbsTimestamp = 0;
+ packet.m_body = pbuf + RTMP_MAX_HEADER_SIZE;
+
+ packet.m_nBodySize = 5;
+
+ AMF_EncodeInt32(packet.m_body, pend, r->m_nClientBW);
+ packet.m_body[4] = r->m_nClientBW2;
+ return RTMP_SendPacket(r, &packet, FALSE);
+}
+
+static int
+SendBytesReceived(RTMP *r)
+{
+ RTMPPacket packet;
+ char pbuf[256], *pend = pbuf + sizeof(pbuf);
+
+ packet.m_nChannel = 0x02; /* control channel (invoke) */
+ packet.m_headerType = RTMP_PACKET_SIZE_MEDIUM;
+ packet.m_packetType = 0x03; /* bytes in */
+ packet.m_nTimeStamp = 0;
+ packet.m_nInfoField2 = 0;
+ packet.m_hasAbsTimestamp = 0;
+ packet.m_body = pbuf + RTMP_MAX_HEADER_SIZE;
+
+ packet.m_nBodySize = 4;
+
+ AMF_EncodeInt32(packet.m_body, pend, r->m_nBytesIn); /* hard coded for now */
+ r->m_nBytesInSent = r->m_nBytesIn;
+
+ /*RTMP_Log(RTMP_LOGDEBUG, "Send bytes report. 0x%x (%d bytes)", (unsigned int)m_nBytesIn, m_nBytesIn); */
+ return RTMP_SendPacket(r, &packet, FALSE);
+}
+
+SAVC(_checkbw);
+
+static int
+SendCheckBW(RTMP *r)
+{
+ RTMPPacket packet;
+ char pbuf[256], *pend = pbuf + sizeof(pbuf);
+ char *enc;
+
+ packet.m_nChannel = 0x03; /* control channel (invoke) */
+ packet.m_headerType = RTMP_PACKET_SIZE_LARGE;
+ packet.m_packetType = 0x14; /* INVOKE */
+ packet.m_nTimeStamp = 0; /* RTMP_GetTime(); */
+ packet.m_nInfoField2 = 0;
+ packet.m_hasAbsTimestamp = 0;
+ packet.m_body = pbuf + RTMP_MAX_HEADER_SIZE;
+
+ enc = packet.m_body;
+ enc = AMF_EncodeString(enc, pend, &av__checkbw);
+ enc = AMF_EncodeNumber(enc, pend, ++r->m_numInvokes);
+ *enc++ = AMF_NULL;
+
+ packet.m_nBodySize = enc - packet.m_body;
+
+ /* triggers _onbwcheck and eventually results in _onbwdone */
+ return RTMP_SendPacket(r, &packet, FALSE);
+}
+
+SAVC(_result);
+
+static int
+SendCheckBWResult(RTMP *r, double txn)
+{
+ RTMPPacket packet;
+ char pbuf[256], *pend = pbuf + sizeof(pbuf);
+ char *enc;
+
+ packet.m_nChannel = 0x03; /* control channel (invoke) */
+ packet.m_headerType = RTMP_PACKET_SIZE_MEDIUM;
+ packet.m_packetType = 0x14; /* INVOKE */
+ packet.m_nTimeStamp = 0x16 * r->m_nBWCheckCounter; /* temp inc value. till we figure it out. */
+ packet.m_nInfoField2 = 0;
+ packet.m_hasAbsTimestamp = 0;
+ packet.m_body = pbuf + RTMP_MAX_HEADER_SIZE;
+
+ enc = packet.m_body;
+ enc = AMF_EncodeString(enc, pend, &av__result);
+ enc = AMF_EncodeNumber(enc, pend, txn);
+ *enc++ = AMF_NULL;
+ enc = AMF_EncodeNumber(enc, pend, (double)r->m_nBWCheckCounter++);
+
+ packet.m_nBodySize = enc - packet.m_body;
+
+ return RTMP_SendPacket(r, &packet, FALSE);
+}
+
+SAVC(ping);
+SAVC(pong);
+
+static int
+SendPong(RTMP *r, double txn)
+{
+ RTMPPacket packet;
+ char pbuf[256], *pend = pbuf + sizeof(pbuf);
+ char *enc;
+
+ packet.m_nChannel = 0x03; /* control channel (invoke) */
+ packet.m_headerType = RTMP_PACKET_SIZE_MEDIUM;
+ packet.m_packetType = 0x14; /* INVOKE */
+ packet.m_nTimeStamp = 0x16 * r->m_nBWCheckCounter; /* temp inc value. till we figure it out. */
+ packet.m_nInfoField2 = 0;
+ packet.m_hasAbsTimestamp = 0;
+ packet.m_body = pbuf + RTMP_MAX_HEADER_SIZE;
+
+ enc = packet.m_body;
+ enc = AMF_EncodeString(enc, pend, &av_pong);
+ enc = AMF_EncodeNumber(enc, pend, txn);
+ *enc++ = AMF_NULL;
+
+ packet.m_nBodySize = enc - packet.m_body;
+
+ return RTMP_SendPacket(r, &packet, FALSE);
+}
+
+SAVC(play);
+
+static int
+SendPlay(RTMP *r)
+{
+ RTMPPacket packet;
+ char pbuf[1024], *pend = pbuf + sizeof(pbuf);
+ char *enc;
+
+ packet.m_nChannel = 0x08; /* we make 8 our stream channel */
+ packet.m_headerType = RTMP_PACKET_SIZE_LARGE;
+ packet.m_packetType = 0x14; /* INVOKE */
+ packet.m_nTimeStamp = 0;
+ packet.m_nInfoField2 = r->m_stream_id; /*0x01000000; */
+ packet.m_hasAbsTimestamp = 0;
+ packet.m_body = pbuf + RTMP_MAX_HEADER_SIZE;
+
+ enc = packet.m_body;
+ enc = AMF_EncodeString(enc, pend, &av_play);
+ enc = AMF_EncodeNumber(enc, pend, ++r->m_numInvokes);
+ *enc++ = AMF_NULL;
+
+ RTMP_Log(RTMP_LOGDEBUG, "%s, seekTime=%d, stopTime=%d, sending play: %s",
+ __FUNCTION__, r->Link.seekTime, r->Link.stopTime,
+ r->Link.playpath.av_val);
+ enc = AMF_EncodeString(enc, pend, &r->Link.playpath);
+ if (!enc)
+ return FALSE;
+
+ /* Optional parameters start and len.
+ *
+ * start: -2, -1, 0, positive number
+ * -2: looks for a live stream, then a recorded stream,
+ * if not found any open a live stream
+ * -1: plays a live stream
+ * >=0: plays a recorded streams from 'start' milliseconds
+ */
+ if (r->Link.lFlags & RTMP_LF_LIVE)
+ enc = AMF_EncodeNumber(enc, pend, -1000.0);
+ else
+ {
+ if (r->Link.seekTime > 0.0)
+ enc = AMF_EncodeNumber(enc, pend, r->Link.seekTime); /* resume from here */
+ else
+ enc = AMF_EncodeNumber(enc, pend, 0.0); /*-2000.0);*/ /* recorded as default, -2000.0 is not reliable since that freezes the player if the stream is not found */
+ }
+ if (!enc)
+ return FALSE;
+
+ /* len: -1, 0, positive number
+ * -1: plays live or recorded stream to the end (default)
+ * 0: plays a frame 'start' ms away from the beginning
+ * >0: plays a live or recoded stream for 'len' milliseconds
+ */
+ /*enc += EncodeNumber(enc, -1.0); */ /* len */
+ if (r->Link.stopTime)
+ {
+ enc = AMF_EncodeNumber(enc, pend, r->Link.stopTime - r->Link.seekTime);
+ if (!enc)
+ return FALSE;
+ }
+
+ packet.m_nBodySize = enc - packet.m_body;
+
+ return RTMP_SendPacket(r, &packet, TRUE);
+}
+
+SAVC(set_playlist);
+SAVC(0);
+
+static int
+SendPlaylist(RTMP *r)
+{
+ RTMPPacket packet;
+ char pbuf[1024], *pend = pbuf + sizeof(pbuf);
+ char *enc;
+
+ packet.m_nChannel = 0x08; /* we make 8 our stream channel */
+ packet.m_headerType = RTMP_PACKET_SIZE_LARGE;
+ packet.m_packetType = 0x14; /* INVOKE */
+ packet.m_nTimeStamp = 0;
+ packet.m_nInfoField2 = r->m_stream_id; /*0x01000000; */
+ packet.m_hasAbsTimestamp = 0;
+ packet.m_body = pbuf + RTMP_MAX_HEADER_SIZE;
+
+ enc = packet.m_body;
+ enc = AMF_EncodeString(enc, pend, &av_set_playlist);
+ enc = AMF_EncodeNumber(enc, pend, 0);
+ *enc++ = AMF_NULL;
+ *enc++ = AMF_ECMA_ARRAY;
+ *enc++ = 0;
+ *enc++ = 0;
+ *enc++ = 0;
+ *enc++ = AMF_OBJECT;
+ enc = AMF_EncodeNamedString(enc, pend, &av_0, &r->Link.playpath);
+ if (!enc)
+ return FALSE;
+ if (enc + 3 >= pend)
+ return FALSE;
+ *enc++ = 0;
+ *enc++ = 0;
+ *enc++ = AMF_OBJECT_END;
+
+ packet.m_nBodySize = enc - packet.m_body;
+
+ return RTMP_SendPacket(r, &packet, TRUE);
+}
+
+static int
+SendSecureTokenResponse(RTMP *r, AVal *resp)
+{
+ RTMPPacket packet;
+ char pbuf[1024], *pend = pbuf + sizeof(pbuf);
+ char *enc;
+
+ packet.m_nChannel = 0x03; /* control channel (invoke) */
+ packet.m_headerType = RTMP_PACKET_SIZE_MEDIUM;
+ packet.m_packetType = 0x14;
+ packet.m_nTimeStamp = 0;
+ packet.m_nInfoField2 = 0;
+ packet.m_hasAbsTimestamp = 0;
+ packet.m_body = pbuf + RTMP_MAX_HEADER_SIZE;
+
+ enc = packet.m_body;
+ enc = AMF_EncodeString(enc, pend, &av_secureTokenResponse);
+ enc = AMF_EncodeNumber(enc, pend, 0.0);
+ *enc++ = AMF_NULL;
+ enc = AMF_EncodeString(enc, pend, resp);
+ if (!enc)
+ return FALSE;
+
+ packet.m_nBodySize = enc - packet.m_body;
+
+ return RTMP_SendPacket(r, &packet, FALSE);
+}
+
+/*
+from http://jira.red5.org/confluence/display/docs/Ping:
+
+Ping is the most mysterious message in RTMP and till now we haven't fully interpreted it yet. In summary, Ping message is used as a special command that are exchanged between client and server. This page aims to document all known Ping messages. Expect the list to grow.
+
+The type of Ping packet is 0x4 and contains two mandatory parameters and two optional parameters. The first parameter is the type of Ping and in short integer. The second parameter is the target of the ping. As Ping is always sent in Channel 2 (control channel) and the target object in RTMP header is always 0 which means the Connection object, it's necessary to put an extra parameter to indicate the exact target object the Ping is sent to. The second parameter takes this responsibility. The value has the same meaning as the target object field in RTMP header. (The second value could also be used as other purposes, like RTT Ping/Pong. It is used as the timestamp.) The third and fourth parameters are optional and could be looked upon as the parameter of the Ping packet. Below is an unexhausted list of Ping messages.
+
+ * type 0: Clear the stream. No third and fourth parameters. The second parameter could be 0. After the connection is established, a Ping 0,0 will be sent from server to client. The message will also be sent to client on the start of Play and in response of a Seek or Pause/Resume request. This Ping tells client to re-calibrate the clock with the timestamp of the next packet server sends.
+ * type 1: Tell the stream to clear the playing buffer.
+ * type 3: Buffer time of the client. The third parameter is the buffer time in millisecond.
+ * type 4: Reset a stream. Used together with type 0 in the case of VOD. Often sent before type 0.
+ * type 6: Ping the client from server. The second parameter is the current time.
+ * type 7: Pong reply from client. The second parameter is the time the server sent with his ping request.
+ * type 26: SWFVerification request
+ * type 27: SWFVerification response
+*/
+int
+RTMP_SendCtrl(RTMP *r, short nType, unsigned int nObject, unsigned int nTime)
+{
+ RTMPPacket packet;
+ char pbuf[256], *pend = pbuf + sizeof(pbuf);
+ int nSize;
+ char *buf;
+
+ RTMP_Log(RTMP_LOGDEBUG, "sending ctrl. type: 0x%04x", (unsigned short)nType);
+
+ packet.m_nChannel = 0x02; /* control channel (ping) */
+ packet.m_headerType = RTMP_PACKET_SIZE_MEDIUM;
+ packet.m_packetType = 0x04; /* ctrl */
+ packet.m_nTimeStamp = 0; /* RTMP_GetTime(); */
+ packet.m_nInfoField2 = 0;
+ packet.m_hasAbsTimestamp = 0;
+ packet.m_body = pbuf + RTMP_MAX_HEADER_SIZE;
+
+ switch(nType) {
+ case 0x03: nSize = 10; break; /* buffer time */
+ case 0x1A: nSize = 3; break; /* SWF verify request */
+ case 0x1B: nSize = 44; break; /* SWF verify response */
+ default: nSize = 6; break;
+ }
+
+ packet.m_nBodySize = nSize;
+
+ buf = packet.m_body;
+ buf = AMF_EncodeInt16(buf, pend, nType);
+
+ if (nType == 0x1B)
+ {
+#ifdef CRYPTO
+ memcpy(buf, r->Link.SWFVerificationResponse, 42);
+ RTMP_Log(RTMP_LOGDEBUG, "Sending SWFVerification response: ");
+ RTMP_LogHex(RTMP_LOGDEBUG, (uint8_t *)packet.m_body, packet.m_nBodySize);
+#endif
+ }
+ else if (nType == 0x1A)
+ {
+ *buf = nObject & 0xff;
+ }
+ else
+ {
+ if (nSize > 2)
+ buf = AMF_EncodeInt32(buf, pend, nObject);
+
+ if (nSize > 6)
+ buf = AMF_EncodeInt32(buf, pend, nTime);
+ }
+
+ return RTMP_SendPacket(r, &packet, FALSE);
+}
+
+static void
+AV_erase(RTMP_METHOD *vals, int *num, int i, int freeit)
+{
+ if (freeit)
+ free(vals[i].name.av_val);
+ (*num)--;
+ for (; i < *num; i++)
+ {
+ vals[i] = vals[i + 1];
+ }
+ vals[i].name.av_val = NULL;
+ vals[i].name.av_len = 0;
+ vals[i].num = 0;
+}
+
+void
+RTMP_DropRequest(RTMP *r, int i, int freeit)
+{
+ AV_erase(r->m_methodCalls, &r->m_numCalls, i, freeit);
+}
+
+static void
+AV_queue(RTMP_METHOD **vals, int *num, AVal *av, int txn)
+{
+ char *tmp;
+ if (!(*num & 0x0f))
+ *vals = realloc(*vals, (*num + 16) * sizeof(RTMP_METHOD));
+ tmp = malloc(av->av_len + 1);
+ memcpy(tmp, av->av_val, av->av_len);
+ tmp[av->av_len] = '\0';
+ (*vals)[*num].num = txn;
+ (*vals)[*num].name.av_len = av->av_len;
+ (*vals)[(*num)++].name.av_val = tmp;
+}
+
+static void
+AV_clear(RTMP_METHOD *vals, int num)
+{
+ int i;
+ for (i = 0; i < num; i++)
+ free(vals[i].name.av_val);
+ free(vals);
+}
+
+SAVC(onBWDone);
+SAVC(onFCSubscribe);
+SAVC(onFCUnsubscribe);
+SAVC(_onbwcheck);
+SAVC(_onbwdone);
+SAVC(_error);
+SAVC(close);
+SAVC(code);
+SAVC(level);
+SAVC(onStatus);
+SAVC(playlist_ready);
+static const AVal av_NetStream_Failed = AVC("NetStream.Failed");
+static const AVal av_NetStream_Play_Failed = AVC("NetStream.Play.Failed");
+static const AVal av_NetStream_Play_StreamNotFound =
+AVC("NetStream.Play.StreamNotFound");
+static const AVal av_NetConnection_Connect_InvalidApp =
+AVC("NetConnection.Connect.InvalidApp");
+static const AVal av_NetStream_Play_Start = AVC("NetStream.Play.Start");
+static const AVal av_NetStream_Play_Complete = AVC("NetStream.Play.Complete");
+static const AVal av_NetStream_Play_Stop = AVC("NetStream.Play.Stop");
+static const AVal av_NetStream_Seek_Notify = AVC("NetStream.Seek.Notify");
+static const AVal av_NetStream_Pause_Notify = AVC("NetStream.Pause.Notify");
+static const AVal av_NetStream_Play_UnpublishNotify =
+AVC("NetStream.Play.UnpublishNotify");
+static const AVal av_NetStream_Publish_Start = AVC("NetStream.Publish.Start");
+
+/* Returns 0 for OK/Failed/error, 1 for 'Stop or Complete' */
+static int
+HandleInvoke(RTMP *r, const char *body, unsigned int nBodySize)
+{
+ AMFObject obj;
+ AVal method;
+ int txn;
+ int ret = 0, nRes;
+ if (body[0] != 0x02) /* make sure it is a string method name we start with */
+ {
+ RTMP_Log(RTMP_LOGWARNING, "%s, Sanity failed. no string method in invoke packet",
+ __FUNCTION__);
+ return 0;
+ }
+
+ nRes = AMF_Decode(&obj, body, nBodySize, FALSE);
+ if (nRes < 0)
+ {
+ RTMP_Log(RTMP_LOGERROR, "%s, error decoding invoke packet", __FUNCTION__);
+ return 0;
+ }
+
+ AMF_Dump(&obj);
+ AMFProp_GetString(AMF_GetProp(&obj, NULL, 0), &method);
+ txn = (int)AMFProp_GetNumber(AMF_GetProp(&obj, NULL, 1));
+ RTMP_Log(RTMP_LOGDEBUG, "%s, server invoking <%s>", __FUNCTION__, method.av_val);
+
+ if (AVMATCH(&method, &av__result))
+ {
+ AVal methodInvoked = {0};
+ int i;
+
+ for (i=0; im_numCalls; i++) {
+ if (r->m_methodCalls[i].num == txn) {
+ methodInvoked = r->m_methodCalls[i].name;
+ AV_erase(r->m_methodCalls, &r->m_numCalls, i, FALSE);
+ break;
+ }
+ }
+ if (!methodInvoked.av_val) {
+ RTMP_Log(RTMP_LOGDEBUG, "%s, received result id %d without matching request",
+ __FUNCTION__, txn);
+ goto leave;
+ }
+
+ RTMP_Log(RTMP_LOGDEBUG, "%s, received result for method call <%s>", __FUNCTION__,
+ methodInvoked.av_val);
+
+ if (AVMATCH(&methodInvoked, &av_connect))
+ {
+ if (r->Link.token.av_len)
+ {
+ AMFObjectProperty p;
+ if (RTMP_FindFirstMatchingProperty(&obj, &av_secureToken, &p))
+ {
+ DecodeTEA(&r->Link.token, &p.p_vu.p_aval);
+ SendSecureTokenResponse(r, &p.p_vu.p_aval);
+ }
+ }
+ if (r->Link.protocol & RTMP_FEATURE_WRITE)
+ {
+ SendReleaseStream(r);
+ SendFCPublish(r);
+ }
+ else
+ {
+ RTMP_SendServerBW(r);
+ RTMP_SendCtrl(r, 3, 0, 300);
+ }
+ RTMP_SendCreateStream(r);
+
+ if (!(r->Link.protocol & RTMP_FEATURE_WRITE))
+ {
+ /* Send the FCSubscribe if live stream or if subscribepath is set */
+ if (r->Link.subscribepath.av_len)
+ SendFCSubscribe(r, &r->Link.subscribepath);
+ else if (r->Link.lFlags & RTMP_LF_LIVE)
+ SendFCSubscribe(r, &r->Link.playpath);
+ }
+ }
+ else if (AVMATCH(&methodInvoked, &av_createStream))
+ {
+ r->m_stream_id = (int)AMFProp_GetNumber(AMF_GetProp(&obj, NULL, 3));
+
+ if (r->Link.protocol & RTMP_FEATURE_WRITE)
+ {
+ SendPublish(r);
+ }
+ else
+ {
+ if (r->Link.lFlags & RTMP_LF_PLST)
+ SendPlaylist(r);
+ SendPlay(r);
+ RTMP_SendCtrl(r, 3, r->m_stream_id, r->m_nBufferMS);
+ }
+ }
+ else if (AVMATCH(&methodInvoked, &av_play) ||
+ AVMATCH(&methodInvoked, &av_publish))
+ {
+ r->m_bPlaying = TRUE;
+ }
+ free(methodInvoked.av_val);
+ }
+ else if (AVMATCH(&method, &av_onBWDone))
+ {
+ if (!r->m_nBWCheckCounter)
+ SendCheckBW(r);
+ }
+ else if (AVMATCH(&method, &av_onFCSubscribe))
+ {
+ /* SendOnFCSubscribe(); */
+ }
+ else if (AVMATCH(&method, &av_onFCUnsubscribe))
+ {
+ RTMP_Close(r);
+ ret = 1;
+ }
+ else if (AVMATCH(&method, &av_ping))
+ {
+ SendPong(r, txn);
+ }
+ else if (AVMATCH(&method, &av__onbwcheck))
+ {
+ SendCheckBWResult(r, txn);
+ }
+ else if (AVMATCH(&method, &av__onbwdone))
+ {
+ int i;
+ for (i = 0; i < r->m_numCalls; i++)
+ if (AVMATCH(&r->m_methodCalls[i].name, &av__checkbw))
+ {
+ AV_erase(r->m_methodCalls, &r->m_numCalls, i, TRUE);
+ break;
+ }
+ }
+ else if (AVMATCH(&method, &av__error))
+ {
+ RTMP_Log(RTMP_LOGERROR, "rtmp server sent error");
+ }
+ else if (AVMATCH(&method, &av_close))
+ {
+ RTMP_Log(RTMP_LOGERROR, "rtmp server requested close");
+ RTMP_Close(r);
+ }
+ else if (AVMATCH(&method, &av_onStatus))
+ {
+ AMFObject obj2;
+ AVal code, level;
+ AMFProp_GetObject(AMF_GetProp(&obj, NULL, 3), &obj2);
+ AMFProp_GetString(AMF_GetProp(&obj2, &av_code, -1), &code);
+ AMFProp_GetString(AMF_GetProp(&obj2, &av_level, -1), &level);
+
+ RTMP_Log(RTMP_LOGDEBUG, "%s, onStatus: %s", __FUNCTION__, code.av_val);
+ if (AVMATCH(&code, &av_NetStream_Failed)
+ || AVMATCH(&code, &av_NetStream_Play_Failed)
+ || AVMATCH(&code, &av_NetStream_Play_StreamNotFound)
+ || AVMATCH(&code, &av_NetConnection_Connect_InvalidApp))
+ {
+ r->m_stream_id = -1;
+ RTMP_Close(r);
+ RTMP_Log(RTMP_LOGERROR, "Closing connection: %s", code.av_val);
+ }
+
+ else if (AVMATCH(&code, &av_NetStream_Play_Start))
+ {
+ int i;
+ r->m_bPlaying = TRUE;
+ for (i = 0; i < r->m_numCalls; i++)
+ {
+ if (AVMATCH(&r->m_methodCalls[i].name, &av_play))
+ {
+ AV_erase(r->m_methodCalls, &r->m_numCalls, i, TRUE);
+ break;
+ }
+ }
+ }
+
+ else if (AVMATCH(&code, &av_NetStream_Publish_Start))
+ {
+ int i;
+ r->m_bPlaying = TRUE;
+ for (i = 0; i < r->m_numCalls; i++)
+ {
+ if (AVMATCH(&r->m_methodCalls[i].name, &av_publish))
+ {
+ AV_erase(r->m_methodCalls, &r->m_numCalls, i, TRUE);
+ break;
+ }
+ }
+ }
+
+ /* Return 1 if this is a Play.Complete or Play.Stop */
+ else if (AVMATCH(&code, &av_NetStream_Play_Complete)
+ || AVMATCH(&code, &av_NetStream_Play_Stop)
+ || AVMATCH(&code, &av_NetStream_Play_UnpublishNotify))
+ {
+ RTMP_Close(r);
+ ret = 1;
+ }
+
+ else if (AVMATCH(&code, &av_NetStream_Seek_Notify))
+ {
+ r->m_read.flags &= ~RTMP_READ_SEEKING;
+ }
+
+ else if (AVMATCH(&code, &av_NetStream_Pause_Notify))
+ {
+ if (r->m_pausing == 1 || r->m_pausing == 2)
+ {
+ RTMP_SendPause(r, FALSE, r->m_pauseStamp);
+ r->m_pausing = 3;
+ }
+ }
+ }
+ else if (AVMATCH(&method, &av_playlist_ready))
+ {
+ int i;
+ for (i = 0; i < r->m_numCalls; i++)
+ {
+ if (AVMATCH(&r->m_methodCalls[i].name, &av_set_playlist))
+ {
+ AV_erase(r->m_methodCalls, &r->m_numCalls, i, TRUE);
+ break;
+ }
+ }
+ }
+ else
+ {
+
+ }
+leave:
+ AMF_Reset(&obj);
+ return ret;
+}
+
+int
+RTMP_FindFirstMatchingProperty(AMFObject *obj, const AVal *name,
+ AMFObjectProperty * p)
+{
+ int n;
+ /* this is a small object search to locate the "duration" property */
+ for (n = 0; n < obj->o_num; n++)
+ {
+ AMFObjectProperty *prop = AMF_GetProp(obj, NULL, n);
+
+ if (AVMATCH(&prop->p_name, name))
+ {
+ *p = *prop;
+ return TRUE;
+ }
+
+ if (prop->p_type == AMF_OBJECT)
+ {
+ if (RTMP_FindFirstMatchingProperty(&prop->p_vu.p_object, name, p))
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+/* Like above, but only check if name is a prefix of property */
+int
+RTMP_FindPrefixProperty(AMFObject *obj, const AVal *name,
+ AMFObjectProperty * p)
+{
+ int n;
+ for (n = 0; n < obj->o_num; n++)
+ {
+ AMFObjectProperty *prop = AMF_GetProp(obj, NULL, n);
+
+ if (prop->p_name.av_len > name->av_len &&
+ !memcmp(prop->p_name.av_val, name->av_val, name->av_len))
+ {
+ *p = *prop;
+ return TRUE;
+ }
+
+ if (prop->p_type == AMF_OBJECT)
+ {
+ if (RTMP_FindPrefixProperty(&prop->p_vu.p_object, name, p))
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+static int
+DumpMetaData(AMFObject *obj)
+{
+ AMFObjectProperty *prop;
+ int n;
+ for (n = 0; n < obj->o_num; n++)
+ {
+ prop = AMF_GetProp(obj, NULL, n);
+ if (prop->p_type != AMF_OBJECT)
+ {
+ char str[256] = "";
+ switch (prop->p_type)
+ {
+ case AMF_NUMBER:
+ snprintf(str, 255, "%.2f", prop->p_vu.p_number);
+ break;
+ case AMF_BOOLEAN:
+ snprintf(str, 255, "%s",
+ prop->p_vu.p_number != 0. ? "TRUE" : "FALSE");
+ break;
+ case AMF_STRING:
+ snprintf(str, 255, "%.*s", prop->p_vu.p_aval.av_len,
+ prop->p_vu.p_aval.av_val);
+ break;
+ case AMF_DATE:
+ snprintf(str, 255, "timestamp:%.2f", prop->p_vu.p_number);
+ break;
+ default:
+ snprintf(str, 255, "INVALID TYPE 0x%02x",
+ (unsigned char)prop->p_type);
+ }
+ if (prop->p_name.av_len)
+ {
+ /* chomp */
+ if (strlen(str) >= 1 && str[strlen(str) - 1] == '\n')
+ str[strlen(str) - 1] = '\0';
+ RTMP_Log(RTMP_LOGINFO, " %-22.*s%s", prop->p_name.av_len,
+ prop->p_name.av_val, str);
+ }
+ }
+ else
+ {
+ if (prop->p_name.av_len)
+ RTMP_Log(RTMP_LOGINFO, "%.*s:", prop->p_name.av_len, prop->p_name.av_val);
+ DumpMetaData(&prop->p_vu.p_object);
+ }
+ }
+ return FALSE;
+}
+
+SAVC(onMetaData);
+SAVC(duration);
+SAVC(video);
+SAVC(audio);
+
+static int
+HandleMetadata(RTMP *r, char *body, unsigned int len)
+{
+ /* allright we get some info here, so parse it and print it */
+ /* also keep duration or filesize to make a nice progress bar */
+
+ AMFObject obj;
+ AVal metastring;
+ int ret = FALSE;
+
+ int nRes = AMF_Decode(&obj, body, len, FALSE);
+ if (nRes < 0)
+ {
+ RTMP_Log(RTMP_LOGERROR, "%s, error decoding meta data packet", __FUNCTION__);
+ return FALSE;
+ }
+
+ AMF_Dump(&obj);
+ AMFProp_GetString(AMF_GetProp(&obj, NULL, 0), &metastring);
+
+ if (AVMATCH(&metastring, &av_onMetaData))
+ {
+ AMFObjectProperty prop;
+ /* Show metadata */
+ RTMP_Log(RTMP_LOGINFO, "Metadata:");
+ DumpMetaData(&obj);
+ if (RTMP_FindFirstMatchingProperty(&obj, &av_duration, &prop))
+ {
+ r->m_fDuration = prop.p_vu.p_number;
+ /*RTMP_Log(RTMP_LOGDEBUG, "Set duration: %.2f", m_fDuration); */
+ }
+ /* Search for audio or video tags */
+ if (RTMP_FindPrefixProperty(&obj, &av_video, &prop))
+ r->m_read.dataType |= 1;
+ if (RTMP_FindPrefixProperty(&obj, &av_audio, &prop))
+ r->m_read.dataType |= 4;
+ ret = TRUE;
+ }
+ AMF_Reset(&obj);
+ return ret;
+}
+
+static void
+HandleChangeChunkSize(RTMP *r, const RTMPPacket *packet)
+{
+ if (packet->m_nBodySize >= 4)
+ {
+ r->m_inChunkSize = AMF_DecodeInt32(packet->m_body);
+ RTMP_Log(RTMP_LOGDEBUG, "%s, received: chunk size change to %d", __FUNCTION__,
+ r->m_inChunkSize);
+ }
+}
+
+static void
+HandleAudio(RTMP *r, const RTMPPacket *packet)
+{
+}
+
+static void
+HandleVideo(RTMP *r, const RTMPPacket *packet)
+{
+}
+
+static void
+HandleCtrl(RTMP *r, const RTMPPacket *packet)
+{
+ short nType = -1;
+ unsigned int tmp;
+ if (packet->m_body && packet->m_nBodySize >= 2)
+ nType = AMF_DecodeInt16(packet->m_body);
+ RTMP_Log(RTMP_LOGDEBUG, "%s, received ctrl. type: %d, len: %d", __FUNCTION__, nType,
+ packet->m_nBodySize);
+ /*RTMP_LogHex(packet.m_body, packet.m_nBodySize); */
+
+ if (packet->m_nBodySize >= 6)
+ {
+ switch (nType)
+ {
+ case 0:
+ tmp = AMF_DecodeInt32(packet->m_body + 2);
+ RTMP_Log(RTMP_LOGDEBUG, "%s, Stream Begin %d", __FUNCTION__, tmp);
+ break;
+
+ case 1:
+ tmp = AMF_DecodeInt32(packet->m_body + 2);
+ RTMP_Log(RTMP_LOGDEBUG, "%s, Stream EOF %d", __FUNCTION__, tmp);
+ if (r->m_pausing == 1)
+ r->m_pausing = 2;
+ break;
+
+ case 2:
+ tmp = AMF_DecodeInt32(packet->m_body + 2);
+ RTMP_Log(RTMP_LOGDEBUG, "%s, Stream Dry %d", __FUNCTION__, tmp);
+ break;
+
+ case 4:
+ tmp = AMF_DecodeInt32(packet->m_body + 2);
+ RTMP_Log(RTMP_LOGDEBUG, "%s, Stream IsRecorded %d", __FUNCTION__, tmp);
+ break;
+
+ case 6: /* server ping. reply with pong. */
+ tmp = AMF_DecodeInt32(packet->m_body + 2);
+ RTMP_Log(RTMP_LOGDEBUG, "%s, Ping %d", __FUNCTION__, tmp);
+ RTMP_SendCtrl(r, 0x07, tmp, 0);
+ break;
+
+ /* FMS 3.5 servers send the following two controls to let the client
+ * know when the server has sent a complete buffer. I.e., when the
+ * server has sent an amount of data equal to m_nBufferMS in duration.
+ * The server meters its output so that data arrives at the client
+ * in realtime and no faster.
+ *
+ * The rtmpdump program tries to set m_nBufferMS as large as
+ * possible, to force the server to send data as fast as possible.
+ * In practice, the server appears to cap this at about 1 hour's
+ * worth of data. After the server has sent a complete buffer, and
+ * sends this BufferEmpty message, it will wait until the play
+ * duration of that buffer has passed before sending a new buffer.
+ * The BufferReady message will be sent when the new buffer starts.
+ * (There is no BufferReady message for the very first buffer;
+ * presumably the Stream Begin message is sufficient for that
+ * purpose.)
+ *
+ * If the network speed is much faster than the data bitrate, then
+ * there may be long delays between the end of one buffer and the
+ * start of the next.
+ *
+ * Since usually the network allows data to be sent at
+ * faster than realtime, and rtmpdump wants to download the data
+ * as fast as possible, we use this RTMP_LF_BUFX hack: when we
+ * get the BufferEmpty message, we send a Pause followed by an
+ * Unpause. This causes the server to send the next buffer immediately
+ * instead of waiting for the full duration to elapse. (That's
+ * also the purpose of the ToggleStream function, which rtmpdump
+ * calls if we get a read timeout.)
+ *
+ * Media player apps don't need this hack since they are just
+ * going to play the data in realtime anyway. It also doesn't work
+ * for live streams since they obviously can only be sent in
+ * realtime. And it's all moot if the network speed is actually
+ * slower than the media bitrate.
+ */
+ case 31:
+ tmp = AMF_DecodeInt32(packet->m_body + 2);
+ RTMP_Log(RTMP_LOGDEBUG, "%s, Stream BufferEmpty %d", __FUNCTION__, tmp);
+ if (!(r->Link.lFlags & RTMP_LF_BUFX))
+ break;
+ if (!r->m_pausing)
+ {
+ r->m_pauseStamp = r->m_channelTimestamp[r->m_mediaChannel];
+ RTMP_SendPause(r, TRUE, r->m_pauseStamp);
+ r->m_pausing = 1;
+ }
+ else if (r->m_pausing == 2)
+ {
+ RTMP_SendPause(r, FALSE, r->m_pauseStamp);
+ r->m_pausing = 3;
+ }
+ break;
+
+ case 32:
+ tmp = AMF_DecodeInt32(packet->m_body + 2);
+ RTMP_Log(RTMP_LOGDEBUG, "%s, Stream BufferReady %d", __FUNCTION__, tmp);
+ break;
+
+ default:
+ tmp = AMF_DecodeInt32(packet->m_body + 2);
+ RTMP_Log(RTMP_LOGDEBUG, "%s, Stream xx %d", __FUNCTION__, tmp);
+ break;
+ }
+
+ }
+
+ if (nType == 0x1A)
+ {
+ RTMP_Log(RTMP_LOGDEBUG, "%s, SWFVerification ping received: ", __FUNCTION__);
+#ifdef CRYPTO
+ /*RTMP_LogHex(packet.m_body, packet.m_nBodySize); */
+
+ /* respond with HMAC SHA256 of decompressed SWF, key is the 30byte player key, also the last 30 bytes of the server handshake are applied */
+ if (r->Link.SWFSize)
+ {
+ RTMP_SendCtrl(r, 0x1B, 0, 0);
+ }
+ else
+ {
+ RTMP_Log(RTMP_LOGERROR,
+ "%s: Ignoring SWFVerification request, use --swfVfy!",
+ __FUNCTION__);
+ }
+#else
+ RTMP_Log(RTMP_LOGERROR,
+ "%s: Ignoring SWFVerification request, no CRYPTO support!",
+ __FUNCTION__);
+#endif
+ }
+}
+
+static void
+HandleServerBW(RTMP *r, const RTMPPacket *packet)
+{
+ r->m_nServerBW = AMF_DecodeInt32(packet->m_body);
+ RTMP_Log(RTMP_LOGDEBUG, "%s: server BW = %d", __FUNCTION__, r->m_nServerBW);
+}
+
+static void
+HandleClientBW(RTMP *r, const RTMPPacket *packet)
+{
+ r->m_nClientBW = AMF_DecodeInt32(packet->m_body);
+ if (packet->m_nBodySize > 4)
+ r->m_nClientBW2 = packet->m_body[4];
+ else
+ r->m_nClientBW2 = -1;
+ RTMP_Log(RTMP_LOGDEBUG, "%s: client BW = %d %d", __FUNCTION__, r->m_nClientBW,
+ r->m_nClientBW2);
+}
+
+static int
+DecodeInt32LE(const char *data)
+{
+ unsigned char *c = (unsigned char *)data;
+ unsigned int val;
+
+ val = (c[3] << 24) | (c[2] << 16) | (c[1] << 8) | c[0];
+ return val;
+}
+
+static int
+EncodeInt32LE(char *output, int nVal)
+{
+ output[0] = nVal;
+ nVal >>= 8;
+ output[1] = nVal;
+ nVal >>= 8;
+ output[2] = nVal;
+ nVal >>= 8;
+ output[3] = nVal;
+ return 4;
+}
+
+int
+RTMP_ReadPacket(RTMP *r, RTMPPacket *packet)
+{
+ uint8_t hbuf[RTMP_MAX_HEADER_SIZE] = { 0 };
+ char *header = (char *)hbuf;
+ int nSize, hSize, nToRead, nChunk;
+ int didAlloc = FALSE;
+
+ RTMP_Log(RTMP_LOGDEBUG2, "%s: fd=%d", __FUNCTION__, r->m_sb.sb_socket);
+
+ if (ReadN(r, (char *)hbuf, 1) == 0)
+ {
+ RTMP_Log(RTMP_LOGERROR, "%s, failed to read RTMP packet header", __FUNCTION__);
+ return FALSE;
+ }
+
+ packet->m_headerType = (hbuf[0] & 0xc0) >> 6;
+ packet->m_nChannel = (hbuf[0] & 0x3f);
+ header++;
+ if (packet->m_nChannel == 0)
+ {
+ if (ReadN(r, (char *)&hbuf[1], 1) != 1)
+ {
+ RTMP_Log(RTMP_LOGERROR, "%s, failed to read RTMP packet header 2nd byte",
+ __FUNCTION__);
+ return FALSE;
+ }
+ packet->m_nChannel = hbuf[1];
+ packet->m_nChannel += 64;
+ header++;
+ }
+ else if (packet->m_nChannel == 1)
+ {
+ int tmp;
+ if (ReadN(r, (char *)&hbuf[1], 2) != 2)
+ {
+ RTMP_Log(RTMP_LOGERROR, "%s, failed to read RTMP packet header 3nd byte",
+ __FUNCTION__);
+ return FALSE;
+ }
+ tmp = (hbuf[2] << 8) + hbuf[1];
+ packet->m_nChannel = tmp + 64;
+ RTMP_Log(RTMP_LOGDEBUG, "%s, m_nChannel: %0x", __FUNCTION__, packet->m_nChannel);
+ header += 2;
+ }
+
+ nSize = packetSize[packet->m_headerType];
+
+ if (nSize == RTMP_LARGE_HEADER_SIZE) /* if we get a full header the timestamp is absolute */
+ packet->m_hasAbsTimestamp = TRUE;
+
+ else if (nSize < RTMP_LARGE_HEADER_SIZE)
+ { /* using values from the last message of this channel */
+ if (r->m_vecChannelsIn[packet->m_nChannel])
+ memcpy(packet, r->m_vecChannelsIn[packet->m_nChannel],
+ sizeof(RTMPPacket));
+ }
+
+ nSize--;
+
+ if (nSize > 0 && ReadN(r, header, nSize) != nSize)
+ {
+ RTMP_Log(RTMP_LOGERROR, "%s, failed to read RTMP packet header. type: %x",
+ __FUNCTION__, (unsigned int)hbuf[0]);
+ return FALSE;
+ }
+
+ hSize = nSize + (header - (char *)hbuf);
+
+ if (nSize >= 3)
+ {
+ packet->m_nTimeStamp = AMF_DecodeInt24(header);
+
+ /*RTMP_Log(RTMP_LOGDEBUG, "%s, reading RTMP packet chunk on channel %x, headersz %i, timestamp %i, abs timestamp %i", __FUNCTION__, packet.m_nChannel, nSize, packet.m_nTimeStamp, packet.m_hasAbsTimestamp); */
+
+ if (nSize >= 6)
+ {
+ packet->m_nBodySize = AMF_DecodeInt24(header + 3);
+ packet->m_nBytesRead = 0;
+ RTMPPacket_Free(packet);
+
+ if (nSize > 6)
+ {
+ packet->m_packetType = header[6];
+
+ if (nSize == 11)
+ packet->m_nInfoField2 = DecodeInt32LE(header + 7);
+ }
+ }
+ if (packet->m_nTimeStamp == 0xffffff)
+ {
+ if (ReadN(r, header + nSize, 4) != 4)
+ {
+ RTMP_Log(RTMP_LOGERROR, "%s, failed to read extended timestamp",
+ __FUNCTION__);
+ return FALSE;
+ }
+ packet->m_nTimeStamp = AMF_DecodeInt32(header + nSize);
+ hSize += 4;
+ }
+ }
+
+ RTMP_LogHexString(RTMP_LOGDEBUG2, (uint8_t *)hbuf, hSize);
+
+ if (packet->m_nBodySize > 0 && packet->m_body == NULL)
+ {
+ if (!RTMPPacket_Alloc(packet, packet->m_nBodySize))
+ {
+ RTMP_Log(RTMP_LOGDEBUG, "%s, failed to allocate packet", __FUNCTION__);
+ return FALSE;
+ }
+ didAlloc = TRUE;
+ packet->m_headerType = (hbuf[0] & 0xc0) >> 6;
+ }
+
+ nToRead = packet->m_nBodySize - packet->m_nBytesRead;
+ nChunk = r->m_inChunkSize;
+ if (nToRead < nChunk)
+ nChunk = nToRead;
+
+ /* Does the caller want the raw chunk? */
+ if (packet->m_chunk)
+ {
+ packet->m_chunk->c_headerSize = hSize;
+ memcpy(packet->m_chunk->c_header, hbuf, hSize);
+ packet->m_chunk->c_chunk = packet->m_body + packet->m_nBytesRead;
+ packet->m_chunk->c_chunkSize = nChunk;
+ }
+
+ if (ReadN(r, packet->m_body + packet->m_nBytesRead, nChunk) != nChunk)
+ {
+ RTMP_Log(RTMP_LOGERROR, "%s, failed to read RTMP packet body. len: %lu",
+ __FUNCTION__, packet->m_nBodySize);
+ return FALSE;
+ }
+
+ RTMP_LogHexString(RTMP_LOGDEBUG2, (uint8_t *)packet->m_body + packet->m_nBytesRead, nChunk);
+
+ packet->m_nBytesRead += nChunk;
+
+ /* keep the packet as ref for other packets on this channel */
+ if (!r->m_vecChannelsIn[packet->m_nChannel])
+ r->m_vecChannelsIn[packet->m_nChannel] = malloc(sizeof(RTMPPacket));
+ memcpy(r->m_vecChannelsIn[packet->m_nChannel], packet, sizeof(RTMPPacket));
+
+ if (RTMPPacket_IsReady(packet))
+ {
+ /* make packet's timestamp absolute */
+ if (!packet->m_hasAbsTimestamp)
+ packet->m_nTimeStamp += r->m_channelTimestamp[packet->m_nChannel]; /* timestamps seem to be always relative!! */
+
+ r->m_channelTimestamp[packet->m_nChannel] = packet->m_nTimeStamp;
+
+ /* reset the data from the stored packet. we keep the header since we may use it later if a new packet for this channel */
+ /* arrives and requests to re-use some info (small packet header) */
+ r->m_vecChannelsIn[packet->m_nChannel]->m_body = NULL;
+ r->m_vecChannelsIn[packet->m_nChannel]->m_nBytesRead = 0;
+ r->m_vecChannelsIn[packet->m_nChannel]->m_hasAbsTimestamp = FALSE; /* can only be false if we reuse header */
+ }
+ else
+ {
+ packet->m_body = NULL; /* so it won't be erased on free */
+ }
+
+ return TRUE;
+}
+
+#ifndef CRYPTO
+static int
+HandShake(RTMP *r, int FP9HandShake)
+{
+ int i;
+ uint32_t uptime, suptime;
+ int bMatch;
+ char type;
+ char clientbuf[RTMP_SIG_SIZE + 1], *clientsig = clientbuf + 1;
+ char serversig[RTMP_SIG_SIZE];
+
+ clientbuf[0] = 0x03; /* not encrypted */
+
+ uptime = htonl(RTMP_GetTime());
+ memcpy(clientsig, &uptime, 4);
+
+ memset(&clientsig[4], 0, 4);
+
+#ifdef _DEBUG
+ for (i = 8; i < RTMP_SIG_SIZE; i++)
+ clientsig[i] = 0xff;
+#else
+ for (i = 8; i < RTMP_SIG_SIZE; i++)
+ clientsig[i] = (char)(rand() % 256);
+#endif
+
+ if (!WriteN(r, clientbuf, RTMP_SIG_SIZE + 1))
+ return FALSE;
+
+ if (ReadN(r, &type, 1) != 1) /* 0x03 or 0x06 */
+ return FALSE;
+
+ RTMP_Log(RTMP_LOGDEBUG, "%s: Type Answer : %02X", __FUNCTION__, type);
+
+ if (type != clientbuf[0])
+ RTMP_Log(RTMP_LOGWARNING, "%s: Type mismatch: client sent %d, server answered %d",
+ __FUNCTION__, clientbuf[0], type);
+
+ if (ReadN(r, serversig, RTMP_SIG_SIZE) != RTMP_SIG_SIZE)
+ return FALSE;
+
+ /* decode server response */
+
+ memcpy(&suptime, serversig, 4);
+ suptime = ntohl(suptime);
+
+ RTMP_Log(RTMP_LOGDEBUG, "%s: Server Uptime : %d", __FUNCTION__, suptime);
+ RTMP_Log(RTMP_LOGDEBUG, "%s: FMS Version : %d.%d.%d.%d", __FUNCTION__,
+ serversig[4], serversig[5], serversig[6], serversig[7]);
+
+ /* 2nd part of handshake */
+ if (!WriteN(r, serversig, RTMP_SIG_SIZE))
+ return FALSE;
+
+ if (ReadN(r, serversig, RTMP_SIG_SIZE) != RTMP_SIG_SIZE)
+ return FALSE;
+
+ bMatch = (memcmp(serversig, clientsig, RTMP_SIG_SIZE) == 0);
+ if (!bMatch)
+ {
+ RTMP_Log(RTMP_LOGWARNING, "%s, client signature does not match!", __FUNCTION__);
+ }
+ return TRUE;
+}
+
+static int
+SHandShake(RTMP *r)
+{
+ int i;
+ char serverbuf[RTMP_SIG_SIZE + 1], *serversig = serverbuf + 1;
+ char clientsig[RTMP_SIG_SIZE];
+ uint32_t uptime;
+ int bMatch;
+
+ if (ReadN(r, serverbuf, 1) != 1) /* 0x03 or 0x06 */
+ return FALSE;
+
+ RTMP_Log(RTMP_LOGDEBUG, "%s: Type Request : %02X", __FUNCTION__, serverbuf[0]);
+
+ if (serverbuf[0] != 3)
+ {
+ RTMP_Log(RTMP_LOGERROR, "%s: Type unknown: client sent %02X",
+ __FUNCTION__, serverbuf[0]);
+ return FALSE;
+ }
+
+ uptime = htonl(RTMP_GetTime());
+ memcpy(serversig, &uptime, 4);
+
+ memset(&serversig[4], 0, 4);
+#ifdef _DEBUG
+ for (i = 8; i < RTMP_SIG_SIZE; i++)
+ serversig[i] = 0xff;
+#else
+ for (i = 8; i < RTMP_SIG_SIZE; i++)
+ serversig[i] = (char)(rand() % 256);
+#endif
+
+ if (!WriteN(r, serverbuf, RTMP_SIG_SIZE + 1))
+ return FALSE;
+
+ if (ReadN(r, clientsig, RTMP_SIG_SIZE) != RTMP_SIG_SIZE)
+ return FALSE;
+
+ /* decode client response */
+
+ memcpy(&uptime, clientsig, 4);
+ uptime = ntohl(uptime);
+
+ RTMP_Log(RTMP_LOGDEBUG, "%s: Client Uptime : %d", __FUNCTION__, uptime);
+ RTMP_Log(RTMP_LOGDEBUG, "%s: Player Version: %d.%d.%d.%d", __FUNCTION__,
+ clientsig[4], clientsig[5], clientsig[6], clientsig[7]);
+
+ /* 2nd part of handshake */
+ if (!WriteN(r, clientsig, RTMP_SIG_SIZE))
+ return FALSE;
+
+ if (ReadN(r, clientsig, RTMP_SIG_SIZE) != RTMP_SIG_SIZE)
+ return FALSE;
+
+ bMatch = (memcmp(serversig, clientsig, RTMP_SIG_SIZE) == 0);
+ if (!bMatch)
+ {
+ RTMP_Log(RTMP_LOGWARNING, "%s, client signature does not match!", __FUNCTION__);
+ }
+ return TRUE;
+}
+#endif
+
+int
+RTMP_SendChunk(RTMP *r, RTMPChunk *chunk)
+{
+ int wrote;
+ char hbuf[RTMP_MAX_HEADER_SIZE];
+
+ RTMP_Log(RTMP_LOGDEBUG2, "%s: fd=%d, size=%d", __FUNCTION__, r->m_sb.sb_socket,
+ chunk->c_chunkSize);
+ RTMP_LogHexString(RTMP_LOGDEBUG2, (uint8_t *)chunk->c_header, chunk->c_headerSize);
+ if (chunk->c_chunkSize)
+ {
+ char *ptr = chunk->c_chunk - chunk->c_headerSize;
+ RTMP_LogHexString(RTMP_LOGDEBUG2, (uint8_t *)chunk->c_chunk, chunk->c_chunkSize);
+ /* save header bytes we're about to overwrite */
+ memcpy(hbuf, ptr, chunk->c_headerSize);
+ memcpy(ptr, chunk->c_header, chunk->c_headerSize);
+ wrote = WriteN(r, ptr, chunk->c_headerSize + chunk->c_chunkSize);
+ memcpy(ptr, hbuf, chunk->c_headerSize);
+ }
+ else
+ wrote = WriteN(r, chunk->c_header, chunk->c_headerSize);
+ return wrote;
+}
+
+int
+RTMP_SendPacket(RTMP *r, RTMPPacket *packet, int queue)
+{
+ const RTMPPacket *prevPacket = r->m_vecChannelsOut[packet->m_nChannel];
+ uint32_t last = 0;
+ int nSize;
+ int hSize, cSize;
+ char *header, *hptr, *hend, hbuf[RTMP_MAX_HEADER_SIZE], c;
+ uint32_t t;
+ char *buffer, *tbuf = NULL, *toff = NULL;
+ int nChunkSize;
+ int tlen;
+
+ if (prevPacket && packet->m_headerType != RTMP_PACKET_SIZE_LARGE)
+ {
+ /* compress a bit by using the prev packet's attributes */
+ if (prevPacket->m_nBodySize == packet->m_nBodySize
+ && prevPacket->m_packetType == packet->m_packetType
+ && packet->m_headerType == RTMP_PACKET_SIZE_MEDIUM)
+ packet->m_headerType = RTMP_PACKET_SIZE_SMALL;
+
+ if (prevPacket->m_nTimeStamp == packet->m_nTimeStamp
+ && packet->m_headerType == RTMP_PACKET_SIZE_SMALL)
+ packet->m_headerType = RTMP_PACKET_SIZE_MINIMUM;
+ last = prevPacket->m_nTimeStamp;
+ }
+
+ if (packet->m_headerType > 3) /* sanity */
+ {
+ RTMP_Log(RTMP_LOGERROR, "sanity failed!! trying to send header of type: 0x%02x.",
+ (unsigned char)packet->m_headerType);
+ return FALSE;
+ }
+
+ nSize = packetSize[packet->m_headerType];
+ hSize = nSize; cSize = 0;
+ t = packet->m_nTimeStamp - last;
+
+ if (packet->m_body)
+ {
+ header = packet->m_body - nSize;
+ hend = packet->m_body;
+ }
+ else
+ {
+ header = hbuf + 6;
+ hend = hbuf + sizeof(hbuf);
+ }
+
+ if (packet->m_nChannel > 319)
+ cSize = 2;
+ else if (packet->m_nChannel > 63)
+ cSize = 1;
+ if (cSize)
+ {
+ header -= cSize;
+ hSize += cSize;
+ }
+
+ if (nSize > 1 && t >= 0xffffff)
+ {
+ header -= 4;
+ hSize += 4;
+ }
+
+ hptr = header;
+ c = packet->m_headerType << 6;
+ switch (cSize)
+ {
+ case 0:
+ c |= packet->m_nChannel;
+ break;
+ case 1:
+ break;
+ case 2:
+ c |= 1;
+ break;
+ }
+ *hptr++ = c;
+ if (cSize)
+ {
+ int tmp = packet->m_nChannel - 64;
+ *hptr++ = tmp & 0xff;
+ if (cSize == 2)
+ *hptr++ = tmp >> 8;
+ }
+
+ if (nSize > 1)
+ {
+ hptr = AMF_EncodeInt24(hptr, hend, t > 0xffffff ? 0xffffff : t);
+ }
+
+ if (nSize > 4)
+ {
+ hptr = AMF_EncodeInt24(hptr, hend, packet->m_nBodySize);
+ *hptr++ = packet->m_packetType;
+ }
+
+ if (nSize > 8)
+ hptr += EncodeInt32LE(hptr, packet->m_nInfoField2);
+
+ if (nSize > 1 && t >= 0xffffff)
+ hptr = AMF_EncodeInt32(hptr, hend, t);
+
+ nSize = packet->m_nBodySize;
+ buffer = packet->m_body;
+ nChunkSize = r->m_outChunkSize;
+
+ RTMP_Log(RTMP_LOGDEBUG2, "%s: fd=%d, size=%d", __FUNCTION__, r->m_sb.sb_socket,
+ nSize);
+ /* send all chunks in one HTTP request */
+ if (r->Link.protocol & RTMP_FEATURE_HTTP)
+ {
+ int chunks = (nSize+nChunkSize-1) / nChunkSize;
+ if (chunks > 1)
+ {
+ tlen = chunks * (cSize + 1) + nSize + hSize;
+ tbuf = malloc(tlen);
+ if (!tbuf)
+ return FALSE;
+ toff = tbuf;
+ }
+ }
+ while (nSize + hSize)
+ {
+ int wrote;
+
+ if (nSize < nChunkSize)
+ nChunkSize = nSize;
+
+ RTMP_LogHexString(RTMP_LOGDEBUG2, (uint8_t *)header, hSize);
+ RTMP_LogHexString(RTMP_LOGDEBUG2, (uint8_t *)buffer, nChunkSize);
+ if (tbuf)
+ {
+ memcpy(toff, header, nChunkSize + hSize);
+ toff += nChunkSize + hSize;
+ }
+ else
+ {
+ wrote = WriteN(r, header, nChunkSize + hSize);
+ if (!wrote)
+ return FALSE;
+ }
+ nSize -= nChunkSize;
+ buffer += nChunkSize;
+ hSize = 0;
+
+ if (nSize > 0)
+ {
+ header = buffer - 1;
+ hSize = 1;
+ if (cSize)
+ {
+ header -= cSize;
+ hSize += cSize;
+ }
+ *header = (0xc0 | c);
+ if (cSize)
+ {
+ int tmp = packet->m_nChannel - 64;
+ header[1] = tmp & 0xff;
+ if (cSize == 2)
+ header[2] = tmp >> 8;
+ }
+ }
+ }
+ if (tbuf)
+ {
+ int wrote = WriteN(r, tbuf, toff-tbuf);
+ free(tbuf);
+ tbuf = NULL;
+ if (!wrote)
+ return FALSE;
+ }
+
+ /* we invoked a remote method */
+ if (packet->m_packetType == 0x14)
+ {
+ AVal method;
+ char *ptr;
+ ptr = packet->m_body + 1;
+ AMF_DecodeString(ptr, &method);
+ RTMP_Log(RTMP_LOGDEBUG, "Invoking %s", method.av_val);
+ /* keep it in call queue till result arrives */
+ if (queue) {
+ int txn;
+ ptr += 3 + method.av_len;
+ txn = (int)AMF_DecodeNumber(ptr);
+ AV_queue(&r->m_methodCalls, &r->m_numCalls, &method, txn);
+ }
+ }
+
+ if (!r->m_vecChannelsOut[packet->m_nChannel])
+ r->m_vecChannelsOut[packet->m_nChannel] = malloc(sizeof(RTMPPacket));
+ memcpy(r->m_vecChannelsOut[packet->m_nChannel], packet, sizeof(RTMPPacket));
+ return TRUE;
+}
+
+int
+RTMP_Serve(RTMP *r)
+{
+ return SHandShake(r);
+}
+
+void
+RTMP_Close(RTMP *r)
+{
+ int i;
+
+ if (RTMP_IsConnected(r))
+ {
+ if (r->m_stream_id > 0)
+ {
+ if ((r->Link.protocol & RTMP_FEATURE_WRITE))
+ SendFCUnpublish(r);
+ i = r->m_stream_id;
+ r->m_stream_id = 0;
+ SendDeleteStream(r, i);
+ }
+ if (r->m_clientID.av_val)
+ {
+ HTTP_Post(r, RTMPT_CLOSE, "", 1);
+ free(r->m_clientID.av_val);
+ r->m_clientID.av_val = NULL;
+ r->m_clientID.av_len = 0;
+ }
+ RTMPSockBuf_Close(&r->m_sb);
+ }
+
+ r->m_stream_id = -1;
+ r->m_sb.sb_socket = -1;
+ r->m_nBWCheckCounter = 0;
+ r->m_nBytesIn = 0;
+ r->m_nBytesInSent = 0;
+
+ if (r->m_read.flags & RTMP_READ_HEADER) {
+ free(r->m_read.buf);
+ r->m_read.buf = NULL;
+ }
+ r->m_read.dataType = 0;
+ r->m_read.flags = 0;
+ r->m_read.status = 0;
+ r->m_read.nResumeTS = 0;
+ r->m_read.nIgnoredFrameCounter = 0;
+ r->m_read.nIgnoredFlvFrameCounter = 0;
+
+ r->m_write.m_nBytesRead = 0;
+ RTMPPacket_Free(&r->m_write);
+
+ for (i = 0; i < RTMP_CHANNELS; i++)
+ {
+ if (r->m_vecChannelsIn[i])
+ {
+ RTMPPacket_Free(r->m_vecChannelsIn[i]);
+ free(r->m_vecChannelsIn[i]);
+ r->m_vecChannelsIn[i] = NULL;
+ }
+ if (r->m_vecChannelsOut[i])
+ {
+ free(r->m_vecChannelsOut[i]);
+ r->m_vecChannelsOut[i] = NULL;
+ }
+ }
+ AV_clear(r->m_methodCalls, r->m_numCalls);
+ r->m_methodCalls = NULL;
+ r->m_numCalls = 0;
+ r->m_numInvokes = 0;
+
+ r->m_bPlaying = FALSE;
+ r->m_sb.sb_size = 0;
+
+ r->m_msgCounter = 0;
+ r->m_resplen = 0;
+ r->m_unackd = 0;
+
+ free(r->Link.playpath0.av_val);
+ r->Link.playpath0.av_val = NULL;
+
+ if (r->Link.lFlags & RTMP_LF_FTCU)
+ {
+ free(r->Link.tcUrl.av_val);
+ r->Link.tcUrl.av_val = NULL;
+ r->Link.lFlags ^= RTMP_LF_FTCU;
+ }
+
+#ifdef CRYPTO
+ if (r->Link.dh)
+ {
+ MDH_free(r->Link.dh);
+ r->Link.dh = NULL;
+ }
+ if (r->Link.rc4keyIn)
+ {
+ RC4_free(r->Link.rc4keyIn);
+ r->Link.rc4keyIn = NULL;
+ }
+ if (r->Link.rc4keyOut)
+ {
+ RC4_free(r->Link.rc4keyOut);
+ r->Link.rc4keyOut = NULL;
+ }
+#endif
+}
+
+int
+RTMPSockBuf_Fill(RTMPSockBuf *sb)
+{
+ int nBytes;
+
+ if (!sb->sb_size)
+ sb->sb_start = sb->sb_buf;
+
+ while (1)
+ {
+ nBytes = sizeof(sb->sb_buf) - sb->sb_size - (sb->sb_start - sb->sb_buf);
+#if defined(CRYPTO) && !defined(NO_SSL)
+ if (sb->sb_ssl)
+ {
+ nBytes = TLS_read(sb->sb_ssl, sb->sb_start + sb->sb_size, nBytes);
+ }
+ else
+#endif
+ {
+ nBytes = recv(sb->sb_socket, sb->sb_start + sb->sb_size, nBytes, 0);
+ }
+ if (nBytes != -1)
+ {
+ sb->sb_size += nBytes;
+ }
+ else
+ {
+ int sockerr = GetSockError();
+ RTMP_Log(RTMP_LOGDEBUG, "%s, recv returned %d. GetSockError(): %d (%s)",
+ __FUNCTION__, nBytes, sockerr, strerror(sockerr));
+ if (sockerr == EINTR && !RTMP_ctrlC)
+ continue;
+
+ if (sockerr == EWOULDBLOCK || sockerr == EAGAIN)
+ {
+ sb->sb_timedout = TRUE;
+ nBytes = 0;
+ }
+ }
+ break;
+ }
+
+ return nBytes;
+}
+
+int
+RTMPSockBuf_Send(RTMPSockBuf *sb, const char *buf, int len)
+{
+ int rc;
+
+#ifdef _DEBUG
+ fwrite(buf, 1, len, netstackdump);
+#endif
+
+#if defined(CRYPTO) && !defined(NO_SSL)
+ if (sb->sb_ssl)
+ {
+ rc = TLS_write(sb->sb_ssl, buf, len);
+ }
+ else
+#endif
+ {
+ rc = send(sb->sb_socket, buf, len, 0);
+ }
+ return rc;
+}
+
+int
+RTMPSockBuf_Close(RTMPSockBuf *sb)
+{
+#if defined(CRYPTO) && !defined(NO_SSL)
+ if (sb->sb_ssl)
+ {
+ TLS_shutdown(sb->sb_ssl);
+ TLS_close(sb->sb_ssl);
+ sb->sb_ssl = NULL;
+ }
+#endif
+ return closesocket(sb->sb_socket);
+}
+
+#define HEX2BIN(a) (((a)&0x40)?((a)&0xf)+9:((a)&0xf))
+
+static void
+DecodeTEA(AVal *key, AVal *text)
+{
+ uint32_t *v, k[4] = { 0 }, u;
+ uint32_t z, y, sum = 0, e, DELTA = 0x9e3779b9;
+ int32_t p, q;
+ int i, n;
+ unsigned char *ptr, *out;
+
+ /* prep key: pack 1st 16 chars into 4 LittleEndian ints */
+ ptr = (unsigned char *)key->av_val;
+ u = 0;
+ n = 0;
+ v = k;
+ p = key->av_len > 16 ? 16 : key->av_len;
+ for (i = 0; i < p; i++)
+ {
+ u |= ptr[i] << (n * 8);
+ if (n == 3)
+ {
+ *v++ = u;
+ u = 0;
+ n = 0;
+ }
+ else
+ {
+ n++;
+ }
+ }
+ /* any trailing chars */
+ if (u)
+ *v = u;
+
+ /* prep text: hex2bin, multiples of 4 */
+ n = (text->av_len + 7) / 8;
+ out = malloc(n * 8);
+ ptr = (unsigned char *)text->av_val;
+ v = (uint32_t *) out;
+ for (i = 0; i < n; i++)
+ {
+ u = (HEX2BIN(ptr[0]) << 4) + HEX2BIN(ptr[1]);
+ u |= ((HEX2BIN(ptr[2]) << 4) + HEX2BIN(ptr[3])) << 8;
+ u |= ((HEX2BIN(ptr[4]) << 4) + HEX2BIN(ptr[5])) << 16;
+ u |= ((HEX2BIN(ptr[6]) << 4) + HEX2BIN(ptr[7])) << 24;
+ *v++ = u;
+ ptr += 8;
+ }
+ v = (uint32_t *) out;
+
+ /* http://www.movable-type.co.uk/scripts/tea-block.html */
+#define MX (((z>>5)^(y<<2)) + ((y>>3)^(z<<4))) ^ ((sum^y) + (k[(p&3)^e]^z));
+ z = v[n - 1];
+ y = v[0];
+ q = 6 + 52 / n;
+ sum = q * DELTA;
+ while (sum != 0)
+ {
+ e = sum >> 2 & 3;
+ for (p = n - 1; p > 0; p--)
+ z = v[p - 1], y = v[p] -= MX;
+ z = v[n - 1];
+ y = v[0] -= MX;
+ sum -= DELTA;
+ }
+
+ text->av_len /= 2;
+ memcpy(text->av_val, out, text->av_len);
+ free(out);
+}
+
+static int
+HTTP_Post(RTMP *r, RTMPTCmd cmd, const char *buf, int len)
+{
+ char hbuf[512];
+ int hlen = snprintf(hbuf, sizeof(hbuf), "POST /%s%s/%d HTTP/1.1\r\n"
+ "Host: %.*s:%d\r\n"
+ "Accept: */*\r\n"
+ "User-Agent: Shockwave Flash\n"
+ "Connection: Keep-Alive\n"
+ "Cache-Control: no-cache\r\n"
+ "Content-type: application/x-fcs\r\n"
+ "Content-length: %d\r\n\r\n", RTMPT_cmds[cmd],
+ r->m_clientID.av_val ? r->m_clientID.av_val : "",
+ r->m_msgCounter, r->Link.hostname.av_len, r->Link.hostname.av_val,
+ r->Link.port, len);
+ RTMPSockBuf_Send(&r->m_sb, hbuf, hlen);
+ hlen = RTMPSockBuf_Send(&r->m_sb, buf, len);
+ r->m_msgCounter++;
+ r->m_unackd++;
+ return hlen;
+}
+
+static int
+HTTP_read(RTMP *r, int fill)
+{
+ char *ptr;
+ int hlen;
+
+ if (fill)
+ RTMPSockBuf_Fill(&r->m_sb);
+ if (r->m_sb.sb_size < 144)
+ return -1;
+ if (strncmp(r->m_sb.sb_start, "HTTP/1.1 200 ", 13))
+ return -1;
+ ptr = strstr(r->m_sb.sb_start, "Content-Length:");
+ if (!ptr)
+ return -1;
+ hlen = atoi(ptr+16);
+ ptr = strstr(ptr, "\r\n\r\n");
+ if (!ptr)
+ return -1;
+ ptr += 4;
+ r->m_sb.sb_size -= ptr - r->m_sb.sb_start;
+ r->m_sb.sb_start = ptr;
+ r->m_unackd--;
+
+ if (!r->m_clientID.av_val)
+ {
+ r->m_clientID.av_len = hlen;
+ r->m_clientID.av_val = malloc(hlen+1);
+ if (!r->m_clientID.av_val)
+ return -1;
+ r->m_clientID.av_val[0] = '/';
+ memcpy(r->m_clientID.av_val+1, ptr, hlen-1);
+ r->m_clientID.av_val[hlen] = 0;
+ r->m_sb.sb_size = 0;
+ }
+ else
+ {
+ r->m_polling = *ptr++;
+ r->m_resplen = hlen - 1;
+ r->m_sb.sb_start++;
+ r->m_sb.sb_size--;
+ }
+ return 0;
+}
+
+#define MAX_IGNORED_FRAMES 50
+
+/* Read from the stream until we get a media packet.
+ * Returns -3 if Play.Close/Stop, -2 if fatal error, -1 if no more media
+ * packets, 0 if ignorable error, >0 if there is a media packet
+ */
+static int
+Read_1_Packet(RTMP *r, char *buf, unsigned int buflen)
+{
+ uint32_t prevTagSize = 0;
+ int rtnGetNextMediaPacket = 0, ret = RTMP_READ_EOF;
+ RTMPPacket packet = { 0 };
+ int recopy = FALSE;
+ unsigned int size;
+ char *ptr, *pend;
+ uint32_t nTimeStamp = 0;
+ unsigned int len;
+
+ rtnGetNextMediaPacket = RTMP_GetNextMediaPacket(r, &packet);
+ while (rtnGetNextMediaPacket)
+ {
+ char *packetBody = packet.m_body;
+ unsigned int nPacketLen = packet.m_nBodySize;
+
+ /* Return -3 if this was completed nicely with invoke message
+ * Play.Stop or Play.Complete
+ */
+ if (rtnGetNextMediaPacket == 2)
+ {
+ RTMP_Log(RTMP_LOGDEBUG,
+ "Got Play.Complete or Play.Stop from server. "
+ "Assuming stream is complete");
+ ret = RTMP_READ_COMPLETE;
+ break;
+ }
+
+ r->m_read.dataType |= (((packet.m_packetType == 0x08) << 2) |
+ (packet.m_packetType == 0x09));
+
+ if (packet.m_packetType == 0x09 && nPacketLen <= 5)
+ {
+ RTMP_Log(RTMP_LOGDEBUG, "ignoring too small video packet: size: %d",
+ nPacketLen);
+ ret = RTMP_READ_IGNORE;
+ break;
+ }
+ if (packet.m_packetType == 0x08 && nPacketLen <= 1)
+ {
+ RTMP_Log(RTMP_LOGDEBUG, "ignoring too small audio packet: size: %d",
+ nPacketLen);
+ ret = RTMP_READ_IGNORE;
+ break;
+ }
+
+ if (r->m_read.flags & RTMP_READ_SEEKING)
+ {
+ ret = RTMP_READ_IGNORE;
+ break;
+ }
+#ifdef _DEBUG
+ RTMP_Log(RTMP_LOGDEBUG, "type: %02X, size: %d, TS: %d ms, abs TS: %d",
+ packet.m_packetType, nPacketLen, packet.m_nTimeStamp,
+ packet.m_hasAbsTimestamp);
+ if (packet.m_packetType == 0x09)
+ RTMP_Log(RTMP_LOGDEBUG, "frametype: %02X", (*packetBody & 0xf0));
+#endif
+
+ if (r->m_read.flags & RTMP_READ_RESUME)
+ {
+ /* check the header if we get one */
+ if (packet.m_nTimeStamp == 0)
+ {
+ if (r->m_read.nMetaHeaderSize > 0
+ && packet.m_packetType == 0x12)
+ {
+ AMFObject metaObj;
+ int nRes =
+ AMF_Decode(&metaObj, packetBody, nPacketLen, FALSE);
+ if (nRes >= 0)
+ {
+ AVal metastring;
+ AMFProp_GetString(AMF_GetProp(&metaObj, NULL, 0),
+ &metastring);
+
+ if (AVMATCH(&metastring, &av_onMetaData))
+ {
+ /* compare */
+ if ((r->m_read.nMetaHeaderSize != nPacketLen) ||
+ (memcmp
+ (r->m_read.metaHeader, packetBody,
+ r->m_read.nMetaHeaderSize) != 0))
+ {
+ ret = RTMP_READ_ERROR;
+ }
+ }
+ AMF_Reset(&metaObj);
+ if (ret == RTMP_READ_ERROR)
+ break;
+ }
+ }
+
+ /* check first keyframe to make sure we got the right position
+ * in the stream! (the first non ignored frame)
+ */
+ if (r->m_read.nInitialFrameSize > 0)
+ {
+ /* video or audio data */
+ if (packet.m_packetType == r->m_read.initialFrameType
+ && r->m_read.nInitialFrameSize == nPacketLen)
+ {
+ /* we don't compare the sizes since the packet can
+ * contain several FLV packets, just make sure the
+ * first frame is our keyframe (which we are going
+ * to rewrite)
+ */
+ if (memcmp
+ (r->m_read.initialFrame, packetBody,
+ r->m_read.nInitialFrameSize) == 0)
+ {
+ RTMP_Log(RTMP_LOGDEBUG, "Checked keyframe successfully!");
+ r->m_read.flags |= RTMP_READ_GOTKF;
+ /* ignore it! (what about audio data after it? it is
+ * handled by ignoring all 0ms frames, see below)
+ */
+ ret = RTMP_READ_IGNORE;
+ break;
+ }
+ }
+
+ /* hande FLV streams, even though the server resends the
+ * keyframe as an extra video packet it is also included
+ * in the first FLV stream chunk and we have to compare
+ * it and filter it out !!
+ */
+ if (packet.m_packetType == 0x16)
+ {
+ /* basically we have to find the keyframe with the
+ * correct TS being nResumeTS
+ */
+ unsigned int pos = 0;
+ uint32_t ts = 0;
+
+ while (pos + 11 < nPacketLen)
+ {
+ /* size without header (11) and prevTagSize (4) */
+ uint32_t dataSize =
+ AMF_DecodeInt24(packetBody + pos + 1);
+ ts = AMF_DecodeInt24(packetBody + pos + 4);
+ ts |= (packetBody[pos + 7] << 24);
+
+#ifdef _DEBUG
+ RTMP_Log(RTMP_LOGDEBUG,
+ "keyframe search: FLV Packet: type %02X, dataSize: %d, timeStamp: %d ms",
+ packetBody[pos], dataSize, ts);
+#endif
+ /* ok, is it a keyframe?:
+ * well doesn't work for audio!
+ */
+ if (packetBody[pos /*6928, test 0 */ ] ==
+ r->m_read.initialFrameType
+ /* && (packetBody[11]&0xf0) == 0x10 */ )
+ {
+ if (ts == r->m_read.nResumeTS)
+ {
+ RTMP_Log(RTMP_LOGDEBUG,
+ "Found keyframe with resume-keyframe timestamp!");
+ if (r->m_read.nInitialFrameSize != dataSize
+ || memcmp(r->m_read.initialFrame,
+ packetBody + pos + 11,
+ r->m_read.
+ nInitialFrameSize) != 0)
+ {
+ RTMP_Log(RTMP_LOGERROR,
+ "FLV Stream: Keyframe doesn't match!");
+ ret = RTMP_READ_ERROR;
+ break;
+ }
+ r->m_read.flags |= RTMP_READ_GOTFLVK;
+
+ /* skip this packet?
+ * check whether skippable:
+ */
+ if (pos + 11 + dataSize + 4 > nPacketLen)
+ {
+ RTMP_Log(RTMP_LOGWARNING,
+ "Non skipable packet since it doesn't end with chunk, stream corrupt!");
+ ret = RTMP_READ_ERROR;
+ break;
+ }
+ packetBody += (pos + 11 + dataSize + 4);
+ nPacketLen -= (pos + 11 + dataSize + 4);
+
+ goto stopKeyframeSearch;
+
+ }
+ else if (r->m_read.nResumeTS < ts)
+ {
+ /* the timestamp ts will only increase with
+ * further packets, wait for seek
+ */
+ goto stopKeyframeSearch;
+ }
+ }
+ pos += (11 + dataSize + 4);
+ }
+ if (ts < r->m_read.nResumeTS)
+ {
+ RTMP_Log(RTMP_LOGERROR,
+ "First packet does not contain keyframe, all "
+ "timestamps are smaller than the keyframe "
+ "timestamp; probably the resume seek failed?");
+ }
+ stopKeyframeSearch:
+ ;
+ if (!(r->m_read.flags & RTMP_READ_GOTFLVK))
+ {
+ RTMP_Log(RTMP_LOGERROR,
+ "Couldn't find the seeked keyframe in this chunk!");
+ ret = RTMP_READ_IGNORE;
+ break;
+ }
+ }
+ }
+ }
+
+ if (packet.m_nTimeStamp > 0
+ && (r->m_read.flags & (RTMP_READ_GOTKF|RTMP_READ_GOTFLVK)))
+ {
+ /* another problem is that the server can actually change from
+ * 09/08 video/audio packets to an FLV stream or vice versa and
+ * our keyframe check will prevent us from going along with the
+ * new stream if we resumed.
+ *
+ * in this case set the 'found keyframe' variables to true.
+ * We assume that if we found one keyframe somewhere and were
+ * already beyond TS > 0 we have written data to the output
+ * which means we can accept all forthcoming data including the
+ * change between 08/09 <-> FLV packets
+ */
+ r->m_read.flags |= (RTMP_READ_GOTKF|RTMP_READ_GOTFLVK);
+ }
+
+ /* skip till we find our keyframe
+ * (seeking might put us somewhere before it)
+ */
+ if (!(r->m_read.flags & RTMP_READ_GOTKF) &&
+ packet.m_packetType != 0x16)
+ {
+ RTMP_Log(RTMP_LOGWARNING,
+ "Stream does not start with requested frame, ignoring data... ");
+ r->m_read.nIgnoredFrameCounter++;
+ if (r->m_read.nIgnoredFrameCounter > MAX_IGNORED_FRAMES)
+ ret = RTMP_READ_ERROR; /* fatal error, couldn't continue stream */
+ else
+ ret = RTMP_READ_IGNORE;
+ break;
+ }
+ /* ok, do the same for FLV streams */
+ if (!(r->m_read.flags & RTMP_READ_GOTFLVK) &&
+ packet.m_packetType == 0x16)
+ {
+ RTMP_Log(RTMP_LOGWARNING,
+ "Stream does not start with requested FLV frame, ignoring data... ");
+ r->m_read.nIgnoredFlvFrameCounter++;
+ if (r->m_read.nIgnoredFlvFrameCounter > MAX_IGNORED_FRAMES)
+ ret = RTMP_READ_ERROR;
+ else
+ ret = RTMP_READ_IGNORE;
+ break;
+ }
+
+ /* we have to ignore the 0ms frames since these are the first
+ * keyframes; we've got these so don't mess around with multiple
+ * copies sent by the server to us! (if the keyframe is found at a
+ * later position there is only one copy and it will be ignored by
+ * the preceding if clause)
+ */
+ if (!(r->m_read.flags & RTMP_READ_NO_IGNORE) &&
+ packet.m_packetType != 0x16)
+ { /* exclude type 0x16 (FLV) since it can
+ * contain several FLV packets */
+ if (packet.m_nTimeStamp == 0)
+ {
+ ret = RTMP_READ_IGNORE;
+ break;
+ }
+ else
+ {
+ /* stop ignoring packets */
+ r->m_read.flags |= RTMP_READ_NO_IGNORE;
+ }
+ }
+ }
+
+ /* calculate packet size and allocate slop buffer if necessary */
+ size = nPacketLen +
+ ((packet.m_packetType == 0x08 || packet.m_packetType == 0x09
+ || packet.m_packetType == 0x12) ? 11 : 0) +
+ (packet.m_packetType != 0x16 ? 4 : 0);
+
+ if (size + 4 > buflen)
+ {
+ /* the extra 4 is for the case of an FLV stream without a last
+ * prevTagSize (we need extra 4 bytes to append it) */
+ r->m_read.buf = malloc(size + 4);
+ if (r->m_read.buf == 0)
+ {
+ RTMP_Log(RTMP_LOGERROR, "Couldn't allocate memory!");
+ ret = RTMP_READ_ERROR; /* fatal error */
+ break;
+ }
+ recopy = TRUE;
+ ptr = r->m_read.buf;
+ }
+ else
+ {
+ ptr = buf;
+ }
+ pend = ptr + size + 4;
+
+ /* use to return timestamp of last processed packet */
+
+ /* audio (0x08), video (0x09) or metadata (0x12) packets :
+ * construct 11 byte header then add rtmp packet's data */
+ if (packet.m_packetType == 0x08 || packet.m_packetType == 0x09
+ || packet.m_packetType == 0x12)
+ {
+ nTimeStamp = r->m_read.nResumeTS + packet.m_nTimeStamp;
+ prevTagSize = 11 + nPacketLen;
+
+ *ptr = packet.m_packetType;
+ ptr++;
+ ptr = AMF_EncodeInt24(ptr, pend, nPacketLen);
+
+#if 0
+ if(packet.m_packetType == 0x09) { /* video */
+
+ /* H264 fix: */
+ if((packetBody[0] & 0x0f) == 7) { /* CodecId = H264 */
+ uint8_t packetType = *(packetBody+1);
+
+ uint32_t ts = AMF_DecodeInt24(packetBody+2); /* composition time */
+ int32_t cts = (ts+0xff800000)^0xff800000;
+ RTMP_Log(RTMP_LOGDEBUG, "cts : %d\n", cts);
+
+ nTimeStamp -= cts;
+ /* get rid of the composition time */
+ CRTMP::EncodeInt24(packetBody+2, 0);
+ }
+ RTMP_Log(RTMP_LOGDEBUG, "VIDEO: nTimeStamp: 0x%08X (%d)\n", nTimeStamp, nTimeStamp);
+ }
+#endif
+
+ ptr = AMF_EncodeInt24(ptr, pend, nTimeStamp);
+ *ptr = (char)((nTimeStamp & 0xFF000000) >> 24);
+ ptr++;
+
+ /* stream id */
+ ptr = AMF_EncodeInt24(ptr, pend, 0);
+ }
+
+ memcpy(ptr, packetBody, nPacketLen);
+ len = nPacketLen;
+
+ /* correct tagSize and obtain timestamp if we have an FLV stream */
+ if (packet.m_packetType == 0x16)
+ {
+ unsigned int pos = 0;
+ int delta;
+
+ /* grab first timestamp and see if it needs fixing */
+ nTimeStamp = AMF_DecodeInt24(packetBody + 4);
+ nTimeStamp |= (packetBody[7] << 24);
+ delta = packet.m_nTimeStamp - nTimeStamp;
+
+ while (pos + 11 < nPacketLen)
+ {
+ /* size without header (11) and without prevTagSize (4) */
+ uint32_t dataSize = AMF_DecodeInt24(packetBody + pos + 1);
+ nTimeStamp = AMF_DecodeInt24(packetBody + pos + 4);
+ nTimeStamp |= (packetBody[pos + 7] << 24);
+
+ if (delta)
+ {
+ nTimeStamp += delta;
+ AMF_EncodeInt24(ptr+pos+4, pend, nTimeStamp);
+ ptr[pos+7] = nTimeStamp>>24;
+ }
+
+ /* set data type */
+ r->m_read.dataType |= (((*(packetBody + pos) == 0x08) << 2) |
+ (*(packetBody + pos) == 0x09));
+
+ if (pos + 11 + dataSize + 4 > nPacketLen)
+ {
+ if (pos + 11 + dataSize > nPacketLen)
+ {
+ RTMP_Log(RTMP_LOGERROR,
+ "Wrong data size (%lu), stream corrupted, aborting!",
+ dataSize);
+ ret = RTMP_READ_ERROR;
+ break;
+ }
+ RTMP_Log(RTMP_LOGWARNING, "No tagSize found, appending!");
+
+ /* we have to append a last tagSize! */
+ prevTagSize = dataSize + 11;
+ AMF_EncodeInt32(ptr + pos + 11 + dataSize, pend,
+ prevTagSize);
+ size += 4;
+ len += 4;
+ }
+ else
+ {
+ prevTagSize =
+ AMF_DecodeInt32(packetBody + pos + 11 + dataSize);
+
+#ifdef _DEBUG
+ RTMP_Log(RTMP_LOGDEBUG,
+ "FLV Packet: type %02X, dataSize: %lu, tagSize: %lu, timeStamp: %lu ms",
+ (unsigned char)packetBody[pos], dataSize, prevTagSize,
+ nTimeStamp);
+#endif
+
+ if (prevTagSize != (dataSize + 11))
+ {
+#ifdef _DEBUG
+ RTMP_Log(RTMP_LOGWARNING,
+ "Tag and data size are not consitent, writing tag size according to dataSize+11: %d",
+ dataSize + 11);
+#endif
+
+ prevTagSize = dataSize + 11;
+ AMF_EncodeInt32(ptr + pos + 11 + dataSize, pend,
+ prevTagSize);
+ }
+ }
+
+ pos += prevTagSize + 4; /*(11+dataSize+4); */
+ }
+ }
+ ptr += len;
+
+ if (packet.m_packetType != 0x16)
+ {
+ /* FLV tag packets contain their own prevTagSize */
+ AMF_EncodeInt32(ptr, pend, prevTagSize);
+ }
+
+ /* In non-live this nTimeStamp can contain an absolute TS.
+ * Update ext timestamp with this absolute offset in non-live mode
+ * otherwise report the relative one
+ */
+ /* RTMP_Log(RTMP_LOGDEBUG, "type: %02X, size: %d, pktTS: %dms, TS: %dms, bLiveStream: %d", packet.m_packetType, nPacketLen, packet.m_nTimeStamp, nTimeStamp, r->Link.lFlags & RTMP_LF_LIVE); */
+ r->m_read.timestamp = (r->Link.lFlags & RTMP_LF_LIVE) ? packet.m_nTimeStamp : nTimeStamp;
+
+ ret = size;
+ break;
+ }
+
+ if (rtnGetNextMediaPacket)
+ RTMPPacket_Free(&packet);
+
+ if (recopy)
+ {
+ len = ret > buflen ? buflen : ret;
+ memcpy(buf, r->m_read.buf, len);
+ r->m_read.bufpos = r->m_read.buf + len;
+ r->m_read.buflen = ret - len;
+ }
+ return ret;
+}
+
+static const char flvHeader[] = { 'F', 'L', 'V', 0x01,
+ 0x00, /* 0x04 == audio, 0x01 == video */
+ 0x00, 0x00, 0x00, 0x09,
+ 0x00, 0x00, 0x00, 0x00
+};
+
+#define HEADERBUF (128*1024)
+int
+RTMP_Read(RTMP *r, char *buf, int size)
+{
+ int nRead = 0, total = 0;
+
+ /* can't continue */
+fail:
+ switch (r->m_read.status) {
+ case RTMP_READ_EOF:
+ case RTMP_READ_COMPLETE:
+ return 0;
+ case RTMP_READ_ERROR: /* corrupted stream, resume failed */
+ SetSockError(EINVAL);
+ return -1;
+ default:
+ break;
+ }
+
+ /* first time thru */
+ if (!(r->m_read.flags & RTMP_READ_HEADER))
+ {
+ if (!(r->m_read.flags & RTMP_READ_RESUME))
+ {
+ char *mybuf = malloc(HEADERBUF), *end = mybuf + HEADERBUF;
+ int cnt = 0;
+ r->m_read.buf = mybuf;
+ r->m_read.buflen = HEADERBUF;
+
+ memcpy(mybuf, flvHeader, sizeof(flvHeader));
+ r->m_read.buf += sizeof(flvHeader);
+ r->m_read.buflen -= sizeof(flvHeader);
+
+ while (r->m_read.timestamp == 0)
+ {
+ nRead = Read_1_Packet(r, r->m_read.buf, r->m_read.buflen);
+ if (nRead < 0)
+ {
+ free(mybuf);
+ r->m_read.buf = NULL;
+ r->m_read.buflen = 0;
+ r->m_read.status = nRead;
+ goto fail;
+ }
+ /* buffer overflow, fix buffer and give up */
+ if (r->m_read.buf < mybuf || r->m_read.buf > end) {
+ mybuf = realloc(mybuf, cnt + nRead);
+ memcpy(mybuf+cnt, r->m_read.buf, nRead);
+ r->m_read.buf = mybuf+cnt+nRead;
+ break;
+ }
+ cnt += nRead;
+ r->m_read.buf += nRead;
+ r->m_read.buflen -= nRead;
+ if (r->m_read.dataType == 5)
+ break;
+ }
+ mybuf[4] = r->m_read.dataType;
+ r->m_read.buflen = r->m_read.buf - mybuf;
+ r->m_read.buf = mybuf;
+ r->m_read.bufpos = mybuf;
+ }
+ r->m_read.flags |= RTMP_READ_HEADER;
+ }
+
+ if ((r->m_read.flags & RTMP_READ_SEEKING) && r->m_read.buf)
+ {
+ /* drop whatever's here */
+ free(r->m_read.buf);
+ r->m_read.buf = NULL;
+ r->m_read.bufpos = NULL;
+ r->m_read.buflen = 0;
+ }
+
+ /* If there's leftover data buffered, use it up */
+ if (r->m_read.buf)
+ {
+ nRead = r->m_read.buflen;
+ if (nRead > size)
+ nRead = size;
+ memcpy(buf, r->m_read.bufpos, nRead);
+ r->m_read.buflen -= nRead;
+ if (!r->m_read.buflen)
+ {
+ free(r->m_read.buf);
+ r->m_read.buf = NULL;
+ r->m_read.bufpos = NULL;
+ }
+ else
+ {
+ r->m_read.bufpos += nRead;
+ }
+ buf += nRead;
+ total += nRead;
+ size -= nRead;
+ }
+
+ while (size > 0 && (nRead = Read_1_Packet(r, buf, size)) >= 0)
+ {
+ if (!nRead) continue;
+ buf += nRead;
+ total += nRead;
+ size -= nRead;
+ break;
+ }
+ if (nRead < 0)
+ r->m_read.status = nRead;
+
+ if (size < 0)
+ total += size;
+ return total;
+}
+
+static const AVal av_setDataFrame = AVC("@setDataFrame");
+
+int
+RTMP_Write(RTMP *r, const char *buf, int size)
+{
+ RTMPPacket *pkt = &r->m_write;
+ char *pend, *enc;
+ int s2 = size, ret, num;
+
+ pkt->m_nChannel = 0x04; /* source channel */
+ pkt->m_nInfoField2 = r->m_stream_id;
+
+ while (s2)
+ {
+ if (!pkt->m_nBytesRead)
+ {
+ if (size < 11) {
+ /* FLV pkt too small */
+ return 0;
+ }
+
+ if (buf[0] == 'F' && buf[1] == 'L' && buf[2] == 'V')
+ {
+ buf += 13;
+ s2 -= 13;
+ }
+
+ pkt->m_packetType = *buf++;
+ pkt->m_nBodySize = AMF_DecodeInt24(buf);
+ buf += 3;
+ pkt->m_nTimeStamp = AMF_DecodeInt24(buf);
+ buf += 3;
+ pkt->m_nTimeStamp |= *buf++ << 24;
+ buf += 3;
+ s2 -= 11;
+
+ if (((pkt->m_packetType == 0x08 || pkt->m_packetType == 0x09) &&
+ !pkt->m_nTimeStamp) || pkt->m_packetType == 0x12)
+ {
+ pkt->m_headerType = RTMP_PACKET_SIZE_LARGE;
+ if (pkt->m_packetType == 0x12)
+ pkt->m_nBodySize += 16;
+ }
+ else
+ {
+ pkt->m_headerType = RTMP_PACKET_SIZE_MEDIUM;
+ }
+
+ if (!RTMPPacket_Alloc(pkt, pkt->m_nBodySize))
+ {
+ RTMP_Log(RTMP_LOGDEBUG, "%s, failed to allocate packet", __FUNCTION__);
+ return FALSE;
+ }
+ enc = pkt->m_body;
+ pend = enc + pkt->m_nBodySize;
+ if (pkt->m_packetType == 0x12)
+ {
+ enc = AMF_EncodeString(enc, pend, &av_setDataFrame);
+ pkt->m_nBytesRead = enc - pkt->m_body;
+ }
+ }
+ else
+ {
+ enc = pkt->m_body + pkt->m_nBytesRead;
+ }
+ num = pkt->m_nBodySize - pkt->m_nBytesRead;
+ if (num > s2)
+ num = s2;
+ memcpy(enc, buf, num);
+ pkt->m_nBytesRead += num;
+ s2 -= num;
+ buf += num;
+ if (pkt->m_nBytesRead == pkt->m_nBodySize)
+ {
+ ret = RTMP_SendPacket(r, pkt, FALSE);
+ RTMPPacket_Free(pkt);
+ pkt->m_nBytesRead = 0;
+ if (!ret)
+ return -1;
+ buf += 4;
+ s2 -= 4;
+ if (s2 < 0)
+ break;
+ }
+ }
+ return size+s2;
+}
diff --git a/Live/src/main/cpp/include/rtmp/rtmp.h b/Live/src/main/cpp/rtmp/rtmp.h
similarity index 100%
rename from Live/src/main/cpp/include/rtmp/rtmp.h
rename to Live/src/main/cpp/rtmp/rtmp.h
diff --git a/Live/src/main/cpp/rtmp/rtmp_sys.h b/Live/src/main/cpp/rtmp/rtmp_sys.h
new file mode 100644
index 00000000..0874cbe6
--- /dev/null
+++ b/Live/src/main/cpp/rtmp/rtmp_sys.h
@@ -0,0 +1,112 @@
+#ifndef __RTMP_SYS_H__
+#define __RTMP_SYS_H__
+/*
+ * Copyright (C) 2010 Howard Chu
+ *
+ * This file is part of librtmp.
+ *
+ * librtmp is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1,
+ * or (at your option) any later version.
+ *
+ * librtmp is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with librtmp see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/lgpl.html
+ */
+
+#ifdef _WIN32
+
+#ifdef _XBOX
+#include
+#include
+#define snprintf _snprintf
+#define strcasecmp stricmp
+#define strncasecmp strnicmp
+#define vsnprintf _vsnprintf
+
+#else /* !_XBOX */
+#include
+#include
+#endif
+
+#define GetSockError() WSAGetLastError()
+#define SetSockError(e) WSASetLastError(e)
+#define setsockopt(a,b,c,d,e) (setsockopt)(a,b,c,(const char *)d,(int)e)
+#define EWOULDBLOCK WSAETIMEDOUT /* we don't use nonblocking, but we do use timeouts */
+#define sleep(n) Sleep(n*1000)
+#define msleep(n) Sleep(n)
+#define SET_RCVTIMEO(tv,s) int tv = s*1000
+#else /* !_WIN32 */
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#define GetSockError() errno
+#define SetSockError(e) errno = e
+#undef closesocket
+#define closesocket(s) close(s)
+#define msleep(n) usleep(n*1000)
+#define SET_RCVTIMEO(tv,s) struct timeval tv = {s,0}
+#endif
+
+#include "rtmp.h"
+
+#ifdef USE_POLARSSL
+#include
+#include
+#include
+typedef struct tls_ctx {
+ havege_state hs;
+ ssl_session ssn;
+} tls_ctx;
+#define TLS_CTX tls_ctx *
+#define TLS_client(ctx,s) s = malloc(sizeof(ssl_context)); ssl_init(s);\
+ ssl_set_endpoint(s, SSL_IS_CLIENT); ssl_set_authmode(s, SSL_VERIFY_NONE);\
+ ssl_set_rng(s, havege_rand, &ctx->hs); ssl_set_ciphers(s, ssl_default_ciphers);\
+ ssl_set_session(s, 1, 600, &ctx->ssn)
+#define TLS_setfd(s,fd) ssl_set_bio(s, net_recv, &fd, net_send, &fd)
+#define TLS_connect(s) ssl_handshake(s)
+#define TLS_read(s,b,l) ssl_read(s,(unsigned char *)b,l)
+#define TLS_write(s,b,l) ssl_write(s,(unsigned char *)b,l)
+#define TLS_shutdown(s) ssl_close_notify(s)
+#define TLS_close(s) ssl_free(s); free(s)
+
+#elif defined(USE_GNUTLS)
+#include
+typedef struct tls_ctx {
+ gnutls_certificate_credentials_t cred;
+ gnutls_priority_t prios;
+} tls_ctx;
+#define TLS_CTX tls_ctx *
+#define TLS_client(ctx,s) gnutls_init((gnutls_session_t *)(&s), GNUTLS_CLIENT); gnutls_priority_set(s, ctx->prios); gnutls_credentials_set(s, GNUTLS_CRD_CERTIFICATE, ctx->cred)
+#define TLS_setfd(s,fd) gnutls_transport_set_ptr(s, (gnutls_transport_ptr_t)(long)fd)
+#define TLS_connect(s) gnutls_handshake(s)
+#define TLS_read(s,b,l) gnutls_record_recv(s,b,l)
+#define TLS_write(s,b,l) gnutls_record_send(s,b,l)
+#define TLS_shutdown(s) gnutls_bye(s, GNUTLS_SHUT_RDWR)
+#define TLS_close(s) gnutls_deinit(s)
+
+#else /* USE_OPENSSL */
+#define TLS_CTX SSL_CTX *
+#define TLS_client(ctx,s) s = SSL_new(ctx)
+#define TLS_setfd(s,fd) SSL_set_fd(s,fd)
+#define TLS_connect(s) SSL_connect(s)
+#define TLS_read(s,b,l) SSL_read(s,b,l)
+#define TLS_write(s,b,l) SSL_write(s,b,l)
+#define TLS_shutdown(s) SSL_shutdown(s)
+#define TLS_close(s) SSL_free(s)
+
+#endif
+#endif
diff --git a/Live/src/main/java/com/frank/live/LiveActivity.java b/Live/src/main/java/com/frank/live/LiveActivity.java
deleted file mode 100644
index 53be202e..00000000
--- a/Live/src/main/java/com/frank/live/LiveActivity.java
+++ /dev/null
@@ -1,129 +0,0 @@
-package com.frank.live;
-
-import android.Manifest;
-import android.annotation.SuppressLint;
-import android.annotation.TargetApi;
-import android.hardware.Camera;
-import android.media.AudioFormat;
-import android.os.Build;
-import android.os.Handler;
-import android.os.Message;
-import android.support.annotation.NonNull;
-import android.support.v7.app.AppCompatActivity;
-import android.os.Bundle;
-import android.text.TextUtils;
-import android.util.Log;
-import android.view.SurfaceHolder;
-import android.view.SurfaceView;
-import android.view.View;
-import android.widget.CompoundButton;
-import android.widget.Toast;
-import android.widget.ToggleButton;
-import com.frank.live.Push.LivePusher;
-import com.frank.live.listener.LiveStateChangeListener;
-import com.frank.live.param.AudioParam;
-import com.frank.live.param.VideoParam;
-
-/**
- * h264与rtmp实时推流直播
- * Created by frank on 2018/1/28.
- */
-
-public class LiveActivity extends AppCompatActivity implements View.OnClickListener, CompoundButton.OnCheckedChangeListener, LiveStateChangeListener {
-
- private final static String TAG = LiveActivity.class.getSimpleName();
- private final static int CODE_CAMERA_RECORD = 0x0001;
- private final static String[] permissions = new String[]{Manifest.permission.CAMERA, Manifest.permission.RECORD_AUDIO};
- private final static String LIVE_URL = "rtmp://192.168.8.115/live/stream";
- private final static int MSG_ERROR = 100;
- private SurfaceHolder surfaceHolder;
- private LivePusher livePusher;
- @SuppressLint("HandlerLeak")
- private Handler mHandler = new Handler(){
- @Override
- public void handleMessage(Message msg) {
- super.handleMessage(msg);
- if(msg.what == MSG_ERROR){
- String errMsg = (String)msg.obj;
- if(!TextUtils.isEmpty(errMsg)){
- Toast.makeText(LiveActivity.this, errMsg, Toast.LENGTH_SHORT).show();
- }
- }
- }
- };
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_live);
-
- initView();
- requirePermission();
- initPusher();
- }
-
- private void initView(){
- findViewById(R.id.btn_swap).setOnClickListener(this);
- ((ToggleButton)findViewById(R.id.btn_live)).setOnCheckedChangeListener(this);
- SurfaceView surface_camera = (SurfaceView) findViewById(R.id.surface_camera);
- surfaceHolder = surface_camera.getHolder();
- }
-
- private void initPusher() {
- int width = 640;//分辨率设置很重要
- int height = 480;
- int videoBitRate = 400;//kb/s jason-->480kb
- int videoFrameRate = 25;//fps
- VideoParam videoParam = new VideoParam(width, height,
- Camera.CameraInfo.CAMERA_FACING_BACK, videoBitRate, videoFrameRate);
- int sampleRate = 44100;//采样率:Hz
- int channelConfig = AudioFormat.CHANNEL_IN_STEREO;//立体声道
- int audioFormat = AudioFormat.ENCODING_PCM_16BIT;//pcm16位
- int numChannels = 2;//声道数
- AudioParam audioParam = new AudioParam(sampleRate, channelConfig, audioFormat, numChannels);
- livePusher = new LivePusher(surfaceHolder, videoParam, audioParam);
- }
-
- @Override
- public void onClick(View v) {
- if(v.getId() == R.id.btn_swap){
- livePusher.switchCamera();
- }
- }
-
- @Override
- public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
- if(isChecked){
- livePusher.startPush(LIVE_URL, this);
- }else {
- livePusher.stopPush();
- }
- }
-
- @Override
- public void onError(String msg) {
- Log.e(TAG, "errMsg=" + msg);
- mHandler.obtainMessage(MSG_ERROR, msg).sendToTarget();
- }
-
- @TargetApi(Build.VERSION_CODES.M)
- private void requirePermission(){
- requestPermissions(permissions, CODE_CAMERA_RECORD);
- }
-
- @Override
- public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
- super.onRequestPermissionsResult(requestCode, permissions, grantResults);
- if(permissions.length > 0 && grantResults.length == permissions.length){
- for(int i=0; i 0){
-// Log.i("AudioPusher", "is recording...");
- liveUtil.pushAudioData(audioBuffer, length);
- }
- }
- }
- audioRecord.stop();
- }
- }
-
- /**
- * 设置静音
- * @param isMute 是否静音
- */
- void setMute(boolean isMute){
- this.isMute = isMute;
- }
-
-}
diff --git a/Live/src/main/java/com/frank/live/Push/LivePusher.java b/Live/src/main/java/com/frank/live/Push/LivePusher.java
deleted file mode 100644
index c4a686ba..00000000
--- a/Live/src/main/java/com/frank/live/Push/LivePusher.java
+++ /dev/null
@@ -1,71 +0,0 @@
-package com.frank.live.Push;
-
-import android.util.Log;
-import android.view.SurfaceHolder;
-import com.frank.live.LiveUtil;
-import com.frank.live.listener.LiveStateChangeListener;
-import com.frank.live.param.AudioParam;
-import com.frank.live.param.VideoParam;
-
-/**
- * 音视频推流
- * Created by frank on 2018/1/28.
- */
-
-public class LivePusher {
-
- private VideoPusher videoPusher;
- private AudioPusher audioPusher;
- private LiveUtil liveUtil;
-
- public LivePusher(SurfaceHolder surfaceHolder, VideoParam videoParam, AudioParam audioParam){
- liveUtil = new LiveUtil();
- videoPusher = new VideoPusher(surfaceHolder, videoParam, liveUtil);
- audioPusher = new AudioPusher(audioParam, liveUtil);
- }
-
- /**
- * 开始推流
- */
- public void startPush(String liveUrl, LiveStateChangeListener liveStateChangeListener){
- videoPusher.startPush();
- audioPusher.startPush();
- liveUtil.setOnLiveStateChangeListener(liveStateChangeListener);
- int result = liveUtil.startPush(liveUrl);
- Log.i("LivePusher", "startPush=" + (result == 0 ? "success" : "fail"));
- }
-
- /**
- * 停止推流
- */
- public void stopPush(){
- videoPusher.stopPush();
- audioPusher.stopPush();
- liveUtil.stopPush();
- }
-
- /**
- * 切换摄像头
- */
- public void switchCamera(){
- videoPusher.switchCamera();
- }
-
- /**
- * 释放资源
- */
- public void release(){
- videoPusher.release();
- audioPusher.release();
- liveUtil.release();
- }
-
- /**
- * 设置静音
- * @param isMute 是否静音
- */
- public void setMute(boolean isMute){
- audioPusher.setMute(isMute);
- }
-
-}
diff --git a/Live/src/main/java/com/frank/live/Push/Pusher.java b/Live/src/main/java/com/frank/live/Push/Pusher.java
deleted file mode 100644
index 73b6dfd5..00000000
--- a/Live/src/main/java/com/frank/live/Push/Pusher.java
+++ /dev/null
@@ -1,12 +0,0 @@
-package com.frank.live.Push;
-
-/**
- *
- * Created by frank on 2018/1/28.
- */
-
-public abstract class Pusher {
- public abstract void startPush();
- public abstract void stopPush();
- public abstract void release();
-}
diff --git a/Live/src/main/java/com/frank/live/Push/VideoPusher.java b/Live/src/main/java/com/frank/live/Push/VideoPusher.java
deleted file mode 100644
index 7ff7a3b2..00000000
--- a/Live/src/main/java/com/frank/live/Push/VideoPusher.java
+++ /dev/null
@@ -1,124 +0,0 @@
-package com.frank.live.Push;
-
-import android.graphics.ImageFormat;
-import android.hardware.Camera;
-import android.util.Log;
-import android.view.SurfaceHolder;
-
-import com.frank.live.LiveUtil;
-import com.frank.live.param.VideoParam;
-import java.io.IOException;
-
-/**
- * 视频推流
- * Created by frank on 2018/1/28.
- */
-
-public class VideoPusher extends Pusher implements SurfaceHolder.Callback, Camera.PreviewCallback {
-
- private SurfaceHolder surfaceHolder;
- private VideoParam videoParam;
- private Camera camera;
- private boolean isPushing;
- private byte[] previewBuffer;
- private LiveUtil liveUtil;
-
- VideoPusher(SurfaceHolder surfaceHolder, VideoParam videoParam, LiveUtil liveUtil){
- this.surfaceHolder = surfaceHolder;
- this.videoParam = videoParam;
- this.liveUtil = liveUtil;
- surfaceHolder.addCallback(this);
- liveUtil.setVideoParams(videoParam.getWidth(), videoParam.getHeight(),
- videoParam.getBitRate(), videoParam.getFrameRate());
- }
-
-
- @Override
- public void startPush() {
- isPushing = true;
- }
-
- @Override
- public void stopPush() {
- isPushing = false;
- }
-
- @Override
- public void release() {
- stopPush();
- stopPreview();
- }
-
- @Override
- public void surfaceCreated(SurfaceHolder holder) {
- startPreview();
- }
-
- @Override
- public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
-
- }
-
- @Override
- public void surfaceDestroyed(SurfaceHolder holder) {
- stopPreview();
- }
-
- /**
- * 开始预览
- */
- private void startPreview() {
- try {
- camera = Camera.open(videoParam.getCameraId());
- Camera.Parameters parameters = camera.getParameters();
- parameters.setPreviewFormat(ImageFormat.NV21);
- parameters.setPictureSize(videoParam.getWidth(), videoParam.getHeight());
- camera.setParameters(parameters);
- camera.setDisplayOrientation(0);//竖屏是90°
- camera.setPreviewDisplay(surfaceHolder);
- camera.startPreview();
- previewBuffer = new byte[videoParam.getWidth() * videoParam.getHeight() * 4];
- camera.addCallbackBuffer(previewBuffer);
- camera.setPreviewCallbackWithBuffer(this);
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
-
- /**
- * 停止预览
- */
- private void stopPreview() {
- if(camera != null){
- camera.stopPreview();
- camera.setPreviewCallback(null);
- camera.release();
- camera = null;
- }
- }
-
- /**
- * 切换摄像头
- */
- void switchCamera(){
-
- if(videoParam.getCameraId() == Camera.CameraInfo.CAMERA_FACING_BACK){
- videoParam.setCameraId(Camera.CameraInfo.CAMERA_FACING_FRONT);
- }else {
- videoParam.setCameraId(Camera.CameraInfo.CAMERA_FACING_BACK);
- }
- //重新开始推流
- stopPreview();
- startPreview();
- }
-
- @Override
- public void onPreviewFrame(byte[] data, Camera camera) {
- camera.addCallbackBuffer(previewBuffer);
- if(isPushing){
-// Log.i("VideoPusher", "isPushing...");
- liveUtil.pushVideoData(data);
- }
- }
-
-}
diff --git a/Live/src/main/java/com/frank/live/PushActivity.java b/Live/src/main/java/com/frank/live/PushActivity.java
deleted file mode 100644
index 6baf7bd0..00000000
--- a/Live/src/main/java/com/frank/live/PushActivity.java
+++ /dev/null
@@ -1,309 +0,0 @@
-
-package com.frank.live;
-
-import android.Manifest;
-import android.annotation.TargetApi;
-import android.app.Activity;
-import android.content.res.Configuration;
-import android.graphics.Bitmap;
-import android.hardware.Camera;
-import android.os.Bundle;
-import android.os.Environment;
-import android.support.annotation.NonNull;
-import android.util.Log;
-import android.view.SurfaceHolder;
-import android.view.SurfaceHolder.Callback;
-import android.view.View;
-import android.view.View.OnClickListener;
-import android.view.WindowManager;
-import android.widget.AdapterView;
-import android.widget.AdapterView.OnItemSelectedListener;
-import android.widget.ArrayAdapter;
-import android.widget.Button;
-import android.widget.ImageView;
-import android.widget.Spinner;
-
-import com.frank.live.view.SmartCameraView;
-import com.seu.magicfilter.utils.MagicFilterType;
-
-import java.io.File;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.nio.ByteBuffer;
-
-public class PushActivity extends Activity implements Callback {
- private static String TAG = PushActivity.class.getSimpleName();
-
- private SmartCameraView mSmartCameraView;
-
-// MagicFilterType magicType = MagicFilterType.SUNRISE;
-
- private Button btnMute;
-
- private boolean isStart = false;
-
- private boolean is_mute = false;
-
- private int mDegree;
-
- private Spinner beautyTypeSelector;
-
- private ImageView img_photo;
- //拍照
- private boolean takePhoto;
-
- private final static int videoWidth = 640;
- private final static int videoHeight = 360;
- private final static String[] permissions = new String[]{Manifest.permission.CAMERA};
- private final static int CODE_CAMERA = 1001;
-
- private final static String[] beautySelector = new String[]{"美颜", "冷酷", "日出","素描","白猫", "浪漫", "原图"};
-
- @Override
- public void onCreate(Bundle savedInstanceState) {
-
- super.onCreate(savedInstanceState);
-
- requestPermissions();
-
- getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
-
- setContentView(R.layout.activity_push);
-
- initView();
- initListener();
- }
-
- @TargetApi(23)
- private void requestPermissions(){
- requestPermissions(permissions, CODE_CAMERA);
- }
-
- private void initView(){
- //SurfaceView
- mSmartCameraView = (SmartCameraView) findViewById(R.id.gl_surfaceview);
- //美颜类型
- beautyTypeSelector = (Spinner) findViewById(R.id.beauty_type_selctor);
- //静音
- btnMute = (Button) findViewById(R.id.button_mute);
- //拍照
- img_photo = (ImageView) findViewById(R.id.img_photo);
- }
-
- private void initListener(){
-
- ArrayAdapter adapterBeautyType = new ArrayAdapter<>(this,
- android.R.layout.simple_spinner_item, beautySelector);
- adapterBeautyType.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
- beautyTypeSelector.setAdapter(adapterBeautyType);
- beautyTypeSelector.setOnItemSelectedListener(new OnItemSelectedListener() {
- @Override
- public void onItemSelected(AdapterView> parent, View view, int position, long id) {
-
- switch (position){
- case 0:
- switchCameraFilter(MagicFilterType.BEAUTY);
- break;
- case 1:
- switchCameraFilter(MagicFilterType.COOL);
- break;
- case 2:
- switchCameraFilter(MagicFilterType.SUNRISE);
- break;
- case 3:
- switchCameraFilter(MagicFilterType.SKETCH);
- break;
- case 4:
- switchCameraFilter(MagicFilterType.WHITECAT);
- break;
- case 5:
- switchCameraFilter(MagicFilterType.ROMANCE);
- break;
- default:
- switchCameraFilter(MagicFilterType.NONE);
- break;
- }
- }
- @Override
- public void onNothingSelected(AdapterView> parent) {
-
- }
- });
-
- btnMute.setOnClickListener(new OnClickListener() {
- @Override
- public void onClick(View view) {
- is_mute = !is_mute;
-
- if ( is_mute )
- btnMute.setText("取消静音");
- else
- btnMute.setText("静音");
- }
- });
-
- //预览数据回调(RGBA格式)
- mSmartCameraView.setPreviewCallback(new SmartCameraView.PreviewCallback() {
- @Override
- public void onGetRgbaFrame(byte[] data, int width, int height) {
-
- if(takePhoto){
- takePhoto = false;
- Log.i(TAG, "takePhoto...");
- doTakePhoto(data, width, height);
- }
-
- }
- });
-
- img_photo.setOnClickListener(new OnClickListener() {
- @Override
- public void onClick(View view) {
- takePhoto = true;
- }
- });
-
- }
-
- private void switchCameraFilter(MagicFilterType type) {
- mSmartCameraView.setFilter(type);
- }
-
- /**
- * 拍照
- * @param data 预览数据
- * @param width 图片宽度
- * @param height 图片高度
- */
- private void doTakePhoto(byte[] data, int width, int height){
- Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
- ByteBuffer buffer = ByteBuffer.wrap(data);
- bitmap.copyPixelsFromBuffer(buffer);
-
- Log.i(TAG, "doTakePhoto...");
- FileOutputStream fileOutputStream = null;
- String PATH = Environment.getExternalStorageDirectory().getPath();
- String filePath = PATH + File.separator + "hello_openGL" + ".jpg";
- try {
- fileOutputStream = new FileOutputStream(filePath);
- bitmap.compress(Bitmap.CompressFormat.JPEG, 100, fileOutputStream);
- fileOutputStream.flush();
- } catch (IOException e) {
- e.printStackTrace();
- Log.e(TAG, "doTakePhoto error=" + e.toString());
- }finally {
- if(fileOutputStream != null){
- try {
- fileOutputStream.close();
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
- }
- }
-
- @Override
- public void surfaceCreated(SurfaceHolder holder) {
- Log.i(TAG, "surfaceCreated..");
- }
-
- @Override
- public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
- Log.i(TAG, "surfaceChanged..");
- }
-
- @Override
- public void surfaceDestroyed(SurfaceHolder holder) {
- // TODO Auto-generated method stub
- Log.i(TAG, "Surface Destroyed");
- }
-
- public void onConfigurationChanged(Configuration newConfig) {
- try {
- super.onConfigurationChanged(newConfig);
- Log.i(TAG, "onConfigurationChanged, start:" + isStart);
-
- setCameraDisplayOrientation(this, getCameraId());
-
- mSmartCameraView.setPreviewOrientation(newConfig.orientation, mDegree);
-
- } catch (Exception ex) {
- Log.e(TAG, "error="+ex.toString());
- }
- }
-
- private int getCameraId() {
- return mSmartCameraView.getCameraId();
- }
-
- public void setPreviewResolution(int width, int height) {
- mSmartCameraView.setPreviewResolution(width, height);
- }
-
- private void setCameraDisplayOrientation (Activity activity, int cameraId) {
- Camera.CameraInfo info = new Camera.CameraInfo();
- Camera.getCameraInfo (cameraId , info);
- int rotation = activity.getWindowManager ().getDefaultDisplay ().getRotation ();
- int degrees = 0;
- switch (rotation) {
- case 0:
- degrees = 0;
- break;
- case 1:
- degrees = 90;
- break;
- case 2:
- degrees = 180;
- break;
- case 3:
- degrees = 270;
- break;
- }
- int result;
- if (info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {
- result = (info.orientation + degrees) % 360;
- result = (360 - result) % 360;
- } else {
- // back-facing
- result = ( info.orientation - degrees + 360) % 360;
- }
-
- Log.i(TAG, "curDegree: "+ result);
-
- mDegree = result;
- }
-
- @Override
- protected void onDestroy(){
- Log.i(TAG, "activity destory!");
-
- if ( isStart ) {
- isStart = false;
- if(mSmartCameraView != null)
- {
- mSmartCameraView.stopCamera();
- }
-
- Log.i(TAG, "onDestroy StopPublish");
- }
-
- super.onDestroy();
- finish();
- System.exit(0);
- }
-
- @Override
- public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
- super.onRequestPermissionsResult(requestCode, permissions, grantResults);
- if(permissions.length > 0 && grantResults.length > 0){
- Log.i(TAG, "permission=" + permissions[0] + "----grantResult=" + grantResults[0]);
-
- setPreviewResolution(videoWidth, videoHeight);
-
- if (!mSmartCameraView.startCamera()) {
- Log.e(TAG, "startCamera error...");
- }
- }
- }
-
-}
\ No newline at end of file
diff --git a/Live/src/main/java/com/frank/live/camera/Camera2Helper.java b/Live/src/main/java/com/frank/live/camera/Camera2Helper.java
new file mode 100644
index 00000000..ac7fdb28
--- /dev/null
+++ b/Live/src/main/java/com/frank/live/camera/Camera2Helper.java
@@ -0,0 +1,611 @@
+package com.frank.live.camera;
+
+import android.Manifest;
+import android.annotation.TargetApi;
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.graphics.ImageFormat;
+import android.graphics.Matrix;
+import android.graphics.Point;
+import android.graphics.RectF;
+import android.graphics.SurfaceTexture;
+import android.hardware.camera2.CameraAccessException;
+import android.hardware.camera2.CameraCaptureSession;
+import android.hardware.camera2.CameraCharacteristics;
+import android.hardware.camera2.CameraDevice;
+import android.hardware.camera2.CameraManager;
+import android.hardware.camera2.CaptureRequest;
+import android.hardware.camera2.params.StreamConfigurationMap;
+import android.media.Image;
+import android.media.ImageReader;
+import android.os.Build;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.util.Log;
+import android.util.Size;
+import android.view.Surface;
+import android.view.TextureView;
+
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.concurrent.Semaphore;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.locks.ReentrantLock;
+
+import androidx.annotation.NonNull;
+
+import com.frank.live.util.YUVUtil;
+
+/**
+ * Camera2: open, preview and close
+ * Created by frank on 2019/12/18.
+ */
+@TargetApi(21)
+public class Camera2Helper {
+
+ private static final String TAG = Camera2Helper.class.getSimpleName();
+
+ public static final String CAMERA_ID_FRONT = "1";
+ public static final String CAMERA_ID_BACK = "0";
+
+ private Context context;
+ private String mCameraId;
+ private String specificCameraId;
+ private TextureView mTextureView;
+ private final int rotation;
+ private final Point previewViewSize;
+ private Camera2Listener camera2Listener;
+ /**
+ * A {@link CameraCaptureSession } for camera preview.
+ */
+ private CameraCaptureSession mCaptureSession;
+
+ /**
+ * A reference to the opened {@link CameraDevice}.
+ */
+ private CameraDevice mCameraDevice;
+
+ private Size mPreviewSize;
+
+ private int rotateDegree = 0;
+
+ private Camera2Helper(Builder builder) {
+ mTextureView = builder.previewDisplayView;
+ specificCameraId = builder.specificCameraId;
+ camera2Listener = builder.camera2Listener;
+ rotation = builder.rotation;
+ rotateDegree = builder.rotateDegree;
+ previewViewSize = builder.previewViewSize;
+ context = builder.context;
+ }
+
+ public void switchCamera() {
+ if (CAMERA_ID_BACK.equals(mCameraId)) {
+ specificCameraId = CAMERA_ID_FRONT;
+ } else if (CAMERA_ID_FRONT.equals(mCameraId)) {
+ specificCameraId = CAMERA_ID_BACK;
+ }
+ stop();
+ start();
+ }
+
+ private int getCameraOrientation(int rotation, String cameraId) {
+ int degree = rotation * 90;
+ switch (rotation) {
+ case Surface.ROTATION_0:
+ degree = 0;
+ break;
+ case Surface.ROTATION_90:
+ degree = 90;
+ break;
+ case Surface.ROTATION_180:
+ degree = 180;
+ break;
+ case Surface.ROTATION_270:
+ degree = 270;
+ break;
+ default:
+ break;
+ }
+ int result;
+ if (CAMERA_ID_FRONT.equals(cameraId)) {
+ result = (mSensorOrientation + degree) % 360;
+ result = (360 - result) % 360;
+ } else {
+ result = (mSensorOrientation - degree + 360) % 360;
+ }
+ Log.i(TAG, "getCameraOrientation, result=" + result);
+ return result;
+ }
+
+ private final TextureView.SurfaceTextureListener mSurfaceTextureListener
+ = new TextureView.SurfaceTextureListener() {
+
+ @Override
+ public void onSurfaceTextureAvailable(SurfaceTexture texture, int width, int height) {
+ Log.i(TAG, "onSurfaceTextureAvailable...");
+ openCamera();
+ }
+
+ @Override
+ public void onSurfaceTextureSizeChanged(SurfaceTexture texture, int width, int height) {
+ Log.i(TAG, "onSurfaceTextureSizeChanged, width=" + width + "--height=" + height);
+ configureTransform(width, height);
+ }
+
+ @Override
+ public boolean onSurfaceTextureDestroyed(SurfaceTexture texture) {
+ Log.i(TAG, "onSurfaceTextureDestroyed...");
+ return true;
+ }
+
+ @Override
+ public void onSurfaceTextureUpdated(SurfaceTexture texture) {
+ }
+
+ };
+
+ private final CameraDevice.StateCallback mDeviceStateCallback = new CameraDevice.StateCallback() {
+
+ @Override
+ public void onOpened(@NonNull CameraDevice cameraDevice) {
+ Log.i(TAG, "onOpened: ");
+ mCameraOpenCloseLock.release();
+ mCameraDevice = cameraDevice;
+ createCameraPreviewSession();
+ if (camera2Listener != null) {
+ camera2Listener.onCameraOpened(mPreviewSize, getCameraOrientation(rotation, mCameraId));
+ }
+ }
+
+ @Override
+ public void onDisconnected(@NonNull CameraDevice cameraDevice) {
+ Log.i(TAG, "onDisconnected: ");
+ mCameraOpenCloseLock.release();
+ cameraDevice.close();
+ mCameraDevice = null;
+ if (camera2Listener != null) {
+ camera2Listener.onCameraClosed();
+ }
+ }
+
+ @Override
+ public void onError(@NonNull CameraDevice cameraDevice, int error) {
+ Log.i(TAG, "onError: ");
+ mCameraOpenCloseLock.release();
+ cameraDevice.close();
+ mCameraDevice = null;
+
+ if (camera2Listener != null) {
+ camera2Listener.onCameraError(new Exception("error occurred, code is " + error));
+ }
+ }
+
+ };
+
+ private final CameraCaptureSession.StateCallback mCaptureStateCallback = new CameraCaptureSession.StateCallback() {
+
+ @Override
+ public void onConfigured(@NonNull CameraCaptureSession cameraCaptureSession) {
+ Log.i(TAG, "onConfigured: ");
+ // The camera is already closed
+ if (null == mCameraDevice) {
+ return;
+ }
+
+ // When the session is ready, we start displaying the preview.
+ mCaptureSession = cameraCaptureSession;
+ try {
+ mCaptureSession.setRepeatingRequest(mPreviewRequestBuilder.build(),
+ new CameraCaptureSession.CaptureCallback() {
+ }, mBackgroundHandler);
+ } catch (CameraAccessException e) {
+ e.printStackTrace();
+ }
+ }
+
+ @Override
+ public void onConfigureFailed(
+ @NonNull CameraCaptureSession cameraCaptureSession) {
+ Log.i(TAG, "onConfigureFailed: ");
+ if (camera2Listener != null) {
+ camera2Listener.onCameraError(new Exception("configureFailed"));
+ }
+ }
+ };
+ /**
+ * An additional thread for running tasks that shouldn't block the UI.
+ */
+ private HandlerThread mBackgroundThread;
+
+ /**
+ * A {@link Handler} for running tasks in the background.
+ */
+ private Handler mBackgroundHandler;
+
+ private ImageReader mImageReader;
+
+
+ /**
+ * {@link CaptureRequest.Builder} for the camera preview
+ */
+ private CaptureRequest.Builder mPreviewRequestBuilder;
+
+
+ /**
+ * A {@link Semaphore} to prevent the app from exiting before closing the camera.
+ */
+ private final Semaphore mCameraOpenCloseLock = new Semaphore(1);
+
+ /**
+ * Orientation of the camera sensor
+ */
+ private int mSensorOrientation;
+
+ private Size getBestSupportedSize(List sizes) {
+ Size defaultSize = sizes.get(0);
+ Log.e(TAG, "default width=" + defaultSize.getWidth() + "--height=" + defaultSize.getHeight());
+ int defaultDelta = Math.abs(defaultSize.getWidth() * defaultSize.getHeight() - previewViewSize.x * previewViewSize.y);
+ for (Size size : sizes) {
+ Log.e(TAG, "current width=" + defaultSize.getWidth() + "--height=" + defaultSize.getHeight());
+ int currentDelta = Math.abs(size.getWidth() * size.getHeight() - previewViewSize.x * previewViewSize.y);
+ if (currentDelta < defaultDelta) {
+ defaultDelta = currentDelta;
+ defaultSize = size;
+ }
+ }
+ Log.e(TAG, "final width=" + defaultSize.getWidth() + "--height=" + defaultSize.getHeight());
+ return defaultSize;
+ }
+
+ public synchronized void start() {
+ if (mCameraDevice != null) {
+ return;
+ }
+ startBackgroundThread();
+
+ // When the screen is turned off and turned back on, the SurfaceTexture is already
+ // available, and "onSurfaceTextureAvailable" will not be called. In that case, we can open
+ // a camera and start preview from here (otherwise, we wait until the surface is ready in
+ // the SurfaceTextureListener).
+ if (mTextureView.isAvailable()) {
+ openCamera();
+ } else {
+ mTextureView.setSurfaceTextureListener(mSurfaceTextureListener);
+ }
+ }
+
+ public void updatePreviewDegree(int degree) {
+ rotateDegree = degree;
+ }
+
+ public synchronized void stop() {
+ if (mCameraDevice == null) {
+ return;
+ }
+ closeCamera();
+ stopBackgroundThread();
+ }
+
+ public void release() {
+ stop();
+ mTextureView = null;
+ camera2Listener = null;
+ context = null;
+ }
+
+ private void setUpCameraOutput(CameraManager cameraManager) {
+ try {
+ if (configCameraParams(cameraManager, specificCameraId)) {
+ return;
+ }
+ for (String cameraId : cameraManager.getCameraIdList()) {
+ if (configCameraParams(cameraManager, cameraId)) {
+ return;
+ }
+ }
+ } catch (CameraAccessException e) {
+ e.printStackTrace();
+ } catch (NullPointerException e) {
+ // Currently an NPE is thrown when the Camera2API is used but not supported on the
+ // device this code runs.
+
+ if (camera2Listener != null) {
+ camera2Listener.onCameraError(e);
+ }
+ }
+ }
+
+ private boolean configCameraParams(CameraManager manager, String cameraId) throws CameraAccessException {
+ CameraCharacteristics characteristics
+ = manager.getCameraCharacteristics(cameraId);
+
+ StreamConfigurationMap map = characteristics.get(
+ CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
+ if (map == null) {
+ return false;
+ }
+ mPreviewSize = getBestSupportedSize(new ArrayList<>(Arrays.asList(map.getOutputSizes(SurfaceTexture.class))));
+ mImageReader = ImageReader.newInstance(mPreviewSize.getWidth(), mPreviewSize.getHeight(),
+ ImageFormat.YUV_420_888, 2);
+ mImageReader.setOnImageAvailableListener(
+ new OnImageAvailableListenerImpl(), mBackgroundHandler);
+
+ mSensorOrientation = characteristics.get(CameraCharacteristics.SENSOR_ORIENTATION);
+ mCameraId = cameraId;
+ return true;
+ }
+
+ private void openCamera() {
+ CameraManager cameraManager = (CameraManager) context.getSystemService(Context.CAMERA_SERVICE);
+ setUpCameraOutput(cameraManager);
+ configureTransform(mTextureView.getWidth(), mTextureView.getHeight());
+ try {
+ if (!mCameraOpenCloseLock.tryAcquire(2500, TimeUnit.MILLISECONDS)) {
+ throw new RuntimeException("Time out waiting to lock camera opening.");
+ }
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M
+ && context.checkSelfPermission(Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) {
+ return;
+ }
+
+ cameraManager.openCamera(mCameraId, mDeviceStateCallback, mBackgroundHandler);
+ } catch (CameraAccessException | InterruptedException e) {
+ if (camera2Listener != null) {
+ camera2Listener.onCameraError(e);
+ }
+ }
+ }
+
+ /**
+ * Closes the current {@link CameraDevice}.
+ */
+ private void closeCamera() {
+ try {
+ mCameraOpenCloseLock.acquire();
+ if (null != mCaptureSession) {
+ mCaptureSession.close();
+ mCaptureSession = null;
+ }
+ if (null != mCameraDevice) {
+ mCameraDevice.close();
+ mCameraDevice = null;
+ }
+ if (null != mImageReader) {
+ mImageReader.close();
+ mImageReader = null;
+ }
+ if (camera2Listener != null) {
+ camera2Listener.onCameraClosed();
+ }
+ } catch (InterruptedException e) {
+ if (camera2Listener != null) {
+ camera2Listener.onCameraError(e);
+ }
+ } finally {
+ mCameraOpenCloseLock.release();
+ }
+ }
+
+ /**
+ * Starts a background thread and its {@link Handler}.
+ */
+ private void startBackgroundThread() {
+ mBackgroundThread = new HandlerThread("CameraBackground");
+ mBackgroundThread.start();
+ mBackgroundHandler = new Handler(mBackgroundThread.getLooper());
+ }
+
+ /**
+ * Stops the background thread and its {@link Handler}.
+ */
+ private void stopBackgroundThread() {
+ mBackgroundThread.quitSafely();
+ try {
+ mBackgroundThread.join();
+ mBackgroundThread = null;
+ mBackgroundHandler = null;
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+ }
+
+ /**
+ * Creates a new {@link CameraCaptureSession} for camera preview.
+ */
+ private void createCameraPreviewSession() {
+ try {
+ SurfaceTexture texture = mTextureView.getSurfaceTexture();
+ assert texture != null;
+
+ // We configure the size of default buffer to be the size of camera preview we want.
+ texture.setDefaultBufferSize(mPreviewSize.getWidth(), mPreviewSize.getHeight());
+
+ // This is the output Surface we need to start preview.
+ Surface surface = new Surface(texture);
+
+ // We set up a CaptureRequest.Builder with the output Surface.
+ mPreviewRequestBuilder
+ = mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
+
+ mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AF_MODE,
+ CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE);
+
+ mPreviewRequestBuilder.addTarget(surface);
+ mPreviewRequestBuilder.addTarget(mImageReader.getSurface());
+
+ // Here, we create a CameraCaptureSession for camera preview.
+ mCameraDevice.createCaptureSession(Arrays.asList(surface, mImageReader.getSurface()),
+ mCaptureStateCallback, mBackgroundHandler
+ );
+ } catch (CameraAccessException e) {
+ e.printStackTrace();
+ }
+ }
+
+ /**
+ * Configures the necessary {@link Matrix} transformation to `mTextureView`.
+ * This method should be called after the camera preview size is determined in
+ * setUpCameraOutputs and also the size of `mTextureView` is fixed.
+ *
+ * @param viewWidth The width of `mTextureView`
+ * @param viewHeight The height of `mTextureView`
+ */
+ private void configureTransform(int viewWidth, int viewHeight) {
+ if (null == mTextureView || null == mPreviewSize) {
+ return;
+ }
+ Matrix matrix = new Matrix();
+ RectF viewRect = new RectF(0, 0, viewWidth, viewHeight);
+ RectF bufferRect = new RectF(0, 0, mPreviewSize.getHeight(), mPreviewSize.getWidth());
+ float centerX = viewRect.centerX();
+ float centerY = viewRect.centerY();
+ if (Surface.ROTATION_90 == rotation || Surface.ROTATION_270 == rotation) {
+ bufferRect.offset(centerX - bufferRect.centerX(), centerY - bufferRect.centerY());
+ matrix.setRectToRect(viewRect, bufferRect, Matrix.ScaleToFit.FILL);
+ float scale = Math.max(
+ (float) viewHeight / mPreviewSize.getHeight(),
+ (float) viewWidth / mPreviewSize.getWidth());
+ matrix.postScale(scale, scale, centerX, centerY);
+ matrix.postRotate((90 * (rotation - 2)) % 360, centerX, centerY);
+ } else if (Surface.ROTATION_180 == rotation) {
+ matrix.postRotate(180, centerX, centerY);
+ }
+ mTextureView.setTransform(matrix);
+ }
+
+ public static final class Builder {
+
+ private TextureView previewDisplayView;
+
+ private String specificCameraId;
+
+ private Camera2Listener camera2Listener;
+
+ private Point previewViewSize;
+
+ private int rotation;
+
+ private int rotateDegree;
+
+ private Context context;
+
+ public Builder() {
+ }
+
+ public Builder previewOn(TextureView val) {
+ previewDisplayView = val;
+ return this;
+ }
+
+ public Builder previewViewSize(Point val) {
+ previewViewSize = val;
+ return this;
+ }
+
+ public Builder rotation(int val) {
+ rotation = val;
+ return this;
+ }
+
+ public Builder rotateDegree(int val) {
+ rotateDegree = val;
+ return this;
+ }
+
+ public Builder specificCameraId(String val) {
+ specificCameraId = val;
+ return this;
+ }
+
+ public Builder cameraListener(Camera2Listener val) {
+ camera2Listener = val;
+ return this;
+ }
+
+ public Builder context(Context val) {
+ context = val;
+ return this;
+ }
+
+ public Camera2Helper build() {
+ if (previewDisplayView == null) {
+ throw new NullPointerException("must preview on a textureView or a surfaceView");
+ }
+ return new Camera2Helper(this);
+ }
+ }
+
+ private class OnImageAvailableListenerImpl implements ImageReader.OnImageAvailableListener {
+ private byte[] temp = null;
+ private byte[] yuvData = null;
+ private byte[] dstData = null;
+ private final ReentrantLock lock = new ReentrantLock();
+
+ @Override
+ public void onImageAvailable(ImageReader reader) {
+ Image image = reader.acquireNextImage();
+ if (camera2Listener != null && image.getFormat() == ImageFormat.YUV_420_888) {
+ Image.Plane[] planes = image.getPlanes();
+ lock.lock();
+
+ int offset = 0;
+ int width = image.getWidth();
+ int height = image.getHeight();
+ int len = width * height;
+ if (yuvData == null) {
+ yuvData = new byte[len * 3 / 2];
+ }
+ planes[0].getBuffer().get(yuvData, offset, len);
+ offset += len;
+ for (int i = 1; i < planes.length; i++) {
+ int srcIndex = 0, dstIndex = 0;
+ int rowStride = planes[i].getRowStride();
+ int pixelsStride = planes[i].getPixelStride();
+ ByteBuffer buffer = planes[i].getBuffer();
+ if (temp == null || temp.length != buffer.capacity()) {
+ temp = new byte[buffer.capacity()];
+ }
+ buffer.get(temp);
+
+ for (int j = 0; j < height / 2; j++) {
+ for (int k = 0; k < width / 2; k++) {
+ yuvData[offset + dstIndex++] = temp[srcIndex];
+ srcIndex += pixelsStride;
+ }
+ if (pixelsStride == 2) {
+ srcIndex += rowStride - width;
+ } else if (pixelsStride == 1) {
+ srcIndex += rowStride - width / 2;
+ }
+ }
+ offset += len / 4;
+ }
+
+ if (rotateDegree == 90 || rotateDegree == 180) {
+ if (dstData == null) {
+ dstData = new byte[len * 3 / 2];
+ }
+ if (rotateDegree == 90) {
+ YUVUtil.YUV420pRotate90(dstData, yuvData, width, height);
+ } else {
+ YUVUtil.YUV420pRotate180(dstData, yuvData, width, height);
+ }
+ if (camera2Listener != null) {
+ camera2Listener.onPreviewFrame(dstData);
+ }
+ } else {
+ if (camera2Listener != null) {
+ camera2Listener.onPreviewFrame(yuvData);
+ }
+ }
+
+ lock.unlock();
+ }
+ image.close();
+ }
+ }
+
+}
diff --git a/Live/src/main/java/com/frank/live/camera/Camera2Listener.java b/Live/src/main/java/com/frank/live/camera/Camera2Listener.java
new file mode 100644
index 00000000..eeaf4676
--- /dev/null
+++ b/Live/src/main/java/com/frank/live/camera/Camera2Listener.java
@@ -0,0 +1,16 @@
+package com.frank.live.camera;
+
+
+import android.util.Size;
+
+public interface Camera2Listener {
+
+ void onCameraOpened(Size previewSize, int displayOrientation);
+
+ void onPreviewFrame(byte[] yuvData);
+
+ void onCameraClosed();
+
+ void onCameraError(Exception e);
+
+}
diff --git a/Live/src/main/java/com/frank/live/camera/CameraHelper.java b/Live/src/main/java/com/frank/live/camera/CameraHelper.java
new file mode 100644
index 00000000..d0508265
--- /dev/null
+++ b/Live/src/main/java/com/frank/live/camera/CameraHelper.java
@@ -0,0 +1,212 @@
+package com.frank.live.camera;
+
+import android.app.Activity;
+import android.graphics.ImageFormat;
+import android.hardware.Camera;
+import android.view.Surface;
+import android.view.SurfaceHolder;
+
+import java.util.List;
+
+public class CameraHelper implements SurfaceHolder.Callback, Camera.PreviewCallback {
+
+ private final Activity mActivity;
+ private int mHeight;
+ private int mWidth;
+ private int mCameraId;
+ private Camera mCamera;
+ private byte[] buffer;
+ private SurfaceHolder mSurfaceHolder;
+ private Camera.PreviewCallback mPreviewCallback;
+ private int mRotation;
+ private OnChangedSizeListener mOnChangedSizeListener;
+ private byte[] bytes;
+
+ public CameraHelper(Activity activity, int cameraId, int width, int height) {
+ mActivity = activity;
+ mCameraId = cameraId;
+ mWidth = width;
+ mHeight = height;
+ }
+
+ public void switchCamera() {
+ if (mCameraId == Camera.CameraInfo.CAMERA_FACING_BACK) {
+ mCameraId = Camera.CameraInfo.CAMERA_FACING_FRONT;
+ } else {
+ mCameraId = Camera.CameraInfo.CAMERA_FACING_BACK;
+ }
+ stopPreview();
+ startPreview();
+ }
+
+ private void stopPreview() {
+ if (mCamera != null) {
+ mCamera.setPreviewCallback(null);
+ mCamera.stopPreview();
+ mCamera.release();
+ mCamera = null;
+ }
+ }
+
+ private void startPreview() {
+ try {
+ mCamera = Camera.open(mCameraId);
+ Camera.Parameters parameters = mCamera.getParameters();
+ parameters.setPreviewFormat(ImageFormat.NV21);
+ setPreviewSize(parameters);
+ setPreviewOrientation(parameters);
+ mCamera.setParameters(parameters);
+ buffer = new byte[mWidth * mHeight * 3 / 2];
+ bytes = new byte[buffer.length];
+ mCamera.addCallbackBuffer(buffer);
+ mCamera.setPreviewCallbackWithBuffer(this);
+ mCamera.setPreviewDisplay(mSurfaceHolder);
+ mCamera.startPreview();
+ } catch (Exception ex) {
+ ex.printStackTrace();
+ }
+ }
+
+ private void setPreviewOrientation(Camera.Parameters parameters) {
+ Camera.CameraInfo info = new Camera.CameraInfo();
+ Camera.getCameraInfo(mCameraId, info);
+ mRotation = mActivity.getWindowManager().getDefaultDisplay().getRotation();
+ int degrees = 0;
+ switch (mRotation) {
+ case Surface.ROTATION_0:
+ degrees = 0;
+ mOnChangedSizeListener.onChanged(mHeight, mWidth);
+ break;
+ case Surface.ROTATION_90:
+ degrees = 90;
+ mOnChangedSizeListener.onChanged(mWidth, mHeight);
+ break;
+ case Surface.ROTATION_270:
+ degrees = 270;
+ mOnChangedSizeListener.onChanged(mWidth, mHeight);
+ break;
+ }
+ int result;
+ if (info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {
+ result = (info.orientation + degrees) % 360;
+ result = (360 - result) % 360; // compensate the mirror
+ } else { // back-facing
+ result = (info.orientation - degrees + 360) % 360;
+ }
+ mCamera.setDisplayOrientation(result);
+ }
+
+ private void setPreviewSize(Camera.Parameters parameters) {
+ List supportedPreviewSizes = parameters.getSupportedPreviewSizes();
+ Camera.Size size = supportedPreviewSizes.get(0);
+ //select the best resolution of camera
+ int m = Math.abs(size.height * size.width - mWidth * mHeight);
+ supportedPreviewSizes.remove(0);
+ for (Camera.Size next : supportedPreviewSizes) {
+ int n = Math.abs(next.height * next.width - mWidth * mHeight);
+ if (n < m) {
+ m = n;
+ size = next;
+ }
+ }
+ mWidth = size.width;
+ mHeight = size.height;
+ parameters.setPreviewSize(mWidth, mHeight);
+ }
+
+ public void setPreviewDisplay(SurfaceHolder surfaceHolder) {
+ mSurfaceHolder = surfaceHolder;
+ mSurfaceHolder.addCallback(this);
+ }
+
+ public void setPreviewCallback(Camera.PreviewCallback previewCallback) {
+ mPreviewCallback = previewCallback;
+ }
+
+ @Override
+ public void surfaceCreated(SurfaceHolder holder) {
+
+ }
+
+ @Override
+ public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
+ stopPreview();
+ startPreview();
+ }
+
+ @Override
+ public void surfaceDestroyed(SurfaceHolder holder) {
+ stopPreview();
+ }
+
+
+ @Override
+ public void onPreviewFrame(byte[] data, Camera camera) {
+ switch (mRotation) {
+ case Surface.ROTATION_0:
+ rotation90(data);
+ break;
+ case Surface.ROTATION_90:
+ case Surface.ROTATION_270:
+ default:
+ break;
+ }
+ mPreviewCallback.onPreviewFrame(bytes, camera);
+ camera.addCallbackBuffer(buffer);
+ }
+
+ private void rotation90(byte[] data) {
+ int index = 0;
+ int ySize = mWidth * mHeight;
+ int uvHeight = mHeight / 2;
+ //back camera
+ if (mCameraId == Camera.CameraInfo.CAMERA_FACING_BACK) {
+
+ for (int i = 0; i < mWidth; i++) {
+ for (int j = mHeight - 1; j >= 0; j--) {
+ bytes[index++] = data[mWidth * j + i];
+ }
+ }
+
+ for (int i = 0; i < mWidth; i += 2) {
+ for (int j = uvHeight - 1; j >= 0; j--) {
+ // v
+ bytes[index++] = data[ySize + mWidth * j + i];
+ // u
+ bytes[index++] = data[ySize + mWidth * j + i + 1];
+ }
+ }
+ } else { // front camera
+ for (int i = 0; i < mWidth; i++) {
+ int nPos = mWidth - 1;
+ for (int j = 0; j < mHeight; j++) {
+ bytes[index++] = data[nPos - i];
+ nPos += mWidth;
+ }
+ }
+ //u v
+ for (int i = 0; i < mWidth; i += 2) {
+ int nPos = ySize + mWidth - 1;
+ for (int j = 0; j < uvHeight; j++) {
+ bytes[index++] = data[nPos - i - 1];
+ bytes[index++] = data[nPos - i];
+ nPos += mWidth;
+ }
+ }
+ }
+ }
+
+
+ public void setOnChangedSizeListener(OnChangedSizeListener listener) {
+ mOnChangedSizeListener = listener;
+ }
+
+ public void release() {
+ mSurfaceHolder.removeCallback(this);
+ stopPreview();
+ }
+
+ public interface OnChangedSizeListener {
+ void onChanged(int w, int h);
+ }
+}
diff --git a/Live/src/main/java/com/frank/live/camera/CameraType.java b/Live/src/main/java/com/frank/live/camera/CameraType.java
new file mode 100644
index 00000000..8f6d8897
--- /dev/null
+++ b/Live/src/main/java/com/frank/live/camera/CameraType.java
@@ -0,0 +1,6 @@
+package com.frank.live.camera;
+
+public enum CameraType {
+ CAMERA1,
+ CAMERA2
+}
diff --git a/Live/src/main/java/com/frank/live/listener/LiveStateChangeListener.java b/Live/src/main/java/com/frank/live/listener/LiveStateChangeListener.java
index b815f6c6..19a413c3 100644
--- a/Live/src/main/java/com/frank/live/listener/LiveStateChangeListener.java
+++ b/Live/src/main/java/com/frank/live/listener/LiveStateChangeListener.java
@@ -1,7 +1,7 @@
package com.frank.live.listener;
/**
- * 直播状态监听
+ * Listener of living state
* Created by frank on 2018/1/29.
*/
diff --git a/Live/src/main/java/com/frank/live/listener/OnFrameDataCallback.java b/Live/src/main/java/com/frank/live/listener/OnFrameDataCallback.java
new file mode 100644
index 00000000..12692e46
--- /dev/null
+++ b/Live/src/main/java/com/frank/live/listener/OnFrameDataCallback.java
@@ -0,0 +1,19 @@
+package com.frank.live.listener;
+
+/**
+ * Video/Audio frame callback
+ * Created by frank on 2022/01/25.
+ */
+
+public interface OnFrameDataCallback {
+
+ int getInputSamples();
+
+ void onAudioFrame(byte[] pcm);
+
+ void onAudioCodecInfo(int sampleRate, int channelCount);
+
+ void onVideoFrame(byte[] yuv, int cameraType);
+
+ void onVideoCodecInfo(int width, int height, int frameRate, int bitrate);
+}
diff --git a/Live/src/main/java/com/frank/live/param/AudioParam.java b/Live/src/main/java/com/frank/live/param/AudioParam.java
index 07377650..811a5cb3 100644
--- a/Live/src/main/java/com/frank/live/param/AudioParam.java
+++ b/Live/src/main/java/com/frank/live/param/AudioParam.java
@@ -2,7 +2,7 @@
/**
- * 音频相关参数
+ * Audio param Entity
* Created by frank on 2018/1/28.
*/
@@ -13,10 +13,10 @@ public class AudioParam {
private int numChannels;
public AudioParam(int sampleRate, int channelConfig, int audioFormat, int numChannels) {
- this.sampleRate = sampleRate;
+ this.sampleRate = sampleRate;
this.channelConfig = channelConfig;
- this.audioFormat = audioFormat;
- this.numChannels = numChannels;
+ this.audioFormat = audioFormat;
+ this.numChannels = numChannels;
}
public int getChannelConfig() {
diff --git a/Live/src/main/java/com/frank/live/param/VideoParam.java b/Live/src/main/java/com/frank/live/param/VideoParam.java
index 2a9f2285..a66e44b3 100644
--- a/Live/src/main/java/com/frank/live/param/VideoParam.java
+++ b/Live/src/main/java/com/frank/live/param/VideoParam.java
@@ -1,7 +1,7 @@
package com.frank.live.param;
/**
- * 视频相关参数
+ * Video param Entity
* Created by frank on 2018/1/28.
*/
@@ -13,10 +13,10 @@ public class VideoParam {
private int frameRate;
public VideoParam(int width, int height, int cameraId, int bitRate, int frameRate) {
- this.width = width;
- this.height = height;
- this.cameraId = cameraId;
- this.bitRate = bitRate;
+ this.width = width;
+ this.height = height;
+ this.cameraId = cameraId;
+ this.bitRate = bitRate;
this.frameRate = frameRate;
}
diff --git a/Live/src/main/java/com/frank/live/stream/AudioStream.java b/Live/src/main/java/com/frank/live/stream/AudioStream.java
new file mode 100644
index 00000000..474f5e69
--- /dev/null
+++ b/Live/src/main/java/com/frank/live/stream/AudioStream.java
@@ -0,0 +1,85 @@
+package com.frank.live.stream;
+
+import android.media.AudioFormat;
+import android.media.AudioRecord;
+import android.media.MediaRecorder;
+
+import com.frank.live.listener.OnFrameDataCallback;
+import com.frank.live.param.AudioParam;
+
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+
+public class AudioStream {
+
+ private boolean isMute;
+ private boolean isLiving;
+ private final int inputSamples;
+ private final ExecutorService executor;
+ private final AudioRecord audioRecord;
+ private final OnFrameDataCallback mCallback;
+
+ public AudioStream(OnFrameDataCallback callback, AudioParam audioParam) {
+ mCallback = callback;
+ executor = Executors.newSingleThreadExecutor();
+ int channelConfig;
+ if (audioParam.getNumChannels() == 2) {
+ channelConfig = AudioFormat.CHANNEL_IN_STEREO;
+ } else {
+ channelConfig = AudioFormat.CHANNEL_IN_MONO;
+ }
+
+ mCallback.onAudioCodecInfo(audioParam.getSampleRate(), audioParam.getNumChannels());
+ inputSamples = mCallback.getInputSamples() * 2;
+
+ int minBufferSize = AudioRecord.getMinBufferSize(audioParam.getSampleRate(),
+ channelConfig, audioParam.getAudioFormat()) * 2;
+ int bufferSizeInBytes = Math.max(minBufferSize, inputSamples);
+ audioRecord = new AudioRecord(MediaRecorder.AudioSource.MIC, audioParam.getSampleRate(),
+ channelConfig, audioParam.getAudioFormat(), bufferSizeInBytes);
+ }
+
+
+ public void startLive() {
+ isLiving = true;
+ executor.submit(new AudioTask());
+ }
+
+ public void stopLive() {
+ isLiving = false;
+ }
+
+
+ public void release() {
+ audioRecord.release();
+ }
+
+
+ class AudioTask implements Runnable {
+
+ @Override
+ public void run() {
+ audioRecord.startRecording();
+ byte[] bytes = new byte[inputSamples];
+ while (isLiving) {
+ if (!isMute) {
+ int len = audioRecord.read(bytes, 0, bytes.length);
+ if (len > 0) {
+ mCallback.onAudioFrame(bytes);
+ }
+ }
+ }
+ audioRecord.stop();
+ }
+ }
+
+ /**
+ * Setting mute or not
+ *
+ * @param isMute isMute
+ */
+ public void setMute(boolean isMute) {
+ this.isMute = isMute;
+ }
+
+}
diff --git a/Live/src/main/java/com/frank/live/stream/VideoStream.java b/Live/src/main/java/com/frank/live/stream/VideoStream.java
new file mode 100644
index 00000000..3a67fc8b
--- /dev/null
+++ b/Live/src/main/java/com/frank/live/stream/VideoStream.java
@@ -0,0 +1,95 @@
+package com.frank.live.stream;
+
+import android.app.Activity;
+import android.content.Context;
+import android.hardware.Camera;
+import android.view.SurfaceHolder;
+import android.view.View;
+
+import com.frank.live.camera.CameraHelper;
+import com.frank.live.listener.OnFrameDataCallback;
+import com.frank.live.param.VideoParam;
+
+public class VideoStream extends VideoStreamBase implements Camera.PreviewCallback,
+ CameraHelper.OnChangedSizeListener {
+
+ private final OnFrameDataCallback mCallback;
+ private final CameraHelper cameraHelper;
+ private final int mBitrate;
+ private final int mFrameRate;
+ private boolean isLiving;
+ private int previewWidth;
+ private int previewHeight;
+ private int rotateDegree = 90;
+
+ public VideoStream(OnFrameDataCallback callback,
+ View view,
+ VideoParam videoParam,
+ Context context) {
+ mCallback = callback;
+ mBitrate = videoParam.getBitRate();
+ mFrameRate = videoParam.getFrameRate();
+ cameraHelper = new CameraHelper((Activity) context,
+ videoParam.getCameraId(),
+ videoParam.getWidth(),
+ videoParam.getHeight());
+ cameraHelper.setPreviewCallback(this);
+ cameraHelper.setOnChangedSizeListener(this);
+ }
+
+ @Override
+ public void setPreviewDisplay(SurfaceHolder surfaceHolder) {
+ cameraHelper.setPreviewDisplay(surfaceHolder);
+ }
+
+ @Override
+ public void switchCamera() {
+ cameraHelper.switchCamera();
+ }
+
+ @Override
+ public void startLive() {
+ isLiving = true;
+ }
+
+ @Override
+ public void stopLive() {
+ isLiving = false;
+ }
+
+ @Override
+ public void release() {
+ cameraHelper.release();
+ }
+
+ @Override
+ public void onPreviewFrame(byte[] data, Camera camera) {
+ if (isLiving && mCallback != null) {
+ mCallback.onVideoFrame(data, 1);
+ }
+ }
+
+ @Override
+ public void onChanged(int w, int h) {
+ previewWidth = w;
+ previewHeight = h;
+ updateVideoCodecInfo(w, h, rotateDegree);
+ }
+
+ @Override
+ public void onPreviewDegreeChanged(int degree) {
+ updateVideoCodecInfo(previewWidth, previewHeight, degree);
+ }
+
+ private void updateVideoCodecInfo(int width, int height, int degree) {
+ if (degree == 90 || degree == 270) {
+ int temp = width;
+ width = height;
+ height = temp;
+ }
+ if (mCallback != null) {
+ mCallback.onVideoCodecInfo(width, height, mFrameRate, mBitrate);
+ }
+ }
+
+}
diff --git a/Live/src/main/java/com/frank/live/stream/VideoStreamBase.java b/Live/src/main/java/com/frank/live/stream/VideoStreamBase.java
new file mode 100644
index 00000000..1b5152c0
--- /dev/null
+++ b/Live/src/main/java/com/frank/live/stream/VideoStreamBase.java
@@ -0,0 +1,24 @@
+package com.frank.live.stream;
+
+import android.view.SurfaceHolder;
+
+/**
+ * Base of VideoStream
+ * Created by frank on 2022/01/27.
+ */
+
+public abstract class VideoStreamBase {
+
+ public abstract void startLive();
+
+ public abstract void setPreviewDisplay(SurfaceHolder surfaceHolder);
+
+ public abstract void switchCamera();
+
+ public abstract void stopLive();
+
+ public abstract void release();
+
+ public abstract void onPreviewDegreeChanged(int degree);
+
+}
diff --git a/Live/src/main/java/com/frank/live/stream/VideoStreamNew.java b/Live/src/main/java/com/frank/live/stream/VideoStreamNew.java
new file mode 100644
index 00000000..caf8dc23
--- /dev/null
+++ b/Live/src/main/java/com/frank/live/stream/VideoStreamNew.java
@@ -0,0 +1,194 @@
+package com.frank.live.stream;
+
+import android.app.Activity;
+import android.content.Context;
+import android.graphics.Point;
+import android.graphics.SurfaceTexture;
+import android.util.Log;
+import android.util.Size;
+import android.view.Surface;
+import android.view.SurfaceHolder;
+import android.view.TextureView;
+import android.view.View;
+
+import com.frank.live.camera.Camera2Helper;
+import com.frank.live.camera.Camera2Listener;
+import com.frank.live.listener.OnFrameDataCallback;
+import com.frank.live.param.VideoParam;
+
+/**
+ * Pushing video stream: using Camera2
+ * Created by frank on 2020/02/12.
+ */
+public class VideoStreamNew extends VideoStreamBase
+ implements TextureView.SurfaceTextureListener, Camera2Listener {
+
+ private static final String TAG = VideoStreamNew.class.getSimpleName();
+
+ private int rotation = 0;
+ private boolean isLiving;
+ private Size previewSize;
+ private final Context mContext;
+ private Camera2Helper camera2Helper;
+ private final VideoParam mVideoParam;
+ private final TextureView mTextureView;
+ private final OnFrameDataCallback mCallback;
+
+ public VideoStreamNew(OnFrameDataCallback callback,
+ View view,
+ VideoParam videoParam,
+ Context context) {
+ this.mCallback = callback;
+ // just support TextureView now
+ this.mTextureView = (TextureView) view;
+ this.mVideoParam = videoParam;
+ this.mContext = context;
+ mTextureView.setSurfaceTextureListener(this);
+ }
+
+ /**
+ * start previewing
+ */
+ private void startPreview() {
+ if (mContext instanceof Activity) {
+ rotation = ((Activity) mContext).getWindowManager().getDefaultDisplay().getRotation();
+ }
+ camera2Helper = new Camera2Helper.Builder()
+ .cameraListener(this)
+ .specificCameraId(Camera2Helper.CAMERA_ID_BACK)
+ .context(mContext.getApplicationContext())
+ .previewOn(mTextureView)
+ .previewViewSize(new Point(mVideoParam.getWidth(), mVideoParam.getHeight()))
+ .rotation(rotation)
+ .rotateDegree(getPreviewDegree(rotation))
+ .build();
+ camera2Helper.start();
+ }
+
+ @Override
+ public void setPreviewDisplay(SurfaceHolder surfaceHolder) {
+
+ }
+
+ @Override
+ public void switchCamera() {
+ if (camera2Helper != null) {
+ camera2Helper.switchCamera();
+ }
+ }
+
+ @Override
+ public void startLive() {
+ isLiving = true;
+ }
+
+ @Override
+ public void stopLive() {
+ isLiving = false;
+ }
+
+ @Override
+ public void release() {
+ if (camera2Helper != null) {
+ camera2Helper.stop();
+ camera2Helper.release();
+ camera2Helper = null;
+ }
+ }
+
+ /**
+ * stop previewing
+ */
+ private void stopPreview() {
+ if (camera2Helper != null) {
+ camera2Helper.stop();
+ }
+ }
+
+ @Override
+ public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) {
+ Log.i(TAG, "onSurfaceTextureAvailable...");
+ startPreview();
+ }
+
+ @Override
+ public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) {
+
+ }
+
+ @Override
+ public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) {
+ Log.i(TAG, "onSurfaceTextureDestroyed...");
+ stopPreview();
+ return false;
+ }
+
+ @Override
+ public void onSurfaceTextureUpdated(SurfaceTexture surface) {
+
+ }
+
+ /**
+ * Camera2 preview frame data
+ *
+ * @param yuvData data of yuv
+ */
+ @Override
+ public void onPreviewFrame(byte[] yuvData) {
+ if (isLiving && mCallback != null) {
+ mCallback.onVideoFrame(yuvData, 2);
+ }
+ }
+
+ private int getPreviewDegree(int rotation) {
+ switch (rotation) {
+ case Surface.ROTATION_0:
+ return 90;
+ case Surface.ROTATION_90:
+ return 0;
+ case Surface.ROTATION_180:
+ return 270;
+ case Surface.ROTATION_270:
+ return 180;
+ default:
+ return -1;
+ }
+ }
+
+ @Override
+ public void onCameraOpened(Size previewSize, int displayOrientation) {
+ Log.i(TAG, "onCameraOpened previewSize=" + previewSize.toString());
+ this.previewSize = previewSize;
+ updateVideoCodecInfo(getPreviewDegree(rotation));
+ }
+
+ @Override
+ public void onCameraClosed() {
+ Log.i(TAG, "onCameraClosed");
+ }
+
+ @Override
+ public void onCameraError(Exception e) {
+ Log.e(TAG, "onCameraError=" + e.toString());
+ }
+
+ @Override
+ public void onPreviewDegreeChanged(int degree) {
+ updateVideoCodecInfo(degree);
+ }
+
+ private void updateVideoCodecInfo(int degree) {
+ camera2Helper.updatePreviewDegree(degree);
+ if (mCallback != null && mVideoParam != null) {
+ int width = previewSize.getWidth();
+ int height = previewSize.getHeight();
+ if (degree == 90 || degree == 270) {
+ int temp = width;
+ width = height;
+ height = temp;
+ }
+ mCallback.onVideoCodecInfo(width, height, mVideoParam.getFrameRate(), mVideoParam.getBitRate());
+ }
+ }
+
+}
diff --git a/Live/src/main/java/com/frank/live/util/YUVUtil.java b/Live/src/main/java/com/frank/live/util/YUVUtil.java
index 6d58fba4..3b6063a0 100644
--- a/Live/src/main/java/com/frank/live/util/YUVUtil.java
+++ b/Live/src/main/java/com/frank/live/util/YUVUtil.java
@@ -1,47 +1,156 @@
package com.frank.live.util;
/**
- * YUV与RGB转换工具类
+ * Tool of transforming YUV format
* Created by frank on 2018/7/1.
*/
public class YUVUtil {
- public static byte[] ARGBtoYUV420SemiPlanar(int[] input, int width, int height) {
+ public static void rgbaToYUV420p(int[] argb, byte[] yuv, int width, int height) {
+ final int frameSize = width * height;
+ int index = 0;
+ int yIndex = 0;
+ int uIndex = frameSize;
+ int vIndex = frameSize * 5 / 4;
+ int R, G, B, Y, U, V;
- final int frameSize = width * height;
- byte[] yuv420sp = new byte[width * height * 3 / 2];
- int yIndex = 0;
- int uvIndex = frameSize;
+ for (int j = 0; j < height; j++) {
+ for (int i = 0; i < width; i++) {
+ R = (argb[index] & 0xff0000) >> 16;
+ G = (argb[index] & 0xff00) >> 8;
+ B = (argb[index] & 0xff);
- int a, R, G, B, Y, U, V;
- int index = 0;
- for (int j = 0; j < height; j++) {
- for (int i = 0; i < width; i++) {
+ // RGB to YUV algorithm
+ Y = ((66 * R + 129 * G + 25 * B + 128) >> 8) + 16;
- a = (input[index] & 0xff000000) >> 24; // a is not used obviously
- R = (input[index] & 0xff0000) >> 16;
- G = (input[index] & 0xff00) >> 8;
- B = (input[index] & 0xff);
+ // I420(YUV420p) -> YYYYYYYY UU VV
+ yuv[yIndex++] = (byte) Y;
+ if (j % 2 == 0 && i % 2 == 0) {
+ U = ((-38 * R - 74 * G + 112 * B + 128) >> 8) + 128;
+ V = ((112 * R - 94 * G - 18 * B + 128) >> 8) + 128;
+ yuv[uIndex++] = (byte) U;
+ yuv[vIndex++] = (byte) V;
+ }
+ index++;
+ }
+ }
+ }
+
+ private static int yuv2argb(int y, int u, int v) {
+ int r, g, b;
+
+ r = y + (int) (1.402f * u);
+ g = y - (int) (0.344f * v + 0.714f * u);
+ b = y + (int) (1.772f * v);
+ r = r > 255 ? 255 : Math.max(r, 0);
+ g = g > 255 ? 255 : Math.max(g, 0);
+ b = b > 255 ? 255 : Math.max(b, 0);
+ return 0xff000000 | (r << 16) | (g << 8) | b;
+ }
+
+ private static void yuv420pToARGB(byte[] yuv, int[] argb, int width, int height) {
+ int size = width * height;
+ int offset = size;
+ int u, v, y1, y2, y3, y4;
- // well known RGB to YUV algorithm
- Y = ((66 * R + 129 * G + 25 * B + 128) >> 8) + 16;
- U = ((-38 * R - 74 * G + 112 * B + 128) >> 8) + 128;
- V = ((112 * R - 94 * G - 18 * B + 128) >> 8) + 128;
+ for (int i = 0, k = 0; i < size; i += 2, k += 2) {
+ y1 = yuv[i] & 0xff;
+ y2 = yuv[i + 1] & 0xff;
+ y3 = yuv[width + i] & 0xff;
+ y4 = yuv[width + i + 1] & 0xff;
- // NV21 has a plane of Y and interleaved planes of VU each sampled by a factor of 2
- // meaning for every 4 Y pixels there are 1 V and 1 U. Note the sampling is every other
- // pixel AND every other scanLine.
- yuv420sp[yIndex++] = (byte) ((Y < 0) ? 0 : ((Y > 255) ? 255 : Y));
- if (j % 2 == 0 && index % 2 == 0) {
- yuv420sp[uvIndex++] = (byte) ((V < 0) ? 0 : ((V > 255) ? 255 : V));
- yuv420sp[uvIndex++] = (byte) ((U < 0) ? 0 : ((U > 255) ? 255 : U));
+ u = yuv[offset + k] & 0xff;
+ v = yuv[offset + k + 1] & 0xff;
+ u = u - 128;
+ v = v - 128;
+
+ argb[i] = yuv2argb(y1, u, v);
+ argb[i + 1] = yuv2argb(y2, u, v);
+ argb[width + i] = yuv2argb(y3, u, v);
+ argb[width + i + 1] = yuv2argb(y4, u, v);
+
+ if (i != 0 && (i + 2) % width == 0)
+ i += width;
}
+ }
- index++;
- }
+ public static void YUV420pRotate90(byte[] dst, byte[] src, int width, int height) {
+ int n = 0;
+ int wh = width * height;
+ int halfWidth = width / 2;
+ int halfHeight = height / 2;
+ // y
+ for (int j = 0; j < width; j++) {
+ for (int i = height - 1; i >= 0; i--) {
+ dst[n++] = src[width * i + j];
+ }
+ }
+ // u
+ for (int i = 0; i < halfWidth; i++) {
+ for (int j = 1; j <= halfHeight; j++) {
+ dst[n++] = src[wh + ((halfHeight - j) * halfWidth + i)];
+ }
+ }
+ // v
+ for (int i = 0; i < halfWidth; i++) {
+ for (int j = 1; j <= halfHeight; j++) {
+ dst[n++] = src[wh + wh / 4 + ((halfHeight - j) * halfWidth + i)];
+ }
+ }
+ }
+
+ public static void YUV420pRotate180(byte[] dst, byte[] src, int width, int height) {
+ int n = 0;
+ int halfWidth = width / 2;
+ int halfHeight = height / 2;
+ // y
+ for (int j = height - 1; j >= 0; j--) {
+ for (int i = width; i > 0; i--) {
+ dst[n++] = src[width * j + i - 1];
+ }
+ }
+ // u
+ int offset = width * height;
+ for (int j = halfHeight - 1; j >= 0; j--) {
+ for (int i = halfWidth; i > 0; i--) {
+ dst[n++] = src[offset + halfWidth * j + i - 1];
+ }
+ }
+ // v
+ offset += halfWidth * halfHeight;
+ for (int j = halfHeight - 1; j >= 0; j--) {
+ for (int i = halfWidth; i > 0; i--) {
+ dst[n++] = src[offset + halfWidth * j + i - 1];
+ }
+ }
+ }
+
+ public static void flipYUV(byte[] dst, byte[] src, int width, int height) {
+ if (dst == null || width <= 0 || height <= 0)
+ return;
+
+ int idx = 0;
+ // Y
+ for (int i = 0; i < width; i++) {
+ for (int j = 0; j < height; j++) {
+ dst[idx++] = src[width - i + (height - j) * width];
+ }
+ }
+ // U
+ int offset = width * height;
+ for (int i = 0; i < width / 2; i++) {
+ for (int j = 0; j < height / 2; j++) {
+ dst[idx++] = src[offset + width - i + (height / 2 - j) * width / 2];
+ }
+ }
+ // V
+ offset += width * height / 4;
+ for (int i = 0; i < width / 2; i++) {
+ for (int j = 0; j < height / 2; j++) {
+ dst[idx++] = src[offset + width - i + (height / 2 - j) * width / 2];
+ }
+ }
}
- return yuv420sp;
- }
}
diff --git a/Live/src/main/java/com/frank/live/view/SmartCameraView.java b/Live/src/main/java/com/frank/live/view/SmartCameraView.java
deleted file mode 100644
index 01eead30..00000000
--- a/Live/src/main/java/com/frank/live/view/SmartCameraView.java
+++ /dev/null
@@ -1,372 +0,0 @@
-package com.frank.live.view;
-
-import android.content.Context;
-import android.content.res.Configuration;
-import android.graphics.ImageFormat;
-import android.graphics.SurfaceTexture;
-import android.hardware.Camera;
-import android.opengl.GLES20;
-import android.opengl.GLSurfaceView;
-import android.opengl.Matrix;
-import android.util.AttributeSet;
-import android.util.Log;
-
-import com.seu.magicfilter.base.gpuimage.GPUImageFilter;
-import com.seu.magicfilter.utils.MagicFilterFactory;
-import com.seu.magicfilter.utils.MagicFilterType;
-import com.seu.magicfilter.utils.OpenGLUtils;
-
-import java.io.IOException;
-import java.nio.ByteBuffer;
-import java.nio.IntBuffer;
-import java.util.List;
-import java.util.concurrent.ConcurrentLinkedQueue;
-
-import javax.microedition.khronos.egl.EGLConfig;
-import javax.microedition.khronos.opengles.GL10;
-
-public class SmartCameraView extends GLSurfaceView implements GLSurfaceView.Renderer {
-
- private GPUImageFilter magicFilter;
- private SurfaceTexture surfaceTexture;
- private int mOESTextureId = OpenGLUtils.NO_TEXTURE;
- private int mSurfaceWidth;
- private int mSurfaceHeight;
- private int mPreviewWidth;
- private int mPreviewHeight;
-
- private float mInputAspectRatio;
- private float mOutputAspectRatio;
- private float[] mProjectionMatrix = new float[16];
- private float[] mSurfaceMatrix = new float[16];
- private float[] mTransformMatrix = new float[16];
-
- private Camera mCamera;
- private ByteBuffer mGLPreviewBuffer;
- private int mCamId = -1;
- private int mPreviewRotation = 0;
- private int mPreviewOrientation = Configuration.ORIENTATION_PORTRAIT;
-
- private Thread worker;
- private final Object writeLock = new Object();
- private ConcurrentLinkedQueue mGLIntBufferCache = new ConcurrentLinkedQueue<>();
- private PreviewCallback mPrevCb;
-
- private final String TAG = "SmartCameraView";
-
- public SmartCameraView(Context context) {
- this(context, null);
- }
-
- public SmartCameraView(Context context, AttributeSet attrs) {
- super(context, attrs);
-
- setEGLContextClientVersion(2);
- setRenderer(this);
- setRenderMode(GLSurfaceView.RENDERMODE_WHEN_DIRTY);
- }
-
- @Override
- public void onSurfaceCreated(GL10 gl, EGLConfig config) {
- Log.e(TAG, "Run into onSurfaceCreated...");
-
- GLES20.glDisable(GL10.GL_DITHER);
- GLES20.glClearColor(0, 0, 0, 0);
-
- magicFilter = new GPUImageFilter(MagicFilterType.NONE);
- magicFilter.init(getContext().getApplicationContext());
- magicFilter.onInputSizeChanged(mPreviewWidth, mPreviewHeight);
-
- mOESTextureId = OpenGLUtils.getExternalOESTextureID();
-
- surfaceTexture = new SurfaceTexture(mOESTextureId);
- surfaceTexture.setOnFrameAvailableListener(new SurfaceTexture.OnFrameAvailableListener() {
- @Override
- public void onFrameAvailable(SurfaceTexture surfaceTexture) {
- requestRender();
- }
- });
-
- // For camera preview on activity creation
- if (mCamera != null) {
- try {
- mCamera.setPreviewTexture(surfaceTexture);
- } catch (IOException ioe) {
- ioe.printStackTrace();
- }
- }
-
- Log.i(TAG, "Run out of onSurfaceCreated...");
- }
-
- @Override
- public void onSurfaceChanged(GL10 gl, int width, int height) {
- Log.i(TAG, "Run into onSurfaceChanged...width: " + width + ", height: " + height);
- GLES20.glViewport(0, 0, width, height);
- mSurfaceWidth = width;
- mSurfaceHeight = height;
- magicFilter.onDisplaySizeChanged(width, height);
-
- mOutputAspectRatio = width > height ? (float) width / height : (float) height / width;
- float aspectRatio = mOutputAspectRatio / mInputAspectRatio;
-
- if (width > height) {
- Matrix.orthoM(mProjectionMatrix, 0, -1.0f, 1.0f, -aspectRatio, aspectRatio, -1.0f, 1.0f);
- } else {
- Matrix.orthoM(mProjectionMatrix, 0, -aspectRatio, aspectRatio, -1.0f, 1.0f, -1.0f, 1.0f);
- }
-
- Log.i(TAG, "Run out onSurfaceChanged--");
- }
-
- @Override
- public void onDrawFrame(GL10 gl) {
-
- GLES20.glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
- GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT | GLES20.GL_DEPTH_BUFFER_BIT);
-
- surfaceTexture.updateTexImage();
-
- surfaceTexture.getTransformMatrix(mSurfaceMatrix);
-
- Matrix.multiplyMM(mTransformMatrix, 0, mSurfaceMatrix, 0, mProjectionMatrix, 0);
- magicFilter.setTextureTransformMatrix(mTransformMatrix);
-
- magicFilter.onDrawFrame(mOESTextureId);
-
- mGLIntBufferCache.add(magicFilter.getGLFboBuffer());
- synchronized (writeLock) {
- writeLock.notifyAll();
- }
- }
-
- public void setPreviewCallback(PreviewCallback cb) {
- mPrevCb = cb;
- }
-
- public int[] setPreviewResolution(int width, int height) {
- getHolder().setFixedSize(width, height);
-
- mCamera = openCamera();
- mPreviewWidth = width;
- mPreviewHeight = height;
-
- mCamera.getParameters().setPreviewSize(mPreviewWidth, mPreviewHeight);
-
- mGLPreviewBuffer = ByteBuffer.allocate(mPreviewWidth * mPreviewHeight * 4);
-
- mInputAspectRatio = mPreviewWidth > mPreviewHeight ?
- (float) mPreviewWidth / mPreviewHeight : (float) mPreviewHeight / mPreviewWidth;
-
- return new int[] { mPreviewWidth, mPreviewHeight };
- }
-
- public boolean setFilter(final MagicFilterType type) {
- if (mCamera == null) {
- return false;
- }
-
- queueEvent(new Runnable() {
- @Override
- public void run() {
- if (magicFilter != null) {
- magicFilter.destroy();
- }
- magicFilter = MagicFilterFactory.initFilters(type);
- if (magicFilter != null) {
- magicFilter.init(getContext().getApplicationContext());
- magicFilter.onInputSizeChanged(mPreviewWidth, mPreviewHeight);
- magicFilter.onDisplaySizeChanged(mSurfaceWidth, mSurfaceHeight);
- }
- }
- });
- requestRender();
- return true;
- }
-
- private void deleteTextures() {
- if (mOESTextureId != OpenGLUtils.NO_TEXTURE) {
- queueEvent(new Runnable() {
- @Override
- public void run() {
- GLES20.glDeleteTextures(1, new int[]{ mOESTextureId }, 0);
- mOESTextureId = OpenGLUtils.NO_TEXTURE;
- }
- });
- }
- }
-
- public void setCameraId(int id) {
- mCamId = id;
- }
-
- public void setPreviewOrientation(int orientation, int degree) {
- mPreviewOrientation = orientation;
- mPreviewRotation = degree;
-
- mCamera.setDisplayOrientation(degree);
-
- }
-
- public int getCameraId() {
- return mCamId;
- }
-
- public boolean startCamera() {
- worker = new Thread(new Runnable() {
- @Override
- public void run() {
- while (!Thread.interrupted()) {
- while (!mGLIntBufferCache.isEmpty()) {
- IntBuffer picture = mGLIntBufferCache.poll();
- mGLPreviewBuffer.asIntBuffer().put(picture.array());
- mPrevCb.onGetRgbaFrame(mGLPreviewBuffer.array(), mPreviewWidth, mPreviewHeight);
- }
- // Waiting for next frame
- synchronized (writeLock) {
- try {
- // isEmpty() may take some time, so we set timeout to detect next frame
- writeLock.wait(500);
- } catch (InterruptedException ie) {
- worker.interrupt();
- }
- }
- }
- }
- });
- worker.start();
-
- if (mCamera == null) {
- mCamera = openCamera();
- if (mCamera == null) {
- return false;
- }
- }
-
- Camera.Parameters params = mCamera.getParameters();
-
- List supportedFocusModes = params.getSupportedFocusModes();
- if (!supportedFocusModes.isEmpty()) {
- if (supportedFocusModes.contains(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE)) {
- params.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE);
- } else {
- params.setFocusMode(supportedFocusModes.get(0));
- }
- }
-
- params.setPictureSize(mPreviewWidth, mPreviewHeight);
- params.setPreviewSize(mPreviewWidth, mPreviewHeight);
-
- int VFPS = 15;
- int[] range = adaptFpsRange(VFPS, params.getSupportedPreviewFpsRange());
- params.setPreviewFpsRange(range[0], range[1]);
- params.setPreviewFormat(ImageFormat.NV21);
-
- params.setFlashMode(Camera.Parameters.FLASH_MODE_OFF);
- params.setWhiteBalance(Camera.Parameters.WHITE_BALANCE_AUTO);
- params.setSceneMode(Camera.Parameters.SCENE_MODE_AUTO);
- if (!params.getSupportedFocusModes().isEmpty()) {
- params.setFocusMode(params.getSupportedFocusModes().get(0));
- }
- mCamera.setParameters(params);
-
- mCamera.setDisplayOrientation(mPreviewRotation);
-
- try {
- mCamera.setPreviewTexture(surfaceTexture);
- } catch (IOException e) {
- e.printStackTrace();
- }
-
- GetParameters(mCamera);
-
- mCamera.startPreview();
-
- return true;
- }
-
- public void stopCamera() {
- if (worker != null) {
- worker.interrupt();
- try {
- worker.join();
- } catch (InterruptedException e) {
- e.printStackTrace();
- worker.interrupt();
- }
- mGLIntBufferCache.clear();
- worker = null;
- }
-
- if (mCamera != null) {
- mCamera.stopPreview();
- mCamera.release();
- mCamera = null;
- }
- }
-
- public void GetParameters(Camera camera) {
- List pictureSizes = camera.getParameters().getSupportedPictureSizes();
- List previewSizes = camera.getParameters().getSupportedPreviewSizes();
- Camera.Size psize;
- for (int i = 0; i < pictureSizes.size(); i++) {
- psize = pictureSizes.get(i);
- Log.i(TAG,psize.width+" x "+psize.height);
- }
- for (int i = 0; i < previewSizes.size(); i++) {
- psize = previewSizes.get(i);
- Log.i(TAG,psize.width+" x "+psize.height);
- }
- }
-
- private Camera openCamera() {
- Camera camera;
- if (mCamId < 0) {
- Camera.CameraInfo info = new Camera.CameraInfo();
-
- int numCameras = Camera.getNumberOfCameras();
- int frontCamId = -1;
- int backCamId = -1;
- for (int i = 0; i < numCameras; i++) {
- Camera.getCameraInfo(i, info);
- if (info.facing == Camera.CameraInfo.CAMERA_FACING_BACK) {
- backCamId = i;
- } else if (info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {
- frontCamId = i;
- break;
- }
- }
- if (frontCamId != -1) {
- mCamId = frontCamId;
- } else if (backCamId != -1) {
- mCamId = backCamId;
- } else {
- mCamId = 0;
- }
- }
- camera = Camera.open(mCamId);
-
- return camera;
- }
-
- private int[] adaptFpsRange(int expectedFps, List fpsRanges) {
- expectedFps *= 1000;
- int[] closestRange = fpsRanges.get(0);
- int measure = Math.abs(closestRange[0] - expectedFps) + Math.abs(closestRange[1] - expectedFps);
- for (int[] range : fpsRanges) {
- if (range[0] <= expectedFps && range[1] >= expectedFps) {
- int curMeasure = Math.abs(range[0] - expectedFps) + Math.abs(range[1] - expectedFps);
- if (curMeasure < measure) {
- closestRange = range;
- measure = curMeasure;
- }
- }
- }
- return closestRange;
- }
-
- public interface PreviewCallback {
-
- void onGetRgbaFrame(byte[] data, int width, int height);
- }
-}
diff --git a/Live/src/main/java/com/seu/magicfilter/advanced/MagicAmaroFilter.java b/Live/src/main/java/com/seu/magicfilter/advanced/MagicAmaroFilter.java
deleted file mode 100644
index 398bf5d0..00000000
--- a/Live/src/main/java/com/seu/magicfilter/advanced/MagicAmaroFilter.java
+++ /dev/null
@@ -1,66 +0,0 @@
-package com.seu.magicfilter.advanced;
-
-import android.opengl.GLES20;
-
-import com.frank.live.R;
-import com.seu.magicfilter.base.gpuimage.GPUImageFilter;
-import com.seu.magicfilter.utils.MagicFilterType;
-import com.seu.magicfilter.utils.OpenGLUtils;
-
-public class MagicAmaroFilter extends GPUImageFilter {
- private int[] inputTextureHandles = {-1,-1,-1};
- private int[] inputTextureUniformLocations = {-1,-1,-1};
- private int mGLStrengthLocation;
-
- public MagicAmaroFilter(){
- super(MagicFilterType.AMARO, R.raw.amaro);
- }
-
- @Override
- protected void onDestroy() {
- super.onDestroy();
- GLES20.glDeleteTextures(inputTextureHandles.length, inputTextureHandles, 0);
- for(int i = 0; i < inputTextureHandles.length; i++)
- inputTextureHandles[i] = -1;
- }
-
- @Override
- protected void onDrawArraysAfter(){
- for(int i = 0; i < inputTextureHandles.length && inputTextureHandles[i] != OpenGLUtils.NO_TEXTURE; i++){
- GLES20.glActiveTexture(GLES20.GL_TEXTURE0 + (i+3));
- GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, 0);
- GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
- }
- }
-
- @Override
- protected void onDrawArraysPre(){
- for(int i = 0; i < inputTextureHandles.length && inputTextureHandles[i] != OpenGLUtils.NO_TEXTURE; i++){
- GLES20.glActiveTexture(GLES20.GL_TEXTURE0 + (i+3));
- GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, inputTextureHandles[i]);
- GLES20.glUniform1i(inputTextureUniformLocations[i], (i+3));
- }
- }
-
- @Override
- protected void onInit(){
- super.onInit();
- for (int i = 0; i < inputTextureUniformLocations.length; i++) {
- inputTextureUniformLocations[i] = GLES20.glGetUniformLocation(getProgram(), "inputImageTexture" + (2 + i));
- }
- mGLStrengthLocation = GLES20.glGetUniformLocation(getProgram(), "strength");
- }
-
- @Override
- protected void onInitialized(){
- super.onInitialized();
- setFloat(mGLStrengthLocation, 1.0f);
- runOnDraw(new Runnable(){
- public void run(){
- inputTextureHandles[0] = OpenGLUtils.loadTexture(getContext(), "filter/brannan_blowout.png");
- inputTextureHandles[1] = OpenGLUtils.loadTexture(getContext(), "filter/overlaymap.png");
- inputTextureHandles[2] = OpenGLUtils.loadTexture(getContext(), "filter/amaromap.png");
- }
- });
- }
-}
diff --git a/Live/src/main/java/com/seu/magicfilter/advanced/MagicAntiqueFilter.java b/Live/src/main/java/com/seu/magicfilter/advanced/MagicAntiqueFilter.java
deleted file mode 100644
index fba5a083..00000000
--- a/Live/src/main/java/com/seu/magicfilter/advanced/MagicAntiqueFilter.java
+++ /dev/null
@@ -1,87 +0,0 @@
-package com.seu.magicfilter.advanced;
-
-import android.opengl.GLES20;
-
-import com.frank.live.R;
-import com.seu.magicfilter.base.gpuimage.GPUImageFilter;
-import com.seu.magicfilter.utils.MagicFilterType;
-
-import java.nio.ByteBuffer;
-
-public class MagicAntiqueFilter extends GPUImageFilter{
- private int[] mToneCurveTexture = {-1};
- private int mToneCurveTextureUniformLocation;
-
- public MagicAntiqueFilter(){
- super(MagicFilterType.ANTIQUE, R.raw.antique);
- }
-
- @Override
- protected void onDestroy(){
- super.onDestroy();
- GLES20.glDeleteTextures(1, mToneCurveTexture, 0);
- this.mToneCurveTexture[0] = -1;
- }
-
- @Override
- protected void onDrawArraysAfter(){
- if (this.mToneCurveTexture[0] != -1){
- GLES20.glActiveTexture(GLES20.GL_TEXTURE3);
- GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, 0);
- GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
- }
- }
-
- @Override
- protected void onDrawArraysPre(){
- if (this.mToneCurveTexture[0] != -1){
- GLES20.glActiveTexture(GLES20.GL_TEXTURE3);
- GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mToneCurveTexture[0]);
- GLES20.glUniform1i(this.mToneCurveTextureUniformLocation, 3);
- }
- }
-
- @Override
- protected void onInit(){
- super.onInit();
- mToneCurveTextureUniformLocation = GLES20.glGetUniformLocation(getProgram(), "curve");
- }
-
- @Override
- protected void onInitialized(){
- super.onInitialized();
- runOnDraw(new Runnable(){
- public void run(){
- GLES20.glGenTextures(1, mToneCurveTexture, 0);
- GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mToneCurveTexture[0]);
- GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D,
- GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR);
- GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D,
- GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_LINEAR);
- GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D,
- GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_CLAMP_TO_EDGE);
- GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D,
- GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_CLAMP_TO_EDGE);
- byte[] arrayOfByte = new byte[2048];
- int[] arrayOfInt1 = { 0, 1, 1, 2, 3, 3, 4, 5, 6, 6, 7, 8, 8, 9, 10, 11, 11, 12, 13, 14, 15, 15, 16, 17, 18, 19, 20, 21, 22, 23, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 48, 49, 50, 51, 52, 53, 55, 56, 57, 58, 59, 61, 62, 63, 64, 66, 67, 68, 69, 71, 72, 73, 74, 76, 77, 78, 79, 81, 82, 83, 85, 86, 87, 89, 90, 91, 93, 94, 95, 96, 98, 99, 100, 102, 103, 104, 106, 107, 108, 110, 111, 112, 114, 115, 116, 118, 119, 120, 122, 123, 124, 126, 127, 128, 130, 131, 132, 134, 135, 136, 137, 139, 140, 141, 143, 144, 145, 146, 148, 149, 150, 152, 153, 154, 155, 157, 158, 159, 160, 161, 163, 164, 165, 166, 168, 169, 170, 171, 172, 173, 175, 176, 177, 178, 179, 180, 181, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 211, 212, 213, 214, 215, 216, 216, 217, 218, 219, 220, 220, 221, 222, 223, 223, 224, 225, 226, 226, 227, 228, 228, 229, 230, 230, 231, 232, 232, 233, 234, 234, 235, 236, 236, 237, 238, 238, 239, 239, 240, 241, 241, 242, 242, 243, 244, 244, 245, 245, 246, 247, 247, 248, 248, 249, 249, 250, 251, 251, 252, 252, 253, 253, 254, 254, 255 };
- int[] arrayOfInt2 = { 15, 15, 16, 17, 18, 19, 20, 20, 21, 22, 23, 23, 24, 25, 26, 27, 28, 29, 30, 31, 31, 32, 33, 34, 35, 37, 38, 39, 40, 41, 42, 43, 43, 44, 45, 46, 48, 49, 50, 51, 52, 53, 55, 56, 57, 57, 58, 59, 61, 62, 63, 64, 66, 67, 68, 69, 71, 72, 72, 73, 74, 76, 77, 78, 79, 81, 82, 83, 85, 86, 87, 87, 89, 90, 91, 93, 94, 95, 96, 98, 99, 100, 102, 102, 103, 104, 106, 107, 108, 110, 111, 112, 114, 115, 116, 118, 118, 119, 120, 122, 123, 124, 126, 127, 128, 130, 131, 132, 134, 134, 135, 136, 137, 139, 140, 141, 143, 144, 145, 146, 148, 149, 149, 150, 152, 153, 154, 155, 157, 158, 159, 160, 161, 163, 163, 164, 165, 166, 168, 169, 170, 171, 172, 173, 175, 176, 177, 177, 178, 179, 180, 181, 183, 184, 185, 186, 187, 188, 189, 190, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 211, 212, 212, 213, 214, 215, 216, 216, 217, 218, 219, 220, 220, 221, 222, 222, 223, 223, 224, 225, 226, 226, 227, 228, 228, 229, 230, 230, 230, 231, 232, 232, 233, 234, 234, 235, 236, 236, 237, 238, 238, 238, 239, 239, 240, 241, 241, 242, 242, 243, 244, 244, 245, 245, 245, 246, 247, 247, 248, 248, 249, 249, 250, 251, 251, 252, 252, 252, 253, 253, 254, 254, 255 };
- int[] arrayOfInt3 = { 87, 89, 89, 90, 90, 91, 91, 93, 93, 94, 95, 95, 96, 96, 98, 98, 99, 100, 100, 102, 102, 103, 103, 104, 104, 106, 107, 107, 108, 108, 110, 110, 111, 112, 112, 114, 114, 115, 115, 116, 118, 118, 119, 119, 120, 120, 122, 123, 123, 124, 124, 126, 126, 127, 128, 128, 130, 130, 131, 131, 132, 134, 134, 135, 135, 136, 136, 137, 139, 139, 140, 140, 141, 143, 143, 144, 144, 145, 146, 146, 148, 148, 149, 150, 150, 152, 152, 153, 154, 154, 155, 155, 157, 158, 158, 159, 159, 160, 161, 161, 163, 163, 164, 165, 165, 166, 168, 168, 169, 169, 170, 171, 171, 172, 173, 173, 175, 175, 176, 177, 177, 178, 179, 179, 180, 181, 181, 183, 183, 184, 185, 185, 186, 187, 187, 188, 189, 189, 190, 191, 191, 192, 193, 193, 194, 195, 195, 196, 197, 197, 198, 199, 199, 200, 201, 201, 202, 203, 204, 204, 205, 206, 206, 207, 208, 208, 209, 210, 211, 211, 211, 212, 212, 213, 214, 215, 215, 216, 216, 217, 217, 218, 219, 219, 220, 220, 221, 221, 222, 223, 223, 223, 224, 225, 226, 226, 226, 227, 228, 228, 228, 229, 230, 230, 230, 231, 232, 232, 232, 233, 234, 234, 235, 235, 236, 236, 237, 238, 238, 238, 239, 239, 240, 240, 241, 241, 242, 242, 242, 243, 244, 244, 244, 245, 245, 246, 247, 247, 247, 248, 248, 249, 249, 249, 250, 251, 251, 252, 252, 252, 253, 253, 254, 254, 254, 255 };
- int[] arrayOfInt4 = { 0, 1, 1, 2, 3, 4, 4, 5, 6, 7, 7, 8, 9, 10, 10, 11, 12, 13, 13, 14, 15, 16, 17, 17, 18, 19, 20, 20, 21, 22, 23, 24, 24, 25, 26, 27, 28, 29, 29, 30, 31, 32, 33, 34, 35, 36, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 64, 65, 66, 67, 68, 69, 70, 72, 73, 74, 75, 76, 78, 79, 80, 81, 83, 84, 85, 86, 88, 89, 90, 91, 93, 94, 95, 97, 98, 99, 101, 102, 103, 105, 106, 107, 109, 110, 111, 113, 114, 115, 117, 118, 119, 121, 122, 123, 125, 126, 127, 129, 130, 131, 133, 134, 136, 137, 138, 140, 141, 142, 144, 145, 146, 148, 149, 150, 152, 153, 154, 156, 157, 158, 159, 161, 162, 163, 165, 166, 167, 168, 170, 171, 172, 173, 175, 176, 177, 178, 180, 181, 182, 183, 184, 186, 187, 188, 189, 190, 191, 192, 193, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 213, 214, 215, 216, 217, 218, 219, 219, 220, 221, 222, 223, 223, 224, 225, 226, 227, 227, 228, 229, 230, 230, 231, 232, 232, 233, 234, 234, 235, 236, 236, 237, 238, 238, 239, 240, 240, 241, 242, 242, 243, 244, 244, 245, 245, 246, 247, 247, 248, 248, 249, 250, 250, 251, 251, 252, 253, 253, 254, 254, 255 };
- for (int i = 0; i < 256; i++){
- arrayOfByte[(i * 4)] = ((byte)arrayOfInt1[i]);
- arrayOfByte[(1 + i * 4)] = ((byte)arrayOfInt2[i]);
- arrayOfByte[(2 + i * 4)] = ((byte)arrayOfInt3[i]);
- arrayOfByte[(3 + i * 4)] = ((byte)arrayOfInt4[i]);
- }
- int[] arrayOfInt5 = { 0, 0, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 5, 5, 5, 6, 6, 6, 7, 7, 8, 8, 8, 9, 9, 10, 10, 10, 11, 11, 11, 12, 12, 13, 13, 13, 14, 14, 14, 15, 15, 16, 16, 16, 17, 17, 17, 18, 18, 18, 19, 19, 20, 20, 20, 21, 21, 21, 22, 22, 23, 23, 23, 24, 24, 24, 25, 25, 25, 25, 26, 26, 27, 27, 28, 28, 28, 28, 29, 29, 30, 29, 31, 31, 31, 31, 32, 32, 33, 33, 34, 34, 34, 34, 35, 35, 36, 36, 37, 37, 37, 38, 38, 39, 39, 39, 40, 40, 40, 41, 42, 42, 43, 43, 44, 44, 45, 45, 45, 46, 47, 47, 48, 48, 49, 50, 51, 51, 52, 52, 53, 53, 54, 55, 55, 56, 57, 57, 58, 59, 60, 60, 61, 62, 63, 63, 64, 65, 66, 67, 68, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 88, 89, 90, 91, 93, 94, 95, 96, 97, 98, 100, 101, 103, 104, 105, 107, 108, 110, 111, 113, 115, 116, 118, 119, 120, 122, 123, 125, 127, 128, 130, 132, 134, 135, 137, 139, 141, 143, 144, 146, 148, 150, 152, 154, 156, 158, 160, 163, 165, 167, 169, 171, 173, 175, 178, 180, 182, 185, 187, 189, 192, 194, 197, 199, 201, 204, 206, 209, 211, 214, 216, 219, 221, 224, 226, 229, 232, 234, 236, 239, 241, 245, 247, 250, 252, 255 };
- for (int j = 0; j < 256; j++){
- arrayOfByte[(1024 + j * 4)] = ((byte)arrayOfInt5[j]);
- arrayOfByte[(1 + (1024 + j * 4))] = ((byte)arrayOfInt5[j]);
- arrayOfByte[(2 + (1024 + j * 4))] = ((byte)arrayOfInt5[j]);
- arrayOfByte[(3 + (1024 + j * 4))] = -1;
- }
- GLES20.glTexImage2D(GLES20.GL_TEXTURE_2D, 0, GLES20.GL_RGBA, 256, 2, 0, GLES20.GL_RGBA, GLES20.GL_UNSIGNED_BYTE, ByteBuffer.wrap(arrayOfByte));
- }
- });
- }
-}
diff --git a/Live/src/main/java/com/seu/magicfilter/advanced/MagicBeautyFilter.java b/Live/src/main/java/com/seu/magicfilter/advanced/MagicBeautyFilter.java
deleted file mode 100644
index 98e46260..00000000
--- a/Live/src/main/java/com/seu/magicfilter/advanced/MagicBeautyFilter.java
+++ /dev/null
@@ -1,29 +0,0 @@
-package com.seu.magicfilter.advanced;
-
-import android.opengl.GLES20;
-
-import com.frank.live.R;
-import com.seu.magicfilter.base.gpuimage.GPUImageFilter;
-import com.seu.magicfilter.utils.MagicFilterType;
-
-/**
- * Created by Administrator on 2016/5/22.
- */
-public class MagicBeautyFilter extends GPUImageFilter {
- private int mSingleStepOffsetLocation;
-
- public MagicBeautyFilter(){
- super(MagicFilterType.BEAUTY, R.raw.beauty);
- }
-
- protected void onInit() {
- super.onInit();
- mSingleStepOffsetLocation = GLES20.glGetUniformLocation(getProgram(), "singleStepOffset");
- }
-
- @Override
- public void onInputSizeChanged(final int width, final int height) {
- super.onInputSizeChanged(width, height);
- setFloatVec2(mSingleStepOffsetLocation, new float[] {2.0f / width, 2.0f / height});
- }
-}
diff --git a/Live/src/main/java/com/seu/magicfilter/advanced/MagicBlackCatFilter.java b/Live/src/main/java/com/seu/magicfilter/advanced/MagicBlackCatFilter.java
deleted file mode 100644
index dfd55652..00000000
--- a/Live/src/main/java/com/seu/magicfilter/advanced/MagicBlackCatFilter.java
+++ /dev/null
@@ -1,89 +0,0 @@
-package com.seu.magicfilter.advanced;
-
-import android.opengl.GLES20;
-
-import com.frank.live.R;
-import com.seu.magicfilter.base.gpuimage.GPUImageFilter;
-import com.seu.magicfilter.utils.MagicFilterType;
-
-import java.nio.ByteBuffer;
-
-public class MagicBlackCatFilter extends GPUImageFilter {
-
- private int[] mToneCurveTexture = {-1};
- private int mToneCurveTextureUniformLocation;
-
- public MagicBlackCatFilter(){
- super(MagicFilterType.BLACKCAT, R.raw.blackcat);
- }
-
- @Override
- protected void onDestroy(){
- super.onDestroy();
- GLES20.glDeleteTextures(1, mToneCurveTexture, 0);
- mToneCurveTexture[0] = -1;
- }
-
- @Override
- protected void onDrawArraysAfter(){
- if (mToneCurveTexture[0] != -1){
- GLES20.glActiveTexture(GLES20.GL_TEXTURE3);
- GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, 0);
- GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
- }
- }
-
- @Override
- protected void onDrawArraysPre(){
- if (mToneCurveTexture[0] != -1){
- GLES20.glActiveTexture(GLES20.GL_TEXTURE3);
- GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mToneCurveTexture[0]);
- GLES20.glUniform1i(mToneCurveTextureUniformLocation, 3);
- }
- }
-
- @Override
- protected void onInit(){
- super.onInit();
- mToneCurveTextureUniformLocation = GLES20.glGetUniformLocation(getProgram(), "curve");
- }
-
- @Override
- protected void onInitialized(){
- super.onInitialized();
- runOnDraw(new Runnable(){
- public void run(){
- GLES20.glGenTextures(1, mToneCurveTexture, 0);
- GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mToneCurveTexture[0]);
- GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D,
- GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR);
- GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D,
- GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_LINEAR);
- GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D,
- GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_CLAMP_TO_EDGE);
- GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D,
- GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_CLAMP_TO_EDGE);
- byte[] arrayOfByte = new byte[2048];
- int[] arrayOfInt1 = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 3, 5, 7, 8, 10, 11, 13, 15, 16, 18, 20, 21, 23, 24, 26, 28, 29, 31, 33, 34, 36, 37, 39, 41, 42, 44, 45, 47, 49, 50, 52, 53, 55, 57, 58, 60, 61, 63, 65, 66, 68, 69, 71, 72, 74, 76, 77, 79, 80, 82, 83, 85, 86, 88, 90, 91, 93, 94, 96, 97, 99, 100, 102, 103, 105, 106, 108, 109, 111, 112, 114, 115, 116, 118, 119, 121, 122, 124, 125, 127, 128, 129, 131, 132, 134, 135, 136, 138, 139, 141, 142, 143, 145, 146, 147, 149, 150, 151, 153, 154, 155, 157, 158, 159, 160, 162, 163, 164, 165, 167, 168, 169, 170, 172, 173, 174, 175, 176, 178, 179, 180, 181, 182, 183, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 199, 200, 201, 202, 203, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 215, 216, 217, 218, 219, 220, 220, 221, 222, 223, 224, 224, 225, 226, 227, 227, 228, 229, 229, 230, 231, 232, 232, 233, 234, 234, 235, 236, 236, 237, 238, 238, 239, 240, 240, 241, 242, 242, 243, 243, 244, 245, 245, 246, 247, 247, 248, 248, 249, 250, 250, 251, 251, 252, 253, 253, 254, 254, 255 };
- int[] arrayOfInt2 = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 3, 5, 7, 8, 10, 11, 13, 15, 16, 16, 18, 20, 21, 23, 24, 26, 28, 29, 31, 33, 34, 36, 37, 39, 41, 41, 42, 44, 45, 47, 49, 50, 52, 53, 55, 57, 58, 60, 61, 63, 65, 66, 68, 69, 71, 72, 74, 76, 77, 79, 80, 82, 83, 85, 86, 86, 88, 90, 91, 93, 94, 96, 97, 99, 100, 102, 103, 105, 106, 108, 109, 111, 112, 114, 115, 116, 118, 119, 121, 122, 124, 125, 127, 128, 129, 131, 134, 135, 136, 138, 139, 141, 142, 143, 145, 146, 147, 149, 150, 151, 153, 154, 155, 157, 158, 159, 160, 162, 163, 164, 165, 167, 168, 169, 170, 172, 173, 174, 175, 176, 179, 180, 181, 182, 183, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 199, 200, 201, 203, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 215, 216, 217, 219, 220, 220, 221, 222, 223, 224, 224, 225, 226, 227, 227, 228, 229, 229, 230, 232, 232, 233, 234, 234, 235, 236, 236, 237, 238, 238, 239, 240, 240, 242, 242, 243, 243, 244, 245, 245, 246, 247, 247, 248, 248, 249, 250, 251, 251, 252, 253, 253, 254, 254, 255 };
- int[] arrayOfInt3 = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 3, 5, 7, 8, 10, 10, 11, 13, 15, 16, 18, 20, 20, 21, 23, 24, 26, 28, 29, 29, 31, 33, 34, 36, 37, 39, 39, 41, 42, 44, 45, 47, 49, 50, 50, 52, 53, 55, 57, 58, 60, 61, 63, 63, 65, 66, 68, 69, 71, 72, 74, 76, 77, 79, 79, 80, 82, 83, 85, 86, 88, 90, 91, 93, 94, 96, 97, 99, 100, 100, 102, 103, 105, 106, 108, 109, 111, 112, 114, 115, 116, 118, 119, 121, 122, 124, 125, 127, 128, 129, 131, 132, 134, 135, 136, 138, 139, 141, 142, 143, 145, 146, 147, 149, 150, 151, 153, 154, 155, 157, 158, 159, 160, 162, 164, 165, 167, 168, 169, 170, 172, 173, 174, 175, 176, 178, 179, 180, 181, 182, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 199, 200, 201, 202, 203, 203, 204, 205, 206, 207, 209, 210, 211, 212, 213, 214, 215, 215, 216, 218, 219, 220, 220, 221, 222, 223, 224, 225, 226, 227, 227, 228, 229, 229, 230, 232, 232, 233, 234, 234, 235, 236, 236, 238, 238, 239, 240, 240, 241, 242, 243, 243, 244, 245, 245, 246, 247, 247, 248, 249, 250, 250, 251, 251, 252, 253, 254, 254, 255 };
- for (int i = 0; i < 256; i++){
- arrayOfByte[(i * 4)] = ((byte)arrayOfInt1[i]);
- arrayOfByte[(1 + i * 4)] = ((byte)arrayOfInt2[i]);
- arrayOfByte[(2 + i * 4)] = ((byte)arrayOfInt3[i]);
- arrayOfByte[(3 + i * 4)] = -1;
- }
- int[] arrayOfInt4 = { 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 11, 11, 12, 13, 13, 14, 14, 15, 16, 17, 18, 18, 19, 19, 20, 21, 21, 23, 24, 25, 26, 26, 26, 27, 28, 29, 30, 31, 32, 32, 33, 34, 35, 36, 37, 38, 38, 38, 39, 40, 41, 43, 44, 45, 45, 46, 47, 48, 49, 49, 50, 51, 52, 53, 54, 55, 56, 57, 57, 58, 59, 60, 61, 62, 63, 64, 65, 65, 66, 67, 68, 69, 70, 70, 71, 72, 74, 75, 76, 76, 77, 78, 79, 80, 81, 82, 82, 83, 85, 86, 87, 88, 89, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 101, 102, 103, 104, 105, 107, 107, 108, 109, 111, 112, 113, 114, 114, 115, 116, 117, 119, 120, 120, 121, 122, 123, 124, 125, 126, 126, 127, 128, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 139, 141, 142, 143, 144, 145, 145, 146, 147, 148, 149, 151, 151, 153, 154, 155, 156, 157, 158, 158, 159, 160, 161, 162, 163, 165, 166, 167, 168, 169, 170, 170, 171, 172, 173, 174, 175, 177, 178, 179, 180, 181, 182, 183, 183, 184, 185, 186, 189, 189, 190, 191, 192, 193, 194, 195, 195, 196, 198, 199, 201, 202, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 213, 214, 214, 215, 216, 218, 219, 220, 221, 221, 222, 223, 225, 227, 227, 228, 229, 230, 230, 230, 230, 230, 230, 230, 230, 230 };
- int[] arrayOfInt5 = { 0, 1, 1, 2, 3, 3, 4, 5, 5, 6, 7, 8, 8, 9, 10, 11, 11, 12, 13, 14, 15, 15, 16, 17, 18, 19, 19, 20, 21, 22, 23, 24, 25, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 39, 40, 41, 42, 43, 44, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 61, 62, 63, 64, 65, 66, 67, 69, 70, 71, 72, 73, 74, 76, 77, 78, 79, 81, 82, 83, 84, 86, 87, 88, 89, 91, 92, 93, 95, 96, 97, 99, 100, 101, 103, 104, 105, 107, 108, 109, 111, 112, 114, 115, 116, 118, 119, 121, 122, 124, 125, 126, 128, 129, 131, 132, 134, 135, 137, 138, 140, 141, 142, 144, 145, 147, 148, 149, 151, 152, 154, 155, 156, 158, 159, 160, 162, 163, 164, 166, 167, 168, 170, 171, 172, 173, 175, 176, 177, 178, 180, 181, 182, 183, 184, 186, 187, 188, 189, 190, 191, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 220, 221, 222, 223, 224, 225, 225, 226, 227, 228, 229, 229, 230, 231, 232, 232, 233, 234, 234, 235, 236, 236, 237, 238, 238, 239, 240, 240, 241, 241, 242, 243, 243, 244, 244, 245, 245, 246, 246, 247, 247, 248, 248, 249, 249, 250, 250, 251, 251, 252, 252, 252, 253, 253, 254, 254, 254, 255, 255 };
- int[] arrayOfInt6 = { 0, 0, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 5, 5, 5, 6, 6, 6, 7, 7, 8, 8, 8, 9, 9, 10, 10, 10, 11, 11, 11, 12, 12, 13, 13, 13, 14, 14, 14, 15, 15, 16, 16, 16, 17, 17, 17, 18, 18, 18, 19, 19, 20, 20, 20, 21, 21, 21, 22, 22, 23, 23, 23, 24, 24, 24, 25, 25, 25, 25, 26, 26, 27, 27, 28, 28, 28, 28, 29, 29, 30, 29, 31, 31, 31, 31, 32, 32, 33, 33, 34, 34, 34, 34, 35, 35, 36, 36, 37, 37, 37, 38, 38, 39, 39, 39, 40, 40, 40, 41, 42, 42, 43, 43, 44, 44, 45, 45, 45, 46, 47, 47, 48, 48, 49, 50, 51, 51, 52, 52, 53, 53, 54, 55, 55, 56, 57, 57, 58, 59, 60, 60, 61, 62, 63, 63, 64, 65, 66, 67, 68, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 88, 89, 90, 91, 93, 94, 95, 96, 97, 98, 100, 101, 103, 104, 105, 107, 108, 110, 111, 113, 115, 116, 118, 119, 120, 122, 123, 125, 127, 128, 130, 132, 134, 135, 137, 139, 141, 143, 144, 146, 148, 150, 152, 154, 156, 158, 160, 163, 165, 167, 169, 171, 173, 175, 178, 180, 182, 185, 187, 189, 192, 194, 197, 199, 201, 204, 206, 209, 211, 214, 216, 219, 221, 224, 226, 229, 232, 234, 236, 239, 241, 245, 247, 250, 252, 255 };
- for (int j = 0; j < 256; j++){
- arrayOfByte[(1024 + j * 4)] = ((byte)arrayOfInt4[j]);
- arrayOfByte[(1 + (1024 + j * 4))] = ((byte)arrayOfInt5[j]);
- arrayOfByte[(2 + (1024 + j * 4))] = ((byte)arrayOfInt6[j]);
- arrayOfByte[(3 + (1024 + j * 4))] = -1;
- }
- GLES20.glTexImage2D(GLES20.GL_TEXTURE_2D, 0, GLES20.GL_RGBA, 256, 2, 0, GLES20.GL_RGBA, GLES20.GL_UNSIGNED_BYTE, ByteBuffer.wrap(arrayOfByte));
- }
- });
- }
-}
diff --git a/Live/src/main/java/com/seu/magicfilter/advanced/MagicBrannanFilter.java b/Live/src/main/java/com/seu/magicfilter/advanced/MagicBrannanFilter.java
deleted file mode 100644
index 10dd89a1..00000000
--- a/Live/src/main/java/com/seu/magicfilter/advanced/MagicBrannanFilter.java
+++ /dev/null
@@ -1,68 +0,0 @@
-package com.seu.magicfilter.advanced;
-
-import android.opengl.GLES20;
-
-import com.frank.live.R;
-import com.seu.magicfilter.base.gpuimage.GPUImageFilter;
-import com.seu.magicfilter.utils.MagicFilterType;
-import com.seu.magicfilter.utils.OpenGLUtils;
-
-public class MagicBrannanFilter extends GPUImageFilter{
- private int[] inputTextureHandles = {-1,-1,-1,-1,-1};
- private int[] inputTextureUniformLocations = {-1,-1,-1,-1,-1};
- private int mGLStrengthLocation;
-
- public MagicBrannanFilter(){
- super(MagicFilterType.BRANNAN, R.raw.brannan);
- }
-
- @Override
- protected void onDestroy() {
- super.onDestroy();
- GLES20.glDeleteTextures(inputTextureHandles.length, inputTextureHandles, 0);
- for(int i = 0; i < inputTextureHandles.length; i++)
- inputTextureHandles[i] = -1;
- }
-
- @Override
- protected void onDrawArraysAfter(){
- for(int i = 0; i < inputTextureHandles.length && inputTextureHandles[i] != OpenGLUtils.NO_TEXTURE; i++){
- GLES20.glActiveTexture(GLES20.GL_TEXTURE0 + (i+3));
- GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, 0);
- GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
- }
- }
-
- @Override
- protected void onDrawArraysPre(){
- for(int i = 0; i < inputTextureHandles.length && inputTextureHandles[i] != OpenGLUtils.NO_TEXTURE; i++){
- GLES20.glActiveTexture(GLES20.GL_TEXTURE0 + (i+3) );
- GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, inputTextureHandles[i]);
- GLES20.glUniform1i(inputTextureUniformLocations[i], (i+3));
- }
- }
-
- @Override
- protected void onInit(){
- super.onInit();
- for (int i = 0; i < inputTextureUniformLocations.length; i++) {
- inputTextureUniformLocations[i] = GLES20.glGetUniformLocation(getProgram(), "inputImageTexture" + (2 + i));
- }
- mGLStrengthLocation = GLES20.glGetUniformLocation(getProgram(), "strength");
- }
-
- @Override
- protected void onInitialized(){
- super.onInitialized();
- setFloat(mGLStrengthLocation, 1.0f);
- runOnDraw(new Runnable(){
- public void run(){
- inputTextureHandles[0] = OpenGLUtils.loadTexture(getContext(), "filter/brannan_process.png");
- inputTextureHandles[1] = OpenGLUtils.loadTexture(getContext(), "filter/brannan_blowout.png");
- inputTextureHandles[2] = OpenGLUtils.loadTexture(getContext(), "filter/brannan_contrast.png");
- inputTextureHandles[3] = OpenGLUtils.loadTexture(getContext(), "filter/brannan_luma.png");
- inputTextureHandles[4] = OpenGLUtils.loadTexture(getContext(), "filter/brannan_screen.png");
- }
- });
- }
-}
diff --git a/Live/src/main/java/com/seu/magicfilter/advanced/MagicBrooklynFilter.java b/Live/src/main/java/com/seu/magicfilter/advanced/MagicBrooklynFilter.java
deleted file mode 100644
index f340296b..00000000
--- a/Live/src/main/java/com/seu/magicfilter/advanced/MagicBrooklynFilter.java
+++ /dev/null
@@ -1,67 +0,0 @@
-package com.seu.magicfilter.advanced;
-
-import android.opengl.GLES20;
-
-import com.frank.live.R;
-import com.seu.magicfilter.base.gpuimage.GPUImageFilter;
-import com.seu.magicfilter.utils.MagicFilterType;
-import com.seu.magicfilter.utils.OpenGLUtils;
-
-public class MagicBrooklynFilter extends GPUImageFilter {
- private int[] inputTextureHandles = {-1,-1,-1};
- private int[] inputTextureUniformLocations = {-1,-1,-1};
- private int mGLStrengthLocation;
-
- public MagicBrooklynFilter(){
- super(MagicFilterType.BROOKLYN, R.raw.brooklyn);
- }
-
- @Override
- protected void onDestroy() {
- super.onDestroy();
- GLES20.glDeleteTextures(inputTextureHandles.length, inputTextureHandles, 0);
- for (int i = 0; i < inputTextureHandles.length; i++) {
- inputTextureHandles[i] = -1;
- }
- }
-
- @Override
- protected void onDrawArraysAfter(){
- for(int i = 0; i < inputTextureHandles.length && inputTextureHandles[i] != OpenGLUtils.NO_TEXTURE; i++){
- GLES20.glActiveTexture(GLES20.GL_TEXTURE0 + (i+3));
- GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, 0);
- GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
- }
- }
-
- @Override
- protected void onDrawArraysPre(){
- for(int i = 0; i < inputTextureHandles.length && inputTextureHandles[i] != OpenGLUtils.NO_TEXTURE; i++){
- GLES20.glActiveTexture(GLES20.GL_TEXTURE0 + (i+3) );
- GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, inputTextureHandles[i]);
- GLES20.glUniform1i(inputTextureUniformLocations[i], (i+3));
- }
- }
-
- @Override
- protected void onInit(){
- super.onInit();
- for (int i = 0; i < inputTextureUniformLocations.length; i++) {
- inputTextureUniformLocations[i] = GLES20.glGetUniformLocation(getProgram(), "inputImageTexture" + (2 + i));
- }
- mGLStrengthLocation = GLES20.glGetUniformLocation(getProgram(), "strength");
- }
-
- @Override
- protected void onInitialized(){
- super.onInitialized();
- setFloat(mGLStrengthLocation, 1.0f);
- runOnDraw(new Runnable(){
- public void run(){
- inputTextureHandles[0] = OpenGLUtils.loadTexture(getContext(), "filter/brooklynCurves1.png");
- inputTextureHandles[1] = OpenGLUtils.loadTexture(getContext(), "filter/filter_map_first.png");
- inputTextureHandles[2] = OpenGLUtils.loadTexture(getContext(), "filter/brooklynCurves2.png");
- }
- });
- }
-}
diff --git a/Live/src/main/java/com/seu/magicfilter/advanced/MagicCalmFilter.java b/Live/src/main/java/com/seu/magicfilter/advanced/MagicCalmFilter.java
deleted file mode 100644
index b2406ad3..00000000
--- a/Live/src/main/java/com/seu/magicfilter/advanced/MagicCalmFilter.java
+++ /dev/null
@@ -1,125 +0,0 @@
-package com.seu.magicfilter.advanced;
-
-import android.opengl.GLES20;
-
-import com.frank.live.R;
-import com.seu.magicfilter.base.gpuimage.GPUImageFilter;
-import com.seu.magicfilter.utils.MagicFilterType;
-import com.seu.magicfilter.utils.OpenGLUtils;
-
-import java.nio.ByteBuffer;
-
-public class MagicCalmFilter extends GPUImageFilter{
- private int[] mToneCurveTexture = {-1};
- private int mToneCurveTextureUniformLocation;
- private int mMaskGrey1TextureId = -1;
- private int mMaskGrey1UniformLocation;
- private int mMaskGrey2TextureId = -1;
- private int mMaskGrey2UniformLocation;
-
- public MagicCalmFilter(){
- super(MagicFilterType.CALM, R.raw.calm);
- }
-
- @Override
- protected void onDestroy(){
- super.onDestroy();
- GLES20.glDeleteTextures(3, new int[]{mToneCurveTexture[0], mMaskGrey1TextureId, mMaskGrey2TextureId}, 0);
- mToneCurveTexture[0] = -1;
- mMaskGrey1TextureId = -1;
- mMaskGrey2TextureId = -1;
- }
-
- @Override
- protected void onDrawArraysAfter(){
- if (mToneCurveTexture[0] != -1){
- GLES20.glActiveTexture(GLES20.GL_TEXTURE3);
- GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, 0);
- GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
- }
- if (mMaskGrey1TextureId != -1){
- GLES20.glActiveTexture(GLES20.GL_TEXTURE4);
- GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, 0);
- GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
- }
- if (mMaskGrey2TextureId != -1){
- GLES20.glActiveTexture(GLES20.GL_TEXTURE5);
- GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, 0);
- GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
- }
- }
-
- @Override
- protected void onDrawArraysPre(){
- if (mToneCurveTexture[0] != -1){
- GLES20.glActiveTexture(GLES20.GL_TEXTURE3);
- GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mToneCurveTexture[0]);
- GLES20.glUniform1i(mToneCurveTextureUniformLocation, 3);
- }
- if (mMaskGrey1TextureId != -1){
- GLES20.glActiveTexture(GLES20.GL_TEXTURE4);
- GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mMaskGrey1TextureId);
- GLES20.glUniform1i(mMaskGrey1UniformLocation, 4);
- }
- if (mMaskGrey2TextureId != -1){
- GLES20.glActiveTexture(GLES20.GL_TEXTURE5);
- GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mMaskGrey2TextureId);
- GLES20.glUniform1i(mMaskGrey2UniformLocation, 5);
- }
- }
-
- @Override
- protected void onInit(){
- super.onInit();
- mToneCurveTextureUniformLocation = GLES20.glGetUniformLocation(getProgram(), "curve");
- mMaskGrey1UniformLocation = GLES20.glGetUniformLocation(getProgram(), "grey1Frame");
- mMaskGrey2UniformLocation = GLES20.glGetUniformLocation(getProgram(), "grey2Frame");
- }
-
- @Override
- protected void onInitialized(){
- super.onInitialized();
- runOnDraw(new Runnable(){
- public void run(){
- GLES20.glGenTextures(1, mToneCurveTexture, 0);
- GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mToneCurveTexture[0]);
- GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D,
- GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR);
- GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D,
- GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_LINEAR);
- GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D,
- GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_CLAMP_TO_EDGE);
- GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D,
- GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_CLAMP_TO_EDGE);
- byte[] arrayOfByte = new byte[3072];
- int[] arrayOfInt1 = { 38, 39, 40, 41, 41, 42, 43, 44, 45, 46, 47, 47, 48, 49, 50, 51, 52, 52, 53, 54, 55, 56, 57, 58, 58, 59, 60, 61, 62, 63, 64, 64, 65, 66, 67, 68, 69, 69, 70, 71, 72, 73, 74, 75, 75, 76, 77, 78, 79, 80, 81, 81, 82, 83, 84, 85, 86, 87, 87, 88, 89, 90, 91, 92, 92, 93, 94, 95, 96, 97, 98, 98, 99, 100, 101, 102, 103, 104, 104, 105, 106, 107, 108, 109, 109, 110, 111, 112, 113, 114, 115, 115, 116, 117, 118, 119, 120, 121, 121, 122, 123, 124, 125, 126, 127, 127, 128, 129, 130, 131, 132, 132, 133, 134, 135, 136, 137, 138, 138, 139, 140, 141, 142, 143, 144, 144, 145, 146, 147, 148, 149, 149, 150, 151, 152, 153, 154, 155, 155, 156, 157, 158, 159, 160, 161, 161, 162, 163, 164, 165, 166, 166, 167, 168, 169, 170, 171, 172, 172, 173, 174, 175, 176, 177, 178, 178, 179, 180, 181, 182, 183, 184, 184, 185, 186, 187, 188, 189, 189, 190, 191, 192, 193, 194, 195, 195, 196, 197, 198, 199, 200, 201, 201, 202, 203, 204, 205, 206, 206, 207, 208, 209, 210, 211, 212, 212, 213, 214, 215, 216, 217, 218, 218, 219, 220, 221, 222, 223, 224, 224, 225, 226, 227, 228, 229, 229, 230, 231, 232, 233, 234, 235, 235, 236, 237, 238, 239, 240, 241, 241, 242, 243, 244, 245, 246, 246, 247, 248, 249, 250, 251, 252, 252, 253, 254, 255 };
- for (int i = 0; i < 256; i++){
- arrayOfByte[(i * 4)] = ((byte)arrayOfInt1[i]);
- arrayOfByte[(1 + i * 4)] = ((byte)arrayOfInt1[i]);
- arrayOfByte[(2 + i * 4)] = ((byte)arrayOfInt1[i]);
- arrayOfByte[(3 + i * 4)] = -1;
- }
- int[] arrayOfInt2 = { 0, 1, 2, 3, 5, 6, 7, 8, 9, 10, 11, 13, 14, 15, 16, 17, 18, 19, 21, 22, 23, 24, 25, 26, 27, 29, 30, 31, 32, 33, 34, 35, 36, 37, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 93, 94, 95, 96, 97, 98, 99, 99, 100, 101, 102, 103, 104, 104, 105, 106, 107, 108, 109, 109, 110, 111, 112, 113, 114, 114, 115, 116, 117, 118, 118, 119, 120, 121, 122, 123, 123, 124, 125, 126, 127, 127, 128, 129, 130, 131, 131, 132, 133, 134, 135, 135, 136, 137, 138, 139, 140, 140, 141, 142, 143, 144, 145, 145, 146, 147, 148, 149, 150, 150, 151, 152, 153, 154, 155, 156, 157, 157, 158, 159, 160, 161, 162, 163, 164, 165, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 196, 197, 198, 199, 200, 201, 202, 203, 204, 206, 207, 208, 209, 210, 211, 213, 214, 215, 216, 217, 218, 220, 221, 222, 223, 224, 226, 227, 228, 229, 230, 232, 233, 234, 235, 237, 238, 239, 240, 241, 243, 244, 245, 246, 248, 249, 250, 251, 253, 254, 255 };
- int[] arrayOfInt3 = { 0, 1, 1, 2, 3, 3, 4, 5, 6, 6, 7, 8, 8, 9, 10, 11, 11, 12, 13, 14, 15, 15, 16, 17, 18, 19, 20, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 36, 37, 38, 39, 40, 42, 43, 44, 46, 47, 48, 50, 51, 53, 54, 56, 57, 59, 60, 62, 64, 65, 67, 69, 70, 72, 74, 75, 77, 79, 80, 82, 84, 85, 87, 89, 91, 92, 94, 96, 97, 99, 101, 102, 104, 106, 107, 109, 111, 112, 114, 115, 117, 118, 120, 121, 123, 124, 126, 127, 129, 130, 132, 133, 134, 136, 137, 138, 140, 141, 142, 144, 145, 146, 147, 149, 150, 151, 152, 153, 155, 156, 157, 158, 159, 160, 161, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 184, 185, 186, 187, 188, 189, 190, 191, 191, 192, 193, 194, 195, 196, 196, 197, 198, 199, 200, 200, 201, 202, 203, 203, 204, 205, 206, 206, 207, 208, 209, 209, 210, 211, 211, 212, 213, 214, 214, 215, 216, 216, 217, 218, 218, 219, 220, 220, 221, 222, 222, 223, 224, 224, 225, 226, 226, 227, 227, 228, 229, 229, 230, 231, 231, 232, 233, 233, 234, 234, 235, 236, 236, 237, 237, 238, 239, 239, 240, 240, 241, 242, 242, 243, 243, 244, 245, 245, 246, 246, 247, 247, 248, 249, 249, 250, 250, 251, 252, 252, 253, 253, 254, 254, 255 };
- for (int j = 0; j < 256; j++){
- arrayOfByte[(1024 + j * 4)] = ((byte)arrayOfInt3[j]);
- arrayOfByte[(1 + (1024 + j * 4))] = ((byte)arrayOfInt3[j]);
- arrayOfByte[(2 + (1024 + j * 4))] = ((byte)arrayOfInt2[j]);
- arrayOfByte[(3 + (1024 + j * 4))] = -1;
- }
- int[] arrayOfInt4 = { 0, 1, 3, 4, 5, 7, 8, 10, 11, 12, 14, 15, 16, 18, 19, 20, 22, 23, 24, 26, 27, 28, 30, 31, 33, 34, 35, 37, 38, 39, 41, 42, 43, 45, 46, 47, 49, 50, 51, 53, 54, 55, 57, 58, 59, 61, 62, 63, 64, 66, 67, 68, 70, 71, 72, 74, 75, 76, 77, 79, 80, 81, 83, 84, 85, 86, 88, 89, 90, 91, 93, 94, 95, 96, 98, 99, 100, 101, 103, 104, 105, 106, 108, 109, 110, 111, 112, 114, 115, 116, 117, 118, 119, 121, 122, 123, 124, 125, 126, 128, 129, 130, 131, 132, 133, 134, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 175, 176, 177, 178, 179, 180, 181, 182, 183, 183, 184, 185, 186, 187, 188, 189, 189, 190, 191, 192, 193, 194, 194, 195, 196, 197, 198, 198, 199, 200, 201, 202, 202, 203, 204, 205, 205, 206, 207, 208, 208, 209, 210, 211, 211, 212, 213, 214, 214, 215, 216, 216, 217, 218, 218, 219, 220, 221, 221, 222, 223, 223, 224, 225, 225, 226, 227, 227, 228, 229, 229, 230, 231, 231, 232, 233, 233, 234, 235, 235, 236, 237, 237, 238, 239, 239, 240, 240, 241, 242, 242, 243, 244, 244, 245, 246, 246, 247, 247, 248, 249, 249, 250, 251, 251, 252, 252, 253, 254, 254, 255 };
- int[] arrayOfInt5 = { 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 6, 6, 6, 6, 7, 7, 7, 8, 8, 8, 8, 9, 9, 9, 10, 10, 10, 11, 11, 11, 11, 12, 12, 12, 13, 13, 13, 14, 14, 14, 15, 15, 16, 16, 16, 17, 17, 17, 18, 18, 18, 19, 19, 20, 20, 21, 21, 21, 22, 22, 23, 23, 24, 24, 24, 25, 25, 26, 26, 27, 27, 28, 28, 29, 29, 30, 30, 31, 31, 32, 33, 33, 34, 34, 35, 35, 36, 37, 37, 38, 38, 39, 40, 40, 41, 42, 42, 43, 44, 44, 45, 46, 47, 47, 48, 49, 49, 50, 51, 52, 53, 53, 54, 55, 56, 57, 57, 58, 59, 60, 61, 62, 63, 64, 65, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 81, 82, 83, 84, 85, 86, 87, 88, 90, 91, 92, 93, 94, 96, 97, 98, 99, 101, 102, 103, 105, 106, 107, 109, 110, 111, 113, 114, 115, 117, 118, 120, 121, 123, 124, 126, 127, 129, 130, 132, 133, 135, 137, 138, 140, 142, 143, 145, 147, 148, 150, 152, 153, 155, 157, 159, 161, 162, 164, 166, 168, 170, 172, 174, 175, 177, 179, 181, 183, 185, 187, 189, 191, 193, 195, 197, 199, 201, 203, 205, 207, 209, 211, 213, 215, 217, 219, 221, 224, 226, 228, 230, 232, 234, 236, 238, 240, 242, 244, 247, 249, 251, 253, 255 };
- int[] arrayOfInt6 = { 0, 0, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 5, 5, 5, 6, 6, 6, 7, 7, 8, 8, 8, 9, 9, 10, 10, 10, 11, 11, 11, 12, 12, 13, 13, 13, 14, 14, 14, 15, 15, 16, 16, 16, 17, 17, 17, 18, 18, 18, 19, 19, 20, 20, 20, 21, 21, 21, 22, 22, 23, 23, 23, 24, 24, 24, 25, 25, 25, 25, 26, 26, 27, 27, 28, 28, 28, 28, 29, 29, 30, 29, 31, 31, 31, 31, 32, 32, 33, 33, 34, 34, 34, 34, 35, 35, 36, 36, 37, 37, 37, 38, 38, 39, 39, 39, 40, 40, 40, 41, 42, 42, 43, 43, 44, 44, 45, 45, 45, 46, 47, 47, 48, 48, 49, 50, 51, 51, 52, 52, 53, 53, 54, 55, 55, 56, 57, 57, 58, 59, 60, 60, 61, 62, 63, 63, 64, 65, 66, 67, 68, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 88, 89, 90, 91, 93, 94, 95, 96, 97, 98, 100, 101, 103, 104, 105, 107, 108, 110, 111, 113, 115, 116, 118, 119, 120, 122, 123, 125, 127, 128, 130, 132, 134, 135, 137, 139, 141, 143, 144, 146, 148, 150, 152, 154, 156, 158, 160, 163, 165, 167, 169, 171, 173, 175, 178, 180, 182, 185, 187, 189, 192, 194, 197, 199, 201, 204, 206, 209, 211, 214, 216, 219, 221, 224, 226, 229, 232, 234, 236, 239, 241, 245, 247, 250, 252, 255 };
- for (int k = 0; k < 256; k++){
- arrayOfByte[(2048 + k * 4)] = ((byte)arrayOfInt4[k]);
- arrayOfByte[(1 + (2048 + k * 4))] = ((byte)arrayOfInt5[k]);
- arrayOfByte[(2 + (2048 + k * 4))] = ((byte)arrayOfInt6[k]);
- arrayOfByte[(3 + (2048 + k * 4))] = -1;
- }
- GLES20.glTexImage2D(GLES20.GL_TEXTURE_2D, 0, GLES20.GL_RGBA, 256, 3, 0, GLES20.GL_RGBA, GLES20.GL_UNSIGNED_BYTE, ByteBuffer.wrap(arrayOfByte));
- mMaskGrey1TextureId = OpenGLUtils.loadTexture(getContext(), "filter/calm_mask1.jpg");
- mMaskGrey2TextureId = OpenGLUtils.loadTexture(getContext(), "filter/calm_mask2.jpg");
- }
- });
- }
-}
diff --git a/Live/src/main/java/com/seu/magicfilter/advanced/MagicCoolFilter.java b/Live/src/main/java/com/seu/magicfilter/advanced/MagicCoolFilter.java
deleted file mode 100644
index 25d94fb6..00000000
--- a/Live/src/main/java/com/seu/magicfilter/advanced/MagicCoolFilter.java
+++ /dev/null
@@ -1,87 +0,0 @@
-package com.seu.magicfilter.advanced;
-
-import android.opengl.GLES20;
-
-import com.frank.live.R;
-import com.seu.magicfilter.base.gpuimage.GPUImageFilter;
-import com.seu.magicfilter.utils.MagicFilterType;
-
-import java.nio.ByteBuffer;
-
-public class MagicCoolFilter extends GPUImageFilter {
- private int[] mToneCurveTexture = {-1};
- private int mToneCurveTextureUniformLocation;
-
- public MagicCoolFilter(){
- super(MagicFilterType.COOL, R.raw.cool);
- }
-
- @Override
- protected void onDestroy(){
- super.onDestroy();
- GLES20.glDeleteTextures(1, mToneCurveTexture, 0);
- this.mToneCurveTexture[0] = -1;
- }
-
- @Override
- protected void onDrawArraysAfter(){
- if (this.mToneCurveTexture[0] != -1){
- GLES20.glActiveTexture(GLES20.GL_TEXTURE3);
- GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, 0);
- GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
- }
- }
-
- @Override
- protected void onDrawArraysPre() {
- if (this.mToneCurveTexture[0] != -1) {
- GLES20.glActiveTexture(GLES20.GL_TEXTURE3);
- GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mToneCurveTexture[0]);
- GLES20.glUniform1i(this.mToneCurveTextureUniformLocation, 3);
- }
- }
-
- @Override
- protected void onInit() {
- super.onInit();
- mToneCurveTextureUniformLocation = GLES20.glGetUniformLocation(getProgram(), "curve");
- }
-
- @Override
- protected void onInitialized() {
- super.onInitialized();
- runOnDraw(new Runnable(){
- public void run(){
- GLES20.glGenTextures(1, mToneCurveTexture, 0);
- GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mToneCurveTexture[0]);
- GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D,
- GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR);
- GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D,
- GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_LINEAR);
- GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D,
- GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_CLAMP_TO_EDGE);
- GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D,
- GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_CLAMP_TO_EDGE);
- byte[] arrayOfByte = new byte[2048];
- int[] arrayOfInt1 = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 2, 3, 4, 5, 5, 6, 7, 8, 9, 9, 10, 11, 12, 12, 13, 14, 15, 16, 16, 17, 18, 19, 20, 20, 21, 22, 23, 24, 24, 25, 26, 27, 28, 28, 29, 30, 31, 32, 33, 33, 34, 35, 36, 37, 38, 39, 39, 40, 41, 42, 43, 44, 45, 46, 47, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 82, 83, 84, 85, 86, 87, 88, 90, 91, 92, 93, 94, 95, 97, 98, 99, 100, 102, 103, 104, 105, 107, 108, 109, 111, 112, 113, 115, 116, 117, 119, 120, 121, 123, 124, 126, 127, 128, 130, 131, 133, 134, 136, 137, 139, 140, 142, 143, 145, 146, 148, 149, 151, 152, 154, 155, 157, 158, 160, 161, 163, 165, 166, 168, 169, 171, 173, 174, 176, 177, 179, 181, 182, 184, 185, 187, 189, 190, 192, 194, 195, 197, 199, 200, 202, 204, 205, 207, 209, 210, 212, 214, 216, 217, 219, 221, 222, 224, 226, 228, 229, 231, 233, 234, 236, 238, 240, 241, 243, 245, 246, 248, 250, 252, 253, 255 };
- int[] arrayOfInt2 = { 0, 1, 2, 3, 4, 5, 6, 7, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 237, 238, 239, 240, 241, 242, 243, 244, 245, 246, 247, 248, 250, 251, 252, 253, 254, 255 };
- int[] arrayOfInt3 = { 0, 3, 6, 9, 11, 14, 17, 20, 23, 26, 28, 31, 34, 37, 40, 43, 45, 48, 51, 54, 57, 59, 62, 65, 68, 70, 73, 76, 79, 81, 84, 87, 89, 92, 95, 97, 100, 102, 105, 108, 110, 113, 115, 118, 120, 123, 125, 128, 130, 133, 135, 137, 140, 142, 144, 147, 149, 151, 153, 156, 158, 160, 162, 164, 166, 168, 171, 173, 175, 177, 179, 180, 182, 184, 186, 188, 190, 191, 193, 195, 197, 198, 200, 201, 203, 205, 206, 207, 209, 210, 212, 213, 214, 216, 217, 218, 219, 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 234, 235, 236, 237, 237, 238, 239, 240, 240, 241, 242, 242, 243, 243, 244, 244, 245, 245, 246, 246, 247, 247, 248, 248, 248, 249, 249, 249, 250, 250, 250, 251, 251, 251, 251, 252, 252, 252, 252, 252, 253, 253, 253, 253, 253, 253, 253, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 };
- int[] arrayOfInt4 = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 13, 17, 21, 24, 32, 36, 39, 46, 50, 53, 56, 62, 65, 68, 73, 75, 78, 80, 85, 87, 88, 92, 94, 95, 96, 99, 100, 102, 104, 106, 107, 109, 110, 112, 113, 115, 116, 117, 120, 121, 122, 123, 125, 126, 127, 129, 130, 131, 132, 134, 135, 136, 138, 139, 140, 141, 142, 143, 144, 146, 147, 148, 149, 150, 151, 152, 154, 154, 155, 156, 158, 159, 159, 161, 162, 163, 163, 165, 166, 166, 168, 169, 169, 170, 172, 172, 173, 175, 175, 176, 177, 178, 179, 180, 181, 182, 182, 184, 184, 185, 186, 187, 188, 188, 190, 190, 191, 192, 193, 194, 194, 196, 196, 197, 197, 199, 199, 200, 201, 202, 202, 203, 204, 205, 205, 207, 207, 208, 208, 210, 210, 211, 212, 213, 213, 214, 215, 215, 216, 217, 218, 218, 219, 220, 221, 221, 222, 223, 223, 224, 225, 226, 226, 227, 228, 228, 229, 230, 230, 231, 232, 232, 233, 234, 235, 235, 236, 237, 237, 238, 239, 239, 240, 240, 241, 242, 242, 243, 244, 244, 245, 246, 246, 247, 248, 248, 249, 249, 250, 251, 251, 252, 253, 253, 254, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 };
- for (int i = 0; i < 256; i++){
- arrayOfByte[(i * 4)] = ((byte)arrayOfInt1[i]);
- arrayOfByte[(1 + i * 4)] = ((byte)arrayOfInt2[i]);
- arrayOfByte[(2 + i * 4)] = ((byte)arrayOfInt3[i]);
- arrayOfByte[(3 + i * 4)] = ((byte)arrayOfInt4[i]);
- }
- int[] arrayOfInt5 = { 0, 0, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 5, 5, 5, 6, 6, 6, 7, 7, 8, 8, 8, 9, 9, 10, 10, 10, 11, 11, 11, 12, 12, 13, 13, 13, 14, 14, 14, 15, 15, 16, 16, 16, 17, 17, 17, 18, 18, 18, 19, 19, 20, 20, 20, 21, 21, 21, 22, 22, 23, 23, 23, 24, 24, 24, 25, 25, 25, 25, 26, 26, 27, 27, 28, 28, 28, 28, 29, 29, 30, 29, 31, 31, 31, 31, 32, 32, 33, 33, 34, 34, 34, 34, 35, 35, 36, 36, 37, 37, 37, 38, 38, 39, 39, 39, 40, 40, 40, 41, 42, 42, 43, 43, 44, 44, 45, 45, 45, 46, 47, 47, 48, 48, 49, 50, 51, 51, 52, 52, 53, 53, 54, 55, 55, 56, 57, 57, 58, 59, 60, 60, 61, 62, 63, 63, 64, 65, 66, 67, 68, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 88, 89, 90, 91, 93, 94, 95, 96, 97, 98, 100, 101, 103, 104, 105, 107, 108, 110, 111, 113, 115, 116, 118, 119, 120, 122, 123, 125, 127, 128, 130, 132, 134, 135, 137, 139, 141, 143, 144, 146, 148, 150, 152, 154, 156, 158, 160, 163, 165, 167, 169, 171, 173, 175, 178, 180, 182, 185, 187, 189, 192, 194, 197, 199, 201, 204, 206, 209, 211, 214, 216, 219, 221, 224, 226, 229, 232, 234, 236, 239, 241, 245, 247, 250, 252, 255 };
- for (int j = 0; j < 256; j++){
- arrayOfByte[(1024 + j * 4)] = ((byte)arrayOfInt5[j]);
- arrayOfByte[(1 + (1024 + j * 4))] = ((byte)arrayOfInt5[j]);
- arrayOfByte[(2 + (1024 + j * 4))] = ((byte)arrayOfInt5[j]);
- arrayOfByte[(3 + (1024 + j * 4))] = -1;
- }
- GLES20.glTexImage2D(GLES20.GL_TEXTURE_2D, 0, GLES20.GL_RGBA, 256, 2, 0, GLES20.GL_RGBA, GLES20.GL_UNSIGNED_BYTE, ByteBuffer.wrap(arrayOfByte));
- }
- });
- }
-}
diff --git a/Live/src/main/java/com/seu/magicfilter/advanced/MagicCrayonFilter.java b/Live/src/main/java/com/seu/magicfilter/advanced/MagicCrayonFilter.java
deleted file mode 100644
index 5f432eb3..00000000
--- a/Live/src/main/java/com/seu/magicfilter/advanced/MagicCrayonFilter.java
+++ /dev/null
@@ -1,42 +0,0 @@
-package com.seu.magicfilter.advanced;
-
-import android.opengl.GLES20;
-
-import com.frank.live.R;
-import com.seu.magicfilter.base.gpuimage.GPUImageFilter;
-import com.seu.magicfilter.utils.MagicFilterType;
-
-public class MagicCrayonFilter extends GPUImageFilter {
-
- private int mSingleStepOffsetLocation;
- //1.0 - 5.0
- private int mStrengthLocation;
-
- public MagicCrayonFilter(){
- super(MagicFilterType.CRAYON, R.raw.crayon);
- }
-
- @Override
- protected void onInit() {
- super.onInit();
- mSingleStepOffsetLocation = GLES20.glGetUniformLocation(getProgram(), "singleStepOffset");
- mStrengthLocation = GLES20.glGetUniformLocation(getProgram(), "strength");
- setFloat(mStrengthLocation, 2.0f);
- }
-
- @Override
- protected void onDestroy() {
- super.onDestroy();
- }
-
- @Override
- protected void onInitialized(){
- super.onInitialized();
- setFloat(mStrengthLocation, 0.5f);
- }
-
- @Override
- public void onInputSizeChanged(final int width, final int height) {
- setFloatVec2(mSingleStepOffsetLocation, new float[] {1.0f / width, 1.0f / height});
- }
-}
diff --git a/Live/src/main/java/com/seu/magicfilter/advanced/MagicEarlyBirdFilter.java b/Live/src/main/java/com/seu/magicfilter/advanced/MagicEarlyBirdFilter.java
deleted file mode 100644
index 2f539543..00000000
--- a/Live/src/main/java/com/seu/magicfilter/advanced/MagicEarlyBirdFilter.java
+++ /dev/null
@@ -1,69 +0,0 @@
-package com.seu.magicfilter.advanced;
-
-import android.opengl.GLES20;
-
-import com.frank.live.R;
-import com.seu.magicfilter.base.gpuimage.GPUImageFilter;
-import com.seu.magicfilter.utils.MagicFilterType;
-import com.seu.magicfilter.utils.OpenGLUtils;
-
-public class MagicEarlyBirdFilter extends GPUImageFilter {
- private int[] inputTextureHandles = {-1,-1,-1,-1,-1};
- private int[] inputTextureUniformLocations = {-1,-1,-1,-1,-1};
- protected int mGLStrengthLocation;
-
- public MagicEarlyBirdFilter(){
- super(MagicFilterType.EARLYBIRD, R.raw.earlybird);
- }
-
- @Override
- protected void onDestroy() {
- super.onDestroy();
- GLES20.glDeleteTextures(inputTextureHandles.length, inputTextureHandles, 0);
- for(int i = 0; i < inputTextureHandles.length; i++)
- inputTextureHandles[i] = -1;
- }
-
- @Override
- protected void onDrawArraysAfter(){
- for(int i = 0; i < inputTextureHandles.length
- && inputTextureHandles[i] != OpenGLUtils.NO_TEXTURE; i++){
- GLES20.glActiveTexture(GLES20.GL_TEXTURE0 + (i+3));
- GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, 0);
- GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
- }
- }
-
- @Override
- protected void onDrawArraysPre(){
- for(int i = 0; i < inputTextureHandles.length
- && inputTextureHandles[i] != OpenGLUtils.NO_TEXTURE; i++){
- GLES20.glActiveTexture(GLES20.GL_TEXTURE0 + (i+3) );
- GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, inputTextureHandles[i]);
- GLES20.glUniform1i(inputTextureUniformLocations[i], (i+3));
- }
- }
-
- @Override
- protected void onInit(){
- super.onInit();
- for(int i=0; i < inputTextureUniformLocations.length; i++)
- inputTextureUniformLocations[i] = GLES20.glGetUniformLocation(getProgram(), "inputImageTexture"+(2+i));
- mGLStrengthLocation = GLES20.glGetUniformLocation(getProgram(), "strength");
- }
-
- @Override
- protected void onInitialized(){
- super.onInitialized();
- setFloat(mGLStrengthLocation, 1.0f);
- runOnDraw(new Runnable(){
- public void run(){
- inputTextureHandles[0] = OpenGLUtils.loadTexture(getContext(), "filter/earlybirdcurves.png");
- inputTextureHandles[1] = OpenGLUtils.loadTexture(getContext(), "filter/earlybirdoverlaymap_new.png");
- inputTextureHandles[2] = OpenGLUtils.loadTexture(getContext(), "filter/vignettemap_new.png");
- inputTextureHandles[3] = OpenGLUtils.loadTexture(getContext(), "filter/earlybirdblowout.png");
- inputTextureHandles[4] = OpenGLUtils.loadTexture(getContext(), "filter/earlybirdmap.png");
- }
- });
- }
-}
diff --git a/Live/src/main/java/com/seu/magicfilter/advanced/MagicEmeraldFilter.java b/Live/src/main/java/com/seu/magicfilter/advanced/MagicEmeraldFilter.java
deleted file mode 100644
index 967941a6..00000000
--- a/Live/src/main/java/com/seu/magicfilter/advanced/MagicEmeraldFilter.java
+++ /dev/null
@@ -1,88 +0,0 @@
-package com.seu.magicfilter.advanced;
-
-import android.opengl.GLES20;
-
-import com.frank.live.R;
-import com.seu.magicfilter.base.gpuimage.GPUImageFilter;
-import com.seu.magicfilter.utils.MagicFilterType;
-
-import java.nio.ByteBuffer;
-
-public class MagicEmeraldFilter extends GPUImageFilter {
- private int[] mToneCurveTexture = {-1};
- private int mToneCurveTextureUniformLocation;
-
- public MagicEmeraldFilter(){
- super(MagicFilterType.EMERALD, R.raw.emerald);
- }
-
- @Override
- protected void onDestroy(){
- super.onDestroy();
- GLES20.glDeleteTextures(1, mToneCurveTexture, 0);
- mToneCurveTexture[0] = -1;
- }
-
- @Override
- protected void onDrawArraysAfter(){
- if (mToneCurveTexture[0] != -1){
- GLES20.glActiveTexture(GLES20.GL_TEXTURE3);
- GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, 0);
- GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
- }
- }
-
- @Override
- protected void onDrawArraysPre(){
- if (mToneCurveTexture[0] != -1){
- GLES20.glActiveTexture(GLES20.GL_TEXTURE3);
- GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mToneCurveTexture[0]);
- GLES20.glUniform1i(mToneCurveTextureUniformLocation, 3);
- }
- }
-
- @Override
- protected void onInit(){
- super.onInit();
- mToneCurveTextureUniformLocation = GLES20.glGetUniformLocation(getProgram(), "curve");
- }
-
- @Override
- protected void onInitialized(){
- super.onInitialized();
- runOnDraw(new Runnable(){
- public void run(){
- GLES20.glGenTextures(1, mToneCurveTexture, 0);
- GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mToneCurveTexture[0]);
- GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D,
- GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR);
- GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D,
- GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_LINEAR);
- GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D,
- GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_CLAMP_TO_EDGE);
- GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D,
- GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_CLAMP_TO_EDGE);
- byte[] arrayOfByte = new byte[2048];
- int[] arrayOfInt1 = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 3, 4, 7, 8, 9, 10, 12, 13, 14, 17, 18, 19, 21, 22, 23, 25, 26, 29, 30, 31, 32, 34, 35, 36, 39, 40, 41, 43, 44, 45, 46, 48, 50, 51, 53, 54, 55, 56, 58, 60, 61, 62, 64, 65, 66, 67, 69, 70, 72, 73, 75, 76, 77, 78, 79, 81, 82, 84, 85, 87, 88, 89, 90, 91, 92, 94, 96, 97, 98, 99, 101, 102, 103, 104, 105, 106, 107, 110, 111, 112, 113, 114, 115, 116, 117, 119, 120, 121, 122, 123, 125, 126, 127, 128, 129, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 173, 174, 175, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 184, 185, 186, 187, 188, 189, 190, 191, 191, 192, 193, 194, 195, 196, 197, 197, 198, 199, 200, 201, 201, 202, 203, 204, 205, 206, 206, 207, 208, 209, 210, 210, 211, 212, 213, 213, 214, 215, 216, 216, 217, 218, 219, 220, 220, 221, 222, 223, 223, 224, 225, 226, 226, 227, 228, 228, 229, 230, 231, 231, 232, 233, 234, 234, 235, 236, 236, 237, 237, 238, 239, 239, 240, 241, 242, 242, 243, 244, 244, 245, 246, 247, 247, 248, 249, 249, 250, 251, 251, 252, 253, 254, 254, 255 };
- int[] arrayOfInt2 = { 0, 0, 0, 0, 0, 0, 1, 3, 4, 5, 7, 8, 9, 10, 12, 13, 14, 16, 18, 19, 21, 22, 23, 25, 26, 27, 29, 30, 31, 32, 34, 35, 36, 37, 39, 40, 41, 43, 44, 45, 46, 48, 50, 51, 53, 54, 55, 56, 58, 59, 60, 61, 62, 64, 65, 66, 67, 69, 70, 71, 72, 73, 75, 76, 77, 78, 79, 82, 83, 84, 85, 87, 88, 89, 90, 91, 92, 94, 95, 96, 97, 98, 99, 101, 102, 103, 104, 105, 106, 107, 109, 111, 112, 113, 114, 115, 116, 117, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 131, 132, 133, 134, 135, 136, 137, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 184, 185, 186, 188, 189, 190, 191, 191, 192, 193, 194, 195, 196, 197, 197, 198, 199, 200, 201, 201, 202, 203, 204, 205, 206, 206, 207, 209, 210, 210, 211, 212, 213, 213, 214, 215, 216, 216, 217, 218, 219, 220, 220, 221, 222, 223, 223, 224, 225, 226, 226, 227, 228, 229, 230, 231, 231, 232, 233, 234, 234, 235, 236, 237, 237, 238, 239, 239, 240, 241, 242, 242, 243, 244, 244, 245, 247, 247, 248, 249, 249, 250, 251, 251, 252, 253, 254, 254, 255, 255, 255, 255, 255, 255 };
- int[] arrayOfInt3 = { 0, 1, 3, 4, 5, 7, 8, 9, 10, 12, 13, 14, 16, 17, 18, 19, 21, 22, 23, 25, 26, 27, 29, 30, 31, 32, 34, 35, 36, 37, 39, 40, 41, 43, 44, 45, 46, 48, 49, 50, 51, 53, 54, 55, 56, 58, 59, 60, 61, 62, 64, 65, 66, 67, 69, 70, 71, 72, 73, 75, 76, 77, 78, 79, 81, 82, 83, 84, 85, 87, 88, 89, 90, 91, 92, 94, 95, 96, 97, 98, 99, 101, 102, 103, 104, 105, 106, 107, 109, 110, 111, 112, 113, 114, 115, 116, 117, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 184, 185, 186, 187, 188, 189, 190, 191, 191, 192, 193, 194, 195, 196, 197, 197, 198, 199, 200, 201, 201, 202, 203, 204, 205, 206, 206, 207, 208, 209, 210, 210, 211, 212, 213, 213, 214, 215, 216, 216, 217, 218, 219, 220, 220, 221, 222, 223, 223, 224, 225, 226, 226, 227, 228, 228, 229, 230, 231, 231, 232, 233, 234, 234, 235, 236, 237, 237, 238, 239, 239, 240, 241, 242, 242, 243, 244, 244, 245, 246, 247, 247, 248, 249, 249, 250, 251, 251, 252, 253, 254, 254, 255 };
- for (int i = 0; i < 256; i++){
- arrayOfByte[(i * 4)] = ((byte)arrayOfInt1[i]);
- arrayOfByte[(1 + i * 4)] = ((byte)arrayOfInt2[i]);
- arrayOfByte[(2 + i * 4)] = ((byte)arrayOfInt3[i]);
- arrayOfByte[(3 + i * 4)] = -1;
- }
- int[] arrayOfInt4 = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 17, 18, 19, 20, 21, 22, 23, 24, 25, 27, 28, 29, 30, 31, 32, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 60, 61, 62, 63, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 123, 124, 125, 126, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 164, 165, 166, 167, 168, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 200, 201, 202, 203, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 224, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255, 255, 255, 255, 255, 255 };
- int[] arrayOfInt5 = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 126, 127, 128, 129, 130, 131, 132, 133, 135, 136, 137, 138, 139, 140, 141, 142, 143, 145, 146, 147, 148, 149, 150, 151, 152, 154, 155, 156, 157, 158, 159, 160, 161, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, 223, 224, 225, 226, 227, 228, 229, 229, 230, 231, 232, 233, 233, 234, 235, 236, 237, 237, 238, 239, 240, 240, 241, 242, 243, 243, 244, 245, 245, 246, 247, 247, 248, 249, 249, 250, 250, 251, 252, 252, 253, 253, 254, 254, 255 };
- int[] arrayOfInt6 = { 0, 0, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 5, 5, 5, 6, 6, 6, 7, 7, 8, 8, 8, 9, 9, 10, 10, 10, 11, 11, 11, 12, 12, 13, 13, 13, 14, 14, 14, 15, 15, 16, 16, 16, 17, 17, 17, 18, 18, 18, 19, 19, 20, 20, 20, 21, 21, 21, 22, 22, 23, 23, 23, 24, 24, 24, 25, 25, 25, 25, 26, 26, 27, 27, 28, 28, 28, 28, 29, 29, 30, 29, 31, 31, 31, 31, 32, 32, 33, 33, 34, 34, 34, 34, 35, 35, 36, 36, 37, 37, 37, 38, 38, 39, 39, 39, 40, 40, 40, 41, 42, 42, 43, 43, 44, 44, 45, 45, 45, 46, 47, 47, 48, 48, 49, 50, 51, 51, 52, 52, 53, 53, 54, 55, 55, 56, 57, 57, 58, 59, 60, 60, 61, 62, 63, 63, 64, 65, 66, 67, 68, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 88, 89, 90, 91, 93, 94, 95, 96, 97, 98, 100, 101, 103, 104, 105, 107, 108, 110, 111, 113, 115, 116, 118, 119, 120, 122, 123, 125, 127, 128, 130, 132, 134, 135, 137, 139, 141, 143, 144, 146, 148, 150, 152, 154, 156, 158, 160, 163, 165, 167, 169, 171, 173, 175, 178, 180, 182, 185, 187, 189, 192, 194, 197, 199, 201, 204, 206, 209, 211, 214, 216, 219, 221, 224, 226, 229, 232, 234, 236, 239, 241, 245, 247, 250, 252, 255 };
- for (int j = 0; j < 256; j++){
- arrayOfByte[(1024 + j * 4)] = ((byte)arrayOfInt5[j]);
- arrayOfByte[(1 + (1024 + j * 4))] = ((byte)arrayOfInt4[j]);
- arrayOfByte[(2 + (1024 + j * 4))] = ((byte)arrayOfInt6[j]);
- arrayOfByte[(3 + (1024 + j * 4))] = -1;
- }
- GLES20.glTexImage2D(GLES20.GL_TEXTURE_2D, 0, GLES20.GL_RGBA, 256, 2, 0, GLES20.GL_RGBA, GLES20.GL_UNSIGNED_BYTE, ByteBuffer.wrap(arrayOfByte));
- }
- });
- }
-}
diff --git a/Live/src/main/java/com/seu/magicfilter/advanced/MagicEvergreenFilter.java b/Live/src/main/java/com/seu/magicfilter/advanced/MagicEvergreenFilter.java
deleted file mode 100644
index 91c592f3..00000000
--- a/Live/src/main/java/com/seu/magicfilter/advanced/MagicEvergreenFilter.java
+++ /dev/null
@@ -1,80 +0,0 @@
-package com.seu.magicfilter.advanced;
-
-import android.opengl.GLES20;
-
-import com.frank.live.R;
-import com.seu.magicfilter.base.gpuimage.GPUImageFilter;
-import com.seu.magicfilter.utils.MagicFilterType;
-
-import java.nio.ByteBuffer;
-
-public class MagicEvergreenFilter extends GPUImageFilter {
- private int[] mToneCurveTexture = {-1};
- private int mToneCurveTextureUniformLocation;
-
- public MagicEvergreenFilter(){
- super(MagicFilterType.EVERGREEN, R.raw.evergreen);
- }
-
- @Override
- protected void onDestroy(){
- super.onDestroy();
- GLES20.glDeleteTextures(1, mToneCurveTexture, 0);
- mToneCurveTexture[0] = -1;
- }
-
- @Override
- protected void onDrawArraysAfter(){
- if (mToneCurveTexture[0] != -1){
- GLES20.glActiveTexture(GLES20.GL_TEXTURE3);
- GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, 0);
- GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
- }
- }
-
- @Override
- protected void onDrawArraysPre(){
- if (mToneCurveTexture[0] != -1){
- GLES20.glActiveTexture(GLES20.GL_TEXTURE3);
- GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mToneCurveTexture[0]);
- GLES20.glUniform1i(mToneCurveTextureUniformLocation, 3);
- }
- }
-
- @Override
- protected void onInit(){
- super.onInit();
- mToneCurveTextureUniformLocation = GLES20.glGetUniformLocation(getProgram(), "curve");
- }
- @Override
- protected void onInitialized() {
- super.onInitialized();
- runOnDraw(new Runnable(){
- public void run(){
- GLES20.glGenTextures(1, mToneCurveTexture, 0);
- GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mToneCurveTexture[0]);
- GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D,
- GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR);
- GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D,
- GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_LINEAR);
- GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D,
- GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_CLAMP_TO_EDGE);
- GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D,
- GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_CLAMP_TO_EDGE);
- byte[] arrayOfByte = new byte[1024];
- int[] arrayOfInt1 = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, 224, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255 };
- int[] arrayOfInt2 = { 0, 1, 1, 2, 3, 4, 4, 5, 6, 6, 7, 8, 9, 9, 10, 11, 12, 12, 13, 14, 15, 15, 16, 17, 17, 18, 19, 20, 21, 21, 22, 23, 24, 24, 25, 26, 27, 28, 28, 29, 30, 31, 32, 32, 33, 34, 35, 36, 37, 38, 38, 39, 40, 41, 42, 43, 44, 45, 46, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 90, 91, 92, 93, 94, 95, 96, 97, 99, 100, 101, 102, 103, 104, 105, 107, 108, 109, 110, 111, 112, 113, 115, 116, 117, 118, 119, 120, 122, 123, 124, 125, 126, 127, 129, 130, 131, 132, 133, 135, 136, 137, 138, 139, 140, 142, 143, 144, 145, 146, 148, 149, 150, 151, 152, 153, 155, 156, 157, 158, 159, 160, 162, 163, 164, 165, 166, 167, 169, 170, 171, 172, 173, 174, 175, 177, 178, 179, 180, 181, 182, 183, 185, 186, 187, 188, 189, 190, 191, 192, 193, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, 241, 241, 242, 243, 244, 245, 246, 247, 247, 248, 249, 250, 251, 252, 252, 253, 254, 255 };
- int[] arrayOfInt3 = { 0, 2, 4, 6, 8, 10, 11, 13, 16, 17, 19, 20, 21, 23, 24, 25, 27, 28, 29, 31, 32, 33, 34, 36, 38, 39, 40, 42, 43, 44, 45, 46, 48, 49, 50, 51, 52, 53, 54, 56, 58, 59, 60, 61, 62, 63, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 76, 77, 78, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 128, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 144, 145, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 157, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 168, 169, 170, 171, 172, 173, 175, 176, 177, 177, 178, 179, 180, 181, 182, 183, 184, 185, 185, 186, 187, 188, 190, 191, 192, 193, 193, 194, 195, 196, 197, 198, 199, 200, 200, 201, 202, 203, 205, 206, 207, 207, 208, 209, 210, 211, 212, 213, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, 224, 225, 225, 226, 227, 228, 229, 230, 231, 231, 232, 234, 235, 236, 237, 237, 238, 239, 240, 241, 242, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 252, 253, 254, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 };
- int[] arrayOfInt4 = { 0, 0, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 5, 5, 5, 6, 6, 6, 7, 7, 8, 8, 8, 9, 9, 10, 10, 10, 11, 11, 11, 12, 12, 13, 13, 13, 14, 14, 14, 15, 15, 16, 16, 16, 17, 17, 17, 18, 18, 18, 19, 19, 20, 20, 20, 21, 21, 21, 22, 22, 23, 23, 23, 24, 24, 24, 25, 25, 25, 25, 26, 26, 27, 27, 28, 28, 28, 28, 29, 29, 30, 29, 31, 31, 31, 31, 32, 32, 33, 33, 34, 34, 34, 34, 35, 35, 36, 36, 37, 37, 37, 38, 38, 39, 39, 39, 40, 40, 40, 41, 42, 42, 43, 43, 44, 44, 45, 45, 45, 46, 47, 47, 48, 48, 49, 50, 51, 51, 52, 52, 53, 53, 54, 55, 55, 56, 57, 57, 58, 59, 60, 60, 61, 62, 63, 63, 64, 65, 66, 67, 68, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 88, 89, 90, 91, 93, 94, 95, 96, 97, 98, 100, 101, 103, 104, 105, 107, 108, 110, 111, 113, 115, 116, 118, 119, 120, 122, 123, 125, 127, 128, 130, 132, 134, 135, 137, 139, 141, 143, 144, 146, 148, 150, 152, 154, 156, 158, 160, 163, 165, 167, 169, 171, 173, 175, 178, 180, 182, 185, 187, 189, 192, 194, 197, 199, 201, 204, 206, 209, 211, 214, 216, 219, 221, 224, 226, 229, 232, 234, 236, 239, 241, 245, 247, 250, 252, 255 };
- for (int i = 0; i < 256; i++)
- {
- arrayOfByte[(i * 4)] = ((byte)arrayOfInt1[i]);
- arrayOfByte[(1 + i * 4)] = ((byte)arrayOfInt2[i]);
- arrayOfByte[(2 + i * 4)] = ((byte)arrayOfInt3[i]);
- arrayOfByte[(3 + i * 4)] = ((byte)arrayOfInt4[i]);
- }
- GLES20.glTexImage2D(GLES20.GL_TEXTURE_2D, 0, GLES20.GL_RGBA, 256, 1, 0, GLES20.GL_RGBA, GLES20.GL_UNSIGNED_BYTE, ByteBuffer.wrap(arrayOfByte));
- }
- });
- }
-}
diff --git a/Live/src/main/java/com/seu/magicfilter/advanced/MagicFreudFilter.java b/Live/src/main/java/com/seu/magicfilter/advanced/MagicFreudFilter.java
deleted file mode 100644
index 9bbbaa9c..00000000
--- a/Live/src/main/java/com/seu/magicfilter/advanced/MagicFreudFilter.java
+++ /dev/null
@@ -1,75 +0,0 @@
-package com.seu.magicfilter.advanced;
-
-import android.opengl.GLES20;
-
-import com.frank.live.R;
-import com.seu.magicfilter.base.gpuimage.GPUImageFilter;
-import com.seu.magicfilter.utils.MagicFilterType;
-import com.seu.magicfilter.utils.OpenGLUtils;
-
-public class MagicFreudFilter extends GPUImageFilter {
- private int mTexelHeightUniformLocation;
- private int mTexelWidthUniformLocation;
- private int[] inputTextureHandles = {-1};
- private int[] inputTextureUniformLocations = {-1};
- private int mGLStrengthLocation;
-
- public MagicFreudFilter(){
- super(MagicFilterType.FREUD, R.raw.freud);
- }
-
- @Override
- protected void onDestroy() {
- super.onDestroy();
- GLES20.glDeleteTextures(1, inputTextureHandles, 0);
- for(int i = 0; i < inputTextureHandles.length; i++)
- inputTextureHandles[i] = -1;
- }
-
- @Override
- protected void onDrawArraysAfter(){
- for (int i = 0; i < inputTextureHandles.length && inputTextureHandles[i] != OpenGLUtils.NO_TEXTURE; i++){
- GLES20.glActiveTexture(GLES20.GL_TEXTURE0 + (i+3));
- GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, 0);
- GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
- }
- }
-
- @Override
- protected void onDrawArraysPre(){
- for (int i = 0; i < inputTextureHandles.length && inputTextureHandles[i] != OpenGLUtils.NO_TEXTURE; i++){
- GLES20.glActiveTexture(GLES20.GL_TEXTURE0 + (i+3) );
- GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, inputTextureHandles[i]);
- GLES20.glUniform1i(inputTextureUniformLocations[i], (i+3));
- }
- }
-
- @Override
- protected void onInit(){
- super.onInit();
- inputTextureUniformLocations[0] = GLES20.glGetUniformLocation(getProgram(), "inputImageTexture2");
-
- mTexelWidthUniformLocation = GLES20.glGetUniformLocation(getProgram(), "inputImageTextureWidth");
- mTexelHeightUniformLocation = GLES20.glGetUniformLocation(getProgram(), "inputImageTextureHeight");
-
- mGLStrengthLocation = GLES20.glGetUniformLocation(getProgram(), "strength");
- }
-
- @Override
- protected void onInitialized(){
- super.onInitialized();
- setFloat(mGLStrengthLocation, 1.0f);
- runOnDraw(new Runnable(){
- public void run(){
- inputTextureHandles[0] = OpenGLUtils.loadTexture(getContext(), "filter/freud_rand.png");
- }
- });
- }
-
- @Override
- public void onInputSizeChanged(int width, int height) {
- super.onInputSizeChanged(width, height);
- GLES20.glUniform1f(mTexelWidthUniformLocation, (float)width);
- GLES20.glUniform1f(mTexelHeightUniformLocation, (float)height);
- }
-}
diff --git a/Live/src/main/java/com/seu/magicfilter/advanced/MagicHealthyFilter.java b/Live/src/main/java/com/seu/magicfilter/advanced/MagicHealthyFilter.java
deleted file mode 100644
index 27bb7d37..00000000
--- a/Live/src/main/java/com/seu/magicfilter/advanced/MagicHealthyFilter.java
+++ /dev/null
@@ -1,109 +0,0 @@
-package com.seu.magicfilter.advanced;
-
-import android.opengl.GLES20;
-
-import com.frank.live.R;
-import com.seu.magicfilter.base.gpuimage.GPUImageFilter;
-import com.seu.magicfilter.utils.MagicFilterType;
-
-import java.nio.ByteBuffer;
-
-public class MagicHealthyFilter extends GPUImageFilter{
-
- private int[] mToneCurveTexture = {-1};
- private int mToneCurveTextureUniformLocation;
- private int mMaskGrey1TextureId = -1;
- private int mMaskGrey1UniformLocation;
- private int mTexelHeightUniformLocation;
- private int mTexelWidthUniformLocation;
-
- public MagicHealthyFilter(){
- super(MagicFilterType.HEALTHY, R.raw.healthy);
- }
-
- @Override
- protected void onDestroy(){
- super.onDestroy();
- GLES20.glDeleteTextures(1, mToneCurveTexture, 0);
- mToneCurveTexture[0] = -1;
- int[] texture = new int[1];
- texture[0] = mMaskGrey1TextureId;
- GLES20.glDeleteTextures(1, texture, 0);
- mMaskGrey1TextureId = -1;
- }
-
- @Override
- protected void onDrawArraysAfter(){
- if (mToneCurveTexture[0] != -1){
- GLES20.glActiveTexture(GLES20.GL_TEXTURE3);
- GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, 0);
- GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
- }
- if (mMaskGrey1TextureId != -1){
- GLES20.glActiveTexture(GLES20.GL_TEXTURE4);
- GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, 0);
- GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
- }
- }
-
- @Override
- protected void onDrawArraysPre(){
- if (mToneCurveTexture[0] != -1){
- GLES20.glActiveTexture(GLES20.GL_TEXTURE3);
- GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mToneCurveTexture[0]);
- GLES20.glUniform1i(mToneCurveTextureUniformLocation, 3);
- }
- if (mMaskGrey1TextureId != -1){
- GLES20.glActiveTexture(GLES20.GL_TEXTURE4);
- GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mMaskGrey1TextureId);
- GLES20.glUniform1i(mMaskGrey1UniformLocation, 4);
- }
- }
-
- @Override
- protected void onInit(){
- super.onInit();
- mToneCurveTextureUniformLocation = GLES20.glGetUniformLocation(getProgram(), "curve");
- mMaskGrey1UniformLocation = GLES20.glGetUniformLocation(getProgram(), "mask");
- mTexelWidthUniformLocation = GLES20.glGetUniformLocation(getProgram(), "texelWidthOffset");
- mTexelHeightUniformLocation = GLES20.glGetUniformLocation(getProgram(), "texelHeightOffset");
- }
-
- @Override
- protected void onInitialized(){
- super.onInitialized();
- runOnDraw(new Runnable(){
- public void run(){
- GLES20.glGenTextures(1, mToneCurveTexture, 0);
- GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mToneCurveTexture[0]);
- GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D,
- GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR);
- GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D,
- GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_LINEAR);
- GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D,
- GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_CLAMP_TO_EDGE);
- GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D,
- GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_CLAMP_TO_EDGE);
- byte[] arrayOfByte = new byte[1024];
- int[] arrayOfInt1 = { 95, 95, 96, 97, 97, 98, 99, 99, 100, 101, 101, 102, 103, 104, 104, 105, 106, 106, 107, 108, 108, 109, 110, 111, 111, 112, 113, 113, 114, 115, 115, 116, 117, 117, 118, 119, 120, 120, 121, 122, 122, 123, 124, 124, 125, 126, 127, 127, 128, 129, 129, 130, 131, 131, 132, 133, 133, 134, 135, 136, 136, 137, 138, 138, 139, 140, 140, 141, 142, 143, 143, 144, 145, 145, 146, 147, 147, 148, 149, 149, 150, 151, 152, 152, 153, 154, 154, 155, 156, 156, 157, 158, 159, 159, 160, 161, 161, 162, 163, 163, 164, 165, 165, 166, 167, 168, 168, 169, 170, 170, 171, 172, 172, 173, 174, 175, 175, 176, 177, 177, 178, 179, 179, 180, 181, 181, 182, 183, 184, 184, 185, 186, 186, 187, 188, 188, 189, 190, 191, 191, 192, 193, 193, 194, 195, 195, 196, 197, 197, 198, 199, 200, 200, 201, 202, 202, 203, 204, 204, 205, 206, 207, 207, 208, 209, 209, 210, 211, 211, 212, 213, 213, 214, 215, 216, 216, 217, 218, 218, 219, 220, 220, 221, 222, 223, 223, 224, 225, 225, 226, 227, 227, 228, 229, 229, 230, 231, 232, 232, 233, 234, 234, 235, 236, 236, 237, 238, 239, 239, 240, 241, 241, 242, 243, 243, 244, 245, 245, 246, 247, 248, 248, 249, 250, 250, 251, 252, 252, 253, 254, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 };
- int[] arrayOfInt2 = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 3, 4, 5, 7, 8, 9, 12, 13, 14, 15, 16, 17, 19, 20, 21, 22, 23, 24, 25, 26, 27, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 41, 42, 43, 44, 45, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 60, 61, 62, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 168, 169, 170, 171, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 189, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 204, 205, 206, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 219, 220, 221, 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, 234, 235, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, 245, 246, 247, 249, 249, 250, 251, 252, 253, 254, 255, 255, 255, 255, 255, 255, 255, 255, 255 };
- int[] arrayOfInt3 = { 0, 1, 2, 3, 3, 4, 5, 6, 7, 8, 9, 10, 10, 11, 12, 13, 14, 15, 16, 17, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 95, 96, 97, 98, 99, 100, 101, 102, 103, 105, 106, 107, 108, 109, 110, 111, 112, 114, 115, 116, 117, 118, 119, 120, 121, 122, 124, 125, 126, 127, 128, 129, 130, 131, 132, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 237, 238, 239, 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 249, 250, 251, 252, 253, 254, 255 };
- for (int i = 0; i < 256; i++)
- {
- arrayOfByte[(i * 4)] = ((byte)arrayOfInt3[i]);
- arrayOfByte[(1 + i * 4)] = ((byte)arrayOfInt2[i]);
- arrayOfByte[(2 + i * 4)] = ((byte)arrayOfInt1[i]);
- arrayOfByte[(3 + i * 4)] = -1;
- }
- GLES20.glTexImage2D(GLES20.GL_TEXTURE_2D, 0, GLES20.GL_RGBA, 256, 1, 0, GLES20.GL_RGBA, GLES20.GL_UNSIGNED_BYTE, ByteBuffer.wrap(arrayOfByte));
- }
- });
- }
-
- @Override
- public void onInputSizeChanged(int width, int height){
- super.onInputSizeChanged(width, height);
- GLES20.glUniform1f(mTexelWidthUniformLocation, 1.0f / width);
- GLES20.glUniform1f(mTexelHeightUniformLocation, 1.0f / height);
- }
-}
diff --git a/Live/src/main/java/com/seu/magicfilter/advanced/MagicHefeFilter.java b/Live/src/main/java/com/seu/magicfilter/advanced/MagicHefeFilter.java
deleted file mode 100644
index a7324e6d..00000000
--- a/Live/src/main/java/com/seu/magicfilter/advanced/MagicHefeFilter.java
+++ /dev/null
@@ -1,68 +0,0 @@
-package com.seu.magicfilter.advanced;
-
-import android.opengl.GLES20;
-
-import com.frank.live.R;
-import com.seu.magicfilter.base.gpuimage.GPUImageFilter;
-import com.seu.magicfilter.utils.MagicFilterType;
-import com.seu.magicfilter.utils.OpenGLUtils;
-
-public class MagicHefeFilter extends GPUImageFilter {
- private int[] inputTextureHandles = {-1,-1,-1,-1};
- private int[] inputTextureUniformLocations = {-1,-1,-1,-1};
- private int mGLStrengthLocation;
-
- public MagicHefeFilter(){
- super(MagicFilterType.HEFE, R.raw.hefe);
- }
-
- @Override
- protected void onDestroy() {
- super.onDestroy();
- GLES20.glDeleteTextures(inputTextureHandles.length, inputTextureHandles, 0);
- for(int i = 0; i < inputTextureHandles.length; i++) {
- inputTextureHandles[i] = -1;
- }
- }
-
- @Override
- protected void onDrawArraysAfter(){
- for(int i = 0; i < inputTextureHandles.length && inputTextureHandles[i] != OpenGLUtils.NO_TEXTURE; i++){
- GLES20.glActiveTexture(GLES20.GL_TEXTURE0 + (i+3));
- GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, 0);
- GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
- }
- }
-
- @Override
- protected void onDrawArraysPre(){
- for(int i = 0; i < inputTextureHandles.length && inputTextureHandles[i] != OpenGLUtils.NO_TEXTURE; i++){
- GLES20.glActiveTexture(GLES20.GL_TEXTURE0 + (i+3) );
- GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, inputTextureHandles[i]);
- GLES20.glUniform1i(inputTextureUniformLocations[i], (i+3));
- }
- }
-
- @Override
- protected void onInit(){
- super.onInit();
- for(int i=0; i < inputTextureUniformLocations.length; i++) {
- inputTextureUniformLocations[i] = GLES20.glGetUniformLocation(getProgram(), "inputImageTexture" + (2 + i));
- }
- mGLStrengthLocation = GLES20.glGetUniformLocation(getProgram(), "strength");
- }
-
- @Override
- protected void onInitialized(){
- super.onInitialized();
- setFloat(mGLStrengthLocation, 1.0f);
- runOnDraw(new Runnable(){
- public void run(){
- inputTextureHandles[0] = OpenGLUtils.loadTexture(getContext(), "filter/edgeburn.png");
- inputTextureHandles[1] = OpenGLUtils.loadTexture(getContext(), "filter/hefemap.png");
- inputTextureHandles[2] = OpenGLUtils.loadTexture(getContext(), "filter/hefemetal.png");
- inputTextureHandles[3] = OpenGLUtils.loadTexture(getContext(), "filter/hefesoftlight.png");
- }
- });
- }
-}
diff --git a/Live/src/main/java/com/seu/magicfilter/advanced/MagicHudsonFilter.java b/Live/src/main/java/com/seu/magicfilter/advanced/MagicHudsonFilter.java
deleted file mode 100644
index 10669c50..00000000
--- a/Live/src/main/java/com/seu/magicfilter/advanced/MagicHudsonFilter.java
+++ /dev/null
@@ -1,68 +0,0 @@
-package com.seu.magicfilter.advanced;
-
-import android.opengl.GLES20;
-
-import com.frank.live.R;
-import com.seu.magicfilter.base.gpuimage.GPUImageFilter;
-import com.seu.magicfilter.utils.MagicFilterType;
-import com.seu.magicfilter.utils.OpenGLUtils;
-
-public class MagicHudsonFilter extends GPUImageFilter {
- private int[] inputTextureHandles = {-1,-1,-1};
- private int[] inputTextureUniformLocations = {-1,-1,-1};
- private int mGLStrengthLocation;
-
- public MagicHudsonFilter(){
- super(MagicFilterType.HUDSON, R.raw.hudson);
- }
-
- @Override
- protected void onDestroy() {
- super.onDestroy();
- GLES20.glDeleteTextures(inputTextureHandles.length, inputTextureHandles, 0);
- for(int i = 0; i < inputTextureHandles.length; i++)
- inputTextureHandles[i] = -1;
- }
-
- @Override
- protected void onDrawArraysAfter(){
- for(int i = 0; i < inputTextureHandles.length
- && inputTextureHandles[i] != OpenGLUtils.NO_TEXTURE; i++){
- GLES20.glActiveTexture(GLES20.GL_TEXTURE0 + (i+3));
- GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, 0);
- GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
- }
- }
-
- @Override
- protected void onDrawArraysPre(){
- for(int i = 0; i < inputTextureHandles.length
- && inputTextureHandles[i] != OpenGLUtils.NO_TEXTURE; i++){
- GLES20.glActiveTexture(GLES20.GL_TEXTURE0 + (i+3) );
- GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, inputTextureHandles[i]);
- GLES20.glUniform1i(inputTextureUniformLocations[i], (i+3));
- }
- }
-
- @Override
- protected void onInit(){
- super.onInit();
- for(int i=0; i < inputTextureUniformLocations.length; i++) {
- inputTextureUniformLocations[i] = GLES20.glGetUniformLocation(getProgram(), "inputImageTexture" + (2 + i));
- }
- mGLStrengthLocation = GLES20.glGetUniformLocation(getProgram(), "strength");
- }
-
- @Override
- protected void onInitialized(){
- super.onInitialized();
- setFloat(mGLStrengthLocation, 1.0f);
- runOnDraw(new Runnable(){
- public void run(){
- inputTextureHandles[0] = OpenGLUtils.loadTexture(getContext(), "filter/ohudsonbackground.png");
- inputTextureHandles[1] = OpenGLUtils.loadTexture(getContext(), "filter/overlaymap.png");
- inputTextureHandles[2] = OpenGLUtils.loadTexture(getContext(), "filter/hudsonmap.png");
- }
- });
- }
-}
diff --git a/Live/src/main/java/com/seu/magicfilter/advanced/MagicImageAdjustFilter.java b/Live/src/main/java/com/seu/magicfilter/advanced/MagicImageAdjustFilter.java
deleted file mode 100644
index 6b1a027c..00000000
--- a/Live/src/main/java/com/seu/magicfilter/advanced/MagicImageAdjustFilter.java
+++ /dev/null
@@ -1,55 +0,0 @@
-package com.seu.magicfilter.advanced;
-
-import com.seu.magicfilter.base.MagicBaseGroupFilter;
-import com.seu.magicfilter.base.gpuimage.GPUImageBrightnessFilter;
-import com.seu.magicfilter.base.gpuimage.GPUImageContrastFilter;
-import com.seu.magicfilter.base.gpuimage.GPUImageExposureFilter;
-import com.seu.magicfilter.base.gpuimage.GPUImageFilter;
-import com.seu.magicfilter.base.gpuimage.GPUImageHueFilter;
-import com.seu.magicfilter.base.gpuimage.GPUImageSaturationFilter;
-import com.seu.magicfilter.base.gpuimage.GPUImageSharpenFilter;
-
-import java.util.ArrayList;
-import java.util.List;
-
-public class MagicImageAdjustFilter extends MagicBaseGroupFilter {
-
- public MagicImageAdjustFilter() {
- super(initFilters());
- }
-
- private static List initFilters(){
- List filters = new ArrayList();
- filters.add(new GPUImageContrastFilter());
- filters.add(new GPUImageBrightnessFilter());
- filters.add(new GPUImageExposureFilter());
- filters.add(new GPUImageHueFilter());
- filters.add(new GPUImageSaturationFilter());
- filters.add(new GPUImageSharpenFilter());
- return filters;
- }
-
- public void setSharpness(final float range){
- ((GPUImageSharpenFilter) filters.get(5)).setSharpness(range);
- }
-
- public void setHue(final float range){
- ((GPUImageHueFilter) filters.get(3)).setHue(range);
- }
-
- public void setBrightness(final float range){
- ((GPUImageBrightnessFilter) filters.get(1)).setBrightness(range);
- }
-
- public void setContrast(final float range){
- ((GPUImageContrastFilter) filters.get(0)).setContrast(range);
- }
-
- public void setSaturation(final float range){
- ((GPUImageSaturationFilter) filters.get(4)).setSaturation(range);
- }
-
- public void setExposure(final float range){
- ((GPUImageExposureFilter) filters.get(2)).setExposure(range);
- }
-}
diff --git a/Live/src/main/java/com/seu/magicfilter/advanced/MagicInkwellFilter.java b/Live/src/main/java/com/seu/magicfilter/advanced/MagicInkwellFilter.java
deleted file mode 100644
index da48b76f..00000000
--- a/Live/src/main/java/com/seu/magicfilter/advanced/MagicInkwellFilter.java
+++ /dev/null
@@ -1,66 +0,0 @@
-package com.seu.magicfilter.advanced;
-
-import android.opengl.GLES20;
-
-import com.frank.live.R;
-import com.seu.magicfilter.base.gpuimage.GPUImageFilter;
-import com.seu.magicfilter.utils.MagicFilterType;
-import com.seu.magicfilter.utils.OpenGLUtils;
-
-public class MagicInkwellFilter extends GPUImageFilter {
- private int[] inputTextureHandles = {-1};
- private int[] inputTextureUniformLocations = {-1};
- private int mGLStrengthLocation;
-
- public MagicInkwellFilter(){
- super(MagicFilterType.INKWELL, R.raw.inkwell);
- }
-
- @Override
- protected void onDestroy() {
- super.onDestroy();
- GLES20.glDeleteTextures(1, inputTextureHandles, 0);
- for(int i = 0; i < inputTextureHandles.length; i++)
- inputTextureHandles[i] = -1;
- }
-
- @Override
- protected void onDrawArraysAfter(){
- for(int i = 0; i < inputTextureHandles.length
- && inputTextureHandles[i] != OpenGLUtils.NO_TEXTURE; i++){
- GLES20.glActiveTexture(GLES20.GL_TEXTURE0 + (i+3));
- GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, 0);
- GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
- }
- }
-
- @Override
- protected void onDrawArraysPre(){
- for(int i = 0; i < inputTextureHandles.length
- && inputTextureHandles[i] != OpenGLUtils.NO_TEXTURE; i++){
- GLES20.glActiveTexture(GLES20.GL_TEXTURE0 + (i+3) );
- GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, inputTextureHandles[i]);
- GLES20.glUniform1i(inputTextureUniformLocations[i], (i+3));
- }
- }
-
- @Override
- protected void onInit(){
- super.onInit();
- for(int i = 0; i < inputTextureUniformLocations.length; i++) {
- inputTextureUniformLocations[i] = GLES20.glGetUniformLocation(getProgram(), "inputImageTexture" + (2 + i));
- }
- mGLStrengthLocation = GLES20.glGetUniformLocation(getProgram(), "strength");
- }
-
- @Override
- protected void onInitialized(){
- super.onInitialized();
- setFloat(mGLStrengthLocation, 1.0f);
- runOnDraw(new Runnable(){
- public void run(){
- inputTextureHandles[0] = OpenGLUtils.loadTexture(getContext(), "filter/inkwellmap.png");
- }
- });
- }
-}
diff --git a/Live/src/main/java/com/seu/magicfilter/advanced/MagicKevinFilter.java b/Live/src/main/java/com/seu/magicfilter/advanced/MagicKevinFilter.java
deleted file mode 100644
index 3e444233..00000000
--- a/Live/src/main/java/com/seu/magicfilter/advanced/MagicKevinFilter.java
+++ /dev/null
@@ -1,65 +0,0 @@
-package com.seu.magicfilter.advanced;
-
-import android.opengl.GLES20;
-
-import com.frank.live.R;
-import com.seu.magicfilter.base.gpuimage.GPUImageFilter;
-import com.seu.magicfilter.utils.MagicFilterType;
-import com.seu.magicfilter.utils.OpenGLUtils;
-
-public class MagicKevinFilter extends GPUImageFilter {
- private int[] inputTextureHandles = {-1};
- private int[] inputTextureUniformLocations = {-1};
- private int mGLStrengthLocation;
-
- public MagicKevinFilter(){
- super(MagicFilterType.KEVIN, R.raw.kevin_new);
- }
-
- @Override
- protected void onDestroy() {
- super.onDestroy();
- GLES20.glDeleteTextures(1, inputTextureHandles, 0);
- for (int i = 0; i < inputTextureHandles.length; i++) {
- inputTextureHandles[i] = -1;
- }
- }
-
- @Override
- protected void onDrawArraysAfter(){
- for(int i = 0; i < inputTextureHandles.length && inputTextureHandles[i] != OpenGLUtils.NO_TEXTURE; i++){
- GLES20.glActiveTexture(GLES20.GL_TEXTURE0 + (i+3));
- GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, 0);
- GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
- }
- }
-
- @Override
- protected void onDrawArraysPre(){
- for(int i = 0; i < inputTextureHandles.length && inputTextureHandles[i] != OpenGLUtils.NO_TEXTURE; i++){
- GLES20.glActiveTexture(GLES20.GL_TEXTURE0 + (i+3) );
- GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, inputTextureHandles[i]);
- GLES20.glUniform1i(inputTextureUniformLocations[i], (i+3));
- }
- }
-
- @Override
- protected void onInit(){
- super.onInit();
- for(int i = 0; i < inputTextureUniformLocations.length; i++) {
- inputTextureUniformLocations[i] = GLES20.glGetUniformLocation(getProgram(), "inputImageTexture" + (2 + i));
- }
- mGLStrengthLocation = GLES20.glGetUniformLocation(getProgram(), "strength");
- }
-
- @Override
- protected void onInitialized(){
- super.onInitialized();
- setFloat(mGLStrengthLocation, 1.0f);
- runOnDraw(new Runnable(){
- public void run(){
- inputTextureHandles[0] = OpenGLUtils.loadTexture(getContext(), "filter/kelvinmap.png");
- }
- });
- }
-}
diff --git a/Live/src/main/java/com/seu/magicfilter/advanced/MagicLatteFilter.java b/Live/src/main/java/com/seu/magicfilter/advanced/MagicLatteFilter.java
deleted file mode 100644
index d6f5a6ab..00000000
--- a/Live/src/main/java/com/seu/magicfilter/advanced/MagicLatteFilter.java
+++ /dev/null
@@ -1,88 +0,0 @@
-package com.seu.magicfilter.advanced;
-
-import android.opengl.GLES20;
-
-import com.frank.live.R;
-import com.seu.magicfilter.base.gpuimage.GPUImageFilter;
-import com.seu.magicfilter.utils.MagicFilterType;
-
-import java.nio.ByteBuffer;
-
-public class MagicLatteFilter extends GPUImageFilter {
- private int[] mToneCurveTexture = {-1};
- private int mToneCurveTextureUniformLocation;
-
- public MagicLatteFilter(){
- super(MagicFilterType.LATTE, R.raw.latte);
- }
-
- @Override
- protected void onDestroy(){
- super.onDestroy();
- GLES20.glDeleteTextures(1, mToneCurveTexture, 0);
- mToneCurveTexture[0] = -1;
- }
-
- @Override
- protected void onDrawArraysAfter(){
- if (mToneCurveTexture[0] != -1){
- GLES20.glActiveTexture(GLES20.GL_TEXTURE3);
- GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, 0);
- GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
- }
- }
-
- @Override
- protected void onDrawArraysPre(){
- if (mToneCurveTexture[0] != -1){
- GLES20.glActiveTexture(GLES20.GL_TEXTURE3);
- GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mToneCurveTexture[0]);
- GLES20.glUniform1i(mToneCurveTextureUniformLocation, 3);
- }
- }
-
- @Override
- protected void onInit(){
- super.onInit();
- mToneCurveTextureUniformLocation = GLES20.glGetUniformLocation(getProgram(), "curve");
- }
-
- @Override
- protected void onInitialized(){
- super.onInitialized();
- runOnDraw(new Runnable(){
- public void run(){
- GLES20.glGenTextures(1, mToneCurveTexture, 0);
- GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mToneCurveTexture[0]);
- GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D,
- GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR);
- GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D,
- GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_LINEAR);
- GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D,
- GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_CLAMP_TO_EDGE);
- GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D,
- GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_CLAMP_TO_EDGE);
- byte[] arrayOfByte = new byte[2048];
- int[] arrayOfInt1 = { 5, 6, 8, 9, 11, 12, 14, 15, 16, 18, 19, 21, 22, 23, 25, 26, 28, 29, 30, 32, 33, 34, 36, 37, 39, 40, 41, 43, 44, 45, 46, 48, 49, 50, 52, 53, 54, 55, 56, 58, 59, 60, 61, 62, 64, 65, 66, 67, 68, 69, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 108, 109, 110, 111, 112, 113, 114, 115, 115, 116, 117, 118, 119, 120, 120, 121, 122, 123, 124, 125, 125, 126, 127, 128, 129, 130, 130, 131, 132, 133, 134, 134, 135, 136, 137, 137, 138, 139, 140, 141, 141, 142, 143, 144, 145, 145, 146, 147, 148, 148, 149, 150, 151, 151, 152, 153, 154, 155, 155, 156, 157, 158, 158, 159, 160, 161, 162, 162, 163, 164, 165, 166, 166, 167, 168, 169, 170, 170, 171, 172, 173, 174, 174, 175, 176, 177, 178, 178, 179, 180, 181, 182, 183, 183, 184, 185, 186, 187, 188, 189, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 215, 216, 217, 218, 219, 220, 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 237, 238, 239, 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255 };
- int[] arrayOfInt2 = { 5, 6, 8, 11, 12, 14, 15, 18, 19, 21, 22, 25, 26, 28, 29, 32, 33, 34, 36, 39, 40, 41, 43, 44, 46, 48, 49, 50, 52, 54, 55, 56, 58, 59, 61, 62, 64, 65, 66, 67, 69, 71, 72, 73, 74, 75, 76, 78, 79, 80, 81, 82, 83, 85, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 108, 108, 109, 110, 111, 112, 113, 114, 115, 115, 116, 117, 118, 119, 120, 120, 121, 122, 123, 125, 125, 126, 127, 128, 129, 130, 130, 131, 132, 133, 134, 134, 135, 136, 137, 137, 138, 139, 140, 141, 141, 142, 143, 144, 145, 145, 146, 147, 148, 148, 149, 149, 150, 151, 151, 152, 153, 154, 155, 155, 156, 157, 158, 158, 159, 160, 161, 162, 162, 163, 164, 165, 165, 166, 166, 167, 168, 169, 170, 170, 171, 172, 173, 174, 174, 175, 175, 176, 177, 178, 178, 179, 180, 181, 182, 183, 183, 184, 184, 185, 186, 187, 188, 189, 189, 190, 191, 192, 192, 193, 194, 195, 196, 197, 198, 198, 199, 199, 200, 201, 202, 203, 204, 205, 206, 206, 207, 208, 209, 210, 211, 212, 213, 213, 214, 215, 215, 216, 217, 218, 219, 219, 220, 221, 222, 223, 224, 225, 226, 226, 227, 228, 229, 230, 231, 232, 232, 233, 234, 235, 237, 238, 239, 240, 240, 241, 242, 243, 244, 245, 246, 246, 247, 248, 249, 250, 251, 252, 252, 253, 254, 255 };
- int[] arrayOfInt3 = { 5, 6, 8, 11, 12, 14, 15, 16, 18, 21, 22, 23, 25, 26, 28, 30, 32, 33, 34, 36, 37, 40, 41, 43, 44, 45, 46, 49, 50, 52, 53, 54, 55, 58, 59, 60, 61, 62, 64, 66, 67, 68, 69, 71, 72, 73, 75, 76, 77, 78, 79, 80, 81, 83, 85, 86, 87, 88, 89, 90, 92, 93, 94, 95, 95, 96, 97, 98, 99, 101, 102, 103, 104, 105, 106, 107, 108, 108, 109, 111, 112, 113, 114, 115, 115, 116, 117, 118, 119, 120, 120, 121, 123, 124, 125, 125, 126, 127, 128, 129, 130, 130, 131, 132, 133, 134, 134, 135, 136, 137, 137, 138, 139, 140, 141, 141, 142, 143, 144, 145, 145, 146, 147, 148, 148, 149, 150, 151, 151, 152, 153, 154, 155, 155, 156, 156, 157, 158, 158, 159, 160, 161, 162, 162, 163, 164, 165, 165, 166, 166, 167, 168, 169, 170, 170, 170, 171, 172, 173, 174, 174, 175, 176, 176, 177, 178, 178, 179, 180, 180, 181, 182, 183, 183, 184, 184, 185, 186, 187, 188, 189, 189, 189, 190, 191, 192, 192, 193, 194, 195, 196, 196, 197, 198, 198, 199, 199, 200, 201, 202, 202, 203, 204, 205, 206, 206, 207, 208, 209, 209, 210, 211, 212, 213, 213, 214, 215, 215, 215, 216, 217, 218, 218, 219, 220, 221, 221, 222, 223, 224, 224, 225, 226, 227, 227, 228, 229, 230, 230, 231, 232, 233, 233, 234, 235, 237, 237, 238, 239, 240, 240, 241, 242, 243, 243, 244 };
- for (int i = 0; i < 256; i++){
- arrayOfByte[(i * 4)] = ((byte)arrayOfInt1[i]);
- arrayOfByte[(1 + i * 4)] = ((byte)arrayOfInt2[i]);
- arrayOfByte[(2 + i * 4)] = ((byte)arrayOfInt3[i]);
- arrayOfByte[(3 + i * 4)] = -1;
- }
- int[] arrayOfInt4 = { 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 9, 10, 12, 13, 14, 15, 16, 18, 19, 20, 21, 22, 24, 25, 26, 27, 28, 30, 31, 32, 33, 34, 36, 37, 38, 39, 40, 42, 43, 44, 45, 46, 48, 49, 50, 51, 52, 54, 55, 56, 57, 58, 60, 61, 62, 63, 64, 66, 67, 68, 69, 71, 72, 73, 74, 75, 77, 78, 79, 80, 81, 83, 84, 85, 86, 87, 89, 90, 91, 92, 93, 95, 96, 97, 98, 99, 101, 102, 103, 104, 105, 107, 108, 109, 110, 111, 113, 114, 115, 116, 117, 119, 120, 121, 122, 123, 125, 126, 127, 128, 129, 131, 132, 133, 134, 135, 137, 138, 139, 140, 141, 143, 144, 145, 146, 147, 149, 150, 151, 152, 153, 155, 156, 157, 158, 159, 161, 162, 163, 164, 165, 167, 168, 169, 170, 171, 173, 174, 175, 176, 177, 179, 180, 181, 182, 184, 185, 186, 187, 188, 190, 191, 192, 193, 194, 196, 197, 198, 199, 200, 202, 203, 204, 205, 206, 208, 209, 210, 211, 212, 214, 215, 216, 217, 218, 220, 221, 222, 223, 224, 226, 227, 228, 229, 230, 232, 233, 234, 235, 236, 238, 239, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240 };
- int[] arrayOfInt5 = { 0, 1, 2, 3, 4, 6, 7, 8, 9, 10, 11, 12, 13, 15, 16, 17, 18, 19, 20, 21, 23, 24, 25, 26, 27, 29, 30, 31, 32, 33, 35, 36, 37, 38, 39, 41, 42, 43, 44, 46, 47, 48, 49, 51, 52, 53, 54, 56, 57, 58, 59, 61, 62, 63, 65, 66, 67, 69, 70, 71, 73, 74, 75, 77, 78, 79, 81, 82, 83, 85, 86, 87, 89, 90, 92, 93, 94, 96, 97, 99, 100, 101, 103, 104, 106, 107, 108, 110, 111, 113, 114, 116, 117, 119, 120, 121, 123, 124, 126, 127, 129, 130, 132, 133, 135, 136, 138, 139, 140, 142, 143, 145, 146, 147, 149, 150, 151, 153, 154, 155, 157, 158, 159, 160, 162, 163, 164, 165, 167, 168, 169, 170, 171, 173, 174, 175, 176, 177, 178, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 210, 211, 212, 213, 214, 215, 215, 216, 217, 218, 219, 219, 220, 221, 222, 222, 223, 224, 225, 225, 226, 227, 227, 228, 229, 229, 230, 231, 231, 232, 233, 233, 234, 234, 235, 236, 236, 237, 237, 238, 238, 239, 240, 240, 241, 241, 242, 242, 243, 243, 244, 244, 244, 245, 245, 246, 246, 247, 247, 247, 248, 248, 249, 249, 249, 250, 250, 250, 251, 251, 251, 252, 252, 252, 252, 253, 253, 253, 253, 254, 254, 254, 254, 255, 255, 255 };
- int[] arrayOfInt6 = { 0, 0, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 5, 5, 5, 6, 6, 6, 7, 7, 8, 8, 8, 9, 9, 10, 10, 10, 11, 11, 11, 12, 12, 13, 13, 13, 14, 14, 14, 15, 15, 16, 16, 16, 17, 17, 17, 18, 18, 18, 19, 19, 20, 20, 20, 21, 21, 21, 22, 22, 23, 23, 23, 24, 24, 24, 25, 25, 25, 25, 26, 26, 27, 27, 28, 28, 28, 28, 29, 29, 30, 29, 31, 31, 31, 31, 32, 32, 33, 33, 34, 34, 34, 34, 35, 35, 36, 36, 37, 37, 37, 38, 38, 39, 39, 39, 40, 40, 40, 41, 42, 42, 43, 43, 44, 44, 45, 45, 45, 46, 47, 47, 48, 48, 49, 50, 51, 51, 52, 52, 53, 53, 54, 55, 55, 56, 57, 57, 58, 59, 60, 60, 61, 62, 63, 63, 64, 65, 66, 67, 68, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 88, 89, 90, 91, 93, 94, 95, 96, 97, 98, 100, 101, 103, 104, 105, 107, 108, 110, 111, 113, 115, 116, 118, 119, 120, 122, 123, 125, 127, 128, 130, 132, 134, 135, 137, 139, 141, 143, 144, 146, 148, 150, 152, 154, 156, 158, 160, 163, 165, 167, 169, 171, 173, 175, 178, 180, 182, 185, 187, 189, 192, 194, 197, 199, 201, 204, 206, 209, 211, 214, 216, 219, 221, 224, 226, 229, 232, 234, 236, 239, 241, 245, 247, 250, 252, 255 };
- for (int j = 0; j < 256; j++){
- arrayOfByte[(1024 + j * 4)] = ((byte)arrayOfInt5[j]);
- arrayOfByte[(1 + (1024 + j * 4))] = ((byte)arrayOfInt4[j]);
- arrayOfByte[(2 + (1024 + j * 4))] = ((byte)arrayOfInt6[j]);
- arrayOfByte[(3 + (1024 + j * 4))] = -1;
- }
- GLES20.glTexImage2D(GLES20.GL_TEXTURE_2D, 0, GLES20.GL_RGBA, 256, 2, 0, GLES20.GL_RGBA, GLES20.GL_UNSIGNED_BYTE, ByteBuffer.wrap(arrayOfByte));
- }
- });
- }
-}
diff --git a/Live/src/main/java/com/seu/magicfilter/advanced/MagicLomoFilter.java b/Live/src/main/java/com/seu/magicfilter/advanced/MagicLomoFilter.java
deleted file mode 100644
index d81f990a..00000000
--- a/Live/src/main/java/com/seu/magicfilter/advanced/MagicLomoFilter.java
+++ /dev/null
@@ -1,67 +0,0 @@
-package com.seu.magicfilter.advanced;
-
-import android.opengl.GLES20;
-
-import com.frank.live.R;
-import com.seu.magicfilter.base.gpuimage.GPUImageFilter;
-import com.seu.magicfilter.utils.MagicFilterType;
-import com.seu.magicfilter.utils.OpenGLUtils;
-
-public class MagicLomoFilter extends GPUImageFilter{
- private int[] inputTextureHandles = {-1,-1};
- private int[] inputTextureUniformLocations = {-1,-1};
- private int mGLStrengthLocation;
-
- public MagicLomoFilter(){
- super(MagicFilterType.LOMO, R.raw.lomo);
- }
-
- @Override
- protected void onDestroy() {
- super.onDestroy();
- GLES20.glDeleteTextures(inputTextureHandles.length, inputTextureHandles, 0);
- for(int i = 0; i < inputTextureHandles.length; i++)
- inputTextureHandles[i] = -1;
- }
-
- @Override
- protected void onDrawArraysAfter(){
- for(int i = 0; i < inputTextureHandles.length
- && inputTextureHandles[i] != OpenGLUtils.NO_TEXTURE; i++){
- GLES20.glActiveTexture(GLES20.GL_TEXTURE0 + (i+3));
- GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, 0);
- GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
- }
- }
-
- @Override
- protected void onDrawArraysPre(){
- for(int i = 0; i < inputTextureHandles.length
- && inputTextureHandles[i] != OpenGLUtils.NO_TEXTURE; i++){
- GLES20.glActiveTexture(GLES20.GL_TEXTURE0 + (i+3) );
- GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, inputTextureHandles[i]);
- GLES20.glUniform1i(inputTextureUniformLocations[i], (i+3));
- }
- }
-
- @Override
- protected void onInit(){
- super.onInit();
- for(int i=0; i < inputTextureUniformLocations.length; i++) {
- inputTextureUniformLocations[i] = GLES20.glGetUniformLocation(getProgram(), "inputImageTexture" + (2 + i));
- }
- mGLStrengthLocation = GLES20.glGetUniformLocation(getProgram(), "strength");
- }
-
- @Override
- protected void onInitialized(){
- super.onInitialized();
- setFloat(mGLStrengthLocation, 1.0f);
- runOnDraw(new Runnable(){
- public void run(){
- inputTextureHandles[0] = OpenGLUtils.loadTexture(getContext(), "filter/vlomomap_new.png");
- inputTextureHandles[1] = OpenGLUtils.loadTexture(getContext(), "filter/vignette_map.png");
- }
- });
- }
-}
diff --git a/Live/src/main/java/com/seu/magicfilter/advanced/MagicN1977Filter.java b/Live/src/main/java/com/seu/magicfilter/advanced/MagicN1977Filter.java
deleted file mode 100644
index 2b964cc2..00000000
--- a/Live/src/main/java/com/seu/magicfilter/advanced/MagicN1977Filter.java
+++ /dev/null
@@ -1,59 +0,0 @@
-package com.seu.magicfilter.advanced;
-
-import android.opengl.GLES20;
-
-import com.frank.live.R;
-import com.seu.magicfilter.base.gpuimage.GPUImageFilter;
-import com.seu.magicfilter.utils.MagicFilterType;
-import com.seu.magicfilter.utils.OpenGLUtils;
-
-public class MagicN1977Filter extends GPUImageFilter{
- private int[] inputTextureHandles = {-1,-1};
- private int[] inputTextureUniformLocations = {-1,-1};
- private int mGLStrengthLocation;
-
- public MagicN1977Filter(){
- super(MagicFilterType.N1977, R.raw.n1977);
- }
-
- @Override
- protected void onDrawArraysAfter(){
- for(int i = 0; i < inputTextureHandles.length
- && inputTextureHandles[i] != OpenGLUtils.NO_TEXTURE; i++){
- GLES20.glActiveTexture(GLES20.GL_TEXTURE0 + (i+3));
- GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, 0);
- GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
- }
- }
-
- @Override
- protected void onDrawArraysPre(){
- for(int i = 0; i < inputTextureHandles.length
- && inputTextureHandles[i] != OpenGLUtils.NO_TEXTURE; i++){
- GLES20.glActiveTexture(GLES20.GL_TEXTURE0 + (i+3) );
- GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, inputTextureHandles[i]);
- GLES20.glUniform1i(inputTextureUniformLocations[i], (i+3));
- }
- }
-
- @Override
- protected void onInit(){
- super.onInit();
- for(int i=0; i < inputTextureUniformLocations.length; i++) {
- inputTextureUniformLocations[i] = GLES20.glGetUniformLocation(getProgram(), "inputImageTexture" + (2 + i));
- }
- mGLStrengthLocation = GLES20.glGetUniformLocation(getProgram(), "strength");
- }
-
- @Override
- protected void onInitialized(){
- super.onInitialized();
- setFloat(mGLStrengthLocation, 1.0f);
- runOnDraw(new Runnable(){
- public void run(){
- inputTextureHandles[0] = OpenGLUtils.loadTexture(getContext(), "filter/n1977map.png");
- inputTextureHandles[1] = OpenGLUtils.loadTexture(getContext(), "filter/n1977blowout.png");
- }
- });
- }
-}
diff --git a/Live/src/main/java/com/seu/magicfilter/advanced/MagicNashvilleFilter.java b/Live/src/main/java/com/seu/magicfilter/advanced/MagicNashvilleFilter.java
deleted file mode 100644
index d5e73770..00000000
--- a/Live/src/main/java/com/seu/magicfilter/advanced/MagicNashvilleFilter.java
+++ /dev/null
@@ -1,65 +0,0 @@
-package com.seu.magicfilter.advanced;
-
-import android.opengl.GLES20;
-
-import com.frank.live.R;
-import com.seu.magicfilter.base.gpuimage.GPUImageFilter;
-import com.seu.magicfilter.utils.MagicFilterType;
-import com.seu.magicfilter.utils.OpenGLUtils;
-
-public class MagicNashvilleFilter extends GPUImageFilter {
- private int[] inputTextureHandles = {-1};
- private int[] inputTextureUniformLocations = {-1};
- private int mGLStrengthLocation;
-
- public MagicNashvilleFilter(){
- super(MagicFilterType.NASHVILLE, R.raw.nashville);
- }
-
- @Override
- protected void onDestroy() {
- super.onDestroy();
- GLES20.glDeleteTextures(1, inputTextureHandles, 0);
- for(int i = 0; i < inputTextureHandles.length; i++) {
- inputTextureHandles[i] = -1;
- }
- }
-
- @Override
- protected void onDrawArraysAfter(){
- for(int i = 0; i < inputTextureHandles.length && inputTextureHandles[i] != OpenGLUtils.NO_TEXTURE; i++){
- GLES20.glActiveTexture(GLES20.GL_TEXTURE0 + (i+3));
- GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, 0);
- GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
- }
- }
-
- @Override
- protected void onDrawArraysPre(){
- for(int i = 0; i < inputTextureHandles.length && inputTextureHandles[i] != OpenGLUtils.NO_TEXTURE; i++){
- GLES20.glActiveTexture(GLES20.GL_TEXTURE0 + (i+3) );
- GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, inputTextureHandles[i]);
- GLES20.glUniform1i(inputTextureUniformLocations[i], (i+3));
- }
- }
-
- @Override
- protected void onInit(){
- super.onInit();
- for(int i=0; i < inputTextureUniformLocations.length; i++) {
- inputTextureUniformLocations[i] = GLES20.glGetUniformLocation(getProgram(), "inputImageTexture" + (2 + i));
- }
- mGLStrengthLocation = GLES20.glGetUniformLocation(getProgram(), "strength");
- }
-
- @Override
- protected void onInitialized(){
- super.onInitialized();
- setFloat(mGLStrengthLocation, 1.0f);
- runOnDraw(new Runnable(){
- public void run(){
- inputTextureHandles[0] = OpenGLUtils.loadTexture(getContext(), "filter/nashvillemap.png");
- }
- });
- }
-}
diff --git a/Live/src/main/java/com/seu/magicfilter/advanced/MagicNostalgiaFilter.java b/Live/src/main/java/com/seu/magicfilter/advanced/MagicNostalgiaFilter.java
deleted file mode 100644
index 1db368e0..00000000
--- a/Live/src/main/java/com/seu/magicfilter/advanced/MagicNostalgiaFilter.java
+++ /dev/null
@@ -1,140 +0,0 @@
-package com.seu.magicfilter.advanced;
-
-import android.opengl.GLES20;
-
-import com.frank.live.R;
-import com.seu.magicfilter.base.gpuimage.GPUImageFilter;
-import com.seu.magicfilter.utils.MagicFilterType;
-
-import java.nio.ByteBuffer;
-
-public class MagicNostalgiaFilter extends GPUImageFilter {
- private int mBlurSizeUniformLocation;
- private int mTexelWidthUniformLocation;
- private int mTexelHeightUniformLocation;
- private int[] mToneCurveTexture = { -1 };
- private int[] mToneCurveTexture2 = { -1 };
- private int mToneCurveTextureUniformLocation;
- private int mToneCurveTextureUniformLocation2;
-
- public MagicNostalgiaFilter(){
- super(MagicFilterType.NOSTALGIA, R.raw.nostalgia);
- }
-
- @Override
- protected void onDestroy(){
- super.onDestroy();
- GLES20.glDeleteTextures(1, mToneCurveTexture, 0);
- mToneCurveTexture[0] = -1;
- GLES20.glDeleteTextures(1, mToneCurveTexture2, 0);
- mToneCurveTexture2[0] = -1;
- }
-
- @Override
- protected void onDrawArraysAfter(){
- if (mToneCurveTexture[0] != -1){
- GLES20.glActiveTexture(GLES20.GL_TEXTURE3);
- GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, 0);
- GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
- }
- if (mToneCurveTexture2[0] != -1){
- GLES20.glActiveTexture(GLES20.GL_TEXTURE4);
- GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, 0);
- GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
- }
- }
-
- @Override
- protected void onDrawArraysPre(){
- if (mToneCurveTexture[0] != -1){
- GLES20.glActiveTexture(GLES20.GL_TEXTURE3);
- GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mToneCurveTexture[0]);
- GLES20.glUniform1i(mToneCurveTextureUniformLocation, 3);
- }
- if (mToneCurveTexture2[0] != -1){
- GLES20.glActiveTexture(GLES20.GL_TEXTURE4);
- GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mToneCurveTexture[0]);
- GLES20.glUniform1i(mToneCurveTextureUniformLocation2, 4);
- }
- GLES20.glUniform1f(mBlurSizeUniformLocation, 1.0F);
- }
-
- @Override
- protected void onInit(){
- super.onInit();
- mToneCurveTextureUniformLocation = GLES20.glGetUniformLocation(getProgram(), "curve");
- mToneCurveTextureUniformLocation2 = GLES20.glGetUniformLocation(getProgram(), "curve2");
- mTexelWidthUniformLocation = GLES20.glGetUniformLocation(getProgram(), "texelWidthOffset");
- mTexelHeightUniformLocation = GLES20.glGetUniformLocation(getProgram(), "texelHeightOffset");
- mBlurSizeUniformLocation = GLES20.glGetUniformLocation(getProgram(), "blurSize");
- }
-
- @Override
- protected void onInitialized(){
- super.onInitialized();
- runOnDraw(new Runnable(){
- public void run(){
- GLES20.glGenTextures(1, mToneCurveTexture, 0);
- GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mToneCurveTexture[0]);
- GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D,
- GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR);
- GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D,
- GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_LINEAR);
- GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D,
- GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_CLAMP_TO_EDGE);
- GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D,
- GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_CLAMP_TO_EDGE);
- byte[] arrayOfByte1 = new byte[2048];
- int[] arrayOfInt1 = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 5, 6, 8, 9, 11, 13, 15, 16, 18, 20, 22, 24, 26, 28, 30, 32, 34, 36, 38, 39, 41, 43, 45, 47, 49, 50, 52, 54, 56, 57, 59, 61, 62, 64, 66, 68, 69, 71, 72, 74, 76, 77, 79, 80, 82, 84, 85, 87, 88, 90, 91, 93, 94, 96, 97, 98, 100, 101, 103, 104, 106, 107, 108, 110, 111, 112, 114, 115, 116, 118, 119, 120, 122, 123, 124, 125, 127, 128, 129, 130, 131, 133, 134, 135, 136, 137, 138, 140, 141, 142, 143, 144, 145, 146, 147, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 174, 175, 176, 177, 178, 179, 180, 181, 182, 182, 183, 184, 185, 186, 187, 188, 188, 189, 190, 191, 192, 193, 193, 194, 195, 196, 197, 197, 198, 199, 200, 201, 201, 202, 203, 204, 204, 205, 206, 207, 207, 208, 209, 210, 210, 211, 212, 213, 213, 214, 215, 216, 216, 217, 218, 219, 219, 220, 221, 221, 222, 223, 224, 224, 225, 226, 226, 227, 228, 228, 229, 230, 231, 231, 232, 233, 233, 234, 235, 235, 236, 237, 237, 238, 239, 240, 240, 241, 242, 242, 243, 244, 244, 245, 246, 246, 247, 248, 248, 249, 250, 250, 251, 252, 252, 253, 254, 254, 255 };
- int[] arrayOfInt2 = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 3, 4, 6, 7, 9, 10, 12, 13, 14, 16, 17, 19, 20, 22, 23, 24, 26, 27, 29, 30, 32, 33, 34, 36, 37, 39, 40, 42, 43, 44, 46, 47, 49, 50, 52, 53, 54, 56, 57, 59, 60, 61, 63, 64, 66, 67, 69, 70, 71, 73, 74, 75, 77, 78, 80, 81, 82, 84, 85, 87, 88, 89, 91, 92, 93, 95, 96, 97, 99, 100, 101, 103, 104, 105, 107, 108, 109, 111, 112, 113, 115, 116, 117, 119, 120, 121, 122, 124, 125, 126, 127, 129, 130, 131, 132, 134, 135, 136, 137, 139, 140, 141, 142, 144, 145, 146, 147, 148, 149, 151, 152, 153, 154, 155, 156, 158, 159, 160, 161, 162, 163, 164, 165, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 198, 199, 200, 201, 202, 203, 204, 204, 205, 206, 207, 208, 209, 209, 210, 211, 212, 213, 213, 214, 215, 216, 216, 217, 218, 219, 219, 220, 221, 222, 222, 223, 224, 225, 225, 226, 227, 227, 228, 229, 229, 230, 231, 231, 232, 233, 233, 234, 235, 235, 236, 237, 237, 238, 239, 239, 240, 241, 241, 242, 243, 243, 244, 244, 245, 246, 246, 247, 248, 248, 249, 249, 250, 251, 251, 252, 253, 253, 254, 254, 255 };
- int[] arrayOfInt3 = { 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 31, 33, 35, 37, 39, 41, 43, 44, 46, 48, 50, 52, 54, 56, 58, 60, 62, 64, 65, 67, 69, 71, 73, 75, 76, 78, 80, 82, 84, 85, 87, 89, 91, 92, 94, 96, 98, 99, 101, 102, 104, 106, 107, 109, 110, 112, 114, 115, 117, 118, 119, 121, 122, 124, 125, 126, 128, 129, 130, 132, 133, 134, 135, 137, 138, 139, 140, 141, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 166, 167, 168, 169, 170, 171, 171, 172, 173, 174, 175, 175, 176, 177, 178, 178, 179, 180, 181, 181, 182, 183, 184, 184, 185, 186, 186, 187, 188, 189, 189, 190, 191, 191, 192, 193, 193, 194, 195, 195, 196, 197, 197, 198, 199, 200, 200, 201, 202, 202, 203, 204, 204, 205, 206, 206, 207, 208, 208, 209, 210, 210, 211, 212, 212, 213, 214, 214, 215, 216, 216, 217, 218, 218, 219, 220, 220, 221, 221, 222, 223, 223, 224, 225, 225, 226, 227, 227, 228, 229, 229, 230, 231, 231, 232, 233, 233, 234, 234, 235, 236, 236, 237, 238, 238, 239, 240, 240, 241, 242, 242, 243, 243, 244, 245, 245, 246, 247, 247, 248, 249, 249, 250, 251, 251, 252, 252, 253, 254, 254, 255 };
- int[] arrayOfInt4 = { 0, 0, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 5, 5, 5, 6, 6, 6, 7, 7, 8, 8, 8, 9, 9, 10, 10, 10, 11, 11, 11, 12, 12, 13, 13, 13, 14, 14, 14, 15, 15, 16, 16, 16, 17, 17, 17, 18, 18, 18, 19, 19, 20, 20, 20, 21, 21, 21, 22, 22, 23, 23, 23, 24, 24, 24, 25, 25, 25, 25, 26, 26, 27, 27, 28, 28, 28, 28, 29, 29, 30, 29, 31, 31, 31, 31, 32, 32, 33, 33, 34, 34, 34, 34, 35, 35, 36, 36, 37, 37, 37, 38, 38, 39, 39, 39, 40, 40, 40, 41, 42, 42, 43, 43, 44, 44, 45, 45, 45, 46, 47, 47, 48, 48, 49, 50, 51, 51, 52, 52, 53, 53, 54, 55, 55, 56, 57, 57, 58, 59, 60, 60, 61, 62, 63, 63, 64, 65, 66, 67, 68, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 88, 89, 90, 91, 93, 94, 95, 96, 97, 98, 100, 101, 103, 104, 105, 107, 108, 110, 111, 113, 115, 116, 118, 119, 120, 122, 123, 125, 127, 128, 130, 132, 134, 135, 137, 139, 141, 143, 144, 146, 148, 150, 152, 154, 156, 158, 160, 163, 165, 167, 169, 171, 173, 175, 178, 180, 182, 185, 187, 189, 192, 194, 197, 199, 201, 204, 206, 209, 211, 214, 216, 219, 221, 224, 226, 229, 232, 234, 236, 239, 241, 245, 247, 250, 252, 255 };
- for (int i = 0; i < 256; i++){
- arrayOfByte1[(0 + i * 4)] = ((byte)arrayOfInt1[i]);
- arrayOfByte1[(1 + i * 4)] = ((byte)arrayOfInt2[i]);
- arrayOfByte1[(2 + i * 4)] = ((byte)arrayOfInt3[i]);
- arrayOfByte1[(3 + i * 4)] = ((byte)arrayOfInt4[i]);
- }
- int[] arrayOfInt5 = { 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 30, 32, 33, 34, 35, 37, 38, 39, 41, 42, 43, 44, 46, 47, 48, 50, 51, 52, 53, 55, 56, 57, 58, 60, 61, 62, 64, 65, 66, 67, 69, 70, 71, 72, 74, 75, 76, 77, 79, 80, 81, 82, 84, 85, 86, 87, 88, 90, 91, 92, 93, 95, 96, 97, 98, 99, 101, 102, 103, 104, 105, 107, 108, 109, 110, 111, 112, 114, 115, 116, 117, 118, 119, 121, 122, 123, 124, 125, 126, 127, 128, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 174, 175, 176, 177, 178, 179, 180, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 198, 199, 200, 201, 202, 204, 205, 206, 207, 209, 210, 211, 213, 214, 215, 217, 218, 220, 221, 222, 224, 225, 227, 228, 230, 231, 233, 234, 235, 237, 238, 240, 241, 243, 244, 246, 247, 249, 250, 252, 253, 255 };
- int[] arrayOfInt6 = { 0, 3, 6, 8, 11, 14, 16, 18, 21, 24, 26, 29, 30, 33, 35, 37, 39, 41, 43, 45, 47, 49, 50, 52, 53, 54, 56, 58, 59, 61, 62, 63, 65, 65, 66, 68, 69, 70, 72, 73, 74, 75, 76, 77, 78, 79, 80, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 112, 113, 114, 115, 115, 116, 117, 118, 119, 120, 121, 122, 123, 123, 124, 125, 126, 127, 127, 128, 129, 130, 131, 132, 133, 134, 135, 135, 135, 136, 137, 138, 139, 140, 140, 141, 142, 143, 144, 145, 146, 146, 147, 147, 148, 149, 149, 150, 151, 152, 153, 154, 154, 155, 156, 157, 158, 158, 159, 159, 160, 161, 161, 162, 163, 164, 164, 165, 166, 167, 167, 168, 169, 170, 170, 170, 171, 172, 173, 173, 174, 175, 176, 176, 177, 178, 179, 179, 180, 181, 181, 182, 182, 183, 183, 184, 185, 186, 186, 187, 188, 188, 189, 190, 191, 191, 192, 193, 193, 194, 194, 194, 195, 196, 197, 197, 198, 199, 199, 200, 201, 201, 202, 203, 203, 204, 205, 205, 206, 206, 207, 207, 208, 209, 209, 210, 211, 211, 212, 213, 213, 214, 215, 215, 216, 217, 217, 217, 217, 218, 219, 219, 220, 221, 221, 222, 223, 223, 224, 225, 225, 226, 227, 227, 228, 228, 229, 229, 229, 230, 231, 231, 232, 232, 233, 234, 234, 235 };
- int[] arrayOfInt7 = { 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 89, 90, 91, 92, 93, 94, 96, 97, 98, 99, 100, 102, 103, 104, 106, 107, 108, 109, 111, 112, 113, 115, 116, 118, 119, 120, 122, 123, 125, 126, 128, 129, 131, 132, 134, 135, 137, 139, 140, 142, 143, 145, 147, 148, 150, 152, 153, 155, 156, 158, 160, 161, 163, 164, 166, 167, 169, 170, 172, 173, 175, 176, 178, 179, 180, 182, 183, 185, 186, 188, 189, 190, 192, 193, 194, 196, 197, 199, 200, 201, 203, 204, 205, 206, 208, 209, 210, 212, 213, 214, 216, 217, 218, 219, 221, 222, 223, 224, 226, 227, 228, 229, 231, 232, 233, 234, 236, 237, 238, 239, 240, 242, 243, 244, 245, 247, 248, 249, 250, 251, 253, 254, 255 };
- for (int j = 0; j < 256; j++){
- arrayOfByte1[(0 + (1024 + j * 4))] = ((byte)arrayOfInt5[j]);
- arrayOfByte1[(1 + (1024 + j * 4))] = ((byte)arrayOfInt6[j]);
- arrayOfByte1[(2 + (1024 + j * 4))] = ((byte)arrayOfInt7[j]);
- arrayOfByte1[(3 + (1024 + j * 4))] = ((byte)arrayOfInt4[j]);
- }
- GLES20.glTexImage2D(GLES20.GL_TEXTURE_2D, 0, GLES20.GL_RGBA, 256, 2, 0, GLES20.GL_RGBA, GLES20.GL_UNSIGNED_BYTE, ByteBuffer.wrap(arrayOfByte1));
- GLES20.glGenTextures(1, mToneCurveTexture2, 0);
- GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mToneCurveTexture2[0]);
- GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D,
- GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR);
- GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D,
- GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_LINEAR);
- GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D,
- GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_CLAMP_TO_EDGE);
- GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D,
- GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_CLAMP_TO_EDGE);
- byte[] arrayOfByte2 = new byte[1024];
- int[] arrayOfInt8 = { 0, 0, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 5, 5, 5, 6, 6, 6, 7, 7, 8, 8, 8, 9, 9, 10, 10, 10, 11, 11, 11, 12, 12, 13, 13, 13, 14, 14, 14, 15, 15, 16, 16, 16, 17, 17, 17, 18, 18, 18, 19, 19, 20, 20, 20, 21, 21, 21, 22, 22, 23, 23, 23, 24, 24, 24, 25, 25, 25, 25, 26, 26, 27, 27, 28, 28, 28, 28, 29, 29, 30, 29, 31, 31, 31, 31, 32, 32, 33, 33, 34, 34, 34, 34, 35, 35, 36, 36, 37, 37, 37, 38, 38, 39, 39, 39, 40, 40, 40, 41, 42, 42, 43, 43, 44, 44, 45, 45, 45, 46, 47, 47, 48, 48, 49, 50, 51, 51, 52, 52, 53, 53, 54, 55, 55, 56, 57, 57, 58, 59, 60, 60, 61, 62, 63, 63, 64, 65, 66, 67, 68, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 88, 89, 90, 91, 93, 94, 95, 96, 97, 98, 100, 101, 103, 104, 105, 107, 108, 110, 111, 113, 115, 116, 118, 119, 120, 122, 123, 125, 127, 128, 130, 132, 134, 135, 137, 139, 141, 143, 144, 146, 148, 150, 152, 154, 156, 158, 160, 163, 165, 167, 169, 171, 173, 175, 178, 180, 182, 185, 187, 189, 192, 194, 197, 199, 201, 204, 206, 209, 211, 214, 216, 219, 221, 224, 226, 229, 232, 234, 236, 239, 241, 245, 247, 250, 252, 255 };
- int[] arrayOfInt9 = { 42, 43, 43, 44, 45, 45, 46, 47, 48, 48, 49, 50, 50, 51, 52, 52, 53, 54, 55, 55, 56, 57, 57, 58, 59, 60, 60, 61, 62, 62, 63, 64, 65, 65, 66, 67, 67, 68, 69, 70, 70, 71, 72, 72, 73, 74, 75, 75, 76, 77, 78, 78, 79, 80, 81, 81, 82, 83, 84, 84, 85, 86, 87, 87, 88, 89, 90, 91, 91, 92, 93, 94, 94, 95, 96, 97, 98, 98, 99, 100, 101, 102, 103, 103, 104, 105, 106, 107, 108, 108, 109, 110, 111, 112, 113, 113, 114, 115, 116, 117, 118, 119, 120, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 191, 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 201, 202, 203, 204, 205, 206, 207, 207, 208, 209, 210, 211, 212, 212, 213, 214, 215, 216, 217, 217, 218, 219, 220, 221, 221, 222, 223, 224, 224, 225, 226, 227, 228, 228, 229, 230, 231, 231, 232, 233, 234, 234, 235, 236, 237, 237, 238, 239, 240, 240, 241, 242, 243, 243, 244, 245, 246, 246, 247, 248, 248, 249, 250, 251, 251, 252, 253, 254, 254, 255 };
- int[] arrayOfInt10 = { 15, 16, 17, 18, 19, 20, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 198, 199, 200, 201, 202, 203, 204, 205, 205, 206, 207, 208, 209, 210, 211, 211, 212, 213, 214, 215, 215, 216, 217, 218, 219, 219, 220, 221, 222, 222, 223, 224, 225, 225, 226, 227, 227, 228, 229, 230, 230, 231, 232, 232, 233, 234, 234, 235, 236, 236, 237, 238, 238, 239, 240, 240, 241, 241, 242, 243, 243, 244, 245, 245, 246, 246, 247, 248, 248, 249, 250, 250, 251, 251, 252, 253, 253, 254, 254, 255 };
- int[] arrayOfInt11 = { 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 174, 175, 176, 177, 178, 179, 180, 181, 182, 182, 183, 184, 185, 186, 187, 188, 189, 190, 190, 191, 192, 193, 194, 195, 196, 197, 197, 198, 199, 200, 201, 202, 203, 203, 204, 205, 206, 207, 208, 209, 209, 210, 211, 212, 213, 214, 214, 215, 216, 217, 218, 219, 219, 220, 221, 222, 223, 224, 224, 225, 226, 227, 228, 229, 229, 230, 231, 232, 233, 234, 234, 235, 236, 237, 238, 239, 239, 240, 241, 242, 243, 244, 244, 245, 246, 247, 248, 248, 249, 250, 251, 252, 253, 253, 254, 255 };
- for (int k = 0; k < 256; k++){
- arrayOfByte2[(0 + k * 4)] = ((byte)arrayOfInt9[k]);
- arrayOfByte2[(1 + k * 4)] = ((byte)arrayOfInt10[k]);
- arrayOfByte2[(2 + k * 4)] = ((byte)arrayOfInt11[k]);
- arrayOfByte2[(3 + k * 4)] = ((byte)arrayOfInt8[k]);
- }
- GLES20.glTexImage2D(GLES20.GL_TEXTURE_2D, 0, GLES20.GL_RGBA, 256, 1, 0, GLES20.GL_RGBA, GLES20.GL_UNSIGNED_BYTE, ByteBuffer.wrap(arrayOfByte2));
- }
- });
- }
-
- @Override
- public void onInputSizeChanged(int width, int height) {
- super.onInputSizeChanged(width, height);
- GLES20.glUniform1f(mTexelWidthUniformLocation, (1.0f / (float)width));
- GLES20.glUniform1f(mTexelHeightUniformLocation, (1.0f / (float)height));
- }
-}
diff --git a/Live/src/main/java/com/seu/magicfilter/advanced/MagicPixelFilter.java b/Live/src/main/java/com/seu/magicfilter/advanced/MagicPixelFilter.java
deleted file mode 100644
index c9a71925..00000000
--- a/Live/src/main/java/com/seu/magicfilter/advanced/MagicPixelFilter.java
+++ /dev/null
@@ -1,65 +0,0 @@
-package com.seu.magicfilter.advanced;
-
-import android.opengl.GLES20;
-
-import com.frank.live.R;
-import com.seu.magicfilter.base.gpuimage.GPUImageFilter;
-import com.seu.magicfilter.utils.MagicFilterType;
-import com.seu.magicfilter.utils.OpenGLUtils;
-
-public class MagicPixelFilter extends GPUImageFilter {
- private int[] inputTextureHandles = {-1};
- private int[] inputTextureUniformLocations = {-1};
- private int mGLStrengthLocation;
-
- public MagicPixelFilter(){
- super(MagicFilterType.PIXAR, R.raw.pixar);
- }
-
- @Override
- protected void onDestroy() {
- super.onDestroy();
- GLES20.glDeleteTextures(1, inputTextureHandles, 0);
- for (int i = 0; i < inputTextureHandles.length; i++) {
- inputTextureHandles[i] = -1;
- }
- }
-
- @Override
- protected void onDrawArraysAfter(){
- for(int i = 0; i < inputTextureHandles.length && inputTextureHandles[i] != OpenGLUtils.NO_TEXTURE; i++){
- GLES20.glActiveTexture(GLES20.GL_TEXTURE0 + (i+3));
- GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, 0);
- GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
- }
- }
-
- @Override
- protected void onDrawArraysPre(){
- for (int i = 0; i < inputTextureHandles.length && inputTextureHandles[i] != OpenGLUtils.NO_TEXTURE; i++){
- GLES20.glActiveTexture(GLES20.GL_TEXTURE0 + (i+3) );
- GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, inputTextureHandles[i]);
- GLES20.glUniform1i(inputTextureUniformLocations[i], (i+3));
- }
- }
-
- @Override
- protected void onInit(){
- super.onInit();
- for (int i=0; i < inputTextureUniformLocations.length; i++) {
- inputTextureUniformLocations[i] = GLES20.glGetUniformLocation(getProgram(), "inputImageTexture" + (2 + i));
- }
- mGLStrengthLocation = GLES20.glGetUniformLocation(getProgram(), "strength");
- }
-
- @Override
- protected void onInitialized(){
- super.onInitialized();
- setFloat(mGLStrengthLocation, 1.0f);
- runOnDraw(new Runnable(){
- public void run(){
-// inputTextureHandles[0] = OpenGLUtils.loadTexture(getContext(), "filter/pixar_curves.png");
- }
- });
- }
-}
diff --git a/Live/src/main/java/com/seu/magicfilter/advanced/MagicRiseFilter.java b/Live/src/main/java/com/seu/magicfilter/advanced/MagicRiseFilter.java
deleted file mode 100644
index 8cd4569a..00000000
--- a/Live/src/main/java/com/seu/magicfilter/advanced/MagicRiseFilter.java
+++ /dev/null
@@ -1,66 +0,0 @@
-package com.seu.magicfilter.advanced;
-
-import android.opengl.GLES20;
-
-import com.frank.live.R;
-import com.seu.magicfilter.base.gpuimage.GPUImageFilter;
-import com.seu.magicfilter.utils.MagicFilterType;
-import com.seu.magicfilter.utils.OpenGLUtils;
-
-
-public class MagicRiseFilter extends GPUImageFilter {
- private int[] inputTextureHandles = {-1,-1,-1};
- private int[] inputTextureUniformLocations = {-1,-1,-1};
-
- public MagicRiseFilter(){
- super(MagicFilterType.RISE, R.raw.rise);
- }
-
- @Override
- protected void onDestroy() {
- super.onDestroy();
- GLES20.glDeleteTextures(inputTextureHandles.length, inputTextureHandles, 0);
- for(int i = 0; i < inputTextureHandles.length; i++)
- inputTextureHandles[i] = -1;
- }
-
- @Override
- protected void onDrawArraysAfter(){
- for(int i = 0; i < inputTextureHandles.length
- && inputTextureHandles[i] != OpenGLUtils.NO_TEXTURE; i++){
- GLES20.glActiveTexture(GLES20.GL_TEXTURE0 + (i+3));
- GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, 0);
- GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
- }
- }
-
- @Override
- protected void onDrawArraysPre(){
- for(int i = 0; i < inputTextureHandles.length
- && inputTextureHandles[i] != OpenGLUtils.NO_TEXTURE; i++){
- GLES20.glActiveTexture(GLES20.GL_TEXTURE0 + (i+3) );
- GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, inputTextureHandles[i]);
- GLES20.glUniform1i(inputTextureUniformLocations[i], (i+3));
- }
- }
-
- @Override
- protected void onInit(){
- super.onInit();
- for(int i=0; i < inputTextureUniformLocations.length; i++){
- inputTextureUniformLocations[i] = GLES20.glGetUniformLocation(getProgram(), "inputImageTexture"+(2+i));
- }
- }
-
- @Override
- protected void onInitialized(){
- super.onInitialized();
- runOnDraw(new Runnable(){
- public void run(){
- inputTextureHandles[0] = OpenGLUtils.loadTexture(getContext(), "filter/blackboard1024.png");
- inputTextureHandles[1] = OpenGLUtils.loadTexture(getContext(), "filter/overlaymap.png");
- inputTextureHandles[2] = OpenGLUtils.loadTexture(getContext(), "filter/risemap.png");
- }
- });
- }
-}
diff --git a/Live/src/main/java/com/seu/magicfilter/advanced/MagicRomanceFilter.java b/Live/src/main/java/com/seu/magicfilter/advanced/MagicRomanceFilter.java
deleted file mode 100644
index 4ca39fea..00000000
--- a/Live/src/main/java/com/seu/magicfilter/advanced/MagicRomanceFilter.java
+++ /dev/null
@@ -1,81 +0,0 @@
-package com.seu.magicfilter.advanced;
-
-import android.opengl.GLES20;
-
-import com.frank.live.R;
-import com.seu.magicfilter.base.gpuimage.GPUImageFilter;
-import com.seu.magicfilter.utils.MagicFilterType;
-
-import java.nio.ByteBuffer;
-
-public class MagicRomanceFilter extends GPUImageFilter {
-
- private int[] mToneCurveTexture = {-1};
- private int mToneCurveTextureUniformLocation;
-
- public MagicRomanceFilter(){
- super(MagicFilterType.ROMANCE, R.raw.romance);
- }
-
- @Override
- protected void onDestroy(){
- super.onDestroy();
- GLES20.glDeleteTextures(1, mToneCurveTexture, 0);
- mToneCurveTexture[0] = -1;
- }
-
- @Override
- protected void onDrawArraysAfter(){
- if (mToneCurveTexture[0] != -1){
- GLES20.glActiveTexture(GLES20.GL_TEXTURE3);
- GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, 0);
- GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
- }
- }
-
- @Override
- protected void onDrawArraysPre(){
- if (mToneCurveTexture[0] != -1){
- GLES20.glActiveTexture(GLES20.GL_TEXTURE3);
- GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mToneCurveTexture[0]);
- GLES20.glUniform1i(mToneCurveTextureUniformLocation, 3);
- }
- }
-
- @Override
- protected void onInit(){
- super.onInit();
- mToneCurveTextureUniformLocation = GLES20.glGetUniformLocation(getProgram(), "curve");
- }
-
- @Override
- protected void onInitialized(){
- super.onInitialized();
- runOnDraw(new Runnable(){
- public void run(){
- GLES20.glGenTextures(1, mToneCurveTexture, 0);
- GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mToneCurveTexture[0]);
- GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D,
- GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR);
- GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D,
- GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_LINEAR);
- GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D,
- GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_CLAMP_TO_EDGE);
- GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D,
- GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_CLAMP_TO_EDGE);
- byte[] romance_arrayOfByte = new byte[1024];
- int[] romance_arrayOfInt1 = { 46, 46, 46, 46, 47, 47, 47, 47, 47, 47, 48, 48, 48, 48, 48, 48, 49, 49, 49, 49, 49, 50, 50, 50, 50, 51, 51, 51, 51, 52, 52, 52, 52, 53, 53, 53, 54, 54, 54, 55, 55, 56, 56, 56, 57, 57, 58, 58, 59, 59, 60, 60, 61, 61, 62, 62, 63, 63, 64, 65, 65, 66, 67, 67, 68, 69, 69, 70, 71, 72, 73, 73, 74, 75, 76, 77, 78, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 100, 101, 102, 103, 104, 105, 106, 107, 109, 110, 111, 112, 113, 114, 116, 117, 118, 119, 120, 122, 123, 124, 125, 127, 128, 129, 130, 131, 133, 134, 135, 136, 138, 139, 140, 141, 143, 144, 145, 146, 148, 149, 150, 151, 153, 154, 155, 156, 158, 159, 160, 161, 162, 164, 165, 166, 167, 169, 170, 171, 172, 173, 175, 176, 177, 178, 179, 180, 182, 183, 184, 185, 186, 187, 188, 189, 191, 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 211, 212, 213, 214, 215, 216, 217, 218, 218, 219, 220, 221, 222, 222, 223, 224, 225, 226, 226, 227, 228, 229, 229, 230, 231, 232, 232, 233, 234, 234, 235, 236, 237, 237, 238, 239, 239, 240, 241, 241, 242, 243, 243, 244, 245, 245, 246, 247, 247, 248, 249, 249, 250, 251, 251, 252, 252, 253, 254, 254, 255 };
- int[] romance_arrayOfInt2 = { 0, 1, 1, 2, 3, 4, 4, 5, 6, 6, 7, 8, 9, 9, 10, 11, 12, 12, 13, 14, 14, 15, 16, 17, 17, 18, 19, 20, 20, 21, 22, 23, 23, 24, 25, 26, 26, 27, 28, 29, 30, 30, 31, 32, 33, 33, 34, 35, 36, 37, 38, 38, 39, 40, 41, 42, 43, 43, 44, 45, 46, 47, 48, 49, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 111, 112, 113, 114, 115, 116, 117, 118, 120, 121, 122, 123, 124, 125, 126, 128, 129, 130, 131, 132, 133, 134, 136, 137, 138, 139, 140, 141, 142, 144, 145, 146, 147, 148, 149, 151, 152, 153, 154, 155, 156, 157, 159, 160, 161, 162, 163, 164, 166, 167, 168, 169, 170, 171, 172, 174, 175, 176, 177, 178, 179, 180, 181, 183, 184, 185, 186, 187, 188, 189, 190, 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 217, 218, 219, 220, 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255 };
- int[] romance_arrayOfInt3 = { 0, 2, 3, 5, 7, 8, 10, 12, 13, 15, 17, 18, 20, 21, 23, 25, 26, 28, 30, 31, 33, 34, 36, 38, 39, 41, 42, 44, 45, 47, 48, 50, 51, 53, 54, 56, 57, 59, 60, 62, 63, 65, 66, 67, 69, 70, 72, 73, 74, 76, 77, 78, 79, 81, 82, 83, 84, 86, 87, 88, 89, 90, 91, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 106, 107, 108, 109, 110, 111, 112, 112, 113, 114, 115, 116, 116, 117, 118, 119, 119, 120, 121, 122, 122, 123, 124, 124, 125, 126, 126, 127, 128, 128, 129, 130, 130, 131, 131, 132, 133, 133, 134, 134, 135, 136, 136, 137, 137, 138, 139, 139, 140, 140, 141, 141, 142, 143, 143, 144, 144, 145, 146, 146, 147, 147, 148, 149, 149, 150, 150, 151, 152, 152, 153, 154, 154, 155, 155, 156, 157, 157, 158, 159, 159, 160, 161, 162, 162, 163, 164, 164, 165, 166, 167, 168, 168, 169, 170, 171, 172, 172, 173, 174, 175, 176, 177, 177, 178, 179, 180, 181, 182, 183, 184, 185, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 218, 219, 220, 221, 222, 223, 224, 225, 226, 227, 228, 229, 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, 242, 243, 244, 245, 246, 247, 248, 249, 251, 252, 253, 254, 255 };
- int[] romance_arrayOfInt4 = { 0, 0, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 5, 5, 5, 6, 6, 6, 7, 7, 8, 8, 8, 9, 9, 10, 10, 10, 11, 11, 11, 12, 12, 13, 13, 13, 14, 14, 14, 15, 15, 16, 16, 16, 17, 17, 17, 18, 18, 18, 19, 19, 20, 20, 20, 21, 21, 21, 22, 22, 23, 23, 23, 24, 24, 24, 25, 25, 25, 25, 26, 26, 27, 27, 28, 28, 28, 28, 29, 29, 30, 29, 31, 31, 31, 31, 32, 32, 33, 33, 34, 34, 34, 34, 35, 35, 36, 36, 37, 37, 37, 38, 38, 39, 39, 39, 40, 40, 40, 41, 42, 42, 43, 43, 44, 44, 45, 45, 45, 46, 47, 47, 48, 48, 49, 50, 51, 51, 52, 52, 53, 53, 54, 55, 55, 56, 57, 57, 58, 59, 60, 60, 61, 62, 63, 63, 64, 65, 66, 67, 68, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 88, 89, 90, 91, 93, 94, 95, 96, 97, 98, 100, 101, 103, 104, 105, 107, 108, 110, 111, 113, 115, 116, 118, 119, 120, 122, 123, 125, 127, 128, 130, 132, 134, 135, 137, 139, 141, 143, 144, 146, 148, 150, 152, 154, 156, 158, 160, 163, 165, 167, 169, 171, 173, 175, 178, 180, 182, 185, 187, 189, 192, 194, 197, 199, 201, 204, 206, 209, 211, 214, 216, 219, 221, 224, 226, 229, 232, 234, 236, 239, 241, 245, 247, 250, 252, 255 };
- for (int i = 0; i < 256; i++){
- romance_arrayOfByte[(i * 4)] = ((byte)romance_arrayOfInt1[i]);
- romance_arrayOfByte[(1 + i * 4)] = ((byte)romance_arrayOfInt2[i]);
- romance_arrayOfByte[(2 + i * 4)] = ((byte)romance_arrayOfInt3[i]);
- romance_arrayOfByte[(3 + i * 4)] = ((byte)romance_arrayOfInt4[i]);
- }
- GLES20.glTexImage2D(GLES20.GL_TEXTURE_2D, 0, GLES20.GL_RGBA, 256, 1, 0, GLES20.GL_RGBA, GLES20.GL_UNSIGNED_BYTE, ByteBuffer.wrap(romance_arrayOfByte));
- }
- });
- }
-}
diff --git a/Live/src/main/java/com/seu/magicfilter/advanced/MagicSakuraFilter.java b/Live/src/main/java/com/seu/magicfilter/advanced/MagicSakuraFilter.java
deleted file mode 100644
index 088899d7..00000000
--- a/Live/src/main/java/com/seu/magicfilter/advanced/MagicSakuraFilter.java
+++ /dev/null
@@ -1,89 +0,0 @@
-package com.seu.magicfilter.advanced;
-
-import android.opengl.GLES20;
-
-import com.frank.live.R;
-import com.seu.magicfilter.base.gpuimage.GPUImageFilter;
-import com.seu.magicfilter.utils.MagicFilterType;
-
-import java.nio.ByteBuffer;
-
-public class MagicSakuraFilter extends GPUImageFilter {
- private int[] mToneCurveTexture = {-1};
- private int mToneCurveTextureUniformLocation;
- private int mTexelHeightUniformLocation;
- private int mTexelWidthUniformLocation;
-
- public MagicSakuraFilter(){
- super(MagicFilterType.SAKURA, R.raw.romance);
- }
-
- @Override
- protected void onDestroy(){
- super.onDestroy();
- GLES20.glDeleteTextures(1, mToneCurveTexture, 0);
- mToneCurveTexture[0] = -1;
- }
-
- @Override
- protected void onDrawArraysAfter(){
- if (mToneCurveTexture[0] != -1){
- GLES20.glActiveTexture(GLES20.GL_TEXTURE3);
- GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, 0);
- GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
- }
- }
-
- @Override
- protected void onDrawArraysPre(){
- if (mToneCurveTexture[0] != -1){
- GLES20.glActiveTexture(GLES20.GL_TEXTURE3);
- GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mToneCurveTexture[0]);
- GLES20.glUniform1i(mToneCurveTextureUniformLocation, 3);
- }
- }
-
- @Override
- protected void onInit(){
- super.onInit();
- mToneCurveTextureUniformLocation = GLES20.glGetUniformLocation(getProgram(), "curve");
- mTexelWidthUniformLocation = GLES20.glGetUniformLocation(getProgram(), "texelWidthOffset");
- mTexelHeightUniformLocation = GLES20.glGetUniformLocation(getProgram(), "texelHeightOffset");
- }
-
- @Override
- protected void onInitialized(){
- super.onInitialized();
- runOnDraw(new Runnable(){
- public void run(){
- GLES20.glGenTextures(1, mToneCurveTexture, 0);
- GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mToneCurveTexture[0]);
- GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D,
- GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR);
- GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D,
- GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_LINEAR);
- GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D,
- GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_CLAMP_TO_EDGE);
- GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D,
- GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_CLAMP_TO_EDGE);
- byte[] arrayOfByte = new byte[1024];
- int[] arrayOfInt = { 95, 95, 96, 97, 97, 98, 99, 99, 100, 101, 101, 102, 103, 104, 104, 105, 106, 106, 107, 108, 108, 109, 110, 111, 111, 112, 113, 113, 114, 115, 115, 116, 117, 117, 118, 119, 120, 120, 121, 122, 122, 123, 124, 124, 125, 126, 127, 127, 128, 129, 129, 130, 131, 131, 132, 133, 133, 134, 135, 136, 136, 137, 138, 138, 139, 140, 140, 141, 142, 143, 143, 144, 145, 145, 146, 147, 147, 148, 149, 149, 150, 151, 152, 152, 153, 154, 154, 155, 156, 156, 157, 158, 159, 159, 160, 161, 161, 162, 163, 163, 164, 165, 165, 166, 167, 168, 168, 169, 170, 170, 171, 172, 172, 173, 174, 175, 175, 176, 177, 177, 178, 179, 179, 180, 181, 181, 182, 183, 184, 184, 185, 186, 186, 187, 188, 188, 189, 190, 191, 191, 192, 193, 193, 194, 195, 195, 196, 197, 197, 198, 199, 200, 200, 201, 202, 202, 203, 204, 204, 205, 206, 207, 207, 208, 209, 209, 210, 211, 211, 212, 213, 213, 214, 215, 216, 216, 217, 218, 218, 219, 220, 220, 221, 222, 223, 223, 224, 225, 225, 226, 227, 227, 228, 229, 229, 230, 231, 232, 232, 233, 234, 234, 235, 236, 236, 237, 238, 239, 239, 240, 241, 241, 242, 243, 243, 244, 245, 245, 246, 247, 248, 248, 249, 250, 250, 251, 252, 252, 253, 254, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 };
- for (int i = 0; i < 256; i++)
- {
- arrayOfByte[(i * 4)] = ((byte)arrayOfInt[i]);
- arrayOfByte[(1 + i * 4)] = ((byte)arrayOfInt[i]);
- arrayOfByte[(2 + i * 4)] = ((byte)arrayOfInt[i]);
- arrayOfByte[(3 + i * 4)] = ((byte)arrayOfInt[i]);
- }
- GLES20.glTexImage2D(GLES20.GL_TEXTURE_2D, 0, GLES20.GL_RGBA, 256, 1, 0, GLES20.GL_RGBA, GLES20.GL_UNSIGNED_BYTE, ByteBuffer.wrap(arrayOfByte));
- }
- });
- }
-
- @Override
- public void onInputSizeChanged(int width, int height) {
- super.onInputSizeChanged(width, height);
- GLES20.glUniform1f(mTexelWidthUniformLocation, (1.0f / (float)width));
- GLES20.glUniform1f(mTexelHeightUniformLocation, (1.0f / (float)height));
- }
-}
diff --git a/Live/src/main/java/com/seu/magicfilter/advanced/MagicSierraFilter.java b/Live/src/main/java/com/seu/magicfilter/advanced/MagicSierraFilter.java
deleted file mode 100644
index 38577964..00000000
--- a/Live/src/main/java/com/seu/magicfilter/advanced/MagicSierraFilter.java
+++ /dev/null
@@ -1,67 +0,0 @@
-package com.seu.magicfilter.advanced;
-
-import android.opengl.GLES20;
-
-import com.frank.live.R;
-import com.seu.magicfilter.base.gpuimage.GPUImageFilter;
-import com.seu.magicfilter.utils.MagicFilterType;
-import com.seu.magicfilter.utils.OpenGLUtils;
-
-public class MagicSierraFilter extends GPUImageFilter {
- private int[] inputTextureHandles = {-1,-1,-1};
- private int[] inputTextureUniformLocations = {-1,-1,-1};
- private int mGLStrengthLocation;
-
- public MagicSierraFilter(){
- super(MagicFilterType.SIERRA, R.raw.sierra);
- }
-
- @Override
- protected void onDestroy() {
- super.onDestroy();
- GLES20.glDeleteTextures(inputTextureHandles.length, inputTextureHandles, 0);
- for(int i = 0; i < inputTextureHandles.length; i++)
- inputTextureHandles[i] = -1;
- }
-
- @Override
- protected void onDrawArraysAfter(){
- for(int i = 0; i < inputTextureHandles.length
- && inputTextureHandles[i] != OpenGLUtils.NO_TEXTURE; i++){
- GLES20.glActiveTexture(GLES20.GL_TEXTURE0 + (i+3));
- GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, 0);
- GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
- }
- }
-
- @Override
- protected void onDrawArraysPre(){
- for(int i = 0; i < inputTextureHandles.length
- && inputTextureHandles[i] != OpenGLUtils.NO_TEXTURE; i++){
- GLES20.glActiveTexture(GLES20.GL_TEXTURE0 + (i+3) );
- GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, inputTextureHandles[i]);
- GLES20.glUniform1i(inputTextureUniformLocations[i], (i+3));
- }
- }
-
- @Override
- protected void onInit(){
- super.onInit();
- for(int i = 0; i < inputTextureUniformLocations.length; i++)
- inputTextureUniformLocations[i] = GLES20.glGetUniformLocation(getProgram(), "inputImageTexture"+(2+i));
- mGLStrengthLocation = GLES20.glGetUniformLocation(getProgram(), "strength");
- }
-
- @Override
- protected void onInitialized(){
- super.onInitialized();
- setFloat(mGLStrengthLocation, 1.0f);
- runOnDraw(new Runnable(){
- public void run(){
- inputTextureHandles[0] = OpenGLUtils.loadTexture(getContext(), "filter/sierravignette.png");
- inputTextureHandles[1] = OpenGLUtils.loadTexture(getContext(), "filter/overlaymap.png");
- inputTextureHandles[2] = OpenGLUtils.loadTexture(getContext(), "filter/sierramap.png");
- }
- });
- }
-}
diff --git a/Live/src/main/java/com/seu/magicfilter/advanced/MagicSketchFilter.java b/Live/src/main/java/com/seu/magicfilter/advanced/MagicSketchFilter.java
deleted file mode 100644
index 733adf4c..00000000
--- a/Live/src/main/java/com/seu/magicfilter/advanced/MagicSketchFilter.java
+++ /dev/null
@@ -1,42 +0,0 @@
-package com.seu.magicfilter.advanced;
-
-import android.opengl.GLES20;
-
-import com.frank.live.R;
-import com.seu.magicfilter.base.gpuimage.GPUImageFilter;
-import com.seu.magicfilter.utils.MagicFilterType;
-
-public class MagicSketchFilter extends GPUImageFilter {
-
- private int mSingleStepOffsetLocation;
- //0.0 - 1.0
- private int mStrengthLocation;
-
- public MagicSketchFilter(){
- super(MagicFilterType.SKETCH, R.raw.sketch);
- }
-
- @Override
- protected void onInit() {
- super.onInit();
- mSingleStepOffsetLocation = GLES20.glGetUniformLocation(getProgram(), "singleStepOffset");
- mStrengthLocation = GLES20.glGetUniformLocation(getProgram(), "strength");
- }
-
- @Override
- protected void onDestroy() {
- super.onDestroy();
- }
-
- @Override
- protected void onInitialized(){
- super.onInitialized();
- setFloat(mStrengthLocation, 0.5f);
- }
-
- @Override
- public void onInputSizeChanged(final int width, final int height) {
- super.onInputSizeChanged(width, height);
- setFloatVec2(mSingleStepOffsetLocation, new float[] {1.0f / width, 1.0f / height});
- }
-}
diff --git a/Live/src/main/java/com/seu/magicfilter/advanced/MagicSkinWhitenFilter.java b/Live/src/main/java/com/seu/magicfilter/advanced/MagicSkinWhitenFilter.java
deleted file mode 100644
index 44b8ef84..00000000
--- a/Live/src/main/java/com/seu/magicfilter/advanced/MagicSkinWhitenFilter.java
+++ /dev/null
@@ -1,93 +0,0 @@
-package com.seu.magicfilter.advanced;
-
-import android.opengl.GLES20;
-
-import com.frank.live.R;
-import com.seu.magicfilter.base.gpuimage.GPUImageFilter;
-import com.seu.magicfilter.utils.MagicFilterType;
-
-import java.nio.ByteBuffer;
-
-public class MagicSkinWhitenFilter extends GPUImageFilter {
- private int mTexelHeightUniformLocation;
- private int mTexelWidthUniformLocation;
- private int mToneCurveTextureUniformLocation;
- private int[] mToneCurveTexture = new int[] {-1};
-
- public MagicSkinWhitenFilter() {
- super(MagicFilterType.SKINWHITEN, R.raw.skinwhiten);
- }
-
- @Override
- protected void onInit() {
- super.onInit();
- mToneCurveTextureUniformLocation = GLES20.glGetUniformLocation(getProgram(), "curve");
- mTexelWidthUniformLocation = GLES20.glGetUniformLocation(getProgram(), "texelWidthOffset");
- mTexelHeightUniformLocation = GLES20.glGetUniformLocation(getProgram(), "texelHeightOffset");
-
- }
-
- @Override
- protected void onDestroy() {
- super.onDestroy();
- GLES20.glDeleteTextures(1, mToneCurveTexture, 0);
- mToneCurveTexture[0] = -1;
- }
-
- @Override
- protected void onInitialized() {
- super.onInitialized();
- runOnDraw(new Runnable() {
- public void run() {
- GLES20.glActiveTexture(GLES20.GL_TEXTURE3);
- GLES20.glGenTextures(1, mToneCurveTexture, 0);
- GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mToneCurveTexture[0]);
- GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D,
- GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR);
- GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D,
- GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_LINEAR);
- GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D,
- GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_CLAMP_TO_EDGE);
- GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D,
- GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_CLAMP_TO_EDGE);
- byte[] arrayOfByte = new byte[1024];
- int[] arrayOfInt1 = { 95, 95, 96, 97, 97, 98, 99, 99, 100, 101, 101, 102, 103, 104, 104, 105, 106, 106, 107, 108, 108, 109, 110, 111, 111, 112, 113, 113, 114, 115, 115, 116, 117, 117, 118, 119, 120, 120, 121, 122, 122, 123, 124, 124, 125, 126, 127, 127, 128, 129, 129, 130, 131, 131, 132, 133, 133, 134, 135, 136, 136, 137, 138, 138, 139, 140, 140, 141, 142, 143, 143, 144, 145, 145, 146, 147, 147, 148, 149, 149, 150, 151, 152, 152, 153, 154, 154, 155, 156, 156, 157, 158, 159, 159, 160, 161, 161, 162, 163, 163, 164, 165, 165, 166, 167, 168, 168, 169, 170, 170, 171, 172, 172, 173, 174, 175, 175, 176, 177, 177, 178, 179, 179, 180, 181, 181, 182, 183, 184, 184, 185, 186, 186, 187, 188, 188, 189, 190, 191, 191, 192, 193, 193, 194, 195, 195, 196, 197, 197, 198, 199, 200, 200, 201, 202, 202, 203, 204, 204, 205, 206, 207, 207, 208, 209, 209, 210, 211, 211, 212, 213, 213, 214, 215, 216, 216, 217, 218, 218, 219, 220, 220, 221, 222, 223, 223, 224, 225, 225, 226, 227, 227, 228, 229, 229, 230, 231, 232, 232, 233, 234, 234, 235, 236, 236, 237, 238, 239, 239, 240, 241, 241, 242, 243, 243, 244, 245, 245, 246, 247, 248, 248, 249, 250, 250, 251, 252, 252, 253, 254, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 };
- int[] arrayOfInt2 = { 0, 0, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 5, 5, 5, 6, 6, 6, 7, 7, 8, 8, 8, 9, 9, 10, 10, 10, 11, 11, 11, 12, 12, 13, 13, 13, 14, 14, 14, 15, 15, 16, 16, 16, 17, 17, 17, 18, 18, 18, 19, 19, 20, 20, 20, 21, 21, 21, 22, 22, 23, 23, 23, 24, 24, 24, 25, 25, 25, 25, 26, 26, 27, 27, 28, 28, 28, 28, 29, 29, 30, 29, 31, 31, 31, 31, 32, 32, 33, 33, 34, 34, 34, 34, 35, 35, 36, 36, 37, 37, 37, 38, 38, 39, 39, 39, 40, 40, 40, 41, 42, 42, 43, 43, 44, 44, 45, 45, 45, 46, 47, 47, 48, 48, 49, 50, 51, 51, 52, 52, 53, 53, 54, 55, 55, 56, 57, 57, 58, 59, 60, 60, 61, 62, 63, 63, 64, 65, 66, 67, 68, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 88, 89, 90, 91, 93, 94, 95, 96, 97, 98, 100, 101, 103, 104, 105, 107, 108, 110, 111, 113, 115, 116, 118, 119, 120, 122, 123, 125, 127, 128, 130, 132, 134, 135, 137, 139, 141, 143, 144, 146, 148, 150, 152, 154, 156, 158, 160, 163, 165, 167, 169, 171, 173, 175, 178, 180, 182, 185, 187, 189, 192, 194, 197, 199, 201, 204, 206, 209, 211, 214, 216, 219, 221, 224, 226, 229, 232, 234, 236, 239, 241, 245, 247, 250, 252, 255 };
- for (int i = 0; i < 256; i++){
- arrayOfByte[(i * 4)] = ((byte)arrayOfInt1[i]);
- arrayOfByte[(1 + i * 4)] = ((byte)arrayOfInt1[i]);
- arrayOfByte[(2 + i * 4)] = ((byte)arrayOfInt2[i]);
- arrayOfByte[(3 + i * 4)] = -1;
- }
- GLES20.glTexImage2D(GLES20.GL_TEXTURE_2D, 0, GLES20.GL_RGBA, 256, 1, 0, GLES20.GL_RGBA, GLES20.GL_UNSIGNED_BYTE, ByteBuffer.wrap(arrayOfByte));
- }
- });
- }
-
- @Override
- protected void onDrawArraysPre() {
- super.onDrawArraysPre();
- if(mToneCurveTexture[0] != -1) {
- GLES20.glActiveTexture(GLES20.GL_TEXTURE3);
- GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mToneCurveTexture[0]);
- GLES20.glUniform1i(this.mToneCurveTextureUniformLocation, 3);
- }
- }
-
- @Override
- protected void onDrawArraysAfter() {
- super.onDrawArraysAfter();
- if (mToneCurveTexture[0] != -1) {
- GLES20.glActiveTexture(GLES20.GL_TEXTURE3);
- GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, 0);
- GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
- }
- }
-
- @Override
- public void onInputSizeChanged(int width, int height) {
- super.onInputSizeChanged(width, height);
- GLES20.glUniform1f(mTexelWidthUniformLocation, (1.0f / (float)width));
- GLES20.glUniform1f(mTexelHeightUniformLocation, (1.0f / (float)height));
- }
-}
diff --git a/Live/src/main/java/com/seu/magicfilter/advanced/MagicSunriseFilter.java b/Live/src/main/java/com/seu/magicfilter/advanced/MagicSunriseFilter.java
deleted file mode 100644
index 3a086650..00000000
--- a/Live/src/main/java/com/seu/magicfilter/advanced/MagicSunriseFilter.java
+++ /dev/null
@@ -1,139 +0,0 @@
-package com.seu.magicfilter.advanced;
-
-import android.opengl.GLES20;
-
-import com.frank.live.R;
-import com.seu.magicfilter.base.gpuimage.GPUImageFilter;
-import com.seu.magicfilter.utils.MagicFilterType;
-
-import java.nio.ByteBuffer;
-
-public class MagicSunriseFilter extends GPUImageFilter {
- private int mMaskGrey1TextureId = -1;
- private int mMaskGrey1UniformLocation;
- private int mMaskGrey2TextureId = -1;
- private int mMaskGrey2UniformLocation;
- private int mMaskGrey3TextureId = -1;
- private int mMaskGrey3UniformLocation;
- private int[] mToneCurveTexture = { -1 };
- private int mToneCurveTextureUniformLocation;
-
- public MagicSunriseFilter(){
- super(MagicFilterType.SUNRISE, R.raw.sunrise);
- }
-
- @Override
- protected void onDestroy(){
- super.onDestroy();
- GLES20.glDeleteTextures(1, mToneCurveTexture, 0);
- mToneCurveTexture[0] = -1;
- GLES20.glDeleteTextures(1, new int[]{mMaskGrey1TextureId}, 0);
- mMaskGrey1TextureId = -1;
- GLES20.glDeleteTextures(1, new int[]{mMaskGrey2TextureId}, 0);
- mMaskGrey2TextureId = -1;
- GLES20.glDeleteTextures(1, new int[]{mMaskGrey3TextureId}, 0);
- mMaskGrey3TextureId = -1;
- }
-
- @Override
- protected void onDrawArraysAfter() {
- if (mToneCurveTexture[0] != -1){
- GLES20.glActiveTexture(GLES20.GL_TEXTURE3);
- GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, 0);
- GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
- }
- if (mMaskGrey1TextureId != -1){
- GLES20.glActiveTexture(GLES20.GL_TEXTURE4);
- GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, 0);
- GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
- }
- if (mMaskGrey2TextureId != -1){
- GLES20.glActiveTexture(GLES20.GL_TEXTURE5);
- GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, 0);
- GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
- }
- if (mMaskGrey3TextureId != -1){
- GLES20.glActiveTexture(GLES20.GL_TEXTURE6);
- GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, 0);
- GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
- }
- }
-
- @Override
- protected void onDrawArraysPre() {
- if (mToneCurveTexture[0] != -1){
- GLES20.glActiveTexture(GLES20.GL_TEXTURE3);
- GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mToneCurveTexture[0]);
- GLES20.glUniform1i(mToneCurveTextureUniformLocation, 3);
- }
- if (mMaskGrey1TextureId != -1){
- GLES20.glActiveTexture(GLES20.GL_TEXTURE4);
- GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mMaskGrey1TextureId);
- GLES20.glUniform1i(mMaskGrey1UniformLocation, 4);
- }
- if (mMaskGrey2TextureId != -1){
- GLES20.glActiveTexture(GLES20.GL_TEXTURE5);
- GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mMaskGrey2TextureId);
- GLES20.glUniform1i(mMaskGrey2UniformLocation, 5);
- }
- if (mMaskGrey3TextureId != -1){
- GLES20.glActiveTexture(GLES20.GL_TEXTURE6);
- GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mMaskGrey3TextureId);
- GLES20.glUniform1i(mMaskGrey3UniformLocation, 6);
- }
- }
-
- @Override
- protected void onInit(){
- super.onInit();
- mToneCurveTextureUniformLocation = GLES20.glGetUniformLocation(getProgram(), "curve");
- mMaskGrey1UniformLocation = GLES20.glGetUniformLocation(getProgram(), "grey1Frame");
- mMaskGrey2UniformLocation = GLES20.glGetUniformLocation(getProgram(), "grey2Frame");
- mMaskGrey3UniformLocation = GLES20.glGetUniformLocation(getProgram(), "grey3Frame");
- }
-
- @Override
- protected void onInitialized(){
- super.onInitialized();
- runOnDraw(new Runnable(){
- public void run(){
- GLES20.glActiveTexture(GLES20.GL_TEXTURE3);
- GLES20.glGenTextures(1, mToneCurveTexture, 0);
- GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mToneCurveTexture[0]);
- GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D,
- GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR);
- GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D,
- GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_LINEAR);
- GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D,
- GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_CLAMP_TO_EDGE);
- GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D,
- GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_CLAMP_TO_EDGE);
- byte[] arrayOfByte = new byte[2048];
- int[] arrayOfInt1 = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 17, 18, 19, 20, 21, 22, 23, 25, 26, 27, 28, 30, 31, 32, 34, 35, 36, 38, 39, 41, 42, 44, 45, 47, 49, 50, 52, 54, 55, 57, 59, 61, 63, 65, 67, 69, 71, 73, 75, 77, 79, 81, 83, 85, 87, 89, 92, 94, 96, 98, 101, 103, 105, 107, 110, 111, 113, 115, 118, 120, 122, 124, 126, 129, 131, 133, 135, 137, 139, 141, 143, 145, 147, 149, 150, 152, 154, 156, 158, 159, 161, 162, 164, 166, 167, 169, 170, 172, 173, 174, 176, 177, 178, 180, 181, 182, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 200, 200, 201, 202, 203, 203, 204, 205, 205, 207, 208, 208, 209, 209, 210, 210, 211, 211, 212, 212, 213, 213, 213, 214, 214, 215, 215, 215, 216, 216, 216, 216, 217, 217, 217, 218, 218, 218, 218, 219, 219, 219, 219, 219, 220, 220, 220, 220, 220, 220, 221, 221, 221, 221, 221, 222, 222, 222, 222, 222, 223, 223, 223, 223, 223, 224, 224, 224, 224, 224, 225, 225, 225, 225, 226, 226, 226, 227, 227, 227, 228, 228, 228, 229, 229, 230, 230, 230, 231, 231, 232, 232, 233, 233, 234, 234, 235, 235, 236, 236, 237, 238, 238, 239, 239, 241, 241, 242, 243, 243, 244, 245, 245, 246, 246, 247, 248, 248, 249, 250, 250, 251, 252, 252, 253, 254, 254, 255 };
- int[] arrayOfInt2 = { 0, 1, 3, 4, 5, 7, 8, 10, 11, 12, 14, 15, 17, 18, 19, 21, 22, 24, 25, 27, 28, 30, 31, 33, 34, 36, 37, 39, 40, 42, 44, 45, 47, 48, 50, 52, 54, 55, 57, 59, 61, 62, 64, 66, 68, 70, 72, 74, 76, 78, 80, 82, 83, 85, 87, 90, 92, 94, 96, 98, 101, 103, 105, 107, 110, 111, 113, 115, 117, 119, 122, 124, 126, 128, 130, 132, 134, 136, 138, 140, 142, 143, 145, 147, 149, 150, 152, 154, 155, 157, 158, 160, 161, 163, 164, 165, 167, 168, 169, 171, 172, 173, 174, 175, 176, 177, 179, 180, 181, 182, 183, 184, 184, 185, 186, 187, 188, 189, 190, 190, 191, 192, 193, 193, 194, 195, 195, 196, 197, 197, 198, 198, 199, 199, 200, 200, 201, 201, 202, 202, 203, 203, 204, 204, 205, 205, 205, 207, 207, 208, 208, 208, 209, 209, 210, 210, 210, 211, 211, 211, 212, 212, 212, 213, 213, 213, 214, 214, 214, 215, 215, 215, 216, 216, 216, 217, 217, 217, 218, 218, 219, 219, 219, 220, 220, 220, 221, 221, 222, 222, 222, 223, 223, 224, 224, 225, 225, 225, 226, 226, 227, 227, 228, 228, 228, 229, 229, 230, 230, 231, 231, 232, 232, 233, 233, 234, 234, 235, 235, 236, 236, 236, 237, 237, 238, 238, 239, 239, 241, 241, 242, 242, 243, 244, 244, 245, 245, 246, 246, 247, 247, 248, 248, 249, 249, 250, 250, 251, 251, 252, 252, 253, 253, 254, 254, 255 };
- int[] arrayOfInt3 = { 0, 1, 3, 4, 5, 6, 8, 9, 10, 11, 13, 14, 15, 17, 18, 19, 21, 22, 23, 25, 26, 28, 29, 30, 32, 33, 35, 36, 38, 39, 41, 43, 44, 46, 47, 49, 51, 53, 54, 56, 58, 60, 62, 64, 66, 68, 69, 71, 73, 76, 78, 80, 82, 83, 85, 87, 89, 91, 93, 95, 97, 100, 102, 104, 106, 108, 110, 111, 113, 115, 117, 119, 121, 123, 125, 127, 129, 130, 132, 134, 136, 138, 139, 141, 143, 145, 146, 148, 150, 151, 153, 155, 156, 158, 159, 161, 162, 164, 165, 167, 168, 169, 171, 172, 173, 175, 176, 177, 179, 180, 181, 182, 183, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 200, 200, 201, 202, 203, 204, 204, 205, 207, 207, 208, 209, 209, 210, 210, 211, 212, 212, 213, 213, 214, 214, 215, 215, 215, 216, 216, 217, 217, 217, 218, 218, 218, 219, 219, 219, 220, 220, 220, 220, 221, 221, 221, 221, 222, 222, 222, 222, 223, 223, 223, 223, 224, 224, 224, 224, 224, 225, 225, 225, 225, 225, 226, 226, 226, 226, 227, 227, 227, 227, 228, 228, 228, 228, 229, 229, 229, 230, 230, 230, 231, 231, 231, 232, 232, 233, 233, 233, 234, 234, 235, 235, 235, 236, 236, 237, 237, 238, 238, 239, 239, 241, 241, 242, 242, 243, 243, 244, 244, 245, 245, 246, 247, 247, 248, 248, 249, 249, 250, 250, 251, 252, 252, 253, 253, 254, 254, 255 };
- int[] arrayOfInt4 = { 0, 0, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 5, 5, 5, 6, 6, 6, 7, 7, 8, 8, 8, 9, 9, 10, 10, 10, 11, 11, 11, 12, 12, 13, 13, 13, 14, 14, 14, 15, 15, 16, 16, 16, 17, 17, 17, 18, 18, 18, 19, 19, 20, 20, 20, 21, 21, 21, 22, 22, 23, 23, 23, 24, 24, 24, 25, 25, 25, 25, 26, 26, 27, 27, 28, 28, 28, 28, 29, 29, 30, 29, 31, 31, 31, 31, 32, 32, 33, 33, 34, 34, 34, 34, 35, 35, 36, 36, 37, 37, 37, 38, 38, 39, 39, 39, 40, 40, 40, 41, 42, 42, 43, 43, 44, 44, 45, 45, 45, 46, 47, 47, 48, 48, 49, 50, 51, 51, 52, 52, 53, 53, 54, 55, 55, 56, 57, 57, 58, 59, 60, 60, 61, 62, 63, 63, 64, 65, 66, 67, 68, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 88, 89, 90, 91, 93, 94, 95, 96, 97, 98, 100, 101, 103, 104, 105, 107, 108, 110, 111, 113, 115, 116, 118, 119, 120, 122, 123, 125, 127, 128, 130, 132, 134, 135, 137, 139, 141, 143, 144, 146, 148, 150, 152, 154, 156, 158, 160, 163, 165, 167, 169, 171, 173, 175, 178, 180, 182, 185, 187, 189, 192, 194, 197, 199, 201, 204, 206, 209, 211, 214, 216, 219, 221, 224, 226, 229, 232, 234, 236, 239, 241, 245, 247, 250, 252, 255 };
- for (int i = 0; i < 256; i++){
- arrayOfByte[(i * 4)] = ((byte)arrayOfInt1[i]);
- arrayOfByte[(1 + i * 4)] = ((byte)arrayOfInt2[i]);
- arrayOfByte[(2 + i * 4)] = ((byte)arrayOfInt3[i]);
- arrayOfByte[(3 + i * 4)] = ((byte)arrayOfInt4[i]);
- }
- int[] arrayOfInt5 = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 5, 6, 7, 8, 9, 10, 12, 13, 14, 15, 16, 17, 19, 20, 21, 22, 23, 24, 26, 27, 28, 29, 30, 31, 32, 34, 35, 36, 37, 38, 39, 41, 42, 43, 44, 45, 46, 48, 49, 50, 51, 52, 53, 54, 56, 57, 58, 59, 60, 61, 63, 64, 65, 66, 67, 68, 70, 71, 72, 73, 74, 75, 77, 78, 79, 80, 81, 82, 83, 85, 86, 87, 88, 89, 90, 92, 93, 94, 95, 96, 97, 99, 100, 101, 102, 103, 104, 105, 107, 108, 109, 110, 111, 112, 114, 115, 116, 117, 118, 119, 121, 122, 123, 124, 125, 126, 128, 129, 130, 131, 132, 133, 134, 136, 137, 138, 139, 140, 141, 143, 144, 145, 146, 147, 148, 150, 151, 152, 153, 154, 155, 156, 158, 159, 160, 161, 162, 163, 165, 166, 167, 168, 169, 170, 172, 173, 174, 175, 176, 177, 178, 180, 181, 182, 183, 184, 185, 187, 188, 189, 190, 191, 192, 194, 195, 196, 197, 198, 199, 201, 202, 203, 204, 205, 206, 207, 209, 210, 211, 212, 213, 214, 216, 217, 218, 219, 220, 221, 223, 224, 225, 226, 227, 228, 230, 231, 232, 233, 234, 235, 236, 238, 239, 240, 241, 242, 243, 245, 246, 247, 248, 249, 250, 252, 253, 254, 255 };
- int[] arrayOfInt6 = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 4, 5, 6, 7, 9, 10, 11, 12, 14, 15, 16, 17, 19, 20, 21, 22, 24, 25, 26, 27, 29, 30, 31, 32, 34, 35, 36, 37, 39, 40, 41, 42, 44, 45, 46, 47, 49, 50, 51, 52, 53, 55, 56, 57, 58, 60, 61, 62, 63, 65, 66, 67, 68, 70, 71, 72, 73, 75, 76, 77, 78, 80, 81, 82, 83, 85, 86, 87, 88, 90, 91, 92, 93, 95, 96, 97, 98, 100, 101, 102, 103, 104, 106, 107, 108, 109, 111, 112, 113, 114, 116, 117, 118, 119, 121, 122, 123, 124, 126, 127, 128, 129, 131, 132, 133, 134, 136, 137, 138, 139, 141, 142, 143, 144, 146, 147, 148, 149, 151, 152, 153, 154, 155, 157, 158, 159, 160, 162, 163, 164, 165, 167, 168, 169, 170, 172, 173, 174, 175, 177, 178, 179, 180, 182, 183, 184, 185, 187, 188, 189, 190, 192, 193, 194, 195, 197, 198, 199, 200, 202, 203, 204, 205, 206, 208, 209, 210, 211, 213, 214, 215, 216, 218, 219, 220, 221, 223, 224, 225, 226, 228, 229, 230, 231, 233, 234, 235, 236, 238, 239, 240, 241, 243, 244, 245, 246, 248, 249, 250, 251, 253, 254, 255 };
- int[] arrayOfInt7 = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 5, 6, 7, 8, 9, 10, 11, 13, 14, 15, 16, 17, 18, 20, 21, 22, 23, 24, 25, 26, 28, 29, 30, 31, 32, 33, 34, 36, 37, 38, 39, 40, 41, 43, 44, 45, 46, 47, 48, 49, 51, 52, 53, 54, 55, 56, 57, 59, 60, 61, 62, 63, 64, 65, 67, 68, 69, 70, 71, 72, 74, 75, 76, 77, 78, 79, 80, 82, 83, 84, 85, 86, 87, 88, 90, 91, 92, 93, 94, 95, 96, 98, 99, 100, 101, 102, 103, 105, 106, 107, 108, 109, 110, 111, 113, 114, 115, 116, 117, 118, 119, 121, 122, 123, 124, 125, 126, 128, 129, 130, 131, 132, 133, 134, 136, 137, 138, 139, 140, 141, 142, 144, 145, 146, 147, 148, 149, 150, 152, 153, 154, 155, 156, 157, 159, 160, 161, 162, 163, 164, 165, 167, 168, 169, 170, 171, 172, 173, 175, 176, 177, 178, 179, 180, 181, 183, 184, 185, 186, 187, 188, 190, 191, 192, 193, 194, 195, 196, 198, 199, 200, 201, 202, 203, 204, 206, 207, 208, 209, 210, 211, 213, 214, 215, 216, 217, 218, 219, 221, 222, 223, 224, 225, 226, 227, 229, 230, 231, 232, 233, 234, 235, 237, 238, 239, 240, 241, 242, 244, 245, 246, 247, 248, 249, 250, 252, 253, 254, 255 };
- int[] arrayOfInt8 = { 0, 0, 0, 1, 1, 1, 2, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 12, 12, 13, 14, 14, 15, 15, 16, 17, 17, 18, 19, 19, 20, 21, 22, 22, 23, 24, 24, 25, 26, 27, 27, 28, 29, 30, 31, 31, 32, 33, 34, 34, 35, 36, 37, 38, 39, 39, 40, 41, 42, 43, 44, 44, 45, 46, 47, 48, 49, 50, 51, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 126, 127, 128, 129, 130, 131, 132, 134, 135, 136, 137, 138, 139, 140, 142, 143, 144, 145, 146, 147, 149, 150, 151, 152, 153, 155, 156, 157, 158, 159, 160, 162, 163, 164, 165, 166, 168, 169, 170, 171, 173, 174, 175, 176, 177, 179, 180, 181, 182, 184, 185, 186, 187, 189, 190, 191, 192, 194, 195, 196, 197, 199, 200, 201, 202, 204, 205, 206, 208, 209, 210, 211, 213, 214, 215, 217, 218, 219, 221, 222, 223, 224, 226, 227, 228, 230, 231, 232, 234, 235, 236, 238, 239, 240, 242, 243, 244, 246, 247, 248, 250, 251, 252, 254, 255 };
- for (int j = 0; j < 256; j++){
- arrayOfByte[(1024 + j * 4)] = ((byte)arrayOfInt5[j]);
- arrayOfByte[(1 + (1024 + j * 4))] = ((byte)arrayOfInt6[j]);
- arrayOfByte[(2 + (1024 + j * 4))] = ((byte)arrayOfInt7[j]);
- arrayOfByte[(3 + (1024 + j * 4))] = ((byte)arrayOfInt8[j]);
- }
- GLES20.glTexImage2D(GLES20.GL_TEXTURE_2D, 0, GLES20.GL_RGBA, 256, 2, 0, GLES20.GL_RGBA, GLES20.GL_UNSIGNED_BYTE, ByteBuffer.wrap(arrayOfByte));
- GLES20.glActiveTexture(GLES20.GL_TEXTURE4);
- GLES20.glActiveTexture(GLES20.GL_TEXTURE5);
- GLES20.glActiveTexture(GLES20.GL_TEXTURE6);
- }
- });
- }
-}
diff --git a/Live/src/main/java/com/seu/magicfilter/advanced/MagicSunsetFilter.java b/Live/src/main/java/com/seu/magicfilter/advanced/MagicSunsetFilter.java
deleted file mode 100644
index 593e8042..00000000
--- a/Live/src/main/java/com/seu/magicfilter/advanced/MagicSunsetFilter.java
+++ /dev/null
@@ -1,120 +0,0 @@
-package com.seu.magicfilter.advanced;
-
-import android.opengl.GLES20;
-
-import com.frank.live.R;
-import com.seu.magicfilter.base.gpuimage.GPUImageFilter;
-import com.seu.magicfilter.utils.MagicFilterType;
-import com.seu.magicfilter.utils.OpenGLUtils;
-
-import java.nio.ByteBuffer;
-
-public class MagicSunsetFilter extends GPUImageFilter {
- private int mMaskGrey1TextureId = -1;
- private int mMaskGrey1UniformLocation;
- private int mMaskGrey2TextureId = -1;
- private int mMaskGrey2UniformLocation;
- private int[] mToneCurveTexture = { -1 };
- private int mToneCurveTextureUniformLocation;
-
- public MagicSunsetFilter(){
- super(MagicFilterType.SUNSET, R.raw.sunset);
- }
-
- @Override
- protected void onDestroy(){
- super.onDestroy();
- GLES20.glDeleteTextures(3, new int[]{mToneCurveTexture[0], mMaskGrey1TextureId, mMaskGrey2TextureId}, 0);
- mToneCurveTexture[0] = -1;
- mMaskGrey1TextureId = -1;
- mMaskGrey2TextureId = -1;
- }
-
- @Override
- protected void onDrawArraysAfter(){
- if (mToneCurveTexture[0] != -1){
- GLES20.glActiveTexture(GLES20.GL_TEXTURE3);
- GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, 0);
- GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
- }
- if (mMaskGrey1TextureId != -1){
- GLES20.glActiveTexture(GLES20.GL_TEXTURE4);
- GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, 0);
- GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
- }
- if (mMaskGrey2TextureId != -1){
- GLES20.glActiveTexture(GLES20.GL_TEXTURE5);
- GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, 0);
- GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
- }
- }
-
- @Override
- protected void onDrawArraysPre() {
- if (mToneCurveTexture[0] != -1){
- GLES20.glActiveTexture(GLES20.GL_TEXTURE3);
- GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mToneCurveTexture[0]);
- GLES20.glUniform1i(mToneCurveTextureUniformLocation, 3);
- }
- if (mMaskGrey1TextureId != -1){
- GLES20.glActiveTexture(GLES20.GL_TEXTURE4);
- GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mMaskGrey1TextureId);
- GLES20.glUniform1i(mMaskGrey1UniformLocation, 4);
- }
- if (mMaskGrey2TextureId != -1){
- GLES20.glActiveTexture(GLES20.GL_TEXTURE5);
- GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mMaskGrey2TextureId);
- GLES20.glUniform1i(mMaskGrey2UniformLocation, 5);
- }
- }
-
- @Override
- protected void onInit() {
- super.onInit();
- mToneCurveTextureUniformLocation = GLES20.glGetUniformLocation(getProgram(), "curve");
- mMaskGrey1UniformLocation = GLES20.glGetUniformLocation(getProgram(), "grey1Frame");
- mMaskGrey2UniformLocation = GLES20.glGetUniformLocation(getProgram(), "grey2Frame");
- }
-
- @Override
- protected void onInitialized() {
- super.onInitialized();
- runOnDraw(new Runnable(){
- public void run(){
- GLES20.glGenTextures(1, mToneCurveTexture, 0);
- GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mToneCurveTexture[0]);
- GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D,
- GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR);
- GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D,
- GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_LINEAR);
- GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D,
- GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_CLAMP_TO_EDGE);
- GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D,
- GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_CLAMP_TO_EDGE);
- byte[] arrayOfByte = new byte[2048];
- int[] arrayOfInt1 = { 0, 1, 2, 3, 5, 5, 7, 8, 9, 10, 11, 12, 13, 15, 16, 16, 18, 19, 20, 21, 23, 24, 25, 26, 27, 29, 30, 31, 32, 33, 35, 36, 38, 39, 40, 41, 42, 44, 45, 47, 48, 49, 51, 52, 54, 55, 56, 59, 60, 62, 63, 64, 66, 67, 70, 71, 72, 74, 76, 78, 79, 80, 83, 84, 85, 88, 89, 90, 93, 94, 95, 98, 99, 100, 102, 104, 106, 107, 108, 109, 112, 113, 114, 116, 117, 118, 119, 120, 122, 124, 125, 126, 128, 129, 130, 131, 132, 132, 133, 135, 136, 137, 138, 139, 140, 141, 142, 142, 143, 145, 146, 147, 148, 148, 149, 150, 151, 151, 152, 153, 154, 155, 155, 156, 157, 157, 158, 159, 160, 160, 161, 162, 162, 163, 164, 165, 165, 166, 167, 167, 168, 169, 169, 170, 171, 171, 172, 173, 173, 174, 175, 175, 176, 177, 177, 178, 178, 179, 179, 180, 181, 181, 182, 183, 183, 184, 185, 185, 186, 187, 188, 188, 189, 190, 190, 191, 192, 193, 193, 194, 194, 194, 195, 196, 197, 197, 198, 199, 200, 201, 201, 202, 203, 204, 204, 205, 206, 207, 208, 208, 208, 209, 210, 211, 212, 212, 213, 214, 215, 216, 217, 218, 218, 219, 220, 221, 222, 222, 223, 224, 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 234, 235, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, 245, 246, 247, 247, 248, 248, 249, 250, 251, 252, 253, 254, 255 };
- int[] arrayOfInt2 = { 0, 1, 2, 3, 4, 5, 6, 7, 9, 9, 10, 12, 12, 13, 14, 16, 16, 17, 19, 20, 20, 22, 23, 24, 25, 26, 27, 29, 30, 31, 32, 33, 35, 36, 37, 39, 40, 41, 42, 43, 44, 46, 47, 49, 50, 51, 53, 54, 56, 57, 59, 61, 62, 64, 65, 66, 69, 70, 72, 73, 76, 77, 78, 80, 82, 84, 85, 87, 89, 90, 93, 94, 95, 98, 99, 100, 103, 104, 106, 108, 109, 111, 112, 114, 116, 117, 118, 120, 122, 123, 124, 125, 126, 129, 130, 131, 132, 133, 135, 136, 137, 138, 139, 140, 141, 142, 143, 145, 146, 147, 148, 149, 150, 151, 152, 152, 153, 154, 155, 156, 157, 158, 158, 159, 160, 161, 162, 162, 163, 164, 165, 165, 166, 167, 167, 168, 169, 170, 170, 171, 172, 172, 173, 173, 174, 175, 175, 176, 177, 177, 178, 178, 178, 179, 179, 180, 181, 181, 182, 182, 183, 184, 184, 185, 185, 186, 187, 187, 188, 188, 189, 190, 190, 191, 191, 192, 193, 193, 194, 194, 194, 195, 195, 196, 197, 197, 198, 199, 199, 200, 201, 202, 202, 203, 204, 204, 205, 206, 207, 208, 208, 208, 209, 210, 210, 211, 212, 213, 214, 215, 215, 216, 217, 218, 219, 220, 221, 222, 222, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 234, 235, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, 245, 246, 247, 248, 248, 249, 250, 251, 252, 253, 254, 255 };
- int[] arrayOfInt3 = { 0, 1, 2, 3, 4, 5, 5, 7, 8, 9, 9, 11, 12, 12, 13, 14, 16, 16, 17, 18, 20, 20, 21, 22, 23, 25, 25, 26, 27, 29, 30, 31, 31, 32, 34, 35, 36, 37, 39, 40, 41, 41, 42, 44, 45, 46, 47, 48, 50, 51, 52, 53, 54, 56, 57, 59, 60, 61, 63, 64, 65, 66, 67, 69, 71, 72, 73, 74, 76, 78, 79, 80, 82, 83, 84, 85, 88, 89, 90, 92, 93, 94, 95, 98, 99, 100, 102, 103, 104, 106, 107, 108, 111, 112, 113, 114, 116, 117, 118, 119, 120, 122, 123, 124, 125, 126, 128, 129, 130, 131, 132, 133, 135, 136, 137, 138, 139, 140, 141, 142, 143, 145, 146, 147, 147, 148, 149, 150, 151, 152, 153, 154, 154, 155, 156, 157, 158, 159, 159, 160, 161, 162, 162, 163, 164, 165, 166, 166, 167, 168, 169, 169, 170, 171, 172, 172, 173, 174, 175, 175, 176, 177, 178, 178, 178, 179, 179, 180, 181, 182, 182, 183, 184, 185, 185, 186, 187, 188, 188, 189, 190, 191, 191, 192, 193, 194, 194, 194, 195, 196, 197, 198, 198, 199, 200, 201, 202, 203, 203, 204, 205, 206, 207, 208, 208, 209, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 222, 223, 224, 225, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 235, 236, 237, 239, 240, 241, 242, 243, 244, 245, 246, 247, 248, 248, 249, 250, 251, 252, 253, 254, 255 };
- int[] arrayOfInt4 = { 0, 1, 3, 4, 6, 7, 9, 10, 12, 13, 14, 16, 17, 19, 20, 21, 23, 24, 26, 27, 28, 30, 31, 32, 34, 35, 36, 38, 39, 40, 42, 43, 44, 45, 47, 48, 49, 51, 52, 53, 54, 55, 57, 58, 59, 60, 62, 63, 64, 65, 66, 67, 69, 70, 71, 72, 73, 74, 75, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 115, 116, 117, 118, 119, 120, 121, 121, 122, 123, 124, 125, 126, 126, 127, 128, 129, 130, 130, 131, 132, 133, 134, 135, 135, 136, 137, 138, 139, 140, 141, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 220, 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, 230, 231, 232, 233, 234, 235, 235, 236, 237, 238, 239, 239, 240, 241, 242, 243, 243, 244, 245, 245, 246, 247, 247, 248, 249, 249, 250, 251, 251, 252, 252, 253, 253, 254, 254, 255 };
- for (int i = 0; i < 256; i++)
- {
- arrayOfByte[(i * 4)] = ((byte)arrayOfInt1[i]);
- arrayOfByte[(1 + i * 4)] = ((byte)arrayOfInt2[i]);
- arrayOfByte[(2 + i * 4)] = ((byte)arrayOfInt3[i]);
- arrayOfByte[(3 + i * 4)] = ((byte)arrayOfInt4[i]);
- }
- int[] arrayOfInt5 = { 0, 0, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 5, 5, 5, 6, 6, 6, 7, 7, 8, 8, 8, 9, 9, 10, 10, 10, 11, 11, 11, 12, 12, 13, 13, 13, 14, 14, 14, 15, 15, 16, 16, 16, 17, 17, 17, 18, 18, 18, 19, 19, 20, 20, 20, 21, 21, 21, 22, 22, 23, 23, 23, 24, 24, 24, 25, 25, 25, 25, 26, 26, 27, 27, 28, 28, 28, 28, 29, 29, 30, 29, 31, 31, 31, 31, 32, 32, 33, 33, 34, 34, 34, 34, 35, 35, 36, 36, 37, 37, 37, 38, 38, 39, 39, 39, 40, 40, 40, 41, 42, 42, 43, 43, 44, 44, 45, 45, 45, 46, 47, 47, 48, 48, 49, 50, 51, 51, 52, 52, 53, 53, 54, 55, 55, 56, 57, 57, 58, 59, 60, 60, 61, 62, 63, 63, 64, 65, 66, 67, 68, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 88, 89, 90, 91, 93, 94, 95, 96, 97, 98, 100, 101, 103, 104, 105, 107, 108, 110, 111, 113, 115, 116, 118, 119, 120, 122, 123, 125, 127, 128, 130, 132, 134, 135, 137, 139, 141, 143, 144, 146, 148, 150, 152, 154, 156, 158, 160, 163, 165, 167, 169, 171, 173, 175, 178, 180, 182, 185, 187, 189, 192, 194, 197, 199, 201, 204, 206, 209, 211, 214, 216, 219, 221, 224, 226, 229, 232, 234, 236, 239, 241, 245, 247, 250, 252, 255 };
- for (int j = 0; j < 256; j++)
- {
- arrayOfByte[(1024 + j * 4)] = ((byte)arrayOfInt5[j]);
- arrayOfByte[(1 + (1024 + j * 4))] = ((byte)arrayOfInt5[j]);
- arrayOfByte[(2 + (1024 + j * 4))] = ((byte)arrayOfInt5[j]);
- arrayOfByte[(3 + (1024 + j * 4))] = -1;
- }
- GLES20.glTexImage2D(GLES20.GL_TEXTURE_2D, 0, GLES20.GL_RGBA, 256, 2, 0, GLES20.GL_RGBA, GLES20.GL_UNSIGNED_BYTE, ByteBuffer.wrap(arrayOfByte));
- mMaskGrey1TextureId = OpenGLUtils.loadTexture(getContext(), "filter/rise_mask1.jpg");
- mMaskGrey2TextureId = OpenGLUtils.loadTexture(getContext(), "filter/rise_mask2.jpg");
- }
- });
- }
-}
diff --git a/Live/src/main/java/com/seu/magicfilter/advanced/MagicSutroFilter.java b/Live/src/main/java/com/seu/magicfilter/advanced/MagicSutroFilter.java
deleted file mode 100644
index fe5d9773..00000000
--- a/Live/src/main/java/com/seu/magicfilter/advanced/MagicSutroFilter.java
+++ /dev/null
@@ -1,68 +0,0 @@
-package com.seu.magicfilter.advanced;
-
-import android.opengl.GLES20;
-
-import com.frank.live.R;
-import com.seu.magicfilter.base.gpuimage.GPUImageFilter;
-import com.seu.magicfilter.utils.MagicFilterType;
-import com.seu.magicfilter.utils.OpenGLUtils;
-
-public class MagicSutroFilter extends GPUImageFilter {
- private int[] inputTextureHandles = {-1,-1,-1,-1,-1};
- private int[] inputTextureUniformLocations = {-1,-1,-1,-1,-1};
- private int mGLStrengthLocation;
-
- public MagicSutroFilter(){
- super(MagicFilterType.SUTRO, R.raw.sutro);
- }
-
- @Override
- protected void onDestroy() {
- super.onDestroy();
- GLES20.glDeleteTextures(inputTextureHandles.length, inputTextureHandles, 0);
- for (int i = 0; i < inputTextureHandles.length; i++) {
- inputTextureHandles[i] = -1;
- }
- }
-
- protected void onDrawArraysAfter(){
- for(int i = 0; i < inputTextureHandles.length && inputTextureHandles[i] != OpenGLUtils.NO_TEXTURE; i++){
- GLES20.glActiveTexture(GLES20.GL_TEXTURE0 + (i+3));
- GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, 0);
- GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
- }
- }
-
- @Override
- protected void onDrawArraysPre(){
- for(int i = 0; i < inputTextureHandles.length && inputTextureHandles[i] != OpenGLUtils.NO_TEXTURE; i++){
- GLES20.glActiveTexture(GLES20.GL_TEXTURE0 + (i+3) );
- GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, inputTextureHandles[i]);
- GLES20.glUniform1i(inputTextureUniformLocations[i], (i+3));
- }
- }
-
- @Override
- protected void onInit() {
- super.onInit();
- for(int i = 0; i < inputTextureUniformLocations.length; i++) {
- inputTextureUniformLocations[i] = GLES20.glGetUniformLocation(getProgram(), "inputImageTexture" + (2 + i));
- }
- mGLStrengthLocation = GLES20.glGetUniformLocation(getProgram(), "strength");
- }
-
- @Override
- protected void onInitialized() {
- super.onInitialized();
- setFloat(mGLStrengthLocation, 1.0f);
- runOnDraw(new Runnable(){
- public void run(){
- inputTextureHandles[0] = OpenGLUtils.loadTexture(getContext(), "filter/vignette_map.png");
- inputTextureHandles[1] = OpenGLUtils.loadTexture(getContext(), "filter/sutrometal.png");
- inputTextureHandles[2] = OpenGLUtils.loadTexture(getContext(), "filter/softlight.png");
- inputTextureHandles[3] = OpenGLUtils.loadTexture(getContext(), "filter/sutroedgeburn.png");
- inputTextureHandles[4] = OpenGLUtils.loadTexture(getContext(), "filter/sutrocurves.png");
- }
- });
- }
-}
diff --git a/Live/src/main/java/com/seu/magicfilter/advanced/MagicSweetsFilter.java b/Live/src/main/java/com/seu/magicfilter/advanced/MagicSweetsFilter.java
deleted file mode 100644
index de98e69e..00000000
--- a/Live/src/main/java/com/seu/magicfilter/advanced/MagicSweetsFilter.java
+++ /dev/null
@@ -1,96 +0,0 @@
-package com.seu.magicfilter.advanced;
-
-import android.opengl.GLES20;
-
-import com.frank.live.R;
-import com.seu.magicfilter.base.gpuimage.GPUImageFilter;
-import com.seu.magicfilter.utils.MagicFilterType;
-import com.seu.magicfilter.utils.OpenGLUtils;
-
-import java.nio.ByteBuffer;
-
-public class MagicSweetsFilter extends GPUImageFilter {
- private int[] mToneCurveTexture = {-1};
- private int mToneCurveTextureUniformLocation;
- private int mMaskGrey1TextureId = -1;
- private int mMaskGrey1UniformLocation;
- private int mLowPerformanceUniformLocation;
-
- public MagicSweetsFilter(){
- super(MagicFilterType.SWEETS, R.raw.sweets);
- }
-
- @Override
- protected void onDestroy(){
- super.onDestroy();
- GLES20.glDeleteTextures(2, new int[]{mToneCurveTexture[0], mMaskGrey1TextureId}, 0);
- mToneCurveTexture[0] = -1;
- mMaskGrey1TextureId = -1;
- }
-
- @Override
- protected void onDrawArraysAfter(){
- if (mToneCurveTexture[0] != -1){
- GLES20.glActiveTexture(GLES20.GL_TEXTURE3);
- GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, 0);
- GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
- }
- if (mMaskGrey1TextureId != -1){
- GLES20.glActiveTexture(GLES20.GL_TEXTURE4);
- GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, 0);
- GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
- }
- }
-
- @Override
- protected void onDrawArraysPre(){
- if (mToneCurveTexture[0] != -1){
- GLES20.glActiveTexture(GLES20.GL_TEXTURE3);
- GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mToneCurveTexture[0]);
- GLES20.glUniform1i(mToneCurveTextureUniformLocation, 3);
- }
- if (mMaskGrey1TextureId != -1){
- GLES20.glActiveTexture(GLES20.GL_TEXTURE4);
- GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mMaskGrey1TextureId);
- GLES20.glUniform1i(mMaskGrey1UniformLocation, 4);
- }
- }
-
- @Override
- protected void onInit(){
- super.onInit();
- mToneCurveTextureUniformLocation = GLES20.glGetUniformLocation(getProgram(), "curve");
- mMaskGrey1UniformLocation = GLES20.glGetUniformLocation(getProgram(), "grey1Frame");
- mLowPerformanceUniformLocation = GLES20.glGetUniformLocation(getProgram(), "lowPerformance");
- setInteger(mLowPerformanceUniformLocation, 1);
- }
-
- @Override
- protected void onInitialized(){
- super.onInitialized();
- runOnDraw(new Runnable(){
- public void run(){
- GLES20.glGenTextures(1, mToneCurveTexture, 0);
- GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mToneCurveTexture[0]);
- GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D,
- GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR);
- GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D,
- GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_LINEAR);
- GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D,
- GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_CLAMP_TO_EDGE);
- GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D,
- GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_CLAMP_TO_EDGE);
- byte[] arrayOfByte = new byte[1024];
- int[] arrayOfInt = { 0, 1, 2, 2, 3, 4, 5, 6, 6, 7, 8, 9, 10, 10, 11, 12, 13, 14, 14, 15, 16, 17, 18, 19, 19, 20, 21, 22, 23, 24, 24, 25, 26, 27, 28, 29, 30, 30, 31, 32, 33, 34, 35, 36, 37, 38, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 71, 72, 73, 74, 75, 76, 77, 79, 80, 81, 82, 83, 84, 86, 87, 88, 89, 90, 92, 93, 94, 95, 96, 98, 99, 100, 101, 103, 104, 105, 106, 108, 109, 110, 111, 113, 114, 115, 116, 118, 119, 120, 121, 123, 124, 125, 126, 128, 129, 130, 132, 133, 134, 135, 137, 138, 139, 140, 142, 143, 144, 145, 147, 148, 149, 150, 152, 153, 154, 155, 157, 158, 159, 160, 161, 163, 164, 165, 166, 167, 169, 170, 171, 172, 173, 174, 176, 177, 178, 179, 180, 181, 182, 183, 184, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 209, 210, 211, 212, 213, 214, 215, 216, 217, 217, 218, 219, 220, 221, 222, 222, 223, 224, 225, 226, 227, 227, 228, 229, 230, 230, 231, 232, 233, 234, 234, 235, 236, 237, 237, 238, 239, 240, 240, 241, 242, 243, 243, 244, 245, 246, 246, 247, 248, 248, 249, 250, 251, 251, 252, 253, 254, 254, 255 };
- for (int i = 0; i < 256; i++){
- arrayOfByte[(i * 4)] = ((byte)arrayOfInt[i]);
- arrayOfByte[(1 + i * 4)] = ((byte)arrayOfInt[i]);
- arrayOfByte[(2 + i * 4)] = ((byte)arrayOfInt[i]);
- arrayOfByte[(3 + i * 4)] = ((byte)i);
- }
- GLES20.glTexImage2D(GLES20.GL_TEXTURE_2D, 0, GLES20.GL_RGBA, 256, 1, 0, GLES20.GL_RGBA, GLES20.GL_UNSIGNED_BYTE, ByteBuffer.wrap(arrayOfByte));
- mMaskGrey1TextureId = OpenGLUtils.loadTexture(getContext(), "filter/rise_mask2.jpg");
- }
- });
- }
-}
diff --git a/Live/src/main/java/com/seu/magicfilter/advanced/MagicTenderFilter.java b/Live/src/main/java/com/seu/magicfilter/advanced/MagicTenderFilter.java
deleted file mode 100644
index da82d62b..00000000
--- a/Live/src/main/java/com/seu/magicfilter/advanced/MagicTenderFilter.java
+++ /dev/null
@@ -1,96 +0,0 @@
-package com.seu.magicfilter.advanced;
-
-import android.opengl.GLES20;
-
-import com.frank.live.R;
-import com.seu.magicfilter.base.gpuimage.GPUImageFilter;
-import com.seu.magicfilter.utils.MagicFilterType;
-import com.seu.magicfilter.utils.OpenGLUtils;
-
-import java.nio.ByteBuffer;
-
-public class MagicTenderFilter extends GPUImageFilter{
- private int[] mToneCurveTexture = {-1};
- private int mToneCurveTextureUniformLocation;
- private int mMaskGrey1TextureId = -1;
- private int mMaskGrey1UniformLocation;
-
- public MagicTenderFilter(){
- super(MagicFilterType.TENDER, R.raw.tender);
- }
-
- @Override
- protected void onDestroy() {
- super.onDestroy();
- GLES20.glDeleteTextures(2, new int[]{mToneCurveTexture[0], mMaskGrey1TextureId}, 0);
- mToneCurveTexture[0] = -1;
- mMaskGrey1TextureId = -1;
- }
-
- @Override
- protected void onDrawArraysAfter() {
- if (mToneCurveTexture[0] != -1){
- GLES20.glActiveTexture(GLES20.GL_TEXTURE3);
- GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, 0);
- GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
- }
- if (mMaskGrey1TextureId != -1){
- GLES20.glActiveTexture(GLES20.GL_TEXTURE4);
- GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, 0);
- GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
- }
- }
-
- @Override
- protected void onDrawArraysPre() {
- if (mToneCurveTexture[0] != -1){
- GLES20.glActiveTexture(GLES20.GL_TEXTURE3);
- GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mToneCurveTexture[0]);
- GLES20.glUniform1i(mToneCurveTextureUniformLocation, 3);
- }
- if (mMaskGrey1TextureId != -1){
- GLES20.glActiveTexture(GLES20.GL_TEXTURE4);
- GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mMaskGrey1TextureId);
- GLES20.glUniform1i(mMaskGrey1UniformLocation, 4);
- }
- }
-
- @Override
- protected void onInit() {
- super.onInit();
- mToneCurveTextureUniformLocation = GLES20.glGetUniformLocation(getProgram(), "curve");
- mMaskGrey1UniformLocation = GLES20.glGetUniformLocation(getProgram(), "grey1Frame");
- }
-
- @Override
- protected void onInitialized() {
- super.onInitialized();
- runOnDraw(new Runnable(){
- public void run(){
- GLES20.glGenTextures(1, mToneCurveTexture, 0);
- GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mToneCurveTexture[0]);
- GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D,
- GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR);
- GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D,
- GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_LINEAR);
- GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D,
- GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_CLAMP_TO_EDGE);
- GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D,
- GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_CLAMP_TO_EDGE);
- byte[] arrayOfByte = new byte[1024];
- int[] arrayOfInt1 = { 10, 12, 14, 15, 17, 19, 21, 22, 24, 26, 28, 29, 31, 33, 35, 38, 40, 41, 43, 45, 47, 48, 50, 52, 53, 55, 57, 58, 60, 61, 63, 65, 66, 68, 69, 71, 72, 74, 75, 77, 79, 80, 81, 83, 84, 86, 87, 89, 92, 93, 94, 96, 97, 99, 100, 101, 103, 104, 105, 107, 108, 109, 110, 112, 113, 114, 116, 117, 118, 119, 120, 122, 123, 124, 125, 126, 127, 129, 130, 131, 132, 133, 134, 135, 136, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 158, 159, 160, 161, 162, 163, 164, 165, 166, 166, 167, 168, 169, 170, 171, 171, 172, 173, 174, 175, 175, 176, 177, 178, 179, 179, 180, 181, 182, 182, 183, 184, 184, 185, 186, 187, 187, 188, 189, 189, 190, 191, 191, 192, 193, 193, 194, 195, 195, 196, 196, 197, 198, 198, 199, 200, 200, 201, 201, 202, 202, 203, 204, 204, 205, 205, 206, 206, 207, 207, 208, 209, 209, 210, 210, 211, 211, 212, 212, 213, 213, 214, 214, 215, 215, 216, 216, 216, 217, 217, 218, 218, 219, 219, 219, 220, 220, 221, 221, 222, 222, 223, 223, 224, 224, 224, 225, 225, 226, 226, 227, 227, 227, 228, 228, 229, 229, 230, 230, 230, 231, 231, 232, 232, 232, 233, 233, 234, 234, 234, 234, 235, 235, 236, 236, 236, 237, 237, 238, 238, 238, 239, 239, 240, 240, 240, 241, 241, 242, 242 };
- int[] arrayOfInt2 = { 10, 12, 14, 15, 17, 19, 19, 21, 22, 24, 26, 28, 29, 31, 33, 35, 36, 36, 38, 40, 41, 43, 45, 47, 48, 50, 52, 52, 53, 55, 57, 58, 60, 61, 63, 65, 66, 68, 69, 69, 71, 72, 74, 75, 77, 79, 80, 81, 83, 84, 86, 86, 87, 89, 90, 92, 93, 94, 96, 97, 99, 100, 101, 103, 103, 104, 105, 107, 108, 109, 110, 112, 113, 114, 116, 117, 118, 119, 120, 122, 122, 123, 124, 125, 126, 127, 129, 130, 131, 132, 133, 134, 135, 136, 138, 139, 140, 141, 142, 143, 144, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 158, 159, 160, 161, 162, 163, 164, 165, 166, 166, 167, 168, 169, 170, 171, 171, 172, 173, 174, 175, 175, 176, 177, 178, 179, 179, 180, 181, 182, 182, 183, 184, 184, 185, 186, 187, 187, 188, 189, 190, 191, 191, 192, 193, 193, 194, 195, 195, 196, 196, 197, 198, 198, 199, 200, 200, 201, 201, 202, 202, 204, 204, 205, 205, 206, 206, 207, 207, 208, 209, 209, 210, 210, 211, 211, 212, 213, 213, 214, 214, 215, 215, 216, 216, 217, 217, 218, 218, 219, 219, 220, 220, 221, 221, 222, 222, 223, 223, 224, 224, 224, 225, 226, 226, 227, 227, 227, 228, 228, 229, 229, 230, 230, 231, 231, 232, 232, 232, 233, 233, 234, 234, 234, 235, 236, 236, 236, 237, 237, 238, 238, 238, 239, 239, 240, 240, 241, 241, 242, 242 };
- int[] arrayOfInt3 = { 10, 12, 12, 14, 15, 15, 17, 17, 19, 21, 21, 22, 24, 24, 26, 28, 28, 29, 31, 31, 33, 33, 35, 36, 36, 38, 40, 40, 41, 43, 43, 45, 47, 47, 48, 50, 52, 52, 53, 55, 55, 57, 58, 58, 60, 61, 63, 63, 65, 66, 68, 68, 69, 71, 71, 72, 74, 75, 77, 77, 79, 80, 81, 81, 83, 84, 86, 87, 87, 89, 90, 92, 93, 94, 94, 96, 97, 99, 100, 101, 103, 103, 104, 105, 107, 108, 109, 110, 112, 113, 113, 114, 116, 117, 118, 119, 120, 122, 123, 124, 125, 126, 127, 129, 130, 130, 131, 132, 133, 134, 135, 136, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 154, 155, 156, 157, 158, 158, 159, 160, 161, 162, 163, 164, 165, 166, 166, 167, 169, 170, 171, 171, 172, 173, 174, 175, 175, 176, 178, 179, 179, 180, 181, 182, 182, 183, 184, 185, 186, 187, 187, 188, 189, 190, 191, 191, 192, 193, 193, 195, 195, 196, 196, 197, 198, 199, 200, 200, 201, 201, 202, 203, 204, 204, 205, 206, 206, 207, 207, 209, 209, 210, 210, 211, 212, 212, 213, 213, 214, 215, 215, 216, 217, 217, 218, 218, 219, 219, 220, 220, 221, 222, 222, 223, 223, 224, 224, 225, 225, 226, 227, 227, 227, 228, 229, 229, 230, 230, 231, 231, 232, 232, 233, 233, 234, 234, 235, 235, 236, 236, 237, 238, 238, 238, 239, 240, 240, 240, 241, 242, 242 };
- int[] arrayOfInt4 = { 0, 0, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 5, 5, 5, 6, 6, 6, 7, 7, 8, 8, 8, 9, 9, 10, 10, 10, 11, 11, 11, 12, 12, 13, 13, 13, 14, 14, 14, 15, 15, 16, 16, 16, 17, 17, 17, 18, 18, 18, 19, 19, 20, 20, 20, 21, 21, 21, 22, 22, 23, 23, 23, 24, 24, 24, 25, 25, 25, 25, 26, 26, 27, 27, 28, 28, 28, 28, 29, 29, 30, 29, 31, 31, 31, 31, 32, 32, 33, 33, 34, 34, 34, 34, 35, 35, 36, 36, 37, 37, 37, 38, 38, 39, 39, 39, 40, 40, 40, 41, 42, 42, 43, 43, 44, 44, 45, 45, 45, 46, 47, 47, 48, 48, 49, 50, 51, 51, 52, 52, 53, 53, 54, 55, 55, 56, 57, 57, 58, 59, 60, 60, 61, 62, 63, 63, 64, 65, 66, 67, 68, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 88, 89, 90, 91, 93, 94, 95, 96, 97, 98, 100, 101, 103, 104, 105, 107, 108, 110, 111, 113, 115, 116, 118, 119, 120, 122, 123, 125, 127, 128, 130, 132, 134, 135, 137, 139, 141, 143, 144, 146, 148, 150, 152, 154, 156, 158, 160, 163, 165, 167, 169, 171, 173, 175, 178, 180, 182, 185, 187, 189, 192, 194, 197, 199, 201, 204, 206, 209, 211, 214, 216, 219, 221, 224, 226, 229, 232, 234, 236, 239, 241, 245, 247, 250, 252, 255 };
- for (int i = 0; i < 256; i++){
- arrayOfByte[(i * 4)] = ((byte)arrayOfInt1[i]);
- arrayOfByte[(1 + i * 4)] = ((byte)arrayOfInt2[i]);
- arrayOfByte[(2 + i * 4)] = ((byte)arrayOfInt3[i]);
- arrayOfByte[(3 + i * 4)] = ((byte)arrayOfInt4[i]);
- }
- GLES20.glTexImage2D(GLES20.GL_TEXTURE_2D, 0, GLES20.GL_RGBA, 256, 1, 0, GLES20.GL_RGBA, GLES20.GL_UNSIGNED_BYTE, ByteBuffer.wrap(arrayOfByte));
- mMaskGrey1TextureId = OpenGLUtils.loadTexture(getContext(), "filter/bluevintage_mask1.jpg");
- }
- });
- }
-}
diff --git a/Live/src/main/java/com/seu/magicfilter/advanced/MagicToasterFilter.java b/Live/src/main/java/com/seu/magicfilter/advanced/MagicToasterFilter.java
deleted file mode 100644
index f860e3d5..00000000
--- a/Live/src/main/java/com/seu/magicfilter/advanced/MagicToasterFilter.java
+++ /dev/null
@@ -1,70 +0,0 @@
-package com.seu.magicfilter.advanced;
-
-import android.opengl.GLES20;
-
-import com.frank.live.R;
-import com.seu.magicfilter.base.gpuimage.GPUImageFilter;
-import com.seu.magicfilter.utils.MagicFilterType;
-import com.seu.magicfilter.utils.OpenGLUtils;
-
-public class MagicToasterFilter extends GPUImageFilter{
- private int[] inputTextureHandles = {-1,-1,-1,-1,-1};
- private int[] inputTextureUniformLocations = {-1,-1,-1,-1,-1};
- private int mGLStrengthLocation;
-
- public MagicToasterFilter(){
- super(MagicFilterType.TOASTER2, R.raw.toaster2_filter_shader);
- }
-
- @Override
- protected void onDestroy() {
- super.onDestroy();
- GLES20.glDeleteTextures(inputTextureHandles.length, inputTextureHandles, 0);
- for(int i = 0; i < inputTextureHandles.length; i++)
- inputTextureHandles[i] = -1;
- }
-
- @Override
- protected void onDrawArraysAfter() {
- for(int i = 0; i < inputTextureHandles.length
- && inputTextureHandles[i] != OpenGLUtils.NO_TEXTURE; i++){
- GLES20.glActiveTexture(GLES20.GL_TEXTURE0 + (i+3));
- GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, 0);
- GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
- }
- }
-
- @Override
- protected void onDrawArraysPre() {
- for(int i = 0; i < inputTextureHandles.length
- && inputTextureHandles[i] != OpenGLUtils.NO_TEXTURE; i++){
- GLES20.glActiveTexture(GLES20.GL_TEXTURE0 + (i+3) );
- GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, inputTextureHandles[i]);
- GLES20.glUniform1i(inputTextureUniformLocations[i], (i+3));
- }
- }
-
- @Override
- protected void onInit() {
- super.onInit();
- for(int i = 0; i < inputTextureUniformLocations.length; i++) {
- inputTextureUniformLocations[i] = GLES20.glGetUniformLocation(getProgram(), "inputImageTexture" + (2 + i));
- }
- mGLStrengthLocation = GLES20.glGetUniformLocation(getProgram(), "strength");
- }
-
- @Override
- protected void onInitialized() {
- super.onInitialized();
- setFloat(mGLStrengthLocation, 1.0f);
- runOnDraw(new Runnable(){
- public void run(){
- inputTextureHandles[0] = OpenGLUtils.loadTexture(getContext(), "filter/toastermetal.png");
- inputTextureHandles[1] = OpenGLUtils.loadTexture(getContext(), "filter/toastersoftlight.png");
- inputTextureHandles[2] = OpenGLUtils.loadTexture(getContext(), "filter/toastercurves.png");
- inputTextureHandles[3] = OpenGLUtils.loadTexture(getContext(), "filter/toasteroverlaymapwarm.png");
- inputTextureHandles[4] = OpenGLUtils.loadTexture(getContext(), "filter/toastercolorshift.png");
- }
- });
- }
-}
diff --git a/Live/src/main/java/com/seu/magicfilter/advanced/MagicValenciaFilter.java b/Live/src/main/java/com/seu/magicfilter/advanced/MagicValenciaFilter.java
deleted file mode 100644
index de55a740..00000000
--- a/Live/src/main/java/com/seu/magicfilter/advanced/MagicValenciaFilter.java
+++ /dev/null
@@ -1,68 +0,0 @@
-package com.seu.magicfilter.advanced;
-
-import android.opengl.GLES20;
-
-import com.frank.live.R;
-import com.seu.magicfilter.base.gpuimage.GPUImageFilter;
-import com.seu.magicfilter.utils.MagicFilterType;
-import com.seu.magicfilter.utils.OpenGLUtils;
-
-public class MagicValenciaFilter extends GPUImageFilter{
- private int[] inputTextureHandles = {-1,-1};
- private int[] inputTextureUniformLocations = {-1,-1};
- private int mGLStrengthLocation;
-
- public MagicValenciaFilter(){
- super(MagicFilterType.VALENCIA, R.raw.valencia);
- }
-
- @Override
- protected void onDrawArraysAfter() {
- for(int i = 0; i < inputTextureHandles.length
- && inputTextureHandles[i] != OpenGLUtils.NO_TEXTURE; i++){
- GLES20.glActiveTexture(GLES20.GL_TEXTURE0 + (i+3));
- GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, 0);
- GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
- }
- }
-
- @Override
- protected void onDrawArraysPre() {
- for(int i = 0; i < inputTextureHandles.length
- && inputTextureHandles[i] != OpenGLUtils.NO_TEXTURE; i++){
- GLES20.glActiveTexture(GLES20.GL_TEXTURE0 + (i+3) );
- GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, inputTextureHandles[i]);
- GLES20.glUniform1i(inputTextureUniformLocations[i], (i+3));
- }
- }
-
- @Override
- public void onInit() {
- super.onInit();
- for(int i = 0; i < inputTextureUniformLocations.length; i++) {
- inputTextureUniformLocations[i] = GLES20.glGetUniformLocation(getProgram(), "inputImageTexture" + (2 + i));
- }
- mGLStrengthLocation = GLES20.glGetUniformLocation(getProgram(), "strength");
- }
-
- @Override
- public void onDestroy() {
- super.onDestroy();
- GLES20.glDeleteTextures(inputTextureHandles.length, inputTextureHandles, 0);
- for(int i = 0; i < inputTextureHandles.length; i++) {
- inputTextureHandles[i] = -1;
- }
- }
-
- @Override
- public void onInitialized() {
- super.onInitialized();
- setFloat(mGLStrengthLocation, 1.0f);
- runOnDraw(new Runnable(){
- public void run(){
- inputTextureHandles[0] = OpenGLUtils.loadTexture(getContext(), "filter/valenciamap.png");
- inputTextureHandles[1] = OpenGLUtils.loadTexture(getContext(), "filter/valenciagradientmap.png");
- }
- });
- }
-}
diff --git a/Live/src/main/java/com/seu/magicfilter/advanced/MagicWaldenFilter.java b/Live/src/main/java/com/seu/magicfilter/advanced/MagicWaldenFilter.java
deleted file mode 100644
index f4163d5d..00000000
--- a/Live/src/main/java/com/seu/magicfilter/advanced/MagicWaldenFilter.java
+++ /dev/null
@@ -1,66 +0,0 @@
-package com.seu.magicfilter.advanced;
-
-import android.opengl.GLES20;
-
-import com.frank.live.R;
-import com.seu.magicfilter.base.gpuimage.GPUImageFilter;
-import com.seu.magicfilter.utils.MagicFilterType;
-import com.seu.magicfilter.utils.OpenGLUtils;
-
-public class MagicWaldenFilter extends GPUImageFilter {
-
- private int[] inputTextureHandles = {-1,-1};
- private int[] inputTextureUniformLocations = {-1,-1};
- private int mGLStrengthLocation;
-
- public MagicWaldenFilter(){
- super(MagicFilterType.WALDEN, R.raw.walden);
- }
-
- @Override
- protected void onDestroy() {
- super.onDestroy();
- GLES20.glDeleteTextures(inputTextureHandles.length, inputTextureHandles, 0);
- for(int i = 0; i < inputTextureHandles.length; i++)
- inputTextureHandles[i] = -1;
- }
-
- @Override
- protected void onDrawArraysAfter(){
- for(int i = 0; i < inputTextureHandles.length
- && inputTextureHandles[i] != OpenGLUtils.NO_TEXTURE; i++){
- GLES20.glActiveTexture(GLES20.GL_TEXTURE0 + (i+3));
- GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, 0);
- GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
- }
- }
-
- @Override
- protected void onDrawArraysPre(){
- for(int i = 0; i < inputTextureHandles.length && inputTextureHandles[i] != OpenGLUtils.NO_TEXTURE; i++){
- GLES20.glActiveTexture(GLES20.GL_TEXTURE0 + (i+3) );
- GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, inputTextureHandles[i]);
- GLES20.glUniform1i(inputTextureUniformLocations[i], (i+3));
- }
- }
-
- @Override
- public void onInit(){
- super.onInit();
- for(int i = 0; i < inputTextureUniformLocations.length; i++)
- inputTextureUniformLocations[i] = GLES20.glGetUniformLocation(getProgram(), "inputImageTexture"+(2+i));
- mGLStrengthLocation = GLES20.glGetUniformLocation(getProgram(), "strength");
- }
-
- @Override
- public void onInitialized(){
- super.onInitialized();
- setFloat(mGLStrengthLocation, 1.0f);
- runOnDraw(new Runnable(){
- public void run(){
- inputTextureHandles[0] = OpenGLUtils.loadTexture(getContext(), "filter/walden_map.png");
- inputTextureHandles[1] = OpenGLUtils.loadTexture(getContext(), "filter/vignette_map.png");
- }
- });
- }
-}
diff --git a/Live/src/main/java/com/seu/magicfilter/advanced/MagicWarmFilter.java b/Live/src/main/java/com/seu/magicfilter/advanced/MagicWarmFilter.java
deleted file mode 100644
index 9a9544c5..00000000
--- a/Live/src/main/java/com/seu/magicfilter/advanced/MagicWarmFilter.java
+++ /dev/null
@@ -1,118 +0,0 @@
-package com.seu.magicfilter.advanced;
-
-import android.opengl.GLES20;
-
-import com.frank.live.R;
-import com.seu.magicfilter.base.gpuimage.GPUImageFilter;
-import com.seu.magicfilter.utils.MagicFilterType;
-
-import java.nio.ByteBuffer;
-
-public class MagicWarmFilter extends GPUImageFilter {
- private int[] mToneCurveTexture = {-1};
- private int mToneCurveTextureUniformLocation;
- private int mMaskGrey1TextureId = -1;
- private int mMaskGrey1UniformLocation;
- private int mMaskGrey2TextureId = -1;
- private int mMaskGrey2UniformLocation;
-
- public MagicWarmFilter(){
- super(MagicFilterType.WARM, R.raw.warm);
- }
-
- @Override
- public void onDestroy(){
- super.onDestroy();
- GLES20.glDeleteTextures(3, new int[]{mToneCurveTexture[0], mMaskGrey1TextureId, mMaskGrey2TextureId}, 0);
- mToneCurveTexture[0] = -1;
- mMaskGrey1TextureId = -1;
- mMaskGrey2TextureId = -1;
- }
-
- @Override
- protected void onDrawArraysAfter(){
- if (mToneCurveTexture[0] != -1){
- GLES20.glActiveTexture(GLES20.GL_TEXTURE3);
- GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, 0);
- GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
- }
- if (mMaskGrey1TextureId != -1){
- GLES20.glActiveTexture(GLES20.GL_TEXTURE4);
- GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, 0);
- GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
- }
- if (mMaskGrey2TextureId != -1){
- GLES20.glActiveTexture(GLES20.GL_TEXTURE5);
- GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, 0);
- GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
- }
- }
-
- @Override
- protected void onDrawArraysPre(){
- if (mToneCurveTexture[0] != -1){
- GLES20.glActiveTexture(GLES20.GL_TEXTURE3);
- GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mToneCurveTexture[0]);
- GLES20.glUniform1i(mToneCurveTextureUniformLocation, 3);
- }
- if (mMaskGrey1TextureId != -1){
- GLES20.glActiveTexture(GLES20.GL_TEXTURE4);
- GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mMaskGrey1TextureId);
- GLES20.glUniform1i(mMaskGrey1UniformLocation, 4);
- }
- if (mMaskGrey2TextureId != -1){
- GLES20.glActiveTexture(GLES20.GL_TEXTURE5);
- GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mMaskGrey2TextureId);
- GLES20.glUniform1i(mMaskGrey2UniformLocation, 5);
- }
- }
-
- @Override
- protected void onInit(){
- super.onInit();
- mToneCurveTextureUniformLocation = GLES20.glGetUniformLocation(getProgram(), "curve");
- mMaskGrey1UniformLocation = GLES20.glGetUniformLocation(getProgram(), "layerImage");
- mMaskGrey2UniformLocation = GLES20.glGetUniformLocation(getProgram(), "greyFrame");
- }
-
- @Override
- protected void onInitialized(){
- super.onInitialized();
- runOnDraw(new Runnable(){
- public void run(){
- GLES20.glGenTextures(1, mToneCurveTexture, 0);
- GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mToneCurveTexture[0]);
- GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D,
- GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR);
- GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D,
- GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_LINEAR);
- GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D,
- GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_CLAMP_TO_EDGE);
- GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D,
- GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_CLAMP_TO_EDGE);
- byte[] arrayOfByte = new byte[2048];
- int[] arrayOfInt1 = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 6, 9, 12, 14, 17, 20, 23, 25, 28, 31, 33, 35, 38, 40, 42, 44, 46, 48, 50, 52, 53, 55, 57, 58, 60, 61, 63, 64, 65, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 80, 81, 82, 83, 83, 84, 85, 85, 86, 87, 87, 88, 88, 89, 90, 90, 91, 91, 92, 93, 93, 94, 94, 95, 96, 96, 97, 98, 99, 99, 100, 101, 102, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 114, 115, 116, 117, 119, 120, 121, 123, 124, 126, 127, 128, 130, 131, 133, 135, 136, 138, 139, 141, 143, 144, 146, 148, 149, 151, 153, 154, 156, 158, 159, 161, 163, 165, 166, 168, 170, 172, 173, 175, 177, 179, 180, 182, 184, 185, 187, 189, 190, 192, 194, 195, 197, 199, 200, 202, 203, 205, 207, 208, 210, 211, 213, 214, 215, 217, 218, 219, 221, 222, 223, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 238, 239, 240, 241, 241, 242, 243, 243, 244, 244, 245, 245, 246, 246, 247, 247, 248, 248, 249, 249, 249, 250, 250, 250, 251, 251, 251, 251, 252, 252, 252, 252, 253, 253, 253, 253, 253, 253, 254, 254, 254, 254, 254, 254, 254, 254, 255, 255, 255, 255, 255, 255 };
- int[] arrayOfInt2 = { 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 87, 88, 89, 90, 91, 92, 93, 94, 95, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 219, 220, 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 235, 236, 237, 238, 239, 240, 241, 242 };
- int[] arrayOfInt3 = { 9, 10, 11, 11, 12, 13, 14, 15, 16, 16, 17, 18, 19, 20, 21, 21, 22, 23, 24, 25, 26, 26, 27, 28, 29, 30, 31, 31, 32, 33, 34, 35, 36, 36, 37, 38, 39, 40, 40, 41, 42, 43, 44, 45, 45, 46, 47, 48, 49, 50, 50, 51, 52, 53, 54, 55, 55, 56, 57, 58, 59, 60, 60, 61, 62, 63, 64, 65, 66, 66, 67, 68, 69, 70, 71, 71, 72, 73, 74, 75, 76, 76, 77, 78, 79, 80, 81, 81, 82, 83, 84, 85, 86, 87, 87, 88, 89, 90, 91, 92, 93, 93, 94, 95, 96, 97, 98, 98, 99, 100, 101, 102, 103, 104, 104, 105, 106, 107, 108, 109, 110, 110, 111, 112, 113, 114, 115, 116, 116, 117, 118, 119, 120, 121, 122, 123, 123, 124, 125, 126, 127, 128, 129, 130, 130, 131, 132, 133, 134, 135, 136, 137, 137, 138, 139, 140, 141, 142, 143, 144, 144, 145, 146, 147, 148, 149, 150, 151, 152, 152, 153, 154, 155, 156, 157, 158, 159, 160, 160, 161, 162, 163, 164, 165, 166, 167, 168, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 215, 216, 217, 218, 219, 220, 221, 222, 223, 224, 225, 225, 226, 227, 228, 229, 230 };
- int[] arrayOfInt4 = { 0, 0, 1, 1, 2, 2, 3, 3, 4, 5, 5, 6, 6, 7, 7, 8, 9, 9, 10, 11, 12, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 28, 29, 30, 31, 33, 34, 35, 37, 38, 40, 41, 42, 44, 45, 47, 48, 50, 51, 53, 54, 56, 58, 59, 61, 62, 64, 65, 67, 69, 70, 72, 73, 75, 77, 78, 80, 82, 83, 85, 86, 88, 90, 91, 93, 94, 96, 98, 99, 101, 102, 104, 105, 107, 108, 110, 111, 113, 114, 116, 117, 119, 120, 122, 123, 124, 126, 127, 129, 130, 131, 133, 134, 136, 137, 138, 140, 141, 142, 144, 145, 146, 147, 149, 150, 151, 153, 154, 155, 156, 157, 159, 160, 161, 162, 163, 165, 166, 167, 168, 169, 170, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 203, 204, 205, 206, 207, 208, 208, 209, 210, 211, 212, 212, 213, 214, 215, 216, 216, 217, 218, 218, 219, 220, 221, 221, 222, 223, 223, 224, 225, 225, 226, 227, 227, 228, 228, 229, 230, 230, 231, 231, 232, 233, 233, 234, 234, 235, 235, 236, 236, 237, 238, 238, 239, 239, 240, 240, 241, 241, 242, 242, 243, 243, 244, 244, 245, 245, 246, 246, 247, 247, 248, 248, 249, 249, 249, 250, 250, 251, 251, 252, 252, 253, 253, 254, 254, 255, 255 };
- for (int i = 0; i < 256; i++){
- arrayOfByte[(i * 4)] = ((byte)arrayOfInt1[i]);
- arrayOfByte[(1 + i * 4)] = ((byte)arrayOfInt2[i]);
- arrayOfByte[(2 + i * 4)] = ((byte)arrayOfInt3[i]);
- arrayOfByte[(3 + i * 4)] = ((byte)arrayOfInt4[i]);
- }
- int[] arrayOfInt5 = { 0, 1, 1, 2, 3, 4, 4, 5, 6, 6, 7, 8, 8, 9, 10, 11, 11, 11, 12, 13, 13, 14, 15, 15, 16, 17, 18, 18, 19, 20, 21, 21, 22, 23, 24, 24, 25, 26, 27, 28, 28, 28, 29, 30, 31, 31, 32, 33, 34, 35, 36, 36, 37, 38, 39, 39, 40, 41, 41, 42, 43, 44, 45, 46, 47, 47, 48, 49, 50, 51, 52, 53, 54, 55, 55, 56, 57, 58, 59, 60, 61, 62, 63, 63, 64, 65, 66, 68, 69, 70, 71, 71, 72, 73, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 86, 87, 88, 89, 90, 92, 93, 94, 95, 95, 97, 98, 99, 100, 102, 103, 104, 105, 106, 108, 109, 110, 111, 112, 114, 115, 116, 117, 118, 119, 122, 123, 124, 125, 126, 127, 129, 130, 131, 132, 133, 134, 135, 137, 138, 139, 141, 142, 143, 144, 145, 146, 148, 149, 150, 151, 152, 154, 155, 156, 157, 158, 159, 161, 162, 164, 165, 166, 167, 168, 169, 170, 171, 173, 174, 175, 176, 177, 178, 179, 180, 183, 184, 185, 186, 187, 188, 190, 191, 192, 193, 194, 195, 196, 198, 199, 200, 201, 202, 203, 205, 206, 207, 208, 209, 210, 212, 213, 214, 215, 216, 217, 219, 220, 221, 222, 223, 224, 226, 227, 228, 229, 230, 231, 233, 234, 235, 236, 237, 239, 240, 241, 242, 243, 243, 244, 246, 247, 248, 249, 250, 251, 253, 254, 255, 255, 255, 255, 255, 255, 255, 255 };
- int[] arrayOfInt6 = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 11, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 28, 29, 30, 31, 32, 33, 34, 35, 37, 38, 39, 39, 40, 41, 42, 43, 44, 45, 46, 47, 47, 48, 49, 50, 51, 52, 53, 54, 55, 55, 56, 57, 58, 60, 61, 62, 63, 63, 64, 65, 66, 67, 68, 69, 70, 71, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 80, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 133, 134, 135, 136, 137, 138, 139, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 154, 155, 156, 157, 158, 159, 161, 162, 164, 165, 166, 167, 168, 169, 170, 171, 173, 174, 175, 176, 177, 178, 179, 180, 182, 183, 184, 185, 186, 187, 190, 191, 192, 193, 194, 195, 196, 198, 199, 200, 201, 202, 203, 205, 206, 207, 208, 209, 210, 212, 213, 214, 215, 216, 217, 220, 221, 222, 223, 224, 226, 227, 228, 229, 230, 231, 233, 234, 235, 236, 237, 239, 240, 241, 242, 243, 244, 246, 247, 249, 250, 251, 253, 254, 255, 255, 255, 255, 255, 255, 255, 255 };
- int[] arrayOfInt7 = { 45, 45, 46, 46, 47, 47, 47, 47, 48, 48, 49, 49, 50, 50, 50, 51, 51, 52, 52, 53, 53, 54, 54, 55, 55, 55, 55, 56, 56, 57, 57, 58, 58, 59, 59, 60, 60, 61, 61, 62, 62, 63, 63, 63, 63, 64, 64, 65, 65, 66, 66, 67, 67, 68, 69, 69, 70, 70, 71, 71, 71, 72, 72, 73, 73, 74, 75, 75, 76, 76, 77, 78, 78, 79, 79, 80, 80, 80, 81, 82, 82, 83, 84, 84, 85, 86, 87, 87, 88, 89, 89, 90, 91, 92, 92, 93, 94, 95, 95, 95, 96, 97, 98, 98, 99, 100, 101, 102, 103, 103, 104, 105, 106, 107, 108, 109, 110, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 135, 136, 137, 138, 139, 141, 142, 143, 144, 146, 147, 148, 149, 150, 151, 152, 154, 156, 157, 158, 159, 160, 161, 162, 165, 166, 167, 168, 169, 170, 171, 173, 175, 176, 177, 178, 179, 180, 182, 183, 184, 186, 187, 188, 190, 191, 192, 193, 194, 195, 196, 198, 199, 200, 201, 202, 203, 205, 206, 207, 208, 209, 210, 212, 213, 214, 215, 216, 217, 217, 219, 220, 221, 222, 223, 224, 226, 227, 227, 228, 229, 230, 231, 233, 234, 235, 235, 236, 237, 239, 240, 241, 241, 242, 243, 244, 246, 246, 247, 248, 249, 250, 251, 251, 253, 254, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 };
- int[] arrayOfInt8 = { 0, 0, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 5, 5, 5, 6, 6, 6, 7, 7, 8, 8, 8, 9, 9, 10, 10, 10, 11, 11, 11, 12, 12, 13, 13, 13, 14, 14, 14, 15, 15, 16, 16, 16, 17, 17, 17, 18, 18, 18, 19, 19, 20, 20, 20, 21, 21, 21, 22, 22, 23, 23, 23, 24, 24, 24, 25, 25, 25, 25, 26, 26, 27, 27, 28, 28, 28, 28, 29, 29, 30, 29, 31, 31, 31, 31, 32, 32, 33, 33, 34, 34, 34, 34, 35, 35, 36, 36, 37, 37, 37, 38, 38, 39, 39, 39, 40, 40, 40, 41, 42, 42, 43, 43, 44, 44, 45, 45, 45, 46, 47, 47, 48, 48, 49, 50, 51, 51, 52, 52, 53, 53, 54, 55, 55, 56, 57, 57, 58, 59, 60, 60, 61, 62, 63, 63, 64, 65, 66, 67, 68, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 88, 89, 90, 91, 93, 94, 95, 96, 97, 98, 100, 101, 103, 104, 105, 107, 108, 110, 111, 113, 115, 116, 118, 119, 120, 122, 123, 125, 127, 128, 130, 132, 134, 135, 137, 139, 141, 143, 144, 146, 148, 150, 152, 154, 156, 158, 160, 163, 165, 167, 169, 171, 173, 175, 178, 180, 182, 185, 187, 189, 192, 194, 197, 199, 201, 204, 206, 209, 211, 214, 216, 219, 221, 224, 226, 229, 232, 234, 236, 239, 241, 245, 247, 250, 252, 255 };
- for (int j = 0; j < 256; j++){
- arrayOfByte[(1024 + j * 4)] = ((byte)arrayOfInt5[j]);
- arrayOfByte[(1 + (1024 + j * 4))] = ((byte)arrayOfInt6[j]);
- arrayOfByte[(2 + (1024 + j * 4))] = ((byte)arrayOfInt7[j]);
- arrayOfByte[(3 + (1024 + j * 4))] = ((byte)arrayOfInt8[j]);
- }
- GLES20.glTexImage2D(GLES20.GL_TEXTURE_2D, 0, GLES20.GL_RGBA, 256, 2, 0, GLES20.GL_RGBA, GLES20.GL_UNSIGNED_BYTE, ByteBuffer.wrap(arrayOfByte));
- }
- });
- }
-}
diff --git a/Live/src/main/java/com/seu/magicfilter/advanced/MagicWhiteCatFilter.java b/Live/src/main/java/com/seu/magicfilter/advanced/MagicWhiteCatFilter.java
deleted file mode 100644
index 90c46981..00000000
--- a/Live/src/main/java/com/seu/magicfilter/advanced/MagicWhiteCatFilter.java
+++ /dev/null
@@ -1,88 +0,0 @@
-package com.seu.magicfilter.advanced;
-
-import android.opengl.GLES20;
-
-import com.frank.live.R;
-import com.seu.magicfilter.base.gpuimage.GPUImageFilter;
-import com.seu.magicfilter.utils.MagicFilterType;
-
-import java.nio.ByteBuffer;
-
-public class MagicWhiteCatFilter extends GPUImageFilter{
-
- private int[] mToneCurveTexture = {-1};
- private int mToneCurveTextureUniformLocation;
-
- public MagicWhiteCatFilter() {
- super(MagicFilterType.WHITECAT, R.raw.whitecat);
- }
-
- @Override
- public void onDestroy() {
- super.onDestroy();
- GLES20.glDeleteTextures(1, mToneCurveTexture, 0);
- mToneCurveTexture[0] = -1;
- }
-
- @Override
- protected void onDrawArraysAfter() {
- if (mToneCurveTexture[0] != -1){
- GLES20.glActiveTexture(GLES20.GL_TEXTURE3);
- GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, 0);
- GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
- }
- }
-
- @Override
- protected void onDrawArraysPre() {
- if (mToneCurveTexture[0] != -1){
- GLES20.glActiveTexture(GLES20.GL_TEXTURE3);
- GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mToneCurveTexture[0]);
- GLES20.glUniform1i(mToneCurveTextureUniformLocation, 3);
- }
- }
-
- @Override
- public void onInit() {
- super.onInit();
- mToneCurveTextureUniformLocation = GLES20.glGetUniformLocation(getProgram(), "curve");
- }
-
- @Override
- public void onInitialized() {
- super.onInitialized();
- runOnDraw(new Runnable(){
- public void run(){
- GLES20.glGenTextures(1, mToneCurveTexture, 0);
- GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mToneCurveTexture[0]);
- GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D,
- GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR);
- GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D,
- GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_LINEAR);
- GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D,
- GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_CLAMP_TO_EDGE);
- GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D,
- GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_CLAMP_TO_EDGE);
- byte[] arrayOfByte = new byte[2048];
- int[] arrayOfInt1 = { 0, 0, 0, 0, 0, 0, 0, 1, 2, 4, 5, 6, 7, 8, 10, 11, 12, 13, 14, 16, 17, 18, 19, 20, 22, 23, 24, 25, 26, 28, 29, 30, 31, 32, 33, 35, 36, 37, 38, 39, 41, 42, 43, 44, 45, 46, 48, 49, 50, 51, 52, 54, 55, 56, 57, 58, 59, 61, 62, 63, 64, 65, 66, 67, 69, 70, 71, 72, 73, 74, 75, 77, 78, 79, 80, 81, 82, 83, 85, 86, 87, 88, 89, 90, 91, 92, 93, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 236, 237, 238, 239, 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 249, 250, 251, 252, 253, 254, 255, 255, 255, 255, 255, 255 };
- int[] arrayOfInt2 = { 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 4, 4, 5, 6, 7, 8, 10, 11, 12, 12, 13, 14, 16, 17, 18, 19, 19, 20, 22, 23, 24, 25, 26, 26, 28, 29, 30, 31, 32, 33, 35, 35, 36, 37, 38, 39, 41, 42, 42, 43, 44, 45, 46, 48, 49, 50, 50, 51, 52, 54, 55, 56, 57, 58, 58, 59, 61, 62, 63, 64, 65, 66, 66, 67, 69, 70, 71, 72, 73, 74, 75, 75, 77, 78, 79, 80, 81, 82, 83, 85, 85, 86, 87, 88, 89, 90, 91, 92, 93, 93, 95, 96, 97, 98, 99, 100, 101, 102, 103, 103, 104, 105, 107, 108, 109, 110, 111, 112, 113, 114, 114, 115, 116, 117, 118, 119, 120, 121, 123, 124, 125, 126, 127, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 182, 183, 184, 185, 186, 187, 188, 189, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 217, 218, 219, 220, 221, 222, 223, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 236, 237, 238, 239, 240, 240 };
- for (int i = 0; i < 256; i++){
- arrayOfByte[(i * 4)] = ((byte)arrayOfInt1[i]);
- arrayOfByte[(1 + i * 4)] = ((byte)arrayOfInt1[i]);
- arrayOfByte[(2 + i * 4)] = ((byte)arrayOfInt2[i]);
- arrayOfByte[(3 + i * 4)] = -1;
- }
- int[] arrayOfInt3 = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 6, 9, 14, 17, 19, 22, 25, 27, 30, 34, 36, 39, 41, 43, 45, 49, 51, 52, 54, 55, 57, 58, 61, 63, 64, 65, 67, 68, 69, 72, 73, 75, 76, 77, 78, 81, 82, 83, 84, 86, 87, 88, 90, 91, 93, 94, 95, 96, 97, 99, 100, 101, 102, 103, 105, 106, 108, 109, 110, 111, 112, 113, 115, 116, 117, 118, 119, 120, 121, 123, 124, 125, 126, 126, 127, 128, 130, 131, 132, 133, 134, 135, 136, 138, 138, 139, 140, 141, 142, 144, 145, 146, 146, 147, 148, 149, 151, 152, 153, 153, 154, 155, 156, 158, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 168, 170, 171, 172, 172, 173, 174, 175, 176, 177, 178, 179, 180, 180, 181, 183, 183, 184, 185, 186, 186, 188, 189, 190, 190, 191, 192, 193, 194, 195, 196, 196, 197, 198, 199, 200, 201, 201, 202, 203, 204, 204, 206, 207, 207, 208, 209, 209, 211, 212, 212, 213, 214, 214, 215, 217, 217, 218, 219, 219, 220, 221, 222, 223, 224, 224, 225, 226, 227, 228, 228, 229, 230, 230, 231, 233, 233, 234, 235, 235, 236, 237, 238, 239, 239, 240, 241, 241, 242, 243, 244, 245, 245, 246, 247, 248, 249, 249, 250, 250, 251, 252, 253, 254, 254, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 };
- int[] arrayOfInt4 = { 0, 2, 4, 6, 8, 11, 13, 15, 17, 19, 21, 23, 25, 27, 29, 31, 32, 34, 36, 38, 40, 42, 44, 46, 47, 49, 51, 53, 54, 56, 58, 60, 61, 63, 65, 66, 68, 70, 71, 73, 74, 76, 77, 79, 80, 82, 83, 85, 86, 88, 89, 91, 92, 93, 95, 96, 98, 99, 100, 101, 103, 104, 105, 107, 108, 109, 110, 111, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 124, 125, 126, 127, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 198, 199, 200, 201, 202, 203, 204, 205, 206, 206, 207, 208, 209, 210, 211, 212, 212, 213, 214, 215, 216, 216, 217, 218, 219, 219, 220, 221, 222, 222, 223, 224, 224, 225, 226, 226, 227, 228, 228, 229, 230, 230, 231, 232, 232, 233, 233, 234, 235, 235, 236, 236, 237, 237, 238, 238, 239, 239, 240, 240, 241, 241, 242, 242, 243, 243, 244, 244, 245, 245, 245, 246, 246, 247, 247, 247, 248, 248, 248, 249, 249, 249, 250, 250, 250, 251, 251, 251, 252, 252, 252, 252, 253, 253, 253, 253, 254, 254, 254, 254, 254, 255, 255, 255 };
- int[] arrayOfInt5 = { 0, 0, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 5, 5, 5, 6, 6, 6, 7, 7, 8, 8, 8, 9, 9, 10, 10, 10, 11, 11, 11, 12, 12, 13, 13, 13, 14, 14, 14, 15, 15, 16, 16, 16, 17, 17, 17, 18, 18, 18, 19, 19, 20, 20, 20, 21, 21, 21, 22, 22, 23, 23, 23, 24, 24, 24, 25, 25, 25, 25, 26, 26, 27, 27, 28, 28, 28, 28, 29, 29, 30, 29, 31, 31, 31, 31, 32, 32, 33, 33, 34, 34, 34, 34, 35, 35, 36, 36, 37, 37, 37, 38, 38, 39, 39, 39, 40, 40, 40, 41, 42, 42, 43, 43, 44, 44, 45, 45, 45, 46, 47, 47, 48, 48, 49, 50, 51, 51, 52, 52, 53, 53, 54, 55, 55, 56, 57, 57, 58, 59, 60, 60, 61, 62, 63, 63, 64, 65, 66, 67, 68, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 88, 89, 90, 91, 93, 94, 95, 96, 97, 98, 100, 101, 103, 104, 105, 107, 108, 110, 111, 113, 115, 116, 118, 119, 120, 122, 123, 125, 127, 128, 130, 132, 134, 135, 137, 139, 141, 143, 144, 146, 148, 150, 152, 154, 156, 158, 160, 163, 165, 167, 169, 171, 173, 175, 178, 180, 182, 185, 187, 189, 192, 194, 197, 199, 201, 204, 206, 209, 211, 214, 216, 219, 221, 224, 226, 229, 232, 234, 236, 239, 241, 245, 247, 250, 252, 255 };
- for (int j = 0; j < 256; j++){
- arrayOfByte[(1024 + j * 4)] = ((byte)arrayOfInt4[j]);
- arrayOfByte[(1 + (1024 + j * 4))] = ((byte)arrayOfInt3[j]);
- arrayOfByte[(2 + (1024 + j * 4))] = ((byte)arrayOfInt5[j]);
- arrayOfByte[(3 + (1024 + j * 4))] = -1;
- }
- GLES20.glTexImage2D(GLES20.GL_TEXTURE_2D, 0, GLES20.GL_RGBA, 256, 2, 0, GLES20.GL_RGBA, GLES20.GL_UNSIGNED_BYTE, ByteBuffer.wrap(arrayOfByte));
- }
- });
- }
-}
diff --git a/Live/src/main/java/com/seu/magicfilter/advanced/MagicXproIIFilter.java b/Live/src/main/java/com/seu/magicfilter/advanced/MagicXproIIFilter.java
deleted file mode 100644
index ef8298ff..00000000
--- a/Live/src/main/java/com/seu/magicfilter/advanced/MagicXproIIFilter.java
+++ /dev/null
@@ -1,66 +0,0 @@
-package com.seu.magicfilter.advanced;
-
-import android.opengl.GLES20;
-
-import com.frank.live.R;
-import com.seu.magicfilter.base.gpuimage.GPUImageFilter;
-import com.seu.magicfilter.utils.MagicFilterType;
-import com.seu.magicfilter.utils.OpenGLUtils;
-
-public class MagicXproIIFilter extends GPUImageFilter{
- private int[] inputTextureHandles = {-1,-1};
- private int[] inputTextureUniformLocations = {-1,-1};
- private int mGLStrengthLocation;
-
- public MagicXproIIFilter(){
- super(MagicFilterType.XPROII, R.raw.xproii_filter_shader);
- }
-
- @Override
- public void onDestroy() {
- super.onDestroy();
- GLES20.glDeleteTextures(inputTextureHandles.length, inputTextureHandles, 0);
- for(int i = 0; i < inputTextureHandles.length; i++)
- inputTextureHandles[i] = -1;
- }
-
- @Override
- protected void onDrawArraysAfter(){
- for(int i = 0; i < inputTextureHandles.length
- && inputTextureHandles[i] != OpenGLUtils.NO_TEXTURE; i++){
- GLES20.glActiveTexture(GLES20.GL_TEXTURE0 + (i+3));
- GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, 0);
- GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
- }
- }
-
- @Override
- protected void onDrawArraysPre(){
- for(int i = 0; i < inputTextureHandles.length
- && inputTextureHandles[i] != OpenGLUtils.NO_TEXTURE; i++){
- GLES20.glActiveTexture(GLES20.GL_TEXTURE0 + (i+3) );
- GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, inputTextureHandles[i]);
- GLES20.glUniform1i(inputTextureUniformLocations[i], (i + 3));
- }
- }
-
- @Override
- public void onInit(){
- super.onInit();
- for(int i = 0; i < inputTextureUniformLocations.length; i++)
- inputTextureUniformLocations[i] = GLES20.glGetUniformLocation(getProgram(), "inputImageTexture"+(2+i));
- mGLStrengthLocation = GLES20.glGetUniformLocation(getProgram(), "strength");
- }
-
- @Override
- public void onInitialized(){
- super.onInitialized();
- setFloat(mGLStrengthLocation, 1.0f);
- runOnDraw(new Runnable(){
- public void run(){
- inputTextureHandles[0] = OpenGLUtils.loadTexture(getContext(), "filter/xpromap.png");
- inputTextureHandles[1] = OpenGLUtils.loadTexture(getContext(), "filter/vignettemap_new.png");
- }
- });
- }
-}
diff --git a/Live/src/main/java/com/seu/magicfilter/base/MagicBaseGroupFilter.java b/Live/src/main/java/com/seu/magicfilter/base/MagicBaseGroupFilter.java
deleted file mode 100644
index e283052b..00000000
--- a/Live/src/main/java/com/seu/magicfilter/base/MagicBaseGroupFilter.java
+++ /dev/null
@@ -1,144 +0,0 @@
-package com.seu.magicfilter.base;
-
-
-import android.content.Context;
-import android.opengl.GLES20;
-
-import com.seu.magicfilter.base.gpuimage.GPUImageFilter;
-import com.seu.magicfilter.utils.OpenGLUtils;
-
-import java.nio.FloatBuffer;
-import java.util.List;
-
-
-public class MagicBaseGroupFilter extends GPUImageFilter {
- private static int[] frameBuffers = null;
- private static int[] frameBufferTextures = null;
- private int frameWidth = -1;
- private int frameHeight = -1;
- protected List filters;
-
- public MagicBaseGroupFilter(List filters) {
- this.filters = filters;
- }
-
- @Override
- public void onDestroy() {
- for (GPUImageFilter filter : filters) {
- filter.destroy();
- }
- destroyFramebuffers();
- }
-
- @Override
- public void init(Context context) {
- for (GPUImageFilter filter : filters) {
- filter.init(context);
- }
- }
-
- @Override
- public void onInputSizeChanged(final int width, final int height) {
- super.onInputSizeChanged(width, height);
- int size = filters.size();
- for (int i = 0; i < size; i++) {
- filters.get(i).onInputSizeChanged(width, height);
- }
- if (frameBuffers != null && (frameWidth != width || frameHeight != height || frameBuffers.length != size - 1)) {
- destroyFramebuffers();
- frameWidth = width;
- frameHeight = height;
- }
- if (frameBuffers == null) {
- frameBuffers = new int[size - 1];
- frameBufferTextures = new int[size - 1];
-
- for (int i = 0; i < size - 1; i++) {
- GLES20.glGenFramebuffers(1, frameBuffers, i);
-
- GLES20.glGenTextures(1, frameBufferTextures, i);
- GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, frameBufferTextures[i]);
- GLES20.glTexImage2D(GLES20.GL_TEXTURE_2D, 0, GLES20.GL_RGBA, width, height, 0,
- GLES20.GL_RGBA, GLES20.GL_UNSIGNED_BYTE, null);
- GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D,
- GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR);
- GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D,
- GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_LINEAR);
- GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D,
- GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_CLAMP_TO_EDGE);
- GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D,
- GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_CLAMP_TO_EDGE);
-
- GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, frameBuffers[i]);
- GLES20.glFramebufferTexture2D(GLES20.GL_FRAMEBUFFER, GLES20.GL_COLOR_ATTACHMENT0,
- GLES20.GL_TEXTURE_2D, frameBufferTextures[i], 0);
-
- GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, 0);
- GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, 0);
- }
- }
- }
-
- @Override
- public int onDrawFrame(final int textureId, final FloatBuffer cubeBuffer,
- final FloatBuffer textureBuffer) {
- if (frameBuffers == null || frameBufferTextures == null) {
- return OpenGLUtils.NOT_INIT;
- }
- int size = filters.size();
- int previousTexture = textureId;
- for (int i = 0; i < size; i++) {
- GPUImageFilter filter = filters.get(i);
- boolean isNotLast = i < size - 1;
- if (isNotLast) {
- GLES20.glViewport(0, 0, mInputWidth, mInputHeight);
- GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, frameBuffers[i]);
- GLES20.glClearColor(0, 0, 0, 0);
- filter.onDrawFrame(previousTexture, mGLCubeBuffer, mGLTextureBuffer);
- GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, 0);
- previousTexture = frameBufferTextures[i];
- } else {
- GLES20.glViewport(0, 0, mOutputWidth, mOutputHeight);
- filter.onDrawFrame(previousTexture, cubeBuffer, textureBuffer);
- }
- }
- return OpenGLUtils.ON_DRAWN;
- }
-
- public int onDrawFrame(int textureId) {
- if (frameBuffers == null || frameBufferTextures == null) {
- return OpenGLUtils.NOT_INIT;
- }
- int size = filters.size();
- int previousTexture = textureId;
- for (int i = 0; i < size; i++) {
- GPUImageFilter filter = filters.get(i);
- boolean isNotLast = i < size - 1;
- if (isNotLast) {
- GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, frameBuffers[i]);
- GLES20.glClearColor(0, 0, 0, 0);
- filter.onDrawFrame(previousTexture, mGLCubeBuffer, mGLTextureBuffer);
- GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, 0);
- previousTexture = frameBufferTextures[i];
- } else {
- filter.onDrawFrame(previousTexture, mGLCubeBuffer, mGLTextureBuffer);
- }
- }
- return OpenGLUtils.ON_DRAWN;
- }
-
- private void destroyFramebuffers() {
- if (frameBufferTextures != null) {
- GLES20.glDeleteTextures(frameBufferTextures.length, frameBufferTextures, 0);
- frameBufferTextures = null;
- }
- if (frameBuffers != null) {
- GLES20.glDeleteFramebuffers(frameBuffers.length, frameBuffers, 0);
- frameBuffers = null;
- }
- }
-
- public int getSize() {
- return filters.size();
- }
-}
diff --git a/Live/src/main/java/com/seu/magicfilter/base/MagicLookupFilter.java b/Live/src/main/java/com/seu/magicfilter/base/MagicLookupFilter.java
deleted file mode 100644
index 6c8253fb..00000000
--- a/Live/src/main/java/com/seu/magicfilter/base/MagicLookupFilter.java
+++ /dev/null
@@ -1,58 +0,0 @@
-package com.seu.magicfilter.base;
-
-import android.opengl.GLES20;
-
-import com.frank.live.R;
-import com.seu.magicfilter.base.gpuimage.GPUImageFilter;
-import com.seu.magicfilter.utils.MagicFilterType;
-import com.seu.magicfilter.utils.OpenGLUtils;
-
-public class MagicLookupFilter extends GPUImageFilter {
-
- protected String table;
-
- public MagicLookupFilter(String table) {
- super(MagicFilterType.LOCKUP, R.raw.lookup);
- this.table = table;
- }
-
- private int mLookupTextureUniform;
- private int mLookupSourceTexture = OpenGLUtils.NO_TEXTURE;
-
- protected void onInit() {
- super.onInit();
- mLookupTextureUniform = GLES20.glGetUniformLocation(getProgram(), "inputImageTexture2");
- }
-
- protected void onInitialized() {
- super.onInitialized();
- runOnDraw(new Runnable() {
- public void run() {
- mLookupSourceTexture = OpenGLUtils.loadTexture(getContext(), table);
- }
- });
- }
-
- protected void onDestroy() {
- super.onDestroy();
- int[] texture = new int[]{mLookupSourceTexture};
- GLES20.glDeleteTextures(1, texture, 0);
- mLookupSourceTexture = -1;
- }
-
- protected void onDrawArraysAfter() {
- if (mLookupSourceTexture != -1) {
- GLES20.glActiveTexture(GLES20.GL_TEXTURE3);
- GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, 0);
- GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
- }
- }
-
- protected void onDrawArraysPre() {
- if (mLookupSourceTexture != -1) {
- GLES20.glActiveTexture(GLES20.GL_TEXTURE3);
- GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mLookupSourceTexture);
- GLES20.glUniform1i(mLookupTextureUniform, 3);
- }
- }
-}
diff --git a/Live/src/main/java/com/seu/magicfilter/base/gpuimage/GPUImageBrightnessFilter.java b/Live/src/main/java/com/seu/magicfilter/base/gpuimage/GPUImageBrightnessFilter.java
deleted file mode 100644
index bc118726..00000000
--- a/Live/src/main/java/com/seu/magicfilter/base/gpuimage/GPUImageBrightnessFilter.java
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * Copyright (C) 2012 CyberAgent
- *
- * 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.seu.magicfilter.base.gpuimage;
-
-import android.opengl.GLES20;
-
-import com.frank.live.R;
-import com.seu.magicfilter.utils.MagicFilterType;
-
-/**
- * brightness value ranges from -1.0 to 1.0, with 0.0 as the normal level
- */
-public class GPUImageBrightnessFilter extends GPUImageFilter {
-
- private int mBrightnessLocation;
- private float mBrightness;
-
- public GPUImageBrightnessFilter() {
- this(0.0f);
- }
-
- public GPUImageBrightnessFilter(final float brightness) {
- super(MagicFilterType.BRIGHTNESS, R.raw.brightness);
- mBrightness = brightness;
- }
-
- @Override
- public void onInit() {
- super.onInit();
- mBrightnessLocation = GLES20.glGetUniformLocation(getProgram(), "brightness");
- }
-
- @Override
- public void onInitialized() {
- super.onInitialized();
- setBrightness(mBrightness);
- }
-
- public void setBrightness(final float brightness) {
- mBrightness = brightness;
- setFloat(mBrightnessLocation, mBrightness);
- }
-}
diff --git a/Live/src/main/java/com/seu/magicfilter/base/gpuimage/GPUImageContrastFilter.java b/Live/src/main/java/com/seu/magicfilter/base/gpuimage/GPUImageContrastFilter.java
deleted file mode 100644
index dc0b2c57..00000000
--- a/Live/src/main/java/com/seu/magicfilter/base/gpuimage/GPUImageContrastFilter.java
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * Copyright (C) 2012 CyberAgent
- *
- * 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.seu.magicfilter.base.gpuimage;
-
-import android.opengl.GLES20;
-
-import com.frank.live.R;
-import com.seu.magicfilter.utils.MagicFilterType;
-
-
-/**
- * Changes the contrast of the image.
- *
- * contrast value ranges from 0.0 to 4.0, with 1.0 as the normal level
- */
-public class GPUImageContrastFilter extends GPUImageFilter {
-
- private int mContrastLocation;
- private float mContrast;
-
- public GPUImageContrastFilter() {
- this(1.0f);
- }
-
- public GPUImageContrastFilter(float contrast) {
- super(MagicFilterType.CONTRAST, R.raw.constrast);
- mContrast = contrast;
- }
-
- @Override
- public void onInit() {
- super.onInit();
- mContrastLocation = GLES20.glGetUniformLocation(getProgram(), "contrast");
- }
-
- @Override
- public void onInitialized() {
- super.onInitialized();
- setContrast(mContrast);
- }
-
- public void setContrast(final float contrast) {
- mContrast = contrast;
- setFloat(mContrastLocation, mContrast);
- }
-}
diff --git a/Live/src/main/java/com/seu/magicfilter/base/gpuimage/GPUImageExposureFilter.java b/Live/src/main/java/com/seu/magicfilter/base/gpuimage/GPUImageExposureFilter.java
deleted file mode 100644
index 16e9a348..00000000
--- a/Live/src/main/java/com/seu/magicfilter/base/gpuimage/GPUImageExposureFilter.java
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * Copyright (C) 2012 CyberAgent
- *
- * 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.seu.magicfilter.base.gpuimage;
-
-import android.opengl.GLES20;
-
-import com.frank.live.R;
-import com.seu.magicfilter.utils.MagicFilterType;
-
-/**
- * exposure: The adjusted exposure (-10.0 - 10.0, with 0.0 as the default)
- */
-public class GPUImageExposureFilter extends GPUImageFilter {
- public static final String EXPOSURE_FRAGMENT_SHADER = "" +
- " varying highp vec2 textureCoordinate;\n" +
- " \n" +
- " uniform sampler2D inputImageTexture;\n" +
- " uniform highp float exposure;\n" +
- " \n" +
- " void main()\n" +
- " {\n" +
- " highp vec4 textureColor = texture2D(inputImageTexture, textureCoordinate);\n" +
- " \n" +
- " gl_FragColor = vec4(textureColor.rgb * pow(2.0, exposure), textureColor.w);\n" +
- " } ";
-
- private int mExposureLocation;
- private float mExposure;
-
- public GPUImageExposureFilter() {
- this(0.0f);
- }
-
- public GPUImageExposureFilter(final float exposure) {
- super(MagicFilterType.EXPOSURE, R.raw.exposure);
- mExposure = exposure;
- }
-
- @Override
- public void onInit() {
- super.onInit();
- mExposureLocation = GLES20.glGetUniformLocation(getProgram(), "exposure");
- }
-
- @Override
- public void onInitialized() {
- super.onInitialized();
- setExposure(mExposure);
- }
-
- public void setExposure(final float exposure) {
- mExposure = exposure;
- setFloat(mExposureLocation, mExposure);
- }
-}
diff --git a/Live/src/main/java/com/seu/magicfilter/base/gpuimage/GPUImageFilter.java b/Live/src/main/java/com/seu/magicfilter/base/gpuimage/GPUImageFilter.java
deleted file mode 100644
index cbabbee6..00000000
--- a/Live/src/main/java/com/seu/magicfilter/base/gpuimage/GPUImageFilter.java
+++ /dev/null
@@ -1,404 +0,0 @@
-/*
- * Copyright (C) 2012 CyberAgent
- *
- * 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.seu.magicfilter.base.gpuimage;
-
-import android.content.Context;
-import android.graphics.PointF;
-import android.opengl.GLES11Ext;
-import android.opengl.GLES20;
-
-import com.frank.live.R;
-import com.seu.magicfilter.utils.MagicFilterType;
-import com.seu.magicfilter.utils.OpenGLUtils;
-import com.seu.magicfilter.utils.Rotation;
-import com.seu.magicfilter.utils.TextureRotationUtil;
-
-import java.nio.ByteBuffer;
-import java.nio.ByteOrder;
-import java.nio.FloatBuffer;
-import java.nio.IntBuffer;
-import java.util.LinkedList;
-
-public class GPUImageFilter {
-
- private boolean mIsInitialized;
- private Context mContext;
- private MagicFilterType mType = MagicFilterType.NONE;
- private final LinkedList mRunOnDraw;
- private final int mVertexShaderId;
- private final int mFragmentShaderId;
-
- private int mGLProgId;
- private int mGLPositionIndex;
- private int mGLInputImageTextureIndex;
- private int mGLTextureCoordinateIndex;
- private int mGLTextureTransformIndex;
-
- protected int mInputWidth;
- protected int mInputHeight;
- protected int mOutputWidth;
- protected int mOutputHeight;
- protected FloatBuffer mGLCubeBuffer;
- protected FloatBuffer mGLTextureBuffer;
-
- private int[] mGLCubeId;
- private int[] mGLTextureCoordinateId;
- private float[] mGLTextureTransformMatrix;
-
- private int[] mGLFboId;
- private int[] mGLFboTexId;
- private IntBuffer mGLFboBuffer;
-
- public GPUImageFilter() {
- this(MagicFilterType.NONE);
- }
-
- public GPUImageFilter(MagicFilterType type) {
- this(type, R.raw.vertex, R.raw.fragment);
- }
-
- public GPUImageFilter(MagicFilterType type, int fragmentShaderId) {
- this(type, R.raw.vertex, fragmentShaderId);
- }
-
- public GPUImageFilter(MagicFilterType type, int vertexShaderId, int fragmentShaderId) {
- mType = type;
- mRunOnDraw = new LinkedList<>();
- mVertexShaderId = vertexShaderId;
- mFragmentShaderId = fragmentShaderId;
-
- mGLCubeBuffer = ByteBuffer.allocateDirect(TextureRotationUtil.CUBE.length * 4)
- .order(ByteOrder.nativeOrder())
- .asFloatBuffer();
- mGLCubeBuffer.put(TextureRotationUtil.CUBE).position(0);
-
- mGLTextureBuffer = ByteBuffer.allocateDirect(TextureRotationUtil.TEXTURE_NO_ROTATION.length * 4)
- .order(ByteOrder.nativeOrder())
- .asFloatBuffer();
- mGLTextureBuffer.put(TextureRotationUtil.getRotation(Rotation.NORMAL, false, true)).position(0);
- }
-
- public void init(Context context) {
- mContext = context;
- onInit();
- onInitialized();
- }
-
- protected void onInit() {
- initVbo();
- loadSamplerShader();
- }
-
- protected void onInitialized() {
- mIsInitialized = true;
- }
-
- public final void destroy() {
- mIsInitialized = false;
- destroyFboTexture();
- destoryVbo();
- GLES20.glDeleteProgram(mGLProgId);
- onDestroy();
- }
-
- protected void onDestroy() {
- }
-
- public void onInputSizeChanged(final int width, final int height) {
- mInputWidth = width;
- mInputHeight = height;
- initFboTexture(width, height);
- }
-
- public void onDisplaySizeChanged(final int width, final int height) {
- mOutputWidth = width;
- mOutputHeight = height;
- }
-
- private void loadSamplerShader() {
- mGLProgId = OpenGLUtils.loadProgram(OpenGLUtils.readShaderFromRawResource(getContext(), mVertexShaderId),
- OpenGLUtils.readShaderFromRawResource(getContext(), mFragmentShaderId));
- mGLPositionIndex = GLES20.glGetAttribLocation(mGLProgId, "position");
- mGLTextureCoordinateIndex = GLES20.glGetAttribLocation(mGLProgId,"inputTextureCoordinate");
- mGLTextureTransformIndex = GLES20.glGetUniformLocation(mGLProgId, "textureTransform");
- mGLInputImageTextureIndex = GLES20.glGetUniformLocation(mGLProgId, "inputImageTexture");
- }
-
- private void initVbo() {
- mGLCubeId = new int[1];
- mGLTextureCoordinateId = new int[1];
-
- GLES20.glGenBuffers(1, mGLCubeId, 0);
- GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, mGLCubeId[0]);
- GLES20.glBufferData(GLES20.GL_ARRAY_BUFFER, mGLCubeBuffer.capacity() * 4, mGLCubeBuffer, GLES20.GL_STATIC_DRAW);
-
- GLES20.glGenBuffers(1, mGLTextureCoordinateId, 0);
- GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, mGLTextureCoordinateId[0]);
- GLES20.glBufferData(GLES20.GL_ARRAY_BUFFER, mGLTextureBuffer.capacity() * 4, mGLTextureBuffer, GLES20.GL_STATIC_DRAW);
- }
-
- private void destoryVbo() {
- if (mGLCubeId != null) {
- GLES20.glDeleteBuffers(1, mGLCubeId, 0);
- mGLCubeId = null;
- }
- if (mGLTextureCoordinateId != null) {
- GLES20.glDeleteBuffers(1, mGLTextureCoordinateId, 0);
- mGLTextureCoordinateId = null;
- }
- }
-
- private void initFboTexture(int width, int height) {
- if (mGLFboId != null && (mInputWidth != width || mInputHeight != height)) {
- destroyFboTexture();
- }
-
- mGLFboId = new int[1];
- mGLFboTexId = new int[1];
- mGLFboBuffer = IntBuffer.allocate(width * height);
-
- GLES20.glGenFramebuffers(1, mGLFboId, 0);
- GLES20.glGenTextures(1, mGLFboTexId, 0);
- GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mGLFboTexId[0]);
- GLES20.glTexImage2D(GLES20.GL_TEXTURE_2D, 0, GLES20.GL_RGBA, width, height, 0, GLES20.GL_RGBA, GLES20.GL_UNSIGNED_BYTE, null);
- GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR);
- GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_LINEAR);
- GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_CLAMP_TO_EDGE);
- GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_CLAMP_TO_EDGE);
- GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, mGLFboId[0]);
- GLES20.glFramebufferTexture2D(GLES20.GL_FRAMEBUFFER, GLES20.GL_COLOR_ATTACHMENT0, GLES20.GL_TEXTURE_2D, mGLFboTexId[0], 0);
- GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, 0);
- GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, 0);
- }
-
- private void destroyFboTexture() {
- if (mGLFboTexId != null) {
- GLES20.glDeleteTextures(1, mGLFboTexId, 0);
- mGLFboTexId = null;
- }
- if (mGLFboId != null) {
- GLES20.glDeleteFramebuffers(1, mGLFboId, 0);
- mGLFboId = null;
- }
- }
-
- public int onDrawFrame(final int textureId, final FloatBuffer cubeBuffer, final FloatBuffer textureBuffer) {
- if (!mIsInitialized) {
- return OpenGLUtils.NOT_INIT;
- }
-
- GLES20.glUseProgram(mGLProgId);
- runPendingOnDrawTasks();
-
- GLES20.glEnableVertexAttribArray(mGLPositionIndex);
- GLES20.glVertexAttribPointer(mGLPositionIndex, 2, GLES20.GL_FLOAT, false, 4 * 2, cubeBuffer);
-
- GLES20.glEnableVertexAttribArray(mGLTextureCoordinateIndex);
- GLES20.glVertexAttribPointer(mGLTextureCoordinateIndex, 2, GLES20.GL_FLOAT, false, 4 * 2, textureBuffer);
-
- if (textureId != OpenGLUtils.NO_TEXTURE) {
- GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
- GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureId);
- GLES20.glUniform1i(mGLInputImageTextureIndex, 0);
- }
-
- onDrawArraysPre();
- GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4);
- onDrawArraysAfter();
-
- GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, 0);
-
- GLES20.glDisableVertexAttribArray(mGLPositionIndex);
- GLES20.glDisableVertexAttribArray(mGLTextureCoordinateIndex);
-
- return OpenGLUtils.ON_DRAWN;
- }
-
- public int onDrawFrame(int cameraTextureId) {
- if (!mIsInitialized) {
- return OpenGLUtils.NOT_INIT;
- }
-
- if (mGLFboId == null) {
- return OpenGLUtils.NO_TEXTURE;
- }
-
- GLES20.glUseProgram(mGLProgId);
- runPendingOnDrawTasks();
-
- GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, mGLCubeId[0]);
- GLES20.glEnableVertexAttribArray(mGLPositionIndex);
- GLES20.glVertexAttribPointer(mGLPositionIndex, 2, GLES20.GL_FLOAT, false, 4 * 2, 0);
-
- GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, mGLTextureCoordinateId[0]);
- GLES20.glEnableVertexAttribArray(mGLTextureCoordinateIndex);
- GLES20.glVertexAttribPointer(mGLTextureCoordinateIndex, 2, GLES20.GL_FLOAT, false, 4 * 2, 0);
-
- GLES20.glUniformMatrix4fv(mGLTextureTransformIndex, 1, false, mGLTextureTransformMatrix, 0);
-
- GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
- GLES20.glBindTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, cameraTextureId);
- GLES20.glUniform1i(mGLInputImageTextureIndex, 0);
-
- onDrawArraysPre();
-
- GLES20.glViewport(0, 0, mInputWidth, mInputHeight);
- GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, mGLFboId[0]);
- GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4);
-
- GLES20.glReadPixels(0, 0, mInputWidth, mInputHeight, GLES20.GL_RGBA, GLES20.GL_UNSIGNED_BYTE, mGLFboBuffer);
- GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, 0);
- GLES20.glViewport(0, 0, mOutputWidth, mOutputHeight);
-
- GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4);
-
- onDrawArraysAfter();
-
- GLES20.glBindTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, 0);
-
- GLES20.glDisableVertexAttribArray(mGLPositionIndex);
- GLES20.glDisableVertexAttribArray(mGLTextureCoordinateIndex);
-
- GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, 0);
-
- return mGLFboTexId[0];
- }
-
- protected void onDrawArraysPre() {}
-
- protected void onDrawArraysAfter() {}
-
- private void runPendingOnDrawTasks() {
- while (!mRunOnDraw.isEmpty()) {
- mRunOnDraw.removeFirst().run();
- }
- }
-
- public int getProgram() {
- return mGLProgId;
- }
-
- public IntBuffer getGLFboBuffer() {
- return mGLFboBuffer;
- }
-
- protected Context getContext() {
- return mContext;
- }
-
- protected MagicFilterType getFilterType() {
- return mType;
- }
-
- public void setTextureTransformMatrix(float[] mtx){
- mGLTextureTransformMatrix = mtx;
- }
-
- protected void setInteger(final int location, final int intValue) {
- runOnDraw(new Runnable() {
- @Override
- public void run() {
- GLES20.glUniform1i(location, intValue);
- }
- });
- }
-
- protected void setFloat(final int location, final float floatValue) {
- runOnDraw(new Runnable() {
- @Override
- public void run() {
- GLES20.glUniform1f(location, floatValue);
- }
- });
- }
-
- protected void setFloatVec2(final int location, final float[] arrayValue) {
- runOnDraw(new Runnable() {
- @Override
- public void run() {
- GLES20.glUniform2fv(location, 1, FloatBuffer.wrap(arrayValue));
- }
- });
- }
-
- protected void setFloatVec3(final int location, final float[] arrayValue) {
- runOnDraw(new Runnable() {
- @Override
- public void run() {
- GLES20.glUniform3fv(location, 1, FloatBuffer.wrap(arrayValue));
- }
- });
- }
-
- protected void setFloatVec4(final int location, final float[] arrayValue) {
- runOnDraw(new Runnable() {
- @Override
- public void run() {
- GLES20.glUniform4fv(location, 1, FloatBuffer.wrap(arrayValue));
- }
- });
- }
-
- protected void setFloatArray(final int location, final float[] arrayValue) {
- runOnDraw(new Runnable() {
- @Override
- public void run() {
- GLES20.glUniform1fv(location, arrayValue.length, FloatBuffer.wrap(arrayValue));
- }
- });
- }
-
- protected void setPoint(final int location, final PointF point) {
- runOnDraw(new Runnable() {
-
- @Override
- public void run() {
- float[] vec2 = new float[2];
- vec2[0] = point.x;
- vec2[1] = point.y;
- GLES20.glUniform2fv(location, 1, vec2, 0);
- }
- });
- }
-
- protected void setUniformMatrix3f(final int location, final float[] matrix) {
- runOnDraw(new Runnable() {
-
- @Override
- public void run() {
- GLES20.glUniformMatrix3fv(location, 1, false, matrix, 0);
- }
- });
- }
-
- protected void setUniformMatrix4f(final int location, final float[] matrix) {
- runOnDraw(new Runnable() {
-
- @Override
- public void run() {
- GLES20.glUniformMatrix4fv(location, 1, false, matrix, 0);
- }
- });
- }
-
- protected void runOnDraw(final Runnable runnable) {
- synchronized (mRunOnDraw) {
- mRunOnDraw.addLast(runnable);
- }
- }
-}
-
diff --git a/Live/src/main/java/com/seu/magicfilter/base/gpuimage/GPUImageHueFilter.java b/Live/src/main/java/com/seu/magicfilter/base/gpuimage/GPUImageHueFilter.java
deleted file mode 100644
index 0ed2772c..00000000
--- a/Live/src/main/java/com/seu/magicfilter/base/gpuimage/GPUImageHueFilter.java
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * Copyright (C) 2012 CyberAgent
- *
- * 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.seu.magicfilter.base.gpuimage;
-
-import android.opengl.GLES20;
-
-import com.frank.live.R;
-import com.seu.magicfilter.utils.MagicFilterType;
-
-public class GPUImageHueFilter extends GPUImageFilter {
-
- private float mHue;
- private int mHueLocation;
-
- public GPUImageHueFilter() {
- this(0.0f);
- }
-
- public GPUImageHueFilter(final float hue) {
- super(MagicFilterType.HUE, R.raw.hue);
- mHue = hue;
- }
-
- @Override
- public void onInit() {
- super.onInit();
- mHueLocation = GLES20.glGetUniformLocation(getProgram(), "hueAdjust");
- }
-
- @Override
- public void onInitialized() {
- super.onInitialized();
- setHue(mHue);
- }
-
- public void setHue(final float hue) {
- mHue = hue;
- float hueAdjust = (mHue % 360.0f) * (float) Math.PI / 180.0f;
- setFloat(mHueLocation, hueAdjust);
- }
-}
diff --git a/Live/src/main/java/com/seu/magicfilter/base/gpuimage/GPUImageSaturationFilter.java b/Live/src/main/java/com/seu/magicfilter/base/gpuimage/GPUImageSaturationFilter.java
deleted file mode 100644
index 5ecb7d38..00000000
--- a/Live/src/main/java/com/seu/magicfilter/base/gpuimage/GPUImageSaturationFilter.java
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * Copyright (C) 2012 CyberAgent
- *
- * 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.seu.magicfilter.base.gpuimage;
-
-import android.opengl.GLES20;
-
-import com.frank.live.R;
-import com.seu.magicfilter.utils.MagicFilterType;
-
-/**
- * saturation: The degree of saturation or desaturation to apply to the image (0.0 - 2.0, with 1.0 as the default)
- */
-public class GPUImageSaturationFilter extends GPUImageFilter {
-
- private int mSaturationLocation;
- private float mSaturation;
-
- public GPUImageSaturationFilter() {
- this(1.0f);
- }
-
- public GPUImageSaturationFilter(final float saturation) {
- super(MagicFilterType.SATURATION, R.raw.saturation);
- mSaturation = saturation;
- }
-
- @Override
- public void onInit() {
- super.onInit();
- mSaturationLocation = GLES20.glGetUniformLocation(getProgram(), "saturation");
- }
-
- @Override
- public void onInitialized() {
- super.onInitialized();
- setSaturation(mSaturation);
- }
-
- public void setSaturation(final float saturation) {
- mSaturation = saturation;
- setFloat(mSaturationLocation, mSaturation);
- }
-}
diff --git a/Live/src/main/java/com/seu/magicfilter/base/gpuimage/GPUImageSharpenFilter.java b/Live/src/main/java/com/seu/magicfilter/base/gpuimage/GPUImageSharpenFilter.java
deleted file mode 100644
index a9bef394..00000000
--- a/Live/src/main/java/com/seu/magicfilter/base/gpuimage/GPUImageSharpenFilter.java
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- * Copyright (C) 2012 CyberAgent
- *
- * 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.seu.magicfilter.base.gpuimage;
-
-import android.opengl.GLES20;
-
-import com.frank.live.R;
-import com.seu.magicfilter.utils.MagicFilterType;
-
-/**
- * Sharpens the picture.
- *
- * sharpness: from -4.0 to 4.0, with 0.0 as the normal level
- */
-public class GPUImageSharpenFilter extends GPUImageFilter {
-
- private int mSharpnessLocation;
- private float mSharpness;
- private int mImageWidthFactorLocation;
- private int mImageHeightFactorLocation;
-
- public GPUImageSharpenFilter() {
- this(0.0f);
- }
-
- public GPUImageSharpenFilter(final float sharpness) {
- super(MagicFilterType.SHARPEN, R.raw.vertex_sharpen, R.raw.sharpen);
- mSharpness = sharpness;
- }
-
- @Override
- public void onInit() {
- super.onInit();
- mSharpnessLocation = GLES20.glGetUniformLocation(getProgram(), "sharpness");
- mImageWidthFactorLocation = GLES20.glGetUniformLocation(getProgram(), "imageWidthFactor");
- mImageHeightFactorLocation = GLES20.glGetUniformLocation(getProgram(), "imageHeightFactor");
- setSharpness(mSharpness);
- }
-
- @Override
- public void onInputSizeChanged(final int width, final int height) {
- super.onInputSizeChanged(width, height);
- setFloat(mImageWidthFactorLocation, 1.0f / width);
- setFloat(mImageHeightFactorLocation, 1.0f / height);
- }
-
- public void setSharpness(final float sharpness) {
- mSharpness = sharpness;
- setFloat(mSharpnessLocation, mSharpness);
- }
-}
diff --git a/Live/src/main/java/com/seu/magicfilter/utils/MagicFilterFactory.java b/Live/src/main/java/com/seu/magicfilter/utils/MagicFilterFactory.java
deleted file mode 100644
index ed50e53d..00000000
--- a/Live/src/main/java/com/seu/magicfilter/utils/MagicFilterFactory.java
+++ /dev/null
@@ -1,163 +0,0 @@
-package com.seu.magicfilter.utils;
-
-import com.seu.magicfilter.advanced.MagicAmaroFilter;
-import com.seu.magicfilter.advanced.MagicAntiqueFilter;
-import com.seu.magicfilter.advanced.MagicBeautyFilter;
-import com.seu.magicfilter.advanced.MagicBlackCatFilter;
-import com.seu.magicfilter.advanced.MagicBrannanFilter;
-import com.seu.magicfilter.advanced.MagicBrooklynFilter;
-import com.seu.magicfilter.advanced.MagicCalmFilter;
-import com.seu.magicfilter.advanced.MagicCoolFilter;
-import com.seu.magicfilter.advanced.MagicCrayonFilter;
-import com.seu.magicfilter.advanced.MagicEarlyBirdFilter;
-import com.seu.magicfilter.advanced.MagicEmeraldFilter;
-import com.seu.magicfilter.advanced.MagicEvergreenFilter;
-import com.seu.magicfilter.advanced.MagicFreudFilter;
-import com.seu.magicfilter.advanced.MagicHealthyFilter;
-import com.seu.magicfilter.advanced.MagicHefeFilter;
-import com.seu.magicfilter.advanced.MagicHudsonFilter;
-import com.seu.magicfilter.advanced.MagicImageAdjustFilter;
-import com.seu.magicfilter.advanced.MagicInkwellFilter;
-import com.seu.magicfilter.advanced.MagicKevinFilter;
-import com.seu.magicfilter.advanced.MagicLatteFilter;
-import com.seu.magicfilter.advanced.MagicLomoFilter;
-import com.seu.magicfilter.advanced.MagicN1977Filter;
-import com.seu.magicfilter.advanced.MagicNashvilleFilter;
-import com.seu.magicfilter.advanced.MagicNostalgiaFilter;
-import com.seu.magicfilter.advanced.MagicPixelFilter;
-import com.seu.magicfilter.advanced.MagicRiseFilter;
-import com.seu.magicfilter.advanced.MagicRomanceFilter;
-import com.seu.magicfilter.advanced.MagicSakuraFilter;
-import com.seu.magicfilter.advanced.MagicSierraFilter;
-import com.seu.magicfilter.advanced.MagicSketchFilter;
-import com.seu.magicfilter.advanced.MagicSkinWhitenFilter;
-import com.seu.magicfilter.advanced.MagicSunriseFilter;
-import com.seu.magicfilter.advanced.MagicSunsetFilter;
-import com.seu.magicfilter.advanced.MagicSutroFilter;
-import com.seu.magicfilter.advanced.MagicSweetsFilter;
-import com.seu.magicfilter.advanced.MagicTenderFilter;
-import com.seu.magicfilter.advanced.MagicToasterFilter;
-import com.seu.magicfilter.advanced.MagicValenciaFilter;
-import com.seu.magicfilter.advanced.MagicWaldenFilter;
-import com.seu.magicfilter.advanced.MagicWarmFilter;
-import com.seu.magicfilter.advanced.MagicWhiteCatFilter;
-import com.seu.magicfilter.advanced.MagicXproIIFilter;
-import com.seu.magicfilter.base.MagicLookupFilter;
-import com.seu.magicfilter.base.gpuimage.GPUImageBrightnessFilter;
-import com.seu.magicfilter.base.gpuimage.GPUImageContrastFilter;
-import com.seu.magicfilter.base.gpuimage.GPUImageExposureFilter;
-import com.seu.magicfilter.base.gpuimage.GPUImageFilter;
-import com.seu.magicfilter.base.gpuimage.GPUImageHueFilter;
-import com.seu.magicfilter.base.gpuimage.GPUImageSaturationFilter;
-import com.seu.magicfilter.base.gpuimage.GPUImageSharpenFilter;
-
-public class MagicFilterFactory{
-
- public static GPUImageFilter initFilters(MagicFilterType type) {
- switch (type) {
- case NONE:
- return new GPUImageFilter();
- case WHITECAT:
- return new MagicWhiteCatFilter();
- case BLACKCAT:
- return new MagicBlackCatFilter();
- case SKINWHITEN:
- return new MagicSkinWhitenFilter();
- case BEAUTY:
- return new MagicBeautyFilter();
- case ROMANCE:
- return new MagicRomanceFilter();
- case SAKURA:
- return new MagicSakuraFilter();
- case AMARO:
- return new MagicAmaroFilter();
- case WALDEN:
- return new MagicWaldenFilter();
- case ANTIQUE:
- return new MagicAntiqueFilter();
- case CALM:
- return new MagicCalmFilter();
- case BRANNAN:
- return new MagicBrannanFilter();
- case BROOKLYN:
- return new MagicBrooklynFilter();
- case EARLYBIRD:
- return new MagicEarlyBirdFilter();
- case FREUD:
- return new MagicFreudFilter();
- case HEFE:
- return new MagicHefeFilter();
- case HUDSON:
- return new MagicHudsonFilter();
- case INKWELL:
- return new MagicInkwellFilter();
- case KEVIN:
- return new MagicKevinFilter();
- case LOCKUP:
- return new MagicLookupFilter("");
- case LOMO:
- return new MagicLomoFilter();
- case N1977:
- return new MagicN1977Filter();
- case NASHVILLE:
- return new MagicNashvilleFilter();
- case PIXAR:
- return new MagicPixelFilter();
- case RISE:
- return new MagicRiseFilter();
- case SIERRA:
- return new MagicSierraFilter();
- case SUTRO:
- return new MagicSutroFilter();
- case TOASTER2:
- return new MagicToasterFilter();
- case VALENCIA:
- return new MagicValenciaFilter();
- case XPROII:
- return new MagicXproIIFilter();
- case EVERGREEN:
- return new MagicEvergreenFilter();
- case HEALTHY:
- return new MagicHealthyFilter();
- case COOL:
- return new MagicCoolFilter();
- case EMERALD:
- return new MagicEmeraldFilter();
- case LATTE:
- return new MagicLatteFilter();
- case WARM:
- return new MagicWarmFilter();
- case TENDER:
- return new MagicTenderFilter();
- case SWEETS:
- return new MagicSweetsFilter();
- case NOSTALGIA:
- return new MagicNostalgiaFilter();
- case SUNRISE:
- return new MagicSunriseFilter();
- case SUNSET:
- return new MagicSunsetFilter();
- case CRAYON:
- return new MagicCrayonFilter();
- case SKETCH:
- return new MagicSketchFilter();
- //image adjust
- case BRIGHTNESS:
- return new GPUImageBrightnessFilter();
- case CONTRAST:
- return new GPUImageContrastFilter();
- case EXPOSURE:
- return new GPUImageExposureFilter();
- case HUE:
- return new GPUImageHueFilter();
- case SATURATION:
- return new GPUImageSaturationFilter();
- case SHARPEN:
- return new GPUImageSharpenFilter();
- case IMAGE_ADJUST:
- return new MagicImageAdjustFilter();
- default:
- return null;
- }
- }
-}
diff --git a/Live/src/main/java/com/seu/magicfilter/utils/MagicFilterType.java b/Live/src/main/java/com/seu/magicfilter/utils/MagicFilterType.java
deleted file mode 100644
index 419c716d..00000000
--- a/Live/src/main/java/com/seu/magicfilter/utils/MagicFilterType.java
+++ /dev/null
@@ -1,59 +0,0 @@
-package com.seu.magicfilter.utils;
-
-/**
- * Created by why8222 on 2016/2/25.
- */
-public enum MagicFilterType {
- NONE,
- FAIRYTALE,
- SUNRISE,
- SUNSET,
- WHITECAT,
- BLACKCAT,
- SKINWHITEN,
- BEAUTY,
- HEALTHY,
- SWEETS,
- ROMANCE,
- SAKURA,
- WARM,
- ANTIQUE,
- NOSTALGIA,
- CALM,
- LATTE,
- TENDER,
- COOL,
- EMERALD,
- EVERGREEN,
- CRAYON,
- SKETCH,
- AMARO,
- BRANNAN,
- BROOKLYN,
- EARLYBIRD,
- FREUD,
- HEFE,
- HUDSON,
- INKWELL,
- KEVIN,
- LOCKUP,
- LOMO,
- N1977,
- NASHVILLE,
- PIXAR,
- RISE,
- SIERRA,
- SUTRO,
- TOASTER2,
- VALENCIA,
- WALDEN,
- XPROII,
- //image adjust
- CONTRAST,
- BRIGHTNESS,
- EXPOSURE,
- HUE,
- SATURATION,
- SHARPEN,
- IMAGE_ADJUST
-}
diff --git a/Live/src/main/java/com/seu/magicfilter/utils/OpenGLUtils.java b/Live/src/main/java/com/seu/magicfilter/utils/OpenGLUtils.java
deleted file mode 100644
index 6de6bee7..00000000
--- a/Live/src/main/java/com/seu/magicfilter/utils/OpenGLUtils.java
+++ /dev/null
@@ -1,230 +0,0 @@
-package com.seu.magicfilter.utils;
-
-import android.content.Context;
-import android.content.res.AssetManager;
-import android.graphics.Bitmap;
-import android.graphics.BitmapFactory;
-import android.opengl.GLES11Ext;
-import android.opengl.GLES20;
-import android.opengl.GLUtils;
-import android.util.Log;
-
-import java.io.BufferedReader;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.InputStreamReader;
-import java.nio.Buffer;
-
-import javax.microedition.khronos.opengles.GL10;
-
-public class OpenGLUtils {
- public static final int NO_TEXTURE = -1;
- public static final int NOT_INIT = -1;
- public static final int ON_DRAWN = 1;
-
- public static int loadTexture(Bitmap img, int usedTexId) {
- return loadTexture(img, usedTexId, false);
- }
-
- public static int loadTexture(Bitmap img, int usedTexId, boolean recyled) {
- if(img == null)
- return NO_TEXTURE;
- int textures[] = new int[1];
- if (usedTexId == NO_TEXTURE) {
- GLES20.glGenTextures(1, textures, 0);
- GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textures[0]);
- GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D,
- GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR);
- GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D,
- GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_LINEAR);
- GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D,
- GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_CLAMP_TO_EDGE);
- GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D,
- GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_CLAMP_TO_EDGE);
-
- GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, img, 0);
- } else {
- GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, usedTexId);
- GLUtils.texSubImage2D(GLES20.GL_TEXTURE_2D, 0, 0, 0, img);
- textures[0] = usedTexId;
- }
- if(recyled)
- img.recycle();
- return textures[0];
- }
-
- public static int loadTexture(Buffer data, int width, int height, int usedTexId) {
- if(data == null)
- return NO_TEXTURE;
- int textures[] = new int[1];
- if (usedTexId == NO_TEXTURE) {
- GLES20.glGenTextures(1, textures, 0);
- GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textures[0]);
- GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D,
- GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR);
- GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D,
- GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_LINEAR);
- GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D,
- GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_CLAMP_TO_EDGE);
- GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D,
- GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_CLAMP_TO_EDGE);
- GLES20.glTexImage2D(GLES20.GL_TEXTURE_2D, 0, GLES20.GL_RGBA, width, height,
- 0, GLES20.GL_RGBA, GLES20.GL_UNSIGNED_BYTE, data);
- } else {
- GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, usedTexId);
- GLES20.glTexSubImage2D(GLES20.GL_TEXTURE_2D, 0, 0, 0, width,
- height, GLES20.GL_RGBA, GLES20.GL_UNSIGNED_BYTE, data);
- textures[0] = usedTexId;
- }
- return textures[0];
- }
-
- public static int loadTexture(Buffer data, int width, int height, int usedTexId, int type) {
- if(data == null)
- return NO_TEXTURE;
- int textures[] = new int[1];
- if (usedTexId == NO_TEXTURE) {
- GLES20.glGenTextures(1, textures, 0);
- GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textures[0]);
- GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D,
- GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR);
- GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D,
- GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_LINEAR);
- GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D,
- GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_CLAMP_TO_EDGE);
- GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D,
- GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_CLAMP_TO_EDGE);
- GLES20.glTexImage2D(GLES20.GL_TEXTURE_2D, 0, GLES20.GL_RGBA, width, height,
- 0, GLES20.GL_RGBA, type, data);
- } else {
- GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, usedTexId);
- GLES20.glTexSubImage2D(GLES20.GL_TEXTURE_2D, 0, 0, 0, width,
- height, GLES20.GL_RGBA, type, data);
- textures[0] = usedTexId;
- }
- return textures[0];
- }
-
- public static int loadTexture(final Context context, final String name){
- final int[] textureHandle = new int[1];
-
- GLES20.glGenTextures(1, textureHandle, 0);
-
- if (textureHandle[0] != 0){
-
- // Read in the resource
- final Bitmap bitmap = getImageFromAssetsFile(context,name);
-
- // Bind to the texture in OpenGL
- GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureHandle[0]);
-
- // Set filtering
- GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR);
- GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_LINEAR);
- GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_CLAMP_TO_EDGE);
- GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_CLAMP_TO_EDGE);
- // Load the bitmap into the bound texture.
- GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, bitmap, 0);
-
- // Recycle the bitmap, since its data has been loaded into OpenGL.
- bitmap.recycle();
- }
-
- if (textureHandle[0] == 0){
- throw new RuntimeException("Error loading texture.");
- }
-
- return textureHandle[0];
- }
-
- private static Bitmap getImageFromAssetsFile(Context context, String fileName){
- Bitmap image = null;
- AssetManager am = context.getResources().getAssets();
- try{
- InputStream is = am.open(fileName);
- image = BitmapFactory.decodeStream(is);
- is.close();
- }catch (IOException e){
- e.printStackTrace();
- }
- return image;
- }
-
- public static int loadProgram(String strVSource, String strFSource) {
- int iVShader;
- int iFShader;
- int iProgId;
- int[] link = new int[1];
- iVShader = loadShader(strVSource, GLES20.GL_VERTEX_SHADER);
- if (iVShader == 0) {
- Log.d("Load Program", "Vertex Shader Failed");
- return 0;
- }
- iFShader = loadShader(strFSource, GLES20.GL_FRAGMENT_SHADER);
- if (iFShader == 0) {
- Log.d("Load Program", "Fragment Shader Failed");
- return 0;
- }
-
- iProgId = GLES20.glCreateProgram();
- GLES20.glAttachShader(iProgId, iVShader);
- GLES20.glAttachShader(iProgId, iFShader);
- GLES20.glLinkProgram(iProgId);
- GLES20.glGetProgramiv(iProgId, GLES20.GL_LINK_STATUS, link, 0);
- if (link[0] <= 0) {
- Log.d("Load Program", "Linking Failed");
- return 0;
- }
- GLES20.glDeleteShader(iVShader);
- GLES20.glDeleteShader(iFShader);
- return iProgId;
- }
-
- private static int loadShader(String strSource, int iType) {
- int[] compiled = new int[1];
- int iShader = GLES20.glCreateShader(iType);
- GLES20.glShaderSource(iShader, strSource);
- GLES20.glCompileShader(iShader);
- GLES20.glGetShaderiv(iShader, GLES20.GL_COMPILE_STATUS, compiled, 0);
- if (compiled[0] == 0) {
- Log.e("Load Shader Failed", "Compilation\n" + GLES20.glGetShaderInfoLog(iShader));
- return 0;
- }
- return iShader;
- }
-
- public static int getExternalOESTextureID(){
- int[] texture = new int[1];
- GLES20.glGenTextures(1, texture, 0);
- GLES20.glBindTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, texture[0]);
- GLES20.glTexParameterf(GLES11Ext.GL_TEXTURE_EXTERNAL_OES,
- GL10.GL_TEXTURE_MIN_FILTER, GL10.GL_LINEAR);
- GLES20.glTexParameterf(GLES11Ext.GL_TEXTURE_EXTERNAL_OES,
- GL10.GL_TEXTURE_MAG_FILTER, GL10.GL_LINEAR);
- GLES20.glTexParameteri(GLES11Ext.GL_TEXTURE_EXTERNAL_OES,
- GL10.GL_TEXTURE_WRAP_S, GL10.GL_CLAMP_TO_EDGE);
- GLES20.glTexParameteri(GLES11Ext.GL_TEXTURE_EXTERNAL_OES,
- GL10.GL_TEXTURE_WRAP_T, GL10.GL_CLAMP_TO_EDGE);
- return texture[0];
- }
-
- public static String readShaderFromRawResource(Context context, int resourceId){
- final InputStream inputStream = context.getResources().openRawResource(resourceId);
- final InputStreamReader inputStreamReader = new InputStreamReader(inputStream);
- final BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
-
- String nextLine;
- final StringBuilder body = new StringBuilder();
-
- try{
- while ((nextLine = bufferedReader.readLine()) != null){
- body.append(nextLine);
- body.append('\n');
- }
- }
- catch (IOException e){
- return null;
- }
- return body.toString();
- }
-}
diff --git a/Live/src/main/java/com/seu/magicfilter/utils/Rotation.java b/Live/src/main/java/com/seu/magicfilter/utils/Rotation.java
deleted file mode 100644
index 105cc787..00000000
--- a/Live/src/main/java/com/seu/magicfilter/utils/Rotation.java
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * Copyright (C) 2012 CyberAgent
- *
- * 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.seu.magicfilter.utils;
-
-public enum Rotation {
- NORMAL, ROTATION_90, ROTATION_180, ROTATION_270;
-
- /**
- * Retrieves the int representation of the Rotation.
- *
- * @return 0, 90, 180 or 270
- */
- public int asInt() {
- switch (this) {
- case NORMAL: return 0;
- case ROTATION_90: return 90;
- case ROTATION_180: return 180;
- case ROTATION_270: return 270;
- default: throw new IllegalStateException("Unknown Rotation!");
- }
- }
-
- /**
- * Create a Rotation from an integer. Needs to be either 0, 90, 180 or 270.
- *
- * @param rotation 0, 90, 180 or 270
- * @return Rotation object
- */
- public static Rotation fromInt(int rotation) {
- switch (rotation) {
- case 0: return NORMAL;
- case 90: return ROTATION_90;
- case 180: return ROTATION_180;
- case 270: return ROTATION_270;
- case 360: return NORMAL;
- default: throw new IllegalStateException(
- rotation + " is an unknown rotation. Needs to be either 0, 90, 180 or 270!");
- }
- }
-}
diff --git a/Live/src/main/java/com/seu/magicfilter/utils/TextureRotationUtil.java b/Live/src/main/java/com/seu/magicfilter/utils/TextureRotationUtil.java
deleted file mode 100644
index f236305e..00000000
--- a/Live/src/main/java/com/seu/magicfilter/utils/TextureRotationUtil.java
+++ /dev/null
@@ -1,96 +0,0 @@
-/*
- * Copyright (C) 2012 CyberAgent
- *
- * 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.seu.magicfilter.utils;
-
-public class TextureRotationUtil {
-
- public static final float TEXTURE_NO_ROTATION[] = {
- 0.0f, 1.0f,
- 1.0f, 1.0f,
- 0.0f, 0.0f,
- 1.0f, 0.0f,
- };
-
- public static final float TEXTURE_ROTATED_90[] = {
- 1.0f, 1.0f,
- 1.0f, 0.0f,
- 0.0f, 1.0f,
- 0.0f, 0.0f,
- };
- public static final float TEXTURE_ROTATED_180[] = {
- 1.0f, 0.0f,
- 0.0f, 0.0f,
- 1.0f, 1.0f,
- 0.0f, 1.0f,
- };
- public static final float TEXTURE_ROTATED_270[] = {
- 0.0f, 0.0f,
- 0.0f, 1.0f,
- 1.0f, 0.0f,
- 1.0f, 1.0f,
- };
-
- public static final float CUBE[] = {
- -1.0f, -1.0f,
- 1.0f, -1.0f,
- -1.0f, 1.0f,
- 1.0f, 1.0f,
- };
-
- private TextureRotationUtil() {}
-
- public static float[] getRotation(final Rotation rotation, final boolean flipHorizontal,
- final boolean flipVertical) {
- float[] rotatedTex;
- switch (rotation) {
- case ROTATION_90:
- rotatedTex = TEXTURE_ROTATED_90;
- break;
- case ROTATION_180:
- rotatedTex = TEXTURE_ROTATED_180;
- break;
- case ROTATION_270:
- rotatedTex = TEXTURE_ROTATED_270;
- break;
- case NORMAL:
- default:
- rotatedTex = TEXTURE_NO_ROTATION;
- break;
- }
- if (flipHorizontal) {
- rotatedTex = new float[]{
- flip(rotatedTex[0]), rotatedTex[1],
- flip(rotatedTex[2]), rotatedTex[3],
- flip(rotatedTex[4]), rotatedTex[5],
- flip(rotatedTex[6]), rotatedTex[7],
- };
- }
- if (flipVertical) {
- rotatedTex = new float[]{
- rotatedTex[0], flip(rotatedTex[1]),
- rotatedTex[2], flip(rotatedTex[3]),
- rotatedTex[4], flip(rotatedTex[5]),
- rotatedTex[6], flip(rotatedTex[7]),
- };
- }
- return rotatedTex;
- }
-
- private static float flip(final float i) {
- return i == 0.0f ? 1.0f : 0.0f;
- }
-}
diff --git a/Live/src/main/res/layout/activity_live.xml b/Live/src/main/res/layout/activity_live.xml
deleted file mode 100644
index a42a6c0b..00000000
--- a/Live/src/main/res/layout/activity_live.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-
-
-
-
-
-
-
-
-
-
diff --git a/Live/src/main/res/layout/activity_push.xml b/Live/src/main/res/layout/activity_push.xml
deleted file mode 100644
index 2a56b4c6..00000000
--- a/Live/src/main/res/layout/activity_push.xml
+++ /dev/null
@@ -1,40 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/Live/src/main/res/mipmap-mdpi/ic_launcher.png b/Live/src/main/res/mipmap-mdpi/ic_launcher.png
deleted file mode 100644
index c133a0cb..00000000
Binary files a/Live/src/main/res/mipmap-mdpi/ic_launcher.png and /dev/null differ
diff --git a/Live/src/main/res/mipmap-mdpi/ic_launcher_round.png b/Live/src/main/res/mipmap-mdpi/ic_launcher_round.png
deleted file mode 100644
index efc028a6..00000000
Binary files a/Live/src/main/res/mipmap-mdpi/ic_launcher_round.png and /dev/null differ
diff --git a/Live/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/Live/src/main/res/mipmap-xxxhdpi/ic_launcher.png
deleted file mode 100644
index aee44e13..00000000
Binary files a/Live/src/main/res/mipmap-xxxhdpi/ic_launcher.png and /dev/null differ
diff --git a/Live/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png b/Live/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
deleted file mode 100644
index 34947cd6..00000000
Binary files a/Live/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png and /dev/null differ
diff --git a/Live/src/main/res/raw/amaro.glsl b/Live/src/main/res/raw/amaro.glsl
deleted file mode 100644
index b5103161..00000000
--- a/Live/src/main/res/raw/amaro.glsl
+++ /dev/null
@@ -1,32 +0,0 @@
-#extension GL_OES_EGL_image_external : require
-
-precision mediump float;
-
-varying mediump vec2 textureCoordinate;
-
-uniform samplerExternalOES inputImageTexture;
-uniform sampler2D inputImageTexture2; //blowout;
-uniform sampler2D inputImageTexture3; //overlay;
-uniform sampler2D inputImageTexture4; //map
-
-uniform float strength;
-
-void main()
-{
- vec4 originColor = texture2D(inputImageTexture, textureCoordinate);
- vec4 texel = texture2D(inputImageTexture, textureCoordinate);
- vec3 bbTexel = texture2D(inputImageTexture2, textureCoordinate).rgb;
-
- texel.r = texture2D(inputImageTexture3, vec2(bbTexel.r, texel.r)).r;
- texel.g = texture2D(inputImageTexture3, vec2(bbTexel.g, texel.g)).g;
- texel.b = texture2D(inputImageTexture3, vec2(bbTexel.b, texel.b)).b;
-
- vec4 mapped;
- mapped.r = texture2D(inputImageTexture4, vec2(texel.r, .16666)).r;
- mapped.g = texture2D(inputImageTexture4, vec2(texel.g, .5)).g;
- mapped.b = texture2D(inputImageTexture4, vec2(texel.b, .83333)).b;
- mapped.a = 1.0;
-
- mapped.rgb = mix(originColor.rgb, mapped.rgb, strength);
- gl_FragColor = mapped;
-}
diff --git a/Live/src/main/res/raw/antique.glsl b/Live/src/main/res/raw/antique.glsl
deleted file mode 100644
index 3a05170e..00000000
--- a/Live/src/main/res/raw/antique.glsl
+++ /dev/null
@@ -1,53 +0,0 @@
-#extension GL_OES_EGL_image_external : require
-
-precision highp float;
-
-varying highp vec2 textureCoordinate;
-
-uniform samplerExternalOES inputImageTexture;
-uniform sampler2D curve;
-
-void main()
-{
- highp vec4 textureColor;
- highp vec4 textureColorRes;
- highp float satVal = 65.0 / 100.0;
-
- float xCoordinate = textureCoordinate.x;
- float yCoordinate = textureCoordinate.y;
-
- highp float redCurveValue;
- highp float greenCurveValue;
- highp float blueCurveValue;
-
- textureColor = texture2D( inputImageTexture, vec2(xCoordinate, yCoordinate));
- textureColorRes = textureColor;
-
- redCurveValue = texture2D(curve, vec2(textureColor.r, 0.0)).r;
- greenCurveValue = texture2D(curve, vec2(textureColor.g, 0.0)).g;
- blueCurveValue = texture2D(curve, vec2(textureColor.b, 0.0)).b;
-
- highp float G = (redCurveValue + greenCurveValue + blueCurveValue);
- G = G / 3.0;
-
- redCurveValue = ((1.0 - satVal) * G + satVal * redCurveValue);
- greenCurveValue = ((1.0 - satVal) * G + satVal * greenCurveValue);
- blueCurveValue = ((1.0 - satVal) * G + satVal * blueCurveValue);
- redCurveValue = (((redCurveValue) > (1.0)) ? (1.0) : (((redCurveValue) < (0.0)) ? (0.0) : (redCurveValue)));
- greenCurveValue = (((greenCurveValue) > (1.0)) ? (1.0) : (((greenCurveValue) < (0.0)) ? (0.0) : (greenCurveValue)));
- blueCurveValue = (((blueCurveValue) > (1.0)) ? (1.0) : (((blueCurveValue) < (0.0)) ? (0.0) : (blueCurveValue)));
-
- redCurveValue = texture2D(curve, vec2(redCurveValue, 0.0)).a;
- greenCurveValue = texture2D(curve, vec2(greenCurveValue, 0.0)).a;
- blueCurveValue = texture2D(curve, vec2(blueCurveValue, 0.0)).a;
-
- highp vec4 base = vec4(redCurveValue, greenCurveValue, blueCurveValue, 1.0);
- highp vec4 overlayer = vec4(250.0/255.0, 227.0/255.0, 193.0/255.0, 1.0);
-
- textureColor = overlayer * base;
- base = (textureColor - base) * 0.850980 + base;
- textureColor = base;
-
- gl_FragColor = vec4(textureColor.r, textureColor.g, textureColor.b, 1.0);
-}
-
\ No newline at end of file
diff --git a/Live/src/main/res/raw/beauty.glsl b/Live/src/main/res/raw/beauty.glsl
deleted file mode 100644
index 1a32a638..00000000
--- a/Live/src/main/res/raw/beauty.glsl
+++ /dev/null
@@ -1,111 +0,0 @@
-#extension GL_OES_EGL_image_external : require
-
-precision highp float;
-
-uniform samplerExternalOES inputImageTexture;
-uniform vec2 singleStepOffset;
-
-varying vec2 textureCoordinate;
-
-const vec4 params = vec4(0.748, 0.874, 0.241, 0.241);
-const vec3 W = vec3(0.299,0.587,0.114);
-const mat3 saturateMatrix = mat3(
- 1.1102,-0.0598,-0.061,
- -0.0774,1.0826,-0.1186,
- -0.0228,-0.0228,1.1772);
-
-vec2 blurCoordinates[24];
-
-float hardLight(float color) {
- if(color <= 0.5) {
- color = color * color * 2.0;
- } else {
- color = 1.0 - ((1.0 - color)*(1.0 - color) * 2.0);
- }
- return color;
-}
-
-void main() {
- vec3 centralColor = texture2D(inputImageTexture, textureCoordinate).rgb;
-
- blurCoordinates[0] = textureCoordinate.xy + singleStepOffset * vec2(0.0, -10.0);
- blurCoordinates[1] = textureCoordinate.xy + singleStepOffset * vec2(0.0, 10.0);
- blurCoordinates[2] = textureCoordinate.xy + singleStepOffset * vec2(-10.0, 0.0);
- blurCoordinates[3] = textureCoordinate.xy + singleStepOffset * vec2(10.0, 0.0);
- blurCoordinates[4] = textureCoordinate.xy + singleStepOffset * vec2(5.0, -8.0);
- blurCoordinates[5] = textureCoordinate.xy + singleStepOffset * vec2(5.0, 8.0);
- blurCoordinates[6] = textureCoordinate.xy + singleStepOffset * vec2(-5.0, 8.0);
- blurCoordinates[7] = textureCoordinate.xy + singleStepOffset * vec2(-5.0, -8.0);
- blurCoordinates[8] = textureCoordinate.xy + singleStepOffset * vec2(8.0, -5.0);
- blurCoordinates[9] = textureCoordinate.xy + singleStepOffset * vec2(8.0, 5.0);
- blurCoordinates[10] = textureCoordinate.xy + singleStepOffset * vec2(-8.0, 5.0);
- blurCoordinates[11] = textureCoordinate.xy + singleStepOffset * vec2(-8.0, -5.0);
- blurCoordinates[12] = textureCoordinate.xy + singleStepOffset * vec2(0.0, -6.0);
- blurCoordinates[13] = textureCoordinate.xy + singleStepOffset * vec2(0.0, 6.0);
- blurCoordinates[14] = textureCoordinate.xy + singleStepOffset * vec2(6.0, 0.0);
- blurCoordinates[15] = textureCoordinate.xy + singleStepOffset * vec2(-6.0, 0.0);
- blurCoordinates[16] = textureCoordinate.xy + singleStepOffset * vec2(-4.0, -4.0);
- blurCoordinates[17] = textureCoordinate.xy + singleStepOffset * vec2(-4.0, 4.0);
- blurCoordinates[18] = textureCoordinate.xy + singleStepOffset * vec2(4.0, -4.0);
- blurCoordinates[19] = textureCoordinate.xy + singleStepOffset * vec2(4.0, 4.0);
- blurCoordinates[20] = textureCoordinate.xy + singleStepOffset * vec2(-2.0, -2.0);
- blurCoordinates[21] = textureCoordinate.xy + singleStepOffset * vec2(-2.0, 2.0);
- blurCoordinates[22] = textureCoordinate.xy + singleStepOffset * vec2(2.0, -2.0);
- blurCoordinates[23] = textureCoordinate.xy + singleStepOffset * vec2(2.0, 2.0);
-
- float sampleColor = centralColor.g * 22.0;
- sampleColor += texture2D(inputImageTexture, blurCoordinates[0]).g;
- sampleColor += texture2D(inputImageTexture, blurCoordinates[1]).g;
- sampleColor += texture2D(inputImageTexture, blurCoordinates[2]).g;
- sampleColor += texture2D(inputImageTexture, blurCoordinates[3]).g;
- sampleColor += texture2D(inputImageTexture, blurCoordinates[4]).g;
- sampleColor += texture2D(inputImageTexture, blurCoordinates[5]).g;
- sampleColor += texture2D(inputImageTexture, blurCoordinates[6]).g;
- sampleColor += texture2D(inputImageTexture, blurCoordinates[7]).g;
- sampleColor += texture2D(inputImageTexture, blurCoordinates[8]).g;
- sampleColor += texture2D(inputImageTexture, blurCoordinates[9]).g;
- sampleColor += texture2D(inputImageTexture, blurCoordinates[10]).g;
- sampleColor += texture2D(inputImageTexture, blurCoordinates[11]).g;
- sampleColor += texture2D(inputImageTexture, blurCoordinates[12]).g * 2.0;
- sampleColor += texture2D(inputImageTexture, blurCoordinates[13]).g * 2.0;
- sampleColor += texture2D(inputImageTexture, blurCoordinates[14]).g * 2.0;
- sampleColor += texture2D(inputImageTexture, blurCoordinates[15]).g * 2.0;
- sampleColor += texture2D(inputImageTexture, blurCoordinates[16]).g * 2.0;
- sampleColor += texture2D(inputImageTexture, blurCoordinates[17]).g * 2.0;
- sampleColor += texture2D(inputImageTexture, blurCoordinates[18]).g * 2.0;
- sampleColor += texture2D(inputImageTexture, blurCoordinates[19]).g * 2.0;
- sampleColor += texture2D(inputImageTexture, blurCoordinates[20]).g * 3.0;
- sampleColor += texture2D(inputImageTexture, blurCoordinates[21]).g * 3.0;
- sampleColor += texture2D(inputImageTexture, blurCoordinates[22]).g * 3.0;
- sampleColor += texture2D(inputImageTexture, blurCoordinates[23]).g * 3.0;
- sampleColor = sampleColor / 62.0;
-
- float highPass = centralColor.g - sampleColor + 0.5;
-
- for(int i = 0; i < 5;i++)
- {
- highPass = hardLight(highPass);
- }
- float luminance = dot(centralColor, W);
- float alpha = pow(luminance, params.r);
-
- vec3 smoothColor = centralColor + (centralColor-vec3(highPass))*alpha*0.1;
-
- smoothColor.r = clamp(pow(smoothColor.r, params.g),0.0,1.0);
- smoothColor.g = clamp(pow(smoothColor.g, params.g),0.0,1.0);
- smoothColor.b = clamp(pow(smoothColor.b, params.g),0.0,1.0);
-
- vec3 screen = vec3(1.0) - (vec3(1.0)-smoothColor) * (vec3(1.0)-centralColor);
- vec3 lighten = max(smoothColor, centralColor);
- vec3 softLight = 2.0 * centralColor*smoothColor + centralColor*centralColor
- - 2.0 * centralColor*centralColor * smoothColor;
-
- gl_FragColor = vec4(mix(centralColor, screen, alpha), 1.0);
- gl_FragColor.rgb = mix(gl_FragColor.rgb, lighten, alpha);
- gl_FragColor.rgb = mix(gl_FragColor.rgb, softLight, params.b);
-
- vec3 satColor = gl_FragColor.rgb * saturateMatrix;
- gl_FragColor.rgb = mix(gl_FragColor.rgb, satColor, params.a);
-
- gl_FragColor.rgb = vec3(gl_FragColor.rgb + vec3(-0.096));
-}
\ No newline at end of file
diff --git a/Live/src/main/res/raw/blackcat.glsl b/Live/src/main/res/raw/blackcat.glsl
deleted file mode 100644
index 36697e41..00000000
--- a/Live/src/main/res/raw/blackcat.glsl
+++ /dev/null
@@ -1,92 +0,0 @@
-#extension GL_OES_EGL_image_external : require
-
-precision highp float;
-
-varying highp vec2 textureCoordinate;
-
-uniform samplerExternalOES inputImageTexture;
-uniform sampler2D curve;
-
-vec3 rgb2hsv(vec3 c)
-{
- vec4 K = vec4(0.0, -1.0 / 3.0, 2.0 / 3.0, -1.0);
- vec4 p = mix(vec4(c.bg, K.wz), vec4(c.gb, K.xy), step(c.b, c.g));
- vec4 q = mix(vec4(p.xyw, c.r), vec4(c.r, p.yzx), step(p.x, c.r));
-
- float d = q.x - min(q.w, q.y);
- float e = 1.0e-10;
- return vec3(abs(q.z + (q.w - q.y) / (6.0 * d + e)), d / (q.x + e), q.x);
-}
-
-vec3 hsv2rgb(vec3 c) {
- vec4 K = vec4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0);
- vec3 p = abs(fract(c.xxx + K.xyz) * 6.0 - K.www);
- return c.z * mix(K.xxx, clamp(p - K.xxx, 0.0, 1.0), c.y);
-}
-
-void main() {
- float GreyVal;
- lowp vec4 textureColor;
- lowp vec4 textureColorOri;
- float xCoordinate = textureCoordinate.x;
- float yCoordinate = textureCoordinate.y;
-
- highp float redCurveValue;
- highp float greenCurveValue;
- highp float blueCurveValue;
- textureColor = texture2D( inputImageTexture, vec2(xCoordinate, yCoordinate));
- // step1 curve
- redCurveValue = texture2D(curve, vec2(textureColor.r, 0.0)).r;
- greenCurveValue = texture2D(curve, vec2(textureColor.g, 0.0)).g;
- blueCurveValue = texture2D(curve, vec2(textureColor.b, 0.0)).b;
-
-
- //textureColor = vec4(redCurveValue, greenCurveValue, blueCurveValue, 1.0);
- vec3 tColor = vec3(redCurveValue, greenCurveValue, blueCurveValue);
- tColor = rgb2hsv(tColor);
-
- tColor.g = tColor.g * 1.2;
-
- float dStrength = 1.0;
- float dSatStrength = 0.3;
-
- float dGap = 0.0;
-
- if( tColor.r >= 0.0 && tColor.r < 0.417)
- {
- tColor.g = tColor.g + (tColor.g * dSatStrength);
- }
- else if( tColor.r > 0.958 && tColor.r <= 1.0)
- {
- tColor.g = tColor.g + (tColor.g * dSatStrength);
- }
- else if( tColor.r >= 0.875 && tColor.r <= 0.958)
- {
- dGap = abs(tColor.r - 0.875);
- dStrength = (dGap / 0.0833);
-
- tColor.g = tColor.g + (tColor.g * dSatStrength * dStrength);
- }
- else if( tColor.r >= 0.0417 && tColor.r <= 0.125)
- {
- dGap = abs(tColor.r - 0.125);
- dStrength = (dGap / 0.0833);
-
- tColor.g = tColor.g + (tColor.g * dSatStrength * dStrength);
- }
-
- tColor = hsv2rgb(tColor);
- tColor = clamp(tColor, 0.0, 1.0);
-
- redCurveValue = texture2D(curve, vec2(tColor.r, 1.0)).r;
- greenCurveValue = texture2D(curve, vec2(tColor.g, 1.0)).r;
- blueCurveValue = texture2D(curve, vec2(tColor.b, 1.0)).r;
-
- redCurveValue = texture2D(curve, vec2(redCurveValue, 1.0)).g;
- greenCurveValue = texture2D(curve, vec2(greenCurveValue, 1.0)).g;
- blueCurveValue = texture2D(curve, vec2(blueCurveValue, 1.0)).g;
-
- textureColor = vec4(redCurveValue, greenCurveValue, blueCurveValue, 1.0);
-
- gl_FragColor = vec4(textureColor.r, textureColor.g, textureColor.b, 1.0);
-}
\ No newline at end of file
diff --git a/Live/src/main/res/raw/brannan.glsl b/Live/src/main/res/raw/brannan.glsl
deleted file mode 100644
index 87c1328c..00000000
--- a/Live/src/main/res/raw/brannan.glsl
+++ /dev/null
@@ -1,73 +0,0 @@
-#extension GL_OES_EGL_image_external : require
-
-precision mediump float;
-
-varying mediump vec2 textureCoordinate;
-
-uniform samplerExternalOES inputImageTexture;
-uniform sampler2D inputImageTexture2; //process
-uniform sampler2D inputImageTexture3; //blowout
-uniform sampler2D inputImageTexture4; //contrast
-uniform sampler2D inputImageTexture5; //luma
-uniform sampler2D inputImageTexture6; //screen
-
-mat3 saturateMatrix = mat3(
- 1.105150, -0.044850,-0.046000,
- -0.088050,1.061950,-0.089200,
- -0.017100,-0.017100,1.132900);
-
-vec3 luma = vec3(.3, .59, .11);
-
-uniform float strength;
-
-void main()
-{
- vec4 originColor = texture2D(inputImageTexture, textureCoordinate);
- vec3 texel = texture2D(inputImageTexture, textureCoordinate).rgb;
-
- vec2 lookup;
- lookup.y = 0.5;
- lookup.x = texel.r;
- texel.r = texture2D(inputImageTexture2, lookup).r;
- lookup.x = texel.g;
- texel.g = texture2D(inputImageTexture2, lookup).g;
- lookup.x = texel.b;
- texel.b = texture2D(inputImageTexture2, lookup).b;
-
- texel = saturateMatrix * texel;
-
- vec2 tc = (2.0 * textureCoordinate) - 1.0;
- float d = dot(tc, tc);
- vec3 sampled;
- lookup.y = 0.5;
- lookup.x = texel.r;
- sampled.r = texture2D(inputImageTexture3, lookup).r;
- lookup.x = texel.g;
- sampled.g = texture2D(inputImageTexture3, lookup).g;
- lookup.x = texel.b;
- sampled.b = texture2D(inputImageTexture3, lookup).b;
- float value = smoothstep(0.0, 1.0, d);
- texel = mix(sampled, texel, value);
-
- lookup.x = texel.r;
- texel.r = texture2D(inputImageTexture4, lookup).r;
- lookup.x = texel.g;
- texel.g = texture2D(inputImageTexture4, lookup).g;
- lookup.x = texel.b;
- texel.b = texture2D(inputImageTexture4, lookup).b;
-
-
- lookup.x = dot(texel, luma);
- texel = mix(texture2D(inputImageTexture5, lookup).rgb, texel, .5);
-
- lookup.x = texel.r;
- texel.r = texture2D(inputImageTexture6, lookup).r;
- lookup.x = texel.g;
- texel.g = texture2D(inputImageTexture6, lookup).g;
- lookup.x = texel.b;
- texel.b = texture2D(inputImageTexture6, lookup).b;
-
- texel = mix(originColor.rgb, texel.rgb, strength);
-
- gl_FragColor = vec4(texel, 1.0);
-}
\ No newline at end of file
diff --git a/Live/src/main/res/raw/brightness.glsl b/Live/src/main/res/raw/brightness.glsl
deleted file mode 100644
index 633683fe..00000000
--- a/Live/src/main/res/raw/brightness.glsl
+++ /dev/null
@@ -1,9 +0,0 @@
-varying highp vec2 textureCoordinate;
-
-uniform sampler2D inputImageTexture;
-uniform lowp float brightness;
-
-void main() {
- lowp vec4 textureColor = texture2D(inputImageTexture, textureCoordinate);
- gl_FragColor = vec4((textureColor.rgb + vec3(brightness)), textureColor.w);
-}
\ No newline at end of file
diff --git a/Live/src/main/res/raw/brooklyn.glsl b/Live/src/main/res/raw/brooklyn.glsl
deleted file mode 100644
index 44951e40..00000000
--- a/Live/src/main/res/raw/brooklyn.glsl
+++ /dev/null
@@ -1,148 +0,0 @@
-#extension GL_OES_EGL_image_external : require
-
-precision mediump float;
-
-varying mediump vec2 textureCoordinate;
-
-uniform samplerExternalOES inputImageTexture;
-uniform sampler2D inputImageTexture2;
-uniform sampler2D inputImageTexture3;
-uniform sampler2D inputImageTexture4;
-
-uniform float strength;
- // gray
-float NCGray(vec4 color)
-{
- float gray = 0.2125 * color.r + 0.7154 * color.g + 0.0721 * color.b;
- return gray;
-}
-
-// tone mapping
-vec4 NCTonemapping(vec4 color)
-{
- vec4 mapped;
- mapped.r = texture2D(inputImageTexture2, vec2(color.r, 0.0)).r;
- mapped.g = texture2D(inputImageTexture2, vec2(color.g, 0.0)).g;
- mapped.b = texture2D(inputImageTexture2, vec2(color.b, 0.0)).b;
- mapped.a = color.a;
-
- return mapped;
-}
-
-// color control
-vec4 NCColorControl(vec4 color, float saturation, float brightness, float contrast)
-{
- float gray = NCGray(color);
-
- color.rgb = vec3(saturation) * color.rgb + vec3(1.0-saturation) * vec3(gray);
- color.r = clamp(color.r, 0.0, 1.0);
- color.g = clamp(color.g, 0.0, 1.0);
- color.b = clamp(color.b, 0.0, 1.0);
-
- color.rgb = vec3(contrast) * (color.rgb - vec3(0.5)) + vec3(0.5);
- color.r = clamp(color.r, 0.0, 1.0);
- color.g = clamp(color.g, 0.0, 1.0);
- color.b = clamp(color.b, 0.0, 1.0);
-
- color.rgb = color.rgb + vec3(brightness);
- color.r = clamp(color.r, 0.0, 1.0);
- color.g = clamp(color.g, 0.0, 1.0);
- color.b = clamp(color.b, 0.0, 1.0);
-
- return color;
-}
-
-// hue adjust
-vec4 NCHueAdjust(vec4 color, float hueAdjust)
-{
- vec3 kRGBToYPrime = vec3(0.299, 0.587, 0.114);
- vec3 kRGBToI = vec3(0.595716, -0.274453, -0.321263);
- vec3 kRGBToQ = vec3(0.211456, -0.522591, 0.31135);
-
- vec3 kYIQToR = vec3(1.0, 0.9563, 0.6210);
- vec3 kYIQToG = vec3(1.0, -0.2721, -0.6474);
- vec3 kYIQToB = vec3(1.0, -1.1070, 1.7046);
-
- float yPrime = dot(color.rgb, kRGBToYPrime);
- float I = dot(color.rgb, kRGBToI);
- float Q = dot(color.rgb, kRGBToQ);
-
- float hue = atan(Q, I);
- float chroma = sqrt (I * I + Q * Q);
-
- hue -= hueAdjust;
-
- Q = chroma * sin (hue);
- I = chroma * cos (hue);
-
- color.r = dot(vec3(yPrime, I, Q), kYIQToR);
- color.g = dot(vec3(yPrime, I, Q), kYIQToG);
- color.b = dot(vec3(yPrime, I, Q), kYIQToB);
-
- return color;
-}
-
-// colorMatrix
-vec4 NCColorMatrix(vec4 color, float red, float green, float blue, float alpha, vec4 bias)
-{
- color = color * vec4(red, green, blue, alpha) + bias;
- return color;
-}
-
-// multiply blend
-vec4 NCMultiplyBlend(vec4 overlay, vec4 base)
-{
- vec4 outputColor;
-
- float a = overlay.a + base.a * (1.0 - overlay.a);
-
- // // normal blend
- // outputColor.r = (base.r * base.a + overlay.r * overlay.a * (1.0 - base.a))/a;
- // outputColor.g = (base.g * base.a + overlay.g * overlay.a * (1.0 - base.a))/a;
- // outputColor.b = (base.b * base.a + overlay.b * overlay.a * (1.0 - base.a))/a;
-
-
- // multiply blend
- outputColor.rgb = ((1.0-base.a) * overlay.rgb * overlay.a + (1.0-overlay.a) * base.rgb * base.a + overlay.a * base.a * overlay.rgb * base.rgb) / a;
-
-
- outputColor.a = a;
-
- return outputColor;
-}
-
-void main()
-{
- vec4 originColor = texture2D(inputImageTexture, textureCoordinate);
- vec4 color = texture2D(inputImageTexture, textureCoordinate);
-
- color.a = 1.0;
-
- // tone mapping
- color.r = texture2D(inputImageTexture2, vec2(color.r, 0.0)).r;
- color.g = texture2D(inputImageTexture2, vec2(color.g, 0.0)).g;
- color.b = texture2D(inputImageTexture2, vec2(color.b, 0.0)).b;
-
- // color control
- color = NCColorControl(color, 0.88, 0.03, 0.85);
-
- // hue adjust
- color = NCHueAdjust(color, -0.0444);
-
- // normal blend
- vec4 bg = vec4(0.5647, 0.1961, 0.0157, 0.14);
- color = NCMultiplyBlend(bg, color);
-
- // normal blend
- vec4 bg2 = texture2D(inputImageTexture3, textureCoordinate);
- bg2.a *= 0.9;
- color = NCMultiplyBlend(bg2, color);
-
- // tone mapping
- color.r = texture2D(inputImageTexture4, vec2(color.r, 0.0)).r;
- color.g = texture2D(inputImageTexture4, vec2(color.g, 0.0)).g;
- color.b = texture2D(inputImageTexture4, vec2(color.b, 0.0)).b;
-
- color.rgb = mix(originColor.rgb, color.rgb, strength);
- gl_FragColor = color;
-}
\ No newline at end of file
diff --git a/Live/src/main/res/raw/calm.glsl b/Live/src/main/res/raw/calm.glsl
deleted file mode 100644
index 57046849..00000000
--- a/Live/src/main/res/raw/calm.glsl
+++ /dev/null
@@ -1,72 +0,0 @@
-#extension GL_OES_EGL_image_external : require
-
-precision highp float;
-
-varying highp vec2 textureCoordinate;
-
-uniform samplerExternalOES inputImageTexture;
-uniform sampler2D grey1Frame;
-uniform sampler2D grey2Frame;
-uniform sampler2D curve;
-
-const mediump vec3 luminanceWeighting = vec3(0.2125, 0.7154, 0.0721);
-
-void main()
-{
- lowp float satura = 0.5;
- float GreyVal;
- lowp vec4 textureColor;
- lowp vec4 textureColorRes;
-
- highp float redCurveValue;
- highp float greenCurveValue;
- highp float blueCurveValue;
-
- vec4 grey1Color;
- vec4 grey2Color;
-
- float xCoordinate = textureCoordinate.x;
- float yCoordinate = textureCoordinate.y;
-
- textureColor = texture2D( inputImageTexture, vec2(xCoordinate, yCoordinate));
- textureColorRes = textureColor;
-
- grey1Color = texture2D(grey1Frame, vec2(xCoordinate, yCoordinate));
- grey2Color = texture2D(grey2Frame, vec2(xCoordinate, yCoordinate));
-
- // step 1. saturation
- lowp float luminance = dot(textureColor.rgb, luminanceWeighting);
- lowp vec3 greyScaleColor = vec3(luminance);
-
- textureColor = vec4(mix(greyScaleColor, textureColor.rgb, satura), textureColor.w);
-
- // step 2. level, blur curve, rgb curve
- redCurveValue = texture2D(curve, vec2(textureColor.r, 0.0)).r;
- redCurveValue = texture2D(curve, vec2(redCurveValue, 1.0/2.0)).r;
-
- greenCurveValue = texture2D(curve, vec2(textureColor.g, 0.0)).g;
- greenCurveValue = texture2D(curve, vec2(greenCurveValue, 1.0/2.0)).g;
-
- blueCurveValue = texture2D(curve, vec2(textureColor.b, 0.0)).b;
- blueCurveValue = texture2D(curve, vec2(blueCurveValue, 1.0/2.0)).b;
- blueCurveValue = texture2D(curve, vec2(blueCurveValue, 1.0/2.0)).g;
-
- lowp vec4 base = vec4(redCurveValue, greenCurveValue, blueCurveValue, 1.0);
-
- redCurveValue = texture2D(curve, vec2(redCurveValue, 1.0)).r;
- greenCurveValue = texture2D(curve, vec2(greenCurveValue, 1.0)).r;
- blueCurveValue = texture2D(curve, vec2(blueCurveValue, 1.0)).r;
- lowp vec4 overlayer = vec4(redCurveValue, greenCurveValue, blueCurveValue, 1.0);
- //gl_FragColor = base * (1.0 - grey1Color.r) + overlayer * grey1Color.r;
- base = (base - overlayer) * (1.0 - grey1Color.r) + overlayer;
-
- redCurveValue = texture2D(curve, vec2(base.r, 1.0)).g;
- greenCurveValue = texture2D(curve, vec2(base.g, 1.0)).g;
- blueCurveValue = texture2D(curve, vec2(base.b, 1.0)).g;
- overlayer = vec4(redCurveValue, greenCurveValue, blueCurveValue, 1.0);
-
- textureColor = (base - overlayer) * (1.0 - grey2Color.r) + overlayer;
- //base * (grey2Color.r) + overlayer * (1.0 - grey2Color.r);
-
- gl_FragColor = vec4(textureColor.r, textureColor.g, textureColor.b, 1.0);
-}
\ No newline at end of file
diff --git a/Live/src/main/res/raw/constrast.glsl b/Live/src/main/res/raw/constrast.glsl
deleted file mode 100644
index eee2d2d0..00000000
--- a/Live/src/main/res/raw/constrast.glsl
+++ /dev/null
@@ -1,9 +0,0 @@
-varying highp vec2 textureCoordinate;
-
-uniform sampler2D inputImageTexture;
-uniform lowp float contrast;
-
-void main() {
- lowp vec4 textureColor = texture2D(inputImageTexture, textureCoordinate);
- gl_FragColor = vec4(((textureColor.rgb - vec3(0.5)) * contrast + vec3(0.5)), textureColor.w);
-}
\ No newline at end of file
diff --git a/Live/src/main/res/raw/cool.glsl b/Live/src/main/res/raw/cool.glsl
deleted file mode 100644
index 8a31bcd0..00000000
--- a/Live/src/main/res/raw/cool.glsl
+++ /dev/null
@@ -1,44 +0,0 @@
-#extension GL_OES_EGL_image_external : require
-
-precision highp float;
-
-varying highp vec2 textureCoordinate;
-
-uniform samplerExternalOES inputImageTexture;
-uniform sampler2D curve;
-
-void main() {
- lowp vec4 textureColor;
- lowp vec4 textureColorOri;
-
- float xCoordinate = textureCoordinate.x;
- float yCoordinate = textureCoordinate.y;
-
- highp float redCurveValue;
- highp float greenCurveValue;
- highp float blueCurveValue;
-
- textureColor = texture2D( inputImageTexture, vec2(xCoordinate, yCoordinate));
- textureColorOri = textureColor;
- // step1 curve
- redCurveValue = texture2D(curve, vec2(textureColor.r, 0.0)).r;
- greenCurveValue = texture2D(curve, vec2(textureColor.g, 0.0)).g;
- blueCurveValue = texture2D(curve, vec2(textureColor.b, 0.0)).b;
- // step2 level
- redCurveValue = texture2D(curve, vec2(redCurveValue, 0.0)).a;
- greenCurveValue = texture2D(curve, vec2(greenCurveValue, 0.0)).a;
- blueCurveValue = texture2D(curve, vec2(blueCurveValue, 0.0)).a;
- // step3 brightness/constrast adjust
- redCurveValue = redCurveValue * 1.25 - 0.12549;
- greenCurveValue = greenCurveValue * 1.25 - 0.12549;
- blueCurveValue = blueCurveValue * 1.25 - 0.12549;
- //redCurveValue = (((redCurveValue) > (1.0)) ? (1.0) : (((redCurveValue) < (0.0)) ? (0.0) : (redCurveValue)));
- //greenCurveValue = (((greenCurveValue) > (1.0)) ? (1.0) : (((greenCurveValue) < (0.0)) ? (0.0) : (greenCurveValue)));
- //blueCurveValue = (((blueCurveValue) > (1.0)) ? (1.0) : (((blueCurveValue) < (0.0)) ? (0.0) : (blueCurveValue)));
- // step4 normal blending with original
- textureColor = vec4(redCurveValue, greenCurveValue, blueCurveValue, 1.0);
- textureColor = (textureColorOri - textureColor) * 0.549 + textureColor;
-
- gl_FragColor = vec4(textureColor.r, textureColor.g, textureColor.b, 1.0);
-}
-
\ No newline at end of file
diff --git a/Live/src/main/res/raw/crayon.glsl b/Live/src/main/res/raw/crayon.glsl
deleted file mode 100644
index b9564b2f..00000000
--- a/Live/src/main/res/raw/crayon.glsl
+++ /dev/null
@@ -1,56 +0,0 @@
-#extension GL_OES_EGL_image_external : require
-
-precision mediump float;
-
-varying highp vec2 textureCoordinate;
-
-uniform samplerExternalOES inputImageTexture;
-uniform vec2 singleStepOffset;
-uniform float strength;
-
-const highp vec3 W = vec3(0.299,0.587,0.114);
-
-const mat3 rgb2yiqMatrix = mat3(
- 0.299, 0.587, 0.114,
- 0.596,-0.275,-0.321,
- 0.212,-0.523, 0.311);
-
-const mat3 yiq2rgbMatrix = mat3(
- 1.0, 0.956, 0.621,
- 1.0,-0.272,-1.703,
- 1.0,-1.106, 0.0);
-
-
-void main()
-{
- vec4 oralColor = texture2D(inputImageTexture, textureCoordinate);
-
- vec3 maxValue = vec3(0.,0.,0.);
-
- for(int i = -2; i<=2; i++)
- {
- for(int j = -2; j<=2; j++)
- {
- vec4 tempColor = texture2D(inputImageTexture, textureCoordinate+singleStepOffset*vec2(i,j));
- maxValue.r = max(maxValue.r,tempColor.r);
- maxValue.g = max(maxValue.g,tempColor.g);
- maxValue.b = max(maxValue.b,tempColor.b);
- }
- }
-
- vec3 textureColor = oralColor.rgb / maxValue;
-
- float gray = dot(textureColor, W);
- float k = 0.223529;
- float alpha = min(gray,k)/k;
-
- textureColor = textureColor * alpha + (1.-alpha)*oralColor.rgb;
-
- vec3 yiqColor = textureColor * rgb2yiqMatrix;
-
- yiqColor.r = max(0.0,min(1.0,pow(gray,strength)));
-
- textureColor = yiqColor * yiq2rgbMatrix;
-
- gl_FragColor = vec4(textureColor, oralColor.w);
-}
\ No newline at end of file
diff --git a/Live/src/main/res/raw/earlybird.glsl b/Live/src/main/res/raw/earlybird.glsl
deleted file mode 100644
index 9162d6b9..00000000
--- a/Live/src/main/res/raw/earlybird.glsl
+++ /dev/null
@@ -1,102 +0,0 @@
-#extension GL_OES_EGL_image_external : require
-
-precision mediump float;
-
-varying mediump vec2 textureCoordinate;
-
-uniform samplerExternalOES inputImageTexture;
-uniform sampler2D inputImageTexture2; //earlyBirdCurves
-uniform sampler2D inputImageTexture3; //earlyBirdOverlay
-uniform sampler2D inputImageTexture4; //vig
-uniform sampler2D inputImageTexture5; //earlyBirdBlowout
-uniform sampler2D inputImageTexture6; //earlyBirdMap
-
-const mat3 saturate = mat3(
- 1.210300,
- -0.089700,
- -0.091000,
- -0.176100,
- 1.123900,
- -0.177400,
- -0.034200,
- -0.034200,
- 1.265800);
-const vec3 rgbPrime = vec3(0.25098, 0.14640522, 0.0);
-const vec3 desaturate = vec3(.3, .59, .11);
-
-void main()
-{
- vec3 texel = texture2D(inputImageTexture, textureCoordinate).rgb;
-
- vec2 lookup;
- lookup.y = 0.5;
-
- lookup.x = texel.r;
- texel.r = texture2D(inputImageTexture2, lookup).r;
-
- lookup.x = texel.g;
- texel.g = texture2D(inputImageTexture2, lookup).g;
-
- lookup.x = texel.b;
- texel.b = texture2D(inputImageTexture2, lookup).b;
-
- float desaturatedColor;
- vec3 result;
- desaturatedColor = dot(desaturate, texel);
-
- lookup.x = desaturatedColor;
- result.r = texture2D(inputImageTexture3, lookup).r;
- lookup.x = desaturatedColor;
- result.g = texture2D(inputImageTexture3, lookup).g;
- lookup.x = desaturatedColor;
- result.b = texture2D(inputImageTexture3, lookup).b;
-
- texel = saturate * mix(texel, result, .5);
-
- vec2 tc = (2.0 * textureCoordinate) - 1.0;
- float d = dot(tc, tc);
-
- vec3 sampled;
- lookup.y = .5;
-
- /*
- lookup.x = texel.r;
- sampled.r = texture2D(inputImageTexture4, lookup).r;
-
- lookup.x = texel.g;
- sampled.g = texture2D(inputImageTexture4, lookup).g;
-
- lookup.x = texel.b;
- sampled.b = texture2D(inputImageTexture4, lookup).b;
-
- float value = smoothstep(0.0, 1.25, pow(d, 1.35)/1.65);
- texel = mix(texel, sampled, value);
- */
-
- //---
- lookup = vec2(d, texel.r);
- texel.r = texture2D(inputImageTexture4, lookup).r;
- lookup.y = texel.g;
- texel.g = texture2D(inputImageTexture4, lookup).g;
- lookup.y = texel.b;
- texel.b = texture2D(inputImageTexture4, lookup).b;
- float value = smoothstep(0.0, 1.25, pow(d, 1.35)/1.65);
-
- //---
- lookup.x = texel.r;
- sampled.r = texture2D(inputImageTexture5, lookup).r;
- lookup.x = texel.g;
- sampled.g = texture2D(inputImageTexture5, lookup).g;
- lookup.x = texel.b;
- sampled.b = texture2D(inputImageTexture5, lookup).b;
- texel = mix(sampled, texel, value);
-
- lookup.x = texel.r;
- texel.r = texture2D(inputImageTexture6, lookup).r;
- lookup.x = texel.g;
- texel.g = texture2D(inputImageTexture6, lookup).g;
- lookup.x = texel.b;
- texel.b = texture2D(inputImageTexture6, lookup).b;
-
- gl_FragColor = vec4(texel, 1.0);
-}
diff --git a/Live/src/main/res/raw/emerald.glsl b/Live/src/main/res/raw/emerald.glsl
deleted file mode 100644
index 8f54c087..00000000
--- a/Live/src/main/res/raw/emerald.glsl
+++ /dev/null
@@ -1,89 +0,0 @@
-#extension GL_OES_EGL_image_external : require
-
-precision highp float;
-
-varying highp vec2 textureCoordinate;
-
-uniform samplerExternalOES inputImageTexture;
-uniform sampler2D curve;
-
-vec3 RGBtoHSL(vec3 c) {
- vec4 K = vec4(0.0, -1.0 / 3.0, 2.0 / 3.0, -1.0);
- vec4 p = mix(vec4(c.bg, K.wz), vec4(c.gb, K.xy), step(c.b, c.g));
- vec4 q = mix(vec4(p.xyw, c.r), vec4(c.r, p.yzx), step(p.x, c.r));
-
- float d = q.x - min(q.w, q.y);
- float e = 1.0e-10;
- return vec3(abs(q.z + (q.w - q.y) / (6.0 * d + e)), d / (q.x + e), q.x);
-}
-
-vec3 HSLtoRGB(vec3 c) {
- vec4 K = vec4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0);
- vec3 p = abs(fract(c.xxx + K.xyz) * 6.0 - K.www);
- return c.z * mix(K.xxx, clamp(p - K.xxx, 0.0, 1.0), c.y);
-}
-
-void main() {
- float GreyVal;
- highp vec4 textureColor;
- float xCoordinate = textureCoordinate.x;
- float yCoordinate = textureCoordinate.y;
-
- highp float redCurveValue;
- highp float greenCurveValue;
- highp float blueCurveValue;
-
- textureColor = texture2D( inputImageTexture, vec2(xCoordinate, yCoordinate));
-
- // step1 curve
- redCurveValue = texture2D(curve, vec2(textureColor.r, 0.0)).r;
- greenCurveValue = texture2D(curve, vec2(textureColor.g, 0.0)).g;
- blueCurveValue = texture2D(curve, vec2(textureColor.b, 0.0)).b;
- vec3 tColor = vec3(redCurveValue, greenCurveValue, blueCurveValue);
- tColor = RGBtoHSL(tColor);
- tColor = clamp(tColor, 0.0, 1.0);
-
- tColor.g = tColor.g * 1.5;
-
- float dStrength = 1.0;
- float dSatStrength = 0.15;
- float dHueStrength = 0.08;
-
- float dGap = 0.0;
-
- if( tColor.r >= 0.625 && tColor.r <= 0.708)
- {
- tColor.r = tColor.r - (tColor.r * dHueStrength);
- tColor.g = tColor.g + (tColor.g * dSatStrength);
- }
- else if( tColor.r >= 0.542 && tColor.r < 0.625)
- {
- dGap = abs(tColor.r - 0.542);
- dStrength = (dGap / 0.0833);
-
- tColor.r = tColor.r + (tColor.r * dHueStrength * dStrength);
- tColor.g = tColor.g + (tColor.g * dSatStrength * dStrength);
- }
- else if( tColor.r > 0.708 && tColor.r <= 0.792)
- {
- dGap = abs(tColor.r - 0.792);
- dStrength = (dGap / 0.0833);
-
- tColor.r = tColor.r + (tColor.r * dHueStrength * dStrength);
- tColor.g = tColor.g + (tColor.g * dSatStrength * dStrength);
- }
-
- tColor = HSLtoRGB(tColor);
- tColor = clamp(tColor, 0.0, 1.0);
-
- redCurveValue = texture2D(curve, vec2(tColor.r, 1.0)).r;
- greenCurveValue = texture2D(curve, vec2(tColor.g, 1.0)).r;
- blueCurveValue = texture2D(curve, vec2(tColor.b, 1.0)).r;
-
- redCurveValue = texture2D(curve, vec2(redCurveValue, 1.0)).g;
- greenCurveValue = texture2D(curve, vec2(greenCurveValue, 1.0)).g;
- blueCurveValue = texture2D(curve, vec2(blueCurveValue, 1.0)).g;
-
- textureColor = vec4(redCurveValue, greenCurveValue, blueCurveValue, 1.0);
- gl_FragColor = vec4(textureColor.r, textureColor.g, textureColor.b, 1.0);
-}
diff --git a/Live/src/main/res/raw/evergreen.glsl b/Live/src/main/res/raw/evergreen.glsl
deleted file mode 100644
index 02f30463..00000000
--- a/Live/src/main/res/raw/evergreen.glsl
+++ /dev/null
@@ -1,84 +0,0 @@
-#extension GL_OES_EGL_image_external : require
-
-precision highp float;
-
-varying highp vec2 textureCoordinate;
-
-uniform samplerExternalOES inputImageTexture;
-uniform sampler2D curve;
-
-vec3 RGBtoHSL(vec3 c)
-{
- vec4 K = vec4(0.0, -1.0 / 3.0, 2.0 / 3.0, -1.0);
- vec4 p = mix(vec4(c.bg, K.wz), vec4(c.gb, K.xy), step(c.b, c.g));
- vec4 q = mix(vec4(p.xyw, c.r), vec4(c.r, p.yzx), step(p.x, c.r));
-
- float d = q.x - min(q.w, q.y);
- float e = 1.0e-10;
- return vec3(abs(q.z + (q.w - q.y) / (6.0 * d + e)), d / (q.x + e), q.x);
-}
-
-vec3 HSLtoRGB(vec3 c)
-{
- vec4 K = vec4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0);
- vec3 p = abs(fract(c.xxx + K.xyz) * 6.0 - K.www);
- return c.z * mix(K.xxx, clamp(p - K.xxx, 0.0, 1.0), c.y);
-}
-
-void main()
-{
- float GreyVal;
- lowp vec4 textureColor;
- float xCoordinate = textureCoordinate.x;
- float yCoordinate = textureCoordinate.y;
-
- highp float redCurveValue;
- highp float greenCurveValue;
- highp float blueCurveValue;
-
- textureColor = texture2D( inputImageTexture, vec2(xCoordinate, yCoordinate));
-
- vec3 tColor = vec3(textureColor.r, textureColor.g, textureColor.b);
-
- tColor = RGBtoHSL(tColor);
- tColor = clamp(tColor, 0.0, 1.0);
-
-
- tColor.g = tColor.g * 1.3;
-
- float dStrength = 1.0;
- float dSatStrength = 0.5;
- float dGap = 0.0;
-
-
- if( tColor.r >= 0.292 && tColor.r <= 0.375)
- {
- tColor.g = tColor.g + (tColor.g * dSatStrength);
- }
- else if( tColor.r >= 0.208 && tColor.r < 0.292)
- {
- dGap = abs(tColor.r - 0.208);
- dStrength = (dGap / 0.0833);
-
- tColor.g = tColor.g + (tColor.g * dSatStrength * dStrength);
- }
- else if( tColor.r > 0.375 && tColor.r <= 0.458)
- {
- dGap = abs(tColor.r - 0.458);
- dStrength = (dGap / 0.0833);
-
- tColor.g = tColor.g + (tColor.g * dSatStrength * dStrength);
- }
- tColor = HSLtoRGB(tColor);
- tColor = clamp(tColor, 0.0, 1.0);
-
- redCurveValue = texture2D(curve, vec2(tColor.r, 0.0)).b;
- greenCurveValue = texture2D(curve, vec2(tColor.g, 0.0)).b;
- blueCurveValue = texture2D(curve, vec2(tColor.b, 0.0)).b;
- redCurveValue = texture2D(curve, vec2(redCurveValue, 0.0)).r;
- blueCurveValue = texture2D(curve, vec2(blueCurveValue, 0.0)).g;
-
- textureColor = vec4(redCurveValue, greenCurveValue, blueCurveValue, 1.0);
-
- gl_FragColor = vec4(textureColor.r, textureColor.g, textureColor.b, 1.0);
-}
\ No newline at end of file
diff --git a/Live/src/main/res/raw/exposure.glsl b/Live/src/main/res/raw/exposure.glsl
deleted file mode 100644
index 88cebd52..00000000
--- a/Live/src/main/res/raw/exposure.glsl
+++ /dev/null
@@ -1,9 +0,0 @@
-varying highp vec2 textureCoordinate;
-
-uniform sampler2D inputImageTexture;
-uniform highp float exposure;
-
-void main() {
- highp vec4 textureColor = texture2D(inputImageTexture, textureCoordinate);
- gl_FragColor = vec4(textureColor.rgb * pow(2.0, exposure), textureColor.w);
-}
\ No newline at end of file
diff --git a/Live/src/main/res/raw/fragment.glsl b/Live/src/main/res/raw/fragment.glsl
deleted file mode 100644
index 2c6ed480..00000000
--- a/Live/src/main/res/raw/fragment.glsl
+++ /dev/null
@@ -1,11 +0,0 @@
-#extension GL_OES_EGL_image_external : require
-
-precision mediump float;
-
-varying mediump vec2 textureCoordinate;
-
-uniform samplerExternalOES inputImageTexture;
-
-void main() {
- gl_FragColor = texture2D(inputImageTexture, textureCoordinate);
-}
\ No newline at end of file
diff --git a/Live/src/main/res/raw/freud.glsl b/Live/src/main/res/raw/freud.glsl
deleted file mode 100644
index bebf10c4..00000000
--- a/Live/src/main/res/raw/freud.glsl
+++ /dev/null
@@ -1,172 +0,0 @@
-#extension GL_OES_EGL_image_external : require
-
-precision highp float;
-varying mediump vec2 textureCoordinate;
-
-uniform samplerExternalOES inputImageTexture;
-uniform sampler2D inputImageTexture2;
-
-uniform float inputImageTextureHeight;
-uniform float inputImageTextureWidth;
-
-float texture2Size = 1024.0;
-
-uniform float strength;
-
-// gray
-float NCGray(vec4 color)
-{
- float gray = 0.2125 * color.r + 0.7154 * color.g + 0.0721 * color.b;
- return gray;
-}
-
-// tone mapping
-vec4 NCTonemapping(vec4 color)
-{
- vec4 mapped;
- mapped.r = texture2D(inputImageTexture2, vec2(color.r, 0.0)).r;
- mapped.g = texture2D(inputImageTexture2, vec2(color.g, 0.0)).g;
- mapped.b = texture2D(inputImageTexture2, vec2(color.b, 0.0)).b;
- mapped.a = color.a;
- return mapped;
-}
-
-// color control
-vec4 NCColorControl(vec4 color, float saturation, float brightness, float contrast)
-{
- float gray = NCGray(color);
-
- color.rgb = vec3(saturation) * color.rgb + vec3(1.0-saturation) * vec3(gray);
- color.r = clamp(color.r, 0.0, 1.0);
- color.g = clamp(color.g, 0.0, 1.0);
- color.b = clamp(color.b, 0.0, 1.0);
-
- color.rgb = vec3(contrast) * (color.rgb - vec3(0.5)) + vec3(0.5);
- color.r = clamp(color.r, 0.0, 1.0);
- color.g = clamp(color.g, 0.0, 1.0);
- color.b = clamp(color.b, 0.0, 1.0);
-
- color.rgb = color.rgb + vec3(brightness);
- color.r = clamp(color.r, 0.0, 1.0);
- color.g = clamp(color.g, 0.0, 1.0);
- color.b = clamp(color.b, 0.0, 1.0);
-
- return color;
-}
-
-// hue adjust
-vec4 NCHueAdjust(vec4 color, float hueAdjust)
-{
- vec3 kRGBToYPrime = vec3(0.299, 0.587, 0.114);
- vec3 kRGBToI = vec3(0.595716, -0.274453, -0.321263);
- vec3 kRGBToQ = vec3(0.211456, -0.522591, 0.31135);
-
- vec3 kYIQToR = vec3(1.0, 0.9563, 0.6210);
- vec3 kYIQToG = vec3(1.0, -0.2721, -0.6474);
- vec3 kYIQToB = vec3(1.0, -1.1070, 1.7046);
-
- float yPrime = dot(color.rgb, kRGBToYPrime);
- float I = dot(color.rgb, kRGBToI);
- float Q = dot(color.rgb, kRGBToQ);
-
- float hue = atan(Q, I);
- float chroma = sqrt (I * I + Q * Q);
-
- hue -= hueAdjust;
-
- Q = chroma * sin (hue);
- I = chroma * cos (hue);
-
- color.r = dot(vec3(yPrime, I, Q), kYIQToR);
- color.g = dot(vec3(yPrime, I, Q), kYIQToG);
- color.b = dot(vec3(yPrime, I, Q), kYIQToB);
-
- return color;
-}
-
-// colorMatrix
-vec4 NCColorMatrix(vec4 color, float red, float green, float blue, float alpha, vec4 bias)
-{
- color = color * vec4(red, green, blue, alpha) + bias;
-
- return color;
-}
-
-// multiply blend
-vec4 NCMultiplyBlend(vec4 overlay, vec4 base)
-{
- vec4 outputColor;
-
- float a = overlay.a + base.a * (1.0 - overlay.a);
-
- // // normal blend
- // outputColor.r = (base.r * base.a + overlay.r * overlay.a * (1.0 - base.a))/a;
- // outputColor.g = (base.g * base.a + overlay.g * overlay.a * (1.0 - base.a))/a;
- // outputColor.b = (base.b * base.a + overlay.b * overlay.a * (1.0 - base.a))/a;
-
-
- // multiply blend
- outputColor.rgb = ((1.0-base.a) * overlay.rgb * overlay.a + (1.0-overlay.a) * base.rgb * base.a + overlay.a * base.a * overlay.rgb * base.rgb) / a;
-
-
- outputColor.a = a;
-
- return outputColor;
-}
-
-// xy should be a integer position (e.g. pixel position on the screen)
-// similar to a texture lookup but is only ALU
-float PseudoRandom(vec2 co)
-{
- // return fract(sin(dot(co.xy ,vec2(12.9898,78.233))) * 43758.5453);
- mediump float a = 12.9898;
- mediump float b = 78.233;
- mediump float c = 43758.5453;
- mediump float dt= dot(co.xy ,vec2(a,b));
- mediump float sn= mod(dt,3.14);
- return fract(sin(sn) * c);
-}
-
-void main()
-{
- vec4 originColor = texture2D(inputImageTexture, textureCoordinate);
- vec4 color = texture2D(inputImageTexture, textureCoordinate);
-
- color.a = 1.0;
-
- // color control
-// color = NCColorControl(color, 0.6, -0.06, 0.75);
- color = NCColorControl(color, 0.5, 0.1, 0.9);
-
- // rand
- float x = textureCoordinate.x*inputImageTextureWidth/texture2Size;
- float y = textureCoordinate.y*inputImageTextureHeight/texture2Size;
-
- vec4 rd = texture2D(inputImageTexture2, vec2( fract(x), fract(y)));
-// vec4 rd = texture2D(inputImageTexture2, textureCoordinate);
-// float rand_number1 = PseudoRandom(textureCoordinate.xy);
-// float rand_number2 = PseudoRandom(textureCoordinate.yx);
-// float rand_number3 = PseudoRandom(vec2(rand_number1, rand_number2));
-// float rand_number4 = PseudoRandom(vec2(rand_number2, rand_number1));
-// float rand_number5 = PseudoRandom(vec2(rand_number3, rand_number4));
-
-// vec4 rd = vec4(rand_number1, rand_number3, rand_number5, 1.0);
-
-// if(rand_number4>0.2)
-// rd = vec4(1.0);
-
- // rand color control
-// rd = NCColorControl(rd, 0.65, 0.1, 0.7);
- rd = NCColorControl(rd, 1.0, 0.4, 1.2);
-
- // normal blend
-// rd.a *= 1.0;
- color = NCMultiplyBlend(rd, color);
-
- // color matrix
-// color = NCColorMatrix(color, 1.0, 1.0, 1.0, 1.0, vec4(-0.1, -0.1, -0.1, 0));
- color = NCColorMatrix(color, 1.0, 1.0, 1.0, 1.0, vec4(-0.15, -0.15, -0.15, 0));
-
- color.rgb = mix(originColor.rgb, color.rgb, strength);
- gl_FragColor = color;
-}
\ No newline at end of file
diff --git a/Live/src/main/res/raw/healthy.glsl b/Live/src/main/res/raw/healthy.glsl
deleted file mode 100644
index 47b89fbd..00000000
--- a/Live/src/main/res/raw/healthy.glsl
+++ /dev/null
@@ -1,141 +0,0 @@
-#extension GL_OES_EGL_image_external : require
-
-precision mediump float;
-
-uniform samplerExternalOES inputImageTexture;
-uniform sampler2D curve;
-uniform sampler2D mask;
-
-uniform float texelWidthOffset ;
-
-uniform float texelHeightOffset;
-
-varying mediump vec2 textureCoordinate;
-
-vec4 level0c(vec4 color, sampler2D sampler)
-{
- color.r = texture2D(sampler, vec2(color.r, 0.)).r;
- color.g = texture2D(sampler, vec2(color.g, 0.)).r;
- color.b = texture2D(sampler, vec2(color.b, 0.)).r;
- return color;
-}
-
-vec4 level1c(vec4 color, sampler2D sampler)
-{
- color.r = texture2D(sampler, vec2(color.r, 0.)).g;
- color.g = texture2D(sampler, vec2(color.g, 0.)).g;
- color.b = texture2D(sampler, vec2(color.b, 0.)).g;
- return color;
-}
-
-vec4 level2c(vec4 color, sampler2D sampler)
-{
- color.r = texture2D(sampler, vec2(color.r,0.)).b;
- color.g = texture2D(sampler, vec2(color.g,0.)).b;
- color.b = texture2D(sampler, vec2(color.b,0.)).b;
- return color;
-}
-
-vec3 rgb2hsv(vec3 c)
-{
- vec4 K = vec4(0.0, -1.0 / 3.0, 2.0 / 3.0, -1.0);
- vec4 p = mix(vec4(c.bg, K.wz), vec4(c.gb, K.xy), step(c.b, c.g));
- vec4 q = mix(vec4(p.xyw, c.r), vec4(c.r, p.yzx), step(p.x, c.r));
-
- float d = q.x - min(q.w, q.y);
- float e = 1.0e-10;
- return vec3(abs(q.z + (q.w - q.y) / (6.0 * d + e)), d / (q.x + e), q.x);
-}
-
-vec3 hsv2rgb(vec3 c)
-{
- vec4 K = vec4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0);
- vec3 p = abs(fract(c.xxx + K.xyz) * 6.0 - K.www);
- return c.z * mix(K.xxx, clamp(p - K.xxx, 0.0, 1.0), c.y);
-}
-
-vec4 normal(vec4 c1, vec4 c2, float alpha)
-{
- return (c2-c1) * alpha + c1;
-}
-
-vec4 multiply(vec4 c1, vec4 c2)
-{
- return c1 * c2 * 1.01;
-}
-
-vec4 overlay(vec4 c1, vec4 c2)
-{
- vec4 color = vec4(0.,0.,0.,1.);
-
- color.r = c1.r < 0.5 ? 2.0*c1.r*c2.r : 1.0 - 2.0*(1.0-c1.r)*(1.0-c2.r);
- color.g = c1.g < 0.5 ? 2.0*c1.g*c2.g : 1.0 - 2.0*(1.0-c1.g)*(1.0-c2.g);
- color.b = c1.b < 0.5 ? 2.0*c1.b*c2.b : 1.0 - 2.0*(1.0-c1.b)*(1.0-c2.b);
-
- return color;
-}
-
-vec4 screen(vec4 c1, vec4 c2)
-{
- return vec4(1.) - ((vec4(1.) - c1) * (vec4(1.) - c2));
-}
-
-void main()
-{
- // iOS ImageLiveFilter adjustment
- // begin
-
- vec4 textureColor;
-
- vec4 t0 = texture2D(mask, vec2(textureCoordinate.x, textureCoordinate.y));
-
- // naver skin
- vec4 c2 = texture2D(inputImageTexture, textureCoordinate);
- vec4 c5 = c2;
-
- // healthy
- vec3 hsv = rgb2hsv(c5.rgb);
- lowp float h = hsv.x;
- lowp float s = hsv.y;
- lowp float v = hsv.z;
-
- lowp float cF = 0.;
- // color strength
- lowp float cG = 0.;
- // color gap;
- lowp float sF = 0.06;
- // saturation strength;
-
- if(h >= 0.125 && h <= 0.208)
- {
- // 45 to 75
- s = s - (s * sF);
- }
- else if (h >= 0.208 && h < 0.292)
- {
- // 75 to 105
- cG = abs(h - 0.208);
- cF = (cG / 0.0833);
- s = s - (s * sF * cF);
- }
- else if (h > 0.042 && h <= 0.125)
- {
- // 15 to 45
- cG = abs(h - 0.125);
- cF = (cG / 0.0833);
- s = s - (s * sF * cF);
- }
- hsv.y = s;
-
- vec4 c6 = vec4(hsv2rgb(hsv),1.);
-
- c6 = normal(c6, screen (c6, c6), 0.275); // screen 70./255.
- c6 = normal(c6, overlay (c6, vec4(1., 0.61176, 0.25098, 1.)), 0.04); // overlay 10./255.
-
- c6 = normal(c6, multiply(c6, t0), 0.262); // multiply 67./255.
-
- c6 = level1c(level0c(c6,curve),curve);
-
- gl_FragColor = c6;
- // end
-}
\ No newline at end of file
diff --git a/Live/src/main/res/raw/hefe.glsl b/Live/src/main/res/raw/hefe.glsl
deleted file mode 100644
index 77983ef7..00000000
--- a/Live/src/main/res/raw/hefe.glsl
+++ /dev/null
@@ -1,46 +0,0 @@
-#extension GL_OES_EGL_image_external : require
-
-precision mediump float;
-
-varying mediump vec2 textureCoordinate;
-
-uniform samplerExternalOES inputImageTexture;
-uniform sampler2D inputImageTexture2; //edgeBurn
-uniform sampler2D inputImageTexture3; //hefeMap
-uniform sampler2D inputImageTexture4; //hefeGradientMap
-uniform sampler2D inputImageTexture5; //hefeSoftLight
-uniform sampler2D inputImageTexture6; //hefeMetal
-
-uniform float strength;
-
-void main()
-{
- vec4 originColor = texture2D(inputImageTexture, textureCoordinate);
- vec3 texel = texture2D(inputImageTexture, textureCoordinate).rgb;
- vec3 edge = texture2D(inputImageTexture2, textureCoordinate).rgb;
- texel = texel * edge;
-
- texel = vec3(
- texture2D(inputImageTexture3, vec2(texel.r, .16666)).r,
- texture2D(inputImageTexture3, vec2(texel.g, .5)).g,
- texture2D(inputImageTexture3, vec2(texel.b, .83333)).b);
-
- vec3 luma = vec3(.30, .59, .11);
- vec3 gradSample = texture2D(inputImageTexture4, vec2(dot(luma, texel), .5)).rgb;
- vec3 final = vec3(
- texture2D(inputImageTexture5, vec2(gradSample.r, texel.r)).r,
- texture2D(inputImageTexture5, vec2(gradSample.g, texel.g)).g,
- texture2D(inputImageTexture5, vec2(gradSample.b, texel.b)).b
- );
-
- vec3 metal = texture2D(inputImageTexture6, textureCoordinate).rgb;
- vec3 metaled = vec3(
- texture2D(inputImageTexture5, vec2(metal.r, texel.r)).r,
- texture2D(inputImageTexture5, vec2(metal.g, texel.g)).g,
- texture2D(inputImageTexture5, vec2(metal.b, texel.b)).b
- );
-
- metaled.rgb = mix(originColor.rgb, metaled.rgb, strength);
-
- gl_FragColor = vec4(metaled, 1.0);
-}
\ No newline at end of file
diff --git a/Live/src/main/res/raw/hudson.glsl b/Live/src/main/res/raw/hudson.glsl
deleted file mode 100644
index 76f5d798..00000000
--- a/Live/src/main/res/raw/hudson.glsl
+++ /dev/null
@@ -1,35 +0,0 @@
-#extension GL_OES_EGL_image_external : require
-
-precision mediump float;
-
-varying mediump vec2 textureCoordinate;
-
-uniform samplerExternalOES inputImageTexture;
-uniform sampler2D inputImageTexture2; //blowout;
-uniform sampler2D inputImageTexture3; //overlay;
-uniform sampler2D inputImageTexture4; //map
-
-uniform float strength;
-
-void main()
-{
- vec4 originColor = texture2D(inputImageTexture, textureCoordinate);
-
- vec4 texel = texture2D(inputImageTexture, textureCoordinate);
-
- vec3 bbTexel = texture2D(inputImageTexture2, textureCoordinate).rgb;
-
- texel.r = texture2D(inputImageTexture3, vec2(bbTexel.r, texel.r)).r;
- texel.g = texture2D(inputImageTexture3, vec2(bbTexel.g, texel.g)).g;
- texel.b = texture2D(inputImageTexture3, vec2(bbTexel.b, texel.b)).b;
-
- vec4 mapped;
- mapped.r = texture2D(inputImageTexture4, vec2(texel.r, .16666)).r;
- mapped.g = texture2D(inputImageTexture4, vec2(texel.g, .5)).g;
- mapped.b = texture2D(inputImageTexture4, vec2(texel.b, .83333)).b;
- mapped.a = 1.0;
-
- mapped.rgb = mix(originColor.rgb, mapped.rgb, strength);
-
- gl_FragColor = mapped;
-}
\ No newline at end of file
diff --git a/Live/src/main/res/raw/hue.glsl b/Live/src/main/res/raw/hue.glsl
deleted file mode 100644
index 894ae0f8..00000000
--- a/Live/src/main/res/raw/hue.glsl
+++ /dev/null
@@ -1,43 +0,0 @@
-precision highp float;
-
-varying highp vec2 textureCoordinate;
-
-uniform sampler2D inputImageTexture;
-uniform mediump float hueAdjust;
-const highp vec4 kRGBToYPrime = vec4 (0.299, 0.587, 0.114, 0.0);
-const highp vec4 kRGBToI = vec4 (0.595716, -0.274453, -0.321263, 0.0);
-const highp vec4 kRGBToQ = vec4 (0.211456, -0.522591, 0.31135, 0.0);
-
-const highp vec4 kYIQToR = vec4 (1.0, 0.9563, 0.6210, 0.0);
-const highp vec4 kYIQToG = vec4 (1.0, -0.2721, -0.6474, 0.0);
-const highp vec4 kYIQToB = vec4 (1.0, -1.1070, 1.7046, 0.0);
-
-void main () {
- // Sample the input pixel
- highp vec4 color = texture2D(inputImageTexture, textureCoordinate);
-
- // Convert to YIQ
- highp float YPrime = dot (color, kRGBToYPrime);
- highp float I = dot (color, kRGBToI);
- highp float Q = dot (color, kRGBToQ);
-
- // Calculate the hue and chroma
- highp float hue = atan (Q, I);
- highp float chroma = sqrt (I * I + Q * Q);
-
- // Make the user's adjustments
- hue += (-hueAdjust); //why negative rotation?
-
- // Convert back to YIQ
- Q = chroma * sin (hue);
- I = chroma * cos (hue);
-
- // Convert back to RGB
- highp vec4 yIQ = vec4 (YPrime, I, Q, 0.0);
- color.r = dot (yIQ, kYIQToR);
- color.g = dot (yIQ, kYIQToG);
- color.b = dot (yIQ, kYIQToB);
-
- // Save the result
- gl_FragColor = color;
-}
\ No newline at end of file
diff --git a/Live/src/main/res/raw/inkwell.glsl b/Live/src/main/res/raw/inkwell.glsl
deleted file mode 100644
index d1aef96e..00000000
--- a/Live/src/main/res/raw/inkwell.glsl
+++ /dev/null
@@ -1,16 +0,0 @@
-#extension GL_OES_EGL_image_external : require
-
-precision mediump float;
-
-varying mediump vec2 textureCoordinate;
-
-uniform samplerExternalOES inputImageTexture;
-uniform sampler2D inputImageTexture2;
-
-void main()
-{
- vec3 texel = texture2D(inputImageTexture, textureCoordinate).rgb;
- texel = vec3(dot(vec3(0.3, 0.6, 0.1), texel));
- texel = vec3(texture2D(inputImageTexture2, vec2(texel.r, .16666)).r);
- gl_FragColor = vec4(texel, 1.0);
-}
\ No newline at end of file
diff --git a/Live/src/main/res/raw/kevin_new.glsl b/Live/src/main/res/raw/kevin_new.glsl
deleted file mode 100644
index bfcd7f08..00000000
--- a/Live/src/main/res/raw/kevin_new.glsl
+++ /dev/null
@@ -1,26 +0,0 @@
-#extension GL_OES_EGL_image_external : require
-
-precision mediump float;
-
-varying mediump vec2 textureCoordinate;
-
-uniform samplerExternalOES inputImageTexture;
-uniform sampler2D inputImageTexture2;
-
-void main()
-{
- vec3 texel = texture2D(inputImageTexture, textureCoordinate).rgb;
- vec2 lookup;
- lookup.y = .5;
-
- lookup.x = texel.r;
- texel.r = texture2D(inputImageTexture2, lookup).r;
-
- lookup.x = texel.g;
- texel.g = texture2D(inputImageTexture2, lookup).g;
-
- lookup.x = texel.b;
- texel.b = texture2D(inputImageTexture2, lookup).b;
-
- gl_FragColor = vec4(texel, 1.0);
-}
diff --git a/Live/src/main/res/raw/latte.glsl b/Live/src/main/res/raw/latte.glsl
deleted file mode 100644
index e1f335eb..00000000
--- a/Live/src/main/res/raw/latte.glsl
+++ /dev/null
@@ -1,163 +0,0 @@
-#extension GL_OES_EGL_image_external : require
-
-precision highp float;
-
-varying highp vec2 textureCoordinate;
-
-uniform samplerExternalOES inputImageTexture;
-uniform sampler2D curve;
-
-vec3 rgb2hsv(vec3 c)
-{
- vec4 K = vec4(0.0, -1.0 / 3.0, 2.0 / 3.0, -1.0);
- vec4 p = mix(vec4(c.bg, K.wz), vec4(c.gb, K.xy), step(c.b, c.g));
- vec4 q = mix(vec4(p.xyw, c.r), vec4(c.r, p.yzx), step(p.x, c.r));
-
- float d = q.x - min(q.w, q.y);
- float e = 1.0e-10;
- return vec3(abs(q.z + (q.w - q.y) / (6.0 * d + e)), d / (q.x + e), q.x);
-}
-
-vec3 hsv2rgb(vec3 c)
-{
- vec4 K = vec4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0);
- vec3 p = abs(fract(c.xxx + K.xyz) * 6.0 - K.www);
- return c.z * mix(K.xxx, clamp(p - K.xxx, 0.0, 1.0), c.y);
-}
-
-void main()
-{
- float GreyVal;
- lowp vec4 textureColor;
- lowp vec4 textureColorOri;
- float xCoordinate = textureCoordinate.x;
- float yCoordinate = textureCoordinate.y;
-
- highp float redCurveValue;
- highp float greenCurveValue;
- highp float blueCurveValue;
-
- textureColor = texture2D( inputImageTexture, vec2(xCoordinate, yCoordinate));
- mediump vec4 base = textureColor;
- mediump vec4 overlay = vec4(0.792, 0.58, 0.372, 1.0);
-
- // step1 overlay blending
- mediump float ra;
- if (base.r < 0.5)
- {
- ra = overlay.r * base.r * 2.0;
- }
- else
- {
- ra = 1.0 - ((1.0 - base.r) * (1.0 - overlay.r) * 2.0);
- }
-
- mediump float ga;
- if (base.g < 0.5)
- {
- ga = overlay.g * base.g * 2.0;
- }
- else
- {
- ga = 1.0 - ((1.0 - base.g) * (1.0 - overlay.g) * 2.0);
- }
-
- mediump float ba;
- if (base.b < 0.5)
- {
- ba = overlay.b * base.b * 2.0;
- }
- else
- {
- ba = 1.0 - ((1.0 - base.b) * (1.0 - overlay.b) * 2.0);
- }
-
- textureColor = vec4(ra, ga, ba, 1.0);
- textureColor = (textureColor - base) * 0.3 + base;
-
- redCurveValue = texture2D(curve, vec2(textureColor.r, 0.0)).r;
- greenCurveValue = texture2D(curve, vec2(textureColor.g, 0.0)).g;
- blueCurveValue = texture2D(curve, vec2(textureColor.b, 0.0)).b;
-
- redCurveValue = texture2D(curve, vec2(redCurveValue, 1.0)).g;
- greenCurveValue = texture2D(curve, vec2(greenCurveValue, 1.0)).g;
- blueCurveValue = texture2D(curve, vec2(blueCurveValue, 1.0)).g;
-
-
- vec3 tColor = vec3(redCurveValue, greenCurveValue, blueCurveValue);
- tColor = rgb2hsv(tColor);
-
- tColor.g = tColor.g * 0.6;
-
- float dStrength = 1.0;
- float dSatStrength = 0.2;
-
- float dGap = 0.0;
-
- if( tColor.r >= 0.0 && tColor.r < 0.417)
- {
- tColor.g = tColor.g + (tColor.g * dSatStrength);
- }
- else if( tColor.r > 0.958 && tColor.r <= 1.0)
- {
- tColor.g = tColor.g + (tColor.g * dSatStrength);
- }
- else if( tColor.r >= 0.875 && tColor.r <= 0.958)
- {
- dGap = abs(tColor.r - 0.875);
- dStrength = (dGap / 0.0833);
-
- tColor.g = tColor.g + (tColor.g * dSatStrength * dStrength);
- }
- else if( tColor.r >= 0.0417 && tColor.r <= 0.125)
- {
- dGap = abs(tColor.r - 0.125);
- dStrength = (dGap / 0.0833);
-
- tColor.g = tColor.g + (tColor.g * dSatStrength * dStrength);
- }
-
-
- tColor = hsv2rgb(tColor);
- tColor = clamp(tColor, 0.0, 1.0);
-
- redCurveValue = texture2D(curve, vec2(tColor.r, 1.0)).r;
- greenCurveValue = texture2D(curve, vec2(tColor.g, 1.0)).r;
- blueCurveValue = texture2D(curve, vec2(tColor.b, 1.0)).r;
-
- base = vec4(redCurveValue, greenCurveValue, blueCurveValue, 1.0);
- overlay = vec4(0.792, 0.494, 0.372, 1.0);
-
- // step5 overlay blending
- if (base.r < 0.5)
- {
- ra = overlay.r * base.r * 2.0;
- }
- else
- {
- ra = 1.0 - ((1.0 - base.r) * (1.0 - overlay.r) * 2.0);
- }
-
- if (base.g < 0.5)
- {
- ga = overlay.g * base.g * 2.0;
- }
- else
- {
- ga = 1.0 - ((1.0 - base.g) * (1.0 - overlay.g) * 2.0);
- }
-
- if (base.b < 0.5)
- {
- ba = overlay.b * base.b * 2.0;
- }
- else
- {
- ba = 1.0 - ((1.0 - base.b) * (1.0 - overlay.b) * 2.0);
- }
-
- textureColor = vec4(ra, ga, ba, 1.0);
- textureColor = (textureColor - base) * 0.15 + base;
-
- gl_FragColor = vec4(textureColor.r, textureColor.g, textureColor.b, 1.0);
-}
\ No newline at end of file
diff --git a/Live/src/main/res/raw/lomo.glsl b/Live/src/main/res/raw/lomo.glsl
deleted file mode 100644
index 10697248..00000000
--- a/Live/src/main/res/raw/lomo.glsl
+++ /dev/null
@@ -1,29 +0,0 @@
-#extension GL_OES_EGL_image_external : require
-
-precision mediump float;
-
-varying mediump vec2 textureCoordinate;
-
-uniform samplerExternalOES inputImageTexture;
-uniform sampler2D inputImageTexture2;
-uniform sampler2D inputImageTexture3;
-
-uniform float strength;
-
-void main()
-{
- vec4 originColor = vec4(0.2,0.6,0.9,1.0);
- vec3 texel;
- vec2 tc = (2.0 * textureCoordinate) - 1.0;
- float d = dot(tc, tc);
- vec2 lookup = vec2(d, originColor.r);
- texel.r = texture2D(inputImageTexture3, lookup).r;
- lookup.y = originColor.g;
- texel.g = texture2D(inputImageTexture3, lookup).g;
- lookup.y = originColor.b;
- texel.b = texture2D(inputImageTexture3, lookup).b;
-
- texel.rgb = mix(originColor.rgb, texel.rgb, strength);
-
- gl_FragColor = vec4(texel,1.0);
-}
\ No newline at end of file
diff --git a/Live/src/main/res/raw/lookup.glsl b/Live/src/main/res/raw/lookup.glsl
deleted file mode 100644
index e70e446f..00000000
--- a/Live/src/main/res/raw/lookup.glsl
+++ /dev/null
@@ -1,33 +0,0 @@
-varying highp vec2 textureCoordinate;
-
-uniform sampler2D inputImageTexture;
-uniform sampler2D inputImageTexture2; // lookup texture\n" +
-
-void main() {
-
- lowp vec4 textureColor = texture2D(inputImageTexture, textureCoordinate);\n" +
-
- mediump float blueColor = textureColor.b * 63.0;
-
- mediump vec2 quad1;
- quad1.y = floor(floor(blueColor) / 8.0);
- quad1.x = floor(blueColor) - (quad1.y * 8.0);
-
- mediump vec2 quad2;\n" +
- quad2.y = floor(ceil(blueColor) / 8.0);\n" +
- quad2.x = ceil(blueColor) - (quad2.y * 8.0);\n" +
-
- highp vec2 texPos1;
- texPos1.x = (quad1.x * 0.125) + 0.5/512.0 + ((0.125 - 1.0/512.0) * textureColor.r);
- texPos1.y = (quad1.y * 0.125) + 0.5/512.0 + ((0.125 - 1.0/512.0) * textureColor.g);
-
- highp vec2 texPos2;\n" +
- texPos2.x = (quad2.x * 0.125) + 0.5/512.0 + ((0.125 - 1.0/512.0) * textureColor.r);
- texPos2.y = (quad2.y * 0.125) + 0.5/512.0 + ((0.125 - 1.0/512.0) * textureColor.g);
-
- lowp vec4 newColor1 = texture2D(inputImageTexture2, texPos1);
- lowp vec4 newColor2 = texture2D(inputImageTexture2, texPos2);
-
- lowp vec4 newColor = mix(newColor1, newColor2, fract(blueColor));
- gl_FragColor = vec4(newColor.rgb, textureColor.w);
-}
\ No newline at end of file
diff --git a/Live/src/main/res/raw/n1977.glsl b/Live/src/main/res/raw/n1977.glsl
deleted file mode 100644
index 2b38a153..00000000
--- a/Live/src/main/res/raw/n1977.glsl
+++ /dev/null
@@ -1,19 +0,0 @@
-#extension GL_OES_EGL_image_external : require
-
-precision mediump float;
-
-varying mediump vec2 textureCoordinate;
-
-uniform samplerExternalOES inputImageTexture;
-uniform sampler2D inputImageTexture2;
-
-void main()
-{
- vec3 texel = texture2D(inputImageTexture, textureCoordinate).rgb;
- texel = vec3(
- texture2D(inputImageTexture2, vec2(texel.r, .16666)).r,
- texture2D(inputImageTexture2, vec2(texel.g, .5)).g,
- texture2D(inputImageTexture2, vec2(texel.b, .83333)).b);
-
- gl_FragColor = vec4(texel, 1.0);
-}
diff --git a/Live/src/main/res/raw/nashville.glsl b/Live/src/main/res/raw/nashville.glsl
deleted file mode 100644
index c4dc45e4..00000000
--- a/Live/src/main/res/raw/nashville.glsl
+++ /dev/null
@@ -1,18 +0,0 @@
-#extension GL_OES_EGL_image_external : require
-
-precision mediump float;
-
-varying mediump vec2 textureCoordinate;
-
-uniform samplerExternalOES inputImageTexture;
-uniform sampler2D inputImageTexture2;
-
-void main()
-{
- vec3 texel = texture2D(inputImageTexture, textureCoordinate).rgb;
- texel = vec3(
- texture2D(inputImageTexture2, vec2(texel.r, .16666)).r,
- texture2D(inputImageTexture2, vec2(texel.g, .5)).g,
- texture2D(inputImageTexture2, vec2(texel.b, .83333)).b);
- gl_FragColor = vec4(texel, 1.0);
-}
diff --git a/Live/src/main/res/raw/nostalgia.glsl b/Live/src/main/res/raw/nostalgia.glsl
deleted file mode 100644
index 1c5a3274..00000000
--- a/Live/src/main/res/raw/nostalgia.glsl
+++ /dev/null
@@ -1,108 +0,0 @@
-#extension GL_OES_EGL_image_external : require
-
-precision highp float;
-
-varying highp vec2 textureCoordinate;
-
-uniform samplerExternalOES inputImageTexture;
-uniform sampler2D curve;
-uniform sampler2D curve2;
-uniform highp float texelWidthOffset;
-uniform highp float texelHeightOffset;
-uniform highp float blurSize;
-
-vec4 OverlayBlendingVec4(vec4 down, vec4 up, float fAlpha)
-{
- if ( down.r < 0.5 )
- {
- up.r = up.r * down.r * 2.0;
- }
- else
- {
- up.r = 1.0 - ( ( 1.0 - down.r) * ( 1.0 - up.r ) * 2.0 );
- }
- if ( down.g < 0.5 )
- {
- up.g = up.g * down.g * 2.0;
- }
- else
- {
- up.g = 1.0 - ( ( 1.0 - down.g) * ( 1.0 - up.g ) * 2.0 );
- }
-
- if ( down.b < 0.5 )
- {
- up.b = up.b * down.b * 2.0;
- }
- else
- {
- up.b = 1.0 - ( ( 1.0 - down.b) * ( 1.0 - up.b ) * 2.0 );
- }
-
- down = ( up - down ) * fAlpha + down;
-
- return down;
-}
-
-void main()
-{
- float xCoordinate = textureCoordinate.x;
- float yCoordinate = textureCoordinate.y;
-
- vec4 textureColor = texture2D( inputImageTexture, vec2(xCoordinate, yCoordinate));
- highp vec2 firstOffset = vec2(1.3846153846 * texelWidthOffset, 1.3846153846 * texelHeightOffset) * blurSize;
- highp vec2 secondOffset = vec2(3.2307692308 * texelWidthOffset, 3.2307692308 * texelHeightOffset) * blurSize;
-
- highp vec2 centerTextureCoordinate = vec2(xCoordinate, yCoordinate);
- highp vec2 oneStepLeftTextureCoordinate = vec2(xCoordinate, yCoordinate) - firstOffset;
- highp vec2 twoStepsLeftTextureCoordinate = vec2(xCoordinate, yCoordinate) - secondOffset;
- highp vec2 oneStepRightTextureCoordinate = vec2(xCoordinate, yCoordinate) + firstOffset;
- highp vec2 twoStepsRightTextureCoordinate = vec2(xCoordinate, yCoordinate) + secondOffset;
-
- lowp vec4 fragmentColor = texture2D(inputImageTexture, vec2(centerTextureCoordinate.x, centerTextureCoordinate.y)) * 0.2270270270;
- fragmentColor += texture2D(inputImageTexture, vec2(oneStepLeftTextureCoordinate.x, oneStepLeftTextureCoordinate.y)) * 0.3162162162;
- fragmentColor += texture2D(inputImageTexture, vec2(oneStepRightTextureCoordinate.x, oneStepRightTextureCoordinate.y)) * 0.3162162162;
- fragmentColor += texture2D(inputImageTexture, vec2(twoStepsLeftTextureCoordinate.x, twoStepsLeftTextureCoordinate.y)) * 0.0702702703;
- fragmentColor += texture2D(inputImageTexture, vec2(twoStepsRightTextureCoordinate.x, twoStepsRightTextureCoordinate.y)) * 0.0702702703;
-
- lowp vec4 blurColor = fragmentColor;
-
- // step1 ScreenBlending
- blurColor = 1.0 - ((1.0 - textureColor) * (1.0 - blurColor));
- blurColor = clamp(blurColor, 0.0, 1.0);
- textureColor = (blurColor - textureColor) * 0.7 + textureColor;
- textureColor = clamp(textureColor, 0.0, 1.0);
-
- // step2 OverlayBlending
- textureColor = OverlayBlendingVec4(textureColor, vec4(0.0, 0.0, 0.0, 1.0), 0.3);
- textureColor = clamp(textureColor, vec4(0.0, 0.0, 0.0, 1.0), vec4(1.0, 1.0, 1.0, 1.0));
-
- // step3 curve
- highp float redCurveValue = texture2D(curve, vec2(textureColor.r, 0.0)).r;
- highp float greenCurveValue = texture2D(curve, vec2(textureColor.g, 0.0)).g;
- highp float blueCurveValue = texture2D(curve, vec2(textureColor.b, 0.0)).b;
-
- // step4 curve
- redCurveValue = texture2D(curve, vec2(redCurveValue, 1.0)).r;
- greenCurveValue = texture2D(curve, vec2(greenCurveValue, 1.0)).r;
- blueCurveValue = texture2D(curve, vec2(blueCurveValue, 1.0)).r;
-
- // step5 level
- redCurveValue = texture2D(curve, vec2(redCurveValue, 1.0)).g;
- greenCurveValue = texture2D(curve, vec2(greenCurveValue, 1.0)).g;
- blueCurveValue = texture2D(curve, vec2(blueCurveValue, 1.0)).g;
-
- // step6 curve
- redCurveValue = texture2D(curve2, vec2(redCurveValue, 1.0)).r;
- greenCurveValue = texture2D(curve2, vec2(greenCurveValue, 1.0)).g;
- blueCurveValue = texture2D(curve2, vec2(blueCurveValue, 1.0)).b;
-
- // step7 curve
- redCurveValue = texture2D(curve, vec2(redCurveValue, 1.0)).b;
- greenCurveValue = texture2D(curve, vec2(greenCurveValue, 1.0)).b;
-
- blueCurveValue = texture2D(curve, vec2(blueCurveValue, 1.0)).b;
-
- lowp vec4 BCSColor = vec4(redCurveValue, greenCurveValue, blueCurveValue, 1.0);
- gl_FragColor = vec4(BCSColor.r,BCSColor.g,BCSColor.b,1.0);
-}
\ No newline at end of file
diff --git a/Live/src/main/res/raw/pixar.glsl b/Live/src/main/res/raw/pixar.glsl
deleted file mode 100644
index 9a91be41..00000000
--- a/Live/src/main/res/raw/pixar.glsl
+++ /dev/null
@@ -1,137 +0,0 @@
-#extension GL_OES_EGL_image_external : require
-
-precision mediump float;
-
-varying mediump vec2 textureCoordinate;
-
-uniform samplerExternalOES inputImageTexture;
-uniform sampler2D inputImageTexture2;
-
-uniform float strength;
-
-// gray
-float NCGray(vec4 color)
-{
- float gray = 0.2125 * color.r + 0.7154 * color.g + 0.0721 * color.b;
- return gray;
-}
-
-// tone mapping
-vec4 NCTonemapping(vec4 color)
-{
- vec4 mapped;
- mapped.r = texture2D(inputImageTexture2, vec2(color.r, 0.0)).r;
- mapped.g = texture2D(inputImageTexture2, vec2(color.g, 0.0)).g;
- mapped.b = texture2D(inputImageTexture2, vec2(color.b, 0.0)).b;
- mapped.a = color.a;
- return mapped;
-}
-
-// color control
-vec4 NCColorControl(vec4 color, float saturation, float brightness, float contrast)
-{
- float gray = NCGray(color);
-
- color.rgb = vec3(saturation) * color.rgb + vec3(1.0-saturation) * vec3(gray);
- color.r = clamp(color.r, 0.0, 1.0);
- color.g = clamp(color.g, 0.0, 1.0);
- color.b = clamp(color.b, 0.0, 1.0);
-
- color.rgb = vec3(contrast) * (color.rgb - vec3(0.5)) + vec3(0.5);
- color.r = clamp(color.r, 0.0, 1.0);
- color.g = clamp(color.g, 0.0, 1.0);
- color.b = clamp(color.b, 0.0, 1.0);
-
- color.rgb = color.rgb + vec3(brightness);
- color.r = clamp(color.r, 0.0, 1.0);
- color.g = clamp(color.g, 0.0, 1.0);
- color.b = clamp(color.b, 0.0, 1.0);
-
- return color;
-}
-
-// hue adjust
-vec4 NCHueAdjust(vec4 color, float hueAdjust)
-{
- vec3 kRGBToYPrime = vec3(0.299, 0.587, 0.114);
- vec3 kRGBToI = vec3(0.595716, -0.274453, -0.321263);
- vec3 kRGBToQ = vec3(0.211456, -0.522591, 0.31135);
-
- vec3 kYIQToR = vec3(1.0, 0.9563, 0.6210);
- vec3 kYIQToG = vec3(1.0, -0.2721, -0.6474);
- vec3 kYIQToB = vec3(1.0, -1.1070, 1.7046);
-
- float yPrime = dot(color.rgb, kRGBToYPrime);
- float I = dot(color.rgb, kRGBToI);
- float Q = dot(color.rgb, kRGBToQ);
-
- float hue = atan(Q, I);
- float chroma = sqrt (I * I + Q * Q);
-
- hue -= hueAdjust;
-
- Q = chroma * sin (hue);
- I = chroma * cos (hue);
-
- color.r = dot(vec3(yPrime, I, Q), kYIQToR);
- color.g = dot(vec3(yPrime, I, Q), kYIQToG);
- color.b = dot(vec3(yPrime, I, Q), kYIQToB);
-
- return color;
-}
-
-// colorMatrix
-vec4 NCColorMatrix(vec4 color, float red, float green, float blue, float alpha, vec4 bias)
-{
- color = color * vec4(red, green, blue, alpha) + bias;
-
- return color;
-}
-
-// multiply blend
-vec4 NCMultiplyBlend(vec4 overlay, vec4 base)
-{
- vec4 outputColor;
-
- float a = overlay.a + base.a * (1.0 - overlay.a);
-
- // // normal blend
- // outputColor.r = (base.r * base.a + overlay.r * overlay.a * (1.0 - base.a))/a;
- // outputColor.g = (base.g * base.a + overlay.g * overlay.a * (1.0 - base.a))/a;
- // outputColor.b = (base.b * base.a + overlay.b * overlay.a * (1.0 - base.a))/a;
-
-
- // multiply blend
- outputColor.rgb = ((1.0-base.a) * overlay.rgb * overlay.a + (1.0-overlay.a) * base.rgb * base.a + overlay.a * base.a * overlay.rgb * base.rgb) / a;
-
-
- outputColor.a = a;
-
- return outputColor;
-}
-
-void main()
-{
- vec4 originColor = texture2D(inputImageTexture, textureCoordinate);
- vec4 color = texture2D(inputImageTexture, textureCoordinate);
-
- color.a = 1.0;
-
- // tone mapping
- color.r = texture2D(inputImageTexture2, vec2(color.r, 0.0)).r;
- color.g = texture2D(inputImageTexture2, vec2(color.g, 0.0)).g;
- color.b = texture2D(inputImageTexture2, vec2(color.b, 0.0)).b;
-
- // color control
- color = NCColorControl(color, 1.0, 0.08, 1.0);
-
- // hue adjust
- color = NCHueAdjust(color, 0.0556);
-
- // color matrix
- color = NCColorMatrix(color, 1.0, 1.0, 1.0, 1.0, vec4(0.02, 0.02, 0.06, 0));
-
- color.rgb = mix(originColor.rgb, color.rgb, strength);
-
- gl_FragColor = color;
-}
\ No newline at end of file
diff --git a/Live/src/main/res/raw/rise.glsl b/Live/src/main/res/raw/rise.glsl
deleted file mode 100644
index 946279c8..00000000
--- a/Live/src/main/res/raw/rise.glsl
+++ /dev/null
@@ -1,33 +0,0 @@
-#extension GL_OES_EGL_image_external : require
-
-precision mediump float;
-
-varying mediump vec2 textureCoordinate;
-
-uniform samplerExternalOES inputImageTexture;
-uniform sampler2D inputImageTexture2; //blowout;
-uniform sampler2D inputImageTexture3; //overlay;
-uniform sampler2D inputImageTexture4; //map
-
-uniform float strength;
-
-void main()
-{
- vec4 originColor = texture2D(inputImageTexture, textureCoordinate);
- vec4 texel = texture2D(inputImageTexture, textureCoordinate);
- vec3 bbTexel = texture2D(inputImageTexture2, textureCoordinate).rgb;
-
- texel.r = texture2D(inputImageTexture3, vec2(bbTexel.r, texel.r)).r;
- texel.g = texture2D(inputImageTexture3, vec2(bbTexel.g, texel.g)).g;
- texel.b = texture2D(inputImageTexture3, vec2(bbTexel.b, texel.b)).b;
-
- vec4 mapped;
- mapped.r = texture2D(inputImageTexture4, vec2(texel.r, .16666)).r;
- mapped.g = texture2D(inputImageTexture4, vec2(texel.g, .5)).g;
- mapped.b = texture2D(inputImageTexture4, vec2(texel.b, .83333)).b;
- mapped.a = 1.0;
-
- mapped.rgb = mix(originColor.rgb, mapped.rgb, strength);
-
- gl_FragColor = mapped;
-}
\ No newline at end of file
diff --git a/Live/src/main/res/raw/romance.glsl b/Live/src/main/res/raw/romance.glsl
deleted file mode 100644
index 6ebe86e9..00000000
--- a/Live/src/main/res/raw/romance.glsl
+++ /dev/null
@@ -1,50 +0,0 @@
-#extension GL_OES_EGL_image_external : require
-
-precision highp float;
-
-varying highp vec2 textureCoordinate;
-
-uniform samplerExternalOES inputImageTexture;
-uniform sampler2D curve;
-
-void main()
-{
- lowp vec4 textureColor;
- lowp vec4 textureColorRes;
- lowp vec4 textureColorOri;
- vec4 grey1Color;
- vec4 layerColor;
- mediump float satVal = 115.0 / 100.0;
-
- float xCoordinate = textureCoordinate.x;
- float yCoordinate = textureCoordinate.y;
-
- highp float redCurveValue;
- highp float greenCurveValue;
- highp float blueCurveValue;
-
- textureColor = texture2D( inputImageTexture, vec2(xCoordinate, yCoordinate));
- textureColorRes = textureColor;
- textureColorOri = textureColor;
-
- // step1. screen blending
- textureColor = 1.0 - ((1.0 - textureColorOri) * (1.0 - textureColorOri));
- textureColor = (textureColor - textureColorOri) + textureColorOri;
-
- // step2. curve
- redCurveValue = texture2D(curve, vec2(textureColor.r, 0.0)).r;
- greenCurveValue = texture2D(curve, vec2(textureColor.g, 0.0)).g;
- blueCurveValue = texture2D(curve, vec2(textureColor.b, 0.0)).b;
-
- // step3. saturation
- highp float G = (redCurveValue + greenCurveValue + blueCurveValue);
- G = G / 3.0;
-
- redCurveValue = ((1.0 - satVal) * G + satVal * redCurveValue);
- greenCurveValue = ((1.0 - satVal) * G + satVal * greenCurveValue);
- blueCurveValue = ((1.0 - satVal) * G + satVal * blueCurveValue);
-
- textureColor = vec4(redCurveValue, greenCurveValue, blueCurveValue, 1.0);
-
- gl_FragColor = vec4(textureColor.r, textureColor.g, textureColor.b, 1.0);
-}
diff --git a/Live/src/main/res/raw/sakura.glsl b/Live/src/main/res/raw/sakura.glsl
deleted file mode 100644
index d34ec226..00000000
--- a/Live/src/main/res/raw/sakura.glsl
+++ /dev/null
@@ -1,71 +0,0 @@
-#extension GL_OES_EGL_image_external : require
-
-precision mediump float;
-
-uniform samplerExternalOES inputImageTexture;
-uniform sampler2D curve;
-uniform float texelWidthOffset;
-uniform float texelHeightOffset;
-
-varying mediump vec2 textureCoordinate;
-
-vec4 gaussianBlur(sampler2D sampler) {
- lowp float strength = 1.;
- vec4 color = vec4(0.);
- vec2 step = vec2(0.);
-
- color += texture2D(sampler,textureCoordinate)* 0.25449 ;
-
- step.x = 1.37754 * texelWidthOffset * strength;
- step.y = 1.37754 * texelHeightOffset * strength;
- color += texture2D(sampler,textureCoordinate+step) * 0.24797;
- color += texture2D(sampler,textureCoordinate-step) * 0.24797;
-
- step.x = 3.37754 * texelWidthOffset * strength;
- step.y = 3.37754 * texelHeightOffset * strength;
- color += texture2D(sampler,textureCoordinate+step) * 0.09122;
- color += texture2D(sampler,textureCoordinate-step) * 0.09122;
-
- step.x = 5.37754 * texelWidthOffset * strength;
- step.y = 5.37754 * texelHeightOffset * strength;
- color += texture2D(sampler,textureCoordinate+step) * 0.03356;
- color += texture2D(sampler,textureCoordinate-step) * 0.03356;
-
- return color;
-}
-
-vec4 overlay(vec4 c1, vec4 c2){
- vec4 r1 = vec4(0.,0.,0.,1.);
-
- r1.r = c1.r < 0.5 ? 2.0*c1.r*c2.r : 1.0 - 2.0*(1.0-c1.r)*(1.0-c2.r);
- r1.g = c1.g < 0.5 ? 2.0*c1.g*c2.g : 1.0 - 2.0*(1.0-c1.g)*(1.0-c2.g);
- r1.b = c1.b < 0.5 ? 2.0*c1.b*c2.b : 1.0 - 2.0*(1.0-c1.b)*(1.0-c2.b);
-
- return r1;
-}
-
-vec4 level0c(vec4 color, sampler2D sampler) {
- color.r = texture2D(sampler, vec2(color.r, 0.)).r;
- color.g = texture2D(sampler, vec2(color.g, 0.)).r;
- color.b = texture2D(sampler, vec2(color.b, 0.)).r;
- return color;
-}
-
-vec4 normal(vec4 c1, vec4 c2, float alpha) {
- return (c2-c1) * alpha + c1;
-}
-
-vec4 screen(vec4 c1, vec4 c2) {
- vec4 r1 = vec4(1.) - ((vec4(1.) - c1) * (vec4(1.) - c2));
- return r1;
-}
-
-void main() {
- // naver skin
- lowp vec4 c0 = texture2D(inputImageTexture, textureCoordinate);
- lowp vec4 c1 = gaussianBlur(inputImageTexture);
- lowp vec4 c2 = overlay(c0, level0c(c1, curve));
- lowp vec4 c3 = normal(c0,c2,0.15);
-
- gl_FragColor = c3;
-}
\ No newline at end of file
diff --git a/Live/src/main/res/raw/saturation.glsl b/Live/src/main/res/raw/saturation.glsl
deleted file mode 100644
index 501e2adc..00000000
--- a/Live/src/main/res/raw/saturation.glsl
+++ /dev/null
@@ -1,15 +0,0 @@
-varying highp vec2 textureCoordinate;
-
-uniform sampler2D inputImageTexture;
-uniform lowp float saturation;
-
-// Values from \"Graphics Shaders: Theory and Practice\" by Bailey and Cunningham
-const mediump vec3 luminanceWeighting = vec3(0.2125, 0.7154, 0.0721);
-
-void main() {
- lowp vec4 textureColor = texture2D(inputImageTexture, textureCoordinate);
- lowp float luminance = dot(textureColor.rgb, luminanceWeighting);
- lowp vec3 greyScaleColor = vec3(luminance);
-
- gl_FragColor = vec4(mix(greyScaleColor, textureColor.rgb, saturation), textureColor.w);
-}
\ No newline at end of file
diff --git a/Live/src/main/res/raw/sharpen.glsl b/Live/src/main/res/raw/sharpen.glsl
deleted file mode 100644
index 4a5921b2..00000000
--- a/Live/src/main/res/raw/sharpen.glsl
+++ /dev/null
@@ -1,22 +0,0 @@
-precision highp float;
-
-varying highp vec2 textureCoordinate;
-varying highp vec2 leftTextureCoordinate;
-varying highp vec2 rightTextureCoordinate;
-varying highp vec2 topTextureCoordinate;
-varying highp vec2 bottomTextureCoordinate;
-
-varying highp float centerMultiplier;
-varying highp float edgeMultiplier;
-
-uniform sampler2D inputImageTexture;
-
-void main() {
- mediump vec3 textureColor = texture2D(inputImageTexture, textureCoordinate).rgb;
- mediump vec3 leftTextureColor = texture2D(inputImageTexture, leftTextureCoordinate).rgb;
- mediump vec3 rightTextureColor = texture2D(inputImageTexture, rightTextureCoordinate).rgb;
- mediump vec3 topTextureColor = texture2D(inputImageTexture, topTextureCoordinate).rgb;
- mediump vec3 bottomTextureColor = texture2D(inputImageTexture, bottomTextureCoordinate).rgb;
-
- gl_FragColor = vec4((textureColor * centerMultiplier - (leftTextureColor * edgeMultiplier + rightTextureColor * edgeMultiplier + topTextureColor * edgeMultiplier + bottomTextureColor * edgeMultiplier)), texture2D(inputImageTexture, bottomTextureCoordinate).w);
-}
\ No newline at end of file
diff --git a/Live/src/main/res/raw/sierra.glsl b/Live/src/main/res/raw/sierra.glsl
deleted file mode 100644
index ce30bbc3..00000000
--- a/Live/src/main/res/raw/sierra.glsl
+++ /dev/null
@@ -1,32 +0,0 @@
-#extension GL_OES_EGL_image_external : require
-
-precision mediump float;
-
-varying mediump vec2 textureCoordinate;
-
-uniform samplerExternalOES inputImageTexture;
-uniform sampler2D inputImageTexture2; //blowout;
-uniform sampler2D inputImageTexture3; //overlay;
-uniform sampler2D inputImageTexture4; //map
-
-uniform float strength;
-
-void main()
-{
- vec4 originColor = texture2D(inputImageTexture, textureCoordinate);
- vec4 texel = texture2D(inputImageTexture, textureCoordinate);
- vec3 bbTexel = texture2D(inputImageTexture2, textureCoordinate).rgb;
-
- texel.r = texture2D(inputImageTexture3, vec2(bbTexel.r, texel.r)).r;
- texel.g = texture2D(inputImageTexture3, vec2(bbTexel.g, texel.g)).g;
- texel.b = texture2D(inputImageTexture3, vec2(bbTexel.b, texel.b)).b;
-
- vec4 mapped;
- mapped.r = texture2D(inputImageTexture4, vec2(texel.r, .16666)).r;
- mapped.g = texture2D(inputImageTexture4, vec2(texel.g, .5)).g;
- mapped.b = texture2D(inputImageTexture4, vec2(texel.b, .83333)).b;
- mapped.a = 1.0;
-
- mapped.rgb = mix(originColor.rgb, mapped.rgb, strength);
- gl_FragColor = mapped;
-}
\ No newline at end of file
diff --git a/Live/src/main/res/raw/sketch.glsl b/Live/src/main/res/raw/sketch.glsl
deleted file mode 100644
index 71cd7940..00000000
--- a/Live/src/main/res/raw/sketch.glsl
+++ /dev/null
@@ -1,49 +0,0 @@
-#extension GL_OES_EGL_image_external : require
-
-precision mediump float;
-
-varying highp vec2 textureCoordinate;
-
-uniform samplerExternalOES inputImageTexture;
-uniform vec2 singleStepOffset;
-uniform float strength;
-
-const highp vec3 W = vec3(0.299,0.587,0.114);
-
-
-void main()
-{
- float threshold = 0.0;
- //pic1
- vec4 oralColor = texture2D(inputImageTexture, textureCoordinate);
-
- //pic2
- vec3 maxValue = vec3(0.,0.,0.);
-
- for(int i = -2; i<=2; i++)
- {
- for(int j = -2; j<=2; j++)
- {
- vec4 tempColor = texture2D(inputImageTexture, textureCoordinate+singleStepOffset*vec2(i,j));
- maxValue.r = max(maxValue.r,tempColor.r);
- maxValue.g = max(maxValue.g,tempColor.g);
- maxValue.b = max(maxValue.b,tempColor.b);
- threshold += dot(tempColor.rgb, W);
- }
- }
- //pic3
- float gray1 = dot(oralColor.rgb, W);
-
- //pic4
- float gray2 = dot(maxValue, W);
-
- //pic5
- float contour = gray1 / gray2;
-
- threshold = threshold / 25.;
- float alpha = max(1.0,gray1>threshold?1.0:(gray1/threshold));
-
- float result = contour * alpha + (1.0-alpha)*gray1;
-
- gl_FragColor = vec4(vec3(result,result,result), oralColor.w);
-}
\ No newline at end of file
diff --git a/Live/src/main/res/raw/skinwhiten.glsl b/Live/src/main/res/raw/skinwhiten.glsl
deleted file mode 100644
index d4a2aacf..00000000
--- a/Live/src/main/res/raw/skinwhiten.glsl
+++ /dev/null
@@ -1,98 +0,0 @@
-#extension GL_OES_EGL_image_external : require
-
-precision highp float;
-
-uniform samplerExternalOES inputImageTexture;
-uniform sampler2D curve;
-
-uniform float texelWidthOffset;
-uniform float texelHeightOffset;
-
-varying mediump vec2 textureCoordinate;
-
-const mediump vec3 luminanceWeighting = vec3(0.2125, 0.7154, 0.0721);
-
-vec4 gaussianBlur(sampler2D sampler) {
- lowp float strength = 1.;
- vec4 color = vec4(0.);
- vec2 step = vec2(0.);
-
- color += texture2D(sampler,textureCoordinate)* 0.25449 ;
-
- step.x = 1.37754 * texelWidthOffset * strength;
- step.y = 1.37754 * texelHeightOffset * strength;
- color += texture2D(sampler,textureCoordinate+step) * 0.24797;
- color += texture2D(sampler,textureCoordinate-step) * 0.24797;
-
- step.x = 3.37754 * texelWidthOffset * strength;
- step.y = 3.37754 * texelHeightOffset * strength;
- color += texture2D(sampler,textureCoordinate+step) * 0.09122;
- color += texture2D(sampler,textureCoordinate-step) * 0.09122;
-
- step.x = 5.37754 * texelWidthOffset * strength;
- step.y = 5.37754 * texelHeightOffset * strength;
-
- color += texture2D(sampler,textureCoordinate+step) * 0.03356;
- color += texture2D(sampler,textureCoordinate-step) * 0.03356;
-
- return color;
-}
-
-void main() {
- vec4 blurColor;
- lowp vec4 textureColor;
- lowp float strength = -1.0 / 510.0;
-
- float xCoordinate = textureCoordinate.x;
- float yCoordinate = textureCoordinate.y;
-
- lowp float satura = 0.7;
- // naver skin
- textureColor = texture2D(inputImageTexture, textureCoordinate);
- blurColor = gaussianBlur(inputImageTexture);
-
- //saturation
- lowp float luminance = dot(blurColor.rgb, luminanceWeighting);
- lowp vec3 greyScaleColor = vec3(luminance);
-
- blurColor = vec4(mix(greyScaleColor, blurColor.rgb, satura), blurColor.w);
-
- lowp float redCurveValue = texture2D(curve, vec2(textureColor.r, 0.0)).r;
- lowp float greenCurveValue = texture2D(curve, vec2(textureColor.g, 0.0)).r;
- lowp float blueCurveValue = texture2D(curve, vec2(textureColor.b, 0.0)).r;
-
- redCurveValue = min(1.0, redCurveValue + strength);
- greenCurveValue = min(1.0, greenCurveValue + strength);
- blueCurveValue = min(1.0, blueCurveValue + strength);
-
- mediump vec4 overlay = blurColor;
-
- mediump vec4 base = vec4(redCurveValue, greenCurveValue, blueCurveValue, 1.0);
- //gl_FragColor = overlay;
-
- // step4 overlay blending
- mediump float ra;
- if (base.r < 0.5) {
- ra = overlay.r * base.r * 2.0;
- } else {
- ra = 1.0 - ((1.0 - base.r) * (1.0 - overlay.r) * 2.0);
- }
-
- mediump float ga;
- if (base.g < 0.5) {
- ga = overlay.g * base.g * 2.0;
- } else {
- ga = 1.0 - ((1.0 - base.g) * (1.0 - overlay.g) * 2.0);
- }
-
- mediump float ba;
- if (base.b < 0.5) {
- ba = overlay.b * base.b * 2.0;
- } else {
- ba = 1.0 - ((1.0 - base.b) * (1.0 - overlay.b) * 2.0);
- }
-
- textureColor = vec4(ra, ga, ba, 1.0);
-
- gl_FragColor = vec4(textureColor.r, textureColor.g, textureColor.b, 1.0);
-}
diff --git a/Live/src/main/res/raw/suger_tablets.glsl b/Live/src/main/res/raw/suger_tablets.glsl
deleted file mode 100644
index 1b734257..00000000
--- a/Live/src/main/res/raw/suger_tablets.glsl
+++ /dev/null
@@ -1,41 +0,0 @@
-#extension GL_OES_EGL_image_external : require
-
-varying mediump vec2 textureCoordinate;
-varying mediump vec2 textureCoordinate2; // TODO: This is not used
-
-uniform samplerExternalOES inputImageTexture;
-uniform sampler2D inputImageTexture2; // lookup texture
-uniform mediump float strength;
-
-void main()
-{
- mediump vec4 originColor = texture2D(inputImageTexture, textureCoordinate);
- mediump vec4 textureColor = texture2D(inputImageTexture, textureCoordinate);
-
- mediump float blueColor = textureColor.b * 63.0;
-
- mediump vec2 quad1;
- quad1.y = floor(floor(blueColor) / 8.0);
- quad1.x = floor(blueColor) - (quad1.y * 8.0);
-
- mediump vec2 quad2;
- quad2.y = floor(ceil(blueColor) / 8.0);
- quad2.x = ceil(blueColor) - (quad2.y * 8.0);
-
- mediump vec2 texPos1;
- texPos1.x = (quad1.x * 0.125) + 0.5/512.0 + ((0.125 - 1.0/512.0) * textureColor.r);
- texPos1.y = (quad1.y * 0.125) + 0.5/512.0 + ((0.125 - 1.0/512.0) * textureColor.g);
-
- mediump vec2 texPos2;
- texPos2.x = (quad2.x * 0.125) + 0.5/512.0 + ((0.125 - 1.0/512.0) * textureColor.r);
- texPos2.y = (quad2.y * 0.125) + 0.5/512.0 + ((0.125 - 1.0/512.0) * textureColor.g);
-
- mediump vec4 newColor1 = texture2D(inputImageTexture2, texPos1);
- mediump vec4 newColor2 = texture2D(inputImageTexture2, texPos2);
-
- mediump vec4 newColor = mix(newColor1, newColor2, fract(blueColor));
-
- newColor.rgb = mix(originColor.rgb, newColor.rgb, strength);
-
- gl_FragColor = vec4(newColor.rgb, textureColor.w);
-}
\ No newline at end of file
diff --git a/Live/src/main/res/raw/sunrise.glsl b/Live/src/main/res/raw/sunrise.glsl
deleted file mode 100644
index c09952d0..00000000
--- a/Live/src/main/res/raw/sunrise.glsl
+++ /dev/null
@@ -1,150 +0,0 @@
-#extension GL_OES_EGL_image_external : require
-
-precision highp float;
-
-varying highp vec2 textureCoordinate;
-
-uniform samplerExternalOES inputImageTexture;
-uniform sampler2D curve;
-
-uniform sampler2D grey1Frame;
-uniform sampler2D grey2Frame;
-uniform sampler2D grey3Frame;
-
-void main()
-{
- float GreyVal;
- lowp vec4 textureColor;
- lowp vec4 textureColorOri;
- float xCoordinate = textureCoordinate.x;
- float yCoordinate = textureCoordinate.y;
-
- highp float redCurveValue;
- highp float greenCurveValue;
- highp float blueCurveValue;
-
- vec4 grey1Color;
- vec4 grey2Color;
- vec4 grey3Color;
-
- textureColor = texture2D( inputImageTexture, vec2(xCoordinate, yCoordinate));
-
- grey1Color = texture2D(grey1Frame, vec2(xCoordinate, yCoordinate));
- grey2Color = texture2D(grey2Frame, vec2(xCoordinate, yCoordinate));
- grey3Color = texture2D(grey3Frame, vec2(xCoordinate, yCoordinate));
-
- mediump vec4 overlay = vec4(0, 0, 0, 1.0);
- mediump vec4 base = textureColor;
-
- // overlay blending
- mediump float ra;
- if (base.r < 0.5)
- {
- ra = overlay.r * base.r * 2.0;
- }
- else
- {
- ra = 1.0 - ((1.0 - base.r) * (1.0 - overlay.r) * 2.0);
- }
-
- mediump float ga;
- if (base.g < 0.5)
- {
- ga = overlay.g * base.g * 2.0;
- }
- else
- {
- ga = 1.0 - ((1.0 - base.g) * (1.0 - overlay.g) * 2.0);
- }
-
- mediump float ba;
- if (base.b < 0.5)
- {
- ba = overlay.b * base.b * 2.0;
- }
- else
- {
- ba = 1.0 - ((1.0 - base.b) * (1.0 - overlay.b) * 2.0);
- }
-
- textureColor = vec4(ra, ga, ba, 1.0);
- base = (textureColor - base) * (grey1Color.r*0.1019) + base;
-
-
- // step2 60% opacity ExclusionBlending
- textureColor = vec4(base.r, base.g, base.b, 1.0);
- mediump vec4 textureColor2 = vec4(0.098, 0.0, 0.1843, 1.0);
- textureColor2 = textureColor + textureColor2 - (2.0 * textureColor2 * textureColor);
-
- textureColor = (textureColor2 - textureColor) * 0.6 + textureColor;
-
- // step3 normal blending with original
- redCurveValue = texture2D(curve, vec2(textureColor.r, 0.0)).r;
- greenCurveValue = texture2D(curve, vec2(textureColor.g, 0.0)).g;
- blueCurveValue = texture2D(curve, vec2(textureColor.b, 0.0)).b;
-
- textureColorOri = vec4(redCurveValue, greenCurveValue, blueCurveValue, 1.0);
- textureColor = (textureColorOri - textureColor) * grey2Color.r + textureColor;
-
- // step4 normal blending with original
- redCurveValue = texture2D(curve, vec2(textureColor.r, 1.0)).r;
- greenCurveValue = texture2D(curve, vec2(textureColor.g, 1.0)).g;
- blueCurveValue = texture2D(curve, vec2(textureColor.b, 1.0)).b;
-
- textureColorOri = vec4(redCurveValue, greenCurveValue, blueCurveValue, 1.0);
- textureColor = (textureColorOri - textureColor) * (grey3Color.r) * 1.0 + textureColor;
-
-
- overlay = vec4(0.6117, 0.6117, 0.6117, 1.0);
- base = textureColor;
- // overlay blending
- if (base.r < 0.5)
- {
- ra = overlay.r * base.r * 2.0;
- }
- else
- {
- ra = 1.0 - ((1.0 - base.r) * (1.0 - overlay.r) * 2.0);
- }
-
- if (base.g < 0.5)
- {
- ga = overlay.g * base.g * 2.0;
- }
- else
- {
- ga = 1.0 - ((1.0 - base.g) * (1.0 - overlay.g) * 2.0);
- }
-
- if (base.b < 0.5)
- {
- ba = overlay.b * base.b * 2.0;
- }
- else
- {
- ba = 1.0 - ((1.0 - base.b) * (1.0 - overlay.b) * 2.0);
- }
-
- textureColor = vec4(ra, ga, ba, 1.0);
- base = (textureColor - base) + base;
-
- // step5-2 30% opacity ExclusionBlending
- textureColor = vec4(base.r, base.g, base.b, 1.0);
- textureColor2 = vec4(0.113725, 0.0039, 0.0, 1.0);
- textureColor2 = textureColor + textureColor2 - (2.0 * textureColor2 * textureColor);
-
- base = (textureColor2 - textureColor) * 0.3 + textureColor;
- redCurveValue = texture2D(curve, vec2(base.r, 1.0)).a;
- greenCurveValue = texture2D(curve, vec2(base.g, 1.0)).a;
- blueCurveValue = texture2D(curve, vec2(base.b, 1.0)).a;
-
- // step6 screen with 60%
- base = vec4(redCurveValue, greenCurveValue, blueCurveValue, 1.0);
- overlay = vec4(1.0, 1.0, 1.0, 1.0);
-
- // screen blending
- textureColor = 1.0 - ((1.0 - base) * (1.0 - overlay));
- textureColor = (textureColor - base) * 0.05098 + base;
-
- gl_FragColor = vec4(textureColor.r, textureColor.g, textureColor.b, 1.0);
-}
\ No newline at end of file
diff --git a/Live/src/main/res/raw/sunset.glsl b/Live/src/main/res/raw/sunset.glsl
deleted file mode 100644
index e44363bc..00000000
--- a/Live/src/main/res/raw/sunset.glsl
+++ /dev/null
@@ -1,108 +0,0 @@
-#extension GL_OES_EGL_image_external : require
-
-precision highp float;
-
-varying highp vec2 textureCoordinate;
-
-uniform samplerExternalOES inputImageTexture;
-uniform sampler2D curve;
-
-uniform sampler2D grey1Frame;
-uniform sampler2D grey2Frame;
-
-void main()
-{
- float GreyVal;
- lowp vec4 textureColor;
- lowp vec4 textureColorOri;
- float xCoordinate = textureCoordinate.x;
- float yCoordinate = textureCoordinate.y;
-
- highp float redCurveValue;
- highp float greenCurveValue;
- highp float blueCurveValue;
-
- vec4 grey1Color;
- vec4 grey2Color;
-
- textureColor = texture2D( inputImageTexture, vec2(xCoordinate, yCoordinate));
- grey1Color = texture2D(grey2Frame, vec2(xCoordinate, yCoordinate));
- grey2Color = texture2D(grey1Frame, vec2(xCoordinate, yCoordinate));
-
- // step1 normal blending with original
- redCurveValue = texture2D(curve, vec2(textureColor.r, 0.0)).r;
- greenCurveValue = texture2D(curve, vec2(textureColor.g, 0.0)).g;
- blueCurveValue = texture2D(curve, vec2(textureColor.b, 0.0)).b;
-
- textureColorOri = vec4(redCurveValue, greenCurveValue, blueCurveValue, 1.0);
- textureColor = (textureColorOri - textureColor) * grey1Color.r + textureColor;
-
- redCurveValue = texture2D(curve, vec2(textureColor.r, 0.0)).a;
- greenCurveValue = texture2D(curve, vec2(textureColor.g, 0.0)).a;
- blueCurveValue = texture2D(curve, vec2(textureColor.b, 0.0)).a;
-
- //textureColor = vec4(redCurveValue, greenCurveValue, blueCurveValue, 1.0);
-
- // step3 60% opacity ExclusionBlending
- textureColor = vec4(redCurveValue, greenCurveValue, blueCurveValue, 1.0);
- mediump vec4 textureColor2 = vec4(0.08627, 0.03529, 0.15294, 1.0);
- textureColor2 = textureColor + textureColor2 - (2.0 * textureColor2 * textureColor);
-
- textureColor = (textureColor2 - textureColor) * 0.6784 + textureColor;
-
-
- mediump vec4 overlay = vec4(0.6431, 0.5882, 0.5803, 1.0);
- mediump vec4 base = textureColor;
-
- // overlay blending
- mediump float ra;
- if (base.r < 0.5) {
- ra = overlay.r * base.r * 2.0;
- } else {
- ra = 1.0 - ((1.0 - base.r) * (1.0 - overlay.r) * 2.0);
- }
-
- mediump float ga;
- if (base.g < 0.5) {
- ga = overlay.g * base.g * 2.0;
- } else {
- ga = 1.0 - ((1.0 - base.g) * (1.0 - overlay.g) * 2.0);
- }
-
- mediump float ba;
- if (base.b < 0.5) {
- ba = overlay.b * base.b * 2.0;
- } else {
- ba = 1.0 - ((1.0 - base.b) * (1.0 - overlay.b) * 2.0);
- }
-
- textureColor = vec4(ra, ga, ba, 1.0);
- base = (textureColor - base) + base;
-
- // again overlay blending
- overlay = vec4(0.0, 0.0, 0.0, 1.0);
-
- // overlay blending
- if (base.r < 0.5) {
- ra = overlay.r * base.r * 2.0;
- } else {
- ra = 1.0 - ((1.0 - base.r) * (1.0 - overlay.r) * 2.0);
- }
-
- if (base.g < 0.5) {
- ga = overlay.g * base.g * 2.0;
- } else {
- ga = 1.0 - ((1.0 - base.g) * (1.0 - overlay.g) * 2.0);
- }
-
- if (base.b < 0.5) {
- ba = overlay.b * base.b * 2.0;
- } else {
- ba = 1.0 - ((1.0 - base.b) * (1.0 - overlay.b) * 2.0);
- }
-
- textureColor = vec4(ra, ga, ba, 1.0);
- textureColor = (textureColor - base) * (grey2Color * 0.549) + base;
-
- gl_FragColor = vec4(textureColor.r, textureColor.g, textureColor.b, 1.0);
-}
\ No newline at end of file
diff --git a/Live/src/main/res/raw/sutro.glsl b/Live/src/main/res/raw/sutro.glsl
deleted file mode 100644
index 832585d7..00000000
--- a/Live/src/main/res/raw/sutro.glsl
+++ /dev/null
@@ -1,48 +0,0 @@
-#extension GL_OES_EGL_image_external : require
-
-precision mediump float;
-
-varying mediump vec2 textureCoordinate;
-
-uniform samplerExternalOES inputImageTexture;
-uniform sampler2D inputImageTexture2; //sutroMap;
-uniform sampler2D inputImageTexture3; //sutroMetal;
-uniform sampler2D inputImageTexture4; //softLight
-uniform sampler2D inputImageTexture5; //sutroEdgeburn
-uniform sampler2D inputImageTexture6; //sutroCurves
-
-uniform float strength;
-
-void main()
-{
- vec4 originColor = texture2D(inputImageTexture, textureCoordinate);
- vec3 texel = texture2D(inputImageTexture, textureCoordinate).rgb;
-
- vec2 tc = (2.0 * textureCoordinate) - 1.0;
- float d = dot(tc, tc);
- vec2 lookup = vec2(d, texel.r);
- texel.r = texture2D(inputImageTexture2, lookup).r;
- lookup.y = texel.g;
- texel.g = texture2D(inputImageTexture2, lookup).g;
- lookup.y = texel.b;
- texel.b = texture2D(inputImageTexture2, lookup).b;
-
- vec3 rgbPrime = vec3(0.1019, 0.0, 0.0);
- float m = dot(vec3(.3, .59, .11), texel.rgb) - 0.03058;
- texel = mix(texel, rgbPrime + m, 0.32);
-
- vec3 metal = texture2D(inputImageTexture3, textureCoordinate).rgb;
- texel.r = texture2D(inputImageTexture4, vec2(metal.r, texel.r)).r;
- texel.g = texture2D(inputImageTexture4, vec2(metal.g, texel.g)).g;
- texel.b = texture2D(inputImageTexture4, vec2(metal.b, texel.b)).b;
-
- texel = texel * texture2D(inputImageTexture5, textureCoordinate).rgb;
-
- texel.r = texture2D(inputImageTexture6, vec2(texel.r, .16666)).r;
- texel.g = texture2D(inputImageTexture6, vec2(texel.g, .5)).g;
- texel.b = texture2D(inputImageTexture6, vec2(texel.b, .83333)).b;
-
- texel.rgb = mix(originColor.rgb, texel.rgb, strength);
-
- gl_FragColor = vec4(texel, 1.0);
-}
\ No newline at end of file
diff --git a/Live/src/main/res/raw/sweets.glsl b/Live/src/main/res/raw/sweets.glsl
deleted file mode 100644
index bced1c37..00000000
--- a/Live/src/main/res/raw/sweets.glsl
+++ /dev/null
@@ -1,156 +0,0 @@
-#extension GL_OES_EGL_image_external : require
-
-precision mediump float;
-
-uniform lowp samplerExternalOES inputImageTexture;
-uniform lowp sampler2D curve;
-uniform lowp sampler2D samplerMask;
-uniform lowp int lowPerformance;
-
-uniform float texelWidthOffset ;
-uniform float texelHeightOffset;
-
-varying mediump vec2 textureCoordinate;
-
-vec4 sharpen(sampler2D sampler)
-{
- vec4 color = texture2D(sampler, textureCoordinate) * 2.;
-
- color -= texture2D(sampler, textureCoordinate-vec2(texelWidthOffset, 0. )) * 0.25;
- color -= texture2D(sampler, textureCoordinate+vec2(texelWidthOffset, 0. )) * 0.25;
- color -= texture2D(sampler, textureCoordinate-vec2(0., texelHeightOffset)) * 0.25;
- color -= texture2D(sampler, textureCoordinate+vec2(0., texelHeightOffset)) * 0.25;
-
- return color;
-}
-
-vec4 gaussianBlur(sampler2D sampler)
-{
- lowp float strength = 1.;
-
- vec4 color = vec4(0.);
- vec2 step = vec2(0.);
-
- color += texture2D(sampler,textureCoordinate)* 0.0443 ;
-
- step.x = 1.49583 * texelWidthOffset * strength;
- step.y = 1.49583 * texelHeightOffset * strength;
- color += texture2D(sampler,textureCoordinate+vec2(step.x, 0.)) * 0.04321;
- color += texture2D(sampler,textureCoordinate-vec2(step.x, 0.)) * 0.04321;
- color += texture2D(sampler,textureCoordinate+vec2(0., step.y)) * 0.04321;
- color += texture2D(sampler,textureCoordinate-vec2(0., step.y)) * 0.04321;
-
- step.x = 2.4719250988753685 * texelWidthOffset * strength;
- step.y = 2.4719250988753685 * texelHeightOffset * strength;
- color += texture2D(sampler,textureCoordinate+step) * 0.041795;
- color += texture2D(sampler,textureCoordinate-step) * 0.041795;
- color += texture2D(sampler,textureCoordinate+vec2(-step.x, step.y)) * 0.041795;
- color += texture2D(sampler,textureCoordinate+vec2( step.x,-step.y)) * 0.041795;
-
- step.x = 5.49583 * texelWidthOffset * strength;
- step.y = 5.49583 * texelHeightOffset * strength;
- color += texture2D(sampler,textureCoordinate+vec2(step.x, 0.)) * 0.040425;
- color += texture2D(sampler,textureCoordinate-vec2(step.x, 0.)) * 0.040425;
- color += texture2D(sampler,textureCoordinate+vec2(0., step.y)) * 0.040425;
- color += texture2D(sampler,textureCoordinate-vec2(0., step.y)) * 0.040425;
-
- step.x = 5.300352223621558 * texelWidthOffset * strength;
- step.y = 5.300352223621558 * texelHeightOffset * strength;
- color += texture2D(sampler,textureCoordinate+step) * 0.0391;
- color += texture2D(sampler,textureCoordinate-step) * 0.0391;
- color += texture2D(sampler,textureCoordinate+vec2(-step.x, step.y)) * 0.0391;
- color += texture2D(sampler,textureCoordinate+vec2( step.x,-step.y)) * 0.0391;
-
- step.x = 9.49583 * texelWidthOffset * strength;
- step.y = 9.49583 * texelHeightOffset * strength;
- color += texture2D(sampler,textureCoordinate+vec2(step.x, 0.)) * 0.037815;
- color += texture2D(sampler,textureCoordinate-vec2(step.x, 0.)) * 0.037815;
- color += texture2D(sampler,textureCoordinate+vec2(0., step.y)) * 0.037815;
- color += texture2D(sampler,textureCoordinate-vec2(0., step.y)) * 0.037815;
-
- step.x = 8.128779348367749 * texelWidthOffset * strength;
- step.y = 8.128779348367749 * texelHeightOffset * strength;
- color += texture2D(sampler,textureCoordinate+step) * 0.03658;
- color += texture2D(sampler,textureCoordinate-step) * 0.03658;
- color += texture2D(sampler,textureCoordinate+vec2(-step.x, step.y)) * 0.03658;
- color += texture2D(sampler,textureCoordinate+vec2( step.x,-step.y)) * 0.03658;
-
- return color;
-}
-
-vec4 level(vec4 color, sampler2D sampler)
-{
- color.r = texture2D(sampler, vec2(color.r, 0.)).r;
- color.g = texture2D(sampler, vec2(color.g, 0.)).g;
- color.b = texture2D(sampler, vec2(color.b, 0.)).b;
-
- return color;
-}
-
-vec4 normal(vec4 c1, vec4 c2, float alpha)
-{
- return (c2-c1) * alpha + c1;
-}
-
-vec4 lighten(vec4 c1, vec4 c2)
-{
- return max(c1,c2);
-}
-
-vec4 overlay(vec4 c1, vec4 c2)
-{
- vec4 r1 = vec4(0.,0.,0.,1.);
- r1.r = c1.r < 0.5 ? 2.0*c1.r*c2.r : 1.0 - 2.0*(1.0-c1.r)*(1.0-c2.r);
- r1.g = c1.g < 0.5 ? 2.0*c1.g*c2.g : 1.0 - 2.0*(1.0-c1.g)*(1.0-c2.g);
- r1.b = c1.b < 0.5 ? 2.0*c1.b*c2.b : 1.0 - 2.0*(1.0-c1.b)*(1.0-c2.b);
-
- return r1;
-}
-
-vec3 lerp (vec3 x, vec3 y, float s)
-{
- return x+s*(y-x);
-}
-
-vec4 adjust (vec4 color, float brightness, float contrast, float saturation)
-{
- vec3 averageLuminance = vec3(0.5);
- vec3 brightedColor = color.rgb * (brightness+1.);
- vec3 intensity = vec3(dot(brightedColor, vec3(0.299, 0.587, 0.114)));
- vec3 saturatedColor = lerp(intensity, brightedColor, saturation+1.);
- vec3 contrastedColor = lerp(averageLuminance, saturatedColor, contrast+1.);
-
- return vec4(contrastedColor,1.);
-}
-
-vec4 vibrance(vec4 color, float strength)
-{
- float luminance = (color.r+color.g+color.b)/3.;
- //dot(color.rgb, vec3(0.299,0.587,0.114));
- float maximum = max(color.r, max(color.g, color.b));
- float amount = (maximum-luminance)*-strength;
-
- return vec4(color.rgb * (1.-amount) + maximum*amount, 1.);
-}
-
-void main()
-{
- vec4 c1;
- vec4 c2;
- if (lowPerformance == 1)
- {
- c1 = texture2D(inputImageTexture, textureCoordinate);
- c2 = texture2D(inputImageTexture, textureCoordinate);
- }
- else
- {
- c1 = sharpen(inputImageTexture);
- c2 = normal(c1, gaussianBlur(inputImageTexture), 0.8); // radius = 13. sharpen?? gaussian blur? ???? ??, ?? blending?? ??
- }
- vec4 c3 = normal(c1, lighten(c1,c2), 0.6); // lighten (0.6)
- c3 = adjust(c3, 0.12, 0., 0.05); // brightness = 12, saturation = 0.5;
- c3 = vibrance(level(c3, curve), 0.5); // vibrance = 0.5;
- c3 = normal(c3, overlay(c3, vec4(0.)), 1.-texture2D(samplerMask, textureCoordinate).r); // vignetting
-
- gl_FragColor = c3;
-}
\ No newline at end of file
diff --git a/Live/src/main/res/raw/tender.glsl b/Live/src/main/res/raw/tender.glsl
deleted file mode 100644
index 0247379f..00000000
--- a/Live/src/main/res/raw/tender.glsl
+++ /dev/null
@@ -1,92 +0,0 @@
-#extension GL_OES_EGL_image_external : require
-
-precision highp float;
-
-varying highp vec2 textureCoordinate;
-
-uniform samplerExternalOES inputImageTexture;
-uniform sampler2D curve;
-uniform sampler2D grey1Frame;
-
-void main()
-{
- mediump vec4 textureColor;
- mediump vec4 textureColorRes;
- vec4 grey1Color;
- mediump float satVal = 65.0 / 100.0;
- mediump float mask1R = 29.0 / 255.0;
- mediump float mask1G = 43.0 / 255.0;
- mediump float mask1B = 95.0 / 255.0;
-
- highp float xCoordinate = textureCoordinate.x;
- highp float yCoordinate = textureCoordinate.y;
-
- highp float redCurveValue;
- highp float greenCurveValue;
- highp float blueCurveValue;
-
- textureColor = texture2D( inputImageTexture, vec2(xCoordinate, yCoordinate));
- textureColorRes = textureColor;
-
- grey1Color = texture2D(grey1Frame, vec2(xCoordinate, yCoordinate));
-
- // step1. saturation
- highp float G = (textureColor.r + textureColor.g + textureColor.b);
- G = G / 3.0;
-
- redCurveValue = ((1.0 - satVal) * G + satVal * textureColor.r);
- greenCurveValue = ((1.0 - satVal) * G + satVal * textureColor.g);
- blueCurveValue = ((1.0 - satVal) * G + satVal * textureColor.b);
-
- // step2 curve
- redCurveValue = texture2D(curve, vec2(textureColor.r, 0.0)).r;
- greenCurveValue = texture2D(curve, vec2(textureColor.g, 0.0)).g;
- blueCurveValue = texture2D(curve, vec2(textureColor.b, 0.0)).b;
-
- // step3 30% opacity ExclusionBlending
- textureColor = vec4(redCurveValue, greenCurveValue, blueCurveValue, 1.0);
- mediump vec4 textureColor2 = vec4(mask1R, mask1G, mask1B, 1.0);
- textureColor2 = textureColor + textureColor2 - (2.0 * textureColor2 * textureColor);
-
- textureColor = (textureColor2 - textureColor) * 0.3 + textureColor;
-
- mediump vec4 overlay = vec4(0, 0, 0, 1.0);
- mediump vec4 base = vec4(textureColor.r, textureColor.g, textureColor.b, 1.0);
-
- // step4 overlay blending
- mediump float ra;
- if (base.r < 0.5)
- {
- ra = overlay.r * base.r * 2.0;
- }
- else
- {
- ra = 1.0 - ((1.0 - base.r) * (1.0 - overlay.r) * 2.0);
- }
-
- mediump float ga;
- if (base.g < 0.5)
- {
- ga = overlay.g * base.g * 2.0;
- }
- else
- {
- ga = 1.0 - ((1.0 - base.g) * (1.0 - overlay.g) * 2.0);
- }
-
- mediump float ba;
- if (base.b < 0.5)
- {
- ba = overlay.b * base.b * 2.0;
- }
- else
- {
- ba = 1.0 - ((1.0 - base.b) * (1.0 - overlay.b) * 2.0);
- }
-
- textureColor = vec4(ra, ga, ba, 1.0);
- base = (textureColor - base) * (grey1Color.r/2.0) + base;
-
- gl_FragColor = vec4(base.r, base.g, base.b, 1.0);
-}
-
\ No newline at end of file
diff --git a/Live/src/main/res/raw/toaster2_filter_shader.glsl b/Live/src/main/res/raw/toaster2_filter_shader.glsl
deleted file mode 100644
index a16f2a9e..00000000
--- a/Live/src/main/res/raw/toaster2_filter_shader.glsl
+++ /dev/null
@@ -1,68 +0,0 @@
-#extension GL_OES_EGL_image_external : require
-
-precision mediump float;
-
-varying mediump vec2 textureCoordinate;
-
-uniform samplerExternalOES inputImageTexture;
-uniform sampler2D inputImageTexture2; //toaster_metal
-uniform sampler2D inputImageTexture3; //toaster_soft_light
-uniform sampler2D inputImageTexture4; //toaster_curves
-uniform sampler2D inputImageTexture5; //toaster_overlay_map_warm
-uniform sampler2D inputImageTexture6; //toaster_color_shift
-
-void main()
-{
- mediump vec3 texel;
- mediump vec2 lookup;
- vec2 blue;
- vec2 green;
- vec2 red;
- mediump vec4 tmpvar_1;
- tmpvar_1 = texture2D (inputImageTexture, textureCoordinate);
- texel = tmpvar_1.xyz;
- mediump vec4 tmpvar_2;
- tmpvar_2 = texture2D (inputImageTexture2, textureCoordinate);
- mediump vec2 tmpvar_3;
- tmpvar_3.x = tmpvar_2.x;
- tmpvar_3.y = tmpvar_1.x;
- texel.x = texture2D (inputImageTexture3, tmpvar_3).x;
- mediump vec2 tmpvar_4;
- tmpvar_4.x = tmpvar_2.y;
- tmpvar_4.y = tmpvar_1.y;
- texel.y = texture2D (inputImageTexture3, tmpvar_4).y;
- mediump vec2 tmpvar_5;
- tmpvar_5.x = tmpvar_2.z;
- tmpvar_5.y = tmpvar_1.z;
- texel.z = texture2D (inputImageTexture3, tmpvar_5).z;
- red.x = texel.x;
- red.y = 0.16666;
- green.x = texel.y;
- green.y = 0.5;
- blue.x = texel.z;
- blue.y = 0.833333;
- texel.x = texture2D (inputImageTexture4, red).x;
- texel.y = texture2D (inputImageTexture4, green).y;
- texel.z = texture2D (inputImageTexture4, blue).z;
- mediump vec2 tmpvar_6;
- tmpvar_6 = ((2.0 * textureCoordinate) - 1.0);
- mediump vec2 tmpvar_7;
- tmpvar_7.x = dot (tmpvar_6, tmpvar_6);
- tmpvar_7.y = texel.x;
- lookup = tmpvar_7;
- texel.x = texture2D (inputImageTexture5, tmpvar_7).x;
- lookup.y = texel.y;
- texel.y = texture2D (inputImageTexture5, lookup).y;
- lookup.y = texel.z;
- texel.z = texture2D (inputImageTexture5, lookup).z;
- red.x = texel.x;
- green.x = texel.y;
- blue.x = texel.z;
- texel.x = texture2D (inputImageTexture6, red).x;
- texel.y = texture2D (inputImageTexture6, green).y;
- texel.z = texture2D (inputImageTexture6, blue).z;
- mediump vec4 tmpvar_8;
- tmpvar_8.w = 1.0;
- tmpvar_8.xyz = texel;
- gl_FragColor = tmpvar_8;
-}
\ No newline at end of file
diff --git a/Live/src/main/res/raw/valencia.glsl b/Live/src/main/res/raw/valencia.glsl
deleted file mode 100644
index de7e4291..00000000
--- a/Live/src/main/res/raw/valencia.glsl
+++ /dev/null
@@ -1,46 +0,0 @@
-#extension GL_OES_EGL_image_external : require
-
-precision mediump float;
-
-varying mediump vec2 textureCoordinate;
-
-uniform samplerExternalOES inputImageTexture;
-uniform sampler2D inputImageTexture2; //map
-uniform sampler2D inputImageTexture3; //gradMap
-
-mat3 saturateMatrix = mat3(
- 1.1402,
- -0.0598,
- -0.061,
- -0.1174,
- 1.0826,
- -0.1186,
- -0.0228,
- -0.0228,
- 1.1772);
-
-vec3 lumaCoeffs = vec3(.3, .59, .11);
-
-uniform float strength;
-
-void main()
-{
- vec4 originColor = texture2D(inputImageTexture, textureCoordinate);
- vec3 texel = texture2D(inputImageTexture, textureCoordinate).rgb;
-
- texel = vec3(
- texture2D(inputImageTexture2, vec2(texel.r, .1666666)).r,
- texture2D(inputImageTexture2, vec2(texel.g, .5)).g,
- texture2D(inputImageTexture2, vec2(texel.b, .8333333)).b
- );
-
- texel = saturateMatrix * texel;
- float luma = dot(lumaCoeffs, texel);
- texel = vec3(
- texture2D(inputImageTexture3, vec2(luma, texel.r)).r,
- texture2D(inputImageTexture3, vec2(luma, texel.g)).g,
- texture2D(inputImageTexture3, vec2(luma, texel.b)).b);
-
- texel.rgb = mix(originColor.rgb, texel.rgb, strength);
- gl_FragColor = vec4(texel, 1.0);
-}
\ No newline at end of file
diff --git a/Live/src/main/res/raw/walden.glsl b/Live/src/main/res/raw/walden.glsl
deleted file mode 100644
index 19c9b5e5..00000000
--- a/Live/src/main/res/raw/walden.glsl
+++ /dev/null
@@ -1,35 +0,0 @@
-#extension GL_OES_EGL_image_external : require
-
-precision mediump float;
-
-varying mediump vec2 textureCoordinate;
-
-uniform samplerExternalOES inputImageTexture;
-uniform sampler2D inputImageTexture2; //map
-uniform sampler2D inputImageTexture3; //vigMap
-
-uniform float strength;
-
-void main()
-{
- vec4 originColor = texture2D(inputImageTexture, textureCoordinate);
- vec3 texel = texture2D(inputImageTexture, textureCoordinate).rgb;
-
- texel = vec3(
- texture2D(inputImageTexture2, vec2(texel.r, .16666)).r,
- texture2D(inputImageTexture2, vec2(texel.g, .5)).g,
- texture2D(inputImageTexture2, vec2(texel.b, .83333)).b);
-
- vec2 tc = (2.0 * textureCoordinate) - 1.0;
- float d = dot(tc, tc);
- vec2 lookup = vec2(d, texel.r);
- texel.r = texture2D(inputImageTexture3, lookup).r;
- lookup.y = texel.g;
- texel.g = texture2D(inputImageTexture3, lookup).g;
- lookup.y = texel.b;
- texel.b = texture2D(inputImageTexture3, lookup).b;
-
- texel.rgb = mix(originColor.rgb, texel.rgb, strength);
-
- gl_FragColor = vec4(texel, 1.0);
-}
\ No newline at end of file
diff --git a/Live/src/main/res/raw/warm.glsl b/Live/src/main/res/raw/warm.glsl
deleted file mode 100644
index d2f40487..00000000
--- a/Live/src/main/res/raw/warm.glsl
+++ /dev/null
@@ -1,58 +0,0 @@
-#extension GL_OES_EGL_image_external : require
-
-precision highp float;
-
-varying highp vec2 textureCoordinate;
-
-uniform samplerExternalOES inputImageTexture;
-uniform sampler2D curve;
-uniform sampler2D greyFrame;
-uniform sampler2D layerImage;
-
-void main()
-{
- lowp vec4 textureColor;
- vec4 greyColor;
- vec4 layerColor;
-
- float xCoordinate = textureCoordinate.x;
- float yCoordinate = textureCoordinate.y;
-
- highp float redCurveValue;
- highp float greenCurveValue;
- highp float blueCurveValue;
-
- textureColor = texture2D( inputImageTexture, vec2(xCoordinate, yCoordinate));
-
- greyColor = texture2D(greyFrame, vec2(xCoordinate, yCoordinate));
- layerColor = texture2D(layerImage, vec2(xCoordinate, yCoordinate));
-
- // step1 curve
- redCurveValue = texture2D(curve, vec2(textureColor.r, 0.0)).r;
- greenCurveValue = texture2D(curve, vec2(textureColor.g, 0.0)).g;
- blueCurveValue = texture2D(curve, vec2(textureColor.b, 0.0)).b;
-
- // step2 curve with mask
- textureColor = vec4(redCurveValue, greenCurveValue, blueCurveValue, 1.0);
-
- redCurveValue = texture2D(curve, vec2(textureColor.r, 0.0)).a;
- greenCurveValue = texture2D(curve, vec2(textureColor.g, 0.0)).a;
- blueCurveValue = texture2D(curve, vec2(textureColor.b, 0.0)).a;
-
- lowp vec4 textureColor2 = vec4(redCurveValue, greenCurveValue, blueCurveValue, 1.0);
-
- // step3 screen with 60%
- lowp vec4 base = vec4(mix(textureColor.rgb, textureColor2.rgb, 1.0 - greyColor.r), textureColor.a);
- lowp vec4 overlayer = vec4(layerColor.r, layerColor.g, layerColor.b, 1.0);
-
- // screen blending
- textureColor = 1.0 - ((1.0 - base) * (1.0 - overlayer));
- textureColor = (textureColor - base) * 0.6 + base;
-
- redCurveValue = texture2D(curve, vec2(textureColor.r, 1.0)).r;
- greenCurveValue = texture2D(curve, vec2(textureColor.g, 1.0)).g;
- blueCurveValue = texture2D(curve, vec2(textureColor.b, 1.0)).b;
- textureColor = vec4(redCurveValue, greenCurveValue, blueCurveValue, 1.0);
-
- gl_FragColor = vec4(textureColor.r, textureColor.g, textureColor.b, 1.0);
-}
\ No newline at end of file
diff --git a/Live/src/main/res/raw/whitecat.glsl b/Live/src/main/res/raw/whitecat.glsl
deleted file mode 100644
index fab69d6b..00000000
--- a/Live/src/main/res/raw/whitecat.glsl
+++ /dev/null
@@ -1,104 +0,0 @@
-#extension GL_OES_EGL_image_external : require
-
-precision highp float;
-
-varying highp vec2 textureCoordinate;
-
-uniform samplerExternalOES inputImageTexture;
-uniform sampler2D curve;
-
-vec3 rgb2hsv(vec3 c)
-{
- vec4 K = vec4(0.0, -1.0 / 3.0, 2.0 / 3.0, -1.0);
- vec4 p = mix(vec4(c.bg, K.wz), vec4(c.gb, K.xy), step(c.b, c.g));
- vec4 q = mix(vec4(p.xyw, c.r), vec4(c.r, p.yzx), step(p.x, c.r));
-
- float d = q.x - min(q.w, q.y);
- float e = 1.0e-10;
- return vec3(abs(q.z + (q.w - q.y) / (6.0 * d + e)), d / (q.x + e), q.x);
-}
-
-vec3 hsv2rgb(vec3 c)
-{
- vec4 K = vec4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0);
- vec3 p = abs(fract(c.xxx + K.xyz) * 6.0 - K.www);
- return c.z * mix(K.xxx, clamp(p - K.xxx, 0.0, 1.0), c.y);
-}
-
-void main()
-{
- float GreyVal;
- lowp vec4 textureColor;
- lowp vec4 textureColorOri;
- float xCoordinate = textureCoordinate.x;
- float yCoordinate = textureCoordinate.y;
-
- highp float redCurveValue;
- highp float greenCurveValue;
- highp float blueCurveValue;
-
- textureColor = texture2D( inputImageTexture, vec2(xCoordinate, yCoordinate));
-
- // step1 20% opacity ExclusionBlending
- mediump vec4 textureColor2 = textureColor;
- textureColor2 = textureColor + textureColor2 - (2.0 * textureColor2 * textureColor);
-
- textureColor = (textureColor2 - textureColor) * 0.2 + textureColor;
-
- // step2 curve
- redCurveValue = texture2D(curve, vec2(textureColor.r, 0.0)).r;
- greenCurveValue = texture2D(curve, vec2(textureColor.g, 0.0)).g;
- blueCurveValue = texture2D(curve, vec2(textureColor.b, 0.0)).b;
-
- redCurveValue = texture2D(curve, vec2(redCurveValue, 1.0)).r;
- greenCurveValue = texture2D(curve, vec2(greenCurveValue, 1.0)).r;
- blueCurveValue = texture2D(curve, vec2(blueCurveValue, 1.0)).r;
-
- redCurveValue = texture2D(curve, vec2(redCurveValue, 1.0)).g;
- greenCurveValue = texture2D(curve, vec2(greenCurveValue, 1.0)).g;
- blueCurveValue = texture2D(curve, vec2(blueCurveValue, 1.0)).g;
-
-
- vec3 tColor = vec3(redCurveValue, greenCurveValue, blueCurveValue);
- tColor = rgb2hsv(tColor);
-
- tColor.g = tColor.g * 0.65;
-
- tColor = hsv2rgb(tColor);
- tColor = clamp(tColor, 0.0, 1.0);
-
- mediump vec4 base = vec4(tColor, 1.0);
- mediump vec4 overlay = vec4(0.62, 0.6, 0.498, 1.0);
- // step6 overlay blending
- mediump float ra;
- if (base.r < 0.5)
- {
- ra = overlay.r * base.r * 2.0;
- } else
- {
- ra = 1.0 - ((1.0 - base.r) * (1.0 - overlay.r) * 2.0);
- }
-
- mediump float ga;
- if (base.g < 0.5)
- {
- ga = overlay.g * base.g * 2.0;
- } else
- {
- ga = 1.0 - ((1.0 - base.g) * (1.0 - overlay.g) * 2.0);
- }
-
- mediump float ba;
- if (base.b < 0.5)
- {
- ba = overlay.b * base.b * 2.0;
- } else
- {
- ba = 1.0 - ((1.0 - base.b) * (1.0 - overlay.b) * 2.0);
- }
- textureColor = vec4(ra, ga, ba, 1.0);
- textureColor = (textureColor - base) * 0.1 + base;
-
- gl_FragColor = vec4(textureColor.r, textureColor.g, textureColor.b, 1.0);
-}
-
\ No newline at end of file
diff --git a/Live/src/main/res/raw/xproii_filter_shader.glsl b/Live/src/main/res/raw/xproii_filter_shader.glsl
deleted file mode 100644
index 98d9a9a9..00000000
--- a/Live/src/main/res/raw/xproii_filter_shader.glsl
+++ /dev/null
@@ -1,37 +0,0 @@
-#extension GL_OES_EGL_image_external : require
-
-precision mediump float;
-
-varying mediump vec2 textureCoordinate;
-
-uniform samplerExternalOES inputImageTexture;
-uniform sampler2D inputImageTexture2; //map
-uniform sampler2D inputImageTexture3; //vigMap
-
-uniform float strength;
-
-void main()
-{
- vec4 originColor = texture2D(inputImageTexture, textureCoordinate);
- vec3 texel = texture2D(inputImageTexture, textureCoordinate).rgb;
-
- vec2 tc = (2.0 * textureCoordinate) - 1.0;
- float d = dot(tc, tc);
- vec2 lookup = vec2(d, texel.r);
- texel.r = texture2D(inputImageTexture3, lookup).r;
- lookup.y = texel.g;
- texel.g = texture2D(inputImageTexture3, lookup).g;
- lookup.y = texel.b;
- texel.b = texture2D(inputImageTexture3, lookup).b;
-
- vec2 red = vec2(texel.r, 0.16666);
- vec2 green = vec2(texel.g, 0.5);
- vec2 blue = vec2(texel.b, .83333);
- texel.r = texture2D(inputImageTexture2, red).r;
- texel.g = texture2D(inputImageTexture2, green).g;
- texel.b = texture2D(inputImageTexture2, blue).b;
-
- texel.rgb = mix(originColor.rgb, texel.rgb, strength);
-
- gl_FragColor = vec4(texel, 1.0);
-}
\ No newline at end of file
diff --git a/Live/src/main/res/values-en/strings.xml b/Live/src/main/res/values-en/strings.xml
new file mode 100644
index 00000000..01ee3a77
--- /dev/null
+++ b/Live/src/main/res/values-en/strings.xml
@@ -0,0 +1,25 @@
+
+ live
+ swap
+ start
+ stop
+ mute
+ voice
+ photo
+
+ beauty
+ cool
+ sunrise
+ sketch
+ white
+ romantic
+ raw
+
+ error of opening video encoder
+ error of video encoding
+ error of opening audio encoder
+ error of audio encoding
+ error of RTMP connecting server
+ error of RTMP connecting stream
+ error of RTMP sending packet
+
diff --git a/Live/src/main/res/values/strings.xml b/Live/src/main/res/values/strings.xml
index 82d655b2..8cb9785e 100644
--- a/Live/src/main/res/values/strings.xml
+++ b/Live/src/main/res/values/strings.xml
@@ -3,4 +3,23 @@
切换
开始
停止
+ 静音
+ 取消静音
+ 拍照
+
+ 美颜
+ 冷酷
+ 日出
+ 素描
+ 纯白
+ 浪漫
+ 原图
+
+ 打开视频编码器失败
+ 视频编码失败
+ 打开音频编码器失败
+ 音频编码失败
+ RTMP连接服务器失败
+ RTMP连接流失败
+ RTMP发送数据包失败
diff --git a/Live/src/test/java/com/frank/live/ExampleUnitTest.java b/Live/src/test/java/com/frank/live/ExampleUnitTest.java
deleted file mode 100644
index f08de73f..00000000
--- a/Live/src/test/java/com/frank/live/ExampleUnitTest.java
+++ /dev/null
@@ -1,17 +0,0 @@
-package com.frank.live;
-
-import org.junit.Test;
-
-import static org.junit.Assert.*;
-
-/**
- * Example local unit test, which will execute on the development machine (host).
- *
- * @see Testing documentation
- */
-public class ExampleUnitTest {
- @Test
- public void addition_isCorrect() throws Exception {
- assertEquals(4, 2 + 2);
- }
-}
\ No newline at end of file
diff --git a/NextPlayer/.gitignore b/NextPlayer/.gitignore
new file mode 100644
index 00000000..796b96d1
--- /dev/null
+++ b/NextPlayer/.gitignore
@@ -0,0 +1 @@
+/build
diff --git a/NextPlayer/build.gradle b/NextPlayer/build.gradle
new file mode 100644
index 00000000..47b850a2
--- /dev/null
+++ b/NextPlayer/build.gradle
@@ -0,0 +1,65 @@
+plugins {
+ id 'com.android.library'
+ id 'maven-publish'
+}
+
+android {
+ compileSdk 34
+ namespace "com.frank.next"
+
+ defaultConfig {
+ minSdk 21
+ targetSdk 34
+
+ consumerProguardFiles "consumer-rules.pro"
+ ndk {
+ abiFilters "arm64-v8a", "armeabi-v7a"
+ }
+ externalNativeBuild {
+ cmake {
+ arguments '-DANDROID_STL=c++_shared'
+ }
+ }
+ }
+
+ sourceSets {
+ main {
+ jniLibs.srcDirs = ["libs"]
+ }
+ }
+
+ buildTypes {
+ release {
+ minifyEnabled false
+ proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
+ }
+ }
+
+ compileOptions {
+ sourceCompatibility JavaVersion.VERSION_1_8
+ targetCompatibility JavaVersion.VERSION_1_8
+ }
+
+// externalNativeBuild {
+// cmake {
+// path "../../engine/CMakeLists.txt"
+// }
+// }
+
+ composeOptions {
+ kotlinCompilerExtensionVersion '1.3.2'
+ }
+
+ publishing {
+ singleVariant('release') {
+ withSourcesJar()
+ withJavadocJar()
+ }
+ }
+}
+
+dependencies {
+ implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
+ implementation "androidx.core:core-ktx:$rootProject.core_ktx"
+ implementation "androidx.appcompat:appcompat:$rootProject.appcompatVersion"
+}
diff --git a/NextPlayer/proguard-rules.pro b/NextPlayer/proguard-rules.pro
new file mode 100644
index 00000000..481bb434
--- /dev/null
+++ b/NextPlayer/proguard-rules.pro
@@ -0,0 +1,21 @@
+# Add project specific ProGuard rules here.
+# You can control the set of applied configuration files using the
+# proguardFiles setting in build.gradle.
+#
+# For more details, see
+# http://developer.android.com/guide/developing/tools/proguard.html
+
+# If your project uses WebView with JS, uncomment the following
+# and specify the fully qualified class name to the JavaScript interface
+# class:
+#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
+# public *;
+#}
+
+# Uncomment this to preserve the line number information for
+# debugging stack traces.
+#-keepattributes SourceFile,LineNumberTable
+
+# If you keep the line number information, uncomment this to
+# hide the original source file name.
+#-renamesourcefileattribute SourceFile
\ No newline at end of file
diff --git a/NextPlayer/src/main/AndroidManifest.xml b/NextPlayer/src/main/AndroidManifest.xml
new file mode 100644
index 00000000..f9c7cbd8
--- /dev/null
+++ b/NextPlayer/src/main/AndroidManifest.xml
@@ -0,0 +1,5 @@
+
+
+
+
\ No newline at end of file
diff --git a/NextPlayer/src/main/java/com/frank/next/loader/LibraryLoader.java b/NextPlayer/src/main/java/com/frank/next/loader/LibraryLoader.java
new file mode 100644
index 00000000..ec378bb1
--- /dev/null
+++ b/NextPlayer/src/main/java/com/frank/next/loader/LibraryLoader.java
@@ -0,0 +1,24 @@
+package com.frank.next.loader;
+
+public class LibraryLoader {
+
+ private static volatile boolean isLibsLoaded = false;
+
+ private static final Object loadLock = new Object();
+
+ public static void loadLibsOnce() {
+ synchronized (loadLock) {
+ if (!isLibsLoaded) {
+ System.loadLibrary("c++_shared");
+ System.loadLibrary("ffmpeg");
+ System.loadLibrary("common");
+ System.loadLibrary("demux");
+ System.loadLibrary("decode");
+ System.loadLibrary("render");
+ System.loadLibrary("nextplayer");
+ isLibsLoaded = true;
+ }
+ }
+ }
+
+}
diff --git a/NextPlayer/src/main/java/com/frank/next/player/BasePlayer.java b/NextPlayer/src/main/java/com/frank/next/player/BasePlayer.java
new file mode 100644
index 00000000..1af106c2
--- /dev/null
+++ b/NextPlayer/src/main/java/com/frank/next/player/BasePlayer.java
@@ -0,0 +1,107 @@
+package com.frank.next.player;
+
+/**
+ * Note: base of player
+ * Date: 2026/1/8
+ * Author: frank
+ */
+public abstract class BasePlayer implements IPlayer {
+
+ private OnInfoListener mOnInfoListener;
+ private OnErrorListener mOnErrorListener;
+ private OnCompleteListener mOnCompleteListener;
+ private OnPreparedListener mOnPreparedListener;
+ private OnBufferUpdateListener mOnBufferUpdateListener;
+ private OnSeekCompleteListener mOnSeekCompleteListener;
+ private OnVideoSizeChangedListener mOnVideoSizeChangedListener;
+
+ public BasePlayer() {
+ }
+
+ @Override
+ public final void setOnPreparedListener(IPlayer.OnPreparedListener listener) {
+ this.mOnPreparedListener = listener;
+ }
+
+ @Override
+ public final void setOnCompletionListener(OnCompleteListener listener) {
+ this.mOnCompleteListener = listener;
+ }
+
+ @Override
+ public final void setOnBufferingUpdateListener(OnBufferUpdateListener listener) {
+ this.mOnBufferUpdateListener = listener;
+ }
+
+ @Override
+ public final void setOnSeekCompleteListener(IPlayer.OnSeekCompleteListener listener) {
+ this.mOnSeekCompleteListener = listener;
+ }
+
+ @Override
+ public final void setOnVideoSizeChangedListener(IPlayer.OnVideoSizeChangedListener listener) {
+ this.mOnVideoSizeChangedListener = listener;
+ }
+
+ @Override
+ public final void setOnErrorListener(IPlayer.OnErrorListener listener) {
+ this.mOnErrorListener = listener;
+ }
+
+ @Override
+ public final void setOnInfoListener(IPlayer.OnInfoListener listener) {
+ this.mOnInfoListener = listener;
+ }
+
+ @Override
+ public void setOnPlayingListener(OnPlayingListener listener) {
+
+ }
+
+ public void resetListeners() {
+ this.mOnInfoListener = null;
+ this.mOnErrorListener = null;
+ this.mOnPreparedListener = null;
+ this.mOnCompleteListener = null;
+ this.mOnSeekCompleteListener = null;
+ this.mOnBufferUpdateListener = null;
+ this.mOnVideoSizeChangedListener = null;
+ }
+
+ protected final void onPrepared() {
+ if (this.mOnPreparedListener != null) {
+ this.mOnPreparedListener.onPrepared(this);
+ }
+ }
+
+ protected void onVideoSizeChanged(int width, int height, int sarNum, int sarDen) {
+ if (this.mOnVideoSizeChangedListener != null) {
+ this.mOnVideoSizeChangedListener.onVideoSizeChanged( width, height);
+ }
+ }
+
+ protected void onInfo(int what, int extra) {
+ if (mOnInfoListener != null) {
+ mOnInfoListener.onInfo(what, extra);
+ }
+ }
+
+ protected void onError(int what, int extra) {
+ if (this.mOnErrorListener != null) {
+ this.mOnErrorListener.onError(what, extra);
+ }
+ }
+
+ protected void onSeekComplete() {
+ if (this.mOnSeekCompleteListener != null) {
+ this.mOnSeekCompleteListener.onSeekComplete(this);
+ }
+ }
+
+ protected final void onComplete() {
+ if (this.mOnCompleteListener != null) {
+ this.mOnCompleteListener.onComplete(this);
+ }
+ }
+
+}
diff --git a/NextPlayer/src/main/java/com/frank/next/player/IPlayer.java b/NextPlayer/src/main/java/com/frank/next/player/IPlayer.java
new file mode 100644
index 00000000..3903773e
--- /dev/null
+++ b/NextPlayer/src/main/java/com/frank/next/player/IPlayer.java
@@ -0,0 +1,179 @@
+package com.frank.next.player;
+
+import android.view.Surface;
+import android.view.SurfaceHolder;
+
+import java.io.IOException;
+import java.util.Map;
+
+/**
+ * Note: interface of player
+ * Date: 2026/1/6
+ * Author: frank
+ */
+public interface IPlayer {
+
+ /**********************************message begin**********************************/
+
+ int MSG_COMPONENT_OPEN = 1000;
+ int MSG_OPEN_INPUT = 1001;
+ int MSG_FIND_STREAM_INFO = 1002;
+ int MSG_VIDEO_FIRST_PACKET = 1004;
+ int MSG_VIDEO_DECODE_START = 1006;
+ int MSG_ON_PREPARED = 1007;
+ int MSG_SET_VIDEO_SIZE = 1008;
+ int MSG_SET_VIDEO_SAR = 1009;
+ int MSG_ROTATION_CHANGED = 1010;
+ int MSG_VIDEO_RENDER_START = 1011;
+ int MSG_AUDIO_RENDER_START = 1012;
+ int MSG_NO_OP = 1013; // Flush
+ int MSG_ON_ERROR = 1014;
+ int MSG_ON_COMPLETED = 1015;
+ int MSG_MEDIA_INFO = 1016;
+
+ int MSG_BUFFER_START = 2000;
+ int MSG_BUFFER_UPDATE = 2001; // progress
+ int MSG_BUFFER_BYTE_UPDATE = 2002; // cached data in bytes
+ int MSG_BUFFER_TIME_UPDATE = 2003; // cached duration in ms
+ int MSG_BUFFER_END = 2004;
+
+ int MSG_SEEK_COMPLETED = 3003;
+ int MSG_PLAY_URL_CHANGED = 3006;
+
+ /*******************************PlayControl begin*********************************/
+
+ void prepareAsync() throws IllegalStateException;
+
+ void start() throws IllegalStateException;
+
+ void pause() throws IllegalStateException;
+
+ void seekTo(long msec) throws IllegalStateException;
+
+ void stop() throws IllegalStateException;
+
+ void reset();
+
+ void release();
+
+ /***********************************Set begin************************************/
+
+ void setCachePath(String path);
+
+ void setEnableMediaCodec(boolean enable);
+
+ void setDataSource(String path) throws IOException, IllegalStateException;
+
+ void setDataSource(String path, Map headers) throws IOException, IllegalStateException;
+
+ void setSurface(Surface surface);
+
+ void setDisplay(SurfaceHolder sh);
+
+ void setSpeed(float speed);
+
+ void setVolume(float leftVolume, float rightVolume);
+
+ void setScreenOnWhilePlaying(boolean screenOn);
+
+
+ /**********************************Get begin***********************************/
+
+ String getAudioCodecInfo();
+
+ String getVideoCodecInfo();
+
+ int getVideoWidth();
+
+ int getVideoHeight();
+
+ long getCurrentPosition();
+
+ long getDuration();
+
+ String getPlayUrl() throws IllegalStateException;
+
+ int getVideoSarNum();
+
+ int getVideoSarDen();
+
+ int getVideoDecoder();
+
+ float getVideoFrameRate();
+
+ float getVideoDecodeFrameRate();
+
+ float getVideoRenderFrameRate();
+
+ long getVideoCacheTime();
+
+ long getAudioCacheTime();
+
+ long getVideoCacheSize();
+
+ long getAudioCacheSize();
+
+ long getBitRate();
+
+ long getFileSize();
+
+ boolean isPlaying();
+
+ int getPlayerState();
+
+ long getSeekCostTime();
+
+ String getDataSource();
+
+
+ /**********************************interface begin**********************************/
+
+ void setOnPreparedListener(OnPreparedListener listener);
+
+ void setOnInfoListener(OnInfoListener listener);
+
+ void setOnErrorListener(OnErrorListener listener);
+
+ void setOnBufferingUpdateListener(OnBufferUpdateListener listener);
+
+ void setOnVideoSizeChangedListener(OnVideoSizeChangedListener listener);
+
+ void setOnSeekCompleteListener(OnSeekCompleteListener listener);
+
+ void setOnCompletionListener(OnCompleteListener listener);
+
+ void setOnPlayingListener(OnPlayingListener listener);
+
+ interface OnPreparedListener {
+ void onPrepared(IPlayer mp);
+ }
+
+ interface OnBufferUpdateListener {
+ void onBufferUpdate(int progress);
+ }
+
+ interface OnVideoSizeChangedListener {
+ void onVideoSizeChanged(int width, int height);
+ }
+
+ interface OnInfoListener {
+ boolean onInfo(int what, int extra);
+ }
+
+ interface OnErrorListener {
+ boolean onError(int what, int extra);
+ }
+
+ interface OnSeekCompleteListener {
+ void onSeekComplete(IPlayer mp);
+ }
+
+ interface OnCompleteListener {
+ void onComplete(IPlayer mp);
+ }
+
+ interface OnPlayingListener {
+ void onPlaying(boolean playing);
+ }
+
+}
diff --git a/NextPlayer/src/main/java/com/frank/next/player/NextPlayer.java b/NextPlayer/src/main/java/com/frank/next/player/NextPlayer.java
new file mode 100644
index 00000000..6b7a779a
--- /dev/null
+++ b/NextPlayer/src/main/java/com/frank/next/player/NextPlayer.java
@@ -0,0 +1,497 @@
+package com.frank.next.player;
+
+import android.content.Context;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
+import android.text.TextUtils;
+import android.util.Log;
+import android.view.Surface;
+import android.view.SurfaceHolder;
+
+import androidx.annotation.NonNull;
+
+import com.frank.next.loader.LibraryLoader;
+
+import java.io.IOException;
+import java.lang.ref.WeakReference;
+import java.nio.charset.StandardCharsets;
+import java.util.Map;
+import java.util.concurrent.atomic.AtomicInteger;
+
+
+public class NextPlayer extends BasePlayer {
+ private final static String TAG = NextPlayer.class.getName();
+
+ enum LogLevel {
+ LOG_DEFAULT,
+ LOG_DEBUG,
+ LOG_INFO,
+ LOG_WARN,
+ LOG_ERROR
+ }
+
+ private static final int gLogCallBackLevel = LogLevel.LOG_DEBUG.ordinal();
+ private static NativeLogCallback mNativeLogListener;
+
+ private int mPlayerId; // call from native
+ private int mVideoWidth;
+ private int mVideoHeight;
+ private int mVideoSarNum;
+ private int mVideoSarDen;
+
+ private String mDataSource;
+ private EventHandler mEventHandler;
+ private SurfaceHolder mSurfaceHolder;
+ private static final AtomicInteger mAtomicInteger = new AtomicInteger(0);
+
+ private static volatile boolean mNativeInitialized = false;
+
+ public static void loadLibraryOnce() {
+ LibraryLoader.loadLibsOnce();
+ }
+
+ private static void initOnce() {
+ synchronized (NextPlayer.class) {
+ if (!mNativeInitialized) {
+ native_init();
+ mNativeInitialized = true;
+ }
+ }
+ }
+
+ public NextPlayer() {
+ this(null);
+ }
+
+ public NextPlayer(Context context) {
+ initPlayer(context);
+ }
+
+ private void initPlayer(Context context) {
+ loadLibraryOnce();
+ initOnce();
+
+ Looper looper;
+ if ((looper = Looper.myLooper()) != null) {
+ mEventHandler = new EventHandler(this, looper);
+ } else if ((looper = Looper.getMainLooper()) != null) {
+ mEventHandler = new EventHandler(this, looper);
+ } else {
+ mEventHandler = null;
+ }
+ mPlayerId = mAtomicInteger.addAndGet(1);
+ native_setup(new WeakReference<>(this));
+ }
+
+ @Override
+ public void setDisplay(SurfaceHolder holder) throws IllegalStateException {
+ mSurfaceHolder = holder;
+ Surface surface;
+ if (holder != null) {
+ surface = holder.getSurface();
+ } else {
+ surface = null;
+ }
+ _setVideoSurface(surface);
+ }
+
+ @Override
+ public void setDataSource(String path, Map headers)
+ throws IOException, IllegalStateException {
+ if (headers != null && !headers.isEmpty()) {
+ StringBuilder sb = new StringBuilder();
+ for (Map.Entry entry : headers.entrySet()) {
+ sb.append(entry.getKey());
+ sb.append(":");
+ String value = entry.getValue();
+ if (!TextUtils.isEmpty(value))
+ sb.append(entry.getValue());
+ sb.append("\r\n");
+ _setHeaders(sb.toString());
+ }
+ }
+ setDataSource(path);
+ }
+
+ @Override
+ public void setDataSource(String path) throws IOException, IllegalStateException {
+ mDataSource = path;
+ _setDataSource(path);
+ }
+
+ @Override
+ public String getDataSource() {
+ return mDataSource;
+ }
+
+ @Override
+ public void prepareAsync() throws IllegalStateException {
+ _prepareAsync();
+ }
+
+ @Override
+ public void start() throws IllegalStateException {
+ _start();
+ }
+
+ @Override
+ public void stop() throws IllegalStateException {
+ _stop();
+ }
+
+ @Override
+ public void pause() throws IllegalStateException {
+ _pause();
+ }
+
+ @Override
+ public void setScreenOnWhilePlaying(boolean screenOn) {
+ if (mSurfaceHolder != null) {
+ mSurfaceHolder.setKeepScreenOn(screenOn);
+ }
+ }
+
+ @Override
+ public void setEnableMediaCodec(boolean enable) {
+ _setEnableMediaCodec(enable);
+ }
+
+ @Override
+ public void setCachePath(String path) {
+ _setVideoCacheDir(path);
+ }
+
+ @Override
+ public String getAudioCodecInfo() {
+ return _getAudioCodecInfo();
+ }
+
+ @Override
+ public String getVideoCodecInfo() {
+ return _getVideoCodecInfo();
+ }
+
+ @Override
+ public float getVideoFrameRate() {
+ return _getVideoFileFps();
+ }
+
+ @Override
+ public int getVideoWidth() {
+ return mVideoWidth;
+ }
+
+ @Override
+ public int getVideoHeight() {
+ return mVideoHeight;
+ }
+
+ @Override
+ public boolean isPlaying() {
+ return _playing();
+ }
+
+ @Override
+ public void seekTo(long msec) throws IllegalStateException {
+ _seekTo(msec);
+ }
+
+ @Override
+ public long getCurrentPosition() {
+ return _getCurrentPosition();
+ }
+
+ @Override
+ public long getDuration() {
+ return _getDuration();
+ }
+
+ @Override
+ public void release() {
+ resetListeners();
+ _release();
+ }
+
+ @Override
+ public void reset() {
+ _reset();
+ mEventHandler.removeCallbacksAndMessages(null);
+ mVideoWidth = 0;
+ mVideoHeight = 0;
+ }
+
+ @Override
+ public void setVolume(float leftVolume, float rightVolume) {
+ _setVolume(leftVolume, rightVolume);
+ }
+
+ @Override
+ public String getPlayUrl() throws IllegalStateException {
+ return _getPlayUrl();
+ }
+
+ @Override
+ public int getVideoSarNum() {
+ return mVideoSarNum;
+ }
+
+ @Override
+ public int getVideoSarDen() {
+ return mVideoSarDen;
+ }
+
+ @Override
+ public void setSurface(Surface surface) {
+ mSurfaceHolder = null;
+ _setVideoSurface(surface);
+ }
+
+ @Override
+ public void setSpeed(float speed) {
+ _setSpeed(speed);
+ }
+
+ @Override
+ public int getVideoDecoder() {
+ return _getVideoDecoder();
+ }
+
+ @Override
+ public float getVideoRenderFrameRate() {
+ return _getVideoRenderFrameRate();
+ }
+
+ @Override
+ public float getVideoDecodeFrameRate() {
+ return _getVideoDecodeFrameRate();
+ }
+
+ @Override
+ public long getVideoCacheTime() {
+ return _getVideoCachedTime();
+ }
+
+ @Override
+ public long getAudioCacheTime() {
+ return _getAudioCachedTime();
+ }
+
+ @Override
+ public long getVideoCacheSize() {
+ return _getVideoCachedSize();
+ }
+
+ @Override
+ public long getAudioCacheSize() {
+ return _getAudioCachedSize();
+ }
+
+ @Override
+ public long getFileSize() {
+ return _getFileSize();
+ }
+
+ @Override
+ public long getBitRate() {
+ return _getBitRate();
+ }
+
+ @Override
+ public long getSeekCostTime() {
+ return _getSeekCostTime();
+ }
+
+ @Override
+ public int getPlayerState() {
+ return _getPlayerState();
+ }
+
+ private static class EventHandler extends Handler {
+ private final WeakReference mWeakPlayer;
+
+ public EventHandler(NextPlayer mp, Looper looper) {
+ super(looper);
+ mWeakPlayer = new WeakReference<>(mp);
+ }
+
+ @Override
+ public void handleMessage(@NonNull Message msg) {
+ NextPlayer player = mWeakPlayer.get();
+ if (player == null) {
+ return;
+ }
+
+ switch (msg.what) {
+ case MSG_ON_PREPARED:
+ player.onPrepared();
+ return;
+
+ case MSG_ON_COMPLETED:
+ player.onComplete();
+ return;
+
+ case MSG_BUFFER_UPDATE:
+ return;
+
+ case MSG_SEEK_COMPLETED: {
+ player.onSeekComplete();
+ player.onInfo(MSG_SEEK_COMPLETED, msg.arg2);
+ return;
+ }
+
+ case MSG_SET_VIDEO_SIZE:
+ player.mVideoWidth = msg.arg1;
+ player.mVideoHeight = msg.arg2;
+ player.onVideoSizeChanged(player.mVideoWidth, player.mVideoHeight,
+ player.mVideoSarNum, player.mVideoSarDen);
+ return;
+
+ case MSG_ON_ERROR:
+ player.onError(msg.arg1, msg.arg2);
+ if (msg.arg2 >= 0) {
+ player.onComplete();
+ }
+ return;
+
+ case MSG_MEDIA_INFO:
+ switch (msg.arg1) {
+ case MSG_VIDEO_RENDER_START:
+ break;
+ case MSG_PLAY_URL_CHANGED:
+ player.onInfo(msg.arg1, (Integer) msg.obj);
+ return;
+ }
+ player.onInfo(msg.arg1, msg.arg2);
+ return;
+
+ case MSG_SET_VIDEO_SAR:
+ player.mVideoSarNum = msg.arg1;
+ player.mVideoSarDen = msg.arg2;
+ player.onVideoSizeChanged(player.mVideoWidth, player.mVideoHeight,
+ player.mVideoSarNum, player.mVideoSarDen);
+ break;
+
+ default:
+ break;
+ }
+ }
+ }
+
+ private static void postEventFromNative(Object weakThiz, int what, int arg1, int arg2, Object obj) {
+ if (weakThiz == null)
+ return;
+
+ NextPlayer mp = (NextPlayer) ((WeakReference>) weakThiz).get();
+ if (mp == null) {
+ return;
+ }
+
+ if (mp.mEventHandler != null) {
+ Message m = mp.mEventHandler.obtainMessage(what, arg1, arg2);
+ mp.mEventHandler.sendMessage(m);
+ }
+ }
+
+ private static void onNativeLog(int level, String tag, byte[] logContent) {
+ if (level < gLogCallBackLevel) {
+ return;
+ }
+ String logStr = new String(logContent, StandardCharsets.UTF_8);
+ if (mNativeLogListener != null) {
+ mNativeLogListener.onLogOutput(level, tag, logStr);
+ } else {
+ Log.println(level, tag, logStr);
+ }
+ }
+
+ private static void log(int level, String log) {
+ if (level < gLogCallBackLevel) {
+ return;
+ }
+ if (mNativeLogListener != null) {
+ mNativeLogListener.onLogOutput(level, TAG, log);
+ } else {
+ Log.println(level, TAG, log);
+ }
+ }
+
+ public static void setNativeLogCallback(NativeLogCallback nativeLogCallback) {
+ mNativeLogListener = nativeLogCallback;
+ }
+
+ public interface NativeLogCallback {
+ void onLogOutput(int logLevel, String tag, String log);
+ }
+
+
+ private static native void native_init();
+
+ private native void native_setup(Object player);
+
+ private native void _setVideoSurface(Surface surface) throws IllegalStateException;
+
+ private native void _setHeaders(String headers);
+
+ private native void _setDataSource(String path)
+ throws IOException, IllegalArgumentException, SecurityException, IllegalStateException;
+
+ private native void _prepareAsync() throws IllegalStateException;
+
+ private native void _start() throws IllegalStateException;
+
+ private native void _stop() throws IllegalStateException;
+
+ private native void _pause() throws IllegalStateException;
+
+ private native void _setEnableMediaCodec(boolean enable);
+
+ private native void _setVideoCacheDir(String dir);
+
+ private native String _getAudioCodecInfo();
+
+ private native String _getVideoCodecInfo();
+
+ private native float _getVideoFileFps();
+
+ private native boolean _playing();
+
+ private native void _seekTo(long msec) throws IllegalStateException;
+
+ private native long _getCurrentPosition();
+
+ private native long _getDuration();
+
+ private native void _reset();
+
+ private native void _setVolume(float leftVolume, float rightVolume);
+
+ private native String _getPlayUrl();
+
+ private native void _setSpeed(float speed);
+
+ private native int _getVideoDecoder();
+
+ private native float _getVideoRenderFrameRate();
+
+ private native float _getVideoDecodeFrameRate();
+
+ private native long _getVideoCachedTime(); // ms
+
+ private native long _getAudioCachedTime();
+
+ private native long _getVideoCachedSize(); // byte
+
+ private native long _getAudioCachedSize();
+
+ private native long _getFileSize();
+
+ private native long _getBitRate();
+
+ private native long _getSeekCostTime();
+
+ private native int _getPlayerState();
+
+ private native void _release();
+
+}
diff --git a/NextPlayer/src/main/java/com/frank/next/renderview/IRenderView.java b/NextPlayer/src/main/java/com/frank/next/renderview/IRenderView.java
new file mode 100644
index 00000000..a7f4ec44
--- /dev/null
+++ b/NextPlayer/src/main/java/com/frank/next/renderview/IRenderView.java
@@ -0,0 +1,55 @@
+package com.frank.next.renderview;
+
+import android.graphics.SurfaceTexture;
+import android.view.Surface;
+import android.view.SurfaceHolder;
+import android.view.View;
+
+import com.frank.next.player.IPlayer;
+
+public interface IRenderView {
+ int RENDER_MODE_ASPECT_FIT = 0; // without clip
+ int RENDER_MODE_ASPECT_FILL = 1; // may clip
+ int RENDER_MODE_16_9 = 2;
+ int RENDER_MODE_4_3 = 3;
+ int RENDER_MODE_WRAP = 4;
+ int RENDER_MODE_MATCH = 5;
+
+ View getView();
+
+ boolean waitForResize();
+
+ void setVideoRotation(int degree);
+
+ void setAspectRatio(int aspectRatio);
+
+ void addRenderCallback(IRenderCallback callback);
+
+ void removeRenderCallback(IRenderCallback callback);
+
+ void setVideoSize(int videoWidth, int videoHeight);
+
+ void setVideoAspectRatio(int videoSarNum, int videoSarDen);
+
+ interface ISurfaceHolder {
+
+ Surface openSurface();
+
+ void bindPlayer(IPlayer mp);
+
+ IRenderView getRenderView();
+
+ SurfaceHolder getSurfaceHolder();
+
+ SurfaceTexture getSurfaceTexture();
+ }
+
+ interface IRenderCallback {
+
+ void onSurfaceCreated(ISurfaceHolder holder, int width, int height);
+
+ void onSurfaceChanged(ISurfaceHolder holder, int format, int width, int height);
+
+ void onSurfaceDestroyed(ISurfaceHolder holder);
+ }
+}
diff --git a/NextPlayer/src/main/java/com/frank/next/renderview/MeasureHelper.java b/NextPlayer/src/main/java/com/frank/next/renderview/MeasureHelper.java
new file mode 100644
index 00000000..daa94af9
--- /dev/null
+++ b/NextPlayer/src/main/java/com/frank/next/renderview/MeasureHelper.java
@@ -0,0 +1,169 @@
+package com.frank.next.renderview;
+
+import android.view.View;
+
+import java.lang.ref.WeakReference;
+
+
+public final class MeasureHelper {
+
+ private int mVideoWidth;
+ private int mVideoHeight;
+ private int mVideoSarNum;
+ private int mVideoSarDen;
+ private int mMeasuredWidth;
+ private int mMeasuredHeight;
+ private int mVideoRotationDegree;
+ private int mCurrentAspectRatio = IRenderView.RENDER_MODE_ASPECT_FIT;
+
+ private final WeakReference mWeakView;
+
+ public MeasureHelper(View view) {
+ mWeakView = new WeakReference<>(view);
+ }
+
+ public View getView() {
+ return mWeakView.get();
+ }
+
+ public int getMeasuredWidth() {
+ return mMeasuredWidth;
+ }
+
+ public int getMeasuredHeight() {
+ return mMeasuredHeight;
+ }
+
+ public void setAspectRatio(int aspectRatio) {
+ mCurrentAspectRatio = aspectRatio;
+ }
+
+ public void setVideoSize(int videoWidth, int videoHeight) {
+ mVideoWidth = videoWidth;
+ mVideoHeight = videoHeight;
+ }
+
+ public void setVideoRotation(int videoRotationDegree) {
+ mVideoRotationDegree = videoRotationDegree;
+ }
+
+ public void setVideoSampleAspectRatio(int videoSarNum, int videoSarDen) {
+ mVideoSarNum = videoSarNum;
+ mVideoSarDen = videoSarDen;
+ }
+
+ public void doMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+ if (mVideoRotationDegree == 90 || mVideoRotationDegree == 270) {
+ int tempSpec = widthMeasureSpec;
+ widthMeasureSpec = heightMeasureSpec;
+ heightMeasureSpec = tempSpec;
+ }
+
+ int width = View.getDefaultSize(mVideoWidth, widthMeasureSpec);
+ int height = View.getDefaultSize(mVideoHeight, heightMeasureSpec);
+
+ if (mCurrentAspectRatio == IRenderView.RENDER_MODE_MATCH) {
+ width = widthMeasureSpec;
+ height = heightMeasureSpec;
+ } else if (mVideoWidth > 0 && mVideoHeight > 0) {
+ int widthSpecMode = View.MeasureSpec.getMode(widthMeasureSpec);
+ int widthSpecSize = View.MeasureSpec.getSize(widthMeasureSpec);
+ int heightSpecMode = View.MeasureSpec.getMode(heightMeasureSpec);
+ int heightSpecSize = View.MeasureSpec.getSize(heightMeasureSpec);
+
+ if (widthSpecMode == View.MeasureSpec.AT_MOST && heightSpecMode == View.MeasureSpec.AT_MOST) {
+ float specAspectRatio = (float) widthSpecSize / (float) heightSpecSize;
+ float displayAspectRatio;
+ switch (mCurrentAspectRatio) {
+ case IRenderView.RENDER_MODE_16_9:
+ displayAspectRatio = 16.0f / 9.0f;
+ if (mVideoRotationDegree == 90 || mVideoRotationDegree == 270)
+ displayAspectRatio = 1.0f / displayAspectRatio;
+ break;
+ case IRenderView.RENDER_MODE_4_3:
+ displayAspectRatio = 4.0f / 3.0f;
+ if (mVideoRotationDegree == 90 || mVideoRotationDegree == 270)
+ displayAspectRatio = 1.0f / displayAspectRatio;
+ break;
+ case IRenderView.RENDER_MODE_ASPECT_FIT:
+ case IRenderView.RENDER_MODE_ASPECT_FILL:
+ case IRenderView.RENDER_MODE_WRAP:
+ default:
+ displayAspectRatio = (float) mVideoWidth / (float) mVideoHeight;
+ if (mVideoSarNum > 0 && mVideoSarDen > 0)
+ displayAspectRatio = displayAspectRatio * mVideoSarNum / mVideoSarDen;
+ break;
+ }
+
+ boolean maybeWider = displayAspectRatio > specAspectRatio;
+
+ switch (mCurrentAspectRatio) {
+ case IRenderView.RENDER_MODE_ASPECT_FIT:
+ case IRenderView.RENDER_MODE_16_9:
+ case IRenderView.RENDER_MODE_4_3:
+ if (maybeWider) {
+ width = widthSpecSize;
+ height = (int) (width / displayAspectRatio);
+ } else {
+ width = (int) (height * displayAspectRatio);
+ height = heightSpecSize;
+ }
+ break;
+ case IRenderView.RENDER_MODE_ASPECT_FILL:
+ if (maybeWider) {
+ height = heightSpecSize;
+ width = (int) (height * displayAspectRatio);
+ } else {
+ width = widthSpecSize;
+ height = (int) (width / displayAspectRatio);
+ }
+ break;
+ case IRenderView.RENDER_MODE_WRAP:
+ default:
+ if (maybeWider) {
+ width = Math.min(mVideoWidth, widthSpecSize);
+ height = (int) (width / displayAspectRatio);
+ } else {
+ height = Math.min(mVideoHeight, heightSpecSize);
+ width = (int) (height * displayAspectRatio);
+ }
+ break;
+ }
+ } else if (widthSpecMode == View.MeasureSpec.EXACTLY && heightSpecMode == View.MeasureSpec.EXACTLY) {
+ width = widthSpecSize;
+ height = heightSpecSize;
+ if (mVideoWidth * height < width * mVideoHeight) {
+ width = height * mVideoWidth / mVideoHeight;
+ } else if (mVideoWidth * height > width * mVideoHeight) {
+ height = width * mVideoHeight / mVideoWidth;
+ }
+ } else if (widthSpecMode == View.MeasureSpec.EXACTLY) {
+ width = widthSpecSize;
+ height = width * mVideoHeight / mVideoWidth;
+ if (heightSpecMode == View.MeasureSpec.AT_MOST && height > heightSpecSize) {
+ height = heightSpecSize;
+ }
+ } else if (heightSpecMode == View.MeasureSpec.EXACTLY) {
+ width = height * mVideoWidth / mVideoHeight;
+ height = heightSpecSize;
+ if (widthSpecMode == View.MeasureSpec.AT_MOST && width > widthSpecSize) {
+ width = widthSpecSize;
+ }
+ } else {
+ width = mVideoWidth;
+ height = mVideoHeight;
+ if (heightSpecMode == View.MeasureSpec.AT_MOST && height > heightSpecSize) {
+ width = height * mVideoWidth / mVideoHeight;
+ height = heightSpecSize;
+ }
+ if (widthSpecMode == View.MeasureSpec.AT_MOST && width > widthSpecSize) {
+ width = widthSpecSize;
+ height = width * mVideoHeight / mVideoWidth;
+ }
+ }
+ }
+ mMeasuredWidth = width;
+ mMeasuredHeight = height;
+ }
+
+}
diff --git a/NextPlayer/src/main/java/com/frank/next/renderview/SurfaceRenderView.java b/NextPlayer/src/main/java/com/frank/next/renderview/SurfaceRenderView.java
new file mode 100644
index 00000000..b94e2606
--- /dev/null
+++ b/NextPlayer/src/main/java/com/frank/next/renderview/SurfaceRenderView.java
@@ -0,0 +1,226 @@
+package com.frank.next.renderview;
+
+import android.content.Context;
+import android.graphics.SurfaceTexture;
+import android.util.AttributeSet;
+import android.view.Surface;
+import android.view.SurfaceHolder;
+import android.view.SurfaceView;
+import android.view.View;
+import android.view.accessibility.AccessibilityEvent;
+import android.view.accessibility.AccessibilityNodeInfo;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
+import com.frank.next.player.IPlayer;
+
+import java.lang.ref.WeakReference;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+/**
+ * Render with SurfaceView
+ */
+
+public class SurfaceRenderView extends SurfaceView implements IRenderView {
+ private MeasureHelper mMeasureHelper;
+
+ public SurfaceRenderView(Context context) {
+ super(context);
+ initView();
+ }
+
+ public SurfaceRenderView(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ initView();
+ }
+
+ public SurfaceRenderView(Context context, AttributeSet attrs, int defStyleAttr) {
+ super(context, attrs, defStyleAttr);
+ initView();
+ }
+
+ private void initView() {
+ mMeasureHelper = new MeasureHelper(this);
+ mSurfaceCallback = new SurfaceCallback(this);
+ getHolder().addCallback(mSurfaceCallback);
+ getHolder().setType(SurfaceHolder.SURFACE_TYPE_NORMAL);
+ }
+
+ @Override
+ public View getView() {
+ return this;
+ }
+
+ @Override
+ public boolean waitForResize() {
+ return true;
+ }
+
+ @Override
+ public void setVideoSize(int videoWidth, int videoHeight) {
+ if (videoWidth > 0 && videoHeight > 0) {
+ mMeasureHelper.setVideoSize(videoWidth, videoHeight);
+ getHolder().setFixedSize(videoWidth, videoHeight);
+ requestLayout();
+ }
+ }
+
+ @Override
+ public void setAspectRatio(int aspectRatio) {
+ mMeasureHelper.setAspectRatio(aspectRatio);
+ requestLayout();
+ }
+
+ @Override
+ public void setVideoAspectRatio(int videoSarNum, int videoSarDen) {
+ if (videoSarNum > 0 && videoSarDen > 0) {
+ mMeasureHelper.setVideoSampleAspectRatio(videoSarNum, videoSarDen);
+ requestLayout();
+ }
+ }
+
+ @Override
+ public void setVideoRotation(int degree) {
+
+ }
+
+ @Override
+ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+ mMeasureHelper.doMeasure(widthMeasureSpec, heightMeasureSpec);
+ setMeasuredDimension(mMeasureHelper.getMeasuredWidth(), mMeasureHelper.getMeasuredHeight());
+ }
+
+ private static final class InternalSurfaceHolder implements IRenderView.ISurfaceHolder {
+ private final SurfaceHolder mSurfaceHolder;
+ private final SurfaceRenderView mSurfaceView;
+
+ public InternalSurfaceHolder(@NonNull SurfaceRenderView surfaceView,
+ @Nullable SurfaceHolder surfaceHolder) {
+ mSurfaceView = surfaceView;
+ mSurfaceHolder = surfaceHolder;
+ }
+
+ public void bindPlayer(IPlayer mp) {
+ if (mp != null) {
+ mp.setDisplay(mSurfaceHolder);
+ }
+ }
+
+ @NonNull
+ @Override
+ public IRenderView getRenderView() {
+ return mSurfaceView;
+ }
+
+ @Nullable
+ @Override
+ public SurfaceHolder getSurfaceHolder() {
+ return mSurfaceHolder;
+ }
+
+ @Nullable
+ @Override
+ public SurfaceTexture getSurfaceTexture() {
+ return null;
+ }
+
+ @Nullable
+ @Override
+ public Surface openSurface() {
+ if (mSurfaceHolder == null)
+ return null;
+ return mSurfaceHolder.getSurface();
+ }
+ }
+
+ @Override
+ public void addRenderCallback(IRenderCallback callback) {
+ mSurfaceCallback.addRenderCallback(callback);
+ }
+
+ @Override
+ public void removeRenderCallback(IRenderCallback callback) {
+ mSurfaceCallback.removeRenderCallback(callback);
+ }
+
+ private SurfaceCallback mSurfaceCallback;
+
+ private static final class SurfaceCallback implements SurfaceHolder.Callback {
+ private SurfaceHolder mSurfaceHolder;
+ private boolean mIsFormatChanged;
+ private int mFormat;
+ private int mWidth;
+ private int mHeight;
+
+ private final WeakReference mWeakSurfaceView;
+ private final Map mRenderCallbackMap = new ConcurrentHashMap<>();
+
+ public SurfaceCallback(@NonNull SurfaceRenderView surfaceView) {
+ mWeakSurfaceView = new WeakReference<>(surfaceView);
+ }
+
+ public void addRenderCallback(@NonNull IRenderCallback callback) {
+ mRenderCallbackMap.put(callback, callback);
+ ISurfaceHolder surfaceHolder = null;
+ if (mSurfaceHolder != null) {
+ surfaceHolder = new InternalSurfaceHolder(mWeakSurfaceView.get(), mSurfaceHolder);
+ callback.onSurfaceCreated(surfaceHolder, mWidth, mHeight);
+ }
+
+ if (mIsFormatChanged) {
+ if (surfaceHolder == null)
+ surfaceHolder = new InternalSurfaceHolder(mWeakSurfaceView.get(), mSurfaceHolder);
+ callback.onSurfaceChanged(surfaceHolder, mFormat, mWidth, mHeight);
+ }
+ }
+
+ public void removeRenderCallback(@NonNull IRenderCallback callback) {
+ mRenderCallbackMap.remove(callback);
+ }
+
+ @Override
+ public void surfaceCreated(SurfaceHolder holder) {
+ mSurfaceHolder = holder;
+ ISurfaceHolder surfaceHolder = new InternalSurfaceHolder(mWeakSurfaceView.get(), mSurfaceHolder);
+ for (IRenderCallback renderCallback : mRenderCallbackMap.keySet()) {
+ renderCallback.onSurfaceCreated(surfaceHolder, 0, 0);
+ }
+ }
+
+ @Override
+ public void surfaceDestroyed(SurfaceHolder holder) {
+ mSurfaceHolder = null;
+ ISurfaceHolder surfaceHolder = new InternalSurfaceHolder(mWeakSurfaceView.get(), mSurfaceHolder);
+ for (IRenderCallback renderCallback : mRenderCallbackMap.keySet()) {
+ renderCallback.onSurfaceDestroyed(surfaceHolder);
+ }
+ }
+
+ @Override
+ public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
+ mWidth = width;
+ mHeight = height;
+ mFormat = format;
+ mSurfaceHolder = holder;
+ mIsFormatChanged = true;
+ ISurfaceHolder surfaceHolder = new InternalSurfaceHolder(mWeakSurfaceView.get(), mSurfaceHolder);
+ for (IRenderCallback renderCallback : mRenderCallbackMap.keySet()) {
+ renderCallback.onSurfaceChanged(surfaceHolder, format, width, height);
+ }
+ }
+ }
+
+ @Override
+ public void onInitializeAccessibilityEvent(AccessibilityEvent event) {
+ super.onInitializeAccessibilityEvent(event);
+ event.setClassName(SurfaceRenderView.class.getName());
+ }
+
+ @Override
+ public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
+ super.onInitializeAccessibilityNodeInfo(info);
+ info.setClassName(SurfaceRenderView.class.getName());
+ }
+}
diff --git a/NextPlayer/src/main/java/com/frank/next/renderview/TextureRenderView.java b/NextPlayer/src/main/java/com/frank/next/renderview/TextureRenderView.java
new file mode 100644
index 00000000..e570bf2b
--- /dev/null
+++ b/NextPlayer/src/main/java/com/frank/next/renderview/TextureRenderView.java
@@ -0,0 +1,281 @@
+package com.frank.next.renderview;
+
+import android.content.Context;
+import android.graphics.SurfaceTexture;
+import android.util.AttributeSet;
+import android.view.Surface;
+import android.view.SurfaceHolder;
+import android.view.TextureView;
+import android.view.View;
+import android.view.accessibility.AccessibilityEvent;
+import android.view.accessibility.AccessibilityNodeInfo;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
+import com.frank.next.player.IPlayer;
+
+import java.lang.ref.WeakReference;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+/**
+ * render of TextureView
+ */
+public class TextureRenderView extends TextureView implements IRenderView {
+
+ private static final String TAG = TextureRenderView.class.getSimpleName();
+
+ private MeasureHelper mMeasureHelper;
+
+ public TextureRenderView(Context context) {
+ super(context);
+ initView();
+ }
+
+ public TextureRenderView(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ initView();
+ }
+
+ public TextureRenderView(Context context, AttributeSet attrs, int defStyleAttr) {
+ super(context, attrs, defStyleAttr);
+ initView();
+ }
+
+ private void initView() {
+ mMeasureHelper = new MeasureHelper(this);
+ mSurfaceCallback = new SurfaceCallback(this);
+ setSurfaceTextureListener(mSurfaceCallback);
+ }
+
+ @Override
+ public View getView() {
+ return this;
+ }
+
+ @Override
+ public boolean waitForResize() {
+ return false;
+ }
+
+ @Override
+ protected void onDetachedFromWindow() {
+ mSurfaceCallback.willDetachFromWindow();
+ super.onDetachedFromWindow();
+ mSurfaceCallback.didDetachFromWindow();
+ }
+
+ @Override
+ public void setVideoSize(int videoWidth, int videoHeight) {
+ if (videoWidth > 0 && videoHeight > 0) {
+ mMeasureHelper.setVideoSize(videoWidth, videoHeight);
+ requestLayout();
+ }
+ }
+
+ @Override
+ public void setVideoAspectRatio(int videoSarNum, int videoSarDen) {
+ if (videoSarNum > 0 && videoSarDen > 0) {
+ mMeasureHelper.setVideoSampleAspectRatio(videoSarNum, videoSarDen);
+ requestLayout();
+ }
+ }
+
+ @Override
+ public void setVideoRotation(int degree) {
+ mMeasureHelper.setVideoRotation(degree);
+ setRotation(degree);
+ }
+
+ @Override
+ public void setAspectRatio(int aspectRatio) {
+ mMeasureHelper.setAspectRatio(aspectRatio);
+ requestLayout();
+ }
+
+ @Override
+ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+ mMeasureHelper.doMeasure(widthMeasureSpec, heightMeasureSpec);
+ setMeasuredDimension(mMeasureHelper.getMeasuredWidth(), mMeasureHelper.getMeasuredHeight());
+ }
+
+ public IRenderView.ISurfaceHolder getSurfaceHolder() {
+ return new VideoSurfaceHolder(this, mSurfaceCallback.mSurfaceTexture);
+ }
+
+ private static final class VideoSurfaceHolder implements IRenderView.ISurfaceHolder {
+ private final TextureRenderView mTextureView;
+ private final SurfaceTexture mSurfaceTexture;
+
+ public VideoSurfaceHolder(@NonNull TextureRenderView textureView, @Nullable SurfaceTexture surfaceTexture) {
+ mTextureView = textureView;
+ mSurfaceTexture = surfaceTexture;
+ }
+
+ public void bindPlayer(IPlayer mp) {
+ if (mp == null)
+ return;
+ mp.setSurface(openSurface());
+ }
+
+ @NonNull
+ @Override
+ public IRenderView getRenderView() {
+ return mTextureView;
+ }
+
+ @Nullable
+ @Override
+ public SurfaceHolder getSurfaceHolder() {
+ return null;
+ }
+
+ @Nullable
+ @Override
+ public SurfaceTexture getSurfaceTexture() {
+ return mSurfaceTexture;
+ }
+
+ @Nullable
+ @Override
+ public Surface openSurface() {
+ if (mSurfaceTexture == null)
+ return null;
+ return new Surface(mSurfaceTexture);
+ }
+ }
+
+ @Override
+ public void addRenderCallback(IRenderCallback callback) {
+ mSurfaceCallback.addRenderCallback(callback);
+ }
+
+ @Override
+ public void removeRenderCallback(IRenderCallback callback) {
+ mSurfaceCallback.removeRenderCallback(callback);
+ }
+
+ private SurfaceCallback mSurfaceCallback;
+
+ private static final class SurfaceCallback implements SurfaceTextureListener {
+ private int mWidth;
+ private int mHeight;
+ private boolean mFormatChanged;
+ private SurfaceTexture mSurfaceTexture;
+ private boolean mOwnSurfaceTexture = true;
+ private boolean mWillDetachFromWindow = false;
+ private boolean mDidDetachFromWindow = false;
+
+ private final WeakReference mWeakRenderView;
+ private final Map mRenderCallbackMap = new ConcurrentHashMap();
+
+ public SurfaceCallback(@NonNull TextureRenderView renderView) {
+ mWeakRenderView = new WeakReference(renderView);
+ }
+
+ public void setOwnSurfaceTexture(boolean ownSurfaceTexture) {
+ mOwnSurfaceTexture = ownSurfaceTexture;
+ }
+
+ public void addRenderCallback(@NonNull IRenderCallback callback) {
+ mRenderCallbackMap.put(callback, callback);
+ ISurfaceHolder surfaceHolder = null;
+ if (mSurfaceTexture != null) {
+ surfaceHolder = new VideoSurfaceHolder(mWeakRenderView.get(), mSurfaceTexture);
+ callback.onSurfaceCreated(surfaceHolder, mWidth, mHeight);
+ }
+
+ if (mFormatChanged) {
+ if (surfaceHolder == null)
+ surfaceHolder = new VideoSurfaceHolder(mWeakRenderView.get(), mSurfaceTexture);
+ callback.onSurfaceChanged(surfaceHolder, 0, mWidth, mHeight);
+ }
+ }
+
+ public void removeRenderCallback(@NonNull IRenderCallback callback) {
+ mRenderCallbackMap.remove(callback);
+ }
+
+ @Override
+ public void onSurfaceTextureAvailable(@NonNull SurfaceTexture surface, int width, int height) {
+ mSurfaceTexture = surface;
+
+ ISurfaceHolder surfaceHolder = new VideoSurfaceHolder(mWeakRenderView.get(), surface);
+ for (IRenderCallback renderCallback : mRenderCallbackMap.keySet()) {
+ renderCallback.onSurfaceCreated(surfaceHolder, 0, 0);
+ }
+ }
+
+ @Override
+ public void onSurfaceTextureSizeChanged(@NonNull SurfaceTexture surface, int width, int height) {
+ mWidth = width;
+ mHeight = height;
+ mFormatChanged = true;
+ mSurfaceTexture = surface;
+
+ ISurfaceHolder surfaceHolder = new VideoSurfaceHolder(mWeakRenderView.get(), surface);
+ for (IRenderCallback renderCallback : mRenderCallbackMap.keySet()) {
+ renderCallback.onSurfaceChanged(surfaceHolder, 0, width, height);
+ }
+ }
+
+ @Override
+ public void onSurfaceTextureUpdated(@NonNull SurfaceTexture surface) {
+ }
+
+ @Override
+ public boolean onSurfaceTextureDestroyed(@NonNull SurfaceTexture surface) {
+ ISurfaceHolder surfaceHolder = new VideoSurfaceHolder(mWeakRenderView.get(), surface);
+ for (IRenderCallback renderCallback : mRenderCallbackMap.keySet()) {
+ renderCallback.onSurfaceDestroyed(surfaceHolder);
+ }
+ return mOwnSurfaceTexture;
+ }
+
+ public void willDetachFromWindow() {
+ mWillDetachFromWindow = true;
+ }
+
+ public void didDetachFromWindow() {
+ mDidDetachFromWindow = true;
+ }
+
+ public void releaseSurfaceTexture(SurfaceTexture surfaceTexture) {
+ if (surfaceTexture == null) {
+ return;
+ }
+ if (mDidDetachFromWindow) {
+ if (surfaceTexture != mSurfaceTexture) {
+ surfaceTexture.release();
+ } else if (!mOwnSurfaceTexture) {
+ surfaceTexture.release();
+ }
+ } else if (mWillDetachFromWindow) {
+ if (surfaceTexture != mSurfaceTexture) {
+ surfaceTexture.release();
+ } else if (!mOwnSurfaceTexture) {
+ setOwnSurfaceTexture(true);
+ }
+ } else {
+ if (surfaceTexture != mSurfaceTexture) {
+ surfaceTexture.release();
+ } else if (!mOwnSurfaceTexture) {
+ setOwnSurfaceTexture(true);
+ }
+ }
+ }
+ }
+
+ @Override
+ public void onInitializeAccessibilityEvent(AccessibilityEvent event) {
+ super.onInitializeAccessibilityEvent(event);
+ event.setClassName(TextureRenderView.class.getName());
+ }
+
+ @Override
+ public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
+ super.onInitializeAccessibilityNodeInfo(info);
+ info.setClassName(TextureRenderView.class.getName());
+ }
+}
diff --git a/README.md b/README.md
index 5f88b416..038205b3 100644
--- a/README.md
+++ b/README.md
@@ -1,61 +1,33 @@
# FFmpegAndroid
-android端基于FFmpeg库的使用。
-基于ffmpeg3.2.4版本,编译生成libffmpeg.so文件。
-添加编译ffmpeg源码的参考脚本
-目前音视频相关处理:
-- #### 音频剪切、拼接
-- #### 音频混音
-- #### 音频转码
-- #### 音视频合成
-- #### 音频抽取
-- #### 音频解码播放
-- #### 音频编码
-- #### 视频抽取
-- #### 视频剪切
-- #### 视频转码
-- #### 视频截图
-- #### 视频转GIF动图
-- #### 视频添加水印
-- #### 视频画面拼接
-- #### 图片合成视频
-- #### 视频解码播放
-- #### 本地直播推流
-- #### 实时直播推流
-- #### 音视频解码播放
-- #### OpenGL+GPUImage滤镜
-- #### FFmpeg的AVFilter滤镜
+### [FFmpeg官方文档](https://ffmpeg.org/)
+### [FFmpeg编译流程](https://github.com/xufuji456/FFmpegAndroid/blob/master/doc/FFmpeg_compile_shell.md)
+### [FFmpeg常用命令行](https://github.com/xufuji456/FFmpegAndroid/blob/master/doc/FFmpeg_command_line.md)
+### [FFmpeg源码分析](https://github.com/xufuji456/FFmpegAndroid/blob/master/doc/FFmpeg_sourcecode.md)
+### [JNI与NDK开发](https://github.com/xufuji456/FFmpegAndroid/blob/master/doc/JNI_develop_practice.md)
+### [音视频知识汇总](https://github.com/xufuji456/FFmpegAndroid/blob/master/doc/multimedia_knowledge.md)
+### [ijkplayer播放器架构](https://github.com/xufuji456/FFmpegAndroid/blob/master/doc/player_framework.md)
-本地直播截图:
-
+----------------------------------------------------------------------------------------------------
-左边是ffplay客户端拉流播放,中间是web网页播放:
-
+常见的流媒体传输协议包括:RTP、RTMP、RTCP、RTSP,流媒体应用协议有HLS、DASH,
+WebRTC设计传输协议有SDP、ICE、NAT、STUN等,常用视频编码协议有H264、HEVC、VVC,
+常用的视频封装格式有mp4,关于C/C++语言标准有C11、C20++等,书籍包括音视频编解码等。
+详细列表可以查阅:[多媒体协议与书籍](https://github.com/xufuji456/FFmpegAndroid/blob/master/doc/multimedia_protocol.md)
-视频添加文字水印(文字白色背景可以改为透明):
-
+音视频工作方向包括:直播、短视频、流媒体传输、视频播放器、音乐播放器、音视频算法、
+流媒体后端、音视频编辑、图像处理(个人概括,具体方向不限于此)。
+详情可查阅:[音视频工作方向](https://github.com/xufuji456/FFmpegAndroid/blob/master/doc/multimedia_work.md)
-视频转成GIF动图:
-
+### 音视频基础知识:
+
-滤镜效果:
-
+### 音视频进阶成长:
+
-
+### 音视频开源库:
+
-
-
-
-
-
-
-
-
-视频画面拼接:
-
-
-***
-
-后续会完善音视频播放、推流直播。
-
+### Joining the group to learn FFmpeg:
+
diff --git a/app/CMakeLists.txt b/app/CMakeLists.txt
deleted file mode 100644
index eb5184ea..00000000
--- a/app/CMakeLists.txt
+++ /dev/null
@@ -1,58 +0,0 @@
-# For more information about using CMake with Android Studio, read the
-# documentation: https://d.android.com/studio/projects/add-native-code.html
-
-# Sets the minimum version of CMake required to build the native library.
-
-cmake_minimum_required(VERSION 3.4.1)
-
-# Creates and names a library, sets it as either STATIC
-# or SHARED, and provides the relative paths to its source code.
-# You can define multiple libraries, and CMake builds them for you.
-# Gradle automatically packages shared libraries with your APK.
-
-add_library( # Sets the name of the library.
- media-handle
-
- # Sets the library as a shared library.
- SHARED
-
- # Provides a relative path to your source file(s).
-
- src/main/cpp/ffmpeg/cmdutils.c
- src/main/cpp/ffmpeg/ffmpeg.c
- src/main/cpp/ffmpeg/ffmpeg_filter.c
- src/main/cpp/ffmpeg/ffmpeg_opt.c
- src/main/cpp/ffmpeg_cmd.c
- src/main/cpp/audio_player.c
- src/main/cpp/openSL_audio_player.c
- src/main/cpp/video_player.c
- src/main/cpp/ffmpeg_pusher.cpp
- src/main/cpp/AVpacket_queue.c
- src/main/cpp/media_player.c
- src/main/cpp/video_filter.c)
-
-add_library( ffmpeg
- SHARED
- IMPORTED )
-set_target_properties( ffmpeg
- PROPERTIES IMPORTED_LOCATION
- ../../../../libs/armeabi-v7a/libffmpeg.so )
-
-set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=gnu++11")
-
-include_directories(src/main/cpp)
-include_directories(src/main/cpp/include)
-
-find_library( # Sets the name of the path variable.
- log-lib
- log )
-
-target_link_libraries( # Specifies the target library.
- media-handle
- ffmpeg
- -landroid #native_window
- -ljnigraphics #bitmap
- -lOpenSLES #openSLES
- # Links the target library to the log library
- # included in the NDK.
- ${log-lib} )
\ No newline at end of file
diff --git a/app/build.gradle b/app/build.gradle
index 25858705..0bb156b0 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -1,15 +1,19 @@
apply plugin: 'com.android.application'
+apply plugin: 'kotlin-android'
+apply plugin: 'kotlin-kapt'
android {
- compileSdkVersion 25
- buildToolsVersion "25.0.2"
+ compileSdkVersion rootProject.ext.compileSdkVersion
+ buildToolsVersion rootProject.ext.buildToolsVersion
+ namespace "com.frank.ffmpeg"
+
defaultConfig {
applicationId "com.frank.ffmpeg"
- minSdkVersion 17
- targetSdkVersion 25
- versionCode 1
- versionName "1.0"
- testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
+ minSdkVersion rootProject.ext.minSdkVersion
+ targetSdkVersion rootProject.ext.targetSdkVersion
+ versionCode rootProject.ext.versionCode
+ versionName rootProject.ext.versionName
+ testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
externalNativeBuild {
cmake {
@@ -17,7 +21,7 @@ android {
}
}
ndk {
- abiFilters "armeabi-v7a"
+ abiFilters "armeabi-v7a", "arm64-v8a"
}
}
buildTypes {
@@ -29,7 +33,7 @@ android {
externalNativeBuild {
cmake {
- path "CMakeLists.txt"
+ path "src/main/cpp/CMakeLists.txt"
}
}
sourceSets {
@@ -38,16 +42,41 @@ android {
jni.srcDirs = []
}
}
+
+ compileOptions {
+ sourceCompatibility = JavaVersion.VERSION_1_8
+ targetCompatibility = JavaVersion.VERSION_1_8
+ }
+
+ kotlinOptions {
+ jvmTarget = JavaVersion.VERSION_1_8
+ }
+
+ packagingOptions {
+ exclude 'META-INF/proguard/coroutines.pro'
+ pickFirst 'lib/armeabi-v7a/libffmpeg.so'
+ pickFirst 'lib/arm64-v8a/libffmpeg.so'
+
+ jniLibs {
+ useLegacyPackaging = true
+ }
+ }
+
+ packagingOptions {
+ doNotStrip "*/arm64-v8a/*.so"
+ doNotStrip "*/armeabi-v7a/*.so"
+ }
+
}
dependencies {
- compile fileTree(include: ['*.jar'], dir: 'libs')
- compile 'com.android.support.constraint:constraint-layout:1.0.2'
- androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
- exclude group: 'com.android.support', module: 'support-annotations'
- })
- compile 'com.android.support:appcompat-v7:25.4.0'
- compile 'com.android.support:recyclerview-v7:25.4.0'
- testCompile 'junit:junit:4.12'
- compile project(':Live')
+ implementation fileTree(include: ['*.jar'], dir: 'libs')
+ implementation "androidx.appcompat:appcompat:$rootProject.appcompatVersion"
+ implementation "androidx.recyclerview:recyclerview:$rootProject.recyclerviewVersion"
+ implementation project(':Live')
+ implementation "androidx.core:core-ktx:$rootProject.core_ktx"
+ implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:$rootProject.lifecycle_ktx"
+ implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
+ implementation project(':CameraFilter')
+ implementation project(':NextPlayer')
}
diff --git a/app/libs/armeabi-v7a/libffmpeg.so b/app/libs/armeabi-v7a/libffmpeg.so
deleted file mode 100644
index f0f699c0..00000000
Binary files a/app/libs/armeabi-v7a/libffmpeg.so and /dev/null differ
diff --git a/app/proguard-rules.pro b/app/proguard-rules.pro
index 7aa439aa..eae199d6 100644
--- a/app/proguard-rules.pro
+++ b/app/proguard-rules.pro
@@ -23,3 +23,18 @@
# If you keep the line number information, uncomment this to
# hide the original source file name.
#-renamesourcefileattribute SourceFile
+-keepclasseswithmembernames class * {
+ native ;
+}
+
+-keep public class com.frank.ffmpeg.AudioPlayer {
+}
+
+-keep public class com.frank.ffmpeg.FFmpegCmd {
+}
+
+-keep public class com.frank.ffmpeg.FFmpegPusher {
+}
+
+-keep public class com.frank.ffmpeg.VideoPlayer {
+}
\ No newline at end of file
diff --git a/app/src/androidTest/java/com/frank/ExampleInstrumentedTest.java b/app/src/androidTest/java/com/frank/ExampleInstrumentedTest.java
deleted file mode 100644
index 0b689d41..00000000
--- a/app/src/androidTest/java/com/frank/ExampleInstrumentedTest.java
+++ /dev/null
@@ -1,26 +0,0 @@
-package com.frank;
-
-import android.content.Context;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.runner.AndroidJUnit4;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import static org.junit.Assert.*;
-
-/**
- * Instrumentation test, which will execute on an Android device.
- *
- * @see Testing documentation
- */
-@RunWith(AndroidJUnit4.class)
-public class ExampleInstrumentedTest {
- @Test
- public void useAppContext() throws Exception {
- // Context of the app under test.
- Context appContext = InstrumentationRegistry.getTargetContext();
-
- assertEquals("codepig.ffmpegcldemo", appContext.getPackageName());
- }
-}
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index b578eea1..f01e911e 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -1,61 +1,58 @@
-
+
+
+
+
+
-
+ android:theme="@style/AppTheme"
+ tools:replace="android:name"
+ android:largeHeap="true"
+ android:requestLegacyExternalStorage="true">
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
+ android:configChanges="orientation|screenSize" />
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/cpp/AVpacket_queue.c b/app/src/main/cpp/AVpacket_queue.c
deleted file mode 100644
index 3ed1f0e8..00000000
--- a/app/src/main/cpp/AVpacket_queue.c
+++ /dev/null
@@ -1,63 +0,0 @@
-//
-// Created by frank on 2018/2/3.
-//
-#include "AVpacket_queue.h"
-#include
-#include
-
-
-AVPacketQueue* queue_init(int size){
- AVPacketQueue* queue = malloc(sizeof(AVPacketQueue));
- queue->size = size;
- queue->next_to_read = 0;
- queue->next_to_write = 0;
- int i;
- queue->packets = malloc(sizeof(*queue->packets) * size);
- for(i = 0; i < size; i++){
- queue->packets[i] = malloc(sizeof(AVPacket));
- }
- return queue;
-}
-
-void queue_free(AVPacketQueue *queue){
- int i;
- for(i=0; isize; i++){
- free(queue->packets[i]);
- }
- free(queue->packets);
- free(queue);
-}
-
-int queue_next(AVPacketQueue* queue, int current){
- return (current+1) % queue->size;
-}
-
-void* queue_push(AVPacketQueue* queue, pthread_mutex_t* mutex, pthread_cond_t* cond){
- int current = queue->next_to_write;
- int next_to_write;
- for(;;){
- next_to_write = queue_next(queue, current);
- //写的不等于读的,跳出循环
- if(next_to_write != queue->next_to_read){
- break;
- }
- pthread_cond_wait(cond, mutex);
- }
- queue->next_to_write = next_to_write;
- pthread_cond_broadcast(cond);
- return queue->packets[current];
-}
-
-void* queue_pop(AVPacketQueue* queue, pthread_mutex_t* mutex, pthread_cond_t* cond){
- int current = queue->next_to_read;
- for(;;){
- //写的不等于读的,跳出循环
- if(queue->next_to_write != queue->next_to_read){
- break;
- }
- pthread_cond_wait(cond, mutex);
- }
- queue->next_to_read = queue_next(queue, current);
- pthread_cond_broadcast(cond);
- return queue->packets[current];
-}
\ No newline at end of file
diff --git a/app/src/main/cpp/AVpacket_queue.h b/app/src/main/cpp/AVpacket_queue.h
deleted file mode 100644
index 3e899f8b..00000000
--- a/app/src/main/cpp/AVpacket_queue.h
+++ /dev/null
@@ -1,25 +0,0 @@
-//
-// Created by frank on 2018/2/3.
-//
-
-#ifndef VIDEOPLAYER_AVPACKET_QUEUE_H
-#define VIDEOPLAYER_AVPACKET_QUEUE_H
-#include
-
-typedef struct AVPacketQueue{
- //队列大小
- int size;
- //指针数组
- void ** packets;
- //下一个写入的packet
- int next_to_write;
- //下一个读取的packet
- int next_to_read;
-}AVPacketQueue;
-
-AVPacketQueue* queue_init(int size);
-void queue_free(AVPacketQueue *queue);
-void* queue_push(AVPacketQueue* queue, pthread_mutex_t* mutex, pthread_cond_t* cond);
-void* queue_pop(AVPacketQueue* queue, pthread_mutex_t* mutex, pthread_cond_t* cond);
-
-#endif //VIDEOPLAYER_AVPACKET_QUEUE_H
\ No newline at end of file
diff --git a/app/src/main/cpp/CMakeLists.txt b/app/src/main/cpp/CMakeLists.txt
new file mode 100644
index 00000000..954069ec
--- /dev/null
+++ b/app/src/main/cpp/CMakeLists.txt
@@ -0,0 +1,100 @@
+# For more information about using CMake with Android Studio, read the
+# documentation: https://d.android.com/studio/projects/add-native-code.html
+
+# Sets the minimum version of CMake required to build the native library.
+
+cmake_minimum_required(VERSION 3.4.1)
+
+# Creates and names a library, sets it as either STATIC
+# or SHARED, and provides the relative paths to its source code.
+# You can define multiple libraries, and CMake builds them for you.
+# Gradle automatically packages shared libraries with your APK.
+
+set(EXTRA ../../../../extra)
+set(EXTRA_FFMPEG ${EXTRA}/ffmpeg)
+
+set(SRC_FFMPEG
+ ffmpeg/cmdutils.c
+ ffmpeg/ffmpeg.c
+ ffmpeg/ffmpeg_demux.c
+ ffmpeg/ffmpeg_filter.c
+ ffmpeg/ffmpeg_hw.c
+ ffmpeg/ffmpeg_mux.c
+ ffmpeg/ffmpeg_mux_init.c
+ ffmpeg/ffmpeg_opt.c
+ ffmpeg/ffprobe.c
+ ffmpeg/objpool.c
+ ffmpeg/opt_common.c
+ ffmpeg/sync_queue.c
+ ffmpeg/thread_queue.c)
+
+set(SRC_VISUALIZER
+ visualizer/fft.cpp
+ visualizer/fixed_fft.cpp
+ visualizer/frank_visualizer.cpp
+ visualizer/frank_visualizer_jni.cpp
+ visualizer/window.cpp)
+
+set(SRC_METADATA
+ metadata/media_retriever.cpp
+ metadata/media_retriever_jni.cpp
+ metadata/metadata_util.c
+ metadata/ffmpeg_media_retriever.c)
+
+set(SRC_FFPLAYER ffplayer)
+
+add_library( # Sets the name of the library.
+ media-handle
+
+ # Sets the library as a shared library.
+ SHARED
+
+ # Provides a relative path to your source file(s).
+ ${SRC_FFMPEG}
+ ${SRC_VISUALIZER}
+ ${SRC_METADATA}
+ ffmpeg_cmd.c
+ video_filter.c
+ media_transcode.cpp
+ ff_audio_player.cpp
+ audio_player_jni.cpp
+)
+
+add_library( ffmpeg
+ SHARED
+ IMPORTED )
+set_target_properties( ffmpeg
+ PROPERTIES IMPORTED_LOCATION
+ ${CMAKE_SOURCE_DIR}/${EXTRA}/libs/${CMAKE_ANDROID_ARCH_ABI}/libffmpeg.so )
+
+set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=gnu++11")
+
+include_directories(.)
+include_directories(${EXTRA_FFMPEG}/include)
+include_directories(metadata)
+
+if(${CMAKE_ANDROID_ARCH_ABI} MATCHES "armeabi-v7a")
+ include_directories(${EXTRA_FFMPEG}/include/armeabi-v7a/libavcodec)
+ include_directories(${EXTRA_FFMPEG}/include/armeabi-v7a/libavutil)
+ message("This is armeabi-v7a")
+elseif(${CMAKE_ANDROID_ARCH_ABI} MATCHES "arm64-v8a")
+ include_directories(${EXTRA_FFMPEG}/include/arm64-v8a/libavcodec)
+ include_directories(${EXTRA_FFMPEG}/include/arm64-v8a/libavutil)
+ message("This is arm64-v8a")
+endif()
+
+find_library( # Sets the name of the path variable.
+ log-lib
+ log )
+
+target_link_options(media-handle PRIVATE "-Wl,-z,max-page-size=16384")
+
+target_link_libraries( # Specifies the target library.
+ media-handle
+ ffmpeg
+ -landroid #native_window
+ -ljnigraphics #bitmap
+ -lOpenSLES #openSLES
+ # Links the target library to the log library
+ # included in the NDK.
+ ${log-lib} )
\ No newline at end of file
diff --git a/app/src/main/cpp/audio_player.c b/app/src/main/cpp/audio_player.c
deleted file mode 100644
index ec1d16a4..00000000
--- a/app/src/main/cpp/audio_player.c
+++ /dev/null
@@ -1,154 +0,0 @@
-//
-// Created by frank on 2018/2/1.
-//
-#include
-#include
-#include
-//封装格式
-#include "libavformat/avformat.h"
-//解码
-#include "libavcodec/avcodec.h"
-//缩放
-#include "libswscale/swscale.h"
-//重采样
-#include "libswresample/swresample.h"
-#include
-
-#define TAG "MediaPlayer"
-#define LOGI(FORMAT,...) __android_log_print(ANDROID_LOG_INFO, TAG, FORMAT, ##__VA_ARGS__);
-#define LOGE(FORMAT,...) __android_log_print(ANDROID_LOG_ERROR, TAG, FORMAT, ##__VA_ARGS__);
-
-#define MAX_AUDIO_FRAME_SIZE 48000 * 4
-
-JNIEXPORT void JNICALL Java_com_frank_ffmpeg_AudioPlayer_play
- (JNIEnv *env, jobject jthiz, jstring input_jstr){
- const char* input_cstr = (*env)->GetStringUTFChars(env,input_jstr,NULL);
- LOGI("input_cstr=%s", input_cstr);
- //注册组件
- av_register_all();
- AVFormatContext *pFormatCtx = avformat_alloc_context();
- //打开音频文件
- if(avformat_open_input(&pFormatCtx,input_cstr,NULL,NULL) != 0){
- LOGI("%s","无法打开音频文件");
- return;
- }
- //获取输入文件信息
- if(avformat_find_stream_info(pFormatCtx,NULL) < 0){
- LOGI("%s","无法获取输入文件信息");
- return;
- }
- //获取音频流索引位置
- int i = 0, audio_stream_idx = -1;
- for(; i < pFormatCtx->nb_streams;i++){
- if(pFormatCtx->streams[i]->codec->codec_type == AVMEDIA_TYPE_AUDIO){
- audio_stream_idx = i;
- break;
- }
- }
-
- //获取音频解码器
- AVCodecContext *codecCtx = pFormatCtx->streams[audio_stream_idx]->codec;
- AVCodec *codec = avcodec_find_decoder(codecCtx->codec_id);
- if(codec == NULL){
- LOGI("%s","无法获取解码器");
- return;
- }
- //打开解码器
- if(avcodec_open2(codecCtx,codec,NULL) < 0){
- LOGI("%s","无法打开解码器");
- return;
- }
- //压缩数据
- AVPacket *packet = (AVPacket *)av_malloc(sizeof(AVPacket));
- //解压缩数据
- AVFrame *frame = av_frame_alloc();
- //frame->16bit 44100 PCM 统一音频采样格式与采样率
- SwrContext *swrCtx = swr_alloc();
-
- //输入的采样格式
- enum AVSampleFormat in_sample_fmt = codecCtx->sample_fmt;
- //输出采样格式16bit PCM
- enum AVSampleFormat out_sample_fmt = AV_SAMPLE_FMT_S16;
- //输入采样率
- int in_sample_rate = codecCtx->sample_rate;
- //输出采样率
- int out_sample_rate = in_sample_rate;
- //声道布局(2个声道,默认立体声stereo)
- uint64_t in_ch_layout = codecCtx->channel_layout;
- //输出的声道布局(立体声)
- uint64_t out_ch_layout = AV_CH_LAYOUT_STEREO;
-
- swr_alloc_set_opts(swrCtx,
- out_ch_layout,out_sample_fmt,out_sample_rate,
- in_ch_layout,in_sample_fmt,in_sample_rate,
- 0, NULL);
- swr_init(swrCtx);
-
- //输出的声道个数
- int out_channel_nb = av_get_channel_layout_nb_channels(out_ch_layout);
-
- jclass player_class = (*env)->GetObjectClass(env,jthiz);
- if(!player_class){
- LOGE("player_class not found...");
- }
- //AudioTrack对象
- jmethodID audio_track_method = (*env)->GetMethodID(env,player_class,"createAudioTrack","(II)Landroid/media/AudioTrack;");
- if(!audio_track_method){
- LOGE("audio_track_method not found...");
- }
- jobject audio_track = (*env)->CallObjectMethod(env,jthiz,audio_track_method,out_sample_rate,out_channel_nb);
-
- //调用play方法
- jclass audio_track_class = (*env)->GetObjectClass(env,audio_track);
- jmethodID audio_track_play_mid = (*env)->GetMethodID(env,audio_track_class,"play","()V");
- (*env)->CallVoidMethod(env,audio_track,audio_track_play_mid);
-
- //获取write()方法
- jmethodID audio_track_write_mid = (*env)->GetMethodID(env,audio_track_class,"write","([BII)I");
-
- //16bit 44100 PCM 数据
- uint8_t *out_buffer = (uint8_t *)av_malloc(MAX_AUDIO_FRAME_SIZE);
-
- int got_frame = 0,index = 0, ret;
- //不断读取编码数据
- while(av_read_frame(pFormatCtx,packet) >= 0){
- //解码音频类型的Packet
- if(packet->stream_index == audio_stream_idx){
- //解码
- ret = avcodec_decode_audio4(codecCtx,frame,&got_frame,packet);
- if(ret < 0){
- break;
- }
- //解码一帧成功
- if(got_frame > 0){
- LOGI("decode frame count=%d",index++);
- //音频格式转换
- swr_convert(swrCtx, &out_buffer, MAX_AUDIO_FRAME_SIZE,(const uint8_t **)frame->data,frame->nb_samples);
- int out_buffer_size = av_samples_get_buffer_size(NULL, out_channel_nb,
- frame->nb_samples, out_sample_fmt, 1);
-
- jbyteArray audio_sample_array = (*env)->NewByteArray(env,out_buffer_size);
- jbyte* sample_byte_array = (*env)->GetByteArrayElements(env,audio_sample_array,NULL);
- //拷贝缓冲数据
- memcpy(sample_byte_array, out_buffer, (size_t) out_buffer_size);
- //释放数组
- (*env)->ReleaseByteArrayElements(env,audio_sample_array,sample_byte_array,0);
- //调用AudioTrack的write方法进行播放
- (*env)->CallIntMethod(env,audio_track,audio_track_write_mid,
- audio_sample_array,0,out_buffer_size);
- //释放局部引用
- (*env)->DeleteLocalRef(env,audio_sample_array);
- usleep(1000 * 16);
- }
- }
- av_free_packet(packet);
- }
- LOGI("decode audio finish");
- av_frame_free(&frame);
- av_free(out_buffer);
- swr_free(&swrCtx);
- avcodec_close(codecCtx);
- avformat_close_input(&pFormatCtx);
- (*env)->ReleaseStringUTFChars(env,input_jstr,input_cstr);
-
-}
\ No newline at end of file
diff --git a/app/src/main/cpp/audio_player_jni.cpp b/app/src/main/cpp/audio_player_jni.cpp
new file mode 100644
index 00000000..fa64098b
--- /dev/null
+++ b/app/src/main/cpp/audio_player_jni.cpp
@@ -0,0 +1,105 @@
+//
+// Created by xu fulong on 2022/9/4.
+//
+
+#include "ff_audio_player.h"
+#include
+#include
+
+#define SLEEP_TIME (16000)
+
+void fftCallback(JNIEnv *env, jobject thiz, jmethodID fft_method, int8_t *data, int size) {
+ jbyteArray dataArray = env->NewByteArray(size);
+ env->SetByteArrayRegion(dataArray, 0, size, data);
+ env->CallVoidMethod(thiz, fft_method, dataArray);
+ env->DeleteLocalRef(dataArray);
+}
+
+AUDIO_PLAYER_FUNC(long, native_1init) {
+ auto *audioPlayer = new FFAudioPlayer();
+ return (long)audioPlayer;
+}
+
+AUDIO_PLAYER_FUNC(void, native_1play, long context, jstring path, jstring filter) {
+ if (path == nullptr)
+ return;
+
+ int result = 0;
+ const char* native_path = env->GetStringUTFChars(path, JNI_FALSE);
+ auto *audioPlayer = (FFAudioPlayer*) context;
+ // open stream, and init work
+ audioPlayer->open(native_path);
+ // init AudioTrack
+ jclass audio_class = env->GetObjectClass(thiz);
+ jmethodID audio_track_method = env->GetMethodID(audio_class,
+ "createAudioTrack", "(II)Landroid/media/AudioTrack;");
+ jobject audio_track = env->CallObjectMethod(thiz, audio_track_method,
+ audioPlayer->getSampleRate(), audioPlayer->getChannel());
+ // play function
+ jclass audio_track_class = env->GetObjectClass(audio_track);
+ jmethodID play_method = env->GetMethodID(audio_track_class, "play", "()V");
+ env->CallVoidMethod(audio_track, play_method);
+ jmethodID write_method = env->GetMethodID(audio_track_class, "write", "([BII)I");
+ jmethodID play_info_method = env->GetMethodID(audio_class, "playInfoFromJNI", "(I)V");
+ env->CallVoidMethod(thiz, play_info_method, 1);
+
+ // demux decode and play
+ while (result >= 0) {
+ result = audioPlayer->decodeAudio();
+ if (result == 0) {
+ continue;
+ } else if (result < 0) {
+ break;
+ }
+ int size = result;
+ // call AudioTrack to play(should be reused array)
+ jbyteArray audio_array = env->NewByteArray(size);
+ jbyte *data_address = env->GetByteArrayElements(audio_array, JNI_FALSE);
+ memcpy(data_address, audioPlayer->getDecodeFrame(), size);
+ env->ReleaseByteArrayElements(audio_array, data_address, 0);
+ env->CallIntMethod(audio_track, write_method, audio_array, 0, size);
+ env->DeleteLocalRef(audio_array);
+
+ // audio sync
+ usleep(SLEEP_TIME);
+ }
+
+ if (result == AVERROR_EOF) {
+ env->CallVoidMethod(thiz, play_info_method, 2);
+ }
+ env->ReleaseStringUTFChars(path, native_path);
+ jmethodID release_method = env->GetMethodID(audio_class, "releaseAudioTrack", "()V");
+ env->CallVoidMethod(thiz, release_method);
+ audioPlayer->close();
+ delete audioPlayer;
+}
+
+AUDIO_PLAYER_FUNC(void, native_1again, long context, jstring filter_jstr) {
+ if (!filter_jstr) return;
+ auto *audioPlayer = (FFAudioPlayer*) context;
+ audioPlayer->setFilterAgain(true);
+ const char *desc = env->GetStringUTFChars(filter_jstr, nullptr);
+ audioPlayer->setFilterDesc(desc);
+}
+
+AUDIO_PLAYER_FUNC(long, native_1get_1position, long context) {
+ auto *audioPlayer = (FFAudioPlayer*) context;
+ if (!audioPlayer)
+ return 0;
+ return audioPlayer->getCurrentPosition();
+}
+
+AUDIO_PLAYER_FUNC(long, native_1get_1duration, long context) {
+ auto *audioPlayer = (FFAudioPlayer*) context;
+ if (!audioPlayer)
+ return 0;
+ return audioPlayer->getDuration();
+}
+
+AUDIO_PLAYER_FUNC(void, native_1release, long context) {
+ auto *audioPlayer = (FFAudioPlayer*) context;
+ if (!audioPlayer)
+ return;
+ audioPlayer->setExit(true);
+}
+
diff --git a/app/src/main/cpp/ff_audio_player.cpp b/app/src/main/cpp/ff_audio_player.cpp
new file mode 100644
index 00000000..26bb104d
--- /dev/null
+++ b/app/src/main/cpp/ff_audio_player.cpp
@@ -0,0 +1,282 @@
+//
+// Created by xu fulong on 2022/9/4.
+//
+
+#include "ff_audio_player.h"
+
+#define AUDIO_TAG "AudioPlayer"
+#define BUFFER_SIZE (48000 * 10)
+
+const char *FILTER_DESC = "superequalizer=6b=4:8b=5:10b=5";
+
+int initFilter(const char *filterDesc, AVCodecContext *codecCtx, AVFilterGraph **graph,
+ AVFilterContext **src, AVFilterContext **sink) {
+ int ret;
+ char args[512];
+ AVFilterContext *buffersrc_ctx;
+ AVFilterContext *buffersink_ctx;
+ AVRational time_base = codecCtx->time_base;
+ AVFilterInOut *inputs = avfilter_inout_alloc();
+ AVFilterInOut *outputs = avfilter_inout_alloc();
+ const AVFilter *buffersrc = avfilter_get_by_name("abuffer");
+ const AVFilter *buffersink = avfilter_get_by_name("abuffersink");
+
+ AVFilterGraph *filter_graph = avfilter_graph_alloc();
+ if (!outputs || !inputs || !filter_graph) {
+ ret = AVERROR(ENOMEM);
+ goto end;
+ }
+
+ /* buffer audio source: the decoded frames from the decoder will be inserted here. */
+ if (!codecCtx->channel_layout)
+ codecCtx->channel_layout = static_cast(av_get_default_channel_layout(
+ codecCtx->channels));
+ snprintf(args, sizeof(args),
+ "time_base=%d/%d:sample_rate=%d:sample_fmt=%s:channel_layout=0x%" PRIx64 "",
+ time_base.num, time_base.den, codecCtx->sample_rate,
+ av_get_sample_fmt_name(codecCtx->sample_fmt), codecCtx->channel_layout);
+
+ ret = avfilter_graph_create_filter(&buffersrc_ctx, buffersrc, "in",
+ args, nullptr, filter_graph);
+ if (ret < 0) {
+ LOGE(AUDIO_TAG, "Cannot create buffer source:%d", ret);
+ goto end;
+ }
+ /* buffer audio sink: to terminate the filter chain. */
+ ret = avfilter_graph_create_filter(&buffersink_ctx, buffersink, "out",
+ nullptr, nullptr, filter_graph);
+ if (ret < 0) {
+ LOGE(AUDIO_TAG, "Cannot create buffer sink:%d", ret);
+ goto end;
+ }
+
+ outputs->name = av_strdup("in");
+ outputs->filter_ctx = buffersrc_ctx;
+ outputs->pad_idx = 0;
+ outputs->next = nullptr;
+ inputs->name = av_strdup("out");
+ inputs->filter_ctx = buffersink_ctx;
+ inputs->pad_idx = 0;
+ inputs->next = nullptr;
+
+ if ((ret = avfilter_graph_parse_ptr(filter_graph, filterDesc,
+ &inputs, &outputs, nullptr)) < 0) {
+ LOGE(AUDIO_TAG, "avfilter_graph_parse_ptr error:%d", ret);
+ goto end;
+ }
+ if ((ret = avfilter_graph_config(filter_graph, nullptr)) < 0) {
+ LOGE(AUDIO_TAG, "avfilter_graph_config error:%d", ret);
+ goto end;
+ }
+ *graph = filter_graph;
+ *src = buffersrc_ctx;
+ *sink = buffersink_ctx;
+end:
+ avfilter_inout_free(&inputs);
+ avfilter_inout_free(&outputs);
+ return ret;
+}
+
+FFAudioPlayer::FFAudioPlayer() {
+ m_state = new AudioPlayerState();
+}
+
+FFAudioPlayer::~FFAudioPlayer() {
+ delete m_state;
+}
+
+int FFAudioPlayer::open(const char *path) {
+ if (!path)
+ return -1;
+
+ int ret;
+ const AVCodec *codec;
+ m_state->inputFrame = av_frame_alloc();
+ m_state->packet = av_packet_alloc();
+ m_state->outBuffer = new uint8_t [BUFFER_SIZE];
+
+ // open input stream
+ ret = avformat_open_input(&m_state->formatContext, path, nullptr, nullptr);
+ if (ret < 0) {
+ LOGE(AUDIO_TAG, "avformat_open_input error=%s", av_err2str(ret));
+ return ret;
+ }
+ // (if need)find info: width、height、sample_rate、duration
+ avformat_find_stream_info(m_state->formatContext, nullptr);
+ // find audio index
+ for (int i=0; iformatContext->nb_streams; i++) {
+ if (AVMEDIA_TYPE_AUDIO == m_state->formatContext->streams[i]->codecpar->codec_type) {
+ m_state->audioIndex = i;
+ break;
+ }
+ }
+ if (m_state->audioIndex == -1) {
+ return -1;
+ }
+ // find audio decoder
+ codec = avcodec_find_decoder(m_state->formatContext->streams[m_state->audioIndex]->codecpar->codec_id);
+ m_state->codecContext = avcodec_alloc_context3(codec);
+ avcodec_parameters_to_context(m_state->codecContext, m_state->formatContext->streams[m_state->audioIndex]->codecpar);
+ // open decoder
+ ret = avcodec_open2(m_state->codecContext, codec, nullptr);
+ if (ret < 0) {
+ LOGE(AUDIO_TAG, "avcodec_open2 error=%s", av_err2str(ret));
+ return ret;
+ }
+ // input and output params
+ int in_sample_rate = m_state->codecContext->sample_rate;
+ auto in_sample_fmt = m_state->codecContext->sample_fmt;
+ int in_ch_layout = (int)m_state->codecContext->channel_layout;
+ m_state->out_sample_rate = in_sample_rate;
+ m_state->out_sample_fmt = AV_SAMPLE_FMT_S16;
+ m_state->out_ch_layout = AV_CH_LAYOUT_STEREO;
+ m_state->out_channel = m_state->codecContext->channels;
+ // init resample context
+ m_state->swrContext = swr_alloc();
+ swr_alloc_set_opts(m_state->swrContext, m_state->out_ch_layout, m_state->out_sample_fmt, m_state->out_sample_rate,
+ in_ch_layout, in_sample_fmt, in_sample_rate, 0, nullptr);
+ swr_init(m_state->swrContext);
+ // init filter graph
+ m_state->filterFrame = av_frame_alloc();
+ initFilter(FILTER_DESC, m_state->codecContext, &m_state->audioFilterGraph,
+ &m_state->audioSrcContext, &m_state->audioSinkContext);
+
+ return 0;
+}
+
+int FFAudioPlayer::getChannel() const {
+ return m_state->out_channel;
+}
+
+int FFAudioPlayer::getSampleRate() const {
+ return m_state->out_sample_rate;
+}
+
+int FFAudioPlayer::decodeAudio() {
+ int ret;
+ std::unique_lock lock(m_state->m_playMutex);
+ bool exit = m_state->exitPlaying;
+ lock.unlock();
+ if (exit) {
+ return -1;
+ }
+ // demux: read a frame(should be demux thread)
+ ret = av_read_frame(m_state->formatContext, m_state->packet);
+ if (ret < 0) {
+ return ret;
+ }
+ // see if audio packet
+ if (m_state->packet->stream_index != m_state->audioIndex) {
+ return 0;
+ }
+ // decode audio frame(should be decode thread)
+ ret = avcodec_send_packet(m_state->codecContext, m_state->packet);
+ if (ret < 0) {
+ LOGE(AUDIO_TAG, "avcodec_send_packet=%s", av_err2str(ret));
+ }
+ ret = avcodec_receive_frame(m_state->codecContext, m_state->inputFrame);
+ if (ret < 0) {
+ if (ret == AVERROR(EAGAIN)) {
+ return 0;
+ } else {
+ return ret;
+ }
+ }
+
+ // change filter
+ if (m_state->filterAgain) {
+ m_state->filterAgain = false;
+ avfilter_graph_free(&m_state->audioFilterGraph);
+ if ((ret = initFilter(m_state->filterDesc, m_state->codecContext, &m_state->audioFilterGraph,
+ &m_state->audioSrcContext, &m_state->audioSinkContext)) < 0) {
+ LOGE(AUDIO_TAG, "init_filter error, ret=%d\n", ret);
+ return ret;
+ }
+ }
+
+ // put into filter
+ ret = av_buffersrc_add_frame(m_state->audioSrcContext, m_state->inputFrame);
+ if (ret < 0) {
+ LOGE(AUDIO_TAG, "av_buffersrc_add_frame error=%s", av_err2str(ret));
+ }
+ // drain from filter
+ ret = av_buffersink_get_frame(m_state->audioSinkContext, m_state->filterFrame);
+ if (ret == AVERROR(EAGAIN)) {
+ return 0;
+ } else if (ret == AVERROR_EOF) {
+ LOGE(AUDIO_TAG, "enf of stream...");
+ return ret;
+ } else if (ret < 0) {
+ LOGE(AUDIO_TAG, "av_buffersink_get_frame error:%s", av_err2str(ret));
+ return ret;
+ }
+
+ // convert audio format and sample_rate
+ swr_convert(m_state->swrContext, &m_state->outBuffer, BUFFER_SIZE,
+ (const uint8_t **)(m_state->filterFrame->data), m_state->filterFrame->nb_samples);
+ // get buffer size after converting
+ int buffer_size = av_samples_get_buffer_size(nullptr, m_state->out_channel,
+ m_state->filterFrame->nb_samples, m_state->out_sample_fmt, 1);
+ // update position
+ AVRational time_base = m_state->formatContext->streams[m_state->audioIndex]->time_base;
+ m_state->m_position = (int64_t)(m_state->filterFrame->pts * av_q2d(time_base) * 1000);
+
+ av_frame_unref(m_state->inputFrame);
+ av_frame_unref(m_state->filterFrame);
+ av_packet_unref(m_state->packet);
+ return buffer_size;
+}
+
+uint8_t *FFAudioPlayer::getDecodeFrame() const {
+ return m_state->outBuffer;
+}
+
+void FFAudioPlayer::setFilterAgain(bool again) {
+ m_state->filterAgain = again;
+}
+
+void FFAudioPlayer::setFilterDesc(const char *filterDescription) {
+ m_state->filterDesc = filterDescription;
+}
+
+void FFAudioPlayer::setExit(bool exit) {
+ std::unique_lock lock(m_state->m_playMutex);
+ m_state->exitPlaying = exit;
+ lock.unlock();
+}
+
+int64_t FFAudioPlayer::getCurrentPosition() {
+ return m_state->m_position;
+}
+
+int64_t FFAudioPlayer::getDuration() {
+ if (!m_state || !m_state->formatContext)
+ return 0;
+ return m_state->formatContext->duration / AV_TIME_BASE * 1000;
+}
+
+void FFAudioPlayer::close() {
+ if (!m_state)
+ return;
+ if (m_state->formatContext) {
+ avformat_close_input(&m_state->formatContext);
+ }
+ if (m_state->codecContext) {
+ avcodec_free_context(&m_state->codecContext);
+ }
+ if (m_state->packet) {
+ av_packet_free(&m_state->packet);
+ }
+ if (m_state->inputFrame) {
+ av_frame_free(&m_state->inputFrame);
+ }
+ if (m_state->swrContext) {
+ swr_close(m_state->swrContext);
+ }
+ avfilter_free(m_state->audioSrcContext);
+ avfilter_free(m_state->audioSinkContext);
+ if (m_state->audioFilterGraph) {
+ avfilter_graph_free(&m_state->audioFilterGraph);
+ }
+ delete[] m_state->outBuffer;
+}
\ No newline at end of file
diff --git a/app/src/main/cpp/ff_audio_player.h b/app/src/main/cpp/ff_audio_player.h
new file mode 100644
index 00000000..f43d0466
--- /dev/null
+++ b/app/src/main/cpp/ff_audio_player.h
@@ -0,0 +1,86 @@
+//
+// Created by xu fulong on 2022/9/4.
+//
+
+#ifndef FF_AUDIO_PLAYER_H
+#define FF_AUDIO_PLAYER_H
+
+#include
+#include "ffmpeg_jni_define.h"
+#include "visualizer/frank_visualizer.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+#include "libavformat/avformat.h"
+#include "libavcodec/avcodec.h"
+#include "libswresample/swresample.h"
+
+#include "libavfilter/buffersink.h"
+#include "libavfilter/buffersrc.h"
+#include "libavfilter/avfilter.h"
+#ifdef __cplusplus
+}
+#endif
+
+struct AudioPlayerState {
+ int out_channel;
+ int out_ch_layout;
+ int out_sample_rate;
+ enum AVSampleFormat out_sample_fmt;
+ int64_t m_position;
+
+ AVPacket *packet;
+ AVFrame *inputFrame;
+ AVFrame *filterFrame;
+ int audioIndex = -1;
+ uint8_t *outBuffer;
+ SwrContext *swrContext;
+
+ AVFormatContext *formatContext;
+ AVCodecContext *codecContext;
+
+ const char *filterDesc;
+ std::atomic filterAgain;
+ bool exitPlaying;
+ std::mutex m_playMutex;
+
+ AVFilterGraph *audioFilterGraph;
+ AVFilterContext *audioSrcContext;
+ AVFilterContext *audioSinkContext;
+};
+
+class FFAudioPlayer {
+private:
+
+ AudioPlayerState *m_state;
+
+public:
+
+ FFAudioPlayer();
+
+ ~FFAudioPlayer();
+
+ int open(const char* path);
+
+ int getSampleRate() const;
+
+ int getChannel() const;
+
+ int decodeAudio();
+
+ uint8_t *getDecodeFrame() const;
+
+ void setFilterAgain(bool again);
+
+ void setFilterDesc(const char *filterDescription);
+
+ void setExit(bool exit);
+
+ int64_t getCurrentPosition();
+
+ int64_t getDuration();
+
+ void close();
+};
+#endif //FF_AUDIO_PLAYER_H
diff --git a/app/src/main/cpp/ffmpeg/cmdutils.c b/app/src/main/cpp/ffmpeg/cmdutils.c
index dc6b16a5..6cea6c54 100644
--- a/app/src/main/cpp/ffmpeg/cmdutils.c
+++ b/app/src/main/cpp/ffmpeg/cmdutils.c
@@ -32,57 +32,41 @@
#include "config.h"
#include "compat/va_copy.h"
#include "libavformat/avformat.h"
-#include "libavfilter/avfilter.h"
-#include "libavresample/avresample.h"
-#include "libavdevice/avdevice.h"
-#include "libswresample/swresample.h"
#include "libswscale/swscale.h"
-#include "libpostproc/postprocess.h"
+#include "libswscale/version.h"
+#include "libswresample/swresample.h"
#include "libavutil/avassert.h"
#include "libavutil/avstring.h"
-#include "libavutil/bprint.h"
+#include "libavutil/channel_layout.h"
#include "libavutil/display.h"
+#include "libavutil/getenv_utf8.h"
#include "libavutil/mathematics.h"
#include "libavutil/imgutils.h"
#include "libavutil/libm.h"
#include "libavutil/parseutils.h"
-#include "libavutil/pixdesc.h"
#include "libavutil/eval.h"
#include "libavutil/dict.h"
#include "libavutil/opt.h"
-#include "libavutil/cpu.h"
-#include "libavutil/version.h"
#include "cmdutils.h"
-#if CONFIG_NETWORK
-#include "libavformat/network.h"
-#endif
-#if HAVE_SYS_RESOURCE_H
-#include
-#include
+#include "fopen_utf8.h"
+#include "opt_common.h"
+#ifdef _WIN32
+#include
+#include "compat/w32dlfcn.h"
#endif
-static int init_report(const char *env);
-
AVDictionary *sws_dict;
AVDictionary *swr_opts;
-AVDictionary *format_opts, *codec_opts, *resample_opts;
+AVDictionary *format_opts, *codec_opts;
-static FILE *report_file;
-static int report_file_level = AV_LOG_DEBUG;
int hide_banner = 0;
-void init_opts(void)
-{
- av_dict_set(&sws_dict, "flags", "bicubic", 0);
-}
-
void uninit_opts(void)
{
av_dict_free(&swr_opts);
av_dict_free(&sws_dict);
av_dict_free(&format_opts);
av_dict_free(&codec_opts);
- av_dict_free(&resample_opts);
}
void log_callback_help(void *ptr, int level, const char *fmt, va_list vl)
@@ -90,20 +74,13 @@ void log_callback_help(void *ptr, int level, const char *fmt, va_list vl)
vfprintf(stdout, fmt, vl);
}
-static void log_callback_report(void *ptr, int level, const char *fmt, va_list vl)
+void init_dynload(void)
{
- va_list vl2;
- char line[1024];
- static int print_prefix = 1;
-
- va_copy(vl2, vl);
- av_log_default_callback(ptr, level, fmt, vl);
- av_log_format_line(ptr, level, fmt, vl2, line, sizeof(line), &print_prefix);
- va_end(vl2);
- if (report_file_level >= level) {
- fputs(line, report_file);
- fflush(report_file);
- }
+#if HAVE_SETDLLDIRECTORY && defined(_WIN32)
+ /* Calling SetDllDirectory with the empty string (but not NULL) removes the
+ * current working directory from the DLL search path as a security pre-caution. */
+ SetDllDirectory("");
+#endif
}
static void (*program_exit)(int ret);
@@ -113,9 +90,18 @@ void register_exit(void (*cb)(int ret))
program_exit = cb;
}
-int exit_program(int ret)
+void report_and_exit(int ret)
{
- return ret;
+ av_log(NULL, AV_LOG_FATAL, "%s\n", av_err2str(ret));
+ exit_program(AVUNERROR(ret));
+}
+
+void exit_program(int ret)
+{
+ if (program_exit)
+ program_exit(ret);
+
+ longjmp(jump_buf, 1);
}
double parse_number_or_die(const char *context, const char *numstr, int type,
@@ -159,7 +145,7 @@ void show_help_options(const OptionDef *options, const char *msg, int req_flags,
first = 1;
for (po = options; po->name; po++) {
- char buf[64];
+ char buf[128];
if (((po->flags & req_flags) != req_flags) ||
(alt_flags && !(po->flags & alt_flags)) ||
@@ -182,23 +168,22 @@ void show_help_options(const OptionDef *options, const char *msg, int req_flags,
void show_help_children(const AVClass *class, int flags)
{
- const AVClass *child = NULL;
+ void *iter = NULL;
+ const AVClass *child;
if (class->option) {
av_opt_show2(&class, NULL, flags, 0);
printf("\n");
}
- while (child = av_opt_child_class_next(class, child))
+ while (child = av_opt_child_class_iterate(class, &iter))
show_help_children(child, flags);
}
static const OptionDef *find_option(const OptionDef *po, const char *name)
{
- const char *p = strchr(name, ':');
- int len = p ? p - name : strlen(name);
-
while (po->name) {
- if (!strncmp(name, po->name, len) && strlen(po->name) == len)
+ const char *end;
+ if (av_strstart(name, po->name, &end) && (!*end || *end == ':'))
break;
po++;
}
@@ -209,7 +194,6 @@ static const OptionDef *find_option(const OptionDef *po, const char *name)
* by default. HAVE_COMMANDLINETOARGVW is true on cygwin, while
* it doesn't provide the actual command line via GetCommandLineW(). */
#if HAVE_COMMANDLINETOARGVW && defined(_WIN32)
-#include
#include
/* Will be leaked on exit */
static char** win32_argv_utf8 = NULL;
@@ -328,6 +312,12 @@ static int write_option(void *optctx, const OptionDef *po, const char *opt,
int parse_option(void *optctx, const char *opt, const char *arg,
const OptionDef *options)
{
+ static const OptionDef opt_avoptions = {
+ .name = "AVOption passthrough",
+ .flags = HAS_ARG,
+ .u.func_arg = opt_default,
+ };
+
const OptionDef *po;
int ret;
@@ -341,7 +331,7 @@ int parse_option(void *optctx, const char *opt, const char *arg,
arg = "1";
if (!po->name)
- po = find_option(options, "default");
+ po = &opt_avoptions;
if (!po->name) {
av_log(NULL, AV_LOG_ERROR, "Unrecognized option '%s'\n", opt);
return AVERROR(EINVAL);
@@ -448,7 +438,7 @@ int locate_option(int argc, char **argv, const OptionDef *options,
return 0;
}
-static void dump_argument(const char *a)
+static void dump_argument(FILE *report_file, const char *a)
{
const unsigned char *p;
@@ -484,7 +474,7 @@ static void check_options(const OptionDef *po)
void parse_loglevel(int argc, char **argv, const OptionDef *options)
{
int idx = locate_option(argc, argv, options, "loglevel");
- const char *env;
+ char *env;
check_options(options);
@@ -493,18 +483,21 @@ void parse_loglevel(int argc, char **argv, const OptionDef *options)
if (idx && argv[idx + 1])
opt_loglevel(NULL, "loglevel", argv[idx + 1]);
idx = locate_option(argc, argv, options, "report");
- if ((env = getenv("FFREPORT")) || idx) {
- init_report(env);
+ env = getenv_utf8("FFREPORT");
+ if (env || idx) {
+ FILE *report_file = NULL;
+ init_report(env, &report_file);
if (report_file) {
int i;
fprintf(report_file, "Command line:\n");
for (i = 0; i < argc; i++) {
- dump_argument(argv[i]);
+ dump_argument(report_file, argv[i]);
fputc(i < argc - 1 ? ' ' : '\n', report_file);
}
fflush(report_file);
}
}
+ freeenv_utf8(env);
idx = locate_option(argc, argv, options, "hide_banner");
if (idx)
hide_banner = 1;
@@ -527,9 +520,6 @@ int opt_default(void *optctx, const char *opt, const char *arg)
char opt_stripped[128];
const char *p;
const AVClass *cc = avcodec_get_class(), *fc = avformat_get_class();
-#if CONFIG_AVRESAMPLE
- const AVClass *rc = avresample_get_class();
-#endif
#if CONFIG_SWSCALE
const AVClass *sc = sws_get_class();
#endif
@@ -561,20 +551,12 @@ int opt_default(void *optctx, const char *opt, const char *arg)
#if CONFIG_SWSCALE
if (!consumed && (o = opt_find(&sc, opt, NULL, 0,
AV_OPT_SEARCH_CHILDREN | AV_OPT_SEARCH_FAKE_OBJ))) {
- struct SwsContext *sws = sws_alloc_context();
- int ret = av_opt_set(sws, opt, arg, 0);
- sws_freeContext(sws);
if (!strcmp(opt, "srcw") || !strcmp(opt, "srch") ||
!strcmp(opt, "dstw") || !strcmp(opt, "dsth") ||
!strcmp(opt, "src_format") || !strcmp(opt, "dst_format")) {
av_log(NULL, AV_LOG_ERROR, "Directly using swscale dimensions/format options is not supported, please use the -s or -pix_fmt options\n");
return AVERROR(EINVAL);
}
- if (ret < 0) {
- av_log(NULL, AV_LOG_ERROR, "Error setting option %s.\n", opt);
- return ret;
- }
-
av_dict_set(&sws_dict, opt, arg, FLAGS);
consumed = 1;
@@ -588,24 +570,10 @@ int opt_default(void *optctx, const char *opt, const char *arg)
#if CONFIG_SWRESAMPLE
if (!consumed && (o=opt_find(&swr_class, opt, NULL, 0,
AV_OPT_SEARCH_CHILDREN | AV_OPT_SEARCH_FAKE_OBJ))) {
- struct SwrContext *swr = swr_alloc();
- int ret = av_opt_set(swr, opt, arg, 0);
- swr_free(&swr);
- if (ret < 0) {
- av_log(NULL, AV_LOG_ERROR, "Error setting option %s.\n", opt);
- return ret;
- }
av_dict_set(&swr_opts, opt, arg, FLAGS);
consumed = 1;
}
#endif
-#if CONFIG_AVRESAMPLE
- if ((o=opt_find(&rc, opt, NULL, 0,
- AV_OPT_SEARCH_CHILDREN | AV_OPT_SEARCH_FAKE_OBJ))) {
- av_dict_set(&resample_opts, opt, arg, FLAGS);
- consumed = 1;
- }
-#endif
if (consumed)
return 0;
@@ -653,14 +621,11 @@ static void finish_group(OptionParseContext *octx, int group_idx,
g->swr_opts = swr_opts;
g->codec_opts = codec_opts;
g->format_opts = format_opts;
- g->resample_opts = resample_opts;
codec_opts = NULL;
format_opts = NULL;
- resample_opts = NULL;
sws_dict = NULL;
swr_opts = NULL;
- init_opts();
memset(&octx->cur_group, 0, sizeof(octx->cur_group));
}
@@ -689,17 +654,15 @@ static void init_parse_context(OptionParseContext *octx,
memset(octx, 0, sizeof(*octx));
octx->nb_groups = nb_groups;
- octx->groups = av_mallocz_array(octx->nb_groups, sizeof(*octx->groups));
+ octx->groups = av_calloc(octx->nb_groups, sizeof(*octx->groups));
if (!octx->groups)
- exit_program(1);
+ report_and_exit(AVERROR(ENOMEM));
for (i = 0; i < octx->nb_groups; i++)
octx->groups[i].group_def = &groups[i];
octx->global_opts.group_def = &global_group;
octx->global_opts.arg = "";
-
- init_opts();
}
void uninit_parse_context(OptionParseContext *octx)
@@ -713,7 +676,6 @@ void uninit_parse_context(OptionParseContext *octx)
av_freep(&l->groups[j].opts);
av_dict_free(&l->groups[j].codec_opts);
av_dict_free(&l->groups[j].format_opts);
- av_dict_free(&l->groups[j].resample_opts);
av_dict_free(&l->groups[j].sws_dict);
av_dict_free(&l->groups[j].swr_opts);
@@ -825,1068 +787,18 @@ do { \
return AVERROR_OPTION_NOT_FOUND;
}
- if (octx->cur_group.nb_opts || codec_opts || format_opts || resample_opts)
- av_log(NULL, AV_LOG_WARNING, "Trailing options were found on the "
- "commandline.\n");
+ if (octx->cur_group.nb_opts || codec_opts || format_opts)
+ av_log(NULL, AV_LOG_WARNING, "Trailing option(s) found in the "
+ "command: may be ignored.\n");
av_log(NULL, AV_LOG_DEBUG, "Finished splitting the commandline.\n");
return 0;
}
-int opt_cpuflags(void *optctx, const char *opt, const char *arg)
-{
- int ret;
- unsigned flags = av_get_cpu_flags();
-
- if ((ret = av_parse_cpu_caps(&flags, arg)) < 0)
- return ret;
-
- av_force_cpu_flags(flags);
- return 0;
-}
-
-int opt_loglevel(void *optctx, const char *opt, const char *arg)
-{
- const struct { const char *name; int level; } log_levels[] = {
- { "quiet" , AV_LOG_QUIET },
- { "panic" , AV_LOG_PANIC },
- { "fatal" , AV_LOG_FATAL },
- { "error" , AV_LOG_ERROR },
- { "warning", AV_LOG_WARNING },
- { "info" , AV_LOG_INFO },
- { "verbose", AV_LOG_VERBOSE },
- { "debug" , AV_LOG_DEBUG },
- { "trace" , AV_LOG_TRACE },
- };
- char *tail;
- int level;
- int flags;
- int i;
-
- flags = av_log_get_flags();
- tail = strstr(arg, "repeat");
- if (tail)
- flags &= ~AV_LOG_SKIP_REPEATED;
- else
- flags |= AV_LOG_SKIP_REPEATED;
-
- av_log_set_flags(flags);
- if (tail == arg)
- arg += 6 + (arg[6]=='+');
- if(tail && !*arg)
- return 0;
-
- for (i = 0; i < FF_ARRAY_ELEMS(log_levels); i++) {
- if (!strcmp(log_levels[i].name, arg)) {
- av_log_set_level(log_levels[i].level);
- return 0;
- }
- }
-
- level = strtol(arg, &tail, 10);
- if (*tail) {
- av_log(NULL, AV_LOG_FATAL, "Invalid loglevel \"%s\". "
- "Possible levels are numbers or:\n", arg);
- for (i = 0; i < FF_ARRAY_ELEMS(log_levels); i++)
- av_log(NULL, AV_LOG_FATAL, "\"%s\"\n", log_levels[i].name);
- exit_program(1);
- }
- av_log_set_level(level);
- return 0;
-}
-
-static void expand_filename_template(AVBPrint *bp, const char *template,
- struct tm *tm)
-{
- int c;
-
- while ((c = *(template++))) {
- if (c == '%') {
- if (!(c = *(template++)))
- break;
- switch (c) {
- case 'p':
- av_bprintf(bp, "%s", program_name);
- break;
- case 't':
- av_bprintf(bp, "%04d%02d%02d-%02d%02d%02d",
- tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday,
- tm->tm_hour, tm->tm_min, tm->tm_sec);
- break;
- case '%':
- av_bprint_chars(bp, c, 1);
- break;
- }
- } else {
- av_bprint_chars(bp, c, 1);
- }
- }
-}
-
-static int init_report(const char *env)
-{
- char *filename_template = NULL;
- char *key, *val;
- int ret, count = 0;
- time_t now;
- struct tm *tm;
- AVBPrint filename;
-
- if (report_file) /* already opened */
- return 0;
- time(&now);
- tm = localtime(&now);
-
- while (env && *env) {
- if ((ret = av_opt_get_key_value(&env, "=", ":", 0, &key, &val)) < 0) {
- if (count)
- av_log(NULL, AV_LOG_ERROR,
- "Failed to parse FFREPORT environment variable: %s\n",
- av_err2str(ret));
- break;
- }
- if (*env)
- env++;
- count++;
- if (!strcmp(key, "file")) {
- av_free(filename_template);
- filename_template = val;
- val = NULL;
- } else if (!strcmp(key, "level")) {
- char *tail;
- report_file_level = strtol(val, &tail, 10);
- if (*tail) {
- av_log(NULL, AV_LOG_FATAL, "Invalid report file level\n");
- exit_program(1);
- }
- } else {
- av_log(NULL, AV_LOG_ERROR, "Unknown key '%s' in FFREPORT\n", key);
- }
- av_free(val);
- av_free(key);
- }
-
- av_bprint_init(&filename, 0, 1);
- expand_filename_template(&filename,
- av_x_if_null(filename_template, "%p-%t.log"), tm);
- av_free(filename_template);
- if (!av_bprint_is_complete(&filename)) {
- av_log(NULL, AV_LOG_ERROR, "Out of memory building report file name\n");
- return AVERROR(ENOMEM);
- }
-
- report_file = fopen(filename.str, "w");
- if (!report_file) {
- int ret = AVERROR(errno);
- av_log(NULL, AV_LOG_ERROR, "Failed to open report \"%s\": %s\n",
- filename.str, strerror(errno));
- return ret;
- }
- av_log_set_callback(log_callback_report);
- av_log(NULL, AV_LOG_INFO,
- "%s started on %04d-%02d-%02d at %02d:%02d:%02d\n"
- "Report written to \"%s\"\n",
- program_name,
- tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday,
- tm->tm_hour, tm->tm_min, tm->tm_sec,
- filename.str);
- av_bprint_finalize(&filename, NULL);
- return 0;
-}
-
-int opt_report(const char *opt)
-{
- return init_report(NULL);
-}
-
-int opt_max_alloc(void *optctx, const char *opt, const char *arg)
-{
- char *tail;
- size_t max;
-
- max = strtol(arg, &tail, 10);
- if (*tail) {
- av_log(NULL, AV_LOG_FATAL, "Invalid max_alloc \"%s\".\n", arg);
- exit_program(1);
- }
- av_max_alloc(max);
- return 0;
-}
-
-int opt_timelimit(void *optctx, const char *opt, const char *arg)
-{
-#if HAVE_SETRLIMIT
- int lim = parse_number_or_die(opt, arg, OPT_INT64, 0, INT_MAX);
- struct rlimit rl = { lim, lim + 1 };
- if (setrlimit(RLIMIT_CPU, &rl))
- perror("setrlimit");
-#else
- av_log(NULL, AV_LOG_WARNING, "-%s not implemented on this OS\n", opt);
-#endif
- return 0;
-}
-
void print_error(const char *filename, int err)
{
- char errbuf[128];
- const char *errbuf_ptr = errbuf;
-
- if (av_strerror(err, errbuf, sizeof(errbuf)) < 0)
- errbuf_ptr = strerror(AVUNERROR(err));
- av_log(NULL, AV_LOG_ERROR, "%s: %s\n", filename, errbuf_ptr);
-}
-
-static int warned_cfg = 0;
-
-#define INDENT 1
-#define SHOW_VERSION 2
-#define SHOW_CONFIG 4
-#define SHOW_COPYRIGHT 8
-
-#define PRINT_LIB_INFO(libname, LIBNAME, flags, level) \
- if (CONFIG_##LIBNAME) { \
- const char *indent = flags & INDENT? " " : ""; \
- if (flags & SHOW_VERSION) { \
- unsigned int version = libname##_version(); \
- av_log(NULL, level, \
- "%slib%-11s %2d.%3d.%3d / %2d.%3d.%3d\n", \
- indent, #libname, \
- LIB##LIBNAME##_VERSION_MAJOR, \
- LIB##LIBNAME##_VERSION_MINOR, \
- LIB##LIBNAME##_VERSION_MICRO, \
- AV_VERSION_MAJOR(version), AV_VERSION_MINOR(version),\
- AV_VERSION_MICRO(version)); \
- } \
- if (flags & SHOW_CONFIG) { \
- const char *cfg = libname##_configuration(); \
- if (strcmp(FFMPEG_CONFIGURATION, cfg)) { \
- if (!warned_cfg) { \
- av_log(NULL, level, \
- "%sWARNING: library configuration mismatch\n", \
- indent); \
- warned_cfg = 1; \
- } \
- av_log(NULL, level, "%s%-11s configuration: %s\n", \
- indent, #libname, cfg); \
- } \
- } \
- } \
-
-static void print_all_libs_info(int flags, int level)
-{
- PRINT_LIB_INFO(avutil, AVUTIL, flags, level);
- PRINT_LIB_INFO(avcodec, AVCODEC, flags, level);
- PRINT_LIB_INFO(avformat, AVFORMAT, flags, level);
- PRINT_LIB_INFO(avdevice, AVDEVICE, flags, level);
- PRINT_LIB_INFO(avfilter, AVFILTER, flags, level);
- PRINT_LIB_INFO(swresample, AVRESAMPLE, flags, level);
- PRINT_LIB_INFO(swscale, SWSCALE, flags, level);
- PRINT_LIB_INFO(swresample, SWRESAMPLE, flags, level);
- PRINT_LIB_INFO(postproc, POSTPROC, flags, level);
-}
-
-static void print_program_info(int flags, int level)
-{
- const char *indent = flags & INDENT? " " : "";
-
- if (flags & SHOW_COPYRIGHT)
- av_log(NULL, level, "\n");
- av_log(NULL, level, FFMPEG_CONFIGURATION, indent);
-}
-
-static void print_buildconf(int flags, int level)
-{
- const char *indent = flags & INDENT ? " " : "";
- char str[] = { FFMPEG_CONFIGURATION };
- char *conflist, *remove_tilde, *splitconf;
-
- // Change all the ' --' strings to '~--' so that
- // they can be identified as tokens.
- while ((conflist = strstr(str, " --")) != NULL) {
- strncpy(conflist, "~--", 3);
- }
-
- // Compensate for the weirdness this would cause
- // when passing 'pkg-config --static'.
- while ((remove_tilde = strstr(str, "pkg-config~")) != NULL) {
- strncpy(remove_tilde, "pkg-config ", 11);
- }
-
- splitconf = strtok(str, "~");
- av_log(NULL, level, "\n%sconfiguration:\n", indent);
- while (splitconf != NULL) {
- av_log(NULL, level, "%s%s%s\n", indent, indent, splitconf);
- splitconf = strtok(NULL, "~");
- }
-}
-
-void show_banner(int argc, char **argv, const OptionDef *options)
-{
- int idx = locate_option(argc, argv, options, "version");
- if (hide_banner || idx)
- return;
-
- print_program_info (INDENT|SHOW_COPYRIGHT, AV_LOG_INFO);
- print_all_libs_info(INDENT|SHOW_CONFIG, AV_LOG_INFO);
- print_all_libs_info(INDENT|SHOW_VERSION, AV_LOG_INFO);
-}
-
-int show_version(void *optctx, const char *opt, const char *arg)
-{
- av_log_set_callback(log_callback_help);
- print_program_info (SHOW_COPYRIGHT, AV_LOG_INFO);
- print_all_libs_info(SHOW_VERSION, AV_LOG_INFO);
-
- return 0;
-}
-
-int show_buildconf(void *optctx, const char *opt, const char *arg)
-{
- av_log_set_callback(log_callback_help);
- print_buildconf (INDENT|0, AV_LOG_INFO);
-
- return 0;
-}
-
-int show_license(void *optctx, const char *opt, const char *arg)
-{
-#if CONFIG_NONFREE
- printf(
- "This version of %s has nonfree parts compiled in.\n"
- "Therefore it is not legally redistributable.\n",
- program_name );
-#elif CONFIG_GPLV3
- printf(
- "%s is free software; you can redistribute it and/or modify\n"
- "it under the terms of the GNU General Public License as published by\n"
- "the Free Software Foundation; either version 3 of the License, or\n"
- "(at your option) any later version.\n"
- "\n"
- "%s is distributed in the hope that it will be useful,\n"
- "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
- "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
- "GNU General Public License for more details.\n"
- "\n"
- "You should have received a copy of the GNU General Public License\n"
- "along with %s. If not, see .\n",
- program_name, program_name, program_name );
-#elif CONFIG_GPL
- printf(
- "%s is free software; you can redistribute it and/or modify\n"
- "it under the terms of the GNU General Public License as published by\n"
- "the Free Software Foundation; either version 2 of the License, or\n"
- "(at your option) any later version.\n"
- "\n"
- "%s is distributed in the hope that it will be useful,\n"
- "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
- "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
- "GNU General Public License for more details.\n"
- "\n"
- "You should have received a copy of the GNU General Public License\n"
- "along with %s; if not, write to the Free Software\n"
- "Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n",
- program_name, program_name, program_name );
-#elif CONFIG_LGPLV3
- printf(
- "%s is free software; you can redistribute it and/or modify\n"
- "it under the terms of the GNU Lesser General Public License as published by\n"
- "the Free Software Foundation; either version 3 of the License, or\n"
- "(at your option) any later version.\n"
- "\n"
- "%s is distributed in the hope that it will be useful,\n"
- "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
- "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
- "GNU Lesser General Public License for more details.\n"
- "\n"
- "You should have received a copy of the GNU Lesser General Public License\n"
- "along with %s. If not, see .\n",
- program_name, program_name, program_name );
-#else
- printf(
- "%s is free software; you can redistribute it and/or\n"
- "modify it under the terms of the GNU Lesser General Public\n"
- "License as published by the Free Software Foundation; either\n"
- "version 2.1 of the License, or (at your option) any later version.\n"
- "\n"
- "%s is distributed in the hope that it will be useful,\n"
- "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
- "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\n"
- "Lesser General Public License for more details.\n"
- "\n"
- "You should have received a copy of the GNU Lesser General Public\n"
- "License along with %s; if not, write to the Free Software\n"
- "Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n",
- program_name, program_name, program_name );
-#endif
-
- return 0;
-}
-
-static int is_device(const AVClass *avclass)
-{
- if (!avclass)
- return 0;
- return AV_IS_INPUT_DEVICE(avclass->category) || AV_IS_OUTPUT_DEVICE(avclass->category);
-}
-
-static int show_formats_devices(void *optctx, const char *opt, const char *arg, int device_only)
-{
- AVInputFormat *ifmt = NULL;
- AVOutputFormat *ofmt = NULL;
- const char *last_name;
- int is_dev;
-
- printf("%s\n"
- " D. = Demuxing supported\n"
- " .E = Muxing supported\n"
- " --\n", device_only ? "Devices:" : "File formats:");
- last_name = "000";
- for (;;) {
- int decode = 0;
- int encode = 0;
- const char *name = NULL;
- const char *long_name = NULL;
-
- while ((ofmt = av_oformat_next(ofmt))) {
- is_dev = is_device(ofmt->priv_class);
- if (!is_dev && device_only)
- continue;
- if ((!name || strcmp(ofmt->name, name) < 0) &&
- strcmp(ofmt->name, last_name) > 0) {
- name = ofmt->name;
- long_name = ofmt->long_name;
- encode = 1;
- }
- }
- while ((ifmt = av_iformat_next(ifmt))) {
- is_dev = is_device(ifmt->priv_class);
- if (!is_dev && device_only)
- continue;
- if ((!name || strcmp(ifmt->name, name) < 0) &&
- strcmp(ifmt->name, last_name) > 0) {
- name = ifmt->name;
- long_name = ifmt->long_name;
- encode = 0;
- }
- if (name && strcmp(ifmt->name, name) == 0)
- decode = 1;
- }
- if (!name)
- break;
- last_name = name;
-
- printf(" %s%s %-15s %s\n",
- decode ? "D" : " ",
- encode ? "E" : " ",
- name,
- long_name ? long_name:" ");
- }
- return 0;
-}
-
-int show_formats(void *optctx, const char *opt, const char *arg)
-{
- return show_formats_devices(optctx, opt, arg, 0);
-}
-
-int show_devices(void *optctx, const char *opt, const char *arg)
-{
- return show_formats_devices(optctx, opt, arg, 1);
-}
-
-#define PRINT_CODEC_SUPPORTED(codec, field, type, list_name, term, get_name) \
- if (codec->field) { \
- const type *p = codec->field; \
- \
- printf(" Supported " list_name ":"); \
- while (*p != term) { \
- get_name(*p); \
- printf(" %s", name); \
- p++; \
- } \
- printf("\n"); \
- } \
-
-static void print_codec(const AVCodec *c)
-{
- int encoder = av_codec_is_encoder(c);
-
- printf("%s %s [%s]:\n", encoder ? "Encoder" : "Decoder", c->name,
- c->long_name ? c->long_name : "");
-
- printf(" General capabilities: ");
- if (c->capabilities & AV_CODEC_CAP_DRAW_HORIZ_BAND)
- printf("horizband ");
- if (c->capabilities & AV_CODEC_CAP_DR1)
- printf("dr1 ");
- if (c->capabilities & AV_CODEC_CAP_TRUNCATED)
- printf("trunc ");
- if (c->capabilities & AV_CODEC_CAP_DELAY)
- printf("delay ");
- if (c->capabilities & AV_CODEC_CAP_SMALL_LAST_FRAME)
- printf("small ");
- if (c->capabilities & AV_CODEC_CAP_SUBFRAMES)
- printf("subframes ");
- if (c->capabilities & AV_CODEC_CAP_EXPERIMENTAL)
- printf("exp ");
- if (c->capabilities & AV_CODEC_CAP_CHANNEL_CONF)
- printf("chconf ");
- if (c->capabilities & AV_CODEC_CAP_PARAM_CHANGE)
- printf("paramchange ");
- if (c->capabilities & AV_CODEC_CAP_VARIABLE_FRAME_SIZE)
- printf("variable ");
- if (c->capabilities & (AV_CODEC_CAP_FRAME_THREADS |
- AV_CODEC_CAP_SLICE_THREADS |
- AV_CODEC_CAP_AUTO_THREADS))
- printf("threads ");
- if (!c->capabilities)
- printf("none");
- printf("\n");
-
- if (c->type == AVMEDIA_TYPE_VIDEO ||
- c->type == AVMEDIA_TYPE_AUDIO) {
- printf(" Threading capabilities: ");
- switch (c->capabilities & (AV_CODEC_CAP_FRAME_THREADS |
- AV_CODEC_CAP_SLICE_THREADS |
- AV_CODEC_CAP_AUTO_THREADS)) {
- case AV_CODEC_CAP_FRAME_THREADS |
- AV_CODEC_CAP_SLICE_THREADS: printf("frame and slice"); break;
- case AV_CODEC_CAP_FRAME_THREADS: printf("frame"); break;
- case AV_CODEC_CAP_SLICE_THREADS: printf("slice"); break;
- case AV_CODEC_CAP_AUTO_THREADS : printf("auto"); break;
- default: printf("none"); break;
- }
- printf("\n");
- }
-
- if (c->supported_framerates) {
- const AVRational *fps = c->supported_framerates;
-
- printf(" Supported framerates:");
- while (fps->num) {
- printf(" %d/%d", fps->num, fps->den);
- fps++;
- }
- printf("\n");
- }
- PRINT_CODEC_SUPPORTED(c, pix_fmts, enum AVPixelFormat, "pixel formats",
- AV_PIX_FMT_NONE, GET_PIX_FMT_NAME);
- PRINT_CODEC_SUPPORTED(c, supported_samplerates, int, "sample rates", 0,
- GET_SAMPLE_RATE_NAME);
- PRINT_CODEC_SUPPORTED(c, sample_fmts, enum AVSampleFormat, "sample formats",
- AV_SAMPLE_FMT_NONE, GET_SAMPLE_FMT_NAME);
- PRINT_CODEC_SUPPORTED(c, channel_layouts, uint64_t, "channel layouts",
- 0, GET_CH_LAYOUT_DESC);
-
- if (c->priv_class) {
- show_help_children(c->priv_class,
- AV_OPT_FLAG_ENCODING_PARAM |
- AV_OPT_FLAG_DECODING_PARAM);
- }
-}
-
-static char get_media_type_char(enum AVMediaType type)
-{
- switch (type) {
- case AVMEDIA_TYPE_VIDEO: return 'V';
- case AVMEDIA_TYPE_AUDIO: return 'A';
- case AVMEDIA_TYPE_DATA: return 'D';
- case AVMEDIA_TYPE_SUBTITLE: return 'S';
- case AVMEDIA_TYPE_ATTACHMENT:return 'T';
- default: return '?';
- }
-}
-
-static const AVCodec *next_codec_for_id(enum AVCodecID id, const AVCodec *prev,
- int encoder)
-{
- while ((prev = av_codec_next(prev))) {
- if (prev->id == id &&
- (encoder ? av_codec_is_encoder(prev) : av_codec_is_decoder(prev)))
- return prev;
- }
- return NULL;
-}
-
-static int compare_codec_desc(const void *a, const void *b)
-{
- const AVCodecDescriptor * const *da = a;
- const AVCodecDescriptor * const *db = b;
-
- return (*da)->type != (*db)->type ? FFDIFFSIGN((*da)->type, (*db)->type) :
- strcmp((*da)->name, (*db)->name);
-}
-
-static unsigned get_codecs_sorted(const AVCodecDescriptor ***rcodecs)
-{
- const AVCodecDescriptor *desc = NULL;
- const AVCodecDescriptor **codecs;
- unsigned nb_codecs = 0, i = 0;
-
- while ((desc = avcodec_descriptor_next(desc)))
- nb_codecs++;
- if (!(codecs = av_calloc(nb_codecs, sizeof(*codecs)))) {
- av_log(NULL, AV_LOG_ERROR, "Out of memory\n");
- exit_program(1);
- }
- desc = NULL;
- while ((desc = avcodec_descriptor_next(desc)))
- codecs[i++] = desc;
- av_assert0(i == nb_codecs);
- qsort(codecs, nb_codecs, sizeof(*codecs), compare_codec_desc);
- *rcodecs = codecs;
- return nb_codecs;
-}
-
-static void print_codecs_for_id(enum AVCodecID id, int encoder)
-{
- const AVCodec *codec = NULL;
-
- printf(" (%s: ", encoder ? "encoders" : "decoders");
-
- while ((codec = next_codec_for_id(id, codec, encoder)))
- printf("%s ", codec->name);
-
- printf(")");
-}
-
-int show_codecs(void *optctx, const char *opt, const char *arg)
-{
- const AVCodecDescriptor **codecs;
- unsigned i, nb_codecs = get_codecs_sorted(&codecs);
-
- printf("Codecs:\n"
- " D..... = Decoding supported\n"
- " .E.... = Encoding supported\n"
- " ..V... = Video codec\n"
- " ..A... = Audio codec\n"
- " ..S... = Subtitle codec\n"
- " ...I.. = Intra frame-only codec\n"
- " ....L. = Lossy compression\n"
- " .....S = Lossless compression\n"
- " -------\n");
- for (i = 0; i < nb_codecs; i++) {
- const AVCodecDescriptor *desc = codecs[i];
- const AVCodec *codec = NULL;
-
- if (strstr(desc->name, "_deprecated"))
- continue;
-
- printf(" ");
- printf(avcodec_find_decoder(desc->id) ? "D" : ".");
- printf(avcodec_find_encoder(desc->id) ? "E" : ".");
-
- printf("%c", get_media_type_char(desc->type));
- printf((desc->props & AV_CODEC_PROP_INTRA_ONLY) ? "I" : ".");
- printf((desc->props & AV_CODEC_PROP_LOSSY) ? "L" : ".");
- printf((desc->props & AV_CODEC_PROP_LOSSLESS) ? "S" : ".");
-
- printf(" %-20s %s", desc->name, desc->long_name ? desc->long_name : "");
-
- /* print decoders/encoders when there's more than one or their
- * names are different from codec name */
- while ((codec = next_codec_for_id(desc->id, codec, 0))) {
- if (strcmp(codec->name, desc->name)) {
- print_codecs_for_id(desc->id, 0);
- break;
- }
- }
- codec = NULL;
- while ((codec = next_codec_for_id(desc->id, codec, 1))) {
- if (strcmp(codec->name, desc->name)) {
- print_codecs_for_id(desc->id, 1);
- break;
- }
- }
-
- printf("\n");
- }
- av_free(codecs);
- return 0;
-}
-
-static void print_codecs(int encoder)
-{
- const AVCodecDescriptor **codecs;
- unsigned i, nb_codecs = get_codecs_sorted(&codecs);
-
- printf("%s:\n"
- " V..... = Video\n"
- " A..... = Audio\n"
- " S..... = Subtitle\n"
- " .F.... = Frame-level multithreading\n"
- " ..S... = Slice-level multithreading\n"
- " ...X.. = Codec is experimental\n"
- " ....B. = Supports draw_horiz_band\n"
- " .....D = Supports direct rendering method 1\n"
- " ------\n",
- encoder ? "Encoders" : "Decoders");
- for (i = 0; i < nb_codecs; i++) {
- const AVCodecDescriptor *desc = codecs[i];
- const AVCodec *codec = NULL;
-
- while ((codec = next_codec_for_id(desc->id, codec, encoder))) {
- printf(" %c", get_media_type_char(desc->type));
- printf((codec->capabilities & AV_CODEC_CAP_FRAME_THREADS) ? "F" : ".");
- printf((codec->capabilities & AV_CODEC_CAP_SLICE_THREADS) ? "S" : ".");
- printf((codec->capabilities & AV_CODEC_CAP_EXPERIMENTAL) ? "X" : ".");
- printf((codec->capabilities & AV_CODEC_CAP_DRAW_HORIZ_BAND)?"B" : ".");
- printf((codec->capabilities & AV_CODEC_CAP_DR1) ? "D" : ".");
-
- printf(" %-20s %s", codec->name, codec->long_name ? codec->long_name : "");
- if (strcmp(codec->name, desc->name))
- printf(" (codec %s)", desc->name);
-
- printf("\n");
- }
- }
- av_free(codecs);
-}
-
-int show_decoders(void *optctx, const char *opt, const char *arg)
-{
- print_codecs(0);
- return 0;
-}
-
-int show_encoders(void *optctx, const char *opt, const char *arg)
-{
- print_codecs(1);
- return 0;
-}
-
-int show_bsfs(void *optctx, const char *opt, const char *arg)
-{
- AVBitStreamFilter *bsf = NULL;
-
- printf("Bitstream filters:\n");
- while ((bsf = av_bitstream_filter_next(bsf)))
- printf("%s\n", bsf->name);
- printf("\n");
- return 0;
-}
-
-int show_protocols(void *optctx, const char *opt, const char *arg)
-{
- void *opaque = NULL;
- const char *name;
-
- printf("Supported file protocols:\n"
- "Input:\n");
- while ((name = avio_enum_protocols(&opaque, 0)))
- printf(" %s\n", name);
- printf("Output:\n");
- while ((name = avio_enum_protocols(&opaque, 1)))
- printf(" %s\n", name);
- return 0;
-}
-
-int show_filters(void *optctx, const char *opt, const char *arg)
-{
-#if CONFIG_AVFILTER
- const AVFilter *filter = NULL;
- char descr[64], *descr_cur;
- int i, j;
- const AVFilterPad *pad;
-
- printf("Filters:\n"
- " T.. = Timeline support\n"
- " .S. = Slice threading\n"
- " ..C = Command support\n"
- " A = Audio input/output\n"
- " V = Video input/output\n"
- " N = Dynamic number and/or type of input/output\n"
- " | = Source or sink filter\n");
- while ((filter = avfilter_next(filter))) {
- descr_cur = descr;
- for (i = 0; i < 2; i++) {
- if (i) {
- *(descr_cur++) = '-';
- *(descr_cur++) = '>';
- }
- pad = i ? filter->outputs : filter->inputs;
- for (j = 0; pad && avfilter_pad_get_name(pad, j); j++) {
- if (descr_cur >= descr + sizeof(descr) - 4)
- break;
- *(descr_cur++) = get_media_type_char(avfilter_pad_get_type(pad, j));
- }
- if (!j)
- *(descr_cur++) = ((!i && (filter->flags & AVFILTER_FLAG_DYNAMIC_INPUTS)) ||
- ( i && (filter->flags & AVFILTER_FLAG_DYNAMIC_OUTPUTS))) ? 'N' : '|';
- }
- *descr_cur = 0;
- printf(" %c%c%c %-17s %-10s %s\n",
- filter->flags & AVFILTER_FLAG_SUPPORT_TIMELINE ? 'T' : '.',
- filter->flags & AVFILTER_FLAG_SLICE_THREADS ? 'S' : '.',
- filter->process_command ? 'C' : '.',
- filter->name, descr, filter->description);
- }
-#else
- printf("No filters available: libavfilter disabled\n");
-#endif
- return 0;
-}
-
-int show_colors(void *optctx, const char *opt, const char *arg)
-{
- const char *name;
- const uint8_t *rgb;
- int i;
-
- printf("%-32s #RRGGBB\n", "name");
-
- for (i = 0; name = av_get_known_color_name(i, &rgb); i++)
- printf("%-32s #%02x%02x%02x\n", name, rgb[0], rgb[1], rgb[2]);
-
- return 0;
-}
-
-int show_pix_fmts(void *optctx, const char *opt, const char *arg)
-{
- const AVPixFmtDescriptor *pix_desc = NULL;
-
- printf("Pixel formats:\n"
- "I.... = Supported Input format for conversion\n"
- ".O... = Supported Output format for conversion\n"
- "..H.. = Hardware accelerated format\n"
- "...P. = Paletted format\n"
- "....B = Bitstream format\n"
- "FLAGS NAME NB_COMPONENTS BITS_PER_PIXEL\n"
- "-----\n");
-
-#if !CONFIG_SWSCALE
-# define sws_isSupportedInput(x) 0
-# define sws_isSupportedOutput(x) 0
-#endif
-
- while ((pix_desc = av_pix_fmt_desc_next(pix_desc))) {
- enum AVPixelFormat pix_fmt = av_pix_fmt_desc_get_id(pix_desc);
- printf("%c%c%c%c%c %-16s %d %2d\n",
- sws_isSupportedInput (pix_fmt) ? 'I' : '.',
- sws_isSupportedOutput(pix_fmt) ? 'O' : '.',
- pix_desc->flags & AV_PIX_FMT_FLAG_HWACCEL ? 'H' : '.',
- pix_desc->flags & AV_PIX_FMT_FLAG_PAL ? 'P' : '.',
- pix_desc->flags & AV_PIX_FMT_FLAG_BITSTREAM ? 'B' : '.',
- pix_desc->name,
- pix_desc->nb_components,
- av_get_bits_per_pixel(pix_desc));
- }
- return 0;
-}
-
-int show_layouts(void *optctx, const char *opt, const char *arg)
-{
- int i = 0;
- uint64_t layout, j;
- const char *name, *descr;
-
- printf("Individual channels:\n"
- "NAME DESCRIPTION\n");
- for (i = 0; i < 63; i++) {
- name = av_get_channel_name((uint64_t)1 << i);
- if (!name)
- continue;
- descr = av_get_channel_description((uint64_t)1 << i);
- printf("%-14s %s\n", name, descr);
- }
- printf("\nStandard channel layouts:\n"
- "NAME DECOMPOSITION\n");
- for (i = 0; !av_get_standard_channel_layout(i, &layout, &name); i++) {
- if (name) {
- printf("%-14s ", name);
- for (j = 1; j; j <<= 1)
- if ((layout & j))
- printf("%s%s", (layout & (j - 1)) ? "+" : "", av_get_channel_name(j));
- printf("\n");
- }
- }
- return 0;
-}
-
-int show_sample_fmts(void *optctx, const char *opt, const char *arg)
-{
- int i;
- char fmt_str[128];
- for (i = -1; i < AV_SAMPLE_FMT_NB; i++)
- printf("%s\n", av_get_sample_fmt_string(fmt_str, sizeof(fmt_str), i));
- return 0;
-}
-
-static void show_help_codec(const char *name, int encoder)
-{
- const AVCodecDescriptor *desc;
- const AVCodec *codec;
-
- if (!name) {
- av_log(NULL, AV_LOG_ERROR, "No codec name specified.\n");
- return;
- }
-
- codec = encoder ? avcodec_find_encoder_by_name(name) :
- avcodec_find_decoder_by_name(name);
-
- if (codec)
- print_codec(codec);
- else if ((desc = avcodec_descriptor_get_by_name(name))) {
- int printed = 0;
-
- while ((codec = next_codec_for_id(desc->id, codec, encoder))) {
- printed = 1;
- print_codec(codec);
- }
-
- if (!printed) {
- av_log(NULL, AV_LOG_ERROR, "Codec '%s' is known to FFmpeg, "
- "but no %s for it are available. FFmpeg might need to be "
- "recompiled with additional external libraries.\n",
- name, encoder ? "encoders" : "decoders");
- }
- } else {
- av_log(NULL, AV_LOG_ERROR, "Codec '%s' is not recognized by FFmpeg.\n",
- name);
- }
-}
-
-static void show_help_demuxer(const char *name)
-{
- const AVInputFormat *fmt = av_find_input_format(name);
-
- if (!fmt) {
- av_log(NULL, AV_LOG_ERROR, "Unknown format '%s'.\n", name);
- return;
- }
-
- printf("Demuxer %s [%s]:\n", fmt->name, fmt->long_name);
-
- if (fmt->extensions)
- printf(" Common extensions: %s.\n", fmt->extensions);
-
- if (fmt->priv_class)
- show_help_children(fmt->priv_class, AV_OPT_FLAG_DECODING_PARAM);
-}
-
-static void show_help_muxer(const char *name)
-{
- const AVCodecDescriptor *desc;
- const AVOutputFormat *fmt = av_guess_format(name, NULL, NULL);
-
- if (!fmt) {
- av_log(NULL, AV_LOG_ERROR, "Unknown format '%s'.\n", name);
- return;
- }
-
- printf("Muxer %s [%s]:\n", fmt->name, fmt->long_name);
-
- if (fmt->extensions)
- printf(" Common extensions: %s.\n", fmt->extensions);
- if (fmt->mime_type)
- printf(" Mime type: %s.\n", fmt->mime_type);
- if (fmt->video_codec != AV_CODEC_ID_NONE &&
- (desc = avcodec_descriptor_get(fmt->video_codec))) {
- printf(" Default video codec: %s.\n", desc->name);
- }
- if (fmt->audio_codec != AV_CODEC_ID_NONE &&
- (desc = avcodec_descriptor_get(fmt->audio_codec))) {
- printf(" Default audio codec: %s.\n", desc->name);
- }
- if (fmt->subtitle_codec != AV_CODEC_ID_NONE &&
- (desc = avcodec_descriptor_get(fmt->subtitle_codec))) {
- printf(" Default subtitle codec: %s.\n", desc->name);
- }
-
- if (fmt->priv_class)
- show_help_children(fmt->priv_class, AV_OPT_FLAG_ENCODING_PARAM);
-}
-
-#if CONFIG_AVFILTER
-static void show_help_filter(const char *name)
-{
-#if CONFIG_AVFILTER
- const AVFilter *f = avfilter_get_by_name(name);
- int i, count;
-
- if (!name) {
- av_log(NULL, AV_LOG_ERROR, "No filter name specified.\n");
- return;
- } else if (!f) {
- av_log(NULL, AV_LOG_ERROR, "Unknown filter '%s'.\n", name);
- return;
- }
-
- printf("Filter %s\n", f->name);
- if (f->description)
- printf(" %s\n", f->description);
-
- if (f->flags & AVFILTER_FLAG_SLICE_THREADS)
- printf(" slice threading supported\n");
-
- printf(" Inputs:\n");
- count = avfilter_pad_count(f->inputs);
- for (i = 0; i < count; i++) {
- printf(" #%d: %s (%s)\n", i, avfilter_pad_get_name(f->inputs, i),
- media_type_string(avfilter_pad_get_type(f->inputs, i)));
- }
- if (f->flags & AVFILTER_FLAG_DYNAMIC_INPUTS)
- printf(" dynamic (depending on the options)\n");
- else if (!count)
- printf(" none (source filter)\n");
-
- printf(" Outputs:\n");
- count = avfilter_pad_count(f->outputs);
- for (i = 0; i < count; i++) {
- printf(" #%d: %s (%s)\n", i, avfilter_pad_get_name(f->outputs, i),
- media_type_string(avfilter_pad_get_type(f->outputs, i)));
- }
- if (f->flags & AVFILTER_FLAG_DYNAMIC_OUTPUTS)
- printf(" dynamic (depending on the options)\n");
- else if (!count)
- printf(" none (sink filter)\n");
-
- if (f->priv_class)
- show_help_children(f->priv_class, AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_FILTERING_PARAM |
- AV_OPT_FLAG_AUDIO_PARAM);
- if (f->flags & AVFILTER_FLAG_SUPPORT_TIMELINE)
- printf("This filter has support for timeline through the 'enable' option.\n");
-#else
- av_log(NULL, AV_LOG_ERROR, "Build without libavfilter; "
- "can not to satisfy request\n");
-#endif
-}
-#endif
-
-int show_help(void *optctx, const char *opt, const char *arg)
-{
- char *topic, *par;
- av_log_set_callback(log_callback_help);
-
- topic = av_strdup(arg ? arg : "");
- if (!topic)
- return AVERROR(ENOMEM);
- par = strchr(topic, '=');
- if (par)
- *par++ = 0;
-
- if (!*topic) {
- show_help_default(topic, par);
- } else if (!strcmp(topic, "decoder")) {
- show_help_codec(par, 0);
- } else if (!strcmp(topic, "encoder")) {
- show_help_codec(par, 1);
- } else if (!strcmp(topic, "demuxer")) {
- show_help_demuxer(par);
- } else if (!strcmp(topic, "muxer")) {
- show_help_muxer(par);
-#if CONFIG_AVFILTER
- } else if (!strcmp(topic, "filter")) {
- show_help_filter(par);
-#endif
- } else {
- show_help_default(topic, par);
- }
-
- av_freep(&topic);
- return 0;
+ av_log(NULL, AV_LOG_ERROR, "%s: %s\n", filename, av_err2str(err));
}
int read_yesno(void)
@@ -1906,28 +818,45 @@ FILE *get_preset_file(char *filename, size_t filename_size,
{
FILE *f = NULL;
int i;
- const char *base[3] = { getenv("FFMPEG_DATADIR"),
- getenv("HOME"),
+#if HAVE_GETMODULEHANDLE && defined(_WIN32)
+ char *datadir = NULL;
+#endif
+ char *env_home = getenv_utf8("HOME");
+ char *env_ffmpeg_datadir = getenv_utf8("FFMPEG_DATADIR");
+ const char *base[3] = { env_ffmpeg_datadir,
+ env_home, /* index=1(HOME) is special: search in a .ffmpeg subfolder */
FFMPEG_DATADIR, };
if (is_path) {
av_strlcpy(filename, preset_name, filename_size);
- f = fopen(filename, "r");
+ f = fopen_utf8(filename, "r");
} else {
-#ifdef _WIN32
- char datadir[MAX_PATH], *ls;
+#if HAVE_GETMODULEHANDLE && defined(_WIN32)
+ wchar_t *datadir_w = get_module_filename(NULL);
base[2] = NULL;
- if (GetModuleFileNameA(GetModuleHandleA(NULL), datadir, sizeof(datadir) - 1))
+ if (wchartoutf8(datadir_w, &datadir))
+ datadir = NULL;
+ av_free(datadir_w);
+
+ if (datadir)
{
- for (ls = datadir; ls < datadir + strlen(datadir); ls++)
+ char *ls;
+ for (ls = datadir; *ls; ls++)
if (*ls == '\\') *ls = '/';
if (ls = strrchr(datadir, '/'))
{
- *ls = 0;
- strncat(datadir, "/ffpresets", sizeof(datadir) - 1 - strlen(datadir));
- base[2] = datadir;
+ ptrdiff_t datadir_len = ls - datadir;
+ size_t desired_size = datadir_len + strlen("/ffpresets") + 1;
+ char *new_datadir = av_realloc_array(
+ datadir, desired_size, sizeof *datadir);
+ if (new_datadir) {
+ datadir = new_datadir;
+ datadir[datadir_len] = 0;
+ strncat(datadir, "/ffpresets", desired_size - 1 - datadir_len);
+ base[2] = datadir;
+ }
}
}
#endif
@@ -1936,17 +865,22 @@ FILE *get_preset_file(char *filename, size_t filename_size,
continue;
snprintf(filename, filename_size, "%s%s/%s.ffpreset", base[i],
i != 1 ? "" : "/.ffmpeg", preset_name);
- f = fopen(filename, "r");
+ f = fopen_utf8(filename, "r");
if (!f && codec_name) {
snprintf(filename, filename_size,
"%s%s/%s-%s.ffpreset",
base[i], i != 1 ? "" : "/.ffmpeg", codec_name,
preset_name);
- f = fopen(filename, "r");
+ f = fopen_utf8(filename, "r");
}
}
}
+#if HAVE_GETMODULEHANDLE && defined(_WIN32)
+ av_free(datadir);
+#endif
+ freeenv_utf8(env_ffmpeg_datadir);
+ freeenv_utf8(env_home);
return f;
}
@@ -1959,10 +893,10 @@ int check_stream_specifier(AVFormatContext *s, AVStream *st, const char *spec)
}
AVDictionary *filter_codec_opts(AVDictionary *opts, enum AVCodecID codec_id,
- AVFormatContext *s, AVStream *st, AVCodec *codec)
+ AVFormatContext *s, AVStream *st, const AVCodec *codec)
{
AVDictionary *ret = NULL;
- AVDictionaryEntry *t = NULL;
+ const AVDictionaryEntry *t = NULL;
int flags = s->oformat ? AV_OPT_FLAG_ENCODING_PARAM
: AV_OPT_FLAG_DECODING_PARAM;
char prefix = 0;
@@ -1972,7 +906,7 @@ AVDictionary *filter_codec_opts(AVDictionary *opts, enum AVCodecID codec_id,
codec = s->oformat ? avcodec_find_encoder(codec_id)
: avcodec_find_decoder(codec_id);
- switch (st->codec->codec_type) {
+ switch (st->codecpar->codec_type) {
case AVMEDIA_TYPE_VIDEO:
prefix = 'v';
flags |= AV_OPT_FLAG_VIDEO_PARAM;
@@ -1987,7 +921,8 @@ AVDictionary *filter_codec_opts(AVDictionary *opts, enum AVCodecID codec_id,
break;
}
- while (t = av_dict_get(opts, "", t, AV_DICT_IGNORE_SUFFIX)) {
+ while (t = av_dict_iterate(opts, t)) {
+ const AVClass *priv_class;
char *p = strchr(t->key, ':');
/* check stream specification in opt name */
@@ -2000,8 +935,8 @@ AVDictionary *filter_codec_opts(AVDictionary *opts, enum AVCodecID codec_id,
if (av_opt_find(&cc, t->key, NULL, flags, AV_OPT_SEARCH_FAKE_OBJ) ||
!codec ||
- (codec->priv_class &&
- av_opt_find(&codec->priv_class, t->key, NULL, flags,
+ ((priv_class = codec->priv_class) &&
+ av_opt_find(&priv_class, t->key, NULL, flags,
AV_OPT_SEARCH_FAKE_OBJ)))
av_dict_set(&ret, t->key, t->value, 0);
else if (t->key[0] == prefix &&
@@ -2023,14 +958,11 @@ AVDictionary **setup_find_stream_info_opts(AVFormatContext *s,
if (!s->nb_streams)
return NULL;
- opts = av_mallocz_array(s->nb_streams, sizeof(*opts));
- if (!opts) {
- av_log(NULL, AV_LOG_ERROR,
- "Could not alloc memory for stream options.\n");
- return NULL;
- }
+ opts = av_calloc(s->nb_streams, sizeof(*opts));
+ if (!opts)
+ report_and_exit(AVERROR(ENOMEM));
for (i = 0; i < s->nb_streams; i++)
- opts[i] = filter_codec_opts(codec_opts, s->streams[i]->codec->codec_id,
+ opts[i] = filter_codec_opts(codec_opts, s->streams[i]->codecpar->codec_id,
s, s->streams[i], NULL);
return opts;
}
@@ -2043,10 +975,8 @@ void *grow_array(void *array, int elem_size, int *size, int new_size)
}
if (*size < new_size) {
uint8_t *tmp = av_realloc_array(array, new_size, elem_size);
- if (!tmp) {
- av_log(NULL, AV_LOG_ERROR, "Could not alloc buffer.\n");
- exit_program(1);
- }
+ if (!tmp)
+ report_and_exit(AVERROR(ENOMEM));
memset(tmp + *size*elem_size, 0, (new_size-*size) * elem_size);
*size = new_size;
return tmp;
@@ -2054,188 +984,29 @@ void *grow_array(void *array, int elem_size, int *size, int new_size)
return array;
}
-double get_rotation(AVStream *st)
+void *allocate_array_elem(void *ptr, size_t elem_size, int *nb_elems)
{
- AVDictionaryEntry *rotate_tag = av_dict_get(st->metadata, "rotate", NULL, 0);
- uint8_t* displaymatrix = av_stream_get_side_data(st,
- AV_PKT_DATA_DISPLAYMATRIX, NULL);
- double theta = 0;
+ void *new_elem;
- if (rotate_tag && *rotate_tag->value && strcmp(rotate_tag->value, "0")) {
- char *tail;
- theta = av_strtod(rotate_tag->value, &tail);
- if (*tail)
- theta = 0;
- }
- if (displaymatrix && !theta)
- theta = -av_display_rotation_get((int32_t*) displaymatrix);
+ if (!(new_elem = av_mallocz(elem_size)) ||
+ av_dynarray_add_nofree(ptr, nb_elems, new_elem) < 0)
+ report_and_exit(AVERROR(ENOMEM));
+ return new_elem;
+}
+
+double get_rotation(int32_t *displaymatrix)
+{
+ double theta = 0;
+ if (displaymatrix)
+ theta = -round(av_display_rotation_get((int32_t*) displaymatrix));
theta -= 360*floor(theta/360 + 0.9/360);
if (fabs(theta - 90*round(theta/90)) > 2)
av_log(NULL, AV_LOG_WARNING, "Odd rotation angle.\n"
"If you want to help, upload a sample "
- "of this file to ftp://upload.ffmpeg.org/incoming/ "
+ "of this file to https://streams.videolan.org/upload/ "
"and contact the ffmpeg-devel mailing list. (ffmpeg-devel@ffmpeg.org)");
return theta;
}
-
-#if CONFIG_AVDEVICE
-static int print_device_sources(AVInputFormat *fmt, AVDictionary *opts)
-{
- int ret, i;
- AVDeviceInfoList *device_list = NULL;
-
- if (!fmt || !fmt->priv_class || !AV_IS_INPUT_DEVICE(fmt->priv_class->category))
- return AVERROR(EINVAL);
-
- printf("Audo-detected sources for %s:\n", fmt->name);
- if (!fmt->get_device_list) {
- ret = AVERROR(ENOSYS);
- printf("Cannot list sources. Not implemented.\n");
- goto fail;
- }
-
- if ((ret = avdevice_list_input_sources(fmt, NULL, opts, &device_list)) < 0) {
- printf("Cannot list sources.\n");
- goto fail;
- }
-
- for (i = 0; i < device_list->nb_devices; i++) {
- printf("%s %s [%s]\n", device_list->default_device == i ? "*" : " ",
- device_list->devices[i]->device_name, device_list->devices[i]->device_description);
- }
-
- fail:
- avdevice_free_list_devices(&device_list);
- return ret;
-}
-
-static int print_device_sinks(AVOutputFormat *fmt, AVDictionary *opts)
-{
- int ret, i;
- AVDeviceInfoList *device_list = NULL;
-
- if (!fmt || !fmt->priv_class || !AV_IS_OUTPUT_DEVICE(fmt->priv_class->category))
- return AVERROR(EINVAL);
-
- printf("Audo-detected sinks for %s:\n", fmt->name);
- if (!fmt->get_device_list) {
- ret = AVERROR(ENOSYS);
- printf("Cannot list sinks. Not implemented.\n");
- goto fail;
- }
-
- if ((ret = avdevice_list_output_sinks(fmt, NULL, opts, &device_list)) < 0) {
- printf("Cannot list sinks.\n");
- goto fail;
- }
-
- for (i = 0; i < device_list->nb_devices; i++) {
- printf("%s %s [%s]\n", device_list->default_device == i ? "*" : " ",
- device_list->devices[i]->device_name, device_list->devices[i]->device_description);
- }
-
- fail:
- avdevice_free_list_devices(&device_list);
- return ret;
-}
-
-static int show_sinks_sources_parse_arg(const char *arg, char **dev, AVDictionary **opts)
-{
- int ret;
- if (arg) {
- char *opts_str = NULL;
- av_assert0(dev && opts);
- *dev = av_strdup(arg);
- if (!*dev)
- return AVERROR(ENOMEM);
- if ((opts_str = strchr(*dev, ','))) {
- *(opts_str++) = '\0';
- if (opts_str[0] && ((ret = av_dict_parse_string(opts, opts_str, "=", ":", 0)) < 0)) {
- av_freep(dev);
- return ret;
- }
- }
- } else
- printf("\nDevice name is not provided.\n"
- "You can pass devicename[,opt1=val1[,opt2=val2...]] as an argument.\n\n");
- return 0;
-}
-
-int show_sources(void *optctx, const char *opt, const char *arg)
-{
- AVInputFormat *fmt = NULL;
- char *dev = NULL;
- AVDictionary *opts = NULL;
- int ret = 0;
- int error_level = av_log_get_level();
-
- av_log_set_level(AV_LOG_ERROR);
-
- if ((ret = show_sinks_sources_parse_arg(arg, &dev, &opts)) < 0)
- goto fail;
-
- do {
- fmt = av_input_audio_device_next(fmt);
- if (fmt) {
- if (!strcmp(fmt->name, "lavfi"))
- continue; //it's pointless to probe lavfi
- if (dev && !av_match_name(dev, fmt->name))
- continue;
- print_device_sources(fmt, opts);
- }
- } while (fmt);
- do {
- fmt = av_input_video_device_next(fmt);
- if (fmt) {
- if (dev && !av_match_name(dev, fmt->name))
- continue;
- print_device_sources(fmt, opts);
- }
- } while (fmt);
- fail:
- av_dict_free(&opts);
- av_free(dev);
- av_log_set_level(error_level);
- return ret;
-}
-
-int show_sinks(void *optctx, const char *opt, const char *arg)
-{
- AVOutputFormat *fmt = NULL;
- char *dev = NULL;
- AVDictionary *opts = NULL;
- int ret = 0;
- int error_level = av_log_get_level();
-
- av_log_set_level(AV_LOG_ERROR);
-
- if ((ret = show_sinks_sources_parse_arg(arg, &dev, &opts)) < 0)
- goto fail;
-
- do {
- fmt = av_output_audio_device_next(fmt);
- if (fmt) {
- if (dev && !av_match_name(dev, fmt->name))
- continue;
- print_device_sinks(fmt, opts);
- }
- } while (fmt);
- do {
- fmt = av_output_video_device_next(fmt);
- if (fmt) {
- if (dev && !av_match_name(dev, fmt->name))
- continue;
- print_device_sinks(fmt, opts);
- }
- } while (fmt);
- fail:
- av_dict_free(&opts);
- av_free(dev);
- av_log_set_level(error_level);
- return ret;
-}
-
-#endif
diff --git a/app/src/main/cpp/ffmpeg/cmdutils.h b/app/src/main/cpp/ffmpeg/cmdutils.h
index aa64ca9e..352417f4 100644
--- a/app/src/main/cpp/ffmpeg/cmdutils.h
+++ b/app/src/main/cpp/ffmpeg/cmdutils.h
@@ -19,8 +19,8 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
-#ifndef CMDUTILS_H
-#define CMDUTILS_H
+#ifndef FFTOOLS_CMDUTILS_H
+#define FFTOOLS_CMDUTILS_H
#include
@@ -34,6 +34,10 @@
#undef main /* We don't want SDL to override our main() */
#endif
+#include
+
+extern jmp_buf jump_buf;
+
/**
* program name, defined by the program for show_version().
*/
@@ -44,11 +48,9 @@ extern const char program_name[];
*/
extern const int program_birth_year;
-extern AVCodecContext *avcodec_opts[AVMEDIA_TYPE_NB];
-extern AVFormatContext *avformat_opts;
extern AVDictionary *sws_dict;
extern AVDictionary *swr_opts;
-extern AVDictionary *format_opts, *codec_opts, *resample_opts;
+extern AVDictionary *format_opts, *codec_opts;
extern int hide_banner;
/**
@@ -56,16 +58,27 @@ extern int hide_banner;
*/
void register_exit(void (*cb)(int ret));
+/**
+ * Reports an error corresponding to the provided
+ * AVERROR code and calls exit_program() with the
+ * corresponding POSIX error code.
+ * @note ret must be an AVERROR-value of a POSIX error code
+ * (i.e. AVERROR(EFOO) and not AVERROR_FOO).
+ * library functions can return both, so call this only
+ * with AVERROR(EFOO) of your own.
+ */
+void report_and_exit(int ret) av_noreturn;
+
/**
* Wraps exit with a program-specific cleanup routine.
*/
-int exit_program(int ret);
+void exit_program(int ret) av_noreturn;
/**
- * Initialize the cmdutils option system, in particular
- * allocate the *_opts contexts.
+ * Initialize dynamic library loading
*/
-void init_opts(void);
+void init_dynload(void);
+
/**
* Uninitialize the cmdutils option system, in particular
* free the *_opts contexts and their contents.
@@ -78,34 +91,12 @@ void uninit_opts(void);
*/
void log_callback_help(void* ptr, int level, const char* fmt, va_list vl);
-/**
- * Override the cpuflags.
- */
-int opt_cpuflags(void *optctx, const char *opt, const char *arg);
-
/**
* Fallback for options that are not explicitly handled, these will be
* parsed through AVOptions.
*/
int opt_default(void *optctx, const char *opt, const char *arg);
-/**
- * Set the libav* libraries log level.
- */
-int opt_loglevel(void *optctx, const char *opt, const char *arg);
-
-int opt_report(const char *opt);
-
-int opt_max_alloc(void *optctx, const char *opt, const char *arg);
-
-int opt_codec_debug(void *optctx, const char *opt, const char *arg);
-
-#if CONFIG_OPENCL
-int opt_opencl(void *optctx, const char *opt, const char *arg);
-
-int opt_opencl_bench(void *optctx, const char *opt, const char *arg);
-#endif
-
/**
* Limit the execution time.
*/
@@ -150,6 +141,7 @@ typedef struct SpecifierOpt {
uint8_t *str;
int i;
int64_t i64;
+ uint64_t ui64;
float f;
double dbl;
} u;
@@ -213,11 +205,6 @@ void show_help_children(const AVClass *class, int flags);
*/
void show_help_default(const char *opt, const char *arg);
-/**
- * Generic -h handler common to all fftools.
- */
-int show_help(void *optctx, const char *opt, const char *arg);
-
/**
* Parse the command line arguments.
*
@@ -276,7 +263,6 @@ typedef struct OptionGroup {
AVDictionary *codec_opts;
AVDictionary *format_opts;
- AVDictionary *resample_opts;
AVDictionary *sws_dict;
AVDictionary *swr_opts;
} OptionGroup;
@@ -373,7 +359,7 @@ int check_stream_specifier(AVFormatContext *s, AVStream *st, const char *spec);
* @return a pointer to the created dictionary
*/
AVDictionary *filter_codec_opts(AVDictionary *opts, enum AVCodecID codec_id,
- AVFormatContext *s, AVStream *st, AVCodec *codec);
+ AVFormatContext *s, AVStream *st, const AVCodec *codec);
/**
* Setup AVCodecContext options for avformat_find_stream_info().
@@ -383,8 +369,8 @@ AVDictionary *filter_codec_opts(AVDictionary *opts, enum AVCodecID codec_id,
* Each dictionary will contain the options from codec_opts which can
* be applied to the corresponding stream codec context.
*
- * @return pointer to the created array of dictionaries, NULL if it
- * cannot be created
+ * @return pointer to the created array of dictionaries.
+ * Calls exit() on failure.
*/
AVDictionary **setup_find_stream_info_opts(AVFormatContext *s,
AVDictionary *codec_opts);
@@ -407,122 +393,6 @@ void print_error(const char *filename, int err);
*/
void show_banner(int argc, char **argv, const OptionDef *options);
-/**
- * Print the version of the program to stdout. The version message
- * depends on the current versions of the repository and of the libav*
- * libraries.
- * This option processing function does not utilize the arguments.
- */
-int show_version(void *optctx, const char *opt, const char *arg);
-
-/**
- * Print the build configuration of the program to stdout. The contents
- * depend on the definition of FFMPEG_CONFIGURATION.
- * This option processing function does not utilize the arguments.
- */
-int show_buildconf(void *optctx, const char *opt, const char *arg);
-
-/**
- * Print the license of the program to stdout. The license depends on
- * the license of the libraries compiled into the program.
- * This option processing function does not utilize the arguments.
- */
-int show_license(void *optctx, const char *opt, const char *arg);
-
-/**
- * Print a listing containing all the formats supported by the
- * program (including devices).
- * This option processing function does not utilize the arguments.
- */
-int show_formats(void *optctx, const char *opt, const char *arg);
-
-/**
- * Print a listing containing all the devices supported by the
- * program.
- * This option processing function does not utilize the arguments.
- */
-int show_devices(void *optctx, const char *opt, const char *arg);
-
-#if CONFIG_AVDEVICE
-/**
- * Print a listing containing audodetected sinks of the output device.
- * Device name with options may be passed as an argument to limit results.
- */
-int show_sinks(void *optctx, const char *opt, const char *arg);
-
-/**
- * Print a listing containing audodetected sources of the input device.
- * Device name with options may be passed as an argument to limit results.
- */
-int show_sources(void *optctx, const char *opt, const char *arg);
-#endif
-
-/**
- * Print a listing containing all the codecs supported by the
- * program.
- * This option processing function does not utilize the arguments.
- */
-int show_codecs(void *optctx, const char *opt, const char *arg);
-
-/**
- * Print a listing containing all the decoders supported by the
- * program.
- */
-int show_decoders(void *optctx, const char *opt, const char *arg);
-
-/**
- * Print a listing containing all the encoders supported by the
- * program.
- */
-int show_encoders(void *optctx, const char *opt, const char *arg);
-
-/**
- * Print a listing containing all the filters supported by the
- * program.
- * This option processing function does not utilize the arguments.
- */
-int show_filters(void *optctx, const char *opt, const char *arg);
-
-/**
- * Print a listing containing all the bit stream filters supported by the
- * program.
- * This option processing function does not utilize the arguments.
- */
-int show_bsfs(void *optctx, const char *opt, const char *arg);
-
-/**
- * Print a listing containing all the protocols supported by the
- * program.
- * This option processing function does not utilize the arguments.
- */
-int show_protocols(void *optctx, const char *opt, const char *arg);
-
-/**
- * Print a listing containing all the pixel formats supported by the
- * program.
- * This option processing function does not utilize the arguments.
- */
-int show_pix_fmts(void *optctx, const char *opt, const char *arg);
-
-/**
- * Print a listing containing all the standard channel layouts supported by
- * the program.
- * This option processing function does not utilize the arguments.
- */
-int show_layouts(void *optctx, const char *opt, const char *arg);
-
-/**
- * Print a listing containing all the sample formats supported by the
- * program.
- */
-int show_sample_fmts(void *optctx, const char *opt, const char *arg);
-
-/**
- * Print a listing containing all the color names and values recognized
- * by the program.
- */
-int show_colors(void *optctx, const char *opt, const char *arg);
-
/**
* Return a positive value if a line read from standard input
* starts with [yY], otherwise return 0.
@@ -562,14 +432,32 @@ FILE *get_preset_file(char *filename, size_t filename_size,
*/
void *grow_array(void *array, int elem_size, int *size, int new_size);
-#define media_type_string av_get_media_type_string
+/**
+ * Atomically add a new element to an array of pointers, i.e. allocate
+ * a new entry, reallocate the array of pointers and make the new last
+ * member of this array point to the newly allocated buffer.
+ * Calls exit() on failure.
+ *
+ * @param array array of pointers to reallocate
+ * @param elem_size size of the new element to allocate
+ * @param nb_elems pointer to the number of elements of the array array;
+ * *nb_elems will be incremented by one by this function.
+ * @return pointer to the newly allocated entry
+ */
+void *allocate_array_elem(void *array, size_t elem_size, int *nb_elems);
#define GROW_ARRAY(array, nb_elems)\
array = grow_array(array, sizeof(*array), &nb_elems, nb_elems + 1)
+#define ALLOC_ARRAY_ELEM(array, nb_elems)\
+ allocate_array_elem(&array, sizeof(*array[0]), &nb_elems)
+
#define GET_PIX_FMT_NAME(pix_fmt)\
const char *name = av_get_pix_fmt_name(pix_fmt);
+#define GET_CODEC_NAME(id)\
+ const char *name = avcodec_descriptor_get(id)->name;
+
#define GET_SAMPLE_FMT_NAME(sample_fmt)\
const char *name = av_get_sample_fmt_name(sample_fmt)
@@ -577,14 +465,6 @@ void *grow_array(void *array, int elem_size, int *size, int new_size);
char name[16];\
snprintf(name, sizeof(name), "%d", rate);
-#define GET_CH_LAYOUT_NAME(ch_layout)\
- char name[16];\
- snprintf(name, sizeof(name), "0x%"PRIx64, ch_layout);
-
-#define GET_CH_LAYOUT_DESC(ch_layout)\
- char name[128];\
- av_get_channel_layout_string(name, sizeof(name), 0, ch_layout);
-
-double get_rotation(AVStream *st);
+double get_rotation(int32_t *displaymatrix);
-#endif /* CMDUTILS_H */
+#endif /* FFTOOLS_CMDUTILS_H */
diff --git a/app/src/main/cpp/ffmpeg/cmdutils_common_opts.h b/app/src/main/cpp/ffmpeg/cmdutils_common_opts.h
deleted file mode 100644
index 758dac19..00000000
--- a/app/src/main/cpp/ffmpeg/cmdutils_common_opts.h
+++ /dev/null
@@ -1,35 +0,0 @@
- { "L" , OPT_EXIT, {.func_arg = show_license}, "show license" },
- { "h" , OPT_EXIT, {.func_arg = show_help}, "show help", "topic" },
- { "?" , OPT_EXIT, {.func_arg = show_help}, "show help", "topic" },
- { "help" , OPT_EXIT, {.func_arg = show_help}, "show help", "topic" },
- { "-help" , OPT_EXIT, {.func_arg = show_help}, "show help", "topic" },
- { "version" , OPT_EXIT, {.func_arg = show_version}, "show version" },
- { "buildconf" , OPT_EXIT, {.func_arg = show_buildconf}, "show build configuration" },
- { "formats" , OPT_EXIT, {.func_arg = show_formats }, "show available formats" },
- { "devices" , OPT_EXIT, {.func_arg = show_devices }, "show available devices" },
- { "codecs" , OPT_EXIT, {.func_arg = show_codecs }, "show available codecs" },
- { "decoders" , OPT_EXIT, {.func_arg = show_decoders }, "show available decoders" },
- { "encoders" , OPT_EXIT, {.func_arg = show_encoders }, "show available encoders" },
- { "bsfs" , OPT_EXIT, {.func_arg = show_bsfs }, "show available bit stream filters" },
- { "protocols" , OPT_EXIT, {.func_arg = show_protocols}, "show available protocols" },
- { "filters" , OPT_EXIT, {.func_arg = show_filters }, "show available filters" },
- { "pix_fmts" , OPT_EXIT, {.func_arg = show_pix_fmts }, "show available pixel formats" },
- { "layouts" , OPT_EXIT, {.func_arg = show_layouts }, "show standard channel layouts" },
- { "sample_fmts", OPT_EXIT, {.func_arg = show_sample_fmts }, "show available audio sample formats" },
- { "colors" , OPT_EXIT, {.func_arg = show_colors }, "show available color names" },
- { "loglevel" , HAS_ARG, {.func_arg = opt_loglevel}, "set logging level", "loglevel" },
- { "v", HAS_ARG, {.func_arg = opt_loglevel}, "set logging level", "loglevel" },
- { "report" , 0, {(void*)opt_report}, "generate a report" },
- { "max_alloc" , HAS_ARG, {.func_arg = opt_max_alloc}, "set maximum size of a single allocated block", "bytes" },
- { "cpuflags" , HAS_ARG | OPT_EXPERT, { .func_arg = opt_cpuflags }, "force specific cpu flags", "flags" },
- { "hide_banner", OPT_BOOL | OPT_EXPERT, {&hide_banner}, "do not show program banner", "hide_banner" },
-#if CONFIG_OPENCL
- { "opencl_bench", OPT_EXIT, {.func_arg = opt_opencl_bench}, "run benchmark on all OpenCL devices and show results" },
- { "opencl_options", HAS_ARG, {.func_arg = opt_opencl}, "set OpenCL environment options" },
-#endif
-#if CONFIG_AVDEVICE
- { "sources" , OPT_EXIT | HAS_ARG, { .func_arg = show_sources },
- "list sources of the input device", "device" },
- { "sinks" , OPT_EXIT | HAS_ARG, { .func_arg = show_sinks },
- "list sinks of the output device", "device" },
-#endif
diff --git a/app/src/main/cpp/ffmpeg/config.h b/app/src/main/cpp/ffmpeg/config.h
index 0aec1145..367ab66d 100644
--- a/app/src/main/cpp/ffmpeg/config.h
+++ b/app/src/main/cpp/ffmpeg/config.h
@@ -1,12 +1,13 @@
/* Automatically generated by configure - do not modify! */
#ifndef FFMPEG_CONFIG_H
#define FFMPEG_CONFIG_H
-#define FFMPEG_CONFIGURATION "--prefix=./android/armv7-a --enable-neon --enable-hwaccel=h264_vaapi --enable-hwaccel=h264_vaapi --enable-hwaccel=h264_dxva2 --enable-hwaccel=mpeg4_vaapi --enable-hwaccels --enable-static --enable-jni --enable-mediacodec --enable-asm --disable-shared --disable-doc --disable-ffmpeg --disable-ffplay --disable-ffprobe --disable-ffserver --disable-avdevice --disable-doc --disable-symver --cross-prefix='D:/adt-bundle-windows-x86_64-20131030/sdk/ndk-bundle/toolchains/arm-linux-androideabi-4.9/prebuilt/windows-x86_64/bin/arm-linux-androideabi-' --target-os=linux --arch=arm --enable-cross-compile --sysroot='D:/adt-bundle-windows-x86_64-20131030/sdk/ndk-bundle/platforms/android-14/arch-arm/' --extra-cflags='-Os -fpic ' --extra-ldflags= --enable-neon"
-#define FFMPEG_LICENSE "LGPL version 2.1 or later"
-#define CONFIG_THIS_YEAR 2017
-#define FFMPEG_DATADIR "./android/armv7-a/share/ffmpeg"
-#define AVCONV_DATADIR "./android/armv7-a/share/ffmpeg"
-#define CC_IDENT "gcc 4.9.x (GCC) 20150123 (prerelease)"
+#define FFMPEG_CONFIGURATION "--target-os=android --prefix=ffmpeg-android/arm64-v8a --cross-prefix=/Users/xufulong/Library/Android/sdk/ndk-bundle/toolchains/llvm/prebuilt/darwin-x86_64/bin/aarch64-linux-android- --enable-cross-compile --arch=aarch64 --cpu=armv8-a --cc=/Users/xufulong/Library/Android/sdk/ndk-bundle/toolchains/llvm/prebuilt/darwin-x86_64/bin/aarch64-linux-android21-clang --cxx=/Users/xufulong/Library/Android/sdk/ndk-bundle/toolchains/llvm/prebuilt/darwin-x86_64/bin/aarch64-linux-android21-clang++ --nm=/Users/xufulong/Library/Android/sdk/ndk-bundle/toolchains/llvm/prebuilt/darwin-x86_64/bin/aarch64-linux-android-nm --strip=/Users/xufulong/Library/Android/sdk/ndk-bundle/toolchains/llvm/prebuilt/darwin-x86_64/bin/aarch64-linux-android-strip --enable-cross-compile --sysroot=/Users/xufulong/Library/Android/sdk/ndk-bundle/toolchains/llvm/prebuilt/darwin-x86_64/sysroot --enable-hwaccels --enable-static --disable-shared --disable-doc --enable-neon --enable-asm --disable-small --enable-jni --disable-ffmpeg --disable-ffplay --disable-ffprobe --disable-debug --enable-gpl --disable-avdevice --disable-indevs --disable-outdevs --extra-cflags='-Os -fPIC -march=armv8-a -mfpu=neon -mfloat-abi=softfp -Iffmpeg-android/arm64-v8a/include' --extra-ldflags='-lc -lm -ldl -llog -lgcc -lz -Lffmpeg-android/arm64-v8a/lib' --enable-avcodec --enable-avformat --enable-avutil --enable-swresample --enable-swscale --enable-avfilter --enable-network --enable-bsfs --disable-postproc --enable-filters --enable-encoders --enable-libmp3lame --enable-libx264 --enable-encoder='libmp3lame,libx264' --disable-encoder='a64multi,a64multi5,alias_pix,amv,apng,aptx,aptx_hd,asv1,asv2,avrp,avui,cinepak,cljr,comfortnoise,dpx,ffvhuff,fits,hap,ilbc_at,mlp,nellymoser,pam,pbm,pcx,pgm,pgmyuv,ppm,prores,prores_aw,prores_ks,qtrle,r10k,r210,ra_144,roq,roq_dpcm,rv10,rv20,s302m,sbc,sgi,snow,sunrast,svq1,targa,tta,utvideo,v210,v308,v408,v410,vc2,wrapped_avframe,xbm,xface,xsub,xwd,y41p,zmbv' --disable-decoders --enable-decoder='mjpeg,mpeg4,h263,h264,flv,hevc,wmv3,msmpeg4v3,msmpeg4v2,msvideo1,vc1,mpeg1video,mpeg2video,aac,ac3,ac3_fixed,m4a,amrnb,amrwb,vorbis,wmav2,truehd,tscc,tscc2,dvvideo,msrle,cinepak,indeo5,vp8,vp9,av1,mp3float,mp3,mp3adufloat,mp3adu,mp3on4float,mp3on4,aac_fixed,aac_latm,eac3,png,wmav1,wmv1,wmv2,pcm_alaw,pcm_dvd,pcm_f16le,pcm_f24le,pcm_f32be,pcm_f32le,pcm_f64be,pcm_f64le,zlib,flac,opus,mlp,pcm_s16be,pcm_s16le,pcm_s24be,pcm_s24le,pcm_s32be,pcm_s32le,pcm_s64be,pcm_s64le,pcm_mulaw,alac,adpcm_ms,pcm_u16be,pcm_u16le,pcm_u24be,pcm_u24le,pcm_u32be,pcm_u32le,pcm_vidc,pcm_zork,adpcm_ima_qt,adpcm_ima_wav,gif' --enable-muxers --enable-parsers --enable-nonfree --enable-protocols --enable-openssl --enable-protocol=https --disable-demuxers --enable-demuxer='aac,ac3,alaw,amr,amrnb,amrwb,ape,asf,asf_o,avi,cavsvideo,codec2,concat,dnxhd,eac3,flac,flv,gif,gif_pipe,h263,h264,hevc,hls,image2,image2pipe,jpeg_pipe,lrc,m4v,matroska,webm,mjpeg,mov,mp4,m4a,3gp,mp3,mpeg,mpegts,mv,ogg,png_pipe,realtext,rm,rtp,rtsp,pcm_s16be,pcm_s16le,pcm_s32be,pcm_s32le,sdp,srt,swf,vc1,wav,webm_dash,manifest,xmv,pcm_f32be,pcm_f32le,pcm_f64be,pcm_f64le,mpegvideo,mulaw,sami,srt' --cpu=armv8-a"
+#define FFMPEG_LICENSE "nonfree and unredistributable"
+#define CONFIG_THIS_YEAR 2023
+#define FFMPEG_DATADIR "ffmpeg-android/arm64-v8a/share/ffmpeg"
+#define AVCONV_DATADIR "ffmpeg-android/arm64-v8a/share/ffmpeg"
+#define CC_IDENT "Android (5900059 based on r365631c) clang version 9.0.8 (https://android.googlesource.com/toolchain/llvm-project 207d7abc1a2abf3ef8d4301736d6a7ebc224a290) (based on LLVM 9.0.8svn)"
+#define OS_NAME android
#define av_restrict restrict
#define EXTERN_PREFIX ""
#define EXTERN_ASM
@@ -14,20 +15,29 @@
#define SLIBSUF ".so"
#define HAVE_MMX2 HAVE_MMXEXT
#define SWS_MAX_FILTER_SIZE 256
+#if defined(__LP64__)
+#define ARCH_AARCH64 1
+#define ARCH_ARM 0
+#else
#define ARCH_AARCH64 0
-#define ARCH_ALPHA 0
#define ARCH_ARM 1
+#endif
+#define ARCH_ALPHA 0
#define ARCH_AVR32 0
#define ARCH_AVR32_AP 0
#define ARCH_AVR32_UC 0
#define ARCH_BFIN 0
#define ARCH_IA64 0
+#define ARCH_LOONGARCH 0
+#define ARCH_LOONGARCH32 0
+#define ARCH_LOONGARCH64 0
#define ARCH_M68K 0
#define ARCH_MIPS 0
#define ARCH_MIPS64 0
#define ARCH_PARISC 0
#define ARCH_PPC 0
#define ARCH_PPC64 0
+#define ARCH_RISCV 0
#define ARCH_S390 0
#define ARCH_SH4 0
#define ARCH_SPARC 0
@@ -38,25 +48,28 @@
#define ARCH_X86 0
#define ARCH_X86_32 0
#define ARCH_X86_64 0
-#define HAVE_ARMV5TE 1
-#define HAVE_ARMV6 1
-#define HAVE_ARMV6T2 1
-#define HAVE_ARMV8 0
+#define HAVE_ARMV5TE 0
+#define HAVE_ARMV6 0
+#define HAVE_ARMV6T2 0
+#define HAVE_ARMV8 1
#define HAVE_NEON 1
#define HAVE_VFP 1
-#define HAVE_VFPV3 1
-#define HAVE_SETEND 1
+#define HAVE_VFPV3 0
+#define HAVE_SETEND 0
#define HAVE_ALTIVEC 0
#define HAVE_DCBZL 0
#define HAVE_LDBRX 0
#define HAVE_POWER8 0
#define HAVE_PPC4XX 0
#define HAVE_VSX 0
+#define HAVE_RVV 0
#define HAVE_AESNI 0
#define HAVE_AMD3DNOW 0
#define HAVE_AMD3DNOWEXT 0
#define HAVE_AVX 0
#define HAVE_AVX2 0
+#define HAVE_AVX512 0
+#define HAVE_AVX512ICL 0
#define HAVE_FMA3 0
#define HAVE_FMA4 0
#define HAVE_MMX 0
@@ -82,11 +95,13 @@
#define HAVE_LOONGSON2 0
#define HAVE_LOONGSON3 0
#define HAVE_MMI 0
-#define HAVE_ARMV5TE_EXTERNAL 1
+#define HAVE_LSX 0
+#define HAVE_LASX 0
+#define HAVE_ARMV5TE_EXTERNAL 0
#define HAVE_ARMV6_EXTERNAL 0
#define HAVE_ARMV6T2_EXTERNAL 0
-#define HAVE_ARMV8_EXTERNAL 0
-#define HAVE_NEON_EXTERNAL 0
+#define HAVE_ARMV8_EXTERNAL 1
+#define HAVE_NEON_EXTERNAL 1
#define HAVE_VFP_EXTERNAL 1
#define HAVE_VFPV3_EXTERNAL 0
#define HAVE_SETEND_EXTERNAL 0
@@ -96,11 +111,14 @@
#define HAVE_POWER8_EXTERNAL 0
#define HAVE_PPC4XX_EXTERNAL 0
#define HAVE_VSX_EXTERNAL 0
+#define HAVE_RVV_EXTERNAL 0
#define HAVE_AESNI_EXTERNAL 0
#define HAVE_AMD3DNOW_EXTERNAL 0
#define HAVE_AMD3DNOWEXT_EXTERNAL 0
#define HAVE_AVX_EXTERNAL 0
#define HAVE_AVX2_EXTERNAL 0
+#define HAVE_AVX512_EXTERNAL 0
+#define HAVE_AVX512ICL_EXTERNAL 0
#define HAVE_FMA3_EXTERNAL 0
#define HAVE_FMA4_EXTERNAL 0
#define HAVE_MMX_EXTERNAL 0
@@ -126,12 +144,14 @@
#define HAVE_LOONGSON2_EXTERNAL 0
#define HAVE_LOONGSON3_EXTERNAL 0
#define HAVE_MMI_EXTERNAL 0
-#define HAVE_ARMV5TE_INLINE 1
+#define HAVE_LSX_EXTERNAL 0
+#define HAVE_LASX_EXTERNAL 0
+#define HAVE_ARMV5TE_INLINE 0
#define HAVE_ARMV6_INLINE 0
#define HAVE_ARMV6T2_INLINE 0
-#define HAVE_ARMV8_INLINE 0
-#define HAVE_NEON_INLINE 0
-#define HAVE_VFP_INLINE 0
+#define HAVE_ARMV8_INLINE 1
+#define HAVE_NEON_INLINE 1
+#define HAVE_VFP_INLINE 1
#define HAVE_VFPV3_INLINE 0
#define HAVE_SETEND_INLINE 0
#define HAVE_ALTIVEC_INLINE 0
@@ -140,11 +160,14 @@
#define HAVE_POWER8_INLINE 0
#define HAVE_PPC4XX_INLINE 0
#define HAVE_VSX_INLINE 0
+#define HAVE_RVV_INLINE 0
#define HAVE_AESNI_INLINE 0
#define HAVE_AMD3DNOW_INLINE 0
#define HAVE_AMD3DNOWEXT_INLINE 0
#define HAVE_AVX_INLINE 0
#define HAVE_AVX2_INLINE 0
+#define HAVE_AVX512_INLINE 0
+#define HAVE_AVX512ICL_INLINE 0
#define HAVE_FMA3_INLINE 0
#define HAVE_FMA4_INLINE 0
#define HAVE_MMX_INLINE 0
@@ -170,39 +193,34 @@
#define HAVE_LOONGSON2_INLINE 0
#define HAVE_LOONGSON3_INLINE 0
#define HAVE_MMI_INLINE 0
-#define HAVE_ALIGNED_STACK 0
-#define HAVE_FAST_64BIT 0
+#define HAVE_LSX_INLINE 0
+#define HAVE_LASX_INLINE 0
+#define HAVE_ALIGNED_STACK 1
+#define HAVE_FAST_64BIT 1
#define HAVE_FAST_CLZ 1
#define HAVE_FAST_CMOV 0
-#define HAVE_LOCAL_ALIGNED_8 0
-#define HAVE_LOCAL_ALIGNED_16 0
-#define HAVE_LOCAL_ALIGNED_32 0
+#define HAVE_FAST_FLOAT16 1
+#define HAVE_LOCAL_ALIGNED 0
#define HAVE_SIMD_ALIGN_16 1
-#define HAVE_ATOMICS_GCC 1
-#define HAVE_ATOMICS_SUNCC 0
-#define HAVE_ATOMICS_WIN32 0
+#define HAVE_SIMD_ALIGN_32 0
+#define HAVE_SIMD_ALIGN_64 0
#define HAVE_ATOMIC_CAS_PTR 0
-#define HAVE_ATOMIC_COMPARE_EXCHANGE 1
#define HAVE_MACHINE_RW_BARRIER 0
#define HAVE_MEMORYBARRIER 0
#define HAVE_MM_EMPTY 0
#define HAVE_RDTSC 0
-#define HAVE_SARESTART 1
#define HAVE_SEM_TIMEDWAIT 1
#define HAVE_SYNC_VAL_COMPARE_AND_SWAP 1
-#define HAVE_CABS 0
-#define HAVE_CEXP 0
#define HAVE_INLINE_ASM 1
#define HAVE_SYMVER 0
-#define HAVE_YASM 0
+#define HAVE_X86ASM 0
#define HAVE_BIGENDIAN 0
-#define HAVE_FAST_UNALIGNED 0
-#define HAVE_ALSA_ASOUNDLIB_H 0
-#define HAVE_ALTIVEC_H 0
+#define HAVE_FAST_UNALIGNED 1
#define HAVE_ARPA_INET_H 1
#define HAVE_ASM_TYPES_H 1
#define HAVE_CDIO_PARANOIA_H 0
#define HAVE_CDIO_PARANOIA_PARANOIA_H 0
+#define HAVE_CUDA_H 0
#define HAVE_DISPATCH_DISPATCH_H 0
#define HAVE_DEV_BKTR_IOCTL_BT848_H 0
#define HAVE_DEV_BKTR_IOCTL_METEOR_H 0
@@ -211,25 +229,19 @@
#define HAVE_DEV_VIDEO_METEOR_IOCTL_METEOR_H 0
#define HAVE_DIRECT_H 0
#define HAVE_DIRENT_H 1
-#define HAVE_DLFCN_H 1
-#define HAVE_D3D11_H 0
+#define HAVE_DXGIDEBUG_H 0
#define HAVE_DXVA_H 0
#define HAVE_ES2_GL_H 0
#define HAVE_GSM_H 0
#define HAVE_IO_H 0
-#define HAVE_MACH_MACH_TIME_H 0
+#define HAVE_LINUX_DMA_BUF_H 0
+#define HAVE_LINUX_PERF_EVENT_H 1
#define HAVE_MACHINE_IOCTL_BT848_H 0
#define HAVE_MACHINE_IOCTL_METEOR_H 0
#define HAVE_MALLOC_H 1
#define HAVE_OPENCV2_CORE_CORE_C_H 0
-#define HAVE_OPENJPEG_2_1_OPENJPEG_H 0
-#define HAVE_OPENJPEG_2_0_OPENJPEG_H 0
-#define HAVE_OPENJPEG_1_5_OPENJPEG_H 0
#define HAVE_OPENGL_GL3_H 0
#define HAVE_POLL_H 1
-#define HAVE_SNDIO_H 0
-#define HAVE_SOUNDCARD_H 0
-#define HAVE_SYS_MMAN_H 1
#define HAVE_SYS_PARAM_H 1
#define HAVE_SYS_RESOURCE_H 1
#define HAVE_SYS_SELECT_H 1
@@ -243,7 +255,7 @@
#define HAVE_VALGRIND_VALGRIND_H 0
#define HAVE_WINDOWS_H 0
#define HAVE_WINSOCK2_H 0
-#define HAVE_INTRINSICS_NEON 0
+#define HAVE_INTRINSICS_NEON 1
#define HAVE_ATANF 1
#define HAVE_ATAN2F 1
#define HAVE_CBRT 1
@@ -261,8 +273,8 @@
#define HAVE_LDEXPF 1
#define HAVE_LLRINT 1
#define HAVE_LLRINTF 1
-#define HAVE_LOG2 0
-#define HAVE_LOG2F 0
+#define HAVE_LOG2 1
+#define HAVE_LOG2F 1
#define HAVE_LOG10F 1
#define HAVE_LRINT 1
#define HAVE_LRINTF 1
@@ -273,25 +285,31 @@
#define HAVE_SINF 1
#define HAVE_TRUNC 1
#define HAVE_TRUNCF 1
+#define HAVE_DOS_PATHS 0
+#define HAVE_LIBC_MSVCRT 0
+#define HAVE_MMAL_PARAMETER_VIDEO_MAX_NUM_CALLBACKS 0
+#define HAVE_SECTION_DATA_REL_RO 1
+#define HAVE_THREADS 1
+#define HAVE_UWP 0
+#define HAVE_WINRT 0
#define HAVE_ACCESS 1
#define HAVE_ALIGNED_MALLOC 0
#define HAVE_ARC4RANDOM 1
#define HAVE_CLOCK_GETTIME 1
#define HAVE_CLOSESOCKET 0
#define HAVE_COMMANDLINETOARGVW 0
-#define HAVE_COTASKMEMFREE 0
-#define HAVE_CRYPTGENRANDOM 0
-#define HAVE_DLOPEN 1
#define HAVE_FCNTL 1
-#define HAVE_FLT_LIM 1
-#define HAVE_FORK 1
#define HAVE_GETADDRINFO 1
+#define HAVE_GETAUXVAL 1
+#define HAVE_GETENV 1
#define HAVE_GETHRTIME 0
#define HAVE_GETOPT 1
+#define HAVE_GETMODULEHANDLE 0
#define HAVE_GETPROCESSAFFINITYMASK 0
#define HAVE_GETPROCESSMEMORYINFO 0
#define HAVE_GETPROCESSTIMES 0
#define HAVE_GETRUSAGE 1
+#define HAVE_GETSTDHANDLE 0
#define HAVE_GETSYSTEMTIMEASFILETIME 0
#define HAVE_GETTIMEOFDAY 1
#define HAVE_GLOB 0
@@ -299,9 +317,7 @@
#define HAVE_GMTIME_R 1
#define HAVE_INET_ATON 1
#define HAVE_ISATTY 1
-#define HAVE_JACK_PORT_GET_LATENCY_RANGE 0
#define HAVE_KBHIT 0
-#define HAVE_LOADLIBRARY 0
#define HAVE_LOCALTIME_R 1
#define HAVE_LSTAT 1
#define HAVE_LZO1X_999_COMPRESS 0
@@ -313,11 +329,14 @@
#define HAVE_MPROTECT 1
#define HAVE_NANOSLEEP 1
#define HAVE_PEEKNAMEDPIPE 0
-#define HAVE_POSIX_MEMALIGN 0
+#define HAVE_POSIX_MEMALIGN 1
+#define HAVE_PRCTL 1
#define HAVE_PTHREAD_CANCEL 0
#define HAVE_SCHED_GETAFFINITY 1
+#define HAVE_SECITEMIMPORT 0
#define HAVE_SETCONSOLETEXTATTRIBUTE 0
#define HAVE_SETCONSOLECTRLHANDLER 0
+#define HAVE_SETDLLDIRECTORY 0
#define HAVE_SETMODE 0
#define HAVE_SETRLIMIT 1
#define HAVE_SLEEP 0
@@ -328,18 +347,23 @@
#define HAVE_UTGETOSTYPEFROMSTRING 0
#define HAVE_VIRTUALALLOC 0
#define HAVE_WGLGETPROCADDRESS 0
+#define HAVE_BCRYPT 0
+#define HAVE_VAAPI_DRM 0
+#define HAVE_VAAPI_X11 0
+#define HAVE_VDPAU_X11 0
#define HAVE_PTHREADS 1
#define HAVE_OS2THREADS 0
#define HAVE_W32THREADS 0
-#define HAVE_AS_DN_DIRECTIVE 1
-#define HAVE_AS_FUNC 1
-#define HAVE_AS_OBJECT_ARCH 1
-#define HAVE_ASM_MOD_Q 1
-#define HAVE_ATTRIBUTE_MAY_ALIAS 1
-#define HAVE_ATTRIBUTE_PACKED 1
+#define HAVE_AS_ARCH_DIRECTIVE 0
+#define HAVE_AS_DN_DIRECTIVE 0
+#define HAVE_AS_FPU_DIRECTIVE 0
+#define HAVE_AS_FUNC 0
+#define HAVE_AS_OBJECT_ARCH 0
+#define HAVE_ASM_MOD_Q 0
+#define HAVE_BLOCKS_EXTENSION 0
#define HAVE_EBP_AVAILABLE 0
#define HAVE_EBX_AVAILABLE 0
-#define HAVE_GNU_AS 1
+#define HAVE_GNU_AS 0
#define HAVE_GNU_WINDRES 0
#define HAVE_IBM_ASM 0
#define HAVE_INLINE_ASM_DIRECT_SYMBOL_REFS 0
@@ -347,12 +371,30 @@
#define HAVE_INLINE_ASM_NONLOCAL_LABELS 1
#define HAVE_PRAGMA_DEPRECATED 1
#define HAVE_RSYNC_CONTIMEOUT 0
-#define HAVE_SYMVER_ASM_LABEL 0
+#define HAVE_SYMVER_ASM_LABEL 1
#define HAVE_SYMVER_GNU_ASM 1
#define HAVE_VFP_ARGS 0
#define HAVE_XFORM_ASM 0
#define HAVE_XMM_CLOBBERS 0
-#define HAVE_CONDITION_VARIABLE_PTR 0
+#define HAVE_DPI_AWARENESS_CONTEXT 0
+#define HAVE_IDXGIOUTPUT5 0
+#define HAVE_KCMVIDEOCODECTYPE_HEVC 0
+#define HAVE_KCMVIDEOCODECTYPE_HEVCWITHALPHA 0
+#define HAVE_KCMVIDEOCODECTYPE_VP9 0
+#define HAVE_KCVPIXELFORMATTYPE_420YPCBCR10BIPLANARVIDEORANGE 0
+#define HAVE_KCVPIXELFORMATTYPE_422YPCBCR8BIPLANARVIDEORANGE 0
+#define HAVE_KCVPIXELFORMATTYPE_422YPCBCR10BIPLANARVIDEORANGE 0
+#define HAVE_KCVPIXELFORMATTYPE_422YPCBCR16BIPLANARVIDEORANGE 0
+#define HAVE_KCVPIXELFORMATTYPE_444YPCBCR8BIPLANARVIDEORANGE 0
+#define HAVE_KCVPIXELFORMATTYPE_444YPCBCR10BIPLANARVIDEORANGE 0
+#define HAVE_KCVPIXELFORMATTYPE_444YPCBCR16BIPLANARVIDEORANGE 0
+#define HAVE_KCVIMAGEBUFFERTRANSFERFUNCTION_SMPTE_ST_2084_PQ 0
+#define HAVE_KCVIMAGEBUFFERTRANSFERFUNCTION_ITU_R_2100_HLG 0
+#define HAVE_KCVIMAGEBUFFERTRANSFERFUNCTION_LINEAR 0
+#define HAVE_KCVIMAGEBUFFERYCBCRMATRIX_ITU_R_2020 0
+#define HAVE_KCVIMAGEBUFFERCOLORPRIMARIES_ITU_R_2020 0
+#define HAVE_KCVIMAGEBUFFERTRANSFERFUNCTION_ITU_R_2020 0
+#define HAVE_KCVIMAGEBUFFERTRANSFERFUNCTION_SMPTE_ST_428_1 0
#define HAVE_SOCKLEN_T 1
#define HAVE_STRUCT_ADDRINFO 1
#define HAVE_STRUCT_GROUP_SOURCE_REQ 1
@@ -365,163 +407,193 @@
#define HAVE_STRUCT_SOCKADDR_IN6 1
#define HAVE_STRUCT_SOCKADDR_SA_LEN 0
#define HAVE_STRUCT_SOCKADDR_STORAGE 1
-#define HAVE_STRUCT_STAT_ST_MTIM_TV_NSEC 0
-#define HAVE_STRUCT_V4L2_FRMIVALENUM_DISCRETE 0
-#define HAVE_ATOMICS_NATIVE 1
-#define HAVE_DOS_PATHS 0
-#define HAVE_DXVA2_LIB 0
-#define HAVE_DXVA2API_COBJ 0
-#define HAVE_LIBC_MSVCRT 0
-#define HAVE_LIBDC1394_1 0
-#define HAVE_LIBDC1394_2 0
+#define HAVE_STRUCT_STAT_ST_MTIM_TV_NSEC 1
+#define HAVE_STRUCT_V4L2_FRMIVALENUM_DISCRETE 1
+#define HAVE_GZIP 1
+#define HAVE_LIBDRM_GETFB2 0
#define HAVE_MAKEINFO 1
#define HAVE_MAKEINFO_HTML 0
-#define HAVE_MMAL_PARAMETER_VIDEO_MAX_NUM_CALLBACKS 0
-#define HAVE_PERL 0
-#define HAVE_POD2MAN 0
-#define HAVE_SDL2 0
-#define HAVE_SECTION_DATA_REL_RO 1
+#define HAVE_OPENCL_D3D11 0
+#define HAVE_OPENCL_DRM_ARM 0
+#define HAVE_OPENCL_DRM_BEIGNET 0
+#define HAVE_OPENCL_DXVA2 0
+#define HAVE_OPENCL_VAAPI_BEIGNET 0
+#define HAVE_OPENCL_VAAPI_INTEL_MEDIA 0
+#define HAVE_PERL 1
+#define HAVE_POD2MAN 1
#define HAVE_TEXI2HTML 0
-#define HAVE_THREADS 1
-#define HAVE_VAAPI_DRM 0
-#define HAVE_VAAPI_X11 0
-#define HAVE_VDPAU_X11 0
-#define HAVE_WINRT 0
-#define HAVE_XLIB 0
-#define CONFIG_BSFS 1
-#define CONFIG_DECODERS 1
-#define CONFIG_ENCODERS 1
-#define CONFIG_HWACCELS 1
-#define CONFIG_PARSERS 1
-#define CONFIG_INDEVS 0
-#define CONFIG_OUTDEVS 0
-#define CONFIG_FILTERS 1
-#define CONFIG_DEMUXERS 1
-#define CONFIG_MUXERS 1
-#define CONFIG_PROTOCOLS 1
+#define HAVE_XMLLINT 1
+#define HAVE_ZLIB_GZIP 1
#define CONFIG_DOC 0
#define CONFIG_HTMLPAGES 0
-#define CONFIG_MANPAGES 0
-#define CONFIG_PODPAGES 0
-#define CONFIG_TXTPAGES 0
-#define CONFIG_AVIO_DIR_CMD_EXAMPLE 1
-#define CONFIG_AVIO_READING_EXAMPLE 1
-#define CONFIG_DECODING_ENCODING_EXAMPLE 1
-#define CONFIG_DEMUXING_DECODING_EXAMPLE 1
+#define CONFIG_MANPAGES 1
+#define CONFIG_PODPAGES 1
+#define CONFIG_TXTPAGES 1
+#define CONFIG_AVIO_HTTP_SERVE_FILES_EXAMPLE 1
+#define CONFIG_AVIO_LIST_DIR_EXAMPLE 1
+#define CONFIG_AVIO_READ_CALLBACK_EXAMPLE 1
+#define CONFIG_DECODE_AUDIO_EXAMPLE 1
+#define CONFIG_DECODE_FILTER_AUDIO_EXAMPLE 1
+#define CONFIG_DECODE_FILTER_VIDEO_EXAMPLE 1
+#define CONFIG_DECODE_VIDEO_EXAMPLE 1
+#define CONFIG_DEMUX_DECODE_EXAMPLE 1
+#define CONFIG_ENCODE_AUDIO_EXAMPLE 1
+#define CONFIG_ENCODE_VIDEO_EXAMPLE 1
#define CONFIG_EXTRACT_MVS_EXAMPLE 1
#define CONFIG_FILTER_AUDIO_EXAMPLE 1
-#define CONFIG_FILTERING_AUDIO_EXAMPLE 1
-#define CONFIG_FILTERING_VIDEO_EXAMPLE 1
-#define CONFIG_HTTP_MULTICLIENT_EXAMPLE 1
-#define CONFIG_METADATA_EXAMPLE 1
-#define CONFIG_MUXING_EXAMPLE 1
-#define CONFIG_QSVDEC_EXAMPLE 0
-#define CONFIG_REMUXING_EXAMPLE 1
-#define CONFIG_RESAMPLING_AUDIO_EXAMPLE 1
-#define CONFIG_SCALING_VIDEO_EXAMPLE 1
+#define CONFIG_HW_DECODE_EXAMPLE 1
+#define CONFIG_MUX_EXAMPLE 1
+#define CONFIG_QSV_DECODE_EXAMPLE 0
+#define CONFIG_REMUX_EXAMPLE 1
+#define CONFIG_RESAMPLE_AUDIO_EXAMPLE 1
+#define CONFIG_SCALE_VIDEO_EXAMPLE 1
+#define CONFIG_SHOW_METADATA_EXAMPLE 1
#define CONFIG_TRANSCODE_AAC_EXAMPLE 1
-#define CONFIG_TRANSCODING_EXAMPLE 1
+#define CONFIG_TRANSCODE_EXAMPLE 1
+#define CONFIG_VAAPI_ENCODE_EXAMPLE 0
+#define CONFIG_VAAPI_TRANSCODE_EXAMPLE 0
+#define CONFIG_QSV_TRANSCODE_EXAMPLE 0
#define CONFIG_AVISYNTH 0
-#define CONFIG_BZLIB 0
-#define CONFIG_CHROMAPRINT 0
-#define CONFIG_CRYSTALHD 0
-#define CONFIG_DECKLINK 0
#define CONFIG_FREI0R 0
-#define CONFIG_GCRYPT 0
+#define CONFIG_LIBCDIO 0
+#define CONFIG_LIBDAVS2 0
+#define CONFIG_LIBRUBBERBAND 0
+#define CONFIG_LIBVIDSTAB 0
+#define CONFIG_LIBX264 1
+#define CONFIG_LIBX265 0
+#define CONFIG_LIBXAVS 0
+#define CONFIG_LIBXAVS2 0
+#define CONFIG_LIBXVID 0
+#define CONFIG_DECKLINK 0
+#define CONFIG_LIBFDK_AAC 0
+#define CONFIG_LIBTLS 0
#define CONFIG_GMP 0
+#define CONFIG_LIBARIBB24 0
+#define CONFIG_LIBLENSFUN 0
+#define CONFIG_LIBOPENCORE_AMRNB 0
+#define CONFIG_LIBOPENCORE_AMRWB 0
+#define CONFIG_LIBVO_AMRWBENC 0
+#define CONFIG_MBEDTLS 0
+#define CONFIG_RKMPP 0
+#define CONFIG_LIBSMBCLIENT 0
+#define CONFIG_CHROMAPRINT 0
+#define CONFIG_GCRYPT 0
#define CONFIG_GNUTLS 0
-#define CONFIG_ICONV 0
#define CONFIG_JNI 1
#define CONFIG_LADSPA 0
+#define CONFIG_LCMS2 0
+#define CONFIG_LIBAOM 0
#define CONFIG_LIBASS 0
#define CONFIG_LIBBLURAY 0
#define CONFIG_LIBBS2B 0
#define CONFIG_LIBCACA 0
-#define CONFIG_LIBCDIO 0
#define CONFIG_LIBCELT 0
+#define CONFIG_LIBCODEC2 0
+#define CONFIG_LIBDAV1D 0
#define CONFIG_LIBDC1394 0
-#define CONFIG_LIBEBUR128 0
-#define CONFIG_LIBFDK_AAC 0
+#define CONFIG_LIBDRM 0
#define CONFIG_LIBFLITE 0
#define CONFIG_LIBFONTCONFIG 0
#define CONFIG_LIBFREETYPE 0
#define CONFIG_LIBFRIBIDI 0
+#define CONFIG_LIBGLSLANG 0
#define CONFIG_LIBGME 0
#define CONFIG_LIBGSM 0
#define CONFIG_LIBIEC61883 0
#define CONFIG_LIBILBC 0
+#define CONFIG_LIBJACK 0
+#define CONFIG_LIBJXL 0
+#define CONFIG_LIBKLVANC 0
#define CONFIG_LIBKVAZAAR 0
#define CONFIG_LIBMODPLUG 0
-#define CONFIG_LIBMP3LAME 0
-#define CONFIG_LIBNUT 0
-#define CONFIG_LIBOPENCORE_AMRNB 0
-#define CONFIG_LIBOPENCORE_AMRWB 0
+#define CONFIG_LIBMP3LAME 1
+#define CONFIG_LIBMYSOFA 0
#define CONFIG_LIBOPENCV 0
#define CONFIG_LIBOPENH264 0
#define CONFIG_LIBOPENJPEG 0
#define CONFIG_LIBOPENMPT 0
+#define CONFIG_LIBOPENVINO 0
#define CONFIG_LIBOPUS 0
+#define CONFIG_LIBPLACEBO 0
#define CONFIG_LIBPULSE 0
+#define CONFIG_LIBRABBITMQ 0
+#define CONFIG_LIBRAV1E 0
+#define CONFIG_LIBRIST 0
+#define CONFIG_LIBRSVG 0
#define CONFIG_LIBRTMP 0
-#define CONFIG_LIBRUBBERBAND 0
-#define CONFIG_LIBSCHROEDINGER 0
+#define CONFIG_LIBSHADERC 0
#define CONFIG_LIBSHINE 0
#define CONFIG_LIBSMBCLIENT 0
#define CONFIG_LIBSNAPPY 0
#define CONFIG_LIBSOXR 0
#define CONFIG_LIBSPEEX 0
+#define CONFIG_LIBSRT 0
#define CONFIG_LIBSSH 0
+#define CONFIG_LIBSVTAV1 0
+#define CONFIG_LIBTENSORFLOW 0
#define CONFIG_LIBTESSERACT 0
#define CONFIG_LIBTHEORA 0
#define CONFIG_LIBTWOLAME 0
+#define CONFIG_LIBUAVS3D 0
#define CONFIG_LIBV4L2 0
-#define CONFIG_LIBVIDSTAB 0
-#define CONFIG_LIBVO_AMRWBENC 0
+#define CONFIG_LIBVMAF 0
#define CONFIG_LIBVORBIS 0
#define CONFIG_LIBVPX 0
-#define CONFIG_LIBWAVPACK 0
#define CONFIG_LIBWEBP 0
-#define CONFIG_LIBX264 0
-#define CONFIG_LIBX265 0
-#define CONFIG_LIBXAVS 0
-#define CONFIG_LIBXCB 0
-#define CONFIG_LIBXCB_SHM 0
-#define CONFIG_LIBXCB_SHAPE 0
-#define CONFIG_LIBXCB_XFIXES 0
-#define CONFIG_LIBXVID 0
+#define CONFIG_LIBXML2 0
#define CONFIG_LIBZIMG 0
#define CONFIG_LIBZMQ 0
#define CONFIG_LIBZVBI 0
-#define CONFIG_LZMA 0
-#define CONFIG_MEDIACODEC 1
-#define CONFIG_NETCDF 0
+#define CONFIG_LV2 0
+#define CONFIG_MEDIACODEC 0
#define CONFIG_OPENAL 0
-#define CONFIG_OPENCL 0
#define CONFIG_OPENGL 0
-#define CONFIG_OPENSSL 0
+#define CONFIG_OPENSSL 1
+#define CONFIG_POCKETSPHINX 0
+#define CONFIG_VAPOURSYNTH 0
+#define CONFIG_ALSA 0
+#define CONFIG_APPKIT 0
+#define CONFIG_AVFOUNDATION 0
+#define CONFIG_BZLIB 0
+#define CONFIG_COREIMAGE 0
+#define CONFIG_ICONV 0
+#define CONFIG_LIBXCB 0
+#define CONFIG_LIBXCB_SHM 0
+#define CONFIG_LIBXCB_SHAPE 0
+#define CONFIG_LIBXCB_XFIXES 0
+#define CONFIG_LZMA 0
+#define CONFIG_MEDIAFOUNDATION 0
+#define CONFIG_METAL 0
#define CONFIG_SCHANNEL 0
-#define CONFIG_SDL 0
#define CONFIG_SDL2 0
#define CONFIG_SECURETRANSPORT 0
-#define CONFIG_VIDEOTOOLBOX 0
-#define CONFIG_X11GRAB 0
+#define CONFIG_SNDIO 0
#define CONFIG_XLIB 0
#define CONFIG_ZLIB 1
+#define CONFIG_CUDA_NVCC 0
+#define CONFIG_CUDA_SDK 0
+#define CONFIG_LIBNPP 0
+#define CONFIG_LIBMFX 0
+#define CONFIG_LIBVPL 0
+#define CONFIG_MMAL 0
+#define CONFIG_OMX 0
+#define CONFIG_OPENCL 0
+#define CONFIG_AMF 0
#define CONFIG_AUDIOTOOLBOX 0
+#define CONFIG_CRYSTALHD 0
#define CONFIG_CUDA 0
+#define CONFIG_CUDA_LLVM 0
#define CONFIG_CUVID 0
#define CONFIG_D3D11VA 0
#define CONFIG_DXVA2 0
-#define CONFIG_LIBMFX 0
-#define CONFIG_LIBNPP 0
-#define CONFIG_MMAL 0
+#define CONFIG_FFNVCODEC 0
+#define CONFIG_NVDEC 0
#define CONFIG_NVENC 0
-#define CONFIG_OMX 0
#define CONFIG_VAAPI 0
-#define CONFIG_VDA 0
#define CONFIG_VDPAU 0
-#define CONFIG_VIDEOTOOLBOX_HWACCEL 0
-#define CONFIG_XVMC 0
+#define CONFIG_VIDEOTOOLBOX 0
+#define CONFIG_VULKAN 0
+#define CONFIG_V4L2_M2M 1
#define CONFIG_FTRAPV 0
#define CONFIG_GRAY 0
#define CONFIG_HARDCODED_TABLES 0
@@ -532,58 +604,80 @@
#define CONFIG_SMALL 0
#define CONFIG_STATIC 1
#define CONFIG_SWSCALE_ALPHA 1
-#define CONFIG_GPL 0
-#define CONFIG_NONFREE 0
+#define CONFIG_GPL 1
+#define CONFIG_NONFREE 1
#define CONFIG_VERSION3 0
-#define CONFIG_AVCODEC 1
#define CONFIG_AVDEVICE 0
#define CONFIG_AVFILTER 1
-#define CONFIG_AVFORMAT 1
-#define CONFIG_AVRESAMPLE 0
-#define CONFIG_AVUTIL 1
+#define CONFIG_SWSCALE 1
#define CONFIG_POSTPROC 0
+#define CONFIG_AVFORMAT 1
+#define CONFIG_AVCODEC 1
#define CONFIG_SWRESAMPLE 1
-#define CONFIG_SWSCALE 1
+#define CONFIG_AVUTIL 1
#define CONFIG_FFPLAY 0
#define CONFIG_FFPROBE 0
-#define CONFIG_FFSERVER 0
#define CONFIG_FFMPEG 0
#define CONFIG_DCT 1
-#define CONFIG_DWT 1
+#define CONFIG_DWT 0
#define CONFIG_ERROR_RESILIENCE 1
#define CONFIG_FAAN 1
-#define CONFIG_FAST_UNALIGNED 0
+#define CONFIG_FAST_UNALIGNED 1
#define CONFIG_FFT 1
#define CONFIG_LSP 1
-#define CONFIG_LZO 1
-#define CONFIG_MDCT 1
+#define CONFIG_MDCT 0
#define CONFIG_PIXELUTILS 1
#define CONFIG_NETWORK 1
#define CONFIG_RDFT 1
+#define CONFIG_AUTODETECT 0
#define CONFIG_FONTCONFIG 0
-#define CONFIG_MEMALIGN_HACK 0
+#define CONFIG_LARGE_TESTS 1
+#define CONFIG_LINUX_PERF 0
+#define CONFIG_MACOS_KPERF 0
#define CONFIG_MEMORY_POISONING 0
#define CONFIG_NEON_CLOBBER_TEST 0
+#define CONFIG_OSSFUZZ 0
#define CONFIG_PIC 1
-#define CONFIG_POD2MAN 0
-#define CONFIG_RAISE_MAJOR 0
+#define CONFIG_PTX_COMPRESSION 1
#define CONFIG_THUMB 0
#define CONFIG_VALGRIND_BACKTRACE 0
#define CONFIG_XMM_CLOBBER_TEST 0
+#define CONFIG_BSFS 1
+#define CONFIG_DECODERS 1
+#define CONFIG_ENCODERS 1
+#define CONFIG_HWACCELS 0
+#define CONFIG_PARSERS 1
+#define CONFIG_INDEVS 0
+#define CONFIG_OUTDEVS 0
+#define CONFIG_FILTERS 1
+#define CONFIG_DEMUXERS 1
+#define CONFIG_MUXERS 1
+#define CONFIG_PROTOCOLS 1
#define CONFIG_AANDCTTABLES 1
#define CONFIG_AC3DSP 1
+#define CONFIG_ADTS_HEADER 1
+#define CONFIG_ATSC_A53 1
#define CONFIG_AUDIO_FRAME_QUEUE 1
#define CONFIG_AUDIODSP 1
#define CONFIG_BLOCKDSP 1
#define CONFIG_BSWAPDSP 1
#define CONFIG_CABAC 1
+#define CONFIG_CBS 1
+#define CONFIG_CBS_AV1 1
+#define CONFIG_CBS_H264 1
+#define CONFIG_CBS_H265 1
+#define CONFIG_CBS_JPEG 0
+#define CONFIG_CBS_MPEG2 1
+#define CONFIG_CBS_VP9 1
+#define CONFIG_DEFLATE_WRAPPER 1
#define CONFIG_DIRAC_PARSE 1
+#define CONFIG_DNN 1
+#define CONFIG_DOVI_RPU 1
#define CONFIG_DVPROFILE 1
#define CONFIG_EXIF 1
#define CONFIG_FAANDCT 1
#define CONFIG_FAANIDCT 1
#define CONFIG_FDCTDSP 1
-#define CONFIG_FLACDSP 1
#define CONFIG_FMTCONVERT 1
#define CONFIG_FRAME_THREAD_ENCODER 1
#define CONFIG_G722DSP 1
@@ -592,1639 +686,69 @@
#define CONFIG_H263DSP 1
#define CONFIG_H264CHROMA 1
#define CONFIG_H264DSP 1
+#define CONFIG_H264PARSE 1
#define CONFIG_H264PRED 1
#define CONFIG_H264QPEL 1
+#define CONFIG_H264_SEI 1
+#define CONFIG_HEVCPARSE 1
+#define CONFIG_HEVC_SEI 1
#define CONFIG_HPELDSP 1
#define CONFIG_HUFFMAN 1
-#define CONFIG_HUFFYUVDSP 1
+#define CONFIG_HUFFYUVDSP 0
#define CONFIG_HUFFYUVENCDSP 1
#define CONFIG_IDCTDSP 1
#define CONFIG_IIRFILTER 1
-#define CONFIG_IMDCT15 1
+#define CONFIG_INFLATE_WRAPPER 1
#define CONFIG_INTRAX8 1
#define CONFIG_ISO_MEDIA 1
#define CONFIG_IVIDSP 1
#define CONFIG_JPEGTABLES 1
#define CONFIG_LGPLV3 0
#define CONFIG_LIBX262 0
-#define CONFIG_LLAUDDSP 1
-#define CONFIG_LLVIDDSP 1
+#define CONFIG_LLAUDDSP 0
+#define CONFIG_LLVIDDSP 0
+#define CONFIG_LLVIDENCDSP 1
#define CONFIG_LPC 1
-#define CONFIG_LZF 1
+#define CONFIG_LZF 0
#define CONFIG_ME_CMP 1
#define CONFIG_MPEG_ER 1
#define CONFIG_MPEGAUDIO 1
#define CONFIG_MPEGAUDIODSP 1
+#define CONFIG_MPEGAUDIOHEADER 1
+#define CONFIG_MPEG4AUDIO 1
#define CONFIG_MPEGVIDEO 1
+#define CONFIG_MPEGVIDEODEC 1
#define CONFIG_MPEGVIDEOENC 1
-#define CONFIG_MSS34DSP 1
+#define CONFIG_MSMPEG4DEC 1
+#define CONFIG_MSMPEG4ENC 1
+#define CONFIG_MSS34DSP 0
#define CONFIG_PIXBLOCKDSP 1
#define CONFIG_QPELDSP 1
#define CONFIG_QSV 0
#define CONFIG_QSVDEC 0
#define CONFIG_QSVENC 0
+#define CONFIG_QSVVPP 0
#define CONFIG_RANGECODER 1
#define CONFIG_RIFFDEC 1
#define CONFIG_RIFFENC 1
#define CONFIG_RTPDEC 1
#define CONFIG_RTPENC_CHAIN 1
-#define CONFIG_RV34DSP 1
+#define CONFIG_RV34DSP 0
+#define CONFIG_SCENE_SAD 1
#define CONFIG_SINEWIN 1
-#define CONFIG_SNAPPY 1
+#define CONFIG_SNAPPY 0
#define CONFIG_SRTP 1
#define CONFIG_STARTCODE 1
-#define CONFIG_TEXTUREDSP 1
-#define CONFIG_TEXTUREDSPENC 0
-#define CONFIG_TPELDSP 1
+#define CONFIG_TEXTUREDSP 0
+#define CONFIG_TEXTUREDSPENC 1
+#define CONFIG_TPELDSP 0
+#define CONFIG_VAAPI_1 0
#define CONFIG_VAAPI_ENCODE 0
#define CONFIG_VC1DSP 1
#define CONFIG_VIDEODSP 1
-#define CONFIG_VP3DSP 1
-#define CONFIG_VP56DSP 1
+#define CONFIG_VP3DSP 0
+#define CONFIG_VP56DSP 0
#define CONFIG_VP8DSP 1
-#define CONFIG_VT_BT2020 0
#define CONFIG_WMA_FREQS 1
#define CONFIG_WMV2DSP 1
-#define CONFIG_AAC_ADTSTOASC_BSF 1
-#define CONFIG_CHOMP_BSF 1
-#define CONFIG_DUMP_EXTRADATA_BSF 1
-#define CONFIG_DCA_CORE_BSF 1
-#define CONFIG_H264_MP4TOANNEXB_BSF 1
-#define CONFIG_HEVC_MP4TOANNEXB_BSF 1
-#define CONFIG_IMX_DUMP_HEADER_BSF 1
-#define CONFIG_MJPEG2JPEG_BSF 1
-#define CONFIG_MJPEGA_DUMP_HEADER_BSF 1
-#define CONFIG_MP3_HEADER_DECOMPRESS_BSF 1
-#define CONFIG_MPEG4_UNPACK_BFRAMES_BSF 1
-#define CONFIG_MOV2TEXTSUB_BSF 1
-#define CONFIG_NOISE_BSF 1
-#define CONFIG_REMOVE_EXTRADATA_BSF 1
-#define CONFIG_TEXT2MOVSUB_BSF 1
-#define CONFIG_VP9_SUPERFRAME_BSF 1
-#define CONFIG_AASC_DECODER 1
-#define CONFIG_AIC_DECODER 1
-#define CONFIG_ALIAS_PIX_DECODER 1
-#define CONFIG_AMV_DECODER 1
-#define CONFIG_ANM_DECODER 1
-#define CONFIG_ANSI_DECODER 1
-#define CONFIG_APNG_DECODER 1
-#define CONFIG_ASV1_DECODER 1
-#define CONFIG_ASV2_DECODER 1
-#define CONFIG_AURA_DECODER 1
-#define CONFIG_AURA2_DECODER 1
-#define CONFIG_AVRP_DECODER 1
-#define CONFIG_AVRN_DECODER 1
-#define CONFIG_AVS_DECODER 1
-#define CONFIG_AVUI_DECODER 1
-#define CONFIG_AYUV_DECODER 1
-#define CONFIG_BETHSOFTVID_DECODER 1
-#define CONFIG_BFI_DECODER 1
-#define CONFIG_BINK_DECODER 1
-#define CONFIG_BMP_DECODER 1
-#define CONFIG_BMV_VIDEO_DECODER 1
-#define CONFIG_BRENDER_PIX_DECODER 1
-#define CONFIG_C93_DECODER 1
-#define CONFIG_CAVS_DECODER 1
-#define CONFIG_CDGRAPHICS_DECODER 1
-#define CONFIG_CDXL_DECODER 1
-#define CONFIG_CFHD_DECODER 1
-#define CONFIG_CINEPAK_DECODER 1
-#define CONFIG_CLJR_DECODER 1
-#define CONFIG_CLLC_DECODER 1
-#define CONFIG_COMFORTNOISE_DECODER 1
-#define CONFIG_CPIA_DECODER 1
-#define CONFIG_CSCD_DECODER 1
-#define CONFIG_CYUV_DECODER 1
-#define CONFIG_DDS_DECODER 1
-#define CONFIG_DFA_DECODER 1
-#define CONFIG_DIRAC_DECODER 1
-#define CONFIG_DNXHD_DECODER 1
-#define CONFIG_DPX_DECODER 1
-#define CONFIG_DSICINVIDEO_DECODER 1
-#define CONFIG_DVAUDIO_DECODER 1
-#define CONFIG_DVVIDEO_DECODER 1
-#define CONFIG_DXA_DECODER 1
-#define CONFIG_DXTORY_DECODER 1
-#define CONFIG_DXV_DECODER 1
-#define CONFIG_EACMV_DECODER 1
-#define CONFIG_EAMAD_DECODER 1
-#define CONFIG_EATGQ_DECODER 1
-#define CONFIG_EATGV_DECODER 1
-#define CONFIG_EATQI_DECODER 1
-#define CONFIG_EIGHTBPS_DECODER 1
-#define CONFIG_EIGHTSVX_EXP_DECODER 1
-#define CONFIG_EIGHTSVX_FIB_DECODER 1
-#define CONFIG_ESCAPE124_DECODER 1
-#define CONFIG_ESCAPE130_DECODER 1
-#define CONFIG_EXR_DECODER 1
-#define CONFIG_FFV1_DECODER 1
-#define CONFIG_FFVHUFF_DECODER 1
-#define CONFIG_FIC_DECODER 1
-#define CONFIG_FLASHSV_DECODER 1
-#define CONFIG_FLASHSV2_DECODER 1
-#define CONFIG_FLIC_DECODER 1
-#define CONFIG_FLV_DECODER 1
-#define CONFIG_FOURXM_DECODER 1
-#define CONFIG_FRAPS_DECODER 1
-#define CONFIG_FRWU_DECODER 1
-#define CONFIG_G2M_DECODER 1
-#define CONFIG_GIF_DECODER 1
-#define CONFIG_H261_DECODER 1
-#define CONFIG_H263_DECODER 1
-#define CONFIG_H263I_DECODER 1
-#define CONFIG_H263P_DECODER 1
-#define CONFIG_H264_DECODER 1
-#define CONFIG_H264_CRYSTALHD_DECODER 0
-#define CONFIG_H264_MEDIACODEC_DECODER 1
-#define CONFIG_H264_MMAL_DECODER 0
-#define CONFIG_H264_QSV_DECODER 0
-#define CONFIG_H264_VDA_DECODER 0
-#define CONFIG_H264_VDPAU_DECODER 0
-#define CONFIG_HAP_DECODER 1
-#define CONFIG_HEVC_DECODER 1
-#define CONFIG_HEVC_QSV_DECODER 0
-#define CONFIG_HNM4_VIDEO_DECODER 1
-#define CONFIG_HQ_HQA_DECODER 1
-#define CONFIG_HQX_DECODER 1
-#define CONFIG_HUFFYUV_DECODER 1
-#define CONFIG_IDCIN_DECODER 1
-#define CONFIG_IFF_ILBM_DECODER 1
-#define CONFIG_INDEO2_DECODER 1
-#define CONFIG_INDEO3_DECODER 1
-#define CONFIG_INDEO4_DECODER 1
-#define CONFIG_INDEO5_DECODER 1
-#define CONFIG_INTERPLAY_VIDEO_DECODER 1
-#define CONFIG_JPEG2000_DECODER 1
-#define CONFIG_JPEGLS_DECODER 1
-#define CONFIG_JV_DECODER 1
-#define CONFIG_KGV1_DECODER 1
-#define CONFIG_KMVC_DECODER 1
-#define CONFIG_LAGARITH_DECODER 1
-#define CONFIG_LOCO_DECODER 1
-#define CONFIG_M101_DECODER 1
-#define CONFIG_MAGICYUV_DECODER 1
-#define CONFIG_MDEC_DECODER 1
-#define CONFIG_MIMIC_DECODER 1
-#define CONFIG_MJPEG_DECODER 1
-#define CONFIG_MJPEGB_DECODER 1
-#define CONFIG_MMVIDEO_DECODER 1
-#define CONFIG_MOTIONPIXELS_DECODER 1
-#define CONFIG_MPEG_XVMC_DECODER 0
-#define CONFIG_MPEG1VIDEO_DECODER 1
-#define CONFIG_MPEG2VIDEO_DECODER 1
-#define CONFIG_MPEG4_DECODER 1
-#define CONFIG_MPEG4_CRYSTALHD_DECODER 0
-#define CONFIG_MPEG4_MMAL_DECODER 0
-#define CONFIG_MPEG4_VDPAU_DECODER 0
-#define CONFIG_MPEGVIDEO_DECODER 1
-#define CONFIG_MPEG_VDPAU_DECODER 0
-#define CONFIG_MPEG1_VDPAU_DECODER 0
-#define CONFIG_MPEG2_MMAL_DECODER 0
-#define CONFIG_MPEG2_CRYSTALHD_DECODER 0
-#define CONFIG_MPEG2_QSV_DECODER 0
-#define CONFIG_MSA1_DECODER 1
-#define CONFIG_MSMPEG4_CRYSTALHD_DECODER 0
-#define CONFIG_MSMPEG4V1_DECODER 1
-#define CONFIG_MSMPEG4V2_DECODER 1
-#define CONFIG_MSMPEG4V3_DECODER 1
-#define CONFIG_MSRLE_DECODER 1
-#define CONFIG_MSS1_DECODER 1
-#define CONFIG_MSS2_DECODER 1
-#define CONFIG_MSVIDEO1_DECODER 1
-#define CONFIG_MSZH_DECODER 1
-#define CONFIG_MTS2_DECODER 1
-#define CONFIG_MVC1_DECODER 1
-#define CONFIG_MVC2_DECODER 1
-#define CONFIG_MXPEG_DECODER 1
-#define CONFIG_NUV_DECODER 1
-#define CONFIG_PAF_VIDEO_DECODER 1
-#define CONFIG_PAM_DECODER 1
-#define CONFIG_PBM_DECODER 1
-#define CONFIG_PCX_DECODER 1
-#define CONFIG_PGM_DECODER 1
-#define CONFIG_PGMYUV_DECODER 1
-#define CONFIG_PICTOR_DECODER 1
-#define CONFIG_PNG_DECODER 1
-#define CONFIG_PPM_DECODER 1
-#define CONFIG_PRORES_DECODER 1
-#define CONFIG_PRORES_LGPL_DECODER 1
-#define CONFIG_PTX_DECODER 1
-#define CONFIG_QDRAW_DECODER 1
-#define CONFIG_QPEG_DECODER 1
-#define CONFIG_QTRLE_DECODER 1
-#define CONFIG_R10K_DECODER 1
-#define CONFIG_R210_DECODER 1
-#define CONFIG_RAWVIDEO_DECODER 1
-#define CONFIG_RL2_DECODER 1
-#define CONFIG_ROQ_DECODER 1
-#define CONFIG_RPZA_DECODER 1
-#define CONFIG_RSCC_DECODER 1
-#define CONFIG_RV10_DECODER 1
-#define CONFIG_RV20_DECODER 1
-#define CONFIG_RV30_DECODER 1
-#define CONFIG_RV40_DECODER 1
-#define CONFIG_S302M_DECODER 1
-#define CONFIG_SANM_DECODER 1
-#define CONFIG_SCREENPRESSO_DECODER 1
-#define CONFIG_SDX2_DPCM_DECODER 1
-#define CONFIG_SGI_DECODER 1
-#define CONFIG_SGIRLE_DECODER 1
-#define CONFIG_SHEERVIDEO_DECODER 1
-#define CONFIG_SMACKER_DECODER 1
-#define CONFIG_SMC_DECODER 1
-#define CONFIG_SMVJPEG_DECODER 1
-#define CONFIG_SNOW_DECODER 1
-#define CONFIG_SP5X_DECODER 1
-#define CONFIG_SUNRAST_DECODER 1
-#define CONFIG_SVQ1_DECODER 1
-#define CONFIG_SVQ3_DECODER 1
-#define CONFIG_TARGA_DECODER 1
-#define CONFIG_TARGA_Y216_DECODER 1
-#define CONFIG_TDSC_DECODER 1
-#define CONFIG_THEORA_DECODER 1
-#define CONFIG_THP_DECODER 1
-#define CONFIG_TIERTEXSEQVIDEO_DECODER 1
-#define CONFIG_TIFF_DECODER 1
-#define CONFIG_TMV_DECODER 1
-#define CONFIG_TRUEMOTION1_DECODER 1
-#define CONFIG_TRUEMOTION2_DECODER 1
-#define CONFIG_TRUEMOTION2RT_DECODER 1
-#define CONFIG_TSCC_DECODER 1
-#define CONFIG_TSCC2_DECODER 1
-#define CONFIG_TXD_DECODER 1
-#define CONFIG_ULTI_DECODER 1
-#define CONFIG_UTVIDEO_DECODER 1
-#define CONFIG_V210_DECODER 1
-#define CONFIG_V210X_DECODER 1
-#define CONFIG_V308_DECODER 1
-#define CONFIG_V408_DECODER 1
-#define CONFIG_V410_DECODER 1
-#define CONFIG_VB_DECODER 1
-#define CONFIG_VBLE_DECODER 1
-#define CONFIG_VC1_DECODER 1
-#define CONFIG_VC1_CRYSTALHD_DECODER 0
-#define CONFIG_VC1_VDPAU_DECODER 0
-#define CONFIG_VC1IMAGE_DECODER 1
-#define CONFIG_VC1_MMAL_DECODER 0
-#define CONFIG_VC1_QSV_DECODER 0
-#define CONFIG_VCR1_DECODER 1
-#define CONFIG_VMDVIDEO_DECODER 1
-#define CONFIG_VMNC_DECODER 1
-#define CONFIG_VP3_DECODER 1
-#define CONFIG_VP5_DECODER 1
-#define CONFIG_VP6_DECODER 1
-#define CONFIG_VP6A_DECODER 1
-#define CONFIG_VP6F_DECODER 1
-#define CONFIG_VP7_DECODER 1
-#define CONFIG_VP8_DECODER 1
-#define CONFIG_VP9_DECODER 1
-#define CONFIG_VQA_DECODER 1
-#define CONFIG_WEBP_DECODER 1
-#define CONFIG_WMV1_DECODER 1
-#define CONFIG_WMV2_DECODER 1
-#define CONFIG_WMV3_DECODER 1
-#define CONFIG_WMV3_CRYSTALHD_DECODER 0
-#define CONFIG_WMV3_VDPAU_DECODER 0
-#define CONFIG_WMV3IMAGE_DECODER 1
-#define CONFIG_WNV1_DECODER 1
-#define CONFIG_XAN_WC3_DECODER 1
-#define CONFIG_XAN_WC4_DECODER 1
-#define CONFIG_XBM_DECODER 1
-#define CONFIG_XFACE_DECODER 1
-#define CONFIG_XL_DECODER 1
-#define CONFIG_XWD_DECODER 1
-#define CONFIG_Y41P_DECODER 1
-#define CONFIG_YLC_DECODER 1
-#define CONFIG_YOP_DECODER 1
-#define CONFIG_YUV4_DECODER 1
-#define CONFIG_ZERO12V_DECODER 1
-#define CONFIG_ZEROCODEC_DECODER 1
-#define CONFIG_ZLIB_DECODER 1
-#define CONFIG_ZMBV_DECODER 1
-#define CONFIG_AAC_DECODER 1
-#define CONFIG_AAC_FIXED_DECODER 1
-#define CONFIG_AAC_LATM_DECODER 1
-#define CONFIG_AC3_DECODER 1
-#define CONFIG_AC3_FIXED_DECODER 1
-#define CONFIG_ALAC_DECODER 1
-#define CONFIG_ALS_DECODER 1
-#define CONFIG_AMRNB_DECODER 1
-#define CONFIG_AMRWB_DECODER 1
-#define CONFIG_APE_DECODER 1
-#define CONFIG_ATRAC1_DECODER 1
-#define CONFIG_ATRAC3_DECODER 1
-#define CONFIG_ATRAC3P_DECODER 1
-#define CONFIG_BINKAUDIO_DCT_DECODER 1
-#define CONFIG_BINKAUDIO_RDFT_DECODER 1
-#define CONFIG_BMV_AUDIO_DECODER 1
-#define CONFIG_COOK_DECODER 1
-#define CONFIG_DCA_DECODER 1
-#define CONFIG_DSD_LSBF_DECODER 1
-#define CONFIG_DSD_MSBF_DECODER 1
-#define CONFIG_DSD_LSBF_PLANAR_DECODER 1
-#define CONFIG_DSD_MSBF_PLANAR_DECODER 1
-#define CONFIG_DSICINAUDIO_DECODER 1
-#define CONFIG_DSS_SP_DECODER 1
-#define CONFIG_DST_DECODER 1
-#define CONFIG_EAC3_DECODER 1
-#define CONFIG_EVRC_DECODER 1
-#define CONFIG_FFWAVESYNTH_DECODER 1
-#define CONFIG_FLAC_DECODER 1
-#define CONFIG_G723_1_DECODER 1
-#define CONFIG_G729_DECODER 1
-#define CONFIG_GSM_DECODER 1
-#define CONFIG_GSM_MS_DECODER 1
-#define CONFIG_IAC_DECODER 1
-#define CONFIG_IMC_DECODER 1
-#define CONFIG_INTERPLAY_ACM_DECODER 1
-#define CONFIG_MACE3_DECODER 1
-#define CONFIG_MACE6_DECODER 1
-#define CONFIG_METASOUND_DECODER 1
-#define CONFIG_MLP_DECODER 1
-#define CONFIG_MP1_DECODER 1
-#define CONFIG_MP1FLOAT_DECODER 1
-#define CONFIG_MP2_DECODER 1
-#define CONFIG_MP2FLOAT_DECODER 1
-#define CONFIG_MP3_DECODER 1
-#define CONFIG_MP3FLOAT_DECODER 1
-#define CONFIG_MP3ADU_DECODER 1
-#define CONFIG_MP3ADUFLOAT_DECODER 1
-#define CONFIG_MP3ON4_DECODER 1
-#define CONFIG_MP3ON4FLOAT_DECODER 1
-#define CONFIG_MPC7_DECODER 1
-#define CONFIG_MPC8_DECODER 1
-#define CONFIG_NELLYMOSER_DECODER 1
-#define CONFIG_ON2AVC_DECODER 1
-#define CONFIG_OPUS_DECODER 1
-#define CONFIG_PAF_AUDIO_DECODER 1
-#define CONFIG_QCELP_DECODER 1
-#define CONFIG_QDM2_DECODER 1
-#define CONFIG_RA_144_DECODER 1
-#define CONFIG_RA_288_DECODER 1
-#define CONFIG_RALF_DECODER 1
-#define CONFIG_SHORTEN_DECODER 1
-#define CONFIG_SIPR_DECODER 1
-#define CONFIG_SMACKAUD_DECODER 1
-#define CONFIG_SONIC_DECODER 1
-#define CONFIG_TAK_DECODER 1
-#define CONFIG_TRUEHD_DECODER 1
-#define CONFIG_TRUESPEECH_DECODER 1
-#define CONFIG_TTA_DECODER 1
-#define CONFIG_TWINVQ_DECODER 1
-#define CONFIG_VMDAUDIO_DECODER 1
-#define CONFIG_VORBIS_DECODER 1
-#define CONFIG_WAVPACK_DECODER 1
-#define CONFIG_WMALOSSLESS_DECODER 1
-#define CONFIG_WMAPRO_DECODER 1
-#define CONFIG_WMAV1_DECODER 1
-#define CONFIG_WMAV2_DECODER 1
-#define CONFIG_WMAVOICE_DECODER 1
-#define CONFIG_WS_SND1_DECODER 1
-#define CONFIG_XMA1_DECODER 1
-#define CONFIG_XMA2_DECODER 1
-#define CONFIG_PCM_ALAW_DECODER 1
-#define CONFIG_PCM_BLURAY_DECODER 1
-#define CONFIG_PCM_DVD_DECODER 1
-#define CONFIG_PCM_F32BE_DECODER 1
-#define CONFIG_PCM_F32LE_DECODER 1
-#define CONFIG_PCM_F64BE_DECODER 1
-#define CONFIG_PCM_F64LE_DECODER 1
-#define CONFIG_PCM_LXF_DECODER 1
-#define CONFIG_PCM_MULAW_DECODER 1
-#define CONFIG_PCM_S8_DECODER 1
-#define CONFIG_PCM_S8_PLANAR_DECODER 1
-#define CONFIG_PCM_S16BE_DECODER 1
-#define CONFIG_PCM_S16BE_PLANAR_DECODER 1
-#define CONFIG_PCM_S16LE_DECODER 1
-#define CONFIG_PCM_S16LE_PLANAR_DECODER 1
-#define CONFIG_PCM_S24BE_DECODER 1
-#define CONFIG_PCM_S24DAUD_DECODER 1
-#define CONFIG_PCM_S24LE_DECODER 1
-#define CONFIG_PCM_S24LE_PLANAR_DECODER 1
-#define CONFIG_PCM_S32BE_DECODER 1
-#define CONFIG_PCM_S32LE_DECODER 1
-#define CONFIG_PCM_S32LE_PLANAR_DECODER 1
-#define CONFIG_PCM_S64BE_DECODER 1
-#define CONFIG_PCM_S64LE_DECODER 1
-#define CONFIG_PCM_U8_DECODER 1
-#define CONFIG_PCM_U16BE_DECODER 1
-#define CONFIG_PCM_U16LE_DECODER 1
-#define CONFIG_PCM_U24BE_DECODER 1
-#define CONFIG_PCM_U24LE_DECODER 1
-#define CONFIG_PCM_U32BE_DECODER 1
-#define CONFIG_PCM_U32LE_DECODER 1
-#define CONFIG_PCM_ZORK_DECODER 1
-#define CONFIG_INTERPLAY_DPCM_DECODER 1
-#define CONFIG_ROQ_DPCM_DECODER 1
-#define CONFIG_SOL_DPCM_DECODER 1
-#define CONFIG_XAN_DPCM_DECODER 1
-#define CONFIG_ADPCM_4XM_DECODER 1
-#define CONFIG_ADPCM_ADX_DECODER 1
-#define CONFIG_ADPCM_AFC_DECODER 1
-#define CONFIG_ADPCM_AICA_DECODER 1
-#define CONFIG_ADPCM_CT_DECODER 1
-#define CONFIG_ADPCM_DTK_DECODER 1
-#define CONFIG_ADPCM_EA_DECODER 1
-#define CONFIG_ADPCM_EA_MAXIS_XA_DECODER 1
-#define CONFIG_ADPCM_EA_R1_DECODER 1
-#define CONFIG_ADPCM_EA_R2_DECODER 1
-#define CONFIG_ADPCM_EA_R3_DECODER 1
-#define CONFIG_ADPCM_EA_XAS_DECODER 1
-#define CONFIG_ADPCM_G722_DECODER 1
-#define CONFIG_ADPCM_G726_DECODER 1
-#define CONFIG_ADPCM_G726LE_DECODER 1
-#define CONFIG_ADPCM_IMA_AMV_DECODER 1
-#define CONFIG_ADPCM_IMA_APC_DECODER 1
-#define CONFIG_ADPCM_IMA_DAT4_DECODER 1
-#define CONFIG_ADPCM_IMA_DK3_DECODER 1
-#define CONFIG_ADPCM_IMA_DK4_DECODER 1
-#define CONFIG_ADPCM_IMA_EA_EACS_DECODER 1
-#define CONFIG_ADPCM_IMA_EA_SEAD_DECODER 1
-#define CONFIG_ADPCM_IMA_ISS_DECODER 1
-#define CONFIG_ADPCM_IMA_OKI_DECODER 1
-#define CONFIG_ADPCM_IMA_QT_DECODER 1
-#define CONFIG_ADPCM_IMA_RAD_DECODER 1
-#define CONFIG_ADPCM_IMA_SMJPEG_DECODER 1
-#define CONFIG_ADPCM_IMA_WAV_DECODER 1
-#define CONFIG_ADPCM_IMA_WS_DECODER 1
-#define CONFIG_ADPCM_MS_DECODER 1
-#define CONFIG_ADPCM_MTAF_DECODER 1
-#define CONFIG_ADPCM_PSX_DECODER 1
-#define CONFIG_ADPCM_SBPRO_2_DECODER 1
-#define CONFIG_ADPCM_SBPRO_3_DECODER 1
-#define CONFIG_ADPCM_SBPRO_4_DECODER 1
-#define CONFIG_ADPCM_SWF_DECODER 1
-#define CONFIG_ADPCM_THP_DECODER 1
-#define CONFIG_ADPCM_THP_LE_DECODER 1
-#define CONFIG_ADPCM_VIMA_DECODER 1
-#define CONFIG_ADPCM_XA_DECODER 1
-#define CONFIG_ADPCM_YAMAHA_DECODER 1
-#define CONFIG_SSA_DECODER 1
-#define CONFIG_ASS_DECODER 1
-#define CONFIG_CCAPTION_DECODER 1
-#define CONFIG_DVBSUB_DECODER 1
-#define CONFIG_DVDSUB_DECODER 1
-#define CONFIG_JACOSUB_DECODER 1
-#define CONFIG_MICRODVD_DECODER 1
-#define CONFIG_MOVTEXT_DECODER 1
-#define CONFIG_MPL2_DECODER 1
-#define CONFIG_PGSSUB_DECODER 1
-#define CONFIG_PJS_DECODER 1
-#define CONFIG_REALTEXT_DECODER 1
-#define CONFIG_SAMI_DECODER 1
-#define CONFIG_SRT_DECODER 1
-#define CONFIG_STL_DECODER 1
-#define CONFIG_SUBRIP_DECODER 1
-#define CONFIG_SUBVIEWER_DECODER 1
-#define CONFIG_SUBVIEWER1_DECODER 1
-#define CONFIG_TEXT_DECODER 1
-#define CONFIG_VPLAYER_DECODER 1
-#define CONFIG_WEBVTT_DECODER 1
-#define CONFIG_XSUB_DECODER 1
-#define CONFIG_AAC_AT_DECODER 0
-#define CONFIG_AC3_AT_DECODER 0
-#define CONFIG_ADPCM_IMA_QT_AT_DECODER 0
-#define CONFIG_ALAC_AT_DECODER 0
-#define CONFIG_AMR_NB_AT_DECODER 0
-#define CONFIG_EAC3_AT_DECODER 0
-#define CONFIG_GSM_MS_AT_DECODER 0
-#define CONFIG_ILBC_AT_DECODER 0
-#define CONFIG_MP1_AT_DECODER 0
-#define CONFIG_MP2_AT_DECODER 0
-#define CONFIG_MP3_AT_DECODER 0
-#define CONFIG_PCM_ALAW_AT_DECODER 0
-#define CONFIG_PCM_MULAW_AT_DECODER 0
-#define CONFIG_QDMC_AT_DECODER 0
-#define CONFIG_QDM2_AT_DECODER 0
-#define CONFIG_LIBCELT_DECODER 0
-#define CONFIG_LIBFDK_AAC_DECODER 0
-#define CONFIG_LIBGSM_DECODER 0
-#define CONFIG_LIBGSM_MS_DECODER 0
-#define CONFIG_LIBILBC_DECODER 0
-#define CONFIG_LIBOPENCORE_AMRNB_DECODER 0
-#define CONFIG_LIBOPENCORE_AMRWB_DECODER 0
-#define CONFIG_LIBOPENJPEG_DECODER 0
-#define CONFIG_LIBOPUS_DECODER 0
-#define CONFIG_LIBSCHROEDINGER_DECODER 0
-#define CONFIG_LIBSPEEX_DECODER 0
-#define CONFIG_LIBVORBIS_DECODER 0
-#define CONFIG_LIBVPX_VP8_DECODER 0
-#define CONFIG_LIBVPX_VP9_DECODER 0
-#define CONFIG_LIBZVBI_TELETEXT_DECODER 0
-#define CONFIG_BINTEXT_DECODER 1
-#define CONFIG_XBIN_DECODER 1
-#define CONFIG_IDF_DECODER 1
-#define CONFIG_LIBOPENH264_DECODER 0
-#define CONFIG_H263_CUVID_DECODER 0
-#define CONFIG_H264_CUVID_DECODER 0
-#define CONFIG_HEVC_CUVID_DECODER 0
-#define CONFIG_HEVC_MEDIACODEC_DECODER 1
-#define CONFIG_MJPEG_CUVID_DECODER 0
-#define CONFIG_MPEG1_CUVID_DECODER 0
-#define CONFIG_MPEG2_CUVID_DECODER 0
-#define CONFIG_MPEG4_CUVID_DECODER 0
-#define CONFIG_MPEG4_MEDIACODEC_DECODER 1
-#define CONFIG_VC1_CUVID_DECODER 0
-#define CONFIG_VP8_CUVID_DECODER 0
-#define CONFIG_VP8_MEDIACODEC_DECODER 1
-#define CONFIG_VP9_CUVID_DECODER 0
-#define CONFIG_VP9_MEDIACODEC_DECODER 1
-#define CONFIG_AA_DEMUXER 1
-#define CONFIG_AAC_DEMUXER 1
-#define CONFIG_AC3_DEMUXER 1
-#define CONFIG_ACM_DEMUXER 1
-#define CONFIG_ACT_DEMUXER 1
-#define CONFIG_ADF_DEMUXER 1
-#define CONFIG_ADP_DEMUXER 1
-#define CONFIG_ADS_DEMUXER 1
-#define CONFIG_ADX_DEMUXER 1
-#define CONFIG_AEA_DEMUXER 1
-#define CONFIG_AFC_DEMUXER 1
-#define CONFIG_AIFF_DEMUXER 1
-#define CONFIG_AIX_DEMUXER 1
-#define CONFIG_AMR_DEMUXER 1
-#define CONFIG_ANM_DEMUXER 1
-#define CONFIG_APC_DEMUXER 1
-#define CONFIG_APE_DEMUXER 1
-#define CONFIG_APNG_DEMUXER 1
-#define CONFIG_AQTITLE_DEMUXER 1
-#define CONFIG_ASF_DEMUXER 1
-#define CONFIG_ASF_O_DEMUXER 1
-#define CONFIG_ASS_DEMUXER 1
-#define CONFIG_AST_DEMUXER 1
-#define CONFIG_AU_DEMUXER 1
-#define CONFIG_AVI_DEMUXER 1
-#define CONFIG_AVISYNTH_DEMUXER 0
-#define CONFIG_AVR_DEMUXER 1
-#define CONFIG_AVS_DEMUXER 1
-#define CONFIG_BETHSOFTVID_DEMUXER 1
-#define CONFIG_BFI_DEMUXER 1
-#define CONFIG_BINTEXT_DEMUXER 1
-#define CONFIG_BINK_DEMUXER 1
-#define CONFIG_BIT_DEMUXER 1
-#define CONFIG_BMV_DEMUXER 1
-#define CONFIG_BFSTM_DEMUXER 1
-#define CONFIG_BRSTM_DEMUXER 1
-#define CONFIG_BOA_DEMUXER 1
-#define CONFIG_C93_DEMUXER 1
-#define CONFIG_CAF_DEMUXER 1
-#define CONFIG_CAVSVIDEO_DEMUXER 1
-#define CONFIG_CDG_DEMUXER 1
-#define CONFIG_CDXL_DEMUXER 1
-#define CONFIG_CINE_DEMUXER 1
-#define CONFIG_CONCAT_DEMUXER 1
-#define CONFIG_DATA_DEMUXER 1
-#define CONFIG_DAUD_DEMUXER 1
-#define CONFIG_DCSTR_DEMUXER 1
-#define CONFIG_DFA_DEMUXER 1
-#define CONFIG_DIRAC_DEMUXER 1
-#define CONFIG_DNXHD_DEMUXER 1
-#define CONFIG_DSF_DEMUXER 1
-#define CONFIG_DSICIN_DEMUXER 1
-#define CONFIG_DSS_DEMUXER 1
-#define CONFIG_DTS_DEMUXER 1
-#define CONFIG_DTSHD_DEMUXER 1
-#define CONFIG_DV_DEMUXER 1
-#define CONFIG_DVBSUB_DEMUXER 1
-#define CONFIG_DVBTXT_DEMUXER 1
-#define CONFIG_DXA_DEMUXER 1
-#define CONFIG_EA_DEMUXER 1
-#define CONFIG_EA_CDATA_DEMUXER 1
-#define CONFIG_EAC3_DEMUXER 1
-#define CONFIG_EPAF_DEMUXER 1
-#define CONFIG_FFM_DEMUXER 1
-#define CONFIG_FFMETADATA_DEMUXER 1
-#define CONFIG_FILMSTRIP_DEMUXER 1
-#define CONFIG_FLAC_DEMUXER 1
-#define CONFIG_FLIC_DEMUXER 1
-#define CONFIG_FLV_DEMUXER 1
-#define CONFIG_LIVE_FLV_DEMUXER 1
-#define CONFIG_FOURXM_DEMUXER 1
-#define CONFIG_FRM_DEMUXER 1
-#define CONFIG_FSB_DEMUXER 1
-#define CONFIG_G722_DEMUXER 1
-#define CONFIG_G723_1_DEMUXER 1
-#define CONFIG_G729_DEMUXER 1
-#define CONFIG_GENH_DEMUXER 1
-#define CONFIG_GIF_DEMUXER 1
-#define CONFIG_GSM_DEMUXER 1
-#define CONFIG_GXF_DEMUXER 1
-#define CONFIG_H261_DEMUXER 1
-#define CONFIG_H263_DEMUXER 1
-#define CONFIG_H264_DEMUXER 1
-#define CONFIG_HEVC_DEMUXER 1
-#define CONFIG_HLS_DEMUXER 1
-#define CONFIG_HNM_DEMUXER 1
-#define CONFIG_ICO_DEMUXER 1
-#define CONFIG_IDCIN_DEMUXER 1
-#define CONFIG_IDF_DEMUXER 1
-#define CONFIG_IFF_DEMUXER 1
-#define CONFIG_ILBC_DEMUXER 1
-#define CONFIG_IMAGE2_DEMUXER 1
-#define CONFIG_IMAGE2PIPE_DEMUXER 1
-#define CONFIG_IMAGE2_ALIAS_PIX_DEMUXER 1
-#define CONFIG_IMAGE2_BRENDER_PIX_DEMUXER 1
-#define CONFIG_INGENIENT_DEMUXER 1
-#define CONFIG_IPMOVIE_DEMUXER 1
-#define CONFIG_IRCAM_DEMUXER 1
-#define CONFIG_ISS_DEMUXER 1
-#define CONFIG_IV8_DEMUXER 1
-#define CONFIG_IVF_DEMUXER 1
-#define CONFIG_IVR_DEMUXER 1
-#define CONFIG_JACOSUB_DEMUXER 1
-#define CONFIG_JV_DEMUXER 1
-#define CONFIG_LMLM4_DEMUXER 1
-#define CONFIG_LOAS_DEMUXER 1
-#define CONFIG_LRC_DEMUXER 1
-#define CONFIG_LVF_DEMUXER 1
-#define CONFIG_LXF_DEMUXER 1
-#define CONFIG_M4V_DEMUXER 1
-#define CONFIG_MATROSKA_DEMUXER 1
-#define CONFIG_MGSTS_DEMUXER 1
-#define CONFIG_MICRODVD_DEMUXER 1
-#define CONFIG_MJPEG_DEMUXER 1
-#define CONFIG_MLP_DEMUXER 1
-#define CONFIG_MLV_DEMUXER 1
-#define CONFIG_MM_DEMUXER 1
-#define CONFIG_MMF_DEMUXER 1
-#define CONFIG_MOV_DEMUXER 1
-#define CONFIG_MP3_DEMUXER 1
-#define CONFIG_MPC_DEMUXER 1
-#define CONFIG_MPC8_DEMUXER 1
-#define CONFIG_MPEGPS_DEMUXER 1
-#define CONFIG_MPEGTS_DEMUXER 1
-#define CONFIG_MPEGTSRAW_DEMUXER 1
-#define CONFIG_MPEGVIDEO_DEMUXER 1
-#define CONFIG_MPJPEG_DEMUXER 1
-#define CONFIG_MPL2_DEMUXER 1
-#define CONFIG_MPSUB_DEMUXER 1
-#define CONFIG_MSF_DEMUXER 1
-#define CONFIG_MSNWC_TCP_DEMUXER 1
-#define CONFIG_MTAF_DEMUXER 1
-#define CONFIG_MTV_DEMUXER 1
-#define CONFIG_MUSX_DEMUXER 1
-#define CONFIG_MV_DEMUXER 1
-#define CONFIG_MVI_DEMUXER 1
-#define CONFIG_MXF_DEMUXER 1
-#define CONFIG_MXG_DEMUXER 1
-#define CONFIG_NC_DEMUXER 1
-#define CONFIG_NISTSPHERE_DEMUXER 1
-#define CONFIG_NSV_DEMUXER 1
-#define CONFIG_NUT_DEMUXER 1
-#define CONFIG_NUV_DEMUXER 1
-#define CONFIG_OGG_DEMUXER 1
-#define CONFIG_OMA_DEMUXER 1
-#define CONFIG_PAF_DEMUXER 1
-#define CONFIG_PCM_ALAW_DEMUXER 1
-#define CONFIG_PCM_MULAW_DEMUXER 1
-#define CONFIG_PCM_F64BE_DEMUXER 1
-#define CONFIG_PCM_F64LE_DEMUXER 1
-#define CONFIG_PCM_F32BE_DEMUXER 1
-#define CONFIG_PCM_F32LE_DEMUXER 1
-#define CONFIG_PCM_S32BE_DEMUXER 1
-#define CONFIG_PCM_S32LE_DEMUXER 1
-#define CONFIG_PCM_S24BE_DEMUXER 1
-#define CONFIG_PCM_S24LE_DEMUXER 1
-#define CONFIG_PCM_S16BE_DEMUXER 1
-#define CONFIG_PCM_S16LE_DEMUXER 1
-#define CONFIG_PCM_S8_DEMUXER 1
-#define CONFIG_PCM_U32BE_DEMUXER 1
-#define CONFIG_PCM_U32LE_DEMUXER 1
-#define CONFIG_PCM_U24BE_DEMUXER 1
-#define CONFIG_PCM_U24LE_DEMUXER 1
-#define CONFIG_PCM_U16BE_DEMUXER 1
-#define CONFIG_PCM_U16LE_DEMUXER 1
-#define CONFIG_PCM_U8_DEMUXER 1
-#define CONFIG_PJS_DEMUXER 1
-#define CONFIG_PMP_DEMUXER 1
-#define CONFIG_PVA_DEMUXER 1
-#define CONFIG_PVF_DEMUXER 1
-#define CONFIG_QCP_DEMUXER 1
-#define CONFIG_R3D_DEMUXER 1
-#define CONFIG_RAWVIDEO_DEMUXER 1
-#define CONFIG_REALTEXT_DEMUXER 1
-#define CONFIG_REDSPARK_DEMUXER 1
-#define CONFIG_RL2_DEMUXER 1
-#define CONFIG_RM_DEMUXER 1
-#define CONFIG_ROQ_DEMUXER 1
-#define CONFIG_RPL_DEMUXER 1
-#define CONFIG_RSD_DEMUXER 1
-#define CONFIG_RSO_DEMUXER 1
-#define CONFIG_RTP_DEMUXER 1
-#define CONFIG_RTSP_DEMUXER 1
-#define CONFIG_SAMI_DEMUXER 1
-#define CONFIG_SAP_DEMUXER 1
-#define CONFIG_SBG_DEMUXER 1
-#define CONFIG_SDP_DEMUXER 1
-#define CONFIG_SDR2_DEMUXER 1
-#define CONFIG_SEGAFILM_DEMUXER 1
-#define CONFIG_SHORTEN_DEMUXER 1
-#define CONFIG_SIFF_DEMUXER 1
-#define CONFIG_SLN_DEMUXER 1
-#define CONFIG_SMACKER_DEMUXER 1
-#define CONFIG_SMJPEG_DEMUXER 1
-#define CONFIG_SMUSH_DEMUXER 1
-#define CONFIG_SOL_DEMUXER 1
-#define CONFIG_SOX_DEMUXER 1
-#define CONFIG_SPDIF_DEMUXER 1
-#define CONFIG_SRT_DEMUXER 1
-#define CONFIG_STR_DEMUXER 1
-#define CONFIG_STL_DEMUXER 1
-#define CONFIG_SUBVIEWER1_DEMUXER 1
-#define CONFIG_SUBVIEWER_DEMUXER 1
-#define CONFIG_SUP_DEMUXER 1
-#define CONFIG_SVAG_DEMUXER 1
-#define CONFIG_SWF_DEMUXER 1
-#define CONFIG_TAK_DEMUXER 1
-#define CONFIG_TEDCAPTIONS_DEMUXER 1
-#define CONFIG_THP_DEMUXER 1
-#define CONFIG_THREEDOSTR_DEMUXER 1
-#define CONFIG_TIERTEXSEQ_DEMUXER 1
-#define CONFIG_TMV_DEMUXER 1
-#define CONFIG_TRUEHD_DEMUXER 1
-#define CONFIG_TTA_DEMUXER 1
-#define CONFIG_TXD_DEMUXER 1
-#define CONFIG_TTY_DEMUXER 1
-#define CONFIG_V210_DEMUXER 1
-#define CONFIG_V210X_DEMUXER 1
-#define CONFIG_VAG_DEMUXER 1
-#define CONFIG_VC1_DEMUXER 1
-#define CONFIG_VC1T_DEMUXER 1
-#define CONFIG_VIVO_DEMUXER 1
-#define CONFIG_VMD_DEMUXER 1
-#define CONFIG_VOBSUB_DEMUXER 1
-#define CONFIG_VOC_DEMUXER 1
-#define CONFIG_VPK_DEMUXER 1
-#define CONFIG_VPLAYER_DEMUXER 1
-#define CONFIG_VQF_DEMUXER 1
-#define CONFIG_W64_DEMUXER 1
-#define CONFIG_WAV_DEMUXER 1
-#define CONFIG_WC3_DEMUXER 1
-#define CONFIG_WEBM_DASH_MANIFEST_DEMUXER 1
-#define CONFIG_WEBVTT_DEMUXER 1
-#define CONFIG_WSAUD_DEMUXER 1
-#define CONFIG_WSD_DEMUXER 1
-#define CONFIG_WSVQA_DEMUXER 1
-#define CONFIG_WTV_DEMUXER 1
-#define CONFIG_WVE_DEMUXER 1
-#define CONFIG_WV_DEMUXER 1
-#define CONFIG_XA_DEMUXER 1
-#define CONFIG_XBIN_DEMUXER 1
-#define CONFIG_XMV_DEMUXER 1
-#define CONFIG_XVAG_DEMUXER 1
-#define CONFIG_XWMA_DEMUXER 1
-#define CONFIG_YOP_DEMUXER 1
-#define CONFIG_YUV4MPEGPIPE_DEMUXER 1
-#define CONFIG_IMAGE_BMP_PIPE_DEMUXER 1
-#define CONFIG_IMAGE_DDS_PIPE_DEMUXER 1
-#define CONFIG_IMAGE_DPX_PIPE_DEMUXER 1
-#define CONFIG_IMAGE_EXR_PIPE_DEMUXER 1
-#define CONFIG_IMAGE_J2K_PIPE_DEMUXER 1
-#define CONFIG_IMAGE_JPEG_PIPE_DEMUXER 1
-#define CONFIG_IMAGE_JPEGLS_PIPE_DEMUXER 1
-#define CONFIG_IMAGE_PAM_PIPE_DEMUXER 1
-#define CONFIG_IMAGE_PBM_PIPE_DEMUXER 1
-#define CONFIG_IMAGE_PCX_PIPE_DEMUXER 1
-#define CONFIG_IMAGE_PGMYUV_PIPE_DEMUXER 1
-#define CONFIG_IMAGE_PGM_PIPE_DEMUXER 1
-#define CONFIG_IMAGE_PICTOR_PIPE_DEMUXER 1
-#define CONFIG_IMAGE_PNG_PIPE_DEMUXER 1
-#define CONFIG_IMAGE_PPM_PIPE_DEMUXER 1
-#define CONFIG_IMAGE_QDRAW_PIPE_DEMUXER 1
-#define CONFIG_IMAGE_SGI_PIPE_DEMUXER 1
-#define CONFIG_IMAGE_SUNRAST_PIPE_DEMUXER 1
-#define CONFIG_IMAGE_TIFF_PIPE_DEMUXER 1
-#define CONFIG_IMAGE_WEBP_PIPE_DEMUXER 1
-#define CONFIG_LIBGME_DEMUXER 0
-#define CONFIG_LIBMODPLUG_DEMUXER 0
-#define CONFIG_LIBNUT_DEMUXER 0
-#define CONFIG_LIBOPENMPT_DEMUXER 0
-#define CONFIG_A64MULTI_ENCODER 1
-#define CONFIG_A64MULTI5_ENCODER 1
-#define CONFIG_ALIAS_PIX_ENCODER 1
-#define CONFIG_AMV_ENCODER 1
-#define CONFIG_APNG_ENCODER 1
-#define CONFIG_ASV1_ENCODER 1
-#define CONFIG_ASV2_ENCODER 1
-#define CONFIG_AVRP_ENCODER 1
-#define CONFIG_AVUI_ENCODER 1
-#define CONFIG_AYUV_ENCODER 1
-#define CONFIG_BMP_ENCODER 1
-#define CONFIG_CINEPAK_ENCODER 1
-#define CONFIG_CLJR_ENCODER 1
-#define CONFIG_COMFORTNOISE_ENCODER 1
-#define CONFIG_DNXHD_ENCODER 1
-#define CONFIG_DPX_ENCODER 1
-#define CONFIG_DVVIDEO_ENCODER 1
-#define CONFIG_FFV1_ENCODER 1
-#define CONFIG_FFVHUFF_ENCODER 1
-#define CONFIG_FLASHSV_ENCODER 1
-#define CONFIG_FLASHSV2_ENCODER 1
-#define CONFIG_FLV_ENCODER 1
-#define CONFIG_GIF_ENCODER 1
-#define CONFIG_H261_ENCODER 1
-#define CONFIG_H263_ENCODER 1
-#define CONFIG_H263P_ENCODER 1
-#define CONFIG_HAP_ENCODER 0
-#define CONFIG_HUFFYUV_ENCODER 1
-#define CONFIG_JPEG2000_ENCODER 1
-#define CONFIG_JPEGLS_ENCODER 1
-#define CONFIG_LJPEG_ENCODER 1
-#define CONFIG_MJPEG_ENCODER 1
-#define CONFIG_MPEG1VIDEO_ENCODER 1
-#define CONFIG_MPEG2VIDEO_ENCODER 1
-#define CONFIG_MPEG4_ENCODER 1
-#define CONFIG_MSMPEG4V2_ENCODER 1
-#define CONFIG_MSMPEG4V3_ENCODER 1
-#define CONFIG_MSVIDEO1_ENCODER 1
-#define CONFIG_PAM_ENCODER 1
-#define CONFIG_PBM_ENCODER 1
-#define CONFIG_PCX_ENCODER 1
-#define CONFIG_PGM_ENCODER 1
-#define CONFIG_PGMYUV_ENCODER 1
-#define CONFIG_PNG_ENCODER 1
-#define CONFIG_PPM_ENCODER 1
-#define CONFIG_PRORES_ENCODER 1
-#define CONFIG_PRORES_AW_ENCODER 1
-#define CONFIG_PRORES_KS_ENCODER 1
-#define CONFIG_QTRLE_ENCODER 1
-#define CONFIG_R10K_ENCODER 1
-#define CONFIG_R210_ENCODER 1
-#define CONFIG_RAWVIDEO_ENCODER 1
-#define CONFIG_ROQ_ENCODER 1
-#define CONFIG_RV10_ENCODER 1
-#define CONFIG_RV20_ENCODER 1
-#define CONFIG_S302M_ENCODER 1
-#define CONFIG_SGI_ENCODER 1
-#define CONFIG_SNOW_ENCODER 1
-#define CONFIG_SUNRAST_ENCODER 1
-#define CONFIG_SVQ1_ENCODER 1
-#define CONFIG_TARGA_ENCODER 1
-#define CONFIG_TIFF_ENCODER 1
-#define CONFIG_UTVIDEO_ENCODER 1
-#define CONFIG_V210_ENCODER 1
-#define CONFIG_V308_ENCODER 1
-#define CONFIG_V408_ENCODER 1
-#define CONFIG_V410_ENCODER 1
-#define CONFIG_VC2_ENCODER 1
-#define CONFIG_WRAPPED_AVFRAME_ENCODER 1
-#define CONFIG_WMV1_ENCODER 1
-#define CONFIG_WMV2_ENCODER 1
-#define CONFIG_XBM_ENCODER 1
-#define CONFIG_XFACE_ENCODER 1
-#define CONFIG_XWD_ENCODER 1
-#define CONFIG_Y41P_ENCODER 1
-#define CONFIG_YUV4_ENCODER 1
-#define CONFIG_ZLIB_ENCODER 1
-#define CONFIG_ZMBV_ENCODER 1
-#define CONFIG_AAC_ENCODER 1
-#define CONFIG_AC3_ENCODER 1
-#define CONFIG_AC3_FIXED_ENCODER 1
-#define CONFIG_ALAC_ENCODER 1
-#define CONFIG_DCA_ENCODER 1
-#define CONFIG_EAC3_ENCODER 1
-#define CONFIG_FLAC_ENCODER 1
-#define CONFIG_G723_1_ENCODER 1
-#define CONFIG_MLP_ENCODER 1
-#define CONFIG_MP2_ENCODER 1
-#define CONFIG_MP2FIXED_ENCODER 1
-#define CONFIG_NELLYMOSER_ENCODER 1
-#define CONFIG_RA_144_ENCODER 1
-#define CONFIG_SONIC_ENCODER 1
-#define CONFIG_SONIC_LS_ENCODER 1
-#define CONFIG_TRUEHD_ENCODER 1
-#define CONFIG_TTA_ENCODER 1
-#define CONFIG_VORBIS_ENCODER 1
-#define CONFIG_WAVPACK_ENCODER 1
-#define CONFIG_WMAV1_ENCODER 1
-#define CONFIG_WMAV2_ENCODER 1
-#define CONFIG_PCM_ALAW_ENCODER 1
-#define CONFIG_PCM_F32BE_ENCODER 1
-#define CONFIG_PCM_F32LE_ENCODER 1
-#define CONFIG_PCM_F64BE_ENCODER 1
-#define CONFIG_PCM_F64LE_ENCODER 1
-#define CONFIG_PCM_MULAW_ENCODER 1
-#define CONFIG_PCM_S8_ENCODER 1
-#define CONFIG_PCM_S8_PLANAR_ENCODER 1
-#define CONFIG_PCM_S16BE_ENCODER 1
-#define CONFIG_PCM_S16BE_PLANAR_ENCODER 1
-#define CONFIG_PCM_S16LE_ENCODER 1
-#define CONFIG_PCM_S16LE_PLANAR_ENCODER 1
-#define CONFIG_PCM_S24BE_ENCODER 1
-#define CONFIG_PCM_S24DAUD_ENCODER 1
-#define CONFIG_PCM_S24LE_ENCODER 1
-#define CONFIG_PCM_S24LE_PLANAR_ENCODER 1
-#define CONFIG_PCM_S32BE_ENCODER 1
-#define CONFIG_PCM_S32LE_ENCODER 1
-#define CONFIG_PCM_S32LE_PLANAR_ENCODER 1
-#define CONFIG_PCM_S64BE_ENCODER 1
-#define CONFIG_PCM_S64LE_ENCODER 1
-#define CONFIG_PCM_U8_ENCODER 1
-#define CONFIG_PCM_U16BE_ENCODER 1
-#define CONFIG_PCM_U16LE_ENCODER 1
-#define CONFIG_PCM_U24BE_ENCODER 1
-#define CONFIG_PCM_U24LE_ENCODER 1
-#define CONFIG_PCM_U32BE_ENCODER 1
-#define CONFIG_PCM_U32LE_ENCODER 1
-#define CONFIG_ROQ_DPCM_ENCODER 1
-#define CONFIG_ADPCM_ADX_ENCODER 1
-#define CONFIG_ADPCM_G722_ENCODER 1
-#define CONFIG_ADPCM_G726_ENCODER 1
-#define CONFIG_ADPCM_IMA_QT_ENCODER 1
-#define CONFIG_ADPCM_IMA_WAV_ENCODER 1
-#define CONFIG_ADPCM_MS_ENCODER 1
-#define CONFIG_ADPCM_SWF_ENCODER 1
-#define CONFIG_ADPCM_YAMAHA_ENCODER 1
-#define CONFIG_SSA_ENCODER 1
-#define CONFIG_ASS_ENCODER 1
-#define CONFIG_DVBSUB_ENCODER 1
-#define CONFIG_DVDSUB_ENCODER 1
-#define CONFIG_MOVTEXT_ENCODER 1
-#define CONFIG_SRT_ENCODER 1
-#define CONFIG_SUBRIP_ENCODER 1
-#define CONFIG_TEXT_ENCODER 1
-#define CONFIG_WEBVTT_ENCODER 1
-#define CONFIG_XSUB_ENCODER 1
-#define CONFIG_AAC_AT_ENCODER 0
-#define CONFIG_ALAC_AT_ENCODER 0
-#define CONFIG_ILBC_AT_ENCODER 0
-#define CONFIG_PCM_ALAW_AT_ENCODER 0
-#define CONFIG_PCM_MULAW_AT_ENCODER 0
-#define CONFIG_LIBFDK_AAC_ENCODER 0
-#define CONFIG_LIBGSM_ENCODER 0
-#define CONFIG_LIBGSM_MS_ENCODER 0
-#define CONFIG_LIBILBC_ENCODER 0
-#define CONFIG_LIBMP3LAME_ENCODER 0
-#define CONFIG_LIBOPENCORE_AMRNB_ENCODER 0
-#define CONFIG_LIBOPENJPEG_ENCODER 0
-#define CONFIG_LIBOPUS_ENCODER 0
-#define CONFIG_LIBSCHROEDINGER_ENCODER 0
-#define CONFIG_LIBSHINE_ENCODER 0
-#define CONFIG_LIBSPEEX_ENCODER 0
-#define CONFIG_LIBTHEORA_ENCODER 0
-#define CONFIG_LIBTWOLAME_ENCODER 0
-#define CONFIG_LIBVO_AMRWBENC_ENCODER 0
-#define CONFIG_LIBVORBIS_ENCODER 0
-#define CONFIG_LIBVPX_VP8_ENCODER 0
-#define CONFIG_LIBVPX_VP9_ENCODER 0
-#define CONFIG_LIBWAVPACK_ENCODER 0
-#define CONFIG_LIBWEBP_ANIM_ENCODER 0
-#define CONFIG_LIBWEBP_ENCODER 0
-#define CONFIG_LIBX262_ENCODER 0
-#define CONFIG_LIBX264_ENCODER 0
-#define CONFIG_LIBX264RGB_ENCODER 0
-#define CONFIG_LIBX265_ENCODER 0
-#define CONFIG_LIBXAVS_ENCODER 0
-#define CONFIG_LIBXVID_ENCODER 0
-#define CONFIG_LIBOPENH264_ENCODER 0
-#define CONFIG_H264_NVENC_ENCODER 0
-#define CONFIG_H264_OMX_ENCODER 0
-#define CONFIG_H264_QSV_ENCODER 0
-#define CONFIG_H264_VAAPI_ENCODER 0
-#define CONFIG_H264_VIDEOTOOLBOX_ENCODER 0
-#define CONFIG_NVENC_ENCODER 0
-#define CONFIG_NVENC_H264_ENCODER 0
-#define CONFIG_NVENC_HEVC_ENCODER 0
-#define CONFIG_HEVC_NVENC_ENCODER 0
-#define CONFIG_HEVC_QSV_ENCODER 0
-#define CONFIG_HEVC_VAAPI_ENCODER 0
-#define CONFIG_LIBKVAZAAR_ENCODER 0
-#define CONFIG_MJPEG_VAAPI_ENCODER 0
-#define CONFIG_MPEG2_QSV_ENCODER 0
-#define CONFIG_ABENCH_FILTER 1
-#define CONFIG_ACOMPRESSOR_FILTER 1
-#define CONFIG_ACROSSFADE_FILTER 1
-#define CONFIG_ACRUSHER_FILTER 1
-#define CONFIG_ADELAY_FILTER 1
-#define CONFIG_AECHO_FILTER 1
-#define CONFIG_AEMPHASIS_FILTER 1
-#define CONFIG_AEVAL_FILTER 1
-#define CONFIG_AFADE_FILTER 1
-#define CONFIG_AFFTFILT_FILTER 1
-#define CONFIG_AFORMAT_FILTER 1
-#define CONFIG_AGATE_FILTER 1
-#define CONFIG_AINTERLEAVE_FILTER 1
-#define CONFIG_ALIMITER_FILTER 1
-#define CONFIG_ALLPASS_FILTER 1
-#define CONFIG_ALOOP_FILTER 1
-#define CONFIG_AMERGE_FILTER 1
-#define CONFIG_AMETADATA_FILTER 1
-#define CONFIG_AMIX_FILTER 1
-#define CONFIG_ANEQUALIZER_FILTER 1
-#define CONFIG_ANULL_FILTER 1
-#define CONFIG_APAD_FILTER 1
-#define CONFIG_APERMS_FILTER 1
-#define CONFIG_APHASER_FILTER 1
-#define CONFIG_APULSATOR_FILTER 1
-#define CONFIG_AREALTIME_FILTER 1
-#define CONFIG_ARESAMPLE_FILTER 1
-#define CONFIG_AREVERSE_FILTER 1
-#define CONFIG_ASELECT_FILTER 1
-#define CONFIG_ASENDCMD_FILTER 1
-#define CONFIG_ASETNSAMPLES_FILTER 1
-#define CONFIG_ASETPTS_FILTER 1
-#define CONFIG_ASETRATE_FILTER 1
-#define CONFIG_ASETTB_FILTER 1
-#define CONFIG_ASHOWINFO_FILTER 1
-#define CONFIG_ASIDEDATA_FILTER 1
-#define CONFIG_ASPLIT_FILTER 1
-#define CONFIG_ASTATS_FILTER 1
-#define CONFIG_ASTREAMSELECT_FILTER 1
-#define CONFIG_ASYNCTS_FILTER 0
-#define CONFIG_ATEMPO_FILTER 1
-#define CONFIG_ATRIM_FILTER 1
-#define CONFIG_AZMQ_FILTER 0
-#define CONFIG_BANDPASS_FILTER 1
-#define CONFIG_BANDREJECT_FILTER 1
-#define CONFIG_BASS_FILTER 1
-#define CONFIG_BIQUAD_FILTER 1
-#define CONFIG_BS2B_FILTER 0
-#define CONFIG_CHANNELMAP_FILTER 1
-#define CONFIG_CHANNELSPLIT_FILTER 1
-#define CONFIG_CHORUS_FILTER 1
-#define CONFIG_COMPAND_FILTER 1
-#define CONFIG_COMPENSATIONDELAY_FILTER 1
-#define CONFIG_CRYSTALIZER_FILTER 1
-#define CONFIG_DCSHIFT_FILTER 1
-#define CONFIG_DYNAUDNORM_FILTER 1
-#define CONFIG_EARWAX_FILTER 1
-#define CONFIG_EBUR128_FILTER 0
-#define CONFIG_EQUALIZER_FILTER 1
-#define CONFIG_EXTRASTEREO_FILTER 1
-#define CONFIG_FIREQUALIZER_FILTER 1
-#define CONFIG_FLANGER_FILTER 1
-#define CONFIG_HDCD_FILTER 1
-#define CONFIG_HIGHPASS_FILTER 1
-#define CONFIG_JOIN_FILTER 1
-#define CONFIG_LADSPA_FILTER 0
-#define CONFIG_LOUDNORM_FILTER 0
-#define CONFIG_LOWPASS_FILTER 1
-#define CONFIG_PAN_FILTER 1
-#define CONFIG_REPLAYGAIN_FILTER 1
-#define CONFIG_RESAMPLE_FILTER 0
-#define CONFIG_RUBBERBAND_FILTER 0
-#define CONFIG_SIDECHAINCOMPRESS_FILTER 1
-#define CONFIG_SIDECHAINGATE_FILTER 1
-#define CONFIG_SILENCEDETECT_FILTER 1
-#define CONFIG_SILENCEREMOVE_FILTER 1
-#define CONFIG_SOFALIZER_FILTER 0
-#define CONFIG_STEREOTOOLS_FILTER 1
-#define CONFIG_STEREOWIDEN_FILTER 1
-#define CONFIG_TREBLE_FILTER 1
-#define CONFIG_TREMOLO_FILTER 1
-#define CONFIG_VIBRATO_FILTER 1
-#define CONFIG_VOLUME_FILTER 1
-#define CONFIG_VOLUMEDETECT_FILTER 1
-#define CONFIG_AEVALSRC_FILTER 1
-#define CONFIG_ANOISESRC_FILTER 1
-#define CONFIG_ANULLSRC_FILTER 1
-#define CONFIG_FLITE_FILTER 0
-#define CONFIG_SINE_FILTER 1
-#define CONFIG_ANULLSINK_FILTER 1
-#define CONFIG_ALPHAEXTRACT_FILTER 1
-#define CONFIG_ALPHAMERGE_FILTER 1
-#define CONFIG_ASS_FILTER 0
-#define CONFIG_ATADENOISE_FILTER 1
-#define CONFIG_AVGBLUR_FILTER 1
-#define CONFIG_BBOX_FILTER 1
-#define CONFIG_BENCH_FILTER 1
-#define CONFIG_BITPLANENOISE_FILTER 1
-#define CONFIG_BLACKDETECT_FILTER 1
-#define CONFIG_BLACKFRAME_FILTER 0
-#define CONFIG_BLEND_FILTER 1
-#define CONFIG_BOXBLUR_FILTER 0
-#define CONFIG_BWDIF_FILTER 1
-#define CONFIG_CHROMAKEY_FILTER 1
-#define CONFIG_CIESCOPE_FILTER 1
-#define CONFIG_CODECVIEW_FILTER 1
-#define CONFIG_COLORBALANCE_FILTER 1
-#define CONFIG_COLORCHANNELMIXER_FILTER 1
-#define CONFIG_COLORKEY_FILTER 1
-#define CONFIG_COLORLEVELS_FILTER 1
-#define CONFIG_COLORMATRIX_FILTER 0
-#define CONFIG_COLORSPACE_FILTER 1
-#define CONFIG_CONVOLUTION_FILTER 1
-#define CONFIG_COPY_FILTER 1
-#define CONFIG_COREIMAGE_FILTER 0
-#define CONFIG_COVER_RECT_FILTER 0
-#define CONFIG_CROP_FILTER 1
-#define CONFIG_CROPDETECT_FILTER 0
-#define CONFIG_CURVES_FILTER 1
-#define CONFIG_DATASCOPE_FILTER 1
-#define CONFIG_DCTDNOIZ_FILTER 1
-#define CONFIG_DEBAND_FILTER 1
-#define CONFIG_DECIMATE_FILTER 1
-#define CONFIG_DEFLATE_FILTER 1
-#define CONFIG_DEJUDDER_FILTER 1
-#define CONFIG_DELOGO_FILTER 0
-#define CONFIG_DESHAKE_FILTER 1
-#define CONFIG_DETELECINE_FILTER 1
-#define CONFIG_DILATION_FILTER 1
-#define CONFIG_DISPLACE_FILTER 1
-#define CONFIG_DRAWBOX_FILTER 1
-#define CONFIG_DRAWGRAPH_FILTER 1
-#define CONFIG_DRAWGRID_FILTER 1
-#define CONFIG_DRAWTEXT_FILTER 0
-#define CONFIG_EDGEDETECT_FILTER 1
-#define CONFIG_ELBG_FILTER 1
-#define CONFIG_EQ_FILTER 0
-#define CONFIG_EROSION_FILTER 1
-#define CONFIG_EXTRACTPLANES_FILTER 1
-#define CONFIG_FADE_FILTER 1
-#define CONFIG_FFTFILT_FILTER 1
-#define CONFIG_FIELD_FILTER 1
-#define CONFIG_FIELDHINT_FILTER 1
-#define CONFIG_FIELDMATCH_FILTER 1
-#define CONFIG_FIELDORDER_FILTER 1
-#define CONFIG_FIND_RECT_FILTER 0
-#define CONFIG_FORMAT_FILTER 1
-#define CONFIG_FPS_FILTER 1
-#define CONFIG_FRAMEPACK_FILTER 1
-#define CONFIG_FRAMERATE_FILTER 1
-#define CONFIG_FRAMESTEP_FILTER 1
-#define CONFIG_FREI0R_FILTER 0
-#define CONFIG_FSPP_FILTER 0
-#define CONFIG_GBLUR_FILTER 1
-#define CONFIG_GEQ_FILTER 0
-#define CONFIG_GRADFUN_FILTER 1
-#define CONFIG_HALDCLUT_FILTER 1
-#define CONFIG_HFLIP_FILTER 1
-#define CONFIG_HISTEQ_FILTER 0
-#define CONFIG_HISTOGRAM_FILTER 1
-#define CONFIG_HQDN3D_FILTER 0
-#define CONFIG_HQX_FILTER 1
-#define CONFIG_HSTACK_FILTER 1
-#define CONFIG_HUE_FILTER 1
-#define CONFIG_HWDOWNLOAD_FILTER 1
-#define CONFIG_HWUPLOAD_FILTER 1
-#define CONFIG_HWUPLOAD_CUDA_FILTER 0
-#define CONFIG_HYSTERESIS_FILTER 1
-#define CONFIG_IDET_FILTER 1
-#define CONFIG_IL_FILTER 1
-#define CONFIG_INFLATE_FILTER 1
-#define CONFIG_INTERLACE_FILTER 0
-#define CONFIG_INTERLEAVE_FILTER 1
-#define CONFIG_KERNDEINT_FILTER 0
-#define CONFIG_LENSCORRECTION_FILTER 1
-#define CONFIG_LOOP_FILTER 1
-#define CONFIG_LUT_FILTER 1
-#define CONFIG_LUT2_FILTER 1
-#define CONFIG_LUT3D_FILTER 1
-#define CONFIG_LUTRGB_FILTER 1
-#define CONFIG_LUTYUV_FILTER 1
-#define CONFIG_MASKEDCLAMP_FILTER 1
-#define CONFIG_MASKEDMERGE_FILTER 1
-#define CONFIG_MCDEINT_FILTER 0
-#define CONFIG_MERGEPLANES_FILTER 1
-#define CONFIG_MESTIMATE_FILTER 1
-#define CONFIG_METADATA_FILTER 1
-#define CONFIG_MINTERPOLATE_FILTER 1
-#define CONFIG_MPDECIMATE_FILTER 0
-#define CONFIG_NEGATE_FILTER 1
-#define CONFIG_NLMEANS_FILTER 1
-#define CONFIG_NNEDI_FILTER 0
-#define CONFIG_NOFORMAT_FILTER 1
-#define CONFIG_NOISE_FILTER 1
-#define CONFIG_NULL_FILTER 1
-#define CONFIG_OCR_FILTER 0
-#define CONFIG_OCV_FILTER 0
-#define CONFIG_OVERLAY_FILTER 1
-#define CONFIG_OWDENOISE_FILTER 0
-#define CONFIG_PAD_FILTER 1
-#define CONFIG_PALETTEGEN_FILTER 1
-#define CONFIG_PALETTEUSE_FILTER 1
-#define CONFIG_PERMS_FILTER 1
-#define CONFIG_PERSPECTIVE_FILTER 0
-#define CONFIG_PHASE_FILTER 0
-#define CONFIG_PIXDESCTEST_FILTER 1
-#define CONFIG_PP_FILTER 0
-#define CONFIG_PP7_FILTER 0
-#define CONFIG_PREWITT_FILTER 1
-#define CONFIG_PSNR_FILTER 1
-#define CONFIG_PULLUP_FILTER 0
-#define CONFIG_QP_FILTER 1
-#define CONFIG_RANDOM_FILTER 1
-#define CONFIG_READVITC_FILTER 1
-#define CONFIG_REALTIME_FILTER 1
-#define CONFIG_REMAP_FILTER 1
-#define CONFIG_REMOVEGRAIN_FILTER 1
-#define CONFIG_REMOVELOGO_FILTER 1
-#define CONFIG_REPEATFIELDS_FILTER 0
-#define CONFIG_REVERSE_FILTER 1
-#define CONFIG_ROTATE_FILTER 1
-#define CONFIG_SAB_FILTER 0
-#define CONFIG_SCALE_FILTER 1
-#define CONFIG_SCALE_NPP_FILTER 0
-#define CONFIG_SCALE_VAAPI_FILTER 0
-#define CONFIG_SCALE2REF_FILTER 1
-#define CONFIG_SELECT_FILTER 1
-#define CONFIG_SELECTIVECOLOR_FILTER 1
-#define CONFIG_SENDCMD_FILTER 1
-#define CONFIG_SEPARATEFIELDS_FILTER 1
-#define CONFIG_SETDAR_FILTER 1
-#define CONFIG_SETFIELD_FILTER 1
-#define CONFIG_SETPTS_FILTER 1
-#define CONFIG_SETSAR_FILTER 1
-#define CONFIG_SETTB_FILTER 1
-#define CONFIG_SHOWINFO_FILTER 1
-#define CONFIG_SHOWPALETTE_FILTER 1
-#define CONFIG_SHUFFLEFRAMES_FILTER 1
-#define CONFIG_SHUFFLEPLANES_FILTER 1
-#define CONFIG_SIDEDATA_FILTER 1
-#define CONFIG_SIGNALSTATS_FILTER 1
-#define CONFIG_SMARTBLUR_FILTER 0
-#define CONFIG_SOBEL_FILTER 1
-#define CONFIG_SPLIT_FILTER 1
-#define CONFIG_SPP_FILTER 0
-#define CONFIG_SSIM_FILTER 1
-#define CONFIG_STEREO3D_FILTER 0
-#define CONFIG_STREAMSELECT_FILTER 1
-#define CONFIG_SUBTITLES_FILTER 0
-#define CONFIG_SUPER2XSAI_FILTER 0
-#define CONFIG_SWAPRECT_FILTER 1
-#define CONFIG_SWAPUV_FILTER 1
-#define CONFIG_TBLEND_FILTER 1
-#define CONFIG_TELECINE_FILTER 1
-#define CONFIG_THUMBNAIL_FILTER 1
-#define CONFIG_TILE_FILTER 1
-#define CONFIG_TINTERLACE_FILTER 0
-#define CONFIG_TRANSPOSE_FILTER 1
-#define CONFIG_TRIM_FILTER 1
-#define CONFIG_UNSHARP_FILTER 1
-#define CONFIG_USPP_FILTER 0
-#define CONFIG_VAGUEDENOISER_FILTER 0
-#define CONFIG_VECTORSCOPE_FILTER 1
-#define CONFIG_VFLIP_FILTER 1
-#define CONFIG_VIDSTABDETECT_FILTER 0
-#define CONFIG_VIDSTABTRANSFORM_FILTER 0
-#define CONFIG_VIGNETTE_FILTER 1
-#define CONFIG_VSTACK_FILTER 1
-#define CONFIG_W3FDIF_FILTER 1
-#define CONFIG_WAVEFORM_FILTER 1
-#define CONFIG_WEAVE_FILTER 1
-#define CONFIG_XBR_FILTER 1
-#define CONFIG_YADIF_FILTER 1
-#define CONFIG_ZMQ_FILTER 0
-#define CONFIG_ZOOMPAN_FILTER 1
-#define CONFIG_ZSCALE_FILTER 0
-#define CONFIG_ALLRGB_FILTER 1
-#define CONFIG_ALLYUV_FILTER 1
-#define CONFIG_CELLAUTO_FILTER 1
-#define CONFIG_COLOR_FILTER 1
-#define CONFIG_COREIMAGESRC_FILTER 0
-#define CONFIG_FREI0R_SRC_FILTER 0
-#define CONFIG_HALDCLUTSRC_FILTER 1
-#define CONFIG_LIFE_FILTER 1
-#define CONFIG_MANDELBROT_FILTER 1
-#define CONFIG_MPTESTSRC_FILTER 0
-#define CONFIG_NULLSRC_FILTER 1
-#define CONFIG_RGBTESTSRC_FILTER 1
-#define CONFIG_SMPTEBARS_FILTER 1
-#define CONFIG_SMPTEHDBARS_FILTER 1
-#define CONFIG_TESTSRC_FILTER 1
-#define CONFIG_TESTSRC2_FILTER 1
-#define CONFIG_YUVTESTSRC_FILTER 1
-#define CONFIG_NULLSINK_FILTER 1
-#define CONFIG_ADRAWGRAPH_FILTER 1
-#define CONFIG_AHISTOGRAM_FILTER 1
-#define CONFIG_APHASEMETER_FILTER 1
-#define CONFIG_AVECTORSCOPE_FILTER 1
-#define CONFIG_CONCAT_FILTER 1
-#define CONFIG_SHOWCQT_FILTER 1
-#define CONFIG_SHOWFREQS_FILTER 1
-#define CONFIG_SHOWSPECTRUM_FILTER 1
-#define CONFIG_SHOWSPECTRUMPIC_FILTER 1
-#define CONFIG_SHOWVOLUME_FILTER 1
-#define CONFIG_SHOWWAVES_FILTER 1
-#define CONFIG_SHOWWAVESPIC_FILTER 1
-#define CONFIG_SPECTRUMSYNTH_FILTER 1
-#define CONFIG_AMOVIE_FILTER 1
-#define CONFIG_MOVIE_FILTER 1
-#define CONFIG_H263_CUVID_HWACCEL 0
-#define CONFIG_H263_VAAPI_HWACCEL 0
-#define CONFIG_H263_VIDEOTOOLBOX_HWACCEL 0
-#define CONFIG_H264_CUVID_HWACCEL 0
-#define CONFIG_H264_D3D11VA_HWACCEL 0
-#define CONFIG_H264_DXVA2_HWACCEL 0
-#define CONFIG_H264_MEDIACODEC_HWACCEL 1
-#define CONFIG_H264_MMAL_HWACCEL 0
-#define CONFIG_H264_QSV_HWACCEL 0
-#define CONFIG_H264_VAAPI_HWACCEL 0
-#define CONFIG_H264_VDA_HWACCEL 0
-#define CONFIG_H264_VDA_OLD_HWACCEL 0
-#define CONFIG_H264_VDPAU_HWACCEL 0
-#define CONFIG_H264_VIDEOTOOLBOX_HWACCEL 0
-#define CONFIG_HEVC_CUVID_HWACCEL 0
-#define CONFIG_HEVC_D3D11VA_HWACCEL 0
-#define CONFIG_HEVC_DXVA2_HWACCEL 0
-#define CONFIG_HEVC_MEDIACODEC_HWACCEL 1
-#define CONFIG_HEVC_QSV_HWACCEL 0
-#define CONFIG_HEVC_VAAPI_HWACCEL 0
-#define CONFIG_HEVC_VDPAU_HWACCEL 0
-#define CONFIG_MJPEG_CUVID_HWACCEL 0
-#define CONFIG_MPEG1_CUVID_HWACCEL 0
-#define CONFIG_MPEG1_XVMC_HWACCEL 0
-#define CONFIG_MPEG1_VDPAU_HWACCEL 0
-#define CONFIG_MPEG1_VIDEOTOOLBOX_HWACCEL 0
-#define CONFIG_MPEG2_CUVID_HWACCEL 0
-#define CONFIG_MPEG2_XVMC_HWACCEL 0
-#define CONFIG_MPEG2_D3D11VA_HWACCEL 0
-#define CONFIG_MPEG2_DXVA2_HWACCEL 0
-#define CONFIG_MPEG2_MMAL_HWACCEL 0
-#define CONFIG_MPEG2_QSV_HWACCEL 0
-#define CONFIG_MPEG2_VAAPI_HWACCEL 0
-#define CONFIG_MPEG2_VDPAU_HWACCEL 0
-#define CONFIG_MPEG2_VIDEOTOOLBOX_HWACCEL 0
-#define CONFIG_MPEG4_CUVID_HWACCEL 0
-#define CONFIG_MPEG4_MEDIACODEC_HWACCEL 1
-#define CONFIG_MPEG4_MMAL_HWACCEL 0
-#define CONFIG_MPEG4_VAAPI_HWACCEL 0
-#define CONFIG_MPEG4_VDPAU_HWACCEL 0
-#define CONFIG_MPEG4_VIDEOTOOLBOX_HWACCEL 0
-#define CONFIG_VC1_CUVID_HWACCEL 0
-#define CONFIG_VC1_D3D11VA_HWACCEL 0
-#define CONFIG_VC1_DXVA2_HWACCEL 0
-#define CONFIG_VC1_VAAPI_HWACCEL 0
-#define CONFIG_VC1_VDPAU_HWACCEL 0
-#define CONFIG_VC1_MMAL_HWACCEL 0
-#define CONFIG_VC1_QSV_HWACCEL 0
-#define CONFIG_VP8_CUVID_HWACCEL 0
-#define CONFIG_VP8_MEDIACODEC_HWACCEL 1
-#define CONFIG_VP9_CUVID_HWACCEL 0
-#define CONFIG_VP9_D3D11VA_HWACCEL 0
-#define CONFIG_VP9_DXVA2_HWACCEL 0
-#define CONFIG_VP9_MEDIACODEC_HWACCEL 1
-#define CONFIG_VP9_VAAPI_HWACCEL 0
-#define CONFIG_WMV3_D3D11VA_HWACCEL 0
-#define CONFIG_WMV3_DXVA2_HWACCEL 0
-#define CONFIG_WMV3_VAAPI_HWACCEL 0
-#define CONFIG_WMV3_VDPAU_HWACCEL 0
-#define CONFIG_ALSA_INDEV 0
-#define CONFIG_AVFOUNDATION_INDEV 0
-#define CONFIG_BKTR_INDEV 0
-#define CONFIG_DECKLINK_INDEV 0
-#define CONFIG_DSHOW_INDEV 0
-#define CONFIG_DV1394_INDEV 0
-#define CONFIG_FBDEV_INDEV 0
-#define CONFIG_GDIGRAB_INDEV 0
-#define CONFIG_IEC61883_INDEV 0
-#define CONFIG_JACK_INDEV 0
-#define CONFIG_LAVFI_INDEV 0
-#define CONFIG_OPENAL_INDEV 0
-#define CONFIG_OSS_INDEV 0
-#define CONFIG_PULSE_INDEV 0
-#define CONFIG_QTKIT_INDEV 0
-#define CONFIG_SNDIO_INDEV 0
-#define CONFIG_V4L2_INDEV 0
-#define CONFIG_VFWCAP_INDEV 0
-#define CONFIG_X11GRAB_INDEV 0
-#define CONFIG_X11GRAB_XCB_INDEV 0
-#define CONFIG_LIBCDIO_INDEV 0
-#define CONFIG_LIBDC1394_INDEV 0
-#define CONFIG_A64_MUXER 1
-#define CONFIG_AC3_MUXER 1
-#define CONFIG_ADTS_MUXER 1
-#define CONFIG_ADX_MUXER 1
-#define CONFIG_AIFF_MUXER 1
-#define CONFIG_AMR_MUXER 1
-#define CONFIG_APNG_MUXER 1
-#define CONFIG_ASF_MUXER 1
-#define CONFIG_ASS_MUXER 1
-#define CONFIG_AST_MUXER 1
-#define CONFIG_ASF_STREAM_MUXER 1
-#define CONFIG_AU_MUXER 1
-#define CONFIG_AVI_MUXER 1
-#define CONFIG_AVM2_MUXER 1
-#define CONFIG_BIT_MUXER 1
-#define CONFIG_CAF_MUXER 1
-#define CONFIG_CAVSVIDEO_MUXER 1
-#define CONFIG_CRC_MUXER 1
-#define CONFIG_DASH_MUXER 1
-#define CONFIG_DATA_MUXER 1
-#define CONFIG_DAUD_MUXER 1
-#define CONFIG_DIRAC_MUXER 1
-#define CONFIG_DNXHD_MUXER 1
-#define CONFIG_DTS_MUXER 1
-#define CONFIG_DV_MUXER 1
-#define CONFIG_EAC3_MUXER 1
-#define CONFIG_F4V_MUXER 1
-#define CONFIG_FFM_MUXER 1
-#define CONFIG_FFMETADATA_MUXER 1
-#define CONFIG_FIFO_MUXER 1
-#define CONFIG_FILMSTRIP_MUXER 1
-#define CONFIG_FLAC_MUXER 1
-#define CONFIG_FLV_MUXER 1
-#define CONFIG_FRAMECRC_MUXER 1
-#define CONFIG_FRAMEHASH_MUXER 1
-#define CONFIG_FRAMEMD5_MUXER 1
-#define CONFIG_G722_MUXER 1
-#define CONFIG_G723_1_MUXER 1
-#define CONFIG_GIF_MUXER 1
-#define CONFIG_GSM_MUXER 1
-#define CONFIG_GXF_MUXER 1
-#define CONFIG_H261_MUXER 1
-#define CONFIG_H263_MUXER 1
-#define CONFIG_H264_MUXER 1
-#define CONFIG_HASH_MUXER 1
-#define CONFIG_HDS_MUXER 1
-#define CONFIG_HEVC_MUXER 1
-#define CONFIG_HLS_MUXER 1
-#define CONFIG_ICO_MUXER 1
-#define CONFIG_ILBC_MUXER 1
-#define CONFIG_IMAGE2_MUXER 1
-#define CONFIG_IMAGE2PIPE_MUXER 1
-#define CONFIG_IPOD_MUXER 1
-#define CONFIG_IRCAM_MUXER 1
-#define CONFIG_ISMV_MUXER 1
-#define CONFIG_IVF_MUXER 1
-#define CONFIG_JACOSUB_MUXER 1
-#define CONFIG_LATM_MUXER 1
-#define CONFIG_LRC_MUXER 1
-#define CONFIG_M4V_MUXER 1
-#define CONFIG_MD5_MUXER 1
-#define CONFIG_MATROSKA_MUXER 1
-#define CONFIG_MATROSKA_AUDIO_MUXER 1
-#define CONFIG_MICRODVD_MUXER 1
-#define CONFIG_MJPEG_MUXER 1
-#define CONFIG_MLP_MUXER 1
-#define CONFIG_MMF_MUXER 1
-#define CONFIG_MOV_MUXER 1
-#define CONFIG_MP2_MUXER 1
-#define CONFIG_MP3_MUXER 1
-#define CONFIG_MP4_MUXER 1
-#define CONFIG_MPEG1SYSTEM_MUXER 1
-#define CONFIG_MPEG1VCD_MUXER 1
-#define CONFIG_MPEG1VIDEO_MUXER 1
-#define CONFIG_MPEG2DVD_MUXER 1
-#define CONFIG_MPEG2SVCD_MUXER 1
-#define CONFIG_MPEG2VIDEO_MUXER 1
-#define CONFIG_MPEG2VOB_MUXER 1
-#define CONFIG_MPEGTS_MUXER 1
-#define CONFIG_MPJPEG_MUXER 1
-#define CONFIG_MXF_MUXER 1
-#define CONFIG_MXF_D10_MUXER 1
-#define CONFIG_MXF_OPATOM_MUXER 1
-#define CONFIG_NULL_MUXER 1
-#define CONFIG_NUT_MUXER 1
-#define CONFIG_OGA_MUXER 1
-#define CONFIG_OGG_MUXER 1
-#define CONFIG_OGV_MUXER 1
-#define CONFIG_OMA_MUXER 1
-#define CONFIG_OPUS_MUXER 1
-#define CONFIG_PCM_ALAW_MUXER 1
-#define CONFIG_PCM_MULAW_MUXER 1
-#define CONFIG_PCM_F64BE_MUXER 1
-#define CONFIG_PCM_F64LE_MUXER 1
-#define CONFIG_PCM_F32BE_MUXER 1
-#define CONFIG_PCM_F32LE_MUXER 1
-#define CONFIG_PCM_S32BE_MUXER 1
-#define CONFIG_PCM_S32LE_MUXER 1
-#define CONFIG_PCM_S24BE_MUXER 1
-#define CONFIG_PCM_S24LE_MUXER 1
-#define CONFIG_PCM_S16BE_MUXER 1
-#define CONFIG_PCM_S16LE_MUXER 1
-#define CONFIG_PCM_S8_MUXER 1
-#define CONFIG_PCM_U32BE_MUXER 1
-#define CONFIG_PCM_U32LE_MUXER 1
-#define CONFIG_PCM_U24BE_MUXER 1
-#define CONFIG_PCM_U24LE_MUXER 1
-#define CONFIG_PCM_U16BE_MUXER 1
-#define CONFIG_PCM_U16LE_MUXER 1
-#define CONFIG_PCM_U8_MUXER 1
-#define CONFIG_PSP_MUXER 1
-#define CONFIG_RAWVIDEO_MUXER 1
-#define CONFIG_RM_MUXER 1
-#define CONFIG_ROQ_MUXER 1
-#define CONFIG_RSO_MUXER 1
-#define CONFIG_RTP_MUXER 1
-#define CONFIG_RTP_MPEGTS_MUXER 1
-#define CONFIG_RTSP_MUXER 1
-#define CONFIG_SAP_MUXER 1
-#define CONFIG_SEGMENT_MUXER 1
-#define CONFIG_STREAM_SEGMENT_MUXER 1
-#define CONFIG_SINGLEJPEG_MUXER 1
-#define CONFIG_SMJPEG_MUXER 1
-#define CONFIG_SMOOTHSTREAMING_MUXER 1
-#define CONFIG_SOX_MUXER 1
-#define CONFIG_SPX_MUXER 1
-#define CONFIG_SPDIF_MUXER 1
-#define CONFIG_SRT_MUXER 1
-#define CONFIG_SWF_MUXER 1
-#define CONFIG_TEE_MUXER 1
-#define CONFIG_TG2_MUXER 1
-#define CONFIG_TGP_MUXER 1
-#define CONFIG_MKVTIMESTAMP_V2_MUXER 1
-#define CONFIG_TRUEHD_MUXER 1
-#define CONFIG_TTA_MUXER 1
-#define CONFIG_UNCODEDFRAMECRC_MUXER 1
-#define CONFIG_VC1_MUXER 1
-#define CONFIG_VC1T_MUXER 1
-#define CONFIG_VOC_MUXER 1
-#define CONFIG_W64_MUXER 1
-#define CONFIG_WAV_MUXER 1
-#define CONFIG_WEBM_MUXER 1
-#define CONFIG_WEBM_DASH_MANIFEST_MUXER 1
-#define CONFIG_WEBM_CHUNK_MUXER 1
-#define CONFIG_WEBP_MUXER 1
-#define CONFIG_WEBVTT_MUXER 1
-#define CONFIG_WTV_MUXER 1
-#define CONFIG_WV_MUXER 1
-#define CONFIG_YUV4MPEGPIPE_MUXER 1
-#define CONFIG_CHROMAPRINT_MUXER 0
-#define CONFIG_LIBNUT_MUXER 0
-#define CONFIG_ALSA_OUTDEV 0
-#define CONFIG_CACA_OUTDEV 0
-#define CONFIG_DECKLINK_OUTDEV 0
-#define CONFIG_FBDEV_OUTDEV 0
-#define CONFIG_OPENGL_OUTDEV 0
-#define CONFIG_OSS_OUTDEV 0
-#define CONFIG_PULSE_OUTDEV 0
-#define CONFIG_SDL2_OUTDEV 0
-#define CONFIG_SNDIO_OUTDEV 0
-#define CONFIG_V4L2_OUTDEV 0
-#define CONFIG_XV_OUTDEV 0
-#define CONFIG_AAC_PARSER 1
-#define CONFIG_AAC_LATM_PARSER 1
-#define CONFIG_AC3_PARSER 1
-#define CONFIG_ADX_PARSER 1
-#define CONFIG_BMP_PARSER 1
-#define CONFIG_CAVSVIDEO_PARSER 1
-#define CONFIG_COOK_PARSER 1
-#define CONFIG_DCA_PARSER 1
-#define CONFIG_DIRAC_PARSER 1
-#define CONFIG_DNXHD_PARSER 1
-#define CONFIG_DPX_PARSER 1
-#define CONFIG_DVAUDIO_PARSER 1
-#define CONFIG_DVBSUB_PARSER 1
-#define CONFIG_DVDSUB_PARSER 1
-#define CONFIG_DVD_NAV_PARSER 1
-#define CONFIG_FLAC_PARSER 1
-#define CONFIG_G729_PARSER 1
-#define CONFIG_GSM_PARSER 1
-#define CONFIG_H261_PARSER 1
-#define CONFIG_H263_PARSER 1
-#define CONFIG_H264_PARSER 1
-#define CONFIG_HEVC_PARSER 1
-#define CONFIG_MJPEG_PARSER 1
-#define CONFIG_MLP_PARSER 1
-#define CONFIG_MPEG4VIDEO_PARSER 1
-#define CONFIG_MPEGAUDIO_PARSER 1
-#define CONFIG_MPEGVIDEO_PARSER 1
-#define CONFIG_OPUS_PARSER 1
-#define CONFIG_PNG_PARSER 1
-#define CONFIG_PNM_PARSER 1
-#define CONFIG_RV30_PARSER 1
-#define CONFIG_RV40_PARSER 1
-#define CONFIG_TAK_PARSER 1
-#define CONFIG_VC1_PARSER 1
-#define CONFIG_VORBIS_PARSER 1
-#define CONFIG_VP3_PARSER 1
-#define CONFIG_VP8_PARSER 1
-#define CONFIG_VP9_PARSER 1
-#define CONFIG_ASYNC_PROTOCOL 1
-#define CONFIG_BLURAY_PROTOCOL 0
-#define CONFIG_CACHE_PROTOCOL 1
-#define CONFIG_CONCAT_PROTOCOL 1
-#define CONFIG_CRYPTO_PROTOCOL 1
-#define CONFIG_DATA_PROTOCOL 1
-#define CONFIG_FFRTMPCRYPT_PROTOCOL 0
-#define CONFIG_FFRTMPHTTP_PROTOCOL 1
-#define CONFIG_FILE_PROTOCOL 1
-#define CONFIG_FTP_PROTOCOL 1
-#define CONFIG_GOPHER_PROTOCOL 1
-#define CONFIG_HLS_PROTOCOL 1
-#define CONFIG_HTTP_PROTOCOL 1
-#define CONFIG_HTTPPROXY_PROTOCOL 1
-#define CONFIG_HTTPS_PROTOCOL 0
-#define CONFIG_ICECAST_PROTOCOL 1
-#define CONFIG_MMSH_PROTOCOL 1
-#define CONFIG_MMST_PROTOCOL 1
-#define CONFIG_MD5_PROTOCOL 1
-#define CONFIG_PIPE_PROTOCOL 1
-#define CONFIG_RTMP_PROTOCOL 1
-#define CONFIG_RTMPE_PROTOCOL 0
-#define CONFIG_RTMPS_PROTOCOL 0
-#define CONFIG_RTMPT_PROTOCOL 1
-#define CONFIG_RTMPTE_PROTOCOL 0
-#define CONFIG_RTMPTS_PROTOCOL 0
-#define CONFIG_RTP_PROTOCOL 1
-#define CONFIG_SCTP_PROTOCOL 0
-#define CONFIG_SRTP_PROTOCOL 1
-#define CONFIG_SUBFILE_PROTOCOL 1
-#define CONFIG_TEE_PROTOCOL 1
-#define CONFIG_TCP_PROTOCOL 1
-#define CONFIG_TLS_GNUTLS_PROTOCOL 0
-#define CONFIG_TLS_SCHANNEL_PROTOCOL 0
-#define CONFIG_TLS_SECURETRANSPORT_PROTOCOL 0
-#define CONFIG_TLS_OPENSSL_PROTOCOL 0
-#define CONFIG_UDP_PROTOCOL 1
-#define CONFIG_UDPLITE_PROTOCOL 1
-#define CONFIG_UNIX_PROTOCOL 1
-#define CONFIG_LIBRTMP_PROTOCOL 0
-#define CONFIG_LIBRTMPE_PROTOCOL 0
-#define CONFIG_LIBRTMPS_PROTOCOL 0
-#define CONFIG_LIBRTMPT_PROTOCOL 0
-#define CONFIG_LIBRTMPTE_PROTOCOL 0
-#define CONFIG_LIBSSH_PROTOCOL 0
-#define CONFIG_LIBSMBCLIENT_PROTOCOL 0
#endif /* FFMPEG_CONFIG_H */
diff --git a/app/src/main/cpp/ffmpeg/ffmpeg.c b/app/src/main/cpp/ffmpeg/ffmpeg.c
index 4dfb092d..f2a04992 100644
--- a/app/src/main/cpp/ffmpeg/ffmpeg.c
+++ b/app/src/main/cpp/ffmpeg/ffmpeg.c
@@ -30,6 +30,7 @@
#include
#include
#include
+#include
#include
#if HAVE_IO_H
@@ -40,16 +41,17 @@
#endif
#include "libavformat/avformat.h"
-#include "libavdevice/avdevice.h"
#include "libswresample/swresample.h"
#include "libavutil/opt.h"
#include "libavutil/channel_layout.h"
#include "libavutil/parseutils.h"
#include "libavutil/samplefmt.h"
#include "libavutil/fifo.h"
+#include "libavutil/hwcontext.h"
#include "libavutil/internal.h"
#include "libavutil/intreadwrite.h"
#include "libavutil/dict.h"
+#include "libavutil/display.h"
#include "libavutil/mathematics.h"
#include "libavutil/pixdesc.h"
#include "libavutil/avstring.h"
@@ -58,8 +60,10 @@
#include "libavutil/timestamp.h"
#include "libavutil/bprint.h"
#include "libavutil/time.h"
+#include "libavutil/thread.h"
#include "libavutil/threadmessage.h"
#include "libavcodec/mathops.h"
+#include "libavcodec/version.h"
#include "libavformat/os_support.h"
# include "libavfilter/avfilter.h"
@@ -95,52 +99,52 @@
#include
#endif
-#if HAVE_PTHREADS
-#include
-#endif
-
#include
#include "ffmpeg.h"
#include "cmdutils.h"
+#include "sync_queue.h"
#include "libavutil/avassert.h"
+jmp_buf jump_buf;
+int cancel_execute = 0;
+
const char program_name[] = "ffmpeg";
const int program_birth_year = 2000;
static FILE *vstats_file;
-const char *const forced_keyframes_const_names[] = {
- "n",
- "n_forced",
- "prev_forced_n",
- "prev_forced_t",
- "t",
- NULL
-};
-
-static void do_video_stats(OutputStream *ost, int frame_size);
-static int64_t getutime(void);
+// optionally attached as opaque_ref to decoded AVFrames
+typedef struct FrameData {
+ uint64_t idx;
+ int64_t pts;
+ AVRational tb;
+} FrameData;
+
+typedef struct BenchmarkTimeStamps {
+ int64_t real_usec;
+ int64_t user_usec;
+ int64_t sys_usec;
+} BenchmarkTimeStamps;
+
+static int trigger_fix_sub_duration_heartbeat(OutputStream *ost, const AVPacket *pkt);
+static BenchmarkTimeStamps get_benchmark_time_stamps(void);
static int64_t getmaxrss(void);
+static int ifilter_has_all_input_formats(FilterGraph *fg);
-static int run_as_daemon = 0;
-static int nb_frames_dup = 0;
-static int nb_frames_drop = 0;
+static int64_t nb_frames_dup = 0;
+static uint64_t dup_warning = 1000;
+static int64_t nb_frames_drop = 0;
static int64_t decode_error_stat[2];
+unsigned nb_output_dumped = 0;
-static int current_time;
+static BenchmarkTimeStamps current_time;
AVIOContext *progress_avio = NULL;
-static uint8_t *subtitle_out;
-
-InputStream **input_streams = NULL;
-int nb_input_streams = 0;
InputFile **input_files = NULL;
int nb_input_files = 0;
-OutputStream **output_streams = NULL;
-int nb_output_streams = 0;
OutputFile **output_files = NULL;
int nb_output_files = 0;
@@ -154,10 +158,6 @@ static struct termios oldtty;
static int restore_tty;
#endif
-#if HAVE_PTHREADS
-static void free_input_threads(void);
-#endif
-
/* sub2video hack:
Convert subtitles to video with alpha to insert them in filter graphs.
This is a temporary solution until libavfilter gets real subtitles support.
@@ -172,7 +172,7 @@ static int sub2video_get_blank_frame(InputStream *ist)
ist->sub2video.frame->width = ist->dec_ctx->width ? ist->dec_ctx->width : ist->sub2video.w;
ist->sub2video.frame->height = ist->dec_ctx->height ? ist->dec_ctx->height : ist->sub2video.h;
ist->sub2video.frame->format = AV_PIX_FMT_RGB32;
- if ((ret = av_frame_get_buffer(frame, 32)) < 0)
+ if ((ret = av_frame_get_buffer(frame, 0)) < 0)
return ret;
memset(frame->data[0], 0, frame->height * frame->linesize[0]);
return 0;
@@ -197,15 +197,15 @@ static void sub2video_copy_rect(uint8_t *dst, int dst_linesize, int w, int h,
}
dst += r->y * dst_linesize + r->x * 4;
- src = r->pict.data[0];
- pal = (uint32_t *)r->pict.data[1];
+ src = r->data[0];
+ pal = (uint32_t *)r->data[1];
for (y = 0; y < r->h; y++) {
dst2 = (uint32_t *)dst;
src2 = src;
for (x = 0; x < r->w; x++)
*(dst2++) = pal[*(src2++)];
dst += dst_linesize;
- src += r->pict.linesize[0];
+ src += r->linesize[0];
}
}
@@ -213,16 +213,21 @@ static void sub2video_push_ref(InputStream *ist, int64_t pts)
{
AVFrame *frame = ist->sub2video.frame;
int i;
+ int ret;
av_assert1(frame->data[0]);
ist->sub2video.last_pts = frame->pts = pts;
- for (i = 0; i < ist->nb_filters; i++)
- av_buffersrc_add_frame_flags(ist->filters[i]->filter, frame,
- AV_BUFFERSRC_FLAG_KEEP_REF |
- AV_BUFFERSRC_FLAG_PUSH);
+ for (i = 0; i < ist->nb_filters; i++) {
+ ret = av_buffersrc_add_frame_flags(ist->filters[i]->filter, frame,
+ AV_BUFFERSRC_FLAG_KEEP_REF |
+ AV_BUFFERSRC_FLAG_PUSH);
+ if (ret != AVERROR_EOF && ret < 0)
+ av_log(NULL, AV_LOG_WARNING, "Error while add the frame to buffer source(%s).\n",
+ av_err2str(ret));
+ }
}
-static void sub2video_update(InputStream *ist, AVSubtitle *sub)
+void sub2video_update(InputStream *ist, int64_t heartbeat_pts, AVSubtitle *sub)
{
AVFrame *frame = ist->sub2video.frame;
int8_t *dst;
@@ -239,12 +244,17 @@ static void sub2video_update(InputStream *ist, AVSubtitle *sub)
AV_TIME_BASE_Q, ist->st->time_base);
num_rects = sub->num_rects;
} else {
- pts = ist->sub2video.end_pts;
+ /* If we are initializing the system, utilize current heartbeat
+ PTS as the start time, and show until the following subpicture
+ is received. Otherwise, utilize the previous subpicture's end time
+ as the fall-back value. */
+ pts = ist->sub2video.initialize ?
+ heartbeat_pts : ist->sub2video.end_pts;
end_pts = INT64_MAX;
num_rects = 0;
}
if (sub2video_get_blank_frame(ist) < 0) {
- av_log(ist->dec_ctx, AV_LOG_ERROR,
+ av_log(NULL, AV_LOG_ERROR,
"Impossible to get a blank canvas.\n");
return;
}
@@ -254,6 +264,7 @@ static void sub2video_update(InputStream *ist, AVSubtitle *sub)
sub2video_copy_rect(dst, dst_linesize, frame->width, frame->height, sub->rects[i]);
sub2video_push_ref(ist, pts);
ist->sub2video.end_pts = end_pts;
+ ist->sub2video.initialize = 0;
}
static void sub2video_heartbeat(InputStream *ist, int64_t pts)
@@ -267,7 +278,7 @@ static void sub2video_heartbeat(InputStream *ist, int64_t pts)
video frames could be accumulating in the filter graph while a filter
(possibly overlay) is desperately waiting for a subtitle frame. */
for (i = 0; i < infile->nb_streams; i++) {
- InputStream *ist2 = input_streams[infile->ist_index + i];
+ InputStream *ist2 = infile->streams[i];
if (!ist2->sub2video.frame)
continue;
/* subtitles seem to be usually muxed ahead of other streams;
@@ -276,8 +287,11 @@ static void sub2video_heartbeat(InputStream *ist, int64_t pts)
/* do not send the heartbeat frame if the subtitle is already ahead */
if (pts2 <= ist2->sub2video.last_pts)
continue;
- if (pts2 >= ist2->sub2video.end_pts || !ist2->sub2video.frame->data[0])
- sub2video_update(ist2, NULL);
+ if (pts2 >= ist2->sub2video.end_pts || ist2->sub2video.initialize)
+ /* if we have hit the end of the current displayed subpicture,
+ or if we need to initialize the system, update the
+ overlayed subpicture and its start/end times */
+ sub2video_update(ist2, pts2 + 1, NULL);
for (j = 0, nb_reqs = 0; j < ist2->nb_filters; j++)
nb_reqs += av_buffersrc_get_nb_failed_requests(ist2->filters[j]->filter);
if (nb_reqs)
@@ -288,11 +302,15 @@ static void sub2video_heartbeat(InputStream *ist, int64_t pts)
static void sub2video_flush(InputStream *ist)
{
int i;
+ int ret;
if (ist->sub2video.end_pts < INT64_MAX)
- sub2video_update(ist, NULL);
- for (i = 0; i < ist->nb_filters; i++)
- av_buffersrc_add_frame(ist->filters[i]->filter, NULL);
+ sub2video_update(ist, INT64_MAX, NULL);
+ for (i = 0; i < ist->nb_filters; i++) {
+ ret = av_buffersrc_add_frame(ist->filters[i]->filter, NULL);
+ if (ret != AVERROR_EOF && ret < 0)
+ av_log(NULL, AV_LOG_WARNING, "Flush the frame error.\n");
+ }
}
/* end of sub2video hack */
@@ -313,20 +331,22 @@ void term_exit(void)
static volatile int received_sigterm = 0;
static volatile int received_nb_signals = 0;
-static volatile int transcode_init_done = 0;
+static atomic_int transcode_init_done = ATOMIC_VAR_INIT(0);
static volatile int ffmpeg_exited = 0;
-static int main_return_code = 0;
+int main_return_code = 0;
+static int64_t copy_ts_first_pts = AV_NOPTS_VALUE;
static void
sigterm_handler(int sig)
{
+ int ret;
received_sigterm = sig;
received_nb_signals++;
term_exit_sigsafe();
if(received_nb_signals > 3) {
- write(2/*STDERR_FILENO*/, "Received > 3 system signals, hard exiting\n",
- strlen("Received > 3 system signals, hard exiting\n"));
-
+ ret = write(2/*STDERR_FILENO*/, "Received > 3 system signals, hard exiting\n",
+ strlen("Received > 3 system signals, hard exiting\n"));
+ if (ret < 0) { /* Do nothing */ };
exit(123);
}
}
@@ -363,10 +383,32 @@ static BOOL WINAPI CtrlHandler(DWORD fdwCtrlType)
}
#endif
+#ifdef __linux__
+#define SIGNAL(sig, func) \
+ do { \
+ action.sa_handler = func; \
+ sigaction(sig, &action, NULL); \
+ } while (0)
+#else
+#define SIGNAL(sig, func) \
+ signal(sig, func)
+#endif
+
void term_init(void)
{
+#if defined __linux__
+ struct sigaction action = {0};
+ action.sa_handler = sigterm_handler;
+
+ /* block other interrupts while processing this one */
+ sigfillset(&action.sa_mask);
+
+ /* restart interruptible functions (i.e. don't fail with EINTR) */
+ action.sa_flags = SA_RESTART;
+#endif
+
#if HAVE_TERMIOS_H
- if(!run_as_daemon){
+ if (stdin_interaction) {
struct termios tty;
if (tcgetattr (0, &tty) == 0) {
oldtty = tty;
@@ -383,14 +425,17 @@ void term_init(void)
tcsetattr (0, TCSANOW, &tty);
}
- signal(SIGQUIT, sigterm_handler); /* Quit (POSIX). */
+ SIGNAL(SIGQUIT, sigterm_handler); /* Quit (POSIX). */
}
#endif
- signal(SIGINT , sigterm_handler); /* Interrupt (ANSI). */
- signal(SIGTERM, sigterm_handler); /* Termination (ANSI). */
+ SIGNAL(SIGINT , sigterm_handler); /* Interrupt (ANSI). */
+ SIGNAL(SIGTERM, sigterm_handler); /* Termination (ANSI). */
#ifdef SIGXCPU
- signal(SIGXCPU, sigterm_handler);
+ SIGNAL(SIGXCPU, sigterm_handler);
+#endif
+#ifdef SIGPIPE
+ signal(SIGPIPE, SIG_IGN); /* Broken pipe (POSIX). */
#endif
#if HAVE_SETCONSOLECTRLHANDLER
SetConsoleCtrlHandler((PHANDLER_ROUTINE) CtrlHandler, TRUE);
@@ -451,7 +496,7 @@ static int read_key(void)
static int decode_interrupt_cb(void *ctx)
{
- return received_nb_signals > transcode_init_done;
+ return received_nb_signals > atomic_load(&transcode_init_done);
}
const AVIOInterruptCB int_cb = { decode_interrupt_cb, NULL };
@@ -469,12 +514,33 @@ static void ffmpeg_cleanup(int ret)
FilterGraph *fg = filtergraphs[i];
avfilter_graph_free(&fg->graph);
for (j = 0; j < fg->nb_inputs; j++) {
- av_freep(&fg->inputs[j]->name);
+ InputFilter *ifilter = fg->inputs[j];
+ struct InputStream *ist = ifilter->ist;
+
+ if (ifilter->frame_queue) {
+ AVFrame *frame;
+ while (av_fifo_read(ifilter->frame_queue, &frame, 1) >= 0)
+ av_frame_free(&frame);
+ av_fifo_freep2(&ifilter->frame_queue);
+ }
+ av_freep(&ifilter->displaymatrix);
+ if (ist->sub2video.sub_queue) {
+ AVSubtitle sub;
+ while (av_fifo_read(ist->sub2video.sub_queue, &sub, 1) >= 0)
+ avsubtitle_free(&sub);
+ av_fifo_freep2(&ist->sub2video.sub_queue);
+ }
+ av_buffer_unref(&ifilter->hw_frames_ctx);
+ av_freep(&ifilter->name);
av_freep(&fg->inputs[j]);
}
av_freep(&fg->inputs);
for (j = 0; j < fg->nb_outputs; j++) {
- av_freep(&fg->outputs[j]->name);
+ OutputFilter *ofilter = fg->outputs[j];
+
+ avfilter_inout_free(&ofilter->out_tmp);
+ av_freep(&ofilter->name);
+ av_channel_layout_uninit(&ofilter->ch_layout);
av_freep(&fg->outputs[j]);
}
av_freep(&fg->outputs);
@@ -484,77 +550,12 @@ static void ffmpeg_cleanup(int ret)
}
av_freep(&filtergraphs);
- av_freep(&subtitle_out);
-
/* close files */
- for (i = 0; i < nb_output_files; i++) {
- OutputFile *of = output_files[i];
- AVFormatContext *s;
- if (!of)
- continue;
- s = of->ctx;
- if (s && s->oformat && !(s->oformat->flags & AVFMT_NOFILE))
- avio_closep(&s->pb);
- avformat_free_context(s);
- av_dict_free(&of->opts);
-
- av_freep(&output_files[i]);
- }
- for (i = 0; i < nb_output_streams; i++) {
- OutputStream *ost = output_streams[i];
- AVBitStreamFilterContext *bsfc;
-
- if (!ost)
- continue;
-
- bsfc = ost->bitstream_filters;
- while (bsfc) {
- AVBitStreamFilterContext *next = bsfc->next;
- av_bitstream_filter_close(bsfc);
- bsfc = next;
- }
- ost->bitstream_filters = NULL;
- av_frame_free(&ost->filtered_frame);
- av_frame_free(&ost->last_frame);
-
- av_parser_close(ost->parser);
-
- av_freep(&ost->forced_keyframes);
- av_expr_free(ost->forced_keyframes_pexpr);
- av_freep(&ost->avfilter);
- av_freep(&ost->logfile_prefix);
-
- av_freep(&ost->audio_channels_map);
- ost->audio_channels_mapped = 0;
-
- av_dict_free(&ost->sws_dict);
-
- avcodec_free_context(&ost->enc_ctx);
-
- av_freep(&output_streams[i]);
- }
-#if HAVE_PTHREADS
- free_input_threads();
-#endif
- for (i = 0; i < nb_input_files; i++) {
- avformat_close_input(&input_files[i]->ctx);
- av_freep(&input_files[i]);
- }
- for (i = 0; i < nb_input_streams; i++) {
- InputStream *ist = input_streams[i];
-
- av_frame_free(&ist->decoded_frame);
- av_frame_free(&ist->filter_frame);
- av_dict_free(&ist->decoder_opts);
- avsubtitle_free(&ist->prev_sub.subtitle);
- av_frame_free(&ist->sub2video.frame);
- av_freep(&ist->filters);
- av_freep(&ist->hwaccel_device);
+ for (i = 0; i < nb_output_files; i++)
+ of_close(&output_files[i]);
- avcodec_free_context(&ist->dec_ctx);
-
- av_freep(&input_streams[i]);
- }
+ for (i = 0; i < nb_input_files; i++)
+ ifile_close(&input_files[i]);
if (vstats_file) {
if (fclose(vstats_file))
@@ -563,10 +564,11 @@ static void ffmpeg_cleanup(int ret)
av_err2str(AVERROR(errno)));
}
av_freep(&vstats_filename);
+ of_enc_stats_close();
+
+ av_freep(&filter_nbthreads);
- av_freep(&input_streams);
av_freep(&input_files);
- av_freep(&output_streams);
av_freep(&output_files);
uninit_opts();
@@ -576,43 +578,71 @@ static void ffmpeg_cleanup(int ret)
if (received_sigterm) {
av_log(NULL, AV_LOG_INFO, "Exiting normally, received signal %d.\n",
(int) received_sigterm);
- } else if (ret && transcode_init_done) {
+ } else if (ret && atomic_load(&transcode_init_done)) {
av_log(NULL, AV_LOG_INFO, "Conversion failed!\n");
}
term_exit();
- ffmpeg_exited = 1;
- filtergraphs = NULL;
- nb_filtergraphs = 0;
- output_files = NULL;
+ nb_input_files = 0;
nb_output_files = 0;
- output_streams = NULL;
- nb_output_streams = 0;
- input_files = NULL;
- nb_input_files = 0;
- input_streams = NULL;
- nb_input_streams = 0;
+ nb_filtergraphs = 0;
+
+ ffmpeg_exited = 1;
+}
+
+/* iterate over all output streams in all output files;
+ * pass NULL to start iteration */
+static OutputStream *ost_iter(OutputStream *prev)
+{
+ int of_idx = prev ? prev->file_index : 0;
+ int ost_idx = prev ? prev->index + 1 : 0;
+
+ for (; of_idx < nb_output_files; of_idx++) {
+ OutputFile *of = output_files[of_idx];
+ if (ost_idx < of->nb_streams)
+ return of->streams[ost_idx];
+
+ ost_idx = 0;
+ }
+
+ return NULL;
+}
+
+InputStream *ist_iter(InputStream *prev)
+{
+ int if_idx = prev ? prev->file_index : 0;
+ int ist_idx = prev ? prev->st->index + 1 : 0;
+
+ for (; if_idx < nb_input_files; if_idx++) {
+ InputFile *f = input_files[if_idx];
+ if (ist_idx < f->nb_streams)
+ return f->streams[ist_idx];
+
+ ist_idx = 0;
+ }
+
+ return NULL;
}
void remove_avoptions(AVDictionary **a, AVDictionary *b)
{
- AVDictionaryEntry *t = NULL;
+ const AVDictionaryEntry *t = NULL;
- while ((t = av_dict_get(b, "", t, AV_DICT_IGNORE_SUFFIX))) {
+ while ((t = av_dict_iterate(b, t))) {
av_dict_set(a, t->key, NULL, AV_DICT_MATCH_CASE);
}
}
void assert_avoptions(AVDictionary *m)
{
- AVDictionaryEntry *t;
+ const AVDictionaryEntry *t;
if ((t = av_dict_get(m, "", NULL, AV_DICT_IGNORE_SUFFIX))) {
av_log(NULL, AV_LOG_FATAL, "Option %s not found.\n", t->key);
exit_program(1);
}
}
-static void abort_codec_experimental(AVCodec *c, int encoder)
+static void abort_codec_experimental(const AVCodec *c, int encoder)
{
exit_program(1);
}
@@ -620,7 +650,7 @@ static void abort_codec_experimental(AVCodec *c, int encoder)
static void update_benchmark(const char *fmt, ...)
{
if (do_benchmark_all) {
- int64_t t = getutime();
+ BenchmarkTimeStamps t = get_benchmark_time_stamps();
va_list va;
char buf[1024];
@@ -628,231 +658,415 @@ static void update_benchmark(const char *fmt, ...)
va_start(va, fmt);
vsnprintf(buf, sizeof(buf), fmt, va);
va_end(va);
- av_log(NULL, AV_LOG_INFO, "bench: %8"PRIu64" %s \n", t - current_time, buf);
+ av_log(NULL, AV_LOG_INFO,
+ "bench: %8" PRIu64 " user %8" PRIu64 " sys %8" PRIu64 " real %s \n",
+ t.user_usec - current_time.user_usec,
+ t.sys_usec - current_time.sys_usec,
+ t.real_usec - current_time.real_usec, buf);
}
current_time = t;
}
}
-static void close_all_output_streams(OutputStream *ost, OSTFinished this_stream, OSTFinished others)
+static void close_output_stream(OutputStream *ost)
{
- int i;
- for (i = 0; i < nb_output_streams; i++) {
- OutputStream *ost2 = output_streams[i];
- ost2->finished |= ost == ost2 ? this_stream : others;
+ OutputFile *of = output_files[ost->file_index];
+ ost->finished |= ENCODER_FINISHED;
+
+ if (ost->sq_idx_encode >= 0)
+ sq_send(of->sq_encode, ost->sq_idx_encode, SQFRAME(NULL));
+}
+
+static int check_recording_time(OutputStream *ost, int64_t ts, AVRational tb)
+{
+ OutputFile *of = output_files[ost->file_index];
+
+ if (of->recording_time != INT64_MAX &&
+ av_compare_ts(ts, tb, of->recording_time, AV_TIME_BASE_Q) >= 0) {
+ close_output_stream(ost);
+ return 0;
}
+ return 1;
}
-static void write_frame(AVFormatContext *s, AVPacket *pkt, OutputStream *ost)
+static double adjust_frame_pts_to_encoder_tb(OutputFile *of, OutputStream *ost,
+ AVFrame *frame)
{
- AVBitStreamFilterContext *bsfc = ost->bitstream_filters;
- AVCodecContext *avctx = ost->encoding_needed ? ost->enc_ctx : ost->st->codec;
- int ret;
+ double float_pts = AV_NOPTS_VALUE; // this is identical to frame.pts but with higher precision
+ const int64_t start_time = (of->start_time == AV_NOPTS_VALUE) ?
+ 0 : of->start_time;
- if (!ost->st->codec->extradata_size && ost->enc_ctx->extradata_size) {
- ost->st->codec->extradata = av_mallocz(ost->enc_ctx->extradata_size + AV_INPUT_BUFFER_PADDING_SIZE);
- if (ost->st->codec->extradata) {
- memcpy(ost->st->codec->extradata, ost->enc_ctx->extradata, ost->enc_ctx->extradata_size);
- ost->st->codec->extradata_size = ost->enc_ctx->extradata_size;
- }
+ AVCodecContext *const enc = ost->enc_ctx;
+
+ AVRational tb = enc->time_base;
+ AVRational filter_tb = frame->time_base;
+ const int extra_bits = av_clip(29 - av_log2(tb.den), 0, 16);
+
+ if (frame->pts == AV_NOPTS_VALUE)
+ goto early_exit;
+
+ tb.den <<= extra_bits;
+ float_pts = av_rescale_q(frame->pts, filter_tb, tb) -
+ av_rescale_q(start_time, AV_TIME_BASE_Q, tb);
+ float_pts /= 1 << extra_bits;
+ // avoid exact midoints to reduce the chance of rounding differences, this
+ // can be removed in case the fps code is changed to work with integers
+ float_pts += FFSIGN(float_pts) * 1.0 / (1<<17);
+
+ frame->pts = av_rescale_q(frame->pts, filter_tb, enc->time_base) -
+ av_rescale_q(start_time, AV_TIME_BASE_Q, enc->time_base);
+ frame->time_base = enc->time_base;
+
+early_exit:
+
+ if (debug_ts) {
+ av_log(NULL, AV_LOG_INFO, "filter -> pts:%s pts_time:%s exact:%f time_base:%d/%d\n",
+ frame ? av_ts2str(frame->pts) : "NULL",
+ (enc && frame) ? av_ts2timestr(frame->pts, &enc->time_base) : "NULL",
+ float_pts,
+ enc ? enc->time_base.num : -1,
+ enc ? enc->time_base.den : -1);
}
- if ((avctx->codec_type == AVMEDIA_TYPE_VIDEO && video_sync_method == VSYNC_DROP) ||
- (avctx->codec_type == AVMEDIA_TYPE_AUDIO && audio_sync_method < 0))
- pkt->pts = pkt->dts = AV_NOPTS_VALUE;
+ return float_pts;
+}
- /*
- * Audio encoders may split the packets -- #frames in != #packets out.
- * But there is no reordering, so we can limit the number of output packets
- * by simply dropping them here.
- * Counting encoded video frames needs to be done separately because of
- * reordering, see do_video_out()
- */
- if (!(avctx->codec_type == AVMEDIA_TYPE_VIDEO && avctx->codec)) {
- if (ost->frame_number >= ost->max_frames) {
- av_packet_unref(pkt);
- return;
+static int init_output_stream(OutputStream *ost, AVFrame *frame,
+ char *error, int error_len);
+
+static int init_output_stream_wrapper(OutputStream *ost, AVFrame *frame,
+ unsigned int fatal)
+{
+ int ret = AVERROR_BUG;
+ char error[1024] = {0};
+
+ if (ost->initialized)
+ return 0;
+
+ ret = init_output_stream(ost, frame, error, sizeof(error));
+ if (ret < 0) {
+ av_log(ost, AV_LOG_ERROR, "Error initializing output stream: %s\n",
+ error);
+
+ if (fatal)
+ exit_program(1);
+ }
+
+ return ret;
+}
+
+static double psnr(double d)
+{
+ return -10.0 * log10(d);
+}
+
+static void update_video_stats(OutputStream *ost, const AVPacket *pkt, int write_vstats)
+{
+ const uint8_t *sd = av_packet_get_side_data(pkt, AV_PKT_DATA_QUALITY_STATS,
+ NULL);
+ AVCodecContext *enc = ost->enc_ctx;
+ int64_t frame_number;
+ double ti1, bitrate, avg_bitrate;
+
+ ost->quality = sd ? AV_RL32(sd) : -1;
+ ost->pict_type = sd ? sd[4] : AV_PICTURE_TYPE_NONE;
+
+ for (int i = 0; ierror); i++) {
+ if (sd && i < sd[5])
+ ost->error[i] = AV_RL64(sd + 8 + 8*i);
+ else
+ ost->error[i] = -1;
+ }
+
+ if (!write_vstats)
+ return;
+
+ /* this is executed just the first time update_video_stats is called */
+ if (!vstats_file) {
+ vstats_file = fopen(vstats_filename, "w");
+ if (!vstats_file) {
+ perror("fopen");
+ exit_program(1);
}
- ost->frame_number++;
}
- if (avctx->codec_type == AVMEDIA_TYPE_VIDEO) {
- int i;
- uint8_t *sd = av_packet_get_side_data(pkt, AV_PKT_DATA_QUALITY_STATS,
- NULL);
- ost->quality = sd ? AV_RL32(sd) : -1;
- ost->pict_type = sd ? sd[4] : AV_PICTURE_TYPE_NONE;
-
- for (i = 0; ierror); i++) {
- if (sd && i < sd[5])
- ost->error[i] = AV_RL64(sd + 8 + 8*i);
- else
- ost->error[i] = -1;
+
+ frame_number = ost->packets_encoded;
+ if (vstats_version <= 1) {
+ fprintf(vstats_file, "frame= %5"PRId64" q= %2.1f ", frame_number,
+ ost->quality / (float)FF_QP2LAMBDA);
+ } else {
+ fprintf(vstats_file, "out= %2d st= %2d frame= %5"PRId64" q= %2.1f ", ost->file_index, ost->index, frame_number,
+ ost->quality / (float)FF_QP2LAMBDA);
+ }
+
+ if (ost->error[0]>=0 && (enc->flags & AV_CODEC_FLAG_PSNR))
+ fprintf(vstats_file, "PSNR= %6.2f ", psnr(ost->error[0] / (enc->width * enc->height * 255.0 * 255.0)));
+
+ fprintf(vstats_file,"f_size= %6d ", pkt->size);
+ /* compute pts value */
+ ti1 = pkt->dts * av_q2d(pkt->time_base);
+ if (ti1 < 0.01)
+ ti1 = 0.01;
+
+ bitrate = (pkt->size * 8) / av_q2d(enc->time_base) / 1000.0;
+ avg_bitrate = (double)(ost->data_size_enc * 8) / ti1 / 1000.0;
+ fprintf(vstats_file, "s_size= %8.0fkB time= %0.3f br= %7.1fkbits/s avg_br= %7.1fkbits/s ",
+ (double)ost->data_size_enc / 1024, ti1, bitrate, avg_bitrate);
+ fprintf(vstats_file, "type= %c\n", av_get_picture_type_char(ost->pict_type));
+}
+
+void enc_stats_write(OutputStream *ost, EncStats *es,
+ const AVFrame *frame, const AVPacket *pkt,
+ uint64_t frame_num)
+{
+ AVIOContext *io = es->io;
+ AVRational tb = frame ? frame->time_base : pkt->time_base;
+ int64_t pts = frame ? frame->pts : pkt->pts;
+
+ AVRational tbi = (AVRational){ 0, 1};
+ int64_t ptsi = INT64_MAX;
+
+ const FrameData *fd;
+
+ if ((frame && frame->opaque_ref) || (pkt && pkt->opaque_ref)) {
+ fd = (const FrameData*)(frame ? frame->opaque_ref->data : pkt->opaque_ref->data);
+ tbi = fd->tb;
+ ptsi = fd->pts;
+ }
+
+ for (size_t i = 0; i < es->nb_components; i++) {
+ const EncStatsComponent *c = &es->components[i];
+
+ switch (c->type) {
+ case ENC_STATS_LITERAL: avio_write (io, c->str, c->str_len); continue;
+ case ENC_STATS_FILE_IDX: avio_printf(io, "%d", ost->file_index); continue;
+ case ENC_STATS_STREAM_IDX: avio_printf(io, "%d", ost->index); continue;
+ case ENC_STATS_TIMEBASE: avio_printf(io, "%d/%d", tb.num, tb.den); continue;
+ case ENC_STATS_TIMEBASE_IN: avio_printf(io, "%d/%d", tbi.num, tbi.den); continue;
+ case ENC_STATS_PTS: avio_printf(io, "%"PRId64, pts); continue;
+ case ENC_STATS_PTS_IN: avio_printf(io, "%"PRId64, ptsi); continue;
+ case ENC_STATS_PTS_TIME: avio_printf(io, "%g", pts * av_q2d(tb)); continue;
+ case ENC_STATS_PTS_TIME_IN: avio_printf(io, "%g", ptsi == INT64_MAX ?
+ INFINITY : ptsi * av_q2d(tbi)); continue;
+ case ENC_STATS_FRAME_NUM: avio_printf(io, "%"PRIu64, frame_num); continue;
+ case ENC_STATS_FRAME_NUM_IN: avio_printf(io, "%"PRIu64, fd ? fd->idx : -1); continue;
}
- if (ost->frame_rate.num && ost->is_cfr) {
- if (pkt->duration > 0)
- av_log(NULL, AV_LOG_WARNING, "Overriding packet duration by frame rate, this should not happen\n");
- pkt->duration = av_rescale_q(1, av_inv_q(ost->frame_rate),
- ost->st->time_base);
+ if (frame) {
+ switch (c->type) {
+ case ENC_STATS_SAMPLE_NUM: avio_printf(io, "%"PRIu64, ost->samples_encoded); continue;
+ case ENC_STATS_NB_SAMPLES: avio_printf(io, "%d", frame->nb_samples); continue;
+ default: av_assert0(0);
+ }
+ } else {
+ switch (c->type) {
+ case ENC_STATS_DTS: avio_printf(io, "%"PRId64, pkt->dts); continue;
+ case ENC_STATS_DTS_TIME: avio_printf(io, "%g", pkt->dts * av_q2d(tb)); continue;
+ case ENC_STATS_PKT_SIZE: avio_printf(io, "%d", pkt->size); continue;
+ case ENC_STATS_BITRATE: {
+ double duration = FFMAX(pkt->duration, 1) * av_q2d(tb);
+ avio_printf(io, "%g", 8.0 * pkt->size / duration);
+ continue;
+ }
+ case ENC_STATS_AVG_BITRATE: {
+ double duration = pkt->dts * av_q2d(tb);
+ avio_printf(io, "%g", duration > 0 ? 8.0 * ost->data_size_enc / duration : -1.);
+ continue;
+ }
+ default: av_assert0(0);
+ }
}
}
+ avio_w8(io, '\n');
+ avio_flush(io);
+}
- if (bsfc)
- av_packet_split_side_data(pkt);
+static int encode_frame(OutputFile *of, OutputStream *ost, AVFrame *frame)
+{
+ AVCodecContext *enc = ost->enc_ctx;
+ AVPacket *pkt = ost->pkt;
+ const char *type_desc = av_get_media_type_string(enc->codec_type);
+ const char *action = frame ? "encode" : "flush";
+ int ret;
- if ((ret = av_apply_bitstream_filters(avctx, pkt, bsfc)) < 0) {
- print_error("", ret);
- if (exit_on_error)
- exit_program(1);
+ if (frame) {
+ if (ost->enc_stats_pre.io)
+ enc_stats_write(ost, &ost->enc_stats_pre, frame, NULL,
+ ost->frames_encoded);
+
+ ost->frames_encoded++;
+ ost->samples_encoded += frame->nb_samples;
+
+ if (debug_ts) {
+ av_log(ost, AV_LOG_INFO, "encoder <- type:%s "
+ "frame_pts:%s frame_pts_time:%s time_base:%d/%d\n",
+ type_desc,
+ av_ts2str(frame->pts), av_ts2timestr(frame->pts, &enc->time_base),
+ enc->time_base.num, enc->time_base.den);
+ }
+ }
+
+ update_benchmark(NULL);
+
+ ret = avcodec_send_frame(enc, frame);
+ if (ret < 0 && !(ret == AVERROR_EOF && !frame)) {
+ av_log(ost, AV_LOG_ERROR, "Error submitting %s frame to the encoder\n",
+ type_desc);
+ return ret;
}
- if (!(s->oformat->flags & AVFMT_NOTIMESTAMPS)) {
- if (pkt->dts != AV_NOPTS_VALUE &&
- pkt->pts != AV_NOPTS_VALUE &&
- pkt->dts > pkt->pts) {
- av_log(s, AV_LOG_WARNING, "Invalid DTS: %"PRId64" PTS: %"PRId64" in output stream %d:%d, replacing by guess\n",
- pkt->dts, pkt->pts,
- ost->file_index, ost->st->index);
- pkt->pts =
- pkt->dts = pkt->pts + pkt->dts + ost->last_mux_dts + 1
- - FFMIN3(pkt->pts, pkt->dts, ost->last_mux_dts + 1)
- - FFMAX3(pkt->pts, pkt->dts, ost->last_mux_dts + 1);
+ while (1) {
+ ret = avcodec_receive_packet(enc, pkt);
+ update_benchmark("%s_%s %d.%d", action, type_desc,
+ ost->file_index, ost->index);
+
+ pkt->time_base = enc->time_base;
+
+ /* if two pass, output log on success and EOF */
+ if ((ret >= 0 || ret == AVERROR_EOF) && ost->logfile && enc->stats_out)
+ fprintf(ost->logfile, "%s", enc->stats_out);
+
+ if (ret == AVERROR(EAGAIN)) {
+ av_assert0(frame); // should never happen during flushing
+ return 0;
+ } else if (ret == AVERROR_EOF) {
+ of_output_packet(of, pkt, ost, 1);
+ return ret;
+ } else if (ret < 0) {
+ av_log(ost, AV_LOG_ERROR, "%s encoding failed\n", type_desc);
+ return ret;
+ }
+
+ if (enc->codec_type == AVMEDIA_TYPE_VIDEO)
+ update_video_stats(ost, pkt, !!vstats_filename);
+ if (ost->enc_stats_post.io)
+ enc_stats_write(ost, &ost->enc_stats_post, NULL, pkt,
+ ost->packets_encoded);
+
+ if (debug_ts) {
+ av_log(ost, AV_LOG_INFO, "encoder -> type:%s "
+ "pkt_pts:%s pkt_pts_time:%s pkt_dts:%s pkt_dts_time:%s "
+ "duration:%s duration_time:%s\n",
+ type_desc,
+ av_ts2str(pkt->pts), av_ts2timestr(pkt->pts, &enc->time_base),
+ av_ts2str(pkt->dts), av_ts2timestr(pkt->dts, &enc->time_base),
+ av_ts2str(pkt->duration), av_ts2timestr(pkt->duration, &enc->time_base));
+ }
+
+ av_packet_rescale_ts(pkt, pkt->time_base, ost->mux_timebase);
+ pkt->time_base = ost->mux_timebase;
+
+ if (debug_ts) {
+ av_log(ost, AV_LOG_INFO, "encoder -> type:%s "
+ "pkt_pts:%s pkt_pts_time:%s pkt_dts:%s pkt_dts_time:%s "
+ "duration:%s duration_time:%s\n",
+ type_desc,
+ av_ts2str(pkt->pts), av_ts2timestr(pkt->pts, &enc->time_base),
+ av_ts2str(pkt->dts), av_ts2timestr(pkt->dts, &enc->time_base),
+ av_ts2str(pkt->duration), av_ts2timestr(pkt->duration, &enc->time_base));
}
- if(
- (avctx->codec_type == AVMEDIA_TYPE_AUDIO || avctx->codec_type == AVMEDIA_TYPE_VIDEO) &&
- pkt->dts != AV_NOPTS_VALUE &&
- ost->last_mux_dts != AV_NOPTS_VALUE) {
- int64_t max = ost->last_mux_dts + !(s->oformat->flags & AVFMT_TS_NONSTRICT);
- if (pkt->dts < max) {
- int loglevel = max - pkt->dts > 2 || avctx->codec_type == AVMEDIA_TYPE_VIDEO ? AV_LOG_WARNING : AV_LOG_DEBUG;
- av_log(s, loglevel, "Non-monotonous DTS in output stream "
- "%d:%d; previous: %"PRId64", current: %"PRId64"; ",
- ost->file_index, ost->st->index, ost->last_mux_dts, pkt->dts);
- if (exit_on_error) {
- av_log(NULL, AV_LOG_FATAL, "aborting.\n");
+
+ if ((ret = trigger_fix_sub_duration_heartbeat(ost, pkt)) < 0) {
+ av_log(NULL, AV_LOG_ERROR,
+ "Subtitle heartbeat logic failed in %s! (%s)\n",
+ __func__, av_err2str(ret));
exit_program(1);
}
- av_log(s, loglevel, "changing to %"PRId64". This may result "
- "in incorrect timestamps in the output file.\n",
- max);
- if(pkt->pts >= pkt->dts)
- pkt->pts = FFMAX(pkt->pts, max);
- pkt->dts = max;
- }
- }
- }
- ost->last_mux_dts = pkt->dts;
- ost->data_size += pkt->size;
- ost->packets_written++;
+ ost->data_size_enc += pkt->size;
- pkt->stream_index = ost->index;
+ ost->packets_encoded++;
- if (debug_ts) {
- av_log(NULL, AV_LOG_INFO, "muxer <- type:%s "
- "pkt_pts:%s pkt_pts_time:%s pkt_dts:%s pkt_dts_time:%s size:%d\n",
- av_get_media_type_string(ost->enc_ctx->codec_type),
- av_ts2str(pkt->pts), av_ts2timestr(pkt->pts, &ost->st->time_base),
- av_ts2str(pkt->dts), av_ts2timestr(pkt->dts, &ost->st->time_base),
- pkt->size
- );
+ of_output_packet(of, pkt, ost, 0);
}
- ret = av_interleaved_write_frame(s, pkt);
- if (ret < 0) {
- print_error("av_interleaved_write_frame()", ret);
- main_return_code = 1;
- close_all_output_streams(ost, MUXER_FINISHED | ENCODER_FINISHED, ENCODER_FINISHED);
- }
- av_packet_unref(pkt);
+ av_assert0(0);
}
-static void close_output_stream(OutputStream *ost)
+static int submit_encode_frame(OutputFile *of, OutputStream *ost,
+ AVFrame *frame)
{
- OutputFile *of = output_files[ost->file_index];
+ int ret;
- ost->finished |= ENCODER_FINISHED;
- if (of->shortest) {
- int64_t end = av_rescale_q(ost->sync_opts - ost->first_pts, ost->enc_ctx->time_base, AV_TIME_BASE_Q);
- of->recording_time = FFMIN(of->recording_time, end);
+ if (ost->sq_idx_encode < 0)
+ return encode_frame(of, ost, frame);
+
+ if (frame) {
+ ret = av_frame_ref(ost->sq_frame, frame);
+ if (ret < 0)
+ return ret;
+ frame = ost->sq_frame;
}
-}
-static int check_recording_time(OutputStream *ost)
-{
- OutputFile *of = output_files[ost->file_index];
+ ret = sq_send(of->sq_encode, ost->sq_idx_encode,
+ SQFRAME(frame));
+ if (ret < 0) {
+ if (frame)
+ av_frame_unref(frame);
+ if (ret != AVERROR_EOF)
+ return ret;
+ }
- if (of->recording_time != INT64_MAX &&
- av_compare_ts(ost->sync_opts - ost->first_pts, ost->enc_ctx->time_base, of->recording_time,
- AV_TIME_BASE_Q) >= 0) {
- close_output_stream(ost);
- return 0;
+ while (1) {
+ AVFrame *enc_frame = ost->sq_frame;
+
+ ret = sq_receive(of->sq_encode, ost->sq_idx_encode,
+ SQFRAME(enc_frame));
+ if (ret == AVERROR_EOF) {
+ enc_frame = NULL;
+ } else if (ret < 0) {
+ return (ret == AVERROR(EAGAIN)) ? 0 : ret;
+ }
+
+ ret = encode_frame(of, ost, enc_frame);
+ if (enc_frame)
+ av_frame_unref(enc_frame);
+ if (ret < 0) {
+ if (ret == AVERROR_EOF)
+ close_output_stream(ost);
+ return ret;
+ }
}
- return 1;
}
-static void do_audio_out(AVFormatContext *s, OutputStream *ost,
+static void do_audio_out(OutputFile *of, OutputStream *ost,
AVFrame *frame)
{
AVCodecContext *enc = ost->enc_ctx;
- AVPacket pkt;
- int got_packet = 0;
+ int ret;
- av_init_packet(&pkt);
- pkt.data = NULL;
- pkt.size = 0;
+ if (frame->pts == AV_NOPTS_VALUE)
+ frame->pts = ost->next_pts;
+ else {
+ int64_t start_time = (of->start_time == AV_NOPTS_VALUE) ? 0 : of->start_time;
+ frame->pts =
+ av_rescale_q(frame->pts, frame->time_base, enc->time_base) -
+ av_rescale_q(start_time, AV_TIME_BASE_Q, enc->time_base);
+ }
+ frame->time_base = enc->time_base;
- if (!check_recording_time(ost))
+ if (!check_recording_time(ost, frame->pts, frame->time_base))
return;
- if (frame->pts == AV_NOPTS_VALUE || audio_sync_method < 0)
- frame->pts = ost->sync_opts;
- ost->sync_opts = frame->pts + frame->nb_samples;
- ost->samples_encoded += frame->nb_samples;
- ost->frames_encoded++;
+ ost->next_pts = frame->pts + frame->nb_samples;
- av_assert0(pkt.size || !pkt.data);
- update_benchmark(NULL);
- if (debug_ts) {
- av_log(NULL, AV_LOG_INFO, "encoder <- type:audio "
- "frame_pts:%s frame_pts_time:%s time_base:%d/%d\n",
- av_ts2str(frame->pts), av_ts2timestr(frame->pts, &enc->time_base),
- enc->time_base.num, enc->time_base.den);
- }
-
- if (avcodec_encode_audio2(enc, &pkt, frame, &got_packet) < 0) {
- av_log(NULL, AV_LOG_FATAL, "Audio encoding failed (avcodec_encode_audio2)\n");
+ ret = submit_encode_frame(of, ost, frame);
+ if (ret < 0 && ret != AVERROR_EOF)
exit_program(1);
- }
- update_benchmark("encode_audio %d.%d", ost->file_index, ost->index);
-
- if (got_packet) {
- av_packet_rescale_ts(&pkt, enc->time_base, ost->st->time_base);
-
- if (debug_ts) {
- av_log(NULL, AV_LOG_INFO, "encoder -> type:audio "
- "pkt_pts:%s pkt_pts_time:%s pkt_dts:%s pkt_dts_time:%s\n",
- av_ts2str(pkt.pts), av_ts2timestr(pkt.pts, &ost->st->time_base),
- av_ts2str(pkt.dts), av_ts2timestr(pkt.dts, &ost->st->time_base));
- }
-
- write_frame(s, &pkt, ost);
- }
}
-static void do_subtitle_out(AVFormatContext *s,
+static void do_subtitle_out(OutputFile *of,
OutputStream *ost,
- InputStream *ist,
AVSubtitle *sub)
{
int subtitle_out_max_size = 1024 * 1024;
- int subtitle_out_size, nb, i;
+ int subtitle_out_size, nb, i, ret;
AVCodecContext *enc;
- AVPacket pkt;
+ AVPacket *pkt = ost->pkt;
int64_t pts;
if (sub->pts == AV_NOPTS_VALUE) {
- av_log(NULL, AV_LOG_ERROR, "Subtitle packets must have a pts\n");
+ av_log(ost, AV_LOG_ERROR, "Subtitle packets must have a pts\n");
if (exit_on_error)
exit_program(1);
return;
@@ -860,14 +1074,6 @@ static void do_subtitle_out(AVFormatContext *s,
enc = ost->enc_ctx;
- if (!subtitle_out) {
- subtitle_out = av_malloc(subtitle_out_max_size);
- if (!subtitle_out) {
- av_log(NULL, AV_LOG_FATAL, "Failed to allocate subtitle_out\n");
- exit_program(1);
- }
- }
-
/* Note: DVB subtitle need one packet to draw them and one other
packet to clear them */
/* XXX: signal it in the codec context ? */
@@ -883,10 +1089,13 @@ static void do_subtitle_out(AVFormatContext *s,
for (i = 0; i < nb; i++) {
unsigned save_num_rects = sub->num_rects;
- ost->sync_opts = av_rescale_q(pts, AV_TIME_BASE_Q, enc->time_base);
- if (!check_recording_time(ost))
+ if (!check_recording_time(ost, pts, AV_TIME_BASE_Q))
return;
+ ret = av_new_packet(pkt, subtitle_out_max_size);
+ if (ret < 0)
+ report_and_exit(AVERROR(ENOMEM));
+
sub->pts = pts;
// start_display_time is required to be 0
sub->pts += av_rescale_q(sub->start_display_time, (AVRational){ 1, 1000 }, AV_TIME_BASE_Q);
@@ -897,392 +1106,257 @@ static void do_subtitle_out(AVFormatContext *s,
ost->frames_encoded++;
- subtitle_out_size = avcodec_encode_subtitle(enc, subtitle_out,
- subtitle_out_max_size, sub);
+ subtitle_out_size = avcodec_encode_subtitle(enc, pkt->data, pkt->size, sub);
if (i == 1)
sub->num_rects = save_num_rects;
if (subtitle_out_size < 0) {
- av_log(NULL, AV_LOG_FATAL, "Subtitle encoding failed\n");
+ av_log(ost, AV_LOG_FATAL, "Subtitle encoding failed\n");
exit_program(1);
}
- av_init_packet(&pkt);
- pkt.data = subtitle_out;
- pkt.size = subtitle_out_size;
- pkt.pts = av_rescale_q(sub->pts, AV_TIME_BASE_Q, ost->st->time_base);
- pkt.duration = av_rescale_q(sub->end_display_time, (AVRational){ 1, 1000 }, ost->st->time_base);
+ av_shrink_packet(pkt, subtitle_out_size);
+ pkt->time_base = ost->mux_timebase;
+ pkt->pts = av_rescale_q(sub->pts, AV_TIME_BASE_Q, pkt->time_base);
+ pkt->duration = av_rescale_q(sub->end_display_time, (AVRational){ 1, 1000 }, pkt->time_base);
if (enc->codec_id == AV_CODEC_ID_DVB_SUBTITLE) {
/* XXX: the pts correction is handled here. Maybe handling
it in the codec would be better */
if (i == 0)
- pkt.pts += 90 * sub->start_display_time;
+ pkt->pts += av_rescale_q(sub->start_display_time, (AVRational){ 1, 1000 }, pkt->time_base);
else
- pkt.pts += 90 * sub->end_display_time;
+ pkt->pts += av_rescale_q(sub->end_display_time, (AVRational){ 1, 1000 }, pkt->time_base);
}
- pkt.dts = pkt.pts;
- write_frame(s, &pkt, ost);
+ pkt->dts = pkt->pts;
+
+ of_output_packet(of, pkt, ost, 0);
}
}
-static void do_video_out(AVFormatContext *s,
- OutputStream *ost,
- AVFrame *next_picture,
- double sync_ipts)
+/* Convert frame timestamps to the encoder timebase and decide how many times
+ * should this (and possibly previous) frame be repeated in order to conform to
+ * desired target framerate (if any).
+ */
+static void video_sync_process(OutputFile *of, OutputStream *ost,
+ AVFrame *next_picture, double duration,
+ int64_t *nb_frames, int64_t *nb_frames_prev)
{
- int ret, format_video_sync;
- AVPacket pkt;
- AVCodecContext *enc = ost->enc_ctx;
- AVCodecContext *mux_enc = ost->st->codec;
- int nb_frames, nb0_frames, i;
- double delta, delta0;
- double duration = 0;
- int frame_size = 0;
- InputStream *ist = NULL;
- AVFilterContext *filter = ost->filter->filter;
-
- if (ost->source_index >= 0)
- ist = input_streams[ost->source_index];
-
- if (filter->inputs[0]->frame_rate.num > 0 &&
- filter->inputs[0]->frame_rate.den > 0)
- duration = 1/(av_q2d(filter->inputs[0]->frame_rate) * av_q2d(enc->time_base));
-
- if(ist && ist->st->start_time != AV_NOPTS_VALUE && ist->st->first_dts != AV_NOPTS_VALUE && ost->frame_rate.num)
- duration = FFMIN(duration, 1/(av_q2d(ost->frame_rate) * av_q2d(enc->time_base)));
+ double delta0, delta;
+
+ double sync_ipts = adjust_frame_pts_to_encoder_tb(of, ost, next_picture);
+ /* delta0 is the "drift" between the input frame (next_picture) and
+ * where it would fall in the output. */
+ delta0 = sync_ipts - ost->next_pts;
+ delta = delta0 + duration;
+
+ // tracks the number of times the PREVIOUS frame should be duplicated,
+ // mostly for variable framerate (VFR)
+ *nb_frames_prev = 0;
+ /* by default, we output a single frame */
+ *nb_frames = 1;
+
+ if (delta0 < 0 &&
+ delta > 0 &&
+ ost->vsync_method != VSYNC_PASSTHROUGH &&
+ ost->vsync_method != VSYNC_DROP) {
+ if (delta0 < -0.6) {
+ av_log(ost, AV_LOG_VERBOSE, "Past duration %f too large\n", -delta0);
+ } else
+ av_log(ost, AV_LOG_DEBUG, "Clipping frame in rate conversion by %f\n", -delta0);
+ sync_ipts = ost->next_pts;
+ duration += delta0;
+ delta0 = 0;
+ }
- if (!ost->filters_script &&
- !ost->filters &&
- next_picture &&
- ist &&
- lrintf(av_frame_get_pkt_duration(next_picture) * av_q2d(ist->st->time_base) / av_q2d(enc->time_base)) > 0) {
- duration = lrintf(av_frame_get_pkt_duration(next_picture) * av_q2d(ist->st->time_base) / av_q2d(enc->time_base));
+ switch (ost->vsync_method) {
+ case VSYNC_VSCFR:
+ if (ost->vsync_frame_number == 0 && delta0 >= 0.5) {
+ av_log(ost, AV_LOG_DEBUG, "Not duplicating %d initial frames\n", (int)lrintf(delta0));
+ delta = duration;
+ delta0 = 0;
+ ost->next_pts = llrint(sync_ipts);
+ }
+ case VSYNC_CFR:
+ // FIXME set to 0.5 after we fix some dts/pts bugs like in avidec.c
+ if (frame_drop_threshold && delta < frame_drop_threshold && ost->vsync_frame_number) {
+ *nb_frames = 0;
+ } else if (delta < -1.1)
+ *nb_frames = 0;
+ else if (delta > 1.1) {
+ *nb_frames = llrintf(delta);
+ if (delta0 > 1.1)
+ *nb_frames_prev = llrintf(delta0 - 0.6);
+ }
+ next_picture->duration = 1;
+ break;
+ case VSYNC_VFR:
+ if (delta <= -0.6)
+ *nb_frames = 0;
+ else if (delta > 0.6)
+ ost->next_pts = llrint(sync_ipts);
+ next_picture->duration = duration;
+ break;
+ case VSYNC_DROP:
+ case VSYNC_PASSTHROUGH:
+ next_picture->duration = duration;
+ ost->next_pts = llrint(sync_ipts);
+ break;
+ default:
+ av_assert0(0);
}
+}
- if (!next_picture) {
- //end, flushing
- nb0_frames = nb_frames = mid_pred(ost->last_nb0_frames[0],
- ost->last_nb0_frames[1],
- ost->last_nb0_frames[2]);
- } else {
- delta0 = sync_ipts - ost->sync_opts; // delta0 is the "drift" between the input frame (next_picture) and where it would fall in the output.
- delta = delta0 + duration;
+static enum AVPictureType forced_kf_apply(void *logctx, KeyframeForceCtx *kf,
+ AVRational tb, const AVFrame *in_picture,
+ int dup_idx)
+{
+ double pts_time;
+
+ if (kf->ref_pts == AV_NOPTS_VALUE)
+ kf->ref_pts = in_picture->pts;
+
+ pts_time = (in_picture->pts - kf->ref_pts) * av_q2d(tb);
+ if (kf->index < kf->nb_pts &&
+ av_compare_ts(in_picture->pts, tb, kf->pts[kf->index], AV_TIME_BASE_Q) >= 0) {
+ kf->index++;
+ goto force_keyframe;
+ } else if (kf->pexpr) {
+ double res;
+ kf->expr_const_values[FKF_T] = pts_time;
+ res = av_expr_eval(kf->pexpr,
+ kf->expr_const_values, NULL);
+ ff_dlog(NULL, "force_key_frame: n:%f n_forced:%f prev_forced_n:%f t:%f prev_forced_t:%f -> res:%f\n",
+ kf->expr_const_values[FKF_N],
+ kf->expr_const_values[FKF_N_FORCED],
+ kf->expr_const_values[FKF_PREV_FORCED_N],
+ kf->expr_const_values[FKF_T],
+ kf->expr_const_values[FKF_PREV_FORCED_T],
+ res);
+
+ kf->expr_const_values[FKF_N] += 1;
+
+ if (res) {
+ kf->expr_const_values[FKF_PREV_FORCED_N] = kf->expr_const_values[FKF_N] - 1;
+ kf->expr_const_values[FKF_PREV_FORCED_T] = kf->expr_const_values[FKF_T];
+ kf->expr_const_values[FKF_N_FORCED] += 1;
+ goto force_keyframe;
+ }
+ } else if (kf->type == KF_FORCE_SOURCE &&
+ in_picture->key_frame == 1 && !dup_idx) {
+ goto force_keyframe;
+ } else if (kf->type == KF_FORCE_SOURCE_NO_DROP && !dup_idx) {
+ kf->dropped_keyframe = 0;
+ if ((in_picture->key_frame == 1) || kf->dropped_keyframe)
+ goto force_keyframe;
+ }
- /* by default, we output a single frame */
- nb0_frames = 0; // tracks the number of times the PREVIOUS frame should be duplicated, mostly for variable framerate (VFR)
- nb_frames = 1;
+ return AV_PICTURE_TYPE_NONE;
- format_video_sync = video_sync_method;
- if (format_video_sync == VSYNC_AUTO) {
- if(!strcmp(s->oformat->name, "avi")) {
- format_video_sync = VSYNC_VFR;
- } else
- format_video_sync = (s->oformat->flags & AVFMT_VARIABLE_FPS) ? ((s->oformat->flags & AVFMT_NOTIMESTAMPS) ? VSYNC_PASSTHROUGH : VSYNC_VFR) : VSYNC_CFR;
- if ( ist
- && format_video_sync == VSYNC_CFR
- && input_files[ist->file_index]->ctx->nb_streams == 1
- && input_files[ist->file_index]->input_ts_offset == 0) {
- format_video_sync = VSYNC_VSCFR;
- }
- if (format_video_sync == VSYNC_CFR && copy_ts) {
- format_video_sync = VSYNC_VSCFR;
- }
- }
- ost->is_cfr = (format_video_sync == VSYNC_CFR || format_video_sync == VSYNC_VSCFR);
-
- if (delta0 < 0 &&
- delta > 0 &&
- format_video_sync != VSYNC_PASSTHROUGH &&
- format_video_sync != VSYNC_DROP) {
- if (delta0 < -0.6) {
- av_log(NULL, AV_LOG_WARNING, "Past duration %f too large\n", -delta0);
- } else
- av_log(NULL, AV_LOG_DEBUG, "Clipping frame in rate conversion by %f\n", -delta0);
- sync_ipts = ost->sync_opts;
- duration += delta0;
- delta0 = 0;
- }
+force_keyframe:
+ av_log(logctx, AV_LOG_DEBUG, "Forced keyframe at time %f\n", pts_time);
+ return AV_PICTURE_TYPE_I;
+}
- switch (format_video_sync) {
- case VSYNC_VSCFR:
- if (ost->frame_number == 0 && delta0 >= 0.5) {
- av_log(NULL, AV_LOG_DEBUG, "Not duplicating %d initial frames\n", (int)lrintf(delta0));
- delta = duration;
- delta0 = 0;
- ost->sync_opts = lrint(sync_ipts);
- }
- case VSYNC_CFR:
- // FIXME set to 0.5 after we fix some dts/pts bugs like in avidec.c
- if (frame_drop_threshold && delta < frame_drop_threshold && ost->frame_number) {
- nb_frames = 0;
- } else if (delta < -1.1)
- nb_frames = 0;
- else if (delta > 1.1) {
- nb_frames = lrintf(delta);
- if (delta0 > 1.1)
- nb0_frames = lrintf(delta0 - 0.6);
- }
- break;
- case VSYNC_VFR:
- if (delta <= -0.6)
- nb_frames = 0;
- else if (delta > 0.6)
- ost->sync_opts = lrint(sync_ipts);
- break;
- case VSYNC_DROP:
- case VSYNC_PASSTHROUGH:
- ost->sync_opts = lrint(sync_ipts);
- break;
- default:
- av_assert0(0);
- }
+/* May modify/reset next_picture */
+static void do_video_out(OutputFile *of,
+ OutputStream *ost,
+ AVFrame *next_picture)
+{
+ int ret;
+ AVCodecContext *enc = ost->enc_ctx;
+ AVRational frame_rate;
+ int64_t nb_frames, nb_frames_prev, i;
+ double duration = 0;
+ InputStream *ist = ost->ist;
+ AVFilterContext *filter = ost->filter->filter;
+
+ init_output_stream_wrapper(ost, next_picture, 1);
+
+ frame_rate = av_buffersink_get_frame_rate(filter);
+ if (frame_rate.num > 0 && frame_rate.den > 0)
+ duration = 1/(av_q2d(frame_rate) * av_q2d(enc->time_base));
+
+ if(ist && ist->st->start_time != AV_NOPTS_VALUE && ist->first_dts != AV_NOPTS_VALUE && ost->frame_rate.num)
+ duration = FFMIN(duration, 1/(av_q2d(ost->frame_rate) * av_q2d(enc->time_base)));
+
+ if (!ost->filters_script &&
+ !ost->filters &&
+ (nb_filtergraphs == 0 || !filtergraphs[0]->graph_desc) &&
+ next_picture &&
+ ist &&
+ lrintf(next_picture->duration * av_q2d(ist->st->time_base) / av_q2d(enc->time_base)) > 0) {
+ duration = lrintf(next_picture->duration * av_q2d(ist->st->time_base) / av_q2d(enc->time_base));
}
- nb_frames = FFMIN(nb_frames, ost->max_frames - ost->frame_number);
- nb0_frames = FFMIN(nb0_frames, nb_frames);
+ if (!next_picture) {
+ //end, flushing
+ nb_frames_prev = nb_frames = mid_pred(ost->last_nb0_frames[0],
+ ost->last_nb0_frames[1],
+ ost->last_nb0_frames[2]);
+ } else {
+ video_sync_process(of, ost, next_picture, duration,
+ &nb_frames, &nb_frames_prev);
+ }
memmove(ost->last_nb0_frames + 1,
ost->last_nb0_frames,
sizeof(ost->last_nb0_frames[0]) * (FF_ARRAY_ELEMS(ost->last_nb0_frames) - 1));
- ost->last_nb0_frames[0] = nb0_frames;
+ ost->last_nb0_frames[0] = nb_frames_prev;
- if (nb0_frames == 0 && ost->last_dropped) {
+ if (nb_frames_prev == 0 && ost->last_dropped) {
nb_frames_drop++;
- av_log(NULL, AV_LOG_VERBOSE,
- "*** dropping frame %d from stream %d at ts %"PRId64"\n",
- ost->frame_number, ost->st->index, ost->last_frame->pts);
+ av_log(ost, AV_LOG_VERBOSE,
+ "*** dropping frame %"PRId64" at ts %"PRId64"\n",
+ ost->vsync_frame_number, ost->last_frame->pts);
}
- if (nb_frames > (nb0_frames && ost->last_dropped) + (nb_frames > nb0_frames)) {
+ if (nb_frames > (nb_frames_prev && ost->last_dropped) + (nb_frames > nb_frames_prev)) {
if (nb_frames > dts_error_threshold * 30) {
- av_log(NULL, AV_LOG_ERROR, "%d frame duplication too large, skipping\n", nb_frames - 1);
+ av_log(ost, AV_LOG_ERROR, "%"PRId64" frame duplication too large, skipping\n", nb_frames - 1);
nb_frames_drop++;
return;
}
- nb_frames_dup += nb_frames - (nb0_frames && ost->last_dropped) - (nb_frames > nb0_frames);
- av_log(NULL, AV_LOG_VERBOSE, "*** %d dup!\n", nb_frames - 1);
+ nb_frames_dup += nb_frames - (nb_frames_prev && ost->last_dropped) - (nb_frames > nb_frames_prev);
+ av_log(ost, AV_LOG_VERBOSE, "*** %"PRId64" dup!\n", nb_frames - 1);
+ if (nb_frames_dup > dup_warning) {
+ av_log(ost, AV_LOG_WARNING, "More than %"PRIu64" frames duplicated\n", dup_warning);
+ dup_warning *= 10;
+ }
}
- ost->last_dropped = nb_frames == nb0_frames && next_picture;
-
- /* duplicates frame if needed */
- for (i = 0; i < nb_frames; i++) {
- AVFrame *in_picture;
- av_init_packet(&pkt);
- pkt.data = NULL;
- pkt.size = 0;
-
- if (i < nb0_frames && ost->last_frame) {
- in_picture = ost->last_frame;
- } else
- in_picture = next_picture;
-
- if (!in_picture)
- return;
-
- in_picture->pts = ost->sync_opts;
-
-#if 1
- if (!check_recording_time(ost))
-#else
- if (ost->frame_number >= ost->max_frames)
-#endif
- return;
-
-#if FF_API_LAVF_FMT_RAWPICTURE
- if (s->oformat->flags & AVFMT_RAWPICTURE &&
- enc->codec->id == AV_CODEC_ID_RAWVIDEO) {
- /* raw pictures are written as AVPicture structure to
- avoid any copies. We support temporarily the older
- method. */
- if (in_picture->interlaced_frame)
- mux_enc->field_order = in_picture->top_field_first ? AV_FIELD_TB:AV_FIELD_BT;
- else
- mux_enc->field_order = AV_FIELD_PROGRESSIVE;
- pkt.data = (uint8_t *)in_picture;
- pkt.size = sizeof(AVPicture);
- pkt.pts = av_rescale_q(in_picture->pts, enc->time_base, ost->st->time_base);
- pkt.flags |= AV_PKT_FLAG_KEY;
-
- write_frame(s, &pkt, ost);
- } else
-#endif
- {
- int got_packet, forced_keyframe = 0;
- double pts_time;
+ ost->last_dropped = nb_frames == nb_frames_prev && next_picture;
+ ost->kf.dropped_keyframe = ost->last_dropped && next_picture && next_picture->key_frame;
- if (enc->flags & (AV_CODEC_FLAG_INTERLACED_DCT | AV_CODEC_FLAG_INTERLACED_ME) &&
- ost->top_field_first >= 0)
- in_picture->top_field_first = !!ost->top_field_first;
+ /* duplicates frame if needed */
+ for (i = 0; i < nb_frames; i++) {
+ AVFrame *in_picture;
- if (in_picture->interlaced_frame) {
- if (enc->codec->id == AV_CODEC_ID_MJPEG)
- mux_enc->field_order = in_picture->top_field_first ? AV_FIELD_TT:AV_FIELD_BB;
- else
- mux_enc->field_order = in_picture->top_field_first ? AV_FIELD_TB:AV_FIELD_BT;
+ if (i < nb_frames_prev && ost->last_frame->buf[0]) {
+ in_picture = ost->last_frame;
} else
- mux_enc->field_order = AV_FIELD_PROGRESSIVE;
-
- in_picture->quality = enc->global_quality;
- in_picture->pict_type = 0;
-
- pts_time = in_picture->pts != AV_NOPTS_VALUE ?
- in_picture->pts * av_q2d(enc->time_base) : NAN;
- if (ost->forced_kf_index < ost->forced_kf_count &&
- in_picture->pts >= ost->forced_kf_pts[ost->forced_kf_index]) {
- ost->forced_kf_index++;
- forced_keyframe = 1;
- } else if (ost->forced_keyframes_pexpr) {
- double res;
- ost->forced_keyframes_expr_const_values[FKF_T] = pts_time;
- res = av_expr_eval(ost->forced_keyframes_pexpr,
- ost->forced_keyframes_expr_const_values, NULL);
- ff_dlog(NULL, "force_key_frame: n:%f n_forced:%f prev_forced_n:%f t:%f prev_forced_t:%f -> res:%f\n",
- ost->forced_keyframes_expr_const_values[FKF_N],
- ost->forced_keyframes_expr_const_values[FKF_N_FORCED],
- ost->forced_keyframes_expr_const_values[FKF_PREV_FORCED_N],
- ost->forced_keyframes_expr_const_values[FKF_T],
- ost->forced_keyframes_expr_const_values[FKF_PREV_FORCED_T],
- res);
- if (res) {
- forced_keyframe = 1;
- ost->forced_keyframes_expr_const_values[FKF_PREV_FORCED_N] =
- ost->forced_keyframes_expr_const_values[FKF_N];
- ost->forced_keyframes_expr_const_values[FKF_PREV_FORCED_T] =
- ost->forced_keyframes_expr_const_values[FKF_T];
- ost->forced_keyframes_expr_const_values[FKF_N_FORCED] += 1;
- }
+ in_picture = next_picture;
- ost->forced_keyframes_expr_const_values[FKF_N] += 1;
- } else if ( ost->forced_keyframes
- && !strncmp(ost->forced_keyframes, "source", 6)
- && in_picture->key_frame==1) {
- forced_keyframe = 1;
- }
+ if (!in_picture)
+ return;
- if (forced_keyframe) {
- in_picture->pict_type = AV_PICTURE_TYPE_I;
- av_log(NULL, AV_LOG_DEBUG, "Forced keyframe at time %f\n", pts_time);
- }
+ in_picture->pts = ost->next_pts;
- update_benchmark(NULL);
- if (debug_ts) {
- av_log(NULL, AV_LOG_INFO, "encoder <- type:video "
- "frame_pts:%s frame_pts_time:%s time_base:%d/%d\n",
- av_ts2str(in_picture->pts), av_ts2timestr(in_picture->pts, &enc->time_base),
- enc->time_base.num, enc->time_base.den);
- }
+ if (!check_recording_time(ost, in_picture->pts, ost->enc_ctx->time_base))
+ return;
- ost->frames_encoded++;
+ in_picture->quality = enc->global_quality;
+ in_picture->pict_type = forced_kf_apply(ost, &ost->kf, enc->time_base, in_picture, i);
- ret = avcodec_encode_video2(enc, &pkt, in_picture, &got_packet);
- update_benchmark("encode_video %d.%d", ost->file_index, ost->index);
- if (ret < 0) {
- av_log(NULL, AV_LOG_FATAL, "Video encoding failed\n");
+ ret = submit_encode_frame(of, ost, in_picture);
+ if (ret == AVERROR_EOF)
+ break;
+ else if (ret < 0)
exit_program(1);
- }
-
- if (got_packet) {
- if (debug_ts) {
- av_log(NULL, AV_LOG_INFO, "encoder -> type:video "
- "pkt_pts:%s pkt_pts_time:%s pkt_dts:%s pkt_dts_time:%s\n",
- av_ts2str(pkt.pts), av_ts2timestr(pkt.pts, &enc->time_base),
- av_ts2str(pkt.dts), av_ts2timestr(pkt.dts, &enc->time_base));
- }
-
- if (pkt.pts == AV_NOPTS_VALUE && !(enc->codec->capabilities & AV_CODEC_CAP_DELAY))
- pkt.pts = ost->sync_opts;
-
- av_packet_rescale_ts(&pkt, enc->time_base, ost->st->time_base);
-
- if (debug_ts) {
- av_log(NULL, AV_LOG_INFO, "encoder -> type:video "
- "pkt_pts:%s pkt_pts_time:%s pkt_dts:%s pkt_dts_time:%s\n",
- av_ts2str(pkt.pts), av_ts2timestr(pkt.pts, &ost->st->time_base),
- av_ts2str(pkt.dts), av_ts2timestr(pkt.dts, &ost->st->time_base));
- }
-
- frame_size = pkt.size;
- write_frame(s, &pkt, ost);
- /* if two pass, output log */
- if (ost->logfile && enc->stats_out) {
- fprintf(ost->logfile, "%s", enc->stats_out);
- }
- }
+ ost->next_pts++;
+ ost->vsync_frame_number++;
}
- ost->sync_opts++;
- /*
- * For video, number of frames in == number of packets out.
- * But there may be reordering, so we can't throw away frames on encoder
- * flush, we need to limit them here, before they go into encoder.
- */
- ost->frame_number++;
- if (vstats_filename && frame_size)
- do_video_stats(ost, frame_size);
- }
-
- if (!ost->last_frame)
- ost->last_frame = av_frame_alloc();
av_frame_unref(ost->last_frame);
- if (next_picture && ost->last_frame)
- av_frame_ref(ost->last_frame, next_picture);
- else
- av_frame_free(&ost->last_frame);
-}
-
-static double psnr(double d)
-{
- return -10.0 * log10(d);
-}
-
-static void do_video_stats(OutputStream *ost, int frame_size)
-{
- AVCodecContext *enc;
- int frame_number;
- double ti1, bitrate, avg_bitrate;
-
- /* this is executed just the first time do_video_stats is called */
- if (!vstats_file) {
- vstats_file = fopen(vstats_filename, "w");
- if (!vstats_file) {
- perror("fopen");
- exit_program(1);
- }
- }
-
- enc = ost->enc_ctx;
- if (enc->codec_type == AVMEDIA_TYPE_VIDEO) {
- frame_number = ost->st->nb_frames;
- fprintf(vstats_file, "frame= %5d q= %2.1f ", frame_number,
- ost->quality / (float)FF_QP2LAMBDA);
-
- if (ost->error[0]>=0 && (enc->flags & AV_CODEC_FLAG_PSNR))
- fprintf(vstats_file, "PSNR= %6.2f ", psnr(ost->error[0] / (enc->width * enc->height * 255.0 * 255.0)));
-
- fprintf(vstats_file,"f_size= %6d ", frame_size);
- /* compute pts value */
- ti1 = av_stream_get_end_pts(ost->st) * av_q2d(ost->st->time_base);
- if (ti1 < 0.01)
- ti1 = 0.01;
-
- bitrate = (frame_size * 8) / av_q2d(enc->time_base) / 1000.0;
- avg_bitrate = (double)(ost->data_size * 8) / ti1 / 1000.0;
- fprintf(vstats_file, "s_size= %8.0fkB time= %0.3f br= %7.1fkbits/s avg_br= %7.1fkbits/s ",
- (double)ost->data_size / 1024, ti1, bitrate, avg_bitrate);
- fprintf(vstats_file, "type= %c\n", av_get_picture_type_char(ost->pict_type));
- }
-}
-
-static void finish_output_stream(OutputStream *ost)
-{
- OutputFile *of = output_files[ost->file_index];
- int i;
-
- ost->finished = ENCODER_FINISHED | MUXER_FINISHED;
-
- if (of->shortest) {
- for (i = 0; i < of->ctx->nb_streams; i++)
- output_streams[of->ost_index + i]->finished = ENCODER_FINISHED | MUXER_FINISHED;
- }
+ if (next_picture)
+ av_frame_move_ref(ost->last_frame, next_picture);
}
/**
@@ -1294,27 +1368,33 @@ static void finish_output_stream(OutputStream *ost)
static int reap_filters(int flush)
{
AVFrame *filtered_frame = NULL;
- int i;
/* Reap all buffers present in the buffer sinks */
- for (i = 0; i < nb_output_streams; i++) {
- OutputStream *ost = output_streams[i];
+ for (OutputStream *ost = ost_iter(NULL); ost; ost = ost_iter(ost)) {
OutputFile *of = output_files[ost->file_index];
AVFilterContext *filter;
AVCodecContext *enc = ost->enc_ctx;
int ret = 0;
- if (!ost->filter)
+ if (!ost->filter || !ost->filter->graph->graph)
continue;
filter = ost->filter->filter;
- if (!ost->filtered_frame && !(ost->filtered_frame = av_frame_alloc())) {
- return AVERROR(ENOMEM);
- }
+ /*
+ * Unlike video, with audio the audio frame size matters.
+ * Currently we are fully reliant on the lavfi filter chain to
+ * do the buffering deed for us, and thus the frame size parameter
+ * needs to be set accordingly. Where does one get the required
+ * frame size? From the initialized AVCodecContext of an audio
+ * encoder. Thus, if we have gotten to an audio stream, initialize
+ * the encoder earlier than receiving the first AVFrame.
+ */
+ if (av_buffersink_get_type(filter) == AVMEDIA_TYPE_AUDIO)
+ init_output_stream_wrapper(ost, NULL, 1);
+
filtered_frame = ost->filtered_frame;
while (1) {
- double float_pts = AV_NOPTS_VALUE; // this is identical to filtered_frame.pts but with higher precision
ret = av_buffersink_get_frame_flags(filter, filtered_frame,
AV_BUFFERSINK_FLAG_NO_REQUEST);
if (ret < 0) {
@@ -1322,8 +1402,8 @@ static int reap_filters(int flush)
av_log(NULL, AV_LOG_WARNING,
"Error in av_buffersink_get_frame_flags(): %s\n", av_err2str(ret));
} else if (flush && ret == AVERROR_EOF) {
- if (filter->inputs[0]->type == AVMEDIA_TYPE_VIDEO)
- do_video_out(of->ctx, ost, NULL, AV_NOPTS_VALUE);
+ if (av_buffersink_get_type(filter) == AVMEDIA_TYPE_VIDEO)
+ do_video_out(of, ost, NULL);
}
break;
}
@@ -1331,48 +1411,35 @@ static int reap_filters(int flush)
av_frame_unref(filtered_frame);
continue;
}
+
if (filtered_frame->pts != AV_NOPTS_VALUE) {
- int64_t start_time = (of->start_time == AV_NOPTS_VALUE) ? 0 : of->start_time;
- AVRational tb = enc->time_base;
- int extra_bits = av_clip(29 - av_log2(tb.den), 0, 16);
-
- tb.den <<= extra_bits;
- float_pts =
- av_rescale_q(filtered_frame->pts, filter->inputs[0]->time_base, tb) -
- av_rescale_q(start_time, AV_TIME_BASE_Q, tb);
- float_pts /= 1 << extra_bits;
- // avoid exact midoints to reduce the chance of rounding differences, this can be removed in case the fps code is changed to work with integers
- float_pts += FFSIGN(float_pts) * 1.0 / (1<<17);
-
- filtered_frame->pts =
- av_rescale_q(filtered_frame->pts, filter->inputs[0]->time_base, enc->time_base) -
- av_rescale_q(start_time, AV_TIME_BASE_Q, enc->time_base);
+ AVRational tb = av_buffersink_get_time_base(filter);
+ ost->last_filter_pts = av_rescale_q(filtered_frame->pts, tb,
+ AV_TIME_BASE_Q);
+ filtered_frame->time_base = tb;
+
+ if (debug_ts)
+ av_log(NULL, AV_LOG_INFO, "filter_raw -> pts:%s pts_time:%s time_base:%d/%d\n",
+ av_ts2str(filtered_frame->pts),
+ av_ts2timestr(filtered_frame->pts, &tb),
+ tb.num, tb.den);
}
- //if (ost->source_index >= 0)
- // *filtered_frame= *input_streams[ost->source_index]->decoded_frame; //for me_threshold
- switch (filter->inputs[0]->type) {
+ switch (av_buffersink_get_type(filter)) {
case AVMEDIA_TYPE_VIDEO:
if (!ost->frame_aspect_ratio.num)
enc->sample_aspect_ratio = filtered_frame->sample_aspect_ratio;
- if (debug_ts) {
- av_log(NULL, AV_LOG_INFO, "filter -> pts:%s pts_time:%s exact:%f time_base:%d/%d\n",
- av_ts2str(filtered_frame->pts), av_ts2timestr(filtered_frame->pts, &enc->time_base),
- float_pts,
- enc->time_base.num, enc->time_base.den);
- }
-
- do_video_out(of->ctx, ost, filtered_frame, float_pts);
+ do_video_out(of, ost, filtered_frame);
break;
case AVMEDIA_TYPE_AUDIO:
if (!(enc->codec->capabilities & AV_CODEC_CAP_PARAM_CHANGE) &&
- enc->channels != av_frame_get_channels(filtered_frame)) {
+ enc->ch_layout.nb_channels != filtered_frame->ch_layout.nb_channels) {
av_log(NULL, AV_LOG_ERROR,
"Audio filter graph output is not normalized and encoder does not support parameter changes\n");
break;
}
- do_audio_out(of->ctx, ost, filtered_frame);
+ do_audio_out(of, ost, filtered_frame);
break;
default:
// TODO support subtitle filters
@@ -1395,17 +1462,20 @@ static void print_final_stats(int64_t total_size)
int i, j;
int pass1_used = 1;
- for (i = 0; i < nb_output_streams; i++) {
- OutputStream *ost = output_streams[i];
- switch (ost->enc_ctx->codec_type) {
- case AVMEDIA_TYPE_VIDEO: video_size += ost->data_size; break;
- case AVMEDIA_TYPE_AUDIO: audio_size += ost->data_size; break;
- case AVMEDIA_TYPE_SUBTITLE: subtitle_size += ost->data_size; break;
- default: other_size += ost->data_size; break;
+ for (OutputStream *ost = ost_iter(NULL); ost; ost = ost_iter(ost)) {
+ AVCodecParameters *par = ost->st->codecpar;
+ const uint64_t s = ost->data_size_mux;
+
+ switch (par->codec_type) {
+ case AVMEDIA_TYPE_VIDEO: video_size += s; break;
+ case AVMEDIA_TYPE_AUDIO: audio_size += s; break;
+ case AVMEDIA_TYPE_SUBTITLE: subtitle_size += s; break;
+ default: other_size += s; break;
}
- extra_size += ost->enc_ctx->extradata_size;
- data_size += ost->data_size;
- if ( (ost->enc_ctx->flags & (AV_CODEC_FLAG_PASS1 | CODEC_FLAG_PASS2))
+ extra_size += par->extradata_size;
+ data_size += s;
+ if (ost->enc_ctx &&
+ (ost->enc_ctx->flags & (AV_CODEC_FLAG_PASS1 | AV_CODEC_FLAG_PASS2))
!= AV_CODEC_FLAG_PASS1)
pass1_used = 0;
}
@@ -1431,17 +1501,17 @@ static void print_final_stats(int64_t total_size)
uint64_t total_packets = 0, total_size = 0;
av_log(NULL, AV_LOG_VERBOSE, "Input file #%d (%s):\n",
- i, f->ctx->filename);
+ i, f->ctx->url);
for (j = 0; j < f->nb_streams; j++) {
- InputStream *ist = input_streams[f->ist_index + j];
- enum AVMediaType type = ist->dec_ctx->codec_type;
+ InputStream *ist = f->streams[j];
+ enum AVMediaType type = ist->par->codec_type;
total_size += ist->data_size;
total_packets += ist->nb_packets;
av_log(NULL, AV_LOG_VERBOSE, " Input stream #%d:%d (%s): ",
- i, j, media_type_string(type));
+ i, j, av_get_media_type_string(type));
av_log(NULL, AV_LOG_VERBOSE, "%"PRIu64" packets read (%"PRIu64" bytes); ",
ist->nb_packets, ist->data_size);
@@ -1465,18 +1535,18 @@ static void print_final_stats(int64_t total_size)
uint64_t total_packets = 0, total_size = 0;
av_log(NULL, AV_LOG_VERBOSE, "Output file #%d (%s):\n",
- i, of->ctx->filename);
+ i, of->url);
- for (j = 0; j < of->ctx->nb_streams; j++) {
- OutputStream *ost = output_streams[of->ost_index + j];
- enum AVMediaType type = ost->enc_ctx->codec_type;
+ for (j = 0; j < of->nb_streams; j++) {
+ OutputStream *ost = of->streams[j];
+ enum AVMediaType type = ost->st->codecpar->codec_type;
- total_size += ost->data_size;
- total_packets += ost->packets_written;
+ total_size += ost->data_size_mux;
+ total_packets += atomic_load(&ost->packets_written);
av_log(NULL, AV_LOG_VERBOSE, " Output stream #%d:%d (%s): ",
- i, j, media_type_string(type));
- if (ost->encoding_needed) {
+ i, j, av_get_media_type_string(type));
+ if (ost->enc_ctx) {
av_log(NULL, AV_LOG_VERBOSE, "%"PRIu64" frames encoded",
ost->frames_encoded);
if (type == AVMEDIA_TYPE_AUDIO)
@@ -1485,7 +1555,7 @@ static void print_final_stats(int64_t total_size)
}
av_log(NULL, AV_LOG_VERBOSE, "%"PRIu64" packets muxed (%"PRIu64" bytes); ",
- ost->packets_written, ost->data_size);
+ atomic_load(&ost->packets_written), ost->data_size_mux);
av_log(NULL, AV_LOG_VERBOSE, "\n");
}
@@ -1505,19 +1575,17 @@ static void print_final_stats(int64_t total_size)
static void print_report(int is_last_report, int64_t timer_start, int64_t cur_time)
{
- char buf[1024];
- AVBPrint buf_script;
- OutputStream *ost;
- AVFormatContext *oc;
- int64_t total_size;
- AVCodecContext *enc;
- int frame_number, vid, i;
+ AVBPrint buf, buf_script;
+ int64_t total_size = of_filesize(output_files[0]);
+ int vid;
double bitrate;
double speed;
int64_t pts = INT64_MIN + 1;
static int64_t last_time = -1;
+ static int first_report = 1;
static int qp_histogram[52];
int hours, mins, secs, us;
+ const char *hours_sign;
int ret;
float t;
@@ -1527,66 +1595,57 @@ static void print_report(int is_last_report, int64_t timer_start, int64_t cur_ti
if (!is_last_report) {
if (last_time == -1) {
last_time = cur_time;
- return;
}
- if ((cur_time - last_time) < 500000)
+ if (((cur_time - last_time) < stats_period && !first_report) ||
+ (first_report && nb_output_dumped < nb_output_files))
return;
last_time = cur_time;
}
t = (cur_time-timer_start) / 1000000.0;
-
- oc = output_files[0]->ctx;
-
- total_size = avio_size(oc->pb);
- if (total_size <= 0) // FIXME improve avio_size() so it works with non seekable output too
- total_size = avio_tell(oc->pb);
-
- buf[0] = '\0';
vid = 0;
- av_bprint_init(&buf_script, 0, 1);
- for (i = 0; i < nb_output_streams; i++) {
- float q = -1;
- ost = output_streams[i];
- enc = ost->enc_ctx;
- if (!ost->stream_copy)
- q = ost->quality / (float) FF_QP2LAMBDA;
-
- if (vid && enc->codec_type == AVMEDIA_TYPE_VIDEO) {
- snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "q=%2.1f ", q);
+ av_bprint_init(&buf, 0, AV_BPRINT_SIZE_AUTOMATIC);
+ av_bprint_init(&buf_script, 0, AV_BPRINT_SIZE_AUTOMATIC);
+ for (OutputStream *ost = ost_iter(NULL); ost; ost = ost_iter(ost)) {
+ const AVCodecContext * const enc = ost->enc_ctx;
+ const float q = enc ? ost->quality / (float) FF_QP2LAMBDA : -1;
+
+ if (vid && ost->st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {
+ av_bprintf(&buf, "q=%2.1f ", q);
av_bprintf(&buf_script, "stream_%d_%d_q=%.1f\n",
ost->file_index, ost->index, q);
}
- if (!vid && enc->codec_type == AVMEDIA_TYPE_VIDEO) {
+ if (!vid && ost->st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {
float fps;
+ uint64_t frame_number = atomic_load(&ost->packets_written);
- frame_number = ost->frame_number;
fps = t > 1 ? frame_number / t : 0;
- snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "frame=%5d fps=%3.*f q=%3.1f ",
+ av_bprintf(&buf, "frame=%5"PRId64" fps=%3.*f q=%3.1f ",
frame_number, fps < 9.95, fps, q);
- av_bprintf(&buf_script, "frame=%d\n", frame_number);
- av_bprintf(&buf_script, "fps=%.1f\n", fps);
+ av_bprintf(&buf_script, "frame=%"PRId64"\n", frame_number);
+ av_bprintf(&buf_script, "fps=%.2f\n", fps);
av_bprintf(&buf_script, "stream_%d_%d_q=%.1f\n",
ost->file_index, ost->index, q);
if (is_last_report)
- snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "L");
+ av_bprintf(&buf, "L");
if (qp_hist) {
int j;
int qp = lrintf(q);
if (qp >= 0 && qp < FF_ARRAY_ELEMS(qp_histogram))
qp_histogram[qp]++;
for (j = 0; j < 32; j++)
- snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "%X", av_log2(qp_histogram[j] + 1));
+ av_bprintf(&buf, "%X", av_log2(qp_histogram[j] + 1));
}
- if ((enc->flags & AV_CODEC_FLAG_PSNR) && (ost->pict_type != AV_PICTURE_TYPE_NONE || is_last_report)) {
+ if (enc && (enc->flags & AV_CODEC_FLAG_PSNR) &&
+ (ost->pict_type != AV_PICTURE_TYPE_NONE || is_last_report)) {
int j;
double error, error_sum = 0;
double scale, scale_sum = 0;
double p;
char type[3] = { 'Y','U','V' };
- snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "PSNR=");
+ av_bprintf(&buf, "PSNR=");
for (j = 0; j < 3; j++) {
if (is_last_report) {
error = enc->error[j];
@@ -1600,21 +1659,28 @@ static void print_report(int is_last_report, int64_t timer_start, int64_t cur_ti
error_sum += error;
scale_sum += scale;
p = psnr(error / scale);
- snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "%c:%2.2f ", type[j], p);
+ av_bprintf(&buf, "%c:%2.2f ", type[j], p);
av_bprintf(&buf_script, "stream_%d_%d_psnr_%c=%2.2f\n",
ost->file_index, ost->index, type[j] | 32, p);
}
p = psnr(error_sum / scale_sum);
- snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "*:%2.2f ", psnr(error_sum / scale_sum));
+ av_bprintf(&buf, "*:%2.2f ", psnr(error_sum / scale_sum));
av_bprintf(&buf_script, "stream_%d_%d_psnr_all=%2.2f\n",
ost->file_index, ost->index, p);
}
vid = 1;
}
/* compute min output value */
- if (av_stream_get_end_pts(ost->st) != AV_NOPTS_VALUE)
- pts = FFMAX(pts, av_rescale_q(av_stream_get_end_pts(ost->st),
- ost->st->time_base, AV_TIME_BASE_Q));
+ if (ost->last_mux_dts != AV_NOPTS_VALUE) {
+ pts = FFMAX(pts, ost->last_mux_dts);
+ if (copy_ts) {
+ if (copy_ts_first_pts == AV_NOPTS_VALUE && pts > 1)
+ copy_ts_first_pts = pts;
+ if (copy_ts_first_pts != AV_NOPTS_VALUE)
+ pts -= copy_ts_first_pts;
+ }
+ }
+
if (is_last_report)
nb_frames_drop += ost->last_dropped;
}
@@ -1625,57 +1691,64 @@ static void print_report(int is_last_report, int64_t timer_start, int64_t cur_ti
secs %= 60;
hours = mins / 60;
mins %= 60;
+ hours_sign = (pts < 0) ? "-" : "";
bitrate = pts && total_size >= 0 ? total_size * 8 / (pts / 1000.0) : -1;
speed = t != 0.0 ? (double)pts / AV_TIME_BASE / t : -1;
- if (total_size < 0) snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf),
- "size=N/A time=");
- else snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf),
- "size=%8.0fkB time=", total_size / 1024.0);
- if (pts < 0)
- snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "-");
- snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf),
- "%02d:%02d:%02d.%02d ", hours, mins, secs,
- (100 * us) / AV_TIME_BASE);
+ if (total_size < 0) av_bprintf(&buf, "size=N/A time=");
+ else av_bprintf(&buf, "size=%8.0fkB time=", total_size / 1024.0);
+ if (pts == AV_NOPTS_VALUE) {
+ av_bprintf(&buf, "N/A ");
+ } else {
+ av_bprintf(&buf, "%s%02d:%02d:%02d.%02d ",
+ hours_sign, hours, mins, secs, (100 * us) / AV_TIME_BASE);
+ }
if (bitrate < 0) {
- snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf),"bitrate=N/A");
+ av_bprintf(&buf, "bitrate=N/A");
av_bprintf(&buf_script, "bitrate=N/A\n");
}else{
- snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf),"bitrate=%6.1fkbits/s", bitrate);
+ av_bprintf(&buf, "bitrate=%6.1fkbits/s", bitrate);
av_bprintf(&buf_script, "bitrate=%6.1fkbits/s\n", bitrate);
}
if (total_size < 0) av_bprintf(&buf_script, "total_size=N/A\n");
else av_bprintf(&buf_script, "total_size=%"PRId64"\n", total_size);
- av_bprintf(&buf_script, "out_time_ms=%"PRId64"\n", pts);
- av_bprintf(&buf_script, "out_time=%02d:%02d:%02d.%06d\n",
- hours, mins, secs, us);
+ if (pts == AV_NOPTS_VALUE) {
+ av_bprintf(&buf_script, "out_time_us=N/A\n");
+ av_bprintf(&buf_script, "out_time_ms=N/A\n");
+ av_bprintf(&buf_script, "out_time=N/A\n");
+ } else {
+ av_bprintf(&buf_script, "out_time_us=%"PRId64"\n", pts);
+ av_bprintf(&buf_script, "out_time_ms=%"PRId64"\n", pts);
+ av_bprintf(&buf_script, "out_time=%s%02d:%02d:%02d.%06d\n",
+ hours_sign, hours, mins, secs, us);
+ }
if (nb_frames_dup || nb_frames_drop)
- snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), " dup=%d drop=%d",
- nb_frames_dup, nb_frames_drop);
- av_bprintf(&buf_script, "dup_frames=%d\n", nb_frames_dup);
- av_bprintf(&buf_script, "drop_frames=%d\n", nb_frames_drop);
+ av_bprintf(&buf, " dup=%"PRId64" drop=%"PRId64, nb_frames_dup, nb_frames_drop);
+ av_bprintf(&buf_script, "dup_frames=%"PRId64"\n", nb_frames_dup);
+ av_bprintf(&buf_script, "drop_frames=%"PRId64"\n", nb_frames_drop);
if (speed < 0) {
- snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf)," speed=N/A");
+ av_bprintf(&buf, " speed=N/A");
av_bprintf(&buf_script, "speed=N/A\n");
} else {
- snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf)," speed=%4.3gx", speed);
+ av_bprintf(&buf, " speed=%4.3gx", speed);
av_bprintf(&buf_script, "speed=%4.3gx\n", speed);
}
if (print_stats || is_last_report) {
const char end = is_last_report ? '\n' : '\r';
if (print_stats==1 && AV_LOG_INFO > av_log_get_level()) {
- fprintf(stderr, "%s %c", buf, end);
+ fprintf(stderr, "%s %c", buf.str, end);
} else
- av_log(NULL, AV_LOG_INFO, "%s %c", buf, end);
+ av_log(NULL, AV_LOG_INFO, "%s %c", buf.str, end);
- fflush(stderr);
+ fflush(stderr);
}
+ av_bprint_finalize(&buf, NULL);
if (progress_avio) {
av_bprintf(&buf_script, "progress=%s\n",
@@ -1691,86 +1764,96 @@ static void print_report(int is_last_report, int64_t timer_start, int64_t cur_ti
}
}
+ first_report = 0;
+
+ int64_t report_position = FFABS(pts) / AV_TIME_BASE;
+ int64_t report_duration = 0;
+ if(input_files) {
+ report_duration = input_files[0]->ctx->duration / AV_TIME_BASE;
+ }
+ if (report_position <= report_duration) {
+ progress_callback((int) report_position, (int) report_duration, STATE_RUNNING);
+ }
+
if (is_last_report)
print_final_stats(total_size);
}
+static int ifilter_parameters_from_codecpar(InputFilter *ifilter, AVCodecParameters *par)
+{
+ int ret;
+
+ // We never got any input. Set a fake format, which will
+ // come from libavformat.
+ ifilter->format = par->format;
+ ifilter->sample_rate = par->sample_rate;
+ ifilter->width = par->width;
+ ifilter->height = par->height;
+ ifilter->sample_aspect_ratio = par->sample_aspect_ratio;
+ ret = av_channel_layout_copy(&ifilter->ch_layout, &par->ch_layout);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
static void flush_encoders(void)
{
- int i, ret;
+ int ret;
- for (i = 0; i < nb_output_streams; i++) {
- OutputStream *ost = output_streams[i];
- AVCodecContext *enc = ost->enc_ctx;
- AVFormatContext *os = output_files[ost->file_index]->ctx;
- int stop_encoding = 0;
+ for (OutputStream *ost = ost_iter(NULL); ost; ost = ost_iter(ost)) {
+ OutputFile *of = output_files[ost->file_index];
+ if (ost->sq_idx_encode >= 0)
+ sq_send(of->sq_encode, ost->sq_idx_encode, SQFRAME(NULL));
+ }
- if (!ost->encoding_needed)
- continue;
+ for (OutputStream *ost = ost_iter(NULL); ost; ost = ost_iter(ost)) {
+ AVCodecContext *enc = ost->enc_ctx;
+ OutputFile *of = output_files[ost->file_index];
- if (enc->codec_type == AVMEDIA_TYPE_AUDIO && enc->frame_size <= 1)
- continue;
-#if FF_API_LAVF_FMT_RAWPICTURE
- if (enc->codec_type == AVMEDIA_TYPE_VIDEO && (os->oformat->flags & AVFMT_RAWPICTURE) && enc->codec->id == AV_CODEC_ID_RAWVIDEO)
+ if (!enc)
continue;
-#endif
- for (;;) {
- int (*encode)(AVCodecContext*, AVPacket*, const AVFrame*, int*) = NULL;
- const char *desc;
+ // Try to enable encoding with no input frames.
+ // Maybe we should just let encoding fail instead.
+ if (!ost->initialized) {
+ FilterGraph *fg = ost->filter->graph;
+
+ av_log(ost, AV_LOG_WARNING,
+ "Finishing stream without any data written to it.\n");
+
+ if (ost->filter && !fg->graph) {
+ int x;
+ for (x = 0; x < fg->nb_inputs; x++) {
+ InputFilter *ifilter = fg->inputs[x];
+ if (ifilter->format < 0 &&
+ ifilter_parameters_from_codecpar(ifilter, ifilter->ist->par) < 0) {
+ av_log(ost, AV_LOG_ERROR, "Error copying paramerets from input stream\n");
+ exit_program(1);
+ }
+ }
- switch (enc->codec_type) {
- case AVMEDIA_TYPE_AUDIO:
- encode = avcodec_encode_audio2;
- desc = "audio";
- break;
- case AVMEDIA_TYPE_VIDEO:
- encode = avcodec_encode_video2;
- desc = "video";
- break;
- default:
- stop_encoding = 1;
- }
+ if (!ifilter_has_all_input_formats(fg))
+ continue;
- if (encode) {
- AVPacket pkt;
- int pkt_size;
- int got_packet;
- av_init_packet(&pkt);
- pkt.data = NULL;
- pkt.size = 0;
-
- update_benchmark(NULL);
- ret = encode(enc, &pkt, NULL, &got_packet);
- update_benchmark("flush_%s %d.%d", desc, ost->file_index, ost->index);
+ ret = configure_filtergraph(fg);
if (ret < 0) {
- av_log(NULL, AV_LOG_FATAL, "%s encoding failed: %s\n",
- desc,
- av_err2str(ret));
+ av_log(ost, AV_LOG_ERROR, "Error configuring filter graph\n");
exit_program(1);
}
- if (ost->logfile && enc->stats_out) {
- fprintf(ost->logfile, "%s", enc->stats_out);
- }
- if (!got_packet) {
- stop_encoding = 1;
- break;
- }
- if (ost->finished & MUXER_FINISHED) {
- av_packet_unref(&pkt);
- continue;
- }
- av_packet_rescale_ts(&pkt, enc->time_base, ost->st->time_base);
- pkt_size = pkt.size;
- write_frame(os, &pkt, ost);
- if (ost->enc_ctx->codec_type == AVMEDIA_TYPE_VIDEO && vstats_filename) {
- do_video_stats(ost, pkt_size);
- }
+
+ of_output_packet(of, ost->pkt, ost, 1);
}
- if (stop_encoding)
- break;
+ init_output_stream_wrapper(ost, NULL, 1);
}
+
+ if (enc->codec_type != AVMEDIA_TYPE_VIDEO && enc->codec_type != AVMEDIA_TYPE_AUDIO)
+ continue;
+
+ ret = submit_encode_frame(of, ost, NULL);
+ if (ret != AVERROR_EOF)
+ exit_program(1);
}
}
@@ -1780,12 +1863,11 @@ static void flush_encoders(void)
static int check_output_constraints(InputStream *ist, OutputStream *ost)
{
OutputFile *of = output_files[ost->file_index];
- int ist_index = input_files[ist->file_index]->ist_index + ist->st->index;
- if (ost->source_index != ist_index)
+ if (ost->ist != ist)
return 0;
- if (ost->finished)
+ if (ost->finished & MUXER_FINISHED)
return 0;
if (of->start_time != AV_NOPTS_VALUE && ist->pts < of->start_time)
@@ -1799,23 +1881,24 @@ static void do_streamcopy(InputStream *ist, OutputStream *ost, const AVPacket *p
OutputFile *of = output_files[ost->file_index];
InputFile *f = input_files [ist->file_index];
int64_t start_time = (of->start_time == AV_NOPTS_VALUE) ? 0 : of->start_time;
- int64_t ost_tb_start_time = av_rescale_q(start_time, AV_TIME_BASE_Q, ost->st->time_base);
- AVPicture pict;
- AVPacket opkt;
+ int64_t ost_tb_start_time = av_rescale_q(start_time, AV_TIME_BASE_Q, ost->mux_timebase);
+ AVPacket *opkt = ost->pkt;
- av_init_packet(&opkt);
+ av_packet_unref(opkt);
+ // EOF: flush output bitstream filters.
+ if (!pkt) {
+ of_output_packet(of, opkt, ost, 1);
+ return;
+ }
- if ((!ost->frame_number && !(pkt->flags & AV_PKT_FLAG_KEY)) &&
+ if (!ost->streamcopy_started && !(pkt->flags & AV_PKT_FLAG_KEY) &&
!ost->copy_initial_nonkeyframes)
return;
- if (!ost->frame_number && !ost->copy_prior_start) {
- int64_t comp_start = start_time;
- if (copy_ts && f->start_time != AV_NOPTS_VALUE)
- comp_start = FFMAX(start_time, f->start_time + f->ts_offset);
+ if (!ost->streamcopy_started && !ost->copy_prior_start) {
if (pkt->pts == AV_NOPTS_VALUE ?
- ist->pts < comp_start :
- pkt->pts < av_rescale_q(comp_start, AV_TIME_BASE_Q, ist->st->time_base))
+ ist->pts < ost->ts_copy_start :
+ pkt->pts < av_rescale_q(ost->ts_copy_start, AV_TIME_BASE_Q, ist->st->time_base))
return;
}
@@ -1826,105 +1909,55 @@ static void do_streamcopy(InputStream *ist, OutputStream *ost, const AVPacket *p
}
if (f->recording_time != INT64_MAX) {
- start_time = f->ctx->start_time;
- if (f->start_time != AV_NOPTS_VALUE && copy_ts)
- start_time += f->start_time;
+ start_time = 0;
+ if (copy_ts) {
+ start_time += f->start_time != AV_NOPTS_VALUE ? f->start_time : 0;
+ start_time += start_at_zero ? 0 : f->start_time_effective;
+ }
if (ist->pts >= f->recording_time + start_time) {
close_output_stream(ost);
return;
}
}
- /* force the input stream PTS */
- if (ost->enc_ctx->codec_type == AVMEDIA_TYPE_VIDEO)
- ost->sync_opts++;
+ if (av_packet_ref(opkt, pkt) < 0)
+ exit_program(1);
- if (pkt->pts != AV_NOPTS_VALUE)
- opkt.pts = av_rescale_q(pkt->pts, ist->st->time_base, ost->st->time_base) - ost_tb_start_time;
- else
- opkt.pts = AV_NOPTS_VALUE;
+ opkt->time_base = ost->mux_timebase;
- if (pkt->dts == AV_NOPTS_VALUE)
- opkt.dts = av_rescale_q(ist->dts, AV_TIME_BASE_Q, ost->st->time_base);
- else
- opkt.dts = av_rescale_q(pkt->dts, ist->st->time_base, ost->st->time_base);
- opkt.dts -= ost_tb_start_time;
+ if (pkt->pts != AV_NOPTS_VALUE)
+ opkt->pts = av_rescale_q(pkt->pts, ist->st->time_base, opkt->time_base) - ost_tb_start_time;
- if (ost->st->codec->codec_type == AVMEDIA_TYPE_AUDIO && pkt->dts != AV_NOPTS_VALUE) {
- int duration = av_get_audio_frame_duration(ist->dec_ctx, pkt->size);
+ if (pkt->dts == AV_NOPTS_VALUE) {
+ opkt->dts = av_rescale_q(ist->dts, AV_TIME_BASE_Q, opkt->time_base);
+ } else if (ost->st->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) {
+ int duration = av_get_audio_frame_duration2(ist->par, pkt->size);
if(!duration)
- duration = ist->dec_ctx->frame_size;
- opkt.dts = opkt.pts = av_rescale_delta(ist->st->time_base, pkt->dts,
- (AVRational){1, ist->dec_ctx->sample_rate}, duration, &ist->filter_in_rescale_delta_last,
- ost->st->time_base) - ost_tb_start_time;
- }
-
- opkt.duration = av_rescale_q(pkt->duration, ist->st->time_base, ost->st->time_base);
- opkt.flags = pkt->flags;
- // FIXME remove the following 2 lines they shall be replaced by the bitstream filters
- if ( ost->st->codec->codec_id != AV_CODEC_ID_H264
- && ost->st->codec->codec_id != AV_CODEC_ID_MPEG1VIDEO
- && ost->st->codec->codec_id != AV_CODEC_ID_MPEG2VIDEO
- && ost->st->codec->codec_id != AV_CODEC_ID_VC1
- ) {
- int ret = av_parser_change(ost->parser, ost->st->codec,
- &opkt.data, &opkt.size,
- pkt->data, pkt->size,
- pkt->flags & AV_PKT_FLAG_KEY);
- if (ret < 0) {
- av_log(NULL, AV_LOG_FATAL, "av_parser_change failed: %s\n",
- av_err2str(ret));
- exit_program(1);
- }
- if (ret) {
- opkt.buf = av_buffer_create(opkt.data, opkt.size, av_buffer_default_free, NULL, 0);
- if (!opkt.buf)
- exit_program(1);
- }
- } else {
- opkt.data = pkt->data;
- opkt.size = pkt->size;
- }
- av_copy_packet_side_data(&opkt, pkt);
+ duration = ist->par->frame_size;
+ opkt->dts = av_rescale_delta(ist->st->time_base, pkt->dts,
+ (AVRational){1, ist->par->sample_rate}, duration,
+ &ist->filter_in_rescale_delta_last, opkt->time_base);
+ /* dts will be set immediately afterwards to what pts is now */
+ opkt->pts = opkt->dts - ost_tb_start_time;
+ } else
+ opkt->dts = av_rescale_q(pkt->dts, ist->st->time_base, opkt->time_base);
+ opkt->dts -= ost_tb_start_time;
+
+ opkt->duration = av_rescale_q(pkt->duration, ist->st->time_base, opkt->time_base);
-#if FF_API_LAVF_FMT_RAWPICTURE
- if (ost->st->codec->codec_type == AVMEDIA_TYPE_VIDEO &&
- ost->st->codec->codec_id == AV_CODEC_ID_RAWVIDEO &&
- (of->ctx->oformat->flags & AVFMT_RAWPICTURE)) {
- /* store AVPicture in AVPacket, as expected by the output format */
- int ret = avpicture_fill(&pict, opkt.data, ost->st->codec->pix_fmt, ost->st->codec->width, ost->st->codec->height);
+ {
+ int ret = trigger_fix_sub_duration_heartbeat(ost, pkt);
if (ret < 0) {
- av_log(NULL, AV_LOG_FATAL, "avpicture_fill failed: %s\n",
- av_err2str(ret));
+ av_log(NULL, AV_LOG_ERROR,
+ "Subtitle heartbeat logic failed in %s! (%s)\n",
+ __func__, av_err2str(ret));
exit_program(1);
}
- opkt.data = (uint8_t *)&pict;
- opkt.size = sizeof(AVPicture);
- opkt.flags |= AV_PKT_FLAG_KEY;
}
-#endif
- write_frame(of->ctx, &opkt, ost);
-}
-
-int guess_input_channel_layout(InputStream *ist)
-{
- AVCodecContext *dec = ist->dec_ctx;
-
- if (!dec->channel_layout) {
- char layout_name[256];
+ of_output_packet(of, opkt, ost, 0);
- if (dec->channels > ist->guess_layout_max)
- return 0;
- dec->channel_layout = av_get_default_channel_layout(dec->channels);
- if (!dec->channel_layout)
- return 0;
- av_get_channel_layout_string(layout_name, sizeof(layout_name),
- dec->channels, dec->channel_layout);
- av_log(NULL, AV_LOG_WARNING, "Guessed Channel Layout for Input Stream "
- "#%d.%d : %s\n", ist->file_index, ist->st->index, layout_name);
- }
- return 1;
+ ost->streamcopy_started = 1;
}
static void check_decode_result(InputStream *ist, int *got_output, int ret)
@@ -1935,174 +1968,306 @@ static void check_decode_result(InputStream *ist, int *got_output, int ret)
if (ret < 0 && exit_on_error)
exit_program(1);
- if (exit_on_error && *got_output && ist) {
- if (av_frame_get_decode_error_flags(ist->decoded_frame) || (ist->decoded_frame->flags & AV_FRAME_FLAG_CORRUPT)) {
- av_log(NULL, AV_LOG_FATAL, "%s: corrupt decoded frame in stream %d\n", input_files[ist->file_index]->ctx->filename, ist->st->index);
- exit_program(1);
+ if (*got_output && ist) {
+ if (ist->decoded_frame->decode_error_flags || (ist->decoded_frame->flags & AV_FRAME_FLAG_CORRUPT)) {
+ av_log(NULL, exit_on_error ? AV_LOG_FATAL : AV_LOG_WARNING,
+ "%s: corrupt decoded frame in stream %d\n", input_files[ist->file_index]->ctx->url, ist->st->index);
+ if (exit_on_error)
+ exit_program(1);
}
}
}
-static int decode_audio(InputStream *ist, AVPacket *pkt, int *got_output)
+// Filters can be configured only if the formats of all inputs are known.
+static int ifilter_has_all_input_formats(FilterGraph *fg)
{
- AVFrame *decoded_frame, *f;
- AVCodecContext *avctx = ist->dec_ctx;
- int i, ret, err = 0, resample_changed;
- AVRational decoded_frame_tb;
+ int i;
+ for (i = 0; i < fg->nb_inputs; i++) {
+ if (fg->inputs[i]->format < 0 && (fg->inputs[i]->type == AVMEDIA_TYPE_AUDIO ||
+ fg->inputs[i]->type == AVMEDIA_TYPE_VIDEO))
+ return 0;
+ }
+ return 1;
+}
- if (!ist->decoded_frame && !(ist->decoded_frame = av_frame_alloc()))
- return AVERROR(ENOMEM);
- if (!ist->filter_frame && !(ist->filter_frame = av_frame_alloc()))
- return AVERROR(ENOMEM);
- decoded_frame = ist->decoded_frame;
+static int ifilter_send_frame(InputFilter *ifilter, AVFrame *frame, int keep_reference)
+{
+ FilterGraph *fg = ifilter->graph;
+ AVFrameSideData *sd;
+ int need_reinit, ret;
+ int buffersrc_flags = AV_BUFFERSRC_FLAG_PUSH;
- update_benchmark(NULL);
- ret = avcodec_decode_audio4(avctx, decoded_frame, got_output, pkt);
- update_benchmark("decode_audio %d.%d", ist->file_index, ist->st->index);
+ if (keep_reference)
+ buffersrc_flags |= AV_BUFFERSRC_FLAG_KEEP_REF;
+
+ /* determine if the parameters for this input changed */
+ need_reinit = ifilter->format != frame->format;
- if (ret >= 0 && avctx->sample_rate <= 0) {
- av_log(avctx, AV_LOG_ERROR, "Sample rate %d invalid\n", avctx->sample_rate);
- ret = AVERROR_INVALIDDATA;
+ switch (ifilter->ist->par->codec_type) {
+ case AVMEDIA_TYPE_AUDIO:
+ need_reinit |= ifilter->sample_rate != frame->sample_rate ||
+ av_channel_layout_compare(&ifilter->ch_layout, &frame->ch_layout);
+ break;
+ case AVMEDIA_TYPE_VIDEO:
+ need_reinit |= ifilter->width != frame->width ||
+ ifilter->height != frame->height;
+ break;
}
- check_decode_result(ist, got_output, ret);
+ if (!ifilter->ist->reinit_filters && fg->graph)
+ need_reinit = 0;
- if (!*got_output || ret < 0)
- return ret;
+ if (!!ifilter->hw_frames_ctx != !!frame->hw_frames_ctx ||
+ (ifilter->hw_frames_ctx && ifilter->hw_frames_ctx->data != frame->hw_frames_ctx->data))
+ need_reinit = 1;
- ist->samples_decoded += decoded_frame->nb_samples;
- ist->frames_decoded++;
+ if (sd = av_frame_get_side_data(frame, AV_FRAME_DATA_DISPLAYMATRIX)) {
+ if (!ifilter->displaymatrix || memcmp(sd->data, ifilter->displaymatrix, sizeof(int32_t) * 9))
+ need_reinit = 1;
+ } else if (ifilter->displaymatrix)
+ need_reinit = 1;
-#if 1
- /* increment next_dts to use for the case where the input stream does not
- have timestamps or there are multiple frames in the packet */
- ist->next_pts += ((int64_t)AV_TIME_BASE * decoded_frame->nb_samples) /
- avctx->sample_rate;
- ist->next_dts += ((int64_t)AV_TIME_BASE * decoded_frame->nb_samples) /
- avctx->sample_rate;
-#endif
+ if (need_reinit) {
+ ret = ifilter_parameters_from_frame(ifilter, frame);
+ if (ret < 0)
+ return ret;
+ }
- resample_changed = ist->resample_sample_fmt != decoded_frame->format ||
- ist->resample_channels != avctx->channels ||
- ist->resample_channel_layout != decoded_frame->channel_layout ||
- ist->resample_sample_rate != decoded_frame->sample_rate;
- if (resample_changed) {
- char layout1[64], layout2[64];
-
- if (!guess_input_channel_layout(ist)) {
- av_log(NULL, AV_LOG_FATAL, "Unable to find default channel "
- "layout for Input Stream #%d.%d\n", ist->file_index,
- ist->st->index);
- exit_program(1);
- }
- decoded_frame->channel_layout = avctx->channel_layout;
+ /* (re)init the graph if possible, otherwise buffer the frame and return */
+ if (need_reinit || !fg->graph) {
+ if (!ifilter_has_all_input_formats(fg)) {
+ AVFrame *tmp = av_frame_clone(frame);
+ if (!tmp)
+ return AVERROR(ENOMEM);
- av_get_channel_layout_string(layout1, sizeof(layout1), ist->resample_channels,
- ist->resample_channel_layout);
- av_get_channel_layout_string(layout2, sizeof(layout2), avctx->channels,
- decoded_frame->channel_layout);
+ ret = av_fifo_write(ifilter->frame_queue, &tmp, 1);
+ if (ret < 0)
+ av_frame_free(&tmp);
- av_log(NULL, AV_LOG_INFO,
- "Input stream #%d:%d frame changed from rate:%d fmt:%s ch:%d chl:%s to rate:%d fmt:%s ch:%d chl:%s\n",
- ist->file_index, ist->st->index,
- ist->resample_sample_rate, av_get_sample_fmt_name(ist->resample_sample_fmt),
- ist->resample_channels, layout1,
- decoded_frame->sample_rate, av_get_sample_fmt_name(decoded_frame->format),
- avctx->channels, layout2);
-
- ist->resample_sample_fmt = decoded_frame->format;
- ist->resample_sample_rate = decoded_frame->sample_rate;
- ist->resample_channel_layout = decoded_frame->channel_layout;
- ist->resample_channels = avctx->channels;
-
- for (i = 0; i < nb_filtergraphs; i++)
- if (ist_in_filtergraph(filtergraphs[i], ist)) {
- FilterGraph *fg = filtergraphs[i];
- if (configure_filtergraph(fg) < 0) {
- av_log(NULL, AV_LOG_FATAL, "Error reinitializing filters!\n");
- exit_program(1);
- }
+ return ret;
+ }
+
+ ret = reap_filters(1);
+ if (ret < 0 && ret != AVERROR_EOF) {
+ av_log(NULL, AV_LOG_ERROR, "Error while filtering: %s\n", av_err2str(ret));
+ return ret;
+ }
+
+ ret = configure_filtergraph(fg);
+ if (ret < 0) {
+ av_log(NULL, AV_LOG_ERROR, "Error reinitializing filters!\n");
+ return ret;
+ }
+ }
+
+ ret = av_buffersrc_add_frame_flags(ifilter->filter, frame, buffersrc_flags);
+ if (ret < 0) {
+ if (ret != AVERROR_EOF)
+ av_log(NULL, AV_LOG_ERROR, "Error while filtering: %s\n", av_err2str(ret));
+ return ret;
+ }
+
+ return 0;
+}
+
+static int ifilter_send_eof(InputFilter *ifilter, int64_t pts)
+{
+ int ret;
+
+ ifilter->eof = 1;
+
+ if (ifilter->filter) {
+ ret = av_buffersrc_close(ifilter->filter, pts, AV_BUFFERSRC_FLAG_PUSH);
+ if (ret < 0)
+ return ret;
+ } else {
+ // the filtergraph was never configured
+ if (ifilter->format < 0) {
+ ret = ifilter_parameters_from_codecpar(ifilter, ifilter->ist->par);
+ if (ret < 0)
+ return ret;
+ }
+ if (ifilter->format < 0 && (ifilter->type == AVMEDIA_TYPE_AUDIO || ifilter->type == AVMEDIA_TYPE_VIDEO)) {
+ av_log(NULL, AV_LOG_ERROR, "Cannot determine format of input stream %d:%d after EOF\n", ifilter->ist->file_index, ifilter->ist->st->index);
+ return AVERROR_INVALIDDATA;
+ }
+ }
+
+ return 0;
+}
+
+// This does not quite work like avcodec_decode_audio4/avcodec_decode_video2.
+// There is the following difference: if you got a frame, you must call
+// it again with pkt=NULL. pkt==NULL is treated differently from pkt->size==0
+// (pkt==NULL means get more output, pkt->size==0 is a flush/drain packet)
+static int decode(InputStream *ist, AVCodecContext *avctx,
+ AVFrame *frame, int *got_frame, AVPacket *pkt)
+{
+ int ret;
+
+ *got_frame = 0;
+
+ if (pkt) {
+ ret = avcodec_send_packet(avctx, pkt);
+ // In particular, we don't expect AVERROR(EAGAIN), because we read all
+ // decoded frames with avcodec_receive_frame() until done.
+ if (ret < 0 && ret != AVERROR_EOF)
+ return ret;
+ }
+
+ ret = avcodec_receive_frame(avctx, frame);
+ if (ret < 0 && ret != AVERROR(EAGAIN))
+ return ret;
+ if (ret >= 0) {
+ if (ist->want_frame_data) {
+ FrameData *fd;
+
+ av_assert0(!frame->opaque_ref);
+ frame->opaque_ref = av_buffer_allocz(sizeof(*fd));
+ if (!frame->opaque_ref) {
+ av_frame_unref(frame);
+ return AVERROR(ENOMEM);
}
+ fd = (FrameData*)frame->opaque_ref->data;
+ fd->pts = frame->pts;
+ fd->tb = avctx->pkt_timebase;
+ fd->idx = avctx->frame_num - 1;
+ }
+
+ *got_frame = 1;
+ }
+
+ return 0;
+}
+
+static int send_frame_to_filters(InputStream *ist, AVFrame *decoded_frame)
+{
+ int i, ret;
+
+ av_assert1(ist->nb_filters > 0); /* ensure ret is initialized */
+ for (i = 0; i < ist->nb_filters; i++) {
+ ret = ifilter_send_frame(ist->filters[i], decoded_frame, i < ist->nb_filters - 1);
+ if (ret == AVERROR_EOF)
+ ret = 0; /* ignore */
+ if (ret < 0) {
+ av_log(NULL, AV_LOG_ERROR,
+ "Failed to inject frame into filter network: %s\n", av_err2str(ret));
+ break;
+ }
}
+ return ret;
+}
+
+static int decode_audio(InputStream *ist, AVPacket *pkt, int *got_output,
+ int *decode_failed)
+{
+ AVFrame *decoded_frame = ist->decoded_frame;
+ AVCodecContext *avctx = ist->dec_ctx;
+ int ret, err = 0;
+ AVRational decoded_frame_tb;
+
+ update_benchmark(NULL);
+ ret = decode(ist, avctx, decoded_frame, got_output, pkt);
+ update_benchmark("decode_audio %d.%d", ist->file_index, ist->st->index);
+ if (ret < 0)
+ *decode_failed = 1;
+
+ if (ret != AVERROR_EOF)
+ check_decode_result(ist, got_output, ret);
+
+ if (!*got_output || ret < 0)
+ return ret;
+
+ ist->samples_decoded += decoded_frame->nb_samples;
+ ist->frames_decoded++;
+
+ /* increment next_dts to use for the case where the input stream does not
+ have timestamps or there are multiple frames in the packet */
+ ist->next_pts += ((int64_t)AV_TIME_BASE * decoded_frame->nb_samples) /
+ decoded_frame->sample_rate;
+ ist->next_dts += ((int64_t)AV_TIME_BASE * decoded_frame->nb_samples) /
+ decoded_frame->sample_rate;
- /* if the decoder provides a pts, use it instead of the last packet pts.
- the decoder could be delaying output by a packet or more. */
if (decoded_frame->pts != AV_NOPTS_VALUE) {
- ist->dts = ist->next_dts = ist->pts = ist->next_pts = av_rescale_q(decoded_frame->pts, avctx->time_base, AV_TIME_BASE_Q);
- decoded_frame_tb = avctx->time_base;
- } else if (decoded_frame->pkt_pts != AV_NOPTS_VALUE) {
- decoded_frame->pts = decoded_frame->pkt_pts;
decoded_frame_tb = ist->st->time_base;
- } else if (pkt->pts != AV_NOPTS_VALUE) {
+ } else if (pkt && pkt->pts != AV_NOPTS_VALUE) {
decoded_frame->pts = pkt->pts;
decoded_frame_tb = ist->st->time_base;
}else {
decoded_frame->pts = ist->dts;
decoded_frame_tb = AV_TIME_BASE_Q;
}
- pkt->pts = AV_NOPTS_VALUE;
+ if (pkt && pkt->duration && ist->prev_pkt_pts != AV_NOPTS_VALUE &&
+ pkt->pts != AV_NOPTS_VALUE && pkt->pts - ist->prev_pkt_pts > pkt->duration)
+ ist->filter_in_rescale_delta_last = AV_NOPTS_VALUE;
+ if (pkt)
+ ist->prev_pkt_pts = pkt->pts;
if (decoded_frame->pts != AV_NOPTS_VALUE)
decoded_frame->pts = av_rescale_delta(decoded_frame_tb, decoded_frame->pts,
- (AVRational){1, avctx->sample_rate}, decoded_frame->nb_samples, &ist->filter_in_rescale_delta_last,
- (AVRational){1, avctx->sample_rate});
+ (AVRational){1, decoded_frame->sample_rate},
+ decoded_frame->nb_samples,
+ &ist->filter_in_rescale_delta_last,
+ (AVRational){1, decoded_frame->sample_rate});
ist->nb_samples = decoded_frame->nb_samples;
- for (i = 0; i < ist->nb_filters; i++) {
- if (i < ist->nb_filters - 1) {
- f = ist->filter_frame;
- err = av_frame_ref(f, decoded_frame);
- if (err < 0)
- break;
- } else
- f = decoded_frame;
- err = av_buffersrc_add_frame_flags(ist->filters[i]->filter, f,
- AV_BUFFERSRC_FLAG_PUSH);
- if (err == AVERROR_EOF)
- err = 0; /* ignore */
- if (err < 0)
- break;
- }
- decoded_frame->pts = AV_NOPTS_VALUE;
+ err = send_frame_to_filters(ist, decoded_frame);
- av_frame_unref(ist->filter_frame);
av_frame_unref(decoded_frame);
return err < 0 ? err : ret;
}
-static int decode_video(InputStream *ist, AVPacket *pkt, int *got_output)
+static int decode_video(InputStream *ist, AVPacket *pkt, int *got_output, int64_t *duration_pts, int eof,
+ int *decode_failed)
{
- AVFrame *decoded_frame, *f;
- int i, ret = 0, err = 0, resample_changed;
+ AVFrame *decoded_frame = ist->decoded_frame;
+ int i, ret = 0, err = 0;
int64_t best_effort_timestamp;
- AVRational *frame_sample_aspect;
+ int64_t dts = AV_NOPTS_VALUE;
- if (!ist->decoded_frame && !(ist->decoded_frame = av_frame_alloc()))
- return AVERROR(ENOMEM);
- if (!ist->filter_frame && !(ist->filter_frame = av_frame_alloc()))
- return AVERROR(ENOMEM);
- decoded_frame = ist->decoded_frame;
- pkt->dts = av_rescale_q(ist->dts, AV_TIME_BASE_Q, ist->st->time_base);
+ // With fate-indeo3-2, we're getting 0-sized packets before EOF for some
+ // reason. This seems like a semi-critical bug. Don't trigger EOF, and
+ // skip the packet.
+ if (!eof && pkt && pkt->size == 0)
+ return 0;
+
+ if (ist->dts != AV_NOPTS_VALUE)
+ dts = av_rescale_q(ist->dts, AV_TIME_BASE_Q, ist->st->time_base);
+ if (pkt) {
+ pkt->dts = dts; // ffmpeg.c probably shouldn't do this
+ }
+
+ // The old code used to set dts on the drain packet, which does not work
+ // with the new API anymore.
+ if (eof) {
+ void *new = av_realloc_array(ist->dts_buffer, ist->nb_dts_buffer + 1, sizeof(ist->dts_buffer[0]));
+ if (!new)
+ return AVERROR(ENOMEM);
+ ist->dts_buffer = new;
+ ist->dts_buffer[ist->nb_dts_buffer++] = dts;
+ }
update_benchmark(NULL);
- ret = avcodec_decode_video2(ist->dec_ctx,
- decoded_frame, got_output, pkt);
+ ret = decode(ist, ist->dec_ctx, decoded_frame, got_output, pkt);
update_benchmark("decode_video %d.%d", ist->file_index, ist->st->index);
+ if (ret < 0)
+ *decode_failed = 1;
// The following line may be required in some cases where there is no parser
// or the parser does not has_b_frames correctly
- if (ist->st->codec->has_b_frames < ist->dec_ctx->has_b_frames) {
+ if (ist->par->video_delay < ist->dec_ctx->has_b_frames) {
if (ist->dec_ctx->codec_id == AV_CODEC_ID_H264) {
- ist->st->codec->has_b_frames = ist->dec_ctx->has_b_frames;
+ ist->par->video_delay = ist->dec_ctx->has_b_frames;
} else
av_log(ist->dec_ctx, AV_LOG_WARNING,
- "has_b_frames is larger in decoder than demuxer %d > %d.\n"
+ "video_delay is larger in decoder than demuxer %d > %d.\n"
"If you want to help, upload a sample "
- "of this file to ftp://upload.ffmpeg.org/incoming/ "
- "and contact the ffmpeg-devel mailing list. (ffmpeg-devel@ffmpeg.org)",
+ "of this file to https://streams.videolan.org/upload/ "
+ "and contact the ffmpeg-devel mailing list. (ffmpeg-devel@ffmpeg.org)\n",
ist->dec_ctx->has_b_frames,
- ist->st->codec->has_b_frames);
+ ist->par->video_delay);
}
- check_decode_result(ist, got_output, ret);
+ if (ret != AVERROR_EOF)
+ check_decode_result(ist, got_output, ret);
if (*got_output && ret >= 0) {
if (ist->dec_ctx->width != decoded_frame->width ||
@@ -2131,11 +2296,27 @@ static int decode_video(InputStream *ist, AVPacket *pkt, int *got_output)
if (err < 0)
goto fail;
}
- ist->hwaccel_retrieved_pix_fmt = decoded_frame->format;
- best_effort_timestamp= av_frame_get_best_effort_timestamp(decoded_frame);
- if(best_effort_timestamp != AV_NOPTS_VALUE)
- ist->next_pts = ist->pts = av_rescale_q(decoded_frame->pts = best_effort_timestamp, ist->st->time_base, AV_TIME_BASE_Q);
+ best_effort_timestamp= decoded_frame->best_effort_timestamp;
+ *duration_pts = decoded_frame->duration;
+
+ if (ist->framerate.num)
+ best_effort_timestamp = ist->cfr_next_pts++;
+
+ if (eof && best_effort_timestamp == AV_NOPTS_VALUE && ist->nb_dts_buffer > 0) {
+ best_effort_timestamp = ist->dts_buffer[0];
+
+ for (i = 0; i < ist->nb_dts_buffer - 1; i++)
+ ist->dts_buffer[i] = ist->dts_buffer[i + 1];
+ ist->nb_dts_buffer--;
+ }
+
+ if(best_effort_timestamp != AV_NOPTS_VALUE) {
+ int64_t ts = av_rescale_q(decoded_frame->pts = best_effort_timestamp, ist->st->time_base, AV_TIME_BASE_Q);
+
+ if (ts != AV_NOPTS_VALUE)
+ ist->next_pts = ist->pts = ts;
+ }
if (debug_ts) {
av_log(NULL, AV_LOG_INFO, "decoder -> ist_index:%d type:video "
@@ -2148,84 +2329,29 @@ static int decode_video(InputStream *ist, AVPacket *pkt, int *got_output)
ist->st->time_base.num, ist->st->time_base.den);
}
- pkt->size = 0;
-
if (ist->st->sample_aspect_ratio.num)
decoded_frame->sample_aspect_ratio = ist->st->sample_aspect_ratio;
- resample_changed = ist->resample_width != decoded_frame->width ||
- ist->resample_height != decoded_frame->height ||
- ist->resample_pix_fmt != decoded_frame->format;
- if (resample_changed) {
- av_log(NULL, AV_LOG_INFO,
- "Input stream #%d:%d frame changed from size:%dx%d fmt:%s to size:%dx%d fmt:%s\n",
- ist->file_index, ist->st->index,
- ist->resample_width, ist->resample_height, av_get_pix_fmt_name(ist->resample_pix_fmt),
- decoded_frame->width, decoded_frame->height, av_get_pix_fmt_name(decoded_frame->format));
-
- ist->resample_width = decoded_frame->width;
- ist->resample_height = decoded_frame->height;
- ist->resample_pix_fmt = decoded_frame->format;
-
- for (i = 0; i < nb_filtergraphs; i++) {
- if (ist_in_filtergraph(filtergraphs[i], ist) && ist->reinit_filters &&
- configure_filtergraph(filtergraphs[i]) < 0) {
- av_log(NULL, AV_LOG_FATAL, "Error reinitializing filters!\n");
- exit_program(1);
- }
- }
- }
-
- frame_sample_aspect= av_opt_ptr(avcodec_get_frame_class(), decoded_frame, "sample_aspect_ratio");
- for (i = 0; i < ist->nb_filters; i++) {
- if (!frame_sample_aspect->num)
- *frame_sample_aspect = ist->st->sample_aspect_ratio;
-
- if (i < ist->nb_filters - 1) {
- f = ist->filter_frame;
- err = av_frame_ref(f, decoded_frame);
- if (err < 0)
- break;
- } else
- f = decoded_frame;
- ret = av_buffersrc_add_frame_flags(ist->filters[i]->filter, f, AV_BUFFERSRC_FLAG_PUSH);
- if (ret == AVERROR_EOF) {
- ret = 0; /* ignore */
- } else if (ret < 0) {
- av_log(NULL, AV_LOG_FATAL,
- "Failed to inject frame into filter network: %s\n", av_err2str(ret));
- exit_program(1);
- }
- }
+ err = send_frame_to_filters(ist, decoded_frame);
fail:
- av_frame_unref(ist->filter_frame);
av_frame_unref(decoded_frame);
return err < 0 ? err : ret;
}
-static int transcode_subtitles(InputStream *ist, AVPacket *pkt, int *got_output)
+static int process_subtitle(InputStream *ist, AVSubtitle *subtitle, int *got_output)
{
- AVSubtitle subtitle;
- int i, ret = avcodec_decode_subtitle2(ist->dec_ctx,
- &subtitle, got_output, pkt);
-
- check_decode_result(NULL, got_output, ret);
-
- if (ret < 0 || !*got_output) {
- if (!pkt->size)
- sub2video_flush(ist);
- return ret;
- }
+ int ret = 0;
+ int free_sub = 1;
if (ist->fix_sub_duration) {
int end = 1;
if (ist->prev_sub.got_output) {
- end = av_rescale(subtitle.pts - ist->prev_sub.subtitle.pts,
+ end = av_rescale(subtitle->pts - ist->prev_sub.subtitle.pts,
1000, AV_TIME_BASE);
if (end < ist->prev_sub.subtitle.end_display_time) {
- av_log(ist->dec_ctx, AV_LOG_DEBUG,
- "Subtitle duration reduced from %d to %d%s\n",
+ av_log(NULL, AV_LOG_DEBUG,
+ "Subtitle duration reduced from %"PRId32" to %d%s\n",
ist->prev_sub.subtitle.end_display_time, end,
end <= 0 ? ", dropping it" : "");
ist->prev_sub.subtitle.end_display_time = end;
@@ -2233,7 +2359,7 @@ static int transcode_subtitles(InputStream *ist, AVPacket *pkt, int *got_output)
}
FFSWAP(int, *got_output, ist->prev_sub.got_output);
FFSWAP(int, ret, ist->prev_sub.ret);
- FFSWAP(AVSubtitle, subtitle, ist->prev_sub.subtitle);
+ FFSWAP(AVSubtitle, *subtitle, ist->prev_sub.subtitle);
if (end <= 0)
goto out;
}
@@ -2241,33 +2367,197 @@ static int transcode_subtitles(InputStream *ist, AVPacket *pkt, int *got_output)
if (!*got_output)
return ret;
- sub2video_update(ist, &subtitle);
+ if (ist->sub2video.frame) {
+ sub2video_update(ist, INT64_MIN, subtitle);
+ } else if (ist->nb_filters) {
+ if (!ist->sub2video.sub_queue)
+ ist->sub2video.sub_queue = av_fifo_alloc2(8, sizeof(AVSubtitle), AV_FIFO_FLAG_AUTO_GROW);
+ if (!ist->sub2video.sub_queue)
+ report_and_exit(AVERROR(ENOMEM));
- if (!subtitle.num_rects)
- goto out;
-
- ist->frames_decoded++;
+ ret = av_fifo_write(ist->sub2video.sub_queue, subtitle, 1);
+ if (ret < 0)
+ exit_program(1);
+ free_sub = 0;
+ }
- for (i = 0; i < nb_output_streams; i++) {
- OutputStream *ost = output_streams[i];
+ if (!subtitle->num_rects)
+ goto out;
- if (!check_output_constraints(ist, ost) || !ost->encoding_needed
- || ost->enc->type != AVMEDIA_TYPE_SUBTITLE)
+ for (OutputStream *ost = ost_iter(NULL); ost; ost = ost_iter(ost)) {
+ if (!check_output_constraints(ist, ost) || !ost->enc_ctx
+ || ost->enc_ctx->codec_type != AVMEDIA_TYPE_SUBTITLE)
continue;
- do_subtitle_out(output_files[ost->file_index]->ctx, ost, ist, &subtitle);
+ do_subtitle_out(output_files[ost->file_index], ost, subtitle);
}
out:
- avsubtitle_free(&subtitle);
+ if (free_sub)
+ avsubtitle_free(subtitle);
+ return ret;
+}
+
+static int copy_av_subtitle(AVSubtitle *dst, AVSubtitle *src)
+{
+ int ret = AVERROR_BUG;
+ AVSubtitle tmp = {
+ .format = src->format,
+ .start_display_time = src->start_display_time,
+ .end_display_time = src->end_display_time,
+ .num_rects = 0,
+ .rects = NULL,
+ .pts = src->pts
+ };
+
+ if (!src->num_rects)
+ goto success;
+
+ if (!(tmp.rects = av_calloc(src->num_rects, sizeof(*tmp.rects))))
+ return AVERROR(ENOMEM);
+
+ for (int i = 0; i < src->num_rects; i++) {
+ AVSubtitleRect *src_rect = src->rects[i];
+ AVSubtitleRect *dst_rect;
+
+ if (!(dst_rect = tmp.rects[i] = av_mallocz(sizeof(*tmp.rects[0])))) {
+ ret = AVERROR(ENOMEM);
+ goto cleanup;
+ }
+
+ tmp.num_rects++;
+
+ dst_rect->type = src_rect->type;
+ dst_rect->flags = src_rect->flags;
+
+ dst_rect->x = src_rect->x;
+ dst_rect->y = src_rect->y;
+ dst_rect->w = src_rect->w;
+ dst_rect->h = src_rect->h;
+ dst_rect->nb_colors = src_rect->nb_colors;
+
+ if (src_rect->text)
+ if (!(dst_rect->text = av_strdup(src_rect->text))) {
+ ret = AVERROR(ENOMEM);
+ goto cleanup;
+ }
+
+ if (src_rect->ass)
+ if (!(dst_rect->ass = av_strdup(src_rect->ass))) {
+ ret = AVERROR(ENOMEM);
+ goto cleanup;
+ }
+
+ for (int j = 0; j < 4; j++) {
+ // SUBTITLE_BITMAP images are special in the sense that they
+ // are like PAL8 images. first pointer to data, second to
+ // palette. This makes the size calculation match this.
+ size_t buf_size = src_rect->type == SUBTITLE_BITMAP && j == 1 ?
+ AVPALETTE_SIZE :
+ src_rect->h * src_rect->linesize[j];
+
+ if (!src_rect->data[j])
+ continue;
+
+ if (!(dst_rect->data[j] = av_memdup(src_rect->data[j], buf_size))) {
+ ret = AVERROR(ENOMEM);
+ goto cleanup;
+ }
+ dst_rect->linesize[j] = src_rect->linesize[j];
+ }
+ }
+
+success:
+ *dst = tmp;
+
+ return 0;
+
+cleanup:
+ avsubtitle_free(&tmp);
+
return ret;
}
+static int fix_sub_duration_heartbeat(InputStream *ist, int64_t signal_pts)
+{
+ int ret = AVERROR_BUG;
+ int got_output = 1;
+ AVSubtitle *prev_subtitle = &ist->prev_sub.subtitle;
+ AVSubtitle subtitle;
+
+ if (!ist->fix_sub_duration || !prev_subtitle->num_rects ||
+ signal_pts <= prev_subtitle->pts)
+ return 0;
+
+ if ((ret = copy_av_subtitle(&subtitle, prev_subtitle)) < 0)
+ return ret;
+
+ subtitle.pts = signal_pts;
+
+ return process_subtitle(ist, &subtitle, &got_output);
+}
+
+static int trigger_fix_sub_duration_heartbeat(OutputStream *ost, const AVPacket *pkt)
+{
+ OutputFile *of = output_files[ost->file_index];
+ int64_t signal_pts = av_rescale_q(pkt->pts, pkt->time_base,
+ AV_TIME_BASE_Q);
+
+ if (!ost->fix_sub_duration_heartbeat || !(pkt->flags & AV_PKT_FLAG_KEY))
+ // we are only interested in heartbeats on streams configured, and
+ // only on random access points.
+ return 0;
+
+ for (int i = 0; i < of->nb_streams; i++) {
+ OutputStream *iter_ost = of->streams[i];
+ InputStream *ist = iter_ost->ist;
+ int ret = AVERROR_BUG;
+
+ if (iter_ost == ost || !ist || !ist->decoding_needed ||
+ ist->dec_ctx->codec_type != AVMEDIA_TYPE_SUBTITLE)
+ // We wish to skip the stream that causes the heartbeat,
+ // output streams without an input stream, streams not decoded
+ // (as fix_sub_duration is only done for decoded subtitles) as
+ // well as non-subtitle streams.
+ continue;
+
+ if ((ret = fix_sub_duration_heartbeat(ist, signal_pts)) < 0)
+ return ret;
+ }
+
+ return 0;
+}
+
+static int transcode_subtitles(InputStream *ist, const AVPacket *pkt,
+ int *got_output, int *decode_failed)
+{
+ AVSubtitle subtitle;
+ int ret = avcodec_decode_subtitle2(ist->dec_ctx,
+ &subtitle, got_output, pkt);
+
+ check_decode_result(NULL, got_output, ret);
+
+ if (ret < 0 || !*got_output) {
+ *decode_failed = 1;
+ if (!pkt->size)
+ sub2video_flush(ist);
+ return ret;
+ }
+
+ ist->frames_decoded++;
+
+ return process_subtitle(ist, &subtitle, got_output);
+}
+
static int send_filter_eof(InputStream *ist)
{
int i, ret;
+ /* TODO keep pts also in stream time base to avoid converting back */
+ int64_t pts = av_rescale_q_rnd(ist->pts, AV_TIME_BASE_Q, ist->st->time_base,
+ AV_ROUND_NEAR_INF | AV_ROUND_PASS_MINMAX);
+
for (i = 0; i < ist->nb_filters; i++) {
- ret = av_buffersrc_add_frame(ist->filters[i]->filter, NULL);
+ ret = ifilter_send_eof(ist->filters[i], pts);
if (ret < 0)
return ret;
}
@@ -2277,14 +2567,19 @@ static int send_filter_eof(InputStream *ist)
/* pkt = NULL means EOF (needed to flush decoder buffers) */
static int process_input_packet(InputStream *ist, const AVPacket *pkt, int no_eof)
{
- int ret = 0, i;
- int got_output = 0;
+ const AVCodecParameters *par = ist->par;
+ int ret = 0;
+ int repeating = 0;
+ int eof_reached = 0;
+
+ AVPacket *avpkt = ist->pkt;
- AVPacket avpkt;
if (!ist->saw_first_ts) {
+ ist->first_dts =
ist->dts = ist->st->avg_frame_rate.num ? - ist->dec_ctx->has_b_frames * AV_TIME_BASE / av_q2d(ist->st->avg_frame_rate) : 0;
ist->pts = 0;
if (pkt && pkt->pts != AV_NOPTS_VALUE && !ist->decoding_needed) {
+ ist->first_dts =
ist->dts += av_rescale_q(pkt->pts, ist->st->time_base, AV_TIME_BASE_Q);
ist->pts = ist->dts; //unused but better to set it to a value thats not totally wrong
}
@@ -2296,96 +2591,118 @@ static int process_input_packet(InputStream *ist, const AVPacket *pkt, int no_eo
if (ist->next_pts == AV_NOPTS_VALUE)
ist->next_pts = ist->pts;
- if (!pkt) {
- /* EOF handling */
- av_init_packet(&avpkt);
- avpkt.data = NULL;
- avpkt.size = 0;
- goto handle_eof;
- } else {
- avpkt = *pkt;
+ if (pkt) {
+ av_packet_unref(avpkt);
+ ret = av_packet_ref(avpkt, pkt);
+ if (ret < 0)
+ return ret;
}
- if (pkt->dts != AV_NOPTS_VALUE) {
+ if (pkt && pkt->dts != AV_NOPTS_VALUE) {
ist->next_dts = ist->dts = av_rescale_q(pkt->dts, ist->st->time_base, AV_TIME_BASE_Q);
- if (ist->dec_ctx->codec_type != AVMEDIA_TYPE_VIDEO || !ist->decoding_needed)
+ if (par->codec_type != AVMEDIA_TYPE_VIDEO || !ist->decoding_needed)
ist->next_pts = ist->pts = ist->dts;
}
// while we have more to decode or while the decoder did output something on EOF
- while (ist->decoding_needed && (avpkt.size > 0 || (!pkt && got_output))) {
- int duration;
- handle_eof:
+ while (ist->decoding_needed) {
+ int64_t duration_dts = 0;
+ int64_t duration_pts = 0;
+ int got_output = 0;
+ int decode_failed = 0;
ist->pts = ist->next_pts;
ist->dts = ist->next_dts;
- if (avpkt.size && avpkt.size != pkt->size &&
- !(ist->dec->capabilities & AV_CODEC_CAP_SUBFRAMES)) {
- av_log(NULL, ist->showed_multi_packet_warning ? AV_LOG_VERBOSE : AV_LOG_WARNING,
- "Multiple frames in a packet from stream %d\n", pkt->stream_index);
- ist->showed_multi_packet_warning = 1;
- }
-
- switch (ist->dec_ctx->codec_type) {
+ switch (par->codec_type) {
case AVMEDIA_TYPE_AUDIO:
- ret = decode_audio (ist, &avpkt, &got_output);
+ ret = decode_audio (ist, repeating ? NULL : avpkt, &got_output,
+ &decode_failed);
+ av_packet_unref(avpkt);
break;
case AVMEDIA_TYPE_VIDEO:
- ret = decode_video (ist, &avpkt, &got_output);
- if (avpkt.duration) {
- duration = av_rescale_q(avpkt.duration, ist->st->time_base, AV_TIME_BASE_Q);
- } else if(ist->dec_ctx->framerate.num != 0 && ist->dec_ctx->framerate.den != 0) {
- int ticks= av_stream_get_parser(ist->st) ? av_stream_get_parser(ist->st)->repeat_pict+1 : ist->dec_ctx->ticks_per_frame;
- duration = ((int64_t)AV_TIME_BASE *
- ist->dec_ctx->framerate.den * ticks) /
- ist->dec_ctx->framerate.num / ist->dec_ctx->ticks_per_frame;
- } else
- duration = 0;
+ ret = decode_video (ist, repeating ? NULL : avpkt, &got_output, &duration_pts, !pkt,
+ &decode_failed);
+ if (!repeating || !pkt || got_output) {
+ if (pkt && pkt->duration) {
+ duration_dts = av_rescale_q(pkt->duration, ist->st->time_base, AV_TIME_BASE_Q);
+ } else if(ist->dec_ctx->framerate.num != 0 && ist->dec_ctx->framerate.den != 0) {
+ int ticks = ist->last_pkt_repeat_pict >= 0 ?
+ ist->last_pkt_repeat_pict + 1 :
+ ist->dec_ctx->ticks_per_frame;
+ duration_dts = ((int64_t)AV_TIME_BASE *
+ ist->dec_ctx->framerate.den * ticks) /
+ ist->dec_ctx->framerate.num / ist->dec_ctx->ticks_per_frame;
+ }
- if(ist->dts != AV_NOPTS_VALUE && duration) {
- ist->next_dts += duration;
- }else
- ist->next_dts = AV_NOPTS_VALUE;
+ if(ist->dts != AV_NOPTS_VALUE && duration_dts) {
+ ist->next_dts += duration_dts;
+ }else
+ ist->next_dts = AV_NOPTS_VALUE;
+ }
- if (got_output)
- ist->next_pts += duration; //FIXME the duration is not correct in some cases
+ if (got_output) {
+ if (duration_pts > 0) {
+ ist->next_pts += av_rescale_q(duration_pts, ist->st->time_base, AV_TIME_BASE_Q);
+ } else {
+ ist->next_pts += duration_dts;
+ }
+ }
+ av_packet_unref(avpkt);
break;
case AVMEDIA_TYPE_SUBTITLE:
- ret = transcode_subtitles(ist, &avpkt, &got_output);
+ if (repeating)
+ break;
+ ret = transcode_subtitles(ist, avpkt, &got_output, &decode_failed);
+ if (!pkt && ret >= 0)
+ ret = AVERROR_EOF;
+ av_packet_unref(avpkt);
break;
default:
return -1;
}
+ if (ret == AVERROR_EOF) {
+ eof_reached = 1;
+ break;
+ }
+
if (ret < 0) {
- av_log(NULL, AV_LOG_ERROR, "Error while decoding stream #%d:%d: %s\n",
- ist->file_index, ist->st->index, av_err2str(ret));
- if (exit_on_error)
+ if (decode_failed) {
+ av_log(NULL, AV_LOG_ERROR, "Error while decoding stream #%d:%d: %s\n",
+ ist->file_index, ist->st->index, av_err2str(ret));
+ } else {
+ av_log(NULL, AV_LOG_FATAL, "Error while processing the decoded "
+ "data for stream #%d:%d\n", ist->file_index, ist->st->index);
+ }
+ if (!decode_failed || exit_on_error)
exit_program(1);
break;
}
- avpkt.dts=
- avpkt.pts= AV_NOPTS_VALUE;
+ if (got_output)
+ ist->got_output = 1;
- // touch data and size only if not EOF
- if (pkt) {
- if(ist->dec_ctx->codec_type != AVMEDIA_TYPE_AUDIO)
- ret = avpkt.size;
- avpkt.data += ret;
- avpkt.size -= ret;
- }
- if (!got_output) {
- continue;
- }
- if (got_output && !pkt)
+ if (!got_output)
+ break;
+
+ // During draining, we might get multiple output frames in this loop.
+ // ffmpeg.c does not drain the filter chain on configuration changes,
+ // which means if we send multiple frames at once to the filters, and
+ // one of those frames changes configuration, the buffered frames will
+ // be lost. This can upset certain FATE tests.
+ // Decode only 1 frame per call on EOF to appease these FATE tests.
+ // The ideal solution would be to rewrite decoding to use the new
+ // decoding API in a better way.
+ if (!pkt)
break;
+
+ repeating = 1;
}
/* after flushing, send an EOF on all the filter inputs attached to the stream */
/* except when looping we need to flush but not to send an EOF */
- if (!pkt && ist->decoding_needed && !got_output && !no_eof) {
+ if (!pkt && ist->decoding_needed && eof_reached && !no_eof) {
int ret = send_filter_eof(ist);
if (ret < 0) {
av_log(NULL, AV_LOG_FATAL, "Error marking filters as finished\n");
@@ -2394,12 +2711,17 @@ static int process_input_packet(InputStream *ist, const AVPacket *pkt, int no_eo
}
/* handle stream copy */
- if (!ist->decoding_needed) {
+ if (!ist->decoding_needed && pkt) {
ist->dts = ist->next_dts;
- switch (ist->dec_ctx->codec_type) {
+ switch (par->codec_type) {
case AVMEDIA_TYPE_AUDIO:
- ist->next_dts += ((int64_t)AV_TIME_BASE * ist->dec_ctx->frame_size) /
- ist->dec_ctx->sample_rate;
+ av_assert1(pkt->duration >= 0);
+ if (par->sample_rate) {
+ ist->next_dts += ((int64_t)AV_TIME_BASE * par->frame_size) /
+ par->sample_rate;
+ } else {
+ ist->next_dts += av_rescale_q(pkt->duration, ist->st->time_base, AV_TIME_BASE_Q);
+ }
break;
case AVMEDIA_TYPE_VIDEO:
if (ist->framerate.num) {
@@ -2410,7 +2732,9 @@ static int process_input_packet(InputStream *ist, const AVPacket *pkt, int no_eo
} else if (pkt->duration) {
ist->next_dts += av_rescale_q(pkt->duration, ist->st->time_base, AV_TIME_BASE_Q);
} else if(ist->dec_ctx->framerate.num != 0) {
- int ticks= av_stream_get_parser(ist->st) ? av_stream_get_parser(ist->st)->repeat_pict + 1 : ist->dec_ctx->ticks_per_frame;
+ int ticks = ist->last_pkt_repeat_pict >= 0 ?
+ ist->last_pkt_repeat_pict + 1 :
+ ist->dec_ctx->ticks_per_frame;
ist->next_dts += ((int64_t)AV_TIME_BASE *
ist->dec_ctx->framerate.den * ticks) /
ist->dec_ctx->framerate.num / ist->dec_ctx->ticks_per_frame;
@@ -2419,122 +2743,75 @@ static int process_input_packet(InputStream *ist, const AVPacket *pkt, int no_eo
}
ist->pts = ist->dts;
ist->next_pts = ist->next_dts;
- }
- for (i = 0; pkt && i < nb_output_streams; i++) {
- OutputStream *ost = output_streams[i];
+ } else if (!ist->decoding_needed)
+ eof_reached = 1;
- if (!check_output_constraints(ist, ost) || ost->encoding_needed)
+ for (OutputStream *ost = ost_iter(NULL); ost; ost = ost_iter(ost)) {
+ if (!check_output_constraints(ist, ost) || ost->enc_ctx ||
+ (!pkt && no_eof))
continue;
do_streamcopy(ist, ost, pkt);
}
- return got_output;
+ return !eof_reached;
}
-static void print_sdp(void)
+static enum AVPixelFormat get_format(AVCodecContext *s, const enum AVPixelFormat *pix_fmts)
{
- char sdp[16384];
- int i;
- int j;
- AVIOContext *sdp_pb;
- AVFormatContext **avc = av_malloc_array(nb_output_files, sizeof(*avc));
+ InputStream *ist = s->opaque;
+ const enum AVPixelFormat *p;
+ int ret;
- if (!avc)
- exit_program(1);
- for (i = 0, j = 0; i < nb_output_files; i++) {
- if (!strcmp(output_files[i]->ctx->oformat->name, "rtp")) {
- avc[j] = output_files[i]->ctx;
- j++;
- }
- }
+ for (p = pix_fmts; *p != AV_PIX_FMT_NONE; p++) {
+ const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(*p);
+ const AVCodecHWConfig *config = NULL;
+ int i;
- if (!j)
- goto fail;
+ if (!(desc->flags & AV_PIX_FMT_FLAG_HWACCEL))
+ break;
- av_sdp_create(avc, j, sdp, sizeof(sdp));
-
- if (!sdp_filename) {
- printf("SDP:\n%s\n", sdp);
- fflush(stdout);
- } else {
- if (avio_open2(&sdp_pb, sdp_filename, AVIO_FLAG_WRITE, &int_cb, NULL) < 0) {
- av_log(NULL, AV_LOG_ERROR, "Failed to open sdp file '%s'\n", sdp_filename);
- } else {
- avio_printf(sdp_pb, "SDP:\n%s", sdp);
- avio_closep(&sdp_pb);
- av_freep(&sdp_filename);
+ if (ist->hwaccel_id == HWACCEL_GENERIC ||
+ ist->hwaccel_id == HWACCEL_AUTO) {
+ for (i = 0;; i++) {
+ config = avcodec_get_hw_config(s->codec, i);
+ if (!config)
+ break;
+ if (!(config->methods &
+ AV_CODEC_HW_CONFIG_METHOD_HW_DEVICE_CTX))
+ continue;
+ if (config->pix_fmt == *p)
+ break;
+ }
}
- }
-
-fail:
- av_freep(&avc);
-}
-
-static const HWAccel *get_hwaccel(enum AVPixelFormat pix_fmt)
-{
- int i;
- for (i = 0; hwaccels[i].name; i++)
- if (hwaccels[i].pix_fmt == pix_fmt)
- return &hwaccels[i];
- return NULL;
-}
-
-static enum AVPixelFormat get_format(AVCodecContext *s, const enum AVPixelFormat *pix_fmts)
-{
- InputStream *ist = s->opaque;
- const enum AVPixelFormat *p;
- int ret;
-
- for (p = pix_fmts; *p != -1; p++) {
- const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(*p);
- const HWAccel *hwaccel;
+ if (config && config->device_type == ist->hwaccel_device_type) {
+ ret = hwaccel_decode_init(s);
+ if (ret < 0) {
+ if (ist->hwaccel_id == HWACCEL_GENERIC) {
+ av_log(NULL, AV_LOG_FATAL,
+ "%s hwaccel requested for input stream #%d:%d, "
+ "but cannot be initialized.\n",
+ av_hwdevice_get_type_name(config->device_type),
+ ist->file_index, ist->st->index);
+ return AV_PIX_FMT_NONE;
+ }
+ continue;
+ }
- if (!(desc->flags & AV_PIX_FMT_FLAG_HWACCEL))
+ ist->hwaccel_pix_fmt = *p;
break;
-
- hwaccel = get_hwaccel(*p);
- if (!hwaccel ||
- (ist->active_hwaccel_id && ist->active_hwaccel_id != hwaccel->id) ||
- (ist->hwaccel_id != HWACCEL_AUTO && ist->hwaccel_id != hwaccel->id))
- continue;
-
- ret = hwaccel->init(s);
- if (ret < 0) {
- if (ist->hwaccel_id == hwaccel->id) {
- av_log(NULL, AV_LOG_FATAL,
- "%s hwaccel requested for input stream #%d:%d, "
- "but cannot be initialized.\n", hwaccel->name,
- ist->file_index, ist->st->index);
- return AV_PIX_FMT_NONE;
- }
- continue;
}
- ist->active_hwaccel_id = hwaccel->id;
- ist->hwaccel_pix_fmt = *p;
- break;
}
return *p;
}
-static int get_buffer(AVCodecContext *s, AVFrame *frame, int flags)
-{
- InputStream *ist = s->opaque;
-
- if (ist->hwaccel_get_buffer && frame->format == ist->hwaccel_pix_fmt)
- return ist->hwaccel_get_buffer(s, frame, flags);
-
- return avcodec_default_get_buffer2(s, frame, flags);
-}
-
-static int init_input_stream(int ist_index, char *error, int error_len)
+static int init_input_stream(InputStream *ist, char *error, int error_len)
{
int ret;
- InputStream *ist = input_streams[ist_index];
if (ist->decoding_needed) {
- AVCodec *codec = ist->dec;
+ const AVCodec *codec = ist->dec;
if (!codec) {
snprintf(error, error_len, "Decoder (codec %s) not found for input stream #%d:%d",
avcodec_get_name(ist->dec_ctx->codec_id), ist->file_index, ist->st->index);
@@ -2543,10 +2820,7 @@ static int init_input_stream(int ist_index, char *error, int error_len)
ist->dec_ctx->opaque = ist;
ist->dec_ctx->get_format = get_format;
- ist->dec_ctx->get_buffer2 = get_buffer;
- ist->dec_ctx->thread_safe_callbacks = 1;
- av_opt_set_int(ist->dec_ctx, "refcounted_frames", 1, 0);
if (ist->dec_ctx->codec_id == AV_CODEC_ID_DVB_SUBTITLE &&
(ist->decoding_needed & DECODING_FOR_OST)) {
av_dict_set(&ist->decoder_opts, "compute_edt", "1", AV_DICT_DONT_OVERWRITE);
@@ -2554,8 +2828,24 @@ static int init_input_stream(int ist_index, char *error, int error_len)
av_log(NULL, AV_LOG_WARNING, "Warning using DVB subtitles for filtering and output at the same time is not fully supported, also see -compute_edt [0|1]\n");
}
+ /* Useful for subtitles retiming by lavf (FIXME), skipping samples in
+ * audio, and video decoders such as cuvid or mediacodec */
+ ist->dec_ctx->pkt_timebase = ist->st->time_base;
+
if (!av_dict_get(ist->decoder_opts, "threads", NULL, 0))
av_dict_set(&ist->decoder_opts, "threads", "auto", 0);
+ /* Attached pics are sparse, therefore we would not want to delay their decoding till EOF. */
+ if (ist->st->disposition & AV_DISPOSITION_ATTACHED_PIC)
+ av_dict_set(&ist->decoder_opts, "threads", "1", 0);
+
+ ret = hw_device_setup_for_decode(ist);
+ if (ret < 0) {
+ snprintf(error, error_len, "Device setup failed for "
+ "decoder on input stream #%d:%d : %s",
+ ist->file_index, ist->st->index, av_err2str(ret));
+ return ret;
+ }
+
if ((ret = avcodec_open2(ist->dec_ctx, codec, &ist->decoder_opts)) < 0) {
if (ret == AVERROR_EXPERIMENTAL)
abort_codec_experimental(codec, 0);
@@ -2575,662 +2865,516 @@ static int init_input_stream(int ist_index, char *error, int error_len)
return 0;
}
-static InputStream *get_input_stream(OutputStream *ost)
+static int init_output_stream_streamcopy(OutputStream *ost)
{
- if (ost->source_index >= 0)
- return input_streams[ost->source_index];
- return NULL;
-}
+ OutputFile *of = output_files[ost->file_index];
+ InputStream *ist = ost->ist;
+ InputFile *ifile = input_files[ist->file_index];
+ AVCodecParameters *par = ost->st->codecpar;
+ AVCodecContext *codec_ctx;
+ AVRational sar;
+ int i, ret;
+ uint32_t codec_tag = par->codec_tag;
-static int compare_int64(const void *a, const void *b)
-{
- return FFDIFFSIGN(*(const int64_t *)a, *(const int64_t *)b);
-}
+ av_assert0(ist && !ost->filter);
-static int init_output_stream(OutputStream *ost, char *error, int error_len)
-{
- int ret = 0;
-
- if (ost->encoding_needed) {
- AVCodec *codec = ost->enc;
- AVCodecContext *dec = NULL;
- InputStream *ist;
+ codec_ctx = avcodec_alloc_context3(NULL);
+ if (!codec_ctx)
+ return AVERROR(ENOMEM);
- if ((ist = get_input_stream(ost)))
- dec = ist->dec_ctx;
- if (dec && dec->subtitle_header) {
- /* ASS code assumes this buffer is null terminated so add extra byte. */
- ost->enc_ctx->subtitle_header = av_mallocz(dec->subtitle_header_size + 1);
- if (!ost->enc_ctx->subtitle_header)
- return AVERROR(ENOMEM);
- memcpy(ost->enc_ctx->subtitle_header, dec->subtitle_header, dec->subtitle_header_size);
- ost->enc_ctx->subtitle_header_size = dec->subtitle_header_size;
- }
- if (!av_dict_get(ost->encoder_opts, "threads", NULL, 0))
- av_dict_set(&ost->encoder_opts, "threads", "auto", 0);
- if (ost->enc->type == AVMEDIA_TYPE_AUDIO &&
- !codec->defaults &&
- !av_dict_get(ost->encoder_opts, "b", NULL, 0) &&
- !av_dict_get(ost->encoder_opts, "ab", NULL, 0))
- av_dict_set(&ost->encoder_opts, "b", "128000", 0);
+ ret = avcodec_parameters_to_context(codec_ctx, ist->par);
+ if (ret >= 0)
+ ret = av_opt_set_dict(codec_ctx, &ost->encoder_opts);
+ if (ret < 0) {
+ av_log(ost, AV_LOG_FATAL,
+ "Error setting up codec context options.\n");
+ avcodec_free_context(&codec_ctx);
+ return ret;
+ }
- if ((ret = avcodec_open2(ost->enc_ctx, codec, &ost->encoder_opts)) < 0) {
- if (ret == AVERROR_EXPERIMENTAL)
- abort_codec_experimental(codec, 1);
- snprintf(error, error_len,
- "Error while opening encoder for output stream #%d:%d - "
- "maybe incorrect parameters such as bit_rate, rate, width or height",
- ost->file_index, ost->index);
- return ret;
- }
- if (ost->enc->type == AVMEDIA_TYPE_AUDIO &&
- !(ost->enc->capabilities & AV_CODEC_CAP_VARIABLE_FRAME_SIZE))
- av_buffersink_set_frame_size(ost->filter->filter,
- ost->enc_ctx->frame_size);
- assert_avoptions(ost->encoder_opts);
- if (ost->enc_ctx->bit_rate && ost->enc_ctx->bit_rate < 1000)
- av_log(NULL, AV_LOG_WARNING, "The bitrate parameter is set too low."
- " It takes bits/s as argument, not kbits/s\n");
+ ret = avcodec_parameters_from_context(par, codec_ctx);
+ avcodec_free_context(&codec_ctx);
+ if (ret < 0) {
+ av_log(ost, AV_LOG_FATAL,
+ "Error getting reference codec parameters.\n");
+ return ret;
+ }
- ret = avcodec_copy_context(ost->st->codec, ost->enc_ctx);
- if (ret < 0) {
- av_log(NULL, AV_LOG_FATAL,
- "Error initializing the output stream codec context.\n");
- exit_program(1);
- }
+ if (!codec_tag) {
+ unsigned int codec_tag_tmp;
+ if (!of->format->codec_tag ||
+ av_codec_get_id (of->format->codec_tag, par->codec_tag) == par->codec_id ||
+ !av_codec_get_tag2(of->format->codec_tag, par->codec_id, &codec_tag_tmp))
+ codec_tag = par->codec_tag;
+ }
- if (ost->enc_ctx->nb_coded_side_data) {
- int i;
+ par->codec_tag = codec_tag;
- ost->st->side_data = av_realloc_array(NULL, ost->enc_ctx->nb_coded_side_data,
- sizeof(*ost->st->side_data));
- if (!ost->st->side_data)
- return AVERROR(ENOMEM);
+ if (!ost->frame_rate.num)
+ ost->frame_rate = ist->framerate;
- for (i = 0; i < ost->enc_ctx->nb_coded_side_data; i++) {
- const AVPacketSideData *sd_src = &ost->enc_ctx->coded_side_data[i];
- AVPacketSideData *sd_dst = &ost->st->side_data[i];
+ if (ost->frame_rate.num)
+ ost->st->avg_frame_rate = ost->frame_rate;
+ else
+ ost->st->avg_frame_rate = ist->st->avg_frame_rate;
- sd_dst->data = av_malloc(sd_src->size);
- if (!sd_dst->data)
- return AVERROR(ENOMEM);
- memcpy(sd_dst->data, sd_src->data, sd_src->size);
- sd_dst->size = sd_src->size;
- sd_dst->type = sd_src->type;
- ost->st->nb_side_data++;
- }
- }
+ ret = avformat_transfer_internal_stream_timing_info(of->format, ost->st, ist->st, copy_tb);
+ if (ret < 0)
+ return ret;
- // copy timebase while removing common factors
- ost->st->time_base = av_add_q(ost->enc_ctx->time_base, (AVRational){0, 1});
- ost->st->codec->codec= ost->enc_ctx->codec;
- } else {
- ret = av_opt_set_dict(ost->enc_ctx, &ost->encoder_opts);
- if (ret < 0) {
- av_log(NULL, AV_LOG_FATAL,
- "Error setting up codec context options.\n");
- return ret;
- }
- // copy timebase while removing common factors
- ost->st->time_base = av_add_q(ost->st->codec->time_base, (AVRational){0, 1});
+ // copy timebase while removing common factors
+ if (ost->st->time_base.num <= 0 || ost->st->time_base.den <= 0) {
+ if (ost->frame_rate.num)
+ ost->st->time_base = av_inv_q(ost->frame_rate);
+ else
+ ost->st->time_base = av_add_q(av_stream_get_codec_timebase(ost->st), (AVRational){0, 1});
}
- return ret;
-}
+ // copy estimated duration as a hint to the muxer
+ if (ost->st->duration <= 0 && ist->st->duration > 0)
+ ost->st->duration = av_rescale_q(ist->st->duration, ist->st->time_base, ost->st->time_base);
-static void parse_forced_key_frames(char *kf, OutputStream *ost,
- AVCodecContext *avctx)
-{
- char *p;
- int n = 1, i, size, index = 0;
- int64_t t, *pts;
-
- for (p = kf; *p; p++)
- if (*p == ',')
- n++;
- size = n;
- pts = av_malloc_array(size, sizeof(*pts));
- if (!pts) {
- av_log(NULL, AV_LOG_FATAL, "Could not allocate forced key frames array.\n");
- exit_program(1);
+ if (!ost->copy_prior_start) {
+ ost->ts_copy_start = (of->start_time == AV_NOPTS_VALUE) ?
+ 0 : of->start_time;
+ if (copy_ts && ifile->start_time != AV_NOPTS_VALUE) {
+ ost->ts_copy_start = FFMAX(ost->ts_copy_start,
+ ifile->start_time + ifile->ts_offset);
+ }
}
- p = kf;
- for (i = 0; i < n; i++) {
- char *next = strchr(p, ',');
-
- if (next)
- *next++ = 0;
-
- if (!memcmp(p, "chapters", 8)) {
-
- AVFormatContext *avf = output_files[ost->file_index]->ctx;
- int j;
-
- if (avf->nb_chapters > INT_MAX - size ||
- !(pts = av_realloc_f(pts, size += avf->nb_chapters - 1,
- sizeof(*pts)))) {
- av_log(NULL, AV_LOG_FATAL,
- "Could not allocate forced key frames array.\n");
- exit_program(1);
- }
- t = p[8] ? parse_time_or_die("force_key_frames", p + 8, 1) : 0;
- t = av_rescale_q(t, AV_TIME_BASE_Q, avctx->time_base);
-
- for (j = 0; j < avf->nb_chapters; j++) {
- AVChapter *c = avf->chapters[j];
- av_assert1(index < size);
- pts[index++] = av_rescale_q(c->start, c->time_base,
- avctx->time_base) + t;
- }
-
- } else {
-
- t = parse_time_or_die("force_key_frames", p, 1);
- av_assert1(index < size);
- pts[index++] = av_rescale_q(t, AV_TIME_BASE_Q, avctx->time_base);
+ if (ist->st->nb_side_data) {
+ for (i = 0; i < ist->st->nb_side_data; i++) {
+ const AVPacketSideData *sd_src = &ist->st->side_data[i];
+ uint8_t *dst_data;
+ dst_data = av_stream_new_side_data(ost->st, sd_src->type, sd_src->size);
+ if (!dst_data)
+ return AVERROR(ENOMEM);
+ memcpy(dst_data, sd_src->data, sd_src->size);
}
+ }
- p = next;
+#if FFMPEG_ROTATION_METADATA
+ if (ost->rotate_overridden) {
+ uint8_t *sd = av_stream_new_side_data(ost->st, AV_PKT_DATA_DISPLAYMATRIX,
+ sizeof(int32_t) * 9);
+ if (sd)
+ av_display_rotation_set((int32_t *)sd, -ost->rotate_override_value);
}
+#endif
- av_assert0(index == size);
- qsort(pts, size, sizeof(*pts), compare_int64);
- ost->forced_kf_count = size;
- ost->forced_kf_pts = pts;
-}
+ switch (par->codec_type) {
+ case AVMEDIA_TYPE_AUDIO:
+ if ((par->block_align == 1 || par->block_align == 1152 || par->block_align == 576) &&
+ par->codec_id == AV_CODEC_ID_MP3)
+ par->block_align = 0;
+ if (par->codec_id == AV_CODEC_ID_AC3)
+ par->block_align = 0;
+ break;
+ case AVMEDIA_TYPE_VIDEO:
+ if (ost->frame_aspect_ratio.num) { // overridden by the -aspect cli option
+ sar =
+ av_mul_q(ost->frame_aspect_ratio,
+ (AVRational){ par->height, par->width });
+ av_log(ost, AV_LOG_WARNING, "Overriding aspect ratio "
+ "with stream copy may produce invalid files\n");
+ }
+ else if (ist->st->sample_aspect_ratio.num)
+ sar = ist->st->sample_aspect_ratio;
+ else
+ sar = par->sample_aspect_ratio;
+ ost->st->sample_aspect_ratio = par->sample_aspect_ratio = sar;
+ ost->st->avg_frame_rate = ist->st->avg_frame_rate;
+ ost->st->r_frame_rate = ist->st->r_frame_rate;
+ break;
+ }
-static void report_new_stream(int input_index, AVPacket *pkt)
-{
- InputFile *file = input_files[input_index];
- AVStream *st = file->ctx->streams[pkt->stream_index];
+ ost->mux_timebase = ist->st->time_base;
- if (pkt->stream_index < file->nb_streams_warn)
- return;
- av_log(file->ctx, AV_LOG_WARNING,
- "New %s stream %d:%d at pos:%"PRId64" and DTS:%ss\n",
- av_get_media_type_string(st->codec->codec_type),
- input_index, pkt->stream_index,
- pkt->pos, av_ts2timestr(pkt->dts, &st->time_base));
- file->nb_streams_warn = pkt->stream_index + 1;
+ return 0;
}
static void set_encoder_id(OutputFile *of, OutputStream *ost)
{
- AVDictionaryEntry *e;
-
+ const char *cname = ost->enc_ctx->codec->name;
uint8_t *encoder_string;
int encoder_string_len;
- int format_flags = 0;
- int codec_flags = 0;
if (av_dict_get(ost->st->metadata, "encoder", NULL, 0))
return;
- e = av_dict_get(of->opts, "fflags", NULL, 0);
- if (e) {
- const AVOption *o = av_opt_find(of->ctx, "fflags", NULL, 0, 0);
- if (!o)
- return;
- av_opt_eval_flags(of->ctx, o, e->value, &format_flags);
- }
- e = av_dict_get(ost->encoder_opts, "flags", NULL, 0);
- if (e) {
- const AVOption *o = av_opt_find(ost->enc_ctx, "flags", NULL, 0, 0);
- if (!o)
- return;
- av_opt_eval_flags(ost->enc_ctx, o, e->value, &codec_flags);
- }
-
- encoder_string_len = sizeof(LIBAVCODEC_IDENT) + strlen(ost->enc->name) + 2;
+ encoder_string_len = sizeof(LIBAVCODEC_IDENT) + strlen(cname) + 2;
encoder_string = av_mallocz(encoder_string_len);
if (!encoder_string)
- exit_program(1);
+ report_and_exit(AVERROR(ENOMEM));
- if (!(format_flags & AVFMT_FLAG_BITEXACT) && !(codec_flags & AV_CODEC_FLAG_BITEXACT))
+ if (!of->bitexact && !ost->bitexact)
av_strlcpy(encoder_string, LIBAVCODEC_IDENT " ", encoder_string_len);
else
av_strlcpy(encoder_string, "Lavc ", encoder_string_len);
- av_strlcat(encoder_string, ost->enc->name, encoder_string_len);
+ av_strlcat(encoder_string, cname, encoder_string_len);
av_dict_set(&ost->st->metadata, "encoder", encoder_string,
AV_DICT_DONT_STRDUP_VAL | AV_DICT_DONT_OVERWRITE);
}
-static int transcode_init(void)
+static void init_encoder_time_base(OutputStream *ost, AVRational default_time_base)
{
- int ret = 0, i, j, k;
- AVFormatContext *oc;
- OutputStream *ost;
- InputStream *ist;
- char error[1024] = {0};
- int want_sdp = 1;
+ InputStream *ist = ost->ist;
+ AVCodecContext *enc_ctx = ost->enc_ctx;
- for (i = 0; i < nb_filtergraphs; i++) {
- FilterGraph *fg = filtergraphs[i];
- for (j = 0; j < fg->nb_outputs; j++) {
- OutputFilter *ofilter = fg->outputs[j];
- if (!ofilter->ost || ofilter->ost->source_index >= 0)
- continue;
- if (fg->nb_inputs != 1)
- continue;
- for (k = nb_input_streams-1; k >= 0 ; k--)
- if (fg->inputs[0]->ist == input_streams[k])
- break;
- ofilter->ost->source_index = k;
+ if (ost->enc_timebase.num > 0) {
+ enc_ctx->time_base = ost->enc_timebase;
+ return;
+ }
+
+ if (ost->enc_timebase.num < 0) {
+ if (ist) {
+ enc_ctx->time_base = ist->st->time_base;
+ return;
}
+
+ av_log(ost, AV_LOG_WARNING,
+ "Input stream data not available, using default time base\n");
}
- /* init framerate emulation */
- for (i = 0; i < nb_input_files; i++) {
- InputFile *ifile = input_files[i];
- if (ifile->rate_emu)
- for (j = 0; j < ifile->nb_streams; j++)
- input_streams[j + ifile->ist_index]->start = av_gettime_relative();
+ enc_ctx->time_base = default_time_base;
+}
+
+static int init_output_stream_encode(OutputStream *ost, AVFrame *frame)
+{
+ InputStream *ist = ost->ist;
+ AVCodecContext *enc_ctx = ost->enc_ctx;
+ AVCodecContext *dec_ctx = NULL;
+ OutputFile *of = output_files[ost->file_index];
+ int ret;
+
+ set_encoder_id(output_files[ost->file_index], ost);
+
+ if (ist) {
+ dec_ctx = ist->dec_ctx;
}
- /* for each output stream, we compute the right encoding parameters */
- for (i = 0; i < nb_output_streams; i++) {
- AVCodecContext *enc_ctx;
- AVCodecContext *dec_ctx = NULL;
- ost = output_streams[i];
- oc = output_files[ost->file_index]->ctx;
- ist = get_input_stream(ost);
+ if (enc_ctx->codec_type == AVMEDIA_TYPE_VIDEO) {
+ if (!ost->frame_rate.num)
+ ost->frame_rate = av_buffersink_get_frame_rate(ost->filter->filter);
+ if (!ost->frame_rate.num && !ost->max_frame_rate.num) {
+ ost->frame_rate = (AVRational){25, 1};
+ av_log(ost, AV_LOG_WARNING,
+ "No information "
+ "about the input framerate is available. Falling "
+ "back to a default value of 25fps. Use the -r option "
+ "if you want a different framerate.\n");
+ }
- if (ost->attachment_filename)
- continue;
+ if (ost->max_frame_rate.num &&
+ (av_q2d(ost->frame_rate) > av_q2d(ost->max_frame_rate) ||
+ !ost->frame_rate.den))
+ ost->frame_rate = ost->max_frame_rate;
+
+ if (enc_ctx->codec->supported_framerates && !ost->force_fps) {
+ int idx = av_find_nearest_q_idx(ost->frame_rate, enc_ctx->codec->supported_framerates);
+ ost->frame_rate = enc_ctx->codec->supported_framerates[idx];
+ }
+ // reduce frame rate for mpeg4 to be within the spec limits
+ if (enc_ctx->codec_id == AV_CODEC_ID_MPEG4) {
+ av_reduce(&ost->frame_rate.num, &ost->frame_rate.den,
+ ost->frame_rate.num, ost->frame_rate.den, 65535);
+ }
+ }
- enc_ctx = ost->stream_copy ? ost->st->codec : ost->enc_ctx;
+ switch (enc_ctx->codec_type) {
+ case AVMEDIA_TYPE_AUDIO:
+ enc_ctx->sample_fmt = av_buffersink_get_format(ost->filter->filter);
+ enc_ctx->sample_rate = av_buffersink_get_sample_rate(ost->filter->filter);
+ ret = av_buffersink_get_ch_layout(ost->filter->filter, &enc_ctx->ch_layout);
+ if (ret < 0)
+ return ret;
- if (ist) {
- dec_ctx = ist->dec_ctx;
+ if (ost->bits_per_raw_sample)
+ enc_ctx->bits_per_raw_sample = ost->bits_per_raw_sample;
+ else if (dec_ctx && ost->filter->graph->is_meta)
+ enc_ctx->bits_per_raw_sample = FFMIN(dec_ctx->bits_per_raw_sample,
+ av_get_bytes_per_sample(enc_ctx->sample_fmt) << 3);
- ost->st->disposition = ist->st->disposition;
- enc_ctx->bits_per_raw_sample = dec_ctx->bits_per_raw_sample;
- enc_ctx->chroma_sample_location = dec_ctx->chroma_sample_location;
- } else {
- for (j=0; jnb_streams; j++) {
- AVStream *st = oc->streams[j];
- if (st != ost->st && st->codec->codec_type == enc_ctx->codec_type)
- break;
- }
- if (j == oc->nb_streams)
- if (enc_ctx->codec_type == AVMEDIA_TYPE_AUDIO || enc_ctx->codec_type == AVMEDIA_TYPE_VIDEO)
- ost->st->disposition = AV_DISPOSITION_DEFAULT;
+ init_encoder_time_base(ost, av_make_q(1, enc_ctx->sample_rate));
+ break;
+
+ case AVMEDIA_TYPE_VIDEO:
+ init_encoder_time_base(ost, av_inv_q(ost->frame_rate));
+
+ if (!(enc_ctx->time_base.num && enc_ctx->time_base.den))
+ enc_ctx->time_base = av_buffersink_get_time_base(ost->filter->filter);
+ if ( av_q2d(enc_ctx->time_base) < 0.001 && ost->vsync_method != VSYNC_PASSTHROUGH
+ && (ost->vsync_method == VSYNC_CFR || ost->vsync_method == VSYNC_VSCFR ||
+ (ost->vsync_method == VSYNC_AUTO && !(of->format->flags & AVFMT_VARIABLE_FPS)))){
+ av_log(ost, AV_LOG_WARNING, "Frame rate very high for a muxer not efficiently supporting it.\n"
+ "Please consider specifying a lower framerate, a different muxer or "
+ "setting vsync/fps_mode to vfr\n");
}
- if (ost->stream_copy) {
- AVRational sar;
- uint64_t extra_size;
+ enc_ctx->width = av_buffersink_get_w(ost->filter->filter);
+ enc_ctx->height = av_buffersink_get_h(ost->filter->filter);
+ enc_ctx->sample_aspect_ratio = ost->st->sample_aspect_ratio =
+ ost->frame_aspect_ratio.num ? // overridden by the -aspect cli option
+ av_mul_q(ost->frame_aspect_ratio, (AVRational){ enc_ctx->height, enc_ctx->width }) :
+ av_buffersink_get_sample_aspect_ratio(ost->filter->filter);
+
+ enc_ctx->pix_fmt = av_buffersink_get_format(ost->filter->filter);
+
+ if (ost->bits_per_raw_sample)
+ enc_ctx->bits_per_raw_sample = ost->bits_per_raw_sample;
+ else if (dec_ctx && ost->filter->graph->is_meta)
+ enc_ctx->bits_per_raw_sample = FFMIN(dec_ctx->bits_per_raw_sample,
+ av_pix_fmt_desc_get(enc_ctx->pix_fmt)->comp[0].depth);
+
+ if (frame) {
+ enc_ctx->color_range = frame->color_range;
+ enc_ctx->color_primaries = frame->color_primaries;
+ enc_ctx->color_trc = frame->color_trc;
+ enc_ctx->colorspace = frame->colorspace;
+ enc_ctx->chroma_sample_location = frame->chroma_location;
+ }
- av_assert0(ist && !ost->filter);
+ enc_ctx->framerate = ost->frame_rate;
- extra_size = (uint64_t)dec_ctx->extradata_size + AV_INPUT_BUFFER_PADDING_SIZE;
+ ost->st->avg_frame_rate = ost->frame_rate;
- if (extra_size > INT_MAX) {
- return AVERROR(EINVAL);
- }
+ // Field order: autodetection
+ if (frame) {
+ if (enc_ctx->flags & (AV_CODEC_FLAG_INTERLACED_DCT | AV_CODEC_FLAG_INTERLACED_ME) &&
+ ost->top_field_first >= 0)
+ frame->top_field_first = !!ost->top_field_first;
- /* if stream_copy is selected, no need to decode or encode */
- enc_ctx->codec_id = dec_ctx->codec_id;
- enc_ctx->codec_type = dec_ctx->codec_type;
+ if (frame->interlaced_frame) {
+ if (enc_ctx->codec->id == AV_CODEC_ID_MJPEG)
+ enc_ctx->field_order = frame->top_field_first ? AV_FIELD_TT:AV_FIELD_BB;
+ else
+ enc_ctx->field_order = frame->top_field_first ? AV_FIELD_TB:AV_FIELD_BT;
+ } else
+ enc_ctx->field_order = AV_FIELD_PROGRESSIVE;
+ }
- if (!enc_ctx->codec_tag) {
- unsigned int codec_tag;
- if (!oc->oformat->codec_tag ||
- av_codec_get_id (oc->oformat->codec_tag, dec_ctx->codec_tag) == enc_ctx->codec_id ||
- !av_codec_get_tag2(oc->oformat->codec_tag, dec_ctx->codec_id, &codec_tag))
- enc_ctx->codec_tag = dec_ctx->codec_tag;
- }
+ // Field order: override
+ if (ost->top_field_first == 0) {
+ enc_ctx->field_order = AV_FIELD_BB;
+ } else if (ost->top_field_first == 1) {
+ enc_ctx->field_order = AV_FIELD_TT;
+ }
- enc_ctx->bit_rate = dec_ctx->bit_rate;
- enc_ctx->rc_max_rate = dec_ctx->rc_max_rate;
- enc_ctx->rc_buffer_size = dec_ctx->rc_buffer_size;
- enc_ctx->field_order = dec_ctx->field_order;
- if (dec_ctx->extradata_size) {
- enc_ctx->extradata = av_mallocz(extra_size);
- if (!enc_ctx->extradata) {
- return AVERROR(ENOMEM);
- }
- memcpy(enc_ctx->extradata, dec_ctx->extradata, dec_ctx->extradata_size);
+ break;
+ case AVMEDIA_TYPE_SUBTITLE:
+ enc_ctx->time_base = AV_TIME_BASE_Q;
+ if (!enc_ctx->width) {
+ enc_ctx->width = ost->ist->par->width;
+ enc_ctx->height = ost->ist->par->height;
+ }
+ if (dec_ctx && dec_ctx->subtitle_header) {
+ /* ASS code assumes this buffer is null terminated so add extra byte. */
+ ost->enc_ctx->subtitle_header = av_mallocz(dec_ctx->subtitle_header_size + 1);
+ if (!ost->enc_ctx->subtitle_header)
+ return AVERROR(ENOMEM);
+ memcpy(ost->enc_ctx->subtitle_header, dec_ctx->subtitle_header,
+ dec_ctx->subtitle_header_size);
+ ost->enc_ctx->subtitle_header_size = dec_ctx->subtitle_header_size;
+ }
+ if (ist && ist->dec->type == AVMEDIA_TYPE_SUBTITLE &&
+ enc_ctx->codec_type == AVMEDIA_TYPE_SUBTITLE) {
+ int input_props = 0, output_props = 0;
+ AVCodecDescriptor const *input_descriptor =
+ avcodec_descriptor_get(ist->dec->id);
+ AVCodecDescriptor const *output_descriptor =
+ avcodec_descriptor_get(ost->enc_ctx->codec_id);
+ if (input_descriptor)
+ input_props = input_descriptor->props & (AV_CODEC_PROP_TEXT_SUB | AV_CODEC_PROP_BITMAP_SUB);
+ if (output_descriptor)
+ output_props = output_descriptor->props & (AV_CODEC_PROP_TEXT_SUB | AV_CODEC_PROP_BITMAP_SUB);
+ if (input_props && output_props && input_props != output_props) {
+ av_log(ost, AV_LOG_ERROR,
+ "Subtitle encoding currently only possible from text to text "
+ "or bitmap to bitmap");
+ return AVERROR_INVALIDDATA;
}
- enc_ctx->extradata_size= dec_ctx->extradata_size;
- enc_ctx->bits_per_coded_sample = dec_ctx->bits_per_coded_sample;
+ }
- enc_ctx->time_base = ist->st->time_base;
- /*
- * Avi is a special case here because it supports variable fps but
- * having the fps and timebase differe significantly adds quite some
- * overhead
- */
- if(!strcmp(oc->oformat->name, "avi")) {
- if ( copy_tb<0 && av_q2d(ist->st->r_frame_rate) >= av_q2d(ist->st->avg_frame_rate)
- && 0.5/av_q2d(ist->st->r_frame_rate) > av_q2d(ist->st->time_base)
- && 0.5/av_q2d(ist->st->r_frame_rate) > av_q2d(dec_ctx->time_base)
- && av_q2d(ist->st->time_base) < 1.0/500 && av_q2d(dec_ctx->time_base) < 1.0/500
- || copy_tb==2){
- enc_ctx->time_base.num = ist->st->r_frame_rate.den;
- enc_ctx->time_base.den = 2*ist->st->r_frame_rate.num;
- enc_ctx->ticks_per_frame = 2;
- } else if ( copy_tb<0 && av_q2d(dec_ctx->time_base)*dec_ctx->ticks_per_frame > 2*av_q2d(ist->st->time_base)
- && av_q2d(ist->st->time_base) < 1.0/500
- || copy_tb==0){
- enc_ctx->time_base = dec_ctx->time_base;
- enc_ctx->time_base.num *= dec_ctx->ticks_per_frame;
- enc_ctx->time_base.den *= 2;
- enc_ctx->ticks_per_frame = 2;
- }
- } else if(!(oc->oformat->flags & AVFMT_VARIABLE_FPS)
- && strcmp(oc->oformat->name, "mov") && strcmp(oc->oformat->name, "mp4") && strcmp(oc->oformat->name, "3gp")
- && strcmp(oc->oformat->name, "3g2") && strcmp(oc->oformat->name, "psp") && strcmp(oc->oformat->name, "ipod")
- && strcmp(oc->oformat->name, "f4v")
- ) {
- if( copy_tb<0 && dec_ctx->time_base.den
- && av_q2d(dec_ctx->time_base)*dec_ctx->ticks_per_frame > av_q2d(ist->st->time_base)
- && av_q2d(ist->st->time_base) < 1.0/500
- || copy_tb==0){
- enc_ctx->time_base = dec_ctx->time_base;
- enc_ctx->time_base.num *= dec_ctx->ticks_per_frame;
- }
- }
- if ( enc_ctx->codec_tag == AV_RL32("tmcd")
- && dec_ctx->time_base.num < dec_ctx->time_base.den
- && dec_ctx->time_base.num > 0
- && 121LL*dec_ctx->time_base.num > dec_ctx->time_base.den) {
- enc_ctx->time_base = dec_ctx->time_base;
- }
+ break;
+ case AVMEDIA_TYPE_DATA:
+ break;
+ default:
+ abort();
+ break;
+ }
- if (!ost->frame_rate.num)
- ost->frame_rate = ist->framerate;
- if(ost->frame_rate.num)
- enc_ctx->time_base = av_inv_q(ost->frame_rate);
+ if (ost->bitexact)
+ enc_ctx->flags |= AV_CODEC_FLAG_BITEXACT;
- av_reduce(&enc_ctx->time_base.num, &enc_ctx->time_base.den,
- enc_ctx->time_base.num, enc_ctx->time_base.den, INT_MAX);
+ if (ost->sq_idx_encode >= 0)
+ sq_set_tb(of->sq_encode, ost->sq_idx_encode, enc_ctx->time_base);
- if (ist->st->nb_side_data) {
- ost->st->side_data = av_realloc_array(NULL, ist->st->nb_side_data,
- sizeof(*ist->st->side_data));
- if (!ost->st->side_data)
- return AVERROR(ENOMEM);
+ ost->mux_timebase = enc_ctx->time_base;
- ost->st->nb_side_data = 0;
- for (j = 0; j < ist->st->nb_side_data; j++) {
- const AVPacketSideData *sd_src = &ist->st->side_data[j];
- AVPacketSideData *sd_dst = &ost->st->side_data[ost->st->nb_side_data];
+ return 0;
+}
- if (ost->rotate_overridden && sd_src->type == AV_PKT_DATA_DISPLAYMATRIX)
- continue;
+static int init_output_stream(OutputStream *ost, AVFrame *frame,
+ char *error, int error_len)
+{
+ int ret = 0;
- sd_dst->data = av_malloc(sd_src->size);
- if (!sd_dst->data)
- return AVERROR(ENOMEM);
- memcpy(sd_dst->data, sd_src->data, sd_src->size);
- sd_dst->size = sd_src->size;
- sd_dst->type = sd_src->type;
- ost->st->nb_side_data++;
- }
- }
+ if (ost->enc_ctx) {
+ const AVCodec *codec = ost->enc_ctx->codec;
+ InputStream *ist = ost->ist;
- ost->parser = av_parser_init(enc_ctx->codec_id);
+ ret = init_output_stream_encode(ost, frame);
+ if (ret < 0)
+ return ret;
- switch (enc_ctx->codec_type) {
- case AVMEDIA_TYPE_AUDIO:
- if (audio_volume != 256) {
- av_log(NULL, AV_LOG_FATAL, "-acodec copy and -vol are incompatible (frames are not decoded)\n");
- exit_program(1);
- }
- enc_ctx->channel_layout = dec_ctx->channel_layout;
- enc_ctx->sample_rate = dec_ctx->sample_rate;
- enc_ctx->channels = dec_ctx->channels;
- enc_ctx->frame_size = dec_ctx->frame_size;
- enc_ctx->audio_service_type = dec_ctx->audio_service_type;
- enc_ctx->block_align = dec_ctx->block_align;
- enc_ctx->initial_padding = dec_ctx->delay;
- enc_ctx->profile = dec_ctx->profile;
-#if FF_API_AUDIOENC_DELAY
- enc_ctx->delay = dec_ctx->delay;
-#endif
- if((enc_ctx->block_align == 1 || enc_ctx->block_align == 1152 || enc_ctx->block_align == 576) && enc_ctx->codec_id == AV_CODEC_ID_MP3)
- enc_ctx->block_align= 0;
- if(enc_ctx->codec_id == AV_CODEC_ID_AC3)
- enc_ctx->block_align= 0;
- break;
- case AVMEDIA_TYPE_VIDEO:
- enc_ctx->pix_fmt = dec_ctx->pix_fmt;
- enc_ctx->width = dec_ctx->width;
- enc_ctx->height = dec_ctx->height;
- enc_ctx->has_b_frames = dec_ctx->has_b_frames;
- if (ost->frame_aspect_ratio.num) { // overridden by the -aspect cli option
- sar =
- av_mul_q(ost->frame_aspect_ratio,
- (AVRational){ enc_ctx->height, enc_ctx->width });
- av_log(NULL, AV_LOG_WARNING, "Overriding aspect ratio "
- "with stream copy may produce invalid files\n");
- }
- else if (ist->st->sample_aspect_ratio.num)
- sar = ist->st->sample_aspect_ratio;
- else
- sar = dec_ctx->sample_aspect_ratio;
- ost->st->sample_aspect_ratio = enc_ctx->sample_aspect_ratio = sar;
- ost->st->avg_frame_rate = ist->st->avg_frame_rate;
- ost->st->r_frame_rate = ist->st->r_frame_rate;
- break;
- case AVMEDIA_TYPE_SUBTITLE:
- enc_ctx->width = dec_ctx->width;
- enc_ctx->height = dec_ctx->height;
- break;
- case AVMEDIA_TYPE_UNKNOWN:
- case AVMEDIA_TYPE_DATA:
- case AVMEDIA_TYPE_ATTACHMENT:
- break;
- default:
- abort();
- }
- } else {
- if (!ost->enc)
- ost->enc = avcodec_find_encoder(enc_ctx->codec_id);
- if (!ost->enc) {
- /* should only happen when a default codec is not present. */
- snprintf(error, sizeof(error), "Encoder (codec %s) not found for output stream #%d:%d",
- avcodec_get_name(ost->st->codec->codec_id), ost->file_index, ost->index);
- ret = AVERROR(EINVAL);
- goto dump_format;
- }
+ if (!av_dict_get(ost->encoder_opts, "threads", NULL, 0))
+ av_dict_set(&ost->encoder_opts, "threads", "auto", 0);
- set_encoder_id(output_files[ost->file_index], ost);
+ if (codec->capabilities & AV_CODEC_CAP_ENCODER_REORDERED_OPAQUE) {
+ ret = av_dict_set(&ost->encoder_opts, "flags", "+copy_opaque", AV_DICT_MULTIKEY);
+ if (ret < 0)
+ return ret;
+ }
-#if CONFIG_LIBMFX
- if (qsv_transcode_init(ost))
- exit_program(1);
-#endif
+ ret = hw_device_setup_for_encode(ost);
+ if (ret < 0) {
+ snprintf(error, error_len, "Device setup failed for "
+ "encoder on output stream #%d:%d : %s",
+ ost->file_index, ost->index, av_err2str(ret));
+ return ret;
+ }
- if (!ost->filter &&
- (enc_ctx->codec_type == AVMEDIA_TYPE_VIDEO ||
- enc_ctx->codec_type == AVMEDIA_TYPE_AUDIO)) {
- FilterGraph *fg;
- fg = init_simple_filtergraph(ist, ost);
- if (configure_filtergraph(fg)) {
- av_log(NULL, AV_LOG_FATAL, "Error opening filters!\n");
- exit_program(1);
- }
- }
+ if ((ret = avcodec_open2(ost->enc_ctx, codec, &ost->encoder_opts)) < 0) {
+ if (ret == AVERROR_EXPERIMENTAL)
+ abort_codec_experimental(codec, 1);
+ snprintf(error, error_len,
+ "Error while opening encoder for output stream #%d:%d - "
+ "maybe incorrect parameters such as bit_rate, rate, width or height",
+ ost->file_index, ost->index);
+ return ret;
+ }
+ if (codec->type == AVMEDIA_TYPE_AUDIO &&
+ !(codec->capabilities & AV_CODEC_CAP_VARIABLE_FRAME_SIZE))
+ av_buffersink_set_frame_size(ost->filter->filter,
+ ost->enc_ctx->frame_size);
+ assert_avoptions(ost->encoder_opts);
+ if (ost->enc_ctx->bit_rate && ost->enc_ctx->bit_rate < 1000 &&
+ ost->enc_ctx->codec_id != AV_CODEC_ID_CODEC2 /* don't complain about 700 bit/s modes */)
+ av_log(ost, AV_LOG_WARNING, "The bitrate parameter is set too low."
+ " It takes bits/s as argument, not kbits/s\n");
- if (enc_ctx->codec_type == AVMEDIA_TYPE_VIDEO) {
- if (!ost->frame_rate.num)
- ost->frame_rate = av_buffersink_get_frame_rate(ost->filter->filter);
- if (ist && !ost->frame_rate.num)
- ost->frame_rate = ist->framerate;
- if (ist && !ost->frame_rate.num)
- ost->frame_rate = ist->st->r_frame_rate;
- if (ist && !ost->frame_rate.num) {
- ost->frame_rate = (AVRational){25, 1};
- av_log(NULL, AV_LOG_WARNING,
- "No information "
- "about the input framerate is available. Falling "
- "back to a default value of 25fps for output stream #%d:%d. Use the -r option "
- "if you want a different framerate.\n",
- ost->file_index, ost->index);
- }
-// ost->frame_rate = ist->st->avg_frame_rate.num ? ist->st->avg_frame_rate : (AVRational){25, 1};
- if (ost->enc && ost->enc->supported_framerates && !ost->force_fps) {
- int idx = av_find_nearest_q_idx(ost->frame_rate, ost->enc->supported_framerates);
- ost->frame_rate = ost->enc->supported_framerates[idx];
- }
- // reduce frame rate for mpeg4 to be within the spec limits
- if (enc_ctx->codec_id == AV_CODEC_ID_MPEG4) {
- av_reduce(&ost->frame_rate.num, &ost->frame_rate.den,
- ost->frame_rate.num, ost->frame_rate.den, 65535);
- }
- }
+ ret = avcodec_parameters_from_context(ost->st->codecpar, ost->enc_ctx);
+ if (ret < 0) {
+ av_log(ost, AV_LOG_FATAL,
+ "Error initializing the output stream codec context.\n");
+ exit_program(1);
+ }
- switch (enc_ctx->codec_type) {
- case AVMEDIA_TYPE_AUDIO:
- enc_ctx->sample_fmt = ost->filter->filter->inputs[0]->format;
- enc_ctx->sample_rate = ost->filter->filter->inputs[0]->sample_rate;
- enc_ctx->channel_layout = ost->filter->filter->inputs[0]->channel_layout;
- enc_ctx->channels = avfilter_link_get_channels(ost->filter->filter->inputs[0]);
- enc_ctx->time_base = (AVRational){ 1, enc_ctx->sample_rate };
- break;
- case AVMEDIA_TYPE_VIDEO:
- enc_ctx->time_base = av_inv_q(ost->frame_rate);
- if (!(enc_ctx->time_base.num && enc_ctx->time_base.den))
- enc_ctx->time_base = ost->filter->filter->inputs[0]->time_base;
- if ( av_q2d(enc_ctx->time_base) < 0.001 && video_sync_method != VSYNC_PASSTHROUGH
- && (video_sync_method == VSYNC_CFR || video_sync_method == VSYNC_VSCFR || (video_sync_method == VSYNC_AUTO && !(oc->oformat->flags & AVFMT_VARIABLE_FPS)))){
- av_log(oc, AV_LOG_WARNING, "Frame rate very high for a muxer not efficiently supporting it.\n"
- "Please consider specifying a lower framerate, a different muxer or -vsync 2\n");
- }
- for (j = 0; j < ost->forced_kf_count; j++)
- ost->forced_kf_pts[j] = av_rescale_q(ost->forced_kf_pts[j],
- AV_TIME_BASE_Q,
- enc_ctx->time_base);
-
- enc_ctx->width = ost->filter->filter->inputs[0]->w;
- enc_ctx->height = ost->filter->filter->inputs[0]->h;
- enc_ctx->sample_aspect_ratio = ost->st->sample_aspect_ratio =
- ost->frame_aspect_ratio.num ? // overridden by the -aspect cli option
- av_mul_q(ost->frame_aspect_ratio, (AVRational){ enc_ctx->height, enc_ctx->width }) :
- ost->filter->filter->inputs[0]->sample_aspect_ratio;
- if (!strncmp(ost->enc->name, "libx264", 7) &&
- enc_ctx->pix_fmt == AV_PIX_FMT_NONE &&
- ost->filter->filter->inputs[0]->format != AV_PIX_FMT_YUV420P)
- av_log(NULL, AV_LOG_WARNING,
- "No pixel format specified, %s for H.264 encoding chosen.\n"
- "Use -pix_fmt yuv420p for compatibility with outdated media players.\n",
- av_get_pix_fmt_name(ost->filter->filter->inputs[0]->format));
- if (!strncmp(ost->enc->name, "mpeg2video", 10) &&
- enc_ctx->pix_fmt == AV_PIX_FMT_NONE &&
- ost->filter->filter->inputs[0]->format != AV_PIX_FMT_YUV420P)
- av_log(NULL, AV_LOG_WARNING,
- "No pixel format specified, %s for MPEG-2 encoding chosen.\n"
- "Use -pix_fmt yuv420p for compatibility with outdated media players.\n",
- av_get_pix_fmt_name(ost->filter->filter->inputs[0]->format));
- enc_ctx->pix_fmt = ost->filter->filter->inputs[0]->format;
-
- ost->st->avg_frame_rate = ost->frame_rate;
-
- if (!dec_ctx ||
- enc_ctx->width != dec_ctx->width ||
- enc_ctx->height != dec_ctx->height ||
- enc_ctx->pix_fmt != dec_ctx->pix_fmt) {
- enc_ctx->bits_per_raw_sample = frame_bits_per_raw_sample;
- }
+ if (ost->enc_ctx->nb_coded_side_data) {
+ int i;
- if (ost->forced_keyframes) {
- if (!strncmp(ost->forced_keyframes, "expr:", 5)) {
- ret = av_expr_parse(&ost->forced_keyframes_pexpr, ost->forced_keyframes+5,
- forced_keyframes_const_names, NULL, NULL, NULL, NULL, 0, NULL);
- if (ret < 0) {
- av_log(NULL, AV_LOG_ERROR,
- "Invalid force_key_frames expression '%s'\n", ost->forced_keyframes+5);
- return ret;
- }
- ost->forced_keyframes_expr_const_values[FKF_N] = 0;
- ost->forced_keyframes_expr_const_values[FKF_N_FORCED] = 0;
- ost->forced_keyframes_expr_const_values[FKF_PREV_FORCED_N] = NAN;
- ost->forced_keyframes_expr_const_values[FKF_PREV_FORCED_T] = NAN;
-
- // Don't parse the 'forced_keyframes' in case of 'keep-source-keyframes',
- // parse it only for static kf timings
- } else if(strncmp(ost->forced_keyframes, "source", 6)) {
- parse_forced_key_frames(ost->forced_keyframes, ost, ost->enc_ctx);
- }
- }
- break;
- case AVMEDIA_TYPE_SUBTITLE:
- enc_ctx->time_base = (AVRational){1, 1000};
- if (!enc_ctx->width) {
- enc_ctx->width = input_streams[ost->source_index]->st->codec->width;
- enc_ctx->height = input_streams[ost->source_index]->st->codec->height;
+ for (i = 0; i < ost->enc_ctx->nb_coded_side_data; i++) {
+ const AVPacketSideData *sd_src = &ost->enc_ctx->coded_side_data[i];
+ uint8_t *dst_data;
+
+ dst_data = av_stream_new_side_data(ost->st, sd_src->type, sd_src->size);
+ if (!dst_data)
+ return AVERROR(ENOMEM);
+ memcpy(dst_data, sd_src->data, sd_src->size);
+ }
+ }
+
+ /*
+ * Add global input side data. For now this is naive, and copies it
+ * from the input stream's global side data. All side data should
+ * really be funneled over AVFrame and libavfilter, then added back to
+ * packet side data, and then potentially using the first packet for
+ * global side data.
+ */
+ if (ist) {
+ int i;
+ for (i = 0; i < ist->st->nb_side_data; i++) {
+ AVPacketSideData *sd = &ist->st->side_data[i];
+ if (sd->type != AV_PKT_DATA_CPB_PROPERTIES) {
+ uint8_t *dst = av_stream_new_side_data(ost->st, sd->type, sd->size);
+ if (!dst)
+ return AVERROR(ENOMEM);
+ memcpy(dst, sd->data, sd->size);
+ if (ist->autorotate && sd->type == AV_PKT_DATA_DISPLAYMATRIX)
+ av_display_rotation_set((int32_t *)dst, 0);
}
- break;
- case AVMEDIA_TYPE_DATA:
- break;
- default:
- abort();
- break;
}
}
- if (ost->disposition) {
- static const AVOption opts[] = {
- { "disposition" , NULL, 0, AV_OPT_TYPE_FLAGS, { .i64 = 0 }, INT64_MIN, INT64_MAX, .unit = "flags" },
- { "default" , NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AV_DISPOSITION_DEFAULT }, .unit = "flags" },
- { "dub" , NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AV_DISPOSITION_DUB }, .unit = "flags" },
- { "original" , NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AV_DISPOSITION_ORIGINAL }, .unit = "flags" },
- { "comment" , NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AV_DISPOSITION_COMMENT }, .unit = "flags" },
- { "lyrics" , NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AV_DISPOSITION_LYRICS }, .unit = "flags" },
- { "karaoke" , NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AV_DISPOSITION_KARAOKE }, .unit = "flags" },
- { "forced" , NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AV_DISPOSITION_FORCED }, .unit = "flags" },
- { "hearing_impaired" , NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AV_DISPOSITION_HEARING_IMPAIRED }, .unit = "flags" },
- { "visual_impaired" , NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AV_DISPOSITION_VISUAL_IMPAIRED }, .unit = "flags" },
- { "clean_effects" , NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AV_DISPOSITION_CLEAN_EFFECTS }, .unit = "flags" },
- { "captions" , NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AV_DISPOSITION_CAPTIONS }, .unit = "flags" },
- { "descriptions" , NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AV_DISPOSITION_DESCRIPTIONS }, .unit = "flags" },
- { "metadata" , NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AV_DISPOSITION_METADATA }, .unit = "flags" },
- { NULL },
- };
- static const AVClass class = {
- .class_name = "",
- .item_name = av_default_item_name,
- .option = opts,
- .version = LIBAVUTIL_VERSION_INT,
- };
- const AVClass *pclass = &class;
-
- ret = av_opt_eval_flags(&pclass, &opts[0], ost->disposition, &ost->st->disposition);
- if (ret < 0)
- goto dump_format;
- }
+ // copy timebase while removing common factors
+ if (ost->st->time_base.num <= 0 || ost->st->time_base.den <= 0)
+ ost->st->time_base = av_add_q(ost->enc_ctx->time_base, (AVRational){0, 1});
+
+ // copy estimated duration as a hint to the muxer
+ if (ost->st->duration <= 0 && ist && ist->st->duration > 0)
+ ost->st->duration = av_rescale_q(ist->st->duration, ist->st->time_base, ost->st->time_base);
+ } else if (ost->ist) {
+ ret = init_output_stream_streamcopy(ost);
+ if (ret < 0)
+ return ret;
}
- /* open each encoder */
- for (i = 0; i < nb_output_streams; i++) {
- ret = init_output_stream(output_streams[i], error, sizeof(error));
- if (ret < 0)
- goto dump_format;
+ ret = of_stream_init(output_files[ost->file_index], ost);
+ if (ret < 0)
+ return ret;
+
+ return ret;
+}
+
+static int transcode_init(void)
+{
+ int ret = 0;
+ char error[1024] = {0};
+
+ /* init framerate emulation */
+ for (int i = 0; i < nb_input_files; i++) {
+ InputFile *ifile = input_files[i];
+ if (ifile->readrate || ifile->rate_emu)
+ for (int j = 0; j < ifile->nb_streams; j++)
+ ifile->streams[j]->start = av_gettime_relative();
}
/* init input streams */
- for (i = 0; i < nb_input_streams; i++)
- if ((ret = init_input_stream(i, error, sizeof(error))) < 0) {
- for (i = 0; i < nb_output_streams; i++) {
- ost = output_streams[i];
- avcodec_close(ost->enc_ctx);
- }
+ for (InputStream *ist = ist_iter(NULL); ist; ist = ist_iter(ist))
+ if ((ret = init_input_stream(ist, error, sizeof(error))) < 0)
goto dump_format;
- }
+
+ /*
+ * initialize stream copy and subtitle/data streams.
+ * Encoded AVFrame based streams will get initialized as follows:
+ * - when the first AVFrame is received in do_video_out
+ * - just before the first AVFrame is received in either transcode_step
+ * or reap_filters due to us requiring the filter chain buffer sink
+ * to be configured with the correct audio frame size, which is only
+ * known after the encoder is initialized.
+ */
+ for (OutputStream *ost = ost_iter(NULL); ost; ost = ost_iter(ost)) {
+ if (ost->enc_ctx &&
+ (ost->st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO ||
+ ost->st->codecpar->codec_type == AVMEDIA_TYPE_AUDIO))
+ continue;
+
+ ret = init_output_stream_wrapper(ost, NULL, 0);
+ if (ret < 0)
+ goto dump_format;
+ }
/* discard unused programs */
- for (i = 0; i < nb_input_files; i++) {
+ for (int i = 0; i < nb_input_files; i++) {
InputFile *ifile = input_files[i];
- for (j = 0; j < ifile->ctx->nb_programs; j++) {
+ for (int j = 0; j < ifile->ctx->nb_programs; j++) {
AVProgram *p = ifile->ctx->programs[j];
int discard = AVDISCARD_ALL;
- for (k = 0; k < p->nb_stream_indexes; k++)
- if (!input_streams[ifile->ist_index + p->stream_index[k]]->discard) {
+ for (int k = 0; k < p->nb_stream_indexes; k++)
+ if (!ifile->streams[p->stream_index[k]]->discard) {
discard = AVDISCARD_DEFAULT;
break;
}
@@ -3238,38 +3382,12 @@ static int transcode_init(void)
}
}
- /* open files and write file headers */
- for (i = 0; i < nb_output_files; i++) {
- oc = output_files[i]->ctx;
- oc->interrupt_callback = int_cb;
- if ((ret = avformat_write_header(oc, &output_files[i]->opts)) < 0) {
- snprintf(error, sizeof(error),
- "Could not write header for output file #%d "
- "(incorrect codec parameters ?): %s",
- i, av_err2str(ret));
- ret = AVERROR(EINVAL);
- goto dump_format;
- }
-// assert_avoptions(output_files[i]->opts);
- if (strcmp(oc->oformat->name, "rtp")) {
- want_sdp = 0;
- }
- }
-
dump_format:
- /* dump the file output parameters - cannot be done before in case
- of stream copy */
- for (i = 0; i < nb_output_files; i++) {
- av_dump_format(output_files[i]->ctx, i, output_files[i]->ctx->filename, 1);
- }
-
/* dump the stream mapping */
av_log(NULL, AV_LOG_INFO, "Stream mapping:\n");
- for (i = 0; i < nb_input_streams; i++) {
- ist = input_streams[i];
-
- for (j = 0; j < ist->nb_filters; j++) {
- if (ist->filters[j]->graph->graph_desc) {
+ for (InputStream *ist = ist_iter(NULL); ist; ist = ist_iter(ist)) {
+ for (int j = 0; j < ist->nb_filters; j++) {
+ if (!filtergraph_is_simple(ist->filters[j]->graph)) {
av_log(NULL, AV_LOG_INFO, " Stream #%d:%d (%s) -> %s",
ist->file_index, ist->st->index, ist->dec ? ist->dec->name : "?",
ist->filters[j]->name);
@@ -3280,9 +3398,7 @@ static int transcode_init(void)
}
}
- for (i = 0; i < nb_output_streams; i++) {
- ost = output_streams[i];
-
+ for (OutputStream *ost = ost_iter(NULL); ost; ost = ost_iter(ost)) {
if (ost->attachment_filename) {
/* an attached file */
av_log(NULL, AV_LOG_INFO, " File %s -> Stream #%d:%d\n",
@@ -3290,31 +3406,25 @@ static int transcode_init(void)
continue;
}
- if (ost->filter && ost->filter->graph->graph_desc) {
+ if (ost->filter && !filtergraph_is_simple(ost->filter->graph)) {
/* output from a complex graph */
av_log(NULL, AV_LOG_INFO, " %s", ost->filter->name);
if (nb_filtergraphs > 1)
av_log(NULL, AV_LOG_INFO, " (graph %d)", ost->filter->graph->index);
av_log(NULL, AV_LOG_INFO, " -> Stream #%d:%d (%s)\n", ost->file_index,
- ost->index, ost->enc ? ost->enc->name : "?");
+ ost->index, ost->enc_ctx->codec->name);
continue;
}
av_log(NULL, AV_LOG_INFO, " Stream #%d:%d -> #%d:%d",
- input_streams[ost->source_index]->file_index,
- input_streams[ost->source_index]->st->index,
+ ost->ist->file_index,
+ ost->ist->st->index,
ost->file_index,
ost->index);
- if (ost->sync_ist != input_streams[ost->source_index])
- av_log(NULL, AV_LOG_INFO, " [sync #%d:%d]",
- ost->sync_ist->file_index,
- ost->sync_ist->st->index);
- if (ost->stream_copy)
- av_log(NULL, AV_LOG_INFO, " (copy)");
- else {
- const AVCodec *in_codec = input_streams[ost->source_index]->dec;
- const AVCodec *out_codec = ost->enc;
+ if (ost->enc_ctx) {
+ const AVCodec *in_codec = ost->ist->dec;
+ const AVCodec *out_codec = ost->enc_ctx->codec;
const char *decoder_name = "?";
const char *in_codec_name = "?";
const char *encoder_name = "?";
@@ -3342,7 +3452,8 @@ static int transcode_init(void)
av_log(NULL, AV_LOG_INFO, " (%s (%s) -> %s (%s))",
in_codec_name, decoder_name,
out_codec_name, encoder_name);
- }
+ } else
+ av_log(NULL, AV_LOG_INFO, " (copy)");
av_log(NULL, AV_LOG_INFO, "\n");
}
@@ -3351,11 +3462,7 @@ static int transcode_init(void)
return ret;
}
- if (sdp_filename || want_sdp) {
- print_sdp();
- }
-
- transcode_init_done = 1;
+ atomic_store(&transcode_init_done, 1);
return 0;
}
@@ -3363,22 +3470,9 @@ static int transcode_init(void)
/* Return 1 if there remain streams where more output is wanted, 0 otherwise. */
static int need_output(void)
{
- int i;
-
- for (i = 0; i < nb_output_streams; i++) {
- OutputStream *ost = output_streams[i];
- OutputFile *of = output_files[ost->file_index];
- AVFormatContext *os = output_files[ost->file_index]->ctx;
-
- if (ost->finished ||
- (os->pb && avio_tell(os->pb) >= of->limit_filesize))
- continue;
- if (ost->frame_number >= ost->max_frames) {
- int j;
- for (j = 0; j < of->ctx->nb_streams; j++)
- close_output_stream(output_streams[of->ost_index + j]);
+ for (OutputStream *ost = ost_iter(NULL); ost; ost = ost_iter(ost)) {
+ if (ost->finished)
continue;
- }
return 1;
}
@@ -3393,17 +3487,25 @@ static int need_output(void)
*/
static OutputStream *choose_output(void)
{
- int i;
int64_t opts_min = INT64_MAX;
OutputStream *ost_min = NULL;
- for (i = 0; i < nb_output_streams; i++) {
- OutputStream *ost = output_streams[i];
- int64_t opts = ost->st->cur_dts == AV_NOPTS_VALUE ? INT64_MIN :
- av_rescale_q(ost->st->cur_dts, ost->st->time_base,
- AV_TIME_BASE_Q);
- if (ost->st->cur_dts == AV_NOPTS_VALUE)
- av_log(NULL, AV_LOG_DEBUG, "cur_dts is invalid (this is harmless if it occurs once at the start per stream)\n");
+ for (OutputStream *ost = ost_iter(NULL); ost; ost = ost_iter(ost)) {
+ int64_t opts;
+
+ if (ost->filter && ost->last_filter_pts != AV_NOPTS_VALUE) {
+ opts = ost->last_filter_pts;
+ } else {
+ opts = ost->last_mux_dts == AV_NOPTS_VALUE ?
+ INT64_MIN : ost->last_mux_dts;
+ if (ost->last_mux_dts == AV_NOPTS_VALUE)
+ av_log(ost, AV_LOG_DEBUG,
+ "cur_dts is invalid [init:%d i_done:%d finish:%d] (this is harmless if it occurs once at the start per stream)\n",
+ ost->initialized, ost->inputs_done, ost->finished);
+ }
+
+ if (!ost->initialized && !ost->inputs_done)
+ return ost->unavailable ? NULL : ost;
if (!ost->finished && opts < opts_min) {
opts_min = opts;
@@ -3432,25 +3534,18 @@ static int check_keyboard_interaction(int64_t cur_time)
if (received_nb_signals)
return AVERROR_EXIT;
/* read_key() returns 0 on EOF */
- if(cur_time - last_time >= 100000 && !run_as_daemon){
+ if (cur_time - last_time >= 100000) {
key = read_key();
last_time = cur_time;
}else
key = -1;
- if (key == 'q')
+ if (key == 'q') {
+ av_log(NULL, AV_LOG_INFO, "\n\n[q] command received. Exiting.\n\n");
return AVERROR_EXIT;
+ }
if (key == '+') av_log_set_level(av_log_get_level()+10);
if (key == '-') av_log_set_level(av_log_get_level()-10);
if (key == 's') qp_hist ^= 1;
- if (key == 'h'){
- if (do_hex_dump){
- do_hex_dump = do_pkt_dump = 0;
- } else if(do_pkt_dump){
- do_hex_dump = 1;
- } else
- do_pkt_dump = 1;
- av_log_set_level(AV_LOG_DEBUG);
- }
if (key == 'c' || key == 'C'){
char buf[4096], target[64], command[256], arg[256] = {0};
double time;
@@ -3476,12 +3571,12 @@ static int check_keyboard_interaction(int64_t cur_time)
key == 'c' ? AVFILTER_CMD_FLAG_ONE : 0);
fprintf(stderr, "Command reply for stream %d: ret:%d res:\n%s", i, ret, buf);
} else if (key == 'c') {
- fprintf(stderr, "Queing commands only on filters supporting the specific command is unsupported\n");
+ fprintf(stderr, "Queuing commands only on filters supporting the specific command is unsupported\n");
ret = AVERROR_PATCHWELCOME;
} else {
ret = avfilter_graph_queue_command(fg->graph, target, command, arg, 0, time);
if (ret < 0)
- fprintf(stderr, "Queing command failed with error %s\n", av_err2str(ret));
+ fprintf(stderr, "Queuing command failed with error %s\n", av_err2str(ret));
}
}
}
@@ -3494,9 +3589,13 @@ static int check_keyboard_interaction(int64_t cur_time)
if (key == 'd' || key == 'D'){
int debug=0;
if(key == 'D') {
- debug = input_streams[0]->st->codec->debug<<1;
+ InputStream *ist = ist_iter(NULL);
+
+ if (ist)
+ debug = ist->dec_ctx->debug << 1;
+
if(!debug) debug = 1;
- while(debug & (FF_DEBUG_DCT_COEFF|FF_DEBUG_VIS_QP|FF_DEBUG_VIS_MB_TYPE)) //unsupported, would just crash
+ while (debug & FF_DEBUG_DCT_COEFF) //unsupported, would just crash
debug += debug;
}else{
char buf[32];
@@ -3512,12 +3611,11 @@ static int check_keyboard_interaction(int64_t cur_time)
if (k <= 0 || sscanf(buf, "%d", &debug)!=1)
fprintf(stderr,"error parsing debug value\n");
}
- for(i=0;ist->codec->debug = debug;
- }
- for(i=0;ienc_ctx->debug = debug;
+ for (InputStream *ist = ist_iter(NULL); ist; ist = ist_iter(ist))
+ ist->dec_ctx->debug = debug;
+ for (OutputStream *ost = ost_iter(NULL); ost; ost = ost_iter(ost)) {
+ if (ost->enc_ctx)
+ ost->enc_ctx->debug = debug;
}
if(debug) av_log_set_level(AV_LOG_DEBUG);
fprintf(stderr,"debug=%d\n", debug);
@@ -3528,7 +3626,7 @@ static int check_keyboard_interaction(int64_t cur_time)
"+ increase verbosity\n"
"- decrease verbosity\n"
"c Send command to first matching filter supporting it\n"
- "C Send/Que command to all matching filters\n"
+ "C Send/Queue command to all matching filters\n"
"D cycle through available debug modes\n"
"h dump packets/hex press to cycle through the 3 states\n"
"q quit\n"
@@ -3538,128 +3636,10 @@ static int check_keyboard_interaction(int64_t cur_time)
return 0;
}
-#if HAVE_PTHREADS
-static void *input_thread(void *arg)
-{
- InputFile *f = arg;
- unsigned flags = f->non_blocking ? AV_THREAD_MESSAGE_NONBLOCK : 0;
- int ret = 0;
-
- while (1) {
- AVPacket pkt;
- ret = av_read_frame(f->ctx, &pkt);
-
- if (ret == AVERROR(EAGAIN)) {
- av_usleep(10000);
- continue;
- }
- if (ret < 0) {
- av_thread_message_queue_set_err_recv(f->in_thread_queue, ret);
- break;
- }
- ret = av_thread_message_queue_send(f->in_thread_queue, &pkt, flags);
- if (flags && ret == AVERROR(EAGAIN)) {
- flags = 0;
- ret = av_thread_message_queue_send(f->in_thread_queue, &pkt, flags);
- av_log(f->ctx, AV_LOG_WARNING,
- "Thread message queue blocking; consider raising the "
- "thread_queue_size option (current value: %d)\n",
- f->thread_queue_size);
- }
- if (ret < 0) {
- if (ret != AVERROR_EOF)
- av_log(f->ctx, AV_LOG_ERROR,
- "Unable to send packet to main thread: %s\n",
- av_err2str(ret));
- av_packet_unref(&pkt);
- av_thread_message_queue_set_err_recv(f->in_thread_queue, ret);
- break;
- }
- }
-
- return NULL;
-}
-
-static void free_input_threads(void)
-{
- int i;
-
- for (i = 0; i < nb_input_files; i++) {
- InputFile *f = input_files[i];
- AVPacket pkt;
-
- if (!f || !f->in_thread_queue)
- continue;
- av_thread_message_queue_set_err_send(f->in_thread_queue, AVERROR_EOF);
- while (av_thread_message_queue_recv(f->in_thread_queue, &pkt, 0) >= 0)
- av_packet_unref(&pkt);
-
- pthread_join(f->thread, NULL);
- f->joined = 1;
- av_thread_message_queue_free(&f->in_thread_queue);
- }
-}
-
-static int init_input_threads(void)
-{
- int i, ret;
-
- if (nb_input_files == 1)
- return 0;
-
- for (i = 0; i < nb_input_files; i++) {
- InputFile *f = input_files[i];
-
- if (f->ctx->pb ? !f->ctx->pb->seekable :
- strcmp(f->ctx->iformat->name, "lavfi"))
- f->non_blocking = 1;
- ret = av_thread_message_queue_alloc(&f->in_thread_queue,
- f->thread_queue_size, sizeof(AVPacket));
- if (ret < 0)
- return ret;
-
- if ((ret = pthread_create(&f->thread, NULL, input_thread, f))) {
- av_log(NULL, AV_LOG_ERROR, "pthread_create failed: %s. Try to increase `ulimit -v` or decrease `ulimit -s`.\n", strerror(ret));
- av_thread_message_queue_free(&f->in_thread_queue);
- return AVERROR(ret);
- }
- }
- return 0;
-}
-
-static int get_input_packet_mt(InputFile *f, AVPacket *pkt)
-{
- return av_thread_message_queue_recv(f->in_thread_queue, pkt,
- f->non_blocking ?
- AV_THREAD_MESSAGE_NONBLOCK : 0);
-}
-#endif
-
-static int get_input_packet(InputFile *f, AVPacket *pkt)
-{
- if (f->rate_emu) {
- int i;
- for (i = 0; i < f->nb_streams; i++) {
- InputStream *ist = input_streams[f->ist_index + i];
- int64_t pts = av_rescale(ist->dts, 1000000, AV_TIME_BASE);
- int64_t now = av_gettime_relative() - ist->start;
- if (pts > now)
- return AVERROR(EAGAIN);
- }
- }
-
-#if HAVE_PTHREADS
- if (nb_input_files > 1)
- return get_input_packet_mt(f, pkt);
-#endif
- return av_read_frame(f->ctx, pkt);
-}
-
static int got_eagain(void)
{
- int i;
- for (i = 0; i < nb_output_streams; i++)
- if (output_streams[i]->unavailable)
+ for (OutputStream *ost = ost_iter(NULL); ost; ost = ost_iter(ost))
+ if (ost->unavailable)
return 1;
return 0;
}
@@ -3669,89 +3649,123 @@ static void reset_eagain(void)
int i;
for (i = 0; i < nb_input_files; i++)
input_files[i]->eagain = 0;
- for (i = 0; i < nb_output_streams; i++)
- output_streams[i]->unavailable = 0;
+ for (OutputStream *ost = ost_iter(NULL); ost; ost = ost_iter(ost))
+ ost->unavailable = 0;
}
-// set duration to max(tmp, duration) in a proper time base and return duration's time_base
-static AVRational duration_max(int64_t tmp, int64_t *duration, AVRational tmp_time_base,
- AVRational time_base)
+static void decode_flush(InputFile *ifile)
{
- int ret;
-
- if (!*duration) {
- *duration = tmp;
- return tmp_time_base;
- }
+ for (int i = 0; i < ifile->nb_streams; i++) {
+ InputStream *ist = ifile->streams[i];
+ int ret;
- ret = av_compare_ts(*duration, time_base, tmp, tmp_time_base);
- if (ret < 0) {
- *duration = tmp;
- return tmp_time_base;
- }
+ if (!ist->processing_needed)
+ continue;
- return time_base;
-}
+ do {
+ ret = process_input_packet(ist, NULL, 1);
+ } while (ret > 0);
-static int seek_to_start(InputFile *ifile, AVFormatContext *is)
-{
- InputStream *ist;
- AVCodecContext *avctx;
- int i, ret, has_audio = 0;
- int64_t duration = 0;
+ if (ist->decoding_needed) {
+ /* report last frame duration to the demuxer thread */
+ if (ist->par->codec_type == AVMEDIA_TYPE_AUDIO) {
+ LastFrameDuration dur;
- ret = av_seek_frame(is, -1, is->start_time, 0);
- if (ret < 0)
- return ret;
+ dur.stream_idx = i;
+ dur.duration = av_rescale_q(ist->nb_samples,
+ (AVRational){ 1, ist->dec_ctx->sample_rate},
+ ist->st->time_base);
- for (i = 0; i < ifile->nb_streams; i++) {
- ist = input_streams[ifile->ist_index + i];
- avctx = ist->dec_ctx;
+ av_thread_message_queue_send(ifile->audio_duration_queue, &dur, 0);
+ }
- // flush decoders
- if (ist->decoding_needed) {
- process_input_packet(ist, NULL, 1);
- avcodec_flush_buffers(avctx);
+ avcodec_flush_buffers(ist->dec_ctx);
}
-
- /* duration is the length of the last frame in a stream
- * when audio stream is present we don't care about
- * last video frame length because it's not defined exactly */
- if (avctx->codec_type == AVMEDIA_TYPE_AUDIO && ist->nb_samples)
- has_audio = 1;
}
+}
- for (i = 0; i < ifile->nb_streams; i++) {
- ist = input_streams[ifile->ist_index + i];
- avctx = ist->dec_ctx;
-
- if (has_audio) {
- if (avctx->codec_type == AVMEDIA_TYPE_AUDIO && ist->nb_samples) {
- AVRational sample_rate = {1, avctx->sample_rate};
-
- duration = av_rescale_q(ist->nb_samples, sample_rate, ist->st->time_base);
- } else
- continue;
+static void ts_discontinuity_detect(InputFile *ifile, InputStream *ist,
+ AVPacket *pkt)
+{
+ const int fmt_is_discont = ifile->ctx->iformat->flags & AVFMT_TS_DISCONT;
+ int disable_discontinuity_correction = copy_ts;
+ int64_t pkt_dts = av_rescale_q_rnd(pkt->dts, ist->st->time_base, AV_TIME_BASE_Q,
+ AV_ROUND_NEAR_INF | AV_ROUND_PASS_MINMAX);
+
+ if (copy_ts && ist->next_dts != AV_NOPTS_VALUE &&
+ fmt_is_discont && ist->st->pts_wrap_bits < 60) {
+ int64_t wrap_dts = av_rescale_q_rnd(pkt->dts + (1LL<st->pts_wrap_bits),
+ ist->st->time_base, AV_TIME_BASE_Q,
+ AV_ROUND_NEAR_INF|AV_ROUND_PASS_MINMAX);
+ if (FFABS(wrap_dts - ist->next_dts) < FFABS(pkt_dts - ist->next_dts)/10)
+ disable_discontinuity_correction = 0;
+ }
+
+ if (ist->next_dts != AV_NOPTS_VALUE && !disable_discontinuity_correction) {
+ int64_t delta = pkt_dts - ist->next_dts;
+ if (fmt_is_discont) {
+ if (FFABS(delta) > 1LL * dts_delta_threshold * AV_TIME_BASE ||
+ pkt_dts + AV_TIME_BASE/10 < FFMAX(ist->pts, ist->dts)) {
+ ifile->ts_offset_discont -= delta;
+ av_log(NULL, AV_LOG_DEBUG,
+ "timestamp discontinuity for stream #%d:%d "
+ "(id=%d, type=%s): %"PRId64", new offset= %"PRId64"\n",
+ ist->file_index, ist->st->index, ist->st->id,
+ av_get_media_type_string(ist->par->codec_type),
+ delta, ifile->ts_offset_discont);
+ pkt->dts -= av_rescale_q(delta, AV_TIME_BASE_Q, ist->st->time_base);
+ if (pkt->pts != AV_NOPTS_VALUE)
+ pkt->pts -= av_rescale_q(delta, AV_TIME_BASE_Q, ist->st->time_base);
+ }
} else {
- if (ist->framerate.num) {
- duration = av_rescale_q(1, ist->framerate, ist->st->time_base);
- } else if (ist->st->avg_frame_rate.num) {
- duration = av_rescale_q(1, ist->st->avg_frame_rate, ist->st->time_base);
- } else duration = 1;
+ if (FFABS(delta) > 1LL * dts_error_threshold * AV_TIME_BASE) {
+ av_log(NULL, AV_LOG_WARNING, "DTS %"PRId64", next:%"PRId64" st:%d invalid dropping\n", pkt->dts, ist->next_dts, pkt->stream_index);
+ pkt->dts = AV_NOPTS_VALUE;
+ }
+ if (pkt->pts != AV_NOPTS_VALUE){
+ int64_t pkt_pts = av_rescale_q(pkt->pts, ist->st->time_base, AV_TIME_BASE_Q);
+ delta = pkt_pts - ist->next_dts;
+ if (FFABS(delta) > 1LL * dts_error_threshold * AV_TIME_BASE) {
+ av_log(NULL, AV_LOG_WARNING, "PTS %"PRId64", next:%"PRId64" invalid dropping st:%d\n", pkt->pts, ist->next_dts, pkt->stream_index);
+ pkt->pts = AV_NOPTS_VALUE;
+ }
+ }
+ }
+ } else if (ist->next_dts == AV_NOPTS_VALUE && !copy_ts &&
+ fmt_is_discont && ifile->last_ts != AV_NOPTS_VALUE) {
+ int64_t delta = pkt_dts - ifile->last_ts;
+ if (FFABS(delta) > 1LL * dts_delta_threshold * AV_TIME_BASE) {
+ ifile->ts_offset_discont -= delta;
+ av_log(NULL, AV_LOG_DEBUG,
+ "Inter stream timestamp discontinuity %"PRId64", new offset= %"PRId64"\n",
+ delta, ifile->ts_offset_discont);
+ pkt->dts -= av_rescale_q(delta, AV_TIME_BASE_Q, ist->st->time_base);
+ if (pkt->pts != AV_NOPTS_VALUE)
+ pkt->pts -= av_rescale_q(delta, AV_TIME_BASE_Q, ist->st->time_base);
}
- if (!ifile->duration)
- ifile->time_base = ist->st->time_base;
- /* the total duration of the stream, max_pts - min_pts is
- * the duration of the stream without the last frame */
- duration += ist->max_pts - ist->min_pts;
- ifile->time_base = duration_max(duration, &ifile->duration, ist->st->time_base,
- ifile->time_base);
}
- if (ifile->loop > 0)
- ifile->loop--;
+ ifile->last_ts = av_rescale_q(pkt->dts, ist->st->time_base, AV_TIME_BASE_Q);
+}
- return ret;
+static void ts_discontinuity_process(InputFile *ifile, InputStream *ist,
+ AVPacket *pkt)
+{
+ int64_t offset = av_rescale_q(ifile->ts_offset_discont, AV_TIME_BASE_Q,
+ ist->st->time_base);
+
+ // apply previously-detected timestamp-discontinuity offset
+ // (to all streams, not just audio/video)
+ if (pkt->dts != AV_NOPTS_VALUE)
+ pkt->dts += offset;
+ if (pkt->pts != AV_NOPTS_VALUE)
+ pkt->pts += offset;
+
+ // detect timestamp discontinuities for audio/video
+ if ((ist->par->codec_type == AVMEDIA_TYPE_VIDEO ||
+ ist->par->codec_type == AVMEDIA_TYPE_AUDIO) &&
+ pkt->dts != AV_NOPTS_VALUE)
+ ts_discontinuity_detect(ifile, ist, pkt);
}
/*
@@ -3766,45 +3780,43 @@ static int process_input(int file_index)
InputFile *ifile = input_files[file_index];
AVFormatContext *is;
InputStream *ist;
- AVPacket pkt;
- int ret, i, j;
- int64_t duration;
- int64_t pkt_dts;
+ AVPacket *pkt;
+ int ret, i;
is = ifile->ctx;
- ret = get_input_packet(ifile, &pkt);
+ ret = ifile_get_packet(ifile, &pkt);
if (ret == AVERROR(EAGAIN)) {
ifile->eagain = 1;
return ret;
}
- if (ret < 0 && ifile->loop) {
- if ((ret = seek_to_start(ifile, is)) < 0)
- return ret;
- ret = get_input_packet(ifile, &pkt);
+ if (ret == 1) {
+ /* the input file is looped: flush the decoders */
+ decode_flush(ifile);
+ return AVERROR(EAGAIN);
}
if (ret < 0) {
if (ret != AVERROR_EOF) {
- print_error(is->filename, ret);
+ print_error(is->url, ret);
if (exit_on_error)
exit_program(1);
}
for (i = 0; i < ifile->nb_streams; i++) {
- ist = input_streams[ifile->ist_index + i];
- if (ist->decoding_needed) {
+ ist = ifile->streams[i];
+ if (ist->processing_needed) {
ret = process_input_packet(ist, NULL, 0);
if (ret>0)
return 0;
}
/* mark all outputs that don't go through lavfi as finished */
- for (j = 0; j < nb_output_streams; j++) {
- OutputStream *ost = output_streams[j];
-
- if (ost->source_index == ifile->ist_index + i &&
- (ost->stream_copy || ost->enc->type == AVMEDIA_TYPE_SUBTITLE))
- finish_output_stream(ost);
+ for (OutputStream *ost = ost_iter(NULL); ost; ost = ost_iter(ost)) {
+ if (ost->ist == ist &&
+ (!ost->enc_ctx || ost->enc_ctx->codec_type == AVMEDIA_TYPE_SUBTITLE)) {
+ OutputFile *of = output_files[ost->file_index];
+ of_output_packet(of, ost->pkt, ost, 1);
+ }
}
}
@@ -3814,190 +3826,54 @@ static int process_input(int file_index)
reset_eagain();
- if (do_pkt_dump) {
- av_pkt_dump_log2(NULL, AV_LOG_INFO, &pkt, do_hex_dump,
- is->streams[pkt.stream_index]);
- }
- /* the following test is needed in case new streams appear
- dynamically in stream : we ignore them */
- if (pkt.stream_index >= ifile->nb_streams) {
- report_new_stream(file_index, &pkt);
- goto discard_packet;
- }
-
- ist = input_streams[ifile->ist_index + pkt.stream_index];
+ ist = ifile->streams[pkt->stream_index];
- ist->data_size += pkt.size;
+ ist->data_size += pkt->size;
ist->nb_packets++;
if (ist->discard)
goto discard_packet;
- if (exit_on_error && (pkt.flags & AV_PKT_FLAG_CORRUPT)) {
- av_log(NULL, AV_LOG_FATAL, "%s: corrupt input packet in stream %d\n", is->filename, pkt.stream_index);
- exit_program(1);
- }
-
- if (debug_ts) {
- av_log(NULL, AV_LOG_INFO, "demuxer -> ist_index:%d type:%s "
- "next_dts:%s next_dts_time:%s next_pts:%s next_pts_time:%s pkt_pts:%s pkt_pts_time:%s pkt_dts:%s pkt_dts_time:%s off:%s off_time:%s\n",
- ifile->ist_index + pkt.stream_index, av_get_media_type_string(ist->dec_ctx->codec_type),
- av_ts2str(ist->next_dts), av_ts2timestr(ist->next_dts, &AV_TIME_BASE_Q),
- av_ts2str(ist->next_pts), av_ts2timestr(ist->next_pts, &AV_TIME_BASE_Q),
- av_ts2str(pkt.pts), av_ts2timestr(pkt.pts, &ist->st->time_base),
- av_ts2str(pkt.dts), av_ts2timestr(pkt.dts, &ist->st->time_base),
- av_ts2str(input_files[ist->file_index]->ts_offset),
- av_ts2timestr(input_files[ist->file_index]->ts_offset, &AV_TIME_BASE_Q));
- }
-
- if(!ist->wrap_correction_done && is->start_time != AV_NOPTS_VALUE && ist->st->pts_wrap_bits < 64){
- int64_t stime, stime2;
- // Correcting starttime based on the enabled streams
- // FIXME this ideally should be done before the first use of starttime but we do not know which are the enabled streams at that point.
- // so we instead do it here as part of discontinuity handling
- if ( ist->next_dts == AV_NOPTS_VALUE
- && ifile->ts_offset == -is->start_time
- && (is->iformat->flags & AVFMT_TS_DISCONT)) {
- int64_t new_start_time = INT64_MAX;
- for (i=0; inb_streams; i++) {
- AVStream *st = is->streams[i];
- if(st->discard == AVDISCARD_ALL || st->start_time == AV_NOPTS_VALUE)
- continue;
- new_start_time = FFMIN(new_start_time, av_rescale_q(st->start_time, st->time_base, AV_TIME_BASE_Q));
- }
- if (new_start_time > is->start_time) {
- av_log(is, AV_LOG_VERBOSE, "Correcting start time by %"PRId64"\n", new_start_time - is->start_time);
- ifile->ts_offset = -new_start_time;
- }
- }
-
- stime = av_rescale_q(is->start_time, AV_TIME_BASE_Q, ist->st->time_base);
- stime2= stime + (1ULL<st->pts_wrap_bits);
- ist->wrap_correction_done = 1;
-
- if(stime2 > stime && pkt.dts != AV_NOPTS_VALUE && pkt.dts > stime + (1LL<<(ist->st->pts_wrap_bits-1))) {
- pkt.dts -= 1ULL<st->pts_wrap_bits;
- ist->wrap_correction_done = 0;
- }
- if(stime2 > stime && pkt.pts != AV_NOPTS_VALUE && pkt.pts > stime + (1LL<<(ist->st->pts_wrap_bits-1))) {
- pkt.pts -= 1ULL<st->pts_wrap_bits;
- ist->wrap_correction_done = 0;
- }
- }
-
/* add the stream-global side data to the first packet */
if (ist->nb_packets == 1) {
- if (ist->st->nb_side_data)
- av_packet_split_side_data(&pkt);
for (i = 0; i < ist->st->nb_side_data; i++) {
AVPacketSideData *src_sd = &ist->st->side_data[i];
uint8_t *dst_data;
- if (av_packet_get_side_data(&pkt, src_sd->type, NULL))
+ if (src_sd->type == AV_PKT_DATA_DISPLAYMATRIX)
continue;
- if (ist->autorotate && src_sd->type == AV_PKT_DATA_DISPLAYMATRIX)
+
+ if (av_packet_get_side_data(pkt, src_sd->type, NULL))
continue;
- dst_data = av_packet_new_side_data(&pkt, src_sd->type, src_sd->size);
+ dst_data = av_packet_new_side_data(pkt, src_sd->type, src_sd->size);
if (!dst_data)
- exit_program(1);
+ report_and_exit(AVERROR(ENOMEM));
memcpy(dst_data, src_sd->data, src_sd->size);
}
}
- if (pkt.dts != AV_NOPTS_VALUE)
- pkt.dts += av_rescale_q(ifile->ts_offset, AV_TIME_BASE_Q, ist->st->time_base);
- if (pkt.pts != AV_NOPTS_VALUE)
- pkt.pts += av_rescale_q(ifile->ts_offset, AV_TIME_BASE_Q, ist->st->time_base);
-
- if (pkt.pts != AV_NOPTS_VALUE)
- pkt.pts *= ist->ts_scale;
- if (pkt.dts != AV_NOPTS_VALUE)
- pkt.dts *= ist->ts_scale;
-
- pkt_dts = av_rescale_q_rnd(pkt.dts, ist->st->time_base, AV_TIME_BASE_Q, AV_ROUND_NEAR_INF|AV_ROUND_PASS_MINMAX);
- if ((ist->dec_ctx->codec_type == AVMEDIA_TYPE_VIDEO ||
- ist->dec_ctx->codec_type == AVMEDIA_TYPE_AUDIO) &&
- pkt_dts != AV_NOPTS_VALUE && ist->next_dts == AV_NOPTS_VALUE && !copy_ts
- && (is->iformat->flags & AVFMT_TS_DISCONT) && ifile->last_ts != AV_NOPTS_VALUE) {
- int64_t delta = pkt_dts - ifile->last_ts;
- if (delta < -1LL*dts_delta_threshold*AV_TIME_BASE ||
- delta > 1LL*dts_delta_threshold*AV_TIME_BASE){
- ifile->ts_offset -= delta;
- av_log(NULL, AV_LOG_DEBUG,
- "Inter stream timestamp discontinuity %"PRId64", new offset= %"PRId64"\n",
- delta, ifile->ts_offset);
- pkt.dts -= av_rescale_q(delta, AV_TIME_BASE_Q, ist->st->time_base);
- if (pkt.pts != AV_NOPTS_VALUE)
- pkt.pts -= av_rescale_q(delta, AV_TIME_BASE_Q, ist->st->time_base);
- }
- }
-
- duration = av_rescale_q(ifile->duration, ifile->time_base, ist->st->time_base);
- if (pkt.pts != AV_NOPTS_VALUE) {
- pkt.pts += duration;
- ist->max_pts = FFMAX(pkt.pts, ist->max_pts);
- ist->min_pts = FFMIN(pkt.pts, ist->min_pts);
- }
-
- if (pkt.dts != AV_NOPTS_VALUE)
- pkt.dts += duration;
-
- pkt_dts = av_rescale_q_rnd(pkt.dts, ist->st->time_base, AV_TIME_BASE_Q, AV_ROUND_NEAR_INF|AV_ROUND_PASS_MINMAX);
- if ((ist->dec_ctx->codec_type == AVMEDIA_TYPE_VIDEO ||
- ist->dec_ctx->codec_type == AVMEDIA_TYPE_AUDIO) &&
- pkt_dts != AV_NOPTS_VALUE && ist->next_dts != AV_NOPTS_VALUE &&
- !copy_ts) {
- int64_t delta = pkt_dts - ist->next_dts;
- if (is->iformat->flags & AVFMT_TS_DISCONT) {
- if (delta < -1LL*dts_delta_threshold*AV_TIME_BASE ||
- delta > 1LL*dts_delta_threshold*AV_TIME_BASE ||
- pkt_dts + AV_TIME_BASE/10 < FFMAX(ist->pts, ist->dts)) {
- ifile->ts_offset -= delta;
- av_log(NULL, AV_LOG_DEBUG,
- "timestamp discontinuity %"PRId64", new offset= %"PRId64"\n",
- delta, ifile->ts_offset);
- pkt.dts -= av_rescale_q(delta, AV_TIME_BASE_Q, ist->st->time_base);
- if (pkt.pts != AV_NOPTS_VALUE)
- pkt.pts -= av_rescale_q(delta, AV_TIME_BASE_Q, ist->st->time_base);
- }
- } else {
- if ( delta < -1LL*dts_error_threshold*AV_TIME_BASE ||
- delta > 1LL*dts_error_threshold*AV_TIME_BASE) {
- av_log(NULL, AV_LOG_WARNING, "DTS %"PRId64", next:%"PRId64" st:%d invalid dropping\n", pkt.dts, ist->next_dts, pkt.stream_index);
- pkt.dts = AV_NOPTS_VALUE;
- }
- if (pkt.pts != AV_NOPTS_VALUE){
- int64_t pkt_pts = av_rescale_q(pkt.pts, ist->st->time_base, AV_TIME_BASE_Q);
- delta = pkt_pts - ist->next_dts;
- if ( delta < -1LL*dts_error_threshold*AV_TIME_BASE ||
- delta > 1LL*dts_error_threshold*AV_TIME_BASE) {
- av_log(NULL, AV_LOG_WARNING, "PTS %"PRId64", next:%"PRId64" invalid dropping st:%d\n", pkt.pts, ist->next_dts, pkt.stream_index);
- pkt.pts = AV_NOPTS_VALUE;
- }
- }
- }
- }
-
- if (pkt.dts != AV_NOPTS_VALUE)
- ifile->last_ts = av_rescale_q(pkt.dts, ist->st->time_base, AV_TIME_BASE_Q);
+ // detect and try to correct for timestamp discontinuities
+ ts_discontinuity_process(ifile, ist, pkt);
if (debug_ts) {
- av_log(NULL, AV_LOG_INFO, "demuxer+ffmpeg -> ist_index:%d type:%s pkt_pts:%s pkt_pts_time:%s pkt_dts:%s pkt_dts_time:%s off:%s off_time:%s\n",
- ifile->ist_index + pkt.stream_index, av_get_media_type_string(ist->dec_ctx->codec_type),
- av_ts2str(pkt.pts), av_ts2timestr(pkt.pts, &ist->st->time_base),
- av_ts2str(pkt.dts), av_ts2timestr(pkt.dts, &ist->st->time_base),
+ av_log(NULL, AV_LOG_INFO, "demuxer+ffmpeg -> ist_index:%d:%d type:%s pkt_pts:%s pkt_pts_time:%s pkt_dts:%s pkt_dts_time:%s duration:%s duration_time:%s off:%s off_time:%s\n",
+ ifile->index, pkt->stream_index,
+ av_get_media_type_string(ist->par->codec_type),
+ av_ts2str(pkt->pts), av_ts2timestr(pkt->pts, &ist->st->time_base),
+ av_ts2str(pkt->dts), av_ts2timestr(pkt->dts, &ist->st->time_base),
+ av_ts2str(pkt->duration), av_ts2timestr(pkt->duration, &ist->st->time_base),
av_ts2str(input_files[ist->file_index]->ts_offset),
av_ts2timestr(input_files[ist->file_index]->ts_offset, &AV_TIME_BASE_Q));
}
- sub2video_heartbeat(ist, pkt.pts);
+ sub2video_heartbeat(ist, pkt->pts);
- process_input_packet(ist, &pkt, 0);
+ process_input_packet(ist, pkt, 0);
discard_packet:
- av_packet_unref(&pkt);
+ av_packet_free(&pkt);
return 0;
}
@@ -4058,7 +3934,7 @@ static int transcode_from_filter(FilterGraph *graph, InputStream **best_ist)
static int transcode_step(void)
{
OutputStream *ost;
- InputStream *ist;
+ InputStream *ist = NULL;
int ret;
ost = choose_output();
@@ -4072,14 +3948,61 @@ static int transcode_step(void)
return AVERROR_EOF;
}
- if (ost->filter) {
+ if (ost->filter && !ost->filter->graph->graph) {
+ if (ifilter_has_all_input_formats(ost->filter->graph)) {
+ ret = configure_filtergraph(ost->filter->graph);
+ if (ret < 0) {
+ av_log(NULL, AV_LOG_ERROR, "Error reinitializing filters!\n");
+ return ret;
+ }
+ }
+ }
+
+ if (ost->filter && ost->filter->graph->graph) {
+ /*
+ * Similar case to the early audio initialization in reap_filters.
+ * Audio is special in ffmpeg.c currently as we depend on lavfi's
+ * audio frame buffering/creation to get the output audio frame size
+ * in samples correct. The audio frame size for the filter chain is
+ * configured during the output stream initialization.
+ *
+ * Apparently avfilter_graph_request_oldest (called in
+ * transcode_from_filter just down the line) peeks. Peeking already
+ * puts one frame "ready to be given out", which means that any
+ * update in filter buffer sink configuration afterwards will not
+ * help us. And yes, even if it would be utilized,
+ * av_buffersink_get_samples is affected, as it internally utilizes
+ * the same early exit for peeked frames.
+ *
+ * In other words, if avfilter_graph_request_oldest would not make
+ * further filter chain configuration or usage of
+ * av_buffersink_get_samples useless (by just causing the return
+ * of the peeked AVFrame as-is), we could get rid of this additional
+ * early encoder initialization.
+ */
+ if (av_buffersink_get_type(ost->filter->filter) == AVMEDIA_TYPE_AUDIO)
+ init_output_stream_wrapper(ost, NULL, 1);
+
if ((ret = transcode_from_filter(ost->filter->graph, &ist)) < 0)
return ret;
if (!ist)
return 0;
+ } else if (ost->filter) {
+ int i;
+ for (i = 0; i < ost->filter->graph->nb_inputs; i++) {
+ InputFilter *ifilter = ost->filter->graph->inputs[i];
+ if (!ifilter->ist->got_output && !input_files[ifilter->ist->file_index]->eof_reached) {
+ ist = ifilter->ist;
+ break;
+ }
+ }
+ if (!ist) {
+ ost->inputs_done = 1;
+ return 0;
+ }
} else {
- av_assert0(ost->source_index >= 0);
- ist = input_streams[ost->source_index];
+ ist = ost->ist;
+ av_assert0(ist);
}
ret = process_input(ist->file_index);
@@ -4101,8 +4024,6 @@ static int transcode_step(void)
static int transcode(void)
{
int ret, i;
- AVFormatContext *os;
- OutputStream *ost;
InputStream *ist;
int64_t timer_start;
int64_t total_packets_written = 0;
@@ -4117,11 +4038,6 @@ static int transcode(void)
timer_start = av_gettime_relative();
-#if HAVE_PTHREADS
- if ((ret = init_input_threads()) < 0)
- goto fail;
-#endif
-
while (!received_sigterm) {
int64_t cur_time= av_gettime_relative();
@@ -4136,26 +4052,25 @@ static int transcode(void)
break;
}
+ if (cancel_execute) {
+ cancel_execute = 0;
+ av_log(NULL, AV_LOG_ERROR, "cancel task by user...");
+ break;
+ }
+
ret = transcode_step();
if (ret < 0 && ret != AVERROR_EOF) {
- char errbuf[128];
- av_strerror(ret, errbuf, sizeof(errbuf));
-
- av_log(NULL, AV_LOG_ERROR, "Error while filtering: %s\n", errbuf);
+ av_log(NULL, AV_LOG_ERROR, "Error while filtering: %s\n", av_err2str(ret));
break;
}
/* dump report by using the output first video and audio streams */
print_report(0, timer_start, cur_time);
}
-#if HAVE_PTHREADS
- free_input_threads();
-#endif
/* at the end of stream, we must flush the decoder buffers */
- for (i = 0; i < nb_input_streams; i++) {
- ist = input_streams[i];
- if (!input_files[ist->file_index]->eof_reached && ist->decoding_needed) {
+ for (ist = ist_iter(NULL); ist; ist = ist_iter(ist)) {
+ if (!input_files[ist->file_index]->eof_reached) {
process_input_packet(ist, NULL, 0);
}
}
@@ -4163,26 +4078,25 @@ static int transcode(void)
term_exit();
- /* write the trailer if needed and close file */
+ /* write the trailer if needed */
for (i = 0; i < nb_output_files; i++) {
- os = output_files[i]->ctx;
- if ((ret = av_write_trailer(os)) < 0) {
- av_log(NULL, AV_LOG_ERROR, "Error writing trailer of %s: %s", os->filename, av_err2str(ret));
- if (exit_on_error)
- exit_program(1);
- }
+ ret = of_write_trailer(output_files[i]);
+ if (ret < 0 && exit_on_error)
+ exit_program(1);
}
/* dump report by using the first video and audio streams */
print_report(1, timer_start, av_gettime_relative());
/* close each encoder */
- for (i = 0; i < nb_output_streams; i++) {
- ost = output_streams[i];
- if (ost->encoding_needed) {
- av_freep(&ost->enc_ctx->stats_in);
+ for (OutputStream *ost = ost_iter(NULL); ost; ost = ost_iter(ost)) {
+ uint64_t packets_written;
+ packets_written = atomic_load(&ost->packets_written);
+ total_packets_written += packets_written;
+ if (!packets_written && (abort_on_flags & ABORT_ON_FLAG_EMPTY_OUTPUT_STREAM)) {
+ av_log(ost, AV_LOG_FATAL, "Empty output\n");
+ exit_program(1);
}
- total_packets_written += ost->packets_written;
}
if (!total_packets_written && (abort_on_flags & ABORT_ON_FLAG_EMPTY_OUTPUT)) {
@@ -4190,65 +4104,39 @@ static int transcode(void)
exit_program(1);
}
- /* close each decoder */
- for (i = 0; i < nb_input_streams; i++) {
- ist = input_streams[i];
- if (ist->decoding_needed) {
- avcodec_close(ist->dec_ctx);
- if (ist->hwaccel_uninit)
- ist->hwaccel_uninit(ist->dec_ctx);
- }
- }
+ hw_device_free_all();
/* finished ! */
ret = 0;
fail:
-#if HAVE_PTHREADS
- free_input_threads();
-#endif
-
- if (output_streams) {
- for (i = 0; i < nb_output_streams; i++) {
- ost = output_streams[i];
- if (ost) {
- if (ost->logfile) {
- if (fclose(ost->logfile))
- av_log(NULL, AV_LOG_ERROR,
- "Error closing logfile, loss of information possible: %s\n",
- av_err2str(AVERROR(errno)));
- ost->logfile = NULL;
- }
- av_freep(&ost->forced_kf_pts);
- av_freep(&ost->apad);
- av_freep(&ost->disposition);
- av_dict_free(&ost->encoder_opts);
- av_dict_free(&ost->sws_dict);
- av_dict_free(&ost->swr_opts);
- av_dict_free(&ost->resample_opts);
- }
- }
- }
return ret;
}
-
-static int64_t getutime(void)
+static BenchmarkTimeStamps get_benchmark_time_stamps(void)
{
+ BenchmarkTimeStamps time_stamps = { av_gettime_relative() };
#if HAVE_GETRUSAGE
struct rusage rusage;
getrusage(RUSAGE_SELF, &rusage);
- return (rusage.ru_utime.tv_sec * 1000000LL) + rusage.ru_utime.tv_usec;
+ time_stamps.user_usec =
+ (rusage.ru_utime.tv_sec * 1000000LL) + rusage.ru_utime.tv_usec;
+ time_stamps.sys_usec =
+ (rusage.ru_stime.tv_sec * 1000000LL) + rusage.ru_stime.tv_usec;
#elif HAVE_GETPROCESSTIMES
HANDLE proc;
FILETIME c, e, k, u;
proc = GetCurrentProcess();
GetProcessTimes(proc, &c, &e, &k, &u);
- return ((int64_t) u.dwHighDateTime << 32 | u.dwLowDateTime) / 10;
+ time_stamps.user_usec =
+ ((int64_t)u.dwHighDateTime << 32 | u.dwLowDateTime) / 10;
+ time_stamps.sys_usec =
+ ((int64_t)k.dwHighDateTime << 32 | k.dwLowDateTime) / 10;
#else
- return av_gettime_relative();
+ time_stamps.user_usec = time_stamps.sys_usec = 0;
#endif
+ return time_stamps;
}
static int64_t getmaxrss(void)
@@ -4269,14 +4157,13 @@ static int64_t getmaxrss(void)
#endif
}
-static void log_callback_null(void *ptr, int level, const char *fmt, va_list vl)
-{
-}
-
int run(int argc, char **argv)
{
int ret;
- int64_t ti;
+ BenchmarkTimeStamps ti;
+ main_return_code = 0;
+
+ init_dynload();
register_exit(ffmpeg_cleanup);
@@ -4285,25 +4172,18 @@ int run(int argc, char **argv)
av_log_set_flags(AV_LOG_SKIP_REPEATED);
parse_loglevel(argc, argv, options);
- if(argc>1 && !strcmp(argv[1], "-d")){
- run_as_daemon=1;
- av_log_set_callback(log_callback_null);
- argc--;
- argv++;
+ if (setjmp(jump_buf)) {
+ main_return_code = 1;
+ goto end;
}
- avcodec_register_all();
#if CONFIG_AVDEVICE
avdevice_register_all();
#endif
- avfilter_register_all();
- av_register_all();
avformat_network_init();
show_banner(argc, argv, options);
- term_init();
-
/* parse options and open all input/output files */
ret = ffmpeg_parse_options(argc, argv);
if (ret < 0)
@@ -4321,19 +4201,33 @@ int run(int argc, char **argv)
exit_program(1);
}
- current_time = ti = getutime();
+ current_time = ti = get_benchmark_time_stamps();
if (transcode() < 0)
exit_program(1);
- ti = getutime() - ti;
if (do_benchmark) {
- av_log(NULL, AV_LOG_INFO, "bench: utime=%0.3fs\n", ti / 1000000.0);
+ int64_t utime, stime, rtime;
+ current_time = get_benchmark_time_stamps();
+ utime = current_time.user_usec - ti.user_usec;
+ stime = current_time.sys_usec - ti.sys_usec;
+ rtime = current_time.real_usec - ti.real_usec;
+ av_log(NULL, AV_LOG_INFO,
+ "bench: utime=%0.3fs stime=%0.3fs rtime=%0.3fs\n",
+ utime / 1000000.0, stime / 1000000.0, rtime / 1000000.0);
}
av_log(NULL, AV_LOG_DEBUG, "%"PRIu64" frames successfully decoded, %"PRIu64" decoding errors\n",
decode_error_stat[0], decode_error_stat[1]);
if ((decode_error_stat[0] + decode_error_stat[1]) * max_error_rate < decode_error_stat[1])
exit_program(69);
- exit_program(received_nb_signals ? 255 : main_return_code);
+// exit_program(received_nb_signals ? 255 : main_return_code);
+end:
+ av_log(NULL, AV_LOG_INFO, "FFmpeg result=%d\n", main_return_code);
+ progress_callback(100, 100, main_return_code == 0 ? STATE_FINISH : STATE_ERROR);
ffmpeg_cleanup(0);
+
return main_return_code;
}
+
+void cancel_task(int cancel) {
+ cancel_execute = cancel;
+}
diff --git a/app/src/main/cpp/ffmpeg/ffmpeg.h b/app/src/main/cpp/ffmpeg/ffmpeg.h
index 4bbc7446..44fcfbe2 100644
--- a/app/src/main/cpp/ffmpeg/ffmpeg.h
+++ b/app/src/main/cpp/ffmpeg/ffmpeg.h
@@ -16,25 +16,24 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
-#ifndef FFMPEG_H
-#define FFMPEG_H
+#ifndef FFTOOLS_FFMPEG_H
+#define FFTOOLS_FFMPEG_H
#include "config.h"
+#include
#include
#include
#include
-#if HAVE_PTHREADS
-#include
-#endif
-
#include "cmdutils.h"
+#include "sync_queue.h"
#include "libavformat/avformat.h"
#include "libavformat/avio.h"
#include "libavcodec/avcodec.h"
+#include "libavcodec/bsf.h"
#include "libavfilter/avfilter.h"
@@ -42,52 +41,57 @@
#include "libavutil/dict.h"
#include "libavutil/eval.h"
#include "libavutil/fifo.h"
+#include "libavutil/hwcontext.h"
#include "libavutil/pixfmt.h"
#include "libavutil/rational.h"
+#include "libavutil/thread.h"
#include "libavutil/threadmessage.h"
#include "libswresample/swresample.h"
-#define VSYNC_AUTO -1
-#define VSYNC_PASSTHROUGH 0
-#define VSYNC_CFR 1
-#define VSYNC_VFR 2
-#define VSYNC_VSCFR 0xfe
-#define VSYNC_DROP 0xff
+// deprecated features
+#define FFMPEG_OPT_PSNR 1
+#define FFMPEG_OPT_MAP_CHANNEL 1
+#define FFMPEG_OPT_MAP_SYNC 1
+#define FFMPEG_ROTATION_METADATA 1
+
+enum VideoSyncMethod {
+ VSYNC_AUTO = -1,
+ VSYNC_PASSTHROUGH,
+ VSYNC_CFR,
+ VSYNC_VFR,
+ VSYNC_VSCFR,
+ VSYNC_DROP,
+};
#define MAX_STREAMS 1024 /* arbitrary sanity check value */
enum HWAccelID {
HWACCEL_NONE = 0,
HWACCEL_AUTO,
- HWACCEL_VDPAU,
- HWACCEL_DXVA2,
- HWACCEL_VDA,
- HWACCEL_VIDEOTOOLBOX,
- HWACCEL_QSV,
+ HWACCEL_GENERIC,
};
-typedef struct HWAccel {
+typedef struct HWDevice {
const char *name;
- int (*init)(AVCodecContext *s);
- enum HWAccelID id;
- enum AVPixelFormat pix_fmt;
-} HWAccel;
+ enum AVHWDeviceType type;
+ AVBufferRef *device_ref;
+} HWDevice;
/* select an input stream for an output stream */
typedef struct StreamMap {
int disabled; /* 1 is this mapping is disabled by a negative map */
int file_index;
int stream_index;
- int sync_file_index;
- int sync_stream_index;
char *linklabel; /* name of an output link, for mapping lavfi outputs */
} StreamMap;
+#if FFMPEG_OPT_MAP_CHANNEL
typedef struct {
int file_idx, stream_idx, channel_idx; // input
int ofile_idx, ostream_idx; // output
} AudioChannelMap;
+#endif
typedef struct OptionsContext {
OptionGroup *g;
@@ -100,12 +104,16 @@ typedef struct OptionsContext {
SpecifierOpt *codec_names;
int nb_codec_names;
+ SpecifierOpt *audio_ch_layouts;
+ int nb_audio_ch_layouts;
SpecifierOpt *audio_channels;
int nb_audio_channels;
SpecifierOpt *audio_sample_rate;
int nb_audio_sample_rate;
SpecifierOpt *frame_rates;
int nb_frame_rates;
+ SpecifierOpt *max_frame_rates;
+ int nb_max_frame_rates;
SpecifierOpt *frame_sizes;
int nb_frame_sizes;
SpecifierOpt *frame_pix_fmts;
@@ -115,8 +123,11 @@ typedef struct OptionsContext {
int64_t input_ts_offset;
int loop;
int rate_emu;
+ float readrate;
int accurate_seek;
int thread_queue_size;
+ int input_sync_ref;
+ int find_stream_info;
SpecifierOpt *ts_scale;
int nb_ts_scale;
@@ -126,17 +137,18 @@ typedef struct OptionsContext {
int nb_hwaccels;
SpecifierOpt *hwaccel_devices;
int nb_hwaccel_devices;
+ SpecifierOpt *hwaccel_output_formats;
+ int nb_hwaccel_output_formats;
SpecifierOpt *autorotate;
int nb_autorotate;
/* output options */
StreamMap *stream_maps;
int nb_stream_maps;
+#if FFMPEG_OPT_MAP_CHANNEL
AudioChannelMap *audio_channel_maps; /* one info entry per -map_channel */
int nb_audio_channel_maps; /* number of (valid) -map_channel settings */
- int metadata_global_manual;
- int metadata_streams_manual;
- int metadata_chapters_manual;
+#endif
const char **attachments;
int nb_attachments;
@@ -144,10 +156,12 @@ typedef struct OptionsContext {
int64_t recording_time;
int64_t stop_time;
- uint64_t limit_filesize;
+ int64_t limit_filesize;
float mux_preload;
float mux_max_delay;
+ float shortest_buf_duration;
int shortest;
+ int bitexact;
int video_disable;
int audio_disable;
@@ -172,10 +186,18 @@ typedef struct OptionsContext {
int nb_qscale;
SpecifierOpt *forced_key_frames;
int nb_forced_key_frames;
+ SpecifierOpt *fps_mode;
+ int nb_fps_mode;
SpecifierOpt *force_fps;
int nb_force_fps;
SpecifierOpt *frame_aspect_ratios;
int nb_frame_aspect_ratios;
+ SpecifierOpt *display_rotations;
+ int nb_display_rotations;
+ SpecifierOpt *display_hflips;
+ int nb_display_hflips;
+ SpecifierOpt *display_vflips;
+ int nb_display_vflips;
SpecifierOpt *rc_overrides;
int nb_rc_overrides;
SpecifierOpt *intra_matrices;
@@ -202,12 +224,18 @@ typedef struct OptionsContext {
int nb_reinit_filters;
SpecifierOpt *fix_sub_duration;
int nb_fix_sub_duration;
+ SpecifierOpt *fix_sub_duration_heartbeat;
+ int nb_fix_sub_duration_heartbeat;
SpecifierOpt *canvas_sizes;
int nb_canvas_sizes;
SpecifierOpt *pass;
int nb_pass;
SpecifierOpt *passlogfiles;
int nb_passlogfiles;
+ SpecifierOpt *max_muxing_queue_size;
+ int nb_max_muxing_queue_size;
+ SpecifierOpt *muxing_queue_data_threshold;
+ int nb_muxing_queue_data_threshold;
SpecifierOpt *guess_layout_max;
int nb_guess_layout_max;
SpecifierOpt *apad;
@@ -218,6 +246,26 @@ typedef struct OptionsContext {
int nb_disposition;
SpecifierOpt *program;
int nb_program;
+ SpecifierOpt *time_bases;
+ int nb_time_bases;
+ SpecifierOpt *enc_time_bases;
+ int nb_enc_time_bases;
+ SpecifierOpt *autoscale;
+ int nb_autoscale;
+ SpecifierOpt *bits_per_raw_sample;
+ int nb_bits_per_raw_sample;
+ SpecifierOpt *enc_stats_pre;
+ int nb_enc_stats_pre;
+ SpecifierOpt *enc_stats_post;
+ int nb_enc_stats_post;
+ SpecifierOpt *mux_stats;
+ int nb_mux_stats;
+ SpecifierOpt *enc_stats_pre_fmt;
+ int nb_enc_stats_pre_fmt;
+ SpecifierOpt *enc_stats_post_fmt;
+ int nb_enc_stats_post_fmt;
+ SpecifierOpt *mux_stats_fmt;
+ int nb_mux_stats_fmt;
} OptionsContext;
typedef struct InputFilter {
@@ -225,6 +273,23 @@ typedef struct InputFilter {
struct InputStream *ist;
struct FilterGraph *graph;
uint8_t *name;
+ enum AVMediaType type; // AVMEDIA_TYPE_SUBTITLE for sub2video
+
+ AVFifo *frame_queue;
+
+ // parameters configured for this input
+ int format;
+
+ int width, height;
+ AVRational sample_aspect_ratio;
+
+ int sample_rate;
+ AVChannelLayout ch_layout;
+
+ AVBufferRef *hw_frames_ctx;
+ int32_t *displaymatrix;
+
+ int eof;
} InputFilter;
typedef struct OutputFilter {
@@ -236,6 +301,19 @@ typedef struct OutputFilter {
/* temporary storage until stream maps are processed */
AVFilterInOut *out_tmp;
enum AVMediaType type;
+
+ /* desired output stream properties */
+ int width, height;
+ AVRational frame_rate;
+ int format;
+ int sample_rate;
+ AVChannelLayout ch_layout;
+
+ // those are only set if no format is specified and the encoder gives us multiple options
+ // They point directly to the relevant lists of the encoder.
+ const int *formats;
+ const AVChannelLayout *ch_layouts;
+ const int *sample_rates;
} OutputFilter;
typedef struct FilterGraph {
@@ -244,6 +322,9 @@ typedef struct FilterGraph {
AVFilterGraph *graph;
int reconfiguration;
+ // true when the filtergraph contains only meta filters
+ // that do not modify the frame data
+ int is_meta;
InputFilter **inputs;
int nb_inputs;
@@ -259,45 +340,60 @@ typedef struct InputStream {
int decoding_needed; /* non zero if the packets must be decoded in 'raw_fifo', see DECODING_FOR_* */
#define DECODING_FOR_OST 1
#define DECODING_FOR_FILTER 2
-
+ int processing_needed; /* non zero if the packets must be processed */
+ // should attach FrameData as opaque_ref after decoding
+ int want_frame_data;
+
+ /**
+ * Codec parameters - to be used by the decoding/streamcopy code.
+ * st->codecpar should not be accessed, because it may be modified
+ * concurrently by the demuxing thread.
+ */
+ AVCodecParameters *par;
AVCodecContext *dec_ctx;
- AVCodec *dec;
+ const AVCodec *dec;
AVFrame *decoded_frame;
- AVFrame *filter_frame; /* a ref of decoded_frame, to be sent to filters */
+ AVPacket *pkt;
+
+ AVRational framerate_guessed;
+ int64_t prev_pkt_pts;
int64_t start; /* time when read started */
/* predicted dts of the next packet read for this stream or (when there are
* several frames in a packet) of the next frame in current packet (in AV_TIME_BASE units) */
int64_t next_dts;
+ int64_t first_dts; ///< dts of the first packet read for this stream (in AV_TIME_BASE units)
int64_t dts; ///< dts of the last packet read for this stream (in AV_TIME_BASE units)
int64_t next_pts; ///< synthetic pts for the next decode frame (in AV_TIME_BASE units)
int64_t pts; ///< current pts of the decoded frame (in AV_TIME_BASE units)
int wrap_correction_done;
+ // the value of AVCodecParserContext.repeat_pict from the AVStream parser
+ // for the last packet returned from ifile_get_packet()
+ // -1 if unknown
+ // FIXME: this is a hack, the avstream parser should not be used
+ int last_pkt_repeat_pict;
+
int64_t filter_in_rescale_delta_last;
int64_t min_pts; /* pts with the smallest value in a current stream */
int64_t max_pts; /* pts with the higher value in a current stream */
+
+ // when forcing constant input framerate through -r,
+ // this contains the pts that will be given to the next decoded frame
+ int64_t cfr_next_pts;
+
int64_t nb_samples; /* number of samples in the last decoded audio frame before looping */
double ts_scale;
int saw_first_ts;
- int showed_multi_packet_warning;
AVDictionary *decoder_opts;
AVRational framerate; /* framerate forced with -r */
int top_field_first;
int guess_layout_max;
int autorotate;
- int resample_height;
- int resample_width;
- int resample_pix_fmt;
-
- int resample_sample_fmt;
- int resample_sample_rate;
- int resample_channels;
- uint64_t resample_channel_layout;
int fix_sub_duration;
struct { /* previous decoded subtitle and related variables */
@@ -309,12 +405,12 @@ typedef struct InputStream {
struct sub2video {
int64_t last_pts;
int64_t end_pts;
+ AVFifo *sub_queue; ///< queue of AVSubtitle* before filter init
AVFrame *frame;
int w, h;
+ unsigned int initialize; ///< marks if sub2video_update should force an initialization
} sub2video;
- int dr1;
-
/* decoded data from this stream goes into all those filters
* currently video and audio only */
InputFilter **filters;
@@ -324,16 +420,12 @@ typedef struct InputStream {
/* hwaccel options */
enum HWAccelID hwaccel_id;
+ enum AVHWDeviceType hwaccel_device_type;
char *hwaccel_device;
+ enum AVPixelFormat hwaccel_output_format;
- /* hwaccel context */
- enum HWAccelID active_hwaccel_id;
- void *hwaccel_ctx;
- void (*hwaccel_uninit)(AVCodecContext *s);
- int (*hwaccel_get_buffer)(AVCodecContext *s, AVFrame *frame, int flags);
int (*hwaccel_retrieve_data)(AVCodecContext *s, AVFrame *frame);
enum AVPixelFormat hwaccel_pix_fmt;
- enum AVPixelFormat hwaccel_retrieved_pix_fmt;
/* stats */
// combined size of all the packets read
@@ -343,37 +435,53 @@ typedef struct InputStream {
// number of frames/samples retrieved from the decoder
uint64_t frames_decoded;
uint64_t samples_decoded;
+
+ int64_t *dts_buffer;
+ int nb_dts_buffer;
+
+ int got_output;
} InputStream;
+typedef struct LastFrameDuration {
+ int stream_idx;
+ int64_t duration;
+} LastFrameDuration;
+
typedef struct InputFile {
+ int index;
+
AVFormatContext *ctx;
int eof_reached; /* true if eof reached */
int eagain; /* true if last read attempt returned EAGAIN */
- int ist_index; /* index of first stream in input_streams */
- int loop; /* set number of times input stream should be looped */
- int64_t duration; /* actual duration of the longest stream in a file
- at the moment when looping happens */
- AVRational time_base; /* time base of the duration */
int64_t input_ts_offset;
-
+ int input_sync_ref;
+ /**
+ * Effective format start time based on enabled streams.
+ */
+ int64_t start_time_effective;
int64_t ts_offset;
+ /**
+ * Extra timestamp offset added by discontinuity handling.
+ */
+ int64_t ts_offset_discont;
int64_t last_ts;
int64_t start_time; /* user-specified start time in AV_TIME_BASE or AV_NOPTS_VALUE */
- int seek_timestamp;
int64_t recording_time;
- int nb_streams; /* number of stream that ffmpeg is aware of; may be different
- from ctx.nb_streams if new streams appear during av_read_frame() */
- int nb_streams_warn; /* number of streams that the user was warned of */
+
+ /* streams that ffmpeg is aware of;
+ * there may be extra streams in ctx that are not mapped to an InputStream
+ * if new streams appear dynamically during demuxing */
+ InputStream **streams;
+ int nb_streams;
+
int rate_emu;
+ float readrate;
int accurate_seek;
-#if HAVE_PTHREADS
- AVThreadMessageQueue *in_thread_queue;
- pthread_t thread; /* thread reading from this file */
- int non_blocking; /* reading packets from the thread should not block */
- int joined; /* the thread has been joined */
- int thread_queue_size; /* maximum number of queued packets */
-#endif
+ /* when looping the input file, this queue is used by decoders to report
+ * the last frame duration back to the demuxer thread */
+ AVThreadMessageQueue *audio_duration_queue;
+ int audio_duration_queue_size;
} InputFile;
enum forced_keyframes_const {
@@ -385,7 +493,43 @@ enum forced_keyframes_const {
FKF_NB
};
-#define ABORT_ON_FLAG_EMPTY_OUTPUT (1 << 0)
+#define ABORT_ON_FLAG_EMPTY_OUTPUT (1 << 0)
+#define ABORT_ON_FLAG_EMPTY_OUTPUT_STREAM (1 << 1)
+
+enum EncStatsType {
+ ENC_STATS_LITERAL = 0,
+ ENC_STATS_FILE_IDX,
+ ENC_STATS_STREAM_IDX,
+ ENC_STATS_FRAME_NUM,
+ ENC_STATS_FRAME_NUM_IN,
+ ENC_STATS_TIMEBASE,
+ ENC_STATS_TIMEBASE_IN,
+ ENC_STATS_PTS,
+ ENC_STATS_PTS_TIME,
+ ENC_STATS_PTS_IN,
+ ENC_STATS_PTS_TIME_IN,
+ ENC_STATS_DTS,
+ ENC_STATS_DTS_TIME,
+ ENC_STATS_SAMPLE_NUM,
+ ENC_STATS_NB_SAMPLES,
+ ENC_STATS_PKT_SIZE,
+ ENC_STATS_BITRATE,
+ ENC_STATS_AVG_BITRATE,
+};
+
+typedef struct EncStatsComponent {
+ enum EncStatsType type;
+
+ uint8_t *str;
+ size_t str_len;
+} EncStatsComponent;
+
+typedef struct EncStats {
+ EncStatsComponent *components;
+ int nb_components;
+
+ AVIOContext *io;
+} EncStats;
extern const char *const forced_keyframes_const_names[];
@@ -394,53 +538,92 @@ typedef enum {
MUXER_FINISHED = 2,
} OSTFinished ;
+enum {
+ KF_FORCE_SOURCE = 1,
+ KF_FORCE_SOURCE_NO_DROP = 2,
+};
+
+typedef struct KeyframeForceCtx {
+ int type;
+
+ int64_t ref_pts;
+
+ // timestamps of the forced keyframes, in AV_TIME_BASE_Q
+ int64_t *pts;
+ int nb_pts;
+ int index;
+
+ AVExpr *pexpr;
+ double expr_const_values[FKF_NB];
+
+ int dropped_keyframe;
+} KeyframeForceCtx;
+
typedef struct OutputStream {
+ const AVClass *class;
+
int file_index; /* file index */
int index; /* stream index in the output file */
- int source_index; /* InputStream index */
+
+ /* input stream that is the source for this output stream;
+ * may be NULL for streams with no well-defined source, e.g.
+ * attachments or outputs from complex filtergraphs */
+ InputStream *ist;
+
AVStream *st; /* stream in the output file */
- int encoding_needed; /* true if encoding needed for this stream */
- int frame_number;
- /* input pts and corresponding output pts
- for A/V sync */
- struct InputStream *sync_ist; /* input stream to sync against */
- int64_t sync_opts; /* output frame counter, could be changed to some true timestamp */ // FIXME look at frame_number
- /* pts of the first frame encoded for this stream, used for limiting
- * recording time */
- int64_t first_pts;
- /* dts of the last packet sent to the muxer */
+ /* number of frames emitted by the video-encoding sync code */
+ int64_t vsync_frame_number;
+ /* predicted pts of the next frame to be encoded
+ * audio/video encoding only */
+ int64_t next_pts;
+ /* dts of the last packet sent to the muxing queue, in AV_TIME_BASE_Q */
int64_t last_mux_dts;
- AVBitStreamFilterContext *bitstream_filters;
+ /* pts of the last frame received from the filters, in AV_TIME_BASE_Q */
+ int64_t last_filter_pts;
+
+ // timestamp from which the streamcopied streams should start,
+ // in AV_TIME_BASE_Q;
+ // everything before it should be discarded
+ int64_t ts_copy_start;
+
+ // the timebase of the packets sent to the muxer
+ AVRational mux_timebase;
+ AVRational enc_timebase;
+
AVCodecContext *enc_ctx;
- AVCodec *enc;
- int64_t max_frames;
AVFrame *filtered_frame;
AVFrame *last_frame;
- int last_dropped;
- int last_nb0_frames[3];
-
- void *hwaccel_ctx;
+ AVFrame *sq_frame;
+ AVPacket *pkt;
+ int64_t last_dropped;
+ int64_t last_nb0_frames[3];
/* video only */
AVRational frame_rate;
+ AVRational max_frame_rate;
+ enum VideoSyncMethod vsync_method;
int is_cfr;
int force_fps;
int top_field_first;
+#if FFMPEG_ROTATION_METADATA
int rotate_overridden;
+#endif
+ int autoscale;
+ int bitexact;
+ int bits_per_raw_sample;
+#if FFMPEG_ROTATION_METADATA
+ double rotate_override_value;
+#endif
AVRational frame_aspect_ratio;
- /* forced key frames */
- int64_t *forced_kf_pts;
- int forced_kf_count;
- int forced_kf_index;
- char *forced_keyframes;
- AVExpr *forced_keyframes_pexpr;
- double forced_keyframes_expr_const_values[FKF_NB];
+ KeyframeForceCtx kf;
/* audio only */
+#if FFMPEG_OPT_MAP_CHANNEL
int *audio_channels_map; /* list of the channels id to pick from the source stream */
int audio_channels_mapped; /* number of channels in audio_channels_map */
+#endif
char *logfile_prefix;
FILE *logfile;
@@ -453,28 +636,36 @@ typedef struct OutputStream {
AVDictionary *encoder_opts;
AVDictionary *sws_dict;
AVDictionary *swr_opts;
- AVDictionary *resample_opts;
char *apad;
OSTFinished finished; /* no more packets should be written for this stream */
int unavailable; /* true if the steram is unavailable (possibly temporarily) */
- int stream_copy;
+
+ // init_output_stream() has been called for this stream
+ // The encoder and the bitstream filters have been initialized and the stream
+ // parameters are set in the AVStream.
+ int initialized;
+
+ int inputs_done;
+
const char *attachment_filename;
+ int streamcopy_started;
int copy_initial_nonkeyframes;
int copy_prior_start;
- char *disposition;
int keep_pix_fmt;
- AVCodecParserContext *parser;
-
/* stats */
- // combined size of all the packets written
- uint64_t data_size;
+ // combined size of all the packets sent to the muxer
+ uint64_t data_size_mux;
+ // combined size of all the packets received from the encoder
+ uint64_t data_size_enc;
// number of packets send to the muxer
- uint64_t packets_written;
+ atomic_uint_least64_t packets_written;
// number of frames/samples sent to the encoder
uint64_t frames_encoded;
uint64_t samples_encoded;
+ // number of packets received from the encoder
+ uint64_t packets_encoded;
/* packet quality factor */
int quality;
@@ -484,26 +675,43 @@ typedef struct OutputStream {
/* frame encode sum of squared error values */
int64_t error[4];
+
+ int sq_idx_encode;
+ int sq_idx_mux;
+
+ EncStats enc_stats_pre;
+ EncStats enc_stats_post;
+
+ /*
+ * bool on whether this stream should be utilized for splitting
+ * subtitles utilizing fix_sub_duration at random access points.
+ */
+ unsigned int fix_sub_duration_heartbeat;
} OutputStream;
typedef struct OutputFile {
- AVFormatContext *ctx;
- AVDictionary *opts;
- int ost_index; /* index of the first stream in output_streams */
+ const AVClass *class;
+
+ int index;
+
+ const AVOutputFormat *format;
+ const char *url;
+
+ OutputStream **streams;
+ int nb_streams;
+
+ SyncQueue *sq_encode;
+
int64_t recording_time; ///< desired length of the resulting file in microseconds == AV_TIME_BASE units
int64_t start_time; ///< start time in microseconds == AV_TIME_BASE units
- uint64_t limit_filesize; /* filesize limit expressed in bytes */
int shortest;
+ int bitexact;
} OutputFile;
-extern InputStream **input_streams;
-extern int nb_input_streams;
extern InputFile **input_files;
extern int nb_input_files;
-extern OutputStream **output_streams;
-extern int nb_output_streams;
extern OutputFile **output_files;
extern int nb_output_files;
@@ -517,13 +725,10 @@ extern float audio_drift_threshold;
extern float dts_delta_threshold;
extern float dts_error_threshold;
-extern int audio_volume;
-extern int audio_sync_method;
-extern int video_sync_method;
+extern enum VideoSyncMethod video_sync_method;
extern float frame_drop_threshold;
extern int do_benchmark;
extern int do_benchmark_all;
-extern int do_deinterlace;
extern int do_hex_dump;
extern int do_pkt_dump;
extern int copy_ts;
@@ -533,51 +738,180 @@ extern int debug_ts;
extern int exit_on_error;
extern int abort_on_flags;
extern int print_stats;
+extern int64_t stats_period;
extern int qp_hist;
extern int stdin_interaction;
-extern int frame_bits_per_raw_sample;
extern AVIOContext *progress_avio;
extern float max_error_rate;
-extern int vdpau_api_ver;
-extern char *videotoolbox_pixfmt;
+
+extern char *filter_nbthreads;
+extern int filter_complex_nbthreads;
+extern int vstats_version;
+extern int auto_conversion_filters;
extern const AVIOInterruptCB int_cb;
extern const OptionDef options[];
-extern const HWAccel hwaccels[];
+extern HWDevice *filter_hw_device;
+
+extern unsigned nb_output_dumped;
+extern int main_return_code;
+
+extern int ignore_unknown_streams;
+extern int copy_unknown_streams;
+extern int recast_media;
+
+#if FFMPEG_OPT_PSNR
+extern int do_psnr;
+#endif
void term_init(void);
void term_exit(void);
-void reset_options(OptionsContext *o, int is_input);
void show_usage(void);
-void opt_output_file(void *optctx, const char *filename);
-
void remove_avoptions(AVDictionary **a, AVDictionary *b);
void assert_avoptions(AVDictionary *m);
-int guess_input_channel_layout(InputStream *ist);
-
-enum AVPixelFormat choose_pixel_fmt(AVStream *st, AVCodecContext *avctx, AVCodec *codec, enum AVPixelFormat target);
-void choose_sample_fmt(AVStream *st, AVCodec *codec);
+void assert_file_overwrite(const char *filename);
+char *file_read(const char *filename);
+AVDictionary *strip_specifiers(const AVDictionary *dict);
+const AVCodec *find_codec_or_die(void *logctx, const char *name,
+ enum AVMediaType type, int encoder);
+int parse_and_set_vsync(const char *arg, int *vsync_var, int file_idx, int st_idx, int is_global);
int configure_filtergraph(FilterGraph *fg);
-int configure_output_filter(FilterGraph *fg, OutputFilter *ofilter, AVFilterInOut *out);
-int ist_in_filtergraph(FilterGraph *fg, InputStream *ist);
-FilterGraph *init_simple_filtergraph(InputStream *ist, OutputStream *ost);
+void check_filter_outputs(void);
+int filtergraph_is_simple(FilterGraph *fg);
+int init_simple_filtergraph(InputStream *ist, OutputStream *ost);
int init_complex_filtergraph(FilterGraph *fg);
+void sub2video_update(InputStream *ist, int64_t heartbeat_pts, AVSubtitle *sub);
+
+int ifilter_parameters_from_frame(InputFilter *ifilter, const AVFrame *frame);
+
int ffmpeg_parse_options(int argc, char **argv);
-int vdpau_init(AVCodecContext *s);
-int dxva2_init(AVCodecContext *s);
-int vda_init(AVCodecContext *s);
-int videotoolbox_init(AVCodecContext *s);
-int qsv_init(AVCodecContext *s);
-int qsv_transcode_init(OutputStream *ost);
+void enc_stats_write(OutputStream *ost, EncStats *es,
+ const AVFrame *frame, const AVPacket *pkt,
+ uint64_t frame_num);
+
+HWDevice *hw_device_get_by_name(const char *name);
+int hw_device_init_from_string(const char *arg, HWDevice **dev);
+void hw_device_free_all(void);
+
+int hw_device_setup_for_decode(InputStream *ist);
+int hw_device_setup_for_encode(OutputStream *ost);
+int hw_device_setup_for_filter(FilterGraph *fg);
+
+int hwaccel_decode_init(AVCodecContext *avctx);
+
+/*
+ * Initialize muxing state for the given stream, should be called
+ * after the codec/streamcopy setup has been done.
+ *
+ * Open the muxer once all the streams have been initialized.
+ */
+int of_stream_init(OutputFile *of, OutputStream *ost);
+int of_write_trailer(OutputFile *of);
+int of_open(const OptionsContext *o, const char *filename);
+void of_close(OutputFile **pof);
+
+void of_enc_stats_close(void);
+
+/*
+ * Send a single packet to the output, applying any bitstream filters
+ * associated with the output stream. This may result in any number
+ * of packets actually being written, depending on what bitstream
+ * filters are applied. The supplied packet is consumed and will be
+ * blank (as if newly-allocated) when this function returns.
+ *
+ * If eof is set, instead indicate EOF to all bitstream filters and
+ * therefore flush any delayed packets to the output. A blank packet
+ * must be supplied in this case.
+ */
+void of_output_packet(OutputFile *of, AVPacket *pkt, OutputStream *ost, int eof);
+int64_t of_filesize(OutputFile *of);
+
+int ifile_open(const OptionsContext *o, const char *filename);
+void ifile_close(InputFile **f);
+
+/**
+ * Get next input packet from the demuxer.
+ *
+ * @param pkt the packet is written here when this function returns 0
+ * @return
+ * - 0 when a packet has been read successfully
+ * - 1 when stream end was reached, but the stream is looped;
+ * caller should flush decoders and read from this demuxer again
+ * - a negative error code on failure
+ */
+int ifile_get_packet(InputFile *f, AVPacket **pkt);
+
+/* iterate over all input streams in all input files;
+ * pass NULL to start iteration */
+InputStream *ist_iter(InputStream *prev);
+
+#define SPECIFIER_OPT_FMT_str "%s"
+#define SPECIFIER_OPT_FMT_i "%i"
+#define SPECIFIER_OPT_FMT_i64 "%"PRId64
+#define SPECIFIER_OPT_FMT_ui64 "%"PRIu64
+#define SPECIFIER_OPT_FMT_f "%f"
+#define SPECIFIER_OPT_FMT_dbl "%lf"
+
+#define WARN_MULTIPLE_OPT_USAGE(name, type, so, st)\
+{\
+ char namestr[128] = "";\
+ const char *spec = so->specifier && so->specifier[0] ? so->specifier : "";\
+ for (int _i = 0; opt_name_##name[_i]; _i++)\
+ av_strlcatf(namestr, sizeof(namestr), "-%s%s", opt_name_##name[_i], opt_name_##name[_i+1] ? (opt_name_##name[_i+2] ? ", " : " or ") : "");\
+ av_log(NULL, AV_LOG_WARNING, "Multiple %s options specified for stream %d, only the last option '-%s%s%s "SPECIFIER_OPT_FMT_##type"' will be used.\n",\
+ namestr, st->index, opt_name_##name[0], spec[0] ? ":" : "", spec, so->u.type);\
+}
+
+#define MATCH_PER_STREAM_OPT(name, type, outvar, fmtctx, st)\
+{\
+ int _ret, _matches = 0;\
+ SpecifierOpt *so;\
+ for (int _i = 0; _i < o->nb_ ## name; _i++) {\
+ char *spec = o->name[_i].specifier;\
+ if ((_ret = check_stream_specifier(fmtctx, st, spec)) > 0) {\
+ outvar = o->name[_i].u.type;\
+ so = &o->name[_i];\
+ _matches++;\
+ } else if (_ret < 0)\
+ exit_program(1);\
+ }\
+ if (_matches > 1)\
+ WARN_MULTIPLE_OPT_USAGE(name, type, so, st);\
+}
+
+#define MATCH_PER_TYPE_OPT(name, type, outvar, fmtctx, mediatype)\
+{\
+ int i;\
+ for (i = 0; i < o->nb_ ## name; i++) {\
+ char *spec = o->name[i].specifier;\
+ if (!strcmp(spec, mediatype))\
+ outvar = o->name[i].u.type;\
+ }\
+}
+
+extern const char * const opt_name_codec_names[];
+extern const char * const opt_name_codec_tags[];
+extern const char * const opt_name_frame_rates[];
+extern const char * const opt_name_top_field_first[];
int run(int argc, char **argv);
+void cancel_task(int cancel);
+
+enum ProgressState {
+ STATE_INIT,
+ STATE_RUNNING,
+ STATE_FINISH,
+ STATE_ERROR,
+};
+
+void progress_callback(int position, int duration, int state);
-#endif /* FFMPEG_H */
+#endif /* FFTOOLS_FFMPEG_H */
diff --git a/app/src/main/cpp/ffmpeg/ffmpeg_demux.c b/app/src/main/cpp/ffmpeg/ffmpeg_demux.c
new file mode 100644
index 00000000..ffece607
--- /dev/null
+++ b/app/src/main/cpp/ffmpeg/ffmpeg_demux.c
@@ -0,0 +1,1131 @@
+/*
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include
+#include
+
+#include "ffmpeg.h"
+
+#include "libavutil/avassert.h"
+#include "libavutil/avstring.h"
+#include "libavutil/display.h"
+#include "libavutil/error.h"
+#include "libavutil/intreadwrite.h"
+#include "libavutil/opt.h"
+#include "libavutil/parseutils.h"
+#include "libavutil/pixdesc.h"
+#include "libavutil/time.h"
+#include "libavutil/timestamp.h"
+#include "libavutil/thread.h"
+#include "libavutil/threadmessage.h"
+
+#include "libavcodec/packet.h"
+
+#include "libavformat/avformat.h"
+
+static const char *const opt_name_discard[] = {"discard", NULL};
+static const char *const opt_name_reinit_filters[] = {"reinit_filter", NULL};
+static const char *const opt_name_fix_sub_duration[] = {"fix_sub_duration", NULL};
+static const char *const opt_name_canvas_sizes[] = {"canvas_size", NULL};
+static const char *const opt_name_guess_layout_max[] = {"guess_layout_max", NULL};
+static const char *const opt_name_ts_scale[] = {"itsscale", NULL};
+static const char *const opt_name_hwaccels[] = {"hwaccel", NULL};
+static const char *const opt_name_hwaccel_devices[] = {"hwaccel_device", NULL};
+static const char *const opt_name_hwaccel_output_formats[] = {"hwaccel_output_format", NULL};
+static const char *const opt_name_autorotate[] = {"autorotate", NULL};
+static const char *const opt_name_display_rotations[] = {"display_rotation", NULL};
+static const char *const opt_name_display_hflips[] = {"display_hflip", NULL};
+static const char *const opt_name_display_vflips[] = {"display_vflip", NULL};
+
+typedef struct Demuxer {
+ InputFile f;
+
+ /* number of times input stream should be looped */
+ int loop;
+ /* actual duration of the longest stream in a file at the moment when
+ * looping happens */
+ int64_t duration;
+ /* time base of the duration */
+ AVRational time_base;
+
+ /* number of streams that the user was warned of */
+ int nb_streams_warn;
+
+ AVThreadMessageQueue *in_thread_queue;
+ int thread_queue_size;
+ pthread_t thread;
+ int non_blocking;
+} Demuxer;
+
+typedef struct DemuxMsg {
+ AVPacket *pkt;
+ int looping;
+
+ // repeat_pict from the demuxer-internal parser
+ int repeat_pict;
+} DemuxMsg;
+
+static Demuxer *demuxer_from_ifile(InputFile *f)
+{
+ return (Demuxer*)f;
+}
+
+static void report_new_stream(Demuxer *d, const AVPacket *pkt)
+{
+ AVStream *st = d->f.ctx->streams[pkt->stream_index];
+
+ if (pkt->stream_index < d->nb_streams_warn)
+ return;
+ av_log(NULL, AV_LOG_WARNING,
+ "New %s stream %d:%d at pos:%"PRId64" and DTS:%ss\n",
+ av_get_media_type_string(st->codecpar->codec_type),
+ d->f.index, pkt->stream_index,
+ pkt->pos, av_ts2timestr(pkt->dts, &st->time_base));
+ d->nb_streams_warn = pkt->stream_index + 1;
+}
+
+static void ifile_duration_update(Demuxer *d, InputStream *ist,
+ int64_t last_duration)
+{
+ /* the total duration of the stream, max_pts - min_pts is
+ * the duration of the stream without the last frame */
+ if (ist->max_pts > ist->min_pts &&
+ ist->max_pts - (uint64_t)ist->min_pts < INT64_MAX - last_duration)
+ last_duration += ist->max_pts - ist->min_pts;
+
+ if (!d->duration ||
+ av_compare_ts(d->duration, d->time_base,
+ last_duration, ist->st->time_base) < 0) {
+ d->duration = last_duration;
+ d->time_base = ist->st->time_base;
+ }
+}
+
+static int seek_to_start(Demuxer *d)
+{
+ InputFile *ifile = &d->f;
+ AVFormatContext *is = ifile->ctx;
+ InputStream *ist;
+ int ret;
+
+ ret = avformat_seek_file(is, -1, INT64_MIN, is->start_time, is->start_time, 0);
+ if (ret < 0)
+ return ret;
+
+ if (ifile->audio_duration_queue_size) {
+ /* duration is the length of the last frame in a stream
+ * when audio stream is present we don't care about
+ * last video frame length because it's not defined exactly */
+ int got_durations = 0;
+
+ while (got_durations < ifile->audio_duration_queue_size) {
+ LastFrameDuration dur;
+ ret = av_thread_message_queue_recv(ifile->audio_duration_queue, &dur, 0);
+ if (ret < 0)
+ return ret;
+ got_durations++;
+
+ ist = ifile->streams[dur.stream_idx];
+ ifile_duration_update(d, ist, dur.duration);
+ }
+ } else {
+ for (int i = 0; i < ifile->nb_streams; i++) {
+ int64_t duration = 0;
+ ist = ifile->streams[i];
+
+ if (ist->framerate.num) {
+ duration = av_rescale_q(1, av_inv_q(ist->framerate), ist->st->time_base);
+ } else if (ist->st->avg_frame_rate.num) {
+ duration = av_rescale_q(1, av_inv_q(ist->st->avg_frame_rate), ist->st->time_base);
+ } else {
+ duration = 1;
+ }
+
+ ifile_duration_update(d, ist, duration);
+ }
+ }
+
+ if (d->loop > 0)
+ d->loop--;
+
+ return ret;
+}
+
+static void ts_fixup(Demuxer *d, AVPacket *pkt, int *repeat_pict)
+{
+ InputFile *ifile = &d->f;
+ InputStream *ist = ifile->streams[pkt->stream_index];
+ const int64_t start_time = ifile->start_time_effective;
+ int64_t duration;
+
+ if (debug_ts) {
+ av_log(NULL, AV_LOG_INFO, "demuxer -> ist_index:%d:%d type:%s "
+ "pkt_pts:%s pkt_pts_time:%s pkt_dts:%s pkt_dts_time:%s duration:%s duration_time:%s\n",
+ ifile->index, pkt->stream_index,
+ av_get_media_type_string(ist->st->codecpar->codec_type),
+ av_ts2str(pkt->pts), av_ts2timestr(pkt->pts, &ist->st->time_base),
+ av_ts2str(pkt->dts), av_ts2timestr(pkt->dts, &ist->st->time_base),
+ av_ts2str(pkt->duration), av_ts2timestr(pkt->duration, &ist->st->time_base));
+ }
+
+ if (!ist->wrap_correction_done && start_time != AV_NOPTS_VALUE &&
+ ist->st->pts_wrap_bits < 64) {
+ int64_t stime, stime2;
+
+ stime = av_rescale_q(start_time, AV_TIME_BASE_Q, ist->st->time_base);
+ stime2= stime + (1ULL<st->pts_wrap_bits);
+ ist->wrap_correction_done = 1;
+
+ if(stime2 > stime && pkt->dts != AV_NOPTS_VALUE && pkt->dts > stime + (1LL<<(ist->st->pts_wrap_bits-1))) {
+ pkt->dts -= 1ULL<st->pts_wrap_bits;
+ ist->wrap_correction_done = 0;
+ }
+ if(stime2 > stime && pkt->pts != AV_NOPTS_VALUE && pkt->pts > stime + (1LL<<(ist->st->pts_wrap_bits-1))) {
+ pkt->pts -= 1ULL<st->pts_wrap_bits;
+ ist->wrap_correction_done = 0;
+ }
+ }
+
+ if (pkt->dts != AV_NOPTS_VALUE)
+ pkt->dts += av_rescale_q(ifile->ts_offset, AV_TIME_BASE_Q, ist->st->time_base);
+ if (pkt->pts != AV_NOPTS_VALUE)
+ pkt->pts += av_rescale_q(ifile->ts_offset, AV_TIME_BASE_Q, ist->st->time_base);
+
+ if (pkt->pts != AV_NOPTS_VALUE)
+ pkt->pts *= ist->ts_scale;
+ if (pkt->dts != AV_NOPTS_VALUE)
+ pkt->dts *= ist->ts_scale;
+
+ duration = av_rescale_q(d->duration, d->time_base, ist->st->time_base);
+ if (pkt->pts != AV_NOPTS_VALUE) {
+ pkt->pts += duration;
+ ist->max_pts = FFMAX(pkt->pts, ist->max_pts);
+ ist->min_pts = FFMIN(pkt->pts, ist->min_pts);
+ }
+
+ if (pkt->dts != AV_NOPTS_VALUE)
+ pkt->dts += duration;
+
+ *repeat_pict = -1;
+ if (ist->st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO &&
+ av_stream_get_parser(ist->st))
+ *repeat_pict = av_stream_get_parser(ist->st)->repeat_pict;
+}
+
+static void thread_set_name(InputFile *f)
+{
+ char name[16];
+ snprintf(name, sizeof(name), "dmx%d:%s", f->index, f->ctx->iformat->name);
+ ff_thread_setname(name);
+}
+
+static void *input_thread(void *arg)
+{
+ Demuxer *d = arg;
+ InputFile *f = &d->f;
+ AVPacket *pkt;
+ unsigned flags = d->non_blocking ? AV_THREAD_MESSAGE_NONBLOCK : 0;
+ int ret = 0;
+
+ pkt = av_packet_alloc();
+ if (!pkt) {
+ ret = AVERROR(ENOMEM);
+ goto finish;
+ }
+
+ thread_set_name(f);
+
+ while (1) {
+ DemuxMsg msg = { NULL };
+
+ ret = av_read_frame(f->ctx, pkt);
+
+ if (ret == AVERROR(EAGAIN)) {
+ av_usleep(10000);
+ continue;
+ }
+ if (ret < 0) {
+ if (d->loop) {
+ /* signal looping to the consumer thread */
+ msg.looping = 1;
+ ret = av_thread_message_queue_send(d->in_thread_queue, &msg, 0);
+ if (ret >= 0)
+ ret = seek_to_start(d);
+ if (ret >= 0)
+ continue;
+
+ /* fallthrough to the error path */
+ }
+
+ if (ret == AVERROR_EOF)
+ av_log(NULL, AV_LOG_VERBOSE, "EOF in input file %d\n", f->index);
+ else
+ av_log(NULL, AV_LOG_ERROR, "Error demuxing input file %d: %s\n",
+ f->index, av_err2str(ret));
+
+ break;
+ }
+
+ if (do_pkt_dump) {
+ av_pkt_dump_log2(NULL, AV_LOG_INFO, pkt, do_hex_dump,
+ f->ctx->streams[pkt->stream_index]);
+ }
+
+ /* the following test is needed in case new streams appear
+ dynamically in stream : we ignore them */
+ if (pkt->stream_index >= f->nb_streams) {
+ report_new_stream(d, pkt);
+ av_packet_unref(pkt);
+ continue;
+ }
+
+ if (pkt->flags & AV_PKT_FLAG_CORRUPT) {
+ av_log(NULL, exit_on_error ? AV_LOG_FATAL : AV_LOG_WARNING,
+ "%s: corrupt input packet in stream %d\n",
+ f->ctx->url, pkt->stream_index);
+ if (exit_on_error) {
+ av_packet_unref(pkt);
+ ret = AVERROR_INVALIDDATA;
+ break;
+ }
+ }
+
+ ts_fixup(d, pkt, &msg.repeat_pict);
+
+ msg.pkt = av_packet_alloc();
+ if (!msg.pkt) {
+ av_packet_unref(pkt);
+ ret = AVERROR(ENOMEM);
+ break;
+ }
+ av_packet_move_ref(msg.pkt, pkt);
+ ret = av_thread_message_queue_send(d->in_thread_queue, &msg, flags);
+ if (flags && ret == AVERROR(EAGAIN)) {
+ flags = 0;
+ ret = av_thread_message_queue_send(d->in_thread_queue, &msg, flags);
+ av_log(f->ctx, AV_LOG_WARNING,
+ "Thread message queue blocking; consider raising the "
+ "thread_queue_size option (current value: %d)\n",
+ d->thread_queue_size);
+ }
+ if (ret < 0) {
+ if (ret != AVERROR_EOF)
+ av_log(f->ctx, AV_LOG_ERROR,
+ "Unable to send packet to main thread: %s\n",
+ av_err2str(ret));
+ av_packet_free(&msg.pkt);
+ break;
+ }
+ }
+
+finish:
+ av_assert0(ret < 0);
+ av_thread_message_queue_set_err_recv(d->in_thread_queue, ret);
+
+ av_packet_free(&pkt);
+
+ av_log(NULL, AV_LOG_VERBOSE, "Terminating demuxer thread %d\n", f->index);
+
+ return NULL;
+}
+
+static void thread_stop(Demuxer *d)
+{
+ InputFile *f = &d->f;
+ DemuxMsg msg;
+
+ if (!d->in_thread_queue)
+ return;
+ av_thread_message_queue_set_err_send(d->in_thread_queue, AVERROR_EOF);
+ while (av_thread_message_queue_recv(d->in_thread_queue, &msg, 0) >= 0)
+ av_packet_free(&msg.pkt);
+
+ pthread_join(d->thread, NULL);
+ av_thread_message_queue_free(&d->in_thread_queue);
+ av_thread_message_queue_free(&f->audio_duration_queue);
+}
+
+static int thread_start(Demuxer *d)
+{
+ int ret;
+ InputFile *f = &d->f;
+
+ if (d->thread_queue_size <= 0)
+ d->thread_queue_size = (nb_input_files > 1 ? 8 : 1);
+
+ if (nb_input_files > 1 &&
+ (f->ctx->pb ? !f->ctx->pb->seekable :
+ strcmp(f->ctx->iformat->name, "lavfi")))
+ d->non_blocking = 1;
+ ret = av_thread_message_queue_alloc(&d->in_thread_queue,
+ d->thread_queue_size, sizeof(DemuxMsg));
+ if (ret < 0)
+ return ret;
+
+ if (d->loop) {
+ int nb_audio_dec = 0;
+
+ for (int i = 0; i < f->nb_streams; i++) {
+ InputStream *ist = f->streams[i];
+ nb_audio_dec += !!(ist->decoding_needed &&
+ ist->st->codecpar->codec_type == AVMEDIA_TYPE_AUDIO);
+ }
+
+ if (nb_audio_dec) {
+ ret = av_thread_message_queue_alloc(&f->audio_duration_queue,
+ nb_audio_dec, sizeof(LastFrameDuration));
+ if (ret < 0)
+ goto fail;
+ f->audio_duration_queue_size = nb_audio_dec;
+ }
+ }
+
+ if ((ret = pthread_create(&d->thread, NULL, input_thread, d))) {
+ av_log(NULL, AV_LOG_ERROR, "pthread_create failed: %s. Try to increase `ulimit -v` or decrease `ulimit -s`.\n", strerror(ret));
+ ret = AVERROR(ret);
+ goto fail;
+ }
+
+ return 0;
+fail:
+ av_thread_message_queue_free(&d->in_thread_queue);
+ return ret;
+}
+
+int ifile_get_packet(InputFile *f, AVPacket **pkt)
+{
+ Demuxer *d = demuxer_from_ifile(f);
+ InputStream *ist;
+ DemuxMsg msg;
+ int ret;
+
+ if (!d->in_thread_queue) {
+ ret = thread_start(d);
+ if (ret < 0)
+ return ret;
+ }
+
+ if (f->readrate || f->rate_emu) {
+ int i;
+ int64_t file_start = copy_ts * (
+ (f->start_time_effective != AV_NOPTS_VALUE ? f->start_time_effective * !start_at_zero : 0) +
+ (f->start_time != AV_NOPTS_VALUE ? f->start_time : 0)
+ );
+ float scale = f->rate_emu ? 1.0 : f->readrate;
+ for (i = 0; i < f->nb_streams; i++) {
+ InputStream *ist = f->streams[i];
+ int64_t stream_ts_offset, pts, now;
+ if (!ist->nb_packets || (ist->decoding_needed && !ist->got_output)) continue;
+ stream_ts_offset = FFMAX(ist->first_dts != AV_NOPTS_VALUE ? ist->first_dts : 0, file_start);
+ pts = av_rescale(ist->dts, 1000000, AV_TIME_BASE);
+ now = (av_gettime_relative() - ist->start) * scale + stream_ts_offset;
+ if (pts > now)
+ return AVERROR(EAGAIN);
+ }
+ }
+
+ ret = av_thread_message_queue_recv(d->in_thread_queue, &msg,
+ d->non_blocking ?
+ AV_THREAD_MESSAGE_NONBLOCK : 0);
+ if (ret < 0)
+ return ret;
+ if (msg.looping)
+ return 1;
+
+ ist = f->streams[msg.pkt->stream_index];
+ ist->last_pkt_repeat_pict = msg.repeat_pict;
+
+ *pkt = msg.pkt;
+ return 0;
+}
+
+static void ist_free(InputStream **pist)
+{
+ InputStream *ist = *pist;
+
+ if (!ist)
+ return;
+
+ av_frame_free(&ist->decoded_frame);
+ av_packet_free(&ist->pkt);
+ av_dict_free(&ist->decoder_opts);
+ avsubtitle_free(&ist->prev_sub.subtitle);
+ av_frame_free(&ist->sub2video.frame);
+ av_freep(&ist->filters);
+ av_freep(&ist->hwaccel_device);
+ av_freep(&ist->dts_buffer);
+
+ avcodec_free_context(&ist->dec_ctx);
+ avcodec_parameters_free(&ist->par);
+
+ av_freep(pist);
+}
+
+void ifile_close(InputFile **pf)
+{
+ InputFile *f = *pf;
+ Demuxer *d = demuxer_from_ifile(f);
+
+ if (!f)
+ return;
+
+ thread_stop(d);
+
+ for (int i = 0; i < f->nb_streams; i++)
+ ist_free(&f->streams[i]);
+ av_freep(&f->streams);
+
+ avformat_close_input(&f->ctx);
+
+ av_freep(pf);
+}
+
+static const AVCodec *choose_decoder(const OptionsContext *o, AVFormatContext *s, AVStream *st,
+ enum HWAccelID hwaccel_id, enum AVHWDeviceType hwaccel_device_type)
+
+{
+ char *codec_name = NULL;
+
+ MATCH_PER_STREAM_OPT(codec_names, str, codec_name, s, st);
+ if (codec_name) {
+ const AVCodec *codec = find_codec_or_die(NULL, codec_name, st->codecpar->codec_type, 0);
+ st->codecpar->codec_id = codec->id;
+ if (recast_media && st->codecpar->codec_type != codec->type)
+ st->codecpar->codec_type = codec->type;
+ return codec;
+ } else {
+ if (st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO &&
+ hwaccel_id == HWACCEL_GENERIC &&
+ hwaccel_device_type != AV_HWDEVICE_TYPE_NONE) {
+ const AVCodec *c;
+ void *i = NULL;
+
+ while ((c = av_codec_iterate(&i))) {
+ const AVCodecHWConfig *config;
+
+ if (c->id != st->codecpar->codec_id ||
+ !av_codec_is_decoder(c))
+ continue;
+
+ for (int j = 0; config = avcodec_get_hw_config(c, j); j++) {
+ if (config->device_type == hwaccel_device_type) {
+ av_log(NULL, AV_LOG_VERBOSE, "Selecting decoder '%s' because of requested hwaccel method %s\n",
+ c->name, av_hwdevice_get_type_name(hwaccel_device_type));
+ return c;
+ }
+ }
+ }
+ }
+
+ return avcodec_find_decoder(st->codecpar->codec_id);
+ }
+}
+
+static int guess_input_channel_layout(InputStream *ist)
+{
+ AVCodecContext *dec = ist->dec_ctx;
+
+ if (dec->ch_layout.order == AV_CHANNEL_ORDER_UNSPEC) {
+ char layout_name[256];
+
+ if (dec->ch_layout.nb_channels > ist->guess_layout_max)
+ return 0;
+ av_channel_layout_default(&dec->ch_layout, dec->ch_layout.nb_channels);
+ if (dec->ch_layout.order == AV_CHANNEL_ORDER_UNSPEC)
+ return 0;
+ av_channel_layout_describe(&dec->ch_layout, layout_name, sizeof(layout_name));
+ av_log(NULL, AV_LOG_WARNING, "Guessed Channel Layout for Input Stream "
+ "#%d.%d : %s\n", ist->file_index, ist->st->index, layout_name);
+ }
+ return 1;
+}
+
+static void add_display_matrix_to_stream(const OptionsContext *o,
+ AVFormatContext *ctx, AVStream *st)
+{
+ double rotation = DBL_MAX;
+ int hflip = -1, vflip = -1;
+ int hflip_set = 0, vflip_set = 0, rotation_set = 0;
+ int32_t *buf;
+
+ MATCH_PER_STREAM_OPT(display_rotations, dbl, rotation, ctx, st);
+ MATCH_PER_STREAM_OPT(display_hflips, i, hflip, ctx, st);
+ MATCH_PER_STREAM_OPT(display_vflips, i, vflip, ctx, st);
+
+ rotation_set = rotation != DBL_MAX;
+ hflip_set = hflip != -1;
+ vflip_set = vflip != -1;
+
+ if (!rotation_set && !hflip_set && !vflip_set)
+ return;
+
+ buf = (int32_t *)av_stream_new_side_data(st, AV_PKT_DATA_DISPLAYMATRIX, sizeof(int32_t) * 9);
+ if (!buf) {
+ av_log(NULL, AV_LOG_FATAL, "Failed to generate a display matrix!\n");
+ exit_program(1);
+ }
+
+ av_display_rotation_set(buf,
+ rotation_set ? -(rotation) : -0.0f);
+
+ av_display_matrix_flip(buf,
+ hflip_set ? hflip : 0,
+ vflip_set ? vflip : 0);
+}
+
+/* Add all the streams from the given input file to the demuxer */
+static void add_input_streams(const OptionsContext *o, Demuxer *d)
+{
+ InputFile *f = &d->f;
+ AVFormatContext *ic = f->ctx;
+ int i, ret;
+
+ for (i = 0; i < ic->nb_streams; i++) {
+ AVStream *st = ic->streams[i];
+ AVCodecParameters *par = st->codecpar;
+ InputStream *ist;
+ char *framerate = NULL, *hwaccel_device = NULL;
+ const char *hwaccel = NULL;
+ char *hwaccel_output_format = NULL;
+ char *codec_tag = NULL;
+ char *next;
+ char *discard_str = NULL;
+ const AVClass *cc = avcodec_get_class();
+ const AVOption *discard_opt = av_opt_find(&cc, "skip_frame", NULL,
+ 0, AV_OPT_SEARCH_FAKE_OBJ);
+
+ ist = ALLOC_ARRAY_ELEM(f->streams, f->nb_streams);
+ ist->st = st;
+ ist->file_index = f->index;
+ ist->discard = 1;
+ st->discard = AVDISCARD_ALL;
+ ist->nb_samples = 0;
+ ist->first_dts = AV_NOPTS_VALUE;
+ ist->min_pts = INT64_MAX;
+ ist->max_pts = INT64_MIN;
+
+ ist->ts_scale = 1.0;
+ MATCH_PER_STREAM_OPT(ts_scale, dbl, ist->ts_scale, ic, st);
+
+ ist->autorotate = 1;
+ MATCH_PER_STREAM_OPT(autorotate, i, ist->autorotate, ic, st);
+
+ MATCH_PER_STREAM_OPT(codec_tags, str, codec_tag, ic, st);
+ if (codec_tag) {
+ uint32_t tag = strtol(codec_tag, &next, 0);
+ if (*next)
+ tag = AV_RL32(codec_tag);
+ st->codecpar->codec_tag = tag;
+ }
+
+ if (st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {
+ add_display_matrix_to_stream(o, ic, st);
+
+ MATCH_PER_STREAM_OPT(hwaccels, str, hwaccel, ic, st);
+ MATCH_PER_STREAM_OPT(hwaccel_output_formats, str,
+ hwaccel_output_format, ic, st);
+
+ if (!hwaccel_output_format && hwaccel && !strcmp(hwaccel, "cuvid")) {
+ av_log(NULL, AV_LOG_WARNING,
+ "WARNING: defaulting hwaccel_output_format to cuda for compatibility "
+ "with old commandlines. This behaviour is DEPRECATED and will be removed "
+ "in the future. Please explicitly set \"-hwaccel_output_format cuda\".\n");
+ ist->hwaccel_output_format = AV_PIX_FMT_CUDA;
+ } else if (!hwaccel_output_format && hwaccel && !strcmp(hwaccel, "qsv")) {
+ av_log(NULL, AV_LOG_WARNING,
+ "WARNING: defaulting hwaccel_output_format to qsv for compatibility "
+ "with old commandlines. This behaviour is DEPRECATED and will be removed "
+ "in the future. Please explicitly set \"-hwaccel_output_format qsv\".\n");
+ ist->hwaccel_output_format = AV_PIX_FMT_QSV;
+ } else if (!hwaccel_output_format && hwaccel && !strcmp(hwaccel, "mediacodec")) {
+ // There is no real AVHWFrameContext implementation. Set
+ // hwaccel_output_format to avoid av_hwframe_transfer_data error.
+ ist->hwaccel_output_format = AV_PIX_FMT_MEDIACODEC;
+ } else if (hwaccel_output_format) {
+ ist->hwaccel_output_format = av_get_pix_fmt(hwaccel_output_format);
+ if (ist->hwaccel_output_format == AV_PIX_FMT_NONE) {
+ av_log(NULL, AV_LOG_FATAL, "Unrecognised hwaccel output "
+ "format: %s", hwaccel_output_format);
+ }
+ } else {
+ ist->hwaccel_output_format = AV_PIX_FMT_NONE;
+ }
+
+ if (hwaccel) {
+ // The NVDEC hwaccels use a CUDA device, so remap the name here.
+ if (!strcmp(hwaccel, "nvdec") || !strcmp(hwaccel, "cuvid"))
+ hwaccel = "cuda";
+
+ if (!strcmp(hwaccel, "none"))
+ ist->hwaccel_id = HWACCEL_NONE;
+ else if (!strcmp(hwaccel, "auto"))
+ ist->hwaccel_id = HWACCEL_AUTO;
+ else {
+ enum AVHWDeviceType type = av_hwdevice_find_type_by_name(hwaccel);
+ if (type != AV_HWDEVICE_TYPE_NONE) {
+ ist->hwaccel_id = HWACCEL_GENERIC;
+ ist->hwaccel_device_type = type;
+ }
+
+ if (!ist->hwaccel_id) {
+ av_log(NULL, AV_LOG_FATAL, "Unrecognized hwaccel: %s.\n",
+ hwaccel);
+ av_log(NULL, AV_LOG_FATAL, "Supported hwaccels: ");
+ type = AV_HWDEVICE_TYPE_NONE;
+ while ((type = av_hwdevice_iterate_types(type)) !=
+ AV_HWDEVICE_TYPE_NONE)
+ av_log(NULL, AV_LOG_FATAL, "%s ",
+ av_hwdevice_get_type_name(type));
+ av_log(NULL, AV_LOG_FATAL, "\n");
+ exit_program(1);
+ }
+ }
+ }
+
+ MATCH_PER_STREAM_OPT(hwaccel_devices, str, hwaccel_device, ic, st);
+ if (hwaccel_device) {
+ ist->hwaccel_device = av_strdup(hwaccel_device);
+ if (!ist->hwaccel_device)
+ report_and_exit(AVERROR(ENOMEM));
+ }
+
+ ist->hwaccel_pix_fmt = AV_PIX_FMT_NONE;
+ }
+
+ ist->dec = choose_decoder(o, ic, st, ist->hwaccel_id, ist->hwaccel_device_type);
+ ist->decoder_opts = filter_codec_opts(o->g->codec_opts, ist->st->codecpar->codec_id, ic, st, ist->dec);
+
+ ist->reinit_filters = -1;
+ MATCH_PER_STREAM_OPT(reinit_filters, i, ist->reinit_filters, ic, st);
+
+ MATCH_PER_STREAM_OPT(discard, str, discard_str, ic, st);
+ ist->user_set_discard = AVDISCARD_NONE;
+
+ if ((o->video_disable && ist->st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) ||
+ (o->audio_disable && ist->st->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) ||
+ (o->subtitle_disable && ist->st->codecpar->codec_type == AVMEDIA_TYPE_SUBTITLE) ||
+ (o->data_disable && ist->st->codecpar->codec_type == AVMEDIA_TYPE_DATA))
+ ist->user_set_discard = AVDISCARD_ALL;
+
+ if (discard_str && av_opt_eval_int(&cc, discard_opt, discard_str, &ist->user_set_discard) < 0) {
+ av_log(NULL, AV_LOG_ERROR, "Error parsing discard %s.\n",
+ discard_str);
+ exit_program(1);
+ }
+
+ ist->filter_in_rescale_delta_last = AV_NOPTS_VALUE;
+ ist->prev_pkt_pts = AV_NOPTS_VALUE;
+
+ ist->dec_ctx = avcodec_alloc_context3(ist->dec);
+ if (!ist->dec_ctx)
+ report_and_exit(AVERROR(ENOMEM));
+
+ ret = avcodec_parameters_to_context(ist->dec_ctx, par);
+ if (ret < 0) {
+ av_log(NULL, AV_LOG_ERROR, "Error initializing the decoder context.\n");
+ exit_program(1);
+ }
+
+ ist->decoded_frame = av_frame_alloc();
+ if (!ist->decoded_frame)
+ report_and_exit(AVERROR(ENOMEM));
+
+ ist->pkt = av_packet_alloc();
+ if (!ist->pkt)
+ report_and_exit(AVERROR(ENOMEM));
+
+ if (o->bitexact)
+ ist->dec_ctx->flags |= AV_CODEC_FLAG_BITEXACT;
+
+ switch (par->codec_type) {
+ case AVMEDIA_TYPE_VIDEO:
+ // avformat_find_stream_info() doesn't set this for us anymore.
+ ist->dec_ctx->framerate = st->avg_frame_rate;
+
+ MATCH_PER_STREAM_OPT(frame_rates, str, framerate, ic, st);
+ if (framerate && av_parse_video_rate(&ist->framerate,
+ framerate) < 0) {
+ av_log(NULL, AV_LOG_ERROR, "Error parsing framerate %s.\n",
+ framerate);
+ exit_program(1);
+ }
+
+ ist->top_field_first = -1;
+ MATCH_PER_STREAM_OPT(top_field_first, i, ist->top_field_first, ic, st);
+
+ ist->framerate_guessed = av_guess_frame_rate(ic, st, NULL);
+
+ break;
+ case AVMEDIA_TYPE_AUDIO:
+ ist->guess_layout_max = INT_MAX;
+ MATCH_PER_STREAM_OPT(guess_layout_max, i, ist->guess_layout_max, ic, st);
+ guess_input_channel_layout(ist);
+ break;
+ case AVMEDIA_TYPE_DATA:
+ case AVMEDIA_TYPE_SUBTITLE: {
+ char *canvas_size = NULL;
+ MATCH_PER_STREAM_OPT(fix_sub_duration, i, ist->fix_sub_duration, ic, st);
+ MATCH_PER_STREAM_OPT(canvas_sizes, str, canvas_size, ic, st);
+ if (canvas_size &&
+ av_parse_video_size(&ist->dec_ctx->width, &ist->dec_ctx->height, canvas_size) < 0) {
+ av_log(NULL, AV_LOG_FATAL, "Invalid canvas size: %s.\n", canvas_size);
+ exit_program(1);
+ }
+ break;
+ }
+ case AVMEDIA_TYPE_ATTACHMENT:
+ case AVMEDIA_TYPE_UNKNOWN:
+ break;
+ default:
+ abort();
+ }
+
+ ist->par = avcodec_parameters_alloc();
+ if (!ist->par)
+ report_and_exit(AVERROR(ENOMEM));
+
+ ret = avcodec_parameters_from_context(ist->par, ist->dec_ctx);
+ if (ret < 0) {
+ av_log(NULL, AV_LOG_ERROR, "Error initializing the decoder context.\n");
+ exit_program(1);
+ }
+ }
+}
+
+static void dump_attachment(AVStream *st, const char *filename)
+{
+ int ret;
+ AVIOContext *out = NULL;
+ const AVDictionaryEntry *e;
+
+ if (!st->codecpar->extradata_size) {
+ av_log(NULL, AV_LOG_WARNING, "No extradata to dump in stream #%d:%d.\n",
+ nb_input_files - 1, st->index);
+ return;
+ }
+ if (!*filename && (e = av_dict_get(st->metadata, "filename", NULL, 0)))
+ filename = e->value;
+ if (!*filename) {
+ av_log(NULL, AV_LOG_FATAL, "No filename specified and no 'filename' tag"
+ "in stream #%d:%d.\n", nb_input_files - 1, st->index);
+ exit_program(1);
+ }
+
+ assert_file_overwrite(filename);
+
+ if ((ret = avio_open2(&out, filename, AVIO_FLAG_WRITE, &int_cb, NULL)) < 0) {
+ av_log(NULL, AV_LOG_FATAL, "Could not open file %s for writing.\n",
+ filename);
+ exit_program(1);
+ }
+
+ avio_write(out, st->codecpar->extradata, st->codecpar->extradata_size);
+ avio_flush(out);
+ avio_close(out);
+}
+
+int ifile_open(const OptionsContext *o, const char *filename)
+{
+ Demuxer *d;
+ InputFile *f;
+ AVFormatContext *ic;
+ const AVInputFormat *file_iformat = NULL;
+ int err, i, ret;
+ int64_t timestamp;
+ AVDictionary *unused_opts = NULL;
+ const AVDictionaryEntry *e = NULL;
+ char * video_codec_name = NULL;
+ char * audio_codec_name = NULL;
+ char *subtitle_codec_name = NULL;
+ char * data_codec_name = NULL;
+ int scan_all_pmts_set = 0;
+
+ int64_t start_time = o->start_time;
+ int64_t start_time_eof = o->start_time_eof;
+ int64_t stop_time = o->stop_time;
+ int64_t recording_time = o->recording_time;
+
+ if (stop_time != INT64_MAX && recording_time != INT64_MAX) {
+ stop_time = INT64_MAX;
+ av_log(NULL, AV_LOG_WARNING, "-t and -to cannot be used together; using -t.\n");
+ }
+
+ if (stop_time != INT64_MAX && recording_time == INT64_MAX) {
+ int64_t start = start_time == AV_NOPTS_VALUE ? 0 : start_time;
+ if (stop_time <= start) {
+ av_log(NULL, AV_LOG_ERROR, "-to value smaller than -ss; aborting.\n");
+ exit_program(1);
+ } else {
+ recording_time = stop_time - start;
+ }
+ }
+
+ if (o->format) {
+ if (!(file_iformat = av_find_input_format(o->format))) {
+ av_log(NULL, AV_LOG_FATAL, "Unknown input format: '%s'\n", o->format);
+ exit_program(1);
+ }
+ }
+
+ if (!strcmp(filename, "-"))
+ filename = "fd:";
+
+ stdin_interaction &= strncmp(filename, "pipe:", 5) &&
+ strcmp(filename, "fd:") &&
+ strcmp(filename, "/dev/stdin");
+
+ /* get default parameters from command line */
+ ic = avformat_alloc_context();
+ if (!ic)
+ report_and_exit(AVERROR(ENOMEM));
+ if (o->nb_audio_sample_rate) {
+ av_dict_set_int(&o->g->format_opts, "sample_rate", o->audio_sample_rate[o->nb_audio_sample_rate - 1].u.i, 0);
+ }
+ if (o->nb_audio_channels) {
+ const AVClass *priv_class;
+ if (file_iformat && (priv_class = file_iformat->priv_class) &&
+ av_opt_find(&priv_class, "ch_layout", NULL, 0,
+ AV_OPT_SEARCH_FAKE_OBJ)) {
+ char buf[32];
+ snprintf(buf, sizeof(buf), "%dC", o->audio_channels[o->nb_audio_channels - 1].u.i);
+ av_dict_set(&o->g->format_opts, "ch_layout", buf, 0);
+ }
+ }
+ if (o->nb_audio_ch_layouts) {
+ const AVClass *priv_class;
+ if (file_iformat && (priv_class = file_iformat->priv_class) &&
+ av_opt_find(&priv_class, "ch_layout", NULL, 0,
+ AV_OPT_SEARCH_FAKE_OBJ)) {
+ av_dict_set(&o->g->format_opts, "ch_layout", o->audio_ch_layouts[o->nb_audio_ch_layouts - 1].u.str, 0);
+ }
+ }
+ if (o->nb_frame_rates) {
+ const AVClass *priv_class;
+ /* set the format-level framerate option;
+ * this is important for video grabbers, e.g. x11 */
+ if (file_iformat && (priv_class = file_iformat->priv_class) &&
+ av_opt_find(&priv_class, "framerate", NULL, 0,
+ AV_OPT_SEARCH_FAKE_OBJ)) {
+ av_dict_set(&o->g->format_opts, "framerate",
+ o->frame_rates[o->nb_frame_rates - 1].u.str, 0);
+ }
+ }
+ if (o->nb_frame_sizes) {
+ av_dict_set(&o->g->format_opts, "video_size", o->frame_sizes[o->nb_frame_sizes - 1].u.str, 0);
+ }
+ if (o->nb_frame_pix_fmts)
+ av_dict_set(&o->g->format_opts, "pixel_format", o->frame_pix_fmts[o->nb_frame_pix_fmts - 1].u.str, 0);
+
+ MATCH_PER_TYPE_OPT(codec_names, str, video_codec_name, ic, "v");
+ MATCH_PER_TYPE_OPT(codec_names, str, audio_codec_name, ic, "a");
+ MATCH_PER_TYPE_OPT(codec_names, str, subtitle_codec_name, ic, "s");
+ MATCH_PER_TYPE_OPT(codec_names, str, data_codec_name, ic, "d");
+
+ if (video_codec_name)
+ ic->video_codec = find_codec_or_die(NULL, video_codec_name , AVMEDIA_TYPE_VIDEO , 0);
+ if (audio_codec_name)
+ ic->audio_codec = find_codec_or_die(NULL, audio_codec_name , AVMEDIA_TYPE_AUDIO , 0);
+ if (subtitle_codec_name)
+ ic->subtitle_codec = find_codec_or_die(NULL, subtitle_codec_name, AVMEDIA_TYPE_SUBTITLE, 0);
+ if (data_codec_name)
+ ic->data_codec = find_codec_or_die(NULL, data_codec_name , AVMEDIA_TYPE_DATA , 0);
+
+ ic->video_codec_id = video_codec_name ? ic->video_codec->id : AV_CODEC_ID_NONE;
+ ic->audio_codec_id = audio_codec_name ? ic->audio_codec->id : AV_CODEC_ID_NONE;
+ ic->subtitle_codec_id = subtitle_codec_name ? ic->subtitle_codec->id : AV_CODEC_ID_NONE;
+ ic->data_codec_id = data_codec_name ? ic->data_codec->id : AV_CODEC_ID_NONE;
+
+ ic->flags |= AVFMT_FLAG_NONBLOCK;
+ if (o->bitexact)
+ ic->flags |= AVFMT_FLAG_BITEXACT;
+ ic->interrupt_callback = int_cb;
+
+ if (!av_dict_get(o->g->format_opts, "scan_all_pmts", NULL, AV_DICT_MATCH_CASE)) {
+ av_dict_set(&o->g->format_opts, "scan_all_pmts", "1", AV_DICT_DONT_OVERWRITE);
+ scan_all_pmts_set = 1;
+ }
+ /* open the input file with generic avformat function */
+ err = avformat_open_input(&ic, filename, file_iformat, &o->g->format_opts);
+ if (err < 0) {
+ print_error(filename, err);
+ if (err == AVERROR_PROTOCOL_NOT_FOUND)
+ av_log(NULL, AV_LOG_ERROR, "Did you mean file:%s?\n", filename);
+ exit_program(1);
+ }
+ if (scan_all_pmts_set)
+ av_dict_set(&o->g->format_opts, "scan_all_pmts", NULL, AV_DICT_MATCH_CASE);
+ remove_avoptions(&o->g->format_opts, o->g->codec_opts);
+ assert_avoptions(o->g->format_opts);
+
+ /* apply forced codec ids */
+ for (i = 0; i < ic->nb_streams; i++)
+ choose_decoder(o, ic, ic->streams[i], HWACCEL_NONE, AV_HWDEVICE_TYPE_NONE);
+
+ if (o->find_stream_info) {
+ AVDictionary **opts = setup_find_stream_info_opts(ic, o->g->codec_opts);
+ int orig_nb_streams = ic->nb_streams;
+
+ /* If not enough info to get the stream parameters, we decode the
+ first frames to get it. (used in mpeg case for example) */
+ ret = avformat_find_stream_info(ic, opts);
+
+ for (i = 0; i < orig_nb_streams; i++)
+ av_dict_free(&opts[i]);
+ av_freep(&opts);
+
+ if (ret < 0) {
+ av_log(NULL, AV_LOG_FATAL, "%s: could not find codec parameters\n", filename);
+ if (ic->nb_streams == 0) {
+ avformat_close_input(&ic);
+ exit_program(1);
+ }
+ }
+ }
+
+ if (start_time != AV_NOPTS_VALUE && start_time_eof != AV_NOPTS_VALUE) {
+ av_log(NULL, AV_LOG_WARNING, "Cannot use -ss and -sseof both, using -ss for %s\n", filename);
+ start_time_eof = AV_NOPTS_VALUE;
+ }
+
+ if (start_time_eof != AV_NOPTS_VALUE) {
+ if (start_time_eof >= 0) {
+ av_log(NULL, AV_LOG_ERROR, "-sseof value must be negative; aborting\n");
+ exit_program(1);
+ }
+ if (ic->duration > 0) {
+ start_time = start_time_eof + ic->duration;
+ if (start_time < 0) {
+ av_log(NULL, AV_LOG_WARNING, "-sseof value seeks to before start of file %s; ignored\n", filename);
+ start_time = AV_NOPTS_VALUE;
+ }
+ } else
+ av_log(NULL, AV_LOG_WARNING, "Cannot use -sseof, duration of %s not known\n", filename);
+ }
+ timestamp = (start_time == AV_NOPTS_VALUE) ? 0 : start_time;
+ /* add the stream start time */
+ if (!o->seek_timestamp && ic->start_time != AV_NOPTS_VALUE)
+ timestamp += ic->start_time;
+
+ /* if seeking requested, we execute it */
+ if (start_time != AV_NOPTS_VALUE) {
+ int64_t seek_timestamp = timestamp;
+
+ if (!(ic->iformat->flags & AVFMT_SEEK_TO_PTS)) {
+ int dts_heuristic = 0;
+ for (i=0; inb_streams; i++) {
+ const AVCodecParameters *par = ic->streams[i]->codecpar;
+ if (par->video_delay) {
+ dts_heuristic = 1;
+ break;
+ }
+ }
+ if (dts_heuristic) {
+ seek_timestamp -= 3*AV_TIME_BASE / 23;
+ }
+ }
+ ret = avformat_seek_file(ic, -1, INT64_MIN, seek_timestamp, seek_timestamp, 0);
+ if (ret < 0) {
+ av_log(NULL, AV_LOG_WARNING, "%s: could not seek to position %0.3f\n",
+ filename, (double)timestamp / AV_TIME_BASE);
+ }
+ }
+
+ d = allocate_array_elem(&input_files, sizeof(*d), &nb_input_files);
+ f = &d->f;
+
+ f->ctx = ic;
+ f->index = nb_input_files - 1;
+ f->start_time = start_time;
+ f->recording_time = recording_time;
+ f->input_sync_ref = o->input_sync_ref;
+ f->input_ts_offset = o->input_ts_offset;
+ f->ts_offset = o->input_ts_offset - (copy_ts ? (start_at_zero && ic->start_time != AV_NOPTS_VALUE ? ic->start_time : 0) : timestamp);
+ f->rate_emu = o->rate_emu;
+ f->accurate_seek = o->accurate_seek;
+ d->loop = o->loop;
+ d->duration = 0;
+ d->time_base = (AVRational){ 1, 1 };
+
+ f->readrate = o->readrate ? o->readrate : 0.0;
+ if (f->readrate < 0.0f) {
+ av_log(NULL, AV_LOG_ERROR, "Option -readrate for Input #%d is %0.3f; it must be non-negative.\n", f->index, f->readrate);
+ exit_program(1);
+ }
+ if (f->readrate && f->rate_emu) {
+ av_log(NULL, AV_LOG_WARNING, "Both -readrate and -re set for Input #%d. Using -readrate %0.3f.\n", f->index, f->readrate);
+ f->rate_emu = 0;
+ }
+
+ d->thread_queue_size = o->thread_queue_size;
+
+ /* update the current parameters so that they match the one of the input stream */
+ add_input_streams(o, d);
+
+ /* dump the file content */
+ av_dump_format(ic, f->index, filename, 0);
+
+ /* check if all codec options have been used */
+ unused_opts = strip_specifiers(o->g->codec_opts);
+ for (i = 0; i < f->nb_streams; i++) {
+ e = NULL;
+ while ((e = av_dict_iterate(f->streams[i]->decoder_opts, e)))
+ av_dict_set(&unused_opts, e->key, NULL, 0);
+ }
+
+ e = NULL;
+ while ((e = av_dict_iterate(unused_opts, e))) {
+ const AVClass *class = avcodec_get_class();
+ const AVOption *option = av_opt_find(&class, e->key, NULL, 0,
+ AV_OPT_SEARCH_CHILDREN | AV_OPT_SEARCH_FAKE_OBJ);
+ const AVClass *fclass = avformat_get_class();
+ const AVOption *foption = av_opt_find(&fclass, e->key, NULL, 0,
+ AV_OPT_SEARCH_CHILDREN | AV_OPT_SEARCH_FAKE_OBJ);
+ if (!option || foption)
+ continue;
+
+
+ if (!(option->flags & AV_OPT_FLAG_DECODING_PARAM)) {
+ av_log(NULL, AV_LOG_ERROR, "Codec AVOption %s (%s) specified for "
+ "input file #%d (%s) is not a decoding option.\n", e->key,
+ option->help ? option->help : "", f->index,
+ filename);
+ exit_program(1);
+ }
+
+ av_log(NULL, AV_LOG_WARNING, "Codec AVOption %s (%s) specified for "
+ "input file #%d (%s) has not been used for any stream. The most "
+ "likely reason is either wrong type (e.g. a video option with "
+ "no video streams) or that it is a private option of some decoder "
+ "which was not actually used for any stream.\n", e->key,
+ option->help ? option->help : "", f->index, filename);
+ }
+ av_dict_free(&unused_opts);
+
+ for (i = 0; i < o->nb_dump_attachment; i++) {
+ int j;
+
+ for (j = 0; j < ic->nb_streams; j++) {
+ AVStream *st = ic->streams[j];
+
+ if (check_stream_specifier(ic, st, o->dump_attachment[i].specifier) == 1)
+ dump_attachment(st, o->dump_attachment[i].u.str);
+ }
+ }
+
+ return 0;
+}
diff --git a/app/src/main/cpp/ffmpeg/ffmpeg_filter.c b/app/src/main/cpp/ffmpeg/ffmpeg_filter.c
index 695df2bc..1f5bbf6c 100644
--- a/app/src/main/cpp/ffmpeg/ffmpeg_filter.c
+++ b/app/src/main/cpp/ffmpeg/ffmpeg_filter.c
@@ -20,12 +20,11 @@
#include
-#include "ffmpeg/ffmpeg.h"
+#include "ffmpeg.h"
#include "libavfilter/avfilter.h"
#include "libavfilter/buffersink.h"
-
-#include "libavresample/avresample.h"
+#include "libavfilter/buffersrc.h"
#include "libavutil/avassert.h"
#include "libavutil/avstring.h"
@@ -38,41 +37,37 @@
#include "libavutil/imgutils.h"
#include "libavutil/samplefmt.h"
-
-static const enum AVPixelFormat *get_compliance_unofficial_pix_fmts(enum AVCodecID codec_id, const enum AVPixelFormat default_formats[])
+// FIXME: YUV420P etc. are actually supported with full color range,
+// yet the latter information isn't available here.
+static const enum AVPixelFormat *get_compliance_normal_pix_fmts(const AVCodec *codec, const enum AVPixelFormat default_formats[])
{
static const enum AVPixelFormat mjpeg_formats[] =
{ AV_PIX_FMT_YUVJ420P, AV_PIX_FMT_YUVJ422P, AV_PIX_FMT_YUVJ444P,
- AV_PIX_FMT_YUV420P, AV_PIX_FMT_YUV422P, AV_PIX_FMT_YUV444P,
AV_PIX_FMT_NONE };
- static const enum AVPixelFormat ljpeg_formats[] =
- { AV_PIX_FMT_BGR24 , AV_PIX_FMT_BGRA , AV_PIX_FMT_BGR0,
- AV_PIX_FMT_YUVJ420P, AV_PIX_FMT_YUVJ444P, AV_PIX_FMT_YUVJ422P,
- AV_PIX_FMT_YUV420P , AV_PIX_FMT_YUV444P , AV_PIX_FMT_YUV422P,
- AV_PIX_FMT_NONE};
- if (codec_id == AV_CODEC_ID_MJPEG) {
+ if (!strcmp(codec->name, "mjpeg")) {
return mjpeg_formats;
- } else if (codec_id == AV_CODEC_ID_LJPEG) {
- return ljpeg_formats;
} else {
return default_formats;
}
}
-enum AVPixelFormat choose_pixel_fmt(AVStream *st, AVCodecContext *enc_ctx, AVCodec *codec, enum AVPixelFormat target)
+static enum AVPixelFormat
+choose_pixel_fmt(const AVCodec *codec, enum AVPixelFormat target,
+ int strict_std_compliance)
{
if (codec && codec->pix_fmts) {
const enum AVPixelFormat *p = codec->pix_fmts;
const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(target);
+ //FIXME: This should check for AV_PIX_FMT_FLAG_ALPHA after PAL8 pixel format without alpha is implemented
int has_alpha = desc ? desc->nb_components % 2 == 0 : 0;
enum AVPixelFormat best= AV_PIX_FMT_NONE;
- if (enc_ctx->strict_std_compliance <= FF_COMPLIANCE_UNOFFICIAL) {
- p = get_compliance_unofficial_pix_fmts(enc_ctx->codec_id, p);
+ if (strict_std_compliance > FF_COMPLIANCE_UNOFFICIAL) {
+ p = get_compliance_normal_pix_fmts(codec, p);
}
for (; *p != AV_PIX_FMT_NONE; p++) {
- best= avcodec_find_best_pix_fmt_of_2(best, *p, target, has_alpha, NULL);
+ best = av_find_best_pix_fmt_of_2(best, *p, target, has_alpha, NULL);
if (*p == target)
break;
}
@@ -89,145 +84,155 @@ enum AVPixelFormat choose_pixel_fmt(AVStream *st, AVCodecContext *enc_ctx, AVCod
return target;
}
-void choose_sample_fmt(AVStream *st, AVCodec *codec)
-{
- if (codec && codec->sample_fmts) {
- const enum AVSampleFormat *p = codec->sample_fmts;
- for (; *p != -1; p++) {
- if (*p == st->codec->sample_fmt)
- break;
- }
- if (*p == -1) {
- if((codec->capabilities & AV_CODEC_CAP_LOSSLESS) && av_get_sample_fmt_name(st->codec->sample_fmt) > av_get_sample_fmt_name(codec->sample_fmts[0]))
- av_log(NULL, AV_LOG_ERROR, "Conversion will not be lossless.\n");
- if(av_get_sample_fmt_name(st->codec->sample_fmt))
- av_log(NULL, AV_LOG_WARNING,
- "Incompatible sample format '%s' for codec '%s', auto-selecting format '%s'\n",
- av_get_sample_fmt_name(st->codec->sample_fmt),
- codec->name,
- av_get_sample_fmt_name(codec->sample_fmts[0]));
- st->codec->sample_fmt = codec->sample_fmts[0];
- }
- }
-}
-
-static char *choose_pix_fmts(OutputStream *ost)
+/* May return NULL (no pixel format found), a static string or a string
+ * backed by the bprint. Nothing has been written to the AVBPrint in case
+ * NULL is returned. The AVBPrint provided should be clean. */
+static const char *choose_pix_fmts(OutputFilter *ofilter, AVBPrint *bprint)
{
- AVDictionaryEntry *strict_dict = av_dict_get(ost->encoder_opts, "strict", NULL, 0);
+ OutputStream *ost = ofilter->ost;
+ AVCodecContext *enc = ost->enc_ctx;
+ const AVDictionaryEntry *strict_dict = av_dict_get(ost->encoder_opts, "strict", NULL, 0);
if (strict_dict)
// used by choose_pixel_fmt() and below
av_opt_set(ost->enc_ctx, "strict", strict_dict->value, 0);
if (ost->keep_pix_fmt) {
- if (ost->filter)
- avfilter_graph_set_auto_convert(ost->filter->graph->graph,
+ avfilter_graph_set_auto_convert(ofilter->graph->graph,
AVFILTER_AUTO_CONVERT_NONE);
if (ost->enc_ctx->pix_fmt == AV_PIX_FMT_NONE)
return NULL;
- return av_strdup(av_get_pix_fmt_name(ost->enc_ctx->pix_fmt));
+ return av_get_pix_fmt_name(ost->enc_ctx->pix_fmt);
}
if (ost->enc_ctx->pix_fmt != AV_PIX_FMT_NONE) {
- return av_strdup(av_get_pix_fmt_name(choose_pixel_fmt(ost->st, ost->enc_ctx, ost->enc, ost->enc_ctx->pix_fmt)));
- } else if (ost->enc && ost->enc->pix_fmts) {
+ return av_get_pix_fmt_name(choose_pixel_fmt(enc->codec, enc->pix_fmt,
+ ost->enc_ctx->strict_std_compliance));
+ } else if (enc->codec->pix_fmts) {
const enum AVPixelFormat *p;
- AVIOContext *s = NULL;
- uint8_t *ret;
- int len;
-
- if (avio_open_dyn_buf(&s) < 0)
- exit_program(1);
- p = ost->enc->pix_fmts;
- if (ost->enc_ctx->strict_std_compliance <= FF_COMPLIANCE_UNOFFICIAL) {
- p = get_compliance_unofficial_pix_fmts(ost->enc_ctx->codec_id, p);
+ p = enc->codec->pix_fmts;
+ if (ost->enc_ctx->strict_std_compliance > FF_COMPLIANCE_UNOFFICIAL) {
+ p = get_compliance_normal_pix_fmts(enc->codec, p);
}
for (; *p != AV_PIX_FMT_NONE; p++) {
const char *name = av_get_pix_fmt_name(*p);
- avio_printf(s, "%s|", name);
+ av_bprintf(bprint, "%s%c", name, p[1] == AV_PIX_FMT_NONE ? '\0' : '|');
}
- len = avio_close_dyn_buf(s, &ret);
- ret[len - 1] = 0;
- return ret;
+ if (!av_bprint_is_complete(bprint))
+ report_and_exit(AVERROR(ENOMEM));
+ return bprint->str;
} else
return NULL;
}
-/* Define a function for building a string containing a list of
- * allowed formats. */
-#define DEF_CHOOSE_FORMAT(type, var, supported_list, none, get_name) \
-static char *choose_ ## var ## s(OutputStream *ost) \
+/* Define a function for appending a list of allowed formats
+ * to an AVBPrint. If nonempty, the list will have a header. */
+#define DEF_CHOOSE_FORMAT(name, type, var, supported_list, none, printf_format, get_name) \
+static void choose_ ## name (OutputFilter *ofilter, AVBPrint *bprint) \
{ \
- if (ost->enc_ctx->var != none) { \
- get_name(ost->enc_ctx->var); \
- return av_strdup(name); \
- } else if (ost->enc && ost->enc->supported_list) { \
+ if (ofilter->var == none && !ofilter->supported_list) \
+ return; \
+ av_bprintf(bprint, #name "="); \
+ if (ofilter->var != none) { \
+ av_bprintf(bprint, printf_format, get_name(ofilter->var)); \
+ } else { \
const type *p; \
- AVIOContext *s = NULL; \
- uint8_t *ret; \
- int len; \
\
- if (avio_open_dyn_buf(&s) < 0) \
- exit_program(1); \
- \
- for (p = ost->enc->supported_list; *p != none; p++) { \
- get_name(*p); \
- avio_printf(s, "%s|", name); \
+ for (p = ofilter->supported_list; *p != none; p++) { \
+ av_bprintf(bprint, printf_format "|", get_name(*p)); \
} \
- len = avio_close_dyn_buf(s, &ret); \
- ret[len - 1] = 0; \
- return ret; \
- } else \
- return NULL; \
+ if (bprint->len > 0) \
+ bprint->str[--bprint->len] = '\0'; \
+ } \
+ av_bprint_chars(bprint, ':', 1); \
}
-// DEF_CHOOSE_FORMAT(enum AVPixelFormat, pix_fmt, pix_fmts, AV_PIX_FMT_NONE,
-// GET_PIX_FMT_NAME)
+//DEF_CHOOSE_FORMAT(pix_fmts, enum AVPixelFormat, format, formats, AV_PIX_FMT_NONE,
+// GET_PIX_FMT_NAME)
-DEF_CHOOSE_FORMAT(enum AVSampleFormat, sample_fmt, sample_fmts,
- AV_SAMPLE_FMT_NONE, GET_SAMPLE_FMT_NAME)
+DEF_CHOOSE_FORMAT(sample_fmts, enum AVSampleFormat, format, formats,
+ AV_SAMPLE_FMT_NONE, "%s", av_get_sample_fmt_name)
-DEF_CHOOSE_FORMAT(int, sample_rate, supported_samplerates, 0,
- GET_SAMPLE_RATE_NAME)
+DEF_CHOOSE_FORMAT(sample_rates, int, sample_rate, sample_rates, 0,
+ "%d", )
-DEF_CHOOSE_FORMAT(uint64_t, channel_layout, channel_layouts, 0,
- GET_CH_LAYOUT_NAME)
+static void choose_channel_layouts(OutputFilter *ofilter, AVBPrint *bprint)
+{
+ if (av_channel_layout_check(&ofilter->ch_layout)) {
+ av_bprintf(bprint, "channel_layouts=");
+ av_channel_layout_describe_bprint(&ofilter->ch_layout, bprint);
+ } else if (ofilter->ch_layouts) {
+ const AVChannelLayout *p;
+
+ av_bprintf(bprint, "channel_layouts=");
+ for (p = ofilter->ch_layouts; p->nb_channels; p++) {
+ av_channel_layout_describe_bprint(p, bprint);
+ av_bprintf(bprint, "|");
+ }
+ if (bprint->len > 0)
+ bprint->str[--bprint->len] = '\0';
+ } else
+ return;
+ av_bprint_chars(bprint, ':', 1);
+}
-FilterGraph *init_simple_filtergraph(InputStream *ist, OutputStream *ost)
+int init_simple_filtergraph(InputStream *ist, OutputStream *ost)
{
FilterGraph *fg = av_mallocz(sizeof(*fg));
+ OutputFilter *ofilter;
+ InputFilter *ifilter;
if (!fg)
- exit_program(1);
+ report_and_exit(AVERROR(ENOMEM));
fg->index = nb_filtergraphs;
- GROW_ARRAY(fg->outputs, fg->nb_outputs);
- if (!(fg->outputs[0] = av_mallocz(sizeof(*fg->outputs[0]))))
- exit_program(1);
- fg->outputs[0]->ost = ost;
- fg->outputs[0]->graph = fg;
+ ofilter = ALLOC_ARRAY_ELEM(fg->outputs, fg->nb_outputs);
+ ofilter->ost = ost;
+ ofilter->graph = fg;
+ ofilter->format = -1;
- ost->filter = fg->outputs[0];
+ ost->filter = ofilter;
- GROW_ARRAY(fg->inputs, fg->nb_inputs);
- if (!(fg->inputs[0] = av_mallocz(sizeof(*fg->inputs[0]))))
- exit_program(1);
- fg->inputs[0]->ist = ist;
- fg->inputs[0]->graph = fg;
+ ifilter = ALLOC_ARRAY_ELEM(fg->inputs, fg->nb_inputs);
+ ifilter->ist = ist;
+ ifilter->graph = fg;
+ ifilter->format = -1;
+
+ ifilter->frame_queue = av_fifo_alloc2(8, sizeof(AVFrame*), AV_FIFO_FLAG_AUTO_GROW);
+ if (!ifilter->frame_queue)
+ report_and_exit(AVERROR(ENOMEM));
GROW_ARRAY(ist->filters, ist->nb_filters);
- ist->filters[ist->nb_filters - 1] = fg->inputs[0];
+ ist->filters[ist->nb_filters - 1] = ifilter;
GROW_ARRAY(filtergraphs, nb_filtergraphs);
filtergraphs[nb_filtergraphs - 1] = fg;
- return fg;
+ return 0;
+}
+
+static char *describe_filter_link(FilterGraph *fg, AVFilterInOut *inout, int in)
+{
+ AVFilterContext *ctx = inout->filter_ctx;
+ AVFilterPad *pads = in ? ctx->input_pads : ctx->output_pads;
+ int nb_pads = in ? ctx->nb_inputs : ctx->nb_outputs;
+ char *res;
+
+ if (nb_pads > 1)
+ res = av_strdup(ctx->filter->name);
+ else
+ res = av_asprintf("%s:%s", ctx->filter->name,
+ avfilter_pad_get_name(pads, inout->pad_idx));
+ if (!res)
+ report_and_exit(AVERROR(ENOMEM));
+ return res;
}
static void init_input_filter(FilterGraph *fg, AVFilterInOut *in)
{
InputStream *ist = NULL;
enum AVMediaType type = avfilter_pad_get_type(in->filter_ctx->input_pads, in->pad_idx);
+ InputFilter *ifilter;
int i;
// TODO: support other filter types
@@ -251,7 +256,7 @@ static void init_input_filter(FilterGraph *fg, AVFilterInOut *in)
s = input_files[file_idx]->ctx;
for (i = 0; i < s->nb_streams; i++) {
- enum AVMediaType stream_type = s->streams[i]->codec->codec_type;
+ enum AVMediaType stream_type = s->streams[i]->codecpar->codec_type;
if (stream_type != type &&
!(stream_type == AVMEDIA_TYPE_SUBTITLE &&
type == AVMEDIA_TYPE_VIDEO /* sub2video hack */))
@@ -266,15 +271,21 @@ static void init_input_filter(FilterGraph *fg, AVFilterInOut *in)
"matches no streams.\n", p, fg->graph_desc);
exit_program(1);
}
- ist = input_streams[input_files[file_idx]->ist_index + st->index];
+ ist = input_files[file_idx]->streams[st->index];
+ if (ist->user_set_discard == AVDISCARD_ALL) {
+ av_log(NULL, AV_LOG_FATAL, "Stream specifier '%s' in filtergraph description %s "
+ "matches a disabled input stream.\n", p, fg->graph_desc);
+ exit_program(1);
+ }
} else {
/* find the first unused stream of corresponding type */
- for (i = 0; i < nb_input_streams; i++) {
- ist = input_streams[i];
+ for (ist = ist_iter(NULL); ist; ist = ist_iter(ist)) {
+ if (ist->user_set_discard == AVDISCARD_ALL)
+ continue;
if (ist->dec_ctx->codec_type == type && ist->discard)
break;
}
- if (i == nb_input_streams) {
+ if (!ist) {
av_log(NULL, AV_LOG_FATAL, "Cannot find a matching stream for "
"unlabeled input pad %d on filter %s\n", in->pad_idx,
in->filter_ctx->name);
@@ -285,16 +296,172 @@ static void init_input_filter(FilterGraph *fg, AVFilterInOut *in)
ist->discard = 0;
ist->decoding_needed |= DECODING_FOR_FILTER;
+ ist->processing_needed = 1;
ist->st->discard = AVDISCARD_NONE;
- GROW_ARRAY(fg->inputs, fg->nb_inputs);
- if (!(fg->inputs[fg->nb_inputs - 1] = av_mallocz(sizeof(*fg->inputs[0]))))
- exit_program(1);
- fg->inputs[fg->nb_inputs - 1]->ist = ist;
- fg->inputs[fg->nb_inputs - 1]->graph = fg;
+ ifilter = ALLOC_ARRAY_ELEM(fg->inputs, fg->nb_inputs);
+ ifilter->ist = ist;
+ ifilter->graph = fg;
+ ifilter->format = -1;
+ ifilter->type = ist->st->codecpar->codec_type;
+ ifilter->name = describe_filter_link(fg, in, 1);
+
+ ifilter->frame_queue = av_fifo_alloc2(8, sizeof(AVFrame*), AV_FIFO_FLAG_AUTO_GROW);
+ if (!ifilter->frame_queue)
+ report_and_exit(AVERROR(ENOMEM));
GROW_ARRAY(ist->filters, ist->nb_filters);
- ist->filters[ist->nb_filters - 1] = fg->inputs[fg->nb_inputs - 1];
+ ist->filters[ist->nb_filters - 1] = ifilter;
+}
+
+static int read_binary(const char *path, uint8_t **data, int *len)
+{
+ AVIOContext *io = NULL;
+ int64_t fsize;
+ int ret;
+
+ *data = NULL;
+ *len = 0;
+
+ ret = avio_open2(&io, path, AVIO_FLAG_READ, &int_cb, NULL);
+ if (ret < 0) {
+ av_log(NULL, AV_LOG_ERROR, "Cannot open file '%s': %s\n",
+ path, av_err2str(ret));
+ return ret;
+ }
+
+ fsize = avio_size(io);
+ if (fsize < 0 || fsize > INT_MAX) {
+ av_log(NULL, AV_LOG_ERROR, "Cannot obtain size of file %s\n", path);
+ ret = AVERROR(EIO);
+ goto fail;
+ }
+
+ *data = av_malloc(fsize);
+ if (!*data) {
+ ret = AVERROR(ENOMEM);
+ goto fail;
+ }
+
+ ret = avio_read(io, *data, fsize);
+ if (ret != fsize) {
+ av_log(NULL, AV_LOG_ERROR, "Error reading file %s\n", path);
+ ret = ret < 0 ? ret : AVERROR(EIO);
+ goto fail;
+ }
+
+ *len = fsize;
+
+ return 0;
+fail:
+ avio_close(io);
+ av_freep(data);
+ *len = 0;
+ return ret;
+}
+
+static int filter_opt_apply(AVFilterContext *f, const char *key, const char *val)
+{
+ const AVOption *o;
+ int ret;
+
+ ret = av_opt_set(f, key, val, AV_OPT_SEARCH_CHILDREN);
+ if (ret >= 0)
+ return 0;
+
+ if (ret == AVERROR_OPTION_NOT_FOUND && key[0] == '/')
+ o = av_opt_find(f, key + 1, NULL, 0, AV_OPT_SEARCH_CHILDREN);
+ if (!o)
+ goto err_apply;
+
+ // key is a valid option name prefixed with '/'
+ // interpret value as a path from which to load the actual option value
+ key++;
+
+ if (o->type == AV_OPT_TYPE_BINARY) {
+ uint8_t *data;
+ int len;
+
+ ret = read_binary(val, &data, &len);
+ if (ret < 0)
+ goto err_load;
+
+ ret = av_opt_set_bin(f, key, data, len, AV_OPT_SEARCH_CHILDREN);
+ av_freep(&data);
+ } else {
+ char *data = file_read(val);
+ if (!data) {
+ ret = AVERROR(EIO);
+ goto err_load;
+ }
+
+ ret = av_opt_set(f, key, data, AV_OPT_SEARCH_CHILDREN);
+ av_freep(&data);
+ }
+ if (ret < 0)
+ goto err_apply;
+
+ return 0;
+
+err_apply:
+ av_log(NULL, AV_LOG_ERROR,
+ "Error applying option '%s' to filter '%s': %s\n",
+ key, f->filter->name, av_err2str(ret));
+ return ret;
+err_load:
+ av_log(NULL, AV_LOG_ERROR,
+ "Error loading value for option '%s' from file '%s'\n",
+ key, val);
+ return ret;
+}
+
+static int graph_opts_apply(AVFilterGraphSegment *seg)
+{
+ for (size_t i = 0; i < seg->nb_chains; i++) {
+ AVFilterChain *ch = seg->chains[i];
+
+ for (size_t j = 0; j < ch->nb_filters; j++) {
+ AVFilterParams *p = ch->filters[j];
+ const AVDictionaryEntry *e = NULL;
+
+ av_assert0(p->filter);
+
+ while ((e = av_dict_iterate(p->opts, e))) {
+ int ret = filter_opt_apply(p->filter, e->key, e->value);
+ if (ret < 0)
+ return ret;
+ }
+
+ av_dict_free(&p->opts);
+ }
+ }
+
+ return 0;
+}
+
+static int graph_parse(AVFilterGraph *graph, const char *desc,
+ AVFilterInOut **inputs, AVFilterInOut **outputs)
+{
+ AVFilterGraphSegment *seg;
+ int ret;
+
+ ret = avfilter_graph_segment_parse(graph, desc, 0, &seg);
+ if (ret < 0)
+ return ret;
+
+ ret = avfilter_graph_segment_create_filters(seg, 0);
+ if (ret < 0)
+ goto fail;
+
+ ret = graph_opts_apply(seg);
+ if (ret < 0)
+ goto fail;
+
+ ret = avfilter_graph_segment_apply(seg, 0, inputs, outputs);
+
+fail:
+ avfilter_graph_segment_free(&seg);
+ return ret;
}
int init_complex_filtergraph(FilterGraph *fg)
@@ -308,8 +475,9 @@ int init_complex_filtergraph(FilterGraph *fg)
graph = avfilter_graph_alloc();
if (!graph)
return AVERROR(ENOMEM);
+ graph->nb_threads = 1;
- ret = avfilter_graph_parse2(graph, fg->graph_desc, &inputs, &outputs);
+ ret = graph_parse(graph, fg->graph_desc, &inputs, &outputs);
if (ret < 0)
goto fail;
@@ -317,17 +485,15 @@ int init_complex_filtergraph(FilterGraph *fg)
init_input_filter(fg, cur);
for (cur = outputs; cur;) {
- GROW_ARRAY(fg->outputs, fg->nb_outputs);
- fg->outputs[fg->nb_outputs - 1] = av_mallocz(sizeof(*fg->outputs[0]));
- if (!fg->outputs[fg->nb_outputs - 1])
- exit_program(1);
+ OutputFilter *const ofilter = ALLOC_ARRAY_ELEM(fg->outputs, fg->nb_outputs);
- fg->outputs[fg->nb_outputs - 1]->graph = fg;
- fg->outputs[fg->nb_outputs - 1]->out_tmp = cur;
- fg->outputs[fg->nb_outputs - 1]->type = avfilter_pad_get_type(cur->filter_ctx->output_pads,
+ ofilter->graph = fg;
+ ofilter->out_tmp = cur;
+ ofilter->type = avfilter_pad_get_type(cur->filter_ctx->output_pads,
cur->pad_idx);
+ ofilter->name = describe_filter_link(fg, cur, 0);
cur = cur->next;
- fg->outputs[fg->nb_outputs - 1]->out_tmp->next = NULL;
+ ofilter->out_tmp->next = NULL;
}
fail:
@@ -411,16 +577,16 @@ static int insert_filter(AVFilterContext **last_filter, int *pad_idx,
static int configure_output_video_filter(FilterGraph *fg, OutputFilter *ofilter, AVFilterInOut *out)
{
- char *pix_fmts;
OutputStream *ost = ofilter->ost;
OutputFile *of = output_files[ost->file_index];
- AVCodecContext *codec = ost->enc_ctx;
AVFilterContext *last_filter = out->filter_ctx;
+ AVBPrint bprint;
int pad_idx = out->pad_idx;
int ret;
+ const char *pix_fmts;
char name[255];
- snprintf(name, sizeof(name), "output stream %d:%d", ost->file_index, ost->index);
+ snprintf(name, sizeof(name), "out_%d_%d", ost->file_index, ost->index);
ret = avfilter_graph_create_filter(&ofilter->filter,
avfilter_get_by_name("buffersink"),
name, NULL, NULL, fg->graph);
@@ -428,21 +594,19 @@ static int configure_output_video_filter(FilterGraph *fg, OutputFilter *ofilter,
if (ret < 0)
return ret;
- if (codec->width || codec->height) {
+ if ((ofilter->width || ofilter->height) && ofilter->ost->autoscale) {
char args[255];
AVFilterContext *filter;
- AVDictionaryEntry *e = NULL;
+ const AVDictionaryEntry *e = NULL;
snprintf(args, sizeof(args), "%d:%d",
- codec->width,
- codec->height);
+ ofilter->width, ofilter->height);
- while ((e = av_dict_get(ost->sws_dict, "", e,
- AV_DICT_IGNORE_SUFFIX))) {
+ while ((e = av_dict_iterate(ost->sws_dict, e))) {
av_strlcatf(args, sizeof(args), ":%s=%s", e->key, e->value);
}
- snprintf(name, sizeof(name), "scaler for output stream %d:%d",
+ snprintf(name, sizeof(name), "scaler_out_%d_%d",
ost->file_index, ost->index);
if ((ret = avfilter_graph_create_filter(&filter, avfilter_get_by_name("scale"),
name, args, NULL, fg->graph)) < 0)
@@ -454,14 +618,14 @@ static int configure_output_video_filter(FilterGraph *fg, OutputFilter *ofilter,
pad_idx = 0;
}
- if ((pix_fmts = choose_pix_fmts(ost))) {
+ av_bprint_init(&bprint, 0, AV_BPRINT_SIZE_UNLIMITED);
+ if ((pix_fmts = choose_pix_fmts(ofilter, &bprint))) {
AVFilterContext *filter;
- snprintf(name, sizeof(name), "pixel format for output stream %d:%d",
- ost->file_index, ost->index);
+
ret = avfilter_graph_create_filter(&filter,
avfilter_get_by_name("format"),
"format", pix_fmts, NULL, fg->graph);
- av_freep(&pix_fmts);
+ av_bprint_finalize(&bprint, NULL);
if (ret < 0)
return ret;
if ((ret = avfilter_link(last_filter, pad_idx, filter, 0)) < 0)
@@ -477,7 +641,7 @@ static int configure_output_video_filter(FilterGraph *fg, OutputFilter *ofilter,
snprintf(args, sizeof(args), "fps=%d/%d", ost->frame_rate.num,
ost->frame_rate.den);
- snprintf(name, sizeof(name), "fps for output stream %d:%d",
+ snprintf(name, sizeof(name), "fps_out_%d_%d",
ost->file_index, ost->index);
ret = avfilter_graph_create_filter(&fps, avfilter_get_by_name("fps"),
name, args, NULL, fg->graph);
@@ -491,7 +655,7 @@ static int configure_output_video_filter(FilterGraph *fg, OutputFilter *ofilter,
pad_idx = 0;
}
- snprintf(name, sizeof(name), "trim for output stream %d:%d",
+ snprintf(name, sizeof(name), "trim_out_%d_%d",
ost->file_index, ost->index);
ret = insert_trim(of->start_time, of->recording_time,
&last_filter, &pad_idx, name);
@@ -512,11 +676,11 @@ static int configure_output_audio_filter(FilterGraph *fg, OutputFilter *ofilter,
AVCodecContext *codec = ost->enc_ctx;
AVFilterContext *last_filter = out->filter_ctx;
int pad_idx = out->pad_idx;
- char *sample_fmts, *sample_rates, *channel_layouts;
+ AVBPrint args;
char name[255];
int ret;
- snprintf(name, sizeof(name), "output stream %d:%d", ost->file_index, ost->index);
+ snprintf(name, sizeof(name), "out_%d_%d", ost->file_index, ost->index);
ret = avfilter_graph_create_filter(&ofilter->filter,
avfilter_get_by_name("abuffersink"),
name, NULL, NULL, fg->graph);
@@ -535,88 +699,69 @@ static int configure_output_audio_filter(FilterGraph *fg, OutputFilter *ofilter,
avfilter_get_by_name(filter_name), \
filter_name, arg, NULL, fg->graph); \
if (ret < 0) \
- return ret; \
+ goto fail; \
\
ret = avfilter_link(last_filter, pad_idx, filt_ctx, 0); \
if (ret < 0) \
- return ret; \
+ goto fail; \
\
last_filter = filt_ctx; \
pad_idx = 0; \
} while (0)
+ av_bprint_init(&args, 0, AV_BPRINT_SIZE_UNLIMITED);
+#if FFMPEG_OPT_MAP_CHANNEL
if (ost->audio_channels_mapped) {
+ AVChannelLayout mapped_layout = { 0 };
int i;
- AVBPrint pan_buf;
- av_bprint_init(&pan_buf, 256, 8192);
- av_bprintf(&pan_buf, "0x%"PRIx64,
- av_get_default_channel_layout(ost->audio_channels_mapped));
+ av_channel_layout_default(&mapped_layout, ost->audio_channels_mapped);
+ av_channel_layout_describe_bprint(&mapped_layout, &args);
for (i = 0; i < ost->audio_channels_mapped; i++)
if (ost->audio_channels_map[i] != -1)
- av_bprintf(&pan_buf, "|c%d=c%d", i, ost->audio_channels_map[i]);
+ av_bprintf(&args, "|c%d=c%d", i, ost->audio_channels_map[i]);
- AUTO_INSERT_FILTER("-map_channel", "pan", pan_buf.str);
- av_bprint_finalize(&pan_buf, NULL);
+ AUTO_INSERT_FILTER("-map_channel", "pan", args.str);
+ av_bprint_clear(&args);
}
+#endif
- if (codec->channels && !codec->channel_layout)
- codec->channel_layout = av_get_default_channel_layout(codec->channels);
+ if (codec->ch_layout.order == AV_CHANNEL_ORDER_UNSPEC)
+ av_channel_layout_default(&codec->ch_layout, codec->ch_layout.nb_channels);
- sample_fmts = choose_sample_fmts(ost);
- sample_rates = choose_sample_rates(ost);
- channel_layouts = choose_channel_layouts(ost);
- if (sample_fmts || sample_rates || channel_layouts) {
+ choose_sample_fmts(ofilter, &args);
+ choose_sample_rates(ofilter, &args);
+ choose_channel_layouts(ofilter, &args);
+ if (!av_bprint_is_complete(&args)) {
+ ret = AVERROR(ENOMEM);
+ goto fail;
+ }
+ if (args.len) {
AVFilterContext *format;
- char args[256];
- args[0] = 0;
-
- if (sample_fmts)
- av_strlcatf(args, sizeof(args), "sample_fmts=%s:",
- sample_fmts);
- if (sample_rates)
- av_strlcatf(args, sizeof(args), "sample_rates=%s:",
- sample_rates);
- if (channel_layouts)
- av_strlcatf(args, sizeof(args), "channel_layouts=%s:",
- channel_layouts);
-
- av_freep(&sample_fmts);
- av_freep(&sample_rates);
- av_freep(&channel_layouts);
-
- snprintf(name, sizeof(name), "audio format for output stream %d:%d",
+
+ snprintf(name, sizeof(name), "format_out_%d_%d",
ost->file_index, ost->index);
ret = avfilter_graph_create_filter(&format,
avfilter_get_by_name("aformat"),
- name, args, NULL, fg->graph);
+ name, args.str, NULL, fg->graph);
if (ret < 0)
- return ret;
+ goto fail;
ret = avfilter_link(last_filter, pad_idx, format, 0);
if (ret < 0)
- return ret;
+ goto fail;
last_filter = format;
pad_idx = 0;
}
- if (audio_volume != 256 && 0) {
- char args[256];
-
- snprintf(args, sizeof(args), "%f", audio_volume / 256.);
- AUTO_INSERT_FILTER("-vol", "volume", args);
- }
-
if (ost->apad && of->shortest) {
- char args[256];
int i;
- for (i=0; ictx->nb_streams; i++)
- if (of->ctx->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO)
+ for (i = 0; i < of->nb_streams; i++)
+ if (of->streams[i]->st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO)
break;
- if (ictx->nb_streams) {
- snprintf(args, sizeof(args), "%s", ost->apad);
- AUTO_INSERT_FILTER("-apad", "apad", args);
+ if (i < of->nb_streams) {
+ AUTO_INSERT_FILTER("-apad", "apad", ost->apad);
}
}
@@ -625,63 +770,61 @@ static int configure_output_audio_filter(FilterGraph *fg, OutputFilter *ofilter,
ret = insert_trim(of->start_time, of->recording_time,
&last_filter, &pad_idx, name);
if (ret < 0)
- return ret;
+ goto fail;
if ((ret = avfilter_link(last_filter, pad_idx, ofilter->filter, 0)) < 0)
- return ret;
-
- return 0;
-}
+ goto fail;
+fail:
+ av_bprint_finalize(&args, NULL);
-#define DESCRIBE_FILTER_LINK(f, inout, in) \
-{ \
- AVFilterContext *ctx = inout->filter_ctx; \
- AVFilterPad *pads = in ? ctx->input_pads : ctx->output_pads; \
- int nb_pads = in ? ctx->nb_inputs : ctx->nb_outputs; \
- AVIOContext *pb; \
- \
- if (avio_open_dyn_buf(&pb) < 0) \
- exit_program(1); \
- \
- avio_printf(pb, "%s", ctx->filter->name); \
- if (nb_pads > 1) \
- avio_printf(pb, ":%s", avfilter_pad_get_name(pads, inout->pad_idx));\
- avio_w8(pb, 0); \
- avio_close_dyn_buf(pb, &f->name); \
+ return ret;
}
-int configure_output_filter(FilterGraph *fg, OutputFilter *ofilter, AVFilterInOut *out)
+static int configure_output_filter(FilterGraph *fg, OutputFilter *ofilter,
+ AVFilterInOut *out)
{
- av_freep(&ofilter->name);
- DESCRIBE_FILTER_LINK(ofilter, out, 0);
-
if (!ofilter->ost) {
- av_log(NULL, AV_LOG_FATAL, "Filter %s has a unconnected output\n", ofilter->name);
+ av_log(NULL, AV_LOG_FATAL, "Filter %s has an unconnected output\n", ofilter->name);
exit_program(1);
}
switch (avfilter_pad_get_type(out->filter_ctx->output_pads, out->pad_idx)) {
case AVMEDIA_TYPE_VIDEO: return configure_output_video_filter(fg, ofilter, out);
case AVMEDIA_TYPE_AUDIO: return configure_output_audio_filter(fg, ofilter, out);
- default: av_assert0(0);
+ default: av_assert0(0); return 0;
}
}
-static int sub2video_prepare(InputStream *ist)
+void check_filter_outputs(void)
+{
+ int i;
+ for (i = 0; i < nb_filtergraphs; i++) {
+ int n;
+ for (n = 0; n < filtergraphs[i]->nb_outputs; n++) {
+ OutputFilter *output = filtergraphs[i]->outputs[n];
+ if (!output->ost) {
+ av_log(NULL, AV_LOG_FATAL, "Filter %s has an unconnected output\n", output->name);
+ exit_program(1);
+ }
+ }
+ }
+}
+
+static int sub2video_prepare(InputStream *ist, InputFilter *ifilter)
{
AVFormatContext *avf = input_files[ist->file_index]->ctx;
int i, w, h;
/* Compute the size of the canvas for the subtitles stream.
- If the subtitles codec has set a size, use it. Otherwise use the
+ If the subtitles codecpar has set a size, use it. Otherwise use the
maximum dimensions of the video streams in the same file. */
- w = ist->dec_ctx->width;
- h = ist->dec_ctx->height;
+ w = ifilter->width;
+ h = ifilter->height;
if (!(w && h)) {
for (i = 0; i < avf->nb_streams; i++) {
- if (avf->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO) {
- w = FFMAX(w, avf->streams[i]->codec->width);
- h = FFMAX(h, avf->streams[i]->codec->height);
+ if (avf->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {
+ w = FFMAX(w, avf->streams[i]->codecpar->width);
+ h = FFMAX(h, avf->streams[i]->codecpar->height);
}
}
if (!(w && h)) {
@@ -690,17 +833,27 @@ static int sub2video_prepare(InputStream *ist)
}
av_log(avf, AV_LOG_INFO, "sub2video: using %dx%d canvas\n", w, h);
}
- ist->sub2video.w = ist->resample_width = w;
- ist->sub2video.h = ist->resample_height = h;
+ ist->sub2video.w = ifilter->width = w;
+ ist->sub2video.h = ifilter->height = h;
+
+ ifilter->width = ist->dec_ctx->width ? ist->dec_ctx->width : ist->sub2video.w;
+ ifilter->height = ist->dec_ctx->height ? ist->dec_ctx->height : ist->sub2video.h;
/* rectangles are AV_PIX_FMT_PAL8, but we have no guarantee that the
palettes for all rectangles are identical or compatible */
- ist->resample_pix_fmt = ist->dec_ctx->pix_fmt = AV_PIX_FMT_RGB32;
+ ifilter->format = AV_PIX_FMT_RGB32;
ist->sub2video.frame = av_frame_alloc();
if (!ist->sub2video.frame)
return AVERROR(ENOMEM);
ist->sub2video.last_pts = INT64_MIN;
+ ist->sub2video.end_pts = INT64_MIN;
+
+ /* sub2video structure has been (re-)initialized.
+ Mark it as such so that the system will be
+ initialized with the first received heartbeat. */
+ ist->sub2video.initialize = 1;
+
return 0;
}
@@ -709,6 +862,7 @@ static int configure_input_video_filter(FilterGraph *fg, InputFilter *ifilter,
{
AVFilterContext *last_filter;
const AVFilter *buffer_filt = avfilter_get_by_name("buffer");
+ const AVPixFmtDescriptor *desc;
InputStream *ist = ifilter->ist;
InputFile *f = input_files[ist->file_index];
AVRational tb = ist->framerate.num ? av_inv_q(ist->framerate) :
@@ -719,100 +873,94 @@ static int configure_input_video_filter(FilterGraph *fg, InputFilter *ifilter,
char name[255];
int ret, pad_idx = 0;
int64_t tsoffset = 0;
+ AVBufferSrcParameters *par = av_buffersrc_parameters_alloc();
+
+ if (!par)
+ return AVERROR(ENOMEM);
+ memset(par, 0, sizeof(*par));
+ par->format = AV_PIX_FMT_NONE;
if (ist->dec_ctx->codec_type == AVMEDIA_TYPE_AUDIO) {
av_log(NULL, AV_LOG_ERROR, "Cannot connect video filter to audio input\n");
- return AVERROR(EINVAL);
+ ret = AVERROR(EINVAL);
+ goto fail;
}
if (!fr.num)
- fr = av_guess_frame_rate(input_files[ist->file_index]->ctx, ist->st, NULL);
+ fr = ist->framerate_guessed;
if (ist->dec_ctx->codec_type == AVMEDIA_TYPE_SUBTITLE) {
- ret = sub2video_prepare(ist);
+ ret = sub2video_prepare(ist, ifilter);
if (ret < 0)
- return ret;
+ goto fail;
}
- sar = ist->st->sample_aspect_ratio.num ?
- ist->st->sample_aspect_ratio :
- ist->dec_ctx->sample_aspect_ratio;
+ sar = ifilter->sample_aspect_ratio;
if(!sar.den)
sar = (AVRational){0,1};
- av_bprint_init(&args, 0, 1);
+ av_bprint_init(&args, 0, AV_BPRINT_SIZE_AUTOMATIC);
av_bprintf(&args,
"video_size=%dx%d:pix_fmt=%d:time_base=%d/%d:"
- "pixel_aspect=%d/%d:sws_param=flags=%d", ist->resample_width,
- ist->resample_height,
- ist->hwaccel_retrieve_data ? ist->hwaccel_retrieved_pix_fmt : ist->resample_pix_fmt,
- tb.num, tb.den, sar.num, sar.den,
- SWS_BILINEAR + ((ist->dec_ctx->flags&AV_CODEC_FLAG_BITEXACT) ? SWS_BITEXACT:0));
+ "pixel_aspect=%d/%d",
+ ifilter->width, ifilter->height, ifilter->format,
+ tb.num, tb.den, sar.num, sar.den);
if (fr.num && fr.den)
av_bprintf(&args, ":frame_rate=%d/%d", fr.num, fr.den);
snprintf(name, sizeof(name), "graph %d input from stream %d:%d", fg->index,
ist->file_index, ist->st->index);
+
if ((ret = avfilter_graph_create_filter(&ifilter->filter, buffer_filt, name,
args.str, NULL, fg->graph)) < 0)
- return ret;
+ goto fail;
+ par->hw_frames_ctx = ifilter->hw_frames_ctx;
+ ret = av_buffersrc_parameters_set(ifilter->filter, par);
+ if (ret < 0)
+ goto fail;
+ av_freep(&par);
last_filter = ifilter->filter;
- if (ist->autorotate) {
- double theta = get_rotation(ist->st);
+ desc = av_pix_fmt_desc_get(ifilter->format);
+ av_assert0(desc);
+
+ // TODO: insert hwaccel enabled filters like transpose_vaapi into the graph
+ if (ist->autorotate && !(desc->flags & AV_PIX_FMT_FLAG_HWACCEL)) {
+ int32_t *displaymatrix = ifilter->displaymatrix;
+ double theta;
+
+ if (!displaymatrix)
+ displaymatrix = (int32_t *)av_stream_get_side_data(ist->st, AV_PKT_DATA_DISPLAYMATRIX, NULL);
+ theta = get_rotation(displaymatrix);
if (fabs(theta - 90) < 1.0) {
- ret = insert_filter(&last_filter, &pad_idx, "transpose", "clock");
+ ret = insert_filter(&last_filter, &pad_idx, "transpose",
+ displaymatrix[3] > 0 ? "cclock_flip" : "clock");
} else if (fabs(theta - 180) < 1.0) {
- ret = insert_filter(&last_filter, &pad_idx, "hflip", NULL);
- if (ret < 0)
- return ret;
- ret = insert_filter(&last_filter, &pad_idx, "vflip", NULL);
+ if (displaymatrix[0] < 0) {
+ ret = insert_filter(&last_filter, &pad_idx, "hflip", NULL);
+ if (ret < 0)
+ return ret;
+ }
+ if (displaymatrix[4] < 0) {
+ ret = insert_filter(&last_filter, &pad_idx, "vflip", NULL);
+ }
} else if (fabs(theta - 270) < 1.0) {
- ret = insert_filter(&last_filter, &pad_idx, "transpose", "cclock");
+ ret = insert_filter(&last_filter, &pad_idx, "transpose",
+ displaymatrix[3] < 0 ? "clock_flip" : "cclock");
} else if (fabs(theta) > 1.0) {
char rotate_buf[64];
snprintf(rotate_buf, sizeof(rotate_buf), "%f*PI/180", theta);
ret = insert_filter(&last_filter, &pad_idx, "rotate", rotate_buf);
+ } else if (fabs(theta) < 1.0) {
+ if (displaymatrix && displaymatrix[4] < 0) {
+ ret = insert_filter(&last_filter, &pad_idx, "vflip", NULL);
+ }
}
if (ret < 0)
return ret;
}
- if (ist->framerate.num) {
- AVFilterContext *setpts;
-
- snprintf(name, sizeof(name), "force CFR for input from stream %d:%d",
- ist->file_index, ist->st->index);
- if ((ret = avfilter_graph_create_filter(&setpts,
- avfilter_get_by_name("setpts"),
- name, "N", NULL,
- fg->graph)) < 0)
- return ret;
-
- if ((ret = avfilter_link(last_filter, 0, setpts, 0)) < 0)
- return ret;
-
- last_filter = setpts;
- }
-
- if (do_deinterlace) {
- AVFilterContext *yadif;
-
- snprintf(name, sizeof(name), "deinterlace input from stream %d:%d",
- ist->file_index, ist->st->index);
- if ((ret = avfilter_graph_create_filter(&yadif,
- avfilter_get_by_name("yadif"),
- name, "", NULL,
- fg->graph)) < 0)
- return ret;
-
- if ((ret = avfilter_link(last_filter, 0, yadif, 0)) < 0)
- return ret;
-
- last_filter = yadif;
- }
-
- snprintf(name, sizeof(name), "trim for input stream %d:%d",
+ snprintf(name, sizeof(name), "trim_in_%d_%d",
ist->file_index, ist->st->index);
if (copy_ts) {
tsoffset = f->start_time == AV_NOPTS_VALUE ? 0 : f->start_time;
@@ -828,6 +976,10 @@ static int configure_input_video_filter(FilterGraph *fg, InputFilter *ifilter,
if ((ret = avfilter_link(last_filter, 0, in->filter_ctx, in->pad_idx)) < 0)
return ret;
return 0;
+fail:
+ av_freep(&par);
+
+ return ret;
}
static int configure_input_audio_filter(FilterGraph *fg, InputFilter *ifilter,
@@ -849,15 +1001,16 @@ static int configure_input_audio_filter(FilterGraph *fg, InputFilter *ifilter,
av_bprint_init(&args, 0, AV_BPRINT_SIZE_AUTOMATIC);
av_bprintf(&args, "time_base=%d/%d:sample_rate=%d:sample_fmt=%s",
- 1, ist->dec_ctx->sample_rate,
- ist->dec_ctx->sample_rate,
- av_get_sample_fmt_name(ist->dec_ctx->sample_fmt));
- if (ist->dec_ctx->channel_layout)
- av_bprintf(&args, ":channel_layout=0x%"PRIx64,
- ist->dec_ctx->channel_layout);
- else
- av_bprintf(&args, ":channels=%d", ist->dec_ctx->channels);
- snprintf(name, sizeof(name), "graph %d input from stream %d:%d", fg->index,
+ 1, ifilter->sample_rate,
+ ifilter->sample_rate,
+ av_get_sample_fmt_name(ifilter->format));
+ if (av_channel_layout_check(&ifilter->ch_layout) &&
+ ifilter->ch_layout.order != AV_CHANNEL_ORDER_UNSPEC) {
+ av_bprintf(&args, ":channel_layout=");
+ av_channel_layout_describe_bprint(&ifilter->ch_layout, &args);
+ } else
+ av_bprintf(&args, ":channels=%d", ifilter->ch_layout.nb_channels);
+ snprintf(name, sizeof(name), "graph_%d_in_%d_%d", fg->index,
ist->file_index, ist->st->index);
if ((ret = avfilter_graph_create_filter(&ifilter->filter, abuffer_filt,
@@ -872,7 +1025,7 @@ static int configure_input_audio_filter(FilterGraph *fg, InputFilter *ifilter,
av_log(NULL, AV_LOG_INFO, opt_name " is forwarded to lavfi " \
"similarly to -af " filter_name "=%s.\n", arg); \
\
- snprintf(name, sizeof(name), "graph %d %s for input stream %d:%d", \
+ snprintf(name, sizeof(name), "graph_%d_%s_in_%d_%d", \
fg->index, filter_name, ist->file_index, ist->st->index); \
ret = avfilter_graph_create_filter(&filt_ctx, \
avfilter_get_by_name(filter_name), \
@@ -887,40 +1040,6 @@ static int configure_input_audio_filter(FilterGraph *fg, InputFilter *ifilter,
last_filter = filt_ctx; \
} while (0)
- if (audio_sync_method > 0) {
- char args[256] = {0};
-
- av_strlcatf(args, sizeof(args), "async=%d", audio_sync_method);
- if (audio_drift_threshold != 0.1)
- av_strlcatf(args, sizeof(args), ":min_hard_comp=%f", audio_drift_threshold);
- if (!fg->reconfiguration)
- av_strlcatf(args, sizeof(args), ":first_pts=0");
- AUTO_INSERT_FILTER_INPUT("-async", "aresample", args);
- }
-
-// if (ost->audio_channels_mapped) {
-// int i;
-// AVBPrint pan_buf;
-// av_bprint_init(&pan_buf, 256, 8192);
-// av_bprintf(&pan_buf, "0x%"PRIx64,
-// av_get_default_channel_layout(ost->audio_channels_mapped));
-// for (i = 0; i < ost->audio_channels_mapped; i++)
-// if (ost->audio_channels_map[i] != -1)
-// av_bprintf(&pan_buf, ":c%d=c%d", i, ost->audio_channels_map[i]);
-// AUTO_INSERT_FILTER_INPUT("-map_channel", "pan", pan_buf.str);
-// av_bprint_finalize(&pan_buf, NULL);
-// }
-
- if (audio_volume != 256) {
- char args[256];
-
- av_log(NULL, AV_LOG_WARNING, "-vol has been deprecated. Use the volume "
- "audio filter instead.\n");
-
- snprintf(args, sizeof(args), "%f", audio_volume / 256.);
- AUTO_INSERT_FILTER_INPUT("-vol", "volume", args);
- }
-
snprintf(name, sizeof(name), "trim for input stream %d:%d",
ist->file_index, ist->st->index);
if (copy_ts) {
@@ -943,9 +1062,6 @@ static int configure_input_audio_filter(FilterGraph *fg, InputFilter *ifilter,
static int configure_input_filter(FilterGraph *fg, InputFilter *ifilter,
AVFilterInOut *in)
{
- av_freep(&ifilter->name);
- DESCRIBE_FILTER_LINK(ifilter, in, 1);
-
if (!ifilter->ist->dec) {
av_log(NULL, AV_LOG_ERROR,
"No decoder for stream #%d:%d, filtering impossible\n",
@@ -955,60 +1071,95 @@ static int configure_input_filter(FilterGraph *fg, InputFilter *ifilter,
switch (avfilter_pad_get_type(in->filter_ctx->input_pads, in->pad_idx)) {
case AVMEDIA_TYPE_VIDEO: return configure_input_video_filter(fg, ifilter, in);
case AVMEDIA_TYPE_AUDIO: return configure_input_audio_filter(fg, ifilter, in);
- default: av_assert0(0);
+ default: av_assert0(0); return 0;
}
}
+static void cleanup_filtergraph(FilterGraph *fg)
+{
+ int i;
+ for (i = 0; i < fg->nb_outputs; i++)
+ fg->outputs[i]->filter = (AVFilterContext *)NULL;
+ for (i = 0; i < fg->nb_inputs; i++)
+ fg->inputs[i]->filter = (AVFilterContext *)NULL;
+ avfilter_graph_free(&fg->graph);
+}
+
+static int filter_is_buffersrc(const AVFilterContext *f)
+{
+ return f->nb_inputs == 0 &&
+ (!strcmp(f->filter->name, "buffer") ||
+ !strcmp(f->filter->name, "abuffer"));
+}
+
+static int graph_is_meta(AVFilterGraph *graph)
+{
+ for (unsigned i = 0; i < graph->nb_filters; i++) {
+ const AVFilterContext *f = graph->filters[i];
+
+ /* in addition to filters flagged as meta, also
+ * disregard sinks and buffersources (but not other sources,
+ * since they introduce data we are not aware of)
+ */
+ if (!((f->filter->flags & AVFILTER_FLAG_METADATA_ONLY) ||
+ f->nb_outputs == 0 ||
+ filter_is_buffersrc(f)))
+ return 0;
+ }
+ return 1;
+}
+
int configure_filtergraph(FilterGraph *fg)
{
AVFilterInOut *inputs, *outputs, *cur;
- int ret, i, simple = !fg->graph_desc;
+ int ret, i, simple = filtergraph_is_simple(fg);
const char *graph_desc = simple ? fg->outputs[0]->ost->avfilter :
fg->graph_desc;
- avfilter_graph_free(&fg->graph);
+ cleanup_filtergraph(fg);
if (!(fg->graph = avfilter_graph_alloc()))
return AVERROR(ENOMEM);
if (simple) {
OutputStream *ost = fg->outputs[0]->ost;
- char args[512];
- AVDictionaryEntry *e = NULL;
- args[0] = 0;
- while ((e = av_dict_get(ost->sws_dict, "", e,
- AV_DICT_IGNORE_SUFFIX))) {
- av_strlcatf(args, sizeof(args), "%s=%s:", e->key, e->value);
- }
- if (strlen(args))
- args[strlen(args)-1] = 0;
- fg->graph->scale_sws_opts = av_strdup(args);
-
- args[0] = 0;
- while ((e = av_dict_get(ost->swr_opts, "", e,
- AV_DICT_IGNORE_SUFFIX))) {
- av_strlcatf(args, sizeof(args), "%s=%s:", e->key, e->value);
+ if (filter_nbthreads) {
+ ret = av_opt_set(fg->graph, "threads", filter_nbthreads, 0);
+ if (ret < 0)
+ goto fail;
+ } else {
+ const AVDictionaryEntry *e = NULL;
+ e = av_dict_get(ost->encoder_opts, "threads", NULL, 0);
+ if (e)
+ av_opt_set(fg->graph, "threads", e->value, 0);
}
- if (strlen(args))
- args[strlen(args)-1] = 0;
- av_opt_set(fg->graph, "aresample_swr_opts", args, 0);
-
- args[0] = '\0';
- while ((e = av_dict_get(fg->outputs[0]->ost->resample_opts, "", e,
- AV_DICT_IGNORE_SUFFIX))) {
- av_strlcatf(args, sizeof(args), "%s=%s:", e->key, e->value);
+
+ if (av_dict_count(ost->sws_dict)) {
+ ret = av_dict_get_string(ost->sws_dict,
+ &fg->graph->scale_sws_opts,
+ '=', ':');
+ if (ret < 0)
+ goto fail;
}
- if (strlen(args))
- args[strlen(args) - 1] = '\0';
- fg->graph->resample_lavr_opts = av_strdup(args);
- e = av_dict_get(ost->encoder_opts, "threads", NULL, 0);
- if (e)
- av_opt_set(fg->graph, "threads", e->value, 0);
+ if (av_dict_count(ost->swr_opts)) {
+ char *args;
+ ret = av_dict_get_string(ost->swr_opts, &args, '=', ':');
+ if (ret < 0)
+ goto fail;
+ av_opt_set(fg->graph, "aresample_swr_opts", args, 0);
+ av_free(args);
+ }
+ } else {
+ fg->graph->nb_threads = filter_complex_nbthreads;
}
- if ((ret = avfilter_graph_parse2(fg->graph, graph_desc, &inputs, &outputs)) < 0)
- return ret;
+ if ((ret = graph_parse(fg->graph, graph_desc, &inputs, &outputs)) < 0)
+ goto fail;
+
+ ret = hw_device_setup_for_filter(fg);
+ if (ret < 0)
+ goto fail;
if (simple && (!inputs || inputs->next || !outputs || outputs->next)) {
const char *num_inputs;
@@ -1032,14 +1183,15 @@ int configure_filtergraph(FilterGraph *fg)
" However, it had %s input(s) and %s output(s)."
" Please adjust, or use a complex filtergraph (-filter_complex) instead.\n",
graph_desc, num_inputs, num_outputs);
- return AVERROR(EINVAL);
+ ret = AVERROR(EINVAL);
+ goto fail;
}
for (cur = inputs, i = 0; cur; cur = cur->next, i++)
if ((ret = configure_input_filter(fg, fg->inputs[i], cur)) < 0) {
avfilter_inout_free(&inputs);
avfilter_inout_free(&outputs);
- return ret;
+ goto fail;
}
avfilter_inout_free(&inputs);
@@ -1047,35 +1199,112 @@ int configure_filtergraph(FilterGraph *fg)
configure_output_filter(fg, fg->outputs[i], cur);
avfilter_inout_free(&outputs);
+ if (!auto_conversion_filters)
+ avfilter_graph_set_auto_convert(fg->graph, AVFILTER_AUTO_CONVERT_NONE);
if ((ret = avfilter_graph_config(fg->graph, NULL)) < 0)
- return ret;
+ goto fail;
+
+ fg->is_meta = graph_is_meta(fg->graph);
+
+ /* limit the lists of allowed formats to the ones selected, to
+ * make sure they stay the same if the filtergraph is reconfigured later */
+ for (i = 0; i < fg->nb_outputs; i++) {
+ OutputFilter *ofilter = fg->outputs[i];
+ AVFilterContext *sink = ofilter->filter;
+
+ ofilter->format = av_buffersink_get_format(sink);
+
+ ofilter->width = av_buffersink_get_w(sink);
+ ofilter->height = av_buffersink_get_h(sink);
+
+ ofilter->sample_rate = av_buffersink_get_sample_rate(sink);
+ av_channel_layout_uninit(&ofilter->ch_layout);
+ ret = av_buffersink_get_ch_layout(sink, &ofilter->ch_layout);
+ if (ret < 0)
+ goto fail;
+ }
fg->reconfiguration = 1;
for (i = 0; i < fg->nb_outputs; i++) {
OutputStream *ost = fg->outputs[i]->ost;
- if (!ost->enc) {
- /* identical to the same check in ffmpeg.c, needed because
- complex filter graphs are initialized earlier */
- av_log(NULL, AV_LOG_ERROR, "Encoder (codec %s) not found for output stream #%d:%d\n",
- avcodec_get_name(ost->st->codec->codec_id), ost->file_index, ost->index);
- return AVERROR(EINVAL);
- }
- if (ost->enc->type == AVMEDIA_TYPE_AUDIO &&
- !(ost->enc->capabilities & AV_CODEC_CAP_VARIABLE_FRAME_SIZE))
+ if (ost->enc_ctx->codec_type == AVMEDIA_TYPE_AUDIO &&
+ !(ost->enc_ctx->codec->capabilities & AV_CODEC_CAP_VARIABLE_FRAME_SIZE))
av_buffersink_set_frame_size(ost->filter->filter,
ost->enc_ctx->frame_size);
}
+ for (i = 0; i < fg->nb_inputs; i++) {
+ AVFrame *tmp;
+ while (av_fifo_read(fg->inputs[i]->frame_queue, &tmp, 1) >= 0) {
+ ret = av_buffersrc_add_frame(fg->inputs[i]->filter, tmp);
+ av_frame_free(&tmp);
+ if (ret < 0)
+ goto fail;
+ }
+ }
+
+ /* send the EOFs for the finished inputs */
+ for (i = 0; i < fg->nb_inputs; i++) {
+ if (fg->inputs[i]->eof) {
+ ret = av_buffersrc_add_frame(fg->inputs[i]->filter, NULL);
+ if (ret < 0)
+ goto fail;
+ }
+ }
+
+ /* process queued up subtitle packets */
+ for (i = 0; i < fg->nb_inputs; i++) {
+ InputStream *ist = fg->inputs[i]->ist;
+ if (ist->sub2video.sub_queue && ist->sub2video.frame) {
+ AVSubtitle tmp;
+ while (av_fifo_read(ist->sub2video.sub_queue, &tmp, 1) >= 0) {
+ sub2video_update(ist, INT64_MIN, &tmp);
+ avsubtitle_free(&tmp);
+ }
+ }
+ }
+
return 0;
+
+fail:
+ cleanup_filtergraph(fg);
+ return ret;
}
-int ist_in_filtergraph(FilterGraph *fg, InputStream *ist)
+int ifilter_parameters_from_frame(InputFilter *ifilter, const AVFrame *frame)
{
- int i;
- for (i = 0; i < fg->nb_inputs; i++)
- if (fg->inputs[i]->ist == ist)
- return 1;
+ AVFrameSideData *sd;
+ int ret;
+
+ av_buffer_unref(&ifilter->hw_frames_ctx);
+
+ ifilter->format = frame->format;
+
+ ifilter->width = frame->width;
+ ifilter->height = frame->height;
+ ifilter->sample_aspect_ratio = frame->sample_aspect_ratio;
+
+ ifilter->sample_rate = frame->sample_rate;
+ ret = av_channel_layout_copy(&ifilter->ch_layout, &frame->ch_layout);
+ if (ret < 0)
+ return ret;
+
+ av_freep(&ifilter->displaymatrix);
+ sd = av_frame_get_side_data(frame, AV_FRAME_DATA_DISPLAYMATRIX);
+ if (sd)
+ ifilter->displaymatrix = av_memdup(sd->data, sizeof(int32_t) * 9);
+
+ if (frame->hw_frames_ctx) {
+ ifilter->hw_frames_ctx = av_buffer_ref(frame->hw_frames_ctx);
+ if (!ifilter->hw_frames_ctx)
+ return AVERROR(ENOMEM);
+ }
+
return 0;
}
+int filtergraph_is_simple(FilterGraph *fg)
+{
+ return !fg->graph_desc;
+}
diff --git a/app/src/main/cpp/ffmpeg/ffmpeg_hw.c b/app/src/main/cpp/ffmpeg/ffmpeg_hw.c
new file mode 100644
index 00000000..88fa7824
--- /dev/null
+++ b/app/src/main/cpp/ffmpeg/ffmpeg_hw.c
@@ -0,0 +1,583 @@
+/*
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include
+
+#include "libavutil/avstring.h"
+#include "libavutil/pixdesc.h"
+#include "libavfilter/buffersink.h"
+
+#include "ffmpeg.h"
+
+static int nb_hw_devices;
+static HWDevice **hw_devices;
+
+static HWDevice *hw_device_get_by_type(enum AVHWDeviceType type)
+{
+ HWDevice *found = NULL;
+ int i;
+ for (i = 0; i < nb_hw_devices; i++) {
+ if (hw_devices[i]->type == type) {
+ if (found)
+ return NULL;
+ found = hw_devices[i];
+ }
+ }
+ return found;
+}
+
+HWDevice *hw_device_get_by_name(const char *name)
+{
+ int i;
+ for (i = 0; i < nb_hw_devices; i++) {
+ if (!strcmp(hw_devices[i]->name, name))
+ return hw_devices[i];
+ }
+ return NULL;
+}
+
+static HWDevice *hw_device_add(void)
+{
+ int err;
+ err = av_reallocp_array(&hw_devices, nb_hw_devices + 1,
+ sizeof(*hw_devices));
+ if (err) {
+ nb_hw_devices = 0;
+ return NULL;
+ }
+ hw_devices[nb_hw_devices] = av_mallocz(sizeof(HWDevice));
+ if (!hw_devices[nb_hw_devices])
+ return NULL;
+ return hw_devices[nb_hw_devices++];
+}
+
+static char *hw_device_default_name(enum AVHWDeviceType type)
+{
+ // Make an automatic name of the form "type%d". We arbitrarily
+ // limit at 1000 anonymous devices of the same type - there is
+ // probably something else very wrong if you get to this limit.
+ const char *type_name = av_hwdevice_get_type_name(type);
+ char *name;
+ size_t index_pos;
+ int index, index_limit = 1000;
+ index_pos = strlen(type_name);
+ name = av_malloc(index_pos + 4);
+ if (!name)
+ return NULL;
+ for (index = 0; index < index_limit; index++) {
+ snprintf(name, index_pos + 4, "%s%d", type_name, index);
+ if (!hw_device_get_by_name(name))
+ break;
+ }
+ if (index >= index_limit) {
+ av_freep(&name);
+ return NULL;
+ }
+ return name;
+}
+
+int hw_device_init_from_string(const char *arg, HWDevice **dev_out)
+{
+ // "type=name"
+ // "type=name,key=value,key2=value2"
+ // "type=name:device,key=value,key2=value2"
+ // "type:device,key=value,key2=value2"
+ // -> av_hwdevice_ctx_create()
+ // "type=name@name"
+ // "type@name"
+ // -> av_hwdevice_ctx_create_derived()
+
+ AVDictionary *options = NULL;
+ const char *type_name = NULL, *name = NULL, *device = NULL;
+ enum AVHWDeviceType type;
+ HWDevice *dev, *src;
+ AVBufferRef *device_ref = NULL;
+ int err;
+ const char *errmsg, *p, *q;
+ size_t k;
+
+ k = strcspn(arg, ":=@");
+ p = arg + k;
+
+ type_name = av_strndup(arg, k);
+ if (!type_name) {
+ err = AVERROR(ENOMEM);
+ goto fail;
+ }
+ type = av_hwdevice_find_type_by_name(type_name);
+ if (type == AV_HWDEVICE_TYPE_NONE) {
+ errmsg = "unknown device type";
+ goto invalid;
+ }
+
+ if (*p == '=') {
+ k = strcspn(p + 1, ":@,");
+
+ name = av_strndup(p + 1, k);
+ if (!name) {
+ err = AVERROR(ENOMEM);
+ goto fail;
+ }
+ if (hw_device_get_by_name(name)) {
+ errmsg = "named device already exists";
+ goto invalid;
+ }
+
+ p += 1 + k;
+ } else {
+ name = hw_device_default_name(type);
+ if (!name) {
+ err = AVERROR(ENOMEM);
+ goto fail;
+ }
+ }
+
+ if (!*p) {
+ // New device with no parameters.
+ err = av_hwdevice_ctx_create(&device_ref, type,
+ NULL, NULL, 0);
+ if (err < 0)
+ goto fail;
+
+ } else if (*p == ':') {
+ // New device with some parameters.
+ ++p;
+ q = strchr(p, ',');
+ if (q) {
+ if (q - p > 0) {
+ device = av_strndup(p, q - p);
+ if (!device) {
+ err = AVERROR(ENOMEM);
+ goto fail;
+ }
+ }
+ err = av_dict_parse_string(&options, q + 1, "=", ",", 0);
+ if (err < 0) {
+ errmsg = "failed to parse options";
+ goto invalid;
+ }
+ }
+
+ err = av_hwdevice_ctx_create(&device_ref, type,
+ q ? device : p[0] ? p : NULL,
+ options, 0);
+ if (err < 0)
+ goto fail;
+
+ } else if (*p == '@') {
+ // Derive from existing device.
+
+ src = hw_device_get_by_name(p + 1);
+ if (!src) {
+ errmsg = "invalid source device name";
+ goto invalid;
+ }
+
+ err = av_hwdevice_ctx_create_derived(&device_ref, type,
+ src->device_ref, 0);
+ if (err < 0)
+ goto fail;
+ } else if (*p == ',') {
+ err = av_dict_parse_string(&options, p + 1, "=", ",", 0);
+
+ if (err < 0) {
+ errmsg = "failed to parse options";
+ goto invalid;
+ }
+
+ err = av_hwdevice_ctx_create(&device_ref, type,
+ NULL, options, 0);
+ if (err < 0)
+ goto fail;
+ } else {
+ errmsg = "parse error";
+ goto invalid;
+ }
+
+ dev = hw_device_add();
+ if (!dev) {
+ err = AVERROR(ENOMEM);
+ goto fail;
+ }
+
+ dev->name = name;
+ dev->type = type;
+ dev->device_ref = device_ref;
+
+ if (dev_out)
+ *dev_out = dev;
+
+ name = NULL;
+ err = 0;
+done:
+ av_freep(&type_name);
+ av_freep(&name);
+ av_freep(&device);
+ av_dict_free(&options);
+ return err;
+invalid:
+ av_log(NULL, AV_LOG_ERROR,
+ "Invalid device specification \"%s\": %s\n", arg, errmsg);
+ err = AVERROR(EINVAL);
+ goto done;
+fail:
+ av_log(NULL, AV_LOG_ERROR,
+ "Device creation failed: %d.\n", err);
+ av_buffer_unref(&device_ref);
+ goto done;
+}
+
+static int hw_device_init_from_type(enum AVHWDeviceType type,
+ const char *device,
+ HWDevice **dev_out)
+{
+ AVBufferRef *device_ref = NULL;
+ HWDevice *dev;
+ char *name;
+ int err;
+
+ name = hw_device_default_name(type);
+ if (!name) {
+ err = AVERROR(ENOMEM);
+ goto fail;
+ }
+
+ err = av_hwdevice_ctx_create(&device_ref, type, device, NULL, 0);
+ if (err < 0) {
+ av_log(NULL, AV_LOG_ERROR,
+ "Device creation failed: %d.\n", err);
+ goto fail;
+ }
+
+ dev = hw_device_add();
+ if (!dev) {
+ err = AVERROR(ENOMEM);
+ goto fail;
+ }
+
+ dev->name = name;
+ dev->type = type;
+ dev->device_ref = device_ref;
+
+ if (dev_out)
+ *dev_out = dev;
+
+ return 0;
+
+fail:
+ av_freep(&name);
+ av_buffer_unref(&device_ref);
+ return err;
+}
+
+void hw_device_free_all(void)
+{
+ int i;
+ for (i = 0; i < nb_hw_devices; i++) {
+ av_freep(&hw_devices[i]->name);
+ av_buffer_unref(&hw_devices[i]->device_ref);
+ av_freep(&hw_devices[i]);
+ }
+ av_freep(&hw_devices);
+ nb_hw_devices = 0;
+}
+
+static HWDevice *hw_device_match_by_codec(const AVCodec *codec)
+{
+ const AVCodecHWConfig *config;
+ HWDevice *dev;
+ int i;
+ for (i = 0;; i++) {
+ config = avcodec_get_hw_config(codec, i);
+ if (!config)
+ return NULL;
+ if (!(config->methods & AV_CODEC_HW_CONFIG_METHOD_HW_DEVICE_CTX))
+ continue;
+ dev = hw_device_get_by_type(config->device_type);
+ if (dev)
+ return dev;
+ }
+}
+
+int hw_device_setup_for_decode(InputStream *ist)
+{
+ const AVCodecHWConfig *config;
+ enum AVHWDeviceType type;
+ HWDevice *dev = NULL;
+ int err, auto_device = 0;
+
+ if (ist->hwaccel_device) {
+ dev = hw_device_get_by_name(ist->hwaccel_device);
+ if (!dev) {
+ if (ist->hwaccel_id == HWACCEL_AUTO) {
+ auto_device = 1;
+ } else if (ist->hwaccel_id == HWACCEL_GENERIC) {
+ type = ist->hwaccel_device_type;
+ err = hw_device_init_from_type(type, ist->hwaccel_device,
+ &dev);
+ } else {
+ // This will be dealt with by API-specific initialisation
+ // (using hwaccel_device), so nothing further needed here.
+ return 0;
+ }
+ } else {
+ if (ist->hwaccel_id == HWACCEL_AUTO) {
+ ist->hwaccel_device_type = dev->type;
+ } else if (ist->hwaccel_device_type != dev->type) {
+ av_log(NULL, AV_LOG_ERROR, "Invalid hwaccel device "
+ "specified for decoder: device %s of type %s is not "
+ "usable with hwaccel %s.\n", dev->name,
+ av_hwdevice_get_type_name(dev->type),
+ av_hwdevice_get_type_name(ist->hwaccel_device_type));
+ return AVERROR(EINVAL);
+ }
+ }
+ } else {
+ if (ist->hwaccel_id == HWACCEL_AUTO) {
+ auto_device = 1;
+ } else if (ist->hwaccel_id == HWACCEL_GENERIC) {
+ type = ist->hwaccel_device_type;
+ dev = hw_device_get_by_type(type);
+
+ // When "-qsv_device device" is used, an internal QSV device named
+ // as "__qsv_device" is created. Another QSV device is created too
+ // if "-init_hw_device qsv=name:device" is used. There are 2 QSV devices
+ // if both "-qsv_device device" and "-init_hw_device qsv=name:device"
+ // are used, hw_device_get_by_type(AV_HWDEVICE_TYPE_QSV) returns NULL.
+ // To keep back-compatibility with the removed ad-hoc libmfx setup code,
+ // call hw_device_get_by_name("__qsv_device") to select the internal QSV
+ // device.
+ if (!dev && type == AV_HWDEVICE_TYPE_QSV)
+ dev = hw_device_get_by_name("__qsv_device");
+
+ if (!dev)
+ err = hw_device_init_from_type(type, NULL, &dev);
+ } else {
+ dev = hw_device_match_by_codec(ist->dec);
+ if (!dev) {
+ // No device for this codec, but not using generic hwaccel
+ // and therefore may well not need one - ignore.
+ return 0;
+ }
+ }
+ }
+
+ if (auto_device) {
+ int i;
+ if (!avcodec_get_hw_config(ist->dec, 0)) {
+ // Decoder does not support any hardware devices.
+ return 0;
+ }
+ for (i = 0; !dev; i++) {
+ config = avcodec_get_hw_config(ist->dec, i);
+ if (!config)
+ break;
+ type = config->device_type;
+ dev = hw_device_get_by_type(type);
+ if (dev) {
+ av_log(NULL, AV_LOG_INFO, "Using auto "
+ "hwaccel type %s with existing device %s.\n",
+ av_hwdevice_get_type_name(type), dev->name);
+ }
+ }
+ for (i = 0; !dev; i++) {
+ config = avcodec_get_hw_config(ist->dec, i);
+ if (!config)
+ break;
+ type = config->device_type;
+ // Try to make a new device of this type.
+ err = hw_device_init_from_type(type, ist->hwaccel_device,
+ &dev);
+ if (err < 0) {
+ // Can't make a device of this type.
+ continue;
+ }
+ if (ist->hwaccel_device) {
+ av_log(NULL, AV_LOG_INFO, "Using auto "
+ "hwaccel type %s with new device created "
+ "from %s.\n", av_hwdevice_get_type_name(type),
+ ist->hwaccel_device);
+ } else {
+ av_log(NULL, AV_LOG_INFO, "Using auto "
+ "hwaccel type %s with new default device.\n",
+ av_hwdevice_get_type_name(type));
+ }
+ }
+ if (dev) {
+ ist->hwaccel_device_type = type;
+ } else {
+ av_log(NULL, AV_LOG_INFO, "Auto hwaccel "
+ "disabled: no device found.\n");
+ ist->hwaccel_id = HWACCEL_NONE;
+ return 0;
+ }
+ }
+
+ if (!dev) {
+ av_log(NULL, AV_LOG_ERROR, "No device available "
+ "for decoder: device type %s needed for codec %s.\n",
+ av_hwdevice_get_type_name(type), ist->dec->name);
+ return err;
+ }
+
+ ist->dec_ctx->hw_device_ctx = av_buffer_ref(dev->device_ref);
+ if (!ist->dec_ctx->hw_device_ctx)
+ return AVERROR(ENOMEM);
+
+ return 0;
+}
+
+int hw_device_setup_for_encode(OutputStream *ost)
+{
+ const AVCodecHWConfig *config;
+ HWDevice *dev = NULL;
+ AVBufferRef *frames_ref = NULL;
+ int i;
+
+ if (ost->filter) {
+ frames_ref = av_buffersink_get_hw_frames_ctx(ost->filter->filter);
+ if (frames_ref &&
+ ((AVHWFramesContext*)frames_ref->data)->format ==
+ ost->enc_ctx->pix_fmt) {
+ // Matching format, will try to use hw_frames_ctx.
+ } else {
+ frames_ref = NULL;
+ }
+ }
+
+ for (i = 0;; i++) {
+ config = avcodec_get_hw_config(ost->enc_ctx->codec, i);
+ if (!config)
+ break;
+
+ if (frames_ref &&
+ config->methods & AV_CODEC_HW_CONFIG_METHOD_HW_FRAMES_CTX &&
+ (config->pix_fmt == AV_PIX_FMT_NONE ||
+ config->pix_fmt == ost->enc_ctx->pix_fmt)) {
+ av_log(ost->enc_ctx, AV_LOG_VERBOSE, "Using input "
+ "frames context (format %s) with %s encoder.\n",
+ av_get_pix_fmt_name(ost->enc_ctx->pix_fmt),
+ ost->enc_ctx->codec->name);
+ ost->enc_ctx->hw_frames_ctx = av_buffer_ref(frames_ref);
+ if (!ost->enc_ctx->hw_frames_ctx)
+ return AVERROR(ENOMEM);
+ return 0;
+ }
+
+ if (!dev &&
+ config->methods & AV_CODEC_HW_CONFIG_METHOD_HW_DEVICE_CTX)
+ dev = hw_device_get_by_type(config->device_type);
+ }
+
+ if (dev) {
+ av_log(ost->enc_ctx, AV_LOG_VERBOSE, "Using device %s "
+ "(type %s) with %s encoder.\n", dev->name,
+ av_hwdevice_get_type_name(dev->type), ost->enc_ctx->codec->name);
+ ost->enc_ctx->hw_device_ctx = av_buffer_ref(dev->device_ref);
+ if (!ost->enc_ctx->hw_device_ctx)
+ return AVERROR(ENOMEM);
+ } else {
+ // No device required, or no device available.
+ }
+ return 0;
+}
+
+static int hwaccel_retrieve_data(AVCodecContext *avctx, AVFrame *input)
+{
+ InputStream *ist = avctx->opaque;
+ AVFrame *output = NULL;
+ enum AVPixelFormat output_format = ist->hwaccel_output_format;
+ int err;
+
+ if (input->format == output_format) {
+ // Nothing to do.
+ return 0;
+ }
+
+ output = av_frame_alloc();
+ if (!output)
+ return AVERROR(ENOMEM);
+
+ output->format = output_format;
+
+ err = av_hwframe_transfer_data(output, input, 0);
+ if (err < 0) {
+ av_log(avctx, AV_LOG_ERROR, "Failed to transfer data to "
+ "output frame: %d.\n", err);
+ goto fail;
+ }
+
+ err = av_frame_copy_props(output, input);
+ if (err < 0) {
+ av_frame_unref(output);
+ goto fail;
+ }
+
+ av_frame_unref(input);
+ av_frame_move_ref(input, output);
+ av_frame_free(&output);
+
+ return 0;
+
+fail:
+ av_frame_free(&output);
+ return err;
+}
+
+int hwaccel_decode_init(AVCodecContext *avctx)
+{
+ InputStream *ist = avctx->opaque;
+
+ ist->hwaccel_retrieve_data = &hwaccel_retrieve_data;
+
+ return 0;
+}
+
+int hw_device_setup_for_filter(FilterGraph *fg)
+{
+ HWDevice *dev;
+ int i;
+
+ // Pick the last hardware device if the user doesn't pick the device for
+ // filters explicitly with the filter_hw_device option.
+ if (filter_hw_device)
+ dev = filter_hw_device;
+ else if (nb_hw_devices > 0) {
+ dev = hw_devices[nb_hw_devices - 1];
+
+ if (nb_hw_devices > 1)
+ av_log(NULL, AV_LOG_WARNING, "There are %d hardware devices. device "
+ "%s of type %s is picked for filters by default. Set hardware "
+ "device explicitly with the filter_hw_device option if device "
+ "%s is not usable for filters.\n",
+ nb_hw_devices, dev->name,
+ av_hwdevice_get_type_name(dev->type), dev->name);
+ } else
+ dev = NULL;
+
+ if (dev) {
+ for (i = 0; i < fg->graph->nb_filters; i++) {
+ fg->graph->filters[i]->hw_device_ctx =
+ av_buffer_ref(dev->device_ref);
+ if (!fg->graph->filters[i]->hw_device_ctx)
+ return AVERROR(ENOMEM);
+ }
+ }
+
+ return 0;
+}
diff --git a/app/src/main/cpp/ffmpeg/ffmpeg_mux.c b/app/src/main/cpp/ffmpeg/ffmpeg_mux.c
new file mode 100644
index 00000000..cf580519
--- /dev/null
+++ b/app/src/main/cpp/ffmpeg/ffmpeg_mux.c
@@ -0,0 +1,751 @@
+/*
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include
+#include
+#include
+
+#include "ffmpeg.h"
+#include "ffmpeg_mux.h"
+#include "objpool.h"
+#include "sync_queue.h"
+#include "thread_queue.h"
+
+#include "libavutil/fifo.h"
+#include "libavutil/intreadwrite.h"
+#include "libavutil/log.h"
+#include "libavutil/mem.h"
+#include "libavutil/timestamp.h"
+#include "libavutil/thread.h"
+
+#include "libavcodec/packet.h"
+
+#include "libavformat/avformat.h"
+#include "libavformat/avio.h"
+
+int want_sdp = 1;
+
+static Muxer *mux_from_of(OutputFile *of)
+{
+ return (Muxer*)of;
+}
+
+static int64_t filesize(AVIOContext *pb)
+{
+ int64_t ret = -1;
+
+ if (pb) {
+ ret = avio_size(pb);
+ if (ret <= 0) // FIXME improve avio_size() so it works with non seekable output too
+ ret = avio_tell(pb);
+ }
+
+ return ret;
+}
+
+static int write_packet(Muxer *mux, OutputStream *ost, AVPacket *pkt)
+{
+ MuxStream *ms = ms_from_ost(ost);
+ AVFormatContext *s = mux->fc;
+ AVStream *st = ost->st;
+ int64_t fs;
+ uint64_t frame_num;
+ int ret;
+
+ fs = filesize(s->pb);
+ atomic_store(&mux->last_filesize, fs);
+ if (fs >= mux->limit_filesize) {
+ ret = AVERROR_EOF;
+ goto fail;
+ }
+
+ if (st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO && ost->vsync_method == VSYNC_DROP)
+ pkt->pts = pkt->dts = AV_NOPTS_VALUE;
+
+ if (st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {
+ if (ost->frame_rate.num && ost->is_cfr) {
+ if (pkt->duration > 0)
+ av_log(ost, AV_LOG_WARNING, "Overriding packet duration by frame rate, this should not happen\n");
+ pkt->duration = av_rescale_q(1, av_inv_q(ost->frame_rate),
+ pkt->time_base);
+ }
+ }
+
+ av_packet_rescale_ts(pkt, pkt->time_base, ost->st->time_base);
+ pkt->time_base = ost->st->time_base;
+
+ if (!(s->oformat->flags & AVFMT_NOTIMESTAMPS)) {
+ if (pkt->dts != AV_NOPTS_VALUE &&
+ pkt->pts != AV_NOPTS_VALUE &&
+ pkt->dts > pkt->pts) {
+ av_log(s, AV_LOG_WARNING, "Invalid DTS: %"PRId64" PTS: %"PRId64" in output stream %d:%d, replacing by guess\n",
+ pkt->dts, pkt->pts,
+ ost->file_index, ost->st->index);
+ pkt->pts =
+ pkt->dts = pkt->pts + pkt->dts + ms->last_mux_dts + 1
+ - FFMIN3(pkt->pts, pkt->dts, ms->last_mux_dts + 1)
+ - FFMAX3(pkt->pts, pkt->dts, ms->last_mux_dts + 1);
+ }
+ if ((st->codecpar->codec_type == AVMEDIA_TYPE_AUDIO || st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO || st->codecpar->codec_type == AVMEDIA_TYPE_SUBTITLE) &&
+ pkt->dts != AV_NOPTS_VALUE &&
+ ms->last_mux_dts != AV_NOPTS_VALUE) {
+ int64_t max = ms->last_mux_dts + !(s->oformat->flags & AVFMT_TS_NONSTRICT);
+ if (pkt->dts < max) {
+ int loglevel = max - pkt->dts > 2 || st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO ? AV_LOG_WARNING : AV_LOG_DEBUG;
+ if (exit_on_error)
+ loglevel = AV_LOG_ERROR;
+ av_log(s, loglevel, "Non-monotonous DTS in output stream "
+ "%d:%d; previous: %"PRId64", current: %"PRId64"; ",
+ ost->file_index, ost->st->index, ms->last_mux_dts, pkt->dts);
+ if (exit_on_error) {
+ ret = AVERROR(EINVAL);
+ goto fail;
+ }
+
+ av_log(s, loglevel, "changing to %"PRId64". This may result "
+ "in incorrect timestamps in the output file.\n",
+ max);
+ if (pkt->pts >= pkt->dts)
+ pkt->pts = FFMAX(pkt->pts, max);
+ pkt->dts = max;
+ }
+ }
+ }
+ ms->last_mux_dts = pkt->dts;
+
+ ost->data_size_mux += pkt->size;
+ frame_num = atomic_fetch_add(&ost->packets_written, 1);
+
+ pkt->stream_index = ost->index;
+
+ if (debug_ts) {
+ av_log(ost, AV_LOG_INFO, "muxer <- type:%s "
+ "pkt_pts:%s pkt_pts_time:%s pkt_dts:%s pkt_dts_time:%s duration:%s duration_time:%s size:%d\n",
+ av_get_media_type_string(st->codecpar->codec_type),
+ av_ts2str(pkt->pts), av_ts2timestr(pkt->pts, &ost->st->time_base),
+ av_ts2str(pkt->dts), av_ts2timestr(pkt->dts, &ost->st->time_base),
+ av_ts2str(pkt->duration), av_ts2timestr(pkt->duration, &ost->st->time_base),
+ pkt->size
+ );
+ }
+
+ if (ms->stats.io)
+ enc_stats_write(ost, &ms->stats, NULL, pkt, frame_num);
+
+ ret = av_interleaved_write_frame(s, pkt);
+ if (ret < 0) {
+ print_error("av_interleaved_write_frame()", ret);
+ goto fail;
+ }
+
+ return 0;
+fail:
+ av_packet_unref(pkt);
+ return ret;
+}
+
+static int sync_queue_process(Muxer *mux, OutputStream *ost, AVPacket *pkt, int *stream_eof)
+{
+ OutputFile *of = &mux->of;
+
+ if (ost->sq_idx_mux >= 0) {
+ int ret = sq_send(mux->sq_mux, ost->sq_idx_mux, SQPKT(pkt));
+ if (ret < 0) {
+ if (ret == AVERROR_EOF)
+ *stream_eof = 1;
+
+ return ret;
+ }
+
+ while (1) {
+ ret = sq_receive(mux->sq_mux, -1, SQPKT(mux->sq_pkt));
+ if (ret < 0)
+ return (ret == AVERROR_EOF || ret == AVERROR(EAGAIN)) ? 0 : ret;
+
+ ret = write_packet(mux, of->streams[ret],
+ mux->sq_pkt);
+ if (ret < 0)
+ return ret;
+ }
+ } else if (pkt)
+ return write_packet(mux, ost, pkt);
+
+ return 0;
+}
+
+static void thread_set_name(OutputFile *of)
+{
+ char name[16];
+ snprintf(name, sizeof(name), "mux%d:%s", of->index, of->format->name);
+ ff_thread_setname(name);
+}
+
+static void *muxer_thread(void *arg)
+{
+ Muxer *mux = arg;
+ OutputFile *of = &mux->of;
+ AVPacket *pkt = NULL;
+ int ret = 0;
+
+ pkt = av_packet_alloc();
+ if (!pkt) {
+ ret = AVERROR(ENOMEM);
+ goto finish;
+ }
+
+ thread_set_name(of);
+
+ while (1) {
+ OutputStream *ost;
+ int stream_idx, stream_eof = 0;
+
+ ret = tq_receive(mux->tq, &stream_idx, pkt);
+ if (stream_idx < 0) {
+ av_log(mux, AV_LOG_VERBOSE, "All streams finished\n");
+ ret = 0;
+ break;
+ }
+
+ ost = of->streams[stream_idx];
+ ret = sync_queue_process(mux, ost, ret < 0 ? NULL : pkt, &stream_eof);
+ av_packet_unref(pkt);
+ if (ret == AVERROR_EOF && stream_eof)
+ tq_receive_finish(mux->tq, stream_idx);
+ else if (ret < 0) {
+ av_log(mux, AV_LOG_ERROR, "Error muxing a packet\n");
+ break;
+ }
+ }
+
+finish:
+ av_packet_free(&pkt);
+
+ for (unsigned int i = 0; i < mux->fc->nb_streams; i++)
+ tq_receive_finish(mux->tq, i);
+
+ av_log(mux, AV_LOG_VERBOSE, "Terminating muxer thread\n");
+
+ return (void*)(intptr_t)ret;
+}
+
+static int thread_submit_packet(Muxer *mux, OutputStream *ost, AVPacket *pkt)
+{
+ int ret = 0;
+
+ if (!pkt || ost->finished & MUXER_FINISHED)
+ goto finish;
+
+ ret = tq_send(mux->tq, ost->index, pkt);
+ if (ret < 0)
+ goto finish;
+
+ return 0;
+
+finish:
+ if (pkt)
+ av_packet_unref(pkt);
+
+ ost->finished |= MUXER_FINISHED;
+ tq_send_finish(mux->tq, ost->index);
+ return ret == AVERROR_EOF ? 0 : ret;
+}
+
+static int queue_packet(Muxer *mux, OutputStream *ost, AVPacket *pkt)
+{
+ MuxStream *ms = ms_from_ost(ost);
+ AVPacket *tmp_pkt = NULL;
+ int ret;
+
+ if (!av_fifo_can_write(ms->muxing_queue)) {
+ size_t cur_size = av_fifo_can_read(ms->muxing_queue);
+ size_t pkt_size = pkt ? pkt->size : 0;
+ unsigned int are_we_over_size =
+ (ms->muxing_queue_data_size + pkt_size) > ms->muxing_queue_data_threshold;
+ size_t limit = are_we_over_size ? ms->max_muxing_queue_size : SIZE_MAX;
+ size_t new_size = FFMIN(2 * cur_size, limit);
+
+ if (new_size <= cur_size) {
+ av_log(ost, AV_LOG_ERROR,
+ "Too many packets buffered for output stream %d:%d.\n",
+ ost->file_index, ost->st->index);
+ return AVERROR(ENOSPC);
+ }
+ ret = av_fifo_grow2(ms->muxing_queue, new_size - cur_size);
+ if (ret < 0)
+ return ret;
+ }
+
+ if (pkt) {
+ ret = av_packet_make_refcounted(pkt);
+ if (ret < 0)
+ return ret;
+
+ tmp_pkt = av_packet_alloc();
+ if (!tmp_pkt)
+ return AVERROR(ENOMEM);
+
+ av_packet_move_ref(tmp_pkt, pkt);
+ ms->muxing_queue_data_size += tmp_pkt->size;
+ }
+ av_fifo_write(ms->muxing_queue, &tmp_pkt, 1);
+
+ return 0;
+}
+
+static int submit_packet(Muxer *mux, AVPacket *pkt, OutputStream *ost)
+{
+ int ret;
+
+ if (mux->tq) {
+ return thread_submit_packet(mux, ost, pkt);
+ } else {
+ /* the muxer is not initialized yet, buffer the packet */
+ ret = queue_packet(mux, ost, pkt);
+ if (ret < 0) {
+ if (pkt)
+ av_packet_unref(pkt);
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+void of_output_packet(OutputFile *of, AVPacket *pkt, OutputStream *ost, int eof)
+{
+ Muxer *mux = mux_from_of(of);
+ MuxStream *ms = ms_from_ost(ost);
+ const char *err_msg;
+ int ret = 0;
+
+ if (!eof && pkt->dts != AV_NOPTS_VALUE)
+ ost->last_mux_dts = av_rescale_q(pkt->dts, pkt->time_base, AV_TIME_BASE_Q);
+
+ /* apply the output bitstream filters */
+ if (ms->bsf_ctx) {
+ int bsf_eof = 0;
+
+ ret = av_bsf_send_packet(ms->bsf_ctx, eof ? NULL : pkt);
+ if (ret < 0) {
+ err_msg = "submitting a packet for bitstream filtering";
+ goto fail;
+ }
+
+ while (!bsf_eof) {
+ ret = av_bsf_receive_packet(ms->bsf_ctx, pkt);
+ if (ret == AVERROR(EAGAIN))
+ return;
+ else if (ret == AVERROR_EOF)
+ bsf_eof = 1;
+ else if (ret < 0) {
+ err_msg = "applying bitstream filters to a packet";
+ goto fail;
+ }
+
+ ret = submit_packet(mux, bsf_eof ? NULL : pkt, ost);
+ if (ret < 0)
+ goto mux_fail;
+ }
+ } else {
+ ret = submit_packet(mux, eof ? NULL : pkt, ost);
+ if (ret < 0)
+ goto mux_fail;
+ }
+
+ return;
+
+mux_fail:
+ err_msg = "submitting a packet to the muxer";
+
+fail:
+ av_log(ost, AV_LOG_ERROR, "Error %s\n", err_msg);
+ if (exit_on_error)
+ exit_program(1);
+
+}
+
+static int thread_stop(Muxer *mux)
+{
+ void *ret;
+
+ if (!mux || !mux->tq)
+ return 0;
+
+ for (unsigned int i = 0; i < mux->fc->nb_streams; i++)
+ tq_send_finish(mux->tq, i);
+
+ pthread_join(mux->thread, &ret);
+
+ tq_free(&mux->tq);
+
+ return (int)(intptr_t)ret;
+}
+
+static void pkt_move(void *dst, void *src)
+{
+ av_packet_move_ref(dst, src);
+}
+
+static int thread_start(Muxer *mux)
+{
+ AVFormatContext *fc = mux->fc;
+ ObjPool *op;
+ int ret;
+
+ op = objpool_alloc_packets();
+ if (!op)
+ return AVERROR(ENOMEM);
+
+ mux->tq = tq_alloc(fc->nb_streams, mux->thread_queue_size, op, pkt_move);
+ if (!mux->tq) {
+ objpool_free(&op);
+ return AVERROR(ENOMEM);
+ }
+
+ ret = pthread_create(&mux->thread, NULL, muxer_thread, (void*)mux);
+ if (ret) {
+ tq_free(&mux->tq);
+ return AVERROR(ret);
+ }
+
+ /* flush the muxing queues */
+ for (int i = 0; i < fc->nb_streams; i++) {
+ OutputStream *ost = mux->of.streams[i];
+ MuxStream *ms = ms_from_ost(ost);
+ AVPacket *pkt;
+
+ /* try to improve muxing time_base (only possible if nothing has been written yet) */
+ if (!av_fifo_can_read(ms->muxing_queue))
+ ost->mux_timebase = ost->st->time_base;
+
+ while (av_fifo_read(ms->muxing_queue, &pkt, 1) >= 0) {
+ ret = thread_submit_packet(mux, ost, pkt);
+ if (pkt) {
+ ms->muxing_queue_data_size -= pkt->size;
+ av_packet_free(&pkt);
+ }
+ if (ret < 0)
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+static int print_sdp(void)
+{
+ char sdp[16384];
+ int i;
+ int j, ret;
+ AVIOContext *sdp_pb;
+ AVFormatContext **avc;
+
+ for (i = 0; i < nb_output_files; i++) {
+ if (!mux_from_of(output_files[i])->header_written)
+ return 0;
+ }
+
+ avc = av_malloc_array(nb_output_files, sizeof(*avc));
+ if (!avc)
+ return AVERROR(ENOMEM);
+ for (i = 0, j = 0; i < nb_output_files; i++) {
+ if (!strcmp(output_files[i]->format->name, "rtp")) {
+ avc[j] = mux_from_of(output_files[i])->fc;
+ j++;
+ }
+ }
+
+ if (!j) {
+ av_log(NULL, AV_LOG_ERROR, "No output streams in the SDP.\n");
+ ret = AVERROR(EINVAL);
+ goto fail;
+ }
+
+ ret = av_sdp_create(avc, j, sdp, sizeof(sdp));
+ if (ret < 0)
+ goto fail;
+
+ if (!sdp_filename) {
+ printf("SDP:\n%s\n", sdp);
+ fflush(stdout);
+ } else {
+ ret = avio_open2(&sdp_pb, sdp_filename, AVIO_FLAG_WRITE, &int_cb, NULL);
+ if (ret < 0) {
+ av_log(NULL, AV_LOG_ERROR, "Failed to open sdp file '%s'\n", sdp_filename);
+ goto fail;
+ }
+
+ avio_print(sdp_pb, sdp);
+ avio_closep(&sdp_pb);
+ av_freep(&sdp_filename);
+ }
+
+ // SDP successfully written, allow muxer threads to start
+ ret = 1;
+
+fail:
+ av_freep(&avc);
+ return ret;
+}
+
+int mux_check_init(Muxer *mux)
+{
+ OutputFile *of = &mux->of;
+ AVFormatContext *fc = mux->fc;
+ int ret, i;
+
+ for (i = 0; i < fc->nb_streams; i++) {
+ OutputStream *ost = of->streams[i];
+ if (!ost->initialized)
+ return 0;
+ }
+
+ ret = avformat_write_header(fc, &mux->opts);
+ if (ret < 0) {
+ av_log(mux, AV_LOG_ERROR, "Could not write header (incorrect codec "
+ "parameters ?): %s\n", av_err2str(ret));
+ return ret;
+ }
+ //assert_avoptions(of->opts);
+ mux->header_written = 1;
+
+ av_dump_format(fc, of->index, fc->url, 1);
+ nb_output_dumped++;
+
+ if (sdp_filename || want_sdp) {
+ ret = print_sdp();
+ if (ret < 0) {
+ av_log(NULL, AV_LOG_ERROR, "Error writing the SDP.\n");
+ return ret;
+ } else if (ret == 1) {
+ /* SDP is written only after all the muxers are ready, so now we
+ * start ALL the threads */
+ for (i = 0; i < nb_output_files; i++) {
+ ret = thread_start(mux_from_of(output_files[i]));
+ if (ret < 0)
+ return ret;
+ }
+ }
+ } else {
+ ret = thread_start(mux_from_of(of));
+ if (ret < 0)
+ return ret;
+ }
+
+ return 0;
+}
+
+static int bsf_init(MuxStream *ms)
+{
+ OutputStream *ost = &ms->ost;
+ AVBSFContext *ctx = ms->bsf_ctx;
+ int ret;
+
+ if (!ctx)
+ return 0;
+
+ ret = avcodec_parameters_copy(ctx->par_in, ost->st->codecpar);
+ if (ret < 0)
+ return ret;
+
+ ctx->time_base_in = ost->st->time_base;
+
+ ret = av_bsf_init(ctx);
+ if (ret < 0) {
+ av_log(ms, AV_LOG_ERROR, "Error initializing bitstream filter: %s\n",
+ ctx->filter->name);
+ return ret;
+ }
+
+ ret = avcodec_parameters_copy(ost->st->codecpar, ctx->par_out);
+ if (ret < 0)
+ return ret;
+ ost->st->time_base = ctx->time_base_out;
+
+ return 0;
+}
+
+int of_stream_init(OutputFile *of, OutputStream *ost)
+{
+ Muxer *mux = mux_from_of(of);
+ MuxStream *ms = ms_from_ost(ost);
+ int ret;
+
+ if (ost->sq_idx_mux >= 0)
+ sq_set_tb(mux->sq_mux, ost->sq_idx_mux, ost->mux_timebase);
+
+ /* initialize bitstream filters for the output stream
+ * needs to be done here, because the codec id for streamcopy is not
+ * known until now */
+ ret = bsf_init(ms);
+ if (ret < 0)
+ return ret;
+
+ ost->initialized = 1;
+
+ return mux_check_init(mux);
+}
+
+int of_write_trailer(OutputFile *of)
+{
+ Muxer *mux = mux_from_of(of);
+ AVFormatContext *fc = mux->fc;
+ int ret;
+
+ if (!mux->tq) {
+ av_log(mux, AV_LOG_ERROR,
+ "Nothing was written into output file, because "
+ "at least one of its streams received no packets.\n");
+ return AVERROR(EINVAL);
+ }
+
+ ret = thread_stop(mux);
+ if (ret < 0)
+ main_return_code = ret;
+
+ ret = av_write_trailer(fc);
+ if (ret < 0) {
+ av_log(mux, AV_LOG_ERROR, "Error writing trailer: %s\n", av_err2str(ret));
+ return ret;
+ }
+
+ mux->last_filesize = filesize(fc->pb);
+
+ if (!(of->format->flags & AVFMT_NOFILE)) {
+ ret = avio_closep(&fc->pb);
+ if (ret < 0) {
+ av_log(mux, AV_LOG_ERROR, "Error closing file: %s\n", av_err2str(ret));
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+static void ost_free(OutputStream **post)
+{
+ OutputStream *ost = *post;
+ MuxStream *ms;
+
+ if (!ost)
+ return;
+ ms = ms_from_ost(ost);
+
+ if (ost->logfile) {
+ if (fclose(ost->logfile))
+ av_log(ms, AV_LOG_ERROR,
+ "Error closing logfile, loss of information possible: %s\n",
+ av_err2str(AVERROR(errno)));
+ ost->logfile = NULL;
+ }
+
+ if (ms->muxing_queue) {
+ AVPacket *pkt;
+ while (av_fifo_read(ms->muxing_queue, &pkt, 1) >= 0)
+ av_packet_free(&pkt);
+ av_fifo_freep2(&ms->muxing_queue);
+ }
+
+ av_bsf_free(&ms->bsf_ctx);
+
+ av_frame_free(&ost->filtered_frame);
+ av_frame_free(&ost->sq_frame);
+ av_frame_free(&ost->last_frame);
+ av_packet_free(&ost->pkt);
+ av_dict_free(&ost->encoder_opts);
+
+ av_freep(&ost->kf.pts);
+ av_expr_free(ost->kf.pexpr);
+
+ av_freep(&ost->avfilter);
+ av_freep(&ost->logfile_prefix);
+ av_freep(&ost->apad);
+
+#if FFMPEG_OPT_MAP_CHANNEL
+ av_freep(&ost->audio_channels_map);
+ ost->audio_channels_mapped = 0;
+#endif
+
+ av_dict_free(&ost->sws_dict);
+ av_dict_free(&ost->swr_opts);
+
+ if (ost->enc_ctx)
+ av_freep(&ost->enc_ctx->stats_in);
+ avcodec_free_context(&ost->enc_ctx);
+
+ for (int i = 0; i < ost->enc_stats_pre.nb_components; i++)
+ av_freep(&ost->enc_stats_pre.components[i].str);
+ av_freep(&ost->enc_stats_pre.components);
+
+ for (int i = 0; i < ost->enc_stats_post.nb_components; i++)
+ av_freep(&ost->enc_stats_post.components[i].str);
+ av_freep(&ost->enc_stats_post.components);
+
+ for (int i = 0; i < ms->stats.nb_components; i++)
+ av_freep(&ms->stats.components[i].str);
+ av_freep(&ms->stats.components);
+
+ av_freep(post);
+}
+
+static void fc_close(AVFormatContext **pfc)
+{
+ AVFormatContext *fc = *pfc;
+
+ if (!fc)
+ return;
+
+ if (!(fc->oformat->flags & AVFMT_NOFILE))
+ avio_closep(&fc->pb);
+ avformat_free_context(fc);
+
+ *pfc = NULL;
+}
+
+void of_close(OutputFile **pof)
+{
+ OutputFile *of = *pof;
+ Muxer *mux;
+
+ if (!of)
+ return;
+ mux = mux_from_of(of);
+
+ thread_stop(mux);
+
+ sq_free(&of->sq_encode);
+ sq_free(&mux->sq_mux);
+
+ for (int i = 0; i < of->nb_streams; i++)
+ ost_free(&of->streams[i]);
+ av_freep(&of->streams);
+
+ av_dict_free(&mux->opts);
+
+ av_packet_free(&mux->sq_pkt);
+
+ fc_close(&mux->fc);
+
+ av_freep(pof);
+}
+
+int64_t of_filesize(OutputFile *of)
+{
+ Muxer *mux = mux_from_of(of);
+ return atomic_load(&mux->last_filesize);
+}
diff --git a/app/src/main/cpp/ffmpeg/ffmpeg_mux.h b/app/src/main/cpp/ffmpeg/ffmpeg_mux.h
new file mode 100644
index 00000000..c76dc2e5
--- /dev/null
+++ b/app/src/main/cpp/ffmpeg/ffmpeg_mux.h
@@ -0,0 +1,102 @@
+/*
+ * Muxer internal APIs - should not be included outside of ffmpeg_mux*
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef FFTOOLS_FFMPEG_MUX_H
+#define FFTOOLS_FFMPEG_MUX_H
+
+#include
+#include
+
+#include "thread_queue.h"
+
+#include "libavformat/avformat.h"
+
+#include "libavcodec/packet.h"
+
+#include "libavutil/dict.h"
+#include "libavutil/fifo.h"
+#include "libavutil/thread.h"
+
+typedef struct MuxStream {
+ OutputStream ost;
+
+ // name used for logging
+ char log_name[32];
+
+ /* the packets are buffered here until the muxer is ready to be initialized */
+ AVFifo *muxing_queue;
+
+ AVBSFContext *bsf_ctx;
+
+ EncStats stats;
+
+ int64_t max_frames;
+
+ /*
+ * The size of the AVPackets' buffers in queue.
+ * Updated when a packet is either pushed or pulled from the queue.
+ */
+ size_t muxing_queue_data_size;
+
+ int max_muxing_queue_size;
+
+ /* Threshold after which max_muxing_queue_size will be in effect */
+ size_t muxing_queue_data_threshold;
+
+ /* dts of the last packet sent to the muxer, in the stream timebase
+ * used for making up missing dts values */
+ int64_t last_mux_dts;
+} MuxStream;
+
+typedef struct Muxer {
+ OutputFile of;
+
+ // name used for logging
+ char log_name[32];
+
+ AVFormatContext *fc;
+
+ pthread_t thread;
+ ThreadQueue *tq;
+
+ AVDictionary *opts;
+
+ int thread_queue_size;
+
+ /* filesize limit expressed in bytes */
+ int64_t limit_filesize;
+ atomic_int_least64_t last_filesize;
+ int header_written;
+
+ SyncQueue *sq_mux;
+ AVPacket *sq_pkt;
+} Muxer;
+
+/* whether we want to print an SDP, set in of_open() */
+extern int want_sdp;
+
+int mux_check_init(Muxer *mux);
+
+static MuxStream *ms_from_ost(OutputStream *ost)
+{
+ return (MuxStream*)ost;
+}
+
+#endif /* FFTOOLS_FFMPEG_MUX_H */
diff --git a/app/src/main/cpp/ffmpeg/ffmpeg_mux_init.c b/app/src/main/cpp/ffmpeg/ffmpeg_mux_init.c
new file mode 100644
index 00000000..b3cc502f
--- /dev/null
+++ b/app/src/main/cpp/ffmpeg/ffmpeg_mux_init.c
@@ -0,0 +1,2400 @@
+/*
+ * Muxer/output file setup.
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include
+
+#include "cmdutils.h"
+#include "ffmpeg.h"
+#include "ffmpeg_mux.h"
+#include "fopen_utf8.h"
+
+#include "libavformat/avformat.h"
+#include "libavformat/avio.h"
+
+#include "libavcodec/avcodec.h"
+
+#include "libavfilter/avfilter.h"
+
+#include "libavutil/avassert.h"
+#include "libavutil/avstring.h"
+#include "libavutil/avutil.h"
+#include "libavutil/bprint.h"
+#include "libavutil/dict.h"
+#include "libavutil/getenv_utf8.h"
+#include "libavutil/intreadwrite.h"
+#include "libavutil/log.h"
+#include "libavutil/mem.h"
+#include "libavutil/opt.h"
+#include "libavutil/parseutils.h"
+#include "libavutil/pixdesc.h"
+
+#define DEFAULT_PASS_LOGFILENAME_PREFIX "ffmpeg2pass"
+
+static const char *const opt_name_apad[] = {"apad", NULL};
+static const char *const opt_name_autoscale[] = {"autoscale", NULL};
+static const char *const opt_name_bits_per_raw_sample[] = {"bits_per_raw_sample", NULL};
+static const char *const opt_name_bitstream_filters[] = {"bsf", "absf", "vbsf", NULL};
+static const char *const opt_name_copy_initial_nonkeyframes[] = {"copyinkf", NULL};
+static const char *const opt_name_copy_prior_start[] = {"copypriorss", NULL};
+static const char *const opt_name_disposition[] = {"disposition", NULL};
+static const char *const opt_name_enc_time_bases[] = {"enc_time_base", NULL};
+static const char *const opt_name_enc_stats_pre[] = {"enc_stats_pre", NULL};
+static const char *const opt_name_enc_stats_post[] = {"enc_stats_post", NULL};
+static const char *const opt_name_mux_stats[] = {"mux_stats", NULL};
+static const char *const opt_name_enc_stats_pre_fmt[] = {"enc_stats_pre_fmt", NULL};
+static const char *const opt_name_enc_stats_post_fmt[] = {"enc_stats_post_fmt", NULL};
+static const char *const opt_name_mux_stats_fmt[] = {"mux_stats_fmt", NULL};
+static const char *const opt_name_filters[] = {"filter", "af", "vf", NULL};
+static const char *const opt_name_filter_scripts[] = {"filter_script", NULL};
+static const char *const opt_name_fix_sub_duration_heartbeat[] = {"fix_sub_duration_heartbeat", NULL};
+static const char *const opt_name_fps_mode[] = {"fps_mode", NULL};
+static const char *const opt_name_force_fps[] = {"force_fps", NULL};
+static const char *const opt_name_forced_key_frames[] = {"forced_key_frames", NULL};
+static const char *const opt_name_frame_aspect_ratios[] = {"aspect", NULL};
+static const char *const opt_name_intra_matrices[] = {"intra_matrix", NULL};
+static const char *const opt_name_inter_matrices[] = {"inter_matrix", NULL};
+static const char *const opt_name_chroma_intra_matrices[] = {"chroma_intra_matrix", NULL};
+static const char *const opt_name_max_frame_rates[] = {"fpsmax", NULL};
+static const char *const opt_name_max_frames[] = {"frames", "aframes", "vframes", "dframes", NULL};
+static const char *const opt_name_max_muxing_queue_size[] = {"max_muxing_queue_size", NULL};
+static const char *const opt_name_muxing_queue_data_threshold[] = {"muxing_queue_data_threshold", NULL};
+static const char *const opt_name_pass[] = {"pass", NULL};
+static const char *const opt_name_passlogfiles[] = {"passlogfile", NULL};
+static const char *const opt_name_presets[] = {"pre", "apre", "vpre", "spre", NULL};
+static const char *const opt_name_qscale[] = {"q", "qscale", NULL};
+static const char *const opt_name_rc_overrides[] = {"rc_override", NULL};
+static const char *const opt_name_time_bases[] = {"time_base", NULL};
+static const char *const opt_name_audio_channels[] = {"ac", NULL};
+static const char *const opt_name_audio_ch_layouts[] = {"channel_layout", "ch_layout", NULL};
+static const char *const opt_name_audio_sample_rate[] = {"ar", NULL};
+static const char *const opt_name_frame_sizes[] = {"s", NULL};
+static const char *const opt_name_frame_pix_fmts[] = {"pix_fmt", NULL};
+static const char *const opt_name_sample_fmts[] = {"sample_fmt", NULL};
+
+static int check_opt_bitexact(void *ctx, const AVDictionary *opts,
+ const char *opt_name, int flag)
+{
+ const AVDictionaryEntry *e = av_dict_get(opts, opt_name, NULL, 0);
+
+ if (e) {
+ const AVOption *o = av_opt_find(ctx, opt_name, NULL, 0, 0);
+ int val = 0;
+ if (!o)
+ return 0;
+ av_opt_eval_flags(ctx, o, e->value, &val);
+ return !!(val & flag);
+ }
+ return 0;
+}
+
+static int choose_encoder(const OptionsContext *o, AVFormatContext *s,
+ OutputStream *ost, const AVCodec **enc)
+{
+ enum AVMediaType type = ost->st->codecpar->codec_type;
+ char *codec_name = NULL;
+
+ *enc = NULL;
+
+ if (type == AVMEDIA_TYPE_VIDEO || type == AVMEDIA_TYPE_AUDIO || type == AVMEDIA_TYPE_SUBTITLE) {
+ MATCH_PER_STREAM_OPT(codec_names, str, codec_name, s, ost->st);
+ if (!codec_name) {
+ ost->st->codecpar->codec_id = av_guess_codec(s->oformat, NULL, s->url,
+ NULL, ost->st->codecpar->codec_type);
+ *enc = avcodec_find_encoder(ost->st->codecpar->codec_id);
+ if (!*enc) {
+ av_log(ost, AV_LOG_FATAL, "Automatic encoder selection failed "
+ "Default encoder for format %s (codec %s) is "
+ "probably disabled. Please choose an encoder manually.\n",
+ s->oformat->name, avcodec_get_name(ost->st->codecpar->codec_id));
+ return AVERROR_ENCODER_NOT_FOUND;
+ }
+ } else if (strcmp(codec_name, "copy")) {
+ *enc = find_codec_or_die(ost, codec_name, ost->st->codecpar->codec_type, 1);
+ ost->st->codecpar->codec_id = (*enc)->id;
+ }
+ }
+
+ return 0;
+}
+
+static char *get_line(AVIOContext *s, AVBPrint *bprint)
+{
+ char c;
+
+ while ((c = avio_r8(s)) && c != '\n')
+ av_bprint_chars(bprint, c, 1);
+
+ if (!av_bprint_is_complete(bprint))
+ report_and_exit(AVERROR(ENOMEM));
+ return bprint->str;
+}
+
+static int get_preset_file_2(const char *preset_name, const char *codec_name, AVIOContext **s)
+{
+ int i, ret = -1;
+ char filename[1000];
+ char *env_avconv_datadir = getenv_utf8("AVCONV_DATADIR");
+ char *env_home = getenv_utf8("HOME");
+ const char *base[3] = { env_avconv_datadir,
+ env_home,
+ AVCONV_DATADIR,
+ };
+
+ for (i = 0; i < FF_ARRAY_ELEMS(base) && ret < 0; i++) {
+ if (!base[i])
+ continue;
+ if (codec_name) {
+ snprintf(filename, sizeof(filename), "%s%s/%s-%s.avpreset", base[i],
+ i != 1 ? "" : "/.avconv", codec_name, preset_name);
+ ret = avio_open2(s, filename, AVIO_FLAG_READ, &int_cb, NULL);
+ }
+ if (ret < 0) {
+ snprintf(filename, sizeof(filename), "%s%s/%s.avpreset", base[i],
+ i != 1 ? "" : "/.avconv", preset_name);
+ ret = avio_open2(s, filename, AVIO_FLAG_READ, &int_cb, NULL);
+ }
+ }
+ freeenv_utf8(env_home);
+ freeenv_utf8(env_avconv_datadir);
+ return ret;
+}
+
+typedef struct EncStatsFile {
+ char *path;
+ AVIOContext *io;
+} EncStatsFile;
+
+static EncStatsFile *enc_stats_files;
+static int nb_enc_stats_files;
+
+static int enc_stats_get_file(AVIOContext **io, const char *path)
+{
+ EncStatsFile *esf;
+ int ret;
+
+ for (int i = 0; i < nb_enc_stats_files; i++)
+ if (!strcmp(path, enc_stats_files[i].path)) {
+ *io = enc_stats_files[i].io;
+ return 0;
+ }
+
+ GROW_ARRAY(enc_stats_files, nb_enc_stats_files);
+
+ esf = &enc_stats_files[nb_enc_stats_files - 1];
+
+ ret = avio_open2(&esf->io, path, AVIO_FLAG_WRITE, &int_cb, NULL);
+ if (ret < 0) {
+ av_log(NULL, AV_LOG_ERROR, "Error opening stats file '%s': %s\n",
+ path, av_err2str(ret));
+ return ret;
+ }
+
+ esf->path = av_strdup(path);
+ if (!esf->path)
+ return AVERROR(ENOMEM);
+
+ *io = esf->io;
+
+ return 0;
+}
+
+void of_enc_stats_close(void)
+{
+ for (int i = 0; i < nb_enc_stats_files; i++) {
+ av_freep(&enc_stats_files[i].path);
+ avio_closep(&enc_stats_files[i].io);
+ }
+ av_freep(&enc_stats_files);
+ nb_enc_stats_files = 0;
+}
+
+static int unescape(char **pdst, size_t *dst_len,
+ const char **pstr, char delim)
+{
+ const char *str = *pstr;
+ char *dst;
+ size_t len, idx;
+
+ *pdst = NULL;
+
+ len = strlen(str);
+ if (!len)
+ return 0;
+
+ dst = av_malloc(len + 1);
+ if (!dst)
+ return AVERROR(ENOMEM);
+
+ for (idx = 0; *str; idx++, str++) {
+ if (str[0] == '\\' && str[1])
+ str++;
+ else if (*str == delim)
+ break;
+
+ dst[idx] = *str;
+ }
+ if (!idx) {
+ av_freep(&dst);
+ return 0;
+ }
+
+ dst[idx] = 0;
+
+ *pdst = dst;
+ *dst_len = idx;
+ *pstr = str;
+
+ return 0;
+}
+
+static int enc_stats_init(OutputStream *ost, EncStats *es, int pre,
+ const char *path, const char *fmt_spec)
+{
+ static const struct {
+ enum EncStatsType type;
+ const char *str;
+ int pre_only:1;
+ int post_only:1;
+ int need_input_data:1;
+ } fmt_specs[] = {
+ { ENC_STATS_FILE_IDX, "fidx" },
+ { ENC_STATS_STREAM_IDX, "sidx" },
+ { ENC_STATS_FRAME_NUM, "n" },
+ { ENC_STATS_FRAME_NUM_IN, "ni", 0, 0, 1 },
+ { ENC_STATS_TIMEBASE, "tb" },
+ { ENC_STATS_TIMEBASE_IN, "tbi", 0, 0, 1 },
+ { ENC_STATS_PTS, "pts" },
+ { ENC_STATS_PTS_TIME, "t" },
+ { ENC_STATS_PTS_IN, "ptsi", 0, 0, 1 },
+ { ENC_STATS_PTS_TIME_IN, "ti", 0, 0, 1 },
+ { ENC_STATS_DTS, "dts", 0, 1 },
+ { ENC_STATS_DTS_TIME, "dt", 0, 1 },
+ { ENC_STATS_SAMPLE_NUM, "sn", 1 },
+ { ENC_STATS_NB_SAMPLES, "samp", 1 },
+ { ENC_STATS_PKT_SIZE, "size", 0, 1 },
+ { ENC_STATS_BITRATE, "br", 0, 1 },
+ { ENC_STATS_AVG_BITRATE, "abr", 0, 1 },
+ };
+ const char *next = fmt_spec;
+
+ int ret;
+
+ while (*next) {
+ EncStatsComponent *c;
+ char *val;
+ size_t val_len;
+
+ // get the sequence up until next opening brace
+ ret = unescape(&val, &val_len, &next, '{');
+ if (ret < 0)
+ return ret;
+
+ if (val) {
+ GROW_ARRAY(es->components, es->nb_components);
+
+ c = &es->components[es->nb_components - 1];
+ c->type = ENC_STATS_LITERAL;
+ c->str = val;
+ c->str_len = val_len;
+ }
+
+ if (!*next)
+ break;
+ next++;
+
+ // get the part inside braces
+ ret = unescape(&val, &val_len, &next, '}');
+ if (ret < 0)
+ return ret;
+
+ if (!val) {
+ av_log(NULL, AV_LOG_ERROR,
+ "Empty formatting directive in: %s\n", fmt_spec);
+ return AVERROR(EINVAL);
+ }
+
+ if (!*next) {
+ av_log(NULL, AV_LOG_ERROR,
+ "Missing closing brace in: %s\n", fmt_spec);
+ ret = AVERROR(EINVAL);
+ goto fail;
+ }
+ next++;
+
+ GROW_ARRAY(es->components, es->nb_components);
+ c = &es->components[es->nb_components - 1];
+
+ for (size_t i = 0; i < FF_ARRAY_ELEMS(fmt_specs); i++) {
+ if (!strcmp(val, fmt_specs[i].str)) {
+ if ((pre && fmt_specs[i].post_only) || (!pre && fmt_specs[i].pre_only)) {
+ av_log(NULL, AV_LOG_ERROR,
+ "Format directive '%s' may only be used %s-encoding\n",
+ val, pre ? "post" : "pre");
+ ret = AVERROR(EINVAL);
+ goto fail;
+ }
+
+ c->type = fmt_specs[i].type;
+
+ if (fmt_specs[i].need_input_data) {
+ if (ost->ist)
+ ost->ist->want_frame_data = 1;
+ else {
+ av_log(ost, AV_LOG_WARNING,
+ "Format directive '%s' is unavailable, because "
+ "this output stream has no associated input stream\n",
+ val);
+ }
+ }
+
+ break;
+ }
+ }
+
+ if (!c->type) {
+ av_log(NULL, AV_LOG_ERROR, "Invalid format directive: %s\n", val);
+ ret = AVERROR(EINVAL);
+ goto fail;
+ }
+
+fail:
+ av_freep(&val);
+ if (ret < 0)
+ return ret;
+ }
+
+ ret = enc_stats_get_file(&es->io, path);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+static const char *output_stream_item_name(void *obj)
+{
+ const MuxStream *ms = obj;
+
+ return ms->log_name;
+}
+
+static const AVClass output_stream_class = {
+ .class_name = "OutputStream",
+ .version = LIBAVUTIL_VERSION_INT,
+ .item_name = output_stream_item_name,
+ .category = AV_CLASS_CATEGORY_MUXER,
+};
+
+static MuxStream *mux_stream_alloc(Muxer *mux, enum AVMediaType type)
+{
+ const char *type_str = av_get_media_type_string(type);
+ MuxStream *ms = allocate_array_elem(&mux->of.streams, sizeof(*ms),
+ &mux->of.nb_streams);
+
+ ms->ost.file_index = mux->of.index;
+ ms->ost.index = mux->of.nb_streams - 1;
+
+ ms->ost.class = &output_stream_class;
+
+ snprintf(ms->log_name, sizeof(ms->log_name), "%cost#%d:%d",
+ type_str ? *type_str : '?', mux->of.index, ms->ost.index);
+
+ return ms;
+}
+
+static OutputStream *new_output_stream(Muxer *mux, const OptionsContext *o,
+ enum AVMediaType type, InputStream *ist)
+{
+ AVFormatContext *oc = mux->fc;
+ MuxStream *ms;
+ OutputStream *ost;
+ const AVCodec *enc;
+ AVStream *st = avformat_new_stream(oc, NULL);
+ int ret = 0;
+ const char *bsfs = NULL, *time_base = NULL;
+ char *next, *codec_tag = NULL;
+ double qscale = -1;
+ int i;
+
+ if (!st)
+ report_and_exit(AVERROR(ENOMEM));
+
+ if (oc->nb_streams - 1 < o->nb_streamid_map)
+ st->id = o->streamid_map[oc->nb_streams - 1];
+
+ ms = mux_stream_alloc(mux, type);
+ ost = &ms->ost;
+
+ ms->muxing_queue = av_fifo_alloc2(8, sizeof(AVPacket*), 0);
+ if (!ms->muxing_queue)
+ report_and_exit(AVERROR(ENOMEM));
+ ms->last_mux_dts = AV_NOPTS_VALUE;
+
+ ost->st = st;
+ ost->ist = ist;
+ ost->kf.ref_pts = AV_NOPTS_VALUE;
+ st->codecpar->codec_type = type;
+
+ ret = choose_encoder(o, oc, ost, &enc);
+ if (ret < 0) {
+ av_log(ost, AV_LOG_FATAL, "Error selecting an encoder\n");
+ exit_program(1);
+ }
+
+ if (enc) {
+ ost->enc_ctx = avcodec_alloc_context3(enc);
+ if (!ost->enc_ctx)
+ report_and_exit(AVERROR(ENOMEM));
+
+ av_strlcat(ms->log_name, "/", sizeof(ms->log_name));
+ av_strlcat(ms->log_name, enc->name, sizeof(ms->log_name));
+ } else {
+ av_strlcat(ms->log_name, "/copy", sizeof(ms->log_name));
+ }
+
+ ost->filtered_frame = av_frame_alloc();
+ if (!ost->filtered_frame)
+ report_and_exit(AVERROR(ENOMEM));
+
+ ost->pkt = av_packet_alloc();
+ if (!ost->pkt)
+ report_and_exit(AVERROR(ENOMEM));
+
+ if (ost->enc_ctx) {
+ AVCodecContext *enc = ost->enc_ctx;
+ AVIOContext *s = NULL;
+ char *buf = NULL, *arg = NULL, *preset = NULL;
+ const char *enc_stats_pre = NULL, *enc_stats_post = NULL, *mux_stats = NULL;
+
+ ost->encoder_opts = filter_codec_opts(o->g->codec_opts, enc->codec_id,
+ oc, st, enc->codec);
+
+ MATCH_PER_STREAM_OPT(presets, str, preset, oc, st);
+ ost->autoscale = 1;
+ MATCH_PER_STREAM_OPT(autoscale, i, ost->autoscale, oc, st);
+ if (preset && (!(ret = get_preset_file_2(preset, enc->codec->name, &s)))) {
+ AVBPrint bprint;
+ av_bprint_init(&bprint, 0, AV_BPRINT_SIZE_UNLIMITED);
+ do {
+ av_bprint_clear(&bprint);
+ buf = get_line(s, &bprint);
+ if (!buf[0] || buf[0] == '#')
+ continue;
+ if (!(arg = strchr(buf, '='))) {
+ av_log(ost, AV_LOG_FATAL, "Invalid line found in the preset file.\n");
+ exit_program(1);
+ }
+ *arg++ = 0;
+ av_dict_set(&ost->encoder_opts, buf, arg, AV_DICT_DONT_OVERWRITE);
+ } while (!s->eof_reached);
+ av_bprint_finalize(&bprint, NULL);
+ avio_closep(&s);
+ }
+ if (ret) {
+ av_log(ost, AV_LOG_FATAL,
+ "Preset %s specified, but could not be opened.\n", preset);
+ exit_program(1);
+ }
+
+ MATCH_PER_STREAM_OPT(enc_stats_pre, str, enc_stats_pre, oc, st);
+ if (enc_stats_pre &&
+ (type == AVMEDIA_TYPE_VIDEO || type == AVMEDIA_TYPE_AUDIO)) {
+ const char *format = "{fidx} {sidx} {n} {t}";
+
+ MATCH_PER_STREAM_OPT(enc_stats_pre_fmt, str, format, oc, st);
+
+ ret = enc_stats_init(ost, &ost->enc_stats_pre, 1, enc_stats_pre, format);
+ if (ret < 0)
+ exit_program(1);
+ }
+
+ MATCH_PER_STREAM_OPT(enc_stats_post, str, enc_stats_post, oc, st);
+ if (enc_stats_post &&
+ (type == AVMEDIA_TYPE_VIDEO || type == AVMEDIA_TYPE_AUDIO)) {
+ const char *format = "{fidx} {sidx} {n} {t}";
+
+ MATCH_PER_STREAM_OPT(enc_stats_post_fmt, str, format, oc, st);
+
+ ret = enc_stats_init(ost, &ost->enc_stats_post, 0, enc_stats_post, format);
+ if (ret < 0)
+ exit_program(1);
+ }
+
+ MATCH_PER_STREAM_OPT(mux_stats, str, mux_stats, oc, st);
+ if (mux_stats &&
+ (type == AVMEDIA_TYPE_VIDEO || type == AVMEDIA_TYPE_AUDIO)) {
+ const char *format = "{fidx} {sidx} {n} {t}";
+
+ MATCH_PER_STREAM_OPT(mux_stats_fmt, str, format, oc, st);
+
+ ret = enc_stats_init(ost, &ms->stats, 0, mux_stats, format);
+ if (ret < 0)
+ exit_program(1);
+ }
+ } else {
+ ost->encoder_opts = filter_codec_opts(o->g->codec_opts, AV_CODEC_ID_NONE, oc, st, NULL);
+ }
+
+
+ if (o->bitexact) {
+ ost->bitexact = 1;
+ } else if (ost->enc_ctx) {
+ ost->bitexact = check_opt_bitexact(ost->enc_ctx, ost->encoder_opts, "flags",
+ AV_CODEC_FLAG_BITEXACT);
+ }
+
+ MATCH_PER_STREAM_OPT(time_bases, str, time_base, oc, st);
+ if (time_base) {
+ AVRational q;
+ if (av_parse_ratio(&q, time_base, INT_MAX, 0, NULL) < 0 ||
+ q.num <= 0 || q.den <= 0) {
+ av_log(ost, AV_LOG_FATAL, "Invalid time base: %s\n", time_base);
+ exit_program(1);
+ }
+ st->time_base = q;
+ }
+
+ MATCH_PER_STREAM_OPT(enc_time_bases, str, time_base, oc, st);
+ if (time_base) {
+ AVRational q;
+ if (av_parse_ratio(&q, time_base, INT_MAX, 0, NULL) < 0 ||
+ q.den <= 0) {
+ av_log(ost, AV_LOG_FATAL, "Invalid time base: %s\n", time_base);
+ exit_program(1);
+ }
+ ost->enc_timebase = q;
+ }
+
+ ms->max_frames = INT64_MAX;
+ MATCH_PER_STREAM_OPT(max_frames, i64, ms->max_frames, oc, st);
+ for (i = 0; inb_max_frames; i++) {
+ char *p = o->max_frames[i].specifier;
+ if (!*p && type != AVMEDIA_TYPE_VIDEO) {
+ av_log(ost, AV_LOG_WARNING, "Applying unspecific -frames to non video streams, maybe you meant -vframes ?\n");
+ break;
+ }
+ }
+
+ ost->copy_prior_start = -1;
+ MATCH_PER_STREAM_OPT(copy_prior_start, i, ost->copy_prior_start, oc ,st);
+
+ MATCH_PER_STREAM_OPT(bitstream_filters, str, bsfs, oc, st);
+ if (bsfs && *bsfs) {
+ ret = av_bsf_list_parse_str(bsfs, &ms->bsf_ctx);
+ if (ret < 0) {
+ av_log(ost, AV_LOG_ERROR, "Error parsing bitstream filter sequence '%s': %s\n", bsfs, av_err2str(ret));
+ exit_program(1);
+ }
+ }
+
+ MATCH_PER_STREAM_OPT(codec_tags, str, codec_tag, oc, st);
+ if (codec_tag) {
+ uint32_t tag = strtol(codec_tag, &next, 0);
+ if (*next)
+ tag = AV_RL32(codec_tag);
+ ost->st->codecpar->codec_tag = tag;
+ if (ost->enc_ctx)
+ ost->enc_ctx->codec_tag = tag;
+ }
+
+ MATCH_PER_STREAM_OPT(qscale, dbl, qscale, oc, st);
+ if (ost->enc_ctx && qscale >= 0) {
+ ost->enc_ctx->flags |= AV_CODEC_FLAG_QSCALE;
+ ost->enc_ctx->global_quality = FF_QP2LAMBDA * qscale;
+ }
+
+ ms->max_muxing_queue_size = 128;
+ MATCH_PER_STREAM_OPT(max_muxing_queue_size, i, ms->max_muxing_queue_size, oc, st);
+
+ ms->muxing_queue_data_threshold = 50*1024*1024;
+ MATCH_PER_STREAM_OPT(muxing_queue_data_threshold, i, ms->muxing_queue_data_threshold, oc, st);
+
+ MATCH_PER_STREAM_OPT(bits_per_raw_sample, i, ost->bits_per_raw_sample,
+ oc, st);
+
+ MATCH_PER_STREAM_OPT(fix_sub_duration_heartbeat, i, ost->fix_sub_duration_heartbeat,
+ oc, st);
+
+ if (oc->oformat->flags & AVFMT_GLOBALHEADER && ost->enc_ctx)
+ ost->enc_ctx->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;
+
+ av_dict_copy(&ost->sws_dict, o->g->sws_dict, 0);
+
+ av_dict_copy(&ost->swr_opts, o->g->swr_opts, 0);
+ if (ost->enc_ctx && av_get_exact_bits_per_sample(ost->enc_ctx->codec_id) == 24)
+ av_dict_set(&ost->swr_opts, "output_sample_bits", "24", 0);
+
+ if (ost->ist) {
+ ost->ist->discard = 0;
+ ost->ist->st->discard = ost->ist->user_set_discard;
+ }
+ ost->last_mux_dts = AV_NOPTS_VALUE;
+ ost->last_filter_pts = AV_NOPTS_VALUE;
+
+ MATCH_PER_STREAM_OPT(copy_initial_nonkeyframes, i,
+ ost->copy_initial_nonkeyframes, oc, st);
+
+ return ost;
+}
+
+static char *get_ost_filters(const OptionsContext *o, AVFormatContext *oc,
+ OutputStream *ost)
+{
+ AVStream *st = ost->st;
+
+ if (ost->filters_script && ost->filters) {
+ av_log(ost, AV_LOG_ERROR, "Both -filter and -filter_script set\n");
+ exit_program(1);
+ }
+
+ if (ost->filters_script)
+ return file_read(ost->filters_script);
+ else if (ost->filters)
+ return av_strdup(ost->filters);
+
+ return av_strdup(st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO ?
+ "null" : "anull");
+}
+
+static void check_streamcopy_filters(const OptionsContext *o, AVFormatContext *oc,
+ OutputStream *ost, enum AVMediaType type)
+{
+ if (ost->filters_script || ost->filters) {
+ av_log(ost, AV_LOG_ERROR,
+ "%s '%s' was defined, but codec copy was selected.\n"
+ "Filtering and streamcopy cannot be used together.\n",
+ ost->filters ? "Filtergraph" : "Filtergraph script",
+ ost->filters ? ost->filters : ost->filters_script);
+ exit_program(1);
+ }
+}
+
+static void parse_matrix_coeffs(void *logctx, uint16_t *dest, const char *str)
+{
+ int i;
+ const char *p = str;
+ for (i = 0;; i++) {
+ dest[i] = atoi(p);
+ if (i == 63)
+ break;
+ p = strchr(p, ',');
+ if (!p) {
+ av_log(logctx, AV_LOG_FATAL,
+ "Syntax error in matrix \"%s\" at coeff %d\n", str, i);
+ exit_program(1);
+ }
+ p++;
+ }
+}
+
+static OutputStream *new_video_stream(Muxer *mux, const OptionsContext *o, InputStream *ist)
+{
+ AVFormatContext *oc = mux->fc;
+ AVStream *st;
+ OutputStream *ost;
+ char *frame_rate = NULL, *max_frame_rate = NULL, *frame_aspect_ratio = NULL;
+
+ ost = new_output_stream(mux, o, AVMEDIA_TYPE_VIDEO, ist);
+ st = ost->st;
+
+ MATCH_PER_STREAM_OPT(frame_rates, str, frame_rate, oc, st);
+ if (frame_rate && av_parse_video_rate(&ost->frame_rate, frame_rate) < 0) {
+ av_log(ost, AV_LOG_FATAL, "Invalid framerate value: %s\n", frame_rate);
+ exit_program(1);
+ }
+
+ MATCH_PER_STREAM_OPT(max_frame_rates, str, max_frame_rate, oc, st);
+ if (max_frame_rate && av_parse_video_rate(&ost->max_frame_rate, max_frame_rate) < 0) {
+ av_log(ost, AV_LOG_FATAL, "Invalid maximum framerate value: %s\n", max_frame_rate);
+ exit_program(1);
+ }
+
+ if (frame_rate && max_frame_rate) {
+ av_log(ost, AV_LOG_ERROR, "Only one of -fpsmax and -r can be set for a stream.\n");
+ exit_program(1);
+ }
+
+ MATCH_PER_STREAM_OPT(frame_aspect_ratios, str, frame_aspect_ratio, oc, st);
+ if (frame_aspect_ratio) {
+ AVRational q;
+ if (av_parse_ratio(&q, frame_aspect_ratio, 255, 0, NULL) < 0 ||
+ q.num <= 0 || q.den <= 0) {
+ av_log(ost, AV_LOG_FATAL, "Invalid aspect ratio: %s\n", frame_aspect_ratio);
+ exit_program(1);
+ }
+ ost->frame_aspect_ratio = q;
+ }
+
+ MATCH_PER_STREAM_OPT(filter_scripts, str, ost->filters_script, oc, st);
+ MATCH_PER_STREAM_OPT(filters, str, ost->filters, oc, st);
+
+ if (ost->enc_ctx) {
+ AVCodecContext *video_enc = ost->enc_ctx;
+ const char *p = NULL, *fps_mode = NULL;
+ char *frame_size = NULL;
+ char *frame_pix_fmt = NULL;
+ char *intra_matrix = NULL, *inter_matrix = NULL;
+ char *chroma_intra_matrix = NULL;
+ int do_pass = 0;
+ int i;
+
+ MATCH_PER_STREAM_OPT(frame_sizes, str, frame_size, oc, st);
+ if (frame_size && av_parse_video_size(&video_enc->width, &video_enc->height, frame_size) < 0) {
+ av_log(ost, AV_LOG_FATAL, "Invalid frame size: %s.\n", frame_size);
+ exit_program(1);
+ }
+
+ MATCH_PER_STREAM_OPT(frame_pix_fmts, str, frame_pix_fmt, oc, st);
+ if (frame_pix_fmt && *frame_pix_fmt == '+') {
+ ost->keep_pix_fmt = 1;
+ if (!*++frame_pix_fmt)
+ frame_pix_fmt = NULL;
+ }
+ if (frame_pix_fmt && (video_enc->pix_fmt = av_get_pix_fmt(frame_pix_fmt)) == AV_PIX_FMT_NONE) {
+ av_log(ost, AV_LOG_FATAL, "Unknown pixel format requested: %s.\n", frame_pix_fmt);
+ exit_program(1);
+ }
+ st->sample_aspect_ratio = video_enc->sample_aspect_ratio;
+
+ MATCH_PER_STREAM_OPT(intra_matrices, str, intra_matrix, oc, st);
+ if (intra_matrix) {
+ if (!(video_enc->intra_matrix = av_mallocz(sizeof(*video_enc->intra_matrix) * 64)))
+ report_and_exit(AVERROR(ENOMEM));
+ parse_matrix_coeffs(ost, video_enc->intra_matrix, intra_matrix);
+ }
+ MATCH_PER_STREAM_OPT(chroma_intra_matrices, str, chroma_intra_matrix, oc, st);
+ if (chroma_intra_matrix) {
+ uint16_t *p = av_mallocz(sizeof(*video_enc->chroma_intra_matrix) * 64);
+ if (!p)
+ report_and_exit(AVERROR(ENOMEM));
+ video_enc->chroma_intra_matrix = p;
+ parse_matrix_coeffs(ost, p, chroma_intra_matrix);
+ }
+ MATCH_PER_STREAM_OPT(inter_matrices, str, inter_matrix, oc, st);
+ if (inter_matrix) {
+ if (!(video_enc->inter_matrix = av_mallocz(sizeof(*video_enc->inter_matrix) * 64)))
+ report_and_exit(AVERROR(ENOMEM));
+ parse_matrix_coeffs(ost, video_enc->inter_matrix, inter_matrix);
+ }
+
+ MATCH_PER_STREAM_OPT(rc_overrides, str, p, oc, st);
+ for (i = 0; p; i++) {
+ int start, end, q;
+ int e = sscanf(p, "%d,%d,%d", &start, &end, &q);
+ if (e != 3) {
+ av_log(ost, AV_LOG_FATAL, "error parsing rc_override\n");
+ exit_program(1);
+ }
+ video_enc->rc_override =
+ av_realloc_array(video_enc->rc_override,
+ i + 1, sizeof(RcOverride));
+ if (!video_enc->rc_override) {
+ av_log(ost, AV_LOG_FATAL, "Could not (re)allocate memory for rc_override.\n");
+ exit_program(1);
+ }
+ video_enc->rc_override[i].start_frame = start;
+ video_enc->rc_override[i].end_frame = end;
+ if (q > 0) {
+ video_enc->rc_override[i].qscale = q;
+ video_enc->rc_override[i].quality_factor = 1.0;
+ }
+ else {
+ video_enc->rc_override[i].qscale = 0;
+ video_enc->rc_override[i].quality_factor = -q/100.0;
+ }
+ p = strchr(p, '/');
+ if (p) p++;
+ }
+ video_enc->rc_override_count = i;
+
+#if FFMPEG_OPT_PSNR
+ if (do_psnr) {
+ av_log(ost, AV_LOG_WARNING, "The -psnr option is deprecated, use -flags +psnr\n");
+ video_enc->flags|= AV_CODEC_FLAG_PSNR;
+ }
+#endif
+
+ /* two pass mode */
+ MATCH_PER_STREAM_OPT(pass, i, do_pass, oc, st);
+ if (do_pass) {
+ if (do_pass & 1) {
+ video_enc->flags |= AV_CODEC_FLAG_PASS1;
+ av_dict_set(&ost->encoder_opts, "flags", "+pass1", AV_DICT_APPEND);
+ }
+ if (do_pass & 2) {
+ video_enc->flags |= AV_CODEC_FLAG_PASS2;
+ av_dict_set(&ost->encoder_opts, "flags", "+pass2", AV_DICT_APPEND);
+ }
+ }
+
+ MATCH_PER_STREAM_OPT(passlogfiles, str, ost->logfile_prefix, oc, st);
+ if (ost->logfile_prefix &&
+ !(ost->logfile_prefix = av_strdup(ost->logfile_prefix)))
+ report_and_exit(AVERROR(ENOMEM));
+
+ if (do_pass) {
+ int ost_idx = -1;
+ char logfilename[1024];
+ FILE *f;
+
+ /* compute this stream's global index */
+ for (int i = 0; i <= ost->file_index; i++)
+ ost_idx += output_files[i]->nb_streams;
+
+ snprintf(logfilename, sizeof(logfilename), "%s-%d.log",
+ ost->logfile_prefix ? ost->logfile_prefix :
+ DEFAULT_PASS_LOGFILENAME_PREFIX,
+ ost_idx);
+ if (!strcmp(ost->enc_ctx->codec->name, "libx264")) {
+ av_dict_set(&ost->encoder_opts, "stats", logfilename, AV_DICT_DONT_OVERWRITE);
+ } else {
+ if (video_enc->flags & AV_CODEC_FLAG_PASS2) {
+ char *logbuffer = file_read(logfilename);
+
+ if (!logbuffer) {
+ av_log(ost, AV_LOG_FATAL, "Error reading log file '%s' for pass-2 encoding\n",
+ logfilename);
+ exit_program(1);
+ }
+ video_enc->stats_in = logbuffer;
+ }
+ if (video_enc->flags & AV_CODEC_FLAG_PASS1) {
+ f = fopen_utf8(logfilename, "wb");
+ if (!f) {
+ av_log(ost, AV_LOG_FATAL,
+ "Cannot write log file '%s' for pass-1 encoding: %s\n",
+ logfilename, strerror(errno));
+ exit_program(1);
+ }
+ ost->logfile = f;
+ }
+ }
+ }
+
+ MATCH_PER_STREAM_OPT(force_fps, i, ost->force_fps, oc, st);
+
+ ost->top_field_first = -1;
+ MATCH_PER_STREAM_OPT(top_field_first, i, ost->top_field_first, oc, st);
+
+ ost->vsync_method = video_sync_method;
+ MATCH_PER_STREAM_OPT(fps_mode, str, fps_mode, oc, st);
+ if (fps_mode)
+ parse_and_set_vsync(fps_mode, &ost->vsync_method, ost->file_index, ost->index, 0);
+
+ if ((ost->frame_rate.num || ost->max_frame_rate.num) &&
+ !(ost->vsync_method == VSYNC_AUTO ||
+ ost->vsync_method == VSYNC_CFR || ost->vsync_method == VSYNC_VSCFR)) {
+ av_log(ost, AV_LOG_FATAL, "One of -r/-fpsmax was specified "
+ "together a non-CFR -vsync/-fps_mode. This is contradictory.\n");
+ exit_program(1);
+ }
+
+ if (ost->vsync_method == VSYNC_AUTO) {
+ if (ost->frame_rate.num || ost->max_frame_rate.num) {
+ ost->vsync_method = VSYNC_CFR;
+ } else if (!strcmp(oc->oformat->name, "avi")) {
+ ost->vsync_method = VSYNC_VFR;
+ } else {
+ ost->vsync_method = (oc->oformat->flags & AVFMT_VARIABLE_FPS) ?
+ ((oc->oformat->flags & AVFMT_NOTIMESTAMPS) ?
+ VSYNC_PASSTHROUGH : VSYNC_VFR) :
+ VSYNC_CFR;
+ }
+
+ if (ost->ist && ost->vsync_method == VSYNC_CFR) {
+ const InputFile *ifile = input_files[ost->ist->file_index];
+
+ if (ifile->nb_streams == 1 && ifile->input_ts_offset == 0)
+ ost->vsync_method = VSYNC_VSCFR;
+ }
+
+ if (ost->vsync_method == VSYNC_CFR && copy_ts) {
+ ost->vsync_method = VSYNC_VSCFR;
+ }
+ }
+ ost->is_cfr = (ost->vsync_method == VSYNC_CFR || ost->vsync_method == VSYNC_VSCFR);
+
+ ost->avfilter = get_ost_filters(o, oc, ost);
+ if (!ost->avfilter)
+ exit_program(1);
+
+ ost->last_frame = av_frame_alloc();
+ if (!ost->last_frame)
+ report_and_exit(AVERROR(ENOMEM));
+ } else
+ check_streamcopy_filters(o, oc, ost, AVMEDIA_TYPE_VIDEO);
+
+ return ost;
+}
+
+static OutputStream *new_audio_stream(Muxer *mux, const OptionsContext *o, InputStream *ist)
+{
+ AVFormatContext *oc = mux->fc;
+ AVStream *st;
+ OutputStream *ost;
+
+ ost = new_output_stream(mux, o, AVMEDIA_TYPE_AUDIO, ist);
+ st = ost->st;
+
+
+ MATCH_PER_STREAM_OPT(filter_scripts, str, ost->filters_script, oc, st);
+ MATCH_PER_STREAM_OPT(filters, str, ost->filters, oc, st);
+
+ if (ost->enc_ctx) {
+ AVCodecContext *audio_enc = ost->enc_ctx;
+ int channels = 0;
+ char *layout = NULL;
+ char *sample_fmt = NULL;
+
+ MATCH_PER_STREAM_OPT(audio_channels, i, channels, oc, st);
+ if (channels) {
+ audio_enc->ch_layout.order = AV_CHANNEL_ORDER_UNSPEC;
+ audio_enc->ch_layout.nb_channels = channels;
+ }
+
+ MATCH_PER_STREAM_OPT(audio_ch_layouts, str, layout, oc, st);
+ if (layout) {
+ if (av_channel_layout_from_string(&audio_enc->ch_layout, layout) < 0) {
+#if FF_API_OLD_CHANNEL_LAYOUT
+ uint64_t mask;
+ AV_NOWARN_DEPRECATED({
+ mask = av_get_channel_layout(layout);
+ })
+ if (!mask) {
+#endif
+ av_log(ost, AV_LOG_FATAL, "Unknown channel layout: %s\n", layout);
+ exit_program(1);
+#if FF_API_OLD_CHANNEL_LAYOUT
+ }
+ av_log(ost, AV_LOG_WARNING, "Channel layout '%s' uses a deprecated syntax.\n",
+ layout);
+ av_channel_layout_from_mask(&audio_enc->ch_layout, mask);
+#endif
+ }
+ }
+
+ MATCH_PER_STREAM_OPT(sample_fmts, str, sample_fmt, oc, st);
+ if (sample_fmt &&
+ (audio_enc->sample_fmt = av_get_sample_fmt(sample_fmt)) == AV_SAMPLE_FMT_NONE) {
+ av_log(ost, AV_LOG_FATAL, "Invalid sample format '%s'\n", sample_fmt);
+ exit_program(1);
+ }
+
+ MATCH_PER_STREAM_OPT(audio_sample_rate, i, audio_enc->sample_rate, oc, st);
+
+ MATCH_PER_STREAM_OPT(apad, str, ost->apad, oc, st);
+ ost->apad = av_strdup(ost->apad);
+
+ ost->avfilter = get_ost_filters(o, oc, ost);
+ if (!ost->avfilter)
+ exit_program(1);
+
+#if FFMPEG_OPT_MAP_CHANNEL
+ /* check for channel mapping for this audio stream */
+ for (int n = 0; n < o->nb_audio_channel_maps; n++) {
+ AudioChannelMap *map = &o->audio_channel_maps[n];
+ if ((map->ofile_idx == -1 || ost->file_index == map->ofile_idx) &&
+ (map->ostream_idx == -1 || ost->st->index == map->ostream_idx)) {
+ InputStream *ist;
+
+ if (map->channel_idx == -1) {
+ ist = NULL;
+ } else if (!ost->ist) {
+ av_log(ost, AV_LOG_FATAL, "Cannot determine input stream for channel mapping %d.%d\n",
+ ost->file_index, ost->st->index);
+ continue;
+ } else {
+ ist = ost->ist;
+ }
+
+ if (!ist || (ist->file_index == map->file_idx && ist->st->index == map->stream_idx)) {
+ if (av_reallocp_array(&ost->audio_channels_map,
+ ost->audio_channels_mapped + 1,
+ sizeof(*ost->audio_channels_map)
+ ) < 0 )
+ report_and_exit(AVERROR(ENOMEM));
+
+ ost->audio_channels_map[ost->audio_channels_mapped++] = map->channel_idx;
+ }
+ }
+ }
+#endif
+ } else
+ check_streamcopy_filters(o, oc, ost, AVMEDIA_TYPE_AUDIO);
+
+ return ost;
+}
+
+static OutputStream *new_data_stream(Muxer *mux, const OptionsContext *o, InputStream *ist)
+{
+ OutputStream *ost;
+
+ ost = new_output_stream(mux, o, AVMEDIA_TYPE_DATA, ist);
+ if (ost->enc_ctx) {
+ av_log(ost, AV_LOG_FATAL, "Data stream encoding not supported yet (only streamcopy)\n");
+ exit_program(1);
+ }
+
+ return ost;
+}
+
+static OutputStream *new_unknown_stream(Muxer *mux, const OptionsContext *o, InputStream *ist)
+{
+ OutputStream *ost;
+
+ ost = new_output_stream(mux, o, AVMEDIA_TYPE_UNKNOWN, ist);
+ if (ost->enc_ctx) {
+ av_log(ost, AV_LOG_FATAL, "Unknown stream encoding not supported yet (only streamcopy)\n");
+ exit_program(1);
+ }
+
+ return ost;
+}
+
+static OutputStream *new_attachment_stream(Muxer *mux, const OptionsContext *o, InputStream *ist)
+{
+ OutputStream *ost = new_output_stream(mux, o, AVMEDIA_TYPE_ATTACHMENT, ist);
+ ost->finished = 1;
+ return ost;
+}
+
+static OutputStream *new_subtitle_stream(Muxer *mux, const OptionsContext *o, InputStream *ist)
+{
+ AVStream *st;
+ OutputStream *ost;
+
+ ost = new_output_stream(mux, o, AVMEDIA_TYPE_SUBTITLE, ist);
+ st = ost->st;
+
+ if (ost->enc_ctx) {
+ AVCodecContext *subtitle_enc = ost->enc_ctx;
+ char *frame_size = NULL;
+
+ MATCH_PER_STREAM_OPT(frame_sizes, str, frame_size, mux->fc, st);
+ if (frame_size && av_parse_video_size(&subtitle_enc->width, &subtitle_enc->height, frame_size) < 0) {
+ av_log(ost, AV_LOG_FATAL, "Invalid frame size: %s.\n", frame_size);
+ exit_program(1);
+ }
+ }
+
+ return ost;
+}
+
+static void init_output_filter(OutputFilter *ofilter, const OptionsContext *o,
+ Muxer *mux)
+{
+ OutputStream *ost;
+
+ switch (ofilter->type) {
+ case AVMEDIA_TYPE_VIDEO: ost = new_video_stream(mux, o, NULL); break;
+ case AVMEDIA_TYPE_AUDIO: ost = new_audio_stream(mux, o, NULL); break;
+ default:
+ av_log(mux, AV_LOG_FATAL, "Only video and audio filters are supported "
+ "currently.\n");
+ exit_program(1);
+ }
+
+ ost->filter = ofilter;
+
+ ofilter->ost = ost;
+ ofilter->format = -1;
+
+ if (!ost->enc_ctx) {
+ av_log(ost, AV_LOG_ERROR, "Streamcopy requested for output stream fed "
+ "from a complex filtergraph. Filtering and streamcopy "
+ "cannot be used together.\n");
+ exit_program(1);
+ }
+
+ if (ost->avfilter && (ost->filters || ost->filters_script)) {
+ const char *opt = ost->filters ? "-vf/-af/-filter" : "-filter_script";
+ av_log(ost, AV_LOG_ERROR,
+ "%s '%s' was specified through the %s option "
+ "for output stream %d:%d, which is fed from a complex filtergraph.\n"
+ "%s and -filter_complex cannot be used together for the same stream.\n",
+ ost->filters ? "Filtergraph" : "Filtergraph script",
+ ost->filters ? ost->filters : ost->filters_script,
+ opt, ost->file_index, ost->index, opt);
+ exit_program(1);
+ }
+
+ avfilter_inout_free(&ofilter->out_tmp);
+}
+
+static void map_auto_video(Muxer *mux, const OptionsContext *o)
+{
+ AVFormatContext *oc = mux->fc;
+ InputStream *best_ist = NULL;
+ int best_score = 0;
+ int qcr;
+
+ /* video: highest resolution */
+ if (av_guess_codec(oc->oformat, NULL, oc->url, NULL, AVMEDIA_TYPE_VIDEO) == AV_CODEC_ID_NONE)
+ return;
+
+ qcr = avformat_query_codec(oc->oformat, oc->oformat->video_codec, 0);
+ for (int j = 0; j < nb_input_files; j++) {
+ InputFile *ifile = input_files[j];
+ InputStream *file_best_ist = NULL;
+ int file_best_score = 0;
+ for (int i = 0; i < ifile->nb_streams; i++) {
+ InputStream *ist = ifile->streams[i];
+ int score;
+
+ if (ist->user_set_discard == AVDISCARD_ALL ||
+ ist->st->codecpar->codec_type != AVMEDIA_TYPE_VIDEO)
+ continue;
+
+ score = ist->st->codecpar->width * ist->st->codecpar->height
+ + 100000000 * !!(ist->st->event_flags & AVSTREAM_EVENT_FLAG_NEW_PACKETS)
+ + 5000000*!!(ist->st->disposition & AV_DISPOSITION_DEFAULT);
+ if((qcr!=MKTAG('A', 'P', 'I', 'C')) && (ist->st->disposition & AV_DISPOSITION_ATTACHED_PIC))
+ score = 1;
+
+ if (score > file_best_score) {
+ if((qcr==MKTAG('A', 'P', 'I', 'C')) && !(ist->st->disposition & AV_DISPOSITION_ATTACHED_PIC))
+ continue;
+ file_best_score = score;
+ file_best_ist = ist;
+ }
+ }
+ if (file_best_ist) {
+ if((qcr == MKTAG('A', 'P', 'I', 'C')) ||
+ !(file_best_ist->st->disposition & AV_DISPOSITION_ATTACHED_PIC))
+ file_best_score -= 5000000*!!(file_best_ist->st->disposition & AV_DISPOSITION_DEFAULT);
+ if (file_best_score > best_score) {
+ best_score = file_best_score;
+ best_ist = file_best_ist;
+ }
+ }
+ }
+ if (best_ist)
+ new_video_stream(mux, o, best_ist);
+}
+
+static void map_auto_audio(Muxer *mux, const OptionsContext *o)
+{
+ AVFormatContext *oc = mux->fc;
+ InputStream *best_ist = NULL;
+ int best_score = 0;
+
+ /* audio: most channels */
+ if (av_guess_codec(oc->oformat, NULL, oc->url, NULL, AVMEDIA_TYPE_AUDIO) == AV_CODEC_ID_NONE)
+ return;
+
+ for (int j = 0; j < nb_input_files; j++) {
+ InputFile *ifile = input_files[j];
+ InputStream *file_best_ist = NULL;
+ int file_best_score = 0;
+ for (int i = 0; i < ifile->nb_streams; i++) {
+ InputStream *ist = ifile->streams[i];
+ int score;
+
+ if (ist->user_set_discard == AVDISCARD_ALL ||
+ ist->st->codecpar->codec_type != AVMEDIA_TYPE_AUDIO)
+ continue;
+
+ score = ist->st->codecpar->ch_layout.nb_channels
+ + 100000000 * !!(ist->st->event_flags & AVSTREAM_EVENT_FLAG_NEW_PACKETS)
+ + 5000000*!!(ist->st->disposition & AV_DISPOSITION_DEFAULT);
+ if (score > file_best_score) {
+ file_best_score = score;
+ file_best_ist = ist;
+ }
+ }
+ if (file_best_ist) {
+ file_best_score -= 5000000*!!(file_best_ist->st->disposition & AV_DISPOSITION_DEFAULT);
+ if (file_best_score > best_score) {
+ best_score = file_best_score;
+ best_ist = file_best_ist;
+ }
+ }
+ }
+ if (best_ist)
+ new_audio_stream(mux, o, best_ist);
+}
+
+static void map_auto_subtitle(Muxer *mux, const OptionsContext *o)
+{
+ AVFormatContext *oc = mux->fc;
+ char *subtitle_codec_name = NULL;
+
+ /* subtitles: pick first */
+ MATCH_PER_TYPE_OPT(codec_names, str, subtitle_codec_name, oc, "s");
+ if (!avcodec_find_encoder(oc->oformat->subtitle_codec) && !subtitle_codec_name)
+ return;
+
+ for (InputStream *ist = ist_iter(NULL); ist; ist = ist_iter(ist))
+ if (ist->st->codecpar->codec_type == AVMEDIA_TYPE_SUBTITLE) {
+ AVCodecDescriptor const *input_descriptor =
+ avcodec_descriptor_get(ist->st->codecpar->codec_id);
+ AVCodecDescriptor const *output_descriptor = NULL;
+ AVCodec const *output_codec =
+ avcodec_find_encoder(oc->oformat->subtitle_codec);
+ int input_props = 0, output_props = 0;
+ if (ist->user_set_discard == AVDISCARD_ALL)
+ continue;
+ if (output_codec)
+ output_descriptor = avcodec_descriptor_get(output_codec->id);
+ if (input_descriptor)
+ input_props = input_descriptor->props & (AV_CODEC_PROP_TEXT_SUB | AV_CODEC_PROP_BITMAP_SUB);
+ if (output_descriptor)
+ output_props = output_descriptor->props & (AV_CODEC_PROP_TEXT_SUB | AV_CODEC_PROP_BITMAP_SUB);
+ if (subtitle_codec_name ||
+ input_props & output_props ||
+ // Map dvb teletext which has neither property to any output subtitle encoder
+ input_descriptor && output_descriptor &&
+ (!input_descriptor->props ||
+ !output_descriptor->props)) {
+ new_subtitle_stream(mux, o, ist);
+ break;
+ }
+ }
+}
+
+static void map_auto_data(Muxer *mux, const OptionsContext *o)
+{
+ AVFormatContext *oc = mux->fc;
+ /* Data only if codec id match */
+ enum AVCodecID codec_id = av_guess_codec(oc->oformat, NULL, oc->url, NULL, AVMEDIA_TYPE_DATA);
+
+ if (codec_id == AV_CODEC_ID_NONE)
+ return;
+
+ for (InputStream *ist = ist_iter(NULL); ist; ist = ist_iter(ist)) {
+ if (ist->user_set_discard == AVDISCARD_ALL)
+ continue;
+ if (ist->st->codecpar->codec_type == AVMEDIA_TYPE_DATA &&
+ ist->st->codecpar->codec_id == codec_id )
+ new_data_stream(mux, o, ist);
+ }
+}
+
+static void map_manual(Muxer *mux, const OptionsContext *o, const StreamMap *map)
+{
+ InputStream *ist;
+
+ if (map->disabled)
+ return;
+
+ if (map->linklabel) {
+ FilterGraph *fg;
+ OutputFilter *ofilter = NULL;
+ int j, k;
+
+ for (j = 0; j < nb_filtergraphs; j++) {
+ fg = filtergraphs[j];
+ for (k = 0; k < fg->nb_outputs; k++) {
+ AVFilterInOut *out = fg->outputs[k]->out_tmp;
+ if (out && !strcmp(out->name, map->linklabel)) {
+ ofilter = fg->outputs[k];
+ goto loop_end;
+ }
+ }
+ }
+loop_end:
+ if (!ofilter) {
+ av_log(mux, AV_LOG_FATAL, "Output with label '%s' does not exist "
+ "in any defined filter graph, or was already used elsewhere.\n", map->linklabel);
+ exit_program(1);
+ }
+ init_output_filter(ofilter, o, mux);
+ } else {
+ ist = input_files[map->file_index]->streams[map->stream_index];
+ if (ist->user_set_discard == AVDISCARD_ALL) {
+ av_log(mux, AV_LOG_FATAL, "Stream #%d:%d is disabled and cannot be mapped.\n",
+ map->file_index, map->stream_index);
+ exit_program(1);
+ }
+ if(o->subtitle_disable && ist->st->codecpar->codec_type == AVMEDIA_TYPE_SUBTITLE)
+ return;
+ if(o-> audio_disable && ist->st->codecpar->codec_type == AVMEDIA_TYPE_AUDIO)
+ return;
+ if(o-> video_disable && ist->st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO)
+ return;
+ if(o-> data_disable && ist->st->codecpar->codec_type == AVMEDIA_TYPE_DATA)
+ return;
+
+ switch (ist->st->codecpar->codec_type) {
+ case AVMEDIA_TYPE_VIDEO: new_video_stream (mux, o, ist); break;
+ case AVMEDIA_TYPE_AUDIO: new_audio_stream (mux, o, ist); break;
+ case AVMEDIA_TYPE_SUBTITLE: new_subtitle_stream (mux, o, ist); break;
+ case AVMEDIA_TYPE_DATA: new_data_stream (mux, o, ist); break;
+ case AVMEDIA_TYPE_ATTACHMENT: new_attachment_stream(mux, o, ist); break;
+ case AVMEDIA_TYPE_UNKNOWN:
+ if (copy_unknown_streams) {
+ new_unknown_stream (mux, o, ist);
+ break;
+ }
+ default:
+ av_log(mux, ignore_unknown_streams ? AV_LOG_WARNING : AV_LOG_FATAL,
+ "Cannot map stream #%d:%d - unsupported type.\n",
+ map->file_index, map->stream_index);
+ if (!ignore_unknown_streams) {
+ av_log(mux, AV_LOG_FATAL,
+ "If you want unsupported types ignored instead "
+ "of failing, please use the -ignore_unknown option\n"
+ "If you want them copied, please use -copy_unknown\n");
+ exit_program(1);
+ }
+ }
+ }
+}
+
+static void of_add_attachments(Muxer *mux, const OptionsContext *o)
+{
+ OutputStream *ost;
+ int err;
+
+ for (int i = 0; i < o->nb_attachments; i++) {
+ AVIOContext *pb;
+ uint8_t *attachment;
+ const char *p;
+ int64_t len;
+
+ if ((err = avio_open2(&pb, o->attachments[i], AVIO_FLAG_READ, &int_cb, NULL)) < 0) {
+ av_log(mux, AV_LOG_FATAL, "Could not open attachment file %s.\n",
+ o->attachments[i]);
+ exit_program(1);
+ }
+ if ((len = avio_size(pb)) <= 0) {
+ av_log(mux, AV_LOG_FATAL, "Could not get size of the attachment %s.\n",
+ o->attachments[i]);
+ exit_program(1);
+ }
+ if (len > INT_MAX - AV_INPUT_BUFFER_PADDING_SIZE ||
+ !(attachment = av_malloc(len + AV_INPUT_BUFFER_PADDING_SIZE))) {
+ av_log(mux, AV_LOG_FATAL, "Attachment %s too large.\n",
+ o->attachments[i]);
+ exit_program(1);
+ }
+ avio_read(pb, attachment, len);
+ memset(attachment + len, 0, AV_INPUT_BUFFER_PADDING_SIZE);
+
+ ost = new_attachment_stream(mux, o, NULL);
+ ost->attachment_filename = o->attachments[i];
+ ost->st->codecpar->extradata = attachment;
+ ost->st->codecpar->extradata_size = len;
+
+ p = strrchr(o->attachments[i], '/');
+ av_dict_set(&ost->st->metadata, "filename", (p && *p) ? p + 1 : o->attachments[i], AV_DICT_DONT_OVERWRITE);
+ avio_closep(&pb);
+ }
+}
+
+static void create_streams(Muxer *mux, const OptionsContext *o)
+{
+ AVFormatContext *oc = mux->fc;
+ int auto_disable_v = o->video_disable;
+ int auto_disable_a = o->audio_disable;
+ int auto_disable_s = o->subtitle_disable;
+ int auto_disable_d = o->data_disable;
+
+ /* create streams for all unlabeled output pads */
+ for (int i = 0; i < nb_filtergraphs; i++) {
+ FilterGraph *fg = filtergraphs[i];
+ for (int j = 0; j < fg->nb_outputs; j++) {
+ OutputFilter *ofilter = fg->outputs[j];
+
+ if (!ofilter->out_tmp || ofilter->out_tmp->name)
+ continue;
+
+ switch (ofilter->type) {
+ case AVMEDIA_TYPE_VIDEO: auto_disable_v = 1; break;
+ case AVMEDIA_TYPE_AUDIO: auto_disable_a = 1; break;
+ case AVMEDIA_TYPE_SUBTITLE: auto_disable_s = 1; break;
+ }
+ init_output_filter(ofilter, o, mux);
+ }
+ }
+
+ if (!o->nb_stream_maps) {
+ /* pick the "best" stream of each type */
+ if (!auto_disable_v)
+ map_auto_video(mux, o);
+ if (!auto_disable_a)
+ map_auto_audio(mux, o);
+ if (!auto_disable_s)
+ map_auto_subtitle(mux, o);
+ if (!auto_disable_d)
+ map_auto_data(mux, o);
+ } else {
+ for (int i = 0; i < o->nb_stream_maps; i++)
+ map_manual(mux, o, &o->stream_maps[i]);
+ }
+
+ of_add_attachments(mux, o);
+
+ if (!oc->nb_streams && !(oc->oformat->flags & AVFMT_NOSTREAMS)) {
+ av_dump_format(oc, nb_output_files - 1, oc->url, 1);
+ av_log(mux, AV_LOG_ERROR, "Output file does not contain any stream\n");
+ exit_program(1);
+ }
+}
+
+static int setup_sync_queues(Muxer *mux, AVFormatContext *oc, int64_t buf_size_us)
+{
+ OutputFile *of = &mux->of;
+ int nb_av_enc = 0, nb_interleaved = 0;
+ int limit_frames = 0, limit_frames_av_enc = 0;
+
+#define IS_AV_ENC(ost, type) \
+ (ost->enc_ctx && (type == AVMEDIA_TYPE_VIDEO || type == AVMEDIA_TYPE_AUDIO))
+#define IS_INTERLEAVED(type) (type != AVMEDIA_TYPE_ATTACHMENT)
+
+ for (int i = 0; i < oc->nb_streams; i++) {
+ OutputStream *ost = of->streams[i];
+ MuxStream *ms = ms_from_ost(ost);
+ enum AVMediaType type = ost->st->codecpar->codec_type;
+
+ ost->sq_idx_encode = -1;
+ ost->sq_idx_mux = -1;
+
+ nb_interleaved += IS_INTERLEAVED(type);
+ nb_av_enc += IS_AV_ENC(ost, type);
+
+ limit_frames |= ms->max_frames < INT64_MAX;
+ limit_frames_av_enc |= (ms->max_frames < INT64_MAX) && IS_AV_ENC(ost, type);
+ }
+
+ if (!((nb_interleaved > 1 && of->shortest) ||
+ (nb_interleaved > 0 && limit_frames)))
+ return 0;
+
+ /* if we have more than one encoded audio/video streams, or at least
+ * one encoded audio/video stream is frame-limited, then we
+ * synchronize them before encoding */
+ if ((of->shortest && nb_av_enc > 1) || limit_frames_av_enc) {
+ of->sq_encode = sq_alloc(SYNC_QUEUE_FRAMES, buf_size_us);
+ if (!of->sq_encode)
+ return AVERROR(ENOMEM);
+
+ for (int i = 0; i < oc->nb_streams; i++) {
+ OutputStream *ost = of->streams[i];
+ MuxStream *ms = ms_from_ost(ost);
+ enum AVMediaType type = ost->st->codecpar->codec_type;
+
+ if (!IS_AV_ENC(ost, type))
+ continue;
+
+ ost->sq_idx_encode = sq_add_stream(of->sq_encode,
+ of->shortest || ms->max_frames < INT64_MAX);
+ if (ost->sq_idx_encode < 0)
+ return ost->sq_idx_encode;
+
+ ost->sq_frame = av_frame_alloc();
+ if (!ost->sq_frame)
+ return AVERROR(ENOMEM);
+
+ if (ms->max_frames != INT64_MAX)
+ sq_limit_frames(of->sq_encode, ost->sq_idx_encode, ms->max_frames);
+ }
+ }
+
+ /* if there are any additional interleaved streams, then ALL the streams
+ * are also synchronized before sending them to the muxer */
+ if (nb_interleaved > nb_av_enc) {
+ mux->sq_mux = sq_alloc(SYNC_QUEUE_PACKETS, buf_size_us);
+ if (!mux->sq_mux)
+ return AVERROR(ENOMEM);
+
+ mux->sq_pkt = av_packet_alloc();
+ if (!mux->sq_pkt)
+ return AVERROR(ENOMEM);
+
+ for (int i = 0; i < oc->nb_streams; i++) {
+ OutputStream *ost = of->streams[i];
+ MuxStream *ms = ms_from_ost(ost);
+ enum AVMediaType type = ost->st->codecpar->codec_type;
+
+ if (!IS_INTERLEAVED(type))
+ continue;
+
+ ost->sq_idx_mux = sq_add_stream(mux->sq_mux,
+ of->shortest || ms->max_frames < INT64_MAX);
+ if (ost->sq_idx_mux < 0)
+ return ost->sq_idx_mux;
+
+ if (ms->max_frames != INT64_MAX)
+ sq_limit_frames(mux->sq_mux, ost->sq_idx_mux, ms->max_frames);
+ }
+ }
+
+#undef IS_AV_ENC
+#undef IS_INTERLEAVED
+
+ return 0;
+}
+
+static void of_add_programs(Muxer *mux, const OptionsContext *o)
+{
+ AVFormatContext *oc = mux->fc;
+ /* process manually set programs */
+ for (int i = 0; i < o->nb_program; i++) {
+ const char *p = o->program[i].u.str;
+ int progid = i+1;
+ AVProgram *program;
+
+ while(*p) {
+ const char *p2 = av_get_token(&p, ":");
+ const char *to_dealloc = p2;
+ char *key;
+ if (!p2)
+ break;
+
+ if(*p) p++;
+
+ key = av_get_token(&p2, "=");
+ if (!key || !*p2) {
+ av_freep(&to_dealloc);
+ av_freep(&key);
+ break;
+ }
+ p2++;
+
+ if (!strcmp(key, "program_num"))
+ progid = strtol(p2, NULL, 0);
+ av_freep(&to_dealloc);
+ av_freep(&key);
+ }
+
+ program = av_new_program(oc, progid);
+ if (!program)
+ report_and_exit(AVERROR(ENOMEM));
+
+ p = o->program[i].u.str;
+ while(*p) {
+ const char *p2 = av_get_token(&p, ":");
+ const char *to_dealloc = p2;
+ char *key;
+ if (!p2)
+ break;
+ if(*p) p++;
+
+ key = av_get_token(&p2, "=");
+ if (!key) {
+ av_log(mux, AV_LOG_FATAL,
+ "No '=' character in program string %s.\n",
+ p2);
+ exit_program(1);
+ }
+ if (!*p2)
+ exit_program(1);
+ p2++;
+
+ if (!strcmp(key, "title")) {
+ av_dict_set(&program->metadata, "title", p2, 0);
+ } else if (!strcmp(key, "program_num")) {
+ } else if (!strcmp(key, "st")) {
+ int st_num = strtol(p2, NULL, 0);
+ av_program_add_stream_index(oc, progid, st_num);
+ } else {
+ av_log(mux, AV_LOG_FATAL, "Unknown program key %s.\n", key);
+ exit_program(1);
+ }
+ av_freep(&to_dealloc);
+ av_freep(&key);
+ }
+ }
+}
+
+/**
+ * Parse a metadata specifier passed as 'arg' parameter.
+ * @param arg metadata string to parse
+ * @param type metadata type is written here -- g(lobal)/s(tream)/c(hapter)/p(rogram)
+ * @param index for type c/p, chapter/program index is written here
+ * @param stream_spec for type s, the stream specifier is written here
+ */
+static void parse_meta_type(void *logctx, const char *arg,
+ char *type, int *index, const char **stream_spec)
+{
+ if (*arg) {
+ *type = *arg;
+ switch (*arg) {
+ case 'g':
+ break;
+ case 's':
+ if (*(++arg) && *arg != ':') {
+ av_log(logctx, AV_LOG_FATAL, "Invalid metadata specifier %s.\n", arg);
+ exit_program(1);
+ }
+ *stream_spec = *arg == ':' ? arg + 1 : "";
+ break;
+ case 'c':
+ case 'p':
+ if (*(++arg) == ':')
+ *index = strtol(++arg, NULL, 0);
+ break;
+ default:
+ av_log(logctx, AV_LOG_FATAL, "Invalid metadata type %c.\n", *arg);
+ exit_program(1);
+ }
+ } else
+ *type = 'g';
+}
+
+static void of_add_metadata(OutputFile *of, AVFormatContext *oc,
+ const OptionsContext *o)
+{
+ for (int i = 0; i < o->nb_metadata; i++) {
+ AVDictionary **m;
+ char type, *val;
+ const char *stream_spec;
+ int index = 0, ret = 0;
+
+ val = strchr(o->metadata[i].u.str, '=');
+ if (!val) {
+ av_log(of, AV_LOG_FATAL, "No '=' character in metadata string %s.\n",
+ o->metadata[i].u.str);
+ exit_program(1);
+ }
+ *val++ = 0;
+
+ parse_meta_type(of, o->metadata[i].specifier, &type, &index, &stream_spec);
+ if (type == 's') {
+ for (int j = 0; j < oc->nb_streams; j++) {
+ OutputStream *ost = of->streams[j];
+ if ((ret = check_stream_specifier(oc, oc->streams[j], stream_spec)) > 0) {
+#if FFMPEG_ROTATION_METADATA
+ if (!strcmp(o->metadata[i].u.str, "rotate")) {
+ char *tail;
+ double theta = av_strtod(val, &tail);
+ if (!*tail) {
+ ost->rotate_overridden = 1;
+ ost->rotate_override_value = theta;
+ }
+
+ av_log(ost, AV_LOG_WARNING,
+ "Conversion of a 'rotate' metadata key to a "
+ "proper display matrix rotation is deprecated. "
+ "See -display_rotation for setting rotation "
+ "instead.");
+ } else {
+#endif
+ av_dict_set(&oc->streams[j]->metadata, o->metadata[i].u.str, *val ? val : NULL, 0);
+#if FFMPEG_ROTATION_METADATA
+ }
+#endif
+ } else if (ret < 0)
+ exit_program(1);
+ }
+ } else {
+ switch (type) {
+ case 'g':
+ m = &oc->metadata;
+ break;
+ case 'c':
+ if (index < 0 || index >= oc->nb_chapters) {
+ av_log(of, AV_LOG_FATAL, "Invalid chapter index %d in metadata specifier.\n", index);
+ exit_program(1);
+ }
+ m = &oc->chapters[index]->metadata;
+ break;
+ case 'p':
+ if (index < 0 || index >= oc->nb_programs) {
+ av_log(of, AV_LOG_FATAL, "Invalid program index %d in metadata specifier.\n", index);
+ exit_program(1);
+ }
+ m = &oc->programs[index]->metadata;
+ break;
+ default:
+ av_log(of, AV_LOG_FATAL, "Invalid metadata specifier %s.\n", o->metadata[i].specifier);
+ exit_program(1);
+ }
+ av_dict_set(m, o->metadata[i].u.str, *val ? val : NULL, 0);
+ }
+ }
+}
+
+static void set_channel_layout(OutputFilter *f, OutputStream *ost)
+{
+ const AVCodec *c = ost->enc_ctx->codec;
+ int i, err;
+
+ if (ost->enc_ctx->ch_layout.order != AV_CHANNEL_ORDER_UNSPEC) {
+ /* Pass the layout through for all orders but UNSPEC */
+ err = av_channel_layout_copy(&f->ch_layout, &ost->enc_ctx->ch_layout);
+ if (err < 0)
+ report_and_exit(AVERROR(ENOMEM));
+ return;
+ }
+
+ /* Requested layout is of order UNSPEC */
+ if (!c->ch_layouts) {
+ /* Use the default native layout for the requested amount of channels when the
+ encoder doesn't have a list of supported layouts */
+ av_channel_layout_default(&f->ch_layout, ost->enc_ctx->ch_layout.nb_channels);
+ return;
+ }
+ /* Encoder has a list of supported layouts. Pick the first layout in it with the
+ same amount of channels as the requested layout */
+ for (i = 0; c->ch_layouts[i].nb_channels; i++) {
+ if (c->ch_layouts[i].nb_channels == ost->enc_ctx->ch_layout.nb_channels)
+ break;
+ }
+ if (c->ch_layouts[i].nb_channels) {
+ /* Use it if one is found */
+ err = av_channel_layout_copy(&f->ch_layout, &c->ch_layouts[i]);
+ if (err < 0)
+ report_and_exit(AVERROR(ENOMEM));
+ return;
+ }
+ /* If no layout for the amount of channels requested was found, use the default
+ native layout for it. */
+ av_channel_layout_default(&f->ch_layout, ost->enc_ctx->ch_layout.nb_channels);
+}
+
+static int copy_chapters(InputFile *ifile, OutputFile *ofile, AVFormatContext *os,
+ int copy_metadata)
+{
+ AVFormatContext *is = ifile->ctx;
+ AVChapter **tmp;
+ int i;
+
+ tmp = av_realloc_f(os->chapters, is->nb_chapters + os->nb_chapters, sizeof(*os->chapters));
+ if (!tmp)
+ return AVERROR(ENOMEM);
+ os->chapters = tmp;
+
+ for (i = 0; i < is->nb_chapters; i++) {
+ AVChapter *in_ch = is->chapters[i], *out_ch;
+ int64_t start_time = (ofile->start_time == AV_NOPTS_VALUE) ? 0 : ofile->start_time;
+ int64_t ts_off = av_rescale_q(start_time - ifile->ts_offset,
+ AV_TIME_BASE_Q, in_ch->time_base);
+ int64_t rt = (ofile->recording_time == INT64_MAX) ? INT64_MAX :
+ av_rescale_q(ofile->recording_time, AV_TIME_BASE_Q, in_ch->time_base);
+
+
+ if (in_ch->end < ts_off)
+ continue;
+ if (rt != INT64_MAX && in_ch->start > rt + ts_off)
+ break;
+
+ out_ch = av_mallocz(sizeof(AVChapter));
+ if (!out_ch)
+ return AVERROR(ENOMEM);
+
+ out_ch->id = in_ch->id;
+ out_ch->time_base = in_ch->time_base;
+ out_ch->start = FFMAX(0, in_ch->start - ts_off);
+ out_ch->end = FFMIN(rt, in_ch->end - ts_off);
+
+ if (copy_metadata)
+ av_dict_copy(&out_ch->metadata, in_ch->metadata, 0);
+
+ os->chapters[os->nb_chapters++] = out_ch;
+ }
+ return 0;
+}
+
+static int copy_metadata(Muxer *mux, AVFormatContext *ic,
+ const char *outspec, const char *inspec,
+ int *metadata_global_manual, int *metadata_streams_manual,
+ int *metadata_chapters_manual, const OptionsContext *o)
+{
+ AVFormatContext *oc = mux->fc;
+ AVDictionary **meta_in = NULL;
+ AVDictionary **meta_out = NULL;
+ int i, ret = 0;
+ char type_in, type_out;
+ const char *istream_spec = NULL, *ostream_spec = NULL;
+ int idx_in = 0, idx_out = 0;
+
+ parse_meta_type(mux, inspec, &type_in, &idx_in, &istream_spec);
+ parse_meta_type(mux, outspec, &type_out, &idx_out, &ostream_spec);
+
+ if (type_in == 'g' || type_out == 'g')
+ *metadata_global_manual = 1;
+ if (type_in == 's' || type_out == 's')
+ *metadata_streams_manual = 1;
+ if (type_in == 'c' || type_out == 'c')
+ *metadata_chapters_manual = 1;
+
+ /* ic is NULL when just disabling automatic mappings */
+ if (!ic)
+ return 0;
+
+#define METADATA_CHECK_INDEX(index, nb_elems, desc)\
+ if ((index) < 0 || (index) >= (nb_elems)) {\
+ av_log(mux, AV_LOG_FATAL, "Invalid %s index %d while processing metadata maps.\n",\
+ (desc), (index));\
+ exit_program(1);\
+ }
+
+#define SET_DICT(type, meta, context, index)\
+ switch (type) {\
+ case 'g':\
+ meta = &context->metadata;\
+ break;\
+ case 'c':\
+ METADATA_CHECK_INDEX(index, context->nb_chapters, "chapter")\
+ meta = &context->chapters[index]->metadata;\
+ break;\
+ case 'p':\
+ METADATA_CHECK_INDEX(index, context->nb_programs, "program")\
+ meta = &context->programs[index]->metadata;\
+ break;\
+ case 's':\
+ break; /* handled separately below */ \
+ default: av_assert0(0);\
+ }\
+
+ SET_DICT(type_in, meta_in, ic, idx_in);
+ SET_DICT(type_out, meta_out, oc, idx_out);
+
+ /* for input streams choose first matching stream */
+ if (type_in == 's') {
+ for (i = 0; i < ic->nb_streams; i++) {
+ if ((ret = check_stream_specifier(ic, ic->streams[i], istream_spec)) > 0) {
+ meta_in = &ic->streams[i]->metadata;
+ break;
+ } else if (ret < 0)
+ exit_program(1);
+ }
+ if (!meta_in) {
+ av_log(mux, AV_LOG_FATAL, "Stream specifier %s does not match any streams.\n", istream_spec);
+ exit_program(1);
+ }
+ }
+
+ if (type_out == 's') {
+ for (i = 0; i < oc->nb_streams; i++) {
+ if ((ret = check_stream_specifier(oc, oc->streams[i], ostream_spec)) > 0) {
+ meta_out = &oc->streams[i]->metadata;
+ av_dict_copy(meta_out, *meta_in, AV_DICT_DONT_OVERWRITE);
+ } else if (ret < 0)
+ exit_program(1);
+ }
+ } else
+ av_dict_copy(meta_out, *meta_in, AV_DICT_DONT_OVERWRITE);
+
+ return 0;
+}
+
+static void copy_meta(Muxer *mux, const OptionsContext *o)
+{
+ OutputFile *of = &mux->of;
+ AVFormatContext *oc = mux->fc;
+ int chapters_input_file = o->chapters_input_file;
+ int metadata_global_manual = 0;
+ int metadata_streams_manual = 0;
+ int metadata_chapters_manual = 0;
+
+ /* copy metadata */
+ for (int i = 0; i < o->nb_metadata_map; i++) {
+ char *p;
+ int in_file_index = strtol(o->metadata_map[i].u.str, &p, 0);
+
+ if (in_file_index >= nb_input_files) {
+ av_log(mux, AV_LOG_FATAL, "Invalid input file index %d while "
+ "processing metadata maps\n", in_file_index);
+ exit_program(1);
+ }
+ copy_metadata(mux,
+ in_file_index >= 0 ? input_files[in_file_index]->ctx : NULL,
+ o->metadata_map[i].specifier, *p ? p + 1 : p,
+ &metadata_global_manual, &metadata_streams_manual,
+ &metadata_chapters_manual, o);
+ }
+
+ /* copy chapters */
+ if (chapters_input_file >= nb_input_files) {
+ if (chapters_input_file == INT_MAX) {
+ /* copy chapters from the first input file that has them*/
+ chapters_input_file = -1;
+ for (int i = 0; i < nb_input_files; i++)
+ if (input_files[i]->ctx->nb_chapters) {
+ chapters_input_file = i;
+ break;
+ }
+ } else {
+ av_log(mux, AV_LOG_FATAL, "Invalid input file index %d in chapter mapping.\n",
+ chapters_input_file);
+ exit_program(1);
+ }
+ }
+ if (chapters_input_file >= 0)
+ copy_chapters(input_files[chapters_input_file], of, oc,
+ !metadata_chapters_manual);
+
+ /* copy global metadata by default */
+ if (!metadata_global_manual && nb_input_files){
+ av_dict_copy(&oc->metadata, input_files[0]->ctx->metadata,
+ AV_DICT_DONT_OVERWRITE);
+ if (of->recording_time != INT64_MAX)
+ av_dict_set(&oc->metadata, "duration", NULL, 0);
+ av_dict_set(&oc->metadata, "creation_time", NULL, 0);
+ av_dict_set(&oc->metadata, "company_name", NULL, 0);
+ av_dict_set(&oc->metadata, "product_name", NULL, 0);
+ av_dict_set(&oc->metadata, "product_version", NULL, 0);
+ }
+ if (!metadata_streams_manual)
+ for (int i = 0; i < of->nb_streams; i++) {
+ OutputStream *ost = of->streams[i];
+
+ if (!ost->ist) /* this is true e.g. for attached files */
+ continue;
+ av_dict_copy(&ost->st->metadata, ost->ist->st->metadata, AV_DICT_DONT_OVERWRITE);
+ if (ost->enc_ctx) {
+ av_dict_set(&ost->st->metadata, "encoder", NULL, 0);
+ }
+ }
+}
+
+static int set_dispositions(Muxer *mux, const OptionsContext *o)
+{
+ OutputFile *of = &mux->of;
+ AVFormatContext *ctx = mux->fc;
+
+ int nb_streams[AVMEDIA_TYPE_NB] = { 0 };
+ int have_default[AVMEDIA_TYPE_NB] = { 0 };
+ int have_manual = 0;
+ int ret = 0;
+
+ const char **dispositions;
+
+ dispositions = av_calloc(ctx->nb_streams, sizeof(*dispositions));
+ if (!dispositions)
+ return AVERROR(ENOMEM);
+
+ // first, copy the input dispositions
+ for (int i = 0; i < ctx->nb_streams; i++) {
+ OutputStream *ost = of->streams[i];
+
+ nb_streams[ost->st->codecpar->codec_type]++;
+
+ MATCH_PER_STREAM_OPT(disposition, str, dispositions[i], ctx, ost->st);
+
+ have_manual |= !!dispositions[i];
+
+ if (ost->ist) {
+ ost->st->disposition = ost->ist->st->disposition;
+
+ if (ost->st->disposition & AV_DISPOSITION_DEFAULT)
+ have_default[ost->st->codecpar->codec_type] = 1;
+ }
+ }
+
+ if (have_manual) {
+ // process manually set dispositions - they override the above copy
+ for (int i = 0; i < ctx->nb_streams; i++) {
+ OutputStream *ost = of->streams[i];
+ const char *disp = dispositions[i];
+
+ if (!disp)
+ continue;
+
+ ret = av_opt_set(ost->st, "disposition", disp, 0);
+ if (ret < 0)
+ goto finish;
+ }
+ } else {
+ // For each media type with more than one stream, find a suitable stream to
+ // mark as default, unless one is already marked default.
+ // "Suitable" means the first of that type, skipping attached pictures.
+ for (int i = 0; i < ctx->nb_streams; i++) {
+ OutputStream *ost = of->streams[i];
+ enum AVMediaType type = ost->st->codecpar->codec_type;
+
+ if (nb_streams[type] < 2 || have_default[type] ||
+ ost->st->disposition & AV_DISPOSITION_ATTACHED_PIC)
+ continue;
+
+ ost->st->disposition |= AV_DISPOSITION_DEFAULT;
+ have_default[type] = 1;
+ }
+ }
+
+finish:
+ av_freep(&dispositions);
+
+ return ret;
+}
+
+const char *const forced_keyframes_const_names[] = {
+ "n",
+ "n_forced",
+ "prev_forced_n",
+ "prev_forced_t",
+ "t",
+ NULL
+};
+
+static int compare_int64(const void *a, const void *b)
+{
+ return FFDIFFSIGN(*(const int64_t *)a, *(const int64_t *)b);
+}
+
+static void parse_forced_key_frames(KeyframeForceCtx *kf, const Muxer *mux,
+ const char *spec)
+{
+ const char *p;
+ int n = 1, i, size, index = 0;
+ int64_t t, *pts;
+
+ for (p = spec; *p; p++)
+ if (*p == ',')
+ n++;
+ size = n;
+ pts = av_malloc_array(size, sizeof(*pts));
+ if (!pts)
+ report_and_exit(AVERROR(ENOMEM));
+
+ p = spec;
+ for (i = 0; i < n; i++) {
+ char *next = strchr(p, ',');
+
+ if (next)
+ *next++ = 0;
+
+ if (!memcmp(p, "chapters", 8)) {
+ AVChapter * const *ch = mux->fc->chapters;
+ unsigned int nb_ch = mux->fc->nb_chapters;
+ int j;
+
+ if (nb_ch > INT_MAX - size ||
+ !(pts = av_realloc_f(pts, size += nb_ch - 1,
+ sizeof(*pts))))
+ report_and_exit(AVERROR(ENOMEM));
+ t = p[8] ? parse_time_or_die("force_key_frames", p + 8, 1) : 0;
+
+ for (j = 0; j < nb_ch; j++) {
+ const AVChapter *c = ch[j];
+ av_assert1(index < size);
+ pts[index++] = av_rescale_q(c->start, c->time_base,
+ AV_TIME_BASE_Q) + t;
+ }
+
+ } else {
+ av_assert1(index < size);
+ pts[index++] = parse_time_or_die("force_key_frames", p, 1);
+ }
+
+ p = next;
+ }
+
+ av_assert0(index == size);
+ qsort(pts, size, sizeof(*pts), compare_int64);
+ kf->nb_pts = size;
+ kf->pts = pts;
+}
+
+static int process_forced_keyframes(Muxer *mux, const OptionsContext *o)
+{
+ for (int i = 0; i < mux->of.nb_streams; i++) {
+ OutputStream *ost = mux->of.streams[i];
+ const char *forced_keyframes = NULL;
+
+ MATCH_PER_STREAM_OPT(forced_key_frames, str, forced_keyframes, mux->fc, ost->st);
+
+ if (!(ost->st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO &&
+ ost->enc_ctx && forced_keyframes))
+ continue;
+
+ if (!strncmp(forced_keyframes, "expr:", 5)) {
+ int ret = av_expr_parse(&ost->kf.pexpr, forced_keyframes + 5,
+ forced_keyframes_const_names, NULL, NULL, NULL, NULL, 0, NULL);
+ if (ret < 0) {
+ av_log(ost, AV_LOG_ERROR,
+ "Invalid force_key_frames expression '%s'\n", forced_keyframes + 5);
+ return ret;
+ }
+ ost->kf.expr_const_values[FKF_N] = 0;
+ ost->kf.expr_const_values[FKF_N_FORCED] = 0;
+ ost->kf.expr_const_values[FKF_PREV_FORCED_N] = NAN;
+ ost->kf.expr_const_values[FKF_PREV_FORCED_T] = NAN;
+
+ // Don't parse the 'forced_keyframes' in case of 'keep-source-keyframes',
+ // parse it only for static kf timings
+ } else if (!strcmp(forced_keyframes, "source")) {
+ ost->kf.type = KF_FORCE_SOURCE;
+ } else if (!strcmp(forced_keyframes, "source_no_drop")) {
+ ost->kf.type = KF_FORCE_SOURCE_NO_DROP;
+ } else {
+ parse_forced_key_frames(&ost->kf, mux, forced_keyframes);
+ }
+ }
+
+ return 0;
+}
+
+static void validate_enc_avopt(Muxer *mux, const AVDictionary *codec_avopt)
+{
+ const AVClass *class = avcodec_get_class();
+ const AVClass *fclass = avformat_get_class();
+ const OutputFile *of = &mux->of;
+
+ AVDictionary *unused_opts;
+ const AVDictionaryEntry *e;
+
+ unused_opts = strip_specifiers(codec_avopt);
+ for (int i = 0; i < of->nb_streams; i++) {
+ e = NULL;
+ while ((e = av_dict_iterate(of->streams[i]->encoder_opts, e)))
+ av_dict_set(&unused_opts, e->key, NULL, 0);
+ }
+
+ e = NULL;
+ while ((e = av_dict_iterate(unused_opts, e))) {
+ const AVOption *option = av_opt_find(&class, e->key, NULL, 0,
+ AV_OPT_SEARCH_CHILDREN | AV_OPT_SEARCH_FAKE_OBJ);
+ const AVOption *foption = av_opt_find(&fclass, e->key, NULL, 0,
+ AV_OPT_SEARCH_CHILDREN | AV_OPT_SEARCH_FAKE_OBJ);
+ if (!option || foption)
+ continue;
+
+ if (!(option->flags & AV_OPT_FLAG_ENCODING_PARAM)) {
+ av_log(mux, AV_LOG_ERROR, "Codec AVOption %s (%s) is not an "
+ "encoding option.\n", e->key, option->help ? option->help : "");
+ exit_program(1);
+ }
+
+ // gop_timecode is injected by generic code but not always used
+ if (!strcmp(e->key, "gop_timecode"))
+ continue;
+
+ av_log(mux, AV_LOG_WARNING, "Codec AVOption %s (%s) has not been used "
+ "for any stream. The most likely reason is either wrong type "
+ "(e.g. a video option with no video streams) or that it is a "
+ "private option of some encoder which was not actually used for "
+ "any stream.\n", e->key, option->help ? option->help : "");
+ }
+ av_dict_free(&unused_opts);
+}
+
+static const char *output_file_item_name(void *obj)
+{
+ const Muxer *mux = obj;
+
+ return mux->log_name;
+}
+
+static const AVClass output_file_class = {
+ .class_name = "OutputFile",
+ .version = LIBAVUTIL_VERSION_INT,
+ .item_name = output_file_item_name,
+ .category = AV_CLASS_CATEGORY_MUXER,
+};
+
+static Muxer *mux_alloc(void)
+{
+ Muxer *mux = allocate_array_elem(&output_files, sizeof(*mux), &nb_output_files);
+
+ mux->of.class = &output_file_class;
+ mux->of.index = nb_output_files - 1;
+
+ snprintf(mux->log_name, sizeof(mux->log_name), "out#%d", mux->of.index);
+
+ return mux;
+}
+
+int of_open(const OptionsContext *o, const char *filename)
+{
+ Muxer *mux;
+ AVFormatContext *oc;
+ int err;
+ OutputFile *of;
+
+ int64_t recording_time = o->recording_time;
+ int64_t stop_time = o->stop_time;
+
+ mux = mux_alloc();
+ of = &mux->of;
+
+ if (stop_time != INT64_MAX && recording_time != INT64_MAX) {
+ stop_time = INT64_MAX;
+ av_log(mux, AV_LOG_WARNING, "-t and -to cannot be used together; using -t.\n");
+ }
+
+ if (stop_time != INT64_MAX && recording_time == INT64_MAX) {
+ int64_t start_time = o->start_time == AV_NOPTS_VALUE ? 0 : o->start_time;
+ if (stop_time <= start_time) {
+ av_log(mux, AV_LOG_ERROR, "-to value smaller than -ss; aborting.\n");
+ exit_program(1);
+ } else {
+ recording_time = stop_time - start_time;
+ }
+ }
+
+ of->recording_time = recording_time;
+ of->start_time = o->start_time;
+ of->shortest = o->shortest;
+
+ mux->thread_queue_size = o->thread_queue_size > 0 ? o->thread_queue_size : 8;
+ mux->limit_filesize = o->limit_filesize;
+ av_dict_copy(&mux->opts, o->g->format_opts, 0);
+
+ if (!strcmp(filename, "-"))
+ filename = "pipe:";
+
+ err = avformat_alloc_output_context2(&oc, NULL, o->format, filename);
+ if (!oc) {
+ print_error(filename, err);
+ exit_program(1);
+ }
+ mux->fc = oc;
+
+ av_strlcat(mux->log_name, "/", sizeof(mux->log_name));
+ av_strlcat(mux->log_name, oc->oformat->name, sizeof(mux->log_name));
+
+ if (strcmp(oc->oformat->name, "rtp"))
+ want_sdp = 0;
+
+ of->format = oc->oformat;
+ if (recording_time != INT64_MAX)
+ oc->duration = recording_time;
+
+ oc->interrupt_callback = int_cb;
+
+ if (o->bitexact) {
+ oc->flags |= AVFMT_FLAG_BITEXACT;
+ of->bitexact = 1;
+ } else {
+ of->bitexact = check_opt_bitexact(oc, mux->opts, "fflags",
+ AVFMT_FLAG_BITEXACT);
+ }
+
+ /* create all output streams for this file */
+ create_streams(mux, o);
+
+ /* check if all codec options have been used */
+ validate_enc_avopt(mux, o->g->codec_opts);
+
+ /* set the decoding_needed flags and create simple filtergraphs */
+ for (int i = 0; i < of->nb_streams; i++) {
+ OutputStream *ost = of->streams[i];
+
+ if (ost->enc_ctx && ost->ist) {
+ InputStream *ist = ost->ist;
+ ist->decoding_needed |= DECODING_FOR_OST;
+ ist->processing_needed = 1;
+
+ if (ost->st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO ||
+ ost->st->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) {
+ err = init_simple_filtergraph(ist, ost);
+ if (err < 0) {
+ av_log(ost, AV_LOG_ERROR,
+ "Error initializing a simple filtergraph\n");
+ exit_program(1);
+ }
+ }
+ } else if (ost->ist) {
+ ost->ist->processing_needed = 1;
+ }
+
+ /* set the filter output constraints */
+ if (ost->filter) {
+ const AVCodec *c = ost->enc_ctx->codec;
+ OutputFilter *f = ost->filter;
+ switch (ost->enc_ctx->codec_type) {
+ case AVMEDIA_TYPE_VIDEO:
+ f->frame_rate = ost->frame_rate;
+ f->width = ost->enc_ctx->width;
+ f->height = ost->enc_ctx->height;
+ if (ost->enc_ctx->pix_fmt != AV_PIX_FMT_NONE) {
+ f->format = ost->enc_ctx->pix_fmt;
+ } else {
+ f->formats = c->pix_fmts;
+ }
+ break;
+ case AVMEDIA_TYPE_AUDIO:
+ if (ost->enc_ctx->sample_fmt != AV_SAMPLE_FMT_NONE) {
+ f->format = ost->enc_ctx->sample_fmt;
+ } else {
+ f->formats = c->sample_fmts;
+ }
+ if (ost->enc_ctx->sample_rate) {
+ f->sample_rate = ost->enc_ctx->sample_rate;
+ } else {
+ f->sample_rates = c->supported_samplerates;
+ }
+ if (ost->enc_ctx->ch_layout.nb_channels) {
+ set_channel_layout(f, ost);
+ } else if (c->ch_layouts) {
+ f->ch_layouts = c->ch_layouts;
+ }
+ break;
+ }
+ }
+ }
+
+ /* check filename in case of an image number is expected */
+ if (oc->oformat->flags & AVFMT_NEEDNUMBER) {
+ if (!av_filename_number_test(oc->url)) {
+ print_error(oc->url, AVERROR(EINVAL));
+ exit_program(1);
+ }
+ }
+
+ if (!(oc->oformat->flags & AVFMT_NOFILE)) {
+ /* test if it already exists to avoid losing precious files */
+ assert_file_overwrite(filename);
+
+ /* open the file */
+ if ((err = avio_open2(&oc->pb, filename, AVIO_FLAG_WRITE,
+ &oc->interrupt_callback,
+ &mux->opts)) < 0) {
+ print_error(filename, err);
+ exit_program(1);
+ }
+ } else if (strcmp(oc->oformat->name, "image2")==0 && !av_filename_number_test(filename))
+ assert_file_overwrite(filename);
+
+ if (o->mux_preload) {
+ av_dict_set_int(&mux->opts, "preload", o->mux_preload*AV_TIME_BASE, 0);
+ }
+ oc->max_delay = (int)(o->mux_max_delay * AV_TIME_BASE);
+
+ /* copy metadata and chapters from input files */
+ copy_meta(mux, o);
+
+ of_add_programs(mux, o);
+ of_add_metadata(of, oc, o);
+
+ err = set_dispositions(mux, o);
+ if (err < 0) {
+ av_log(mux, AV_LOG_FATAL, "Error setting output stream dispositions\n");
+ exit_program(1);
+ }
+
+ // parse forced keyframe specifications;
+ // must be done after chapters are created
+ err = process_forced_keyframes(mux, o);
+ if (err < 0) {
+ av_log(mux, AV_LOG_FATAL, "Error processing forced keyframes\n");
+ exit_program(1);
+ }
+
+ err = setup_sync_queues(mux, oc, o->shortest_buf_duration * AV_TIME_BASE);
+ if (err < 0) {
+ av_log(mux, AV_LOG_FATAL, "Error setting up output sync queues\n");
+ exit_program(1);
+ }
+
+ of->url = filename;
+
+ /* write the header for files with no streams */
+ if (of->format->flags & AVFMT_NOSTREAMS && oc->nb_streams == 0) {
+ int ret = mux_check_init(mux);
+ if (ret < 0)
+ return ret;
+ }
+
+ return 0;
+}
diff --git a/app/src/main/cpp/ffmpeg/ffmpeg_opt.c b/app/src/main/cpp/ffmpeg/ffmpeg_opt.c
index bb154398..055275d8 100644
--- a/app/src/main/cpp/ffmpeg/ffmpeg_opt.c
+++ b/app/src/main/cpp/ffmpeg/ffmpeg_opt.c
@@ -18,21 +18,33 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
+#include "config.h"
+
#include
-#include "ffmpeg/ffmpeg.h"
-#include "ffmpeg/cmdutils.h"
+#if HAVE_SYS_RESOURCE_H
+#include
+#include
+#endif
+
+#include "ffmpeg.h"
+#include "cmdutils.h"
+#include "opt_common.h"
+#include "sync_queue.h"
#include "libavformat/avformat.h"
#include "libavcodec/avcodec.h"
+#include "libavcodec/bsf.h"
#include "libavfilter/avfilter.h"
#include "libavutil/avassert.h"
#include "libavutil/avstring.h"
#include "libavutil/avutil.h"
+#include "libavutil/bprint.h"
#include "libavutil/channel_layout.h"
+#include "libavutil/display.h"
#include "libavutil/intreadwrite.h"
#include "libavutil/fifo.h"
#include "libavutil/mathematics.h"
@@ -40,50 +52,13 @@
#include "libavutil/parseutils.h"
#include "libavutil/pixdesc.h"
#include "libavutil/pixfmt.h"
-#include "libavutil/time_internal.h"
-
-#define DEFAULT_PASS_LOGFILENAME_PREFIX "ffmpeg2pass"
-
-#define MATCH_PER_STREAM_OPT(name, type, outvar, fmtctx, st)\
-{\
- int i, ret;\
- for (i = 0; i < o->nb_ ## name; i++) {\
- char *spec = o->name[i].specifier;\
- if ((ret = check_stream_specifier(fmtctx, st, spec)) > 0)\
- outvar = o->name[i].u.type;\
- else if (ret < 0)\
- exit_program(1);\
- }\
-}
-#define MATCH_PER_TYPE_OPT(name, type, outvar, fmtctx, mediatype)\
-{\
- int i;\
- for (i = 0; i < o->nb_ ## name; i++) {\
- char *spec = o->name[i].specifier;\
- if (!strcmp(spec, mediatype))\
- outvar = o->name[i].u.type;\
- }\
-}
+const char *const opt_name_codec_names[] = {"c", "codec", "acodec", "vcodec", "scodec", "dcodec", NULL};
+const char *const opt_name_frame_rates[] = {"r", NULL};
+const char *const opt_name_codec_tags[] = {"tag", "atag", "vtag", "stag", NULL};
+const char *const opt_name_top_field_first[] = {"top", NULL};
-const HWAccel hwaccels[] = {
-#if HAVE_VDPAU_X11
- { "vdpau", vdpau_init, HWACCEL_VDPAU, AV_PIX_FMT_VDPAU },
-#endif
-#if HAVE_DXVA2_LIB
- { "dxva2", dxva2_init, HWACCEL_DXVA2, AV_PIX_FMT_DXVA2_VLD },
-#endif
-#if CONFIG_VDA
- { "vda", videotoolbox_init, HWACCEL_VDA, AV_PIX_FMT_VDA },
-#endif
-#if CONFIG_VIDEOTOOLBOX
- { "videotoolbox", videotoolbox_init, HWACCEL_VIDEOTOOLBOX, AV_PIX_FMT_VIDEOTOOLBOX },
-#endif
-#if CONFIG_LIBMFX
- { "qsv", qsv_init, HWACCEL_QSV, AV_PIX_FMT_QSV },
-#endif
- { 0 },
-};
+HWDevice *filter_hw_device;
char *vstats_filename;
char *sdp_filename;
@@ -92,11 +67,8 @@ float audio_drift_threshold = 0.1;
float dts_delta_threshold = 10;
float dts_error_threshold = 3600*30;
-int audio_volume = 256;
-int audio_sync_method = 0;
-int video_sync_method = VSYNC_AUTO;
+enum VideoSyncMethod video_sync_method = VSYNC_AUTO;
float frame_drop_threshold = 0;
-int do_deinterlace = 0;
int do_benchmark = 0;
int do_benchmark_all = 0;
int do_hex_dump = 0;
@@ -110,19 +82,22 @@ int abort_on_flags = 0;
int print_stats = -1;
int qp_hist = 0;
int stdin_interaction = 1;
-int frame_bits_per_raw_sample = 0;
float max_error_rate = 2.0/3;
+char *filter_nbthreads;
+int filter_complex_nbthreads = 0;
+int vstats_version = 2;
+int auto_conversion_filters = 1;
+int64_t stats_period = 500000;
-static int intra_only = 0;
static int file_overwrite = 0;
static int no_file_overwrite = 0;
-static int do_psnr = 0;
-static int input_sync;
-static int override_ffserver = 0;
-static int input_stream_potentially_available = 0;
-static int ignore_unknown_streams = 0;
-static int copy_unknown_streams = 0;
+#if FFMPEG_OPT_PSNR
+int do_psnr = 0;
+#endif
+int ignore_unknown_streams = 0;
+int copy_unknown_streams = 0;
+int recast_media = 0;
static void uninit_options(OptionsContext *o)
{
@@ -151,7 +126,9 @@ static void uninit_options(OptionsContext *o)
for (i = 0; i < o->nb_stream_maps; i++)
av_freep(&o->stream_maps[i].linklabel);
av_freep(&o->stream_maps);
+#if FFMPEG_OPT_MAP_CHANNEL
av_freep(&o->audio_channel_maps);
+#endif
av_freep(&o->streamid_map);
av_freep(&o->attachments);
}
@@ -165,30 +142,34 @@ static void init_options(OptionsContext *o)
o->start_time = AV_NOPTS_VALUE;
o->start_time_eof = AV_NOPTS_VALUE;
o->recording_time = INT64_MAX;
- o->limit_filesize = UINT64_MAX;
+ o->limit_filesize = INT64_MAX;
o->chapters_input_file = INT_MAX;
o->accurate_seek = 1;
+ o->thread_queue_size = -1;
+ o->input_sync_ref = -1;
+ o->find_stream_info = 1;
+ o->shortest_buf_duration = 10.f;
}
static int show_hwaccels(void *optctx, const char *opt, const char *arg)
{
- int i;
+ enum AVHWDeviceType type = AV_HWDEVICE_TYPE_NONE;
printf("Hardware acceleration methods:\n");
- for (i = 0; i < FF_ARRAY_ELEMS(hwaccels) - 1; i++) {
- printf("%s\n", hwaccels[i].name);
- }
+ while ((type = av_hwdevice_iterate_types(type)) !=
+ AV_HWDEVICE_TYPE_NONE)
+ printf("%s\n", av_hwdevice_get_type_name(type));
printf("\n");
return 0;
}
/* return a copy of the input with the stream specifiers removed from the keys */
-static AVDictionary *strip_specifiers(AVDictionary *dict)
+AVDictionary *strip_specifiers(const AVDictionary *dict)
{
- AVDictionaryEntry *e = NULL;
+ const AVDictionaryEntry *e = NULL;
AVDictionary *ret = NULL;
- while ((e = av_dict_get(dict, "", e, AV_DICT_IGNORE_SUFFIX))) {
+ while ((e = av_dict_iterate(dict, e))) {
char *p = strchr(e->key, ':');
if (p)
@@ -200,11 +181,129 @@ static AVDictionary *strip_specifiers(AVDictionary *dict)
return ret;
}
+int parse_and_set_vsync(const char *arg, int *vsync_var, int file_idx, int st_idx, int is_global)
+{
+ if (!av_strcasecmp(arg, "cfr")) *vsync_var = VSYNC_CFR;
+ else if (!av_strcasecmp(arg, "vfr")) *vsync_var = VSYNC_VFR;
+ else if (!av_strcasecmp(arg, "passthrough")) *vsync_var = VSYNC_PASSTHROUGH;
+ else if (!av_strcasecmp(arg, "drop")) *vsync_var = VSYNC_DROP;
+ else if (!is_global && !av_strcasecmp(arg, "auto")) *vsync_var = VSYNC_AUTO;
+ else if (!is_global) {
+ av_log(NULL, AV_LOG_FATAL, "Invalid value %s specified for fps_mode of #%d:%d.\n", arg, file_idx, st_idx);
+ exit_program(1);
+ }
+
+ if (is_global && *vsync_var == VSYNC_AUTO) {
+ video_sync_method = parse_number_or_die("vsync", arg, OPT_INT, VSYNC_AUTO, VSYNC_VFR);
+ av_log(NULL, AV_LOG_WARNING, "Passing a number to -vsync is deprecated,"
+ " use a string argument as described in the manual.\n");
+ }
+ return 0;
+}
+
+/* Correct input file start times based on enabled streams */
+static void correct_input_start_times(void)
+{
+ for (int i = 0; i < nb_input_files; i++) {
+ InputFile *ifile = input_files[i];
+ AVFormatContext *is = ifile->ctx;
+ int64_t new_start_time = INT64_MAX, diff, abs_start_seek;
+
+ ifile->start_time_effective = is->start_time;
+
+ if (is->start_time == AV_NOPTS_VALUE ||
+ !(is->iformat->flags & AVFMT_TS_DISCONT))
+ continue;
+
+ for (int j = 0; j < is->nb_streams; j++) {
+ AVStream *st = is->streams[j];
+ if(st->discard == AVDISCARD_ALL || st->start_time == AV_NOPTS_VALUE)
+ continue;
+ new_start_time = FFMIN(new_start_time, av_rescale_q(st->start_time, st->time_base, AV_TIME_BASE_Q));
+ }
+
+ diff = new_start_time - is->start_time;
+ if (diff) {
+ av_log(NULL, AV_LOG_VERBOSE, "Correcting start time of Input #%d by %"PRId64" us.\n", i, diff);
+ ifile->start_time_effective = new_start_time;
+ if (copy_ts && start_at_zero)
+ ifile->ts_offset = -new_start_time;
+ else if (!copy_ts) {
+ abs_start_seek = is->start_time + (ifile->start_time != AV_NOPTS_VALUE) ? ifile->start_time : 0;
+ ifile->ts_offset = abs_start_seek > new_start_time ? -abs_start_seek : -new_start_time;
+ } else if (copy_ts)
+ ifile->ts_offset = 0;
+
+ ifile->ts_offset += ifile->input_ts_offset;
+ }
+ }
+}
+
+static int apply_sync_offsets(void)
+{
+ for (int i = 0; i < nb_input_files; i++) {
+ InputFile *ref, *self = input_files[i];
+ int64_t adjustment;
+ int64_t self_start_time, ref_start_time, self_seek_start, ref_seek_start;
+ int start_times_set = 1;
+
+ if (self->input_sync_ref == -1 || self->input_sync_ref == i) continue;
+ if (self->input_sync_ref >= nb_input_files || self->input_sync_ref < -1) {
+ av_log(NULL, AV_LOG_FATAL, "-isync for input %d references non-existent input %d.\n", i, self->input_sync_ref);
+ exit_program(1);
+ }
+
+ if (copy_ts && !start_at_zero) {
+ av_log(NULL, AV_LOG_FATAL, "Use of -isync requires that start_at_zero be set if copyts is set.\n");
+ exit_program(1);
+ }
+
+ ref = input_files[self->input_sync_ref];
+ if (ref->input_sync_ref != -1 && ref->input_sync_ref != self->input_sync_ref) {
+ av_log(NULL, AV_LOG_ERROR, "-isync for input %d references a resynced input %d. Sync not set.\n", i, self->input_sync_ref);
+ continue;
+ }
+
+ if (self->ctx->start_time_realtime != AV_NOPTS_VALUE && ref->ctx->start_time_realtime != AV_NOPTS_VALUE) {
+ self_start_time = self->ctx->start_time_realtime;
+ ref_start_time = ref->ctx->start_time_realtime;
+ } else if (self->start_time_effective != AV_NOPTS_VALUE && ref->start_time_effective != AV_NOPTS_VALUE) {
+ self_start_time = self->start_time_effective;
+ ref_start_time = ref->start_time_effective;
+ } else {
+ start_times_set = 0;
+ }
+
+ if (start_times_set) {
+ self_seek_start = self->start_time == AV_NOPTS_VALUE ? 0 : self->start_time;
+ ref_seek_start = ref->start_time == AV_NOPTS_VALUE ? 0 : ref->start_time;
+
+ adjustment = (self_start_time - ref_start_time) + !copy_ts*(self_seek_start - ref_seek_start) + ref->input_ts_offset;
+
+ self->ts_offset += adjustment;
+
+ av_log(NULL, AV_LOG_INFO, "Adjusted ts offset for Input #%d by %"PRId64" us to sync with Input #%d.\n", i, adjustment, self->input_sync_ref);
+ } else {
+ av_log(NULL, AV_LOG_INFO, "Unable to identify start times for Inputs #%d and %d both. No sync adjustment made.\n", i, self->input_sync_ref);
+ }
+ }
+
+ return 0;
+}
+
+static int opt_filter_threads(void *optctx, const char *opt, const char *arg)
+{
+ av_free(filter_nbthreads);
+ filter_nbthreads = av_strdup(arg);
+ return 0;
+}
+
static int opt_abort_on(void *optctx, const char *opt, const char *arg)
{
static const AVOption opts[] = {
- { "abort_on" , NULL, 0, AV_OPT_TYPE_FLAGS, { .i64 = 0 }, INT64_MIN, INT64_MAX, .unit = "flags" },
- { "empty_output" , NULL, 0, AV_OPT_TYPE_CONST, { .i64 = ABORT_ON_FLAG_EMPTY_OUTPUT }, .unit = "flags" },
+ { "abort_on" , NULL, 0, AV_OPT_TYPE_FLAGS, { .i64 = 0 }, INT64_MIN, INT64_MAX, .unit = "flags" },
+ { "empty_output" , NULL, 0, AV_OPT_TYPE_CONST, { .i64 = ABORT_ON_FLAG_EMPTY_OUTPUT }, .unit = "flags" },
+ { "empty_output_stream", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = ABORT_ON_FLAG_EMPTY_OUTPUT_STREAM }, .unit = "flags" },
{ NULL },
};
static const AVClass class = {
@@ -218,25 +317,19 @@ static int opt_abort_on(void *optctx, const char *opt, const char *arg)
return av_opt_eval_flags(&pclass, &opts[0], arg, &abort_on_flags);
}
-static int opt_sameq(void *optctx, const char *opt, const char *arg)
+static int opt_stats_period(void *optctx, const char *opt, const char *arg)
{
- av_log(NULL, AV_LOG_ERROR, "Option '%s' was removed. "
- "If you are looking for an option to preserve the quality (which is not "
- "what -%s was for), use -qscale 0 or an equivalent quality factor option.\n",
- opt, opt);
- return AVERROR(EINVAL);
-}
+ int64_t user_stats_period = parse_time_or_die(opt, arg, 1);
-static int opt_video_channel(void *optctx, const char *opt, const char *arg)
-{
- av_log(NULL, AV_LOG_WARNING, "This option is deprecated, use -channel.\n");
- return opt_default(optctx, "channel", arg);
-}
+ if (user_stats_period <= 0) {
+ av_log(NULL, AV_LOG_ERROR, "stats_period %s must be positive.\n", arg);
+ return AVERROR(EINVAL);
+ }
-static int opt_video_standard(void *optctx, const char *opt, const char *arg)
-{
- av_log(NULL, AV_LOG_WARNING, "This option is deprecated, use -standard.\n");
- return opt_default(optctx, "standard", arg);
+ stats_period = user_stats_period;
+ av_log(NULL, AV_LOG_INFO, "ffmpeg stats and -progress period set to %s.\n", arg);
+
+ return 0;
}
static int opt_audio_codec(void *optctx, const char *opt, const char *arg)
@@ -267,10 +360,11 @@ static int opt_map(void *optctx, const char *opt, const char *arg)
{
OptionsContext *o = optctx;
StreamMap *m = NULL;
- int i, negative = 0, file_idx;
- int sync_file_idx = -1, sync_stream_idx = 0;
- char *p, *sync;
- char *map;
+ int i, negative = 0, file_idx, disabled = 0;
+#if FFMPEG_OPT_MAP_SYNC
+ char *sync;
+#endif
+ char *map, *p;
char *allow_unused;
if (*arg == '-') {
@@ -281,28 +375,13 @@ static int opt_map(void *optctx, const char *opt, const char *arg)
if (!map)
return AVERROR(ENOMEM);
+#if FFMPEG_OPT_MAP_SYNC
/* parse sync stream first, just pick first matching stream */
if (sync = strchr(map, ',')) {
*sync = 0;
- sync_file_idx = strtol(sync + 1, &sync, 0);
- if (sync_file_idx >= nb_input_files || sync_file_idx < 0) {
- av_log(NULL, AV_LOG_FATAL, "Invalid sync file index: %d.\n", sync_file_idx);
- exit_program(1);
- }
- if (*sync)
- sync++;
- for (i = 0; i < input_files[sync_file_idx]->nb_streams; i++)
- if (check_stream_specifier(input_files[sync_file_idx]->ctx,
- input_files[sync_file_idx]->ctx->streams[i], sync) == 1) {
- sync_stream_idx = i;
- break;
- }
- if (i == input_files[sync_file_idx]->nb_streams) {
- av_log(NULL, AV_LOG_FATAL, "Sync stream specification in map %s does not "
- "match any streams.\n", arg);
- exit_program(1);
- }
+ av_log(NULL, AV_LOG_WARNING, "Specifying a sync stream is deprecated and has no effect\n");
}
+#endif
if (map[0] == '[') {
@@ -338,25 +417,25 @@ static int opt_map(void *optctx, const char *opt, const char *arg)
if (check_stream_specifier(input_files[file_idx]->ctx, input_files[file_idx]->ctx->streams[i],
*p == ':' ? p + 1 : p) <= 0)
continue;
+ if (input_files[file_idx]->streams[i]->user_set_discard == AVDISCARD_ALL) {
+ disabled = 1;
+ continue;
+ }
GROW_ARRAY(o->stream_maps, o->nb_stream_maps);
m = &o->stream_maps[o->nb_stream_maps - 1];
m->file_index = file_idx;
m->stream_index = i;
-
- if (sync_file_idx >= 0) {
- m->sync_file_index = sync_file_idx;
- m->sync_stream_index = sync_stream_idx;
- } else {
- m->sync_file_index = file_idx;
- m->sync_stream_index = i;
- }
}
}
if (!m) {
if (allow_unused) {
av_log(NULL, AV_LOG_VERBOSE, "Stream map '%s' matches no streams; ignoring.\n", arg);
+ } else if (disabled) {
+ av_log(NULL, AV_LOG_FATAL, "Stream map '%s' matches disabled streams.\n"
+ "To ignore this, add a trailing '?' to the map.\n", arg);
+ exit_program(1);
} else {
av_log(NULL, AV_LOG_FATAL, "Stream map '%s' matches no streams.\n"
"To ignore this, add a trailing '?' to the map.\n", arg);
@@ -376,12 +455,24 @@ static int opt_attach(void *optctx, const char *opt, const char *arg)
return 0;
}
+#if FFMPEG_OPT_MAP_CHANNEL
static int opt_map_channel(void *optctx, const char *opt, const char *arg)
{
OptionsContext *o = optctx;
int n;
AVStream *st;
AudioChannelMap *m;
+ char *allow_unused;
+ char *mapchan;
+
+ av_log(NULL, AV_LOG_WARNING,
+ "The -%s option is deprecated and will be removed. "
+ "It can be replaced by the 'pan' filter, or in some cases by "
+ "combinations of 'channelsplit', 'channelmap', 'amerge' filters.\n", opt);
+
+ mapchan = av_strdup(arg);
+ if (!mapchan)
+ return AVERROR(ENOMEM);
GROW_ARRAY(o->audio_channel_maps, o->nb_audio_channel_maps);
m = &o->audio_channel_maps[o->nb_audio_channel_maps - 1];
@@ -392,2105 +483,277 @@ static int opt_map_channel(void *optctx, const char *opt, const char *arg)
m->file_idx = m->stream_idx = -1;
if (n == 1)
m->ofile_idx = m->ostream_idx = -1;
- return 0;
- }
-
- /* normal syntax */
- n = sscanf(arg, "%d.%d.%d:%d.%d",
- &m->file_idx, &m->stream_idx, &m->channel_idx,
- &m->ofile_idx, &m->ostream_idx);
-
- if (n != 3 && n != 5) {
- av_log(NULL, AV_LOG_FATAL, "Syntax error, mapchan usage: "
- "[file.stream.channel|-1][:syncfile:syncstream]\n");
- exit_program(1);
- }
-
- if (n != 5) // only file.stream.channel specified
- m->ofile_idx = m->ostream_idx = -1;
-
- /* check input */
- if (m->file_idx < 0 || m->file_idx >= nb_input_files) {
- av_log(NULL, AV_LOG_FATAL, "mapchan: invalid input file index: %d\n",
- m->file_idx);
- exit_program(1);
- }
- if (m->stream_idx < 0 ||
- m->stream_idx >= input_files[m->file_idx]->nb_streams) {
- av_log(NULL, AV_LOG_FATAL, "mapchan: invalid input file stream index #%d.%d\n",
- m->file_idx, m->stream_idx);
- exit_program(1);
- }
- st = input_files[m->file_idx]->ctx->streams[m->stream_idx];
- if (st->codec->codec_type != AVMEDIA_TYPE_AUDIO) {
- av_log(NULL, AV_LOG_FATAL, "mapchan: stream #%d.%d is not an audio stream.\n",
- m->file_idx, m->stream_idx);
- exit_program(1);
- }
- if (m->channel_idx < 0 || m->channel_idx >= st->codec->channels) {
- av_log(NULL, AV_LOG_FATAL, "mapchan: invalid audio channel #%d.%d.%d\n",
- m->file_idx, m->stream_idx, m->channel_idx);
- exit_program(1);
- }
- return 0;
-}
-
-static int opt_sdp_file(void *optctx, const char *opt, const char *arg)
-{
- av_free(sdp_filename);
- sdp_filename = av_strdup(arg);
- return 0;
-}
-
-/**
- * Parse a metadata specifier passed as 'arg' parameter.
- * @param arg metadata string to parse
- * @param type metadata type is written here -- g(lobal)/s(tream)/c(hapter)/p(rogram)
- * @param index for type c/p, chapter/program index is written here
- * @param stream_spec for type s, the stream specifier is written here
- */
-static void parse_meta_type(char *arg, char *type, int *index, const char **stream_spec)
-{
- if (*arg) {
- *type = *arg;
- switch (*arg) {
- case 'g':
- break;
- case 's':
- if (*(++arg) && *arg != ':') {
- av_log(NULL, AV_LOG_FATAL, "Invalid metadata specifier %s.\n", arg);
- exit_program(1);
- }
- *stream_spec = *arg == ':' ? arg + 1 : "";
- break;
- case 'c':
- case 'p':
- if (*(++arg) == ':')
- *index = strtol(++arg, NULL, 0);
- break;
- default:
- av_log(NULL, AV_LOG_FATAL, "Invalid metadata type %c.\n", *arg);
- exit_program(1);
- }
- } else
- *type = 'g';
-}
-
-static int copy_metadata(char *outspec, char *inspec, AVFormatContext *oc, AVFormatContext *ic, OptionsContext *o)
-{
- AVDictionary **meta_in = NULL;
- AVDictionary **meta_out = NULL;
- int i, ret = 0;
- char type_in, type_out;
- const char *istream_spec = NULL, *ostream_spec = NULL;
- int idx_in = 0, idx_out = 0;
-
- parse_meta_type(inspec, &type_in, &idx_in, &istream_spec);
- parse_meta_type(outspec, &type_out, &idx_out, &ostream_spec);
-
- if (!ic) {
- if (type_out == 'g' || !*outspec)
- o->metadata_global_manual = 1;
- if (type_out == 's' || !*outspec)
- o->metadata_streams_manual = 1;
- if (type_out == 'c' || !*outspec)
- o->metadata_chapters_manual = 1;
- return 0;
- }
-
- if (type_in == 'g' || type_out == 'g')
- o->metadata_global_manual = 1;
- if (type_in == 's' || type_out == 's')
- o->metadata_streams_manual = 1;
- if (type_in == 'c' || type_out == 'c')
- o->metadata_chapters_manual = 1;
-
- /* ic is NULL when just disabling automatic mappings */
- if (!ic)
- return 0;
-
-#define METADATA_CHECK_INDEX(index, nb_elems, desc)\
- if ((index) < 0 || (index) >= (nb_elems)) {\
- av_log(NULL, AV_LOG_FATAL, "Invalid %s index %d while processing metadata maps.\n",\
- (desc), (index));\
- exit_program(1);\
- }
-
-#define SET_DICT(type, meta, context, index)\
- switch (type) {\
- case 'g':\
- meta = &context->metadata;\
- break;\
- case 'c':\
- METADATA_CHECK_INDEX(index, context->nb_chapters, "chapter")\
- meta = &context->chapters[index]->metadata;\
- break;\
- case 'p':\
- METADATA_CHECK_INDEX(index, context->nb_programs, "program")\
- meta = &context->programs[index]->metadata;\
- break;\
- case 's':\
- break; /* handled separately below */ \
- default: av_assert0(0);\
- }\
-
- SET_DICT(type_in, meta_in, ic, idx_in);
- SET_DICT(type_out, meta_out, oc, idx_out);
-
- /* for input streams choose first matching stream */
- if (type_in == 's') {
- for (i = 0; i < ic->nb_streams; i++) {
- if ((ret = check_stream_specifier(ic, ic->streams[i], istream_spec)) > 0) {
- meta_in = &ic->streams[i]->metadata;
- break;
- } else if (ret < 0)
- exit_program(1);
- }
- if (!meta_in) {
- av_log(NULL, AV_LOG_FATAL, "Stream specifier %s does not match any streams.\n", istream_spec);
- exit_program(1);
- }
- }
-
- if (type_out == 's') {
- for (i = 0; i < oc->nb_streams; i++) {
- if ((ret = check_stream_specifier(oc, oc->streams[i], ostream_spec)) > 0) {
- meta_out = &oc->streams[i]->metadata;
- av_dict_copy(meta_out, *meta_in, AV_DICT_DONT_OVERWRITE);
- } else if (ret < 0)
- exit_program(1);
- }
- } else
- av_dict_copy(meta_out, *meta_in, AV_DICT_DONT_OVERWRITE);
-
- return 0;
-}
-
-static int opt_recording_timestamp(void *optctx, const char *opt, const char *arg)
-{
- OptionsContext *o = optctx;
- char buf[128];
- int64_t recording_timestamp = parse_time_or_die(opt, arg, 0) / 1E6;
- struct tm time = *gmtime((time_t*)&recording_timestamp);
- if (!strftime(buf, sizeof(buf), "creation_time=%Y-%m-%dT%H:%M:%S%z", &time))
- return -1;
- parse_option(o, "metadata", buf, options);
-
- av_log(NULL, AV_LOG_WARNING, "%s is deprecated, set the 'creation_time' metadata "
- "tag instead.\n", opt);
- return 0;
-}
-
-static AVCodec *find_codec_or_die(const char *name, enum AVMediaType type, int encoder)
-{
- const AVCodecDescriptor *desc;
- const char *codec_string = encoder ? "encoder" : "decoder";
- AVCodec *codec;
-
- codec = encoder ?
- avcodec_find_encoder_by_name(name) :
- avcodec_find_decoder_by_name(name);
-
- if (!codec && (desc = avcodec_descriptor_get_by_name(name))) {
- codec = encoder ? avcodec_find_encoder(desc->id) :
- avcodec_find_decoder(desc->id);
- if (codec)
- av_log(NULL, AV_LOG_VERBOSE, "Matched %s '%s' for codec '%s'.\n",
- codec_string, codec->name, desc->name);
- }
-
- if (!codec) {
- av_log(NULL, AV_LOG_FATAL, "Unknown %s '%s'\n", codec_string, name);
- exit_program(1);
- }
- if (codec->type != type) {
- av_log(NULL, AV_LOG_FATAL, "Invalid %s type '%s'\n", codec_string, name);
- exit_program(1);
- }
- return codec;
-}
-
-static AVCodec *choose_decoder(OptionsContext *o, AVFormatContext *s, AVStream *st)
-{
- char *codec_name = NULL;
-
- MATCH_PER_STREAM_OPT(codec_names, str, codec_name, s, st);
- if (codec_name) {
- AVCodec *codec = find_codec_or_die(codec_name, st->codec->codec_type, 0);
- st->codec->codec_id = codec->id;
- return codec;
- } else
- return avcodec_find_decoder(st->codec->codec_id);
-}
-
-/* Add all the streams from the given input file to the global
- * list of input streams. */
-static void add_input_streams(OptionsContext *o, AVFormatContext *ic)
-{
- int i, ret;
-
- for (i = 0; i < ic->nb_streams; i++) {
- AVStream *st = ic->streams[i];
- AVCodecContext *dec = st->codec;
- InputStream *ist = av_mallocz(sizeof(*ist));
- char *framerate = NULL, *hwaccel = NULL, *hwaccel_device = NULL;
- char *codec_tag = NULL;
- char *next;
- char *discard_str = NULL;
- const AVOption *discard_opt = av_opt_find(dec, "skip_frame", NULL, 0, 0);
-
- if (!ist)
- exit_program(1);
-
- GROW_ARRAY(input_streams, nb_input_streams);
- input_streams[nb_input_streams - 1] = ist;
-
- ist->st = st;
- ist->file_index = nb_input_files;
- ist->discard = 1;
- st->discard = AVDISCARD_ALL;
- ist->nb_samples = 0;
- ist->min_pts = INT64_MAX;
- ist->max_pts = INT64_MIN;
-
- ist->ts_scale = 1.0;
- MATCH_PER_STREAM_OPT(ts_scale, dbl, ist->ts_scale, ic, st);
-
- ist->autorotate = 1;
- MATCH_PER_STREAM_OPT(autorotate, i, ist->autorotate, ic, st);
-
- MATCH_PER_STREAM_OPT(codec_tags, str, codec_tag, ic, st);
- if (codec_tag) {
- uint32_t tag = strtol(codec_tag, &next, 0);
- if (*next)
- tag = AV_RL32(codec_tag);
- st->codec->codec_tag = tag;
- }
-
- ist->dec = choose_decoder(o, ic, st);
- ist->decoder_opts = filter_codec_opts(o->g->codec_opts, ist->st->codec->codec_id, ic, st, ist->dec);
-
- ist->reinit_filters = -1;
- MATCH_PER_STREAM_OPT(reinit_filters, i, ist->reinit_filters, ic, st);
-
- MATCH_PER_STREAM_OPT(discard, str, discard_str, ic, st);
- ist->user_set_discard = AVDISCARD_NONE;
- if (discard_str && av_opt_eval_int(dec, discard_opt, discard_str, &ist->user_set_discard) < 0) {
- av_log(NULL, AV_LOG_ERROR, "Error parsing discard %s.\n",
- discard_str);
- exit_program(1);
- }
-
- ist->filter_in_rescale_delta_last = AV_NOPTS_VALUE;
-
- ist->dec_ctx = avcodec_alloc_context3(ist->dec);
- if (!ist->dec_ctx) {
- av_log(NULL, AV_LOG_ERROR, "Error allocating the decoder context.\n");
- exit_program(1);
- }
-
- ret = avcodec_copy_context(ist->dec_ctx, dec);
- if (ret < 0) {
- av_log(NULL, AV_LOG_ERROR, "Error initializing the decoder context.\n");
- exit_program(1);
- }
-
- switch (dec->codec_type) {
- case AVMEDIA_TYPE_VIDEO:
- if(!ist->dec)
- ist->dec = avcodec_find_decoder(dec->codec_id);
-#if FF_API_EMU_EDGE
- if (av_codec_get_lowres(dec)) {
- dec->flags |= CODEC_FLAG_EMU_EDGE;
- }
-#endif
-
- ist->resample_height = ist->dec_ctx->height;
- ist->resample_width = ist->dec_ctx->width;
- ist->resample_pix_fmt = ist->dec_ctx->pix_fmt;
-
- MATCH_PER_STREAM_OPT(frame_rates, str, framerate, ic, st);
- if (framerate && av_parse_video_rate(&ist->framerate,
- framerate) < 0) {
- av_log(NULL, AV_LOG_ERROR, "Error parsing framerate %s.\n",
- framerate);
- exit_program(1);
- }
-
- ist->top_field_first = -1;
- MATCH_PER_STREAM_OPT(top_field_first, i, ist->top_field_first, ic, st);
-
- MATCH_PER_STREAM_OPT(hwaccels, str, hwaccel, ic, st);
- if (hwaccel) {
- if (!strcmp(hwaccel, "none"))
- ist->hwaccel_id = HWACCEL_NONE;
- else if (!strcmp(hwaccel, "auto"))
- ist->hwaccel_id = HWACCEL_AUTO;
- else {
- int i;
- for (i = 0; hwaccels[i].name; i++) {
- if (!strcmp(hwaccels[i].name, hwaccel)) {
- ist->hwaccel_id = hwaccels[i].id;
- break;
- }
- }
-
- if (!ist->hwaccel_id) {
- av_log(NULL, AV_LOG_FATAL, "Unrecognized hwaccel: %s.\n",
- hwaccel);
- av_log(NULL, AV_LOG_FATAL, "Supported hwaccels: ");
- for (i = 0; hwaccels[i].name; i++)
- av_log(NULL, AV_LOG_FATAL, "%s ", hwaccels[i].name);
- av_log(NULL, AV_LOG_FATAL, "\n");
- exit_program(1);
- }
- }
- }
-
- MATCH_PER_STREAM_OPT(hwaccel_devices, str, hwaccel_device, ic, st);
- if (hwaccel_device) {
- ist->hwaccel_device = av_strdup(hwaccel_device);
- if (!ist->hwaccel_device)
- exit_program(1);
- }
- ist->hwaccel_pix_fmt = AV_PIX_FMT_NONE;
-
- break;
- case AVMEDIA_TYPE_AUDIO:
- ist->guess_layout_max = INT_MAX;
- MATCH_PER_STREAM_OPT(guess_layout_max, i, ist->guess_layout_max, ic, st);
- guess_input_channel_layout(ist);
-
- ist->resample_sample_fmt = ist->dec_ctx->sample_fmt;
- ist->resample_sample_rate = ist->dec_ctx->sample_rate;
- ist->resample_channels = ist->dec_ctx->channels;
- ist->resample_channel_layout = ist->dec_ctx->channel_layout;
-
- break;
- case AVMEDIA_TYPE_DATA:
- case AVMEDIA_TYPE_SUBTITLE: {
- char *canvas_size = NULL;
- if(!ist->dec)
- ist->dec = avcodec_find_decoder(dec->codec_id);
- MATCH_PER_STREAM_OPT(fix_sub_duration, i, ist->fix_sub_duration, ic, st);
- MATCH_PER_STREAM_OPT(canvas_sizes, str, canvas_size, ic, st);
- if (canvas_size &&
- av_parse_video_size(&ist->dec_ctx->width, &ist->dec_ctx->height, canvas_size) < 0) {
- av_log(NULL, AV_LOG_FATAL, "Invalid canvas size: %s.\n", canvas_size);
- exit_program(1);
- }
- break;
- }
- case AVMEDIA_TYPE_ATTACHMENT:
- case AVMEDIA_TYPE_UNKNOWN:
- break;
- default:
- abort();
- }
- }
-}
-
-static void assert_file_overwrite(const char *filename)
-{
- if (file_overwrite && no_file_overwrite) {
- fprintf(stderr, "Error, both -y and -n supplied. Exiting.\n");
- exit_program(1);
- }
-
- if (!file_overwrite) {
- const char *proto_name = avio_find_protocol_name(filename);
- if (proto_name && !strcmp(proto_name, "file") && avio_check(filename, 0) == 0) {
- if (stdin_interaction && !no_file_overwrite) {
- fprintf(stderr,"File '%s' already exists. Overwrite ? [y/N] ", filename);
- fflush(stderr);
- term_exit();
- signal(SIGINT, SIG_DFL);
- if (!read_yesno()) {
- av_log(NULL, AV_LOG_FATAL, "Not overwriting - exiting\n");
- exit_program(1);
- }
- term_init();
- }
- else {
- av_log(NULL, AV_LOG_FATAL, "File '%s' already exists. Exiting.\n", filename);
- exit_program(1);
- }
- }
- }
-}
-
-static void dump_attachment(AVStream *st, const char *filename)
-{
- int ret;
- AVIOContext *out = NULL;
- AVDictionaryEntry *e;
-
- if (!st->codec->extradata_size) {
- av_log(NULL, AV_LOG_WARNING, "No extradata to dump in stream #%d:%d.\n",
- nb_input_files - 1, st->index);
- return;
- }
- if (!*filename && (e = av_dict_get(st->metadata, "filename", NULL, 0)))
- filename = e->value;
- if (!*filename) {
- av_log(NULL, AV_LOG_FATAL, "No filename specified and no 'filename' tag"
- "in stream #%d:%d.\n", nb_input_files - 1, st->index);
- exit_program(1);
- }
-
- assert_file_overwrite(filename);
-
- if ((ret = avio_open2(&out, filename, AVIO_FLAG_WRITE, &int_cb, NULL)) < 0) {
- av_log(NULL, AV_LOG_FATAL, "Could not open file %s for writing.\n",
- filename);
- exit_program(1);
- }
-
- avio_write(out, st->codec->extradata, st->codec->extradata_size);
- avio_flush(out);
- avio_close(out);
-}
-
-static int open_input_file(OptionsContext *o, const char *filename)
-{
- InputFile *f;
- AVFormatContext *ic;
- AVInputFormat *file_iformat = NULL;
- int err, i, ret;
- int64_t timestamp;
- AVDictionary **opts;
- AVDictionary *unused_opts = NULL;
- AVDictionaryEntry *e = NULL;
- int orig_nb_streams; // number of streams before avformat_find_stream_info
- char * video_codec_name = NULL;
- char * audio_codec_name = NULL;
- char *subtitle_codec_name = NULL;
- char * data_codec_name = NULL;
- int scan_all_pmts_set = 0;
-
- if (o->format) {
- if (!(file_iformat = av_find_input_format(o->format))) {
- av_log(NULL, AV_LOG_FATAL, "Unknown input format: '%s'\n", o->format);
- exit_program(1);
- }
- }
-
- if (!strcmp(filename, "-"))
- filename = "pipe:";
-
- stdin_interaction &= strncmp(filename, "pipe:", 5) &&
- strcmp(filename, "/dev/stdin");
-
- /* get default parameters from command line */
- ic = avformat_alloc_context();
- if (!ic) {
- print_error(filename, AVERROR(ENOMEM));
- exit_program(1);
- }
- if (o->nb_audio_sample_rate) {
- av_dict_set_int(&o->g->format_opts, "sample_rate", o->audio_sample_rate[o->nb_audio_sample_rate - 1].u.i, 0);
- }
- if (o->nb_audio_channels) {
- /* because we set audio_channels based on both the "ac" and
- * "channel_layout" options, we need to check that the specified
- * demuxer actually has the "channels" option before setting it */
- if (file_iformat && file_iformat->priv_class &&
- av_opt_find(&file_iformat->priv_class, "channels", NULL, 0,
- AV_OPT_SEARCH_FAKE_OBJ)) {
- av_dict_set_int(&o->g->format_opts, "channels", o->audio_channels[o->nb_audio_channels - 1].u.i, 0);
- }
- }
- if (o->nb_frame_rates) {
- /* set the format-level framerate option;
- * this is important for video grabbers, e.g. x11 */
- if (file_iformat && file_iformat->priv_class &&
- av_opt_find(&file_iformat->priv_class, "framerate", NULL, 0,
- AV_OPT_SEARCH_FAKE_OBJ)) {
- av_dict_set(&o->g->format_opts, "framerate",
- o->frame_rates[o->nb_frame_rates - 1].u.str, 0);
- }
- }
- if (o->nb_frame_sizes) {
- av_dict_set(&o->g->format_opts, "video_size", o->frame_sizes[o->nb_frame_sizes - 1].u.str, 0);
- }
- if (o->nb_frame_pix_fmts)
- av_dict_set(&o->g->format_opts, "pixel_format", o->frame_pix_fmts[o->nb_frame_pix_fmts - 1].u.str, 0);
-
- MATCH_PER_TYPE_OPT(codec_names, str, video_codec_name, ic, "v");
- MATCH_PER_TYPE_OPT(codec_names, str, audio_codec_name, ic, "a");
- MATCH_PER_TYPE_OPT(codec_names, str, subtitle_codec_name, ic, "s");
- MATCH_PER_TYPE_OPT(codec_names, str, data_codec_name, ic, "d");
-
- ic->video_codec_id = video_codec_name ?
- find_codec_or_die(video_codec_name , AVMEDIA_TYPE_VIDEO , 0)->id : AV_CODEC_ID_NONE;
- ic->audio_codec_id = audio_codec_name ?
- find_codec_or_die(audio_codec_name , AVMEDIA_TYPE_AUDIO , 0)->id : AV_CODEC_ID_NONE;
- ic->subtitle_codec_id= subtitle_codec_name ?
- find_codec_or_die(subtitle_codec_name, AVMEDIA_TYPE_SUBTITLE, 0)->id : AV_CODEC_ID_NONE;
- ic->data_codec_id = data_codec_name ?
- find_codec_or_die(data_codec_name, AVMEDIA_TYPE_DATA, 0)->id : AV_CODEC_ID_NONE;
-
- if (video_codec_name)
- av_format_set_video_codec (ic, find_codec_or_die(video_codec_name , AVMEDIA_TYPE_VIDEO , 0));
- if (audio_codec_name)
- av_format_set_audio_codec (ic, find_codec_or_die(audio_codec_name , AVMEDIA_TYPE_AUDIO , 0));
- if (subtitle_codec_name)
- av_format_set_subtitle_codec(ic, find_codec_or_die(subtitle_codec_name, AVMEDIA_TYPE_SUBTITLE, 0));
- if (data_codec_name)
- av_format_set_data_codec(ic, find_codec_or_die(data_codec_name, AVMEDIA_TYPE_DATA, 0));
-
- ic->flags |= AVFMT_FLAG_NONBLOCK;
- ic->interrupt_callback = int_cb;
-
- if (!av_dict_get(o->g->format_opts, "scan_all_pmts", NULL, AV_DICT_MATCH_CASE)) {
- av_dict_set(&o->g->format_opts, "scan_all_pmts", "1", AV_DICT_DONT_OVERWRITE);
- scan_all_pmts_set = 1;
- }
- /* open the input file with generic avformat function */
- err = avformat_open_input(&ic, filename, file_iformat, &o->g->format_opts);
- if (err < 0) {
- print_error(filename, err);
- exit_program(1);
- }
- if (scan_all_pmts_set)
- av_dict_set(&o->g->format_opts, "scan_all_pmts", NULL, AV_DICT_MATCH_CASE);
- remove_avoptions(&o->g->format_opts, o->g->codec_opts);
- assert_avoptions(o->g->format_opts);
-
- /* apply forced codec ids */
- for (i = 0; i < ic->nb_streams; i++)
- choose_decoder(o, ic, ic->streams[i]);
-
- /* Set AVCodecContext options for avformat_find_stream_info */
- opts = setup_find_stream_info_opts(ic, o->g->codec_opts);
- orig_nb_streams = ic->nb_streams;
-
- /* If not enough info to get the stream parameters, we decode the
- first frames to get it. (used in mpeg case for example) */
- ret = avformat_find_stream_info(ic, opts);
- if (ret < 0) {
- av_log(NULL, AV_LOG_FATAL, "%s: could not find codec parameters\n", filename);
- if (ic->nb_streams == 0) {
- avformat_close_input(&ic);
- exit_program(1);
- }
- }
-
- if (o->start_time_eof != AV_NOPTS_VALUE) {
- if (ic->duration>0) {
- o->start_time = o->start_time_eof + ic->duration;
- } else
- av_log(NULL, AV_LOG_WARNING, "Cannot use -sseof, duration of %s not known\n", filename);
- }
- timestamp = (o->start_time == AV_NOPTS_VALUE) ? 0 : o->start_time;
- /* add the stream start time */
- if (!o->seek_timestamp && ic->start_time != AV_NOPTS_VALUE)
- timestamp += ic->start_time;
-
- /* if seeking requested, we execute it */
- if (o->start_time != AV_NOPTS_VALUE) {
- int64_t seek_timestamp = timestamp;
-
- if (!(ic->iformat->flags & AVFMT_SEEK_TO_PTS)) {
- int dts_heuristic = 0;
- for (i=0; inb_streams; i++) {
- AVCodecContext *avctx = ic->streams[i]->codec;
- if (avctx->has_b_frames)
- dts_heuristic = 1;
- }
- if (dts_heuristic) {
- seek_timestamp -= 3*AV_TIME_BASE / 23;
- }
- }
- ret = avformat_seek_file(ic, -1, INT64_MIN, seek_timestamp, seek_timestamp, 0);
- if (ret < 0) {
- av_log(NULL, AV_LOG_WARNING, "%s: could not seek to position %0.3f\n",
- filename, (double)timestamp / AV_TIME_BASE);
- }
- }
-
- /* update the current parameters so that they match the one of the input stream */
- add_input_streams(o, ic);
-
- /* dump the file content */
- av_dump_format(ic, nb_input_files, filename, 0);
-
- GROW_ARRAY(input_files, nb_input_files);
- f = av_mallocz(sizeof(*f));
- if (!f)
- exit_program(1);
- input_files[nb_input_files - 1] = f;
-
- f->ctx = ic;
- f->ist_index = nb_input_streams - ic->nb_streams;
- f->start_time = o->start_time;
- f->recording_time = o->recording_time;
- f->input_ts_offset = o->input_ts_offset;
- f->ts_offset = o->input_ts_offset - (copy_ts ? (start_at_zero && ic->start_time != AV_NOPTS_VALUE ? ic->start_time : 0) : timestamp);
- f->nb_streams = ic->nb_streams;
- f->rate_emu = o->rate_emu;
- f->accurate_seek = o->accurate_seek;
- f->loop = o->loop;
- f->duration = 0;
- f->time_base = (AVRational){ 1, 1 };
-#if HAVE_PTHREADS
- f->thread_queue_size = o->thread_queue_size > 0 ? o->thread_queue_size : 8;
-#endif
-
- /* check if all codec options have been used */
- unused_opts = strip_specifiers(o->g->codec_opts);
- for (i = f->ist_index; i < nb_input_streams; i++) {
- e = NULL;
- while ((e = av_dict_get(input_streams[i]->decoder_opts, "", e,
- AV_DICT_IGNORE_SUFFIX)))
- av_dict_set(&unused_opts, e->key, NULL, 0);
- }
-
- e = NULL;
- while ((e = av_dict_get(unused_opts, "", e, AV_DICT_IGNORE_SUFFIX))) {
- const AVClass *class = avcodec_get_class();
- const AVOption *option = av_opt_find(&class, e->key, NULL, 0,
- AV_OPT_SEARCH_CHILDREN | AV_OPT_SEARCH_FAKE_OBJ);
- const AVClass *fclass = avformat_get_class();
- const AVOption *foption = av_opt_find(&fclass, e->key, NULL, 0,
- AV_OPT_SEARCH_CHILDREN | AV_OPT_SEARCH_FAKE_OBJ);
- if (!option || foption)
- continue;
-
-
- if (!(option->flags & AV_OPT_FLAG_DECODING_PARAM)) {
- av_log(NULL, AV_LOG_ERROR, "Codec AVOption %s (%s) specified for "
- "input file #%d (%s) is not a decoding option.\n", e->key,
- option->help ? option->help : "", nb_input_files - 1,
- filename);
- exit_program(1);
- }
-
- av_log(NULL, AV_LOG_WARNING, "Codec AVOption %s (%s) specified for "
- "input file #%d (%s) has not been used for any stream. The most "
- "likely reason is either wrong type (e.g. a video option with "
- "no video streams) or that it is a private option of some decoder "
- "which was not actually used for any stream.\n", e->key,
- option->help ? option->help : "", nb_input_files - 1, filename);
- }
- av_dict_free(&unused_opts);
-
- for (i = 0; i < o->nb_dump_attachment; i++) {
- int j;
-
- for (j = 0; j < ic->nb_streams; j++) {
- AVStream *st = ic->streams[j];
-
- if (check_stream_specifier(ic, st, o->dump_attachment[i].specifier) == 1)
- dump_attachment(st, o->dump_attachment[i].u.str);
- }
- }
-
- for (i = 0; i < orig_nb_streams; i++)
- av_dict_free(&opts[i]);
- av_freep(&opts);
-
- input_stream_potentially_available = 1;
-
- return 0;
-}
-
-static uint8_t *get_line(AVIOContext *s)
-{
- AVIOContext *line;
- uint8_t *buf;
- char c;
-
- if (avio_open_dyn_buf(&line) < 0) {
- av_log(NULL, AV_LOG_FATAL, "Could not alloc buffer for reading preset.\n");
- exit_program(1);
- }
-
- while ((c = avio_r8(s)) && c != '\n')
- avio_w8(line, c);
- avio_w8(line, 0);
- avio_close_dyn_buf(line, &buf);
-
- return buf;
-}
-
-static int get_preset_file_2(const char *preset_name, const char *codec_name, AVIOContext **s)
-{
- int i, ret = -1;
- char filename[1000];
- const char *base[3] = { getenv("AVCONV_DATADIR"),
- getenv("HOME"),
- AVCONV_DATADIR,
- };
-
- for (i = 0; i < FF_ARRAY_ELEMS(base) && ret < 0; i++) {
- if (!base[i])
- continue;
- if (codec_name) {
- snprintf(filename, sizeof(filename), "%s%s/%s-%s.avpreset", base[i],
- i != 1 ? "" : "/.avconv", codec_name, preset_name);
- ret = avio_open2(s, filename, AVIO_FLAG_READ, &int_cb, NULL);
- }
- if (ret < 0) {
- snprintf(filename, sizeof(filename), "%s%s/%s.avpreset", base[i],
- i != 1 ? "" : "/.avconv", preset_name);
- ret = avio_open2(s, filename, AVIO_FLAG_READ, &int_cb, NULL);
- }
- }
- return ret;
-}
-
-static void choose_encoder(OptionsContext *o, AVFormatContext *s, OutputStream *ost)
-{
- char *codec_name = NULL;
-
- MATCH_PER_STREAM_OPT(codec_names, str, codec_name, s, ost->st);
- if (!codec_name) {
- ost->st->codec->codec_id = av_guess_codec(s->oformat, NULL, s->filename,
- NULL, ost->st->codec->codec_type);
- ost->enc = avcodec_find_encoder(ost->st->codec->codec_id);
- } else if (!strcmp(codec_name, "copy"))
- ost->stream_copy = 1;
- else {
- ost->enc = find_codec_or_die(codec_name, ost->st->codec->codec_type, 1);
- ost->st->codec->codec_id = ost->enc->id;
- }
-}
-
-static OutputStream *new_output_stream(OptionsContext *o, AVFormatContext *oc, enum AVMediaType type, int source_index)
-{
- OutputStream *ost;
- AVStream *st = avformat_new_stream(oc, NULL);
- int idx = oc->nb_streams - 1, ret = 0;
- char *bsf = NULL, *next, *codec_tag = NULL;
- AVBitStreamFilterContext *bsfc, *bsfc_prev = NULL;
- double qscale = -1;
- int i;
-
- if (!st) {
- av_log(NULL, AV_LOG_FATAL, "Could not alloc stream.\n");
- exit_program(1);
- }
-
- if (oc->nb_streams - 1 < o->nb_streamid_map)
- st->id = o->streamid_map[oc->nb_streams - 1];
-
- GROW_ARRAY(output_streams, nb_output_streams);
- if (!(ost = av_mallocz(sizeof(*ost))))
- exit_program(1);
- output_streams[nb_output_streams - 1] = ost;
-
- ost->file_index = nb_output_files - 1;
- ost->index = idx;
- ost->st = st;
- st->codec->codec_type = type;
- choose_encoder(o, oc, ost);
-
- ost->enc_ctx = avcodec_alloc_context3(ost->enc);
- if (!ost->enc_ctx) {
- av_log(NULL, AV_LOG_ERROR, "Error allocating the encoding context.\n");
- exit_program(1);
- }
- ost->enc_ctx->codec_type = type;
-
- if (ost->enc) {
- AVIOContext *s = NULL;
- char *buf = NULL, *arg = NULL, *preset = NULL;
-
- ost->encoder_opts = filter_codec_opts(o->g->codec_opts, ost->enc->id, oc, st, ost->enc);
-
- MATCH_PER_STREAM_OPT(presets, str, preset, oc, st);
- if (preset && (!(ret = get_preset_file_2(preset, ost->enc->name, &s)))) {
- do {
- buf = get_line(s);
- if (!buf[0] || buf[0] == '#') {
- av_free(buf);
- continue;
- }
- if (!(arg = strchr(buf, '='))) {
- av_log(NULL, AV_LOG_FATAL, "Invalid line found in the preset file.\n");
- exit_program(1);
- }
- *arg++ = 0;
- av_dict_set(&ost->encoder_opts, buf, arg, AV_DICT_DONT_OVERWRITE);
- av_free(buf);
- } while (!s->eof_reached);
- avio_closep(&s);
- }
- if (ret) {
- av_log(NULL, AV_LOG_FATAL,
- "Preset %s specified for stream %d:%d, but could not be opened.\n",
- preset, ost->file_index, ost->index);
- exit_program(1);
- }
- } else {
- ost->encoder_opts = filter_codec_opts(o->g->codec_opts, AV_CODEC_ID_NONE, oc, st, NULL);
- }
-
- ost->max_frames = INT64_MAX;
- MATCH_PER_STREAM_OPT(max_frames, i64, ost->max_frames, oc, st);
- for (i = 0; inb_max_frames; i++) {
- char *p = o->max_frames[i].specifier;
- if (!*p && type != AVMEDIA_TYPE_VIDEO) {
- av_log(NULL, AV_LOG_WARNING, "Applying unspecific -frames to non video streams, maybe you meant -vframes ?\n");
- break;
- }
- }
-
- ost->copy_prior_start = -1;
- MATCH_PER_STREAM_OPT(copy_prior_start, i, ost->copy_prior_start, oc ,st);
-
- MATCH_PER_STREAM_OPT(bitstream_filters, str, bsf, oc, st);
- while (bsf) {
- char *arg = NULL;
- if (next = strchr(bsf, ','))
- *next++ = 0;
- if (arg = strchr(bsf, '='))
- *arg++ = 0;
- if (!(bsfc = av_bitstream_filter_init(bsf))) {
- av_log(NULL, AV_LOG_FATAL, "Unknown bitstream filter %s\n", bsf);
- exit_program(1);
- }
- if (bsfc_prev)
- bsfc_prev->next = bsfc;
- else
- ost->bitstream_filters = bsfc;
- if (arg)
- if (!(bsfc->args = av_strdup(arg))) {
- av_log(NULL, AV_LOG_FATAL, "Bitstream filter memory allocation failed\n");
- exit_program(1);
- }
-
- bsfc_prev = bsfc;
- bsf = next;
- }
-
- MATCH_PER_STREAM_OPT(codec_tags, str, codec_tag, oc, st);
- if (codec_tag) {
- uint32_t tag = strtol(codec_tag, &next, 0);
- if (*next)
- tag = AV_RL32(codec_tag);
- ost->st->codec->codec_tag =
- ost->enc_ctx->codec_tag = tag;
- }
-
- MATCH_PER_STREAM_OPT(qscale, dbl, qscale, oc, st);
- if (qscale >= 0) {
- ost->enc_ctx->flags |= AV_CODEC_FLAG_QSCALE;
- ost->enc_ctx->global_quality = FF_QP2LAMBDA * qscale;
- }
-
- MATCH_PER_STREAM_OPT(disposition, str, ost->disposition, oc, st);
- ost->disposition = av_strdup(ost->disposition);
-
- if (oc->oformat->flags & AVFMT_GLOBALHEADER)
- ost->enc_ctx->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;
-
- av_dict_copy(&ost->sws_dict, o->g->sws_dict, 0);
-
- av_dict_copy(&ost->swr_opts, o->g->swr_opts, 0);
- if (ost->enc && av_get_exact_bits_per_sample(ost->enc->id) == 24)
- av_dict_set(&ost->swr_opts, "output_sample_bits", "24", 0);
-
- av_dict_copy(&ost->resample_opts, o->g->resample_opts, 0);
-
- ost->source_index = source_index;
- if (source_index >= 0) {
- ost->sync_ist = input_streams[source_index];
- input_streams[source_index]->discard = 0;
- input_streams[source_index]->st->discard = input_streams[source_index]->user_set_discard;
- }
- ost->last_mux_dts = AV_NOPTS_VALUE;
-
- return ost;
-}
-
-static void parse_matrix_coeffs(uint16_t *dest, const char *str)
-{
- int i;
- const char *p = str;
- for (i = 0;; i++) {
- dest[i] = atoi(p);
- if (i == 63)
- break;
- p = strchr(p, ',');
- if (!p) {
- av_log(NULL, AV_LOG_FATAL, "Syntax error in matrix \"%s\" at coeff %d\n", str, i);
- exit_program(1);
- }
- p++;
- }
-}
-
-/* read file contents into a string */
-static uint8_t *read_file(const char *filename)
-{
- AVIOContext *pb = NULL;
- AVIOContext *dyn_buf = NULL;
- int ret = avio_open(&pb, filename, AVIO_FLAG_READ);
- uint8_t buf[1024], *str;
-
- if (ret < 0) {
- av_log(NULL, AV_LOG_ERROR, "Error opening file %s.\n", filename);
- return NULL;
- }
-
- ret = avio_open_dyn_buf(&dyn_buf);
- if (ret < 0) {
- avio_closep(&pb);
- return NULL;
- }
- while ((ret = avio_read(pb, buf, sizeof(buf))) > 0)
- avio_write(dyn_buf, buf, ret);
- avio_w8(dyn_buf, 0);
- avio_closep(&pb);
-
- ret = avio_close_dyn_buf(dyn_buf, &str);
- if (ret < 0)
- return NULL;
- return str;
-}
-
-static char *get_ost_filters(OptionsContext *o, AVFormatContext *oc,
- OutputStream *ost)
-{
- AVStream *st = ost->st;
-
- if (ost->filters_script && ost->filters) {
- av_log(NULL, AV_LOG_ERROR, "Both -filter and -filter_script set for "
- "output stream #%d:%d.\n", nb_output_files, st->index);
- exit_program(1);
- }
-
- if (ost->filters_script)
- return read_file(ost->filters_script);
- else if (ost->filters)
- return av_strdup(ost->filters);
-
- return av_strdup(st->codec->codec_type == AVMEDIA_TYPE_VIDEO ?
- "null" : "anull");
-}
-
-static void check_streamcopy_filters(OptionsContext *o, AVFormatContext *oc,
- const OutputStream *ost, enum AVMediaType type)
-{
- if (ost->filters_script || ost->filters) {
- av_log(NULL, AV_LOG_ERROR,
- "%s '%s' was defined for %s output stream %d:%d but codec copy was selected.\n"
- "Filtering and streamcopy cannot be used together.\n",
- ost->filters ? "Filtergraph" : "Filtergraph script",
- ost->filters ? ost->filters : ost->filters_script,
- av_get_media_type_string(type), ost->file_index, ost->index);
- exit_program(1);
- }
-}
-
-static OutputStream *new_video_stream(OptionsContext *o, AVFormatContext *oc, int source_index)
-{
- AVStream *st;
- OutputStream *ost;
- AVCodecContext *video_enc;
- char *frame_rate = NULL, *frame_aspect_ratio = NULL;
-
- ost = new_output_stream(o, oc, AVMEDIA_TYPE_VIDEO, source_index);
- st = ost->st;
- video_enc = ost->enc_ctx;
-
- MATCH_PER_STREAM_OPT(frame_rates, str, frame_rate, oc, st);
- if (frame_rate && av_parse_video_rate(&ost->frame_rate, frame_rate) < 0) {
- av_log(NULL, AV_LOG_FATAL, "Invalid framerate value: %s\n", frame_rate);
- exit_program(1);
- }
- if (frame_rate && video_sync_method == VSYNC_PASSTHROUGH)
- av_log(NULL, AV_LOG_ERROR, "Using -vsync 0 and -r can produce invalid output files\n");
-
- MATCH_PER_STREAM_OPT(frame_aspect_ratios, str, frame_aspect_ratio, oc, st);
- if (frame_aspect_ratio) {
- AVRational q;
- if (av_parse_ratio(&q, frame_aspect_ratio, 255, 0, NULL) < 0 ||
- q.num <= 0 || q.den <= 0) {
- av_log(NULL, AV_LOG_FATAL, "Invalid aspect ratio: %s\n", frame_aspect_ratio);
- exit_program(1);
- }
- ost->frame_aspect_ratio = q;
- }
-
- MATCH_PER_STREAM_OPT(filter_scripts, str, ost->filters_script, oc, st);
- MATCH_PER_STREAM_OPT(filters, str, ost->filters, oc, st);
-
- if (!ost->stream_copy) {
- const char *p = NULL;
- char *frame_size = NULL;
- char *frame_pix_fmt = NULL;
- char *intra_matrix = NULL, *inter_matrix = NULL;
- char *chroma_intra_matrix = NULL;
- int do_pass = 0;
- int i;
-
- MATCH_PER_STREAM_OPT(frame_sizes, str, frame_size, oc, st);
- if (frame_size && av_parse_video_size(&video_enc->width, &video_enc->height, frame_size) < 0) {
- av_log(NULL, AV_LOG_FATAL, "Invalid frame size: %s.\n", frame_size);
- exit_program(1);
- }
-
- video_enc->bits_per_raw_sample = frame_bits_per_raw_sample;
- MATCH_PER_STREAM_OPT(frame_pix_fmts, str, frame_pix_fmt, oc, st);
- if (frame_pix_fmt && *frame_pix_fmt == '+') {
- ost->keep_pix_fmt = 1;
- if (!*++frame_pix_fmt)
- frame_pix_fmt = NULL;
- }
- if (frame_pix_fmt && (video_enc->pix_fmt = av_get_pix_fmt(frame_pix_fmt)) == AV_PIX_FMT_NONE) {
- av_log(NULL, AV_LOG_FATAL, "Unknown pixel format requested: %s.\n", frame_pix_fmt);
- exit_program(1);
- }
- st->sample_aspect_ratio = video_enc->sample_aspect_ratio;
-
- if (intra_only)
- video_enc->gop_size = 0;
- MATCH_PER_STREAM_OPT(intra_matrices, str, intra_matrix, oc, st);
- if (intra_matrix) {
- if (!(video_enc->intra_matrix = av_mallocz(sizeof(*video_enc->intra_matrix) * 64))) {
- av_log(NULL, AV_LOG_FATAL, "Could not allocate memory for intra matrix.\n");
- exit_program(1);
- }
- parse_matrix_coeffs(video_enc->intra_matrix, intra_matrix);
- }
- MATCH_PER_STREAM_OPT(chroma_intra_matrices, str, chroma_intra_matrix, oc, st);
- if (chroma_intra_matrix) {
- uint16_t *p = av_mallocz(sizeof(*video_enc->chroma_intra_matrix) * 64);
- if (!p) {
- av_log(NULL, AV_LOG_FATAL, "Could not allocate memory for intra matrix.\n");
- exit_program(1);
- }
- av_codec_set_chroma_intra_matrix(video_enc, p);
- parse_matrix_coeffs(p, chroma_intra_matrix);
- }
- MATCH_PER_STREAM_OPT(inter_matrices, str, inter_matrix, oc, st);
- if (inter_matrix) {
- if (!(video_enc->inter_matrix = av_mallocz(sizeof(*video_enc->inter_matrix) * 64))) {
- av_log(NULL, AV_LOG_FATAL, "Could not allocate memory for inter matrix.\n");
- exit_program(1);
- }
- parse_matrix_coeffs(video_enc->inter_matrix, inter_matrix);
- }
-
- MATCH_PER_STREAM_OPT(rc_overrides, str, p, oc, st);
- for (i = 0; p; i++) {
- int start, end, q;
- int e = sscanf(p, "%d,%d,%d", &start, &end, &q);
- if (e != 3) {
- av_log(NULL, AV_LOG_FATAL, "error parsing rc_override\n");
- exit_program(1);
- }
- video_enc->rc_override =
- av_realloc_array(video_enc->rc_override,
- i + 1, sizeof(RcOverride));
- if (!video_enc->rc_override) {
- av_log(NULL, AV_LOG_FATAL, "Could not (re)allocate memory for rc_override.\n");
- exit_program(1);
- }
- video_enc->rc_override[i].start_frame = start;
- video_enc->rc_override[i].end_frame = end;
- if (q > 0) {
- video_enc->rc_override[i].qscale = q;
- video_enc->rc_override[i].quality_factor = 1.0;
- }
- else {
- video_enc->rc_override[i].qscale = 0;
- video_enc->rc_override[i].quality_factor = -q/100.0;
- }
- p = strchr(p, '/');
- if (p) p++;
- }
- video_enc->rc_override_count = i;
-
- if (do_psnr)
- video_enc->flags|= AV_CODEC_FLAG_PSNR;
-
- /* two pass mode */
- MATCH_PER_STREAM_OPT(pass, i, do_pass, oc, st);
- if (do_pass) {
- if (do_pass & 1) {
- video_enc->flags |= AV_CODEC_FLAG_PASS1;
- av_dict_set(&ost->encoder_opts, "flags", "+pass1", AV_DICT_APPEND);
- }
- if (do_pass & 2) {
- video_enc->flags |= AV_CODEC_FLAG_PASS2;
- av_dict_set(&ost->encoder_opts, "flags", "+pass2", AV_DICT_APPEND);
- }
- }
-
- MATCH_PER_STREAM_OPT(passlogfiles, str, ost->logfile_prefix, oc, st);
- if (ost->logfile_prefix &&
- !(ost->logfile_prefix = av_strdup(ost->logfile_prefix)))
- exit_program(1);
-
- if (do_pass) {
- char logfilename[1024];
- FILE *f;
-
- snprintf(logfilename, sizeof(logfilename), "%s-%d.log",
- ost->logfile_prefix ? ost->logfile_prefix :
- DEFAULT_PASS_LOGFILENAME_PREFIX,
- i);
- if (!strcmp(ost->enc->name, "libx264")) {
- av_dict_set(&ost->encoder_opts, "stats", logfilename, AV_DICT_DONT_OVERWRITE);
- } else {
- if (video_enc->flags & AV_CODEC_FLAG_PASS2) {
- char *logbuffer = read_file(logfilename);
-
- if (!logbuffer) {
- av_log(NULL, AV_LOG_FATAL, "Error reading log file '%s' for pass-2 encoding\n",
- logfilename);
- exit_program(1);
- }
- video_enc->stats_in = logbuffer;
- }
- if (video_enc->flags & AV_CODEC_FLAG_PASS1) {
- f = av_fopen_utf8(logfilename, "wb");
- if (!f) {
- av_log(NULL, AV_LOG_FATAL,
- "Cannot write log file '%s' for pass-1 encoding: %s\n",
- logfilename, strerror(errno));
- exit_program(1);
- }
- ost->logfile = f;
- }
- }
- }
-
- MATCH_PER_STREAM_OPT(forced_key_frames, str, ost->forced_keyframes, oc, st);
- if (ost->forced_keyframes)
- ost->forced_keyframes = av_strdup(ost->forced_keyframes);
-
- MATCH_PER_STREAM_OPT(force_fps, i, ost->force_fps, oc, st);
-
- ost->top_field_first = -1;
- MATCH_PER_STREAM_OPT(top_field_first, i, ost->top_field_first, oc, st);
-
-
- ost->avfilter = get_ost_filters(o, oc, ost);
- if (!ost->avfilter)
- exit_program(1);
- } else {
- MATCH_PER_STREAM_OPT(copy_initial_nonkeyframes, i, ost->copy_initial_nonkeyframes, oc ,st);
- }
-
- if (ost->stream_copy)
- check_streamcopy_filters(o, oc, ost, AVMEDIA_TYPE_VIDEO);
-
- return ost;
-}
-
-static OutputStream *new_audio_stream(OptionsContext *o, AVFormatContext *oc, int source_index)
-{
- int n;
- AVStream *st;
- OutputStream *ost;
- AVCodecContext *audio_enc;
-
- ost = new_output_stream(o, oc, AVMEDIA_TYPE_AUDIO, source_index);
- st = ost->st;
-
- audio_enc = ost->enc_ctx;
- audio_enc->codec_type = AVMEDIA_TYPE_AUDIO;
-
- MATCH_PER_STREAM_OPT(filter_scripts, str, ost->filters_script, oc, st);
- MATCH_PER_STREAM_OPT(filters, str, ost->filters, oc, st);
-
- if (!ost->stream_copy) {
- char *sample_fmt = NULL;
-
- MATCH_PER_STREAM_OPT(audio_channels, i, audio_enc->channels, oc, st);
-
- MATCH_PER_STREAM_OPT(sample_fmts, str, sample_fmt, oc, st);
- if (sample_fmt &&
- (audio_enc->sample_fmt = av_get_sample_fmt(sample_fmt)) == AV_SAMPLE_FMT_NONE) {
- av_log(NULL, AV_LOG_FATAL, "Invalid sample format '%s'\n", sample_fmt);
- exit_program(1);
- }
-
- MATCH_PER_STREAM_OPT(audio_sample_rate, i, audio_enc->sample_rate, oc, st);
-
- MATCH_PER_STREAM_OPT(apad, str, ost->apad, oc, st);
- ost->apad = av_strdup(ost->apad);
-
- ost->avfilter = get_ost_filters(o, oc, ost);
- if (!ost->avfilter)
- exit_program(1);
-
- /* check for channel mapping for this audio stream */
- for (n = 0; n < o->nb_audio_channel_maps; n++) {
- AudioChannelMap *map = &o->audio_channel_maps[n];
- if ((map->ofile_idx == -1 || ost->file_index == map->ofile_idx) &&
- (map->ostream_idx == -1 || ost->st->index == map->ostream_idx)) {
- InputStream *ist;
-
- if (map->channel_idx == -1) {
- ist = NULL;
- } else if (ost->source_index < 0) {
- av_log(NULL, AV_LOG_FATAL, "Cannot determine input stream for channel mapping %d.%d\n",
- ost->file_index, ost->st->index);
- continue;
- } else {
- ist = input_streams[ost->source_index];
- }
-
- if (!ist || (ist->file_index == map->file_idx && ist->st->index == map->stream_idx)) {
- if (av_reallocp_array(&ost->audio_channels_map,
- ost->audio_channels_mapped + 1,
- sizeof(*ost->audio_channels_map)
- ) < 0 )
- exit_program(1);
-
- ost->audio_channels_map[ost->audio_channels_mapped++] = map->channel_idx;
- }
- }
- }
- }
-
- if (ost->stream_copy)
- check_streamcopy_filters(o, oc, ost, AVMEDIA_TYPE_AUDIO);
-
- return ost;
-}
-
-static OutputStream *new_data_stream(OptionsContext *o, AVFormatContext *oc, int source_index)
-{
- OutputStream *ost;
-
- ost = new_output_stream(o, oc, AVMEDIA_TYPE_DATA, source_index);
- if (!ost->stream_copy) {
- av_log(NULL, AV_LOG_FATAL, "Data stream encoding not supported yet (only streamcopy)\n");
- exit_program(1);
- }
-
- return ost;
-}
-
-static OutputStream *new_unknown_stream(OptionsContext *o, AVFormatContext *oc, int source_index)
-{
- OutputStream *ost;
-
- ost = new_output_stream(o, oc, AVMEDIA_TYPE_UNKNOWN, source_index);
- if (!ost->stream_copy) {
- av_log(NULL, AV_LOG_FATAL, "Unknown stream encoding not supported yet (only streamcopy)\n");
- exit_program(1);
- }
-
- return ost;
-}
-
-static OutputStream *new_attachment_stream(OptionsContext *o, AVFormatContext *oc, int source_index)
-{
- OutputStream *ost = new_output_stream(o, oc, AVMEDIA_TYPE_ATTACHMENT, source_index);
- ost->stream_copy = 1;
- ost->finished = 1;
- return ost;
-}
-
-static OutputStream *new_subtitle_stream(OptionsContext *o, AVFormatContext *oc, int source_index)
-{
- AVStream *st;
- OutputStream *ost;
- AVCodecContext *subtitle_enc;
-
- ost = new_output_stream(o, oc, AVMEDIA_TYPE_SUBTITLE, source_index);
- st = ost->st;
- subtitle_enc = ost->enc_ctx;
-
- subtitle_enc->codec_type = AVMEDIA_TYPE_SUBTITLE;
-
- MATCH_PER_STREAM_OPT(copy_initial_nonkeyframes, i, ost->copy_initial_nonkeyframes, oc, st);
-
- if (!ost->stream_copy) {
- char *frame_size = NULL;
-
- MATCH_PER_STREAM_OPT(frame_sizes, str, frame_size, oc, st);
- if (frame_size && av_parse_video_size(&subtitle_enc->width, &subtitle_enc->height, frame_size) < 0) {
- av_log(NULL, AV_LOG_FATAL, "Invalid frame size: %s.\n", frame_size);
- exit_program(1);
- }
- }
-
- return ost;
-}
-
-/* arg format is "output-stream-index:streamid-value". */
-static int opt_streamid(void *optctx, const char *opt, const char *arg)
-{
- OptionsContext *o = optctx;
- int idx;
- char *p;
- char idx_str[16];
-
- av_strlcpy(idx_str, arg, sizeof(idx_str));
- p = strchr(idx_str, ':');
- if (!p) {
- av_log(NULL, AV_LOG_FATAL,
- "Invalid value '%s' for option '%s', required syntax is 'index:value'\n",
- arg, opt);
- exit_program(1);
- }
- *p++ = '\0';
- idx = parse_number_or_die(opt, idx_str, OPT_INT, 0, MAX_STREAMS-1);
- o->streamid_map = grow_array(o->streamid_map, sizeof(*o->streamid_map), &o->nb_streamid_map, idx+1);
- o->streamid_map[idx] = parse_number_or_die(opt, p, OPT_INT, 0, INT_MAX);
- return 0;
-}
-
-static int copy_chapters(InputFile *ifile, OutputFile *ofile, int copy_metadata)
-{
- AVFormatContext *is = ifile->ctx;
- AVFormatContext *os = ofile->ctx;
- AVChapter **tmp;
- int i;
-
- tmp = av_realloc_f(os->chapters, is->nb_chapters + os->nb_chapters, sizeof(*os->chapters));
- if (!tmp)
- return AVERROR(ENOMEM);
- os->chapters = tmp;
-
- for (i = 0; i < is->nb_chapters; i++) {
- AVChapter *in_ch = is->chapters[i], *out_ch;
- int64_t start_time = (ofile->start_time == AV_NOPTS_VALUE) ? 0 : ofile->start_time;
- int64_t ts_off = av_rescale_q(start_time - ifile->ts_offset,
- AV_TIME_BASE_Q, in_ch->time_base);
- int64_t rt = (ofile->recording_time == INT64_MAX) ? INT64_MAX :
- av_rescale_q(ofile->recording_time, AV_TIME_BASE_Q, in_ch->time_base);
-
-
- if (in_ch->end < ts_off)
- continue;
- if (rt != INT64_MAX && in_ch->start > rt + ts_off)
- break;
-
- out_ch = av_mallocz(sizeof(AVChapter));
- if (!out_ch)
- return AVERROR(ENOMEM);
-
- out_ch->id = in_ch->id;
- out_ch->time_base = in_ch->time_base;
- out_ch->start = FFMAX(0, in_ch->start - ts_off);
- out_ch->end = FFMIN(rt, in_ch->end - ts_off);
-
- if (copy_metadata)
- av_dict_copy(&out_ch->metadata, in_ch->metadata, 0);
-
- os->chapters[os->nb_chapters++] = out_ch;
- }
- return 0;
-}
-
-static int read_ffserver_streams(OptionsContext *o, AVFormatContext *s, const char *filename)
-{
- int i, err;
- AVFormatContext *ic = avformat_alloc_context();
-
- ic->interrupt_callback = int_cb;
- err = avformat_open_input(&ic, filename, NULL, NULL);
- if (err < 0)
- return err;
- /* copy stream format */
- for(i=0;inb_streams;i++) {
- AVStream *st;
- OutputStream *ost;
- AVCodec *codec;
- const char *enc_config;
-
- codec = avcodec_find_encoder(ic->streams[i]->codec->codec_id);
- if (!codec) {
- av_log(s, AV_LOG_ERROR, "no encoder found for codec id %i\n", ic->streams[i]->codec->codec_id);
- return AVERROR(EINVAL);
- }
- if (codec->type == AVMEDIA_TYPE_AUDIO)
- opt_audio_codec(o, "c:a", codec->name);
- else if (codec->type == AVMEDIA_TYPE_VIDEO)
- opt_video_codec(o, "c:v", codec->name);
- ost = new_output_stream(o, s, codec->type, -1);
- st = ost->st;
-
- avcodec_get_context_defaults3(st->codec, codec);
- enc_config = av_stream_get_recommended_encoder_configuration(ic->streams[i]);
- if (enc_config) {
- AVDictionary *opts = NULL;
- av_dict_parse_string(&opts, enc_config, "=", ",", 0);
- av_opt_set_dict2(st->codec, &opts, AV_OPT_SEARCH_CHILDREN);
- av_dict_free(&opts);
- }
-
- if (st->codec->codec_type == AVMEDIA_TYPE_AUDIO && !ost->stream_copy)
- choose_sample_fmt(st, codec);
- else if (st->codec->codec_type == AVMEDIA_TYPE_VIDEO && !ost->stream_copy)
- choose_pixel_fmt(st, st->codec, codec, st->codec->pix_fmt);
- avcodec_copy_context(ost->enc_ctx, st->codec);
- if (enc_config)
- av_dict_parse_string(&ost->encoder_opts, enc_config, "=", ",", 0);
- }
-
- avformat_close_input(&ic);
- return err;
-}
-
-static void init_output_filter(OutputFilter *ofilter, OptionsContext *o,
- AVFormatContext *oc)
-{
- OutputStream *ost;
-
- switch (ofilter->type) {
- case AVMEDIA_TYPE_VIDEO: ost = new_video_stream(o, oc, -1); break;
- case AVMEDIA_TYPE_AUDIO: ost = new_audio_stream(o, oc, -1); break;
- default:
- av_log(NULL, AV_LOG_FATAL, "Only video and audio filters are supported "
- "currently.\n");
- exit_program(1);
- }
-
- ost->source_index = -1;
- ost->filter = ofilter;
-
- ofilter->ost = ost;
-
- if (ost->stream_copy) {
- av_log(NULL, AV_LOG_ERROR, "Streamcopy requested for output stream %d:%d, "
- "which is fed from a complex filtergraph. Filtering and streamcopy "
- "cannot be used together.\n", ost->file_index, ost->index);
- exit_program(1);
- }
-
- if (ost->avfilter && (ost->filters || ost->filters_script)) {
- const char *opt = ost->filters ? "-vf/-af/-filter" : "-filter_script";
- av_log(NULL, AV_LOG_ERROR,
- "%s '%s' was specified through the %s option "
- "for output stream %d:%d, which is fed from a complex filtergraph.\n"
- "%s and -filter_complex cannot be used together for the same stream.\n",
- ost->filters ? "Filtergraph" : "Filtergraph script",
- ost->filters ? ost->filters : ost->filters_script,
- opt, ost->file_index, ost->index, opt);
- exit_program(1);
- }
-
- avfilter_inout_free(&ofilter->out_tmp);
-}
-
-static int init_complex_filters(void)
-{
- int i, ret = 0;
-
- for (i = 0; i < nb_filtergraphs; i++) {
- ret = init_complex_filtergraph(filtergraphs[i]);
- if (ret < 0)
- return ret;
- }
- return 0;
-}
-
-static int configure_complex_filters(void)
-{
- int i, ret = 0;
-
- for (i = 0; i < nb_filtergraphs; i++)
- if (!filtergraphs[i]->graph &&
- (ret = configure_filtergraph(filtergraphs[i])) < 0)
- return ret;
- return 0;
-}
-
-static int open_output_file(OptionsContext *o, const char *filename)
-{
- AVFormatContext *oc;
- int i, j, err;
- AVOutputFormat *file_oformat;
- OutputFile *of;
- OutputStream *ost;
- InputStream *ist;
- AVDictionary *unused_opts = NULL;
- AVDictionaryEntry *e = NULL;
-
-
- if (o->stop_time != INT64_MAX && o->recording_time != INT64_MAX) {
- o->stop_time = INT64_MAX;
- av_log(NULL, AV_LOG_WARNING, "-t and -to cannot be used together; using -t.\n");
- }
-
- if (o->stop_time != INT64_MAX && o->recording_time == INT64_MAX) {
- int64_t start_time = o->start_time == AV_NOPTS_VALUE ? 0 : o->start_time;
- if (o->stop_time <= start_time) {
- av_log(NULL, AV_LOG_ERROR, "-to value smaller than -ss; aborting.\n");
- exit_program(1);
- } else {
- o->recording_time = o->stop_time - start_time;
- }
- }
-
- GROW_ARRAY(output_files, nb_output_files);
- of = av_mallocz(sizeof(*of));
- if (!of)
- exit_program(1);
- output_files[nb_output_files - 1] = of;
-
- of->ost_index = nb_output_streams;
- of->recording_time = o->recording_time;
- of->start_time = o->start_time;
- of->limit_filesize = o->limit_filesize;
- of->shortest = o->shortest;
- av_dict_copy(&of->opts, o->g->format_opts, 0);
-
- if (!strcmp(filename, "-"))
- filename = "pipe:";
-
- err = avformat_alloc_output_context2(&oc, NULL, o->format, filename);
- if (!oc) {
- print_error(filename, err);
- exit_program(1);
- }
-
- of->ctx = oc;
- if (o->recording_time != INT64_MAX)
- oc->duration = o->recording_time;
-
- file_oformat= oc->oformat;
- oc->interrupt_callback = int_cb;
-
- /* create streams for all unlabeled output pads */
- for (i = 0; i < nb_filtergraphs; i++) {
- FilterGraph *fg = filtergraphs[i];
- for (j = 0; j < fg->nb_outputs; j++) {
- OutputFilter *ofilter = fg->outputs[j];
-
- if (!ofilter->out_tmp || ofilter->out_tmp->name)
- continue;
-
- switch (ofilter->type) {
- case AVMEDIA_TYPE_VIDEO: o->video_disable = 1; break;
- case AVMEDIA_TYPE_AUDIO: o->audio_disable = 1; break;
- case AVMEDIA_TYPE_SUBTITLE: o->subtitle_disable = 1; break;
- }
- init_output_filter(ofilter, o, oc);
- }
- }
-
- /* ffserver seeking with date=... needs a date reference */
- if (!strcmp(file_oformat->name, "ffm") &&
- av_strstart(filename, "http:", NULL)) {
- int err = parse_option(o, "metadata", "creation_time=now", options);
- if (err < 0) {
- print_error(filename, err);
- exit_program(1);
- }
- }
-
- if (!strcmp(file_oformat->name, "ffm") && !override_ffserver &&
- av_strstart(filename, "http:", NULL)) {
- int j;
- /* special case for files sent to ffserver: we get the stream
- parameters from ffserver */
- int err = read_ffserver_streams(o, oc, filename);
- if (err < 0) {
- print_error(filename, err);
- exit_program(1);
- }
- for(j = nb_output_streams - oc->nb_streams; j < nb_output_streams; j++) {
- ost = output_streams[j];
- for (i = 0; i < nb_input_streams; i++) {
- ist = input_streams[i];
- if(ist->st->codec->codec_type == ost->st->codec->codec_type){
- ost->sync_ist= ist;
- ost->source_index= i;
- if(ost->st->codec->codec_type == AVMEDIA_TYPE_AUDIO) ost->avfilter = av_strdup("anull");
- if(ost->st->codec->codec_type == AVMEDIA_TYPE_VIDEO) ost->avfilter = av_strdup("null");
- ist->discard = 0;
- ist->st->discard = ist->user_set_discard;
- break;
- }
- }
- if(!ost->sync_ist){
- av_log(NULL, AV_LOG_FATAL, "Missing %s stream which is required by this ffm\n", av_get_media_type_string(ost->st->codec->codec_type));
- exit_program(1);
- }
- }
- } else if (!o->nb_stream_maps) {
- char *subtitle_codec_name = NULL;
- /* pick the "best" stream of each type */
-
- /* video: highest resolution */
- if (!o->video_disable && av_guess_codec(oc->oformat, NULL, filename, NULL, AVMEDIA_TYPE_VIDEO) != AV_CODEC_ID_NONE) {
- int area = 0, idx = -1;
- int qcr = avformat_query_codec(oc->oformat, oc->oformat->video_codec, 0);
- for (i = 0; i < nb_input_streams; i++) {
- int new_area;
- ist = input_streams[i];
- new_area = ist->st->codec->width * ist->st->codec->height + 100000000*!!ist->st->codec_info_nb_frames;
- if((qcr!=MKTAG('A', 'P', 'I', 'C')) && (ist->st->disposition & AV_DISPOSITION_ATTACHED_PIC))
- new_area = 1;
- if (ist->st->codec->codec_type == AVMEDIA_TYPE_VIDEO &&
- new_area > area) {
- if((qcr==MKTAG('A', 'P', 'I', 'C')) && !(ist->st->disposition & AV_DISPOSITION_ATTACHED_PIC))
- continue;
- area = new_area;
- idx = i;
- }
- }
- if (idx >= 0)
- new_video_stream(o, oc, idx);
- }
-
- /* audio: most channels */
- if (!o->audio_disable && av_guess_codec(oc->oformat, NULL, filename, NULL, AVMEDIA_TYPE_AUDIO) != AV_CODEC_ID_NONE) {
- int best_score = 0, idx = -1;
- for (i = 0; i < nb_input_streams; i++) {
- int score;
- ist = input_streams[i];
- score = ist->st->codec->channels + 100000000*!!ist->st->codec_info_nb_frames;
- if (ist->st->codec->codec_type == AVMEDIA_TYPE_AUDIO &&
- score > best_score) {
- best_score = score;
- idx = i;
- }
- }
- if (idx >= 0)
- new_audio_stream(o, oc, idx);
- }
-
- /* subtitles: pick first */
- MATCH_PER_TYPE_OPT(codec_names, str, subtitle_codec_name, oc, "s");
- if (!o->subtitle_disable && (avcodec_find_encoder(oc->oformat->subtitle_codec) || subtitle_codec_name)) {
- for (i = 0; i < nb_input_streams; i++)
- if (input_streams[i]->st->codec->codec_type == AVMEDIA_TYPE_SUBTITLE) {
- AVCodecDescriptor const *input_descriptor =
- avcodec_descriptor_get(input_streams[i]->st->codec->codec_id);
- AVCodecDescriptor const *output_descriptor = NULL;
- AVCodec const *output_codec =
- avcodec_find_encoder(oc->oformat->subtitle_codec);
- int input_props = 0, output_props = 0;
- if (output_codec)
- output_descriptor = avcodec_descriptor_get(output_codec->id);
- if (input_descriptor)
- input_props = input_descriptor->props & (AV_CODEC_PROP_TEXT_SUB | AV_CODEC_PROP_BITMAP_SUB);
- if (output_descriptor)
- output_props = output_descriptor->props & (AV_CODEC_PROP_TEXT_SUB | AV_CODEC_PROP_BITMAP_SUB);
- if (subtitle_codec_name ||
- input_props & output_props ||
- // Map dvb teletext which has neither property to any output subtitle encoder
- input_descriptor && output_descriptor &&
- (!input_descriptor->props ||
- !output_descriptor->props)) {
- new_subtitle_stream(o, oc, i);
- break;
- }
- }
- }
- /* Data only if codec id match */
- if (!o->data_disable ) {
- enum AVCodecID codec_id = av_guess_codec(oc->oformat, NULL, filename, NULL, AVMEDIA_TYPE_DATA);
- for (i = 0; codec_id != AV_CODEC_ID_NONE && i < nb_input_streams; i++) {
- if (input_streams[i]->st->codec->codec_type == AVMEDIA_TYPE_DATA
- && input_streams[i]->st->codec->codec_id == codec_id )
- new_data_stream(o, oc, i);
- }
- }
- } else {
- for (i = 0; i < o->nb_stream_maps; i++) {
- StreamMap *map = &o->stream_maps[i];
-
- if (map->disabled)
- continue;
-
- if (map->linklabel) {
- FilterGraph *fg;
- OutputFilter *ofilter = NULL;
- int j, k;
-
- for (j = 0; j < nb_filtergraphs; j++) {
- fg = filtergraphs[j];
- for (k = 0; k < fg->nb_outputs; k++) {
- AVFilterInOut *out = fg->outputs[k]->out_tmp;
- if (out && !strcmp(out->name, map->linklabel)) {
- ofilter = fg->outputs[k];
- goto loop_end;
- }
- }
- }
-loop_end:
- if (!ofilter) {
- av_log(NULL, AV_LOG_FATAL, "Output with label '%s' does not exist "
- "in any defined filter graph, or was already used elsewhere.\n", map->linklabel);
- exit_program(1);
- }
- init_output_filter(ofilter, o, oc);
- } else {
- int src_idx = input_files[map->file_index]->ist_index + map->stream_index;
-
- ist = input_streams[input_files[map->file_index]->ist_index + map->stream_index];
- if(o->subtitle_disable && ist->st->codec->codec_type == AVMEDIA_TYPE_SUBTITLE)
- continue;
- if(o-> audio_disable && ist->st->codec->codec_type == AVMEDIA_TYPE_AUDIO)
- continue;
- if(o-> video_disable && ist->st->codec->codec_type == AVMEDIA_TYPE_VIDEO)
- continue;
- if(o-> data_disable && ist->st->codec->codec_type == AVMEDIA_TYPE_DATA)
- continue;
-
- ost = NULL;
- switch (ist->st->codec->codec_type) {
- case AVMEDIA_TYPE_VIDEO: ost = new_video_stream (o, oc, src_idx); break;
- case AVMEDIA_TYPE_AUDIO: ost = new_audio_stream (o, oc, src_idx); break;
- case AVMEDIA_TYPE_SUBTITLE: ost = new_subtitle_stream (o, oc, src_idx); break;
- case AVMEDIA_TYPE_DATA: ost = new_data_stream (o, oc, src_idx); break;
- case AVMEDIA_TYPE_ATTACHMENT: ost = new_attachment_stream(o, oc, src_idx); break;
- case AVMEDIA_TYPE_UNKNOWN:
- if (copy_unknown_streams) {
- ost = new_unknown_stream (o, oc, src_idx);
- break;
- }
- default:
- av_log(NULL, ignore_unknown_streams ? AV_LOG_WARNING : AV_LOG_FATAL,
- "Cannot map stream #%d:%d - unsupported type.\n",
- map->file_index, map->stream_index);
- if (!ignore_unknown_streams) {
- av_log(NULL, AV_LOG_FATAL,
- "If you want unsupported types ignored instead "
- "of failing, please use the -ignore_unknown option\n"
- "If you want them copied, please use -copy_unknown\n");
- exit_program(1);
- }
- }
- if (ost)
- ost->sync_ist = input_streams[ input_files[map->sync_file_index]->ist_index
- + map->sync_stream_index];
- }
- }
- }
-
- /* handle attached files */
- for (i = 0; i < o->nb_attachments; i++) {
- AVIOContext *pb;
- uint8_t *attachment;
- const char *p;
- int64_t len;
-
- if ((err = avio_open2(&pb, o->attachments[i], AVIO_FLAG_READ, &int_cb, NULL)) < 0) {
- av_log(NULL, AV_LOG_FATAL, "Could not open attachment file %s.\n",
- o->attachments[i]);
- exit_program(1);
- }
- if ((len = avio_size(pb)) <= 0) {
- av_log(NULL, AV_LOG_FATAL, "Could not get size of the attachment %s.\n",
- o->attachments[i]);
- exit_program(1);
- }
- if (!(attachment = av_malloc(len))) {
- av_log(NULL, AV_LOG_FATAL, "Attachment %s too large to fit into memory.\n",
- o->attachments[i]);
- exit_program(1);
- }
- avio_read(pb, attachment, len);
-
- ost = new_attachment_stream(o, oc, -1);
- ost->stream_copy = 1;
- ost->attachment_filename = o->attachments[i];
- ost->finished = 1;
- ost->st->codec->extradata = attachment;
- ost->st->codec->extradata_size = len;
-
- p = strrchr(o->attachments[i], '/');
- av_dict_set(&ost->st->metadata, "filename", (p && *p) ? p + 1 : o->attachments[i], AV_DICT_DONT_OVERWRITE);
- avio_closep(&pb);
+ av_free(mapchan);
+ return 0;
}
- for (i = nb_output_streams - oc->nb_streams; i < nb_output_streams; i++) { //for all streams of this output file
- AVDictionaryEntry *e;
- ost = output_streams[i];
+ /* normal syntax */
+ n = sscanf(arg, "%d.%d.%d:%d.%d",
+ &m->file_idx, &m->stream_idx, &m->channel_idx,
+ &m->ofile_idx, &m->ostream_idx);
- if ((ost->stream_copy || ost->attachment_filename)
- && (e = av_dict_get(o->g->codec_opts, "flags", NULL, AV_DICT_IGNORE_SUFFIX))
- && (!e->key[5] || check_stream_specifier(oc, ost->st, e->key+6)))
- if (av_opt_set(ost->st->codec, "flags", e->value, 0) < 0)
- exit_program(1);
+ if (n != 3 && n != 5) {
+ av_log(NULL, AV_LOG_FATAL, "Syntax error, mapchan usage: "
+ "[file.stream.channel|-1][:syncfile:syncstream]\n");
+ exit_program(1);
}
- if (!oc->nb_streams && !(oc->oformat->flags & AVFMT_NOSTREAMS)) {
- av_dump_format(oc, nb_output_files - 1, oc->filename, 1);
- av_log(NULL, AV_LOG_ERROR, "Output file #%d does not contain any stream\n", nb_output_files - 1);
+ if (n != 5) // only file.stream.channel specified
+ m->ofile_idx = m->ostream_idx = -1;
+
+ /* check input */
+ if (m->file_idx < 0 || m->file_idx >= nb_input_files) {
+ av_log(NULL, AV_LOG_FATAL, "mapchan: invalid input file index: %d\n",
+ m->file_idx);
+ exit_program(1);
+ }
+ if (m->stream_idx < 0 ||
+ m->stream_idx >= input_files[m->file_idx]->nb_streams) {
+ av_log(NULL, AV_LOG_FATAL, "mapchan: invalid input file stream index #%d.%d\n",
+ m->file_idx, m->stream_idx);
+ exit_program(1);
+ }
+ st = input_files[m->file_idx]->ctx->streams[m->stream_idx];
+ if (st->codecpar->codec_type != AVMEDIA_TYPE_AUDIO) {
+ av_log(NULL, AV_LOG_FATAL, "mapchan: stream #%d.%d is not an audio stream.\n",
+ m->file_idx, m->stream_idx);
exit_program(1);
}
+ /* allow trailing ? to map_channel */
+ if (allow_unused = strchr(mapchan, '?'))
+ *allow_unused = 0;
+ if (m->channel_idx < 0 || m->channel_idx >= st->codecpar->ch_layout.nb_channels ||
+ input_files[m->file_idx]->streams[m->stream_idx]->user_set_discard == AVDISCARD_ALL) {
+ if (allow_unused) {
+ av_log(NULL, AV_LOG_VERBOSE, "mapchan: invalid audio channel #%d.%d.%d\n",
+ m->file_idx, m->stream_idx, m->channel_idx);
+ } else {
+ av_log(NULL, AV_LOG_FATAL, "mapchan: invalid audio channel #%d.%d.%d\n"
+ "To ignore this, add a trailing '?' to the map_channel.\n",
+ m->file_idx, m->stream_idx, m->channel_idx);
+ exit_program(1);
+ }
- /* check if all codec options have been used */
- unused_opts = strip_specifiers(o->g->codec_opts);
- for (i = of->ost_index; i < nb_output_streams; i++) {
- e = NULL;
- while ((e = av_dict_get(output_streams[i]->encoder_opts, "", e,
- AV_DICT_IGNORE_SUFFIX)))
- av_dict_set(&unused_opts, e->key, NULL, 0);
}
+ av_free(mapchan);
+ return 0;
+}
+#endif
- e = NULL;
- while ((e = av_dict_get(unused_opts, "", e, AV_DICT_IGNORE_SUFFIX))) {
- const AVClass *class = avcodec_get_class();
- const AVOption *option = av_opt_find(&class, e->key, NULL, 0,
- AV_OPT_SEARCH_CHILDREN | AV_OPT_SEARCH_FAKE_OBJ);
- const AVClass *fclass = avformat_get_class();
- const AVOption *foption = av_opt_find(&fclass, e->key, NULL, 0,
- AV_OPT_SEARCH_CHILDREN | AV_OPT_SEARCH_FAKE_OBJ);
- if (!option || foption)
- continue;
+static int opt_sdp_file(void *optctx, const char *opt, const char *arg)
+{
+ av_free(sdp_filename);
+ sdp_filename = av_strdup(arg);
+ return 0;
+}
+#if CONFIG_VAAPI
+static int opt_vaapi_device(void *optctx, const char *opt, const char *arg)
+{
+ const char *prefix = "vaapi:";
+ char *tmp;
+ int err;
+ tmp = av_asprintf("%s%s", prefix, arg);
+ if (!tmp)
+ return AVERROR(ENOMEM);
+ err = hw_device_init_from_string(tmp, NULL);
+ av_free(tmp);
+ return err;
+}
+#endif
- if (!(option->flags & AV_OPT_FLAG_ENCODING_PARAM)) {
- av_log(NULL, AV_LOG_ERROR, "Codec AVOption %s (%s) specified for "
- "output file #%d (%s) is not an encoding option.\n", e->key,
- option->help ? option->help : "", nb_output_files - 1,
- filename);
- exit_program(1);
- }
+#if CONFIG_QSV
+static int opt_qsv_device(void *optctx, const char *opt, const char *arg)
+{
+ const char *prefix = "qsv=__qsv_device:hw_any,child_device=";
+ int err;
+ char *tmp = av_asprintf("%s%s", prefix, arg);
- // gop_timecode is injected by generic code but not always used
- if (!strcmp(e->key, "gop_timecode"))
- continue;
+ if (!tmp)
+ return AVERROR(ENOMEM);
- av_log(NULL, AV_LOG_WARNING, "Codec AVOption %s (%s) specified for "
- "output file #%d (%s) has not been used for any stream. The most "
- "likely reason is either wrong type (e.g. a video option with "
- "no video streams) or that it is a private option of some encoder "
- "which was not actually used for any stream.\n", e->key,
- option->help ? option->help : "", nb_output_files - 1, filename);
- }
- av_dict_free(&unused_opts);
+ err = hw_device_init_from_string(tmp, NULL);
+ av_free(tmp);
- /* set the encoding/decoding_needed flags */
- for (i = of->ost_index; i < nb_output_streams; i++) {
- OutputStream *ost = output_streams[i];
+ return err;
+}
+#endif
- ost->encoding_needed = !ost->stream_copy;
- if (ost->encoding_needed && ost->source_index >= 0) {
- InputStream *ist = input_streams[ost->source_index];
- ist->decoding_needed |= DECODING_FOR_OST;
- }
+static int opt_init_hw_device(void *optctx, const char *opt, const char *arg)
+{
+ if (!strcmp(arg, "list")) {
+ enum AVHWDeviceType type = AV_HWDEVICE_TYPE_NONE;
+ printf("Supported hardware device types:\n");
+ while ((type = av_hwdevice_iterate_types(type)) !=
+ AV_HWDEVICE_TYPE_NONE)
+ printf("%s\n", av_hwdevice_get_type_name(type));
+ printf("\n");
+ exit_program(0);
+ } else {
+ return hw_device_init_from_string(arg, NULL);
}
+}
- /* check filename in case of an image number is expected */
- if (oc->oformat->flags & AVFMT_NEEDNUMBER) {
- if (!av_filename_number_test(oc->filename)) {
- print_error(oc->filename, AVERROR(EINVAL));
- exit_program(1);
- }
+static int opt_filter_hw_device(void *optctx, const char *opt, const char *arg)
+{
+ if (filter_hw_device) {
+ av_log(NULL, AV_LOG_ERROR, "Only one filter device can be used.\n");
+ return AVERROR(EINVAL);
}
-
- if (!(oc->oformat->flags & AVFMT_NOSTREAMS) && !input_stream_potentially_available) {
- av_log(NULL, AV_LOG_ERROR,
- "No input streams but output needs an input stream\n");
- exit_program(1);
+ filter_hw_device = hw_device_get_by_name(arg);
+ if (!filter_hw_device) {
+ av_log(NULL, AV_LOG_ERROR, "Invalid filter device %s.\n", arg);
+ return AVERROR(EINVAL);
}
+ return 0;
+}
- if (!(oc->oformat->flags & AVFMT_NOFILE)) {
- /* test if it already exists to avoid losing precious files */
- assert_file_overwrite(filename);
+static int opt_recording_timestamp(void *optctx, const char *opt, const char *arg)
+{
+ OptionsContext *o = optctx;
+ char buf[128];
+ int64_t recording_timestamp = parse_time_or_die(opt, arg, 0) / 1E6;
+ struct tm time = *gmtime((time_t*)&recording_timestamp);
+ if (!strftime(buf, sizeof(buf), "creation_time=%Y-%m-%dT%H:%M:%S%z", &time))
+ return -1;
+ parse_option(o, "metadata", buf, options);
- /* open the file */
- if ((err = avio_open2(&oc->pb, filename, AVIO_FLAG_WRITE,
- &oc->interrupt_callback,
- &of->opts)) < 0) {
- print_error(filename, err);
- exit_program(1);
- }
- } else if (strcmp(oc->oformat->name, "image2")==0 && !av_filename_number_test(filename))
- assert_file_overwrite(filename);
+ av_log(NULL, AV_LOG_WARNING, "%s is deprecated, set the 'creation_time' metadata "
+ "tag instead.\n", opt);
+ return 0;
+}
- if (o->mux_preload) {
- av_dict_set_int(&of->opts, "preload", o->mux_preload*AV_TIME_BASE, 0);
- }
- oc->max_delay = (int)(o->mux_max_delay * AV_TIME_BASE);
+const AVCodec *find_codec_or_die(void *logctx, const char *name,
+ enum AVMediaType type, int encoder)
+{
+ const AVCodecDescriptor *desc;
+ const char *codec_string = encoder ? "encoder" : "decoder";
+ const AVCodec *codec;
- /* copy metadata */
- for (i = 0; i < o->nb_metadata_map; i++) {
- char *p;
- int in_file_index = strtol(o->metadata_map[i].u.str, &p, 0);
+ codec = encoder ?
+ avcodec_find_encoder_by_name(name) :
+ avcodec_find_decoder_by_name(name);
- if (in_file_index >= nb_input_files) {
- av_log(NULL, AV_LOG_FATAL, "Invalid input file index %d while processing metadata maps\n", in_file_index);
- exit_program(1);
- }
- copy_metadata(o->metadata_map[i].specifier, *p ? p + 1 : p, oc,
- in_file_index >= 0 ?
- input_files[in_file_index]->ctx : NULL, o);
+ if (!codec && (desc = avcodec_descriptor_get_by_name(name))) {
+ codec = encoder ? avcodec_find_encoder(desc->id) :
+ avcodec_find_decoder(desc->id);
+ if (codec)
+ av_log(logctx, AV_LOG_VERBOSE, "Matched %s '%s' for codec '%s'.\n",
+ codec_string, codec->name, desc->name);
}
- /* copy chapters */
- if (o->chapters_input_file >= nb_input_files) {
- if (o->chapters_input_file == INT_MAX) {
- /* copy chapters from the first input file that has them*/
- o->chapters_input_file = -1;
- for (i = 0; i < nb_input_files; i++)
- if (input_files[i]->ctx->nb_chapters) {
- o->chapters_input_file = i;
- break;
- }
- } else {
- av_log(NULL, AV_LOG_FATAL, "Invalid input file index %d in chapter mapping.\n",
- o->chapters_input_file);
- exit_program(1);
- }
+ if (!codec) {
+ av_log(logctx, AV_LOG_FATAL, "Unknown %s '%s'\n", codec_string, name);
+ exit_program(1);
}
- if (o->chapters_input_file >= 0)
- copy_chapters(input_files[o->chapters_input_file], of,
- !o->metadata_chapters_manual);
-
- /* copy global metadata by default */
- if (!o->metadata_global_manual && nb_input_files){
- av_dict_copy(&oc->metadata, input_files[0]->ctx->metadata,
- AV_DICT_DONT_OVERWRITE);
- if(o->recording_time != INT64_MAX)
- av_dict_set(&oc->metadata, "duration", NULL, 0);
- av_dict_set(&oc->metadata, "creation_time", NULL, 0);
+ if (codec->type != type && !recast_media) {
+ av_log(logctx, AV_LOG_FATAL, "Invalid %s type '%s'\n", codec_string, name);
+ exit_program(1);
}
- if (!o->metadata_streams_manual)
- for (i = of->ost_index; i < nb_output_streams; i++) {
- InputStream *ist;
- if (output_streams[i]->source_index < 0) /* this is true e.g. for attached files */
- continue;
- ist = input_streams[output_streams[i]->source_index];
- av_dict_copy(&output_streams[i]->st->metadata, ist->st->metadata, AV_DICT_DONT_OVERWRITE);
- if (!output_streams[i]->stream_copy) {
- av_dict_set(&output_streams[i]->st->metadata, "encoder", NULL, 0);
- if (ist->autorotate)
- av_dict_set(&output_streams[i]->st->metadata, "rotate", NULL, 0);
- }
- }
+ return codec;
+}
- /* process manually set programs */
- for (i = 0; i < o->nb_program; i++) {
- const char *p = o->program[i].u.str;
- int progid = i+1;
- AVProgram *program;
-
- while(*p) {
- const char *p2 = av_get_token(&p, ":");
- const char *to_dealloc = p2;
- char *key;
- if (!p2)
- break;
-
- if(*p) p++;
-
- key = av_get_token(&p2, "=");
- if (!key || !*p2) {
- av_freep(&to_dealloc);
- av_freep(&key);
- break;
- }
- p2++;
+void assert_file_overwrite(const char *filename)
+{
+ const char *proto_name = avio_find_protocol_name(filename);
- if (!strcmp(key, "program_num"))
- progid = strtol(p2, NULL, 0);
- av_freep(&to_dealloc);
- av_freep(&key);
- }
+ if (file_overwrite && no_file_overwrite) {
+ fprintf(stderr, "Error, both -y and -n supplied. Exiting.\n");
+ exit_program(1);
+ }
- program = av_new_program(oc, progid);
-
- p = o->program[i].u.str;
- while(*p) {
- const char *p2 = av_get_token(&p, ":");
- const char *to_dealloc = p2;
- char *key;
- if (!p2)
- break;
- if(*p) p++;
-
- key = av_get_token(&p2, "=");
- if (!key) {
- av_log(NULL, AV_LOG_FATAL,
- "No '=' character in program string %s.\n",
- p2);
- exit_program(1);
+ if (!file_overwrite) {
+ if (proto_name && !strcmp(proto_name, "file") && avio_check(filename, 0) == 0) {
+ if (stdin_interaction && !no_file_overwrite) {
+ fprintf(stderr,"File '%s' already exists. Overwrite? [y/N] ", filename);
+ fflush(stderr);
+ term_exit();
+ signal(SIGINT, SIG_DFL);
+ if (!read_yesno()) {
+ av_log(NULL, AV_LOG_FATAL, "Not overwriting - exiting\n");
+ exit_program(1);
+ }
+ term_init();
}
- if (!*p2)
- exit_program(1);
- p2++;
-
- if (!strcmp(key, "title")) {
- av_dict_set(&program->metadata, "title", p2, 0);
- } else if (!strcmp(key, "program_num")) {
- } else if (!strcmp(key, "st")) {
- int st_num = strtol(p2, NULL, 0);
- av_program_add_stream_index(oc, progid, st_num);
- } else {
- av_log(NULL, AV_LOG_FATAL, "Unknown program key %s.\n", key);
+ else {
+ av_log(NULL, AV_LOG_FATAL, "File '%s' already exists. Exiting.\n", filename);
exit_program(1);
}
- av_freep(&to_dealloc);
- av_freep(&key);
}
}
- /* process manually set metadata */
- for (i = 0; i < o->nb_metadata; i++) {
- AVDictionary **m;
- char type, *val;
- const char *stream_spec;
- int index = 0, j, ret = 0;
- char now_time[256];
-
- val = strchr(o->metadata[i].u.str, '=');
- if (!val) {
- av_log(NULL, AV_LOG_FATAL, "No '=' character in metadata string %s.\n",
- o->metadata[i].u.str);
- exit_program(1);
- }
- *val++ = 0;
-
- if (!strcmp(o->metadata[i].u.str, "creation_time") &&
- !strcmp(val, "now")) {
- time_t now = time(0);
- struct tm *ptm, tmbuf;
- ptm = localtime_r(&now, &tmbuf);
- if (ptm) {
- if (strftime(now_time, sizeof(now_time), "%Y-%m-%d %H:%M:%S", ptm))
- val = now_time;
- }
+ if (proto_name && !strcmp(proto_name, "file")) {
+ for (int i = 0; i < nb_input_files; i++) {
+ InputFile *file = input_files[i];
+ if (file->ctx->iformat->flags & AVFMT_NOFILE)
+ continue;
+ if (!strcmp(filename, file->ctx->url)) {
+ av_log(NULL, AV_LOG_FATAL, "Output %s same as Input #%d - exiting\n", filename, i);
+ av_log(NULL, AV_LOG_WARNING, "FFmpeg cannot edit existing files in-place.\n");
+ exit_program(1);
+ }
}
+ }
+}
- parse_meta_type(o->metadata[i].specifier, &type, &index, &stream_spec);
- if (type == 's') {
- for (j = 0; j < oc->nb_streams; j++) {
- ost = output_streams[nb_output_streams - oc->nb_streams + j];
- if ((ret = check_stream_specifier(oc, oc->streams[j], stream_spec)) > 0) {
- av_dict_set(&oc->streams[j]->metadata, o->metadata[i].u.str, *val ? val : NULL, 0);
- if (!strcmp(o->metadata[i].u.str, "rotate")) {
- ost->rotate_overridden = 1;
- }
- } else if (ret < 0)
- exit_program(1);
- }
- }
- else {
- switch (type) {
- case 'g':
- m = &oc->metadata;
- break;
- case 'c':
- if (index < 0 || index >= oc->nb_chapters) {
- av_log(NULL, AV_LOG_FATAL, "Invalid chapter index %d in metadata specifier.\n", index);
- exit_program(1);
- }
- m = &oc->chapters[index]->metadata;
- break;
- case 'p':
- if (index < 0 || index >= oc->nb_programs) {
- av_log(NULL, AV_LOG_FATAL, "Invalid program index %d in metadata specifier.\n", index);
- exit_program(1);
- }
- m = &oc->programs[index]->metadata;
- break;
- default:
- av_log(NULL, AV_LOG_FATAL, "Invalid metadata specifier %s.\n", o->metadata[i].specifier);
- exit_program(1);
- }
- av_dict_set(m, o->metadata[i].u.str, *val ? val : NULL, 0);
- }
+/* read file contents into a string */
+char *file_read(const char *filename)
+{
+ AVIOContext *pb = NULL;
+ int ret = avio_open(&pb, filename, AVIO_FLAG_READ);
+ AVBPrint bprint;
+ char *str;
+
+ if (ret < 0) {
+ av_log(NULL, AV_LOG_ERROR, "Error opening file %s.\n", filename);
+ return NULL;
+ }
+
+ av_bprint_init(&bprint, 0, AV_BPRINT_SIZE_UNLIMITED);
+ ret = avio_read_to_bprint(pb, &bprint, SIZE_MAX);
+ avio_closep(&pb);
+ if (ret < 0) {
+ av_bprint_finalize(&bprint, NULL);
+ return NULL;
+ }
+ ret = av_bprint_finalize(&bprint, &str);
+ if (ret < 0)
+ return NULL;
+ return str;
+}
+
+/* arg format is "output-stream-index:streamid-value". */
+static int opt_streamid(void *optctx, const char *opt, const char *arg)
+{
+ OptionsContext *o = optctx;
+ int idx;
+ char *p;
+ char idx_str[16];
+
+ av_strlcpy(idx_str, arg, sizeof(idx_str));
+ p = strchr(idx_str, ':');
+ if (!p) {
+ av_log(NULL, AV_LOG_FATAL,
+ "Invalid value '%s' for option '%s', required syntax is 'index:value'\n",
+ arg, opt);
+ exit_program(1);
}
+ *p++ = '\0';
+ idx = parse_number_or_die(opt, idx_str, OPT_INT, 0, MAX_STREAMS-1);
+ o->streamid_map = grow_array(o->streamid_map, sizeof(*o->streamid_map), &o->nb_streamid_map, idx+1);
+ o->streamid_map[idx] = parse_number_or_die(opt, p, OPT_INT, 0, INT_MAX);
+ return 0;
+}
+
+static int init_complex_filters(void)
+{
+ int i, ret = 0;
+ for (i = 0; i < nb_filtergraphs; i++) {
+ ret = init_complex_filtergraph(filtergraphs[i]);
+ if (ret < 0)
+ return ret;
+ }
return 0;
}
@@ -2512,14 +775,14 @@ static int opt_target(void *optctx, const char *opt, const char *arg)
} else {
/* Try to determine PAL/NTSC by peeking in the input files */
if (nb_input_files) {
- int i, j, fr;
+ int i, j;
for (j = 0; j < nb_input_files; j++) {
for (i = 0; i < input_files[j]->nb_streams; i++) {
- AVCodecContext *c = input_files[j]->ctx->streams[i]->codec;
- if (c->codec_type != AVMEDIA_TYPE_VIDEO ||
- !c->time_base.num)
+ AVStream *st = input_files[j]->ctx->streams[i];
+ int64_t fr;
+ if (st->codecpar->codec_type != AVMEDIA_TYPE_VIDEO)
continue;
- fr = c->time_base.den * 1000 / c->time_base.num;
+ fr = st->time_base.den * 1000LL / st->time_base.num;
if (fr == 25000) {
norm = PAL;
break;
@@ -2749,8 +1012,11 @@ static int opt_preset(void *optctx, const char *opt, const char *arg)
static int opt_old2new(void *optctx, const char *opt, const char *arg)
{
OptionsContext *o = optctx;
+ int ret;
char *s = av_asprintf("%s:%c", opt + 1, *opt);
- int ret = parse_option(o, s, arg, options);
+ if (!s)
+ return AVERROR(ENOMEM);
+ ret = parse_option(o, s, arg, options);
av_free(s);
return ret;
}
@@ -2781,6 +1047,8 @@ static int opt_qscale(void *optctx, const char *opt, const char *arg)
return parse_option(o, "q:v", arg, options);
}
s = av_asprintf("q%s", opt + 6);
+ if (!s)
+ return AVERROR(ENOMEM);
ret = parse_option(o, s, arg, options);
av_free(s);
return ret;
@@ -2812,60 +1080,22 @@ static int opt_audio_filters(void *optctx, const char *opt, const char *arg)
static int opt_vsync(void *optctx, const char *opt, const char *arg)
{
- if (!av_strcasecmp(arg, "cfr")) video_sync_method = VSYNC_CFR;
- else if (!av_strcasecmp(arg, "vfr")) video_sync_method = VSYNC_VFR;
- else if (!av_strcasecmp(arg, "passthrough")) video_sync_method = VSYNC_PASSTHROUGH;
- else if (!av_strcasecmp(arg, "drop")) video_sync_method = VSYNC_DROP;
-
- if (video_sync_method == VSYNC_AUTO)
- video_sync_method = parse_number_or_die("vsync", arg, OPT_INT, VSYNC_AUTO, VSYNC_VFR);
+ av_log(NULL, AV_LOG_WARNING, "-vsync is deprecated. Use -fps_mode\n");
+ parse_and_set_vsync(arg, &video_sync_method, -1, -1, 1);
return 0;
}
static int opt_timecode(void *optctx, const char *opt, const char *arg)
{
OptionsContext *o = optctx;
+ int ret;
char *tcr = av_asprintf("timecode=%s", arg);
- int ret = parse_option(o, "metadata:g", tcr, options);
+ if (!tcr)
+ return AVERROR(ENOMEM);
+ ret = parse_option(o, "metadata:g", tcr, options);
if (ret >= 0)
ret = av_dict_set(&o->g->codec_opts, "gop_timecode", arg, 0);
av_free(tcr);
- return 0;
-}
-
-static int opt_channel_layout(void *optctx, const char *opt, const char *arg)
-{
- OptionsContext *o = optctx;
- char layout_str[32];
- char *stream_str;
- char *ac_str;
- int ret, channels, ac_str_size;
- uint64_t layout;
-
- layout = av_get_channel_layout(arg);
- if (!layout) {
- av_log(NULL, AV_LOG_ERROR, "Unknown channel layout: %s\n", arg);
- return AVERROR(EINVAL);
- }
- snprintf(layout_str, sizeof(layout_str), "%"PRIu64, layout);
- ret = opt_default_new(o, opt, layout_str);
- if (ret < 0)
- return ret;
-
- /* set 'ac' option based on channel layout */
- channels = av_get_channel_layout_nb_channels(layout);
- snprintf(layout_str, sizeof(layout_str), "%d", channels);
- stream_str = strchr(opt, ':');
- ac_str_size = 3 + (stream_str ? strlen(stream_str) : 0);
- ac_str = av_mallocz(ac_str_size);
- if (!ac_str)
- return AVERROR(ENOMEM);
- av_strlcpy(ac_str, "ac", 3);
- if (stream_str)
- av_strlcat(ac_str, stream_str, ac_str_size);
- ret = parse_option(o, ac_str, layout_str, options);
- av_free(ac_str);
-
return ret;
}
@@ -2877,32 +1107,26 @@ static int opt_audio_qscale(void *optctx, const char *opt, const char *arg)
static int opt_filter_complex(void *optctx, const char *opt, const char *arg)
{
- GROW_ARRAY(filtergraphs, nb_filtergraphs);
- if (!(filtergraphs[nb_filtergraphs - 1] = av_mallocz(sizeof(*filtergraphs[0]))))
- return AVERROR(ENOMEM);
- filtergraphs[nb_filtergraphs - 1]->index = nb_filtergraphs - 1;
- filtergraphs[nb_filtergraphs - 1]->graph_desc = av_strdup(arg);
- if (!filtergraphs[nb_filtergraphs - 1]->graph_desc)
- return AVERROR(ENOMEM);
+ FilterGraph *fg = ALLOC_ARRAY_ELEM(filtergraphs, nb_filtergraphs);
- input_stream_potentially_available = 1;
+ fg->index = nb_filtergraphs - 1;
+ fg->graph_desc = av_strdup(arg);
+ if (!fg->graph_desc)
+ return AVERROR(ENOMEM);
return 0;
}
static int opt_filter_complex_script(void *optctx, const char *opt, const char *arg)
{
- uint8_t *graph_desc = read_file(arg);
+ FilterGraph *fg;
+ char *graph_desc = file_read(arg);
if (!graph_desc)
return AVERROR(EINVAL);
- GROW_ARRAY(filtergraphs, nb_filtergraphs);
- if (!(filtergraphs[nb_filtergraphs - 1] = av_mallocz(sizeof(*filtergraphs[0]))))
- return AVERROR(ENOMEM);
- filtergraphs[nb_filtergraphs - 1]->index = nb_filtergraphs - 1;
- filtergraphs[nb_filtergraphs - 1]->graph_desc = graph_desc;
-
- input_stream_potentially_available = 1;
+ fg = ALLOC_ARRAY_ELEM(filtergraphs, nb_filtergraphs);
+ fg->index = nb_filtergraphs - 1;
+ fg->graph_desc = graph_desc;
return 0;
}
@@ -2928,7 +1152,7 @@ void show_help_default(const char *opt, const char *arg)
" -h -- print basic options\n"
" -h long -- print more options\n"
" -h full -- print all options (including all format and codec specific options, very long)\n"
- " -h type=name -- print all options for the named decoder/encoder/demuxer/muxer/filter\n"
+ " -h type=name -- print all options for the named decoder/encoder/demuxer/muxer/filter/bsf/protocol\n"
" See man %s for detailed description of the options.\n"
"\n", program_name);
@@ -2936,7 +1160,7 @@ void show_help_default(const char *opt, const char *arg)
OPT_EXIT, 0, 0);
show_help_options(options, "Global options (affect whole program "
- "instead of just one file:",
+ "instead of just one file):",
0, per_file | OPT_EXIT | OPT_EXPERT, 0);
if (show_advanced)
show_help_options(options, "Advanced global options:", OPT_EXPERT,
@@ -2971,8 +1195,11 @@ void show_help_default(const char *opt, const char *arg)
#if CONFIG_SWSCALE
show_help_children(sws_get_class(), flags);
#endif
+#if CONFIG_SWRESAMPLE
show_help_children(swr_get_class(), AV_OPT_FLAG_AUDIO_PARAM);
+#endif
show_help_children(avfilter_get_class(), AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_AUDIO_PARAM | AV_OPT_FLAG_FILTERING_PARAM);
+ show_help_children(av_bsf_get_class(), AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_AUDIO_PARAM | AV_OPT_FLAG_BSF_PARAM);
}
}
@@ -2989,12 +1216,12 @@ enum OptGroup {
};
static const OptionGroupDef groups[] = {
- [GROUP_OUTFILE] = { "output file", NULL, OPT_OUTPUT },
- [GROUP_INFILE] = { "input file", "i", OPT_INPUT },
+ [GROUP_OUTFILE] = { "output url", NULL, OPT_OUTPUT },
+ [GROUP_INFILE] = { "input url", "i", OPT_INPUT },
};
static int open_files(OptionGroupList *l, const char *inout,
- int (*open_file)(OptionsContext*, const char*))
+ int (*open_file)(const OptionsContext*, const char*))
{
int i, ret;
@@ -3009,6 +1236,7 @@ static int open_files(OptionGroupList *l, const char *inout,
if (ret < 0) {
av_log(NULL, AV_LOG_ERROR, "Error parsing options for %s file "
"%s.\n", inout, g->arg);
+ uninit_options(&o);
return ret;
}
@@ -3029,7 +1257,6 @@ static int open_files(OptionGroupList *l, const char *inout,
int ffmpeg_parse_options(int argc, char **argv)
{
OptionParseContext octx;
- uint8_t error[128];
int ret;
memset(&octx, 0, sizeof(octx));
@@ -3049,8 +1276,11 @@ int ffmpeg_parse_options(int argc, char **argv)
goto fail;
}
+ /* configure terminal and setup signal handlers */
+ term_init();
+
/* open input files */
- ret = open_files(&octx.groups[GROUP_INFILE], "input", open_input_file);
+ ret = open_files(&octx.groups[GROUP_INFILE], "input", ifile_open);
if (ret < 0) {
av_log(NULL, AV_LOG_FATAL, "Error opening input files: ");
goto fail;
@@ -3064,24 +1294,22 @@ int ffmpeg_parse_options(int argc, char **argv)
}
/* open output files */
- ret = open_files(&octx.groups[GROUP_OUTFILE], "output", open_output_file);
+ ret = open_files(&octx.groups[GROUP_OUTFILE], "output", of_open);
if (ret < 0) {
av_log(NULL, AV_LOG_FATAL, "Error opening output files: ");
goto fail;
}
- /* configure the complex filtergraphs */
- ret = configure_complex_filters();
- if (ret < 0) {
- av_log(NULL, AV_LOG_FATAL, "Error configuring complex filters.\n");
- goto fail;
- }
+ correct_input_start_times();
+
+ apply_sync_offsets();
+
+ check_filter_outputs();
fail:
uninit_parse_context(&octx);
if (ret < 0) {
- av_strerror(ret, error, sizeof(error));
- av_log(NULL, AV_LOG_FATAL, "%s\n", error);
+ av_log(NULL, AV_LOG_FATAL, "%s\n", av_err2str(ret));
}
return ret;
}
@@ -3103,10 +1331,23 @@ static int opt_progress(void *optctx, const char *opt, const char *arg)
return 0;
}
+int opt_timelimit(void *optctx, const char *opt, const char *arg)
+{
+#if HAVE_SETRLIMIT
+ int lim = parse_number_or_die(opt, arg, OPT_INT64, 0, INT_MAX);
+ struct rlimit rl = { lim, lim + 1 };
+ if (setrlimit(RLIMIT_CPU, &rl))
+ perror("setrlimit");
+#else
+ av_log(NULL, AV_LOG_WARNING, "-%s not implemented on this OS\n", opt);
+#endif
+ return 0;
+}
+
#define OFFSET(x) offsetof(OptionsContext, x)
const OptionDef options[] = {
/* main options */
-#include "ffmpeg/cmdutils_common_opts.h"
+ CMDUTILS_COMMON_OPTIONS
{ "f", HAS_ARG | OPT_STRING | OPT_OFFSET |
OPT_INPUT | OPT_OUTPUT, { .off = OFFSET(format) },
"force format", "fmt" },
@@ -3118,6 +1359,8 @@ const OptionDef options[] = {
"Ignore unknown stream types" },
{ "copy_unknown", OPT_BOOL | OPT_EXPERT, { ©_unknown_streams },
"Copy unknown stream types" },
+ { "recast_media", OPT_BOOL | OPT_EXPERT, { &recast_media },
+ "allow recasting stream type in order to force a decoder of different media type" },
{ "c", HAS_ARG | OPT_STRING | OPT_SPEC |
OPT_INPUT | OPT_OUTPUT, { .off = OFFSET(codec_names) },
"codec name", "codec" },
@@ -3131,8 +1374,10 @@ const OptionDef options[] = {
OPT_OUTPUT, { .func_arg = opt_map },
"set input stream mapping",
"[-]input_file_id[:stream_specifier][,sync_file_id[:stream_specifier]]" },
+#if FFMPEG_OPT_MAP_CHANNEL
{ "map_channel", HAS_ARG | OPT_EXPERT | OPT_PERFILE | OPT_OUTPUT, { .func_arg = opt_map_channel },
- "map an audio channel from one stream to another", "file.stream.channel[:syncfile.syncstream]" },
+ "map an audio channel from one stream to another (deprecated)", "file.stream.channel[:syncfile.syncstream]" },
+#endif
{ "map_metadata", HAS_ARG | OPT_STRING | OPT_SPEC |
OPT_OUTPUT, { .off = OFFSET(metadata_map) },
"set metadata information of outfile from infile",
@@ -3144,7 +1389,7 @@ const OptionDef options[] = {
OPT_INPUT | OPT_OUTPUT, { .off = OFFSET(recording_time) },
"record or transcode \"duration\" seconds of audio/video",
"duration" },
- { "to", HAS_ARG | OPT_TIME | OPT_OFFSET | OPT_OUTPUT, { .off = OFFSET(stop_time) },
+ { "to", HAS_ARG | OPT_TIME | OPT_OFFSET | OPT_INPUT | OPT_OUTPUT, { .off = OFFSET(stop_time) },
"record or transcode stop time", "time_stop" },
{ "fs", HAS_ARG | OPT_INT64 | OPT_OFFSET | OPT_OUTPUT, { .off = OFFSET(limit_filesize) },
"set the limit file size in bytes", "limit_size" },
@@ -3152,7 +1397,7 @@ const OptionDef options[] = {
OPT_INPUT | OPT_OUTPUT, { .off = OFFSET(start_time) },
"set the start time offset", "time_off" },
{ "sseof", HAS_ARG | OPT_TIME | OPT_OFFSET |
- OPT_INPUT | OPT_OUTPUT, { .off = OFFSET(start_time_eof) },
+ OPT_INPUT, { .off = OFFSET(start_time_eof) },
"set the start time offset relative to EOF", "time_off" },
{ "seek_timestamp", HAS_ARG | OPT_INT | OPT_OFFSET |
OPT_INPUT, { .off = OFFSET(seek_timestamp) },
@@ -3160,6 +1405,9 @@ const OptionDef options[] = {
{ "accurate_seek", OPT_BOOL | OPT_OFFSET | OPT_EXPERT |
OPT_INPUT, { .off = OFFSET(accurate_seek) },
"enable/disable accurate seeking with -ss" },
+ { "isync", HAS_ARG | OPT_INT | OPT_OFFSET |
+ OPT_EXPERT | OPT_INPUT, { .off = OFFSET(input_sync_ref) },
+ "Indicate the input index for sync reference", "sync ref" },
{ "itsoffset", HAS_ARG | OPT_TIME | OPT_OFFSET |
OPT_EXPERT | OPT_INPUT, { .off = OFFSET(input_ts_offset) },
"set the input ts offset", "time_off" },
@@ -3184,23 +1432,24 @@ const OptionDef options[] = {
{ "stdin", OPT_BOOL | OPT_EXPERT, { &stdin_interaction },
"enable or disable interaction on standard input" },
{ "timelimit", HAS_ARG | OPT_EXPERT, { .func_arg = opt_timelimit },
- "set max runtime in seconds", "limit" },
+ "set max runtime in seconds in CPU user time", "limit" },
{ "dump", OPT_BOOL | OPT_EXPERT, { &do_pkt_dump },
"dump each input packet" },
{ "hex", OPT_BOOL | OPT_EXPERT, { &do_hex_dump },
"when dumping packets, also dump the payload" },
{ "re", OPT_BOOL | OPT_EXPERT | OPT_OFFSET |
OPT_INPUT, { .off = OFFSET(rate_emu) },
- "read input at native frame rate", "" },
+ "read input at native frame rate; equivalent to -readrate 1", "" },
+ { "readrate", HAS_ARG | OPT_FLOAT | OPT_OFFSET |
+ OPT_EXPERT | OPT_INPUT, { .off = OFFSET(readrate) },
+ "read input at specified rate", "speed" },
{ "target", HAS_ARG | OPT_PERFILE | OPT_OUTPUT, { .func_arg = opt_target },
"specify target file type (\"vcd\", \"svcd\", \"dvd\", \"dv\" or \"dv50\" "
"with optional prefixes \"pal-\", \"ntsc-\" or \"film-\")", "type" },
{ "vsync", HAS_ARG | OPT_EXPERT, { .func_arg = opt_vsync },
- "video sync method", "" },
+ "set video sync method globally; deprecated, use -fps_mode", "" },
{ "frame_drop_threshold", HAS_ARG | OPT_FLOAT | OPT_EXPERT, { &frame_drop_threshold },
"frame drop threshold", "" },
- { "async", HAS_ARG | OPT_INT | OPT_EXPERT, { &audio_sync_method },
- "audio sync method", "" },
{ "adrift_threshold", HAS_ARG | OPT_FLOAT | OPT_EXPERT, { &audio_drift_threshold },
"audio drift threshold", "threshold" },
{ "copyts", OPT_BOOL | OPT_EXPERT, { ©_ts },
@@ -3212,6 +1461,11 @@ const OptionDef options[] = {
{ "shortest", OPT_BOOL | OPT_EXPERT | OPT_OFFSET |
OPT_OUTPUT, { .off = OFFSET(shortest) },
"finish encoding within shortest input" },
+ { "shortest_buf_duration", HAS_ARG | OPT_FLOAT | OPT_EXPERT | OPT_OFFSET | OPT_OUTPUT, { .off = OFFSET(shortest_buf_duration) },
+ "maximum buffering duration (in seconds) for the -shortest option" },
+ { "bitexact", OPT_BOOL | OPT_EXPERT | OPT_OFFSET |
+ OPT_OUTPUT | OPT_INPUT, { .off = OFFSET(bitexact) },
+ "bitexact mode" },
{ "apad", OPT_STRING | HAS_ARG | OPT_SPEC |
OPT_OUTPUT, { .off = OFFSET(apad) },
"audio pad", "" },
@@ -3243,18 +1497,26 @@ const OptionDef options[] = {
"set profile", "profile" },
{ "filter", HAS_ARG | OPT_STRING | OPT_SPEC | OPT_OUTPUT, { .off = OFFSET(filters) },
"set stream filtergraph", "filter_graph" },
+ { "filter_threads", HAS_ARG, { .func_arg = opt_filter_threads },
+ "number of non-complex filter threads" },
{ "filter_script", HAS_ARG | OPT_STRING | OPT_SPEC | OPT_OUTPUT, { .off = OFFSET(filter_scripts) },
"read stream filtergraph description from a file", "filename" },
{ "reinit_filter", HAS_ARG | OPT_INT | OPT_SPEC | OPT_INPUT, { .off = OFFSET(reinit_filters) },
"reinit filtergraph on input parameter changes", "" },
{ "filter_complex", HAS_ARG | OPT_EXPERT, { .func_arg = opt_filter_complex },
"create a complex filtergraph", "graph_description" },
+ { "filter_complex_threads", HAS_ARG | OPT_INT, { &filter_complex_nbthreads },
+ "number of threads for -filter_complex" },
{ "lavfi", HAS_ARG | OPT_EXPERT, { .func_arg = opt_filter_complex },
"create a complex filtergraph", "graph_description" },
{ "filter_complex_script", HAS_ARG | OPT_EXPERT, { .func_arg = opt_filter_complex_script },
"read complex filtergraph description from a file", "filename" },
+ { "auto_conversion_filters", OPT_BOOL | OPT_EXPERT, { &auto_conversion_filters },
+ "enable automatic conversion filters globally" },
{ "stats", OPT_BOOL, { &print_stats },
"print progress report during encoding", },
+ { "stats_period", HAS_ARG | OPT_EXPERT, { .func_arg = opt_stats_period },
+ "set the period at which ffmpeg updates stats and -progress output", "time" },
{ "attach", HAS_ARG | OPT_PERFILE | OPT_EXPERT |
OPT_OUTPUT, { .func_arg = opt_attach },
"add an attachment to the output file", "filename" },
@@ -3266,16 +1528,34 @@ const OptionDef options[] = {
{ "debug_ts", OPT_BOOL | OPT_EXPERT, { &debug_ts },
"print timestamp debugging info" },
{ "max_error_rate", HAS_ARG | OPT_FLOAT, { &max_error_rate },
- "maximum error rate", "ratio of errors (0.0: no errors, 1.0: 100% errors) above which ffmpeg returns an error instead of success." },
+ "ratio of decoding errors (0.0: no errors, 1.0: 100% errors) above which ffmpeg returns an error instead of success.", "maximum error rate" },
{ "discard", OPT_STRING | HAS_ARG | OPT_SPEC |
OPT_INPUT, { .off = OFFSET(discard) },
"discard", "" },
{ "disposition", OPT_STRING | HAS_ARG | OPT_SPEC |
OPT_OUTPUT, { .off = OFFSET(disposition) },
"disposition", "" },
- { "thread_queue_size", HAS_ARG | OPT_INT | OPT_OFFSET | OPT_EXPERT | OPT_INPUT,
+ { "thread_queue_size", HAS_ARG | OPT_INT | OPT_OFFSET | OPT_EXPERT | OPT_INPUT | OPT_OUTPUT,
{ .off = OFFSET(thread_queue_size) },
"set the maximum number of queued packets from the demuxer" },
+ { "find_stream_info", OPT_BOOL | OPT_INPUT | OPT_EXPERT | OPT_OFFSET, { .off = OFFSET(find_stream_info) },
+ "read and decode the streams to fill missing information with heuristics" },
+ { "bits_per_raw_sample", OPT_INT | HAS_ARG | OPT_EXPERT | OPT_SPEC | OPT_OUTPUT,
+ { .off = OFFSET(bits_per_raw_sample) },
+ "set the number of bits per raw sample", "number" },
+
+ { "stats_enc_pre", HAS_ARG | OPT_SPEC | OPT_EXPERT | OPT_OUTPUT | OPT_STRING, { .off = OFFSET(enc_stats_pre) },
+ "write encoding stats before encoding" },
+ { "stats_enc_post", HAS_ARG | OPT_SPEC | OPT_EXPERT | OPT_OUTPUT | OPT_STRING, { .off = OFFSET(enc_stats_post) },
+ "write encoding stats after encoding" },
+ { "stats_mux_pre", HAS_ARG | OPT_SPEC | OPT_EXPERT | OPT_OUTPUT | OPT_STRING, { .off = OFFSET(mux_stats) },
+ "write packets stats before muxing" },
+ { "stats_enc_pre_fmt", HAS_ARG | OPT_SPEC | OPT_EXPERT | OPT_OUTPUT | OPT_STRING, { .off = OFFSET(enc_stats_pre_fmt) },
+ "format of the stats written with -stats_enc_pre" },
+ { "stats_enc_post_fmt", HAS_ARG | OPT_SPEC | OPT_EXPERT | OPT_OUTPUT | OPT_STRING, { .off = OFFSET(enc_stats_post_fmt) },
+ "format of the stats written with -stats_enc_post" },
+ { "stats_mux_pre_fmt", HAS_ARG | OPT_SPEC | OPT_EXPERT | OPT_OUTPUT | OPT_STRING, { .off = OFFSET(mux_stats_fmt) },
+ "format of the stats written with -stats_mux_pre" },
/* video options */
{ "vframes", OPT_VIDEO | HAS_ARG | OPT_PERFILE | OPT_OUTPUT, { .func_arg = opt_video_frames },
@@ -3283,6 +1563,9 @@ const OptionDef options[] = {
{ "r", OPT_VIDEO | HAS_ARG | OPT_STRING | OPT_SPEC |
OPT_INPUT | OPT_OUTPUT, { .off = OFFSET(frame_rates) },
"set frame rate (Hz value, fraction or abbreviation)", "rate" },
+ { "fpsmax", OPT_VIDEO | HAS_ARG | OPT_STRING | OPT_SPEC |
+ OPT_OUTPUT, { .off = OFFSET(max_frame_rates) },
+ "set max frame rate (Hz value, fraction or abbreviation)", "rate" },
{ "s", OPT_VIDEO | HAS_ARG | OPT_SUBTITLE | OPT_STRING | OPT_SPEC |
OPT_INPUT | OPT_OUTPUT, { .off = OFFSET(frame_sizes) },
"set frame size (WxH or abbreviation)", "size" },
@@ -3292,10 +1575,16 @@ const OptionDef options[] = {
{ "pix_fmt", OPT_VIDEO | HAS_ARG | OPT_EXPERT | OPT_STRING | OPT_SPEC |
OPT_INPUT | OPT_OUTPUT, { .off = OFFSET(frame_pix_fmts) },
"set pixel format", "format" },
- { "bits_per_raw_sample", OPT_VIDEO | OPT_INT | HAS_ARG, { &frame_bits_per_raw_sample },
- "set the number of bits per raw sample", "number" },
- { "intra", OPT_VIDEO | OPT_BOOL | OPT_EXPERT, { &intra_only },
- "deprecated use -g 1" },
+ { "display_rotation", OPT_VIDEO | HAS_ARG | OPT_DOUBLE | OPT_SPEC |
+ OPT_INPUT, { .off = OFFSET(display_rotations) },
+ "set pure counter-clockwise rotation in degrees for stream(s)",
+ "angle" },
+ { "display_hflip", OPT_VIDEO | OPT_BOOL | OPT_SPEC | OPT_INPUT, { .off = OFFSET(display_hflips) },
+ "set display horizontal flip for stream(s) "
+ "(overrides any display rotation if it is not set)"},
+ { "display_vflip", OPT_VIDEO | OPT_BOOL | OPT_SPEC | OPT_INPUT, { .off = OFFSET(display_vflips) },
+ "set display vertical flip for stream(s) "
+ "(overrides any display rotation if it is not set)"},
{ "vn", OPT_VIDEO | OPT_BOOL | OPT_OFFSET | OPT_INPUT | OPT_OUTPUT,{ .off = OFFSET(video_disable) },
"disable video" },
{ "rc_override", OPT_VIDEO | HAS_ARG | OPT_EXPERT | OPT_STRING | OPT_SPEC |
@@ -3304,10 +1593,6 @@ const OptionDef options[] = {
{ "vcodec", OPT_VIDEO | HAS_ARG | OPT_PERFILE | OPT_INPUT |
OPT_OUTPUT, { .func_arg = opt_video_codec },
"force video codec ('copy' to copy stream)", "codec" },
- { "sameq", OPT_VIDEO | OPT_EXPERT , { .func_arg = opt_sameq },
- "Removed" },
- { "same_quant", OPT_VIDEO | OPT_EXPERT , { .func_arg = opt_sameq },
- "Removed" },
{ "timecode", OPT_VIDEO | HAS_ARG | OPT_PERFILE | OPT_OUTPUT, { .func_arg = opt_timecode },
"set initial TimeCode value.", "hh:mm:ss[:;.]ff" },
{ "pass", OPT_VIDEO | HAS_ARG | OPT_SPEC | OPT_INT | OPT_OUTPUT, { .off = OFFSET(pass) },
@@ -3315,14 +1600,16 @@ const OptionDef options[] = {
{ "passlogfile", OPT_VIDEO | HAS_ARG | OPT_STRING | OPT_EXPERT | OPT_SPEC |
OPT_OUTPUT, { .off = OFFSET(passlogfiles) },
"select two pass log file name prefix", "prefix" },
- { "deinterlace", OPT_VIDEO | OPT_BOOL | OPT_EXPERT, { &do_deinterlace },
- "this option is deprecated, use the yadif filter instead" },
+#if FFMPEG_OPT_PSNR
{ "psnr", OPT_VIDEO | OPT_BOOL | OPT_EXPERT, { &do_psnr },
- "calculate PSNR of compressed frames" },
+ "calculate PSNR of compressed frames (deprecated, use -flags +psnr)" },
+#endif
{ "vstats", OPT_VIDEO | OPT_EXPERT , { .func_arg = opt_vstats },
"dump video coding statistics to file" },
{ "vstats_file", OPT_VIDEO | HAS_ARG | OPT_EXPERT , { .func_arg = opt_vstats_file },
"dump video coding statistics to file", "file" },
+ { "vstats_version", OPT_VIDEO | OPT_INT | HAS_ARG | OPT_EXPERT , { &vstats_version },
+ "Version of the vstats format to use."},
{ "vf", OPT_VIDEO | HAS_ARG | OPT_PERFILE | OPT_OUTPUT, { .func_arg = opt_video_filters },
"set video filters", "filter_graph" },
{ "intra_matrix", OPT_VIDEO | HAS_ARG | OPT_EXPERT | OPT_STRING | OPT_SPEC |
@@ -3342,6 +1629,9 @@ const OptionDef options[] = {
"force video tag/fourcc", "fourcc/tag" },
{ "qphist", OPT_VIDEO | OPT_BOOL | OPT_EXPERT , { &qp_hist },
"show QP histogram" },
+ { "fps_mode", OPT_VIDEO | HAS_ARG | OPT_STRING | OPT_EXPERT |
+ OPT_SPEC | OPT_OUTPUT, { .off = OFFSET(fps_mode) },
+ "set framerate mode for matching video streams; overrides vsync" },
{ "force_fps", OPT_VIDEO | OPT_BOOL | OPT_EXPERT | OPT_SPEC |
OPT_OUTPUT, { .off = OFFSET(force_fps) },
"force the selected framerate, disable the best supported framerate selection" },
@@ -3351,8 +1641,6 @@ const OptionDef options[] = {
{ "force_key_frames", OPT_VIDEO | OPT_STRING | HAS_ARG | OPT_EXPERT |
OPT_SPEC | OPT_OUTPUT, { .off = OFFSET(forced_key_frames) },
"force key frames at specified timestamps", "timestamps" },
- { "ab", OPT_VIDEO | HAS_ARG | OPT_PERFILE | OPT_OUTPUT, { .func_arg = opt_bitrate },
- "audio bitrate (please use -b:a)", "bitrate" },
{ "b", OPT_VIDEO | HAS_ARG | OPT_PERFILE | OPT_OUTPUT, { .func_arg = opt_bitrate },
"video bitrate (please use -b:v)", "bitrate" },
{ "hwaccel", OPT_VIDEO | OPT_STRING | HAS_ARG | OPT_EXPERT |
@@ -3361,17 +1649,22 @@ const OptionDef options[] = {
{ "hwaccel_device", OPT_VIDEO | OPT_STRING | HAS_ARG | OPT_EXPERT |
OPT_SPEC | OPT_INPUT, { .off = OFFSET(hwaccel_devices) },
"select a device for HW acceleration", "devicename" },
-#if HAVE_VDPAU_X11
- { "vdpau_api_ver", HAS_ARG | OPT_INT | OPT_EXPERT, { &vdpau_api_ver }, "" },
-#endif
-#if CONFIG_VDA || CONFIG_VIDEOTOOLBOX
- { "videotoolbox_pixfmt", HAS_ARG | OPT_STRING | OPT_EXPERT, { &videotoolbox_pixfmt}, "" },
-#endif
+ { "hwaccel_output_format", OPT_VIDEO | OPT_STRING | HAS_ARG | OPT_EXPERT |
+ OPT_SPEC | OPT_INPUT, { .off = OFFSET(hwaccel_output_formats) },
+ "select output format used with HW accelerated decoding", "format" },
{ "hwaccels", OPT_EXIT, { .func_arg = show_hwaccels },
"show available HW acceleration methods" },
{ "autorotate", HAS_ARG | OPT_BOOL | OPT_SPEC |
OPT_EXPERT | OPT_INPUT, { .off = OFFSET(autorotate) },
"automatically insert correct rotate filters" },
+ { "autoscale", HAS_ARG | OPT_BOOL | OPT_SPEC |
+ OPT_EXPERT | OPT_OUTPUT, { .off = OFFSET(autoscale) },
+ "automatically insert a scale filter at the end of the filter graph" },
+ { "fix_sub_duration_heartbeat", OPT_VIDEO | OPT_BOOL | OPT_EXPERT |
+ OPT_SPEC | OPT_OUTPUT, { .off = OFFSET(fix_sub_duration_heartbeat) },
+ "set this video output stream to be a heartbeat stream for "
+ "fix_sub_duration, according to which subtitles should be split at "
+ "random access points" },
/* audio options */
{ "aframes", OPT_AUDIO | HAS_ARG | OPT_PERFILE | OPT_OUTPUT, { .func_arg = opt_audio_frames },
@@ -3389,16 +1682,19 @@ const OptionDef options[] = {
{ "acodec", OPT_AUDIO | HAS_ARG | OPT_PERFILE |
OPT_INPUT | OPT_OUTPUT, { .func_arg = opt_audio_codec },
"force audio codec ('copy' to copy stream)", "codec" },
+ { "ab", OPT_AUDIO | HAS_ARG | OPT_PERFILE | OPT_OUTPUT, { .func_arg = opt_bitrate },
+ "audio bitrate (please use -b:a)", "bitrate" },
{ "atag", OPT_AUDIO | HAS_ARG | OPT_EXPERT | OPT_PERFILE |
OPT_OUTPUT, { .func_arg = opt_old2new },
"force audio tag/fourcc", "fourcc/tag" },
- { "vol", OPT_AUDIO | HAS_ARG | OPT_INT, { &audio_volume },
- "change audio volume (256=normal)" , "volume" },
{ "sample_fmt", OPT_AUDIO | HAS_ARG | OPT_EXPERT | OPT_SPEC |
OPT_STRING | OPT_INPUT | OPT_OUTPUT, { .off = OFFSET(sample_fmts) },
"set sample format", "format" },
- { "channel_layout", OPT_AUDIO | HAS_ARG | OPT_EXPERT | OPT_PERFILE |
- OPT_INPUT | OPT_OUTPUT, { .func_arg = opt_channel_layout },
+ { "channel_layout", OPT_AUDIO | HAS_ARG | OPT_EXPERT | OPT_SPEC |
+ OPT_STRING | OPT_INPUT | OPT_OUTPUT, { .off = OFFSET(audio_ch_layouts) },
+ "set channel layout", "layout" },
+ { "ch_layout", OPT_AUDIO | HAS_ARG | OPT_EXPERT | OPT_SPEC |
+ OPT_STRING | OPT_INPUT | OPT_OUTPUT, { .off = OFFSET(audio_ch_layouts) },
"set channel layout", "layout" },
{ "af", OPT_AUDIO | HAS_ARG | OPT_PERFILE | OPT_OUTPUT, { .func_arg = opt_audio_filters },
"set audio filters", "filter_graph" },
@@ -3417,23 +1713,22 @@ const OptionDef options[] = {
{ "canvas_size", OPT_SUBTITLE | HAS_ARG | OPT_STRING | OPT_SPEC | OPT_INPUT, { .off = OFFSET(canvas_sizes) },
"set canvas size (WxH or abbreviation)", "size" },
- /* grab options */
- { "vc", HAS_ARG | OPT_EXPERT | OPT_VIDEO, { .func_arg = opt_video_channel },
- "deprecated, use -channel", "channel" },
- { "tvstd", HAS_ARG | OPT_EXPERT | OPT_VIDEO, { .func_arg = opt_video_standard },
- "deprecated, use -standard", "standard" },
- { "isync", OPT_BOOL | OPT_EXPERT, { &input_sync }, "this option is deprecated and does nothing", "" },
-
/* muxer options */
{ "muxdelay", OPT_FLOAT | HAS_ARG | OPT_EXPERT | OPT_OFFSET | OPT_OUTPUT, { .off = OFFSET(mux_max_delay) },
"set the maximum demux-decode delay", "seconds" },
{ "muxpreload", OPT_FLOAT | HAS_ARG | OPT_EXPERT | OPT_OFFSET | OPT_OUTPUT, { .off = OFFSET(mux_preload) },
"set the initial demux-decode delay", "seconds" },
- { "override_ffserver", OPT_BOOL | OPT_EXPERT | OPT_OUTPUT, { &override_ffserver },
- "override the options from ffserver", "" },
{ "sdp_file", HAS_ARG | OPT_EXPERT | OPT_OUTPUT, { .func_arg = opt_sdp_file },
"specify a file in which to print sdp information", "file" },
+ { "time_base", HAS_ARG | OPT_STRING | OPT_EXPERT | OPT_SPEC | OPT_OUTPUT, { .off = OFFSET(time_bases) },
+ "set the desired time base hint for output stream (1:24, 1:48000 or 0.04166, 2.0833e-5)", "ratio" },
+ { "enc_time_base", HAS_ARG | OPT_STRING | OPT_EXPERT | OPT_SPEC | OPT_OUTPUT, { .off = OFFSET(enc_time_bases) },
+ "set the desired time base for the encoder (1:24, 1:48000 or 0.04166, 2.0833e-5). "
+ "two special values are defined - "
+ "0 = use frame rate (video) or sample rate (audio),"
+ "-1 = match source time base", "ratio" },
+
{ "bsf", HAS_ARG | OPT_STRING | OPT_SPEC | OPT_EXPERT | OPT_OUTPUT, { .off = OFFSET(bitstream_filters) },
"A comma-separated list of bitstream filters", "bitstream_filters" },
{ "absf", HAS_ARG | OPT_AUDIO | OPT_EXPERT| OPT_PERFILE | OPT_OUTPUT, { .func_arg = opt_old2new },
@@ -3449,11 +1744,32 @@ const OptionDef options[] = {
"set the subtitle options to the indicated preset", "preset" },
{ "fpre", HAS_ARG | OPT_EXPERT| OPT_PERFILE | OPT_OUTPUT, { .func_arg = opt_preset },
"set options from indicated preset file", "filename" },
+
+ { "max_muxing_queue_size", HAS_ARG | OPT_INT | OPT_SPEC | OPT_EXPERT | OPT_OUTPUT, { .off = OFFSET(max_muxing_queue_size) },
+ "maximum number of packets that can be buffered while waiting for all streams to initialize", "packets" },
+ { "muxing_queue_data_threshold", HAS_ARG | OPT_INT | OPT_SPEC | OPT_EXPERT | OPT_OUTPUT, { .off = OFFSET(muxing_queue_data_threshold) },
+ "set the threshold after which max_muxing_queue_size is taken into account", "bytes" },
+
/* data codec support */
{ "dcodec", HAS_ARG | OPT_DATA | OPT_PERFILE | OPT_EXPERT | OPT_INPUT | OPT_OUTPUT, { .func_arg = opt_data_codec },
"force data codec ('copy' to copy stream)", "codec" },
{ "dn", OPT_BOOL | OPT_VIDEO | OPT_OFFSET | OPT_INPUT | OPT_OUTPUT, { .off = OFFSET(data_disable) },
"disable data" },
+#if CONFIG_VAAPI
+ { "vaapi_device", HAS_ARG | OPT_EXPERT, { .func_arg = opt_vaapi_device },
+ "set VAAPI hardware device (DRM path or X11 display name)", "device" },
+#endif
+
+#if CONFIG_QSV
+ { "qsv_device", HAS_ARG | OPT_EXPERT, { .func_arg = opt_qsv_device },
+ "set QSV hardware device (DirectX adapter index, DRM path or X11 display name)", "device"},
+#endif
+
+ { "init_hw_device", HAS_ARG | OPT_EXPERT, { .func_arg = opt_init_hw_device },
+ "initialise hardware device", "args" },
+ { "filter_hw_device", HAS_ARG | OPT_EXPERT, { .func_arg = opt_filter_hw_device },
+ "set hardware device used when filtering", "device" },
+
{ NULL, },
};
diff --git a/app/src/main/cpp/ffmpeg/ffprobe.c b/app/src/main/cpp/ffmpeg/ffprobe.c
new file mode 100644
index 00000000..2a64f09b
--- /dev/null
+++ b/app/src/main/cpp/ffmpeg/ffprobe.c
@@ -0,0 +1,4288 @@
+/*
+ * Copyright (c) 2007-2010 Stefano Sabatini
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/**
+ * @file
+ * simple media prober based on the FFmpeg libraries
+ */
+
+#include "config.h"
+#include "libavutil/ffversion.h"
+
+#include
+#include
+
+#include "libavformat/avformat.h"
+#include "libavformat/version.h"
+#include "libavcodec/avcodec.h"
+#include "libavcodec/version.h"
+#include "libavutil/ambient_viewing_environment.h"
+#include "libavutil/avassert.h"
+#include "libavutil/avstring.h"
+#include "libavutil/bprint.h"
+#include "libavutil/channel_layout.h"
+#include "libavutil/display.h"
+#include "libavutil/hash.h"
+#include "libavutil/hdr_dynamic_metadata.h"
+#include "libavutil/mastering_display_metadata.h"
+#include "libavutil/hdr_dynamic_vivid_metadata.h"
+#include "libavutil/dovi_meta.h"
+#include "libavutil/opt.h"
+#include "libavutil/pixdesc.h"
+#include "libavutil/spherical.h"
+#include "libavutil/stereo3d.h"
+#include "libavutil/dict.h"
+#include "libavutil/intreadwrite.h"
+#include "libavutil/libm.h"
+#include "libavutil/parseutils.h"
+#include "libavutil/timecode.h"
+#include "libavutil/timestamp.h"
+#include "libswscale/swscale.h"
+#include "libswscale/version.h"
+#include "libswresample/swresample.h"
+#include "libswresample/version.h"
+#include "libavfilter/version.h"
+#include "cmdutils.h"
+#include "opt_common.h"
+
+#include "libavutil/thread.h"
+
+#if !HAVE_THREADS
+# ifdef pthread_mutex_lock
+# undef pthread_mutex_lock
+# endif
+# define pthread_mutex_lock(a) do{}while(0)
+# ifdef pthread_mutex_unlock
+# undef pthread_mutex_unlock
+# endif
+# define pthread_mutex_unlock(a) do{}while(0)
+#endif
+
+#include "ffprobe.h"
+
+typedef struct InputStream {
+ AVStream *st;
+
+ AVCodecContext *dec_ctx;
+} InputStream;
+
+typedef struct InputFile {
+ AVFormatContext *fmt_ctx;
+
+ InputStream *streams;
+ int nb_streams;
+} InputFile;
+
+const char ffprobe_program_name[] = "ffprobe";
+const int ffprobe_program_birth_year = 2007;
+
+static int do_bitexact = 0;
+static int do_count_frames = 0;
+static int do_count_packets = 0;
+static int do_read_frames = 0;
+static int do_read_packets = 0;
+static int do_show_chapters = 0;
+static int do_show_error = 0;
+static int do_show_format = 0;
+static int do_show_frames = 0;
+static int do_show_packets = 0;
+static int do_show_programs = 0;
+static int do_show_streams = 0;
+static int do_show_stream_disposition = 0;
+static int do_show_data = 0;
+static int do_show_program_version = 0;
+static int do_show_library_versions = 0;
+static int do_show_pixel_formats = 0;
+static int do_show_pixel_format_flags = 0;
+static int do_show_pixel_format_components = 0;
+static int do_show_log = 0;
+
+static int do_show_chapter_tags = 0;
+static int do_show_format_tags = 0;
+static int do_show_frame_tags = 0;
+static int do_show_program_tags = 0;
+static int do_show_stream_tags = 0;
+static int do_show_packet_tags = 0;
+
+static int show_value_unit = 0;
+static int use_value_prefix = 0;
+static int use_byte_value_binary_prefix = 0;
+static int use_value_sexagesimal_format = 0;
+static int show_private_data = 1;
+
+#define SHOW_OPTIONAL_FIELDS_AUTO -1
+#define SHOW_OPTIONAL_FIELDS_NEVER 0
+#define SHOW_OPTIONAL_FIELDS_ALWAYS 1
+static int show_optional_fields = SHOW_OPTIONAL_FIELDS_AUTO;
+
+static char *print_format;
+static char *stream_specifier;
+static char *show_data_hash;
+
+typedef struct ReadInterval {
+ int id; ///< identifier
+ int64_t start, end; ///< start, end in second/AV_TIME_BASE units
+ int has_start, has_end;
+ int start_is_offset, end_is_offset;
+ int duration_frames;
+} ReadInterval;
+
+static ReadInterval *read_intervals;
+static int read_intervals_nb = 0;
+
+static int find_stream_info = 1;
+
+/* section structure definition */
+
+#define SECTION_MAX_NB_CHILDREN 10
+
+struct section {
+ int id; ///< unique id identifying a section
+ const char *name;
+
+#define SECTION_FLAG_IS_WRAPPER 1 ///< the section only contains other sections, but has no data at its own level
+#define SECTION_FLAG_IS_ARRAY 2 ///< the section contains an array of elements of the same type
+#define SECTION_FLAG_HAS_VARIABLE_FIELDS 4 ///< the section may contain a variable number of fields with variable keys.
+ /// For these sections the element_name field is mandatory.
+ int flags;
+ int children_ids[SECTION_MAX_NB_CHILDREN+1]; ///< list of children section IDS, terminated by -1
+ const char *element_name; ///< name of the contained element, if provided
+ const char *unique_name; ///< unique section name, in case the name is ambiguous
+ AVDictionary *entries_to_show;
+ int show_all_entries;
+};
+
+typedef enum {
+ SECTION_ID_NONE = -1,
+ SECTION_ID_CHAPTER,
+ SECTION_ID_CHAPTER_TAGS,
+ SECTION_ID_CHAPTERS,
+ SECTION_ID_ERROR,
+ SECTION_ID_FORMAT,
+ SECTION_ID_FORMAT_TAGS,
+ SECTION_ID_FRAME,
+ SECTION_ID_FRAMES,
+ SECTION_ID_FRAME_TAGS,
+ SECTION_ID_FRAME_SIDE_DATA_LIST,
+ SECTION_ID_FRAME_SIDE_DATA,
+ SECTION_ID_FRAME_SIDE_DATA_TIMECODE_LIST,
+ SECTION_ID_FRAME_SIDE_DATA_TIMECODE,
+ SECTION_ID_FRAME_SIDE_DATA_COMPONENT_LIST,
+ SECTION_ID_FRAME_SIDE_DATA_COMPONENT,
+ SECTION_ID_FRAME_SIDE_DATA_PIECE_LIST,
+ SECTION_ID_FRAME_SIDE_DATA_PIECE,
+ SECTION_ID_FRAME_LOG,
+ SECTION_ID_FRAME_LOGS,
+ SECTION_ID_LIBRARY_VERSION,
+ SECTION_ID_LIBRARY_VERSIONS,
+ SECTION_ID_PACKET,
+ SECTION_ID_PACKET_TAGS,
+ SECTION_ID_PACKETS,
+ SECTION_ID_PACKETS_AND_FRAMES,
+ SECTION_ID_PACKET_SIDE_DATA_LIST,
+ SECTION_ID_PACKET_SIDE_DATA,
+ SECTION_ID_PIXEL_FORMAT,
+ SECTION_ID_PIXEL_FORMAT_FLAGS,
+ SECTION_ID_PIXEL_FORMAT_COMPONENT,
+ SECTION_ID_PIXEL_FORMAT_COMPONENTS,
+ SECTION_ID_PIXEL_FORMATS,
+ SECTION_ID_PROGRAM_STREAM_DISPOSITION,
+ SECTION_ID_PROGRAM_STREAM_TAGS,
+ SECTION_ID_PROGRAM,
+ SECTION_ID_PROGRAM_STREAMS,
+ SECTION_ID_PROGRAM_STREAM,
+ SECTION_ID_PROGRAM_TAGS,
+ SECTION_ID_PROGRAM_VERSION,
+ SECTION_ID_PROGRAMS,
+ SECTION_ID_ROOT,
+ SECTION_ID_STREAM,
+ SECTION_ID_STREAM_DISPOSITION,
+ SECTION_ID_STREAMS,
+ SECTION_ID_STREAM_TAGS,
+ SECTION_ID_STREAM_SIDE_DATA_LIST,
+ SECTION_ID_STREAM_SIDE_DATA,
+ SECTION_ID_SUBTITLE,
+} SectionID;
+
+static struct section sections[] = {
+ [SECTION_ID_CHAPTERS] = { SECTION_ID_CHAPTERS, "chapters", SECTION_FLAG_IS_ARRAY, { SECTION_ID_CHAPTER, -1 } },
+ [SECTION_ID_CHAPTER] = { SECTION_ID_CHAPTER, "chapter", 0, { SECTION_ID_CHAPTER_TAGS, -1 } },
+ [SECTION_ID_CHAPTER_TAGS] = { SECTION_ID_CHAPTER_TAGS, "tags", SECTION_FLAG_HAS_VARIABLE_FIELDS, { -1 }, .element_name = "tag", .unique_name = "chapter_tags" },
+ [SECTION_ID_ERROR] = { SECTION_ID_ERROR, "error", 0, { -1 } },
+ [SECTION_ID_FORMAT] = { SECTION_ID_FORMAT, "format", 0, { SECTION_ID_FORMAT_TAGS, -1 } },
+ [SECTION_ID_FORMAT_TAGS] = { SECTION_ID_FORMAT_TAGS, "tags", SECTION_FLAG_HAS_VARIABLE_FIELDS, { -1 }, .element_name = "tag", .unique_name = "format_tags" },
+ [SECTION_ID_FRAMES] = { SECTION_ID_FRAMES, "frames", SECTION_FLAG_IS_ARRAY, { SECTION_ID_FRAME, SECTION_ID_SUBTITLE, -1 } },
+ [SECTION_ID_FRAME] = { SECTION_ID_FRAME, "frame", 0, { SECTION_ID_FRAME_TAGS, SECTION_ID_FRAME_SIDE_DATA_LIST, SECTION_ID_FRAME_LOGS, -1 } },
+ [SECTION_ID_FRAME_TAGS] = { SECTION_ID_FRAME_TAGS, "tags", SECTION_FLAG_HAS_VARIABLE_FIELDS, { -1 }, .element_name = "tag", .unique_name = "frame_tags" },
+ [SECTION_ID_FRAME_SIDE_DATA_LIST] ={ SECTION_ID_FRAME_SIDE_DATA_LIST, "side_data_list", SECTION_FLAG_IS_ARRAY, { SECTION_ID_FRAME_SIDE_DATA, -1 }, .element_name = "side_data", .unique_name = "frame_side_data_list" },
+ [SECTION_ID_FRAME_SIDE_DATA] = { SECTION_ID_FRAME_SIDE_DATA, "side_data", 0, { SECTION_ID_FRAME_SIDE_DATA_TIMECODE_LIST, SECTION_ID_FRAME_SIDE_DATA_COMPONENT_LIST, -1 }, .unique_name = "frame_side_data" },
+ [SECTION_ID_FRAME_SIDE_DATA_TIMECODE_LIST] = { SECTION_ID_FRAME_SIDE_DATA_TIMECODE_LIST, "timecodes", SECTION_FLAG_IS_ARRAY, { SECTION_ID_FRAME_SIDE_DATA_TIMECODE, -1 } },
+ [SECTION_ID_FRAME_SIDE_DATA_TIMECODE] = { SECTION_ID_FRAME_SIDE_DATA_TIMECODE, "timecode", 0, { -1 } },
+ [SECTION_ID_FRAME_SIDE_DATA_COMPONENT_LIST] = { SECTION_ID_FRAME_SIDE_DATA_COMPONENT_LIST, "components", SECTION_FLAG_IS_ARRAY, { SECTION_ID_FRAME_SIDE_DATA_COMPONENT, -1 } },
+ [SECTION_ID_FRAME_SIDE_DATA_COMPONENT] = { SECTION_ID_FRAME_SIDE_DATA_COMPONENT, "component", 0, { SECTION_ID_FRAME_SIDE_DATA_PIECE_LIST, -1 } },
+ [SECTION_ID_FRAME_SIDE_DATA_PIECE_LIST] = { SECTION_ID_FRAME_SIDE_DATA_PIECE_LIST, "pieces", SECTION_FLAG_IS_ARRAY, { SECTION_ID_FRAME_SIDE_DATA_PIECE, -1 } },
+ [SECTION_ID_FRAME_SIDE_DATA_PIECE] = { SECTION_ID_FRAME_SIDE_DATA_PIECE, "section", 0, { -1 } },
+ [SECTION_ID_FRAME_LOGS] = { SECTION_ID_FRAME_LOGS, "logs", SECTION_FLAG_IS_ARRAY, { SECTION_ID_FRAME_LOG, -1 } },
+ [SECTION_ID_FRAME_LOG] = { SECTION_ID_FRAME_LOG, "log", 0, { -1 }, },
+ [SECTION_ID_LIBRARY_VERSIONS] = { SECTION_ID_LIBRARY_VERSIONS, "library_versions", SECTION_FLAG_IS_ARRAY, { SECTION_ID_LIBRARY_VERSION, -1 } },
+ [SECTION_ID_LIBRARY_VERSION] = { SECTION_ID_LIBRARY_VERSION, "library_version", 0, { -1 } },
+ [SECTION_ID_PACKETS] = { SECTION_ID_PACKETS, "packets", SECTION_FLAG_IS_ARRAY, { SECTION_ID_PACKET, -1} },
+ [SECTION_ID_PACKETS_AND_FRAMES] = { SECTION_ID_PACKETS_AND_FRAMES, "packets_and_frames", SECTION_FLAG_IS_ARRAY, { SECTION_ID_PACKET, -1} },
+ [SECTION_ID_PACKET] = { SECTION_ID_PACKET, "packet", 0, { SECTION_ID_PACKET_TAGS, SECTION_ID_PACKET_SIDE_DATA_LIST, -1 } },
+ [SECTION_ID_PACKET_TAGS] = { SECTION_ID_PACKET_TAGS, "tags", SECTION_FLAG_HAS_VARIABLE_FIELDS, { -1 }, .element_name = "tag", .unique_name = "packet_tags" },
+ [SECTION_ID_PACKET_SIDE_DATA_LIST] ={ SECTION_ID_PACKET_SIDE_DATA_LIST, "side_data_list", SECTION_FLAG_IS_ARRAY, { SECTION_ID_PACKET_SIDE_DATA, -1 }, .element_name = "side_data", .unique_name = "packet_side_data_list" },
+ [SECTION_ID_PACKET_SIDE_DATA] = { SECTION_ID_PACKET_SIDE_DATA, "side_data", 0, { -1 }, .unique_name = "packet_side_data" },
+ [SECTION_ID_PIXEL_FORMATS] = { SECTION_ID_PIXEL_FORMATS, "pixel_formats", SECTION_FLAG_IS_ARRAY, { SECTION_ID_PIXEL_FORMAT, -1 } },
+ [SECTION_ID_PIXEL_FORMAT] = { SECTION_ID_PIXEL_FORMAT, "pixel_format", 0, { SECTION_ID_PIXEL_FORMAT_FLAGS, SECTION_ID_PIXEL_FORMAT_COMPONENTS, -1 } },
+ [SECTION_ID_PIXEL_FORMAT_FLAGS] = { SECTION_ID_PIXEL_FORMAT_FLAGS, "flags", 0, { -1 }, .unique_name = "pixel_format_flags" },
+ [SECTION_ID_PIXEL_FORMAT_COMPONENTS] = { SECTION_ID_PIXEL_FORMAT_COMPONENTS, "components", SECTION_FLAG_IS_ARRAY, {SECTION_ID_PIXEL_FORMAT_COMPONENT, -1 }, .unique_name = "pixel_format_components" },
+ [SECTION_ID_PIXEL_FORMAT_COMPONENT] = { SECTION_ID_PIXEL_FORMAT_COMPONENT, "component", 0, { -1 } },
+ [SECTION_ID_PROGRAM_STREAM_DISPOSITION] = { SECTION_ID_PROGRAM_STREAM_DISPOSITION, "disposition", 0, { -1 }, .unique_name = "program_stream_disposition" },
+ [SECTION_ID_PROGRAM_STREAM_TAGS] = { SECTION_ID_PROGRAM_STREAM_TAGS, "tags", SECTION_FLAG_HAS_VARIABLE_FIELDS, { -1 }, .element_name = "tag", .unique_name = "program_stream_tags" },
+ [SECTION_ID_PROGRAM] = { SECTION_ID_PROGRAM, "program", 0, { SECTION_ID_PROGRAM_TAGS, SECTION_ID_PROGRAM_STREAMS, -1 } },
+ [SECTION_ID_PROGRAM_STREAMS] = { SECTION_ID_PROGRAM_STREAMS, "streams", SECTION_FLAG_IS_ARRAY, { SECTION_ID_PROGRAM_STREAM, -1 }, .unique_name = "program_streams" },
+ [SECTION_ID_PROGRAM_STREAM] = { SECTION_ID_PROGRAM_STREAM, "stream", 0, { SECTION_ID_PROGRAM_STREAM_DISPOSITION, SECTION_ID_PROGRAM_STREAM_TAGS, -1 }, .unique_name = "program_stream" },
+ [SECTION_ID_PROGRAM_TAGS] = { SECTION_ID_PROGRAM_TAGS, "tags", SECTION_FLAG_HAS_VARIABLE_FIELDS, { -1 }, .element_name = "tag", .unique_name = "program_tags" },
+ [SECTION_ID_PROGRAM_VERSION] = { SECTION_ID_PROGRAM_VERSION, "program_version", 0, { -1 } },
+ [SECTION_ID_PROGRAMS] = { SECTION_ID_PROGRAMS, "programs", SECTION_FLAG_IS_ARRAY, { SECTION_ID_PROGRAM, -1 } },
+ [SECTION_ID_ROOT] = { SECTION_ID_ROOT, "root", SECTION_FLAG_IS_WRAPPER,
+ { SECTION_ID_CHAPTERS, SECTION_ID_FORMAT, SECTION_ID_FRAMES, SECTION_ID_PROGRAMS, SECTION_ID_STREAMS,
+ SECTION_ID_PACKETS, SECTION_ID_ERROR, SECTION_ID_PROGRAM_VERSION, SECTION_ID_LIBRARY_VERSIONS,
+ SECTION_ID_PIXEL_FORMATS, -1} },
+ [SECTION_ID_STREAMS] = { SECTION_ID_STREAMS, "streams", SECTION_FLAG_IS_ARRAY, { SECTION_ID_STREAM, -1 } },
+ [SECTION_ID_STREAM] = { SECTION_ID_STREAM, "stream", 0, { SECTION_ID_STREAM_DISPOSITION, SECTION_ID_STREAM_TAGS, SECTION_ID_STREAM_SIDE_DATA_LIST, -1 } },
+ [SECTION_ID_STREAM_DISPOSITION] = { SECTION_ID_STREAM_DISPOSITION, "disposition", 0, { -1 }, .unique_name = "stream_disposition" },
+ [SECTION_ID_STREAM_TAGS] = { SECTION_ID_STREAM_TAGS, "tags", SECTION_FLAG_HAS_VARIABLE_FIELDS, { -1 }, .element_name = "tag", .unique_name = "stream_tags" },
+ [SECTION_ID_STREAM_SIDE_DATA_LIST] ={ SECTION_ID_STREAM_SIDE_DATA_LIST, "side_data_list", SECTION_FLAG_IS_ARRAY, { SECTION_ID_STREAM_SIDE_DATA, -1 }, .element_name = "side_data", .unique_name = "stream_side_data_list" },
+ [SECTION_ID_STREAM_SIDE_DATA] = { SECTION_ID_STREAM_SIDE_DATA, "side_data", 0, { -1 }, .unique_name = "stream_side_data" },
+ [SECTION_ID_SUBTITLE] = { SECTION_ID_SUBTITLE, "subtitle", 0, { -1 } },
+};
+
+static const OptionDef *options;
+
+/* FFprobe context */
+static const char *input_filename;
+static const char *print_input_filename;
+static const AVInputFormat *iformat = NULL;
+static const char *output_filename = NULL;
+
+static struct AVHashContext *hash;
+
+static const struct {
+ double bin_val;
+ double dec_val;
+ const char *bin_str;
+ const char *dec_str;
+} si_prefixes[] = {
+ { 1.0, 1.0, "", "" },
+ { 1.024e3, 1e3, "Ki", "K" },
+ { 1.048576e6, 1e6, "Mi", "M" },
+ { 1.073741824e9, 1e9, "Gi", "G" },
+ { 1.099511627776e12, 1e12, "Ti", "T" },
+ { 1.125899906842624e15, 1e15, "Pi", "P" },
+};
+
+static const char unit_second_str[] = "s" ;
+static const char unit_hertz_str[] = "Hz" ;
+static const char unit_byte_str[] = "byte" ;
+static const char unit_bit_per_second_str[] = "bit/s";
+
+static int nb_streams;
+static uint64_t *nb_streams_packets;
+static uint64_t *nb_streams_frames;
+static int *selected_streams;
+
+#if HAVE_THREADS
+pthread_mutex_t log_mutex;
+#endif
+typedef struct LogBuffer {
+ char *context_name;
+ int log_level;
+ char *log_message;
+ AVClassCategory category;
+ char *parent_name;
+ AVClassCategory parent_category;
+}LogBuffer;
+
+static LogBuffer *log_buffer;
+static int log_buffer_size;
+
+static int buffer_length = 0;
+static int buffer_size = 256 * 1024;
+char *print_buffer = NULL;
+
+int get_category(void *ptr) {
+ AVClass *avc = *(AVClass **) ptr;
+ if (!avc
+ || (avc->version & 0xFF) < 100
+ || avc->version < (51 << 16 | 59 << 8)
+ || avc->category >= AV_CLASS_CATEGORY_NB)
+ return AV_CLASS_CATEGORY_NA + 16;
+
+ if (avc->get_category)
+ return avc->get_category(ptr) + 16;
+
+ return avc->category + 16;
+}
+
+void format_line(void *avcl, const char *fmt, va_list vl,
+ AVBPrint part[4], int *print_prefix, int type[2]) {
+ AVClass *avc = avcl ? *(AVClass **) avcl : NULL;
+ av_bprint_init(part + 0, 0, 1);
+ av_bprint_init(part + 1, 0, 1);
+ av_bprint_init(part + 2, 0, 1);
+ av_bprint_init(part + 3, 0, 65536);
+
+ if (type) type[0] = type[1] = AV_CLASS_CATEGORY_NA + 16;
+ if (*print_prefix && avc) {
+ if (avc->parent_log_context_offset) {
+ AVClass **parent = *(AVClass ***) (((uint8_t *) avcl) +
+ avc->parent_log_context_offset);
+ if (parent && *parent) {
+ av_bprintf(part + 0, "[%s @ %p] ",
+ (*parent)->item_name(parent), parent);
+ if (type) type[0] = get_category(parent);
+ }
+ }
+ av_bprintf(part + 1, "[%s @ %p] ",
+ avc->item_name(avcl), avcl);
+ if (type) type[1] = get_category(avcl);
+ }
+
+ av_vbprintf(part + 3, fmt, vl);
+
+ if (*part[0].str || *part[1].str || *part[2].str || *part[3].str) {
+ char lastc = part[3].len && part[3].len <= part[3].size ? part[3].str[part[3].len - 1] : 0;
+ *print_prefix = lastc == '\n' || lastc == '\r';
+ }
+}
+
+int printf_json(char *buffer, int maxsize, char *fmt, va_list args) {
+
+ static int print_prefix = 1;
+ int type[2];
+ AVBPrint part[4];
+ format_line(NULL, fmt, args, part, &print_prefix, type);
+ int length = snprintf(buffer, maxsize, "%s%s%s%s", part[0].str, part[1].str, part[2].str,
+ part[3].str);
+ return length;
+}
+
+/**
+ * print the output result as json string
+ *
+ */
+void frank_printf_json(char *fmt, ...) {
+ va_list args;
+ va_start(args, fmt);
+ int length = printf_json(print_buffer + buffer_length, buffer_size - buffer_length, fmt, args);
+ buffer_length += length;
+ va_end(args);
+}
+
+static void log_callback(void *ptr, int level, const char *fmt, va_list vl)
+{
+ AVClass* avc = ptr ? *(AVClass **) ptr : NULL;
+ va_list vl2;
+ char line[1024];
+ static int print_prefix = 1;
+ void *new_log_buffer;
+
+ va_copy(vl2, vl);
+ av_log_default_callback(ptr, level, fmt, vl);
+ av_log_format_line(ptr, level, fmt, vl2, line, sizeof(line), &print_prefix);
+ va_end(vl2);
+
+#if HAVE_THREADS
+ pthread_mutex_lock(&log_mutex);
+
+ new_log_buffer = av_realloc_array(log_buffer, log_buffer_size + 1, sizeof(*log_buffer));
+ if (new_log_buffer) {
+ char *msg;
+ int i;
+
+ log_buffer = new_log_buffer;
+ memset(&log_buffer[log_buffer_size], 0, sizeof(log_buffer[log_buffer_size]));
+ log_buffer[log_buffer_size].context_name= avc ? av_strdup(avc->item_name(ptr)) : NULL;
+ if (avc) {
+ if (avc->get_category) log_buffer[log_buffer_size].category = avc->get_category(ptr);
+ else log_buffer[log_buffer_size].category = avc->category;
+ }
+ log_buffer[log_buffer_size].log_level = level;
+ msg = log_buffer[log_buffer_size].log_message = av_strdup(line);
+ for (i=strlen(msg) - 1; i>=0 && msg[i] == '\n'; i--) {
+ msg[i] = 0;
+ }
+ if (avc && avc->parent_log_context_offset) {
+ AVClass** parent = *(AVClass ***) (((uint8_t *) ptr) +
+ avc->parent_log_context_offset);
+ if (parent && *parent) {
+ log_buffer[log_buffer_size].parent_name = av_strdup((*parent)->item_name(parent));
+ log_buffer[log_buffer_size].parent_category =
+ (*parent)->get_category ? (*parent)->get_category(parent) :(*parent)->category;
+ }
+ }
+ log_buffer_size ++;
+ }
+
+ pthread_mutex_unlock(&log_mutex);
+#endif
+}
+
+static void ffprobe_cleanup(int ret)
+{
+ int i;
+ for (i = 0; i < FF_ARRAY_ELEMS(sections); i++)
+ av_dict_free(&(sections[i].entries_to_show));
+
+ buffer_length = 0;
+ input_filename = NULL;
+ output_filename = NULL;
+#if HAVE_THREADS
+ pthread_mutex_destroy(&log_mutex);
+#endif
+}
+
+struct unit_value {
+ union { double d; long long int i; } val;
+ const char *unit;
+};
+
+static char *value_string(char *buf, int buf_size, struct unit_value uv)
+{
+ double vald;
+ long long int vali;
+ int show_float = 0;
+
+ if (uv.unit == unit_second_str) {
+ vald = uv.val.d;
+ show_float = 1;
+ } else {
+ vald = vali = uv.val.i;
+ }
+
+ if (uv.unit == unit_second_str && use_value_sexagesimal_format) {
+ double secs;
+ int hours, mins;
+ secs = vald;
+ mins = (int)secs / 60;
+ secs = secs - mins * 60;
+ hours = mins / 60;
+ mins %= 60;
+ snprintf(buf, buf_size, "%d:%02d:%09.6f", hours, mins, secs);
+ } else {
+ const char *prefix_string = "";
+
+ if (use_value_prefix && vald > 1) {
+ long long int index;
+
+ if (uv.unit == unit_byte_str && use_byte_value_binary_prefix) {
+ index = (long long int) (log2(vald)) / 10;
+ index = av_clip(index, 0, FF_ARRAY_ELEMS(si_prefixes) - 1);
+ vald /= si_prefixes[index].bin_val;
+ prefix_string = si_prefixes[index].bin_str;
+ } else {
+ index = (long long int) (log10(vald)) / 3;
+ index = av_clip(index, 0, FF_ARRAY_ELEMS(si_prefixes) - 1);
+ vald /= si_prefixes[index].dec_val;
+ prefix_string = si_prefixes[index].dec_str;
+ }
+ vali = vald;
+ }
+
+ if (show_float || (use_value_prefix && vald != (long long int)vald))
+ snprintf(buf, buf_size, "%f", vald);
+ else
+ snprintf(buf, buf_size, "%lld", vali);
+ av_strlcatf(buf, buf_size, "%s%s%s", *prefix_string || show_value_unit ? " " : "",
+ prefix_string, show_value_unit ? uv.unit : "");
+ }
+
+ return buf;
+}
+
+/* WRITERS API */
+
+typedef struct WriterContext WriterContext;
+
+#define WRITER_FLAG_DISPLAY_OPTIONAL_FIELDS 1
+#define WRITER_FLAG_PUT_PACKETS_AND_FRAMES_IN_SAME_CHAPTER 2
+
+typedef enum {
+ WRITER_STRING_VALIDATION_FAIL,
+ WRITER_STRING_VALIDATION_REPLACE,
+ WRITER_STRING_VALIDATION_IGNORE,
+ WRITER_STRING_VALIDATION_NB
+} StringValidation;
+
+typedef struct Writer {
+ const AVClass *priv_class; ///< private class of the writer, if any
+ int priv_size; ///< private size for the writer context
+ const char *name;
+
+ int (*init) (WriterContext *wctx);
+ void (*uninit)(WriterContext *wctx);
+
+ void (*print_section_header)(WriterContext *wctx);
+ void (*print_section_footer)(WriterContext *wctx);
+ void (*print_integer) (WriterContext *wctx, const char *, long long int);
+ void (*print_rational) (WriterContext *wctx, AVRational *q, char *sep);
+ void (*print_string) (WriterContext *wctx, const char *, const char *);
+ int flags; ///< a combination or WRITER_FLAG_*
+} Writer;
+
+#define SECTION_MAX_NB_LEVELS 10
+
+struct WriterContext {
+ const AVClass *class; ///< class of the writer
+ const Writer *writer; ///< the Writer of which this is an instance
+ AVIOContext *avio; ///< the I/O context used to write
+
+ void (* writer_w8)(WriterContext *wctx, int b);
+ void (* writer_put_str)(WriterContext *wctx, const char *str);
+ void (* writer_printf)(WriterContext *wctx, const char *fmt, ...);
+
+ char *name; ///< name of this writer instance
+ void *priv; ///< private data for use by the filter
+
+ const struct section *sections; ///< array containing all sections
+ int nb_sections; ///< number of sections
+
+ int level; ///< current level, starting from 0
+
+ /** number of the item printed in the given section, starting from 0 */
+ unsigned int nb_item[SECTION_MAX_NB_LEVELS];
+
+ /** section per each level */
+ const struct section *section[SECTION_MAX_NB_LEVELS];
+ AVBPrint section_pbuf[SECTION_MAX_NB_LEVELS]; ///< generic print buffer dedicated to each section,
+ /// used by various writers
+
+ unsigned int nb_section_packet; ///< number of the packet section in case we are in "packets_and_frames" section
+ unsigned int nb_section_frame; ///< number of the frame section in case we are in "packets_and_frames" section
+ unsigned int nb_section_packet_frame; ///< nb_section_packet or nb_section_frame according if is_packets_and_frames
+
+ int string_validation;
+ char *string_validation_replacement;
+ unsigned int string_validation_utf8_flags;
+};
+
+static const char *writer_get_name(void *p)
+{
+ WriterContext *wctx = p;
+ return wctx->writer->name;
+}
+
+#define OFFSET(x) offsetof(WriterContext, x)
+
+static const AVOption writer_options[] = {
+ { "string_validation", "set string validation mode",
+ OFFSET(string_validation), AV_OPT_TYPE_INT, {.i64=WRITER_STRING_VALIDATION_REPLACE}, 0, WRITER_STRING_VALIDATION_NB-1, .unit = "sv" },
+ { "sv", "set string validation mode",
+ OFFSET(string_validation), AV_OPT_TYPE_INT, {.i64=WRITER_STRING_VALIDATION_REPLACE}, 0, WRITER_STRING_VALIDATION_NB-1, .unit = "sv" },
+ { "ignore", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = WRITER_STRING_VALIDATION_IGNORE}, .unit = "sv" },
+ { "replace", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = WRITER_STRING_VALIDATION_REPLACE}, .unit = "sv" },
+ { "fail", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = WRITER_STRING_VALIDATION_FAIL}, .unit = "sv" },
+ { "string_validation_replacement", "set string validation replacement string", OFFSET(string_validation_replacement), AV_OPT_TYPE_STRING, {.str=""}},
+ { "svr", "set string validation replacement string", OFFSET(string_validation_replacement), AV_OPT_TYPE_STRING, {.str="\xEF\xBF\xBD"}},
+ { NULL }
+};
+
+static void *writer_child_next(void *obj, void *prev)
+{
+ WriterContext *ctx = obj;
+ if (!prev && ctx->writer && ctx->writer->priv_class && ctx->priv)
+ return ctx->priv;
+ return NULL;
+}
+
+static const AVClass writer_class = {
+ .class_name = "Writer",
+ .item_name = writer_get_name,
+ .option = writer_options,
+ .version = LIBAVUTIL_VERSION_INT,
+ .child_next = writer_child_next,
+};
+
+static int writer_close(WriterContext **wctx)
+{
+ int i;
+ int ret = 0;
+
+ if (!*wctx)
+ return -1;
+
+ if ((*wctx)->writer->uninit)
+ (*wctx)->writer->uninit(*wctx);
+ for (i = 0; i < SECTION_MAX_NB_LEVELS; i++)
+ av_bprint_finalize(&(*wctx)->section_pbuf[i], NULL);
+ if ((*wctx)->writer->priv_class)
+ av_opt_free((*wctx)->priv);
+ av_freep(&((*wctx)->priv));
+ av_opt_free(*wctx);
+ if ((*wctx)->avio) {
+ avio_flush((*wctx)->avio);
+ ret = avio_close((*wctx)->avio);
+ }
+ av_freep(wctx);
+ return ret;
+}
+
+static void bprint_bytes(AVBPrint *bp, const uint8_t *ubuf, size_t ubuf_size)
+{
+ int i;
+ av_bprintf(bp, "0X");
+ for (i = 0; i < ubuf_size; i++)
+ av_bprintf(bp, "%02X", ubuf[i]);
+}
+
+static inline void writer_w8_avio(WriterContext *wctx, int b)
+{
+ avio_w8(wctx->avio, b);
+}
+
+static inline void writer_put_str_avio(WriterContext *wctx, const char *str)
+{
+ avio_write(wctx->avio, str, strlen(str));
+}
+
+static inline void writer_printf_avio(WriterContext *wctx, const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ avio_vprintf(wctx->avio, fmt, ap);
+ va_end(ap);
+}
+
+static inline void writer_w8_printf(WriterContext *wctx, int b)
+{
+ printf("%c", b);
+}
+
+static inline void writer_put_str_printf(WriterContext *wctx, const char *str)
+{
+ printf("%s", str);
+}
+
+static inline void writer_printf_printf(WriterContext *wctx, const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ vprintf(fmt, ap);
+ va_end(ap);
+}
+
+static int writer_open(WriterContext **wctx, const Writer *writer, const char *args,
+ const struct section *sections, int nb_sections, const char *output)
+{
+ int i, ret = 0;
+
+ if (!(*wctx = av_mallocz(sizeof(WriterContext)))) {
+ ret = AVERROR(ENOMEM);
+ goto fail;
+ }
+
+ if (!((*wctx)->priv = av_mallocz(writer->priv_size))) {
+ ret = AVERROR(ENOMEM);
+ goto fail;
+ }
+
+ (*wctx)->class = &writer_class;
+ (*wctx)->writer = writer;
+ (*wctx)->level = -1;
+ (*wctx)->sections = sections;
+ (*wctx)->nb_sections = nb_sections;
+
+ av_opt_set_defaults(*wctx);
+
+ if (writer->priv_class) {
+ void *priv_ctx = (*wctx)->priv;
+ *((const AVClass **)priv_ctx) = writer->priv_class;
+ av_opt_set_defaults(priv_ctx);
+ }
+
+ /* convert options to dictionary */
+ if (args) {
+ AVDictionary *opts = NULL;
+ const AVDictionaryEntry *opt = NULL;
+
+ if ((ret = av_dict_parse_string(&opts, args, "=", ":", 0)) < 0) {
+ av_log(*wctx, AV_LOG_ERROR, "Failed to parse option string '%s' provided to writer context\n", args);
+ av_dict_free(&opts);
+ goto fail;
+ }
+
+ while ((opt = av_dict_iterate(opts, opt))) {
+ if ((ret = av_opt_set(*wctx, opt->key, opt->value, AV_OPT_SEARCH_CHILDREN)) < 0) {
+ av_log(*wctx, AV_LOG_ERROR, "Failed to set option '%s' with value '%s' provided to writer context\n",
+ opt->key, opt->value);
+ av_dict_free(&opts);
+ goto fail;
+ }
+ }
+
+ av_dict_free(&opts);
+ }
+
+ /* validate replace string */
+ {
+ const uint8_t *p = (*wctx)->string_validation_replacement;
+ const uint8_t *endp = p + strlen(p);
+ while (*p) {
+ const uint8_t *p0 = p;
+ int32_t code;
+ ret = av_utf8_decode(&code, &p, endp, (*wctx)->string_validation_utf8_flags);
+ if (ret < 0) {
+ AVBPrint bp;
+ av_bprint_init(&bp, 0, AV_BPRINT_SIZE_AUTOMATIC);
+ bprint_bytes(&bp, p0, p-p0),
+ av_log(wctx, AV_LOG_ERROR,
+ "Invalid UTF8 sequence %s found in string validation replace '%s'\n",
+ bp.str, (*wctx)->string_validation_replacement);
+ return ret;
+ }
+ }
+ }
+
+ if (!output_filename) {
+ (*wctx)->writer_w8 = writer_w8_printf;
+ (*wctx)->writer_put_str = writer_put_str_printf;
+ (*wctx)->writer_printf = writer_printf_printf;
+ } else {
+ if ((ret = avio_open(&(*wctx)->avio, output, AVIO_FLAG_WRITE)) < 0) {
+ av_log(*wctx, AV_LOG_ERROR,
+ "Failed to open output '%s' with error: %s\n", output, av_err2str(ret));
+ goto fail;
+ }
+ (*wctx)->writer_w8 = writer_w8_avio;
+ (*wctx)->writer_put_str = writer_put_str_avio;
+ (*wctx)->writer_printf = writer_printf_avio;
+ }
+
+ for (i = 0; i < SECTION_MAX_NB_LEVELS; i++)
+ av_bprint_init(&(*wctx)->section_pbuf[i], 1, AV_BPRINT_SIZE_UNLIMITED);
+
+ if ((*wctx)->writer->init)
+ ret = (*wctx)->writer->init(*wctx);
+ if (ret < 0)
+ goto fail;
+
+ return 0;
+
+fail:
+ writer_close(wctx);
+ return ret;
+}
+
+static inline void writer_print_section_header(WriterContext *wctx,
+ int section_id)
+{
+ int parent_section_id;
+ wctx->level++;
+ av_assert0(wctx->level < SECTION_MAX_NB_LEVELS);
+ parent_section_id = wctx->level ?
+ (wctx->section[wctx->level-1])->id : SECTION_ID_NONE;
+
+ wctx->nb_item[wctx->level] = 0;
+ wctx->section[wctx->level] = &wctx->sections[section_id];
+
+ if (section_id == SECTION_ID_PACKETS_AND_FRAMES) {
+ wctx->nb_section_packet = wctx->nb_section_frame =
+ wctx->nb_section_packet_frame = 0;
+ } else if (parent_section_id == SECTION_ID_PACKETS_AND_FRAMES) {
+ wctx->nb_section_packet_frame = section_id == SECTION_ID_PACKET ?
+ wctx->nb_section_packet : wctx->nb_section_frame;
+ }
+
+ if (wctx->writer->print_section_header)
+ wctx->writer->print_section_header(wctx);
+}
+
+static inline void writer_print_section_footer(WriterContext *wctx)
+{
+ int section_id = wctx->section[wctx->level]->id;
+ int parent_section_id = wctx->level ?
+ wctx->section[wctx->level-1]->id : SECTION_ID_NONE;
+
+ if (parent_section_id != SECTION_ID_NONE)
+ wctx->nb_item[wctx->level-1]++;
+ if (parent_section_id == SECTION_ID_PACKETS_AND_FRAMES) {
+ if (section_id == SECTION_ID_PACKET) wctx->nb_section_packet++;
+ else wctx->nb_section_frame++;
+ }
+ if (wctx->writer->print_section_footer)
+ wctx->writer->print_section_footer(wctx);
+ wctx->level--;
+}
+
+static inline void writer_print_integer(WriterContext *wctx,
+ const char *key, long long int val)
+{
+ const struct section *section = wctx->section[wctx->level];
+
+ if (section->show_all_entries || av_dict_get(section->entries_to_show, key, NULL, 0)) {
+ wctx->writer->print_integer(wctx, key, val);
+ wctx->nb_item[wctx->level]++;
+ }
+}
+
+static inline int validate_string(WriterContext *wctx, char **dstp, const char *src)
+{
+ const uint8_t *p, *endp;
+ AVBPrint dstbuf;
+ int invalid_chars_nb = 0, ret = 0;
+
+ av_bprint_init(&dstbuf, 0, AV_BPRINT_SIZE_UNLIMITED);
+
+ endp = src + strlen(src);
+ for (p = (uint8_t *)src; *p;) {
+ uint32_t code;
+ int invalid = 0;
+ const uint8_t *p0 = p;
+
+ if (av_utf8_decode(&code, &p, endp, wctx->string_validation_utf8_flags) < 0) {
+ AVBPrint bp;
+ av_bprint_init(&bp, 0, AV_BPRINT_SIZE_AUTOMATIC);
+ bprint_bytes(&bp, p0, p-p0);
+ av_log(wctx, AV_LOG_DEBUG,
+ "Invalid UTF-8 sequence %s found in string '%s'\n", bp.str, src);
+ invalid = 1;
+ }
+
+ if (invalid) {
+ invalid_chars_nb++;
+
+ switch (wctx->string_validation) {
+ case WRITER_STRING_VALIDATION_FAIL:
+ av_log(wctx, AV_LOG_ERROR,
+ "Invalid UTF-8 sequence found in string '%s'\n", src);
+ ret = AVERROR_INVALIDDATA;
+ goto end;
+ break;
+
+ case WRITER_STRING_VALIDATION_REPLACE:
+ av_bprintf(&dstbuf, "%s", wctx->string_validation_replacement);
+ break;
+ }
+ }
+
+ if (!invalid || wctx->string_validation == WRITER_STRING_VALIDATION_IGNORE)
+ av_bprint_append_data(&dstbuf, p0, p-p0);
+ }
+
+ if (invalid_chars_nb && wctx->string_validation == WRITER_STRING_VALIDATION_REPLACE) {
+ av_log(wctx, AV_LOG_WARNING,
+ "%d invalid UTF-8 sequence(s) found in string '%s', replaced with '%s'\n",
+ invalid_chars_nb, src, wctx->string_validation_replacement);
+ }
+
+end:
+ av_bprint_finalize(&dstbuf, dstp);
+ return ret;
+}
+
+#define PRINT_STRING_OPT 1
+#define PRINT_STRING_VALIDATE 2
+
+static inline int writer_print_string(WriterContext *wctx,
+ const char *key, const char *val, int flags)
+{
+ const struct section *section = wctx->section[wctx->level];
+ int ret = 0;
+
+ if (show_optional_fields == SHOW_OPTIONAL_FIELDS_NEVER ||
+ (show_optional_fields == SHOW_OPTIONAL_FIELDS_AUTO
+ && (flags & PRINT_STRING_OPT)
+ && !(wctx->writer->flags & WRITER_FLAG_DISPLAY_OPTIONAL_FIELDS)))
+ return 0;
+
+ if (section->show_all_entries || av_dict_get(section->entries_to_show, key, NULL, 0)) {
+ if (flags & PRINT_STRING_VALIDATE) {
+ char *key1 = NULL, *val1 = NULL;
+ ret = validate_string(wctx, &key1, key);
+ if (ret < 0) goto end;
+ ret = validate_string(wctx, &val1, val);
+ if (ret < 0) goto end;
+ wctx->writer->print_string(wctx, key1, val1);
+ end:
+ if (ret < 0) {
+ av_log(wctx, AV_LOG_ERROR,
+ "Invalid key=value string combination %s=%s in section %s\n",
+ key, val, section->unique_name);
+ }
+ av_free(key1);
+ av_free(val1);
+ } else {
+ wctx->writer->print_string(wctx, key, val);
+ }
+
+ wctx->nb_item[wctx->level]++;
+ }
+
+ return ret;
+}
+
+static inline void writer_print_rational(WriterContext *wctx,
+ const char *key, AVRational q, char sep)
+{
+ AVBPrint buf;
+ av_bprint_init(&buf, 0, AV_BPRINT_SIZE_AUTOMATIC);
+ av_bprintf(&buf, "%d%c%d", q.num, sep, q.den);
+ writer_print_string(wctx, key, buf.str, 0);
+}
+
+static void writer_print_time(WriterContext *wctx, const char *key,
+ int64_t ts, const AVRational *time_base, int is_duration)
+{
+ char buf[128];
+
+ if ((!is_duration && ts == AV_NOPTS_VALUE) || (is_duration && ts == 0)) {
+ writer_print_string(wctx, key, "N/A", PRINT_STRING_OPT);
+ } else {
+ double d = ts * av_q2d(*time_base);
+ struct unit_value uv;
+ uv.val.d = d;
+ uv.unit = unit_second_str;
+ value_string(buf, sizeof(buf), uv);
+ writer_print_string(wctx, key, buf, 0);
+ }
+}
+
+static void writer_print_ts(WriterContext *wctx, const char *key, int64_t ts, int is_duration)
+{
+ if ((!is_duration && ts == AV_NOPTS_VALUE) || (is_duration && ts == 0)) {
+ writer_print_string(wctx, key, "N/A", PRINT_STRING_OPT);
+ } else {
+ writer_print_integer(wctx, key, ts);
+ }
+}
+
+static void writer_print_data(WriterContext *wctx, const char *name,
+ const uint8_t *data, int size)
+{
+ AVBPrint bp;
+ int offset = 0, l, i;
+
+ av_bprint_init(&bp, 0, AV_BPRINT_SIZE_UNLIMITED);
+ av_bprintf(&bp, "\n");
+ while (size) {
+ av_bprintf(&bp, "%08x: ", offset);
+ l = FFMIN(size, 16);
+ for (i = 0; i < l; i++) {
+ av_bprintf(&bp, "%02x", data[i]);
+ if (i & 1)
+ av_bprintf(&bp, " ");
+ }
+ av_bprint_chars(&bp, ' ', 41 - 2 * i - i / 2);
+ for (i = 0; i < l; i++)
+ av_bprint_chars(&bp, data[i] - 32U < 95 ? data[i] : '.', 1);
+ av_bprintf(&bp, "\n");
+ offset += l;
+ data += l;
+ size -= l;
+ }
+ writer_print_string(wctx, name, bp.str, 0);
+ av_bprint_finalize(&bp, NULL);
+}
+
+static void writer_print_data_hash(WriterContext *wctx, const char *name,
+ const uint8_t *data, int size)
+{
+ char *p, buf[AV_HASH_MAX_SIZE * 2 + 64] = { 0 };
+
+ if (!hash)
+ return;
+ av_hash_init(hash);
+ av_hash_update(hash, data, size);
+ snprintf(buf, sizeof(buf), "%s:", av_hash_get_name(hash));
+ p = buf + strlen(buf);
+ av_hash_final_hex(hash, p, buf + sizeof(buf) - p);
+ writer_print_string(wctx, name, buf, 0);
+}
+
+static void writer_print_integers(WriterContext *wctx, const char *name,
+ uint8_t *data, int size, const char *format,
+ int columns, int bytes, int offset_add)
+{
+ AVBPrint bp;
+ int offset = 0, l, i;
+
+ av_bprint_init(&bp, 0, AV_BPRINT_SIZE_UNLIMITED);
+ av_bprintf(&bp, "\n");
+ while (size) {
+ av_bprintf(&bp, "%08x: ", offset);
+ l = FFMIN(size, columns);
+ for (i = 0; i < l; i++) {
+ if (bytes == 1) av_bprintf(&bp, format, *data);
+ else if (bytes == 2) av_bprintf(&bp, format, AV_RN16(data));
+ else if (bytes == 4) av_bprintf(&bp, format, AV_RN32(data));
+ data += bytes;
+ size --;
+ }
+ av_bprintf(&bp, "\n");
+ offset += offset_add;
+ }
+ writer_print_string(wctx, name, bp.str, 0);
+ av_bprint_finalize(&bp, NULL);
+}
+
+#define writer_w8(wctx_, b_) (wctx_)->writer_w8(wctx_, b_)
+#define writer_put_str(wctx_, str_) (wctx_)->writer_put_str(wctx_, str_)
+#define writer_printf(wctx_, fmt_, ...) (wctx_)->writer_printf(wctx_, fmt_, __VA_ARGS__)
+
+#define MAX_REGISTERED_WRITERS_NB 64
+
+static const Writer *registered_writers[MAX_REGISTERED_WRITERS_NB + 1];
+
+static int writer_register(const Writer *writer)
+{
+ static int next_registered_writer_idx = 0;
+
+ if (next_registered_writer_idx == MAX_REGISTERED_WRITERS_NB)
+ return AVERROR(ENOMEM);
+
+ registered_writers[next_registered_writer_idx++] = writer;
+ return 0;
+}
+
+static const Writer *writer_get_by_name(const char *name)
+{
+ int i;
+
+ for (i = 0; registered_writers[i]; i++)
+ if (!strcmp(registered_writers[i]->name, name))
+ return registered_writers[i];
+
+ return NULL;
+}
+
+
+/* WRITERS */
+
+#define DEFINE_WRITER_CLASS(name) \
+static const char *name##_get_name(void *ctx) \
+{ \
+ return #name ; \
+} \
+static const AVClass name##_class = { \
+ .class_name = #name, \
+ .item_name = name##_get_name, \
+ .option = name##_options \
+}
+
+/* Default output */
+
+typedef struct DefaultContext {
+ const AVClass *class;
+ int nokey;
+ int noprint_wrappers;
+ int nested_section[SECTION_MAX_NB_LEVELS];
+} DefaultContext;
+
+#undef OFFSET
+#define OFFSET(x) offsetof(DefaultContext, x)
+
+static const AVOption default_options[] = {
+ { "noprint_wrappers", "do not print headers and footers", OFFSET(noprint_wrappers), AV_OPT_TYPE_BOOL, {.i64=0}, 0, 1 },
+ { "nw", "do not print headers and footers", OFFSET(noprint_wrappers), AV_OPT_TYPE_BOOL, {.i64=0}, 0, 1 },
+ { "nokey", "force no key printing", OFFSET(nokey), AV_OPT_TYPE_BOOL, {.i64=0}, 0, 1 },
+ { "nk", "force no key printing", OFFSET(nokey), AV_OPT_TYPE_BOOL, {.i64=0}, 0, 1 },
+ {NULL},
+};
+
+DEFINE_WRITER_CLASS(default);
+
+/* lame uppercasing routine, assumes the string is lower case ASCII */
+static inline char *upcase_string(char *dst, size_t dst_size, const char *src)
+{
+ int i;
+ for (i = 0; src[i] && i < dst_size-1; i++)
+ dst[i] = av_toupper(src[i]);
+ dst[i] = 0;
+ return dst;
+}
+
+static void default_print_section_header(WriterContext *wctx)
+{
+ DefaultContext *def = wctx->priv;
+ char buf[32];
+ const struct section *section = wctx->section[wctx->level];
+ const struct section *parent_section = wctx->level ?
+ wctx->section[wctx->level-1] : NULL;
+
+ av_bprint_clear(&wctx->section_pbuf[wctx->level]);
+ if (parent_section &&
+ !(parent_section->flags & (SECTION_FLAG_IS_WRAPPER|SECTION_FLAG_IS_ARRAY))) {
+ def->nested_section[wctx->level] = 1;
+ av_bprintf(&wctx->section_pbuf[wctx->level], "%s%s:",
+ wctx->section_pbuf[wctx->level-1].str,
+ upcase_string(buf, sizeof(buf),
+ av_x_if_null(section->element_name, section->name)));
+ }
+
+ if (def->noprint_wrappers || def->nested_section[wctx->level])
+ return;
+
+ if (!(section->flags & (SECTION_FLAG_IS_WRAPPER|SECTION_FLAG_IS_ARRAY)))
+ writer_printf(wctx, "[%s]\n", upcase_string(buf, sizeof(buf), section->name));
+}
+
+static void default_print_section_footer(WriterContext *wctx)
+{
+ DefaultContext *def = wctx->priv;
+ const struct section *section = wctx->section[wctx->level];
+ char buf[32];
+
+ if (def->noprint_wrappers || def->nested_section[wctx->level])
+ return;
+
+ if (!(section->flags & (SECTION_FLAG_IS_WRAPPER|SECTION_FLAG_IS_ARRAY)))
+ writer_printf(wctx, "[/%s]\n", upcase_string(buf, sizeof(buf), section->name));
+}
+
+static void default_print_str(WriterContext *wctx, const char *key, const char *value)
+{
+ DefaultContext *def = wctx->priv;
+
+ if (!def->nokey)
+ writer_printf(wctx, "%s%s=", wctx->section_pbuf[wctx->level].str, key);
+ writer_printf(wctx, "%s\n", value);
+}
+
+static void default_print_int(WriterContext *wctx, const char *key, long long int value)
+{
+ DefaultContext *def = wctx->priv;
+
+ if (!def->nokey)
+ writer_printf(wctx, "%s%s=", wctx->section_pbuf[wctx->level].str, key);
+ writer_printf(wctx, "%lld\n", value);
+}
+
+static const Writer default_writer = {
+ .name = "default",
+ .priv_size = sizeof(DefaultContext),
+ .print_section_header = default_print_section_header,
+ .print_section_footer = default_print_section_footer,
+ .print_integer = default_print_int,
+ .print_string = default_print_str,
+ .flags = WRITER_FLAG_DISPLAY_OPTIONAL_FIELDS,
+ .priv_class = &default_class,
+};
+
+/* Compact output */
+
+/**
+ * Apply C-language-like string escaping.
+ */
+static const char *c_escape_str(AVBPrint *dst, const char *src, const char sep, void *log_ctx)
+{
+ const char *p;
+
+ for (p = src; *p; p++) {
+ switch (*p) {
+ case '\b': av_bprintf(dst, "%s", "\\b"); break;
+ case '\f': av_bprintf(dst, "%s", "\\f"); break;
+ case '\n': av_bprintf(dst, "%s", "\\n"); break;
+ case '\r': av_bprintf(dst, "%s", "\\r"); break;
+ case '\\': av_bprintf(dst, "%s", "\\\\"); break;
+ default:
+ if (*p == sep)
+ av_bprint_chars(dst, '\\', 1);
+ av_bprint_chars(dst, *p, 1);
+ }
+ }
+ return dst->str;
+}
+
+/**
+ * Quote fields containing special characters, check RFC4180.
+ */
+static const char *csv_escape_str(AVBPrint *dst, const char *src, const char sep, void *log_ctx)
+{
+ char meta_chars[] = { sep, '"', '\n', '\r', '\0' };
+ int needs_quoting = !!src[strcspn(src, meta_chars)];
+
+ if (needs_quoting)
+ av_bprint_chars(dst, '"', 1);
+
+ for (; *src; src++) {
+ if (*src == '"')
+ av_bprint_chars(dst, '"', 1);
+ av_bprint_chars(dst, *src, 1);
+ }
+ if (needs_quoting)
+ av_bprint_chars(dst, '"', 1);
+ return dst->str;
+}
+
+static const char *none_escape_str(AVBPrint *dst, const char *src, const char sep, void *log_ctx)
+{
+ return src;
+}
+
+typedef struct CompactContext {
+ const AVClass *class;
+ char *item_sep_str;
+ char item_sep;
+ int nokey;
+ int print_section;
+ char *escape_mode_str;
+ const char * (*escape_str)(AVBPrint *dst, const char *src, const char sep, void *log_ctx);
+ int nested_section[SECTION_MAX_NB_LEVELS];
+ int has_nested_elems[SECTION_MAX_NB_LEVELS];
+ int terminate_line[SECTION_MAX_NB_LEVELS];
+} CompactContext;
+
+#undef OFFSET
+#define OFFSET(x) offsetof(CompactContext, x)
+
+static const AVOption compact_options[]= {
+ {"item_sep", "set item separator", OFFSET(item_sep_str), AV_OPT_TYPE_STRING, {.str="|"}, 0, 0 },
+ {"s", "set item separator", OFFSET(item_sep_str), AV_OPT_TYPE_STRING, {.str="|"}, 0, 0 },
+ {"nokey", "force no key printing", OFFSET(nokey), AV_OPT_TYPE_BOOL, {.i64=0}, 0, 1 },
+ {"nk", "force no key printing", OFFSET(nokey), AV_OPT_TYPE_BOOL, {.i64=0}, 0, 1 },
+ {"escape", "set escape mode", OFFSET(escape_mode_str), AV_OPT_TYPE_STRING, {.str="c"}, 0, 0 },
+ {"e", "set escape mode", OFFSET(escape_mode_str), AV_OPT_TYPE_STRING, {.str="c"}, 0, 0 },
+ {"print_section", "print section name", OFFSET(print_section), AV_OPT_TYPE_BOOL, {.i64=1}, 0, 1 },
+ {"p", "print section name", OFFSET(print_section), AV_OPT_TYPE_BOOL, {.i64=1}, 0, 1 },
+ {NULL},
+};
+
+DEFINE_WRITER_CLASS(compact);
+
+static av_cold int compact_init(WriterContext *wctx)
+{
+ CompactContext *compact = wctx->priv;
+
+ if (strlen(compact->item_sep_str) != 1) {
+ av_log(wctx, AV_LOG_ERROR, "Item separator '%s' specified, but must contain a single character\n",
+ compact->item_sep_str);
+ return AVERROR(EINVAL);
+ }
+ compact->item_sep = compact->item_sep_str[0];
+
+ if (!strcmp(compact->escape_mode_str, "none")) compact->escape_str = none_escape_str;
+ else if (!strcmp(compact->escape_mode_str, "c" )) compact->escape_str = c_escape_str;
+ else if (!strcmp(compact->escape_mode_str, "csv" )) compact->escape_str = csv_escape_str;
+ else {
+ av_log(wctx, AV_LOG_ERROR, "Unknown escape mode '%s'\n", compact->escape_mode_str);
+ return AVERROR(EINVAL);
+ }
+
+ return 0;
+}
+
+static void compact_print_section_header(WriterContext *wctx)
+{
+ CompactContext *compact = wctx->priv;
+ const struct section *section = wctx->section[wctx->level];
+ const struct section *parent_section = wctx->level ?
+ wctx->section[wctx->level-1] : NULL;
+ compact->terminate_line[wctx->level] = 1;
+ compact->has_nested_elems[wctx->level] = 0;
+
+ av_bprint_clear(&wctx->section_pbuf[wctx->level]);
+ if (!(section->flags & SECTION_FLAG_IS_ARRAY) && parent_section &&
+ !(parent_section->flags & (SECTION_FLAG_IS_WRAPPER|SECTION_FLAG_IS_ARRAY))) {
+ compact->nested_section[wctx->level] = 1;
+ compact->has_nested_elems[wctx->level-1] = 1;
+ av_bprintf(&wctx->section_pbuf[wctx->level], "%s%s:",
+ wctx->section_pbuf[wctx->level-1].str,
+ (char *)av_x_if_null(section->element_name, section->name));
+ wctx->nb_item[wctx->level] = wctx->nb_item[wctx->level-1];
+ } else {
+ if (parent_section && compact->has_nested_elems[wctx->level-1] &&
+ (section->flags & SECTION_FLAG_IS_ARRAY)) {
+ compact->terminate_line[wctx->level-1] = 0;
+ }
+ if (parent_section && !(parent_section->flags & (SECTION_FLAG_IS_WRAPPER|SECTION_FLAG_IS_ARRAY)) &&
+ wctx->level && wctx->nb_item[wctx->level-1])
+ writer_w8(wctx, compact->item_sep);
+ if (compact->print_section &&
+ !(section->flags & (SECTION_FLAG_IS_WRAPPER|SECTION_FLAG_IS_ARRAY)))
+ writer_printf(wctx, "%s%c", section->name, compact->item_sep);
+ }
+}
+
+static void compact_print_section_footer(WriterContext *wctx)
+{
+ CompactContext *compact = wctx->priv;
+
+ if (!compact->nested_section[wctx->level] &&
+ compact->terminate_line[wctx->level] &&
+ !(wctx->section[wctx->level]->flags & (SECTION_FLAG_IS_WRAPPER|SECTION_FLAG_IS_ARRAY)))
+ writer_w8(wctx, '\n');
+}
+
+static void compact_print_str(WriterContext *wctx, const char *key, const char *value)
+{
+ CompactContext *compact = wctx->priv;
+ AVBPrint buf;
+
+ if (wctx->nb_item[wctx->level]) writer_w8(wctx, compact->item_sep);
+ if (!compact->nokey)
+ writer_printf(wctx, "%s%s=", wctx->section_pbuf[wctx->level].str, key);
+ av_bprint_init(&buf, 1, AV_BPRINT_SIZE_UNLIMITED);
+ writer_put_str(wctx, compact->escape_str(&buf, value, compact->item_sep, wctx));
+ av_bprint_finalize(&buf, NULL);
+}
+
+static void compact_print_int(WriterContext *wctx, const char *key, long long int value)
+{
+ CompactContext *compact = wctx->priv;
+
+ if (wctx->nb_item[wctx->level]) writer_w8(wctx, compact->item_sep);
+ if (!compact->nokey)
+ writer_printf(wctx, "%s%s=", wctx->section_pbuf[wctx->level].str, key);
+ writer_printf(wctx, "%lld", value);
+}
+
+static const Writer compact_writer = {
+ .name = "compact",
+ .priv_size = sizeof(CompactContext),
+ .init = compact_init,
+ .print_section_header = compact_print_section_header,
+ .print_section_footer = compact_print_section_footer,
+ .print_integer = compact_print_int,
+ .print_string = compact_print_str,
+ .flags = WRITER_FLAG_DISPLAY_OPTIONAL_FIELDS,
+ .priv_class = &compact_class,
+};
+
+/* CSV output */
+
+#undef OFFSET
+#define OFFSET(x) offsetof(CompactContext, x)
+
+static const AVOption csv_options[] = {
+ {"item_sep", "set item separator", OFFSET(item_sep_str), AV_OPT_TYPE_STRING, {.str=","}, 0, 0 },
+ {"s", "set item separator", OFFSET(item_sep_str), AV_OPT_TYPE_STRING, {.str=","}, 0, 0 },
+ {"nokey", "force no key printing", OFFSET(nokey), AV_OPT_TYPE_BOOL, {.i64=1}, 0, 1 },
+ {"nk", "force no key printing", OFFSET(nokey), AV_OPT_TYPE_BOOL, {.i64=1}, 0, 1 },
+ {"escape", "set escape mode", OFFSET(escape_mode_str), AV_OPT_TYPE_STRING, {.str="csv"}, 0, 0 },
+ {"e", "set escape mode", OFFSET(escape_mode_str), AV_OPT_TYPE_STRING, {.str="csv"}, 0, 0 },
+ {"print_section", "print section name", OFFSET(print_section), AV_OPT_TYPE_BOOL, {.i64=1}, 0, 1 },
+ {"p", "print section name", OFFSET(print_section), AV_OPT_TYPE_BOOL, {.i64=1}, 0, 1 },
+ {NULL},
+};
+
+DEFINE_WRITER_CLASS(csv);
+
+static const Writer csv_writer = {
+ .name = "csv",
+ .priv_size = sizeof(CompactContext),
+ .init = compact_init,
+ .print_section_header = compact_print_section_header,
+ .print_section_footer = compact_print_section_footer,
+ .print_integer = compact_print_int,
+ .print_string = compact_print_str,
+ .flags = WRITER_FLAG_DISPLAY_OPTIONAL_FIELDS,
+ .priv_class = &csv_class,
+};
+
+/* Flat output */
+
+typedef struct FlatContext {
+ const AVClass *class;
+ const char *sep_str;
+ char sep;
+ int hierarchical;
+} FlatContext;
+
+#undef OFFSET
+#define OFFSET(x) offsetof(FlatContext, x)
+
+static const AVOption flat_options[]= {
+ {"sep_char", "set separator", OFFSET(sep_str), AV_OPT_TYPE_STRING, {.str="."}, 0, 0 },
+ {"s", "set separator", OFFSET(sep_str), AV_OPT_TYPE_STRING, {.str="."}, 0, 0 },
+ {"hierarchical", "specify if the section specification should be hierarchical", OFFSET(hierarchical), AV_OPT_TYPE_BOOL, {.i64=1}, 0, 1 },
+ {"h", "specify if the section specification should be hierarchical", OFFSET(hierarchical), AV_OPT_TYPE_BOOL, {.i64=1}, 0, 1 },
+ {NULL},
+};
+
+DEFINE_WRITER_CLASS(flat);
+
+static av_cold int flat_init(WriterContext *wctx)
+{
+ FlatContext *flat = wctx->priv;
+
+ if (strlen(flat->sep_str) != 1) {
+ av_log(wctx, AV_LOG_ERROR, "Item separator '%s' specified, but must contain a single character\n",
+ flat->sep_str);
+ return AVERROR(EINVAL);
+ }
+ flat->sep = flat->sep_str[0];
+
+ return 0;
+}
+
+static const char *flat_escape_key_str(AVBPrint *dst, const char *src, const char sep)
+{
+ const char *p;
+
+ for (p = src; *p; p++) {
+ if (!((*p >= '0' && *p <= '9') ||
+ (*p >= 'a' && *p <= 'z') ||
+ (*p >= 'A' && *p <= 'Z')))
+ av_bprint_chars(dst, '_', 1);
+ else
+ av_bprint_chars(dst, *p, 1);
+ }
+ return dst->str;
+}
+
+static const char *flat_escape_value_str(AVBPrint *dst, const char *src)
+{
+ const char *p;
+
+ for (p = src; *p; p++) {
+ switch (*p) {
+ case '\n': av_bprintf(dst, "%s", "\\n"); break;
+ case '\r': av_bprintf(dst, "%s", "\\r"); break;
+ case '\\': av_bprintf(dst, "%s", "\\\\"); break;
+ case '"': av_bprintf(dst, "%s", "\\\""); break;
+ case '`': av_bprintf(dst, "%s", "\\`"); break;
+ case '$': av_bprintf(dst, "%s", "\\$"); break;
+ default: av_bprint_chars(dst, *p, 1); break;
+ }
+ }
+ return dst->str;
+}
+
+static void flat_print_section_header(WriterContext *wctx)
+{
+ FlatContext *flat = wctx->priv;
+ AVBPrint *buf = &wctx->section_pbuf[wctx->level];
+ const struct section *section = wctx->section[wctx->level];
+ const struct section *parent_section = wctx->level ?
+ wctx->section[wctx->level-1] : NULL;
+
+ /* build section header */
+ av_bprint_clear(buf);
+ if (!parent_section)
+ return;
+ av_bprintf(buf, "%s", wctx->section_pbuf[wctx->level-1].str);
+
+ if (flat->hierarchical ||
+ !(section->flags & (SECTION_FLAG_IS_ARRAY|SECTION_FLAG_IS_WRAPPER))) {
+ av_bprintf(buf, "%s%s", wctx->section[wctx->level]->name, flat->sep_str);
+
+ if (parent_section->flags & SECTION_FLAG_IS_ARRAY) {
+ int n = parent_section->id == SECTION_ID_PACKETS_AND_FRAMES ?
+ wctx->nb_section_packet_frame : wctx->nb_item[wctx->level-1];
+ av_bprintf(buf, "%d%s", n, flat->sep_str);
+ }
+ }
+}
+
+static void flat_print_int(WriterContext *wctx, const char *key, long long int value)
+{
+ writer_printf(wctx, "%s%s=%lld\n", wctx->section_pbuf[wctx->level].str, key, value);
+}
+
+static void flat_print_str(WriterContext *wctx, const char *key, const char *value)
+{
+ FlatContext *flat = wctx->priv;
+ AVBPrint buf;
+
+ writer_put_str(wctx, wctx->section_pbuf[wctx->level].str);
+ av_bprint_init(&buf, 1, AV_BPRINT_SIZE_UNLIMITED);
+ writer_printf(wctx, "%s=", flat_escape_key_str(&buf, key, flat->sep));
+ av_bprint_clear(&buf);
+ writer_printf(wctx, "\"%s\"\n", flat_escape_value_str(&buf, value));
+ av_bprint_finalize(&buf, NULL);
+}
+
+static const Writer flat_writer = {
+ .name = "flat",
+ .priv_size = sizeof(FlatContext),
+ .init = flat_init,
+ .print_section_header = flat_print_section_header,
+ .print_integer = flat_print_int,
+ .print_string = flat_print_str,
+ .flags = WRITER_FLAG_DISPLAY_OPTIONAL_FIELDS|WRITER_FLAG_PUT_PACKETS_AND_FRAMES_IN_SAME_CHAPTER,
+ .priv_class = &flat_class,
+};
+
+/* INI format output */
+
+typedef struct INIContext {
+ const AVClass *class;
+ int hierarchical;
+} INIContext;
+
+#undef OFFSET
+#define OFFSET(x) offsetof(INIContext, x)
+
+static const AVOption ini_options[] = {
+ {"hierarchical", "specify if the section specification should be hierarchical", OFFSET(hierarchical), AV_OPT_TYPE_BOOL, {.i64=1}, 0, 1 },
+ {"h", "specify if the section specification should be hierarchical", OFFSET(hierarchical), AV_OPT_TYPE_BOOL, {.i64=1}, 0, 1 },
+ {NULL},
+};
+
+DEFINE_WRITER_CLASS(ini);
+
+static char *ini_escape_str(AVBPrint *dst, const char *src)
+{
+ int i = 0;
+ char c = 0;
+
+ while (c = src[i++]) {
+ switch (c) {
+ case '\b': av_bprintf(dst, "%s", "\\b"); break;
+ case '\f': av_bprintf(dst, "%s", "\\f"); break;
+ case '\n': av_bprintf(dst, "%s", "\\n"); break;
+ case '\r': av_bprintf(dst, "%s", "\\r"); break;
+ case '\t': av_bprintf(dst, "%s", "\\t"); break;
+ case '\\':
+ case '#' :
+ case '=' :
+ case ':' : av_bprint_chars(dst, '\\', 1);
+ default:
+ if ((unsigned char)c < 32)
+ av_bprintf(dst, "\\x00%02x", c & 0xff);
+ else
+ av_bprint_chars(dst, c, 1);
+ break;
+ }
+ }
+ return dst->str;
+}
+
+static void ini_print_section_header(WriterContext *wctx)
+{
+ INIContext *ini = wctx->priv;
+ AVBPrint *buf = &wctx->section_pbuf[wctx->level];
+ const struct section *section = wctx->section[wctx->level];
+ const struct section *parent_section = wctx->level ?
+ wctx->section[wctx->level-1] : NULL;
+
+ av_bprint_clear(buf);
+ if (!parent_section) {
+ writer_put_str(wctx, "# ffprobe output\n\n");
+ return;
+ }
+
+ if (wctx->nb_item[wctx->level-1])
+ writer_w8(wctx, '\n');
+
+ av_bprintf(buf, "%s", wctx->section_pbuf[wctx->level-1].str);
+ if (ini->hierarchical ||
+ !(section->flags & (SECTION_FLAG_IS_ARRAY|SECTION_FLAG_IS_WRAPPER))) {
+ av_bprintf(buf, "%s%s", buf->str[0] ? "." : "", wctx->section[wctx->level]->name);
+
+ if (parent_section->flags & SECTION_FLAG_IS_ARRAY) {
+ int n = parent_section->id == SECTION_ID_PACKETS_AND_FRAMES ?
+ wctx->nb_section_packet_frame : wctx->nb_item[wctx->level-1];
+ av_bprintf(buf, ".%d", n);
+ }
+ }
+
+ if (!(section->flags & (SECTION_FLAG_IS_ARRAY|SECTION_FLAG_IS_WRAPPER)))
+ writer_printf(wctx, "[%s]\n", buf->str);
+}
+
+static void ini_print_str(WriterContext *wctx, const char *key, const char *value)
+{
+ AVBPrint buf;
+
+ av_bprint_init(&buf, 1, AV_BPRINT_SIZE_UNLIMITED);
+ writer_printf(wctx, "%s=", ini_escape_str(&buf, key));
+ av_bprint_clear(&buf);
+ writer_printf(wctx, "%s\n", ini_escape_str(&buf, value));
+ av_bprint_finalize(&buf, NULL);
+}
+
+static void ini_print_int(WriterContext *wctx, const char *key, long long int value)
+{
+ writer_printf(wctx, "%s=%lld\n", key, value);
+}
+
+static const Writer ini_writer = {
+ .name = "ini",
+ .priv_size = sizeof(INIContext),
+ .print_section_header = ini_print_section_header,
+ .print_integer = ini_print_int,
+ .print_string = ini_print_str,
+ .flags = WRITER_FLAG_DISPLAY_OPTIONAL_FIELDS|WRITER_FLAG_PUT_PACKETS_AND_FRAMES_IN_SAME_CHAPTER,
+ .priv_class = &ini_class,
+};
+
+/* JSON output */
+
+typedef struct JSONContext {
+ const AVClass *class;
+ int indent_level;
+ int compact;
+ const char *item_sep, *item_start_end;
+} JSONContext;
+
+#undef OFFSET
+#define OFFSET(x) offsetof(JSONContext, x)
+
+static const AVOption json_options[]= {
+ { "compact", "enable compact output", OFFSET(compact), AV_OPT_TYPE_BOOL, {.i64=0}, 0, 1 },
+ { "c", "enable compact output", OFFSET(compact), AV_OPT_TYPE_BOOL, {.i64=0}, 0, 1 },
+ { NULL }
+};
+
+DEFINE_WRITER_CLASS(json);
+
+static av_cold int json_init(WriterContext *wctx)
+{
+ JSONContext *json = wctx->priv;
+
+ json->item_sep = json->compact ? ", " : ",\n";
+ json->item_start_end = json->compact ? " " : "\n";
+
+ return 0;
+}
+
+static const char *json_escape_str(AVBPrint *dst, const char *src, void *log_ctx)
+{
+ static const char json_escape[] = {'"', '\\', '\b', '\f', '\n', '\r', '\t', 0};
+ static const char json_subst[] = {'"', '\\', 'b', 'f', 'n', 'r', 't', 0};
+ const char *p;
+
+ for (p = src; *p; p++) {
+ char *s = strchr(json_escape, *p);
+ if (s) {
+ av_bprint_chars(dst, '\\', 1);
+ av_bprint_chars(dst, json_subst[s - json_escape], 1);
+ } else if ((unsigned char)*p < 32) {
+ av_bprintf(dst, "\\u00%02x", *p & 0xff);
+ } else {
+ av_bprint_chars(dst, *p, 1);
+ }
+ }
+ return dst->str;
+}
+
+#define JSON_INDENT() frank_printf_json("%*c", json->indent_level * 4, ' ')
+
+static void json_print_section_header(WriterContext *wctx)
+{
+ JSONContext *json = wctx->priv;
+ AVBPrint buf;
+ const struct section *section = wctx->section[wctx->level];
+ const struct section *parent_section = wctx->level ?
+ wctx->section[wctx->level-1] : NULL;
+
+ if (wctx->level && wctx->nb_item[wctx->level-1])
+ frank_printf_json(",\n");
+
+ if (section->flags & SECTION_FLAG_IS_WRAPPER) {
+ frank_printf_json("{\n");
+ json->indent_level++;
+ } else {
+ av_bprint_init(&buf, 1, AV_BPRINT_SIZE_UNLIMITED);
+ json_escape_str(&buf, section->name, wctx);
+ JSON_INDENT();
+
+ json->indent_level++;
+ if (section->flags & SECTION_FLAG_IS_ARRAY) {
+ frank_printf_json("\"%s\": [\n", buf.str);
+ } else if (parent_section && !(parent_section->flags & SECTION_FLAG_IS_ARRAY)) {
+ frank_printf_json("\"%s\": {%s", buf.str, json->item_start_end);
+ } else {
+ frank_printf_json("{%s", json->item_start_end);
+
+ /* this is required so the parser can distinguish between packets and frames */
+ if (parent_section && parent_section->id == SECTION_ID_PACKETS_AND_FRAMES) {
+ if (!json->compact)
+ JSON_INDENT();
+ frank_printf_json("\"type\": \"%s\"", section->name);
+ wctx->nb_item[wctx->level]++;
+ }
+ }
+ av_bprint_finalize(&buf, NULL);
+ }
+}
+
+static void json_print_section_footer(WriterContext *wctx)
+{
+ JSONContext *json = wctx->priv;
+ const struct section *section = wctx->section[wctx->level];
+
+ if (wctx->level == 0) {
+ json->indent_level--;
+ frank_printf_json("\n}\n");
+ } else if (section->flags & SECTION_FLAG_IS_ARRAY) {
+ frank_printf_json("\n");
+ json->indent_level--;
+ JSON_INDENT();
+ frank_printf_json( "]");
+ } else {
+ frank_printf_json("%s",json->item_start_end);
+ json->indent_level--;
+ if (!json->compact)
+ JSON_INDENT();
+ frank_printf_json("}");
+ }
+}
+
+static inline void json_print_item_str(WriterContext *wctx,
+ const char *key, const char *value)
+{
+ AVBPrint buf;
+
+ av_bprint_init(&buf, 1, AV_BPRINT_SIZE_UNLIMITED);
+ frank_printf_json("\"%s\":", json_escape_str(&buf, key, wctx));
+ av_bprint_clear(&buf);
+ frank_printf_json(" \"%s\"", json_escape_str(&buf, value, wctx));
+ av_bprint_finalize(&buf, NULL);
+}
+
+static void json_print_str(WriterContext *wctx, const char *key, const char *value)
+{
+ JSONContext *json = wctx->priv;
+ const struct section *parent_section = wctx->level ?
+ wctx->section[wctx->level-1] : NULL;
+
+ if (wctx->nb_item[wctx->level] || (parent_section && parent_section->id == SECTION_ID_PACKETS_AND_FRAMES))
+ frank_printf_json(json->item_sep);
+ if (!json->compact)
+ JSON_INDENT();
+ json_print_item_str(wctx, key, value);
+}
+
+static void json_print_int(WriterContext *wctx, const char *key, long long int value)
+{
+ JSONContext *json = wctx->priv;
+ const struct section *parent_section = wctx->level ?
+ wctx->section[wctx->level-1] : NULL;
+ AVBPrint buf;
+
+ if (wctx->nb_item[wctx->level] || (parent_section && parent_section->id == SECTION_ID_PACKETS_AND_FRAMES))
+ frank_printf_json(json->item_sep);
+ if (!json->compact)
+ JSON_INDENT();
+
+ av_bprint_init(&buf, 1, AV_BPRINT_SIZE_UNLIMITED);
+ frank_printf_json("\"%s\": %lld", json_escape_str(&buf, key, wctx), value);
+ av_bprint_finalize(&buf, NULL);
+}
+
+static const Writer json_writer = {
+ .name = "json",
+ .priv_size = sizeof(JSONContext),
+ .init = json_init,
+ .print_section_header = json_print_section_header,
+ .print_section_footer = json_print_section_footer,
+ .print_integer = json_print_int,
+ .print_string = json_print_str,
+ .flags = WRITER_FLAG_PUT_PACKETS_AND_FRAMES_IN_SAME_CHAPTER,
+ .priv_class = &json_class,
+};
+
+/* XML output */
+
+typedef struct XMLContext {
+ const AVClass *class;
+ int within_tag;
+ int indent_level;
+ int fully_qualified;
+ int xsd_strict;
+} XMLContext;
+
+#undef OFFSET
+#define OFFSET(x) offsetof(XMLContext, x)
+
+static const AVOption xml_options[] = {
+ {"fully_qualified", "specify if the output should be fully qualified", OFFSET(fully_qualified), AV_OPT_TYPE_BOOL, {.i64=0}, 0, 1 },
+ {"q", "specify if the output should be fully qualified", OFFSET(fully_qualified), AV_OPT_TYPE_BOOL, {.i64=0}, 0, 1 },
+ {"xsd_strict", "ensure that the output is XSD compliant", OFFSET(xsd_strict), AV_OPT_TYPE_BOOL, {.i64=0}, 0, 1 },
+ {"x", "ensure that the output is XSD compliant", OFFSET(xsd_strict), AV_OPT_TYPE_BOOL, {.i64=0}, 0, 1 },
+ {NULL},
+};
+
+DEFINE_WRITER_CLASS(xml);
+
+static av_cold int xml_init(WriterContext *wctx)
+{
+ XMLContext *xml = wctx->priv;
+
+ if (xml->xsd_strict) {
+ xml->fully_qualified = 1;
+#define CHECK_COMPLIANCE(opt, opt_name) \
+ if (opt) { \
+ av_log(wctx, AV_LOG_ERROR, \
+ "XSD-compliant output selected but option '%s' was selected, XML output may be non-compliant.\n" \
+ "You need to disable such option with '-no%s'\n", opt_name, opt_name); \
+ return AVERROR(EINVAL); \
+ }
+ CHECK_COMPLIANCE(show_private_data, "private");
+ CHECK_COMPLIANCE(show_value_unit, "unit");
+ CHECK_COMPLIANCE(use_value_prefix, "prefix");
+ }
+
+ return 0;
+}
+
+#define XML_INDENT() writer_printf(wctx, "%*c", xml->indent_level * 4, ' ')
+
+static void xml_print_section_header(WriterContext *wctx)
+{
+ XMLContext *xml = wctx->priv;
+ const struct section *section = wctx->section[wctx->level];
+ const struct section *parent_section = wctx->level ?
+ wctx->section[wctx->level-1] : NULL;
+
+ if (wctx->level == 0) {
+ const char *qual = " xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" "
+ "xmlns:ffprobe=\"http://www.ffmpeg.org/schema/ffprobe\" "
+ "xsi:schemaLocation=\"http://www.ffmpeg.org/schema/ffprobe ffprobe.xsd\"";
+
+ writer_put_str(wctx, "\n");
+ writer_printf(wctx, "<%sffprobe%s>\n",
+ xml->fully_qualified ? "ffprobe:" : "",
+ xml->fully_qualified ? qual : "");
+ return;
+ }
+
+ if (xml->within_tag) {
+ xml->within_tag = 0;
+ writer_put_str(wctx, ">\n");
+ }
+ if (section->flags & SECTION_FLAG_HAS_VARIABLE_FIELDS) {
+ xml->indent_level++;
+ } else {
+ if (parent_section && (parent_section->flags & SECTION_FLAG_IS_WRAPPER) &&
+ wctx->level && wctx->nb_item[wctx->level-1])
+ writer_w8(wctx, '\n');
+ xml->indent_level++;
+
+ if (section->flags & SECTION_FLAG_IS_ARRAY) {
+ XML_INDENT(); writer_printf(wctx, "<%s>\n", section->name);
+ } else {
+ XML_INDENT(); writer_printf(wctx, "<%s ", section->name);
+ xml->within_tag = 1;
+ }
+ }
+}
+
+static void xml_print_section_footer(WriterContext *wctx)
+{
+ XMLContext *xml = wctx->priv;
+ const struct section *section = wctx->section[wctx->level];
+
+ if (wctx->level == 0) {
+ writer_printf(wctx, "%sffprobe>\n", xml->fully_qualified ? "ffprobe:" : "");
+ } else if (xml->within_tag) {
+ xml->within_tag = 0;
+ writer_put_str(wctx, "/>\n");
+ xml->indent_level--;
+ } else if (section->flags & SECTION_FLAG_HAS_VARIABLE_FIELDS) {
+ xml->indent_level--;
+ } else {
+ XML_INDENT(); writer_printf(wctx, "%s>\n", section->name);
+ xml->indent_level--;
+ }
+}
+
+static void xml_print_str(WriterContext *wctx, const char *key, const char *value)
+{
+ AVBPrint buf;
+ XMLContext *xml = wctx->priv;
+ const struct section *section = wctx->section[wctx->level];
+
+ av_bprint_init(&buf, 1, AV_BPRINT_SIZE_UNLIMITED);
+
+ if (section->flags & SECTION_FLAG_HAS_VARIABLE_FIELDS) {
+ XML_INDENT();
+ av_bprint_escape(&buf, key, NULL,
+ AV_ESCAPE_MODE_XML, AV_ESCAPE_FLAG_XML_DOUBLE_QUOTES);
+ writer_printf(wctx, "<%s key=\"%s\"",
+ section->element_name, buf.str);
+ av_bprint_clear(&buf);
+
+ av_bprint_escape(&buf, value, NULL,
+ AV_ESCAPE_MODE_XML, AV_ESCAPE_FLAG_XML_DOUBLE_QUOTES);
+ writer_printf(wctx, " value=\"%s\"/>\n", buf.str);
+ } else {
+ if (wctx->nb_item[wctx->level])
+ writer_w8(wctx, ' ');
+
+ av_bprint_escape(&buf, value, NULL,
+ AV_ESCAPE_MODE_XML, AV_ESCAPE_FLAG_XML_DOUBLE_QUOTES);
+ writer_printf(wctx, "%s=\"%s\"", key, buf.str);
+ }
+
+ av_bprint_finalize(&buf, NULL);
+}
+
+static void xml_print_int(WriterContext *wctx, const char *key, long long int value)
+{
+ if (wctx->nb_item[wctx->level])
+ writer_w8(wctx, ' ');
+ writer_printf(wctx, "%s=\"%lld\"", key, value);
+}
+
+static Writer xml_writer = {
+ .name = "xml",
+ .priv_size = sizeof(XMLContext),
+ .init = xml_init,
+ .print_section_header = xml_print_section_header,
+ .print_section_footer = xml_print_section_footer,
+ .print_integer = xml_print_int,
+ .print_string = xml_print_str,
+ .flags = WRITER_FLAG_PUT_PACKETS_AND_FRAMES_IN_SAME_CHAPTER,
+ .priv_class = &xml_class,
+};
+
+static void writer_register_all(void)
+{
+ static int initialized;
+
+ if (initialized)
+ return;
+ initialized = 1;
+
+ writer_register(&default_writer);
+ writer_register(&compact_writer);
+ writer_register(&csv_writer);
+ writer_register(&flat_writer);
+ writer_register(&ini_writer);
+ writer_register(&json_writer);
+ writer_register(&xml_writer);
+}
+
+#define print_fmt(k, f, ...) do { \
+ av_bprint_clear(&pbuf); \
+ av_bprintf(&pbuf, f, __VA_ARGS__); \
+ writer_print_string(w, k, pbuf.str, 0); \
+} while (0)
+
+#define print_list_fmt(k, f, n, m, ...) do { \
+ av_bprint_clear(&pbuf); \
+ for (int idx = 0; idx < n; idx++) { \
+ for (int idx2 = 0; idx2 < m; idx2++) { \
+ if (idx > 0 || idx2 > 0) \
+ av_bprint_chars(&pbuf, ' ', 1); \
+ av_bprintf(&pbuf, f, __VA_ARGS__); \
+ } \
+ } \
+ writer_print_string(w, k, pbuf.str, 0); \
+} while (0)
+
+#define print_int(k, v) writer_print_integer(w, k, v)
+#define print_q(k, v, s) writer_print_rational(w, k, v, s)
+#define print_str(k, v) writer_print_string(w, k, v, 0)
+#define print_str_opt(k, v) writer_print_string(w, k, v, PRINT_STRING_OPT)
+#define print_str_validate(k, v) writer_print_string(w, k, v, PRINT_STRING_VALIDATE)
+#define print_time(k, v, tb) writer_print_time(w, k, v, tb, 0)
+#define print_ts(k, v) writer_print_ts(w, k, v, 0)
+#define print_duration_time(k, v, tb) writer_print_time(w, k, v, tb, 1)
+#define print_duration_ts(k, v) writer_print_ts(w, k, v, 1)
+#define print_val(k, v, u) do { \
+ struct unit_value uv; \
+ uv.val.i = v; \
+ uv.unit = u; \
+ writer_print_string(w, k, value_string(val_str, sizeof(val_str), uv), 0); \
+} while (0)
+
+#define print_section_header(s) writer_print_section_header(w, s)
+#define print_section_footer(s) writer_print_section_footer(w, s)
+
+#define REALLOCZ_ARRAY_STREAM(ptr, cur_n, new_n) \
+{ \
+ ret = av_reallocp_array(&(ptr), (new_n), sizeof(*(ptr))); \
+ if (ret < 0) \
+ goto end; \
+ memset( (ptr) + (cur_n), 0, ((new_n) - (cur_n)) * sizeof(*(ptr)) ); \
+}
+
+static inline int show_tags(WriterContext *w, AVDictionary *tags, int section_id)
+{
+ const AVDictionaryEntry *tag = NULL;
+ int ret = 0;
+
+ if (!tags)
+ return 0;
+ writer_print_section_header(w, section_id);
+
+ while ((tag = av_dict_iterate(tags, tag))) {
+ if ((ret = print_str_validate(tag->key, tag->value)) < 0)
+ break;
+ }
+ writer_print_section_footer(w);
+
+ return ret;
+}
+
+static void print_dovi_metadata(WriterContext *w, const AVDOVIMetadata *dovi)
+{
+ if (!dovi)
+ return;
+
+ {
+ const AVDOVIRpuDataHeader *hdr = av_dovi_get_header(dovi);
+ const AVDOVIDataMapping *mapping = av_dovi_get_mapping(dovi);
+ const AVDOVIColorMetadata *color = av_dovi_get_color(dovi);
+ AVBPrint pbuf;
+
+ av_bprint_init(&pbuf, 1, AV_BPRINT_SIZE_UNLIMITED);
+
+ // header
+ print_int("rpu_type", hdr->rpu_type);
+ print_int("rpu_format", hdr->rpu_format);
+ print_int("vdr_rpu_profile", hdr->vdr_rpu_profile);
+ print_int("vdr_rpu_level", hdr->vdr_rpu_level);
+ print_int("chroma_resampling_explicit_filter_flag",
+ hdr->chroma_resampling_explicit_filter_flag);
+ print_int("coef_data_type", hdr->coef_data_type);
+ print_int("coef_log2_denom", hdr->coef_log2_denom);
+ print_int("vdr_rpu_normalized_idc", hdr->vdr_rpu_normalized_idc);
+ print_int("bl_video_full_range_flag", hdr->bl_video_full_range_flag);
+ print_int("bl_bit_depth", hdr->bl_bit_depth);
+ print_int("el_bit_depth", hdr->el_bit_depth);
+ print_int("vdr_bit_depth", hdr->vdr_bit_depth);
+ print_int("spatial_resampling_filter_flag",
+ hdr->spatial_resampling_filter_flag);
+ print_int("el_spatial_resampling_filter_flag",
+ hdr->el_spatial_resampling_filter_flag);
+ print_int("disable_residual_flag", hdr->disable_residual_flag);
+
+ // data mapping values
+ print_int("vdr_rpu_id", mapping->vdr_rpu_id);
+ print_int("mapping_color_space", mapping->mapping_color_space);
+ print_int("mapping_chroma_format_idc",
+ mapping->mapping_chroma_format_idc);
+
+ print_int("nlq_method_idc", mapping->nlq_method_idc);
+ switch (mapping->nlq_method_idc) {
+ case AV_DOVI_NLQ_NONE:
+ print_str("nlq_method_idc_name", "none");
+ break;
+ case AV_DOVI_NLQ_LINEAR_DZ:
+ print_str("nlq_method_idc_name", "linear_dz");
+ break;
+ default:
+ print_str("nlq_method_idc_name", "unknown");
+ break;
+ }
+
+ print_int("num_x_partitions", mapping->num_x_partitions);
+ print_int("num_y_partitions", mapping->num_y_partitions);
+
+ writer_print_section_header(w, SECTION_ID_FRAME_SIDE_DATA_COMPONENT_LIST);
+
+ for (int c = 0; c < 3; c++) {
+ const AVDOVIReshapingCurve *curve = &mapping->curves[c];
+ writer_print_section_header(w, SECTION_ID_FRAME_SIDE_DATA_COMPONENT);
+
+ print_list_fmt("pivots", "%"PRIu16, curve->num_pivots, 1, curve->pivots[idx]);
+
+ writer_print_section_header(w, SECTION_ID_FRAME_SIDE_DATA_PIECE_LIST);
+ for (int i = 0; i < curve->num_pivots - 1; i++) {
+
+ writer_print_section_header(w, SECTION_ID_FRAME_SIDE_DATA_PIECE);
+ print_int("mapping_idc", curve->mapping_idc[i]);
+ switch (curve->mapping_idc[i]) {
+ case AV_DOVI_MAPPING_POLYNOMIAL:
+ print_str("mapping_idc_name", "polynomial");
+ print_int("poly_order", curve->poly_order[i]);
+ print_list_fmt("poly_coef", "%"PRIi64,
+ curve->poly_order[i] + 1, 1,
+ curve->poly_coef[i][idx]);
+ break;
+ case AV_DOVI_MAPPING_MMR:
+ print_str("mapping_idc_name", "mmr");
+ print_int("mmr_order", curve->mmr_order[i]);
+ print_int("mmr_constant", curve->mmr_constant[i]);
+ print_list_fmt("mmr_coef", "%"PRIi64,
+ curve->mmr_order[i], 7,
+ curve->mmr_coef[i][idx][idx2]);
+ break;
+ default:
+ print_str("mapping_idc_name", "unknown");
+ break;
+ }
+
+ // SECTION_ID_FRAME_SIDE_DATA_PIECE
+ writer_print_section_footer(w);
+ }
+
+ // SECTION_ID_FRAME_SIDE_DATA_PIECE_LIST
+ writer_print_section_footer(w);
+
+ if (mapping->nlq_method_idc != AV_DOVI_NLQ_NONE) {
+ const AVDOVINLQParams *nlq = &mapping->nlq[c];
+ print_int("nlq_offset", nlq->nlq_offset);
+ print_int("vdr_in_max", nlq->vdr_in_max);
+
+ switch (mapping->nlq_method_idc) {
+ case AV_DOVI_NLQ_LINEAR_DZ:
+ print_int("linear_deadzone_slope", nlq->linear_deadzone_slope);
+ print_int("linear_deadzone_threshold", nlq->linear_deadzone_threshold);
+ break;
+ }
+ }
+
+ // SECTION_ID_FRAME_SIDE_DATA_COMPONENT
+ writer_print_section_footer(w);
+ }
+
+ // SECTION_ID_FRAME_SIDE_DATA_COMPONENT_LIST
+ writer_print_section_footer(w);
+
+ // color metadata
+ print_int("dm_metadata_id", color->dm_metadata_id);
+ print_int("scene_refresh_flag", color->scene_refresh_flag);
+ print_list_fmt("ycc_to_rgb_matrix", "%d/%d",
+ FF_ARRAY_ELEMS(color->ycc_to_rgb_matrix), 1,
+ color->ycc_to_rgb_matrix[idx].num,
+ color->ycc_to_rgb_matrix[idx].den);
+ print_list_fmt("ycc_to_rgb_offset", "%d/%d",
+ FF_ARRAY_ELEMS(color->ycc_to_rgb_offset), 1,
+ color->ycc_to_rgb_offset[idx].num,
+ color->ycc_to_rgb_offset[idx].den);
+ print_list_fmt("rgb_to_lms_matrix", "%d/%d",
+ FF_ARRAY_ELEMS(color->rgb_to_lms_matrix), 1,
+ color->rgb_to_lms_matrix[idx].num,
+ color->rgb_to_lms_matrix[idx].den);
+ print_int("signal_eotf", color->signal_eotf);
+ print_int("signal_eotf_param0", color->signal_eotf_param0);
+ print_int("signal_eotf_param1", color->signal_eotf_param1);
+ print_int("signal_eotf_param2", color->signal_eotf_param2);
+ print_int("signal_bit_depth", color->signal_bit_depth);
+ print_int("signal_color_space", color->signal_color_space);
+ print_int("signal_chroma_format", color->signal_chroma_format);
+ print_int("signal_full_range_flag", color->signal_full_range_flag);
+ print_int("source_min_pq", color->source_min_pq);
+ print_int("source_max_pq", color->source_max_pq);
+ print_int("source_diagonal", color->source_diagonal);
+
+ av_bprint_finalize(&pbuf, NULL);
+ }
+}
+
+static void print_dynamic_hdr10_plus(WriterContext *w, const AVDynamicHDRPlus *metadata)
+{
+ if (!metadata)
+ return;
+ print_int("application version", metadata->application_version);
+ print_int("num_windows", metadata->num_windows);
+ for (int n = 1; n < metadata->num_windows; n++) {
+ const AVHDRPlusColorTransformParams *params = &metadata->params[n];
+ print_q("window_upper_left_corner_x",
+ params->window_upper_left_corner_x,'/');
+ print_q("window_upper_left_corner_y",
+ params->window_upper_left_corner_y,'/');
+ print_q("window_lower_right_corner_x",
+ params->window_lower_right_corner_x,'/');
+ print_q("window_lower_right_corner_y",
+ params->window_lower_right_corner_y,'/');
+ print_q("window_upper_left_corner_x",
+ params->window_upper_left_corner_x,'/');
+ print_q("window_upper_left_corner_y",
+ params->window_upper_left_corner_y,'/');
+ print_int("center_of_ellipse_x",
+ params->center_of_ellipse_x ) ;
+ print_int("center_of_ellipse_y",
+ params->center_of_ellipse_y );
+ print_int("rotation_angle",
+ params->rotation_angle);
+ print_int("semimajor_axis_internal_ellipse",
+ params->semimajor_axis_internal_ellipse);
+ print_int("semimajor_axis_external_ellipse",
+ params->semimajor_axis_external_ellipse);
+ print_int("semiminor_axis_external_ellipse",
+ params->semiminor_axis_external_ellipse);
+ print_int("overlap_process_option",
+ params->overlap_process_option);
+ }
+ print_q("targeted_system_display_maximum_luminance",
+ metadata->targeted_system_display_maximum_luminance,'/');
+ if (metadata->targeted_system_display_actual_peak_luminance_flag) {
+ print_int("num_rows_targeted_system_display_actual_peak_luminance",
+ metadata->num_rows_targeted_system_display_actual_peak_luminance);
+ print_int("num_cols_targeted_system_display_actual_peak_luminance",
+ metadata->num_cols_targeted_system_display_actual_peak_luminance);
+ for (int i = 0; i < metadata->num_rows_targeted_system_display_actual_peak_luminance; i++) {
+ for (int j = 0; j < metadata->num_cols_targeted_system_display_actual_peak_luminance; j++) {
+ print_q("targeted_system_display_actual_peak_luminance",
+ metadata->targeted_system_display_actual_peak_luminance[i][j],'/');
+ }
+ }
+ }
+ for (int n = 0; n < metadata->num_windows; n++) {
+ const AVHDRPlusColorTransformParams *params = &metadata->params[n];
+ for (int i = 0; i < 3; i++) {
+ print_q("maxscl",params->maxscl[i],'/');
+ }
+ print_q("average_maxrgb",
+ params->average_maxrgb,'/');
+ print_int("num_distribution_maxrgb_percentiles",
+ params->num_distribution_maxrgb_percentiles);
+ for (int i = 0; i < params->num_distribution_maxrgb_percentiles; i++) {
+ print_int("distribution_maxrgb_percentage",
+ params->distribution_maxrgb[i].percentage);
+ print_q("distribution_maxrgb_percentile",
+ params->distribution_maxrgb[i].percentile,'/');
+ }
+ print_q("fraction_bright_pixels",
+ params->fraction_bright_pixels,'/');
+ }
+ if (metadata->mastering_display_actual_peak_luminance_flag) {
+ print_int("num_rows_mastering_display_actual_peak_luminance",
+ metadata->num_rows_mastering_display_actual_peak_luminance);
+ print_int("num_cols_mastering_display_actual_peak_luminance",
+ metadata->num_cols_mastering_display_actual_peak_luminance);
+ for (int i = 0; i < metadata->num_rows_mastering_display_actual_peak_luminance; i++) {
+ for (int j = 0; j < metadata->num_cols_mastering_display_actual_peak_luminance; j++) {
+ print_q("mastering_display_actual_peak_luminance",
+ metadata->mastering_display_actual_peak_luminance[i][j],'/');
+ }
+ }
+ }
+
+ for (int n = 0; n < metadata->num_windows; n++) {
+ const AVHDRPlusColorTransformParams *params = &metadata->params[n];
+ if (params->tone_mapping_flag) {
+ print_q("knee_point_x", params->knee_point_x,'/');
+ print_q("knee_point_y", params->knee_point_y,'/');
+ print_int("num_bezier_curve_anchors",
+ params->num_bezier_curve_anchors );
+ for (int i = 0; i < params->num_bezier_curve_anchors; i++) {
+ print_q("bezier_curve_anchors",
+ params->bezier_curve_anchors[i],'/');
+ }
+ }
+ if (params->color_saturation_mapping_flag) {
+ print_q("color_saturation_weight",
+ params->color_saturation_weight,'/');
+ }
+ }
+}
+
+static void print_dynamic_hdr_vivid(WriterContext *w, const AVDynamicHDRVivid *metadata)
+{
+ if (!metadata)
+ return;
+ print_int("system_start_code", metadata->system_start_code);
+ print_int("num_windows", metadata->num_windows);
+
+ for (int n = 0; n < metadata->num_windows; n++) {
+ const AVHDRVividColorTransformParams *params = &metadata->params[n];
+
+ print_q("minimum_maxrgb", params->minimum_maxrgb, '/');
+ print_q("average_maxrgb", params->average_maxrgb, '/');
+ print_q("variance_maxrgb", params->variance_maxrgb, '/');
+ print_q("maximum_maxrgb", params->maximum_maxrgb, '/');
+ }
+
+ for (int n = 0; n < metadata->num_windows; n++) {
+ const AVHDRVividColorTransformParams *params = &metadata->params[n];
+
+ print_int("tone_mapping_mode_flag", params->tone_mapping_mode_flag);
+ print_int("tone_mapping_param_num", params->tone_mapping_param_num);
+ if (params->tone_mapping_mode_flag) {
+ for (int i = 0; i < params->tone_mapping_param_num; i++) {
+ const AVHDRVividColorToneMappingParams *tm_params = ¶ms->tm_params[i];
+
+ print_q("targeted_system_display_maximum_luminance",
+ tm_params->targeted_system_display_maximum_luminance, '/');
+ print_int("base_enable_flag", tm_params->base_enable_flag);
+ if (tm_params->base_enable_flag) {
+ print_q("base_param_m_p", tm_params->base_param_m_p, '/');
+ print_q("base_param_m_m", tm_params->base_param_m_m, '/');
+ print_q("base_param_m_a", tm_params->base_param_m_a, '/');
+ print_q("base_param_m_b", tm_params->base_param_m_b, '/');
+ print_q("base_param_m_n", tm_params->base_param_m_n, '/');
+
+ print_int("base_param_k1", tm_params->base_param_k1);
+ print_int("base_param_k2", tm_params->base_param_k2);
+ print_int("base_param_k3", tm_params->base_param_k3);
+ print_int("base_param_Delta_enable_mode",
+ tm_params->base_param_Delta_enable_mode);
+ print_q("base_param_Delta", tm_params->base_param_Delta, '/');
+ }
+ print_int("3Spline_enable_flag", tm_params->three_Spline_enable_flag);
+ if (tm_params->three_Spline_enable_flag) {
+ print_int("3Spline_num", tm_params->three_Spline_num);
+ print_int("3Spline_TH_mode", tm_params->three_Spline_TH_mode);
+
+ for (int j = 0; j < tm_params->three_Spline_num; j++) {
+ print_q("3Spline_TH_enable_MB", tm_params->three_Spline_TH_enable_MB, '/');
+ print_q("3Spline_TH_enable", tm_params->three_Spline_TH_enable, '/');
+ print_q("3Spline_TH_Delta1", tm_params->three_Spline_TH_Delta1, '/');
+ print_q("3Spline_TH_Delta2", tm_params->three_Spline_TH_Delta2, '/');
+ print_q("3Spline_enable_Strength", tm_params->three_Spline_enable_Strength, '/');
+ }
+ }
+ }
+ }
+
+ print_int("color_saturation_mapping_flag", params->color_saturation_mapping_flag);
+ if (params->color_saturation_mapping_flag) {
+ print_int("color_saturation_num", params->color_saturation_num);
+ for (int i = 0; i < params->color_saturation_num; i++) {
+ print_q("color_saturation_gain", params->color_saturation_gain[i], '/');
+ }
+ }
+ }
+}
+
+static void print_ambient_viewing_environment(WriterContext *w,
+ const AVAmbientViewingEnvironment *env)
+{
+ if (!env)
+ return;
+
+ print_q("ambient_illuminance", env->ambient_illuminance, '/');
+ print_q("ambient_light_x", env->ambient_light_x, '/');
+ print_q("ambient_light_y", env->ambient_light_y, '/');
+}
+
+static void print_pkt_side_data(WriterContext *w,
+ AVCodecParameters *par,
+ const AVPacketSideData *side_data,
+ int nb_side_data,
+ SectionID id_data_list,
+ SectionID id_data)
+{
+ int i;
+
+ writer_print_section_header(w, id_data_list);
+ for (i = 0; i < nb_side_data; i++) {
+ const AVPacketSideData *sd = &side_data[i];
+ const char *name = av_packet_side_data_name(sd->type);
+
+ writer_print_section_header(w, id_data);
+ print_str("side_data_type", name ? name : "unknown");
+ if (sd->type == AV_PKT_DATA_DISPLAYMATRIX && sd->size >= 9*4) {
+ double rotation = av_display_rotation_get((int32_t *)sd->data);
+ if (isnan(rotation))
+ rotation = 0;
+ writer_print_integers(w, "displaymatrix", sd->data, 9, " %11d", 3, 4, 1);
+ print_int("rotation", rotation);
+ } else if (sd->type == AV_PKT_DATA_STEREO3D) {
+ const AVStereo3D *stereo = (AVStereo3D *)sd->data;
+ print_str("type", av_stereo3d_type_name(stereo->type));
+ print_int("inverted", !!(stereo->flags & AV_STEREO3D_FLAG_INVERT));
+ } else if (sd->type == AV_PKT_DATA_SPHERICAL) {
+ const AVSphericalMapping *spherical = (AVSphericalMapping *)sd->data;
+ print_str("projection", av_spherical_projection_name(spherical->projection));
+ if (spherical->projection == AV_SPHERICAL_CUBEMAP) {
+ print_int("padding", spherical->padding);
+ } else if (spherical->projection == AV_SPHERICAL_EQUIRECTANGULAR_TILE) {
+ size_t l, t, r, b;
+ av_spherical_tile_bounds(spherical, par->width, par->height,
+ &l, &t, &r, &b);
+ print_int("bound_left", l);
+ print_int("bound_top", t);
+ print_int("bound_right", r);
+ print_int("bound_bottom", b);
+ }
+
+ print_int("yaw", (double) spherical->yaw / (1 << 16));
+ print_int("pitch", (double) spherical->pitch / (1 << 16));
+ print_int("roll", (double) spherical->roll / (1 << 16));
+ } else if (sd->type == AV_PKT_DATA_SKIP_SAMPLES && sd->size == 10) {
+ print_int("skip_samples", AV_RL32(sd->data));
+ print_int("discard_padding", AV_RL32(sd->data + 4));
+ print_int("skip_reason", AV_RL8(sd->data + 8));
+ print_int("discard_reason", AV_RL8(sd->data + 9));
+ } else if (sd->type == AV_PKT_DATA_MASTERING_DISPLAY_METADATA) {
+ AVMasteringDisplayMetadata *metadata = (AVMasteringDisplayMetadata *)sd->data;
+
+ if (metadata->has_primaries) {
+ print_q("red_x", metadata->display_primaries[0][0], '/');
+ print_q("red_y", metadata->display_primaries[0][1], '/');
+ print_q("green_x", metadata->display_primaries[1][0], '/');
+ print_q("green_y", metadata->display_primaries[1][1], '/');
+ print_q("blue_x", metadata->display_primaries[2][0], '/');
+ print_q("blue_y", metadata->display_primaries[2][1], '/');
+
+ print_q("white_point_x", metadata->white_point[0], '/');
+ print_q("white_point_y", metadata->white_point[1], '/');
+ }
+
+ if (metadata->has_luminance) {
+ print_q("min_luminance", metadata->min_luminance, '/');
+ print_q("max_luminance", metadata->max_luminance, '/');
+ }
+ } else if (sd->type == AV_PKT_DATA_CONTENT_LIGHT_LEVEL) {
+ AVContentLightMetadata *metadata = (AVContentLightMetadata *)sd->data;
+ print_int("max_content", metadata->MaxCLL);
+ print_int("max_average", metadata->MaxFALL);
+ } else if (sd->type == AV_PKT_DATA_DOVI_CONF) {
+ AVDOVIDecoderConfigurationRecord *dovi = (AVDOVIDecoderConfigurationRecord *)sd->data;
+ print_int("dv_version_major", dovi->dv_version_major);
+ print_int("dv_version_minor", dovi->dv_version_minor);
+ print_int("dv_profile", dovi->dv_profile);
+ print_int("dv_level", dovi->dv_level);
+ print_int("rpu_present_flag", dovi->rpu_present_flag);
+ print_int("el_present_flag", dovi->el_present_flag);
+ print_int("bl_present_flag", dovi->bl_present_flag);
+ print_int("dv_bl_signal_compatibility_id", dovi->dv_bl_signal_compatibility_id);
+ } else if (sd->type == AV_PKT_DATA_AUDIO_SERVICE_TYPE) {
+ enum AVAudioServiceType *t = (enum AVAudioServiceType *)sd->data;
+ print_int("service_type", *t);
+ } else if (sd->type == AV_PKT_DATA_MPEGTS_STREAM_ID) {
+ print_int("id", *sd->data);
+ } else if (sd->type == AV_PKT_DATA_CPB_PROPERTIES) {
+ const AVCPBProperties *prop = (AVCPBProperties *)sd->data;
+ print_int("max_bitrate", prop->max_bitrate);
+ print_int("min_bitrate", prop->min_bitrate);
+ print_int("avg_bitrate", prop->avg_bitrate);
+ print_int("buffer_size", prop->buffer_size);
+ print_int("vbv_delay", prop->vbv_delay);
+ } else if (sd->type == AV_PKT_DATA_WEBVTT_IDENTIFIER ||
+ sd->type == AV_PKT_DATA_WEBVTT_SETTINGS) {
+ if (do_show_data)
+ writer_print_data(w, "data", sd->data, sd->size);
+ writer_print_data_hash(w, "data_hash", sd->data, sd->size);
+ } else if (sd->type == AV_PKT_DATA_AFD && sd->size > 0) {
+ print_int("active_format", *sd->data);
+ }
+ writer_print_section_footer(w);
+ }
+ writer_print_section_footer(w);
+}
+
+static void print_color_range(WriterContext *w, enum AVColorRange color_range)
+{
+ const char *val = av_color_range_name(color_range);
+ if (!val || color_range == AVCOL_RANGE_UNSPECIFIED) {
+ print_str_opt("color_range", "unknown");
+ } else {
+ print_str("color_range", val);
+ }
+}
+
+static void print_color_space(WriterContext *w, enum AVColorSpace color_space)
+{
+ const char *val = av_color_space_name(color_space);
+ if (!val || color_space == AVCOL_SPC_UNSPECIFIED) {
+ print_str_opt("color_space", "unknown");
+ } else {
+ print_str("color_space", val);
+ }
+}
+
+static void print_primaries(WriterContext *w, enum AVColorPrimaries color_primaries)
+{
+ const char *val = av_color_primaries_name(color_primaries);
+ if (!val || color_primaries == AVCOL_PRI_UNSPECIFIED) {
+ print_str_opt("color_primaries", "unknown");
+ } else {
+ print_str("color_primaries", val);
+ }
+}
+
+static void print_color_trc(WriterContext *w, enum AVColorTransferCharacteristic color_trc)
+{
+ const char *val = av_color_transfer_name(color_trc);
+ if (!val || color_trc == AVCOL_TRC_UNSPECIFIED) {
+ print_str_opt("color_transfer", "unknown");
+ } else {
+ print_str("color_transfer", val);
+ }
+}
+
+static void print_chroma_location(WriterContext *w, enum AVChromaLocation chroma_location)
+{
+ const char *val = av_chroma_location_name(chroma_location);
+ if (!val || chroma_location == AVCHROMA_LOC_UNSPECIFIED) {
+ print_str_opt("chroma_location", "unspecified");
+ } else {
+ print_str("chroma_location", val);
+ }
+}
+
+
+static void clear_log(int need_lock)
+{
+ int i;
+
+ if (need_lock)
+ pthread_mutex_lock(&log_mutex);
+ for (i=0; istreams[pkt->stream_index].st;
+ AVBPrint pbuf;
+ const char *s;
+
+ av_bprint_init(&pbuf, 1, AV_BPRINT_SIZE_UNLIMITED);
+
+ writer_print_section_header(w, SECTION_ID_PACKET);
+
+ s = av_get_media_type_string(st->codecpar->codec_type);
+ if (s) print_str ("codec_type", s);
+ else print_str_opt("codec_type", "unknown");
+ print_int("stream_index", pkt->stream_index);
+ print_ts ("pts", pkt->pts);
+ print_time("pts_time", pkt->pts, &st->time_base);
+ print_ts ("dts", pkt->dts);
+ print_time("dts_time", pkt->dts, &st->time_base);
+ print_duration_ts("duration", pkt->duration);
+ print_duration_time("duration_time", pkt->duration, &st->time_base);
+ print_val("size", pkt->size, unit_byte_str);
+ if (pkt->pos != -1) print_fmt ("pos", "%"PRId64, pkt->pos);
+ else print_str_opt("pos", "N/A");
+ print_fmt("flags", "%c%c%c", pkt->flags & AV_PKT_FLAG_KEY ? 'K' : '_',
+ pkt->flags & AV_PKT_FLAG_DISCARD ? 'D' : '_',
+ pkt->flags & AV_PKT_FLAG_CORRUPT ? 'C' : '_');
+ if (do_show_data)
+ writer_print_data(w, "data", pkt->data, pkt->size);
+ writer_print_data_hash(w, "data_hash", pkt->data, pkt->size);
+
+ if (pkt->side_data_elems) {
+ size_t size;
+ const uint8_t *side_metadata;
+
+ side_metadata = av_packet_get_side_data(pkt, AV_PKT_DATA_STRINGS_METADATA, &size);
+ if (side_metadata && size && do_show_packet_tags) {
+ AVDictionary *dict = NULL;
+ if (av_packet_unpack_dictionary(side_metadata, size, &dict) >= 0)
+ show_tags(w, dict, SECTION_ID_PACKET_TAGS);
+ av_dict_free(&dict);
+ }
+
+ print_pkt_side_data(w, st->codecpar, pkt->side_data, pkt->side_data_elems,
+ SECTION_ID_PACKET_SIDE_DATA_LIST,
+ SECTION_ID_PACKET_SIDE_DATA);
+ }
+
+ writer_print_section_footer(w);
+
+ av_bprint_finalize(&pbuf, NULL);
+ fflush(stdout);
+}
+
+static void show_subtitle(WriterContext *w, AVSubtitle *sub, AVStream *stream,
+ AVFormatContext *fmt_ctx)
+{
+ AVBPrint pbuf;
+
+ av_bprint_init(&pbuf, 1, AV_BPRINT_SIZE_UNLIMITED);
+
+ writer_print_section_header(w, SECTION_ID_SUBTITLE);
+
+ print_str ("media_type", "subtitle");
+ print_ts ("pts", sub->pts);
+ print_time("pts_time", sub->pts, &AV_TIME_BASE_Q);
+ print_int ("format", sub->format);
+ print_int ("start_display_time", sub->start_display_time);
+ print_int ("end_display_time", sub->end_display_time);
+ print_int ("num_rects", sub->num_rects);
+
+ writer_print_section_footer(w);
+
+ av_bprint_finalize(&pbuf, NULL);
+ fflush(stdout);
+}
+
+static void show_frame(WriterContext *w, AVFrame *frame, AVStream *stream,
+ AVFormatContext *fmt_ctx)
+{
+ AVBPrint pbuf;
+ char val_str[128];
+ const char *s;
+ int i;
+
+ av_bprint_init(&pbuf, 1, AV_BPRINT_SIZE_UNLIMITED);
+
+ writer_print_section_header(w, SECTION_ID_FRAME);
+
+ s = av_get_media_type_string(stream->codecpar->codec_type);
+ if (s) print_str ("media_type", s);
+ else print_str_opt("media_type", "unknown");
+ print_int("stream_index", stream->index);
+ print_int("key_frame", frame->key_frame);
+ print_ts ("pts", frame->pts);
+ print_time("pts_time", frame->pts, &stream->time_base);
+ print_ts ("pkt_dts", frame->pkt_dts);
+ print_time("pkt_dts_time", frame->pkt_dts, &stream->time_base);
+ print_ts ("best_effort_timestamp", frame->best_effort_timestamp);
+ print_time("best_effort_timestamp_time", frame->best_effort_timestamp, &stream->time_base);
+#if LIBAVUTIL_VERSION_MAJOR < 59
+ AV_NOWARN_DEPRECATED(
+ print_duration_ts ("pkt_duration", frame->pkt_duration);
+ print_duration_time("pkt_duration_time", frame->pkt_duration, &stream->time_base);
+ )
+#endif
+ print_duration_ts ("duration", frame->duration);
+ print_duration_time("duration_time", frame->duration, &stream->time_base);
+ if (frame->pkt_pos != -1) print_fmt ("pkt_pos", "%"PRId64, frame->pkt_pos);
+ else print_str_opt("pkt_pos", "N/A");
+ if (frame->pkt_size != -1) print_val ("pkt_size", frame->pkt_size, unit_byte_str);
+ else print_str_opt("pkt_size", "N/A");
+
+ switch (stream->codecpar->codec_type) {
+ AVRational sar;
+
+ case AVMEDIA_TYPE_VIDEO:
+ print_int("width", frame->width);
+ print_int("height", frame->height);
+ s = av_get_pix_fmt_name(frame->format);
+ if (s) print_str ("pix_fmt", s);
+ else print_str_opt("pix_fmt", "unknown");
+ sar = av_guess_sample_aspect_ratio(fmt_ctx, stream, frame);
+ if (sar.num) {
+ print_q("sample_aspect_ratio", sar, ':');
+ } else {
+ print_str_opt("sample_aspect_ratio", "N/A");
+ }
+ print_fmt("pict_type", "%c", av_get_picture_type_char(frame->pict_type));
+#if LIBAVUTIL_VERSION_MAJOR < 59
+ AV_NOWARN_DEPRECATED(
+ print_int("coded_picture_number", frame->coded_picture_number);
+ print_int("display_picture_number", frame->display_picture_number);
+ )
+#endif
+ print_int("interlaced_frame", frame->interlaced_frame);
+ print_int("top_field_first", frame->top_field_first);
+ print_int("repeat_pict", frame->repeat_pict);
+
+ print_color_range(w, frame->color_range);
+ print_color_space(w, frame->colorspace);
+ print_primaries(w, frame->color_primaries);
+ print_color_trc(w, frame->color_trc);
+ print_chroma_location(w, frame->chroma_location);
+ break;
+
+ case AVMEDIA_TYPE_AUDIO:
+ s = av_get_sample_fmt_name(frame->format);
+ if (s) print_str ("sample_fmt", s);
+ else print_str_opt("sample_fmt", "unknown");
+ print_int("nb_samples", frame->nb_samples);
+ print_int("channels", frame->ch_layout.nb_channels);
+ if (frame->ch_layout.order != AV_CHANNEL_ORDER_UNSPEC) {
+ av_channel_layout_describe(&frame->ch_layout, val_str, sizeof(val_str));
+ print_str ("channel_layout", val_str);
+ } else
+ print_str_opt("channel_layout", "unknown");
+ break;
+ }
+ if (do_show_frame_tags)
+ show_tags(w, frame->metadata, SECTION_ID_FRAME_TAGS);
+ if (do_show_log)
+ show_log(w, SECTION_ID_FRAME_LOGS, SECTION_ID_FRAME_LOG, do_show_log);
+ if (frame->nb_side_data) {
+ writer_print_section_header(w, SECTION_ID_FRAME_SIDE_DATA_LIST);
+ for (i = 0; i < frame->nb_side_data; i++) {
+ AVFrameSideData *sd = frame->side_data[i];
+ const char *name;
+
+ writer_print_section_header(w, SECTION_ID_FRAME_SIDE_DATA);
+ name = av_frame_side_data_name(sd->type);
+ print_str("side_data_type", name ? name : "unknown");
+ if (sd->type == AV_FRAME_DATA_DISPLAYMATRIX && sd->size >= 9*4) {
+ double rotation = av_display_rotation_get((int32_t *)sd->data);
+ if (isnan(rotation))
+ rotation = 0;
+ writer_print_integers(w, "displaymatrix", sd->data, 9, " %11d", 3, 4, 1);
+ print_int("rotation", rotation);
+ } else if (sd->type == AV_FRAME_DATA_AFD && sd->size > 0) {
+ print_int("active_format", *sd->data);
+ } else if (sd->type == AV_FRAME_DATA_GOP_TIMECODE && sd->size >= 8) {
+ char tcbuf[AV_TIMECODE_STR_SIZE];
+ av_timecode_make_mpeg_tc_string(tcbuf, *(int64_t *)(sd->data));
+ print_str("timecode", tcbuf);
+ } else if (sd->type == AV_FRAME_DATA_S12M_TIMECODE && sd->size == 16) {
+ uint32_t *tc = (uint32_t*)sd->data;
+ int m = FFMIN(tc[0],3);
+ writer_print_section_header(w, SECTION_ID_FRAME_SIDE_DATA_TIMECODE_LIST);
+ for (int j = 1; j <= m ; j++) {
+ char tcbuf[AV_TIMECODE_STR_SIZE];
+ av_timecode_make_smpte_tc_string2(tcbuf, stream->avg_frame_rate, tc[j], 0, 0);
+ writer_print_section_header(w, SECTION_ID_FRAME_SIDE_DATA_TIMECODE);
+ print_str("value", tcbuf);
+ writer_print_section_footer(w);
+ }
+ writer_print_section_footer(w);
+ } else if (sd->type == AV_FRAME_DATA_MASTERING_DISPLAY_METADATA) {
+ AVMasteringDisplayMetadata *metadata = (AVMasteringDisplayMetadata *)sd->data;
+
+ if (metadata->has_primaries) {
+ print_q("red_x", metadata->display_primaries[0][0], '/');
+ print_q("red_y", metadata->display_primaries[0][1], '/');
+ print_q("green_x", metadata->display_primaries[1][0], '/');
+ print_q("green_y", metadata->display_primaries[1][1], '/');
+ print_q("blue_x", metadata->display_primaries[2][0], '/');
+ print_q("blue_y", metadata->display_primaries[2][1], '/');
+
+ print_q("white_point_x", metadata->white_point[0], '/');
+ print_q("white_point_y", metadata->white_point[1], '/');
+ }
+
+ if (metadata->has_luminance) {
+ print_q("min_luminance", metadata->min_luminance, '/');
+ print_q("max_luminance", metadata->max_luminance, '/');
+ }
+ } else if (sd->type == AV_FRAME_DATA_DYNAMIC_HDR_PLUS) {
+ AVDynamicHDRPlus *metadata = (AVDynamicHDRPlus *)sd->data;
+ print_dynamic_hdr10_plus(w, metadata);
+ } else if (sd->type == AV_FRAME_DATA_CONTENT_LIGHT_LEVEL) {
+ AVContentLightMetadata *metadata = (AVContentLightMetadata *)sd->data;
+ print_int("max_content", metadata->MaxCLL);
+ print_int("max_average", metadata->MaxFALL);
+ } else if (sd->type == AV_FRAME_DATA_ICC_PROFILE) {
+ const AVDictionaryEntry *tag = av_dict_get(sd->metadata, "name", NULL, AV_DICT_MATCH_CASE);
+ if (tag)
+ print_str(tag->key, tag->value);
+ print_int("size", sd->size);
+ } else if (sd->type == AV_FRAME_DATA_DOVI_METADATA) {
+ print_dovi_metadata(w, (const AVDOVIMetadata *)sd->data);
+ } else if (sd->type == AV_FRAME_DATA_DYNAMIC_HDR_VIVID) {
+ AVDynamicHDRVivid *metadata = (AVDynamicHDRVivid *)sd->data;
+ print_dynamic_hdr_vivid(w, metadata);
+ } else if (sd->type == AV_FRAME_DATA_AMBIENT_VIEWING_ENVIRONMENT) {
+ print_ambient_viewing_environment(
+ w, (const AVAmbientViewingEnvironment *)sd->data);
+ }
+ writer_print_section_footer(w);
+ }
+ writer_print_section_footer(w);
+ }
+
+ writer_print_section_footer(w);
+
+ av_bprint_finalize(&pbuf, NULL);
+ fflush(stdout);
+}
+
+static av_always_inline int process_frame(WriterContext *w,
+ InputFile *ifile,
+ AVFrame *frame, const AVPacket *pkt,
+ int *packet_new)
+{
+ AVFormatContext *fmt_ctx = ifile->fmt_ctx;
+ AVCodecContext *dec_ctx = ifile->streams[pkt->stream_index].dec_ctx;
+ AVCodecParameters *par = ifile->streams[pkt->stream_index].st->codecpar;
+ AVSubtitle sub;
+ int ret = 0, got_frame = 0;
+
+ clear_log(1);
+ if (dec_ctx) {
+ switch (par->codec_type) {
+ case AVMEDIA_TYPE_VIDEO:
+ case AVMEDIA_TYPE_AUDIO:
+ if (*packet_new) {
+ ret = avcodec_send_packet(dec_ctx, pkt);
+ if (ret == AVERROR(EAGAIN)) {
+ ret = 0;
+ } else if (ret >= 0 || ret == AVERROR_EOF) {
+ ret = 0;
+ *packet_new = 0;
+ }
+ }
+ if (ret >= 0) {
+ ret = avcodec_receive_frame(dec_ctx, frame);
+ if (ret >= 0) {
+ got_frame = 1;
+ } else if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) {
+ ret = 0;
+ }
+ }
+ break;
+
+ case AVMEDIA_TYPE_SUBTITLE:
+ if (*packet_new)
+ ret = avcodec_decode_subtitle2(dec_ctx, &sub, &got_frame, pkt);
+ *packet_new = 0;
+ break;
+ default:
+ *packet_new = 0;
+ }
+ } else {
+ *packet_new = 0;
+ }
+
+ if (ret < 0)
+ return ret;
+ if (got_frame) {
+ int is_sub = (par->codec_type == AVMEDIA_TYPE_SUBTITLE);
+ nb_streams_frames[pkt->stream_index]++;
+ if (do_show_frames)
+ if (is_sub)
+ show_subtitle(w, &sub, ifile->streams[pkt->stream_index].st, fmt_ctx);
+ else
+ show_frame(w, frame, ifile->streams[pkt->stream_index].st, fmt_ctx);
+ if (is_sub)
+ avsubtitle_free(&sub);
+ }
+ return got_frame || *packet_new;
+}
+
+static void log_read_interval(const ReadInterval *interval, void *log_ctx, int log_level)
+{
+ av_log(log_ctx, log_level, "id:%d", interval->id);
+
+ if (interval->has_start) {
+ av_log(log_ctx, log_level, " start:%s%s", interval->start_is_offset ? "+" : "",
+ av_ts2timestr(interval->start, &AV_TIME_BASE_Q));
+ } else {
+ av_log(log_ctx, log_level, " start:N/A");
+ }
+
+ if (interval->has_end) {
+ av_log(log_ctx, log_level, " end:%s", interval->end_is_offset ? "+" : "");
+ if (interval->duration_frames)
+ av_log(log_ctx, log_level, "#%"PRId64, interval->end);
+ else
+ av_log(log_ctx, log_level, "%s", av_ts2timestr(interval->end, &AV_TIME_BASE_Q));
+ } else {
+ av_log(log_ctx, log_level, " end:N/A");
+ }
+
+ av_log(log_ctx, log_level, "\n");
+}
+
+static int read_interval_packets(WriterContext *w, InputFile *ifile,
+ const ReadInterval *interval, int64_t *cur_ts)
+{
+ AVFormatContext *fmt_ctx = ifile->fmt_ctx;
+ AVPacket *pkt = NULL;
+ AVFrame *frame = NULL;
+ int ret = 0, i = 0, frame_count = 0;
+ int64_t start = -INT64_MAX, end = interval->end;
+ int has_start = 0, has_end = interval->has_end && !interval->end_is_offset;
+
+ av_log(NULL, AV_LOG_VERBOSE, "Processing read interval ");
+ log_read_interval(interval, NULL, AV_LOG_VERBOSE);
+
+ if (interval->has_start) {
+ int64_t target;
+ if (interval->start_is_offset) {
+ if (*cur_ts == AV_NOPTS_VALUE) {
+ av_log(NULL, AV_LOG_ERROR,
+ "Could not seek to relative position since current "
+ "timestamp is not defined\n");
+ ret = AVERROR(EINVAL);
+ goto end;
+ }
+ target = *cur_ts + interval->start;
+ } else {
+ target = interval->start;
+ }
+
+ av_log(NULL, AV_LOG_VERBOSE, "Seeking to read interval start point %s\n",
+ av_ts2timestr(target, &AV_TIME_BASE_Q));
+ if ((ret = avformat_seek_file(fmt_ctx, -1, -INT64_MAX, target, INT64_MAX, 0)) < 0) {
+ av_log(NULL, AV_LOG_ERROR, "Could not seek to position %"PRId64": %s\n",
+ interval->start, av_err2str(ret));
+ goto end;
+ }
+ }
+
+ frame = av_frame_alloc();
+ if (!frame) {
+ ret = AVERROR(ENOMEM);
+ goto end;
+ }
+ pkt = av_packet_alloc();
+ if (!pkt) {
+ ret = AVERROR(ENOMEM);
+ goto end;
+ }
+ while (!av_read_frame(fmt_ctx, pkt)) {
+ if (fmt_ctx->nb_streams > nb_streams) {
+ REALLOCZ_ARRAY_STREAM(nb_streams_frames, nb_streams, fmt_ctx->nb_streams);
+ REALLOCZ_ARRAY_STREAM(nb_streams_packets, nb_streams, fmt_ctx->nb_streams);
+ REALLOCZ_ARRAY_STREAM(selected_streams, nb_streams, fmt_ctx->nb_streams);
+ nb_streams = fmt_ctx->nb_streams;
+ }
+ if (selected_streams[pkt->stream_index]) {
+ AVRational tb = ifile->streams[pkt->stream_index].st->time_base;
+ int64_t pts = pkt->pts != AV_NOPTS_VALUE ? pkt->pts : pkt->dts;
+
+ if (pts != AV_NOPTS_VALUE)
+ *cur_ts = av_rescale_q(pts, tb, AV_TIME_BASE_Q);
+
+ if (!has_start && *cur_ts != AV_NOPTS_VALUE) {
+ start = *cur_ts;
+ has_start = 1;
+ }
+
+ if (has_start && !has_end && interval->end_is_offset) {
+ end = start + interval->end;
+ has_end = 1;
+ }
+
+ if (interval->end_is_offset && interval->duration_frames) {
+ if (frame_count >= interval->end)
+ break;
+ } else if (has_end && *cur_ts != AV_NOPTS_VALUE && *cur_ts >= end) {
+ break;
+ }
+
+ frame_count++;
+ if (do_read_packets) {
+ if (do_show_packets)
+ show_packet(w, ifile, pkt, i++);
+ nb_streams_packets[pkt->stream_index]++;
+ }
+ if (do_read_frames) {
+ int packet_new = 1;
+ while (process_frame(w, ifile, frame, pkt, &packet_new) > 0);
+ }
+ }
+ av_packet_unref(pkt);
+ }
+ av_packet_unref(pkt);
+ //Flush remaining frames that are cached in the decoder
+ for (i = 0; i < ifile->nb_streams; i++) {
+ pkt->stream_index = i;
+ if (do_read_frames) {
+ while (process_frame(w, ifile, frame, pkt, &(int){1}) > 0);
+ if (ifile->streams[i].dec_ctx)
+ avcodec_flush_buffers(ifile->streams[i].dec_ctx);
+ }
+ }
+
+end:
+ av_frame_free(&frame);
+ av_packet_free(&pkt);
+ if (ret < 0) {
+ av_log(NULL, AV_LOG_ERROR, "Could not read packets in interval ");
+ log_read_interval(interval, NULL, AV_LOG_ERROR);
+ }
+ return ret;
+}
+
+static int read_packets(WriterContext *w, InputFile *ifile)
+{
+ AVFormatContext *fmt_ctx = ifile->fmt_ctx;
+ int i, ret = 0;
+ int64_t cur_ts = fmt_ctx->start_time;
+
+ if (read_intervals_nb == 0) {
+ ReadInterval interval = (ReadInterval) { .has_start = 0, .has_end = 0 };
+ ret = read_interval_packets(w, ifile, &interval, &cur_ts);
+ } else {
+ for (i = 0; i < read_intervals_nb; i++) {
+ ret = read_interval_packets(w, ifile, &read_intervals[i], &cur_ts);
+ if (ret < 0)
+ break;
+ }
+ }
+
+ return ret;
+}
+
+static int show_stream(WriterContext *w, AVFormatContext *fmt_ctx, int stream_idx, InputStream *ist, int in_program)
+{
+ AVStream *stream = ist->st;
+ AVCodecParameters *par;
+ AVCodecContext *dec_ctx;
+ char val_str[128];
+ const char *s;
+ AVRational sar, dar;
+ AVBPrint pbuf;
+ const AVCodecDescriptor *cd;
+ int ret = 0;
+ const char *profile = NULL;
+
+ av_bprint_init(&pbuf, 1, AV_BPRINT_SIZE_UNLIMITED);
+
+ writer_print_section_header(w, in_program ? SECTION_ID_PROGRAM_STREAM : SECTION_ID_STREAM);
+
+ print_int("index", stream->index);
+
+ par = stream->codecpar;
+ dec_ctx = ist->dec_ctx;
+ if (cd = avcodec_descriptor_get(par->codec_id)) {
+ print_str("codec_name", cd->name);
+ if (!do_bitexact) {
+ print_str("codec_long_name",
+ cd->long_name ? cd->long_name : "unknown");
+ }
+ } else {
+ print_str_opt("codec_name", "unknown");
+ if (!do_bitexact) {
+ print_str_opt("codec_long_name", "unknown");
+ }
+ }
+
+ if (!do_bitexact && (profile = avcodec_profile_name(par->codec_id, par->profile)))
+ print_str("profile", profile);
+ else {
+ if (par->profile != FF_PROFILE_UNKNOWN) {
+ char profile_num[12];
+ snprintf(profile_num, sizeof(profile_num), "%d", par->profile);
+ print_str("profile", profile_num);
+ } else
+ print_str_opt("profile", "unknown");
+ }
+
+ s = av_get_media_type_string(par->codec_type);
+ if (s) print_str ("codec_type", s);
+ else print_str_opt("codec_type", "unknown");
+
+ /* print AVI/FourCC tag */
+ print_str("codec_tag_string", av_fourcc2str(par->codec_tag));
+ print_fmt("codec_tag", "0x%04"PRIx32, par->codec_tag);
+
+ switch (par->codec_type) {
+ case AVMEDIA_TYPE_VIDEO:
+ print_int("width", par->width);
+ print_int("height", par->height);
+ if (dec_ctx) {
+ print_int("coded_width", dec_ctx->coded_width);
+ print_int("coded_height", dec_ctx->coded_height);
+ print_int("closed_captions", !!(dec_ctx->properties & FF_CODEC_PROPERTY_CLOSED_CAPTIONS));
+ print_int("film_grain", !!(dec_ctx->properties & FF_CODEC_PROPERTY_FILM_GRAIN));
+ }
+ print_int("has_b_frames", par->video_delay);
+ sar = av_guess_sample_aspect_ratio(fmt_ctx, stream, NULL);
+ if (sar.num) {
+ print_q("sample_aspect_ratio", sar, ':');
+ av_reduce(&dar.num, &dar.den,
+ par->width * sar.num,
+ par->height * sar.den,
+ 1024*1024);
+ print_q("display_aspect_ratio", dar, ':');
+ } else {
+ print_str_opt("sample_aspect_ratio", "N/A");
+ print_str_opt("display_aspect_ratio", "N/A");
+ }
+ s = av_get_pix_fmt_name(par->format);
+ if (s) print_str ("pix_fmt", s);
+ else print_str_opt("pix_fmt", "unknown");
+ print_int("level", par->level);
+
+ print_color_range(w, par->color_range);
+ print_color_space(w, par->color_space);
+ print_color_trc(w, par->color_trc);
+ print_primaries(w, par->color_primaries);
+ print_chroma_location(w, par->chroma_location);
+
+ if (par->field_order == AV_FIELD_PROGRESSIVE)
+ print_str("field_order", "progressive");
+ else if (par->field_order == AV_FIELD_TT)
+ print_str("field_order", "tt");
+ else if (par->field_order == AV_FIELD_BB)
+ print_str("field_order", "bb");
+ else if (par->field_order == AV_FIELD_TB)
+ print_str("field_order", "tb");
+ else if (par->field_order == AV_FIELD_BT)
+ print_str("field_order", "bt");
+ else
+ print_str_opt("field_order", "unknown");
+
+ if (dec_ctx)
+ print_int("refs", dec_ctx->refs);
+ break;
+
+ case AVMEDIA_TYPE_AUDIO:
+ s = av_get_sample_fmt_name(par->format);
+ if (s) print_str ("sample_fmt", s);
+ else print_str_opt("sample_fmt", "unknown");
+ print_val("sample_rate", par->sample_rate, unit_hertz_str);
+ print_int("channels", par->ch_layout.nb_channels);
+
+ if (par->ch_layout.order != AV_CHANNEL_ORDER_UNSPEC) {
+ av_channel_layout_describe(&par->ch_layout, val_str, sizeof(val_str));
+ print_str ("channel_layout", val_str);
+ } else {
+ print_str_opt("channel_layout", "unknown");
+ }
+
+ print_int("bits_per_sample", av_get_bits_per_sample(par->codec_id));
+
+ print_int("initial_padding", par->initial_padding);
+ break;
+
+ case AVMEDIA_TYPE_SUBTITLE:
+ if (par->width)
+ print_int("width", par->width);
+ else
+ print_str_opt("width", "N/A");
+ if (par->height)
+ print_int("height", par->height);
+ else
+ print_str_opt("height", "N/A");
+ break;
+ }
+
+ if (dec_ctx && dec_ctx->codec->priv_class && show_private_data) {
+ const AVOption *opt = NULL;
+ while (opt = av_opt_next(dec_ctx->priv_data,opt)) {
+ uint8_t *str;
+ if (!(opt->flags & AV_OPT_FLAG_EXPORT)) continue;
+ if (av_opt_get(dec_ctx->priv_data, opt->name, 0, &str) >= 0) {
+ print_str(opt->name, str);
+ av_free(str);
+ }
+ }
+ }
+
+ if (fmt_ctx->iformat->flags & AVFMT_SHOW_IDS) print_fmt ("id", "0x%x", stream->id);
+ else print_str_opt("id", "N/A");
+ print_q("r_frame_rate", stream->r_frame_rate, '/');
+ print_q("avg_frame_rate", stream->avg_frame_rate, '/');
+ print_q("time_base", stream->time_base, '/');
+ print_ts ("start_pts", stream->start_time);
+ print_time("start_time", stream->start_time, &stream->time_base);
+ print_ts ("duration_ts", stream->duration);
+ print_time("duration", stream->duration, &stream->time_base);
+ if (par->bit_rate > 0) print_val ("bit_rate", par->bit_rate, unit_bit_per_second_str);
+ else print_str_opt("bit_rate", "N/A");
+ if (dec_ctx && dec_ctx->rc_max_rate > 0)
+ print_val ("max_bit_rate", dec_ctx->rc_max_rate, unit_bit_per_second_str);
+ else
+ print_str_opt("max_bit_rate", "N/A");
+ if (dec_ctx && dec_ctx->bits_per_raw_sample > 0) print_fmt("bits_per_raw_sample", "%d", dec_ctx->bits_per_raw_sample);
+ else print_str_opt("bits_per_raw_sample", "N/A");
+ if (stream->nb_frames) print_fmt ("nb_frames", "%"PRId64, stream->nb_frames);
+ else print_str_opt("nb_frames", "N/A");
+ if (nb_streams_frames[stream_idx]) print_fmt ("nb_read_frames", "%"PRIu64, nb_streams_frames[stream_idx]);
+ else print_str_opt("nb_read_frames", "N/A");
+ if (nb_streams_packets[stream_idx]) print_fmt ("nb_read_packets", "%"PRIu64, nb_streams_packets[stream_idx]);
+ else print_str_opt("nb_read_packets", "N/A");
+ if (do_show_data)
+ writer_print_data(w, "extradata", par->extradata,
+ par->extradata_size);
+
+ if (par->extradata_size > 0) {
+ print_int("extradata_size", par->extradata_size);
+ writer_print_data_hash(w, "extradata_hash", par->extradata,
+ par->extradata_size);
+ }
+
+ /* Print disposition information */
+#define PRINT_DISPOSITION(flagname, name) do { \
+ print_int(name, !!(stream->disposition & AV_DISPOSITION_##flagname)); \
+ } while (0)
+
+ if (do_show_stream_disposition) {
+ writer_print_section_header(w, in_program ? SECTION_ID_PROGRAM_STREAM_DISPOSITION : SECTION_ID_STREAM_DISPOSITION);
+ PRINT_DISPOSITION(DEFAULT, "default");
+ PRINT_DISPOSITION(DUB, "dub");
+ PRINT_DISPOSITION(ORIGINAL, "original");
+ PRINT_DISPOSITION(COMMENT, "comment");
+ PRINT_DISPOSITION(LYRICS, "lyrics");
+ PRINT_DISPOSITION(KARAOKE, "karaoke");
+ PRINT_DISPOSITION(FORCED, "forced");
+ PRINT_DISPOSITION(HEARING_IMPAIRED, "hearing_impaired");
+ PRINT_DISPOSITION(VISUAL_IMPAIRED, "visual_impaired");
+ PRINT_DISPOSITION(CLEAN_EFFECTS, "clean_effects");
+ PRINT_DISPOSITION(ATTACHED_PIC, "attached_pic");
+ PRINT_DISPOSITION(TIMED_THUMBNAILS, "timed_thumbnails");
+ PRINT_DISPOSITION(CAPTIONS, "captions");
+ PRINT_DISPOSITION(DESCRIPTIONS, "descriptions");
+ PRINT_DISPOSITION(METADATA, "metadata");
+ PRINT_DISPOSITION(DEPENDENT, "dependent");
+ PRINT_DISPOSITION(STILL_IMAGE, "still_image");
+ writer_print_section_footer(w);
+ }
+
+ if (do_show_stream_tags)
+ ret = show_tags(w, stream->metadata, in_program ? SECTION_ID_PROGRAM_STREAM_TAGS : SECTION_ID_STREAM_TAGS);
+
+ if (stream->nb_side_data) {
+ print_pkt_side_data(w, stream->codecpar, stream->side_data, stream->nb_side_data,
+ SECTION_ID_STREAM_SIDE_DATA_LIST,
+ SECTION_ID_STREAM_SIDE_DATA);
+ }
+
+ writer_print_section_footer(w);
+ av_bprint_finalize(&pbuf, NULL);
+ fflush(stdout);
+
+ return ret;
+}
+
+static int show_streams(WriterContext *w, InputFile *ifile)
+{
+ AVFormatContext *fmt_ctx = ifile->fmt_ctx;
+ int i, ret = 0;
+
+ writer_print_section_header(w, SECTION_ID_STREAMS);
+ for (i = 0; i < ifile->nb_streams; i++)
+ if (selected_streams[i]) {
+ ret = show_stream(w, fmt_ctx, i, &ifile->streams[i], 0);
+ if (ret < 0)
+ break;
+ }
+ writer_print_section_footer(w);
+
+ return ret;
+}
+
+static int show_program(WriterContext *w, InputFile *ifile, AVProgram *program)
+{
+ AVFormatContext *fmt_ctx = ifile->fmt_ctx;
+ int i, ret = 0;
+
+ writer_print_section_header(w, SECTION_ID_PROGRAM);
+ print_int("program_id", program->id);
+ print_int("program_num", program->program_num);
+ print_int("nb_streams", program->nb_stream_indexes);
+ print_int("pmt_pid", program->pmt_pid);
+ print_int("pcr_pid", program->pcr_pid);
+ if (do_show_program_tags)
+ ret = show_tags(w, program->metadata, SECTION_ID_PROGRAM_TAGS);
+ if (ret < 0)
+ goto end;
+
+ writer_print_section_header(w, SECTION_ID_PROGRAM_STREAMS);
+ for (i = 0; i < program->nb_stream_indexes; i++) {
+ if (selected_streams[program->stream_index[i]]) {
+ ret = show_stream(w, fmt_ctx, program->stream_index[i], &ifile->streams[program->stream_index[i]], 1);
+ if (ret < 0)
+ break;
+ }
+ }
+ writer_print_section_footer(w);
+
+end:
+ writer_print_section_footer(w);
+ return ret;
+}
+
+static int show_programs(WriterContext *w, InputFile *ifile)
+{
+ AVFormatContext *fmt_ctx = ifile->fmt_ctx;
+ int i, ret = 0;
+
+ writer_print_section_header(w, SECTION_ID_PROGRAMS);
+ for (i = 0; i < fmt_ctx->nb_programs; i++) {
+ AVProgram *program = fmt_ctx->programs[i];
+ if (!program)
+ continue;
+ ret = show_program(w, ifile, program);
+ if (ret < 0)
+ break;
+ }
+ writer_print_section_footer(w);
+ return ret;
+}
+
+static int show_chapters(WriterContext *w, InputFile *ifile)
+{
+ AVFormatContext *fmt_ctx = ifile->fmt_ctx;
+ int i, ret = 0;
+
+ writer_print_section_header(w, SECTION_ID_CHAPTERS);
+ for (i = 0; i < fmt_ctx->nb_chapters; i++) {
+ AVChapter *chapter = fmt_ctx->chapters[i];
+
+ writer_print_section_header(w, SECTION_ID_CHAPTER);
+ print_int("id", chapter->id);
+ print_q ("time_base", chapter->time_base, '/');
+ print_int("start", chapter->start);
+ print_time("start_time", chapter->start, &chapter->time_base);
+ print_int("end", chapter->end);
+ print_time("end_time", chapter->end, &chapter->time_base);
+ if (do_show_chapter_tags)
+ ret = show_tags(w, chapter->metadata, SECTION_ID_CHAPTER_TAGS);
+ writer_print_section_footer(w);
+ }
+ writer_print_section_footer(w);
+
+ return ret;
+}
+
+static int show_format(WriterContext *w, InputFile *ifile)
+{
+ AVFormatContext *fmt_ctx = ifile->fmt_ctx;
+ char val_str[128];
+ int64_t size = fmt_ctx->pb ? avio_size(fmt_ctx->pb) : -1;
+ int ret = 0;
+
+ writer_print_section_header(w, SECTION_ID_FORMAT);
+ print_str_validate("filename", fmt_ctx->url);
+ print_int("nb_streams", fmt_ctx->nb_streams);
+ print_int("nb_programs", fmt_ctx->nb_programs);
+ print_str("format_name", fmt_ctx->iformat->name);
+ if (!do_bitexact) {
+ if (fmt_ctx->iformat->long_name) print_str ("format_long_name", fmt_ctx->iformat->long_name);
+ else print_str_opt("format_long_name", "unknown");
+ }
+ print_time("start_time", fmt_ctx->start_time, &AV_TIME_BASE_Q);
+ print_time("duration", fmt_ctx->duration, &AV_TIME_BASE_Q);
+ if (size >= 0) print_val ("size", size, unit_byte_str);
+ else print_str_opt("size", "N/A");
+ if (fmt_ctx->bit_rate > 0) print_val ("bit_rate", fmt_ctx->bit_rate, unit_bit_per_second_str);
+ else print_str_opt("bit_rate", "N/A");
+ print_int("probe_score", fmt_ctx->probe_score);
+ if (do_show_format_tags)
+ ret = show_tags(w, fmt_ctx->metadata, SECTION_ID_FORMAT_TAGS);
+
+ writer_print_section_footer(w);
+ fflush(stdout);
+ return ret;
+}
+
+static void show_error(WriterContext *w, int err)
+{
+ writer_print_section_header(w, SECTION_ID_ERROR);
+ print_int("code", err);
+ print_str("string", av_err2str(err));
+ writer_print_section_footer(w);
+}
+
+static int open_input_file(InputFile *ifile, const char *filename,
+ const char *print_filename)
+{
+ int err, i;
+ AVFormatContext *fmt_ctx = NULL;
+ const AVDictionaryEntry *t = NULL;
+ int scan_all_pmts_set = 0;
+
+ fmt_ctx = avformat_alloc_context();
+ if (!fmt_ctx)
+ report_and_exit(AVERROR(ENOMEM));
+
+ if (!av_dict_get(format_opts, "scan_all_pmts", NULL, AV_DICT_MATCH_CASE)) {
+ av_dict_set(&format_opts, "scan_all_pmts", "1", AV_DICT_DONT_OVERWRITE);
+ scan_all_pmts_set = 1;
+ }
+ if ((err = avformat_open_input(&fmt_ctx, filename,
+ iformat, &format_opts)) < 0) {
+ print_error(filename, err);
+ return err;
+ }
+ if (print_filename) {
+ av_freep(&fmt_ctx->url);
+ fmt_ctx->url = av_strdup(print_filename);
+ }
+ ifile->fmt_ctx = fmt_ctx;
+ if (scan_all_pmts_set)
+ av_dict_set(&format_opts, "scan_all_pmts", NULL, AV_DICT_MATCH_CASE);
+ while ((t = av_dict_iterate(format_opts, t)))
+ av_log(NULL, AV_LOG_WARNING, "Option %s skipped - not known to demuxer.\n", t->key);
+
+ if (find_stream_info) {
+ AVDictionary **opts = setup_find_stream_info_opts(fmt_ctx, codec_opts);
+ int orig_nb_streams = fmt_ctx->nb_streams;
+
+ err = avformat_find_stream_info(fmt_ctx, opts);
+
+ for (i = 0; i < orig_nb_streams; i++)
+ av_dict_free(&opts[i]);
+ av_freep(&opts);
+
+ if (err < 0) {
+ print_error(filename, err);
+ return err;
+ }
+ }
+
+ av_dump_format(fmt_ctx, 0, filename, 0);
+
+ ifile->streams = av_calloc(fmt_ctx->nb_streams, sizeof(*ifile->streams));
+ if (!ifile->streams)
+ exit(1);
+ ifile->nb_streams = fmt_ctx->nb_streams;
+
+ /* bind a decoder to each input stream */
+ for (i = 0; i < fmt_ctx->nb_streams; i++) {
+ InputStream *ist = &ifile->streams[i];
+ AVStream *stream = fmt_ctx->streams[i];
+ const AVCodec *codec;
+
+ ist->st = stream;
+
+ if (stream->codecpar->codec_id == AV_CODEC_ID_PROBE) {
+ av_log(NULL, AV_LOG_WARNING,
+ "Failed to probe codec for input stream %d\n",
+ stream->index);
+ continue;
+ }
+
+ codec = avcodec_find_decoder(stream->codecpar->codec_id);
+ if (!codec) {
+ av_log(NULL, AV_LOG_WARNING,
+ "Unsupported codec with id %d for input stream %d\n",
+ stream->codecpar->codec_id, stream->index);
+ continue;
+ }
+ {
+ AVDictionary *opts = filter_codec_opts(codec_opts, stream->codecpar->codec_id,
+ fmt_ctx, stream, codec);
+
+ ist->dec_ctx = avcodec_alloc_context3(codec);
+ if (!ist->dec_ctx)
+ exit(1);
+
+ err = avcodec_parameters_to_context(ist->dec_ctx, stream->codecpar);
+ if (err < 0)
+ exit(1);
+
+ if (do_show_log) {
+ // For loging it is needed to disable at least frame threads as otherwise
+ // the log information would need to be reordered and matches up to contexts and frames
+ // That is in fact possible but not trivial
+ av_dict_set(&codec_opts, "threads", "1", 0);
+ }
+
+ ist->dec_ctx->pkt_timebase = stream->time_base;
+
+ if (avcodec_open2(ist->dec_ctx, codec, &opts) < 0) {
+ av_log(NULL, AV_LOG_WARNING, "Could not open codec for input stream %d\n",
+ stream->index);
+ exit(1);
+ }
+
+ if ((t = av_dict_get(opts, "", NULL, AV_DICT_IGNORE_SUFFIX))) {
+ av_log(NULL, AV_LOG_ERROR, "Option %s for input stream %d not found\n",
+ t->key, stream->index);
+ return AVERROR_OPTION_NOT_FOUND;
+ }
+ }
+ }
+
+ ifile->fmt_ctx = fmt_ctx;
+ return 0;
+}
+
+static void close_input_file(InputFile *ifile)
+{
+ int i;
+
+ /* close decoder for each stream */
+ for (i = 0; i < ifile->nb_streams; i++)
+ avcodec_free_context(&ifile->streams[i].dec_ctx);
+
+ av_freep(&ifile->streams);
+ ifile->nb_streams = 0;
+
+ avformat_close_input(&ifile->fmt_ctx);
+}
+
+static int probe_file(WriterContext *wctx, const char *filename,
+ const char *print_filename)
+{
+ InputFile ifile = { 0 };
+ int ret, i;
+ int section_id;
+
+ do_read_frames = do_show_frames || do_count_frames;
+ do_read_packets = do_show_packets || do_count_packets;
+
+ ret = open_input_file(&ifile, filename, print_filename);
+ if (ret < 0)
+ goto end;
+
+#define CHECK_END if (ret < 0) goto end
+
+ nb_streams = ifile.fmt_ctx->nb_streams;
+ REALLOCZ_ARRAY_STREAM(nb_streams_frames,0,ifile.fmt_ctx->nb_streams);
+ REALLOCZ_ARRAY_STREAM(nb_streams_packets,0,ifile.fmt_ctx->nb_streams);
+ REALLOCZ_ARRAY_STREAM(selected_streams,0,ifile.fmt_ctx->nb_streams);
+
+ for (i = 0; i < ifile.fmt_ctx->nb_streams; i++) {
+ if (stream_specifier) {
+ ret = avformat_match_stream_specifier(ifile.fmt_ctx,
+ ifile.fmt_ctx->streams[i],
+ stream_specifier);
+ CHECK_END;
+ else
+ selected_streams[i] = ret;
+ ret = 0;
+ } else {
+ selected_streams[i] = 1;
+ }
+ if (!selected_streams[i])
+ ifile.fmt_ctx->streams[i]->discard = AVDISCARD_ALL;
+ }
+
+ if (do_read_frames || do_read_packets) {
+ if (do_show_frames && do_show_packets &&
+ wctx->writer->flags & WRITER_FLAG_PUT_PACKETS_AND_FRAMES_IN_SAME_CHAPTER)
+ section_id = SECTION_ID_PACKETS_AND_FRAMES;
+ else if (do_show_packets && !do_show_frames)
+ section_id = SECTION_ID_PACKETS;
+ else // (!do_show_packets && do_show_frames)
+ section_id = SECTION_ID_FRAMES;
+ if (do_show_frames || do_show_packets)
+ writer_print_section_header(wctx, section_id);
+ ret = read_packets(wctx, &ifile);
+ if (do_show_frames || do_show_packets)
+ writer_print_section_footer(wctx);
+ CHECK_END;
+ }
+
+ if (do_show_programs) {
+ ret = show_programs(wctx, &ifile);
+ CHECK_END;
+ }
+
+ if (do_show_streams) {
+ ret = show_streams(wctx, &ifile);
+ CHECK_END;
+ }
+ if (do_show_chapters) {
+ ret = show_chapters(wctx, &ifile);
+ CHECK_END;
+ }
+ if (do_show_format) {
+ ret = show_format(wctx, &ifile);
+ CHECK_END;
+ }
+
+end:
+ if (ifile.fmt_ctx)
+ close_input_file(&ifile);
+ av_freep(&nb_streams_frames);
+ av_freep(&nb_streams_packets);
+ av_freep(&selected_streams);
+
+ return ret;
+}
+
+static void show_usage(void)
+{
+ av_log(NULL, AV_LOG_INFO, "Simple multimedia streams analyzer\n");
+ av_log(NULL, AV_LOG_INFO, "usage: %s [OPTIONS] INPUT_FILE\n", ffprobe_program_name);
+ av_log(NULL, AV_LOG_INFO, "\n");
+}
+
+static void ffprobe_show_program_version(WriterContext *w)
+{
+ AVBPrint pbuf;
+ av_bprint_init(&pbuf, 1, AV_BPRINT_SIZE_UNLIMITED);
+
+ writer_print_section_header(w, SECTION_ID_PROGRAM_VERSION);
+ print_str("version", FFMPEG_VERSION);
+ print_fmt("copyright", "Copyright (c) %d-%d the FFmpeg developers",
+ ffprobe_program_birth_year, CONFIG_THIS_YEAR);
+ print_str("compiler_ident", CC_IDENT);
+ print_str("configuration", FFMPEG_CONFIGURATION);
+ writer_print_section_footer(w);
+
+ av_bprint_finalize(&pbuf, NULL);
+}
+
+#define SHOW_LIB_VERSION(libname, LIBNAME) \
+ do { \
+ if (CONFIG_##LIBNAME) { \
+ unsigned int version = libname##_version(); \
+ writer_print_section_header(w, SECTION_ID_LIBRARY_VERSION); \
+ print_str("name", "lib" #libname); \
+ print_int("major", LIB##LIBNAME##_VERSION_MAJOR); \
+ print_int("minor", LIB##LIBNAME##_VERSION_MINOR); \
+ print_int("micro", LIB##LIBNAME##_VERSION_MICRO); \
+ print_int("version", version); \
+ print_str("ident", LIB##LIBNAME##_IDENT); \
+ writer_print_section_footer(w); \
+ } \
+ } while (0)
+
+static void ffprobe_show_library_versions(WriterContext *w)
+{
+ writer_print_section_header(w, SECTION_ID_LIBRARY_VERSIONS);
+ SHOW_LIB_VERSION(avutil, AVUTIL);
+ SHOW_LIB_VERSION(avcodec, AVCODEC);
+ SHOW_LIB_VERSION(avformat, AVFORMAT);
+ SHOW_LIB_VERSION(avfilter, AVFILTER);
+ SHOW_LIB_VERSION(swscale, SWSCALE);
+ SHOW_LIB_VERSION(swresample, SWRESAMPLE);
+ writer_print_section_footer(w);
+}
+
+#define PRINT_PIX_FMT_FLAG(flagname, name) \
+ do { \
+ print_int(name, !!(pixdesc->flags & AV_PIX_FMT_FLAG_##flagname)); \
+ } while (0)
+
+static void ffprobe_show_pixel_formats(WriterContext *w)
+{
+ const AVPixFmtDescriptor *pixdesc = NULL;
+ int i, n;
+
+ writer_print_section_header(w, SECTION_ID_PIXEL_FORMATS);
+ while (pixdesc = av_pix_fmt_desc_next(pixdesc)) {
+ writer_print_section_header(w, SECTION_ID_PIXEL_FORMAT);
+ print_str("name", pixdesc->name);
+ print_int("nb_components", pixdesc->nb_components);
+ if ((pixdesc->nb_components >= 3) && !(pixdesc->flags & AV_PIX_FMT_FLAG_RGB)) {
+ print_int ("log2_chroma_w", pixdesc->log2_chroma_w);
+ print_int ("log2_chroma_h", pixdesc->log2_chroma_h);
+ } else {
+ print_str_opt("log2_chroma_w", "N/A");
+ print_str_opt("log2_chroma_h", "N/A");
+ }
+ n = av_get_bits_per_pixel(pixdesc);
+ if (n) print_int ("bits_per_pixel", n);
+ else print_str_opt("bits_per_pixel", "N/A");
+ if (do_show_pixel_format_flags) {
+ writer_print_section_header(w, SECTION_ID_PIXEL_FORMAT_FLAGS);
+ PRINT_PIX_FMT_FLAG(BE, "big_endian");
+ PRINT_PIX_FMT_FLAG(PAL, "palette");
+ PRINT_PIX_FMT_FLAG(BITSTREAM, "bitstream");
+ PRINT_PIX_FMT_FLAG(HWACCEL, "hwaccel");
+ PRINT_PIX_FMT_FLAG(PLANAR, "planar");
+ PRINT_PIX_FMT_FLAG(RGB, "rgb");
+ PRINT_PIX_FMT_FLAG(ALPHA, "alpha");
+ writer_print_section_footer(w);
+ }
+ if (do_show_pixel_format_components && (pixdesc->nb_components > 0)) {
+ writer_print_section_header(w, SECTION_ID_PIXEL_FORMAT_COMPONENTS);
+ for (i = 0; i < pixdesc->nb_components; i++) {
+ writer_print_section_header(w, SECTION_ID_PIXEL_FORMAT_COMPONENT);
+ print_int("index", i + 1);
+ print_int("bit_depth", pixdesc->comp[i].depth);
+ writer_print_section_footer(w);
+ }
+ writer_print_section_footer(w);
+ }
+ writer_print_section_footer(w);
+ }
+ writer_print_section_footer(w);
+}
+
+static int opt_show_optional_fields(void *optctx, const char *opt, const char *arg)
+{
+ if (!av_strcasecmp(arg, "always")) show_optional_fields = SHOW_OPTIONAL_FIELDS_ALWAYS;
+ else if (!av_strcasecmp(arg, "never")) show_optional_fields = SHOW_OPTIONAL_FIELDS_NEVER;
+ else if (!av_strcasecmp(arg, "auto")) show_optional_fields = SHOW_OPTIONAL_FIELDS_AUTO;
+
+ if (show_optional_fields == SHOW_OPTIONAL_FIELDS_AUTO && av_strcasecmp(arg, "auto"))
+ show_optional_fields = parse_number_or_die("show_optional_fields", arg, OPT_INT, SHOW_OPTIONAL_FIELDS_AUTO, SHOW_OPTIONAL_FIELDS_ALWAYS);
+ return 0;
+}
+
+static int opt_format(void *optctx, const char *opt, const char *arg)
+{
+ iformat = av_find_input_format(arg);
+ if (!iformat) {
+ av_log(NULL, AV_LOG_ERROR, "Unknown input format: %s\n", arg);
+ return AVERROR(EINVAL);
+ }
+ return 0;
+}
+
+static inline void mark_section_show_entries(SectionID section_id,
+ int show_all_entries, AVDictionary *entries)
+{
+ struct section *section = §ions[section_id];
+
+ section->show_all_entries = show_all_entries;
+ if (show_all_entries) {
+ SectionID *id;
+ for (id = section->children_ids; *id != -1; id++)
+ mark_section_show_entries(*id, show_all_entries, entries);
+ } else {
+ av_dict_copy(§ion->entries_to_show, entries, 0);
+ }
+}
+
+static int match_section(const char *section_name,
+ int show_all_entries, AVDictionary *entries)
+{
+ int i, ret = 0;
+
+ for (i = 0; i < FF_ARRAY_ELEMS(sections); i++) {
+ const struct section *section = §ions[i];
+ if (!strcmp(section_name, section->name) ||
+ (section->unique_name && !strcmp(section_name, section->unique_name))) {
+ av_log(NULL, AV_LOG_DEBUG,
+ "'%s' matches section with unique name '%s'\n", section_name,
+ (char *)av_x_if_null(section->unique_name, section->name));
+ ret++;
+ mark_section_show_entries(section->id, show_all_entries, entries);
+ }
+ }
+ return ret;
+}
+
+static int opt_show_entries(void *optctx, const char *opt, const char *arg)
+{
+ const char *p = arg;
+ int ret = 0;
+
+ while (*p) {
+ AVDictionary *entries = NULL;
+ char *section_name = av_get_token(&p, "=:");
+ int show_all_entries = 0;
+
+ if (!section_name) {
+ av_log(NULL, AV_LOG_ERROR,
+ "Missing section name for option '%s'\n", opt);
+ return AVERROR(EINVAL);
+ }
+
+ if (*p == '=') {
+ p++;
+ while (*p && *p != ':') {
+ char *entry = av_get_token(&p, ",:");
+ if (!entry)
+ break;
+ av_log(NULL, AV_LOG_VERBOSE,
+ "Adding '%s' to the entries to show in section '%s'\n",
+ entry, section_name);
+ av_dict_set(&entries, entry, "", AV_DICT_DONT_STRDUP_KEY);
+ if (*p == ',')
+ p++;
+ }
+ } else {
+ show_all_entries = 1;
+ }
+
+ ret = match_section(section_name, show_all_entries, entries);
+ if (ret == 0) {
+ av_log(NULL, AV_LOG_ERROR, "No match for section '%s'\n", section_name);
+ ret = AVERROR(EINVAL);
+ }
+ av_dict_free(&entries);
+ av_free(section_name);
+
+ if (ret <= 0)
+ break;
+ if (*p)
+ p++;
+ }
+
+ return ret;
+}
+
+static void opt_input_file(void *optctx, const char *arg)
+{
+ if (input_filename) {
+ av_log(NULL, AV_LOG_ERROR,
+ "Argument '%s' provided as input filename, but '%s' was already specified.\n",
+ arg, input_filename);
+ exit_program(1);
+ }
+ if (!strcmp(arg, "-"))
+ arg = "fd:";
+ input_filename = arg;
+}
+
+static int opt_input_file_i(void *optctx, const char *opt, const char *arg)
+{
+ opt_input_file(optctx, arg);
+ return 0;
+}
+
+static void opt_output_file(void *optctx, const char *arg)
+{
+ if (output_filename) {
+ av_log(NULL, AV_LOG_ERROR,
+ "Argument '%s' provided as output filename, but '%s' was already specified.\n",
+ arg, output_filename);
+ exit_program(1);
+ }
+ if (!strcmp(arg, "-"))
+ arg = "fd:";
+ output_filename = arg;
+}
+
+static int opt_output_file_o(void *optctx, const char *opt, const char *arg)
+{
+ opt_output_file(optctx, arg);
+ return 0;
+}
+
+static int opt_print_filename(void *optctx, const char *opt, const char *arg)
+{
+ print_input_filename = arg;
+ return 0;
+}
+
+void probe_show_help_default(const char *opt, const char *arg)
+{
+ av_log_set_callback(log_callback_help);
+ show_usage();
+ show_help_options(options, "Main options:", 0, 0, 0);
+ printf("\n");
+
+ show_help_children(avformat_get_class(), AV_OPT_FLAG_DECODING_PARAM);
+ show_help_children(avcodec_get_class(), AV_OPT_FLAG_DECODING_PARAM);
+}
+
+/**
+ * Parse interval specification, according to the format:
+ * INTERVAL ::= [START|+START_OFFSET][%[END|+END_OFFSET]]
+ * INTERVALS ::= INTERVAL[,INTERVALS]
+*/
+static int parse_read_interval(const char *interval_spec,
+ ReadInterval *interval)
+{
+ int ret = 0;
+ char *next, *p, *spec = av_strdup(interval_spec);
+ if (!spec)
+ return AVERROR(ENOMEM);
+
+ if (!*spec) {
+ av_log(NULL, AV_LOG_ERROR, "Invalid empty interval specification\n");
+ ret = AVERROR(EINVAL);
+ goto end;
+ }
+
+ p = spec;
+ next = strchr(spec, '%');
+ if (next)
+ *next++ = 0;
+
+ /* parse first part */
+ if (*p) {
+ interval->has_start = 1;
+
+ if (*p == '+') {
+ interval->start_is_offset = 1;
+ p++;
+ } else {
+ interval->start_is_offset = 0;
+ }
+
+ ret = av_parse_time(&interval->start, p, 1);
+ if (ret < 0) {
+ av_log(NULL, AV_LOG_ERROR, "Invalid interval start specification '%s'\n", p);
+ goto end;
+ }
+ } else {
+ interval->has_start = 0;
+ }
+
+ /* parse second part */
+ p = next;
+ if (p && *p) {
+ int64_t us;
+ interval->has_end = 1;
+
+ if (*p == '+') {
+ interval->end_is_offset = 1;
+ p++;
+ } else {
+ interval->end_is_offset = 0;
+ }
+
+ if (interval->end_is_offset && *p == '#') {
+ long long int lli;
+ char *tail;
+ interval->duration_frames = 1;
+ p++;
+ lli = strtoll(p, &tail, 10);
+ if (*tail || lli < 0) {
+ av_log(NULL, AV_LOG_ERROR,
+ "Invalid or negative value '%s' for duration number of frames\n", p);
+ goto end;
+ }
+ interval->end = lli;
+ } else {
+ interval->duration_frames = 0;
+ ret = av_parse_time(&us, p, 1);
+ if (ret < 0) {
+ av_log(NULL, AV_LOG_ERROR, "Invalid interval end/duration specification '%s'\n", p);
+ goto end;
+ }
+ interval->end = us;
+ }
+ } else {
+ interval->has_end = 0;
+ }
+
+end:
+ av_free(spec);
+ return ret;
+}
+
+static int parse_read_intervals(const char *intervals_spec)
+{
+ int ret, n, i;
+ char *p, *spec = av_strdup(intervals_spec);
+ if (!spec)
+ return AVERROR(ENOMEM);
+
+ /* preparse specification, get number of intervals */
+ for (n = 0, p = spec; *p; p++)
+ if (*p == ',')
+ n++;
+ n++;
+
+ read_intervals = av_malloc_array(n, sizeof(*read_intervals));
+ if (!read_intervals) {
+ ret = AVERROR(ENOMEM);
+ goto end;
+ }
+ read_intervals_nb = n;
+
+ /* parse intervals */
+ p = spec;
+ for (i = 0; p; i++) {
+ char *next;
+
+ av_assert0(i < read_intervals_nb);
+ next = strchr(p, ',');
+ if (next)
+ *next++ = 0;
+
+ read_intervals[i].id = i;
+ ret = parse_read_interval(p, &read_intervals[i]);
+ if (ret < 0) {
+ av_log(NULL, AV_LOG_ERROR, "Error parsing read interval #%d '%s'\n",
+ i, p);
+ goto end;
+ }
+ av_log(NULL, AV_LOG_VERBOSE, "Parsed log interval ");
+ log_read_interval(&read_intervals[i], NULL, AV_LOG_VERBOSE);
+ p = next;
+ }
+ av_assert0(i == read_intervals_nb);
+
+end:
+ av_free(spec);
+ return ret;
+}
+
+static int opt_read_intervals(void *optctx, const char *opt, const char *arg)
+{
+ return parse_read_intervals(arg);
+}
+
+static int opt_pretty(void *optctx, const char *opt, const char *arg)
+{
+ show_value_unit = 1;
+ use_value_prefix = 1;
+ use_byte_value_binary_prefix = 1;
+ use_value_sexagesimal_format = 1;
+ return 0;
+}
+
+static void print_section(SectionID id, int level)
+{
+ const SectionID *pid;
+ const struct section *section = §ions[id];
+ printf("%c%c%c",
+ section->flags & SECTION_FLAG_IS_WRAPPER ? 'W' : '.',
+ section->flags & SECTION_FLAG_IS_ARRAY ? 'A' : '.',
+ section->flags & SECTION_FLAG_HAS_VARIABLE_FIELDS ? 'V' : '.');
+ printf("%*c %s", level * 4, ' ', section->name);
+ if (section->unique_name)
+ printf("/%s", section->unique_name);
+ printf("\n");
+
+ for (pid = section->children_ids; *pid != -1; pid++)
+ print_section(*pid, level+1);
+}
+
+static int opt_sections(void *optctx, const char *opt, const char *arg)
+{
+ printf("Sections:\n"
+ "W.. = Section is a wrapper (contains other sections, no local entries)\n"
+ ".A. = Section contains an array of elements of the same type\n"
+ "..V = Section may contain a variable number of fields with variable keys\n"
+ "FLAGS NAME/UNIQUE_NAME\n"
+ "---\n");
+ print_section(SECTION_ID_ROOT, 0);
+ return 0;
+}
+
+static int opt_show_versions(void *optctx, const char *opt, const char *arg)
+{
+ mark_section_show_entries(SECTION_ID_PROGRAM_VERSION, 1, NULL);
+ mark_section_show_entries(SECTION_ID_LIBRARY_VERSION, 1, NULL);
+ return 0;
+}
+
+#define DEFINE_OPT_SHOW_SECTION(section, target_section_id) \
+ static int opt_show_##section(void *optctx, const char *opt, const char *arg) \
+ { \
+ mark_section_show_entries(SECTION_ID_##target_section_id, 1, NULL); \
+ return 0; \
+ }
+
+DEFINE_OPT_SHOW_SECTION(chapters, CHAPTERS)
+DEFINE_OPT_SHOW_SECTION(error, ERROR)
+DEFINE_OPT_SHOW_SECTION(format, FORMAT)
+DEFINE_OPT_SHOW_SECTION(frames, FRAMES)
+DEFINE_OPT_SHOW_SECTION(library_versions, LIBRARY_VERSIONS)
+DEFINE_OPT_SHOW_SECTION(packets, PACKETS)
+DEFINE_OPT_SHOW_SECTION(pixel_formats, PIXEL_FORMATS)
+DEFINE_OPT_SHOW_SECTION(program_version, PROGRAM_VERSION)
+DEFINE_OPT_SHOW_SECTION(streams, STREAMS)
+DEFINE_OPT_SHOW_SECTION(programs, PROGRAMS)
+
+static const OptionDef real_options[] = {
+ CMDUTILS_COMMON_OPTIONS
+ { "f", HAS_ARG, {.func_arg = opt_format}, "force format", "format" },
+ { "unit", OPT_BOOL, {&show_value_unit}, "show unit of the displayed values" },
+ { "prefix", OPT_BOOL, {&use_value_prefix}, "use SI prefixes for the displayed values" },
+ { "byte_binary_prefix", OPT_BOOL, {&use_byte_value_binary_prefix},
+ "use binary prefixes for byte units" },
+ { "sexagesimal", OPT_BOOL, {&use_value_sexagesimal_format},
+ "use sexagesimal format HOURS:MM:SS.MICROSECONDS for time units" },
+ { "pretty", 0, {.func_arg = opt_pretty},
+ "prettify the format of displayed values, make it more human readable" },
+ { "print_format", OPT_STRING | HAS_ARG, { &print_format },
+ "set the output printing format (available formats are: default, compact, csv, flat, ini, json, xml)", "format" },
+ { "of", OPT_STRING | HAS_ARG, { &print_format }, "alias for -print_format", "format" },
+ { "select_streams", OPT_STRING | HAS_ARG, { &stream_specifier }, "select the specified streams", "stream_specifier" },
+ { "sections", OPT_EXIT, {.func_arg = opt_sections}, "print sections structure and section information, and exit" },
+ { "show_data", OPT_BOOL, { &do_show_data }, "show packets data" },
+ { "show_data_hash", OPT_STRING | HAS_ARG, { &show_data_hash }, "show packets data hash" },
+ { "show_error", 0, { .func_arg = &opt_show_error }, "show probing error" },
+ { "show_format", 0, { .func_arg = &opt_show_format }, "show format/container info" },
+ { "show_frames", 0, { .func_arg = &opt_show_frames }, "show frames info" },
+ { "show_entries", HAS_ARG, {.func_arg = opt_show_entries},
+ "show a set of specified entries", "entry_list" },
+#if HAVE_THREADS
+ { "show_log", OPT_INT|HAS_ARG, { &do_show_log }, "show log" },
+#endif
+ { "show_packets", 0, { .func_arg = &opt_show_packets }, "show packets info" },
+ { "show_programs", 0, { .func_arg = &opt_show_programs }, "show programs info" },
+ { "show_streams", 0, { .func_arg = &opt_show_streams }, "show streams info" },
+ { "show_chapters", 0, { .func_arg = &opt_show_chapters }, "show chapters info" },
+ { "count_frames", OPT_BOOL, { &do_count_frames }, "count the number of frames per stream" },
+ { "count_packets", OPT_BOOL, { &do_count_packets }, "count the number of packets per stream" },
+ { "show_program_version", 0, { .func_arg = &opt_show_program_version }, "show ffprobe version" },
+ { "show_library_versions", 0, { .func_arg = &opt_show_library_versions }, "show library versions" },
+ { "show_versions", 0, { .func_arg = &opt_show_versions }, "show program and library versions" },
+ { "show_pixel_formats", 0, { .func_arg = &opt_show_pixel_formats }, "show pixel format descriptions" },
+ { "show_optional_fields", HAS_ARG, { .func_arg = &opt_show_optional_fields }, "show optional fields" },
+ { "show_private_data", OPT_BOOL, { &show_private_data }, "show private data" },
+ { "private", OPT_BOOL, { &show_private_data }, "same as show_private_data" },
+ { "bitexact", OPT_BOOL, {&do_bitexact}, "force bitexact output" },
+ { "read_intervals", HAS_ARG, {.func_arg = opt_read_intervals}, "set read intervals", "read_intervals" },
+ { "i", HAS_ARG, {.func_arg = opt_input_file_i}, "read specified file", "input_file"},
+ { "o", HAS_ARG, {.func_arg = opt_output_file_o}, "write to specified output", "output_file"},
+ { "print_filename", HAS_ARG, {.func_arg = opt_print_filename}, "override the printed input filename", "print_file"},
+ { "find_stream_info", OPT_BOOL | OPT_INPUT | OPT_EXPERT, { &find_stream_info },
+ "read and decode the streams to fill missing information with heuristics" },
+ { NULL, },
+};
+
+static inline int check_section_show_entries(int section_id)
+{
+ int *id;
+ struct section *section = §ions[section_id];
+ if (sections[section_id].show_all_entries || sections[section_id].entries_to_show)
+ return 1;
+ for (id = section->children_ids; *id != -1; id++)
+ if (check_section_show_entries(*id))
+ return 1;
+ return 0;
+}
+
+#define SET_DO_SHOW(id, varname) do { \
+ if (check_section_show_entries(SECTION_ID_##id)) \
+ do_show_##varname = 1; \
+ } while (0)
+
+char* ffprobe_run(int argc, char **argv)
+{
+ const Writer *w;
+ WriterContext *wctx;
+ char *buf;
+ char *w_name = NULL, *w_args = NULL;
+ int ret, input_ret, i;
+
+ buffer_length = 0;
+ if(print_buffer == NULL) {
+ print_buffer = av_malloc(sizeof(char) * buffer_size);
+ }
+ memset(print_buffer, '\0', (size_t) buffer_size);
+
+ if (setjmp(jump_buf)) {
+ ret = 1;
+ goto end;
+ }
+
+ init_dynload();
+
+#if HAVE_THREADS
+ ret = pthread_mutex_init(&log_mutex, NULL);
+ if (ret != 0) {
+ goto end;
+ }
+#endif
+ av_log_set_flags(AV_LOG_SKIP_REPEATED);
+
+ options = real_options;
+ parse_loglevel(argc, argv, options);
+ avformat_network_init();
+#if CONFIG_AVDEVICE
+ avdevice_register_all();
+#endif
+
+ show_banner(argc, argv, options);
+ parse_options(NULL, argc, argv, options, opt_input_file);
+
+ if (do_show_log)
+ av_log_set_callback(log_callback);
+
+ /* mark things to show, based on -show_entries */
+ SET_DO_SHOW(CHAPTERS, chapters);
+ SET_DO_SHOW(ERROR, error);
+ SET_DO_SHOW(FORMAT, format);
+ SET_DO_SHOW(FRAMES, frames);
+ SET_DO_SHOW(LIBRARY_VERSIONS, library_versions);
+ SET_DO_SHOW(PACKETS, packets);
+ SET_DO_SHOW(PIXEL_FORMATS, pixel_formats);
+ SET_DO_SHOW(PIXEL_FORMAT_FLAGS, pixel_format_flags);
+ SET_DO_SHOW(PIXEL_FORMAT_COMPONENTS, pixel_format_components);
+ SET_DO_SHOW(PROGRAM_VERSION, program_version);
+ SET_DO_SHOW(PROGRAMS, programs);
+ SET_DO_SHOW(STREAMS, streams);
+ SET_DO_SHOW(STREAM_DISPOSITION, stream_disposition);
+ SET_DO_SHOW(PROGRAM_STREAM_DISPOSITION, stream_disposition);
+
+ SET_DO_SHOW(CHAPTER_TAGS, chapter_tags);
+ SET_DO_SHOW(FORMAT_TAGS, format_tags);
+ SET_DO_SHOW(FRAME_TAGS, frame_tags);
+ SET_DO_SHOW(PROGRAM_TAGS, program_tags);
+ SET_DO_SHOW(STREAM_TAGS, stream_tags);
+ SET_DO_SHOW(PROGRAM_STREAM_TAGS, stream_tags);
+ SET_DO_SHOW(PACKET_TAGS, packet_tags);
+
+ if (do_bitexact && (do_show_program_version || do_show_library_versions)) {
+ av_log(NULL, AV_LOG_ERROR,
+ "-bitexact and -show_program_version or -show_library_versions "
+ "options are incompatible\n");
+ ret = AVERROR(EINVAL);
+ goto end;
+ }
+
+ writer_register_all();
+
+ if (!print_format)
+ print_format = av_strdup("default");
+ if (!print_format) {
+ ret = AVERROR(ENOMEM);
+ goto end;
+ }
+ w_name = av_strtok(print_format, "=", &buf);
+ if (!w_name) {
+ av_log(NULL, AV_LOG_ERROR,
+ "No name specified for the output format\n");
+ ret = AVERROR(EINVAL);
+ goto end;
+ }
+ w_args = buf;
+
+ if (show_data_hash) {
+ if ((ret = av_hash_alloc(&hash, show_data_hash)) < 0) {
+ if (ret == AVERROR(EINVAL)) {
+ const char *n;
+ av_log(NULL, AV_LOG_ERROR,
+ "Unknown hash algorithm '%s'\nKnown algorithms:",
+ show_data_hash);
+ for (i = 0; (n = av_hash_names(i)); i++)
+ av_log(NULL, AV_LOG_ERROR, " %s", n);
+ av_log(NULL, AV_LOG_ERROR, "\n");
+ }
+ goto end;
+ }
+ }
+
+ w = writer_get_by_name(w_name);
+ if (!w) {
+ av_log(NULL, AV_LOG_ERROR, "Unknown output format with name '%s'\n", w_name);
+ ret = AVERROR(EINVAL);
+ goto end;
+ }
+
+ if ((ret = writer_open(&wctx, w, w_args,
+ sections, FF_ARRAY_ELEMS(sections), output_filename)) >= 0) {
+ if (w == &xml_writer)
+ wctx->string_validation_utf8_flags |= AV_UTF8_FLAG_EXCLUDE_XML_INVALID_CONTROL_CODES;
+
+ writer_print_section_header(wctx, SECTION_ID_ROOT);
+
+ if (do_show_program_version)
+ ffprobe_show_program_version(wctx);
+ if (do_show_library_versions)
+ ffprobe_show_library_versions(wctx);
+ if (do_show_pixel_formats)
+ ffprobe_show_pixel_formats(wctx);
+
+ if (!input_filename &&
+ ((do_show_format || do_show_programs || do_show_streams || do_show_chapters || do_show_packets || do_show_error) ||
+ (!do_show_program_version && !do_show_library_versions && !do_show_pixel_formats))) {
+ show_usage();
+ av_log(NULL, AV_LOG_ERROR, "You have to specify one input file.\n");
+ av_log(NULL, AV_LOG_ERROR, "Use -h to get full help or, even better, run 'man %s'.\n", ffprobe_program_name);
+ ret = AVERROR(EINVAL);
+ } else if (input_filename) {
+ ret = probe_file(wctx, input_filename, print_input_filename);
+ if (ret < 0 && do_show_error)
+ show_error(wctx, ret);
+ }
+
+ input_ret = ret;
+
+ writer_print_section_footer(wctx);
+ ret = writer_close(&wctx);
+ if (ret < 0)
+ av_log(NULL, AV_LOG_ERROR, "Writing output failed: %s\n", av_err2str(ret));
+
+ ret = FFMIN(ret, input_ret);
+ }
+
+end:
+ av_freep(&print_format);
+ av_freep(&read_intervals);
+ av_hash_freep(&hash);
+
+ uninit_opts();
+ for (i = 0; i < FF_ARRAY_ELEMS(sections); i++)
+ av_dict_free(&(sections[i].entries_to_show));
+
+ avformat_network_deinit();
+ ffprobe_cleanup(ret);
+
+ return print_buffer;
+}
diff --git a/app/src/main/cpp/ffmpeg/ffprobe.h b/app/src/main/cpp/ffmpeg/ffprobe.h
new file mode 100644
index 00000000..1f660192
--- /dev/null
+++ b/app/src/main/cpp/ffmpeg/ffprobe.h
@@ -0,0 +1,12 @@
+//
+// Created by frank on 2020-01-06.
+//
+
+#ifndef FFMPEGANDROID_FFPROBE_H
+#define FFMPEGANDROID_FFPROBE_H
+
+char* ffprobe_run(int argc, char **argv);
+
+void frank_printf_json(char *fmt, ...);
+
+#endif //FFMPEGANDROID_FFPROBE_H
diff --git a/app/src/main/cpp/ffmpeg/fopen_utf8.h b/app/src/main/cpp/ffmpeg/fopen_utf8.h
new file mode 100644
index 00000000..e5be8417
--- /dev/null
+++ b/app/src/main/cpp/ffmpeg/fopen_utf8.h
@@ -0,0 +1,71 @@
+/*
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef FFTOOLS_FOPEN_UTF8_H
+#define FFTOOLS_FOPEN_UTF8_H
+
+#include
+
+/* The fopen_utf8 function here is essentially equivalent to avpriv_fopen_utf8,
+ * except that it doesn't set O_CLOEXEC, and that it isn't exported
+ * from a different library. (On Windows, each DLL might use a different
+ * CRT, and FILE* handles can't be shared across them.) */
+
+#ifdef _WIN32
+#include "libavutil/wchar_filename.h"
+
+static inline FILE *fopen_utf8(const char *path_utf8, const char *mode)
+{
+ wchar_t *path_w, *mode_w;
+ FILE *f;
+
+ /* convert UTF-8 to wide chars */
+ if (get_extended_win32_path(path_utf8, &path_w)) /* This sets errno on error. */
+ return NULL;
+ if (!path_w)
+ goto fallback;
+
+ if (utf8towchar(mode, &mode_w))
+ return NULL;
+ if (!mode_w) {
+ /* If failing to interpret the mode string as utf8, it is an invalid
+ * parameter. */
+ av_freep(&path_w);
+ errno = EINVAL;
+ return NULL;
+ }
+
+ f = _wfopen(path_w, mode_w);
+ av_freep(&path_w);
+ av_freep(&mode_w);
+
+ return f;
+fallback:
+ /* path may be in CP_ACP */
+ return fopen(path_utf8, mode);
+}
+
+#else
+
+static inline FILE *fopen_utf8(const char *path, const char *mode)
+{
+ return fopen(path, mode);
+}
+#endif
+
+#endif /* FFTOOLS_FOPEN_UTF8_H */
diff --git a/app/src/main/cpp/ffmpeg/objpool.c b/app/src/main/cpp/ffmpeg/objpool.c
new file mode 100644
index 00000000..87237cf7
--- /dev/null
+++ b/app/src/main/cpp/ffmpeg/objpool.c
@@ -0,0 +1,131 @@
+/*
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include
+
+#include "libavcodec/packet.h"
+
+#include "libavutil/common.h"
+#include "libavutil/error.h"
+#include "libavutil/frame.h"
+#include "libavutil/mem.h"
+
+#include "objpool.h"
+
+struct ObjPool {
+ void *pool[32];
+ unsigned int pool_count;
+
+ ObjPoolCBAlloc alloc;
+ ObjPoolCBReset reset;
+ ObjPoolCBFree free;
+};
+
+ObjPool *objpool_alloc(ObjPoolCBAlloc cb_alloc, ObjPoolCBReset cb_reset,
+ ObjPoolCBFree cb_free)
+{
+ ObjPool *op = av_mallocz(sizeof(*op));
+
+ if (!op)
+ return NULL;
+
+ op->alloc = cb_alloc;
+ op->reset = cb_reset;
+ op->free = cb_free;
+
+ return op;
+}
+
+void objpool_free(ObjPool **pop)
+{
+ ObjPool *op = *pop;
+
+ if (!op)
+ return;
+
+ for (unsigned int i = 0; i < op->pool_count; i++)
+ op->free(&op->pool[i]);
+
+ av_freep(pop);
+}
+
+int objpool_get(ObjPool *op, void **obj)
+{
+ if (op->pool_count) {
+ *obj = op->pool[--op->pool_count];
+ op->pool[op->pool_count] = NULL;
+ } else
+ *obj = op->alloc();
+
+ return *obj ? 0 : AVERROR(ENOMEM);
+}
+
+void objpool_release(ObjPool *op, void **obj)
+{
+ if (!*obj)
+ return;
+
+ op->reset(*obj);
+
+ if (op->pool_count < FF_ARRAY_ELEMS(op->pool))
+ op->pool[op->pool_count++] = *obj;
+ else
+ op->free(obj);
+
+ *obj = NULL;
+}
+
+static void *alloc_packet(void)
+{
+ return av_packet_alloc();
+}
+static void *alloc_frame(void)
+{
+ return av_frame_alloc();
+}
+
+static void reset_packet(void *obj)
+{
+ av_packet_unref(obj);
+}
+static void reset_frame(void *obj)
+{
+ av_frame_unref(obj);
+}
+
+static void free_packet(void **obj)
+{
+ AVPacket *pkt = *obj;
+ av_packet_free(&pkt);
+ *obj = NULL;
+}
+static void free_frame(void **obj)
+{
+ AVFrame *frame = *obj;
+ av_frame_free(&frame);
+ *obj = NULL;
+}
+
+ObjPool *objpool_alloc_packets(void)
+{
+ return objpool_alloc(alloc_packet, reset_packet, free_packet);
+}
+ObjPool *objpool_alloc_frames(void)
+{
+ return objpool_alloc(alloc_frame, reset_frame, free_frame);
+}
diff --git a/app/src/main/cpp/ffmpeg/objpool.h b/app/src/main/cpp/ffmpeg/objpool.h
new file mode 100644
index 00000000..1b2aea6a
--- /dev/null
+++ b/app/src/main/cpp/ffmpeg/objpool.h
@@ -0,0 +1,37 @@
+/*
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef FFTOOLS_OBJPOOL_H
+#define FFTOOLS_OBJPOOL_H
+
+typedef struct ObjPool ObjPool;
+
+typedef void* (*ObjPoolCBAlloc)(void);
+typedef void (*ObjPoolCBReset)(void *);
+typedef void (*ObjPoolCBFree)(void **);
+
+void objpool_free(ObjPool **op);
+ObjPool *objpool_alloc(ObjPoolCBAlloc cb_alloc, ObjPoolCBReset cb_reset,
+ ObjPoolCBFree cb_free);
+ObjPool *objpool_alloc_packets(void);
+ObjPool *objpool_alloc_frames(void);
+
+int objpool_get(ObjPool *op, void **obj);
+void objpool_release(ObjPool *op, void **obj);
+
+#endif // FFTOOLS_OBJPOOL_H
diff --git a/app/src/main/cpp/ffmpeg/opt_common.c b/app/src/main/cpp/ffmpeg/opt_common.c
new file mode 100644
index 00000000..54c21e4d
--- /dev/null
+++ b/app/src/main/cpp/ffmpeg/opt_common.c
@@ -0,0 +1,1459 @@
+/*
+ * Option handlers shared between the tools.
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "config.h"
+
+#include
+
+#include "cmdutils.h"
+#include "opt_common.h"
+
+#include "libavutil/avassert.h"
+#include "libavutil/avstring.h"
+#include "libavutil/bprint.h"
+#include "libavutil/channel_layout.h"
+#include "libavutil/cpu.h"
+#include "libavutil/dict.h"
+#include "libavutil/error.h"
+#include "libavutil/ffversion.h"
+#include "libavutil/log.h"
+#include "libavutil/mem.h"
+#include "libavutil/opt.h"
+#include "libavutil/parseutils.h"
+#include "libavutil/pixdesc.h"
+#include "libavutil/version.h"
+
+#include "libavcodec/avcodec.h"
+#include "libavcodec/bsf.h"
+#include "libavcodec/codec.h"
+#include "libavcodec/codec_desc.h"
+#include "libavcodec/version.h"
+
+#include "libavformat/avformat.h"
+#include "libavformat/version.h"
+
+#include "libavfilter/avfilter.h"
+#include "libavfilter/version.h"
+
+#include "libswscale/swscale.h"
+#include "libswscale/version.h"
+
+#include "libswresample/swresample.h"
+#include "libswresample/version.h"
+
+enum show_muxdemuxers {
+ SHOW_DEFAULT,
+ SHOW_DEMUXERS,
+ SHOW_MUXERS,
+};
+
+static FILE *report_file;
+static int report_file_level = AV_LOG_DEBUG;
+
+int show_license(void *optctx, const char *opt, const char *arg)
+{
+#if CONFIG_NONFREE
+ printf(
+ "This version of %s has nonfree parts compiled in.\n"
+ "Therefore it is not legally redistributable.\n",
+ program_name );
+#elif CONFIG_GPLV3
+ printf(
+ "%s is free software; you can redistribute it and/or modify\n"
+ "it under the terms of the GNU General Public License as published by\n"
+ "the Free Software Foundation; either version 3 of the License, or\n"
+ "(at your option) any later version.\n"
+ "\n"
+ "%s is distributed in the hope that it will be useful,\n"
+ "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
+ "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
+ "GNU General Public License for more details.\n"
+ "\n"
+ "You should have received a copy of the GNU General Public License\n"
+ "along with %s. If not, see .\n",
+ program_name, program_name, program_name );
+#elif CONFIG_GPL
+ printf(
+ "%s is free software; you can redistribute it and/or modify\n"
+ "it under the terms of the GNU General Public License as published by\n"
+ "the Free Software Foundation; either version 2 of the License, or\n"
+ "(at your option) any later version.\n"
+ "\n"
+ "%s is distributed in the hope that it will be useful,\n"
+ "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
+ "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
+ "GNU General Public License for more details.\n"
+ "\n"
+ "You should have received a copy of the GNU General Public License\n"
+ "along with %s; if not, write to the Free Software\n"
+ "Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n",
+ program_name, program_name, program_name );
+#elif CONFIG_LGPLV3
+ printf(
+ "%s is free software; you can redistribute it and/or modify\n"
+ "it under the terms of the GNU Lesser General Public License as published by\n"
+ "the Free Software Foundation; either version 3 of the License, or\n"
+ "(at your option) any later version.\n"
+ "\n"
+ "%s is distributed in the hope that it will be useful,\n"
+ "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
+ "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
+ "GNU Lesser General Public License for more details.\n"
+ "\n"
+ "You should have received a copy of the GNU Lesser General Public License\n"
+ "along with %s. If not, see .\n",
+ program_name, program_name, program_name );
+#else
+ printf(
+ "%s is free software; you can redistribute it and/or\n"
+ "modify it under the terms of the GNU Lesser General Public\n"
+ "License as published by the Free Software Foundation; either\n"
+ "version 2.1 of the License, or (at your option) any later version.\n"
+ "\n"
+ "%s is distributed in the hope that it will be useful,\n"
+ "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
+ "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\n"
+ "Lesser General Public License for more details.\n"
+ "\n"
+ "You should have received a copy of the GNU Lesser General Public\n"
+ "License along with %s; if not, write to the Free Software\n"
+ "Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n",
+ program_name, program_name, program_name );
+#endif
+
+ return 0;
+}
+
+static int warned_cfg = 0;
+
+#define INDENT 1
+#define SHOW_VERSION 2
+#define SHOW_CONFIG 4
+#define SHOW_COPYRIGHT 8
+
+#define PRINT_LIB_INFO(libname, LIBNAME, flags, level) \
+ if (CONFIG_##LIBNAME) { \
+ const char *indent = flags & INDENT? " " : ""; \
+ if (flags & SHOW_VERSION) { \
+ unsigned int version = libname##_version(); \
+ av_log(NULL, level, \
+ "%slib%-11s %2d.%3d.%3d / %2d.%3d.%3d\n", \
+ indent, #libname, \
+ LIB##LIBNAME##_VERSION_MAJOR, \
+ LIB##LIBNAME##_VERSION_MINOR, \
+ LIB##LIBNAME##_VERSION_MICRO, \
+ AV_VERSION_MAJOR(version), AV_VERSION_MINOR(version),\
+ AV_VERSION_MICRO(version)); \
+ } \
+ if (flags & SHOW_CONFIG) { \
+ const char *cfg = libname##_configuration(); \
+ if (strcmp(FFMPEG_CONFIGURATION, cfg)) { \
+ if (!warned_cfg) { \
+ av_log(NULL, level, \
+ "%sWARNING: library configuration mismatch\n", \
+ indent); \
+ warned_cfg = 1; \
+ } \
+ av_log(NULL, level, "%s%-11s configuration: %s\n", \
+ indent, #libname, cfg); \
+ } \
+ } \
+ } \
+
+static void print_all_libs_info(int flags, int level)
+{
+ PRINT_LIB_INFO(avutil, AVUTIL, flags, level)
+ PRINT_LIB_INFO(avcodec, AVCODEC, flags, level)
+ PRINT_LIB_INFO(avformat, AVFORMAT, flags, level)
+ PRINT_LIB_INFO(avfilter, AVFILTER, flags, level)
+ PRINT_LIB_INFO(swscale, SWSCALE, flags, level)
+ PRINT_LIB_INFO(swresample, SWRESAMPLE, flags, level)
+}
+
+static void print_program_info(int flags, int level)
+{
+ const char *indent = flags & INDENT? " " : "";
+
+ av_log(NULL, level, "%s version " FFMPEG_VERSION, program_name);
+ if (flags & SHOW_COPYRIGHT)
+ av_log(NULL, level, " Copyright (c) %d-%d the FFmpeg developers",
+ program_birth_year, CONFIG_THIS_YEAR);
+ av_log(NULL, level, "\n");
+ av_log(NULL, level, "%sbuilt with %s\n", indent, CC_IDENT);
+
+ av_log(NULL, level, "%sconfiguration: " FFMPEG_CONFIGURATION "\n", indent);
+}
+
+static void print_buildconf(int flags, int level)
+{
+ const char *indent = flags & INDENT ? " " : "";
+ char str[] = { FFMPEG_CONFIGURATION };
+ char *conflist, *remove_tilde, *splitconf;
+
+ // Change all the ' --' strings to '~--' so that
+ // they can be identified as tokens.
+ while ((conflist = strstr(str, " --")) != NULL) {
+ conflist[0] = '~';
+ }
+
+ // Compensate for the weirdness this would cause
+ // when passing 'pkg-config --static'.
+ while ((remove_tilde = strstr(str, "pkg-config~")) != NULL) {
+ remove_tilde[sizeof("pkg-config~") - 2] = ' ';
+ }
+
+ splitconf = strtok(str, "~");
+ av_log(NULL, level, "\n%sconfiguration:\n", indent);
+ while (splitconf != NULL) {
+ av_log(NULL, level, "%s%s%s\n", indent, indent, splitconf);
+ splitconf = strtok(NULL, "~");
+ }
+}
+
+void show_banner(int argc, char **argv, const OptionDef *options)
+{
+ int idx = locate_option(argc, argv, options, "version");
+ if (hide_banner || idx)
+ return;
+
+ print_program_info (INDENT|SHOW_COPYRIGHT, AV_LOG_INFO);
+ print_all_libs_info(INDENT|SHOW_CONFIG, AV_LOG_INFO);
+ print_all_libs_info(INDENT|SHOW_VERSION, AV_LOG_INFO);
+}
+
+int show_version(void *optctx, const char *opt, const char *arg)
+{
+ av_log_set_callback(log_callback_help);
+ print_program_info (SHOW_COPYRIGHT, AV_LOG_INFO);
+ print_all_libs_info(SHOW_VERSION, AV_LOG_INFO);
+
+ return 0;
+}
+
+int show_buildconf(void *optctx, const char *opt, const char *arg)
+{
+ av_log_set_callback(log_callback_help);
+ print_buildconf (INDENT|0, AV_LOG_INFO);
+
+ return 0;
+}
+
+#define PRINT_CODEC_SUPPORTED(codec, field, type, list_name, term, get_name) \
+ if (codec->field) { \
+ const type *p = codec->field; \
+ \
+ printf(" Supported " list_name ":"); \
+ while (*p != term) { \
+ get_name(*p); \
+ printf(" %s", name); \
+ p++; \
+ } \
+ printf("\n"); \
+ } \
+
+static void print_codec(const AVCodec *c)
+{
+ int encoder = av_codec_is_encoder(c);
+
+ printf("%s %s [%s]:\n", encoder ? "Encoder" : "Decoder", c->name,
+ c->long_name ? c->long_name : "");
+
+ printf(" General capabilities: ");
+ if (c->capabilities & AV_CODEC_CAP_DRAW_HORIZ_BAND)
+ printf("horizband ");
+ if (c->capabilities & AV_CODEC_CAP_DR1)
+ printf("dr1 ");
+ if (c->capabilities & AV_CODEC_CAP_DELAY)
+ printf("delay ");
+ if (c->capabilities & AV_CODEC_CAP_SMALL_LAST_FRAME)
+ printf("small ");
+ if (c->capabilities & AV_CODEC_CAP_SUBFRAMES)
+ printf("subframes ");
+ if (c->capabilities & AV_CODEC_CAP_EXPERIMENTAL)
+ printf("exp ");
+ if (c->capabilities & AV_CODEC_CAP_CHANNEL_CONF)
+ printf("chconf ");
+ if (c->capabilities & AV_CODEC_CAP_PARAM_CHANGE)
+ printf("paramchange ");
+ if (c->capabilities & AV_CODEC_CAP_VARIABLE_FRAME_SIZE)
+ printf("variable ");
+ if (c->capabilities & (AV_CODEC_CAP_FRAME_THREADS |
+ AV_CODEC_CAP_SLICE_THREADS |
+ AV_CODEC_CAP_OTHER_THREADS))
+ printf("threads ");
+ if (c->capabilities & AV_CODEC_CAP_AVOID_PROBING)
+ printf("avoidprobe ");
+ if (c->capabilities & AV_CODEC_CAP_HARDWARE)
+ printf("hardware ");
+ if (c->capabilities & AV_CODEC_CAP_HYBRID)
+ printf("hybrid ");
+ if (!c->capabilities)
+ printf("none");
+ printf("\n");
+
+ if (c->type == AVMEDIA_TYPE_VIDEO ||
+ c->type == AVMEDIA_TYPE_AUDIO) {
+ printf(" Threading capabilities: ");
+ switch (c->capabilities & (AV_CODEC_CAP_FRAME_THREADS |
+ AV_CODEC_CAP_SLICE_THREADS |
+ AV_CODEC_CAP_OTHER_THREADS)) {
+ case AV_CODEC_CAP_FRAME_THREADS |
+ AV_CODEC_CAP_SLICE_THREADS: printf("frame and slice"); break;
+ case AV_CODEC_CAP_FRAME_THREADS: printf("frame"); break;
+ case AV_CODEC_CAP_SLICE_THREADS: printf("slice"); break;
+ case AV_CODEC_CAP_OTHER_THREADS: printf("other"); break;
+ default: printf("none"); break;
+ }
+ printf("\n");
+ }
+
+ if (avcodec_get_hw_config(c, 0)) {
+ printf(" Supported hardware devices: ");
+ for (int i = 0;; i++) {
+ const AVCodecHWConfig *config = avcodec_get_hw_config(c, i);
+ const char *name;
+ if (!config)
+ break;
+ name = av_hwdevice_get_type_name(config->device_type);
+ if (name)
+ printf("%s ", name);
+ }
+ printf("\n");
+ }
+
+ if (c->supported_framerates) {
+ const AVRational *fps = c->supported_framerates;
+
+ printf(" Supported framerates:");
+ while (fps->num) {
+ printf(" %d/%d", fps->num, fps->den);
+ fps++;
+ }
+ printf("\n");
+ }
+ PRINT_CODEC_SUPPORTED(c, pix_fmts, enum AVPixelFormat, "pixel formats",
+ AV_PIX_FMT_NONE, GET_PIX_FMT_NAME);
+ PRINT_CODEC_SUPPORTED(c, supported_samplerates, int, "sample rates", 0,
+ GET_SAMPLE_RATE_NAME);
+ PRINT_CODEC_SUPPORTED(c, sample_fmts, enum AVSampleFormat, "sample formats",
+ AV_SAMPLE_FMT_NONE, GET_SAMPLE_FMT_NAME);
+
+ if (c->ch_layouts) {
+ const AVChannelLayout *p = c->ch_layouts;
+
+ printf(" Supported channel layouts:");
+ while (p->nb_channels) {
+ char name[128];
+ av_channel_layout_describe(p, name, sizeof(name));
+ printf(" %s", name);
+ p++;
+ }
+ printf("\n");
+ }
+
+ if (c->priv_class) {
+ show_help_children(c->priv_class,
+ AV_OPT_FLAG_ENCODING_PARAM |
+ AV_OPT_FLAG_DECODING_PARAM);
+ }
+}
+
+static const AVCodec *next_codec_for_id(enum AVCodecID id, void **iter,
+ int encoder)
+{
+ const AVCodec *c;
+ while ((c = av_codec_iterate(iter))) {
+ if (c->id == id &&
+ (encoder ? av_codec_is_encoder(c) : av_codec_is_decoder(c)))
+ return c;
+ }
+ return NULL;
+}
+
+static void show_help_codec(const char *name, int encoder)
+{
+ const AVCodecDescriptor *desc;
+ const AVCodec *codec;
+
+ if (!name) {
+ av_log(NULL, AV_LOG_ERROR, "No codec name specified.\n");
+ return;
+ }
+
+ codec = encoder ? avcodec_find_encoder_by_name(name) :
+ avcodec_find_decoder_by_name(name);
+
+ if (codec)
+ print_codec(codec);
+ else if ((desc = avcodec_descriptor_get_by_name(name))) {
+ void *iter = NULL;
+ int printed = 0;
+
+ while ((codec = next_codec_for_id(desc->id, &iter, encoder))) {
+ printed = 1;
+ print_codec(codec);
+ }
+
+ if (!printed) {
+ av_log(NULL, AV_LOG_ERROR, "Codec '%s' is known to FFmpeg, "
+ "but no %s for it are available. FFmpeg might need to be "
+ "recompiled with additional external libraries.\n",
+ name, encoder ? "encoders" : "decoders");
+ }
+ } else {
+ av_log(NULL, AV_LOG_ERROR, "Codec '%s' is not recognized by FFmpeg.\n",
+ name);
+ }
+}
+
+static void show_help_demuxer(const char *name)
+{
+ const AVInputFormat *fmt = av_find_input_format(name);
+
+ if (!fmt) {
+ av_log(NULL, AV_LOG_ERROR, "Unknown format '%s'.\n", name);
+ return;
+ }
+
+ printf("Demuxer %s [%s]:\n", fmt->name, fmt->long_name);
+
+ if (fmt->extensions)
+ printf(" Common extensions: %s.\n", fmt->extensions);
+
+ if (fmt->priv_class)
+ show_help_children(fmt->priv_class, AV_OPT_FLAG_DECODING_PARAM);
+}
+
+static void show_help_protocol(const char *name)
+{
+ const AVClass *proto_class;
+
+ if (!name) {
+ av_log(NULL, AV_LOG_ERROR, "No protocol name specified.\n");
+ return;
+ }
+
+ proto_class = avio_protocol_get_class(name);
+ if (!proto_class) {
+ av_log(NULL, AV_LOG_ERROR, "Unknown protocol '%s'.\n", name);
+ return;
+ }
+
+ show_help_children(proto_class, AV_OPT_FLAG_DECODING_PARAM | AV_OPT_FLAG_ENCODING_PARAM);
+}
+
+static void show_help_muxer(const char *name)
+{
+ const AVCodecDescriptor *desc;
+ const AVOutputFormat *fmt = av_guess_format(name, NULL, NULL);
+
+ if (!fmt) {
+ av_log(NULL, AV_LOG_ERROR, "Unknown format '%s'.\n", name);
+ return;
+ }
+
+ printf("Muxer %s [%s]:\n", fmt->name, fmt->long_name);
+
+ if (fmt->extensions)
+ printf(" Common extensions: %s.\n", fmt->extensions);
+ if (fmt->mime_type)
+ printf(" Mime type: %s.\n", fmt->mime_type);
+ if (fmt->video_codec != AV_CODEC_ID_NONE &&
+ (desc = avcodec_descriptor_get(fmt->video_codec))) {
+ printf(" Default video codec: %s.\n", desc->name);
+ }
+ if (fmt->audio_codec != AV_CODEC_ID_NONE &&
+ (desc = avcodec_descriptor_get(fmt->audio_codec))) {
+ printf(" Default audio codec: %s.\n", desc->name);
+ }
+ if (fmt->subtitle_codec != AV_CODEC_ID_NONE &&
+ (desc = avcodec_descriptor_get(fmt->subtitle_codec))) {
+ printf(" Default subtitle codec: %s.\n", desc->name);
+ }
+
+ if (fmt->priv_class)
+ show_help_children(fmt->priv_class, AV_OPT_FLAG_ENCODING_PARAM);
+}
+
+#if CONFIG_AVFILTER
+static void show_help_filter(const char *name)
+{
+#if CONFIG_AVFILTER
+ const AVFilter *f = avfilter_get_by_name(name);
+ int i, count;
+
+ if (!name) {
+ av_log(NULL, AV_LOG_ERROR, "No filter name specified.\n");
+ return;
+ } else if (!f) {
+ av_log(NULL, AV_LOG_ERROR, "Unknown filter '%s'.\n", name);
+ return;
+ }
+
+ printf("Filter %s\n", f->name);
+ if (f->description)
+ printf(" %s\n", f->description);
+
+ if (f->flags & AVFILTER_FLAG_SLICE_THREADS)
+ printf(" slice threading supported\n");
+
+ printf(" Inputs:\n");
+ count = avfilter_filter_pad_count(f, 0);
+ for (i = 0; i < count; i++) {
+ printf(" #%d: %s (%s)\n", i, avfilter_pad_get_name(f->inputs, i),
+ av_get_media_type_string(avfilter_pad_get_type(f->inputs, i)));
+ }
+ if (f->flags & AVFILTER_FLAG_DYNAMIC_INPUTS)
+ printf(" dynamic (depending on the options)\n");
+ else if (!count)
+ printf(" none (source filter)\n");
+
+ printf(" Outputs:\n");
+ count = avfilter_filter_pad_count(f, 1);
+ for (i = 0; i < count; i++) {
+ printf(" #%d: %s (%s)\n", i, avfilter_pad_get_name(f->outputs, i),
+ av_get_media_type_string(avfilter_pad_get_type(f->outputs, i)));
+ }
+ if (f->flags & AVFILTER_FLAG_DYNAMIC_OUTPUTS)
+ printf(" dynamic (depending on the options)\n");
+ else if (!count)
+ printf(" none (sink filter)\n");
+
+ if (f->priv_class)
+ show_help_children(f->priv_class, AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_FILTERING_PARAM |
+ AV_OPT_FLAG_AUDIO_PARAM);
+ if (f->flags & AVFILTER_FLAG_SUPPORT_TIMELINE)
+ printf("This filter has support for timeline through the 'enable' option.\n");
+#else
+ av_log(NULL, AV_LOG_ERROR, "Build without libavfilter; "
+ "can not to satisfy request\n");
+#endif
+}
+#endif
+
+static void show_help_bsf(const char *name)
+{
+ const AVBitStreamFilter *bsf = av_bsf_get_by_name(name);
+
+ if (!name) {
+ av_log(NULL, AV_LOG_ERROR, "No bitstream filter name specified.\n");
+ return;
+ } else if (!bsf) {
+ av_log(NULL, AV_LOG_ERROR, "Unknown bit stream filter '%s'.\n", name);
+ return;
+ }
+
+ printf("Bit stream filter %s\n", bsf->name);
+ PRINT_CODEC_SUPPORTED(bsf, codec_ids, enum AVCodecID, "codecs",
+ AV_CODEC_ID_NONE, GET_CODEC_NAME);
+ if (bsf->priv_class)
+ show_help_children(bsf->priv_class, AV_OPT_FLAG_BSF_PARAM);
+}
+
+int show_help(void *optctx, const char *opt, const char *arg)
+{
+ char *topic, *par;
+ av_log_set_callback(log_callback_help);
+
+ topic = av_strdup(arg ? arg : "");
+ if (!topic)
+ return AVERROR(ENOMEM);
+ par = strchr(topic, '=');
+ if (par)
+ *par++ = 0;
+
+ if (!*topic) {
+ show_help_default(topic, par);
+ } else if (!strcmp(topic, "decoder")) {
+ show_help_codec(par, 0);
+ } else if (!strcmp(topic, "encoder")) {
+ show_help_codec(par, 1);
+ } else if (!strcmp(topic, "demuxer")) {
+ show_help_demuxer(par);
+ } else if (!strcmp(topic, "muxer")) {
+ show_help_muxer(par);
+ } else if (!strcmp(topic, "protocol")) {
+ show_help_protocol(par);
+#if CONFIG_AVFILTER
+ } else if (!strcmp(topic, "filter")) {
+ show_help_filter(par);
+#endif
+ } else if (!strcmp(topic, "bsf")) {
+ show_help_bsf(par);
+ } else {
+ show_help_default(topic, par);
+ }
+
+ av_freep(&topic);
+ return 0;
+}
+
+static void print_codecs_for_id(enum AVCodecID id, int encoder)
+{
+ void *iter = NULL;
+ const AVCodec *codec;
+
+ printf(" (%s: ", encoder ? "encoders" : "decoders");
+
+ while ((codec = next_codec_for_id(id, &iter, encoder)))
+ printf("%s ", codec->name);
+
+ printf(")");
+}
+
+static int compare_codec_desc(const void *a, const void *b)
+{
+ const AVCodecDescriptor * const *da = a;
+ const AVCodecDescriptor * const *db = b;
+
+ return (*da)->type != (*db)->type ? FFDIFFSIGN((*da)->type, (*db)->type) :
+ strcmp((*da)->name, (*db)->name);
+}
+
+static unsigned get_codecs_sorted(const AVCodecDescriptor ***rcodecs)
+{
+ const AVCodecDescriptor *desc = NULL;
+ const AVCodecDescriptor **codecs;
+ unsigned nb_codecs = 0, i = 0;
+
+ while ((desc = avcodec_descriptor_next(desc)))
+ nb_codecs++;
+ if (!(codecs = av_calloc(nb_codecs, sizeof(*codecs))))
+ report_and_exit(AVERROR(ENOMEM));
+ desc = NULL;
+ while ((desc = avcodec_descriptor_next(desc)))
+ codecs[i++] = desc;
+ av_assert0(i == nb_codecs);
+ qsort(codecs, nb_codecs, sizeof(*codecs), compare_codec_desc);
+ *rcodecs = codecs;
+ return nb_codecs;
+}
+
+static char get_media_type_char(enum AVMediaType type)
+{
+ switch (type) {
+ case AVMEDIA_TYPE_VIDEO: return 'V';
+ case AVMEDIA_TYPE_AUDIO: return 'A';
+ case AVMEDIA_TYPE_DATA: return 'D';
+ case AVMEDIA_TYPE_SUBTITLE: return 'S';
+ case AVMEDIA_TYPE_ATTACHMENT:return 'T';
+ default: return '?';
+ }
+}
+
+int show_codecs(void *optctx, const char *opt, const char *arg)
+{
+ const AVCodecDescriptor **codecs;
+ unsigned i, nb_codecs = get_codecs_sorted(&codecs);
+
+ printf("Codecs:\n"
+ " D..... = Decoding supported\n"
+ " .E.... = Encoding supported\n"
+ " ..V... = Video codec\n"
+ " ..A... = Audio codec\n"
+ " ..S... = Subtitle codec\n"
+ " ..D... = Data codec\n"
+ " ..T... = Attachment codec\n"
+ " ...I.. = Intra frame-only codec\n"
+ " ....L. = Lossy compression\n"
+ " .....S = Lossless compression\n"
+ " -------\n");
+ for (i = 0; i < nb_codecs; i++) {
+ const AVCodecDescriptor *desc = codecs[i];
+ const AVCodec *codec;
+ void *iter = NULL;
+
+ if (strstr(desc->name, "_deprecated"))
+ continue;
+
+ printf(" ");
+ printf(avcodec_find_decoder(desc->id) ? "D" : ".");
+ printf(avcodec_find_encoder(desc->id) ? "E" : ".");
+
+ printf("%c", get_media_type_char(desc->type));
+ printf((desc->props & AV_CODEC_PROP_INTRA_ONLY) ? "I" : ".");
+ printf((desc->props & AV_CODEC_PROP_LOSSY) ? "L" : ".");
+ printf((desc->props & AV_CODEC_PROP_LOSSLESS) ? "S" : ".");
+
+ printf(" %-20s %s", desc->name, desc->long_name ? desc->long_name : "");
+
+ /* print decoders/encoders when there's more than one or their
+ * names are different from codec name */
+ while ((codec = next_codec_for_id(desc->id, &iter, 0))) {
+ if (strcmp(codec->name, desc->name)) {
+ print_codecs_for_id(desc->id, 0);
+ break;
+ }
+ }
+ iter = NULL;
+ while ((codec = next_codec_for_id(desc->id, &iter, 1))) {
+ if (strcmp(codec->name, desc->name)) {
+ print_codecs_for_id(desc->id, 1);
+ break;
+ }
+ }
+
+ printf("\n");
+ }
+ av_free(codecs);
+ return 0;
+}
+
+static void print_codecs(int encoder)
+{
+ const AVCodecDescriptor **codecs;
+ unsigned i, nb_codecs = get_codecs_sorted(&codecs);
+
+ printf("%s:\n"
+ " V..... = Video\n"
+ " A..... = Audio\n"
+ " S..... = Subtitle\n"
+ " .F.... = Frame-level multithreading\n"
+ " ..S... = Slice-level multithreading\n"
+ " ...X.. = Codec is experimental\n"
+ " ....B. = Supports draw_horiz_band\n"
+ " .....D = Supports direct rendering method 1\n"
+ " ------\n",
+ encoder ? "Encoders" : "Decoders");
+ for (i = 0; i < nb_codecs; i++) {
+ const AVCodecDescriptor *desc = codecs[i];
+ const AVCodec *codec;
+ void *iter = NULL;
+
+ while ((codec = next_codec_for_id(desc->id, &iter, encoder))) {
+ printf(" %c", get_media_type_char(desc->type));
+ printf((codec->capabilities & AV_CODEC_CAP_FRAME_THREADS) ? "F" : ".");
+ printf((codec->capabilities & AV_CODEC_CAP_SLICE_THREADS) ? "S" : ".");
+ printf((codec->capabilities & AV_CODEC_CAP_EXPERIMENTAL) ? "X" : ".");
+ printf((codec->capabilities & AV_CODEC_CAP_DRAW_HORIZ_BAND)?"B" : ".");
+ printf((codec->capabilities & AV_CODEC_CAP_DR1) ? "D" : ".");
+
+ printf(" %-20s %s", codec->name, codec->long_name ? codec->long_name : "");
+ if (strcmp(codec->name, desc->name))
+ printf(" (codec %s)", desc->name);
+
+ printf("\n");
+ }
+ }
+ av_free(codecs);
+}
+
+int show_decoders(void *optctx, const char *opt, const char *arg)
+{
+ print_codecs(0);
+ return 0;
+}
+
+int show_encoders(void *optctx, const char *opt, const char *arg)
+{
+ print_codecs(1);
+ return 0;
+}
+
+int show_bsfs(void *optctx, const char *opt, const char *arg)
+{
+ const AVBitStreamFilter *bsf = NULL;
+ void *opaque = NULL;
+
+ printf("Bitstream filters:\n");
+ while ((bsf = av_bsf_iterate(&opaque)))
+ printf("%s\n", bsf->name);
+ printf("\n");
+ return 0;
+}
+
+int show_filters(void *optctx, const char *opt, const char *arg)
+{
+#if CONFIG_AVFILTER
+ const AVFilter *filter = NULL;
+ char descr[64], *descr_cur;
+ void *opaque = NULL;
+ int i, j;
+ const AVFilterPad *pad;
+
+ printf("Filters:\n"
+ " T.. = Timeline support\n"
+ " .S. = Slice threading\n"
+ " ..C = Command support\n"
+ " A = Audio input/output\n"
+ " V = Video input/output\n"
+ " N = Dynamic number and/or type of input/output\n"
+ " | = Source or sink filter\n");
+ while ((filter = av_filter_iterate(&opaque))) {
+ descr_cur = descr;
+ for (i = 0; i < 2; i++) {
+ unsigned nb_pads;
+ if (i) {
+ *(descr_cur++) = '-';
+ *(descr_cur++) = '>';
+ }
+ pad = i ? filter->outputs : filter->inputs;
+ nb_pads = avfilter_filter_pad_count(filter, i);
+ for (j = 0; j < nb_pads; j++) {
+ if (descr_cur >= descr + sizeof(descr) - 4)
+ break;
+ *(descr_cur++) = get_media_type_char(avfilter_pad_get_type(pad, j));
+ }
+ if (!j)
+ *(descr_cur++) = ((!i && (filter->flags & AVFILTER_FLAG_DYNAMIC_INPUTS)) ||
+ ( i && (filter->flags & AVFILTER_FLAG_DYNAMIC_OUTPUTS))) ? 'N' : '|';
+ }
+ *descr_cur = 0;
+ printf(" %c%c%c %-17s %-10s %s\n",
+ filter->flags & AVFILTER_FLAG_SUPPORT_TIMELINE ? 'T' : '.',
+ filter->flags & AVFILTER_FLAG_SLICE_THREADS ? 'S' : '.',
+ filter->process_command ? 'C' : '.',
+ filter->name, descr, filter->description);
+ }
+#else
+ printf("No filters available: libavfilter disabled\n");
+#endif
+ return 0;
+}
+
+static int is_device(const AVClass *avclass)
+{
+ if (!avclass)
+ return 0;
+ return AV_IS_INPUT_DEVICE(avclass->category) || AV_IS_OUTPUT_DEVICE(avclass->category);
+}
+
+static int show_formats_devices(void *optctx, const char *opt, const char *arg, int device_only, int muxdemuxers)
+{
+ void *ifmt_opaque = NULL;
+ const AVInputFormat *ifmt = NULL;
+ void *ofmt_opaque = NULL;
+ const AVOutputFormat *ofmt = NULL;
+ const char *last_name;
+ int is_dev;
+
+ printf("%s\n"
+ " D. = Demuxing supported\n"
+ " .E = Muxing supported\n"
+ " --\n", device_only ? "Devices:" : "File formats:");
+ last_name = "000";
+ for (;;) {
+ int decode = 0;
+ int encode = 0;
+ const char *name = NULL;
+ const char *long_name = NULL;
+
+ if (muxdemuxers !=SHOW_DEMUXERS) {
+ ofmt_opaque = NULL;
+ while ((ofmt = av_muxer_iterate(&ofmt_opaque))) {
+ is_dev = is_device(ofmt->priv_class);
+ if (!is_dev && device_only)
+ continue;
+ if ((!name || strcmp(ofmt->name, name) < 0) &&
+ strcmp(ofmt->name, last_name) > 0) {
+ name = ofmt->name;
+ long_name = ofmt->long_name;
+ encode = 1;
+ }
+ }
+ }
+ if (muxdemuxers != SHOW_MUXERS) {
+ ifmt_opaque = NULL;
+ while ((ifmt = av_demuxer_iterate(&ifmt_opaque))) {
+ is_dev = is_device(ifmt->priv_class);
+ if (!is_dev && device_only)
+ continue;
+ if ((!name || strcmp(ifmt->name, name) < 0) &&
+ strcmp(ifmt->name, last_name) > 0) {
+ name = ifmt->name;
+ long_name = ifmt->long_name;
+ encode = 0;
+ }
+ if (name && strcmp(ifmt->name, name) == 0)
+ decode = 1;
+ }
+ }
+ if (!name)
+ break;
+ last_name = name;
+
+ printf(" %c%c %-15s %s\n",
+ decode ? 'D' : ' ',
+ encode ? 'E' : ' ',
+ name,
+ long_name ? long_name:" ");
+ }
+ return 0;
+}
+
+int show_formats(void *optctx, const char *opt, const char *arg)
+{
+ return show_formats_devices(optctx, opt, arg, 0, SHOW_DEFAULT);
+}
+
+int show_muxers(void *optctx, const char *opt, const char *arg)
+{
+ return show_formats_devices(optctx, opt, arg, 0, SHOW_MUXERS);
+}
+
+int show_demuxers(void *optctx, const char *opt, const char *arg)
+{
+ return show_formats_devices(optctx, opt, arg, 0, SHOW_DEMUXERS);
+}
+
+int show_devices(void *optctx, const char *opt, const char *arg)
+{
+ return show_formats_devices(optctx, opt, arg, 1, SHOW_DEFAULT);
+}
+
+int show_protocols(void *optctx, const char *opt, const char *arg)
+{
+ void *opaque = NULL;
+ const char *name;
+
+ printf("Supported file protocols:\n"
+ "Input:\n");
+ while ((name = avio_enum_protocols(&opaque, 0)))
+ printf(" %s\n", name);
+ printf("Output:\n");
+ while ((name = avio_enum_protocols(&opaque, 1)))
+ printf(" %s\n", name);
+ return 0;
+}
+
+int show_colors(void *optctx, const char *opt, const char *arg)
+{
+ const char *name;
+ const uint8_t *rgb;
+ int i;
+
+ printf("%-32s #RRGGBB\n", "name");
+
+ for (i = 0; name = av_get_known_color_name(i, &rgb); i++)
+ printf("%-32s #%02x%02x%02x\n", name, rgb[0], rgb[1], rgb[2]);
+
+ return 0;
+}
+
+int show_pix_fmts(void *optctx, const char *opt, const char *arg)
+{
+ const AVPixFmtDescriptor *pix_desc = NULL;
+
+ printf("Pixel formats:\n"
+ "I.... = Supported Input format for conversion\n"
+ ".O... = Supported Output format for conversion\n"
+ "..H.. = Hardware accelerated format\n"
+ "...P. = Paletted format\n"
+ "....B = Bitstream format\n"
+ "FLAGS NAME NB_COMPONENTS BITS_PER_PIXEL BIT_DEPTHS\n"
+ "-----\n");
+
+#if !CONFIG_SWSCALE
+# define sws_isSupportedInput(x) 0
+# define sws_isSupportedOutput(x) 0
+#endif
+
+ while ((pix_desc = av_pix_fmt_desc_next(pix_desc))) {
+ enum AVPixelFormat av_unused pix_fmt = av_pix_fmt_desc_get_id(pix_desc);
+ printf("%c%c%c%c%c %-16s %d %3d %d",
+ sws_isSupportedInput (pix_fmt) ? 'I' : '.',
+ sws_isSupportedOutput(pix_fmt) ? 'O' : '.',
+ pix_desc->flags & AV_PIX_FMT_FLAG_HWACCEL ? 'H' : '.',
+ pix_desc->flags & AV_PIX_FMT_FLAG_PAL ? 'P' : '.',
+ pix_desc->flags & AV_PIX_FMT_FLAG_BITSTREAM ? 'B' : '.',
+ pix_desc->name,
+ pix_desc->nb_components,
+ av_get_bits_per_pixel(pix_desc),
+ pix_desc->comp[0].depth);
+
+ for (unsigned i = 1; i < pix_desc->nb_components; i++)
+ printf("-%d", pix_desc->comp[i].depth);
+ printf("\n");
+ }
+ return 0;
+}
+
+int show_layouts(void *optctx, const char *opt, const char *arg)
+{
+ const AVChannelLayout *ch_layout;
+ void *iter = NULL;
+ char buf[128], buf2[128];
+ int i = 0;
+
+ printf("Individual channels:\n"
+ "NAME DESCRIPTION\n");
+ for (i = 0; i < 63; i++) {
+ av_channel_name(buf, sizeof(buf), i);
+ if (strstr(buf, "USR"))
+ continue;
+ av_channel_description(buf2, sizeof(buf2), i);
+ printf("%-14s %s\n", buf, buf2);
+ }
+ printf("\nStandard channel layouts:\n"
+ "NAME DECOMPOSITION\n");
+ while (ch_layout = av_channel_layout_standard(&iter)) {
+ av_channel_layout_describe(ch_layout, buf, sizeof(buf));
+ printf("%-14s ", buf);
+ for (i = 0; i < 63; i++) {
+ int idx = av_channel_layout_index_from_channel(ch_layout, i);
+ if (idx >= 0) {
+ av_channel_name(buf2, sizeof(buf2), i);
+ printf("%s%s", idx ? "+" : "", buf2);
+ }
+ }
+ printf("\n");
+ }
+ return 0;
+}
+
+int show_sample_fmts(void *optctx, const char *opt, const char *arg)
+{
+ int i;
+ char fmt_str[128];
+ for (i = -1; i < AV_SAMPLE_FMT_NB; i++)
+ printf("%s\n", av_get_sample_fmt_string(fmt_str, sizeof(fmt_str), i));
+ return 0;
+}
+
+int show_dispositions(void *optctx, const char *opt, const char *arg)
+{
+ for (int i = 0; i < 32; i++) {
+ const char *str = av_disposition_to_string(1U << i);
+ if (str)
+ printf("%s\n", str);
+ }
+ return 0;
+}
+
+int opt_cpuflags(void *optctx, const char *opt, const char *arg)
+{
+ int ret;
+ unsigned flags = av_get_cpu_flags();
+
+ if ((ret = av_parse_cpu_caps(&flags, arg)) < 0)
+ return ret;
+
+ av_force_cpu_flags(flags);
+ return 0;
+}
+
+int opt_cpucount(void *optctx, const char *opt, const char *arg)
+{
+ int ret;
+ int count;
+
+ static const AVOption opts[] = {
+ {"count", NULL, 0, AV_OPT_TYPE_INT, { .i64 = -1}, -1, INT_MAX},
+ {NULL},
+ };
+ static const AVClass class = {
+ .class_name = "cpucount",
+ .item_name = av_default_item_name,
+ .option = opts,
+ .version = LIBAVUTIL_VERSION_INT,
+ };
+ const AVClass *pclass = &class;
+
+ ret = av_opt_eval_int(&pclass, opts, arg, &count);
+
+ if (!ret) {
+ av_cpu_force_count(count);
+ }
+
+ return ret;
+}
+
+static void expand_filename_template(AVBPrint *bp, const char *template,
+ struct tm *tm)
+{
+ int c;
+
+ while ((c = *(template++))) {
+ if (c == '%') {
+ if (!(c = *(template++)))
+ break;
+ switch (c) {
+ case 'p':
+ av_bprintf(bp, "%s", program_name);
+ break;
+ case 't':
+ av_bprintf(bp, "%04d%02d%02d-%02d%02d%02d",
+ tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday,
+ tm->tm_hour, tm->tm_min, tm->tm_sec);
+ break;
+ case '%':
+ av_bprint_chars(bp, c, 1);
+ break;
+ }
+ } else {
+ av_bprint_chars(bp, c, 1);
+ }
+ }
+}
+
+static void log_callback_report(void *ptr, int level, const char *fmt, va_list vl)
+{
+ va_list vl2;
+ char line[1024];
+ static int print_prefix = 1;
+
+ va_copy(vl2, vl);
+ av_log_default_callback(ptr, level, fmt, vl);
+ av_log_format_line(ptr, level, fmt, vl2, line, sizeof(line), &print_prefix);
+ va_end(vl2);
+ if (report_file_level >= level) {
+ fputs(line, report_file);
+ fflush(report_file);
+ }
+}
+
+int init_report(const char *env, FILE **file)
+{
+ char *filename_template = NULL;
+ char *key, *val;
+ int ret, count = 0;
+ int prog_loglevel, envlevel = 0;
+ time_t now;
+ struct tm *tm;
+ AVBPrint filename;
+
+ if (report_file) /* already opened */
+ return 0;
+ time(&now);
+ tm = localtime(&now);
+
+ while (env && *env) {
+ if ((ret = av_opt_get_key_value(&env, "=", ":", 0, &key, &val)) < 0) {
+ if (count)
+ av_log(NULL, AV_LOG_ERROR,
+ "Failed to parse FFREPORT environment variable: %s\n",
+ av_err2str(ret));
+ break;
+ }
+ if (*env)
+ env++;
+ count++;
+ if (!strcmp(key, "file")) {
+ av_free(filename_template);
+ filename_template = val;
+ val = NULL;
+ } else if (!strcmp(key, "level")) {
+ char *tail;
+ report_file_level = strtol(val, &tail, 10);
+ if (*tail) {
+ av_log(NULL, AV_LOG_FATAL, "Invalid report file level\n");
+ exit_program(1);
+ }
+ envlevel = 1;
+ } else {
+ av_log(NULL, AV_LOG_ERROR, "Unknown key '%s' in FFREPORT\n", key);
+ }
+ av_free(val);
+ av_free(key);
+ }
+
+ av_bprint_init(&filename, 0, AV_BPRINT_SIZE_AUTOMATIC);
+ expand_filename_template(&filename,
+ av_x_if_null(filename_template, "%p-%t.log"), tm);
+ av_free(filename_template);
+ if (!av_bprint_is_complete(&filename)) {
+ av_log(NULL, AV_LOG_ERROR, "Out of memory building report file name\n");
+ return AVERROR(ENOMEM);
+ }
+
+ prog_loglevel = av_log_get_level();
+ if (!envlevel)
+ report_file_level = FFMAX(report_file_level, prog_loglevel);
+
+ report_file = fopen(filename.str, "w");
+ if (!report_file) {
+ int ret = AVERROR(errno);
+ av_log(NULL, AV_LOG_ERROR, "Failed to open report \"%s\": %s\n",
+ filename.str, strerror(errno));
+ return ret;
+ }
+ av_log_set_callback(log_callback_report);
+ av_log(NULL, AV_LOG_INFO,
+ "%s started on %04d-%02d-%02d at %02d:%02d:%02d\n"
+ "Report written to \"%s\"\n"
+ "Log level: %d\n",
+ program_name,
+ tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday,
+ tm->tm_hour, tm->tm_min, tm->tm_sec,
+ filename.str, report_file_level);
+ av_bprint_finalize(&filename, NULL);
+
+ if (file)
+ *file = report_file;
+
+ return 0;
+}
+
+int opt_report(void *optctx, const char *opt, const char *arg)
+{
+ return init_report(NULL, NULL);
+}
+
+int opt_max_alloc(void *optctx, const char *opt, const char *arg)
+{
+ char *tail;
+ size_t max;
+
+ max = strtol(arg, &tail, 10);
+ if (*tail) {
+ av_log(NULL, AV_LOG_FATAL, "Invalid max_alloc \"%s\".\n", arg);
+ exit_program(1);
+ }
+ av_max_alloc(max);
+ return 0;
+}
+
+int opt_loglevel(void *optctx, const char *opt, const char *arg)
+{
+ const struct { const char *name; int level; } log_levels[] = {
+ { "quiet" , AV_LOG_QUIET },
+ { "panic" , AV_LOG_PANIC },
+ { "fatal" , AV_LOG_FATAL },
+ { "error" , AV_LOG_ERROR },
+ { "warning", AV_LOG_WARNING },
+ { "info" , AV_LOG_INFO },
+ { "verbose", AV_LOG_VERBOSE },
+ { "debug" , AV_LOG_DEBUG },
+ { "trace" , AV_LOG_TRACE },
+ };
+ const char *token;
+ char *tail;
+ int flags = av_log_get_flags();
+ int level = av_log_get_level();
+ int cmd, i = 0;
+
+ av_assert0(arg);
+ while (*arg) {
+ token = arg;
+ if (*token == '+' || *token == '-') {
+ cmd = *token++;
+ } else {
+ cmd = 0;
+ }
+ if (!i && !cmd) {
+ flags = 0; /* missing relative prefix, build absolute value */
+ }
+ if (av_strstart(token, "repeat", &arg)) {
+ if (cmd == '-') {
+ flags |= AV_LOG_SKIP_REPEATED;
+ } else {
+ flags &= ~AV_LOG_SKIP_REPEATED;
+ }
+ } else if (av_strstart(token, "level", &arg)) {
+ if (cmd == '-') {
+ flags &= ~AV_LOG_PRINT_LEVEL;
+ } else {
+ flags |= AV_LOG_PRINT_LEVEL;
+ }
+ } else {
+ break;
+ }
+ i++;
+ }
+ if (!*arg) {
+ goto end;
+ } else if (*arg == '+') {
+ arg++;
+ } else if (!i) {
+ flags = av_log_get_flags(); /* level value without prefix, reset flags */
+ }
+
+ for (i = 0; i < FF_ARRAY_ELEMS(log_levels); i++) {
+ if (!strcmp(log_levels[i].name, arg)) {
+ level = log_levels[i].level;
+ goto end;
+ }
+ }
+
+ level = strtol(arg, &tail, 10);
+ if (*tail) {
+ av_log(NULL, AV_LOG_FATAL, "Invalid loglevel \"%s\". "
+ "Possible levels are numbers or:\n", arg);
+ for (i = 0; i < FF_ARRAY_ELEMS(log_levels); i++)
+ av_log(NULL, AV_LOG_FATAL, "\"%s\"\n", log_levels[i].name);
+ exit_program(1);
+ }
+
+end:
+ av_log_set_flags(flags);
+ av_log_set_level(level);
+ return 0;
+}
+
+#if CONFIG_AVDEVICE
+static void print_device_list(const AVDeviceInfoList *device_list)
+{
+ // print devices
+ for (int i = 0; i < device_list->nb_devices; i++) {
+ const AVDeviceInfo *device = device_list->devices[i];
+ printf("%c %s [%s] (", device_list->default_device == i ? '*' : ' ',
+ device->device_name, device->device_description);
+ if (device->nb_media_types > 0) {
+ for (int j = 0; j < device->nb_media_types; ++j) {
+ const char* media_type = av_get_media_type_string(device->media_types[j]);
+ if (j > 0)
+ printf(", ");
+ printf("%s", media_type ? media_type : "unknown");
+ }
+ } else {
+ printf("none");
+ }
+ printf(")\n");
+ }
+}
+
+static int print_device_sources(const AVInputFormat *fmt, AVDictionary *opts)
+{
+ int ret;
+ AVDeviceInfoList *device_list = NULL;
+
+ if (!fmt || !fmt->priv_class || !AV_IS_INPUT_DEVICE(fmt->priv_class->category))
+ return AVERROR(EINVAL);
+
+ printf("Auto-detected sources for %s:\n", fmt->name);
+ if ((ret = avdevice_list_input_sources(fmt, NULL, opts, &device_list)) < 0) {
+ printf("Cannot list sources: %s\n", av_err2str(ret));
+ goto fail;
+ }
+
+ print_device_list(device_list);
+
+ fail:
+ avdevice_free_list_devices(&device_list);
+ return ret;
+}
+
+static int print_device_sinks(const AVOutputFormat *fmt, AVDictionary *opts)
+{
+ int ret;
+ AVDeviceInfoList *device_list = NULL;
+
+ if (!fmt || !fmt->priv_class || !AV_IS_OUTPUT_DEVICE(fmt->priv_class->category))
+ return AVERROR(EINVAL);
+
+ printf("Auto-detected sinks for %s:\n", fmt->name);
+ if ((ret = avdevice_list_output_sinks(fmt, NULL, opts, &device_list)) < 0) {
+ printf("Cannot list sinks: %s\n", av_err2str(ret));
+ goto fail;
+ }
+
+ print_device_list(device_list);
+
+ fail:
+ avdevice_free_list_devices(&device_list);
+ return ret;
+}
+
+static int show_sinks_sources_parse_arg(const char *arg, char **dev, AVDictionary **opts)
+{
+ int ret;
+ if (arg) {
+ char *opts_str = NULL;
+ av_assert0(dev && opts);
+ *dev = av_strdup(arg);
+ if (!*dev)
+ return AVERROR(ENOMEM);
+ if ((opts_str = strchr(*dev, ','))) {
+ *(opts_str++) = '\0';
+ if (opts_str[0] && ((ret = av_dict_parse_string(opts, opts_str, "=", ":", 0)) < 0)) {
+ av_freep(dev);
+ return ret;
+ }
+ }
+ } else
+ printf("\nDevice name is not provided.\n"
+ "You can pass devicename[,opt1=val1[,opt2=val2...]] as an argument.\n\n");
+ return 0;
+}
+
+int show_sources(void *optctx, const char *opt, const char *arg)
+{
+ const AVInputFormat *fmt = NULL;
+ char *dev = NULL;
+ AVDictionary *opts = NULL;
+ int ret = 0;
+ int error_level = av_log_get_level();
+
+ av_log_set_level(AV_LOG_WARNING);
+
+ if ((ret = show_sinks_sources_parse_arg(arg, &dev, &opts)) < 0)
+ goto fail;
+
+ do {
+ fmt = av_input_audio_device_next(fmt);
+ if (fmt) {
+ if (!strcmp(fmt->name, "lavfi"))
+ continue; //it's pointless to probe lavfi
+ if (dev && !av_match_name(dev, fmt->name))
+ continue;
+ print_device_sources(fmt, opts);
+ }
+ } while (fmt);
+ do {
+ fmt = av_input_video_device_next(fmt);
+ if (fmt) {
+ if (dev && !av_match_name(dev, fmt->name))
+ continue;
+ print_device_sources(fmt, opts);
+ }
+ } while (fmt);
+ fail:
+ av_dict_free(&opts);
+ av_free(dev);
+ av_log_set_level(error_level);
+ return ret;
+}
+
+int show_sinks(void *optctx, const char *opt, const char *arg)
+{
+ const AVOutputFormat *fmt = NULL;
+ char *dev = NULL;
+ AVDictionary *opts = NULL;
+ int ret = 0;
+ int error_level = av_log_get_level();
+
+ av_log_set_level(AV_LOG_WARNING);
+
+ if ((ret = show_sinks_sources_parse_arg(arg, &dev, &opts)) < 0)
+ goto fail;
+
+ do {
+ fmt = av_output_audio_device_next(fmt);
+ if (fmt) {
+ if (dev && !av_match_name(dev, fmt->name))
+ continue;
+ print_device_sinks(fmt, opts);
+ }
+ } while (fmt);
+ do {
+ fmt = av_output_video_device_next(fmt);
+ if (fmt) {
+ if (dev && !av_match_name(dev, fmt->name))
+ continue;
+ print_device_sinks(fmt, opts);
+ }
+ } while (fmt);
+ fail:
+ av_dict_free(&opts);
+ av_free(dev);
+ av_log_set_level(error_level);
+ return ret;
+}
+#endif /* CONFIG_AVDEVICE */
diff --git a/app/src/main/cpp/ffmpeg/opt_common.h b/app/src/main/cpp/ffmpeg/opt_common.h
new file mode 100644
index 00000000..ea1d16e7
--- /dev/null
+++ b/app/src/main/cpp/ffmpeg/opt_common.h
@@ -0,0 +1,231 @@
+/*
+ * Option handlers shared between the tools.
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef FFTOOLS_OPT_COMMON_H
+#define FFTOOLS_OPT_COMMON_H
+
+#include "config.h"
+
+#include "cmdutils.h"
+
+#if CONFIG_AVDEVICE
+/**
+ * Print a listing containing autodetected sinks of the output device.
+ * Device name with options may be passed as an argument to limit results.
+ */
+int show_sinks(void *optctx, const char *opt, const char *arg);
+
+/**
+ * Print a listing containing autodetected sources of the input device.
+ * Device name with options may be passed as an argument to limit results.
+ */
+int show_sources(void *optctx, const char *opt, const char *arg);
+#endif
+
+#if CONFIG_AVDEVICE
+#define CMDUTILS_COMMON_OPTIONS_AVDEVICE \
+ { "sources" , OPT_EXIT | HAS_ARG, { .func_arg = show_sources }, \
+ "list sources of the input device", "device" }, \
+ { "sinks" , OPT_EXIT | HAS_ARG, { .func_arg = show_sinks }, \
+ "list sinks of the output device", "device" }, \
+
+#else
+#define CMDUTILS_COMMON_OPTIONS_AVDEVICE
+#endif
+
+/**
+ * Print the license of the program to stdout. The license depends on
+ * the license of the libraries compiled into the program.
+ * This option processing function does not utilize the arguments.
+ */
+int show_license(void *optctx, const char *opt, const char *arg);
+
+/**
+ * Generic -h handler common to all fftools.
+ */
+int show_help(void *optctx, const char *opt, const char *arg);
+
+/**
+ * Print the version of the program to stdout. The version message
+ * depends on the current versions of the repository and of the libav*
+ * libraries.
+ * This option processing function does not utilize the arguments.
+ */
+int show_version(void *optctx, const char *opt, const char *arg);
+
+/**
+ * Print the build configuration of the program to stdout. The contents
+ * depend on the definition of FFMPEG_CONFIGURATION.
+ * This option processing function does not utilize the arguments.
+ */
+int show_buildconf(void *optctx, const char *opt, const char *arg);
+
+/**
+ * Print a listing containing all the formats supported by the
+ * program (including devices).
+ * This option processing function does not utilize the arguments.
+ */
+int show_formats(void *optctx, const char *opt, const char *arg);
+
+/**
+ * Print a listing containing all the muxers supported by the
+ * program (including devices).
+ * This option processing function does not utilize the arguments.
+ */
+int show_muxers(void *optctx, const char *opt, const char *arg);
+
+/**
+ * Print a listing containing all the demuxer supported by the
+ * program (including devices).
+ * This option processing function does not utilize the arguments.
+ */
+int show_demuxers(void *optctx, const char *opt, const char *arg);
+
+/**
+ * Print a listing containing all the devices supported by the
+ * program.
+ * This option processing function does not utilize the arguments.
+ */
+int show_devices(void *optctx, const char *opt, const char *arg);
+
+/**
+ * Print a listing containing all the codecs supported by the
+ * program.
+ * This option processing function does not utilize the arguments.
+ */
+int show_codecs(void *optctx, const char *opt, const char *arg);
+
+/**
+ * Print a listing containing all the decoders supported by the
+ * program.
+ */
+int show_decoders(void *optctx, const char *opt, const char *arg);
+
+/**
+ * Print a listing containing all the encoders supported by the
+ * program.
+ */
+int show_encoders(void *optctx, const char *opt, const char *arg);
+
+/**
+ * Print a listing containing all the bit stream filters supported by the
+ * program.
+ * This option processing function does not utilize the arguments.
+ */
+int show_bsfs(void *optctx, const char *opt, const char *arg);
+
+/**
+ * Print a listing containing all the protocols supported by the
+ * program.
+ * This option processing function does not utilize the arguments.
+ */
+int show_protocols(void *optctx, const char *opt, const char *arg);
+
+/**
+ * Print a listing containing all the filters supported by the
+ * program.
+ * This option processing function does not utilize the arguments.
+ */
+int show_filters(void *optctx, const char *opt, const char *arg);
+
+/**
+ * Print a listing containing all the pixel formats supported by the
+ * program.
+ * This option processing function does not utilize the arguments.
+ */
+int show_pix_fmts(void *optctx, const char *opt, const char *arg);
+
+/**
+ * Print a listing containing all the standard channel layouts supported by
+ * the program.
+ * This option processing function does not utilize the arguments.
+ */
+int show_layouts(void *optctx, const char *opt, const char *arg);
+
+/**
+ * Print a listing containing all the sample formats supported by the
+ * program.
+ */
+int show_sample_fmts(void *optctx, const char *opt, const char *arg);
+
+/**
+ * Print a listing containing all supported stream dispositions.
+ */
+int show_dispositions(void *optctx, const char *opt, const char *arg);
+
+/**
+ * Print a listing containing all the color names and values recognized
+ * by the program.
+ */
+int show_colors(void *optctx, const char *opt, const char *arg);
+
+/**
+ * Set the libav* libraries log level.
+ */
+int opt_loglevel(void *optctx, const char *opt, const char *arg);
+
+int opt_report(void *optctx, const char *opt, const char *arg);
+int init_report(const char *env, FILE **file);
+
+int opt_max_alloc(void *optctx, const char *opt, const char *arg);
+
+/**
+ * Override the cpuflags.
+ */
+int opt_cpuflags(void *optctx, const char *opt, const char *arg);
+
+/**
+ * Override the cpucount.
+ */
+int opt_cpucount(void *optctx, const char *opt, const char *arg);
+
+#define CMDUTILS_COMMON_OPTIONS \
+ { "L", OPT_EXIT, { .func_arg = show_license }, "show license" }, \
+ { "h", OPT_EXIT, { .func_arg = show_help }, "show help", "topic" }, \
+ { "?", OPT_EXIT, { .func_arg = show_help }, "show help", "topic" }, \
+ { "help", OPT_EXIT, { .func_arg = show_help }, "show help", "topic" }, \
+ { "-help", OPT_EXIT, { .func_arg = show_help }, "show help", "topic" }, \
+ { "version", OPT_EXIT, { .func_arg = show_version }, "show version" }, \
+ { "buildconf", OPT_EXIT, { .func_arg = show_buildconf }, "show build configuration" }, \
+ { "formats", OPT_EXIT, { .func_arg = show_formats }, "show available formats" }, \
+ { "muxers", OPT_EXIT, { .func_arg = show_muxers }, "show available muxers" }, \
+ { "demuxers", OPT_EXIT, { .func_arg = show_demuxers }, "show available demuxers" }, \
+ { "devices", OPT_EXIT, { .func_arg = show_devices }, "show available devices" }, \
+ { "codecs", OPT_EXIT, { .func_arg = show_codecs }, "show available codecs" }, \
+ { "decoders", OPT_EXIT, { .func_arg = show_decoders }, "show available decoders" }, \
+ { "encoders", OPT_EXIT, { .func_arg = show_encoders }, "show available encoders" }, \
+ { "bsfs", OPT_EXIT, { .func_arg = show_bsfs }, "show available bit stream filters" }, \
+ { "protocols", OPT_EXIT, { .func_arg = show_protocols }, "show available protocols" }, \
+ { "filters", OPT_EXIT, { .func_arg = show_filters }, "show available filters" }, \
+ { "pix_fmts", OPT_EXIT, { .func_arg = show_pix_fmts }, "show available pixel formats" }, \
+ { "layouts", OPT_EXIT, { .func_arg = show_layouts }, "show standard channel layouts" }, \
+ { "sample_fmts", OPT_EXIT, { .func_arg = show_sample_fmts }, "show available audio sample formats" }, \
+ { "dispositions", OPT_EXIT, { .func_arg = show_dispositions}, "show available stream dispositions" }, \
+ { "colors", OPT_EXIT, { .func_arg = show_colors }, "show available color names" }, \
+ { "loglevel", HAS_ARG, { .func_arg = opt_loglevel }, "set logging level", "loglevel" }, \
+ { "v", HAS_ARG, { .func_arg = opt_loglevel }, "set logging level", "loglevel" }, \
+ { "report", 0, { .func_arg = opt_report }, "generate a report" }, \
+ { "max_alloc", HAS_ARG, { .func_arg = opt_max_alloc }, "set maximum size of a single allocated block", "bytes" }, \
+ { "cpuflags", HAS_ARG | OPT_EXPERT, { .func_arg = opt_cpuflags }, "force specific cpu flags", "flags" }, \
+ { "cpucount", HAS_ARG | OPT_EXPERT, { .func_arg = opt_cpucount }, "force specific cpu count", "count" }, \
+ { "hide_banner", OPT_BOOL | OPT_EXPERT, {&hide_banner}, "do not show program banner", "hide_banner" }, \
+ CMDUTILS_COMMON_OPTIONS_AVDEVICE \
+
+#endif /* FFTOOLS_OPT_COMMON_H */
diff --git a/app/src/main/cpp/ffmpeg/sync_queue.c b/app/src/main/cpp/ffmpeg/sync_queue.c
new file mode 100644
index 00000000..c2b23ee4
--- /dev/null
+++ b/app/src/main/cpp/ffmpeg/sync_queue.c
@@ -0,0 +1,448 @@
+/*
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include
+#include
+
+#include "libavutil/avassert.h"
+#include "libavutil/error.h"
+#include "libavutil/fifo.h"
+#include "libavutil/mathematics.h"
+#include "libavutil/mem.h"
+
+#include "objpool.h"
+#include "sync_queue.h"
+
+typedef struct SyncQueueStream {
+ AVFifo *fifo;
+ AVRational tb;
+
+ /* stream head: largest timestamp seen */
+ int64_t head_ts;
+ int limiting;
+ /* no more frames will be sent for this stream */
+ int finished;
+
+ uint64_t frames_sent;
+ uint64_t frames_max;
+} SyncQueueStream;
+
+struct SyncQueue {
+ enum SyncQueueType type;
+
+ /* no more frames will be sent for any stream */
+ int finished;
+ /* sync head: the stream with the _smallest_ head timestamp
+ * this stream determines which frames can be output */
+ int head_stream;
+ /* the finished stream with the smallest finish timestamp or -1 */
+ int head_finished_stream;
+
+ // maximum buffering duration in microseconds
+ int64_t buf_size_us;
+
+ SyncQueueStream *streams;
+ unsigned int nb_streams;
+
+ // pool of preallocated frames to avoid constant allocations
+ ObjPool *pool;
+};
+
+static void frame_move(const SyncQueue *sq, SyncQueueFrame dst,
+ SyncQueueFrame src)
+{
+ if (sq->type == SYNC_QUEUE_PACKETS)
+ av_packet_move_ref(dst.p, src.p);
+ else
+ av_frame_move_ref(dst.f, src.f);
+}
+
+static int64_t frame_ts(const SyncQueue *sq, SyncQueueFrame frame)
+{
+ return (sq->type == SYNC_QUEUE_PACKETS) ?
+ frame.p->pts + frame.p->duration :
+ frame.f->pts + frame.f->duration;
+}
+
+static int frame_null(const SyncQueue *sq, SyncQueueFrame frame)
+{
+ return (sq->type == SYNC_QUEUE_PACKETS) ? (frame.p == NULL) : (frame.f == NULL);
+}
+
+static void finish_stream(SyncQueue *sq, unsigned int stream_idx)
+{
+ SyncQueueStream *st = &sq->streams[stream_idx];
+
+ st->finished = 1;
+
+ if (st->limiting && st->head_ts != AV_NOPTS_VALUE) {
+ /* check if this stream is the new finished head */
+ if (sq->head_finished_stream < 0 ||
+ av_compare_ts(st->head_ts, st->tb,
+ sq->streams[sq->head_finished_stream].head_ts,
+ sq->streams[sq->head_finished_stream].tb) < 0) {
+ sq->head_finished_stream = stream_idx;
+ }
+
+ /* mark as finished all streams that should no longer receive new frames,
+ * due to them being ahead of some finished stream */
+ st = &sq->streams[sq->head_finished_stream];
+ for (unsigned int i = 0; i < sq->nb_streams; i++) {
+ SyncQueueStream *st1 = &sq->streams[i];
+ if (st != st1 && st1->head_ts != AV_NOPTS_VALUE &&
+ av_compare_ts(st->head_ts, st->tb, st1->head_ts, st1->tb) <= 0)
+ st1->finished = 1;
+ }
+ }
+
+ /* mark the whole queue as finished if all streams are finished */
+ for (unsigned int i = 0; i < sq->nb_streams; i++) {
+ if (!sq->streams[i].finished)
+ return;
+ }
+ sq->finished = 1;
+}
+
+static void queue_head_update(SyncQueue *sq)
+{
+ if (sq->head_stream < 0) {
+ /* wait for one timestamp in each stream before determining
+ * the queue head */
+ for (unsigned int i = 0; i < sq->nb_streams; i++) {
+ SyncQueueStream *st = &sq->streams[i];
+ if (st->limiting && st->head_ts == AV_NOPTS_VALUE)
+ return;
+ }
+
+ // placeholder value, correct one will be found below
+ sq->head_stream = 0;
+ }
+
+ for (unsigned int i = 0; i < sq->nb_streams; i++) {
+ SyncQueueStream *st_head = &sq->streams[sq->head_stream];
+ SyncQueueStream *st_other = &sq->streams[i];
+ if (st_other->limiting && st_other->head_ts != AV_NOPTS_VALUE &&
+ av_compare_ts(st_other->head_ts, st_other->tb,
+ st_head->head_ts, st_head->tb) < 0)
+ sq->head_stream = i;
+ }
+}
+
+/* update this stream's head timestamp */
+static void stream_update_ts(SyncQueue *sq, unsigned int stream_idx, int64_t ts)
+{
+ SyncQueueStream *st = &sq->streams[stream_idx];
+
+ if (ts == AV_NOPTS_VALUE ||
+ (st->head_ts != AV_NOPTS_VALUE && st->head_ts >= ts))
+ return;
+
+ st->head_ts = ts;
+
+ /* if this stream is now ahead of some finished stream, then
+ * this stream is also finished */
+ if (sq->head_finished_stream >= 0 &&
+ av_compare_ts(sq->streams[sq->head_finished_stream].head_ts,
+ sq->streams[sq->head_finished_stream].tb,
+ ts, st->tb) <= 0)
+ finish_stream(sq, stream_idx);
+
+ /* update the overall head timestamp if it could have changed */
+ if (st->limiting &&
+ (sq->head_stream < 0 || sq->head_stream == stream_idx))
+ queue_head_update(sq);
+}
+
+/* If the queue for the given stream (or all streams when stream_idx=-1)
+ * is overflowing, trigger a fake heartbeat on lagging streams.
+ *
+ * @return 1 if heartbeat triggered, 0 otherwise
+ */
+static int overflow_heartbeat(SyncQueue *sq, int stream_idx)
+{
+ SyncQueueStream *st;
+ SyncQueueFrame frame;
+ int64_t tail_ts = AV_NOPTS_VALUE;
+
+ /* if no stream specified, pick the one that is most ahead */
+ if (stream_idx < 0) {
+ int64_t ts = AV_NOPTS_VALUE;
+
+ for (int i = 0; i < sq->nb_streams; i++) {
+ st = &sq->streams[i];
+ if (st->head_ts != AV_NOPTS_VALUE &&
+ (ts == AV_NOPTS_VALUE ||
+ av_compare_ts(ts, sq->streams[stream_idx].tb,
+ st->head_ts, st->tb) < 0)) {
+ ts = st->head_ts;
+ stream_idx = i;
+ }
+ }
+ /* no stream has a timestamp yet -> nothing to do */
+ if (stream_idx < 0)
+ return 0;
+ }
+
+ st = &sq->streams[stream_idx];
+
+ /* get the chosen stream's tail timestamp */
+ for (size_t i = 0; tail_ts == AV_NOPTS_VALUE &&
+ av_fifo_peek(st->fifo, &frame, 1, i) >= 0; i++)
+ tail_ts = frame_ts(sq, frame);
+
+ /* overflow triggers when the tail is over specified duration behind the head */
+ if (tail_ts == AV_NOPTS_VALUE || tail_ts >= st->head_ts ||
+ av_rescale_q(st->head_ts - tail_ts, st->tb, AV_TIME_BASE_Q) < sq->buf_size_us)
+ return 0;
+
+ /* signal a fake timestamp for all streams that prevent tail_ts from being output */
+ tail_ts++;
+ for (unsigned int i = 0; i < sq->nb_streams; i++) {
+ SyncQueueStream *st1 = &sq->streams[i];
+ int64_t ts;
+
+ if (st == st1 || st1->finished ||
+ (st1->head_ts != AV_NOPTS_VALUE &&
+ av_compare_ts(tail_ts, st->tb, st1->head_ts, st1->tb) <= 0))
+ continue;
+
+ ts = av_rescale_q(tail_ts, st->tb, st1->tb);
+ if (st1->head_ts != AV_NOPTS_VALUE)
+ ts = FFMAX(st1->head_ts + 1, ts);
+
+ stream_update_ts(sq, i, ts);
+ }
+
+ return 1;
+}
+
+int sq_send(SyncQueue *sq, unsigned int stream_idx, SyncQueueFrame frame)
+{
+ SyncQueueStream *st;
+ SyncQueueFrame dst;
+ int64_t ts;
+ int ret;
+
+ av_assert0(stream_idx < sq->nb_streams);
+ st = &sq->streams[stream_idx];
+
+ av_assert0(st->tb.num > 0 && st->tb.den > 0);
+
+ if (frame_null(sq, frame)) {
+ finish_stream(sq, stream_idx);
+ return 0;
+ }
+ if (st->finished)
+ return AVERROR_EOF;
+
+ ret = objpool_get(sq->pool, (void**)&dst);
+ if (ret < 0)
+ return ret;
+
+ frame_move(sq, dst, frame);
+
+ ts = frame_ts(sq, dst);
+
+ ret = av_fifo_write(st->fifo, &dst, 1);
+ if (ret < 0) {
+ frame_move(sq, frame, dst);
+ objpool_release(sq->pool, (void**)&dst);
+ return ret;
+ }
+
+ stream_update_ts(sq, stream_idx, ts);
+
+ st->frames_sent++;
+ if (st->frames_sent >= st->frames_max)
+ finish_stream(sq, stream_idx);
+
+ return 0;
+}
+
+static int receive_for_stream(SyncQueue *sq, unsigned int stream_idx,
+ SyncQueueFrame frame)
+{
+ SyncQueueStream *st_head = sq->head_stream >= 0 ?
+ &sq->streams[sq->head_stream] : NULL;
+ SyncQueueStream *st;
+
+ av_assert0(stream_idx < sq->nb_streams);
+ st = &sq->streams[stream_idx];
+
+ if (av_fifo_can_read(st->fifo)) {
+ SyncQueueFrame peek;
+ int64_t ts;
+ int cmp = 1;
+
+ av_fifo_peek(st->fifo, &peek, 1, 0);
+ ts = frame_ts(sq, peek);
+
+ /* check if this stream's tail timestamp does not overtake
+ * the overall queue head */
+ if (ts != AV_NOPTS_VALUE && st_head)
+ cmp = av_compare_ts(ts, st->tb, st_head->head_ts, st_head->tb);
+
+ /* We can release frames that do not end after the queue head.
+ * Frames with no timestamps are just passed through with no conditions.
+ */
+ if (cmp <= 0 || ts == AV_NOPTS_VALUE) {
+ frame_move(sq, frame, peek);
+ objpool_release(sq->pool, (void**)&peek);
+ av_fifo_drain2(st->fifo, 1);
+ return 0;
+ }
+ }
+
+ return (sq->finished || (st->finished && !av_fifo_can_read(st->fifo))) ?
+ AVERROR_EOF : AVERROR(EAGAIN);
+}
+
+static int receive_internal(SyncQueue *sq, int stream_idx, SyncQueueFrame frame)
+{
+ int nb_eof = 0;
+ int ret;
+
+ /* read a frame for a specific stream */
+ if (stream_idx >= 0) {
+ ret = receive_for_stream(sq, stream_idx, frame);
+ return (ret < 0) ? ret : stream_idx;
+ }
+
+ /* read a frame for any stream with available output */
+ for (unsigned int i = 0; i < sq->nb_streams; i++) {
+ ret = receive_for_stream(sq, i, frame);
+ if (ret == AVERROR_EOF || ret == AVERROR(EAGAIN)) {
+ nb_eof += (ret == AVERROR_EOF);
+ continue;
+ }
+ return (ret < 0) ? ret : i;
+ }
+
+ return (nb_eof == sq->nb_streams) ? AVERROR_EOF : AVERROR(EAGAIN);
+}
+
+int sq_receive(SyncQueue *sq, int stream_idx, SyncQueueFrame frame)
+{
+ int ret = receive_internal(sq, stream_idx, frame);
+
+ /* try again if the queue overflowed and triggered a fake heartbeat
+ * for lagging streams */
+ if (ret == AVERROR(EAGAIN) && overflow_heartbeat(sq, stream_idx))
+ ret = receive_internal(sq, stream_idx, frame);
+
+ return ret;
+}
+
+int sq_add_stream(SyncQueue *sq, int limiting)
+{
+ SyncQueueStream *tmp, *st;
+
+ tmp = av_realloc_array(sq->streams, sq->nb_streams + 1, sizeof(*sq->streams));
+ if (!tmp)
+ return AVERROR(ENOMEM);
+ sq->streams = tmp;
+
+ st = &sq->streams[sq->nb_streams];
+ memset(st, 0, sizeof(*st));
+
+ st->fifo = av_fifo_alloc2(1, sizeof(SyncQueueFrame), AV_FIFO_FLAG_AUTO_GROW);
+ if (!st->fifo)
+ return AVERROR(ENOMEM);
+
+ /* we set a valid default, so that a pathological stream that never
+ * receives even a real timebase (and no frames) won't stall all other
+ * streams forever; cf. overflow_heartbeat() */
+ st->tb = (AVRational){ 1, 1 };
+ st->head_ts = AV_NOPTS_VALUE;
+ st->frames_max = UINT64_MAX;
+ st->limiting = limiting;
+
+ return sq->nb_streams++;
+}
+
+void sq_set_tb(SyncQueue *sq, unsigned int stream_idx, AVRational tb)
+{
+ SyncQueueStream *st;
+
+ av_assert0(stream_idx < sq->nb_streams);
+ st = &sq->streams[stream_idx];
+
+ av_assert0(!av_fifo_can_read(st->fifo));
+
+ if (st->head_ts != AV_NOPTS_VALUE)
+ st->head_ts = av_rescale_q(st->head_ts, st->tb, tb);
+
+ st->tb = tb;
+}
+
+void sq_limit_frames(SyncQueue *sq, unsigned int stream_idx, uint64_t frames)
+{
+ SyncQueueStream *st;
+
+ av_assert0(stream_idx < sq->nb_streams);
+ st = &sq->streams[stream_idx];
+
+ st->frames_max = frames;
+ if (st->frames_sent >= st->frames_max)
+ finish_stream(sq, stream_idx);
+}
+
+SyncQueue *sq_alloc(enum SyncQueueType type, int64_t buf_size_us)
+{
+ SyncQueue *sq = av_mallocz(sizeof(*sq));
+
+ if (!sq)
+ return NULL;
+
+ sq->type = type;
+ sq->buf_size_us = buf_size_us;
+
+ sq->head_stream = -1;
+ sq->head_finished_stream = -1;
+
+ sq->pool = (type == SYNC_QUEUE_PACKETS) ? objpool_alloc_packets() :
+ objpool_alloc_frames();
+ if (!sq->pool) {
+ av_freep(&sq);
+ return NULL;
+ }
+
+ return sq;
+}
+
+void sq_free(SyncQueue **psq)
+{
+ SyncQueue *sq = *psq;
+
+ if (!sq)
+ return;
+
+ for (unsigned int i = 0; i < sq->nb_streams; i++) {
+ SyncQueueFrame frame;
+ while (av_fifo_read(sq->streams[i].fifo, &frame, 1) >= 0)
+ objpool_release(sq->pool, (void**)&frame);
+
+ av_fifo_freep2(&sq->streams[i].fifo);
+ }
+
+ av_freep(&sq->streams);
+
+ objpool_free(&sq->pool);
+
+ av_freep(psq);
+}
diff --git a/app/src/main/cpp/ffmpeg/sync_queue.h b/app/src/main/cpp/ffmpeg/sync_queue.h
new file mode 100644
index 00000000..3f823ff0
--- /dev/null
+++ b/app/src/main/cpp/ffmpeg/sync_queue.h
@@ -0,0 +1,109 @@
+/*
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef FFTOOLS_SYNC_QUEUE_H
+#define FFTOOLS_SYNC_QUEUE_H
+
+#include
+
+#include "libavcodec/packet.h"
+
+#include "libavutil/frame.h"
+
+enum SyncQueueType {
+ SYNC_QUEUE_PACKETS,
+ SYNC_QUEUE_FRAMES,
+};
+
+typedef union SyncQueueFrame {
+ AVFrame *f;
+ AVPacket *p;
+} SyncQueueFrame;
+
+#define SQFRAME(frame) ((SyncQueueFrame){ .f = (frame) })
+#define SQPKT(pkt) ((SyncQueueFrame){ .p = (pkt) })
+
+typedef struct SyncQueue SyncQueue;
+
+/**
+ * Allocate a sync queue of the given type.
+ *
+ * @param buf_size_us maximum duration that will be buffered in microseconds
+ */
+SyncQueue *sq_alloc(enum SyncQueueType type, int64_t buf_size_us);
+void sq_free(SyncQueue **sq);
+
+/**
+ * Add a new stream to the sync queue.
+ *
+ * @param limiting whether the stream is limiting, i.e. no other stream can be
+ * longer than this one
+ * @return
+ * - a non-negative stream index on success
+ * - a negative error code on error
+ */
+int sq_add_stream(SyncQueue *sq, int limiting);
+
+/**
+ * Set the timebase for the stream with index stream_idx. Should be called
+ * before sending any frames for this stream.
+ */
+void sq_set_tb(SyncQueue *sq, unsigned int stream_idx, AVRational tb);
+
+/**
+ * Limit the number of output frames for stream with index stream_idx
+ * to max_frames.
+ */
+void sq_limit_frames(SyncQueue *sq, unsigned int stream_idx,
+ uint64_t max_frames);
+
+/**
+ * Submit a frame for the stream with index stream_idx.
+ *
+ * On success, the sync queue takes ownership of the frame and will reset the
+ * contents of the supplied frame. On failure, the frame remains owned by the
+ * caller.
+ *
+ * Sending a frame with NULL contents marks the stream as finished.
+ *
+ * @return
+ * - 0 on success
+ * - AVERROR_EOF when no more frames should be submitted for this stream
+ * - another a negative error code on failure
+ */
+int sq_send(SyncQueue *sq, unsigned int stream_idx, SyncQueueFrame frame);
+
+/**
+ * Read a frame from the queue.
+ *
+ * @param stream_idx index of the stream to read a frame for. May be -1, then
+ * try to read a frame from any stream that is ready for
+ * output.
+ * @param frame output frame will be written here on success. The frame is owned
+ * by the caller.
+ *
+ * @return
+ * - a non-negative index of the stream to which the returned frame belongs
+ * - AVERROR(EAGAIN) when more frames need to be submitted to the queue
+ * - AVERROR_EOF when no more frames will be available for this stream (for any
+ * stream if stream_idx is -1)
+ * - another negative error code on failure
+ */
+int sq_receive(SyncQueue *sq, int stream_idx, SyncQueueFrame frame);
+
+#endif // FFTOOLS_SYNC_QUEUE_H
diff --git a/app/src/main/cpp/ffmpeg/thread_queue.c b/app/src/main/cpp/ffmpeg/thread_queue.c
new file mode 100644
index 00000000..a1ab4ce9
--- /dev/null
+++ b/app/src/main/cpp/ffmpeg/thread_queue.c
@@ -0,0 +1,245 @@
+/*
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include
+#include
+
+#include "libavutil/avassert.h"
+#include "libavutil/error.h"
+#include "libavutil/fifo.h"
+#include "libavutil/intreadwrite.h"
+#include "libavutil/mem.h"
+#include "libavutil/thread.h"
+
+#include "objpool.h"
+#include "thread_queue.h"
+
+enum {
+ FINISHED_SEND = (1 << 0),
+ FINISHED_RECV = (1 << 1),
+};
+
+typedef struct FifoElem {
+ void *obj;
+ unsigned int stream_idx;
+} FifoElem;
+
+struct ThreadQueue {
+ int *finished;
+ unsigned int nb_streams;
+
+ AVFifo *fifo;
+
+ ObjPool *obj_pool;
+ void (*obj_move)(void *dst, void *src);
+
+ pthread_mutex_t lock;
+ pthread_cond_t cond;
+};
+
+void tq_free(ThreadQueue **ptq)
+{
+ ThreadQueue *tq = *ptq;
+
+ if (!tq)
+ return;
+
+ if (tq->fifo) {
+ FifoElem elem;
+ while (av_fifo_read(tq->fifo, &elem, 1) >= 0)
+ objpool_release(tq->obj_pool, &elem.obj);
+ }
+ av_fifo_freep2(&tq->fifo);
+
+ objpool_free(&tq->obj_pool);
+
+ av_freep(&tq->finished);
+
+ pthread_cond_destroy(&tq->cond);
+ pthread_mutex_destroy(&tq->lock);
+
+ av_freep(ptq);
+}
+
+ThreadQueue *tq_alloc(unsigned int nb_streams, size_t queue_size,
+ ObjPool *obj_pool, void (*obj_move)(void *dst, void *src))
+{
+ ThreadQueue *tq;
+ int ret;
+
+ tq = av_mallocz(sizeof(*tq));
+ if (!tq)
+ return NULL;
+
+ ret = pthread_cond_init(&tq->cond, NULL);
+ if (ret) {
+ av_freep(&tq);
+ return NULL;
+ }
+
+ ret = pthread_mutex_init(&tq->lock, NULL);
+ if (ret) {
+ pthread_cond_destroy(&tq->cond);
+ av_freep(&tq);
+ return NULL;
+ }
+
+ tq->finished = av_calloc(nb_streams, sizeof(*tq->finished));
+ if (!tq->finished)
+ goto fail;
+ tq->nb_streams = nb_streams;
+
+ tq->fifo = av_fifo_alloc2(queue_size, sizeof(FifoElem), 0);
+ if (!tq->fifo)
+ goto fail;
+
+ tq->obj_pool = obj_pool;
+ tq->obj_move = obj_move;
+
+ return tq;
+fail:
+ tq_free(&tq);
+ return NULL;
+}
+
+int tq_send(ThreadQueue *tq, unsigned int stream_idx, void *data)
+{
+ int *finished;
+ int ret;
+
+ av_assert0(stream_idx < tq->nb_streams);
+ finished = &tq->finished[stream_idx];
+
+ pthread_mutex_lock(&tq->lock);
+
+ if (*finished & FINISHED_SEND) {
+ ret = AVERROR(EINVAL);
+ goto finish;
+ }
+
+ while (!(*finished & FINISHED_RECV) && !av_fifo_can_write(tq->fifo))
+ pthread_cond_wait(&tq->cond, &tq->lock);
+
+ if (*finished & FINISHED_RECV) {
+ ret = AVERROR_EOF;
+ *finished |= FINISHED_SEND;
+ } else {
+ FifoElem elem = { .stream_idx = stream_idx };
+
+ ret = objpool_get(tq->obj_pool, &elem.obj);
+ if (ret < 0)
+ goto finish;
+
+ tq->obj_move(elem.obj, data);
+
+ ret = av_fifo_write(tq->fifo, &elem, 1);
+ av_assert0(ret >= 0);
+ pthread_cond_broadcast(&tq->cond);
+ }
+
+finish:
+ pthread_mutex_unlock(&tq->lock);
+
+ return ret;
+}
+
+static int receive_locked(ThreadQueue *tq, int *stream_idx,
+ void *data)
+{
+ FifoElem elem;
+ unsigned int nb_finished = 0;
+
+ if (av_fifo_read(tq->fifo, &elem, 1) >= 0) {
+ tq->obj_move(data, elem.obj);
+ objpool_release(tq->obj_pool, &elem.obj);
+ *stream_idx = elem.stream_idx;
+ return 0;
+ }
+
+ for (unsigned int i = 0; i < tq->nb_streams; i++) {
+ if (!(tq->finished[i] & FINISHED_SEND))
+ continue;
+
+ /* return EOF to the consumer at most once for each stream */
+ if (!(tq->finished[i] & FINISHED_RECV)) {
+ tq->finished[i] |= FINISHED_RECV;
+ *stream_idx = i;
+ return AVERROR_EOF;
+ }
+
+ nb_finished++;
+ }
+
+ return nb_finished == tq->nb_streams ? AVERROR_EOF : AVERROR(EAGAIN);
+}
+
+int tq_receive(ThreadQueue *tq, int *stream_idx, void *data)
+{
+ int ret;
+
+ *stream_idx = -1;
+
+ pthread_mutex_lock(&tq->lock);
+
+ while (1) {
+ ret = receive_locked(tq, stream_idx, data);
+ if (ret == AVERROR(EAGAIN)) {
+ pthread_cond_wait(&tq->cond, &tq->lock);
+ continue;
+ }
+
+ break;
+ }
+
+ if (ret == 0)
+ pthread_cond_broadcast(&tq->cond);
+
+ pthread_mutex_unlock(&tq->lock);
+
+ return ret;
+}
+
+void tq_send_finish(ThreadQueue *tq, unsigned int stream_idx)
+{
+ av_assert0(stream_idx < tq->nb_streams);
+
+ pthread_mutex_lock(&tq->lock);
+
+ /* mark the stream as send-finished;
+ * next time the consumer thread tries to read this stream it will get
+ * an EOF and recv-finished flag will be set */
+ tq->finished[stream_idx] |= FINISHED_SEND;
+ pthread_cond_broadcast(&tq->cond);
+
+ pthread_mutex_unlock(&tq->lock);
+}
+
+void tq_receive_finish(ThreadQueue *tq, unsigned int stream_idx)
+{
+ av_assert0(stream_idx < tq->nb_streams);
+
+ pthread_mutex_lock(&tq->lock);
+
+ /* mark the stream as recv-finished;
+ * next time the producer thread tries to send for this stream, it will
+ * get an EOF and send-finished flag will be set */
+ tq->finished[stream_idx] |= FINISHED_RECV;
+ pthread_cond_broadcast(&tq->cond);
+
+ pthread_mutex_unlock(&tq->lock);
+}
diff --git a/app/src/main/cpp/ffmpeg/thread_queue.h b/app/src/main/cpp/ffmpeg/thread_queue.h
new file mode 100644
index 00000000..0cc8c71e
--- /dev/null
+++ b/app/src/main/cpp/ffmpeg/thread_queue.h
@@ -0,0 +1,81 @@
+/*
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef FFTOOLS_THREAD_QUEUE_H
+#define FFTOOLS_THREAD_QUEUE_H
+
+#include
+
+#include "objpool.h"
+
+typedef struct ThreadQueue ThreadQueue;
+
+/**
+ * Allocate a queue for sending data between threads.
+ *
+ * @param nb_streams number of streams for which a distinct EOF state is
+ * maintained
+ * @param queue_size number of items that can be stored in the queue without
+ * blocking
+ * @param obj_pool object pool that will be used to allocate items stored in the
+ * queue; the pool becomes owned by the queue
+ * @param callback that moves the contents between two data pointers
+ */
+ThreadQueue *tq_alloc(unsigned int nb_streams, size_t queue_size,
+ ObjPool *obj_pool, void (*obj_move)(void *dst, void *src));
+void tq_free(ThreadQueue **tq);
+
+/**
+ * Send an item for the given stream to the queue.
+ *
+ * @param data the item to send, its contents will be moved using the callback
+ * provided to tq_alloc(); on failure the item will be left
+ * untouched
+ * @return
+ * - 0 the item was successfully sent
+ * - AVERROR(ENOMEM) could not allocate an item for writing to the FIFO
+ * - AVERROR(EINVAL) the sending side has previously been marked as finished
+ * - AVERROR_EOF the receiving side has marked the given stream as finished
+ */
+int tq_send(ThreadQueue *tq, unsigned int stream_idx, void *data);
+/**
+ * Mark the given stream finished from the sending side.
+ */
+void tq_send_finish(ThreadQueue *tq, unsigned int stream_idx);
+
+/**
+ * Read the next item from the queue.
+ *
+ * @param stream_idx the index of the stream that was processed or -1 will be
+ * written here
+ * @param data the data item will be written here on success using the
+ * callback provided to tq_alloc()
+ * @return
+ * - 0 a data item was successfully read; *stream_idx contains a non-negative
+ * stream index
+ * - AVERROR_EOF When *stream_idx is non-negative, this signals that the sending
+ * side has marked the given stream as finished. This will happen at most once
+ * for each stream. When *stream_idx is -1, all streams are done.
+ */
+int tq_receive(ThreadQueue *tq, int *stream_idx, void *data);
+/**
+ * Mark the given stream finished from the receiving side.
+ */
+void tq_receive_finish(ThreadQueue *tq, unsigned int stream_idx);
+
+#endif // FFTOOLS_THREAD_QUEUE_H
diff --git a/app/src/main/cpp/ffmpeg_cmd.c b/app/src/main/cpp/ffmpeg_cmd.c
index e05a4a7b..776e2b69 100644
--- a/app/src/main/cpp/ffmpeg_cmd.c
+++ b/app/src/main/cpp/ffmpeg_cmd.c
@@ -1,25 +1,120 @@
+
#include
#include "ffmpeg/ffmpeg.h"
+#include "ffmpeg/ffprobe.h"
+#include "ffmpeg_jni_define.h"
+
+#define FFMPEG_TAG "FFmpegCmd"
+#define INPUT_SIZE (8 * 1024)
+
+#define ALOGI(TAG, FORMAT, ...) __android_log_vprint(ANDROID_LOG_INFO, TAG, FORMAT, ##__VA_ARGS__)
+#define ALOGE(TAG, FORMAT, ...) __android_log_vprint(ANDROID_LOG_ERROR, TAG, FORMAT, ##__VA_ARGS__)
+
+int err_count;
+JNIEnv *ff_env;
+jclass ff_class;
+jmethodID ff_method;
+jmethodID msg_method;
+
+void log_callback(void *, int, const char *, va_list);
+
+void init(JNIEnv *env) {
+ ff_env = env;
+ err_count = 0;
+ ff_class = (*env)->FindClass(env, "com/frank/ffmpeg/FFmpegCmd");
+ ff_method = (*env)->GetStaticMethodID(env, ff_class, "onProgressCallback", "(III)V");
+ msg_method = (*env)->GetStaticMethodID(env, ff_class, "onMsgCallback", "(Ljava/lang/String;I)V");
+}
+
+FFMPEG_FUNC(jint, handle, jobjectArray commands) {
+ init(env);
+ // set the level of log
+ av_log_set_level(AV_LOG_INFO);
+ // set the callback of log, and redirect to print android log
+ av_log_set_callback(log_callback);
-JNIEXPORT jint JNICALL Java_com_frank_ffmpeg_FFmpegCmd_handle
-(JNIEnv *env, jclass obj, jobjectArray commands){
int argc = (*env)->GetArrayLength(env, commands);
- char **argv = (char**)malloc(argc * sizeof(char*));
+ char **argv = (char **) malloc(argc * sizeof(char *));
int i;
int result;
for (i = 0; i < argc; i++) {
jstring jstr = (jstring) (*env)->GetObjectArrayElement(env, commands, i);
- char* temp = (char*) (*env)->GetStringUTFChars(env, jstr, 0);
- argv[i] = malloc(1024);
+ char *temp = (char *) (*env)->GetStringUTFChars(env, jstr, 0);
+ argv[i] = malloc(INPUT_SIZE);
strcpy(argv[i], temp);
(*env)->ReleaseStringUTFChars(env, jstr, temp);
}
- //执行ffmpeg命令
- result = run(argc, argv);
- //释放内存
+ //execute ffmpeg cmd
+ result = run(argc, argv);
+ //release memory
for (i = 0; i < argc; i++) {
free(argv[i]);
}
free(argv);
return result;
-}
\ No newline at end of file
+}
+
+FFMPEG_FUNC(void, cancelTaskJni, jint cancel) {
+ cancel_task(cancel);
+}
+
+void msg_callback(const char *format, va_list args, int level) {
+ if (ff_env && msg_method) {
+ char *ff_msg = (char *) malloc(sizeof(char) * INPUT_SIZE);
+ if (!ff_msg)
+ return;
+ vsprintf(ff_msg, format, args);
+ jstring jstr = (*ff_env)->NewStringUTF(ff_env, ff_msg);
+ if (jstr)
+ (*ff_env)->CallStaticVoidMethod(ff_env, ff_class, msg_method, jstr, level);
+ free(ff_msg);
+ }
+}
+
+void log_callback(void *ptr, int level, const char *format, va_list args) {
+ switch (level) {
+ case AV_LOG_INFO:
+ ALOGI(FFMPEG_TAG, format, args);
+ if (format && strncmp("silence", format, 7) == 0) {
+ msg_callback(format, args, 3);
+ }
+ break;
+ case AV_LOG_ERROR:
+ ALOGE(FFMPEG_TAG, format, args);
+ if (err_count < 10) {
+ err_count++;
+ msg_callback(format, args, 6);
+ }
+ break;
+ default:
+ break;
+ }
+}
+
+void progress_callback(int position, int duration, int state) {
+ if (ff_env && ff_class && ff_method) {
+ (*ff_env)->CallStaticVoidMethod(ff_env, ff_class, ff_method, position, duration, state);
+ }
+}
+
+FFMPEG_FUNC(jstring, handleProbe, jobjectArray commands) {
+ int argc = (*env)->GetArrayLength(env, commands);
+ char **argv = (char **) malloc(argc * sizeof(char *));
+ int i;
+ for (i = 0; i < argc; i++) {
+ jstring jstr = (jstring) (*env)->GetObjectArrayElement(env, commands, i);
+ char *temp = (char *) (*env)->GetStringUTFChars(env, jstr, 0);
+ argv[i] = (char *)(malloc(1024));
+ strcpy(argv[i], temp);
+ (*env)->ReleaseStringUTFChars(env, jstr, temp);
+ }
+ //execute ffprobe command
+ char *result = ffprobe_run(argc, argv);
+ //release memory
+ for (i = 0; i < argc; i++) {
+ free(argv[i]);
+ }
+ free(argv);
+
+ return (*env)->NewStringUTF(env, result);
+}
diff --git a/app/src/main/cpp/ffmpeg_jni_define.h b/app/src/main/cpp/ffmpeg_jni_define.h
new file mode 100644
index 00000000..d86714a5
--- /dev/null
+++ b/app/src/main/cpp/ffmpeg_jni_define.h
@@ -0,0 +1,37 @@
+//
+// Created by frank on 2019/11/9.
+//
+
+#ifndef FFMPEGANDROID_FFMPEG_JNI_DEFINE_H
+#define FFMPEGANDROID_FFMPEG_JNI_DEFINE_H
+
+#include
+
+#define LOGI(TAG, FORMAT, ...) __android_log_print(ANDROID_LOG_INFO, TAG, FORMAT, ##__VA_ARGS__)
+#define LOGE(TAG, FORMAT, ...) __android_log_print(ANDROID_LOG_ERROR, TAG, FORMAT, ##__VA_ARGS__)
+
+#define AUDIO_PLAYER_FUNC(RETURN_TYPE, FUNC_NAME, ...) \
+extern "C" { \
+ JNIEXPORT RETURN_TYPE JNICALL Java_com_frank_ffmpeg_AudioPlayer_ ## FUNC_NAME \
+ (JNIEnv *env, jobject thiz, ##__VA_ARGS__);\
+}\
+ JNIEXPORT RETURN_TYPE JNICALL Java_com_frank_ffmpeg_AudioPlayer_ ## FUNC_NAME \
+ (JNIEnv *env, jobject thiz, ##__VA_ARGS__)\
+
+#define FFMPEG_FUNC(RETURN_TYPE, FUNC_NAME, ...) \
+ JNIEXPORT RETURN_TYPE JNICALL Java_com_frank_ffmpeg_FFmpegCmd_ ## FUNC_NAME \
+ (JNIEnv *env, jclass thiz, ##__VA_ARGS__)\
+
+#define VIDEO_PLAYER_FUNC(RETURN_TYPE, FUNC_NAME, ...) \
+ JNIEXPORT RETURN_TYPE JNICALL Java_com_frank_ffmpeg_VideoPlayer_ ## FUNC_NAME \
+ (JNIEnv *env, jobject thiz, ##__VA_ARGS__)\
+
+#define RETRIEVER_FUNC(RETURN_TYPE, FUNC_NAME, ...) \
+extern "C" { \
+ JNIEXPORT RETURN_TYPE JNICALL Java_com_frank_ffmpeg_metadata_FFmpegMediaRetriever_ ## FUNC_NAME \
+ (JNIEnv *env, jobject thiz, ##__VA_ARGS__);\
+}\
+ JNIEXPORT RETURN_TYPE JNICALL Java_com_frank_ffmpeg_metadata_FFmpegMediaRetriever_ ## FUNC_NAME \
+ (JNIEnv *env, jobject thiz, ##__VA_ARGS__)\
+
+#endif //FFMPEGANDROID_FFMPEG_JNI_DEFINE_H
diff --git a/app/src/main/cpp/ffmpeg_pusher.cpp b/app/src/main/cpp/ffmpeg_pusher.cpp
deleted file mode 100644
index c36430c1..00000000
--- a/app/src/main/cpp/ffmpeg_pusher.cpp
+++ /dev/null
@@ -1,178 +0,0 @@
-//
-// Created by frank on 2018/2/2.
-//
-
-#include
-#include
-#include
-
-#define LOG_TAG "FFmpegLive"
-#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__)
-#define LOGI(...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-#include
-#include
-#include
-#include
-
- JNIEXPORT jint JNICALL
- Java_com_frank_ffmpeg_Pusher_pushStream(JNIEnv *env, jobject, jstring filePath, jstring liveUrl) {
-
- AVOutputFormat *output_format = NULL;
- AVFormatContext *in_format = NULL, *out_format = NULL;
- AVPacket packet;
- const char *file_path, *live_url;
- int video_index = -1;
- int ret = 0, i;
- int frame_index = 0;
- int64_t start_time = 0;
-
- file_path = env->GetStringUTFChars(filePath, NULL);
- live_url = env->GetStringUTFChars(liveUrl, NULL);
-
- LOGI("file_path=%s", file_path);
- LOGI("live_url=%s", live_url);
-
- //注册所有组件
- av_register_all();
- //初始化网络
- avformat_network_init();
- //打开输入文件
- if((ret = avformat_open_input(&in_format, file_path, 0, 0)) < 0){
- LOGE("could not open input file...");
- goto end;
- }
- //寻找流信息
- if((ret = avformat_find_stream_info(in_format, 0)) < 0){
- LOGE("could not find stream info...");
- goto end;
- }
- //
- for(i=0; inb_streams; i++){
- //找到视频流
- if(in_format->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO){
- video_index = i;
- break;
- }
- }
- av_dump_format(in_format, 0, file_path, 0);
- //分配输出封装格式上下文, rtmp协议支持格式为flv
- avformat_alloc_output_context2(&out_format, NULL, "flv", live_url);
- if(!out_format){
- LOGE("could not alloc output context...");
- ret = AVERROR_UNKNOWN;
- goto end;
- }
- //根据输入流来创建输出流
- for(i=0; inb_streams; i++){
- AVStream *in_stream = in_format->streams[i];
- AVStream *out_stream = avformat_new_stream(out_format, in_stream->codec->codec);
- if(!out_stream){
- LOGE("could not alloc output stream...");
- ret = AVERROR_UNKNOWN;
- goto end;
- }
- //复制封装格式上下文
- ret = avcodec_copy_context(out_stream->codec, in_stream->codec);
- if(ret < 0){
- LOGE("could not copy context...");
- goto end;
- }
- out_stream->codec->codec_tag = 0;
- if(out_format->oformat->flags & AVFMT_GLOBALHEADER){
- out_stream->codec->flags |= CODEC_FLAG_GLOBAL_HEADER;
- }
- }
- //封装格式
- output_format = out_format->oformat;
- //打开输出文件/URL
- if(!(output_format->flags & AVFMT_NOFILE)){
- ret = avio_open(&out_format->pb, live_url, AVIO_FLAG_WRITE);
- if(ret < 0){
- LOGE("could not open output url '%s'", live_url);
- goto end;
- }
- }
- //写文件头
- ret = avformat_write_header(out_format, NULL);
- if(ret < 0){
- LOGE("could not write header...");
- goto end;
- }
- //获取开始时间
- start_time = av_gettime();
- //开始循环读一帧数据
- while (1){
- AVStream *in_stream, *out_stream;
- ret = av_read_frame(in_format, &packet);
- if(ret < 0){
- break;
- }
- //计算帧间隔,参考时钟/采样率
- if(packet.pts == AV_NOPTS_VALUE){
- AVRational time_base = in_format->streams[video_index]->time_base;
- int64_t cal_duration = (int64_t)(AV_TIME_BASE/av_q2d(in_format->streams[video_index]->r_frame_rate));
- packet.pts = (int64_t)((frame_index * cal_duration)/(av_q2d(time_base) * AV_TIME_BASE));
- packet.dts = packet.pts;
- packet.duration = (int64_t)(cal_duration/(av_q2d(time_base) * AV_TIME_BASE));
- }
- //视频帧之间延时
- if(packet.stream_index == video_index){
- AVRational time_base = in_format->streams[video_index]->time_base;
- AVRational time_base_q = {1, AV_TIME_BASE};
- int64_t pts_time = av_rescale_q(packet.dts, time_base, time_base_q);
- int64_t now_time = av_gettime() - start_time;
- //延时以保持同步
- if(pts_time > now_time){
- av_usleep((unsigned int)(pts_time - now_time));
- }
- }
- in_stream = in_format->streams[packet.stream_index];
- out_stream = out_format->streams[packet.stream_index];
-
- //pts/dts转换
- packet.pts = av_rescale_q_rnd(packet.pts, in_stream->time_base, out_stream->time_base,
- (AVRounding)(AV_ROUND_NEAR_INF | AV_ROUND_PASS_MINMAX));
- packet.dts = av_rescale_q_rnd(packet.dts, in_stream->time_base, out_stream->time_base,
- (AVRounding)(AV_ROUND_NEAR_INF | AV_ROUND_PASS_MINMAX));
- packet.duration = av_rescale_q(packet.duration, in_stream->time_base, out_stream->time_base);
- packet.pos = -1;
-
- //视频帧计数
- if(packet.stream_index == video_index){
- frame_index ++;
- LOGI("write frame = %d", frame_index);
- }
- //写一帧数据
- ret = av_interleaved_write_frame(out_format, &packet);
- if(ret < 0){
- LOGE("could not write frame...");
- break;
- }
- //释放包数据内存
- av_packet_unref(&packet);
- }
- //写文件尾
- av_write_trailer(out_format);
-
- end:
- avformat_close_input(&in_format);
- if(out_format && !(out_format->flags & AVFMT_NOFILE)){
- avio_close(out_format->pb);
- }
- avformat_free_context(in_format);
- avformat_free_context(out_format);
- env->ReleaseStringUTFChars(filePath, file_path);
- env->ReleaseStringUTFChars(liveUrl, live_url);
- if(ret < 0 && ret != AVERROR_EOF){
- return -1;
- }
- return 0;
- }
-
-#ifdef __cplusplus
-}
-#endif
\ No newline at end of file
diff --git a/app/src/main/cpp/include/libavcodec/avcodec.h b/app/src/main/cpp/include/libavcodec/avcodec.h
deleted file mode 100644
index 10947396..00000000
--- a/app/src/main/cpp/include/libavcodec/avcodec.h
+++ /dev/null
@@ -1,5402 +0,0 @@
-/*
- * copyright (c) 2001 Fabrice Bellard
- *
- * This file is part of FFmpeg.
- *
- * FFmpeg is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * FFmpeg is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with FFmpeg; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- */
-
-#ifndef AVCODEC_AVCODEC_H
-#define AVCODEC_AVCODEC_H
-
-/**
- * @file
- * @ingroup libavc
- * Libavcodec external API header
- */
-
-#include
-#include "libavutil/samplefmt.h"
-#include "libavutil/attributes.h"
-#include "libavutil/avutil.h"
-#include "libavutil/buffer.h"
-#include "libavutil/cpu.h"
-#include "libavutil/channel_layout.h"
-#include "libavutil/dict.h"
-#include "libavutil/frame.h"
-#include "libavutil/log.h"
-#include "libavutil/pixfmt.h"
-#include "libavutil/rational.h"
-
-#include "version.h"
-
-/**
- * @defgroup libavc Encoding/Decoding Library
- * @{
- *
- * @defgroup lavc_decoding Decoding
- * @{
- * @}
- *
- * @defgroup lavc_encoding Encoding
- * @{
- * @}
- *
- * @defgroup lavc_codec Codecs
- * @{
- * @defgroup lavc_codec_native Native Codecs
- * @{
- * @}
- * @defgroup lavc_codec_wrappers External library wrappers
- * @{
- * @}
- * @defgroup lavc_codec_hwaccel Hardware Accelerators bridge
- * @{
- * @}
- * @}
- * @defgroup lavc_internal Internal
- * @{
- * @}
- * @}
- *
- */
-
-/**
- * @defgroup lavc_core Core functions/structures.
- * @ingroup libavc
- *
- * Basic definitions, functions for querying libavcodec capabilities,
- * allocating core structures, etc.
- * @{
- */
-
-
-/**
- * Identify the syntax and semantics of the bitstream.
- * The principle is roughly:
- * Two decoders with the same ID can decode the same streams.
- * Two encoders with the same ID can encode compatible streams.
- * There may be slight deviations from the principle due to implementation
- * details.
- *
- * If you add a codec ID to this list, add it so that
- * 1. no value of a existing codec ID changes (that would break ABI),
- * 2. it is as close as possible to similar codecs
- *
- * After adding new codec IDs, do not forget to add an entry to the codec
- * descriptor list and bump libavcodec minor version.
- */
-enum AVCodecID {
- AV_CODEC_ID_NONE,
-
- /* video codecs */
- AV_CODEC_ID_MPEG1VIDEO,
- AV_CODEC_ID_MPEG2VIDEO, ///< preferred ID for MPEG-1/2 video decoding
-#if FF_API_XVMC
- AV_CODEC_ID_MPEG2VIDEO_XVMC,
-#endif /* FF_API_XVMC */
- AV_CODEC_ID_H261,
- AV_CODEC_ID_H263,
- AV_CODEC_ID_RV10,
- AV_CODEC_ID_RV20,
- AV_CODEC_ID_MJPEG,
- AV_CODEC_ID_MJPEGB,
- AV_CODEC_ID_LJPEG,
- AV_CODEC_ID_SP5X,
- AV_CODEC_ID_JPEGLS,
- AV_CODEC_ID_MPEG4,
- AV_CODEC_ID_RAWVIDEO,
- AV_CODEC_ID_MSMPEG4V1,
- AV_CODEC_ID_MSMPEG4V2,
- AV_CODEC_ID_MSMPEG4V3,
- AV_CODEC_ID_WMV1,
- AV_CODEC_ID_WMV2,
- AV_CODEC_ID_H263P,
- AV_CODEC_ID_H263I,
- AV_CODEC_ID_FLV1,
- AV_CODEC_ID_SVQ1,
- AV_CODEC_ID_SVQ3,
- AV_CODEC_ID_DVVIDEO,
- AV_CODEC_ID_HUFFYUV,
- AV_CODEC_ID_CYUV,
- AV_CODEC_ID_H264,
- AV_CODEC_ID_INDEO3,
- AV_CODEC_ID_VP3,
- AV_CODEC_ID_THEORA,
- AV_CODEC_ID_ASV1,
- AV_CODEC_ID_ASV2,
- AV_CODEC_ID_FFV1,
- AV_CODEC_ID_4XM,
- AV_CODEC_ID_VCR1,
- AV_CODEC_ID_CLJR,
- AV_CODEC_ID_MDEC,
- AV_CODEC_ID_ROQ,
- AV_CODEC_ID_INTERPLAY_VIDEO,
- AV_CODEC_ID_XAN_WC3,
- AV_CODEC_ID_XAN_WC4,
- AV_CODEC_ID_RPZA,
- AV_CODEC_ID_CINEPAK,
- AV_CODEC_ID_WS_VQA,
- AV_CODEC_ID_MSRLE,
- AV_CODEC_ID_MSVIDEO1,
- AV_CODEC_ID_IDCIN,
- AV_CODEC_ID_8BPS,
- AV_CODEC_ID_SMC,
- AV_CODEC_ID_FLIC,
- AV_CODEC_ID_TRUEMOTION1,
- AV_CODEC_ID_VMDVIDEO,
- AV_CODEC_ID_MSZH,
- AV_CODEC_ID_ZLIB,
- AV_CODEC_ID_QTRLE,
- AV_CODEC_ID_TSCC,
- AV_CODEC_ID_ULTI,
- AV_CODEC_ID_QDRAW,
- AV_CODEC_ID_VIXL,
- AV_CODEC_ID_QPEG,
- AV_CODEC_ID_PNG,
- AV_CODEC_ID_PPM,
- AV_CODEC_ID_PBM,
- AV_CODEC_ID_PGM,
- AV_CODEC_ID_PGMYUV,
- AV_CODEC_ID_PAM,
- AV_CODEC_ID_FFVHUFF,
- AV_CODEC_ID_RV30,
- AV_CODEC_ID_RV40,
- AV_CODEC_ID_VC1,
- AV_CODEC_ID_WMV3,
- AV_CODEC_ID_LOCO,
- AV_CODEC_ID_WNV1,
- AV_CODEC_ID_AASC,
- AV_CODEC_ID_INDEO2,
- AV_CODEC_ID_FRAPS,
- AV_CODEC_ID_TRUEMOTION2,
- AV_CODEC_ID_BMP,
- AV_CODEC_ID_CSCD,
- AV_CODEC_ID_MMVIDEO,
- AV_CODEC_ID_ZMBV,
- AV_CODEC_ID_AVS,
- AV_CODEC_ID_SMACKVIDEO,
- AV_CODEC_ID_NUV,
- AV_CODEC_ID_KMVC,
- AV_CODEC_ID_FLASHSV,
- AV_CODEC_ID_CAVS,
- AV_CODEC_ID_JPEG2000,
- AV_CODEC_ID_VMNC,
- AV_CODEC_ID_VP5,
- AV_CODEC_ID_VP6,
- AV_CODEC_ID_VP6F,
- AV_CODEC_ID_TARGA,
- AV_CODEC_ID_DSICINVIDEO,
- AV_CODEC_ID_TIERTEXSEQVIDEO,
- AV_CODEC_ID_TIFF,
- AV_CODEC_ID_GIF,
- AV_CODEC_ID_DXA,
- AV_CODEC_ID_DNXHD,
- AV_CODEC_ID_THP,
- AV_CODEC_ID_SGI,
- AV_CODEC_ID_C93,
- AV_CODEC_ID_BETHSOFTVID,
- AV_CODEC_ID_PTX,
- AV_CODEC_ID_TXD,
- AV_CODEC_ID_VP6A,
- AV_CODEC_ID_AMV,
- AV_CODEC_ID_VB,
- AV_CODEC_ID_PCX,
- AV_CODEC_ID_SUNRAST,
- AV_CODEC_ID_INDEO4,
- AV_CODEC_ID_INDEO5,
- AV_CODEC_ID_MIMIC,
- AV_CODEC_ID_RL2,
- AV_CODEC_ID_ESCAPE124,
- AV_CODEC_ID_DIRAC,
- AV_CODEC_ID_BFI,
- AV_CODEC_ID_CMV,
- AV_CODEC_ID_MOTIONPIXELS,
- AV_CODEC_ID_TGV,
- AV_CODEC_ID_TGQ,
- AV_CODEC_ID_TQI,
- AV_CODEC_ID_AURA,
- AV_CODEC_ID_AURA2,
- AV_CODEC_ID_V210X,
- AV_CODEC_ID_TMV,
- AV_CODEC_ID_V210,
- AV_CODEC_ID_DPX,
- AV_CODEC_ID_MAD,
- AV_CODEC_ID_FRWU,
- AV_CODEC_ID_FLASHSV2,
- AV_CODEC_ID_CDGRAPHICS,
- AV_CODEC_ID_R210,
- AV_CODEC_ID_ANM,
- AV_CODEC_ID_BINKVIDEO,
- AV_CODEC_ID_IFF_ILBM,
-#define AV_CODEC_ID_IFF_BYTERUN1 AV_CODEC_ID_IFF_ILBM
- AV_CODEC_ID_KGV1,
- AV_CODEC_ID_YOP,
- AV_CODEC_ID_VP8,
- AV_CODEC_ID_PICTOR,
- AV_CODEC_ID_ANSI,
- AV_CODEC_ID_A64_MULTI,
- AV_CODEC_ID_A64_MULTI5,
- AV_CODEC_ID_R10K,
- AV_CODEC_ID_MXPEG,
- AV_CODEC_ID_LAGARITH,
- AV_CODEC_ID_PRORES,
- AV_CODEC_ID_JV,
- AV_CODEC_ID_DFA,
- AV_CODEC_ID_WMV3IMAGE,
- AV_CODEC_ID_VC1IMAGE,
- AV_CODEC_ID_UTVIDEO,
- AV_CODEC_ID_BMV_VIDEO,
- AV_CODEC_ID_VBLE,
- AV_CODEC_ID_DXTORY,
- AV_CODEC_ID_V410,
- AV_CODEC_ID_XWD,
- AV_CODEC_ID_CDXL,
- AV_CODEC_ID_XBM,
- AV_CODEC_ID_ZEROCODEC,
- AV_CODEC_ID_MSS1,
- AV_CODEC_ID_MSA1,
- AV_CODEC_ID_TSCC2,
- AV_CODEC_ID_MTS2,
- AV_CODEC_ID_CLLC,
- AV_CODEC_ID_MSS2,
- AV_CODEC_ID_VP9,
- AV_CODEC_ID_AIC,
- AV_CODEC_ID_ESCAPE130,
- AV_CODEC_ID_G2M,
- AV_CODEC_ID_WEBP,
- AV_CODEC_ID_HNM4_VIDEO,
- AV_CODEC_ID_HEVC,
-#define AV_CODEC_ID_H265 AV_CODEC_ID_HEVC
- AV_CODEC_ID_FIC,
- AV_CODEC_ID_ALIAS_PIX,
- AV_CODEC_ID_BRENDER_PIX,
- AV_CODEC_ID_PAF_VIDEO,
- AV_CODEC_ID_EXR,
- AV_CODEC_ID_VP7,
- AV_CODEC_ID_SANM,
- AV_CODEC_ID_SGIRLE,
- AV_CODEC_ID_MVC1,
- AV_CODEC_ID_MVC2,
- AV_CODEC_ID_HQX,
- AV_CODEC_ID_TDSC,
- AV_CODEC_ID_HQ_HQA,
- AV_CODEC_ID_HAP,
- AV_CODEC_ID_DDS,
- AV_CODEC_ID_DXV,
- AV_CODEC_ID_SCREENPRESSO,
- AV_CODEC_ID_RSCC,
-
- AV_CODEC_ID_Y41P = 0x8000,
- AV_CODEC_ID_AVRP,
- AV_CODEC_ID_012V,
- AV_CODEC_ID_AVUI,
- AV_CODEC_ID_AYUV,
- AV_CODEC_ID_TARGA_Y216,
- AV_CODEC_ID_V308,
- AV_CODEC_ID_V408,
- AV_CODEC_ID_YUV4,
- AV_CODEC_ID_AVRN,
- AV_CODEC_ID_CPIA,
- AV_CODEC_ID_XFACE,
- AV_CODEC_ID_SNOW,
- AV_CODEC_ID_SMVJPEG,
- AV_CODEC_ID_APNG,
- AV_CODEC_ID_DAALA,
- AV_CODEC_ID_CFHD,
-
- /* various PCM "codecs" */
- AV_CODEC_ID_FIRST_AUDIO = 0x10000, ///< A dummy id pointing at the start of audio codecs
- AV_CODEC_ID_PCM_S16LE = 0x10000,
- AV_CODEC_ID_PCM_S16BE,
- AV_CODEC_ID_PCM_U16LE,
- AV_CODEC_ID_PCM_U16BE,
- AV_CODEC_ID_PCM_S8,
- AV_CODEC_ID_PCM_U8,
- AV_CODEC_ID_PCM_MULAW,
- AV_CODEC_ID_PCM_ALAW,
- AV_CODEC_ID_PCM_S32LE,
- AV_CODEC_ID_PCM_S32BE,
- AV_CODEC_ID_PCM_U32LE,
- AV_CODEC_ID_PCM_U32BE,
- AV_CODEC_ID_PCM_S24LE,
- AV_CODEC_ID_PCM_S24BE,
- AV_CODEC_ID_PCM_U24LE,
- AV_CODEC_ID_PCM_U24BE,
- AV_CODEC_ID_PCM_S24DAUD,
- AV_CODEC_ID_PCM_ZORK,
- AV_CODEC_ID_PCM_S16LE_PLANAR,
- AV_CODEC_ID_PCM_DVD,
- AV_CODEC_ID_PCM_F32BE,
- AV_CODEC_ID_PCM_F32LE,
- AV_CODEC_ID_PCM_F64BE,
- AV_CODEC_ID_PCM_F64LE,
- AV_CODEC_ID_PCM_BLURAY,
- AV_CODEC_ID_PCM_LXF,
- AV_CODEC_ID_S302M,
- AV_CODEC_ID_PCM_S8_PLANAR,
- AV_CODEC_ID_PCM_S24LE_PLANAR,
- AV_CODEC_ID_PCM_S32LE_PLANAR,
- AV_CODEC_ID_PCM_S16BE_PLANAR,
- /* new PCM "codecs" should be added right below this line starting with
- * an explicit value of for example 0x10800
- */
-
- /* various ADPCM codecs */
- AV_CODEC_ID_ADPCM_IMA_QT = 0x11000,
- AV_CODEC_ID_ADPCM_IMA_WAV,
- AV_CODEC_ID_ADPCM_IMA_DK3,
- AV_CODEC_ID_ADPCM_IMA_DK4,
- AV_CODEC_ID_ADPCM_IMA_WS,
- AV_CODEC_ID_ADPCM_IMA_SMJPEG,
- AV_CODEC_ID_ADPCM_MS,
- AV_CODEC_ID_ADPCM_4XM,
- AV_CODEC_ID_ADPCM_XA,
- AV_CODEC_ID_ADPCM_ADX,
- AV_CODEC_ID_ADPCM_EA,
- AV_CODEC_ID_ADPCM_G726,
- AV_CODEC_ID_ADPCM_CT,
- AV_CODEC_ID_ADPCM_SWF,
- AV_CODEC_ID_ADPCM_YAMAHA,
- AV_CODEC_ID_ADPCM_SBPRO_4,
- AV_CODEC_ID_ADPCM_SBPRO_3,
- AV_CODEC_ID_ADPCM_SBPRO_2,
- AV_CODEC_ID_ADPCM_THP,
- AV_CODEC_ID_ADPCM_IMA_AMV,
- AV_CODEC_ID_ADPCM_EA_R1,
- AV_CODEC_ID_ADPCM_EA_R3,
- AV_CODEC_ID_ADPCM_EA_R2,
- AV_CODEC_ID_ADPCM_IMA_EA_SEAD,
- AV_CODEC_ID_ADPCM_IMA_EA_EACS,
- AV_CODEC_ID_ADPCM_EA_XAS,
- AV_CODEC_ID_ADPCM_EA_MAXIS_XA,
- AV_CODEC_ID_ADPCM_IMA_ISS,
- AV_CODEC_ID_ADPCM_G722,
- AV_CODEC_ID_ADPCM_IMA_APC,
- AV_CODEC_ID_ADPCM_VIMA,
-#if FF_API_VIMA_DECODER
- AV_CODEC_ID_VIMA = AV_CODEC_ID_ADPCM_VIMA,
-#endif
-
- AV_CODEC_ID_ADPCM_AFC = 0x11800,
- AV_CODEC_ID_ADPCM_IMA_OKI,
- AV_CODEC_ID_ADPCM_DTK,
- AV_CODEC_ID_ADPCM_IMA_RAD,
- AV_CODEC_ID_ADPCM_G726LE,
- AV_CODEC_ID_ADPCM_THP_LE,
- AV_CODEC_ID_ADPCM_PSX,
- AV_CODEC_ID_ADPCM_AICA,
-
- /* AMR */
- AV_CODEC_ID_AMR_NB = 0x12000,
- AV_CODEC_ID_AMR_WB,
-
- /* RealAudio codecs*/
- AV_CODEC_ID_RA_144 = 0x13000,
- AV_CODEC_ID_RA_288,
-
- /* various DPCM codecs */
- AV_CODEC_ID_ROQ_DPCM = 0x14000,
- AV_CODEC_ID_INTERPLAY_DPCM,
- AV_CODEC_ID_XAN_DPCM,
- AV_CODEC_ID_SOL_DPCM,
-
- AV_CODEC_ID_SDX2_DPCM = 0x14800,
-
- /* audio codecs */
- AV_CODEC_ID_MP2 = 0x15000,
- AV_CODEC_ID_MP3, ///< preferred ID for decoding MPEG audio layer 1, 2 or 3
- AV_CODEC_ID_AAC,
- AV_CODEC_ID_AC3,
- AV_CODEC_ID_DTS,
- AV_CODEC_ID_VORBIS,
- AV_CODEC_ID_DVAUDIO,
- AV_CODEC_ID_WMAV1,
- AV_CODEC_ID_WMAV2,
- AV_CODEC_ID_MACE3,
- AV_CODEC_ID_MACE6,
- AV_CODEC_ID_VMDAUDIO,
- AV_CODEC_ID_FLAC,
- AV_CODEC_ID_MP3ADU,
- AV_CODEC_ID_MP3ON4,
- AV_CODEC_ID_SHORTEN,
- AV_CODEC_ID_ALAC,
- AV_CODEC_ID_WESTWOOD_SND1,
- AV_CODEC_ID_GSM, ///< as in Berlin toast format
- AV_CODEC_ID_QDM2,
- AV_CODEC_ID_COOK,
- AV_CODEC_ID_TRUESPEECH,
- AV_CODEC_ID_TTA,
- AV_CODEC_ID_SMACKAUDIO,
- AV_CODEC_ID_QCELP,
- AV_CODEC_ID_WAVPACK,
- AV_CODEC_ID_DSICINAUDIO,
- AV_CODEC_ID_IMC,
- AV_CODEC_ID_MUSEPACK7,
- AV_CODEC_ID_MLP,
- AV_CODEC_ID_GSM_MS, /* as found in WAV */
- AV_CODEC_ID_ATRAC3,
-#if FF_API_VOXWARE
- AV_CODEC_ID_VOXWARE,
-#endif
- AV_CODEC_ID_APE,
- AV_CODEC_ID_NELLYMOSER,
- AV_CODEC_ID_MUSEPACK8,
- AV_CODEC_ID_SPEEX,
- AV_CODEC_ID_WMAVOICE,
- AV_CODEC_ID_WMAPRO,
- AV_CODEC_ID_WMALOSSLESS,
- AV_CODEC_ID_ATRAC3P,
- AV_CODEC_ID_EAC3,
- AV_CODEC_ID_SIPR,
- AV_CODEC_ID_MP1,
- AV_CODEC_ID_TWINVQ,
- AV_CODEC_ID_TRUEHD,
- AV_CODEC_ID_MP4ALS,
- AV_CODEC_ID_ATRAC1,
- AV_CODEC_ID_BINKAUDIO_RDFT,
- AV_CODEC_ID_BINKAUDIO_DCT,
- AV_CODEC_ID_AAC_LATM,
- AV_CODEC_ID_QDMC,
- AV_CODEC_ID_CELT,
- AV_CODEC_ID_G723_1,
- AV_CODEC_ID_G729,
- AV_CODEC_ID_8SVX_EXP,
- AV_CODEC_ID_8SVX_FIB,
- AV_CODEC_ID_BMV_AUDIO,
- AV_CODEC_ID_RALF,
- AV_CODEC_ID_IAC,
- AV_CODEC_ID_ILBC,
- AV_CODEC_ID_OPUS,
- AV_CODEC_ID_COMFORT_NOISE,
- AV_CODEC_ID_TAK,
- AV_CODEC_ID_METASOUND,
- AV_CODEC_ID_PAF_AUDIO,
- AV_CODEC_ID_ON2AVC,
- AV_CODEC_ID_DSS_SP,
-
- AV_CODEC_ID_FFWAVESYNTH = 0x15800,
- AV_CODEC_ID_SONIC,
- AV_CODEC_ID_SONIC_LS,
- AV_CODEC_ID_EVRC,
- AV_CODEC_ID_SMV,
- AV_CODEC_ID_DSD_LSBF,
- AV_CODEC_ID_DSD_MSBF,
- AV_CODEC_ID_DSD_LSBF_PLANAR,
- AV_CODEC_ID_DSD_MSBF_PLANAR,
- AV_CODEC_ID_4GV,
- AV_CODEC_ID_INTERPLAY_ACM,
- AV_CODEC_ID_XMA1,
- AV_CODEC_ID_XMA2,
-
- /* subtitle codecs */
- AV_CODEC_ID_FIRST_SUBTITLE = 0x17000, ///< A dummy ID pointing at the start of subtitle codecs.
- AV_CODEC_ID_DVD_SUBTITLE = 0x17000,
- AV_CODEC_ID_DVB_SUBTITLE,
- AV_CODEC_ID_TEXT, ///< raw UTF-8 text
- AV_CODEC_ID_XSUB,
- AV_CODEC_ID_SSA,
- AV_CODEC_ID_MOV_TEXT,
- AV_CODEC_ID_HDMV_PGS_SUBTITLE,
- AV_CODEC_ID_DVB_TELETEXT,
- AV_CODEC_ID_SRT,
-
- AV_CODEC_ID_MICRODVD = 0x17800,
- AV_CODEC_ID_EIA_608,
- AV_CODEC_ID_JACOSUB,
- AV_CODEC_ID_SAMI,
- AV_CODEC_ID_REALTEXT,
- AV_CODEC_ID_STL,
- AV_CODEC_ID_SUBVIEWER1,
- AV_CODEC_ID_SUBVIEWER,
- AV_CODEC_ID_SUBRIP,
- AV_CODEC_ID_WEBVTT,
- AV_CODEC_ID_MPL2,
- AV_CODEC_ID_VPLAYER,
- AV_CODEC_ID_PJS,
- AV_CODEC_ID_ASS,
- AV_CODEC_ID_HDMV_TEXT_SUBTITLE,
-
- /* other specific kind of codecs (generally used for attachments) */
- AV_CODEC_ID_FIRST_UNKNOWN = 0x18000, ///< A dummy ID pointing at the start of various fake codecs.
- AV_CODEC_ID_TTF = 0x18000,
-
- AV_CODEC_ID_BINTEXT = 0x18800,
- AV_CODEC_ID_XBIN,
- AV_CODEC_ID_IDF,
- AV_CODEC_ID_OTF,
- AV_CODEC_ID_SMPTE_KLV,
- AV_CODEC_ID_DVD_NAV,
- AV_CODEC_ID_TIMED_ID3,
- AV_CODEC_ID_BIN_DATA,
-
-
- AV_CODEC_ID_PROBE = 0x19000, ///< codec_id is not known (like AV_CODEC_ID_NONE) but lavf should attempt to identify it
-
- AV_CODEC_ID_MPEG2TS = 0x20000, /**< _FAKE_ codec to indicate a raw MPEG-2 TS
- * stream (only used by libavformat) */
- AV_CODEC_ID_MPEG4SYSTEMS = 0x20001, /**< _FAKE_ codec to indicate a MPEG-4 Systems
- * stream (only used by libavformat) */
- AV_CODEC_ID_FFMETADATA = 0x21000, ///< Dummy codec for streams containing only metadata information.
- AV_CODEC_ID_WRAPPED_AVFRAME = 0x21001, ///< Passthrough codec, AVFrames wrapped in AVPacket
-};
-
-/**
- * This struct describes the properties of a single codec described by an
- * AVCodecID.
- * @see avcodec_descriptor_get()
- */
-typedef struct AVCodecDescriptor {
- enum AVCodecID id;
- enum AVMediaType type;
- /**
- * Name of the codec described by this descriptor. It is non-empty and
- * unique for each codec descriptor. It should contain alphanumeric
- * characters and '_' only.
- */
- const char *name;
- /**
- * A more descriptive name for this codec. May be NULL.
- */
- const char *long_name;
- /**
- * Codec properties, a combination of AV_CODEC_PROP_* flags.
- */
- int props;
- /**
- * MIME type(s) associated with the codec.
- * May be NULL; if not, a NULL-terminated array of MIME types.
- * The first item is always non-NULL and is the preferred MIME type.
- */
- const char *const *mime_types;
- /**
- * If non-NULL, an array of profiles recognized for this codec.
- * Terminated with FF_PROFILE_UNKNOWN.
- */
- const struct AVProfile *profiles;
-} AVCodecDescriptor;
-
-/**
- * Codec uses only intra compression.
- * Video codecs only.
- */
-#define AV_CODEC_PROP_INTRA_ONLY (1 << 0)
-/**
- * Codec supports lossy compression. Audio and video codecs only.
- * @note a codec may support both lossy and lossless
- * compression modes
- */
-#define AV_CODEC_PROP_LOSSY (1 << 1)
-/**
- * Codec supports lossless compression. Audio and video codecs only.
- */
-#define AV_CODEC_PROP_LOSSLESS (1 << 2)
-/**
- * Codec supports frame reordering. That is, the coded order (the order in which
- * the encoded packets are output by the encoders / stored / input to the
- * decoders) may be different from the presentation order of the corresponding
- * frames.
- *
- * For codecs that do not have this property set, PTS and DTS should always be
- * equal.
- */
-#define AV_CODEC_PROP_REORDER (1 << 3)
-/**
- * Subtitle codec is bitmap based
- * Decoded AVSubtitle data can be read from the AVSubtitleRect->pict field.
- */
-#define AV_CODEC_PROP_BITMAP_SUB (1 << 16)
-/**
- * Subtitle codec is text based.
- * Decoded AVSubtitle data can be read from the AVSubtitleRect->ass field.
- */
-#define AV_CODEC_PROP_TEXT_SUB (1 << 17)
-
-/**
- * @ingroup lavc_decoding
- * Required number of additionally allocated bytes at the end of the input bitstream for decoding.
- * This is mainly needed because some optimized bitstream readers read
- * 32 or 64 bit at once and could read over the end.
- * Note: If the first 23 bits of the additional bytes are not 0, then damaged
- * MPEG bitstreams could cause overread and segfault.
- */
-#define AV_INPUT_BUFFER_PADDING_SIZE 32
-
-/**
- * @ingroup lavc_encoding
- * minimum encoding buffer size
- * Used to avoid some checks during header writing.
- */
-#define AV_INPUT_BUFFER_MIN_SIZE 16384
-
-#if FF_API_WITHOUT_PREFIX
-/**
- * @deprecated use AV_INPUT_BUFFER_PADDING_SIZE instead
- */
-#define FF_INPUT_BUFFER_PADDING_SIZE 32
-
-/**
- * @deprecated use AV_INPUT_BUFFER_MIN_SIZE instead
- */
-#define FF_MIN_BUFFER_SIZE 16384
-#endif /* FF_API_WITHOUT_PREFIX */
-
-/**
- * @ingroup lavc_encoding
- * motion estimation type.
- * @deprecated use codec private option instead
- */
-#if FF_API_MOTION_EST
-enum Motion_Est_ID {
- ME_ZERO = 1, ///< no search, that is use 0,0 vector whenever one is needed
- ME_FULL,
- ME_LOG,
- ME_PHODS,
- ME_EPZS, ///< enhanced predictive zonal search
- ME_X1, ///< reserved for experiments
- ME_HEX, ///< hexagon based search
- ME_UMH, ///< uneven multi-hexagon search
- ME_TESA, ///< transformed exhaustive search algorithm
- ME_ITER=50, ///< iterative search
-};
-#endif
-
-/**
- * @ingroup lavc_decoding
- */
-enum AVDiscard{
- /* We leave some space between them for extensions (drop some
- * keyframes for intra-only or drop just some bidir frames). */
- AVDISCARD_NONE =-16, ///< discard nothing
- AVDISCARD_DEFAULT = 0, ///< discard useless packets like 0 size packets in avi
- AVDISCARD_NONREF = 8, ///< discard all non reference
- AVDISCARD_BIDIR = 16, ///< discard all bidirectional frames
- AVDISCARD_NONINTRA= 24, ///< discard all non intra frames
- AVDISCARD_NONKEY = 32, ///< discard all frames except keyframes
- AVDISCARD_ALL = 48, ///< discard all
-};
-
-enum AVAudioServiceType {
- AV_AUDIO_SERVICE_TYPE_MAIN = 0,
- AV_AUDIO_SERVICE_TYPE_EFFECTS = 1,
- AV_AUDIO_SERVICE_TYPE_VISUALLY_IMPAIRED = 2,
- AV_AUDIO_SERVICE_TYPE_HEARING_IMPAIRED = 3,
- AV_AUDIO_SERVICE_TYPE_DIALOGUE = 4,
- AV_AUDIO_SERVICE_TYPE_COMMENTARY = 5,
- AV_AUDIO_SERVICE_TYPE_EMERGENCY = 6,
- AV_AUDIO_SERVICE_TYPE_VOICE_OVER = 7,
- AV_AUDIO_SERVICE_TYPE_KARAOKE = 8,
- AV_AUDIO_SERVICE_TYPE_NB , ///< Not part of ABI
-};
-
-/**
- * @ingroup lavc_encoding
- */
-typedef struct RcOverride{
- int start_frame;
- int end_frame;
- int qscale; // If this is 0 then quality_factor will be used instead.
- float quality_factor;
-} RcOverride;
-
-#if FF_API_MAX_BFRAMES
-/**
- * @deprecated there is no libavcodec-wide limit on the number of B-frames
- */
-#define FF_MAX_B_FRAMES 16
-#endif
-
-/* encoding support
- These flags can be passed in AVCodecContext.flags before initialization.
- Note: Not everything is supported yet.
-*/
-
-/**
- * Allow decoders to produce frames with data planes that are not aligned
- * to CPU requirements (e.g. due to cropping).
- */
-#define AV_CODEC_FLAG_UNALIGNED (1 << 0)
-/**
- * Use fixed qscale.
- */
-#define AV_CODEC_FLAG_QSCALE (1 << 1)
-/**
- * 4 MV per MB allowed / advanced prediction for H.263.
- */
-#define AV_CODEC_FLAG_4MV (1 << 2)
-/**
- * Output even those frames that might be corrupted.
- */
-#define AV_CODEC_FLAG_OUTPUT_CORRUPT (1 << 3)
-/**
- * Use qpel MC.
- */
-#define AV_CODEC_FLAG_QPEL (1 << 4)
-/**
- * Use internal 2pass ratecontrol in first pass mode.
- */
-#define AV_CODEC_FLAG_PASS1 (1 << 9)
-/**
- * Use internal 2pass ratecontrol in second pass mode.
- */
-#define AV_CODEC_FLAG_PASS2 (1 << 10)
-/**
- * loop filter.
- */
-#define AV_CODEC_FLAG_LOOP_FILTER (1 << 11)
-/**
- * Only decode/encode grayscale.
- */
-#define AV_CODEC_FLAG_GRAY (1 << 13)
-/**
- * error[?] variables will be set during encoding.
- */
-#define AV_CODEC_FLAG_PSNR (1 << 15)
-/**
- * Input bitstream might be truncated at a random location
- * instead of only at frame boundaries.
- */
-#define AV_CODEC_FLAG_TRUNCATED (1 << 16)
-/**
- * Use interlaced DCT.
- */
-#define AV_CODEC_FLAG_INTERLACED_DCT (1 << 18)
-/**
- * Force low delay.
- */
-#define AV_CODEC_FLAG_LOW_DELAY (1 << 19)
-/**
- * Place global headers in extradata instead of every keyframe.
- */
-#define AV_CODEC_FLAG_GLOBAL_HEADER (1 << 22)
-/**
- * Use only bitexact stuff (except (I)DCT).
- */
-#define AV_CODEC_FLAG_BITEXACT (1 << 23)
-/* Fx : Flag for h263+ extra options */
-/**
- * H.263 advanced intra coding / MPEG-4 AC prediction
- */
-#define AV_CODEC_FLAG_AC_PRED (1 << 24)
-/**
- * interlaced motion estimation
- */
-#define AV_CODEC_FLAG_INTERLACED_ME (1 << 29)
-#define AV_CODEC_FLAG_CLOSED_GOP (1U << 31)
-
-/**
- * Allow non spec compliant speedup tricks.
- */
-#define AV_CODEC_FLAG2_FAST (1 << 0)
-/**
- * Skip bitstream encoding.
- */
-#define AV_CODEC_FLAG2_NO_OUTPUT (1 << 2)
-/**
- * Place global headers at every keyframe instead of in extradata.
- */
-#define AV_CODEC_FLAG2_LOCAL_HEADER (1 << 3)
-
-/**
- * timecode is in drop frame format. DEPRECATED!!!!
- */
-#define AV_CODEC_FLAG2_DROP_FRAME_TIMECODE (1 << 13)
-
-/**
- * Input bitstream might be truncated at a packet boundaries
- * instead of only at frame boundaries.
- */
-#define AV_CODEC_FLAG2_CHUNKS (1 << 15)
-/**
- * Discard cropping information from SPS.
- */
-#define AV_CODEC_FLAG2_IGNORE_CROP (1 << 16)
-
-/**
- * Show all frames before the first keyframe
- */
-#define AV_CODEC_FLAG2_SHOW_ALL (1 << 22)
-/**
- * Export motion vectors through frame side data
- */
-#define AV_CODEC_FLAG2_EXPORT_MVS (1 << 28)
-/**
- * Do not skip samples and export skip information as frame side data
- */
-#define AV_CODEC_FLAG2_SKIP_MANUAL (1 << 29)
-
-/* Unsupported options :
- * Syntax Arithmetic coding (SAC)
- * Reference Picture Selection
- * Independent Segment Decoding */
-/* /Fx */
-/* codec capabilities */
-
-/**
- * Decoder can use draw_horiz_band callback.
- */
-#define AV_CODEC_CAP_DRAW_HORIZ_BAND (1 << 0)
-/**
- * Codec uses get_buffer() for allocating buffers and supports custom allocators.
- * If not set, it might not use get_buffer() at all or use operations that
- * assume the buffer was allocated by avcodec_default_get_buffer.
- */
-#define AV_CODEC_CAP_DR1 (1 << 1)
-#define AV_CODEC_CAP_TRUNCATED (1 << 3)
-/**
- * Encoder or decoder requires flushing with NULL input at the end in order to
- * give the complete and correct output.
- *
- * NOTE: If this flag is not set, the codec is guaranteed to never be fed with
- * with NULL data. The user can still send NULL data to the public encode
- * or decode function, but libavcodec will not pass it along to the codec
- * unless this flag is set.
- *
- * Decoders:
- * The decoder has a non-zero delay and needs to be fed with avpkt->data=NULL,
- * avpkt->size=0 at the end to get the delayed data until the decoder no longer
- * returns frames.
- *
- * Encoders:
- * The encoder needs to be fed with NULL data at the end of encoding until the
- * encoder no longer returns data.
- *
- * NOTE: For encoders implementing the AVCodec.encode2() function, setting this
- * flag also means that the encoder must set the pts and duration for
- * each output packet. If this flag is not set, the pts and duration will
- * be determined by libavcodec from the input frame.
- */
-#define AV_CODEC_CAP_DELAY (1 << 5)
-/**
- * Codec can be fed a final frame with a smaller size.
- * This can be used to prevent truncation of the last audio samples.
- */
-#define AV_CODEC_CAP_SMALL_LAST_FRAME (1 << 6)
-
-#if FF_API_CAP_VDPAU
-/**
- * Codec can export data for HW decoding (VDPAU).
- */
-#define AV_CODEC_CAP_HWACCEL_VDPAU (1 << 7)
-#endif
-
-/**
- * Codec can output multiple frames per AVPacket
- * Normally demuxers return one frame at a time, demuxers which do not do
- * are connected to a parser to split what they return into proper frames.
- * This flag is reserved to the very rare category of codecs which have a
- * bitstream that cannot be split into frames without timeconsuming
- * operations like full decoding. Demuxers carring such bitstreams thus
- * may return multiple frames in a packet. This has many disadvantages like
- * prohibiting stream copy in many cases thus it should only be considered
- * as a last resort.
- */
-#define AV_CODEC_CAP_SUBFRAMES (1 << 8)
-/**
- * Codec is experimental and is thus avoided in favor of non experimental
- * encoders
- */
-#define AV_CODEC_CAP_EXPERIMENTAL (1 << 9)
-/**
- * Codec should fill in channel configuration and samplerate instead of container
- */
-#define AV_CODEC_CAP_CHANNEL_CONF (1 << 10)
-/**
- * Codec supports frame-level multithreading.
- */
-#define AV_CODEC_CAP_FRAME_THREADS (1 << 12)
-/**
- * Codec supports slice-based (or partition-based) multithreading.
- */
-#define AV_CODEC_CAP_SLICE_THREADS (1 << 13)
-/**
- * Codec supports changed parameters at any point.
- */
-#define AV_CODEC_CAP_PARAM_CHANGE (1 << 14)
-/**
- * Codec supports avctx->thread_count == 0 (auto).
- */
-#define AV_CODEC_CAP_AUTO_THREADS (1 << 15)
-/**
- * Audio encoder supports receiving a different number of samples in each call.
- */
-#define AV_CODEC_CAP_VARIABLE_FRAME_SIZE (1 << 16)
-/**
- * Codec is intra only.
- */
-#define AV_CODEC_CAP_INTRA_ONLY 0x40000000
-/**
- * Codec is lossless.
- */
-#define AV_CODEC_CAP_LOSSLESS 0x80000000
-
-
-#if FF_API_WITHOUT_PREFIX
-/**
- * Allow decoders to produce frames with data planes that are not aligned
- * to CPU requirements (e.g. due to cropping).
- */
-#define CODEC_FLAG_UNALIGNED AV_CODEC_FLAG_UNALIGNED
-#define CODEC_FLAG_QSCALE AV_CODEC_FLAG_QSCALE
-#define CODEC_FLAG_4MV AV_CODEC_FLAG_4MV
-#define CODEC_FLAG_OUTPUT_CORRUPT AV_CODEC_FLAG_OUTPUT_CORRUPT
-#define CODEC_FLAG_QPEL AV_CODEC_FLAG_QPEL
-#if FF_API_GMC
-/**
- * @deprecated use the "gmc" private option of the libxvid encoder
- */
-#define CODEC_FLAG_GMC 0x0020 ///< Use GMC.
-#endif
-#if FF_API_MV0
-/**
- * @deprecated use the flag "mv0" in the "mpv_flags" private option of the
- * mpegvideo encoders
- */
-#define CODEC_FLAG_MV0 0x0040
-#endif
-#if FF_API_INPUT_PRESERVED
-/**
- * @deprecated passing reference-counted frames to the encoders replaces this
- * flag
- */
-#define CODEC_FLAG_INPUT_PRESERVED 0x0100
-#endif
-#define CODEC_FLAG_PASS1 AV_CODEC_FLAG_PASS1
-#define CODEC_FLAG_PASS2 AV_CODEC_FLAG_PASS2
-#define CODEC_FLAG_GRAY AV_CODEC_FLAG_GRAY
-#if FF_API_EMU_EDGE
-/**
- * @deprecated edges are not used/required anymore. I.e. this flag is now always
- * set.
- */
-#define CODEC_FLAG_EMU_EDGE 0x4000
-#endif
-#define CODEC_FLAG_PSNR AV_CODEC_FLAG_PSNR
-#define CODEC_FLAG_TRUNCATED AV_CODEC_FLAG_TRUNCATED
-
-#if FF_API_NORMALIZE_AQP
-/**
- * @deprecated use the flag "naq" in the "mpv_flags" private option of the
- * mpegvideo encoders
- */
-#define CODEC_FLAG_NORMALIZE_AQP 0x00020000
-#endif
-#define CODEC_FLAG_INTERLACED_DCT AV_CODEC_FLAG_INTERLACED_DCT
-#define CODEC_FLAG_LOW_DELAY AV_CODEC_FLAG_LOW_DELAY
-#define CODEC_FLAG_GLOBAL_HEADER AV_CODEC_FLAG_GLOBAL_HEADER
-#define CODEC_FLAG_BITEXACT AV_CODEC_FLAG_BITEXACT
-#define CODEC_FLAG_AC_PRED AV_CODEC_FLAG_AC_PRED
-#define CODEC_FLAG_LOOP_FILTER AV_CODEC_FLAG_LOOP_FILTER
-#define CODEC_FLAG_INTERLACED_ME AV_CODEC_FLAG_INTERLACED_ME
-#define CODEC_FLAG_CLOSED_GOP AV_CODEC_FLAG_CLOSED_GOP
-#define CODEC_FLAG2_FAST AV_CODEC_FLAG2_FAST
-#define CODEC_FLAG2_NO_OUTPUT AV_CODEC_FLAG2_NO_OUTPUT
-#define CODEC_FLAG2_LOCAL_HEADER AV_CODEC_FLAG2_LOCAL_HEADER
-#define CODEC_FLAG2_DROP_FRAME_TIMECODE AV_CODEC_FLAG2_DROP_FRAME_TIMECODE
-#define CODEC_FLAG2_IGNORE_CROP AV_CODEC_FLAG2_IGNORE_CROP
-
-#define CODEC_FLAG2_CHUNKS AV_CODEC_FLAG2_CHUNKS
-#define CODEC_FLAG2_SHOW_ALL AV_CODEC_FLAG2_SHOW_ALL
-#define CODEC_FLAG2_EXPORT_MVS AV_CODEC_FLAG2_EXPORT_MVS
-#define CODEC_FLAG2_SKIP_MANUAL AV_CODEC_FLAG2_SKIP_MANUAL
-
-/* Unsupported options :
- * Syntax Arithmetic coding (SAC)
- * Reference Picture Selection
- * Independent Segment Decoding */
-/* /Fx */
-/* codec capabilities */
-
-#define CODEC_CAP_DRAW_HORIZ_BAND AV_CODEC_CAP_DRAW_HORIZ_BAND ///< Decoder can use draw_horiz_band callback.
-/**
- * Codec uses get_buffer() for allocating buffers and supports custom allocators.
- * If not set, it might not use get_buffer() at all or use operations that
- * assume the buffer was allocated by avcodec_default_get_buffer.
- */
-#define CODEC_CAP_DR1 AV_CODEC_CAP_DR1
-#define CODEC_CAP_TRUNCATED AV_CODEC_CAP_TRUNCATED
-#if FF_API_XVMC
-/* Codec can export data for HW decoding. This flag indicates that
- * the codec would call get_format() with list that might contain HW accelerated
- * pixel formats (XvMC, VDPAU, VAAPI, etc). The application can pick any of them
- * including raw image format.
- * The application can use the passed context to determine bitstream version,
- * chroma format, resolution etc.
- */
-#define CODEC_CAP_HWACCEL 0x0010
-#endif /* FF_API_XVMC */
-/**
- * Encoder or decoder requires flushing with NULL input at the end in order to
- * give the complete and correct output.
- *
- * NOTE: If this flag is not set, the codec is guaranteed to never be fed with
- * with NULL data. The user can still send NULL data to the public encode
- * or decode function, but libavcodec will not pass it along to the codec
- * unless this flag is set.
- *
- * Decoders:
- * The decoder has a non-zero delay and needs to be fed with avpkt->data=NULL,
- * avpkt->size=0 at the end to get the delayed data until the decoder no longer
- * returns frames.
- *
- * Encoders:
- * The encoder needs to be fed with NULL data at the end of encoding until the
- * encoder no longer returns data.
- *
- * NOTE: For encoders implementing the AVCodec.encode2() function, setting this
- * flag also means that the encoder must set the pts and duration for
- * each output packet. If this flag is not set, the pts and duration will
- * be determined by libavcodec from the input frame.
- */
-#define CODEC_CAP_DELAY AV_CODEC_CAP_DELAY
-/**
- * Codec can be fed a final frame with a smaller size.
- * This can be used to prevent truncation of the last audio samples.
- */
-#define CODEC_CAP_SMALL_LAST_FRAME AV_CODEC_CAP_SMALL_LAST_FRAME
-#if FF_API_CAP_VDPAU
-/**
- * Codec can export data for HW decoding (VDPAU).
- */
-#define CODEC_CAP_HWACCEL_VDPAU AV_CODEC_CAP_HWACCEL_VDPAU
-#endif
-/**
- * Codec can output multiple frames per AVPacket
- * Normally demuxers return one frame at a time, demuxers which do not do
- * are connected to a parser to split what they return into proper frames.
- * This flag is reserved to the very rare category of codecs which have a
- * bitstream that cannot be split into frames without timeconsuming
- * operations like full decoding. Demuxers carring such bitstreams thus
- * may return multiple frames in a packet. This has many disadvantages like
- * prohibiting stream copy in many cases thus it should only be considered
- * as a last resort.
- */
-#define CODEC_CAP_SUBFRAMES AV_CODEC_CAP_SUBFRAMES
-/**
- * Codec is experimental and is thus avoided in favor of non experimental
- * encoders
- */
-#define CODEC_CAP_EXPERIMENTAL AV_CODEC_CAP_EXPERIMENTAL
-/**
- * Codec should fill in channel configuration and samplerate instead of container
- */
-#define CODEC_CAP_CHANNEL_CONF AV_CODEC_CAP_CHANNEL_CONF
-#if FF_API_NEG_LINESIZES
-/**
- * @deprecated no codecs use this capability
- */
-#define CODEC_CAP_NEG_LINESIZES 0x0800
-#endif
-/**
- * Codec supports frame-level multithreading.
- */
-#define CODEC_CAP_FRAME_THREADS AV_CODEC_CAP_FRAME_THREADS
-/**
- * Codec supports slice-based (or partition-based) multithreading.
- */
-#define CODEC_CAP_SLICE_THREADS AV_CODEC_CAP_SLICE_THREADS
-/**
- * Codec supports changed parameters at any point.
- */
-#define CODEC_CAP_PARAM_CHANGE AV_CODEC_CAP_PARAM_CHANGE
-/**
- * Codec supports avctx->thread_count == 0 (auto).
- */
-#define CODEC_CAP_AUTO_THREADS AV_CODEC_CAP_AUTO_THREADS
-/**
- * Audio encoder supports receiving a different number of samples in each call.
- */
-#define CODEC_CAP_VARIABLE_FRAME_SIZE AV_CODEC_CAP_VARIABLE_FRAME_SIZE
-/**
- * Codec is intra only.
- */
-#define CODEC_CAP_INTRA_ONLY AV_CODEC_CAP_INTRA_ONLY
-/**
- * Codec is lossless.
- */
-#define CODEC_CAP_LOSSLESS AV_CODEC_CAP_LOSSLESS
-
-/**
- * HWAccel is experimental and is thus avoided in favor of non experimental
- * codecs
- */
-#define HWACCEL_CODEC_CAP_EXPERIMENTAL 0x0200
-#endif /* FF_API_WITHOUT_PREFIX */
-
-#if FF_API_MB_TYPE
-//The following defines may change, don't expect compatibility if you use them.
-#define MB_TYPE_INTRA4x4 0x0001
-#define MB_TYPE_INTRA16x16 0x0002 //FIXME H.264-specific
-#define MB_TYPE_INTRA_PCM 0x0004 //FIXME H.264-specific
-#define MB_TYPE_16x16 0x0008
-#define MB_TYPE_16x8 0x0010
-#define MB_TYPE_8x16 0x0020
-#define MB_TYPE_8x8 0x0040
-#define MB_TYPE_INTERLACED 0x0080
-#define MB_TYPE_DIRECT2 0x0100 //FIXME
-#define MB_TYPE_ACPRED 0x0200
-#define MB_TYPE_GMC 0x0400
-#define MB_TYPE_SKIP 0x0800
-#define MB_TYPE_P0L0 0x1000
-#define MB_TYPE_P1L0 0x2000
-#define MB_TYPE_P0L1 0x4000
-#define MB_TYPE_P1L1 0x8000
-#define MB_TYPE_L0 (MB_TYPE_P0L0 | MB_TYPE_P1L0)
-#define MB_TYPE_L1 (MB_TYPE_P0L1 | MB_TYPE_P1L1)
-#define MB_TYPE_L0L1 (MB_TYPE_L0 | MB_TYPE_L1)
-#define MB_TYPE_QUANT 0x00010000
-#define MB_TYPE_CBP 0x00020000
-//Note bits 24-31 are reserved for codec specific use (h264 ref0, mpeg1 0mv, ...)
-#endif
-
-/**
- * Pan Scan area.
- * This specifies the area which should be displayed.
- * Note there may be multiple such areas for one frame.
- */
-typedef struct AVPanScan{
- /**
- * id
- * - encoding: Set by user.
- * - decoding: Set by libavcodec.
- */
- int id;
-
- /**
- * width and height in 1/16 pel
- * - encoding: Set by user.
- * - decoding: Set by libavcodec.
- */
- int width;
- int height;
-
- /**
- * position of the top left corner in 1/16 pel for up to 3 fields/frames
- * - encoding: Set by user.
- * - decoding: Set by libavcodec.
- */
- int16_t position[3][2];
-}AVPanScan;
-
-/**
- * This structure describes the bitrate properties of an encoded bitstream. It
- * roughly corresponds to a subset the VBV parameters for MPEG-2 or HRD
- * parameters for H.264/HEVC.
- */
-typedef struct AVCPBProperties {
- /**
- * Maximum bitrate of the stream, in bits per second.
- * Zero if unknown or unspecified.
- */
- int max_bitrate;
- /**
- * Minimum bitrate of the stream, in bits per second.
- * Zero if unknown or unspecified.
- */
- int min_bitrate;
- /**
- * Average bitrate of the stream, in bits per second.
- * Zero if unknown or unspecified.
- */
- int avg_bitrate;
-
- /**
- * The size of the buffer to which the ratecontrol is applied, in bits.
- * Zero if unknown or unspecified.
- */
- int buffer_size;
-
- /**
- * The delay between the time the packet this structure is associated with
- * is received and the time when it should be decoded, in periods of a 27MHz
- * clock.
- *
- * UINT64_MAX when unknown or unspecified.
- */
- uint64_t vbv_delay;
-} AVCPBProperties;
-
-#if FF_API_QSCALE_TYPE
-#define FF_QSCALE_TYPE_MPEG1 0
-#define FF_QSCALE_TYPE_MPEG2 1
-#define FF_QSCALE_TYPE_H264 2
-#define FF_QSCALE_TYPE_VP56 3
-#endif
-
-/**
- * The decoder will keep a reference to the frame and may reuse it later.
- */
-#define AV_GET_BUFFER_FLAG_REF (1 << 0)
-
-/**
- * @defgroup lavc_packet AVPacket
- *
- * Types and functions for working with AVPacket.
- * @{
- */
-enum AVPacketSideDataType {
- AV_PKT_DATA_PALETTE,
- AV_PKT_DATA_NEW_EXTRADATA,
-
- /**
- * An AV_PKT_DATA_PARAM_CHANGE side data packet is laid out as follows:
- * @code
- * u32le param_flags
- * if (param_flags & AV_SIDE_DATA_PARAM_CHANGE_CHANNEL_COUNT)
- * s32le channel_count
- * if (param_flags & AV_SIDE_DATA_PARAM_CHANGE_CHANNEL_LAYOUT)
- * u64le channel_layout
- * if (param_flags & AV_SIDE_DATA_PARAM_CHANGE_SAMPLE_RATE)
- * s32le sample_rate
- * if (param_flags & AV_SIDE_DATA_PARAM_CHANGE_DIMENSIONS)
- * s32le width
- * s32le height
- * @endcode
- */
- AV_PKT_DATA_PARAM_CHANGE,
-
- /**
- * An AV_PKT_DATA_H263_MB_INFO side data packet contains a number of
- * structures with info about macroblocks relevant to splitting the
- * packet into smaller packets on macroblock edges (e.g. as for RFC 2190).
- * That is, it does not necessarily contain info about all macroblocks,
- * as long as the distance between macroblocks in the info is smaller
- * than the target payload size.
- * Each MB info structure is 12 bytes, and is laid out as follows:
- * @code
- * u32le bit offset from the start of the packet
- * u8 current quantizer at the start of the macroblock
- * u8 GOB number
- * u16le macroblock address within the GOB
- * u8 horizontal MV predictor
- * u8 vertical MV predictor
- * u8 horizontal MV predictor for block number 3
- * u8 vertical MV predictor for block number 3
- * @endcode
- */
- AV_PKT_DATA_H263_MB_INFO,
-
- /**
- * This side data should be associated with an audio stream and contains
- * ReplayGain information in form of the AVReplayGain struct.
- */
- AV_PKT_DATA_REPLAYGAIN,
-
- /**
- * This side data contains a 3x3 transformation matrix describing an affine
- * transformation that needs to be applied to the decoded video frames for
- * correct presentation.
- *
- * See libavutil/display.h for a detailed description of the data.
- */
- AV_PKT_DATA_DISPLAYMATRIX,
-
- /**
- * This side data should be associated with a video stream and contains
- * Stereoscopic 3D information in form of the AVStereo3D struct.
- */
- AV_PKT_DATA_STEREO3D,
-
- /**
- * This side data should be associated with an audio stream and corresponds
- * to enum AVAudioServiceType.
- */
- AV_PKT_DATA_AUDIO_SERVICE_TYPE,
-
- /**
- * This side data contains quality related information from the encoder.
- * @code
- * u32le quality factor of the compressed frame. Allowed range is between 1 (good) and FF_LAMBDA_MAX (bad).
- * u8 picture type
- * u8 error count
- * u16 reserved
- * u64le[error count] sum of squared differences between encoder in and output
- * @endcode
- */
- AV_PKT_DATA_QUALITY_STATS,
-
- /**
- * This side data contains an integer value representing the stream index
- * of a "fallback" track. A fallback track indicates an alternate
- * track to use when the current track can not be decoded for some reason.
- * e.g. no decoder available for codec.
- */
- AV_PKT_DATA_FALLBACK_TRACK,
-
- /**
- * This side data corresponds to the AVCPBProperties struct.
- */
- AV_PKT_DATA_CPB_PROPERTIES,
-
- /**
- * Recommmends skipping the specified number of samples
- * @code
- * u32le number of samples to skip from start of this packet
- * u32le number of samples to skip from end of this packet
- * u8 reason for start skip
- * u8 reason for end skip (0=padding silence, 1=convergence)
- * @endcode
- */
- AV_PKT_DATA_SKIP_SAMPLES=70,
-
- /**
- * An AV_PKT_DATA_JP_DUALMONO side data packet indicates that
- * the packet may contain "dual mono" audio specific to Japanese DTV
- * and if it is true, recommends only the selected channel to be used.
- * @code
- * u8 selected channels (0=mail/left, 1=sub/right, 2=both)
- * @endcode
- */
- AV_PKT_DATA_JP_DUALMONO,
-
- /**
- * A list of zero terminated key/value strings. There is no end marker for
- * the list, so it is required to rely on the side data size to stop.
- */
- AV_PKT_DATA_STRINGS_METADATA,
-
- /**
- * Subtitle event position
- * @code
- * u32le x1
- * u32le y1
- * u32le x2
- * u32le y2
- * @endcode
- */
- AV_PKT_DATA_SUBTITLE_POSITION,
-
- /**
- * Data found in BlockAdditional element of matroska container. There is
- * no end marker for the data, so it is required to rely on the side data
- * size to recognize the end. 8 byte id (as found in BlockAddId) followed
- * by data.
- */
- AV_PKT_DATA_MATROSKA_BLOCKADDITIONAL,
-
- /**
- * The optional first identifier line of a WebVTT cue.
- */
- AV_PKT_DATA_WEBVTT_IDENTIFIER,
-
- /**
- * The optional settings (rendering instructions) that immediately
- * follow the timestamp specifier of a WebVTT cue.
- */
- AV_PKT_DATA_WEBVTT_SETTINGS,
-
- /**
- * A list of zero terminated key/value strings. There is no end marker for
- * the list, so it is required to rely on the side data size to stop. This
- * side data includes updated metadata which appeared in the stream.
- */
- AV_PKT_DATA_METADATA_UPDATE,
-};
-
-#define AV_PKT_DATA_QUALITY_FACTOR AV_PKT_DATA_QUALITY_STATS //DEPRECATED
-
-typedef struct AVPacketSideData {
- uint8_t *data;
- int size;
- enum AVPacketSideDataType type;
-} AVPacketSideData;
-
-/**
- * This structure stores compressed data. It is typically exported by demuxers
- * and then passed as input to decoders, or received as output from encoders and
- * then passed to muxers.
- *
- * For video, it should typically contain one compressed frame. For audio it may
- * contain several compressed frames. Encoders are allowed to output empty
- * packets, with no compressed data, containing only side data
- * (e.g. to update some stream parameters at the end of encoding).
- *
- * AVPacket is one of the few structs in FFmpeg, whose size is a part of public
- * ABI. Thus it may be allocated on stack and no new fields can be added to it
- * without libavcodec and libavformat major bump.
- *
- * The semantics of data ownership depends on the buf field.
- * If it is set, the packet data is dynamically allocated and is
- * valid indefinitely until a call to av_packet_unref() reduces the
- * reference count to 0.
- *
- * If the buf field is not set av_packet_ref() would make a copy instead
- * of increasing the reference count.
- *
- * The side data is always allocated with av_malloc(), copied by
- * av_packet_ref() and freed by av_packet_unref().
- *
- * @see av_packet_ref
- * @see av_packet_unref
- */
-typedef struct AVPacket {
- /**
- * A reference to the reference-counted buffer where the packet data is
- * stored.
- * May be NULL, then the packet data is not reference-counted.
- */
- AVBufferRef *buf;
- /**
- * Presentation timestamp in AVStream->time_base units; the time at which
- * the decompressed packet will be presented to the user.
- * Can be AV_NOPTS_VALUE if it is not stored in the file.
- * pts MUST be larger or equal to dts as presentation cannot happen before
- * decompression, unless one wants to view hex dumps. Some formats misuse
- * the terms dts and pts/cts to mean something different. Such timestamps
- * must be converted to true pts/dts before they are stored in AVPacket.
- */
- int64_t pts;
- /**
- * Decompression timestamp in AVStream->time_base units; the time at which
- * the packet is decompressed.
- * Can be AV_NOPTS_VALUE if it is not stored in the file.
- */
- int64_t dts;
- uint8_t *data;
- int size;
- int stream_index;
- /**
- * A combination of AV_PKT_FLAG values
- */
- int flags;
- /**
- * Additional packet data that can be provided by the container.
- * Packet can contain several types of side information.
- */
- AVPacketSideData *side_data;
- int side_data_elems;
-
- /**
- * Duration of this packet in AVStream->time_base units, 0 if unknown.
- * Equals next_pts - this_pts in presentation order.
- */
- int64_t duration;
-
- int64_t pos; ///< byte position in stream, -1 if unknown
-
-#if FF_API_CONVERGENCE_DURATION
- /**
- * @deprecated Same as the duration field, but as int64_t. This was required
- * for Matroska subtitles, whose duration values could overflow when the
- * duration field was still an int.
- */
- attribute_deprecated
- int64_t convergence_duration;
-#endif
-} AVPacket;
-#define AV_PKT_FLAG_KEY 0x0001 ///< The packet contains a keyframe
-#define AV_PKT_FLAG_CORRUPT 0x0002 ///< The packet content is corrupted
-
-enum AVSideDataParamChangeFlags {
- AV_SIDE_DATA_PARAM_CHANGE_CHANNEL_COUNT = 0x0001,
- AV_SIDE_DATA_PARAM_CHANGE_CHANNEL_LAYOUT = 0x0002,
- AV_SIDE_DATA_PARAM_CHANGE_SAMPLE_RATE = 0x0004,
- AV_SIDE_DATA_PARAM_CHANGE_DIMENSIONS = 0x0008,
-};
-/**
- * @}
- */
-
-struct AVCodecInternal;
-
-enum AVFieldOrder {
- AV_FIELD_UNKNOWN,
- AV_FIELD_PROGRESSIVE,
- AV_FIELD_TT, //< Top coded_first, top displayed first
- AV_FIELD_BB, //< Bottom coded first, bottom displayed first
- AV_FIELD_TB, //< Top coded first, bottom displayed first
- AV_FIELD_BT, //< Bottom coded first, top displayed first
-};
-
-/**
- * main external API structure.
- * New fields can be added to the end with minor version bumps.
- * Removal, reordering and changes to existing fields require a major
- * version bump.
- * Please use AVOptions (av_opt* / av_set/get*()) to access these fields from user
- * applications.
- * sizeof(AVCodecContext) must not be used outside libav*.
- */
-typedef struct AVCodecContext {
- /**
- * information on struct for av_log
- * - set by avcodec_alloc_context3
- */
- const AVClass *av_class;
- int log_level_offset;
-
- enum AVMediaType codec_type; /* see AVMEDIA_TYPE_xxx */
- const struct AVCodec *codec;
-#if FF_API_CODEC_NAME
- /**
- * @deprecated this field is not used for anything in libavcodec
- */
- attribute_deprecated
- char codec_name[32];
-#endif
- enum AVCodecID codec_id; /* see AV_CODEC_ID_xxx */
-
- /**
- * fourcc (LSB first, so "ABCD" -> ('D'<<24) + ('C'<<16) + ('B'<<8) + 'A').
- * This is used to work around some encoder bugs.
- * A demuxer should set this to what is stored in the field used to identify the codec.
- * If there are multiple such fields in a container then the demuxer should choose the one
- * which maximizes the information about the used codec.
- * If the codec tag field in a container is larger than 32 bits then the demuxer should
- * remap the longer ID to 32 bits with a table or other structure. Alternatively a new
- * extra_codec_tag + size could be added but for this a clear advantage must be demonstrated
- * first.
- * - encoding: Set by user, if not then the default based on codec_id will be used.
- * - decoding: Set by user, will be converted to uppercase by libavcodec during init.
- */
- unsigned int codec_tag;
-
-#if FF_API_STREAM_CODEC_TAG
- /**
- * @deprecated this field is unused
- */
- attribute_deprecated
- unsigned int stream_codec_tag;
-#endif
-
- void *priv_data;
-
- /**
- * Private context used for internal data.
- *
- * Unlike priv_data, this is not codec-specific. It is used in general
- * libavcodec functions.
- */
- struct AVCodecInternal *internal;
-
- /**
- * Private data of the user, can be used to carry app specific stuff.
- * - encoding: Set by user.
- * - decoding: Set by user.
- */
- void *opaque;
-
- /**
- * the average bitrate
- * - encoding: Set by user; unused for constant quantizer encoding.
- * - decoding: Set by user, may be overwritten by libavcodec
- * if this info is available in the stream
- */
- int64_t bit_rate;
-
- /**
- * number of bits the bitstream is allowed to diverge from the reference.
- * the reference can be CBR (for CBR pass1) or VBR (for pass2)
- * - encoding: Set by user; unused for constant quantizer encoding.
- * - decoding: unused
- */
- int bit_rate_tolerance;
-
- /**
- * Global quality for codecs which cannot change it per frame.
- * This should be proportional to MPEG-1/2/4 qscale.
- * - encoding: Set by user.
- * - decoding: unused
- */
- int global_quality;
-
- /**
- * - encoding: Set by user.
- * - decoding: unused
- */
- int compression_level;
-#define FF_COMPRESSION_DEFAULT -1
-
- /**
- * AV_CODEC_FLAG_*.
- * - encoding: Set by user.
- * - decoding: Set by user.
- */
- int flags;
-
- /**
- * AV_CODEC_FLAG2_*
- * - encoding: Set by user.
- * - decoding: Set by user.
- */
- int flags2;
-
- /**
- * some codecs need / can use extradata like Huffman tables.
- * mjpeg: Huffman tables
- * rv10: additional flags
- * mpeg4: global headers (they can be in the bitstream or here)
- * The allocated memory should be AV_INPUT_BUFFER_PADDING_SIZE bytes larger
- * than extradata_size to avoid problems if it is read with the bitstream reader.
- * The bytewise contents of extradata must not depend on the architecture or CPU endianness.
- * - encoding: Set/allocated/freed by libavcodec.
- * - decoding: Set/allocated/freed by user.
- */
- uint8_t *extradata;
- int extradata_size;
-
- /**
- * This is the fundamental unit of time (in seconds) in terms
- * of which frame timestamps are represented. For fixed-fps content,
- * timebase should be 1/framerate and timestamp increments should be
- * identically 1.
- * This often, but not always is the inverse of the frame rate or field rate
- * for video.
- * - encoding: MUST be set by user.
- * - decoding: the use of this field for decoding is deprecated.
- * Use framerate instead.
- */
- AVRational time_base;
-
- /**
- * For some codecs, the time base is closer to the field rate than the frame rate.
- * Most notably, H.264 and MPEG-2 specify time_base as half of frame duration
- * if no telecine is used ...
- *
- * Set to time_base ticks per frame. Default 1, e.g., H.264/MPEG-2 set it to 2.
- */
- int ticks_per_frame;
-
- /**
- * Codec delay.
- *
- * Encoding: Number of frames delay there will be from the encoder input to
- * the decoder output. (we assume the decoder matches the spec)
- * Decoding: Number of frames delay in addition to what a standard decoder
- * as specified in the spec would produce.
- *
- * Video:
- * Number of frames the decoded output will be delayed relative to the
- * encoded input.
- *
- * Audio:
- * For encoding, this field is unused (see initial_padding).
- *
- * For decoding, this is the number of samples the decoder needs to
- * output before the decoder's output is valid. When seeking, you should
- * start decoding this many samples prior to your desired seek point.
- *
- * - encoding: Set by libavcodec.
- * - decoding: Set by libavcodec.
- */
- int delay;
-
-
- /* video only */
- /**
- * picture width / height.
- *
- * @note Those fields may not match the values of the last
- * AVFrame outputted by avcodec_decode_video2 due frame
- * reordering.
- *
- * - encoding: MUST be set by user.
- * - decoding: May be set by the user before opening the decoder if known e.g.
- * from the container. Some decoders will require the dimensions
- * to be set by the caller. During decoding, the decoder may
- * overwrite those values as required while parsing the data.
- */
- int width, height;
-
- /**
- * Bitstream width / height, may be different from width/height e.g. when
- * the decoded frame is cropped before being output or lowres is enabled.
- *
- * @note Those field may not match the value of the last
- * AVFrame outputted by avcodec_decode_video2 due frame
- * reordering.
- *
- * - encoding: unused
- * - decoding: May be set by the user before opening the decoder if known
- * e.g. from the container. During decoding, the decoder may
- * overwrite those values as required while parsing the data.
- */
- int coded_width, coded_height;
-
-#if FF_API_ASPECT_EXTENDED
-#define FF_ASPECT_EXTENDED 15
-#endif
-
- /**
- * the number of pictures in a group of pictures, or 0 for intra_only
- * - encoding: Set by user.
- * - decoding: unused
- */
- int gop_size;
-
- /**
- * Pixel format, see AV_PIX_FMT_xxx.
- * May be set by the demuxer if known from headers.
- * May be overridden by the decoder if it knows better.
- *
- * @note This field may not match the value of the last
- * AVFrame outputted by avcodec_decode_video2 due frame
- * reordering.
- *
- * - encoding: Set by user.
- * - decoding: Set by user if known, overridden by libavcodec while
- * parsing the data.
- */
- enum AVPixelFormat pix_fmt;
-
-#if FF_API_MOTION_EST
- /**
- * This option does nothing
- * @deprecated use codec private options instead
- */
- attribute_deprecated int me_method;
-#endif
-
- /**
- * If non NULL, 'draw_horiz_band' is called by the libavcodec
- * decoder to draw a horizontal band. It improves cache usage. Not
- * all codecs can do that. You must check the codec capabilities
- * beforehand.
- * When multithreading is used, it may be called from multiple threads
- * at the same time; threads might draw different parts of the same AVFrame,
- * or multiple AVFrames, and there is no guarantee that slices will be drawn
- * in order.
- * The function is also used by hardware acceleration APIs.
- * It is called at least once during frame decoding to pass
- * the data needed for hardware render.
- * In that mode instead of pixel data, AVFrame points to
- * a structure specific to the acceleration API. The application
- * reads the structure and can change some fields to indicate progress
- * or mark state.
- * - encoding: unused
- * - decoding: Set by user.
- * @param height the height of the slice
- * @param y the y position of the slice
- * @param type 1->top field, 2->bottom field, 3->frame
- * @param offset offset into the AVFrame.data from which the slice should be read
- */
- void (*draw_horiz_band)(struct AVCodecContext *s,
- const AVFrame *src, int offset[AV_NUM_DATA_POINTERS],
- int y, int type, int height);
-
- /**
- * callback to negotiate the pixelFormat
- * @param fmt is the list of formats which are supported by the codec,
- * it is terminated by -1 as 0 is a valid format, the formats are ordered by quality.
- * The first is always the native one.
- * @note The callback may be called again immediately if initialization for
- * the selected (hardware-accelerated) pixel format failed.
- * @warning Behavior is undefined if the callback returns a value not
- * in the fmt list of formats.
- * @return the chosen format
- * - encoding: unused
- * - decoding: Set by user, if not set the native format will be chosen.
- */
- enum AVPixelFormat (*get_format)(struct AVCodecContext *s, const enum AVPixelFormat * fmt);
-
- /**
- * maximum number of B-frames between non-B-frames
- * Note: The output will be delayed by max_b_frames+1 relative to the input.
- * - encoding: Set by user.
- * - decoding: unused
- */
- int max_b_frames;
-
- /**
- * qscale factor between IP and B-frames
- * If > 0 then the last P-frame quantizer will be used (q= lastp_q*factor+offset).
- * If < 0 then normal ratecontrol will be done (q= -normal_q*factor+offset).
- * - encoding: Set by user.
- * - decoding: unused
- */
- float b_quant_factor;
-
-#if FF_API_RC_STRATEGY
- /** @deprecated use codec private option instead */
- attribute_deprecated int rc_strategy;
-#define FF_RC_STRATEGY_XVID 1
-#endif
-
-#if FF_API_PRIVATE_OPT
- /** @deprecated use encoder private options instead */
- attribute_deprecated
- int b_frame_strategy;
-#endif
-
- /**
- * qscale offset between IP and B-frames
- * - encoding: Set by user.
- * - decoding: unused
- */
- float b_quant_offset;
-
- /**
- * Size of the frame reordering buffer in the decoder.
- * For MPEG-2 it is 1 IPB or 0 low delay IP.
- * - encoding: Set by libavcodec.
- * - decoding: Set by libavcodec.
- */
- int has_b_frames;
-
-#if FF_API_PRIVATE_OPT
- /** @deprecated use encoder private options instead */
- attribute_deprecated
- int mpeg_quant;
-#endif
-
- /**
- * qscale factor between P and I-frames
- * If > 0 then the last p frame quantizer will be used (q= lastp_q*factor+offset).
- * If < 0 then normal ratecontrol will be done (q= -normal_q*factor+offset).
- * - encoding: Set by user.
- * - decoding: unused
- */
- float i_quant_factor;
-
- /**
- * qscale offset between P and I-frames
- * - encoding: Set by user.
- * - decoding: unused
- */
- float i_quant_offset;
-
- /**
- * luminance masking (0-> disabled)
- * - encoding: Set by user.
- * - decoding: unused
- */
- float lumi_masking;
-
- /**
- * temporary complexity masking (0-> disabled)
- * - encoding: Set by user.
- * - decoding: unused
- */
- float temporal_cplx_masking;
-
- /**
- * spatial complexity masking (0-> disabled)
- * - encoding: Set by user.
- * - decoding: unused
- */
- float spatial_cplx_masking;
-
- /**
- * p block masking (0-> disabled)
- * - encoding: Set by user.
- * - decoding: unused
- */
- float p_masking;
-
- /**
- * darkness masking (0-> disabled)
- * - encoding: Set by user.
- * - decoding: unused
- */
- float dark_masking;
-
- /**
- * slice count
- * - encoding: Set by libavcodec.
- * - decoding: Set by user (or 0).
- */
- int slice_count;
-
-#if FF_API_PRIVATE_OPT
- /** @deprecated use encoder private options instead */
- attribute_deprecated
- int prediction_method;
-#define FF_PRED_LEFT 0
-#define FF_PRED_PLANE 1
-#define FF_PRED_MEDIAN 2
-#endif
-
- /**
- * slice offsets in the frame in bytes
- * - encoding: Set/allocated by libavcodec.
- * - decoding: Set/allocated by user (or NULL).
- */
- int *slice_offset;
-
- /**
- * sample aspect ratio (0 if unknown)
- * That is the width of a pixel divided by the height of the pixel.
- * Numerator and denominator must be relatively prime and smaller than 256 for some video standards.
- * - encoding: Set by user.
- * - decoding: Set by libavcodec.
- */
- AVRational sample_aspect_ratio;
-
- /**
- * motion estimation comparison function
- * - encoding: Set by user.
- * - decoding: unused
- */
- int me_cmp;
- /**
- * subpixel motion estimation comparison function
- * - encoding: Set by user.
- * - decoding: unused
- */
- int me_sub_cmp;
- /**
- * macroblock comparison function (not supported yet)
- * - encoding: Set by user.
- * - decoding: unused
- */
- int mb_cmp;
- /**
- * interlaced DCT comparison function
- * - encoding: Set by user.
- * - decoding: unused
- */
- int ildct_cmp;
-#define FF_CMP_SAD 0
-#define FF_CMP_SSE 1
-#define FF_CMP_SATD 2
-#define FF_CMP_DCT 3
-#define FF_CMP_PSNR 4
-#define FF_CMP_BIT 5
-#define FF_CMP_RD 6
-#define FF_CMP_ZERO 7
-#define FF_CMP_VSAD 8
-#define FF_CMP_VSSE 9
-#define FF_CMP_NSSE 10
-#define FF_CMP_W53 11
-#define FF_CMP_W97 12
-#define FF_CMP_DCTMAX 13
-#define FF_CMP_DCT264 14
-#define FF_CMP_CHROMA 256
-
- /**
- * ME diamond size & shape
- * - encoding: Set by user.
- * - decoding: unused
- */
- int dia_size;
-
- /**
- * amount of previous MV predictors (2a+1 x 2a+1 square)
- * - encoding: Set by user.
- * - decoding: unused
- */
- int last_predictor_count;
-
-#if FF_API_PRIVATE_OPT
- /** @deprecated use encoder private options instead */
- attribute_deprecated
- int pre_me;
-#endif
-
- /**
- * motion estimation prepass comparison function
- * - encoding: Set by user.
- * - decoding: unused
- */
- int me_pre_cmp;
-
- /**
- * ME prepass diamond size & shape
- * - encoding: Set by user.
- * - decoding: unused
- */
- int pre_dia_size;
-
- /**
- * subpel ME quality
- * - encoding: Set by user.
- * - decoding: unused
- */
- int me_subpel_quality;
-
-#if FF_API_AFD
- /**
- * DTG active format information (additional aspect ratio
- * information only used in DVB MPEG-2 transport streams)
- * 0 if not set.
- *
- * - encoding: unused
- * - decoding: Set by decoder.
- * @deprecated Deprecated in favor of AVSideData
- */
- attribute_deprecated int dtg_active_format;
-#define FF_DTG_AFD_SAME 8
-#define FF_DTG_AFD_4_3 9
-#define FF_DTG_AFD_16_9 10
-#define FF_DTG_AFD_14_9 11
-#define FF_DTG_AFD_4_3_SP_14_9 13
-#define FF_DTG_AFD_16_9_SP_14_9 14
-#define FF_DTG_AFD_SP_4_3 15
-#endif /* FF_API_AFD */
-
- /**
- * maximum motion estimation search range in subpel units
- * If 0 then no limit.
- *
- * - encoding: Set by user.
- * - decoding: unused
- */
- int me_range;
-
-#if FF_API_QUANT_BIAS
- /**
- * @deprecated use encoder private option instead
- */
- attribute_deprecated int intra_quant_bias;
-#define FF_DEFAULT_QUANT_BIAS 999999
-
- /**
- * @deprecated use encoder private option instead
- */
- attribute_deprecated int inter_quant_bias;
-#endif
-
- /**
- * slice flags
- * - encoding: unused
- * - decoding: Set by user.
- */
- int slice_flags;
-#define SLICE_FLAG_CODED_ORDER 0x0001 ///< draw_horiz_band() is called in coded order instead of display
-#define SLICE_FLAG_ALLOW_FIELD 0x0002 ///< allow draw_horiz_band() with field slices (MPEG2 field pics)
-#define SLICE_FLAG_ALLOW_PLANE 0x0004 ///< allow draw_horiz_band() with 1 component at a time (SVQ1)
-
-#if FF_API_XVMC
- /**
- * XVideo Motion Acceleration
- * - encoding: forbidden
- * - decoding: set by decoder
- * @deprecated XvMC doesn't need it anymore.
- */
- attribute_deprecated int xvmc_acceleration;
-#endif /* FF_API_XVMC */
-
- /**
- * macroblock decision mode
- * - encoding: Set by user.
- * - decoding: unused
- */
- int mb_decision;
-#define FF_MB_DECISION_SIMPLE 0 ///< uses mb_cmp
-#define FF_MB_DECISION_BITS 1 ///< chooses the one which needs the fewest bits
-#define FF_MB_DECISION_RD 2 ///< rate distortion
-
- /**
- * custom intra quantization matrix
- * - encoding: Set by user, can be NULL.
- * - decoding: Set by libavcodec.
- */
- uint16_t *intra_matrix;
-
- /**
- * custom inter quantization matrix
- * - encoding: Set by user, can be NULL.
- * - decoding: Set by libavcodec.
- */
- uint16_t *inter_matrix;
-
-#if FF_API_PRIVATE_OPT
- /** @deprecated use encoder private options instead */
- attribute_deprecated
- int scenechange_threshold;
-
- /** @deprecated use encoder private options instead */
- attribute_deprecated
- int noise_reduction;
-#endif
-
-#if FF_API_MPV_OPT
- /**
- * @deprecated this field is unused
- */
- attribute_deprecated
- int me_threshold;
-
- /**
- * @deprecated this field is unused
- */
- attribute_deprecated
- int mb_threshold;
-#endif
-
- /**
- * precision of the intra DC coefficient - 8
- * - encoding: Set by user.
- * - decoding: Set by libavcodec
- */
- int intra_dc_precision;
-
- /**
- * Number of macroblock rows at the top which are skipped.
- * - encoding: unused
- * - decoding: Set by user.
- */
- int skip_top;
-
- /**
- * Number of macroblock rows at the bottom which are skipped.
- * - encoding: unused
- * - decoding: Set by user.
- */
- int skip_bottom;
-
-#if FF_API_MPV_OPT
- /**
- * @deprecated use encoder private options instead
- */
- attribute_deprecated
- float border_masking;
-#endif
-
- /**
- * minimum MB lagrange multipler
- * - encoding: Set by user.
- * - decoding: unused
- */
- int mb_lmin;
-
- /**
- * maximum MB lagrange multipler
- * - encoding: Set by user.
- * - decoding: unused
- */
- int mb_lmax;
-
-#if FF_API_PRIVATE_OPT
- /**
- * @deprecated use encoder private options instead
- */
- attribute_deprecated
- int me_penalty_compensation;
-#endif
-
- /**
- *
- * - encoding: Set by user.
- * - decoding: unused
- */
- int bidir_refine;
-
-#if FF_API_PRIVATE_OPT
- /** @deprecated use encoder private options instead */
- attribute_deprecated
- int brd_scale;
-#endif
-
- /**
- * minimum GOP size
- * - encoding: Set by user.
- * - decoding: unused
- */
- int keyint_min;
-
- /**
- * number of reference frames
- * - encoding: Set by user.
- * - decoding: Set by lavc.
- */
- int refs;
-
-#if FF_API_PRIVATE_OPT
- /** @deprecated use encoder private options instead */
- attribute_deprecated
- int chromaoffset;
-#endif
-
-#if FF_API_UNUSED_MEMBERS
- /**
- * Multiplied by qscale for each frame and added to scene_change_score.
- * - encoding: Set by user.
- * - decoding: unused
- */
- attribute_deprecated int scenechange_factor;
-#endif
-
- /**
- *
- * Note: Value depends upon the compare function used for fullpel ME.
- * - encoding: Set by user.
- * - decoding: unused
- */
- int mv0_threshold;
-
-#if FF_API_PRIVATE_OPT
- /** @deprecated use encoder private options instead */
- attribute_deprecated
- int b_sensitivity;
-#endif
-
- /**
- * Chromaticity coordinates of the source primaries.
- * - encoding: Set by user
- * - decoding: Set by libavcodec
- */
- enum AVColorPrimaries color_primaries;
-
- /**
- * Color Transfer Characteristic.
- * - encoding: Set by user
- * - decoding: Set by libavcodec
- */
- enum AVColorTransferCharacteristic color_trc;
-
- /**
- * YUV colorspace type.
- * - encoding: Set by user
- * - decoding: Set by libavcodec
- */
- enum AVColorSpace colorspace;
-
- /**
- * MPEG vs JPEG YUV range.
- * - encoding: Set by user
- * - decoding: Set by libavcodec
- */
- enum AVColorRange color_range;
-
- /**
- * This defines the location of chroma samples.
- * - encoding: Set by user
- * - decoding: Set by libavcodec
- */
- enum AVChromaLocation chroma_sample_location;
-
- /**
- * Number of slices.
- * Indicates number of picture subdivisions. Used for parallelized
- * decoding.
- * - encoding: Set by user
- * - decoding: unused
- */
- int slices;
-
- /** Field order
- * - encoding: set by libavcodec
- * - decoding: Set by user.
- */
- enum AVFieldOrder field_order;
-
- /* audio only */
- int sample_rate; ///< samples per second
- int channels; ///< number of audio channels
-
- /**
- * audio sample format
- * - encoding: Set by user.
- * - decoding: Set by libavcodec.
- */
- enum AVSampleFormat sample_fmt; ///< sample format
-
- /* The following data should not be initialized. */
- /**
- * Number of samples per channel in an audio frame.
- *
- * - encoding: set by libavcodec in avcodec_open2(). Each submitted frame
- * except the last must contain exactly frame_size samples per channel.
- * May be 0 when the codec has AV_CODEC_CAP_VARIABLE_FRAME_SIZE set, then the
- * frame size is not restricted.
- * - decoding: may be set by some decoders to indicate constant frame size
- */
- int frame_size;
-
- /**
- * Frame counter, set by libavcodec.
- *
- * - decoding: total number of frames returned from the decoder so far.
- * - encoding: total number of frames passed to the encoder so far.
- *
- * @note the counter is not incremented if encoding/decoding resulted in
- * an error.
- */
- int frame_number;
-
- /**
- * number of bytes per packet if constant and known or 0
- * Used by some WAV based audio codecs.
- */
- int block_align;
-
- /**
- * Audio cutoff bandwidth (0 means "automatic")
- * - encoding: Set by user.
- * - decoding: unused
- */
- int cutoff;
-
- /**
- * Audio channel layout.
- * - encoding: set by user.
- * - decoding: set by user, may be overwritten by libavcodec.
- */
- uint64_t channel_layout;
-
- /**
- * Request decoder to use this channel layout if it can (0 for default)
- * - encoding: unused
- * - decoding: Set by user.
- */
- uint64_t request_channel_layout;
-
- /**
- * Type of service that the audio stream conveys.
- * - encoding: Set by user.
- * - decoding: Set by libavcodec.
- */
- enum AVAudioServiceType audio_service_type;
-
- /**
- * desired sample format
- * - encoding: Not used.
- * - decoding: Set by user.
- * Decoder will decode to this format if it can.
- */
- enum AVSampleFormat request_sample_fmt;
-
- /**
- * This callback is called at the beginning of each frame to get data
- * buffer(s) for it. There may be one contiguous buffer for all the data or
- * there may be a buffer per each data plane or anything in between. What
- * this means is, you may set however many entries in buf[] you feel necessary.
- * Each buffer must be reference-counted using the AVBuffer API (see description
- * of buf[] below).
- *
- * The following fields will be set in the frame before this callback is
- * called:
- * - format
- * - width, height (video only)
- * - sample_rate, channel_layout, nb_samples (audio only)
- * Their values may differ from the corresponding values in
- * AVCodecContext. This callback must use the frame values, not the codec
- * context values, to calculate the required buffer size.
- *
- * This callback must fill the following fields in the frame:
- * - data[]
- * - linesize[]
- * - extended_data:
- * * if the data is planar audio with more than 8 channels, then this
- * callback must allocate and fill extended_data to contain all pointers
- * to all data planes. data[] must hold as many pointers as it can.
- * extended_data must be allocated with av_malloc() and will be freed in
- * av_frame_unref().
- * * otherwise exended_data must point to data
- * - buf[] must contain one or more pointers to AVBufferRef structures. Each of
- * the frame's data and extended_data pointers must be contained in these. That
- * is, one AVBufferRef for each allocated chunk of memory, not necessarily one
- * AVBufferRef per data[] entry. See: av_buffer_create(), av_buffer_alloc(),
- * and av_buffer_ref().
- * - extended_buf and nb_extended_buf must be allocated with av_malloc() by
- * this callback and filled with the extra buffers if there are more
- * buffers than buf[] can hold. extended_buf will be freed in
- * av_frame_unref().
- *
- * If AV_CODEC_CAP_DR1 is not set then get_buffer2() must call
- * avcodec_default_get_buffer2() instead of providing buffers allocated by
- * some other means.
- *
- * Each data plane must be aligned to the maximum required by the target
- * CPU.
- *
- * @see avcodec_default_get_buffer2()
- *
- * Video:
- *
- * If AV_GET_BUFFER_FLAG_REF is set in flags then the frame may be reused
- * (read and/or written to if it is writable) later by libavcodec.
- *
- * avcodec_align_dimensions2() should be used to find the required width and
- * height, as they normally need to be rounded up to the next multiple of 16.
- *
- * Some decoders do not support linesizes changing between frames.
- *
- * If frame multithreading is used and thread_safe_callbacks is set,
- * this callback may be called from a different thread, but not from more
- * than one at once. Does not need to be reentrant.
- *
- * @see avcodec_align_dimensions2()
- *
- * Audio:
- *
- * Decoders request a buffer of a particular size by setting
- * AVFrame.nb_samples prior to calling get_buffer2(). The decoder may,
- * however, utilize only part of the buffer by setting AVFrame.nb_samples
- * to a smaller value in the output frame.
- *
- * As a convenience, av_samples_get_buffer_size() and
- * av_samples_fill_arrays() in libavutil may be used by custom get_buffer2()
- * functions to find the required data size and to fill data pointers and
- * linesize. In AVFrame.linesize, only linesize[0] may be set for audio
- * since all planes must be the same size.
- *
- * @see av_samples_get_buffer_size(), av_samples_fill_arrays()
- *
- * - encoding: unused
- * - decoding: Set by libavcodec, user can override.
- */
- int (*get_buffer2)(struct AVCodecContext *s, AVFrame *frame, int flags);
-
- /**
- * If non-zero, the decoded audio and video frames returned from
- * avcodec_decode_video2() and avcodec_decode_audio4() are reference-counted
- * and are valid indefinitely. The caller must free them with
- * av_frame_unref() when they are not needed anymore.
- * Otherwise, the decoded frames must not be freed by the caller and are
- * only valid until the next decode call.
- *
- * - encoding: unused
- * - decoding: set by the caller before avcodec_open2().
- */
- int refcounted_frames;
-
- /* - encoding parameters */
- float qcompress; ///< amount of qscale change between easy & hard scenes (0.0-1.0)
- float qblur; ///< amount of qscale smoothing over time (0.0-1.0)
-
- /**
- * minimum quantizer
- * - encoding: Set by user.
- * - decoding: unused
- */
- int qmin;
-
- /**
- * maximum quantizer
- * - encoding: Set by user.
- * - decoding: unused
- */
- int qmax;
-
- /**
- * maximum quantizer difference between frames
- * - encoding: Set by user.
- * - decoding: unused
- */
- int max_qdiff;
-
-#if FF_API_MPV_OPT
- /**
- * @deprecated use encoder private options instead
- */
- attribute_deprecated
- float rc_qsquish;
-
- attribute_deprecated
- float rc_qmod_amp;
- attribute_deprecated
- int rc_qmod_freq;
-#endif
-
- /**
- * decoder bitstream buffer size
- * - encoding: Set by user.
- * - decoding: unused
- */
- int rc_buffer_size;
-
- /**
- * ratecontrol override, see RcOverride
- * - encoding: Allocated/set/freed by user.
- * - decoding: unused
- */
- int rc_override_count;
- RcOverride *rc_override;
-
-#if FF_API_MPV_OPT
- /**
- * @deprecated use encoder private options instead
- */
- attribute_deprecated
- const char *rc_eq;
-#endif
-
- /**
- * maximum bitrate
- * - encoding: Set by user.
- * - decoding: Set by user, may be overwritten by libavcodec.
- */
- int64_t rc_max_rate;
-
- /**
- * minimum bitrate
- * - encoding: Set by user.
- * - decoding: unused
- */
- int64_t rc_min_rate;
-
-#if FF_API_MPV_OPT
- /**
- * @deprecated use encoder private options instead
- */
- attribute_deprecated
- float rc_buffer_aggressivity;
-
- attribute_deprecated
- float rc_initial_cplx;
-#endif
-
- /**
- * Ratecontrol attempt to use, at maximum, of what can be used without an underflow.
- * - encoding: Set by user.
- * - decoding: unused.
- */
- float rc_max_available_vbv_use;
-
- /**
- * Ratecontrol attempt to use, at least, times the amount needed to prevent a vbv overflow.
- * - encoding: Set by user.
- * - decoding: unused.
- */
- float rc_min_vbv_overflow_use;
-
- /**
- * Number of bits which should be loaded into the rc buffer before decoding starts.
- * - encoding: Set by user.
- * - decoding: unused
- */
- int rc_initial_buffer_occupancy;
-
-#if FF_API_CODER_TYPE
-#define FF_CODER_TYPE_VLC 0
-#define FF_CODER_TYPE_AC 1
-#define FF_CODER_TYPE_RAW 2
-#define FF_CODER_TYPE_RLE 3
-#if FF_API_UNUSED_MEMBERS
-#define FF_CODER_TYPE_DEFLATE 4
-#endif /* FF_API_UNUSED_MEMBERS */
- /**
- * @deprecated use encoder private options instead
- */
- attribute_deprecated
- int coder_type;
-#endif /* FF_API_CODER_TYPE */
-
-#if FF_API_PRIVATE_OPT
- /** @deprecated use encoder private options instead */
- attribute_deprecated
- int context_model;
-#endif
-
-#if FF_API_MPV_OPT
- /**
- * @deprecated use encoder private options instead
- */
- attribute_deprecated
- int lmin;
-
- /**
- * @deprecated use encoder private options instead
- */
- attribute_deprecated
- int lmax;
-#endif
-
-#if FF_API_PRIVATE_OPT
- /** @deprecated use encoder private options instead */
- attribute_deprecated
- int frame_skip_threshold;
-
- /** @deprecated use encoder private options instead */
- attribute_deprecated
- int frame_skip_factor;
-
- /** @deprecated use encoder private options instead */
- attribute_deprecated
- int frame_skip_exp;
-
- /** @deprecated use encoder private options instead */
- attribute_deprecated
- int frame_skip_cmp;
-#endif /* FF_API_PRIVATE_OPT */
-
- /**
- * trellis RD quantization
- * - encoding: Set by user.
- * - decoding: unused
- */
- int trellis;
-
-#if FF_API_PRIVATE_OPT
- /** @deprecated use encoder private options instead */
- attribute_deprecated
- int min_prediction_order;
-
- /** @deprecated use encoder private options instead */
- attribute_deprecated
- int max_prediction_order;
-
- /** @deprecated use encoder private options instead */
- attribute_deprecated
- int64_t timecode_frame_start;
-#endif
-
-#if FF_API_RTP_CALLBACK
- /**
- * @deprecated unused
- */
- /* The RTP callback: This function is called */
- /* every time the encoder has a packet to send. */
- /* It depends on the encoder if the data starts */
- /* with a Start Code (it should). H.263 does. */
- /* mb_nb contains the number of macroblocks */
- /* encoded in the RTP payload. */
- attribute_deprecated
- void (*rtp_callback)(struct AVCodecContext *avctx, void *data, int size, int mb_nb);
-#endif
-
-#if FF_API_PRIVATE_OPT
- /** @deprecated use encoder private options instead */
- attribute_deprecated
- int rtp_payload_size; /* The size of the RTP payload: the coder will */
- /* do its best to deliver a chunk with size */
- /* below rtp_payload_size, the chunk will start */
- /* with a start code on some codecs like H.263. */
- /* This doesn't take account of any particular */
- /* headers inside the transmitted RTP payload. */
-#endif
-
-#if FF_API_STAT_BITS
- /* statistics, used for 2-pass encoding */
- attribute_deprecated
- int mv_bits;
- attribute_deprecated
- int header_bits;
- attribute_deprecated
- int i_tex_bits;
- attribute_deprecated
- int p_tex_bits;
- attribute_deprecated
- int i_count;
- attribute_deprecated
- int p_count;
- attribute_deprecated
- int skip_count;
- attribute_deprecated
- int misc_bits;
-
- /** @deprecated this field is unused */
- attribute_deprecated
- int frame_bits;
-#endif
-
- /**
- * pass1 encoding statistics output buffer
- * - encoding: Set by libavcodec.
- * - decoding: unused
- */
- char *stats_out;
-
- /**
- * pass2 encoding statistics input buffer
- * Concatenated stuff from stats_out of pass1 should be placed here.
- * - encoding: Allocated/set/freed by user.
- * - decoding: unused
- */
- char *stats_in;
-
- /**
- * Work around bugs in encoders which sometimes cannot be detected automatically.
- * - encoding: Set by user
- * - decoding: Set by user
- */
- int workaround_bugs;
-#define FF_BUG_AUTODETECT 1 ///< autodetection
-#if FF_API_OLD_MSMPEG4
-#define FF_BUG_OLD_MSMPEG4 2
-#endif
-#define FF_BUG_XVID_ILACE 4
-#define FF_BUG_UMP4 8
-#define FF_BUG_NO_PADDING 16
-#define FF_BUG_AMV 32
-#if FF_API_AC_VLC
-#define FF_BUG_AC_VLC 0 ///< Will be removed, libavcodec can now handle these non-compliant files by default.
-#endif
-#define FF_BUG_QPEL_CHROMA 64
-#define FF_BUG_STD_QPEL 128
-#define FF_BUG_QPEL_CHROMA2 256
-#define FF_BUG_DIRECT_BLOCKSIZE 512
-#define FF_BUG_EDGE 1024
-#define FF_BUG_HPEL_CHROMA 2048
-#define FF_BUG_DC_CLIP 4096
-#define FF_BUG_MS 8192 ///< Work around various bugs in Microsoft's broken decoders.
-#define FF_BUG_TRUNCATED 16384
-
- /**
- * strictly follow the standard (MPEG4, ...).
- * - encoding: Set by user.
- * - decoding: Set by user.
- * Setting this to STRICT or higher means the encoder and decoder will
- * generally do stupid things, whereas setting it to unofficial or lower
- * will mean the encoder might produce output that is not supported by all
- * spec-compliant decoders. Decoders don't differentiate between normal,
- * unofficial and experimental (that is, they always try to decode things
- * when they can) unless they are explicitly asked to behave stupidly
- * (=strictly conform to the specs)
- */
- int strict_std_compliance;
-#define FF_COMPLIANCE_VERY_STRICT 2 ///< Strictly conform to an older more strict version of the spec or reference software.
-#define FF_COMPLIANCE_STRICT 1 ///< Strictly conform to all the things in the spec no matter what consequences.
-#define FF_COMPLIANCE_NORMAL 0
-#define FF_COMPLIANCE_UNOFFICIAL -1 ///< Allow unofficial extensions
-#define FF_COMPLIANCE_EXPERIMENTAL -2 ///< Allow nonstandardized experimental things.
-
- /**
- * error concealment flags
- * - encoding: unused
- * - decoding: Set by user.
- */
- int error_concealment;
-#define FF_EC_GUESS_MVS 1
-#define FF_EC_DEBLOCK 2
-#define FF_EC_FAVOR_INTER 256
-
- /**
- * debug
- * - encoding: Set by user.
- * - decoding: Set by user.
- */
- int debug;
-#define FF_DEBUG_PICT_INFO 1
-#define FF_DEBUG_RC 2
-#define FF_DEBUG_BITSTREAM 4
-#define FF_DEBUG_MB_TYPE 8
-#define FF_DEBUG_QP 16
-#if FF_API_DEBUG_MV
-/**
- * @deprecated this option does nothing
- */
-#define FF_DEBUG_MV 32
-#endif
-#define FF_DEBUG_DCT_COEFF 0x00000040
-#define FF_DEBUG_SKIP 0x00000080
-#define FF_DEBUG_STARTCODE 0x00000100
-#if FF_API_UNUSED_MEMBERS
-#define FF_DEBUG_PTS 0x00000200
-#endif /* FF_API_UNUSED_MEMBERS */
-#define FF_DEBUG_ER 0x00000400
-#define FF_DEBUG_MMCO 0x00000800
-#define FF_DEBUG_BUGS 0x00001000
-#if FF_API_DEBUG_MV
-#define FF_DEBUG_VIS_QP 0x00002000 ///< only access through AVOptions from outside libavcodec
-#define FF_DEBUG_VIS_MB_TYPE 0x00004000 ///< only access through AVOptions from outside libavcodec
-#endif
-#define FF_DEBUG_BUFFERS 0x00008000
-#define FF_DEBUG_THREADS 0x00010000
-#define FF_DEBUG_GREEN_MD 0x00800000
-#define FF_DEBUG_NOMC 0x01000000
-
-#if FF_API_DEBUG_MV
- /**
- * debug
- * Code outside libavcodec should access this field using AVOptions
- * - encoding: Set by user.
- * - decoding: Set by user.
- */
- int debug_mv;
-#define FF_DEBUG_VIS_MV_P_FOR 0x00000001 //visualize forward predicted MVs of P frames
-#define FF_DEBUG_VIS_MV_B_FOR 0x00000002 //visualize forward predicted MVs of B frames
-#define FF_DEBUG_VIS_MV_B_BACK 0x00000004 //visualize backward predicted MVs of B frames
-#endif
-
- /**
- * Error recognition; may misdetect some more or less valid parts as errors.
- * - encoding: unused
- * - decoding: Set by user.
- */
- int err_recognition;
-
-/**
- * Verify checksums embedded in the bitstream (could be of either encoded or
- * decoded data, depending on the codec) and print an error message on mismatch.
- * If AV_EF_EXPLODE is also set, a mismatching checksum will result in the
- * decoder returning an error.
- */
-#define AV_EF_CRCCHECK (1<<0)
-#define AV_EF_BITSTREAM (1<<1) ///< detect bitstream specification deviations
-#define AV_EF_BUFFER (1<<2) ///< detect improper bitstream length
-#define AV_EF_EXPLODE (1<<3) ///< abort decoding on minor error detection
-
-#define AV_EF_IGNORE_ERR (1<<15) ///< ignore errors and continue
-#define AV_EF_CAREFUL (1<<16) ///< consider things that violate the spec, are fast to calculate and have not been seen in the wild as errors
-#define AV_EF_COMPLIANT (1<<17) ///< consider all spec non compliances as errors
-#define AV_EF_AGGRESSIVE (1<<18) ///< consider things that a sane encoder should not do as an error
-
-
- /**
- * opaque 64bit number (generally a PTS) that will be reordered and
- * output in AVFrame.reordered_opaque
- * - encoding: unused
- * - decoding: Set by user.
- */
- int64_t reordered_opaque;
-
- /**
- * Hardware accelerator in use
- * - encoding: unused.
- * - decoding: Set by libavcodec
- */
- struct AVHWAccel *hwaccel;
-
- /**
- * Hardware accelerator context.
- * For some hardware accelerators, a global context needs to be
- * provided by the user. In that case, this holds display-dependent
- * data FFmpeg cannot instantiate itself. Please refer to the
- * FFmpeg HW accelerator documentation to know how to fill this
- * is. e.g. for VA API, this is a struct vaapi_context.
- * - encoding: unused
- * - decoding: Set by user
- */
- void *hwaccel_context;
-
- /**
- * error
- * - encoding: Set by libavcodec if flags & AV_CODEC_FLAG_PSNR.
- * - decoding: unused
- */
- uint64_t error[AV_NUM_DATA_POINTERS];
-
- /**
- * DCT algorithm, see FF_DCT_* below
- * - encoding: Set by user.
- * - decoding: unused
- */
- int dct_algo;
-#define FF_DCT_AUTO 0
-#define FF_DCT_FASTINT 1
-#define FF_DCT_INT 2
-#define FF_DCT_MMX 3
-#define FF_DCT_ALTIVEC 5
-#define FF_DCT_FAAN 6
-
- /**
- * IDCT algorithm, see FF_IDCT_* below.
- * - encoding: Set by user.
- * - decoding: Set by user.
- */
- int idct_algo;
-#define FF_IDCT_AUTO 0
-#define FF_IDCT_INT 1
-#define FF_IDCT_SIMPLE 2
-#define FF_IDCT_SIMPLEMMX 3
-#define FF_IDCT_ARM 7
-#define FF_IDCT_ALTIVEC 8
-#if FF_API_ARCH_SH4
-#define FF_IDCT_SH4 9
-#endif
-#define FF_IDCT_SIMPLEARM 10
-#if FF_API_UNUSED_MEMBERS
-#define FF_IDCT_IPP 13
-#endif /* FF_API_UNUSED_MEMBERS */
-#define FF_IDCT_XVID 14
-#if FF_API_IDCT_XVIDMMX
-#define FF_IDCT_XVIDMMX 14
-#endif /* FF_API_IDCT_XVIDMMX */
-#define FF_IDCT_SIMPLEARMV5TE 16
-#define FF_IDCT_SIMPLEARMV6 17
-#if FF_API_ARCH_SPARC
-#define FF_IDCT_SIMPLEVIS 18
-#endif
-#define FF_IDCT_FAAN 20
-#define FF_IDCT_SIMPLENEON 22
-#if FF_API_ARCH_ALPHA
-#define FF_IDCT_SIMPLEALPHA 23
-#endif
-#define FF_IDCT_SIMPLEAUTO 128
-
- /**
- * bits per sample/pixel from the demuxer (needed for huffyuv).
- * - encoding: Set by libavcodec.
- * - decoding: Set by user.
- */
- int bits_per_coded_sample;
-
- /**
- * Bits per sample/pixel of internal libavcodec pixel/sample format.
- * - encoding: set by user.
- * - decoding: set by libavcodec.
- */
- int bits_per_raw_sample;
-
-#if FF_API_LOWRES
- /**
- * low resolution decoding, 1-> 1/2 size, 2->1/4 size
- * - encoding: unused
- * - decoding: Set by user.
- * Code outside libavcodec should access this field using:
- * av_codec_{get,set}_lowres(avctx)
- */
- int lowres;
-#endif
-
-#if FF_API_CODED_FRAME
- /**
- * the picture in the bitstream
- * - encoding: Set by libavcodec.
- * - decoding: unused
- *
- * @deprecated use the quality factor packet side data instead
- */
- attribute_deprecated AVFrame *coded_frame;
-#endif
-
- /**
- * thread count
- * is used to decide how many independent tasks should be passed to execute()
- * - encoding: Set by user.
- * - decoding: Set by user.
- */
- int thread_count;
-
- /**
- * Which multithreading methods to use.
- * Use of FF_THREAD_FRAME will increase decoding delay by one frame per thread,
- * so clients which cannot provide future frames should not use it.
- *
- * - encoding: Set by user, otherwise the default is used.
- * - decoding: Set by user, otherwise the default is used.
- */
- int thread_type;
-#define FF_THREAD_FRAME 1 ///< Decode more than one frame at once
-#define FF_THREAD_SLICE 2 ///< Decode more than one part of a single frame at once
-
- /**
- * Which multithreading methods are in use by the codec.
- * - encoding: Set by libavcodec.
- * - decoding: Set by libavcodec.
- */
- int active_thread_type;
-
- /**
- * Set by the client if its custom get_buffer() callback can be called
- * synchronously from another thread, which allows faster multithreaded decoding.
- * draw_horiz_band() will be called from other threads regardless of this setting.
- * Ignored if the default get_buffer() is used.
- * - encoding: Set by user.
- * - decoding: Set by user.
- */
- int thread_safe_callbacks;
-
- /**
- * The codec may call this to execute several independent things.
- * It will return only after finishing all tasks.
- * The user may replace this with some multithreaded implementation,
- * the default implementation will execute the parts serially.
- * @param count the number of things to execute
- * - encoding: Set by libavcodec, user can override.
- * - decoding: Set by libavcodec, user can override.
- */
- int (*execute)(struct AVCodecContext *c, int (*func)(struct AVCodecContext *c2, void *arg), void *arg2, int *ret, int count, int size);
-
- /**
- * The codec may call this to execute several independent things.
- * It will return only after finishing all tasks.
- * The user may replace this with some multithreaded implementation,
- * the default implementation will execute the parts serially.
- * Also see avcodec_thread_init and e.g. the --enable-pthread configure option.
- * @param c context passed also to func
- * @param count the number of things to execute
- * @param arg2 argument passed unchanged to func
- * @param ret return values of executed functions, must have space for "count" values. May be NULL.
- * @param func function that will be called count times, with jobnr from 0 to count-1.
- * threadnr will be in the range 0 to c->thread_count-1 < MAX_THREADS and so that no
- * two instances of func executing at the same time will have the same threadnr.
- * @return always 0 currently, but code should handle a future improvement where when any call to func
- * returns < 0 no further calls to func may be done and < 0 is returned.
- * - encoding: Set by libavcodec, user can override.
- * - decoding: Set by libavcodec, user can override.
- */
- int (*execute2)(struct AVCodecContext *c, int (*func)(struct AVCodecContext *c2, void *arg, int jobnr, int threadnr), void *arg2, int *ret, int count);
-
- /**
- * noise vs. sse weight for the nsse comparison function
- * - encoding: Set by user.
- * - decoding: unused
- */
- int nsse_weight;
-
- /**
- * profile
- * - encoding: Set by user.
- * - decoding: Set by libavcodec.
- */
- int profile;
-#define FF_PROFILE_UNKNOWN -99
-#define FF_PROFILE_RESERVED -100
-
-#define FF_PROFILE_AAC_MAIN 0
-#define FF_PROFILE_AAC_LOW 1
-#define FF_PROFILE_AAC_SSR 2
-#define FF_PROFILE_AAC_LTP 3
-#define FF_PROFILE_AAC_HE 4
-#define FF_PROFILE_AAC_HE_V2 28
-#define FF_PROFILE_AAC_LD 22
-#define FF_PROFILE_AAC_ELD 38
-#define FF_PROFILE_MPEG2_AAC_LOW 128
-#define FF_PROFILE_MPEG2_AAC_HE 131
-
-#define FF_PROFILE_DTS 20
-#define FF_PROFILE_DTS_ES 30
-#define FF_PROFILE_DTS_96_24 40
-#define FF_PROFILE_DTS_HD_HRA 50
-#define FF_PROFILE_DTS_HD_MA 60
-#define FF_PROFILE_DTS_EXPRESS 70
-
-#define FF_PROFILE_MPEG2_422 0
-#define FF_PROFILE_MPEG2_HIGH 1
-#define FF_PROFILE_MPEG2_SS 2
-#define FF_PROFILE_MPEG2_SNR_SCALABLE 3
-#define FF_PROFILE_MPEG2_MAIN 4
-#define FF_PROFILE_MPEG2_SIMPLE 5
-
-#define FF_PROFILE_H264_CONSTRAINED (1<<9) // 8+1; constraint_set1_flag
-#define FF_PROFILE_H264_INTRA (1<<11) // 8+3; constraint_set3_flag
-
-#define FF_PROFILE_H264_BASELINE 66
-#define FF_PROFILE_H264_CONSTRAINED_BASELINE (66|FF_PROFILE_H264_CONSTRAINED)
-#define FF_PROFILE_H264_MAIN 77
-#define FF_PROFILE_H264_EXTENDED 88
-#define FF_PROFILE_H264_HIGH 100
-#define FF_PROFILE_H264_HIGH_10 110
-#define FF_PROFILE_H264_HIGH_10_INTRA (110|FF_PROFILE_H264_INTRA)
-#define FF_PROFILE_H264_HIGH_422 122
-#define FF_PROFILE_H264_HIGH_422_INTRA (122|FF_PROFILE_H264_INTRA)
-#define FF_PROFILE_H264_HIGH_444 144
-#define FF_PROFILE_H264_HIGH_444_PREDICTIVE 244
-#define FF_PROFILE_H264_HIGH_444_INTRA (244|FF_PROFILE_H264_INTRA)
-#define FF_PROFILE_H264_CAVLC_444 44
-
-#define FF_PROFILE_VC1_SIMPLE 0
-#define FF_PROFILE_VC1_MAIN 1
-#define FF_PROFILE_VC1_COMPLEX 2
-#define FF_PROFILE_VC1_ADVANCED 3
-
-#define FF_PROFILE_MPEG4_SIMPLE 0
-#define FF_PROFILE_MPEG4_SIMPLE_SCALABLE 1
-#define FF_PROFILE_MPEG4_CORE 2
-#define FF_PROFILE_MPEG4_MAIN 3
-#define FF_PROFILE_MPEG4_N_BIT 4
-#define FF_PROFILE_MPEG4_SCALABLE_TEXTURE 5
-#define FF_PROFILE_MPEG4_SIMPLE_FACE_ANIMATION 6
-#define FF_PROFILE_MPEG4_BASIC_ANIMATED_TEXTURE 7
-#define FF_PROFILE_MPEG4_HYBRID 8
-#define FF_PROFILE_MPEG4_ADVANCED_REAL_TIME 9
-#define FF_PROFILE_MPEG4_CORE_SCALABLE 10
-#define FF_PROFILE_MPEG4_ADVANCED_CODING 11
-#define FF_PROFILE_MPEG4_ADVANCED_CORE 12
-#define FF_PROFILE_MPEG4_ADVANCED_SCALABLE_TEXTURE 13
-#define FF_PROFILE_MPEG4_SIMPLE_STUDIO 14
-#define FF_PROFILE_MPEG4_ADVANCED_SIMPLE 15
-
-#define FF_PROFILE_JPEG2000_CSTREAM_RESTRICTION_0 0
-#define FF_PROFILE_JPEG2000_CSTREAM_RESTRICTION_1 1
-#define FF_PROFILE_JPEG2000_CSTREAM_NO_RESTRICTION 2
-#define FF_PROFILE_JPEG2000_DCINEMA_2K 3
-#define FF_PROFILE_JPEG2000_DCINEMA_4K 4
-
-#define FF_PROFILE_VP9_0 0
-#define FF_PROFILE_VP9_1 1
-#define FF_PROFILE_VP9_2 2
-#define FF_PROFILE_VP9_3 3
-
-#define FF_PROFILE_HEVC_MAIN 1
-#define FF_PROFILE_HEVC_MAIN_10 2
-#define FF_PROFILE_HEVC_MAIN_STILL_PICTURE 3
-#define FF_PROFILE_HEVC_REXT 4
-
- /**
- * level
- * - encoding: Set by user.
- * - decoding: Set by libavcodec.
- */
- int level;
-#define FF_LEVEL_UNKNOWN -99
-
- /**
- * Skip loop filtering for selected frames.
- * - encoding: unused
- * - decoding: Set by user.
- */
- enum AVDiscard skip_loop_filter;
-
- /**
- * Skip IDCT/dequantization for selected frames.
- * - encoding: unused
- * - decoding: Set by user.
- */
- enum AVDiscard skip_idct;
-
- /**
- * Skip decoding for selected frames.
- * - encoding: unused
- * - decoding: Set by user.
- */
- enum AVDiscard skip_frame;
-
- /**
- * Header containing style information for text subtitles.
- * For SUBTITLE_ASS subtitle type, it should contain the whole ASS
- * [Script Info] and [V4+ Styles] section, plus the [Events] line and
- * the Format line following. It shouldn't include any Dialogue line.
- * - encoding: Set/allocated/freed by user (before avcodec_open2())
- * - decoding: Set/allocated/freed by libavcodec (by avcodec_open2())
- */
- uint8_t *subtitle_header;
- int subtitle_header_size;
-
-#if FF_API_ERROR_RATE
- /**
- * @deprecated use the 'error_rate' private AVOption of the mpegvideo
- * encoders
- */
- attribute_deprecated
- int error_rate;
-#endif
-
-#if FF_API_VBV_DELAY
- /**
- * VBV delay coded in the last frame (in periods of a 27 MHz clock).
- * Used for compliant TS muxing.
- * - encoding: Set by libavcodec.
- * - decoding: unused.
- * @deprecated this value is now exported as a part of
- * AV_PKT_DATA_CPB_PROPERTIES packet side data
- */
- attribute_deprecated
- uint64_t vbv_delay;
-#endif
-
-#if FF_API_SIDEDATA_ONLY_PKT
- /**
- * Encoding only and set by default. Allow encoders to output packets
- * that do not contain any encoded data, only side data.
- *
- * Some encoders need to output such packets, e.g. to update some stream
- * parameters at the end of encoding.
- *
- * @deprecated this field disables the default behaviour and
- * it is kept only for compatibility.
- */
- attribute_deprecated
- int side_data_only_packets;
-#endif
-
- /**
- * Audio only. The number of "priming" samples (padding) inserted by the
- * encoder at the beginning of the audio. I.e. this number of leading
- * decoded samples must be discarded by the caller to get the original audio
- * without leading padding.
- *
- * - decoding: unused
- * - encoding: Set by libavcodec. The timestamps on the output packets are
- * adjusted by the encoder so that they always refer to the
- * first sample of the data actually contained in the packet,
- * including any added padding. E.g. if the timebase is
- * 1/samplerate and the timestamp of the first input sample is
- * 0, the timestamp of the first output packet will be
- * -initial_padding.
- */
- int initial_padding;
-
- /**
- * - decoding: For codecs that store a framerate value in the compressed
- * bitstream, the decoder may export it here. { 0, 1} when
- * unknown.
- * - encoding: unused
- */
- AVRational framerate;
-
- /**
- * Nominal unaccelerated pixel format, see AV_PIX_FMT_xxx.
- * - encoding: unused.
- * - decoding: Set by libavcodec before calling get_format()
- */
- enum AVPixelFormat sw_pix_fmt;
-
- /**
- * Timebase in which pkt_dts/pts and AVPacket.dts/pts are.
- * Code outside libavcodec should access this field using:
- * av_codec_{get,set}_pkt_timebase(avctx)
- * - encoding unused.
- * - decoding set by user.
- */
- AVRational pkt_timebase;
-
- /**
- * AVCodecDescriptor
- * Code outside libavcodec should access this field using:
- * av_codec_{get,set}_codec_descriptor(avctx)
- * - encoding: unused.
- * - decoding: set by libavcodec.
- */
- const AVCodecDescriptor *codec_descriptor;
-
-#if !FF_API_LOWRES
- /**
- * low resolution decoding, 1-> 1/2 size, 2->1/4 size
- * - encoding: unused
- * - decoding: Set by user.
- * Code outside libavcodec should access this field using:
- * av_codec_{get,set}_lowres(avctx)
- */
- int lowres;
-#endif
-
- /**
- * Current statistics for PTS correction.
- * - decoding: maintained and used by libavcodec, not intended to be used by user apps
- * - encoding: unused
- */
- int64_t pts_correction_num_faulty_pts; /// Number of incorrect PTS values so far
- int64_t pts_correction_num_faulty_dts; /// Number of incorrect DTS values so far
- int64_t pts_correction_last_pts; /// PTS of the last frame
- int64_t pts_correction_last_dts; /// DTS of the last frame
-
- /**
- * Character encoding of the input subtitles file.
- * - decoding: set by user
- * - encoding: unused
- */
- char *sub_charenc;
-
- /**
- * Subtitles character encoding mode. Formats or codecs might be adjusting
- * this setting (if they are doing the conversion themselves for instance).
- * - decoding: set by libavcodec
- * - encoding: unused
- */
- int sub_charenc_mode;
-#define FF_SUB_CHARENC_MODE_DO_NOTHING -1 ///< do nothing (demuxer outputs a stream supposed to be already in UTF-8, or the codec is bitmap for instance)
-#define FF_SUB_CHARENC_MODE_AUTOMATIC 0 ///< libavcodec will select the mode itself
-#define FF_SUB_CHARENC_MODE_PRE_DECODER 1 ///< the AVPacket data needs to be recoded to UTF-8 before being fed to the decoder, requires iconv
-
- /**
- * Skip processing alpha if supported by codec.
- * Note that if the format uses pre-multiplied alpha (common with VP6,
- * and recommended due to better video quality/compression)
- * the image will look as if alpha-blended onto a black background.
- * However for formats that do not use pre-multiplied alpha
- * there might be serious artefacts (though e.g. libswscale currently
- * assumes pre-multiplied alpha anyway).
- * Code outside libavcodec should access this field using AVOptions
- *
- * - decoding: set by user
- * - encoding: unused
- */
- int skip_alpha;
-
- /**
- * Number of samples to skip after a discontinuity
- * - decoding: unused
- * - encoding: set by libavcodec
- */
- int seek_preroll;
-
-#if !FF_API_DEBUG_MV
- /**
- * debug motion vectors
- * Code outside libavcodec should access this field using AVOptions
- * - encoding: Set by user.
- * - decoding: Set by user.
- */
- int debug_mv;
-#define FF_DEBUG_VIS_MV_P_FOR 0x00000001 //visualize forward predicted MVs of P frames
-#define FF_DEBUG_VIS_MV_B_FOR 0x00000002 //visualize forward predicted MVs of B frames
-#define FF_DEBUG_VIS_MV_B_BACK 0x00000004 //visualize backward predicted MVs of B frames
-#endif
-
- /**
- * custom intra quantization matrix
- * Code outside libavcodec should access this field using av_codec_g/set_chroma_intra_matrix()
- * - encoding: Set by user, can be NULL.
- * - decoding: unused.
- */
- uint16_t *chroma_intra_matrix;
-
- /**
- * dump format separator.
- * can be ", " or "\n " or anything else
- * Code outside libavcodec should access this field using AVOptions
- * (NO direct access).
- * - encoding: Set by user.
- * - decoding: Set by user.
- */
- uint8_t *dump_separator;
-
- /**
- * ',' separated list of allowed decoders.
- * If NULL then all are allowed
- * - encoding: unused
- * - decoding: set by user through AVOPtions (NO direct access)
- */
- char *codec_whitelist;
-
- /*
- * Properties of the stream that gets decoded
- * To be accessed through av_codec_get_properties() (NO direct access)
- * - encoding: unused
- * - decoding: set by libavcodec
- */
- unsigned properties;
-#define FF_CODEC_PROPERTY_LOSSLESS 0x00000001
-#define FF_CODEC_PROPERTY_CLOSED_CAPTIONS 0x00000002
-
- /**
- * Additional data associated with the entire coded stream.
- *
- * - decoding: unused
- * - encoding: may be set by libavcodec after avcodec_open2().
- */
- AVPacketSideData *coded_side_data;
- int nb_coded_side_data;
-
-} AVCodecContext;
-
-AVRational av_codec_get_pkt_timebase (const AVCodecContext *avctx);
-void av_codec_set_pkt_timebase (AVCodecContext *avctx, AVRational val);
-
-const AVCodecDescriptor *av_codec_get_codec_descriptor(const AVCodecContext *avctx);
-void av_codec_set_codec_descriptor(AVCodecContext *avctx, const AVCodecDescriptor *desc);
-
-unsigned av_codec_get_codec_properties(const AVCodecContext *avctx);
-
-int av_codec_get_lowres(const AVCodecContext *avctx);
-void av_codec_set_lowres(AVCodecContext *avctx, int val);
-
-int av_codec_get_seek_preroll(const AVCodecContext *avctx);
-void av_codec_set_seek_preroll(AVCodecContext *avctx, int val);
-
-uint16_t *av_codec_get_chroma_intra_matrix(const AVCodecContext *avctx);
-void av_codec_set_chroma_intra_matrix(AVCodecContext *avctx, uint16_t *val);
-
-/**
- * AVProfile.
- */
-typedef struct AVProfile {
- int profile;
- const char *name; ///< short name for the profile
-} AVProfile;
-
-typedef struct AVCodecDefault AVCodecDefault;
-
-struct AVSubtitle;
-
-/**
- * AVCodec.
- */
-typedef struct AVCodec {
- /**
- * Name of the codec implementation.
- * The name is globally unique among encoders and among decoders (but an
- * encoder and a decoder can share the same name).
- * This is the primary way to find a codec from the user perspective.
- */
- const char *name;
- /**
- * Descriptive name for the codec, meant to be more human readable than name.
- * You should use the NULL_IF_CONFIG_SMALL() macro to define it.
- */
- const char *long_name;
- enum AVMediaType type;
- enum AVCodecID id;
- /**
- * Codec capabilities.
- * see AV_CODEC_CAP_*
- */
- int capabilities;
- const AVRational *supported_framerates; ///< array of supported framerates, or NULL if any, array is terminated by {0,0}
- const enum AVPixelFormat *pix_fmts; ///< array of supported pixel formats, or NULL if unknown, array is terminated by -1
- const int *supported_samplerates; ///< array of supported audio samplerates, or NULL if unknown, array is terminated by 0
- const enum AVSampleFormat *sample_fmts; ///< array of supported sample formats, or NULL if unknown, array is terminated by -1
- const uint64_t *channel_layouts; ///< array of support channel layouts, or NULL if unknown. array is terminated by 0
- uint8_t max_lowres; ///< maximum value for lowres supported by the decoder, no direct access, use av_codec_get_max_lowres()
- const AVClass *priv_class; ///< AVClass for the private context
- const AVProfile *profiles; ///< array of recognized profiles, or NULL if unknown, array is terminated by {FF_PROFILE_UNKNOWN}
-
- /*****************************************************************
- * No fields below this line are part of the public API. They
- * may not be used outside of libavcodec and can be changed and
- * removed at will.
- * New public fields should be added right above.
- *****************************************************************
- */
- int priv_data_size;
- struct AVCodec *next;
- /**
- * @name Frame-level threading support functions
- * @{
- */
- /**
- * If defined, called on thread contexts when they are created.
- * If the codec allocates writable tables in init(), re-allocate them here.
- * priv_data will be set to a copy of the original.
- */
- int (*init_thread_copy)(AVCodecContext *);
- /**
- * Copy necessary context variables from a previous thread context to the current one.
- * If not defined, the next thread will start automatically; otherwise, the codec
- * must call ff_thread_finish_setup().
- *
- * dst and src will (rarely) point to the same context, in which case memcpy should be skipped.
- */
- int (*update_thread_context)(AVCodecContext *dst, const AVCodecContext *src);
- /** @} */
-
- /**
- * Private codec-specific defaults.
- */
- const AVCodecDefault *defaults;
-
- /**
- * Initialize codec static data, called from avcodec_register().
- */
- void (*init_static_data)(struct AVCodec *codec);
-
- int (*init)(AVCodecContext *);
- int (*encode_sub)(AVCodecContext *, uint8_t *buf, int buf_size,
- const struct AVSubtitle *sub);
- /**
- * Encode data to an AVPacket.
- *
- * @param avctx codec context
- * @param avpkt output AVPacket (may contain a user-provided buffer)
- * @param[in] frame AVFrame containing the raw data to be encoded
- * @param[out] got_packet_ptr encoder sets to 0 or 1 to indicate that a
- * non-empty packet was returned in avpkt.
- * @return 0 on success, negative error code on failure
- */
- int (*encode2)(AVCodecContext *avctx, AVPacket *avpkt, const AVFrame *frame,
- int *got_packet_ptr);
- int (*decode)(AVCodecContext *, void *outdata, int *outdata_size, AVPacket *avpkt);
- int (*close)(AVCodecContext *);
- /**
- * Flush buffers.
- * Will be called when seeking
- */
- void (*flush)(AVCodecContext *);
- /**
- * Internal codec capabilities.
- * See FF_CODEC_CAP_* in internal.h
- */
- int caps_internal;
-} AVCodec;
-
-int av_codec_get_max_lowres(const AVCodec *codec);
-
-struct MpegEncContext;
-
-/**
- * @defgroup lavc_hwaccel AVHWAccel
- * @{
- */
-typedef struct AVHWAccel {
- /**
- * Name of the hardware accelerated codec.
- * The name is globally unique among encoders and among decoders (but an
- * encoder and a decoder can share the same name).
- */
- const char *name;
-
- /**
- * Type of codec implemented by the hardware accelerator.
- *
- * See AVMEDIA_TYPE_xxx
- */
- enum AVMediaType type;
-
- /**
- * Codec implemented by the hardware accelerator.
- *
- * See AV_CODEC_ID_xxx
- */
- enum AVCodecID id;
-
- /**
- * Supported pixel format.
- *
- * Only hardware accelerated formats are supported here.
- */
- enum AVPixelFormat pix_fmt;
-
- /**
- * Hardware accelerated codec capabilities.
- * see HWACCEL_CODEC_CAP_*
- */
- int capabilities;
-
- /*****************************************************************
- * No fields below this line are part of the public API. They
- * may not be used outside of libavcodec and can be changed and
- * removed at will.
- * New public fields should be added right above.
- *****************************************************************
- */
- struct AVHWAccel *next;
-
- /**
- * Allocate a custom buffer
- */
- int (*alloc_frame)(AVCodecContext *avctx, AVFrame *frame);
-
- /**
- * Called at the beginning of each frame or field picture.
- *
- * Meaningful frame information (codec specific) is guaranteed to
- * be parsed at this point. This function is mandatory.
- *
- * Note that buf can be NULL along with buf_size set to 0.
- * Otherwise, this means the whole frame is available at this point.
- *
- * @param avctx the codec context
- * @param buf the frame data buffer base
- * @param buf_size the size of the frame in bytes
- * @return zero if successful, a negative value otherwise
- */
- int (*start_frame)(AVCodecContext *avctx, const uint8_t *buf, uint32_t buf_size);
-
- /**
- * Callback for each slice.
- *
- * Meaningful slice information (codec specific) is guaranteed to
- * be parsed at this point. This function is mandatory.
- * The only exception is XvMC, that works on MB level.
- *
- * @param avctx the codec context
- * @param buf the slice data buffer base
- * @param buf_size the size of the slice in bytes
- * @return zero if successful, a negative value otherwise
- */
- int (*decode_slice)(AVCodecContext *avctx, const uint8_t *buf, uint32_t buf_size);
-
- /**
- * Called at the end of each frame or field picture.
- *
- * The whole picture is parsed at this point and can now be sent
- * to the hardware accelerator. This function is mandatory.
- *
- * @param avctx the codec context
- * @return zero if successful, a negative value otherwise
- */
- int (*end_frame)(AVCodecContext *avctx);
-
- /**
- * Size of per-frame hardware accelerator private data.
- *
- * Private data is allocated with av_mallocz() before
- * AVCodecContext.get_buffer() and deallocated after
- * AVCodecContext.release_buffer().
- */
- int frame_priv_data_size;
-
- /**
- * Called for every Macroblock in a slice.
- *
- * XvMC uses it to replace the ff_mpv_decode_mb().
- * Instead of decoding to raw picture, MB parameters are
- * stored in an array provided by the video driver.
- *
- * @param s the mpeg context
- */
- void (*decode_mb)(struct MpegEncContext *s);
-
- /**
- * Initialize the hwaccel private data.
- *
- * This will be called from ff_get_format(), after hwaccel and
- * hwaccel_context are set and the hwaccel private data in AVCodecInternal
- * is allocated.
- */
- int (*init)(AVCodecContext *avctx);
-
- /**
- * Uninitialize the hwaccel private data.
- *
- * This will be called from get_format() or avcodec_close(), after hwaccel
- * and hwaccel_context are already uninitialized.
- */
- int (*uninit)(AVCodecContext *avctx);
-
- /**
- * Size of the private data to allocate in
- * AVCodecInternal.hwaccel_priv_data.
- */
- int priv_data_size;
-} AVHWAccel;
-
-/**
- * Hardware acceleration should be used for decoding even if the codec level
- * used is unknown or higher than the maximum supported level reported by the
- * hardware driver.
- *
- * It's generally a good idea to pass this flag unless you have a specific
- * reason not to, as hardware tends to under-report supported levels.
- */
-#define AV_HWACCEL_FLAG_IGNORE_LEVEL (1 << 0)
-
-/**
- * Hardware acceleration can output YUV pixel formats with a different chroma
- * sampling than 4:2:0 and/or other than 8 bits per component.
- */
-#define AV_HWACCEL_FLAG_ALLOW_HIGH_DEPTH (1 << 1)
-
-/**
- * @}
- */
-
-#if FF_API_AVPICTURE
-/**
- * @defgroup lavc_picture AVPicture
- *
- * Functions for working with AVPicture
- * @{
- */
-
-/**
- * Picture data structure.
- *
- * Up to four components can be stored into it, the last component is
- * alpha.
- * @deprecated use AVFrame or imgutils functions instead
- */
-typedef struct AVPicture {
- attribute_deprecated
- uint8_t *data[AV_NUM_DATA_POINTERS]; ///< pointers to the image data planes
- attribute_deprecated
- int linesize[AV_NUM_DATA_POINTERS]; ///< number of bytes per line
-} AVPicture;
-
-/**
- * @}
- */
-#endif
-
-enum AVSubtitleType {
- SUBTITLE_NONE,
-
- SUBTITLE_BITMAP, ///< A bitmap, pict will be set
-
- /**
- * Plain text, the text field must be set by the decoder and is
- * authoritative. ass and pict fields may contain approximations.
- */
- SUBTITLE_TEXT,
-
- /**
- * Formatted text, the ass field must be set by the decoder and is
- * authoritative. pict and text fields may contain approximations.
- */
- SUBTITLE_ASS,
-};
-
-#define AV_SUBTITLE_FLAG_FORCED 0x00000001
-
-typedef struct AVSubtitleRect {
- int x; ///< top left corner of pict, undefined when pict is not set
- int y; ///< top left corner of pict, undefined when pict is not set
- int w; ///< width of pict, undefined when pict is not set
- int h; ///< height of pict, undefined when pict is not set
- int nb_colors; ///< number of colors in pict, undefined when pict is not set
-
-#if FF_API_AVPICTURE
- /**
- * @deprecated unused
- */
- attribute_deprecated
- AVPicture pict;
-#endif
- /**
- * data+linesize for the bitmap of this subtitle.
- * Can be set for text/ass as well once they are rendered.
- */
- uint8_t *data[4];
- int linesize[4];
-
- enum AVSubtitleType type;
-
- char *text; ///< 0 terminated plain UTF-8 text
-
- /**
- * 0 terminated ASS/SSA compatible event line.
- * The presentation of this is unaffected by the other values in this
- * struct.
- */
- char *ass;
-
- int flags;
-} AVSubtitleRect;
-
-typedef struct AVSubtitle {
- uint16_t format; /* 0 = graphics */
- uint32_t start_display_time; /* relative to packet pts, in ms */
- uint32_t end_display_time; /* relative to packet pts, in ms */
- unsigned num_rects;
- AVSubtitleRect **rects;
- int64_t pts; ///< Same as packet pts, in AV_TIME_BASE
-} AVSubtitle;
-
-/**
- * If c is NULL, returns the first registered codec,
- * if c is non-NULL, returns the next registered codec after c,
- * or NULL if c is the last one.
- */
-AVCodec *av_codec_next(const AVCodec *c);
-
-/**
- * Return the LIBAVCODEC_VERSION_INT constant.
- */
-unsigned avcodec_version(void);
-
-/**
- * Return the libavcodec build-time configuration.
- */
-const char *avcodec_configuration(void);
-
-/**
- * Return the libavcodec license.
- */
-const char *avcodec_license(void);
-
-/**
- * Register the codec codec and initialize libavcodec.
- *
- * @warning either this function or avcodec_register_all() must be called
- * before any other libavcodec functions.
- *
- * @see avcodec_register_all()
- */
-void avcodec_register(AVCodec *codec);
-
-/**
- * Register all the codecs, parsers and bitstream filters which were enabled at
- * configuration time. If you do not call this function you can select exactly
- * which formats you want to support, by using the individual registration
- * functions.
- *
- * @see avcodec_register
- * @see av_register_codec_parser
- * @see av_register_bitstream_filter
- */
-void avcodec_register_all(void);
-
-/**
- * Allocate an AVCodecContext and set its fields to default values. The
- * resulting struct should be freed with avcodec_free_context().
- *
- * @param codec if non-NULL, allocate private data and initialize defaults
- * for the given codec. It is illegal to then call avcodec_open2()
- * with a different codec.
- * If NULL, then the codec-specific defaults won't be initialized,
- * which may result in suboptimal default settings (this is
- * important mainly for encoders, e.g. libx264).
- *
- * @return An AVCodecContext filled with default values or NULL on failure.
- * @see avcodec_get_context_defaults
- */
-AVCodecContext *avcodec_alloc_context3(const AVCodec *codec);
-
-/**
- * Free the codec context and everything associated with it and write NULL to
- * the provided pointer.
- */
-void avcodec_free_context(AVCodecContext **avctx);
-
-/**
- * Set the fields of the given AVCodecContext to default values corresponding
- * to the given codec (defaults may be codec-dependent).
- *
- * Do not call this function if a non-NULL codec has been passed
- * to avcodec_alloc_context3() that allocated this AVCodecContext.
- * If codec is non-NULL, it is illegal to call avcodec_open2() with a
- * different codec on this AVCodecContext.
- */
-int avcodec_get_context_defaults3(AVCodecContext *s, const AVCodec *codec);
-
-/**
- * Get the AVClass for AVCodecContext. It can be used in combination with
- * AV_OPT_SEARCH_FAKE_OBJ for examining options.
- *
- * @see av_opt_find().
- */
-const AVClass *avcodec_get_class(void);
-
-/**
- * Get the AVClass for AVFrame. It can be used in combination with
- * AV_OPT_SEARCH_FAKE_OBJ for examining options.
- *
- * @see av_opt_find().
- */
-const AVClass *avcodec_get_frame_class(void);
-
-/**
- * Get the AVClass for AVSubtitleRect. It can be used in combination with
- * AV_OPT_SEARCH_FAKE_OBJ for examining options.
- *
- * @see av_opt_find().
- */
-const AVClass *avcodec_get_subtitle_rect_class(void);
-
-/**
- * Copy the settings of the source AVCodecContext into the destination
- * AVCodecContext. The resulting destination codec context will be
- * unopened, i.e. you are required to call avcodec_open2() before you
- * can use this AVCodecContext to decode/encode video/audio data.
- *
- * @param dest target codec context, should be initialized with
- * avcodec_alloc_context3(NULL), but otherwise uninitialized
- * @param src source codec context
- * @return AVERROR() on error (e.g. memory allocation error), 0 on success
- */
-int avcodec_copy_context(AVCodecContext *dest, const AVCodecContext *src);
-
-/**
- * Initialize the AVCodecContext to use the given AVCodec. Prior to using this
- * function the context has to be allocated with avcodec_alloc_context3().
- *
- * The functions avcodec_find_decoder_by_name(), avcodec_find_encoder_by_name(),
- * avcodec_find_decoder() and avcodec_find_encoder() provide an easy way for
- * retrieving a codec.
- *
- * @warning This function is not thread safe!
- *
- * @note Always call this function before using decoding routines (such as
- * @ref avcodec_decode_video2()).
- *
- * @code
- * avcodec_register_all();
- * av_dict_set(&opts, "b", "2.5M", 0);
- * codec = avcodec_find_decoder(AV_CODEC_ID_H264);
- * if (!codec)
- * exit(1);
- *
- * context = avcodec_alloc_context3(codec);
- *
- * if (avcodec_open2(context, codec, opts) < 0)
- * exit(1);
- * @endcode
- *
- * @param avctx The context to initialize.
- * @param codec The codec to open this context for. If a non-NULL codec has been
- * previously passed to avcodec_alloc_context3() or
- * avcodec_get_context_defaults3() for this context, then this
- * parameter MUST be either NULL or equal to the previously passed
- * codec.
- * @param options A dictionary filled with AVCodecContext and codec-private options.
- * On return this object will be filled with options that were not found.
- *
- * @return zero on success, a negative value on error
- * @see avcodec_alloc_context3(), avcodec_find_decoder(), avcodec_find_encoder(),
- * av_dict_set(), av_opt_find().
- */
-int avcodec_open2(AVCodecContext *avctx, const AVCodec *codec, AVDictionary **options);
-
-/**
- * Close a given AVCodecContext and free all the data associated with it
- * (but not the AVCodecContext itself).
- *
- * Calling this function on an AVCodecContext that hasn't been opened will free
- * the codec-specific data allocated in avcodec_alloc_context3() /
- * avcodec_get_context_defaults3() with a non-NULL codec. Subsequent calls will
- * do nothing.
- */
-int avcodec_close(AVCodecContext *avctx);
-
-/**
- * Free all allocated data in the given subtitle struct.
- *
- * @param sub AVSubtitle to free.
- */
-void avsubtitle_free(AVSubtitle *sub);
-
-/**
- * @}
- */
-
-/**
- * @addtogroup lavc_packet
- * @{
- */
-
-/**
- * Allocate an AVPacket and set its fields to default values. The resulting
- * struct must be freed using av_packet_free().
- *
- * @return An AVPacket filled with default values or NULL on failure.
- *
- * @note this only allocates the AVPacket itself, not the data buffers. Those
- * must be allocated through other means such as av_new_packet.
- *
- * @see av_new_packet
- */
-AVPacket *av_packet_alloc(void);
-
-/**
- * Create a new packet that references the same data as src.
- *
- * This is a shortcut for av_packet_alloc()+av_packet_ref().
- *
- * @return newly created AVPacket on success, NULL on error.
- *
- * @see av_packet_alloc
- * @see av_packet_ref
- */
-AVPacket *av_packet_clone(AVPacket *src);
-
-/**
- * Free the packet, if the packet is reference counted, it will be
- * unreferenced first.
- *
- * @param packet packet to be freed. The pointer will be set to NULL.
- * @note passing NULL is a no-op.
- */
-void av_packet_free(AVPacket **pkt);
-
-/**
- * Initialize optional fields of a packet with default values.
- *
- * Note, this does not touch the data and size members, which have to be
- * initialized separately.
- *
- * @param pkt packet
- */
-void av_init_packet(AVPacket *pkt);
-
-/**
- * Allocate the payload of a packet and initialize its fields with
- * default values.
- *
- * @param pkt packet
- * @param size wanted payload size
- * @return 0 if OK, AVERROR_xxx otherwise
- */
-int av_new_packet(AVPacket *pkt, int size);
-
-/**
- * Reduce packet size, correctly zeroing padding
- *
- * @param pkt packet
- * @param size new size
- */
-void av_shrink_packet(AVPacket *pkt, int size);
-
-/**
- * Increase packet size, correctly zeroing padding
- *
- * @param pkt packet
- * @param grow_by number of bytes by which to increase the size of the packet
- */
-int av_grow_packet(AVPacket *pkt, int grow_by);
-
-/**
- * Initialize a reference-counted packet from av_malloc()ed data.
- *
- * @param pkt packet to be initialized. This function will set the data, size,
- * buf and destruct fields, all others are left untouched.
- * @param data Data allocated by av_malloc() to be used as packet data. If this
- * function returns successfully, the data is owned by the underlying AVBuffer.
- * The caller may not access the data through other means.
- * @param size size of data in bytes, without the padding. I.e. the full buffer
- * size is assumed to be size + AV_INPUT_BUFFER_PADDING_SIZE.
- *
- * @return 0 on success, a negative AVERROR on error
- */
-int av_packet_from_data(AVPacket *pkt, uint8_t *data, int size);
-
-#if FF_API_AVPACKET_OLD_API
-/**
- * @warning This is a hack - the packet memory allocation stuff is broken. The
- * packet is allocated if it was not really allocated.
- *
- * @deprecated Use av_packet_ref
- */
-attribute_deprecated
-int av_dup_packet(AVPacket *pkt);
-/**
- * Copy packet, including contents
- *
- * @return 0 on success, negative AVERROR on fail
- */
-int av_copy_packet(AVPacket *dst, const AVPacket *src);
-
-/**
- * Copy packet side data
- *
- * @return 0 on success, negative AVERROR on fail
- */
-int av_copy_packet_side_data(AVPacket *dst, const AVPacket *src);
-
-/**
- * Free a packet.
- *
- * @deprecated Use av_packet_unref
- *
- * @param pkt packet to free
- */
-attribute_deprecated
-void av_free_packet(AVPacket *pkt);
-#endif
-/**
- * Allocate new information of a packet.
- *
- * @param pkt packet
- * @param type side information type
- * @param size side information size
- * @return pointer to fresh allocated data or NULL otherwise
- */
-uint8_t* av_packet_new_side_data(AVPacket *pkt, enum AVPacketSideDataType type,
- int size);
-
-/**
- * Wrap an existing array as a packet side data.
- *
- * @param pkt packet
- * @param type side information type
- * @param data the side data array. It must be allocated with the av_malloc()
- * family of functions. The ownership of the data is transferred to
- * pkt.
- * @param size side information size
- * @return a non-negative number on success, a negative AVERROR code on
- * failure. On failure, the packet is unchanged and the data remains
- * owned by the caller.
- */
-int av_packet_add_side_data(AVPacket *pkt, enum AVPacketSideDataType type,
- uint8_t *data, size_t size);
-
-/**
- * Shrink the already allocated side data buffer
- *
- * @param pkt packet
- * @param type side information type
- * @param size new side information size
- * @return 0 on success, < 0 on failure
- */
-int av_packet_shrink_side_data(AVPacket *pkt, enum AVPacketSideDataType type,
- int size);
-
-/**
- * Get side information from packet.
- *
- * @param pkt packet
- * @param type desired side information type
- * @param size pointer for side information size to store (optional)
- * @return pointer to data if present or NULL otherwise
- */
-uint8_t* av_packet_get_side_data(AVPacket *pkt, enum AVPacketSideDataType type,
- int *size);
-
-int av_packet_merge_side_data(AVPacket *pkt);
-
-int av_packet_split_side_data(AVPacket *pkt);
-
-const char *av_packet_side_data_name(enum AVPacketSideDataType type);
-
-/**
- * Pack a dictionary for use in side_data.
- *
- * @param dict The dictionary to pack.
- * @param size pointer to store the size of the returned data
- * @return pointer to data if successful, NULL otherwise
- */
-uint8_t *av_packet_pack_dictionary(AVDictionary *dict, int *size);
-/**
- * Unpack a dictionary from side_data.
- *
- * @param data data from side_data
- * @param size size of the data
- * @param dict the metadata storage dictionary
- * @return 0 on success, < 0 on failure
- */
-int av_packet_unpack_dictionary(const uint8_t *data, int size, AVDictionary **dict);
-
-
-/**
- * Convenience function to free all the side data stored.
- * All the other fields stay untouched.
- *
- * @param pkt packet
- */
-void av_packet_free_side_data(AVPacket *pkt);
-
-/**
- * Setup a new reference to the data described by a given packet
- *
- * If src is reference-counted, setup dst as a new reference to the
- * buffer in src. Otherwise allocate a new buffer in dst and copy the
- * data from src into it.
- *
- * All the other fields are copied from src.
- *
- * @see av_packet_unref
- *
- * @param dst Destination packet
- * @param src Source packet
- *
- * @return 0 on success, a negative AVERROR on error.
- */
-int av_packet_ref(AVPacket *dst, const AVPacket *src);
-
-/**
- * Wipe the packet.
- *
- * Unreference the buffer referenced by the packet and reset the
- * remaining packet fields to their default values.
- *
- * @param pkt The packet to be unreferenced.
- */
-void av_packet_unref(AVPacket *pkt);
-
-/**
- * Move every field in src to dst and reset src.
- *
- * @see av_packet_unref
- *
- * @param src Source packet, will be reset
- * @param dst Destination packet
- */
-void av_packet_move_ref(AVPacket *dst, AVPacket *src);
-
-/**
- * Copy only "properties" fields from src to dst.
- *
- * Properties for the purpose of this function are all the fields
- * beside those related to the packet data (buf, data, size)
- *
- * @param dst Destination packet
- * @param src Source packet
- *
- * @return 0 on success AVERROR on failure.
- *
- */
-int av_packet_copy_props(AVPacket *dst, const AVPacket *src);
-
-/**
- * Convert valid timing fields (timestamps / durations) in a packet from one
- * timebase to another. Timestamps with unknown values (AV_NOPTS_VALUE) will be
- * ignored.
- *
- * @param pkt packet on which the conversion will be performed
- * @param tb_src source timebase, in which the timing fields in pkt are
- * expressed
- * @param tb_dst destination timebase, to which the timing fields will be
- * converted
- */
-void av_packet_rescale_ts(AVPacket *pkt, AVRational tb_src, AVRational tb_dst);
-
-/**
- * @}
- */
-
-/**
- * @addtogroup lavc_decoding
- * @{
- */
-
-/**
- * Find a registered decoder with a matching codec ID.
- *
- * @param id AVCodecID of the requested decoder
- * @return A decoder if one was found, NULL otherwise.
- */
-AVCodec *avcodec_find_decoder(enum AVCodecID id);
-
-/**
- * Find a registered decoder with the specified name.
- *
- * @param name name of the requested decoder
- * @return A decoder if one was found, NULL otherwise.
- */
-AVCodec *avcodec_find_decoder_by_name(const char *name);
-
-/**
- * The default callback for AVCodecContext.get_buffer2(). It is made public so
- * it can be called by custom get_buffer2() implementations for decoders without
- * AV_CODEC_CAP_DR1 set.
- */
-int avcodec_default_get_buffer2(AVCodecContext *s, AVFrame *frame, int flags);
-
-#if FF_API_EMU_EDGE
-/**
- * Return the amount of padding in pixels which the get_buffer callback must
- * provide around the edge of the image for codecs which do not have the
- * CODEC_FLAG_EMU_EDGE flag.
- *
- * @return Required padding in pixels.
- *
- * @deprecated CODEC_FLAG_EMU_EDGE is deprecated, so this function is no longer
- * needed
- */
-attribute_deprecated
-unsigned avcodec_get_edge_width(void);
-#endif
-
-/**
- * Modify width and height values so that they will result in a memory
- * buffer that is acceptable for the codec if you do not use any horizontal
- * padding.
- *
- * May only be used if a codec with AV_CODEC_CAP_DR1 has been opened.
- */
-void avcodec_align_dimensions(AVCodecContext *s, int *width, int *height);
-
-/**
- * Modify width and height values so that they will result in a memory
- * buffer that is acceptable for the codec if you also ensure that all
- * line sizes are a multiple of the respective linesize_align[i].
- *
- * May only be used if a codec with AV_CODEC_CAP_DR1 has been opened.
- */
-void avcodec_align_dimensions2(AVCodecContext *s, int *width, int *height,
- int linesize_align[AV_NUM_DATA_POINTERS]);
-
-/**
- * Converts AVChromaLocation to swscale x/y chroma position.
- *
- * The positions represent the chroma (0,0) position in a coordinates system
- * with luma (0,0) representing the origin and luma(1,1) representing 256,256
- *
- * @param xpos horizontal chroma sample position
- * @param ypos vertical chroma sample position
- */
-int avcodec_enum_to_chroma_pos(int *xpos, int *ypos, enum AVChromaLocation pos);
-
-/**
- * Converts swscale x/y chroma position to AVChromaLocation.
- *
- * The positions represent the chroma (0,0) position in a coordinates system
- * with luma (0,0) representing the origin and luma(1,1) representing 256,256
- *
- * @param xpos horizontal chroma sample position
- * @param ypos vertical chroma sample position
- */
-enum AVChromaLocation avcodec_chroma_pos_to_enum(int xpos, int ypos);
-
-/**
- * Decode the audio frame of size avpkt->size from avpkt->data into frame.
- *
- * Some decoders may support multiple frames in a single AVPacket. Such
- * decoders would then just decode the first frame and the return value would be
- * less than the packet size. In this case, avcodec_decode_audio4 has to be
- * called again with an AVPacket containing the remaining data in order to
- * decode the second frame, etc... Even if no frames are returned, the packet
- * needs to be fed to the decoder with remaining data until it is completely
- * consumed or an error occurs.
- *
- * Some decoders (those marked with AV_CODEC_CAP_DELAY) have a delay between input
- * and output. This means that for some packets they will not immediately
- * produce decoded output and need to be flushed at the end of decoding to get
- * all the decoded data. Flushing is done by calling this function with packets
- * with avpkt->data set to NULL and avpkt->size set to 0 until it stops
- * returning samples. It is safe to flush even those decoders that are not
- * marked with AV_CODEC_CAP_DELAY, then no samples will be returned.
- *
- * @warning The input buffer, avpkt->data must be AV_INPUT_BUFFER_PADDING_SIZE
- * larger than the actual read bytes because some optimized bitstream
- * readers read 32 or 64 bits at once and could read over the end.
- *
- * @note The AVCodecContext MUST have been opened with @ref avcodec_open2()
- * before packets may be fed to the decoder.
- *
- * @param avctx the codec context
- * @param[out] frame The AVFrame in which to store decoded audio samples.
- * The decoder will allocate a buffer for the decoded frame by
- * calling the AVCodecContext.get_buffer2() callback.
- * When AVCodecContext.refcounted_frames is set to 1, the frame is
- * reference counted and the returned reference belongs to the
- * caller. The caller must release the frame using av_frame_unref()
- * when the frame is no longer needed. The caller may safely write
- * to the frame if av_frame_is_writable() returns 1.
- * When AVCodecContext.refcounted_frames is set to 0, the returned
- * reference belongs to the decoder and is valid only until the
- * next call to this function or until closing or flushing the
- * decoder. The caller may not write to it.
- * @param[out] got_frame_ptr Zero if no frame could be decoded, otherwise it is
- * non-zero. Note that this field being set to zero
- * does not mean that an error has occurred. For
- * decoders with AV_CODEC_CAP_DELAY set, no given decode
- * call is guaranteed to produce a frame.
- * @param[in] avpkt The input AVPacket containing the input buffer.
- * At least avpkt->data and avpkt->size should be set. Some
- * decoders might also require additional fields to be set.
- * @return A negative error code is returned if an error occurred during
- * decoding, otherwise the number of bytes consumed from the input
- * AVPacket is returned.
- */
-int avcodec_decode_audio4(AVCodecContext *avctx, AVFrame *frame,
- int *got_frame_ptr, const AVPacket *avpkt);
-
-/**
- * Decode the video frame of size avpkt->size from avpkt->data into picture.
- * Some decoders may support multiple frames in a single AVPacket, such
- * decoders would then just decode the first frame.
- *
- * @warning The input buffer must be AV_INPUT_BUFFER_PADDING_SIZE larger than
- * the actual read bytes because some optimized bitstream readers read 32 or 64
- * bits at once and could read over the end.
- *
- * @warning The end of the input buffer buf should be set to 0 to ensure that
- * no overreading happens for damaged MPEG streams.
- *
- * @note Codecs which have the AV_CODEC_CAP_DELAY capability set have a delay
- * between input and output, these need to be fed with avpkt->data=NULL,
- * avpkt->size=0 at the end to return the remaining frames.
- *
- * @note The AVCodecContext MUST have been opened with @ref avcodec_open2()
- * before packets may be fed to the decoder.
- *
- * @param avctx the codec context
- * @param[out] picture The AVFrame in which the decoded video frame will be stored.
- * Use av_frame_alloc() to get an AVFrame. The codec will
- * allocate memory for the actual bitmap by calling the
- * AVCodecContext.get_buffer2() callback.
- * When AVCodecContext.refcounted_frames is set to 1, the frame is
- * reference counted and the returned reference belongs to the
- * caller. The caller must release the frame using av_frame_unref()
- * when the frame is no longer needed. The caller may safely write
- * to the frame if av_frame_is_writable() returns 1.
- * When AVCodecContext.refcounted_frames is set to 0, the returned
- * reference belongs to the decoder and is valid only until the
- * next call to this function or until closing or flushing the
- * decoder. The caller may not write to it.
- *
- * @param[in] avpkt The input AVPacket containing the input buffer.
- * You can create such packet with av_init_packet() and by then setting
- * data and size, some decoders might in addition need other fields like
- * flags&AV_PKT_FLAG_KEY. All decoders are designed to use the least
- * fields possible.
- * @param[in,out] got_picture_ptr Zero if no frame could be decompressed, otherwise, it is nonzero.
- * @return On error a negative value is returned, otherwise the number of bytes
- * used or zero if no frame could be decompressed.
- */
-int avcodec_decode_video2(AVCodecContext *avctx, AVFrame *picture,
- int *got_picture_ptr,
- const AVPacket *avpkt);
-
-/**
- * Decode a subtitle message.
- * Return a negative value on error, otherwise return the number of bytes used.
- * If no subtitle could be decompressed, got_sub_ptr is zero.
- * Otherwise, the subtitle is stored in *sub.
- * Note that AV_CODEC_CAP_DR1 is not available for subtitle codecs. This is for
- * simplicity, because the performance difference is expect to be negligible
- * and reusing a get_buffer written for video codecs would probably perform badly
- * due to a potentially very different allocation pattern.
- *
- * Some decoders (those marked with CODEC_CAP_DELAY) have a delay between input
- * and output. This means that for some packets they will not immediately
- * produce decoded output and need to be flushed at the end of decoding to get
- * all the decoded data. Flushing is done by calling this function with packets
- * with avpkt->data set to NULL and avpkt->size set to 0 until it stops
- * returning subtitles. It is safe to flush even those decoders that are not
- * marked with CODEC_CAP_DELAY, then no subtitles will be returned.
- *
- * @note The AVCodecContext MUST have been opened with @ref avcodec_open2()
- * before packets may be fed to the decoder.
- *
- * @param avctx the codec context
- * @param[out] sub The Preallocated AVSubtitle in which the decoded subtitle will be stored,
- * must be freed with avsubtitle_free if *got_sub_ptr is set.
- * @param[in,out] got_sub_ptr Zero if no subtitle could be decompressed, otherwise, it is nonzero.
- * @param[in] avpkt The input AVPacket containing the input buffer.
- */
-int avcodec_decode_subtitle2(AVCodecContext *avctx, AVSubtitle *sub,
- int *got_sub_ptr,
- AVPacket *avpkt);
-
-/**
- * @defgroup lavc_parsing Frame parsing
- * @{
- */
-
-enum AVPictureStructure {
- AV_PICTURE_STRUCTURE_UNKNOWN, //< unknown
- AV_PICTURE_STRUCTURE_TOP_FIELD, //< coded as top field
- AV_PICTURE_STRUCTURE_BOTTOM_FIELD, //< coded as bottom field
- AV_PICTURE_STRUCTURE_FRAME, //< coded as frame
-};
-
-typedef struct AVCodecParserContext {
- void *priv_data;
- struct AVCodecParser *parser;
- int64_t frame_offset; /* offset of the current frame */
- int64_t cur_offset; /* current offset
- (incremented by each av_parser_parse()) */
- int64_t next_frame_offset; /* offset of the next frame */
- /* video info */
- int pict_type; /* XXX: Put it back in AVCodecContext. */
- /**
- * This field is used for proper frame duration computation in lavf.
- * It signals, how much longer the frame duration of the current frame
- * is compared to normal frame duration.
- *
- * frame_duration = (1 + repeat_pict) * time_base
- *
- * It is used by codecs like H.264 to display telecined material.
- */
- int repeat_pict; /* XXX: Put it back in AVCodecContext. */
- int64_t pts; /* pts of the current frame */
- int64_t dts; /* dts of the current frame */
-
- /* private data */
- int64_t last_pts;
- int64_t last_dts;
- int fetch_timestamp;
-
-#define AV_PARSER_PTS_NB 4
- int cur_frame_start_index;
- int64_t cur_frame_offset[AV_PARSER_PTS_NB];
- int64_t cur_frame_pts[AV_PARSER_PTS_NB];
- int64_t cur_frame_dts[AV_PARSER_PTS_NB];
-
- int flags;
-#define PARSER_FLAG_COMPLETE_FRAMES 0x0001
-#define PARSER_FLAG_ONCE 0x0002
-/// Set if the parser has a valid file offset
-#define PARSER_FLAG_FETCHED_OFFSET 0x0004
-#define PARSER_FLAG_USE_CODEC_TS 0x1000
-
- int64_t offset; ///< byte offset from starting packet start
- int64_t cur_frame_end[AV_PARSER_PTS_NB];
-
- /**
- * Set by parser to 1 for key frames and 0 for non-key frames.
- * It is initialized to -1, so if the parser doesn't set this flag,
- * old-style fallback using AV_PICTURE_TYPE_I picture type as key frames
- * will be used.
- */
- int key_frame;
-
-#if FF_API_CONVERGENCE_DURATION
- /**
- * @deprecated unused
- */
- attribute_deprecated
- int64_t convergence_duration;
-#endif
-
- // Timestamp generation support:
- /**
- * Synchronization point for start of timestamp generation.
- *
- * Set to >0 for sync point, 0 for no sync point and <0 for undefined
- * (default).
- *
- * For example, this corresponds to presence of H.264 buffering period
- * SEI message.
- */
- int dts_sync_point;
-
- /**
- * Offset of the current timestamp against last timestamp sync point in
- * units of AVCodecContext.time_base.
- *
- * Set to INT_MIN when dts_sync_point unused. Otherwise, it must
- * contain a valid timestamp offset.
- *
- * Note that the timestamp of sync point has usually a nonzero
- * dts_ref_dts_delta, which refers to the previous sync point. Offset of
- * the next frame after timestamp sync point will be usually 1.
- *
- * For example, this corresponds to H.264 cpb_removal_delay.
- */
- int dts_ref_dts_delta;
-
- /**
- * Presentation delay of current frame in units of AVCodecContext.time_base.
- *
- * Set to INT_MIN when dts_sync_point unused. Otherwise, it must
- * contain valid non-negative timestamp delta (presentation time of a frame
- * must not lie in the past).
- *
- * This delay represents the difference between decoding and presentation
- * time of the frame.
- *
- * For example, this corresponds to H.264 dpb_output_delay.
- */
- int pts_dts_delta;
-
- /**
- * Position of the packet in file.
- *
- * Analogous to cur_frame_pts/dts
- */
- int64_t cur_frame_pos[AV_PARSER_PTS_NB];
-
- /**
- * Byte position of currently parsed frame in stream.
- */
- int64_t pos;
-
- /**
- * Previous frame byte position.
- */
- int64_t last_pos;
-
- /**
- * Duration of the current frame.
- * For audio, this is in units of 1 / AVCodecContext.sample_rate.
- * For all other types, this is in units of AVCodecContext.time_base.
- */
- int duration;
-
- enum AVFieldOrder field_order;
-
- /**
- * Indicate whether a picture is coded as a frame, top field or bottom field.
- *
- * For example, H.264 field_pic_flag equal to 0 corresponds to
- * AV_PICTURE_STRUCTURE_FRAME. An H.264 picture with field_pic_flag
- * equal to 1 and bottom_field_flag equal to 0 corresponds to
- * AV_PICTURE_STRUCTURE_TOP_FIELD.
- */
- enum AVPictureStructure picture_structure;
-
- /**
- * Picture number incremented in presentation or output order.
- * This field may be reinitialized at the first picture of a new sequence.
- *
- * For example, this corresponds to H.264 PicOrderCnt.
- */
- int output_picture_number;
-
- /**
- * Dimensions of the decoded video intended for presentation.
- */
- int width;
- int height;
-
- /**
- * Dimensions of the coded video.
- */
- int coded_width;
- int coded_height;
-
- /**
- * The format of the coded data, corresponds to enum AVPixelFormat for video
- * and for enum AVSampleFormat for audio.
- *
- * Note that a decoder can have considerable freedom in how exactly it
- * decodes the data, so the format reported here might be different from the
- * one returned by a decoder.
- */
- int format;
-} AVCodecParserContext;
-
-typedef struct AVCodecParser {
- int codec_ids[5]; /* several codec IDs are permitted */
- int priv_data_size;
- int (*parser_init)(AVCodecParserContext *s);
- /* This callback never returns an error, a negative value means that
- * the frame start was in a previous packet. */
- int (*parser_parse)(AVCodecParserContext *s,
- AVCodecContext *avctx,
- const uint8_t **poutbuf, int *poutbuf_size,
- const uint8_t *buf, int buf_size);
- void (*parser_close)(AVCodecParserContext *s);
- int (*split)(AVCodecContext *avctx, const uint8_t *buf, int buf_size);
- struct AVCodecParser *next;
-} AVCodecParser;
-
-AVCodecParser *av_parser_next(const AVCodecParser *c);
-
-void av_register_codec_parser(AVCodecParser *parser);
-AVCodecParserContext *av_parser_init(int codec_id);
-
-/**
- * Parse a packet.
- *
- * @param s parser context.
- * @param avctx codec context.
- * @param poutbuf set to pointer to parsed buffer or NULL if not yet finished.
- * @param poutbuf_size set to size of parsed buffer or zero if not yet finished.
- * @param buf input buffer.
- * @param buf_size input length, to signal EOF, this should be 0 (so that the last frame can be output).
- * @param pts input presentation timestamp.
- * @param dts input decoding timestamp.
- * @param pos input byte position in stream.
- * @return the number of bytes of the input bitstream used.
- *
- * Example:
- * @code
- * while(in_len){
- * len = av_parser_parse2(myparser, AVCodecContext, &data, &size,
- * in_data, in_len,
- * pts, dts, pos);
- * in_data += len;
- * in_len -= len;
- *
- * if(size)
- * decode_frame(data, size);
- * }
- * @endcode
- */
-int av_parser_parse2(AVCodecParserContext *s,
- AVCodecContext *avctx,
- uint8_t **poutbuf, int *poutbuf_size,
- const uint8_t *buf, int buf_size,
- int64_t pts, int64_t dts,
- int64_t pos);
-
-/**
- * @return 0 if the output buffer is a subset of the input, 1 if it is allocated and must be freed
- * @deprecated use AVBitStreamFilter
- */
-int av_parser_change(AVCodecParserContext *s,
- AVCodecContext *avctx,
- uint8_t **poutbuf, int *poutbuf_size,
- const uint8_t *buf, int buf_size, int keyframe);
-void av_parser_close(AVCodecParserContext *s);
-
-/**
- * @}
- * @}
- */
-
-/**
- * @addtogroup lavc_encoding
- * @{
- */
-
-/**
- * Find a registered encoder with a matching codec ID.
- *
- * @param id AVCodecID of the requested encoder
- * @return An encoder if one was found, NULL otherwise.
- */
-AVCodec *avcodec_find_encoder(enum AVCodecID id);
-
-/**
- * Find a registered encoder with the specified name.
- *
- * @param name name of the requested encoder
- * @return An encoder if one was found, NULL otherwise.
- */
-AVCodec *avcodec_find_encoder_by_name(const char *name);
-
-/**
- * Encode a frame of audio.
- *
- * Takes input samples from frame and writes the next output packet, if
- * available, to avpkt. The output packet does not necessarily contain data for
- * the most recent frame, as encoders can delay, split, and combine input frames
- * internally as needed.
- *
- * @param avctx codec context
- * @param avpkt output AVPacket.
- * The user can supply an output buffer by setting
- * avpkt->data and avpkt->size prior to calling the
- * function, but if the size of the user-provided data is not
- * large enough, encoding will fail. If avpkt->data and
- * avpkt->size are set, avpkt->destruct must also be set. All
- * other AVPacket fields will be reset by the encoder using
- * av_init_packet(). If avpkt->data is NULL, the encoder will
- * allocate it. The encoder will set avpkt->size to the size
- * of the output packet.
- *
- * If this function fails or produces no output, avpkt will be
- * freed using av_packet_unref().
- * @param[in] frame AVFrame containing the raw audio data to be encoded.
- * May be NULL when flushing an encoder that has the
- * AV_CODEC_CAP_DELAY capability set.
- * If AV_CODEC_CAP_VARIABLE_FRAME_SIZE is set, then each frame
- * can have any number of samples.
- * If it is not set, frame->nb_samples must be equal to
- * avctx->frame_size for all frames except the last.
- * The final frame may be smaller than avctx->frame_size.
- * @param[out] got_packet_ptr This field is set to 1 by libavcodec if the
- * output packet is non-empty, and to 0 if it is
- * empty. If the function returns an error, the
- * packet can be assumed to be invalid, and the
- * value of got_packet_ptr is undefined and should
- * not be used.
- * @return 0 on success, negative error code on failure
- */
-int avcodec_encode_audio2(AVCodecContext *avctx, AVPacket *avpkt,
- const AVFrame *frame, int *got_packet_ptr);
-
-/**
- * Encode a frame of video.
- *
- * Takes input raw video data from frame and writes the next output packet, if
- * available, to avpkt. The output packet does not necessarily contain data for
- * the most recent frame, as encoders can delay and reorder input frames
- * internally as needed.
- *
- * @param avctx codec context
- * @param avpkt output AVPacket.
- * The user can supply an output buffer by setting
- * avpkt->data and avpkt->size prior to calling the
- * function, but if the size of the user-provided data is not
- * large enough, encoding will fail. All other AVPacket fields
- * will be reset by the encoder using av_init_packet(). If
- * avpkt->data is NULL, the encoder will allocate it.
- * The encoder will set avpkt->size to the size of the
- * output packet. The returned data (if any) belongs to the
- * caller, he is responsible for freeing it.
- *
- * If this function fails or produces no output, avpkt will be
- * freed using av_packet_unref().
- * @param[in] frame AVFrame containing the raw video data to be encoded.
- * May be NULL when flushing an encoder that has the
- * AV_CODEC_CAP_DELAY capability set.
- * @param[out] got_packet_ptr This field is set to 1 by libavcodec if the
- * output packet is non-empty, and to 0 if it is
- * empty. If the function returns an error, the
- * packet can be assumed to be invalid, and the
- * value of got_packet_ptr is undefined and should
- * not be used.
- * @return 0 on success, negative error code on failure
- */
-int avcodec_encode_video2(AVCodecContext *avctx, AVPacket *avpkt,
- const AVFrame *frame, int *got_packet_ptr);
-
-int avcodec_encode_subtitle(AVCodecContext *avctx, uint8_t *buf, int buf_size,
- const AVSubtitle *sub);
-
-
-/**
- * @}
- */
-
-#if FF_API_AVCODEC_RESAMPLE
-/**
- * @defgroup lavc_resample Audio resampling
- * @ingroup libavc
- * @deprecated use libswresample instead
- *
- * @{
- */
-struct ReSampleContext;
-struct AVResampleContext;
-
-typedef struct ReSampleContext ReSampleContext;
-
-/**
- * Initialize audio resampling context.
- *
- * @param output_channels number of output channels
- * @param input_channels number of input channels
- * @param output_rate output sample rate
- * @param input_rate input sample rate
- * @param sample_fmt_out requested output sample format
- * @param sample_fmt_in input sample format
- * @param filter_length length of each FIR filter in the filterbank relative to the cutoff frequency
- * @param log2_phase_count log2 of the number of entries in the polyphase filterbank
- * @param linear if 1 then the used FIR filter will be linearly interpolated
- between the 2 closest, if 0 the closest will be used
- * @param cutoff cutoff frequency, 1.0 corresponds to half the output sampling rate
- * @return allocated ReSampleContext, NULL if error occurred
- */
-attribute_deprecated
-ReSampleContext *av_audio_resample_init(int output_channels, int input_channels,
- int output_rate, int input_rate,
- enum AVSampleFormat sample_fmt_out,
- enum AVSampleFormat sample_fmt_in,
- int filter_length, int log2_phase_count,
- int linear, double cutoff);
-
-attribute_deprecated
-int audio_resample(ReSampleContext *s, short *output, short *input, int nb_samples);
-
-/**
- * Free resample context.
- *
- * @param s a non-NULL pointer to a resample context previously
- * created with av_audio_resample_init()
- */
-attribute_deprecated
-void audio_resample_close(ReSampleContext *s);
-
-
-/**
- * Initialize an audio resampler.
- * Note, if either rate is not an integer then simply scale both rates up so they are.
- * @param filter_length length of each FIR filter in the filterbank relative to the cutoff freq
- * @param log2_phase_count log2 of the number of entries in the polyphase filterbank
- * @param linear If 1 then the used FIR filter will be linearly interpolated
- between the 2 closest, if 0 the closest will be used
- * @param cutoff cutoff frequency, 1.0 corresponds to half the output sampling rate
- */
-attribute_deprecated
-struct AVResampleContext *av_resample_init(int out_rate, int in_rate, int filter_length, int log2_phase_count, int linear, double cutoff);
-
-/**
- * Resample an array of samples using a previously configured context.
- * @param src an array of unconsumed samples
- * @param consumed the number of samples of src which have been consumed are returned here
- * @param src_size the number of unconsumed samples available
- * @param dst_size the amount of space in samples available in dst
- * @param update_ctx If this is 0 then the context will not be modified, that way several channels can be resampled with the same context.
- * @return the number of samples written in dst or -1 if an error occurred
- */
-attribute_deprecated
-int av_resample(struct AVResampleContext *c, short *dst, short *src, int *consumed, int src_size, int dst_size, int update_ctx);
-
-
-/**
- * Compensate samplerate/timestamp drift. The compensation is done by changing
- * the resampler parameters, so no audible clicks or similar distortions occur
- * @param compensation_distance distance in output samples over which the compensation should be performed
- * @param sample_delta number of output samples which should be output less
- *
- * example: av_resample_compensate(c, 10, 500)
- * here instead of 510 samples only 500 samples would be output
- *
- * note, due to rounding the actual compensation might be slightly different,
- * especially if the compensation_distance is large and the in_rate used during init is small
- */
-attribute_deprecated
-void av_resample_compensate(struct AVResampleContext *c, int sample_delta, int compensation_distance);
-attribute_deprecated
-void av_resample_close(struct AVResampleContext *c);
-
-/**
- * @}
- */
-#endif
-
-#if FF_API_AVPICTURE
-/**
- * @addtogroup lavc_picture
- * @{
- */
-
-/**
- * @deprecated unused
- */
-attribute_deprecated
-int avpicture_alloc(AVPicture *picture, enum AVPixelFormat pix_fmt, int width, int height);
-
-/**
- * @deprecated unused
- */
-attribute_deprecated
-void avpicture_free(AVPicture *picture);
-
-/**
- * @deprecated use av_image_fill_arrays() instead.
- */
-attribute_deprecated
-int avpicture_fill(AVPicture *picture, const uint8_t *ptr,
- enum AVPixelFormat pix_fmt, int width, int height);
-
-/**
- * @deprecated use av_image_copy_to_buffer() instead.
- */
-attribute_deprecated
-int avpicture_layout(const AVPicture *src, enum AVPixelFormat pix_fmt,
- int width, int height,
- unsigned char *dest, int dest_size);
-
-/**
- * @deprecated use av_image_get_buffer_size() instead.
- */
-attribute_deprecated
-int avpicture_get_size(enum AVPixelFormat pix_fmt, int width, int height);
-
-/**
- * @deprecated av_image_copy() instead.
- */
-attribute_deprecated
-void av_picture_copy(AVPicture *dst, const AVPicture *src,
- enum AVPixelFormat pix_fmt, int width, int height);
-
-/**
- * @deprecated unused
- */
-attribute_deprecated
-int av_picture_crop(AVPicture *dst, const AVPicture *src,
- enum AVPixelFormat pix_fmt, int top_band, int left_band);
-
-/**
- * @deprecated unused
- */
-attribute_deprecated
-int av_picture_pad(AVPicture *dst, const AVPicture *src, int height, int width, enum AVPixelFormat pix_fmt,
- int padtop, int padbottom, int padleft, int padright, int *color);
-
-/**
- * @}
- */
-#endif
-
-/**
- * @defgroup lavc_misc Utility functions
- * @ingroup libavc
- *
- * Miscellaneous utility functions related to both encoding and decoding
- * (or neither).
- * @{
- */
-
-/**
- * @defgroup lavc_misc_pixfmt Pixel formats
- *
- * Functions for working with pixel formats.
- * @{
- */
-
-/**
- * Utility function to access log2_chroma_w log2_chroma_h from
- * the pixel format AVPixFmtDescriptor.
- *
- * This function asserts that pix_fmt is valid. See av_pix_fmt_get_chroma_sub_sample
- * for one that returns a failure code and continues in case of invalid
- * pix_fmts.
- *
- * @param[in] pix_fmt the pixel format
- * @param[out] h_shift store log2_chroma_w
- * @param[out] v_shift store log2_chroma_h
- *
- * @see av_pix_fmt_get_chroma_sub_sample
- */
-
-void avcodec_get_chroma_sub_sample(enum AVPixelFormat pix_fmt, int *h_shift, int *v_shift);
-
-/**
- * Return a value representing the fourCC code associated to the
- * pixel format pix_fmt, or 0 if no associated fourCC code can be
- * found.
- */
-unsigned int avcodec_pix_fmt_to_codec_tag(enum AVPixelFormat pix_fmt);
-
-/**
- * @deprecated see av_get_pix_fmt_loss()
- */
-int avcodec_get_pix_fmt_loss(enum AVPixelFormat dst_pix_fmt, enum AVPixelFormat src_pix_fmt,
- int has_alpha);
-
-/**
- * Find the best pixel format to convert to given a certain source pixel
- * format. When converting from one pixel format to another, information loss
- * may occur. For example, when converting from RGB24 to GRAY, the color
- * information will be lost. Similarly, other losses occur when converting from
- * some formats to other formats. avcodec_find_best_pix_fmt_of_2() searches which of
- * the given pixel formats should be used to suffer the least amount of loss.
- * The pixel formats from which it chooses one, are determined by the
- * pix_fmt_list parameter.
- *
- *
- * @param[in] pix_fmt_list AV_PIX_FMT_NONE terminated array of pixel formats to choose from
- * @param[in] src_pix_fmt source pixel format
- * @param[in] has_alpha Whether the source pixel format alpha channel is used.
- * @param[out] loss_ptr Combination of flags informing you what kind of losses will occur.
- * @return The best pixel format to convert to or -1 if none was found.
- */
-enum AVPixelFormat avcodec_find_best_pix_fmt_of_list(const enum AVPixelFormat *pix_fmt_list,
- enum AVPixelFormat src_pix_fmt,
- int has_alpha, int *loss_ptr);
-
-/**
- * @deprecated see av_find_best_pix_fmt_of_2()
- */
-enum AVPixelFormat avcodec_find_best_pix_fmt_of_2(enum AVPixelFormat dst_pix_fmt1, enum AVPixelFormat dst_pix_fmt2,
- enum AVPixelFormat src_pix_fmt, int has_alpha, int *loss_ptr);
-
-attribute_deprecated
-#if AV_HAVE_INCOMPATIBLE_LIBAV_ABI
-enum AVPixelFormat avcodec_find_best_pix_fmt2(const enum AVPixelFormat *pix_fmt_list,
- enum AVPixelFormat src_pix_fmt,
- int has_alpha, int *loss_ptr);
-#else
-enum AVPixelFormat avcodec_find_best_pix_fmt2(enum AVPixelFormat dst_pix_fmt1, enum AVPixelFormat dst_pix_fmt2,
- enum AVPixelFormat src_pix_fmt, int has_alpha, int *loss_ptr);
-#endif
-
-
-enum AVPixelFormat avcodec_default_get_format(struct AVCodecContext *s, const enum AVPixelFormat * fmt);
-
-/**
- * @}
- */
-
-#if FF_API_SET_DIMENSIONS
-/**
- * @deprecated this function is not supposed to be used from outside of lavc
- */
-attribute_deprecated
-void avcodec_set_dimensions(AVCodecContext *s, int width, int height);
-#endif
-
-/**
- * Put a string representing the codec tag codec_tag in buf.
- *
- * @param buf buffer to place codec tag in
- * @param buf_size size in bytes of buf
- * @param codec_tag codec tag to assign
- * @return the length of the string that would have been generated if
- * enough space had been available, excluding the trailing null
- */
-size_t av_get_codec_tag_string(char *buf, size_t buf_size, unsigned int codec_tag);
-
-void avcodec_string(char *buf, int buf_size, AVCodecContext *enc, int encode);
-
-/**
- * Return a name for the specified profile, if available.
- *
- * @param codec the codec that is searched for the given profile
- * @param profile the profile value for which a name is requested
- * @return A name for the profile if found, NULL otherwise.
- */
-const char *av_get_profile_name(const AVCodec *codec, int profile);
-
-/**
- * Return a name for the specified profile, if available.
- *
- * @param codec_id the ID of the codec to which the requested profile belongs
- * @param profile the profile value for which a name is requested
- * @return A name for the profile if found, NULL otherwise.
- *
- * @note unlike av_get_profile_name(), which searches a list of profiles
- * supported by a specific decoder or encoder implementation, this
- * function searches the list of profiles from the AVCodecDescriptor
- */
-const char *avcodec_profile_name(enum AVCodecID codec_id, int profile);
-
-int avcodec_default_execute(AVCodecContext *c, int (*func)(AVCodecContext *c2, void *arg2),void *arg, int *ret, int count, int size);
-int avcodec_default_execute2(AVCodecContext *c, int (*func)(AVCodecContext *c2, void *arg2, int, int),void *arg, int *ret, int count);
-//FIXME func typedef
-
-/**
- * Fill AVFrame audio data and linesize pointers.
- *
- * The buffer buf must be a preallocated buffer with a size big enough
- * to contain the specified samples amount. The filled AVFrame data
- * pointers will point to this buffer.
- *
- * AVFrame extended_data channel pointers are allocated if necessary for
- * planar audio.
- *
- * @param frame the AVFrame
- * frame->nb_samples must be set prior to calling the
- * function. This function fills in frame->data,
- * frame->extended_data, frame->linesize[0].
- * @param nb_channels channel count
- * @param sample_fmt sample format
- * @param buf buffer to use for frame data
- * @param buf_size size of buffer
- * @param align plane size sample alignment (0 = default)
- * @return >=0 on success, negative error code on failure
- * @todo return the size in bytes required to store the samples in
- * case of success, at the next libavutil bump
- */
-int avcodec_fill_audio_frame(AVFrame *frame, int nb_channels,
- enum AVSampleFormat sample_fmt, const uint8_t *buf,
- int buf_size, int align);
-
-/**
- * Reset the internal decoder state / flush internal buffers. Should be called
- * e.g. when seeking or when switching to a different stream.
- *
- * @note when refcounted frames are not used (i.e. avctx->refcounted_frames is 0),
- * this invalidates the frames previously returned from the decoder. When
- * refcounted frames are used, the decoder just releases any references it might
- * keep internally, but the caller's reference remains valid.
- */
-void avcodec_flush_buffers(AVCodecContext *avctx);
-
-/**
- * Return codec bits per sample.
- *
- * @param[in] codec_id the codec
- * @return Number of bits per sample or zero if unknown for the given codec.
- */
-int av_get_bits_per_sample(enum AVCodecID codec_id);
-
-/**
- * Return the PCM codec associated with a sample format.
- * @param be endianness, 0 for little, 1 for big,
- * -1 (or anything else) for native
- * @return AV_CODEC_ID_PCM_* or AV_CODEC_ID_NONE
- */
-enum AVCodecID av_get_pcm_codec(enum AVSampleFormat fmt, int be);
-
-/**
- * Return codec bits per sample.
- * Only return non-zero if the bits per sample is exactly correct, not an
- * approximation.
- *
- * @param[in] codec_id the codec
- * @return Number of bits per sample or zero if unknown for the given codec.
- */
-int av_get_exact_bits_per_sample(enum AVCodecID codec_id);
-
-/**
- * Return audio frame duration.
- *
- * @param avctx codec context
- * @param frame_bytes size of the frame, or 0 if unknown
- * @return frame duration, in samples, if known. 0 if not able to
- * determine.
- */
-int av_get_audio_frame_duration(AVCodecContext *avctx, int frame_bytes);
-
-
-typedef struct AVBitStreamFilterContext {
- void *priv_data;
- struct AVBitStreamFilter *filter;
- AVCodecParserContext *parser;
- struct AVBitStreamFilterContext *next;
- /**
- * Internal default arguments, used if NULL is passed to av_bitstream_filter_filter().
- * Not for access by library users.
- */
- char *args;
-} AVBitStreamFilterContext;
-
-
-typedef struct AVBitStreamFilter {
- const char *name;
- int priv_data_size;
- int (*filter)(AVBitStreamFilterContext *bsfc,
- AVCodecContext *avctx, const char *args,
- uint8_t **poutbuf, int *poutbuf_size,
- const uint8_t *buf, int buf_size, int keyframe);
- void (*close)(AVBitStreamFilterContext *bsfc);
- struct AVBitStreamFilter *next;
-} AVBitStreamFilter;
-
-/**
- * Register a bitstream filter.
- *
- * The filter will be accessible to the application code through
- * av_bitstream_filter_next() or can be directly initialized with
- * av_bitstream_filter_init().
- *
- * @see avcodec_register_all()
- */
-void av_register_bitstream_filter(AVBitStreamFilter *bsf);
-
-/**
- * Create and initialize a bitstream filter context given a bitstream
- * filter name.
- *
- * The returned context must be freed with av_bitstream_filter_close().
- *
- * @param name the name of the bitstream filter
- * @return a bitstream filter context if a matching filter was found
- * and successfully initialized, NULL otherwise
- */
-AVBitStreamFilterContext *av_bitstream_filter_init(const char *name);
-
-/**
- * Filter bitstream.
- *
- * This function filters the buffer buf with size buf_size, and places the
- * filtered buffer in the buffer pointed to by poutbuf.
- *
- * The output buffer must be freed by the caller.
- *
- * @param bsfc bitstream filter context created by av_bitstream_filter_init()
- * @param avctx AVCodecContext accessed by the filter, may be NULL.
- * If specified, this must point to the encoder context of the
- * output stream the packet is sent to.
- * @param args arguments which specify the filter configuration, may be NULL
- * @param poutbuf pointer which is updated to point to the filtered buffer
- * @param poutbuf_size pointer which is updated to the filtered buffer size in bytes
- * @param buf buffer containing the data to filter
- * @param buf_size size in bytes of buf
- * @param keyframe set to non-zero if the buffer to filter corresponds to a key-frame packet data
- * @return >= 0 in case of success, or a negative error code in case of failure
- *
- * If the return value is positive, an output buffer is allocated and
- * is available in *poutbuf, and is distinct from the input buffer.
- *
- * If the return value is 0, the output buffer is not allocated and
- * should be considered identical to the input buffer, or in case
- * *poutbuf was set it points to the input buffer (not necessarily to
- * its starting address).
- */
-int av_bitstream_filter_filter(AVBitStreamFilterContext *bsfc,
- AVCodecContext *avctx, const char *args,
- uint8_t **poutbuf, int *poutbuf_size,
- const uint8_t *buf, int buf_size, int keyframe);
-
-/**
- * Release bitstream filter context.
- *
- * @param bsf the bitstream filter context created with
- * av_bitstream_filter_init(), can be NULL
- */
-void av_bitstream_filter_close(AVBitStreamFilterContext *bsf);
-
-/**
- * If f is NULL, return the first registered bitstream filter,
- * if f is non-NULL, return the next registered bitstream filter
- * after f, or NULL if f is the last one.
- *
- * This function can be used to iterate over all registered bitstream
- * filters.
- */
-AVBitStreamFilter *av_bitstream_filter_next(const AVBitStreamFilter *f);
-
-/* memory */
-
-/**
- * Same behaviour av_fast_malloc but the buffer has additional
- * AV_INPUT_BUFFER_PADDING_SIZE at the end which will always be 0.
- *
- * In addition the whole buffer will initially and after resizes
- * be 0-initialized so that no uninitialized data will ever appear.
- */
-void av_fast_padded_malloc(void *ptr, unsigned int *size, size_t min_size);
-
-/**
- * Same behaviour av_fast_padded_malloc except that buffer will always
- * be 0-initialized after call.
- */
-void av_fast_padded_mallocz(void *ptr, unsigned int *size, size_t min_size);
-
-/**
- * Encode extradata length to a buffer. Used by xiph codecs.
- *
- * @param s buffer to write to; must be at least (v/255+1) bytes long
- * @param v size of extradata in bytes
- * @return number of bytes written to the buffer.
- */
-unsigned int av_xiphlacing(unsigned char *s, unsigned int v);
-
-#if FF_API_MISSING_SAMPLE
-/**
- * Log a generic warning message about a missing feature. This function is
- * intended to be used internally by FFmpeg (libavcodec, libavformat, etc.)
- * only, and would normally not be used by applications.
- * @param[in] avc a pointer to an arbitrary struct of which the first field is
- * a pointer to an AVClass struct
- * @param[in] feature string containing the name of the missing feature
- * @param[in] want_sample indicates if samples are wanted which exhibit this feature.
- * If want_sample is non-zero, additional verbage will be added to the log
- * message which tells the user how to report samples to the development
- * mailing list.
- * @deprecated Use avpriv_report_missing_feature() instead.
- */
-attribute_deprecated
-void av_log_missing_feature(void *avc, const char *feature, int want_sample);
-
-/**
- * Log a generic warning message asking for a sample. This function is
- * intended to be used internally by FFmpeg (libavcodec, libavformat, etc.)
- * only, and would normally not be used by applications.
- * @param[in] avc a pointer to an arbitrary struct of which the first field is
- * a pointer to an AVClass struct
- * @param[in] msg string containing an optional message, or NULL if no message
- * @deprecated Use avpriv_request_sample() instead.
- */
-attribute_deprecated
-void av_log_ask_for_sample(void *avc, const char *msg, ...) av_printf_format(2, 3);
-#endif /* FF_API_MISSING_SAMPLE */
-
-/**
- * Register the hardware accelerator hwaccel.
- */
-void av_register_hwaccel(AVHWAccel *hwaccel);
-
-/**
- * If hwaccel is NULL, returns the first registered hardware accelerator,
- * if hwaccel is non-NULL, returns the next registered hardware accelerator
- * after hwaccel, or NULL if hwaccel is the last one.
- */
-AVHWAccel *av_hwaccel_next(const AVHWAccel *hwaccel);
-
-
-/**
- * Lock operation used by lockmgr
- */
-enum AVLockOp {
- AV_LOCK_CREATE, ///< Create a mutex
- AV_LOCK_OBTAIN, ///< Lock the mutex
- AV_LOCK_RELEASE, ///< Unlock the mutex
- AV_LOCK_DESTROY, ///< Free mutex resources
-};
-
-/**
- * Register a user provided lock manager supporting the operations
- * specified by AVLockOp. The "mutex" argument to the function points
- * to a (void *) where the lockmgr should store/get a pointer to a user
- * allocated mutex. It is NULL upon AV_LOCK_CREATE and equal to the
- * value left by the last call for all other ops. If the lock manager is
- * unable to perform the op then it should leave the mutex in the same
- * state as when it was called and return a non-zero value. However,
- * when called with AV_LOCK_DESTROY the mutex will always be assumed to
- * have been successfully destroyed. If av_lockmgr_register succeeds
- * it will return a non-negative value, if it fails it will return a
- * negative value and destroy all mutex and unregister all callbacks.
- * av_lockmgr_register is not thread-safe, it must be called from a
- * single thread before any calls which make use of locking are used.
- *
- * @param cb User defined callback. av_lockmgr_register invokes calls
- * to this callback and the previously registered callback.
- * The callback will be used to create more than one mutex
- * each of which must be backed by its own underlying locking
- * mechanism (i.e. do not use a single static object to
- * implement your lock manager). If cb is set to NULL the
- * lockmgr will be unregistered.
- */
-int av_lockmgr_register(int (*cb)(void **mutex, enum AVLockOp op));
-
-/**
- * Get the type of the given codec.
- */
-enum AVMediaType avcodec_get_type(enum AVCodecID codec_id);
-
-/**
- * Get the name of a codec.
- * @return a static string identifying the codec; never NULL
- */
-const char *avcodec_get_name(enum AVCodecID id);
-
-/**
- * @return a positive value if s is open (i.e. avcodec_open2() was called on it
- * with no corresponding avcodec_close()), 0 otherwise.
- */
-int avcodec_is_open(AVCodecContext *s);
-
-/**
- * @return a non-zero number if codec is an encoder, zero otherwise
- */
-int av_codec_is_encoder(const AVCodec *codec);
-
-/**
- * @return a non-zero number if codec is a decoder, zero otherwise
- */
-int av_codec_is_decoder(const AVCodec *codec);
-
-/**
- * @return descriptor for given codec ID or NULL if no descriptor exists.
- */
-const AVCodecDescriptor *avcodec_descriptor_get(enum AVCodecID id);
-
-/**
- * Iterate over all codec descriptors known to libavcodec.
- *
- * @param prev previous descriptor. NULL to get the first descriptor.
- *
- * @return next descriptor or NULL after the last descriptor
- */
-const AVCodecDescriptor *avcodec_descriptor_next(const AVCodecDescriptor *prev);
-
-/**
- * @return codec descriptor with the given name or NULL if no such descriptor
- * exists.
- */
-const AVCodecDescriptor *avcodec_descriptor_get_by_name(const char *name);
-
-/**
- * Allocate a CPB properties structure and initialize its fields to default
- * values.
- *
- * @param size if non-NULL, the size of the allocated struct will be written
- * here. This is useful for embedding it in side data.
- *
- * @return the newly allocated struct or NULL on failure
- */
-AVCPBProperties *av_cpb_properties_alloc(size_t *size);
-
-/**
- * @}
- */
-
-#endif /* AVCODEC_AVCODEC_H */
diff --git a/app/src/main/cpp/include/libavcodec/avdct.h b/app/src/main/cpp/include/libavcodec/avdct.h
deleted file mode 100644
index 272422e4..00000000
--- a/app/src/main/cpp/include/libavcodec/avdct.h
+++ /dev/null
@@ -1,84 +0,0 @@
-/*
- * This file is part of FFmpeg.
- *
- * FFmpeg is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * FFmpeg is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with FFmpeg; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- */
-
-#ifndef AVCODEC_AVDCT_H
-#define AVCODEC_AVDCT_H
-
-#include "libavutil/opt.h"
-
-/**
- * AVDCT context.
- * @note function pointers can be NULL if the specific features have been
- * disabled at build time.
- */
-typedef struct AVDCT {
- const AVClass *av_class;
-
- void (*idct)(int16_t *block /* align 16 */);
-
- /**
- * IDCT input permutation.
- * Several optimized IDCTs need a permutated input (relative to the
- * normal order of the reference IDCT).
- * This permutation must be performed before the idct_put/add.
- * Note, normally this can be merged with the zigzag/alternate scan
- * An example to avoid confusion:
- * - (->decode coeffs -> zigzag reorder -> dequant -> reference IDCT -> ...)
- * - (x -> reference DCT -> reference IDCT -> x)
- * - (x -> reference DCT -> simple_mmx_perm = idct_permutation
- * -> simple_idct_mmx -> x)
- * - (-> decode coeffs -> zigzag reorder -> simple_mmx_perm -> dequant
- * -> simple_idct_mmx -> ...)
- */
- uint8_t idct_permutation[64];
-
- void (*fdct)(int16_t *block /* align 16 */);
-
-
- /**
- * DCT algorithm.
- * must use AVOptions to set this field.
- */
- int dct_algo;
-
- /**
- * IDCT algorithm.
- * must use AVOptions to set this field.
- */
- int idct_algo;
-
- void (*get_pixels)(int16_t *block /* align 16 */,
- const uint8_t *pixels /* align 8 */,
- ptrdiff_t line_size);
-
- int bits_per_sample;
-} AVDCT;
-
-/**
- * Allocates a AVDCT context.
- * This needs to be initialized with avcodec_dct_init() after optionally
- * configuring it with AVOptions.
- *
- * To free it use av_free()
- */
-AVDCT *avcodec_dct_alloc(void);
-int avcodec_dct_init(AVDCT *);
-
-const AVClass *avcodec_dct_get_class(void);
-
-#endif /* AVCODEC_AVDCT_H */
diff --git a/app/src/main/cpp/include/libavcodec/avfft.h b/app/src/main/cpp/include/libavcodec/avfft.h
deleted file mode 100644
index 0c0f9b8d..00000000
--- a/app/src/main/cpp/include/libavcodec/avfft.h
+++ /dev/null
@@ -1,118 +0,0 @@
-/*
- * This file is part of FFmpeg.
- *
- * FFmpeg is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * FFmpeg is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with FFmpeg; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- */
-
-#ifndef AVCODEC_AVFFT_H
-#define AVCODEC_AVFFT_H
-
-/**
- * @file
- * @ingroup lavc_fft
- * FFT functions
- */
-
-/**
- * @defgroup lavc_fft FFT functions
- * @ingroup lavc_misc
- *
- * @{
- */
-
-typedef float FFTSample;
-
-typedef struct FFTComplex {
- FFTSample re, im;
-} FFTComplex;
-
-typedef struct FFTContext FFTContext;
-
-/**
- * Set up a complex FFT.
- * @param nbits log2 of the length of the input array
- * @param inverse if 0 perform the forward transform, if 1 perform the inverse
- */
-FFTContext *av_fft_init(int nbits, int inverse);
-
-/**
- * Do the permutation needed BEFORE calling ff_fft_calc().
- */
-void av_fft_permute(FFTContext *s, FFTComplex *z);
-
-/**
- * Do a complex FFT with the parameters defined in av_fft_init(). The
- * input data must be permuted before. No 1.0/sqrt(n) normalization is done.
- */
-void av_fft_calc(FFTContext *s, FFTComplex *z);
-
-void av_fft_end(FFTContext *s);
-
-FFTContext *av_mdct_init(int nbits, int inverse, double scale);
-void av_imdct_calc(FFTContext *s, FFTSample *output, const FFTSample *input);
-void av_imdct_half(FFTContext *s, FFTSample *output, const FFTSample *input);
-void av_mdct_calc(FFTContext *s, FFTSample *output, const FFTSample *input);
-void av_mdct_end(FFTContext *s);
-
-/* Real Discrete Fourier Transform */
-
-enum RDFTransformType {
- DFT_R2C,
- IDFT_C2R,
- IDFT_R2C,
- DFT_C2R,
-};
-
-typedef struct RDFTContext RDFTContext;
-
-/**
- * Set up a real FFT.
- * @param nbits log2 of the length of the input array
- * @param trans the type of transform
- */
-RDFTContext *av_rdft_init(int nbits, enum RDFTransformType trans);
-void av_rdft_calc(RDFTContext *s, FFTSample *data);
-void av_rdft_end(RDFTContext *s);
-
-/* Discrete Cosine Transform */
-
-typedef struct DCTContext DCTContext;
-
-enum DCTTransformType {
- DCT_II = 0,
- DCT_III,
- DCT_I,
- DST_I,
-};
-
-/**
- * Set up DCT.
- *
- * @param nbits size of the input array:
- * (1 << nbits) for DCT-II, DCT-III and DST-I
- * (1 << nbits) + 1 for DCT-I
- * @param type the type of transform
- *
- * @note the first element of the input of DST-I is ignored
- */
-DCTContext *av_dct_init(int nbits, enum DCTTransformType type);
-void av_dct_calc(DCTContext *s, FFTSample *data);
-void av_dct_end (DCTContext *s);
-
-/**
- * @}
- */
-
-#endif /* AVCODEC_AVFFT_H */
diff --git a/app/src/main/cpp/include/libavcodec/d3d11va.h b/app/src/main/cpp/include/libavcodec/d3d11va.h
deleted file mode 100644
index 6816b6c1..00000000
--- a/app/src/main/cpp/include/libavcodec/d3d11va.h
+++ /dev/null
@@ -1,112 +0,0 @@
-/*
- * Direct3D11 HW acceleration
- *
- * copyright (c) 2009 Laurent Aimar
- * copyright (c) 2015 Steve Lhomme
- *
- * This file is part of FFmpeg.
- *
- * FFmpeg is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * FFmpeg is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with FFmpeg; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- */
-
-#ifndef AVCODEC_D3D11VA_H
-#define AVCODEC_D3D11VA_H
-
-/**
- * @file
- * @ingroup lavc_codec_hwaccel_d3d11va
- * Public libavcodec D3D11VA header.
- */
-
-#if !defined(_WIN32_WINNT) || _WIN32_WINNT < 0x0602
-#undef _WIN32_WINNT
-#define _WIN32_WINNT 0x0602
-#endif
-
-#include
-#include
-
-/**
- * @defgroup lavc_codec_hwaccel_d3d11va Direct3D11
- * @ingroup lavc_codec_hwaccel
- *
- * @{
- */
-
-#define FF_DXVA2_WORKAROUND_SCALING_LIST_ZIGZAG 1 ///< Work around for Direct3D11 and old UVD/UVD+ ATI video cards
-#define FF_DXVA2_WORKAROUND_INTEL_CLEARVIDEO 2 ///< Work around for Direct3D11 and old Intel GPUs with ClearVideo interface
-
-/**
- * This structure is used to provides the necessary configurations and data
- * to the Direct3D11 FFmpeg HWAccel implementation.
- *
- * The application must make it available as AVCodecContext.hwaccel_context.
- *
- * Use av_d3d11va_alloc_context() exclusively to allocate an AVD3D11VAContext.
- */
-typedef struct AVD3D11VAContext {
- /**
- * D3D11 decoder object
- */
- ID3D11VideoDecoder *decoder;
-
- /**
- * D3D11 VideoContext
- */
- ID3D11VideoContext *video_context;
-
- /**
- * D3D11 configuration used to create the decoder
- */
- D3D11_VIDEO_DECODER_CONFIG *cfg;
-
- /**
- * The number of surface in the surface array
- */
- unsigned surface_count;
-
- /**
- * The array of Direct3D surfaces used to create the decoder
- */
- ID3D11VideoDecoderOutputView **surface;
-
- /**
- * A bit field configuring the workarounds needed for using the decoder
- */
- uint64_t workaround;
-
- /**
- * Private to the FFmpeg AVHWAccel implementation
- */
- unsigned report_id;
-
- /**
- * Mutex to access video_context
- */
- HANDLE context_mutex;
-} AVD3D11VAContext;
-
-/**
- * Allocate an AVD3D11VAContext.
- *
- * @return Newly-allocated AVD3D11VAContext or NULL on failure.
- */
-AVD3D11VAContext *av_d3d11va_alloc_context(void);
-
-/**
- * @}
- */
-
-#endif /* AVCODEC_D3D11VA_H */
diff --git a/app/src/main/cpp/include/libavcodec/dirac.h b/app/src/main/cpp/include/libavcodec/dirac.h
deleted file mode 100644
index e6d9d346..00000000
--- a/app/src/main/cpp/include/libavcodec/dirac.h
+++ /dev/null
@@ -1,131 +0,0 @@
-/*
- * Copyright (C) 2007 Marco Gerards
- * Copyright (C) 2009 David Conrad
- * Copyright (C) 2011 Jordi Ortiz
- *
- * This file is part of FFmpeg.
- *
- * FFmpeg is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * FFmpeg is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with FFmpeg; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- */
-
-#ifndef AVCODEC_DIRAC_H
-#define AVCODEC_DIRAC_H
-
-/**
- * @file
- * Interface to Dirac Decoder/Encoder
- * @author Marco Gerards
- * @author David Conrad
- * @author Jordi Ortiz
- */
-
-#include "avcodec.h"
-
-/**
- * The spec limits the number of wavelet decompositions to 4 for both
- * level 1 (VC-2) and 128 (long-gop default).
- * 5 decompositions is the maximum before >16-bit buffers are needed.
- * Schroedinger allows this for DD 9,7 and 13,7 wavelets only, limiting
- * the others to 4 decompositions (or 3 for the fidelity filter).
- *
- * We use this instead of MAX_DECOMPOSITIONS to save some memory.
- */
-#define MAX_DWT_LEVELS 5
-
-/**
- * Parse code values:
- *
- * Dirac Specification ->
- * 9.6.1 Table 9.1
- *
- * VC-2 Specification ->
- * 10.4.1 Table 10.1
- */
-
-enum DiracParseCodes {
- DIRAC_PCODE_SEQ_HEADER = 0x00,
- DIRAC_PCODE_END_SEQ = 0x10,
- DIRAC_PCODE_AUX = 0x20,
- DIRAC_PCODE_PAD = 0x30,
- DIRAC_PCODE_PICTURE_CODED = 0x08,
- DIRAC_PCODE_PICTURE_RAW = 0x48,
- DIRAC_PCODE_PICTURE_LOW_DEL = 0xC8,
- DIRAC_PCODE_PICTURE_HQ = 0xE8,
- DIRAC_PCODE_INTER_NOREF_CO1 = 0x0A,
- DIRAC_PCODE_INTER_NOREF_CO2 = 0x09,
- DIRAC_PCODE_INTER_REF_CO1 = 0x0D,
- DIRAC_PCODE_INTER_REF_CO2 = 0x0E,
- DIRAC_PCODE_INTRA_REF_CO = 0x0C,
- DIRAC_PCODE_INTRA_REF_RAW = 0x4C,
- DIRAC_PCODE_INTRA_REF_PICT = 0xCC,
- DIRAC_PCODE_MAGIC = 0x42424344,
-};
-
-typedef struct DiracVersionInfo {
- int major;
- int minor;
-} DiracVersionInfo;
-
-typedef struct AVDiracSeqHeader {
- unsigned width;
- unsigned height;
- uint8_t chroma_format; ///< 0: 444 1: 422 2: 420
-
- uint8_t interlaced;
- uint8_t top_field_first;
-
- uint8_t frame_rate_index; ///< index into dirac_frame_rate[]
- uint8_t aspect_ratio_index; ///< index into dirac_aspect_ratio[]
-
- uint16_t clean_width;
- uint16_t clean_height;
- uint16_t clean_left_offset;
- uint16_t clean_right_offset;
-
- uint8_t pixel_range_index; ///< index into dirac_pixel_range_presets[]
- uint8_t color_spec_index; ///< index into dirac_color_spec_presets[]
-
- int profile;
- int level;
-
- AVRational framerate;
- AVRational sample_aspect_ratio;
-
- enum AVPixelFormat pix_fmt;
- enum AVColorRange color_range;
- enum AVColorPrimaries color_primaries;
- enum AVColorTransferCharacteristic color_trc;
- enum AVColorSpace colorspace;
-
- DiracVersionInfo version;
- int bit_depth;
-} AVDiracSeqHeader;
-
-/**
- * Parse a Dirac sequence header.
- *
- * @param dsh this function will allocate and fill an AVDiracSeqHeader struct
- * and write it into this pointer. The caller must free it with
- * av_free().
- * @param buf the data buffer
- * @param buf_size the size of the data buffer in bytes
- * @param log_ctx if non-NULL, this function will log errors here
- * @return 0 on success, a negative AVERROR code on failure
- */
-int av_dirac_parse_sequence_header(AVDiracSeqHeader **dsh,
- const uint8_t *buf, size_t buf_size,
- void *log_ctx);
-
-#endif /* AVCODEC_DIRAC_H */
diff --git a/app/src/main/cpp/include/libavcodec/dv_profile.h b/app/src/main/cpp/include/libavcodec/dv_profile.h
deleted file mode 100644
index 9380a66f..00000000
--- a/app/src/main/cpp/include/libavcodec/dv_profile.h
+++ /dev/null
@@ -1,83 +0,0 @@
-/*
- * This file is part of FFmpeg.
- *
- * FFmpeg is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * FFmpeg is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with FFmpeg; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- */
-
-#ifndef AVCODEC_DV_PROFILE_H
-#define AVCODEC_DV_PROFILE_H
-
-#include
-
-#include "libavutil/pixfmt.h"
-#include "libavutil/rational.h"
-#include "avcodec.h"
-
-/* minimum number of bytes to read from a DV stream in order to
- * determine the profile */
-#define DV_PROFILE_BYTES (6 * 80) /* 6 DIF blocks */
-
-
-/*
- * AVDVProfile is used to express the differences between various
- * DV flavors. For now it's primarily used for differentiating
- * 525/60 and 625/50, but the plans are to use it for various
- * DV specs as well (e.g. SMPTE314M vs. IEC 61834).
- */
-typedef struct AVDVProfile {
- int dsf; /* value of the dsf in the DV header */
- int video_stype; /* stype for VAUX source pack */
- int frame_size; /* total size of one frame in bytes */
- int difseg_size; /* number of DIF segments per DIF channel */
- int n_difchan; /* number of DIF channels per frame */
- AVRational time_base; /* 1/framerate */
- int ltc_divisor; /* FPS from the LTS standpoint */
- int height; /* picture height in pixels */
- int width; /* picture width in pixels */
- AVRational sar[2]; /* sample aspect ratios for 4:3 and 16:9 */
- enum AVPixelFormat pix_fmt; /* picture pixel format */
- int bpm; /* blocks per macroblock */
- const uint8_t *block_sizes; /* AC block sizes, in bits */
- int audio_stride; /* size of audio_shuffle table */
- int audio_min_samples[3]; /* min amount of audio samples */
- /* for 48kHz, 44.1kHz and 32kHz */
- int audio_samples_dist[5]; /* how many samples are supposed to be */
- /* in each frame in a 5 frames window */
- const uint8_t (*audio_shuffle)[9]; /* PCM shuffling table */
-} AVDVProfile;
-
-/**
- * Get a DV profile for the provided compressed frame.
- *
- * @param sys the profile used for the previous frame, may be NULL
- * @param frame the compressed data buffer
- * @param buf_size size of the buffer in bytes
- * @return the DV profile for the supplied data or NULL on failure
- */
-const AVDVProfile *av_dv_frame_profile(const AVDVProfile *sys,
- const uint8_t *frame, unsigned buf_size);
-
-/**
- * Get a DV profile for the provided stream parameters.
- */
-const AVDVProfile *av_dv_codec_profile(int width, int height, enum AVPixelFormat pix_fmt);
-
-/**
- * Get a DV profile for the provided stream parameters.
- * The frame rate is used as a best-effort parameter.
- */
-const AVDVProfile *av_dv_codec_profile2(int width, int height, enum AVPixelFormat pix_fmt, AVRational frame_rate);
-
-#endif /* AVCODEC_DV_PROFILE_H */
diff --git a/app/src/main/cpp/include/libavcodec/dxva2.h b/app/src/main/cpp/include/libavcodec/dxva2.h
deleted file mode 100644
index 22c93992..00000000
--- a/app/src/main/cpp/include/libavcodec/dxva2.h
+++ /dev/null
@@ -1,93 +0,0 @@
-/*
- * DXVA2 HW acceleration
- *
- * copyright (c) 2009 Laurent Aimar
- *
- * This file is part of FFmpeg.
- *
- * FFmpeg is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * FFmpeg is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with FFmpeg; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- */
-
-#ifndef AVCODEC_DXVA2_H
-#define AVCODEC_DXVA2_H
-
-/**
- * @file
- * @ingroup lavc_codec_hwaccel_dxva2
- * Public libavcodec DXVA2 header.
- */
-
-#if !defined(_WIN32_WINNT) || _WIN32_WINNT < 0x0602
-#undef _WIN32_WINNT
-#define _WIN32_WINNT 0x0602
-#endif
-
-#include
-#include