Mercurial > mplayer.hg
annotate libmpeg2/decode.c @ 32529:0624fa95a2aa
Make the file protocol read up to 64 kB at once when the cache is used,
assuming that files will generally be readable with high bandwidth.
This should improve performance when playing e.g. from high-latency
network shares.
author | reimar |
---|---|
date | Wed, 10 Nov 2010 17:21:28 +0000 |
parents | 32a214ee10e5 |
children |
rev | line source |
---|---|
9857 | 1 /* |
2 * decode.c | |
12932 | 3 * Copyright (C) 2000-2003 Michel Lespinasse <walken@zoy.org> |
9857 | 4 * Copyright (C) 1999-2000 Aaron Holtzman <aholtzma@ess.engr.uvic.ca> |
5 * | |
6 * This file is part of mpeg2dec, a free MPEG-2 video stream decoder. | |
7 * See http://libmpeg2.sourceforge.net/ for updates. | |
8 * | |
9 * mpeg2dec is free software; you can redistribute it and/or modify | |
10 * it under the terms of the GNU General Public License as published by | |
11 * the Free Software Foundation; either version 2 of the License, or | |
12 * (at your option) any later version. | |
13 * | |
14 * mpeg2dec is distributed in the hope that it will be useful, | |
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
17 * GNU General Public License for more details. | |
18 * | |
19 * You should have received a copy of the GNU General Public License | |
20 * along with this program; if not, write to the Free Software | |
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
22 */ | |
23 | |
24 #include "config.h" | |
25 | |
26 #include <string.h> /* memcmp/memset, try to remove */ | |
27 #include <stdlib.h> | |
28 #include <inttypes.h> | |
29 | |
30 #include "mpeg2.h" | |
12932 | 31 #include "attributes.h" |
9857 | 32 #include "mpeg2_internal.h" |
33 | |
34 static int mpeg2_accels = 0; | |
35 | |
36 #define BUFFER_SIZE (1194 * 1024) | |
37 | |
38 const mpeg2_info_t * mpeg2_info (mpeg2dec_t * mpeg2dec) | |
39 { | |
40 return &(mpeg2dec->info); | |
41 } | |
42 | |
43 static inline int skip_chunk (mpeg2dec_t * mpeg2dec, int bytes) | |
44 { | |
45 uint8_t * current; | |
46 uint32_t shift; | |
47 uint8_t * limit; | |
48 uint8_t byte; | |
49 | |
50 if (!bytes) | |
51 return 0; | |
52 | |
53 current = mpeg2dec->buf_start; | |
54 shift = mpeg2dec->shift; | |
55 limit = current + bytes; | |
56 | |
57 do { | |
58 byte = *current++; | |
59 if (shift == 0x00000100) { | |
60 int skipped; | |
61 | |
62 mpeg2dec->shift = 0xffffff00; | |
63 skipped = current - mpeg2dec->buf_start; | |
64 mpeg2dec->buf_start = current; | |
65 return skipped; | |
66 } | |
67 shift = (shift | byte) << 8; | |
68 } while (current < limit); | |
69 | |
70 mpeg2dec->shift = shift; | |
71 mpeg2dec->buf_start = current; | |
72 return 0; | |
73 } | |
74 | |
75 static inline int copy_chunk (mpeg2dec_t * mpeg2dec, int bytes) | |
76 { | |
77 uint8_t * current; | |
78 uint32_t shift; | |
79 uint8_t * chunk_ptr; | |
80 uint8_t * limit; | |
81 uint8_t byte; | |
82 | |
83 if (!bytes) | |
84 return 0; | |
85 | |
86 current = mpeg2dec->buf_start; | |
87 shift = mpeg2dec->shift; | |
88 chunk_ptr = mpeg2dec->chunk_ptr; | |
89 limit = current + bytes; | |
90 | |
91 do { | |
92 byte = *current++; | |
93 if (shift == 0x00000100) { | |
94 int copied; | |
95 | |
96 mpeg2dec->shift = 0xffffff00; | |
97 mpeg2dec->chunk_ptr = chunk_ptr + 1; | |
98 copied = current - mpeg2dec->buf_start; | |
99 mpeg2dec->buf_start = current; | |
100 return copied; | |
101 } | |
102 shift = (shift | byte) << 8; | |
103 *chunk_ptr++ = byte; | |
104 } while (current < limit); | |
105 | |
106 mpeg2dec->shift = shift; | |
107 mpeg2dec->buf_start = current; | |
108 return 0; | |
109 } | |
110 | |
111 void mpeg2_buffer (mpeg2dec_t * mpeg2dec, uint8_t * start, uint8_t * end) | |
112 { | |
113 mpeg2dec->buf_start = start; | |
114 mpeg2dec->buf_end = end; | |
115 } | |
116 | |
12932 | 117 int mpeg2_getpos (mpeg2dec_t * mpeg2dec) |
118 { | |
119 return mpeg2dec->buf_end - mpeg2dec->buf_start; | |
120 } | |
121 | |
122 static inline mpeg2_state_t seek_chunk (mpeg2dec_t * mpeg2dec) | |
9857 | 123 { |
124 int size, skipped; | |
125 | |
126 size = mpeg2dec->buf_end - mpeg2dec->buf_start; | |
127 skipped = skip_chunk (mpeg2dec, size); | |
128 if (!skipped) { | |
12932 | 129 mpeg2dec->bytes_since_tag += size; |
130 return STATE_BUFFER; | |
9857 | 131 } |
12932 | 132 mpeg2dec->bytes_since_tag += skipped; |
9857 | 133 mpeg2dec->code = mpeg2dec->buf_start[-1]; |
27572 | 134 return STATE_INTERNAL_NORETURN; |
9857 | 135 } |
136 | |
12932 | 137 mpeg2_state_t mpeg2_seek_header (mpeg2dec_t * mpeg2dec) |
9857 | 138 { |
27572 | 139 while (!(mpeg2dec->code == 0xb3 || |
140 ((mpeg2dec->code == 0xb7 || mpeg2dec->code == 0xb8 || | |
141 !mpeg2dec->code) && mpeg2dec->sequence.width != (unsigned)-1))) | |
12932 | 142 if (seek_chunk (mpeg2dec) == STATE_BUFFER) |
143 return STATE_BUFFER; | |
9857 | 144 mpeg2dec->chunk_start = mpeg2dec->chunk_ptr = mpeg2dec->chunk_buffer; |
12932 | 145 mpeg2dec->user_data_len = 0; |
27572 | 146 return ((mpeg2dec->code == 0xb7) ? |
147 mpeg2_header_end (mpeg2dec) : mpeg2_parse_header (mpeg2dec)); | |
9857 | 148 } |
149 | |
150 #define RECEIVED(code,state) (((state) << 8) + (code)) | |
151 | |
12932 | 152 mpeg2_state_t mpeg2_parse (mpeg2dec_t * mpeg2dec) |
9857 | 153 { |
154 int size_buffer, size_chunk, copied; | |
155 | |
12932 | 156 if (mpeg2dec->action) { |
157 mpeg2_state_t state; | |
158 | |
159 state = mpeg2dec->action (mpeg2dec); | |
27572 | 160 if ((int)state > (int)STATE_INTERNAL_NORETURN) |
12932 | 161 return state; |
9858
9af61fc7955c
changed input and output buffer handling to be mplayer-compatible...
arpi
parents:
9857
diff
changeset
|
162 } |
9af61fc7955c
changed input and output buffer handling to be mplayer-compatible...
arpi
parents:
9857
diff
changeset
|
163 |
9857 | 164 while (1) { |
165 while ((unsigned) (mpeg2dec->code - mpeg2dec->first_decode_slice) < | |
166 mpeg2dec->nb_decode_slices) { | |
167 size_buffer = mpeg2dec->buf_end - mpeg2dec->buf_start; | |
168 size_chunk = (mpeg2dec->chunk_buffer + BUFFER_SIZE - | |
169 mpeg2dec->chunk_ptr); | |
170 if (size_buffer <= size_chunk) { | |
171 copied = copy_chunk (mpeg2dec, size_buffer); | |
172 if (!copied) { | |
12932 | 173 mpeg2dec->bytes_since_tag += size_buffer; |
9857 | 174 mpeg2dec->chunk_ptr += size_buffer; |
12932 | 175 return STATE_BUFFER; |
9857 | 176 } |
177 } else { | |
178 copied = copy_chunk (mpeg2dec, size_chunk); | |
179 if (!copied) { | |
180 /* filled the chunk buffer without finding a start code */ | |
12932 | 181 mpeg2dec->bytes_since_tag += size_chunk; |
9857 | 182 mpeg2dec->action = seek_chunk; |
183 return STATE_INVALID; | |
184 } | |
185 } | |
12932 | 186 mpeg2dec->bytes_since_tag += copied; |
9857 | 187 |
188 mpeg2_slice (&(mpeg2dec->decoder), mpeg2dec->code, | |
189 mpeg2dec->chunk_start); | |
190 mpeg2dec->code = mpeg2dec->buf_start[-1]; | |
191 mpeg2dec->chunk_ptr = mpeg2dec->chunk_start; | |
192 } | |
193 if ((unsigned) (mpeg2dec->code - 1) >= 0xb0 - 1) | |
194 break; | |
12932 | 195 if (seek_chunk (mpeg2dec) == STATE_BUFFER) |
196 return STATE_BUFFER; | |
9858
9af61fc7955c
changed input and output buffer handling to be mplayer-compatible...
arpi
parents:
9857
diff
changeset
|
197 } |
9857 | 198 |
27572 | 199 mpeg2dec->action = mpeg2_seek_header; |
12932 | 200 switch (mpeg2dec->code) { |
201 case 0x00: | |
202 return mpeg2dec->state; | |
27572 | 203 case 0xb3: |
12932 | 204 case 0xb7: |
205 case 0xb8: | |
27572 | 206 return (mpeg2dec->state == STATE_SLICE) ? STATE_SLICE : STATE_INVALID; |
9857 | 207 default: |
12932 | 208 mpeg2dec->action = seek_chunk; |
9857 | 209 return STATE_INVALID; |
210 } | |
211 } | |
212 | |
12932 | 213 mpeg2_state_t mpeg2_parse_header (mpeg2dec_t * mpeg2dec) |
9857 | 214 { |
215 static int (* process_header[]) (mpeg2dec_t * mpeg2dec) = { | |
216 mpeg2_header_picture, mpeg2_header_extension, mpeg2_header_user_data, | |
217 mpeg2_header_sequence, NULL, NULL, NULL, NULL, mpeg2_header_gop | |
218 }; | |
219 int size_buffer, size_chunk, copied; | |
220 | |
221 mpeg2dec->action = mpeg2_parse_header; | |
12932 | 222 mpeg2dec->info.user_data = NULL; mpeg2dec->info.user_data_len = 0; |
9857 | 223 while (1) { |
224 size_buffer = mpeg2dec->buf_end - mpeg2dec->buf_start; | |
225 size_chunk = (mpeg2dec->chunk_buffer + BUFFER_SIZE - | |
226 mpeg2dec->chunk_ptr); | |
227 if (size_buffer <= size_chunk) { | |
228 copied = copy_chunk (mpeg2dec, size_buffer); | |
229 if (!copied) { | |
12932 | 230 mpeg2dec->bytes_since_tag += size_buffer; |
9857 | 231 mpeg2dec->chunk_ptr += size_buffer; |
12932 | 232 return STATE_BUFFER; |
9857 | 233 } |
234 } else { | |
235 copied = copy_chunk (mpeg2dec, size_chunk); | |
236 if (!copied) { | |
237 /* filled the chunk buffer without finding a start code */ | |
12932 | 238 mpeg2dec->bytes_since_tag += size_chunk; |
9857 | 239 mpeg2dec->code = 0xb4; |
240 mpeg2dec->action = mpeg2_seek_header; | |
241 return STATE_INVALID; | |
242 } | |
243 } | |
12932 | 244 mpeg2dec->bytes_since_tag += copied; |
9858
9af61fc7955c
changed input and output buffer handling to be mplayer-compatible...
arpi
parents:
9857
diff
changeset
|
245 |
9857 | 246 if (process_header[mpeg2dec->code & 0x0b] (mpeg2dec)) { |
247 mpeg2dec->code = mpeg2dec->buf_start[-1]; | |
248 mpeg2dec->action = mpeg2_seek_header; | |
249 return STATE_INVALID; | |
250 } | |
251 | |
252 mpeg2dec->code = mpeg2dec->buf_start[-1]; | |
253 switch (RECEIVED (mpeg2dec->code, mpeg2dec->state)) { | |
254 | |
255 /* state transition after a sequence header */ | |
256 case RECEIVED (0x00, STATE_SEQUENCE): | |
257 case RECEIVED (0xb8, STATE_SEQUENCE): | |
258 mpeg2_header_sequence_finalize (mpeg2dec); | |
259 break; | |
260 | |
261 /* other legal state transitions */ | |
262 case RECEIVED (0x00, STATE_GOP): | |
12932 | 263 mpeg2_header_gop_finalize (mpeg2dec); |
9857 | 264 break; |
265 case RECEIVED (0x01, STATE_PICTURE): | |
266 case RECEIVED (0x01, STATE_PICTURE_2ND): | |
12932 | 267 mpeg2_header_picture_finalize (mpeg2dec, mpeg2_accels); |
9857 | 268 mpeg2dec->action = mpeg2_header_slice_start; |
269 break; | |
270 | |
271 /* legal headers within a given state */ | |
272 case RECEIVED (0xb2, STATE_SEQUENCE): | |
273 case RECEIVED (0xb2, STATE_GOP): | |
274 case RECEIVED (0xb2, STATE_PICTURE): | |
275 case RECEIVED (0xb2, STATE_PICTURE_2ND): | |
276 case RECEIVED (0xb5, STATE_SEQUENCE): | |
277 case RECEIVED (0xb5, STATE_PICTURE): | |
278 case RECEIVED (0xb5, STATE_PICTURE_2ND): | |
279 mpeg2dec->chunk_ptr = mpeg2dec->chunk_start; | |
280 continue; | |
281 | |
282 default: | |
283 mpeg2dec->action = mpeg2_seek_header; | |
284 return STATE_INVALID; | |
285 } | |
286 | |
287 mpeg2dec->chunk_start = mpeg2dec->chunk_ptr = mpeg2dec->chunk_buffer; | |
12932 | 288 mpeg2dec->user_data_len = 0; |
9857 | 289 return mpeg2dec->state; |
290 } | |
291 } | |
292 | |
12932 | 293 int mpeg2_convert (mpeg2dec_t * mpeg2dec, mpeg2_convert_t convert, void * arg) |
9857 | 294 { |
12932 | 295 mpeg2_convert_init_t convert_init; |
296 int error; | |
9857 | 297 |
12932 | 298 error = convert (MPEG2_CONVERT_SET, NULL, &(mpeg2dec->sequence), 0, |
299 mpeg2_accels, arg, &convert_init); | |
300 if (!error) { | |
301 mpeg2dec->convert = convert; | |
302 mpeg2dec->convert_arg = arg; | |
303 mpeg2dec->convert_id_size = convert_init.id_size; | |
304 mpeg2dec->convert_stride = 0; | |
9857 | 305 } |
12932 | 306 return error; |
307 } | |
9857 | 308 |
12932 | 309 int mpeg2_stride (mpeg2dec_t * mpeg2dec, int stride) |
310 { | |
311 if (!mpeg2dec->convert) { | |
312 if (stride < (int) mpeg2dec->sequence.width) | |
313 stride = mpeg2dec->sequence.width; | |
314 mpeg2dec->decoder.stride_frame = stride; | |
315 } else { | |
316 mpeg2_convert_init_t convert_init; | |
317 | |
318 stride = mpeg2dec->convert (MPEG2_CONVERT_STRIDE, NULL, | |
319 &(mpeg2dec->sequence), stride, | |
320 mpeg2_accels, mpeg2dec->convert_arg, | |
321 &convert_init); | |
322 mpeg2dec->convert_id_size = convert_init.id_size; | |
323 mpeg2dec->convert_stride = stride; | |
324 } | |
325 return stride; | |
9857 | 326 } |
327 | |
328 void mpeg2_set_buf (mpeg2dec_t * mpeg2dec, uint8_t * buf[3], void * id) | |
329 { | |
12932 | 330 mpeg2_fbuf_t * fbuf; |
9857 | 331 |
332 if (mpeg2dec->custom_fbuf) { | |
333 if (mpeg2dec->state == STATE_SEQUENCE) { | |
334 mpeg2dec->fbuf[2] = mpeg2dec->fbuf[1]; | |
335 mpeg2dec->fbuf[1] = mpeg2dec->fbuf[0]; | |
336 } | |
12932 | 337 mpeg2_set_fbuf (mpeg2dec, (mpeg2dec->decoder.coding_type == |
338 PIC_FLAG_CODING_TYPE_B)); | |
339 fbuf = mpeg2dec->fbuf[0]; | |
9857 | 340 } else { |
341 fbuf = &(mpeg2dec->fbuf_alloc[mpeg2dec->alloc_index].fbuf); | |
342 mpeg2dec->alloc_index_user = ++mpeg2dec->alloc_index; | |
343 } | |
344 fbuf->buf[0] = buf[0]; | |
345 fbuf->buf[1] = buf[1]; | |
346 fbuf->buf[2] = buf[2]; | |
347 fbuf->id = id; | |
31860 | 348 // HACK! FIXME! At first I frame, copy pointers to prediction frame too! |
349 if (mpeg2dec->custom_fbuf && !mpeg2dec->fbuf[1]->buf[0]) { | |
350 mpeg2dec->fbuf[1]->buf[0] = buf[0]; | |
351 mpeg2dec->fbuf[1]->buf[1] = buf[1]; | |
352 mpeg2dec->fbuf[1]->buf[2] = buf[2]; | |
353 mpeg2dec->fbuf[1]->id = NULL; | |
354 } | |
9857 | 355 } |
356 | |
357 void mpeg2_custom_fbuf (mpeg2dec_t * mpeg2dec, int custom_fbuf) | |
358 { | |
359 mpeg2dec->custom_fbuf = custom_fbuf; | |
360 } | |
361 | |
362 void mpeg2_skip (mpeg2dec_t * mpeg2dec, int skip) | |
363 { | |
364 mpeg2dec->first_decode_slice = 1; | |
365 mpeg2dec->nb_decode_slices = skip ? 0 : (0xb0 - 1); | |
366 } | |
367 | |
368 void mpeg2_slice_region (mpeg2dec_t * mpeg2dec, int start, int end) | |
369 { | |
370 start = (start < 1) ? 1 : (start > 0xb0) ? 0xb0 : start; | |
371 end = (end < start) ? start : (end > 0xb0) ? 0xb0 : end; | |
372 mpeg2dec->first_decode_slice = start; | |
373 mpeg2dec->nb_decode_slices = end - start; | |
374 } | |
375 | |
12932 | 376 void mpeg2_tag_picture (mpeg2dec_t * mpeg2dec, uint32_t tag, uint32_t tag2) |
9857 | 377 { |
12932 | 378 mpeg2dec->tag_previous = mpeg2dec->tag_current; |
379 mpeg2dec->tag2_previous = mpeg2dec->tag2_current; | |
380 mpeg2dec->tag_current = tag; | |
381 mpeg2dec->tag2_current = tag2; | |
382 mpeg2dec->num_tags++; | |
383 mpeg2dec->bytes_since_tag = 0; | |
9857 | 384 } |
385 | |
386 uint32_t mpeg2_accel (uint32_t accel) | |
387 { | |
388 if (!mpeg2_accels) { | |
27572 | 389 mpeg2_accels = mpeg2_detect_accel (accel) | MPEG2_ACCEL_DETECT; |
390 mpeg2_cpu_state_init (mpeg2_accels); | |
391 mpeg2_idct_init (mpeg2_accels); | |
392 mpeg2_mc_init (mpeg2_accels); | |
9857 | 393 } |
394 return mpeg2_accels & ~MPEG2_ACCEL_DETECT; | |
395 } | |
396 | |
12932 | 397 void mpeg2_reset (mpeg2dec_t * mpeg2dec, int full_reset) |
398 { | |
399 mpeg2dec->buf_start = mpeg2dec->buf_end = NULL; | |
400 mpeg2dec->num_tags = 0; | |
401 mpeg2dec->shift = 0xffffff00; | |
402 mpeg2dec->code = 0xb4; | |
403 mpeg2dec->action = mpeg2_seek_header; | |
404 mpeg2dec->state = STATE_INVALID; | |
405 mpeg2dec->first = 1; | |
406 | |
407 mpeg2_reset_info(&(mpeg2dec->info)); | |
408 mpeg2dec->info.gop = NULL; | |
409 mpeg2dec->info.user_data = NULL; | |
410 mpeg2dec->info.user_data_len = 0; | |
411 if (full_reset) { | |
412 mpeg2dec->info.sequence = NULL; | |
413 mpeg2_header_state_init (mpeg2dec); | |
414 } | |
415 | |
416 } | |
417 | |
9857 | 418 mpeg2dec_t * mpeg2_init (void) |
419 { | |
420 mpeg2dec_t * mpeg2dec; | |
421 | |
422 mpeg2_accel (MPEG2_ACCEL_DETECT); | |
423 | |
424 mpeg2dec = (mpeg2dec_t *) mpeg2_malloc (sizeof (mpeg2dec_t), | |
12932 | 425 MPEG2_ALLOC_MPEG2DEC); |
9857 | 426 if (mpeg2dec == NULL) |
427 return NULL; | |
428 | |
12932 | 429 memset (mpeg2dec->decoder.DCTblock, 0, 64 * sizeof (int16_t)); |
430 memset (mpeg2dec->quantizer_matrix, 0, 4 * 64 * sizeof (uint8_t)); | |
9857 | 431 |
432 mpeg2dec->chunk_buffer = (uint8_t *) mpeg2_malloc (BUFFER_SIZE + 4, | |
12932 | 433 MPEG2_ALLOC_CHUNK); |
9857 | 434 |
12932 | 435 mpeg2dec->sequence.width = (unsigned)-1; |
436 mpeg2_reset (mpeg2dec, 1); | |
9857 | 437 |
438 return mpeg2dec; | |
439 } | |
440 | |
441 void mpeg2_close (mpeg2dec_t * mpeg2dec) | |
442 { | |
12932 | 443 mpeg2_header_state_init (mpeg2dec); |
9857 | 444 mpeg2_free (mpeg2dec->chunk_buffer); |
445 mpeg2_free (mpeg2dec); | |
446 } |