Example #1
0
static
int caf_read_frames(pcm_reader_t *preader, void *buffer, unsigned nframes)
{
    int rc;
    unsigned i, j, nbytes;
    caf_reader_t *reader = (caf_reader_t *)preader;
    unsigned bpf = reader->sample_format.bytes_per_frame;
    unsigned nchannels = reader->sample_format.channels_per_frame;
    unsigned bpc = bpf / nchannels;
    uint8_t tmp[64]; /* enough room for maximum bpf: 8ch float64 */
    uint8_t *bp;
    uint8_t *chanmap = reader->chanmap;

    if (nframes > reader->length - reader->position)
        nframes = reader->length - reader->position;
    nbytes = nframes * bpf;
    if (nbytes) {
        if ((rc = pcm_read(&reader->io, buffer, nbytes)) < 0)
            return -1;
        nframes = rc / bpf;
        for (bp = buffer, i = 0; i < nframes; ++i, bp += bpf) {
            memcpy(tmp, bp, bpf);
            for (j = 0; j < nchannels; ++j)
                memcpy(bp + bpc * j, tmp + bpc * chanmap[j], bpc);
        }
        reader->position += nframes;
    }
    if (nframes == 0) {
        /* fetch info after data chunk */
        uint32_t fcc;
        int64_t chunk_size;
        while ((fcc = caf_next_chunk(reader, &chunk_size)) != 0) {
            if (fcc == M4AF_FOURCC('i','n','f','o'))
                TRY_IO(caf_info(reader, chunk_size));
            else
                TRY_IO(pcm_skip(&reader->io, chunk_size));
        }
    }
    return nframes;
FAIL:
    return 0;
}
Example #2
0
static
int caf_desc(caf_reader_t *reader, int64_t chunk_size)
{
    double mSampleRate;
    uint32_t mFormatID, mFormatFlags, mBytesPerPacket, mFramesPerPacket,
             mChannelsPerFrame, mBitsPerChannel;
    pcm_sample_description_t *desc = &reader->sample_format;

    ENSURE(chunk_size >= 32);
    TRY_IO(pcm_scanb(&reader->io, "QLLLLLL", &mSampleRate, &mFormatID,
                     &mFormatFlags, &mBytesPerPacket, &mFramesPerPacket,
                     &mChannelsPerFrame, &mBitsPerChannel) != 7);

    ENSURE(mFormatID == M4AF_FOURCC('l','p','c','m'));
    ENSURE(mSampleRate && mBytesPerPacket &&
           mChannelsPerFrame >= 1 && mChannelsPerFrame <= 8 &&
           mBitsPerChannel && mFramesPerPacket == 1 &&
           mBytesPerPacket % mChannelsPerFrame == 0 &&
           mBytesPerPacket >= mChannelsPerFrame * ((mBitsPerChannel + 7) / 8));

    desc->sample_rate        = mSampleRate;
    desc->bits_per_channel   = mBitsPerChannel;
    desc->bytes_per_frame    = mBytesPerPacket;
    desc->channels_per_frame = mChannelsPerFrame;

    switch (mFormatFlags) {
    case 0: desc->sample_type = PCM_TYPE_SINT_BE;  break;
    case 1: desc->sample_type = PCM_TYPE_FLOAT_BE; break;
    case 2: desc->sample_type = PCM_TYPE_SINT;     break;
    case 3: desc->sample_type = PCM_TYPE_FLOAT;    break;
    default: goto FAIL;
    }

    TRY_IO(pcm_skip(&reader->io, chunk_size - 32));
    return 0;
FAIL:
    return -1;
}
Example #3
0
static
int caf_parse(caf_reader_t *reader, int64_t *data_length)
{
    uint32_t fcc;
    int64_t chunk_size;

    *data_length = 0;

    /* CAFFileHeader */
    TRY_IO(pcm_read32be(&reader->io, &fcc));
    ENSURE(fcc == M4AF_FOURCC('c','a','f','f'));
    TRY_IO(pcm_skip(&reader->io, 4)); /* mFileVersion, mFileFlags */

    while ((fcc = caf_next_chunk(reader, &chunk_size)) != 0) {
        if (fcc == M4AF_FOURCC('d','e','s','c'))
            TRY_IO(caf_desc(reader, chunk_size));
        else if (fcc == M4AF_FOURCC('i','n','f','o'))
            TRY_IO(caf_info(reader, chunk_size));
        else if (fcc == M4AF_FOURCC('c','h','a','n')) {
            ENSURE(reader->sample_format.channels_per_frame);
            if (apple_chan_chunk(&reader->io, chunk_size,
                                 &reader->sample_format, reader->chanmap) < 0)
                goto FAIL;
        } else if (fcc == M4AF_FOURCC('d','a','t','a')) {
            TRY_IO(pcm_skip(&reader->io, 4)); /* mEditCount */
            *data_length = (chunk_size == ~0ULL) ? chunk_size : chunk_size - 4;
            reader->data_offset = pcm_tell(&reader->io);
            break;
        } else
            TRY_IO(pcm_skip(&reader->io, chunk_size));
    }
    ENSURE(reader->sample_format.channels_per_frame);
    ENSURE(fcc == M4AF_FOURCC('d','a','t','a'));
    return 0;
FAIL:
    return -1;
}
Example #4
0
static
int parse_options(int argc, char **argv, aacenc_param_ex_t *params)
{
    int ch;
    int n;

#define OPT_INCLUDE_SBR_DELAY    M4AF_FOURCC('s','d','l','y')
#define OPT_MOOV_BEFORE_MDAT     M4AF_FOURCC('m','o','o','v')
#define OPT_RAW_CHANNELS         M4AF_FOURCC('r','c','h','n')
#define OPT_RAW_RATE             M4AF_FOURCC('r','r','a','t')
#define OPT_RAW_FORMAT           M4AF_FOURCC('r','f','m','t')
#define OPT_SHORT_TAG            M4AF_FOURCC('s','t','a','g')
#define OPT_SHORT_TAG_FILE       M4AF_FOURCC('s','t','g','f')
#define OPT_LONG_TAG             M4AF_FOURCC('l','t','a','g')
#define OPT_TAG_FROM_JSON        M4AF_FOURCC('t','f','j','s')

    static struct option long_options[] = {
        { "help",             no_argument,       0, 'h' },
        { "profile",          required_argument, 0, 'p' },
        { "bitrate",          required_argument, 0, 'b' },
        { "bitrate-mode",     required_argument, 0, 'm' },
        { "bandwidth",        required_argument, 0, 'w' },
        { "afterburner",      required_argument, 0, 'a' },
        { "lowdelay-sbr",     required_argument, 0, 'L' },
        { "sbr-ratio",        required_argument, 0, 's' },
        { "transport-format", required_argument, 0, 'f' },
        { "adts-crc-check",   no_argument,       0, 'C' },
        { "header-period",    required_argument, 0, 'P' },

        { "gapless-mode",     required_argument, 0, 'G' },
        { "include-sbr-delay", no_argument,      0, OPT_INCLUDE_SBR_DELAY  },
        { "ignorelength",     no_argument,       0, 'I' },
        { "silent",           no_argument,       0, 'S' },
        { "moov-before-mdat", no_argument,       0, OPT_MOOV_BEFORE_MDAT   },

        { "raw",              no_argument,       0, 'R' },
        { "raw-channels",     required_argument, 0, OPT_RAW_CHANNELS       },
        { "raw-rate",         required_argument, 0, OPT_RAW_RATE           },
        { "raw-format",       required_argument, 0, OPT_RAW_FORMAT         },

        { "title",            required_argument, 0, M4AF_TAG_TITLE         },
        { "artist",           required_argument, 0, M4AF_TAG_ARTIST        },
        { "album",            required_argument, 0, M4AF_TAG_ALBUM         },
        { "genre",            required_argument, 0, M4AF_TAG_GENRE         },
        { "date",             required_argument, 0, M4AF_TAG_DATE          },
        { "composer",         required_argument, 0, M4AF_TAG_COMPOSER      },
        { "grouping",         required_argument, 0, M4AF_TAG_GROUPING      },
        { "comment",          required_argument, 0, M4AF_TAG_COMMENT       },
        { "album-artist",     required_argument, 0, M4AF_TAG_ALBUM_ARTIST  },
        { "track",            required_argument, 0, M4AF_TAG_TRACK         },
        { "disk",             required_argument, 0, M4AF_TAG_DISK          },
        { "tempo",            required_argument, 0, M4AF_TAG_TEMPO         },
        { "tag",              required_argument, 0, OPT_SHORT_TAG          },
        { "tag-from-file",    required_argument, 0, OPT_SHORT_TAG_FILE     },
        { "long-tag",         required_argument, 0, OPT_LONG_TAG           },
        { "tag-from-json",    required_argument, 0, OPT_TAG_FROM_JSON      },
        { 0,                  0,                 0, 0                      },
    };
    params->afterburner = 1;

    aacenc_getmainargs(&argc, &argv);
    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':
            return usage(), -1;
        case 'p':
            if (sscanf(optarg, "%u", &n) != 1) {
                fprintf(stderr, "invalid arg for profile\n");
                return -1;
            }
            params->profile = n;
            break;
        case 'b':
            if (sscanf(optarg, "%u", &n) != 1) {
                fprintf(stderr, "invalid arg for bitrate\n");
                return -1;
            }
            params->bitrate = n;
            break;
        case 'm':
            if (sscanf(optarg, "%u", &n) != 1 || n > 5) {
                fprintf(stderr, "invalid arg for bitrate-mode\n");
                return -1;
            }
            params->bitrate_mode = n;
            break;
        case 'w':
            if (sscanf(optarg, "%u", &n) != 1) {
                fprintf(stderr, "invalid arg for bandwidth\n");
                return -1;
            }
            params->bandwidth = n;
            break;
        case 'a':
            if (sscanf(optarg, "%u", &n) != 1 || n > 1) {
                fprintf(stderr, "invalid arg for afterburner\n");
                return -1;
            }
            params->afterburner = n;
            break;
        case 'L':
            if (sscanf(optarg, "%d", &n) != 1 || n < -1 || n > 1) {
                fprintf(stderr, "invalid arg for lowdelay-sbr\n");
                return -1;
            }
            params->lowdelay_sbr = n;
            break;
        case 's':
            if (sscanf(optarg, "%u", &n) != 1 || n > 2) {
                fprintf(stderr, "invalid arg for sbr-ratio\n");
                return -1;
            }
            params->sbr_ratio = n;
            break;
        case 'f':
            if (sscanf(optarg, "%u", &n) != 1) {
                fprintf(stderr, "invalid arg for transport-format\n");
                return -1;
            }
            params->transport_format = n;
            break;
        case 'C':
            params->adts_crc_check = 1;
            break;
        case 'P':
            if (sscanf(optarg, "%u", &n) != 1) {
                fprintf(stderr, "invalid arg for header-period\n");
                return -1;
            }
            params->header_period = n;
            break;
        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 OPT_INCLUDE_SBR_DELAY:
            params->include_sbr_delay = 1;
            break;
        case 'I':
            params->ignore_length = 1;
            break;
        case 'S':
            params->silent = 1;
            break;
        case OPT_MOOV_BEFORE_MDAT:
            params->moov_before_mdat = 1;
            break;
        case 'R':
            params->is_raw = 1;
            break;
        case OPT_RAW_CHANNELS:
            if (sscanf(optarg, "%u", &n) != 1) {
                fprintf(stderr, "invalid arg for raw-channels\n");
                return -1;
            }
            params->raw_channels = n;
            break;
        case OPT_RAW_RATE:
            if (sscanf(optarg, "%u", &n) != 1) {
                fprintf(stderr, "invalid arg for raw-rate\n");
                return -1;
            }
            params->raw_rate = n;
            break;
        case OPT_RAW_FORMAT:
            params->raw_format = optarg;
            break;
        case M4AF_TAG_TITLE:
        case M4AF_TAG_ARTIST:
        case M4AF_TAG_ALBUM:
        case M4AF_TAG_GENRE:
        case M4AF_TAG_DATE:
        case M4AF_TAG_COMPOSER:
        case M4AF_TAG_GROUPING:
        case M4AF_TAG_COMMENT:
        case M4AF_TAG_ALBUM_ARTIST:
        case M4AF_TAG_TRACK:
        case M4AF_TAG_DISK:
        case M4AF_TAG_TEMPO:
            aacenc_add_tag_to_store(&params->tags, ch, 0, optarg,
                                    strlen(optarg), 0);
            break;
        case OPT_SHORT_TAG:
        case OPT_SHORT_TAG_FILE:
        case OPT_LONG_TAG:
            {
                char *val;
                size_t klen;
                unsigned fcc = M4AF_FOURCC('-','-','-','-');

                if ((val = strchr(optarg, ':')) == 0) {
                    fprintf(stderr, "invalid arg for tag\n");
                    return -1;
                }
                *val++ = '\0';
                if (ch == OPT_SHORT_TAG || ch == OPT_SHORT_TAG_FILE) {
                    /*
                     * take care of U+00A9(COPYRIGHT SIGN).
                     * 1) if length of fcc is 3, we prepend '\xa9'.
                     * 2) U+00A9 becomes "\xc2\xa9" in UTF-8. Therefore
                     *    we remove first '\xc2'.
                     */
                    if (optarg[0] == '\xc2')
                        ++optarg;
                    if ((klen = strlen(optarg))== 3)
                        fcc = 0xa9;
                    else if (klen != 4) {
                        fprintf(stderr, "invalid arg for tag\n");
                        return -1;
                    }
                    for (; *optarg; ++optarg)
                        fcc = ((fcc << 8) | (*optarg & 0xff));
                }
                aacenc_add_tag_to_store(&params->tags, fcc, optarg,
                                        val, strlen(val),
                                        ch == OPT_SHORT_TAG_FILE);
            }
            break;
        case OPT_TAG_FROM_JSON:
            params->json_filename = optarg;
            break;
        default:
            return usage(), -1;
        }
    }
    if (argc == optind)
        return usage(), -1;

    if (!params->bitrate && !params->bitrate_mode) {
        fprintf(stderr, "bitrate or bitrate-mode is mandatory\n");
        return -1;
    }
    if (params->output_filename && !strcmp(params->output_filename, "-") &&
        !params->transport_format) {
        fprintf(stderr, "stdout streaming is not available on M4A output\n");
        return -1;
    }
    if (params->bitrate && params->bitrate < 10000)
        params->bitrate *= 1000;

    if (params->is_raw) {
        if (!params->raw_channels)
            params->raw_channels = 2;
        if (!params->raw_rate)
            params->raw_rate = 44100;
        if (!params->raw_format)
            params->raw_format = "S16L";
    }
    params->input_filename = argv[optind];
    return 0;
};