ijksdl_vout_android_nativewindow.c 8.4 KB
Newer Older
Z
Zhang Rui 已提交
1
/*****************************************************************************
Z
Zhang Rui 已提交
2
 * ijksdl_vout_android_nativewindow.c
Z
Zhang Rui 已提交
3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
 *****************************************************************************
 *
 * copyright (c) 2013 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
 */

Z
Zhang Rui 已提交
24
#include "ijksdl_vout_android_nativewindow.h"
Z
Zhang Rui 已提交
25

Z
Zhang Rui 已提交
26 27
#include <assert.h>
#include <android/native_window.h>
28
#include "ijkutil/ijkutil.h"
Z
Zhang Rui 已提交
29 30 31
#include "ijksdl/ijksdl_ffinc.h"
#include "ijksdl/ijksdl_vout.h"
#include "ijksdl/ijksdl_vout_internal.h"
Z
Zhang Rui 已提交
32 33

typedef struct SDL_VoutSurface_Opaque {
34
    SDL_Vout *vout;
Z
Zhang Rui 已提交
35 36
} SDL_VoutSurface_Opaque;

37 38 39
typedef struct SDL_Vout_Opaque {
    ANativeWindow *native_window;
} SDL_Vout_Opaque;
Z
Zhang Rui 已提交
40

Z
Zhang Rui 已提交
41
static void vout_free_l(SDL_Vout *vout)
Z
Zhang Rui 已提交
42 43 44 45 46 47 48 49 50 51 52 53 54 55
{
    if (!vout)
        return;

    SDL_Vout_Opaque *opaque = vout->opaque;
    if (opaque) {
        if (opaque->native_window) {
            ANativeWindow_release(opaque->native_window);
        }
    }

    SDL_Vout_FreeInternal(vout);
}

Z
Zhang Rui 已提交
56
#if 0
57
static SDL_VoutSurface *vout_set_video_mode_l(SDL_Vout *vout, int w, int h, int bpp, int flags)
Z
Zhang Rui 已提交
58
{
59 60 61 62 63 64
    SDL_Vout_Opaque *opaque = vout->opaque;
    SDL_VoutSurface *surface = &opaque->dummy_surface;
    ANativeWindow *native_window = opaque->native_window;
    int curr_w = 0;
    int curr_h = 0;
    int curr_format = 0;
65 66
    int buf_w = (w + 1) & ~1;
    int buf_h = (h + 1) & ~1;
Z
Zhang Rui 已提交
67

68
    assert(bpp == 0);
69 70
    if (!native_window)
        return NULL;
Z
Zhang Rui 已提交
71

72 73 74
    curr_w = ANativeWindow_getWidth(native_window);
    curr_h = ANativeWindow_getHeight(native_window);
    curr_format = ANativeWindow_getFormat(native_window);
75 76 77
    if (curr_w == buf_w && curr_h == buf_h) {
        surface->w = w;
        surface->h = h;
78 79
        surface->format = curr_format;
        return surface;
Z
Zhang Rui 已提交
80 81
    }

82 83 84 85
    ALOGI("vout_set_video_mode_l (w:%d, h:%d, fmt:%d) => (w:%d, h:%d, fmt:%d)",
        curr_w, curr_h, curr_format,
        buf_w, buf_h, curr_format);
    ANativeWindow_setBuffersGeometry(native_window, buf_w, buf_h, curr_format);
86 87 88
    curr_w = ANativeWindow_getWidth(native_window);
    curr_h = ANativeWindow_getHeight(native_window);
    curr_format = ANativeWindow_getFormat(native_window);
89 90 91
    if (curr_w == buf_w && curr_h == buf_h) {
        surface->w = w;
        surface->h = h;
92 93
        surface->format = curr_format;
        return surface;
Z
Zhang Rui 已提交
94 95
    }

96 97 98
    ALOGE("vout_set_video_mode_l (w:%d, h:%d, fmt:%d) => (w:%d, h:%d, fmt:%d)",
        curr_w, curr_h, curr_format,
        buf_w, buf_h, curr_format);
99 100 101
    return NULL;
}

