Mercurial > mplayer.hg
annotate libmpcodecs/ad_spdif.c @ 35627:51358e7bde85
Cosmetic: Add and adjust comments.
author | ib |
---|---|
date | Thu, 10 Jan 2013 10:48:27 +0000 |
parents | 2b45dfcde03c |
children | 8517826b0dbd |
rev | line source |
---|---|
34103 | 1 /* |
2 * This file is part of MPlayer. | |
3 * | |
4 * MPlayer is free software; you can redistribute it and/or modify | |
5 * it under the terms of the GNU General Public License as published by | |
6 * the Free Software Foundation; either version 2 of the License, or | |
7 * (at your option) any later version. | |
8 * | |
9 * MPlayer is distributed in the hope that it will be useful, | |
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
12 * GNU General Public License for more details. | |
13 * | |
14 * You should have received a copy of the GNU General Public License along | |
15 * with MPlayer; if not, write to the Free Software Foundation, Inc., | |
16 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | |
17 */ | |
18 | |
19 #include <string.h> | |
20 | |
21 #include "config.h" | |
22 #include "mp_msg.h" | |
23 #include "ad_internal.h" | |
34206
92841858c5cb
Use init_avformat() instead of av_register_all().
cehoyos
parents:
34205
diff
changeset
|
24 #include "av_helpers.h" |
34103 | 25 #include "libavformat/avformat.h" |
26 #include "libavcodec/avcodec.h" | |
27 #include "libavutil/opt.h" | |
28 | |
29 static const ad_info_t info = { | |
30 "libavformat/spdifenc audio pass-through decoder.", | |
31 "spdif", | |
32 "Naoya OYAMA", | |
33 "Naoya OYAMA", | |
34 "For ALL hardware decoders" | |
35 }; | |
36 | |
37 LIBAD_EXTERN(spdif) | |
38 | |
39 #define FILENAME_SPDIFENC "spdif" | |
40 #define OUTBUF_SIZE 65536 | |
41 struct spdifContext { | |
42 AVFormatContext *lavf_ctx; | |
43 int iec61937_packet_size; | |
44 int out_buffer_len; | |
45 int out_buffer_size; | |
46 uint8_t *out_buffer; | |
47 uint8_t pb_buffer[OUTBUF_SIZE]; | |
48 }; | |
49 | |
50 static int read_packet(void *p, uint8_t *buf, int buf_size) | |
51 { | |
52 // spdifenc does not use read callback. | |
53 return 0; | |
54 } | |
55 | |
56 static int write_packet(void *p, uint8_t *buf, int buf_size) | |
57 { | |
58 int len; | |
59 struct spdifContext *ctx = p; | |
60 | |
61 len = FFMIN(buf_size, ctx->out_buffer_size -ctx->out_buffer_len); | |
62 memcpy(&ctx->out_buffer[ctx->out_buffer_len], buf, len); | |
63 ctx->out_buffer_len += len; | |
64 return len; | |
65 } | |
66 | |
67 static int64_t seek(void *p, int64_t offset, int whence) | |
68 { | |
69 // spdifenc does not use seek callback. | |
70 return 0; | |
71 } | |
72 | |
73 static int preinit(sh_audio_t *sh) | |
74 { | |
75 sh->samplesize = 2; | |
76 return 1; | |
77 } | |
78 | |
79 static int init(sh_audio_t *sh) | |
80 { | |
81 int i, x, in_size, srate, bps, *dtshd_rate; | |
82 unsigned char *start; | |
83 double pts; | |
84 static const struct { | |
85 const char *name; enum CodecID id; | |
86 } fmt_id_type[] = { | |
87 { "aac" , CODEC_ID_AAC }, | |
88 { "ac3" , CODEC_ID_AC3 }, | |
89 { "dca" , CODEC_ID_DTS }, | |
90 { "eac3", CODEC_ID_EAC3 }, | |
91 { "mpa" , CODEC_ID_MP3 }, | |
92 { "thd" , CODEC_ID_TRUEHD }, | |
93 { NULL , 0 } | |
94 }; | |
95 AVFormatContext *lavf_ctx = NULL; | |
96 AVStream *stream = NULL; | |
97 const AVOption *opt = NULL; | |
98 struct spdifContext *spdif_ctx = NULL; | |
99 | |
100 spdif_ctx = av_mallocz(sizeof(*spdif_ctx)); | |
101 if (!spdif_ctx) | |
102 goto fail; | |
103 spdif_ctx->lavf_ctx = avformat_alloc_context(); | |
104 if (!spdif_ctx->lavf_ctx) | |
105 goto fail; | |
106 | |
107 sh->context = spdif_ctx; | |
108 lavf_ctx = spdif_ctx->lavf_ctx; | |
109 | |
34206
92841858c5cb
Use init_avformat() instead of av_register_all().
cehoyos
parents:
34205
diff
changeset
|
110 init_avformat(); |
34103 | 111 lavf_ctx->oformat = av_guess_format(FILENAME_SPDIFENC, NULL, NULL); |
112 if (!lavf_ctx->oformat) | |
113 goto fail; | |
114 lavf_ctx->priv_data = av_mallocz(lavf_ctx->oformat->priv_data_size); | |
115 if (!lavf_ctx->priv_data) | |
116 goto fail; | |
117 lavf_ctx->pb = avio_alloc_context(spdif_ctx->pb_buffer, OUTBUF_SIZE, 1, spdif_ctx, | |
118 read_packet, write_packet, seek); | |
119 if (!lavf_ctx->pb) | |
120 goto fail; | |
34204
c1b5018b5edb
Use new API avformat_new_stream() instead of the deprecated
cehoyos
parents:
34203
diff
changeset
|
121 stream = avformat_new_stream(lavf_ctx, 0); |
34103 | 122 if (!stream) |
123 goto fail; | |
124 lavf_ctx->duration = AV_NOPTS_VALUE; | |
125 lavf_ctx->start_time = AV_NOPTS_VALUE; | |
126 for (i = 0; fmt_id_type[i].name; i++) { | |
127 if (!strcmp(sh->codec->dll, fmt_id_type[i].name)) { | |
128 lavf_ctx->streams[0]->codec->codec_id = fmt_id_type[i].id; | |
129 break; | |
130 } | |
131 } | |
132 lavf_ctx->raw_packet_buffer_remaining_size = RAW_PACKET_BUFFER_SIZE; | |
133 if (AVERROR_PATCHWELCOME == lavf_ctx->oformat->write_header(lavf_ctx)) { | |
134 mp_msg(MSGT_DECAUDIO,MSGL_INFO, | |
135 "This codec is not supported by spdifenc.\n"); | |
136 goto fail; | |
137 } | |
138 | |
139 // get sample_rate & bitrate from parser | |
140 x = ds_get_packet_pts(sh->ds, &start, &pts); | |
141 in_size = x; | |
142 if (x <= 0) { | |
143 pts = MP_NOPTS_VALUE; | |
144 x = 0; | |
145 } | |
146 ds_parse(sh->ds, &start, &x, pts, 0); | |
35423
eef7c4527712
Do not fall back to 0 for samplerate when parser is not initialized.
reimar
parents:
35306
diff
changeset
|
147 srate = 48000; //fake value |
eef7c4527712
Do not fall back to 0 for samplerate when parser is not initialized.
reimar
parents:
35306
diff
changeset
|
148 bps = 768000/8; //fake value |
eef7c4527712
Do not fall back to 0 for samplerate when parser is not initialized.
reimar
parents:
35306
diff
changeset
|
149 if (x && sh->avctx) { // we have parser and large enough buffer |
34103 | 150 if (sh->avctx->sample_rate < 44100) { |
151 mp_msg(MSGT_DECAUDIO,MSGL_INFO, | |
152 "This stream sample_rate[%d Hz] may be broken. " | |
153 "Force reset 48000Hz.\n", | |
154 sh->avctx->sample_rate); | |
155 srate = 48000; //fake value | |
156 } else | |
157 srate = sh->avctx->sample_rate; | |
158 bps = sh->avctx->bit_rate/8; | |
159 } | |
160 sh->ds->buffer_pos -= in_size; | |
161 | |
162 switch (lavf_ctx->streams[0]->codec->codec_id) { | |
163 case CODEC_ID_AAC: | |
164 spdif_ctx->iec61937_packet_size = 16384; | |
165 sh->sample_format = AF_FORMAT_IEC61937_LE; | |
166 sh->samplerate = srate; | |
167 sh->channels = 2; | |
168 sh->i_bps = bps; | |
169 break; | |
170 case CODEC_ID_AC3: | |
171 spdif_ctx->iec61937_packet_size = 6144; | |
35442
2b45dfcde03c
ad_spdif: use the more specific AF_FORMAT_AC3_LE when
reimar
parents:
35423
diff
changeset
|
172 sh->sample_format = AF_FORMAT_AC3_LE; |
34103 | 173 sh->samplerate = srate; |
174 sh->channels = 2; | |
175 sh->i_bps = bps; | |
176 break; | |
177 case CODEC_ID_DTS: // FORCE USE DTS-HD | |
178 opt = av_opt_find(&lavf_ctx->oformat->priv_class, | |
179 "dtshd_rate", NULL, 0, 0); | |
180 if (!opt) | |
181 goto fail; | |
182 dtshd_rate = (int*)(((uint8_t*)lavf_ctx->priv_data) + | |
183 opt->offset); | |
184 *dtshd_rate = 192000*4; | |
185 spdif_ctx->iec61937_packet_size = 32768; | |
186 sh->sample_format = AF_FORMAT_IEC61937_LE; | |
187 sh->samplerate = 192000; // DTS core require 48000 | |
188 sh->channels = 2*4; | |
189 sh->i_bps = bps; | |
190 break; | |
191 case CODEC_ID_EAC3: | |
192 spdif_ctx->iec61937_packet_size = 24576; | |
193 sh->sample_format = AF_FORMAT_IEC61937_LE; | |
194 sh->samplerate = 192000; | |
195 sh->channels = 2; | |
196 sh->i_bps = bps; | |
197 break; | |
198 case CODEC_ID_MP3: | |
199 spdif_ctx->iec61937_packet_size = 4608; | |
200 sh->sample_format = AF_FORMAT_MPEG2; | |
201 sh->samplerate = srate; | |
202 sh->channels = 2; | |
203 sh->i_bps = bps; | |
204 break; | |
205 case CODEC_ID_TRUEHD: | |
206 spdif_ctx->iec61937_packet_size = 61440; | |
207 sh->sample_format = AF_FORMAT_IEC61937_LE; | |
208 sh->samplerate = 192000; | |
209 sh->channels = 8; | |
210 sh->i_bps = bps; | |
211 break; | |
212 default: | |
213 break; | |
214 } | |
215 | |
216 return 1; | |
217 | |
218 fail: | |
219 uninit(sh); | |
220 return 0; | |
221 } | |
222 | |
223 static int decode_audio(sh_audio_t *sh, unsigned char *buf, | |
224 int minlen, int maxlen) | |
225 { | |
226 struct spdifContext *spdif_ctx = sh->context; | |
227 AVFormatContext *lavf_ctx = spdif_ctx->lavf_ctx; | |
228 AVPacket pkt; | |
229 double pts; | |
230 int ret, in_size, consumed, x; | |
231 unsigned char *start = NULL; | |
232 | |
233 consumed = spdif_ctx->out_buffer_len = 0; | |
234 spdif_ctx->out_buffer_size = maxlen; | |
235 spdif_ctx->out_buffer = buf; | |
236 while (spdif_ctx->out_buffer_len + spdif_ctx->iec61937_packet_size < maxlen | |
237 && spdif_ctx->out_buffer_len < minlen) { | |
238 if (sh->ds->eof) | |
239 break; | |
240 x = ds_get_packet_pts(sh->ds, &start, &pts); | |
241 if (x <= 0) { | |
242 x = 0; | |
243 ds_parse(sh->ds, &start, &x, MP_NOPTS_VALUE, 0); | |
244 if (x == 0) | |
245 continue; // END_NOT_FOUND | |
246 in_size = x; | |
247 } else { | |
248 in_size = x; | |
249 consumed = ds_parse(sh->ds, &start, &x, pts, 0); | |
250 if (x == 0) { | |
251 mp_msg(MSGT_DECAUDIO,MSGL_V, | |
252 "start[%p] pkt.size[%d] in_size[%d] consumed[%d] x[%d].\n", | |
35306
f30c2707e168
Do not use pkt which is uninitialized at that point.
reimar
parents:
34206
diff
changeset
|
253 start, 0, in_size, consumed, x); |
34103 | 254 continue; // END_NOT_FOUND |
255 } | |
256 sh->ds->buffer_pos -= in_size - consumed; | |
257 } | |
258 av_init_packet(&pkt); | |
259 pkt.data = start; | |
260 pkt.size = x; | |
261 mp_msg(MSGT_DECAUDIO,MSGL_V, | |
262 "start[%p] pkt.size[%d] in_size[%d] consumed[%d] x[%d].\n", | |
263 start, pkt.size, in_size, consumed, x); | |
264 if (pts != MP_NOPTS_VALUE) { | |
265 sh->pts = pts; | |
266 sh->pts_bytes = 0; | |
267 } | |
268 ret = lavf_ctx->oformat->write_packet(lavf_ctx, &pkt); | |
269 if (ret < 0) | |
270 break; | |
271 } | |
272 sh->pts_bytes += spdif_ctx->out_buffer_len; | |
273 return spdif_ctx->out_buffer_len; | |
274 } | |
275 | |
276 static int control(sh_audio_t *sh, int cmd, void* arg, ...) | |
277 { | |
278 unsigned char *start; | |
279 double pts; | |
280 | |
281 switch (cmd) { | |
282 case ADCTRL_RESYNC_STREAM: | |
283 case ADCTRL_SKIP_FRAME: | |
284 ds_get_packet_pts(sh->ds, &start, &pts); | |
285 return CONTROL_TRUE; | |
286 } | |
287 return CONTROL_UNKNOWN; | |
288 } | |
289 | |
290 static void uninit(sh_audio_t *sh) | |
291 { | |
292 struct spdifContext *spdif_ctx = sh->context; | |
293 AVFormatContext *lavf_ctx = spdif_ctx->lavf_ctx; | |
294 | |
295 if (lavf_ctx) { | |
296 if (lavf_ctx->oformat) | |
297 lavf_ctx->oformat->write_trailer(lavf_ctx); | |
298 av_freep(&lavf_ctx->pb); | |
299 if (lavf_ctx->streams) { | |
300 av_freep(&lavf_ctx->streams[0]->codec); | |
301 av_freep(&lavf_ctx->streams[0]->info); | |
302 av_freep(&lavf_ctx->streams[0]); | |
303 } | |
304 av_freep(&lavf_ctx->streams); | |
305 av_freep(&lavf_ctx->priv_data); | |
306 } | |
307 av_freep(&lavf_ctx); | |
308 av_freep(&spdif_ctx); | |
309 } |