~ubuntu-branches/ubuntu/wily/gmerlin-encoders/wily-proposed

« back to all changes in this revision

Viewing changes to plugins/faac/e_faac.c

  • Committer: Bazaar Package Importer
  • Author(s): IOhannes m zmoelnig (gpg-key at iem)
  • Date: 2011-01-15 20:19:05 UTC
  • Revision ID: james.westby@ubuntu.com-20110115201905-qign5pihv1b977ct
Tags: upstream-1.0.0
ImportĀ upstreamĀ versionĀ 1.0.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*****************************************************************
 
2
 * gmerlin-encoders - encoder plugins for gmerlin
 
3
 *
 
4
 * Copyright (c) 2001 - 2011 Members of the Gmerlin project
 
5
 * gmerlin-general@lists.sourceforge.net
 
6
 * http://gmerlin.sourceforge.net
 
7
 *
 
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.
 
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 General Public License for more details.
 
17
 *
 
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
 * *****************************************************************/
 
21
 
 
22
#include <stdio.h>
 
23
#include <string.h>
 
24
#include <stdlib.h>
 
25
#include <errno.h>
 
26
 
 
27
#include <faac.h>
 
28
 
 
29
#include <config.h>
 
30
 
 
31
#include <gmerlin_encoders.h>
 
32
 
 
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"
 
38
 
 
39
#include <gmerlin/translation.h>
 
40
 
 
41
typedef struct
 
42
  {
 
43
  FILE * output;
 
44
  char * filename;
 
45
  
 
46
  faacEncHandle enc;
 
47
  faacEncConfigurationPtr enc_config;
 
48
  
 
49
  gavl_audio_format_t format;
 
50
 
 
51
  gavl_audio_frame_t * frame;
 
52
  uint8_t            * output_buffer;
 
53
  unsigned int output_buffer_size;
 
54
    
 
55
  bgen_id3v1_t * id3v1;
 
56
  
 
57
  int do_id3v1;
 
58
  int do_id3v2;
 
59
  int id3v2_charset;
 
60
 
 
61
  int64_t samples_read;
 
62
  bg_encoder_callbacks_t * cb;
 
63
  
 
64
  } faac_t;
 
65
 
 
66
static void * create_faac()
 
67
  {
 
68
  faac_t * ret;
 
69
  ret = calloc(1, sizeof(*ret));
 
70
  return ret;
 
71
  }
 
72
 
 
73
static void destroy_faac(void * priv)
 
74
  {
 
75
  faac_t * faac;
 
76
  faac = (faac_t*)priv;
 
77
  
 
78
  free(faac);
 
79
  }
 
80
 
 
81
static void set_callbacks_faac(void * data, bg_encoder_callbacks_t * cb)
 
82
  {
 
83
  faac_t * faac = data;
 
84
  faac->cb = cb;
 
85
  }
 
86
 
 
87
static const bg_parameter_info_t audio_parameters[] =
 
88
  {
 
89
    {
 
90
      .name =        "basic",
 
91
      .long_name =   TRS("Basic options"),
 
92
      .type =        BG_PARAMETER_SECTION
 
93
    },
 
94
    {
 
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",
 
100
                              "mpeg2_lc",
 
101
                              "mpeg4_main",
 
102
                              "mpeg4_lc",
 
103
                              "mpeg4_ltp",
 
104
                              (char*)0 },
 
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)"),
 
110
                               (char*)0 },
 
111
    },
 
112
    {
 
113
      .name =        "bitrate",
 
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)"),
 
119
    },
 
120
    {
 
121
      .name =        "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"),
 
128
    },
 
129
    {
 
130
      .name =        "advanced",
 
131
      .long_name =   TRS("Advanced options"),
 
132
      .type =        BG_PARAMETER_SECTION
 
133
    },
 
134
    {
 
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",
 
140
                              "No short",
 
141
                              "No long",
 
142
                              (char*)0 },
 
143
      .multi_labels = (char const *[]){ TRS("Both"),
 
144
                               TRS("No short"),
 
145
                               TRS("No long"),
 
146
                               (char*)0 },
 
147
    },
 
148
    {
 
149
      .name =        "tns",
 
150
      .type =        BG_PARAMETER_CHECKBUTTON,
 
151
      .long_name =   TRS("Use temporal noise shaping"),
 
152
      .val_default = { .val_i = 0 }
 
153
    },
 
154
    {
 
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 }
 
159
    },
 
160
    { /* End of parameters */ }
 
161
  };
 
