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 }; |
