Mercurial > mplayer.hg
annotate libao2/pl_surround.c @ 8843:c70444c5b516
I have seen problems where DVD subtitles don't display
at the right time and sometimes they don't appear at
all. The problem stems from the fact that subtitle
command packets are being applied as soon as they are
read and assembled from the input stream. Sometimes,
a fully assembled subtitle packet arrives at the
spudec_assemble function before the previous subtitle
appears onscreen and thus the viewer only sees the
second subtitle. So I created a patch that queues
assembled subtitle packets and applies them at the
appropriate time within the heartbeat function. The
reset function clears the packet queue when seeking
through the video.
Tomasz Farkas <tomasz_farkas@yahoo.co.uk>
author | arpi |
---|---|
date | Wed, 08 Jan 2003 18:36:36 +0000 |
parents | 46d21c0f36aa |
children | 12b1790038b0 |
rev | line source |
---|---|
3313 | 1 /* |
2 This is an ao2 plugin to do simple decoding of matrixed surround | |
3 sound. This will provide a (basic) surround-sound effect from | |
4 audio encoded for Dolby Surround, Pro Logic etc. | |
5 | |
6 * This program is free software; you can redistribute it and/or modify | |
7 * it under the terms of the GNU General Public License as published by | |
8 * the Free Software Foundation; either version 2 of the License, or | |
9 * (at your option) any later version. | |
10 * | |
11 * This program 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 | |
14 * GNU General Public License for more details. | |
15 * | |
16 * You should have received a copy of the GNU General Public License | |
17 * along with this program; if not, write to the Free Software | |
18 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | |
19 | |
20 Original author: Steve Davies <steve@daviesfam.org> | |
21 */ | |
22 | |
23 /* The principle: Make rear channels by extracting anti-phase data | |
3681 | 24 from the front channels, delay by 20msec and feed to rear in anti-phase |
3313 | 25 */ |
26 | |
27 | |
3681 | 28 // SPLITREAR: Define to decode two distinct rear channels - |
29 // this doesn't work so well in practice because | |
30 // separation in a passive matrix is not high. | |
31 // C (dialogue) to Ls and Rs 14dB or so - | |
32 // so dialogue leaks to the rear. | |
33 // Still - give it a try and send feedback. | |
34 // comment this define for old behaviour of a single | |
35 // surround sent to rear in anti-phase | |
36 #define SPLITREAR | |
37 | |
38 | |
3313 | 39 #include <stdio.h> |
40 #include <stdlib.h> | |
6237 | 41 #include <string.h> |
3317 | 42 #include <unistd.h> |
3313 | 43 |
44 #include "audio_out.h" | |
45 #include "audio_plugin.h" | |
46 #include "audio_plugin_internal.h" | |
47 #include "afmt.h" | |
48 | |
3485
439b0b1d50b9
include 7kHz lowpass filter for surround channels, as per Dolby recommendation
steve
parents:
3420
diff
changeset
|
49 #include "remez.h" |
439b0b1d50b9
include 7kHz lowpass filter for surround channels, as per Dolby recommendation
steve
parents:
3420
diff
changeset
|
50 #include "firfilter.c" |
439b0b1d50b9
include 7kHz lowpass filter for surround channels, as per Dolby recommendation
steve
parents:
3420
diff
changeset
|
51 |
3313 | 52 static ao_info_t info = |
53 { | |
54 "Surround decoder plugin", | |
55 "surround", | |
56 "Steve Davies <steve@daviesfam.org>", | |
57 "" | |
58 }; | |
59 | |
60 LIBAO_PLUGIN_EXTERN(surround) | |
61 | |
62 // local data | |
63 typedef struct pl_surround_s | |
64 { | |
65 int passthrough; // Just be a "NO-OP" | |
66 int msecs; // Rear channel delay in milliseconds | |
67 int16_t* databuf; // Output audio buffer | |
3485
439b0b1d50b9
include 7kHz lowpass filter for surround channels, as per Dolby recommendation
steve
parents:
3420
diff
changeset
|
68 int16_t* Ls_delaybuf; // circular buffer to be used for delaying Ls audio |
439b0b1d50b9
include 7kHz lowpass filter for surround channels, as per Dolby recommendation
steve
parents:
3420
diff
changeset
|
69 int16_t* Rs_delaybuf; // circular buffer to be used for delaying Rs audio |
439b0b1d50b9
include 7kHz lowpass filter for surround channels, as per Dolby recommendation
steve
parents:
3420
diff
changeset
|
70 int delaybuf_len; // delaybuf buffer length in samples |
439b0b1d50b9
include 7kHz lowpass filter for surround channels, as per Dolby recommendation
steve
parents:
3420
diff
changeset
|
71 int delaybuf_pos; // offset in buffer where we are reading/writing |
439b0b1d50b9
include 7kHz lowpass filter for surround channels, as per Dolby recommendation
steve
parents:
3420
diff
changeset
|
72 double* filter_coefs_surround; // FIR filter coefficients for surround sound 7kHz lowpass |
3313 | 73 int rate; // input data rate |
74 int format; // input format | |
75 int input_channels; // input channels | |
76 | |
77 } pl_surround_t; | |
78 | |
3681 | 79 static pl_surround_t pl_surround={0,20,NULL,NULL,NULL,0,0,NULL,0,0,0}; |
3313 | 80 |
81 // to set/get/query special features/parameters | |
82 static int control(int cmd,int arg){ | |
83 switch(cmd){ | |
84 case AOCONTROL_PLUGIN_SET_LEN: | |
85 if (pl_surround.passthrough) return CONTROL_OK; | |
86 //fprintf(stderr, "pl_surround: AOCONTROL_PLUGIN_SET_LEN with arg=%d\n", arg); | |
87 //fprintf(stderr, "pl_surround: ao_plugin_data.len=%d\n", ao_plugin_data.len); | |
88 // Allocate an output buffer | |
89 if (pl_surround.databuf != NULL) { | |
90 free(pl_surround.databuf); pl_surround.databuf = NULL; | |
91 } | |
3485
439b0b1d50b9
include 7kHz lowpass filter for surround channels, as per Dolby recommendation
steve
parents:
3420
diff
changeset
|
92 // Allocate output buffer |
3313 | 93 pl_surround.databuf = calloc(ao_plugin_data.len, 1); |
3485
439b0b1d50b9
include 7kHz lowpass filter for surround channels, as per Dolby recommendation
steve
parents:
3420
diff
changeset
|
94 // Return back smaller len so we don't get overflowed... |
3313 | 95 ao_plugin_data.len /= 2; |
96 return CONTROL_OK; | |
97 } | |
98 return -1; | |
99 } | |
100 | |
101 // open & setup audio device | |
102 // return: 1=success 0=fail | |
103 static int init(){ | |
104 | |
105 fprintf(stderr, "pl_surround: init input rate=%d, channels=%d\n", ao_plugin_data.rate, ao_plugin_data.channels); | |
106 if (ao_plugin_data.channels != 2) { | |
107 fprintf(stderr, "pl_surround: source audio must have 2 channels, using passthrough mode\n"); | |
108 pl_surround.passthrough = 1; | |
109 return 1; | |
110 } | |
8741
46d21c0f36aa
(nicer) endianness fix for every plugin except pl_format
colin
parents:
8123
diff
changeset
|
111 if (ao_plugin_data.format != AFMT_S16_NE) { |
46d21c0f36aa
(nicer) endianness fix for every plugin except pl_format
colin
parents:
8123
diff
changeset
|
112 fprintf(stderr, "pl_surround: I'm dumb and can only handle AFMT_S16_NE audio format, using passthrough mode\n"); |
3313 | 113 pl_surround.passthrough = 1; |
114 return 1; | |
115 } | |
116 | |
117 pl_surround.passthrough = 0; | |
118 | |
119 /* Store info on input format to expect */ | |
120 pl_surround.rate=ao_plugin_data.rate; | |
121 pl_surround.format=ao_plugin_data.format; | |
122 pl_surround.input_channels=ao_plugin_data.channels; | |
123 | |
124 // Input 2 channels, output will be 4 - tell ao_plugin | |
125 ao_plugin_data.channels = 4; | |
126 ao_plugin_data.sz_mult /= 2; | |
127 | |
3485
439b0b1d50b9
include 7kHz lowpass filter for surround channels, as per Dolby recommendation
steve
parents:
3420
diff
changeset
|
128 // Figure out buffer space (in int16_ts) needed for the 15msec delay |
3495
cc1c879533ee
tweaked surround lowpass filter, included some new test code
steve
parents:
3485
diff
changeset
|
129 // Extra 31 samples allow for lowpass filter delay (taps-1) |
cc1c879533ee
tweaked surround lowpass filter, included some new test code
steve
parents:
3485
diff
changeset
|
130 pl_surround.delaybuf_len = (pl_surround.rate * pl_surround.msecs / 1000) + 31; |
3485
439b0b1d50b9
include 7kHz lowpass filter for surround channels, as per Dolby recommendation
steve
parents:
3420
diff
changeset
|
131 // Allocate delay buffers |
439b0b1d50b9
include 7kHz lowpass filter for surround channels, as per Dolby recommendation
steve
parents:
3420
diff
changeset
|
132 pl_surround.Ls_delaybuf=(void*)calloc(pl_surround.delaybuf_len,sizeof(int16_t)); |
439b0b1d50b9
include 7kHz lowpass filter for surround channels, as per Dolby recommendation
steve
parents:
3420
diff
changeset
|
133 pl_surround.Rs_delaybuf=(void*)calloc(pl_surround.delaybuf_len,sizeof(int16_t)); |
439b0b1d50b9
include 7kHz lowpass filter for surround channels, as per Dolby recommendation
steve
parents:
3420
diff
changeset
|
134 fprintf(stderr, "pl_surround: %dmsec surround delay, rate %d - buffers are %d bytes each\n", |
3420
cfc10bc948c4
split surround delay buf into Ls and Rs in prep for active decoding stuff, and fiddled a bit more with surround level
steve
parents:
3410
diff
changeset
|
135 pl_surround.msecs,pl_surround.rate, pl_surround.delaybuf_len*sizeof(int16_t)); |
3485
439b0b1d50b9
include 7kHz lowpass filter for surround channels, as per Dolby recommendation
steve
parents:
3420
diff
changeset
|
136 pl_surround.delaybuf_pos = 0; |
439b0b1d50b9
include 7kHz lowpass filter for surround channels, as per Dolby recommendation
steve
parents:
3420
diff
changeset
|
137 // Surround filer coefficients |
439b0b1d50b9
include 7kHz lowpass filter for surround channels, as per Dolby recommendation
steve
parents:
3420
diff
changeset
|
138 pl_surround.filter_coefs_surround = calc_coefficients_7kHz_lowpass(pl_surround.rate); |
3495
cc1c879533ee
tweaked surround lowpass filter, included some new test code
steve
parents:
3485
diff
changeset
|
139 //dump_filter_coefficients(pl_surround.filter_coefs_surround); |
cc1c879533ee
tweaked surround lowpass filter, included some new test code
steve
parents:
3485
diff
changeset
|
140 //testfilter(pl_surround.filter_coefs_surround, 32, pl_surround.rate); |
3313 | 141 return 1; |
142 } | |
143 | |
144 // close plugin | |
145 static void uninit(){ | |
146 // fprintf(stderr, "pl_surround: uninit called!\n"); | |
147 if (pl_surround.passthrough) return; | |
3485
439b0b1d50b9
include 7kHz lowpass filter for surround channels, as per Dolby recommendation
steve
parents:
3420
diff
changeset
|
148 if(pl_surround.Ls_delaybuf) |
439b0b1d50b9
include 7kHz lowpass filter for surround channels, as per Dolby recommendation
steve
parents:
3420
diff
changeset
|
149 free(pl_surround.Ls_delaybuf); |
439b0b1d50b9
include 7kHz lowpass filter for surround channels, as per Dolby recommendation
steve
parents:
3420
diff
changeset
|
150 if(pl_surround.Rs_delaybuf) |
439b0b1d50b9
include 7kHz lowpass filter for surround channels, as per Dolby recommendation
steve
parents:
3420
diff
changeset
|
151 free(pl_surround.Rs_delaybuf); |
5501 | 152 if(pl_surround.databuf) { |
3313 | 153 free(pl_surround.databuf); |
5501 | 154 pl_surround.databuf = NULL; |
155 } | |
3313 | 156 pl_surround.delaybuf_len=0; |
157 } | |
158 | |
159 // empty buffers | |
160 static void reset() | |
161 { | |
162 if (pl_surround.passthrough) return; | |
163 //fprintf(stderr, "pl_surround: reset called\n"); | |
3485
439b0b1d50b9
include 7kHz lowpass filter for surround channels, as per Dolby recommendation
steve
parents:
3420
diff
changeset
|
164 pl_surround.delaybuf_pos = 0; |
439b0b1d50b9
include 7kHz lowpass filter for surround channels, as per Dolby recommendation
steve
parents:
3420
diff
changeset
|
165 memset(pl_surround.Ls_delaybuf, 0, sizeof(int16_t)*pl_surround.delaybuf_len); |
439b0b1d50b9
include 7kHz lowpass filter for surround channels, as per Dolby recommendation
steve
parents:
3420
diff
changeset
|
166 memset(pl_surround.Rs_delaybuf, 0, sizeof(int16_t)*pl_surround.delaybuf_len); |
3313 | 167 } |
168 | |
3681 | 169 // The beginnings of an active matrix... |
170 static double steering_matrix[][12] = { | |
171 // LL RL LR RR LS RS LLs RLs LRs RRs LC RC | |
172 {.707, .0, .0, .707, .5, -.5, .5878, -.3928, .3928, -.5878, .5, .5}, | |
173 }; | |
174 | |
175 // Experimental moving average dominances | |
8123
9fc45fe0d444
*HUGE* set of compiler warning fixes, unused variables removal
arpi
parents:
6237
diff
changeset
|
176 //static int amp_L = 0, amp_R = 0, amp_C = 0, amp_S = 0; |
3313 | 177 |
178 // processes 'ao_plugin_data.len' bytes of 'data' | |
179 // called for every block of data | |
180 static int play(){ | |
181 int16_t *in, *out; | |
182 int i, samples; | |
3681 | 183 double *matrix = steering_matrix[0]; // later we'll index based on detected dominance |
3313 | 184 |
185 if (pl_surround.passthrough) return 1; | |
186 | |
3420
cfc10bc948c4
split surround delay buf into Ls and Rs in prep for active decoding stuff, and fiddled a bit more with surround level
steve
parents:
3410
diff
changeset
|
187 // fprintf(stderr, "pl_surround: play %d bytes, %d samples\n", ao_plugin_data.len, samples); |
3313 | 188 |
189 samples = ao_plugin_data.len / sizeof(int16_t) / pl_surround.input_channels; | |
3495
cc1c879533ee
tweaked surround lowpass filter, included some new test code
steve
parents:
3485
diff
changeset
|
190 out = pl_surround.databuf; in = (int16_t *)ao_plugin_data.data; |
3313 | 191 |
3681 | 192 // Testing - place a 1kHz tone on Lt and Rt in anti-phase: should decode in S |
3495
cc1c879533ee
tweaked surround lowpass filter, included some new test code
steve
parents:
3485
diff
changeset
|
193 //sinewave(in, samples, pl_surround.input_channels, 1000, 0.0, pl_surround.rate); |
cc1c879533ee
tweaked surround lowpass filter, included some new test code
steve
parents:
3485
diff
changeset
|
194 //sinewave(&in[1], samples, pl_surround.input_channels, 1000, PI, pl_surround.rate); |
cc1c879533ee
tweaked surround lowpass filter, included some new test code
steve
parents:
3485
diff
changeset
|
195 |
3313 | 196 for (i=0; i<samples; i++) { |
3373 | 197 |
3681 | 198 // Dominance: |
199 //abs(in[0]) abs(in[1]); | |
200 //abs(in[0]+in[1]) abs(in[0]-in[1]); | |
201 //10 * log( abs(in[0]) / (abs(in[1])|1) ); | |
202 //10 * log( abs(in[0]+in[1]) / (abs(in[0]-in[1])|1) ); | |
203 | |
3410 | 204 // About volume balancing... |
3373 | 205 // Surround encoding does the following: |
206 // Lt=L+.707*C+.707*S, Rt=R+.707*C-.707*S | |
3420
cfc10bc948c4
split surround delay buf into Ls and Rs in prep for active decoding stuff, and fiddled a bit more with surround level
steve
parents:
3410
diff
changeset
|
207 // So S should be extracted as: |
cfc10bc948c4
split surround delay buf into Ls and Rs in prep for active decoding stuff, and fiddled a bit more with surround level
steve
parents:
3410
diff
changeset
|
208 // (Lt-Rt) |
3410 | 209 // But we are splitting the S to two output channels, so we |
3420
cfc10bc948c4
split surround delay buf into Ls and Rs in prep for active decoding stuff, and fiddled a bit more with surround level
steve
parents:
3410
diff
changeset
|
210 // must take 3dB off as we split it: |
cfc10bc948c4
split surround delay buf into Ls and Rs in prep for active decoding stuff, and fiddled a bit more with surround level
steve
parents:
3410
diff
changeset
|
211 // Ls=Rs=.707*(Lt-Rt) |
cfc10bc948c4
split surround delay buf into Ls and Rs in prep for active decoding stuff, and fiddled a bit more with surround level
steve
parents:
3410
diff
changeset
|
212 // Trouble is, Lt could be +32767, Rt -32768, so possibility that S will |
3681 | 213 // overflow. So to avoid that, we cut L/R by 3dB (*.707), and S by 6dB (/2). |
214 // this keeps the overall balance, but guarantees no overflow. | |
3373 | 215 |
3420
cfc10bc948c4
split surround delay buf into Ls and Rs in prep for active decoding stuff, and fiddled a bit more with surround level
steve
parents:
3410
diff
changeset
|
216 // output front left and right |
3681 | 217 out[0] = matrix[0]*in[0] + matrix[1]*in[1]; |
218 out[1] = matrix[2]*in[0] + matrix[3]*in[1]; | |
219 // output Ls and Rs - from 20msec ago, lowpass filtered @ 7kHz | |
3485
439b0b1d50b9
include 7kHz lowpass filter for surround channels, as per Dolby recommendation
steve
parents:
3420
diff
changeset
|
220 out[2] = firfilter(pl_surround.Ls_delaybuf, pl_surround.delaybuf_pos, |
439b0b1d50b9
include 7kHz lowpass filter for surround channels, as per Dolby recommendation
steve
parents:
3420
diff
changeset
|
221 pl_surround.delaybuf_len, 32, pl_surround.filter_coefs_surround); |
3681 | 222 #ifdef SPLITREAR |
223 out[3] = firfilter(pl_surround.Rs_delaybuf, pl_surround.delaybuf_pos, | |
224 pl_surround.delaybuf_len, 32, pl_surround.filter_coefs_surround); | |
225 #else | |
226 out[3] = -out[2]; | |
227 #endif | |
228 // calculate and save surround for 20msecs time | |
229 #ifdef SPLITREAR | |
230 pl_surround.Ls_delaybuf[pl_surround.delaybuf_pos] = | |
231 matrix[6]*in[0] + matrix[7]*in[1]; | |
232 pl_surround.Rs_delaybuf[pl_surround.delaybuf_pos++] = | |
233 matrix[8]*in[0] + matrix[9]*in[1]; | |
234 #else | |
3718 | 235 pl_surround.Ls_delaybuf[pl_surround.delaybuf_pos++] = |
3681 | 236 matrix[4]*in[0] + matrix[5]*in[1]; |
237 #endif | |
3485
439b0b1d50b9
include 7kHz lowpass filter for surround channels, as per Dolby recommendation
steve
parents:
3420
diff
changeset
|
238 pl_surround.delaybuf_pos %= pl_surround.delaybuf_len; |
3681 | 239 |
3313 | 240 // next samples... |
241 in = &in[pl_surround.input_channels]; out = &out[4]; | |
242 } | |
3681 | 243 |
244 // Show some state | |
245 //printf("\npl_surround: delaybuf_pos=%d, samples=%d\r\033[A", pl_surround.delaybuf_pos, samples); | |
3313 | 246 |
247 // Set output block/len | |
248 ao_plugin_data.data=pl_surround.databuf; | |
249 ao_plugin_data.len=samples*sizeof(int16_t)*4; | |
250 return 1; | |
251 } |