Mercurial > mplayer.hg
annotate libmpdemux/demux_nsv.c @ 29135:628596ce7d8c
Move addition of MMX-OBJS to OBJS into common.mak instead of duplicating it.
author | diego |
---|---|
date | Sun, 12 Apr 2009 22:49:58 +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 }; |