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