102
static SDL_VoutSurface *vout_set_video_mode(SDL_Vout *vout, int w, int h, int bpp, Uint32 flags)
103 104
{
    SDL_LockMutex(vout->mutex);
105
    SDL_VoutSurface *surface = vout_set_video_mode_l(vout, w, h, bpp, flags);
106 107
    SDL_UnlockMutex(vout->mutex);
    return surface;
Z
Zhang Rui 已提交
108
}
Z
Zhang Rui 已提交
109
#endif
Z
Zhang Rui 已提交
110

111 112 113 114 115 116 117 118 119 120 121
static void vout_copy_image_yv12(ANativeWindow_Buffer *out_buffer, const SDL_VoutOverlay *overlay)
{
    assert(overlay->format == SDL_YV12_OVERLAY);
    assert(overlay->planes == 3);

    int min_height = IJKMIN(out_buffer->height, overlay->h);
    int dst_y_pitch = out_buffer->stride;
    int dst_c_pitch = IJKALIGN(out_buffer->stride / 2, 16);
    int dst_y_size = dst_y_pitch * out_buffer->height;
    int dst_c_size = dst_c_pitch * out_buffer->height / 2;

Z
Zhang Rui 已提交
122
    uint8_t *dst_pixels_array[] = {
123 124 125 126
        out_buffer->bits,
        out_buffer->bits + dst_y_size,
        out_buffer->bits + dst_y_size + dst_c_size
    };
Z
Zhang Rui 已提交
127
    int dst_plane_size_array[] = { dst_y_size, dst_c_size, dst_c_size };
128 129 130 131 132
    int dst_pitches[] = { dst_y_pitch, dst_c_pitch, dst_c_pitch };

    for (int i = 0; i < 3; ++i) {
        int dst_pitch = dst_pitches[i];
        int src_pitch = overlay->pitches[i];
Z
Zhang Rui 已提交
133
        uint8_t *dst_pixels = dst_pixels_array[i];
134
        const uint8_t *src_pixels = overlay->pixels[i];
Z
Zhang Rui 已提交
135
        int dst_plane_size = dst_plane_size_array[i];
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 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

        if (dst_pitch == src_pitch) {
            memcpy(dst_pixels, src_pixels, dst_plane_size);
        } else {
            int bytewidth = IJKMIN(dst_pitch, src_pitch);
            av_image_copy_plane(dst_pixels, dst_pitch, src_pixels, src_pitch, bytewidth, min_height);
        }
    }
}

