]> git.sesse.net Git - vlc/blob - modules/codec/shine/shine_mod.c
avcodec: set EncodeAudio/Video at the end
[vlc] / modules / codec / shine / shine_mod.c
1 /*****************************************************************************
2  * shine_mod.c: MP3 encoder using Shine, a fixed point implementation
3  *****************************************************************************
4  * Copyright (C) 2008-2009 M2X
5  *
6  * Authors: Rafaël Carré <rcarre@m2x.nl>
7  *
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.
12  *
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.
17  *
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  *****************************************************************************/
22
23 /*****************************************************************************
24  * Preamble
25  *****************************************************************************/
26 #ifdef HAVE_CONFIG_H
27 # include "config.h"
28 #endif
29
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>
35 #include <vlc_bits.h>
36
37 #include <assert.h>
38 #include <inttypes.h>
39
40 /* shine.c uses a lot of static variables, so we include the C file to keep
41  * the scope.
42  * Note that it makes this decoder non reentrant, this is why we have the
43  * struct entrant below */
44 #include "shine.c"
45
46 struct encoder_sys_t
47 {
48     block_fifo_t *p_fifo;
49
50     unsigned int i_buffer;
51     uint8_t *p_buffer;
52 };
53
54 /*****************************************************************************
55  * Local prototypes
56  *****************************************************************************/
57 static int  OpenEncoder   ( vlc_object_t * );
58 static void CloseEncoder  ( vlc_object_t * );
59
60 static block_t *EncodeFrame  ( encoder_t *, block_t * );
61
62 vlc_module_begin();
63     set_category( CAT_INPUT );
64     set_subcategory( SUBCAT_INPUT_ACODEC );
65     set_description( _("MP3 fixed point audio encoder") );
66     set_capability( "encoder", 50 );
67     set_callbacks( OpenEncoder, CloseEncoder );
68 vlc_module_end();
69
70 static struct
71 {
72     bool busy;
73     vlc_mutex_t lock;
74 } entrant = { false, VLC_STATIC_MUTEX, };
75
76 static int OpenEncoder( vlc_object_t *p_this )
77 {
78     encoder_t *p_enc = (encoder_t*)p_this;
79     encoder_sys_t *p_sys;
80
81     /* shine is an 'MP3' encoder */
82     if( (p_enc->fmt_out.i_codec != VLC_CODEC_MP3 && p_enc->fmt_out.i_codec != VLC_CODEC_MPGA) ||
83         p_enc->fmt_out.audio.i_channels > 2 )
84         return VLC_EGENERIC;
85
86     /* Shine is strict on its input */
87     if( p_enc->fmt_in.audio.i_channels != 2 )
88     {
89         msg_Err( p_enc, "Only stereo input is accepted, rejecting %d channels",
90             p_enc->fmt_in.audio.i_channels );
91         return VLC_EGENERIC;
92     }
93
94     if( p_enc->fmt_out.i_bitrate <= 0 )
95     {
96         msg_Err( p_enc, "unknown bitrate" );
97         return VLC_EGENERIC;
98     }
99
100     msg_Dbg( p_enc, "bitrate %d, samplerate %d, channels %d",
101              p_enc->fmt_out.i_bitrate, p_enc->fmt_out.audio.i_rate,
102              p_enc->fmt_out.audio.i_channels );
103
104     vlc_mutex_lock( &entrant.lock );
105     if( entrant.busy )
106     {
107         msg_Err( p_enc, "encoder already in progress" );
108         vlc_mutex_unlock( &entrant.lock );
109         return VLC_EGENERIC;
110     }
111     entrant.busy = true;
112     vlc_mutex_unlock( &entrant.lock );
113
114     p_enc->p_sys = p_sys = calloc( 1, sizeof( *p_sys ) );
115     if( !p_sys )
116         goto enomem;
117
118     if( !( p_sys->p_fifo = block_FifoNew() ) )
119     {
120         free( p_sys );
121         goto enomem;
122     }
123
124     init_mp3_encoder_engine( p_enc->fmt_out.audio.i_rate,
125         p_enc->fmt_out.audio.i_channels, p_enc->fmt_out.i_bitrate / 1000 );
126
127     p_enc->pf_encode_audio = EncodeFrame;
128     p_enc->fmt_out.i_cat = AUDIO_ES;
129
130     return VLC_SUCCESS;
131
132 enomem:
133     vlc_mutex_lock( &entrant.lock );
134     entrant.busy = false;
135     vlc_mutex_unlock( &entrant.lock );
136     return VLC_ENOMEM;
137 }
138
139 /* We split/pack PCM blocks to a fixed size: pcm_chunk_size bytes */
140 static block_t *GetPCM( encoder_t *p_enc, block_t *p_block )
141 {
142     encoder_sys_t *p_sys = p_enc->p_sys;
143     block_t *p_pcm_block;
144
145     if( !p_block ) goto buffered; /* just return a block if we can */
146
147     /* Put the PCM samples sent by VLC in the Fifo */
148     while( p_sys->i_buffer + p_block->i_buffer >= pcm_chunk_size )
149     {
150         unsigned int i_buffer = 0;
151         p_pcm_block = block_Alloc( pcm_chunk_size );
152         if( !p_pcm_block )
153             break;
154
155         if( p_sys->i_buffer )
156         {
157             memcpy( p_pcm_block->p_buffer, p_sys->p_buffer, p_sys->i_buffer );
158
159             i_buffer = p_sys->i_buffer;
160             p_sys->i_buffer = 0;
161             free( p_sys->p_buffer );
162         }
163
164         memcpy( p_pcm_block->p_buffer + i_buffer,
165                     p_block->p_buffer, pcm_chunk_size - i_buffer );
166         p_block->p_buffer += pcm_chunk_size - i_buffer;
167
168         p_block->i_buffer -= pcm_chunk_size - i_buffer;
169
170         block_FifoPut( p_sys->p_fifo, p_pcm_block );
171     }
172
173     /* We hadn't enough data to make a block, put it in standby */
174     if( p_block->i_buffer )
175     {
176         uint8_t *p_tmp;
177
178         if( p_sys->i_buffer > 0 )
179             p_tmp = realloc( p_sys->p_buffer, p_block->i_buffer + p_sys->i_buffer );
180         else
181             p_tmp = malloc( p_block->i_buffer );
182
183         if( !p_tmp )
184         {
185             p_sys->i_buffer = 0;
186             free( p_sys->p_buffer );
187             p_sys->p_buffer = NULL;
188             return NULL;
189         }
190         p_sys->p_buffer = p_tmp;
191         memcpy( p_sys->p_buffer + p_sys->i_buffer,
192                     p_block->p_buffer, p_block->i_buffer );
193
194         p_sys->i_buffer += p_block->i_buffer;
195         p_block->i_buffer = 0;
196     }
197
198 buffered:
199     /* and finally get a block back */
200     return block_FifoCount( p_sys->p_fifo ) > 0 ? block_FifoGet( p_sys->p_fifo ) : NULL;
201 }
202
203 static block_t *EncodeFrame( encoder_t *p_enc, block_t *p_block )
204 {
205     block_t *p_pcm_block;
206     block_t *p_chain = NULL;
207     unsigned int i_samples = p_block->i_buffer >> 2 /* s16l stereo */;
208     mtime_t start_date = p_block->i_pts;
209     start_date -= (mtime_t)i_samples * (mtime_t)1000000 / (mtime_t)p_enc->fmt_out.audio.i_rate;
210
211     VLC_UNUSED(p_enc);
212
213     do {
214         p_pcm_block = GetPCM( p_enc, p_block );
215         if( !p_pcm_block )
216             break;
217
218         p_block = NULL; /* we don't need it anymore */
219
220         uint32_t enc_buffer[16384]; /* storage for 65536 Bytes XXX: too much */
221         struct enc_chunk_hdr *chunk = (void*) enc_buffer;
222         chunk->enc_data = ENC_CHUNK_SKIP_HDR(chunk->enc_data, chunk);
223
224         encode_frame( (char*)p_pcm_block->p_buffer, chunk );
225         block_Release( p_pcm_block );
226
227         block_t *p_mp3_block = block_Alloc( chunk->enc_size );
228         if( !p_mp3_block )
229             break;
230
231         memcpy( p_mp3_block->p_buffer, chunk->enc_data, chunk->enc_size );
232
233         /* date management */
234         p_mp3_block->i_length = SAMP_PER_FRAME1 * 1000000 /
235             p_enc->fmt_out.audio.i_rate;
236
237         start_date += p_mp3_block->i_length;
238         p_mp3_block->i_dts = p_mp3_block->i_pts = start_date;
239
240         p_mp3_block->i_nb_samples = SAMP_PER_FRAME1;
241
242         block_ChainAppend( &p_chain, p_mp3_block );
243
244     } while( p_pcm_block );
245
246     return p_chain;
247 }
248
249 static void CloseEncoder( vlc_object_t *p_this )
250 {
251     encoder_sys_t *p_sys = ((encoder_t*)p_this)->p_sys;
252
253     vlc_mutex_lock( &entrant.lock );
254     entrant.busy = false;
255     vlc_mutex_unlock( &entrant.lock );
256
257     /* TODO: we should send the last PCM block padded with 0
258      * But we don't know if other blocks will come before it's too late */
259     if( p_sys->i_buffer )
260         free( p_sys->p_buffer );
261
262     block_FifoRelease( p_sys->p_fifo );
263     free( p_sys );
264 }