annotate ffmpeg/libavdevice/sdl.c @ 13:844d341cf643 tip

Back up before ISMIR
author Yading Song <yading.song@eecs.qmul.ac.uk>
date Thu, 31 Oct 2013 13:17:06 +0000
parents 6840f77b83aa
children
rev   line source
yading@10 1 /*
yading@10 2 * Copyright (c) 2011 Stefano Sabatini
yading@10 3 *
yading@10 4 * This file is part of FFmpeg.
yading@10 5 *
yading@10 6 * FFmpeg is free software; you can redistribute it and/or
yading@10 7 * modify it under the terms of the GNU Lesser General Public
yading@10 8 * License as published by the Free Software Foundation; either
yading@10 9 * version 2.1 of the License, or (at your option) any later version.
yading@10 10 *
yading@10 11 * FFmpeg is distributed in the hope that it will be useful,
yading@10 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
yading@10 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
yading@10 14 * Lesser General Public License for more details.
yading@10 15 *
yading@10 16 * You should have received a copy of the GNU Lesser General Public
yading@10 17 * License along with FFmpeg; if not, write to the Free Software
yading@10 18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
yading@10 19 */
yading@10 20
yading@10 21 /**
yading@10 22 * @file
yading@10 23 * libSDL output device
yading@10 24 */
yading@10 25
yading@10 26 #include <SDL.h>
yading@10 27 #include "libavutil/avstring.h"
yading@10 28 #include "libavutil/opt.h"
yading@10 29 #include "libavutil/parseutils.h"
yading@10 30 #include "libavutil/pixdesc.h"
yading@10 31 #include "avdevice.h"
yading@10 32
yading@10 33 typedef struct {
yading@10 34 AVClass *class;
yading@10 35 SDL_Surface *surface;
yading@10 36 SDL_Overlay *overlay;
yading@10 37 char *window_title;
yading@10 38 char *icon_title;
yading@10 39 int window_width, window_height; /**< size of the window */
yading@10 40 int window_fullscreen;
yading@10 41 int overlay_width, overlay_height; /**< size of the video in the window */
yading@10 42 int overlay_x, overlay_y;
yading@10 43 int overlay_fmt;
yading@10 44 int sdl_was_already_inited;
yading@10 45 } SDLContext;
yading@10 46
yading@10 47 static const struct sdl_overlay_pix_fmt_entry {
yading@10 48 enum AVPixelFormat pix_fmt; int overlay_fmt;
yading@10 49 } sdl_overlay_pix_fmt_map[] = {
yading@10 50 { AV_PIX_FMT_YUV420P, SDL_IYUV_OVERLAY },
yading@10 51 { AV_PIX_FMT_YUYV422, SDL_YUY2_OVERLAY },
yading@10 52 { AV_PIX_FMT_UYVY422, SDL_UYVY_OVERLAY },
yading@10 53 { AV_PIX_FMT_NONE, 0 },
yading@10 54 };
yading@10 55
yading@10 56 static int sdl_write_trailer(AVFormatContext *s)
yading@10 57 {
yading@10 58 SDLContext *sdl = s->priv_data;
yading@10 59
yading@10 60 av_freep(&sdl->window_title);
yading@10 61 av_freep(&sdl->icon_title);
yading@10 62
yading@10 63 if (sdl->overlay) {
yading@10 64 SDL_FreeYUVOverlay(sdl->overlay);
yading@10 65 sdl->overlay = NULL;
yading@10 66 }
yading@10 67 if (!sdl->sdl_was_already_inited)
yading@10 68 SDL_Quit();
yading@10 69
yading@10 70 return 0;
yading@10 71 }
yading@10 72
yading@10 73 static int sdl_write_header(AVFormatContext *s)
yading@10 74 {
yading@10 75 SDLContext *sdl = s->priv_data;
yading@10 76 AVStream *st = s->streams[0];
yading@10 77 AVCodecContext *encctx = st->codec;
yading@10 78 AVRational sar, dar; /* sample and display aspect ratios */
yading@10 79 int i, ret;
yading@10 80 int flags = SDL_SWSURFACE | sdl->window_fullscreen ? SDL_FULLSCREEN : 0;
yading@10 81
yading@10 82 if (!sdl->window_title)
yading@10 83 sdl->window_title = av_strdup(s->filename);
yading@10 84 if (!sdl->icon_title)
yading@10 85 sdl->icon_title = av_strdup(sdl->window_title);
yading@10 86
yading@10 87 if (SDL_WasInit(SDL_INIT_VIDEO)) {
yading@10 88 av_log(s, AV_LOG_ERROR,
yading@10 89 "SDL video subsystem was already inited, aborting\n");
yading@10 90 sdl->sdl_was_already_inited = 1;
yading@10 91 ret = AVERROR(EINVAL);
yading@10 92 goto fail;
yading@10 93 }
yading@10 94
yading@10 95 if (SDL_Init(SDL_INIT_VIDEO) != 0) {
yading@10 96 av_log(s, AV_LOG_ERROR, "Unable to initialize SDL: %s\n", SDL_GetError());
yading@10 97 ret = AVERROR(EINVAL);
yading@10 98 goto fail;
yading@10 99 }
yading@10 100
yading@10 101 if ( s->nb_streams > 1
yading@10 102 || encctx->codec_type != AVMEDIA_TYPE_VIDEO
yading@10 103 || encctx->codec_id != AV_CODEC_ID_RAWVIDEO) {
yading@10 104 av_log(s, AV_LOG_ERROR, "Only supports one rawvideo stream\n");
yading@10 105 ret = AVERROR(EINVAL);
yading@10 106 goto fail;
yading@10 107 }
yading@10 108
yading@10 109 for (i = 0; sdl_overlay_pix_fmt_map[i].pix_fmt != AV_PIX_FMT_NONE; i++) {
yading@10 110 if (sdl_overlay_pix_fmt_map[i].pix_fmt == encctx->pix_fmt) {
yading@10 111 sdl->overlay_fmt = sdl_overlay_pix_fmt_map[i].overlay_fmt;
yading@10 112 break;
yading@10 113 }
yading@10 114 }
yading@10 115
yading@10 116 if (!sdl->overlay_fmt) {
yading@10 117 av_log(s, AV_LOG_ERROR,
yading@10 118 "Unsupported pixel format '%s', choose one of yuv420p, yuyv422, or uyvy422\n",
yading@10 119 av_get_pix_fmt_name(encctx->pix_fmt));
yading@10 120 ret = AVERROR(EINVAL);
yading@10 121 goto fail;
yading@10 122 }
yading@10 123
yading@10 124 /* compute overlay width and height from the codec context information */
yading@10 125 sar = st->sample_aspect_ratio.num ? st->sample_aspect_ratio : (AVRational){ 1, 1 };
yading@10 126 dar = av_mul_q(sar, (AVRational){ encctx->width, encctx->height });
yading@10 127
yading@10 128 /* we suppose the screen has a 1/1 sample aspect ratio */
yading@10 129 if (sdl->window_width && sdl->window_height) {
yading@10 130 /* fit in the window */
yading@10 131 if (av_cmp_q(dar, (AVRational){ sdl->window_width, sdl->window_height }) > 0) {
yading@10 132 /* fit in width */
yading@10 133 sdl->overlay_width = sdl->window_width;
yading@10 134 sdl->overlay_height = av_rescale(sdl->overlay_width, dar.den, dar.num);
yading@10 135 } else {
yading@10 136 /* fit in height */
yading@10 137 sdl->overlay_height = sdl->window_height;
yading@10 138 sdl->overlay_width = av_rescale(sdl->overlay_height, dar.num, dar.den);
yading@10 139 }
yading@10 140 } else {
yading@10 141 if (sar.num > sar.den) {
yading@10 142 sdl->overlay_width = encctx->width;
yading@10 143 sdl->overlay_height = av_rescale(sdl->overlay_width, dar.den, dar.num);
yading@10 144 } else {
yading@10 145 sdl->overlay_height = encctx->height;
yading@10 146 sdl->overlay_width = av_rescale(sdl->overlay_height, dar.num, dar.den);
yading@10 147 }
yading@10 148 sdl->window_width = sdl->overlay_width;
yading@10 149 sdl->window_height = sdl->overlay_height;
yading@10 150 }
yading@10 151 sdl->overlay_x = (sdl->window_width - sdl->overlay_width ) / 2;
yading@10 152 sdl->overlay_y = (sdl->window_height - sdl->overlay_height) / 2;
yading@10 153
yading@10 154 SDL_WM_SetCaption(sdl->window_title, sdl->icon_title);
yading@10 155 sdl->surface = SDL_SetVideoMode(sdl->window_width, sdl->window_height,
yading@10 156 24, flags);
yading@10 157 if (!sdl->surface) {
yading@10 158 av_log(s, AV_LOG_ERROR, "Unable to set video mode: %s\n", SDL_GetError());
yading@10 159 ret = AVERROR(EINVAL);
yading@10 160 goto fail;
yading@10 161 }
yading@10 162
yading@10 163 sdl->overlay = SDL_CreateYUVOverlay(encctx->width, encctx->height,
yading@10 164 sdl->overlay_fmt, sdl->surface);
yading@10 165 if (!sdl->overlay || sdl->overlay->pitches[0] < encctx->width) {
yading@10 166 av_log(s, AV_LOG_ERROR,
yading@10 167 "SDL does not support an overlay with size of %dx%d pixels\n",
yading@10 168 encctx->width, encctx->height);
yading@10 169 ret = AVERROR(EINVAL);
yading@10 170 goto fail;
yading@10 171 }
yading@10 172
yading@10 173 av_log(s, AV_LOG_VERBOSE, "w:%d h:%d fmt:%s sar:%d/%d -> w:%d h:%d\n",
yading@10 174 encctx->width, encctx->height, av_get_pix_fmt_name(encctx->pix_fmt), sar.num, sar.den,
yading@10 175 sdl->overlay_width, sdl->overlay_height);
yading@10 176 return 0;
yading@10 177
yading@10 178 fail:
yading@10 179 sdl_write_trailer(s);
yading@10 180 return ret;
yading@10 181 }
yading@10 182
yading@10 183 static int sdl_write_packet(AVFormatContext *s, AVPacket *pkt)
yading@10 184 {
yading@10 185 SDLContext *sdl = s->priv_data;
yading@10 186 AVCodecContext *encctx = s->streams[0]->codec;
yading@10 187 SDL_Rect rect = { sdl->overlay_x, sdl->overlay_y, sdl->overlay_width, sdl->overlay_height };
yading@10 188 AVPicture pict;
yading@10 189 int i;
yading@10 190
yading@10 191 avpicture_fill(&pict, pkt->data, encctx->pix_fmt, encctx->width, encctx->height);
yading@10 192
yading@10 193 SDL_FillRect(sdl->surface, &sdl->surface->clip_rect,
yading@10 194 SDL_MapRGB(sdl->surface->format, 0, 0, 0));
yading@10 195 SDL_LockYUVOverlay(sdl->overlay);
yading@10 196 for (i = 0; i < 3; i++) {
yading@10 197 sdl->overlay->pixels [i] = pict.data [i];
yading@10 198 sdl->overlay->pitches[i] = pict.linesize[i];
yading@10 199 }
yading@10 200 SDL_DisplayYUVOverlay(sdl->overlay, &rect);
yading@10 201 SDL_UnlockYUVOverlay(sdl->overlay);
yading@10 202
yading@10 203 SDL_UpdateRect(sdl->surface, rect.x, rect.y, rect.w, rect.h);
yading@10 204
yading@10 205 return 0;
yading@10 206 }
yading@10 207
yading@10 208 #define OFFSET(x) offsetof(SDLContext,x)
yading@10 209
yading@10 210 static const AVOption options[] = {
yading@10 211 { "window_title", "set SDL window title", OFFSET(window_title), AV_OPT_TYPE_STRING, {.str = NULL }, 0, 0, AV_OPT_FLAG_ENCODING_PARAM },
yading@10 212 { "icon_title", "set SDL iconified window title", OFFSET(icon_title) , AV_OPT_TYPE_STRING, {.str = NULL }, 0, 0, AV_OPT_FLAG_ENCODING_PARAM },
yading@10 213 { "window_size", "set SDL window forced size", OFFSET(window_width), AV_OPT_TYPE_IMAGE_SIZE,{.str=NULL}, 0, 0, AV_OPT_FLAG_ENCODING_PARAM },
yading@10 214 { "window_fullscreen", "set SDL window fullscreen", OFFSET(window_fullscreen), AV_OPT_TYPE_INT,{.i64=0}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM },
yading@10 215 { NULL },
yading@10 216 };
yading@10 217
yading@10 218 static const AVClass sdl_class = {
yading@10 219 .class_name = "sdl outdev",
yading@10 220 .item_name = av_default_item_name,
yading@10 221 .option = options,
yading@10 222 .version = LIBAVUTIL_VERSION_INT,
yading@10 223 };
yading@10 224
yading@10 225 AVOutputFormat ff_sdl_muxer = {
yading@10 226 .name = "sdl",
yading@10 227 .long_name = NULL_IF_CONFIG_SMALL("SDL output device"),
yading@10 228 .priv_data_size = sizeof(SDLContext),
yading@10 229 .audio_codec = AV_CODEC_ID_NONE,
yading@10 230 .video_codec = AV_CODEC_ID_RAWVIDEO,
yading@10 231 .write_header = sdl_write_header,
yading@10 232 .write_packet = sdl_write_packet,
yading@10 233 .write_trailer = sdl_write_trailer,
yading@10 234 .flags = AVFMT_NOFILE | AVFMT_VARIABLE_FPS | AVFMT_NOTIMESTAMPS,
yading@10 235 .priv_class = &sdl_class,
yading@10 236 };