This source file includes following definitions.
- AAC_RegisterMimeTypes
- AAC_CanHandleURL
- AAC_GetESD
- AAC_SetupObject
- ADTS_SyncFrame
- AAC_ConfigureFromFile
- AAC_RegulateDataRate
- AAC_OnLiveData
- AAC_disconnect_from_http_and_free
- AAC_NetIO
- aac_download_file
- AAC_Reader_del
- AAC_Reader_new
- aac_is_local
- AAC_ConnectService
- AAC_CloseService
- AAC_GetServiceDesc
- AAC_ConnectChannel
- AAC_DisconnectChannel
- AAC_ServiceCommand
- AAC_ChannelGetSLP
- AAC_ChannelReleaseSLP
- AAC_Load
- AAC_Delete
- QueryInterfaces
- LoadInterface
- ShutdownInterface
#ifndef DONT_USE_TERMINAL_MODULE_API
#include <gpac/modules/service.h>
#endif
#include <gpac/modules/codec.h>
#include <gpac/avparse.h>
#include <gpac/constants.h>
#include <gpac/download.h>
#include <time.h>
#ifndef GPAC_DISABLE_AV_PARSERS
typedef struct
{
#ifndef DONT_USE_TERMINAL_MODULE_API
GF_ClientService *service;
GF_InputService *input;
LPNETCHANNEL ch;
#endif
Bool is_remote;
FILE *stream;
u32 duration;
Bool needs_connection;
u32 pad_bytes;
Bool done;
u32 is_inline;
char *data;
u32 data_size;
GF_SLHeader sl_hdr;
u32 sample_rate, oti, sr_idx, nb_ch, prof;
Double start_range, end_range;
u32 current_time, nb_samp;
GF_DownloadSession *dnload;
#ifdef DONT_USE_TERMINAL_MODULE_API
GF_DownloadManager *dm;
#endif
Bool is_live;
char prev_data[1000];
u32 prev_size;
char *icy_name;
char *icy_genre;
char *icy_track_name;
Bool hybrid_on;
u64 prev_map_time;
} AACReader;
typedef struct
{
Bool is_mp2, no_crc;
u32 profile, sr_idx, nb_ch, frame_size, hdr_size;
} ADTSHeader;
#ifndef DONT_USE_TERMINAL_MODULE_API
static const char * AAC_MIMES[] = { "audio/x-m4a", "audio/aac", "audio/aacp", "audio/x-aac", 0 };
static const char * AAC_EXTENSIONS = "aac mp4a";
static const char * AAC_DESC = "MPEG-4 AAC Music";
static u32 AAC_RegisterMimeTypes(const GF_InputService *plug) {
int i;
if (!plug)
return 0;
for (i = 0 ; AAC_MIMES[i] ; i++)
gf_service_register_mime( plug, AAC_MIMES[i], AAC_EXTENSIONS, AAC_DESC);
return i;
}
static Bool AAC_CanHandleURL(GF_InputService *plug, const char *url)
{
char *sExt;
if (!plug || !url)
return GF_FALSE;
sExt = strrchr(url, '.');
if (!strnicmp(url, "rtsp://", 7)) return GF_FALSE;
{
int i;
for (i = 0 ; AAC_MIMES[i] ; i++)
if (gf_service_check_mime_register(plug, AAC_MIMES[i], AAC_EXTENSIONS, AAC_DESC, sExt))
return GF_TRUE;
}
return GF_FALSE;
}
#endif
static GF_ESD *AAC_GetESD(AACReader *read)
{
GF_BitStream *dsi;
GF_ESD *esd;
u32 i, sbr_sr_idx, sbr_oti;
esd = gf_odf_desc_esd_new(0);
if (!esd)
return NULL;
esd->decoderConfig->streamType = GF_STREAM_AUDIO;
esd->decoderConfig->objectTypeIndication = read->oti;
esd->ESID = 1;
esd->OCRESID = 1;
esd->slConfig->timestampResolution = read->sample_rate;
if (read->is_live) esd->slConfig->useAccessUnitEndFlag = esd->slConfig->useAccessUnitStartFlag = 1;
dsi = gf_bs_new(NULL, 0, GF_BITSTREAM_WRITE);
gf_bs_write_int(dsi, read->prof, 5);
gf_bs_write_int(dsi, read->sr_idx, 4);
gf_bs_write_int(dsi, read->nb_ch, 4);
gf_bs_align(dsi);
sbr_sr_idx = 0;
sbr_oti = 0;
if (read->sample_rate<=24000) {
sbr_sr_idx = read->sr_idx;
for (i=0; i<16; i++) {
if (GF_M4ASampleRates[i] == (u32) 2*read->sample_rate) {
sbr_sr_idx = i;
break;
}
}
}
gf_bs_write_int(dsi, 0x2b7, 11);
gf_bs_write_int(dsi, sbr_oti, 5);
gf_bs_write_int(dsi, 1, 1);
gf_bs_write_int(dsi, sbr_sr_idx, 4);
gf_bs_write_int(dsi, 0x548, 11);
gf_bs_write_int(dsi, 1, 1);
gf_bs_align(dsi);
gf_bs_get_content(dsi, &esd->decoderConfig->decoderSpecificInfo->data, &esd->decoderConfig->decoderSpecificInfo->dataLength);
gf_bs_del(dsi);
return esd;
}
#ifndef DONT_USE_TERMINAL_MODULE_API
static void AAC_SetupObject(AACReader *read)
{
GF_ESD *esd;
GF_ObjectDescriptor *od = (GF_ObjectDescriptor *) gf_odf_desc_new(GF_ODF_OD_TAG);
od->objectDescriptorID = 0;
od->service_ifce = read->input;
esd = AAC_GetESD(read);
esd->OCRESID = 0;
gf_list_add(od->ESDescriptors, esd);
gf_service_declare_media(read->service, (GF_Descriptor*)od, GF_FALSE);
}
#endif
static Bool ADTS_SyncFrame(GF_BitStream *bs, Bool is_complete, ADTSHeader *hdr)
{
u32 val;
u64 start_pos, pos;
start_pos = gf_bs_get_position(bs);
while (gf_bs_available(bs)) {
val = gf_bs_read_u8(bs);
if (val!=0xFF) continue;
val = gf_bs_read_int(bs, 4);
if (val != 0x0F) {
gf_bs_read_int(bs, 4);
continue;
}
hdr->is_mp2 = (Bool)gf_bs_read_int(bs, 1);
gf_bs_read_int(bs, 2);
hdr->no_crc = (Bool)gf_bs_read_int(bs, 1);
pos = gf_bs_get_position(bs) - 2;
hdr->profile = 1 + gf_bs_read_int(bs, 2);
hdr->sr_idx = gf_bs_read_int(bs, 4);
gf_bs_read_int(bs, 1);
hdr->nb_ch = gf_bs_read_int(bs, 3);
gf_bs_read_int(bs, 4);
hdr->frame_size = gf_bs_read_int(bs, 13);
gf_bs_read_int(bs, 11);
gf_bs_read_int(bs, 2);
hdr->hdr_size = 7;
if (!hdr->no_crc) {
gf_bs_read_u16(bs);
hdr->hdr_size = 9;
}
if (hdr->frame_size < hdr->hdr_size) {
gf_bs_seek(bs, pos+1);
continue;
}
hdr->frame_size -= hdr->hdr_size;
if (is_complete && (gf_bs_available(bs) == hdr->frame_size)) return GF_TRUE;
else if (gf_bs_available(bs) <= hdr->frame_size) break;
gf_bs_skip_bytes(bs, hdr->frame_size);
val = gf_bs_read_u8(bs);
if (val!=0xFF) {
gf_bs_seek(bs, pos+1);
continue;
}
val = gf_bs_read_int(bs, 4);
if (val!=0x0F) {
gf_bs_read_int(bs, 4);
gf_bs_seek(bs, pos+1);
continue;
}
gf_bs_seek(bs, pos+hdr->hdr_size);
return GF_TRUE;
}
gf_bs_seek(bs, start_pos);
return GF_FALSE;
}
static Bool AAC_ConfigureFromFile(AACReader *read)
{
Bool sync;
GF_BitStream *bs;
ADTSHeader hdr;
if (!read || !read->stream) return GF_FALSE;
bs = gf_bs_from_file(read->stream, GF_BITSTREAM_READ);
sync = ADTS_SyncFrame(bs, !read->is_remote, &hdr);
if (!sync) {
gf_bs_del(bs);
return GF_FALSE;
}
read->nb_ch = hdr.nb_ch;
read->prof = hdr.profile;
read->sr_idx = hdr.sr_idx;
read->oti = hdr.is_mp2 ? read->prof+GPAC_OTI_AUDIO_AAC_MPEG2_MP : GPAC_OTI_AUDIO_AAC_MPEG4;
read->sample_rate = GF_M4ASampleRates[read->sr_idx];
read->duration = 0;
if (!read->is_remote) {
read->duration = 1024;
gf_bs_skip_bytes(bs, hdr.frame_size);
while (ADTS_SyncFrame(bs, !read->is_remote, &hdr)) {
read->duration += 1024;
gf_bs_skip_bytes(bs, hdr.frame_size);
}
}
gf_bs_del(bs);
gf_fseek(read->stream, 0, SEEK_SET);
return 1;
}
#ifndef DONT_USE_TERMINAL_MODULE_API
static void AAC_RegulateDataRate(AACReader *read)
{
GF_NetworkCommand com;
if (!read)
return;
memset(&com, 0, sizeof(GF_NetworkCommand));
com.command_type = GF_NET_CHAN_BUFFER_QUERY;
com.base.on_channel = read->ch;
while (read->ch) {
gf_service_command(read->service, &com, GF_OK);
if (com.buffer.occupancy < com.buffer.max) break;
gf_sleep(2);
}
}
#endif
static void AAC_OnLiveData(AACReader *read, const char *data, u32 data_size)
{
u32 pos;
Bool sync;
GF_BitStream *bs;
ADTSHeader hdr;
assert( read->data || (!read->data && !read->data_size));
read->data = gf_realloc(read->data, sizeof(char)*(read->data_size+data_size) );
memcpy(read->data + read->data_size, data, sizeof(char)*data_size);
read->data_size += data_size;
if (read->needs_connection) {
read->needs_connection = 0;
bs = gf_bs_new((const char *)read->data, read->data_size, GF_BITSTREAM_READ);
sync = ADTS_SyncFrame(bs, 0, &hdr);
gf_bs_del(bs);
if (!sync) return;
read->nb_ch = hdr.nb_ch;
read->prof = hdr.profile;
read->sr_idx = hdr.sr_idx;
read->oti = hdr.is_mp2 ? read->prof+GPAC_OTI_AUDIO_AAC_MPEG2_MP-1 : GPAC_OTI_AUDIO_AAC_MPEG4;
read->sample_rate = GF_M4ASampleRates[read->sr_idx];
read->is_live = 1;
memset(&read->sl_hdr, 0, sizeof(GF_SLHeader));
#ifndef DONT_USE_TERMINAL_MODULE_API
gf_service_connect_ack(read->service, NULL, GF_OK);
AAC_SetupObject(read);
#endif
}
#ifndef DONT_USE_TERMINAL_MODULE_API
if (!read->ch) return;
#endif
if (read->data_size<=7) return;
bs = gf_bs_new((const char *)read->data, read->data_size, GF_BITSTREAM_READ);
hdr.frame_size = pos = 0;
while (ADTS_SyncFrame(bs, 0, &hdr)) {
pos = (u32) gf_bs_get_position(bs);
read->sl_hdr.accessUnitStartFlag = 1;
read->sl_hdr.accessUnitEndFlag = 1;
read->sl_hdr.AU_sequenceNumber++;
read->sl_hdr.compositionTimeStampFlag = 1;
read->sl_hdr.compositionTimeStamp += 1024;
#ifndef DONT_USE_TERMINAL_MODULE_API
gf_service_send_packet(read->service, read->ch, read->data + pos, hdr.frame_size, &read->sl_hdr, GF_OK);
#else
SampleCallBack(audio_prog, AUDIO_DATA_ESID, read->data + pos, hdr.frame_size, read->sl_hdr.compositionTimeStamp);
#endif
gf_bs_skip_bytes(bs, hdr.frame_size);
#ifndef DONT_USE_TERMINAL_MODULE_API
#ifndef _WIN32_WCE
if (read->hybrid_on && (!read->prev_map_time || (read->sl_hdr.compositionTimeStamp - read->prev_map_time) > read->sample_rate*5)) {
Double hybrid_delay = 0.0;
time_t now;
struct tm *now_tm;
const char *opt;
opt = gf_modules_get_option((GF_BaseInterface *)read->input, "HybRadio", "AudioDelay");
if (opt) {
hybrid_delay = atof(opt);
}
time(&now);
now += (s32)hybrid_delay;
now_tm = gmtime(&now);
{
GF_NetworkCommand com;
memset(&com, 0, sizeof(com));
com.command_type = GF_NET_CHAN_MAP_TIME;
com.map_time.media_time = now_tm->tm_hour*3600+now_tm->tm_min*60+now_tm->tm_sec + hybrid_delay;
com.map_time.timestamp = read->sl_hdr.compositionTimeStamp;
com.map_time.reset_buffers = 0;
com.base.on_channel = read->ch;
gf_service_command(read->service, &com, GF_OK);
GF_LOG(GF_LOG_INFO, GF_LOG_MEDIA, ("[AAC In] Mapping WC Time %04d/%02d/%02d %02d:%02d:%02d and AAC time "LLD" (audio delay %f)\n",
(now_tm->tm_year + 1900), (now_tm->tm_mon + 1), now_tm->tm_mday, now_tm->tm_hour, now_tm->tm_min, now_tm->tm_sec,
com.map_time.timestamp, hybrid_delay));
}
read->prev_map_time = read->sl_hdr.compositionTimeStamp;
}
#endif
#endif
}
pos = (u32) gf_bs_get_position(bs);
gf_bs_del(bs);
if (pos) {
char *d;
assert( read->data);
assert( read->data_size >= pos);
read->data_size -= pos;
d = gf_malloc(sizeof(char) * read->data_size);
assert( d );
memcpy(d, read->data + pos, sizeof(char) * read->data_size);
gf_free(read->data);
read->data = d;
}
#ifndef DONT_USE_TERMINAL_MODULE_API
AAC_RegulateDataRate(read);
#endif
}
static void AAC_disconnect_from_http_and_free(AACReader * read)
{
if (!read)
return;
if (read->dnload) {
gf_dm_sess_abort(read->dnload);
#ifdef DONT_USE_TERMINAL_MODULE_API
gf_dm_sess_del( read->dnload);
#else
gf_service_download_del(read->dnload);
#endif
}
read->dnload = NULL;
}
void AAC_NetIO(void *cbk, GF_NETIO_Parameter *param)
{
GF_Err e;
const char *szCache;
u32 total_size, bytes_done;
AACReader *read = (AACReader *) cbk;
e = param->error;
if (param->msg_type==GF_NETIO_DATA_TRANSFERED) {
if (read->stream) {
read->is_remote = 0;
e = GF_EOS;
} else if (!read->needs_connection) {
return;
}
} else if (param->msg_type==GF_NETIO_PARSE_HEADER) {
if (!strcmp(param->name, "icy-name")) {
if (read->icy_name) gf_free(read->icy_name);
read->icy_name = gf_strdup(param->value);
}
if (!strcmp(param->name, "icy-genre")) {
if (read->icy_genre) gf_free(read->icy_genre);
read->icy_genre = gf_strdup(param->value);
}
if (!strcmp(param->name, "icy-meta")) {
#ifndef DONT_USE_TERMINAL_MODULE_API
GF_NetworkCommand com;
#endif
char *meta;
if (read->icy_track_name) gf_free(read->icy_track_name);
read->icy_track_name = NULL;
meta = param->value;
while (meta && meta[0]) {
char *sep = strchr(meta, ';');
if (sep) sep[0] = 0;
if (!strnicmp(meta, "StreamTitle=", 12)) {
read->icy_track_name = gf_strdup(meta+12);
if (!strcmp(read->icy_track_name, "''")) {
gf_free(read->icy_track_name);
read->icy_track_name = NULL;
}
}
if (!sep) break;
sep[0] = ';';
meta = sep+1;
}
#ifndef DONT_USE_TERMINAL_MODULE_API
com.base.command_type = GF_NET_SERVICE_INFO;
gf_service_command(read->service, &com, GF_OK);
#endif
}
return;
} else {
#ifndef DONT_USE_TERMINAL_MODULE_API
gf_service_download_update_stats(read->dnload);
#endif
if (param->msg_type!=GF_NETIO_DATA_EXCHANGE) return;
}
if (e >= GF_OK) {
if (read->needs_connection) {
gf_dm_sess_get_stats(read->dnload, NULL, NULL, &total_size, NULL, NULL, NULL);
if (!total_size) read->is_live = 1;
}
if (read->is_live) {
if (!e) AAC_OnLiveData(read, param->data, param->size);
return;
}
if (read->stream) return;
szCache = gf_dm_sess_get_cache_name(read->dnload);
if (!szCache) e = GF_IO_ERR;
else {
read->stream = gf_fopen((char *) szCache, "rb");
if (!read->stream) e = GF_SERVICE_ERROR;
else {
if (e==GF_EOS) read->is_remote = 0;
e = GF_OK;
if (!AAC_ConfigureFromFile(read)) {
gf_dm_sess_get_stats(read->dnload, NULL, NULL, NULL, &bytes_done, NULL, NULL);
if (bytes_done>10*1024) {
e = GF_CORRUPTED_DATA;
} else {
gf_fclose(read->stream);
read->stream = NULL;
return;
}
}
}
}
}
if (read->needs_connection) {
read->needs_connection = 0;
#ifndef DONT_USE_TERMINAL_MODULE_API
gf_service_connect_ack(read->service, NULL, e);
if (!e) AAC_SetupObject(read);
#else
if (e) {
GF_LOG(GF_LOG_ERROR, GF_LOG_APP, ("Failed to initialize AAC reader\n"));
}
#endif
}
}
void aac_download_file(AACReader *read, char *url)
{
read->needs_connection = 1;
AAC_disconnect_from_http_and_free(read);
#ifndef DONT_USE_TERMINAL_MODULE_API
read->dnload = gf_service_download_new(read->service, url, 0, AAC_NetIO, read);
#else
{
GF_Err e;
if (!read->dm)
read->dm = gf_dm_new(NULL);
assert( read->dm );
read->dnload = gf_dm_sess_new_simple(read->dm, url, 0, AAC_NetIO, read, &e);
}
#endif
if (!read->dnload ) {
read->needs_connection = 0;
#ifndef DONT_USE_TERMINAL_MODULE_API
gf_service_connect_ack(read->service, NULL, GF_NOT_SUPPORTED);
#endif
}
#ifndef DONT_USE_TERMINAL_MODULE_API
gf_dm_sess_process(read->dnload);
#endif
}
static void AAC_Reader_del(AACReader * read)
{
if (!read)
return;
AAC_disconnect_from_http_and_free(read);
#ifdef DONT_USE_TERMINAL_MODULE_API
if (read->dm)
gf_dm_del(read->dm);
read->dm = NULL;
#endif
if (read->icy_name)
gf_free(read->icy_name);
if (read->icy_genre)
gf_free(read->icy_genre);
if (read->icy_track_name)
gf_free(read->icy_track_name);
read->icy_name = read->icy_genre = read->icy_track_name = NULL;
if (read->stream)
gf_fclose(read->stream);
if (read->data)
gf_free(read->data);
read->data = NULL;
read->stream = NULL;
#ifndef DONT_USE_TERMINAL_MODULE_API
gf_free( read );
#endif
}
static AACReader * AAC_Reader_new() {
AACReader *reader = gf_malloc(sizeof(AACReader));
memset(reader, 0, sizeof(AACReader));
return reader;
}
#ifndef DONT_USE_TERMINAL_MODULE_API
static Bool aac_is_local(const char *url)
{
if (!strnicmp(url, "file://", 7)) return 1;
if (strstr(url, "://")) return 0;
return 1;
}
static GF_Err AAC_ConnectService(GF_InputService *plug, GF_ClientService *serv, const char *url)
{
char szURL[2048];
char *ext;
const char *opt;
GF_Err reply;
AACReader *read = plug->priv;
read->service = serv;
read->input = plug;
opt = gf_modules_get_option((GF_BaseInterface *)read->input, "HybRadio", "Activated");
if (opt && !strcmp(opt, "true")) {
read->hybrid_on = 1;
}
AAC_disconnect_from_http_and_free(read);
strcpy(szURL, url);
ext = strrchr(szURL, '#');
if (ext) ext[0] = 0;
read->is_remote = !aac_is_local(szURL);
if (read->is_remote) {
aac_download_file(read, (char *) szURL);
return GF_OK;
}
reply = GF_OK;
read->stream = gf_fopen(szURL, "rb");
if (!read->stream) {
reply = GF_URL_ERROR;
} else if (!AAC_ConfigureFromFile(read)) {
gf_fclose(read->stream);
read->stream = NULL;
reply = GF_NOT_SUPPORTED;
}
gf_service_connect_ack(serv, NULL, reply);
if (!reply && read->is_inline ) AAC_SetupObject(read);
return GF_OK;
}
static GF_Err AAC_CloseService(GF_InputService *plug)
{
AACReader *read;
if (!plug)
return GF_BAD_PARAM;
read = plug->priv;
if (!read)
return GF_BAD_PARAM;
gf_service_disconnect_ack(read->service, NULL, GF_OK);
AAC_Reader_del( read );
plug->priv = NULL;
return GF_OK;
}
static GF_Descriptor *AAC_GetServiceDesc(GF_InputService *plug, u32 expect_type, const char *sub_url)
{
AACReader *read = plug->priv;
if (expect_type==GF_MEDIA_OBJECT_UNDEF) expect_type=GF_MEDIA_OBJECT_AUDIO;
if (expect_type==GF_MEDIA_OBJECT_AUDIO) {
GF_ESD *esd;
GF_ObjectDescriptor *od = (GF_ObjectDescriptor *) gf_odf_desc_new(GF_ODF_OD_TAG);
od->objectDescriptorID = 1;
esd = AAC_GetESD(read);
esd->OCRESID = 0;
gf_list_add(od->ESDescriptors, esd);
return (GF_Descriptor *) od;
}
read->is_inline = 1;
return NULL;
}
static GF_Err AAC_ConnectChannel(GF_InputService *plug, LPNETCHANNEL channel, const char *url, Bool upstream)
{
u32 ES_ID=0;
GF_Err e;
AACReader *read = plug->priv;
e = GF_SERVICE_ERROR;
if (read->ch==channel) {
GF_LOG(GF_LOG_INFO, GF_LOG_MEDIA, ("[AAC_IN] read->ch==channel = %p, GF_SERVICE_ERROR\n", channel));
goto exit;
}
e = GF_STREAM_NOT_FOUND;
if (strstr(url, "ES_ID")) {
sscanf(url, "ES_ID=%ud", &ES_ID);
}
else if (!read->ch && AAC_CanHandleURL(plug, url)) ES_ID = 1;
if (ES_ID==1) {
read->ch = channel;
e = GF_OK;
}
exit:
gf_service_connect_ack(read->service, channel, e);
return e;
}
static GF_Err AAC_DisconnectChannel(GF_InputService *plug, LPNETCHANNEL channel)
{
AACReader *read = plug->priv;
GF_Err e = GF_STREAM_NOT_FOUND;
if (read->ch == channel) {
AAC_disconnect_from_http_and_free(read);
read->ch = NULL;
if (read->data)
gf_free(read->data);
read->data = NULL;
e = GF_OK;
}
gf_service_disconnect_ack(read->service, channel, e);
return GF_OK;
}
static GF_Err AAC_ServiceCommand(GF_InputService *plug, GF_NetworkCommand *com)
{
AACReader *read = plug->priv;
if (com->base.command_type==GF_NET_SERVICE_INFO) {
com->info.name = read->icy_track_name ? read->icy_track_name : read->icy_name;
com->info.comment = read->icy_genre;
return GF_OK;
}
if (!com->base.on_channel) {
if (read->is_live && (com->command_type==GF_NET_IS_CACHABLE)) return GF_OK;
return GF_NOT_SUPPORTED;
}
switch (com->command_type) {
case GF_NET_CHAN_SET_PULL:
if ((read->ch == com->base.on_channel) && read->is_live) return GF_NOT_SUPPORTED;
return GF_OK;
case GF_NET_CHAN_INTERACTIVE:
if ((read->ch == com->base.on_channel) && read->is_live) return GF_NOT_SUPPORTED;
return GF_OK;
case GF_NET_CHAN_BUFFER:
if ((read->ch == com->base.on_channel) && read->is_live) {
if (com->buffer.max<1000) com->buffer.max = 1000;
com->buffer.min = com->buffer.max/2;
}
return GF_OK;
case GF_NET_CHAN_SET_PADDING:
read->pad_bytes = com->pad.padding_bytes;
return GF_OK;
case GF_NET_CHAN_DURATION:
com->duration.duration = read->duration;
com->duration.duration /= read->sample_rate;
return GF_OK;
case GF_NET_CHAN_PLAY:
read->start_range = com->play.start_range;
read->end_range = com->play.end_range;
read->current_time = 0;
if (read->stream) gf_fseek(read->stream, 0, SEEK_SET);
if (read->ch == com->base.on_channel) {
read->done = 0;
if (!read->is_remote && !read->duration) {
AAC_ConfigureFromFile(read);
if (read->duration) {
GF_NetworkCommand rcfg;
rcfg.base.on_channel = read->ch;
rcfg.base.command_type = GF_NET_CHAN_DURATION;
rcfg.duration.duration = read->duration;
rcfg.duration.duration /= read->sample_rate;
gf_service_command(read->service, &rcfg, GF_OK);
}
}
}
return GF_OK;
case GF_NET_CHAN_STOP:
return GF_OK;
default:
return GF_OK;
}
}
static GF_Err AAC_ChannelGetSLP(GF_InputService *plug, LPNETCHANNEL channel, char **out_data_ptr, u32 *out_data_size, GF_SLHeader *out_sl_hdr, Bool *sl_compressed, GF_Err *out_reception_status, Bool *is_new_data)
{
u64 pos;
u32 start_from;
Bool sync;
GF_BitStream *bs;
ADTSHeader hdr;
AACReader *read = plug->priv;
*out_reception_status = GF_OK;
*sl_compressed = 0;
*is_new_data = 0;
memset(&read->sl_hdr, 0, sizeof(GF_SLHeader));
read->sl_hdr.randomAccessPointFlag = 1;
read->sl_hdr.compositionTimeStampFlag = 1;
if (read->ch != channel) return GF_STREAM_NOT_FOUND;
if (read->done) {
*out_reception_status = GF_EOS;
return GF_OK;
}
if (!read->data) {
if (!read->stream) {
*out_data_ptr = NULL;
*out_data_size = 0;
return GF_OK;
}
bs = gf_bs_from_file(read->stream, GF_BITSTREAM_READ);
*is_new_data = 1;
fetch_next:
pos = gf_ftell(read->stream);
sync = ADTS_SyncFrame(bs, !read->is_remote, &hdr);
if (!sync) {
gf_bs_del(bs);
if (!read->dnload) {
if (read->input->query_proxy) {
GF_NetworkCommand param;
param.command_type = GF_NET_SERVICE_QUERY_NEXT;
if ((read->input->query_proxy(read->input, ¶m)==GF_OK)
&& param.url_query.next_url
) {
gf_fclose(read->stream);
read->stream = gf_fopen(param.url_query.next_url, "rb");
*out_reception_status = GF_OK;
return GF_OK;
}
}
*out_reception_status = GF_EOS;
read->done = 1;
} else {
gf_fseek(read->stream, pos, SEEK_SET);
*out_reception_status = GF_OK;
}
return GF_OK;
}
if (!hdr.frame_size) {
gf_bs_del(bs);
*out_reception_status = GF_EOS;
read->done = 1;
return GF_OK;
}
read->data_size = hdr.frame_size;
read->nb_samp = 1024;
if (read->start_range && read->duration) {
start_from = (u32) (read->start_range * read->sample_rate);
if (read->current_time + read->nb_samp < start_from) {
read->current_time += read->nb_samp;
goto fetch_next;
} else {
read->start_range = 0;
}
}
read->sl_hdr.compositionTimeStamp = read->current_time;
assert( !read->data);
read->data = gf_malloc(sizeof(char) * (read->data_size+read->pad_bytes));
gf_bs_read_data(bs, read->data, read->data_size);
if (read->pad_bytes) memset(read->data + read->data_size, 0, sizeof(char) * read->pad_bytes);
gf_bs_del(bs);
}
*out_sl_hdr = read->sl_hdr;
*out_data_ptr = read->data;
*out_data_size = read->data_size;
return GF_OK;
}
static GF_Err AAC_ChannelReleaseSLP(GF_InputService *plug, LPNETCHANNEL channel)
{
AACReader *read = plug->priv;
if (read->ch == channel) {
if (!read->data) return GF_BAD_PARAM;
gf_free(read->data);
read->data = NULL;
read->current_time += read->nb_samp;
return GF_OK;
}
return GF_BAD_PARAM;
}
GF_InputService *AAC_Load()
{
GF_InputService *plug = gf_malloc(sizeof(GF_InputService));
memset(plug, 0, sizeof(GF_InputService));
GF_REGISTER_MODULE_INTERFACE(plug, GF_NET_CLIENT_INTERFACE, "GPAC AAC Reader", "gpac distribution")
plug->CanHandleURL = AAC_CanHandleURL;
plug->ConnectService = AAC_ConnectService;
plug->CloseService = AAC_CloseService;
plug->GetServiceDescriptor = AAC_GetServiceDesc;
plug->ConnectChannel = AAC_ConnectChannel;
plug->DisconnectChannel = AAC_DisconnectChannel;
plug->ServiceCommand = AAC_ServiceCommand;
plug->ChannelGetSLP = AAC_ChannelGetSLP;
plug->ChannelReleaseSLP = AAC_ChannelReleaseSLP;
plug->RegisterMimeTypes = AAC_RegisterMimeTypes;
plug->priv = AAC_Reader_new();
return plug;
}
void AAC_Delete(void *ifce)
{
AACReader *read;
GF_InputService *plug = (GF_InputService *) ifce;
if (!plug)
return;
read = plug->priv;
if (read) {
AAC_Reader_del(read);
plug->priv = NULL;
}
gf_free(plug);
}
#endif
#endif
#ifndef DONT_USE_TERMINAL_MODULE_API
GPAC_MODULE_EXPORT
const u32 *QueryInterfaces()
{
static u32 si [] = {
#ifndef GPAC_DISABLE_AV_PARSERS
GF_NET_CLIENT_INTERFACE,
#endif
#ifdef GPAC_HAS_FAAD
GF_MEDIA_DECODER_INTERFACE,
#endif
0
};
return si;
}
#ifdef GPAC_HAS_FAAD
GF_BaseDecoder *NewFAADDec();
void DeleteFAADDec(GF_BaseDecoder *ifcg);
#endif
GPAC_MODULE_EXPORT
GF_BaseInterface *LoadInterface(u32 InterfaceType)
{
#ifndef GPAC_DISABLE_AV_PARSERS
if (InterfaceType == GF_NET_CLIENT_INTERFACE) return (GF_BaseInterface *)AAC_Load();
#endif
#ifdef GPAC_HAS_FAAD
if (InterfaceType == GF_MEDIA_DECODER_INTERFACE) return (GF_BaseInterface *)NewFAADDec();
#endif
return NULL;
}
GPAC_MODULE_EXPORT
void ShutdownInterface(GF_BaseInterface *ifce)
{
switch (ifce->InterfaceType) {
#ifdef GPAC_HAS_FAAD
case GF_MEDIA_DECODER_INTERFACE:
DeleteFAADDec((GF_BaseDecoder *)ifce);
break;
#endif
#ifndef GPAC_DISABLE_AV_PARSERS
case GF_NET_CLIENT_INTERFACE:
AAC_Delete(ifce);
break;
#endif
}
}
GPAC_MODULE_STATIC_DECLARATION( aac_in )
#endif