00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00026 #include <SDL.h>
00027 #include "libavutil/avstring.h"
00028 #include "libavutil/opt.h"
00029 #include "libavutil/parseutils.h"
00030 #include "libavutil/pixdesc.h"
00031 #include "avdevice.h"
00032
00033 typedef struct {
00034 AVClass *class;
00035 SDL_Surface *surface;
00036 SDL_Overlay *overlay;
00037 char *window_title;
00038 char *icon_title;
00039 int window_width, window_height;
00040 int overlay_width, overlay_height;
00041 int overlay_fmt;
00042 int sdl_was_already_inited;
00043 } SDLContext;
00044
00045 static const struct sdl_overlay_pix_fmt_entry {
00046 enum PixelFormat pix_fmt; int overlay_fmt;
00047 } sdl_overlay_pix_fmt_map[] = {
00048 { PIX_FMT_YUV420P, SDL_IYUV_OVERLAY },
00049 { PIX_FMT_YUYV422, SDL_YUY2_OVERLAY },
00050 { PIX_FMT_UYVY422, SDL_UYVY_OVERLAY },
00051 { PIX_FMT_NONE, 0 },
00052 };
00053
00054 static int sdl_write_trailer(AVFormatContext *s)
00055 {
00056 SDLContext *sdl = s->priv_data;
00057
00058 av_freep(&sdl->window_title);
00059 av_freep(&sdl->icon_title);
00060
00061 if (sdl->overlay) {
00062 SDL_FreeYUVOverlay(sdl->overlay);
00063 sdl->overlay = NULL;
00064 }
00065 if (!sdl->sdl_was_already_inited)
00066 SDL_Quit();
00067
00068 return 0;
00069 }
00070
00071 static int sdl_write_header(AVFormatContext *s)
00072 {
00073 SDLContext *sdl = s->priv_data;
00074 AVStream *st = s->streams[0];
00075 AVCodecContext *encctx = st->codec;
00076 float sar, dar;
00077 int i, ret;
00078
00079 if (!sdl->window_title)
00080 sdl->window_title = av_strdup(s->filename);
00081 if (!sdl->icon_title)
00082 sdl->icon_title = av_strdup(sdl->window_title);
00083
00084 if (SDL_WasInit(SDL_INIT_VIDEO)) {
00085 av_log(s, AV_LOG_ERROR,
00086 "SDL video subsystem was already inited, aborting.\n");
00087 sdl->sdl_was_already_inited = 1;
00088 ret = AVERROR(EINVAL);
00089 goto fail;
00090 }
00091
00092 if (SDL_Init(SDL_INIT_VIDEO) != 0) {
00093 av_log(s, AV_LOG_ERROR, "Unable to initialize SDL: %s\n", SDL_GetError());
00094 ret = AVERROR(EINVAL);
00095 goto fail;
00096 }
00097
00098 if ( s->nb_streams > 1
00099 || encctx->codec_type != AVMEDIA_TYPE_VIDEO
00100 || encctx->codec_id != CODEC_ID_RAWVIDEO) {
00101 av_log(s, AV_LOG_ERROR, "Only supports one rawvideo stream\n");
00102 ret = AVERROR(EINVAL);
00103 goto fail;
00104 }
00105
00106 for (i = 0; sdl_overlay_pix_fmt_map[i].pix_fmt != PIX_FMT_NONE; i++) {
00107 if (sdl_overlay_pix_fmt_map[i].pix_fmt == encctx->pix_fmt) {
00108 sdl->overlay_fmt = sdl_overlay_pix_fmt_map[i].overlay_fmt;
00109 break;
00110 }
00111 }
00112
00113 if (!sdl->overlay_fmt) {
00114 av_log(s, AV_LOG_ERROR,
00115 "Unsupported pixel format '%s', choose one of yuv420p, yuyv422, or uyvy422.\n",
00116 av_get_pix_fmt_name(encctx->pix_fmt));
00117 ret = AVERROR(EINVAL);
00118 goto fail;
00119 }
00120
00121
00122 sar = st->sample_aspect_ratio.num ? av_q2d(st->sample_aspect_ratio) : 1;
00123 dar = sar * (float)encctx->width / (float)encctx->height;
00124
00125
00126 sdl->overlay_height = encctx->height;
00127 sdl->overlay_width = ((int)rint(sdl->overlay_height * dar));
00128 if (sdl->overlay_width > encctx->width) {
00129 sdl->overlay_width = encctx->width;
00130 sdl->overlay_height = ((int)rint(sdl->overlay_width / dar));
00131 }
00132
00133 if (!sdl->window_width || !sdl->window_height) {
00134 sdl->window_width = sdl->overlay_width;
00135 sdl->window_height = sdl->overlay_height;
00136 }
00137
00138 SDL_WM_SetCaption(sdl->window_title, sdl->icon_title);
00139 sdl->surface = SDL_SetVideoMode(sdl->window_width, sdl->window_height,
00140 24, SDL_SWSURFACE);
00141 if (!sdl->surface) {
00142 av_log(s, AV_LOG_ERROR, "Unable to set video mode: %s\n", SDL_GetError());
00143 ret = AVERROR(EINVAL);
00144 goto fail;
00145 }
00146
00147 sdl->overlay = SDL_CreateYUVOverlay(sdl->overlay_width, sdl->overlay_height,
00148 sdl->overlay_fmt, sdl->surface);
00149 if (!sdl->overlay || sdl->overlay->pitches[0] < sdl->overlay_width) {
00150 av_log(s, AV_LOG_ERROR,
00151 "SDL does not support an overlay with size of %dx%d pixels.\n",
00152 sdl->overlay_width, sdl->overlay_height);
00153 ret = AVERROR(EINVAL);
00154 goto fail;
00155 }
00156
00157 av_log(s, AV_LOG_INFO, "w:%d h:%d fmt:%s sar:%f -> w:%d h:%d\n",
00158 encctx->width, encctx->height, av_get_pix_fmt_name(encctx->pix_fmt), sar,
00159 sdl->window_width, sdl->window_height);
00160 return 0;
00161
00162 fail:
00163 sdl_write_trailer(s);
00164 return ret;
00165 }
00166
00167 static int sdl_write_packet(AVFormatContext *s, AVPacket *pkt)
00168 {
00169 SDLContext *sdl = s->priv_data;
00170 AVCodecContext *encctx = s->streams[0]->codec;
00171 SDL_Rect rect = { 0, 0, sdl->window_width, sdl->window_height };
00172 AVPicture pict;
00173 int i;
00174
00175 avpicture_fill(&pict, pkt->data, encctx->pix_fmt, encctx->width, encctx->height);
00176
00177 SDL_FillRect(sdl->surface, &sdl->surface->clip_rect,
00178 SDL_MapRGB(sdl->surface->format, 0, 0, 0));
00179 SDL_LockYUVOverlay(sdl->overlay);
00180 for (i = 0; i < 3; i++) {
00181 sdl->overlay->pixels [i] = pict.data [i];
00182 sdl->overlay->pitches[i] = pict.linesize[i];
00183 }
00184 SDL_DisplayYUVOverlay(sdl->overlay, &rect);
00185 SDL_UnlockYUVOverlay(sdl->overlay);
00186
00187 SDL_UpdateRect(sdl->surface, 0, 0, sdl->overlay_width, sdl->overlay_height);
00188
00189 return 0;
00190 }
00191
00192 #define OFFSET(x) offsetof(SDLContext,x)
00193
00194 static const AVOption options[] = {
00195 { "window_title", "SDL window title", OFFSET(window_title), AV_OPT_TYPE_STRING, {.str = NULL }, 0, 0, AV_OPT_FLAG_ENCODING_PARAM },
00196 { "icon_title", "SDL iconified window title", OFFSET(icon_title) , AV_OPT_TYPE_STRING, {.str = NULL }, 0, 0, AV_OPT_FLAG_ENCODING_PARAM },
00197 { "window_size", "SDL window forced size", OFFSET(window_width), AV_OPT_TYPE_IMAGE_SIZE,{.str=NULL}, 0, 0, AV_OPT_FLAG_ENCODING_PARAM },
00198 { NULL },
00199 };
00200
00201 static const AVClass sdl_class = {
00202 .class_name = "sdl outdev",
00203 .item_name = av_default_item_name,
00204 .option = options,
00205 .version = LIBAVUTIL_VERSION_INT,
00206 };
00207
00208 AVOutputFormat ff_sdl_muxer = {
00209 .name = "sdl",
00210 .long_name = NULL_IF_CONFIG_SMALL("SDL output device"),
00211 .priv_data_size = sizeof(SDLContext),
00212 .audio_codec = CODEC_ID_NONE,
00213 .video_codec = CODEC_ID_RAWVIDEO,
00214 .write_header = sdl_write_header,
00215 .write_packet = sdl_write_packet,
00216 .write_trailer = sdl_write_trailer,
00217 .flags = AVFMT_NOFILE,
00218 .priv_class = &sdl_class,
00219 };