annotate mpegvideo_parser.c @ 6994:5a5ded44808a libavcodec

In mpeg1/2 timestamps are associated with the access unit which contains the first picture startcode that commences in the PES packet, instead of the first access unit that commences in the PES packet. Fix the parser to handle that properly. This was a very long standing bug ... The change to the seek regressions is because the mpeg ts muxer stores too many invalid and randomized timestamps which overflow the 4 entry buffer we use in the parser.
author michael
date Tue, 03 Jun 2008 02:43:17 +0000
parents cb31fe7bd914
children 04423b2f6e0b
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
4915
c22e10113015 move mpegvideo_parser in it's own file
aurel
parents:
diff changeset
1 /*
c22e10113015 move mpegvideo_parser in it's own file
aurel
parents:
diff changeset
2 * MPEG1 / MPEG2 video parser
c22e10113015 move mpegvideo_parser in it's own file
aurel
parents:
diff changeset
3 * Copyright (c) 2000,2001 Fabrice Bellard.
c22e10113015 move mpegvideo_parser in it's own file
aurel
parents:
diff changeset
4 * Copyright (c) 2002-2004 Michael Niedermayer <michaelni@gmx.at>
c22e10113015 move mpegvideo_parser in it's own file
aurel
parents:
diff changeset
5 *
c22e10113015 move mpegvideo_parser in it's own file
aurel
parents:
diff changeset
6 * This file is part of FFmpeg.
c22e10113015 move mpegvideo_parser in it's own file
aurel
parents:
diff changeset
7 *
c22e10113015 move mpegvideo_parser in it's own file
aurel
parents:
diff changeset
8 * FFmpeg is free software; you can redistribute it and/or
c22e10113015 move mpegvideo_parser in it's own file
aurel
parents:
diff changeset
9 * modify it under the terms of the GNU Lesser General Public
c22e10113015 move mpegvideo_parser in it's own file
aurel
parents:
diff changeset
10 * License as published by the Free Software Foundation; either
c22e10113015 move mpegvideo_parser in it's own file
aurel
parents:
diff changeset
11 * version 2.1 of the License, or (at your option) any later version.
c22e10113015 move mpegvideo_parser in it's own file
aurel
parents:
diff changeset
12 *
c22e10113015 move mpegvideo_parser in it's own file
aurel
parents:
diff changeset
13 * FFmpeg is distributed in the hope that it will be useful,
c22e10113015 move mpegvideo_parser in it's own file
aurel
parents:
diff changeset
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
c22e10113015 move mpegvideo_parser in it's own file
aurel
parents:
diff changeset
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
c22e10113015 move mpegvideo_parser in it's own file
aurel
parents:
diff changeset
16 * Lesser General Public License for more details.
c22e10113015 move mpegvideo_parser in it's own file
aurel
parents:
diff changeset
17 *
c22e10113015 move mpegvideo_parser in it's own file
aurel
parents:
diff changeset
18 * You should have received a copy of the GNU Lesser General Public
c22e10113015 move mpegvideo_parser in it's own file
aurel
parents:
diff changeset
19 * License along with FFmpeg; if not, write to the Free Software
c22e10113015 move mpegvideo_parser in it's own file
aurel
parents:
diff changeset
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
c22e10113015 move mpegvideo_parser in it's own file
aurel
parents:
diff changeset
21 */
c22e10113015 move mpegvideo_parser in it's own file
aurel
parents:
diff changeset
22
c22e10113015 move mpegvideo_parser in it's own file
aurel
parents:
diff changeset
23 #include "parser.h"
c22e10113015 move mpegvideo_parser in it's own file
aurel
parents:
diff changeset
24 #include "mpegvideo.h"
c22e10113015 move mpegvideo_parser in it's own file
aurel
parents:
diff changeset
25
c22e10113015 move mpegvideo_parser in it's own file
aurel
parents:
diff changeset
26 static void mpegvideo_extract_headers(AVCodecParserContext *s,
c22e10113015 move mpegvideo_parser in it's own file
aurel
parents:
diff changeset
27 AVCodecContext *avctx,
c22e10113015 move mpegvideo_parser in it's own file
aurel
parents:
diff changeset
28 const uint8_t *buf, int buf_size)
c22e10113015 move mpegvideo_parser in it's own file
aurel
parents:
diff changeset
29 {
c22e10113015 move mpegvideo_parser in it's own file
aurel
parents:
diff changeset
30 ParseContext1 *pc = s->priv_data;
c22e10113015 move mpegvideo_parser in it's own file
aurel
parents:
diff changeset
31 const uint8_t *buf_end;
6994
5a5ded44808a In mpeg1/2 timestamps are associated with the access unit which
michael
parents: 6564
diff changeset
32 const uint8_t *buf_start= buf;
4915
c22e10113015 move mpegvideo_parser in it's own file
aurel
parents:
diff changeset
33 uint32_t start_code;
c22e10113015 move mpegvideo_parser in it's own file
aurel
parents:
diff changeset
34 int frame_rate_index, ext_type, bytes_left;
c22e10113015 move mpegvideo_parser in it's own file
aurel
parents:
diff changeset
35 int frame_rate_ext_n, frame_rate_ext_d;
c22e10113015 move mpegvideo_parser in it's own file
aurel
parents:
diff changeset
36 int picture_structure, top_field_first, repeat_first_field, progressive_frame;
c22e10113015 move mpegvideo_parser in it's own file
aurel
parents:
diff changeset
37 int horiz_size_ext, vert_size_ext, bit_rate_ext;
c22e10113015 move mpegvideo_parser in it's own file
aurel
parents:
diff changeset
38 //FIXME replace the crap with get_bits()
c22e10113015 move mpegvideo_parser in it's own file
aurel
parents:
diff changeset
39 s->repeat_pict = 0;
c22e10113015 move mpegvideo_parser in it's own file
aurel
parents:
diff changeset
40 buf_end = buf + buf_size;
c22e10113015 move mpegvideo_parser in it's own file
aurel
parents:
diff changeset
41 while (buf < buf_end) {
c22e10113015 move mpegvideo_parser in it's own file
aurel
parents:
diff changeset
42 start_code= -1;
c22e10113015 move mpegvideo_parser in it's own file
aurel
parents:
diff changeset
43 buf= ff_find_start_code(buf, buf_end, &start_code);
c22e10113015 move mpegvideo_parser in it's own file
aurel
parents:
diff changeset
44 bytes_left = buf_end - buf;
c22e10113015 move mpegvideo_parser in it's own file
aurel
parents:
diff changeset
45 switch(start_code) {
c22e10113015 move mpegvideo_parser in it's own file
aurel
parents:
diff changeset
46 case PICTURE_START_CODE:
6994
5a5ded44808a In mpeg1/2 timestamps are associated with the access unit which
michael
parents: 6564
diff changeset
47 ff_fetch_timestamp(s, buf-buf_start-4, 1);
5a5ded44808a In mpeg1/2 timestamps are associated with the access unit which
michael
parents: 6564
diff changeset
48
4915
c22e10113015 move mpegvideo_parser in it's own file
aurel
parents:
diff changeset
49 if (bytes_left >= 2) {
c22e10113015 move mpegvideo_parser in it's own file
aurel
parents:
diff changeset
50 s->pict_type = (buf[1] >> 3) & 7;
c22e10113015 move mpegvideo_parser in it's own file
aurel
parents:
diff changeset
51 }
c22e10113015 move mpegvideo_parser in it's own file
aurel
parents:
diff changeset
52 break;
c22e10113015 move mpegvideo_parser in it's own file
aurel
parents:
diff changeset
53 case SEQ_START_CODE:
c22e10113015 move mpegvideo_parser in it's own file
aurel
parents:
diff changeset
54 if (bytes_left >= 7) {
c22e10113015 move mpegvideo_parser in it's own file
aurel
parents:
diff changeset
55 pc->width = (buf[0] << 4) | (buf[1] >> 4);
c22e10113015 move mpegvideo_parser in it's own file
aurel
parents:
diff changeset
56 pc->height = ((buf[1] & 0x0f) << 8) | buf[2];
c22e10113015 move mpegvideo_parser in it's own file
aurel
parents:
diff changeset
57 avcodec_set_dimensions(avctx, pc->width, pc->height);
c22e10113015 move mpegvideo_parser in it's own file
aurel
parents:
diff changeset
58 frame_rate_index = buf[3] & 0xf;
c22e10113015 move mpegvideo_parser in it's own file
aurel
parents:
diff changeset
59 pc->frame_rate.den = avctx->time_base.den = ff_frame_rate_tab[frame_rate_index].num;
c22e10113015 move mpegvideo_parser in it's own file
aurel
parents:
diff changeset
60 pc->frame_rate.num = avctx->time_base.num = ff_frame_rate_tab[frame_rate_index].den;
c22e10113015 move mpegvideo_parser in it's own file
aurel
parents:
diff changeset
61 avctx->bit_rate = ((buf[4]<<10) | (buf[5]<<2) | (buf[6]>>6))*400;
c22e10113015 move mpegvideo_parser in it's own file
aurel
parents:
diff changeset
62 avctx->codec_id = CODEC_ID_MPEG1VIDEO;
c22e10113015 move mpegvideo_parser in it's own file
aurel
parents:
diff changeset
63 avctx->sub_id = 1;
c22e10113015 move mpegvideo_parser in it's own file
aurel
parents:
diff changeset
64 }
c22e10113015 move mpegvideo_parser in it's own file
aurel
parents:
diff changeset
65 break;
c22e10113015 move mpegvideo_parser in it's own file
aurel
parents:
diff changeset
66 case EXT_START_CODE:
c22e10113015 move mpegvideo_parser in it's own file
aurel
parents:
diff changeset
67 if (bytes_left >= 1) {
c22e10113015 move mpegvideo_parser in it's own file
aurel
parents:
diff changeset
68 ext_type = (buf[0] >> 4);
c22e10113015 move mpegvideo_parser in it's own file
aurel
parents:
diff changeset
69 switch(ext_type) {
c22e10113015 move mpegvideo_parser in it's own file
aurel
parents:
diff changeset
70 case 0x1: /* sequence extension */
c22e10113015 move mpegvideo_parser in it's own file
aurel
parents:
diff changeset
71 if (bytes_left >= 6) {
c22e10113015 move mpegvideo_parser in it's own file
aurel
parents:
diff changeset
72 horiz_size_ext = ((buf[1] & 1) << 1) | (buf[2] >> 7);
c22e10113015 move mpegvideo_parser in it's own file
aurel
parents:
diff changeset
73 vert_size_ext = (buf[2] >> 5) & 3;
c22e10113015 move mpegvideo_parser in it's own file
aurel
parents:
diff changeset
74 bit_rate_ext = ((buf[2] & 0x1F)<<7) | (buf[3]>>1);
c22e10113015 move mpegvideo_parser in it's own file
aurel
parents:
diff changeset
75 frame_rate_ext_n = (buf[5] >> 5) & 3;
c22e10113015 move mpegvideo_parser in it's own file
aurel
parents:
diff changeset
76 frame_rate_ext_d = (buf[5] & 0x1f);
c22e10113015 move mpegvideo_parser in it's own file
aurel
parents:
diff changeset
77 pc->progressive_sequence = buf[1] & (1 << 3);
c22e10113015 move mpegvideo_parser in it's own file
aurel
parents:
diff changeset
78 avctx->has_b_frames= !(buf[5] >> 7);
c22e10113015 move mpegvideo_parser in it's own file
aurel
parents:
diff changeset
79
c22e10113015 move mpegvideo_parser in it's own file
aurel
parents:
diff changeset
80 pc->width |=(horiz_size_ext << 12);
c22e10113015 move mpegvideo_parser in it's own file
aurel
parents:
diff changeset
81 pc->height |=( vert_size_ext << 12);
c22e10113015 move mpegvideo_parser in it's own file
aurel
parents:
diff changeset
82 avctx->bit_rate += (bit_rate_ext << 18) * 400;
c22e10113015 move mpegvideo_parser in it's own file
aurel
parents:
diff changeset
83 avcodec_set_dimensions(avctx, pc->width, pc->height);
c22e10113015 move mpegvideo_parser in it's own file
aurel
parents:
diff changeset
84 avctx->time_base.den = pc->frame_rate.den * (frame_rate_ext_n + 1);
c22e10113015 move mpegvideo_parser in it's own file
aurel
parents:
diff changeset
85 avctx->time_base.num = pc->frame_rate.num * (frame_rate_ext_d + 1);
c22e10113015 move mpegvideo_parser in it's own file
aurel
parents:
diff changeset
86 avctx->codec_id = CODEC_ID_MPEG2VIDEO;
c22e10113015 move mpegvideo_parser in it's own file
aurel
parents:
diff changeset
87 avctx->sub_id = 2; /* forces MPEG2 */
c22e10113015 move mpegvideo_parser in it's own file
aurel
parents:
diff changeset
88 }
c22e10113015 move mpegvideo_parser in it's own file
aurel
parents:
diff changeset
89 break;
c22e10113015 move mpegvideo_parser in it's own file
aurel
parents:
diff changeset
90 case 0x8: /* picture coding extension */
c22e10113015 move mpegvideo_parser in it's own file
aurel
parents:
diff changeset
91 if (bytes_left >= 5) {
c22e10113015 move mpegvideo_parser in it's own file
aurel
parents:
diff changeset
92 picture_structure = buf[2]&3;
c22e10113015 move mpegvideo_parser in it's own file
aurel
parents:
diff changeset
93 top_field_first = buf[3] & (1 << 7);
c22e10113015 move mpegvideo_parser in it's own file
aurel
parents:
diff changeset
94 repeat_first_field = buf[3] & (1 << 1);
c22e10113015 move mpegvideo_parser in it's own file
aurel
parents:
diff changeset
95 progressive_frame = buf[4] & (1 << 7);
c22e10113015 move mpegvideo_parser in it's own file
aurel
parents:
diff changeset
96
c22e10113015 move mpegvideo_parser in it's own file
aurel
parents:
diff changeset
97 /* check if we must repeat the frame */
c22e10113015 move mpegvideo_parser in it's own file
aurel
parents:
diff changeset
98 if (repeat_first_field) {
c22e10113015 move mpegvideo_parser in it's own file
aurel
parents:
diff changeset
99 if (pc->progressive_sequence) {
c22e10113015 move mpegvideo_parser in it's own file
aurel
parents:
diff changeset
100 if (top_field_first)
c22e10113015 move mpegvideo_parser in it's own file
aurel
parents:
diff changeset
101 s->repeat_pict = 4;
c22e10113015 move mpegvideo_parser in it's own file
aurel
parents:
diff changeset
102 else
c22e10113015 move mpegvideo_parser in it's own file
aurel
parents:
diff changeset
103 s->repeat_pict = 2;
c22e10113015 move mpegvideo_parser in it's own file
aurel
parents:
diff changeset
104 } else if (progressive_frame) {
c22e10113015 move mpegvideo_parser in it's own file
aurel
parents:
diff changeset
105 s->repeat_pict = 1;
c22e10113015 move mpegvideo_parser in it's own file
aurel
parents:
diff changeset
106 }
c22e10113015 move mpegvideo_parser in it's own file
aurel
parents:
diff changeset
107 }
c22e10113015 move mpegvideo_parser in it's own file
aurel
parents:
diff changeset
108 }
c22e10113015 move mpegvideo_parser in it's own file
aurel
parents:
diff changeset
109 break;
c22e10113015 move mpegvideo_parser in it's own file
aurel
parents:
diff changeset
110 }
c22e10113015 move mpegvideo_parser in it's own file
aurel
parents:
diff changeset
111 }
c22e10113015 move mpegvideo_parser in it's own file
aurel
parents:
diff changeset
112 break;
c22e10113015 move mpegvideo_parser in it's own file
aurel
parents:
diff changeset
113 case -1:
c22e10113015 move mpegvideo_parser in it's own file
aurel
parents:
diff changeset
114 goto the_end;
c22e10113015 move mpegvideo_parser in it's own file
aurel
parents:
diff changeset
115 default:
c22e10113015 move mpegvideo_parser in it's own file
aurel
parents:
diff changeset
116 /* we stop parsing when we encounter a slice. It ensures
c22e10113015 move mpegvideo_parser in it's own file
aurel
parents:
diff changeset
117 that this function takes a negligible amount of time */
c22e10113015 move mpegvideo_parser in it's own file
aurel
parents:
diff changeset
118 if (start_code >= SLICE_MIN_START_CODE &&
c22e10113015 move mpegvideo_parser in it's own file
aurel
parents:
diff changeset
119 start_code <= SLICE_MAX_START_CODE)
c22e10113015 move mpegvideo_parser in it's own file
aurel
parents:
diff changeset
120 goto the_end;
c22e10113015 move mpegvideo_parser in it's own file
aurel
parents:
diff changeset
121 break;
c22e10113015 move mpegvideo_parser in it's own file
aurel
parents:
diff changeset
122 }
c22e10113015 move mpegvideo_parser in it's own file
aurel
parents:
diff changeset
123 }
c22e10113015 move mpegvideo_parser in it's own file
aurel
parents:
diff changeset
124 the_end: ;
c22e10113015 move mpegvideo_parser in it's own file
aurel
parents:
diff changeset
125 }
c22e10113015 move mpegvideo_parser in it's own file
aurel
parents:
diff changeset
126
c22e10113015 move mpegvideo_parser in it's own file
aurel
parents:
diff changeset
127 static int mpegvideo_parse(AVCodecParserContext *s,
c22e10113015 move mpegvideo_parser in it's own file
aurel
parents:
diff changeset
128 AVCodecContext *avctx,
4931
0d1cc37d9430 make some parser parameters const to avoid casting const to non-const
aurel
parents: 4916
diff changeset
129 const uint8_t **poutbuf, int *poutbuf_size,
4915
c22e10113015 move mpegvideo_parser in it's own file
aurel
parents:
diff changeset
130 const uint8_t *buf, int buf_size)
c22e10113015 move mpegvideo_parser in it's own file
aurel
parents:
diff changeset
131 {
c22e10113015 move mpegvideo_parser in it's own file
aurel
parents:
diff changeset
132 ParseContext1 *pc1 = s->priv_data;
c22e10113015 move mpegvideo_parser in it's own file
aurel
parents:
diff changeset
133 ParseContext *pc= &pc1->pc;
c22e10113015 move mpegvideo_parser in it's own file
aurel
parents:
diff changeset
134 int next;
c22e10113015 move mpegvideo_parser in it's own file
aurel
parents:
diff changeset
135
c22e10113015 move mpegvideo_parser in it's own file
aurel
parents:
diff changeset
136 if(s->flags & PARSER_FLAG_COMPLETE_FRAMES){
c22e10113015 move mpegvideo_parser in it's own file
aurel
parents:
diff changeset
137 next= buf_size;
c22e10113015 move mpegvideo_parser in it's own file
aurel
parents:
diff changeset
138 }else{
4916
13ef168891b0 add a ff_ prefix to the now exported mpeg1_find_frame_end() function
aurel
parents: 4915
diff changeset
139 next= ff_mpeg1_find_frame_end(pc, buf, buf_size);
4915
c22e10113015 move mpegvideo_parser in it's own file
aurel
parents:
diff changeset
140
4931
0d1cc37d9430 make some parser parameters const to avoid casting const to non-const
aurel
parents: 4916
diff changeset
141 if (ff_combine_frame(pc, next, &buf, &buf_size) < 0) {
4915
c22e10113015 move mpegvideo_parser in it's own file
aurel
parents:
diff changeset
142 *poutbuf = NULL;
c22e10113015 move mpegvideo_parser in it's own file
aurel
parents:
diff changeset
143 *poutbuf_size = 0;
c22e10113015 move mpegvideo_parser in it's own file
aurel
parents:
diff changeset
144 return buf_size;
c22e10113015 move mpegvideo_parser in it's own file
aurel
parents:
diff changeset
145 }
c22e10113015 move mpegvideo_parser in it's own file
aurel
parents:
diff changeset
146
c22e10113015 move mpegvideo_parser in it's own file
aurel
parents:
diff changeset
147 }
c22e10113015 move mpegvideo_parser in it's own file
aurel
parents:
diff changeset
148 /* we have a full frame : we just parse the first few MPEG headers
c22e10113015 move mpegvideo_parser in it's own file
aurel
parents:
diff changeset
149 to have the full timing information. The time take by this
c22e10113015 move mpegvideo_parser in it's own file
aurel
parents:
diff changeset
150 function should be negligible for uncorrupted streams */
c22e10113015 move mpegvideo_parser in it's own file
aurel
parents:
diff changeset
151 mpegvideo_extract_headers(s, avctx, buf, buf_size);
c22e10113015 move mpegvideo_parser in it's own file
aurel
parents:
diff changeset
152 #if 0
c22e10113015 move mpegvideo_parser in it's own file
aurel
parents:
diff changeset
153 printf("pict_type=%d frame_rate=%0.3f repeat_pict=%d\n",
c22e10113015 move mpegvideo_parser in it's own file
aurel
parents:
diff changeset
154 s->pict_type, (double)avctx->time_base.den / avctx->time_base.num, s->repeat_pict);
c22e10113015 move mpegvideo_parser in it's own file
aurel
parents:
diff changeset
155 #endif
c22e10113015 move mpegvideo_parser in it's own file
aurel
parents:
diff changeset
156
4931
0d1cc37d9430 make some parser parameters const to avoid casting const to non-const
aurel
parents: 4916
diff changeset
157 *poutbuf = buf;
4915
c22e10113015 move mpegvideo_parser in it's own file
aurel
parents:
diff changeset
158 *poutbuf_size = buf_size;
c22e10113015 move mpegvideo_parser in it's own file
aurel
parents:
diff changeset
159 return next;
c22e10113015 move mpegvideo_parser in it's own file
aurel
parents:
diff changeset
160 }
c22e10113015 move mpegvideo_parser in it's own file
aurel
parents:
diff changeset
161
c22e10113015 move mpegvideo_parser in it's own file
aurel
parents:
diff changeset
162 static int mpegvideo_split(AVCodecContext *avctx,
c22e10113015 move mpegvideo_parser in it's own file
aurel
parents:
diff changeset
163 const uint8_t *buf, int buf_size)
c22e10113015 move mpegvideo_parser in it's own file
aurel
parents:
diff changeset
164 {
c22e10113015 move mpegvideo_parser in it's own file
aurel
parents:
diff changeset
165 int i;
c22e10113015 move mpegvideo_parser in it's own file
aurel
parents:
diff changeset
166 uint32_t state= -1;
c22e10113015 move mpegvideo_parser in it's own file
aurel
parents:
diff changeset
167
c22e10113015 move mpegvideo_parser in it's own file
aurel
parents:
diff changeset
168 for(i=0; i<buf_size; i++){
c22e10113015 move mpegvideo_parser in it's own file
aurel
parents:
diff changeset
169 state= (state<<8) | buf[i];
c22e10113015 move mpegvideo_parser in it's own file
aurel
parents:
diff changeset
170 if(state != 0x1B3 && state != 0x1B5 && state < 0x200 && state >= 0x100)
c22e10113015 move mpegvideo_parser in it's own file
aurel
parents:
diff changeset
171 return i-3;
c22e10113015 move mpegvideo_parser in it's own file
aurel
parents:
diff changeset
172 }
c22e10113015 move mpegvideo_parser in it's own file
aurel
parents:
diff changeset
173 return 0;
c22e10113015 move mpegvideo_parser in it's own file
aurel
parents:
diff changeset
174 }
c22e10113015 move mpegvideo_parser in it's own file
aurel
parents:
diff changeset
175
c22e10113015 move mpegvideo_parser in it's own file
aurel
parents:
diff changeset
176 AVCodecParser mpegvideo_parser = {
c22e10113015 move mpegvideo_parser in it's own file
aurel
parents:
diff changeset
177 { CODEC_ID_MPEG1VIDEO, CODEC_ID_MPEG2VIDEO },
c22e10113015 move mpegvideo_parser in it's own file
aurel
parents:
diff changeset
178 sizeof(ParseContext1),
c22e10113015 move mpegvideo_parser in it's own file
aurel
parents:
diff changeset
179 NULL,
c22e10113015 move mpegvideo_parser in it's own file
aurel
parents:
diff changeset
180 mpegvideo_parse,
c22e10113015 move mpegvideo_parser in it's own file
aurel
parents:
diff changeset
181 ff_parse1_close,
c22e10113015 move mpegvideo_parser in it's own file
aurel
parents:
diff changeset
182 };