Commit | Line | Data |
---|---|---|
2ba45a60 DM |
1 | /* |
2 | * Audio and Video frame extraction | |
3 | * Copyright (c) 2003 Fabrice Bellard | |
4 | * Copyright (c) 2003 Michael Niedermayer | |
5 | * | |
6 | * This file is part of FFmpeg. | |
7 | * | |
8 | * FFmpeg is free software; you can redistribute it and/or | |
9 | * modify it under the terms of the GNU Lesser General Public | |
10 | * License as published by the Free Software Foundation; either | |
11 | * version 2.1 of the License, or (at your option) any later version. | |
12 | * | |
13 | * FFmpeg is distributed in the hope that it will be useful, | |
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
16 | * Lesser General Public License for more details. | |
17 | * | |
18 | * You should have received a copy of the GNU Lesser General Public | |
19 | * License along with FFmpeg; if not, write to the Free Software | |
20 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | |
21 | */ | |
22 | ||
23 | #include <stdint.h> | |
24 | #include <string.h> | |
25 | ||
26 | #include "libavutil/atomic.h" | |
27 | #include "libavutil/mem.h" | |
28 | ||
29 | #include "parser.h" | |
30 | ||
31 | static AVCodecParser *av_first_parser = NULL; | |
32 | ||
33 | AVCodecParser *av_parser_next(const AVCodecParser *p) | |
34 | { | |
35 | if (p) | |
36 | return p->next; | |
37 | else | |
38 | return av_first_parser; | |
39 | } | |
40 | ||
41 | void av_register_codec_parser(AVCodecParser *parser) | |
42 | { | |
43 | do { | |
44 | parser->next = av_first_parser; | |
45 | } while (parser->next != avpriv_atomic_ptr_cas((void * volatile *)&av_first_parser, parser->next, parser)); | |
46 | } | |
47 | ||
48 | AVCodecParserContext *av_parser_init(int codec_id) | |
49 | { | |
50 | AVCodecParserContext *s = NULL; | |
51 | AVCodecParser *parser; | |
52 | int ret; | |
53 | ||
54 | if (codec_id == AV_CODEC_ID_NONE) | |
55 | return NULL; | |
56 | ||
57 | for (parser = av_first_parser; parser; parser = parser->next) { | |
58 | if (parser->codec_ids[0] == codec_id || | |
59 | parser->codec_ids[1] == codec_id || | |
60 | parser->codec_ids[2] == codec_id || | |
61 | parser->codec_ids[3] == codec_id || | |
62 | parser->codec_ids[4] == codec_id) | |
63 | goto found; | |
64 | } | |
65 | return NULL; | |
66 | ||
67 | found: | |
68 | s = av_mallocz(sizeof(AVCodecParserContext)); | |
69 | if (!s) | |
70 | goto err_out; | |
71 | s->parser = parser; | |
72 | s->priv_data = av_mallocz(parser->priv_data_size); | |
73 | if (!s->priv_data) | |
74 | goto err_out; | |
75 | s->fetch_timestamp=1; | |
76 | s->pict_type = AV_PICTURE_TYPE_I; | |
77 | if (parser->parser_init) { | |
78 | ret = parser->parser_init(s); | |
79 | if (ret != 0) | |
80 | goto err_out; | |
81 | } | |
82 | s->key_frame = -1; | |
83 | s->convergence_duration = 0; | |
84 | s->dts_sync_point = INT_MIN; | |
85 | s->dts_ref_dts_delta = INT_MIN; | |
86 | s->pts_dts_delta = INT_MIN; | |
87 | return s; | |
88 | ||
89 | err_out: | |
90 | if (s) | |
91 | av_freep(&s->priv_data); | |
92 | av_free(s); | |
93 | return NULL; | |
94 | } | |
95 | ||
96 | void ff_fetch_timestamp(AVCodecParserContext *s, int off, int remove) | |
97 | { | |
98 | int i; | |
99 | ||
100 | s->dts = | |
101 | s->pts = AV_NOPTS_VALUE; | |
102 | s->pos = -1; | |
103 | s->offset = 0; | |
104 | for (i = 0; i < AV_PARSER_PTS_NB; i++) { | |
105 | if (s->cur_offset + off >= s->cur_frame_offset[i] && | |
106 | (s->frame_offset < s->cur_frame_offset[i] || | |
107 | (!s->frame_offset && !s->next_frame_offset)) && // first field/frame | |
108 | // check disabled since MPEG-TS does not send complete PES packets | |
109 | /*s->next_frame_offset + off <*/ s->cur_frame_end[i]){ | |
110 | ||
111 | s->dts = s->cur_frame_dts[i]; | |
112 | s->pts = s->cur_frame_pts[i]; | |
113 | s->pos = s->cur_frame_pos[i]; | |
114 | s->offset = s->next_frame_offset - s->cur_frame_offset[i]; | |
115 | if (remove) | |
116 | s->cur_frame_offset[i] = INT64_MAX; | |
117 | if (s->cur_offset + off < s->cur_frame_end[i]) | |
118 | break; | |
119 | } | |
120 | } | |
121 | } | |
122 | ||
123 | int av_parser_parse2(AVCodecParserContext *s, AVCodecContext *avctx, | |
124 | uint8_t **poutbuf, int *poutbuf_size, | |
125 | const uint8_t *buf, int buf_size, | |
126 | int64_t pts, int64_t dts, int64_t pos) | |
127 | { | |
128 | int index, i; | |
129 | uint8_t dummy_buf[FF_INPUT_BUFFER_PADDING_SIZE]; | |
130 | ||
131 | if (!(s->flags & PARSER_FLAG_FETCHED_OFFSET)) { | |
132 | s->next_frame_offset = | |
133 | s->cur_offset = pos; | |
134 | s->flags |= PARSER_FLAG_FETCHED_OFFSET; | |
135 | } | |
136 | ||
137 | if (buf_size == 0) { | |
138 | /* padding is always necessary even if EOF, so we add it here */ | |
139 | memset(dummy_buf, 0, sizeof(dummy_buf)); | |
140 | buf = dummy_buf; | |
141 | } else if (s->cur_offset + buf_size != s->cur_frame_end[s->cur_frame_start_index]) { /* skip remainder packets */ | |
142 | /* add a new packet descriptor */ | |
143 | i = (s->cur_frame_start_index + 1) & (AV_PARSER_PTS_NB - 1); | |
144 | s->cur_frame_start_index = i; | |
145 | s->cur_frame_offset[i] = s->cur_offset; | |
146 | s->cur_frame_end[i] = s->cur_offset + buf_size; | |
147 | s->cur_frame_pts[i] = pts; | |
148 | s->cur_frame_dts[i] = dts; | |
149 | s->cur_frame_pos[i] = pos; | |
150 | } | |
151 | ||
152 | if (s->fetch_timestamp) { | |
153 | s->fetch_timestamp = 0; | |
154 | s->last_pts = s->pts; | |
155 | s->last_dts = s->dts; | |
156 | s->last_pos = s->pos; | |
157 | ff_fetch_timestamp(s, 0, 0); | |
158 | } | |
159 | /* WARNING: the returned index can be negative */ | |
160 | index = s->parser->parser_parse(s, avctx, (const uint8_t **) poutbuf, | |
161 | poutbuf_size, buf, buf_size); | |
162 | /* update the file pointer */ | |
163 | if (*poutbuf_size) { | |
164 | /* fill the data for the current frame */ | |
165 | s->frame_offset = s->next_frame_offset; | |
166 | ||
167 | /* offset of the next frame */ | |
168 | s->next_frame_offset = s->cur_offset + index; | |
169 | s->fetch_timestamp = 1; | |
170 | } | |
171 | if (index < 0) | |
172 | index = 0; | |
173 | s->cur_offset += index; | |
174 | return index; | |
175 | } | |
176 | ||
177 | int av_parser_change(AVCodecParserContext *s, AVCodecContext *avctx, | |
178 | uint8_t **poutbuf, int *poutbuf_size, | |
179 | const uint8_t *buf, int buf_size, int keyframe) | |
180 | { | |
181 | if (s && s->parser->split) { | |
182 | if (avctx->flags & CODEC_FLAG_GLOBAL_HEADER || | |
183 | avctx->flags2 & CODEC_FLAG2_LOCAL_HEADER) { | |
184 | int i = s->parser->split(avctx, buf, buf_size); | |
185 | buf += i; | |
186 | buf_size -= i; | |
187 | } | |
188 | } | |
189 | ||
190 | /* cast to avoid warning about discarding qualifiers */ | |
191 | *poutbuf = (uint8_t *) buf; | |
192 | *poutbuf_size = buf_size; | |
193 | if (avctx->extradata) { | |
194 | if (keyframe && (avctx->flags2 & CODEC_FLAG2_LOCAL_HEADER)) { | |
195 | int size = buf_size + avctx->extradata_size; | |
196 | ||
197 | *poutbuf_size = size; | |
198 | *poutbuf = av_malloc(size + FF_INPUT_BUFFER_PADDING_SIZE); | |
199 | ||
200 | memcpy(*poutbuf, avctx->extradata, avctx->extradata_size); | |
201 | memcpy(*poutbuf + avctx->extradata_size, buf, | |
202 | buf_size + FF_INPUT_BUFFER_PADDING_SIZE); | |
203 | return 1; | |
204 | } | |
205 | } | |
206 | ||
207 | return 0; | |
208 | } | |
209 | ||
210 | void av_parser_close(AVCodecParserContext *s) | |
211 | { | |
212 | if (s) { | |
213 | if (s->parser->parser_close) | |
214 | s->parser->parser_close(s); | |
f6fa7814 | 215 | av_freep(&s->priv_data); |
2ba45a60 DM |
216 | av_free(s); |
217 | } | |
218 | } | |
219 | ||
220 | int ff_combine_frame(ParseContext *pc, int next, | |
221 | const uint8_t **buf, int *buf_size) | |
222 | { | |
223 | if (pc->overread) { | |
224 | av_dlog(NULL, "overread %d, state:%X next:%d index:%d o_index:%d\n", | |
225 | pc->overread, pc->state, next, pc->index, pc->overread_index); | |
226 | av_dlog(NULL, "%X %X %X %X\n", | |
227 | (*buf)[0], (*buf)[1], (*buf)[2], (*buf)[3]); | |
228 | } | |
229 | ||
230 | /* Copy overread bytes from last frame into buffer. */ | |
231 | for (; pc->overread > 0; pc->overread--) | |
232 | pc->buffer[pc->index++] = pc->buffer[pc->overread_index++]; | |
233 | ||
234 | /* flush remaining if EOF */ | |
235 | if (!*buf_size && next == END_NOT_FOUND) | |
236 | next = 0; | |
237 | ||
238 | pc->last_index = pc->index; | |
239 | ||
240 | /* copy into buffer end return */ | |
241 | if (next == END_NOT_FOUND) { | |
242 | void *new_buffer = av_fast_realloc(pc->buffer, &pc->buffer_size, | |
243 | *buf_size + pc->index + | |
244 | FF_INPUT_BUFFER_PADDING_SIZE); | |
245 | ||
246 | if (!new_buffer) { | |
247 | pc->index = 0; | |
248 | return AVERROR(ENOMEM); | |
249 | } | |
250 | pc->buffer = new_buffer; | |
251 | memcpy(&pc->buffer[pc->index], *buf, *buf_size); | |
252 | pc->index += *buf_size; | |
253 | return -1; | |
254 | } | |
255 | ||
256 | *buf_size = | |
257 | pc->overread_index = pc->index + next; | |
258 | ||
259 | /* append to buffer */ | |
260 | if (pc->index) { | |
261 | void *new_buffer = av_fast_realloc(pc->buffer, &pc->buffer_size, | |
262 | next + pc->index + | |
263 | FF_INPUT_BUFFER_PADDING_SIZE); | |
264 | if (!new_buffer) { | |
265 | pc->overread_index = | |
266 | pc->index = 0; | |
267 | return AVERROR(ENOMEM); | |
268 | } | |
269 | pc->buffer = new_buffer; | |
270 | if (next > -FF_INPUT_BUFFER_PADDING_SIZE) | |
271 | memcpy(&pc->buffer[pc->index], *buf, | |
272 | next + FF_INPUT_BUFFER_PADDING_SIZE); | |
273 | pc->index = 0; | |
274 | *buf = pc->buffer; | |
275 | } | |
276 | ||
277 | /* store overread bytes */ | |
278 | for (; next < 0; next++) { | |
279 | pc->state = pc->state << 8 | pc->buffer[pc->last_index + next]; | |
280 | pc->state64 = pc->state64 << 8 | pc->buffer[pc->last_index + next]; | |
281 | pc->overread++; | |
282 | } | |
283 | ||
284 | if (pc->overread) { | |
285 | av_dlog(NULL, "overread %d, state:%X next:%d index:%d o_index:%d\n", | |
286 | pc->overread, pc->state, next, pc->index, pc->overread_index); | |
287 | av_dlog(NULL, "%X %X %X %X\n", | |
288 | (*buf)[0], (*buf)[1], (*buf)[2], (*buf)[3]); | |
289 | } | |
290 | ||
291 | return 0; | |
292 | } | |
293 | ||
294 | void ff_parse_close(AVCodecParserContext *s) | |
295 | { | |
296 | ParseContext *pc = s->priv_data; | |
297 | ||
298 | av_freep(&pc->buffer); | |
299 | } | |
300 | ||
301 | int ff_mpeg4video_split(AVCodecContext *avctx, const uint8_t *buf, int buf_size) | |
302 | { | |
303 | int i; | |
304 | uint32_t state = -1; | |
305 | ||
306 | for (i = 0; i < buf_size; i++) { | |
307 | state = state << 8 | buf[i]; | |
308 | if (state == 0x1B3 || state == 0x1B6) | |
309 | return i - 3; | |
310 | } | |
311 | return 0; | |
312 | } |