提交 6e15cdb2 编写于 作者: Z Zhang Rui

android/gles2: implement gles2 render

上级 2a00f5d7
......@@ -50,18 +50,21 @@
<item>RGB 565</item>
<item>RGB 888X</item>
<item>YV12</item>
<item>OpenGL ES2</item>
</string-array>
<string-array name="pref_entry_values_pixel_format">
<item></item>
<item>fcc-rv16</item>
<item>fcc-rv32</item>
<item>fcc-yv12</item>
<item>fcc-_es2</item>
</string-array>
<string-array name="pref_entry_summaries_pixel_format">
<item>Auto Select</item>
<item>RGB 565</item>
<item>RGB 888X</item>
<item>YV12</item>
<item>OpenGL ES2</item>
</string-array>
<!-- -->
......
......@@ -249,7 +249,7 @@ static int amc_fill_frame(
frame->width = opaque->frame_width;
frame->height = opaque->frame_height;
frame->format = SDL_FCC__AMC;
frame->format = IJK_AV_PIX_FMT__ANDROID_MEDIACODEC;
frame->sample_aspect_ratio = opaque->avctx->sample_aspect_ratio;
frame->pts = av_rescale_q(buffer_info->presentationTimeUs, AV_TIME_BASE_Q, is->video_st->time_base);
if (frame->pts < 0)
......
......@@ -1157,7 +1157,7 @@ display:
/* allocate a picture (needs to do that in main thread to avoid
potential locking problems */
static void alloc_picture(FFPlayer *ffp, Uint32 overlay_format)
static void alloc_picture(FFPlayer *ffp, int frame_format)
{
VideoState *is = ffp->is;
Frame *vp;
......@@ -1173,8 +1173,9 @@ static void alloc_picture(FFPlayer *ffp, Uint32 overlay_format)
video_open(ffp, 0, vp);
#endif
SDL_VoutSetOverlayFormat(ffp->vout, ffp->overlay_format);
vp->bmp = SDL_Vout_CreateOverlay(vp->width, vp->height,
overlay_format,
frame_format,
ffp->vout);
#ifdef FFP_MERGE
bufferdiff = vp->bmp ? FFMAX(vp->bmp->pixels[0], vp->bmp->pixels[1]) - FFMIN(vp->bmp->pixels[0], vp->bmp->pixels[1]) : 0;
......@@ -1246,15 +1247,7 @@ static int queue_picture(FFPlayer *ffp, AVFrame *src_frame, double pts, double d
/* the allocation must be done in the main thread to avoid
locking problems. */
switch (src_frame->format) {
case SDL_FCC__AMC:
case SDL_FCC__VTB:
alloc_picture(ffp, src_frame->format);
break;
default:
alloc_picture(ffp, ffp->overlay_format);
break;
}
alloc_picture(ffp, src_frame->format);
if (is->videoq.abort_request)
return -1;
......@@ -3301,6 +3294,7 @@ void ffp_set_option_int(FFPlayer *ffp, int opt_category, const char *name, int64
void ffp_set_overlay_format(FFPlayer *ffp, int chroma_fourcc)
{
switch (chroma_fourcc) {
case SDL_FCC__GLES2:
case SDL_FCC_I420:
case SDL_FCC_YV12:
case SDL_FCC_RV16:
......@@ -3653,11 +3647,6 @@ void ffp_frame_queue_push(FrameQueue *f)
return frame_queue_push(f);
}
void ffp_alloc_picture(FFPlayer *ffp, Uint32 overlay_format)
{
return alloc_picture(ffp, overlay_format);
}
int ffp_queue_picture(FFPlayer *ffp, AVFrame *src_frame, double pts, double duration, int64_t pos, int serial)
{
return queue_picture(ffp, src_frame, pts, duration, pos, serial);
......
......@@ -82,7 +82,6 @@ bool ffp_is_flush_packet(AVPacket *pkt);
Frame *ffp_frame_queue_peek_writable(FrameQueue *f);
void ffp_frame_queue_push(FrameQueue *f);
void ffp_alloc_picture(FFPlayer *ffp, Uint32 overlay_format);
int ffp_queue_picture(FFPlayer *ffp, AVFrame *src_frame, double pts, double duration, int64_t pos, int serial);
int ffp_get_master_sync_type(VideoState *is);
......
......@@ -85,10 +85,8 @@ static const AVOption ffp_context_options[] = {
{ "overlay-format", "fourcc of overlay format",
OPTION_OFFSET(overlay_format), OPTION_INT(SDL_FCC_RV32, INT_MIN, INT_MAX),
.unit = "overlay-format" },
{ "fcc-_es2", "", 0, OPTION_CONST(SDL_FCC__GLES2), .unit = "overlay-format" },
{ "fcc-i420", "", 0, OPTION_CONST(SDL_FCC_I420), .unit = "overlay-format" },
#ifdef __APPLE__
{ "fcc-i4al", "", 0, OPTION_CONST(SDL_FCC_I444P10LE), .unit = "overlay-format" },
#endif
{ "fcc-yv12", "", 0, OPTION_CONST(SDL_FCC_YV12), .unit = "overlay-format" },
{ "fcc-rv16", "", 0, OPTION_CONST(SDL_FCC_RV16), .unit = "overlay-format" },
{ "fcc-rv24", "", 0, OPTION_CONST(SDL_FCC_RV24), .unit = "overlay-format" },
......
......@@ -20,7 +20,7 @@ LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_CFLAGS += -std=c99
LOCAL_LDLIBS += -llog -landroid -lOpenSLES
LOCAL_LDLIBS += -llog -landroid -lOpenSLES -lEGL -lGLESv2
LOCAL_C_INCLUDES += $(LOCAL_PATH)
LOCAL_C_INCLUDES += $(realpath $(LOCAL_PATH)/..)
......@@ -30,12 +30,22 @@ LOCAL_C_INCLUDES += $(realpath $(LOCAL_PATH)/../ijkj4a)
LOCAL_SRC_FILES += ijksdl_aout.c
LOCAL_SRC_FILES += ijksdl_audio.c
LOCAL_SRC_FILES += ijksdl_egl.c
LOCAL_SRC_FILES += ijksdl_error.c
LOCAL_SRC_FILES += ijksdl_mutex.c
LOCAL_SRC_FILES += ijksdl_stdinc.c
LOCAL_SRC_FILES += ijksdl_thread.c
LOCAL_SRC_FILES += ijksdl_timer.c
LOCAL_SRC_FILES += ijksdl_vout.c
LOCAL_SRC_FILES += gles2/color.c
LOCAL_SRC_FILES += gles2/common.c
LOCAL_SRC_FILES += gles2/renderer.c
LOCAL_SRC_FILES += gles2/renderer_yuv420p.c
LOCAL_SRC_FILES += gles2/renderer_yuv444p10le.c
LOCAL_SRC_FILES += gles2/shader.c
LOCAL_SRC_FILES += gles2/fsh/yuv420p.fsh.c
LOCAL_SRC_FILES += gles2/fsh/yuv444p10le.fsh.c
LOCAL_SRC_FILES += gles2/vsh/mvp.vsh.c
LOCAL_SRC_FILES += dummy/ijksdl_vout_dummy.c
......
......@@ -28,6 +28,7 @@
#include "ijksdl/ijksdl_vout.h"
#include "ijksdl/ijksdl_vout_internal.h"
#include "ijksdl/ijksdl_container.h"
#include "ijksdl/ijksdl_egl.h"
#include "ijksdl/ffmpeg/ijksdl_vout_overlay_ffmpeg.h"
#include "ijksdl_codec_android_mediacodec.h"
#include "ijksdl_inc_internal_android.h"
......@@ -87,22 +88,24 @@ typedef struct SDL_Vout_Opaque {
ISDL_Array overlay_manager;
ISDL_Array overlay_pool;
IJK_EGL *egl;
} SDL_Vout_Opaque;
static SDL_VoutOverlay *func_create_overlay_l(int width, int height, Uint32 format, SDL_Vout *vout)
static SDL_VoutOverlay *func_create_overlay_l(int width, int height, int frame_format, SDL_Vout *vout)
{
switch (format) {
case SDL_FCC__AMC:
return SDL_VoutAMediaCodec_CreateOverlay(width, height, format, vout);
switch (frame_format) {
case IJK_AV_PIX_FMT__ANDROID_MEDIACODEC:
return SDL_VoutAMediaCodec_CreateOverlay(width, height, vout);
default:
return SDL_VoutFFmpeg_CreateOverlay(width, height, format, vout);
return SDL_VoutFFmpeg_CreateOverlay(width, height, frame_format, vout);
}
}
static SDL_VoutOverlay *func_create_overlay(int width, int height, Uint32 format, SDL_Vout *vout)
static SDL_VoutOverlay *func_create_overlay(int width, int height, int frame_format, SDL_Vout *vout)
{
SDL_LockMutex(vout->mutex);
SDL_VoutOverlay *overlay = func_create_overlay_l(width, height, format, vout);
SDL_VoutOverlay *overlay = func_create_overlay_l(width, height, frame_format, vout);
SDL_UnlockMutex(vout->mutex);
return overlay;
}
......@@ -127,6 +130,8 @@ static void func_free_l(SDL_Vout *vout)
opaque->native_window = NULL;
}
IJK_EGL_freep(&opaque->egl);
SDL_AMediaCodec_decreaseReferenceP(&opaque->acodec);
}
......@@ -159,11 +164,20 @@ static int func_display_overlay_l(SDL_Vout *vout, SDL_VoutOverlay *overlay)
}
switch(overlay->format) {
case SDL_FCC__AMC:
case SDL_FCC__AMC: {
IJK_EGL_terminate(opaque->egl);
return SDL_VoutOverlayAMediaCodec_releaseFrame_l(overlay, NULL, true);
default:
return SDL_Android_NativeWindow_display_l(native_window, overlay);
}
case SDL_FCC_YV12:
case SDL_FCC_I420:
case SDL_FCC_I444P10LE:
if (vout->overlay_format == SDL_FCC__GLES2 && opaque->egl)
return IJK_EGL_display(opaque->egl, native_window, overlay);
break;
}
IJK_EGL_terminate(opaque->egl);
return SDL_Android_NativeWindow_display_l(native_window, overlay);
}
static int func_display_overlay(SDL_Vout *vout, SDL_VoutOverlay *overlay)
......@@ -191,6 +205,10 @@ SDL_Vout *SDL_VoutAndroid_CreateForANativeWindow()
if (ISDL_Array__init(&opaque->overlay_pool, 32))
goto fail;
opaque->egl = IJK_EGL_create();
if (!opaque->egl)
goto fail;
vout->opaque_class = &g_nativewindow_class;
vout->create_overlay = func_create_overlay;
vout->free_l = func_free_l;
......@@ -232,8 +250,9 @@ static void SDL_VoutAndroid_SetNativeWindow_l(SDL_Vout *vout, ANativeWindow *nat
SDL_VoutAndroid_invalidateAllBuffers_l(vout);
}
return;
}
} else
IJK_EGL_terminate(opaque->egl);
SDL_VoutAndroid_invalidateAllBuffers_l(vout);
if (opaque->native_window)
......
......@@ -105,7 +105,7 @@ inline static bool check_object(SDL_VoutOverlay* object, const char *func_name)
static int func_fill_frame(SDL_VoutOverlay *overlay, const AVFrame *frame)
{
assert(frame->format == SDL_FCC__AMC);
assert(frame->format == IJK_AV_PIX_FMT__ANDROID_MEDIACODEC);
SDL_VoutOverlay_Opaque *opaque = overlay->opaque;
......@@ -133,10 +133,10 @@ static int func_fill_frame(SDL_VoutOverlay *overlay, const AVFrame *frame)
return 0;
}
SDL_VoutOverlay *SDL_VoutAMediaCodec_CreateOverlay(int width, int height, Uint32 format, SDL_Vout *vout)
SDL_VoutOverlay *SDL_VoutAMediaCodec_CreateOverlay(int width, int height, SDL_Vout *vout)
{
SDLTRACE("SDL_VoutAMediaCodec_CreateOverlay(w=%d, h=%d, fmt=%.4s(0x%x, vout=%p)\n",
width, height, (const char*) &format, format, vout);
SDLTRACE("SDL_VoutAMediaCodec_CreateOverlay(w=%d, h=%d, fmt=_AMC vout=%p)\n",
width, height, vout);
SDL_VoutOverlay *overlay = SDL_VoutOverlay_CreateInternal(sizeof(SDL_VoutOverlay_Opaque));
if (!overlay) {
ALOGE("overlay allocation failed");
......@@ -150,7 +150,7 @@ SDL_VoutOverlay *SDL_VoutAMediaCodec_CreateOverlay(int width, int height, Uint32
opaque->buffer_proxy = NULL;
overlay->opaque_class = &g_vout_overlay_amediacodec_class;
overlay->format = format;
overlay->format = SDL_FCC__AMC;
overlay->pitches = opaque->pitches;
overlay->pixels = opaque->pixels;
overlay->w = width;
......@@ -163,12 +163,8 @@ SDL_VoutOverlay *SDL_VoutAMediaCodec_CreateOverlay(int width, int height, Uint32
overlay->unref = overlay_unref;
overlay->func_fill_frame = func_fill_frame;
switch (format) {
case SDL_FCC__AMC: {
break;
}
default:
ALOGE("SDL_VoutAMediaCodec_CreateOverlay(...): unknown format %.4s(0x%x)\n", (char*)&format, format);
if (!opaque->mutex) {
ALOGE("SDL_CreateMutex failed");
goto fail;
}
......
......@@ -30,7 +30,7 @@
typedef struct SDL_AMediaCodec SDL_AMediaCodec;
typedef struct SDL_AMediaCodecBufferInfo SDL_AMediaCodecBufferInfo;
SDL_VoutOverlay *SDL_VoutAMediaCodec_CreateOverlay(int width, int height, Uint32 format, SDL_Vout *vout);
SDL_VoutOverlay *SDL_VoutAMediaCodec_CreateOverlay(int width, int height, SDL_Vout *vout);
bool SDL_VoutOverlayAMediaCodec_isKindOf(SDL_VoutOverlay *overlay);
int SDL_VoutOverlayAMediaCodec_releaseFrame_l(SDL_VoutOverlay *overlay, SDL_AMediaCodec *acodec, bool render);
......
......@@ -182,7 +182,6 @@ static int func_fill_frame(SDL_VoutOverlay *overlay, const AVFrame *frame)
dst_format = AV_PIX_FMT_YUV420P;
}
break;
#ifdef __APPLE__
case SDL_FCC_I444P10LE:
if (frame->format == AV_PIX_FMT_YUV444P10LE) {
// ALOGE("direct draw frame");
......@@ -193,7 +192,6 @@ static int func_fill_frame(SDL_VoutOverlay *overlay, const AVFrame *frame)
dst_format = AV_PIX_FMT_YUV444P10LE;
}
break;
#endif
case SDL_FCC_RV32:
dst_format = AV_PIX_FMT_0BGR32;
break;
......@@ -283,10 +281,32 @@ static SDL_Class g_vout_overlay_ffmpeg_class = {
};
#ifndef __clang_analyzer__
SDL_VoutOverlay *SDL_VoutFFmpeg_CreateOverlay(int width, int height, Uint32 format, SDL_Vout *display)
SDL_VoutOverlay *SDL_VoutFFmpeg_CreateOverlay(int width, int height, int frame_format, SDL_Vout *display)
{
Uint32 overlay_format = display->overlay_format;
switch (overlay_format) {
case SDL_FCC__GLES2: {
switch (frame_format) {
case AV_PIX_FMT_YUV444P10LE:
overlay_format = SDL_FCC_I444P10LE;
break;
case AV_PIX_FMT_YUV420P:
case AV_PIX_FMT_YUVJ420P:
default:
#if defined(__ANDROID__)
overlay_format = SDL_FCC_YV12;
#else
overlay_format = SDL_FCC_I420;
#endif
break;
}
break;
}
}
SDLTRACE("SDL_VoutFFmpeg_CreateOverlay(w=%d, h=%d, fmt=%.4s(0x%x, dp=%p)\n",
width, height, (const char*) &format, format, display);
width, height, (const char*) &overlay_format, overlay_format, display);
SDL_VoutOverlay *overlay = SDL_VoutOverlay_CreateInternal(sizeof(SDL_VoutOverlay_Opaque));
if (!overlay) {
ALOGE("overlay allocation failed");
......@@ -298,7 +318,7 @@ SDL_VoutOverlay *SDL_VoutFFmpeg_CreateOverlay(int width, int height, Uint32 form
opaque->sws_flags = SWS_BILINEAR;
overlay->opaque_class = &g_vout_overlay_ffmpeg_class;
overlay->format = format;
overlay->format = overlay_format;
overlay->pitches = opaque->pitches;
overlay->pixels = opaque->pixels;
overlay->w = width;
......@@ -311,7 +331,7 @@ SDL_VoutOverlay *SDL_VoutFFmpeg_CreateOverlay(int width, int height, Uint32 form
enum AVPixelFormat ff_format = AV_PIX_FMT_NONE;
int buf_width = width;
int buf_height = height;
switch (format) {
switch (overlay_format) {
case SDL_FCC_I420:
case SDL_FCC_YV12: {
ff_format = AV_PIX_FMT_YUV420P;
......@@ -330,28 +350,23 @@ SDL_VoutOverlay *SDL_VoutFFmpeg_CreateOverlay(int width, int height, Uint32 form
opaque->planes = 3;
break;
}
#ifdef __APPLE__
case SDL_FCC_I444P10LE: {
if (format == SDL_FCC_I444P10LE)
ff_format = AV_PIX_FMT_YUV444P10LE;
else
ff_format = AV_PIX_FMT_YUV420P;
// FIXME: need runtime config
ff_format = AV_PIX_FMT_YUV444P10LE;
// FIXME: need runtime config
#if defined(__ANDROID__)
// 16 bytes align pitch for arm-neon image-convert
buf_width = IJKALIGN(width, 16); // 1 bytes per pixel for Y-plane
// 16 bytes align pitch for arm-neon image-convert
buf_width = IJKALIGN(width, 16); // 1 bytes per pixel for Y-plane
#elif defined(__APPLE__)
// 2^n align for width
buf_width = width;
if (width > 0)
buf_width = 1 << (sizeof(int) * 8 - __builtin_clz(width));
// 2^n align for width
buf_width = width;
if (width > 0)
buf_width = 1 << (sizeof(int) * 8 - __builtin_clz(width));
#else
buf_width = IJKALIGN(width, 16); // unknown platform
#endif
opaque->planes = 3;
break;
}
buf_width = IJKALIGN(width, 16); // unknown platform
#endif
opaque->planes = 3;
break;
}
case SDL_FCC_RV16: {
ff_format = AV_PIX_FMT_RGB565;
buf_width = IJKALIGN(width, 8); // 2 bytes per pixel
......@@ -378,7 +393,7 @@ SDL_VoutOverlay *SDL_VoutFFmpeg_CreateOverlay(int width, int height, Uint32 form
break;
}
default:
ALOGE("SDL_VoutFFmpeg_CreateOverlay(...): unknown format %.4s(0x%x)\n", (char*)&format, format);
ALOGE("SDL_VoutFFmpeg_CreateOverlay(...): unknown format %.4s(0x%x)\n", (char*)&overlay_format, overlay_format);
goto fail;
}
......
......@@ -29,6 +29,6 @@
#include "ijksdl_inc_ffmpeg.h"
// TODO: 9 alignment to speed up memcpy when display
SDL_VoutOverlay *SDL_VoutFFmpeg_CreateOverlay(int width, int height, Uint32 format, SDL_Vout *vout);
SDL_VoutOverlay *SDL_VoutFFmpeg_CreateOverlay(int width, int height, int frame_format, SDL_Vout *vout);
#endif
/*
* copyright (c) 2016 Zhang Rui <bbcallen@gmail.com>
*
* This file is part of ijkPlayer.
*
* ijkPlayer 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.
*
* ijkPlayer 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 ijkPlayer; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "internal.h"
// BT.709, which is the standard for HDTV.
static const GLfloat g_bt709[] = {
1.164, 1.164, 1.164,
0.0, -0.213, 2.112,
1.793, -0.533, 0.0,
};
const GLfloat *IJK_GLES2_getColorMatrix_bt709()
{
return g_bt709;
}
static const GLfloat g_bt601[] = {
1.164, 1.164, 1.164,
0.0, -0.392, 2.017,
1.596, -0.813, 0.0,
};
const GLfloat *IJK_GLES2_getColorMatrix_bt601()
{
return g_bt709;
}
/*
* copyright (c) 2016 Zhang Rui <bbcallen@gmail.com>
*
* This file is part of ijkPlayer.
*
* ijkPlayer 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.
*
* ijkPlayer 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 ijkPlayer; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "internal.h"
void IJK_GLES2_checkError(const char* op) {
for (GLint error = glGetError(); error; error = glGetError()) {
ALOGE("[GLES2] after %s() glError (0x%x)\n", op, error);
}
}
void IJK_GLES2_printString(const char *name, GLenum s) {
const char *v = (const char *) glGetString(s);
ALOGI("[GLES2] %s = %s\n", name, v);
}
void IJK_GLES2_loadOrtho(IJK_GLES_Matrix *matrix, GLfloat left, GLfloat right, GLfloat bottom, GLfloat top, GLfloat near, GLfloat far)
{
GLfloat r_l = right - left;
GLfloat t_b = top - bottom;
GLfloat f_n = far - near;
GLfloat tx = - (right + left) / (right - left);
GLfloat ty = - (top + bottom) / (top - bottom);
GLfloat tz = - (far + near) / (far - near);
matrix->m[0] = 2.0f / r_l;
matrix->m[1] = 0.0f;
matrix->m[2] = 0.0f;
matrix->m[3] = 0.0f;
matrix->m[4] = 0.0f;
matrix->m[5] = 2.0f / t_b;
matrix->m[6] = 0.0f;
matrix->m[7] = 0.0f;
matrix->m[8] = 0.0f;
matrix->m[9] = 0.0f;
matrix->m[10] = -2.0f / f_n;
matrix->m[11] = 0.0f;
matrix->m[12] = tx;
matrix->m[13] = ty;
matrix->m[14] = tz;
matrix->m[15] = 1.0f;
}
/*
* copyright (c) 2016 Zhang Rui <bbcallen@gmail.com>
*
* This file is part of ijkPlayer.
*
* ijkPlayer 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.
*
* ijkPlayer 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 ijkPlayer; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "ijksdl/gles2/internal.h"
static const char g_shader[] = IJK_GLES_STRING(
precision highp float;
varying highp vec2 vv2_Texcoord;
uniform mat3 um3_ColorConversion;
uniform lowp sampler2D us2_SamplerX;
uniform lowp sampler2D us2_SamplerY;
uniform lowp sampler2D us2_SamplerZ;
void main()
{
mediump vec3 yuv;
lowp vec3 rgb;
yuv.x = (texture2D(us2_SamplerX, vv2_Texcoord).r - (16.0 / 255.0));
yuv.y = (texture2D(us2_SamplerY, vv2_Texcoord).r - 0.5);
yuv.z = (texture2D(us2_SamplerZ, vv2_Texcoord).r - 0.5);
rgb = um3_ColorConversion * yuv;
gl_FragColor = vec4(rgb, 1);
}
);
const char *IJK_GLES2_getFragmentShader_yuv420p()
{
return g_shader;
}
/*
* copyright (c) 2016 Zhang Rui <bbcallen@gmail.com>
*
* This file is part of ijkPlayer.
*
* ijkPlayer 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.
*
* ijkPlayer 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 ijkPlayer; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "ijksdl/gles2/internal.h"
static const char g_shader[] = IJK_GLES_STRING(
precision highp float;
varying highp vec2 vv2_Texcoord;
uniform mat3 um3_ColorConversion;
uniform lowp sampler2D us2_SamplerX;
uniform lowp sampler2D us2_SamplerY;
uniform lowp sampler2D us2_SamplerZ;
void main()
{
mediump vec3 yuv_l;
mediump vec3 yuv_h;
mediump vec3 yuv;
lowp vec3 rgb;
yuv_l.x = texture2D(us2_SamplerX, vv2_Texcoord).r;
yuv_h.x = texture2D(us2_SamplerX, vv2_Texcoord).a;
yuv_l.y = texture2D(us2_SamplerY, vv2_Texcoord).r;
yuv_h.y = texture2D(us2_SamplerY, vv2_Texcoord).a;
yuv_l.z = texture2D(us2_SamplerZ, vv2_Texcoord).r;
yuv_h.z = texture2D(us2_SamplerZ, vv2_Texcoord).a;
yuv = (yuv_l * 255.0 + yuv_h * 255.0 * 256.0) / (1023.0) - vec3(16.0 / 255.0, 0.5, 0.5);
rgb = um3_ColorConversion * yuv;
gl_FragColor = vec4(rgb, 1);
}
);
const char *IJK_GLES2_getFragmentShader_yuv444p10le()
{
return g_shader;
}
/*
* copyright (c) 2016 Zhang Rui <bbcallen@gmail.com>
*
* This file is part of ijkPlayer.
*
* ijkPlayer 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.
*
* ijkPlayer 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 ijkPlayer; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef IJKSDL__IJKSDL_GLES2__INTERNAL__H
#define IJKSDL__IJKSDL_GLES2__INTERNAL__H
#include <assert.h>
#include <stdlib.h>
#include "ijksdl/ijksdl_fourcc.h"
#include "ijksdl/ijksdl_log.h"
#include "ijksdl/ijksdl_gles2.h"
#include "ijksdl/ijksdl_vout.h"
#define IJK_GLES_STRINGIZE(x) #x
#define IJK_GLES_STRINGIZE2(x) IJK_GLES_STRINGIZE(x)
#define IJK_GLES_STRING(x) IJK_GLES_STRINGIZE2(x)
typedef struct IJK_GLES_Matrix
{
GLfloat m[16];
} IJK_GLES_Matrix;
void IJK_GLES2_loadOrtho(IJK_GLES_Matrix *matrix, GLfloat left, GLfloat right, GLfloat bottom, GLfloat top, GLfloat near, GLfloat far);
const char *IJK_GLES2_getVertexShader_default();
const char *IJK_GLES2_getFragmentShader_yuv420p();
const char *IJK_GLES2_getFragmentShader_yuv444p10le();
const GLfloat *IJK_GLES2_getColorMatrix_bt709();
const GLfloat *IJK_GLES2_getColorMatrix_bt601();
IJK_GLES2_Renderer *IJK_GLES2_Renderer_create_base(const char *fragment_shader_source);
IJK_GLES2_Renderer *IJK_GLES2_Renderer_create_yuv420p();
IJK_GLES2_Renderer *IJK_GLES2_Renderer_create_yuv444p10le();
#endif
/*
* copyright (c) 2016 Zhang Rui <bbcallen@gmail.com>
*
* This file is part of ijkPlayer.
*
* ijkPlayer 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.
*
* ijkPlayer 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 ijkPlayer; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "internal.h"
static void IJK_GLES2_printProgramInfo(GLuint program)
{
if (!program)
return;
GLint info_len = 0;
glGetProgramiv(program, GL_INFO_LOG_LENGTH, &info_len);
if (!info_len) {
ALOGE("[GLES2][Program] empty info\n");
return;
}
char buf_stack[32];
char *buf_heap = NULL;
char *buf = buf_stack;
size_t buf_len = sizeof(buf_stack) - 1;
if (info_len > sizeof(buf_stack)) {
buf_heap = (char*) malloc(info_len + 1);
if (buf_heap) {
buf = buf_heap;
buf_len = info_len;
}
}
glGetProgramInfoLog(program, buf_len, NULL, buf);
ALOGE("[GLES2][Program] error %s\n", buf);
if (buf_heap)
free(buf_heap);
}
void IJK_GLES2_Render_reset(IJK_GLES2_Renderer *renderer)
{
if (!renderer)
return;
if (renderer->vertex_shader)
glDeleteShader(renderer->vertex_shader);
if (renderer->fragment_shader)
glDeleteShader(renderer->fragment_shader);
if (renderer->program)
glDeleteProgram(renderer->program);
for (int i = 0; i < IJK_GLES2_MAX_PLANE; ++i) {
if (renderer->plane_textures[i]) {
glDeleteTextures(1, &renderer->plane_textures[i]);
}
}
memset(renderer, 0, sizeof(IJK_GLES2_Renderer));
}
void IJK_GLES2_Renderer_free(IJK_GLES2_Renderer *renderer)
{
if (!renderer)
return;
#if 0
if (renderer->vertex_shader) ALOGW("[GLES2] renderer: vertex_shader not deleted.\n");
if (renderer->fragment_shader) ALOGW("[GLES2] renderer: fragment_shader not deleted.\n");
if (renderer->program) ALOGW("[GLES2] renderer: program not deleted.\n");
for (int i = 0; i < IJK_GLES2_MAX_PLANE; ++i) {
if (renderer->plane_textures[i])
ALOGW("[GLES2] renderer: plane texture[%d] not deleted.\n", i);
}
#endif
free(renderer);
}
void IJK_GLES2_Renderer_freeP(IJK_GLES2_Renderer **renderer)
{
if (!renderer || !*renderer)
return;
IJK_GLES2_Renderer_free(*renderer);
*renderer = NULL;
}
IJK_GLES2_Renderer *IJK_GLES2_Renderer_create_base(const char *fragment_shader_source)
{
assert(fragment_shader_source);
IJK_GLES2_Renderer *renderer = (IJK_GLES2_Renderer *)calloc(1, sizeof(IJK_GLES2_Renderer));
if (!renderer)
goto fail;
renderer->vertex_shader = IJK_GLES2_loadShader(GL_VERTEX_SHADER, IJK_GLES2_getVertexShader_default());
if (!renderer->vertex_shader)
goto fail;
renderer->fragment_shader = IJK_GLES2_loadShader(GL_FRAGMENT_SHADER, fragment_shader_source);
if (!renderer->fragment_shader)
goto fail;
renderer->program = glCreateProgram(); IJK_GLES2_checkError("glCreateProgram");
if (!renderer->program)
goto fail;
glAttachShader(renderer->program, renderer->vertex_shader); IJK_GLES2_checkError("glAttachShader(vertex)");
glAttachShader(renderer->program, renderer->fragment_shader); IJK_GLES2_checkError("glAttachShader(fragment)");
glLinkProgram(renderer->program); IJK_GLES2_checkError("glLinkProgram");
GLint link_status = GL_FALSE;
glGetProgramiv(renderer->program, GL_LINK_STATUS, &link_status);
if (!link_status)
goto fail;
renderer->av4_position = glGetAttribLocation(renderer->program, "av4_Position"); IJK_GLES2_checkError_TRACE("glGetAttribLocation(av4_Position)");
renderer->av2_texcoord = glGetAttribLocation(renderer->program, "av2_Texcoord"); IJK_GLES2_checkError_TRACE("glGetAttribLocation(av2_Texcoord)");
renderer->um4_mvp = glGetUniformLocation(renderer->program, "um4_ModelViewProjection"); IJK_GLES2_checkError_TRACE("glGetUniformLocation(um4_ModelViewProjection)");
return renderer;
fail:
if (renderer->program)
IJK_GLES2_printProgramInfo(renderer->program);
IJK_GLES2_Renderer_free(renderer);
return NULL;
}
IJK_GLES2_Renderer *IJK_GLES2_Renderer_create(SDL_VoutOverlay *overlay)
{
if (!overlay)
return NULL;
IJK_GLES2_printString("Version", GL_VERSION);
IJK_GLES2_printString("Vendor", GL_VENDOR);
IJK_GLES2_printString("Renderer", GL_RENDERER);
IJK_GLES2_printString("Extensions", GL_EXTENSIONS);
switch (overlay->format) {
case SDL_FCC_YV12: return IJK_GLES2_Renderer_create_yuv420p();
case SDL_FCC_I420: return IJK_GLES2_Renderer_create_yuv420p();
case SDL_FCC_I444P10LE: return IJK_GLES2_Renderer_create_yuv444p10le();
default: return NULL;
}
}
GLboolean IJK_GLES2_Renderer_isValid(IJK_GLES2_Renderer *renderer)
{
return renderer && renderer->program;
}
static const GLfloat g_vertices[] = {
-1.0f, -1.0f,
1.0f, -1.0f,
-1.0f, 1.0f,
1.0f, 1.0f
};
/*
* Per-Context routine
*/
GLboolean IJK_GLES2_Renderer_setupGLES()
{
glClearColor(0.0f, 0.0f, 0.0f, 1.0f); IJK_GLES2_checkError_TRACE("glClearColor");
glEnable(GL_CULL_FACE); IJK_GLES2_checkError_TRACE("glEnable(GL_CULL_FACE)");
glCullFace(GL_BACK); IJK_GLES2_checkError_TRACE("glCullFace");
glDisable(GL_DEPTH_TEST);
return GL_TRUE;
}
static void IJK_GLES2_Renderer_TexCoords_reset(IJK_GLES2_Renderer *renderer)
{
renderer->texcoords[0] = 0.0f;
renderer->texcoords[1] = 1.0f;
renderer->texcoords[2] = 1.0f;
renderer->texcoords[3] = 1.0f;
renderer->texcoords[4] = 0.0f;
renderer->texcoords[5] = 0.0f;
renderer->texcoords[6] = 1.0f;
renderer->texcoords[7] = 0.0f;
}
static void IJK_GLES2_Renderer_TexCoords_cropRight(IJK_GLES2_Renderer *renderer, GLfloat cropRight)
{
ALOGE("IJK_GLES2_Renderer_TexCoords_cropRight");
renderer->texcoords[0] = 0.0f;
renderer->texcoords[1] = 1.0f;
renderer->texcoords[2] = 1.0f - cropRight;
renderer->texcoords[3] = 1.0f;
renderer->texcoords[4] = 0.0f;
renderer->texcoords[5] = 0.0f;
renderer->texcoords[6] = 1.0f - cropRight;
renderer->texcoords[7] = 0.0f;
}
static void IJK_GLES2_Renderer_TexCoords_reloadVertex(IJK_GLES2_Renderer *renderer)
{
glVertexAttribPointer(renderer->av2_texcoord, 2, GL_FLOAT, GL_FALSE, 0, renderer->texcoords); IJK_GLES2_checkError_TRACE("glVertexAttribPointer(av2_texcoord)");
glEnableVertexAttribArray(renderer->av2_texcoord); IJK_GLES2_checkError_TRACE("glEnableVertexAttribArray(av2_texcoord)");
}
/*
* Per-Renderer routine
*/
GLboolean IJK_GLES2_Renderer_use(IJK_GLES2_Renderer *renderer)
{
if (!renderer)
return GL_FALSE;
assert(renderer->func_use);
if (!renderer->func_use(renderer))
return GL_FALSE;
IJK_GLES_Matrix modelViewProj;
IJK_GLES2_loadOrtho(&modelViewProj, -1.0f, 1.0f, -1.0f, 1.0f, -1.0f, 1.0f);
glUniformMatrix4fv(renderer->um4_mvp, 1, GL_FALSE, modelViewProj.m); IJK_GLES2_checkError_TRACE("glUniformMatrix4fv(um4_mvp)");
IJK_GLES2_Renderer_TexCoords_reset(renderer);
IJK_GLES2_Renderer_TexCoords_reloadVertex(renderer);
glVertexAttribPointer(renderer->av4_position, 2, GL_FLOAT, GL_FALSE, 0, g_vertices); IJK_GLES2_checkError_TRACE("glVertexAttribPointer(av2_texcoord)");
glEnableVertexAttribArray(renderer->av4_position); IJK_GLES2_checkError_TRACE("glEnableVertexAttribArray(av2_texcoord)");
return GL_TRUE;
}
static GLboolean IJK_GLES2_Renderer_prepareForOverlay(IJK_GLES2_Renderer *renderer, SDL_VoutOverlay *overlay)
{
assert(renderer);
assert(overlay);
assert(renderer->func_getBufferWidth);
GLsizei buffer_width = renderer->func_getBufferWidth(renderer, overlay);
GLsizei visible_width = overlay->w;
if (buffer_width > 0 &&
buffer_width > visible_width &&
buffer_width != renderer->buffer_width &&
visible_width != renderer->visible_width) {
renderer->buffer_width = buffer_width;
renderer->visible_width = visible_width;
GLsizei padding_pixels = buffer_width - visible_width;
GLfloat padding_normalized = ((GLfloat)padding_pixels) / buffer_width;
ALOGI("[yuv420p] padding changed: %d - %d = %d (%f)\n",
buffer_width, visible_width,
padding_pixels, padding_normalized);
IJK_GLES2_Renderer_TexCoords_reset(renderer);
IJK_GLES2_Renderer_TexCoords_cropRight(renderer, padding_normalized);
IJK_GLES2_Renderer_TexCoords_reloadVertex(renderer);
}
return GL_TRUE;
}
/*
* Per-Frame routine
*/
GLboolean IJK_GLES2_Renderer_renderOverlay(IJK_GLES2_Renderer *renderer, SDL_VoutOverlay *overlay)
{
if (!renderer || !overlay || !renderer->func_uploadTexture)
return GL_FALSE;
glClear(GL_COLOR_BUFFER_BIT); IJK_GLES2_checkError_TRACE("glClear");
IJK_GLES2_Renderer_prepareForOverlay(renderer, overlay);
if (!renderer->func_uploadTexture(renderer, overlay))
return GL_FALSE;
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); IJK_GLES2_checkError_TRACE("glDrawArrays");
return GL_TRUE;
}
/*
* copyright (c) 2016 Zhang Rui <bbcallen@gmail.com>
*
* This file is part of ijkPlayer.
*
* ijkPlayer 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.
*
* ijkPlayer 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 ijkPlayer; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "internal.h"
static GLboolean yuv420p_use(IJK_GLES2_Renderer *renderer)
{
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
glUseProgram(renderer->program); IJK_GLES2_checkError_TRACE("glUseProgram");
if (0 == renderer->plane_textures[0])
glGenTextures(3, renderer->plane_textures);
for (int i = 0; i < 3; ++i) {
glActiveTexture(GL_TEXTURE0 + i);
glBindTexture(GL_TEXTURE_2D, renderer->plane_textures[i]);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glUniform1i(renderer->us2_sampler[i], i);
}
glUniformMatrix3fv(renderer->um3_color_conversion, 1, GL_FALSE, IJK_GLES2_getColorMatrix_bt709());
return GL_TRUE;
}
static GLsizei yuv420p_getBufferWidth(IJK_GLES2_Renderer *renderer, SDL_VoutOverlay *overlay)
{
if (!overlay)
return 0;
return overlay->pitches[0] / 1;
}
static GLboolean yuv420p_uploadTexture(IJK_GLES2_Renderer *renderer, SDL_VoutOverlay *overlay)
{
if (!renderer || !overlay)
return GL_FALSE;
int planes[3] = { 0, 1, 2 };
const GLsizei widths[3] = { overlay->pitches[0], overlay->pitches[1], overlay->pitches[2] };
const GLsizei heights[3] = { overlay->h, overlay->h / 2, overlay->h / 2 };
const GLubyte *pixels[3] = { overlay->pixels[0], overlay->pixels[1], overlay->pixels[2] };
switch (overlay->format) {
case SDL_FCC_I420:
break;
case SDL_FCC_YV12:
planes[1] = 2;
planes[2] = 1;
break;
default:
ALOGE("[yuv420p] unexpected format %x\n", overlay->format);
return GL_FALSE;
}
for (int i = 0; i < 3; ++i) {
int plane = planes[i];
glBindTexture(GL_TEXTURE_2D, renderer->plane_textures[i]);
glTexImage2D(GL_TEXTURE_2D,
0,
GL_LUMINANCE,
widths[plane],
heights[plane],
0,
GL_LUMINANCE,
GL_UNSIGNED_BYTE,
pixels[plane]);
}
return GL_TRUE;
}
IJK_GLES2_Renderer *IJK_GLES2_Renderer_create_yuv420p()
{
IJK_GLES2_Renderer *renderer = IJK_GLES2_Renderer_create_base(IJK_GLES2_getFragmentShader_yuv420p());
if (!renderer)
goto fail;
renderer->us2_sampler[0] = glGetUniformLocation(renderer->program, "us2_SamplerX"); IJK_GLES2_checkError_TRACE("glGetUniformLocation(us2_SamplerX)");
renderer->us2_sampler[1] = glGetUniformLocation(renderer->program, "us2_SamplerY"); IJK_GLES2_checkError_TRACE("glGetUniformLocation(us2_SamplerY)");
renderer->us2_sampler[2] = glGetUniformLocation(renderer->program, "us2_SamplerZ"); IJK_GLES2_checkError_TRACE("glGetUniformLocation(us2_SamplerZ)");
renderer->um3_color_conversion = glGetUniformLocation(renderer->program, "um3_ColorConversion"); IJK_GLES2_checkError_TRACE("glGetUniformLocation(um3_ColorConversionMatrix)");
renderer->func_use = yuv420p_use;
renderer->func_getBufferWidth = yuv420p_getBufferWidth;
renderer->func_uploadTexture = yuv420p_uploadTexture;
return renderer;
fail:
IJK_GLES2_Renderer_free(renderer);
return NULL;
}
/*
* copyright (c) 2016 Zhang Rui <bbcallen@gmail.com>
*
* This file is part of ijkPlayer.
*
* ijkPlayer 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.
*
* ijkPlayer 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 ijkPlayer; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "internal.h"
static GLboolean yuv444p10le_use(IJK_GLES2_Renderer *renderer)
{
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
glUseProgram(renderer->program); IJK_GLES2_checkError_TRACE("glUseProgram");
if (0 == renderer->plane_textures[0])
glGenTextures(3, renderer->plane_textures);
for (int i = 0; i < 3; ++i) {
glActiveTexture(GL_TEXTURE0 + i);
glBindTexture(GL_TEXTURE_2D, renderer->plane_textures[i]);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glUniform1i(renderer->us2_sampler[i], i);
}
glUniformMatrix3fv(renderer->um3_color_conversion, 1, GL_FALSE, IJK_GLES2_getColorMatrix_bt709());
return GL_TRUE;
}
static GLsizei yuv444p10le_getBufferWidth(IJK_GLES2_Renderer *renderer, SDL_VoutOverlay *overlay)
{
if (!overlay)
return 0;
return overlay->pitches[0] / 2;
}
static GLboolean yuv444p10le_uploadTexture(IJK_GLES2_Renderer *renderer, SDL_VoutOverlay *overlay)
{
if (!renderer || !overlay)
return GL_FALSE;
int planes[3] = { 0, 1, 2 };
const GLsizei widths[3] = { overlay->pitches[0] / 2, overlay->pitches[1] / 2, overlay->pitches[2] / 2 };
const GLsizei heights[3] = { overlay->h, overlay->h, overlay->h };
const GLubyte *pixels[3] = { overlay->pixels[0], overlay->pixels[1], overlay->pixels[2] };
switch (overlay->format) {
case SDL_FCC_I444P10LE:
break;
default:
ALOGE("[yuv420p10le] unexpected format %x\n", overlay->format);
return GL_FALSE;
}
for (int i = 0; i < 3; ++i) {
int plane = planes[i];
glBindTexture(GL_TEXTURE_2D, renderer->plane_textures[i]); IJK_GLES2_checkError_TRACE("glBindTexture");
glTexImage2D(GL_TEXTURE_2D,
0,
GL_LUMINANCE_ALPHA,
widths[plane],
heights[plane],
0,
GL_LUMINANCE_ALPHA,
GL_UNSIGNED_BYTE,
pixels[plane]); IJK_GLES2_checkError_TRACE("glTexImage2D");
}
return GL_TRUE;
}
IJK_GLES2_Renderer *IJK_GLES2_Renderer_create_yuv444p10le()
{
IJK_GLES2_Renderer *renderer = IJK_GLES2_Renderer_create_base(IJK_GLES2_getFragmentShader_yuv444p10le());
if (!renderer)
goto fail;
renderer->us2_sampler[0] = glGetUniformLocation(renderer->program, "us2_SamplerX"); IJK_GLES2_checkError_TRACE("glGetUniformLocation(us2_SamplerX)");
renderer->us2_sampler[1] = glGetUniformLocation(renderer->program, "us2_SamplerY"); IJK_GLES2_checkError_TRACE("glGetUniformLocation(us2_SamplerY)");
renderer->us2_sampler[2] = glGetUniformLocation(renderer->program, "us2_SamplerZ"); IJK_GLES2_checkError_TRACE("glGetUniformLocation(us2_SamplerZ)");
renderer->um3_color_conversion = glGetUniformLocation(renderer->program, "um3_ColorConversion"); IJK_GLES2_checkError_TRACE("glGetUniformLocation(um3_ColorConversionMatrix)");
renderer->func_use = yuv444p10le_use;
renderer->func_getBufferWidth = yuv444p10le_getBufferWidth;
renderer->func_uploadTexture = yuv444p10le_uploadTexture;
return renderer;
fail:
IJK_GLES2_Renderer_free(renderer);
return NULL;
}
/*
* copyright (c) 2016 Zhang Rui <bbcallen@gmail.com>
*
* This file is part of ijkPlayer.
*
* ijkPlayer 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.
*
* ijkPlayer 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 ijkPlayer; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "internal.h"
static void IJK_GLES2_printShaderInfo(GLuint shader)
{
if (!shader)
return;
GLint info_len = 0;
glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &info_len);
if (!info_len) {
ALOGE("[GLES2][Shader] empty info\n");
return;
}
char buf_stack[32];
char *buf_heap = NULL;
char *buf = buf_stack;
size_t buf_len = sizeof(buf_stack) - 1;
if (info_len > sizeof(buf_stack)) {
buf_heap = (char*) malloc(info_len + 1);
if (buf_heap) {
buf = buf_heap;
buf_len = info_len;
}
}
glGetShaderInfoLog(shader, buf_len, NULL, buf);
ALOGE("[GLES2][Shader] error %s\n", buf);
if (buf_heap)
free(buf_heap);
}
GLuint IJK_GLES2_loadShader(GLenum shader_type, const char *shader_source)
{
assert(shader);
GLuint shader = glCreateShader(shader_type); IJK_GLES2_checkError("glCreateShader");
if (!shader)
return 0;
assert(shader_source);
glShaderSource(shader, 1, &shader_source, NULL); IJK_GLES2_checkError_TRACE("glShaderSource");
glCompileShader(shader); IJK_GLES2_checkError_TRACE("glCompileShader");
GLint compile_status = 0;
glGetShaderiv(shader, GL_COMPILE_STATUS, &compile_status);
if (!compile_status)
goto fail;
return shader;
fail:
if (shader) {
IJK_GLES2_printShaderInfo(shader);
glDeleteShader(shader);
}
return 0;
}
/*
* copyright (c) 2016 Zhang Rui <bbcallen@gmail.com>
*
* This file is part of ijkPlayer.
*
* ijkPlayer 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.
*
* ijkPlayer 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 ijkPlayer; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "ijksdl/gles2/internal.h"
static const char g_shader[] = IJK_GLES_STRING(
precision highp float;
varying highp vec2 vv2_Texcoord;
attribute highp vec4 av4_Position;
attribute highp vec2 av2_Texcoord;
uniform mat4 um4_ModelViewProjection;
void main()
{
gl_Position = um4_ModelViewProjection * av4_Position;
vv2_Texcoord = av2_Texcoord.xy;
}
);
const char *IJK_GLES2_getVertexShader_default()
{
return g_shader;
}
/*
* copyright (c) 2016 Zhang Rui <bbcallen@gmail.com>
*
* This file is part of ijkPlayer.
*
* ijkPlayer 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.
*
* ijkPlayer 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 ijkPlayer; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "ijksdl_egl.h"
#include <stdlib.h>
#include <stdbool.h>
#include <GLES2/gl2.h>
#include <GLES2/gl2ext.h>
#include <EGL/egl.h>
#include <EGL/eglext.h>
#include <EGL/eglplatform.h>
#include "ijksdl/ijksdl_gles2.h"
#include "ijksdl/ijksdl_log.h"
#include "ijksdl/ijksdl_vout.h"
#include "ijksdl/gles2/internal.h"
#define IJK_EGL_RENDER_BUFFER 0
typedef struct IJK_EGL_Opaque {
IJK_GLES2_Renderer *renderer;
} IJK_EGL_Opaque;
static EGLBoolean IJK_EGL_isValid(IJK_EGL* egl)
{
if (egl &&
egl->window &&
egl->display &&
egl->surface &&
egl->context) {
return EGL_TRUE;
}
return EGL_FALSE;
}
void IJK_EGL_terminate(IJK_EGL* egl)
{
if (!IJK_EGL_isValid(egl))
return;
if (egl->opaque)
IJK_GLES2_Renderer_freeP(&egl->opaque->renderer);
if (egl->display) {
eglMakeCurrent(egl->display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
if (egl->context)
eglDestroyContext(egl->display, egl->context);
if (egl->surface)
eglDestroySurface(egl->display, egl->surface);
eglTerminate(egl->display);
eglReleaseThread(); // FIXME: call at thread exit
}
egl->context = EGL_NO_CONTEXT;
egl->surface = EGL_NO_SURFACE;
egl->display = EGL_NO_DISPLAY;
}
static int IJK_EGL_getSurfaceWidth(IJK_EGL* egl)
{
EGLint width = 0;
if (!eglQuerySurface(egl->display, egl->surface, EGL_WIDTH, &width)) {
ALOGE("[EGL] eglQuerySurface(EGL_WIDTH) returned error %d", eglGetError());
return 0;
}
return width;
}
static int IJK_EGL_getSurfaceHeight(IJK_EGL* egl)
{
EGLint height = 0;
if (!eglQuerySurface(egl->display, egl->surface, EGL_HEIGHT, &height)) {
ALOGE("[EGL] eglQuerySurface(EGL_HEIGHT) returned error %d", eglGetError());
return 0;
}
return height;
}
static EGLBoolean IJK_EGL_setSurfaceSize(IJK_EGL* egl, int width, int height)
{
if (!IJK_EGL_isValid(egl))
return EGL_FALSE;
#ifdef __ANDROID__
egl->width = IJK_EGL_getSurfaceWidth(egl);
egl->height = IJK_EGL_getSurfaceHeight(egl);
if (width != egl->width || height != egl->height) {
int format = ANativeWindow_getFormat(egl->window);
ALOGI("ANativeWindow_setBuffersGeometry(w=%d,h=%d) -> (w=%d,h=%d);",
egl->width, egl->height,
width, height);
int ret = ANativeWindow_setBuffersGeometry(egl->window, width, height, format);
if (ret) {
ALOGE("[EGL] ANativeWindow_setBuffersGeometry() returned error %d", ret);
return EGL_FALSE;
}
egl->width = IJK_EGL_getSurfaceWidth(egl);
egl->height = IJK_EGL_getSurfaceHeight(egl);
return (egl->width && egl->height) ? EGL_TRUE : EGL_FALSE;
}
return EGL_TRUE;
#else
// FIXME: other platform?
#endif
return EGL_FALSE;
}
static EGLBoolean IJK_EGL_makeCurrent(IJK_EGL* egl, EGLNativeWindowType window)
{
if (window && window == egl->window &&
egl->display &&
egl->surface &&
egl->context) {
if (!eglMakeCurrent(egl->display, egl->surface, egl->surface, egl->context)) {
ALOGE("[EGL] elgMakeCurrent() failed (cached)\n");
return EGL_FALSE;
}
return EGL_TRUE;
}
IJK_EGL_terminate(egl);
egl->window = window;
if (!window)
return EGL_FALSE;
EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
if (display == EGL_NO_DISPLAY) {
ALOGE("[EGL] eglGetDisplay failed\n");
return EGL_FALSE;
}
EGLint major, minor;
if (!eglInitialize(display, &major, &minor)) {
ALOGE("[EGL] eglInitialize failed\n");
return EGL_FALSE;
}
ALOGI("[EGL] eglInitialize %d.%d\n", (int)major, (int)minor);
static const EGLint configAttribs[] = {
EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
EGL_BLUE_SIZE, 8,
EGL_GREEN_SIZE, 8,
EGL_RED_SIZE, 8,
EGL_NONE
};
static const EGLint contextAttribs[] = {
EGL_CONTEXT_CLIENT_VERSION, 2,
EGL_NONE
};
EGLConfig config;
EGLint numConfig;
if (!eglChooseConfig(display, configAttribs, &config, 1, &numConfig)) {
ALOGE("[EGL] eglChooseConfig failed\n");
eglTerminate(display);
return EGL_FALSE;
}
#ifdef __ANDROID__
{
EGLint native_visual_id = 0;
if (!eglGetConfigAttrib(display, config, EGL_NATIVE_VISUAL_ID, &native_visual_id)) {
ALOGE("[EGL] eglGetConfigAttrib() returned error %d", eglGetError());
eglTerminate(display);
return EGL_FALSE;
}
int32_t width = ANativeWindow_getWidth(window);
int32_t height = ANativeWindow_getWidth(window);
ALOGI("[EGL] ANativeWindow_setBuffersGeometry(f=%d);", native_visual_id);
int ret = ANativeWindow_setBuffersGeometry(window, width, height, native_visual_id);
if (ret) {
ALOGE("[EGL] ANativeWindow_setBuffersGeometry(format) returned error %d", ret);
eglTerminate(display);
return EGL_FALSE;
}
}
#endif
EGLSurface surface = eglCreateWindowSurface(display, config, window, NULL);
if (surface == EGL_NO_SURFACE) {
ALOGE("[EGL] eglCreateWindowSurface failed\n");
eglTerminate(display);
return EGL_FALSE;
}
EGLSurface context = eglCreateContext(display, config, EGL_NO_CONTEXT, contextAttribs);
if (context == EGL_NO_CONTEXT) {
ALOGE("[EGL] eglCreateContext failed\n");
eglDestroySurface(display, surface);
eglTerminate(display);
return EGL_FALSE;
}
if (!eglMakeCurrent(display, surface, surface, context)) {
ALOGE("[EGL] elgMakeCurrent() failed (new)\n");
eglDestroyContext(display, context);
eglDestroySurface(display, surface);
eglTerminate(display);
return EGL_FALSE;
}
#if 0
#if defined(__ANDROID__)
{
const char *extensions = (const char *) glGetString(GL_EXTENSIONS);
if (extensions) {
char *dup_extensions = strdup(extensions);
if (dup_extensions) {
char *brk = NULL;
char *ext = strtok_r(dup_extensions, " ", &brk);
while (ext) {
if (0 == strcmp(ext, "GL_EXT_texture_rg"))
egl->gles2_extensions[IJK_GLES2__GL_EXT_texture_rg] = 1;
ext = strtok_r(NULL, " ", &brk);
}
free(dup_extensions);
}
}
}
#elif defined(__APPLE__)
egl->gles2_extensions[IJK_GLES2__GL_EXT_texture_rg] = 1;
#endif
ALOGI("[EGL] GLES2 extensions begin:\n");
ALOGI("[EGL] GL_EXT_texture_rg: %d\n", egl->gles2_extensions[IJK_GLES2__GL_EXT_texture_rg]);
ALOGI("[EGL] GLES2 extensions end.\n");
#endif
IJK_GLES2_Renderer_setupGLES();
egl->context = context;
egl->surface = surface;
egl->display = display;
return EGL_TRUE;
}
static EGLBoolean IJK_EGL_prepareRenderer(IJK_EGL* egl, SDL_VoutOverlay *overlay)
{
assert(egl);
assert(egl->opaque);
IJK_EGL_Opaque *opaque = egl->opaque;
// FIXME: check render against overlay
if (!IJK_GLES2_Renderer_isValid(opaque->renderer)) {
opaque->renderer = IJK_GLES2_Renderer_create(overlay);
if (!opaque->renderer) {
ALOGE("[EGL] Could not create render.");
return EGL_FALSE;
}
if (!IJK_GLES2_Renderer_use(opaque->renderer)) {
ALOGE("[EGL] Could not use render.");
IJK_GLES2_Renderer_freeP(&opaque->renderer);
return EGL_FALSE;
}
}
if (!IJK_EGL_setSurfaceSize(egl, overlay->w, overlay->h)) {
ALOGE("[EGL] IJK_EGL_setSurfaceSize(%d, %d) failed\n", overlay->w, overlay->h);
return EGL_FALSE;
}
glViewport(0, 0, egl->width, egl->height); IJK_GLES2_checkError_TRACE("glViewport");
return EGL_TRUE;
}
static EGLBoolean IJK_EGL_display_internal(IJK_EGL* egl, EGLNativeWindowType window, SDL_VoutOverlay *overlay)
{
IJK_EGL_Opaque *opaque = egl->opaque;
if (!IJK_EGL_prepareRenderer(egl, overlay)) {
ALOGE("[EGL] IJK_EGL_prepareRenderer failed\n");
return EGL_FALSE;
}
if (!IJK_GLES2_Renderer_renderOverlay(opaque->renderer, overlay)) {
ALOGE("[EGL] IJK_GLES2_render failed\n");
return EGL_FALSE;
}
eglSwapBuffers(egl->display, egl->surface);
return EGL_TRUE;
}
EGLBoolean IJK_EGL_display(IJK_EGL* egl, EGLNativeWindowType window, SDL_VoutOverlay *overlay)
{
EGLBoolean ret = EGL_FALSE;
if (!egl)
return EGL_FALSE;
IJK_EGL_Opaque *opaque = egl->opaque;
if (!opaque)
return EGL_FALSE;
if (!IJK_EGL_makeCurrent(egl, window))
return EGL_FALSE;
ret = IJK_EGL_display_internal(egl, window, overlay);
eglMakeCurrent(egl->display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
eglReleaseThread(); // FIXME: call at thread exit
return ret;
}
void IJK_EGL_releaseWindow(IJK_EGL* egl)
{
if (!egl || !egl->opaque || !egl->opaque->renderer)
return;
IJK_EGL_terminate(egl);
}
void IJK_EGL_free(IJK_EGL *egl)
{
if (!egl)
return;
IJK_EGL_terminate(egl);
memset(egl, 0, sizeof(IJK_EGL));
free(egl);
}
void IJK_EGL_freep(IJK_EGL **egl)
{
if (!egl || !*egl)
return;
IJK_EGL_free(*egl);
*egl = NULL;
}
static SDL_Class g_class = {
.name = "EGL",
};
IJK_EGL *IJK_EGL_create()
{
IJK_EGL *egl = (IJK_EGL*) mallocz(sizeof(IJK_EGL));
if (!egl)
return NULL;
egl->opaque_class = &g_class;
egl->opaque = mallocz(sizeof(IJK_EGL_Opaque));
if (!egl->opaque) {
free(egl);
return NULL;
}
return egl;
}
/*
* copyright (c) 2016 Zhang Rui <bbcallen@gmail.com>
*
* This file is part of ijkPlayer.
*
* ijkPlayer 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.
*
* ijkPlayer 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 ijkPlayer; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef IJKSDL__IJKSDL_EGL_H
#define IJKSDL__IJKSDL_EGL_H
#include <EGL/egl.h>
#include <EGL/eglext.h>
#include <EGL/eglplatform.h>
#include "ijksdl_class.h"
typedef struct SDL_VoutOverlay SDL_VoutOverlay;
typedef struct IJK_EGL_Opaque IJK_EGL_Opaque;
#if 0
enum {
IJK_GLES2__GL_EXT_texture_rg,
IJK_GLES2__MAX_EXT,
};
#endif
typedef struct IJK_EGL
{
SDL_Class *opaque_class;
IJK_EGL_Opaque *opaque;
EGLNativeWindowType window;
EGLDisplay display;
EGLSurface surface;
EGLContext context;
EGLint width;
EGLint height;
#if 0
uint8_t gles2_extensions[IJK_GLES2__MAX_EXT];
#endif
} IJK_EGL;
IJK_EGL *IJK_EGL_create();
void IJK_EGL_free(IJK_EGL *egl);
void IJK_EGL_freep(IJK_EGL **egl);
EGLBoolean IJK_EGL_display(IJK_EGL* egl, EGLNativeWindowType window, SDL_VoutOverlay *overlay);
void IJK_EGL_terminate(IJK_EGL* egl);
#endif
......@@ -63,8 +63,15 @@
// opaque formats
#define SDL_FCC__AMC SDL_FOURCC('_', 'A', 'M', 'C') /**< Android MediaCodec */
#define SDL_FCC__VTB SDL_FOURCC('_', 'V', 'T', 'B') /**< iOS VideoToolbox */
#define SDL_FCC__GLES2 SDL_FOURCC('_', 'E', 'S', '2') /**< let Vout choose format */
// undefine
#define SDL_FCC_UNDF SDL_FOURCC('U', 'N', 'D', 'F') /**< undefined */
enum {
IJK_AV_PIX_FMT__START = 10000,
IJK_AV_PIX_FMT__ANDROID_MEDIACODEC,
IJK_AV_PIX_FMT__VIDEO_TOOLBOX,
};
#endif
/*
* copyright (c) 2016 Zhang Rui <bbcallen@gmail.com>
*
* This file is part of ijkPlayer.
*
* ijkPlayer 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.
*
* ijkPlayer 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 ijkPlayer; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef IJKSDL__IJKSDL_GLES2_H
#define IJKSDL__IJKSDL_GLES2_H
#include <GLES2/gl2.h>
#include <GLES2/gl2ext.h>
#include <GLES2/gl2platform.h>
typedef struct SDL_VoutOverlay SDL_VoutOverlay;
/*
* Common
*/
#define IJK_GLES2_checkError_TRACE(op) IJK_GLES2_checkError(op)
#define IJK_GLES2_checkError_DEBUG(op) IJK_GLES2_checkError(op)
void IJK_GLES2_printString(const char *name, GLenum s);
void IJK_GLES2_checkError(const char *op);
GLuint IJK_GLES2_loadShader(GLenum shader_type, const char *shader_source);
/*
* Renderer
*/
#define IJK_GLES2_MAX_PLANE 3
typedef struct IJK_GLES2_Renderer IJK_GLES2_Renderer;
typedef struct IJK_GLES2_Renderer
{
GLuint program;
GLuint vertex_shader;
GLuint fragment_shader;
GLuint plane_textures[IJK_GLES2_MAX_PLANE];
GLuint av4_position;
GLuint av2_texcoord;
GLuint um4_mvp;
GLuint us2_sampler[IJK_GLES2_MAX_PLANE];
GLuint um3_color_conversion;
GLboolean (*func_use)(IJK_GLES2_Renderer *renderer);
GLsizei (*func_getBufferWidth)(IJK_GLES2_Renderer *renderer, SDL_VoutOverlay *overlay);
GLboolean (*func_uploadTexture)(IJK_GLES2_Renderer *renderer, SDL_VoutOverlay *overlay);
GLsizei buffer_width;
GLsizei visible_width;
GLfloat texcoords[8];
} IJK_GLES2_Renderer;
IJK_GLES2_Renderer *IJK_GLES2_Renderer_create(SDL_VoutOverlay *overlay);
void IJK_GLES2_Renderer_reset(IJK_GLES2_Renderer *renderer);
void IJK_GLES2_Renderer_free(IJK_GLES2_Renderer *renderer);
void IJK_GLES2_Renderer_freeP(IJK_GLES2_Renderer **renderer);
GLboolean IJK_GLES2_Renderer_setupGLES();
GLboolean IJK_GLES2_Renderer_isValid(IJK_GLES2_Renderer *renderer);
GLboolean IJK_GLES2_Renderer_use(IJK_GLES2_Renderer *renderer);
GLboolean IJK_GLES2_Renderer_renderOverlay(IJK_GLES2_Renderer *renderer, SDL_VoutOverlay *overlay);
#endif
......@@ -58,10 +58,19 @@ int SDL_VoutDisplayYUVOverlay(SDL_Vout *vout, SDL_VoutOverlay *overlay)
return -1;
}
SDL_VoutOverlay *SDL_Vout_CreateOverlay(int width, int height, Uint32 format, SDL_Vout *vout)
int SDL_VoutSetOverlayFormat(SDL_Vout *vout, Uint32 overlay_format)
{
if (!vout)
return -1;
vout->overlay_format = overlay_format;
return 0;
}
SDL_VoutOverlay *SDL_Vout_CreateOverlay(int width, int height, int frame_format, SDL_Vout *vout)
{
if (vout && vout->create_overlay)
return vout->create_overlay(width, height, format, vout);
return vout->create_overlay(width, height, frame_format, vout);
return NULL;
}
......
......@@ -63,16 +63,19 @@ struct SDL_Vout {
SDL_Class *opaque_class;
SDL_Vout_Opaque *opaque;
SDL_VoutOverlay *(*create_overlay)(int width, int height, Uint32 format, SDL_Vout *vout);
SDL_VoutOverlay *(*create_overlay)(int width, int height, int frame_format, SDL_Vout *vout);
void (*free_l)(SDL_Vout *vout);
int (*display_overlay)(SDL_Vout *vout, SDL_VoutOverlay *overlay);
Uint32 overlay_format;
};
void SDL_VoutFree(SDL_Vout *vout);
void SDL_VoutFreeP(SDL_Vout **pvout);
int SDL_VoutDisplayYUVOverlay(SDL_Vout *vout, SDL_VoutOverlay *overlay);
int SDL_VoutDisplayYUVOverlay(SDL_Vout *vout, SDL_VoutOverlay *overlay);
int SDL_VoutSetOverlayFormat(SDL_Vout *vout, Uint32 overlay_format);
SDL_VoutOverlay *SDL_Vout_CreateOverlay(int width, int height, Uint32 format, SDL_Vout *vout);
SDL_VoutOverlay *SDL_Vout_CreateOverlay(int width, int height, int frame_format, SDL_Vout *vout);
int SDL_VoutLockYUVOverlay(SDL_VoutOverlay *overlay);
int SDL_VoutUnlockYUVOverlay(SDL_VoutOverlay *overlay);
void SDL_VoutFreeYUVOverlay(SDL_VoutOverlay *overlay);
......
......@@ -252,7 +252,7 @@ void QueuePicture(VideoToolBoxContext* ctx) {
double duration = (frame_rate.num && frame_rate.den ? av_q2d((AVRational) {frame_rate.den, frame_rate.num}) : 0);
double pts = (picture.pts == AV_NOPTS_VALUE) ? NAN : picture.pts * av_q2d(tb);
picture.format = SDL_FCC__VTB;
picture.format = IJK_AV_PIX_FMT__VIDEO_TOOLBOX;
picture.sample_aspect_ratio.num = 1;
picture.sample_aspect_ratio.den = 1;
......
......@@ -37,15 +37,13 @@ struct SDL_Vout_Opaque {
IJKSDLGLView *gl_view;
};
static SDL_VoutOverlay *vout_create_overlay_l(int width, int height, Uint32 format, SDL_Vout *vout)
static SDL_VoutOverlay *vout_create_overlay_l(int width, int height, int frame_format, SDL_Vout *vout)
{
if (format == SDL_FCC__VTB)
{
return SDL_VoutVideoToolBox_CreateOverlay(width, height, format, vout);
}
else
{
return SDL_VoutFFmpeg_CreateOverlay(width, height, format, vout);
switch (frame_format) {
case IJK_AV_PIX_FMT__VIDEO_TOOLBOX:
return SDL_VoutVideoToolBox_CreateOverlay(width, height, vout);
default:
return SDL_VoutFFmpeg_CreateOverlay(width, height, frame_format, vout);
}
}
......
......@@ -29,7 +29,7 @@
#include "ijksdl_vout.h"
#include "ijksdl_inc_ffmpeg.h"
SDL_VoutOverlay *SDL_VoutVideoToolBox_CreateOverlay(int width, int height, Uint32 format, SDL_Vout *vout);
SDL_VoutOverlay *SDL_VoutVideoToolBox_CreateOverlay(int width, int height, SDL_Vout *vout);
CVPixelBufferRef SDL_VoutOverlayVideoToolBox_GetCVPixelBufferRef(SDL_VoutOverlay *overlay);
#endif
......@@ -85,7 +85,7 @@ static void func_unref(SDL_VoutOverlay *overlay)
static int func_fill_frame(SDL_VoutOverlay *overlay, const AVFrame *frame)
{
assert(frame->format == SDL_FCC__VTB);
assert(frame->format == IJK_AV_PIX_FMT__VIDEO_TOOLBOX);
CVBufferRef pixel_buffer = CVBufferRetain(frame->opaque);
SDL_VoutOverlay_Opaque *opaque = overlay->opaque;
......@@ -154,9 +154,10 @@ CVPixelBufferRef SDL_VoutOverlayVideoToolBox_GetCVPixelBufferRef(SDL_VoutOverlay
return opaque->pixel_buffer;
}
SDL_VoutOverlay *SDL_VoutVideoToolBox_CreateOverlay(int width, int height, Uint32 format, SDL_Vout *display)
SDL_VoutOverlay *SDL_VoutVideoToolBox_CreateOverlay(int width, int height, SDL_Vout *display)
{
SDLTRACE("SDL_VoutVideoToolBox_CreateOverlay(w=%d, h=%d, fmt=%.4s(0x%x, dp=%p)\n", width, height, (const char*) &format, format, display);
SDLTRACE("SDL_VoutVideoToolBox_CreateOverlay(w=%d, h=%d, fmt=_VTB, dp=%p)\n",
width, height, display);
SDL_VoutOverlay *overlay = SDL_VoutOverlay_CreateInternal(sizeof(SDL_VoutOverlay_Opaque));
if (!overlay) {
ALOGE("overlay allocation failed");
......@@ -164,7 +165,7 @@ SDL_VoutOverlay *SDL_VoutVideoToolBox_CreateOverlay(int width, int height, Uint3
}
SDL_VoutOverlay_Opaque *opaque = overlay->opaque;
overlay->opaque_class = &g_vout_overlay_videotoolbox_class;
overlay->format = format;
overlay->format = SDL_FCC__VTB;
overlay->w = width;
overlay->h = height;
overlay->pitches = opaque->pitches;
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册