Mercurial > pt1.oyama
diff libdlna-0.2.3/src/audio_aac.c @ 129:4f6d9621ee00
add multi session streaming & add depending librarys.
- libupnp-1.6.6
- libdlna-0.2.3
author | Naoya OYAMA <naoya.oyama@gmail.com> |
---|---|
date | Sun, 10 Oct 2010 15:33:18 +0900 |
parents | |
children |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libdlna-0.2.3/src/audio_aac.c Sun Oct 10 15:33:18 2010 +0900 @@ -0,0 +1,567 @@ +/* + * libdlna: reference DLNA standards implementation. + * Copyright (C) 2007 Benjamin Zores <ben@geexbox.org> + * + * This file is part of libdlna. + * + * libdlna is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * libdlna is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with libdlna; if not, write to the Free Software + * Foundation, Inc, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> + +#include "dlna_internals.h" +#include "profiles.h" +#include "containers.h" + +/* Profile for audio media class content */ +static dlna_profile_t aac_adts = { + .id = "AAC_ADTS", + .mime = MIME_AUDIO_ADTS, + .label = LABEL_AUDIO_2CH +}; + +/* Profile for audio media class content */ +static dlna_profile_t aac_adts_320 = { + .id = "AAC_ADTS_320", + .mime = MIME_AUDIO_ADTS, + .label = LABEL_AUDIO_2CH +}; + +/* Profile for audio media class content */ +static dlna_profile_t aac_iso = { + .id = "AAC_ISO", + .mime = MIME_AUDIO_MPEG_4, + .label = LABEL_AUDIO_2CH +}; + +/* Profile for audio media class content */ +static dlna_profile_t aac_iso_320 = { + .id = "AAC_ISO_320", + .mime = MIME_AUDIO_MPEG_4, + .label = LABEL_AUDIO_2CH +}; + +/* Profile for audio media class content. In the case of AAC LTP profiles, + both the ISO file formats and the ADTS format are supported by + the same profile. */ +static dlna_profile_t aac_ltp_iso = { + .id = "AAC_LTP_ISO", + .mime = MIME_AUDIO_MPEG_4, + .label = LABEL_AUDIO_2CH +}; + +/* Profile for audio media class content with up to 5.1 channels */ +static dlna_profile_t aac_ltp_mult5_iso = { + .id = "AAC_LTP_MULT5_ISO", + .mime = MIME_AUDIO_MPEG_4, + .label = LABEL_AUDIO_MULTI +}; + +/* Profile for audio media class content with up to 7.1 channels */ +static dlna_profile_t aac_ltp_mult7_iso = { + .id = "AAC_LTP_MULT7_ISO", + .mime = MIME_AUDIO_MPEG_4, + .label = LABEL_AUDIO_MULTI +}; + +/* Profile for audio media class content with up to 5.1 channels */ +static dlna_profile_t aac_mult5_adts = { + .id = "AAC_MULT5_ADTS", + .mime = MIME_AUDIO_ADTS, + .label = LABEL_AUDIO_MULTI +}; + +/* Profile for audio media class content with up to 5.1 channels */ +static dlna_profile_t aac_mult5_iso = { + .id = "AAC_MULT5_ISO", + .mime = MIME_AUDIO_MPEG_4, + .label = LABEL_AUDIO_MULTI +}; + +/* Profile for audio media class content */ +static dlna_profile_t heaac_l2_adts = { + .id = "HEAAC_L2_ADTS", + .mime = MIME_AUDIO_ADTS, + .label = LABEL_AUDIO_2CH +}; + +/* Profile for audio media class content */ +static dlna_profile_t heaac_l2_iso = { + .id = "HEAAC_L2_ISO", + .mime = MIME_AUDIO_MPEG_4, + .label = LABEL_AUDIO_2CH +}; + +/* Profile for audio media class content */ +static dlna_profile_t heaac_l3_adts = { + .id = "HEAAC_L3_ADTS", + .mime = MIME_AUDIO_ADTS, + .label = LABEL_AUDIO_2CH +}; + +/* Profile for audio media class content */ +static dlna_profile_t heaac_l3_iso = { + .id = "HEAAC_L3_ISO", + .mime = MIME_AUDIO_MPEG_4, + .label = LABEL_AUDIO_2CH +}; + +/* Profile for audio media class content with up to 5.1 channels */ +static dlna_profile_t heaac_mult5_adts = { + .id = "HEAAC_MULT5_ADTS", + .mime = MIME_AUDIO_ADTS, + .label = LABEL_AUDIO_MULTI +}; + +/* Profile for audio media class content with up to 5.1 channels */ +static dlna_profile_t heaac_mult5_iso = { + .id = "HEAAC_MULT5_ISO", + .mime = MIME_AUDIO_MPEG_4, + .label = LABEL_AUDIO_MULTI +}; + +/* Profile for audio media class content */ +static dlna_profile_t heaac_l2_adts_320 = { + .id = "HEAAC_L2_ADTS_320", + .mime = MIME_AUDIO_ADTS, + .label = LABEL_AUDIO_2CH +}; + +/* Profile for audio media class content */ +static dlna_profile_t heaac_l2_iso_320 = { + .id = "HEAAC_L2_ISO_320", + .mime = MIME_AUDIO_MPEG_4, + .label = LABEL_AUDIO_2CH +}; + +/* Profile for audio media class content */ +static dlna_profile_t bsac_iso = { + .id = "BSAC_ISO", + .mime = MIME_AUDIO_MPEG_4, + .label = LABEL_AUDIO_2CH +}; + +/* Profile for audio media class content with up to 5.1 channels */ +static dlna_profile_t bsac_mult5_iso = { + .id = "BSAC_MULT5_ISO", + .mime = MIME_AUDIO_MPEG_4, + .label = LABEL_AUDIO_MULTI +}; + +static dlna_profile_t heaac_v2_l2 = { + .id = "HEAACv2_L2", + .mime = MIME_AUDIO_MPEG_4, + .label = LABEL_AUDIO_2CH +}; + +static dlna_profile_t heaac_v2_l2_adts = { + .id = "HEAACv2_L2", + .mime = MIME_AUDIO_ADTS, + .label = LABEL_AUDIO_2CH +}; + +static dlna_profile_t heaac_v2_l2_320 = { + .id = "HEAACv2_L2_320", + .mime = MIME_AUDIO_MPEG_4, + .label = LABEL_AUDIO_2CH +}; + +static dlna_profile_t heaac_v2_l2_320_adts = { + .id = "HEAACv2_L2_320", + .mime = MIME_AUDIO_ADTS, + .label = LABEL_AUDIO_2CH +}; + +static dlna_profile_t heaac_v2_l3 = { + .id = "HEAACv2_L3", + .mime = MIME_AUDIO_MPEG_4, + .label = LABEL_AUDIO_2CH +}; + +static dlna_profile_t heaac_v2_l3_adts = { + .id = "HEAACv2_L3", + .mime = MIME_AUDIO_ADTS, + .label = LABEL_AUDIO_2CH +}; + +static dlna_profile_t heaac_v2_mult5 = { + .id = "HEAACv2_MULT5", + .mime = MIME_AUDIO_MPEG_4, + .label = LABEL_AUDIO_2CH +}; + +static dlna_profile_t heaac_v2_mult5_adts = { + .id = "HEAACv2_MULT5", + .mime = MIME_AUDIO_ADTS, + .label = LABEL_AUDIO_2CH +}; + +typedef enum { + AAC_MUXED, /* AAC is muxed in a container */ + AAC_RAW /* AAC is raw (ADTS) */ +} aac_container_type_t; + +/* HeAACv1 (a.k.a. AACplus v1) is AAC LC + Spectral Band Replication (SBR) */ +/* HeAACv2 (a.ka.a AACplus v2) is HeAACv1 + Parametric Stereo (PS) */ + +typedef enum { + AAC_INVALID = 0, + AAC_MAIN = 1, /* AAC Main */ + AAC_LC = 2, /* AAC Low complexity */ + AAC_SSR = 3, /* AAC SSR */ + AAC_LTP = 4, /* AAC Long term prediction */ + AAC_HE = 5, /* AAC High efficiency (SBR) */ + AAC_SCALE = 6, /* Scalable */ + AAC_TWINVQ = 7, /* TwinVQ */ + AAC_CELP = 8, /* CELP */ + AAC_HVXC = 9, /* HVXC */ + AAC_TTSI = 12, /* TTSI */ + AAC_MS = 13, /* Main synthetic */ + AAC_WAVE = 14, /* Wavetable synthesis */ + AAC_MIDI = 15, /* General MIDI */ + AAC_FX = 16, /* Algorithmic Synthesis and Audio FX */ + AAC_LC_ER = 17, /* AAC Low complexity with error recovery */ + AAC_LTP_ER = 19, /* AAC Long term prediction with error recovery */ + AAC_SCALE_ER = 20, /* AAC scalable with error recovery */ + AAC_TWINVQ_ER = 21, /* TwinVQ with error recovery */ + AAC_BSAC_ER = 22, /* BSAC with error recovery */ + AAC_LD_ER = 23, /* AAC LD with error recovery */ + AAC_CELP_ER = 24, /* CELP with error recovery */ + AAC_HXVC_ER = 25, /* HXVC with error recovery */ + AAC_HILN_ER = 26, /* HILN with error recovery */ + AAC_PARAM_ER = 27, /* Parametric with error recovery */ + AAC_SSC = 28, /* AAC SSC */ + AAC_HE_L3 = 31, /* Reserved : seems to be HeAAC L3 */ +} aac_object_type_t; + +static const struct { + dlna_profile_t *profile; + aac_container_type_t ct; + audio_profile_t ap; +} aac_profiles_mapping[] = { + { &aac_adts, AAC_RAW, AUDIO_PROFILE_AAC }, + { &aac_adts_320, AAC_RAW, AUDIO_PROFILE_AAC_320 }, + { &aac_iso, AAC_MUXED, AUDIO_PROFILE_AAC }, + { &aac_iso_320, AAC_MUXED, AUDIO_PROFILE_AAC_320 }, + { &aac_ltp_iso, AAC_MUXED, AUDIO_PROFILE_AAC_LTP }, + { &aac_ltp_mult5_iso, AAC_MUXED, AUDIO_PROFILE_AAC_LTP_MULT5 }, + { &aac_ltp_mult7_iso, AAC_MUXED, AUDIO_PROFILE_AAC_LTP_MULT7 }, + { &aac_mult5_adts, AAC_RAW, AUDIO_PROFILE_AAC_MULT5 }, + { &aac_mult5_iso, AAC_MUXED, AUDIO_PROFILE_AAC_MULT5 }, + { &heaac_l2_adts, AAC_RAW, AUDIO_PROFILE_AAC_HE_L2 }, + { &heaac_l2_iso, AAC_MUXED, AUDIO_PROFILE_AAC_HE_L2 }, + { &heaac_l3_adts, AAC_RAW, AUDIO_PROFILE_AAC_HE_L3 }, + { &heaac_l3_iso, AAC_MUXED, AUDIO_PROFILE_AAC_HE_L3 }, + { &heaac_mult5_adts, AAC_RAW, AUDIO_PROFILE_AAC_HE_MULT5 }, + { &heaac_mult5_iso, AAC_MUXED, AUDIO_PROFILE_AAC_HE_MULT5 }, + { &heaac_l2_adts_320, AAC_RAW, AUDIO_PROFILE_AAC_HE_L2_320 }, + { &heaac_l2_iso_320, AAC_MUXED, AUDIO_PROFILE_AAC_HE_L2_320 }, + { &heaac_v2_l2, AAC_MUXED, AUDIO_PROFILE_AAC_HE_V2_L2 }, + { &heaac_v2_l2_adts, AAC_RAW, AUDIO_PROFILE_AAC_HE_V2_L2 }, + { &heaac_v2_l2_320, AAC_MUXED, AUDIO_PROFILE_AAC_HE_V2_L2_320 }, + { &heaac_v2_l2_320_adts, AAC_RAW, AUDIO_PROFILE_AAC_HE_V2_L2_320 }, + { &heaac_v2_l3, AAC_MUXED, AUDIO_PROFILE_AAC_HE_V2_L3 }, + { &heaac_v2_l3_adts, AAC_RAW, AUDIO_PROFILE_AAC_HE_V2_L3 }, + { &heaac_v2_mult5, AAC_MUXED, AUDIO_PROFILE_AAC_HE_V2_MULT5 }, + { &heaac_v2_mult5_adts, AAC_RAW, AUDIO_PROFILE_AAC_HE_V2_MULT5 }, + { &bsac_iso, AAC_MUXED, AUDIO_PROFILE_AAC_BSAC }, + { &bsac_mult5_iso, AAC_MUXED, AUDIO_PROFILE_AAC_BSAC_MULT5 }, + { NULL, 0, 0 } +}; + +static aac_object_type_t +aac_object_type_get (uint8_t *data, int len) +{ + uint8_t t = AAC_INVALID; + + if (!data || len < 1) + goto aac_object_type_error; + + t = data[0] >> 3; /* Get 5 first bits */ + + aac_object_type_error: +#ifdef HAVE_DEBUG + fprintf (stderr, "AAC Object Type: %d\n", t); +#endif /* HAVE_DEBUG */ + + return t; +} + +static audio_profile_t +audio_profile_guess_aac_priv (AVCodecContext *ac, aac_object_type_t type) +{ + if (!ac) + return AUDIO_PROFILE_INVALID; + + /* check for AAC variants codec */ + if (ac->codec_id != CODEC_ID_AAC) + return AUDIO_PROFILE_INVALID; + + switch (type) + { + /* AAC Low Complexity variants */ + case AAC_LC: + case AAC_LC_ER: + { + if (ac->sample_rate < 8000 || ac->sample_rate > 48000) + break; + + if (ac->channels <= 2) /* AAC @ Level 1/2 */ + { + if (ac->bit_rate <= 320000) + return AUDIO_PROFILE_AAC_320; + + if (ac->bit_rate <= 576000) + return AUDIO_PROFILE_AAC; + + break; + } + else if (ac->channels <= 6) + { + if (ac->bit_rate <= 1440000) + return AUDIO_PROFILE_AAC_MULT5; + + break; + } + break; + } + + /* AAC Long Term Prediction variants */ + case AAC_LTP: + case AAC_LTP_ER: + { + if (ac->sample_rate < 8000) + break; + + if (ac->sample_rate <= 48000) + { + if (ac->channels <= 2 && ac->bit_rate <= 576000) + return AUDIO_PROFILE_AAC_LTP; + + break; + } + else if (ac->sample_rate <= 96000) + { + if (ac->channels <= 6 && ac->bit_rate <= 2880000) + return AUDIO_PROFILE_AAC_LTP_MULT5; + + if (ac->channels <= 8 && ac->bit_rate <= 4032000) + return AUDIO_PROFILE_AAC_LTP_MULT7; + + break; + } + + break; + } + + /* AAC High efficiency (with SBR) variants */ + case AAC_HE: + case AAC_HE_L3: + { + if (ac->sample_rate < 8000) + break; + + if (ac->sample_rate <= 24000) /* HE-AAC @ Level 2 */ + { + if (ac->channels > 2) + break; + + if (ac->bit_rate <= 320000) + return AUDIO_PROFILE_AAC_HE_L2_320; + + if (ac->bit_rate <= 576000) + return AUDIO_PROFILE_AAC_HE_L2; + + break; + } + else if (ac->sample_rate <= 48000) + { + /* HE-AAC @ Level 3 */ + if (ac->channels <= 2 && ac->bit_rate <= 576000) + return AUDIO_PROFILE_AAC_HE_L3; + + /* HE-AAC @ Level 4/5 */ + if (ac->channels <= 6 && ac->bit_rate <= 1440000) + return AUDIO_PROFILE_AAC_HE_MULT5; + + break; + } + + break; + } + + /* AAC High efficiency v2 (with PS) variants */ + case AAC_PARAM_ER: + { + if (ac->sample_rate < 8000) + break; + + if (ac->sample_rate <= 24000) /* HE-AAC @ Level 2 */ + { + if (ac->channels > 2) + break; + + if (ac->bit_rate <= 320000) + return AUDIO_PROFILE_AAC_HE_V2_L2_320; + + if (ac->bit_rate <= 576000) + return AUDIO_PROFILE_AAC_HE_V2_L2; + + break; + } + else if (ac->sample_rate <= 48000) + { + /* HE-AAC @ Level 3 */ + if (ac->channels <= 2 && ac->bit_rate <= 576000) + return AUDIO_PROFILE_AAC_HE_V2_L3; + + /* HE-AAC @ Level 4/5 */ + if (ac->channels <= 6 && ac->bit_rate <= 2880000) + return AUDIO_PROFILE_AAC_HE_V2_MULT5; + + break; + } + + break; + } + + case AAC_BSAC_ER: + { + if (ac->sample_rate < 16000 || ac->sample_rate > 48000) + break; + + if (ac->bit_rate > 128000) + break; + + if (ac->channels <= 2) + return AUDIO_PROFILE_AAC_BSAC; + else if (ac->channels <= 6) + return AUDIO_PROFILE_AAC_BSAC_MULT5; + + break; + } + + default: + break; + } + + return AUDIO_PROFILE_INVALID; +} + +audio_profile_t +audio_profile_guess_aac (AVCodecContext *ac) +{ + aac_object_type_t type; + + if (!ac) + return AUDIO_PROFILE_INVALID; + + type = aac_object_type_get (ac->extradata, ac->extradata_size); + return audio_profile_guess_aac_priv (ac, type); +} + +static aac_object_type_t +aac_adts_object_type_get (AVFormatContext *ctx) +{ + int fd; + unsigned char buf[4]; + uint8_t t = AAC_INVALID; + + if (!ctx) + return t; + + fd = open (ctx->filename, O_RDONLY); + read (fd, buf, sizeof (buf) - 1); + t = (buf[2] & 0xC0) >> 6; + close (fd); + +#ifdef HAVE_DEBUG + fprintf (stderr, "AAC Object Type: %d\n", t); +#endif /* HAVE_DEBUG */ + + return t; +} + +static aac_container_type_t +aac_get_format (AVFormatContext *ctx) +{ + int fd; + unsigned char buf[4]; + aac_container_type_t ct = AAC_MUXED; + + if (!ctx) + return ct; + + fd = open (ctx->filename, O_RDONLY); + read (fd, buf, sizeof (buf) - 1); + if ((buf[0] == 0xFF) && ((buf[1] & 0xF6) == 0xF0)) + { + ct = AAC_RAW; +#ifdef HAVE_DEBUG + fprintf (stderr, "AAC has an ADTS header\n"); +#endif /* HAVE_DEBUG */ + } + close (fd); + + return ct; +} + +static dlna_profile_t * +probe_mpeg4 (AVFormatContext *ctx, + dlna_container_type_t st, + av_codecs_t *codecs) +{ + audio_profile_t ap; + aac_container_type_t ct = AAC_MUXED; + int i; + + if (!stream_ctx_is_audio (codecs)) + return NULL; + + /* check for ADTS */ + if (st == CT_AAC) + { + aac_object_type_t ot; + ct = aac_get_format (ctx); + ot = aac_adts_object_type_get (ctx); + ap = audio_profile_guess_aac_priv (codecs->ac, ot); + } + else + ap = audio_profile_guess_aac (codecs->ac); + + if (ap == AUDIO_PROFILE_INVALID) + return NULL; + + /* find profile according to container type and audio profiles */ + for (i = 0; aac_profiles_mapping[i].profile; i++) + if (aac_profiles_mapping[i].ct == ct && + aac_profiles_mapping[i].ap == ap) + return aac_profiles_mapping[i].profile; + + return NULL; +} + +dlna_registered_profile_t dlna_profile_audio_mpeg4 = { + .id = DLNA_PROFILE_AUDIO_MPEG4, + .class = DLNA_CLASS_AUDIO, + .extensions = "aac,adts,3gp,mp4,mov,qt,m4a", + .probe = probe_mpeg4, + .next = NULL +};