sdl.c
Go to the documentation of this file.
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 "libavutil/avstring.h"
28 #include "libavutil/opt.h"
29 #include "libavutil/parseutils.h"
30 #include "libavutil/pixdesc.h"
31 #include "avdevice.h"
32 
33 typedef struct {
34  AVClass *class;
35  SDL_Surface *surface;
36  SDL_Overlay *overlay;
37  char *window_title;
38  char *icon_title;
39  int window_width, window_height; /**< size of the window */
41  int overlay_width, overlay_height; /**< size of the video in the window */
42  int overlay_x, overlay_y;
45 } SDLContext;
46 
47 static const struct sdl_overlay_pix_fmt_entry {
48  enum AVPixelFormat pix_fmt; int overlay_fmt;
50  { AV_PIX_FMT_YUV420P, SDL_IYUV_OVERLAY },
51  { AV_PIX_FMT_YUYV422, SDL_YUY2_OVERLAY },
52  { AV_PIX_FMT_UYVY422, SDL_UYVY_OVERLAY },
53  { AV_PIX_FMT_NONE, 0 },
54 };
55 
57 {
58  SDLContext *sdl = s->priv_data;
59 
60  av_freep(&sdl->window_title);
61  av_freep(&sdl->icon_title);
62 
63  if (sdl->overlay) {
64  SDL_FreeYUVOverlay(sdl->overlay);
65  sdl->overlay = NULL;
66  }
67  if (!sdl->sdl_was_already_inited)
68  SDL_Quit();
69 
70  return 0;
71 }
72 
74 {
75  SDLContext *sdl = s->priv_data;
76  AVStream *st = s->streams[0];
77  AVCodecContext *encctx = st->codec;
78  AVRational sar, dar; /* sample and display aspect ratios */
79  int i, ret;
80  int flags = SDL_SWSURFACE | sdl->window_fullscreen ? SDL_FULLSCREEN : 0;
81 
82  if (!sdl->window_title)
83  sdl->window_title = av_strdup(s->filename);
84  if (!sdl->icon_title)
85  sdl->icon_title = av_strdup(sdl->window_title);
86 
87  if (SDL_WasInit(SDL_INIT_VIDEO)) {
89  "SDL video subsystem was already inited, aborting\n");
90  sdl->sdl_was_already_inited = 1;
91  ret = AVERROR(EINVAL);
92  goto fail;
93  }
94 
95  if (SDL_Init(SDL_INIT_VIDEO) != 0) {
96  av_log(s, AV_LOG_ERROR, "Unable to initialize SDL: %s\n", SDL_GetError());
97  ret = AVERROR(EINVAL);
98  goto fail;
99  }
100 
101  if ( s->nb_streams > 1
102  || encctx->codec_type != AVMEDIA_TYPE_VIDEO
103  || encctx->codec_id != AV_CODEC_ID_RAWVIDEO) {
104  av_log(s, AV_LOG_ERROR, "Only supports one rawvideo stream\n");
105  ret = AVERROR(EINVAL);
106  goto fail;
107  }
108 
109  for (i = 0; sdl_overlay_pix_fmt_map[i].pix_fmt != AV_PIX_FMT_NONE; i++) {
110  if (sdl_overlay_pix_fmt_map[i].pix_fmt == encctx->pix_fmt) {
112  break;
113  }
114  }
115 
116  if (!sdl->overlay_fmt) {
117  av_log(s, AV_LOG_ERROR,
118  "Unsupported pixel format '%s', choose one of yuv420p, yuyv422, or uyvy422\n",
119  av_get_pix_fmt_name(encctx->pix_fmt));
120  ret = AVERROR(EINVAL);
121  goto fail;
122  }
123 
124  /* compute overlay width and height from the codec context information */
125  sar = st->sample_aspect_ratio.num ? st->sample_aspect_ratio : (AVRational){ 1, 1 };
126  dar = av_mul_q(sar, (AVRational){ encctx->width, encctx->height });
127 
128  /* we suppose the screen has a 1/1 sample aspect ratio */
129  if (sdl->window_width && sdl->window_height) {
130  /* fit in the window */
131  if (av_cmp_q(dar, (AVRational){ sdl->window_width, sdl->window_height }) > 0) {
132  /* fit in width */
133  sdl->overlay_width = sdl->window_width;
134  sdl->overlay_height = av_rescale(sdl->overlay_width, dar.den, dar.num);
135  } else {
136  /* fit in height */
137  sdl->overlay_height = sdl->window_height;
138  sdl->overlay_width = av_rescale(sdl->overlay_height, dar.num, dar.den);
139  }
140  } else {
141  if (sar.num > sar.den) {
142  sdl->overlay_width = encctx->width;
143  sdl->overlay_height = av_rescale(sdl->overlay_width, dar.den, dar.num);
144  } else {
145  sdl->overlay_height = encctx->height;
146  sdl->overlay_width = av_rescale(sdl->overlay_height, dar.num, dar.den);
147  }
148  sdl->window_width = sdl->overlay_width;
149  sdl->window_height = sdl->overlay_height;
150  }
151  sdl->overlay_x = (sdl->window_width - sdl->overlay_width ) / 2;
152  sdl->overlay_y = (sdl->window_height - sdl->overlay_height) / 2;
153 
154  SDL_WM_SetCaption(sdl->window_title, sdl->icon_title);
155  sdl->surface = SDL_SetVideoMode(sdl->window_width, sdl->window_height,
156  24, flags);
157  if (!sdl->surface) {
158  av_log(s, AV_LOG_ERROR, "Unable to set video mode: %s\n", SDL_GetError());
159  ret = AVERROR(EINVAL);
160  goto fail;
161  }
162 
163  sdl->overlay = SDL_CreateYUVOverlay(encctx->width, encctx->height,
164  sdl->overlay_fmt, sdl->surface);
165  if (!sdl->overlay || sdl->overlay->pitches[0] < encctx->width) {
166  av_log(s, AV_LOG_ERROR,
167  "SDL does not support an overlay with size of %dx%d pixels\n",
168  encctx->width, encctx->height);
169  ret = AVERROR(EINVAL);
170  goto fail;
171  }
172 
173  av_log(s, AV_LOG_VERBOSE, "w:%d h:%d fmt:%s sar:%d/%d -> w:%d h:%d\n",
174  encctx->width, encctx->height, av_get_pix_fmt_name(encctx->pix_fmt), sar.num, sar.den,
175  sdl->overlay_width, sdl->overlay_height);
176  return 0;
177 
178 fail:
180  return ret;
181 }
182 
184 {
185  SDLContext *sdl = s->priv_data;
186  AVCodecContext *encctx = s->streams[0]->codec;
187  SDL_Rect rect = { sdl->overlay_x, sdl->overlay_y, sdl->overlay_width, sdl->overlay_height };
188  AVPicture pict;
189  int i;
190 
191  avpicture_fill(&pict, pkt->data, encctx->pix_fmt, encctx->width, encctx->height);
192 
193  SDL_FillRect(sdl->surface, &sdl->surface->clip_rect,
194  SDL_MapRGB(sdl->surface->format, 0, 0, 0));
195  SDL_LockYUVOverlay(sdl->overlay);
196  for (i = 0; i < 3; i++) {
197  sdl->overlay->pixels [i] = pict.data [i];
198  sdl->overlay->pitches[i] = pict.linesize[i];
199  }
200  SDL_DisplayYUVOverlay(sdl->overlay, &rect);
201  SDL_UnlockYUVOverlay(sdl->overlay);
202 
203  SDL_UpdateRect(sdl->surface, rect.x, rect.y, rect.w, rect.h);
204 
205  return 0;
206 }
207 
208 #define OFFSET(x) offsetof(SDLContext,x)
209 
210 static const AVOption options[] = {
211  { "window_title", "set SDL window title", OFFSET(window_title), AV_OPT_TYPE_STRING, {.str = NULL }, 0, 0, AV_OPT_FLAG_ENCODING_PARAM },
212  { "icon_title", "set SDL iconified window title", OFFSET(icon_title) , AV_OPT_TYPE_STRING, {.str = NULL }, 0, 0, AV_OPT_FLAG_ENCODING_PARAM },
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 },
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 },
215  { NULL },
216 };
217 
218 static const AVClass sdl_class = {
219  .class_name = "sdl outdev",
220  .item_name = av_default_item_name,
221  .option = options,
222  .version = LIBAVUTIL_VERSION_INT,
223 };
224 
226  .name = "sdl",
227  .long_name = NULL_IF_CONFIG_SMALL("SDL output device"),
228  .priv_data_size = sizeof(SDLContext),
229  .audio_codec = AV_CODEC_ID_NONE,
230  .video_codec = AV_CODEC_ID_RAWVIDEO,
235  .priv_class = &sdl_class,
236 };
packed YUV 4:2:2, 16bpp, Cb Y0 Cr Y1
Definition: pixfmt.h:85
const char * s
Definition: avisynth_c.h:668
Definition: sdl.c:33
int linesize[AV_NUM_DATA_POINTERS]
number of bytes per line
int overlay_fmt
Definition: sdl.c:48
AVOption.
Definition: opt.h:251
av_default_item_name
static int write_packet(AVFormatContext *s, AVPacket *pkt)
AVRational sample_aspect_ratio
sample aspect ratio (0 if unknown)
Definition: avformat.h:709
int num
numerator
Definition: rational.h:44
static int sdl_write_header(AVFormatContext *s)
Definition: sdl.c:73
enum AVPixelFormat pix_fmt
Definition: sdl.c:48
enum AVPixelFormat pix_fmt
Pixel format, see AV_PIX_FMT_xxx.
static int av_cmp_q(AVRational a, AVRational b)
Compare two rationals.
Definition: rational.h:55
four components are given, that&#39;s all.
int avpicture_fill(AVPicture *picture, const uint8_t *ptr, enum AVPixelFormat pix_fmt, int width, int height)
Fill in the AVPicture fields, always assume a linesize alignment of 1.
Definition: avpicture.c:34
SDL_Overlay * overlay
Definition: sdl.c:36
void av_freep(void *arg)
Free a memory block which has been allocated with av_malloc(z)() or av_realloc() and set the pointer ...
Definition: mem.c:198
Format I/O context.
Definition: avformat.h:944
const char * class_name
The name of the class; usually it is the same name as the context structure type to which the AVClass...
Definition: log.h:55
int window_fullscreen
Definition: sdl.c:40
int overlay_width
Definition: sdl.c:41
AVOptions.
uint8_t * data[AV_NUM_DATA_POINTERS]
static AVPacket pkt
Definition: demuxing.c:56
AVStream ** streams
Definition: avformat.h:992
int overlay_y
Definition: sdl.c:42
uint8_t * data
AVRational av_mul_q(AVRational b, AVRational c)
Multiply two rationals.
Definition: rational.c:80
enum AVPixelFormat pix_fmt
Definition: v4l.c:63
static int write_trailer(AVFormatContext *s)
#define AV_OPT_FLAG_ENCODING_PARAM
a generic parameter which can be set by the user for muxing or encoding
Definition: opt.h:281
Main libavdevice API header.
Definition: sdl.c:47
#define NULL_IF_CONFIG_SMALL(x)
Return NULL if CONFIG_SMALL is true, otherwise the argument without modification. ...
void av_log(void *avcl, int level, const char *fmt,...)
Definition: log.c:246
AVCodecContext * codec
Codec context associated with this stream.
Definition: avformat.h:662
unsigned int nb_streams
A list of all streams in the file.
Definition: avformat.h:991
#define AV_LOG_VERBOSE
Definition: log.h:157
struct AVRational AVRational
rational number numerator/denominator
static int sdl_write_trailer(AVFormatContext *s)
Definition: sdl.c:56
char filename[1024]
input or output filename
Definition: avformat.h:994
int64_t av_rescale(int64_t a, int64_t b, int64_t c)
Rescale a 64-bit integer with rounding to nearest.
Definition: mathematics.c:118
char * icon_title
Definition: sdl.c:38
ret
Definition: avfilter.c:821
int width
picture width / height.
const char * name
Definition: avformat.h:378
int sdl_was_already_inited
Definition: sdl.c:44
int window_height
size of the window
Definition: sdl.c:39
LIBAVUTIL_VERSION_INT
Definition: eval.c:55
#define OFFSET(x)
Definition: sdl.c:208
Stream structure.
Definition: avformat.h:643
#define AVFMT_NOTIMESTAMPS
Format does not need / have any timestamps.
Definition: avformat.h:352
int window_width
Definition: sdl.c:39
NULL
Definition: eval.c:55
enum AVMediaType codec_type
enum AVCodecID codec_id
char * av_strdup(const char *s)
Duplicate the string s.
Definition: mem.c:220
main external API structure.
#define AV_LOG_ERROR
Something went wrong and cannot losslessly be recovered.
Definition: log.h:148
packed YUV 4:2:2, 16bpp, Y0 Cb Y1 Cr
Definition: pixfmt.h:69
static const char * window_title
Definition: ffplay.c:274
Describe the class of an AVClass context structure.
Definition: log.h:50
Definition: f_ebur128.c:90
synthesis window for stochastic i
rational number numerator/denominator
Definition: rational.h:43
static int sdl_write_packet(AVFormatContext *s, AVPacket *pkt)
Definition: sdl.c:183
static const struct sdl_overlay_pix_fmt_entry sdl_overlay_pix_fmt_map[]
static const AVOption options[]
Definition: sdl.c:210
offset must point to two consecutive integers
Definition: opt.h:230
int overlay_x
Definition: sdl.c:42
Filter the word “frame” indicates either a video frame or a group of audio as stored in an AVFilterBuffer structure Format for each input and each output the list of supported formats For video that means pixel format For audio that means channel sample they are references to shared objects When the negotiation mechanism computes the intersection of the formats supported at each end of a all references to both lists are replaced with a reference to the intersection And when a single format is eventually chosen for a link amongst the remaining all references to the list are updated That means that if a filter requires that its input and output have the same format amongst a supported all it has to do is use a reference to the same list of formats query_formats can leave some formats unset and return AVERROR(EAGAIN) to cause the negotiation mechanism toagain later.That can be used by filters with complex requirements to use the format negotiated on one link to set the formats supported on another.Buffer references ownership and permissions
misc parsing utilities
static int flags
Definition: cpu.c:23
AVOutputFormat ff_sdl_muxer
Definition: sdl.c:225
planar YUV 4:2:0, 12bpp, (1 Cr & Cb sample per 2x2 Y samples)
Definition: pixfmt.h:68
int overlay_fmt
Definition: sdl.c:43
#define AVFMT_NOFILE
Demuxer will use avio_open, no opened file should be provided by the caller.
Definition: avformat.h:345
int den
denominator
Definition: rational.h:45
#define AVFMT_VARIABLE_FPS
Format allows variable fps.
Definition: avformat.h:355
SDL_Surface * surface
Definition: sdl.c:35
char * window_title
Definition: sdl.c:37
void * priv_data
Format private data.
Definition: avformat.h:964
static void write_header(FFV1Context *f)
Definition: ffv1enc.c:470
int overlay_height
size of the video in the window
Definition: sdl.c:41
static const AVClass sdl_class
Definition: sdl.c:218
const char * av_get_pix_fmt_name(enum AVPixelFormat pix_fmt)
Return the short name for a pixel format, NULL in case pix_fmt is unknown.
Definition: pixdesc.c:1700
AVPixelFormat
Pixel format.
Definition: pixfmt.h:66
This structure stores compressed data.