vo_gl: Make it possible to select GL_NEAREST scaling
[mplayer/glamo.git] / libmpdemux / demux_y4m.c
blob7f390deacc3d593fd01b2d1ff5d92a090172a85f
1 /*
2 * Y4M file parser
3 * copyright (c) 2001 Rik Snel
4 * (using yuv4mpeg*.[ch] from mjpeg.sourceforge.net)
5 * (derived from demux_viv.c)
6 * older YUV4MPEG (used by xawtv) support by Alex Beregszaszi
8 * This file is part of MPlayer.
10 * MPlayer is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
15 * MPlayer is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
20 * You should have received a copy of the GNU General Public License along
21 * with MPlayer; if not, write to the Free Software Foundation, Inc.,
22 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <unistd.h>
28 #include <string.h> /* strtok */
30 #include "config.h"
31 #include "mp_msg.h"
32 #include "yuv4mpeg.h"
34 #include "stream/stream.h"
35 #include "demuxer.h"
36 #include "stheader.h"
38 typedef struct {
39 int framenum;
40 y4m_stream_info_t* si;
41 int is_older;
42 } y4m_priv_t;
44 static int y4m_check_file(demuxer_t* demuxer){
45 int orig_pos = stream_tell(demuxer->stream);
46 char buf[10];
47 y4m_priv_t* priv;
49 mp_msg(MSGT_DEMUX, MSGL_V, "Checking for YUV4MPEG2\n");
51 if(stream_read(demuxer->stream, buf, 9)!=9)
52 return 0;
54 buf[9] = 0;
56 if (strncmp("YUV4MPEG2", buf, 9) && strncmp("YUV4MPEG ", buf, 9)) {
57 return 0;
60 demuxer->priv = malloc(sizeof(y4m_priv_t));
61 priv = demuxer->priv;
63 priv->is_older = 0;
65 if (!strncmp("YUV4MPEG ", buf, 9))
67 mp_msg(MSGT_DEMUX, MSGL_V, "Found older YUV4MPEG format (used by xawtv)\n");
68 priv->is_older = 1;
71 mp_msg(MSGT_DEMUX,MSGL_DBG2,"Success: YUV4MPEG2\n");
73 stream_seek(demuxer->stream, orig_pos);
75 return DEMUXER_TYPE_Y4M;
78 static void read_streaminfo(demuxer_t *demuxer);
80 // return value:
81 // 0 = EOF or no stream found
82 // 1 = successfully read a packet
83 static int demux_y4m_fill_buffer(demuxer_t *demux, demux_stream_t *dsds) {
84 demux_stream_t *ds=demux->video;
85 demux_packet_t *dp;
86 y4m_priv_t *priv=demux->priv;
87 y4m_frame_info_t fi;
88 unsigned char *buf[3];
89 int err, size;
90 int nextc;
92 // Concatenated stream check; only done if seekable so skip(-1) works
93 if (demux->stream->flags & MP_STREAM_SEEK_BW) {
94 nextc = stream_read_char(demux->stream);
95 stream_skip(demux->stream, -1);
96 if (nextc == 'Y') {
97 read_streaminfo(demux);
98 demux->seekable = 0;
102 y4m_init_frame_info(&fi);
104 demux->filepos=stream_tell(demux->stream);
106 size = ((sh_video_t*)ds->sh)->disp_w*((sh_video_t*)ds->sh)->disp_h;
108 dp = new_demux_packet(3*size/2);
110 /* swap U and V components */
111 buf[0] = dp->buffer;
112 buf[1] = dp->buffer + 5*size/4;
113 buf[2] = dp->buffer + size;
115 if (priv->is_older)
117 int c;
119 c = stream_read_char(demux->stream); /* F */
120 if (c == -256)
121 return 0; /* EOF */
122 if (c != 'F')
124 mp_msg(MSGT_DEMUX, MSGL_V, "Bad frame at %d\n", (int)stream_tell(demux->stream)-1);
125 return 0;
127 stream_skip(demux->stream, 5); /* RAME\n */
128 stream_read(demux->stream, buf[0], size);
129 stream_read(demux->stream, buf[1], size/4);
130 stream_read(demux->stream, buf[2], size/4);
132 else
134 if ((err=y4m_read_frame(demux->stream, priv->si, &fi, buf)) != Y4M_OK) {
135 mp_msg(MSGT_DEMUX, MSGL_ERR, "error reading frame %s\n", y4m_strerr(err));
136 return 0;
140 /* This seems to be the right way to calculate the presentation time stamp */
141 dp->pts=(float)priv->framenum/((sh_video_t*)ds->sh)->fps;
142 priv->framenum++;
143 dp->pos=demux->filepos;
144 dp->flags=0;
145 ds_add_packet(ds, dp);
147 return 1;
150 static void read_streaminfo(demuxer_t *demuxer)
152 y4m_priv_t *priv = demuxer->priv;
153 sh_video_t *sh = demuxer->video->sh;
154 y4m_ratio_t ratio;
155 int err;
157 if (priv->is_older)
159 char buf[4];
160 int frame_rate_code;
162 stream_skip(demuxer->stream, 8); /* YUV4MPEG */
163 stream_skip(demuxer->stream, 1); /* space */
164 stream_read(demuxer->stream, (char *)&buf[0], 3);
165 buf[3] = 0;
166 sh->disp_w = atoi(buf);
167 stream_skip(demuxer->stream, 1); /* space */
168 stream_read(demuxer->stream, (char *)&buf[0], 3);
169 buf[3] = 0;
170 sh->disp_h = atoi(buf);
171 stream_skip(demuxer->stream, 1); /* space */
172 stream_read(demuxer->stream, (char *)&buf[0], 1);
173 buf[1] = 0;
174 frame_rate_code = atoi(buf);
175 stream_skip(demuxer->stream, 1); /* new-line */
177 if (!sh->fps)
179 /* values from xawtv */
180 switch(frame_rate_code)
182 case 1:
183 sh->fps = 23.976f;
184 break;
185 case 2:
186 sh->fps = 24.0f;
187 break;
188 case 3:
189 sh->fps = 25.0f;
190 break;
191 case 4:
192 sh->fps = 29.97f;
193 break;
194 case 5:
195 sh->fps = 30.0f;
196 break;
197 case 6:
198 sh->fps = 50.0f;
199 break;
200 case 7:
201 sh->fps = 59.94f;
202 break;
203 case 8:
204 sh->fps = 60.0f;
205 break;
206 default:
207 sh->fps = 25.0f;
210 sh->frametime = 1.0f/sh->fps;
212 else
214 y4m_init_stream_info(priv->si);
215 if ((err=y4m_read_stream_header(demuxer->stream, priv->si)) != Y4M_OK)
216 mp_msg(MSGT_DEMUXER, MSGL_FATAL, "error parsing YUV4MPEG header: %s\n", y4m_strerr(err));
218 if(!sh->fps) {
219 ratio = y4m_si_get_framerate(priv->si);
220 if (ratio.d != 0)
221 sh->fps=(float)ratio.n/(float)ratio.d;
222 else
223 sh->fps=15.0f;
225 sh->frametime=1.0f/sh->fps;
227 ratio = y4m_si_get_sampleaspect(priv->si);
229 sh->disp_w = y4m_si_get_width(priv->si);
230 sh->disp_h = y4m_si_get_height(priv->si);
232 if (ratio.d != 0 && ratio.n != 0)
233 sh->aspect = (float)(sh->disp_w*ratio.n)/(float)(sh->disp_h*ratio.d);
235 demuxer->seekable = 0;
238 sh->format = mmioFOURCC('Y', 'V', '1', '2');
240 sh->bih->biSize=40;
241 sh->bih->biWidth = sh->disp_w;
242 sh->bih->biHeight = sh->disp_h;
243 sh->bih->biPlanes=3;
244 sh->bih->biBitCount=12;
245 sh->bih->biCompression=sh->format;
246 sh->bih->biSizeImage=sh->bih->biWidth*sh->bih->biHeight*3/2; /* YV12 */
248 mp_msg(MSGT_DEMUX, MSGL_INFO, "YUV4MPEG2 Video stream %d size: display: %dx%d, codec: %ux%u\n",
249 demuxer->video->id, sh->disp_w, sh->disp_h, sh->bih->biWidth,
250 sh->bih->biHeight);
253 static demuxer_t* demux_open_y4m(demuxer_t* demuxer){
254 y4m_priv_t* priv = demuxer->priv;
255 sh_video_t* sh=new_sh_video(demuxer,0);
257 priv->framenum = 0;
258 priv->si = malloc(sizeof(y4m_stream_info_t));
260 sh->bih=calloc(1, sizeof(BITMAPINFOHEADER));
262 demuxer->video->sh=sh;
263 sh->ds=demuxer->video;
264 demuxer->video->id=0;
266 read_streaminfo(demuxer);
268 return demuxer;
271 static void demux_seek_y4m(demuxer_t *demuxer, float rel_seek_secs, float audio_delay, int flags) {
272 sh_video_t* sh = demuxer->video->sh;
273 y4m_priv_t* priv = demuxer->priv;
274 int rel_seek_frames = sh->fps*rel_seek_secs;
275 int size = 3*sh->disp_w*sh->disp_h/2;
276 off_t curr_pos = stream_tell(demuxer->stream);
278 if (priv->framenum + rel_seek_frames < 0) rel_seek_frames = -priv->framenum;
280 //printf("seektoframe=%d rel_seek_secs=%f seektooffset=%ld\n", priv->framenum + rel_seek_frames, rel_seek_secs, curr_pos + rel_seek_frames*(size+6));
281 //printf("framenum=%d, curr_pos=%ld, currpos/(size+6)=%f\n", priv->framenum, curr_pos, (float)curr_pos/(float)(size+6));
282 priv->framenum += rel_seek_frames;
284 if (priv->is_older) {
285 /* Well this is easy: every frame takes up size+6 bytes
286 * in the stream and we may assume that the stream pointer
287 * is always at the beginning of a frame.
288 * framenum is the number of the frame that is about to be
289 * demuxed (counting from ONE (see demux_open_y4m)) */
290 stream_seek(demuxer->stream, curr_pos + rel_seek_frames*(size+6));
291 } else {
292 /* should never come here, because seeking for YUV4MPEG2
293 * is disabled. */
294 mp_msg(MSGT_DEMUX, MSGL_WARN, "Seeking for YUV4MPEG2 not yet implemented!\n");
298 static void demux_close_y4m(demuxer_t *demuxer)
300 y4m_priv_t* priv = demuxer->priv;
302 if(!priv)
303 return;
304 if (!priv->is_older)
305 y4m_fini_stream_info(((y4m_priv_t*)demuxer->priv)->si);
306 free(((y4m_priv_t*)demuxer->priv)->si);
307 free(demuxer->priv);
308 return;
312 const demuxer_desc_t demuxer_desc_y4m = {
313 "YUV4MPEG2 demuxer",
314 "y4m",
315 "YUV4MPEG2",
316 "Rik snel",
318 DEMUXER_TYPE_Y4M,
319 1, // safe autodetect
320 y4m_check_file,
321 demux_y4m_fill_buffer,
322 demux_open_y4m,
323 demux_close_y4m,
324 demux_seek_y4m,
325 NULL