ijksdl_vout_overlay_ffmpeg.c 8.3 KB
Newer Older
1
/*****************************************************************************
Z
Zhang Rui 已提交
2
 * ijksdl_vout_overlay_ffmpeg.c
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_overlay_ffmpeg.h"
25

Z
Zhang Rui 已提交
26
#include <assert.h>
27 28 29
#include "../ijksdl_stdinc.h"
#include "../ijksdl_mutex.h"
#include "../ijksdl_vout_internal.h"
Z
Zhang Rui 已提交
30
#include "../ijksdl_video.h"
Z
Zhang Rui 已提交
31
#include "ijksdl_inc_ffmpeg.h"
Z
Zhang Rui 已提交
32
#include "ijksdl_image_convert.h"
33 34

typedef struct SDL_VoutOverlay_Opaque {
35 36
    SDL_mutex *mutex;

37
    AVFrame *frame;
38 39 40 41
    AVBufferRef *frame_buffer;
    int planes;

    AVFrame *linked_frame;
42 43 44

    Uint16 pitches[AV_NUM_DATA_POINTERS];
    Uint8 *pixels[AV_NUM_DATA_POINTERS];
Z
Zhang Rui 已提交
45 46

    int no_neon_warned;
47 48 49
} SDL_VoutOverlay_Opaque;

/* Always assume a linesize alignment of 1 here */
Z
Zhang Rui 已提交
50
// TODO: 9 alignment to speed up memcpy when display
51 52 53
static AVFrame *alloc_avframe(SDL_VoutOverlay_Opaque* opaque, enum AVPixelFormat format, int width, int height)
{
    int frame_bytes = avpicture_get_size(format, width, height);
54 55
    AVBufferRef *frame_buffer_ref = av_buffer_alloc(frame_bytes);
    if (!frame_buffer_ref)
56 57
        return NULL;

58
    AVFrame *frame = av_frame_alloc();
59
    if (!frame) {
60
        av_buffer_unref(&frame_buffer_ref);
61 62 63
        return NULL;
    }

64 65 66 67 68 69 70
    AVFrame *linked_frame = av_frame_alloc();
    if (!frame) {
        av_frame_free(&frame);
        av_buffer_unref(&frame_buffer_ref);
        return NULL;
    }

71
    AVPicture *pic = (AVPicture *) frame;
72
    avcodec_get_frame_defaults(frame);
73 74
    avpicture_fill(pic, frame_buffer_ref->data, format, width, height);
    opaque->frame_buffer = frame_buffer_ref;
75
    opaque->linked_frame = linked_frame;
76 77 78 79 80
    return frame;
}

static void overlay_free_l(SDL_VoutOverlay *overlay)
{
Z
Zhang Rui 已提交
81
    ALOGE("SDL_Overlay(ffmpeg): overlay_free_l(%p)", overlay);
82 83 84 85 86 87 88 89
    if (!overlay)
        return;

    SDL_VoutOverlay_Opaque *opaque = overlay->opaque;
    if (!opaque)
        return;

    if (opaque->frame)
90
        av_frame_free(&opaque->frame);
91

92 93 94 95 96
    if (opaque->linked_frame) {
        av_frame_unref(opaque->linked_frame);
        av_frame_free(&opaque->linked_frame);
    }

97 98
    if (opaque->frame_buffer)
        av_buffer_unref(&opaque->frame_buffer);
99

100 101 102
    if (opaque->mutex)
        SDL_DestroyMutex(opaque->mutex);

103 104 105
    SDL_VoutOverlay_FreeInternal(overlay);
}

106
static void overlay_fill(SDL_VoutOverlay *overlay, AVFrame *frame, int planes)
107 108 109 110 111 112 113 114 115 116
{
    AVPicture *pic = (AVPicture *) frame;
    overlay->planes = planes;

    for (int i = 0; i < AV_NUM_DATA_POINTERS; ++i) {
        overlay->pixels[i] = pic->data[i];
        overlay->pitches[i] = pic->linesize[i];
    }
}

117 118 119 120 121 122 123 124 125 126 127 128
static int overlay_lock(SDL_VoutOverlay *overlay)
{
    SDL_VoutOverlay_Opaque *opaque = overlay->opaque;
    return SDL_LockMutex(opaque->mutex);
}

