android_nativewindow.c 9.8 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
/*****************************************************************************
 * android_nativewindow_yv12.c
 *****************************************************************************
 *
 * 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
 */

#include "android_nativewindow.h"

#include <assert.h>
#include <android/native_window.h>
#include "ijkutil/ijkutil.h"
#include "../ijksdl_vout.h"
#include "../ijksdl_vout_internal.h"
31
#include "../ffmpeg/ijksdl_inc_ffmpeg.h"
Z
Zhang Rui 已提交
32
#include "ijksdl_inc_internal_android.h"
33

Z
Zhang Rui 已提交
34 35 36 37 38
#ifdef SDLTRACE
#undef SDLTRACE
#define SDLTRACE(...)
#endif

Z
Zhang Rui 已提交
39
static int android_render_yv12_on_yv12(ANativeWindow_Buffer *out_buffer, const SDL_VoutOverlay *overlay)
40
{
Z
Zhang Rui 已提交
41
    // SDLTRACE("SDL_VoutAndroid: android_render_yv12_on_yv12(%p)", overlay);
Z
Zhang Rui 已提交
42
    assert(overlay->format == SDL_FCC_YV12);
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
    assert(overlay->planes == 3);

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

    // ALOGE("stride:%d/%d, size:%d/%d", dst_y_stride, dst_c_stride, dst_y_size, dst_c_size);

    uint8_t *dst_pixels_array[] = {
        out_buffer->bits,
        out_buffer->bits + dst_y_size,
        out_buffer->bits + dst_y_size + dst_c_size,
    };
    int dst_line_height[] = { min_height, min_height / 2, min_height / 2 };
    int dst_line_size_array[] = { dst_y_stride, dst_c_stride, dst_c_stride };

    for (int i = 0; i < 3; ++i) {
        int dst_line_size = dst_line_size_array[i];
        int src_line_size = overlay->pitches[i];
        int line_height = dst_line_height[i];
        uint8_t *dst_pixels = dst_pixels_array[i];
        const uint8_t *src_pixels = overlay->pixels[i];

        if (dst_line_size == src_line_size) {
69
            int plane_size = src_line_size * line_height;
70

71
            // ALOGE("sdl_image_copy_plane %p %p %d", dst_pixels, src_pixels, dst_plane_size);
72
            memcpy(dst_pixels, src_pixels, plane_size);
73
        } else {
Z
Zhang Rui 已提交
74
            // TODO: 9 padding
75 76
            int bytewidth = IJKMIN(dst_line_size, src_line_size);

77
            // ALOGE("av_image_copy_plane %p %d %p %d %d %d", dst_pixels, dst_line_size, src_pixels, src_line_size, bytewidth, line_height);
78 79 80
            av_image_copy_plane(dst_pixels, dst_line_size, src_pixels, src_line_size, bytewidth, line_height);
        }
    }
Z
Zhang Rui 已提交
81 82

    return 0;
83 84
}

Z
Zhang Rui 已提交
85 86 87 88 89 90 91 92 93 94 95 96 97 98
static int android_render_on_yv12(ANativeWindow_Buffer *out_buffer, const SDL_VoutOverlay *overlay)
{
    assert(out_buffer);
    assert(overlay);

    switch (overlay->format) {
    case SDL_FCC_YV12: {
        return android_render_yv12_on_yv12(out_buffer, overlay);
    }
    }

    return -1;
}

99
static int android_render_rgb_on_rgb(ANativeWindow_Buffer *out_buffer, const SDL_VoutOverlay *overlay, int bpp)
Z
Zhang Rui 已提交
100
{
101
    // SDLTRACE("SDL_VoutAndroid: android_render_rgb_on_rgb(%p)", overlay);
Z
Zhang Rui 已提交
102
    assert(overlay->format == SDL_FCC_RV16);
Z
Zhang Rui 已提交
103 104 105 106 107
    assert(overlay->planes == 1);

    int min_height = IJKMIN(out_buffer->height, overlay->h);
    int dst_stride = out_buffer->stride;
    int src_line_size = overlay->pitches[0];
108
    int dst_line_size = dst_stride * bpp / 8;
Z
Zhang Rui 已提交
109 110 111 112 113 114

    uint8_t *dst_pixels = out_buffer->bits;
    const uint8_t *src_pixels = overlay->pixels[0];

    if (dst_line_size == src_line_size) {
        int plane_size = src_line_size * min_height;
Z
Zhang Rui 已提交
115
        // ALOGE("android_render_rgb_on_rgb (pix-match) %p %p %d", dst_pixels, src_pixels, plane_size);
Z
Zhang Rui 已提交
116 117
        memcpy(dst_pixels, src_pixels, plane_size);
    } else {
Z
Zhang Rui 已提交
118
        // TODO: 9 padding
Z
Zhang Rui 已提交
119 120
        int bytewidth = IJKMIN(dst_line_size, src_line_size);

Z
Zhang Rui 已提交
121
        // ALOGE("android_render_rgb_on_rgb (pix-mismatch) %p %d %p %d %d %d", dst_pixels, dst_line_size, src_pixels, src_line_size, bytewidth, min_height);
Z
Zhang Rui 已提交
122 123 124 125 126 127
        av_image_copy_plane(dst_pixels, dst_line_size, src_pixels, src_line_size, bytewidth, min_height);
    }

    return 0;
}

