/*
* Copyright (C) 2011 The Android Open Source Project
*
* 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.
*/
#ifndef NATIVE_WINDOW_RENDERER_H_
#define NATIVE_WINDOW_RENDERER_H_
#include <EGL/egl.h>
#include <GLES2/gl2.h>
#include <media/stagefright/MediaBuffer.h>
#include <media/stagefright/MetaData.h>
#include <utils/RefBase.h>
#include <utils/threads.h>
#include "M4xVSS_API.h"
// The NativeWindowRenderer draws video frames stored in MediaBuffers to
// an ANativeWindow. It can apply "rendering mode" and color effects to
// the frames. "Rendering mode" is the option to do resizing, cropping,
// or black-bordering when the source and destination aspect ratio are
// different. Color effects include sepia, negative, and gradient.
//
// The input to NativeWindowRenderer is provided by the RenderInput class,
// and there can be multiple active RenderInput at the same time. Although
// we only expect that happens briefly when one clip is about to finish
// and the next clip is about to start.
//
// We allocate a SurfaceTexture for each RenderInput and the user can use
// the getTargetWindow() function to get the corresponding ANativeWindow
// for that SurfaceTexture. The intention is that the user can pass that
// ANativeWindow to OMXCodec::Create() so the codec can decode directly
// to buffers provided by the texture.
namespace android {
class SurfaceTexture;
class SurfaceTextureClient;
class RenderInput;
class NativeWindowRenderer {
public:
NativeWindowRenderer(sp<ANativeWindow> nativeWindow, int width, int height);
~NativeWindowRenderer();
RenderInput* createRenderInput();
void destroyRenderInput(RenderInput* input);
private:
// No copy constructor and assignment
NativeWindowRenderer(const NativeWindowRenderer &);
NativeWindowRenderer &operator=(const NativeWindowRenderer &);
// Initialization and finialization
void initializeEGL();
void terminateEGL();
void createPrograms();
void createProgram(
GLuint vertexShader, GLuint fragmentShader, GLuint* outPgm);
void loadShader(
GLenum shaderType, const char* pSource, GLuint* outShader);
// These functions are executed every frame.
void render(RenderInput* input);
void queueInternalBuffer(ANativeWindow* anw, MediaBuffer* buffer);
void queueExternalBuffer(ANativeWindow* anw, MediaBuffer* buffer,
int width, int height);
void copyI420Buffer(MediaBuffer* src, uint8_t* dst,
int srcWidth, int srcHeight, int stride);
void updateProgramAndHandle(uint32_t videoEffect);
void calculatePositionCoordinates(M4xVSS_MediaRendering renderingMode,
int srcWidth, int srcHeight);
// These variables are initialized once and doesn't change afterwards.
sp<ANativeWindow> mNativeWindow;
int mDstWidth, mDstHeight;
EGLDisplay mEglDisplay;
EGLSurface mEglSurface;
EGLContext mEglContext;
enum {
EFFECT_NORMAL,
EFFECT_SEPIA,
EFFECT_NEGATIVE,
EFFECT_GRADIENT,
NUMBER_OF_EFFECTS
};
GLuint mProgram[NUMBER_OF_EFFECTS];
// We use one shader program for each effect. mLastVideoEffect remembers
// the program used for the last frame. when the effect used changes,
// we change the program used and update the handles.
uint32_t mLastVideoEffect;
GLint mPositionHandle;
GLint mTexPosHandle;
GLint mTexMatrixHandle;
// This is the vertex coordinates used for the frame texture.
// It's calculated according the the rendering mode and the source and
// destination aspect ratio.
GLfloat mPositionCoordinates[8];
// We use a different GL id for each SurfaceTexture.
GLuint mNextTextureId;
// Number of existing RenderInputs, just for debugging.
int mActiveInputs;
// The GL thread functions
static int threadStart(void* self);
void glThread();
// These variables are used to communicate between the GL thread and
// other threads.
Mutex mLock;
Condition mCond;
enum {
CMD_IDLE,
CMD_RENDER_INPUT,
CMD_RESERVE_TEXTURE,
CMD_DELETE_TEXTURE,
CMD_QUIT,
};
int mThreadCmd;
RenderInput* mThreadRenderInput;
GLuint mThreadTextureId;
// These functions are used to send commands to the GL thread.
// sendRequest() also waits for the GL thread acknowledges the
// command is finished.
void startRequest(int cmd);
void sendRequest();
friend class RenderInput;
};
class RenderInput {
public:
// Returns the ANativeWindow corresponds to the SurfaceTexture.
ANativeWindow* getTargetWindow();
// Updates video frame size from the MediaSource's metadata. Specifically
// we look for kKeyWidth, kKeyHeight, and (optionally) kKeyCropRect.
void updateVideoSize(sp<MetaData> meta);
// Renders the buffer with the given video effect and rending mode.
// The video effets are defined in VideoEditorTools.h
// Set isExternalBuffer to true only when the buffer given is not
// provided by the SurfaceTexture.
void render(MediaBuffer *buffer, uint32_t videoEffect,
M4xVSS_MediaRendering renderingMode, bool isExternalBuffer);
private:
RenderInput(NativeWindowRenderer* renderer, GLuint textureId);
~RenderInput();
NativeWindowRenderer* mRenderer;
GLuint mTextureId;
sp<SurfaceTexture> mST;
sp<SurfaceTextureClient> mSTC;
int mWidth, mHeight;
// These are only valid during render() calls
uint32_t mVideoEffect;
M4xVSS_MediaRendering mRenderingMode;
bool mIsExternalBuffer;
MediaBuffer* mBuffer;
friend class NativeWindowRenderer;
};
} // namespace android
#endif // NATIVE_WINDOW_RENDERER_H_