162
static const bg_parameter_info_t * get_audio_parameters_faac(void * data)
 
163
  {
 
164
  return audio_parameters;
 
165
  }
 
166
 
 
167
static void set_audio_parameter_faac(void * data, int stream, const char * name,
 
168
                                     const bg_parameter_value_t * v)
 
169
  {
 
170
  faac_t * faac;
 
171
  faac = (faac_t*)data;
 
172
  
 
173
  if(stream)
 
174
    return;
 
175
    
 
176
  else if(!name)
 
177
    {
 
178
    /* Set encoding parameters */
 
179
    
 
180
    if(!faacEncSetConfiguration(faac->enc, faac->enc_config))
 
181
      bg_log(BG_LOG_ERROR, LOG_DOMAIN,  "faacEncSetConfiguration failed");
 
182
    }
 
183
    
 
184
  else if(!strcmp(name, "object_type"))
 
185
    {
 
186
    if(!strcmp(v->val_str, "mpeg2_main"))
 
187
      {
 
188
      faac->enc_config->mpegVersion = MPEG2;
 
189
      faac->enc_config->aacObjectType = MAIN;
 
190
      }
 
191
    else if(!strcmp(v->val_str, "mpeg2_lc"))
 
192
      {
 
193
      faac->enc_config->mpegVersion = MPEG2;
 
194
      faac->enc_config->aacObjectType = LOW;
 
195
      }
 
196
    else if(!strcmp(v->val_str, "mpeg4_main"))
 
197
      {
 
198
      faac->enc_config->mpegVersion = MPEG4;
 
199
      faac->enc_config->aacObjectType = MAIN;
 
200
      }
 
201
    else if(!strcmp(v->val_str, "mpeg4_lc"))
 
202
      {
 
203
      faac->enc_config->mpegVersion = MPEG4;
 
204
      faac->enc_config->aacObjectType = LOW;
 
205
      }
 
206
    else if(!strcmp(v->val_str, "mpeg4_ltp"))
 
207
      {
 
208
      faac->enc_config->mpegVersion = MPEG4;
 
209
      faac->enc_config->aacObjectType = LTP;
 
210
      }
 
211
    }
 
212
  else if(!strcmp(name, "bitrate"))
 
213
    {
 
214
    faac->enc_config->bitRate =
 
215
      (v->val_i * 1000) / faac->format.num_channels;
 
216
    }
 
217
  else if(!strcmp(name, "quality"))
 
218
    {
 
219
    faac->enc_config->quantqual = v->val_i;
 
220
    }
 
221
  else if(!strcmp(name, "block_types"))
 
222
    {
 
223
    if(!strcmp(v->val_str, "Both"))
 
224
      {
 
225
      faac->enc_config->shortctl = SHORTCTL_NORMAL;
 
226
      }
 
227
    else if(!strcmp(v->val_str, "No short"))
 
228
      {
 
229
      faac->enc_config->shortctl = SHORTCTL_NOSHORT;
 
230
      }
 
231
    else if(!strcmp(v->val_str, "No long"))
 
232
      {
 
233
      faac->enc_config->shortctl = SHORTCTL_NOLONG;
 
234
      }
 
235
    }
 
236
  else if(!strcmp(name, "tns"))
 
237
    {
 
238
    faac->enc_config->useTns = v->val_i;
 
239
    }
 
240
  else if(!strcmp(name, "no_midside"))
 
241
    {
 
242
    faac->enc_config->allowMidside = !v->val_i;
 
243
    }
 
244
  }
 
245
 
 
246
static const bg_parameter_info_t parameters[] =
 
247
  {
 
248
    {
 
249
      .name =        "do_id3v1",
 
250
      .long_name =   TRS("Write ID3V1.1 tag"),
 
251
      .type =        BG_PARAMETER_CHECKBUTTON,
 
252
      .val_default = { .val_i = 1 },
 
253
    },
 
254
    {
 
255
      .name =        "do_id3v2",
 
256
      .long_name =   TRS("Write ID3V2 tag"),
 
257
      .type =        BG_PARAMETER_CHECKBUTTON,
 
258
      .val_default = { .val_i = 1 },
 
259
    },
 
260
    {
 
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 },
 
269
    },
 
270
    { /* End of parameters */ }
 
271
  };
 
272
 
 
273
static const bg_parameter_info_t * get_parameters_faac(void * data)
 
274
  {
 
275
  return parameters;
 
276
  }
 
