Mercurial > mplayer.hg
annotate libmpdemux/demux_nsv.c @ 24449:1007f99949af
10l, placed terminating 0 at the wrong place.
author | reimar |
---|---|
date | Fri, 14 Sep 2007 16:12:33 +0000 |
parents | 4d81dbdf46b9 |
children | d4fe6e23283e |
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 ); |
184 demuxer->audio->sh = sh_audio; | |
185 sh_audio->format=mmioFOURCC(hdr[8],hdr[9],hdr[10],hdr[11]); | |
186 sh_audio->ds = demuxer->audio; | |
12896 | 187 priv->a_format=mmioFOURCC(hdr[8],hdr[9],hdr[10],hdr[11]); |
12175 | 188 } |
189 | |
190 // store hdr fps | |
191 priv->fps=hdr[16]; | |
192 | |
12896 | 193 if ((demuxer->video->id != -2) && strncmp(hdr+4,"NONE", 4)) { |
12198 | 194 /* Create a new video stream header */ |
195 sh_video = new_sh_video ( demuxer, 0 ); | |
196 | |
197 /* Make sure the demuxer knows about the new video stream header | |
198 * (even though new_sh_video() ought to take care of it) | |
199 */ | |
200 demuxer->video->sh = sh_video; | |
201 | |
202 /* Make sure that the video demuxer stream header knows about its | |
203 * parent video demuxer stream (this is getting wacky), or else | |
204 * video_read_properties() will choke | |
205 */ | |
206 sh_video->ds = demuxer->video; | |
207 | |
12175 | 208 // bytes 4-7 video codec fourcc |
209 priv->v_format = sh_video->format=mmioFOURCC(hdr[4],hdr[5],hdr[6],hdr[7]); | |
210 | |
211 // new video stream! parse header | |
212 sh_video->disp_w=hdr[12]|(hdr[13]<<8); | |
213 sh_video->disp_h=hdr[14]|(hdr[15]<<8); | |
18885 | 214 sh_video->bih=calloc(1,sizeof(BITMAPINFOHEADER)); |
12175 | 215 sh_video->bih->biSize=sizeof(BITMAPINFOHEADER); |
216 sh_video->bih->biPlanes=1; | |
217 sh_video->bih->biBitCount=24; | |
218 sh_video->bih->biWidth=hdr[12]|(hdr[13]<<8); | |
219 sh_video->bih->biHeight=hdr[14]|(hdr[15]<<8); | |
220 memcpy(&sh_video->bih->biCompression,hdr+4,4); | |
221 sh_video->bih->biSizeImage=sh_video->bih->biWidth*sh_video->bih->biHeight*3; | |
222 | |
223 // here we search for the correct keyframe | |
12275 | 224 // vp6 keyframe is when the 2nd byte of the vp6 header is |
225 // 0x36 for VP61 and 0x46 for VP62 | |
12272 | 226 if((priv->v_format==mmioFOURCC('V','P','6','1')) || |
227 (priv->v_format==mmioFOURCC('V','P','6','2')) || | |
228 (priv->v_format==mmioFOURCC('V','P','3','1'))) { | |
229 stream_read(demuxer->stream,buf,10); | |
12277 | 230 if (((((priv->v_format>>16) & 0xff) == '6') && ((buf[8]&0x0e)!=0x06)) || |
12272 | 231 ((((priv->v_format>>16) & 0xff) == '3') && (buf[8]!=0x00 || buf[9]!=0x08))) { |
232 mp_msg(MSGT_DEMUX,MSGL_V,"demux_nsv: searching %.4s keyframe...\n", (char*)&priv->v_format); | |
12277 | 233 while(((((priv->v_format>>16) & 0xff) == '6') && ((buf[8]&0x0e)!=0x06)) || |
12272 | 234 ((((priv->v_format>>16) & 0xff) == '3') && (buf[8]!=0x00 || buf[9]!=0x08))){ |
235 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
|
236 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
|
237 audiolen=(buf[5])|(buf[6]<<8); |
12272 | 238 stream_skip(demuxer->stream, videolen+audiolen-3); |
239 stream_read(demuxer->stream,buf,10); | |
12277 | 240 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
|
241 if(buf[0]==0x4E){ |
aeb377ccb110
Fix vp61 keyframe search (do not skip blocks if 1st frame is keyframe)
rtognimp
parents:
12175
diff
changeset
|
242 mp_msg(MSGT_DEMUX,MSGL_DBG2,"demux_nsv: Got NSVs block.\n"); |
12272 | 243 stream_skip(demuxer->stream,7); |
244 stream_read(demuxer->stream,buf,10); | |
12175 | 245 } |
246 } | |
247 } | |
248 | |
13299
6f8fe531dd73
avoid always skipping first junk with a "sync lost" message
reimar
parents:
12896
diff
changeset
|
249 // 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
|
250 // we seek 17 backwards |
6f8fe531dd73
avoid always skipping first junk with a "sync lost" message
reimar
parents:
12896
diff
changeset
|
251 stream_skip(demuxer->stream,7); |
12175 | 252 } |
253 | |
254 switch(priv->fps){ | |
255 case 0x80: | |
256 sh_video->fps=30; | |
257 break; | |
258 case 0x81: | |
259 sh_video->fps=(float)30000.0/1001.0; | |
260 break; | |
261 case 0x82: | |
262 sh_video->fps=25; | |
263 break; | |
264 case 0x83: | |
265 sh_video->fps=(float)24000.0/1001.0; | |
266 break; | |
267 case 0x85: | |
268 sh_video->fps=(float)15000.0/1001.0; | |
269 break; | |
15991 | 270 case 0x89: |
271 sh_video->fps=(float)10000.0/1001.0; | |
272 break; | |
12175 | 273 default: |
274 sh_video->fps = (float)priv->fps; | |
275 } | |
276 sh_video->frametime = (float)1.0 / (float)sh_video->fps; | |
12198 | 277 } |
12175 | 278 } |
279 | |
13299
6f8fe531dd73
avoid always skipping first junk with a "sync lost" message
reimar
parents:
12896
diff
changeset
|
280 // seek to start of NSV header |
6f8fe531dd73
avoid always skipping first junk with a "sync lost" message
reimar
parents:
12896
diff
changeset
|
281 stream_seek(demuxer->stream,stream_tell(demuxer->stream)-17); |
12175 | 282 |
283 return demuxer; | |
284 } | |
285 | |
16175 | 286 static int nsv_check_file ( demuxer_t* demuxer ) |
12175 | 287 { |
20473 | 288 uint32_t hdr = 0; |
16318 | 289 int i; |
12175 | 290 |
291 mp_msg ( MSGT_DEMUX, MSGL_V, "Checking for Nullsoft Streaming Video\n" ); | |
292 | |
16318 | 293 for (i = 0; i < HEADER_SEARCH_SIZE; i++) { |
20473 | 294 uint8_t c = stream_read_char(demuxer->stream); |
295 if (stream_eof(demuxer->stream)) | |
16318 | 296 return 0; |
20473 | 297 if (hdr == mmioFOURCC('s', 'V', 'S', 'N') || |
298 (hdr == mmioFOURCC('f', 'V', 'S', 'N') && !c)) { | |
299 stream_seek(demuxer->stream,stream_tell(demuxer->stream)-5); | |
16318 | 300 return DEMUXER_TYPE_NSV; |
301 } | |
20473 | 302 hdr = (hdr << 8) | c; |
16318 | 303 } |
304 | |
305 return 0; | |
12175 | 306 } |
307 | |
16175 | 308 static void demux_close_nsv(demuxer_t* demuxer) { |
12175 | 309 nsv_priv_t* priv = demuxer->priv; |
310 | |
311 if(!priv) | |
312 return; | |
313 free(priv); | |
314 | |
315 } | |
16175 | 316 |
317 | |
318 demuxer_desc_t demuxer_desc_nsv = { | |
319 "NullsoftVideo demuxer", | |
320 "nsv", | |
321 "Nullsoft Streaming Video", | |
322 "Reza Jelveh", | |
323 "nsv and nsa streaming files", | |
324 DEMUXER_TYPE_NSV, | |
16318 | 325 0, // safe but expensive autodetect |
16175 | 326 nsv_check_file, |
327 demux_nsv_fill_buffer, | |
328 demux_open_nsv, | |
329 demux_close_nsv, | |
330 demux_seek_nsv, | |
331 NULL | |
332 }; |