128 129 130 131 132
static int android_render_rgb565_on_rgb565(ANativeWindow_Buffer *out_buffer, const SDL_VoutOverlay *overlay)
{
    return android_render_rgb_on_rgb(out_buffer, overlay, 16);
}

Z
Zhang Rui 已提交
133 134 135 136 137 138
static int android_render_on_rgb565(ANativeWindow_Buffer *out_buffer, const SDL_VoutOverlay *overlay)
{
    assert(out_buffer);
    assert(overlay);

    switch (overlay->format) {
Z
Zhang Rui 已提交
139
    case SDL_FCC_RV16: {
Z
Zhang Rui 已提交
140 141 142 143 144 145 146
        return android_render_rgb565_on_rgb565(out_buffer, overlay);
    }
    }

    return -1;
}

147 148 149 150 151 152 153 154 155 156 157
static int android_render_rgb32_on_rgb8888(ANativeWindow_Buffer *out_buffer, const SDL_VoutOverlay *overlay)
{
    return android_render_rgb_on_rgb(out_buffer, overlay, 32);
}

static int android_render_on_rgb8888(ANativeWindow_Buffer *out_buffer, const SDL_VoutOverlay *overlay)
{
    assert(out_buffer);
    assert(overlay);

    switch (overlay->format) {
Z
Zhang Rui 已提交
158
    case SDL_FCC_RV32: {
159 160 161 162 163 164 165
        return android_render_rgb32_on_rgb8888(out_buffer, overlay);
    }
    }

    return -1;
}

166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181
typedef struct AndroidHalFourccDescriptor {
    Uint32 fcc_or_hal;
    const char* name;

    int hal_format;

    int (*render)(ANativeWindow_Buffer *native_buffer, const SDL_VoutOverlay *overlay);
} AndroidHalFourccDescriptor;

static AndroidHalFourccDescriptor g_hal_fcc_map[] = {
    // YV12
    { HAL_PIXEL_FORMAT_YV12, "HAL_YV12", HAL_PIXEL_FORMAT_YV12, android_render_on_yv12 },
    { SDL_FCC_YV12, "YV12", HAL_PIXEL_FORMAT_YV12, android_render_on_yv12 },

    // RGB565
    { HAL_PIXEL_FORMAT_RGB_565, "HAL_RGB_565", HAL_PIXEL_FORMAT_RGB_565, android_render_on_rgb565 },
Z
Zhang Rui 已提交
182
    { SDL_FCC_RV16, "RV16", HAL_PIXEL_FORMAT_RGB_565, android_render_on_rgb565 },
183 184 185 186 187

    // RGB8888
    { HAL_PIXEL_FORMAT_RGBX_8888, "HAL_RGBX_8888", HAL_PIXEL_FORMAT_RGBX_8888, android_render_on_rgb8888 },
    { HAL_PIXEL_FORMAT_RGBA_8888, "HAL_RGBA_8888", HAL_PIXEL_FORMAT_RGBA_8888, android_render_on_rgb8888 },
    { HAL_PIXEL_FORMAT_BGRA_8888, "HAL_BGRA_8888", HAL_PIXEL_FORMAT_BGRA_8888, android_render_on_rgb8888 },
Z
Zhang Rui 已提交
188
    { SDL_FCC_RV32, "RV32", HAL_PIXEL_FORMAT_RGBX_8888, android_render_on_rgb8888 },
189 190 191 192 193 194 195 196 197 198 199 200 201
};

