Details | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
4349 | Serge | 1 | /* |
2 | * Dirac parser |
||
3 | * |
||
4 | * Copyright (c) 2007-2008 Marco Gerards |
||
5 | * Copyright (c) 2008 BBC, Anuradha Suraparaju |
||
6 | * |
||
7 | * This file is part of FFmpeg. |
||
8 | * |
||
9 | * FFmpeg is free software; you can redistribute it and/or |
||
10 | * modify it under the terms of the GNU Lesser General Public |
||
11 | * License as published by the Free Software Foundation; either |
||
12 | * version 2.1 of the License, or (at your option) any later version. |
||
13 | * |
||
14 | * FFmpeg 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 GNU |
||
17 | * Lesser General Public License for more details. |
||
18 | * |
||
19 | * You should have received a copy of the GNU Lesser General Public |
||
20 | * License along with FFmpeg; if not, write to the Free Software |
||
21 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
||
22 | */ |
||
23 | |||
24 | /** |
||
25 | * @file |
||
26 | * Dirac Parser |
||
27 | * @author Marco Gerards |
||
28 | */ |
||
29 | |||
30 | #include |
||
31 | |||
32 | #include "libavutil/intreadwrite.h" |
||
33 | #include "libavutil/mem.h" |
||
34 | #include "parser.h" |
||
35 | |||
36 | #define DIRAC_PARSE_INFO_PREFIX 0x42424344 |
||
37 | |||
38 | /** |
||
39 | * Find the end of the current frame in the bitstream. |
||
40 | * @return the position of the first byte of the next frame or -1 |
||
41 | */ |
||
42 | typedef struct DiracParseContext { |
||
43 | int state; |
||
44 | int is_synced; |
||
45 | int sync_offset; |
||
46 | int header_bytes_needed; |
||
47 | int overread_index; |
||
48 | int buffer_size; |
||
49 | int index; |
||
50 | uint8_t *buffer; |
||
51 | int dirac_unit_size; |
||
52 | uint8_t *dirac_unit; |
||
53 | } DiracParseContext; |
||
54 | |||
55 | static int find_frame_end(DiracParseContext *pc, |
||
56 | const uint8_t *buf, int buf_size) |
||
57 | { |
||
58 | uint32_t state = pc->state; |
||
59 | int i = 0; |
||
60 | |||
61 | if (!pc->is_synced) { |
||
62 | for (i = 0; i < buf_size; i++) { |
||
63 | state = (state << 8) | buf[i]; |
||
64 | if (state == DIRAC_PARSE_INFO_PREFIX) { |
||
65 | state = -1; |
||
66 | pc->is_synced = 1; |
||
67 | pc->header_bytes_needed = 9; |
||
68 | pc->sync_offset = i; |
||
69 | break; |
||
70 | } |
||
71 | } |
||
72 | } |
||
73 | |||
74 | if (pc->is_synced) { |
||
75 | pc->sync_offset = 0; |
||
76 | for (; i < buf_size; i++) { |
||
77 | if (state == DIRAC_PARSE_INFO_PREFIX) { |
||
78 | if ((buf_size-i) >= pc->header_bytes_needed) { |
||
79 | pc->state = -1; |
||
80 | return i + pc->header_bytes_needed; |
||
81 | } else { |
||
82 | pc->header_bytes_needed = 9-(buf_size-i); |
||
83 | break; |
||
84 | } |
||
85 | } else |
||
86 | state = (state << 8) | buf[i]; |
||
87 | } |
||
88 | } |
||
89 | pc->state = state; |
||
90 | return -1; |
||
91 | } |
||
92 | |||
93 | typedef struct DiracParseUnit |
||
94 | { |
||
95 | int next_pu_offset; |
||
96 | int prev_pu_offset; |
||
97 | uint8_t pu_type; |
||
98 | } DiracParseUnit; |
||
99 | |||
100 | static int unpack_parse_unit(DiracParseUnit *pu, DiracParseContext *pc, |
||
101 | int offset) |
||
102 | { |
||
103 | uint8_t *start = pc->buffer + offset; |
||
104 | uint8_t *end = pc->buffer + pc->index; |
||
105 | if (start < pc->buffer || (start+13 > end)) |
||
106 | return 0; |
||
107 | pu->pu_type = start[4]; |
||
108 | |||
109 | pu->next_pu_offset = AV_RB32(start+5); |
||
110 | pu->prev_pu_offset = AV_RB32(start+9); |
||
111 | |||
112 | if (pu->pu_type == 0x10 && pu->next_pu_offset == 0) |
||
113 | pu->next_pu_offset = 13; |
||
114 | |||
115 | return 1; |
||
116 | } |
||
117 | |||
118 | static int dirac_combine_frame(AVCodecParserContext *s, AVCodecContext *avctx, |
||
119 | int next, const uint8_t **buf, int *buf_size) |
||
120 | { |
||
121 | int parse_timing_info = (s->pts == AV_NOPTS_VALUE && |
||
122 | s->dts == AV_NOPTS_VALUE); |
||
123 | DiracParseContext *pc = s->priv_data; |
||
124 | |||
125 | if (pc->overread_index) { |
||
126 | memcpy(pc->buffer, pc->buffer + pc->overread_index, |
||
127 | pc->index - pc->overread_index); |
||
128 | pc->index -= pc->overread_index; |
||
129 | pc->overread_index = 0; |
||
130 | if (*buf_size == 0 && pc->buffer[4] == 0x10) { |
||
131 | *buf = pc->buffer; |
||
132 | *buf_size = pc->index; |
||
133 | return 0; |
||
134 | } |
||
135 | } |
||
136 | |||
137 | if ( next == -1) { |
||
138 | /* Found a possible frame start but not a frame end */ |
||
139 | void *new_buffer = av_fast_realloc(pc->buffer, &pc->buffer_size, |
||
140 | pc->index + (*buf_size - |
||
141 | pc->sync_offset)); |
||
142 | pc->buffer = new_buffer; |
||
143 | memcpy(pc->buffer+pc->index, (*buf + pc->sync_offset), |
||
144 | *buf_size - pc->sync_offset); |
||
145 | pc->index += *buf_size - pc->sync_offset; |
||
146 | return -1; |
||
147 | } else { |
||
148 | /* Found a possible frame start and a possible frame end */ |
||
149 | DiracParseUnit pu1, pu; |
||
150 | void *new_buffer = av_fast_realloc(pc->buffer, &pc->buffer_size, |
||
151 | pc->index + next); |
||
152 | pc->buffer = new_buffer; |
||
153 | memcpy(pc->buffer + pc->index, *buf, next); |
||
154 | pc->index += next; |
||
155 | |||
156 | /* Need to check if we have a valid Parse Unit. We can't go by the |
||
157 | * sync pattern 'BBCD' alone because arithmetic coding of the residual |
||
158 | * and motion data can cause the pattern triggering a false start of |
||
159 | * frame. So check if the previous parse offset of the next parse unit |
||
160 | * is equal to the next parse offset of the current parse unit then |
||
161 | * we can be pretty sure that we have a valid parse unit */ |
||
162 | if (!unpack_parse_unit(&pu1, pc, pc->index - 13) || |
||
163 | !unpack_parse_unit(&pu, pc, pc->index - 13 - pu1.prev_pu_offset) || |
||
164 | pu.next_pu_offset != pu1.prev_pu_offset || |
||
165 | pc->index < pc->dirac_unit_size + 13LL + pu1.prev_pu_offset |
||
166 | ) { |
||
167 | pc->index -= 9; |
||
168 | *buf_size = next-9; |
||
169 | pc->header_bytes_needed = 9; |
||
170 | return -1; |
||
171 | } |
||
172 | |||
173 | /* All non-frame data must be accompanied by frame data. This is to |
||
174 | * ensure that pts is set correctly. So if the current parse unit is |
||
175 | * not frame data, wait for frame data to come along */ |
||
176 | |||
177 | pc->dirac_unit = pc->buffer + pc->index - 13 - |
||
178 | pu1.prev_pu_offset - pc->dirac_unit_size; |
||
179 | |||
180 | pc->dirac_unit_size += pu.next_pu_offset; |
||
181 | |||
182 | if ((pu.pu_type&0x08) != 0x08) { |
||
183 | pc->header_bytes_needed = 9; |
||
184 | *buf_size = next; |
||
185 | return -1; |
||
186 | } |
||
187 | |||
188 | /* Get the picture number to set the pts and dts*/ |
||
189 | if (parse_timing_info) { |
||
190 | uint8_t *cur_pu = pc->buffer + |
||
191 | pc->index - 13 - pu1.prev_pu_offset; |
||
192 | int pts = AV_RB32(cur_pu + 13); |
||
193 | if (s->last_pts == 0 && s->last_dts == 0) |
||
194 | s->dts = pts - 1; |
||
195 | else |
||
196 | s->dts = s->last_dts+1; |
||
197 | s->pts = pts; |
||
198 | if (!avctx->has_b_frames && (cur_pu[4] & 0x03)) |
||
199 | avctx->has_b_frames = 1; |
||
200 | } |
||
201 | if (avctx->has_b_frames && s->pts == s->dts) |
||
202 | s->pict_type = AV_PICTURE_TYPE_B; |
||
203 | |||
204 | /* Finally have a complete Dirac data unit */ |
||
205 | *buf = pc->dirac_unit; |
||
206 | *buf_size = pc->dirac_unit_size; |
||
207 | |||
208 | pc->dirac_unit_size = 0; |
||
209 | pc->overread_index = pc->index-13; |
||
210 | pc->header_bytes_needed = 9; |
||
211 | } |
||
212 | return next; |
||
213 | } |
||
214 | |||
215 | static int dirac_parse(AVCodecParserContext *s, AVCodecContext *avctx, |
||
216 | const uint8_t **poutbuf, int *poutbuf_size, |
||
217 | const uint8_t *buf, int buf_size) |
||
218 | { |
||
219 | DiracParseContext *pc = s->priv_data; |
||
220 | int next; |
||
221 | |||
222 | *poutbuf = NULL; |
||
223 | *poutbuf_size = 0; |
||
224 | |||
225 | if (s->flags & PARSER_FLAG_COMPLETE_FRAMES) { |
||
226 | next = buf_size; |
||
227 | *poutbuf = buf; |
||
228 | *poutbuf_size = buf_size; |
||
229 | /* Assume that data has been packetized into an encapsulation unit. */ |
||
230 | } else { |
||
231 | next = find_frame_end(pc, buf, buf_size); |
||
232 | if (!pc->is_synced && next == -1) { |
||
233 | /* No frame start found yet. So throw away the entire buffer. */ |
||
234 | return buf_size; |
||
235 | } |
||
236 | |||
237 | if (dirac_combine_frame(s, avctx, next, &buf, &buf_size) < 0) { |
||
238 | return buf_size; |
||
239 | } |
||
240 | } |
||
241 | |||
242 | *poutbuf = buf; |
||
243 | *poutbuf_size = buf_size; |
||
244 | return next; |
||
245 | } |
||
246 | |||
247 | static void dirac_parse_close(AVCodecParserContext *s) |
||
248 | { |
||
249 | DiracParseContext *pc = s->priv_data; |
||
250 | |||
251 | if (pc->buffer_size > 0) |
||
252 | av_free(pc->buffer); |
||
253 | } |
||
254 | |||
255 | AVCodecParser ff_dirac_parser = { |
||
256 | .codec_ids = { AV_CODEC_ID_DIRAC }, |
||
257 | .priv_data_size = sizeof(DiracParseContext), |
||
258 | .parser_parse = dirac_parse, |
||
259 | .parser_close = dirac_parse_close, |
||
260 | };>>>><>>><>> |