277
 
 
278
 
 
279
static void set_parameter_faac(void * data, const char * name,
 
280
                               const bg_parameter_value_t * v)
 
281
  {
 
282
  faac_t * faac;
 
283
  faac = (faac_t*)data;
 
284
  
 
285
  if(!name)
 
286
    return;
 
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);
 
293
  }
 
294
 
 
295
static int open_faac(void * data, const char * filename,
 
296
                     const bg_metadata_t * metadata,
 
297
                     const bg_chapter_list_t * chapter_list)
 
298
  {
 
299
  faac_t * faac;
 
300
  bgen_id3v2_t * id3v2;
 
301
 
 
302
  faac = (faac_t*)data;
 
303
 
 
304
  faac->filename = bg_filename_ensure_extension(filename, "aac");
 
305
 
 
306
  if(!bg_encoder_cb_create_output_file(faac->cb, faac->filename))
 
307
    return 0;
 
308
  
 
309
  faac->output = fopen(faac->filename, "wb");
 
310
 
 
311
  if(!faac->output)
 
312
    {
 
313
    bg_log(BG_LOG_ERROR, LOG_DOMAIN, "Cannot open %s: %s",
 
314
           filename, strerror(errno));
 
315
    return 0;
 
316
    }
 
317
  
 
318
 
 
319
  if(faac->do_id3v1 && metadata)
 
320
    faac->id3v1 = bgen_id3v1_create(metadata);
 
321
  if(faac->do_id3v2 && metadata)
 
322
    {
 
323
    id3v2 = bgen_id3v2_create(metadata);
 
324
    bgen_id3v2_write(faac->output, id3v2, faac->id3v2_charset);
 
325
    bgen_id3v2_destroy(id3v2);
 
326
    }
 
327
  return 1;
 
328
  }
 
329
 
 
330
static int add_audio_stream_faac(void * data,
 
331
                                 const char * language,
 
332
                                 const gavl_audio_format_t * format)
 
333
  {
 
334
  unsigned long input_samples;
 
335
  unsigned long output_bytes;
 
336
  
 
337
  faac_t * faac;
 
338
  
 
339
  faac = (faac_t*)data;
 
340
 
 
341
  /* Create encoder handle and get configuration */
 
342
 
 
343
  faac->enc = faacEncOpen(format->samplerate,
 
344
                          format->num_channels,
 
345
                          &input_samples,
 
346
                          &output_bytes);
 
347
  
 
348
  faac->enc_config = faacEncGetCurrentConfiguration(faac->enc);
 
349
  faac->enc_config->inputFormat = FAAC_INPUT_FLOAT;
 
350
  
 
351
  /* Copy and adjust format */
 
352
 
 
353
  gavl_audio_format_copy(&faac->format, format);
 
354
 
 
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;
 
358
 
 
359
  switch(faac->format.num_channels)
 
360
    {
 
361
    case 1:
 
362
      faac->format.channel_locations[0] = GAVL_CHID_FRONT_CENTER;
 
363
      break;
 
364
    case 2:
 
365
      faac->format.channel_locations[0] = GAVL_CHID_FRONT_LEFT;
 
366
      faac->format.channel_locations[1] = GAVL_CHID_FRONT_RIGHT;
 
367
      break;
 
368
    case 3:
 
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;
 
372
      break;
 
373
    case 4:
 
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;
 
378
      break;
 
379
    case 5:
 
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;
 
385
      break;
 
386
    case 6:
 
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;
 
393
      break;
 
394
 
 
395
    }
 
396
 
 
397
  
 
398
  faac->frame = gavl_audio_frame_create(&faac->format);
 
399
  
 
400
  faac->output_buffer = malloc(output_bytes);
 
401
  faac->output_buffer_size = output_bytes;
 
402
  
 
403
  return 0;
 
404
  }
 
405
 
 
406
static int flush_audio(faac_t * faac)
 
407
  {
 
408
  int i, imax;
 
409
  int bytes_encoded;
 
410
 
 
411
  /* First, we must scale the samples to -32767 .. 32767 */
 
412
 
 
413
  imax = faac->frame->valid_samples * faac->format.num_channels;
 
414
  
 
415
  for(i = 0; i < imax; i++)
 
416
    faac->frame->samples.f[i] *= 32767.0;
 
417
  
 
418
  /* Encode the stuff */
 
419
 
 
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;
 
424
 
 
425
  /* Write this to the file */
 
426
 
 
427
  if(bytes_encoded)
 
428
    {
 
429
    if(fwrite(faac->output_buffer, 1, bytes_encoded, faac->output) < bytes_encoded)
 
430
      return -1;
 
431
    }
 
432
  return bytes_encoded;
 
433
  }
 
