WinGui: Fix another instance of the Caliburn vs Json.net sillyness where objects...
[HandBrake.git] / libhb / encvorbis.c
blobc4ff206e106741aa77a5a9b6c5d69a6ce6b50f65
1 /* encvorbis.c
3 Copyright (c) 2003-2015 HandBrake Team
4 This file is part of the HandBrake source code
5 Homepage: <http://handbrake.fr/>.
6 It may be used under the terms of the GNU General Public License v2.
7 For full terms see the file COPYING file or visit http://www.gnu.org/licenses/gpl-2.0.html
8 */
10 #include "hb.h"
11 #include "audio_remap.h"
13 #include "vorbis/vorbisenc.h"
15 #define OGGVORBIS_FRAME_SIZE 1024
17 int encvorbisInit( hb_work_object_t *, hb_job_t * );
18 int encvorbisWork( hb_work_object_t *, hb_buffer_t **, hb_buffer_t ** );
19 void encvorbisClose( hb_work_object_t * );
21 hb_work_object_t hb_encvorbis =
23 WORK_ENCVORBIS,
24 "Vorbis encoder (libvorbis)",
25 encvorbisInit,
26 encvorbisWork,
27 encvorbisClose
30 struct hb_work_private_s
32 uint8_t *buf;
33 hb_job_t *job;
34 hb_list_t *list;
36 vorbis_dsp_state vd;
37 vorbis_comment vc;
38 vorbis_block vb;
39 vorbis_info vi;
41 unsigned input_samples;
42 uint64_t pts;
43 int64_t prev_blocksize;
44 int out_discrete_channels;
46 int remap_table[8];
49 int encvorbisInit(hb_work_object_t *w, hb_job_t *job)
51 hb_work_private_t *pv = calloc(1, sizeof(hb_work_private_t));
52 hb_audio_t *audio = w->audio;
53 w->private_data = pv;
54 pv->job = job;
56 int i;
57 ogg_packet header[3];
59 hb_log("encvorbis: opening libvorbis");
61 /* init */
62 for (i = 0; i < 3; i++)
64 // Zero vorbis headers so that we don't crash in mk_laceXiph
65 // when vorbis_encode_setup_managed fails.
66 memset(w->config->vorbis.headers[i], 0, sizeof(ogg_packet));
68 vorbis_info_init(&pv->vi);
70 pv->out_discrete_channels =
71 hb_mixdown_get_discrete_channel_count(audio->config.out.mixdown);
73 if (audio->config.out.bitrate > 0)
75 if (vorbis_encode_setup_managed(&pv->vi, pv->out_discrete_channels,
76 audio->config.out.samplerate, -1,
77 audio->config.out.bitrate * 1000, -1))
79 hb_error("encvorbis: vorbis_encode_setup_managed() failed");
80 *job->done_error = HB_ERROR_INIT;
81 *job->die = 1;
82 return -1;
85 else if (audio->config.out.quality != HB_INVALID_AUDIO_QUALITY)
87 // map VBR quality to Vorbis API (divide by 10)
88 if (vorbis_encode_setup_vbr(&pv->vi, pv->out_discrete_channels,
89 audio->config.out.samplerate,
90 audio->config.out.quality / 10))
92 hb_error("encvorbis: vorbis_encode_setup_vbr() failed");
93 *job->done_error = HB_ERROR_INIT;
94 *job->die = 1;
95 return -1;
99 if (vorbis_encode_ctl(&pv->vi, OV_ECTL_RATEMANAGE2_SET, NULL) ||
100 vorbis_encode_setup_init(&pv->vi))
102 hb_error("encvorbis: vorbis_encode_ctl(ratemanage2_set) OR vorbis_encode_setup_init() failed");
103 *job->done_error = HB_ERROR_INIT;
104 *job->die = 1;
105 return -1;
108 /* add a comment */
109 vorbis_comment_init(&pv->vc);
110 vorbis_comment_add_tag(&pv->vc, "Encoder", "HandBrake");
111 vorbis_comment_add_tag(&pv->vc, "LANGUAGE", w->config->vorbis.language);
113 /* set up the analysis state and auxiliary encoding storage */
114 vorbis_analysis_init(&pv->vd, &pv->vi);
115 vorbis_block_init(&pv->vd, &pv->vb);
117 /* get the 3 headers */
118 vorbis_analysis_headerout(&pv->vd, &pv->vc,
119 &header[0], &header[1], &header[2]);
120 ogg_packet *pheader;
121 for (i = 0; i < 3; i++)
123 pheader = (ogg_packet*)w->config->theora.headers[i];
124 memcpy(pheader, &header[i], sizeof(ogg_packet));
125 pheader->packet = w->config->theora.headers[i] + sizeof(ogg_packet);
126 memcpy(pheader->packet, header[i].packet, header[i].bytes );
129 pv->input_samples = pv->out_discrete_channels * OGGVORBIS_FRAME_SIZE;
130 audio->config.out.samples_per_frame = OGGVORBIS_FRAME_SIZE;
131 pv->buf = malloc(pv->input_samples * sizeof(float));
133 pv->list = hb_list_init();
135 // channel remapping
136 uint64_t layout = hb_ff_mixdown_xlat(audio->config.out.mixdown, NULL);
137 hb_audio_remap_build_table(&hb_vorbis_chan_map,
138 audio->config.in.channel_map, layout,
139 pv->remap_table);
141 return 0;
144 /***********************************************************************
145 * Close
146 ***********************************************************************
148 **********************************************************************/
149 void encvorbisClose(hb_work_object_t * w)
151 hb_work_private_t *pv = w->private_data;
153 vorbis_comment_clear(&pv->vc);
154 vorbis_block_clear(&pv->vb);
155 vorbis_info_clear(&pv->vi);
156 vorbis_dsp_clear(&pv->vd);
158 if (pv->list)
160 hb_list_empty(&pv->list);
163 free(pv->buf);
164 free(pv);
165 w->private_data = NULL;
168 /***********************************************************************
169 * Flush
170 ***********************************************************************
172 **********************************************************************/
173 static hb_buffer_t * Flush( hb_work_object_t * w )
175 hb_work_private_t * pv = w->private_data;
176 hb_buffer_t * buf;
177 int64_t blocksize = 0;
179 if( vorbis_analysis_blockout( &pv->vd, &pv->vb ) == 1 )
181 ogg_packet op;
183 vorbis_analysis( &pv->vb, NULL );
184 vorbis_bitrate_addblock( &pv->vb );
186 if( vorbis_bitrate_flushpacket( &pv->vd, &op ) )
188 buf = hb_buffer_init( op.bytes );
189 memcpy( buf->data, op.packet, op.bytes );
190 blocksize = vorbis_packet_blocksize(&pv->vi, &op);
192 buf->s.type = AUDIO_BUF;
193 buf->s.frametype = HB_FRAME_AUDIO;
195 buf->s.start = (int64_t)(vorbis_granule_time(&pv->vd, op.granulepos) * 90000);
196 buf->s.stop = (int64_t)(vorbis_granule_time(&pv->vd, (pv->prev_blocksize + blocksize)/4 + op.granulepos) * 90000);
197 buf->s.duration = buf->s.stop - buf->s.start;
198 /* The stop time isn't accurate for the first ~3 packets, as the actual blocksize depends on the previous _and_ current packets. */
199 pv->prev_blocksize = blocksize;
200 return buf;
204 return NULL;
207 /***********************************************************************
208 * Encode
209 ***********************************************************************
211 **********************************************************************/
212 static hb_buffer_t* Encode(hb_work_object_t *w)
214 hb_work_private_t *pv = w->private_data;
215 hb_buffer_t *buf;
216 float **buffer;
217 int i, j;
219 /* Try to extract more data */
220 if ((buf = Flush(w)) != NULL)
222 return buf;
225 /* Check if we need more data */
226 if (hb_list_bytes(pv->list) < pv->input_samples * sizeof(float))
228 return NULL;
231 /* Process more samples */
232 hb_list_getbytes(pv->list, pv->buf, pv->input_samples * sizeof(float),
233 &pv->pts, NULL);
234 buffer = vorbis_analysis_buffer(&pv->vd, OGGVORBIS_FRAME_SIZE);
235 for (i = 0; i < OGGVORBIS_FRAME_SIZE; i++)
237 for (j = 0; j < pv->out_discrete_channels; j++)
239 buffer[j][i] = ((float*)pv->buf)[(pv->out_discrete_channels * i +
240 pv->remap_table[j])];
244 vorbis_analysis_wrote(&pv->vd, OGGVORBIS_FRAME_SIZE);
246 /* Try to extract again */
247 return Flush(w);
250 /***********************************************************************
251 * Work
252 ***********************************************************************
254 **********************************************************************/
255 int encvorbisWork( hb_work_object_t * w, hb_buffer_t ** buf_in,
256 hb_buffer_t ** buf_out )
258 hb_work_private_t * pv = w->private_data;
259 hb_buffer_t * in = *buf_in;
260 hb_buffer_t * buf;
262 *buf_in = NULL;
263 if (in->s.flags & HB_BUF_FLAG_EOF)
265 /* EOF on input - send it downstream & say we're done */
266 *buf_out = in;
267 return HB_WORK_DONE;
270 hb_list_add( pv->list, in );
272 *buf_out = buf = Encode( w );
273 while( buf )
275 buf->next = Encode( w );
276 buf = buf->next;
279 return HB_WORK_OK;