The decoder is just a wrapper around the AAC decoder.
based on patch by Paul Kendall { paul <ät> kcbbs gen nz }
Originally committed as revision 25642 to svn://svn.ffmpeg.org/ffmpeg/trunk
... | ... |
@@ -1188,6 +1188,7 @@ rdft_select="fft" |
1188 | 1188 |
# decoders / encoders / hardware accelerators |
1189 | 1189 |
aac_decoder_select="mdct rdft" |
1190 | 1190 |
aac_encoder_select="mdct" |
1191 |
+aac_latm_decoder_select="aac_decoder aac_latm_parser" |
|
1191 | 1192 |
ac3_decoder_select="mdct ac3_parser" |
1192 | 1193 |
alac_encoder_select="lpc" |
1193 | 1194 |
amrnb_decoder_select="lsp" |
... | ... |
@@ -576,6 +576,7 @@ OBJS-$(CONFIG_H264_PARSER) += h264_parser.o h264.o \ |
576 | 576 |
h264_loopfilter.o h264_cabac.o \ |
577 | 577 |
h264_cavlc.o h264_ps.o \ |
578 | 578 |
mpegvideo.o error_resilience.o |
579 |
+OBJS-$(CONFIG_AAC_LATM_PARSER) += latm_parser.o |
|
579 | 580 |
OBJS-$(CONFIG_MJPEG_PARSER) += mjpeg_parser.o |
580 | 581 |
OBJS-$(CONFIG_MLP_PARSER) += mlp_parser.o mlp.o |
581 | 582 |
OBJS-$(CONFIG_MPEG4VIDEO_PARSER) += mpeg4video_parser.o h263.o \ |
... | ... |
@@ -3,6 +3,10 @@ |
3 | 3 |
* Copyright (c) 2005-2006 Oded Shimon ( ods15 ods15 dyndns org ) |
4 | 4 |
* Copyright (c) 2006-2007 Maxim Gavrilov ( maxim.gavrilov gmail com ) |
5 | 5 |
* |
6 |
+ * AAC LATM decoder |
|
7 |
+ * Copyright (c) 2008-2010 Paul Kendall <paul@kcbbs.gen.nz> |
|
8 |
+ * Copyright (c) 2010 Janne Grunau <janne-ffmpeg@jannau.net> |
|
9 |
+ * |
|
6 | 10 |
* This file is part of FFmpeg. |
7 | 11 |
* |
8 | 12 |
* FFmpeg is free software; you can redistribute it and/or |
... | ... |
@@ -2098,6 +2102,261 @@ static av_cold int aac_decode_close(AVCodecContext *avctx) |
2098 | 2098 |
return 0; |
2099 | 2099 |
} |
2100 | 2100 |
|
2101 |
+ |
|
2102 |
+#define LOAS_SYNC_WORD 0x2b7 ///< 11 bits LOAS sync word |
|
2103 |
+ |
|
2104 |
+struct LATMContext { |
|
2105 |
+ AACContext aac_ctx; ///< containing AACContext |
|
2106 |
+ int initialized; ///< initilized after a valid extradata was seen |
|
2107 |
+ |
|
2108 |
+ // parser data |
|
2109 |
+ int audio_mux_version_A; ///< LATM syntax version |
|
2110 |
+ int frame_length_type; ///< 0/1 variable/fixed frame length |
|
2111 |
+ int frame_length; ///< frame length for fixed frame length |
|
2112 |
+}; |
|
2113 |
+ |
|
2114 |
+static inline uint32_t latm_get_value(GetBitContext *b) |
|
2115 |
+{ |
|
2116 |
+ int length = get_bits(b, 2); |
|
2117 |
+ |
|
2118 |
+ return get_bits_long(b, (length+1)*8); |
|
2119 |
+} |
|
2120 |
+ |
|
2121 |
+static int latm_decode_audio_specific_config(struct LATMContext *latmctx, |
|
2122 |
+ GetBitContext *gb) |
|
2123 |
+{ |
|
2124 |
+ AVCodecContext *avctx = latmctx->aac_ctx.avctx; |
|
2125 |
+ MPEG4AudioConfig m4ac; |
|
2126 |
+ int config_start_bit = get_bits_count(gb); |
|
2127 |
+ int bits_consumed, esize; |
|
2128 |
+ |
|
2129 |
+ if (config_start_bit % 8) { |
|
2130 |
+ av_log_missing_feature(latmctx->aac_ctx.avctx, "audio specific " |
|
2131 |
+ "config not byte aligned.\n", 1); |
|
2132 |
+ return AVERROR_INVALIDDATA; |
|
2133 |
+ } else { |
|
2134 |
+ bits_consumed = |
|
2135 |
+ decode_audio_specific_config(NULL, avctx, &m4ac, |
|
2136 |
+ gb->buffer + (config_start_bit / 8), |
|
2137 |
+ get_bits_left(gb) / 8); |
|
2138 |
+ |
|
2139 |
+ if (bits_consumed < 0) |
|
2140 |
+ return AVERROR_INVALIDDATA; |
|
2141 |
+ |
|
2142 |
+ esize = (bits_consumed+7) / 8; |
|
2143 |
+ |
|
2144 |
+ if (avctx->extradata_size <= esize) { |
|
2145 |
+ av_free(avctx->extradata); |
|
2146 |
+ avctx->extradata = av_malloc(esize + FF_INPUT_BUFFER_PADDING_SIZE); |
|
2147 |
+ if (!avctx->extradata) |
|
2148 |
+ return AVERROR(ENOMEM); |
|
2149 |
+ } |
|
2150 |
+ |
|
2151 |
+ avctx->extradata_size = esize; |
|
2152 |
+ memcpy(avctx->extradata, gb->buffer + (config_start_bit/8), esize); |
|
2153 |
+ memset(avctx->extradata+esize, 0, FF_INPUT_BUFFER_PADDING_SIZE); |
|
2154 |
+ } |
|
2155 |
+ |
|
2156 |
+ return bits_consumed; |
|
2157 |
+} |
|
2158 |
+ |
|
2159 |
+static int read_stream_mux_config(struct LATMContext *latmctx, |
|
2160 |
+ GetBitContext *gb) |
|
2161 |
+{ |
|
2162 |
+ int ret, audio_mux_version = get_bits(gb, 1); |
|
2163 |
+ |
|
2164 |
+ latmctx->audio_mux_version_A = 0; |
|
2165 |
+ if (audio_mux_version) |
|
2166 |
+ latmctx->audio_mux_version_A = get_bits(gb, 1); |
|
2167 |
+ |
|
2168 |
+ if (!latmctx->audio_mux_version_A) { |
|
2169 |
+ |
|
2170 |
+ if (audio_mux_version) |
|
2171 |
+ latm_get_value(gb); // taraFullness |
|
2172 |
+ |
|
2173 |
+ skip_bits(gb, 1); // allStreamSameTimeFraming |
|
2174 |
+ skip_bits(gb, 6); // numSubFrames |
|
2175 |
+ // numPrograms |
|
2176 |
+ if (get_bits(gb, 4)) { // numPrograms |
|
2177 |
+ av_log_missing_feature(latmctx->aac_ctx.avctx, |
|
2178 |
+ "multiple programs are not supported\n", 1); |
|
2179 |
+ return AVERROR_PATCHWELCOME; |
|
2180 |
+ } |
|
2181 |
+ |
|
2182 |
+ // for each program (which there is only on in DVB) |
|
2183 |
+ |
|
2184 |
+ // for each layer (which there is only on in DVB) |
|
2185 |
+ if (get_bits(gb, 3)) { // numLayer |
|
2186 |
+ av_log_missing_feature(latmctx->aac_ctx.avctx, |
|
2187 |
+ "multiple layers are not supported\n", 1); |
|
2188 |
+ return AVERROR_PATCHWELCOME; |
|
2189 |
+ } |
|
2190 |
+ |
|
2191 |
+ // for all but first stream: use_same_config = get_bits(gb, 1); |
|
2192 |
+ if (!audio_mux_version) { |
|
2193 |
+ if ((ret = latm_decode_audio_specific_config(latmctx, gb)) < 0) |
|
2194 |
+ return ret; |
|
2195 |
+ } else { |
|
2196 |
+ int ascLen = latm_get_value(gb); |
|
2197 |
+ if ((ret = latm_decode_audio_specific_config(latmctx, gb)) < 0) |
|
2198 |
+ return ret; |
|
2199 |
+ ascLen -= ret; |
|
2200 |
+ skip_bits_long(gb, ascLen); |
|
2201 |
+ } |
|
2202 |
+ |
|
2203 |
+ latmctx->frame_length_type = get_bits(gb, 3); |
|
2204 |
+ switch (latmctx->frame_length_type) { |
|
2205 |
+ case 0: |
|
2206 |
+ skip_bits(gb, 8); // latmBufferFullness |
|
2207 |
+ break; |
|
2208 |
+ case 1: |
|
2209 |
+ latmctx->frame_length = get_bits(gb, 9); |
|
2210 |
+ break; |
|
2211 |
+ case 3: |
|
2212 |
+ case 4: |
|
2213 |
+ case 5: |
|
2214 |
+ skip_bits(gb, 6); // CELP frame length table index |
|
2215 |
+ break; |
|
2216 |
+ case 6: |
|
2217 |
+ case 7: |
|
2218 |
+ skip_bits(gb, 1); // HVXC frame length table index |
|
2219 |
+ break; |
|
2220 |
+ } |
|
2221 |
+ |
|
2222 |
+ if (get_bits(gb, 1)) { // other data |
|
2223 |
+ if (audio_mux_version) { |
|
2224 |
+ latm_get_value(gb); // other_data_bits |
|
2225 |
+ } else { |
|
2226 |
+ int esc; |
|
2227 |
+ do { |
|
2228 |
+ esc = get_bits(gb, 1); |
|
2229 |
+ skip_bits(gb, 8); |
|
2230 |
+ } while (esc); |
|
2231 |
+ } |
|
2232 |
+ } |
|
2233 |
+ |
|
2234 |
+ if (get_bits(gb, 1)) // crc present |
|
2235 |
+ skip_bits(gb, 8); // config_crc |
|
2236 |
+ } |
|
2237 |
+ |
|
2238 |
+ return 0; |
|
2239 |
+} |
|
2240 |
+ |
|
2241 |
+static int read_payload_length_info(struct LATMContext *ctx, GetBitContext *gb) |
|
2242 |
+{ |
|
2243 |
+ uint8_t tmp; |
|
2244 |
+ |
|
2245 |
+ if (ctx->frame_length_type == 0) { |
|
2246 |
+ int mux_slot_length = 0; |
|
2247 |
+ do { |
|
2248 |
+ tmp = get_bits(gb, 8); |
|
2249 |
+ mux_slot_length += tmp; |
|
2250 |
+ } while (tmp == 255); |
|
2251 |
+ return mux_slot_length; |
|
2252 |
+ } else if (ctx->frame_length_type == 1) { |
|
2253 |
+ return ctx->frame_length; |
|
2254 |
+ } else if (ctx->frame_length_type == 3 || |
|
2255 |
+ ctx->frame_length_type == 5 || |
|
2256 |
+ ctx->frame_length_type == 7) { |
|
2257 |
+ skip_bits(gb, 2); // mux_slot_length_coded |
|
2258 |
+ } |
|
2259 |
+ return 0; |
|
2260 |
+} |
|
2261 |
+ |
|
2262 |
+static int read_audio_mux_element(struct LATMContext *latmctx, |
|
2263 |
+ GetBitContext *gb) |
|
2264 |
+{ |
|
2265 |
+ int err; |
|
2266 |
+ uint8_t use_same_mux = get_bits(gb, 1); |
|
2267 |
+ if (!use_same_mux) { |
|
2268 |
+ if ((err = read_stream_mux_config(latmctx, gb)) < 0) |
|
2269 |
+ return err; |
|
2270 |
+ } else if (!latmctx->aac_ctx.avctx->extradata) { |
|
2271 |
+ av_log(latmctx->aac_ctx.avctx, AV_LOG_DEBUG, |
|
2272 |
+ "no decoder config found\n"); |
|
2273 |
+ return AVERROR(EAGAIN); |
|
2274 |
+ } |
|
2275 |
+ if (latmctx->audio_mux_version_A == 0) { |
|
2276 |
+ int mux_slot_length_bytes = read_payload_length_info(latmctx, gb); |
|
2277 |
+ if (mux_slot_length_bytes * 8 > get_bits_left(gb)) { |
|
2278 |
+ av_log(latmctx->aac_ctx.avctx, AV_LOG_ERROR, "incomplete frame\n"); |
|
2279 |
+ return AVERROR_INVALIDDATA; |
|
2280 |
+ } else if (mux_slot_length_bytes * 8 + 256 < get_bits_left(gb)) { |
|
2281 |
+ av_log(latmctx->aac_ctx.avctx, AV_LOG_ERROR, |
|
2282 |
+ "frame length mismatch %d << %d\n", |
|
2283 |
+ mux_slot_length_bytes * 8, get_bits_left(gb)); |
|
2284 |
+ return AVERROR_INVALIDDATA; |
|
2285 |
+ } |
|
2286 |
+ } |
|
2287 |
+ return 0; |
|
2288 |
+} |
|
2289 |
+ |
|
2290 |
+ |
|
2291 |
+static int latm_decode_frame(AVCodecContext *avctx, void *out, int *out_size, |
|
2292 |
+ AVPacket *avpkt) |
|
2293 |
+{ |
|
2294 |
+ struct LATMContext *latmctx = avctx->priv_data; |
|
2295 |
+ int muxlength, err; |
|
2296 |
+ GetBitContext gb; |
|
2297 |
+ |
|
2298 |
+ if (avpkt->size == 0) |
|
2299 |
+ return 0; |
|
2300 |
+ |
|
2301 |
+ init_get_bits(&gb, avpkt->data, avpkt->size * 8); |
|
2302 |
+ |
|
2303 |
+ // check for LOAS sync word |
|
2304 |
+ if (get_bits(&gb, 11) != LOAS_SYNC_WORD) |
|
2305 |
+ return AVERROR_INVALIDDATA; |
|
2306 |
+ |
|
2307 |
+ muxlength = get_bits(&gb, 13); |
|
2308 |
+ // not enough data, the parser should have sorted this |
|
2309 |
+ if (muxlength+3 > avpkt->size) |
|
2310 |
+ return AVERROR_INVALIDDATA; |
|
2311 |
+ |
|
2312 |
+ if ((err = read_audio_mux_element(latmctx, &gb)) < 0) |
|
2313 |
+ return err; |
|
2314 |
+ |
|
2315 |
+ if (!latmctx->initialized) { |
|
2316 |
+ if (!avctx->extradata) { |
|
2317 |
+ *out_size = 0; |
|
2318 |
+ return avpkt->size; |
|
2319 |
+ } else { |
|
2320 |
+ if ((err = aac_decode_init(avctx)) < 0) |
|
2321 |
+ return err; |
|
2322 |
+ latmctx->initialized = 1; |
|
2323 |
+ } |
|
2324 |
+ } |
|
2325 |
+ |
|
2326 |
+ if (show_bits(&gb, 12) == 0xfff) { |
|
2327 |
+ av_log(latmctx->aac_ctx.avctx, AV_LOG_ERROR, |
|
2328 |
+ "ADTS header detected, probably as result of configuration " |
|
2329 |
+ "misparsing\n"); |
|
2330 |
+ return AVERROR_INVALIDDATA; |
|
2331 |
+ } |
|
2332 |
+ |
|
2333 |
+ if ((err = aac_decode_frame_int(avctx, out, out_size, &gb)) < 0) |
|
2334 |
+ return err; |
|
2335 |
+ |
|
2336 |
+ return muxlength; |
|
2337 |
+} |
|
2338 |
+ |
|
2339 |
+av_cold static int latm_decode_init(AVCodecContext *avctx) |
|
2340 |
+{ |
|
2341 |
+ struct LATMContext *latmctx = avctx->priv_data; |
|
2342 |
+ int ret; |
|
2343 |
+ |
|
2344 |
+ ret = aac_decode_init(avctx); |
|
2345 |
+ |
|
2346 |
+ if (avctx->extradata_size > 0) { |
|
2347 |
+ latmctx->initialized = !ret; |
|
2348 |
+ } else { |
|
2349 |
+ latmctx->initialized = 0; |
|
2350 |
+ } |
|
2351 |
+ |
|
2352 |
+ return ret; |
|
2353 |
+} |
|
2354 |
+ |
|
2355 |
+ |
|
2101 | 2356 |
AVCodec aac_decoder = { |
2102 | 2357 |
"aac", |
2103 | 2358 |
AVMEDIA_TYPE_AUDIO, |
... | ... |
@@ -2113,3 +2372,23 @@ AVCodec aac_decoder = { |
2113 | 2113 |
}, |
2114 | 2114 |
.channel_layouts = aac_channel_layout, |
2115 | 2115 |
}; |
2116 |
+ |
|
2117 |
+/* |
|
2118 |
+ Note: This decoder filter is intended to decode LATM streams transferred |
|
2119 |
+ in MPEG transport streams which only contain one program. |
|
2120 |
+ To do a more complex LATM demuxing a separate LATM demuxer should be used. |
|
2121 |
+*/ |
|
2122 |
+AVCodec aac_latm_decoder = { |
|
2123 |
+ .name = "aac_latm", |
|
2124 |
+ .type = CODEC_TYPE_AUDIO, |
|
2125 |
+ .id = CODEC_ID_AAC_LATM, |
|
2126 |
+ .priv_data_size = sizeof(struct LATMContext), |
|
2127 |
+ .init = latm_decode_init, |
|
2128 |
+ .close = aac_decode_close, |
|
2129 |
+ .decode = latm_decode_frame, |
|
2130 |
+ .long_name = NULL_IF_CONFIG_SMALL("AAC LATM (Advanced Audio Codec LATM syntax)"), |
|
2131 |
+ .sample_fmts = (const enum SampleFormat[]) { |
|
2132 |
+ SAMPLE_FMT_S16,SAMPLE_FMT_NONE |
|
2133 |
+ }, |
|
2134 |
+ .channel_layouts = aac_channel_layout, |
|
2135 |
+}; |
... | ... |
@@ -220,6 +220,7 @@ void avcodec_register_all(void) |
220 | 220 |
|
221 | 221 |
/* audio codecs */ |
222 | 222 |
REGISTER_ENCDEC (AAC, aac); |
223 |
+ REGISTER_DECODER (AAC_LATM, aac_latm); |
|
223 | 224 |
REGISTER_ENCDEC (AC3, ac3); |
224 | 225 |
REGISTER_ENCDEC (ALAC, alac); |
225 | 226 |
REGISTER_DECODER (ALS, als); |
... | ... |
@@ -366,6 +367,7 @@ void avcodec_register_all(void) |
366 | 366 |
|
367 | 367 |
/* parsers */ |
368 | 368 |
REGISTER_PARSER (AAC, aac); |
369 |
+ REGISTER_PARSER (AAC_LATM, aac_latm); |
|
369 | 370 |
REGISTER_PARSER (AC3, ac3); |
370 | 371 |
REGISTER_PARSER (CAVSVIDEO, cavsvideo); |
371 | 372 |
REGISTER_PARSER (DCA, dca); |
... | ... |
@@ -31,7 +31,7 @@ |
31 | 31 |
#include "libavutil/cpu.h" |
32 | 32 |
|
33 | 33 |
#define LIBAVCODEC_VERSION_MAJOR 52 |
34 |
-#define LIBAVCODEC_VERSION_MINOR 93 |
|
34 |
+#define LIBAVCODEC_VERSION_MINOR 94 |
|
35 | 35 |
#define LIBAVCODEC_VERSION_MICRO 0 |
36 | 36 |
|
37 | 37 |
#define LIBAVCODEC_VERSION_INT AV_VERSION_INT(LIBAVCODEC_VERSION_MAJOR, \ |
... | ... |
@@ -376,6 +376,7 @@ enum CodecID { |
376 | 376 |
CODEC_ID_ATRAC1, |
377 | 377 |
CODEC_ID_BINKAUDIO_RDFT, |
378 | 378 |
CODEC_ID_BINKAUDIO_DCT, |
379 |
+ CODEC_ID_AAC_LATM, |
|
379 | 380 |
|
380 | 381 |
/* subtitle codecs */ |
381 | 382 |
CODEC_ID_DVD_SUBTITLE= 0x17000, |
382 | 383 |
new file mode 100644 |
... | ... |
@@ -0,0 +1,119 @@ |
0 |
+/* |
|
1 |
+ * copyright (c) 2008 Paul Kendall <paul@kcbbs.gen.nz> |
|
2 |
+ * |
|
3 |
+ * This file is part of FFmpeg. |
|
4 |
+ * |
|
5 |
+ * FFmpeg is free software; you can redistribute it and/or |
|
6 |
+ * modify it under the terms of the GNU Lesser General Public |
|
7 |
+ * License as published by the Free Software Foundation; either |
|
8 |
+ * version 2.1 of the License, or (at your option) any later version. |
|
9 |
+ * |
|
10 |
+ * FFmpeg is distributed in the hope that it will be useful, |
|
11 |
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
12 |
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
|
13 |
+ * Lesser General Public License for more details. |
|
14 |
+ * |
|
15 |
+ * You should have received a copy of the GNU Lesser General Public |
|
16 |
+ * License along with FFmpeg; if not, write to the Free Software |
|
17 |
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
|
18 |
+ */ |
|
19 |
+ |
|
20 |
+/** |
|
21 |
+ * @file |
|
22 |
+ * AAC LATM parser |
|
23 |
+ */ |
|
24 |
+ |
|
25 |
+#include <stdio.h> |
|
26 |
+#include <stdlib.h> |
|
27 |
+#include <string.h> |
|
28 |
+#include <math.h> |
|
29 |
+#include <sys/types.h> |
|
30 |
+ |
|
31 |
+#include "parser.h" |
|
32 |
+ |
|
33 |
+#define LATM_HEADER 0x56e000 // 0x2b7 (11 bits) |
|
34 |
+#define LATM_MASK 0xFFE000 // top 11 bits |
|
35 |
+#define LATM_SIZE_MASK 0x001FFF // bottom 13 bits |
|
36 |
+ |
|
37 |
+typedef struct LATMParseContext{ |
|
38 |
+ ParseContext pc; |
|
39 |
+ int count; |
|
40 |
+} LATMParseContext; |
|
41 |
+ |
|
42 |
+/** |
|
43 |
+ * finds the end of the current frame in the bitstream. |
|
44 |
+ * @return the position of the first byte of the next frame, or -1 |
|
45 |
+ */ |
|
46 |
+static int latm_find_frame_end(AVCodecParserContext *s1, const uint8_t *buf, |
|
47 |
+ int buf_size) |
|
48 |
+{ |
|
49 |
+ LATMParseContext *s = s1->priv_data; |
|
50 |
+ ParseContext *pc = &s->pc; |
|
51 |
+ int pic_found, i; |
|
52 |
+ uint32_t state; |
|
53 |
+ |
|
54 |
+ pic_found = pc->frame_start_found; |
|
55 |
+ state = pc->state; |
|
56 |
+ |
|
57 |
+ i = 0; |
|
58 |
+ if (!pic_found) { |
|
59 |
+ for (i = 0; i < buf_size; i++) { |
|
60 |
+ state = (state<<8) | buf[i]; |
|
61 |
+ if ((state & LATM_MASK) == LATM_HEADER) { |
|
62 |
+ i++; |
|
63 |
+ s->count = -i; |
|
64 |
+ pic_found = 1; |
|
65 |
+ break; |
|
66 |
+ } |
|
67 |
+ } |
|
68 |
+ } |
|
69 |
+ |
|
70 |
+ if (pic_found) { |
|
71 |
+ /* EOF considered as end of frame */ |
|
72 |
+ if (buf_size == 0) |
|
73 |
+ return 0; |
|
74 |
+ if ((state & LATM_SIZE_MASK) - s->count <= buf_size) { |
|
75 |
+ pc->frame_start_found = 0; |
|
76 |
+ pc->state = -1; |
|
77 |
+ return (state & LATM_SIZE_MASK) - s->count; |
|
78 |
+ } |
|
79 |
+ } |
|
80 |
+ |
|
81 |
+ s->count += buf_size; |
|
82 |
+ pc->frame_start_found = pic_found; |
|
83 |
+ pc->state = state; |
|
84 |
+ |
|
85 |
+ return END_NOT_FOUND; |
|
86 |
+} |
|
87 |
+ |
|
88 |
+static int latm_parse(AVCodecParserContext *s1, AVCodecContext *avctx, |
|
89 |
+ const uint8_t **poutbuf, int *poutbuf_size, |
|
90 |
+ const uint8_t *buf, int buf_size) |
|
91 |
+{ |
|
92 |
+ LATMParseContext *s = s1->priv_data; |
|
93 |
+ ParseContext *pc = &s->pc; |
|
94 |
+ int next; |
|
95 |
+ |
|
96 |
+ if (s1->flags & PARSER_FLAG_COMPLETE_FRAMES) { |
|
97 |
+ next = buf_size; |
|
98 |
+ } else { |
|
99 |
+ next = latm_find_frame_end(s1, buf, buf_size); |
|
100 |
+ |
|
101 |
+ if (ff_combine_frame(pc, next, &buf, &buf_size) < 0) { |
|
102 |
+ *poutbuf = NULL; |
|
103 |
+ *poutbuf_size = 0; |
|
104 |
+ return buf_size; |
|
105 |
+ } |
|
106 |
+ } |
|
107 |
+ *poutbuf = buf; |
|
108 |
+ *poutbuf_size = buf_size; |
|
109 |
+ return next; |
|
110 |
+} |
|
111 |
+ |
|
112 |
+AVCodecParser aac_latm_parser = { |
|
113 |
+ { CODEC_ID_AAC_LATM }, |
|
114 |
+ sizeof(LATMParseContext), |
|
115 |
+ NULL, |
|
116 |
+ latm_parse, |
|
117 |
+ ff_parse_close |
|
118 |
+}; |