434
 
 
435
static int write_audio_frame_faac(void * data, gavl_audio_frame_t * frame,
 
436
                                  int stream)
 
437
  {
 
438
  int samples_done = 0;
 
439
  int samples_copied;
 
440
    
 
441
  faac_t * faac;
 
442
  faac = (faac_t*)data;
 
443
 
 
444
  
 
445
  while(samples_done < frame->valid_samples)
 
446
    {
 
447
 
 
448
    /* Copy frame into our buffer */
 
449
    
 
450
    samples_copied =
 
451
      gavl_audio_frame_copy(&faac->format,
 
452
                            faac->frame,                                                 /* dst */
 
453
                            frame,                                                       /* src */
 
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 */
 
458
    
 
459
    samples_done += samples_copied;
 
460
    faac->frame->valid_samples += samples_copied;
 
461
    
 
462
    /* Encode buffer */
 
463
 
 
464
    if(faac->frame->valid_samples == faac->format.samples_per_frame)
 
465
      {
 
466
      if(flush_audio(faac) < 0)
 
467
        return 0;
 
468
      }
 
469
    }
 
470
  
 
471
  faac->samples_read += frame->valid_samples;
 
472
  return 1;
 
473
  }
 
474
 
 
475
static void get_audio_format_faac(void * data, int stream,
 
476
                                 gavl_audio_format_t * ret)
 
477
  {
 
478
  faac_t * faac;
 
479
  faac = (faac_t*)data;
 
480
  gavl_audio_format_copy(ret, &faac->format);
 
481
  }
 
482
 
 
483
 
 
484
static int close_faac(void * data, int do_delete)
 
485
  {
 
486
  int ret = 1, result;
 
487
  faac_t * faac;
 
488
  faac = (faac_t*)data;
 
489
 
 
490
  /* Flush remaining audio data */
 
491
 
 
492
  if(faac->samples_read)
 
493
    {
 
494
    while(1)
 
495
      {
 
496
      result = flush_audio(faac);
 
497
      if(result > 0)
 
498
        continue;
 
499
      else if(result < 0)
 
500
        ret = 0;
 
501
      break;
 
502
      }
 
503
    }
 
504
  
 
505
  if(faac->enc)
 
506
    {
 
507
    faacEncClose(faac->enc);
 
508
    faac->enc = (faacEncHandle)0;
 
509
    }
 
510
  
 
511
  if(faac->output)
 
512
    {
 
513
    /* Write id3v1 tag */
 
514
    if(faac->id3v1)
 
515
      {
 
516
      if(ret)
 
517
        ret = bgen_id3v1_write(faac->output, faac->id3v1);
 
518
      bgen_id3v1_destroy(faac->id3v1);
 
519
      faac->id3v1 = (bgen_id3v1_t*)0;    
 
520
      }
 
521
    fclose(faac->output);
 
522
    faac->output = (FILE*)0;
 
523
    }
 
524
  
 
525
  if(faac->filename)
 
526
    {
 
527
    if(do_delete)
 
528
      remove(faac->filename);
 
529
    free(faac->filename);
 
530
    faac->filename = (char*)0;
 
531
    }
 
532
  return ret;
 
533
  }
 
534
  
 
535
const bg_encoder_plugin_t the_plugin =
 
536
  {
 
537
    .common =
 
538
    {
 
539
      BG_LOCALE,
 
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,
 
545
      .priority =        5,
 
546
      .create =            create_faac,
 
547
      .destroy =           destroy_faac,
 
548
      .get_parameters =    get_parameters_faac,
 
549
      .set_parameter =     set_parameter_faac,
 
550
    },
 
551
    .max_audio_streams =   1,
 
552
    .max_video_streams =   0,
 
553
    
 
554
    .set_callbacks =       set_callbacks_faac,
 
555
    
 
556
    .open =                open_faac,
 
557
    
 
558
    .get_audio_parameters =    get_audio_parameters_faac,
 
559
 
 
560
    .add_audio_stream =        add_audio_stream_faac,
 
561
    
 
562
    .set_audio_parameter =     set_audio_parameter_faac,
 
563
 
 
564
    .get_audio_format =        get_audio_format_faac,
 
565
    
 
566
    .write_audio_frame =   write_audio_frame_faac,
 
567
    .close =               close_faac
 
568
  };
 
569
 
 
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;