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