Mercurial > libavcodec.hg
comparison dirac_parser.c @ 8422:e623323d409f libavcodec
Fix incorrectly constructed Dirac parse units that caused A/V sync loss.
Fixes issue 694.
patch by Anuradha Suraparaju, anuradha rd.bbc.co uk
author | diego |
---|---|
date | Mon, 22 Dec 2008 00:01:39 +0000 |
parents | cebe9c3422a8 |
children | 2acf0ae7b041 |
comparison
equal
deleted
inserted
replaced
8421:9ea0742666b9 | 8422:e623323d409f |
---|---|
1 /* | 1 /* |
2 * Dirac parser | 2 * Dirac parser |
3 * | 3 * |
4 * Copyright (c) 2007 Marco Gerards <marco@gnu.org> | 4 * Copyright (c) 2007-2008 Marco Gerards <marco@gnu.org> |
5 * Copyright (c) 2008 BBC, Anuradha Suraparaju <asuraparaju@gmail.com> | |
5 * | 6 * |
6 * This file is part of FFmpeg. | 7 * This file is part of FFmpeg. |
7 * | 8 * |
8 * FFmpeg is free software; you can redistribute it and/or | 9 * FFmpeg is free software; you can redistribute it and/or |
9 * modify it under the terms of the GNU Lesser General Public | 10 * modify it under the terms of the GNU Lesser General Public |
32 | 33 |
33 /** | 34 /** |
34 * Finds the end of the current frame in the bitstream. | 35 * Finds the end of the current frame in the bitstream. |
35 * @return the position of the first byte of the next frame or -1 | 36 * @return the position of the first byte of the next frame or -1 |
36 */ | 37 */ |
37 static int find_frame_end(ParseContext *pc, const uint8_t *buf, int buf_size) | 38 typedef struct DiracParseContext { |
39 int state; | |
40 int is_synced; | |
41 int sync_offset; | |
42 int header_bytes_needed; | |
43 int overread_index; | |
44 int buffer_size; | |
45 int index; | |
46 uint8_t *buffer; | |
47 int dirac_unit_size; | |
48 uint8_t *dirac_unit; | |
49 } DiracParseContext; | |
50 | |
51 static int find_frame_end(DiracParseContext *pc, | |
52 const uint8_t *buf, int buf_size) | |
38 { | 53 { |
39 uint32_t state = pc->state; | 54 uint32_t state = pc->state; |
40 int i; | 55 int i = 0; |
41 | 56 |
42 for (i = 0; i < buf_size; i++) { | 57 if (!pc->is_synced) { |
43 state = (state << 8) | buf[i]; | 58 for (i = 0; i < buf_size; i++) { |
44 if (state == DIRAC_PARSE_INFO_PREFIX) { | 59 state = (state << 8) | buf[i]; |
45 pc->frame_start_found ^= 1; | 60 if (state == DIRAC_PARSE_INFO_PREFIX) { |
46 if (!pc->frame_start_found) { | 61 state = -1; |
47 pc->state = -1; | 62 pc->is_synced = 1; |
48 return i - 3; | 63 pc->header_bytes_needed = 9; |
64 pc->sync_offset = i; | |
65 break; | |
49 } | 66 } |
50 } | 67 } |
51 } | 68 } |
52 | 69 |
70 if (pc->is_synced) { | |
71 pc->sync_offset = 0; | |
72 for (; i < buf_size; i++) { | |
73 if (state == DIRAC_PARSE_INFO_PREFIX) { | |
74 if ((buf_size-i) >= pc->header_bytes_needed) { | |
75 pc->state = -1; | |
76 return i + pc->header_bytes_needed; | |
77 } else { | |
78 pc->header_bytes_needed = 9-(buf_size-i); | |
79 break; | |
80 } | |
81 } else | |
82 state = (state << 8) | buf[i]; | |
83 } | |
84 } | |
53 pc->state = state; | 85 pc->state = state; |
54 | 86 return -1; |
55 return END_NOT_FOUND; | 87 } |
88 | |
89 typedef struct DiracParseUnit | |
90 { | |
91 int next_pu_offset; | |
92 int prev_pu_offset; | |
93 uint8_t pu_type; | |
94 } DiracParseUnit; | |
95 | |
96 static int unpack_parse_unit(DiracParseUnit *pu, DiracParseContext *pc, | |
97 int offset) | |
98 { | |
99 uint8_t *start = pc->buffer + offset; | |
100 uint8_t *end = pc->buffer + pc->index; | |
101 if (start < pc->buffer || (start+13 > end)) | |
102 return 0; | |
103 pu->pu_type = start[4]; | |
104 | |
105 pu->next_pu_offset = AV_RB32(start+5); | |
106 pu->prev_pu_offset = AV_RB32(start+9); | |
107 | |
108 if (pu->pu_type == 0x10 && pu->next_pu_offset == 0) | |
109 pu->next_pu_offset = 13; | |
110 | |
111 return 1; | |
112 } | |
113 | |
114 static int dirac_combine_frame(AVCodecParserContext *s, AVCodecContext *avctx, | |
115 int next, const uint8_t **buf, int *buf_size) | |
116 { | |
117 int parse_timing_info = (s->pts == AV_NOPTS_VALUE && | |
118 s->dts == AV_NOPTS_VALUE); | |
119 DiracParseContext *pc = s->priv_data; | |
120 | |
121 if (pc->overread_index) { | |
122 memcpy(pc->buffer, pc->buffer + pc->overread_index, | |
123 pc->index - pc->overread_index); | |
124 pc->index -= pc->overread_index; | |
125 pc->overread_index = 0; | |
126 if (*buf_size == 0 && pc->buffer[4] == 0x10) { | |
127 *buf = pc->buffer; | |
128 *buf_size = pc->index; | |
129 return 0; | |
130 } | |
131 } | |
132 | |
133 if ( next == -1) { | |
134 /* Found a possible frame start but not a frame end */ | |
135 void *new_buffer = av_fast_realloc(pc->buffer, &pc->buffer_size, | |
136 pc->index + (*buf_size - | |
137 pc->sync_offset)); | |
138 pc->buffer = new_buffer; | |
139 memcpy(pc->buffer+pc->index, (*buf + pc->sync_offset), | |
140 *buf_size - pc->sync_offset); | |
141 pc->index += *buf_size - pc->sync_offset; | |
142 return -1; | |
143 } else { | |
144 /* Found a possible frame start and a possible frame end */ | |
145 DiracParseUnit pu1, pu; | |
146 void *new_buffer = av_fast_realloc(pc->buffer, &pc->buffer_size, | |
147 pc->index + next); | |
148 pc->buffer = new_buffer; | |
149 memcpy(pc->buffer + pc->index, *buf, next); | |
150 pc->index += next; | |
151 | |
152 /* Need to check if we have a valid Parse Unit. We can't go by the | |
153 * sync pattern 'BBCD' alone because arithmetic coding of the residual | |
154 * and motion data can cause the pattern triggering a false start of | |
155 * frame. So check if the previous parse offset of the next parse unit | |
156 * is equal to the next parse offset of the current parse unit then | |
157 * we can be pretty sure that we have a valid parse unit */ | |
158 if (!unpack_parse_unit(&pu1, pc, pc->index - 13) || | |
159 !unpack_parse_unit(&pu, pc, pc->index - 13 - pu1.prev_pu_offset) || | |
160 pu.next_pu_offset != pu1.prev_pu_offset) { | |
161 pc->index -= 9; | |
162 *buf_size = next-9; | |
163 pc->header_bytes_needed = 9; | |
164 return -1; | |
165 } | |
166 | |
167 /* All non-frame data must be accompanied by frame data. This is to | |
168 * ensure that pts is set correctly. So if the current parse unit is | |
169 * not frame data, wait for frame data to come along */ | |
170 | |
171 pc->dirac_unit = pc->buffer + pc->index - 13 - | |
172 pu1.prev_pu_offset - pc->dirac_unit_size; | |
173 | |
174 pc->dirac_unit_size += pu.next_pu_offset; | |
175 | |
176 if ((pu.pu_type&0x08) != 0x08) { | |
177 pc->header_bytes_needed = 9; | |
178 *buf_size = next; | |
179 return -1; | |
180 } | |
181 | |
182 /* Get the picture number to set the pts and dts*/ | |
183 if (parse_timing_info) { | |
184 uint8_t *cur_pu = pc->buffer + | |
185 pc->index - 13 - pu1.prev_pu_offset; | |
186 int pts = AV_RB32(cur_pu + 13); | |
187 if (s->last_pts == 0 && s->last_dts == 0) | |
188 s->dts = pts - 1; | |
189 else | |
190 s->dts = s->last_dts+1; | |
191 s->pts = pts; | |
192 if (!avctx->has_b_frames && (cur_pu[4] & 0x03)) | |
193 avctx->has_b_frames = 1; | |
194 } | |
195 if (avctx->has_b_frames && s->pts == s->dts) | |
196 s->pict_type = FF_B_TYPE; | |
197 | |
198 /* Finally have a complete Dirac data unit */ | |
199 *buf = pc->dirac_unit; | |
200 *buf_size = pc->dirac_unit_size; | |
201 | |
202 pc->dirac_unit_size = 0; | |
203 pc->overread_index = pc->index-13; | |
204 pc->header_bytes_needed = 9; | |
205 } | |
206 return next; | |
56 } | 207 } |
57 | 208 |
58 static int dirac_parse(AVCodecParserContext *s, AVCodecContext *avctx, | 209 static int dirac_parse(AVCodecParserContext *s, AVCodecContext *avctx, |
59 const uint8_t **poutbuf, int *poutbuf_size, | 210 const uint8_t **poutbuf, int *poutbuf_size, |
60 const uint8_t *buf, int buf_size) | 211 const uint8_t *buf, int buf_size) |
61 { | 212 { |
62 ParseContext *pc = s->priv_data; | 213 DiracParseContext *pc = s->priv_data; |
63 int next; | 214 int next; |
215 | |
216 *poutbuf = NULL; | |
217 *poutbuf_size = 0; | |
64 | 218 |
65 if (s->flags & PARSER_FLAG_COMPLETE_FRAMES) { | 219 if (s->flags & PARSER_FLAG_COMPLETE_FRAMES) { |
66 next = buf_size; | 220 next = buf_size; |
67 }else{ | 221 *poutbuf = buf; |
222 *poutbuf_size = buf_size; | |
223 /* Assume that data has been packetized into an encapsulation unit. */ | |
224 } else { | |
68 next = find_frame_end(pc, buf, buf_size); | 225 next = find_frame_end(pc, buf, buf_size); |
69 | 226 if (!pc->is_synced && next == -1) { |
70 if (ff_combine_frame(pc, next, &buf, &buf_size) < 0) { | 227 /* No frame start found yet. So throw away the entire buffer. */ |
71 *poutbuf = NULL; | 228 return buf_size; |
72 *poutbuf_size = 0; | 229 } |
230 | |
231 if (dirac_combine_frame(s, avctx, next, &buf, &buf_size) < 0) { | |
73 return buf_size; | 232 return buf_size; |
74 } | 233 } |
75 } | 234 } |
76 | 235 |
77 *poutbuf = buf; | 236 *poutbuf = buf; |
78 *poutbuf_size = buf_size; | 237 *poutbuf_size = buf_size; |
79 return next; | 238 return next; |
80 } | 239 } |
81 | 240 |
241 static void dirac_parse_close(AVCodecParserContext *s) | |
242 { | |
243 DiracParseContext *pc = s->priv_data; | |
244 | |
245 if (pc->buffer_size > 0) | |
246 av_free(pc->buffer); | |
247 } | |
248 | |
82 AVCodecParser dirac_parser = { | 249 AVCodecParser dirac_parser = { |
83 { CODEC_ID_DIRAC }, | 250 { CODEC_ID_DIRAC }, |
84 sizeof(ParseContext), | 251 sizeof(DiracParseContext), |
85 NULL, | 252 NULL, |
86 dirac_parse, | 253 dirac_parse, |
87 ff_parse_close, | 254 dirac_parse_close, |
88 }; | 255 }; |