1 /*****************************************************************************
2 * shine_mod.c: MP3 encoder using Shine, a fixed point implementation
3 *****************************************************************************
4 * Copyright (C) 2008-2009 M2X
6 * Authors: Rafaël Carré <rcarre@m2x.nl>
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms of the GNU Lesser General Public License as published by
10 * the Free Software Foundation; either version 2.1 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public License
19 * along with this program; if not, write to the Free Software Foundation,
20 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
21 *****************************************************************************/
23 /*****************************************************************************
25 *****************************************************************************/
30 #include <vlc_common.h>
31 #include <vlc_plugin.h>
32 #include <vlc_codec.h>
33 #include <vlc_block.h>
34 #include <vlc_block_helper.h>
41 #include <shine/layer3.h>
46 unsigned int samples_per_frame
;
49 unsigned int i_buffer
;
53 /*****************************************************************************
55 *****************************************************************************/
56 static int OpenEncoder ( vlc_object_t
* );
57 static void CloseEncoder ( vlc_object_t
* );
59 static block_t
*EncodeFrame ( encoder_t
*, block_t
* );
62 set_category( CAT_INPUT
);
63 set_subcategory( SUBCAT_INPUT_ACODEC
);
64 set_description( N_("MP3 fixed point audio encoder") );
65 set_capability( "encoder", 50 );
66 set_callbacks( OpenEncoder
, CloseEncoder
);
73 } entrant
= { false, VLC_STATIC_MUTEX
, };
75 static int OpenEncoder( vlc_object_t
*p_this
)
77 encoder_t
*p_enc
= (encoder_t
*)p_this
;
80 /* shine is an 'MP3' encoder */
81 if( (p_enc
->fmt_out
.i_codec
!= VLC_CODEC_MP3
&& p_enc
->fmt_out
.i_codec
!= VLC_CODEC_MPGA
) ||
82 p_enc
->fmt_out
.audio
.i_channels
> 2 )
85 /* Shine is strict on its input */
86 if( p_enc
->fmt_in
.audio
.i_channels
!= 2 )
88 msg_Err( p_enc
, "Only stereo input is accepted, rejecting %d channels",
89 p_enc
->fmt_in
.audio
.i_channels
);
93 if( p_enc
->fmt_out
.i_bitrate
<= 0 )
95 msg_Err( p_enc
, "unknown bitrate" );
99 msg_Dbg( p_enc
, "bitrate %d, samplerate %d, channels %d",
100 p_enc
->fmt_out
.i_bitrate
, p_enc
->fmt_out
.audio
.i_rate
,
101 p_enc
->fmt_out
.audio
.i_channels
);
103 vlc_mutex_lock( &entrant
.lock
);
106 msg_Err( p_enc
, "encoder already in progress" );
107 vlc_mutex_unlock( &entrant
.lock
);
111 vlc_mutex_unlock( &entrant
.lock
);
113 p_enc
->p_sys
= p_sys
= calloc( 1, sizeof( *p_sys
) );
117 if( !( p_sys
->p_fifo
= block_FifoNew() ) )
123 shine_config_t cfg
= {
125 .channels
= p_enc
->fmt_out
.audio
.i_channels
,
126 .samplerate
= p_enc
->fmt_out
.audio
.i_rate
,
130 shine_set_config_mpeg_defaults(&cfg
.mpeg
);
131 cfg
.mpeg
.bitr
= p_enc
->fmt_out
.i_bitrate
/ 1000;
133 if (shine_check_config(cfg
.wave
.samplerate
, cfg
.mpeg
.bitr
) == -1) {
134 msg_Err(p_enc
, "Invalid bitrate %d\n", cfg
.mpeg
.bitr
);
139 p_sys
->s
= shine_initialise(&cfg
);
140 p_sys
->samples_per_frame
= shine_samples_per_pass(p_sys
->s
);
142 p_enc
->pf_encode_audio
= EncodeFrame
;
143 p_enc
->fmt_out
.i_cat
= AUDIO_ES
;
145 p_enc
->fmt_in
.i_codec
= VLC_CODEC_S16N
;
150 vlc_mutex_lock( &entrant
.lock
);
151 entrant
.busy
= false;
152 vlc_mutex_unlock( &entrant
.lock
);
156 /* We split/pack PCM blocks to a fixed size: p_sys->samples_per_frame * 4 bytes */
157 static block_t
*GetPCM( encoder_t
*p_enc
, block_t
*p_block
)
159 encoder_sys_t
*p_sys
= p_enc
->p_sys
;
160 block_t
*p_pcm_block
;
162 if( !p_block
) goto buffered
; /* just return a block if we can */
164 /* Put the PCM samples sent by VLC in the Fifo */
165 while( p_sys
->i_buffer
+ p_block
->i_buffer
>= p_sys
->samples_per_frame
* 4 )
167 unsigned int i_buffer
= 0;
168 p_pcm_block
= block_Alloc( p_sys
->samples_per_frame
* 4 );
172 if( p_sys
->i_buffer
)
174 memcpy( p_pcm_block
->p_buffer
, p_sys
->p_buffer
, p_sys
->i_buffer
);
176 i_buffer
= p_sys
->i_buffer
;
178 free( p_sys
->p_buffer
);
179 p_sys
->p_buffer
= NULL
;
182 memcpy( p_pcm_block
->p_buffer
+ i_buffer
,
183 p_block
->p_buffer
, p_sys
->samples_per_frame
* 4 - i_buffer
);
184 p_block
->p_buffer
+= p_sys
->samples_per_frame
* 4 - i_buffer
;
186 p_block
->i_buffer
-= p_sys
->samples_per_frame
* 4 - i_buffer
;
188 block_FifoPut( p_sys
->p_fifo
, p_pcm_block
);
191 /* We hadn't enough data to make a block, put it in standby */
192 if( p_block
->i_buffer
)
196 if( p_sys
->i_buffer
> 0 )
197 p_tmp
= realloc( p_sys
->p_buffer
, p_block
->i_buffer
+ p_sys
->i_buffer
);
199 p_tmp
= malloc( p_block
->i_buffer
);
204 free( p_sys
->p_buffer
);
205 p_sys
->p_buffer
= NULL
;
208 p_sys
->p_buffer
= p_tmp
;
209 memcpy( p_sys
->p_buffer
+ p_sys
->i_buffer
,
210 p_block
->p_buffer
, p_block
->i_buffer
);
212 p_sys
->i_buffer
+= p_block
->i_buffer
;
213 p_block
->i_buffer
= 0;
217 /* and finally get a block back */
218 return block_FifoCount( p_sys
->p_fifo
) > 0 ? block_FifoGet( p_sys
->p_fifo
) : NULL
;
221 static block_t
*EncodeFrame( encoder_t
*p_enc
, block_t
*p_block
)
223 if (!p_block
) /* TODO: flush */
226 encoder_sys_t
*p_sys
= p_enc
->p_sys
;
227 block_t
*p_pcm_block
;
228 block_t
*p_chain
= NULL
;
229 unsigned int i_samples
= p_block
->i_buffer
>> 2 /* s16l stereo */;
230 vlc_tick_t start_date
= p_block
->i_pts
;
231 start_date
-= (vlc_tick_t
)i_samples
* CLOCK_FREQ
/ (vlc_tick_t
)p_enc
->fmt_out
.audio
.i_rate
;
236 p_pcm_block
= GetPCM( p_enc
, p_block
);
240 p_block
= NULL
; /* we don't need it anymore */
241 int16_t pcm_planar_buf
[SHINE_MAX_SAMPLES
* 2];
242 int16_t *pcm_planar_buf_chans
[2] = {
244 &pcm_planar_buf
[p_sys
->samples_per_frame
],
246 aout_Deinterleave( pcm_planar_buf
, p_pcm_block
->p_buffer
,
247 p_sys
->samples_per_frame
, p_enc
->fmt_in
.audio
.i_channels
, p_enc
->fmt_in
.i_codec
);
250 unsigned char *buf
= shine_encode_buffer(p_sys
->s
, pcm_planar_buf_chans
, &written
);
251 block_Release( p_pcm_block
);
256 block_t
*p_mp3_block
= block_Alloc( written
);
260 memcpy( p_mp3_block
->p_buffer
, buf
, written
);
262 /* date management */
263 p_mp3_block
->i_length
= p_sys
->samples_per_frame
* CLOCK_FREQ
/
264 p_enc
->fmt_out
.audio
.i_rate
;
266 start_date
+= p_mp3_block
->i_length
;
267 p_mp3_block
->i_dts
= p_mp3_block
->i_pts
= start_date
;
269 p_mp3_block
->i_nb_samples
= p_sys
->samples_per_frame
;
271 block_ChainAppend( &p_chain
, p_mp3_block
);
273 } while( p_pcm_block
);
278 static void CloseEncoder( vlc_object_t
*p_this
)
280 encoder_sys_t
*p_sys
= ((encoder_t
*)p_this
)->p_sys
;
282 vlc_mutex_lock( &entrant
.lock
);
283 entrant
.busy
= false;
284 vlc_mutex_unlock( &entrant
.lock
);
286 /* TODO: we should send the last PCM block padded with 0
287 * But we don't know if other blocks will come before it's too late */
288 if( p_sys
->i_buffer
)
289 free( p_sys
->p_buffer
);
291 shine_close(p_sys
->s
);
293 block_FifoRelease( p_sys
->p_fifo
);