1
/*****************************************************************
2
* gmerlin-encoders - encoder plugins for gmerlin
4
* Copyright (c) 2001 - 2011 Members of the Gmerlin project
5
* gmerlin-general@lists.sourceforge.net
6
* http://gmerlin.sourceforge.net
8
* This program is free software: you can redistribute it and/or modify
9
* it under the terms of the GNU General Public License as published by
10
* the Free Software Foundation, either version 2 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 General Public License for more details.
18
* You should have received a copy of the GNU General Public License
19
* along with this program. If not, see <http://www.gnu.org/licenses/>.
20
* *****************************************************************/
31
#include <gmerlin_encoders.h>
33
#include <gmerlin/plugin.h>
34
#include <gmerlin/pluginfuncs.h>
35
#include <gmerlin/utils.h>
36
#include <gmerlin/log.h>
37
#define LOG_DOMAIN "e_faac"
39
#include <gmerlin/translation.h>
47
faacEncConfigurationPtr enc_config;
49
gavl_audio_format_t format;
51
gavl_audio_frame_t * frame;
52
uint8_t * output_buffer;
53
unsigned int output_buffer_size;
62
bg_encoder_callbacks_t * cb;
66
static void * create_faac()
69
ret = calloc(1, sizeof(*ret));
73
static void destroy_faac(void * priv)
81
static void set_callbacks_faac(void * data, bg_encoder_callbacks_t * cb)
87
static const bg_parameter_info_t audio_parameters[] =
91
.long_name = TRS("Basic options"),
92
.type = BG_PARAMETER_SECTION
95
.name = "object_type",
96
.long_name = TRS("Object type"),
97
.type = BG_PARAMETER_STRINGLIST,
98
.val_default = { .val_str = "mpeg4_main" },
99
.multi_names = (char const *[]){ "mpeg2_main",
105
.multi_labels = (char const *[]){ TRS("MPEG-2 Main profile"),
106
TRS("MPEG-2 Low Complexity profile (LC)"),
107
TRS("MPEG-4 Main profile"),
108
TRS("MPEG-4 Low Complexity profile (LC)"),
109
TRS("MPEG-4 Long Term Prediction (LTP)"),
114
.long_name = TRS("Bitrate (kbps)"),
115
.type = BG_PARAMETER_INT,
116
.val_min = { .val_i = 0 },
117
.val_max = { .val_i = 1000 },
118
.help_string = TRS("Average bitrate (0: VBR based on quality)"),
122
.long_name = TRS("Quality"),
123
.type = BG_PARAMETER_SLIDER_INT,
124
.val_min = { .val_i = 10 },
125
.val_max = { .val_i = 500 },
126
.val_default = { .val_i = 100 },
127
.help_string = TRS("Quantizer quality"),
131
.long_name = TRS("Advanced options"),
132
.type = BG_PARAMETER_SECTION
135
.name = "block_types",
136
.long_name = TRS("Block types"),
137
.type = BG_PARAMETER_STRINGLIST,
138
.val_default = { .val_str = "Both" },
139
.multi_names = (char const *[]){ "Both",
143
.multi_labels = (char const *[]){ TRS("Both"),
150
.type = BG_PARAMETER_CHECKBUTTON,
151
.long_name = TRS("Use temporal noise shaping"),
152
.val_default = { .val_i = 0 }
155
.name = "no_midside",
156
.long_name = TRS("Don\'t use mid/side coding"),
157
.type = BG_PARAMETER_CHECKBUTTON,
158
.val_default = { .val_i = 0 }
160
{ /* End of parameters */ }
162
static const bg_parameter_info_t * get_audio_parameters_faac(void * data)
164
return audio_parameters;
167
static void set_audio_parameter_faac(void * data, int stream, const char * name,
168
const bg_parameter_value_t * v)
171
faac = (faac_t*)data;
178
/* Set encoding parameters */
180
if(!faacEncSetConfiguration(faac->enc, faac->enc_config))
181
bg_log(BG_LOG_ERROR, LOG_DOMAIN, "faacEncSetConfiguration failed");
184
else if(!strcmp(name, "object_type"))
186
if(!strcmp(v->val_str, "mpeg2_main"))
188
faac->enc_config->mpegVersion = MPEG2;
189
faac->enc_config->aacObjectType = MAIN;
191
else if(!strcmp(v->val_str, "mpeg2_lc"))
193
faac->enc_config->mpegVersion = MPEG2;
194
faac->enc_config->aacObjectType = LOW;
196
else if(!strcmp(v->val_str, "mpeg4_main"))
198
faac->enc_config->mpegVersion = MPEG4;
199
faac->enc_config->aacObjectType = MAIN;
201
else if(!strcmp(v->val_str, "mpeg4_lc"))
203
faac->enc_config->mpegVersion = MPEG4;
204
faac->enc_config->aacObjectType = LOW;
206
else if(!strcmp(v->val_str, "mpeg4_ltp"))
208
faac->enc_config->mpegVersion = MPEG4;
209
faac->enc_config->aacObjectType = LTP;
212
else if(!strcmp(name, "bitrate"))
214
faac->enc_config->bitRate =
215
(v->val_i * 1000) / faac->format.num_channels;
217
else if(!strcmp(name, "quality"))
219
faac->enc_config->quantqual = v->val_i;
221
else if(!strcmp(name, "block_types"))
223
if(!strcmp(v->val_str, "Both"))
225
faac->enc_config->shortctl = SHORTCTL_NORMAL;
227
else if(!strcmp(v->val_str, "No short"))
229
faac->enc_config->shortctl = SHORTCTL_NOSHORT;
231
else if(!strcmp(v->val_str, "No long"))
233
faac->enc_config->shortctl = SHORTCTL_NOLONG;
236
else if(!strcmp(name, "tns"))
238
faac->enc_config->useTns = v->val_i;
240
else if(!strcmp(name, "no_midside"))
242
faac->enc_config->allowMidside = !v->val_i;
246
static const bg_parameter_info_t parameters[] =
250
.long_name = TRS("Write ID3V1.1 tag"),
251
.type = BG_PARAMETER_CHECKBUTTON,
252
.val_default = { .val_i = 1 },
256
.long_name = TRS("Write ID3V2 tag"),
257
.type = BG_PARAMETER_CHECKBUTTON,
258
.val_default = { .val_i = 1 },
261
.name = "id3v2_charset",
262
.long_name = TRS("ID3V2 Encoding"),
263
.type = BG_PARAMETER_STRINGLIST,
264
.val_default = { .val_str = "3" },
265
.multi_names = (char const *[]){ "0", "1",
266
"2", "3", (char*)0 },
267
.multi_labels = (char const *[]){ TRS("ISO-8859-1"), TRS("UTF-16 LE"),
268
TRS("UTF-16 BE"), TRS("UTF-8"), (char*)0 },
270
{ /* End of parameters */ }
273
static const bg_parameter_info_t * get_parameters_faac(void * data)
279
static void set_parameter_faac(void * data, const char * name,
280
const bg_parameter_value_t * v)
283
faac = (faac_t*)data;
287
else if(!strcmp(name, "do_id3v1"))
288
faac->do_id3v1 = v->val_i;
289
else if(!strcmp(name, "do_id3v2"))
290
faac->do_id3v2 = v->val_i;
291
else if(!strcmp(name, "id3v2_charset"))
292
faac->id3v2_charset = atoi(v->val_str);
295
static int open_faac(void * data, const char * filename,
296
const bg_metadata_t * metadata,
297
const bg_chapter_list_t * chapter_list)
300
bgen_id3v2_t * id3v2;
302
faac = (faac_t*)data;
304
faac->filename = bg_filename_ensure_extension(filename, "aac");
306
if(!bg_encoder_cb_create_output_file(faac->cb, faac->filename))
309
faac->output = fopen(faac->filename, "wb");
313
bg_log(BG_LOG_ERROR, LOG_DOMAIN, "Cannot open %s: %s",
314
filename, strerror(errno));
319
if(faac->do_id3v1 && metadata)
320
faac->id3v1 = bgen_id3v1_create(metadata);
321
if(faac->do_id3v2 && metadata)
323
id3v2 = bgen_id3v2_create(metadata);
324
bgen_id3v2_write(faac->output, id3v2, faac->id3v2_charset);
325
bgen_id3v2_destroy(id3v2);
330
static int add_audio_stream_faac(void * data,
331
const char * language,
332
const gavl_audio_format_t * format)
334
unsigned long input_samples;
335
unsigned long output_bytes;
339
faac = (faac_t*)data;
341
/* Create encoder handle and get configuration */
343
faac->enc = faacEncOpen(format->samplerate,
344
format->num_channels,
348
faac->enc_config = faacEncGetCurrentConfiguration(faac->enc);
349
faac->enc_config->inputFormat = FAAC_INPUT_FLOAT;
351
/* Copy and adjust format */
353
gavl_audio_format_copy(&faac->format, format);
355
faac->format.interleave_mode = GAVL_INTERLEAVE_ALL;
356
faac->format.sample_format = GAVL_SAMPLE_FLOAT;
357
faac->format.samples_per_frame = input_samples / format->num_channels;
359
switch(faac->format.num_channels)
362
faac->format.channel_locations[0] = GAVL_CHID_FRONT_CENTER;
365
faac->format.channel_locations[0] = GAVL_CHID_FRONT_LEFT;
366
faac->format.channel_locations[1] = GAVL_CHID_FRONT_RIGHT;
369
faac->format.channel_locations[0] = GAVL_CHID_FRONT_CENTER;
370
faac->format.channel_locations[1] = GAVL_CHID_FRONT_LEFT;
371
faac->format.channel_locations[2] = GAVL_CHID_FRONT_RIGHT;
374
faac->format.channel_locations[0] = GAVL_CHID_FRONT_CENTER;
375
faac->format.channel_locations[1] = GAVL_CHID_FRONT_LEFT;
376
faac->format.channel_locations[2] = GAVL_CHID_FRONT_RIGHT;
377
faac->format.channel_locations[3] = GAVL_CHID_REAR_CENTER;
380
faac->format.channel_locations[0] = GAVL_CHID_FRONT_CENTER;
381
faac->format.channel_locations[1] = GAVL_CHID_FRONT_LEFT;
382
faac->format.channel_locations[2] = GAVL_CHID_FRONT_RIGHT;
383
faac->format.channel_locations[3] = GAVL_CHID_REAR_LEFT;
384
faac->format.channel_locations[4] = GAVL_CHID_REAR_RIGHT;
387
faac->format.channel_locations[0] = GAVL_CHID_FRONT_CENTER;
388
faac->format.channel_locations[1] = GAVL_CHID_FRONT_LEFT;
389
faac->format.channel_locations[2] = GAVL_CHID_FRONT_RIGHT;
390
faac->format.channel_locations[3] = GAVL_CHID_REAR_LEFT;
391
faac->format.channel_locations[4] = GAVL_CHID_REAR_RIGHT;
392
faac->format.channel_locations[5] = GAVL_CHID_LFE;
398
faac->frame = gavl_audio_frame_create(&faac->format);
400
faac->output_buffer = malloc(output_bytes);
401
faac->output_buffer_size = output_bytes;
406
static int flush_audio(faac_t * faac)
411
/* First, we must scale the samples to -32767 .. 32767 */
413
imax = faac->frame->valid_samples * faac->format.num_channels;
415
for(i = 0; i < imax; i++)
416
faac->frame->samples.f[i] *= 32767.0;
418
/* Encode the stuff */
420
bytes_encoded = faacEncEncode(faac->enc, (int32_t*)faac->frame->samples.f,
421
faac->frame->valid_samples * faac->format.num_channels,
422
faac->output_buffer, faac->output_buffer_size);
423
faac->frame->valid_samples = 0;
425
/* Write this to the file */
429
if(fwrite(faac->output_buffer, 1, bytes_encoded, faac->output) < bytes_encoded)
432
return bytes_encoded;
435
static int write_audio_frame_faac(void * data, gavl_audio_frame_t * frame,
438
int samples_done = 0;
442
faac = (faac_t*)data;
445
while(samples_done < frame->valid_samples)
448
/* Copy frame into our buffer */
451
gavl_audio_frame_copy(&faac->format,
452
faac->frame, /* dst */
454
faac->frame->valid_samples, /* dst_pos */
455
samples_done, /* src_pos */
456
faac->format.samples_per_frame - faac->frame->valid_samples, /* dst_size */
457
frame->valid_samples - samples_done); /* src_size */
459
samples_done += samples_copied;
460
faac->frame->valid_samples += samples_copied;
464
if(faac->frame->valid_samples == faac->format.samples_per_frame)
466
if(flush_audio(faac) < 0)
471
faac->samples_read += frame->valid_samples;
475
static void get_audio_format_faac(void * data, int stream,
476
gavl_audio_format_t * ret)
479
faac = (faac_t*)data;
480
gavl_audio_format_copy(ret, &faac->format);
484
static int close_faac(void * data, int do_delete)
488
faac = (faac_t*)data;
490
/* Flush remaining audio data */
492
if(faac->samples_read)
496
result = flush_audio(faac);
507
faacEncClose(faac->enc);
508
faac->enc = (faacEncHandle)0;
513
/* Write id3v1 tag */
517
ret = bgen_id3v1_write(faac->output, faac->id3v1);
518
bgen_id3v1_destroy(faac->id3v1);
519
faac->id3v1 = (bgen_id3v1_t*)0;
521
fclose(faac->output);
522
faac->output = (FILE*)0;
528
remove(faac->filename);
529
free(faac->filename);
530
faac->filename = (char*)0;
535
const bg_encoder_plugin_t the_plugin =
540
.name = "e_faac", /* Unique short name */
541
.long_name = TRS("Faac encoder"),
542
.description = TRS("Plugin for encoding AAC streams (with ADTS headers). Based on faac (http://faac.sourceforge.net)."),
543
.type = BG_PLUGIN_ENCODER_AUDIO,
544
.flags = BG_PLUGIN_FILE,
546
.create = create_faac,
547
.destroy = destroy_faac,
548
.get_parameters = get_parameters_faac,
549
.set_parameter = set_parameter_faac,
551
.max_audio_streams = 1,
552
.max_video_streams = 0,
554
.set_callbacks = set_callbacks_faac,
558
.get_audio_parameters = get_audio_parameters_faac,
560
.add_audio_stream = add_audio_stream_faac,
562
.set_audio_parameter = set_audio_parameter_faac,
564
.get_audio_format = get_audio_format_faac,
566
.write_audio_frame = write_audio_frame_faac,
570
/* Include this into all plugin modules exactly once
571
to let the plugin loader obtain the API version */
572
BG_GET_PLUGIN_API_VERSION;