static int overlay_unlock(SDL_VoutOverlay *overlay)
{
    SDL_VoutOverlay_Opaque *opaque = overlay->opaque;
    return SDL_UnlockMutex(opaque->mutex);
}

129
SDL_VoutOverlay *SDL_VoutFFmpeg_CreateOverlay(int width, int height, Uint32 format, SDL_Vout *display)
130
{
131 132
    SDLTRACE("SDL_VoutFFmpeg_CreateOverlay(w=%d, h=%d, fmt=%.4s(0x%x, dp=%p)",
        width, height, (const char*) &format, format, display);
133
    SDL_VoutOverlay *overlay = SDL_VoutOverlay_CreateInternal(sizeof(SDL_VoutOverlay_Opaque));
Z
Zhang Rui 已提交
134
    if (!overlay) {
Z
Zhang Rui 已提交
135
        ALOGE("overlay allocation failed");
136
        return NULL;
Z
Zhang Rui 已提交
137
    }
138 139

    SDL_VoutOverlay_Opaque *opaque = overlay->opaque;
Z
Zhang Rui 已提交
140
    overlay->format = format;
141 142
    overlay->pitches = opaque->pitches;
    overlay->pixels = opaque->pixels;
Z
Zhang Rui 已提交
143 144
    overlay->w = width;
    overlay->h = height;
145

Z
Zhang Rui 已提交
146
    enum AVPixelFormat ff_format = AV_PIX_FMT_NONE;
Z
Zhang Rui 已提交
147
    int buf_width = width;  // must be aligned to 16 bytes pitch for arm-neon image-convert
Z
Zhang Rui 已提交
148
    int buf_height = height;
149
    switch (format) {
150
    case SDL_FCC_YV12: {
Z
Zhang Rui 已提交
151
        ff_format = AV_PIX_FMT_YUV420P;
Z
Zhang Rui 已提交
152
        buf_width = IJKALIGN(width, 16); // 1 bytes per pixel for Y-plane
153
        opaque->planes = 3;
154 155
        break;
    }
Z
Zhang Rui 已提交
156
    case SDL_FCC_RV16: {
Z
Zhang Rui 已提交
157
        ff_format = AV_PIX_FMT_RGB565;
Z
Zhang Rui 已提交
158
        buf_width = IJKALIGN(width, 8); // 2 bytes per pixel
159
        opaque->planes = 1;
160 161
        break;
    }
Z
Zhang Rui 已提交
162
    case SDL_FCC_RV32: {
Z
Zhang Rui 已提交
163
        ff_format = AV_PIX_FMT_0BGR32;
Z
Zhang Rui 已提交
164
        buf_width = IJKALIGN(width, 4); // 4 bytes per pixel
165
        opaque->planes = 1;
166
        break;
167
    }
168
    default:
169
        ALOGE("SDL_VoutFFmpeg_CreateOverlay(...): unknown format %.4s(0x%x)", (char*)&format, format);
Z
Zhang Rui 已提交
170
        goto fail;
171 172
    }

Z
Zhang Rui 已提交
173 174 175 176
    opaque->frame = alloc_avframe(opaque, ff_format, buf_width, buf_height);
    if (!opaque->frame) {
        ALOGE("overlay->opaque->frame allocation failed");
        goto fail;
177
    }
Z
Zhang Rui 已提交
178
    opaque->mutex = SDL_CreateMutex();
179
    overlay_fill(overlay, opaque->frame, opaque->planes);
180

Z
Zhang Rui 已提交
181 182 183
    overlay->free_l = overlay_free_l;
    overlay->lock = overlay_lock;
    overlay->unlock = overlay_unlock;
Z
Zhang Rui 已提交
184

Z
Zhang Rui 已提交
185
    return overlay;
Z
Zhang Rui 已提交
186

Z
Zhang Rui 已提交
187 188 189
    fail:
    overlay_free_l(overlay);
    return NULL;
Z
Zhang Rui 已提交
190
}
Z
Zhang Rui 已提交
191

