mirror of
https://github.com/nu774/fdkaac.git
synced 2025-06-05 23:29:14 +02:00
Compare commits
10 Commits
Author | SHA1 | Date | |
---|---|---|---|
9517c27537 | |||
d317e29d46 | |||
ffc230a83e | |||
70e912edba | |||
bd02d0e753 | |||
d6a8b9652a | |||
229c3ead72 | |||
4d060c0da0 | |||
1184a1f52b | |||
93fb917b75 |
@ -31,8 +31,9 @@ AC_TYPE_UINT8_T
|
||||
AC_CHECK_TYPES([ptrdiff_t])
|
||||
|
||||
AC_SYS_LARGEFILE
|
||||
AC_CHECK_TYPES([struct __timeb64],[],[],[[#include <sys/timeb.h>]])
|
||||
AC_FUNC_FSEEKO
|
||||
AC_CHECK_FUNCS([sigaction gettimeofday nl_langinfo strdup _vscprintf])
|
||||
AC_CHECK_FUNCS([sigaction gettimeofday nl_langinfo _vscprintf fseeko64])
|
||||
AC_CHECK_FUNC(getopt_long)
|
||||
AM_CONDITIONAL([FDK_NO_GETOPT_LONG],[test "$ac_cv_func_getopt_long" != "yes"])
|
||||
AC_SEARCH_LIBS([aacEncOpen],[fdk-aac],[],[],[])
|
||||
|
@ -6,7 +6,10 @@
|
||||
#define COMPAT_H
|
||||
|
||||
#ifndef HAVE_FSEEKO
|
||||
# if _MSC_VER >= 1400
|
||||
# if HAVE_FSEEKO64
|
||||
# define fseeko fseeko64
|
||||
# define ftello ftello64
|
||||
# elif _MSC_VER >= 1400
|
||||
# define fseeko _fseeki64
|
||||
# define ftello _ftelli64
|
||||
# else
|
||||
|
@ -31,8 +31,13 @@ int __wgetmainargs(int *, wchar_t ***, wchar_t ***, int, _startupinfo *);
|
||||
|
||||
int64_t aacenc_timer(void)
|
||||
{
|
||||
#if HAVE_STRUCT___TIMEB64
|
||||
struct __timeb64 tv;
|
||||
_ftime64(&tv);
|
||||
#else
|
||||
struct timeb tv;
|
||||
ftime(&tv);
|
||||
#endif
|
||||
return (int64_t)tv.time * 1000 + tv.millitm;
|
||||
}
|
||||
|
||||
|
167
src/m4af.c
167
src/m4af.c
@ -79,6 +79,7 @@ struct m4af_ctx_t {
|
||||
int64_t modification_time;
|
||||
int64_t mdat_pos;
|
||||
int64_t mdat_size;
|
||||
int priming_mode;
|
||||
int last_error;
|
||||
|
||||
m4af_itmf_entry_t *itmf_table;
|
||||
@ -148,6 +149,13 @@ int m4af_write(m4af_ctx_t *ctx, const void *data, uint32_t size)
|
||||
return rc;
|
||||
}
|
||||
|
||||
static
|
||||
int m4af_write16(m4af_ctx_t *ctx, uint32_t data)
|
||||
{
|
||||
data = m4af_htob16(data);
|
||||
return m4af_write(ctx, &data, 2);
|
||||
}
|
||||
|
||||
static
|
||||
int m4af_write32(m4af_ctx_t *ctx, uint32_t data)
|
||||
{
|
||||
@ -277,6 +285,11 @@ void m4af_set_priming(m4af_ctx_t *ctx, uint32_t track_idx,
|
||||
track->padding = padding;
|
||||
}
|
||||
|
||||
void m4af_set_priming_mode(m4af_ctx_t *ctx, int mode)
|
||||
{
|
||||
ctx->priming_mode = mode;
|
||||
}
|
||||
|
||||
static
|
||||
int m4af_add_sample_entry(m4af_ctx_t *ctx, uint32_t track_idx,
|
||||
uint32_t size, uint32_t delta)
|
||||
@ -426,52 +439,68 @@ int m4af_write_sample(m4af_ctx_t *ctx, uint32_t track_idx, const void *data,
|
||||
}
|
||||
|
||||
static
|
||||
int m4af_add_itmf_entry(m4af_ctx_t *ctx)
|
||||
m4af_itmf_entry_t *m4af_find_itmf_slot(m4af_ctx_t *ctx, uint32_t fcc,
|
||||
const char *name)
|
||||
{
|
||||
m4af_itmf_entry_t *entry;
|
||||
m4af_itmf_entry_t *entry = ctx->itmf_table;
|
||||
|
||||
if (name)
|
||||
fcc = M4AF_FOURCC('-','-','-','-');
|
||||
|
||||
if (fcc != M4AF_TAG_ARTWORK)
|
||||
for (; entry != ctx->itmf_table + ctx->num_tags; ++entry)
|
||||
if (fcc == entry->fcc && (!name || !strcmp(name, entry->name)))
|
||||
return entry;
|
||||
|
||||
if (ctx->num_tags == ctx->itmf_table_capacity) {
|
||||
uint32_t new_size = ctx->itmf_table_capacity;
|
||||
new_size = new_size ? new_size * 2 : 1;
|
||||
entry = m4af_realloc(ctx->itmf_table, new_size * sizeof(*entry));
|
||||
if (entry == 0) {
|
||||
ctx->last_error = M4AF_NO_MEMORY;
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
ctx->itmf_table = entry;
|
||||
ctx->itmf_table_capacity = new_size;
|
||||
}
|
||||
++ctx->num_tags;
|
||||
return 0;
|
||||
entry = &ctx->itmf_table[ctx->num_tags++];
|
||||
memset(entry, 0, sizeof(m4af_itmf_entry_t));
|
||||
entry->fcc = fcc;
|
||||
if (name) {
|
||||
char *name_copy = m4af_realloc(0, strlen(name) + 1);
|
||||
if (!name_copy) {
|
||||
ctx->last_error = M4AF_NO_MEMORY;
|
||||
--ctx->num_tags;
|
||||
return 0;
|
||||
}
|
||||
strcpy(name_copy, name);
|
||||
entry->name = name_copy;
|
||||
}
|
||||
return entry;
|
||||
}
|
||||
|
||||
int m4af_add_itmf_long_tag(m4af_ctx_t *ctx, const char *name,
|
||||
const char *data)
|
||||
{
|
||||
m4af_itmf_entry_t *entry;
|
||||
char *data_copy = 0;
|
||||
size_t name_len = strlen(name);
|
||||
size_t data_len = strlen(data);
|
||||
char *name_copy = m4af_realloc(0, name_len + 1);
|
||||
char *data_copy = m4af_realloc(0, data_len);
|
||||
if (!name_copy || !data_copy) {
|
||||
if (!name_len || !data_len)
|
||||
return 0;
|
||||
|
||||
if ((entry = m4af_find_itmf_slot(ctx, 0, name)) == 0)
|
||||
goto FAIL;
|
||||
entry->type_code = M4AF_UTF8;
|
||||
if ((data_copy = m4af_realloc(entry->data, data_len)) == 0) {
|
||||
ctx->last_error = M4AF_NO_MEMORY;
|
||||
goto FAIL;
|
||||
}
|
||||
if (m4af_add_itmf_entry(ctx) < 0)
|
||||
goto FAIL;
|
||||
memcpy(name_copy, name, name_len + 1);
|
||||
memcpy(data_copy, data, data_len);
|
||||
entry = ctx->itmf_table + ctx->num_tags - 1;
|
||||
entry->fcc = M4AF_FOURCC('-','-','-','-');
|
||||
entry->name = name_copy;
|
||||
entry->type_code = M4AF_UTF8;
|
||||
entry->data = data_copy;
|
||||
entry->data_size = data_len;
|
||||
return 0;
|
||||
FAIL:
|
||||
if (name_copy)
|
||||
m4af_free(name_copy);
|
||||
if (data_copy)
|
||||
m4af_free(data_copy);
|
||||
return ctx->last_error;
|
||||
}
|
||||
|
||||
@ -480,24 +509,22 @@ int m4af_add_itmf_short_tag(m4af_ctx_t *ctx, uint32_t fcc,
|
||||
uint32_t data_size)
|
||||
{
|
||||
m4af_itmf_entry_t *entry;
|
||||
char *data_copy = m4af_realloc(0, data_size);
|
||||
if (!data_copy) {
|
||||
char *data_copy = 0;
|
||||
|
||||
if (!data_size)
|
||||
return 0;
|
||||
if ((entry = m4af_find_itmf_slot(ctx, fcc, 0)) == 0)
|
||||
goto FAIL;
|
||||
entry->type_code = type_code;
|
||||
if ((data_copy = m4af_realloc(entry->data, data_size)) == 0) {
|
||||
ctx->last_error = M4AF_NO_MEMORY;
|
||||
goto FAIL;
|
||||
}
|
||||
if (m4af_add_itmf_entry(ctx) < 0)
|
||||
goto FAIL;
|
||||
entry = ctx->itmf_table + ctx->num_tags - 1;
|
||||
entry->fcc = fcc;
|
||||
entry->name = 0;
|
||||
entry->type_code = type_code;
|
||||
memcpy(data_copy, data, data_size);
|
||||
entry->data = data_copy;
|
||||
entry->data_size = data_size;
|
||||
return 0;
|
||||
FAIL:
|
||||
if (data_copy)
|
||||
m4af_free(data_copy);
|
||||
return ctx->last_error;
|
||||
}
|
||||
|
||||
@ -809,12 +836,50 @@ void m4af_write_stsd_box(m4af_ctx_t *ctx, uint32_t track_idx)
|
||||
m4af_update_box_size(ctx, pos);
|
||||
}
|
||||
|
||||
static
|
||||
void m4af_write_sbgp_box(m4af_ctx_t *ctx, uint32_t track_idx)
|
||||
{
|
||||
m4af_track_t *track = &ctx->track[track_idx];
|
||||
m4af_write(ctx,
|
||||
"\0\0\0\034" /* size: 28 */
|
||||
"sbgp" /* type */
|
||||
"\0" /* version */
|
||||
"\0\0\0" /* flags */
|
||||
"roll" /* grouping_type */
|
||||
"\0\0\0\001" /* entry_count: 1 */
|
||||
, 20);
|
||||
m4af_write32(ctx, track->num_samples);
|
||||
m4af_write32(ctx, 1); /* group_description_index */
|
||||
}
|
||||
|
||||
static
|
||||
void m4af_write_sgpd_box(m4af_ctx_t *ctx, uint32_t track_idx)
|
||||
{
|
||||
m4af_track_t *track = &ctx->track[track_idx];
|
||||
m4af_write(ctx,
|
||||
"\0\0\0\032" /* size */
|
||||
"sgpd" /* type */
|
||||
"\001" /* version */
|
||||
"\0\0\0" /* flags */
|
||||
"roll" /* grouping_type */
|
||||
"\0\0\0\002" /* default_length: 2 */
|
||||
"\0\0\0\001" /* entry_count: 1 */
|
||||
"\377\377" /* payload_data: -1 */
|
||||
, 26);
|
||||
}
|
||||
|
||||
static
|
||||
void m4af_write_stbl_box(m4af_ctx_t *ctx, uint32_t track_idx)
|
||||
{
|
||||
m4af_track_t *track = &ctx->track[track_idx];
|
||||
int64_t pos = m4af_tell(ctx);
|
||||
m4af_write(ctx, "\0\0\0\0stbl", 8);
|
||||
m4af_write_stsd_box(ctx, track_idx);
|
||||
if ((ctx->priming_mode & M4AF_PRIMING_MODE_EDTS) &&
|
||||
(track->encoder_delay || track->padding)) {
|
||||
m4af_write_sbgp_box(ctx, track_idx);
|
||||
m4af_write_sgpd_box(ctx, track_idx);
|
||||
}
|
||||
m4af_write_stts_box(ctx, track_idx);
|
||||
m4af_write_stsc_box(ctx, track_idx);
|
||||
m4af_write_stsz_box(ctx, track_idx);
|
||||
@ -948,6 +1013,42 @@ void m4af_write_mdia_box(m4af_ctx_t *ctx, uint32_t track_idx)
|
||||
m4af_update_box_size(ctx, pos);
|
||||
}
|
||||
|
||||
static
|
||||
void m4af_write_elst_box(m4af_ctx_t *ctx, uint32_t track_idx)
|
||||
{
|
||||
m4af_track_t *track = &ctx->track[track_idx];
|
||||
uint8_t version;
|
||||
int64_t duration = track->duration - track->encoder_delay - track->padding;
|
||||
int64_t pos = m4af_tell(ctx);
|
||||
duration = (double)duration / track->timescale * ctx->timescale + .5;
|
||||
version = (duration > UINT32_MAX);
|
||||
|
||||
m4af_write(ctx, "\0\0\0\0elst", 8);
|
||||
m4af_write(ctx, &version, 1);
|
||||
m4af_write(ctx, "\0\0\0", 3); /* flags */
|
||||
m4af_write32(ctx, 1); /* entry_count: 1 */
|
||||
if (version) {
|
||||
m4af_write64(ctx, duration);
|
||||
m4af_write64(ctx, track->encoder_delay);
|
||||
} else {
|
||||
m4af_write32(ctx, duration);
|
||||
m4af_write32(ctx, track->encoder_delay);
|
||||
}
|
||||
m4af_write16(ctx, 1); /* media_rate_integer */
|
||||
m4af_write16(ctx, 0); /* media_rate_fraction */
|
||||
m4af_update_box_size(ctx, pos);
|
||||
}
|
||||
|
||||
static
|
||||
void m4af_write_edts_box(m4af_ctx_t *ctx, uint32_t track_idx)
|
||||
{
|
||||
m4af_track_t *track = &ctx->track[track_idx];
|
||||
int64_t pos = m4af_tell(ctx);
|
||||
m4af_write(ctx, "\0\0\0\0edts", 8);
|
||||
m4af_write_elst_box(ctx, track_idx);
|
||||
m4af_update_box_size(ctx, pos);
|
||||
}
|
||||
|
||||
static
|
||||
void m4af_write_tkhd_box(m4af_ctx_t *ctx, uint32_t track_idx)
|
||||
{
|
||||
@ -1001,9 +1102,13 @@ void m4af_write_tkhd_box(m4af_ctx_t *ctx, uint32_t track_idx)
|
||||
static
|
||||
void m4af_write_trak_box(m4af_ctx_t *ctx, uint32_t track_idx)
|
||||
{
|
||||
m4af_track_t *track = &ctx->track[track_idx];
|
||||
int64_t pos = m4af_tell(ctx);
|
||||
m4af_write(ctx, "\0\0\0\0trak", 8);
|
||||
m4af_write_tkhd_box(ctx, track_idx);
|
||||
if ((ctx->priming_mode & M4AF_PRIMING_MODE_EDTS) &&
|
||||
(track->encoder_delay || track->padding))
|
||||
m4af_write_edts_box(ctx, track_idx);
|
||||
m4af_write_mdia_box(ctx, track_idx);
|
||||
m4af_update_box_size(ctx, pos);
|
||||
}
|
||||
@ -1213,7 +1318,9 @@ int m4af_finalize(m4af_ctx_t *ctx)
|
||||
}
|
||||
m4af_flush_chunk(ctx, i);
|
||||
}
|
||||
if (ctx->track[0].encoder_delay || ctx->track[0].padding)
|
||||
track = ctx->track;
|
||||
if ((ctx->priming_mode & M4AF_PRIMING_MODE_ITUNSMPB) &&
|
||||
(track->encoder_delay || track->padding))
|
||||
m4af_set_iTunSMPB(ctx);
|
||||
m4af_finalize_mdat(ctx);
|
||||
m4af_write_moov_box(ctx);
|
||||
|
@ -52,6 +52,12 @@ enum m4af_codec_type {
|
||||
M4AF_CODEC_TEXT = M4AF_FOURCC('t','e','x','t'),
|
||||
};
|
||||
|
||||
enum m4af_priming_mode {
|
||||
M4AF_PRIMING_MODE_ITUNSMPB = 1,
|
||||
M4AF_PRIMING_MODE_EDTS = 2,
|
||||
M4AF_PRIMING_MODE_BOTH = 3
|
||||
};
|
||||
|
||||
typedef int (*m4af_read_callback)(void *cookie, void *buffer, uint32_t size);
|
||||
typedef int (*m4af_write_callback)(void *cookie, const void *data,
|
||||
uint32_t size);
|
||||
@ -94,6 +100,8 @@ int m4af_set_decoder_specific_info(m4af_ctx_t *ctx, uint32_t track_idx,
|
||||
void m4af_set_priming(m4af_ctx_t *ctx, uint32_t track_idx,
|
||||
uint32_t encoder_delay, uint32_t padding);
|
||||
|
||||
void m4af_set_priming_mode(m4af_ctx_t *ctx, int mode);
|
||||
|
||||
void m4af_set_fixed_frame_duration(m4af_ctx_t *ctx, uint32_t track_idx,
|
||||
uint32_t length);
|
||||
|
||||
|
18
src/main.c
18
src/main.c
@ -148,6 +148,10 @@ PROGNAME " %s\n"
|
||||
" transport layer\n"
|
||||
"\n"
|
||||
" -o <filename> Output filename\n"
|
||||
" -G, --gapless-mode <n> Encoder delay signaling for gapless playback\n"
|
||||
" 0: iTunSMPB (default)\n"
|
||||
" 1: ISO standard (edts + sgpd)\n"
|
||||
" 2: Both\n"
|
||||
" --ignorelength Ignore length of WAV header\n"
|
||||
" -S, --silent Don't print progress messages\n"
|
||||
"\n"
|
||||
@ -199,6 +203,7 @@ typedef struct aacenc_param_ex_t {
|
||||
|
||||
char *input_filename;
|
||||
char *output_filename;
|
||||
unsigned gapless_mode;
|
||||
unsigned ignore_length;
|
||||
int silent;
|
||||
|
||||
@ -239,6 +244,7 @@ int parse_options(int argc, char **argv, aacenc_param_ex_t *params)
|
||||
{ "adts-crc-check", no_argument, 0, 'C' },
|
||||
{ "header-period", required_argument, 0, 'P' },
|
||||
|
||||
{ "gapless-mode", required_argument, 0, 'G' },
|
||||
{ "ignorelength", no_argument, 0, 'I' },
|
||||
{ "silent", no_argument, 0, 'S' },
|
||||
|
||||
@ -268,7 +274,7 @@ int parse_options(int argc, char **argv, aacenc_param_ex_t *params)
|
||||
params->afterburner = 1;
|
||||
|
||||
aacenc_getmainargs(&argc, &argv);
|
||||
while ((ch = getopt_long(argc, argv, "hp:b:m:w:a:Ls:f:CP:Io:SR",
|
||||
while ((ch = getopt_long(argc, argv, "hp:b:m:w:a:Ls:f:CP:G:Io:SR",
|
||||
long_options, 0)) != EOF) {
|
||||
switch (ch) {
|
||||
case 'h':
|
||||
@ -325,7 +331,7 @@ int parse_options(int argc, char **argv, aacenc_param_ex_t *params)
|
||||
}
|
||||
params->transport_format = n;
|
||||
break;
|
||||
case 'c':
|
||||
case 'C':
|
||||
params->adts_crc_check = 1;
|
||||
break;
|
||||
case 'P':
|
||||
@ -338,6 +344,13 @@ int parse_options(int argc, char **argv, aacenc_param_ex_t *params)
|
||||
case 'o':
|
||||
params->output_filename = optarg;
|
||||
break;
|
||||
case 'G':
|
||||
if (sscanf(optarg, "%u", &n) != 1 || n > 2) {
|
||||
fprintf(stderr, "invalid arg for gapless-mode\n");
|
||||
return -1;
|
||||
}
|
||||
params->gapless_mode = n;
|
||||
break;
|
||||
case 'I':
|
||||
params->ignore_length = 1;
|
||||
break;
|
||||
@ -718,6 +731,7 @@ int main(int argc, char **argv)
|
||||
aacinfo.confSize);
|
||||
m4af_set_fixed_frame_duration(m4af, 0,
|
||||
framelen >> downsampled_timescale);
|
||||
m4af_set_priming_mode(m4af, params.gapless_mode + 1);
|
||||
m4af_begin_write(m4af);
|
||||
}
|
||||
frame_count = encode(wavf, encoder, aacinfo.frameLength, ofp, m4af,
|
||||
|
@ -166,6 +166,28 @@ void tag_put_number_pair(m4af_ctx_t *m4af, uint32_t fcc,
|
||||
}
|
||||
}
|
||||
|
||||
static
|
||||
const char *aacenc_json_object_get_string(JSON_Object *obj, const char *key,
|
||||
char *buf)
|
||||
{
|
||||
JSON_Value_Type type;
|
||||
const char *val = 0;
|
||||
|
||||
type = json_value_get_type(json_object_get_value(obj, key));
|
||||
if (type == JSONString)
|
||||
val = json_object_get_string(obj, key);
|
||||
else if (type == JSONNumber) {
|
||||
double num = json_object_get_number(obj, key);
|
||||
sprintf(buf, "%.15g", num);
|
||||
val = buf;
|
||||
} else if (type == JSONBoolean) {
|
||||
int n = json_object_get_boolean(obj, key);
|
||||
sprintf(buf, "%d", n);
|
||||
val = buf;
|
||||
}
|
||||
return val;
|
||||
}
|
||||
|
||||
void aacenc_put_tags_from_json(m4af_ctx_t *m4af, const char *json_filename)
|
||||
{
|
||||
char *data = 0;
|
||||
@ -202,37 +224,29 @@ void aacenc_put_tags_from_json(m4af_ctx_t *m4af, const char *json_filename)
|
||||
nelts = json_object_get_count(root);
|
||||
for (i = 0; i < nelts; ++i) {
|
||||
char buf[256];
|
||||
const char *key = 0;
|
||||
const char *val = 0;
|
||||
uint32_t fcc = 0;
|
||||
JSON_Value_Type type;
|
||||
|
||||
key = json_object_get_name(root, i);
|
||||
type = json_value_get_type(json_object_get_value(root, key));
|
||||
if (type == JSONString)
|
||||
val = json_object_get_string(root, key);
|
||||
else if (type == JSONNumber) {
|
||||
double num = json_object_get_number(root, key);
|
||||
sprintf(buf, "%g", num);
|
||||
val = buf;
|
||||
} else if (type == JSONBoolean) {
|
||||
int n = json_object_get_boolean(root, key);
|
||||
sprintf(buf, "%d", n);
|
||||
val = buf;
|
||||
}
|
||||
fcc = get_tag_fcc_from_name(key);
|
||||
const char *key = json_object_get_name(root, i);
|
||||
const char *val = aacenc_json_object_get_string(root, key, buf);
|
||||
uint32_t fcc = get_tag_fcc_from_name(key);
|
||||
if (!val || !fcc)
|
||||
continue;
|
||||
|
||||
switch (fcc) {
|
||||
case TAG_TOTAL_DISCS:
|
||||
total_discs = strdup(val); break;
|
||||
total_discs = realloc(total_discs, strlen(val) + 1);
|
||||
strcpy(total_discs, val);
|
||||
break;
|
||||
case TAG_TOTAL_TRACKS:
|
||||
total_tracks = strdup(val); break;
|
||||
total_tracks = realloc(total_tracks, strlen(val) + 1);
|
||||
strcpy(total_tracks, val);
|
||||
break;
|
||||
case M4AF_TAG_DISK:
|
||||
disc = strdup(val); break;
|
||||
disc = realloc(disc, strlen(val) + 1);
|
||||
strcpy(disc, val);
|
||||
break;
|
||||
case M4AF_TAG_TRACK:
|
||||
track = strdup(val); break;
|
||||
track = realloc(track, strlen(val) + 1);
|
||||
strcpy(track, val);
|
||||
break;
|
||||
default:
|
||||
{
|
||||
entry.tag = fcc;
|
||||
|
Reference in New Issue
Block a user