static int voud_display_overlay_l(SDL_Vout *vout, SDL_VoutOverlay *overlay)
{
    SDL_Vout_Opaque *opaque = vout->opaque;
    ANativeWindow *native_window = opaque->native_window;
    int curr_w, curr_h, curr_format;
    int retval;

    if (!native_window)
        return -1;

    if (!overlay || overlay->w <= 0 || overlay->h <= 0)
        return -1;

    int buf_w = (overlay->w + 1) & ~1;
    int buf_h = (overlay->h + 1) & ~1;

    curr_w = ANativeWindow_getWidth(native_window);
    curr_h = ANativeWindow_getHeight(native_window);
    curr_format = ANativeWindow_getFormat(native_window);
    if (curr_w != buf_w ||
        curr_h != buf_h ||
        curr_format != overlay->format) {

        // correct w, h, format
        ALOGI("vout_set_video_mode_l (w:%d, h:%d, fmt:%d) => (w:%d, h:%d, fmt:%d)",
            curr_w, curr_h, curr_format,
            buf_w, buf_h, overlay->format);
        ANativeWindow_setBuffersGeometry(native_window, buf_w, buf_h, overlay->format);
        curr_w = ANativeWindow_getWidth(native_window);
        curr_h = ANativeWindow_getHeight(native_window);
        curr_format = ANativeWindow_getFormat(native_window);

        if (curr_w != buf_w ||
            curr_h != buf_h ||
            curr_format != overlay->format) {
            ALOGE("unexpected native window (w:%d, h:%d, fmt:%d), expecting (w:%d, h:%d, fmt:%d)",
                curr_w, curr_h, curr_format,
                buf_w, buf_h, overlay->format);
            return -1;
        }
    }

    ANativeWindow_Buffer out_buffer;
    retval = ANativeWindow_lock(native_window, &out_buffer, NULL);
    if (retval < 0) {
        ALOGE("voud_display_overlay_l: ANativeWindow_lock: failed %d", retval);
        return retval;
    }

    if (out_buffer.width != buf_w || out_buffer.height != buf_w) {
        ALOGE("unexpected native window buffer (w:%d, h:%d, fmt:%d), expecting (w:%d, h:%d, fmt:%d)",
            out_buffer.width, out_buffer.height, out_buffer.format,
            buf_w, buf_h, overlay->format);
        return -1;
    }

    int copy_ret = 0;
    switch (out_buffer.format) {
    case SDL_YV12_OVERLAY:
        vout_copy_image_yv12(&out_buffer, overlay);
        break;
    default:
        ALOGE("voud_display_overlay_l: unexpected buffer format: %d", out_buffer.format);
        copy_ret = -1;
        break;
    }

    retval = ANativeWindow_unlockAndPost(native_window);
    if (retval < 0) {
        ALOGE("voud_display_overlay_l: ANativeWindow_unlockAndPost: failed %d", retval);
        return retval;
    }
    return copy_ret;
}

221 222
static int voud_display_overlay(SDL_Vout *vout, SDL_VoutOverlay *overlay)
{
223 224 225 226
    SDL_LockMutex(vout->mutex);
    int retval = voud_display_overlay_l(vout, overlay);
    SDL_UnlockMutex(vout->mutex);
    return retval;
227 228
}

Z
Zhang Rui 已提交
229
SDL_Vout *SDL_VoutAndroid_CreateForANativeWindow()
Z
Zhang Rui 已提交
230
{
231
    SDL_Vout *vout = SDL_Vout_CreateInternal(sizeof(SDL_Vout_Opaque));
Z
Zhang Rui 已提交
232 233 234
    if (!vout)
        return NULL;

235
    SDL_Vout_Opaque *opaque = vout->opaque;
Z
Zhang Rui 已提交
236
    opaque->native_window = NULL;
237

Z
Zhang Rui 已提交
238
    vout->free_l = vout_free_l;
239
    vout->display_overlay = voud_display_overlay;
Z
Zhang Rui 已提交
240 241 242 243

    return vout;
}

Z
Zhang Rui 已提交
244
static void SDL_VoutAndroid_SetNativeWindow_l(SDL_Vout *vout, ANativeWindow *native_window)
Z
Zhang Rui 已提交
245 246 247 248 249 250 251 252 253
{
    SDL_Vout_Opaque *opaque = vout->opaque;

    if (opaque->native_window == native_window)
        return;

    if (opaque->native_window)
        ANativeWindow_release(opaque->native_window);

254 255 256
    if (native_window)
        ANativeWindow_acquire(native_window);

Z
Zhang Rui 已提交
257 258 259
    opaque->native_window = native_window;
}

Z
Zhang Rui 已提交
260
void SDL_VoutAndroid_SetNativeWindow(SDL_Vout *vout, ANativeWindow *native_window)
Z
Zhang Rui 已提交
261 262 263 264 265
{
    SDL_LockMutex(vout->mutex);
    SDL_VoutAndroid_SetNativeWindow_l(vout, native_window);
    SDL_UnlockMutex(vout->mutex);
}