Ticket #1744: 0002-lavd-sdl-add-event-handler-thread.patch

File 0002-lavd-sdl-add-event-handler-thread.patch, 8.3 KB (added by saste, 5 years ago)
  • doc/outdevs.texi

    From 9a8f091d17c21daebcc1d1f922d1525a7ad891f6 Mon Sep 17 00:00:00 2001
    From: Stefano Sabatini <stefasab@gmail.com>
    Date: Sun, 24 Nov 2013 19:32:59 +0100
    Subject: [PATCH] lavd/sdl: add event handler thread
    
    SDL_Init() is called on the event handler thread, as required by SDL in
    Windows to avoid deadlocks.
    
    Should address ticket #1743 and #1744.
    
    TODO: bump micro
    ---
     doc/outdevs.texi  |  10 ++++
     libavdevice/sdl.c | 154 ++++++++++++++++++++++++++++++++++++++++++++----------
     2 files changed, 137 insertions(+), 27 deletions(-)
    
    diff --git a/doc/outdevs.texi b/doc/outdevs.texi
    index 8038def..6c8422c 100644
    a b Set fullscreen mode when non-zero value is provided. 
    209209Default value is zero.
    210210@end table
    211211
     212@subsection Interactive commands
     213
     214The window created by the device can be controlled through the
     215following interactive commands.
     216
     217@table @key
     218@item q, ESC
     219Quit the device immediately.
     220@end table
     221
    212222@subsection Examples
    213223
    214224The following command shows the @command{ffmpeg} output is an
  • libavdevice/sdl.c

    diff --git a/libavdevice/sdl.c b/libavdevice/sdl.c
    index 0210ad2..91a2143 100644
    a b  
    2424 */
    2525
    2626#include <SDL.h>
     27#include <SDL_thread.h>
     28
    2729#include "libavutil/avstring.h"
    2830#include "libavutil/opt.h"
    2931#include "libavutil/parseutils.h"
    3032#include "libavutil/pixdesc.h"
     33#include "libavutil/time.h"
    3134#include "avdevice.h"
    3235
    3336typedef struct {
    typedef struct { 
    4245    int overlay_x, overlay_y;
    4346    int overlay_fmt;
    4447    int sdl_was_already_inited;
     48    SDL_Thread *event_thread;
     49    SDL_mutex *mutex;
     50    SDL_cond *init_cond;
     51    int init_ret; /* return code used to signal initialization errors */
     52    int inited;
     53    int quit;
    4554} SDLContext;
    4655
    4756static const struct sdl_overlay_pix_fmt_entry {
    static int sdl_write_trailer(AVFormatContext *s) 
    5766{
    5867    SDLContext *sdl = s->priv_data;
    5968
    60     if (sdl->overlay) {
     69    sdl->quit = 1;
     70
     71    if (sdl->overlay)
    6172        SDL_FreeYUVOverlay(sdl->overlay);
    62         sdl->overlay = NULL;
    63     }
     73    if (sdl->event_thread)
     74        SDL_WaitThread(sdl->event_thread, NULL);
     75    if (sdl->mutex)
     76        SDL_DestroyMutex(sdl->mutex);
     77    if (sdl->init_cond)
     78        SDL_DestroyCond(sdl->init_cond);
     79
    6480    if (!sdl->sdl_was_already_inited)
    6581        SDL_Quit();
    6682
    6783    return 0;
    6884}
    6985
     86static int event_thread(void *arg)
     87{
     88    AVFormatContext *s = arg;
     89    SDLContext *sdl = s->priv_data;
     90    int flags = SDL_SWSURFACE | sdl->window_fullscreen ? SDL_FULLSCREEN : 0;
     91    AVStream *st = s->streams[0];
     92    AVCodecContext *encctx = st->codec;
     93
     94    /* initialization */
     95    if (SDL_Init(SDL_INIT_VIDEO) != 0) {
     96        av_log(s, AV_LOG_ERROR, "Unable to initialize SDL: %s\n", SDL_GetError());
     97        sdl->init_ret = AVERROR(EINVAL);
     98        goto init_end;
     99    }
     100
     101    SDL_WM_SetCaption(sdl->window_title, sdl->icon_title);
     102    sdl->surface = SDL_SetVideoMode(sdl->window_width, sdl->window_height,
     103                                    24, flags);
     104    if (!sdl->surface) {
     105        av_log(sdl, AV_LOG_ERROR, "Unable to set video mode: %s\n", SDL_GetError());
     106        sdl->init_ret = AVERROR(EINVAL);
     107        goto init_end;
     108    }
     109
     110    sdl->overlay = SDL_CreateYUVOverlay(encctx->width, encctx->height,
     111                                        sdl->overlay_fmt, sdl->surface);
     112    if (!sdl->overlay || sdl->overlay->pitches[0] < encctx->width) {
     113        av_log(s, AV_LOG_ERROR,
     114               "SDL does not support an overlay with size of %dx%d pixels\n",
     115               encctx->width, encctx->height);
     116        sdl->init_ret = AVERROR(EINVAL);
     117        goto init_end;
     118    }
     119
     120    sdl->init_ret = 0;
     121    av_log(s, AV_LOG_VERBOSE, "w:%d h:%d fmt:%s -> w:%d h:%d\n",
     122           encctx->width, encctx->height, av_get_pix_fmt_name(encctx->pix_fmt),
     123           sdl->overlay_width, sdl->overlay_height);
     124
     125init_end:
     126    SDL_LockMutex(sdl->mutex);
     127    sdl->inited = 1;
     128    SDL_UnlockMutex(sdl->mutex);
     129    SDL_CondSignal(sdl->init_cond);
     130
     131    if (sdl->init_ret < 0)
     132        return sdl->init_ret;
     133
     134    /* event loop */
     135    while (!sdl->quit) {
     136        int ret;
     137        SDL_Event event;
     138        SDL_PumpEvents();
     139        ret = SDL_PeepEvents(&event, 1, SDL_GETEVENT, SDL_ALLEVENTS);
     140        if (ret < 0)
     141            av_log(s, AV_LOG_ERROR, "Error when getting SDL event: %s\n", SDL_GetError());
     142        if (ret <= 0)
     143            continue;
     144
     145        switch (event.type) {
     146        case SDL_KEYDOWN:
     147            switch (event.key.keysym.sym) {
     148            case SDLK_ESCAPE:
     149            case SDLK_q:
     150                sdl->quit = 1;
     151                break;
     152            }
     153            break;
     154        case SDL_QUIT:
     155            sdl->quit = 1;
     156            break;
     157        default:
     158            break;
     159        }
     160    }
     161
     162    return 0;
     163}
     164
    70165static int sdl_write_header(AVFormatContext *s)
    71166{
    72167    SDLContext *sdl = s->priv_data;
    static int sdl_write_header(AVFormatContext *s) 
    74169    AVCodecContext *encctx = st->codec;
    75170    AVRational sar, dar; /* sample and display aspect ratios */
    76171    int i, ret;
    77     int flags = SDL_SWSURFACE | sdl->window_fullscreen ? SDL_FULLSCREEN : 0;
    78172
    79173    if (!sdl->window_title)
    80174        sdl->window_title = av_strdup(s->filename);
    static int sdl_write_header(AVFormatContext *s) 
    89183        goto fail;
    90184    }
    91185
    92     if (SDL_Init(SDL_INIT_VIDEO) != 0) {
    93         av_log(s, AV_LOG_ERROR, "Unable to initialize SDL: %s\n", SDL_GetError());
    94         ret = AVERROR(EINVAL);
    95         goto fail;
    96     }
    97 
    98186    if (   s->nb_streams > 1
    99187        || encctx->codec_type != AVMEDIA_TYPE_VIDEO
    100188        || encctx->codec_id   != AV_CODEC_ID_RAWVIDEO) {
    static int sdl_write_header(AVFormatContext *s) 
    148236    sdl->overlay_x = (sdl->window_width  - sdl->overlay_width ) / 2;
    149237    sdl->overlay_y = (sdl->window_height - sdl->overlay_height) / 2;
    150238
    151     SDL_WM_SetCaption(sdl->window_title, sdl->icon_title);
    152     sdl->surface = SDL_SetVideoMode(sdl->window_width, sdl->window_height,
    153                                     24, flags);
    154     if (!sdl->surface) {
    155         av_log(s, AV_LOG_ERROR, "Unable to set video mode: %s\n", SDL_GetError());
    156         ret = AVERROR(EINVAL);
     239    sdl->init_cond = SDL_CreateCond();
     240    if (!sdl->init_cond) {
     241        av_log(s, AV_LOG_ERROR, "Could not create SDL condition variable: %s\n", SDL_GetError());
     242        ret = AVERROR_EXTERNAL;
    157243        goto fail;
    158244    }
    159 
    160     sdl->overlay = SDL_CreateYUVOverlay(encctx->width, encctx->height,
    161                                         sdl->overlay_fmt, sdl->surface);
    162     if (!sdl->overlay || sdl->overlay->pitches[0] < encctx->width) {
    163         av_log(s, AV_LOG_ERROR,
    164                "SDL does not support an overlay with size of %dx%d pixels\n",
    165                encctx->width, encctx->height);
    166         ret = AVERROR(EINVAL);
     245    sdl->mutex = SDL_CreateMutex();
     246    if (!sdl->mutex) {
     247        av_log(s, AV_LOG_ERROR, "Could not create SDL mutex: %s\n", SDL_GetError());
     248        ret = AVERROR_EXTERNAL;
     249        goto fail;
     250    }
     251    sdl->event_thread = SDL_CreateThread(event_thread, s);
     252    if (!sdl->event_thread) {
     253        av_log(s, AV_LOG_ERROR, "Could not create SDL event thread: %s\n", SDL_GetError());
     254        ret = AVERROR_EXTERNAL;
    167255        goto fail;
    168256    }
    169257
    170     av_log(s, AV_LOG_VERBOSE, "w:%d h:%d fmt:%s sar:%d/%d -> w:%d h:%d\n",
    171            encctx->width, encctx->height, av_get_pix_fmt_name(encctx->pix_fmt), sar.num, sar.den,
    172            sdl->overlay_width, sdl->overlay_height);
     258    /* wait until the video system has been inited */
     259    SDL_LockMutex(sdl->mutex);
     260    if (!sdl->inited) {
     261        SDL_CondWait(sdl->init_cond, sdl->mutex);
     262    }
     263    SDL_UnlockMutex(sdl->mutex);
     264    if (sdl->init_ret < 0) {
     265        ret = sdl->init_ret;
     266        goto fail;
     267    }
    173268    return 0;
    174269
    175270fail:
    static int sdl_write_packet(AVFormatContext *s, AVPacket *pkt) 
    185280    AVPicture pict;
    186281    int i;
    187282
     283    if (sdl->quit)
     284        return AVERROR(EIO);
    188285    avpicture_fill(&pict, pkt->data, encctx->pix_fmt, encctx->width, encctx->height);
    189286
     287    SDL_LockMutex(sdl->mutex);
    190288    SDL_FillRect(sdl->surface, &sdl->surface->clip_rect,
    191289                 SDL_MapRGB(sdl->surface->format, 0, 0, 0));
     290    SDL_UnlockMutex(sdl->mutex);
     291
    192292    SDL_LockYUVOverlay(sdl->overlay);
    193293    for (i = 0; i < 3; i++) {
    194294        sdl->overlay->pixels [i] = pict.data    [i];