]> git.sesse.net Git - vlc/blob - modules/video_output/yuv.c
Updated xcb to use new VOUT_DISPLAY_CHANGE_DISPLAY_SIZE parameter.
[vlc] / modules / video_output / yuv.c
1 /*****************************************************************************
2  * yuv.c : yuv video output
3  *****************************************************************************
4  * Copyright (C) 2008, M2X BV
5  * $Id$
6  *
7  * Authors: Jean-Paul Saman <jpsaman@videolan.org>
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
22  *****************************************************************************/
23
24 /*****************************************************************************
25  * Preamble
26  *****************************************************************************/
27
28 #ifdef HAVE_CONFIG_H
29 # include "config.h"
30 #endif
31
32 #include <vlc_common.h>
33 #include <vlc_plugin.h>
34 #include <vlc_vout_display.h>
35 #include <vlc_picture_pool.h>
36 #include <vlc_charset.h>
37
38 /*****************************************************************************
39  * Module descriptor
40  *****************************************************************************/
41 #define YUV_FILE_TEXT N_("device, fifo or filename")
42 #define YUV_FILE_LONGTEXT N_("device, fifo or filename to write yuv frames too.")
43
44 #define CHROMA_TEXT N_("Chroma used.")
45 #define CHROMA_LONGTEXT N_(\
46     "Force use of a specific chroma for output. Default is I420.")
47
48 #define YUV4MPEG2_TEXT N_("YUV4MPEG2 header (default disabled)")
49 #define YUV4MPEG2_LONGTEXT N_("The YUV4MPEG2 header is compatible " \
50     "with mplayer yuv video ouput and requires YV12/I420 fourcc. By default "\
51     "vlc writes the fourcc of the picture frame into the output destination.")
52
53 #define CFG_PREFIX "yuv-"
54
55 static int  Open (vlc_object_t *);
56 static void Close(vlc_object_t *);
57
58 vlc_module_begin()
59     set_shortname(N_("YUV output"))
60     set_description(N_("YUV video output"))
61     set_category(CAT_VIDEO)
62     set_subcategory(SUBCAT_VIDEO_VOUT)
63     set_capability("vout display", 0)
64
65     add_string(CFG_PREFIX "file", "stream.yuv", NULL,
66                 YUV_FILE_TEXT, YUV_FILE_LONGTEXT, false)
67     add_string(CFG_PREFIX "chroma", NULL, NULL,
68                 CHROMA_TEXT, CHROMA_LONGTEXT, true)
69     add_bool  (CFG_PREFIX "yuv4mpeg2", false, NULL,
70                 YUV4MPEG2_TEXT, YUV4MPEG2_LONGTEXT, true)
71
72     set_callbacks(Open, Close)
73 vlc_module_end()
74
75 /*****************************************************************************
76  * Local prototypes
77  *****************************************************************************/
78 static const char *const ppsz_vout_options[] = {
79     "file", "chroma", "yuv4mpeg2", NULL
80 };
81
82 /* */
83 static picture_t *Get    (vout_display_t *);
84 static void       Display(vout_display_t *, picture_t *);
85 static int        Control(vout_display_t *, int, va_list);
86 static void       Manage (vout_display_t *);
87
88 /*****************************************************************************
89  * vout_display_sys_t: video output descriptor
90  *****************************************************************************/
91 struct vout_display_sys_t {
92     FILE *f;
93     bool  is_first;
94     bool  is_yuv4mpeg2;
95     bool  use_dr;
96
97     picture_pool_t *pool;
98 };
99
100 /* */
101 static int Open(vlc_object_t *object)
102 {
103     vout_display_t *vd = (vout_display_t *)object;
104     vout_display_sys_t *sys;
105
106     /* Allocate instance and initialize some members */
107     vd->sys = sys = malloc(sizeof(*sys));
108     if (!sys)
109         return VLC_ENOMEM;
110
111     sys->is_first = false;
112     sys->is_yuv4mpeg2 = var_CreateGetBool(vd, CFG_PREFIX "yuv4mpeg2");
113     sys->pool = NULL;
114
115     /* */
116     char *psz_fcc = var_CreateGetNonEmptyString(vd, CFG_PREFIX "chroma");
117     const vlc_fourcc_t requested_chroma = vlc_fourcc_GetCodecFromString(VIDEO_ES,
118                                                                         psz_fcc);
119     free(psz_fcc);
120
121     const vlc_fourcc_t chroma = requested_chroma ? requested_chroma :
122                                                    VLC_CODEC_I420;
123     if (sys->is_yuv4mpeg2) {
124         switch (chroma) {
125         case VLC_CODEC_YV12:
126         case VLC_CODEC_I420:
127         case VLC_CODEC_J420:
128             break;
129         default:
130             msg_Err(vd, "YUV4MPEG2 mode needs chroma YV12 not %4.4s as requested",
131                     (char *)&chroma);
132             free(sys);
133             return VLC_EGENERIC;
134         }
135     }
136     sys->use_dr = chroma == vd->fmt.i_chroma;
137     msg_Dbg(vd, "Using chroma %4.4s", (char *)&chroma);
138
139     /* */
140     char *name = var_CreateGetNonEmptyString(vd, CFG_PREFIX "file");
141     if (!name) {
142         msg_Err(vd, "Empty file name");
143         free(sys);
144         return VLC_EGENERIC;
145     }
146     sys->f = utf8_fopen(name, "wb");
147
148     if (!sys->f) {
149         msg_Err(vd, "Failed to open %s", name);
150         free(name);
151         free(sys);
152         return VLC_EGENERIC;
153     }
154     msg_Dbg(vd, "Writing data to %s", name);
155     free(name);
156
157     /* */
158     video_format_t fmt = vd->fmt;
159     fmt.i_chroma = chroma;
160     video_format_FixRgb(&fmt);
161
162     /* */
163     vout_display_info_t info = vd->info;
164     info.has_hide_mouse = true;
165
166     /* */
167     vd->fmt     = fmt;
168     vd->info    = info;
169     vd->get     = Get;
170     vd->prepare = NULL;
171     vd->display = Display;
172     vd->control = Control;
173     vd->manage  = Manage;
174
175     vout_display_SendEventFullscreen(vd, false);
176     return VLC_SUCCESS;
177 }
178
179 /* */
180 static void Close(vlc_object_t *object)
181 {
182     vout_display_t *vd = (vout_display_t *)object;
183     vout_display_sys_t *sys = vd->sys;
184
185     if (sys->pool)
186         picture_pool_Delete(sys->pool);
187     fclose(sys->f);
188     free(sys);
189 }
190
191 /*****************************************************************************
192  *
193  *****************************************************************************/
194 static picture_t *Get(vout_display_t *vd)
195 {
196     vout_display_sys_t *sys = vd->sys;
197     if (!sys->pool) {
198         sys->pool = picture_pool_NewFromFormat(&vd->fmt, sys->use_dr ? VOUT_MAX_PICTURES : 1);
199         if (!sys->pool)
200             return NULL;
201     }
202     return picture_pool_Get(sys->pool);
203 }
204
205 static void Display(vout_display_t *vd, picture_t *picture)
206 {
207     vout_display_sys_t *sys = vd->sys;
208
209     /* */
210     video_format_t fmt = vd->fmt;
211     fmt.i_sar_num = vd->source.i_sar_num;
212     fmt.i_sar_den = vd->source.i_sar_den;
213
214     /* */
215     char type;
216     if (picture->b_progressive)
217         type = 'p';
218     else if (picture->b_top_field_first)
219         type = 't';
220     else
221         type = 'b';
222
223     if (type != 'p') {
224         msg_Warn(vd, "Received a non progressive frame, "
225                      "it will be written as progressive.");
226         type = 'p';
227     }
228
229     /* */
230     if (!sys->is_first) {
231         const char *header;
232         char buffer[5];
233         if (sys->is_yuv4mpeg2) {
234             /* MPlayer compatible header, unfortunately it doesn't tell you
235              * the exact fourcc used. */
236             header = "YUV4MPEG2";
237         } else {
238             snprintf(buffer, sizeof(buffer), "%4.4s", 
239                      (const char*)&fmt.i_chroma);
240             header = buffer;
241         }
242
243         fprintf(sys->f, "%s W%d H%d F%d:%d I%c A%d:%d\n",
244                 header,
245                 fmt.i_visible_width, fmt.i_visible_height,
246                 fmt.i_frame_rate, fmt.i_frame_rate_base,
247                 type,
248                 fmt.i_sar_num, fmt.i_sar_den);
249         sys->is_first = true;
250     }
251
252     /* */
253     fprintf(sys->f, "FRAME\n");
254     for (int i = 0; i < picture->i_planes; i++) {
255         const plane_t *plane = &picture->p[i];
256         for( int y = 0; y < plane->i_visible_lines; y++) {
257             const size_t written = fwrite(&plane->p_pixels[y*plane->i_pitch],
258                                           1, plane->i_visible_pitch, sys->f);
259             if (written != (size_t)plane->i_visible_pitch)
260                 msg_Warn(vd, "only %zd of %d bytes written",
261                          written, plane->i_visible_pitch);
262         }
263     }
264     fflush(sys->f);
265
266     /* */
267     picture_Release(picture);
268 }
269
270 static int Control(vout_display_t *vd, int query, va_list args)
271 {
272     VLC_UNUSED(vd);
273     switch (query) {
274     case VOUT_DISPLAY_CHANGE_FULLSCREEN: {
275         const vout_display_cfg_t *cfg = va_arg(args, const vout_display_cfg_t *);
276         if (cfg->is_fullscreen)
277             return VLC_EGENERIC;
278         return VLC_SUCCESS;
279     }
280     default:
281         return VLC_EGENERIC;
282     }
283 }
284 static void Manage (vout_display_t *vd)
285 {
286     VLC_UNUSED(vd);
287 }
288