Ticket #3604: 0002-avdev-Add-SDL2-output-device.patch

File 0002-avdev-Add-SDL2-output-device.patch, 15.3 KB (added by ethe, 11 years ago)
  • configure

    From baba1e15a6036098e5853ea0d41de18426e50b3f Mon Sep 17 00:00:00 2001
    From: Josh de Kock <josh@itanimul.li>
    Date: Tue, 23 Feb 2016 23:04:53 +0000
    Subject: [PATCH 2/2] avdev: Add SDL2 output device
    
    ---
     configure                |   1 +
     libavdevice/Makefile     |   1 +
     libavdevice/alldevices.c |   1 +
     libavdevice/sdl2.c       | 382 +++++++++++++++++++++++++++++++++++++++++++++++
     4 files changed, 385 insertions(+)
     create mode 100644 libavdevice/sdl2.c
    
    diff --git a/configure b/configure
    index bd65ce4..bcd4881 100755
    a b pulse_outdev_deps="libpulse"  
    27762776qtkit_indev_extralibs="-framework QTKit -framework Foundation -framework QuartzCore"
    27772777qtkit_indev_select="qtkit"
    27782778sdl_outdev_deps="sdl"
     2779sdl2_outdev_deps="sdl2"
    27792780sndio_indev_deps="sndio_h"
    27802781sndio_outdev_deps="sndio_h"
    27812782v4l_indev_deps="linux_videodev_h"
  • libavdevice/Makefile

    diff --git a/libavdevice/Makefile b/libavdevice/Makefile
    index 8394e87..9e503ee 100644
    a b OBJS-$(CONFIG_PULSE_OUTDEV) += pulse_audio_enc.o \  
    3939                                            pulse_audio_common.o
    4040OBJS-$(CONFIG_QTKIT_INDEV)               += qtkit.o
    4141OBJS-$(CONFIG_SDL_OUTDEV)                += sdl.o
     42OBJS-$(CONFIG_SDL2_OUTDEV)               += sdl2.o
    4243OBJS-$(CONFIG_SNDIO_INDEV)               += sndio_dec.o sndio.o
    4344OBJS-$(CONFIG_SNDIO_OUTDEV)              += sndio_enc.o sndio.o
    4445OBJS-$(CONFIG_V4L2_INDEV)                += v4l2.o v4l2-common.o timefilter.o
  • libavdevice/alldevices.c

    diff --git a/libavdevice/alldevices.c b/libavdevice/alldevices.c
    index 26aecf2..c0a9d9a 100644
    a b void avdevice_register_all(void)  
    6464    REGISTER_INOUTDEV(PULSE,            pulse);
    6565    REGISTER_INDEV   (QTKIT,            qtkit);
    6666    REGISTER_OUTDEV  (SDL,              sdl);
     67    REGISTER_OUTDEV  (SDL2,             sdl2);
    6768    REGISTER_INOUTDEV(SNDIO,            sndio);
    6869    REGISTER_INOUTDEV(V4L2,             v4l2);
    6970//    REGISTER_INDEV   (V4L,              v4l
  • new file libavdevice/sdl2.c

    diff --git a/libavdevice/sdl2.c b/libavdevice/sdl2.c
    new file mode 100644
    index 0000000..92d88cf
    - +  
     1/*
     2 * Copyright (c) 2011 Stefano Sabatini
     3 *
     4 * This file is part of FFmpeg.
     5 *
     6 * FFmpeg is free software; you can redistribute it and/or
     7 * modify it under the terms of the GNU Lesser General Public
     8 * License as published by the Free Software Foundation; either
     9 * version 2.1 of the License, or (at your option) any later version.
     10 *
     11 * FFmpeg is distributed in the hope that it will be useful,
     12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
     13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     14 * Lesser General Public License for more details.
     15 *
     16 * You should have received a copy of the GNU Lesser General Public
     17 * License along with FFmpeg; if not, write to the Free Software
     18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
     19 */
     20
     21/**
     22 * @file
     23 * libSDL output device
     24 */
     25
     26#include <SDL.h>
     27#include <SDL_thread.h>
     28
     29#include "libavutil/avstring.h"
     30#include "libavutil/imgutils.h"
     31#include "libavutil/opt.h"
     32#include "libavutil/parseutils.h"
     33#include "libavutil/pixdesc.h"
     34#include "libavutil/time.h"
     35#include "avdevice.h"
     36
     37typedef struct {
     38    AVClass *class;
     39    SDL_Window *window;
     40    SDL_Renderer *renderer;
     41    char *window_title;
     42    int window_width,  window_height;  /**< size of the window */
     43    int window_fullscreen;
     44    int window_borderless;
     45
     46    SDL_Texture *texture;
     47    int texture_fmt;
     48
     49    int sdl_was_already_inited;
     50    SDL_Thread *event_thread;
     51    SDL_mutex *mutex;
     52    SDL_cond *init_cond;
     53    int init_ret; /* return code used to signal initialization errors */
     54    int inited;
     55    int quit;
     56} SDLContext;
     57
     58static const struct sdl_overlay_pix_fmt_entry {
     59    enum AVPixelFormat pix_fmt; int texture_fmt;
     60} sdl_overlay_pix_fmt_map[] = {
     61    { AV_PIX_FMT_RGB8, SDL_PIXELFORMAT_RGB332 },
     62    { AV_PIX_FMT_RGB444, SDL_PIXELFORMAT_RGB444 },
     63    { AV_PIX_FMT_RGB555, SDL_PIXELFORMAT_RGB555 },
     64    { AV_PIX_FMT_BGR555, SDL_PIXELFORMAT_BGR555 },
     65    // { AV_PIX_FMT_NONE, SDL_PIXELFORMAT_ARGB4444 }, // these aren't implemented in FFmpeg
     66    // { AV_PIX_FMT_NONE, SDL_PIXELFORMAT_RGBA4444 }, // but keeping them here in-case they
     67    // { AV_PIX_FMT_NONE, SDL_PIXELFORMAT_ABGR4444 }, // are
     68    // { AV_PIX_FMT_NONE, SDL_PIXELFORMAT_BGRA4444 },
     69    // { AV_PIX_FMT_NONE, SDL_PIXELFORMAT_ARGB1555 },
     70    // { AV_PIX_FMT_NONE, SDL_PIXELFORMAT_RGBA5551 },
     71    // { AV_PIX_FMT_NONE, SDL_PIXELFORMAT_ABGR1555 },
     72    // { AV_PIX_FMT_NONE, SDL_PIXELFORMAT_BGRA5551 },
     73    { AV_PIX_FMT_RGB565, SDL_PIXELFORMAT_RGB565 },
     74    { AV_PIX_FMT_BGR565, SDL_PIXELFORMAT_BGR565 },
     75    { AV_PIX_FMT_RGB24, SDL_PIXELFORMAT_RGB24 },
     76    { AV_PIX_FMT_BGR24, SDL_PIXELFORMAT_BGR24 },
     77    { AV_PIX_FMT_RGB24, SDL_PIXELFORMAT_RGB888 }, // is this right?
     78    { AV_PIX_FMT_RGB0, SDL_PIXELFORMAT_RGBX8888 },
     79    { AV_PIX_FMT_BGR24, SDL_PIXELFORMAT_BGR888 }, // is this right?
     80    { AV_PIX_FMT_BGR0, SDL_PIXELFORMAT_BGRX8888 },
     81    { AV_PIX_FMT_ARGB, SDL_PIXELFORMAT_ARGB8888 },
     82    { AV_PIX_FMT_RGBA, SDL_PIXELFORMAT_RGBA8888 },
     83    { AV_PIX_FMT_ABGR, SDL_PIXELFORMAT_ABGR8888 },
     84    { AV_PIX_FMT_BGRA, SDL_PIXELFORMAT_BGRA8888 },
     85    // { AV_PIX_FMT_NONE, SDL_PIXELFORMAT_ARGB2101010 }, // not implemented
     86    { AV_PIX_FMT_YUV420P, SDL_PIXELFORMAT_IYUV },
     87    { AV_PIX_FMT_YUYV422, SDL_PIXELFORMAT_YUY2 },
     88    { AV_PIX_FMT_UYVY422, SDL_PIXELFORMAT_UYVY },
     89    { AV_PIX_FMT_NONE,    0                },
     90};
     91
     92static int sdl2_write_trailer(AVFormatContext *s)
     93{
     94    SDLContext *sdl = s->priv_data;
     95
     96    sdl->quit = 1;
     97
     98    if (sdl->texture)
     99        SDL_DestroyTexture(sdl->texture);
     100    sdl->texture = NULL;
     101    if (sdl->event_thread)
     102        SDL_WaitThread(sdl->event_thread, NULL);
     103    sdl->event_thread = NULL;
     104    if (sdl->mutex)
     105        SDL_DestroyMutex(sdl->mutex);
     106    sdl->mutex = NULL;
     107    if (sdl->init_cond)
     108        SDL_DestroyCond(sdl->init_cond);
     109    sdl->init_cond = NULL;
     110
     111    if (sdl->renderer)
     112        SDL_DestroyRenderer(sdl->renderer);
     113    sdl->renderer = NULL;
     114
     115    if (sdl->window)
     116        SDL_DestroyWindow(sdl->window);
     117    sdl->window = NULL;
     118
     119    if (!sdl->sdl_was_already_inited)
     120        SDL_Quit();
     121
     122    return 0;
     123}
     124
     125#define SDL_BASE_FLAGS (SDL_SWSURFACE|SDL_WINDOW_RESIZABLE)
     126
     127static int event_thread(void *arg)
     128{
     129    AVFormatContext *s = arg;
     130    SDLContext *sdl = s->priv_data;
     131    int flags = SDL_BASE_FLAGS | (sdl->window_fullscreen ? SDL_WINDOW_FULLSCREEN : 0) |
     132                                 (sdl->window_borderless ? SDL_WINDOW_BORDERLESS : 0);
     133    AVStream *st = s->streams[0];
     134    AVCodecContext *encctx = st->codec;
     135
     136    /* initialization */
     137    if (!sdl->sdl_was_already_inited){
     138        if (SDL_Init(SDL_INIT_VIDEO) != 0) {
     139            av_log(s, AV_LOG_ERROR, "Unable to initialize SDL: %s\n", SDL_GetError());
     140            sdl->init_ret = AVERROR(EINVAL);
     141            goto init_end;
     142        }
     143    }
     144
     145    sdl->window_width = encctx->width;
     146    sdl->window_height = encctx->height;
     147
     148    if (SDL_CreateWindowAndRenderer(sdl->window_width, sdl->window_height,
     149                                    flags, &sdl->window, &sdl->renderer) != 0){
     150        av_log(sdl, AV_LOG_ERROR, "Couldn't create window and renderer: %s\n", SDL_GetError());
     151        sdl->init_ret = AVERROR(EINVAL);
     152        goto init_end;
     153    }
     154
     155    SDL_SetWindowTitle(sdl->window, sdl->window_title);
     156
     157    sdl->texture = SDL_CreateTexture(sdl->renderer, sdl->texture_fmt, SDL_TEXTUREACCESS_STREAMING,
     158                                     sdl->window_width, sdl->window_height);
     159
     160    if (!sdl->texture) {
     161        av_log(sdl, AV_LOG_ERROR, "Unable to set create mode: %s\n", SDL_GetError());
     162        sdl->init_ret = AVERROR(EINVAL);
     163        goto init_end;
     164    }
     165
     166    sdl->init_ret = 0;
     167    av_log(s, AV_LOG_VERBOSE, "w:%d h:%d fmt:%s -> w:%d h:%d\n",
     168           encctx->width, encctx->height, av_get_pix_fmt_name(encctx->pix_fmt),
     169           sdl->window_width, sdl->window_height);
     170
     171init_end:
     172    SDL_LockMutex(sdl->mutex);
     173    sdl->inited = 1;
     174    SDL_UnlockMutex(sdl->mutex);
     175    SDL_CondSignal(sdl->init_cond);
     176
     177    if (sdl->init_ret < 0)
     178        return sdl->init_ret;
     179
     180    /* event loop */
     181    while (!sdl->quit) {
     182        SDL_Event event;
     183        while (SDL_PollEvent(&event)){
     184            switch (event.type) {
     185                case SDL_KEYDOWN:
     186                    switch (event.key.keysym.sym) {
     187                    case SDLK_ESCAPE:
     188                    case SDLK_q:
     189                        sdl->quit = 1;
     190                        break;
     191                    }
     192                    break;
     193                case SDL_QUIT:
     194                    sdl->quit = 1;
     195                    break;
     196
     197                case SDL_WINDOWEVENT_SIZE_CHANGED:
     198                    sdl->window_width  = event.window.data1;
     199                    sdl->window_height = event.window.data2;
     200                    break;
     201
     202                default:
     203                    break;
     204            }
     205        }
     206    }
     207
     208    return 0;
     209}
     210
     211static int sdl2_write_header(AVFormatContext *s)
     212{
     213    SDLContext *sdl = s->priv_data;
     214    AVStream *st = s->streams[0];
     215    AVCodecContext *encctx = st->codec;
     216    int i, ret;
     217
     218    if (!sdl->window_title)
     219        sdl->window_title = av_strdup(s->filename);
     220
     221    if (SDL_WasInit(SDL_INIT_VIDEO)) {
     222        av_log(s, AV_LOG_WARNING,
     223               "SDL video subsystem was already inited, you could have multiple SDL outputs. This may cause unknown behaviour.\n");
     224        sdl->sdl_was_already_inited = 1;
     225    }
     226
     227    if (   s->nb_streams > 1
     228        || encctx->codec_type != AVMEDIA_TYPE_VIDEO
     229        || encctx->codec_id   != AV_CODEC_ID_RAWVIDEO) {
     230        av_log(s, AV_LOG_ERROR, "Only supports one rawvideo stream\n");
     231        ret = AVERROR(EINVAL);
     232        goto fail;
     233    }
     234
     235    for (i = 0; sdl_overlay_pix_fmt_map[i].pix_fmt != AV_PIX_FMT_NONE; i++) {
     236        if (sdl_overlay_pix_fmt_map[i].pix_fmt == encctx->pix_fmt) {
     237            sdl->texture_fmt = sdl_overlay_pix_fmt_map[i].texture_fmt;
     238            break;
     239        }
     240    }
     241
     242    if (!sdl->texture_fmt) {
     243        av_log(s, AV_LOG_ERROR,
     244               "Unsupported pixel format '%s', choose one of yuv420p, yuyv422, uyvy422, BGRA\n",
     245               av_get_pix_fmt_name(encctx->pix_fmt));
     246        ret = AVERROR(EINVAL);
     247        goto fail;
     248    }
     249
     250    sdl->init_cond = SDL_CreateCond();
     251    if (!sdl->init_cond) {
     252        av_log(s, AV_LOG_ERROR, "Could not create SDL condition variable: %s\n", SDL_GetError());
     253        ret = AVERROR_EXTERNAL;
     254        goto fail;
     255    }
     256    sdl->mutex = SDL_CreateMutex();
     257    if (!sdl->mutex) {
     258        av_log(s, AV_LOG_ERROR, "Could not create SDL mutex: %s\n", SDL_GetError());
     259        ret = AVERROR_EXTERNAL;
     260        goto fail;
     261    }
     262    sdl->event_thread = SDL_CreateThread(event_thread, "SDL2 Event Thread",s);
     263    if (!sdl->event_thread) {
     264        av_log(s, AV_LOG_ERROR, "Could not create SDL event thread: %s\n", SDL_GetError());
     265        ret = AVERROR_EXTERNAL;
     266        goto fail;
     267    }
     268
     269    /* wait until the video system has been inited */
     270    SDL_LockMutex(sdl->mutex);
     271    while (!sdl->inited) {
     272        SDL_CondWait(sdl->init_cond, sdl->mutex);
     273    }
     274    SDL_UnlockMutex(sdl->mutex);
     275    if (sdl->init_ret < 0) {
     276        av_log(s, AV_LOG_DEBUG, "sdl->init_ret < 0\n");
     277        ret = sdl->init_ret;
     278        goto fail;
     279    }
     280    SDL_PumpEvents();
     281    return 0;
     282
     283fail:
     284    sdl2_write_trailer(s);
     285    return ret;
     286}
     287
     288static int sdl2_write_packet(AVFormatContext *s, AVPacket *pkt)
     289{
     290    int ret = 0;
     291
     292    SDLContext *sdl = s->priv_data;
     293    AVCodecContext *encctx = s->streams[0]->codec;
     294    uint8_t *data[4];
     295    int linesize[4];
     296
     297    if (sdl->quit) {
     298        sdl2_write_trailer(s);
     299        return AVERROR(EIO);
     300    }
     301
     302    av_image_fill_arrays(data, linesize, pkt->data, encctx->pix_fmt, encctx->width, encctx->height, 1);
     303    SDL_LockMutex(sdl->mutex);
     304    switch (sdl->texture_fmt) {
     305        case SDL_PIXELFORMAT_IYUV:
     306        case SDL_PIXELFORMAT_YUY2:
     307        case SDL_PIXELFORMAT_UYVY:
     308            ret = SDL_UpdateYUVTexture(sdl->texture, NULL,
     309                                       data[0], linesize[0],
     310                                       data[1], linesize[1],
     311                                       data[2], linesize[2]);
     312            break;
     313        case SDL_PIXELFORMAT_RGB332:
     314        case SDL_PIXELFORMAT_RGB444:
     315        case SDL_PIXELFORMAT_RGB555:
     316        case SDL_PIXELFORMAT_BGR555:
     317        // case SDL_PIXELFORMAT_ARGB4444:
     318        // case SDL_PIXELFORMAT_RGBA4444:
     319        // case SDL_PIXELFORMAT_ABGR4444:
     320        // case SDL_PIXELFORMAT_BGRA4444:
     321        // case SDL_PIXELFORMAT_ARGB1555:
     322        // case SDL_PIXELFORMAT_RGBA5551:
     323        // case SDL_PIXELFORMAT_ABGR1555:
     324        // case SDL_PIXELFORMAT_BGRA5551:
     325        case SDL_PIXELFORMAT_RGB565:
     326        case SDL_PIXELFORMAT_BGR565:
     327        case SDL_PIXELFORMAT_RGB24:
     328        case SDL_PIXELFORMAT_BGR24:
     329        case SDL_PIXELFORMAT_RGB888: // is this right?
     330        case SDL_PIXELFORMAT_RGBX8888:
     331        case SDL_PIXELFORMAT_BGR888: // is this right?
     332        case SDL_PIXELFORMAT_BGRX8888:
     333        case SDL_PIXELFORMAT_ARGB8888:
     334        case SDL_PIXELFORMAT_RGBA8888:
     335        case SDL_PIXELFORMAT_ABGR8888:
     336        case SDL_PIXELFORMAT_BGRA8888:
     337        // case SDL_PIXELFORMAT_ARGB2101010:
     338            ret = SDL_UpdateTexture(sdl->texture, NULL, data[0], linesize[0]);
     339            break;
     340        default:
     341            av_log(NULL, AV_LOG_FATAL, "Unsupported pixel format\n");
     342            ret = -1;
     343            break;
     344    }
     345    SDL_RenderClear(sdl->renderer);
     346    SDL_RenderCopy(sdl->renderer, sdl->texture, NULL, NULL);
     347    SDL_RenderPresent(sdl->renderer);
     348    SDL_UnlockMutex(sdl->mutex);
     349    SDL_PumpEvents();
     350    return ret;
     351}
     352
     353#define OFFSET(x) offsetof(SDLContext,x)
     354
     355static const AVOption options[] = {
     356    { "window_title", "set SDL window title",           OFFSET(window_title), AV_OPT_TYPE_STRING, { .str = NULL }, 0, 0, AV_OPT_FLAG_ENCODING_PARAM },
     357    { "window_size",  "set SDL window forced size",     OFFSET(window_width), AV_OPT_TYPE_IMAGE_SIZE, { .str = NULL }, 0, 0, AV_OPT_FLAG_ENCODING_PARAM },
     358    { "window_fullscreen", "set SDL window fullscreen", OFFSET(window_fullscreen), AV_OPT_TYPE_INT, { .i64 = 0 }, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM },
     359    { "window_borderless", "set SDL window border off", OFFSET(window_fullscreen), AV_OPT_TYPE_INT, { .i64 = 0 }, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM },
     360    { NULL },
     361};
     362
     363static const AVClass sdl2_class = {
     364    .class_name = "sdl2 outdev",
     365    .item_name  = av_default_item_name,
     366    .option     = options,
     367    .version    = LIBAVUTIL_VERSION_INT,
     368    .category   = AV_CLASS_CATEGORY_DEVICE_VIDEO_OUTPUT,
     369};
     370
     371AVOutputFormat ff_sdl2_muxer = {
     372    .name           = "sdl2",
     373    .long_name      = NULL_IF_CONFIG_SMALL("SDL2 output device"),
     374    .priv_data_size = sizeof(SDLContext),
     375    .audio_codec    = AV_CODEC_ID_NONE,
     376    .video_codec    = AV_CODEC_ID_RAWVIDEO,
     377    .write_header   = sdl2_write_header,
     378    .write_packet   = sdl2_write_packet,
     379    .write_trailer  = sdl2_write_trailer,
     380    .flags          = AVFMT_NOFILE | AVFMT_VARIABLE_FPS | AVFMT_NOTIMESTAMPS,
     381    .priv_class     = &sdl2_class,
     382};
     383 No newline at end of file