Mercurial > mplayer.hg
annotate libmpdemux/demux_nsv.c @ 27319:09cf111f68b8
Revert to previous dependency checking behavior.
Take included header files into account when generating dependency files.
This has problems when header files are removed or renamed, but does not
silently miscompile files.
author | diego |
---|---|
date | Sat, 26 Jul 2008 18:36:48 +0000 |
parents | c8a489c8cae8 |
children | d643e4643313 |
rev | line source |
---|---|
12175 | 1 |
2 /* | |
3 * Nullsoft Streaming Video demuxer | |
4 * for MPlayer | |
5 * by Reza Jelveh <reza.jelveh@tuhh.de> | |
6 * seeking and PCM audio not yet supported | |
7 * PCM needs extra audio chunk "miniheader" parsing | |
12181
12ddc64011fe
Add license, remove bogus comment as told by Reza Jelveh, the author.
diego
parents:
12179
diff
changeset
|
8 * Based on A'rpis G2 work |
12ddc64011fe
Add license, remove bogus comment as told by Reza Jelveh, the author.
diego
parents:
12179
diff
changeset
|
9 * Licence: GPL |
12175 | 10 */ |
11 | |
12 #include <stdio.h> | |
13 #include <stdlib.h> | |
14 #include <unistd.h> | |
15 | |
16 #include "config.h" | |
17 #include "mp_msg.h" | |
18 #include "help_mp.h" | |
22605
4d81dbdf46b9
Add explicit location for headers from the stream/ directory.
diego
parents:
20473
diff
changeset
|
19 #include "stream/stream.h" |
12175 | 20 #include "demuxer.h" |
21 #include "stheader.h" | |
22 | |
23 typedef struct { | |
24 float v_pts; | |
25 int video_pack_no; | |
26 unsigned int a_format; | |
27 unsigned int v_format; | |
28 unsigned char fps; | |
29 } nsv_priv_t; | |
30 | |
18251
fdb789f1a99a
Increase HEADER_SEARCH_SIZE, fixes high-bitrate streams from demoscene.tv.
diego
parents:
17636
diff
changeset
|
31 #define HEADER_SEARCH_SIZE 256000 |
16318 | 32 |
33 | |
12175 | 34 /** |
35 * Seeking still to be implemented | |
36 */ | |
17636 | 37 static void demux_seek_nsv ( demuxer_t *demuxer, float rel_seek_secs, float audio_delay, int flags ) |
12175 | 38 { |
39 // seeking is not yet implemented | |
40 } | |
41 | |
42 | |
16175 | 43 static int demux_nsv_fill_buffer ( demuxer_t *demuxer, demux_stream_t *ds ) |
12175 | 44 { |
45 unsigned char hdr[17]; | |
46 // for the extra data | |
47 unsigned char aux[6]; | |
48 int i_aux = 0; | |
49 // videolen = audio chunk length, audiolen = video chunk length | |
50 int videolen,audiolen; | |
51 | |
12272 | 52 sh_video_t *sh_video = demuxer->video->sh; |
53 sh_audio_t *sh_audio = demuxer->audio->sh; | |
12175 | 54 |
55 nsv_priv_t * priv = demuxer->priv; | |
56 | |
57 // if the audio/video chunk has no new header the first 2 bytes will be discarded 0xBEEF | |
58 // or rather 0xEF 0xBE | |
59 stream_read(demuxer->stream,hdr,7); | |
60 if(stream_eof(demuxer->stream)) return 0; | |
61 // sometimes instead of 0xBEEF as described for the next audio/video chunk we get | |
62 // a whole new header | |
63 | |
64 mp_dbg(MSGT_DEMUX,MSGL_DBG2,"demux_nsv: %08X %08X\n",hdr[0]<<8|hdr[1],stream_tell(demuxer->stream)); | |
65 switch(hdr[0]<<8|hdr[1]) { | |
66 case 0x4E53: | |
67 if(hdr[2]==0x56 && hdr[3]==0x73){ | |
68 // NSVs | |
69 // get the header since there is no more metaheader after the first one | |
70 // there is no more need to skip that | |
71 stream_read(demuxer->stream,hdr+7,17-7); | |
72 stream_read(demuxer->stream,hdr,7); | |
73 } | |
74 break; | |
75 | |
76 case 0xEFBE: | |
77 break; | |
78 | |
79 default: | |
12272 | 80 mp_dbg(MSGT_DEMUX,MSGL_WARN,"demux_nsv: sync lost\n"); |
12175 | 81 break; |
82 } | |
83 | |
12272 | 84 if (sh_video) |
12175 | 85 sh_video->pts = priv->v_pts =demuxer->video->pts= priv->video_pack_no * |
86 (float)sh_video->frametime; | |
12272 | 87 else |
88 priv->v_pts = priv->video_pack_no; | |
12175 | 89 |
90 demuxer->filepos=stream_tell(demuxer->stream); | |
91 | |
92 | |
93 mp_dbg(MSGT_DEMUX,MSGL_DBG2,"demux_nsv: %08X: %02X %02X | %02X %02X %02X | %02X %02X \n", | |
94 (int)demuxer->filepos, hdr[0],hdr[1],hdr[2],hdr[3],hdr[4],hdr[5],hdr[6]); | |
95 | |
96 // read video: | |
97 videolen=(hdr[2]>>4)|(hdr[3]<<4)|(hdr[4]<<0xC); | |
98 //check if we got extra data like subtitles here | |
99 if( (hdr[2]&0x0f) != 0x0 ) { | |
100 stream_read( demuxer->stream, aux, 6); | |
101 | |
102 i_aux = aux[0]|aux[1]<<8; | |
103 // We skip this extra data | |
104 stream_skip( demuxer->stream, i_aux ); | |
105 i_aux+=6; | |
106 videolen -= i_aux; | |
107 } | |
108 | |
109 | |
110 // we need to return an empty packet when the | |
111 // video frame is empty otherwise the stream will fasten up | |
12272 | 112 if(sh_video) { |
12175 | 113 if( (hdr[2]&0x0f) != 0x0 ) |
114 ds_read_packet(demuxer->video,demuxer->stream,videolen,priv->v_pts,demuxer->filepos-i_aux,0); | |
115 else | |
116 ds_read_packet(demuxer->video,demuxer->stream,videolen,priv->v_pts,demuxer->filepos,0); | |
117 } | |
118 else | |
119 stream_skip(demuxer->stream,videolen); | |
120 | |
121 // read audio: | |
122 audiolen=(hdr[5])|(hdr[6]<<8); | |
123 // we need to return an empty packet when the | |
124 // audio frame is empty otherwise the stream will fasten up | |
12272 | 125 if(sh_audio) { |
12175 | 126 ds_read_packet(demuxer->audio,demuxer->stream,audiolen,priv->v_pts,demuxer->filepos+videolen,0); |
127 } | |
128 else | |
129 stream_skip(demuxer->stream,audiolen); | |
130 | |
131 ++priv->video_pack_no; | |
132 | |
133 return 1; | |
134 | |
135 } | |
136 | |
137 | |
16175 | 138 static demuxer_t* demux_open_nsv ( demuxer_t* demuxer ) |
12175 | 139 { |
140 // last 2 bytes 17 and 18 are unknown but right after that comes the length | |
141 unsigned char hdr[17]; | |
142 int videolen,audiolen; | |
12272 | 143 unsigned char buf[10]; |
12175 | 144 sh_video_t *sh_video = NULL; |
145 sh_audio_t *sh_audio = NULL; | |
146 | |
147 | |
148 nsv_priv_t * priv = malloc(sizeof(nsv_priv_t)); | |
149 demuxer->priv=priv; | |
150 priv->video_pack_no=0; | |
151 | |
152 /* disable seeking yet to be fixed*/ | |
153 demuxer->seekable = 0; | |
154 | |
155 stream_read(demuxer->stream,hdr,4); | |
156 if(stream_eof(demuxer->stream)) return 0; | |
157 | |
158 if(hdr[0]==0x4E && hdr[1]==0x53 && hdr[2]==0x56){ | |
159 // NSV header! | |
160 if(hdr[3]==0x73){ | |
161 // NSVs | |
162 stream_read(demuxer->stream,hdr+4,17-4); | |
163 } | |
164 | |
165 if(hdr[3]==0x66){ | |
166 // NSVf | |
167 int len=stream_read_dword_le(demuxer->stream); | |
168 // TODO: parse out metadata!!!! | |
169 stream_skip(demuxer->stream,len-8); | |
170 | |
171 // NSVs | |
172 stream_read(demuxer->stream,hdr,17); | |
20470
054516eecb9b
Better check for non-broken NSVf-header to avoid incorrect detection.
reimar
parents:
18885
diff
changeset
|
173 if (stream_eof(demuxer->stream) || strncmp(hdr, "NSVs", 4)) |
054516eecb9b
Better check for non-broken NSVf-header to avoid incorrect detection.
reimar
parents:
18885
diff
changeset
|
174 return 0; |
12175 | 175 } |
176 | |
177 // dummy debug message | |
178 mp_msg(MSGT_DEMUX,MSGL_V,"demux_nsv: Header: %.12s\n",hdr); | |
179 | |
180 // bytes 8-11 audio codec fourcc | |
181 // PCM fourcc needs extra parsing for every audio chunk, yet to implement | |
12896 | 182 if((demuxer->audio->id != -2) && strncmp(hdr+8,"NONE", 4)){//&&strncmp(hdr+8,"VLB ", 4)){ |
12175 | 183 sh_audio = new_sh_audio ( demuxer, 0 ); |
26295
c8a489c8cae8
Set demuxer->audio->id to avoid breakage due to r26301
reimar
parents:
25707
diff
changeset
|
184 demuxer->audio->id = 0; |
12175 | 185 demuxer->audio->sh = sh_audio; |
186 sh_audio->format=mmioFOURCC(hdr[8],hdr[9],hdr[10],hdr[11]); | |
187 sh_audio->ds = demuxer->audio; | |
12896 | 188 priv->a_format=mmioFOURCC(hdr[8],hdr[9],hdr[10],hdr[11]); |
12175 | 189 } |
190 | |
191 // store hdr fps | |
192 priv->fps=hdr[16]; | |
193 | |
12896 | 194 if ((demuxer->video->id != -2) && strncmp(hdr+4,"NONE", 4)) { |
12198 | 195 /* Create a new video stream header */ |
196 sh_video = new_sh_video ( demuxer, 0 ); | |
197 | |
198 /* Make sure the demuxer knows about the new video stream header | |
199 * (even though new_sh_video() ought to take care of it) | |
200 */ | |
201 demuxer->video->sh = sh_video; | |
202 | |
203 /* Make sure that the video demuxer stream header knows about its | |
204 * parent video demuxer stream (this is getting wacky), or else | |
205 * video_read_properties() will choke | |
206 */ | |
207 sh_video->ds = demuxer->video; | |
208 | |
12175 | 209 // bytes 4-7 video codec fourcc |
210 priv->v_format = sh_video->format=mmioFOURCC(hdr[4],hdr[5],hdr[6],hdr[7]); | |
211 | |
212 // new video stream! parse header | |
213 sh_video->disp_w=hdr[12]|(hdr[13]<<8); | |
214 sh_video->disp_h=hdr[14]|(hdr[15]<<8); | |
18885 | 215 sh_video->bih=calloc(1,sizeof(BITMAPINFOHEADER)); |
12175 | 216 sh_video->bih->biSize=sizeof(BITMAPINFOHEADER); |
217 sh_video->bih->biPlanes=1; | |
218 sh_video->bih->biBitCount=24; | |
219 sh_video->bih->biWidth=hdr[12]|(hdr[13]<<8); | |
220 sh_video->bih->biHeight=hdr[14]|(hdr[15]<<8); | |
221 memcpy(&sh_video->bih->biCompression,hdr+4,4); | |
222 sh_video->bih->biSizeImage=sh_video->bih->biWidth*sh_video->bih->biHeight*3; | |
223 | |
224 // here we search for the correct keyframe | |
12275 | 225 // vp6 keyframe is when the 2nd byte of the vp6 header is |
226 // 0x36 for VP61 and 0x46 for VP62 | |
12272 | 227 if((priv->v_format==mmioFOURCC('V','P','6','1')) || |
228 (priv->v_format==mmioFOURCC('V','P','6','2')) || | |
229 (priv->v_format==mmioFOURCC('V','P','3','1'))) { | |
230 stream_read(demuxer->stream,buf,10); | |
12277 | 231 if (((((priv->v_format>>16) & 0xff) == '6') && ((buf[8]&0x0e)!=0x06)) || |
12272 | 232 ((((priv->v_format>>16) & 0xff) == '3') && (buf[8]!=0x00 || buf[9]!=0x08))) { |
233 mp_msg(MSGT_DEMUX,MSGL_V,"demux_nsv: searching %.4s keyframe...\n", (char*)&priv->v_format); | |
12277 | 234 while(((((priv->v_format>>16) & 0xff) == '6') && ((buf[8]&0x0e)!=0x06)) || |
12272 | 235 ((((priv->v_format>>16) & 0xff) == '3') && (buf[8]!=0x00 || buf[9]!=0x08))){ |
236 mp_msg(MSGT_DEMUX,MSGL_DBG2,"demux_nsv: %.4s block skip.\n", (char*)&priv->v_format); | |
12179
aeb377ccb110
Fix vp61 keyframe search (do not skip blocks if 1st frame is keyframe)
rtognimp
parents:
12175
diff
changeset
|
237 videolen=(buf[2]>>4)|(buf[3]<<4)|(buf[4]<<0xC); |
aeb377ccb110
Fix vp61 keyframe search (do not skip blocks if 1st frame is keyframe)
rtognimp
parents:
12175
diff
changeset
|
238 audiolen=(buf[5])|(buf[6]<<8); |
12272 | 239 stream_skip(demuxer->stream, videolen+audiolen-3); |
240 stream_read(demuxer->stream,buf,10); | |
12277 | 241 if(stream_eof(demuxer->stream)) return 0; |
12179
aeb377ccb110
Fix vp61 keyframe search (do not skip blocks if 1st frame is keyframe)
rtognimp
parents:
12175
diff
changeset
|
242 if(buf[0]==0x4E){ |
aeb377ccb110
Fix vp61 keyframe search (do not skip blocks if 1st frame is keyframe)
rtognimp
parents:
12175
diff
changeset
|
243 mp_msg(MSGT_DEMUX,MSGL_DBG2,"demux_nsv: Got NSVs block.\n"); |
12272 | 244 stream_skip(demuxer->stream,7); |
245 stream_read(demuxer->stream,buf,10); | |
12175 | 246 } |
247 } | |
248 } | |
249 | |
13299
6f8fe531dd73
avoid always skipping first junk with a "sync lost" message
reimar
parents:
12896
diff
changeset
|
250 // data starts 10 bytes before current pos but later |
6f8fe531dd73
avoid always skipping first junk with a "sync lost" message
reimar
parents:
12896
diff
changeset
|
251 // we seek 17 backwards |
6f8fe531dd73
avoid always skipping first junk with a "sync lost" message
reimar
parents:
12896
diff
changeset
|
252 stream_skip(demuxer->stream,7); |
12175 | 253 } |
254 | |
255 switch(priv->fps){ | |
256 case 0x80: | |
257 sh_video->fps=30; | |
258 break; | |
259 case 0x81: | |
260 sh_video->fps=(float)30000.0/1001.0; | |
261 break; | |
262 case 0x82: | |
263 sh_video->fps=25; | |
264 break; | |
265 case 0x83: | |
266 sh_video->fps=(float)24000.0/1001.0; | |
267 break; | |
268 case 0x85: | |
269 sh_video->fps=(float)15000.0/1001.0; | |
270 break; | |
15991 | 271 case 0x89: |
272 sh_video->fps=(float)10000.0/1001.0; | |
273 break; | |
12175 | 274 default: |
275 sh_video->fps = (float)priv->fps; | |
276 } | |
277 sh_video->frametime = (float)1.0 / (float)sh_video->fps; | |
12198 | 278 } |
12175 | 279 } |
280 | |
13299
6f8fe531dd73
avoid always skipping first junk with a "sync lost" message
reimar
parents:
12896
diff
changeset
|
281 // seek to start of NSV header |
6f8fe531dd73
avoid always skipping first junk with a "sync lost" message
reimar
parents:
12896
diff
changeset
|
282 stream_seek(demuxer->stream,stream_tell(demuxer->stream)-17); |
12175 | 283 |
284 return demuxer; | |
285 } | |
286 | |
16175 | 287 static int nsv_check_file ( demuxer_t* demuxer ) |
12175 | 288 { |
20473 | 289 uint32_t hdr = 0; |
16318 | 290 int i; |
12175 | 291 |
292 mp_msg ( MSGT_DEMUX, MSGL_V, "Checking for Nullsoft Streaming Video\n" ); | |
293 | |
16318 | 294 for (i = 0; i < HEADER_SEARCH_SIZE; i++) { |
20473 | 295 uint8_t c = stream_read_char(demuxer->stream); |
296 if (stream_eof(demuxer->stream)) | |
16318 | 297 return 0; |
20473 | 298 if (hdr == mmioFOURCC('s', 'V', 'S', 'N') || |
299 (hdr == mmioFOURCC('f', 'V', 'S', 'N') && !c)) { | |
300 stream_seek(demuxer->stream,stream_tell(demuxer->stream)-5); | |
16318 | 301 return DEMUXER_TYPE_NSV; |
302 } | |
20473 | 303 hdr = (hdr << 8) | c; |
16318 | 304 } |
305 | |
306 return 0; | |
12175 | 307 } |
308 | |
16175 | 309 static void demux_close_nsv(demuxer_t* demuxer) { |
12175 | 310 nsv_priv_t* priv = demuxer->priv; |
311 | |
312 if(!priv) | |
313 return; | |
314 free(priv); | |
315 | |
316 } | |
16175 | 317 |
318 | |
25707
d4fe6e23283e
Make all demuxer_desc_t const, thus moving them to .rodata
reimar
parents:
22605
diff
changeset
|
319 const demuxer_desc_t demuxer_desc_nsv = { |
16175 | 320 "NullsoftVideo demuxer", |
321 "nsv", | |
322 "Nullsoft Streaming Video", | |
323 "Reza Jelveh", | |
324 "nsv and nsa streaming files", | |
325 DEMUXER_TYPE_NSV, | |
16318 | 326 0, // safe but expensive autodetect |
16175 | 327 nsv_check_file, |
328 demux_nsv_fill_buffer, | |
329 demux_open_nsv, | |
330 demux_close_nsv, | |
331 demux_seek_nsv, | |
332 NULL | |
333 }; |