Add explanatory comments to the #endif part of multiple inclusion guards.
[mplayer/greg.git] / libmpdemux / demux_y4m.c
blob38d74f83c2f8c4bf69a220da2284d0141e196336
1 // Y4M file parser by Rik Snel (using yuv4mpeg*.[ch] from
2 // mjpeg.sourceforge.net) (derived from demux_viv.c)
3 // older YUV4MPEG (used by xawtv) support by Alex Beregszaszi
5 #include <stdio.h>
6 #include <stdlib.h>
7 #include <unistd.h>
8 #include <string.h> /* strtok */
10 #include "config.h"
11 #include "mp_msg.h"
12 #include "help_mp.h"
13 #include "yuv4mpeg.h"
15 //#include "stream/stream.h"
16 #include "demuxer.h"
17 #include "stheader.h"
19 typedef struct {
20 int framenum;
21 y4m_stream_info_t* si;
22 int is_older;
23 } y4m_priv_t;
25 static int y4m_check_file(demuxer_t* demuxer){
26 int orig_pos = stream_tell(demuxer->stream);
27 char buf[10];
28 y4m_priv_t* priv;
30 mp_msg(MSGT_DEMUX, MSGL_V, "Checking for YUV4MPEG2\n");
32 if(stream_read(demuxer->stream, buf, 9)!=9)
33 return 0;
35 buf[9] = 0;
37 if (strncmp("YUV4MPEG2", buf, 9) && strncmp("YUV4MPEG ", buf, 9)) {
38 return 0;
41 demuxer->priv = malloc(sizeof(y4m_priv_t));
42 priv = demuxer->priv;
44 priv->is_older = 0;
46 if (!strncmp("YUV4MPEG ", buf, 9))
48 mp_msg(MSGT_DEMUX, MSGL_V, "Found older YUV4MPEG format (used by xawtv)\n");
49 priv->is_older = 1;
52 mp_msg(MSGT_DEMUX,MSGL_DBG2,"Success: YUV4MPEG2\n");
54 stream_seek(demuxer->stream, orig_pos);
56 return DEMUXER_TYPE_Y4M;
60 // return value:
61 // 0 = EOF or no stream found
62 // 1 = successfully read a packet
63 static int demux_y4m_fill_buffer(demuxer_t *demux, demux_stream_t *dsds) {
64 demux_stream_t *ds=demux->video;
65 demux_packet_t *dp;
66 y4m_priv_t *priv=demux->priv;
67 y4m_frame_info_t fi;
68 unsigned char *buf[3];
69 int err, size;
71 y4m_init_frame_info(&fi);
73 demux->filepos=stream_tell(demux->stream);
75 size = ((sh_video_t*)ds->sh)->disp_w*((sh_video_t*)ds->sh)->disp_h;
77 dp = new_demux_packet(3*size/2);
79 /* swap U and V components */
80 buf[0] = dp->buffer;
81 buf[1] = dp->buffer + 5*size/4;
82 buf[2] = dp->buffer + size;
84 if (priv->is_older)
86 int c;
88 c = stream_read_char(demux->stream); /* F */
89 if (c == -256)
90 return 0; /* EOF */
91 if (c != 'F')
93 mp_msg(MSGT_DEMUX, MSGL_V, "Bad frame at %d\n", (int)stream_tell(demux->stream)-1);
94 return 0;
96 stream_skip(demux->stream, 5); /* RAME\n */
97 stream_read(demux->stream, buf[0], size);
98 stream_read(demux->stream, buf[1], size/4);
99 stream_read(demux->stream, buf[2], size/4);
101 else
103 if ((err=y4m_read_frame(demux->stream, priv->si, &fi, buf)) != Y4M_OK) {
104 mp_msg(MSGT_DEMUX, MSGL_V, "error reading frame %s\n", y4m_strerr(err));
105 return 0;
109 /* This seems to be the right way to calculate the presentation time stamp */
110 dp->pts=(float)priv->framenum/((sh_video_t*)ds->sh)->fps;
111 priv->framenum++;
112 dp->pos=demux->filepos;
113 dp->flags=0;
114 ds_add_packet(ds, dp);
116 return 1;
119 static demuxer_t* demux_open_y4m(demuxer_t* demuxer){
120 y4m_priv_t* priv = demuxer->priv;
121 y4m_ratio_t ratio;
122 sh_video_t* sh=new_sh_video(demuxer,0);
123 int err;
125 priv->framenum = 0;
126 priv->si = malloc(sizeof(y4m_stream_info_t));
128 if (priv->is_older)
130 char buf[4];
131 int frame_rate_code;
133 stream_skip(demuxer->stream, 8); /* YUV4MPEG */
134 stream_skip(demuxer->stream, 1); /* space */
135 stream_read(demuxer->stream, (char *)&buf[0], 3);
136 buf[3] = 0;
137 sh->disp_w = atoi(buf);
138 stream_skip(demuxer->stream, 1); /* space */
139 stream_read(demuxer->stream, (char *)&buf[0], 3);
140 buf[3] = 0;
141 sh->disp_h = atoi(buf);
142 stream_skip(demuxer->stream, 1); /* space */
143 stream_read(demuxer->stream, (char *)&buf[0], 1);
144 buf[1] = 0;
145 frame_rate_code = atoi(buf);
146 stream_skip(demuxer->stream, 1); /* new-line */
148 if (!sh->fps)
150 /* values from xawtv */
151 switch(frame_rate_code)
153 case 1:
154 sh->fps = 23.976f;
155 break;
156 case 2:
157 sh->fps = 24.0f;
158 break;
159 case 3:
160 sh->fps = 25.0f;
161 break;
162 case 4:
163 sh->fps = 29.97f;
164 break;
165 case 5:
166 sh->fps = 30.0f;
167 break;
168 case 6:
169 sh->fps = 50.0f;
170 break;
171 case 7:
172 sh->fps = 59.94f;
173 break;
174 case 8:
175 sh->fps = 60.0f;
176 break;
177 default:
178 sh->fps = 25.0f;
181 sh->frametime = 1.0f/sh->fps;
183 else
185 y4m_init_stream_info(priv->si);
186 if ((err=y4m_read_stream_header(demuxer->stream, priv->si)) != Y4M_OK)
187 mp_msg(MSGT_DEMUXER, MSGL_FATAL, "error parsing YUV4MPEG header: %s\n", y4m_strerr(err));
189 if(!sh->fps) {
190 ratio = y4m_si_get_framerate(priv->si);
191 if (ratio.d != 0)
192 sh->fps=(float)ratio.n/(float)ratio.d;
193 else
194 sh->fps=15.0f;
196 sh->frametime=1.0f/sh->fps;
198 ratio = y4m_si_get_sampleaspect(priv->si);
200 sh->disp_w = y4m_si_get_width(priv->si);
201 sh->disp_h = y4m_si_get_height(priv->si);
203 if (ratio.d != 0 && ratio.n != 0)
204 sh->aspect = (float)(sh->disp_w*ratio.n)/(float)(sh->disp_h*ratio.d);
206 demuxer->seekable = 0;
209 sh->format = mmioFOURCC('Y', 'V', '1', '2');
211 sh->bih=malloc(sizeof(BITMAPINFOHEADER));
212 memset(sh->bih,0,sizeof(BITMAPINFOHEADER));
213 sh->bih->biSize=40;
214 sh->bih->biWidth = sh->disp_w;
215 sh->bih->biHeight = sh->disp_h;
216 sh->bih->biPlanes=3;
217 sh->bih->biBitCount=12;
218 sh->bih->biCompression=sh->format;
219 sh->bih->biSizeImage=sh->bih->biWidth*sh->bih->biHeight*3/2; /* YV12 */
221 demuxer->video->sh=sh;
222 sh->ds=demuxer->video;
223 demuxer->video->id=0;
226 mp_msg(MSGT_DEMUX, MSGL_INFO, "YUV4MPEG2 Video stream %d size: display: %dx%d, codec: %ux%u\n",
227 demuxer->video->id, sh->disp_w, sh->disp_h, sh->bih->biWidth,
228 sh->bih->biHeight);
230 return demuxer;
233 static void demux_seek_y4m(demuxer_t *demuxer, float rel_seek_secs, float audio_delay, int flags) {
234 sh_video_t* sh = demuxer->video->sh;
235 y4m_priv_t* priv = demuxer->priv;
236 int rel_seek_frames = sh->fps*rel_seek_secs;
237 int size = 3*sh->disp_w*sh->disp_h/2;
238 off_t curr_pos = stream_tell(demuxer->stream);
240 if (priv->framenum + rel_seek_frames < 0) rel_seek_frames = -priv->framenum;
242 //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));
243 //printf("framenum=%d, curr_pos=%ld, currpos/(size+6)=%f\n", priv->framenum, curr_pos, (float)curr_pos/(float)(size+6));
244 priv->framenum += rel_seek_frames;
246 if (priv->is_older) {
247 /* Well this is easy: every frame takes up size+6 bytes
248 * in the stream and we may assume that the stream pointer
249 * is always at the beginning of a frame.
250 * framenum is the number of the frame that is about to be
251 * demuxed (counting from ONE (see demux_open_y4m)) */
252 stream_seek(demuxer->stream, curr_pos + rel_seek_frames*(size+6));
253 } else {
254 /* should never come here, because seeking for YUV4MPEG2
255 * is disabled. */
256 mp_msg(MSGT_DEMUX, MSGL_WARN, "Seeking for YUV4MPEG2 not yet implemented!\n");
260 static void demux_close_y4m(demuxer_t *demuxer)
262 y4m_priv_t* priv = demuxer->priv;
264 if(!priv)
265 return;
266 if (!priv->is_older)
267 y4m_fini_stream_info(((y4m_priv_t*)demuxer->priv)->si);
268 free(((y4m_priv_t*)demuxer->priv)->si);
269 free(demuxer->priv);
270 return;
274 demuxer_desc_t demuxer_desc_y4m = {
275 "YUV4MPEG2 demuxer",
276 "y4m",
277 "YUV4MPEG2",
278 "Rik snel",
280 DEMUXER_TYPE_Y4M,
281 1, // safe autodetect
282 y4m_check_file,
283 demux_y4m_fill_buffer,
284 demux_open_y4m,
285 demux_close_y4m,
286 demux_seek_y4m,
287 NULL