AndroidHalFourccDescriptor *native_window_get_desc(int fourcc_or_hal)
{
    for (int i = 0; i < NELEM(g_hal_fcc_map); ++i) {
        AndroidHalFourccDescriptor *desc = &g_hal_fcc_map[i];
        if (desc->fcc_or_hal == fourcc_or_hal)
            return desc;
    }

    return NULL;
}

Z
Zhang Rui 已提交
202
int sdl_native_window_display_l(ANativeWindow *native_window, SDL_VoutOverlay *overlay)
203 204 205 206
{
    int retval;

    if (!native_window) {
Z
Zhang Rui 已提交
207
        ALOGE("sdl_native_window_display_l: NULL native_window");
208 209 210 211
        return -1;
    }

    if (!overlay) {
Z
Zhang Rui 已提交
212
        ALOGE("sdl_native_window_display_l: NULL overlay");
213 214 215 216
        return -1;
    }

    if (overlay->w <= 0 || overlay->h <= 0) {
Z
Zhang Rui 已提交
217
        ALOGE("sdl_native_window_display_l: invalid overlay dimensions(%d, %d)", overlay->w, overlay->h);
218 219 220
        return -1;
    }

221 222
    int curr_w = ANativeWindow_getWidth(native_window);
    int curr_h = ANativeWindow_getHeight(native_window);
Z
Zhang Rui 已提交
223
    int curr_format = ANativeWindow_getFormat(native_window);
224 225 226 227 228 229
    int buff_w = IJKALIGN(overlay->w, 2);
    int buff_h = IJKALIGN(overlay->h, 2);

    AndroidHalFourccDescriptor *voutDesc = native_window_get_desc(curr_format);
    if (!voutDesc) {
        ALOGE("sdl_native_window_display_l: unknown hal format: %d", curr_format);
Z
Zhang Rui 已提交
230
        return -1;
231 232 233 234 235 236 237 238 239
    }

    AndroidHalFourccDescriptor *overlayDesc = native_window_get_desc(overlay->format);
    if (!overlayDesc) {
        ALOGE("sdl_native_window_display_l: unknown overlay format: %d", overlay->format);
        return -1;
    }

    if (voutDesc->hal_format != overlayDesc->hal_format) {
Z
Zhang Rui 已提交
240
        ALOGD("ANativeWindow_setBuffersGeometry: w=%d, h=%d, f=%.4s(0x%x) => w=%d, h=%d, f=%.4s(0x%x)",
241 242 243 244 245 246 247 248
            curr_w, curr_h, (char*) &curr_format, curr_format,
            buff_w, buff_h, (char*) &overlay->format, overlay->format);
        retval = ANativeWindow_setBuffersGeometry(native_window, buff_w, buff_h, overlayDesc->hal_format);
        if (retval < 0) {
            ALOGE("sdl_native_window_display_l: ANativeWindow_setBuffersGeometry: failed %d", retval);
            return retval;
        }
    }
Z
Zhang Rui 已提交
249

250 251 252
    ANativeWindow_Buffer out_buffer;
    retval = ANativeWindow_lock(native_window, &out_buffer, NULL);
    if (retval < 0) {
253
        ALOGE("sdl_native_window_display_l: ANativeWindow_lock: failed %d", retval);
254 255 256
        return retval;
    }

Z
Zhang Rui 已提交
257
    if (out_buffer.width != buff_w || out_buffer.height != buff_h) {
258 259 260
        ALOGE("unexpected native window buffer (%p)(w:%d, h:%d, fmt:'%.4s'0x%x), expecting (w:%d, h:%d, fmt:'%.4s'0x%x)",
            native_window,
            out_buffer.width, out_buffer.height, (char*)&out_buffer.format, out_buffer.format,
Z
Zhang Rui 已提交
261
            buff_w, buff_h, (char*)&overlay->format, overlay->format);
Z
Zhang Rui 已提交
262
        // TODO: 8 set all black
263 264 265 266
        ANativeWindow_unlockAndPost(native_window);
        return -1;
    }

267 268
    int render_ret = voutDesc->render(&out_buffer, overlay);
    if (render_ret < 0) {
Z
Zhang Rui 已提交
269
        // TODO: 8 set all black
270
        // return after unlock image;
Z
Zhang Rui 已提交
271
    }
272 273 274

    retval = ANativeWindow_unlockAndPost(native_window);
    if (retval < 0) {
275
        ALOGE("sdl_native_window_display_l: ANativeWindow_unlockAndPost: failed %d", retval);
276 277
        return retval;
    }
Z
Zhang Rui 已提交
278

279
    return render_ret;
Z
Zhang Rui 已提交
280
}