/src/ffmpeg/libavcodec/adx_parser.c
Line | Count | Source |
1 | | /* |
2 | | * Copyright (c) 2011 Justin Ruggles |
3 | | * |
4 | | * This file is part of FFmpeg. |
5 | | * |
6 | | * FFmpeg is free software; you can redistribute it and/or |
7 | | * modify it under the terms of the GNU Lesser General Public |
8 | | * License as published by the Free Software Foundation; either |
9 | | * version 2.1 of the License, or (at your option) any later version. |
10 | | * |
11 | | * FFmpeg is distributed in the hope that it will be useful, |
12 | | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
13 | | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
14 | | * Lesser General Public License for more details. |
15 | | * |
16 | | * You should have received a copy of the GNU Lesser General Public |
17 | | * License along with FFmpeg; if not, write to the Free Software |
18 | | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
19 | | */ |
20 | | |
21 | | /** |
22 | | * @file |
23 | | * ADX audio parser |
24 | | * |
25 | | * Splits packets into individual blocks. |
26 | | */ |
27 | | |
28 | | #include "parser.h" |
29 | | #include "adx.h" |
30 | | #include "parser_internal.h" |
31 | | |
32 | | typedef struct ADXParseContext { |
33 | | ParseContext pc; |
34 | | int header_size; |
35 | | int block_size; |
36 | | int remaining; |
37 | | } ADXParseContext; |
38 | | |
39 | | static int adx_parse(AVCodecParserContext *s1, |
40 | | AVCodecContext *avctx, |
41 | | const uint8_t **poutbuf, int *poutbuf_size, |
42 | | const uint8_t *buf, int buf_size) |
43 | 715k | { |
44 | 715k | ADXParseContext *s = s1->priv_data; |
45 | 715k | ParseContext *pc = &s->pc; |
46 | 715k | int next = END_NOT_FOUND; |
47 | 715k | int i; |
48 | 715k | uint64_t state = pc->state64; |
49 | | |
50 | 715k | if (!s->header_size) { |
51 | 95.7M | for (i = 0; i < buf_size; i++) { |
52 | 95.7M | state = (state << 8) | buf[i]; |
53 | | /* check for fixed fields in ADX header for possible match */ |
54 | 95.7M | if ((state & 0xFFFF0000FFFFFF00) == 0x8000000003120400ULL) { |
55 | 20.7k | int channels = state & 0xFF; |
56 | 20.7k | int header_size = ((state >> 32) & 0xFFFF) + 4; |
57 | 20.7k | if (channels > 0 && header_size >= 8) { |
58 | 423 | s->header_size = header_size; |
59 | 423 | s->block_size = BLOCK_SIZE * channels; |
60 | 423 | s->remaining = i - 7 + s->header_size + s->block_size; |
61 | 423 | break; |
62 | 423 | } |
63 | 20.7k | } |
64 | 95.7M | } |
65 | 31.4k | pc->state64 = state; |
66 | 31.4k | } |
67 | | |
68 | 715k | if (s->header_size) { |
69 | 684k | if (!s->remaining) |
70 | 640k | s->remaining = s->block_size; |
71 | 684k | if (s->remaining <= buf_size) { |
72 | 640k | next = s->remaining; |
73 | 640k | s->remaining = 0; |
74 | 640k | } else |
75 | 44.1k | s->remaining -= buf_size; |
76 | 684k | } else if (avctx->ch_layout.nb_channels > 0) { |
77 | 10.4k | if (!s->block_size) |
78 | 18 | s->block_size = avctx->ch_layout.nb_channels * BLOCK_SIZE; |
79 | 10.4k | if (!s->remaining) |
80 | 10.4k | s->remaining = s->block_size; |
81 | 10.4k | if (s->remaining <= buf_size) { |
82 | 10.4k | next = s->remaining; |
83 | 10.4k | s->remaining = 0; |
84 | 10.4k | } else |
85 | 55 | s->remaining -= buf_size; |
86 | 10.4k | } |
87 | | |
88 | 715k | if (ff_combine_frame(pc, next, &buf, &buf_size) < 0 || !buf_size) { |
89 | 64.6k | *poutbuf = NULL; |
90 | 64.6k | *poutbuf_size = 0; |
91 | 64.6k | return buf_size; |
92 | 64.6k | } |
93 | | |
94 | 651k | s1->duration = BLOCK_SAMPLES; |
95 | | |
96 | 651k | *poutbuf = buf; |
97 | 651k | *poutbuf_size = buf_size; |
98 | 651k | return next; |
99 | 715k | } |
100 | | |
101 | | const FFCodecParser ff_adx_parser = { |
102 | | PARSER_CODEC_LIST(AV_CODEC_ID_ADPCM_ADX), |
103 | | .priv_data_size = sizeof(ADXParseContext), |
104 | | .parse = adx_parse, |
105 | | .close = ff_parse_close, |
106 | | }; |