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