Commit | Line | Data |
---|---|---|
2ba45a60 DM |
1 | /* |
2 | * DCA parser | |
3 | * Copyright (C) 2004 Gildas Bazin | |
4 | * Copyright (C) 2004 Benjamin Zores | |
5 | * Copyright (C) 2006 Benjamin Larsson | |
6 | * Copyright (C) 2007 Konstantin Shishkov | |
7 | * | |
8 | * This file is part of FFmpeg. | |
9 | * | |
10 | * FFmpeg is free software; you can redistribute it and/or | |
11 | * modify it under the terms of the GNU Lesser General Public | |
12 | * License as published by the Free Software Foundation; either | |
13 | * version 2.1 of the License, or (at your option) any later version. | |
14 | * | |
15 | * FFmpeg is distributed in the hope that it will be useful, | |
16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
18 | * Lesser General Public License for more details. | |
19 | * | |
20 | * You should have received a copy of the GNU Lesser General Public | |
21 | * License along with FFmpeg; if not, write to the Free Software | |
22 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | |
23 | */ | |
24 | ||
2ba45a60 DM |
25 | #include "dca.h" |
26 | #include "get_bits.h" | |
f6fa7814 | 27 | #include "parser.h" |
2ba45a60 DM |
28 | |
29 | typedef struct DCAParseContext { | |
30 | ParseContext pc; | |
31 | uint32_t lastmarker; | |
32 | int size; | |
33 | int framesize; | |
34 | int hd_pos; | |
35 | } DCAParseContext; | |
36 | ||
37 | #define IS_MARKER(state, i, buf, buf_size) \ | |
f6fa7814 DM |
38 | ((state == DCA_MARKER_14B_LE && (i < buf_size - 2) && (buf[i + 1] & 0xF0) == 0xF0 && buf[i + 2] == 0x07) || \ |
39 | (state == DCA_MARKER_14B_BE && (i < buf_size - 2) && buf[i + 1] == 0x07 && (buf[i + 2] & 0xF0) == 0xF0) || \ | |
40 | state == DCA_MARKER_RAW_LE || state == DCA_MARKER_RAW_BE || state == DCA_HD_MARKER) | |
2ba45a60 DM |
41 | |
42 | /** | |
43 | * Find the end of the current frame in the bitstream. | |
44 | * @return the position of the first byte of the next frame, or -1 | |
45 | */ | |
f6fa7814 | 46 | static int dca_find_frame_end(DCAParseContext *pc1, const uint8_t *buf, |
2ba45a60 DM |
47 | int buf_size) |
48 | { | |
49 | int start_found, i; | |
50 | uint32_t state; | |
51 | ParseContext *pc = &pc1->pc; | |
52 | ||
53 | start_found = pc->frame_start_found; | |
f6fa7814 | 54 | state = pc->state; |
2ba45a60 DM |
55 | |
56 | i = 0; | |
57 | if (!start_found) { | |
58 | for (i = 0; i < buf_size; i++) { | |
59 | state = (state << 8) | buf[i]; | |
60 | if (IS_MARKER(state, i, buf, buf_size)) { | |
61 | if (!pc1->lastmarker || state == pc1->lastmarker || pc1->lastmarker == DCA_HD_MARKER) { | |
f6fa7814 | 62 | start_found = 1; |
2ba45a60 DM |
63 | pc1->lastmarker = state; |
64 | i++; | |
65 | break; | |
66 | } | |
67 | } | |
68 | } | |
69 | } | |
70 | if (start_found) { | |
71 | for (; i < buf_size; i++) { | |
72 | pc1->size++; | |
73 | state = (state << 8) | buf[i]; | |
74 | if (state == DCA_HD_MARKER && !pc1->hd_pos) | |
75 | pc1->hd_pos = pc1->size; | |
76 | if (IS_MARKER(state, i, buf, buf_size) && (state == pc1->lastmarker || pc1->lastmarker == DCA_HD_MARKER)) { | |
f6fa7814 | 77 | if (pc1->framesize > pc1->size) |
2ba45a60 DM |
78 | continue; |
79 | pc->frame_start_found = 0; | |
f6fa7814 DM |
80 | pc->state = -1; |
81 | pc1->size = 0; | |
2ba45a60 DM |
82 | return i - 3; |
83 | } | |
84 | } | |
85 | } | |
86 | pc->frame_start_found = start_found; | |
f6fa7814 | 87 | pc->state = state; |
2ba45a60 DM |
88 | return END_NOT_FOUND; |
89 | } | |
90 | ||
f6fa7814 | 91 | static av_cold int dca_parse_init(AVCodecParserContext *s) |
2ba45a60 DM |
92 | { |
93 | DCAParseContext *pc1 = s->priv_data; | |
94 | ||
95 | pc1->lastmarker = 0; | |
96 | return 0; | |
97 | } | |
98 | ||
99 | static int dca_parse_params(const uint8_t *buf, int buf_size, int *duration, | |
100 | int *sample_rate, int *framesize) | |
101 | { | |
102 | GetBitContext gb; | |
103 | uint8_t hdr[12 + FF_INPUT_BUFFER_PADDING_SIZE] = { 0 }; | |
104 | int ret, sample_blocks, sr_code; | |
105 | ||
106 | if (buf_size < 12) | |
107 | return AVERROR_INVALIDDATA; | |
108 | ||
109 | if ((ret = avpriv_dca_convert_bitstream(buf, 12, hdr, 12)) < 0) | |
110 | return ret; | |
111 | ||
112 | init_get_bits(&gb, hdr, 96); | |
113 | ||
114 | skip_bits_long(&gb, 39); | |
115 | sample_blocks = get_bits(&gb, 7) + 1; | |
116 | if (sample_blocks < 8) | |
117 | return AVERROR_INVALIDDATA; | |
118 | *duration = 256 * (sample_blocks / 8); | |
119 | ||
120 | *framesize = get_bits(&gb, 14) + 1; | |
121 | if (*framesize < 95) | |
122 | return AVERROR_INVALIDDATA; | |
123 | ||
124 | skip_bits(&gb, 6); | |
f6fa7814 | 125 | sr_code = get_bits(&gb, 4); |
2ba45a60 DM |
126 | *sample_rate = avpriv_dca_sample_rates[sr_code]; |
127 | if (*sample_rate == 0) | |
128 | return AVERROR_INVALIDDATA; | |
129 | ||
130 | return 0; | |
131 | } | |
132 | ||
f6fa7814 DM |
133 | static int dca_parse(AVCodecParserContext *s, AVCodecContext *avctx, |
134 | const uint8_t **poutbuf, int *poutbuf_size, | |
135 | const uint8_t *buf, int buf_size) | |
2ba45a60 DM |
136 | { |
137 | DCAParseContext *pc1 = s->priv_data; | |
138 | ParseContext *pc = &pc1->pc; | |
139 | int next, duration, sample_rate; | |
140 | ||
141 | if (s->flags & PARSER_FLAG_COMPLETE_FRAMES) { | |
142 | next = buf_size; | |
143 | } else { | |
144 | next = dca_find_frame_end(pc1, buf, buf_size); | |
145 | ||
146 | if (ff_combine_frame(pc, next, &buf, &buf_size) < 0) { | |
f6fa7814 | 147 | *poutbuf = NULL; |
2ba45a60 DM |
148 | *poutbuf_size = 0; |
149 | return buf_size; | |
150 | } | |
151 | } | |
152 | ||
153 | /* read the duration and sample rate from the frame header */ | |
154 | if (!dca_parse_params(buf, buf_size, &duration, &sample_rate, &pc1->framesize)) { | |
f6fa7814 | 155 | s->duration = duration; |
2ba45a60 DM |
156 | avctx->sample_rate = sample_rate; |
157 | } else | |
158 | s->duration = 0; | |
159 | ||
f6fa7814 | 160 | *poutbuf = buf; |
2ba45a60 DM |
161 | *poutbuf_size = buf_size; |
162 | return next; | |
163 | } | |
164 | ||
165 | AVCodecParser ff_dca_parser = { | |
166 | .codec_ids = { AV_CODEC_ID_DTS }, | |
167 | .priv_data_size = sizeof(DCAParseContext), | |
168 | .parser_init = dca_parse_init, | |
169 | .parser_parse = dca_parse, | |
170 | .parser_close = ff_parse_close, | |
171 | }; |