192 193
int SDL_VoutFFmpeg_ConvertFrame(
    SDL_VoutOverlay *overlay, AVFrame *frame,
Z
Zhang Rui 已提交
194 195 196 197
    struct SwsContext **p_sws_ctx, int sws_flags)
{
    assert(overlay);
    assert(p_sws_ctx);
Z
Zhang Rui 已提交
198
    SDL_VoutOverlay_Opaque *opaque = overlay->opaque;
Z
Zhang Rui 已提交
199 200
    AVPicture dest_pic = { { 0 } };

201 202 203 204 205
    for (int i = 0; i < overlay->planes; ++i) {
        dest_pic.data[i] = overlay->pixels[i];
        dest_pic.linesize[i] = overlay->pitches[i];
    }

206 207 208
    av_frame_unref(opaque->linked_frame);

    int use_linked_frame = 0;
Z
Zhang Rui 已提交
209 210 211
    enum AVPixelFormat dst_format = AV_PIX_FMT_NONE;
    switch (overlay->format) {
    case SDL_FCC_YV12:
212 213 214 215 216 217 218 219 220 221 222 223
        if (frame->format == AV_PIX_FMT_YUV420P || frame->format == AV_PIX_FMT_YUVJ420P) {
            // ALOGE("direct draw frame");
            use_linked_frame = 1;
            av_frame_ref(opaque->linked_frame, frame);
            overlay_fill(overlay, opaque->linked_frame, opaque->planes);
            FFSWAP(Uint8*, overlay->pixels[1], overlay->pixels[2]);
        } else {
            // ALOGE("copy draw frame");
            overlay_fill(overlay, opaque->frame, opaque->planes);
            dest_pic.data[2] = overlay->pixels[1];
            dest_pic.data[1] = overlay->pixels[2];
        }
Z
Zhang Rui 已提交
224 225
        break;
    case SDL_FCC_RV32:
Z
Zhang Rui 已提交
226
        // TODO: 9 android only
227
        overlay_fill(overlay, opaque->frame, opaque->planes);
Z
Zhang Rui 已提交
228 229 230
        dst_format = AV_PIX_FMT_0BGR32;
        break;
    case SDL_FCC_RV16:
Z
Zhang Rui 已提交
231
        // TODO: 9 android only
232
        overlay_fill(overlay, opaque->frame, opaque->planes);
Z
Zhang Rui 已提交
233 234 235 236 237 238 239 240
        dst_format = AV_PIX_FMT_RGB565;
        break;
    default:
        ALOGE("SDL_VoutFFmpeg_ConvertPicture: unexpected overlay format %s(%d)",
            (char*)&overlay->format, overlay->format);
        return -1;
    }

241 242 243
    if (use_linked_frame) {
        // do nothing
    } else if (ijk_image_convert(frame->width, frame->height,
Z
Zhang Rui 已提交
244
        dst_format, dest_pic.data, dest_pic.linesize,
245
        frame->format, (const uint8_t**) frame->data, frame->linesize)) {
Z
Zhang Rui 已提交
246
        *p_sws_ctx = sws_getCachedContext(*p_sws_ctx,
247
            frame->width, frame->height, frame->format, frame->width, frame->height,
Z
Zhang Rui 已提交
248 249 250 251 252 253
            dst_format, sws_flags, NULL, NULL, NULL);
        if (*p_sws_ctx == NULL) {
            ALOGE("sws_getCachedContext failed");
            return -1;
        }

254 255
        sws_scale(*p_sws_ctx, (const uint8_t**) frame->data, frame->linesize,
            0, frame->height, dest_pic.data, dest_pic.linesize);
Z
Zhang Rui 已提交
256 257 258

        if (!opaque->no_neon_warned) {
            opaque->no_neon_warned = 1;
259
            ALOGE("non-neon image convert %s -> %s", av_get_pix_fmt_name(frame->format), av_get_pix_fmt_name(dst_format));
Z
Zhang Rui 已提交
260
        }
Z
Zhang Rui 已提交
261 262
    }

Z
Zhang Rui 已提交
263
    // TODO: 9 draw black if overlay is larger than screen
Z
Zhang Rui 已提交
264 265
    return 0;
}