Mercurial > mplayer.hg
annotate libmpeg2/decode.c @ 29851:eaa7bfc52c2c
Set the EOF flag when dvdnav reached the end of the requested title.
Otherwise it would just hang, either at the menu or trying to play the
last played frame as a still frame.
author | reimar |
---|---|
date | Wed, 11 Nov 2009 09:09:08 +0000 |
parents | da2271c341ee |
children | 020ae1402728 |
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 | |
14732
1385ec491ffb
Mark locally modified files as such to comply more closely with GPL 2a.
diego
parents:
12932
diff
changeset
|
22 * |
27571
fd18fa10de53
libmpeg-0.4.1.diff was renamed to libmpeg2_changes.diff.
diego
parents:
21526
diff
changeset
|
23 * Modified for use with MPlayer, see libmpeg2_changes.diff for the exact changes. |
18783 | 24 * detailed changelog at http://svn.mplayerhq.hu/mplayer/trunk/ |
14732
1385ec491ffb
Mark locally modified files as such to comply more closely with GPL 2a.
diego
parents:
12932
diff
changeset
|
25 * $Id$ |
9857 | 26 */ |
27 | |
28 #include "config.h" | |
29 | |
30 #include <string.h> /* memcmp/memset, try to remove */ | |
31 #include <stdlib.h> | |
32 #include <inttypes.h> | |
33 | |
34 #include "mpeg2.h" | |
12932 | 35 #include "attributes.h" |
9857 | 36 #include "mpeg2_internal.h" |
37 | |
38 static int mpeg2_accels = 0; | |
39 | |
40 #define BUFFER_SIZE (1194 * 1024) | |
41 | |
42 const mpeg2_info_t * mpeg2_info (mpeg2dec_t * mpeg2dec) | |
43 { | |
44 return &(mpeg2dec->info); | |
45 } | |
46 | |
47 static inline int skip_chunk (mpeg2dec_t * mpeg2dec, int bytes) | |
48 { | |
49 uint8_t * current; | |
50 uint32_t shift; | |
51 uint8_t * limit; | |
52 uint8_t byte; | |
53 | |
54 if (!bytes) | |
55 return 0; | |
56 | |
57 current = mpeg2dec->buf_start; | |
58 shift = mpeg2dec->shift; | |
59 limit = current + bytes; | |
60 | |
61 do { | |
62 byte = *current++; | |
63 if (shift == 0x00000100) { | |
64 int skipped; | |
65 | |
66 mpeg2dec->shift = 0xffffff00; | |
67 skipped = current - mpeg2dec->buf_start; | |
68 mpeg2dec->buf_start = current; | |
69 return skipped; | |
70 } | |
71 shift = (shift | byte) << 8; | |
72 } while (current < limit); | |
73 | |
74 mpeg2dec->shift = shift; | |
75 mpeg2dec->buf_start = current; | |
76 return 0; | |
77 } | |
78 | |
79 static inline int copy_chunk (mpeg2dec_t * mpeg2dec, int bytes) | |
80 { | |
81 uint8_t * current; | |
82 uint32_t shift; | |
83 uint8_t * chunk_ptr; | |
84 uint8_t * limit; | |
85 uint8_t byte; | |
86 | |
87 if (!bytes) | |
88 return 0; | |
89 | |
90 current = mpeg2dec->buf_start; | |
91 shift = mpeg2dec->shift; | |
92 chunk_ptr = mpeg2dec->chunk_ptr; | |
93 limit = current + bytes; | |
94 | |
95 do { | |
96 byte = *current++; | |
97 if (shift == 0x00000100) { | |
98 int copied; | |
99 | |
100 mpeg2dec->shift = 0xffffff00; | |
101 mpeg2dec->chunk_ptr = chunk_ptr + 1; | |
102 copied = current - mpeg2dec->buf_start; | |
103 mpeg2dec->buf_start = current; | |
104 return copied; | |
105 } | |
106 shift = (shift | byte) << 8; | |
107 *chunk_ptr++ = byte; | |
108 } while (current < limit); | |
109 | |
110 mpeg2dec->shift = shift; | |
111 mpeg2dec->buf_start = current; | |
112 return 0; | |
113 } | |
114 | |
115 void mpeg2_buffer (mpeg2dec_t * mpeg2dec, uint8_t * start, uint8_t * end) | |
116 { | |
117 mpeg2dec->buf_start = start; | |
118 mpeg2dec->buf_end = end; | |
119 } | |
120 | |
12932 | 121 int mpeg2_getpos (mpeg2dec_t * mpeg2dec) |
122 { | |
123 return mpeg2dec->buf_end - mpeg2dec->buf_start; | |
124 } | |
125 | |
126 static inline mpeg2_state_t seek_chunk (mpeg2dec_t * mpeg2dec) | |
9857 | 127 { |
128 int size, skipped; | |
129 | |
130 size = mpeg2dec->buf_end - mpeg2dec->buf_start; | |
131 skipped = skip_chunk (mpeg2dec, size); | |
132 if (!skipped) { | |
12932 | 133 mpeg2dec->bytes_since_tag += size; |
134 return STATE_BUFFER; | |
9857 | 135 } |
12932 | 136 mpeg2dec->bytes_since_tag += skipped; |
9857 | 137 mpeg2dec->code = mpeg2dec->buf_start[-1]; |
27572 | 138 return STATE_INTERNAL_NORETURN; |
9857 | 139 } |
140 | |
12932 | 141 mpeg2_state_t mpeg2_seek_header (mpeg2dec_t * mpeg2dec) |
9857 | 142 { |
27572 | 143 while (!(mpeg2dec->code == 0xb3 || |
144 ((mpeg2dec->code == 0xb7 || mpeg2dec->code == 0xb8 || | |
145 !mpeg2dec->code) && mpeg2dec->sequence.width != (unsigned)-1))) | |
12932 | 146 if (seek_chunk (mpeg2dec) == STATE_BUFFER) |
147 return STATE_BUFFER; | |
9857 | 148 mpeg2dec->chunk_start = mpeg2dec->chunk_ptr = mpeg2dec->chunk_buffer; |
12932 | 149 mpeg2dec->user_data_len = 0; |
27572 | 150 return ((mpeg2dec->code == 0xb7) ? |
151 mpeg2_header_end (mpeg2dec) : mpeg2_parse_header (mpeg2dec)); | |
9857 | 152 } |
153 | |
154 #define RECEIVED(code,state) (((state) << 8) + (code)) | |
155 | |
12932 | 156 mpeg2_state_t mpeg2_parse (mpeg2dec_t * mpeg2dec) |
9857 | 157 { |
158 int size_buffer, size_chunk, copied; | |
159 | |
12932 | 160 if (mpeg2dec->action) { |
161 mpeg2_state_t state; | |
162 | |
163 state = mpeg2dec->action (mpeg2dec); | |
27572 | 164 if ((int)state > (int)STATE_INTERNAL_NORETURN) |
12932 | 165 return state; |
9858
9af61fc7955c
changed input and output buffer handling to be mplayer-compatible...
arpi
parents:
9857
diff
changeset
|
166 } |
9af61fc7955c
changed input and output buffer handling to be mplayer-compatible...
arpi
parents:
9857
diff
changeset
|
167 |
9857 | 168 while (1) { |
169 while ((unsigned) (mpeg2dec->code - mpeg2dec->first_decode_slice) < | |
170 mpeg2dec->nb_decode_slices) { | |
171 size_buffer = mpeg2dec->buf_end - mpeg2dec->buf_start; | |
172 size_chunk = (mpeg2dec->chunk_buffer + BUFFER_SIZE - | |
173 mpeg2dec->chunk_ptr); | |
174 if (size_buffer <= size_chunk) { | |
175 copied = copy_chunk (mpeg2dec, size_buffer); | |
176 if (!copied) { | |
12932 | 177 mpeg2dec->bytes_since_tag += size_buffer; |
9857 | 178 mpeg2dec->chunk_ptr += size_buffer; |
12932 | 179 return STATE_BUFFER; |
9857 | 180 } |
181 } else { | |
182 copied = copy_chunk (mpeg2dec, size_chunk); | |
183 if (!copied) { | |
184 /* filled the chunk buffer without finding a start code */ | |
12932 | 185 mpeg2dec->bytes_since_tag += size_chunk; |
9857 | 186 mpeg2dec->action = seek_chunk; |
187 return STATE_INVALID; | |
188 } | |
189 } | |
12932 | 190 mpeg2dec->bytes_since_tag += copied; |
9857 | 191 |
192 mpeg2_slice (&(mpeg2dec->decoder), mpeg2dec->code, | |
193 mpeg2dec->chunk_start); | |
194 mpeg2dec->code = mpeg2dec->buf_start[-1]; | |
195 mpeg2dec->chunk_ptr = mpeg2dec->chunk_start; | |
196 } | |
197 if ((unsigned) (mpeg2dec->code - 1) >= 0xb0 - 1) | |
198 break; | |
12932 | 199 if (seek_chunk (mpeg2dec) == STATE_BUFFER) |
200 return STATE_BUFFER; | |
9858
9af61fc7955c
changed input and output buffer handling to be mplayer-compatible...
arpi
parents:
9857
diff
changeset
|
201 } |
9857 | 202 |
27572 | 203 mpeg2dec->action = mpeg2_seek_header; |
12932 | 204 switch (mpeg2dec->code) { |
205 case 0x00: | |
206 return mpeg2dec->state; | |
27572 | 207 case 0xb3: |
12932 | 208 case 0xb7: |
209 case 0xb8: | |
27572 | 210 return (mpeg2dec->state == STATE_SLICE) ? STATE_SLICE : STATE_INVALID; |
9857 | 211 default: |
12932 | 212 mpeg2dec->action = seek_chunk; |
9857 | 213 return STATE_INVALID; |
214 } | |
215 } | |
216 | |
12932 | 217 mpeg2_state_t mpeg2_parse_header (mpeg2dec_t * mpeg2dec) |
9857 | 218 { |
219 static int (* process_header[]) (mpeg2dec_t * mpeg2dec) = { | |
220 mpeg2_header_picture, mpeg2_header_extension, mpeg2_header_user_data, | |
221 mpeg2_header_sequence, NULL, NULL, NULL, NULL, mpeg2_header_gop | |
222 }; | |
223 int size_buffer, size_chunk, copied; | |
224 | |
225 mpeg2dec->action = mpeg2_parse_header; | |
12932 | 226 mpeg2dec->info.user_data = NULL; mpeg2dec->info.user_data_len = 0; |
9857 | 227 while (1) { |
228 size_buffer = mpeg2dec->buf_end - mpeg2dec->buf_start; | |
229 size_chunk = (mpeg2dec->chunk_buffer + BUFFER_SIZE - | |
230 mpeg2dec->chunk_ptr); | |
231 if (size_buffer <= size_chunk) { | |
232 copied = copy_chunk (mpeg2dec, size_buffer); | |
233 if (!copied) { | |
12932 | 234 mpeg2dec->bytes_since_tag += size_buffer; |
9857 | 235 mpeg2dec->chunk_ptr += size_buffer; |
12932 | 236 return STATE_BUFFER; |
9857 | 237 } |
238 } else { | |
239 copied = copy_chunk (mpeg2dec, size_chunk); | |
240 if (!copied) { | |
241 /* filled the chunk buffer without finding a start code */ | |
12932 | 242 mpeg2dec->bytes_since_tag += size_chunk; |
9857 | 243 mpeg2dec->code = 0xb4; |
244 mpeg2dec->action = mpeg2_seek_header; | |
245 return STATE_INVALID; | |
246 } | |
247 } | |
12932 | 248 mpeg2dec->bytes_since_tag += copied; |
9858
9af61fc7955c
changed input and output buffer handling to be mplayer-compatible...
arpi
parents:
9857
diff
changeset
|
249 |
9857 | 250 if (process_header[mpeg2dec->code & 0x0b] (mpeg2dec)) { |
251 mpeg2dec->code = mpeg2dec->buf_start[-1]; | |
252 mpeg2dec->action = mpeg2_seek_header; | |
253 return STATE_INVALID; | |
254 } | |
255 | |
256 mpeg2dec->code = mpeg2dec->buf_start[-1]; | |
257 switch (RECEIVED (mpeg2dec->code, mpeg2dec->state)) { | |
258 | |
259 /* state transition after a sequence header */ | |
260 case RECEIVED (0x00, STATE_SEQUENCE): | |
261 case RECEIVED (0xb8, STATE_SEQUENCE): | |
262 mpeg2_header_sequence_finalize (mpeg2dec); | |
263 break; | |
264 | |
265 /* other legal state transitions */ | |
266 case RECEIVED (0x00, STATE_GOP): | |
12932 | 267 mpeg2_header_gop_finalize (mpeg2dec); |
9857 | 268 break; |
269 case RECEIVED (0x01, STATE_PICTURE): | |
270 case RECEIVED (0x01, STATE_PICTURE_2ND): | |
12932 | 271 mpeg2_header_picture_finalize (mpeg2dec, mpeg2_accels); |
9857 | 272 mpeg2dec->action = mpeg2_header_slice_start; |
273 break; | |
274 | |
275 /* legal headers within a given state */ | |
276 case RECEIVED (0xb2, STATE_SEQUENCE): | |
277 case RECEIVED (0xb2, STATE_GOP): | |
278 case RECEIVED (0xb2, STATE_PICTURE): | |
279 case RECEIVED (0xb2, STATE_PICTURE_2ND): | |
280 case RECEIVED (0xb5, STATE_SEQUENCE): | |
281 case RECEIVED (0xb5, STATE_PICTURE): | |
282 case RECEIVED (0xb5, STATE_PICTURE_2ND): | |
283 mpeg2dec->chunk_ptr = mpeg2dec->chunk_start; | |
284 continue; | |
285 | |
286 default: | |
287 mpeg2dec->action = mpeg2_seek_header; | |
288 return STATE_INVALID; | |
289 } | |
290 | |
291 mpeg2dec->chunk_start = mpeg2dec->chunk_ptr = mpeg2dec->chunk_buffer; | |
12932 | 292 mpeg2dec->user_data_len = 0; |
9857 | 293 return mpeg2dec->state; |
294 } | |
295 } | |
296 | |
12932 | 297 int mpeg2_convert (mpeg2dec_t * mpeg2dec, mpeg2_convert_t convert, void * arg) |
9857 | 298 { |
12932 | 299 mpeg2_convert_init_t convert_init; |
300 int error; | |
9857 | 301 |
12932 | 302 error = convert (MPEG2_CONVERT_SET, NULL, &(mpeg2dec->sequence), 0, |
303 mpeg2_accels, arg, &convert_init); | |
304 if (!error) { | |
305 mpeg2dec->convert = convert; | |
306 mpeg2dec->convert_arg = arg; | |
307 mpeg2dec->convert_id_size = convert_init.id_size; | |
308 mpeg2dec->convert_stride = 0; | |
9857 | 309 } |
12932 | 310 return error; |
311 } | |
9857 | 312 |
12932 | 313 int mpeg2_stride (mpeg2dec_t * mpeg2dec, int stride) |
314 { | |
315 if (!mpeg2dec->convert) { | |
316 if (stride < (int) mpeg2dec->sequence.width) | |
317 stride = mpeg2dec->sequence.width; | |
318 mpeg2dec->decoder.stride_frame = stride; | |
319 } else { | |
320 mpeg2_convert_init_t convert_init; | |
321 | |
322 stride = mpeg2dec->convert (MPEG2_CONVERT_STRIDE, NULL, | |
323 &(mpeg2dec->sequence), stride, | |
324 mpeg2_accels, mpeg2dec->convert_arg, | |
325 &convert_init); | |
326 mpeg2dec->convert_id_size = convert_init.id_size; | |
327 mpeg2dec->convert_stride = stride; | |
328 } | |
329 return stride; | |
9857 | 330 } |
331 | |
332 void mpeg2_set_buf (mpeg2dec_t * mpeg2dec, uint8_t * buf[3], void * id) | |
333 { | |
12932 | 334 mpeg2_fbuf_t * fbuf; |
9857 | 335 |
336 if (mpeg2dec->custom_fbuf) { | |
337 if (mpeg2dec->state == STATE_SEQUENCE) { | |
338 mpeg2dec->fbuf[2] = mpeg2dec->fbuf[1]; | |
339 mpeg2dec->fbuf[1] = mpeg2dec->fbuf[0]; | |
340 } | |
12932 | 341 mpeg2_set_fbuf (mpeg2dec, (mpeg2dec->decoder.coding_type == |
342 PIC_FLAG_CODING_TYPE_B)); | |
343 fbuf = mpeg2dec->fbuf[0]; | |
9857 | 344 } else { |
345 fbuf = &(mpeg2dec->fbuf_alloc[mpeg2dec->alloc_index].fbuf); | |
346 mpeg2dec->alloc_index_user = ++mpeg2dec->alloc_index; | |
347 } | |
348 fbuf->buf[0] = buf[0]; | |
349 fbuf->buf[1] = buf[1]; | |
350 fbuf->buf[2] = buf[2]; | |
351 fbuf->id = id; | |
9858
9af61fc7955c
changed input and output buffer handling to be mplayer-compatible...
arpi
parents:
9857
diff
changeset
|
352 // HACK! FIXME! At first I frame, copy pointers to prediction frame too! |
9af61fc7955c
changed input and output buffer handling to be mplayer-compatible...
arpi
parents:
9857
diff
changeset
|
353 if (mpeg2dec->custom_fbuf && !mpeg2dec->fbuf[1]->buf[0]){ |
9af61fc7955c
changed input and output buffer handling to be mplayer-compatible...
arpi
parents:
9857
diff
changeset
|
354 mpeg2dec->fbuf[1]->buf[0]=buf[0]; |
9af61fc7955c
changed input and output buffer handling to be mplayer-compatible...
arpi
parents:
9857
diff
changeset
|
355 mpeg2dec->fbuf[1]->buf[1]=buf[1]; |
9af61fc7955c
changed input and output buffer handling to be mplayer-compatible...
arpi
parents:
9857
diff
changeset
|
356 mpeg2dec->fbuf[1]->buf[2]=buf[2]; |
9af61fc7955c
changed input and output buffer handling to be mplayer-compatible...
arpi
parents:
9857
diff
changeset
|
357 mpeg2dec->fbuf[1]->id=NULL; |
9af61fc7955c
changed input and output buffer handling to be mplayer-compatible...
arpi
parents:
9857
diff
changeset
|
358 } |
27572 | 359 // printf("libmpeg2: FBUF 0:%p 1:%p 2:%p\n", |
360 // mpeg2dec->fbuf[0]->buf[0],mpeg2dec->fbuf[1]->buf[0],mpeg2dec->fbuf[2]->buf[0]); | |
9857 | 361 } |
362 | |
363 void mpeg2_custom_fbuf (mpeg2dec_t * mpeg2dec, int custom_fbuf) | |
364 { | |
365 mpeg2dec->custom_fbuf = custom_fbuf; | |
366 } | |
367 | |
368 void mpeg2_skip (mpeg2dec_t * mpeg2dec, int skip) | |
369 { | |
370 mpeg2dec->first_decode_slice = 1; | |
371 mpeg2dec->nb_decode_slices = skip ? 0 : (0xb0 - 1); | |
372 } | |
373 | |
374 void mpeg2_slice_region (mpeg2dec_t * mpeg2dec, int start, int end) | |
375 { | |
376 start = (start < 1) ? 1 : (start > 0xb0) ? 0xb0 : start; | |
377 end = (end < start) ? start : (end > 0xb0) ? 0xb0 : end; | |
378 mpeg2dec->first_decode_slice = start; | |
379 mpeg2dec->nb_decode_slices = end - start; | |
380 } | |
381 | |
12932 | 382 void mpeg2_tag_picture (mpeg2dec_t * mpeg2dec, uint32_t tag, uint32_t tag2) |
9857 | 383 { |
12932 | 384 mpeg2dec->tag_previous = mpeg2dec->tag_current; |
385 mpeg2dec->tag2_previous = mpeg2dec->tag2_current; | |
386 mpeg2dec->tag_current = tag; | |
387 mpeg2dec->tag2_current = tag2; | |
388 mpeg2dec->num_tags++; | |
389 mpeg2dec->bytes_since_tag = 0; | |
9857 | 390 } |
391 | |
392 uint32_t mpeg2_accel (uint32_t accel) | |
393 { | |
394 if (!mpeg2_accels) { | |
27572 | 395 mpeg2_accels = mpeg2_detect_accel (accel) | MPEG2_ACCEL_DETECT; |
396 mpeg2_cpu_state_init (mpeg2_accels); | |
397 mpeg2_idct_init (mpeg2_accels); | |
398 mpeg2_mc_init (mpeg2_accels); | |
9857 | 399 } |
400 return mpeg2_accels & ~MPEG2_ACCEL_DETECT; | |
401 } | |
402 | |
12932 | 403 void mpeg2_reset (mpeg2dec_t * mpeg2dec, int full_reset) |
404 { | |
405 mpeg2dec->buf_start = mpeg2dec->buf_end = NULL; | |
406 mpeg2dec->num_tags = 0; | |
407 mpeg2dec->shift = 0xffffff00; | |
408 mpeg2dec->code = 0xb4; | |
409 mpeg2dec->action = mpeg2_seek_header; | |
410 mpeg2dec->state = STATE_INVALID; | |
411 mpeg2dec->first = 1; | |
412 | |
413 mpeg2_reset_info(&(mpeg2dec->info)); | |
414 mpeg2dec->info.gop = NULL; | |
415 mpeg2dec->info.user_data = NULL; | |
416 mpeg2dec->info.user_data_len = 0; | |
417 if (full_reset) { | |
418 mpeg2dec->info.sequence = NULL; | |
419 mpeg2_header_state_init (mpeg2dec); | |
420 } | |
421 | |
422 } | |
423 | |
9857 | 424 mpeg2dec_t * mpeg2_init (void) |
425 { | |
426 mpeg2dec_t * mpeg2dec; | |
427 | |
428 mpeg2_accel (MPEG2_ACCEL_DETECT); | |
429 | |
430 mpeg2dec = (mpeg2dec_t *) mpeg2_malloc (sizeof (mpeg2dec_t), | |
12932 | 431 MPEG2_ALLOC_MPEG2DEC); |
9857 | 432 if (mpeg2dec == NULL) |
433 return NULL; | |
434 | |
12932 | 435 memset (mpeg2dec->decoder.DCTblock, 0, 64 * sizeof (int16_t)); |
436 memset (mpeg2dec->quantizer_matrix, 0, 4 * 64 * sizeof (uint8_t)); | |
9857 | 437 |
438 mpeg2dec->chunk_buffer = (uint8_t *) mpeg2_malloc (BUFFER_SIZE + 4, | |
12932 | 439 MPEG2_ALLOC_CHUNK); |
9857 | 440 |
12932 | 441 mpeg2dec->sequence.width = (unsigned)-1; |
442 mpeg2_reset (mpeg2dec, 1); | |
9857 | 443 |
444 return mpeg2dec; | |
445 } | |
446 | |
447 void mpeg2_close (mpeg2dec_t * mpeg2dec) | |
448 { | |
12932 | 449 mpeg2_header_state_init (mpeg2dec); |
9857 | 450 mpeg2_free (mpeg2dec->chunk_buffer); |
451 mpeg2_free (mpeg2dec); | |
452 } |