Mercurial > mplayer.hg
annotate libmpdemux/pnm.c @ 18077:cede662f40a5
timestamps are 33 bits long, so they don't fit in an unsigned int; 10l
author | nicodvb |
---|---|
date | Tue, 11 Apr 2006 20:05:24 +0000 |
parents | c0068de90f44 |
children |
rev | line source |
---|---|
8570 | 1 /* |
2 * Copyright (C) 2000-2002 the xine project | |
3 * | |
4 * This file is part of xine, a free video player. | |
5 * | |
6 * xine is free software; you can redistribute it and/or modify | |
7 * it under the terms of the GNU General Public License as published by | |
8 * the Free Software Foundation; either version 2 of the License, or | |
9 * (at your option) any later version. | |
10 * | |
11 * xine is distributed in the hope that it will be useful, | |
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
14 * GNU General Public License for more details. | |
15 * | |
16 * You should have received a copy of the GNU General Public License | |
17 * along with this program; if not, write to the Free Software | |
18 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA | |
19 * | |
20 * $Id$ | |
21 * | |
22 * pnm protocol implementation | |
23 * based upon code from joschka | |
24 */ | |
25 | |
15614
a4a46131ee71
Change header order to avoid compile error because of STREAM_SEEK
reimar
parents:
15585
diff
changeset
|
26 #include "config.h" |
a4a46131ee71
Change header order to avoid compile error because of STREAM_SEEK
reimar
parents:
15585
diff
changeset
|
27 |
8570 | 28 #include <unistd.h> |
29 #include <stdio.h> | |
30 #include <assert.h> | |
31 #include <string.h> | |
32 #include <sys/stat.h> | |
33 #include <fcntl.h> | |
34 #include <errno.h> | |
35 #include <stdlib.h> | |
36 #include <sys/time.h> | |
8584 | 37 #include <inttypes.h> |
10281 | 38 #ifndef HAVE_WINSOCK2 |
39 #define closesocket close | |
40 #include <sys/socket.h> | |
41 //#include <netinet/in.h> | |
42 //#include <netdb.h> | |
43 #else | |
44 #include <winsock2.h> | |
45 #endif | |
46 | |
15614
a4a46131ee71
Change header order to avoid compile error because of STREAM_SEEK
reimar
parents:
15585
diff
changeset
|
47 #include "stream.h" |
a4a46131ee71
Change header order to avoid compile error because of STREAM_SEEK
reimar
parents:
15585
diff
changeset
|
48 #include "demuxer.h" |
a4a46131ee71
Change header order to avoid compile error because of STREAM_SEEK
reimar
parents:
15585
diff
changeset
|
49 #include "help_mp.h" |
17092 | 50 #include "osdep/timer.h" |
15614
a4a46131ee71
Change header order to avoid compile error because of STREAM_SEEK
reimar
parents:
15585
diff
changeset
|
51 |
8570 | 52 #include "pnm.h" |
53 //#include "libreal/rmff.h" | |
54 | |
15585 | 55 extern int network_bandwidth; |
56 | |
8570 | 57 #define FOURCC_TAG( ch0, ch1, ch2, ch3 ) \ |
58 (((long)(unsigned char)(ch3) ) | \ | |
59 ( (long)(unsigned char)(ch2) << 8 ) | \ | |
60 ( (long)(unsigned char)(ch1) << 16 ) | \ | |
61 ( (long)(unsigned char)(ch0) << 24 ) ) | |
62 | |
63 | |
64 #define RMF_TAG FOURCC_TAG('.', 'R', 'M', 'F') | |
65 #define PROP_TAG FOURCC_TAG('P', 'R', 'O', 'P') | |
66 #define MDPR_TAG FOURCC_TAG('M', 'D', 'P', 'R') | |
67 #define CONT_TAG FOURCC_TAG('C', 'O', 'N', 'T') | |
68 #define DATA_TAG FOURCC_TAG('D', 'A', 'T', 'A') | |
69 #define INDX_TAG FOURCC_TAG('I', 'N', 'D', 'X') | |
70 #define PNA_TAG FOURCC_TAG('P', 'N', 'A', 0 ) | |
71 | |
72 /* | |
73 #define LOG | |
74 */ | |
75 | |
8880 | 76 #define BUF_SIZE 4096 |
77 #define HEADER_SIZE 4096 | |
8570 | 78 |
79 struct pnm_s { | |
80 | |
81 int s; | |
82 | |
83 // char *host; | |
84 // int port; | |
85 char *path; | |
86 // char *url; | |
87 | |
88 char buffer[BUF_SIZE]; /* scratch buffer */ | |
89 | |
90 /* receive buffer */ | |
91 uint8_t recv[BUF_SIZE]; | |
92 int recv_size; | |
93 int recv_read; | |
94 | |
95 uint8_t header[HEADER_SIZE]; | |
96 int header_len; | |
97 int header_read; | |
98 unsigned int seq_num[4]; /* two streams with two indices */ | |
99 unsigned int seq_current[2]; /* seqs of last stream chunk read */ | |
100 uint32_t ts_current; /* timestamp of current chunk */ | |
101 uint32_t ts_last[2]; /* timestamps of last chunks */ | |
102 unsigned int packet; /* number of last recieved packet */ | |
103 }; | |
104 | |
105 /* | |
106 * utility macros | |
107 */ | |
108 | |
109 #define BE_16(x) ((((uint8_t*)(x))[0] << 8) | ((uint8_t*)(x))[1]) | |
110 #define BE_32(x) ((((uint8_t*)(x))[0] << 24) | \ | |
111 (((uint8_t*)(x))[1] << 16) | \ | |
112 (((uint8_t*)(x))[2] << 8) | \ | |
113 ((uint8_t*)(x))[3]) | |
114 | |
115 /* D means direct (no pointer) */ | |
116 #define BE_16D(x) ((x & 0xff00) >> 8)|((x & 0x00ff) << 8) | |
117 | |
118 /* sizes */ | |
119 #define PREAMBLE_SIZE 8 | |
120 #define CHECKSUM_SIZE 3 | |
121 | |
122 | |
123 /* header of rm files */ | |
124 #define RM_HEADER_SIZE 0x12 | |
15626
941b1a71351f
printf converted to mp_msg; made static many unnecessarily global symbols
nicodvb
parents:
15614
diff
changeset
|
125 static const unsigned char rm_header[]={ |
8570 | 126 0x2e, 0x52, 0x4d, 0x46, /* object_id ".RMF" */ |
127 0x00, 0x00, 0x00, 0x12, /* header_size 0x12 */ | |
128 0x00, 0x00, /* object_version 0x00 */ | |
129 0x00, 0x00, 0x00, 0x00, /* file_version 0x00 */ | |
130 0x00, 0x00, 0x00, 0x06 /* num_headers 0x06 */ | |
131 }; | |
132 | |
133 /* data chunk header */ | |
134 #define PNM_DATA_HEADER_SIZE 18 | |
15626
941b1a71351f
printf converted to mp_msg; made static many unnecessarily global symbols
nicodvb
parents:
15614
diff
changeset
|
135 static const unsigned char pnm_data_header[]={ |
8570 | 136 'D','A','T','A', |
137 0,0,0,0, /* data chunk size */ | |
138 0,0, /* object version */ | |
139 0,0,0,0, /* num packets */ | |
140 0,0,0,0}; /* next data header */ | |
141 | |
142 /* pnm request chunk ids */ | |
143 | |
144 #define PNA_CLIENT_CAPS 0x03 | |
145 #define PNA_CLIENT_CHALLANGE 0x04 | |
146 #define PNA_BANDWIDTH 0x05 | |
147 #define PNA_GUID 0x13 | |
148 #define PNA_TIMESTAMP 0x17 | |
149 #define PNA_TWENTYFOUR 0x18 | |
150 | |
151 #define PNA_CLIENT_STRING 0x63 | |
152 #define PNA_PATH_REQUEST 0x52 | |
153 | |
15626
941b1a71351f
printf converted to mp_msg; made static many unnecessarily global symbols
nicodvb
parents:
15614
diff
changeset
|
154 static const unsigned char pnm_challenge[] = "0990f6b4508b51e801bd6da011ad7b56"; |
941b1a71351f
printf converted to mp_msg; made static many unnecessarily global symbols
nicodvb
parents:
15614
diff
changeset
|
155 static const unsigned char pnm_timestamp[] = "[15/06/1999:22:22:49 00:00]"; |
941b1a71351f
printf converted to mp_msg; made static many unnecessarily global symbols
nicodvb
parents:
15614
diff
changeset
|
156 static const unsigned char pnm_guid[] = "3eac2411-83d5-11d2-f3ea-d7c3a51aa8b0"; |
941b1a71351f
printf converted to mp_msg; made static many unnecessarily global symbols
nicodvb
parents:
15614
diff
changeset
|
157 static const unsigned char pnm_response[] = "97715a899cbe41cee00dd434851535bf"; |
941b1a71351f
printf converted to mp_msg; made static many unnecessarily global symbols
nicodvb
parents:
15614
diff
changeset
|
158 static const unsigned char client_string[] = "WinNT_9.0_6.0.6.45_plus32_MP60_en-US_686l"; |
8570 | 159 |
160 #define PNM_HEADER_SIZE 11 | |
15626
941b1a71351f
printf converted to mp_msg; made static many unnecessarily global symbols
nicodvb
parents:
15614
diff
changeset
|
161 static const unsigned char pnm_header[] = { |
8570 | 162 'P','N','A', |
163 0x00, 0x0a, | |
164 0x00, 0x14, | |
165 0x00, 0x02, | |
166 0x00, 0x01 }; | |
167 | |
168 #define PNM_CLIENT_CAPS_SIZE 126 | |
15626
941b1a71351f
printf converted to mp_msg; made static many unnecessarily global symbols
nicodvb
parents:
15614
diff
changeset
|
169 static const unsigned char pnm_client_caps[] = { |
8570 | 170 0x07, 0x8a, 'p','n','r','v', |
171 0, 0x90, 'p','n','r','v', | |
172 0, 0x64, 'd','n','e','t', | |
173 0, 0x46, 'p','n','r','v', | |
174 0, 0x32, 'd','n','e','t', | |
175 0, 0x2b, 'p','n','r','v', | |
176 0, 0x28, 'd','n','e','t', | |
177 0, 0x24, 'p','n','r','v', | |
178 0, 0x19, 'd','n','e','t', | |
179 0, 0x18, 'p','n','r','v', | |
180 0, 0x14, 's','i','p','r', | |
181 0, 0x14, 'd','n','e','t', | |
182 0, 0x24, '2','8','_','8', | |
183 0, 0x12, 'p','n','r','v', | |
184 0, 0x0f, 'd','n','e','t', | |
185 0, 0x0a, 's','i','p','r', | |
186 0, 0x0a, 'd','n','e','t', | |
187 0, 0x08, 's','i','p','r', | |
188 0, 0x06, 's','i','p','r', | |
189 0, 0x12, 'l','p','c','J', | |
190 0, 0x07, '0','5','_','6' }; | |
191 | |
15626
941b1a71351f
printf converted to mp_msg; made static many unnecessarily global symbols
nicodvb
parents:
15614
diff
changeset
|
192 static const uint32_t pnm_default_bandwidth=10485800; |
941b1a71351f
printf converted to mp_msg; made static many unnecessarily global symbols
nicodvb
parents:
15614
diff
changeset
|
193 static const uint32_t pnm_available_bandwidths[]={14400,19200,28800,33600,34430,57600, |
8570 | 194 115200,262200,393216,524300,1544000,10485800}; |
195 | |
196 #define PNM_TWENTYFOUR_SIZE 16 | |
15626
941b1a71351f
printf converted to mp_msg; made static many unnecessarily global symbols
nicodvb
parents:
15614
diff
changeset
|
197 static unsigned char pnm_twentyfour[]={ |
8570 | 198 0xd5, 0x42, 0xa3, 0x1b, 0xef, 0x1f, 0x70, 0x24, |
199 0x85, 0x29, 0xb3, 0x8d, 0xba, 0x11, 0xf3, 0xd6 }; | |
200 | |
201 /* now other data follows. marked with 0x0000 at the beginning */ | |
15626
941b1a71351f
printf converted to mp_msg; made static many unnecessarily global symbols
nicodvb
parents:
15614
diff
changeset
|
202 static int after_chunks_length=6; |
941b1a71351f
printf converted to mp_msg; made static many unnecessarily global symbols
nicodvb
parents:
15614
diff
changeset
|
203 static unsigned char after_chunks[]={ |
8570 | 204 0x00, 0x00, /* mark */ |
205 | |
206 0x50, 0x84, /* seems to be fixated */ | |
207 0x1f, 0x3a /* varies on each request (checksum ?)*/ | |
208 }; | |
209 | |
210 static void hexdump (char *buf, int length); | |
211 | |
212 static int rm_write(int s, const char *buf, int len) { | |
213 int total, timeout; | |
214 | |
215 total = 0; timeout = 30; | |
216 while (total < len){ | |
217 int n; | |
218 | |
10206
35e306346e59
Using recv/send instead read/write for proper MinGW support (it's a 4.2BSD standard). Patch by FloDt <flodt8@yahoo.de>
alex
parents:
8880
diff
changeset
|
219 n = send (s, &buf[total], len - total, 0); |
8570 | 220 |
221 if (n > 0) | |
222 total += n; | |
223 else if (n < 0) { | |
10281 | 224 #ifndef HAVE_WINSOCK2 |
8570 | 225 if ((timeout>0) && ((errno == EAGAIN) || (errno == EINPROGRESS))) { |
10281 | 226 #else |
227 if ((timeout>0) && ((errno == EAGAIN) || (WSAGetLastError() == WSAEINPROGRESS))) { | |
228 #endif | |
16372
b313a38c69cb
replace sleep with usec_sleep, required for recent mingw versions, patch by Robert Swain <robert.swain at gmail.com>
faust3
parents:
15626
diff
changeset
|
229 usec_sleep (1000000); timeout--; |
8570 | 230 } else |
231 return -1; | |
232 } | |
233 } | |
234 | |
235 return total; | |
236 } | |
237 | |
238 static ssize_t rm_read(int fd, void *buf, size_t count) { | |
239 | |
240 ssize_t ret, total; | |
241 | |
242 total = 0; | |
243 | |
244 while (total < count) { | |
245 | |
246 fd_set rset; | |
247 struct timeval timeout; | |
248 | |
249 FD_ZERO (&rset); | |
250 FD_SET (fd, &rset); | |
251 | |
252 timeout.tv_sec = 3; | |
253 timeout.tv_usec = 0; | |
254 | |
255 if (select (fd+1, &rset, NULL, NULL, &timeout) <= 0) { | |
256 return -1; | |
257 } | |
258 | |
10206
35e306346e59
Using recv/send instead read/write for proper MinGW support (it's a 4.2BSD standard). Patch by FloDt <flodt8@yahoo.de>
alex
parents:
8880
diff
changeset
|
259 ret=recv (fd, ((uint8_t*)buf)+total, count-total, 0); |
8570 | 260 |
261 if (ret<=0) { | |
15626
941b1a71351f
printf converted to mp_msg; made static many unnecessarily global symbols
nicodvb
parents:
15614
diff
changeset
|
262 mp_msg(MSGT_OPEN, MSGL_ERR, "input_pnm: read error.\n"); |
8570 | 263 return ret; |
264 } else | |
265 total += ret; | |
266 } | |
267 | |
268 return total; | |
269 } | |
270 | |
271 /* | |
272 * debugging utilities | |
273 */ | |
274 | |
275 static void hexdump (char *buf, int length) { | |
276 | |
277 int i; | |
278 | |
15626
941b1a71351f
printf converted to mp_msg; made static many unnecessarily global symbols
nicodvb
parents:
15614
diff
changeset
|
279 mp_msg(MSGT_OPEN, MSGL_INFO, "input_pnm: ascii>"); |
8570 | 280 for (i = 0; i < length; i++) { |
281 unsigned char c = buf[i]; | |
282 | |
283 if ((c >= 32) && (c <= 128)) | |
15626
941b1a71351f
printf converted to mp_msg; made static many unnecessarily global symbols
nicodvb
parents:
15614
diff
changeset
|
284 mp_msg(MSGT_OPEN, MSGL_INFO, "%c", c); |
8570 | 285 else |
15626
941b1a71351f
printf converted to mp_msg; made static many unnecessarily global symbols
nicodvb
parents:
15614
diff
changeset
|
286 mp_msg(MSGT_OPEN, MSGL_INFO, "."); |
8570 | 287 } |
15626
941b1a71351f
printf converted to mp_msg; made static many unnecessarily global symbols
nicodvb
parents:
15614
diff
changeset
|
288 mp_msg(MSGT_OPEN, MSGL_INFO, "\n"); |
8570 | 289 |
15626
941b1a71351f
printf converted to mp_msg; made static many unnecessarily global symbols
nicodvb
parents:
15614
diff
changeset
|
290 mp_msg(MSGT_OPEN, MSGL_INFO, "input_pnm: hexdump> "); |
8570 | 291 for (i = 0; i < length; i++) { |
292 unsigned char c = buf[i]; | |
293 | |
15626
941b1a71351f
printf converted to mp_msg; made static many unnecessarily global symbols
nicodvb
parents:
15614
diff
changeset
|
294 mp_msg(MSGT_OPEN, MSGL_INFO, "%02x", c); |
8570 | 295 |
296 if ((i % 16) == 15) | |
15626
941b1a71351f
printf converted to mp_msg; made static many unnecessarily global symbols
nicodvb
parents:
15614
diff
changeset
|
297 mp_msg(MSGT_OPEN, MSGL_INFO, "\npnm: "); |
8570 | 298 |
299 if ((i % 2) == 1) | |
15626
941b1a71351f
printf converted to mp_msg; made static many unnecessarily global symbols
nicodvb
parents:
15614
diff
changeset
|
300 mp_msg(MSGT_OPEN, MSGL_INFO, " "); |
8570 | 301 |
302 } | |
15626
941b1a71351f
printf converted to mp_msg; made static many unnecessarily global symbols
nicodvb
parents:
15614
diff
changeset
|
303 mp_msg(MSGT_OPEN, MSGL_INFO, "\n"); |
8570 | 304 } |
305 | |
306 /* | |
307 * pnm_get_chunk gets a chunk from stream | |
308 * and returns number of bytes read | |
309 */ | |
310 | |
15076
1a02a23202c2
Stop streaming if we got a server error or message on pnm streaming.
rtognimp
parents:
14164
diff
changeset
|
311 static int pnm_get_chunk(pnm_t *p, |
8570 | 312 unsigned int max, |
313 unsigned int *chunk_type, | |
314 char *data, int *need_response) { | |
315 | |
316 unsigned int chunk_size; | |
14164 | 317 unsigned int n; |
8570 | 318 char *ptr; |
319 | |
14164 | 320 if (max < PREAMBLE_SIZE) |
321 return -1; | |
322 | |
8570 | 323 /* get first PREAMBLE_SIZE bytes and ignore checksum */ |
324 rm_read (p->s, data, CHECKSUM_SIZE); | |
325 if (data[0] == 0x72) | |
326 rm_read (p->s, data, PREAMBLE_SIZE); | |
327 else | |
328 rm_read (p->s, data+CHECKSUM_SIZE, PREAMBLE_SIZE-CHECKSUM_SIZE); | |
329 | |
14164 | 330 max -= PREAMBLE_SIZE; |
331 | |
8570 | 332 *chunk_type = BE_32(data); |
333 chunk_size = BE_32(data+4); | |
334 | |
335 switch (*chunk_type) { | |
336 case PNA_TAG: | |
337 *need_response=0; | |
338 ptr=data+PREAMBLE_SIZE; | |
14164 | 339 if (max < 1) |
340 return -1; | |
8570 | 341 rm_read (p->s, ptr++, 1); |
14164 | 342 max -= 1; |
8570 | 343 |
344 while(1) { | |
345 /* expecting following chunk format: 0x4f <chunk size> <data...> */ | |
346 | |
14164 | 347 if (max < 2) |
348 return -1; | |
8570 | 349 rm_read (p->s, ptr, 2); |
14164 | 350 max -= 2; |
8570 | 351 if (*ptr == 'X') /* checking for server message */ |
352 { | |
15626
941b1a71351f
printf converted to mp_msg; made static many unnecessarily global symbols
nicodvb
parents:
15614
diff
changeset
|
353 mp_msg(MSGT_OPEN, MSGL_WARN, "input_pnm: got a message from server:\n"); |
14164 | 354 if (max < 1) |
355 return -1; | |
8570 | 356 rm_read (p->s, ptr+2, 1); |
14164 | 357 max = -1; |
8570 | 358 n=BE_16(ptr+1); |
14164 | 359 if (max < n) |
360 return -1; | |
8570 | 361 rm_read (p->s, ptr+3, n); |
14164 | 362 max -= n; |
8570 | 363 ptr[3+n]=0; |
15626
941b1a71351f
printf converted to mp_msg; made static many unnecessarily global symbols
nicodvb
parents:
15614
diff
changeset
|
364 mp_msg(MSGT_OPEN, MSGL_WARN, "%s\n",ptr+3); |
8570 | 365 return -1; |
366 } | |
367 | |
368 if (*ptr == 'F') /* checking for server error */ | |
369 { | |
15626
941b1a71351f
printf converted to mp_msg; made static many unnecessarily global symbols
nicodvb
parents:
15614
diff
changeset
|
370 mp_msg(MSGT_OPEN, MSGL_ERR, "input_pnm: server error.\n"); |
8570 | 371 return -1; |
372 } | |
373 if (*ptr == 'i') | |
374 { | |
375 ptr+=2; | |
376 *need_response=1; | |
377 continue; | |
378 } | |
379 if (*ptr != 0x4f) break; | |
380 n=ptr[1]; | |
14164 | 381 if (max < n) |
382 return -1; | |
8570 | 383 rm_read (p->s, ptr+2, n); |
14164 | 384 max -= n; |
8570 | 385 ptr+=(n+2); |
386 } | |
387 /* the checksum of the next chunk is ignored here */ | |
14164 | 388 if (max < 1) |
389 return -1; | |
8570 | 390 rm_read (p->s, ptr+2, 1); |
391 ptr+=3; | |
392 chunk_size=ptr-data; | |
393 break; | |
394 case RMF_TAG: | |
395 case DATA_TAG: | |
396 case PROP_TAG: | |
397 case MDPR_TAG: | |
398 case CONT_TAG: | |
14164 | 399 if (chunk_size > max || chunk_size < PREAMBLE_SIZE) { |
15626
941b1a71351f
printf converted to mp_msg; made static many unnecessarily global symbols
nicodvb
parents:
15614
diff
changeset
|
400 mp_msg(MSGT_OPEN, MSGL_ERR, "error: max chunk size exceded (max was 0x%04x)\n", max); |
14164 | 401 #ifdef LOG |
8570 | 402 n=rm_read (p->s, &data[PREAMBLE_SIZE], 0x100 - PREAMBLE_SIZE); |
403 hexdump(data,n+PREAMBLE_SIZE); | |
14164 | 404 #endif |
8570 | 405 return -1; |
406 } | |
407 rm_read (p->s, &data[PREAMBLE_SIZE], chunk_size-PREAMBLE_SIZE); | |
408 break; | |
409 default: | |
410 *chunk_type = 0; | |
411 chunk_size = PREAMBLE_SIZE; | |
412 break; | |
413 } | |
414 | |
415 return chunk_size; | |
416 } | |
417 | |
418 /* | |
419 * writes a chunk to a buffer, returns number of bytes written | |
420 */ | |
421 | |
422 static int pnm_write_chunk(uint16_t chunk_id, uint16_t length, | |
423 const char *chunk, char *data) { | |
424 | |
425 data[0]=(chunk_id>>8)%0xff; | |
426 data[1]=chunk_id%0xff; | |
427 data[2]=(length>>8)%0xff; | |
428 data[3]=length%0xff; | |
429 memcpy(&data[4],chunk,length); | |
430 | |
431 return length+4; | |
432 } | |
433 | |
434 /* | |
435 * constructs a request and sends it | |
436 */ | |
437 | |
438 static void pnm_send_request(pnm_t *p, uint32_t bandwidth) { | |
439 | |
440 uint16_t i16; | |
441 int c=PNM_HEADER_SIZE; | |
442 char fixme[]={0,1}; | |
443 | |
444 memcpy(p->buffer,pnm_header,PNM_HEADER_SIZE); | |
445 c+=pnm_write_chunk(PNA_CLIENT_CHALLANGE,strlen(pnm_challenge), | |
446 pnm_challenge,&p->buffer[c]); | |
447 c+=pnm_write_chunk(PNA_CLIENT_CAPS,PNM_CLIENT_CAPS_SIZE, | |
448 pnm_client_caps,&p->buffer[c]); | |
449 c+=pnm_write_chunk(0x0a,0,NULL,&p->buffer[c]); | |
450 c+=pnm_write_chunk(0x0c,0,NULL,&p->buffer[c]); | |
451 c+=pnm_write_chunk(0x0d,0,NULL,&p->buffer[c]); | |
452 c+=pnm_write_chunk(0x16,2,fixme,&p->buffer[c]); | |
453 c+=pnm_write_chunk(PNA_TIMESTAMP,strlen(pnm_timestamp), | |
454 pnm_timestamp,&p->buffer[c]); | |
455 c+=pnm_write_chunk(PNA_BANDWIDTH,4, | |
456 (const char *)&pnm_default_bandwidth,&p->buffer[c]); | |
457 c+=pnm_write_chunk(0x08,0,NULL,&p->buffer[c]); | |
458 c+=pnm_write_chunk(0x0e,0,NULL,&p->buffer[c]); | |
459 c+=pnm_write_chunk(0x0f,0,NULL,&p->buffer[c]); | |
460 c+=pnm_write_chunk(0x11,0,NULL,&p->buffer[c]); | |
461 c+=pnm_write_chunk(0x10,0,NULL,&p->buffer[c]); | |
462 c+=pnm_write_chunk(0x15,0,NULL,&p->buffer[c]); | |
463 c+=pnm_write_chunk(0x12,0,NULL,&p->buffer[c]); | |
464 c+=pnm_write_chunk(PNA_GUID,strlen(pnm_guid), | |
465 pnm_guid,&p->buffer[c]); | |
466 c+=pnm_write_chunk(PNA_TWENTYFOUR,PNM_TWENTYFOUR_SIZE, | |
467 pnm_twentyfour,&p->buffer[c]); | |
468 | |
469 /* data after chunks */ | |
470 memcpy(&p->buffer[c],after_chunks,after_chunks_length); | |
471 c+=after_chunks_length; | |
472 | |
473 /* client id string */ | |
474 p->buffer[c]=PNA_CLIENT_STRING; | |
11000 | 475 i16=BE_16D((strlen(client_string)-1)); /* don't know why do we have -1 here */ |
8570 | 476 memcpy(&p->buffer[c+1],&i16,2); |
477 memcpy(&p->buffer[c+3],client_string,strlen(client_string)+1); | |
478 c=c+3+strlen(client_string)+1; | |
479 | |
480 /* file path */ | |
481 p->buffer[c]=0; | |
482 p->buffer[c+1]=PNA_PATH_REQUEST; | |
483 i16=BE_16D(strlen(p->path)); | |
484 memcpy(&p->buffer[c+2],&i16,2); | |
485 memcpy(&p->buffer[c+4],p->path,strlen(p->path)); | |
486 c=c+4+strlen(p->path); | |
487 | |
488 /* some trailing bytes */ | |
489 p->buffer[c]='y'; | |
490 p->buffer[c+1]='B'; | |
491 | |
492 rm_write(p->s,p->buffer,c+2); | |
493 } | |
494 | |
495 /* | |
496 * pnm_send_response sends a response of a challenge | |
497 */ | |
498 | |
499 static void pnm_send_response(pnm_t *p, const char *response) { | |
500 | |
501 int size=strlen(response); | |
502 | |
503 p->buffer[0]=0x23; | |
504 p->buffer[1]=0; | |
505 p->buffer[2]=(unsigned char) size; | |
506 | |
507 memcpy(&p->buffer[3], response, size); | |
508 | |
509 rm_write (p->s, p->buffer, size+3); | |
510 | |
511 } | |
512 | |
513 /* | |
514 * get headers and challenge and fix headers | |
515 * write headers to p->header | |
516 * write challenge to p->buffer | |
517 * | |
518 * return 0 on error. != 0 on success | |
519 */ | |
520 | |
521 static int pnm_get_headers(pnm_t *p, int *need_response) { | |
522 | |
523 uint32_t chunk_type; | |
524 uint8_t *ptr=p->header; | |
525 uint8_t *prop_hdr=NULL; | |
526 int chunk_size,size=0; | |
527 int nr; | |
528 /* rmff_header_t *h; */ | |
529 | |
530 *need_response=0; | |
531 | |
532 while(1) { | |
533 if (HEADER_SIZE-size<=0) | |
534 { | |
15626
941b1a71351f
printf converted to mp_msg; made static many unnecessarily global symbols
nicodvb
parents:
15614
diff
changeset
|
535 mp_msg(MSGT_OPEN, MSGL_ERR, "input_pnm: header buffer overflow. exiting\n"); |
8570 | 536 return 0; |
537 } | |
538 chunk_size=pnm_get_chunk(p,HEADER_SIZE-size,&chunk_type,ptr,&nr); | |
539 if (chunk_size < 0) return 0; | |
540 if (chunk_type == 0) break; | |
541 if (chunk_type == PNA_TAG) | |
542 { | |
543 memcpy(ptr, rm_header, RM_HEADER_SIZE); | |
544 chunk_size=RM_HEADER_SIZE; | |
545 *need_response=nr; | |
546 } | |
547 if (chunk_type == DATA_TAG) | |
548 chunk_size=0; | |
549 if (chunk_type == RMF_TAG) | |
550 chunk_size=0; | |
551 if (chunk_type == PROP_TAG) | |
552 prop_hdr=ptr; | |
553 size+=chunk_size; | |
554 ptr+=chunk_size; | |
555 } | |
556 | |
8852 | 557 if (!prop_hdr) { |
15626
941b1a71351f
printf converted to mp_msg; made static many unnecessarily global symbols
nicodvb
parents:
15614
diff
changeset
|
558 mp_msg(MSGT_OPEN, MSGL_ERR, "input_pnm: error while parsing headers.\n"); |
8852 | 559 return 0; |
560 } | |
561 | |
8570 | 562 /* set data offset */ |
563 size--; | |
564 prop_hdr[42]=(size>>24)%0xff; | |
565 prop_hdr[43]=(size>>16)%0xff; | |
566 prop_hdr[44]=(size>>8)%0xff; | |
567 prop_hdr[45]=(size)%0xff; | |
568 size++; | |
569 | |
570 /* read challenge */ | |
571 memcpy (p->buffer, ptr, PREAMBLE_SIZE); | |
572 rm_read (p->s, &p->buffer[PREAMBLE_SIZE], 64); | |
573 | |
574 /* now write a data header */ | |
575 memcpy(ptr, pnm_data_header, PNM_DATA_HEADER_SIZE); | |
576 size+=PNM_DATA_HEADER_SIZE; | |
577 /* | |
578 h=rmff_scan_header(p->header); | |
579 rmff_fix_header(h); | |
580 p->header_len=rmff_get_header_size(h); | |
581 rmff_dump_header(h, p->header, HEADER_SIZE); | |
582 */ | |
583 p->header_len=size; | |
584 | |
585 return 1; | |
586 } | |
587 | |
588 /* | |
589 * determine correct stream number by looking at indices | |
590 */ | |
591 | |
592 static int pnm_calc_stream(pnm_t *p) { | |
593 | |
594 char str0=0,str1=0; | |
595 | |
596 /* looking at the first index to | |
597 * find possible stream types | |
598 */ | |
599 if (p->seq_current[0]==p->seq_num[0]) str0=1; | |
600 if (p->seq_current[0]==p->seq_num[2]) str1=1; | |
601 | |
602 switch (str0+str1) { | |
603 case 1: /* one is possible, good. */ | |
604 if (str0) | |
605 { | |
606 p->seq_num[0]++; | |
607 p->seq_num[1]=p->seq_current[1]+1; | |
608 return 0; | |
609 } else | |
610 { | |
611 p->seq_num[2]++; | |
612 p->seq_num[3]=p->seq_current[1]+1; | |
613 return 1; | |
614 } | |
615 break; | |
616 case 0: | |
617 case 2: /* both types or none possible, not so good */ | |
618 /* try to figure out by second index */ | |
619 if ( (p->seq_current[1] == p->seq_num[1]) | |
620 &&(p->seq_current[1] != p->seq_num[3])) | |
621 { | |
622 /* ok, only stream0 matches */ | |
623 p->seq_num[0]=p->seq_current[0]+1; | |
624 p->seq_num[1]++; | |
625 return 0; | |
626 } | |
627 if ( (p->seq_current[1] == p->seq_num[3]) | |
628 &&(p->seq_current[1] != p->seq_num[1])) | |
629 { | |
630 /* ok, only stream1 matches */ | |
631 p->seq_num[2]=p->seq_current[0]+1; | |
632 p->seq_num[3]++; | |
633 return 1; | |
634 } | |
635 /* wow, both streams match, or not. */ | |
636 /* now we try to decide by timestamps */ | |
637 if (p->ts_current < p->ts_last[1]) | |
638 return 0; | |
639 if (p->ts_current < p->ts_last[0]) | |
640 return 1; | |
641 /* does not help, we guess type 0 */ | |
642 #ifdef LOG | |
15626
941b1a71351f
printf converted to mp_msg; made static many unnecessarily global symbols
nicodvb
parents:
15614
diff
changeset
|
643 mp_msg(MSGT_OPEN, MSGL_INFO, "guessing stream# 0\n"); |
8570 | 644 #endif |
645 p->seq_num[0]=p->seq_current[0]+1; | |
646 p->seq_num[1]=p->seq_current[1]+1; | |
647 return 0; | |
648 break; | |
649 } | |
15626
941b1a71351f
printf converted to mp_msg; made static many unnecessarily global symbols
nicodvb
parents:
15614
diff
changeset
|
650 mp_msg(MSGT_OPEN, MSGL_ERR, "input_pnm: wow, something very nasty happened in pnm_calc_stream\n"); |
8570 | 651 return 2; |
652 } | |
653 | |
654 /* | |
655 * gets a stream chunk and writes it to a recieve buffer | |
656 */ | |
657 | |
658 static int pnm_get_stream_chunk(pnm_t *p) { | |
659 | |
660 int n; | |
661 char keepalive='!'; | |
662 unsigned int fof1, fof2, stream; | |
663 | |
664 /* send a keepalive */ | |
665 /* realplayer seems to do that every 43th package */ | |
666 if ((p->packet%43) == 42) | |
667 { | |
668 rm_write(p->s,&keepalive,1); | |
669 } | |
670 | |
671 /* data chunks begin with: 'Z' <o> <o> <i1> 'Z' <i2> | |
672 * where <o> is the offset to next stream chunk, | |
673 * <i1> is a 16 bit index | |
674 * <i2> is a 8 bit index which counts from 0x10 to somewhere | |
675 */ | |
676 | |
677 n = rm_read (p->s, p->buffer, 8); | |
15077
a893e0bfa9d6
"Fix" for pnm EOF detection (stop on read errors)
rtognimp
parents:
15076
diff
changeset
|
678 if (n<0) return -1; |
8570 | 679 if (n<8) return 0; |
680 | |
681 /* skip 8 bytes if 0x62 is read */ | |
682 if (p->buffer[0] == 0x62) | |
683 { | |
684 n = rm_read (p->s, p->buffer, 8); | |
685 if (n<8) return 0; | |
686 #ifdef LOG | |
15626
941b1a71351f
printf converted to mp_msg; made static many unnecessarily global symbols
nicodvb
parents:
15614
diff
changeset
|
687 mp_msg(MSGT_OPEN, MSGL_WARN, "input_pnm: had to seek 8 bytes on 0x62\n"); |
8570 | 688 #endif |
689 } | |
690 | |
691 /* a server message */ | |
692 if (p->buffer[0] == 'X') | |
693 { | |
694 int size=BE_16(&p->buffer[1]); | |
695 | |
696 rm_read (p->s, &p->buffer[8], size-5); | |
697 p->buffer[size+3]=0; | |
15626
941b1a71351f
printf converted to mp_msg; made static many unnecessarily global symbols
nicodvb
parents:
15614
diff
changeset
|
698 mp_msg(MSGT_OPEN, MSGL_WARN, "input_pnm: got message from server while reading stream:\n%s\n", &p->buffer[3]); |
15076
1a02a23202c2
Stop streaming if we got a server error or message on pnm streaming.
rtognimp
parents:
14164
diff
changeset
|
699 return -1; |
8570 | 700 } |
701 if (p->buffer[0] == 'F') | |
702 { | |
15626
941b1a71351f
printf converted to mp_msg; made static many unnecessarily global symbols
nicodvb
parents:
15614
diff
changeset
|
703 mp_msg(MSGT_OPEN, MSGL_ERR, "input_pnm: server error.\n"); |
15076
1a02a23202c2
Stop streaming if we got a server error or message on pnm streaming.
rtognimp
parents:
14164
diff
changeset
|
704 return -1; |
8570 | 705 } |
706 | |
707 /* skip bytewise to next chunk. | |
11000 | 708 * seems, that we don't need that, if we send enough |
8570 | 709 * keepalives |
710 */ | |
711 n=0; | |
712 while (p->buffer[0] != 0x5a) { | |
713 int i; | |
714 for (i=1; i<8; i++) { | |
715 p->buffer[i-1]=p->buffer[i]; | |
716 } | |
717 rm_read (p->s, &p->buffer[7], 1); | |
718 n++; | |
719 } | |
720 | |
721 #ifdef LOG | |
15626
941b1a71351f
printf converted to mp_msg; made static many unnecessarily global symbols
nicodvb
parents:
15614
diff
changeset
|
722 if (n) mp_msg(MSGT_OPEN, MSGL_WARN, "input_pnm: had to seek %i bytes to next chunk\n", n); |
8570 | 723 #endif |
724 | |
725 /* check for 'Z's */ | |
726 if ((p->buffer[0] != 0x5a)||(p->buffer[7] != 0x5a)) | |
727 { | |
15626
941b1a71351f
printf converted to mp_msg; made static many unnecessarily global symbols
nicodvb
parents:
15614
diff
changeset
|
728 mp_msg(MSGT_OPEN, MSGL_ERR, "input_pnm: bad boundaries\n"); |
8570 | 729 hexdump(p->buffer, 8); |
730 return 0; | |
731 } | |
732 | |
733 /* check offsets */ | |
734 fof1=BE_16(&p->buffer[1]); | |
735 fof2=BE_16(&p->buffer[3]); | |
736 if (fof1 != fof2) | |
737 { | |
15626
941b1a71351f
printf converted to mp_msg; made static many unnecessarily global symbols
nicodvb
parents:
15614
diff
changeset
|
738 mp_msg(MSGT_OPEN, MSGL_ERR, "input_pnm: frame offsets are different: 0x%04x 0x%04x\n",fof1,fof2); |
8570 | 739 return 0; |
740 } | |
741 | |
742 /* get first index */ | |
743 p->seq_current[0]=BE_16(&p->buffer[5]); | |
744 | |
745 /* now read the rest of stream chunk */ | |
746 n = rm_read (p->s, &p->recv[5], fof1-5); | |
747 if (n<(fof1-5)) return 0; | |
748 | |
749 /* get second index */ | |
750 p->seq_current[1]=p->recv[5]; | |
751 | |
752 /* get timestamp */ | |
753 p->ts_current=BE_32(&p->recv[6]); | |
754 | |
755 /* get stream number */ | |
756 stream=pnm_calc_stream(p); | |
757 | |
758 /* saving timestamp */ | |
759 p->ts_last[stream]=p->ts_current; | |
760 | |
761 /* constructing a data packet header */ | |
762 | |
763 p->recv[0]=0; /* object version */ | |
764 p->recv[1]=0; | |
765 | |
766 fof2=BE_16(&fof2); | |
767 memcpy(&p->recv[2], &fof2, 2); | |
768 /*p->recv[2]=(fof2>>8)%0xff;*/ /* length */ | |
769 /*p->recv[3]=(fof2)%0xff;*/ | |
770 | |
771 p->recv[4]=0; /* stream number */ | |
772 p->recv[5]=stream; | |
773 | |
774 p->recv[10]=p->recv[10] & 0xfe; /* streambox seems to do that... */ | |
775 | |
776 p->packet++; | |
777 | |
778 p->recv_size=fof1; | |
779 | |
780 return fof1; | |
781 } | |
782 | |
783 // pnm_t *pnm_connect(const char *mrl) { | |
15626
941b1a71351f
printf converted to mp_msg; made static many unnecessarily global symbols
nicodvb
parents:
15614
diff
changeset
|
784 static pnm_t *pnm_connect(int fd, char *path) { |
8570 | 785 |
786 pnm_t *p=malloc(sizeof(pnm_t)); | |
8852 | 787 int need_response=0; |
8570 | 788 |
789 p->path=strdup(path); | |
790 p->s=fd; | |
791 | |
792 pnm_send_request(p,pnm_available_bandwidths[10]); | |
793 if (!pnm_get_headers(p, &need_response)) { | |
15626
941b1a71351f
printf converted to mp_msg; made static many unnecessarily global symbols
nicodvb
parents:
15614
diff
changeset
|
794 mp_msg(MSGT_OPEN, MSGL_ERR, "input_pnm: failed to set up stream\n"); |
8570 | 795 free(p->path); |
796 free(p); | |
797 return NULL; | |
798 } | |
799 if (need_response) | |
800 pnm_send_response(p, pnm_response); | |
801 p->ts_last[0]=0; | |
802 p->ts_last[1]=0; | |
803 | |
804 /* copy header to recv */ | |
805 | |
806 memcpy(p->recv, p->header, p->header_len); | |
807 p->recv_size = p->header_len; | |
808 p->recv_read = 0; | |
809 | |
810 return p; | |
811 } | |
812 | |
15626
941b1a71351f
printf converted to mp_msg; made static many unnecessarily global symbols
nicodvb
parents:
15614
diff
changeset
|
813 static int pnm_read (pnm_t *this, char *data, int len) { |
8570 | 814 |
815 int to_copy=len; | |
816 char *dest=data; | |
817 char *source=this->recv + this->recv_read; | |
818 int fill=this->recv_size - this->recv_read; | |
15076
1a02a23202c2
Stop streaming if we got a server error or message on pnm streaming.
rtognimp
parents:
14164
diff
changeset
|
819 int retval; |
8570 | 820 |
821 if (len < 0) return 0; | |
822 while (to_copy > fill) { | |
823 | |
824 memcpy(dest, source, fill); | |
825 to_copy -= fill; | |
826 dest += fill; | |
827 this->recv_read=0; | |
828 | |
15076
1a02a23202c2
Stop streaming if we got a server error or message on pnm streaming.
rtognimp
parents:
14164
diff
changeset
|
829 if ((retval = pnm_get_stream_chunk (this)) <= 0) { |
8570 | 830 #ifdef LOG |
15626
941b1a71351f
printf converted to mp_msg; made static many unnecessarily global symbols
nicodvb
parents:
15614
diff
changeset
|
831 mp_msg(MSGT_OPEN, MSGL_INFO, "input_pnm: %d of %d bytes provided\n", len-to_copy, len); |
8570 | 832 #endif |
15076
1a02a23202c2
Stop streaming if we got a server error or message on pnm streaming.
rtognimp
parents:
14164
diff
changeset
|
833 if (retval < 0) |
1a02a23202c2
Stop streaming if we got a server error or message on pnm streaming.
rtognimp
parents:
14164
diff
changeset
|
834 return retval; |
1a02a23202c2
Stop streaming if we got a server error or message on pnm streaming.
rtognimp
parents:
14164
diff
changeset
|
835 else |
8570 | 836 return len-to_copy; |
837 } | |
838 source = this->recv; | |
839 fill = this->recv_size - this->recv_read; | |
840 } | |
841 | |
842 memcpy(dest, source, to_copy); | |
843 this->recv_read += to_copy; | |
844 | |
845 #ifdef LOG | |
15585 | 846 mp_msg(MSGT_OPEN, MSGL_INFO, "input_pnm: %d bytes provided\n", len); |
8570 | 847 #endif |
848 | |
849 return len; | |
850 } | |
851 | |
15585 | 852 static int pnm_peek_header (pnm_t *this, char *data) { |
8570 | 853 |
854 memcpy (data, this->header, this->header_len); | |
855 return this->header_len; | |
856 } | |
857 | |
15585 | 858 static void pnm_close(pnm_t *p) { |
8570 | 859 |
10281 | 860 if (p->s >= 0) closesocket(p->s); |
8570 | 861 free(p->path); |
862 free(p); | |
863 } | |
864 | |
15585 | 865 static int pnm_streaming_read( int fd, char *buffer, int size, streaming_ctrl_t *stream_ctrl ) { |
866 return pnm_read(stream_ctrl->data, buffer, size); | |
867 } | |
868 | |
869 static int open_s(stream_t *stream,int mode, void* opts, int* file_format) { | |
870 int fd; | |
871 pnm_t *pnm; | |
872 URL_t *url; | |
873 | |
874 mp_msg(MSGT_OPEN, MSGL_INFO, "STREAM_PNM, URL: %s\n", stream->url); | |
875 stream->streaming_ctrl = streaming_ctrl_new(); | |
876 if(stream->streaming_ctrl==NULL) { | |
877 return STREAM_ERROR; | |
878 } | |
879 stream->streaming_ctrl->bandwidth = network_bandwidth; | |
880 url = url_new(stream->url); | |
881 stream->streaming_ctrl->url = check4proxies(url); | |
882 //url_free(url); | |
883 | |
884 fd = connect2Server( stream->streaming_ctrl->url->hostname, | |
885 stream->streaming_ctrl->url->port ? stream->streaming_ctrl->url->port : 7070,1 ); | |
886 | |
887 if(fd<0) | |
888 goto fail; | |
889 | |
890 pnm = pnm_connect(fd,stream->streaming_ctrl->url->file); | |
891 if(!pnm) | |
892 goto fail; | |
893 stream->type = STREAMTYPE_STREAM; | |
894 stream->fd=fd; | |
895 stream->streaming_ctrl->data=pnm; | |
896 stream->streaming_ctrl->streaming_read = pnm_streaming_read; | |
897 //stream->streaming_ctrl->streaming_seek = nop_streaming_seek; | |
898 stream->streaming_ctrl->prebuffer_size = 8*1024; // 8 KBytes | |
899 stream->streaming_ctrl->buffering = 1; | |
900 stream->streaming_ctrl->status = streaming_playing_e; | |
901 *file_format = DEMUXER_TYPE_REAL; | |
902 fixup_network_stream_cache(stream); | |
903 return STREAM_OK; | |
904 | |
905 fail: | |
906 streaming_ctrl_free(stream->streaming_ctrl); | |
907 stream->streaming_ctrl = NULL; | |
908 return STREAM_UNSUPORTED; | |
909 } | |
910 | |
911 | |
912 stream_info_t stream_info_pnm = { | |
913 "RealNetworks pnm", | |
914 "pnm", | |
915 "Arpi, xine team", | |
916 "ported from xine", | |
917 open_s, | |
918 {"pnm", NULL}, //pnm as fallback | |
919 NULL, | |
920 0 // Urls are an option string | |
921 }; |